#!/usr/bin/ksh
#
# Tivoli plugin script to verify that BoKS security is enabled on a client
#
# Written by Thomas Sluyter (nagiosATkilalaDOTnl)
# By request of Unixerius, the Netherlands
# Last Modified: 10-01-2010
#
# Description:
#   The check_boks_client script checks many different things on a per-client
# basis. That particular script needs to run locally on the client itself.
# This script, check_boks_ssmactive, is meant to do one quick check on a
# clients, from the master server. The only thing it checks is whether BoKS
# security is actually active on the client, which is rather important!
#   By running this script from the master server you can blanket your whole
# domain in one blow.
#
# Usage: 
# ./check_boks_ssmactive [[-h HOST] [-H HG] [-i FILE] | -A] [-x HOST] [-X HG]  [-d -o FILE] [-f FILE]
#
# -h HOST	Verify BoKS security for HOST. Multiple -h entries allowed.
# -H HGROUP	Verify BoKS security for HOSTGROUP. Multiple -H entries allowed.
# -i FILE	Verify BoKS security for all hosts in FILE.
# -A 		Verify BoKS security for ALL hosts.
# -x EXCLUDE	Hosts to exclude (when using -H or -A). Multiple -x entries allowed.
# -X EXCLUDEHG	Host groups to exclude (when using -A). Multiple -X entries allowed.
# -f FILE	Log file that lists hosts with disabled BoKS. Default logs into $BOKS_var.
# -d 		Debug mode. Provides error logging. 
# -o FILE	Output file for debugging logs. Required when -d is passed.
#
# Example: 
# ./check_boks_ssmactive -h HOST1 -h HOST2 -f $BOKS_var/BOKSdisabled.txt
# ./check_boks_ssmactive -A -d -o /tmp/foobar
#
# Limitations:
# * This script must be run on a BoKS master.
# * This script must be run as root from the BoKS shell.
# * This script was tested with BoKS 6.0.x and 6.5.x.
# * If the script malfunctions, you may want to verify the platform specific
#   variables under "SETTING THINGS UP". 
#
# Output:
# This script is meant to be called as a Tivoli numeric script.
# Hence both the output and the exit code are a single digit. Please
# configure your numeric script calls accordingly:
#
# 0     OK			Everything OK. Or host unreachable.
# 1 	WARNING		Problem with script parameters or input. 
# 2     SEVERE		One or more hosts are NOT secure. Refer to log file.
# 3		CRITICAL	Not used.
#
# The list of actual failed hosts can be found in the output file.
#
# Other notes:
# *  Use the debugging option to find out the cause of your problems if this
#    script ever misbehaves.
#


### SETTING THINGS UP ###

PROGNAME=$(basename $0)
PATH="/usr/bin:/usr/sbin:/bin:/sbin:$PATH"

