diff options
| author | Scott Garman <scott.a.garman@intel.com> | 2011-05-09 23:02:39 -0700 | 
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2011-06-06 15:52:18 +0100 | 
| commit | 37b8c18a3c2f3e77a9810a56a8ee786855ae1ba3 (patch) | |
| tree | 987e849cfdb31913f08469021d16b5a2b0cc4a61 | |
| parent | 254ca8c1667b8d35914555714239a09bfb4f43be (diff) | |
| download | openembedded-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>
| -rw-r--r-- | meta/recipes-extended/shadow/files/add_root_cmd_options.patch | 1296 | ||||
| -rw-r--r-- | meta/recipes-extended/shadow/shadow-native_4.1.4.3.bb | 66 | 
2 files changed, 1362 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 (); diff --git a/meta/recipes-extended/shadow/shadow-native_4.1.4.3.bb b/meta/recipes-extended/shadow/shadow-native_4.1.4.3.bb new file mode 100644 index 0000000000..2f93e051ba --- /dev/null +++ b/meta/recipes-extended/shadow/shadow-native_4.1.4.3.bb @@ -0,0 +1,66 @@ +SUMMARY = "Tools to change and administer password and group data" +DESCRIPTION = "Tools to change and administer password and group data" +HOMEPAGE = "http://pkg-shadow.alioth.debian.org" +BUGTRACKER = "https://alioth.debian.org/tracker/?group_id=30580" +SECTION = "base utils" +PRIORITY = "optional" +LICENSE = "BSD | Artistic" +LIC_FILES_CHKSUM = "file://COPYING;md5=08c553a87d4e51bbed50b20e0adcaede \ +                    file://src/passwd.c;firstline=8;endline=30;md5=2899a045e90511d0e043b85a7db7e2fe" + +PR = "r0" + +SRC_URI = "ftp://pkg-shadow.alioth.debian.org/pub/pkg-shadow/shadow-${PV}.tar.bz2 \ +           file://shadow.automake-1.11.patch \ +           file://shadow-4.1.3-dots-in-usernames.patch \ +           file://shadow-4.1.4.2-env-reset-keep-locale.patch \ +           file://add_root_cmd_options.patch" + +SRC_URI[md5sum] = "b8608d8294ac88974f27b20f991c0e79" +SRC_URI[sha256sum] = "633f5bb4ea0c88c55f3642c97f9d25cbef74f82e0b4cf8d54e7ad6f9f9caa778"  + +inherit autotools gettext native + +EXTRA_OECONF += "--without-audit \ +                 --without-libcrack \ +                 --without-libpam \ +                 --without-selinux" + +do_install_append() { +	# Enable CREATE_HOME by default. +	sed -i 's/#CREATE_HOME/CREATE_HOME/g' ${D}${sysconfdir}/login.defs + +	# As we are on an embedded system, ensure the users mailbox is in +	# ~/ not /var/spool/mail by default, as who knows where or how big +	# /var is. The system MDA will set this later anyway. +	sed -i 's/MAIL_DIR/#MAIL_DIR/g' ${D}${sysconfdir}/login.defs +	sed -i 's/#MAIL_FILE/MAIL_FILE/g' ${D}${sysconfdir}/login.defs + +	# Disable checking emails. +	sed -i 's/MAIL_CHECK_ENAB/#MAIL_CHECK_ENAB/g' ${D}${sysconfdir}/login.defs + +	# Now we don't have a mail system. Disable mail creation for now. +	sed -i 's:/bin/bash:/bin/sh:g' ${D}${sysconfdir}/default/useradd +	sed -i '/^CREATE_MAIL_SPOOL/ s:^:#:' ${D}${sysconfdir}/default/useradd + +	install -d ${D}${sbindir} ${D}${base_sbindir} ${D}${base_bindir}  +	for i in passwd chfn newgrp chsh ; do +		mv ${D}${bindir}/$i ${D}${bindir}/$i.${PN} +	done + +	mv ${D}${sbindir}/chpasswd ${D}${sbindir}/chpasswd.${PN} +} + +pkg_postinst_${PN} () { +	update-alternatives --install ${bindir}/passwd passwd passwd.${PN} 200 +	update-alternatives --install ${sbindir}/chpasswd chpasswd chpasswd.${PN} 200 +	update-alternatives --install ${bindir}/chfn chfn chfn.${PN} 200 +	update-alternatives --install ${bindir}/newgrp newgrp newgrp.${PN} 200 +	update-alternatives --install ${bindir}/chsh chsh chsh.${PN} 200 +} + +pkg_prerm_${PN} () { +	for i in passwd chpasswd chfn newgrp chsh ; do +		update-alternatives --remove $i $i.${PN} +	done +} | 
