1#!/usr/bin/env bash
2# SPDX-License-Identifier: LGPL-2.1-or-later
3set -e
4
5SYSUSERS="${1:-systemd-sysusers}"
6
7[ -e "$(dirname $0)/../systemd-runtest.env" ] && . "$(dirname $0)/../systemd-runtest.env"
8SYSTEMD_TEST_DATA=${SYSTEMD_TEST_DATA:-@SYSTEMD_TEST_DATA@}
9SOURCE=$SYSTEMD_TEST_DATA/test-sysusers
10
11TESTDIR=$(mktemp --tmpdir --directory "test-sysusers.XXXXXXXXXX")
12trap "rm -rf '$TESTDIR'" EXIT INT QUIT PIPE
13
14prepare_testdir() {
15    mkdir -p $TESTDIR/etc/sysusers.d/
16    mkdir -p $TESTDIR/usr/lib/sysusers.d/
17    rm -f $TESTDIR/etc/*{passwd,group,shadow}
18    for i in $1.initial-{passwd,group,shadow}; do
19        test -f $i && cp $i $TESTDIR/etc/${i#*.initial-}
20    done
21    return 0
22}
23
24[ @SYSTEM_UID_MAX@ -lt @SYSTEM_GID_MAX@ ] && system_guid_max=@SYSTEM_UID_MAX@ || system_guid_max=@SYSTEM_GID_MAX@
25
26preprocess() {
27    m=${2:-$system_guid_max}
28
29    sed -e "s/SYSTEM_UGID_MAX/$m/g;
30            s#NOLOGIN#@NOLOGIN@#g" "$1"
31}
32
33compare() {
34    if ! diff -u $TESTDIR/etc/passwd <(preprocess $1.expected-passwd $3); then
35        echo "**** Unexpected output for $f $2"
36        exit 1
37    fi
38
39    if ! diff -u $TESTDIR/etc/group <(preprocess $1.expected-group $3); then
40        echo "**** Unexpected output for $f $2"
41        exit 1
42    fi
43}
44
45rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
46
47# happy tests
48for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
49    echo "*** Running $f"
50    prepare_testdir ${f%.input}
51    cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
52    $SYSUSERS --root=$TESTDIR
53
54    compare ${f%.*} ""
55done
56
57for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
58    echo "*** Running $f on stdin"
59    prepare_testdir ${f%.input}
60    touch $TESTDIR/etc/sysusers.d/test.conf
61    cat $f | $SYSUSERS --root=$TESTDIR -
62
63    compare ${f%.*} "on stdin"
64done
65
66for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
67    echo "*** Running $f on stdin with --replace"
68    prepare_testdir ${f%.input}
69    touch $TESTDIR/etc/sysusers.d/test.conf
70    # this overrides test.conf which is masked on disk
71    cat $f | $SYSUSERS --root=$TESTDIR --replace=/etc/sysusers.d/test.conf -
72    # this should be ignored
73    cat $SOURCE/test-1.input | $SYSUSERS --root=$TESTDIR --replace=/usr/lib/sysusers.d/test.conf -
74
75    compare ${f%.*} "on stdin with --replace"
76done
77
78# test --inline
79echo "*** Testing --inline"
80prepare_testdir $SOURCE/inline
81# copy a random file to make sure it is ignored
82cp $f $TESTDIR/etc/sysusers.d/confuse.conf
83$SYSUSERS --root=$TESTDIR --inline \
84          "u     u1   222 -     - /bin/zsh" \
85          "g     g1   111"
86
87compare $SOURCE/inline "(--inline)"
88
89# test --replace
90echo "*** Testing --inline with --replace"
91prepare_testdir $SOURCE/inline
92# copy a random file to make sure it is ignored
93cp $f $TESTDIR/etc/sysusers.d/confuse.conf
94$SYSUSERS --root=$TESTDIR \
95          --inline \
96          --replace=/etc/sysusers.d/confuse.conf \
97          "u     u1   222 -     - /bin/zsh" \
98          "g     g1   111"
99
100compare $SOURCE/inline "(--inline --replace=…)"
101
102rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
103
104cat >$TESTDIR/etc/login.defs <<EOF
105SYS_UID_MIN abcd
106SYS_UID_MAX abcd
107SYS_GID_MIN abcd
108SYS_GID_MAX abcd
109SYS_UID_MIN 401
110SYS_UID_MAX 555
111SYS_GID_MIN 405
112SYS_GID_MAX 666
113SYS_UID_MIN abcd
114SYS_UID_MAX abcd
115SYS_GID_MIN abcd
116SYS_GID_MAX abcd
117SYS_UID_MIN999
118SYS_UID_MAX999
119SYS_GID_MIN999
120SYS_GID_MAX999
121EOF
122
123for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
124    echo "*** Running $f (with login.defs)"
125    prepare_testdir ${f%.input}
126    cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
127    $SYSUSERS --root=$TESTDIR
128
129    [ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
130    compare ${f%.*} "(with login.defs)" $bound
131done
132
133rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
134
135mv $TESTDIR/etc/login.defs $TESTDIR/etc/login.defs.moved
136ln -s ../../../../../etc/login.defs.moved $TESTDIR/etc/login.defs
137
138for f in $(ls -1 $SOURCE/test-*.input | sort -V); do
139    echo "*** Running $f (with login.defs symlinked)"
140    prepare_testdir ${f%.input}
141    cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
142    $SYSUSERS --root=$TESTDIR
143
144    [ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
145    compare ${f%.*} "(with login.defs symlinked)" $bound
146done
147
148rm -f $TESTDIR/etc/sysusers.d/* $TESTDIR/usr/lib/sysusers.d/*
149
150# tests for error conditions
151for f in $(ls -1 $SOURCE/unhappy-*.input | sort -V); do
152    echo "*** Running test $f"
153    prepare_testdir ${f%.input}
154    cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
155    $SYSUSERS --root=$TESTDIR 2>&1 | tail -n1 > $TESTDIR/err
156    if ! diff -u $TESTDIR/err  ${f%.*}.expected-err; then
157        echo "**** Unexpected error output for $f"
158        cat $TESTDIR/err
159        exit 1
160    fi
161done
162