2020-10-11 16:35:19 +00:00
|
|
|
#include "lock.hh"
|
2006-09-04 21:06:23 +00:00
|
|
|
#include "globals.hh"
|
2020-10-11 16:35:19 +00:00
|
|
|
#include "pathlocks.hh"
|
2006-09-04 21:06:23 +00:00
|
|
|
|
2020-10-11 16:35:19 +00:00
|
|
|
#include <grp.h>
|
|
|
|
#include <pwd.h>
|
2003-07-20 19:29:38 +00:00
|
|
|
|
2004-05-11 18:05:44 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2009-01-12 16:30:32 +00:00
|
|
|
|
2006-09-04 21:06:23 +00:00
|
|
|
namespace nix {
|
|
|
|
|
2017-01-25 11:45:38 +00:00
|
|
|
UserLock::UserLock()
|
2005-10-20 16:58:34 +00:00
|
|
|
{
|
2012-07-30 23:55:41 +00:00
|
|
|
assert(settings.buildUsersGroup != "");
|
2020-05-05 10:04:36 +00:00
|
|
|
createDirs(settings.nixStateDir + "/userpool");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UserLock::findFreeUser() {
|
2020-05-14 14:00:54 +00:00
|
|
|
if (enabled()) return true;
|
2006-12-06 20:00:15 +00:00
|
|
|
|
|
|
|
/* Get the members of the build-users-group. */
|
2017-04-13 18:53:23 +00:00
|
|
|
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
|
2006-12-06 20:00:15 +00:00
|
|
|
if (!gr)
|
2020-04-21 23:07:07 +00:00
|
|
|
throw Error("the group '%1%' specified in 'build-users-group' does not exist",
|
|
|
|
settings.buildUsersGroup);
|
2006-12-06 20:00:15 +00:00
|
|
|
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);
|
2006-12-06 20:00:15 +00:00
|
|
|
users.push_back(*p);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (users.empty())
|
2020-04-21 23:07:07 +00:00
|
|
|
throw Error("the build users group '%1%' has no members",
|
|
|
|
settings.buildUsersGroup);
|
2005-10-20 16:58:34 +00:00
|
|
|
|
2006-12-06 20:00:15 +00:00
|
|
|
/* 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);
|
2005-10-20 16:58:34 +00:00
|
|
|
|
2015-07-17 17:24:28 +00:00
|
|
|
struct passwd * pw = getpwnam(i.c_str());
|
2005-10-20 16:58:34 +00:00
|
|
|
if (!pw)
|
2020-04-21 23:07:07 +00:00
|
|
|
throw Error("the user '%1%' in the group '%2%' does not exist",
|
|
|
|
i, settings.buildUsersGroup);
|
2009-09-23 17:05:51 +00:00
|
|
|
|
2012-07-27 13:59:18 +00:00
|
|
|
|
2012-07-30 23:55:41 +00:00
|
|
|
fnUserLock = (format("%1%/userpool/%2%") % settings.nixStateDir % pw->pw_uid).str();
|
2005-10-20 16:58:34 +00:00
|
|
|
|
2019-12-09 22:57:33 +00:00
|
|
|
AutoCloseFD fd = open(fnUserLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600);
|
|
|
|
if (!fd)
|
2020-04-21 23:07:07 +00:00
|
|
|
throw SysError("opening user lock '%1%'", fnUserLock);
|
2005-10-20 16:58:34 +00:00
|
|
|
|
2019-12-09 22:57:33 +00:00
|
|
|
if (lockFile(fd.get(), ltWrite, false)) {
|
|
|
|
fdUserLock = std::move(fd);
|
|
|
|
user = i;
|
|
|
|
uid = pw->pw_uid;
|
2006-12-07 00:19:27 +00:00
|
|
|
|
2019-12-09 22:57:33 +00:00
|
|
|
/* Sanity check... */
|
|
|
|
if (uid == getuid() || uid == geteuid())
|
2020-04-21 23:07:07 +00:00
|
|
|
throw Error("the Nix user should not be a member of '%1%'",
|
|
|
|
settings.buildUsersGroup);
|
2012-07-27 13:59:18 +00:00
|
|
|
|
2015-07-21 12:45:24 +00:00
|
|
|
#if __linux__
|
2019-12-09 22:57:33 +00:00
|
|
|
/* Get the list of supplementary groups of this build user. This
|
|
|
|
is usually either empty or contains a group such as "kvm". */
|
fix(libstore/lock): support users that belong to more than 10 groups
The manpage for `getgrouplist` says:
> If the number of groups of which user is a member is less than or
> equal to *ngroups, then the value *ngroups is returned.
>
> If the user is a member of more than *ngroups groups, then
> getgrouplist() returns -1. In this case, the value returned in
> *ngroups can be used to resize the buffer passed to a further
> call getgrouplist().
In our original code, however, we allocated a list of size `10` and, if
`getgrouplist` returned `-1` threw an exception. In practice, this
caused the code to fail for any user belonging to more than 10 groups.
While unusual for single-user systems, large companies commonly have a
huge number of POSIX groups users belong to, causing this issue to crop
up and make multi-user Nix unusable in such settings.
The fix is relatively simple, when `getgrouplist` fails, it stores the
real number of GIDs in `ngroups`, so we must resize our list and retry.
Only then, if it errors once more, we can raise an exception.
This should be backported to, at least, 2.9.x.
2022-06-08 17:45:39 +00:00
|
|
|
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.
|
2019-12-09 22:57:33 +00:00
|
|
|
if (err == -1)
|
fix(libstore/lock): support users that belong to more than 10 groups
The manpage for `getgrouplist` says:
> If the number of groups of which user is a member is less than or
> equal to *ngroups, then the value *ngroups is returned.
>
> If the user is a member of more than *ngroups groups, then
> getgrouplist() returns -1. In this case, the value returned in
> *ngroups can be used to resize the buffer passed to a further
> call getgrouplist().
In our original code, however, we allocated a list of size `10` and, if
`getgrouplist` returned `-1` threw an exception. In practice, this
caused the code to fail for any user belonging to more than 10 groups.
While unusual for single-user systems, large companies commonly have a
huge number of POSIX groups users belong to, causing this issue to crop
up and make multi-user Nix unusable in such settings.
The fix is relatively simple, when `getgrouplist` fails, it stores the
real number of GIDs in `ngroups`, so we must resize our list and retry.
Only then, if it errors once more, we can raise an exception.
This should be backported to, at least, 2.9.x.
2022-06-08 17:45:39 +00:00
|
|
|
throw Error("failed to get list of supplementary groups for '%1%'",
|
|
|
|
pw->pw_name);
|
2019-12-09 22:57:33 +00:00
|
|
|
|
fix(libstore/lock): support users that belong to more than 10 groups
The manpage for `getgrouplist` says:
> If the number of groups of which user is a member is less than or
> equal to *ngroups, then the value *ngroups is returned.
>
> If the user is a member of more than *ngroups groups, then
> getgrouplist() returns -1. In this case, the value returned in
> *ngroups can be used to resize the buffer passed to a further
> call getgrouplist().
In our original code, however, we allocated a list of size `10` and, if
`getgrouplist` returned `-1` threw an exception. In practice, this
caused the code to fail for any user belonging to more than 10 groups.
While unusual for single-user systems, large companies commonly have a
huge number of POSIX groups users belong to, causing this issue to crop
up and make multi-user Nix unusable in such settings.
The fix is relatively simple, when `getgrouplist` fails, it stores the
real number of GIDs in `ngroups`, so we must resize our list and retry.
Only then, if it errors once more, we can raise an exception.
This should be backported to, at least, 2.9.x.
2022-06-08 17:45:39 +00:00
|
|
|
// Finally, trim back the GID list to its real size
|
2019-12-09 22:57:33 +00:00
|
|
|
supplementaryGIDs.resize(ngroups);
|
2015-07-21 12:45:24 +00:00
|
|
|
#endif
|
2015-07-01 12:56:34 +00:00
|
|
|
|
2020-05-14 14:00:54 +00:00
|
|
|
isEnabled = true;
|
2020-05-05 10:04:36 +00:00
|
|
|
return true;
|
2005-10-20 16:58:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-05 10:04:36 +00:00
|
|
|
return false;
|
2005-10-20 16:58:34 +00:00
|
|
|
}
|
|
|
|
|
2006-12-07 16:33:31 +00:00
|
|
|
void UserLock::kill()
|
|
|
|
{
|
2013-11-14 10:57:37 +00:00
|
|
|
killUser(uid);
|
2006-12-07 14:14:35 +00:00
|
|
|
}
|
|
|
|
|
2006-09-04 21:06:23 +00:00
|
|
|
}
|