about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2006-12-06T17·29+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2006-12-06T17·29+0000
commit751f6d2157a1b89f2463b68a90f8515deb3f942c (patch)
tree1a1bb95535212fdc0646a0385053bf1e635af414
parent9f0efa6611d010bf2fb88a2f6a583c4f32fd89ac (diff)
* nix-setuid-helper: allow running programs under a different uid.
-rw-r--r--src/libmain/setuid-common.hh22
-rw-r--r--src/libmain/shared.cc13
-rw-r--r--src/nix-setuid-helper/main.cc116
3 files changed, 140 insertions, 11 deletions
diff --git a/src/libmain/setuid-common.hh b/src/libmain/setuid-common.hh
new file mode 100644
index 000000000000..a3e840996161
--- /dev/null
+++ b/src/libmain/setuid-common.hh
@@ -0,0 +1,22 @@
+/* Code shared between libmain and nix-setuid-helper. */
+
+extern char * * environ;
+
+
+namespace nix {
+    
+
+void setuidCleanup()
+{
+    /* Don't trust the environment. */
+    environ = 0;
+
+    /* Make sure that file descriptors 0, 1, 2 are open. */
+    for (int fd = 0; fd <= 2; ++fd) {
+        struct stat st;
+        if (fstat(fd, &st) == -1) abort();
+    }
+}
+
+ 
+}
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 393f31fcda66..fa72ca5bc444 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -14,7 +14,7 @@
 #include <aterm2.h>
 
 
-extern char * * environ;
+#include "setuid-common.hh"
 
 
 namespace nix {
@@ -218,20 +218,11 @@ static void setuidInit()
     uid_t nixUid = geteuid();
     gid_t nixGid = getegid();
     
-    fprintf(stderr, "<<< setuid mode >>>\n");
-
-    /* Don't trust the environment. */
-    environ = 0;
+    setuidCleanup();
 
     /* Don't trust the current directory. */
     if (chdir("/") == -1) abort();
 
-    /* Make sure that file descriptors 0, 1, 2 are open. */
-    for (int fd = 0; fd <= 2; ++fd) {
-        struct stat st;
-        if (fstat(fd, &st) == -1) abort();
-    }
-
     /* Set the real (and preferably also the save) uid/gid to the
        effective uid/gid.  This matters mostly when we're not using
        build-users (bad!), since some builders (like Perl) complain
diff --git a/src/nix-setuid-helper/main.cc b/src/nix-setuid-helper/main.cc
index ff70fa6560a8..50a059f50476 100644
--- a/src/nix-setuid-helper/main.cc
+++ b/src/nix-setuid-helper/main.cc
@@ -1,3 +1,119 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <pwd.h>
+#include <grp.h>
+
+#include <iostream>
+#include <vector>
+
+#include "util.hh"
+
+#include "../libmain/setuid-common.hh"
+
+using namespace nix;
+
+
+static void secureChown(uid_t uidTarget, gid_t gidTarget,
+    const Path & path)
+{
+    /* Recursively chown `path' to the specified uid and gid, but only
+       if it is currently owned by the Nix account. */
+    /* !!! */
+}
+
+
+static void runBuilder(string userName,
+    string program, int argc, char * * argv)
+{
+    struct passwd * pw = getpwnam(userName.c_str());
+    if (!pw)
+        throw Error(format("the user `%1%' does not exist") % userName);
+
+    gid_t gidBuilders = 1234;
+    
+    /* Chown the current directory, *if* it is owned by the Nix
+       account.  The idea is that the current directory is the
+       temporary build directory in /tmp or somewhere else, and we
+       don't want to create that directory here. */
+    secureChown(pw->pw_uid, gidBuilders, ".");
+
+    /* Set the real, effective and saved gid.  Must be done before
+       setuid(), otherwise it won't set the real and saved gids. */
+    //setgid(gidBuilders);
+
+    /* Set the real, effective and saved uid. */
+    setuid(pw->pw_uid);
+    if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
+        throw Error("cannot setuid");
+
+    /* 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)
+        throw SysError(format("cannot execute `%1%'") % program);
+}
+
+
+static void run(int argc, char * * argv) 
+{
+    char * * oldEnviron = environ;
+    
+    setuidCleanup();
+
+    if (geteuid() != 0)
+        throw Error("nix-setuid-wrapper must be setuid root");
+
+
+    /* Read the configuration file.  It should consist of two words:
+       
+       <nix-user-name> <nix-builders-group>
+
+       The first is the privileged account under which the main Nix
+       processes run (i.e., the supposed caller).  It should match our
+       real uid.  The second is the Unix group to which the Nix
+       builders belong (and nothing else!). */
+    /* !!! */
+    
+    
+    /* Make sure that we are called by the Nix account, not by someone
+       else. */
+    // ...
+
+    /* Perform the desired command. */
+    if (argc < 2)
+        throw Error("invalid arguments");
+
+    string command(argv[1]);
+
+    if (command == "run-builder") {
+        /* Syntax: nix-setuid-helper run-builder <username> <program>
+             <args...> */
+        if (argc < 4) throw Error("missing user name / program name");
+        runBuilder(argv[2], argv[3], argc - 4, argv + 4);
+    }
+
+    else if (command == "fix-ownership") {
+        /* Syntax: nix-setuid-helper <fix-ownership> <path> */
+    }
+
+    else throw Error ("invalid command");
+}
+
+
+
 int main(int argc, char * * argv)
 {
+    try {
+        run(argc, argv);
+    } catch (Error & e) {
+        std::cerr << e.msg() << std::endl;
+        return 1;
+    }
 }