[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] chroot: add --before to get UID/GID before chroot
From: |
norihiro |
Subject: |
[PATCH] chroot: add --before to get UID/GID before chroot |
Date: |
Wed, 20 Jul 2011 02:44:31 +0900 |
User-agent: |
Mutt/1.4.2.1i |
I have a feature request for chroot.
An option --userspec did not work with a chroot jail created from scratch,
even if it has /etc/passwd and /etc/group and it says:
chroot: invalid user
The option --userspec requires many files to retrieve UID/GID.
I suggest an option --before to retrieve UID/GID before chroot.
With the option --before, UID/GID is retrieved from old root.
I attached a patch to add the option --before.
I split an old function set_additional_groups into 2 functions
get_additional_groups and set_additional_groups.
With --before, get_additional_groups and/or parse_user_spec will
be called before chroot and store UID/GIDs to local variables
in a function main. Without --before, get_additional_groups will
be called just before set_additional_groups and parse_user_spec
will be called in same order to that of previous.
Thanks.
>From 38c0c5256c21a00de5e1f77a394fcf4af05c10e7 Mon Sep 17 00:00:00 2001
From: Kamae Norihiro <address@hidden>
Date: Wed, 20 Jul 2011 01:40:29 +0900
Subject: [PATCH] chroot: add --before to get UID/GID before chroot
If you use chroot jail which has no account information,
chroot with --userspec or --groups will fail with
error invalid user.
With --before, UID/GID will be retrieved before chroot
to get account informations from old root.
* src/chroot.c: add option --before
* NEWS: mention about the option
* doc/coreutils.texi: describe it
---
NEWS | 6 ++++
doc/coreutils.texi | 7 +++++
src/chroot.c | 74 ++++++++++++++++++++++++++++++++++++++++++----------
3 files changed, 73 insertions(+), 14 deletions(-)
diff --git a/NEWS b/NEWS
index 61e6e63..84cb141 100644
--- a/NEWS
+++ b/NEWS
@@ -41,6 +41,12 @@ GNU coreutils NEWS -*-
outline -*-
directly from a shell prompt, where the command is interactive or needs to
receive signals initiated from the terminal.
+ chroot accepts a new --before option. With --userspec and/or --groups and
+ this option, UID/GID will be determined before chroot(). For example,
+ with a small chroot jail without account information files, this option
+ enables the option --userspec or --groups to work with an account before
+ chroot call.
+
** Improvements
shuf outputs small subsets of large permutations much more efficiently.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 424446c..9bf59fb 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -15004,6 +15004,13 @@ Use this option to specify the supplementary
@var{groups} to be
used by the new process.
The items in the list (names or numeric IDs) must be separated by commas.
+@itemx --before
+@opindex --before
+By default, option @option{--userspec} or @option{--groups}
+retrieves UID or GID from @var{newroot}.
+Use this option
+to retrieve UID or GID from old root.
+
@end table
Here are a few tips to help avoid common problems in using chroot.
diff --git a/src/chroot.c b/src/chroot.c
index 95c227b..e068fbf 100644
--- a/src/chroot.c
+++ b/src/chroot.c
@@ -40,13 +40,15 @@
enum
{
GROUPS = UCHAR_MAX + 1,
- USERSPEC
+ USERSPEC,
+ BEFORE
};
static struct option const long_opts[] =
{
{"groups", required_argument, NULL, GROUPS},
{"userspec", required_argument, NULL, USERSPEC},
+ {"before", no_argument, NULL, BEFORE},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
@@ -58,7 +60,7 @@ static struct option const long_opts[] =
resulting numbers. Upon any failure give a diagnostic and return nonzero.
Otherwise return zero. */
static int
-set_additional_groups (char const *groups)
+get_additional_groups (char const *groups, size_t *n_gids_ret, GETGROUPS_T
**gids_ret)
{
GETGROUPS_T *gids = NULL;
size_t n_gids_allocated = 0;
@@ -93,6 +95,17 @@ set_additional_groups (char const *groups)
gids[n_gids++] = value;
}
+ *n_gids_ret = n_gids;
+ *gids_ret = gids;
+
+ free (buffer);
+ return ret;
+}
+
+static int
+set_additional_groups (char const *groups, int n_gids, GETGROUPS_T *gids)
+{
+ int ret = 0;
if (ret == 0 && n_gids == 0)
{
error (0, 0, _("invalid group list %s"), quote (groups));
@@ -106,7 +119,6 @@ set_additional_groups (char const *groups)
error (0, errno, _("failed to set additional groups"));
}
- free (buffer);
free (gids);
return ret;
}
@@ -132,6 +144,7 @@ Run COMMAND with root directory set to NEWROOT.\n\
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\
+ --before UID or GID is determined before chroot\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
@@ -151,6 +164,11 @@ main (int argc, char **argv)
int c;
char const *userspec = NULL;
char const *groups = NULL;
+ bool before = false;
+ uid_t uid = -1;
+ gid_t gid = -1;
+ int n_gids;
+ GETGROUPS_T *gids = NULL;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
@@ -173,6 +191,10 @@ main (int argc, char **argv)
groups = optarg;
break;
+ case BEFORE:
+ before = true;
+ break;
+
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -188,6 +210,24 @@ main (int argc, char **argv)
usage (EXIT_CANCELED);
}
+ if (before)
+ {
+ if (userspec)
+ {
+ char *user;
+ char *group;
+ char const *err = parse_user_spec (userspec, &uid, &gid, &user,
&group);
+
+ if (err)
+ error (EXIT_CANCELED, errno, "%s", err);
+
+ free (user);
+ free (group);
+ }
+ if (groups && get_additional_groups (groups, &n_gids, &gids))
+ exit (EXIT_CANCELED);
+ }
+
if (chroot (argv[optind]) != 0)
error (EXIT_CANCELED, errno, _("cannot change root directory to %s"),
argv[optind]);
@@ -217,19 +257,22 @@ main (int argc, char **argv)
Diagnose any failures. If any have failed, exit before execvp. */
if (userspec)
{
- uid_t uid = -1;
- gid_t gid = -1;
- char *user;
- char *group;
- char const *err = parse_user_spec (userspec, &uid, &gid, &user, &group);
+ if (!before)
+ {
+ char *user;
+ char *group;
+ char const *err = parse_user_spec (userspec, &uid, &gid, &user,
&group);
- if (err)
- error (EXIT_CANCELED, errno, "%s", err);
+ if (err)
+ error (EXIT_CANCELED, errno, "%s", err);
- free (user);
- free (group);
+ free (user);
+ free (group);
+ if (groups && get_additional_groups (groups, &n_gids, &gids))
+ fail = true;
+ }
- if (groups && set_additional_groups (groups))
+ if (!fail && groups && set_additional_groups (groups, n_gids, gids))
fail = true;
if (gid != (gid_t) -1 && setgid (gid))
@@ -246,11 +289,14 @@ main (int argc, char **argv)
}
else
{
+ if (!before && groups && get_additional_groups (groups, n_gids, gids))
+ fail = true;
+
/* Yes, this call is identical to the one above.
However, when --userspec and --groups groups are used together,
we don't want to call this function until after parsing USER:GROUP,
and it must be called before setuid. */
- if (groups && set_additional_groups (groups))
+ if (groups && set_additional_groups (groups, n_gids, gids))
fail = true;
}
--
1.7.4.4
--
Kamae Norihiro
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [PATCH] chroot: add --before to get UID/GID before chroot,
norihiro <=