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/modules.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)
59 const char *progname = NULL;
60 char *radius_dir = NULL;
61 const char *radacct_dir = NULL;
62 const char *radlog_dir = NULL;
63 const char *radlib_dir = NULL;
64 int log_stripped_names;
66 int check_config = FALSE;
68 const char *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION ", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
72 static int debug_memory = 0;
75 * Configuration items.
81 static void usage(int);
83 static void sig_fatal (int);
85 static void sig_hup (int);
91 int main(int argc, char *argv[])
95 int spawn_flag = TRUE;
96 int dont_fork = FALSE;
100 struct sigaction act;
104 set_auth_parameters(argc,argv);
107 if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
115 if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
116 fprintf(stderr, "%s: Unable to initialize socket library.\n");
124 radius_dir = strdup(RADIUS_DIR);
127 * Ensure that the configuration is initialized.
129 memset(&mainconfig, 0, sizeof(mainconfig));
130 mainconfig.myip.af = AF_UNSPEC;
131 mainconfig.port = -1;
132 mainconfig.name = "radiusd";
134 #ifdef HAVE_SIGACTION
135 memset(&act, 0, sizeof(act));
137 sigemptyset( &act.sa_mask ) ;
141 * Don't put output anywhere until we get told a little
144 mainconfig.radlog_dest = RADLOG_NULL;
145 mainconfig.radlog_fd = -1;
146 mainconfig.log_file = NULL;
148 /* Process the options. */
149 while ((argval = getopt(argc, argv, "Cd:fhi:l:mn:p:stvxX")) != EOF) {
159 if (radius_dir) free(radius_dir);
160 radius_dir = strdup(optarg);
172 if (strcmp(optarg, "stdout") == 0) {
175 mainconfig.log_file = strdup(optarg);
176 mainconfig.radlog_dest = RADLOG_FILES;
177 mainconfig.radlog_fd = open(mainconfig.log_file,
178 O_WRONLY | O_APPEND | O_CREAT, 0640);
179 if (mainconfig.radlog_fd < 0) {
180 fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, strerror(errno));
183 fr_log_fp = fdopen(mainconfig.radlog_fd, "a");
187 if (ip_hton(optarg, AF_UNSPEC, &mainconfig.myip) < 0) {
188 fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg);
195 mainconfig.name = optarg;
203 mainconfig.port = atoi(optarg);
204 if ((mainconfig.port <= 0) ||
205 (mainconfig.port >= 65536)) {
206 fprintf(stderr, "radiusd: Invalid port number %s\n", optarg);
212 case 's': /* Single process mode */
217 case 't': /* no child threads */
229 mainconfig.log_auth = TRUE;
230 mainconfig.log_auth_badpass = TRUE;
231 mainconfig.log_auth_goodpass = TRUE;
234 mainconfig.radlog_dest = RADLOG_STDOUT;
235 mainconfig.radlog_fd = STDOUT_FILENO;
248 if (flag && (flag != 0x03)) {
249 fprintf(stderr, "radiusd: The options -i and -p cannot be used individually.\n");
254 radlog(L_INFO, "%s", radiusd_version);
255 radlog(L_INFO, "Copyright (C) 1999-2009 The FreeRADIUS server project and contributors.\n");
256 radlog(L_INFO, "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
257 radlog(L_INFO, "PARTICULAR PURPOSE.\n");
258 radlog(L_INFO, "You may redistribute copies of FreeRADIUS under the terms of the\n");
259 radlog(L_INFO, "GNU General Public License v2.\n");
260 radlog(L_INFO, "\n");
263 /* Read the configuration files, BEFORE doing anything else. */
264 if (read_mainconfig(0) < 0) {
270 * Disconnect from session
272 if (dont_fork == FALSE) {
276 radlog(L_ERR, "Couldn't fork: %s", strerror(errno));
281 * The parent exits, so the child can run in the background.
293 * Ensure that we're using the CORRECT pid after forking,
294 * NOT the one we started with.
296 radius_pid = getpid();
299 * If we're running as a daemon, close the default file
300 * descriptors, AFTER forking.
305 devnull = open("/dev/null", O_RDWR);
307 radlog(L_ERR|L_CONS, "Failed opening /dev/null: %s\n",
311 dup2(devnull, STDIN_FILENO);
312 if (mainconfig.radlog_dest == RADLOG_STDOUT) {
314 mainconfig.radlog_fd = STDOUT_FILENO;
316 dup2(devnull, STDOUT_FILENO);
318 if (mainconfig.radlog_dest == RADLOG_STDERR) {
320 mainconfig.radlog_fd = STDERR_FILENO;
322 dup2(devnull, STDERR_FILENO);
327 setlinebuf(stdout); /* unbuffered output */
331 * Initialize the event pool, including threads.
333 radius_event_init(mainconfig.config, spawn_flag);
336 * Now that we've set everything up, we can install the signal
337 * handlers. Before this, if we get any signal, we don't know
338 * what to do, so we might as well do the default, and die.
341 signal(SIGPIPE, SIG_IGN);
343 #ifdef HAVE_SIGACTION
344 act.sa_handler = sig_hup;
345 sigaction(SIGHUP, &act, NULL);
346 act.sa_handler = sig_fatal;
347 sigaction(SIGTERM, &act, NULL);
350 signal(SIGHUP, sig_hup);
352 signal(SIGTERM, sig_fatal);
355 * If we're debugging, then a CTRL-C will cause the
356 * server to die immediately. Use SIGTERM to shut down
357 * the server cleanly in that case.
359 if ((debug_memory == 1) || (debug_flag == 0)) {
360 #ifdef HAVE_SIGACTION
361 act.sa_handler = sig_fatal;
362 sigaction(SIGINT, &act, NULL);
363 sigaction(SIGQUIT, &act, NULL);
365 signal(SIGINT, sig_fatal);
367 signal(SIGQUIT, sig_fatal);
373 * Everything seems to have loaded OK, exit gracefully.
376 DEBUG("Configuration appears to be OK.");
381 radius_stats_init(0);
385 * Only write the PID file if we're running as a daemon.
387 * And write it AFTER we've forked, so that we write the
390 if (dont_fork == FALSE) {
393 fp = fopen(mainconfig.pid_file, "w");
396 * FIXME: What about following symlinks,
397 * and having it over-write a normal file?
399 fprintf(fp, "%d\n", (int) radius_pid);
402 radlog(L_ERR|L_CONS, "Failed creating PID file %s: %s\n",
403 mainconfig.pid_file, strerror(errno));
408 exec_trigger(NULL, NULL, "server.start");
411 * Process requests until HUP or exit.
413 while ((rcode = radius_event_process()) == 0x80) {
415 radius_stats_init(1);
421 radlog(L_ERR, "Exiting due to internal error: %s",
425 radlog(L_INFO, "Exiting normally.");
428 exec_trigger(NULL, NULL, "server.stop");
431 * Ignore the TERM signal: we're
434 signal(SIGTERM, SIG_IGN);
437 * Send a TERM signal to all
438 * associated processes
439 * (including us, which gets
443 if (spawn_flag) kill(-radius_pid, SIGTERM);
447 * We're exiting, so we can delete the PID
448 * file. (If it doesn't exist, we can ignore
449 * the error returned by unlink)
451 if (dont_fork == FALSE) {
452 unlink(mainconfig.pid_file);
458 * Free the configuration items.
463 * Detach any modules.
467 xlat_free(); /* modules may have xlat's */
480 * Display the syntax for starting this program.
482 static void NEVER_RETURNS usage(int status)
484 FILE *output = status?stderr:stdout;
487 "Usage: %s [-d db_dir] [-l log_dir] [-i address] [-n name] [-fsvXx]\n", progname);
488 fprintf(output, "Options:\n\n");
489 fprintf(output, " -C Check configuration and exit.\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_file Logging output will be written to this file.\n");
495 fprintf(output, " -m On SIGINT or SIGQUIT exit cleanly instead of immediately.\n");
496 fprintf(output, " -n name Read raddb/name.conf instead of raddb/radiusd.conf\n");
497 fprintf(output, " -p port Listen on port ONLY.\n");
498 fprintf(output, " -s Do not spawn child processes to handle requests.\n");
499 fprintf(output, " -t Disable threads.\n");
500 fprintf(output, " -v Print server version information.\n");
501 fprintf(output, " -X Turn on full debugging.\n");
502 fprintf(output, " -x Turn on additional debugging. (-xx gives more debugging).\n");
508 * We got a fatal signal.
510 static void sig_fatal(int sig)
512 if (getpid() != radius_pid) _exit(sig);
516 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
524 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
536 * We got the hangup signal.
537 * Re-read the configuration files.
539 static void sig_hup(int sig)
541 sig = sig; /* -Wunused */
543 reset_signal(SIGHUP, sig_hup);
545 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);