/*
* Global variables.
*/
-char const *progname = NULL;
-char const *radius_dir = NULL;
-char const *radacct_dir = NULL;
-char const *radlog_dir = NULL;
-char const *radlib_dir = NULL;
-bool log_stripped_names;
-log_debug_t debug_flag = 0;
-bool check_config = false;
+char const *progname = NULL;
+char const *radacct_dir = NULL;
+char const *radlog_dir = NULL;
+char const *radlib_dir = NULL;
+bool log_stripped_names;
char const *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION_STRING
#ifdef RADIUSD_VERSION_COMMIT
#endif
", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
-pid_t radius_pid;
+static pid_t radius_pid;
/*
* Configuration items.
int status;
int argval;
bool spawn_flag = true;
- bool write_pid = false;
bool display_version = false;
int flag = 0;
int from_child[2] = {-1, -1};
+ fr_state_t *state = NULL;
/*
- * We probably don't want to free the talloc autofree context
- * directly, so we'll allocate a new context beneath it, and
- * free that before any leak reports.
+ * We probably don't want to free the talloc autofree context
+ * directly, so we'll allocate a new context beneath it, and
+ * free that before any leak reports.
*/
TALLOC_CTX *autofree = talloc_init("main");
- /*
- * If the server was built with debugging enabled always install
- * the basic fatal signal handlers.
- */
-#ifndef NDEBUG
- if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
- fr_perror("radiusd");
- exit(EXIT_FAILURE);
- }
-#endif
-
#ifdef OSFC2
- set_auth_parameters(argc,argv);
+ set_auth_parameters(argc, argv);
#endif
if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
}
#endif
- debug_flag = 0;
+ rad_debug_lvl = 0;
set_radius_dir(autofree, RADIUS_DIR);
/*
/* Process the options. */
while ((argval = getopt(argc, argv, "Cd:D:fhi:l:mMn:p:PstvxX")) != EOF) {
- switch(argval) {
+ switch (argval) {
case 'C':
check_config = true;
spawn_flag = false;
break;
case 'D':
- main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
+ main_config.dictionary_dir = talloc_typed_strdup(autofree, optarg);
break;
case 'f':
case 'P':
/* Force the PID to be written, even in -f mode */
- write_pid = true;
+ main_config.write_pid = true;
break;
case 's': /* Single process mode */
case 'X':
spawn_flag = false;
main_config.daemonize = false;
- debug_flag += 2;
+ rad_debug_lvl += 2;
main_config.log_auth = true;
main_config.log_auth_badpass = true;
main_config.log_auth_goodpass = true;
break;
case 'x':
- debug_flag++;
+ rad_debug_lvl++;
break;
default:
}
/*
- * Mismatch between the binary and the libraries it depends on
+ * Mismatch between the binary and the libraries it depends on.
*/
if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
fr_perror("radiusd");
exit(EXIT_FAILURE);
}
- if (rad_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
- exit(EXIT_FAILURE);
- }
+ if (rad_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) exit(EXIT_FAILURE);
/*
- * Mismatch between build time OpenSSL and linked SSL,
- * better to die here than segfault later.
+ * Mismatch between build time OpenSSL and linked SSL, better to die
+ * here than segfault later.
*/
#ifdef HAVE_OPENSSL_CRYPTO_H
- if (ssl_check_consistency() < 0) {
- exit(EXIT_FAILURE);
- }
+ if (ssl_check_consistency() < 0) exit(EXIT_FAILURE);
#endif
if (flag && (flag != 0x03)) {
}
/*
- * According to the talloc peeps, no two threads
- * may modify any part of a ctx tree with a common
- * root without synchronisation.
+ * According to the talloc peeps, no two threads may modify any part of
+ * a ctx tree with a common root without synchronisation.
*
- * So we can't run with a null context and threads.
+ * So we can't run with a null context and threads.
*/
if (main_config.memory_report) {
if (spawn_flag) {
}
/*
- * Better here, so it doesn't matter whether we get passed
- * -xv or -vx.
+ * Better here, so it doesn't matter whether we get passed -xv or -vx.
*/
if (display_version) {
/* Don't print timestamps */
- debug_flag += 2;
+ rad_debug_lvl += 2;
fr_log_fp = stdout;
default_log.dst = L_DST_STDOUT;
default_log.fd = STDOUT_FILENO;
- version();
+ INFO("%s: %s", progname, radiusd_version);
+ version_print();
exit(EXIT_SUCCESS);
}
- if (debug_flag) {
- version();
- }
+ if (rad_debug_lvl) version_print();
+
+ /*
+ * Under linux CAP_SYS_PTRACE is usually only available before setuid/setguid,
+ * so we need to check whether we can attach before calling those functions
+ * (in main_config_init()).
+ */
+ fr_store_debug_state();
/*
- * Initialising OpenSSL once, here, is safer than having individual
- * modules do it.
+ * Initialising OpenSSL once, here, is safer than having individual modules do it.
*/
#ifdef HAVE_OPENSSL_CRYPTO_H
tls_global_init();
#endif
/*
- * Initialize any event loops just enough so module instantiations
- * can add fd/event to them, but do not start them yet.
+ * Write the PID always if we're running as a daemon.
*/
- if (!radius_event_init(autofree)) {
- exit(EXIT_FAILURE);
- }
+ if (main_config.daemonize) main_config.write_pid = true;
- /* Read the configuration files, BEFORE doing anything else. */
- if (main_config_init() < 0) {
- exit(EXIT_FAILURE);
- }
+ /*
+ * Read the configuration files, BEFORE doing anything else.
+ */
+ if (main_config_init() < 0) exit(EXIT_FAILURE);
- /* Check for vulnerabilities in the version of libssl were linked against */
-#ifdef HAVE_OPENSSL_CRYPTO_H
-#ifdef ENABLE_OPENSSL_VERSION_CHECK
- if (tls_global_version_check(main_config.allow_vulnerable_openssl) < 0) {
- exit(EXIT_FAILURE);
- }
-#endif
+ /*
+ * This is very useful in figuring out why the panic_action didn't fire.
+ */
+ INFO("%s", fr_debug_state_to_msg(fr_debug_state));
+
+ /*
+ * Check for vulnerabilities in the version of libssl were linked against.
+ */
+#if defined(HAVE_OPENSSL_CRYPTO_H) && defined(ENABLE_OPENSSL_VERSION_CHECK)
+ if (tls_global_version_check(main_config.allow_vulnerable_openssl) < 0) exit(EXIT_FAILURE);
#endif
+ fr_talloc_fault_setup();
+
/*
- * Load the modules
+ * Set the panic action (if required)
*/
- if (modules_init(main_config.config) < 0) {
- exit(EXIT_FAILURE);
- }
+ {
+ char const *panic_action = NULL;
- /* Set the panic action (if required) */
- if (main_config.panic_action &&
-#ifndef NDEBUG
- !getenv("PANIC_ACTION") &&
-#endif
- (fr_fault_setup(main_config.panic_action, argv[0]) < 0)) {
- fr_perror("radiusd");
- exit(EXIT_FAILURE);
+ panic_action = getenv("PANIC_ACTION");
+ if (!panic_action) panic_action = main_config.panic_action;
+
+ if (panic_action && (fr_fault_setup(panic_action, argv[0]) < 0)) {
+ fr_perror("radiusd");
+ exit(EXIT_FAILURE);
+ }
}
#ifndef __MINGW32__
-
-
/*
* Disconnect from session
*/
close(from_child[1]);
/*
- * The child writes a 0x01 byte on
- * success, and closes the pipe on error.
+ * The child writes a 0x01 byte on success, and closes
+ * the pipe on error.
*/
if ((read(from_child[0], &ret, 1) < 0)) {
ret = 0;
#endif
/*
- * Ensure that we're using the CORRECT pid after forking,
- * NOT the one we started with.
+ * Ensure that we're using the CORRECT pid after forking, NOT the one
+ * we started with.
*/
radius_pid = getpid();
/*
- * Redirect stderr/stdout as appropriate.
+ * Initialize any event loops just enough so module instantiations can
+ * add fd/event to them, but do not start them yet.
+ *
+ * This has to be done post-fork in case we're using kqueue, where the
+ * queue isn't inherited by the child process.
+ */
+ if (!radius_event_init(autofree)) exit(EXIT_FAILURE);
+
+ /*
+ * Load the modules
+ */
+ if (modules_init(main_config.config) < 0) exit(EXIT_FAILURE);
+
+ /*
+ * Redirect stderr/stdout as appropriate.
*/
if (radlog_init(&default_log, main_config.daemonize) < 0) {
ERROR("%s", fr_strerror());
exit(EXIT_FAILURE);
}
+ event_loop_started = true;
+
/*
- * Start the event loop(s) and threads.
+ * Start the event loop(s) and threads.
*/
radius_event_start(main_config.config, spawn_flag);
/*
- * Now that we've set everything up, we can install the signal
- * handlers. Before this, if we get any signal, we don't know
- * what to do, so we might as well do the default, and die.
+ * Now that we've set everything up, we can install the signal
+ * handlers. Before this, if we get any signal, we don't know
+ * what to do, so we might as well do the default, and die.
*/
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
}
/*
- * If we're debugging, then a CTRL-C will cause the
- * server to die immediately. Use SIGTERM to shut down
- * the server cleanly in that case.
+ * If we're debugging, then a CTRL-C will cause the server to die
+ * immediately. Use SIGTERM to shut down the server cleanly in
+ * that case.
*/
- if (main_config.debug_memory || (debug_flag == 0)) {
+ if (main_config.debug_memory || (rad_debug_lvl == 0)) {
if ((fr_set_signal(SIGINT, sig_fatal) < 0)
#ifdef SIGQUIT
|| (fr_set_signal(SIGQUIT, sig_fatal) < 0)
}
/*
- * Everything seems to have loaded OK, exit gracefully.
+ * Everything seems to have loaded OK, exit gracefully.
*/
if (check_config) {
DEBUG("Configuration appears to be OK");
/* for -C -m|-M */
- if (main_config.debug_memory) {
- goto cleanup;
- }
+ if (main_config.debug_memory) goto cleanup;
exit(EXIT_SUCCESS);
}
#endif
/*
- * Write the PID always if we're running as a daemon.
+ * Write the PID after we've forked, so that we write the correct one.
*/
- if (main_config.daemonize) write_pid = true;
-
- /*
- * Write the PID after we've forked, so that we write the
- * correct one.
- */
- if (write_pid) {
+ if (main_config.write_pid) {
FILE *fp;
fp = fopen(main_config.pid_file, "w");
if (fp != NULL) {
/*
- * FIXME: What about following symlinks,
- * and having it over-write a normal file?
+ * @fixme What about following symlinks,
+ * and having it over-write a normal file?
*/
fprintf(fp, "%d\n", (int) radius_pid);
fclose(fp);
} else {
- ERROR("Failed creating PID file %s: %s\n",
- main_config.pid_file, fr_syserror(errno));
+ ERROR("Failed creating PID file %s: %s", main_config.pid_file, fr_syserror(errno));
exit(EXIT_FAILURE);
}
}
exec_trigger(NULL, NULL, "server.start", false);
/*
- * Inform the parent (who should still be waiting) that
- * the rest of initialisation went OK, and that it should
- * exit with a 0 status. If we don't get this far, then
- * we just close the pipe on exit, and the parent gets a
- * read failure.
+ * Inform the parent (who should still be waiting) that the rest of
+ * initialisation went OK, and that it should exit with a 0 status.
+ * If we don't get this far, then we just close the pipe on exit, and the
+ * parent gets a read failure.
*/
if (main_config.daemonize) {
if (write(from_child[1], "\001", 1) < 0) {
}
/*
- * Clear the libfreeradius error buffer
+ * Clear the libfreeradius error buffer.
*/
fr_strerror();
- fr_state_init();
+ /*
+ * Initialise the state rbtree (used to link multiple rounds of challenges).
+ */
+ state = fr_state_init(NULL);
/*
- * Process requests until HUP or exit.
+ * Process requests until HUP or exit.
*/
while ((status = radius_event_process()) == 0x80) {
#ifdef WITH_STATS
}
/*
- * Ignore the TERM signal: we're
- * about to die.
+ * Ignore the TERM signal: we're about to die.
*/
signal(SIGTERM, SIG_IGN);
/*
- * Fire signal and stop triggers after ignoring SIGTERM, so handlers are
- * not killed with the rest of the process group, below.
+ * Fire signal and stop triggers after ignoring SIGTERM, so handlers are
+ * not killed with the rest of the process group, below.
*/
- if (status == 2)
- exec_trigger(NULL, NULL, "server.signal.term", true);
+ if (status == 2) exec_trigger(NULL, NULL, "server.signal.term", true);
exec_trigger(NULL, NULL, "server.stop", false);
/*
- * Send a TERM signal to all
- * associated processes
- * (including us, which gets
- * ignored.)
+ * Send a TERM signal to all associated processes
+ * (including us, which gets ignored.)
*/
#ifndef __MINGW32__
if (spawn_flag) kill(-radius_pid, SIGTERM);
#endif
/*
- * We're exiting, so we can delete the PID
- * file. (If it doesn't exist, we can ignore
- * the error returned by unlink)
+ * We're exiting, so we can delete the PID file.
+ * (If it doesn't exist, we can ignore the error returned by unlink)
*/
- if (main_config.daemonize) {
- unlink(main_config.pid_file);
- }
+ if (main_config.daemonize) unlink(main_config.pid_file);
radius_event_free();
cleanup:
/*
- * Detach any modules.
+ * Detach any modules.
*/
modules_free();
xlat_free(); /* modules may have xlat's */
- fr_state_delete();
+ fr_state_delete(state);
/*
- * Free the configuration items.
+ * Free the configuration items.
*/
main_config_free();
#endif
/*
- * So we don't see autofreed memory in the talloc report
+ * So we don't see autofreed memory in the talloc report
*/
talloc_free(autofree);
fprintf(output, " -h Print this help message.\n");
fprintf(output, " -i <ipaddr> Listen on ipaddr ONLY.\n");
fprintf(output, " -l <log_file> Logging output will be written to this file.\n");
- fprintf(output, " -m On SIGINT or SIGQUIT exit cleanly instead of immediately.\n");
+ fprintf(output, " -m On SIGINT or SIGQUIT clean up all used memory instead of just exiting.\n");
fprintf(output, " -n <name> Read raddb/name.conf instead of raddb/radiusd.conf.\n");
fprintf(output, " -p <port> Listen on port ONLY.\n");
fprintf(output, " -P Always write out PID, even with -f.\n");
- fprintf(output, " -s Do not spawn child processes to handle requests.\n");
+ fprintf(output, " -s Do not spawn child processes to handle requests (same as -ft).\n");
fprintf(output, " -t Disable threads.\n");
fprintf(output, " -v Print server version information.\n");
- fprintf(output, " -X Turn on full debugging.\n");
- fprintf(output, " -x Turn on additional debugging. (-xx gives more debugging).\n");
+ fprintf(output, " -X Turn on full debugging (similar to -tfxxl stdout).\n");
+ fprintf(output, " -x Turn on additional debugging (-xx gives more debugging).\n");
exit(status);
}
{
if (getpid() != radius_pid) _exit(sig);
- switch(sig) {
+ switch (sig) {
case SIGTERM:
radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
break;