######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## 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. ######################################################### ########################################################################## # TO-DO # We really should search for specific strings (authentication failure, # bad username, check pass, password changed, session opened/closed, # account expired, etc., using the service name as a variable in the hash, # instead of having to add a test for every new service. ########################################################################### use strict; use Logwatch ':sort'; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my ($service, $line, %data); while ($line = ) { chomp $line; $service = $line; # for fedora and others if ($line =~ s/^... .. ..:..:.. .+ .+\(pam_unix\)\[\d+\]: //) { $service =~ s/^... .. ..:..:.. .+ (.+)\(pam_unix\)\[\d+\]: .*$/$1/; # new fedora (fc5) version } elsif ( $line =~ s/^... .. ..:..:.. .+ pam_unix\(.+:.+\): // ) { $service =~ s/^... .. ..:..:.. .+ pam_unix\((.+):.+\): .*$/$1/; # fedora with pam_sss } elsif ( $line =~ s/^... .. ..:..:.. .+ pam_sss\(.+:.+\): // ) { if ($line =~ /received for user/) { # ignore this line - paired with authentication failure next; } $service =~ s/^... .. ..:..:.. .+ pam_sss\((.+):.+\): .*$/$1/; # for debian sarge - "normal" lines } elsif ($line =~ s/^... .. ..:..:.. .+ [^ :]+: \(pam_unix\) //) { $service =~ s/^... .. ..:..:.. .+ ([^\s:\[\]]+)(?:\[[0-9]+\]|): \(pam_unix\) .*$/$1/; #for debian sarge - kdm - why can't they log in standard-compliant way? } elsif ( $line =~ s/^... .. ..:..:.. .+ [^\s:\[\]]+: [0-9:\[\]\.]+ \(pam_unix\) //) { $service =~ s/^... .. ..:..:.. .+ ([^\s:\[\]]+): [0-9:\[\]\.]+ \(pam_unix\) .*$/$1/; #for debian woody } elsif ( $line =~ s/^... .. ..:..:.. .+ PAM_unix\[\d+\]: \((.*?)\) // ) { $service =~ s/^... .. ..:..:.. .+ PAM_unix\[\d+\]: \(([^ ]*)\) .*/$1/; # for Ubuntu 7.10 } elsif ( $line =~ s/^... .. ..:..:.. .+ \S+\[\d+\]: pam_unix_\S+\(.+:.+\): // ) { $service =~ s/^... .. ..:..:.. .+ \S+\[\d+\]: pam_unix_\S+\((.+):.+\): .*$/$1/; # for debian and others ? } elsif ($line =~ s/^... .. ..:..:.. \S+ \S+\[\d+\]: PAM //) { $service =~ s/^... .. ..:..:.. \S+ (\S+)\[\d+\]: PAM .*/$1/; } else { next; } # handle password expiring globally if ($line =~ /^password for user (.+) will expire in (\d+) days/) { $data{"all"}{'Password Expiring'}{"$1 in $2 days"}++; next; } # lowercase the service $service = lc($service); # Generic messages if (my ($user) = ($line =~ /^Access denied for user ([^:]+):/)) { $data{$service}{'Access denied'}{$user}++; next; } elsif ($line =~ s/^authentication success; logname=(\S*) uid=(\d+) .*user=(\S*)$/$1($2) -> $3/) { ($Detail >= 5) && $data{$service}{'Authentication Success'}{$line}++; next; } # Service specific messages if ( grep $_ eq $service, qw/ssh sshd login ftp vsftpd proftpd rsh remote rlogin rexec systemd-user/) { if ($line =~ s/^session opened for user (.+) by \(uid=\d+\)/$1/) { ($Detail >= 5) && $data{$service}{'Sessions Opened'}{$line}++; } elsif ($line =~ s/^session opened for user ([^ ]*) by ([^ ]*)\(uid=\d+\)/$1 by $2/) { ($Detail >= 5) && $data{$service}{'Sessions Opened'}{$line}++; } elsif ($line =~ s/^session opened for user (.+) by LOGIN\(uid=\d+\)/$1/) { $data{$service}{'Sessions Opened'}{$line}++; } elsif ($line =~ /session closed for user/) { } elsif ($line =~ /^service\(sshd\) ignoring max retries/) { # ignore these lines } elsif ($line =~ s/^authentication failure; .*rhost=(\S*)\s+user=(\S*)$/$2 ($1)/) { $data{$service}{'Authentication Failures'}{$line}++; } elsif ($line =~ s/^authentication failure; .*rhost=(\S*)\s*$/unknown ($1)/) { $data{$service}{'Authentication Failures'}{$line}++; } elsif ($line =~ s/^authentication failure; logname=(\S*) uid=(\d+) .*user=(\S*)$/$1($2) -> $3/) { $data{$service}{'Authentication Failures'}{$line}++; } elsif ($line =~ s/^authentication failure; logname=(\S*) .*rhost=(\S*)\s+user=(\S*)$/($3 or $1)($2): /) { $data{$service}{'Authentication Failures'}{$line}++; } elsif ($line =~ s/^(\d+) more authentication failures?; .*rhost=(\S*)\s+user=(\S*)$/$3 ($2)/) { $data{$service}{'Authentication Failures'}{$line} += $1; } elsif ($line =~ s/^(\d+) more authentication failures?; .*rhost=(\S*)\s*$/unknown ($2)/) { $data{$service}{'Authentication Failures'}{$line} += $1; } elsif ($line =~ /check pass; user unknown/) { $data{$service}{'Invalid Users'}{'Unknown Account'}++; } elsif ($line =~ s/^password changed for (.+)/$1(by sshd)/) { ($Detail >= 5) && $data{passwd}{'Password changed'}{$line}++; } elsif ($line =~ s/^account (.+) has expired \((?:failed to change password|account expired)\)$/$1/) { $data{$service}{'Expired Accounts'}{$line}++; } elsif ($line =~ s/bad username \[(.*)\]/$1/) { $data{$service}{'Invalid Users'}{"Bad User: $line"}++; } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif (grep $_ eq $service, qw/su sudo su-l polkit-1/) { if ( my ($logname, $uid, $ruser, $user) = ($line =~ /^authentication failure; logname=(\S*)\s+uid=(\d+) (?:.*ruser=(\S*)\s+)?.*user=(\S*)$/)) { $line = ($logname or $ruser)."($uid) -> $user"; $data{$service}{'Authentication Failures'}{$line}++; } elsif ($line =~ /session closed for user/) { # ignore this line } elsif ($line =~ /conversation failed/) { # ignore this line. An other line will describe the reason. } elsif (my ($nam, $byid) = ($line =~ /session opened for user (.+) by (.+)$/)) { # resolve uid to name if possible my $onam; if ($byid =~ s/^\(uid=(\d+)\)$/$1/) { $onam = getpwuid($byid) || $byid; } elsif ($byid =~ s/^(\S+)\(uid=\d+\)$/$1/) { $onam = $byid; } else { $onam = $byid; } $data{$service}{'Sessions Opened'}{"$onam -> $nam"}++; } elsif ($line =~ s/auth could not identify password for \[(.*)\]/$1/) { $data{$service}{'Not Identify Password For'}{$line}++; } elsif ($line =~ /^account root has password changed in future/) { #I'm not sure whether this info could not be reported } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif (grep $_ eq $service, qw/passwd propassd/) { if ($line =~ s/^password changed for (.+)/$1/) { ($Detail >= 5) && $data{$service}{'Password changed'}{$line}++; } } elsif (grep $_ eq $service, qw/gdm gdm-password gdm-smartcard gdm-welcome gdm-launch-environment kdm kcheckpass xdm imap dovecot cups/) { if ($line =~ s/^session opened for user (.+) by (?:\(unknown\)|\w+)?\(uid=\d+\)/$1/) { ($Detail >= 5) && $data{$service}{'Sessions Opened'}{$line}++; } elsif ($line =~ s/^authentication failure;.* user=(.+)$/$1/) { $data{$service}{'Authentication Failures'}{$line}++; } elsif ($line =~ s/^authentication failure;.* ruser=(.+) rhost=.+$/$1/) { $data{$service}{'Authentication Failures'}{$line}++; } elsif ($line =~ /check pass; user unknown/) { $data{$service}{'Invalid Users'}{'Unknown Account'}++; } elsif ($line =~ /session closed for user/) { # ignore this line } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif (grep $_ eq $service, qw/spop3d pop/) { if ($line =~ s/^session opened for user (.+)/$1/) { $data{$service}{'Sessions Opened'}{$line}++; } elsif ($line =~ /session closed for user/) { # ignore this line } elsif ($line =~ s/^authentication failure; .*user=(.+)$/$1/) { $data{$service}{'Authentication Failures'}{$line}++; } elsif ($line =~ s/^account (.+) has expired (failed to change password)$/$1/) { $data{$service}{'Expired Accounts'}{$line}++; } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif ($service eq 'tpop3d') { if ($line =~ s/^authentication failure; .*rhost=(.+) user=(.+)$/$2 ($1)/) { $data{$service}{'Authentication Failures'}{$line}++; } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif (grep $_ eq $service, qw/pure-ftpd vsftpd/) { if ($line =~ s/^session opened for user (.+)/$1/) { $data{$service}{'Sessions Opened'}{$line}++; } elsif ($line =~ s/^check pass; (.+)/$1/) { $data{$service}{'Password Failures'}{$line}++; } elsif ($line =~ s/^authentication failure; .*user=(.+)$/$1/) { $data{$service}{'Authentication Failures'}{$line}++; } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif (grep $_ eq $service, qw/xscreensaver gnome-screensaver kscreensaver cinnamon-screensaver/) { if ($line =~ s/^authentication failure; .*uid=(\d+) euid=(\d+) tty=(.+) ruser= rhost= user=(.+)$/$4($1,$2) on display $3/) { $data{$service}{'Authentication Failures'}{$line}++; } } elsif ($service =~ /^(?:\/[\w\/]+\/|f)?crond?$/ ) { if ($line =~ s/^session opened for user (.+) by \(uid=\d+\)/$1/) { ($Detail >= 5) && $data{$service}{'Sessions Opened'}{$line}++; } elsif ($line =~ /session closed for user/) { # ignore this line } elsif ($line =~ /^account root has password changed in future/) { #I'm not sure whether this info could not be reported } elsif ($line =~ /^adding faulty module: (.+)/) { $data{$service}{'Faulty modules'}{$1}++; } elsif ($line =~ /^unable to dlopen\(.+\): (.+)$/) { $data{$service}{'Unable to dlopen'}{$1}++; } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif ($service eq 'cyrus') { if ($line =~ /check pass; user unknown/) { $data{$service}{'Invalid Users'}{'Unknown Account'}++; } elsif ($line =~ /authentication failure; logname= uid=0 euid=0 tty= ruser= rhost=/) { # ignore this line } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif (grep $_ eq $service, qw/samba smbd/) { if ($line =~ s/^session opened for user (\S+) by (.+)/$1/) { ($Detail >= 5) && $data{$service}{'Sessions Opened'}{$line}++; } elsif ($line =~ s/^session closed for user (.+)/$1/) { ($Detail >= 8) && $data{$service}{'Sessions Closed'}{$line}++; } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif (grep $_ eq $service, qw/runuser runuser-l/) { if ($line =~/^session (opened)?(\/)?(closed)? for user [\w\.\-]+/) { } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif ($service eq 'atd') { if ($line =~/^session (opened)?(\/)?(closed)? for user [\w\.\-]+/) { } elsif ($line =~ /^account root has password changed in future/) { #I'm not sure whether this info could not be reported } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif ($service eq 'system-config-date') { if ($line =~ s/auth could not identify password for \[(.*)\]/$1/) { $data{$service}{'Not Identify Password For'}{$line}++; } else { $data{$service}{'Unknown Entries'}{$line}++; } } elsif ($service eq 'smtp') { if ($line =~ s/^authentication failure; logname=(\S*) uid=(\d+).*user=(\S*)$/$1($2) -> $3/) { $data{$service}{'Authentication Failures'}{$line}++; } elsif ($line =~ /authentication failure; logname= uid=0 euid=0 tty= ruser= rhost=/) { # ignore this line } elsif ($line =~ /check pass; user unknown/) { $data{$service}{'Invalid Users'}{'Unknown Account'}++; } else { $data{$service}{'Unknown Entries'}{$line}++; } } else { $data{$service}{'Unknown Entries'}{$line}++; } } foreach my $service (sort {$a cmp $b} keys %data) { print "$service:\n"; foreach my $type (sort {$a cmp $b} keys %{$data{$service}}) { print " $type:\n"; my $sort = CountOrder(%{$data{$service}{$type}}); foreach my $entry (sort $sort keys %{$data{$service}{$type}}) { print " $entry: $data{$service}{$type}{$entry} Time(s)\n"; } } 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: