#!/bin/sh
# PCP QA Test No. 1356
# Check selinux attributes, types and classes
#
# Copyright (c) 2021 Ken McDonell.  All Rights Reserved.
#

if [ $# -eq 0 ]
then
    seq=`basename $0`
    echo "QA output created by $seq"
else
    # use $seq from caller, unless not set
    [ -n "$seq" ] || seq=`basename $0`
    echo "QA output created by `basename $0` $*"
fi

# get standard environment, filters and checks
. ./common.product
. ./common.filter
. ./common.check

eval `sed -n -e '/^PCP_SELINUX_DIR *=/s/  *//gp'  /usr/include/pcp/builddefs`
[ -z "$PCP_SELINUX_DIR" ] && _notrun "PCP_SELINIX_DIR not defined in /usr/include/pcp/builddefs"
[ ! -d "$PCP_SELINUX_DIR" ] && _notrun "$PCP_SELINUX_DIR: dir not found"

_cleanup()
{
    cd $here
    $sudo rm -rf $tmp $tmp.*
}

status=0	# success is the default!
$sudo rm -rf $tmp $tmp.* $seq.full
trap "_cleanup; exit \$status" 0 1 2 3 15

seinfo --common >/dev/null 2>&1
if test $? -eq 0
then
    seinfo_common_flag="--common"
else
    seinfo_common_flag=""
fi

# attributes
#
if seinfo -a $seinfo_common_flag >$tmp.attr 2>>$tmp.err
then
    echo "Attributes ..." >>$seq.full
    cat -n $tmp.attr | head -3 >>$seq.full
    echo "..." >>$seq.full
    cat -n $tmp.attr | tail -3 >>$seq.full
else
    _notrun "seinfo -a fails: `cat $tmp.err`"
    # NOTREACHED
fi

# types
#
if seinfo -t $seinfo_common_flag >$tmp.type 2>>$tmp.err
then
    echo "Types ..." >>$seq.full
    cat -n $tmp.type | head -3 >>$seq.full
    echo "..." >>$seq.full
    cat -n $tmp.type | tail -3 >>$seq.full
else
    _notrun "seinfo -t fails: `cat $tmp.err`"
    # NOTREACHED
fi

# classes
#
if seinfo -c $seinfo_common_flag >$tmp.class 2>>$tmp.err
then
    echo "Classes ..." >>$seq.full
    cat -n $tmp.class | head -3 >>$seq.full
    echo "..." >>$seq.full
    cat -n $tmp.class | tail -3 >>$seq.full
else
    _notrun "seinfo -c fails: `cat $tmp.err`"
    # NOTREACHED
fi

# real QA test starts here

# Note: skip $PCP_SELINUX_DIR/pcpupstream-container.te cause if you're
#       not in a container, seinfo does not report some types (it appears)
#
for rule in $PCP_SELINUX_DIR/pcpupstream.te pcpqa.te
do
    echo
    echo "$rule:" | sed -e "s@$PCP_SELINUX_DIR@PCP_SELINUX_DIR@"
    if [ ! -f $rule ]
    then
	echo "Warning: $rule: not found"
	continue
    fi
    $PCP_AWK_PROG <$rule >$tmp.tmp '
$1 == "require"		{ req = 1; next }
req == 1 && $1 == "}"	{ exit }
req == 1		{ print }'

    rm -f $tmp.err
    sed -n <$tmp.tmp -e '/^[ 	]*attribute */{
s///
s/[ 	]*#.*//
s/;//
p
}' \
    | while read attr
    do
	if grep "^[ 	]*$attr\$" $tmp.attr >/dev/null
	then
	    :
	else
	    echo "Error: Attribute \"$attr\" in $rule but not in seinfo -a output"
	    touch $tmp.err
	fi
    done
    [ -f $tmp.err ] || echo "Attributes OK"

    rm -f $tmp.err
    sed -n <$tmp.tmp -e '/^[ 	]*type */{
s///
s/[ 	]*#.*//
s/;//
p
}' \
    | while read type
    do
	if grep "^[ 	]*$type\$" $tmp.type >/dev/null
	then
	    :
	else
	    echo "Error: Type \"$type\" in $rule but not in seinfo -t output"
	    touch $tmp.err
	fi
    done
    [ -f $tmp.err ] || echo "Types OK"

    rm -f $tmp.err
    sed -n <$tmp.tmp -e '/^[ 	]*class */{
s///
s/[ 	]*#.*//
s/{//
s/}//
s/;//
p
}' \
    | while read class perms
    do
	if grep "^[ 	]*$class\$" $tmp.class >/dev/null
	then
	    seinfo -x $seinfo_common_flag --class=$class >$tmp.perm
	    for perm in $perms
	    do
		if grep "^[ 	]*$perm\$" $tmp.perm >/dev/null
		then
		    :
		else
		    echo "Error: Permission \"$perm\" for Class \"$class\" in $rule but not in seinfo -x --class=$class output"
		    touch $tmp.err
		fi
	    done
	else
	    echo "Error: Class \"$class\" in $rule but not in seinfo -c output"
	    touch $tmp.err
	fi
    done
    [ -f $tmp.err ] || echo "Classes and Permissions OK"

done

# success, all done
exit
