On 02/16/2010 10:04 AM, P. Levine wrote:
> Attached is a tentative patch to add a chroot flag to useradd and
> groupadd (via --chroot or -R).

Sorry, wrong patch.

I've attached the correct one.

-- Peter Levine



diff -Naur shadow-4.1.4.2.old/config.h.in shadow-4.1.4.2/config.h.in
--- shadow-4.1.4.2.old/config.h.in	2009-07-23 21:15:58.000000000 -0400
+++ shadow-4.1.4.2/config.h.in	2010-02-16 07:19:48.000000000 -0500
@@ -68,6 +68,12 @@
 /* Define to 1 if you have the <fcntl.h> header file. */
 #undef HAVE_FCNTL_H
 
+/* Define to 1 if you have the `fgetgrent_r' function. */
+#undef HAVE_FGETGRENT_R
+
+/* Define to 1 if you have the `fgetpwent_r' function. */
+#undef HAVE_FGETPWENT_R
+
 /* Define to 1 if you have the `fsync' function. */
 #undef HAVE_FSYNC
 
diff -Naur shadow-4.1.4.2.old/configure shadow-4.1.4.2/configure
--- shadow-4.1.4.2.old/configure	2009-07-23 21:15:56.000000000 -0400
+++ shadow-4.1.4.2/configure	2010-02-16 07:19:48.000000000 -0500
@@ -13536,7 +13536,8 @@
 for ac_func in l64a fchmod fchown fsync futimes getgroups gethostname getspnam \
 	gettimeofday getusershell getutent initgroups lchown lckpwdf lstat \
 	lutimes memcpy memset setgroups sigaction strchr updwtmp updwtmpx innetgr \
-	getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo
+	fgetpwent_r fgetgrent_r getpwnam_r getpwuid_r getgrnam_r getgrgid_r \
+	getspnam_r getaddrinfo
 do
 as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
diff -Naur shadow-4.1.4.2.old/configure.in shadow-4.1.4.2/configure.in
--- shadow-4.1.4.2.old/configure.in	2009-07-23 21:10:31.000000000 -0400
+++ shadow-4.1.4.2/configure.in	2010-02-16 07:19:48.000000000 -0500
@@ -41,7 +41,8 @@
 AC_CHECK_FUNCS(l64a fchmod fchown fsync futimes getgroups gethostname getspnam \
 	gettimeofday getusershell getutent initgroups lchown lckpwdf lstat \
 	lutimes memcpy memset setgroups sigaction strchr updwtmp updwtmpx innetgr \
-	getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo)
+	fgetpwent_r fgetgrent_r getpwnam_r getpwuid_r getgrnam_r getgrgid_r \
+	getspnam_r getaddrinfo)
 AC_SYS_LARGEFILE
 
 dnl Checks for typedefs, structures, and compiler characteristics.
diff -Naur shadow-4.1.4.2.old/lib/prototypes.h shadow-4.1.4.2/lib/prototypes.h
--- shadow-4.1.4.2.old/lib/prototypes.h	2009-05-18 14:32:21.000000000 -0400
+++ shadow-4.1.4.2/lib/prototypes.h	2010-02-16 07:19:48.000000000 -0500
@@ -154,6 +154,7 @@
 
 /* getgr_nam_gid.c */
 extern /*...@null@*/struct group *getgr_nam_gid (const char *grname);
+extern /*...@null@*/struct group *fgetgr_nam_gid (const char *grname);
 
 /* getlong.c */
 extern int getlong (const char *numstr, /*...@out@*/long int *result);
@@ -400,6 +401,15 @@
 /* xgetspnam.c */
 extern /*...@null@*/ /*...@only@*/struct spwd *xgetspnam(const char *);
 
+/* xfgetpwnam.c */
+extern /*...@null@*/ /*...@only@*/struct passwd *xfgetpwnam (const char *);
+/* xfgetpwuid.c */
+extern /*...@null@*/ /*...@only@*/struct passwd *xfgetpwuid (uid_t);
+/* xfgetgrnam.c */
+extern /*...@null@*/ /*...@only@*/struct group *xfgetgrnam (const char *);
+/* xfgetgrgid.c */
+extern /*...@null@*/ /*...@only@*/struct group *xfgetgrgid (gid_t);
+
 /* yesno.c */
 extern bool yes_or_no (bool read_only);
 
diff -Naur shadow-4.1.4.2.old/libmisc/Makefile.am shadow-4.1.4.2/libmisc/Makefile.am
--- shadow-4.1.4.2.old/libmisc/Makefile.am	2009-05-17 14:39:06.000000000 -0400
+++ shadow-4.1.4.2/libmisc/Makefile.am	2010-02-16 07:19:48.000000000 -0500
@@ -1,5 +1,5 @@
 
-EXTRA_DIST = .indent.pro xgetXXbyYY.c
+EXTRA_DIST = .indent.pro xgetXXbyYY.c xfgetXXbyYY.c
 
 INCLUDES = -I$(top_srcdir)/lib
 
@@ -59,6 +59,10 @@
 	user_busy.c \
 	utmp.c \
 	valid.c \
+	xfgetpwnam.c \
+	xfgetpwuid.c \
+	xfgetgrnam.c \
+	xfgetgrgid.c \
 	xgetpwnam.c \
 	xgetpwuid.c \
 	xgetgrnam.c \
