#!/bin/ksh
#
# Script to create clean BoKS dump for projects and audits.
#
# Written by Thomas Sluyter (nagiosATkilalaDOTnl)
# By request of Unixerius, the Netherlands
# Last Modified: 11-09-2009
#
# Description:
#   From time to time one will need a BoKS database dump that includes
# all the tables, but is limited to one or two specific applications.
# For example, one could be migrating an application or hostgroup to 
# another BoKS domain. Or one might be performing a security audit on
# a specific group of servers.
#   This script will make a dump of all BoKS information relevant to 
# a set of specified servers or host groups. It will strip the password
# information for all accounts (for obvious security reasons).
#
# Usage:
# ./SafeDump.ksh [-g HOSTGROUP] [-h HOST | -f FILE] [-p] -d DIRECTORY
# -g HOSTGROUP	Hostgroup to dump the BoKS information for. Multiple allowed.
# -h HOST	Host to dump the BoKS information for. Multiple allowed.
# -f FILE	List of hostnames to dump the BoKS information for. 
# -p		Disable hiding of account passwords for non-root accounts.
# -d DIRECTORY  Location to store the output files.
#
# Examples:
# $PROGNAME -f /tmp/hostlist -d /tmp/BOKSdump
# $PROGNAME -g HG_APP1 -g HG_APP3 -d /tmp/BOKSdump
# $PROGNAME -g HG_APP1 -h HOST1 -h HOST5 -d /tmp/BOKSdump
#
# Limitations:
# * This script must be run as root, from the BoKS shell.
# * The database dump will NEVER contain root passwords due to security
#   reasons. These will be replaced with a dummy value.
# * By default the script will NOT contain the passwords to non-root 
#   accounts for security reasons. This behaviour can be turned off with
#   the -p flag.
#
# Input:
# * By using a combination of the -f, -h and -g flags one can provide a
#   list of servers to be included in the database dump.
#
# Output:
# * The script creates a new directory (-d flag) that contains files called
#   "tableN". Each file relates to a real BoKS database table. 
# * During runtime the script will create a temporary directory containing
#   actual BoKS database dumps. This directory will be removed once the 
#   script has completed.
#
# Other notes:
# None.
#
#


### SETTING THINGS UP ###

PROGNAME=$(basename $0)
PATH="/usr/bin:/usr/sbin:/bin:/sbin:$PATH"
TEMPDIR="/tmp/$PROGNAME.temp"; rm -rf $TEMPDIR >/dev/null 2>&1; mkdir $TEMPDIR
TABLES="1 2 6 7 9 15 16 17 31 47 48 49"	# Relevant table numbers.

HOSTLIST="$TEMPDIR/hostlist"		# Tempfile containing list of all relevant hosts.
HLTEMP="$TEMPDIR/hostlist.temp"		# Tempfile for building the tempfile. Yeah... I know...
HOSTGROUPS=""				# Default if -g parameter is not passed.
HOSTFILE=""				# Default if -f parameter is not passed.
HOSTS=""				# Default if -h parameter is not passwd
SHOWPASS="0"				# Default if -p parameter is not passed.
OUTPDIR="/tmp/$PROGNAME.$(date +%Y%m%d)"	# Default if -d parameter is not passed.



# Setting up platform specific options

case $(uname) in
    AIX)   BOKSSBIN="/opt/boksm/sbin";
           BOKSBIN="/opt/boksm/bin";
           BOKSLIB="/opt/boksm/lib";
           BOKSCFG="/etc/opt/boksm";
	   AWK="/usr/bin/awk";;
    Linux) BOKSSBIN="/opt/boksm/sbin";
           BOKSBIN="/opt/boksm/bin";
           BOKSLIB="/opt/boksm/lib";
           BOKSCFG="/etc/opt/boksm";
	   AWK="/bin/awk";;
    SunOS) BOKSSBIN="/opt/boksm/sbin";
           BOKSBIN="/opt/boksm/bin";
           BOKSLIB="/opt/boksm/lib";
           BOKSCFG="/etc/opt/boksm";
	   AWK="/usr/xpg4/bin/awk";;
    *)     [[ $DEBUG -gt 0 ]] && echo "OS not supported." >> $DEBUGFILE;
           echo "\nERROR: OS not supported."; exit 1 ;;
esac


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

if [[ ( -z $(echo $BOKS_etc) ) || ( -z $(id | $AWK '{print $1}' | grep root) ) ]]
then
        echo "ERROR: Script must be run using the BoKS shell.\n"
        exit 1
fi


### REQUISITE COMMAND LINE STUFF ###

