#! /bin/sh
# Automated libuser fs function regression tester
#
# Copyright (c) 2012 Red Hat, Inc. All rights reserved.
#
# This is free software; you can redistribute it and/or modify it under
# the terms of the GNU Library General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Author: Miloslav Trmač <mitr@redhat.com>

if ! fakeroot --version &>/dev/null; then
    echo 'fakeroot not available, skipping test' >&2
    exit 77
fi

srcdir=$srcdir/tests

workdir=$(pwd)/test_fs

umask 002

trap 'status=$?; chmod -R u+rwx "$workdir"; rm -rf "$workdir"; exit $status' 0
trap '(exit 1); exit 1' 1 2 13 15

rm -rf "$workdir"
mkdir "$workdir"

# Set up an the environment
mkdir "$workdir"/files
> "$workdir"/files/passwd
> "$workdir"/files/shadow
> "$workdir"/files/group
> "$workdir"/files/gshadow

# Set up the client
LIBUSER_CONF=$workdir/libuser.conf
export LIBUSER_CONF
sed "s|@WORKDIR@|$workdir|g; s|@TOP_BUILDDIR@|$(pwd)|g" \
    < "$srcdir"/fs.conf.in > "$LIBUSER_CONF"
# Ugly non-portable hacks
LD_LIBRARY_PATH=$(pwd)/lib/.libs
export LD_LIBRARY_PATH
PYTHONPATH=$(pwd)/python/.libs
export PYTHONPATH

# Test lu_homedir_remove()
fakeroot > "$workdir"/rm_output <<EOF
# User's "own" content
mkdir -p "$workdir"/rm/root/{dir,unreadable}
touch "$workdir"/rm/{kept,root/{dir,unreadable}/f}
mkfifo "$workdir"/rm/root/fifo
ln -s ../kept "$workdir"/rm/root/symlink
chown -R 555:555 "$workdir"/rm/root
chmod 701 "$workdir"/rm/root
chmod 000 "$workdir"/rm/root/unreadable

# Other content in the home directory
mknod "$workdir"/rm/root/block b 1 1
mknod "$workdir"/rm/root/char c 1 1
echo 'foo' > "$workdir"/rm/secret
chmod 000 "$workdir"/rm/secret
ln "$workdir"/rm/{secret,root/hardlink}

$VALGRIND python "$srcdir"/fs_test.py --remove "$workdir/rm/root"
if [ \$? -ne 0 ]; then
   exit 1
fi

LC_ALL=C ls -lnR "$workdir/rm" | tail -n +3 | \
	awk '{ printf("%.10s %d %4d %4d %8d %s\n",
		      \$1, \$2, \$3, \$4, \$5, \$9) ;}'

EOF

diff "$workdir"/rm_output - <<EOF
-rw-rw-r-- 1    0    0        0 kept
---------- 1    0    0        4 secret
EOF
if [ $? -ne 0 ]; then
    exit 1
fi


# Test lu_homedir_remove_for_user_if_owned()
fakeroot > "$workdir"/rm_owned_output1 <<EOF
# User's "own" content
mkdir -p "$workdir"/rm_owned1/root/dir
touch "$workdir"/rm_owned1/root/dir/f
chown -R 555:555 "$workdir"/rm_owned1/root
chmod 701 "$workdir"/rm_owned1/root

# Other content in the home directory
mkdir "$workdir"/rm_owned1/root/non-owned-dir
touch "$workdir"/rm_owned1/root/non-owned-dir/f

$VALGRIND python "$srcdir"/fs_test.py --remove-if-owned \
	"$workdir/rm_owned1/root" 555
if [ \$? -ne 0 ]; then
   exit 1
fi

LC_ALL=C ls -lnR "$workdir"/rm_owned1 | tail -n +3 | \
	awk '{ printf("%.10s %d %4d %4d %8d %s\n",
		      \$1, \$2, \$3, \$4, \$5, \$9) ;}'

EOF

diff "$workdir"/rm_owned_output1 - <<EOF
EOF
if [ $? -ne 0 ]; then
    exit 1
fi

# Nothing is touched if the home directory is not owned by the right UID
fakeroot > "$workdir"/rm_owned_output2 2>&1 <<EOF
# Non-owned home directory
mkdir -p "$workdir"/rm_owned2/root/dir
touch "$workdir"/rm_owned2/root/dir/f
chown -R 555:555 "$workdir"/rm_owned2/root
chown 444:444 "$workdir"/rm_owned2/root
chmod 701 "$workdir"/rm_owned2/root

# Other content in the home directory
mkdir "$workdir"/rm_owned2/root/non-owned-dir
touch "$workdir"/rm_owned2/root/non-owned-dir/f

$VALGRIND python "$srcdir"/fs_test.py --remove-if-owned \
	"$workdir/rm_owned2/root" 555
echo \$?

cd "$workdir"/rm_owned2
LC_ALL=C ls -lnR | \
	awk 'NF > 3 { printf("%.10s %d %4d %4d %s\n",
			     \$1, \$2, \$3, \$4, \$9); }
             NF <= 3 && !/total/ { print }'
EOF

