aboutsummaryrefslogtreecommitdiff
path: root/src/nix-setuid-helper/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-setuid-helper/main.cc')
-rw-r--r--src/nix-setuid-helper/main.cc53
1 files changed, 43 insertions, 10 deletions
diff --git a/src/nix-setuid-helper/main.cc b/src/nix-setuid-helper/main.cc
index e2bab9e3e..6fa87e372 100644
--- a/src/nix-setuid-helper/main.cc
+++ b/src/nix-setuid-helper/main.cc
@@ -17,7 +17,10 @@
using namespace nix;
-static void secureChown(uid_t uidTarget, gid_t gidTarget,
+/* Recursively change the ownership of `path' from `uidFrom' to
+ `uidTo' and `gidTo'. Barf if we encounter a file not owned by
+ `uidFrom'. */
+static void secureChown(uid_t uidFrom, uid_t uidTo, gid_t gidTo,
const Path & path)
{
/* Recursively chown `path' to the specified uid and gid, but only
@@ -35,24 +38,53 @@ static uid_t nameToUid(const string & userName)
}
-static void runBuilder(const string & targetUser,
+/* 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
+ user. */
+static void runBuilder(uid_t uidNix,
+ const string & buildUsersGroup, const string & targetUser,
string program, int argc, char * * argv)
{
uid_t uidTargetUser = nameToUid(targetUser);
- gid_t gidBuilders = 1234;
+
+ /* Sanity check. */
+ if (uidTargetUser == 0)
+ throw Error("won't setuid to root");
+
+ /* Get the gid and members of buildUsersGroup. */
+ struct group * gr = getgrnam(buildUsersGroup.c_str());
+ if (!gr)
+ throw Error(format("group `%1%' does not exist") % buildUsersGroup);
+ gid_t gidBuildUsers = gr->gr_gid;
+
+ /* Verify that the target user is a member of that group. */
+ Strings users;
+ bool found = false;
+ for (char * * p = gr->gr_mem; *p; ++p)
+ if (string(*p) == targetUser) {
+ found = true;
+ break;
+ }
+ if (!found)
+ throw Error(format("user `%1%' is not a member of `%2%'")
+ % targetUser % buildUsersGroup);
/* 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(uidTargetUser, gidBuilders, ".");
+ secureChown(uidNix, uidTargetUser, gidBuildUsers, ".");
-
/* Set the real, effective and saved gid. Must be done before
setuid(), otherwise it won't set the real and saved gids. */
if (setgroups(0, 0) == -1)
throw SysError("cannot clear the set of supplementary groups");
- //setgid(gidBuilders);
+
+ if (setgid(gidBuildUsers) == -1 ||
+ getgid() != gidBuildUsers ||
+ getegid() != gidBuildUsers)
+ throw SysError("setgid failed");
/* Set the real, effective and saved uid. */
if (setuid(uidTargetUser) == -1 ||
@@ -116,14 +148,14 @@ static void run(int argc, char * * argv)
throw Error(format("parse error in `%1%'") % configFile);
Strings::iterator i = tokens.begin();
- string allowedUser = *i++;
+ string nixUser = *i++;
string buildUsersGroup = *i++;
/* Check that the caller (real uid) is the one allowed to call
this program. */
- uid_t uidAllowedUser = nameToUid(allowedUser);
- if (uidAllowedUser != getuid())
+ uid_t uidNix = nameToUid(nixUser);
+ if (uidNix != getuid())
throw Error("you are not allowed to call this program, go away");
@@ -137,7 +169,8 @@ static void run(int argc, char * * argv)
/* 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);
+ runBuilder(uidNix, buildUsersGroup,
+ argv[2], argv[3], argc - 4, argv + 4);
}
else if (command == "fix-ownership") {