]> granicus.if.org Git - shadow/commitdiff
2010-01-30 Paweł Hajdan, Jr. <phajdan.jr@gentoo.org>
authornekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Thu, 4 Mar 2010 18:11:13 +0000 (18:11 +0000)
committernekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Thu, 4 Mar 2010 18:11:13 +0000 (18:11 +0000)
* 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.

27 files changed:
ChangeLog
NEWS
configure.in
lib/Makefile.am
lib/commonio.c
lib/getdef.c
lib/prototypes.h
lib/shadowio.c
lib/tcbfuncs.c [new file with mode: 0644]
lib/tcbfuncs.h [new file with mode: 0644]
libmisc/copydir.c
man/Makefile.am
man/generate_mans.deps
man/generate_mans.mak
man/login.defs.5.xml
man/login.defs.d/TCB_AUTH_GROUP.xml [new file with mode: 0644]
man/login.defs.d/TCB_SYMLINKS.xml [new file with mode: 0644]
man/login.defs.d/USE_TCB.xml [new file with mode: 0644]
man/vipw.8.xml
src/Makefile.am
src/chage.c
src/pwconv.c
src/pwunconv.c
src/useradd.c
src/userdel.c
src/usermod.c
src/vipw.c

index 6a0095d7941dde1448845caeeb4f7cb958355702..5940ba7445c39836a0098d1b2a2c7437c4c2fcea 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,32 @@
-2009-01-24  Nicolas François  <nicolas.francois@centraliens.net>
+2010-01-30  Paweł Hajdan, Jr.  <phajdan.jr@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@centraliens.net>
 
        * libmisc/env.c: Fix sanitize_env() noslash support. This fixes
        Alioth#311740.
 
-2009-01-24  Nicolas François  <nicolas.francois@centraliens.net>
+2010-01-24  Nicolas François  <nicolas.francois@centraliens.net>
 
        * src/su.c: Do not sanitize the environment. This breaks
        --preserve-environment. This sanitation was disabled on Debian
        Unixes will handle setuid executables properly. This fixes
        Alioth#312287.
 
-2009-01-24  Nicolas François  <nicolas.francois@centraliens.net>
+2010-01-24  Nicolas François  <nicolas.francois@centraliens.net>
 
        * libmisc/setupenv.c: Fix typo from 2009-11-01.
 
-2009-01-24  Paweł Hajdan, Jr.  <phajdan.jr@gentoo.org>
+2010-01-24  Paweł Hajdan, Jr.  <phajdan.jr@gentoo.org>
 
        * configure.in: Add support for TCB in configure.in. Actual TCB
        support will follow.
diff --git a/NEWS b/NEWS
index 474ef8b083305d86c866e5a7e0036fd32a30551c..9d4bebfe20bcd053c2e1b068b27a1432e3c0e819 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ shadow-4.1.4.2 -> shadow-4.1.4.3                                        UNRELEASED
 - 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.
index 4d634f19ad6f97457b3ea2f03828c3d94003ca07..f99ab2c7c57e4847fa4e99c5b118fa4283775222 100644 (file)
@@ -405,6 +405,7 @@ if test "$with_tcb" != "no"; then
                with_tcb="no"
        fi
 fi
+AM_CONDITIONAL(WITH_TCB, test x$with_tcb = xyes)
 
 AC_SUBST(LIBPAM)
 if test "$with_libpam" != "no"; then
index 024297ef8972c0284f58830aa4f054510e633177..ee7ec6ee89906392c6ccac22c030719be275ad57 100644 (file)
@@ -49,6 +49,10 @@ libshadow_la_SOURCES = \
        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:
 #
index 3850da121c0c4be7b58573819ebd3a848ea5d13f..618a80e1acb58bf8b89120c142e26c4c3830316e 100644 (file)
@@ -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 @@ int commonio_open (struct commonio_db *db, int mode)
        void *eptr = NULL;
        int flags = mode;
        size_t buflen;
+       int fd;
        int saved_errno;
 
        mode &= ~O_CREAT;
@@ -553,7 +557,24 @@ int commonio_open (struct commonio_db *db, int mode)
        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
