Don't need to preallocate 4 x NGROUP_MAX on AIX or BSD/Linux.

For BSD/Linux, getgrouplist(3) will tell us the number of groups if
we don't have enough.  For AIX, we can count the entries in the
group set before allocating the group vector.
This commit is contained in:
Todd C. Miller
2018-07-26 15:12:26 -06:00
parent 394524fd5d
commit 86413f95ec

View File

@@ -86,22 +86,25 @@ sudo_getgrouplist2_v1(const char *name, GETGROUPS_T basegid,
grpsize = NGROUPS_MAX;
/*
* It is possible to belong to more groups in the group database
* than NGROUPS_MAX. We start off with NGROUPS_MAX * 4 entries
* and double this as needed.
* than NGROUPS_MAX.
*/
grpsize <<= 1;
for (tries = 0; tries < 10; tries++) {
free(groups);
groups = reallocarray(NULL, grpsize, 2 * sizeof(*groups));
groups = reallocarray(NULL, grpsize, sizeof(*groups));
if (groups == NULL)
return -1;
grpsize <<= 1;
ngroups = grpsize;
if (getgrouplist(name, basegid, groups, &ngroups) != -1) {
*groupsp = groups;
*ngroupsp = ngroups;
return 0;
}
if (ngroups == grpsize) {
/* Failed for some reason other than ngroups too small. */
break;
}
/* getgrouplist(3) set ngroups to the required length, use it. */
grpsize = ngroups;
}
free(groups);
return -1;
@@ -118,59 +121,47 @@ sudo_getgrouplist2_v1(const char *name, GETGROUPS_T basegid,
GETGROUPS_T **groupsp, int *ngroupsp)
{
GETGROUPS_T *groups = *groupsp;
char *cp, *grset = NULL;
char *cp, *last, *grset = NULL;
const char *errstr;
int ngroups = 1;
int grpsize = *ngroupsp;
int ret = -1;
gid_t gid;
#ifdef HAVE_SETAUTHDB
aix_setauthdb((char *) name, NULL);
#endif
if ((grset = getgrset(name)) == NULL)
goto done;
if (groups == NULL) {
/* Dynamically-sized group vector. */
grpsize = (int)sysconf(_SC_NGROUPS_MAX);
if (grpsize < 0)
grpsize = NGROUPS_MAX;
groups = reallocarray(NULL, grpsize, 4 * sizeof(*groups));
/* Dynamically-sized group vector, count groups and alloc. */
grpsize = 1; /* reserve one for basegid */
if (*grset != '\0') {
grset++;
for (cp = grset; *cp != '\0'; cp++) {
if (*cp == ',')
grpsize++;
}
}
groups = reallocarray(NULL, grpsize, sizeof(*groups));
if (groups == NULL)
return -1;
grpsize <<= 2;
} else {
/* Static group vector. */
if (grpsize <= 0)
if (grpsize < 1)
return -1;
}
/* We support BSD semantics where the first element is the base gid */
groups[0] = basegid;
#ifdef HAVE_SETAUTHDB
aix_setauthdb((char *) name, NULL);
#endif
if ((grset = getgrset(name)) != NULL) {
char *last;
const char *errstr;
for (cp = strtok_r(grset, ",", &last); cp != NULL; cp = strtok_r(NULL, ",", &last)) {
gid = sudo_strtoid(cp, NULL, NULL, &errstr);
if (errstr == NULL && gid != basegid) {
if (ngroups == grpsize) {
GETGROUPS_T *tmp;
if (*groupsp != NULL) {
/* Static group vector. */
goto done;
}
tmp = reallocarray(groups, grpsize, 2 * sizeof(*groups));
if (tmp == NULL) {
free(groups);
groups = NULL;
ngroups = 0;
goto done;
}
groups = tmp;
grpsize <<= 1;
}
groups[ngroups++] = gid;
}
for (cp = strtok_r(grset, ",", &last); cp != NULL; cp = strtok_r(NULL, ",", &last)) {
gid = sudo_strtoid(cp, NULL, NULL, &errstr);
if (errstr == NULL && gid != basegid) {
if (ngroups == grpsize)
goto done;
groups[ngroups++] = gid;
}
}
ret = 0;
@@ -464,7 +455,7 @@ sudo_getgrouplist2_v1(const char *name, GETGROUPS_T basegid,
grpsize <<= 2;
} else {
/* Static group vector. */
if (grpsize <= 0)
if (grpsize < 1)
return -1;
}