#!/bin/bash

# check bitlk images parsing

[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
TST_DIR=bitlk-images
MAP=bitlktst
DUMP_VK_FILE=bitlk-test-vk

if [ -n "$CRYPTSETUP_TESTS_RUN_IN_MESON" ]; then
	CRYPTSETUP_VALGRIND=$CRYPTSETUP
else
	CRYPTSETUP_VALGRIND=../.libs/cryptsetup
	CRYPTSETUP_LIB_VALGRIND=../.libs
fi

[ -z "$srcdir" ] && srcdir="."

remove_mapping()
{
	[ -b /dev/mapper/$MAP ] && dmsetup remove --retry $MAP
	rm -rf $TST_DIR
}

fail()
{
	[ -n "$1" ] && echo "$1"
	echo " [FAILED]"
	echo "FAILED backtrace:"
	while caller $frame; do ((frame++)); done
	remove_mapping
	exit 2
}

_sigchld() { local c=$?; [ $c -eq 139 ] && fail "Segfault"; [ $c -eq 134 ] && fail "Aborted"; }
trap _sigchld CHLD

skip()
{
	[ -n "$1" ] && echo "$1"
	echo "Test skipped."
	remove_mapping
	exit 77
}

load_vars()
{
	if echo "$1" | grep -q -e "two-recovery"; then
		# 2 extra variables for image with 2 recovery passphrases
		num_vars=10
	else
		num_vars=8
	fi

	local file=$(echo $1 | sed -e s/^$TST_DIR\\/// | sed -e s/\.img$//)
	eval $(grep -A$num_vars -Fx "[$file]" $TST_DIR/images.conf | grep =)
}

check_dump()
{
	dump=$1
	file=$2

	# load variables for this image from config file
	load_vars $file $num_vars

	# volume size
	dump_size=$(echo "$dump" | grep "Volume size:" | cut -d: -f2 | tr -d "\t\n ")
	[ "$dump_size" = "104857600[bytes]" -o "$dump_size" = "134217728[bytes]" -o "$dump_size" = "105906176[bytes]"  ] || fail " volume size check from dump failed."

	# description
	dump_desc=$(echo "$dump" | grep Description: | cut -d: -f2 | tr -d "\t\n ")
	[ "${dump_desc:0:7}" = "DESKTOP" -o  "${dump_desc:0:3}" = "WIN" ] || fail " Description check from dump failed."

	# GUID
	dump_guid=$(echo "$dump" | grep Version -A 1 | tail -1 | cut -d: -f2 | tr -d "\t\n ")
	[ ! -z "$GUID" -a "$dump_guid" = "$GUID"  ] || fail " GUID check from dump failed."

	# cipher
	dump_cipher=$(echo "$dump" | grep "Cipher name" | cut -d: -f2 | tr -d "\t\n ")
	dump_mode=$(echo "$dump" | grep "Cipher mode" | cut -d: -f2 | tr -d "\t\n ")
	cipher=$(echo "$dump_cipher-$dump_mode")
	[ ! -z "$CIPHER" -a "$cipher" = "$CIPHER" ] || fail " cipher check from dump failed."

	if echo "$file" | grep -q -e "smart-card"; then
		# smart card protected VMK GUID
		dump_sc_vmk=$(echo "$dump" | grep "VMK protected with smart card" -B 1 | head -1 | cut -d: -f2 | tr -d "\t ")
		[ ! -z "$SC_VMK_GUID" -a "$dump_sc_vmk" = "$SC_VMK_GUID" ] || fail " smart card protected VMK GUID check from dump failed."
	elif echo "$file" | grep -q -e "startup-key"; then
		# startup key protected VMK GUID
		dump_sk_vmk=$(echo "$dump" | grep "VMK protected with startup key" -B 1 | head -1 | cut -d: -f2 | tr -d "\t ")
		[ ! -z "$SK_VMK_GUID" -a "$dump_sk_vmk" = "$SK_VMK_GUID" ] || fail " startup key protected VMK GUID check from dump failed."
	elif echo "$file" | grep -q -e "two-recovery"; then
		# second recovery passphrase protected VMK GUID
		dump_rp2_vmk=$(echo "$dump" | grep "VMK protected with recovery passphrase" -B 1 | tail -2 | head -1 | cut -d: -f2 | tr -d "\t ")
		[ ! -z "$RP2_VMK_GUID" -a "$dump_rp2_vmk" = "$RP2_VMK_GUID" ] || fail " second recovery passphrase protected VMK GUID check from dump failed."
	else
		# password protected VMK GUID
		dump_pw_vmk=$(echo "$dump" | grep "VMK protected with passphrase" -B 1 | head -1 | cut -d: -f2 | tr -d "\t ")
		[ ! -z "$PW_VMK_GUID" -a "$dump_pw_vmk" = "$PW_VMK_GUID" ] || fail " password protected VMK GUID check from dump failed."
	fi

	# recovery password protected VMK GUID
	dump_rp_vmk=$(echo "$dump" | grep "VMK protected with recovery passphrase" -B 1 | head -1 | cut -d: -f2 | tr -d "\t ")
	[ ! -z "$RP_VMK_GUID" -a "$dump_rp_vmk" = "$RP_VMK_GUID" ] || fail " recovery password protected VMK GUID check from dump failed."

}

valgrind_setup()
{
	command -v valgrind >/dev/null || fail "Cannot find valgrind."
	[ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable."
	[ ! -f valg.sh ] && fail "Unable to get location of valg runner script."
	if [ -z "$CRYPTSETUP_TESTS_RUN_IN_MESON" ]; then
		export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH"
	fi
}

valgrind_run()
{
	INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@"
}

export LANG=C
[ ! -x "$CRYPTSETUP" ] && skip "Cannot find $CRYPTSETUP, test skipped."
[ ! -d $TST_DIR ] && tar xJSf $srcdir/bitlk-images.tar.xz --no-same-owner 2>/dev/null || skip "Incompatible tar."

[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run

echo "HEADER CHECK"
for file in $(ls $TST_DIR/bitlk-*) ; do
	echo -n " $file"
	out=$($CRYPTSETUP bitlkDump $file)
	check_dump "$out" "$file"
	echo " [OK]"
done

if [ $(id -u) != 0 ]; then
	echo "WARNING: You must be root to run activation part of test, test skipped."
	remove_mapping
	exit 0
fi

echo "ACTIVATION FS UUID CHECK"
for file in $(ls $TST_DIR/bitlk-*) ; do
	# load variables for this image from config file
	load_vars $file

	# test with both passphrase and recovery passphrase
	for PASSPHRASE in $PW $RP ; do
		echo -n " $file"
		echo $PASSPHRASE | $CRYPTSETUP bitlkOpen -r $file --test-passphrase >/dev/null 2>&1
		ret=$?
		[ $ret -eq 1 ] && echo " [N/A]" && continue
		echo $PASSPHRASE | $CRYPTSETUP bitlkOpen -r $file $MAP >/dev/null 2>&1
		ret=$?
		[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "aes-cbc" ) && echo " [N/A]" && continue
		[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "aes-cbc-elephant" ) && echo " [N/A]" && continue
		[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "clearkey" ) && echo " [N/A]" && continue
		[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "eow" ) && echo " [N/A]" && continue
		[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "-4k.img" ) && echo " [N/A]" && continue
		[ $ret -eq 0 ] || fail " failed to open $file ($ret)"
		$CRYPTSETUP status $MAP >/dev/null || fail
		$CRYPTSETUP status /dev/mapper/$MAP >/dev/null || fail
		uuid=$(blkid -p -o value -s UUID /dev/mapper/$MAP)
		sha256sum=$(sha256sum /dev/mapper/$MAP | cut -d" " -f1)
		$CRYPTSETUP remove $MAP || fail
		[ "$uuid" = "$UUID" ] || fail " UUID check failed."
		[ "$sha256sum" = "$SHA256SUM" ] || fail " SHA256 sum check failed."
		echo " [OK]"
	done

	# test with volume key
	rm -f $DUMP_VK_FILE >/dev/null 2>&1
	echo -n " $file"
	echo $PASSPHRASE | $CRYPTSETUP bitlkDump -r $file --dump-volume-key --volume-key-file $DUMP_VK_FILE >/dev/null 2>&1
	ret=$?
	[ $ret -eq 0 ] || fail " failed to dump volume key"
	$CRYPTSETUP bitlkOpen -r $file $MAP --volume-key-file $DUMP_VK_FILE --test-passphrase >/dev/null 2>&1
	ret=$?
	[ $ret -eq 1 ] || fail " test passphrase with volume key unexpectedly succeeded"
	$CRYPTSETUP bitlkOpen -r $file $MAP --volume-key-file $DUMP_VK_FILE >/dev/null 2>&1
	ret=$?
	[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "aes-cbc" ) && echo " [N/A]" && continue
	[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "aes-cbc-elephant" ) && echo " [N/A]" && continue
	[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "clearkey" ) && echo " [N/A]" && continue
	[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "eow" ) && echo " [N/A]" && continue
	[ $ret -eq 1 ] && ( echo "$file" | grep -q -e "-4k.img" ) && echo " [N/A]" && continue
	[ $ret -eq 0 ] || fail " failed to open $file using volume key ($ret)"
	$CRYPTSETUP status $MAP >/dev/null || fail
	$CRYPTSETUP status /dev/mapper/$MAP >/dev/null || fail
	uuid=$(blkid -p -o value -s UUID /dev/mapper/$MAP)
	sha256sum=$(sha256sum /dev/mapper/$MAP | cut -d" " -f1)
	$CRYPTSETUP remove $MAP || fail
	[ "$uuid" = "$UUID" ] || fail " UUID check failed."
	[ "$sha256sum" = "$SHA256SUM" ] || fail " SHA256 sum check failed."
	echo " [OK]"
	rm -f $DUMP_VK_FILE >/dev/null 2>&1

	# startup key test -- we need to use BEK file from the archive
	if echo "$file" | grep -q -e "startup-key"; then
		echo -n " $file"
		bek_file=$(echo $SK_VMK_GUID.BEK | tr /a-z/ /A-Z/)
		$CRYPTSETUP bitlkOpen -r $file --test-passphrase --key-file $TST_DIR/$bek_file
		ret=$?
		[ $ret -eq 1 ] && echo " [N/A]" && continue
		$CRYPTSETUP bitlkOpen -r $file $MAP --key-file $TST_DIR/$bek_file >/dev/null 2>&1
		ret=$?
		[ $ret -eq 0 ] || fail " failed to open $file ($ret)"
		$CRYPTSETUP status $MAP >/dev/null || fail
		$CRYPTSETUP status /dev/mapper/$MAP >/dev/null || fail
		uuid=$(blkid -p -o value -s UUID /dev/mapper/$MAP)
		sha256sum=$(sha256sum /dev/mapper/$MAP | cut -d" " -f1)
		$CRYPTSETUP remove $MAP || fail
		[ "$uuid" = "$UUID" ] || fail " UUID check failed."
		[ "$sha256sum" = "$SHA256SUM" ] || fail " SHA256 sum check failed."
		echo " [OK]"

	fi

	# second recovery key
	if echo "$file" | grep -q -e "two-recovery"; then
		echo -n " $file"
		echo $RP2 | $CRYPTSETUP bitlkOpen -r $file --test-passphrase >/dev/null 2>&1
		ret=$?
		[ $ret -eq 1 ] && echo " [N/A]" && continue
		echo $RP2 | $CRYPTSETUP bitlkOpen -r $file $MAP >/dev/null 2>&1
		ret=$?
		[ $ret -eq 0 ] || fail " failed to open $file ($ret)"
		$CRYPTSETUP status $MAP >/dev/null || fail
		$CRYPTSETUP status /dev/mapper/$MAP >/dev/null || fail
		uuid=$(blkid -p -o value -s UUID /dev/mapper/$MAP)
		sha256sum=$(sha256sum /dev/mapper/$MAP | cut -d" " -f1)
		$CRYPTSETUP remove $MAP || fail
		[ "$uuid" = "$UUID" ] || fail " UUID check failed."
		[ "$sha256sum" = "$SHA256SUM" ] || fail " SHA256 sum check failed."
		echo " [OK]"

	fi
done

remove_mapping
exit 0
