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.
This commit is contained in:
parent
12e86c0735
commit
931930feb1
1 changed files with 19 additions and 6 deletions
|
@ -67,13 +67,26 @@ bool UserLock::findFreeUser() {
|
||||||
#if __linux__
|
#if __linux__
|
||||||
/* Get the list of supplementary groups of this build user. This
|
/* Get the list of supplementary groups of this build user. This
|
||||||
is usually either empty or contains a group such as "kvm". */
|
is usually either empty or contains a group such as "kvm". */
|
||||||
supplementaryGIDs.resize(10);
|
int ngroups = 32; // arbitrary initial guess
|
||||||
int ngroups = supplementaryGIDs.size();
|
supplementaryGIDs.resize(ngroups);
|
||||||
int err = getgrouplist(pw->pw_name, pw->pw_gid,
|
|
||||||
supplementaryGIDs.data(), &ngroups);
|
|
||||||
if (err == -1)
|
|
||||||
throw Error("failed to get list of supplementary groups for '%1%'", pw->pw_name);
|
|
||||||
|
|
||||||
|
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);
|
supplementaryGIDs.resize(ngroups);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue