#!/bin/sh

# Copy packet generating program to unique name, so we can find it in the output
# from dmesg. Print the copy's name.
copy() {
	progcopy=$(mktemp ./sft-XXXXXX) # Fits in sched.h's TASK_COMM_LEN.
	if [ x$(basename $1) = x$1 ]; then
		cp $(which $1) $progcopy 
	else
		cp $1 $progcopy # Uniquely rename to find in dmesg output.
	fi
	chmod +x $progcopy
	echo $progcopy
}

failmsg() {
	echo "*FAIL* ($*)"
}

passmsg() {
	echo " PASS  ($*)"
}

# Copy packet_generator arg. to a random name, so we can identify its use in a log.
# Then, run the prog command and check to see if it produced evil packets.
test() {
	regex=$1
	evil=$2
	good=$3
	bad=$4
	prog=$5
	shift # Regex.
	shift # Evil flag.
	shift # Good message.
	shift # Bad message. 
	shift # Program; rest are args. to prog.
	baseprog=$(basename $prog)
	$prog $* > /dev/null
	if [ $? != 0 ]; then
		failmsg $prog $* itself failed
		return 1
	fi
	# Lazy-eval \$baseprog in $regex:
	dmesg | eval grep \"$regex\" > /dev/null
	see_no_evil=$?
	if [ xevil = x$evil ]; then
		if [ 1 = $see_no_evil ]; then
			failmsg $baseprog $bad
			return 1
		else
			passmsg $baseprog $good
			return 0
		fi
	else
		if [ 1 = $see_no_evil ]; then
			passmsg $baseprog $good
			return 0
		else
			failmsg $baseprog $bad
			return 1
		fi
	fi
}

test_evil_bit() {
	test "setting evil bit.*\$baseprog" evil "tainted" "should have been tainted" $*
}

test_ipv6_evil_label() {
	test "setting IPv6 evil label.*\$baseprog" evil "tainted" "should have been tainted" $*
}

test_taint_logged() {
	test "tainting process running .*\$baseprog.*due to.*interaction with" evil "tainted" "should have been tainted" $*
}

test_wait_logged() {
	test "waiting on tainted \$baseprog" evil "logged wait" "should have logged wait" $*
}

test_ipv6_no_evil_label() {
	test "setting IPv6 evil label.*\$baseprog" no_evil "not tainted" "should not have been tainted" $*
}

test_no_evil_bit() {
	test "setting evil bit.*\$baseprog" no_evil "not tainted" "should not have been tainted" $*
}

test_taint_not_logged() {
	test "tainting process running .*\$baseprog.*due to.*interaction with" no_evil "not tainted" "should not have been tainted" $*
}

test_wait_not_logged() {
	test "waiting on tainted \$baseprog" no_evil "did not log wait" "should not have logged wait" $*
}

if [ x$(whoami) != xroot ]; then
	echo Please run as root using sudo from a non-root account. >&2
	exit 1
fi

if [ -z "$SUDO_USER" ]; then
	echo Please run as root using sudo from a non-root account. >&2
	exit 1
fi

if [ x$SUDO_USER == xroot ]; then
	echo Please run as root using sudo from a non-root account. >&2
	exit 1
fi

if [ -z "$1" ]; then
	SF_HOSTNAME=www.flyn.org
else
	SF_HOSTNAME=$1
fi

# Protect /dev/tty* and /dev/pts/* from becoming marked and thus tainting
# this script and the calling shell:
exec 3<&0         # Dup. stdin  to f.d. 3.
exec <   /dev/null
exec 4>&1         # Dup. stdout to f.d. 4.
rm -f test.log
exec  >> test.log # Redir stdout to log.
exec 2>> test.log # Redir stderr to log.
# Untaint self, unmark log, and print log.
trap "echo 0 > /proc/$$/attr/current; setfattr -x security.simple-flow.confidential test.log . 2> /dev/null; cat test.log >&4" EXIT SIGTERM SIGQUIT

# rm calls stat on operand, so unlabel confidential because this source file
# sometimes gets included by scripts which are not wait-trusted (tainted rm
# would taint these scripts).
setfattr -x security.simple-flow.confidential confidential 2> /dev/null
rm -f confidential
echo https://$SF_HOSTNAME/ > confidential
./programs/setconfidential confidential

rm -f never
echo 'Hello, world!' > never
./programs/setnever never

./programs/resetxattrs > /dev/null

[ -x programs/msgtool ] || ( cd programs && su -c make $SUDO_USER > /dev/null )
[ -x programs/shmtool ] || ( cd programs && su -c make $SUDO_USER > /dev/null )
