diff options
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | src/shared/user-record.c | 13 | ||||
-rw-r--r-- | src/shared/user-record.h | 1 | ||||
-rw-r--r-- | src/sysusers/sysusers.c | 22 | ||||
-rw-r--r-- | src/test/test-user-record.c | 48 | ||||
-rwxr-xr-x | test/test-sysusers.sh.in | 59 | ||||
-rw-r--r-- | test/test-sysusers/test-10.expected-group | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-10.expected-passwd | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-13.expected-group | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-13.expected-passwd | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-14.expected-passwd | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-2.expected-group | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-2.expected-passwd | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-2.input | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-6.expected-group | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-6.expected-passwd | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-8.expected-passwd | 2 | ||||
-rw-r--r-- | test/test-sysusers/test-9.expected-passwd | 2 |
18 files changed, 143 insertions, 25 deletions
diff --git a/meson.build b/meson.build index 3bec86db81..23cf3e528a 100644 --- a/meson.build +++ b/meson.build @@ -1467,6 +1467,7 @@ foreach term : ['analyze', have = get_option(term) name = 'ENABLE_' + term.underscorify().to_upper() conf.set10(name, have) + substs.set10(name, have) endforeach enable_sysusers = conf.get('ENABLE_SYSUSERS') == 1 diff --git a/src/shared/user-record.c b/src/shared/user-record.c index 3ba78d455f..7e7b28eb55 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -37,21 +37,24 @@ static int parse_alloc_uid(const char *path, const char *name, const char *t, ui *ret_uid = uid; return 0; } +#endif -static int read_login_defs(UGIDAllocationRange *ret_defs, const char *path) { - _cleanup_fclose_ FILE *f = NULL; +int read_login_defs(UGIDAllocationRange *ret_defs, const char *path, const char *root) { UGIDAllocationRange defs = { .system_alloc_uid_min = SYSTEM_ALLOC_UID_MIN, .system_uid_max = SYSTEM_UID_MAX, .system_alloc_gid_min = SYSTEM_ALLOC_GID_MIN, .system_gid_max = SYSTEM_GID_MAX, }; + +#if ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES + _cleanup_fclose_ FILE *f = NULL; int r; if (!path) path = "/etc/login.defs"; - r = fopen_unlocked(path, "re", &f); + r = chase_symlinks_and_fopen_unlocked(path, root, CHASE_PREFIX_ROOT, "re", &f, NULL); if (r == -ENOENT) goto assign; if (r < 0) @@ -88,11 +91,11 @@ static int read_login_defs(UGIDAllocationRange *ret_defs, const char *path) { defs.system_alloc_gid_min = MIN(defs.system_gid_max - 1, (gid_t) SYSTEM_ALLOC_GID_MIN); /* Look at sys_gid_max to make sure sys_gid_min..sys_gid_max remains a valid range. */ } +#endif *ret_defs = defs; return 0; } -#endif const UGIDAllocationRange *acquire_ugid_allocation_range(void) { #if ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES @@ -114,7 +117,7 @@ const UGIDAllocationRange *acquire_ugid_allocation_range(void) { static thread_local bool initialized = false; if (!initialized) { - (void) read_login_defs(&defs, NULL); + (void) read_login_defs(&defs, NULL, NULL); initialized = true; } #endif diff --git a/src/shared/user-record.h b/src/shared/user-record.h index 1f87eff6d5..2e74b910c2 100644 --- a/src/shared/user-record.h +++ b/src/shared/user-record.h @@ -43,6 +43,7 @@ typedef struct UGIDAllocationRange { gid_t system_gid_max; } UGIDAllocationRange; +int read_login_defs(UGIDAllocationRange *ret_defs, const char *path, const char *root); const UGIDAllocationRange *acquire_ugid_allocation_range(void); typedef enum UserDisposition { diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 7349e9fcb9..987950d602 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -26,6 +26,7 @@ #include "strv.h" #include "tmpfile-util-label.h" #include "uid-range.h" +#include "user-record.h" #include "user-util.h" #include "utf8.h" #include "util.h" @@ -1949,10 +1950,25 @@ static int run(int argc, char *argv[]) { return log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m"); if (!uid_range) { - /* Default to default range of 1..SYSTEM_UID_MAX */ - r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX); + /* Default to default range of SYSTEMD_UID_MIN..SYSTEM_UID_MAX. */ + UGIDAllocationRange defs; + + r = read_login_defs(&defs, NULL, arg_root); if (r < 0) - return log_oom(); + return log_error_errno(r, "Failed to read %s%s: %m", + strempty(arg_root), "/etc/login.defs"); + + /* We pick a range that very conservative: we look at compiled-in maximum and the value in + * /etc/login.defs. That way the uids/gids which we allocate will be interpreted correctly, + * even if /etc/login.defs is removed later. (The bottom bound doesn't matter much, since + * it's only used during allocation, so we use the configured value directly). */ + uid_t begin = defs.system_alloc_uid_min, + end = MIN3((uid_t) SYSTEM_UID_MAX, defs.system_uid_max, defs.system_gid_max); + if (begin < end) { + r = uid_range_add(&uid_range, &n_uid_range, begin, end - begin + 1); + if (r < 0) + return log_oom(); + } } r = add_implicit(); diff --git a/src/test/test-user-record.c b/src/test/test-user-record.c index fcab61d694..d623706648 100644 --- a/src/test/test-user-record.c +++ b/src/test/test-user-record.c @@ -3,10 +3,55 @@ #include <unistd.h> #include <sys/types.h> +#include "fd-util.h" +#include "fileio.h" #include "format-util.h" +#include "fs-util.h" +#include "tmpfile-util.h" #include "tests.h" #include "user-record.h" +static void test_read_login_defs(const char *path) { + log_info("/* %s(\"%s\") */", __func__, path ?: "<custom>"); + + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-user-record.XXXXXX"; + _cleanup_fclose_ FILE *f = NULL; + if (!path) { + assert_se(fmkostemp_safe(name, "r+", &f) == 0); + fprintf(f, + "SYS_UID_MIN "UID_FMT"\n" + "SYS_UID_MAX "UID_FMT"\n" + "SYS_GID_MIN "GID_FMT"\n" + "SYS_GID_MAX "GID_FMT"\n", + SYSTEM_ALLOC_UID_MIN + 5, + SYSTEM_UID_MAX + 5, + SYSTEM_ALLOC_GID_MIN + 5, + SYSTEM_GID_MAX + 5); + assert_se(fflush_and_check(f) >= 0); + } + + UGIDAllocationRange defs; + assert_se(read_login_defs(&defs, path ?: name, NULL) >= 0); + + log_info("system_alloc_uid_min="UID_FMT, defs.system_alloc_uid_min); + log_info("system_uid_max="UID_FMT, defs.system_uid_max); + log_info("system_alloc_gid_min="GID_FMT, defs.system_alloc_gid_min); + log_info("system_gid_max="GID_FMT, defs.system_gid_max); + + if (!path) { + uid_t offset = ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES ? 5 : 0; + assert_se(defs.system_alloc_uid_min == SYSTEM_ALLOC_UID_MIN + offset); + assert_se(defs.system_uid_max == SYSTEM_UID_MAX + offset); + assert_se(defs.system_alloc_gid_min == SYSTEM_ALLOC_GID_MIN + offset); + assert_se(defs.system_gid_max == SYSTEM_GID_MAX + offset); + } else if (streq(path, "/dev/null")) { + assert_se(defs.system_alloc_uid_min == SYSTEM_ALLOC_UID_MIN); + assert_se(defs.system_uid_max == SYSTEM_UID_MAX); + assert_se(defs.system_alloc_gid_min == SYSTEM_ALLOC_GID_MIN); + assert_se(defs.system_gid_max == SYSTEM_GID_MAX); + } +} + static void test_acquire_ugid_allocation_range(void) { log_info("/* %s */", __func__); @@ -48,6 +93,9 @@ static void test_gid_is_system(void) { int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); + test_read_login_defs("/dev/null"); + test_read_login_defs("/etc/login.defs"); + test_read_login_defs(NULL); test_acquire_ugid_allocation_range(); test_uid_is_system(); test_gid_is_system(); diff --git a/test/test-sysusers.sh.in b/test/test-sysusers.sh.in index 39d238c1f7..6e133cc841 100755 --- a/test/test-sysusers.sh.in +++ b/test/test-sysusers.sh.in @@ -20,19 +20,22 @@ prepare_testdir() { return 0 } +[ @SYSTEM_UID_MAX@ -lt @SYSTEM_GID_MAX@ ] && system_guid_max=@SYSTEM_UID_MAX@ || system_guid_max=@SYSTEM_GID_MAX@ + preprocess() { - sed -e "s/SYSTEM_UID_MAX/@SYSTEM_UID_MAX@/g" \ - -e "s/SYSTEM_GID_MAX/@SYSTEM_GID_MAX@/g" \ - -e "s#NOLOGIN#@NOLOGIN@#g" "$1" + m=${2:-$system_guid_max} + + sed -e "s/SYSTEM_UGID_MAX/$m/g; + s#NOLOGIN#@NOLOGIN@#g" "$1" } compare() { - if ! diff -u $TESTDIR/etc/passwd <(preprocess $1.expected-passwd); then + if ! diff -u $TESTDIR/etc/passwd <(preprocess $1.expected-passwd $3); then echo "**** Unexpected output for $f $2" exit 1 fi - if ! diff -u $TESTDIR/etc/group <(preprocess $1.expected-group); then + if ! diff -u $TESTDIR/etc/group <(preprocess $1.expected-group $3); then echo "**** Unexpected output for $f $2" exit 1 fi @@ -97,6 +100,52 @@ compare $SOURCE/inline "(--inline --replace=…)" rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/* +cat >$TESTDIR/etc/login.defs <<EOF +SYS_UID_MIN abcd +SYS_UID_MAX abcd +SYS_GID_MIN abcd +SYS_GID_MAX abcd +SYS_UID_MIN 401 +SYS_UID_MAX 555 +SYS_GID_MIN 405 +SYS_GID_MAX 666 +SYS_UID_MIN abcd +SYS_UID_MAX abcd +SYS_GID_MIN abcd +SYS_GID_MAX abcd +SYS_UID_MIN999 +SYS_UID_MAX999 +SYS_GID_MIN999 +SYS_GID_MAX999 +EOF + +for f in $(ls -1 $SOURCE/test-*.input | sort -V); do + echo "*** Running $f (with login.defs)" + prepare_testdir ${f%.input} + cp $f $TESTDIR/usr/lib/sysusers.d/test.conf + $SYSUSERS --root=$TESTDIR + + [ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max + compare ${f%.*} "(with login.defs)" $bound +done + +rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/* + +mv $TESTDIR/etc/login.defs $TESTDIR/etc/login.defs.moved +ln -s ../../../../../etc/login.defs.moved $TESTDIR/etc/login.defs + +for f in $(ls -1 $SOURCE/test-*.input | sort -V); do + echo "*** Running $f (with login.defs symlinked)" + prepare_testdir ${f%.input} + cp $f $TESTDIR/usr/lib/sysusers.d/test.conf + $SYSUSERS --root=$TESTDIR + + [ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max + compare ${f%.*} "(with login.defs symlinked)" $bound +done + +rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/* + # tests for error conditions for f in $(ls -1 $SOURCE/unhappy-*.input | sort -V); do echo "*** Running test $f" diff --git a/test/test-sysusers/test-10.expected-group b/test/test-sysusers/test-10.expected-group index 1c92158720..c94a8322d2 100644 --- a/test/test-sysusers/test-10.expected-group +++ b/test/test-sysusers/test-10.expected-group @@ -1,2 +1,2 @@ u1:x:300:u2 -u2:x:SYSTEM_UID_MAX: +u2:x:SYSTEM_UGID_MAX: diff --git a/test/test-sysusers/test-10.expected-passwd b/test/test-sysusers/test-10.expected-passwd index ca2d764ea0..e5f2a69993 100644 --- a/test/test-sysusers/test-10.expected-passwd +++ b/test/test-sysusers/test-10.expected-passwd @@ -1,2 +1,2 @@ u1:x:300:300::/:NOLOGIN -u2:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:NOLOGIN +u2:x:SYSTEM_UGID_MAX:SYSTEM_UGID_MAX::/:NOLOGIN diff --git a/test/test-sysusers/test-13.expected-group b/test/test-sysusers/test-13.expected-group index c78ea54bd3..1677d41b45 100644 --- a/test/test-sysusers/test-13.expected-group +++ b/test/test-sysusers/test-13.expected-group @@ -1,5 +1,5 @@ hoge:x:300: baz:x:302: -yyy:x:SYSTEM_GID_MAX: +yyy:x:SYSTEM_UGID_MAX: foo:x:301: ccc:x:305: diff --git a/test/test-sysusers/test-13.expected-passwd b/test/test-sysusers/test-13.expected-passwd index ffc20a8193..4a2c34b4cb 100644 --- a/test/test-sysusers/test-13.expected-passwd +++ b/test/test-sysusers/test-13.expected-passwd @@ -2,4 +2,4 @@ foo:x:301:301::/:NOLOGIN aaa:x:303:302::/:NOLOGIN bbb:x:304:302::/:NOLOGIN ccc:x:305:305::/:NOLOGIN -zzz:x:306:SYSTEM_GID_MAX::/:NOLOGIN +zzz:x:306:SYSTEM_UGID_MAX::/:NOLOGIN diff --git a/test/test-sysusers/test-14.expected-passwd b/test/test-sysusers/test-14.expected-passwd index 62ed4f50af..3c3bef2c8e 100644 --- a/test/test-sysusers/test-14.expected-passwd +++ b/test/test-sysusers/test-14.expected-passwd @@ -1 +1 @@ -aaa:x:SYSTEM_UID_MAX:987::/:NOLOGIN +aaa:x:SYSTEM_UGID_MAX:987::/:NOLOGIN diff --git a/test/test-sysusers/test-2.expected-group b/test/test-sysusers/test-2.expected-group index 8fcc03f4e9..fa216d79de 100644 --- a/test/test-sysusers/test-2.expected-group +++ b/test/test-sysusers/test-2.expected-group @@ -1,4 +1,4 @@ -u1:x:SYSTEM_UID_MAX: +u1:x:SYSTEM_UGID_MAX: u2:x:777: u3:x:778: u4:x:779: diff --git a/test/test-sysusers/test-2.expected-passwd b/test/test-sysusers/test-2.expected-passwd index af8068813b..ce49e84aad 100644 --- a/test/test-sysusers/test-2.expected-passwd +++ b/test/test-sysusers/test-2.expected-passwd @@ -1,4 +1,4 @@ -u1:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX:some gecos:/random/dir:NOLOGIN +u1:x:SYSTEM_UGID_MAX:SYSTEM_UGID_MAX:some gecos:/random/dir:NOLOGIN u2:x:777:777:some gecos:/random/dir:/bin/zsh u3:x:778:778::/random/dir2:/bin/bash u4:x:779:779::/:/bin/csh diff --git a/test/test-sysusers/test-2.input b/test/test-sysusers/test-2.input index cedea9e401..773d9e5da1 100644 --- a/test/test-sysusers/test-2.input +++ b/test/test-sysusers/test-2.input @@ -1,4 +1,4 @@ -# Test generation of ID dynamically based on SYSTEM_UID_MAX and +# Test generation of ID dynamically based on SYSTEM_UGID_MAX and # replacement of all fields up to the login shell. # #Type Name ID GECOS homedir shell diff --git a/test/test-sysusers/test-6.expected-group b/test/test-sysusers/test-6.expected-group index 499c9008ce..2ef661a4a1 100644 --- a/test/test-sysusers/test-6.expected-group +++ b/test/test-sysusers/test-6.expected-group @@ -1,2 +1,2 @@ g1:x:111: -u1:x:SYSTEM_UID_MAX: +u1:x:SYSTEM_UGID_MAX: diff --git a/test/test-sysusers/test-6.expected-passwd b/test/test-sysusers/test-6.expected-passwd index ba55a13e18..d589e2ede6 100644 --- a/test/test-sysusers/test-6.expected-passwd +++ b/test/test-sysusers/test-6.expected-passwd @@ -1 +1 @@ -u1:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:NOLOGIN +u1:x:SYSTEM_UGID_MAX:SYSTEM_UGID_MAX::/:NOLOGIN diff --git a/test/test-sysusers/test-8.expected-passwd b/test/test-sysusers/test-8.expected-passwd index 23e99f0513..b5b8fac437 100644 --- a/test/test-sysusers/test-8.expected-passwd +++ b/test/test-sysusers/test-8.expected-passwd @@ -1 +1 @@ -username:x:SYSTEM_UID_MAX:300::/:NOLOGIN +username:x:SYSTEM_UGID_MAX:300::/:NOLOGIN diff --git a/test/test-sysusers/test-9.expected-passwd b/test/test-sysusers/test-9.expected-passwd index 0bffbcd9c7..fc2a060d69 100644 --- a/test/test-sysusers/test-9.expected-passwd +++ b/test/test-sysusers/test-9.expected-passwd @@ -1,2 +1,2 @@ user1:x:300:300::/:NOLOGIN -user2:x:SYSTEM_UID_MAX:300::/:NOLOGIN +user2:x:SYSTEM_UGID_MAX:300::/:NOLOGIN |