diff options
author | Giuseppe Scrivano <gscrivano@gnu.org> | 2009-05-01 23:50:11 +0200 |
---|---|---|
committer | Jim Meyering <meyering@redhat.com> | 2009-05-26 15:10:22 +0200 |
commit | c45c51fe97193898f3909dcf5e4c0e117ab239a2 (patch) | |
tree | 9a146adbde39cce97dbd4e1ee5aa3eb296fe02a6 /src | |
parent | 39285f6008a26ff1d5facbffcbf12f57d60564d1 (diff) | |
download | coreutils-c45c51fe97193898f3909dcf5e4c0e117ab239a2.tar.xz |
chroot: accept new options --userspec=U:G and --groups=G1,G2,G3
* NEWS: Note chroot's new options.
* doc/coreutils.texi: Document them.
* src/chroot.c (main): Add support for --userspec and --groups.
* tests/Makefile.am (root-tests): Add chroot/credentials.
* tests/chroot/credentials: New file.
* tests/test-lib.sh: Define NON_ROOT_GROUP to a default value.
Diffstat (limited to 'src')
-rw-r--r-- | src/chroot.c | 125 |
1 files changed, 122 insertions, 3 deletions
diff --git a/src/chroot.c b/src/chroot.c index 6d3fddf77..788a1fc41 100644 --- a/src/chroot.c +++ b/src/chroot.c @@ -21,17 +21,88 @@ #include <getopt.h> #include <stdio.h> #include <sys/types.h> +#include <grp.h> #include "system.h" #include "error.h" #include "long-options.h" #include "quote.h" +#include "userspec.h" +#include "xstrtol.h" /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "chroot" #define AUTHORS proper_name ("Roland McGrath") +#ifndef MAXGID +# define MAXGID GID_T_MAX +#endif + +enum +{ + GROUPS = UCHAR_MAX + 1, + USERSPEC +}; + +static struct option const long_opts[] = +{ + {"groups", required_argument, NULL, GROUPS}, + {"userspec", required_argument, NULL, USERSPEC}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Groups is a comma separated list of additional groups. */ +static int +set_additional_groups (char const *groups) +{ + GETGROUPS_T *gids = NULL; + size_t n_gids_allocated = 0; + size_t n_gids = 0; + char *buffer = xstrdup (groups); + char const *tmp; + int ret; + + for (tmp = strtok (buffer, ","); tmp; tmp = strtok (NULL, ",")) + { + struct group *g; + unsigned long int value; + + if (xstrtoul (tmp, NULL, 10, &value, "") == LONGINT_OK && value <= MAXGID) + { + g = getgrgid (value); + } + else + { + g = getgrnam (tmp); + if (g != NULL) + value = g->gr_gid; + } + + if (g == NULL) + { + error (0, errno, _("cannot find group %s"), tmp); + free (buffer); + return 1; + } + + if (n_gids == n_gids_allocated) + gids = x2nrealloc (gids, &n_gids_allocated, sizeof *gids); + gids[n_gids++] = value; + } + + free (buffer); + + ret = setgroups (n_gids, gids); + + free (gids); + + return ret; +} + + void usage (int status) { @@ -41,13 +112,20 @@ usage (int status) else { printf (_("\ -Usage: %s NEWROOT [COMMAND [ARG]...]\n\ +Usage: %s [OPTION] NEWROOT [COMMAND [ARG]...]\n\ or: %s OPTION\n\ "), program_name, program_name); + fputs (_("\ Run COMMAND with root directory set to NEWROOT.\n\ \n\ "), stdout); + + fputs (_("\ + --userspec=USER:GROUP specify user and group (ID or name) to use\n\ + --groups=G_LIST specify supplementary groups as g1,g2,..,gN\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); fputs (_("\ @@ -62,6 +140,10 @@ If no command is given, run ``${SHELL} -i'' (default: /bin/sh).\n\ int main (int argc, char **argv) { + int c; + char const *userspec = NULL; + char const *groups = NULL; + initialize_main (&argc, &argv); set_program_name (argv[0]); setlocale (LC_ALL, ""); @@ -73,8 +155,21 @@ main (int argc, char **argv) parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version, usage, AUTHORS, (char const *) NULL); - if (getopt_long (argc, argv, "+", NULL, NULL) != -1) - usage (EXIT_FAILURE); + + while ((c = getopt_long (argc, argv, "+", long_opts, NULL)) != -1) + { + switch (c) + { + case USERSPEC: + userspec = optarg; + break; + case GROUPS: + groups = optarg; + break; + default: + usage (EXIT_FAILURE); + } + } if (argc <= optind) { @@ -105,6 +200,30 @@ main (int argc, char **argv) argv += optind + 1; } + if (userspec) + { + uid_t uid; + gid_t gid; + char *user; + char *group; + char const *err = parse_user_spec (userspec, &uid, &gid, &user, &group); + + if (err) + error (EXIT_FAILURE, errno, "%s", err); + + free (user); + free (group); + + if (groups && set_additional_groups (groups)) + error (0, errno, _("failed to set additional groups")); + + if (gid && setgid (gid)) + error (0, errno, _("failed to set group-ID")); + + if (uid && setuid (uid)) + error (0, errno, _("failed to set user-ID")); + } + /* Execute the given command. */ execvp (argv[0], argv); |