* Verify that the desired target user is in the build users group (as

specified in the setuid config file).
This commit is contained in:
Eelco Dolstra 2006-12-06 23:15:26 +00:00
parent f07ac41656
commit 62ab131412

View file

@ -17,7 +17,10 @@
using namespace nix; 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) const Path & path)
{ {
/* Recursively chown `path' to the specified uid and gid, but only /* 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) string program, int argc, char * * argv)
{ {
uid_t uidTargetUser = nameToUid(targetUser); 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 /* Chown the current directory, *if* it is owned by the Nix
account. The idea is that the current directory is the account. The idea is that the current directory is the
temporary build directory in /tmp or somewhere else, and we temporary build directory in /tmp or somewhere else, and we
don't want to create that directory here. */ 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 /* Set the real, effective and saved gid. Must be done before
setuid(), otherwise it won't set the real and saved gids. */ setuid(), otherwise it won't set the real and saved gids. */
if (setgroups(0, 0) == -1) if (setgroups(0, 0) == -1)
throw SysError("cannot clear the set of supplementary groups"); 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. */ /* Set the real, effective and saved uid. */
if (setuid(uidTargetUser) == -1 || if (setuid(uidTargetUser) == -1 ||
@ -116,14 +148,14 @@ static void run(int argc, char * * argv)
throw Error(format("parse error in `%1%'") % configFile); throw Error(format("parse error in `%1%'") % configFile);
Strings::iterator i = tokens.begin(); Strings::iterator i = tokens.begin();
string allowedUser = *i++; string nixUser = *i++;
string buildUsersGroup = *i++; string buildUsersGroup = *i++;
/* Check that the caller (real uid) is the one allowed to call /* Check that the caller (real uid) is the one allowed to call
this program. */ this program. */
uid_t uidAllowedUser = nameToUid(allowedUser); uid_t uidNix = nameToUid(nixUser);
if (uidAllowedUser != getuid()) if (uidNix != getuid())
throw Error("you are not allowed to call this program, go away"); 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> /* Syntax: nix-setuid-helper run-builder <username> <program>
<args...> */ <args...> */
if (argc < 4) throw Error("missing user name / program name"); 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") { else if (command == "fix-ownership") {