#!/bin/bash
#Copyright 2001, William Stearns <wstearns@pobox.com>
#Copyleft:
#	detectlib provides the back-end functions for removing worms and viruses.
#	Copyright (C) 2001 William Stearns <wstearns@pobox.com>
#
#	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.
#
#	The author can also be reached at:
#        William Stearns
#email:  wstearns@pobox.com				(preferred)
#web:    http://www.pobox.com/~wstearns
#snail:  544 Winchester Place
#        Colchester VT, 05446, USA

DetectLibVer="022"

False=1		#As far as bash is concerned.
True=0

#Please leave Need_Utils before the rest, please.  This gets called at
#the beginning of each function that needs a system tool.
Need_Utils () {
	for OneUtil in $* ; do
		if ! type -path $OneUtil >/dev/null 2>/dev/null ; then
			echo Missing support tool \"$OneUtil\" in path \"$PATH\"
			echo Exiting.
			exit $False
		fi
	done
}

debug () {
	:
	#echo '++++ (debugging information)' $* >/dev/stderr
}

#-------------------------------------------------------------------------
# askYN function, returns true or false depending on user input.
#-------------------------------------------------------------------------
askYN () {	#SUDO checked
	TESTYN=""
	while [ "$TESTYN" != 'Y' ] && [ "$TESTYN" != 'N' ] ; do
		echo -n '?' >/dev/stderr
		read TESTYN || :
		case $TESTYN in
		T*|t*|Y*|y*)		TESTYN='Y'	;;
		F*|f*|N*|n*)		TESTYN='N'	;;
		esac
	done

	if [ "$TESTYN" = 'Y' ]; then
		return 0 #True
	else
		return 1 #False
	fi
} #End of askYN


#No required utils outside of bash builtins
AttackName () {
#Params: A descriptive name for this worm.
	if [ -n "$*" ]; then
		NameOfAttack="$*"
	else
		debug Null attack name in AttackName.
	fi
}

#No required utils outside of bash builtins
AttackMarker () {
#Params: One or more files or directories whose presence (of any of them, not all of them) 
#essentially guarantees the attack is on the system.
#DO NOT ASSUME ANY EXTERNAL UTILITY CAN BE TRUSTED AT THIS POINT.
	AttackPresent=$False
	if [ -z "$NameOfAttack" ]; then
		debug Null attack name in AttackMarker.
	fi
	for OneFile in $* ; do
		if [ -e $OneFile ]; then
			debug Found $OneFile
			AttackPresent=$True
		fi
	done
	if [ "$AttackPresent" = "$True" ]; then
		echo $NameOfAttack detected.
	else
		echo $NameOfAttack DOES NOT appear to be present on this system, good.
	fi
	return $AttackPresent
}



Need_Utils rm
AttackFiles () {

	OrigList=$*
	FoundFiles=""
	FoundDirs=""
	FoundSpecials=""
	while [ -n "$1" ]; do
		if [ -d "$1" ]; then
			FoundDirs="$FoundDirs $1"
			ObjectsFound=$True
		elif [ -f "$1" ]; then			
			FoundFiles="$FoundFiles $1"
			ObjectsFound=$True
		elif [ -b "$1" ] || [ -c "$1" ] || [ -p "$1" ] || [ -S "$1" ]; then
			FoundSpecials="$FoundSpecials $1"
			ObjectsFound=$True
		else
			MissingFiles="$MissingFiles $1"
		fi
		shift
	done

	if [ "$ObjectsFound" = "$True" ]; then
		echo Do you wish to delete the following files:
		echo $FoundFiles $FoundSpecials
		echo and directories:?
		echo $FoundDirs
		echo If so, enter \"Y\" without the quotes.
		if askYN ; then
			if [ -n "$FoundFiles$FoundSpecials" ]; then
				rm -f $FoundFiles $FoundSpecials
			fi
			if [ -n "$FoundDirs" ]; then
				rm -ri $FoundDirs
			fi
		else
			echo NOT removing the above listed files and directories.
		fi
		return $True
	else
		echo None of the following files and directories were detected:
		echo $OrigList
		return $False
	fi
}

Need_Utils mv
ReplacedFile () {
#Params: Suspect utility name, Where the good copy was moved if replaced.
	if [ -f "$2" ]; then
		echo \"$2\" found, so we assume \"$1\" is a trojan version and
		echo will restore the original version.
		if [ ! -f "$1" ]; then
			debug \"$1\" does not exist in WrappedUtil.
		fi
		echo Would you like to restore $1 from ${2}
		if askYN ; then
			mv -f "$2" "$1"
		else
			echo NOT restoring $1 from $2 .
		fi
	fi
}