diff -Naur shadow-4.1.4.2.old/libmisc/Makefile.in shadow-4.1.4.2/libmisc/Makefile.in
--- shadow-4.1.4.2.old/libmisc/Makefile.in	2009-07-23 21:15:59.000000000 -0400
+++ shadow-4.1.4.2/libmisc/Makefile.in	2010-02-16 07:19:48.000000000 -0500
@@ -64,9 +64,10 @@
 	shell.$(OBJEXT) system.$(OBJEXT) strtoday.$(OBJEXT) \
 	sub.$(OBJEXT) sulog.$(OBJEXT) ttytype.$(OBJEXT) tz.$(OBJEXT) \
 	ulimit.$(OBJEXT) user_busy.$(OBJEXT) utmp.$(OBJEXT) \
-	valid.$(OBJEXT) xgetpwnam.$(OBJEXT) xgetpwuid.$(OBJEXT) \
-	xgetgrnam.$(OBJEXT) xgetgrgid.$(OBJEXT) xgetspnam.$(OBJEXT) \
-	xmalloc.$(OBJEXT) yesno.$(OBJEXT)
+	valid.$(OBJEXT) xfgetpwnam.$(OBJEXT) xfgetpwuid.$(OBJEXT) \
+	xfgetgrnam.$(OBJEXT) xfgetgrgid.$(OBJEXT) xgetpwnam.$(OBJEXT) \
+	xgetpwuid.$(OBJEXT) xgetgrnam.$(OBJEXT) xgetgrgid.$(OBJEXT) \
+	xgetspnam.$(OBJEXT) xmalloc.$(OBJEXT) yesno.$(OBJEXT)
 libmisc_a_OBJECTS = $(am_libmisc_a_OBJECTS)
 DEFAULT_INCLUDES = -...@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
@@ -232,7 +233,7 @@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-EXTRA_DIST = .indent.pro xgetXXbyYY.c
+EXTRA_DIST = .indent.pro xgetXXbyYY.c xfgetXXbyYY.c
 INCLUDES = -I$(top_srcdir)/lib
 noinst_LIBRARIES = libmisc.a
 libmisc_a_SOURCES = \
@@ -289,6 +290,10 @@
 	user_busy.c \
 	utmp.c \
 	valid.c \
+	xfgetpwnam.c \
+	xfgetpwuid.c \
+	xfgetgrnam.c \
+	xfgetgrgid.c \
 	xgetpwnam.c \
 	xgetpwuid.c \
 	xgetgrnam.c \
@@ -395,6 +400,10 @@
 @AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/user_busy...@am__quote@
 @AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/utmp...@am__quote@
 @AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/valid...@am__quote@
+...@amdep_true@@am__include@ @am__qu...@./$(DEPDIR)/xfgetgrgid...@am__quote@
+...@amdep_true@@am__include@ @am__qu...@./$(DEPDIR)/xfgetgrnam...@am__quote@
+...@amdep_true@@am__include@ @am__qu...@./$(DEPDIR)/xfgetpwnam...@am__quote@
+...@amdep_true@@am__include@ @am__qu...@./$(DEPDIR)/xfgetpwuid...@am__quote@
 @AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/xgetgrgid...@am__quote@
 @AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/xgetgrnam...@am__quote@
 @AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/xgetpwnam...@am__quote@
diff -Naur shadow-4.1.4.2.old/libmisc/getgr_nam_gid.c shadow-4.1.4.2/libmisc/getgr_nam_gid.c
--- shadow-4.1.4.2.old/libmisc/getgr_nam_gid.c	2009-04-29 09:50:14.000000000 -0400
+++ shadow-4.1.4.2/libmisc/getgr_nam_gid.c	2010-02-16 07:19:48.000000000 -0500
@@ -64,3 +64,29 @@
 	return xgetgrnam (grname);
 }
 
