#ifdef DELETE_BLOCKED_REQUESTS
{ "delete_blocked_requests", PW_TYPE_INTEGER, 0, &mainconfig.kill_unresponsive_children, Stringify(FALSE) },
#endif
- { "allow_core_dumps", PW_TYPE_BOOLEAN, 0, &allow_core_dumps, "no" },
-
{ "pidfile", PW_TYPE_STRING_PTR, 0, &mainconfig.pid_file, "${run_dir}/radiusd.pid"},
{ "checkrad", PW_TYPE_STRING_PTR, 0, &mainconfig.checkrad, "${sbindir}/checkrad" },
{ NULL, -1, 0, NULL, NULL }
};
+static const CONF_PARSER bootstrap_config[] = {
+#ifdef HAVE_SETUID
+ { "user", PW_TYPE_STRING_PTR, 0, &uid_name, NULL },
+ { "group", PW_TYPE_STRING_PTR, 0, &gid_name, NULL },
+#endif
+ { "chroot", PW_TYPE_STRING_PTR, 0, &chroot_dir, NULL },
+ { "allow_core_dumps", PW_TYPE_BOOLEAN, 0, &allow_core_dumps, "no" },
+
+ { NULL, -1, 0, NULL, NULL }
+};
+
+
+
#define MAX_ARGV (256)
return(0);
}
+#ifdef HAVE_SYS_RESOURCE_H
+static struct rlimit core_limits;
+#endif
+
+static void fr_set_dumpable(void)
+{
+ /*
+ * If configured, turn core dumps off.
+ */
+ if (!allow_core_dumps) {
+#ifdef HAVE_SYS_RESOURCE_H
+ struct rlimit no_core;
+
+
+ no_core.rlim_cur = 0;
+ no_core.rlim_max = 0;
+
+ if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
+ radlog(L_ERR, "Failed disabling core dumps: %s",
+ strerror(errno));
+ }
+#endif
+ return;
+ }
+
+ /*
+ * Set or re-set the dumpable flag.
+ */
+#ifdef HAVE_SYS_PRCTL_H
+#ifdef PR_SET_DUMPABLE
+ if (prctl(PR_SET_DUMPABLE, 1) < 0) {
+ radlog(L_ERR,"Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: '%s'",
+ strerror(errno));
+ }
+#endif
+#endif
+
+ /*
+ * Reset the core dump limits to their original value.
+ */
+#ifdef HAVE_SYS_RESOURCE_H
+ if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
+ radlog(L_ERR, "Cannot update core dump limit: %s",
+ strerror(errno));
+ }
+#endif
+}
#ifdef HAVE_SETUID
static int doing_setuid = FALSE;
progname);
_exit(1);
}
+
+ fr_set_dumpable();
}
void fr_suid_down_permanent(void)
radlog(L_ERR, "Switched to unknown uid");
_exit(1);
}
+
+ fr_set_dumpable();
}
#else
/*
progname, uid_name, strerror(errno));
_exit(1);
}
+
+ fr_set_dumpable();
}
void fr_suid_down_permanent(void)
{
+ fr_set_dumpable();
}
#endif /* HAVE_SETRESUID && HAVE_GETRESUID */
#else /* HAVE_SETUID */
}
void fr_suid_down(void)
{
+ fr_set_dumpable();
}
void fr_suid_down_permanent(void)
{
+ fr_set_dumpable();
}
#endif /* HAVE_SETUID */
*/
static int switch_users(CONF_SECTION *cs)
{
- CONF_PAIR *cp;
-
#ifdef HAVE_SYS_RESOURCE_H
- struct rlimit core_limits;
+ /*
+ * Get the current maximum for core files. Do this
+ * before anything else so as to ensure it's properly
+ * initialized.
+ */
+ if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
+ radlog(L_ERR, "Failed to get current core limit: %s", strerror(errno));
+ return 0;
+ }
#endif
/*
*/
if (debug_flag && (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. */
- cp = cf_pair_find(cs, "group");
- if (cp) gid_name = cf_pair_value(cp);
if (gid_name) {
struct group *gr;
- DEBUG2("group = %s", gid_name);
gr = getgrnam(gid_name);
if (gr == NULL) {
fprintf(stderr, "%s: Cannot get ID for group %s: %s\n",
#ifdef HAVE_PWD_H
/* Set UID. */
- cp = cf_pair_find(cs, "user");
- if (cp) uid_name = cf_pair_value(cp);
if (uid_name) {
struct passwd *pw;
- DEBUG2("user = %s", uid_name);
pw = getpwnam(uid_name);
if (pw == NULL) {
fprintf(stderr, "%s: Cannot get passwd entry for user %s: %s\n",
progname, uid_name, strerror(errno));
return 0;
}
- server_uid = pw->pw_uid;
+
+ if (getuid() == pw->pw_uid) {
+ uid_name = NULL;
+ } else {
+
+ server_uid = pw->pw_uid;
#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, strerror(errno));
- return 0;
- }
+ if (initgroups(uid_name, server_gid) < 0) {
+ fprintf(stderr, "%s: Cannot initialize supplementary group list for user %s: %s\n",
+ progname, uid_name, strerror(errno));
+ return 0;
+ }
#endif
+ }
} else {
server_uid = getuid();
}
#endif
- cp = cf_pair_find(cs, "chroot");
- if (cp) chroot_dir = cf_pair_value(cp);
if (chroot_dir) {
- DEBUG2("chroot = %s", chroot_dir);
if (chroot(chroot_dir) < 0) {
fprintf(stderr, "%s: Failed to perform chroot %s: %s",
progname, chroot_dir, strerror(errno));
* things needed inside of the chroot are the
* logging directories.
*/
- radlog(L_INFO, "performing chroot to %s\n", chroot_dir);
}
#ifdef HAVE_GRP_H
/*
* Just before losing root permissions, ensure that the
* log files have the correct owner && group.
+ *
+ * We have to do this because the log file MAY have been
+ * specified on the command-line.
*/
if (uid_name || gid_name) {
if ((mainconfig.radlog_dest == RADLOG_FILES) &&
- (mainconfig.log_file != NULL)) {
- int fd = open(mainconfig.log_file,
- O_WRONLY | O_APPEND | O_CREAT, 0640);
- if (fd < 0) {
- fprintf(stderr, "%s: Cannot write to log file %s: %s\n",
- progname, mainconfig.log_file, strerror(errno));
+ (mainconfig.radlog_fd < 0)) {
+ mainconfig.radlog_fd = open(mainconfig.log_file,
+ O_WRONLY | O_APPEND | O_CREAT, 0640);
+ if (mainconfig.radlog_fd < 0) {
+ fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, strerror(errno));
return 0;
}
- close(fd);
- }
- if (chown(mainconfig.log_file, server_uid, server_gid) < 0) {
- fprintf(stderr, "%s: Cannot change ownership of log file: %s\n",
- progname, mainconfig.log_file, strerror(errno));
- return 0;
+ if (chown(mainconfig.log_file, server_uid, server_gid) < 0) {
+ fprintf(stderr, "%s: Cannot change ownership of log file %s: %s\n",
+ progname, mainconfig.log_file, strerror(errno));
+ return 0;
+ }
}
}
doing_setuid = TRUE;
fr_suid_down();
-
- /*
- * Now core dumps are disabled on most secure systems.
- */
- }
-#endif
-
-#ifdef HAVE_SYS_RESOURCE_H
- /* Get the current maximum for core files. */
- if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
- radlog(L_ERR, "Failed to get current core limit: %s", strerror(errno));
- return 0;
}
#endif
/*
- * Core dumps are allowed if we're in debug mode, OR
- * we've allowed them, OR we did a setuid (which turns
- * core dumps off).
- *
- * Otherwise, disable core dumps for security.
- *
+ * This also clears the dumpable flag if core dumps
+ * aren't allowed.
*/
- if (!(debug_flag || allow_core_dumps || doing_setuid)) {
-#ifdef HAVE_SYS_RESOURCE_H
- struct rlimit no_core;
-
- no_core.rlim_cur = 0;
- no_core.rlim_max = 0;
-
- if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
- radlog(L_ERR, "Failed disabling core dumps: %s",
- strerror(errno));
- return 0;
- }
-#endif
-
- /*
- * Otherwise, re-enable core dumps if we're
- * running as a daemon, AND core dumps are
- * allowed, AND we changed UID's.
- */
- } else if ((debug_flag == 0) && allow_core_dumps && doing_setuid) {
- /*
- * Set the dumpable flag.
- */
-#ifdef HAVE_SYS_PRCTL_H
-#ifdef PR_SET_DUMPABLE
- if (prctl(PR_SET_DUMPABLE, 1) < 0) {
- radlog(L_ERR,"Cannot enable core dumps: prctl(PR_SET_DUMPABLE) failed: '%s'",
- strerror(errno));
- }
-#endif
-#endif
-
- /*
- * Reset the core dump limits again, just to
- * double check that they haven't changed.
- */
-#ifdef HAVE_SYS_RESOURCE_H
- if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
- radlog(L_ERR, "Cannot update core dump limit: %s",
- strerror(errno));
- return 0;
- }
-#endif
+ fr_set_dumpable();
+ if (allow_core_dumps) {
radlog(L_INFO, "Core dumps are enabled.");
}
- /*
- * Else we're debugging (so core dumps are enabled)
- * OR we're not debugging, AND "allow_core_dumps == FALSE",
- * OR we're not debugging, AND core dumps are allowed,
- * BUT we didn't call setuid, so we haven't changed the
- * core dump capabilities inherited from the parent shell.
- */
return 1;
}
cf_section_free(&cs);
return -1;
}
+
+#ifdef HAVE_SYSLOG_H
+ /*
+ * Call openlog only once, when the
+ * program starts.
+ */
+ openlog(progname, LOG_PID, mainconfig.syslog_facility);
+#endif
+
+ } else if (mainconfig.radlog_dest == RADLOG_FILES) {
+ if (!mainconfig.log_file) {
+ fprintf(stderr, "radiusd: Error: Specified \"files\" as a log destination, but no log filename was given!\n");
+ cf_section_free(&cs);
+ return -1;
+ }
}
}
if (!switch_users(cs)) exit(1);
#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 ((mainconfig.radlog_dest == RADLOG_FILES) &&
+ (mainconfig.radlog_fd < 0)) {
+ mainconfig.radlog_fd = open(mainconfig.log_file,
+ O_WRONLY | O_APPEND | O_CREAT, 0640);
+ if (mainconfig.radlog_fd < 0) {
+ fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, strerror(errno));
+ cf_section_free(&cs);
+ return -1;
+ }
+ }
+
/* Initialize the dictionary */
cp = cf_pair_find(cs, "dictionary");
if (cp) p = cf_pair_value(cp);
CONF_SECTION *cs;
char buffer[1024];
+ radlog(L_INFO, "HUP - Re-reading configuration files");
+
/* Read the configuration file */
snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
radius_dir, mainconfig.name);
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.
+ */
+ if (mainconfig.radlog_dest == RADLOG_FILES) {
+ int fd, old_fd;
+
+ fd = open(mainconfig.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 = mainconfig.radlog_fd;
+ mainconfig.radlog_fd = fd;
+ close(old_fd);
+ }
+ }
+
+ radlog(L_INFO, "HUP - loading modules");
+
+ /*
* Prefer the new module configuration.
*/
module_hup(cf_section_sub_find(cs, "modules"));