/* * Do chroot, if requested. * * Switch UID and GID to what is specified in the config file */ static int switch_users(CONF_SECTION *cs) { #ifdef HAVE_SYS_RESOURCE_H /* * 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 /* * Don't do chroot/setuid/setgid if we're in debugging * as non-root. */ 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. */ if (gid_name) { struct group *gr; gr = getgrnam(gid_name); if (gr == NULL) { fprintf(stderr, "%s: Cannot get ID for group %s: %s\n", progname, gid_name, strerror(errno)); return 0; } server_gid = gr->gr_gid; } else { server_gid = getgid(); } #endif #ifdef HAVE_PWD_H /* Set UID. */ if (uid_name) { struct passwd *pw; 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; } 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; } #endif } } else { server_uid = getuid(); } #endif if (chroot_dir) { if (chroot(chroot_dir) < 0) { fprintf(stderr, "%s: Failed to perform chroot %s: %s", progname, chroot_dir, strerror(errno)); return 0; } /* * Note that we leave chdir alone. It may be * OUTSIDE of the root. This allows us to read * the configuration from "-d ./etc/raddb", with * the chroot as "./chroot/" for example. After * the server has been loaded, it does a "cd * ${logdir}" below, so that core files (if any) * go to a logging directory. * * This also allows the configuration of the * server to be outside of the chroot. If the * server is statically linked, then the only * things needed inside of the chroot are the * logging directories. */ } #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, strerror(errno)); return 0; } #endif #ifdef HAVE_SETUID /* * 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.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; } 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; } } } if (uid_name) { doing_setuid = TRUE; fr_suid_down(); } #endif /* * This also clears the dumpable flag if core dumps * aren't allowed. */ fr_set_dumpable(); if (allow_core_dumps) { radlog(L_INFO, "Core dumps are enabled."); } return 1; }
/* * Do chroot, if requested. * * Switch UID and GID to what is specified in the config file */ static int switch_users(CONF_SECTION *cs) { CONF_PAIR *cp; #ifdef HAVE_SYS_RESOURCE_H struct rlimit core_limits; #endif /* * Don't do chroot/setuid/setgid if we're in debugging * as non-root. */ if (debug_flag && (getuid() != 0)) return 1; #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", progname, gid_name, strerror(errno)); return 0; } server_gid = gr->gr_gid; } else { server_gid = getgid(); } #endif #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; #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; } #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)); return 0; } /* * Note that we leave chdir alone. It may be * OUTSIDE of the root. This allows us to read * the configuration from "-d ./etc/raddb", with * the chroot as "./chroot/" for example. After * the server has been loaded, it does a "cd * ${logdir}" below, so that core files (if any) * go to a logging directory. * * This also allows the configuration of the * server to be outside of the chroot. If the * server is statically linked, then the only * things needed inside of the chroot are the * logging directories. */ radlog(L_INFO, "performing chroot to %s\n", chroot_dir); } #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, strerror(errno)); return 0; } #endif #ifdef HAVE_PWD_H if (uid_name) { fr_suid_down(); /* * Now core dumps are disabled on most secure systems. */ did_setuid = TRUE; } #endif /* * Double check that we can write to the log directory. * * If we can't, don't start, as we can't log any errors! */ 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)); return 0; } close(fd); /* * After this it's safe to call radlog(), as it's going * to the right place. */ } #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. * */ if (!(debug_flag || allow_core_dumps || did_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 && did_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 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; }