+/*
+ * fgetgr_nam_gid - Return a pointer to the group specified by a string
+ * using recursive calls to fgetgrent.
+ * The string may be a valid GID or a valid groupname.
+ * If the group does not exist on the system, NULL is returned.
+ */
+extern /*...@null@*/struct group *fgetgr_nam_gid (const char *grname)
+{
+	long long int gid;
+	char *endptr;
+
+	if (NULL == grname) {
+		return NULL;
+	}
+
+	errno = 0;
+	gid = strtoll (grname, &endptr, 10);
+	if (   ('\0' != *grname)
+	    && ('\0' == *endptr)
+	    && (ERANGE != errno)
+	    && (/*...@+longintegral@*/gid == (gid_t)gid)/*...@=longintegral@*/) {
+		return xfgetgrgid ((gid_t) gid);
+	}
+	return xfgetgrnam (grname);
+}
+
diff -Naur shadow-4.1.4.2.old/libmisc/xfgetXXbyYY.c shadow-4.1.4.2/libmisc/xfgetXXbyYY.c
--- shadow-4.1.4.2.old/libmisc/xfgetXXbyYY.c	1969-12-31 19:00:00.000000000 -0500
+++ shadow-4.1.4.2/libmisc/xfgetXXbyYY.c	2010-02-16 07:19:48.000000000 -0500
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2007 - 2009, Nicolas François
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the copyright holders or contributors may not be used to
+ *    endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * According to the Linux-PAM documentation:
+ *
+ *  4.1. Care about standard library calls
+ *
+ *  In general, writers of authorization-granting applications should
+ *  assume that each module is likely to call any or all 'libc' functions.
+ *  For 'libc' functions that return pointers to static/dynamically
+ *  allocated structures (ie.  the library allocates the memory and the
+ *  user is not expected to 'free()' it) any module call to this function
+ *  is likely to corrupt a pointer previously obtained by the application.
+ *  The application programmer should either re-call such a 'libc'
+ *  function after a call to the Linux-PAM library, or copy the structure
+ *  contents to some safe area of memory before passing control to the
+ *  Linux-PAM library.
+ *
+ *  Two important function classes that fall into this category are
+ *  getpwnam(3) and syslog(3).
+ *
+ * This file provide wrapper to the getpwnam or getpwnam_r functions.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "prototypes.h"
+
+#define F_FUNCTION_NAME	F_FUNCTION_NAME1 (DB_TYPE)
+#define F_FUNCTION_NAME1(name) F_FUNCTION_NAME2 (name)
+#define F_FUNCTION_NAME2(name) fget##name##ent
+#define F_COMPARE F_COMPARE1 (DB_TYPE,ARG_NAME)
+#define F_COMPARE1(name1,name2) F_COMPARE2 (name1,name2)
+#define F_COMPARE2(name1,name2) F_COMPARE3 (name1 ## _ ## name2,name2)
+#define F_COMPARE3(name1,name2) F_COMPARE_## name2 (result->name1,name2)
+#define F_COMPARE_gid	F_COMPARE_num
+#define F_COMPARE_uid	F_COMPARE_num
+#define F_COMPARE_namp	F_COMPARE_str
+#define F_COMPARE_name	F_COMPARE_str
+#define F_COMPARE_num(name1,name2)	(name1 == name2)
+#define F_COMPARE_str(name1,name2)	(!strcmp(name1,name2))
+
+#define XFUNCTION_NAME XPREFIX (FUNCTION_NAME)
+#define XPREFIX(name) XPREFIX1 (name)
+#define XPREFIX1(name) x##name
+#define REENTRANT_NAME APPEND_R (F_FUNCTION_NAME)
+#define APPEND_R(name) APPEND_R1 (name)
+#define APPEND_R1(name) name##_r
+#define STRINGIZE(name) STRINGIZE1 (name)
+#define STRINGIZE1(name) #name
+
+/*...@null@*/ /*...@only@*/LOOKUP_TYPE *XFUNCTION_NAME (ARG_TYPE ARG_NAME)
+{
+	FILE *stream = NULL;
+	if ((stream = fopen (DB_FILE, "r")) == NULL) {
+		fprintf (stderr, _("%s: Error opening the database file.\n"),
+		         "x" STRINGIZE(FUNCTION_NAME));
+		exit (1);
+	}
+#if HAVE_FUNCTION_R
+	LOOKUP_TYPE *result=NULL;
+	char *buffer=NULL;
+	/* we have to start with something */
+	size_t length = 0x100;
+
+	result = malloc(sizeof(LOOKUP_TYPE));
+	if (NULL == result) {
+		fprintf (stderr, _("%s: out of memory\n"),
+		         "x" STRINGIZE(FUNCTION_NAME));
+		exit (13);
+	}
+
+	while (true) {
+		int status;
+		LOOKUP_TYPE *resbuf = NULL;
+		buffer = (char *)realloc (buffer, length);
+		if (NULL == buffer) {
+			fprintf (stderr, _("%s: out of memory\n"),
+			         "x" STRINGIZE(FUNCTION_NAME));
+			exit (13);
+		}
+		errno = 0;
+		status = REENTRANT_NAME(stream, result, buffer,
+	                        length, &resbuf);
+		while ((0 ==status) && (resbuf == result)) {
+			if (F_COMPARE) {
+				/* Build a result structure that can be freed by
+				 * the shadow *_free functions. */
+				LOOKUP_TYPE *ret_result = DUP_FUNCTION(result);
+				(void) fclose (stream);
+				free(buffer);
+				free(result);
+				return ret_result;
+			} else {
+				status = REENTRANT_NAME(stream, result, buffer,
+		                	        length, &resbuf);
+			}
+		}
+
+		if (ERANGE != errno) {
+			(void) fclose (stream);
+			free (buffer);
+			free (result);
+			return NULL;
+		}
+
+		if (length <= ((size_t)-1 / 4)) {
+			length *= 4;
+		} else if (length == (size_t) -1) {
+			break;
+		} else {
+			length = (size_t) -1;
+		}
+	}
+
+	(void) fclose (stream);
+	free(buffer);
+	free(result);
+	return NULL;
+
+#else /* !HAVE_FUNCTION_R */
+
+	/* No reentrant function.
+	 * Duplicate the structure to avoid other call to overwrite it.
+	 *
+	 * We should also restore the initial structure. But that would be
+	 * overkill.
+	 */
+	LOOKUP_TYPE *result = F_FUNCTION_NAME(stream);
+
+	while (result) {
+		if (F_COMPARE) {
+			result = DUP_FUNCTION(result);
+			if (NULL == result) {
+				fprintf (stderr, _("%s: out of memory\n"),
+				         "x" STRINGIZE(FUNCTION_NAME));
+				exit (13);
+			}
+			break;
+		} else {
+			result = F_FUNCTION_NAME(stream);
+		}
+	}
+
+	(void) fclose (stream);
+	return result;
+#endif
+}
+
diff -Naur shadow-4.1.4.2.old/libmisc/xfgetgrgid.c shadow-4.1.4.2/libmisc/xfgetgrgid.c
--- shadow-4.1.4.2.old/libmisc/xfgetgrgid.c	1969-12-31 19:00:00.000000000 -0500
+++ shadow-4.1.4.2/libmisc/xfgetgrgid.c	2010-02-16 07:19:48.000000000 -0500
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007 - 2009, Nicolas François
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the copyright holders or contributors may not be used to
+ *    endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * According to the Linux-PAM documentation:
+ *
+ *  4.1. Care about standard library calls
+ *
+ *  In general, writers of authorization-granting applications should
+ *  assume that each module is likely to call any or all 'libc' functions.
+ *  For 'libc' functions that return pointers to static/dynamically
+ *  allocated structures (ie.  the library allocates the memory and the
+ *  user is not expected to 'free()' it) any module call to this function
+ *  is likely to corrupt a pointer previously obtained by the application.
+ *  The application programmer should either re-call such a 'libc'
+ *  function after a call to the Linux-PAM library, or copy the structure
+ *  contents to some safe area of memory before passing control to the
+ *  Linux-PAM library.
+ *
+ *  Two important function classes that fall into this category are
+ *  getpwnam(3) and syslog(3).
+ *
+ * This file provide wrapper to the getpwnam or getpwnam_r functions.
+ */
+
+#include <config.h>
+
+#include "groupio.h"
+
+#define LOOKUP_TYPE	struct group
+#define FUNCTION_NAME	fgetgrgid
+#define ARG_TYPE	gid_t
+#define ARG_NAME	gid
+#define DB_TYPE	gr
+#define DB_FILE GROUP_FILE
+#define DUP_FUNCTION	__gr_dup
+#define HAVE_FUNCTION_R (defined HAVE_FGETGRENT_R)
+
+#include "xfgetXXbyYY.c"
+
diff -Naur shadow-4.1.4.2.old/libmisc/xfgetgrnam.c shadow-4.1.4.2/libmisc/xfgetgrnam.c
--- shadow-4.1.4.2.old/libmisc/xfgetgrnam.c	1969-12-31 19:00:00.000000000 -0500
+++ shadow-4.1.4.2/libmisc/xfgetgrnam.c	2010-02-16 07:19:48.000000000 -0500
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007 - 2009, Nicolas François
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the copyright holders or contributors may not be used to
+ *    endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * According to the Linux-PAM documentation:
+ *
+ *  4.1. Care about standard library calls
+ *
+ *  In general, writers of authorization-granting applications should
+ *  assume that each module is likely to call any or all 'libc' functions.
+ *  For 'libc' functions that return pointers to static/dynamically
+ *  allocated structures (ie.  the library allocates the memory and the
+ *  user is not expected to 'free()' it) any module call to this function
+ *  is likely to corrupt a pointer previously obtained by the application.
+ *  The application programmer should either re-call such a 'libc'
+ *  function after a call to the Linux-PAM library, or copy the structure
+ *  contents to some safe area of memory before passing control to the
+ *  Linux-PAM library.
+ *
+ *  Two important function classes that fall into this category are
+ *  getpwnam(3) and syslog(3).
+ *
+ * This file provide wrapper to the getpwnam or getpwnam_r functions.
+ */
+
+#include <config.h>
+
+#include "groupio.h"
+
+#define LOOKUP_TYPE	struct group
+#define FUNCTION_NAME	fgetgrnam
+#define ARG_TYPE	const char *
+#define ARG_NAME	name
+#define DB_TYPE	gr
+#define DB_FILE	GROUP_FILE
+#define DUP_FUNCTION	__gr_dup
+#define HAVE_FUNCTION_R (defined HAVE_FGETGRENT_R)
+
+#include "xfgetXXbyYY.c"
+
diff -Naur shadow-4.1.4.2.old/libmisc/xfgetpwnam.c shadow-4.1.4.2/libmisc/xfgetpwnam.c
--- shadow-4.1.4.2.old/libmisc/xfgetpwnam.c	1969-12-31 19:00:00.000000000 -0500
+++ shadow-4.1.4.2/libmisc/xfgetpwnam.c	2010-02-16 07:19:48.000000000 -0500
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007 - 2009, Nicolas François
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the copyright holders or contributors may not be used to
+ *    endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * According to the Linux-PAM documentation:
+ *
+ *  4.1. Care about standard library calls
+ *
+ *  In general, writers of authorization-granting applications should
+ *  assume that each module is likely to call any or all 'libc' functions.
+ *  For 'libc' functions that return pointers to static/dynamically
+ *  allocated structures (ie.  the library allocates the memory and the
+ *  user is not expected to 'free()' it) any module call to this function
+ *  is likely to corrupt a pointer previously obtained by the application.
+ *  The application programmer should either re-call such a 'libc'
+ *  function after a call to the Linux-PAM library, or copy the structure
+ *  contents to some safe area of memory before passing control to the
+ *  Linux-PAM library.
+ *
+ *  Two important function classes that fall into this category are
+ *  getpwnam(3) and syslog(3).
+ *
+ * This file provide wrapper to the getpwnam or getpwnam_r functions.
+ */
+
+#include <config.h>
+
+#include "pwio.h"
+
+#define LOOKUP_TYPE	struct passwd
+#define FUNCTION_NAME	fgetpwnam
+#define ARG_TYPE	const char *
+#define ARG_NAME	name
+#define DB_TYPE	pw
+#define DB_FILE PASSWD_FILE
+#define DUP_FUNCTION	__pw_dup
+#define HAVE_FUNCTION_R (defined HAVE_FGETPWENT_R)
+
+#include "xfgetXXbyYY.c"
+
diff -Naur shadow-4.1.4.2.old/libmisc/xfgetpwuid.c shadow-4.1.4.2/libmisc/xfgetpwuid.c
--- shadow-4.1.4.2.old/libmisc/xfgetpwuid.c	1969-12-31 19:00:00.000000000 -0500
+++ shadow-4.1.4.2/libmisc/xfgetpwuid.c	2010-02-16 07:19:48.000000000 -0500
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007 - 2009, Nicolas François
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the copyright holders or contributors may not be used to
+ *    endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * According to the Linux-PAM documentation:
+ *
+ *  4.1. Care about standard library calls
+ *
+ *  In general, writers of authorization-granting applications should
+ *  assume that each module is likely to call any or all 'libc' functions.
+ *  For 'libc' functions that return pointers to static/dynamically
+ *  allocated structures (ie.  the library allocates the memory and the
+ *  user is not expected to 'free()' it) any module call to this function
+ *  is likely to corrupt a pointer previously obtained by the application.
+ *  The application programmer should either re-call such a 'libc'
+ *  function after a call to the Linux-PAM library, or copy the structure
+ *  contents to some safe area of memory before passing control to the
+ *  Linux-PAM library.
+ *
+ *  Two important function classes that fall into this category are
+ *  getpwnam(3) and syslog(3).
+ *
+ * This file provide wrapper to the getpwnam or getpwnam_r functions.
+ */
+
+#include <config.h>
+
+#include "pwio.h"
+
+#define LOOKUP_TYPE	struct passwd
+#define FUNCTION_NAME	fgetpwuid
+#define ARG_TYPE	uid_t
+#define ARG_NAME	uid
+#define DB_TYPE	pw
+#define DB_FILE PASSWD_FILE
+#define DUP_FUNCTION	__pw_dup
+#define HAVE_FUNCTION_R (defined HAVE_FGETPWENT_R)
+
+#include "xfgetXXbyYY.c"
+
diff -Naur shadow-4.1.4.2.old/man/groupadd.8 shadow-4.1.4.2/man/groupadd.8
--- shadow-4.1.4.2.old/man/groupadd.8	2009-07-23 21:16:24.000000000 -0400
+++ shadow-4.1.4.2/man/groupadd.8	2010-02-16 07:19:48.000000000 -0500
@@ -99,6 +99,18 @@
 login\&.defs, instead of
 \fBGID_MIN\fR\-\fBGID_MAX\fR\&.
 .RE
