File Coverage

lib/Audit/Log.pm
Criterion Covered Total %
statement 66 66 100.0
branch 21 24 87.5
condition 13 18 72.2
subroutine 6 6 100.0
pod 2 2 100.0
total 108 116 93.1


line stmt bran cond sub pod time code
1             package Audit::Log 0.003;
2              
3 1     1   90906 use strict;
  1         3  
  1         34  
4 1     1   6 use warnings;
  1         2  
  1         31  
5              
6 1     1   26 use 5.006;
  1         3  
7 1     1   9 use v5.12.0; # Before 5.006, v5.10.0 would not be understood.
  1         3  
8              
9             # ABSTRACT: auditd log parser with no external dependencies, using no perl features past 5.12
10              
11             sub new {
12 1     1 1 175 my ( $class, $path, @returning ) = @_;
13 1 50       5 $path = '/var/log/audit/audit.log' unless $path;
14 1 50       22 die "Cannot access $path" unless -f $path;
15 1         9 return bless( { path => $path, returning => \@returning }, $class );
16             }
17              
18             sub search {
19 1     1 1 22 my ( $self, %options ) = @_;
20              
21 1         3 my $ret = [];
22 1         3 my $in_block = 1;
23 1         1 my $line = -1;
24 1         3 my ( $cwd, $exe, $comm ) = ( '', '', '' );
25 1         43 open( my $fh, '<', $self->{path} );
26 1         43 LINE: while (<$fh>) {
27 327 100 100     1095 next if index( $_, 'SYSCALL' ) < 0 && !$in_block;
28              
29             # I am trying to cheat here to snag the timestamp.
30 105         134 my $msg_start = index( $_, 'msg=audit(' ) + 10;
31 105         107 my $msg_end = index( $_, ':' );
32 105         147 my $timestamp = substr( $_, $msg_start, $msg_end - $msg_start );
33 105 100 66     367 next if $options{older} && $timestamp > $options{older};
34 84 100 66     277 next if $options{newer} && $timestamp < $options{newer};
35              
36             # Snag CWDs
37 43 100       90 if ( index( $_, 'type=CWD' ) == 0 ) {
38 3         5 my $cwd_start = index( $_, 'cwd="' ) + 5;
39 3         4 my $cwd_end = index( $_, "\n" ) - 1;
40 3         5 $cwd = substr( $_, $cwd_start, $cwd_end - $cwd_start );
41 3         4 $line++;
42 3         8 next;
43             }
44              
45             # Replace GROUP SEPARATOR usage with simple spaces
46 40         153 s/[\x1D]/ /g;
47              
48             my %parsed = map {
49 1052         1497 my @out = split( /=/, $_ );
50 1052         1989 shift @out, join( '=', @out )
51 1052         1087 } grep { $_ } map {
52 40         275 my $subj = $_;
  1052         1065  
53 1052         1249 $subj =~ s/"//g;
54 1052         998 chomp $subj;
55 1052         1242 $subj
56             } split( / /, $_ );
57              
58 40         191 $line++;
59 40         50 $parsed{line} = $line;
60 40         58 $parsed{timestamp} = $timestamp;
61 40         53 $parsed{cwd} = $cwd;
62 40   66     74 $parsed{exe} //= $exe;
63 40   66     90 $parsed{comm} //= $comm;
64              
65 40 100 66     130 if ( exists $options{key} && $parsed{type} eq 'SYSCALL' ) {
66 19         83 $in_block = $parsed{key} =~ $options{key};
67 19         26 $exe = $parsed{exe};
68 19         21 $comm = $parsed{comm};
69 19         19 $cwd = '';
70 19 100       133 next unless $in_block;
71             }
72              
73             # Check constraints BEFORE filtering returned values, this is a WHERE clause
74 24         55 CONSTRAINT: foreach my $constraint ( keys(%options) ) {
75 110 100       158 next CONSTRAINT if !exists $parsed{$constraint};
76 28 100       298 next LINE if $parsed{$constraint} !~ $options{$constraint};
77             }
78              
79             # Filter fields for RETURNING clause
80 2 50       5 if ( @{ $self->{returning} } ) {
  2         7  
81 2         10 foreach my $field ( keys(%parsed) ) {
82             delete $parsed{$field}
83 46 100       46 unless grep { $field eq $_ } @{ $self->{returning} };
  368         449  
  46         55  
84             }
85             }
86 2         12 push( @$ret, \%parsed );
87             }
88 1         26 close($fh);
89 1         15 return $ret;
90             }
91              
92             1;
93              
94             __END__