From 60b24b02011b37f6e287838e816532b940e5001f Mon Sep 17 00:00:00 2001 From: Brian Cox Date: Sat, 24 Jun 2017 10:57:18 -0700 Subject: [PATCH] Add a test-harness test for policy updates, & tidy up some existing test code --- src/test-harness/tests/dbupdate.pm | 2 +- src/test-harness/tests/polupdate.pm | 299 ++++++++++++++++++++++++++++ src/test-harness/twtools.pm | 54 +++-- 3 files changed, 341 insertions(+), 14 deletions(-) create mode 100644 src/test-harness/tests/polupdate.pm diff --git a/src/test-harness/tests/dbupdate.pm b/src/test-harness/tests/dbupdate.pm index 9d7a228..51746d6 100644 --- a/src/test-harness/tests/dbupdate.pm +++ b/src/test-harness/tests/dbupdate.pm @@ -177,7 +177,7 @@ sub RunBasicTest if( $n != 0 ) { - twtools("FAILED -- violations after update\n"); + twtools::logStatus("FAILED -- violations after update\n"); return 0; } diff --git a/src/test-harness/tests/polupdate.pm b/src/test-harness/tests/polupdate.pm new file mode 100644 index 0000000..1b95b4c --- /dev/null +++ b/src/test-harness/tests/polupdate.pm @@ -0,0 +1,299 @@ + +use twtools; + +package polupdate; + + +###################################################################### +# One time module initialization goes in here... +# +BEGIN +{ + # This is the root directory we will be integrity checking + # + $root1 = "$twtools::twcwd/$twtools::twrootdir/polupdate-test-1"; + $root2 = "$twtools::twcwd/$twtools::twrootdir/polupdate-test-2"; + $root3 = "$twtools::twcwd/$twtools::twrootdir/polupdate-test-3"; + + # Here are the names of the report files this test will create + # + $report1 = "$twtools::twcwd/$twtools::twrootdir/report/polupdate-1.twr"; + $report2 = "$twtools::twcwd/$twtools::twrootdir/report/polupdate-2.twr"; + $report3 = "$twtools::twcwd/$twtools::twrootdir/report/polupdate-3.twr"; + $report4 = "$twtools::twcwd/$twtools::twrootdir/report/polupdate-4.twr"; +} + +###################################################################### +# PolicyFileString -- return the policy text as a string +# +sub PolicyFileString +{ + return < \$(ReadOnly)+M; #read only plus MD5 + $root2 -> \$(ReadOnly)+M; #read only plus MD5 + +POLICY_END + +} + +###################################################################### +# PolicyFileStringNew -- return the policy text as a string +# +sub PolicyFileStringNew +{ + return < \$(ReadOnly)+S; #read only plus SHA1 + $root3 -> \$(ReadOnly)+S; #read only plus SHA1 + +POLICY_END + +} + +###################################################################### +# CreateFile -- create a file with the specified contents +# +# input: path -- path to the file; relative to $root +# contents -- string to put in the file +# +sub CreateFile +{ + my ($path, $contents) = @_; + + system( "echo $contents > $root/$path" ); + + $? && die "Create file failed for $root/$path\n"; +} + +###################################################################### +# RemoveFile -- removes the named file +# +sub RemoveFile +{ + my ($path) = @_; + + if( -e "$root/$path" ) + { + system( "rm -f $root/$path" ); + } + + $? && die "Remove file failed for $root/$path\n"; +} + + +###################################################################### +# CreateDir -- create a directory +# +sub CreateDir +{ + my($dir) = @_; + + # NOTE: mkdir fails if it is already a directory! + # + if( ! -d "$dir" ) + { + system( "rm -f $dir" ); + system( "mkdir -p $dir" ); + + $? && die "Mkdir failed for $dir\n"; + } +} + +###################################################################### +# MoveFile -- move a file from one place to another +# NOTE: file names are relative to $root +# +# input: old_name -- name of file to move +# new_name -- where it should be moved to +# +sub MoveFile +{ + my($old, $new) = @_; + + system( "mv $old $new" ); + $? && die "mv $old $new failed!\n"; +} + +###################################################################### +# PrintDatabase +# +sub PrintDatabase +{ + system( "$twtools::twrootdir/bin/twprint -m d -c $twtools::twrootdir/tw.cfg" ); +} + +###################################################################### +# PrintReport +# +sub PrintReport +{ + my ($report) = @_; + system( "$twtools::twrootdir/bin/twprint -m r -c $twtools::twrootdir/tw.cfg -r $report" ); +} + +###################################################################### +# PrepareForTest -- creates the files that each test will be +# integrity checking and initializes the database. +# +sub PrepareForTest +{ + # make sure we are cleaned up... + # + cleanup(); + + # Make the files we will be using... + # + CreateDir ( "$root1/sub" ); + CreateFile( "$root1/sub/hello.txt", "hello world one" ); + + CreateDir ( "$root2/sub" ); + CreateFile( "$root2/sub/hello.txt", "hello world two" ); + + CreateDir ( "$root3/sub" ); + CreateFile( "$root3/sub/hello.txt", "hello world three" ); + + # Initialize the database + # + twtools::InitializeDatabase(); +} + +###################################################################### +# RunBasicTest -- performs a rudimentary UpdateDatabase test +# +sub RunBasicTest +{ + printf("%-30s", "-- polupdate.basic test"); + + PrepareForTest(); + + twtools::WritePolicyFile( PolicyFileStringNew() ); + if( ! twtools::UpdatePolicy() ) + { + twtools::logStatus("FAILED -- update policy returned nonzero\n"); + return 0; + } + + # do another IC and make sure there are no violations + # + twtools::RunIntegrityCheck(); + + ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() ); + + if( $n != 0 ) + { + twtools::logStatus("FAILED -- violations after update\n"); + return 0; + } + + ++$twtools::twpassedtests; + print "PASSED\n"; + return 1; +} + +###################################################################### +# RunSecureModeTest -- performs a rudimentary UpdateDatabase test +# +sub RunSecureModeTest +{ + printf("%-30s", "-- polupdate.secure-mode test"); + + PrepareForTest(); + + twtools::WritePolicyFile( PolicyFileStringNew() ); + if( ! twtools::UpdatePolicy({ secure-mode => "high" } )) + { + twtools::logStatus("FAILED -- update policy returned nonzero\n"); + return 0; + } + + # do another IC and make sure there are no violations + # + twtools::RunIntegrityCheck(); + + ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() ); + + if( $n != 0 ) + { + twtools::logStatus("FAILED -- violations after update\n"); + return 0; + } + + ++$twtools::twpassedtests; + print "PASSED\n"; + return 1; +} + + +###################################################################### +# +# Initialize the test +# + +sub initialize +{ + # Make the policy file + # + twtools::GeneratePolicyFile( PolicyFileString() ); + return 1; +} + + +###################################################################### +# +# Run the test. +# +sub run +{ + eval { + RunBasicTest(); + } or do { + my $e = $@; + twtools::logStatus("Exception in Polupdate RunBasicTest: $e\n"); + ++$twtools::twfailedtests; + print "*FAILED*\n"; + }; + + # bump the total test count since this file's a twofer + ++$twtools::twtotaltests; + + eval { + RunSecureModeTest(); + } or do { + my $e = $@; + twtools::logStatus("Exception in Polupdate RunSecureModeTest: $e\n"); + ++$twtools::twfailedtests; + print "*FAILED*\n"; + }; +} + +sub cleanup +{ + # remove all of the files we were integrity checking... + # + system( "rm -rf $root1/*" ); + system( "rm -rf $root2/*" ); + system( "rm -rf $root3/*" ); + $? && print "WARNING: polupdate cleanup failed.\n"; + + # remove the report files we created... + # + system( "rm -f $report1" ) if (-e $report1); + system( "rm -r $report2" ) if (-e $report2); + system( "rm -r $report3" ) if (-e $report3); + system( "rm -r $report4" ) if (-e $report4); + +} + + +###################################################################### +# One time module cleanup goes in here... +# +END +{ +} + +1; + diff --git a/src/test-harness/twtools.pm b/src/test-harness/twtools.pm index 8a904df..2c50a3a 100644 --- a/src/test-harness/twtools.pm +++ b/src/test-harness/twtools.pm @@ -17,7 +17,9 @@ BEGIN { $twsitekeyloc = "key/site.key"; $twlocalkeyloc = "key/local.key"; $twpolicyloc = "policy/twpol.txt"; + $twpolfileloc = "policy/tw.pol"; $twcfgloc = "tw.cfg"; + $twsitepass = "testing"; $twlocalpass = "testing"; @@ -35,7 +37,7 @@ BEGIN { %twcfgdirs = ( ROOT => '', - POLFILE => 'policy/tw.pol', + POLFILE => $twpolfileloc, DBFILE => 'db/$(HOSTNAME).twd', REPORTFILE => 'report/$(HOSTNAME)-$(DATE).twr', SITEKEYFILE => $twsitekeyloc, @@ -158,15 +160,29 @@ sub GenerateKeys { # sub SignConfigFile { - if (!-e "$twrootdir/tw.cfg") { + if (!-e "$twrootdir/$twcfgloc") { print "signing configuration file...\n" if $verbose; - logStatus(`$twrootdir/bin/twadmin -m F -Q $twsitepass -c $twrootdir/tw.cfg -S $twrootdir/$twsitekeyloc $twrootdir/twcfg.txt`); + logStatus(`$twrootdir/bin/twadmin -m F -Q $twsitepass -c $twrootdir/$twcfgloc -S $twrootdir/$twsitekeyloc $twrootdir/twcfg.txt`); } return ($? == 0); } +###################################################################### +# Write policy text to disk... Note the contents +# of the policy file are passed in as '$twstr'. +# +sub WritePolicyFile { + + my ($twstr) = @_; + + open(FH, ">$twrootdir/$twpolicyloc") || warn $!; + print FH $twstr; + close(FH); +} + + ###################################################################### # Generate and sign the policy file... Note the contents # of the policy file are passed in as '$twstr'. @@ -175,13 +191,11 @@ sub GeneratePolicyFile { my ($twstr) = @_; - open(FH, ">$twrootdir/$twpolicyloc") || warn $!; - print FH $twstr; - close(FH); + WritePolicyFile($twstr); print "generating policy file...\n" if $verbose; - logStatus(`$twrootdir/bin/twadmin -m P -c $twrootdir/tw.cfg -Q $twsitepass -p $twrootdir/policy/tw.pol $twrootdir/policy/twpol.txt`); + logStatus(`$twrootdir/bin/twadmin -m P -c $twrootdir/$twcfgloc -Q $twsitepass -p $twrootdir/$twpolfileloc $twrootdir/$twpolicyloc`); return ($? == 0); } @@ -195,14 +209,14 @@ sub InitializeDatabase { my ($twmsg) = @_; print "initializing database for '$twmsg' test...\n" if $verbose; - logStatus(`$twrootdir/bin/tripwire -m i -P $twsitepass -p $twrootdir/policy/tw.pol -c $twrootdir/tw.cfg 2>&1`); + logStatus(`$twrootdir/bin/tripwire -m i -P $twsitepass -p $twrootdir/$twpolfileloc -c $twrootdir/$twcfgloc 2>&1`); return ($? == 0); } ###################################################################### -# Run tripwire to initialize the database... +# Run tripwire to update the database... # sub UpdateDatabase { @@ -211,11 +225,25 @@ sub UpdateDatabase { $params{'secure-mode'} = "low" if( ! defined($params{'secure-mode'}) ); print "updating database for '$twmsg' test...\n" if $verbose; - logStatus(`$twrootdir/bin/tripwire -m u -a -P $twsitepass -Z $params{'secure-mode'} -p $twrootdir/policy/tw.pol -c $twrootdir/tw.cfg -r $params{'report'} 2>&1`); + logStatus(`$twrootdir/bin/tripwire -m u -a -P $twsitepass -Z $params{'secure-mode'} -p $twrootdir/$twpolfileloc -c $twrootdir/$twcfgloc -r $params{'report'} 2>&1`); return ($? == 0); } +###################################################################### +# Run tripwire to update the policy... +# +sub UpdatePolicy { + + my (%params) = %{$_[0]}; + $params{'secure-mode'} = "low" if( ! defined($params{'secure-mode'}) ); + + print "updating policy for '$twmsg' test...\n" if $verbose; + logStatus(`$twrootdir/bin/tripwire -m p -P $twsitepass -Q $twlocalpass -Z $params{'secure-mode'} -p $twrootdir/$twpolfileloc -c $twrootdir/$twcfgloc $twrootdir/$twpolicyloc 2>&1`); + + return ($? == 0); +} + ###################################################################### # Use twprint to get a report level 0 report and return @@ -226,7 +254,7 @@ sub RunReport(%) { my (%params) = %{$_[0]}; $params{report} = $reportloc if( ! defined($params{report}) ); - my (@out) = `$twrootdir/bin/twprint -m r -c $twrootdir/tw.cfg -t 0 -r $params{report}`; + my (@out) = `$twrootdir/bin/twprint -m r -c $twrootdir/$twcfgloc -t 0 -r $params{report}`; logStatus(@out); @@ -240,7 +268,7 @@ sub RunReport(%) { # sub RunEmailTest { - my (@out) = `$twrootdir/bin/tripwire --test -c $twrootdir/tw.cfg --email elvis\@mars`; + my (@out) = `$twrootdir/bin/tripwire --test -c $twrootdir/$twcfgloc --email elvis\@mars`; logStatus(@out); @@ -258,7 +286,7 @@ sub RunIntegrityCheck { $params{report} = $reportloc if( ! defined($params{report}) ); print("running integrity check for test '$twmsg'...\n") if $verbose; - logStatus(`$twrootdir/bin/tripwire -m c -r $params{report} -p $twrootdir/policy/tw.pol -c $twrootdir/tw.cfg 2>&1`); + logStatus(`$twrootdir/bin/tripwire -m c -r $params{report} -p $twrootdir/$twpolfileloc -c $twrootdir/$twcfgloc 2>&1`); return ($? & 8); }