+.PP
+\fB\-R\fR, \fB\-\-chroot\fR \fIROOT_DIR\fR
+.RS 4
+Access files from a root directory other than /\&.
+.sp
+Instead of accessing or altering files from the usual directory, paths will be prefixed with
+\fBROOT_DIR\fR\&.
+.sp
+For instance, instead of adding a group to
+/etc/group, the group would be added to
+\fBROOT_DIR\fR/etc/group\&.
+.RE
 .SH "CONFIGURATION"
 .PP
 The following configuration variables in
diff -Naur shadow-4.1.4.2.old/man/groupadd.8.xml shadow-4.1.4.2/man/groupadd.8.xml
--- shadow-4.1.4.2.old/man/groupadd.8.xml	2009-05-21 08:02:13.000000000 -0400
+++ shadow-4.1.4.2/man/groupadd.8.xml	2010-02-16 07:19:48.000000000 -0500
@@ -179,6 +179,26 @@
 	  </para>
 	</listitem>
       </varlistentry>
+      <varlistentry>
+	<term>
+	  <option>-R</option>, <option>--chroot</option>
+	  <replaceable>ROOT_DIR</replaceable>
+	</term>
+	<listitem>
+	  <para>
+	    Access files from a root directory other than /.
+	  </para>
+	  <para>
+	    Instead of accessing or altering files from the usual directory,
+	    paths will be prefixed with <option>ROOT_DIR</option>.
+	  </para>
+	  <para>
+	    For instance, instead of adding a group to
+	    <filename>/etc/group</filename>, the group would be added to
+	    <filename><option>ROOT_DIR</option>/etc/group</filename>.
+	  </para>
+	</listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
diff -Naur shadow-4.1.4.2.old/man/useradd.8 shadow-4.1.4.2/man/useradd.8
--- shadow-4.1.4.2.old/man/useradd.8	2009-07-23 21:16:44.000000000 -0400
+++ shadow-4.1.4.2/man/useradd.8	2010-02-16 07:19:48.000000000 -0500
@@ -285,6 +285,18 @@
 options if you want a home directory for a system account to be created\&.
 .RE
 .PP
