[Pkg-shadow-commits] r3095 - in upstream/trunk: . lib libmisc man man/login.defs.d src

Nicolas FRANÇOIS nekral-guest at alioth.debian.org
Thu Mar 4 18:11:15 UTC 2010


Author: nekral-guest
Date: 2010-03-04 18:11:13 +0000 (Thu, 04 Mar 2010)
New Revision: 3095

Added:
   upstream/trunk/lib/tcbfuncs.c
   upstream/trunk/lib/tcbfuncs.h
   upstream/trunk/man/login.defs.d/TCB_AUTH_GROUP.xml
   upstream/trunk/man/login.defs.d/TCB_SYMLINKS.xml
   upstream/trunk/man/login.defs.d/USE_TCB.xml
Modified:
   upstream/trunk/ChangeLog
   upstream/trunk/NEWS
   upstream/trunk/configure.in
   upstream/trunk/lib/Makefile.am
   upstream/trunk/lib/commonio.c
   upstream/trunk/lib/getdef.c
   upstream/trunk/lib/prototypes.h
   upstream/trunk/lib/shadowio.c
   upstream/trunk/libmisc/copydir.c
   upstream/trunk/man/Makefile.am
   upstream/trunk/man/generate_mans.deps
   upstream/trunk/man/generate_mans.mak
   upstream/trunk/man/login.defs.5.xml
   upstream/trunk/man/vipw.8.xml
   upstream/trunk/src/Makefile.am
   upstream/trunk/src/chage.c
   upstream/trunk/src/pwconv.c
   upstream/trunk/src/pwunconv.c
   upstream/trunk/src/useradd.c
   upstream/trunk/src/userdel.c
   upstream/trunk/src/usermod.c
   upstream/trunk/src/vipw.c
Log:
2010-01-30  Pawe?\197?\130 Hajdan, Jr.  <phajdan.jr at gentoo.org>

	* NEWS: Add support for TCB.
	* lib/tcbfuncs.h, lib/tcbfuncs.c, lib/Makefile.am: New library to
	support TCB.
	* lib/prototypes, libmisc/copydir.c (remove_tree): Add boolean
	parameter remove_root.
	* configure.in: Add conditional WITH_TCB.
	* src/userdel.c, src/usermod.c: Add support for TCB. Update call to
	remove_tree().
	* src/pwconv.c, src/pwunconv.c: Should not be used with TCB enabled.
	* src/vipw.c: Add support for TCB. Update call to remove_tree().
	* src/useradd.c: Add support for TCB. Open the shadow file outside
	of open_files().
	* src/chage.c: Add support for TCB.
	* src/Makefile.am: Install passwd sgid shadow when TCB is enabled.
	* lib/getdefs.c, man/vipw.8.xml, man/login.defs.5.xml,
	man/login.defs/TCB_AUTH_GROUP.xml, man/login.defs/USE_TCB.xml,
	man/login.defs/TCB_SYMLINKS.xml, man/generate_mans.mak,
	man/generate_mans.deps, man/Makefile.am: New configuration
	parameters: TCB_AUTH_GROUP, TCB_SYMLINKS, USE_TCB.
	* lib/shadowio.c, lib/commonio.c: Add support for TCB.



Modified: upstream/trunk/ChangeLog
===================================================================
--- upstream/trunk/ChangeLog	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/ChangeLog	2010-03-04 18:11:13 UTC (rev 3095)
@@ -1,9 +1,32 @@
-2009-01-24  Nicolas François  <nicolas.francois at centraliens.net>
+2010-01-30  Paweł Hajdan, Jr.  <phajdan.jr at gentoo.org>
 
+	* NEWS: Add support for TCB.
+	* lib/tcbfuncs.h, lib/tcbfuncs.c, lib/Makefile.am: New library to
+	support TCB.
+	* lib/prototypes, libmisc/copydir.c (remove_tree): Add boolean
+	parameter remove_root.
+	* configure.in: Add conditional WITH_TCB.
+	* src/userdel.c, src/usermod.c: Add support for TCB. Update call to
+	remove_tree().
+	* src/pwconv.c, src/pwunconv.c: Should not be used with TCB enabled.
+	* src/vipw.c: Add support for TCB. Update call to remove_tree().
+	* src/useradd.c: Add support for TCB. Open the shadow file outside
+	of open_files().
+	* src/chage.c: Add support for TCB.
+	* src/Makefile.am: Install passwd sgid shadow when TCB is enabled.
+	* lib/getdefs.c, man/vipw.8.xml, man/login.defs.5.xml,
+	man/login.defs/TCB_AUTH_GROUP.xml, man/login.defs/USE_TCB.xml,
+	man/login.defs/TCB_SYMLINKS.xml, man/generate_mans.mak,
+	man/generate_mans.deps, man/Makefile.am: New configuration
+	parameters: TCB_AUTH_GROUP, TCB_SYMLINKS, USE_TCB.
+	* lib/shadowio.c, lib/commonio.c: Add support for TCB.
+
+2010-01-24  Nicolas François  <nicolas.francois at centraliens.net>
+
 	* libmisc/env.c: Fix sanitize_env() noslash support. This fixes
 	Alioth#311740.
 
-2009-01-24  Nicolas François  <nicolas.francois at centraliens.net>
+2010-01-24  Nicolas François  <nicolas.francois at centraliens.net>
 
 	* src/su.c: Do not sanitize the environment. This breaks
 	--preserve-environment. This sanitation was disabled on Debian
@@ -12,11 +35,11 @@
 	Unixes will handle setuid executables properly. This fixes
 	Alioth#312287.
 
-2009-01-24  Nicolas François  <nicolas.francois at centraliens.net>
+2010-01-24  Nicolas François  <nicolas.francois at centraliens.net>
 
 	* libmisc/setupenv.c: Fix typo from 2009-11-01.
 
-2009-01-24  Paweł Hajdan, Jr.  <phajdan.jr at gentoo.org>
+2010-01-24  Paweł Hajdan, Jr.  <phajdan.jr at gentoo.org>
 
 	* configure.in: Add support for TCB in configure.in. Actual TCB
 	support will follow.

Modified: upstream/trunk/NEWS
===================================================================
--- upstream/trunk/NEWS	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/NEWS	2010-03-04 18:11:13 UTC (rev 3095)
@@ -5,6 +5,7 @@
 - general
   * report usage error to stderr, but report usage help to stdout (and return
     zero) when explicitly requested (e.g. with --help).
