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-2012 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>
30 #include <freeradius-devel/radiusd.h>
31 #include <freeradius-devel/modules.h>
32 #include <freeradius-devel/rad_assert.h>
43 #ifdef HAVE_SYS_WAIT_H
44 # include <sys/wait.h>
47 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
50 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
56 char const *progname = NULL;
57 char const *radius_dir = NULL;
58 char const *radacct_dir = NULL;
59 char const *radlog_dir = NULL;
60 char const *radlib_dir = NULL;
61 bool log_stripped_names;
62 log_debug_t debug_flag = 0;
63 bool check_config = false;
65 char const *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION_STRING
66 #ifdef RADIUSD_VERSION_COMMIT
67 " (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
69 ", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
74 * Configuration items.
80 static void usage(int);
82 static void sig_fatal (int);
84 static void sig_hup (int);
90 int main(int argc, char *argv[])
92 int rcode = EXIT_SUCCESS;
95 bool spawn_flag = true;
96 bool write_pid = false;
97 bool display_version = false;
99 int from_child[2] = {-1, -1};
102 * We probably don't want to free the talloc autofree context
103 * directly, so we'll allocate a new context beneath it, and
104 * free that before any leak reports.
106 TALLOC_CTX *autofree = talloc_init("main");
109 * If the server was built with debugging enabled always install
110 * the basic fatal signal handlers.
113 if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
114 fr_perror("radiusd");
120 set_auth_parameters(argc,argv);
123 if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
131 if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
132 fprintf(stderr, "%s: Unable to initialize socket library.\n", progname);
139 set_radius_dir(autofree, RADIUS_DIR);
142 * Ensure that the configuration is initialized.
144 memset(&main_config, 0, sizeof(main_config));
145 main_config.myip.af = AF_UNSPEC;
146 main_config.port = 0;
147 main_config.name = "radiusd";
148 main_config.daemonize = true;
151 * Don't put output anywhere until we get told a little
154 default_log.dst = L_DST_NULL;
156 main_config.log_file = NULL;
158 /* Process the options. */
159 while ((argval = getopt(argc, argv, "Cd:D:fhi:l:mMn:p:PstvxX")) != EOF) {
165 main_config.daemonize = false;
169 set_radius_dir(autofree, optarg);
173 main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
177 main_config.daemonize = false;
185 if (strcmp(optarg, "stdout") == 0) {
188 main_config.log_file = strdup(optarg);
189 default_log.dst = L_DST_FILES;
190 default_log.fd = open(main_config.log_file,
191 O_WRONLY | O_APPEND | O_CREAT, 0640);
192 if (default_log.fd < 0) {
193 fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno));
196 fr_log_fp = fdopen(default_log.fd, "a");
200 if (ip_hton(&main_config.myip, AF_UNSPEC, optarg, false) < 0) {
201 fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg);
208 main_config.name = optarg;
212 main_config.debug_memory = true;
216 main_config.memory_report = true;
217 main_config.debug_memory = true;
224 port = strtoul(optarg, 0, 10);
225 if ((port == 0) || (port > UINT16_MAX)) {
226 fprintf(stderr, "radiusd: Invalid port number \"%s\"\n", optarg);
230 main_config.port = (uint16_t) port;
236 /* Force the PID to be written, even in -f mode */
240 case 's': /* Single process mode */
242 main_config.daemonize = false;
245 case 't': /* no child threads */
250 display_version = true;
255 main_config.daemonize = false;
257 main_config.log_auth = true;
258 main_config.log_auth_badpass = true;
259 main_config.log_auth_goodpass = true;
262 default_log.dst = L_DST_STDOUT;
263 default_log.fd = STDOUT_FILENO;
277 * Mismatch between the binary and the libraries it depends on
279 if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
280 fr_perror("radiusd");
284 if (rad_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
289 * Mismatch between build time OpenSSL and linked SSL,
290 * better to die here than segfault later.
292 #ifdef HAVE_OPENSSL_CRYPTO_H
293 if (ssl_check_consistency() < 0) {
298 if (flag && (flag != 0x03)) {
299 fprintf(stderr, "radiusd: The options -i and -p cannot be used individually.\n");
304 * Better here, so it doesn't matter whether we get passed
307 if (display_version) {
308 /* Don't print timestamps */
311 default_log.dst = L_DST_STDOUT;
312 default_log.fd = STDOUT_FILENO;
323 * Initialising OpenSSL once, here, is safer than having individual
326 #ifdef HAVE_OPENSSL_CRYPTO_H
331 * Initialize any event loops just enough so module instantiations
332 * can add fd/event to them, but do not start them yet.
334 if (!radius_event_init(autofree)) {
338 /* Read the configuration files, BEFORE doing anything else. */
339 if (main_config_init() < 0) {
343 /* Check for vulnerabilities in the version of libssl were linked against */
344 #ifdef HAVE_OPENSSL_CRYPTO_H
345 if (tls_global_version_check(main_config.allow_vulnerable_openssl) < 0) {
353 if (modules_init(main_config.config) < 0) {
357 /* Set the panic action (if required) */
358 if (main_config.panic_action &&
360 !getenv("PANIC_ACTION") &&
362 (fr_fault_setup(main_config.panic_action, argv[0]) < 0)) {
363 fr_perror("radiusd");
371 * Disconnect from session
373 if (main_config.daemonize) {
378 * Really weird things happen if we leave stdin open and call things like
381 devnull = open("/dev/null", O_RDWR);
383 ERROR("Failed opening /dev/null: %s", fr_syserror(errno));
386 dup2(devnull, STDIN_FILENO);
390 if (pipe(from_child) != 0) {
391 ERROR("Couldn't open pipe for child status: %s", fr_syserror(errno));
397 ERROR("Couldn't fork: %s", fr_syserror(errno));
402 * The parent exits, so the child can run in the background.
404 * As the child can still encounter an error during initialisation
405 * we do a blocking read on a pipe between it and the parent.
407 * Just before entering the event loop the child will send a success
408 * or failure message to the parent, via the pipe.
414 /* So the pipe is correctly widowed if the child exits */
415 close(from_child[1]);
418 * The child writes a 0x01 byte on
419 * success, and closes the pipe on error.
421 if ((read(from_child[0], &ret, 1) < 0)) {
425 /* For cleanliness... */
426 close(from_child[0]);
428 /* Don't turn children into zombies */
430 waitpid(pid, &stat_loc, WNOHANG);
437 /* so the pipe is correctly widowed if the parent exits?! */
438 close(from_child[0]);
446 * Ensure that we're using the CORRECT pid after forking,
447 * NOT the one we started with.
449 radius_pid = getpid();
452 * Redirect stderr/stdout as appropriate.
454 if (radlog_init(&default_log, main_config.daemonize) < 0) {
455 ERROR("%s", fr_strerror());
460 * Start the event loop(s) and threads.
462 radius_event_start(main_config.config, spawn_flag);
465 * Now that we've set everything up, we can install the signal
466 * handlers. Before this, if we get any signal, we don't know
467 * what to do, so we might as well do the default, and die.
470 signal(SIGPIPE, SIG_IGN);
473 if ((fr_set_signal(SIGHUP, sig_hup) < 0) ||
474 (fr_set_signal(SIGTERM, sig_fatal) < 0)) {
475 ERROR("%s", fr_strerror());
480 * If we're debugging, then a CTRL-C will cause the
481 * server to die immediately. Use SIGTERM to shut down
482 * the server cleanly in that case.
484 if (main_config.debug_memory || (debug_flag == 0)) {
485 if ((fr_set_signal(SIGINT, sig_fatal) < 0)
487 || (fr_set_signal(SIGQUIT, sig_fatal) < 0)
490 ERROR("%s", fr_strerror());
496 * Everything seems to have loaded OK, exit gracefully.
499 DEBUG("Configuration appears to be OK");
502 if (main_config.debug_memory) {
510 radius_stats_init(0);
514 * Write the PID always if we're running as a daemon.
516 if (main_config.daemonize) write_pid = true;
519 * Write the PID after we've forked, so that we write the
525 fp = fopen(main_config.pid_file, "w");
528 * FIXME: What about following symlinks,
529 * and having it over-write a normal file?
531 fprintf(fp, "%d\n", (int) radius_pid);
534 ERROR("Failed creating PID file %s: %s\n",
535 main_config.pid_file, fr_syserror(errno));
540 exec_trigger(NULL, NULL, "server.start", false);
543 * Inform the parent (who should still be waiting) that
544 * the rest of initialisation went OK, and that it should
545 * exit with a 0 status. If we don't get this far, then
546 * we just close the pipe on exit, and the parent gets a
549 if (main_config.daemonize) {
550 if (write(from_child[1], "\001", 1) < 0) {
551 WARN("Failed informing parent of successful start: %s",
554 close(from_child[1]);
558 * Clear the libfreeradius error buffer
563 * Process requests until HUP or exit.
565 while ((status = radius_event_process()) == 0x80) {
567 radius_stats_init(1);
572 ERROR("Exiting due to internal error: %s", fr_strerror());
573 rcode = EXIT_FAILURE;
575 INFO("Exiting normally");
578 exec_trigger(NULL, NULL, "server.stop", false);
581 * Ignore the TERM signal: we're
584 signal(SIGTERM, SIG_IGN);
587 * Send a TERM signal to all
588 * associated processes
589 * (including us, which gets
593 if (spawn_flag) kill(-radius_pid, SIGTERM);
597 * We're exiting, so we can delete the PID
598 * file. (If it doesn't exist, we can ignore
599 * the error returned by unlink)
601 if (main_config.daemonize) {
602 unlink(main_config.pid_file);
609 * Detach any modules.
613 xlat_free(); /* modules may have xlat's */
616 * Free the configuration items.
624 #ifdef HAVE_OPENSSL_CRYPTO_H
625 tls_global_cleanup();
629 * So we don't see autofreed memory in the talloc report
631 talloc_free(autofree);
633 if (main_config.memory_report) {
634 INFO("Allocated memory at time of report:");
635 fr_log_talloc_report(NULL);
643 * Display the syntax for starting this program.
645 static void NEVER_RETURNS usage(int status)
647 FILE *output = status?stderr:stdout;
649 fprintf(output, "Usage: %s [options]\n", progname);
650 fprintf(output, "Options:\n");
651 fprintf(output, " -C Check configuration and exit.\n");
652 fprintf(stderr, " -d <raddb> Set configuration directory (defaults to " RADDBDIR ").\n");
653 fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
654 fprintf(output, " -f Run as a foreground process, not a daemon.\n");
655 fprintf(output, " -h Print this help message.\n");
656 fprintf(output, " -i <ipaddr> Listen on ipaddr ONLY.\n");
657 fprintf(output, " -l <log_file> Logging output will be written to this file.\n");
658 fprintf(output, " -m On SIGINT or SIGQUIT exit cleanly instead of immediately.\n");
659 fprintf(output, " -n <name> Read raddb/name.conf instead of raddb/radiusd.conf.\n");
660 fprintf(output, " -p <port> Listen on port ONLY.\n");
661 fprintf(output, " -P Always write out PID, even with -f.\n");
662 fprintf(output, " -s Do not spawn child processes to handle requests.\n");
663 fprintf(output, " -t Disable threads.\n");
664 fprintf(output, " -v Print server version information.\n");
665 fprintf(output, " -X Turn on full debugging.\n");
666 fprintf(output, " -x Turn on additional debugging. (-xx gives more debugging).\n");
672 * We got a fatal signal.
674 static void sig_fatal(int sig)
676 if (getpid() != radius_pid) _exit(sig);
680 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
687 if (main_config.debug_memory || main_config.memory_report) {
688 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
700 * We got the hangup signal.
701 * Re-read the configuration files.
703 static void sig_hup(UNUSED int sig)
705 reset_signal(SIGHUP, sig_hup);
707 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);