diff "$workdir"/rm_owned_output2 - <<EOF
\`$workdir/rm_owned2/root' is not owned by UID \`555'
1
.:
drwx-----x 4  444  444 root

./root:
drwxrwxr-x 2  555  555 dir
drwxrwxr-x 2    0    0 non-owned-dir

./root/dir:
-rw-rw-r-- 1  555  555 f

./root/non-owned-dir:
-rw-rw-r-- 1    0    0 f
EOF
if [ $? -ne 0 ]; then
    exit 1
fi


# Prepare an "interesting" home directory, to be used both directly and as
# a skeleton
fakeroot -s "$workdir"/save <<EOF
mkdir -p "$workdir"/common/{dir,unreadable,group-owned}
cd "$workdir"/common
# User's "own" content
for i in '.' dir group-owned; do
    touch "\$i"/f "\$i"/setuid
    chmod u+xs "\$i"/setuid
    mkfifo "\$i"/fifo
    ln -s ../outside "\$i"/symlink
done
mkdir setgid
chmod g+s setgid
echo 'content' > unreadable/f
chmod 000 unreadable/f unreadable
chown -R 555:555 .
chgrp -R 444 group-owned

# Other content in the home directory
mknod block b 1 1
mknod char c 1 1
echo 'foo' > secret
chmod 000 secret
EOF


# Test lu_homedir_move()
fakeroot -i "$workdir"/save -s "$workdir"/save > "$workdir"/mv_output <<EOF
cp -a "$workdir"/common "$workdir"/home1
# This seems to be a fakeroot bug
# (https://bugzilla.redhat.com/show_bug.cgi?id=887001) - in the copy, mode-0
# files are really unreadable in the underlying filesystem.  However, a chmod
# resets the state.
chmod 0 "$workdir"/home1/{unreadable,unreadable/f,secret}

$VALGRIND python "$srcdir"/fs_test.py --move "$workdir"/{home1,home2}
if [ \$? -ne 0 ]; then
   exit 1
fi

cd "$workdir"/home2
LC_ALL=C ls -lnR | \
	awk 'NF > 3 { printf("%.10s %d %4d %4d %s\n",
			     \$1, \$2, \$3, \$4, \$9); }
             NF <= 3 && !/total/ { print }'
EOF

# Special files and fifos are not copied over.  Ownership and permissions are
# preserved.
diff "$workdir"/mv_output - <<EOF
.:
drwx------ 2  555  555 dir
-rw------- 1  555  555 f
drwx------ 2  555  444 group-owned
---------- 1    0    0 secret
drwxrwsr-x 2  555  555 setgid
-rwsrw-r-- 1  555  555 setuid
lrwxrwxrwx 1  555  555 symlink
d--------- 2  555  555 unreadable

./dir:
-rw------- 1  555  555 f
-rwsrw-r-- 1  555  555 setuid
lrwxrwxrwx 1  555  555 symlink

./group-owned:
-rw------- 1  555  444 f
-rwsrw-r-- 1  555  444 setuid
lrwxrwxrwx 1  555  444 symlink

./setgid:

./unreadable:
---------- 1  555  555 f
EOF
if [ $? -ne 0 ]; then
    exit 1
fi

# Moving onto an existing directory is prohibited
fakeroot > "$workdir"/mv2_output 2>&1 <<EOF
mkdir "$workdir"/mv2home{1,2}

$VALGRIND python "$srcdir"/fs_test.py --move "$workdir"/mv2home{1,2}
echo \$?
EOF
diff "$workdir"/mv2_output - <<EOF
Error creating \`$workdir/mv2home2': File exists
1
EOF
if [ $? -ne 0 ]; then
    exit 1
fi


# Test lu_homedir_populate()
fakeroot -i "$workdir"/save -s "$workdir"/save > "$workdir"/pop_output <<EOF
cp -a "$workdir"/common "$workdir"/skel
# This seems to be a fakeroot bug
# (https://bugzilla.redhat.com/show_bug.cgi?id=887001) - in the copy, mode-0
# files are really unreadable in the underlying filesystem.  However, a chmod
# resets the state.
chmod 0 "$workdir"/skel/{unreadable,unreadable/f,secret}
chown -R 0:0 "$workdir"/skel
chgrp -R 444 "$workdir"/skel/group-owned

$VALGRIND python "$srcdir"/fs_test.py --populate "$workdir"/newhome 556 557
if [ \$? -ne 0 ]; then
   exit 1
fi

cd "$workdir"/newhome
LC_ALL=C ls -lnR | \
	awk 'NF > 3 { printf("%.10s %d %4d %4d %s\n",
			     \$1, \$2, \$3, \$4, \$9); }
             NF <= 3 && !/total/ { print }'
EOF

# Special files and fifos are not copied over.  Permissions are preserved,
# ownership is changed to the desired values except for non-root groups
diff "$workdir"/pop_output - <<EOF
.:
drwx------ 2  556  557 dir
-rw------- 1  556  557 f
drwx------ 2  556  444 group-owned
---------- 1  556  557 secret
drwxrwsr-x 2  556  557 setgid
-rwsrw-r-- 1  556  557 setuid
lrwxrwxrwx 1  556  557 symlink
d--------- 2  556  557 unreadable

./dir:
-rw------- 1  556  557 f
-rwsrw-r-- 1  556  557 setuid
lrwxrwxrwx 1  556  557 symlink

./group-owned:
-rw------- 1  556  444 f
-rwsrw-r-- 1  556  444 setuid
lrwxrwxrwx 1  556  444 symlink

./setgid:

./unreadable:
---------- 1  556  557 f
EOF
if [ $? -ne 0 ]; then
    exit 1
fi

# Populating an existing directory is prohibited
fakeroot > "$workdir"/pop2_output 2>&1 <<EOF
rm -rf "$workdir"/skel
mkdir "$workdir"/{skel,pop2}

$VALGRIND python "$srcdir"/fs_test.py --populate "$workdir"/pop2 556 557
echo \$?
EOF
diff "$workdir"/pop2_output - <<EOF
Error creating \`$workdir/pop2': File exists
1
EOF
if [ $? -ne 0 ]; then
    exit 1
fi
