changeset 12280:39be377f1765

getgroups: don't expose GETGROUPS_T to user These days, most systems already declare getgroups with gid_t*. But in the rare case that GETGROUPS_T is still int but gid_t is short, the user should not have to uglify their code; let the replacement hide all the magic. Tested by configuring with ac_cv_type_getgroups=uint64_t on a platform with 32-bit gid_t, and ignoring compiler warnings. However, since we don't replace setgroups, the GETGROUPS_T workaround is still needed there for now. * lib/getgroups.c (rpl_getgroups): Change signature. Copy array an element at a time if GETGROUPS_T is wrong size. * lib/getugroups.h (getugroups): Change signature. * lib/unistd.in.h (getgroups): Likewise. * m4/getgroups.m4 (gl_FUNC_GETGROUPS): Use replacement if signature needs fixing. * m4/getugroups.m4 (gl_GETUGROUPS): No longer need AC_TYPE_GETGROUPS. * modules/group-member (Depends-on): Add getgroups. * lib/group-member.c (group_info, get_group_info): Use gid_t. (group_member): Rely on getgroups replacement. * lib/getugroups.c (getugroups): Use gid_t. * tests/test-getgroups.c (main): Likewise. * NEWS: Mention the signature change. * doc/posix-functions/getgroups.texi (getgroups): Mention the problem with signature. * doc/glibc-functions/setgroups.texi (setgroups): Mention that GETGROUPS_T is still useful for setgroups. Signed-off-by: Eric Blake <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Thu, 12 Nov 2009 10:19:39 -0700
parents 6a41b8f5f874
children 9c11ef292284
files ChangeLog NEWS doc/glibc-functions/setgroups.texi doc/posix-functions/getgroups.texi lib/getgroups.c lib/getugroups.c lib/getugroups.h lib/group-member.c lib/unistd.in.h m4/getgroups.m4 m4/getugroups.m4 modules/group-member tests/test-getgroups.c
diffstat 13 files changed, 87 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
 2009-11-13  Eric Blake  <ebb9@byu.net>
 
+	getgroups: don't expose GETGROUPS_T to user
+	* lib/getgroups.c (rpl_getgroups): Change signature.  Copy array
+	an element at a time if GETGROUPS_T is wrong size.
+	* lib/getugroups.h (getugroups): Change signature.
+	* lib/unistd.in.h (getgroups): Likewise.
+	* m4/getgroups.m4 (gl_FUNC_GETGROUPS): Use replacement if
+	signature needs fixing.
+	* m4/getugroups.m4 (gl_GETUGROUPS): No longer need
+	AC_TYPE_GETGROUPS.
+	* modules/group-member (Depends-on): Add getgroups.
+	* lib/group-member.c (group_info, get_group_info): Use gid_t.
+	(group_member): Rely on getgroups replacement.
+	* lib/getugroups.c (getugroups): Use gid_t.
+	* tests/test-getgroups.c (main): Likewise.
+	* NEWS: Mention the signature change.
+	* doc/posix-functions/getgroups.texi (getgroups): Mention the
+	problem with signature.
+	* doc/glibc-functions/setgroups.texi (setgroups): Mention that
+	GETGROUPS_T is still useful for setgroups.
+
 	getgroups, getugroups: provide stubs for mingw
 	* lib/getgroups.c (getgroups): Provide ENOSYS stub for mingw.
 	* lib/getugroups.c (getugroups): Likewise.
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,10 @@
 
 Date        Modules         Changes
 
+2009-11-12  getgroups       These functions now use a signature of gid_t,
+            getugroups      rather than GETGROUPS_T.  This probably has no
+                            effect except on very old platforms.
+
 2009-11-04  tempname        The gen_tempname function takes an additional
                             'suffixlen' argument. You can safely pass 0.
 
--- a/doc/glibc-functions/setgroups.texi
+++ b/doc/glibc-functions/setgroups.texi
@@ -13,4 +13,10 @@
 @item
 This function is missing on some platforms:
 AIX 5.1, mingw, Interix 3.5, BeOS.
+@item
+On very old systems, this function operated on an array of @samp{int},
+even though that was a different size than an array of @samp{gid_t};
+you can use autoconf's AC_TYPE_GETGROUPS to set @code{GETGROUPS_T} to
+the appropriate size (since @code{getgroups} and @code{setgroups}
+share the same bug).
 @end itemize
--- a/doc/posix-functions/getgroups.texi
+++ b/doc/posix-functions/getgroups.texi
@@ -14,6 +14,9 @@
 @item
 On Ultrix 4.3, @code{getgroups (0, 0)} always fails.  See macro
 @samp{AC_FUNC_GETGROUPS}.
+@item
+On very old systems, this function operated on an array of @samp{int},
+even though that was a different size than an array of @samp{gid_t}.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/lib/getgroups.c
+++ b/lib/getgroups.c
@@ -48,14 +48,44 @@
    whether the effective group id is included in the list.  */
 
 int
