static bool done_setuid = false;
static int dfd[2] = { -1, -1 };
+static uid_t saved_uid = (uid_t)-1;
+static gid_t saved_gid = (gid_t)-1;
+
#if HAVE_LIBCAP
static bool non_root = false;
}
void
-named_os_changeuser(void) {
+named_os_restoreuser(void) {
+ if (runas_pw == NULL || done_setuid) {
+ return;
+ }
+
+ REQUIRE(saved_uid != (uid_t)-1);
+ REQUIRE(saved_gid != (gid_t)-1);
+
+ setperms(saved_uid, saved_gid);
+}
+
+void
+named_os_changeuser(bool permanent) {
char strbuf[ISC_STRERRORSIZE];
if (runas_pw == NULL || done_setuid) {
return;
}
+ if (!permanent) {
+ saved_uid = getuid();
+ saved_gid = getgid();
+
+ setperms(runas_pw->pw_uid, runas_pw->pw_gid);
+
+ return;
+ }
+
done_setuid = true;
if (setgid(runas_pw->pw_gid) == -1) {
}
uid_t
-ns_os_uid(void) {
+named_os_uid(void) {
if (runas_pw == NULL) {
return (0);
}
named_os_minprivs(void) {
#if HAVE_LIBCAP
linux_keepcaps();
- named_os_changeuser();
+ named_os_changeuser(true);
linux_minprivs();
#endif /* HAVE_LIBCAP */
}
free(f);
if (switch_user && runas_pw != NULL) {
- uid_t olduid = getuid();
- gid_t oldgid = getgid();
-
/*
- * Set UID/GID to the one we'll be running with
+ * Temporarily set UID/GID to the one we'll be running with
* eventually.
*/
- setperms(runas_pw->pw_uid, runas_pw->pw_gid);
+ named_os_changeuser(false);
fd = safe_open(filename, mode, false);
/* Restore UID/GID to previous uid/gid */
- setperms(olduid, oldgid);
+ named_os_restoreuser();
if (fd == -1) {
fd = safe_open(filename, mode, false);
#endif /* HAVE_LMDB */
/*
- * Relinquish root privileges.
+ * Switch to the effective UID for setting up files.
+ * Later, after configuring all the listening ports,
+ * we'll relinquish root privileges permanently.
*/
if (first_time) {
- named_os_changeuser();
+ named_os_changeuser(false);
}
/*
isc_loopmgr_resume(named_g_loopmgr);
exclusive = false;
+ /* Take back root privileges temporarily */
+ if (first_time) {
+ named_os_restoreuser();
+ }
+
/* Configure the statistics channel(s) */
result = named_statschannels_configure(named_g_server, config,
named_g_aclconfctx);
(void)ns_interfacemgr_scan(server->interfacemgr, true, true);
+ /*
+ * Permanently drop root privileges now.
+ */
+ if (first_time) {
+ named_os_changeuser(true);
+ }
+
/*
* These cleans up either the old production view list
* or our temporary list depending on whether they
/*
* Database files must be owned by the eventual user, not by root.
*/
- ret = chown(dbpath_copy, ns_os_uid(), -1);
+ ret = chown(dbpath_copy, named_os_uid(), -1);
UNUSED(ret);
/*