#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
+#include <freeradius-devel/modpriv.h>
#include <freeradius-devel/rad_assert.h>
#include <sys/stat.h>
-
-#ifdef HAVE_PWD_H
#include <pwd.h>
-#endif
-
-#ifdef HAVE_GRP_H
#include <grp.h>
-#endif
#ifdef HAVE_SYSLOG_H
-# include <syslog.h>
-#endif
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
+# include <syslog.h>
#endif
#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
+# include <fcntl.h>
#endif
-struct main_config_t main_config;
-char *debug_condition = NULL;
-extern bool log_dates_utc;
+main_config_t main_config; //!< Main server configuration.
+extern fr_cond_t *debug_condition;
+fr_cond_t *debug_condition = NULL; //!< Condition used to mark packets up for checking.
+bool event_loop_started = false; //!< Whether the main event loop has been started yet.
typedef struct cached_config_t {
struct cached_config_t *next;
static char const *radius_dir = NULL; //!< Path to raddb directory
+/**********************************************************************
+ *
+ * We need to figure out where the logs go, before doing anything
+ * else. This is so that the log messages go to the correct
+ * place.
+ *
+ * BUT, we want the settings from the command line to over-ride
+ * the ones in the configuration file. So, these items are
+ * parsed ONLY if there is no "-l foo" on the command line.
+ *
+ **********************************************************************/
/*
- * Security configuration for the server.
- */
-static const CONF_PARSER security_config[] = {
- { "max_attributes", FR_CONF_POINTER(PW_TYPE_INTEGER, &fr_max_attributes), STRINGIFY(0) },
- { "reject_delay", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.reject_delay), STRINGIFY(0) },
- { "status_server", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.status_server), "no"},
- { "allow_vulnerable_openssl", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.allow_vulnerable_openssl), "no"},
- { NULL, -1, 0, NULL, NULL }
-};
-
-
-/*
- * Logging configuration for the server.
+ * Log destinations
*/
-static const CONF_PARSER logdest_config[] = {
+static const CONF_PARSER startup_log_config[] = {
{ "destination", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dest), "files" },
{ "syslog_facility", FR_CONF_POINTER(PW_TYPE_STRING, &syslog_facility), STRINGIFY(0) },
+ { "localstatedir", FR_CONF_POINTER(PW_TYPE_STRING, &localstatedir), "${prefix}/var"},
+ { "logdir", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dir), "${localstatedir}/log"},
{ "file", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.log_file), "${logdir}/radius.log" },
- { "requests", FR_CONF_POINTER(PW_TYPE_STRING, &default_log.file), NULL },
- { NULL, -1, 0, NULL, NULL }
+ { "requests", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_DEPRECATED, &default_log.file), NULL },
+ CONF_PARSER_TERMINATOR
};
-static const CONF_PARSER serverdest_config[] = {
- { "log", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) logdest_config },
+/*
+ * Basic configuration for the server.
+ */
+static const CONF_PARSER startup_server_config[] = {
+ { "log", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) startup_log_config },
+
+ { "name", FR_CONF_POINTER(PW_TYPE_STRING, &my_name), "radiusd"},
+ { "prefix", FR_CONF_POINTER(PW_TYPE_STRING, &prefix), "/usr/local"},
+
{ "log_file", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.log_file), NULL },
{ "log_destination", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dest), NULL },
{ "use_utc", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &log_dates_utc), NULL },
- { NULL, -1, 0, NULL, NULL }
+ CONF_PARSER_TERMINATOR
};
-static const CONF_PARSER log_config_nodest[] = {
+/**********************************************************************
+ *
+ * Now that we've parsed the log destination, AND the security
+ * items, we can parse the rest of the configuration items.
+ *
+ **********************************************************************/
+static const CONF_PARSER log_config[] = {
{ "stripped_names", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &log_stripped_names),"no" },
{ "auth", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_auth), "no" },
{ "auth_badpass", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_auth_badpass), "no" },
{ "msg_goodpass", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.auth_goodpass_msg), NULL},
{ "colourise",FR_CONF_POINTER(PW_TYPE_BOOLEAN, &do_colourise), NULL },
{ "use_utc", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &log_dates_utc), NULL },
- { "msg_denied", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.denied_msg),
- "You are already logged in - access denied" },
-
- { NULL, -1, 0, NULL, NULL }
+ { "msg_denied", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.denied_msg), "You are already logged in - access denied" },
+ CONF_PARSER_TERMINATOR
};
/*
- * A mapping of configuration file names to internal variables
+ * Security configuration for the server.
*/
+static const CONF_PARSER security_config[] = {
+ { "max_attributes", FR_CONF_POINTER(PW_TYPE_INTEGER, &fr_max_attributes), STRINGIFY(0) },
+ { "reject_delay", FR_CONF_POINTER(PW_TYPE_TIMEVAL, &main_config.reject_delay), STRINGIFY(0) },
+ { "status_server", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.status_server), "no"},
+#ifdef ENABLE_OPENSSL_VERSION_CHECK
+ { "allow_vulnerable_openssl", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.allow_vulnerable_openssl), "no"},
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER resources[] = {
+ /*
+ * Don't set a default here. It's set in the code, below. This means that
+ * the config item will *not* get printed out in debug mode, so that no one knows
+ * it exists.
+ */
+ { "talloc_pool_size", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.talloc_pool_size), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
static const CONF_PARSER server_config[] = {
/*
* FIXME: 'prefix' is the ONLY one which should be
#ifdef WITH_PROXY
{ "proxy_requests", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.proxy_requests), "yes" },
#endif
- { "log", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) log_config_nodest },
+ { "log", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) log_config },
+
+ { "resources", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) resources },
/*
* People with old configs will have these. They are listed
{ "log_stripped_names", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &log_stripped_names), NULL },
{ "security", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) security_config },
-
- { NULL, -1, 0, NULL, NULL }
+ CONF_PARSER_TERMINATOR
};
+
+/**********************************************************************
+ *
+ * The next few items are here as a "bootstrap" for security.
+ * They allow the server to switch users, chroot, while still
+ * opening the various output files with the correct permission.
+ *
+ * It's rare (or impossible) to have parse errors here, so we
+ * don't worry too much about that. In contrast, when we parse
+ * the rest of the configuration, we CAN get parse errors. We
+ * want THOSE parse errors to go to the log file, and we want the
+ * log file to have the correct permissions.
+ *
+ **********************************************************************/
static const CONF_PARSER bootstrap_security_config[] = {
#ifdef HAVE_SETUID
{ "user", FR_CONF_POINTER(PW_TYPE_STRING, &uid_name), NULL },
#endif
{ "chroot", FR_CONF_POINTER(PW_TYPE_STRING, &chroot_dir), NULL },
{ "allow_core_dumps", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &allow_core_dumps), "no" },
-
- { NULL, -1, 0, NULL, NULL }
+ CONF_PARSER_TERMINATOR
};
static const CONF_PARSER bootstrap_config[] = {
{ "security", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) bootstrap_security_config },
+ { "name", FR_CONF_POINTER(PW_TYPE_STRING, &my_name), "radiusd"},
+ { "prefix", FR_CONF_POINTER(PW_TYPE_STRING, &prefix), "/usr/local"},
+ { "localstatedir", FR_CONF_POINTER(PW_TYPE_STRING, &localstatedir), "${prefix}/var"},
+
+ { "logdir", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dir), "${localstatedir}/log"},
+ { "run_dir", FR_CONF_POINTER(PW_TYPE_STRING, &run_dir), "${localstatedir}/run/${name}"},
+
/*
* For backwards compatibility.
*/
#endif
{ "chroot", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_DEPRECATED, &chroot_dir), NULL },
{ "allow_core_dumps", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &allow_core_dumps), NULL },
-
- { NULL, -1, 0, NULL, NULL }
+ CONF_PARSER_TERMINATOR
};
-
-#define MAX_ARGV (256)
-
-
static size_t config_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
{
size_t len = 0;
- static char const *disallowed = "%{}\\'\"`";
+ static char const disallowed[] = "%{}\\'\"`";
while (in[0]) {
/*
return -1;
}
- cp = cf_itemtopair(ci);
+ cp = cf_item_to_pair(ci);
/*
* Ensure that we only copy what's necessary.
strlcpy(out, request->client->shortname, outlen);
return strlen(out);
}
- RDEBUG("Client does not contain config item \"%s\"", fmt);
*out = '\0';
return 0;
}
}
strlcpy(buffer, p, (q + 1) - p);
- if (fr_pton(&ip, buffer, 0, false) <= 0) {
+ if (fr_pton(&ip, buffer, -1, AF_UNSPEC, false) < 0) {
REDEBUG("\"%s\" is not a valid IPv4 or IPv6 address", buffer);
goto error;
}
strlcpy(out, request->client->shortname, outlen);
return strlen(out);
}
- RDEBUG("Client does not contain config item \"%s\"", fmt);
*out = '\0';
return 0;
}
return -1;
}
-#ifdef HAVE_SETUID
-static bool doing_setuid = false;
-
-# if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
-void fr_suid_up(void)
-{
- uid_t ruid, euid, suid;
-
- if (getresuid(&ruid, &euid, &suid) < 0) {
- ERROR("Failed getting saved UID's");
- fr_exit_now(1);
- }
-
- if (setresuid(-1, suid, -1) < 0) {
- ERROR("Failed switching to privileged user");
- fr_exit_now(1);
- }
-
- if (geteuid() != suid) {
- ERROR("Switched to unknown UID");
- fr_exit_now(1);
- }
-}
-
-void fr_suid_down(void)
-{
- if (!doing_setuid) return;
-
- if (setresuid(-1, server_uid, geteuid()) < 0) {
- fprintf(stderr, "%s: Failed switching to uid %s: %s\n",
- progname, uid_name, fr_syserror(errno));
- fr_exit_now(1);
- }
-
- if (geteuid() != server_uid) {
- fprintf(stderr, "%s: Failed switching uid: UID is incorrect\n",
- progname);
- fr_exit_now(1);
- }
-
- fr_set_dumpable(allow_core_dumps);
-}
-
-void fr_suid_down_permanent(void)
-{
- if (!doing_setuid) return;
-
- if (setresuid(server_uid, server_uid, server_uid) < 0) {
- ERROR("Failed in permanent switch to uid %s: %s",
- uid_name, fr_syserror(errno));
- fr_exit_now(1);
- }
-
- if (geteuid() != server_uid) {
- ERROR("Switched to unknown uid");
- fr_exit_now(1);
- }
-
- fr_set_dumpable(allow_core_dumps);
-}
-# else
/*
- * Much less secure...
+ * Xlat for %{listen:foo}
*/
-void fr_suid_up(void)
+static ssize_t xlat_listen(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
{
-}
+ char const *value = NULL;
+ CONF_PAIR *cp;
-void fr_suid_down(void)
-{
- if (!uid_name) return;
+ if (!fmt || !out || (outlen < 1)) return 0;
- if (setuid(server_uid) < 0) {
- fprintf(stderr, "%s: Failed switching to uid %s: %s\n",
- progname, uid_name, fr_syserror(errno));
- fr_exit(1);
+ if (!request->listener) {
+ RWDEBUG("No listener associated with this request");
+ *out = '\0';
+ return 0;
}
- fr_set_dumpable(allow_core_dumps);
-}
+ cp = cf_pair_find(request->listener->cs, fmt);
+ if (!cp || !(value = cf_pair_value(cp))) {
+ RDEBUG("Listener does not contain config item \"%s\"", fmt);
+ *out = '\0';
+ return 0;
+ }
-void fr_suid_down_permanent(void)
-{
- fr_set_dumpable(allow_core_dumps);
-}
-# endif /* HAVE_SETRESUID && HAVE_GETRESUID */
-#else /* HAVE_SETUID */
-void fr_suid_up(void)
-{
-}
-void fr_suid_down(void)
-{
- fr_set_dumpable(allow_core_dumps);
-}
-void fr_suid_down_permanent(void)
-{
- fr_set_dumpable(allow_core_dumps);
+ strlcpy(out, value, outlen);
+
+ return strlen(out);
}
-#endif /* HAVE_SETUID */
#ifdef HAVE_SETUID
-
/*
* Do chroot, if requested.
*
*/
static int switch_users(CONF_SECTION *cs)
{
+ bool do_suid = false;
+ bool do_sgid = false;
+
/*
* Get the current maximum for core files. Do this
* before anything else so as to ensure it's properly
* Don't do chroot/setuid/setgid if we're in debugging
* as non-root.
*/
- if (debug_flag && (getuid() != 0)) return 1;
+ if (rad_debug_lvl && (getuid() != 0)) return 1;
if (cf_section_parse(cs, NULL, bootstrap_config) < 0) {
fprintf(stderr, "radiusd: Error: Failed to parse user/group information.\n");
return 0;
}
-
#ifdef HAVE_GRP_H
- /* Set GID. */
+ /*
+ * Get the correct GID for the server.
+ */
+ server_gid = getgid();
+
if (gid_name) {
struct group *gr;
gr = getgrnam(gid_name);
- if (gr == NULL) {
+ if (!gr) {
fprintf(stderr, "%s: Cannot get ID for group %s: %s\n",
progname, gid_name, fr_syserror(errno));
return 0;
}
- server_gid = gr->gr_gid;
- } else {
- server_gid = getgid();
+
+ if (server_gid != gr->gr_gid) {
+ server_gid = gr->gr_gid;
+ do_sgid = true;
+ }
}
#endif
-#ifdef HAVE_PWD_H
- /* Set UID. */
+ /*
+ * Get the correct UID for the server.
+ */
+ server_uid = getuid();
+
if (uid_name) {
- struct passwd *pw;
+ struct passwd *user;
- pw = getpwnam(uid_name);
- if (pw == NULL) {
+ if (rad_getpwnam(cs, &user, uid_name) < 0) {
fprintf(stderr, "%s: Cannot get passwd entry for user %s: %s\n",
- progname, uid_name, fr_syserror(errno));
+ progname, uid_name, fr_strerror());
return 0;
}
- if (getuid() == pw->pw_uid) {
- uid_name = NULL;
- } else {
-
- server_uid = pw->pw_uid;
+ /*
+ * We're not the correct user. Go set that.
+ */
+ if (server_uid != user->pw_uid) {
+ server_uid = user->pw_uid;
+ do_suid = true;
#ifdef HAVE_INITGROUPS
if (initgroups(uid_name, server_gid) < 0) {
fprintf(stderr, "%s: Cannot initialize supplementary group list for user %s: %s\n",
progname, uid_name, fr_syserror(errno));
+ talloc_free(user);
return 0;
}
#endif
}
- } else {
- server_uid = getuid();
+
+ talloc_free(user);
}
-#endif
+ /*
+ * Do chroot BEFORE changing UIDs.
+ */
if (chroot_dir) {
if (chroot(chroot_dir) < 0) {
fprintf(stderr, "%s: Failed to perform chroot %s: %s",
}
#ifdef HAVE_GRP_H
- /* Set GID. */
- if (gid_name && (setgid(server_gid) < 0)) {
- fprintf(stderr, "%s: Failed setting group to %s: %s",
- progname, gid_name, fr_syserror(errno));
- return 0;
+ /*
+ * Set the GID. Don't bother checking it.
+ */
+ if (do_sgid) {
+ if (setgid(server_gid) < 0){
+ fprintf(stderr, "%s: Failed setting group to %s: %s",
+ progname, gid_name, fr_syserror(errno));
+ return 0;
+ }
}
#endif
-#ifdef HAVE_SETUID
/*
- * Just before losing root permissions, ensure that the
- * log files have the correct owner && group.
+ * The directories for PID files and logs must exist. We
+ * need to create them if we're told to write files to
+ * those directories.
+ *
+ * Because this creation is new in 3.0.9, it's a soft
+ * fail.
*
- * We have to do this because the log file MAY have been
- * specified on the command-line.
*/
- if (uid_name || gid_name) {
- if ((default_log.dst == L_DST_FILES) &&
- (default_log.fd < 0)) {
- default_log.fd = open(main_config.log_file,
- O_WRONLY | O_APPEND | O_CREAT, 0640);
- if (default_log.fd < 0) {
- fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno));
- return 0;
- }
+ if (main_config.write_pid) {
+ char *my_dir;
- if (chown(main_config.log_file, server_uid, server_gid) < 0) {
- fprintf(stderr, "%s: Cannot change ownership of log file %s: %s\n",
- progname, main_config.log_file, fr_syserror(errno));
- return 0;
- }
+ my_dir = talloc_strdup(NULL, run_dir);
+ if (rad_mkdir(my_dir, 0750, server_uid, server_gid) < 0) {
+ DEBUG("Failed to create run_dir %s: %s",
+ my_dir, strerror(errno));
}
+ talloc_free(my_dir);
}
- if (uid_name) {
- doing_setuid = true;
+ if (default_log.dst == L_DST_FILES) {
+ char *my_dir;
- fr_suid_down();
+ my_dir = talloc_strdup(NULL, radlog_dir);
+ if (rad_mkdir(my_dir, 0750, server_uid, server_gid) < 0) {
+ DEBUG("Failed to create logdir %s: %s",
+ my_dir, strerror(errno));
+ }
+ talloc_free(my_dir);
+ }
+
+ /*
+ * Once we're done with all of the privileged work,
+ * permanently change the UID.
+ */
+ if (do_suid) {
+ rad_suid_set_down_uid(server_uid);
+ rad_suid_down();
+ }
+
+ /*
+ * If we don't already have a log file open, open one
+ * now. We may not have been logging anything yet. The
+ * server normally starts up fairly quietly.
+ */
+ if ((default_log.dst == L_DST_FILES) &&
+ (default_log.fd < 0)) {
+ default_log.fd = open(main_config.log_file,
+ O_WRONLY | O_APPEND | O_CREAT, 0640);
+ if (default_log.fd < 0) {
+ fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno));
+ return 0;
+ }
+ }
+
+ /*
+ * If we need to change UID, ensure that the log files
+ * have the correct owner && group.
+ *
+ * We have to do this because some log files MAY already
+ * have been written as root. We need to change them to
+ * have the correct ownership before proceeding.
+ */
+ if ((do_suid || do_sgid) &&
+ (default_log.dst == L_DST_FILES)) {
+ if (fchown(default_log.fd, server_uid, server_gid) < 0) {
+ fprintf(stderr, "%s: Cannot change ownership of log file %s: %s\n",
+ progname, main_config.log_file, fr_syserror(errno));
+ return 0;
+ }
}
-#endif
/*
* This also clears the dumpable flag if core dumps
int main_config_init(void)
{
char const *p = NULL;
- CONF_SECTION *cs;
+ CONF_SECTION *cs, *subcs;
struct stat statbuf;
cached_config_t *cc;
char buffer[1024];
}
#endif
-#ifdef S_IROTH
- if (0 && (statbuf.st_mode & S_IROTH) != 0) {
+#if 0 && defined(S_IROTH)
+ if (statbuf.st_mode & S_IROTH != 0) {
ERROR("Configuration directory %s is globally readable. Refusing to start due to insecure configuration.",
radius_dir);
return -1;
}
/*
+ * About sizeof(REQUEST) + sizeof(RADIUS_PACKET) * 2 + sizeof(VALUE_PAIR) * 400
+ *
+ * Which should be enough for many configurations.
+ */
+ main_config.talloc_pool_size = 8 * 1024; /* default */
+
+ /*
* Read the distribution dictionaries first, then
* the ones in raddb.
*/
*/
DICT_READ_OPTIONAL(radius_dir, RADIUS_DICTIONARY);
+ cs = cf_section_alloc(NULL, "main", NULL);
+ if (!cs) return -1;
+
+ /*
+ * Add a 'feature' subsection off the main config
+ * We check if it's defined first, as the user may
+ * have defined their own feature flags, or want
+ * to manually override the ones set by modules
+ * or the server.
+ */
+ subcs = cf_section_sub_find(cs, "feature");
+ if (!subcs) {
+ subcs = cf_section_alloc(cs, "feature", NULL);
+ if (!subcs) return -1;
+
+ cf_section_add(cs, subcs);
+ }
+ version_init_features(subcs);
+
+ /*
+ * Add a 'version' subsection off the main config
+ * We check if it's defined first, this is for
+ * backwards compatibility.
+ */
+ subcs = cf_section_sub_find(cs, "version");
+ if (!subcs) {
+ subcs = cf_section_alloc(cs, "version", NULL);
+ if (!subcs) return -1;
+ cf_section_add(cs, subcs);
+ }
+ version_init_numbers(subcs);
+
/* Read the configuration file */
- snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
- radius_dir, main_config.name);
- if ((cs = cf_file_read(buffer)) == NULL) {
+ snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", radius_dir, main_config.name);
+ if (cf_file_read(cs, buffer) < 0) {
ERROR("Errors reading or parsing %s", buffer);
+ talloc_free(cs);
return -1;
}
* set it now.
*/
if (default_log.dst == L_DST_NULL) {
- if (cf_section_parse(cs, NULL, serverdest_config) < 0) {
+ if (cf_section_parse(cs, NULL, startup_server_config) < 0) {
fprintf(stderr, "radiusd: Error: Failed to parse log{} section.\n");
cf_file_free(cs);
return -1;
cf_file_free(cs);
return -1;
}
- main_config.syslog_facility = fr_str2int(syslog_str2fac, syslog_facility, -1);
+ main_config.syslog_facility = fr_str2int(syslog_facility_table, syslog_facility, -1);
if (main_config.syslog_facility < 0) {
fprintf(stderr, "radiusd: Error: Unknown syslog_facility %s\n",
syslog_facility);
#endif
/*
- * Open the log file AFTER switching uid / gid. If we
- * did switch uid/gid, then the code in switch_users()
- * took care of setting the file permissions correctly.
- */
- if ((default_log.dst == L_DST_FILES) &&
- (default_log.fd < 0)) {
- default_log.fd = open(main_config.log_file,
- O_WRONLY | O_APPEND | O_CREAT, 0640);
- if (default_log.fd < 0) {
- fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno));
- cf_file_free(cs);
- return -1;
- }
- }
-
- /*
* This allows us to figure out where, relative to
* radiusd.conf, the other configuration files exist.
*/
- if (cf_section_parse(cs, NULL, server_config) < 0) {
- return -1;
- }
+ if (cf_section_parse(cs, NULL, server_config) < 0) return -1;
/*
* We ignore colourization of output until after the
* command-line: use whatever is in the config
* file.
*/
- if (debug_flag == 0) {
- debug_flag = main_config.debug_level;
+ if (rad_debug_lvl == 0) {
+ rad_debug_lvl = main_config.debug_level;
+ }
+ fr_debug_lvl = rad_debug_lvl;
+
+ FR_INTEGER_COND_CHECK("max_request_time", main_config.max_request_time,
+ (main_config.max_request_time != 0), 100);
+
+ /*
+ * reject_delay can be zero. OR 1 though 10.
+ */
+ if ((main_config.reject_delay.tv_sec != 0) || (main_config.reject_delay.tv_usec != 0)) {
+ FR_TIMEVAL_BOUND_CHECK("reject_delay", &main_config.reject_delay, >=, 1, 0);
}
- fr_debug_flag = debug_flag;
+ FR_TIMEVAL_BOUND_CHECK("reject_delay", &main_config.reject_delay, <=, 10, 0);
- FR_INTEGER_COND_CHECK("max_request_time", main_config.max_request_time, (main_config.max_request_time != 0), 100);
- FR_INTEGER_BOUND_CHECK("reject_delay", main_config.reject_delay, <=, 10);
FR_INTEGER_BOUND_CHECK("cleanup_delay", main_config.cleanup_delay, <=, 10);
+ FR_INTEGER_BOUND_CHECK("resources.talloc_pool_size", main_config.talloc_pool_size, >=, 2 * 1024);
+ FR_INTEGER_BOUND_CHECK("resources.talloc_pool_size", main_config.talloc_pool_size, <=, 1024 * 1024);
+
/*
* Set default initial request processing delay to 1/3 of a second.
* Will be updated by the lowest response window across all home servers,
* if it is less than this.
*/
main_config.init_delay.tv_sec = 0;
- main_config.init_delay.tv_usec = 1000000 / 3;
+ main_config.init_delay.tv_usec = 2* (1000000 / 3);
/*
* Free the old configuration items, and replace them
}
DEBUG2("%s: #### Loading Clients ####", main_config.name);
- if (!clients_parse_section(cs, false)) {
+ if (!client_list_parse_section(cs, false)) {
return -1;
}
/*
- * Register the %{config:section.subsection} xlat function.
+ * Register the %{config:section.subsection} xlat function.
*/
xlat_register("config", xlat_config, NULL, NULL);
xlat_register("client", xlat_client, NULL, NULL);
xlat_register("getclient", xlat_getclient, NULL, NULL);
+ xlat_register("listen", xlat_listen, NULL, NULL);
/*
* Go update our behaviour, based on the configuration
* Sanity check the configuration for internal
* consistency.
*/
- FR_INTEGER_BOUND_CHECK("reject_delay", main_config.reject_delay, <=, main_config.cleanup_delay);
+ FR_TIMEVAL_BOUND_CHECK("reject_delay", &main_config.reject_delay, <=, main_config.cleanup_delay, 0);
if (chroot_dir) {
if (chdir(radlog_dir) < 0) {
* Clean up the configuration data
* structures.
*/
- clients_free(NULL);
+ client_list_free(NULL);
realms_free();
listen_free(&main_config.listen);
void hup_logfile(void)
{
- int fd, old_fd;
+ int fd, old_fd;
- if (default_log.dst != L_DST_FILES) return;
+ if (default_log.dst != L_DST_FILES) return;
- fd = open(main_config.log_file,
- O_WRONLY | O_APPEND | O_CREAT, 0640);
- if (fd >= 0) {
- /*
- * Atomic swap. We'd like to keep the old
- * FD around so that callers don't
- * suddenly find the FD closed, and the
- * writes go nowhere. But that's hard to
- * do. So... we have the case where a
- * log message *might* be lost on HUP.
- */
- old_fd = default_log.fd;
- default_log.fd = fd;
- close(old_fd);
- }
+ fd = open(main_config.log_file,
+ O_WRONLY | O_APPEND | O_CREAT, 0640);
+ if (fd >= 0) {
+ /*
+ * Atomic swap. We'd like to keep the old
+ * FD around so that callers don't
+ * suddenly find the FD closed, and the
+ * writes go nowhere. But that's hard to
+ * do. So... we have the case where a
+ * log message *might* be lost on HUP.
+ */
+ old_fd = default_log.fd;
+ default_log.fd = fd;
+ close(old_fd);
+ }
+}
+
+static int hup_callback(void *ctx, void *data)
+{
+ CONF_SECTION *modules = ctx;
+ CONF_SECTION *cs = data;
+ CONF_SECTION *parent;
+ char const *name;
+ module_instance_t *mi;
+
+ /*
+ * Files may be defined in sub-sections of a module
+ * config. Walk up the tree until we find the module
+ * definition.
+ */
+ parent = cf_item_parent(cf_section_to_item(cs));
+ while (parent != modules) {
+ cs = parent;
+ parent = cf_item_parent(cf_section_to_item(cs));
+
+ /*
+ * Something went wrong. Oh well...
+ */
+ if (!parent) return 0;
+ }
+
+ name = cf_section_name2(cs);
+ if (!name) name = cf_section_name1(cs);
+
+ mi = module_find(modules, name);
+ if (!mi) return 0;
+
+ if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) return 0;
+
+ if (!module_hup_module(mi->cs, mi, time(NULL))) return 0;
+
+ return 0;
}
void main_config_hup(void)
{
+ int rcode;
cached_config_t *cc;
CONF_SECTION *cs;
+ time_t when;
char buffer[1024];
- INFO("HUP - Re-reading configuration files");
+ static time_t last_hup = 0;
+
+ /*
+ * Re-open the log file. If we can't, then keep logging
+ * to the old log file.
+ *
+ * The "open log file" code is here rather than in log.c,
+ * because it makes that function MUCH simpler.
+ */
+ hup_logfile();
+
+ /*
+ * Only check the config files every few seconds.
+ */
+ when = time(NULL);
+ if ((last_hup + 2) >= when) {
+ INFO("HUP - Last HUP was too recent. Ignoring");
+ return;
+ }
+ last_hup = when;
+
+ rcode = cf_file_changed(cs_cache->cs, hup_callback);
+ if (rcode == CF_FILE_NONE) {
+ INFO("HUP - No files changed. Ignoring");
+ return;
+ }
+
+ if (rcode == CF_FILE_ERROR) {
+ INFO("HUP - Cannot read configuration files. Ignoring");
+ return;
+ }
+
+ /*
+ * No config files have changed.
+ */
+ if ((rcode & CF_FILE_CONFIG) == 0) {
+ if ((rcode & CF_FILE_MODULE) != 0) {
+ INFO("HUP - Files loaded by a module have changed.");
+
+ /*
+ * FIXME: reload the module.
+ */
+
+ }
+ return;
+ }
+
+ cs = cf_section_alloc(NULL, "main", NULL);
+ if (!cs) return;
/* Read the configuration file */
- snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
- radius_dir, main_config.name);
- if ((cs = cf_file_read(buffer)) == NULL) {
+ snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", radius_dir, main_config.name);
+
+ INFO("HUP - Re-reading configuration files");
+ if (cf_file_read(cs, buffer) < 0) {
ERROR("Failed to re-read or parse %s", buffer);
+ talloc_free(cs);
return;
}
cc->next = cs_cache;
cs_cache = cc;
- /*
- * Re-open the log file. If we can't, then keep logging
- * to the old log file.
- *
- * The "open log file" code is here rather than in log.c,
- * because it makes that function MUCH simpler.
- */
- hup_logfile();
-
INFO("HUP - loading modules");
/*
*/
virtual_servers_load(cs);
- virtual_servers_free(cc->created - main_config.max_request_time * 4);
+ virtual_servers_free(cc->created - (main_config.max_request_time * 4));
}