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);
163 signal(SIGTRAP, sig_fatal);
164 signal(SIGIOT, sig_fatal);
165 signal(SIGTERM, sig_fatal);
166 signal(SIGCHLD, sig_cleanup);
168 signal(SIGFPE, sig_fatal);
169 signal(SIGSEGV, sig_fatal);
170 signal(SIGILL, sig_fatal);
174 * Close unused file descriptors.
176 for (t = 32; t >= 3; t--)
177 if(t!=devnull) close(t);
180 * Process the options.
182 while((argval = getopt(argc, argv, "ASa:ci:l:d:bfp:svxyz")) != EOF) {
191 radacct_dir = optarg;
194 #if defined(WITH_DBM) || defined(WITH_NDBM)
212 if ((myip = ip_getaddr(optarg)) == 0) {
213 fprintf(stderr, "radiusd: %s: host unknown\n",
224 log_stripped_names++;
228 radius_port = atoi(optarg);
231 case 's': /* Single process mode */
259 * Open Authentication socket.
261 svp = getservbyname ("radius", "udp");
263 auth_port = radius_port;
264 else if (svp != NULL)
265 auth_port = ntohs(svp->s_port);
267 auth_port = PW_AUTH_UDP_PORT;
269 sockfd = socket (AF_INET, SOCK_DGRAM, 0);
271 perror("auth socket");
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);
281 result = bind (sockfd, & salocal, sizeof (*sin));
283 perror ("auth bind");
288 * Open Accounting Socket.
290 svp = getservbyname ("radacct", "udp");
291 if (radius_port || svp == (struct servent *) 0)
292 acct_port = auth_port + 1;
294 acct_port = ntohs(svp->s_port);
296 acctfd = socket (AF_INET, SOCK_DGRAM, 0);
298 perror ("acct socket");
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);
308 result = bind (acctfd, & salocal, sizeof (*sin));
310 perror ("acct bind");
314 radius_pid = getpid();
316 if ((fp = fopen(RADIUS_PID, "w")) != NULL) {
317 fprintf(fp, "%d\n", radius_pid);
327 * Register built-in compare functions.
329 pair_builtincompare_init();
332 * Connect 0, 1 and 2 to /dev/null.
334 if (!debug_flag && devnull >= 0) {
338 if (devnull > 2) close(devnull);
342 * Disconnect from session
344 if(debug_flag == 0 && dontfork == 0) {
347 log(L_ERR|L_CONS, "Couldn't fork");
358 * Use linebuffered or unbuffered stdout if
359 * the debug flag is on.
361 if (debug_flag) setlinebuf(stdout);
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.
371 log(L_ERR|L_CONS, "Couldn't fork");
377 log(L_INFO, "Ready to process requests.");
384 log(L_INFO, "Ready to process requests.");
388 * Receive user requests
395 if (getpid() == radius_pid && acct_pid)
396 kill(acct_pid, SIGHUP);
401 FD_SET(sockfd, &readfds);
403 FD_SET(acctfd, &readfds);
405 status = select(32, &readfds, NULL, NULL, NULL);
411 for (i = 0; i < 2; i++) {
413 if (i == 0) fd = sockfd;
414 if (i == 1) fd = acctfd;
415 if (fd < 0 || !FD_ISSET(fd, &readfds))
418 packet = rad_recv(fd);
419 if (packet == NULL) {
420 log(L_ERR, "%s", librad_errstr);
425 * See if we know this client.
427 if ((cl = client_find(packet->src_ipaddr)) == NULL) {
428 log(L_ERR, "request from unknown client: %s",
429 ip_hostname(packet->src_ipaddr));
433 if (rad_decode(packet, cl->secret) != 0) {
434 log(L_ERR, "%s", librad_errstr);
438 if ((request = malloc(sizeof(REQUEST))) == NULL) {
439 log(L_ERR|L_CONS, "no memory");
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);
453 * Respond to supported requests:
455 * PW_AUTHENTICATION_REQUEST - Authentication request from
456 * a client network access server.
458 * PW_ACCOUNTING_REQUEST - Accounting request from
459 * a client network access server.
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.
467 int radrespond(REQUEST *request, int activefd)
471 VALUE_PAIR *namepair;
478 * First, see if we need to proxy this request.
480 switch(request->packet->code) {
482 case PW_AUTHENTICATION_REQUEST:
483 case PW_ACCOUNTING_REQUEST:
485 * Setup username and stuff.
487 if ((e = rad_mangle(request)) < 0)
489 namepair = pairfind(request->packet->vps, PW_USER_NAME);
490 if (namepair == NULL)
493 * We always call proxy_send, it returns non-zero
494 * if it did actually proxy the request.
496 if (proxy_send(request, activefd) != 0)
500 case PW_AUTHENTICATION_ACK:
501 case PW_AUTHENTICATION_REJECT:
502 case PW_ACCOUNTING_RESPONSE:
503 if (proxy_receive(request, activefd) < 0)
509 * Select the required function and indicate if
510 * we need to fork off a child to handle it.
512 switch(request->packet->code) {
514 case PW_AUTHENTICATION_REQUEST:
515 dospawn = spawn_flag;
516 fun = rad_authenticate;
519 case PW_ACCOUNTING_REQUEST:
520 fun = rad_accounting;
523 case PW_PASSWORD_REQUEST:
525 * FIXME: print an error message here.
526 * We don't support this anymore.
528 /* rad_passchange(request, activefd); */
537 * If we did select a function, execute it
538 * (perhaps through rad_spawn_child)
542 rad_spawn_child(request, activefd, fun);
544 (*fun)(request, activefd);
545 request_free(request);
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).
560 static void rad_spawn_child(REQUEST *request, int activefd, FUNP fun)
569 curtime = (UINT4)time(NULL);
571 curreq = first_request;
572 prevreq = (REQUEST *)NULL;
573 pkt = request->packet;
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).
580 request_list_busy = 1;
582 while(curreq != (REQUEST *)NULL) {
583 if (curreq->child_pid == -1 &&
584 curreq->timestamp + CLEANUP_DELAY <= curtime) {
586 * Request completed, delete it
588 if (prevreq == (REQUEST *)NULL) {
589 first_request = curreq->next;
590 request_free(curreq);
591 curreq = first_request;
593 prevreq->next = curreq->next;
594 request_free(curreq);
595 curreq = prevreq->next;
597 } else if (curreq->packet->src_ipaddr == pkt->src_ipaddr &&
598 curreq->packet->id == pkt->id) {
600 * Compare the request vectors to see
601 * if it really is the same request.
603 if (!memcmp(curreq->packet->vector, pkt->vector, 16)) {
605 * This is a duplicate request - just drop it
608 "Dropping duplicate authentication packet"
609 " from client %s - ID: %d",
610 client_name(request->packet->src_ipaddr),
611 request->packet->id);
613 request_free(request);
614 request_list_busy = 0;
615 sig_cleanup(SIGCHLD);
620 * If the old request was completed,
621 * delete it right now.
623 if (curreq->child_pid == -1) {
624 curreq->timestamp = curtime - CLEANUP_DELAY;
629 * Not completed yet, do nothing special.
632 curreq = curreq->next;
635 if (curreq->timestamp + MAX_REQUEST_TIME <= curtime &&
636 curreq->child_pid != -1) {
638 * This request seems to have hung -
641 child_pid = curreq->child_pid;
643 "Killing unresponsive child pid %d",
645 curreq->child_pid = -1;
646 kill(child_pid, SIGTERM);
649 curreq = curreq->next;
655 * This is a new request
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);
664 request_list_busy = 0;
665 sig_cleanup(SIGCHLD);
671 * Add this request to the list
673 request->next = (REQUEST *)NULL;
674 request->child_pid = -1;
675 request->timestamp = curtime;
677 if (prevreq == (REQUEST *)NULL)
678 first_request = request;
680 prevreq->next = request;
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);
690 if (child_pid == 0) {
692 * This is the child, it should go ahead and respond
694 request_list_busy = 0;
695 signal(SIGCHLD, SIG_DFL);
696 (*fun)(request, activefd);
703 request->child_pid = child_pid;
705 request_list_busy = 0;
706 sig_cleanup(SIGCHLD);
711 void sig_cleanup(int sig)
718 * request_list_busy is a lock on the request list
720 if (request_list_busy) {
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.
732 signal(SIGCHLD, sig_cleanup);
735 pid = waitpid((pid_t)-1, &status, WNOHANG);
742 curreq = first_request;
743 while (curreq != (REQUEST *)NULL) {
744 if (curreq->child_pid == pid) {
745 curreq->child_pid = -1;
749 curreq->timestamp = (UINT4)time(NULL);
752 curreq = curreq->next;
758 * Display the syntax for starting this program.
760 static void usage(void)
763 #if defined(WITH_DBM) || defined(WITH_NDBM)
764 "Usage: %s [-a acct_dir] [-d db_dir] [-l logdir] [-bcsxyz]\n",
766 "Usage: %s [-a acct_dir] [-d db_dir] [-l logdir] [-csxyz]\n",
774 * We got a fatal signal. Clean up and exit.
776 static void sig_fatal(int sig)
778 char *me = "MASTER: ";
780 if (radius_pid == getpid()) {
782 * FIXME: kill all children, not only the
783 * accounting process. Oh well..
786 kill(acct_pid, SIGKILL);
793 log(L_ERR, "%saccounting process died - exit.", me);
796 log(L_ERR, "%sfailed in select() - exit.", me);
799 log(L_INFO, "%sexit.", me);
802 log(L_ERR, "%sexit on signal (%d)", me, sig);
806 exit(sig == SIGTERM ? 0 : 1);
811 * We got the hangup signal.
812 * Re-read the configuration files.
815 static void sig_hup(int sig)
817 signal(SIGHUP, sig_hup);