summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/shared/user-record.c13
-rw-r--r--src/shared/user-record.h1
-rw-r--r--src/sysusers/sysusers.c22
-rw-r--r--src/test/test-user-record.c48
4 files changed, 76 insertions, 8 deletions
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();