From 6e4b15b5ee28b52b4a03c74fe8a9ac9bc8a976ea Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 12 Nov 2009 10:19:39 -0700 Subject: [PATCH] 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 --- ChangeLog | 20 ++++++++++++++++++++ NEWS | 4 ++++ doc/glibc-functions/setgroups.texi | 6 ++++++ doc/posix-functions/getgroups.texi | 3 +++ lib/getgroups.c | 34 ++++++++++++++++++++++++++++++++-- lib/getugroups.c | 2 +- lib/getugroups.h | 6 +++--- lib/group-member.c | 29 +++++++++++------------------ lib/unistd.in.h | 2 +- m4/getgroups.m4 | 5 +++-- m4/getugroups.m4 | 5 +---- modules/group-member | 1 + tests/test-getgroups.c | 2 +- 13 files changed, 87 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index 26aa6437e..09e63fb15 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,25 @@ 2009-11-13 Eric Blake + 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 a6351504e..2f364f74c 100644 --- 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. diff --git a/doc/glibc-functions/setgroups.texi b/doc/glibc-functions/setgroups.texi index 1b3e6fed9..bcbd84157 100644 --- a/doc/glibc-functions/setgroups.texi +++ b/doc/glibc-functions/setgroups.texi @@ -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 diff --git a/doc/posix-functions/getgroups.texi b/doc/posix-functions/getgroups.texi index 951705e8a..745210e85 100644 --- a/doc/posix-functions/getgroups.texi +++ b/doc/posix-functions/getgroups.texi @@ -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: diff --git a/lib/getgroups.c b/lib/getgroups.c index bad676ea5..e4540fe9b 100644 --- a/lib/getgroups.c +++ b/lib/getgroups.c @@ -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) diff --git a/lib/getugroups.c b/lib/getugroups.c index a614ec7be..8605ab1a1 100644 --- a/lib/getugroups.c +++ b/lib/getugroups.c @@ -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; diff --git a/lib/getugroups.h b/lib/getugroups.h index f2914add7..cbaa6640a 100644 --- 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 . */ #include -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); diff --git a/lib/group-member.c b/lib/group-member.c index a34efc04a..7934c0a33 100644 --- 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 @@ 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