lix/src/libstore/lock.cc

107 lines
3.1 KiB
C++
Raw Normal View History

2020-10-11 16:35:19 +00:00
#include "lock.hh"
#include "globals.hh"
2020-10-11 16:35:19 +00:00
#include "pathlocks.hh"
2020-10-11 16:35:19 +00:00
#include <grp.h>
#include <pwd.h>
2003-07-20 19:29:38 +00:00
#include <fcntl.h>
#include <unistd.h>
namespace nix {
2017-01-25 11:45:38 +00:00
UserLock::UserLock()
{
assert(settings.buildUsersGroup != "");
createDirs(settings.nixStateDir + "/userpool");
}
bool UserLock::findFreeUser() {
if (enabled()) return true;
/* Get the members of the build-users-group. */
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
if (!gr)
throw Error("the group '%1%' specified in 'build-users-group' does not exist",
settings.buildUsersGroup);
gid = gr->gr_gid;
/* Copy the result of getgrnam. */
Strings users;
for (char * * p = gr->gr_mem; *p; ++p) {
2020-05-11 21:52:15 +00:00
debug("found build user '%1%'", *p);
users.push_back(*p);
}
if (users.empty())
throw Error("the build users group '%1%' has no members",
settings.buildUsersGroup);
/* Find a user account that isn't currently in use for another
build. */
2015-07-17 17:24:28 +00:00
for (auto & i : users) {
2020-05-11 21:52:15 +00:00
debug("trying user '%1%'", i);
2015-07-17 17:24:28 +00:00
struct passwd * pw = getpwnam(i.c_str());
if (!pw)
throw Error("the user '%1%' in the group '%2%' does not exist",
i, settings.buildUsersGroup);
2012-07-27 13:59:18 +00:00
fnUserLock = (format("%1%/userpool/%2%") % settings.nixStateDir % pw->pw_uid).str();
AutoCloseFD fd = open(fnUserLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600);
if (!fd)
throw SysError("opening user lock '%1%'", fnUserLock);
if (lockFile(fd.get(), ltWrite, false)) {
fdUserLock = std::move(fd);
user = i;
uid = pw->pw_uid;
2006-12-07 00:19:27 +00:00
/* Sanity check... */
if (uid == getuid() || uid == geteuid())
throw Error("the Nix user should not be a member of '%1%'",
settings.buildUsersGroup);
2012-07-27 13:59:18 +00:00
#if __linux__
/* Get the list of supplementary groups of this build user. This
is usually either empty or contains a group such as "kvm". */
int ngroups = 32; // arbitrary initial guess
supplementaryGIDs.resize(ngroups);
int err = getgrouplist(pw->pw_name, pw->pw_gid, supplementaryGIDs.data(),
&ngroups);
// Our initial size of 32 wasn't sufficient, the correct size has
// been stored in ngroups, so we try again.
if (err == -1) {
supplementaryGIDs.resize(ngroups);
err = getgrouplist(pw->pw_name, pw->pw_gid, supplementaryGIDs.data(),
&ngroups);
}
// If it failed once more, then something must be broken.
if (err == -1)
throw Error("failed to get list of supplementary groups for '%1%'",
pw->pw_name);
// Finally, trim back the GID list to its real size
supplementaryGIDs.resize(ngroups);
#endif
isEnabled = true;
return true;
}
}
return false;
}
void UserLock::kill()
{
killUser(uid);
}
}