mirror of
https://github.com/ovh/debian-cis.git
synced 2024-12-04 04:28:19 +01:00
de295b3a77
* Revert "fix: clean obsolete check 99.5.4.5.1, now handled by 5.3.4 (#215)"
This reverts commit 670c8c62f5
.
We still want to verify the preexisting hashes in /etc/shadow,
even if the PAM configuration is correct for new passwords (5.3.4).
* Adapt 5.3.4, 99.5.4.5.1 and 99.5.4.5.2 to yescrypt
227 lines
6.2 KiB
Bash
Executable File
227 lines
6.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# run-shellcheck
|
|
# stop on any error
|
|
set -e
|
|
# stop on undefined variable
|
|
set -u
|
|
|
|
mytmpdir=$(mktemp -d -t debian-cis-test.XXXXXX)
|
|
totalerrors=255
|
|
|
|
cleanup_and_exit() {
|
|
rm -rf "$mytmpdir"
|
|
if [ "$totalerrors" -eq 255 ]; then
|
|
fatal "RUNTIME ERROR"
|
|
fi
|
|
exit $totalerrors
|
|
}
|
|
trap "cleanup_and_exit" EXIT HUP INT
|
|
|
|
outdir="$mytmpdir/out"
|
|
mkdir -p "$outdir" || exit 1
|
|
|
|
tests_list=""
|
|
testno=0
|
|
testcount=0
|
|
|
|
skip_tests=0
|
|
dismiss_count=0
|
|
nbfailedret=0
|
|
nbfailedgrep=0
|
|
nbfailedconsist=0
|
|
listfailedret=""
|
|
listfailedgrep=""
|
|
listfailedconsist=""
|
|
|
|
usecase=""
|
|
usecase_name=""
|
|
usecase_name_root=""
|
|
usecase_name_sudo=""
|
|
declare -a REGISTERED_TESTS
|
|
|
|
#####################
|
|
# Utility functions #
|
|
#####################
|
|
# in case a fatal event occurs, fatal logs and exits with return code 1
|
|
fatal() {
|
|
printf "\033[1;91m###### \033[0m\n" >&2
|
|
printf "%b %b\n" "\033[1;91mFATAL\033[0m" "$*" >&2
|
|
printf "%b \n" "\033[1;91mEXIT TEST SUITE WITH FAILURE\033[0m" >&2
|
|
trap - EXIT
|
|
exit 255
|
|
}
|
|
# prints that a test failed
|
|
fail() {
|
|
printf "%b %b\n" "\033[1;30m\033[41m[FAIL]\033[0m" "$*" >&2
|
|
}
|
|
# prints that a test succeded
|
|
ok() {
|
|
printf "%b %b\n" "\033[30m\033[42m[ OK ]\033[0m" "$*" >&2
|
|
}
|
|
|
|
skip() {
|
|
printf "%b %b\n" "\033[30m\e[43m[SKIP]\033[0m" "$*" >&2
|
|
}
|
|
# retrieves audit script logfile
|
|
get_stdout() {
|
|
cat "$outdir"/"$usecase_name".log
|
|
}
|
|
|
|
# Reset the list of test assertions
|
|
clear_registered_tests() {
|
|
unset REGISTERED_TESTS
|
|
declare -a REGISTERED_TESTS
|
|
# shellcheck disable=2034
|
|
dismiss_count=0
|
|
skip_tests=0
|
|
}
|
|
|
|
# Generates a formated test name
|
|
make_usecase_name() {
|
|
usecase=$1
|
|
shift
|
|
role=$1
|
|
usecase_name=$(printf '%03d-%s-%s-%s' "$testno" "$name" "$usecase" "$role" | sed -re "s=/=_=g")
|
|
echo -n "$usecase_name"
|
|
}
|
|
|
|
# Plays the registered test suite
|
|
play_registered_tests() {
|
|
if [ "$skip_tests" -eq 1 ]; then
|
|
return
|
|
fi
|
|
usecase_name=$1
|
|
if [[ "${REGISTERED_TESTS[*]}" ]]; then
|
|
export numtest=${#REGISTERED_TESTS[@]}
|
|
for t in "${!REGISTERED_TESTS[@]}"; do
|
|
${REGISTERED_TESTS[$t]}
|
|
done
|
|
fi
|
|
}
|
|
|
|
# Plays comparison tests to ensure that root and sudo exection have the same output
|
|
play_consistency_tests() {
|
|
consist_test=0
|
|
printf "\033[34m*** [%03d] %s::%s Root/Sudo Consistency Tests\033[0m\n" "$testno" "$test_file" "$usecase"
|
|
retfile_root=$outdir/${usecase_name_root}.retval
|
|
retfile_sudo=$outdir/${usecase_name_sudo}.retval
|
|
cmp "$retfile_root" "$retfile_sudo" && ret=0 || ret=1
|
|
if [[ ! 0 -eq $ret ]]; then
|
|
fail "$name" return values differ
|
|
diff "$retfile_root" "$retfile_sudo" || true
|
|
consist_test=1
|
|
else
|
|
ok "$name return values are equal"
|
|
|
|
fi
|
|
retfile_root=$outdir/${usecase_name_root}.log
|
|
retfile_sudo=$outdir/${usecase_name_sudo}.log
|
|
cmp "$retfile_root" "$retfile_sudo" && ret=0 || ret=1
|
|
if [[ ! 0 -eq $ret ]]; then
|
|
fail "$name" logs differ
|
|
diff "$retfile_root" "$retfile_sudo" || true
|
|
consist_test=1
|
|
else
|
|
ok "$name logs are identical"
|
|
fi
|
|
|
|
if [ 1 -eq $consist_test ]; then
|
|
nbfailedconsist=$((nbfailedconsist + 1))
|
|
listfailedconsist="$listfailedconsist $(make_usecase_name "$usecase" consist)"
|
|
fi
|
|
}
|
|
|
|
# Actually runs one single audit script
|
|
_run() {
|
|
usecase_name=$1
|
|
shift
|
|
printf "\033[34m*** [%03d] %s \033[0m(%s)\n" "$testno" "$usecase_name" "$*"
|
|
bash -c "$*" >"$outdir/$usecase_name.log" 2>"$outdir/${usecase_name}_err.log" && true
|
|
echo $? >"$outdir/$usecase_name.retval"
|
|
ret=$(<"$outdir"/"$usecase_name".retval)
|
|
get_stdout
|
|
if [ -s "$outdir/${usecase_name}_err.log" ]; then
|
|
echo ">>> stderr follows"
|
|
cat "$outdir/${usecase_name}_err.log"
|
|
echo "<<< end of stderr"
|
|
fi
|
|
}
|
|
|
|
# Load assertion functions for functionnal tests
|
|
if [ ! -f "$(dirname "$0")"/lib.sh ]; then
|
|
fatal "Cannot locate lib.sh"
|
|
fi
|
|
# shellcheck source=../tests/lib.sh
|
|
. "$(dirname "$0")"/lib.sh
|
|
|
|
###################
|
|
# Execution start #
|
|
###################
|
|
printf "\033[1;36m###\n### %s\n### \033[0m\n" "Starting debian-cis functional testing"
|
|
|
|
. /etc/default/cis-hardening
|
|
|
|
# if no scripts were passed as arguments, list all available test scenarii to be played
|
|
if [ $# -eq 0 ]; then
|
|
tests_list=$(ls -v "$(dirname "$0")"/hardening/)
|
|
testcount=$(wc -l <<<"$tests_list")
|
|
else
|
|
tests_list="$*"
|
|
testcount=$#
|
|
fi
|
|
|
|
for test_file in $tests_list; do
|
|
test_file_path=$(dirname "$0")/hardening/"$test_file"
|
|
if [ ! -f "$test_file_path" ]; then
|
|
fatal "Test file \"$test_file\" does not exist"
|
|
fi
|
|
# script var is used inside test files
|
|
# shellcheck disable=2034
|
|
script="$(basename "$test_file" .sh)"
|
|
# source test scenario file to add `test_audit` func
|
|
# shellcheck disable=1090
|
|
. "$test_file_path"
|
|
testno=$((testno + 1))
|
|
# shellcheck disable=2001
|
|
name="$(echo "${test_file%%.sh}" | sed 's/\d+\.\d+_//')"
|
|
printf "\033[1;36m### [%03d/%03d] %s \033[0m\n" "$testno" "$testcount" "$test_file"
|
|
# test_audit is the function defined in $test_file, that carries the actual functional tests for this script
|
|
test_audit
|
|
# reset var names
|
|
usecase_name=""
|
|
usecase_name_root=""
|
|
usecase_name_sudo=""
|
|
unset -f test_audit
|
|
echo ""
|
|
done
|
|
|
|
stderrunexpected=""
|
|
for file in "$outdir"/*_err.log; do
|
|
if [ -s "$file" ]; then
|
|
stderrunexpected="$stderrunexpected $(basename "$file")"
|
|
fi
|
|
done
|
|
|
|
printf "\033[1;36m###\n### %s \033[0m\n" "Test report"
|
|
if [ $((nbfailedret + nbfailedgrep + nbfailedconsist)) -eq 0 ] && [ -z "$stderrunexpected" ]; then
|
|
echo -e "\033[42m\033[30mAll tests succeeded :)\033[0m"
|
|
echo -e "\033[42m\033[30mStderr is empty :)\033[0m"
|
|
|
|
else
|
|
(
|
|
echo -e "\033[41mOne or more tests failed :(\033[0m"
|
|
echo -e "- $nbfailedret unexpected return values ${listfailedret}"
|
|
echo -e "- $nbfailedgrep unexpected text values $listfailedgrep"
|
|
echo -e "- $nbfailedconsist root/sudo consistency $listfailedconsist"
|
|
echo -e "- stderr detected on $stderrunexpected"
|
|
) | tee "$outdir"/summary
|
|
fi
|
|
echo
|
|
|
|
set +e
|
|
set +u
|
|
totalerrors=$((nbfailedret + nbfailedgrep + nbfailedconsist))
|
|
# leave `exit 255` for runtime errors
|
|
[ $totalerrors -ge 255 ] && totalerrors=254
|
|
exit $totalerrors
|