##########################################################################
# $Id$
##########################################################################
# $Log: audit,v $
# Revision 1.15 2009/02/20 17:59:47 mike
# Patch from Ivan Varekova -mgt
#
# Revision 1.14 2008/05/04 14:15:39 mike
# Parsing of logw lines fedora bug #440534 -mgt
#
# Revision 1.13 2008/03/25 14:41:58 kirk
# updated copyright to Ron Kuris
#
# Revision 1.12 2008/03/24 23:31:26 kirk
# added copyright/license notice to each script
#
# Revision 1.11 2007/07/18 18:22:45 bjorn
# Additional filtering, by Ivana Varekova.
#
# Revision 1.10 2007/02/16 03:25:17 bjorn
# Don't test for selinux, and filter "Started dispatcher", by Ivana Varekova.
#
# Revision 1.9 2006/12/20 15:25:09 bjorn
# Additional filtering, by Ivana Varekova.
#
# Revision 1.8 2006/09/15 15:40:58 bjorn
# Additional filtering by Ivana Varekova.
#
# Revision 1.7 2006/08/23 22:54:04 bjorn
# Filtering additional informational messages, by Marcela Maslanova.
#
# Revision 1.6 2006/03/20 20:42:57 bjorn
# Additional filtering, by Ivana Varekova.
#
# Revision 1.5 2005/12/06 02:36:35 bjorn
# Report low disk space, by Ivana Varekova.
#
# Revision 1.4 2005/10/26 05:52:12 bjorn
# Filtering modifications by Ivana Varekova
#
# Revision 1.3 2005/10/01 19:09:07 bjorn
# Extensive modifications by Ivana Varekova
#
# Revision 1.2 2005/06/07 18:43:32 bjorn
# Limiting number of unmatched statement
#
# Revision 1.1 2005/05/04 15:56:13 bjorn
# Audit (for selinux) submitted by Ron Kuris
#
##########################################################################
########################################################
# selinux audit log summaries
#
# This was written and is maintained by:
# Ron Kuris <swcafe@gmail.com>
#
# Please send all comments, suggestions, bug reports,
# etc, to logwatch-devel@lists.sourceforge.net
########################################################
########################################################
## (c) 2006,2008 Ron Kuris <swcafe@gmail.com>
## Covered under the included MIT/X-Consortium License:
## http://www.opensource.org/licenses/mit-license.php
## All modifications and contributions by other persons to
## this script are assumed to have been donated to the
## Logwatch project and thus assume the above copyright
## and licensing terms. If you want to make contributions
## under your own copyright or a different license this
## must be explicitly stated in the contribution an the
## Logwatch project reserves the right to not accept such
## contributions. If you have made significant
## contributions to this script and want to claim
## copyright please contact logwatch-devel@lists.sourceforge.net.
#########################################################
use strict;
use Logwatch ':all';
my (%denials, %grants, %loads);
my @OtherList;
my $othercount = 0;
my $Debug = ($ENV{'LOGWATCH_DEBUG'} || 0);
my $Detail = ($ENV{'LOGWATCH_DETAIL_LEVEL'} || 0);
my $NumberOfInits = 0;
my $NumberOfDStarts = 0;
my $NumberOfDStartsPid = 0;
my $NumberOfDStops = 0;
my $NumberOfDdStarts = 0;
my $NumberOfDdStops = 0;
my $NumberOfAllowedMessages = 0;
my $NumberOfLostMessages = 0;
my %InvalidContext = ();
my %BugLog = ();
my $UELimit = 100;
my $ThisLine;
my %Warning = ();
my %AuditctlStatus = ();
print STDERR "\n\nDEBUG: Inside audit filter\n\n" if ( $Debug >= 5 );
while ($ThisLine = <STDIN>) {
chomp($ThisLine);
# Remove timestamp if present
$ThisLine =~ s/^\[\s*\d+\.\d+\]\s*//;
if (( $ThisLine =~ /initializing netlink (socket|subsys) \(disabled\)/) or
( $ThisLine =~ /audit_pid=[0-9]* old=[0-9]*(?: by auid=[0-9]*)?/) or
( $ThisLine =~ /(arch=[0-9]+ )?syscall=[0-9]+ (success=(no|yes) )?exit=[0-9-]+( a[0-3]=[0-9a-f]+)* items=[0-9]+ (ppid=[0-9]+ )?pid=[0-9]+ (loginuid=[0-9-]+ )?(auid=[0-9]+ )?uid=[0-9]+ gid=[0-9]+ euid=[0-9]+ suid=[0-9]+ fsuid=[0-9]+ egid=[0-9]+ sgid=[0-9]+ fsgid=[0-9]+/) or
( $ThisLine =~ /Audit daemon rotating log files/) or
( $ThisLine =~ /audit_backlog_limit=[0-9]* old=[0-9]*(?: by auid=[0-9]*)?/) or
( $ThisLine =~ /SELinux: unrecognized netlink message type=[0-9]+ for sclass=[0-9]+/) or
( $ThisLine =~ /audit\([0-9.]+:[0-9]+\): saddr=[0-9]+/) or
( $ThisLine =~ /nargs=[0-9]+ a0=[0-9a-f]+ a1=[0-9a-f]+ a2=[0-9a-f]+ a3=[0-9a-f]+ a4=[0-9a-f]+ a5=[0-9a-f]+/) or
( $ThisLine =~ /^audit\([0-9.]+:[0-9]+\): ( ?(path|cwd|item|name|flags)=["\/A-Za-z0-9]*)*$/) or
( $ThisLine =~ /: enforcing=[0-9]+ old_enforcing=[0-9]+ auid=[0-9]+/) or
( $ThisLine =~ /: policy loaded auid=[0-9]+/) or
( $ThisLine =~ /: user pid=[0-9]+ uid=[0-9]+ auid=[0-9]+ subj=system_u:system_r:system_dbusd_t:[0-9a-z:.\-]+ msg=/) or
( $ThisLine =~ /audit\([0-9.]+:[0-9]+\): (selinux=[0-9]+|auid=[0-9]+|prom=[0-9]+|old_prom=[0-9]+|dev=[^ ]+|ses=[0-9]+| )+$/) or
( $ThisLine =~ /auditd[ ]+S [0-9A-F]+ [0-9]+ [0-9]+[ ]+[0-9]([ ]*[0-9]+[ ]*|[ ]*)[0-9]+ [0-9]+ \(NOTLB\)/) or
( $ThisLine =~ /Started dispatcher: \/sbin\/audispd pid: [0-9]+/) or
( $ThisLine =~ /audit\([0-9.]*:[0-9]*\): bool=.* val=.* old_val=.* auid=[0-9]*/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): audit_enabled=[0-9]* old=[0-9]* auid=[0-9]* ses=[0-9]*/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): auid=[0-9]* ses=[0-9]* subj=system_u:system_r:.*:s0 op=.* key=.* list=[0-9]* res=[0-9]*/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=0 uid=0 auid=[0-9]* ses=[0-9]* subj=system_u:system_r:.*:s0 .* res=success/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=1 uid=0 auid=[0-9]* ses=[0-9]* subj=system_u:system_r:init_t:s0 .* res=success/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=[0-9]* uid=0 auid=[0-9]* ses=[0-9]*$/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=[0-9]* uid=0 auid=[0-9]* ses=[0-9]* subj=.*res=success/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=[0-9]* uid=0 old auid=[0-9]* new auid=[0-9]+ old ses=[0-9]* new ses=[0-9]+ res=1$/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=[0-9]* uid=0 subj=.* old-auid=[0-9]* auid=[0-9]+ old-ses=[0-9]* ses=[0-9]+ res=1$/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): cwd=".*"/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): user/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): proctitle=/) or
( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): table=/) or
( $ThisLine =~ /audit_printk_skb: [0-9]* callbacks suppressed/) or
( $ThisLine =~ /item=[0-9] name="\S*" inode=[0-9]+ dev=\S* mode=[0-9]* ouid=[0-9]* ogid=[0-9]* rdev=[0-9:]* obj=\S*/) or
( $ThisLine =~ /^auditctl(?:\[[0-9]+\])?: No rules$/ )
) {
# Ignore these entries
} elsif ( $ThisLine =~ /audit\([0-9]{10}.[0-9]{3}:[0-9]\): initialized$/) {
$NumberOfInits++;
} elsif ( $ThisLine =~ /Init complete, audit pid set to: [0-9]+/) {
$NumberOfDStartsPid++;
} elsif ( $ThisLine =~ /Init complete, auditd [0-9,.]+ listening for events/) {
$NumberOfDStarts++;
} elsif ( $ThisLine =~ /The audit daemon is exiting./) {
$NumberOfDStops++;
} elsif ( $ThisLine =~ /audit_lost=[0-9]+ (audit_backlog=[0-9]+ )?audit_rate_limit=[0-9]+ audit_backlog_limit=[0-9]+$/) {
$NumberOfLostMessages++;
} elsif ( $ThisLine =~ /auditd startup succeeded/) {
$NumberOfDdStarts++;
} elsif ( $ThisLine =~ /auditd shutdown succeeded/) {
$NumberOfDdStops++;
} elsif (( $ThisLine =~ /netlink socket too busy/) or
( $ThisLine =~ /Error sending signal_info request \(Invalid argument\)/) or
( $ThisLine =~ /major=[0-9]+ name_count=[0-9]+: freeing multiple contexts \([1-2]\)/)) {
$ThisLine =~ s/audit\(:[0-9]+\): //;
$BugLog{$ThisLine}++;
} elsif (( $ThisLine =~ /(Audit daemon is low on disk space for logging.*)/) or
( $ThisLine =~ /(Audit daemon has no space left.*)/) or
( $ThisLine =~ /(Audit daemon is suspending logging due to.*)/)) {
$Warning{$1}++;
} elsif ( my ($status) = ( $ThisLine =~ /AUDIT_STATUS: (.*)/ ) ) {
$AuditctlStatus{$status}++;
} elsif ( my ($status) = ( $ThisLine =~ /^auditctl(?:\[[0-9]+\])?: (.*)/ ) ) {
$AuditctlStatus{$status}++;
} elsif ( $ThisLine =~ /audit\([0-9]+\.[0-9]+:[0-9]+\): apparmor=/) {
# AppArmor
if ( $ThisLine =~ /apparmor="STATUS" operation="profile_(load|replace)" name="([^"]+)"/ ) {
# type=1400 audit(1314853473.168:33616): apparmor="STATUS" operation="profile_replace" name="/usr/lib/apache2/mpm-prefork/apache2//DEFAULT_URI" pid=26566 comm="apparmor_parser"
$loads{$2}++;
} elsif ( $ThisLine =~ /apparmor="DENIED" operation="([^"]+)" parent=\d+ profile="([^"]+)" name="([^"]+)" pid=\d+ comm="([^"]+)"/ ) {
# type=1400 audit(1314853822.672:33649): apparmor="DENIED" operation="mknod" parent=27250 profile="/usr/lib/apache2/mpm-prefork/apache2//example.com" name="/usr/share/wordpress/1114140474e5f13bea68a4.tmp" pid=27289 comm="apache2" requested_mask="c" denied_mask="c" fsuid=33 ouid=33
# type=1400 audit(1315353795.331:33657): apparmor="DENIED" operation="exec" parent=14952 profile="/usr/lib/apache2/mpm-prefork/apache2//example.com" name="/usr/lib/sm.bin/sendmail" pid=14953 comm="sh" requested_mask="x" denied_mask="x" fsuid=33 ouid=0
$denials{$1.' '.$3.' ('.$2.' via '.$4 . ')'}++;
} elsif ( $ThisLine =~ /apparmor="ALLOWED" operation="([^"]+)" (info="([^"]+)" )?(error=[+-]?\d+ )?(parent=\d+ )?profile="([^"]+)" (name="([^"]+)" )?pid=\d+ comm="([^"]+)"/ ) {
# type=1400 audit(1369519203.141:259049): apparmor="ALLOWED" operation="exec" parent=3733 profile="/usr/sbin/dovecot//null-1c//null-1d" name="/usr/lib/dovecot/pop3-login" pid=24634 comm="dovecot" requested_mask="x" denied_mask="x" fsuid=0 ouid=0 target="/usr/sbin/dovecot//null-1c//null-1d//null-d12"
# type=1400 audit(1369627891.522:447576): apparmor="ALLOWED" operation="capable" parent=1 profile="/usr/sbin/dovecot//null-1c//null-1d" pid=3733 comm="dovecot" capability=5 capname="kill"
# type=1400 audit(1369823965.682:824587): apparmor="ALLOWED" operation="getattr" info="Failed name lookup - deleted entry" error=-2 parent=1 profile="/usr/sbin/dovecot//null-1c//null-1d" name="/var/lib/dovecot/.temp.3733.d786c1fcaaa73248" pid=3733 comm="dovecot" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
# type=1400 audit(1410503892.382:55490): apparmor="ALLOWED" operation="open" profile="/usr/lib/dovecot/imap" name="/root/mails/.Drafts/dovecot.index.log" pid=6305 comm="imap" requested_mask="rw" denied_mask="rw" fsuid=1003 ouid=1003
$NumberOfAllowedMessages++;
} else {
$othercount++;
$ThisLine =~ s/^\s*//;
if ($othercount < $UELimit+1) {
push @OtherList, $ThisLine;
}
}
} elsif ( $Detail > 9 ) {
if ( $ThisLine =~ /avc:\s*denied\s*{\s*([^}]+).*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) {
$denials{$2.' '.$3.' ('.$1.$4 . ')'}++;
} elsif ( $ThisLine =~ /avc:\s*granted\s*{\s*([^}]+).*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) {
$grants{$2.' '.$3.' ('.$1.$4 . ')'}++;
} elsif ($ThisLine =~ /security_compute_sid:\s*invalid context\s*(\S+)\s*for\s*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) {
$InvalidContext{$4." running as ".$2." acting on ".$3." \nshould transit to invalid ".$1}++;
} elsif ($ThisLine =~ /security_sid_mls_copy:\s*invalid context\s*(\S+)/) {
$InvalidContext{"context: ".$1}++;
} else {
$othercount++;
$ThisLine =~ s/^\s*//;
if ($othercount < $UELimit+1) {
push @OtherList, $ThisLine;
}
}
} elsif ( $Detail > 4 ) {
if ( $ThisLine =~ /avc:\s*denied\s*{\s*[^}]+.*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) {
$denials{$1.' '.$2.' ('.$3 . ')'}++;
} elsif ( $ThisLine =~ /avc:\s*granted\s*{\s*[^}]+}.*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) {
$grants{$1.' '.$2.' ('.$3 . ')'}++;
} elsif ($ThisLine =~ /security_compute_sid:\s*invalid context\s*(\S+)\s*for\s*scontext=(\S+)\s*tcontext=\S+\s*tclass=(\S+)/ ) {
$InvalidContext{$3." running as ".$2." should transit to invalid ".$1}++;
} elsif ($ThisLine =~ /security_sid_mls_copy:\s*invalid context\s*(\S+)/) {
$InvalidContext{"context: ".$1}++;
} else {
$othercount++;
$ThisLine =~ s/^\s*//;
if ($othercount < $UELimit+1) {
push @OtherList, $ThisLine;
}
}
} else {
if ( $ThisLine =~ /avc:\s*denied\s*{\s*[^}]+.*scontext=([^:]+):[^:]+:\S+\s*tcontext=([^:]+):[^:]+:\S+\s*tclass=(\S+)/ ) {
$denials{$1.' '.$2.' ('.$3 . ')'}++;
} elsif ( $ThisLine =~ /avc:\s*granted\s*{\s*[^}]+.*scontext=([^:]+):[^:]+:\S+\s*tcontext=([^:]+):[^:]+:\S+\s*tclass=(\S+)/ ) {
$grants{$1.' '.$2.' ('.$3 . ')'}++;
} elsif ($ThisLine =~ /security_compute_sid:\s*invalid context\s*(\S+)\s*for\s*scontext=(\S+)\s*tcontext=\S+\s*tclass=(\S+)/ ) {
$InvalidContext{$3." running as ".$2." should transit to invalid ".$1}++;
} elsif ($ThisLine =~ /security_sid_mls_copy:\s*invalid context\s*(\S+)/) {
$InvalidContext{"context: ".$1}++;
} else {
$othercount++;
$ThisLine =~ s/^\s*//;
if ($othercount < $UELimit+1) {
push @OtherList, $ThisLine;
}
}
}
}
if ( %Warning) {
foreach my $key (keys %Warning) {
print " Warning: $key: ". $Warning{$key}. " times\n";
}
}
if ( keys %denials ) {
print "\n\n*** Denials ***\n";
foreach my $key (sort keys %denials) {
print " $key: ". $denials{$key} . " times\n";
}
}
if ( keys %grants ) {
print "\n\n*** Grants ***\n";
foreach my $key (sort keys %grants) {
print " $key: ". $grants{$key} . " times\n";
}
}
if ( keys %InvalidContext) {
print "\n\n*** Invalid Context ***\n";
foreach my $key (sort keys %InvalidContext) {
print " $key: ". $InvalidContext{$key} . " times\n";
}
}
if ( keys %loads ) {
print "\n\n*** Loads ***\n";
foreach my $key (sort keys %loads) {
print " $key: ". $loads{$key} . " times\n";
}
}
if ($Detail and $NumberOfDStarts+$NumberOfDStartsPid) {
print "\n Number of audit daemon starts: ",$NumberOfDStarts+$NumberOfDStartsPid," \n";
}
if (($Detail >9) and ($NumberOfDStartsPid)) {
print " starts with pid change: $NumberOfDStartsPid \n"
}
if ($Detail and $NumberOfDStops) {
print "\n Number of audit daemon stops: $NumberOfDStops \n";
}
if ($Detail and keys(%AuditctlStatus)) {
print "\n Auditctl status:\n";
foreach my $key (sort keys %AuditctlStatus) {
print " $key: ". $AuditctlStatus{$key} . " times\n";
}
}
if ($NumberOfAllowedMessages) {
print "\n Number of allowed messages: $NumberOfAllowedMessages\n";
}
if ($NumberOfLostMessages) {
print "\n Number of lost messages: $NumberOfLostMessages\n";
}
if ($Detail>9) {
if ($NumberOfInits) {
print "\n Number of audit initializations: $NumberOfInits \n";
}
if ($NumberOfDdStarts) {
print "\n Number of auditd daemon starts: $NumberOfDdStarts \n";
}
if ($NumberOfDdStops) {
print "\n Number of auditd daemon stops: $NumberOfDdStops \n";
}
}
if ( %BugLog) {
print "\n*** Logs which could mean a bug ***\n";
foreach my $Entry (keys %BugLog) {
print " $Entry\n";
}
}
if ( $#OtherList >= 0 ) {
print "\n**Unmatched Entries** ";
if ($othercount > $UELimit) {
print "(Only first $UELimit out of $othercount are printed)";
}
print "\n ";
print join("\n ", @OtherList);
print "\n";
}
exit(0);
# vi: shiftwidth=3 tabstop=3 syntax=perl et
# Local Variables:
# mode: perl
# perl-indent-level: 3
# indent-tabs-mode: nil
# End: