440 lines
12 KiB
Perl
440 lines
12 KiB
Perl
|
||
use twtools;
|
||
|
||
package integritycheck;
|
||
|
||
|
||
######################################################################
|
||
# One time module initialization goes in here...
|
||
#
|
||
BEGIN
|
||
{
|
||
$description = "integrity check test";
|
||
|
||
# This is the root directory we will be integrity checking
|
||
#
|
||
$root = "$twtools::twcwd/$twtools::twrootdir/ic-test-a";
|
||
$root2 = "$twtools::twcwd/$twtools::twrootdir/ic-test-b";
|
||
|
||
# Here are the names of the report files this test will create
|
||
#
|
||
$report1 = "$twtools::twcwd/$twtools::twrootdir/report/ic-1.twr";
|
||
|
||
$report2 = "$twtools::twcwd/$twtools::twrootdir/report/dbupdate-2.twr";
|
||
$report3 = "$twtools::twcwd/$twtools::twrootdir/report/dbupdate-3.twr";
|
||
$report4 = "$twtools::twcwd/$twtools::twrootdir/report/dbupdate-4.twr";
|
||
}
|
||
|
||
######################################################################
|
||
# PolicyFileString -- return the policy text as a string
|
||
#
|
||
sub PolicyFileString
|
||
{
|
||
return <<POLICY_END;
|
||
# Policy file generated by integrity checks test
|
||
#
|
||
(rulename="RuleA", severity=30, emailto="elvis\@mars")
|
||
{
|
||
$root -> \$(ReadOnly) +S -ab; #read only plus SHA-1 minus atime & blocks
|
||
}
|
||
|
||
(rulename="RuleB", severity=200, emailto="elvis\@mars")
|
||
{
|
||
$root2 -> \$(ReadOnly) +S -ab; #read only plus SHA-1 minus atime & blocks
|
||
}
|
||
|
||
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 > $path" );
|
||
|
||
$? && die "Create file failed for $path\n";
|
||
}
|
||
|
||
######################################################################
|
||
# RemoveFile -- removes the named file
|
||
#
|
||
sub RemoveFile
|
||
{
|
||
my ($path) = @_;
|
||
|
||
if( -e "$path" )
|
||
{
|
||
system( "rm -f $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 $root/$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 ( "$root");
|
||
CreateDir ( "$root/subdir" );
|
||
CreateFile( "$root/subdir/modify.txt", "hello world" );
|
||
CreateFile( "$root/copy-src.txt", "asdf" );
|
||
|
||
CreateDir ( "$root2");
|
||
CreateFile( "$root2/deleteme.txt", "goodbye cruel world" );
|
||
|
||
# Initialize the database
|
||
#
|
||
twtools::InitializeDatabase();
|
||
}
|
||
|
||
|
||
######################################################################
|
||
#
|
||
# Run the test.
|
||
#
|
||
sub run
|
||
{
|
||
twtools::logStatus("*** Beginning $description\n");
|
||
printf("%-30s", "-- $description");
|
||
|
||
if ($^O eq "dragonfly") {
|
||
++$twtools::twskippedtests;
|
||
print "SKIPPED; TODO: DragonflyBSD has fewer expected changes here; refactor so we can test for correct values\n";
|
||
return;
|
||
}
|
||
|
||
my $twpassed = 1;
|
||
my $dir_mods = ($^O eq "skyos") ? 0 : 1;
|
||
|
||
PrepareForTest();
|
||
|
||
# make some violations...
|
||
#
|
||
MoveFile ( "$root/copy-src.txt", "$root/copy-dest.txt" );
|
||
CreateFile( "$root/subdir/modify.txt", "bark bark bark" );
|
||
RemoveFile( "$root2/deleteme.txt");
|
||
|
||
#######################################################
|
||
# First run a full IC
|
||
#
|
||
twtools::RunIntegrityCheck();
|
||
|
||
# Make sure we got 6 violations: 3 mod, 1 add, 2 rm.
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
my $n_expected = $dir_mods ? 6 : 4;
|
||
my $c_expected = $dir_mods ? 3 : 1;
|
||
|
||
if( ($n != $n_expected) || ($a != 1) || ($r != 2) || ($c != $c_expected) )
|
||
{
|
||
twtools::logStatus("Full IC failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
# TODO: Make RunReport+AnalyzeReport play nice with signed report files
|
||
#######################################################
|
||
# Do it again, but sign it this time.
|
||
#
|
||
#twtools::RunIntegrityCheck({trailing_opts => "-E -P $twtools::twlocalpass"});
|
||
|
||
# Make sure we got 6 violations: 3 mod, 1 add, 2 rm.
|
||
#
|
||
#my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
|
||
#if( ($n != 6) || ($a != 1) || ($r != 2) || ($c != 3) )
|
||
#{
|
||
# twtools::logStatus("Full IC with signing failed: $n $a $r $c\n");
|
||
# $twpassed = 0;
|
||
#}
|
||
|
||
#######################################################
|
||
# Now run 'just' the FS section, aka the whole policy
|
||
#
|
||
RemoveFile("$reportloc");
|
||
twtools::RunIntegrityCheck(trailing_opts => "-x FS");
|
||
|
||
# Make sure we got 6 violations: 3 mod, 1 add, 2 rm.
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
my $n_expected = $dir_mods ? 6 : 4;
|
||
my $c_expected = $dir_mods ? 3 : 1;
|
||
|
||
if( ($n != $n_expected) || ($a != 1) || ($r != 2) || ($c != $c_expected) )
|
||
{
|
||
twtools::logStatus("IC with FS section failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
#######################################################
|
||
# Now run a check ignoring the SHA attribute, should still return same changes
|
||
#
|
||
RemoveFile("$reportloc");
|
||
twtools::RunIntegrityCheck(trailing_opts => "-i S");
|
||
|
||
# Make sure we got 6 violations: 3 mod, 1 add, 2 rm.
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
my $n_expected = $dir_mods ? 6 : 4;
|
||
my $c_expected = $dir_mods ? 3 : 1;
|
||
|
||
if( ($n != $n_expected) || ($a != 1) || ($r != 2) || ($c != $c_expected) )
|
||
{
|
||
twtools::logStatus("IC with FS section failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
#######################################################
|
||
# Now just run RuleA
|
||
#
|
||
RemoveFile("$reportloc");
|
||
twtools::RunIntegrityCheck({trailing_opts => "-R RuleA"});
|
||
|
||
# Make sure we got 4 violations this time: 2 mod, 1 add, 1 rm.
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
my $n_expected = $dir_mods ? 4 : 3;
|
||
my $c_expected = $dir_mods ? 2 : 1;
|
||
|
||
if( ($n != $n_expected) || ($a != 1) || ($r != 1) || ($c != $c_expected) )
|
||
{
|
||
twtools::logStatus("IC of Rule A failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
#######################################################
|
||
# Now run severity level 200, meaning RuleB
|
||
#
|
||
RemoveFile("$reportloc");
|
||
twtools::RunIntegrityCheck({trailing_opts => "-l 200"});
|
||
|
||
# Make sure we got 2 violations this time: 1 mod, 0 add, 1 rm.
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
my $n_expected = $dir_mods ? 2 : 1;
|
||
my $c_expected = $dir_mods ? 1 : 0;
|
||
|
||
if( ($n != $n_expected) || ($a != 0) || ($r != 1) || ($c != $c_expected) )
|
||
{
|
||
twtools::logStatus("IC of severity 200+ failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
#######################################################
|
||
# Now run severity level "high", also meaning RuleB
|
||
#
|
||
RemoveFile("$reportloc");
|
||
twtools::RunIntegrityCheck({trailing_opts => "-l high"});
|
||
|
||
# Make sure we got 2 violations this time: 1 mod, 0 add, 1 rm.
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
my $n_expected = $dir_mods ? 2 : 1;
|
||
my $c_expected = $dir_mods ? 1 : 0;
|
||
|
||
if( ($n != $n_expected) || ($a != 0) || ($r != 1) || ($c != $c_expected) )
|
||
{
|
||
twtools::logStatus("IC of severity 'high' failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
#######################################################
|
||
# Now run against one object, modify.txt
|
||
#
|
||
RemoveFile("$reportloc");
|
||
twtools::RunIntegrityCheck({trailing_opts => "$root/subdir/modify.txt"});
|
||
|
||
# Make sure we got 1 violation this time: 1 mod, 0 add, 0 rm.
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
|
||
if( ($n != 1) || ($a != 0) || ($r != 0) || ($c != 1) )
|
||
{
|
||
twtools::logStatus("IC of single object modify.txt failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
#######################################################
|
||
# Run a few full check w/ email reporting, all the valid levels
|
||
# (we're configured to pipe to cat as a fake mailprogram)
|
||
#
|
||
RemoveFile("$reportloc");
|
||
twtools::RunIntegrityCheck({trailing_opts => "-M -t 0"});
|
||
twtools::RunIntegrityCheck({trailing_opts => "-M -t 1"});
|
||
twtools::RunIntegrityCheck({trailing_opts => "-M -t 2"});
|
||
twtools::RunIntegrityCheck({trailing_opts => "-M -t 3"});
|
||
twtools::RunIntegrityCheck({trailing_opts => "-M -t 4"});
|
||
|
||
# Make sure we got 6 violations: 3 mod, 1 add, 2 rm.
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
my $n_expected = $dir_mods ? 6 : 4;
|
||
my $c_expected = $dir_mods ? 3 : 1;
|
||
|
||
if( ($n != $n_expected) || ($a != 1) || ($r != 2) || ($c != $c_expected) )
|
||
{
|
||
twtools::logStatus("Full IC failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
|
||
#######################################################
|
||
# Now run an interactive IC with cat as a fake editor, so DB gets auto updated.
|
||
#
|
||
RemoveFile("$reportloc");
|
||
twtools::RunIntegrityCheck({trailing_opts => "-I -V cat -P $twtools::twlocalpass"});
|
||
|
||
# Make sure we got 6 violations: 3 mod, 1 add, 2 rm.
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
my $n_expected = $dir_mods ? 6 : 4;
|
||
my $c_expected = $dir_mods ? 3 : 1;
|
||
|
||
if( ($n != $n_expected) || ($a != 1) || ($r != 2) || ($c != $c_expected) )
|
||
{
|
||
twtools::logStatus("Interactive IC failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
#######################################################
|
||
# Finally run another full IC to verify db was updated
|
||
# + also exercise the verbose & hex output options since we don't elsewhere.
|
||
#
|
||
RemoveFile("$reportloc");
|
||
twtools::RunIntegrityCheck({trailing_opts => "-v -h"});
|
||
|
||
# Make sure we got no violations this time
|
||
#
|
||
my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() );
|
||
|
||
if( ($n != 0) || ($a != 0) || ($r != 0) || ($c != 0) )
|
||
{
|
||
twtools::logStatus("IC after interactive IC failed: $n $a $r $c\n");
|
||
$twpassed = 0;
|
||
}
|
||
|
||
#########################################################
|
||
#
|
||
# See if the tests all succeeded...
|
||
#
|
||
if ($twpassed) {
|
||
++$twtools::twpassedtests;
|
||
print "PASSED\n";
|
||
return 1;
|
||
}
|
||
else {
|
||
++$twtools::twfailedtests;
|
||
print "*FAILED*\n";
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
######################################################################
|
||
#
|
||
# Initialize the test
|
||
#
|
||
|
||
sub initialize
|
||
{
|
||
# Make the policy file
|
||
#
|
||
twtools::GeneratePolicyFile( PolicyFileString() );
|
||
return 1;
|
||
}
|
||
|
||
|
||
sub cleanup
|
||
{
|
||
# remove all of the files we were integrity checking...
|
||
#
|
||
system( "rm -rf $root/*" );
|
||
system( "rm -rf $root2/*" );
|
||
$? && print "WARNING: IC 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;
|
||
|