index c36dc15e8f2e6bee9ddd800ed459ae5412fb3478..19c756bd3c8782550f9a3b280462050ae03595a5 100644 (file)
@@ -123,6 +123,11 @@ static struct itemdef def_table[] = {
 #ifdef USE_SYSLOG
        {"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}
 };
index c61801915ee3236f71f60f9f3312ba3fc6342d1b..a4f524217adc9f341e0d3889058b4e606d3e39c0 100644 (file)
@@ -117,7 +117,7 @@ extern bool console (const char *);
 /* 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);
index 9ea6a55b0356b7f3cb1ff83fe73d8331466f12a6..cda02c2d4c7fd191410cc7454ccda8ce7be871b5 100644 (file)
 #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 @@ bool spw_file_present (void)
 
 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_rewind (void)
 
 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 @@ void __spw_del_entry (const struct commonio_entry *ent)
 /* 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 ());
 }
diff --git a/lib/tcbfuncs.c b/lib/tcbfuncs.c
new file mode 100644 (file)
index 0000000..fdbe93e
--- /dev/null
@@ -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;
+}
diff --git a/lib/tcbfuncs.h b/lib/tcbfuncs.h
new file mode 100644 (file)
index 0000000..51d4782
--- /dev/null
@@ -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
index ad3c99318bacdbef305116c564f87305eb963de8..3a67e75db400a6716d794b335c46c4e269ccb7b7 100644 (file)
@@ -668,7 +668,7 @@ static int copy_file (const char *src, const char *dst,
  *     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 @@ int remove_tree (const char *root)
                        /*
                         * Recursively delete this directory.
                         */
-                       if (remove_tree (new_name) != 0) {
+                       if (remove_tree (new_name, true) != 0) {
                                err = -1;
                                break;
                        }
@@ -740,7 +740,7 @@ int remove_tree (const char *root)
        }
        (void) closedir (dir);
 
-       if (0 == err) {
+       if (remove_root && 0 == err) {
                if (rmdir (root) != 0) {
                        err = -1;
                }
index a8e9a5a659e4c7e9b40fdd6dcb48aa47a7ae9818..850f15672ac40a1bd1ac92edb3eb0f6f22c4d508 100644 (file)
@@ -149,6 +149,8 @@ login_defs_v = \
        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 @@ login_defs_v = \
        UMASK.xml \
        USERDEL_CMD.xml \
        USERGROUPS_ENAB.xml \
+       USE_TCB.xml \
        SYS_GID_MAX.xml \
        SYS_UID_MAX.xml
 
index 264fa0acf60984820b7a4d7515cd6ed9e90eb3bd..32abd8fb4f17b43889a85b6b965cf6891ed4d760 100644 (file)
@@ -105,6 +105,8 @@ login.defs.5: login.defs.d/SYS_GID_MAX.xml
 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/ULIMIT.xml
 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
index 9d4c83e57a8abcaf9bbd6976f06252beaa86a6f0..82fcfcdb25d4f8bc1bdc07cbbcaff2dcb85aaa6a 100644 (file)
@@ -8,6 +8,11 @@ SHADOWGRP_COND=gshadow
 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 @@ endif
 
 %: %.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
index ece0c469044cb5705556a7beb9fb67838876718d..f7732c89dc515423089525facefebb1873674993 100644 (file)
@@ -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'>
       &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 -->
       &UMASK;
       &USERDEL_CMD;
       &USERGROUPS_ENAB;
+      &USE_TCB;
     </variablelist>
   </refsect1>
 
        <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>
+      <varlistentry condition="tcb">
+       <term>pwunconv</term>
+       <listitem>
+         <para>
+           <phrase condition="tcb">USE_TCB</phrase>
+         </para>
        </listitem>
       </varlistentry>
-      <!-- pwunconv: no variables -->
       <varlistentry>
        <term>su</term>
        <listitem>
            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>
          <para>
            MAIL_DIR MAIL_FILE MAX_MEMBERS_PER_GROUP USERDEL_CMD
            USERGROUPS_ENAB
+           <phrase condition="tcb">USE_TCB</phrase>
          </para>
        </listitem>
       </varlistentry>
        <listitem>
          <para>
            MAIL_DIR MAIL_FILE MAX_MEMBERS_PER_GROUP
+           <phrase condition="tcb">USE_TCB</phrase>
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry condition="tcb">
+       <term>vipw</term>
+       <listitem>
+         <para>
+           <phrase condition="tcb">USE_TCB</phrase>
          </para>
        </listitem>
       </varlistentry>
-      <!-- vipw / vigr: no variables (MAX_MEMBERS_PER_GROUP linked but not used) -->
     </variablelist>
   </refsect1>
 
diff --git a/man/login.defs.d/TCB_AUTH_GROUP.xml b/man/login.defs.d/TCB_AUTH_GROUP.xml
new file mode 100644 (file)
index 0000000..f9c9f72
--- /dev/null
@@ -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>
diff --git a/man/login.defs.d/TCB_SYMLINKS.xml b/man/login.defs.d/TCB_SYMLINKS.xml
new file mode 100644 (file)
index 0000000..76b34fb
--- /dev/null
@@ -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>
diff --git a/man/login.defs.d/USE_TCB.xml b/man/login.defs.d/USE_TCB.xml
new file mode 100644 (file)
index 0000000..6fbe4d9
--- /dev/null
@@ -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>
index d96fcf6960238fc670943472dba461986ef3bcd7..4557e9a597691840a211ef898e23ad77537899ee 100644 (file)
          <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>
 
       <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>.
index 6a3b4c5cfd7292b4d8068dd4d0ae7c814a163386..9bfd6ec07372ca4107cc7f70f5655c3d8e736b2f 100644 (file)
@@ -5,6 +5,7 @@ EXTRA_DIST = \
 ubindir = ${prefix}/bin
 usbindir = ${prefix}/sbin
 suidperms = 4755
+sgidperms = 2755
 
 INCLUDES = \
        -I${top_srcdir}/lib \
@@ -53,7 +54,13 @@ if ACCT_TOOLS_SETUID
        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 @@ install-am: all-am
        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
index f8b27b05f21abff8f2410d75d4590a1430fb57ba..4788a2026dfd877ba6f560272d5e1210aa46fb20 100644 (file)
@@ -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 @@ int main (int argc, char **argv)
        }
 
        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]);
