From e0066f36c22dce02f9d6327cb881ee7eec6e7539 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Thu, 5 Jul 2007 17:42:29 +0200 Subject: setuidgid: set all groups, not just the primary one; mgetgroups: new module I wanted to use the xgetgroups function from id.c, so factored it out and made it into a non-exiting function (hence the "m" prefix rather than "x"). * src/setuidgid.c (main): Use mgetgroups. Include "mgetgroups.h". * src/id.c (xgetgroups): Remove function. Include "mgetgroups.h". (print_group_list): Use mgetgroups, not xgetgroups. * gl/modules/mgetgroups: New module. * gl/lib/mgetgroups.c: New file. mgetgroups is derived from id.c's xgetgroups function. * bootstrap.conf (gnulib_modules): Add mgetgroups. * gl/m4/mgetgroups.m4: New file. * gl/lib/mgetgroups.h: New file. --- ChangeLog | 18 ++++++++++++ bootstrap.conf | 3 +- gl/lib/mgetgroups.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ gl/lib/mgetgroups.h | 21 ++++++++++++++ gl/m4/mgetgroups.m4 | 10 +++++++ gl/modules/mgetgroups | 25 ++++++++++++++++ lib/.cvsignore | 3 ++ lib/.gitignore | 3 ++ m4/.cvsignore | 1 + m4/.gitignore | 2 ++ src/id.c | 65 +++++++++-------------------------------- src/setuidgid.c | 20 +++++++++++-- 12 files changed, 195 insertions(+), 56 deletions(-) create mode 100644 gl/lib/mgetgroups.c create mode 100644 gl/lib/mgetgroups.h create mode 100644 gl/m4/mgetgroups.m4 create mode 100644 gl/modules/mgetgroups diff --git a/ChangeLog b/ChangeLog index 470c6099e..7aafd142e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,23 @@ 2007-07-05 Jim Meyering + setuidgid: set all groups, not just the primary one. + I wanted to use the xgetgroups function from id.c, so factored + it out and made it into a non-exiting function (hence the "m" + prefix rather than "x"). + * src/setuidgid.c (main): Use mgetgroups. + Include "mgetgroups.h". + + * src/id.c (xgetgroups): Remove function. + Include "mgetgroups.h". + (print_group_list): Use mgetgroups, not xgetgroups. + + * gl/modules/mgetgroups: New module. + * gl/lib/mgetgroups.c: New file. mgetgroups is derived from + id.c's xgetgroups function. + * bootstrap.conf (gnulib_modules): Add mgetgroups. + * gl/m4/mgetgroups.m4: New file. + * gl/lib/mgetgroups.h: New file. + * bootstrap: Merge in changes from gnulib. * src/id.c: Include "getugroups.h" rather than declaring manually. diff --git a/bootstrap.conf b/bootstrap.conf index 9d2d67b53..7f460059b 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -60,7 +60,8 @@ gnulib_modules=" inttostr inttypes isapipe lchmod lchown lib-ignore linebuffer link-follow long-options lstat malloc mbswidth memcasecmp mempcpy - memrchr mkancesdirs mkdir mkdir-p mkstemp mktime modechange + memrchr mgetgroups + mkancesdirs mkdir mkdir-p mkstemp mktime modechange mountlist mpsort obstack pathmax perl physmem posixtm posixver putenv quote quotearg raise readlink mreadlink-with-size readtokens readtokens0 readutmp diff --git a/gl/lib/mgetgroups.c b/gl/lib/mgetgroups.c new file mode 100644 index 000000000..8552f2639 --- /dev/null +++ b/gl/lib/mgetgroups.c @@ -0,0 +1,80 @@ +/* getugroups.c -- return a list of the groups a user is in + + Copyright (C) 2007 Free Software Foundation. + + 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 2, 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, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Extracted from coreutils' src/id.c. */ + +#include + +#include "mgetgroups.h" + +#include +#include +#include + +#include "getugroups.h" +#include "xalloc.h" + +/* 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). Upon failure, + don't modify *GROUPS, set errno, and return -1. Otherwise, return + the number of groups. */ + +int +mgetgroups (const char *username, gid_t gid, GETGROUPS_T **groups) +{ + int max_n_groups; + int ng; + GETGROUPS_T *g; + + max_n_groups = (username + ? getugroups (0, NULL, username, gid) + : 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 (max_n_groups < 0) + max_n_groups = 5; + + if (xalloc_oversized (max_n_groups, sizeof *g)) + { + errno = ENOMEM; + return -1; + } + + g = malloc (max_n_groups * sizeof *g); + if (g == NULL) + return -1; + + ng = (username + ? getugroups (max_n_groups, g, username, gid) + : getgroups (max_n_groups, g)); + + if (ng < 0) + { + int saved_errno = errno; + free (g); + errno = saved_errno; + return -1; + } + + *groups = g; + return ng; +} diff --git a/gl/lib/mgetgroups.h b/gl/lib/mgetgroups.h new file mode 100644 index 000000000..23f04e189 --- /dev/null +++ b/gl/lib/mgetgroups.h @@ -0,0 +1,21 @@ +/* Get a list of all group IDs associated with a specified user ID. + Copyright (C) 2007 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 2, 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; see the file COPYING. + If not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include + +int mgetgroups (const char *username, gid_t gid, GETGROUPS_T **groups); diff --git a/gl/m4/mgetgroups.m4 b/gl/m4/mgetgroups.m4 new file mode 100644 index 000000000..81835415f --- /dev/null +++ b/gl/m4/mgetgroups.m4 @@ -0,0 +1,10 @@ +#serial 1 +dnl Copyright (C) 2007 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_LIBOBJ([mgetgroups]) +]) diff --git a/gl/modules/mgetgroups b/gl/modules/mgetgroups new file mode 100644 index 000000000..3e2ead100 --- /dev/null +++ b/gl/modules/mgetgroups @@ -0,0 +1,25 @@ +Description: +Return the group IDs of a user in malloc'd storage. + +Files: +lib/mgetgroups.c +lib/mgetgroups.h +m4/mgetgroups.m4 + +Depends-on: +free +getugroups +xalloc + +configure.ac: +gl_MGETGROUPS + +Makefile.am: + +Include: + +License: +LGPL + +Maintainer: +Jim Meyering diff --git a/lib/.cvsignore b/lib/.cvsignore index ea040c3b9..ee01fa6ec 100644 --- a/lib/.cvsignore +++ b/lib/.cvsignore @@ -151,6 +151,7 @@ gettext.h gettime.c gettimeofday.c getugroups.c +getugroups.h getusershell.c gnulib.mk group-member.c @@ -218,6 +219,8 @@ memmove.c mempcpy.c memrchr.c memset.c +mgetgroups.c +mgetgroups.h mkancesdirs.c mkancesdirs.h mkdir-p.c diff --git a/lib/.gitignore b/lib/.gitignore index ae7ef06e8..8f77f31ad 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -144,6 +144,7 @@ gettext.h gettime.c gettimeofday.c getugroups.c +getugroups.h getusershell.c gnulib.mk group-member.c @@ -212,6 +213,8 @@ memmove.c mempcpy.c memrchr.c memset.c +mgetgroups.c +mgetgroups.h mkancesdirs.c mkancesdirs.h mkdir-p.c diff --git a/m4/.cvsignore b/m4/.cvsignore index ec7015626..88f1d88aa 100644 --- a/m4/.cvsignore +++ b/m4/.cvsignore @@ -144,6 +144,7 @@ memmove.m4 mempcpy.m4 memrchr.m4 memset.m4 +mgetgroups.m4 mkancesdirs.m4 mkdir-p.m4 mkdir-slash.m4 diff --git a/m4/.gitignore b/m4/.gitignore index a10566a9e..17ff10048 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -92,6 +92,7 @@ iconv.m4 iconv_h.m4 iconv_open.m4 idcache.m4 +include_next.m4 inet_ntop.m4 inline.m4 intl.m4 @@ -138,6 +139,7 @@ memmove.m4 mempcpy.m4 memrchr.m4 memset.m4 +mgetgroups.m4 mkancesdirs.m4 mkdir-p.m4 mkdir-slash.m4 diff --git a/src/id.c b/src/id.c index 208775eb5..90c944587 100644 --- a/src/id.c +++ b/src/id.c @@ -30,6 +30,7 @@ #include "system.h" #include "error.h" #include "getugroups.h" +#include "mgetgroups.h" #include "quote.h" /* The official name of this program (e.g., no `g' prefix). */ @@ -278,50 +279,6 @@ print_group (gid_t gid) printf ("%s", grp->gr_name); } -#if HAVE_GETGROUPS - -/* FIXME: document */ - -static bool -xgetgroups (const char *username, gid_t gid, int *n_groups, - GETGROUPS_T **groups) -{ - int max_n_groups; - int ng; - GETGROUPS_T *g = NULL; - - if (!username) - max_n_groups = getgroups (0, NULL); - else - max_n_groups = getugroups (0, NULL, username, gid); - - if (max_n_groups < 0) - ng = -1; - else - { - g = xnmalloc (max_n_groups, sizeof *g); - if (!username) - ng = getgroups (max_n_groups, g); - else - ng = getugroups (max_n_groups, g, username, gid); - } - - if (ng < 0) - { - error (0, errno, _("cannot get supplemental group list")); - free (g); - return false; - } - else - { - *n_groups = ng; - *groups = g; - return true; - } -} - -#endif /* HAVE_GETGROUPS */ - /* Print all of the distinct groups the user is in. */ static void @@ -342,13 +299,15 @@ print_group_list (const char *username) #if HAVE_GETGROUPS { - int n_groups; GETGROUPS_T *groups; - int i; + size_t i; - if (! xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1), - &n_groups, &groups)) + int n_groups = mgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1), + &groups); + if (n_groups < 0) { + error (0, errno, _("failed to get groups for user %s"), + quote (username)); ok = false; return; } @@ -400,13 +359,15 @@ print_full_info (const char *username) #if HAVE_GETGROUPS { - int n_groups; GETGROUPS_T *groups; - int i; + size_t i; - if (! xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1), - &n_groups, &groups)) + int n_groups = mgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1), + &groups); + if (n_groups < 0) { + error (0, errno, _("failed to get groups for user %s"), + quote (username)); ok = false; return; } diff --git a/src/setuidgid.c b/src/setuidgid.c index 27c4c7991..ccc8403fc 100644 --- a/src/setuidgid.c +++ b/src/setuidgid.c @@ -1,5 +1,5 @@ /* setuidgid - run a command with the UID and GID of a specified user - Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2003-2007 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 @@ -28,6 +28,7 @@ #include "error.h" #include "long-options.h" +#include "mgetgroups.h" #include "quote.h" #define PROGRAM_NAME "setuidgid" @@ -105,8 +106,21 @@ main (int argc, char **argv) _("unknown user-ID: %s"), quote (user_id)); #if HAVE_SETGROUPS - if (setgroups (1, &pwd->pw_gid)) - error (SETUIDGID_FAILURE, errno, _("cannot set supplemental group")); + { + GETGROUPS_T *groups; + int n_groups = mgetgroups (user_id, pwd->pw_gid, &groups); + if (n_groups < 0) + { + n_groups = 1; + groups = xmalloc (sizeof *groups); + *groups = pwd->pw_gid; + } + + if (0 < n_groups && setgroups (n_groups, groups)) + error (SETUIDGID_FAILURE, errno, _("cannot set supplemental group(s)")); + + free (groups); + } #endif if (setgid (pwd->pw_gid)) -- cgit v1.2.3-54-g00ecf