From 8c4c7e9f211d2d5ed1099ca21b049f6ed567e678 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 12 Nov 2009 11:31:52 -0700 Subject: [PATCH] mgetgroups: new module, taken from coreutils Wrapper function that makes using getgroups/getugroups easier to use. As part of the move from coreutils, convert GETGROUPS_T to gid_t, and allow mgetgroups(NULL,getegid(),&list) as a way to ensure that the effective gid is in the list. * modules/mgetgroups: New file. * lib/mgetgroups.h: Likewise. * lib/mgetgroups.c (mgetgroups): Likewise. * m4/mgetgroups.m4 (gl_MGETGROUPS): Likewise. * MODULES.html.sh (Users and groups): Mention it. Signed-off-by: Eric Blake --- ChangeLog | 7 +++ MODULES.html.sh | 1 + lib/mgetgroups.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/mgetgroups.h | 19 +++++++ m4/mgetgroups.m4 | 11 ++++ modules/mgetgroups | 26 ++++++++++ 6 files changed, 213 insertions(+) create mode 100644 lib/mgetgroups.c create mode 100644 lib/mgetgroups.h create mode 100644 m4/mgetgroups.m4 create mode 100644 modules/mgetgroups diff --git a/ChangeLog b/ChangeLog index 09e63fb15..8425e3f3f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2009-11-13 Eric Blake + mgetgroups: new module, taken from coreutils + * modules/mgetgroups: New file. + * lib/mgetgroups.h: Likewise. + * lib/mgetgroups.c (mgetgroups): Likewise. + * m4/mgetgroups.m4 (gl_MGETGROUPS): Likewise. + * MODULES.html.sh (Users and groups): Mention it. + 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. diff --git a/MODULES.html.sh b/MODULES.html.sh index 5738ea4b4..7d42b736d 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2580,6 +2580,7 @@ func_all_modules () func_module getugroups func_module group-member func_module idcache + func_module mgetgroups func_module userspec func_end_table diff --git a/lib/mgetgroups.c b/lib/mgetgroups.c new file mode 100644 index 000000000..f68e28f79 --- /dev/null +++ b/lib/mgetgroups.c @@ -0,0 +1,149 @@ +/* mgetgroups.c -- return a list of the groups a user or current process is in + + 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Extracted from coreutils' src/id.c. */ + +#include + +#include "mgetgroups.h" + +#include +#include +#include +#include +#include +#if HAVE_GETGROUPLIST +# include +#endif + +#include "getugroups.h" +#include "xalloc.h" + +static gid_t * +realloc_groupbuf (gid_t *g, size_t num) +{ + if (xalloc_oversized (num, sizeof *g)) + { + errno = ENOMEM; + return NULL; + } + + return realloc (g, num * sizeof *g); +} + +/* Like getugroups, but store the result in malloc'd storage. + Set *GROUPS to the malloc'd list of all group IDs of which USERNAME + is a member. If GID is not -1, store it first. GID should be the + group ID (pw_gid) obtained from getpwuid, in case USERNAME is not + listed in the groups database (e.g., /etc/groups). If USERNAME is + NULL, store the supplementary groups of the current process, and GID + should be -1 or the effective group ID (getegid). Upon failure, + don't modify *GROUPS, set errno, and return -1. Otherwise, return + the number of groups. */ + +int +mgetgroups (char const *username, gid_t gid, gid_t **groups) +{ + int max_n_groups; + int ng; + gid_t *g; + +#if HAVE_GETGROUPLIST + /* We prefer to use getgrouplist if available, because it has better + performance characteristics. + + In glibc 2.3.2, getgrouplist is buggy. If you pass a zero as the + length of the output buffer, getgrouplist will still write to the + buffer. Contrary to what some versions of the getgrouplist + manpage say, this doesn't happen with nonzero buffer sizes. + Therefore our usage here just avoids a zero sized buffer. */ + if (username) + { + enum { N_GROUPS_INIT = 10 }; + max_n_groups = N_GROUPS_INIT; + + g = realloc_groupbuf (NULL, max_n_groups); + if (g == NULL) + return -1; + + while (1) + { + gid_t *h; + int last_n_groups = max_n_groups; + + /* getgrouplist updates max_n_groups to num required. */ + ng = getgrouplist (username, gid, g, &max_n_groups); + + /* Some systems (like Darwin) have a bug where they + never increase max_n_groups. */ + if (ng < 0 && last_n_groups == max_n_groups) + max_n_groups *= 2; + + if ((h = realloc_groupbuf (g, max_n_groups)) == NULL) + { + int saved_errno = errno; + free (g); + errno = saved_errno; + return -1; + } + g = h; + + if (0 <= ng) + { + *groups = g; + /* On success some systems just return 0 from getgrouplist, + so return max_n_groups rather than ng. */ + return max_n_groups; + } + } + } + /* else no username, so fall through and use getgroups. */ +#endif + + max_n_groups = (username + ? getugroups (0, NULL, username, gid) + : getgroups (0, NULL) + (gid != -1)); + + /* If we failed to count groups with NULL for a buffer, + try again with a non-NULL one, just in case. */ + if (max_n_groups < 0) + max_n_groups = 5; + + g = realloc_groupbuf (NULL, max_n_groups); + if (g == NULL) + return -1; + + ng = (username + ? getugroups (max_n_groups, g, username, gid) + : getgroups (max_n_groups, g + (gid != -1))); + + if (ng < 0) + { + int saved_errno = errno; + free (g); + errno = saved_errno; + return -1; + } + + if (!username && gid != -1) + { + *g = gid; + ng++; + } + *groups = g; + return ng; +} diff --git a/lib/mgetgroups.h b/lib/mgetgroups.h new file mode 100644 index 000000000..909d84c64 --- /dev/null +++ b/lib/mgetgroups.h @@ -0,0 +1,19 @@ +/* Get a list of all group IDs associated with a specified user ID. + 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +int mgetgroups (const char *username, gid_t gid, gid_t **groups); diff --git a/m4/mgetgroups.m4 b/m4/mgetgroups.m4 new file mode 100644 index 000000000..3d1958ffd --- /dev/null +++ b/m4/mgetgroups.m4 @@ -0,0 +1,11 @@ +#serial 4 +dnl Copyright (C) 2007-2009 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_MGETGROUPS], +[ + AC_CHECK_FUNCS_ONCE([getgrouplist]) + AC_LIBOBJ([mgetgroups]) +]) diff --git a/modules/mgetgroups b/modules/mgetgroups new file mode 100644 index 000000000..58ef74086 --- /dev/null +++ b/modules/mgetgroups @@ -0,0 +1,26 @@ +Description: +Return the group IDs of a user or current process in malloc'd storage. + +Files: +lib/mgetgroups.c +lib/mgetgroups.h +m4/mgetgroups.m4 + +Depends-on: +getgroups +getugroups +xalloc + +configure.ac: +gl_MGETGROUPS + +Makefile.am: + +Include: +"mgetgroups.h" + +License: +GPL + +Maintainer: +Jim Meyering, Eric Blake -- 2.11.0