From 563dc6f8e2cda4114dd20f32655890ed378c3740 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Thu, 15 Mar 2018 18:46:28 +0100 Subject: [PATCH 1/2] sysusers: do not append entries after the NIS ones The NIS-catchall entry switches from files to NIS lookup and never goes back, so it must be the last entry in /etc/passwd (the other +/-{user,@netgroup} entries don't have to be). That's how the nss_compat mode for /etc/passwd (and /etc/group) traditionally works. It's age-old historic behaviour that the NIS entry must be the last one. It doesn't seem to be specified somewhere, but it worked like this since very early SunOS when NIS was first included. Fixes: #8467 --- src/sysusers/sysusers.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index cd273ef2c9..5dcc213b17 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; From 97e34e945c6a047fc8673a7c216090cf164ead1f Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Thu, 15 Mar 2018 13:39:38 +0100 Subject: [PATCH 2/2] test: add a sysusers test with NIS entries --- test/TEST-21-SYSUSERS/test-11.expected-group | 6 ++++++ test/TEST-21-SYSUSERS/test-11.expected-passwd | 6 ++++++ test/TEST-21-SYSUSERS/test-11.initial-group | 4 ++++ test/TEST-21-SYSUSERS/test-11.initial-passwd | 5 +++++ test/TEST-21-SYSUSERS/test-11.input | 3 +++ test/TEST-21-SYSUSERS/test.sh | 19 +++++++++++++------ 6 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 test/TEST-21-SYSUSERS/test-11.expected-group create mode 100644 test/TEST-21-SYSUSERS/test-11.expected-passwd create mode 100644 test/TEST-21-SYSUSERS/test-11.initial-group create mode 100644 test/TEST-21-SYSUSERS/test-11.initial-passwd create mode 100644 test/TEST-21-SYSUSERS/test-11.input 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 0000000000..815a6c5940 --- /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 0000000000..3f9ab3901f --- /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 0000000000..88d31f2c72 --- /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 0000000000..45d3ffd5c2 --- /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 0000000000..bffc2cd7ea --- /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 bebbab9d23..73cbe10b69 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