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.
This commit is contained in:
nekral-guest 2010-03-04 18:11:13 +00:00
parent 5ba95d4c53
commit 391a384715
27 changed files with 1067 additions and 44 deletions

View File

@ -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
@ -12,11 +35,11 @@
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.

1
NEWS
View File

@ -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.

View 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

View 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:
#

View 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

View 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}
};

View 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);

View File

@ -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 @@ 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 ());
}

501
lib/tcbfuncs.c Normal file
View File

@ -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;
}

13
lib/tcbfuncs.h Normal file
View File

@ -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

View 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;
}

View 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

View 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

View 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

View 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'>
@ -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>
<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>
@ -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>
<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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>.

View 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

View 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]);

View 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"),

View 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);

View 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) {

View File

@ -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 @@ 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");

View 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");

View File

@ -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 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 {