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.
This commit is contained in:
Jim Meyering 2007-07-05 17:42:29 +02:00
parent b8031ff7c7
commit e0066f36c2
12 changed files with 195 additions and 56 deletions

View File

@ -1,5 +1,23 @@
2007-07-05 Jim Meyering <jim@meyering.net>
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.

View File

@ -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

80
gl/lib/mgetgroups.c Normal file
View File

@ -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 <config.h>
#include "mgetgroups.h"
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#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;
}

21
gl/lib/mgetgroups.h Normal file
View File

@ -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 <sys/types.h>
int mgetgroups (const char *username, gid_t gid, GETGROUPS_T **groups);

10
gl/m4/mgetgroups.m4 Normal file
View File

@ -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])
])

25
gl/modules/mgetgroups Normal file
View File

@ -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

View File

@ -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

3
lib/.gitignore vendored
View File

@ -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

View File

@ -144,6 +144,7 @@ memmove.m4
mempcpy.m4
memrchr.m4
memset.m4
mgetgroups.m4
mkancesdirs.m4
mkdir-p.m4
mkdir-slash.m4

2
m4/.gitignore vendored
View File

@ -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

View File

@ -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;
}

View File

@ -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))