+  * initial support for tcb (http://openwall.com/tcb/).
 
 - groupmod
   * Fixed groupmod when configured with --enable-account-tools-setuid.

Modified: upstream/trunk/configure.in
===================================================================
--- upstream/trunk/configure.in	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/configure.in	2010-03-04 18:11:13 UTC (rev 3095)
@@ -405,6 +405,7 @@
 		with_tcb="no"
 	fi
 fi
+AM_CONDITIONAL(WITH_TCB, test x$with_tcb = xyes)
 
 AC_SUBST(LIBPAM)
 if test "$with_libpam" != "no"; then

Modified: upstream/trunk/lib/Makefile.am
===================================================================
--- upstream/trunk/lib/Makefile.am	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/lib/Makefile.am	2010-03-04 18:11:13 UTC (rev 3095)
@@ -49,6 +49,10 @@
 	shadowmem.c \
 	utent.c
 
+if WITH_TCB
+libshadow_la_SOURCES += tcbfuncs.c tcbfuncs.h
+endif
+
 # These files are unneeded for some reason, listed in
 # order of appearance:
 #

Modified: upstream/trunk/lib/commonio.c
===================================================================
--- upstream/trunk/lib/commonio.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/lib/commonio.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -48,6 +48,9 @@
 #ifdef WITH_SELINUX
 #include <selinux/selinux.h>
 #endif
+#ifdef WITH_TCB
+#include <tcb.h>
+#endif
 #include "prototypes.h"
 #include "commonio.h"
 
@@ -533,6 +536,7 @@
 	void *eptr = NULL;
 	int flags = mode;
 	size_t buflen;
+	int fd;
 	int saved_errno;
 
 	mode &= ~O_CREAT;
@@ -553,7 +557,24 @@
 	db->cursor = NULL;
 	db->changed = false;
 
-	db->fp = fopen (db->filename, db->readonly ? "r" : "r+");
+	fd = open(db->filename, (db->readonly ? O_RDONLY : O_RDWR) |
+		O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
+	saved_errno = errno;
+	db->fp = NULL;
+	if (fd >= 0) {
+#ifdef WITH_TCB
+		if (tcb_is_suspect(fd)) {
+			close(fd);
+			errno = EINVAL;
+			return 0;
+		}
+#endif
+		db->fp = fdopen(fd, db->readonly ? "r" : "r+");
+		saved_errno = errno;
+		if (!db->fp)
+			close(fd);
+	}
+	errno = saved_errno;
 
 	/*
 	 * If O_CREAT was specified and the file didn't exist, it will be

Modified: upstream/trunk/lib/getdef.c
===================================================================
--- upstream/trunk/lib/getdef.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/lib/getdef.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -124,6 +124,11 @@
 	{"SYSLOG_SG_ENAB", NULL},
 	{"SYSLOG_SU_ENAB", NULL},
 #endif
+#ifdef WITH_TCB
+	{"TCB_AUTH_GROUP", NULL},
+	{"TCB_SYMLINKS", NULL},
+	{"USE_TCB", NULL},
+#endif
 	{NULL, NULL}
 };
 

Modified: upstream/trunk/lib/prototypes.h
===================================================================
--- upstream/trunk/lib/prototypes.h	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/lib/prototypes.h	2010-03-04 18:11:13 UTC (rev 3095)
@@ -117,7 +117,7 @@
 /* copydir.c */
 extern int copy_tree (const char *src_root, const char *dst_root,
                       long int uid, long int gid);
-extern int remove_tree (const char *root);
+extern int remove_tree (const char *root, bool remove_root);
 
 #ifdef WITH_SELINUX
 extern int selinux_file_context (const char *dst_name);

Modified: upstream/trunk/lib/shadowio.c
===================================================================
--- upstream/trunk/lib/shadowio.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/lib/shadowio.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -41,6 +41,10 @@
 #include <stdio.h>
 #include "commonio.h"
 #include "shadowio.h"
+#ifdef WITH_TCB
+#include <tcb.h>
+#include "tcbfuncs.h"
+#endif
 
 static /*@null@*/ /*@only@*/void *shadow_dup (const void *ent)
 {
@@ -120,12 +124,40 @@
 
 int spw_lock (void)
 {
-	return commonio_lock (&shadow_db);
+#ifdef WITH_TCB
+	int retval = 0;
+
+	if (!getdef_bool("USE_TCB"))
+#endif
+		return commonio_lock (&shadow_db);
+#ifdef WITH_TCB
+	if (!shadowtcb_drop_priv())
+		return 0;
+	if (lckpwdf_tcb(shadow_db.filename) == 0) {
+		shadow_db.locked = 1;
+		retval = 1;
+	}
+	if (!shadowtcb_gain_priv())
+		return 0;
+	return retval;
+#endif
 }
 
 int spw_open (int mode)
 {
-	return commonio_open (&shadow_db, mode);
+	int retval = 0;
+#ifdef WITH_TCB
+	int use_tcb = getdef_bool("USE_TCB");
+
+	if (use_tcb && !shadowtcb_drop_priv() != 0)
+		return 0;
+#endif
+	retval = commonio_open (&shadow_db, mode);
+#ifdef WITH_TCB
+	if (use_tcb && !shadowtcb_gain_priv() != 0)
+		return 0;
+#endif
+	return retval;
 }
 
 /*@observer@*/ /*@null@*/const struct spwd *spw_locate (const char *name)
@@ -155,12 +187,40 @@
 
 int spw_close (void)
 {
-	return commonio_close (&shadow_db);
+	int retval = 0;
+#ifdef WITH_TCB
+	int use_tcb = getdef_bool("USE_TCB");
+
+	if (use_tcb && !shadowtcb_drop_priv() != 0)
+		return 0;
+#endif
+	retval = commonio_close (&shadow_db);
+#ifdef WITH_TCB
+	if (use_tcb && !shadowtcb_gain_priv() != 0)
+		return 0;
+#endif
+	return retval;
 }
 
 int spw_unlock (void)
 {
-	return commonio_unlock (&shadow_db);
+#ifdef WITH_TCB
+	int retval = 0;
+
+	if (!getdef_bool("USE_TCB"))
+#endif
+		return commonio_unlock (&shadow_db);
+#ifdef WITH_TCB
+	if (!shadowtcb_drop_priv())
+		return 0;
+	if (ulckpwdf_tcb() == 0) {
+		shadow_db.locked = 0;
+		retval = 1;
+	}
+	if (!shadowtcb_gain_priv())
+		return 0;
+	return retval;
+#endif
 }
 
 struct commonio_entry *__spw_get_head (void)
@@ -176,5 +236,9 @@
 /* Sort with respect to passwd ordering. */
 int spw_sort ()
 {
+#ifdef WITH_TCB
+	if (getdef_bool("USE_TCB"))
+		return 0;
+#endif
 	return commonio_sort_wrt (&shadow_db, __pw_get_db ());
 }

Added: upstream/trunk/lib/tcbfuncs.c
===================================================================
--- upstream/trunk/lib/tcbfuncs.c	                        (rev 0)
+++ upstream/trunk/lib/tcbfuncs.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2001 Rafal Wojtczuk, Solar Designer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <tcb.h>
+#include <unistd.h>
+
+#include "config.h"
+
+#include "defines.h"
+#include "getdef.h"
+
+#define SHADOWTCB_HASH_BY 1000
+#define SHADOWTCB_LOCK_SUFFIX ".lock"
+
+static char *stored_tcb_user = NULL;
+
+int shadowtcb_drop_priv()
+{
+	if (!getdef_bool("USE_TCB"))
+		return 1;
+	
+	if (stored_tcb_user)
+		return !tcb_drop_priv(stored_tcb_user);
+	
+	return 0;
+}
+
+int shadowtcb_gain_priv()
+{
+	if (!getdef_bool("USE_TCB"))
+		return 1;
+	return !tcb_gain_priv();
+}
+
+/* In case something goes wrong, we return immediately, not polluting the
+ * code with free(). All errors are fatal, so the application is expected
+ * to exit soon.
+ */
+#define OUT_OF_MEMORY do { \
+	fprintf(stderr, "Out of memory.\n"); \
+	fflush(stderr); \
+	return 0; \
+} while(0)
+
+/* Returns user's tcb directory path relative to TCB_DIR. */
+static char *shadowtcb_path_rel(const char *name, uid_t uid)
+{
+	char *ret;
+
+	if (!getdef_bool("TCB_SYMLINKS") || uid < SHADOWTCB_HASH_BY) {
+		asprintf(&ret, "%s", name);
+	} else if (uid < SHADOWTCB_HASH_BY * SHADOWTCB_HASH_BY) {
+		asprintf(&ret, ":%dK/%s", uid / SHADOWTCB_HASH_BY, name);
+	} else {
+		asprintf(&ret, ":%dM/:%dK/%s",
+			uid / (SHADOWTCB_HASH_BY * SHADOWTCB_HASH_BY),
+			(uid % (SHADOWTCB_HASH_BY * SHADOWTCB_HASH_BY)) / SHADOWTCB_HASH_BY,
+			name);
+	}
+	if (!ret) {
+		OUT_OF_MEMORY;
+	}
+	return ret;
+}
+
+static char *shadowtcb_path_rel_existing(const char *name)
+{
+	char *path, *rval;
+	struct stat st;
+	char link[8192];
+	int ret;
+
+	asprintf(&path, TCB_DIR "/%s", name);
+	if (!path) {
+		OUT_OF_MEMORY;
+	}
+	if (lstat(path, &st)) {
+		fprintf(stderr, "Cannot stat %s: %s\n", path, strerror(errno));
+		free(path);
+		return NULL;
+	}
+	if (S_ISDIR(st.st_mode)) {
+		free(path);
+		rval = strdup(name);
+		if (!rval) {
+			OUT_OF_MEMORY;
+		}
+		return rval;
+	}
+	if (!S_ISLNK(st.st_mode)) {
+		fprintf(stderr, "%s is neither a directory, nor a symlink.\n", path);
+		free(path);
+		return NULL;
+	}
+	ret = readlink(path, link, sizeof(link) - 1);
+	free(path);
+	if (ret == -1) {
+		perror("readlink");
+		return NULL;
+	}
+	if (ret >= sizeof(link) - 1) {
+		link[sizeof(link) - 1] = '\0';
+		fprintf(stderr, "Suspiciously long symlink: %s\n", link);
+		return NULL;
+	}
+	link[ret] = '\0';
+	rval = strdup(link);
+	if (!rval) {
+		OUT_OF_MEMORY;
+	}
+	return rval;
+}
+
+static char *shadowtcb_path(const char *name, uid_t uid)
+{
+	char *ret, *rel;
+
+	if (!(rel = shadowtcb_path_rel(name, uid)))
+		return 0;
+	asprintf(&ret, TCB_DIR "/%s", rel);
+	free(rel);
+	if (!ret) {
+		OUT_OF_MEMORY;
+	}
+	return ret;
+}
+
+static char *shadowtcb_path_existing(const char *name)
+{
+	char *ret, *rel;
+
+	if (!(rel = shadowtcb_path_rel_existing(name)))
+		return 0;
+	asprintf(&ret, TCB_DIR "/%s", rel);
+	free(rel);
+	if (!ret) {
+		OUT_OF_MEMORY;
+	}
+	return ret;
+}
+
+static int mkdir_leading(const char *name, uid_t uid)
+{
+	char *ind, *dir, *ptr, *path = shadowtcb_path_rel(name, uid);
+	struct stat st;
+
+	if (!path)
+		return 0;
+	ptr = path;
+	if (stat(TCB_DIR, &st)) {
+		perror("stat");
+		goto out_free_path;
+	}
+	while ((ind = strchr(ptr, '/'))) {
+		*ind = 0;
+		asprintf(&dir, TCB_DIR "/%s", path);
+		if (!dir) {
+			OUT_OF_MEMORY;
+		}
+		if (mkdir(dir, 0700) && errno != EEXIST) {
+			perror("mkdir");
+			goto out_free_dir;
+		}
+		if (chown(dir, 0, st.st_gid)) {
+			perror("chown");
+			goto out_free_dir;
+		}
+		if (chmod(dir, 0711)) {
+			perror("chmod");
+			goto out_free_dir;
+		}
+		free(dir);
+		*ind = '/';
+		ptr = ind + 1;
+	}
+	free(path);
+	return 1;
+out_free_dir:
+	free(dir);
+out_free_path:
+	free(path);
+	return 0;
+}
+
+static int unlink_suffs(const char *user)
+{
+	static char *suffs[] = { "+", "-", SHADOWTCB_LOCK_SUFFIX };
+	char *tmp;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		asprintf(&tmp, TCB_FMT "%s", user, suffs[i]);
+		if (!tmp) {
+			OUT_OF_MEMORY;
+		}
+		if (unlink(tmp) && errno != ENOENT) {
+			fprintf(stderr, "unlink: %s: %s\n", tmp,
+				strerror(errno));
+			free(tmp);
+			return 0;
+		}
+		free(tmp);
+	}
+
+	return 1;
+}
+
+/* path should be a relative existing tcb directory */
+static int rmdir_leading(char *path)
+{
+	char *ind, *dir;
+	int ret = 1;
+	while ((ind = strrchr(path, '/'))) {
+		*ind = 0;
+		asprintf(&dir, TCB_DIR "/%s", path);
+		if (!dir) {
+			OUT_OF_MEMORY;
+		}
+		if (rmdir(dir)) {
+			if (errno != ENOTEMPTY) {
+				perror("rmdir");
+				ret = 0;
+			}
+			free(dir);
+			break;
+		}
+		free(dir);
+	}
+	return ret;
+}
+
+static int move_dir(const char *user_newname, uid_t user_newid)
+{
+	char *olddir = NULL, *newdir = NULL;
+	char *real_old_dir = NULL, *real_new_dir = NULL;
+	char *real_old_dir_rel = NULL, *real_new_dir_rel = NULL;
+	uid_t old_uid, the_newid;
+	struct stat oldmode;
+	int ret = 0;
+
+	asprintf(&olddir, TCB_DIR "/%s", stored_tcb_user);
+	if (!olddir)
+		goto out_free_nomem;
+	if (stat(olddir, &oldmode)) {
+		perror("stat");
+		goto out_free;
+	}
+	old_uid = oldmode.st_uid;
+	the_newid = (user_newid == -1) ? old_uid : user_newid;
+	if (!(real_old_dir = shadowtcb_path_existing(stored_tcb_user)))
+		goto out_free;
+	if (!(real_new_dir = shadowtcb_path(user_newname, the_newid)))
+		goto out_free;
+	if (!strcmp(real_old_dir, real_new_dir)) {
+		ret = 1;
+		goto out_free;
+	}
+	if (!(real_old_dir_rel = shadowtcb_path_rel_existing(stored_tcb_user)))
+		goto out_free;
+	if (!mkdir_leading(user_newname, the_newid))
+		goto out_free;
+	if (rename(real_old_dir, real_new_dir)) {
+		perror("rename");
+		goto out_free;
+	}
+	if (!rmdir_leading(real_old_dir_rel))
+		goto out_free;
+	if (unlink(olddir) && errno != ENOENT) {
+		perror("unlink");
+		goto out_free;
+	}
+	asprintf(&newdir, TCB_DIR "/%s", user_newname);
+	if (!newdir)
+		goto out_free_nomem;
+	if (!(real_new_dir_rel = shadowtcb_path_rel(user_newname, the_newid)))
+		goto out_free;
+	if (strcmp(real_new_dir, newdir) && symlink(real_new_dir_rel, newdir)) {
+		perror("symlink");
+		goto out_free;
+	}
+	ret = 1;
+	goto out_free;
+out_free_nomem:
+	fprintf(stderr, "Out of memory\n");
+	fflush(stderr);
+out_free:
+	free(olddir);
+	free(newdir);
+	free(real_old_dir);
+	free(real_new_dir);
+	free(real_old_dir_rel);
+	free(real_new_dir_rel);
+	return ret;
+}
+
+int shadowtcb_set_user(const char* name)
+{
+	char *buf;
+	int retval;
+
+	if (!getdef_bool("USE_TCB"))
+		return 1;
+	
+	if (stored_tcb_user)
+		free(stored_tcb_user);
+	
+	stored_tcb_user = strdup(name);
+	if (!stored_tcb_user) {
+		OUT_OF_MEMORY;
+	}
+	asprintf(&buf, TCB_FMT, name);
+	if (!buf) {
+		OUT_OF_MEMORY;
+	}
+
+	retval = spw_setdbname(buf);
+	free(buf);
+	return retval;
+}
+
+/* tcb directory must be empty before shadowtcb_remove is called. */
+int shadowtcb_remove(const char *name)
+{
+	int ret = 1;
+	char *path = shadowtcb_path_existing(name);
+	char *rel = shadowtcb_path_rel_existing(name);
+	if (!path || !rel || rmdir(path))
+		return 0;
+	if (!rmdir_leading(rel))
+		return 0;
+	free(path);
+	free(rel);
+	asprintf(&path, TCB_DIR "/%s", name);
+	if (!path) {
+		OUT_OF_MEMORY;
+	}
+	if (unlink(path) && errno != ENOENT)
+		ret = 0;
+	free(path);
+	return ret;
+}
+
+int shadowtcb_move(const char *user_newname, uid_t user_newid)
+{
+	struct stat dirmode, filemode;
+	char *tcbdir, *shadow;
+	int ret = 0;
+
+	if (!getdef_bool("USE_TCB"))
+		return 1;
+	if (!user_newname)
+		user_newname = stored_tcb_user;
+	if (!move_dir(user_newname, user_newid))
+		return 0;
+	if (user_newid == -1)
+		return 1;
+	asprintf(&tcbdir, TCB_DIR "/%s", user_newname);
+	asprintf(&shadow, TCB_FMT, user_newname);
+	if (!tcbdir || !shadow) {
+		OUT_OF_MEMORY;
+	}
+	if (stat(tcbdir, &dirmode)) {
+		perror("stat");
+		goto out_free;
+	}
+	if (chown(tcbdir, 0, 0)) {
+		perror("chown");
+		goto out_free;
+	}
+	if (chmod(tcbdir, 0700)) {
+		perror("chmod");
+		goto out_free;
+	}
+	if (lstat(shadow, &filemode)) {
+		if (errno != ENOENT) {
+			perror("lstat");
+			goto out_free;
+		}
+		fprintf(stderr,
+			"Warning, user %s has no tcb shadow file.\n",
+			user_newname);
+	} else {
+		if (!S_ISREG(filemode.st_mode) ||
+			filemode.st_nlink != 1) {
+			fprintf(stderr,
+				"Emergency: %s's tcb shadow is not a regular file"
+				" with st_nlink=1.\n"
+				"The account is left locked.\n",
+				user_newname);
+			goto out_free;
+		}
+		if (chown(shadow, user_newid, filemode.st_gid)) {
+			perror("chown");
+			goto out_free;
+		}
+		if (chmod(shadow, filemode.st_mode & 07777)) {
+			perror("chmod");
+			goto out_free;
+		}
+	}
+	if (!unlink_suffs(user_newname))
+		goto out_free;
+	if (chown(tcbdir, user_newid, dirmode.st_gid)) {
+		perror("chown");
+		goto out_free;
+	}
+	ret = 1;
+out_free:
+	free(tcbdir);
+	free(shadow);
+	return ret;
+}
+
+int shadowtcb_create(const char *name, uid_t uid)
+{
+	char *dir, *shadow;
+	struct stat tcbdir_stat;
+	gid_t shadowgid, authgid;
+	struct group *gr;
+	int fd, ret = 0;
+
+	if (!getdef_bool("USE_TCB"))
+		return 1;
+	if (stat(TCB_DIR, &tcbdir_stat)) {
+		perror("stat");
+		return 0;
+	}
+	shadowgid = tcbdir_stat.st_gid;
+	if (getdef_bool("TCB_AUTH_GROUP") &&
+		(gr = getgrnam("auth"))) {
+		authgid = gr->gr_gid;
+	} else {
+		authgid = shadowgid;
+	}
+	
+	asprintf(&dir, TCB_DIR "/%s", name);
+	asprintf(&shadow, TCB_FMT, name);
+	if (!dir || !shadow) {
+		OUT_OF_MEMORY;
+	}
+	if (mkdir(dir, 0700)) {
+		fprintf(stderr, "mkdir: %s: %s\n", dir, strerror(errno));
+		goto out_free;
+		return 0;
+	}
+	fd = open(shadow, O_RDWR | O_CREAT | O_TRUNC, 0600);
+	if (fd < 0) {
+		perror("open");
+		goto out_free;
+	}
+	close(fd);
+	if (chown(shadow, 0, authgid)) {
+		perror("chown");
+		goto out_free;
+	}
+	if (chmod(shadow, authgid == shadowgid ? 0600 : 0640)) {
+		perror("chmod");
+		goto out_free;
+	}
+	if (chown(dir, 0, authgid)) {
+		perror("chown");
+		goto out_free;
+	}
+	if (chmod(dir, authgid == shadowgid ? 02700 : 02710)) {
+		perror("chmod");
+		goto out_free;
+	}
+	if (!shadowtcb_set_user(name) || !shadowtcb_move(NULL, uid))
+		goto out_free;
+	ret = 1;
+out_free:
+	free(dir);
+	free(shadow);
+	return ret;
+}

Added: upstream/trunk/lib/tcbfuncs.h
===================================================================
--- upstream/trunk/lib/tcbfuncs.h	                        (rev 0)
+++ upstream/trunk/lib/tcbfuncs.h	2010-03-04 18:11:13 UTC (rev 3095)
@@ -0,0 +1,13 @@
+#ifndef _TCBFUNCS_H
+#define _TCBFUNCS_H
+
+#include <sys/types.h>
+
+extern int shadowtcb_drop_priv();
+extern int shadowtcb_gain_priv();
+extern int shadowtcb_set_user(const char *name);
+extern int shadowtcb_remove(const char *name);
+extern int shadowtcb_move(const char *user_newname, uid_t user_newid);
+extern int shadowtcb_create(const char *name, uid_t uid);
+
+#endif

Modified: upstream/trunk/libmisc/copydir.c
===================================================================
--- upstream/trunk/libmisc/copydir.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/libmisc/copydir.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -668,7 +668,7 @@
  *	At the end, it deletes the root directory itself.
  */
 
-int remove_tree (const char *root)
+int remove_tree (const char *root, bool remove_root)
 {
 	char *new_name = NULL;
 	int err = 0;
@@ -721,7 +721,7 @@
 			/*
 			 * Recursively delete this directory.
 			 */
-			if (remove_tree (new_name) != 0) {
+			if (remove_tree (new_name, true) != 0) {
 				err = -1;
 				break;
 			}
@@ -740,7 +740,7 @@
 	}
 	(void) closedir (dir);
 
-	if (0 == err) {
+	if (remove_root && 0 == err) {
 		if (rmdir (root) != 0) {
 			err = -1;
 		}

Modified: upstream/trunk/man/Makefile.am
===================================================================
--- upstream/trunk/man/Makefile.am	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/man/Makefile.am	2010-03-04 18:11:13 UTC (rev 3095)
@@ -149,6 +149,8 @@
 	SU_WHEEL_ONLY.xml \
 	SYSLOG_SG_ENAB.xml \
 	SYSLOG_SU_ENAB.xml \
+	TCB_AUTH_GROUP.xml \
+	TCB_SYMLINKS.xml \
 	TTYGROUP.xml \
 	TTYTYPE_FILE.xml \
 	UID_MAX.xml \
@@ -156,6 +158,7 @@
 	UMASK.xml \
 	USERDEL_CMD.xml \
 	USERGROUPS_ENAB.xml \
+	USE_TCB.xml \
 	SYS_GID_MAX.xml \
 	SYS_UID_MAX.xml
 

Modified: upstream/trunk/man/generate_mans.deps
===================================================================
--- upstream/trunk/man/generate_mans.deps	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/man/generate_mans.deps	2010-03-04 18:11:13 UTC (rev 3095)
@@ -105,6 +105,8 @@
 login.defs.5: login.defs.d/SYSLOG_SG_ENAB.xml
 login.defs.5: login.defs.d/SYSLOG_SU_ENAB.xml
 login.defs.5: login.defs.d/SYS_UID_MAX.xml
+login.defs.5: login.defs.d/TCB_AUTH_GROUP.xml
+login.defs.5: login.defs.d/TCB_SYMLINKS.xml
 login.defs.5: login.defs.d/TTYGROUP.xml
 login.defs.5: login.defs.d/TTYTYPE_FILE.xml
 login.defs.5: login.defs.d/UID_MAX.xml
@@ -112,6 +114,7 @@
 login.defs.5: login.defs.d/UMASK.xml
 login.defs.5: login.defs.d/USERDEL_CMD.xml
 login.defs.5: login.defs.d/USERGROUPS_ENAB.xml
+login.defs.5: login.defs.d/USE_TCB.xml
 newgrp.1: login.defs.d/SYSLOG_SG_ENAB.xml
 newusers.8: login.defs.d/ENCRYPT_METHOD.xml
 newusers.8: login.defs.d/GID_MAX.xml

Modified: upstream/trunk/man/generate_mans.mak
===================================================================
--- upstream/trunk/man/generate_mans.mak	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/man/generate_mans.mak	2010-03-04 18:11:13 UTC (rev 3095)
@@ -8,6 +8,11 @@
 else
 SHADOWGRP_COND=no_gshadow
 endif
+if WITH_TCB
+TCB_COND=tcb
+else
+TCB_COND=no_tcb
+endif
 
 if USE_SHA_CRYPT
 SHA_CRYPT_COND=sha_crypt
@@ -20,7 +25,7 @@
 
 %: %.xml-config Makefile config.xml
 if ENABLE_REGENERATE_MAN
-	$(XSLTPROC) --stringparam profile.condition "$(PAM_COND);$(SHADOWGRP_COND);$(SHA_CRYPT_COND)" \
+	$(XSLTPROC) --stringparam profile.condition "$(PAM_COND);$(SHADOWGRP_COND);$(TCB_COND);$(SHA_CRYPT_COND)" \
 	            -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/profile-docbook.xsl $<
 else
 	@echo you need to run configure with --enable-man to generate man pages

Modified: upstream/trunk/man/login.defs.5.xml
===================================================================
--- upstream/trunk/man/login.defs.5.xml	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/man/login.defs.5.xml	2010-03-04 18:11:13 UTC (rev 3095)
@@ -82,6 +82,8 @@
 <!ENTITY SYSLOG_SG_ENAB        SYSTEM "login.defs.d/SYSLOG_SG_ENAB.xml">
 <!ENTITY SYSLOG_SU_ENAB        SYSTEM "login.defs.d/SYSLOG_SU_ENAB.xml">
 <!ENTITY SYS_UID_MAX           SYSTEM "login.defs.d/SYS_UID_MAX.xml">
+<!ENTITY TCB_AUTH_GROUP        SYSTEM "login.defs.d/TCB_AUTH_GROUP.xml">
+<!ENTITY TCB_SYMLINKS          SYSTEM "login.defs.d/TCB_SYMLINKS.xml">
 <!ENTITY TTYGROUP              SYSTEM "login.defs.d/TTYGROUP.xml">
 <!ENTITY TTYTYPE_FILE          SYSTEM "login.defs.d/TTYTYPE_FILE.xml">
 <!ENTITY UID_MAX               SYSTEM "login.defs.d/UID_MAX.xml">
@@ -89,6 +91,7 @@
 <!ENTITY UMASK                 SYSTEM "login.defs.d/UMASK.xml">
 <!ENTITY USERDEL_CMD           SYSTEM "login.defs.d/USERDEL_CMD.xml">
 <!ENTITY USERGROUPS_ENAB       SYSTEM "login.defs.d/USERGROUPS_ENAB.xml">
+<!ENTITY USE_TCB               SYSTEM "login.defs.d/USE_TCB.xml">
 ]>
 
 <refentry id='login.defs.5'>
@@ -195,6 +198,8 @@
       &SYS_UID_MAX; <!-- documents also SYS_UID_MIN -->
       &SYSLOG_SG_ENAB;
       &SYSLOG_SU_ENAB;
+      &TCB_AUTH_GROUP;
+      &TCB_SYMLINKS;
       &TTYGROUP;
       &TTYTYPE_FILE;
       &UID_MAX; <!-- documents also UID_MIN -->
@@ -202,6 +207,7 @@
       &UMASK;
       &USERDEL_CMD;
       &USERGROUPS_ENAB;
+      &USE_TCB;
     </variablelist>
   </refsect1>
 
@@ -381,16 +387,27 @@
 	<listitem>
 	  <para>
 	    PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE
+	    <phrase condition="tcb">USE_TCB</phrase>
 	  </para>
 	</listitem>
       </varlistentry>
       <varlistentry>
 	<term>pwconv</term>
 	<listitem>
-	  <para>PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE</para>
+	  <para>
+	    PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE
+	    <phrase condition="tcb">USE_TCB</phrase>
+	  </para>
 	</listitem>
       </varlistentry>
-      <!-- pwunconv: no variables -->
+      <varlistentry condition="tcb">
+	<term>pwunconv</term>
+	<listitem>
+	  <para>
+	    <phrase condition="tcb">USE_TCB</phrase>
+	  </para>
+	</listitem>
+      </varlistentry>
       <varlistentry>
 	<term>su</term>
 	<listitem>
@@ -427,6 +444,7 @@
 	    PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE
 	    SYS_GID_MAX SYS_GID_MIN SYS_UID_MAX SYS_UID_MIN UID_MAX UID_MIN
 	    UMASK
+	    <phrase condition="tcb">TCB_AUTH_GROUP TCB_SYMLINK USE_TCB</phrase>
 	  </para>
 	</listitem>
       </varlistentry>
@@ -436,6 +454,7 @@
 	  <para>
 	    MAIL_DIR MAIL_FILE MAX_MEMBERS_PER_GROUP USERDEL_CMD
 	    USERGROUPS_ENAB
+	    <phrase condition="tcb">USE_TCB</phrase>
 	  </para>
 	</listitem>
       </varlistentry>
@@ -444,10 +463,18 @@
 	<listitem>
 	  <para>
 	    MAIL_DIR MAIL_FILE MAX_MEMBERS_PER_GROUP
+	    <phrase condition="tcb">USE_TCB</phrase>
 	  </para>
 	</listitem>
       </varlistentry>
-      <!-- vipw / vigr: no variables (MAX_MEMBERS_PER_GROUP linked but not used) -->
+      <varlistentry condition="tcb">
+	<term>vipw</term>
+	<listitem>
+	  <para>
+	    <phrase condition="tcb">USE_TCB</phrase>
+	  </para>
+	</listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 

Added: upstream/trunk/man/login.defs.d/TCB_AUTH_GROUP.xml
===================================================================
--- upstream/trunk/man/login.defs.d/TCB_AUTH_GROUP.xml	                        (rev 0)
+++ upstream/trunk/man/login.defs.d/TCB_AUTH_GROUP.xml	2010-03-04 18:11:13 UTC (rev 3095)
@@ -0,0 +1,37 @@
+<!--
+   Copyright (c) 2010, Pawel Hajdan
+   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.
+-->
+<varlistentry condition="tcb">
+  <term><option>TCB_AUTH_GROUP</option> (boolean)</term>
+  <listitem>
+    <para>
+      If <replaceable>yes</replaceable>, newly created tcb shadow files
+      will be group owned by the <replaceable>auth</replaceable> group.
+    </para>
+  </listitem>
+</varlistentry>

Added: upstream/trunk/man/login.defs.d/TCB_SYMLINKS.xml
===================================================================
--- upstream/trunk/man/login.defs.d/TCB_SYMLINKS.xml	                        (rev 0)
+++ upstream/trunk/man/login.defs.d/TCB_SYMLINKS.xml	2010-03-04 18:11:13 UTC (rev 3095)
@@ -0,0 +1,53 @@
+<!--
+   Copyright (c) 2010, Pawel Hajdan
+   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.
+-->
+<varlistentry condition="tcb">
+  <term><option>TCB_SYMLINKS</option> (boolean)</term>
+  <listitem>
+    <para>
+      If <replaceable>yes</replaceable>, the location of the user tcb
+      directory to be created will not be automatically set to /etc/tcb/user,
+      but will be computed depending on the UID of the user, according to
+      the following algorithm:
+      <programlisting>
+if ( UID is less than 1000) {
+  use /etc/tcb/user
+} else if ( UID is less than 1000000) {
+  kilos = UID / 1000
+  use /etc/tcb/:kilos/user
+  make symlink /etc/tcb/user to the above directory
+} else {
+  megas = UID / 1000000
+  kilos = ( UID / megas * 1000000 ) / 1000
+  use /etc/tcb/:megas/:kilos/user
+  make symlink /etc/tcb/user to the above directory
+}
+      </programlisting>
+    </para>
+  </listitem>
+</varlistentry>

Added: upstream/trunk/man/login.defs.d/USE_TCB.xml
===================================================================
--- upstream/trunk/man/login.defs.d/USE_TCB.xml	                        (rev 0)
+++ upstream/trunk/man/login.defs.d/USE_TCB.xml	2010-03-04 18:11:13 UTC (rev 3095)
@@ -0,0 +1,38 @@
+<!--
+   Copyright (c) 2010, Pawel Hajdan
+   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.
+-->
+<varlistentry condition="tcb">
+  <term><option>USE_TCB</option> (boolean)</term>
+  <listitem>
+    <para>
+      If <replaceable>yes</replaceable>, the <citerefentry>
+      <refentrytitle>tcb</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      password shadowing scheme will be used.
+    </para>
+  </listitem>
+</varlistentry>

Modified: upstream/trunk/man/vipw.8.xml
===================================================================
--- upstream/trunk/man/vipw.8.xml	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/man/vipw.8.xml	2010-03-04 18:11:13 UTC (rev 3095)
@@ -117,6 +117,12 @@
 	  <para>Edit shadow or gshadow database.</para>
 	</listitem>
       </varlistentry>
+      <varlistentry condition="tcb">
+	<term><option>-u</option>, <option>--user</option></term>
+	<listitem>
+	  <para>Indicates which user's tcb shadow file to edit.</para>
+	</listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
@@ -165,6 +171,9 @@
       <citerefentry>
 	<refentrytitle>passwd</refentrytitle><manvolnum>5</manvolnum>
       </citerefentry>,
+      <citerefentry condition="tcb">
+	<refentrytitle>tcb</refentrytitle><manvolnum>5</manvolnum>
+      </citerefentry>,
       <citerefentry>
 	<refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum>
       </citerefentry>.

Modified: upstream/trunk/src/Makefile.am
===================================================================
--- upstream/trunk/src/Makefile.am	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/src/Makefile.am	2010-03-04 18:11:13 UTC (rev 3095)
@@ -5,6 +5,7 @@
 ubindir = ${prefix}/bin
 usbindir = ${prefix}/sbin
 suidperms = 4755
+sgidperms = 2755
 
 INCLUDES = \
 	-I${top_srcdir}/lib \
@@ -53,7 +54,13 @@
 	suidubins += chage chgpasswd chpasswd groupadd groupdel groupmod newusers useradd userdel usermod
 endif
 
+if WITH_TCB
+suidubins -= passwd
+shadowsgidubins = passwd
+endif
+
 LDADD          = $(INTLLIBS) \
+		 $(LIBTCB) \
 		 $(top_builddir)/libmisc/libmisc.a \
 		 $(top_builddir)/lib/libshadow.la
 AM_CPPFLAGS    = -DLOCALEDIR=\"$(datadir)/locale\"
@@ -114,3 +121,9 @@
 	for i in $(suidubins); do \
 		chmod -f $(suidperms) $(DESTDIR)$(ubindir)/$$i; \
 	done
+if WITH_TCB
+	for i in $(shadowsgidubins); do \
+		chown root:shadow $(DESTDIR)$(ubindir)/$$i; \
+		chmod -f $(sgidperms) $(DESTDIR)$(ubindir)/$$i; \
+	done
+endif

Modified: upstream/trunk/src/chage.c
===================================================================
--- upstream/trunk/src/chage.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/src/chage.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -56,6 +56,9 @@
 #include "defines.h"
 #include "pwio.h"
 #include "shadowio.h"
+#ifdef WITH_TCB
+#include "tcbfuncs.h"
+#endif
 /*@-exitarg@*/
 #include "exitcodes.h"
 
@@ -853,6 +856,10 @@
 	}
 
 	STRFCPY (user_name, pw->pw_name);
+#ifdef WITH_TCB
+	if (!shadowtcb_set_user(pw->pw_name))
+		fail_exit(E_NOPERM);
+#endif
 	user_uid = pw->pw_uid;
 
 	sp = spw_locate (argv[optind]);

Modified: upstream/trunk/src/pwconv.c
===================================================================
--- upstream/trunk/src/pwconv.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/src/pwconv.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -133,6 +133,11 @@
 
 	OPENLOG ("pwconv");
 
+	if (getdef_bool("USE_TCB")) {
+		fprintf(stderr, _("%s: can't work with tcb enabled\n"), Prog);
+		fail_exit(E_FAILURE);
+	}
+
 	if (pw_lock () == 0) {
 		fprintf (stderr,
 		         _("%s: cannot lock %s; try again later.\n"),

Modified: upstream/trunk/src/pwunconv.c
===================================================================
--- upstream/trunk/src/pwunconv.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/src/pwunconv.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -93,6 +93,11 @@
 
 	OPENLOG ("pwunconv");
 
+	if (getdef_bool("USE_TCB")) {
+		fprintf(stderr, _("%s: can't work with tcb enabled\n"), Prog);
+		exit(1);
+	}
+
 	if (!spw_file_present ()) {
 		/* shadow not installed, do nothing */
 		exit (0);

Modified: upstream/trunk/src/useradd.c
===================================================================
--- upstream/trunk/src/useradd.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/src/useradd.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -65,6 +65,9 @@
 #include "sgroupio.h"
 #endif
 #include "shadowio.h"
+#ifdef WITH_TCB
+#include "tcbfuncs.h"
+#endif
 
 #ifndef SKEL_DIR
 #define SKEL_DIR "/etc/skel"
@@ -192,6 +195,7 @@
 static void process_flags (int argc, char **argv);
 static void close_files (void);
 static void open_files (void);
+static void open_shadow (void);
 static void faillog_reset (uid_t);
 static void lastlog_reset (uid_t);
 static void usr_update (void);
@@ -1429,22 +1433,9 @@
 		fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ());
 		fail_exit (E_PW_UPDATE);
 	}
-	if (is_shadow_pwd) {
-		if (spw_lock () == 0) {
-			fprintf (stderr,
-			         _("%s: cannot lock %s; try again later.\n"),
-			         Prog, spw_dbname ());
-			fail_exit (E_PW_UPDATE);
-		}
-		spw_locked = true;
-		if (spw_open (O_RDWR) == 0) {
-			fprintf (stderr,
-			         _("%s: cannot open %s\n"),
-			         Prog, spw_dbname ());
-			fail_exit (E_PW_UPDATE);
-		}
-	}
 
+	/* shadow file will be opened by open_shadow(); */
+
 	/*
 	 * Lock and open the group file.
 	 */
@@ -1478,6 +1469,25 @@
 #endif
 }
 
+static void open_shadow (void)
+{
+	if (!is_shadow_pwd)
+		return;
+	if (!spw_lock ()) {
+		fprintf(stderr,
+			_("%s: cannot lock shadow password file\n"),
+			Prog);
+		fail_exit(E_PW_UPDATE);
+	}
+	spw_locked = true;
+	if (!spw_open (O_RDWR)) {
+		fprintf(stderr,
+			_("%s: cannot open shadow password file\n"),
+			Prog);
+		fail_exit(E_PW_UPDATE);
+	}
+}
+
 static char *empty_list = NULL;
 
 /*
@@ -1990,6 +2000,16 @@
 		}
 	}
 
+#ifdef WITH_TCB
+	if (getdef_bool("USE_TCB")) {
+		if (!shadowtcb_create(user_name, user_id)) {
+			fprintf(stderr, "Failed to create tcb directory for %s\n", user_name);
+			fail_exit (E_UID_IN_USE);
+		}
+	}
+#endif
+	open_shadow();
+
 	/* do we have to add a group for that user? This is why we need to
 	 * open the group files in the open_files() function  --gafton */
 	if (Uflg) {

Modified: upstream/trunk/src/userdel.c
===================================================================
--- upstream/trunk/src/userdel.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/src/userdel.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -59,6 +59,10 @@
 #ifdef	SHADOWGRP
 #include "sgroupio.h"
 #endif
+#ifdef WITH_TCB
+#include <tcb.h>
+#include "tcbfuncs.h"
+#endif
 /*@-exitarg@*/
 #include "exitcodes.h"
 
@@ -107,6 +111,9 @@
 #endif
 static int is_owner (uid_t, const char *);
 static int remove_mailbox (void);
+#ifdef WITH_TCB
+static int remove_tcbdir (const char *user_name, uid_t user_id);
+#endif
 
 /*
  * usage - display usage message and exit
@@ -731,6 +738,49 @@
 	return errors;
 }
 
+#ifdef WITH_TCB
+static int remove_tcbdir (const char *user_name, uid_t user_id)
+{
+	char *buf;
+	int ret = 0;
+
+	if (!getdef_bool("USE_TCB"))
+		return 0;
+	
+	buf = malloc(strlen(TCB_DIR) + strlen(user_name) + 2);
+	if (!buf) {
+		fprintf(stderr, "Can't allocate memory, "
+			"tcb entry for %s not removed.\n",
+			user_name);
+		return 1;
+	}
+	snprintf(buf, strlen(TCB_DIR) + strlen(user_name) + 2,
+		TCB_DIR "/%s", user_name);
+	if (!shadowtcb_drop_priv()) {
+		perror("shadowtcb_drop_priv");
+		free(buf);
+		return 1;
+	}
+	/* Only remove directory contents with dropped privileges.
+	 * We will regain them and remove the user's tcb directory afterwards.
+	 */
+	if (remove_tree(buf, false)) {
+		perror("remove_tree");
+		shadowtcb_gain_priv();
+		free(buf);
+		return 1;
+	}
+	shadowtcb_gain_priv();
+	free(buf);
+	if (!shadowtcb_remove(user_name)) {
+		fprintf(stderr, "Cannot remove tcb files for %s: %s\n",
+			user_name, strerror(errno));
+		ret = 1;
+	}
+	return ret;
+}
+#endif
+
 /*
  * main - userdel command
  */
@@ -851,6 +901,10 @@
 		user_id = pwd->pw_uid;
 		user_home = xstrdup (pwd->pw_dir);
 	}
+#ifdef WITH_TCB
+	if (!shadowtcb_set_user(user_name))
+		exit (E_NOTFOUND);
+#endif
 #ifdef	USE_NIS
 
 	/*
@@ -951,7 +1005,7 @@
 #endif
 
 	if (rflg) {
-		if (remove_tree (user_home) != 0) {
+		if (remove_tree (user_home, true) != 0) {
 			fprintf (stderr,
 				 _("%s: error removing directory %s\n"),
 				 Prog, user_home);
@@ -996,6 +1050,10 @@
 	user_cancel (user_name);
 	close_files ();
 
+#ifdef WITH_TCB
+	errors += remove_tcbdir(user_name, user_id);
+#endif
+
 	nscd_flush_cache ("passwd");
 	nscd_flush_cache ("group");
 

Modified: upstream/trunk/src/usermod.c
===================================================================
--- upstream/trunk/src/usermod.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/src/usermod.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -63,6 +63,9 @@
 #include "sgroupio.h"
 #endif
 #include "shadowio.h"
+#ifdef WITH_TCB
+#include "tcbfuncs.h"
+#endif
 
 /*
  * exit status values
@@ -1438,7 +1441,7 @@
 				if (copy_tree (user_home, user_newhome,
 				               uflg ? (long int)user_newid : -1,
 				               gflg ? (long int)user_newgid : -1) == 0) {
-					if (remove_tree (user_home) != 0) {
+					if (remove_tree (user_home, true) != 0) {
 						fprintf (stderr,
 						         _("%s: warning: failed to completely remove old home directory %s"),
 						         Prog, user_home);
@@ -1456,7 +1459,7 @@
 
 				/* TODO: do some cleanup if the copy
 				 *       was started */
-				(void) remove_tree (user_newhome);
+				(void) remove_tree (user_newhome, true);
 			}
 			fprintf (stderr,
 			         _("%s: cannot rename directory %s to %s\n"),
@@ -1655,7 +1658,7 @@
 		return;
 	}
 	if (uflg) {
-		if (fchown (fd, user_newid, (gid_t) - 1) < 0) {
+		if (fchown (fd, user_newid, (gid_t) -1) < 0) {
 			perror (_("failed to change mailbox owner"));
 		}
 #ifdef WITH_AUDIT
@@ -1770,6 +1773,11 @@
 #endif				/* USE_PAM */
 #endif				/* ACCT_TOOLS_SETUID */
 
+#ifdef WITH_TCB
+	if (!shadowtcb_set_user(user_name))
+		exit(E_PW_UPDATE);
+#endif
+
 	/*
 	 * Do the hard stuff - open the files, change the user entries,
 	 * change the home directory, then close and update the files.
@@ -1784,6 +1792,13 @@
 	}
 	close_files ();
 
+#ifdef WITH_TCB
+	if ((user_newname || user_newid != -1) &&
+		!shadowtcb_move(user_newname, user_newid)) {
+		exit(E_PW_UPDATE);
+	}
+#endif
+
 	nscd_flush_cache ("passwd");
 	nscd_flush_cache ("group");
 

Modified: upstream/trunk/src/vipw.c
===================================================================
--- upstream/trunk/src/vipw.c	2010-01-24 17:30:36 UTC (rev 3094)
+++ upstream/trunk/src/vipw.c	2010-03-04 18:11:13 UTC (rev 3095)
@@ -48,6 +48,10 @@
 #include "shadowio.h"
 /*@-exitarg@*/
 #include "exitcodes.h"
+#ifdef WITH_TCB
+#include <tcb.h>
+#include "tcbfuncs.h"
+#endif
 
 #define MSG_WARN_EDIT_OTHER_FILE _( \
 	"You have modified %s.\n"\
@@ -62,6 +66,8 @@
 static bool createedit = false;
 static int (*unlock) (void);
 static bool quiet = false;
+static const char *user = NULL;
+static bool tcb_mode = false;
 
 /* local function prototypes */
 static void usage (int status);
@@ -83,6 +89,9 @@
 	         "  -p, --passwd                  edit passwd database\n"
 	         "  -q, --quiet                   quiet mode\n"
 	         "  -s, --shadow                  edit shadow or gshadow database\n"
+#ifdef WITH_TCB
+	         "  -u, --user                    which user's tcb shadow file to edit\n"
+#endif
 	         "\n"), (E_SUCCESS != status) ? stderr : stdout);
 	exit (status);
 }
