Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Re: syscheck: check system files for changes

by starbolin (Hermit)
on Apr 16, 2008 at 19:02 UTC ( [id://680898]=note: print w/replies, xml ) Need Help??


in reply to syscheck: check system files for changes

I borrowed your code and have been using it to keep track of my BSD system. Unfortunately, it fell down behind the book-rack where the dog got it and ripped it into little tiny shreds. I got it put back together again with plenty of tape and glue but it's not the same program it once was. All the data access got rolled up into their own loops, well.. most of them, and some time when I wasn't looking the CHECKED field totally wandered off but I did find a hash key to take it's place. I did manage to push most of the flow control out of the loops and push the data access inside of the subroutines so it should be more suited to converting to OO; something I would like to tackle when the round-toit I requisitioned is finally delivered.

#!/usr/bin/perl -w # # syschk.pl - given a list of directories, compare the hack of the fil +es # by cianoz # # 24 Jan 2008 bet - Added program name to die strings. # 25 Jan 2008 bet - Added creation of db directory if not exists. # Print mode in hex. # 11 Feb 2008 bet - Loopified stat checking. # 19 Feb 2008 bet - Added sanity checks for -f arg # 06 Apr 2008 bet - resequence # 11 Apr 2008 bet - CHECKED field no longer needed # # If we parallel the files we have the benefit # of hashing them sequentially while the # routine is still in cache, also the # fetches or writes # to the DB will be consecutive,, # note: no difference noted. # # In an object world the db objects # ( file refs ; would check themselves,, # use warnings; use strict; use vars qw(%opt %DB $VERSION $NAME $DEFRC $DEFDB $DEFNM $DEFLIB $DEBU +G); use subs qw( initialize check ); use diagnostics; $DEBUG = 0; $VERSION = '0.9.2'; $0 =~ m|/|g; $NAME = $'; $DEFNM = 'sum.db'; $DEFLIB = "/var/db/syschk"; $DEFDB = "$DEFLIB/$DEFNM"; $DEFRC = '/etc/syschk.rc'; use File::Find 'find'; use Digest::MD5; use Getopt::Std; use DB_File; use English '-no_match_vars'; getopts('hvidtf:c:', \%opt); if( $opt{h} ) { print(<<EOF); $NAME $VERSION USAGE: $NAME [-hvi] [-f checksum_file] [-c config_file] DESCRIPTION: This program checks files and directories in your system, reporting if they were modified (by checking an md5,sha1 sum) created or deleted since last time you initialized it. I use it to check my /etc /sbin /lib /bin /usr/bin and /usr/sbin You can run it from a cron job or manually (it is safe to store a copy of the checksum database outside the syste +m). It takes about 2 minutes to scan all relevant files on my (chinoz) sys +tems. Although it works for me it is all but perfect: I would appreciate some hints to make it better. Options: -h this (poor) help -i create (initialize) a new checksum database -f <checksum_file> use another checksum file instead of $DEFDB -c <config_file> use another config file instead of $DEFRC ( - for STDIN) -v verbose output (not yet implemented :) EOF exit 0; } # end -h option my $rcfile = $opt{c} || $DEFRC; my $dbfile = $opt{f} || $DEFDB; $DEBUG= ($opt{d})?1:0; if( $dbfile =~ m<^([\-.\w/]+)$> ) { $dbfile = $1; # Sanitized } else { die "$NAME reports invalid file path. $!\n"; } ( $EUID==0 ) or die "$NAME must run as root.\n"; if( $opt{i} ) { unless (-e $DEFLIB) { print "Creating $DEFLIB\n"; mkdir $DEFLIB, 0644 or die "No syscheck subdir and cannot crea +te one."; } if (-e $dbfile) { unlink( $dbfile ) or die "$NAME cannot unlink $dbfile: $!\n"; } else { print "$NAME reports $dbfile missing.\n","Creating $dbfile\n"; } } # point to the particular find() handler we're going to use. my $process = ( $opt{i} ) ?\&initialize :\&check; # end options processing tie %DB, 'DB_File', $dbfile or die "$NAME cannot tie $dbfile\n"; print header(); # read in the rcfile # Three argument open is more secure here. open( RC, "<", $rcfile ) or die "$NAME cannot open $rcfile: $!\n"; my @directories = grep { chomp; ( not ( /^\s*[#\$]/ or /^\s*$/ )) } <R +C>; close RC; my %filenames; # Convert a list of directories into files and store in a HoH find \&get_files, @directories; for ( keys %filenames ) { if ( $filenames{$_}->{openp} ) { $filenames{$_}->{hash} = hashit($_); $filenames{$_}->{stat} = statit($_); &$process ( $_ ); close $filenames{$_}->{handle}; } else { print "- unopened file: $_\n"; } } # Post processing deletions() unless $opt{i}; totals() if $opt{t}; print footer(); untie %DB; exit 0; # # End of MAIN # ################################################################ ################################################################ # # Subroutines # sub get_files { # callback from find() # modifies global %filenames if( -f $_ ) { # Only process plain files. my $fname = $File::Find::name; print "Open: $fname\n" if $DEBUG; # Three argument open is more secure here. my $openp = open( my $file, '<', $_ ); $file = $file || 0; $filenames{$fname} = +{ handle=>$file, openp=>$openp }; } } # hashit ( filenmame ) # sub hashit { my $md5 = new Digest::MD5; $md5->addfile( $filenames{$_[0]}->{handle} ); return $md5->hexdigest; } # statit ( filename ) sub statit { my( undef, undef, $mode, undef, $uid, $gid, undef, undef, undef, $mtime, undef, undef, undef, ) = stat ( $filenames{$_[0]}->{handle} ); return { mode => $mode, uid => $uid, gid => $gid, time => $mtime, }; } # initialize ( filename ) - aliased to process() if opt{i} # Write HoH to database sub initialize { my $fname = $_[0]; # record it # "$digest:$mode:$uid:$gid:$mtime"; $DB{$fname} =join ':', ( $filenames{$fname}->{hash}, $filenames{$fname}{stat}{mode}, $filenames{$fname}{stat}{uid}, $filenames{$fname}{stat}{gid}, $filenames{$fname}{stat}{time}, ); } # check ( filename ) - aliased to process() if not opt{i} # Get the DB record an compare to the HoH sub check{ my $fname = $_[0]; print "Check $fname\n" if ($DEBUG); if( exists $DB{$fname} ) { my( $digest, $mode, $uid, $gid, $mtime) = split( ':', $DB{$fna +me}); my @these = ( # List of data to be compared according to the +format: # was--------is-------------------------------type [ $digest, "$filenames{$fname}->{hash}", 'digest' ], [ $uid, $filenames{$fname}{stat}{uid}, 'uid' ], [ $gid, $filenames{$fname}{stat}{gid}, 'gid' ], [ sprintf( "%o", $mode ), sprintf( "%o", $filenames{$fname}{stat}{mode} ), 'mode +' ], [ scalar localtime $mtime, scalar localtime $filenames{$fname}{stat}{time}, 'time +' ], ); compare( \@these, $fname ); # $DB{$fname} .= ':CHECKED'; } else { # !frecord print "- new file: $fname\n"; } } sub compare() { # \@, $fname my( $tests, $fname ) = @_; foreach( @$tests ) { my( $was, $is, $type ) = @$_; if( $was ne $is ) { print "File $fname - $type changed:\n", "\t old: $was\n\t new: $is\n"; } } } sub deletions { # Prints a list of file found but not in database print "\nDeleted files:\n"; print "\t", join "\n\t", grep { not exists $filenames{$_} } keys +%DB; print "\n"; } sub totals { print "Files checked: "; print scalar grep $filenames{$_}{openp}, keys %filenames ; print "\n"; } sub header { return join '', ( "$NAME V. $VERSION\n", "Begin time: ", scalar localtime time, "\n", "\n---- BEGIN REPORT ---\n", $opt{i}?"Initialize database: $dbfile\n":'', ); } sub footer { return ( "\n---- END REPORT ---\n", "End time: ", scalar localtime time, "\n" ); } __END__


s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}

Replies are listed 'Best First'.
Re^2: syscheck: check system files for changes
by Anonymous Monk on Aug 18, 2009 at 04:55 UTC
    Thanks for the leg up on this. i need it as a based point for a more general monitoring tool. Once i have made improvements will share the src

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://680898]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2024-04-16 13:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found