uid_t uid;
bool gid_set:1;
- bool gid_must_exist:1;
+ // id_set_strict means that the group with the specified gid must
+ // exist and that the check if a uid clashes with a gid is skipped
+ bool id_set_strict:1;
bool uid_set:1;
bool todo_user:1;
return 0;
}
-static int uid_is_ok(uid_t uid, const char *name) {
+static int uid_is_ok(uid_t uid, const char *name, bool check_with_gid) {
struct passwd *p;
struct group *g;
const char *n;
/* Try to avoid using uids that are already used by a group
* that doesn't have the same name as our new user. */
- i = ordered_hashmap_get(todo_gids, GID_TO_PTR(uid));
- if (i && !streq(i->name, name))
- return 0;
+ if (check_with_gid) {
+ i = ordered_hashmap_get(todo_gids, GID_TO_PTR(uid));
+ if (i && !streq(i->name, name))
+ return 0;
+ }
/* Let's check the files directly */
if (hashmap_contains(database_uid, UID_TO_PTR(uid)))
return 0;
- n = hashmap_get(database_gid, GID_TO_PTR(uid));
- if (n && !streq(n, name))
- return 0;
+ if (check_with_gid) {
+ n = hashmap_get(database_gid, GID_TO_PTR(uid));
+ if (n && !streq(n, name))
+ return 0;
+ }
/* Let's also check via NSS, to avoid UID clashes over LDAP and such, just in case */
if (!arg_root) {
if (!IN_SET(errno, 0, ENOENT))
return -errno;
- errno = 0;
- g = getgrgid((gid_t) uid);
- if (g) {
- if (!streq(g->gr_name, name))
- return 0;
- } else if (!IN_SET(errno, 0, ENOENT))
- return -errno;
+ if (check_with_gid) {
+ errno = 0;
+ g = getgrgid((gid_t) uid);
+ if (g) {
+ if (!streq(g->gr_name, name))
+ return 0;
+ } else if (!IN_SET(errno, 0, ENOENT))
+ return -errno;
+ }
}
return 1;
/* Try to use the suggested numeric uid */
if (i->uid_set) {
- r = uid_is_ok(i->uid, i->name);
+ r = uid_is_ok(i->uid, i->name, !i->id_set_strict);
if (r < 0)
return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid);
if (r == 0) {
if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
log_debug("User ID " UID_FMT " of file not suitable for %s.", c, i->name);
else {
- r = uid_is_ok(c, i->name);
+ r = uid_is_ok(c, i->name, true);
if (r < 0)
return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid);
else if (r > 0) {
/* Otherwise, try to reuse the group ID */
if (!i->uid_set && i->gid_set) {
- r = uid_is_ok((uid_t) i->gid, i->name);
+ r = uid_is_ok((uid_t) i->gid, i->name, true);
if (r < 0)
return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid);
if (r > 0) {
return r;
}
- r = uid_is_ok(search_uid, i->name);
+ r = uid_is_ok(search_uid, i->name, true);
if (r < 0)
return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid);
else if (r > 0)
r = gid_is_ok(i->gid);
if (r < 0)
return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid);
- if (i->gid_must_exist) {
+ if (i->id_set_strict) {
/* If we require the gid to already exist we can return here:
* r > 0: means the gid does not exist -> fail
* r == 0: means the gid exists -> nothing more to do.
if (r < 0)
return log_error_errno(r, "Failed to parse GID: '%s': %m", id);
i->gid_set = true;
- i->gid_must_exist = true;
+ i->id_set_strict = true;
free_and_replace(resolved_id, uid);
}
r = parse_uid(resolved_id, &i->uid);
}
if (!uid_range) {
- /* Default to default range of 1..SYSTEMD_UID_MAX */
+ /* Default to default range of 1..SYSTEM_UID_MAX */
r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX);
if (r < 0) {
log_oom();
--- /dev/null
+root:x:0:0::/root:/bin/sh
+daemon:x:1:1::/usr/sbin:/sbin/nologin
+bin:x:2:2::/bin:/sbin/nologin
+sys:x:3:3::/dev:/sbin/nologin
+sync:x:4:65534::/bin:/sbin/nologin
+games:x:5:60::/usr/games:/sbin/nologin
+man:x:6:12::/var/cache/man:/sbin/nologin
+lp:x:7:7::/var/spool/lpd:/sbin/nologin
+mail:x:8:8::/var/mail:/sbin/nologin
+news:x:9:9::/var/spool/news:/sbin/nologin
+uucp:x:10:10::/var/spool/uucp:/sbin/nologin
+proxy:x:13:13::/bin:/sbin/nologin
+www-data:x:33:33::/var/www:/sbin/nologin
+backup:x:34:34::/var/backups:/sbin/nologin
+list:x:38:38::/var/list:/sbin/nologin
+irc:x:39:39::/var/run/ircd:/sbin/nologin
+gnats:x:41:41::/var/lib/gnats:/sbin/nologin
+nobody:x:65534:65534::/nonexistent:/sbin/nologin
mkdir -p $TESTDIR/etc $TESTDIR/usr/lib/sysusers.d $TESTDIR/tmp
}
+preprocess() {
+ in="$1"
+
+ # see meson.build how to extract this. gcc -E was used before to
+ # get this value from config.h, however the autopkgtest fails with
+ # it
+ SYSTEM_UID_MAX=$(awk 'BEGIN { uid=999 } /^\s*SYS_UID_MAX\s+/ { uid=$2 } END { print uid }' /etc/login.defs)
+ sed "s/SYSTEM_UID_MAX/${SYSTEM_UID_MAX}/g" "$in"
+}
+
test_run() {
# ensure our build of systemd-sysusers is run
PATH=${BUILD_DIR}:$PATH
cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
systemd-sysusers --root=$TESTDIR
- if ! diff -u $TESTDIR/etc/passwd ${f%.*}.expected-passwd; then
+ if ! diff -u $TESTDIR/etc/passwd <(preprocess ${f%.*}.expected-passwd); then
echo "**** Unexpected output for $f"
exit 1
fi
- if ! diff -u $TESTDIR/etc/group ${f%.*}.expected-group; then
+ if ! diff -u $TESTDIR/etc/group <(preprocess ${f%.*}.expected-group); then
echo "**** Unexpected output for $f"
exit 1
fi