#!/usr/bin/perl
$|=1 ;

$here = `pwd` ; chomp($here) ; $here =~ s%.*/%% ;

$ENV{'PATH'} = "/bin:/usr/bin:/sbin:/usr/sbin/:/usr/local/sbin:/usr/local/bin" ;


$MAXF= 20 ;
$SIZES= 3000 ;
$SIZEF= 2000 ;

@progs = ('ps','ls','netstat','login','inetd','du','find') ;
#@libs = ('libcrypt.so.1','libpam.so.0','libpam_misc.so.0') ;

dbmopen(%cache,'.config',0644) ;
if ($cache{'present'}) {
  print "Cached values found in .config[.db]\n" ;
}
$cache{'present'} = 1 ;

print "Choose name for rkdet (recommend renaming)\n" ;
$rkdet = 'rkdet' ;
if ($cache{'rkdet'}) { $rkdet = $cache{'rkdet'} ; }
print "$rkdet  " ;
$a = (<STDIN>) ;  chomp($a) ;
if ($a) { $rkdet = $a ; } 
$version="0.54" ; $release = '1' ;
if ($rkdet ne 'rkdet') {
  print "If building from SRPM you may need to repeat this build in order to create $rkdet-$version-$release.rpm\n" ;
}
$cache{'rkdet'} = $rkdet ;

print "pick a delete tool for \"make clean\"\n" ;
print "Select delete tool:\n" ;
$p = `which bcwipe 2>/dev/null` ; chomp($p) ;
unless (-x $p) {
  $p = `which rm 2>/dev/null` ; chomp($p) ;
}
$rm = "$p -f" ;
if ($cache{'rm'}) { $rm = $cache{'rm'} ; }
print "$rm " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( -x $a) {
  $rm = $a ; 
} elsif(!$a && $p) {
  $rm = "$p -f" ;
} else {
  print "  not found; cannot continue\n" ;
  exit 1;
}
$cache{'rm'} = $rm ;

print "Select checksum program:\n" ;
$p = `which md5sum 2>/dev/null` ; chomp($p) ;
unless (-x $p) {
  $p = `which sum 2>/dev/null` ; chomp($p) ;
}
if ($cache{'cksum0'}) { $p = $cache{'cksum0'} ; }
print "$p " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( -x $a) {
  $cksum0 = $a ; push (@myprogs,$a) ;
} elsif(!$a && $p) {
  $cksum0 = $p ; push (@myprogs,$p) ;
} else {
  print "  not found; cannot continue\n" ;
  exit 1;
}
$cache{'cksum0'} = $cksum0 ;


print "Select who command:\n" ;
$p = `which w 2>/dev/null` ; chomp($p) ;
if ($cache{'wcmd'}) { $p = $cache{'wcmd'} ; }
print "$p " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( -x $a) {
  $wcmd = $a ;
} elsif(!$a && $p) {
  $wcmd = $p ;
} else {
  print "  not found\n" ;
}
$cache{'wcmd'} = $wcmd ;

print "Select netstat:\n" ;
$p = `which netstat 2>/dev/null` ; chomp($p) ;
if ($cache{'netstat0'}) { $p = $cache{'netstat0'} ; }
print "$p " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( -x $a) {
  $netstat0 = $a ;
} elsif(!$a && $p) {
  $netstat0 = $p ;
} else {
  print "  not found\n" ;
}
$cache{'netstat0'} = $netstat0 ;

print "Select ps:\n" ;
$p = `which ps 2>/dev/null` ; chomp($p) ;
if ($cache{'ps0'}) { $p = $cache{'ps0'} ; }
print "$p " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( -x $a) {
  $ps0 = $a ;
} elsif(!$a && $p) {
  $ps0 = $p ;
} else {
  print "  not found\n" ;
}
$cache{'ps0'} = $ps0 ;

