summaryrefslogtreecommitdiff
path: root/meta/recipes-extended/shadow/files
diff options
context:
space:
mode:
authorScott Garman <scott.a.garman@intel.com>2011-05-09 23:02:39 -0700
committerRichard Purdie <richard.purdie@linuxfoundation.org>2011-06-06 15:52:18 +0100
commit37b8c18a3c2f3e77a9810a56a8ee786855ae1ba3 (patch)
tree987e849cfdb31913f08469021d16b5a2b0cc4a61 /meta/recipes-extended/shadow/files
parent254ca8c1667b8d35914555714239a09bfb4f43be (diff)
downloadopenembedded-core-37b8c18a3c2f3e77a9810a56a8ee786855ae1ba3.tar.gz
openembedded-core-37b8c18a3c2f3e77a9810a56a8ee786855ae1ba3.tar.bz2
openembedded-core-37b8c18a3c2f3e77a9810a56a8ee786855ae1ba3.zip
shadow: add a -native recipe with customized utilities
This adds a -native recipe for the shadow utilities. The custom --root option allows the the following utilities to be run within a chroot when invoked under pseudo: * useradd * groupadd * usermod * groupmod * userdel * groupdel * passwd * gpasswd * pwconv * pwunconv * grpconv * grpunconv They can then be used to manipulate user and group account information in target sysroots. useradd was also modified to create home directories recursively when necessary. Signed-off-by: Scott Garman <scott.a.garman@intel.com>
Diffstat (limited to 'meta/recipes-extended/shadow/files')
-rw-r--r--meta/recipes-extended/shadow/files/add_root_cmd_options.patch1296
1 files changed, 1296 insertions, 0 deletions
diff --git a/meta/recipes-extended/shadow/files/add_root_cmd_options.patch b/meta/recipes-extended/shadow/files/add_root_cmd_options.patch
new file mode 100644
index 0000000000..db969bbb60
--- /dev/null
+++ b/meta/recipes-extended/shadow/files/add_root_cmd_options.patch
@@ -0,0 +1,1296 @@
+Add a --root command option to the following utilties:
+
+* useradd
+* groupadd
+* usermod
+* groupmod
+* userdel
+* groupdel
+* passwd
+* gpasswd
+* pwconv
+* pwunconv
+* grpconv
+* grpunconv
+
+This option allows the utilities to be chrooted when run under pseudo.
+They can then be used to manipulate user and group account information
+in target sysroots.
+
+The useradd utility was also modified to create home directories
+recursively when necessary.
+
+Upstream-Status: Inappropriate [Other]
+Workaround is specific to our build system.
+
+Signed-off-by: Scott Garman <scott.a.garman@intel.com>
+
+diff -urN shadow-4.1.4.3.orig//src/gpasswd.c shadow-4.1.4.3//src/gpasswd.c
+--- shadow-4.1.4.3.orig//src/gpasswd.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/gpasswd.c 2011-05-28 17:09:52.346013331 -0700
+@@ -63,6 +63,7 @@
+ * (/etc/gshadow present) */
+ static bool is_shadowgrp;
+ #endif
++static const char *newroot = "";
+
+ /* Flags set by options */
+ static bool aflg = false;
+@@ -97,6 +98,7 @@
+ static void usage (void);
+ static RETSIGTYPE catch_signals (int killed);
+ static bool is_valid_user_list (const char *users);
++static void process_root_flag (int argc, char **argv);
+ static void process_flags (int argc, char **argv);
+ static void check_flags (int argc, int opt_index);
+ static void open_files (void);
+@@ -136,6 +138,7 @@
+ "Options:\n"
+ " -a, --add USER add USER to GROUP\n"
+ " -d, --delete USER remove USER from GROUP\n"
++ " -Q --root CHROOT_DIR directory to chroot into\n"
+ " -r, --remove-password remove the GROUP's password\n"
+ " -R, --restrict restrict access to GROUP to its members\n"
+ " -M, --members USER,... set the list of members of GROUP\n"
+@@ -226,6 +229,55 @@
+ }
+
+ /*
++ * process_root_flag - chroot if given the --root option
++ *
++ * We do this outside of process_flags() because
++ * the is_shadow_pwd boolean needs to be set before
++ * process_flags(), and if we do need to chroot() we
++ * must do so before is_shadow_pwd gets set.
++ */
++static void process_root_flag (int argc, char **argv)
++{
++ /*
++ * Parse the command line options.
++ */
++ int flag;
++ int option_index = 0;
++ static struct option long_options[] = {
++ {"root", required_argument, NULL, 'Q'},
++ {NULL, 0, NULL, '\0'}
++ };
++
++ while ((flag = getopt_long (argc, argv, "a:A:d:gM:Q:rR", long_options, &option_index)) != -1) {
++ switch (flag) {
++ case 'Q':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
++ /* no-op on everything else - they will be hanled by process_flags() */
++ }
++ }
++}
++
++/*
+ * process_flags - process the command line options and arguments
+ */
+ static void process_flags (int argc, char **argv)
+@@ -235,6 +287,7 @@
+ static struct option long_options[] = {
+ {"add", required_argument, NULL, 'a'},
+ {"delete", required_argument, NULL, 'd'},
++ {"root", required_argument, NULL, 'Q'},
+ {"remove-password", no_argument, NULL, 'r'},
+ {"restrict", no_argument, NULL, 'R'},
+ {"administrators", required_argument, NULL, 'A'},
+@@ -242,7 +295,7 @@
+ {NULL, 0, NULL, '\0'}
+ };
+
+- while ((flag = getopt_long (argc, argv, "a:A:d:gM:rR", long_options, &option_index)) != -1) {
++ while ((flag = getopt_long (argc, argv, "a:A:d:gM:Q:rR", long_options, &option_index)) != -1) {
+ switch (flag) {
+ case 'a': /* add a user */
+ aflg = true;
+@@ -283,6 +336,9 @@
+ }
+ Mflg = true;
+ break;
++ case 'Q':
++ /* no-op since we handled this in process_root_flag() earlier */
++ break;
+ case 'r': /* remove group password */
+ rflg = true;
+ break;
+@@ -995,6 +1051,8 @@
+ setbuf (stdout, NULL);
+ setbuf (stderr, NULL);
+
++ process_root_flag (argc, argv);
++
+ #ifdef SHADOWGRP
+ is_shadowgrp = sgr_file_present ();
+ #endif
+diff -urN shadow-4.1.4.3.orig//src/groupadd.c shadow-4.1.4.3//src/groupadd.c
+--- shadow-4.1.4.3.orig//src/groupadd.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/groupadd.c 2011-05-28 17:09:52.346013331 -0700
+@@ -76,6 +76,7 @@
+ static gid_t group_id;
+ static /*@null@*/char *group_passwd;
+ static /*@null@*/char *empty_list = NULL;
++static const char *newroot = "";
+
+ static bool oflg = false; /* permit non-unique group ID to be specified with -g */
+ static bool gflg = false; /* ID value for the new group */
+@@ -120,6 +121,7 @@
+ (void) fputs (_(" -o, --non-unique allow to create groups with duplicate\n"
+ " (non-unique) GID\n"), stderr);
+ (void) fputs (_(" -p, --password PASSWORD use this encrypted password for the new group\n"), stderr);
++ (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), stderr);
+ (void) fputs (_(" -r, --system create a system account\n"), stderr);
+ (void) fputs ("\n", stderr);
+ exit (E_USAGE);
+@@ -383,12 +385,13 @@
+ {"key", required_argument, NULL, 'K'},
+ {"non-unique", no_argument, NULL, 'o'},
+ {"password", required_argument, NULL, 'p'},
++ {"root", required_argument, NULL, 'R'},
+ {"system", no_argument, NULL, 'r'},
+ {NULL, 0, NULL, '\0'}
+ };
+
+ while ((c =
+- getopt_long (argc, argv, "fg:hK:op:r", long_options,
++ getopt_long (argc, argv, "fg:hK:op:R:r", long_options,
+ &option_index)) != -1) {
+ switch (c) {
+ case 'f':
+@@ -440,6 +443,28 @@
+ pflg = true;
+ group_passwd = optarg;
+ break;
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
+ case 'r':
+ rflg = true;
+ break;
+diff -urN shadow-4.1.4.3.orig//src/groupdel.c shadow-4.1.4.3//src/groupdel.c
+--- shadow-4.1.4.3.orig//src/groupdel.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/groupdel.c 2011-05-28 17:09:52.346013331 -0700
+@@ -36,6 +36,7 @@
+
+ #include <ctype.h>
+ #include <fcntl.h>
++#include <getopt.h>
+ #include <grp.h>
+ #include <pwd.h>
+ #ifdef ACCT_TOOLS_SETUID
+@@ -59,6 +60,7 @@
+
+ static char *group_name;
+ static gid_t group_id = -1;
++static const char *newroot = "";
+
+ #ifdef SHADOWGRP
+ static bool is_shadow_grp;
+@@ -70,12 +72,14 @@
+ /*@-exitarg@*/
+ #define E_SUCCESS 0 /* success */
+ #define E_USAGE 2 /* invalid command syntax */
++#define E_BAD_ARG 3 /* invalid argument to option */
+ #define E_NOTFOUND 6 /* specified group doesn't exist */
+ #define E_GROUP_BUSY 8 /* can't remove user's primary group */
+ #define E_GRP_UPDATE 10 /* can't update group file */
+
+ /* local function prototypes */
+ static void usage (void);
++static void process_flags (int argc, char **argv);
+ static void grp_update (void);
+ static void close_files (void);
+ static void open_files (void);
+@@ -86,11 +90,78 @@
+ */
+ static void usage (void)
+ {
+- fputs (_("Usage: groupdel group\n"), stderr);
++ (void) fprintf (stderr,
++ _("Usage: groupdel [options]\n"
++ "\n"
++ "Options:\n"),
++ Prog);
++ (void) fputs (_(" -g, --group GROUP group name to delete\n"), stderr);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
++ (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), stderr);
++ (void) fputs ("\n", stderr);
+ exit (E_USAGE);
+ }
+
+ /*
++ * process_flags - perform command line argument setting
++ *
++ * process_flags() interprets the command line arguments and sets
++ * the values that the user will be created with accordingly. The
++ * values are checked for sanity.
++ */
++static void process_flags (int argc, char **argv)
++{
++ {
++ /*
++ * Parse the command line options.
++ */
++ int c;
++ static struct option long_options[] = {
++ {"group", required_argument, NULL, 'g'},
++ {"help", no_argument, NULL, 'h'},
++ {"root", required_argument, NULL, 'R'},
++ {NULL, 0, NULL, '\0'}
++ };
++ while ((c = getopt_long (argc, argv,
++ "g:R:",
++ long_options, NULL)) != -1) {
++ switch (c) {
++ case 'g':
++ group_name = optarg;
++ break;
++ case 'h':
++ usage ();
++ break;
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
++ default:
++ usage ();
++ }
++ }
++ }
++}
++
++/*
+ * grp_update - update group file entries
+ *
+ * grp_update() writes the new records to the group files.
+@@ -328,14 +399,14 @@
+ (void) bindtextdomain (PACKAGE, LOCALEDIR);
+ (void) textdomain (PACKAGE);
+
+- if (argc != 2) {
++ if (argc == 1) {
+ usage ();
+ }
+
+- group_name = argv[1];
+-
+ OPENLOG ("groupdel");
+
++ process_flags (argc, argv);
++
+ #ifdef ACCT_TOOLS_SETUID
+ #ifdef USE_PAM
+ {
+diff -urN shadow-4.1.4.3.orig//src/groupmod.c shadow-4.1.4.3//src/groupmod.c
+--- shadow-4.1.4.3.orig//src/groupmod.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/groupmod.c 2011-05-28 17:09:52.346013331 -0700
+@@ -79,6 +79,7 @@
+ static char *group_passwd;
+ static gid_t group_id;
+ static gid_t group_newid;
++static char *newroot = "";
+
+ struct cleanup_info_mod info_passwd;
+ struct cleanup_info_mod info_group;
+@@ -126,6 +127,7 @@
+ (void) fputs (_(" -o, --non-unique allow to use a duplicate (non-unique) GID\n"), stderr);
+ (void) fputs (_(" -p, --password PASSWORD change the password to this (encrypted)\n"
+ " PASSWORD\n"), stderr);
++ (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), stderr);
+ (void) fputs ("\n", stderr);
+ exit (E_USAGE);
+ }
+@@ -346,10 +348,11 @@
+ {"new-name", required_argument, NULL, 'n'},
+ {"non-unique", no_argument, NULL, 'o'},
+ {"password", required_argument, NULL, 'p'},
++ {"root", required_argument, NULL, 'R'},
+ {NULL, 0, NULL, '\0'}
+ };
+ while ((c =
+- getopt_long (argc, argv, "g:hn:op:",
++ getopt_long (argc, argv, "g:hn:op:R:",
+ long_options, &option_index)) != -1) {
+ switch (c) {
+ case 'g':
+@@ -373,6 +376,28 @@
+ group_passwd = optarg;
+ pflg = true;
+ break;
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
+ default:
+ usage ();
+ }
+diff -urN shadow-4.1.4.3.orig//src/grpconv.c shadow-4.1.4.3//src/grpconv.c
+--- shadow-4.1.4.3.orig//src/grpconv.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/grpconv.c 2011-05-28 17:09:52.346013331 -0700
+@@ -39,6 +39,7 @@
+
+ #include <errno.h>
+ #include <fcntl.h>
++#include <getopt.h>
+ #include <grp.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -50,6 +51,14 @@
+ #ifdef SHADOWGRP
+ #include "groupio.h"
+ #include "sgroupio.h"
++
++/*
++ * exit status values
++ */
++/*@-exitarg@*/
++#define E_USAGE 2 /* invalid command syntax */
++#define E_BAD_ARG 3 /* invalid argument to option */
++
+ /*
+ * Global variables
+ */
+@@ -57,9 +66,12 @@
+
+ static bool gr_locked = false;
+ static bool sgr_locked = false;
++static const char *newroot = "";
+
+ /* local function prototypes */
+ static void fail_exit (int status);
++static void usage (void);
++static void process_flags (int argc, char **argv);
+
+ static void fail_exit (int status)
+ {
+@@ -82,6 +94,77 @@
+ exit (status);
+ }
+
++/*
++ * usage - display usage message and exit
++ */
++static void usage (void)
++{
++ (void) fprintf (stderr,
++ _("Usage: grpconv [options]\n"
++ "\n"
++ "Options:\n"),
++ Prog);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
++ (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), stderr);
++ (void) fputs ("\n", stderr);
++ exit (E_USAGE);
++}
++
++/*
++ * process_flags - perform command line argument setting
++ *
++ * process_flags() interprets the command line arguments and sets
++ * the values that the user will be created with accordingly. The
++ * values are checked for sanity.
++ */
++static void process_flags (int argc, char **argv)
++{
++ {
++ /*
++ * Parse the command line options.
++ */
++ int c;
++ static struct option long_options[] = {
++ {"help", no_argument, NULL, 'h'},
++ {"root", required_argument, NULL, 'R'},
++ {NULL, 0, NULL, '\0'}
++ };
++ while ((c = getopt_long (argc, argv,
++ "R:",
++ long_options, NULL)) != -1) {
++ switch (c) {
++ case 'h':
++ usage ();
++ break;
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
++ default:
++ usage ();
++ }
++ }
++ }
++}
++
+ int main (int argc, char **argv)
+ {
+ const struct group *gr;
+@@ -100,6 +183,8 @@
+
+ OPENLOG ("grpconv");
+
++ process_flags (argc, argv);
++
+ if (gr_lock () == 0) {
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+diff -urN shadow-4.1.4.3.orig//src/grpunconv.c shadow-4.1.4.3//src/grpunconv.c
+--- shadow-4.1.4.3.orig//src/grpunconv.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/grpunconv.c 2011-05-28 17:09:52.346013331 -0700
+@@ -43,6 +43,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <fcntl.h>
++#include <getopt.h>
+ #include <time.h>
+ #include <unistd.h>
+ #include <grp.h>
+@@ -51,6 +52,14 @@
+ #ifdef SHADOWGRP
+ #include "groupio.h"
+ #include "sgroupio.h"
++
++/*
++ * exit status values
++ */
++/*@-exitarg@*/
++#define E_USAGE 2 /* invalid command syntax */
++#define E_BAD_ARG 3 /* invalid argument to option */
++
+ /*
+ * Global variables
+ */
+@@ -58,9 +67,12 @@
+
+ static bool gr_locked = false;
+ static bool sgr_locked = false;
++static const char *newroot = "";
+
+ /* local function prototypes */
+ static void fail_exit (int status);
++static void usage (void);
++static void process_flags (int argc, char **argv);
+
+ static void fail_exit (int status)
+ {
+@@ -83,6 +95,77 @@
+ exit (status);
+ }
+
++/*
++ * usage - display usage message and exit
++ */
++static void usage (void)
++{
++ (void) fprintf (stderr,
++ _("Usage: grpunconv [options]\n"
++ "\n"
++ "Options:\n"),
++ Prog);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
++ (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), stderr);
++ (void) fputs ("\n", stderr);
++ exit (E_USAGE);
++}
++
++/*
++ * process_flags - perform command line argument setting
++ *
++ * process_flags() interprets the command line arguments and sets
++ * the values that the user will be created with accordingly. The
++ * values are checked for sanity.
++ */
++static void process_flags (int argc, char **argv)
++{
++ {
++ /*
++ * Parse the command line options.
++ */
++ int c;
++ static struct option long_options[] = {
++ {"help", no_argument, NULL, 'h'},
++ {"root", required_argument, NULL, 'R'},
++ {NULL, 0, NULL, '\0'}
++ };
++ while ((c = getopt_long (argc, argv,
++ "R:",
++ long_options, NULL)) != -1) {
++ switch (c) {
++ case 'h':
++ usage ();
++ break;
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
++ default:
++ usage ();
++ }
++ }
++ }
++}
++
+ int main (int argc, char **argv)
+ {
+ const struct group *gr;
+@@ -100,6 +183,8 @@
+
+ OPENLOG ("grpunconv");
+
++ process_flags (argc, argv);
++
+ if (sgr_file_present () == 0) {
+ exit (0); /* no /etc/gshadow, nothing to do */
+ }
+diff -urN shadow-4.1.4.3.orig//src/passwd.c shadow-4.1.4.3//src/passwd.c
+--- shadow-4.1.4.3.orig//src/passwd.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/passwd.c 2011-05-28 17:09:52.346013331 -0700
+@@ -75,6 +75,7 @@
+ static char *name; /* The name of user whose password is being changed */
+ static char *myname; /* The current user's name */
+ static bool amroot; /* The caller's real UID was 0 */
++static const char *newroot = "";
+
+ static bool
+ aflg = false, /* -a - show status for all users */
+@@ -174,6 +175,7 @@
+ " -n, --mindays MIN_DAYS set minimum number of days before password\n"
+ " change to MIN_DAYS\n"
+ " -q, --quiet quiet mode\n"
++ " -R, --root CHROOT_DIR directory to chroot into\n"
+ " -r, --repository REPOSITORY change password in REPOSITORY repository\n"
+ " -S, --status report password status on the named account\n"
+ " -u, --unlock unlock the password of the named account\n"
+@@ -803,6 +805,7 @@
+ {"lock", no_argument, NULL, 'l'},
+ {"mindays", required_argument, NULL, 'n'},
+ {"quiet", no_argument, NULL, 'q'},
++ {"root", required_argument, NULL, 'R'},
+ {"repository", required_argument, NULL, 'r'},
+ {"status", no_argument, NULL, 'S'},
+ {"unlock", no_argument, NULL, 'u'},
+@@ -811,7 +814,7 @@
+ {NULL, 0, NULL, '\0'}
+ };
+
+- while ((c = getopt_long (argc, argv, "adei:kln:qr:Suw:x:",
++ while ((c = getopt_long (argc, argv, "adei:kln:qR:r:Suw:x:",
+ long_options, &option_index)) != -1) {
+ switch (c) {
+ case 'a':
+@@ -858,6 +861,28 @@
+ case 'q':
+ qflg = true; /* ok for users */
+ break;
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
+ case 'r':
+ /* -r repository (files|nis|nisplus) */
+ /* only "files" supported for now */
+diff -urN shadow-4.1.4.3.orig//src/pwconv.c shadow-4.1.4.3//src/pwconv.c
+--- shadow-4.1.4.3.orig//src/pwconv.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/pwconv.c 2011-05-28 17:09:52.346013331 -0700
+@@ -59,6 +59,7 @@
+
+ #include <errno.h>
+ #include <fcntl.h>
++#include <getopt.h>
+ #include <pwd.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -79,6 +80,7 @@
+ #define E_SUCCESS 0 /* success */
+ #define E_NOPERM 1 /* permission denied */
+ #define E_USAGE 2 /* invalid command syntax */
++#define E_BAD_ARG 3 /* invalid argument to option */
+ #define E_FAILURE 3 /* unexpected failure, nothing done */
+ #define E_MISSING 4 /* unexpected failure, passwd file missing */
+ #define E_PWDBUSY 5 /* passwd file(s) busy */
+@@ -90,9 +92,12 @@
+
+ static bool spw_locked = false;
+ static bool pw_locked = false;
++static const char *newroot = "";
+
+ /* local function prototypes */
+ static void fail_exit (int status);
++static void usage (void);
++static void process_flags (int argc, char **argv);
+
+ static void fail_exit (int status)
+ {
+@@ -115,6 +120,77 @@
+ exit (status);
+ }
+
++/*
++ * usage - display usage message and exit
++ */
++static void usage (void)
++{
++ (void) fprintf (stderr,
++ _("Usage: pwconv [options]\n"
++ "\n"
++ "Options:\n"),
++ Prog);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
++ (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), stderr);
++ (void) fputs ("\n", stderr);
++ exit (E_USAGE);
++}
++
++/*
++ * process_flags - perform command line argument setting
++ *
++ * process_flags() interprets the command line arguments and sets
++ * the values that the user will be created with accordingly. The
++ * values are checked for sanity.
++ */
++static void process_flags (int argc, char **argv)
++{
++ {
++ /*
++ * Parse the command line options.
++ */
++ int c;
++ static struct option long_options[] = {
++ {"help", no_argument, NULL, 'h'},
++ {"root", required_argument, NULL, 'R'},
++ {NULL, 0, NULL, '\0'}
++ };
++ while ((c = getopt_long (argc, argv,
++ "R:",
++ long_options, NULL)) != -1) {
++ switch (c) {
++ case 'h':
++ usage ();
++ break;
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
++ default:
++ usage ();
++ }
++ }
++ }
++}
++
+ int main (int argc, char **argv)
+ {
+ const struct passwd *pw;
+@@ -122,9 +198,6 @@
+ const struct spwd *sp;
+ struct spwd spent;
+
+- if (1 != argc) {
+- (void) fputs (_("Usage: pwconv\n"), stderr);
+- }
+ Prog = Basename (argv[0]);
+
+ (void) setlocale (LC_ALL, "");
+@@ -133,6 +206,8 @@
+
+ OPENLOG ("pwconv");
+
++ process_flags (argc, argv);
++
+ if (pw_lock () == 0) {
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+diff -urN shadow-4.1.4.3.orig//src/pwunconv.c shadow-4.1.4.3//src/pwunconv.c
+--- shadow-4.1.4.3.orig//src/pwunconv.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/pwunconv.c 2011-05-28 17:09:52.356013600 -0700
+@@ -35,6 +35,7 @@
+ #ident "$Id: pwunconv.c 2852 2009-04-30 21:44:35Z nekral-guest $"
+
+ #include <fcntl.h>
++#include <getopt.h>
+ #include <pwd.h>
+ #include <stdio.h>
+ #include <sys/types.h>
+@@ -46,15 +47,24 @@
+ #include "shadowio.h"
+
+ /*
++ * exit status values
++ */
++/*@-exitarg@*/
++#define E_USAGE 2 /* invalid command syntax */
++#define E_BAD_ARG 3 /* invalid argument to option */
++/*
+ * Global variables
+ */
+ char *Prog;
+
+ static bool spw_locked = false;
+ static bool pw_locked = false;
++static const char *newroot = "";
+
+ /* local function prototypes */
+ static void fail_exit (int status);
++static void usage (void);
++static void process_flags (int argc, char **argv);
+
+ static void fail_exit (int status)
+ {
+@@ -75,6 +85,76 @@
+ exit (status);
+ }
+
++/*
++ * usage - display usage message and exit
++ */
++static void usage (void)
++{
++ (void) fprintf (stderr,
++ _("Usage: pwunconv [options]\n"
++ "\n"
++ "Options:\n"),
++ Prog);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
++ (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), stderr);
++ (void) fputs ("\n", stderr);
++ exit (E_USAGE);
++}
++
++/*
++ * process_flags - perform command line argument setting
++ *
++ * process_flags() interprets the command line arguments and sets
++ * the values that the user will be created with accordingly. The
++ * values are checked for sanity.
++ */
++static void process_flags (int argc, char **argv)
++{
++ {
++ /*
++ * Parse the command line options.
++ */
++ int c;
++ static struct option long_options[] = {
++ {"help", no_argument, NULL, 'h'},
++ {"root", required_argument, NULL, 'R'},
++ {NULL, 0, NULL, '\0'}
++ };
++ while ((c = getopt_long (argc, argv,
++ "R:",
++ long_options, NULL)) != -1) {
++ switch (c) {
++ case 'h':
++ usage ();
++ break;
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
++ default:
++ usage ();
++ }
++ }
++ }
++}
+
+ int main (int argc, char **argv)
+ {
+@@ -93,6 +173,8 @@
+
+ OPENLOG ("pwunconv");
+
++ process_flags (argc, argv);
++
+ if (!spw_file_present ()) {
+ /* shadow not installed, do nothing */
+ exit (0);
+diff -urN shadow-4.1.4.3.orig//src/useradd.c shadow-4.1.4.3//src/useradd.c
+--- shadow-4.1.4.3.orig//src/useradd.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/useradd.c 2011-05-28 17:10:25.446909971 -0700
+@@ -112,6 +112,7 @@
+ #ifdef WITH_SELINUX
+ static const char *user_selinux = "";
+ #endif
++static const char *newroot = "";
+
+ static long user_expire = -1;
+ static bool is_shadow_pwd;
+@@ -189,6 +190,7 @@
+ static void new_spent (struct spwd *);
+ static void grp_update (void);
+
++static void process_root_flag (int argc, char **argv);
+ static void process_flags (int argc, char **argv);
+ static void close_files (void);
+ static void open_files (void);
+@@ -711,6 +713,7 @@
+ (void) fputs (_(" -o, --non-unique allow to create users with duplicate\n"
+ " (non-unique) UID\n"), stderr);
+ (void) fputs (_(" -p, --password PASSWORD encrypted password of the new account\n"), stderr);
++ (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), stderr);
+ (void) fputs (_(" -r, --system create a system account\n"), stderr);
+ (void) fputs (_(" -s, --shell SHELL login shell of the new account\n"), stderr);
+ (void) fputs (_(" -u, --uid UID user ID of the new account\n"), stderr);
+@@ -943,6 +946,59 @@
+ }
+
+ /*
++ * process_root_flag - chroot if given the --root option
++ *
++ * We do this outside of process_flags() because
++ * the is_shadow_pwd boolean needs to be set before
++ * process_flags(), and if we do need to chroot() we
++ * must do so before is_shadow_pwd gets set.
++ */
++static void process_root_flag (int argc, char **argv)
++{
++ /*
++ * Parse the command line options.
++ */
++ int c;
++ static struct option long_options[] = {
++ {"root", required_argument, NULL, 'R'},
++ {NULL, 0, NULL, '\0'}
++ };
++ while ((c = getopt_long (argc, argv,
++#ifdef WITH_SELINUX
++ "b:c:d:De:f:g:G:k:K:lmMNop:R:rs:u:UZ:",
++#else
++ "b:c:d:De:f:g:G:k:K:lmMNop:R:rs:u:U",
++#endif
++ long_options, NULL)) != -1) {
++ switch (c) {
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
++ /* no-op on everything else - they will be hanled by process_flags() */
++ }
++ }
++}
++
++/*
+ * process_flags - perform command line argument setting
+ *
+ * process_flags() interprets the command line arguments and sets
+@@ -978,6 +1034,7 @@
+ {"no-user-group", no_argument, NULL, 'N'},
+ {"non-unique", no_argument, NULL, 'o'},
+ {"password", required_argument, NULL, 'p'},
++ {"root", required_argument, NULL, 'R'},
+ {"system", no_argument, NULL, 'r'},
+ {"shell", required_argument, NULL, 's'},
+ #ifdef WITH_SELINUX
+@@ -989,9 +1046,9 @@
+ };
+ while ((c = getopt_long (argc, argv,
+ #ifdef WITH_SELINUX
+- "b:c:d:De:f:g:G:k:K:lmMNop:rs:u:UZ:",
++ "b:c:d:De:f:g:G:k:K:lmMNop:R:rs:u:UZ:",
+ #else
+- "b:c:d:De:f:g:G:k:K:lmMNop:rs:u:U",
++ "b:c:d:De:f:g:G:k:K:lmMNop:R:rs:u:U",
+ #endif
+ long_options, NULL)) != -1) {
+ switch (c) {
+@@ -1156,6 +1213,9 @@
+ }
+ user_pass = optarg;
+ break;
++ case 'R':
++ /* no-op since we handled this in process_root_flag() earlier */
++ break;
+ case 'r':
+ rflg = true;
+ break;
+@@ -1748,8 +1808,16 @@
+ #ifdef WITH_SELINUX
+ selinux_file_context (user_home);
+ #endif
+- /* XXX - create missing parent directories. --marekm */
+- if (mkdir (user_home, 0) != 0) {
++ /* shell out to invoke mkdir -p
++ * creating a subshell under pseudo's chroot() breaks the jail
++ * (bug in pseudo), so make sure we include the full host path
++ * to the sysroot when the --root option is in use.
++ */
++ int sysroot_path_len = strlen(newroot);
++ int home_path_len = strlen(user_home);
++ char cmd[sysroot_path_len + home_path_len + 10];
++ sprintf(cmd, "mkdir -p %s%s", newroot, user_home);
++ if (system (cmd) != 0) {
+ fprintf (stderr,
+ _("%s: cannot create directory %s\n"),
+ Prog, user_home);
+@@ -1861,6 +1929,7 @@
+ */
+ user_groups[0] = (char *) 0;
+
++ process_root_flag (argc, argv);
+
+ is_shadow_pwd = spw_file_present ();
+ #ifdef SHADOWGRP
+diff -urN shadow-4.1.4.3.orig//src/userdel.c shadow-4.1.4.3//src/userdel.c
+--- shadow-4.1.4.3.orig//src/userdel.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/userdel.c 2011-05-28 17:09:52.356013600 -0700
+@@ -79,6 +79,7 @@
+ static char *user_name;
+ static uid_t user_id;
+ static char *user_home;
++static const char *newroot = "";
+
+ static bool fflg = false;
+ static bool rflg = false;
+@@ -119,6 +120,7 @@
+ " -f, --force force removal of files,\n"
+ " even if not owned by user\n"
+ " -h, --help display this help message and exit\n"
++ " -R, --root CHROOT_DIR directory to chroot into\n"
+ " -r, --remove remove home directory and mail spool\n"
+ "\n"), stderr);
+ exit (E_USAGE);
+@@ -768,12 +770,34 @@
+ {"remove", no_argument, NULL, 'r'},
+ {NULL, 0, NULL, '\0'}
+ };
+- while ((c = getopt_long (argc, argv, "fhr",
++ while ((c = getopt_long (argc, argv, "fhR:r",
+ long_options, NULL)) != -1) {
+ switch (c) {
+ case 'f': /* force remove even if not owned by user */
+ fflg = true;
+ break;
++ case 'R':
++ if ('/' != optarg[0]) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
+ case 'r': /* remove home dir and mailbox */
+ rflg = true;
+ break;
+diff -urN shadow-4.1.4.3.orig//src/usermod.c shadow-4.1.4.3//src/usermod.c
+--- shadow-4.1.4.3.orig//src/usermod.c 2011-02-13 09:58:16.000000000 -0800
++++ shadow-4.1.4.3//src/usermod.c 2011-05-28 17:09:52.356013600 -0700
+@@ -110,6 +110,7 @@
+ static long user_newinactive;
+ static long sys_ngroups;
+ static char **user_groups; /* NULL-terminated list */
++static const char *newroot = "";
+
+ static bool
+ aflg = false, /* append to existing secondary group set */
+@@ -164,6 +165,7 @@
+ #endif
+ static void grp_update (void);
+
++static void process_root_flag (int, char **);
+ static void process_flags (int, char **);
+ static void close_files (void);
+ static void open_files (void);
+@@ -323,6 +325,7 @@
+ " new location (use only with -d)\n"
+ " -o, --non-unique allow using duplicate (non-unique) UID\n"
+ " -p, --password PASSWORD use encrypted password for the new password\n"
++ " -R --root CHROOT_DIR directory to chroot into\n"
+ " -s, --shell SHELL new login shell for the user account\n"
+ " -u, --uid UID new UID for the user account\n"
+ " -U, --unlock unlock the user account\n"
+@@ -802,6 +805,60 @@
+ }
+
+ /*
++ * process_root_flag - chroot if given the --root option
++ *
++ * We do this outside of process_flags() because
++ * the is_shadow_pwd boolean needs to be set before
++ * process_flags(), and if we do need to chroot() we
++ * must do so before is_shadow_pwd gets set.
++ */
++static void process_root_flag (int argc, char **argv)
++{
++ /*
++ * Parse the command line options.
++ */
++ int c;
++ static struct option long_options[] = {
++ {"root", required_argument, NULL, 'R'},
++ {NULL, 0, NULL, '\0'}
++ };
++ while ((c = getopt_long (argc, argv,
++#ifdef WITH_SELINUX
++ "ac:d:e:f:g:G:hl:Lmop:R:s:u:UZ:",
++#else
++ "ac:d:e:f:g:G:hl:Lmop:R:s:u:U",
++#endif
++ long_options, NULL)) != -1) {
++ switch (c) {
++ case 'R':
++ if ( (!VALID (optarg) )
++ || ( ('/' != optarg[0]) ) ) {
++ fprintf (stderr,
++ _("%s: invalid chroot path '%s'\n"),
++ Prog, optarg);
++ exit (E_BAD_ARG);
++ }
++ newroot = optarg;
++
++ if (access (newroot, F_OK) != 0) {
++ fprintf(stderr,
++ _("%s: chroot directory %s does not exist\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ if ( chroot(newroot) != 0 ) {
++ fprintf(stderr,
++ _("%s: unable to chroot to directory %s\n"),
++ Prog, newroot);
++ exit (E_BAD_ARG);
++ }
++ break;
++ /* no-op on everything else - they will be hanled by process_flags() */
++ }
++ }
++}
++
++/*
+ * process_flags - perform command line argument setting
+ *
+ * process_flags() interprets the command line arguments and sets the
+@@ -895,6 +952,7 @@
+ {"move-home", no_argument, NULL, 'm'},
+ {"non-unique", no_argument, NULL, 'o'},
+ {"password", required_argument, NULL, 'p'},
++ {"root", required_argument, NULL, 'R'},
+ #ifdef WITH_SELINUX
+ {"selinux-user", required_argument, NULL, 'Z'},
+ #endif
+@@ -905,9 +963,9 @@
+ };
+ while ((c = getopt_long (argc, argv,
+ #ifdef WITH_SELINUX
+- "ac:d:e:f:g:G:hl:Lmop:s:u:UZ:",
++ "ac:d:e:f:g:G:hl:Lmop:R:s:u:UZ:",
+ #else
+- "ac:d:e:f:g:G:hl:Lmop:s:u:U",
++ "ac:d:e:f:g:G:hl:Lmop:R:s:u:U",
+ #endif
+ long_options, NULL)) != -1) {
+ switch (c) {
+@@ -999,6 +1057,9 @@
+ user_pass = optarg;
+ pflg = true;
+ break;
++ case 'R':
++ /* no-op since we handled this in process_root_flag() earlier */
++ break;
+ case 's':
+ if (!VALID (optarg)) {
+ fprintf (stderr,
+@@ -1715,6 +1776,8 @@
+
+ OPENLOG ("usermod");
+
++ process_root_flag (argc, argv);
++
+ is_shadow_pwd = spw_file_present ();
+ #ifdef SHADOWGRP
+ is_shadow_grp = sgr_file_present ();