+\fB\-R\fR, \fB\-\-chroot\fR \fIROOT_DIR\fR
+.RS 4
+Access files from a root directory other than /\&.
+.sp
+Instead of accessing or altering files from the usual directory, paths will be prefixed with
+\fBROOT_DIR\fR\&.
+.sp
+For instance, instead of adding a user to
+/etc/passwd, the user would be added to
+\fBROOT_DIR\fR/etc/passwd\&.
+.RE
+.PP
 \fB\-s\fR, \fB\-\-shell\fR \fISHELL\fR
 .RS 4
 The name of the user\'s login shell\&. The default is to leave this field blank, which causes the system to select the default login shell specified by the
diff -Naur shadow-4.1.4.2.old/man/useradd.8.xml shadow-4.1.4.2/man/useradd.8.xml
--- shadow-4.1.4.2.old/man/useradd.8.xml	2009-05-21 08:02:13.000000000 -0400
+++ shadow-4.1.4.2/man/useradd.8.xml	2010-02-16 07:19:48.000000000 -0500
@@ -425,6 +425,26 @@
       </varlistentry>
       <varlistentry>
 	<term>
+	  <option>-R</option>, <option>--chroot</option>
+	  <replaceable>ROOT_DIR</replaceable>
+	</term>
+	<listitem>
+	  <para>
+	    Access files from a root directory other than /.
+	  </para>
+	  <para>
+	    Instead of accessing or altering files from the usual directory,
+	    paths will be prefixed with <option>ROOT_DIR</option>.
+	  </para>
+	  <para>
+	    For instance, instead of adding a user to
+	    <filename>/etc/passwd</filename>, the user would be added to
+	    <filename><option>ROOT_DIR</option>/etc/passwd</filename>.
+	  </para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term>
 	  <option>-s</option>, <option>--shell</option>
 	  <replaceable>SHELL</replaceable>
 	</term>