print "rkdet will attempt to send mail if intrusion is detected\n" ;
print "Select mail command:\n" ;
$p = `which mail 2>/dev/null` ; chomp($p) ;
if (-x $p) {
  $mail = "$p -s 'Intrusion Report for %s' root" ;
} else {
  $mail = "mail -s 'Intrusion Report for %s' root" ;
}
if ($cache{'mail'}) { $mail = $cache{'mail'} ; }
print "\"$mail\" " ;
$a = (<STDIN>) ;  chomp($a) ;
if ($a) { $mail = $a ; }
$cache{'mail'} = $mail ;

print "Select mail subject:\n" ;
$p ="Intruder Report for" ;
if ($cache{'mailmsg'}) { $p = $cache{'mailmsg'} ; }
print "\"$p\" " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( $a) {
  $mailmsg = $a ; 
} else {
  $mailmsg = $p ;
}
$cache{'mailmsg'} = $mailmsg ;

print "rkdet will generate a message at boot time\n" ;
print "you may wish to specify a particular person or department\n" ;

print "Select startup message:\n" ;
$p="(See your network guru for details)" ;
if ($cache{'guru'}) { $p = $cache{'guru'} ; }
print "$p " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( $a) {
  $guru = $a ;
} else {
  $guru = $p ;
}
$cache{'guru'} = $guru ;

print "Select run argument (see documentation)\n" ;
if ($cache{'arg'}) {
  if ($cache{'arg'} % 2) { $p = 'y' ; } else { $p = 'n' ; }
  if ($cache{'arg'}/2 % 2) {  $q = 'l' ; } else { $q = 'w' ; } 
} else {
  $p = 'y' ; $q = 'l' ;
}
print "Check for sniffer [$p] " ;
$a = (<STDIN>) ;  chomp($a) ;
unless ($a) { $a = $p ; }
$arg = ($a =~ /y/i) ;
print "Disconnect WAN [w] or LAN [l] or only log [o] ?\n[$q] " ;
$a = (<STDIN>) ;  chomp($a) ;
unless ($a) { $a = $q ; }
$arg += ($a =~ /l/i) * 2 ;
$arg += ($a =~ /o/i) * 4 ;
$p= int(rand(1000))*8 + $arg ;
print "Select actual argument:\n" ;
print "$p " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( $a) {
  $arg = $a ;
} else {
  $arg = $p ;
}
$cache{'arg'} = $arg ;

print<<EOT;
rkdet will attempt to disconnect the computer from the network.
Normally it will either delete the default gateway, allowing access only
to the local network, or take the eth0 Ethernet interface down, blocking
all access. You should change these defaults to use an ipchains firewall
command, or if you use a different interface.
EOT
print "Select WAN disconnect command:\n" ;
$p = `which route 2>/dev/null` ; chomp($p) ;
$p = "$p del default" ;
if ($cache{'delcmd'}) { $p = $cache{'delcmd'} ; }
print "$p " ;
$a = (<STDIN>) ;  chomp($a) ;
if ($a) {
  $delcmd = $a ;
} else {
  $delcmd = $p ;
}
$cache{'delcmd'} = $delcmd ;

print "Select LAN disconnect command:\n" ;
foreach $_ (split(/\n/,`route`)) {
  if (/^default/) {
    s/.* // ; $dev = $_ ;
  }
}
$p = `which ifconfig 2>/dev/null` ; chomp($p) ;
$p = "$p $dev down" ;
if ($cache{'offcmd'}) { $p = $cache{'offcmd'} ; }
print "$p " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( $a) {
  $offcmd = $a ;
} else {
  $offcmd = $p ;
}
$cache{'offcmd'} = $offcmd ;

print "rkdet will log events to a logfile\n" ;
print "Select logfile:\n" ;
if (-d '/var/log') { $p = "/var/log" ; }
$p = "$p/$rkdet.log" ;
if ($cache{'mylog'}) { $p = $cache{'mylog'} ; }
print "$p " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( $a) {
  $mylog =  $a ;
} else {
  $mylog =  $p ;
}
$cache{'mylog'} = $mylog ;

