From 86413f95ec8a28731a7795b95b7a04c00f7a4c5c Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 26 Jul 2018 15:12:26 -0600 Subject: [PATCH] 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. --- lib/util/getgrouplist.c | 77 ++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/lib/util/getgrouplist.c b/lib/util/getgrouplist.c index ce4e6d063..4d47ade82 100644 --- a/lib/util/getgrouplist.c +++ b/lib/util/getgrouplist.c @@ -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; } -- 2.40.0