2 * radiusd.c Main loop of the radius server.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2000-2004,2006 The FreeRADIUS server project
21 * Copyright 1999,2000 Miquel van Smoorenburg <miquels@cistron.nl>
22 * Copyright 2000 Alan DeKok <aland@ox.org>
23 * Copyright 2000 Alan Curry <pacman-radius@cqc.com>
24 * Copyright 2000 Jeff Carneal <jeff@apex.net>
25 * Copyright 2000 Chad Miller <cmiller@surfsouth.com>
28 #include <freeradius-devel/ident.h>
31 #include <freeradius-devel/radiusd.h>
32 #include <freeradius-devel/radius_snmp.h>
33 #include <freeradius-devel/rad_assert.h>
46 #ifdef HAVE_SYS_WAIT_H
47 # include <sys/wait.h>
50 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
53 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
56 #ifndef HAVE_PTHREAD_H
57 #define thread_pool_lock(_x)
58 #define thread_pool_unlock(_x)
64 const char *progname = NULL;
65 const char *radius_dir = NULL;
66 const char *radacct_dir = NULL;
67 const char *radlog_dir = NULL;
68 const char *radlib_dir = NULL;
69 int log_stripped_names;
71 int log_auth_detail = FALSE;
73 const char *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION ", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
78 static int debug_memory = 0;
81 * Configuration items.
87 static void usage(int);
89 static void sig_fatal (int);
90 static void sig_hup (int);
95 int main(int argc, char *argv[])
98 unsigned char buffer[4096];
101 int spawn_flag = TRUE;
102 int dont_fork = FALSE;
104 #ifdef HAVE_SIGACTION
105 struct sigaction act;
109 set_auth_parameters(argc,argv);
112 if ((progname = strrchr(argv[0], '/')) == NULL)
119 radius_dir = strdup(RADIUS_DIR);
122 * Ensure that the configuration is initialized.
124 memset(&mainconfig, 0, sizeof(mainconfig));
125 mainconfig.myip.af = AF_UNSPEC;
126 mainconfig.port = -1;
127 mainconfig.radiusd_conf = strdup("radiusd.conf");
129 #ifdef HAVE_SIGACTION
130 memset(&act, 0, sizeof(act));
132 sigemptyset( &act.sa_mask ) ;
136 * Don't put output anywhere until we get told a little
139 mainconfig.radlog_fd = -1;
140 mainconfig.log_file = NULL;
142 /* Process the options. */
143 while ((argval = getopt(argc, argv, "Aa:bcd:fg:hi:l:mn:p:sSvxXyz")) != EOF) {
148 log_auth_detail = TRUE;
152 if (radacct_dir) free(radacct_dir);
153 radacct_dir = strdup(optarg);
157 /* ignore for backwards compatibility with Cistron */
161 if (radius_dir) free(radius_dir);
162 radius_dir = strdup(optarg);
174 if (ip_hton(optarg, AF_UNSPEC, &mainconfig.myip) < 0) {
175 fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg);
181 if ((strcmp(optarg, "stdout") == 0) ||
182 (strcmp(optarg, "stderr") == 0) ||
183 (strcmp(optarg, "syslog") == 0)) {
184 fprintf(stderr, "radiusd: -l %s is unsupported. Use log_destination in radiusd.conf\n", optarg);
187 if (radlog_dir) free(radlog_dir);
188 radlog_dir = strdup(optarg);
192 fprintf(stderr, "radiusd: -g is unsupported. Use log_destination in radiusd.conf.\n");
201 if ((strchr(optarg, '/') != NULL) ||
202 (strchr(optarg, '.') != NULL) ||
203 (strlen(optarg) > 45)) usage(1);
205 snprintf(buffer, sizeof(buffer), "%s.conf",
207 if (mainconfig.radiusd_conf)
208 free(mainconfig.radiusd_conf);
209 mainconfig.radiusd_conf = strdup(buffer);
213 log_stripped_names++;
217 mainconfig.port = atoi(optarg);
218 if ((mainconfig.port <= 0) ||
219 (mainconfig.port >= 65536)) {
220 fprintf(stderr, "radiusd: Invalid port number %s\n", optarg);
225 case 's': /* Single process mode */
235 * BIG debugging mode for users who are
236 * TOO LAZY to type '-sfxxyz -l stdout' themselves.
242 mainconfig.log_auth = TRUE;
243 mainconfig.log_auth_badpass = TRUE;
244 mainconfig.log_auth_goodpass = TRUE;
245 mainconfig.radlog_dest = RADLOG_STDOUT;
246 mainconfig.radlog_fd = STDOUT_FILENO;
254 mainconfig.log_auth = TRUE;
255 mainconfig.log_auth_badpass = TRUE;
259 mainconfig.log_auth_badpass = TRUE;
260 mainconfig.log_auth_goodpass = TRUE;
270 radlog(L_INFO, "%s", radiusd_version);
271 radlog(L_INFO, "Copyright (C) 2000-2007 The FreeRADIUS server project.\n");
272 radlog(L_INFO, "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
273 radlog(L_INFO, "PARTICULAR PURPOSE.\n");
274 radlog(L_INFO, "You may redistribute copies of FreeRADIUS under the terms of the\n");
275 radlog(L_INFO, "GNU General Public License.\n");
279 /* Read the configuration files, BEFORE doing anything else. */
280 if (read_mainconfig(0) < 0) {
285 * Disconnect from session
287 if (debug_flag == 0 && dont_fork == FALSE) {
290 radlog(L_ERR|L_CONS, "Couldn't fork");
295 * The parent exits, so the child can run in the background.
306 * If we're NOT debugging, trap fatal signals, so we can
307 * easily clean up after ourselves.
309 * If we ARE debugging, don't trap them, so we can
312 if ((mainconfig.allow_core_dumps == FALSE) && (debug_flag == 0)) {
314 #ifdef HAVE_SIGACTION
315 act.sa_handler = sig_fatal;
316 sigaction(SIGSEGV, &act, NULL);
318 signal(SIGSEGV, sig_fatal);
324 * Ensure that we're using the CORRECT pid after forking,
325 * NOT the one we started with.
327 radius_pid = getpid();
330 * Only write the PID file if we're running as a daemon.
332 * And write it AFTER we've forked, so that we write the
335 if (dont_fork == FALSE) {
338 fp = fopen(mainconfig.pid_file, "w");
341 * FIXME: What about following symlinks,
342 * and having it over-write a normal file?
344 fprintf(fp, "%d\n", (int) radius_pid);
347 radlog(L_ERR|L_CONS, "Failed creating PID file %s: %s\n",
348 mainconfig.pid_file, strerror(errno));
354 * If we're running as a daemon, close the default file
355 * descriptors, AFTER forking.
360 devnull = open("/dev/null", O_RDWR);
362 radlog(L_ERR|L_CONS, "Failed opening /dev/null: %s\n",
366 dup2(devnull, STDIN_FILENO);
367 if (mainconfig.radlog_dest == RADLOG_STDOUT) {
368 mainconfig.radlog_fd = dup(STDOUT_FILENO);
370 dup2(devnull, STDOUT_FILENO);
371 if (mainconfig.radlog_dest == RADLOG_STDERR) {
372 mainconfig.radlog_fd = dup(STDERR_FILENO);
374 dup2(devnull, STDERR_FILENO);
379 * It's called the thread pool, but it does a little
382 radius_event_init(mainconfig.config, spawn_flag);
385 * Use linebuffered or unbuffered stdout if
386 * the debug flag is on.
388 if (debug_flag == TRUE)
392 * Now that we've set everything up, we can install the signal
393 * handlers. Before this, if we get any signal, we don't know
394 * what to do, so we might as well do the default, and die.
396 signal(SIGPIPE, SIG_IGN);
397 #ifdef HAVE_SIGACTION
398 act.sa_handler = sig_hup;
399 sigaction(SIGHUP, &act, NULL);
400 act.sa_handler = sig_fatal;
401 sigaction(SIGTERM, &act, NULL);
403 signal(SIGHUP, sig_hup);
404 signal(SIGTERM, sig_fatal);
407 * If we're debugging, then a CTRL-C will cause the
408 * server to die immediately. Use SIGTERM to shut down
409 * the server cleanly in that case.
411 if ((debug_memory == 1) || (debug_flag == 0)) {
412 #ifdef HAVE_SIGACTION
413 act.sa_handler = sig_fatal;
414 sigaction(SIGINT, &act, NULL);
415 sigaction(SIGQUIT, &act, NULL);
417 signal(SIGINT, sig_fatal);
418 signal(SIGQUIT, sig_fatal);
423 * Process requests until HUP or exit.
425 while ((rcode = radius_event_process()) == 0x80) {
428 * Reload anything that can safely be reloaded.
430 DEBUG("HUP support not available.");
432 thread_pool_unlock();
438 * Ignore the TERM signal: we're
441 signal(SIGTERM, SIG_IGN);
444 * Send a TERM signal to all
445 * associated processes
446 * (including us, which gets
449 kill(-radius_pid, SIGTERM);
452 * We're exiting, so we can delete the PID
453 * file. (If it doesn't exist, we can ignore
454 * the error returned by unlink)
456 if (dont_fork == FALSE) {
457 unlink(mainconfig.pid_file);
463 * Free the configuration items.
468 * Detach any modules.
479 * Display the syntax for starting this program.
481 static void NEVER_RETURNS usage(int status)
483 FILE *output = status?stderr:stdout;
486 "Usage: %s [-a acct_dir] [-d db_dir] [-l log_dir] [-i address] [-AcfnsSvXxyz]\n", progname);
487 fprintf(output, "Options:\n\n");
488 fprintf(output, " -a acct_dir use accounting directory 'acct_dir'.\n");
489 fprintf(output, " -A Log auth detail.\n");
490 fprintf(output, " -d raddb_dir Configuration files are in \"raddbdir/*\".\n");
491 fprintf(output, " -f Run as a foreground process, not a daemon.\n");
492 fprintf(output, " -h Print this help message.\n");
493 fprintf(output, " -i ipaddr Listen on ipaddr ONLY\n");
494 fprintf(output, " -l log_dir Log file is \"log_dir/radius.log\" (not used in debug mode)\n");
495 fprintf(output, " -p port Listen on port ONLY\n");
496 fprintf(output, " -s Do not spawn child processes to handle requests.\n");
497 fprintf(output, " -S Log stripped names.\n");
498 fprintf(output, " -v Print server version information.\n");
499 fprintf(output, " -X Turn on full debugging.\n");
500 fprintf(output, " -x Turn on additional debugging. (-xx gives more debugging).\n");
501 fprintf(output, " -y Log authentication failures, with password.\n");
502 fprintf(output, " -z Log authentication successes, with password.\n");
508 * We got a fatal signal.
510 static void sig_fatal(int sig)
515 * We can't really do anything
516 * intelligent here so just die
521 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
527 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
533 radius_signal_self(RADIUS_SIGNAL_SELF_EXIT);
540 * We got the hangup signal.
541 * Re-read the configuration files.
543 static void sig_hup(int sig)
545 sig = sig; /* -Wunused */
547 reset_signal(SIGHUP, sig_hup);
549 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);