-rpl_getgroups (int n, GETGROUPS_T *group)
+rpl_getgroups (int n, gid_t *group)
 {
   int n_groups;
   GETGROUPS_T *gbuf;
   int saved_errno;
 
   if (n != 0)
-    return getgroups (n, group);
+    {
+      int result;
+      int saved_errno;
+      if (sizeof *group == sizeof *gbuf)
+        return getgroups (n, (GETGROUPS_T *) group);
+
+      if (n < 0)
+        {
+          errno = EINVAL;
+          return -1;
+        }
+      if (SIZE_MAX / sizeof *gbuf <= n)
+        {
+          errno = ENOMEM;
+          return -1;
+        }
+      gbuf = malloc (n * sizeof *gbuf);
+      if (!gbuf)
+        return -1;
+      result = getgroups (n, gbuf);
+      if (0 <= result)
+        {
+          n = result;
+          while (n--)
+            group[n] = gbuf[n];
+        }
+      saved_errno = errno;
+      free (gbuf);
+      errno == saved_errno;
+      return result;
+    }
 
   n = 20;
   while (1)
--- a/lib/getugroups.c
+++ b/lib/getugroups.c
@@ -55,7 +55,7 @@
    Otherwise, return the number of IDs we've written into GROUPLIST.  */
 
 int
-getugroups (int maxcount, GETGROUPS_T *grouplist, char const *username,
+getugroups (int maxcount, gid_t *grouplist, char const *username,
 	    gid_t gid)
 {
   int count = 0;
--- a/lib/getugroups.h
+++ b/lib/getugroups.h
@@ -1,5 +1,5 @@
 /* Get a list of group IDs associated with a specified user ID.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -15,5 +15,5 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <sys/types.h>
-int getugroups (int maxcount, GETGROUPS_T *grouplist, char const *username,
-		gid_t gid);
+int getugroups (int maxcount, gid_t *grouplist, char const *username,
+                gid_t gid);
--- a/lib/group-member.c
+++ b/lib/group-member.c
@@ -1,6 +1,6 @@
 /* group-member.c -- determine whether group id is in calling user's group list
 
-   Copyright (C) 1994, 1997, 1998, 2003, 2005, 2006 Free Software
+   Copyright (C) 1994, 1997, 1998, 2003, 2005, 2006, 2009 Free Software
    Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -32,11 +32,9 @@
 struct group_info
   {
     int n_groups;
-    GETGROUPS_T *group;
+    gid_t *group;
   };
 
-#if HAVE_GETGROUPS
-
 static void
 free_group_info (struct group_info const *g)
 {
@@ -48,7 +46,7 @@
 {
   int n_groups;
   int n_group_slots = getgroups (0, NULL);
-  GETGROUPS_T *group;
+  gid_t *group;
 
   if (n_group_slots < 0)
     return false;
@@ -72,18 +70,14 @@
   return true;
 }
 
-#endif /* not HAVE_GETGROUPS */
-
 /* Return non-zero if GID is one that we have in our groups list.
-   If there is no getgroups function, return non-zero if GID matches
-   either of the current or effective group IDs.  */
+   Note that the groups list is not guaranteed to contain the current
+   or effective group ID, so they should generally be checked
+   separately.  */
 
 int
 group_member (gid_t gid)
 {
-#ifndef HAVE_GETGROUPS
-  return ((gid == getgid ()) || (gid == getegid ()));
-#else
   int i;
   int found;
   struct group_info gi;
@@ -96,16 +90,15 @@
   for (i = 0; i < gi.n_groups; i++)
     {
       if (gid == gi.group[i])
-	{
-	  found = 1;
-	  break;
-	}
+        {
+          found = 1;
+          break;
+        }
     }
 
   free_group_info (&gi);
 
   return found;
-#endif /* HAVE_GETGROUPS */
 }
 
 #ifdef TEST
@@ -119,7 +112,7 @@
 
   program_name = argv[0];
 
-  for (i=1; i<argc; i++)
+  for (i = 1; i < argc; i++)
     {
       gid_t gid;
 
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -417,7 +417,7 @@
    If N is 0, return the group count; otherwise, N describes how many
    entries are available in GROUPS.  Return -1 and set errno if N is
    not 0 and not large enough.  Fails with ENOSYS on some systems.  */
-int getgroups (int n, GETGROUPS_T *groups);
+int getgroups (int n, gid_t *groups);
 # endif
 #elif defined GNULIB_POSIXCHECK
 # undef getgroups
--- a/m4/getgroups.m4
+++ b/m4/getgroups.m4
@@ -1,4 +1,4 @@
-# serial 13
+# serial 14
 
 dnl From Jim Meyering.
 dnl A wrapper around AC_FUNC_GETGROUPS.
@@ -17,7 +17,8 @@
   if test "$ac_cv_func_getgroups" != yes; then
     AC_LIBOBJ([getgroups])
     HAVE_GETGROUPS=0
-  elif test "$ac_cv_func_getgroups_works" != yes; then
+  elif test "$ac_cv_func_getgroups_works.$ac_cv_type_getgroups" != yes.gid_t
+  then
     AC_LIBOBJ([getgroups])
     REPLACE_GETGROUPS=1
   fi
--- a/m4/getugroups.m4
+++ b/m4/getugroups.m4
@@ -1,4 +1,4 @@
-# getugroups.m4 serial 7
+# getugroups.m4 serial 8
 dnl Copyright (C) 2002, 2003, 2005, 2006, 2009 Free Software
 dnl Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
@@ -9,7 +9,4 @@
 [
   AC_LIBOBJ([getugroups])
   AC_CHECK_HEADERS_ONCE([grp.h])
-
-  dnl Prerequisites of lib/getugroups.c.
-  AC_TYPE_GETGROUPS
 ])
--- a/modules/group-member
+++ b/modules/group-member
@@ -8,6 +8,7 @@
 
 Depends-on:
 extensions
+getgroups
 xalloc
 stdbool
 
--- a/tests/test-getgroups.c
+++ b/tests/test-getgroups.c
@@ -40,7 +40,7 @@
 main (int argc, char **argv _UNUSED_PARAMETER_)
 {
   int result;
-  GETGROUPS_T *groups;
+  gid_t *groups;
 
   errno = 0;
   result = getgroups (0, NULL);