mgetgroups: add xgetgroups, and avoid ENOSYS failures
authorEric Blake <ebb9@byu.net>
Fri, 4 Dec 2009 15:26:23 +0000 (08:26 -0700)
committerEric Blake <ebb9@byu.net>
Sat, 5 Dec 2009 01:02:53 +0000 (18:02 -0700)
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 <scott.gnu.2009@scottrix.co.uk>.

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
lib/mgetgroups.c
lib/mgetgroups.h
modules/mgetgroups

index 15bdded..48e1026 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2009-12-04  Eric Blake  <ebb9@byu.net>
 
+       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 <scott.gnu.2009@scottrix.co.uk>.
+
        mgetgroups: avoid argument promotion issues with -1
        * lib/mgetgroups.c (mgetgroups): A cast is required when checking
        for invalid gid_t.
index 9a733d5..7a61db4 100644 (file)
@@ -116,13 +116,24 @@ mgetgroups (char const *username, gid_t gid, gid_t **groups)
 
   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 @@ mgetgroups (char const *username, gid_t gid, gid_t **groups)
 
   if (ng < 0)
     {
+      /* Failure is unexpected, but handle it anyway.  */
       int saved_errno = errno;
       free (g);
       errno = saved_errno;
@@ -147,3 +159,14 @@ mgetgroups (char const *username, gid_t gid, gid_t **groups)
   *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;
+}
index 909d84c..4868d28 100644 (file)
@@ -17,3 +17,4 @@
 #include <sys/types.h>
 
 int mgetgroups (const char *username, gid_t gid, gid_t **groups);
+int xgetgroups (const char *username, gid_t gid, gid_t **groups);
index 58ef740..cd249db 100644 (file)
@@ -9,6 +9,7 @@ m4/mgetgroups.m4
 Depends-on:
 getgroups
 getugroups
+realloc
 xalloc
 
 configure.ac: