| 10 | rodolico | 1 | #! /usr/bin/env perl
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | # script to process samba audit log, storing summary of information
 | 
        
           |  |  | 4 | # for future processing.
 | 
        
           |  |  | 5 | # will read $summaryFile into memory, if it exists, then scan
 | 
        
           |  |  | 6 | # $auditFile, adding new entries.
 | 
        
           |  |  | 7 | # will then write results back to $summaryFile (making a backup first)
 | 
        
           |  |  | 8 | # resulting file is a tab delimited text file, where each line begins
 | 
        
           |  |  | 9 | # with three standard fields; username, timestamp and IP.
 | 
        
           |  |  | 10 | # the remaining fields are actions based on %headers below (other actions
 | 
        
           |  |  | 11 | # are ignored).
 | 
        
           |  |  | 12 | #
 | 
        
           |  |  | 13 | # NOTE: timestamp is floor'd to the nearest day, ie int(timestamp/86400)*86400
 | 
        
           |  |  | 14 | # as we want to summarize a days activity.
 | 
        
           |  |  | 15 |   | 
        
           |  |  | 16 | use strict;
 | 
        
           |  |  | 17 | use warnings;
 | 
        
           |  |  | 18 | use Parse::Syslog;
 | 
        
           |  |  | 19 | # apt-get install libparse-syslog-perl
 | 
        
           |  |  | 20 |   | 
        
           |  |  | 21 | # path to Samba audit file
 | 
        
           |  |  | 22 | my $auditFile = '/var/log/samba/audit.log.1';
 | 
        
           |  |  | 23 |   | 
        
           |  |  | 24 | # path to our historical summary file
 | 
        
           |  |  | 25 | my $summaryFile = '/opt/sambaAudit/samba_audit.summary';
 | 
        
           |  |  | 26 | # hash to store all our activity
 | 
        
           |  |  | 27 | my %activity;
 | 
        
           |  |  | 28 | # hash containing the action headers we care about
 | 
        
           |  |  | 29 | my %headers = ( 'mkdir' => 1, 'pread' => 1, 'pwrite' => 1,'rmdir' => 1,'unlink' => 1 );
 | 
        
           |  |  | 30 | # number of seconds in a day, 86400. BREAKS on Daylight Savings Time
 | 
        
           |  |  | 31 | my $secondsInDay = 60*60*24;
 | 
        
           |  |  | 32 |   | 
        
           |  |  | 33 | # function loads the summary file into %activity
 | 
        
           |  |  | 34 | # also modified %headers, based on the headers it finds in the summary file
 | 
        
           |  |  | 35 | sub loadSummary {
 | 
        
           |  |  | 36 |    open SUMMARY,"<$summaryFile" or return;
 | 
        
           |  |  | 37 |    #print STDERR "Loading summary file\n";
 | 
        
           |  |  | 38 |    # file exists, so read in the first line, which is the headers
 | 
        
           |  |  | 39 |    my $line = <SUMMARY>;
 | 
        
           |  |  | 40 |    chomp $line;
 | 
        
           |  |  | 41 |    my @headers = split( "\t", $line );
 | 
        
           |  |  | 42 |    # replace our preset ones with whatever headers we have here
 | 
        
           |  |  | 43 |    %headers = map{ $_ => 1 } @headers;
 | 
        
           |  |  | 44 |    # the following are not actions, so remove them from the headers
 | 
        
           |  |  | 45 |    delete @headers{qw(user day ip)};
 | 
        
           |  |  | 46 |    # read each line and create the activity.
 | 
        
           |  |  | 47 |    # note that user, timestamp and IP are required to be in the first
 | 
        
           |  |  | 48 |    # three columns
 | 
        
           |  |  | 49 |    while ( $line = <SUMMARY> ) {
 | 
        
           |  |  | 50 |       chomp $line;
 | 
        
           |  |  | 51 |       my @data = split( "\t", $line );
 | 
        
           |  |  | 52 |       for ( my $i = 3; $i < @headers; $i++ ) {
 | 
        
           |  |  | 53 |          $activity{$data[0]}{$data[1]}{$data[2]}{$headers[$i]} = $data[$i];
 | 
        
           |  |  | 54 |       }
 | 
        
           |  |  | 55 |    }
 | 
        
           |  |  | 56 |    close SUMMARY;
 | 
        
           |  |  | 57 | }
 | 
        
           |  |  | 58 |   | 
        
           |  |  | 59 | sub mailLog {
 | 
        
           |  |  | 60 |    my $from = 'rodo@dailydata.net';
 | 
        
           |  |  | 61 |    my $to = 'rodo@dailydata.net';
 | 
        
           |  |  | 62 |    my $server = 'smtp.dailydata.net:587';
 | 
        
           |  |  | 63 |    my $smtpuser = 'rodo@dailydata.net';
 | 
        
           |  |  | 64 |    my $smtppass = 'naught/nice3';
 | 
        
           |  |  | 65 |    `/opt/sendEmail/sendEmail.pl -f '$from' -t '$to' -u 'Samba Audit Log' -s 'smtp.dailydata.net:587' -a /opt/sambaAudit/samba_audit.summary -xu '$smtpuser' -xp '$smtppass' -l /tmp/sendemail.log -m 'Attached is the tab delimited file from the audit log'`;
 | 
        
           |  |  | 66 | }
 | 
        
           |  |  | 67 |   | 
        
           |  |  | 68 | # get our summary file into the access hash
 | 
        
           |  |  | 69 | &loadSummary();
 | 
        
           |  |  | 70 |   | 
        
           |  |  | 71 | # use Parse::Syslog to read in each line, mainly to get the timestamp
 | 
        
           |  |  | 72 | my $parser = Parse::Syslog->new( $auditFile );
 | 
        
           |  |  | 73 | while ( my $sl = $parser->next ) {
 | 
        
           |  |  | 74 |    # remove the time from it; just date
 | 
        
           |  |  | 75 |    my $timestamp = int( $sl->{'timestamp'} / $secondsInDay ) * $secondsInDay;
 | 
        
           |  |  | 76 |    # text contains the information we care about
 | 
        
           |  |  | 77 |    my @temp = split( '\|', $sl->{'text'} );
 | 
        
           |  |  | 78 |    # and we only care about the first three of them, which are user, ip
 | 
        
           |  |  | 79 |    # and the action they took
 | 
        
           |  |  | 80 |    my ( $user, $ip, $action ) = @temp[0..2];
 | 
        
           |  |  | 81 |    # update %activity if this is an action we track
 | 
        
           |  |  | 82 |    $activity{$user}{$timestamp}{$ip}{$action}++ if $headers{$action};
 | 
        
           |  |  | 83 | }
 | 
        
           |  |  | 84 |   | 
        
           |  |  | 85 | # make a backup of the summary file, if it exists
 | 
        
           |  |  | 86 | unlink "$summaryFile~" if -e "$summaryFile~";
 | 
        
           |  |  | 87 | rename $summaryFile, "$summaryFile~" if -e $summaryFile;
 | 
        
           |  |  | 88 | # and overwrite it
 | 
        
           |  |  | 89 | open SUMMARY, ">$summaryFile" or die "Could not save summary file $summaryFile: $!\n";
 | 
        
           |  |  | 90 | my @line; # the line we'll build for output
 | 
        
           |  |  | 91 | # header line
 | 
        
           |  |  | 92 | print SUMMARY "user\tday\tip\t" . join( "\t", sort keys %headers ) . "\n";
 | 
        
           |  |  | 93 | # process each user
 | 
        
           |  |  | 94 | foreach my $user ( sort keys %activity ) {
 | 
        
           |  |  | 95 |    push @line, $user;
 | 
        
           |  |  | 96 |    my $timestamp = $activity{$user};
 | 
        
           |  |  | 97 |    # process the date
 | 
        
           |  |  | 98 |    foreach my $time ( sort keys %$timestamp ) {
 | 
        
           |  |  | 99 |       push @line, $time;
 | 
        
           |  |  | 100 |       my $ips = $$timestamp{$time};
 | 
        
           |  |  | 101 |       # and the time
 | 
        
           |  |  | 102 |       foreach my $ip ( sort keys %$ips ) {
 | 
        
           |  |  | 103 |          push @line, $ip;
 | 
        
           |  |  | 104 |          my $actions = $$ips{$ip};
 | 
        
           |  |  | 105 |          # Finally, get the actions (all of them)
 | 
        
           |  |  | 106 |          foreach my $action ( sort keys %headers ) {
 | 
        
           |  |  | 107 |             push @line, $$actions{$action} ? $$actions{$action} : 0;
 | 
        
           |  |  | 108 |          }
 | 
        
           |  |  | 109 |          # finished with all the actions, so dump the line
 | 
        
           |  |  | 110 |          print SUMMARY join( "\t", @line ) . "\n";
 | 
        
           |  |  | 111 |          # and delete all the actions for a new IP
 | 
        
           |  |  | 112 |          delete @line[2..$#line];
 | 
        
           |  |  | 113 |       } # ip
 | 
        
           |  |  | 114 |       # delete the IP also for a new timestamp
 | 
        
           |  |  | 115 |       delete @line[1..$#line];
 | 
        
           |  |  | 116 |    } # timestamp
 | 
        
           |  |  | 117 |    # completely reset @line for a new user
 | 
        
           |  |  | 118 |    @line = ();
 | 
        
           |  |  | 119 | } # user
 | 
        
           |  |  | 120 | close SUMMARY;
 | 
        
           |  |  | 121 |   | 
        
           |  |  | 122 | &mailLog();
 | 
        
           |  |  | 123 |   | 
        
           |  |  | 124 | 1;
 |