print_usage() {
	echo "\nUsage: $PROGNAME [-g HOSTGROUP] [-h HOST] [-f FILE] [-p] -d DIRECTORY"
	echo "-g HOSTGROUP\tHostgroup to dump the BoKS information for. Multiple allowed."
	echo "-h HOST\t\tHost to dump the BoKS information for. Multiple allowed."
	echo "-f FILE\t\tList of hostnames to dump the BoKS information for."
	echo "-p\t\tDisable hiding of account passwords for non-root accounts."
	echo "-d DIRECTORY\tLocation to store the output files."
	echo "\nExamples:"
	echo "$PROGNAME -f /tmp/hostlist -d /tmp/BOKSdump"
	echo "$PROGNAME -g HG_APP1 -g HG_APP3 -d /tmp/BOKSdump"
	echo "$PROGNAME -g HG_APP1 -h HOST1 -h HOST5 -d /tmp/BOKSdump"
        echo "\nThis script must be run as root...\n"
        exit 1
}


# The following construct is inspired by http://www.shelldorado.com/goodcoding/cmdargs.html

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

while [[ $# -gt 0 ]]
do
    case "$1" in
        -g) if [[ (-z $(echo $2 | grep ^-)) && ($(echo $2) != "") ]]
            then
                HOSTGROUPS="$HOSTGROUPS $2"; shift
            else
                echo "\nERROR: Hostgroup not specified correctly. Use -g.\n\n"
                print_usage
            fi;;
        -h) if [[ (-z $(echo $2 | grep ^-)) && ($(echo $2) != "") ]]
            then
                HOSTS="$HOSTS $2"; shift
            else
                echo "\nERROR: Hostnames not specified correctly. Use -h.\n\n"
                print_usage
            fi;;
        -f) if [[ (-z $(echo $2 | grep ^-)) && ($(echo $2) != "") ]]
            then
                HOSTFILE="$2"; shift
                if [[ ! -f $HOSTFILE ]]
                then
                    echo "\nERROR: Input file does not exist.\n\n"
                    exit 1
                fi
            else
                echo "\nERROR: Input file not specified. Use -f.\n\n"
                print_usage
            fi;;
        -d) if [[ (-z $(echo $2 | grep ^-)) && ($(echo $2) != "") ]]
            then
                OUTPDIR="$2"; shift
            fi;;
	-p) SHOWPASS="1"; echo "\nWARNING: SHOWING USER PASSWORDS IN DUMPS!\n";;
        -*) print_usage;;
        *)  print_usage;;
    esac
    shift
done


