Initial revision
[freeradius.git] / src / main / radiusd.c
1 /*
2  * radiusd.c    Main loop of the radius server.
3  *
4  * Version:     @(#)radiusd.c  1.90  22-Jul-1999  miquels@cistron.nl
5  *
6  */
7
8 /* don't look here for the version, run radiusd -v or look in version.c */
9 char radiusd_sccsid[] =
10 "@(#)radiusd.c  1.90 Copyright 1999 Cistron Internet Services B.V.";
11
12 #include        "autoconf.h"
13
14 #include        <sys/types.h>
15 #include        <sys/socket.h>
16 #include        <sys/time.h>
17 #include        <sys/file.h>
18 #include        <netinet/in.h>
19
20 #include        <stdio.h>
21 #include        <stdlib.h>
22 #include        <string.h>
23 #include        <netdb.h>
24 #include        <fcntl.h>
25 #include        <time.h>
26 #include        <ctype.h>
27 #include        <unistd.h>
28 #include        <signal.h>
29 #include        <errno.h>
30 #include        <sys/wait.h>
31 #if HAVE_GETOPT_H
32 #  include      <getopt.h>
33 #endif
34 #if HAVE_SYS_SELECT_H
35 #  include      <sys/select.h>
36 #endif
37
38 #include        "radiusd.h"
39
40 /*
41  *      Global variables.
42  */
43 char                    *progname;
44 char                    *radius_dir;
45 char                    *radacct_dir;
46 char                    *radlog_dir;
47 int                     log_stripped_names;
48 int                     cache_passwd = 0;
49 int                     debug_flag;
50 int                     use_dbm = 0;
51 UINT4                   myip = 0;
52 int                     log_auth_detail = 0;
53 int                     log_auth = 0;
54 int                     log_auth_pass  = 0;
55 int                     auth_port;
56 int                     acct_port;
57
58 static int              got_chld = 0;
59 static int              request_list_busy = 0;
60 static int              sockfd;
61 static int              acctfd;
62 static int              spawn_flag;
63 static int              acct_pid;
64 static int              radius_pid;
65 static int              need_reload = 0;
66 static REQUEST          *first_request;
67
68 #if !defined(__linux__) && !defined(__GNU_LIBRARY__)
69 extern int      errno;
70 #endif
71
72 typedef         int (*FUNP)(REQUEST *, int);
73
74 static void     usage(void);
75
76 static void     sig_fatal (int);
77 static void     sig_hup (int);
78
79 static int      radrespond (REQUEST *, int);
80 static void     rad_spawn_child (REQUEST *, int, FUNP);
81
82 /*
83  *      Read config files.
84  */
85 static void reread_config(int reload)
86 {
87         int res = 0;
88         int pid = getpid();
89
90         if (!reload) {
91                 log(L_INFO, "Starting - reading configuration files ...");
92         } else if (pid == radius_pid) {
93                 log(L_INFO, "Reloading configuration files.");
94         }
95
96         /* Read users file etc. */
97         if (res == 0 && read_config_files() != 0)
98                 res = -1;
99
100         if (res != 0) {
101           if (pid == radius_pid) {
102                         log(L_ERR|L_CONS,
103                                 "Errors reading config file - EXITING");
104                         if (acct_pid) {
105                                 signal(SIGCHLD, SIG_DFL);
106                                 kill(acct_pid, SIGTERM);
107                         }
108                 }
109                 exit(1);
110         }
111 }
112
113
114 int main(int argc, char **argv)
115 {
116         CLIENT                  *cl;
117         REQUEST                 *request;
118         RADIUS_PACKET           *packet;
119 #ifdef RADIUS_PID
120         FILE                    *fp;
121 #endif
122         struct  sockaddr        salocal;
123         struct  sockaddr_in     *sin;
124         struct  servent         *svp;
125         fd_set                  readfds;
126         int                     result;
127         int                     argval;
128         int                     t;
129         int                     pid;
130         int                     i;
131         int                     fd = 0;
132         int                     status;
133         int                     dontfork = 0;
134         int                     radius_port = 0;
135
136 #ifdef OSFC2
137         set_auth_parameters(argc,argv);
138 #endif
139
140         if ((progname = strrchr(argv[0], '/')) == NULL)
141                 progname = argv[0];
142         else
143                 progname++;
144
145         debug_flag = 0;
146         spawn_flag = 1;
147         radacct_dir = RADACCT_DIR;
148         radius_dir = RADIUS_DIR;
149         radlog_dir = RADLOG_DIR;
150
151         signal(SIGHUP, sig_hup);
152         signal(SIGINT, sig_fatal);
153         signal(SIGQUIT, sig_fatal);
154         signal(SIGTRAP, sig_fatal);
155         signal(SIGIOT, sig_fatal);
156         signal(SIGTERM, sig_fatal);
157         signal(SIGCHLD, sig_cleanup);
158 #if 0
159         signal(SIGFPE, sig_fatal);
160         signal(SIGSEGV, sig_fatal);
161         signal(SIGILL, sig_fatal);
162 #endif
163
164         /*
165          *      Close unused file descriptors.
166          */
167         for (t = 32; t >= 3; t--)
168                         close(t);
169
170         /*
171          *      Process the options.
172          */
173         while((argval = getopt(argc, argv, "ASa:ci:l:d:bfp:svxyz")) != EOF) {
174
175                 switch(argval) {
176
177                 case 'A':
178                         log_auth_detail++;
179                         break;
180
181                 case 'a':
182                         radacct_dir = optarg;
183                         break;
184                 
185 #if defined(WITH_DBM) || defined(WITH_NDBM)
186                 case 'b':
187                         use_dbm++;
188                         break;
189 #endif
190                 case 'c':
191                         cache_passwd = 1;
192                         break;
193
194                 case 'd':
195                         radius_dir = optarg;
196                         break;
197                 
198                 case 'f':
199                         dontfork = 1;
200                         break;
201
202                 case 'i':
203                         if ((myip = ip_getaddr(optarg)) == 0) {
204                                 fprintf(stderr, "radiusd: %s: host unknown\n",
205                                         optarg);
206                                 exit(1);
207                         }
208                         break;
209                 
210                 case 'l':
211                         radlog_dir = optarg;
212                         break;
213                 
214                 case 'S':
215                         log_stripped_names++;
216                         break;
217
218                 case 'p':
219                         radius_port = atoi(optarg);
220                         break;
221
222                 case 's':       /* Single process mode */
223                         spawn_flag = 0;
224                         break;
225
226                 case 'v':
227                         version();
228                         break;
229
230                 case 'x':
231                         debug_flag++;
232                         librad_debug++;
233                         break;
234                 
235                 case 'y':
236                         log_auth = 1;
237                         break;
238
239                 case 'z':
240                         log_auth_pass = 1;
241                         break;
242
243                 default:
244                         usage();
245                         break;
246                 }
247         }
248
249         /*
250          *      Open Authentication socket.
251          */
252         svp = getservbyname ("radius", "udp");
253         if (radius_port)
254                 auth_port = radius_port;
255         else if (svp != NULL)
256                 auth_port = ntohs(svp->s_port);
257         else
258                 auth_port = PW_AUTH_UDP_PORT;
259
260         sockfd = socket (AF_INET, SOCK_DGRAM, 0);
261         if (sockfd < 0) {
262                 perror("auth socket");
263                 exit(1);
264         }
265
266         sin = (struct sockaddr_in *) & salocal;
267         memset ((char *) sin, '\0', sizeof (salocal));
268         sin->sin_family = AF_INET;
269         sin->sin_addr.s_addr = myip ? myip : INADDR_ANY;
270         sin->sin_port = htons(auth_port);
271
272         result = bind (sockfd, & salocal, sizeof (*sin));
273         if (result < 0) {
274                 perror ("auth bind");
275                 exit(1);
276         }
277
278         /*
279          *      Open Accounting Socket.
280          */
281         svp = getservbyname ("radacct", "udp");
282         if (radius_port || svp == (struct servent *) 0)
283                 acct_port = auth_port + 1;
284         else
285                 acct_port = ntohs(svp->s_port);
286         
287         acctfd = socket (AF_INET, SOCK_DGRAM, 0);
288         if (acctfd < 0) {
289                 perror ("acct socket");
290                 exit(1);
291         }
292
293         sin = (struct sockaddr_in *) & salocal;
294         memset ((char *) sin, '\0', sizeof (salocal));
295         sin->sin_family = AF_INET;
296         sin->sin_addr.s_addr = myip ? myip : INADDR_ANY;
297         sin->sin_port = htons(acct_port);
298
299         result = bind (acctfd, & salocal, sizeof (*sin));
300         if (result < 0) {
301                 perror ("acct bind");
302                 exit(1);
303         }
304
305         radius_pid = getpid();
306 #ifdef RADIUS_PID
307         if ((fp = fopen(RADIUS_PID, "w")) != NULL) {
308                 fprintf(fp, "%d\n", radius_pid);
309                 fclose(fp);
310         }
311 #endif
312         /*
313          *      Read config files.
314          */
315         reread_config(0);
316
317         /*
318          *      Register built-in compare functions.
319          */
320         pair_builtincompare_init();
321
322         /*
323          *      Disconnect from session
324          */
325         if(debug_flag == 0 && dontfork == 0) {
326                 pid = fork();
327                 if(pid < 0) {
328                         log(L_ERR|L_CONS, "Couldn't fork");
329                         exit(1);
330                 }
331                 if(pid > 0) {
332                         exit(0);
333                 }
334 #ifdef HAVE_SETSID
335                 setsid();
336 #endif
337         }
338         /*
339          *      Use linebuffered or unbuffered stdout if
340          *      the debug flag is on.
341          */
342         if (debug_flag) setlinebuf(stdout);
343
344 #if !defined(M_UNIX) && !defined(__linux__)
345         /*
346          *      Open system console as stderr
347          */
348         if (!debug_flag) {
349                 t = open("/dev/console", O_WRONLY | O_NOCTTY);
350                 if (t != 2) {
351                         dup2(t, 2);
352                         close(t);
353                 }
354         }
355 #endif
356         /*
357          *      If we are in forking mode, we will start a child
358          *      to listen for Accounting requests.  If not, we will 
359          *      listen for them ourself.
360          */
361         if (spawn_flag) {
362                 acct_pid = fork();
363                 if(acct_pid < 0) {
364                         log(L_ERR|L_CONS, "Couldn't fork");
365                         exit(1);
366                 }
367                 if(acct_pid > 0) {
368                         close(acctfd);
369                         acctfd = -1;
370                         log(L_INFO, "Ready to process requests.");
371                 }
372                 else {
373                         close(sockfd);
374                         sockfd = -1;
375                 }
376         } else
377                 log(L_INFO, "Ready to process requests.");
378
379
380         /*
381          *      Receive user requests
382          */
383         for(;;) {
384
385                 if (need_reload) {
386                         reread_config(1);
387                         need_reload = 0;
388                         if (getpid() == radius_pid && acct_pid)
389                                 kill(acct_pid, SIGHUP);
390                 }
391
392                 FD_ZERO(&readfds);
393                 if (sockfd >= 0)
394                         FD_SET(sockfd, &readfds);
395                 if (acctfd >= 0)
396                         FD_SET(acctfd, &readfds);
397
398                 status = select(32, &readfds, NULL, NULL, NULL);
399                 if (status == -1) {
400                         if (errno == EINTR)
401                                 continue;
402                         sig_fatal(101);
403                 }
404                 for (i = 0; i < 2; i++) {
405
406                         if (i == 0) fd = sockfd;
407                         if (i == 1) fd = acctfd;
408                         if (fd < 0 || !FD_ISSET(fd, &readfds))
409                                 continue;
410
411                         packet = rad_recv(fd);
412                         if (packet == NULL) continue;
413
414                         /*
415                          *      See if we know this client.
416                          */
417                         if ((cl = client_find(packet->src_ipaddr)) == NULL) {
418                                 log(L_ERR, "request from unknown client: %s",
419                                         ip_hostname(packet->src_ipaddr));
420                                         rad_free(packet);
421                                         continue;
422                         }
423                         if (rad_decode(packet, cl->secret) != 0) {
424                                 log(L_ERR, "%s", librad_errstr);
425                                 rad_free(packet);
426                                 continue;
427                         }
428                         if ((request = malloc(sizeof(REQUEST))) == NULL) {
429                                 log(L_ERR|L_CONS, "no memory");
430                                 exit(1);
431                         }
432                         memset(request, 0, sizeof(REQUEST));
433                         request->packet = packet;
434                         request->timestamp = time(NULL);
435                         strcpy(request->secret, cl->secret);
436                         radrespond(request, fd);
437                 }
438         }
439 }
440
441
442 /*
443  *      Respond to supported requests:
444  *
445  *              PW_AUTHENTICATION_REQUEST - Authentication request from
446  *                              a client network access server.
447  *
448  *              PW_ACCOUNTING_REQUEST - Accounting request from
449  *                              a client network access server.
450  *
451  *              PW_AUTHENTICATION_ACK
452  *              PW_AUTHENTICATION_REJECT
453  *              PW_ACCOUNTING_RESPONSE - Reply from a remote Radius server.
454  *                              Relay reply back to original NAS.
455  *
456  */
457 int radrespond(REQUEST *request, int activefd)
458 {
459         int dospawn;
460         FUNP fun;
461         VALUE_PAIR *namepair;
462         int e;
463
464         dospawn = 0;
465         fun = NULL;
466
467         /*
468          *      First, see if we need to proxy this request.
469          */
470         switch(request->packet->code) {
471
472         case PW_AUTHENTICATION_REQUEST:
473         case PW_ACCOUNTING_REQUEST:
474                 /*
475                  *      Setup username and stuff.
476                  */
477                 if ((e = rad_mangle(request)) < 0)
478                         return e;
479                 namepair = pairfind(request->packet->vps, PW_USER_NAME);
480                 if (namepair == NULL)
481                         break;
482                 /*
483                  *      We always call proxy_send, it returns non-zero
484                  *      if it did actually proxy the request.
485                  */
486                 if (proxy_send(request, activefd) != 0)
487                         return 0;
488                 break;
489
490         case PW_AUTHENTICATION_ACK:
491         case PW_AUTHENTICATION_REJECT:
492         case PW_ACCOUNTING_RESPONSE:
493                 if (proxy_receive(request, activefd) < 0)
494                         return 0;
495                 break;
496         }
497
498         /*
499          *      Select the required function and indicate if
500          *      we need to fork off a child to handle it.
501          */
502         switch(request->packet->code) {
503
504         case PW_AUTHENTICATION_REQUEST:
505                 dospawn = spawn_flag;
506                 fun = rad_authenticate;
507                 break;
508         
509         case PW_ACCOUNTING_REQUEST:
510                 fun = rad_accounting;
511                 break;
512         
513         case PW_PASSWORD_REQUEST:
514                 /*
515                  *      FIXME: print an error message here.
516                  *      We don't support this anymore.
517                  */
518                 /* rad_passchange(request, activefd); */
519                 break;
520         
521
522         default:
523                 break;
524         }
525
526         /*
527          *      If we did select a function, execute it
528          *      (perhaps through rad_spawn_child)
529          */
530         if (fun) {
531                 if (dospawn)
532                         rad_spawn_child(request, activefd, fun);
533                 else {
534                         (*fun)(request, activefd);
535                         request_free(request);
536                 }
537         }
538
539         return 0;
540 }
541
542
543 /*
544  *      Spawns child processes to perform authentication/accounting
545  *      and respond to RADIUS clients.  This functions also
546  *      cleans up complete child requests, and verifies that there
547  *      is only one process responding to each request (duplicate
548  *      requests are filtered out).
549  */
550 static void rad_spawn_child(REQUEST *request, int activefd, FUNP fun)
551 {
552         REQUEST         *curreq;
553         REQUEST         *prevreq;
554         RADIUS_PACKET   *pkt;
555         UINT4           curtime;
556         int             request_count;
557         int             child_pid;
558
559         curtime = (UINT4)time(NULL);
560         request_count = 0;
561         curreq = first_request;
562         prevreq = (REQUEST *)NULL;
563         pkt = request->packet;
564
565         /*
566          *      When mucking around with the request list, we block
567          *      asynchronous access (through the SIGCHLD handler) to
568          *      the list - equivalent to sigblock(SIGCHLD).
569          */
570         request_list_busy = 1;
571
572         while(curreq != (REQUEST *)NULL) {
573                 if (curreq->child_pid == -1 &&
574                     curreq->timestamp + CLEANUP_DELAY <= curtime) {
575                         /*
576                          *      Request completed, delete it
577                          */
578                         if (prevreq == (REQUEST *)NULL) {
579                                 first_request = curreq->next;
580                                 request_free(curreq);
581                                 curreq = first_request;
582                         } else {
583                                 prevreq->next = curreq->next;
584                                 request_free(curreq);
585                                 curreq = prevreq->next;
586                         }
587                 } else if (curreq->packet->src_ipaddr == pkt->src_ipaddr &&
588                            curreq->packet->id == pkt->id) {
589                         /*
590                          *      Compare the request vectors to see
591                          *      if it really is the same request.
592                          */
593                         if (!memcmp(curreq->packet->vector, pkt->vector, 16)) {
594                                 /*
595                                  * This is a duplicate request - just drop it
596                                  */
597                                 log(L_ERR,
598                                 "Dropping duplicate authentication packet"
599                                 " from client %s - ID: %d",
600                                 client_name(request->packet->src_ipaddr),
601                                 request->packet->id);
602
603                                 request_free(request);
604                                 request_list_busy = 0;
605                                 sig_cleanup(SIGCHLD);
606
607                                 return;
608                         }
609                         /*
610                          *      If the old request was completed,
611                          *      delete it right now.
612                          */
613                         if (curreq->child_pid == -1) {
614                                 curreq->timestamp = curtime - CLEANUP_DELAY;
615                                 continue;
616                         }
617
618                         /*
619                          *      Not completed yet, do nothing special.
620                          */
621                         prevreq = curreq;
622                         curreq = curreq->next;
623                         request_count++;
624                 } else {
625                         if (curreq->timestamp + MAX_REQUEST_TIME <= curtime &&
626                             curreq->child_pid != -1) {
627                                 /*
628                                  *      This request seems to have hung -
629                                  *      kill it
630                                  */
631                                 child_pid = curreq->child_pid;
632                                 log(L_ERR,
633                                         "Killing unresponsive child pid %d",
634                                                                 child_pid);
635                                 curreq->child_pid = -1;
636                                 kill(child_pid, SIGTERM);
637                         }
638                         prevreq = curreq;
639                         curreq = curreq->next;
640                         request_count++;
641                 }
642         }
643
644         /*
645          *      This is a new request
646          */
647         if (request_count > MAX_REQUESTS) {
648                 log(L_ERR, "Dropping request (too many): "
649                                 "from client %s - ID: %d",
650                                 client_name(request->packet->src_ipaddr),
651                                 request->packet->id);
652                 request_free(request);
653
654                 request_list_busy = 0;
655                 sig_cleanup(SIGCHLD);
656                                 
657                 return;
658         }
659
660         /*
661          *      Add this request to the list
662          */
663         request->next = (REQUEST *)NULL;
664         request->child_pid = -1;
665         request->timestamp = curtime;
666
667         if (prevreq == (REQUEST *)NULL)
668                 first_request = request;
669         else
670                 prevreq->next = request;
671
672         /*
673          *      fork our child
674          */
675         if ((child_pid = fork()) < 0) {
676                 log(L_ERR, "Fork failed for request from nas %s - ID: %d",
677                                 nas_name2(request->packet),
678                                 request->packet->id);
679         }
680         if (child_pid == 0) {
681                 /*
682                  *      This is the child, it should go ahead and respond
683                  */
684                 request_list_busy = 0;
685                 signal(SIGCHLD, SIG_DFL);
686                 (*fun)(request, activefd);
687                 exit(0);
688         }
689
690         /*
691          *      Register the Child
692          */
693         request->child_pid = child_pid;
694
695         request_list_busy = 0;
696         sig_cleanup(SIGCHLD);
697 }
698
699
700 /*ARGSUSED*/
701 void sig_cleanup(int sig)
702 {
703         int             status;
704         pid_t           pid;
705         REQUEST *curreq;
706  
707         /*
708          *      request_list_busy is a lock on the request list
709          */
710         if (request_list_busy) {
711                 got_chld = 1;
712                 return;
713         }
714         got_chld = 0;
715
716         /*
717          *      There are reports that this line on Solaris 2.5.x
718          *      caused trouble. Should be fixed now that Solaris
719          *      [defined(sun) && defined(__svr4__)] has it's own
720          *      sun_signal() function.
721          */
722         signal(SIGCHLD, sig_cleanup);
723
724         for (;;) {
725                 pid = waitpid((pid_t)-1, &status, WNOHANG);
726                 if (pid <= 0)
727                         return;
728
729                 if (pid == acct_pid)
730                         sig_fatal(100);
731
732                 curreq = first_request;
733                 while (curreq != (REQUEST *)NULL) {
734                         if (curreq->child_pid == pid) {
735                                 curreq->child_pid = -1;
736                                 /*
737                                  *      FIXME: UINT4 ?
738                                  */
739                                 curreq->timestamp = (UINT4)time(NULL);
740                                 break;
741                         }
742                         curreq = curreq->next;
743                 }
744         }
745 }
746
747 /*
748  *      Display the syntax for starting this program.
749  */
750 static void usage(void)
751 {
752         fprintf(stderr,
753 #if defined(WITH_DBM) || defined(WITH_NDBM)
754                 "Usage: %s [-a acct_dir] [-d db_dir] [-l logdir] [-bcsxyz]\n",
755 #else
756                 "Usage: %s [-a acct_dir] [-d db_dir] [-l logdir] [-csxyz]\n",
757 #endif
758                 progname);
759         exit(1);
760 }
761
762
763 /*
764  *      We got a fatal signal. Clean up and exit.
765  */
766 static void sig_fatal(int sig)
767 {
768         char *me = "MASTER: ";
769
770         if (radius_pid == getpid()) {
771                 /*
772                  *      FIXME: kill all children, not only the
773                  *      accounting process. Oh well..
774                  */
775                 if (acct_pid > 0)
776                         kill(acct_pid, SIGKILL);
777         } else {
778                 me = "CHILD: ";
779         }
780
781         switch(sig) {
782                 case 100:
783                         log(L_ERR, "%saccounting process died - exit.", me);
784                         break;
785                 case 101:
786                         log(L_ERR, "%sfailed in select() - exit.", me);
787                         break;
788                 case SIGTERM:
789                         log(L_INFO, "%sexit.", me);
790                         break;
791                 default:
792                         log(L_ERR, "%sexit on signal (%d)", me, sig);
793                         break;
794         }
795
796         exit(sig == SIGTERM ? 0 : 1);
797 }
798
799
800 /*
801  *      We got the hangup signal.
802  *      Re-read the configuration files.
803  */
804 /*ARGSUSED*/
805 static void sig_hup(int sig)
806 {
807         signal(SIGHUP, sig_hup);
808         need_reload = 1;
809 }
810