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;
137 set_auth_parameters(argc,argv);
140 if ((progname = strrchr(argv[0], '/')) == NULL)
147 radacct_dir = RADACCT_DIR;
148 radius_dir = RADIUS_DIR;
149 radlog_dir = RADLOG_DIR;
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);
159 signal(SIGFPE, sig_fatal);
160 signal(SIGSEGV, sig_fatal);
161 signal(SIGILL, sig_fatal);
165 * Close unused file descriptors.
167 for (t = 32; t >= 3; t--)
171 * Process the options.
173 while((argval = getopt(argc, argv, "ASa:ci:l:d:bfp:svxyz")) != EOF) {
182 radacct_dir = optarg;
185 #if defined(WITH_DBM) || defined(WITH_NDBM)
203 if ((myip = ip_getaddr(optarg)) == 0) {
204 fprintf(stderr, "radiusd: %s: host unknown\n",
215 log_stripped_names++;
219 radius_port = atoi(optarg);
222 case 's': /* Single process mode */
250 * Open Authentication socket.
252 svp = getservbyname ("radius", "udp");
254 auth_port = radius_port;
255 else if (svp != NULL)
256 auth_port = ntohs(svp->s_port);
258 auth_port = PW_AUTH_UDP_PORT;
260 sockfd = socket (AF_INET, SOCK_DGRAM, 0);
262 perror("auth socket");
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);
272 result = bind (sockfd, & salocal, sizeof (*sin));
274 perror ("auth bind");
279 * Open Accounting Socket.
281 svp = getservbyname ("radacct", "udp");
282 if (radius_port || svp == (struct servent *) 0)
283 acct_port = auth_port + 1;
285 acct_port = ntohs(svp->s_port);
287 acctfd = socket (AF_INET, SOCK_DGRAM, 0);
289 perror ("acct socket");
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);
299 result = bind (acctfd, & salocal, sizeof (*sin));
301 perror ("acct bind");
305 radius_pid = getpid();
307 if ((fp = fopen(RADIUS_PID, "w")) != NULL) {
308 fprintf(fp, "%d\n", radius_pid);
318 * Register built-in compare functions.
320 pair_builtincompare_init();
323 * Disconnect from session
325 if(debug_flag == 0 && dontfork == 0) {
328 log(L_ERR|L_CONS, "Couldn't fork");
339 * Use linebuffered or unbuffered stdout if
340 * the debug flag is on.
342 if (debug_flag) setlinebuf(stdout);
344 #if !defined(M_UNIX) && !defined(__linux__)
346 * Open system console as stderr
349 t = open("/dev/console", O_WRONLY | O_NOCTTY);
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.
364 log(L_ERR|L_CONS, "Couldn't fork");
370 log(L_INFO, "Ready to process requests.");
377 log(L_INFO, "Ready to process requests.");
381 * Receive user requests
388 if (getpid() == radius_pid && acct_pid)
389 kill(acct_pid, SIGHUP);
394 FD_SET(sockfd, &readfds);
396 FD_SET(acctfd, &readfds);
398 status = select(32, &readfds, NULL, NULL, NULL);
404 for (i = 0; i < 2; i++) {
406 if (i == 0) fd = sockfd;
407 if (i == 1) fd = acctfd;
408 if (fd < 0 || !FD_ISSET(fd, &readfds))
411 packet = rad_recv(fd);
412 if (packet == NULL) continue;
415 * See if we know this client.
417 if ((cl = client_find(packet->src_ipaddr)) == NULL) {
418 log(L_ERR, "request from unknown client: %s",
419 ip_hostname(packet->src_ipaddr));
423 if (rad_decode(packet, cl->secret) != 0) {
424 log(L_ERR, "%s", librad_errstr);
428 if ((request = malloc(sizeof(REQUEST))) == NULL) {
429 log(L_ERR|L_CONS, "no memory");
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);
443 * Respond to supported requests:
445 * PW_AUTHENTICATION_REQUEST - Authentication request from
446 * a client network access server.
448 * PW_ACCOUNTING_REQUEST - Accounting request from
449 * a client network access server.
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.
457 int radrespond(REQUEST *request, int activefd)
461 VALUE_PAIR *namepair;
468 * First, see if we need to proxy this request.
470 switch(request->packet->code) {
472 case PW_AUTHENTICATION_REQUEST:
473 case PW_ACCOUNTING_REQUEST:
475 * Setup username and stuff.
477 if ((e = rad_mangle(request)) < 0)
479 namepair = pairfind(request->packet->vps, PW_USER_NAME);
480 if (namepair == NULL)
483 * We always call proxy_send, it returns non-zero
484 * if it did actually proxy the request.
486 if (proxy_send(request, activefd) != 0)
490 case PW_AUTHENTICATION_ACK:
491 case PW_AUTHENTICATION_REJECT:
492 case PW_ACCOUNTING_RESPONSE:
493 if (proxy_receive(request, activefd) < 0)
499 * Select the required function and indicate if
500 * we need to fork off a child to handle it.
502 switch(request->packet->code) {
504 case PW_AUTHENTICATION_REQUEST:
505 dospawn = spawn_flag;
506 fun = rad_authenticate;
509 case PW_ACCOUNTING_REQUEST:
510 fun = rad_accounting;
513 case PW_PASSWORD_REQUEST:
515 * FIXME: print an error message here.
516 * We don't support this anymore.
518 /* rad_passchange(request, activefd); */
527 * If we did select a function, execute it
528 * (perhaps through rad_spawn_child)
532 rad_spawn_child(request, activefd, fun);
534 (*fun)(request, activefd);
535 request_free(request);
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).
550 static void rad_spawn_child(REQUEST *request, int activefd, FUNP fun)
559 curtime = (UINT4)time(NULL);
561 curreq = first_request;
562 prevreq = (REQUEST *)NULL;
563 pkt = request->packet;
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).
570 request_list_busy = 1;
572 while(curreq != (REQUEST *)NULL) {
573 if (curreq->child_pid == -1 &&
574 curreq->timestamp + CLEANUP_DELAY <= curtime) {
576 * Request completed, delete it
578 if (prevreq == (REQUEST *)NULL) {
579 first_request = curreq->next;
580 request_free(curreq);
581 curreq = first_request;
583 prevreq->next = curreq->next;
584 request_free(curreq);
585 curreq = prevreq->next;
587 } else if (curreq->packet->src_ipaddr == pkt->src_ipaddr &&
588 curreq->packet->id == pkt->id) {
590 * Compare the request vectors to see
591 * if it really is the same request.
593 if (!memcmp(curreq->packet->vector, pkt->vector, 16)) {
595 * This is a duplicate request - just drop it
598 "Dropping duplicate authentication packet"
599 " from client %s - ID: %d",
600 client_name(request->packet->src_ipaddr),
601 request->packet->id);
603 request_free(request);
604 request_list_busy = 0;
605 sig_cleanup(SIGCHLD);
610 * If the old request was completed,
611 * delete it right now.
613 if (curreq->child_pid == -1) {
614 curreq->timestamp = curtime - CLEANUP_DELAY;
619 * Not completed yet, do nothing special.
622 curreq = curreq->next;
625 if (curreq->timestamp + MAX_REQUEST_TIME <= curtime &&
626 curreq->child_pid != -1) {
628 * This request seems to have hung -
631 child_pid = curreq->child_pid;
633 "Killing unresponsive child pid %d",
635 curreq->child_pid = -1;
636 kill(child_pid, SIGTERM);
639 curreq = curreq->next;
645 * This is a new request
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);
654 request_list_busy = 0;
655 sig_cleanup(SIGCHLD);
661 * Add this request to the list
663 request->next = (REQUEST *)NULL;
664 request->child_pid = -1;
665 request->timestamp = curtime;
667 if (prevreq == (REQUEST *)NULL)
668 first_request = request;
670 prevreq->next = request;
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);
680 if (child_pid == 0) {
682 * This is the child, it should go ahead and respond
684 request_list_busy = 0;
685 signal(SIGCHLD, SIG_DFL);
686 (*fun)(request, activefd);
693 request->child_pid = child_pid;
695 request_list_busy = 0;
696 sig_cleanup(SIGCHLD);
701 void sig_cleanup(int sig)
708 * request_list_busy is a lock on the request list
710 if (request_list_busy) {
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.
722 signal(SIGCHLD, sig_cleanup);
725 pid = waitpid((pid_t)-1, &status, WNOHANG);
732 curreq = first_request;
733 while (curreq != (REQUEST *)NULL) {
734 if (curreq->child_pid == pid) {
735 curreq->child_pid = -1;
739 curreq->timestamp = (UINT4)time(NULL);
742 curreq = curreq->next;
748 * Display the syntax for starting this program.
750 static void usage(void)
753 #if defined(WITH_DBM) || defined(WITH_NDBM)
754 "Usage: %s [-a acct_dir] [-d db_dir] [-l logdir] [-bcsxyz]\n",
756 "Usage: %s [-a acct_dir] [-d db_dir] [-l logdir] [-csxyz]\n",
764 * We got a fatal signal. Clean up and exit.
766 static void sig_fatal(int sig)
768 char *me = "MASTER: ";
770 if (radius_pid == getpid()) {
772 * FIXME: kill all children, not only the
773 * accounting process. Oh well..
776 kill(acct_pid, SIGKILL);
783 log(L_ERR, "%saccounting process died - exit.", me);
786 log(L_ERR, "%sfailed in select() - exit.", me);
789 log(L_INFO, "%sexit.", me);
792 log(L_ERR, "%sexit on signal (%d)", me, sig);
796 exit(sig == SIGTERM ? 0 : 1);
801 * We got the hangup signal.
802 * Re-read the configuration files.
805 static void sig_hup(int sig)
807 signal(SIGHUP, sig_hup);