2 * radiusd.c Main loop of the radius server.
4 * Version: @(#)radiusd.c 1.90 22-Jul-1999 miquels@cistron.nl
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.";
14 #include <sys/types.h>
15 #include <sys/socket.h>
18 #include <netinet/in.h>
35 # include <sys/select.h>
47 int log_stripped_names;
52 int log_auth_detail = 0;
54 int log_auth_pass = 0;
58 static int got_chld = 0;
59 static int request_list_busy = 0;
62 static int spawn_flag;
64 static int radius_pid;
65 static int need_reload = 0;
66 static REQUEST *first_request;
68 #if !defined(__linux__) && !defined(__GNU_LIBRARY__)
72 typedef int (*FUNP)(REQUEST *, int);
74 static void usage(void);
76 static void sig_fatal (int);
77 static void sig_hup (int);
79 static int radrespond (REQUEST *, int);
80 static void rad_spawn_child (REQUEST *, int, FUNP);
85 static void reread_config(int reload)
91 log(L_INFO, "Starting - reading configuration files ...");
92 } else if (pid == radius_pid) {
93 log(L_INFO, "Reloading configuration files.");
96 /* Read users file etc. */
97 if (res == 0 && read_config_files() != 0)
101 if (pid == radius_pid) {
103 "Errors reading config file - EXITING");
105 signal(SIGCHLD, SIG_DFL);
106 kill(acct_pid, SIGTERM);
114 int main(int argc, char **argv)
118 RADIUS_PACKET *packet;
122 struct sockaddr salocal;
123 struct sockaddr_in *sin;
138 set_auth_parameters(argc,argv);
142 * Open /dev/null, and make sure filedescriptors
143 * 0, 1 and 2 are connected to something.
146 while (devnull >= 0 && devnull < 3)
147 devnull = open("/dev/null", O_RDWR);
149 if ((progname = strrchr(argv[0], '/')) == NULL)
156 radacct_dir = RADACCT_DIR;
157 radius_dir = RADIUS_DIR;
158 radlog_dir = RADLOG_DIR;
160 signal(SIGHUP, sig_hup);
161 signal(SIGINT, sig_fatal);
162 signal(SIGQUIT, sig_fatal);
164 signal(SIGTRAP, sig_fatal);
167 signal(SIGIOT, sig_fatal);
169 signal(SIGTERM, sig_fatal);
170 signal(SIGCHLD, sig_cleanup);
172 signal(SIGFPE, sig_fatal);
173 signal(SIGSEGV, sig_fatal);
174 signal(SIGILL, sig_fatal);
178 * Close unused file descriptors.
180 for (t = 32; t >= 3; t--)
181 if(t!=devnull) close(t);
184 * Process the options.
186 while((argval = getopt(argc, argv, "ASa:ci:l:d:bfp:svxyz")) != EOF) {
195 radacct_dir = optarg;
198 #if defined(WITH_DBM) || defined(WITH_NDBM)
216 if ((myip = ip_getaddr(optarg)) == 0) {
217 fprintf(stderr, "radiusd: %s: host unknown\n",
228 log_stripped_names++;
232 radius_port = atoi(optarg);
235 case 's': /* Single process mode */
263 * Open Authentication socket.
265 svp = getservbyname ("radius", "udp");
267 auth_port = radius_port;
268 else if (svp != NULL)
269 auth_port = ntohs(svp->s_port);
271 auth_port = PW_AUTH_UDP_PORT;
273 sockfd = socket (AF_INET, SOCK_DGRAM, 0);
275 perror("auth socket");
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);
285 result = bind (sockfd, & salocal, sizeof (*sin));
287 perror ("auth bind");
292 * Open Accounting Socket.
294 svp = getservbyname ("radacct", "udp");
295 if (radius_port || svp == (struct servent *) 0)
296 acct_port = auth_port + 1;
298 acct_port = ntohs(svp->s_port);
300 acctfd = socket (AF_INET, SOCK_DGRAM, 0);
302 perror ("acct socket");
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);
312 result = bind (acctfd, & salocal, sizeof (*sin));
314 perror ("acct bind");
318 radius_pid = getpid();
320 if ((fp = fopen(RADIUS_PID, "w")) != NULL) {
321 fprintf(fp, "%d\n", radius_pid);
331 * Register built-in compare functions.
333 pair_builtincompare_init();
336 * Connect 0, 1 and 2 to /dev/null.
338 if (!debug_flag && devnull >= 0) {
342 if (devnull > 2) close(devnull);
346 * Disconnect from session
348 if(debug_flag == 0 && dontfork == 0) {
351 log(L_ERR|L_CONS, "Couldn't fork");
362 * Use linebuffered or unbuffered stdout if
363 * the debug flag is on.
365 if (debug_flag) setlinebuf(stdout);
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.
375 log(L_ERR|L_CONS, "Couldn't fork");
381 log(L_INFO, "Ready to process requests.");
388 log(L_INFO, "Ready to process requests.");
392 * Receive user requests
399 if (getpid() == radius_pid && acct_pid)
400 kill(acct_pid, SIGHUP);
405 FD_SET(sockfd, &readfds);
407 FD_SET(acctfd, &readfds);
409 status = select(32, &readfds, NULL, NULL, NULL);
415 for (i = 0; i < 2; i++) {
417 if (i == 0) fd = sockfd;
418 if (i == 1) fd = acctfd;
419 if (fd < 0 || !FD_ISSET(fd, &readfds))
422 packet = rad_recv(fd);
423 if (packet == NULL) {
424 log(L_ERR, "%s", librad_errstr);
429 * See if we know this client.
431 if ((cl = client_find(packet->src_ipaddr)) == NULL) {
432 log(L_ERR, "request from unknown client: %s",
433 ip_hostname(packet->src_ipaddr));
437 if (rad_decode(packet, cl->secret) != 0) {
438 log(L_ERR, "%s", librad_errstr);
442 if ((request = malloc(sizeof(REQUEST))) == NULL) {
443 log(L_ERR|L_CONS, "no memory");
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);
457 * Respond to supported requests:
459 * PW_AUTHENTICATION_REQUEST - Authentication request from
460 * a client network access server.
462 * PW_ACCOUNTING_REQUEST - Accounting request from
463 * a client network access server.
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.
471 int radrespond(REQUEST *request, int activefd)
475 VALUE_PAIR *namepair;
482 * First, see if we need to proxy this request.
484 switch(request->packet->code) {
486 case PW_AUTHENTICATION_REQUEST:
487 case PW_ACCOUNTING_REQUEST:
489 * Setup username and stuff.
491 if ((e = rad_mangle(request)) < 0)
493 namepair = pairfind(request->packet->vps, PW_USER_NAME);
494 if (namepair == NULL)
497 * We always call proxy_send, it returns non-zero
498 * if it did actually proxy the request.
500 if (proxy_send(request, activefd) != 0)
504 case PW_AUTHENTICATION_ACK:
505 case PW_AUTHENTICATION_REJECT:
506 case PW_ACCOUNTING_RESPONSE:
507 if (proxy_receive(request, activefd) < 0)
513 * Select the required function and indicate if
514 * we need to fork off a child to handle it.
516 switch(request->packet->code) {
518 case PW_AUTHENTICATION_REQUEST:
519 dospawn = spawn_flag;
520 fun = rad_authenticate;
523 case PW_ACCOUNTING_REQUEST:
524 fun = rad_accounting;
527 case PW_PASSWORD_REQUEST:
529 * FIXME: print an error message here.
530 * We don't support this anymore.
532 /* rad_passchange(request, activefd); */
541 * If we did select a function, execute it
542 * (perhaps through rad_spawn_child)
546 rad_spawn_child(request, activefd, fun);
548 (*fun)(request, activefd);
549 request_free(request);
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).
564 static void rad_spawn_child(REQUEST *request, int activefd, FUNP fun)
573 curtime = (UINT4)time(NULL);
575 curreq = first_request;
576 prevreq = (REQUEST *)NULL;
577 pkt = request->packet;
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).
584 request_list_busy = 1;
586 while(curreq != (REQUEST *)NULL) {
587 if (curreq->child_pid == -1 &&
588 curreq->timestamp + CLEANUP_DELAY <= curtime) {
590 * Request completed, delete it
592 if (prevreq == (REQUEST *)NULL) {
593 first_request = curreq->next;
594 request_free(curreq);
595 curreq = first_request;
597 prevreq->next = curreq->next;
598 request_free(curreq);
599 curreq = prevreq->next;
601 } else if (curreq->packet->src_ipaddr == pkt->src_ipaddr &&
602 curreq->packet->id == pkt->id) {
604 * Compare the request vectors to see
605 * if it really is the same request.
607 if (!memcmp(curreq->packet->vector, pkt->vector, 16)) {
609 * This is a duplicate request - just drop it
612 "Dropping duplicate authentication packet"
613 " from client %s - ID: %d",
614 client_name(request->packet->src_ipaddr),
615 request->packet->id);
617 request_free(request);
618 request_list_busy = 0;
619 sig_cleanup(SIGCHLD);
624 * If the old request was completed,
625 * delete it right now.
627 if (curreq->child_pid == -1) {
628 curreq->timestamp = curtime - CLEANUP_DELAY;
633 * Not completed yet, do nothing special.
636 curreq = curreq->next;
639 if (curreq->timestamp + MAX_REQUEST_TIME <= curtime &&
640 curreq->child_pid != -1) {
642 * This request seems to have hung -
645 child_pid = curreq->child_pid;
647 "Killing unresponsive child pid %d",
649 curreq->child_pid = -1;
650 kill(child_pid, SIGTERM);
653 curreq = curreq->next;
659 * This is a new request
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);
668 request_list_busy = 0;
669 sig_cleanup(SIGCHLD);
675 * Add this request to the list
677 request->next = (REQUEST *)NULL;
678 request->child_pid = -1;
679 request->timestamp = curtime;
681 if (prevreq == (REQUEST *)NULL)
682 first_request = request;
684 prevreq->next = request;
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);
694 if (child_pid == 0) {
696 * This is the child, it should go ahead and respond
698 request_list_busy = 0;
699 signal(SIGCHLD, SIG_DFL);
700 (*fun)(request, activefd);
707 request->child_pid = child_pid;
709 request_list_busy = 0;
710 sig_cleanup(SIGCHLD);
715 void sig_cleanup(int sig)
722 * request_list_busy is a lock on the request list
724 if (request_list_busy) {
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.
736 signal(SIGCHLD, sig_cleanup);
739 pid = waitpid((pid_t)-1, &status, WNOHANG);
746 curreq = first_request;
747 while (curreq != (REQUEST *)NULL) {
748 if (curreq->child_pid == pid) {
749 curreq->child_pid = -1;
753 curreq->timestamp = (UINT4)time(NULL);
756 curreq = curreq->next;
762 * Display the syntax for starting this program.
764 static void usage(void)
767 #if defined(WITH_DBM) || defined(WITH_NDBM)
768 "Usage: %s [-a acct_dir] [-d db_dir] [-l logdir] [-bcsxyz]\n",
770 "Usage: %s [-a acct_dir] [-d db_dir] [-l logdir] [-csxyz]\n",
778 * We got a fatal signal. Clean up and exit.
780 static void sig_fatal(int sig)
782 char *me = "MASTER: ";
784 if (radius_pid == getpid()) {
786 * FIXME: kill all children, not only the
787 * accounting process. Oh well..
790 kill(acct_pid, SIGKILL);
797 log(L_ERR, "%saccounting process died - exit.", me);
800 log(L_ERR, "%sfailed in select() - exit.", me);
803 log(L_INFO, "%sexit.", me);
806 log(L_ERR, "%sexit on signal (%d)", me, sig);
810 exit(sig == SIGTERM ? 0 : 1);
815 * We got the hangup signal.
816 * Re-read the configuration files.
819 static void sig_hup(int sig)
821 signal(SIGHUP, sig_hup);