@@ -175,6 +184,8 @@
 #define DEFAULT_EDITOR "vi"
 #endif
 
+#define SHADOWTCB_SCRATCHDIR ":tmp"
+
 /*
  *
  */
@@ -187,9 +198,23 @@
 	int status;
 	FILE *f;
 	char filebackup[1024], fileedit[1024];
+	char *to_rename;
 
 	snprintf (filebackup, sizeof filebackup, "%s-", file);
-	snprintf (fileedit, sizeof fileedit, "%s.edit", file);
+#ifdef WITH_TCB
+	if (tcb_mode) {
+		if (mkdir(TCB_DIR "/" SHADOWTCB_SCRATCHDIR, 0700) && errno != EEXIST)
+			vipwexit (_("failed to create scratch directory"), errno, 1);
+		if (!shadowtcb_drop_priv())
+			vipwexit (_("failed to drop privileges"), errno, 1);
+		snprintf(fileedit, sizeof fileedit,
+			TCB_DIR "/" SHADOWTCB_SCRATCHDIR "/.vipw.shadow.%s", user);
+	} else {
+#endif
+		snprintf (fileedit, sizeof fileedit, "%s.edit", file);
+#ifdef WITH_TCB
+	}
+#endif
 	unlock = file_unlock;
 	filename = file;
 	fileeditname = fileedit;