NukedFiles () {
#Params: Files which may have been removed from the system or truncated to 0 bytes.
	if [ -n "$*" ]; then
		echo The following files may have been removed from the system or
		echo truncated.  You should inspect them to see if they need to be
		echo restored from backup.
		echo $*
	else
		debug Null filelist in NukedFiles
	fi
}

Need_Utils killall
PathToRunningApps () {
#Params: full path to apps that may be running as part of the attack
	echo Would you like to kill all running processes run from the
	echo following executables?  If so, enter \"Y\" without quotes.
	echo $*
	if askYN ; then
		for OneApp in $* ; do
			killall -9 $OneApp
			killall -9 ${OneApp##*/}
		done
	else
		echo NOT removing the above listed applications.
	fi
}



Need_Utils cat $SUDO grep mktemp dd rm || exit 1	#printf wc
AddedLine () {
#Params: file which may have had a line added, line that was added (or at least enough of a regexp to match).
	if [ "$#" != "2" ]; then
		echo Incorrect number of arguments to AddedLine! >/dev/stderr
	else
		#case "$1" in
		#/*)
		#    echo Filename is not relative in AddedLine! >/dev/stderr
		#    ;;
		#*)
		if [ ! -f "$1" ]; then
			echo "$1" doesn\'t exist, can\'t remove \"$2\". >/dev/stderr
#FIXME - does this allow a partial line?
		elif $SUDO cat "$1" | grep -q "$2" ; then
			OLDUMASK=`umask`
			umask 177
			TMPFILE=`mktemp -q /tmp/delline.XXXXXX`
			if [ $? -ne 0 ]; then
				echo "$0: Can't create temp file, exiting..."
				exit 1
			fi
			$SUDO cat "$1" >"$TMPFILE"
			cat "$TMPFILE" | grep -v "$2" | $SUDO dd of="$1" 2>/dev/null
			#printf "%1s%-2s%-40s%-50s\n" '-' "$[ `$SUDO cat "$TMPFILE" | wc -l` - `$SUDO cat "$1" | wc -l` ]" "$1" "$2"
			echo "Removing \"$2\" from $1"
			#Was: echo -n "Removing \"$2\" from $1; " ; echo $[ `$SUDO cat "$TMPFILE" | wc -l` - `$SUDO cat "$1" | wc -l` ] lines removed.
			$SUDO rm -f "$TMPFILE"
			umask $OLDUMASK
		else
			echo \"$2\" is not in "$1" - not removing. >/dev/stderr
		fi
		#    ;;
		#esac
	fi
}

ServicesStopped () {
#Params: names of SysVinit scripts that may need to be restarted.
	for OneService in $* ; do
		echo Would you like to stop and start service \"$OneService\"?
		echo If so, enter \"Y\" without quotes.
		if askYN ; then
			if [ -f /etc/rc.d/init.d/$OneService ]; then
				/etc/rc.d/init.d/$OneService stop
				/etc/rc.d/init.d/$OneService start
			elif [ -f /etc/init.d/$OneService ]; then
				/etc/init.d/$OneService stop
				/etc/init.d/$OneService start
			else
				echo Can\'t find the script that stops and starts the service.
				echo Please restart it by hand.
			fi
		else
			echo NOT restarting the above listed service.
		fi
	done
}

SuspectUtils=""
PackagesMangled () {
#Params: pairs of files overwritten, the name(s) of package(s) that should not be trusted anymore
#FIXME - both this and Need_Utils need to compare to each other at each invocation;
#overlap should cause very loud warnings!
	echo The following packages \(rpms, debs, tars, etc.\) may have been
	echo modified beyond my ability to fix them.  If any of the following
	echo are installed on your system, please pull down fresh copies from
	echo a trusted source.  Please check for packages that have been
	echo updated since your distribution was released and get those if they
	echo exist.
	echo -e "Modified File\tPossible Package Name"
	while [ -n "$1" ]; do
		echo -e "$1\t$2"
		if [ -z "$2" ]; then
			debug One parameter short in PackagesMangled after \"$1\"
			shift 1
		else
			shift 2
		fi
	done
}

#Need_Utils mkdir
#Last function, please
InitDetectLib () {
	if [ ! "$DetectLibInitialized" = "$True" ]; then

		#set PATH=/knowngood

		DetectLibInitialized=$True
	fi
}