print "rkdet will generate a warning message on logged-in terminals\n" ;
print "Select down message:\n" ;
$p ="Checksum failure - disconnecting network" ;
if ($cache{'downmsg'}) { $p = $cache{'downmsg'} ; }
print "\"$p\" " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( $a) {
  $downmsg = $a ; 
} else {
  $downmsg = $p ;
}
$cache{'downmsg'} = $downmsg ;

print "rkdet will send a message if it is sent a TERMinate signal\n" ;
print "Select kill message:\n" ;
$p ="Attempt to kill $rkdet" ;
if ($cache{'kilmsg'}) { $p = $cache{'kilmsg'} ; }
print "\"$p\" " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( $a) {
  $kilmsg = $a ; 
} else {
  $kilmsg = $p ;
}
$cache{'kilmsg'} = $kilmsg ;



print "Choose install directory\n" ;
$p = '/usr/sbin' ;
if ($cache{'bindir'}) { $p = $cache{'bindir'} ; }
print "$p  " ;
$a = (<STDIN>) ;  chomp($a) ;
if ( -d $a) {
  $bindir =  $a ;
} elsif(!$a) {
  $bindir = '/usr/sbin';
} else {
  print "  not a directory; cannot continue\n" ;
  exit 1;
}
$cache{'bindir'} = $bindir ;




print "Select files to check:\n" ;
foreach $prog (@progs) {
  $p = `which $prog 2>/dev/null` ; chomp($p) ;
  print "$prog ($p) " ;
  $a = (<STDIN>) ;  chomp($a) ;
  if ( -f $a) {
    push (@myprogs,$a) ;
  } elsif(!$a && $p) {
    push (@myprogs,$p) ;
  } else {
    print "  not found; will not check $prog\n" ;
  }
}
foreach $lib (@libs) {
  $p = "/lib/".$lib ;
  unless ( -f $p) { $p = '' ; }
  print "$lib ($p)  " ;
  $a = (<STDIN>) ;  chomp($a) ;
  if ( -f $a) {
    push (@myprogs,$a) ;
  } elsif(!$a && $p) {
    push (@myprogs,$p) ;
  } else {
    print "  not found; will not check $lib\n" ;
  }
}

print "triggers set to (see .spec file) :\n" ;
foreach $p (@myprogs) {
  $rpm = `rpm -qf $p` ; chomp($rpm) ;
  $rpm =~ s/-[\d].*// ;
  $trig{$rpm}++ ;
}
foreach $rpm (keys (%trig)) {
  print "$rpm\n" ;
}
push (@myprogs,"$bindir/$rkdet") ;

$fcs = '' ;
open (OUT,">xfiles.txt") or die "Cannot write xfiles.txt" ;
foreach $p (@myprogs) {
  print OUT "$p\n" ; $fsc .= "$p\n" ;
}  
close (OUT) ;

$maxf = @myprogs ;
if ($maxf >=$MAXF) {
  print "You need to increase MAXF in rkdet.c to at least $maxf\n" ;
}
$sizef = length($fsc) ;
if ($sizef >= $SIZEF) {
  print "You need to increase SIZEF in rkdet.cto at least $sizef\n" ;
}
$sizes = length(`$cksum0 $0`) - length($0) ;
$sizes = $sizes * $maxf + $sizef ;
if ($sizes >= $SIZES) {
  print "You need to increase SIZES in rkdet.c to at least $sizes\n" ;
}


$cksum = "$bindir/$rkdet.sm" ;
$netstat = "$bindir/$rkdet.ns" ;
$ps = "$bindir/$rkdet.ps" ;

for ($i=-1;$i<rand(50);$i++) {
  $rand .=  ('.', '/', 0..9,'A'..'Z', 'a'..'z')[rand 64] ;
}


