about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2006-12-07T00·42+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2006-12-07T00·42+0000
commita45c498e4e1109e0147b46df1230db718e5bceb1 (patch)
tree8bc06d51167649ac2401d86e6c2398330c4c85fd
parent813a7c65c99951a946e8342713884d46af1f2966 (diff)
* If Nix is not running as root, call the setuid helper to start the
  builder under the desired build user.

-rw-r--r--src/libstore/build.cc58
-rw-r--r--src/nix-setuid-helper/main.cc9
2 files changed, 41 insertions, 26 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index b4eded1b9dd5..be6f934890e1 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1342,11 +1342,6 @@ void DerivationGoal::startBuilder()
 
             initChild();
 
-            /* Fill in the arguments. */
-            Strings args(drv.args);
-            args.push_front(baseNameOf(drv.builder));
-            const char * * argArr = strings2CharPtrs(args);
-
             /* Fill in the environment. */
             Strings envStrs;
             for (Environment::const_iterator i = env.begin();
@@ -1354,32 +1349,53 @@ void DerivationGoal::startBuilder()
                 envStrs.push_back(i->first + "=" + i->second);
             const char * * envArr = strings2CharPtrs(envStrs);
 
+            Path program = drv.builder.c_str();
+            std::vector<const char *> args; /* careful with c_str()! */
+            
             /* 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) {
+            if (buildUser.enabled()) {
                 printMsg(lvlInfo, format("switching to uid `%1%'") % buildUser.getUID());
+
+                if (amPrivileged()) {
+                    
+                    if (setgroups(0, 0) == -1)
+                        throw SysError("cannot clear the set of supplementary groups");
                 
-                if (setgroups(0, 0) == -1)
-                    throw SysError("cannot clear the set of supplementary groups");
-                
-                if (setgid(buildUser.getGID()) == -1 ||
-                    getgid() != buildUser.getGID() ||
-                    getegid() != buildUser.getGID())
-                    throw SysError("setgid failed");
-
-                if (setuid(buildUser.getUID()) == -1 ||
-                    getuid() != buildUser.getUID() ||
-                    geteuid() != buildUser.getUID())
-                    throw SysError("setuid failed");
+                    if (setgid(buildUser.getGID()) == -1 ||
+                        getgid() != buildUser.getGID() ||
+                        getegid() != buildUser.getGID())
+                        throw SysError("setgid failed");
+
+                    if (setuid(buildUser.getUID()) == -1 ||
+                        getuid() != buildUser.getUID() ||
+                        geteuid() != buildUser.getUID())
+                        throw SysError("setuid failed");
+                    
+                } else {
+                    /* Let the setuid helper take care of it. */
+                    program = nixLibexecDir + "/nix-setuid-helper";
+                    args.push_back(program.c_str());
+                    args.push_back("run-builder");
+                    args.push_back("nix-builder-1"); /* !!! TODO */
+                    args.push_back(drv.builder.c_str());
+                }
             }
             
+            /* Fill in the arguments. */
+            string builderBasename = baseNameOf(drv.builder);
+            args.push_back(builderBasename.c_str());
+            for (Strings::iterator i = drv.args.begin();
+                 i != drv.args.end(); ++i)
+                args.push_back(i->c_str());
+            args.push_back(0);
+
             /* Execute the program.  This should not return. */
-            execve(drv.builder.c_str(),
-                (char * *) argArr, (char * *) envArr);
+            execve(program.c_str(), (char * *) &args[0], (char * *) envArr);
 
             throw SysError(format("executing `%1%'")
                 % drv.builder);
@@ -1484,7 +1500,7 @@ void DerivationGoal::computeClosure()
            build.  Also, the output should be owned by the build
            user. */
         if ((st.st_mode & (S_IWGRP | S_IWOTH)) ||
-            (buildUser.getUID() != 0 && st.st_uid != buildUser.getUID()))
+            (buildUser.enabled() && st.st_uid != buildUser.getUID()))
             throw Error(format("suspicious ownership or permission on `%1%'; rejecting this build output") % path);
 #endif
 
diff --git a/src/nix-setuid-helper/main.cc b/src/nix-setuid-helper/main.cc
index bf70ee0890b0..ea60b280019f 100644
--- a/src/nix-setuid-helper/main.cc
+++ b/src/nix-setuid-helper/main.cc
@@ -57,7 +57,7 @@ static uid_t nameToUid(const string & userName)
    user. */
 static void runBuilder(uid_t uidNix,
     const string & buildUsersGroup, const string & targetUser,
-    string program, int argc, char * * argv)
+    string program, int argc, char * * argv, char * * env)
 {
     uid_t uidTargetUser = nameToUid(targetUser);
 
@@ -107,12 +107,11 @@ static void runBuilder(uid_t uidNix,
 
     /* Execute the program. */
     std::vector<const char *> args;
-    args.push_back(program.c_str());
     for (int i = 0; i < argc; ++i)
         args.push_back(argv[i]);
     args.push_back(0);
     
-    if (execve(program.c_str(), (char * *) &args[0], 0) == -1)
+    if (execve(program.c_str(), (char * *) &args[0], env) == -1)
         throw SysError(format("cannot execute `%1%'") % program);
 }
 
@@ -180,10 +179,10 @@ static void run(int argc, char * * argv)
 
     if (command == "run-builder") {
         /* Syntax: nix-setuid-helper run-builder <username> <program>
-             <args...> */
+             <arg0 arg1...> */
         if (argc < 4) throw Error("missing user name / program name");
         runBuilder(uidNix, buildUsersGroup,
-            argv[2], argv[3], argc - 4, argv + 4);
+            argv[2], argv[3], argc - 4, argv + 4, oldEnviron);
     }
 
     else if (command == "fix-ownership") {