#! /bin/sh

#
# Copyright Rainer Wichmann (2006)
#
# License Information:
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

BUILDOPTS="--quiet $TRUST --enable-xml-log --enable-suidcheck --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
export BUILDOPTS

MAXTEST=7; export MAXTEST

## Quarantine SUID/SGID files if found
#
# SuidCheckQuarantineFiles = yes

## Method for Quarantining files:
#  0 - Delete or truncate the file.
#  1 - Remove SUID/SGID permissions from file.
#  2 - Move SUID/SGID file to quarantine dir.
#
# SuidCheckQuarantineMethod = 0

## For method 0 and 2, really delete instead of truncating
# 
# SuidCheckQuarantineDelete = yes

SUIDPOLICY_7="
[ReadOnly]
file=${BASE}
[SuidCheck]
SuidCheckActive = yes
SuidCheckExclude = ${BASE}/a/a
SuidCheckInterval = 10
SeveritySuidCheck = crit
SuidCheckQuarantineFiles = no
SuidCheckQuarantineMethod = 2
SuidCheckQuarantineDelete = yes
"

mod_suiddata_7 () {
    one_sec_sleep
    chmod 4444 "${BASE}/a/a/y"
    chmod 4444 "${BASE}/a/a/a/y"
    mkdir "${BASE}/a/abc"
    touch "${BASE}/a/abc/y"
    chmod 4444 "${BASE}/a/abc/y"
}

