getgroups: don't expose GETGROUPS_T to user
authorEric Blake <ebb9@byu.net>
Thu, 12 Nov 2009 17:19:39 +0000 (10:19 -0700)
committerEric Blake <ebb9@byu.net>
Fri, 13 Nov 2009 14:39:56 +0000 (07:39 -0700)
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>
13 files changed:
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

index 26aa643..09e63fb 100644 (file)
--- 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.
diff --git a/NEWS b/NEWS
index a635150..2f364f7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,10 @@ User visible incompatible changes
 
 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.
 
index 1b3e6fe..bcbd841 100644 (file)
@@ -13,4 +13,10 @@ Portability problems not fixed by Gnulib:
 @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
index 951705e..745210e 100644 (file)
@@ -14,6 +14,9 @@ mingw.
 @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:
index bad676e..e4540fe 100644 (file)
@@ -48,14 +48,44 @@ getgroups (int n _UNUSED_PARAMETER_, GETGROUPS_T *groups _UNUSED_PARAMETER_)
    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)
index a614ec7..8605ab1 100644 (file)
@@ -55,7 +55,7 @@ getugroups (int maxcount _UNUSED_PARAMETER_,
    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;
index f2914ad..cbaa664 100644 (file)
@@ -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);
index a34efc0..7934c0a 100644 (file)
@@ -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
 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 @@ get_group_info (struct group_info *gi)
 {
   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 @@ get_group_info (struct group_info *gi)
   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 @@ group_member (gid_t gid)
   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 @@ main (int argc, char **argv)
 
   program_name = argv[0];
 
-  for (i=1; i<argc; i++)
+  for (i = 1; i < argc; i++)
     {
       gid_t gid;
 
index 90494e4..c321987 100644 (file)
@@ -417,7 +417,7 @@ extern int getdtablesize (void);
    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
index 1dd39ea..4d96712 100644 (file)
@@ -1,4 +1,4 @@
-# serial 13
+# serial 14
 
 dnl From Jim Meyering.
 dnl A wrapper around AC_FUNC_GETGROUPS.
@@ -17,7 +17,8 @@ AC_DEFUN([gl_FUNC_GETGROUPS],
   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
index e437e1b..d311f77 100644 (file)
@@ -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_DEFUN([gl_GETUGROUPS],
 [
   AC_LIBOBJ([getugroups])
   AC_CHECK_HEADERS_ONCE([grp.h])
-
-  dnl Prerequisites of lib/getugroups.c.
-  AC_TYPE_GETGROUPS
 ])
index 45c8bd5..20075dd 100644 (file)
@@ -8,6 +8,7 @@ m4/group-member.m4
 
 Depends-on:
 extensions
+getgroups
 xalloc
 stdbool
 
index 5324df1..ffa873f 100644 (file)
@@ -40,7 +40,7 @@ int
 main (int argc, char **argv _UNUSED_PARAMETER_)
 {
   int result;
-  GETGROUPS_T *groups;
+  gid_t *groups;
 
   errno = 0;
   result = getgroups (0, NULL);