aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2006-12-06 17:29:10 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2006-12-06 17:29:10 +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 000000000..a3e840996
--- /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 393f31fcd..fa72ca5bc 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 ff70fa656..50a059f50 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;
+ }
}