[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] chroot specify user/group feature
From: |
Giuseppe Scrivano |
Subject: |
Re: [PATCH] chroot specify user/group feature |
Date: |
Tue, 19 May 2009 22:32:04 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.0.93 (gnu/linux) |
Hi Jim,
this is an updated version for the previous patch. I added
documentation and new tests.
Since I don't use short-named options, there are not conflicts with -u,
-g and -G used by different chroot implementations.
In my first version -g has a different meaning than the -g on FreeBSD
and OpenBSD; now I removed this option and I kept only the long-named
version --groups.
Regards,
Giuseppe
>From 60834e55e2826d41de545794123a7007536873e4 Mon Sep 17 00:00:00 2001
From: Giuseppe Scrivano <address@hidden>
Date: Fri, 1 May 2009 23:50:11 +0200
Subject: [PATCH] Chroot now accepts the options --userspec and --groups.
* NEWS: Added note about the new chroot features.
* doc/coreutils.texi: Likewise.
* src/chroot.c (main): Added support for --userspec and --groups.
* tests/Makefile.am: Added tests for chroot.
* tests/chroot/credentials: Likewise.
* tests/test-lib.sh: Likewise.
---
NEWS | 5 ++
doc/coreutils.texi | 13 ++++-
src/chroot.c | 125 ++++++++++++++++++++++++++++++++++++++++++++-
tests/Makefile.am | 1 +
tests/chroot/credentials | 41 +++++++++++++++
tests/test-lib.sh | 1 +
6 files changed, 181 insertions(+), 5 deletions(-)
create mode 100644 tests/chroot/credentials
diff --git a/NEWS b/NEWS
index 31f1b1a..3af06e4 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,11 @@ GNU coreutils NEWS -*-
outline -*-
truncate -s failed to skip all whitespace in the option argument in
some locales.
+** New features
+
+ chroot now accepts the options --userspec and --groups.
+
+
* Noteworthy changes in release 7.4 (2009-05-07) [stable]
** Bug fixes
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index b96fdb2..29745b1 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -14157,8 +14157,17 @@ variable or @command{/bin/sh} if not set, invoked with
the @option{-i} option.
@var{command} must not be a special built-in utility
(@pxref{Special built-in utilities}).
-The only options are @option{--help} and @option{--version}. @xref{Common
-options}. Options must precede operands.
+Options accepted by chroot are @option{--help}, @option{--version},
address@hidden and @option{--groups}. @xref{Common options}.
+Options must precede operands.
+
+If not specified differently, @command{chroot} keeps the user
+credentials in the new environment, that usually is the super-user.
+This behaviour can be changed by the @option{--userspec} option. It
+allows to specify new credentials in the form @var{user:group}.
+Additional groups can be configured using the @option{--groups}
+option. If any of @option{--userspec} or @option{--groups} are not
+specified then the original values are kept.
Here are a few tips to help avoid common problems in using chroot.
To start with a simple example, make @var{command} refer to a statically
diff --git a/src/chroot.c b/src/chroot.c
index 6d3fddf..ca9ac00 100644
--- a/src/chroot.c
+++ b/src/chroot.c
@@ -21,17 +21,80 @@
#include <getopt.h>
#include <stdio.h>
#include <sys/types.h>
+#include <grp.h>
#include "system.h"
#include "error.h"
#include "long-options.h"
+#include "userspec.h"
#include "quote.h"
+#include "xstrtol.h"
+
+#ifndef GID_T_MAX
+# define GID_T_MAX TYPE_MAXIMUM (gid_t)
+#endif
+
+#ifndef MAXGID
+# define MAXGID GID_T_MAX
+#endif
+
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "chroot"
#define AUTHORS proper_name ("Roland McGrath")
+enum { USERSPEC = UCHAR_MAX + 1, GROUPS};
+
+static struct option const long_opts[] =
+{
+ {"userspec", required_argument, NULL, USERSPEC},
+ {"groups", required_argument, NULL, GROUPS},
+ {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 (const char *groups)
+{
+ gid_t groups_id [NGROUPS];
+ int ngroups = 0;
+ char *buffer = xstrdup (groups);
+ const char *tmp;
+
+ 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;
+ }
+
+ groups_id[ngroups++] = value;
+ }
+
+ free (buffer);
+
+ return setgroups (ngroups, groups_id);
+}
+
+
void
usage (int status)
{
@@ -41,13 +104,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, specify the userspec in the form USER:GROUP\n\
+ --groups, specify the additional groups as g1,g2,..,gn\n\
+"), stdout);
+
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
@@ -62,6 +132,10 @@ If no command is given, run ``${SHELL} -i'' (default:
/bin/sh).\n\
int
main (int argc, char **argv)
{
+ int c;
+ const char *userspec = NULL;
+ const char *groups = NULL;
+
initialize_main (&argc, &argv);
set_program_name (argv[0]);
setlocale (LC_ALL, "");
@@ -73,8 +147,20 @@ 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 +191,39 @@ main (int argc, char **argv)
argv += optind + 1;
}
+ if (userspec)
+ {
+ uid_t uid;
+ gid_t gid;
+ char *user;
+ char *group;
+ const char *err = parse_user_spec (userspec, &uid, &gid, &user, &group);
+ if (err)
+ {
+ perror (err);
+ exit (1);
+ }
+
+ free (user);
+ free (group);
+
+ if (groups)
+ {
+ if (set_additional_groups (groups))
+ error (0, errno, _("cannot set additional groups"));
+ }
+
+ if (gid && setgid (gid))
+ {
+ error (0, errno, _("cannot setgid"));
+ }
+
+ if (uid && setuid (uid))
+ {
+ error (0, errno, _("cannot setgid"));
+ }
+ }
+
/* Execute the given command. */
execvp (argv[0], argv);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7fe74c0..c3746e2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -24,6 +24,7 @@ root_tests = \
cp/preserve-gid \
cp/special-bits \
cp/cp-mv-enotsup-xattr \
+ chroot/credentials \
dd/skip-seek-past-dev \
install/install-C-root \
ls/capability \
diff --git a/tests/chroot/credentials b/tests/chroot/credentials
new file mode 100644
index 0000000..f3e7a32
--- /dev/null
+++ b/tests/chroot/credentials
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Verify that the credentials are changed correctly.
+
+# Copyright (C) 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 <http://www.gnu.org/licenses/>.
+
+
+if test "$VERBOSE" = yes; then
+ set -x
+ chroot --version
+fi
+
+. $srcdir/test-lib.sh
+
+require_root_
+
+fail=0
+
+# Verify that root credentials are kept.
+test `chroot / whoami` == root || fail=1
+test "`groups`" == "`chroot / groups`" || fail=1
+
+# Verify that credentials are changed correctly.
+test "`chroot --userspec=$NON_ROOT_USERNAME:$NON_ROOT_GROUP / whoami`" != root
|| fail=1
+
+# Verify that there are no additional groups.
+test "`chroot --userspec=$NON_ROOT_USERNAME:$NON_ROOT_GROUP --groups="" / id
-nG`" == $NON_ROOT_GROUP || fail=1
+
+Exit $fail
diff --git a/tests/test-lib.sh b/tests/test-lib.sh
index 17a3538..a765bd6 100644
--- a/tests/test-lib.sh
+++ b/tests/test-lib.sh
@@ -204,6 +204,7 @@ require_root_()
{
uid_is_privileged_ || skip_test_ "must be run as root"
NON_ROOT_USERNAME=${NON_ROOT_USERNAME=nobody}
+ NON_ROOT_GROUP=${NON_ROOT_GROUP=nogroup}
}
skip_if_root_() { uid_is_privileged_ && skip_test_ "must be run as non-root"; }
--
1.6.2.4
- Re: [PATCH] chroot specify user/group feature, Jim Meyering, 2009/05/18
- Re: [PATCH] chroot specify user/group feature, Giuseppe Scrivano, 2009/05/18
- Re: [PATCH] chroot specify user/group feature, Jim Meyering, 2009/05/18
- Re: [PATCH] chroot specify user/group feature, Giuseppe Scrivano, 2009/05/20
- Re: [PATCH] chroot specify user/group feature, Jim Meyering, 2009/05/25
- Re: [PATCH] chroot specify user/group feature, Jim Meyering, 2009/05/26
- Re: [PATCH] chroot specify user/group feature, Eric Blake, 2009/05/27
- Re: [PATCH] chroot specify user/group feature, Giuseppe Scrivano, 2009/05/27
- Re: [PATCH] chroot specify user/group feature, Jim Meyering, 2009/05/27
- Re: [PATCH] chroot specify user/group feature, Giuseppe Scrivano, 2009/05/28