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 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 = -I.@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__quote@./$(DEPDIR)/user_busy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/valid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfgetgrgid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfgetgrnam.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfgetpwnam.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfgetpwuid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xgetgrgid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xgetgrnam.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xgetpwnam.Po@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 +#include +#include +#include +#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 + +#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 + +#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 + +#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 + +#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 @@ + + + , + ROOT_DIR + + + + Access files from a root directory other than /. + + + Instead of accessing or altering files from the usual directory, + paths will be prefixed with . + + + For instance, instead of adding a group to + /etc/group, the group would be added to + /etc/group. + + + 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 @@ + , + ROOT_DIR + + + + Access files from a root directory other than /. + + + Instead of accessing or altering files from the usual directory, + paths will be prefixed with . + + + For instance, instead of adding a user to + /etc/passwd, the user would be added to + /etc/passwd. + + + + + , SHELL 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);