about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libmain/shared.cc2
-rw-r--r--src/libmain/shared.hh3
-rw-r--r--src/libstore/build.cc44
-rw-r--r--src/libstore/local-store.cc6
4 files changed, 34 insertions, 21 deletions
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index da5aeadeb673..8577d34a50e3 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -258,6 +258,8 @@ static void setuidInit()
     if (setuid(nixUid)) abort();
     if (setgid(nixGid)) abort();
 #endif
+
+    setuidMode = true;
 }
 
 
diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh
index 16162604a914..20262004bdbd 100644
--- a/src/libmain/shared.hh
+++ b/src/libmain/shared.hh
@@ -24,6 +24,9 @@ namespace nix {
 Path makeRootName(const Path & gcRoot, int & counter);
 void printGCWarning();
 
+/* Whether we're running setuid. */
+bool setuidMode = false;
+
 }
 
 
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index d8b90252b43b..8a109bcefdab 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1271,12 +1271,10 @@ void DerivationGoal::startBuilder()
     }
 
     
-    /* If we are running as root, and the `build-allow-root' setting
-       is `false', then we have to build as one of the users listed in
-       `build-users'. */
-    if (!queryBoolSetting("build-allow-root", true) &&
-        getuid() == rootUserId)
-    {
+    /* If `build-users' is not empty, then we have to build as one of
+       the users listed in `build-users'. */
+    gid_t gidBuildGroup = -1;    
+    if (querySetting("build-users", Strings()).size() > 0) {
         buildUser.acquire();
         assert(buildUser.getUID() != 0);
 
@@ -1288,6 +1286,14 @@ void DerivationGoal::startBuilder()
         if (chown(tmpDir.c_str(), buildUser.getUID(), (gid_t) -1) == -1)
             throw SysError(format("cannot change ownership of `%1%'") % tmpDir);
 
+        /* What group to execute the builder in? */
+        string buildGroup = querySetting("build-users-group", "nix");
+        struct group * gr = getgrnam(buildGroup.c_str());
+        if (!gr) throw Error(
+            format("the group `%1%' specified in `build-users-group' does not exist")
+            % buildGroup);
+        gidBuildGroup = gr->gr_gid;
+        
         /* Check that the Nix store has the appropriate permissions,
            i.e., owned by root and mode 1777 (sticky bit on so that
            the builder can create its output but not mess with the
@@ -1295,13 +1301,13 @@ void DerivationGoal::startBuilder()
         struct stat st;
         if (stat(nixStore.c_str(), &st) == -1)
             throw SysError(format("cannot stat `%1%'") % nixStore);
-        if (st.st_uid != rootUserId)
-            throw Error(format("`%1%' is not owned by root") % nixStore);
         if (!(st.st_mode & S_ISVTX) ||
-            ((st.st_mode & S_IRWXO) != S_IRWXO))
+            ((st.st_mode & S_IRWXG) != S_IRWXG) ||
+            (st.st_gid != gidBuildGroup))
             throw Error(format(
                 "builder does not have write permission to `%1%'; "
-                "try `chmod 1777 %1%'") % nixStore);
+                "try `chgrp %1% %2%; chmod 1775 %2%'")
+                % buildGroup % nixStore);
     }
 
     
@@ -1343,23 +1349,25 @@ void DerivationGoal::startBuilder()
                 envStrs.push_back(i->first + "=" + i->second);
             const char * * envArr = strings2CharPtrs(envStrs);
 
-            /* If we are running as root and `build-allow-root' is
-               `false', then switch to the user we allocated above.
-               Make sure that we drop all root privileges.  Note that
-               initChild() above has closed all file descriptors
-               except std*, so that's safe.  Also note that setuid()
-               when run as root sets the real, effective and saved
-               UIDs. */
+            /* If we are running in `build-users' mode, then switch to
+               the user we allocated above.  Make sure that we drop
+               all root privileges.  Note that initChild() above has
+               closed all file descriptors except std*, so that's
+               safe.  Also note that setuid() when run as root sets
+               the real, effective and saved UIDs. */
             if (buildUser.getUID() != 0) {
                 printMsg(lvlError, format("switching to uid `%1%'") % buildUser.getUID());
                 
-                /* !!! setgid also */
                 if (setgroups(0, 0) == -1)
                     throw SysError("cannot clear the set of supplementary groups");
+                
                 setuid(buildUser.getUID());
                 assert(getuid() == buildUser.getUID());
                 assert(geteuid() == buildUser.getUID());
 
+                setgid(gidBuildGroup);
+                assert(getgid() == gidBuildGroup);
+                assert(getegid() == gidBuildGroup);
             }
             
             /* Execute the program.  This should not return. */
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 0b8900f2501b..2f3f3a7da882 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -235,10 +235,10 @@ void canonicalisePathMetaData(const Path & path)
                 throw SysError(format("changing mode of `%1%' to %2$o") % path % mode);
         }
 
-        if (st.st_uid != getuid() || st.st_gid != getgid()) {
-            if (chown(path.c_str(), getuid(), getgid()) == -1)
+        if (st.st_uid != geteuid() || st.st_gid != getegid()) {
+            if (chown(path.c_str(), geteuid(), getegid()) == -1)
                 throw SysError(format("changing owner/group of `%1%' to %2%/%3%")
-                    % path % getuid() % getgid());
+                    % path % geteuid() % getegid());
         }
 
         if (st.st_mtime != 0) {