TEMPDIR="/tmp/$PROGNAME.$(date +%Y%m%d)"; mkdir $TEMPDIR >/dev/null 2>&1; rm $TEMPDIR/* >/dev/null 2>&1; chmod 600 $TEMPDIR
HOSTLIST="$TEMPDIR/hostlist"
EXCLUDELIST="$TEMPDIR/excludelist"

HOSTNAMES="" 		# Default if -h parameter is not passed.
HOSTGROUPS=""		# Default if -H parameter is not passed.
HOSTFILE=""		# Default if -i parameter is not passed.
ALL="0"			# Default if -A parameter is not passed.
EXCLUDES=""             # Default if -x parameter is not passed.
EXCLUDEHGS=""           # Default if -X parameter is not passed.
DEBUG="0"		# Default if -d parameter is not passed.
DEBUGFILE=""		# Default if -o parameter is not passed.
LOGFILE="$BOKS_var/$PROGNAME.$(date +%Y%m%d)"	# Default if -f is not passed.

STATE_OK="0"            # Exit code when everything's OK
STATE_WA="1"            # Exit code when there might be a problem
STATE_SE="2"            # Exit code when there's a problem
STATE_CR="3"            # Exit code when there's a problem


# Setting up platform specific options

case $(uname) in
	AIX)    BOKSSBIN="/opt/boksm/sbin";
		BOKSBIN="/opt/boksm/bin";
		BOKSLIB="/opt/boksm/lib";
		BOKSTMP="/var/opt/boksm/tmp";
		BOKSETC="/etc/opt/boksm";
		AWK="/usr/bin/awk";
		GREP="/usr/bin/grep";
		PING="/bin/ping -c 1";
		PINGPARAM="";;
	Linux) BOKSSBIN="/opt/boksm/sbin";
		BOKSBIN="/opt/boksm/bin";
		BOKSLIB="/opt/boksm/lib";
		BOKSTMP="/var/opt/boksm/tmp";
		BOKSETC="/etc/opt/boksm";
		AWK="/bin/awk";
		GREP="/bin/grep";
		PING="/bin/ping -c 1";
		PINGPARAM="";;
	SunOS)  BOKSSBIN="/opt/boksm/sbin";
		BOKSBIN="/opt/boksm/bin";
		BOKSLIB="/opt/boksm/lib";
		BOKSETC="/etc/opt/boksm";
		BOKSTMP="/var/opt/boksm/tmp";
		AWK="/usr/xpg4/bin/awk";
		GREP="/usr/xpg4/bin/grep";
		PING="/usr/sbin/ping";
		PINGPARAM="1";;
	*)      echo "\nERROR: OS is not supported."; exit 1 ;;
esac


# Quick check to see if you're running as root with the BoKS shell

if [[ ( -z $BOKS_etc ) || ( -z $(id | $GREP "uid=0") ) ]]
then
        echo "ERROR: Script must be run as root, from the BoKS shell.\n"
        exit 1
fi


### REQUISITE COMMAND LINE STUFF ###

print_usage() {
	echo "\nUsage:"
	echo "$PROGNAME [[-h HOST] [-H HG] [-i FILE] | -A] [-x HOST] [-X HG] [-d -o FILE] [-f FILE]"
	echo "\n-h HOST\t\tVerify BoKS security for HOST. Multiple -h entries allowed."
	echo "-H HGROUP\tVerify BoKS security for HOSTGROUP. Multiple -H entries allowed."
	echo "-i FILE\t\tVerify BoKS security for all hosts in FILE."
	echo "-A\t\tVerify BoKS security for ALL hosts."
	echo "-x EXCLUDE\tHosts to exclude (when using -H or -A). Multiple -x entries allowed."
	echo "-X EXCLUDEHG\tHostgroups to exclude (when using -A). Multiple -X entries allowed."
	echo "-f FILE\t\tLog file that lists errors in root password files. Default logs into $BOKS_var."
	echo "-d\t\tDebug mode. Provides error logging."
	echo "-o FILE\t\tOutput file for debugging logs. Required when -d is passed."
	echo "\nExamples:"
	echo "$PROGNAME -h HOST1 -h HOST2 -f $BOKS_var/BOKSdisabled.txt"
	echo "$PROGNAME -A -d -o /tmp/foobar -f $BOKS_var/BOKSdisabled.txt\n\n"
	exit 1
}


[[ $# -eq 0 ]] && print_usage

while [[ $# -gt 0 ]]
do
    case "$1" in
	-h) if [[ (-z $(echo $2 | $GREP ^-)) && (! -z $2) ]]
	    then
		HOSTNAMES="$HOSTNAMES $2"; shift
	    else
		echo "\nERROR: Hostname incorrectly specified. Use -h.\n\n"
		print_usage
	    fi;;
	-H) if [[ (-z $(echo $2 | $GREP ^-)) && (! -z $2) ]]
	    then
		HOSTGROUPS="$HOSTGROUPS $2"; shift
	    else
		echo "\nERROR: Hostgroup incorrectly specified. Use -H.\n\n"
		print_usage
	    fi;;
	-i) if [[ (-z $(echo $2 | $GREP ^-)) && (! -z $2) ]]
	    then
		if [[ -f $2 ]]
		then
		    HOSTFILE="$2"; shift
		else
		    echo "\nERROR: Input file does not exist. Use -i.\n\n"
		    print_usage
		fi
	    else
		echo "\nERROR: Input file incorrectly specified. Use -i.\n\n"
		print_usage
	    fi;;
	-A) ALL="1";;
	-x) if [[ (-z $(echo $2 | $GREP ^-)) && (! -z $2) ]]
	    then
		EXCLUDES="$EXCLUDES $2"; shift
	    else
		echo "\nERROR: Hostname to exclude incorrectly specified. Use -x.\n\n"
		print_usage
	    fi;;
	-X) if [[ (-z $(echo $2 | $GREP ^-)) && (! -z $2) ]]
	    then
		EXCLUDEHGS="$EXCLUDEHGS $2"; shift
	    else
		echo "\nERROR: Hostgroup to exclude incorrectly specified. Use -X.\n\n"
		print_usage
	    fi;;
	-f) if [[ (-z $(echo $2 | $GREP ^-)) && (! -z $2) ]]
	    then
		if [[ -d $(dirname $2) ]]
		then
		    LOGFILE="$2"
		    echo > $LOGFILE; chown root:root $LOGFILE; chmod 0644 $LOGFILE
		    shift
		else
		    echo "\nERROR: Output directory for log file does not exist. Use -f.\n\n"
		    print_usage
		fi
	    else
		echo "\nERROR: Log file not specified. Use -f.\n\n"
		print_usage
	    fi;;
	-d) DEBUG="1";;
	-o) if [[ (-z $(echo $2 | $GREP ^-)) && (! -z $2) ]]
	    then
		if [[ -d $(dirname $2) ]]
		then
		    DEBUGFILE="$2"
		    echo > $DEBUGFILE; chown root:root $DEBUGFILE; chmod 0600 $DEBUGFILE
		    shift
		else
		    echo "\nERROR: Output directory for debug log does not exist. Use -o.\n\n"
		    print_usage
		fi
	    else
		echo "\nERROR: Debug log output file not specified. Use -o.\n\n"
		print_usage
	    fi;;
	-*) print_usage;;
	*)  print_usage;;	
    esac
    shift
done


# Some final checks and initialisation

if [[ $DEBUG -gt 0 ]]
then
	echo "=== SETUP ===" >> $DEBUGFILE
	echo "OS name is $(uname)" >> $DEBUGFILE
	echo "BOKSSBIN is $BOKSSBIN" >> $DEBUGFILE
	echo "BOKSBIN is $BOKSBIN" >> $DEBUGFILE
	echo "BOKSLIB is $BOKSLIB" >> $DEBUGFILE
	echo "BOKSETC is $BOKSETC \n" >> $DEBUGFILE
	echo "Parameters passed to script are:" >> $DEBUGFILE
	echo "HOSTNAMES = $HOSTNAMES" >> $DEBUGFILE
	echo "HOSTGROUPS = $HOSTGROUPS" >> $DEBUGFILE
	echo "HOSTFILE = $HOSTFILE" >> $DEBUGFILE
	echo "ALL = $ALL" >> $DEBUGFILE
	echo "EXCLUDES = $EXCLUDES" >> $DEBUGFILE
	echo "EXCLUDEHGS = $EXCLUDEHGS" >> $DEBUGFILE
	echo "DEBUG = $DEBUG" >> $DEBUGFILE
	echo "DEBUGFILE = $DEBUGFILE \n" >> $DEBUGFILE
	echo "LOGFILE = $LOGFILE \n" >> $DEBUGFILE
fi



### DEFINING SUBROUTINES ###


function ExitScript
{
        EXIT="$1"

        rm -rf $TEMPDIR
        echo $EXIT
        exit $EXIT
}


GenerateHostList()
{
	[[ $DEBUG -gt 0 ]] && echo "\n=== STARTING GenerateHostList ===\n" >> $DEBUGFILE

	rm $HOSTLIST 2>/dev/null; touch $HOSTLIST
	if [[ ! -f $HOSTLIST ]] 
	then
	    echo "ERROR: Failed to create list of hosts in $TEMPDIR."
	    ExitScript $STATE_WA
	fi
	
	if [[ $ALL -gt 0 ]] 
	then
            [[ $DEBUG -gt 0 ]] && echo "Parameter -A passed. Adding all hosts to hostlist." >> $DEBUGFILE
	    $BOKSSBIN/lsbks -l *:root | $GREP -v ^: | $GREP -v ^-| $AWK -F: '{print $1}' > $HOSTLIST 2>/dev/null
	else
	    if [[ $HOSTNAMES != "" ]]
	    then
        	[[ $DEBUG -gt 0 ]] && echo "Hostnames passed with -h parameter. Adding to hostlist." >> $DEBUGFILE
		for HOST in $(echo $HOSTNAMES); do echo $HOST >> $HOSTLIST; done
	    fi
	
	    if [[ $HOSTGROUPS != "" ]]
	    then
        	[[ $DEBUG -gt 0 ]] && echo "Hostgroups passed with -H parameter. Resolving and adding to hostlist." >> $DEBUGFILE
		for HG in $(echo $HOSTGROUPS); do hgrpadm -l -g $HG | $AWK '{print $2}' | $GREP -v ^- >> $HOSTLIST; done
	    fi
	
	    if [[ $HOSTFILE != "" ]]
	    then
        	[[ $DEBUG -gt 0 ]] && echo "List of hosts passed with -i parameter. Adding to hostlist." >> $DEBUGFILE
		cat $HOSTFILE | $GREP -v ^- >> $HOSTLIST
	    fi
	fi

	cat $HOSTLIST | sort -u > $HOSTLIST.temp; mv $HOSTLIST.temp $HOSTLIST
	NUMHOSTS=$(wc -l $HOSTLIST | $AWK '{print $1}')

	[[ $DEBUG -gt 0 ]] && echo "Host list is $NUMHOSTS lines." >> $DEBUGFILE
}


GenerateExcludeList()
{
	[[ $DEBUG -gt 0 ]] && echo "\n=== STARTING GenerateExcludeList ===\n" >> $DEBUGFILE

	rm $EXCLUDELIST 2>/dev/null; touch $EXCLUDELIST
	if [[ ! -f $EXCLUDELIST ]] 
	then
	    echo "ERROR: Failed to create exclude list in $TEMPDIR."
	    ExitScript $STATE_WA
	fi
	
	if [[ $EXCLUDES != "" ]]
	then
            [[ $DEBUG -gt 0 ]] && echo "Hostnames passed with -x parameter. Adding to exclude list." >> $DEBUGFILE
	    for HOST in $(echo $EXCLUDES); do echo $HOST >> $EXCLUDELIST; done
	fi
	
	if [[ $EXCLUDEHGS != "" ]]
	then
            [[ $DEBUG -gt 0 ]] && echo "Hostgroups passed with -X parameter. Resolving and adding to exclude list." >> $DEBUGFILE
	    for HG in $(echo $EXCLUDEHGS); do hgrpadm -l -g $HG | $AWK '{print $2}' | $GREP -v ^- >> $EXCLUDELIST; done
	fi

	cat $EXCLUDELIST | sort -u > $EXCLUDELIST.temp; mv $EXCLUDELIST.temp $EXCLUDELIST
	NUMEXCLUDE=$(wc -l $EXCLUDELIST | $AWK '{print $1}')

	[[ $DEBUG -gt 0 ]] && echo "Exclude list is $NUMEXCLUDE lines." >> $DEBUGFILE
}


TestConnection()
{
	[[ $DEBUG -gt 0 ]] && echo "\n=== STARTING TestConnection ===\n" >> $DEBUGFILE

	if [[ -z $($BOKSSBIN/hostadm -l -h $HOST | $GREP UNIXBOKSHOST) ]]
	then
		echo "$HOST\SKIPPING\tHost is not a BoKS client." >> $LOGFILE
		[[ $DEBUG -gt 0 ]] && echo "SKIPPING: $HOST is not a BoKS client." >> $DEBUGFILE
		return 1
	fi

	IP=$($BOKSSBIN/hostadm -l -h $HOST | $GREP ^IP-address | $AWK '{print $2}')
        $PING $IP $PINGPARAM >/dev/null 2>&1
        PINGSTATUS=$?

        $BOKSLIB/cadm -l -f bcastaddr -h $HOST >/dev/null 2>&1
        CADMSTATUS=$?

        if [[ ($PINGSTATUS -gt 0) && ($CADMSTATUS -gt 0) ]]
	then
	    echo "$HOST\tWARNING\tHost is not reachable." >> $LOGFILE
	    [[ $DEBUG -gt 0 ]] && echo "WARNING: Host $HOST is unreachable." >> $DEBUGFILE
	    return 1
	fi

	return 0
}


TestSecurity()
{
	[[ $DEBUG -gt 0 ]] && echo "\n=== STARTING TestConnection ===\n" >> $DEBUGFILE

	if [[ $($BOKSLIB/cadm -l -f ENV -h $HOST 2>/dev/null | grep "SSM_ACTIVE=true" | wc -l) -gt 0 ]]
	then
		[[ $DEBUG -gt 0 ]] && echo "OK: BoKS security on $HOST is ACTIVE." >> $DEBUGFILE

		echo "$HOST\tOK\tBoKS is active" >> $LOGFILE	
	else
		[[ $DEBUG -gt 0 ]] && echo "ERROR: BoKS security on $HOST is DISABLED" >> $DEBUGFILE

		echo "$HOST\tERROR\tBoKS is disabled" >> $LOGFILE	
		let FAIL=$FAIL+1
	fi

	# Ensuring that we don't flood the BoKS domain with cadm requests.
	sleep 1
}



### FINALLY, THE MAIN ROUTINE ###

[[ $DEBUG -gt 0 ]] && echo "\n=== STARTING MAIN PHASE ===\n $(date) \n" >> $DEBUGFILE

GenerateHostList
GenerateExcludeList

[[ -z $(wc -l $HOSTLIST) ]] && ExitScript $STATE_WA

COUNT="0"; FAIL="0"

for HOST in $(cat $HOSTLIST)
do
	[[ $DEBUG -gt 0 ]] && echo "\n=== STARTING FOR HOST $HOST ===\n" >> $DEBUGFILE

        if [[ (! -z $($GREP -x $HOST $EXCLUDELIST)) || (-z $(lsbks -l $HOST:root)) ]]
	then
		echo "$HOST\tEXCLUDED\tHost excluded by choice." >> $LOGFILE
		[[ $DEBUG -gt 0 ]] && echo "INFO: Host $HOST is on exclude list." >> $DEBUGFILE
		continue
	fi

	TestConnection

	if [[ $? -gt 0 ]]; then continue; fi

	TestSecurity

	let COUNT=$COUNT+1
done


if [[ $DEBUG -gt 0 ]] 
then
	echo "\n\n=== SCRIPT FINISHED ===\n\n" >> $DEBUGFILE
	echo "Ran for $COUNT BoKS clients ($NUMHOSTS total, $NUMEXCLUDE excluded, $FAIL failed).\n" >> $DEBUGFILE
	date >> $DEBUGFILE
fi

echo "\nRan for $COUNT BoKS clients ($NUMHOSTS total, $NUMEXCLUDE excluded, $FAIL failed).\n" >> $LOGFILE

if [[ $FAIL -gt 0 ]]
then
	ExitScript $STATE_SE	
else
	ExitScript $STATE_OK
fi
