# HG changeset patch # User Eric Blake # Date 1259940383 25200 # Node ID 642c575d57003db25d8bc28205847544447b24f3 # Parent e63e3a5265e5ddf66bd944319d1b6050ec732e30 mgetgroups: add xgetgroups, and avoid ENOSYS failures ENOSYS implies that there are no supplemental groups, so we can treat it the same as a return of 0 from getgroups rather than exposing failure to the user. This in turn fixes a crash in coreutils' id, which freed an uninitialized pointer. * lib/mgetgroups.h (xgetgroups): New prototype. * lib/mgetgroups.c (xgetgroups): New wrapper. (mgetgroups): Handle ENOSYS. * modules/mgetgroups (Depends-on): Add realloc. Reported by Scott Harrison . Signed-off-by: Eric Blake diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2009-12-04 Eric Blake + mgetgroups: add xgetgroups, and avoid ENOSYS failures + * lib/mgetgroups.h (xgetgroups): New prototype. + * lib/mgetgroups.c (xgetgroups): New wrapper. + (mgetgroups): Handle ENOSYS. + * modules/mgetgroups (Depends-on): Add realloc. + Reported by Scott Harrison . + mgetgroups: avoid argument promotion issues with -1 * lib/mgetgroups.c (mgetgroups): A cast is required when checking for invalid gid_t. diff --git a/lib/mgetgroups.c b/lib/mgetgroups.c --- a/lib/mgetgroups.c +++ b/lib/mgetgroups.c @@ -116,13 +116,24 @@ max_n_groups = (username ? getugroups (0, NULL, username, gid) - : getgroups (0, NULL) + (gid != (gid_t) -1)); + : getgroups (0, NULL)); - /* If we failed to count groups with NULL for a buffer, - try again with a non-NULL one, just in case. */ + /* If we failed to count groups because there is no supplemental + group support, then return an array containing just GID. + Otherwise, we fail for the same reason. */ if (max_n_groups < 0) - max_n_groups = 5; + { + if (errno == ENOSYS && (g = realloc_groupbuf (NULL, 1))) + { + *groups = g; + *g = gid; + return gid != (gid_t) -1; + } + return -1; + } + if (!username && gid != (gid_t) -1) + max_n_groups++; g = realloc_groupbuf (NULL, max_n_groups); if (g == NULL) return -1; @@ -133,6 +144,7 @@ if (ng < 0) { + /* Failure is unexpected, but handle it anyway. */ int saved_errno = errno; free (g); errno = saved_errno; @@ -147,3 +159,14 @@ *groups = g; return ng; } + +/* Like mgetgroups, but call xalloc_die on allocation failure. */ + +int +xgetgroups (char const *username, gid_t gid, gid_t **groups) +{ + int result = mgetgroups (username, gid, groups); + if (result == -1 && errno == ENOMEM) + xalloc_die (); + return result; +} diff --git a/lib/mgetgroups.h b/lib/mgetgroups.h --- a/lib/mgetgroups.h +++ b/lib/mgetgroups.h @@ -17,3 +17,4 @@ #include int mgetgroups (const char *username, gid_t gid, gid_t **groups); +int xgetgroups (const char *username, gid_t gid, gid_t **groups); diff --git a/modules/mgetgroups b/modules/mgetgroups --- a/modules/mgetgroups +++ b/modules/mgetgroups @@ -9,6 +9,7 @@ Depends-on: getgroups getugroups +realloc xalloc configure.ac: