* Verify that the desired target user is in the build users group (as
specified in the setuid config file).
This commit is contained in:
parent
f07ac41656
commit
62ab131412
|
@ -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") {
|
||||
|
|
Loading…
Reference in a new issue