diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index cd273ef2c98..5dcc213b171 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -396,6 +396,7 @@ static const char* default_shell(uid_t uid) { static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) { _cleanup_fclose_ FILE *original = NULL, *passwd = NULL; _cleanup_(unlink_and_freep) char *passwd_tmp = NULL; + struct passwd *pw = NULL; Iterator iterator; Item *i; int r; @@ -409,7 +410,6 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char original = fopen(passwd_path, "re"); if (original) { - struct passwd *pw; r = sync_rights(original, passwd); if (r < 0) @@ -429,6 +429,10 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char return -EEXIST; } + /* Make sure we keep the NIS entries (if any) at the end. */ + if (IN_SET(pw->pw_name[0], '+', '-')) + break; + errno = 0; if (putpwent(pw, passwd) < 0) return errno ? -errno : -EIO; @@ -468,6 +472,17 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char return errno ? -errno : -EIO; } + /* Append the remaining NIS entries if any */ + while (pw) { + errno = 0; + if (putpwent(pw, passwd) < 0) + return errno ? -errno : -EIO; + + pw = fgetpwent(original); + } + if (!IN_SET(errno, 0, ENOENT)) + return -errno; + r = fflush_and_check(passwd); if (r < 0) return r; @@ -567,6 +582,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char ** _cleanup_fclose_ FILE *original = NULL, *group = NULL; _cleanup_(unlink_and_freep) char *group_tmp = NULL; bool group_changed = false; + struct group *gr = NULL; Iterator iterator; Item *i; int r; @@ -580,7 +596,6 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char ** original = fopen(group_path, "re"); if (original) { - struct group *gr; r = sync_rights(original, group); if (r < 0) @@ -604,6 +619,10 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char ** return -EEXIST; } + /* Make sure we keep the NIS entries (if any) at the end. */ + if (IN_SET(gr->gr_name[0], '+', '-')) + break; + r = putgrent_with_members(gr, group); if (r < 0) return r; @@ -636,6 +655,17 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char ** group_changed = true; } + /* Append the remaining NIS entries if any */ + while (gr) { + errno = 0; + if (putgrent(gr, group) != 0) + return errno > 0 ? -errno : -EIO; + + gr = fgetgrent(original); + } + if (!IN_SET(errno, 0, ENOENT)) + return -errno; + r = fflush_sync_and_check(group); if (r < 0) return r; diff --git a/test/TEST-21-SYSUSERS/test-11.expected-group b/test/TEST-21-SYSUSERS/test-11.expected-group new file mode 100644 index 00000000000..815a6c5940e --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-11.expected-group @@ -0,0 +1,6 @@ +o1:x:100: +g1:x:111: +u1:x:222: ++giant:::bill,tina,alan,hetty +-transport::: ++::: diff --git a/test/TEST-21-SYSUSERS/test-11.expected-passwd b/test/TEST-21-SYSUSERS/test-11.expected-passwd new file mode 100644 index 00000000000..3f9ab3901f8 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-11.expected-passwd @@ -0,0 +1,6 @@ +root:x:0:0:root:/root:/bin/bash +systemd-network:x:492:492:Systemd Network Management:/:/usr/sbin/nologin +systemd-resolve:x:491:491:Systemd Resolver:/:/usr/sbin/nologin +systemd-timesync:x:493:493:Systemd Time Synchronization:/:/usr/sbin/nologin +u1:x:222:222::/:/sbin/nologin ++:::::: diff --git a/test/TEST-21-SYSUSERS/test-11.initial-group b/test/TEST-21-SYSUSERS/test-11.initial-group new file mode 100644 index 00000000000..88d31f2c729 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-11.initial-group @@ -0,0 +1,4 @@ +o1:x:100 ++giant:::bill,tina,alan,hetty +-transport::: ++::: diff --git a/test/TEST-21-SYSUSERS/test-11.initial-passwd b/test/TEST-21-SYSUSERS/test-11.initial-passwd new file mode 100644 index 00000000000..45d3ffd5c28 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-11.initial-passwd @@ -0,0 +1,5 @@ +root:x:0:0:root:/root:/bin/bash +systemd-network:x:492:492:Systemd Network Management:/:/usr/sbin/nologin +systemd-resolve:x:491:491:Systemd Resolver:/:/usr/sbin/nologin +systemd-timesync:x:493:493:Systemd Time Synchronization:/:/usr/sbin/nologin ++:::::: diff --git a/test/TEST-21-SYSUSERS/test-11.input b/test/TEST-21-SYSUSERS/test-11.input new file mode 100644 index 00000000000..bffc2cd7eae --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-11.input @@ -0,0 +1,3 @@ +#Type Name ID GECOS HOMEDIR +u u1 222 - - +g g1 111 - - diff --git a/test/TEST-21-SYSUSERS/test.sh b/test/TEST-21-SYSUSERS/test.sh index bebbab9d237..73cbe10b69a 100755 --- a/test/TEST-21-SYSUSERS/test.sh +++ b/test/TEST-21-SYSUSERS/test.sh @@ -10,6 +10,13 @@ test_setup() { mkdir -p $TESTDIR/etc/sysusers.d $TESTDIR/usr/lib/sysusers.d $TESTDIR/tmp } +prepare_testdir() { + rm -f $TESTDIR/etc/*{passwd,group,shadow} + for i in $1.initial-{passwd,group,shadow}; do + test -f $i && cp $i $TESTDIR/etc/${i#*.initial-} + done +} + preprocess() { in="$1" @@ -41,7 +48,7 @@ test_run() { # happy tests for f in test-*.input; do echo "*** Running $f" - rm -f $TESTDIR/etc/*{passwd,group,shadow} + prepare_testdir ${f%.input} cp $f $TESTDIR/usr/lib/sysusers.d/test.conf systemd-sysusers --root=$TESTDIR @@ -50,7 +57,7 @@ test_run() { for f in test-*.input; do echo "*** Running $f on stdin" - rm -f $TESTDIR/etc/*{passwd,group,shadow} + prepare_testdir ${f%.input} touch $TESTDIR/etc/sysusers.d/test.conf cat $f | systemd-sysusers --root=$TESTDIR - @@ -59,7 +66,7 @@ test_run() { for f in test-*.input; do echo "*** Running $f on stdin with --replace" - rm -f $TESTDIR/etc/*{passwd,group,shadow} + prepare_testdir ${f%.input} touch $TESTDIR/etc/sysusers.d/test.conf # this overrides test.conf which is masked on disk cat $f | systemd-sysusers --root=$TESTDIR --replace=/etc/sysusers.d/test.conf - @@ -71,7 +78,7 @@ test_run() { # test --inline echo "*** Testing --inline" - rm -f $TESTDIR/etc/*{passwd,group,shadow} + prepare_testdir # copy a random file to make sure it is ignored cp $f $TESTDIR/etc/sysusers.d/confuse.conf systemd-sysusers --root=$TESTDIR --inline \ @@ -82,7 +89,7 @@ test_run() { # test --replace echo "*** Testing --inline with --replace" - rm -f $TESTDIR/etc/*{passwd,group,shadow} + prepare_testdir # copy a random file to make sure it is ignored cp $f $TESTDIR/etc/sysusers.d/confuse.conf systemd-sysusers --root=$TESTDIR \ @@ -98,7 +105,7 @@ test_run() { # tests for error conditions for f in unhappy-*.input; do echo "*** Running test $f" - rm -f $TESTDIR/etc/*{passwd,group,shadow} + prepare_testdir ${f%.input} cp $f $TESTDIR/usr/lib/sysusers.d/test.conf systemd-sysusers --root=$TESTDIR 2> /dev/null journalctl -t systemd-sysusers -o cat | tail -n1 > $TESTDIR/tmp/err