index d0a1b399fd2752ed3c3aeab491135a148d0783a9..b59777bd71220542456501b274079ca55ed581a1 100644 (file)
@@ -133,6 +133,11 @@ int main (int argc, char **argv)
 
        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"),
index 7bc495653902312bb6165f8fb906d9b2a4aef4be..f49a9f7a2ef22081191df6875cb093af70926d10 100644 (file)
@@ -93,6 +93,11 @@ int main (int argc, char **argv)
 
        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);
index 3581b3784fad2cd73b8b8061fa857926f054faf3..cd83ad9e22cc66958c647be1f22f68eca9e070c9 100644 (file)
@@ -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 grp_update (void);
 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,21 +1433,8 @@ static void open_files (void)
                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 @@ static void open_files (void)
 #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 @@ int main (int argc, char **argv)
                }
        }
 
+#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) {
index d59eaeb4ba973fc6283726f37c766b74bad3ab83..3375db581c191e3758e23172244f701c64bc1e1a 100644 (file)
 #ifdef SHADOWGRP
 #include "sgroupio.h"
 #endif
+#ifdef WITH_TCB
+#include <tcb.h>
+#include "tcbfuncs.h"
+#endif
 /*@-exitarg@*/
 #include "exitcodes.h"
 
@@ -107,6 +111,9 @@ static bool path_prefix (const char *, const char *);
 #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 @@ static int remove_mailbox (void)
        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 @@ int main (int argc, char **argv)
                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 @@ int main (int argc, char **argv)
 #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 @@ int main (int argc, char **argv)
        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");
 
index ab92009ce8e4d50b2a57c82107d92eacd2d1e415..d12f5eaa3e4dbfd91a72945b33a6dd13152447d4 100644 (file)
@@ -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 @@ static void move_home (void)
                                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 @@ static void move_home (void)
 
                                /* 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 @@ static void move_mailbox (void)
                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 @@ int main (int argc, char **argv)
 #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 @@ int main (int argc, char **argv)
        }
        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");
 
index 746da8c13e2f2d2a3bc6d8a55676d0d322004f71..3c2d3fd2b764ba4a80b44cd7d6c4101c14b242f2 100644 (file)
 #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 filelocked = false;
 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 @@ static void usage (int status)
                 "  -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 @@ static void vipwexit (const char *msg, int syserr, int ret)
 #define DEFAULT_EDITOR "vi"
 #endif
 
+#define SHADOWTCB_SCRATCHDIR ":tmp"
+
 /*
  *
  */
@@ -187,9 +198,23 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
        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;
@@ -212,11 +237,19 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
                        vipwexit (_("setfscreatecon () failed"), errno, 1);
                }
        }
+#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 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
        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 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
         * 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 @@ int main (int argc, char **argv)
                        {"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 @@ int main (int argc, char **argv)
                        case 's':
                                editshadow = true;
                                break;
+                       case 'u':
+                               user = optarg;
+                               break;
                        default:
                                usage (E_USAGE);
                        }
@@ -372,9 +453,20 @@ int main (int argc, char **argv)
 
        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 {