From 6e6494680d1f20a13cddaf73edc0af43a4a7b03f Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Sat, 18 Apr 2020 19:17:51 -0500 Subject: [PATCH 1/5] trivial: drop useless version-info from libshadow_la_LDFLAGS Signed-off-by: Serge Hallyn --- lib/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index a40c08a1..f9ae3c4c 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -5,7 +5,6 @@ DEFS = noinst_LTLIBRARIES = libshadow.la -libshadow_la_LDFLAGS = -version-info 0:0:0 libshadow_la_CPPFLAGS = $(ECONF_CPPFLAGS) if HAVE_VENDORDIR libshadow_la_CPPFLAGS += -DVENDORDIR=\"$(VENDORDIR)\" From 316a153abb553fbcff722924a3877c312717227a Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Sat, 18 Apr 2020 23:32:59 -0500 Subject: [PATCH 2/5] tests: use git to determine top_dir Signed-off-by: Serge Hallyn --- tests/common/config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common/config.sh b/tests/common/config.sh index 9b504852..b92436c5 100644 --- a/tests/common/config.sh +++ b/tests/common/config.sh @@ -2,7 +2,7 @@ set -e -build_path=/root/build/shadow-4.1.5/ +build_path=$(git rev-parse --show-toplevel) # Save the configuration files in tmp. save_config () From 089cf55e2c35d2c3ae98b3a8adfe24019f8950e4 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Fri, 24 Apr 2020 16:41:34 -0500 Subject: [PATCH 3/5] drop svn complications from test runner Signed-off-by: Serge Hallyn --- tests/common/config.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/common/config.sh b/tests/common/config.sh index b92436c5..ea66ef3c 100644 --- a/tests/common/config.sh +++ b/tests/common/config.sh @@ -8,7 +8,7 @@ build_path=$(git rev-parse --show-toplevel) save_config () { [ ! -d tmp ] && mkdir tmp - find config -depth -path "*/.svn/*" -prune -o -type f -print | sed -e 's/config\///' | + find config -depth -type f -print | sed -e 's/config\///' | while read file do mkdir -p "tmp/$(dirname "$file")" @@ -19,7 +19,7 @@ save_config () # Copy the config files from config to the system change_config () { - find config -depth -path "*/.svn/*" -prune -o -type f -print | sed -e 's/config\///' | + find config -depth -type f -print | sed -e 's/config\///' | while read file do cp -f "config/$file" "/$file" @@ -30,7 +30,7 @@ change_config () # The config files must be saved before with save_config (). restore_config () { - find config -depth -path "*/.svn/*" -prune -o -type f -print | sed -e 's/config\///' | + find config -depth -type f -print | sed -e 's/config\///' | while read file do if [ -f "tmp/$file" ]; then @@ -54,7 +54,6 @@ prepare_chroot () { mkdir tmp/root cp -rfdp config_chroot/* tmp/root/ - find tmp/root/ -name .svn -type d -print0 | xargs -0 rm -rf lists=/root/tests/common/config_chroot.list [ -f config_chroot.list ] && lists="$lists config_chroot.list" From 43a917cce54019799a8de037fd63780a2b640afc Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Sat, 18 Apr 2020 14:57:56 -0500 Subject: [PATCH 4/5] configure: define abi versions Signed-off-by: Serge Hallyn --- configure.ac | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e4c6aaec..b8bc2b7a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,11 +1,21 @@ dnl Process this file with autoconf to produce a configure script. -AC_PREREQ([2.64]) +AC_PREREQ([2.69]) +m4_define([libsubid_abi_major], 1) +m4_define([libsubid_abi_minor], 0) +m4_define([libsubid_abi_micro], 0) +m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro]) AC_INIT([shadow], [4.8.1], [pkg-shadow-devel@lists.alioth.debian.org], [], [https://github.com/shadow-maint/shadow]) AM_INIT_AUTOMAKE([1.11 foreign dist-xz]) +AC_CONFIG_MACRO_DIRS([m4]) AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS([config.h]) +AC_SUBST([LIBSUBID_ABI_MAJOR], [libsubid_abi_major]) +AC_SUBST([LIBSUBID_ABI_MINOR], [libsubid_abi_minor]) +AC_SUBST([LIBSUBID_ABI_MICRO], [libsubid_abi_micro]) +AC_SUBST([LIBSUBID_ABI], [libsubid_abi]) + dnl Some hacks... test "$prefix" = "NONE" && prefix="/usr" test "$prefix" = "/usr" && exec_prefix="" From 0a7888b1fad613a052b988b01a71933b67296e68 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Sat, 18 Apr 2020 18:03:54 -0500 Subject: [PATCH 5/5] Create a new libsubid Closes #154 Currently this has three functions: one which returns the list of subuid ranges for a user, one returning the subgids, and one which frees the ranges lists. I might be mistaken about what -disable-man means; some of the code suggests it means just don't re-generate them, but not totally ignore them. But that doesn't seem to really work, so let's just ignore man/ when -disable-man. Remove --disable-shared. I'm not sure why it was there, but it stems from long, long ago, and I suspect it comes from some ancient toolchain bug. Create a tests/run_some, a shorter version of run_all. I'll slowly add tests to this as I verify they work, then I can work on fixing the once which don't. Also, don't touch man/ if not -enable-man. Changelog: Apr 22: change the subid list api as recomended by Dan Walsh. Apr 23: implement get_subid_owner Apr 24: implement range add/release Apr 25: finish tests and rebase May 10: make @owner const Signed-off-by: Serge Hallyn --- .travis.yml | 12 +- Makefile.am | 13 +- autogen.sh | 2 +- configure.ac | 3 +- lib/subordinateio.c | 204 +++++++++++++++- lib/subordinateio.h | 7 + libsubid/Makefile.am | 25 ++ libsubid/api.c | 231 ++++++++++++++++++ libsubid/api.h | 17 ++ libsubid/subid.h | 17 ++ src/.gitignore | 4 + src/Makefile.am | 60 +++++ src/free_subid_range.c | 50 ++++ src/get_subid_owners.c | 40 +++ src/list_subid_ranges.c | 41 ++++ src/new_subid_range.c | 57 +++++ tests/libsubid/01_list_ranges/config.txt | 0 .../libsubid/01_list_ranges/config/etc/subgid | 2 + .../libsubid/01_list_ranges/config/etc/subuid | 3 + .../libsubid/01_list_ranges/list_ranges.test | 38 +++ tests/libsubid/02_get_subid_owners/config.txt | 0 .../02_get_subid_owners/config/etc/passwd | 20 ++ .../02_get_subid_owners/config/etc/subgid | 2 + .../02_get_subid_owners/config/etc/subuid | 4 + .../02_get_subid_owners/get_subid_owners.test | 52 ++++ .../03_add_remove/add_remove_subids.test | 59 +++++ tests/libsubid/03_add_remove/config.txt | 0 .../libsubid/03_add_remove/config/etc/passwd | 20 ++ .../libsubid/03_add_remove/config/etc/subgid | 2 + .../libsubid/03_add_remove/config/etc/subuid | 1 + tests/run_some | 136 +++++++++++ 31 files changed, 1105 insertions(+), 17 deletions(-) create mode 100644 libsubid/Makefile.am create mode 100644 libsubid/api.c create mode 100644 libsubid/api.h create mode 100644 libsubid/subid.h create mode 100644 src/free_subid_range.c create mode 100644 src/get_subid_owners.c create mode 100644 src/list_subid_ranges.c create mode 100644 src/new_subid_range.c create mode 100644 tests/libsubid/01_list_ranges/config.txt create mode 100644 tests/libsubid/01_list_ranges/config/etc/subgid create mode 100644 tests/libsubid/01_list_ranges/config/etc/subuid create mode 100755 tests/libsubid/01_list_ranges/list_ranges.test create mode 100644 tests/libsubid/02_get_subid_owners/config.txt create mode 100644 tests/libsubid/02_get_subid_owners/config/etc/passwd create mode 100644 tests/libsubid/02_get_subid_owners/config/etc/subgid create mode 100644 tests/libsubid/02_get_subid_owners/config/etc/subuid create mode 100755 tests/libsubid/02_get_subid_owners/get_subid_owners.test create mode 100755 tests/libsubid/03_add_remove/add_remove_subids.test create mode 100644 tests/libsubid/03_add_remove/config.txt create mode 100644 tests/libsubid/03_add_remove/config/etc/passwd create mode 100644 tests/libsubid/03_add_remove/config/etc/subgid create mode 100644 tests/libsubid/03_add_remove/config/etc/subuid create mode 100755 tests/run_some diff --git a/.travis.yml b/.travis.yml index ba73e7e2..7bc8340b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ arch: before_install: - sudo apt-get update -qq - - sudo apt-get -y install -qq automake autopoint xsltproc libselinux1-dev gettext + - sudo apt-get -y install -qq automake autopoint xsltproc libselinux1-dev gettext expect script: - ./autogen.sh --without-selinux --disable-man - grep ENABLE_ config.status @@ -38,4 +38,14 @@ addons: build_command: "make -j4" branch_pattern: master +script: + - cat /proc/self/uid_map + - cat /proc/self/status + - systemd-detect-virt + - ./autogen.sh --without-selinux --disable-man + - grep ENABLE_ config.status + - make + - sudo make install + - (cd tests; sudo ./run_some; cat testsuite.log) + # vim:et:ts=2:sw=2 diff --git a/Makefile.am b/Makefile.am index 8851f5d6..b6456cf9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,5 +2,14 @@ EXTRA_DIST = NEWS README TODO shadow.spec.in -SUBDIRS = po man libmisc lib src \ - contrib doc etc +SUBDIRS = libmisc lib + +if ENABLE_SUBIDS +SUBDIRS += libsubid +endif + +SUBDIRS += src po contrib doc etc + +if ENABLE_REGENERATE_MAN +SUBDIRS += man +endif diff --git a/autogen.sh b/autogen.sh index 336463c9..b90fefb3 100755 --- a/autogen.sh +++ b/autogen.sh @@ -6,7 +6,7 @@ autoreconf -v -f --install || exit 1 CFLAGS="-O2 -Wall" \ --enable-man \ --enable-maintainer-mode \ - --disable-shared \ + --enable-shared \ --without-libpam \ --with-selinux \ "$@" diff --git a/configure.ac b/configure.ac index b8bc2b7a..b766eff0 100644 --- a/configure.ac +++ b/configure.ac @@ -22,8 +22,8 @@ test "$prefix" = "/usr" && exec_prefix="" AC_GNU_SOURCE -AM_DISABLE_SHARED AM_ENABLE_STATIC +AM_ENABLE_SHARED AM_MAINTAINER_MODE @@ -725,6 +725,7 @@ AC_CONFIG_FILES([ man/zh_TW/Makefile libmisc/Makefile lib/Makefile + libsubid/Makefile src/Makefile contrib/Makefile etc/Makefile diff --git a/lib/subordinateio.c b/lib/subordinateio.c index 0d89a64e..67202c98 100644 --- a/lib/subordinateio.c +++ b/lib/subordinateio.c @@ -13,14 +13,7 @@ #include "subordinateio.h" #include #include - -struct subordinate_range { - const char *owner; - unsigned long start; - unsigned long count; -}; - -#define NFIELDS 3 +#include /* * subordinate_dup: create a duplicate range @@ -78,7 +71,7 @@ static void *subordinate_parse (const char *line) static char rangebuf[1024]; int i; char *cp; - char *fields[NFIELDS]; + char *fields[SUBID_NFIELDS]; /* * Copy the string to a temporary buffer so the substrings can @@ -93,7 +86,7 @@ static void *subordinate_parse (const char *line) * field. The fields are converted into NUL terminated strings. */ - for (cp = rangebuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) { + for (cp = rangebuf, i = 0; (i < SUBID_NFIELDS) && (NULL != cp); i++) { fields[i] = cp; while (('\0' != *cp) && (':' != *cp)) { cp++; @@ -108,10 +101,10 @@ static void *subordinate_parse (const char *line) } /* - * There must be exactly NFIELDS colon separated fields or + * There must be exactly SUBID_NFIELDS colon separated fields or * the entry is invalid. Also, fields must be non-blank. */ - if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0') + if (i != SUBID_NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0') return NULL; range.owner = fields[0]; if (getulong (fields[1], &range.start) == 0) @@ -314,6 +307,39 @@ static bool have_range(struct commonio_db *db, return false; } +static bool append_range(struct subordinate_range ***ranges, const struct subordinate_range *new, int n) +{ + struct subordinate_range *tmp; + if (!*ranges) { + *ranges = malloc(2 * sizeof(struct subordinate_range **)); + if (!*ranges) + return false; + } else { + struct subordinate_range **new; + new = realloc(*ranges, (n + 2) * (sizeof(struct subordinate_range **))); + if (!new) + return false; + *ranges = new; + } + (*ranges)[n] = (*ranges)[n+1] = NULL; + tmp = subordinate_dup(new); + if (!tmp) + return false; + (*ranges)[n] = tmp; + return true; +} + +void free_subordinate_ranges(struct subordinate_range **ranges) +{ + int i; + + if (!ranges) + return; + for (i = 0; ranges[i]; i++) + subordinate_free(ranges[i]); + free(ranges); +} + /* * subordinate_range_cmp: compare uid ranges * @@ -692,6 +718,160 @@ gid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count) start = find_free_range (&subordinate_gid_db, min, max, count); return start == ULONG_MAX ? (gid_t) -1 : start; } + +/* + struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) + * + * @owner: username + * @id_type: UID or GUID + * + * Returns the subuid or subgid ranges which are owned by the specified + * user. Username may be a username or a string representation of a + * UID number. If id_type is UID, then subuids are returned, else + * subgids are returned. If there is an error, < 0 is returned. + * + * The caller must free the subordinate range list. + */ +struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) +{ + // TODO - need to handle owner being either uid or username + const struct subordinate_range *range; + struct subordinate_range **ranges = NULL; + struct commonio_db *db; + int size = 0; + + if (id_type == ID_TYPE_UID) + db = &subordinate_uid_db; + else + db = &subordinate_gid_db; + + commonio_rewind(db); + while ((range = commonio_next(db)) != NULL) { + if (0 == strcmp(range->owner, owner)) { + if (!append_range(&ranges, range, size++)) { + free_subordinate_ranges(ranges); + return NULL; + } + } + } + + return ranges; +} + +static bool all_digits(const char *str) +{ + int i; + + for (i = 0; str[i] != '\0'; i++) + if (!isdigit(str[i])) + return false; + return true; +} + +static int append_uids(uid_t **uids, const char *owner, int n) +{ + uid_t owner_uid; + uid_t *ret; + int i; + + if (all_digits(owner)) { + i = sscanf(owner, "%d", &owner_uid); + if (i != 1) { + // should not happen + free(*uids); + *uids = NULL; + return -1; + } + } else { + struct passwd *pwd = getpwnam(owner); + if (NULL == pwd) { + /* Username not defined in /etc/passwd, or error occured during lookup */ + free(*uids); + *uids = NULL; + return -1; + } + owner_uid = pwd->pw_uid; + } + + for (i = 0; i < n; i++) { + if (owner_uid == (*uids)[i]) + return n; + } + + ret = realloc(*uids, (n + 1) * sizeof(uid_t)); + if (!ret) { + free(*uids); + return -1; + } + ret[n] = owner_uid; + *uids = ret; + return n+1; +} + +int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type) +{ + const struct subordinate_range *range; + struct commonio_db *db; + int n = 0; + + *uids = NULL; + if (id_type == ID_TYPE_UID) + db = &subordinate_uid_db; + else + db = &subordinate_gid_db; + + commonio_rewind(db); + while ((range = commonio_next(db)) != NULL) { + if (id >= range->start && id < range->start + range-> count) { + n = append_uids(uids, range->owner, n); + if (n < 0) + break; + } + } + + return n; +} + +bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse) +{ + struct commonio_db *db; + const struct subordinate_range *r; + + if (id_type == ID_TYPE_UID) + db = &subordinate_uid_db; + else + db = &subordinate_gid_db; + commonio_rewind(db); + if (reuse) { + while ((r = commonio_next(db)) != NULL) { + // TODO account for username vs uid_t + if (0 != strcmp(r->owner, range->owner)) + continue; + if (r->count >= range->count) { + range->count = r->count; + range->start = r->start; + return true; + } + } + } + + range->start = find_free_range(db, range->start, ULONG_MAX, range->count); + if (range->start == ULONG_MAX) + return false; + + return add_range(db, range->owner, range->start, range->count) == 1; +} + +bool release_subid_range(struct subordinate_range *range, enum subid_type id_type) +{ + struct commonio_db *db; + if (id_type == ID_TYPE_UID) + db = &subordinate_uid_db; + else + db = &subordinate_gid_db; + return remove_range(db, range->owner, range->start, range->count) == 1; +} + #else /* !ENABLE_SUBIDS */ extern int errno; /* warning: ANSI C forbids an empty source file */ #endif /* !ENABLE_SUBIDS */ diff --git a/lib/subordinateio.h b/lib/subordinateio.h index a21d72b8..13a21341 100644 --- a/lib/subordinateio.h +++ b/lib/subordinateio.h @@ -11,6 +11,8 @@ #include +#include "../libsubid/subid.h" + extern int sub_uid_close(void); extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count); extern bool sub_uid_file_present (void); @@ -23,6 +25,11 @@ extern int sub_uid_unlock (void); extern int sub_uid_add (const char *owner, uid_t start, unsigned long count); extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count); extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count); +extern struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type); +extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse); +extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type); +extern int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type); +extern void free_subordinate_ranges(struct subordinate_range **ranges); extern int sub_gid_close(void); extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count); diff --git a/libsubid/Makefile.am b/libsubid/Makefile.am new file mode 100644 index 00000000..bdbc52c3 --- /dev/null +++ b/libsubid/Makefile.am @@ -0,0 +1,25 @@ +lib_LTLIBRARIES = libsubid.la +libsubid_la_LDFLAGS = -Wl,-soname,libsubid.so.@LIBSUBID_ABI@ \ + -shared -version-info @LIBSUBID_ABI_MAJOR@ +libsubid_la_SOURCES = api.c + +MISCLIBS = \ + $(LIBAUDIT) \ + $(LIBSELINUX) \ + $(LIBSEMANAGE) \ + $(LIBCRYPT_NOPAM) \ + $(LIBSKEY) \ + $(LIBMD) \ + $(LIBECONF) \ + $(LIBCRYPT) \ + $(LIBTCB) + +libsubid_la_LIBADD = \ + $(top_srcdir)/lib/libshadow.la \ + $(top_srcdir)/libmisc/libmisc.a \ + $(MISCLIBS) + +AM_CPPFLAGS = \ + -I${top_srcdir}/lib \ + -I${top_srcdir}/libmisc \ + -DLOCALEDIR=\"$(datadir)/locale\" diff --git a/libsubid/api.c b/libsubid/api.c new file mode 100644 index 00000000..91d73bed --- /dev/null +++ b/libsubid/api.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2020 Serge Hallyn + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "subordinateio.h" +#include "idmapping.h" +#include "api.h" + +static struct subordinate_range **get_subid_ranges(const char *owner, enum subid_type id_type) +{ + struct subordinate_range **ranges = NULL; + + switch (id_type) { + case ID_TYPE_UID: + if (!sub_uid_open(O_RDONLY)) { + return NULL; + } + break; + case ID_TYPE_GID: + if (!sub_gid_open(O_RDONLY)) { + return NULL; + } + break; + default: + return NULL; + } + + ranges = list_owner_ranges(owner, id_type); + + if (id_type == ID_TYPE_UID) + sub_uid_close(); + else + sub_gid_close(); + + return ranges; +} + +struct subordinate_range **get_subuid_ranges(const char *owner) +{ + return get_subid_ranges(owner, ID_TYPE_UID); +} + +struct subordinate_range **get_subgid_ranges(const char *owner) +{ + return get_subid_ranges(owner, ID_TYPE_GID); +} + +void subid_free_ranges(struct subordinate_range **ranges) +{ + return free_subordinate_ranges(ranges); +} + +int get_subid_owner(unsigned long id, uid_t **owner, enum subid_type id_type) +{ + int ret = -1; + + switch (id_type) { + case ID_TYPE_UID: + if (!sub_uid_open(O_RDONLY)) { + return -1; + } + break; + case ID_TYPE_GID: + if (!sub_gid_open(O_RDONLY)) { + return -1; + } + break; + default: + return -1; + } + + ret = find_subid_owners(id, owner, id_type); + + if (id_type == ID_TYPE_UID) + sub_uid_close(); + else + sub_gid_close(); + + return ret; +} + +int get_subuid_owners(uid_t uid, uid_t **owner) +{ + return get_subid_owner((unsigned long)uid, owner, ID_TYPE_UID); +} + +int get_subgid_owners(gid_t gid, uid_t **owner) +{ + return get_subid_owner((unsigned long)gid, owner, ID_TYPE_GID); +} + +bool grant_subid_range(struct subordinate_range *range, bool reuse, + enum subid_type id_type) +{ + bool ret; + + switch (id_type) { + case ID_TYPE_UID: + if (!sub_uid_lock()) { + printf("Failed loging subuids (errno %d)\n", errno); + return false; + } + if (!sub_uid_open(O_CREAT | O_RDWR)) { + printf("Failed opening subuids (errno %d)\n", errno); + sub_uid_unlock(); + return false; + } + break; + case ID_TYPE_GID: + if (!sub_gid_lock()) { + printf("Failed loging subgids (errno %d)\n", errno); + return false; + } + if (!sub_gid_open(O_CREAT | O_RDWR)) { + printf("Failed opening subgids (errno %d)\n", errno); + sub_gid_unlock(); + return false; + } + break; + default: + return false; + } + + ret = new_subid_range(range, id_type, reuse); + + if (id_type == ID_TYPE_UID) { + sub_uid_close(); + sub_uid_unlock(); + } else { + sub_gid_close(); + sub_gid_unlock(); + } + + return ret; +} + +bool grant_subuid_range(struct subordinate_range *range, bool reuse) +{ + return grant_subid_range(range, reuse, ID_TYPE_UID); +} + +bool grant_subgid_range(struct subordinate_range *range, bool reuse) +{ + return grant_subid_range(range, reuse, ID_TYPE_GID); +} + +bool free_subid_range(struct subordinate_range *range, enum subid_type id_type) +{ + bool ret; + + switch (id_type) { + case ID_TYPE_UID: + if (!sub_uid_lock()) { + printf("Failed loging subuids (errno %d)\n", errno); + return false; + } + if (!sub_uid_open(O_CREAT | O_RDWR)) { + printf("Failed opening subuids (errno %d)\n", errno); + sub_uid_unlock(); + return false; + } + break; + case ID_TYPE_GID: + if (!sub_gid_lock()) { + printf("Failed loging subgids (errno %d)\n", errno); + return false; + } + if (!sub_gid_open(O_CREAT | O_RDWR)) { + printf("Failed opening subgids (errno %d)\n", errno); + sub_gid_unlock(); + return false; + } + break; + default: + return false; + } + + ret = release_subid_range(range, id_type); + + if (id_type == ID_TYPE_UID) { + sub_uid_close(); + sub_uid_unlock(); + } else { + sub_gid_close(); + sub_gid_unlock(); + } + + return ret; +} + +bool free_subuid_range(struct subordinate_range *range) +{ + return free_subid_range(range, ID_TYPE_UID); +} + +bool free_subgid_range(struct subordinate_range *range) +{ + return free_subid_range(range, ID_TYPE_GID); +} diff --git a/libsubid/api.h b/libsubid/api.h new file mode 100644 index 00000000..f65e3ec9 --- /dev/null +++ b/libsubid/api.h @@ -0,0 +1,17 @@ +#include "subid.h" +#include + +struct subordinate_range **get_subuid_ranges(const char *owner); +struct subordinate_range **get_subgid_ranges(const char *owner); +void subid_free_ranges(struct subordinate_range **ranges); + +int get_subuid_owners(uid_t uid, uid_t **owner); +int get_subgid_owners(uid_t uid, uid_t **owner); + +/* range should be pre-allocated with owner and count filled in, start is + * ignored, can be 0 */ +bool grant_subuid_range(struct subordinate_range *range, bool reuse); +bool grant_subgid_range(struct subordinate_range *range, bool reuse); + +bool free_subuid_range(struct subordinate_range *range); +bool free_subgid_range(struct subordinate_range *range); diff --git a/libsubid/subid.h b/libsubid/subid.h new file mode 100644 index 00000000..ba9a2f6f --- /dev/null +++ b/libsubid/subid.h @@ -0,0 +1,17 @@ +#include + +#ifndef SUBID_RANGE_DEFINED +#define SUBID_RANGE_DEFINED 1 +struct subordinate_range { + const char *owner; + unsigned long start; + unsigned long count; +}; + +enum subid_type { + ID_TYPE_UID = 1, + ID_TYPE_GID = 2 +}; + +#define SUBID_NFIELDS 3 +#endif diff --git a/src/.gitignore b/src/.gitignore index d5716b98..8c14e6f4 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -33,3 +33,7 @@ /userdel /usermod /vipw +/get_subid_owners +/list_subid_ranges +/new_subid_range +/free_subid_range diff --git a/src/Makefile.am b/src/Makefile.am index f175928a..8499ce08 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -156,4 +156,64 @@ if FCAPS setcap cap_setuid+ep $(DESTDIR)$(ubindir)/newuidmap setcap cap_setgid+ep $(DESTDIR)$(ubindir)/newgidmap endif + +noinst_PROGRAMS += list_subid_ranges \ + get_subid_owners \ + new_subid_range \ + free_subid_range + +MISCLIBS = \ + $(LIBAUDIT) \ + $(LIBSELINUX) \ + $(LIBSEMANAGE) \ + $(LIBCRYPT_NOPAM) \ + $(LIBSKEY) \ + $(LIBMD) \ + $(LIBECONF) \ + $(LIBCRYPT) \ + $(LIBTCB) + +list_subid_ranges_LDADD = \ + $(top_builddir)/lib/libshadow.la \ + $(top_builddir)/libmisc/libmisc.a \ + $(top_builddir)/libsubid/libsubid.la \ + $(MISCLIBS) + +list_subid_ranges_CPPFLAGS = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/libmisc \ + -I$(top_srcdir)/libsubid + +get_subid_owners_LDADD = \ + $(top_builddir)/lib/libshadow.la \ + $(top_builddir)/libmisc/libmisc.a \ + $(top_builddir)/libsubid/libsubid.la \ + $(MISCLIBS) + +get_subid_owners_CPPFLAGS = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/libmisc \ + -I$(top_srcdir)/libsubid + +new_subid_range_CPPFLAGS = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/libmisc \ + -I$(top_srcdir)/libsubid + +new_subid_range_LDADD = \ + $(top_builddir)/lib/libshadow.la \ + $(top_builddir)/libmisc/libmisc.a \ + $(top_builddir)/libsubid/libsubid.la \ + $(MISCLIBS) + +free_subid_range_CPPFLAGS = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/libmisc \ + -I$(top_srcdir)/libsubid + +free_subid_range_LDADD = \ + $(top_builddir)/lib/libshadow.la \ + $(top_builddir)/libmisc/libmisc.a \ + $(top_builddir)/libsubid/libsubid.la \ + $(MISCLIBS) endif diff --git a/src/free_subid_range.c b/src/free_subid_range.c new file mode 100644 index 00000000..36858875 --- /dev/null +++ b/src/free_subid_range.c @@ -0,0 +1,50 @@ +#include +#include +#include "api.h" +#include "stdlib.h" +#include "prototypes.h" + +/* Test program for the subid freeing routine */ + +const char *Prog; + +void usage(void) +{ + fprintf(stderr, "Usage: %s [-g] user start count\n", Prog); + fprintf(stderr, " Release a user's subuid (or with -g, subgid) range\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int c; + bool ok; + struct subordinate_range range; + bool group = false; // get subuids by default + + Prog = Basename (argv[0]); + while ((c = getopt(argc, argv, "g")) != EOF) { + switch(c) { + case 'g': group = true; break; + default: usage(); + } + } + argv = &argv[optind]; + argc = argc - optind; + if (argc < 3) + usage(); + range.owner = argv[0]; + range.start = atoi(argv[1]); + range.count = atoi(argv[2]); + if (group) + ok = free_subgid_range(&range); + else + ok = free_subuid_range(&range); + + if (!ok) { + fprintf(stderr, "Failed freeing id range\n"); + exit(EXIT_FAILURE); + } + + return 0; +} diff --git a/src/get_subid_owners.c b/src/get_subid_owners.c new file mode 100644 index 00000000..a4385540 --- /dev/null +++ b/src/get_subid_owners.c @@ -0,0 +1,40 @@ +#include +#include "api.h" +#include "stdlib.h" +#include "prototypes.h" + +const char *Prog; + +void usage(void) +{ + fprintf(stderr, "Usage: [-g] %s subuid\n", Prog); + fprintf(stderr, " list uids who own the given subuid\n"); + fprintf(stderr, " pass -g to query a subgid\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int i, n; + uid_t *uids; + + Prog = Basename (argv[0]); + if (argc < 2) { + usage(); + } + if (argc == 3 && strcmp(argv[1], "-g") == 0) + n = get_subgid_owners(atoi(argv[2]), &uids); + else if (argc == 2 && strcmp(argv[1], "-h") == 0) + usage(); + else + n = get_subuid_owners(atoi(argv[1]), &uids); + if (n < 0) { + fprintf(stderr, "No owners found\n"); + exit(1); + } + for (i = 0; i < n; i++) { + printf("%d\n", uids[i]); + } + free(uids); + return 0; +} diff --git a/src/list_subid_ranges.c b/src/list_subid_ranges.c new file mode 100644 index 00000000..cdba610e --- /dev/null +++ b/src/list_subid_ranges.c @@ -0,0 +1,41 @@ +#include +#include "api.h" +#include "stdlib.h" +#include "prototypes.h" + +const char *Prog; + +void usage(void) +{ + fprintf(stderr, "Usage: %s [-g] user\n", Prog); + fprintf(stderr, " list subuid ranges for user\n"); + fprintf(stderr, " pass -g to list subgid ranges\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int i; + struct subordinate_range **ranges; + + Prog = Basename (argv[0]); + if (argc < 2) { + usage(); + } + if (argc == 3 && strcmp(argv[1], "-g") == 0) + ranges = get_subgid_ranges(argv[2]); + else if (argc == 2 && strcmp(argv[1], "-h") == 0) + usage(); + else + ranges = get_subuid_ranges(argv[1]); + if (!ranges) { + fprintf(stderr, "Error fetching ranges\n"); + exit(1); + } + for (i = 0; ranges[i]; i++) { + printf("%d: %s %lu %lu\n", i, ranges[i]->owner, + ranges[i]->start, ranges[i]->count); + } + subid_free_ranges(ranges); + return 0; +} diff --git a/src/new_subid_range.c b/src/new_subid_range.c new file mode 100644 index 00000000..6d7b033b --- /dev/null +++ b/src/new_subid_range.c @@ -0,0 +1,57 @@ +#include +#include +#include "api.h" +#include "stdlib.h" +#include "prototypes.h" + +/* Test program for the subid creation routine */ + +const char *Prog; + +void usage(void) +{ + fprintf(stderr, "Usage: %s [-g] [-n] user count\n", Prog); + fprintf(stderr, " Find a subuid (or with -g, subgid) range for user\n"); + fprintf(stderr, " If -n is given, a new range will be created even if one exists\n"); + fprintf(stderr, " count defaults to 65536\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int c; + struct subordinate_range range; + bool makenew = false; // reuse existing by default + bool group = false; // get subuids by default + bool ok; + + Prog = Basename (argv[0]); + while ((c = getopt(argc, argv, "gn")) != EOF) { + switch(c) { + case 'n': makenew = true; break; + case 'g': group = true; break; + default: usage(); + } + } + argv = &argv[optind]; + argc = argc - optind; + if (argc == 0) + usage(); + range.owner = argv[0]; + range.start = 0; + range.count = 65536; + if (argc > 1) + range.count = atoi(argv[1]); + if (group) + ok = grant_subgid_range(&range, !makenew); + else + ok = grant_subuid_range(&range, !makenew); + + if (!ok) { + fprintf(stderr, "Failed creating new id range\n"); + exit(EXIT_FAILURE); + } + printf("Subuid range %lu:%lu\n", range.start, range.count); + + return 0; +} diff --git a/tests/libsubid/01_list_ranges/config.txt b/tests/libsubid/01_list_ranges/config.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/libsubid/01_list_ranges/config/etc/subgid b/tests/libsubid/01_list_ranges/config/etc/subgid new file mode 100644 index 00000000..b9495cfc --- /dev/null +++ b/tests/libsubid/01_list_ranges/config/etc/subgid @@ -0,0 +1,2 @@ +foo:200000:10000 +root:500000:1000 diff --git a/tests/libsubid/01_list_ranges/config/etc/subuid b/tests/libsubid/01_list_ranges/config/etc/subuid new file mode 100644 index 00000000..e5c537be --- /dev/null +++ b/tests/libsubid/01_list_ranges/config/etc/subuid @@ -0,0 +1,3 @@ +foo:300000:10000 +foo:400000:10000 +root:500000:1000 diff --git a/tests/libsubid/01_list_ranges/list_ranges.test b/tests/libsubid/01_list_ranges/list_ranges.test new file mode 100755 index 00000000..b131303b --- /dev/null +++ b/tests/libsubid/01_list_ranges/list_ranges.test @@ -0,0 +1,38 @@ +#!/bin/sh + +set -e + +cd $(dirname $0) + +. ../../common/config.sh +. ../../common/log.sh + +log_start "$0" "list_ranges shows subid ranges" + +save_config + +# restore the files on exit +trap 'log_status "$0" "FAILURE"; restore_config' 0 + +change_config + +echo -n "list foo's ranges..." +${build_path}/src/list_subid_ranges foo > /tmp/subuidlistout +${build_path}/src/list_subid_ranges -g foo > /tmp/subgidlistout +echo "OK" + +echo -n "Check the subuid ranges..." +[ $(wc -l /tmp/subuidlistout | awk '{ print $1 }') -eq 2 ] +grep "0: foo 300000 10000" /tmp/subuidlistout +grep "1: foo 400000 10000" /tmp/subuidlistout +echo "OK" + +echo -n "Check the subgid ranges..." +[ $(wc -l /tmp/subgidlistout | awk '{ print $1 }') -eq 1 ] +grep "0: foo 200000 10000" /tmp/subgidlistout +echo "OK" + +log_status "$0" "SUCCESS" +restore_config +trap '' 0 + diff --git a/tests/libsubid/02_get_subid_owners/config.txt b/tests/libsubid/02_get_subid_owners/config.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/libsubid/02_get_subid_owners/config/etc/passwd b/tests/libsubid/02_get_subid_owners/config/etc/passwd new file mode 100644 index 00000000..bf52df00 --- /dev/null +++ b/tests/libsubid/02_get_subid_owners/config/etc/passwd @@ -0,0 +1,20 @@ +root:x:0:0:root:/root:/bin/bash +daemon:x:1:1:daemon:/usr/sbin:/bin/sh +bin:x:2:2:bin:/bin:/bin/sh +sys:x:3:3:sys:/dev:/bin/sh +sync:x:4:65534:sync:/bin:/bin/sync +games:x:5:60:games:/usr/games:/bin/sh +man:x:6:12:man:/var/cache/man:/bin/sh +lp:x:7:7:lp:/var/spool/lpd:/bin/sh +mail:x:8:8:mail:/var/mail:/bin/sh +news:x:9:9:news:/var/spool/news:/bin/sh +uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh +proxy:x:13:13:proxy:/bin:/bin/sh +www-data:x:33:33:www-data:/var/www:/bin/sh +backup:x:34:34:backup:/var/backups:/bin/sh +list:x:38:38:Mailing List Manager:/var/list:/bin/sh +irc:x:39:39:ircd:/var/run/ircd:/bin/sh +gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh +nobody:x:65534:65534:nobody:/nonexistent:/bin/sh +Debian-exim:x:102:102::/var/spool/exim4:/bin/false +foo:x:1000:1000::/home/foo:/bin/false diff --git a/tests/libsubid/02_get_subid_owners/config/etc/subgid b/tests/libsubid/02_get_subid_owners/config/etc/subgid new file mode 100644 index 00000000..b9495cfc --- /dev/null +++ b/tests/libsubid/02_get_subid_owners/config/etc/subgid @@ -0,0 +1,2 @@ +foo:200000:10000 +root:500000:1000 diff --git a/tests/libsubid/02_get_subid_owners/config/etc/subuid b/tests/libsubid/02_get_subid_owners/config/etc/subuid new file mode 100644 index 00000000..dd11875a --- /dev/null +++ b/tests/libsubid/02_get_subid_owners/config/etc/subuid @@ -0,0 +1,4 @@ +foo:300000:10000 +foo:400000:10000 +foo:500000:10000 +root:500000:1000 diff --git a/tests/libsubid/02_get_subid_owners/get_subid_owners.test b/tests/libsubid/02_get_subid_owners/get_subid_owners.test new file mode 100755 index 00000000..145477cb --- /dev/null +++ b/tests/libsubid/02_get_subid_owners/get_subid_owners.test @@ -0,0 +1,52 @@ +#!/bin/sh + +set -e + +cd $(dirname $0) + +. ../../common/config.sh +. ../../common/log.sh + +log_start "$0" "get subid owners" + +save_config + +# restore the files on exit +trap 'log_status "$0" "FAILURE"; restore_config' 0 + +change_config + +echo -n "Noone owns 0 as a subid..." +[ -z "$(${build_path}/src/get_subid_owners 0)" ] +echo "OK" + +echo -n "foo owns subuid 300000..." +[ "$(${build_path}/src/get_subid_owners 300000)" = "1000" ] +echo "OK" + +echo -n "foo owns subgid 200000..." +[ "$(${build_path}/src/get_subid_owners -g 200000)" = "1000" ] +echo "OK" + +echo -n "Noone owns subuid 200000..." +[ -z "$(${build_path}/src/get_subid_owners -g 300000)" ] +echo "OK" + +echo -n "Noone owns subgid 300000..." +[ -z "$(${build_path}/src/get_subid_owners -g 300000)" ] +echo "OK" + +echo -n "Both foo and root own subuid 500000..." +cat > /tmp/expected << EOF +1000 +0 +EOF +${build_path}/src/get_subid_owners 500000 > /tmp/actual +diff /tmp/expected /tmp/actual + +echo "OK" + +log_status "$0" "SUCCESS" +restore_config +trap '' 0 + diff --git a/tests/libsubid/03_add_remove/add_remove_subids.test b/tests/libsubid/03_add_remove/add_remove_subids.test new file mode 100755 index 00000000..a24a9752 --- /dev/null +++ b/tests/libsubid/03_add_remove/add_remove_subids.test @@ -0,0 +1,59 @@ +#!/bin/sh + +set -e + +cd $(dirname $0) + +. ../../common/config.sh +. ../../common/log.sh + +log_start "$0" "add and remove subid ranges" + +save_config + +# restore the files on exit +trap 'log_status "$0" "FAILURE"; restore_config' 0 + +change_config + +echo -n "Existing ranges returned when possible..." +res=$(${build_path}/src/new_subid_range foo 500) +echo "debug" +echo "res is $res" +echo "wanted Subuid range 300000:10000" +echo "end debug" +[ "$res" = "Subuid range 300000:10000" ] +[ $(grep -c foo /etc/subuid) -eq 1 ] +echo "OK" + +echo -n "New range returned if requested..." +res=$(${build_path}/src/new_subid_range foo 500 -n) +[ "$res" = "Subuid range 310000:500" ] +[ $(grep -c foo /etc/subuid) -eq 2 ] +echo "OK" + +echo -n "Free works..." +res=$(${build_path}/src/free_subid_range foo 310000 500) +[ $(grep -c foo /etc/subuid) -eq 1 ] +echo "OK" + +echo -n "Subgids work too..." +res=$(${build_path}/src/new_subid_range -g foo 100000) +echo "DEBUG: res is ${res}" +[ "$res" = "Subuid range 501000:100000" ] +echo "DEBUG: subgid is:" +cat /etc/subgid +[ $(grep -c foo /etc/subgid) -eq 2 ] + +echo -n "Subgid free works..." +res=$(${build_path}/src/free_subid_range -g foo 501000 100000) +echo "DEBUG: res is ${res}" +echo "DEBUG: subgid is:" +cat /etc/subgid +[ $(grep -c foo /etc/subgid) -eq 1 ] +echo "OK" + +log_status "$0" "SUCCESS" +restore_config +trap '' 0 + diff --git a/tests/libsubid/03_add_remove/config.txt b/tests/libsubid/03_add_remove/config.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/libsubid/03_add_remove/config/etc/passwd b/tests/libsubid/03_add_remove/config/etc/passwd new file mode 100644 index 00000000..bf52df00 --- /dev/null +++ b/tests/libsubid/03_add_remove/config/etc/passwd @@ -0,0 +1,20 @@ +root:x:0:0:root:/root:/bin/bash +daemon:x:1:1:daemon:/usr/sbin:/bin/sh +bin:x:2:2:bin:/bin:/bin/sh +sys:x:3:3:sys:/dev:/bin/sh +sync:x:4:65534:sync:/bin:/bin/sync +games:x:5:60:games:/usr/games:/bin/sh +man:x:6:12:man:/var/cache/man:/bin/sh +lp:x:7:7:lp:/var/spool/lpd:/bin/sh +mail:x:8:8:mail:/var/mail:/bin/sh +news:x:9:9:news:/var/spool/news:/bin/sh +uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh +proxy:x:13:13:proxy:/bin:/bin/sh +www-data:x:33:33:www-data:/var/www:/bin/sh +backup:x:34:34:backup:/var/backups:/bin/sh +list:x:38:38:Mailing List Manager:/var/list:/bin/sh +irc:x:39:39:ircd:/var/run/ircd:/bin/sh +gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh +nobody:x:65534:65534:nobody:/nonexistent:/bin/sh +Debian-exim:x:102:102::/var/spool/exim4:/bin/false +foo:x:1000:1000::/home/foo:/bin/false diff --git a/tests/libsubid/03_add_remove/config/etc/subgid b/tests/libsubid/03_add_remove/config/etc/subgid new file mode 100644 index 00000000..b9495cfc --- /dev/null +++ b/tests/libsubid/03_add_remove/config/etc/subgid @@ -0,0 +1,2 @@ +foo:200000:10000 +root:500000:1000 diff --git a/tests/libsubid/03_add_remove/config/etc/subuid b/tests/libsubid/03_add_remove/config/etc/subuid new file mode 100644 index 00000000..cf80c2f7 --- /dev/null +++ b/tests/libsubid/03_add_remove/config/etc/subuid @@ -0,0 +1 @@ +foo:300000:10000 diff --git a/tests/run_some b/tests/run_some new file mode 100755 index 00000000..2d085d59 --- /dev/null +++ b/tests/run_some @@ -0,0 +1,136 @@ +#!/bin/sh + +set -e + +export LC_ALL=C +unset LANG +unset LANGUAGE +. common/config.sh + +USE_PAM="yes" +FAILURE_TESTS="yes" + +succeeded=0 +failed=0 +failed_tests="" + +run_test() +{ + [ -f RUN_TEST.STOP ] && exit 1 + + if $1 > $1.log + then + succeeded=$((succeeded+1)) + echo -n "+" + else + failed=$((failed+1)) + failed_tests="$failed_tests $1" + echo -n "-" + fi + cat $1.log >> testsuite.log + [ -f /etc/passwd.lock ] && echo $1 /etc/passwd.lock || true + [ -f /etc/group.lock ] && echo $1 /etc/group.lock || true + [ -f /etc/shadow.lock ] && echo $1 /etc/shadow.lock || true + [ -f /etc/gshadow.lock ] && echo $1 /etc/gshadow.lock || true + if [ "$(stat -c"%G" /etc/shadow)" != "shadow" ] + then + echo $1 + ls -l /etc/shadow + chgrp shadow /etc/shadow + fi + if [ -d /nonexistent ] + then + echo $1 /nonexistent + rmdir /nonexistent + fi +} + +echo "+: test passed" +echo "-: test failed" + +# Empty the complete log. +> testsuite.log + +find ${build_path} -name "*.gcda" -delete +run_test ./su/01/su_root.test +run_test ./su/01/su_user.test +find ${build_path} -name "*.gcda" -exec chmod a+rw {} \; +run_test ./su/02/env_FOO-options_--login +run_test ./su/02/env_FOO-options_--login_bash +run_test ./su/02/env_FOO-options_--preserve-environment +run_test ./su/02/env_FOO-options_--preserve-environment_bash +run_test ./su/02/env_FOO-options_- +run_test ./su/02/env_FOO-options_-_bash +run_test ./su/02/env_FOO-options_-l-m +run_test ./su/02/env_FOO-options_-l-m_bash +run_test ./su/02/env_FOO-options_-l +run_test ./su/02/env_FOO-options_-l_bash +run_test ./su/02/env_FOO-options_-m_bash +run_test ./su/02/env_FOO-options_-m +run_test ./su/02/env_FOO-options_-p +run_test ./su/02/env_FOO-options_-p_bash +run_test ./su/02/env_FOO-options__bash +run_test ./su/02/env_FOO-options_ +run_test ./su/02/env_FOO-options_-p- +run_test ./su/02/env_FOO-options_-p-_bash +run_test ./su/02/env_special-options_-l-p +run_test ./su/02/env_special-options_-l +run_test ./su/02/env_special-options_-l-p_bash +run_test ./su/02/env_special-options_-l_bash +run_test ./su/02/env_special-options_-p +run_test ./su/02/env_special-options_-p_bash +run_test ./su/02/env_special-options_ +run_test ./su/02/env_special-options__bash +run_test ./su/02/env_special_root-options_-l-p +run_test ./su/02/env_special_root-options_-l-p_bash +run_test ./su/02/env_special_root-options_-l +run_test ./su/02/env_special_root-options_-l_bash +run_test ./su/02/env_special_root-options_-p +run_test ./su/02/env_special_root-options_-p_bash +run_test ./su/02/env_special_root-options_ +run_test ./su/02/env_special_root-options__bash +run_test ./su/03/su_run_command01.test +run_test ./su/03/su_run_command02.test +run_test ./su/03/su_run_command03.test +run_test ./su/03/su_run_command04.test +run_test ./su/03/su_run_command05.test +run_test ./su/03/su_run_command06.test +run_test ./su/03/su_run_command07.test +run_test ./su/03/su_run_command08.test +run_test ./su/03/su_run_command09.test +run_test ./su/03/su_run_command10.test +run_test ./su/03/su_run_command11.test +run_test ./su/03/su_run_command12.test +run_test ./su/03/su_run_command13.test +run_test ./su/03/su_run_command14.test +run_test ./su/03/su_run_command15.test +run_test ./su/03/su_run_command16.test +run_test ./su/03/su_run_command17.test +run_test ./su/04/su_wrong_user.test +run_test ./su/04/su_user_wrong_passwd.test +run_test ./su/04/su_user_wrong_passwd_syslog.test +run_test ./su/05/su_user_wrong_passwd_syslog.test +run_test ./su/06/su_user_syslog.test +run_test ./su/07/su_user_syslog.test +run_test ./su/08/env_special-options_ +run_test ./su/08/env_special_root-options_ +run_test ./su/09/env_special-options_ +run_test ./su/09/env_special_root-options_ +run_test ./su/10_su_sulog_success/su.test +run_test ./su/11_su_sulog_failure/su.test +run_test ./su/12_su_child_failure/su.test +run_test ./su/13_su_child_success/su.test +run_test ./libsubid/01_list_ranges/list_ranges.test +run_test ./libsubid/02_get_subid_owners/get_subid_owners.test +run_test ./libsubid/03_add_remove/add_remove_subids.test + +echo +echo "$succeeded test(s) passed" +echo "$failed test(s) failed" +echo "log written in 'testsuite.log'" +if [ "$failed" != "0" ] +then + echo "the following tests failed:" + echo $failed_tests +fi +