mkdir $OUTPDIR > /dev/null 2>&1; rm $OUTPDIR/* >/dev/null 2>&1
echo "\nINFO: Storing output in $OUTPDIR.\n"

if [[ ! -d $TEMPDIR ]]
then
	echo "ERROR: Temporary directory $TEMPDIR not created."
	exit 1
fi

if [[ ! -d $OUTPDIR ]]
then
	echo "ERROR: Output directory $OUTPDIR not created."
	exit 1
fi


### DEFINING SUBROUTINES ###

DumpAllTables()
{
	echo "Dumping all relevant tables into tempdir."
	for NUM in $TABLES
	do
	    dumpbase -t$NUM > $TEMPDIR/table$NUM
	done
	echo ""
}

ParseHostList()
{
	echo "Expanding input into list of hosts."
	echo > $HLTEMP

	[[ ! -z $HOSTFILE ]] && cat $HOSTFILE >> $HLTEMP

	if [ ! -z $HOSTGROUPS ]
        then
		for HG in $(echo $HOSTGROUPS)
		do
			hgrpadm -l -g $HG | $AWK '{print $2}' | grep -v ^- >> $HLTEMP
		done
	fi

	if [ ! -z $HOSTS ]
        then
		for HOST in $(echo $HOSTS)
		do
			echo $HOST >> $HLTEMP
		done
	fi

	cat $HLTEMP | sort -u > $HOSTLIST
}

CheckHostList()
{
	echo "Checking hosts from provided hostlist."
	for HOST in $(cat $HOSTLIST)
	do
	    [[ -z $(grep $HOST $TEMPDIR/table6) ]] && echo "WARNING: $HOST not in BoKS."
	done
	echo ""
}

GetHosts()
{
	echo "Building tables 6 and 15."
	head -2 $TEMPDIR/table6 > $OUTPDIR/table6
	head -2 $TEMPDIR/table15 > $OUTPDIR/table15

	for HOST in $(cat $HOSTLIST)
	do
	    grep $HOST $TEMPDIR/table6 >> $OUTPDIR/table6
	    grep $HOST $TEMPDIR/table15 >> $OUTPDIR/table15
	done
}

GetHostgroups()
{
	echo "Building tables 7 and 9."
	head -2 $TEMPDIR/table7 > $OUTPDIR/table7
	head -2 $TEMPDIR/table9 > $OUTPDIR/table9

	for HOST in $(cat $HOSTLIST)
	do
	    grep $HOST $TEMPDIR/table7 >> $OUTPDIR/table7
	    grep $HOST $TEMPDIR/table9 >> $OUTPDIR/table9
	done

	grep ^RGROUP $OUTPDIR/table7 | $AWK -F\" '{print $2}' > $TEMPDIR/hostgroups.a
	grep ^RHOST $OUTPDIR/table9 | $AWK -F\" '{print $4}' >> $TEMPDIR/hostgroups.a
	cat $TEMPDIR/hostgroups.a | sort -u > $TEMPDIR/hostgroups
}

GetAccounts()
{
	echo "Building table 1."
	head -2 $TEMPDIR/table1 > $OUTPDIR/table1

	for HGROUP in $(cat $TEMPDIR/hostgroups)
	do
	    if [[ $SHOWPASS -eq 1 ]]
	    then
		grep $HGROUP $TEMPDIR/table1 >> $OUTPDIR/table1
	    else
		grep $HGROUP $TEMPDIR/table1 | sed -e 's/PSW="[^"]*"/PSW="2bnrYkJlosbZk"/' >> $OUTPDIR/table1
	    fi
	done

	for HOST in $(cat $HOSTLIST)
	do
	    grep $HOST $TEMPDIR/table1 | grep -v root >> $TEMPDIR/localaccounts
	    grep $HOST $TEMPDIR/table1 | grep root >> $TEMPDIR/rootaccounts
	done

	if [[ $SHOWPASS -eq 1 ]]
	then
	    cat $TEMPDIR/localaccounts >> $OUTPDIR/table1
	else
	    cat $TEMPDIR/localaccounts | sed -e 's/PSW="[^"]*"/PSW="2bnrYkJlosbZk"/' >> $OUTPDIR/table1
	fi

	sed -e 's/PSW="[^"]*"/PSW="2bnrYkJlosbZk"/' $TEMPDIR/rootaccounts >> $OUTPDIR/table1

	grep ^RLOGNAME $OUTPDIR/table1 | $AWK -F\" '{print $2}' | sort -u > $TEMPDIR/users
}

GetUserclasses()
{
        echo "Building tables 17 and 49."
        head -2 $TEMPDIR/table49 > $OUTPDIR/table49

        for USER in $(cat $TEMPDIR/users)
        do
            grep $USER $TEMPDIR/table49 >> $OUTPDIR/table49
        done

        grep ^RLOGNAME $OUTPDIR/table1 | $AWK -F\" '{print $8}' >> $TEMPDIR/userclasses.a
        grep ^RUSER $OUTPDIR/table49 | $AWK -F\" '{print $4}' > $TEMPDIR/userclasses.a
        cat $TEMPDIR/userclasses.a | sort -u > $TEMPDIR/userclasses

        for USERCLASS in $(cat $TEMPDIR/userclasses)
        do
            grep $USERCLASS $TEMPDIR/table17 >> $OUTPDIR/table17
        done
}

GetAccessRoutes()
{
        echo "Building tables 2, 16 and 31."
        head -2 $TEMPDIR/table2 > $OUTPDIR/table2
        head -2 $TEMPDIR/table16 > $OUTPDIR/table16

        for USER in $(cat $TEMPDIR/users)
        do
            grep $USER $TEMPDIR/table2 >> $OUTPDIR/table2
            grep $USER $TEMPDIR/table31 >> $OUTPDIR/table31
        done

        for USERCLASS in $(cat $TEMPDIR/userclasses)
        do
            grep $USERCLASS $TEMPDIR/table16 >> $OUTPDIR/table16
        done
}

GetGroups()
{
	echo "Building tables 47 and 48."
	head -2 $TEMPDIR/table47 > $OUTPDIR/table47
	head -2 $TEMPDIR/table48 > $OUTPDIR/table48

	for USER in $(cat $TEMPDIR/users)
	do
	    grep $USER $TEMPDIR/table48 >> $OUTPDIR/table48
	done

	grep ^RLOGNAME $OUTPDIR/table1 | $AWK -F\" '{print $6}' > $TEMPDIR/groupids.a
	grep ^RUSER $OUTPDIR/table48 | $AWK -F\" '{print $4}' >> $TEMPDIR/groupids.a
	cat $TEMPDIR/groupids.a | sort -u > $TEMPDIR/groupids

	for GID in $(cat $TEMPDIR/groupids)
	do
	    grep ^RNAME $TEMPDIR/table47 | grep $GID >> $OUTPDIR/table47
	done
}


### FINALLY, THE MAIN ROUTINE ###

DumpAllTables

ParseHostList
CheckHostList

GetHosts
GetHostgroups
GetAccounts
GetUserclasses
GetAccessRoutes
GetGroups



### CLEANUP ###

echo "Cleaning temporary files."
rm -rf $TEMPDIR

echo "Done. Output stored in $OUTPDIR."



