diff options
Diffstat (limited to 'meta/recipes-extended/shadow/files')
-rw-r--r-- | meta/recipes-extended/shadow/files/add_root_cmd_options.patch | 1296 |
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 (); |