diff -Naur shadow-4.1.4.2.old/src/groupadd.c shadow-4.1.4.2/src/groupadd.c
--- shadow-4.1.4.2.old/src/groupadd.c	2009-06-05 18:16:58.000000000 -0400
+++ shadow-4.1.4.2/src/groupadd.c	2010-02-16 08:18:58.000000000 -0500
@@ -72,6 +72,8 @@
  */
 char *Prog;
 
+#define	VALID(s)	(strcspn (s, ":\n") == strlen (s))
+
 static /*...@null@*/char *group_name;
 static gid_t group_id;
 static /*...@null@*/char *group_passwd;
@@ -81,6 +83,8 @@
 static bool gflg = false;	/* ID value for the new group */
 static bool fflg = false;	/* if group already exists, do nothing and exit(0) */
 static bool rflg = false;	/* create a system account */
+static bool Rflg = false;	/* root directory offset to access files from */
+
 static bool pflg = false;	/* new encrypted password */
 
 #ifdef SHADOWGRP
@@ -121,6 +125,7 @@
 	                "                                (non-unique) GID\n"), stderr);
 	(void) fputs (_("  -p, --password PASSWORD       use this encrypted password for the new group\n"), stderr);
 	(void) fputs (_("  -r, --system                  create a system account\n"), stderr);
+	(void) fputs (_("  -R, --chroot ROOT_DIR         access files from an alternate root directory\n"), stderr);
 	(void) fputs ("\n", stderr);
 	exit (E_USAGE);
 }
@@ -373,6 +378,8 @@
 	/*
 	 * Parse the command line options.
 	 */
+	int argc_saved = argc;
+	static bool parse_chroot =  false;
 	char *cp;
 	int option_index = 0;
 	int c;
@@ -384,12 +391,35 @@
 		{"non-unique", no_argument, NULL, 'o'},
 		{"password", required_argument, NULL, 'p'},
 		{"system", no_argument, NULL, 'r'},