open (OUT,">xstrings.txt") or die "Cannot write xstrings.txt" ;
print OUT<<EOT;
delcmd;3;$delcmd
mylog;3;$mylog
offcmd;1;$offcmd
ifcmd;4;interface status
mailfmt;4;$mail
netcmd;9;$netstat -nt
wcmd;3;$wcmd
downmsg;5;$downmsg
mailmsg;9;$mailmsg
md5cmd;3;$cksum 2>&1 %s
md5msg;3;Checksums differ: %s
kmsg;4;Intrusion Report checksum %d ifstatus %d
kilmsg;9;$kilmsg
pmmsg;1;Warning: Interface %s is in promiscuous mode
dbmsg;1;Warning: Interface %s is in debug mode
rand;1;$rand
EOT


open (OUT,">Makefile") or die "Cannot write Makefile" ;
print OUT<<EOT;
#
# change ME to rename rkdet to something else (recommended)
#
ME= $rkdet
PACKAGE=$rkdet-$version
RELEASE=$release
#
# Makefile for $rkdet
#
#
BINDIR=	$bindir
# substitute disk wipe if you like...
RM= $rm

# XOR to test messages
#OPTS = -DXOR

# TEST to disable network disconnect
# NOFORK to disable forking
#OPTS = -DTEST -DNOFORK -DINTV=4


CFLAGS=	-O2 
#CFLAGS= -g

CC= umask 077 ; gcc

rkdet:	rkdet.o if-generic.o
	\$(CC) \$(CFLAGS) \$(OPTS) -o rkdet rkdet.o if-generic.o
	strip rkdet

install:	rkdet 
	install -s -m 700 rkdet  \$(BINDIR)/\$(ME)
	install -m 700 rkdet.rc /etc/rc.d/init.d/\$(ME)
	strip \$(BINDIR)/\$(ME)
	install -m 700 $cksum0 $cksum
	install -m 700 $ps0 $ps
	install -m 700 $netstat0 $netstat

check:	rkdet.c xstrings.c xfiles.c if-generic.o xstrings.h
	\$(CC) \$(CFLAGS) -DXOR  -o rkdet-test rkdet.c if-generic.o
	echo "Checking commands and messages"
	./rkdet-test
	$(RM) rkdet-test

rkdet.o:	rkdet.c xstrings.c xstrings.h xfiles.c Makefile
	\$(CC) \$(CFLAGS) \$(OPTS) -o rkdet.o -c rkdet.c

if-generic.o:	if-generic.c
	\$(CC) \$(CFLAGS) -o if-generic.o -c if-generic.c

xstrings.c:	xstrings.txt mkmsg.pl
	umask 077 ; ./mkmsg.pl < xstrings.txt > xstrings.c

xstrings.h:	xstrings.txt mkmsgh.pl
	umask 077 ; ./mkmsgh.pl < xstrings.txt > xstrings.h

xfiles.c:	xfiles.txt mkfil.pl
	umask 077 ; ./mkfil.pl < xfiles.txt > xfiles.c

clean:
	\$(RM) xstrings.c xstrings.h xfiles.c core rkdet *.o .config* \#*

tar:	../../SOURCES/\$(PACKAGE).tar.gz

../../SOURCES/\$(PACKAGE).tar.gz:	rkdet.c xstrings.txt xfiles.txt \$(PACKAGE).spec INSTALL Readme README Makefile configure if-generic.c mkmsg.pl mkmsgh.pl rkdet.rc CHANGES panic.sh
	make clean
EOT
if ($here eq "$rkdet-$version") {
  print OUT "	cd ../ ; tar -zcf ../SOURCES/\$(PACKAGE).tar.gz \$(PACKAGE)\n" ;
} else {
  print OUT "	cd ../ ; rm -rf \$(PACKAGE) ; cp -a $here \$(PACKAGE) ; tar -zcf ../SOURCES/\$(PACKAGE).tar.gz \$(PACKAGE) ; rm -rf \$(PACKAGE)\n" ;
}
print OUT<<EOT;

rpm:	../../SOURCES/\$(PACKAGE).tar.gz \$(PACKAGE).spec
	cp -f \$(PACKAGE).spec ../../SPECS
	cd .. ; rpm -ba ../SPECS/\$(PACKAGE).spec