@@ -213,10 +238,18 @@
 		}
 	}
 #endif
+#ifdef WITH_TCB
+	if (tcb_mode && !shadowtcb_gain_priv())
+		vipwexit (_("failed to gain privileges"), errno, 1);
+#endif
 	if (file_lock () == 0) {
 		vipwexit (_("Couldn't lock file"), errno, 5);
 	}
 	filelocked = true;
+#ifdef WITH_TCB
+	if (tcb_mode && !shadowtcb_drop_priv())
+		vipwexit (_("failed to drop privileges"), errno, 1);
+#endif
 
 	/* edited copy has same owners, perm */
 	if (stat (file, &st1) != 0) {
@@ -226,6 +259,10 @@
 	if (NULL == f) {
 		vipwexit (file, 1, 1);
 	}
+#ifdef WITH_TCB
+	if (tcb_mode && !shadowtcb_gain_priv())
+		vipwexit (_("failed to gain privileges"), errno, 1);
+#endif
 	if (create_backup_file (f, fileedit, &st1) != 0) {
 		vipwexit (_("Couldn't make backup"), errno, 1);
 	}
@@ -300,15 +337,49 @@
 	 * without saving). Use pwck or grpck to do the check.  --marekm
 	 */
 	createedit = false;
+#ifdef WITH_TCB
+	if (tcb_mode) {
+		if (!(f = fopen(fileedit, "r")))
+			vipwexit (_("failed to open scratch file"), errno, 1);
+		if (unlink(fileedit))
+			vipwexit (_("failed to unlink scratch file"), errno, 1);
+		if (!shadowtcb_drop_priv())
+			vipwexit (_("failed to drop privileges"), errno, 1);
+		if (stat(file, &st1))
+			vipwexit (_("failed to stat edited file"), errno, 1);
+		to_rename = malloc(strlen(file) + 2);
+		if (!to_rename)
+			vipwexit (_("failed to allocate memory"), errno, 1);
+		snprintf(to_rename, strlen(file) + 2, "%s+", file);
+		if (create_backup_file(f, to_rename, &st1)) {
+			free(to_rename);
+			vipwexit (_("failed to create backup file"), errno, 1);
+		}
+	} else {
+#endif
+		to_rename = fileedit;
+#ifdef WITH_TCB
+	}
+#endif
 	unlink (filebackup);
 	link (file, filebackup);
