diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 7ae0dd4ec4..03a708b747 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -351,6 +351,8 @@ public: void acquire(); void release(); + void kill(); + string getUser() { return user; } uid_t getUID() { return uid; } uid_t getGID() { return gid; } @@ -452,29 +454,8 @@ void UserLock::release() } -bool amPrivileged() -{ - return geteuid() == 0; -} - - -bool haveBuildUsers() -{ - return querySetting("build-users-group", "") != ""; -} - - -static void killUserWrapped(uid_t uid) -{ - if (amPrivileged()) - killUser(uid); - else - /* !!! TODO */ - printMsg(lvlError, "must kill"); -} - - -void getOwnership(const Path & path) +static void runSetuidHelper(const string & command, + const string & arg) { string program = nixLibexecDir + "/nix-setuid-helper"; @@ -491,8 +472,8 @@ void getOwnership(const Path & path) std::vector args; /* careful with c_str()! */ args.push_back(program.c_str()); - args.push_back("get-ownership"); - args.push_back(path.c_str()); + args.push_back(command.c_str()); + args.push_back(arg.c_str()); args.push_back(0); execve(program.c_str(), (char * *) &args[0], 0); @@ -514,6 +495,34 @@ void getOwnership(const Path & path) } +void UserLock::kill() +{ + assert(enabled()); + if (amPrivileged()) + killUser(uid); + else + runSetuidHelper("kill", user); +} + + +bool amPrivileged() +{ + return geteuid() == 0; +} + + +bool haveBuildUsers() +{ + return querySetting("build-users-group", "") != ""; +} + + +void getOwnership(const Path & path) +{ + runSetuidHelper("get-ownership", path); +} + + static void deletePathWrapped(const Path & path) { /* When using build users and we're not root, we may not have @@ -850,7 +859,7 @@ void DerivationGoal::buildDone() open and modifies them after they have been chown'ed to root. */ if (buildUser.enabled()) - killUserWrapped(buildUser.getUID()); + buildUser.kill(); /* Close the read side of the logger pipe. */ logPipe.readSide.close(); @@ -1332,7 +1341,7 @@ void DerivationGoal::startBuilder() /* Make sure that no other processes are executing under this uid. */ - killUserWrapped(buildUser.getUID()); + buildUser.kill(); /* Change ownership of the temporary build directory, if we're root. If we're not root, then the setuid helper will do it diff --git a/src/nix-setuid-helper/main.cc b/src/nix-setuid-helper/main.cc index e9ffcfd023..dc0b2cd6cb 100644 --- a/src/nix-setuid-helper/main.cc +++ b/src/nix-setuid-helper/main.cc @@ -66,6 +66,15 @@ static uid_t nameToUid(const string & userName) } +static void checkIfBuildUser(const StringSet & buildUsers, + const string & userName) +{ + if (buildUsers.find(userName) == buildUsers.end()) + throw Error(format("user `%1%' is not a member of the build users group") + % userName); +} + + /* Run `program' under user account `targetUser'. `targetUser' should be a member of `buildUsersGroup'. The ownership of the current directory is changed from the Nix user (uidNix) to the target @@ -80,10 +89,9 @@ static void runBuilder(uid_t uidNix, gid_t gidBuildUsers, if (uidTargetUser == 0) throw Error("won't setuid to root"); - /* Verify that the target user is a member of that group. */ - if (buildUsers.find(targetUser) == buildUsers.end()) - throw Error(format("user `%1%' is not a member of the build users group") - % targetUser); + /* Verify that the target user is a member of the build users + group. */ + checkIfBuildUser(buildUsers, targetUser); /* Chown the current directory, *if* it is owned by the Nix account. The idea is that the current directory is the @@ -118,6 +126,21 @@ static void runBuilder(uid_t uidNix, gid_t gidBuildUsers, } +void killBuildUser(gid_t gidBuildUsers, + const StringSet & buildUsers, const string & userName) +{ + uid_t uid = nameToUid(userName); + + /* Verify that the user whose processes we are to kill is a member + of the build users group. */ + checkIfBuildUser(buildUsers, userName); + + assert(uid != 0); + + killUser(uid); +} + + #ifndef NIX_SETUID_CONFIG_FILE #define NIX_SETUID_CONFIG_FILE "/etc/nix-setuid.conf" #endif @@ -204,6 +227,12 @@ static void run(int argc, char * * argv) secureChown(-1, gidBuildUsers, uidNix, gidBuildUsers, argv[2]); } + else if (command == "kill") { + /* Syntax: nix-setuid-helper kill */ + if (argc != 3) throw Error("missing user name"); + killBuildUser(gidBuildUsers, buildUsers, argv[2]); + } + else throw Error ("invalid command"); }