+		{"chroot", required_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:rR:", long_options,
 		             &option_index)) != -1) {
+		if (!parse_chroot) {
+		switch (c) {
+		case 'R':
+			if ((!VALID(optarg))
+			    || (optarg[0] != '/')) {
+				fprintf (stderr,
+				         _("%s: invalid root directory '%s'\n"),
+				         Prog, optarg);
+				exit (E_BAD_ARG);
+			}
+			if ( chroot(optarg) != 0 ) {
+				fprintf (stderr,
+			         _("%s: unable to change root directory to '%s': %s\n"),
+			         Prog, optarg, strerror (errno));
+				exit (1);
+			}
+			Rflg = true;
+			break;
+		default:
+			break;
+		}
+		} else {
 		switch (c) {
 		case 'f':
 			/*
@@ -443,9 +473,20 @@
 		case 'r':
 			rflg = true;
 			break;
+		case 'R':
+			break;
 		default:
 			usage ();
 		}
+		}
+	}
+
+	/* Finished parsing for chroot flag */
+	if (!parse_chroot) {
+		parse_chroot = true;
+		argc = argc_saved;
+		optind = 0;
+		return;
 	}
 
 	/*
@@ -476,8 +517,10 @@
 	/*
 	 * Check if the group already exist.
 	 */
-	/* local, no need for xgetgrnam */
-	if (getgrnam (group_name) != NULL) {
+	/* no chroot flag, local, no need for xgetgrnam */
+	if (((!Rflg) && (getgrnam (group_name) != NULL)) ||
+	/* chroot flag set, use compatible xfgetgrnam */
+		((Rflg) && (xfgetgrnam (group_name) != NULL))) {
 		/* The group already exist */
 		if (fflg) {
 			/* OK, no need to do anything */
@@ -489,7 +532,8 @@
 		exit (E_NAME_IN_USE);
 	}
 
-	if (gflg && (getgrgid (group_id) != NULL)) {
+	if (((gflg) && (!Rflg) && (getgrgid (group_id) != NULL)) ||
+		((gflg) && (Rflg) && (xfgetgrgid (group_id) != NULL))) {
 		/* A GID was specified, and a group already exist with that GID
 		 *  - either we will use this GID anyway (-o)
 		 *  - either we ignore the specified GID and
@@ -524,6 +568,8 @@
 {
 #ifdef ACCT_TOOLS_SETUID
 #ifdef USE_PAM
+	/* chroot doesn't work with PAM libs */
+	if (!Rflg) {
 	pam_handle_t *pamh = NULL;
 	int retval;
 	struct passwd *pampw;
@@ -553,6 +599,7 @@
 		fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
 		exit (1);
 	}
+	}
 #endif				/* USE_PAM */
 #endif				/* ACCT_TOOLS_SETUID */
 }
@@ -579,6 +626,12 @@
 	OPENLOG ("groupadd");
 
 	/*
+	 * Parse the chroot option before other options
+	 * but after opening the log.
+	 */
+	process_flags (argc, argv);
+
+	/*
 	 * Parse the command line options.
 	 */
 	process_flags (argc, argv);
diff -Naur shadow-4.1.4.2.old/src/useradd.c shadow-4.1.4.2/src/useradd.c
--- shadow-4.1.4.2.old/src/useradd.c	2009-06-05 18:16:58.000000000 -0400
+++ shadow-4.1.4.2/src/useradd.c	2010-02-16 08:17:32.000000000 -0500
@@ -143,6 +143,7 @@
     Nflg = false,		/* do not create a group having the same name as the user, but add the user to def_group (or the group specified with -g) */
     oflg = false,		/* permit non-unique user ID to be specified with -u */
     rflg = false,		/* create a system account */
+    Rflg = false,		/* root directory offset to access files from */
     sflg = false,		/* shell program for new account */
     uflg = false,		/* specify user ID for new account */
     Uflg = false,		/* create a group having the same name as the user */
@@ -286,6 +287,7 @@
 	FILE *fp;
 	char buf[1024];
 	char *cp;
+	const struct group *grp;
 
 	/*
 	 * Open the defaults file for reading.
@@ -317,7 +319,11 @@
 		 * Primary GROUP identifier
 		 */
 		if (MATCH (buf, DGROUP)) {
-			const struct group *grp = getgr_nam_gid (cp);
+			if (!Rflg) {
+				grp = getgr_nam_gid (cp);
+			} else {
+				grp = fgetgr_nam_gid (cp);
+			}
 			if (NULL == grp) {
 				fprintf (stderr,
 				         _("%s: group '%s' does not exist\n"),
@@ -618,7 +624,11 @@
 		 * Names starting with digits are treated as numerical
 		 * GID values, otherwise the string is looked up as is.
 		 */
-		grp = getgr_nam_gid (list);
+		if (!Rflg) {
+			grp = getgr_nam_gid (list);
+		} else {
+			grp = fgetgr_nam_gid (list);
+		}
 
 		/*
 		 * There must be a match, either by GID value or by
@@ -712,6 +722,7 @@
 	                "                                (non-unique) UID\n"), stderr);
 	(void) fputs (_("  -p, --password PASSWORD       encrypted password of the new account\n"), stderr);
 	(void) fputs (_("  -r, --system                  create a system account\n"), stderr);
+	(void) fputs (_("  -R, --chroot ROOT_DIR         access files from an alternate root directory\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);
 	(void) fputs (_("  -U, --user-group              create a group with the same name as the user\n"), stderr);
@@ -960,6 +971,8 @@
 		 * Parse the command line options.
 		 */
 		int c;
+		int argc_saved = argc;
+		static bool parse_chroot =  false;
 		static struct option long_options[] = {
 			{"base-dir", required_argument, NULL, 'b'},
 			{"comment", required_argument, NULL, 'c'},
@@ -979,6 +992,7 @@
 			{"non-unique", no_argument, NULL, 'o'},
 			{"password", required_argument, NULL, 'p'},
 			{"system", no_argument, NULL, 'r'},
+			{"chroot", required_argument, NULL, 'R'},
 			{"shell", required_argument, NULL, 's'},
 #ifdef WITH_SELINUX
 			{"selinux-user", required_argument, NULL, 'Z'},
@@ -989,11 +1003,33 @@
 		};
 		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:rR:s: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:rR:s:u:U",
 #endif
 		                         long_options, NULL)) != -1) {
+			if (!parse_chroot) {
+			switch (c) {
+			case 'R':
+				if ((!VALID(optarg))
+				    || (optarg[0] != '/')) {
+					fprintf (stderr,
+					         _("%s: invalid root directory '%s'\n"),
+					         Prog, optarg);
+					exit (E_BAD_ARG);
+				}
+				if ( chroot(optarg) != 0 ) {
+					fprintf (stderr,
+				         _("%s: unable to change root directory to '%s': %s\n"),
+				         Prog, optarg, strerror (errno));
+					fail_exit (1);
+				}
+				Rflg = true;
+				break;
+			default:
+				break;
+			}
+			} else {
 			switch (c) {
 			case 'b':
 				if (   ( !VALID (optarg) )
@@ -1081,7 +1117,11 @@
 				fflg = true;
 				break;
 			case 'g':
-				grp = getgr_nam_gid (optarg);
+				if (!Rflg) {
+					grp = getgr_nam_gid (optarg);
+				} else {
+					grp = fgetgr_nam_gid (optarg);
+				}
 				if (NULL == grp) {
 					fprintf (stderr,
 					         _("%s: group '%s' does not exist\n"),
@@ -1159,6 +1199,8 @@
 			case 'r':
 				rflg = true;
 				break;
+			case 'R':
+				break;
 			case 's':
 				if (   ( !VALID (optarg) )
 				    || (   ('\0' != optarg[0])
@@ -1204,6 +1246,14 @@
 				usage ();
 			}
 			anyflag = true;
+			}
+		}
+		/* Finished parsing for chroot flag */
+		if (!parse_chroot) {
+			parse_chroot = true;
+			argc = argc_saved;
+			optind = 0;
+			return;
 		}
 	}
 
@@ -1663,8 +1713,10 @@
 	 * no user with this UID exists yet (entries for shared UIDs
 	 * are left unchanged).  --marekm
 	 */
-	/* local, no need for xgetpwuid */
-	if ((!lflg) && (getpwuid (user_id) == NULL)) {
+	/* no chroot flag, local, no need for xgetpwuid */
+	if ((((!Rflg) && (!lflg)) && (getpwuid (user_id) == NULL)) ||
+		/* chroot flag set, use compatible xfgetpwuid */
+		((!lflg) && (xfgetpwuid (user_id) == NULL))) {
 		faillog_reset (user_id);
 		lastlog_reset (user_id);
 	}
@@ -1806,7 +1858,11 @@
 			return;
 		}
 
-		gr = getgrnam ("mail"); /* local, no need for xgetgrnam */
+		if (!Rflg) {
+			gr = getgrnam ("mail"); /* no chroot flag, local, no need for xgetgrnam */
+		} else {
+			gr = xfgetgrnam ("mail"); /* chroot flag set, use compatible xfgetgrnam */
+		}
 		if (NULL == gr) {
 			fputs (_("Group 'mail' not found. Creating the user mailbox file with 0600 mode.\n"),
 			       stderr);
@@ -1861,6 +1917,12 @@
 	 */
 	user_groups[0] = (char *) 0;
 
+	/*
+	 * Parse the chroot option before other options
+	 * and before accessing any database files,
+	 * but after opening the log.
+	 */
+	process_flags (argc, argv);
 
 	is_shadow_pwd = spw_file_present ();
 #ifdef SHADOWGRP
@@ -1873,6 +1935,8 @@
 
 #ifdef ACCT_TOOLS_SETUID
 #ifdef USE_PAM
+	/* chroot doesn't work with PAM libs */
+	if (!Rflg) {
 	{
 		struct passwd *pampw;
 		pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
@@ -1901,6 +1965,7 @@
 		fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
 		fail_exit (1);
 	}
+	}
 #endif				/* USE_PAM */
 #endif				/* ACCT_TOOLS_SETUID */
 
@@ -1920,7 +1985,8 @@
 	/*
 	 * Start with a quick check to see if the user exists.
 	 */
-	if (getpwnam (user_name) != NULL) { /* local, no need for xgetpwnam */
+	if (((!Rflg) && (getpwnam (user_name) != NULL)) || /* no chroot flag, local, no need for xgetpwnam */
+		((Rflg) && (xfgetpwnam (user_name) != NULL))) { /* chroot flag set, use compatible xfgetpwnam */
 		fprintf (stderr, _("%s: user '%s' already exists\n"), Prog, user_name);
 #ifdef WITH_AUDIT
 		audit_logger (AUDIT_ADD_USER, Prog,
@@ -1938,8 +2004,10 @@
 	 * --bero
 	 */
 	if (Uflg) {
-		/* local, no need for xgetgrnam */
-		if (getgrnam (user_name) != NULL) {
+		/* no chroot flag, local, no need for xgetgrnam */
+		if (((!Rflg) && (getgrnam (user_name) != NULL)) ||
+			/* chroot flag set, use compatible xfgetgrnam */
+			((Rflg) && (xfgetgrnam (user_name) != NULL))) {
 			fprintf (stderr,
 			         _("%s: group %s exists - if you want to add this user to that group, use -g.\n"),
 			         Prog, user_name);
@@ -1974,7 +2042,8 @@
 				fail_exit (E_UID_IN_USE);
 			}
 		} else {
-			if (getpwuid (user_id) != NULL) {
+			if (((!Rflg) && (getpwuid (user_id) != NULL)) || 
+				((Rflg) && (xfgetpwuid (user_id) != NULL))) {
 				fprintf (stderr,
 				         _("%s: UID %lu is not unique\n"),
 				         Prog, (unsigned long) user_id);

Reply via email to