chk_suiddata_7 () {
    one_sec_sleep
    tmp=`ls -l "${BASE}/a/a/y" 2>/dev/null | awk '{ print $1}'`
    if [ "x$tmp" = "x-r-Sr--r--" ]; then
	egrep "CRIT.*POLICY \[SuidCheck\].*${BASE}/a/a/y" $LOGFILE >/dev/null 2>&1
	if [ $? -eq 0 ]; then
	    [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y";
	    return 1
	fi
	egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/y" $LOGFILE >/dev/null 2>&1
	if [ $? -eq 0 ]; then
	    [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y";
	    return 1
	fi
    else
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (suid not kept)";
	return 1
    fi
    tmp=`ls -l "${BASE}/a/a/a/y" 2>/dev/null | awk '{ print $1}'`
    if [ "x$tmp" = "x-r-Sr--r--" ]; then
	egrep "CRIT.*POLICY \[SuidCheck\].*${BASE}/a/a/a/y" $LOGFILE >/dev/null 2>&1
	if [ $? -eq 0 ]; then
	    [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/a/y";
	    return 1
	fi
	egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/a/y" $LOGFILE >/dev/null 2>&1
	if [ $? -eq 0 ]; then
	    [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/a/y";
	    return 1
	fi
    else
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/a/y (suid not kept)";
	return 1
    fi
    tmp=`ls -l "${BASE}/a/abc/y" 2>/dev/null | awk '{ print $1}'`
    if [ "x$tmp" = "x-r-Sr--r--" ]; then
	egrep "CRIT.*POLICY \[SuidCheck\].*${BASE}/a/abc/y" $LOGFILE >/dev/null 2>&1
	if [ $? -ne 0 ]; then
	    [ -z "$verbose" ] || log_msg_fail "${BASE}/a/abc/y";
	    return 1
	fi
	egrep "CRIT.*POLICY ADDED.*${BASE}/a/abc/y" $LOGFILE >/dev/null 2>&1
	if [ $? -ne 0 ]; then
	    [ -z "$verbose" ] || log_msg_fail "${BASE}/a/abc/y";
	    return 1
	fi
	return 0;
    else
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/abc/y (suid not kept)";
	return 1
    fi
}


SUIDPOLICY_6="
[ReadOnly]
file=${BASE}
[SuidCheck]
SuidCheckActive = yes
SuidCheckInterval = 10
SeveritySuidCheck = crit
SuidCheckQuarantineFiles = no
SuidCheckQuarantineMethod = 2
SuidCheckQuarantineDelete = yes
"

mod_suiddata_6 () {
    one_sec_sleep
    chmod 4755 "${BASE}/a/a/y"
}

chk_suiddata_6 () {
    one_sec_sleep
    tmp=`ls -l "${BASE}/a/a/y" 2>/dev/null | awk '{ print $1}'`
    if [ "x$tmp" = "x-rwsr-xr-x" ]; then
	egrep "CRIT.*POLICY \[SuidCheck\].*${BASE}/a/a/y" $LOGFILE >/dev/null 2>&1
	if [ $? -ne 0 ]; then
	    [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y";
	    return 1
	fi
	egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/y" $LOGFILE >/dev/null 2>&1
	if [ $? -ne 0 ]; then
	    [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y";
	    return 1
	fi
	return 0;
    else
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (suid not kept)";
	return 1
    fi
}

SUIDPOLICY_5="
[ReadOnly]
file=${BASE}
[SuidCheck]
SuidCheckActive = yes
SuidCheckInterval = 10
SeveritySuidCheck = crit
SuidCheckQuarantineFiles = yes
SuidCheckQuarantineMethod = 2
SuidCheckQuarantineDelete = yes
"

mod_suiddata_5 () {
    one_sec_sleep
    chmod 4755 "${BASE}/a/a/y"
}

chk_suiddata_5 () {
    one_sec_sleep
    if [ ! -f "${BASE}/a/a/x" ]; then
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/x (erroneously deleted)";
	return 1
    fi
    if [ -f "${BASE}/a/a/y" ]; then
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (not deleted)";
	return 1
    fi
    if [ -f .quarantine/y ]; then
	if [ -f .quarantine/y.info ]; then
	    return 0;
	else
	    [ -z "$verbose" ] || log_msg_fail ".quarantine/y.info (missing)";
	    return 1
	fi
    else
	[ -z "$verbose" ] || log_msg_fail ".quarantine/y (missing)";
	return 1
    fi
}

SUIDPOLICY_4="
[ReadOnly]
file=${BASE}
[SuidCheck]
SuidCheckActive = yes
SuidCheckInterval = 10
SeveritySuidCheck = crit
SuidCheckQuarantineFiles = yes
SuidCheckQuarantineMethod = 2
SuidCheckQuarantineDelete = no
"

mod_suiddata_4 () {
    one_sec_sleep
    chmod 4755 "${BASE}/a/a/y"
}

chk_suiddata_4 () {
    one_sec_sleep
    tmp=`cat "${BASE}/a/a/y" 2>/dev/null | wc -c`
    if [ $tmp -ne 0 ]; then
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (not truncated)";
	return 1
    fi
    if [ -f .quarantine/y ]; then
	if [ -f .quarantine/y.info ]; then
	    return 0;
	else
	    [ -z "$verbose" ] || log_msg_fail ".quarantine/y.info (missing)";
	    return 1
	fi
    else
	[ -z "$verbose" ] || log_msg_fail ".quarantine/y (missing)";
	return 1
    fi
}

SUIDPOLICY_3="
[ReadOnly]
file=${BASE}
[SuidCheck]
SuidCheckActive = yes
SuidCheckInterval = 10
SeveritySuidCheck = crit
SuidCheckQuarantineFiles = yes
SuidCheckQuarantineMethod = 1
SuidCheckQuarantineDelete = no
"

mod_suiddata_3 () {
    one_sec_sleep
    chmod 4755 "${BASE}/a/a/y"
}

chk_suiddata_3 () {
    one_sec_sleep
    tmp=`ls -l "${BASE}/a/a/y" 2>/dev/null | awk '{ print $1}'`
    if [ "x$tmp" = "x-rwxr-xr-x" ]; then
	return 0;
    else
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (suid not removed)";
	return 1
    fi
}

SUIDPOLICY_2="
[ReadOnly]
file=${BASE}
[SuidCheck]
SuidCheckActive = yes
SuidCheckInterval = 10
SeveritySuidCheck = crit
SuidCheckQuarantineFiles = yes
SuidCheckQuarantineMethod = 0
SuidCheckQuarantineDelete = no
"

mod_suiddata_2 () {
    one_sec_sleep
    chmod 4755 "${BASE}/a/a/y"
}

chk_suiddata_2 () {
    one_sec_sleep
    tmp=`cat "${BASE}/a/a/y" 2>/dev/null | wc -c`
    if [ $tmp -ne 0 ]; then
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (not truncated)";
	return 1
    fi
}

SUIDPOLICY_1="
[ReadOnly]
file=${BASE}
[SuidCheck]
SuidCheckActive = yes
SuidCheckInterval = 10
SeveritySuidCheck = crit
SuidCheckQuarantineFiles = yes
SuidCheckQuarantineMethod = 0
SuidCheckQuarantineDelete = yes
"

mod_suiddata_1 () {
    one_sec_sleep
    chmod 4755 "${BASE}/a/a/y"
}

chk_suiddata_1 () {
    one_sec_sleep
    if [ -f "${BASE}/a/a/y" ]; then
	[ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (not removed)";
	return 1
    fi
}

prep_suidpolicy ()
{
    test -f "${RCFILE}" || touch "${RCFILE}"
    eval echo '"$'"SUIDPOLICY_$1"'"' >>"${RCFILE}"
    if [ "x$1" = "x5" ]; then
	chmod 4755 "${BASE}/a/a/x"
    fi
}

testrun_internal_1c ()
{
	[ -z "$verbose" ] || echo Working directory: $PW_DIR
	[ -z "$verbose" ] || { echo MAKE is $MAKE; echo; }

	#
	# test standalone compilation
	#
	[ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }

	if test -r "Makefile"; then
		$MAKE distclean >/dev/null 
	fi

	${TOP_SRCDIR}/configure ${BUILDOPTS} 

	#
	if test x$? = x0; then
		[ -z "$verbose" ] ||     log_msg_ok "configure..."; 
		$MAKE  'DBGDEF=-DSH_SUIDTESTDIR=\"${BASE}\"' >/dev/null 2>&1
		if test x$? = x0; then
		    [ -z "$verbose" ] || log_msg_ok "make..."; 
		else
		    [ -z "$quiet" ] &&   log_msg_fail "make..."; 
		    return 1
		fi

	else
		[ -z "$quiet" ] &&       log_msg_fail "configure...";
		return 1
	fi

	[ -z "$verbose" ] || { echo; echo "${S}Running test suite${E}"; echo; }

	tcount=1
	POLICY=`eval echo '"$'"SUIDPOLICY_$tcount"'"'`

	until [ -z "$POLICY" ]
	do
	  prep_init
	  check_err $? ${tcount}; errval=$?
	  if [ $errval -eq 0 ]; then
	      prep_testdata
	      check_err $? ${tcount}; errval=$?
	  fi
	  if [ $errval -eq 0 ]; then
	      prep_suidpolicy   ${tcount}
	      check_err $? ${tcount}; errval=$?
	  fi
	  if [ $errval -eq 0 ]; then
	      run_init
	      check_err $? ${tcount}; errval=$?
	  fi
	  if [ $errval -eq 0 ]; then
	      eval mod_suiddata_${tcount}
	      check_err $? ${tcount}; errval=$?
	  fi
	  if [ $errval -eq 0 ]; then
	      run_check
	      check_err $? ${tcount}; errval=$?
	  fi
	  if [ $errval -eq 0 ]; then
	      eval chk_suiddata_${tcount}
	      check_err $? ${tcount}; errval=$?
	  fi
	  if [ $testrun1_setup -eq 0 ]; then
	      if [ $errval -eq 0 ]; then
		  run_update
		  check_err $? ${tcount}; errval=$?
	      fi
	      if [ $errval -eq 0 ]; then
		  run_check_after_update
		  check_err $? ${tcount}; errval=$?
	      fi
	  fi
	  #
	  if [ $errval -eq 0 ]; then
	      [ -z "$quiet" ] && log_ok ${tcount} ${MAXTEST};
	  fi
	  let "tcount = tcount + 1" >/dev/null
	  POLICY=`eval echo '"$'"SUIDPOLICY_$tcount"'"'`
	done
	    
	return 0
}

testrun1c ()
{
    log_start "RUN STANDALONE W/SUIDCHK"
    testrun_internal_1c
    log_end "RUN STANDALONE W/SUIDCHK"
    return 0
}

