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