sign:
	cd .. ; rpm --resign ../SRPMS/\$(PACKAGE)-\${RELEASE}.src.rpm 
	cd .. ; rpm  --resign ../RPMS/i386/\$(PACKAGE)-\${RELEASE}.i386.rpm
	cd .. ; pgps -a ../SOURCES/\$(PACKAGE).tar.gz

config:	configure
	./configure

EOT

open (OUT,">$rkdet-$version.spec") or die "Cannot write spec" ;
print OUT<<EOT;
Summary: Daemon to check system operation
%define version $version
%define name $rkdet
Name: %{name}
Version: %{version}
Release: 2
Source: http://vancouver-webpages.com/rkdet/%{name}-%{version}.tar.gz
Copyright: Freeware
Packager: Andrew Daviel <andrew\@vancouver-webpages.com>
Group: Networking/Daemons

%description
Consult your system manager for details

%prep
%setup -n %{name}-%{version}

%build
echo "You should probably run the configure script (in /usr/src/redhat/BUILD/%{name}-%{version})"
echo "to customise the tool for your site and make it less easy to find"
make 

%install
make install
install -m 700 $cksum0 $bindir/%{name}.sm
install -m 700 /bin/ps $bindir/%{name}.ps
install -m 700 /bin/netstat $bindir/%{name}.ns

%pre
[ \$1 -gt 1 ] && /etc/rc.d/init.d/%{name} stop
exit 0

%post
[ \$1 -eq 1 ] && /sbin/chkconfig --add %{name}
#[ \$1 -eq 1 ] && /etc/rc.d/init.d/%{name} start
exit 0

%preun
[ \$1 -eq 0 ] && /etc/rc.d/init.d/%{name} stop
[ \$1 -eq 0 ] && /sbin/chkconfig --del %{name}
exit 0

%postun
[ \$1 -eq 1 ] && /etc/rc.d/init.d/%{name} start
exit 0

%files
$bindir/%{name}
/etc/rc.d/init.d/%{name}
$bindir/%{name}.sm
$bindir/%{name}.ps
$bindir/%{name}.ns

EOT


$line = '' ;
foreach $rpm (keys (%trig)) {
  $line .= "$rpm, " ;
}
$line =~ s/, $// ;

print OUT<<EOT;
%triggerin -- $line
[ \$1 -eq 1 -a \$2 -eq 1 ] && /etc/rc.d/init.d/%{name} reload
[ \$1 -eq 1 -a \$2 -eq 2 ] && /etc/rc.d/init.d/%{name} reload
exit 0

%triggerun -- $line
[ \$1 -eq 1 -a \$2 -eq 0 ] && /etc/rc.d/init.d/%{name} reload
exit 0

%doc Readme
EOT

# status returns: 3 stopped, 2 dead, 1 dead, 0 run
open (OUT,">rkdet.rc") or die "Cannot write rc" ;
print OUT<<EOT;
#! /bin/sh
#
# chkconfig: 2345 05 95
# description: no description available
# processname: $rkdet

# Get functions
. /etc/rc.d/init.d/functions

# See how we were called.
case "\$1" in
  start)
	echo "Starting $rkdet "
	echo -n "$guru"
	daemon $rkdet $arg
	echo
	touch /var/lock/subsys/$rkdet
	;;
  stop)
	echo -n "Stopping $rkdet "
	killproc $rkdet -9
	echo
	rm -f /var/lock/subsys/$rkdet
	;;
  status)
	status $rkdet
	;;
  restart)
	\$0 stop
	\$0 start
	;;
  reload)
	status $rkdet || exit
	\$0 stop
	\$0 start
	;;
  *)
	echo "Usage: \$0 {start|stop|status|restart|reload}"
	exit 1
	;;
esac

exit 0
EOT

print<<EOT;

The list of files to check can be found in xfiles.txt. This may be edited
before running make.
The list of commands and messages can be found in xstrings.txt. This may be edited
before running make.

EOT