-	if (rename (fileedit, file) == -1) {
+	if (rename (to_rename, file) == -1) {
 		fprintf (stderr,
 		         _("%s: can't restore %s: %s (your changes are in %s)\n"),
-		         progname, file, strerror (errno), fileedit);
+		         progname, file, strerror (errno), to_rename);
+		if (tcb_mode)
+			free(to_rename);
 		vipwexit (0, 0, 1);
 	}
 
+#ifdef WITH_TCB
+	if (tcb_mode) {
+		free(to_rename);
+		if (!shadowtcb_gain_priv())
+			vipwexit (_("failed to gain privileges"), errno, 1);
+	}
+#endif
+
 	if ((*file_unlock) () == 0) {
 		fprintf (stderr, _("%s: failed to unlock %s\n"), progname, fileeditname);
 		SYSLOG ((LOG_ERR, "failed to unlock %s", fileeditname));
@@ -343,11 +414,18 @@
 			{"passwd", no_argument, NULL, 'p'},
 			{"quiet", no_argument, NULL, 'q'},
 			{"shadow", no_argument, NULL, 's'},
+#ifdef WITH_TCB
+			{"user", required_argument, NULL, 'u'},
+#endif
 			{NULL, 0, NULL, '\0'}
 		};
-		while ((c =
-			getopt_long (argc, argv, "ghpqs",
-				     long_options, NULL)) != -1) {
+		while ((c = getopt_long (argc, argv,
+#ifdef WITH_TCB
+				"ghpqsu:",
+#else
+				"ghpqs",
+#endif
+				long_options, NULL)) != -1) {
 			switch (c) {
 			case 'g':
 				do_vipw = false;
@@ -364,6 +442,9 @@
 			case 's':
 				editshadow = true;
 				break;
+			case 'u':
+				user = optarg;
+				break;
 			default:
 				usage (E_USAGE);
 			}
@@ -372,9 +453,20 @@
 
 	if (do_vipw) {
 		if (editshadow) {
-			vipwedit (SHADOW_FILE, spw_lock, spw_unlock);
+#ifdef WITH_TCB
+			if (getdef_bool("USE_TCB") && user) {
+				if (!shadowtcb_set_user(user)) {
+					fprintf (stderr,
+						_("%s: failed to find tcb directory for %s\n"),
+						progname, user);
+					return E_SHADOW_NOTFOUND;
+				}
+				tcb_mode = true;
+			}
+#endif
+			vipwedit (spw_dbname (), spw_lock, spw_unlock);
 			printf (MSG_WARN_EDIT_OTHER_FILE,
-			        SHADOW_FILE,
+			        spw_dbname (),
 			        PASSWD_FILE,
 			        "vipw");
 		} else {




More information about the Pkg-shadow-commits mailing list