1 /* This file is part of GNU Radius.
2    Copyright (C) 2000,2001,2002,2003,2004,2005,2007,
3    2008 Free Software Foundation
4 
5    GNU Radius is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9 
10    GNU Radius is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with GNU Radius; if not, write to the Free Software Foundation,
17    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <netinet/in.h>
25 #include <netdb.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <sys/wait.h>
33 
34 #include <radiusd.h>
35 #include <radius/radargp.h>
36 #include <radius/radutmp.h>
37 #include <radius/argcv.h>
38 #include <rewrite.h>
39 #include <snmp/asn1.h>
40 #include <snmp/snmp.h>
41 #include <timestr.h>
42 
43 const char *argp_program_version = "radiusd (" PACKAGE ") " VERSION;
44 static char doc[] = N_("GNU radius daemon");
45 
46 #define SHOW_DEFAULTS_OPTION 256
47 #define SELECT_PORTS_OPTION 257
48 
49 static struct argp_option options[] = {
50 #define GRP 100
51         {NULL, 0, NULL, 0,
52          N_("radiusd specific switches:"), GRP},
53         {"foreground", 'f', NULL, 0,
54          N_("Stay in foreground"), GRP+1},
55         {"mode", 'm', "{t|c|b}", 0,
56          N_("Select operation mode: test, checkconf, builddbm."), GRP+1},
57         {"single-process", 's', NULL, 0,
58          N_("Run in single process mode"), GRP+1},
59         {"pid-file-dir", 'P', N_("DIR"), 0,
60          N_("Store pidfile in DIR"), GRP+1},
61 	{"show-defaults", SHOW_DEFAULTS_OPTION, NULL, 0,
62 	 N_("Show compilation defaults"), GRP+1},
63 	{"quiet", 'q', NULL, 0,
64 	 N_("Quiet mode (valid only with --mode)"), GRP+1},
65 	{"select-free-ports", SELECT_PORTS_OPTION, N_("FILE"), 0,
66 	 N_("Select port numbers from available UDP ports"), GRP+1 },
67 #undef GRP
68 #define GRP 200
69 	{NULL, 0, NULL, 0,
70          N_("Daemon configuration options. Please use raddb/config instead."),
71 	 GRP},
72 
73         {"log-auth-detail", 'A', 0, 0,
74          N_("Do detailed authentication logging"), GRP+1},
75         {"acct-directory",  'a', N_("DIR"), 0,
76          N_("Set accounting directory"), GRP+1},
77 #ifdef USE_DBM
78         {"dbm", 'b', NULL, 0,
79          N_("Enable DBM support"), GRP+1},
80 #endif
81         {"logging-directory", 'l', N_("DIR"), 0,
82          N_("Set logging directory name"), GRP+1},
83         {"do-not-resolve", 'n', NULL, 0,
84          N_("Do not resolve IP addresses"), GRP+1},
85         {"ip-address", 'i', N_("IPADDR"), 0,
86          N_("Listen on IPADDR"), GRP+1},
87         {"port", 'p', "NUMBER", 0,
88          N_("Set authentication port number"), GRP+1},
89         {"log-stripped-names", 'S', NULL, 0,
90          N_("Strip prefixes/suffixes off user names before logging"), GRP+1},
91         {"debug", 'x', N_("DEBUGSPEC"), 0,
92          N_("Set debugging level"), GRP+1},
93         {"log-auth", 'y', NULL, 0,
94          N_("Log authentications"), GRP+1},
95         {"log-auth-pass", 'z', NULL, 0,
96          N_("Log users' passwords"), GRP+1},
97 #undef GRP
98         {NULL, 0, NULL, 0, NULL, 0}
99 };
100 
101 
102 /* *************************** Global Variables **************************** */
103 
104 int        debug_flag;     /* can be raised from debugger only */
105 int        log_mode;       /* logging mode */
106 int        console_logging_priority = -1; /* Default priority for console
107 					     logging */
108 char       *auth_log_hook; /* Authentication logging hook function */
109 
110 static int foreground; /* Stay in the foreground */
111 int spawn_flag;        /* Whether to spawn new children for handling
112 			  the requests */
113 
114 int use_dbm = 0;       /* Use DBM storage */
115 int auth_detail = 0;   /* Produce detailed logs of authentication packets */
116 char *auth_detail_template; /* Template for filenames of these logs */
117 int acct_detail = 1;   /* Produce detailed logs of accounting packets */
118 char *acct_detail_template; /* Template for filenames of these logs */
119 int acct_system = 1;   /* Run system accounting into radutmp/radwtmp files */
120 int auth_trace_rules = 0; /* Produce trace logs for each auth request */
121 int acct_trace_rules = 0; /* Produce trace logs for each acct request */
122 int strip_names;          /* Strip preffixes/suffixes off the usernames */
123 int suspend_flag;         /* Suspend processing of RADIUS requests */
124 int auth_reject_malformed_names = 0; /* Respond with Access-Reject packets
125 					for requests with malformed user
126 					names */
127 
128 char *select_free_ports;
129 FILE *port_file;
130 
131 RADIUS_USER radiusd_user; /* Run the daemon with this user privileges */
132 RADIUS_USER exec_user;    /* Run the user programs with this user privileges */
133 
134 #define CMD_NONE     0 /* No command */
135 #define CMD_CLEANUP  1 /* Cleanup finished children */
136 #define CMD_RELOAD   2 /* The reload of the configuration is needed */
137 #define CMD_RESTART  3 /* Try to restart */
138 #define CMD_MEMINFO  4 /* Dump memory usage statistics */
139 #define CMD_DUMPDB   5 /* Dump authentication database */
140 #define CMD_SHUTDOWN 6 /* Stop immediately */
141 #define CMD_SUSPEND  7 /* Suspend service */
142 #define CMD_CONTINUE 8 /* Continue after suspend */
143 
144 int daemon_command = CMD_NONE;
145 
146 static INPUT *radius_input;   /* The input channels */
147 
148 #ifdef USE_SNMP
149 int snmp_port;
150 serv_stat saved_status;
151 #endif
152 
153                     /* These are the user flag marking attributes that
154 		       can be used in comparing ... */
155 int auth_comp_flag; /* ... authentication requests */
156 int acct_comp_flag; /* ... accounting requests */
157 
158 int checkrad_assume_logged = 1;
159 size_t max_requests = MAX_REQUESTS;
160 size_t max_children = MAX_CHILDREN;
161 unsigned process_timeout = PROCESS_TIMEOUT;
162 unsigned radiusd_write_timeout = RADIUSD_WRITE_TIMEOUT;
163 unsigned radiusd_read_timeout = RADIUSD_READ_TIMEOUT;
164 
165 grad_uint32_t warning_seconds;
166 int use_guile;
167 char *message_text[MSG_COUNT];
168 grad_uint32_t myip = INADDR_ANY;
169 grad_uint32_t ref_ip = INADDR_ANY;
170 int auth_port;
171 int acct_port;
172 
173 pid_t radiusd_pid;
174 int radius_mode = MODE_DAEMON;
175 
176 /* Invocation vector for self-restart */
177 int  xargc;
178 char **xargv;
179 char *x_debug_spec;
180 
181 /* Forward declarations */
182 static RETSIGTYPE sig_handler(int sig);
183 void radiusd_main_loop();
184 static size_t radius_count_channels();
185 void radiusd_run_preconfig_hooks(void *data);
186 struct cfg_stmt config_syntax[];
187 
188 
189 /* ************************ Command Line Parser **************************** */
190 
191 static error_t
parse_opt(int key,char * arg,struct argp_state * state)192 parse_opt(int key, char *arg, struct argp_state *state)
193 {
194         switch (key) {
195         case 'A':
196                 auth_detail++;
197                 break;
198 
199         case 'a':
200                 grad_acct_dir = grad_estrdup(arg);
201                 break;
202 
203 #ifdef USE_DBM
204         case 'b':
205                 use_dbm++;
206                 break;
207 #endif
208 
209         case 'f':
210                 foreground = 1;
211                 break;
212 
213         case 'l':
214                 grad_log_dir = grad_estrdup(arg);
215                 break;
216 
217         case 'm':
218                 switch (arg[0]) {
219                 case 't':
220                         radius_mode = MODE_TEST;
221                         break;
222 
223                 case 'b':
224 #ifdef USE_DBM
225                         radius_mode = MODE_BUILDDBM;
226 #else
227                         argp_error(state,
228 				   _("radiusd compiled without DBM support"));
229                         exit(1);
230 #endif
231                         break;
232 
233                 case 'c':
234                         radius_mode = MODE_CHECKCONF;
235                         break;
236 
237                 default:
238                         argp_error(state, _("unknown mode: %s"), arg);
239 			exit(1);
240 		}
241                 break;
242 
243         case 'n':
244                 grad_resolve_hostnames = 0;
245                 break;
246 
247         case 'i':
248                 if ((myip = grad_ip_gethostaddr(arg)) == 0)
249                         fprintf(stderr,
250                                 _("invalid IP address: %s"),
251                                 arg);
252                 break;
253 
254         case 'P':
255                 grad_pid_dir = arg;
256                 break;
257 
258         case 'p':
259                 auth_port = atoi(arg);
260 		acct_port = auth_port+1;
261                 break;
262 
263 	case 'q':
264 		console_logging_priority = GRAD_LOG_ERR;
265 		break;
266 
267         case 'S':
268                 strip_names++;
269                 break;
270 
271         case 's':       /* Single process mode */
272                 spawn_flag = 0;
273                 break;
274 
275 	case SELECT_PORTS_OPTION:
276 		select_free_ports = arg;
277 		break;
278 
279         case 'x':
280                 x_debug_spec = arg;
281                 grad_set_debug_levels(arg);
282                 break;
283 
284         case 'y':
285                 log_mode |= RLOG_AUTH;
286                 break;
287 
288         case 'z':
289                 log_mode |= RLOG_AUTH_PASS;
290                 break;
291 
292 	case SHOW_DEFAULTS_OPTION:
293 		show_compilation_defaults();
294 		exit(0);
295 
296         default:
297                 return ARGP_ERR_UNKNOWN;
298         }
299         return 0;
300 }
301 
302 static struct argp argp = {
303         options,
304         parse_opt,
305         NULL,
306         doc,
307         grad_common_argp_child,
308         NULL, NULL
309 };
310 
311 
312 /* *********************** Configuration Functions ************************* */
313 void
set_config_defaults()314 set_config_defaults()
315 {
316         username_valid_chars = grad_estrdup(".-_!@#$%^&\\/");
317         message_text[MSG_ACCOUNT_CLOSED] =
318                 grad_estrdup(_("Sorry, your account is currently closed\n"));
319         message_text[MSG_PASSWORD_EXPIRED] =
320                 grad_estrdup(_("Password has expired\n"));
321         message_text[MSG_PASSWORD_EXPIRE_WARNING] =
322                 grad_estrdup(_("Password will expire in %R{Password-Expire-Days} Days\n"));
323         message_text[MSG_ACCESS_DENIED] =
324                 grad_estrdup(_("\nAccess denied\n"));
325         message_text[MSG_REALM_QUOTA] =
326                 grad_estrdup(_("\nRealm quota exceeded - access denied\n"));
327         message_text[MSG_MULTIPLE_LOGIN] =
328                 grad_estrdup(_("\nYou are already logged in %R{Simultaneous-Use} times - access denied\n"));
329         message_text[MSG_SECOND_LOGIN] =
330                 grad_estrdup(_("\nYou are already logged in - access denied\n"));
331         message_text[MSG_TIMESPAN_VIOLATION] =
332                 grad_estrdup(_("You are calling outside your allowed timespan\n"));
333 }
334 
335 static int
get_port_number(char * name,char * proto,int defval)336 get_port_number(char *name, char *proto, int defval)
337 {
338         struct servent *svp;
339 
340 	svp = getservbyname(name, proto);
341 	return svp ? ntohs(svp->s_port) : defval;
342 }
343 
344 unsigned
max_ttl(time_t * t)345 max_ttl(time_t *t)
346 {
347 	unsigned i, delta = 0;
348 
349 	for (i = 0; i < R_MAX; i++)
350 		if (delta < request_class[i].ttl)
351 			delta = request_class[i].ttl;
352 	if (t) {
353 		time(t);
354 		*t += delta;
355 	}
356 	return delta;
357 }
358 
359 static void
terminate_subprocesses()360 terminate_subprocesses()
361 {
362 	int kill_sent = 0;
363 	time_t t;
364 
365         /* Flush any pending requests and empty the request queue */
366 	radiusd_flush_queue();
367 	request_init_queue();
368 
369 	/* Terminate all subprocesses */
370 	grad_log(GRAD_LOG_INFO, _("Terminating the subprocesses"));
371 	rpp_kill(-1, SIGTERM);
372 
373 	max_ttl(&t);
374 
375 	while (rpp_count()) {
376 		sleep(1);
377 		radiusd_cleanup();
378 		if (time(NULL) >= t) {
379 			if (kill_sent) {
380 				int n = rpp_count();
381 				grad_log(GRAD_LOG_CRIT,
382 				         ngettext("%d process left!",
383 					 	  "%d processes left!",
384 						  n),
385 				         n);
386 				break;
387 			}
388 			max_ttl(&t);
389 			rpp_kill(-1, SIGKILL);
390 			kill_sent = 1;
391 		}
392 	}
393 }
394 
395 static void
radiusd_preconfig_hook(void * a ARG_UNUSED,void * b ARG_UNUSED)396 radiusd_preconfig_hook(void *a ARG_UNUSED, void *b ARG_UNUSED)
397 {
398 	terminate_subprocesses();
399 	input_close_channels(radius_input);
400 }
401 
402 static void
radiusd_postconfig_hook(void * a ARG_UNUSED,void * b ARG_UNUSED)403 radiusd_postconfig_hook(void *a ARG_UNUSED, void *b ARG_UNUSED)
404 {
405 	if (radius_mode == MODE_DAEMON && radius_count_channels() == 0) {
406 		if (foreground) {
407 			grad_log(GRAD_LOG_ALERT,
408 			         _("Radiusd is not listening on any port."));
409 			exit(1);
410 		} else
411 			grad_log(GRAD_LOG_ALERT,
412 			         _("Radiusd is not listening on any port. Trying to continue anyway..."));
413 	}
414 }
415 
416 static void
daemon_postconfig_hook(void * a ARG_UNUSED,void * b ARG_UNUSED)417 daemon_postconfig_hook(void *a ARG_UNUSED, void *b ARG_UNUSED)
418 {
419 	system_acct_init();
420 }
421 
422 void
radiusd_setup()423 radiusd_setup()
424 {
425 	int i;
426 
427 	/* Close unneeded file descriptors */
428         for (i = grad_max_fd(); i >= 3; i--)
429                 close(i);
430         /* Determine default port numbers for authentication and accounting */
431 	if (auth_port == 0)
432 		auth_port = get_port_number("radius", "udp", DEF_AUTH_PORT);
433 	if (acct_port == 0)
434 		acct_port = get_port_number("radacct", "udp", auth_port+1);
435 #ifdef USE_SNMP
436 	snmp_port = get_port_number("snmp", "udp", 161);
437 #endif
438         srand(time(NULL));
439 
440 #ifdef HAVE_CRYPT_SET_FORMAT
441 	/* MD5 hashes are handled by libgnuradius function md5crypt(). To
442 	   handle DES hashes it falls back to system crypt(). The behaviour
443 	   of the latter on FreeBSD depends upon a 'default format'. so e.g.
444 	   crypt() may generate MD5 hashes even if presented with a valid
445 	   MD5 salt.
446 
447 	   To make sure this does not happen, we need to set the default
448 	   crypt() format. */
449 
450 	crypt_set_format("des");
451 #endif
452 
453 	/* Register radiusd hooks first. This ensures they will be
454 	   executed after all other hooks */
455 	radiusd_set_preconfig_hook(radiusd_preconfig_hook, NULL, 0);
456 	radiusd_set_postconfig_hook(radiusd_postconfig_hook, NULL, 0);
457 
458 	rewrite_init();
459 	dynload_init();
460         snmp_init(0, 0, (snmp_alloc_t)grad_emalloc, (snmp_free_t)grad_free);
461 	mlc_init();
462 	sql_init();
463 }
464 
465 void
common_init()466 common_init()
467 {
468 	grad_log(GRAD_LOG_INFO, _("Starting"));
469 
470 	radiusd_pid = getpid();
471 	radius_input = input_create();
472 	input_register_method(radius_input, "rpp", 0,
473 			      rpp_input_handler,
474 			      rpp_input_close,
475 			      NULL);
476 	input_register_method(radius_input, "udp", 1,
477 			      udp_input_handler,
478 			      udp_input_close,
479 			      udp_input_cmp);
480 #ifdef HAVE_SETVBUF
481         setvbuf(stdout, NULL, _IOLBF, 0);
482 #endif
483 	radiusd_signal_init(sig_handler);
484 	forward_init();
485 #ifdef USE_SNMP
486         snmpserv_init(&saved_status);
487 #endif
488 	acct_init();
489 	if (select_free_ports) {
490 		port_file = fopen(select_free_ports, "w");
491 		if (!port_file) {
492 			grad_log(GRAD_LOG_CRIT|GRAD_LOG_PERROR,
493 				 _("Cannot open output file %s"),
494 				 select_free_ports);
495 			exit(1);
496 		}
497 	}
498 
499 	radiusd_reconfigure();
500 
501 	if (port_file) {
502 		fclose(port_file);
503 		port_file = NULL;
504 		select_free_ports = NULL;
505 	}
506 
507 	grad_log(GRAD_LOG_INFO, _("Ready"));
508 }
509 
510 
511 /* ************************** Core of radiusd ****************************** */
512 void
radiusd_daemon()513 radiusd_daemon()
514 {
515         char *p;
516         int i;
517         pid_t pid;
518 
519         switch (pid = fork()) {
520         case -1:
521                 grad_log(GRAD_LOG_CRIT|GRAD_LOG_PERROR, "fork");
522                 exit(1);
523         case 0: /* Child */
524                 break;
525         default: /* Parent */
526                 exit(0);
527         }
528 
529 #ifdef HAVE_SETSID
530         setsid();
531 #endif
532         /* SIGHUP is ignored because when the session leader terminates
533            all process in the session are sent the SIGHUP.  */
534         grad_set_signal(SIGHUP, SIG_IGN);
535 
536         /* fork() again so the parent, can exit. This means that we, as a
537            non-session group leader, can never regain a controlling
538            terminal. */
539         switch (pid = fork()) {
540         case 0:
541                 break;
542         case -1:
543                 grad_log(GRAD_LOG_CRIT|GRAD_LOG_PERROR, "fork");
544                 exit(1);
545         default:
546                 exit(0);
547         }
548 
549         /* This is needed for messages generated by guile
550            functions.
551 	   FIXME: The compiled-in value of grad_log_dir is used */
552         p = grad_mkfilename(grad_log_dir, "radius.stderr");
553         i = open(p, O_CREAT|O_WRONLY, 0644);
554         if (i != -1) {
555                 if (i != 2)
556                         dup2(i, 2);
557                 if (i != 1)
558                         dup2(i, 1);
559                 if (i != 1 && i != 2)
560                         close(i);
561                 fflush(stdout);
562                 fflush(stderr);
563         }
564         grad_free(p);
565 }
566 
567 int
radiusd_master()568 radiusd_master()
569 {
570 	return radiusd_pid == getpid();
571 }
572 
573 
574 /* ****************************** Main function **************************** */
575 
576 void
radiusd_main()577 radiusd_main()
578 {
579         switch (radius_mode) {
580         case MODE_CHECKCONF:
581                 common_init();
582                 exit(0);
583 
584         case MODE_TEST:
585                 common_init();
586                 tsh();
587 
588 #ifdef USE_DBM
589         case MODE_BUILDDBM:
590                 common_init();
591                 exit(builddbm(NULL));
592 #endif
593 
594         case MODE_DAEMON:
595 		if (myip != INADDR_ANY)
596 			ref_ip = myip;
597 		else
598 			ref_ip = grad_first_ip();
599 		if (ref_ip == INADDR_ANY)
600 		    grad_log(GRAD_LOG_ALERT, _("can't find out my own IP address"));
601 
602 		chdir("/");
603 		umask(022);
604 
605                 if (!foreground)
606                         radiusd_daemon();
607 		/* Install daemon-specific hook */
608 		radiusd_set_postconfig_hook(daemon_postconfig_hook,
609 					    NULL, 0);
610                 common_init();
611         }
612 
613 	radiusd_pidfile_write(RADIUSD_PID_FILE);
614 
615 	if (radiusd_user.username) {
616 		char *p;
617 		log_change_owner(&radiusd_user);
618 		p = grad_mkfilename(grad_log_dir, "radius.stderr");
619 		chown(p, radiusd_user.uid, radiusd_user.gid);
620 		grad_free(p);
621 		radius_switch_to_user(&radiusd_user);
622 	}
623 
624         radiusd_main_loop();
625 }
626 
627 void
radiusd_start()628 radiusd_start()
629 {
630 #ifdef USE_SERVER_GUILE
631 	scheme_main();
632 #else
633 	radiusd_main();
634 #endif
635 }
636 
637 int
main(int argc,char ** argv)638 main(int argc, char **argv)
639 {
640         /* debug_flag can be set only from debugger.
641            It means developer is taking control in his hands, so
642            we won't modify any variables that could prevent him
643            from doing so. */
644 	if (debug_flag == 0) {
645                 foreground = 0;
646                 spawn_flag = 1;
647         }
648         grad_app_setup();
649 	grad_set_logger(radiusd_logger);
650 
651         /* save the invocation */
652         xargc = argc;
653         xargv = argv;
654 
655         /* Set up some default values */
656         set_config_defaults();
657 
658         /* Process the options.  */
659         argp_program_version_hook = version;
660         if (grad_argp_parse(&argp, &argc, &argv, 0, NULL, NULL))
661                 return 1;
662 
663         log_set_default("default.log", -1, -1);
664         if (radius_mode != MODE_DAEMON)
665                 log_set_to_console(-1, console_logging_priority);
666 
667 	radiusd_setup();
668 	radiusd_start();
669 	/*NOTREACHED*/
670 }
671 
672 static int
snmp_request_to_command()673 snmp_request_to_command()
674 {
675 #ifdef USE_SNMP
676 	if (server_stat && server_stat->auth.status != saved_status) {
677 		saved_status = server_stat->auth.status;
678 		switch (server_stat->auth.status) {
679 		case serv_reset:
680 			return CMD_RESTART;
681 
682 		case serv_init:
683 			return CMD_RELOAD;
684 
685 		case serv_running:
686 			return CMD_CONTINUE;
687 
688 		case serv_suspended:
689 			return CMD_SUSPEND;
690 
691 		case serv_shutdown:
692 			return CMD_SHUTDOWN;
693 
694 		case serv_other:
695 			/* nothing */;
696 		}
697 	}
698 #endif
699 	return CMD_NONE;
700 }
701 
702 void
radiusd_suspend()703 radiusd_suspend()
704 {
705 	if (suspend_flag == 0) {
706 		terminate_subprocesses();
707 		grad_log(GRAD_LOG_NOTICE, _("RADIUSD SUSPENDED"));
708 		suspend_flag = 1;
709 	}
710 }
711 
712 void
radiusd_continue()713 radiusd_continue()
714 {
715 	if (suspend_flag) {
716 		terminate_subprocesses();
717 		suspend_flag = 0;
718 #ifdef USE_SNMP
719 		server_stat->auth.status = serv_running;
720 		server_stat->acct.status = serv_running;
721 #endif
722 	}
723 }
724 
725 static void
check_reload()726 check_reload()
727 {
728 	if (daemon_command == CMD_NONE)
729 		daemon_command = snmp_request_to_command();
730 
731         switch (daemon_command) {
732 	case CMD_CLEANUP:
733 		radiusd_cleanup();
734 		break;
735 
736         case CMD_RELOAD:
737                 grad_log(GRAD_LOG_INFO, _("Reloading configuration now"));
738                 radiusd_reconfigure();
739                 break;
740 
741         case CMD_RESTART:
742                 radiusd_restart();
743                 break;
744 
745         case CMD_MEMINFO:
746                 break;
747 
748         case CMD_DUMPDB:
749                 grad_log(GRAD_LOG_INFO, _("Dumping users db to `%s'"),
750 		       RADIUS_DUMPDB_NAME);
751                 dump_users_db();
752                 break;
753 
754 	case CMD_SUSPEND:
755 		radiusd_suspend();
756 		break;
757 
758 	case CMD_CONTINUE:
759 		radiusd_continue();
760 		break;
761 
762 	case CMD_SHUTDOWN:
763 		radiusd_exit();
764 		break;
765         }
766         daemon_command = CMD_NONE;
767 }
768 
769 void
radiusd_register_input_fd(char * name,int fd,void * data)770 radiusd_register_input_fd(char *name, int fd, void *data)
771 {
772 	input_register_channel(radius_input, name, fd, data);
773 }
774 
775 void
radiusd_close_channel(int fd)776 radiusd_close_channel(int fd)
777 {
778 	input_close_channel_fd(radius_input, fd);
779 }
780 
781 void
radiusd_collect_children()782 radiusd_collect_children()
783 {
784 	pid_t pid;
785 	int status;
786 
787 	for (;;) {
788 		pid = waitpid((pid_t)-1, &status, WNOHANG);
789 		if (pid <= 0)
790 			break;
791 		rpp_status_changed(pid, status);
792 	}
793 }
794 
795 void
radiusd_cleanup()796 radiusd_cleanup()
797 {
798 	rpp_collect_exited ();
799 }
800 
801 void
radiusd_restart()802 radiusd_restart()
803 {
804 	pid_t pid;
805 
806 	grad_log(GRAD_LOG_NOTICE, _("restart initiated"));
807 	if (xargv[0][0] != '/') {
808 		grad_log(GRAD_LOG_ERR,
809 		         _("can't restart: not started as absolute pathname"));
810 		return;
811 	}
812 
813 	radiusd_run_preconfig_hooks(NULL);
814 
815 	if (foreground)
816 		pid = 0; /* make-believe we're child */
817 	else
818 		pid = fork();
819 	if (pid < 0) {
820 		grad_log(GRAD_LOG_CRIT|GRAD_LOG_PERROR,
821 		         _("radiusd_restart: cannot fork"));
822 		return;
823 	}
824 
825 	radiusd_signal_init(SIG_DFL);
826 	if (pid > 0) {
827 		/* Parent */
828 		sleep(10);
829 		exit(0);
830 	}
831 
832 	/* Let the things settle */
833 	sleep(10);
834 
835 	/* Child */
836 	grad_log(GRAD_LOG_NOTICE, _("restarting radius"));
837 	execvp(xargv[0], xargv);
838 	grad_log(GRAD_LOG_CRIT|GRAD_LOG_PERROR,
839 	         _("RADIUS NOT RESTARTED: exec failed"));
840 	exit(1);
841 	/*NOTREACHED*/
842 }
843 
844 
845 
846 static int
radiusd_rpp_wait(void * arg)847 radiusd_rpp_wait(void *arg)
848 {
849 	time_t *tp = arg;
850 	struct timeval tv;
851 
852 	if (time(NULL) > *tp)
853 		return 1;
854 
855 	tv.tv_sec = 2;
856 	tv.tv_usec = 0;
857 	input_select_channel(radius_input, "rpp", &tv);
858 	return 0;
859 }
860 
861 void
radiusd_flush_queue()862 radiusd_flush_queue()
863 {
864 	time_t t;
865 	max_ttl(&t);
866 	rpp_flush(radiusd_rpp_wait, &t);
867 }
868 
869 void
radiusd_exit()870 radiusd_exit()
871 {
872         stat_done();
873 	radiusd_pidfile_remove(RADIUSD_PID_FILE);
874 
875 	radiusd_flush_queue();
876 	grad_log(GRAD_LOG_CRIT, _("Normal shutdown."));
877 
878 	rpp_kill(-1, SIGTERM);
879 	radiusd_exit0();
880 }
881 
882 void
radiusd_exit0()883 radiusd_exit0()
884 {
885         radiusd_sql_shutdown();
886         exit(0);
887 }
888 
889 void
radiusd_main_loop()890 radiusd_main_loop()
891 {
892         grad_log(GRAD_LOG_INFO, _("Ready to process requests."));
893 
894         for (;;) {
895 		log_open(GRAD_LOG_MAIN);
896 		check_reload();
897 		input_select(radius_input, NULL);
898 	}
899 }
900 
901 
902 /* ************************ Coniguration Functions ************************* */
903 
904 struct hook_rec {
905 	void (*function)(void *func_data, void *call_data);
906 	void *data;
907 	int once; /* Run once and remove */
908 };
909 
910 static grad_list_t /* of struct hook_rec */ *preconfig;
911 static grad_list_t /* of struct hook_rec */ *postconfig;
912 
913 void
radiusd_set_preconfig_hook(void (* f)(void *,void *),void * p,int once)914 radiusd_set_preconfig_hook(void (*f)(void *, void *), void *p, int once)
915 {
916 	struct hook_rec *hp = grad_emalloc(sizeof(*hp));
917 	hp->function = f;
918 	hp->data = p;
919 	hp->once = once;
920 	if (!preconfig)
921 		preconfig = grad_list_create();
922 	grad_list_prepend(preconfig, hp);
923 }
924 
925 void
radiusd_set_postconfig_hook(void (* f)(void *,void *),void * p,int once)926 radiusd_set_postconfig_hook(void (*f)(void *, void *), void *p, int once)
927 {
928 	struct hook_rec *hp = grad_emalloc(sizeof(*hp));
929 	hp->function = f;
930 	hp->data = p;
931 	hp->once = once;
932 	if (!postconfig)
933 		postconfig = grad_list_create();
934 	grad_list_prepend(postconfig, hp);
935 }
936 
937 struct hook_runtime_closure {
938 	grad_list_t *list;
939 	void *call_data;
940 };
941 
942 static int
_hook_call(void * item,void * data)943 _hook_call(void *item, void *data)
944 {
945 	struct hook_rec *hp = item;
946 	struct hook_runtime_closure *clos = data;
947 	hp->function(hp->data, clos->call_data);
948 	if (hp->once) {
949 		grad_list_remove(clos->list, hp, NULL);
950 		grad_free(hp);
951 	}
952 	return 0;
953 }
954 
955 void
radiusd_run_preconfig_hooks(void * data)956 radiusd_run_preconfig_hooks(void *data)
957 {
958 	struct hook_runtime_closure clos;
959 	clos.list = preconfig;
960 	clos.call_data = data;
961 	grad_list_iterate(clos.list, _hook_call, &clos);
962 }
963 
964 void
radiusd_run_postconfig_hooks(void * data)965 radiusd_run_postconfig_hooks(void *data)
966 {
967 	struct hook_runtime_closure clos;
968 	clos.list = postconfig;
969 	clos.call_data = data;
970 	grad_list_iterate(clos.list, _hook_call, &clos);
971 }
972 
973 void
radiusd_reconfigure()974 radiusd_reconfigure()
975 {
976         int rc = 0;
977         char *filename;
978 
979 	radiusd_run_preconfig_hooks(NULL);
980 
981 	grad_log(GRAD_LOG_INFO, _("Loading configuration files."));
982 	/* Read main configuration file */
983         filename = grad_mkfilename(grad_config_dir, RADIUS_CONFIG);
984         cfg_read(filename, config_syntax, NULL);
985 	grad_free(filename);
986 
987 	/* Read other files */
988         rc = reload_config_file(reload_all);
989 
990         if (rc) {
991                 grad_log(GRAD_LOG_CRIT, _("Errors reading config file - EXITING"));
992                 exit(1);
993         }
994 
995 	grad_path_init();
996 	radiusd_run_postconfig_hooks(NULL);
997 }
998 
999 
1000 /* ***************************** Signal Handling *************************** */
1001 
1002 static RETSIGTYPE
sig_handler(int sig)1003 sig_handler(int sig)
1004 {
1005         switch (sig) {
1006 	case SIGHUP:
1007 		daemon_command = CMD_RELOAD;
1008                 break;
1009 
1010 	case SIGUSR1:
1011 		daemon_command = CMD_MEMINFO;
1012 		break;
1013 
1014         case SIGUSR2:
1015 		daemon_command = CMD_DUMPDB;
1016 		break;
1017 
1018 	case SIGCHLD:
1019 		radiusd_collect_children ();
1020 		daemon_command = CMD_CLEANUP;
1021 		break;
1022 
1023 	case SIGTERM:
1024 	case SIGQUIT:
1025 		daemon_command = CMD_SHUTDOWN;
1026 		break;
1027 
1028 	case SIGPIPE:
1029 		/*FIXME: Any special action? */
1030 		daemon_command = CMD_CLEANUP;
1031 		break;
1032 
1033 	default:
1034 		abort();
1035 	}
1036 	grad_reset_signal(sig, sig_handler);
1037 }
1038 
1039 void
radiusd_signal_init(RETSIGTYPE (* hp)(int sig))1040 radiusd_signal_init(RETSIGTYPE (*hp)(int sig))
1041 {
1042 	static int signum[] = {
1043 		SIGHUP, SIGUSR1, SIGUSR2, SIGCHLD,
1044 		SIGTERM, SIGQUIT, SIGPIPE
1045 	};
1046 	int i;
1047 
1048 	for (i = 0; i < sizeof(signum)/sizeof(signum[0]); i++)
1049 		grad_set_signal(signum[i], hp);
1050 }
1051 
1052 
1053 /* ************************************************************************* */
1054 
1055 void
radiusd_pidfile_write(char * name)1056 radiusd_pidfile_write(char *name)
1057 {
1058         pid_t pid = getpid();
1059         char *p = grad_mkfilename(grad_pid_dir, name);
1060 	FILE *fp = fopen(p, "w");
1061 	if (fp) {
1062                 fprintf(fp, "%lu\n", (u_long) pid);
1063                 fclose(fp);
1064         }
1065         grad_free(p);
1066 }
1067 
1068 pid_t
radiusd_pidfile_read(char * name)1069 radiusd_pidfile_read(char *name)
1070 {
1071 	unsigned long val;
1072 	char *p = grad_mkfilename(grad_pid_dir, name);
1073 	FILE *fp = fopen(p, "r");
1074 	if (!fp)
1075 		return -1;
1076 	if (fscanf(fp, "%lu", &val) != 1)
1077 		val = -1;
1078 	fclose(fp);
1079 	grad_free(p);
1080 	return (pid_t) val;
1081 }
1082 
1083 void
radiusd_pidfile_remove(char * name)1084 radiusd_pidfile_remove(char *name)
1085 {
1086 	char *p = grad_mkfilename(grad_pid_dir, name);
1087 	unlink(p);
1088 	grad_free(p);
1089 }
1090 
1091 
1092 
1093 /* ************************************************************************* */
1094 static u_char recv_buffer[RAD_BUFFER_SIZE];
1095 
1096 struct udp_data {
1097 	int type;
1098 	struct sockaddr_in addr;
1099 };
1100 
1101 int
udp_input_handler(int fd,void * data)1102 udp_input_handler(int fd, void *data)
1103 {
1104         struct sockaddr sa;
1105 	socklen_t salen = sizeof (sa);
1106 	int size;
1107 	struct udp_data *sd = data;
1108 
1109 	size = recvfrom(fd, (char *) recv_buffer, sizeof(recv_buffer),
1110 			0, &sa, &salen);
1111 	if (size < 0)
1112 		request_fail(sd->type, (struct sockaddr_in*)&sa);
1113 	else {
1114 		REQUEST *req = request_create(sd->type,
1115 					      fd,
1116 					      &sd->addr,
1117 					      (struct sockaddr_in*)&sa,
1118 					      recv_buffer, size);
1119 
1120 		if (request_handle(req,
1121 				   spawn_flag ?
1122 				   rpp_forward_request : request_respond))
1123 			request_free(req);
1124 	}
1125 	return 0;
1126 }
1127 
1128 int
udp_input_close(int fd,void * data)1129 udp_input_close(int fd, void *data)
1130 {
1131 	close(fd);
1132 	grad_free(data);
1133 	return 0;
1134 }
1135 
1136 int
udp_input_cmp(const void * a,const void * b)1137 udp_input_cmp(const void *a, const void *b)
1138 {
1139 	const struct udp_data *sda = a;
1140 	const struct udp_data *sdb = b;
1141 
1142 	if (sda->addr.sin_port != sdb->addr.sin_port)
1143 		return 1;
1144 	if (sda->addr.sin_addr.s_addr == INADDR_ANY
1145 	    || sdb->addr.sin_addr.s_addr == INADDR_ANY)
1146 		return 0;
1147 	return sda->addr.sin_addr.s_addr != sdb->addr.sin_addr.s_addr;
1148 }
1149 
1150 int
udp_open(int type,grad_uint32_t ipaddr,int port,int nonblock)1151 udp_open(int type, grad_uint32_t ipaddr, int port, int nonblock)
1152 {
1153 	int fd;
1154 	struct sockaddr_in s;
1155 	struct udp_data *p;
1156 
1157 	if (select_free_ports)
1158 		port = 0;
1159         s.sin_family = AF_INET;
1160         s.sin_addr.s_addr = htonl(ipaddr);
1161         s.sin_port = htons(port);
1162 
1163 	if (port && (p = input_find_channel(radius_input, "udp", &s))) {
1164 		char buffer[GRAD_IPV4_STRING_LENGTH];
1165 		grad_log(GRAD_LOG_ERR,
1166 		         _("socket %s:%d is already assigned for %s"),
1167 		         grad_ip_iptostr(ipaddr, buffer),
1168 		         port,
1169 		         request_class[p->type].name);
1170 		return 1;
1171 	}
1172 
1173         fd = socket(PF_INET, SOCK_DGRAM, 0);
1174 	if (nonblock)
1175 		grad_set_nonblocking(fd);
1176         if (fd < 0) {
1177                 grad_log(GRAD_LOG_CRIT|GRAD_LOG_PERROR, "%s socket",
1178 		         request_class[type].name);
1179 		return 1;
1180         }
1181         if (bind(fd, (struct sockaddr*) &s, sizeof(s)) < 0) {
1182                 grad_log(GRAD_LOG_CRIT|GRAD_LOG_PERROR,
1183                          "%s bind", request_class[type].name);
1184 		close(fd);
1185 		return 1;
1186 	}
1187 
1188 	if (port == 0) {
1189 		socklen_t len = sizeof(s);
1190 		if (getsockname(fd, &s, &len)) {
1191 			grad_log(GRAD_LOG_CRIT|GRAD_LOG_PERROR,
1192 				 "%s getsockname", request_class[type].name);
1193 			close(fd);
1194 			return 1;
1195 		}
1196 		port = ntohs(s.sin_port);
1197 		grad_log(GRAD_LOG_INFO, "%s=%u",
1198 			 request_class[type].name, port);
1199 		fprintf(port_file, "%s=%u\n",
1200 			request_class[type].name, port);
1201 		switch (type) {
1202 		case R_AUTH:
1203 			auth_port = port;
1204 			break;
1205 
1206 		case R_ACCT:
1207 			acct_port = port;
1208 			break;
1209 
1210 #ifdef USE_SNMP
1211 		case R_SNMP:
1212 			snmp_port = port;
1213 			break;
1214 #endif
1215 		}
1216 	}
1217 
1218 	p = grad_emalloc(sizeof(*p));
1219 	p->type = type;
1220 	p->addr = s;
1221 	input_register_channel(radius_input, "udp", fd, p);
1222 	return 0;
1223 }
1224 
1225 static int
channel_counter(void * item,void * data)1226 channel_counter(void *item, void *data)
1227 {
1228 	struct udp_data *p = item;
1229 	if (p->type == R_AUTH || p->type == R_ACCT)
1230 		++*(size_t*)data;
1231 	return 0;
1232 }
1233 
1234 static size_t
radius_count_channels()1235 radius_count_channels()
1236 {
1237 	size_t count = 0;
1238 
1239 	input_iterate_channels(radius_input, "udp", channel_counter, &count);
1240 	return count;
1241 }
1242 
1243 
1244 /* ************************************************************************* */
1245 
1246 static int _opened_auth_sockets;
1247 static int _opened_acct_sockets;
1248 
1249 static int
rad_cfg_listen_auth(int argc,cfg_value_t * argv,void * block_data,void * handler_data)1250 rad_cfg_listen_auth(int argc, cfg_value_t *argv,
1251 		    void *block_data, void *handler_data)
1252 {
1253 	int i, errcnt = 0;
1254 
1255 	if (argc == 2 && argv[1].type == CFG_BOOLEAN) {
1256 		if (argv[1].v.bool == 0)
1257 			auth_port = 0;
1258 		return 0;
1259 	}
1260 
1261 	for (i = 1; i < argc; i++)
1262 		if (argv[i].type == CFG_NETWORK) {
1263 			if (argv[i].v.network.netmask != 0xffffffffL)
1264 				cfg_type_error(CFG_HOST);
1265 		} else if (argv[i].type != CFG_HOST) {
1266 			cfg_type_error(CFG_HOST);
1267 			errcnt++;
1268 		}
1269 
1270 	if (errcnt == 0 && radius_mode == MODE_DAEMON) {
1271 		for (i = 1; i < argc; i++) {
1272 			grad_uint32_t ip;
1273 			int port;
1274 
1275 			if (argv[i].type == CFG_NETWORK) {
1276 				ip = argv[i].v.network.ipaddr;
1277 				port = auth_port;
1278 			} else {
1279 				ip = argv[i].v.host.ipaddr;
1280 				port = argv[i].v.host.port;
1281 			}
1282 
1283 			if (udp_open(R_AUTH, ip, port, 0))
1284 				errcnt++;
1285 		}
1286 	}
1287 	if (errcnt == 0)
1288 		_opened_auth_sockets++;
1289 	return 0;
1290 }
1291 
1292 int
auth_stmt_begin(int finish,void * block_data,void * handler_data)1293 auth_stmt_begin(int finish, void *block_data, void *handler_data)
1294 {
1295 	if (!finish)
1296 		_opened_auth_sockets = 0;
1297 	else if (radius_mode == MODE_DAEMON
1298 		 && !_opened_auth_sockets
1299 		 && auth_port)
1300 		udp_open(R_AUTH, INADDR_ANY, auth_port, 0);
1301 	return 0;
1302 }
1303 
1304 static int
rad_cfg_listen_acct(int argc,cfg_value_t * argv,void * block_data,void * handler_data)1305 rad_cfg_listen_acct(int argc, cfg_value_t *argv,
1306 		    void *block_data, void *handler_data)
1307 {
1308 	int i, errcnt = 0;
1309 
1310 	if (argc == 2 && argv[1].type == CFG_BOOLEAN) {
1311 		if (argv[1].v.bool == 0)
1312 			acct_port = 0;
1313 		return 0;
1314 	}
1315 
1316 	for (i = 1; i < argc; i++)
1317 		if (argv[i].type == CFG_NETWORK) {
1318 			if (argv[i].v.network.netmask != 0xffffffffL)
1319 				cfg_type_error(CFG_HOST);
1320 		} else if (argv[i].type != CFG_HOST) {
1321 			cfg_type_error(CFG_HOST);
1322 			errcnt++;
1323 		}
1324 
1325 	if (errcnt == 0 && radius_mode == MODE_DAEMON) {
1326 		for (i = 1; i < argc; i++) {
1327 			grad_uint32_t ip;
1328 			int port;
1329 
1330 			if (argv[i].type == CFG_NETWORK) {
1331 				ip = argv[i].v.network.ipaddr;
1332 				port = acct_port;
1333 			} else {
1334 				ip = argv[i].v.host.ipaddr;
1335 				port = argv[i].v.host.port;
1336 			}
1337 
1338 			if (udp_open(R_ACCT, ip, port, 0))
1339 				errcnt++;
1340 		}
1341 	}
1342 	_opened_acct_sockets++;
1343 	return 0;
1344 }
1345 
1346 int
acct_stmt_begin(int finish,void * block_data,void * handler_data)1347 acct_stmt_begin(int finish, void *block_data, void *handler_data)
1348 {
1349 	if (!finish)
1350 		_opened_acct_sockets = 0;
1351 	else if (radius_mode == MODE_DAEMON
1352 		 && !_opened_acct_sockets
1353 		 && acct_port)
1354 		udp_open(R_ACCT, INADDR_ANY, acct_port, 0);
1355 	return 0;
1356 }
1357 
1358 static int
rad_cfg_user(int argc,cfg_value_t * argv,void * block_data,void * handler_data)1359 rad_cfg_user(int argc, cfg_value_t *argv,
1360 	     void *block_data, void *handler_data)
1361 {
1362 	RADIUS_USER *usr = handler_data;
1363 
1364 	if (argc != 2 || argv[1].type != CFG_STRING)
1365 		return 1;
1366 	return radius_get_user_ids((RADIUS_USER *) handler_data,
1367 				   argv[1].v.string);
1368 }
1369 
1370 int
option_stmt_end(void * block_data,void * handler_data)1371 option_stmt_end(void *block_data, void *handler_data)
1372 {
1373 	if (exec_user.username && radiusd_user.uid != 0) {
1374 		grad_log(GRAD_LOG_WARN, _("Ignoring exec-program-user"));
1375 		grad_free(exec_user.username);
1376 		exec_user.username = NULL;
1377 	} else if (exec_user.username == NULL
1378 		   && radiusd_user.uid == 0 && getuid() == 0)
1379 		radius_get_user_ids(&exec_user, "daemon");
1380 	return 0;
1381 }
1382 
1383 struct cfg_stmt option_stmt[] = {
1384 	{ "source-ip", CS_STMT, NULL, cfg_get_ipaddr, &myip,
1385 	  NULL, NULL },
1386 	{ "max-requests", CS_STMT, NULL, cfg_get_size_t, &max_requests,
1387 	  NULL, NULL },
1388 	{ "max-threads", CS_STMT, NULL, cfg_get_size_t, &max_children,
1389 	  NULL, NULL },
1390 	{ "max-processes", CS_STMT, NULL, cfg_get_size_t, &max_children,
1391 	  NULL, NULL },
1392 	{ "process-idle-timeout", CS_STMT, NULL, cfg_get_unsigned, &process_timeout,
1393 	  NULL, NULL },
1394 	{ "master-read-timeout", CS_STMT, NULL,
1395 	  cfg_get_unsigned, &radiusd_read_timeout, NULL, NULL },
1396 	{ "master-write-timeout", CS_STMT, NULL,
1397 	  cfg_get_unsigned, &radiusd_write_timeout, NULL, NULL },
1398 	{ "exec-program-user", CS_STMT, NULL, rad_cfg_user,
1399 	  &exec_user, NULL, NULL },
1400 	{ "radiusd-user", CS_STMT, NULL, rad_cfg_user,
1401 	  &radiusd_user, NULL, NULL },
1402 	{ "log-dir", CS_STMT, NULL, cfg_get_string, &grad_log_dir,
1403 	  NULL, NULL },
1404 	{ "acct-dir", CS_STMT, NULL, cfg_get_string, &grad_acct_dir,
1405 	  NULL, NULL },
1406 	{ "resolve", CS_STMT, NULL, cfg_get_boolean, &grad_resolve_hostnames,
1407 	  NULL, NULL },
1408 	{ "username-chars", CS_STMT, NULL, cfg_get_string,
1409 	  &username_valid_chars, NULL, NULL },
1410 	/* Obsolete statements */
1411 	{ "usr2delay", CS_STMT, NULL, cfg_obsolete, NULL, NULL, NULL },
1412 	{ NULL, }
1413 };
1414 
1415 struct cfg_stmt message_stmt[] = {
1416 	{ "account-closed", CS_STMT, NULL,
1417 	  cfg_get_string, &message_text[MSG_ACCOUNT_CLOSED],
1418 	  NULL, NULL },
1419 	{ "password-expired", CS_STMT, NULL,
1420 	  cfg_get_string, &message_text[MSG_PASSWORD_EXPIRED],
1421 	  NULL, NULL },
1422 	{ "access-denied", CS_STMT, NULL,
1423 	  cfg_get_string, &message_text[MSG_ACCESS_DENIED],
1424 	  NULL, NULL },
1425 	{ "realm-quota", CS_STMT, NULL,
1426 	  cfg_get_string, &message_text[MSG_REALM_QUOTA],
1427 	  NULL, NULL },
1428 	{ "multiple-login", CS_STMT, NULL,
1429 	  cfg_get_string, &message_text[MSG_MULTIPLE_LOGIN],
1430 	  NULL, NULL },
1431 	{ "second-login", CS_STMT, NULL,
1432 	  cfg_get_string, &message_text[MSG_SECOND_LOGIN],
1433 	  NULL, NULL },
1434 	{ "timespan-violation", CS_STMT, NULL,
1435 	  cfg_get_string, &message_text[MSG_TIMESPAN_VIOLATION],
1436 	  NULL, NULL },
1437 	{ "password-expire-warning", CS_STMT, NULL,
1438 	  cfg_get_string, &message_text[MSG_PASSWORD_EXPIRE_WARNING],
1439 	  NULL, NULL },
1440 	{ NULL, }
1441 };
1442 
1443 struct cfg_stmt auth_stmt[] = {
1444 	{ "port", CS_STMT, NULL, cfg_get_port, &auth_port, NULL, NULL },
1445 	{ "listen", CS_STMT, NULL, rad_cfg_listen_auth, NULL, NULL, NULL },
1446 	{ "forward", CS_STMT, NULL, rad_cfg_forward_auth, NULL, NULL, NULL },
1447 	{ "max-requests", CS_STMT, NULL,
1448 	  cfg_get_integer, &request_class[R_AUTH].max_requests, NULL, NULL },
1449 	{ "time-to-live", CS_STMT, NULL,
1450 	  cfg_get_integer, &request_class[R_AUTH].ttl, NULL, NULL },
1451 	{ "request-cleanup-delay", CS_STMT, NULL,
1452 	  cfg_get_integer, &request_class[R_AUTH].cleanup_delay, NULL, NULL },
1453 	{ "detail", CS_STMT, NULL, cfg_get_boolean, &auth_detail,
1454 	  NULL, NULL },
1455 	{ "detail-file-name", CS_STMT, NULL, cfg_get_string,
1456 	  &auth_detail_template, NULL, NULL },
1457 	{ "strip-names", CS_STMT, NULL, cfg_get_boolean, &strip_names,
1458 	  NULL, NULL },
1459 	{ "checkrad-assume-logged", CS_STMT, NULL,
1460 	  cfg_get_boolean, &checkrad_assume_logged,
1461 	  NULL, NULL },
1462 	{ "reject-malformed-names", CS_STMT, NULL,
1463 	  cfg_get_boolean, &auth_reject_malformed_names,
1464 	  NULL, NULL },
1465 	{ "password-expire-warning", CS_STMT, NULL,
1466 	  cfg_get_uint32_t, &warning_seconds,
1467 	  NULL, NULL },
1468 	{ "compare-attribute-flag", CS_STMT, NULL,
1469 	  cfg_get_integer, &auth_comp_flag,
1470 	  NULL, NULL },
1471 	{ "trace-rules", CS_STMT, NULL, cfg_get_boolean, &auth_trace_rules,
1472 	  NULL, NULL },
1473 	/* Obsolete statements */
1474 	{ "spawn", CS_STMT, NULL, cfg_obsolete, NULL, NULL, NULL },
1475 	{ NULL, }
1476 };
1477 
1478 struct cfg_stmt acct_stmt[] = {
1479 	{ "port", CS_STMT, NULL, cfg_get_port, &acct_port, NULL, NULL },
1480 	{ "listen", CS_STMT, NULL, rad_cfg_listen_acct, NULL, NULL, NULL },
1481 	{ "forward", CS_STMT, NULL, rad_cfg_forward_acct, NULL, NULL, NULL },
1482 	{ "max-requests", CS_STMT, NULL,
1483 	  cfg_get_integer, &request_class[R_ACCT].max_requests,
1484 	  NULL, NULL },
1485 	{ "time-to-live", CS_STMT, NULL,
1486 	  cfg_get_integer, &request_class[R_ACCT].ttl,
1487 	  NULL, NULL },
1488 	{ "request-cleanup-delay", CS_STMT, NULL,
1489 	  cfg_get_integer, &request_class[R_ACCT].cleanup_delay,
1490 	  NULL, NULL },
1491 	{ "detail", CS_STMT, NULL, cfg_get_boolean, &acct_detail,
1492 	  NULL, NULL },
1493 	{ "detail-file-name", CS_STMT, NULL, cfg_get_string,
1494 	  &acct_detail_template, NULL, NULL },
1495 	{ "system", CS_STMT, NULL, cfg_get_boolean, &acct_system,
1496 	  NULL, NULL },
1497 	{ "compare-attribute-flag", CS_STMT, NULL,
1498 	  cfg_get_integer, &acct_comp_flag,
1499 	  NULL, NULL },
1500 	{ "trace-rules", CS_STMT, NULL, cfg_get_boolean, &acct_trace_rules,
1501 	  NULL, NULL },
1502 	/* Obsolete statements */
1503 	{ "spawn", CS_STMT, NULL, cfg_obsolete, NULL, NULL, NULL },
1504 	{ NULL, }
1505 };
1506 
1507 struct cfg_stmt proxy_stmt[] = {
1508 	{ "max-requests", CS_STMT, NULL, cfg_obsolete, NULL, NULL, NULL },
1509 	{ "request-cleanup-delay", CS_STMT, NULL,
1510 	  cfg_obsolete, NULL, NULL, NULL },
1511 	{ NULL, }
1512 };
1513 
1514 struct cfg_stmt config_syntax[] = {
1515 	{ "option", CS_BLOCK, NULL, NULL, NULL, option_stmt, option_stmt_end },
1516 	{ "message", CS_BLOCK, NULL, NULL, NULL, message_stmt, NULL },
1517 	{ "logging", CS_BLOCK, logging_stmt_begin, logging_stmt_handler, NULL,
1518 	  logging_stmt, logging_stmt_end },
1519 	{ "auth", CS_BLOCK, auth_stmt_begin, NULL, NULL, auth_stmt, NULL },
1520 	{ "acct", CS_BLOCK, acct_stmt_begin, NULL, NULL, acct_stmt, NULL  },
1521 	{ "mlc",  CS_BLOCK, NULL, NULL, NULL, mlc_stmt, NULL },
1522 	{ "proxy", CS_BLOCK, NULL, NULL, NULL, proxy_stmt, NULL  },
1523 	{ "rewrite", CS_BLOCK, rewrite_stmt_term, NULL, NULL, rewrite_stmt, NULL },
1524 	{ "filters", CS_BLOCK, filters_stmt_term, NULL, NULL, filters_stmt,
1525 	  NULL },
1526 	{ "loadable-modules", CS_BLOCK, dynload_stmt_term, NULL, NULL,
1527 	  dynload_stmt, NULL },
1528 #ifdef USE_DBM
1529 	{ "usedbm", CS_STMT, NULL, cfg_get_boolean, &use_dbm, NULL, NULL },
1530 #endif
1531 #ifdef USE_SNMP
1532 	{ "snmp", CS_BLOCK, snmp_stmt_begin, NULL, NULL, snmp_stmt, NULL },
1533 #endif
1534 #ifdef USE_SERVER_GUILE
1535 	{ "guile", CS_BLOCK, NULL, guile_cfg_handler, NULL, guile_stmt, NULL },
1536 #endif
1537 	{ NULL, },
1538 };
1539