changeset 12382:642c575d5700

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 <scott.gnu.2009@scottrix.co.uk>. Signed-off-by: Eric Blake <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Fri, 04 Dec 2009 08:26:23 -0700
parents e63e3a5265e5
children a22f69c2029c
files ChangeLog lib/mgetgroups.c lib/mgetgroups.h modules/mgetgroups
diffstat 4 files changed, 36 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- 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;
+}
--- a/lib/mgetgroups.h
+++ b/lib/mgetgroups.h
@@ -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);
--- a/modules/mgetgroups
+++ b/modules/mgetgroups
@@ -9,6 +9,7 @@
 Depends-on:
 getgroups
 getugroups
+realloc
 xalloc
 
 configure.ac: