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