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
*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)
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
static thread_local bool initialized = false;
if (!initialized) {
- (void) read_login_defs(&defs, NULL);
+ (void) read_login_defs(&defs, NULL, NULL);
initialized = true;
}
#endif
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 {
#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"
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();
#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__);
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();
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
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"
u1:x:300:u2
-u2:x:SYSTEM_UID_MAX:
+u2:x:SYSTEM_UGID_MAX:
u1:x:300:300::/:NOLOGIN
-u2:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:NOLOGIN
+u2:x:SYSTEM_UGID_MAX:SYSTEM_UGID_MAX::/:NOLOGIN
hoge:x:300:
baz:x:302:
-yyy:x:SYSTEM_GID_MAX:
+yyy:x:SYSTEM_UGID_MAX:
foo:x:301:
ccc:x:305:
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
-aaa:x:SYSTEM_UID_MAX:987::/:NOLOGIN
+aaa:x:SYSTEM_UGID_MAX:987::/:NOLOGIN
-u1:x:SYSTEM_UID_MAX:
+u1:x:SYSTEM_UGID_MAX:
u2:x:777:
u3:x:778:
u4:x:779:
-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
-# 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
g1:x:111:
-u1:x:SYSTEM_UID_MAX:
+u1:x:SYSTEM_UGID_MAX:
-u1:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:NOLOGIN
+u1:x:SYSTEM_UGID_MAX:SYSTEM_UGID_MAX::/:NOLOGIN
-username:x:SYSTEM_UID_MAX:300::/:NOLOGIN
+username:x:SYSTEM_UGID_MAX:300::/:NOLOGIN
user1:x:300:300::/:NOLOGIN
-user2:x:SYSTEM_UID_MAX:300::/:NOLOGIN
+user2:x:SYSTEM_UGID_MAX:300::/:NOLOGIN