* 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
1 changed files with 43 additions and 10 deletions
|
@ -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") {
|
||||||
|
|
Loading…
Reference in a new issue