Patchwork [2/7] shadow: add a -native recipe with customized utilities

login
register
mail settings
Submitter Scott Garman
Date June 2, 2011, 11:50 p.m.
Message ID <e298a5a0c4b2d7fb5ee8fc947a862d4ea24438f5.1307058256.git.scott.a.garman@intel.com>
Download mbox | patch
Permalink /patch/5359/
State New, archived
Headers show

Comments

Scott Garman - June 2, 2011, 11:50 p.m.
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>
---
 .../shadow/files/add_root_cmd_options.patch        | 1296 ++++++++++++++++++++
 .../shadow/shadow-native_4.1.4.3.bb                |   66 +
 2 files changed, 1362 insertions(+), 0 deletions(-)
 create mode 100644 meta/recipes-extended/shadow/files/add_root_cmd_options.patch
 create mode 100644 meta/recipes-extended/shadow/shadow-native_4.1.4.3.bb

Patch

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 0000000..db969bb
--- /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 0000000..2f93e05
--- /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
+}