From 014cd416c259897189ebabf471840e26ee873603 Mon Sep 17 00:00:00 2001 From: Erich Eckner Date: Sun, 1 Oct 2023 10:20:06 +0200 Subject: sshd: revert to arch default --- sshd | 484 ++++++++++++++++++++++++++++--------------------------------------- 1 file changed, 198 insertions(+), 286 deletions(-) diff --git a/sshd b/sshd index 47d32a2..c41be67 100644 --- a/sshd +++ b/sshd @@ -1,165 +1,11 @@ -########################################################################## -# $Id$ -########################################################################## -# $Log: sshd,v $ -# Revision 1.79 2011/01/05 10:49:03 stefan -# ignoring PAM 2 more authentication failures -# -# Revision 1.78 2010/05/10 10:49:03 stefan -# ignoring nasty PTR records -# -# Revision 1.77 2009/02/20 17:49:03 mike -# pam_winbind ignores from JT Moree -mgt -# -# Revision 1.76 2009/02/20 17:39:15 mike -# Added pam_chroot from Alan Brenner -mgt -# -# Revision 1.75 2008/05/12 21:44:26 mike -# One more Solaris 10 filter -mgt -# -# Revision 1.74 2008/05/12 21:35:19 mike -# Solaris 10 cleanups pam_unix_auth and -mgt -# -# Revision 1.73 2008/05/03 16:15:22 mike -# Added debug1 line from Fedora patch tree -mgt -# -# Revision 1.72 2008/03/24 23:31:27 kirk -# added copyright/license notice to each script -# -# Revision 1.71 2007/11/25 20:20:05 bjorn -# Modified regexp of AllowUsers to allow for host names. -# -# Revision 1.70 2007/11/25 20:02:57 bjorn -# Handling chmod, chown errors, by Ivana Varekova. -# -# Revision 1.69 2007/09/20 00:00:15 bjorn -# Corrected handling of invalid logins, by Dan Wallis. -# -# Revision 1.68 2007/07/14 14:21:22 mike -# Added chan_read_failed ignore -mgt -# -# Revision 1.67 2007/06/18 03:53:25 bjorn -# Counting of some "not allowed" statements, by Jesus de Santos García. -# -# Revision 1.66 2007/04/15 20:59:02 bjorn -# Added support for refused_connections_threshold, by JT Moree. -# -# -# Revision 1.65 2007/01/29 20:09:17 bjorn -# Improved filtering, by Ivana Varekova. -# -# Revision 1.64 2006/11/12 20:59:31 bjorn -# Additional 'illegal user' processing, by Ivana Varekova. -# -# Revision 1.63 2006/09/15 15:40:58 bjorn -# Additional filtering by Ivana Varekova. -# -# Revision 1.62 2006/07/28 17:44:04 bjorn -# Filtering postponed with publickey, by Markus Lude. -# -# Revision 1.61 2006/03/20 20:42:57 bjorn -# Additional filtering, by Ivana Varekova. -# -# Revision 1.60 2006/03/08 04:29:34 bjorn -# Filter pam_krb5 message, by Markus Lude. -# -# Revision 1.59 2006/01/20 22:31:04 bjorn -# Handle new pam_unix format, by Ivana Varekova. -# -# Revision 1.58 2005/12/01 04:13:47 bjorn -# Removed extraneous 'these' sprinkled in output. -# -# Revision 1.57 2005/11/24 16:47:09 bjorn -# Count unknowns, by David Baldwin. -# -# Revision 1.56 2005/11/22 18:38:30 bjorn -# Filtering additional pam messages, by Ivana Varekova. -# -# Revision 1.55 2005/11/16 19:56:51 bjorn -# Filtering forced-command-only string. -# -# Revision 1.54 2005/10/19 05:48:39 bjorn -# Added name/IP mismatch detection, and filtering redundant entries, by -# Gilles Detillieux -# -# Revision 1.53 2005/10/01 18:59:48 bjorn -# Corrected patch from rev. 1.51 -# -# Revision 1.52 2005/10/01 18:28:12 bjorn -# Modified to 'use strict', and added more filtering, by David Baldwin -# -# Revision 1.51 2005/09/29 15:06:55 bjorn -# Filtering failed bind on 0.0.0.0, by Ivana Varekova. -# -# Revision 1.50 2005/09/28 18:49:19 mike -# Ignore channel_lookup and server_input_channel_req from David Baldwin -mgt -# -# Revision 1.49 2005/09/28 18:28:52 mike -# Patch for no route read error -mgt -# -# Revision 1.48 2005/09/27 21:03:20 bjorn -# Allow filtering by host/network address -# -# Revision 1.47 2005/09/13 18:52:37 mike -# Patch from David Baldwin, ldap and key ignores, improved reset and timeout regex -mgt -# -# Revision 1.46 2005/08/31 23:19:38 bjorn -# LookupIP needs to be done after sorting by IP address, not before -# -# Revision 1.45 2005/07/21 05:56:59 bjorn -# Allow non-space chars for username -# -# Revision 1.44 2005/05/21 22:47:48 bjorn -# Provide summary per IP address, cleaned up "illegal" vs. "invalid" -# usage, removed duplicate code, all submitted by Gilles Detillieux -# -# Revision 1.43 2005/04/20 17:19:32 bjorn -# Remove pam_unix, for Debian -# -# Revision 1.42 2005/04/17 23:29:23 bjorn -# Reporting changes and pam filtering from Paweł Gołaszewski and Willi Mann -# -# Revision 1.41 2005/02/24 17:08:05 kirk -# Applying consolidated patches from Mike Tremaine -# -# Revision 1.9 2005/02/13 22:50:46 mgt -# patches from Pawel -mgt -# -# Revision 1.8 2005/02/13 21:26:13 mgt -# patches from Michael Weiser -mgt -# -# Revision 1.7 2005/02/13 21:03:40 mgt -# Patch from Jeffery ? -mgt -# -# Revision 1.6 2004/10/06 21:40:44 mgt -# Patches from Kenneth -mgt -# -# Revision 1.5 2004/07/29 19:33:29 mgt -# Chmod and removed perl call -mgt -# -# Revision 1.4 2004/07/27 00:23:07 mgt -# Suse 9.1 fix -mgt -# -# Revision 1.3 2004/07/10 01:54:36 mgt -# sync with kirk -mgt -# -# Revision 1.38 2004/06/23 15:01:17 kirk -# - Added more patches from blues@ds.pg.gda.pl -# -# Revision 1.37 2004/02/03 19:13:14 kirk -# More Solaris patches from Sean Boran -# -# Revision 1.36 2004/02/03 18:39:34 kirk -# Patches from [ISO-8859-2] Pawe? Go?aszewski" -# -# Revision 1.35 2004/02/03 03:52:20 kirk -# Added mailscanner filter and more Solaris support from Mike Tremaine -# -# Revision 1.34 2004/02/03 02:45:26 kirk -# Tons of patches, and new 'oidentd' and 'shaperd' filters from -# Pawe? Go?aszewski" -# -########################################################################## + +######################################################## +# 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 @@ -184,8 +30,28 @@ my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $IgnoreHost = $ENV{'sshd_ignore_host'} || ""; my $RefusedConnectionsThreshold = $ENV{'refused_connections_threshold'} || 0; +my $IllegalUsersThreshold = $ENV{'illegal_users_threshold'} || 0; +DoLookup( $ENV{'sshd_ip_lookup'} ); my $DebugCounter = 0; +#Init String Containers +my ( +$Action, $Address, $Addresses, +$BytesRead, $BytesWritten, $ClientVer, +$Code, $Dir, $EmptyUser, +$Error, $File, $FingerP, +$Flags, $From, $Host, +$IP, $IlegUser, $InvaUser, +$Key, $Line, $Method, +$Mode, $Modtime, $Offer, +$Option, $Perm, $Pom, +$Pom1, $Pom2, $Port, +$Prio, $Reason, $Received, +$Sent, $To, $User, +$Why, $realm, $user, +$hr, $min, $sec, +$conn, +); # No sense in running if 'sshd' doesn't even exist on this system... #unless (( -f "/usr/sbin/sshd" ) or ( -f "/usr/local/sbin/sshd") or ( -f "/usr/lib/ssh/sshd")) { # exit (0); @@ -193,7 +59,6 @@ my $DebugCounter = 0; my %Users = (); my %IllegalUsers = (); -my %PotentialIllegalUsers = (); my %TooManyFailures = (); my %NoIdent = (); my %BindFailed = (); @@ -246,10 +111,16 @@ my $sftpRequests = 0; my $NetworkErrors = 0; my $Kills = 0; my $Starts = 0; -my $NetworkErrors = 0; my $StatusNoSuchFile = 0; my $BytesSent = 0; my $BytesReceived = 0; +my $NoCipher = 0; +my $MaxStartupsThrottling = 0; +my $MaxStartupsDrops = 0; +my $MaxStartupsTime = 0; +my %MaxStartupsIPs = (); + +my $multiline = 0; if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside SSHD Filter \n\n"; @@ -262,8 +133,20 @@ while (defined(my $ThisLine = )) { $DebugCounter++; } chomp($ThisLine); + + if ( $multiline ) { + if ( ($Host) = ($ThisLine =~ /^banner exchange: Connection from ([^ ]+)(?: port \d+)?:/) ) { + $NegotiationFailed{$Reason}{$Host}{$Offer}++; + } elsif ( ($Host) = ($ThisLine =~ /^Connection reset by ([^ ]+)(?: port \d+)?/) ) { + $NegotiationFailed{$Reason}{$Host}{$Offer}++; + } + } + + $multiline = 0; + if ( ($ThisLine =~ /^pam_succeed_if: requirement "uid < 100" (not|was) met by user /) or + ($ThisLine =~ /^pam_succeed_if\(.*?\): requirement "uid >= 1000" (not|was) met by user /) or ($ThisLine =~ m/^(log: )?$/ ) or ($ThisLine =~ m/^(log: )?\^\[\[60G/ ) or ($ThisLine =~ m/^(log: )? succeeded$/ ) or @@ -292,6 +175,8 @@ while (defined(my $ThisLine = )) { # usually followed by a session opened for user ($ThisLine =~ m/^pam_krb5\[\d+\]: authentication succeeds for /) or ($ThisLine =~ m/^nss_ldap: reconnect/) or + ($ThisLine =~ /gkr-pam: gnome-keyring-daemon started properly/) or + ($ThisLine =~ /gkr-pam: unable to locate daemon control file/) or ($ThisLine =~ m/^pam_ldap: error trying to bind as user "[^"]+" \(Invalid credentials\)/) or ($ThisLine =~ m/^pam_ldap: ldap_starttls_s: Can't contact LDAP server/) or ($ThisLine =~ m/^pam_sss\(sshd:.*\)/) or @@ -305,6 +190,7 @@ while (defined(my $ThisLine = )) { ($ThisLine =~ /pam_winbind\(sshd:account\): user .* OK/) or ($ThisLine =~ /pam_systemd\(sshd:session\): Moving/) or ($ThisLine =~ /pam_systemd\(sshd:session\): .*: Connection reset by peer/) or + ($ThisLine =~ /userauth_finish: .*: Connection reset by peer/) or ($ThisLine =~ /PAM \d+ more authentication failures?;/) or ($ThisLine =~ /^PAM service\(sshd\) ignoring max retries;/) or ($ThisLine =~ /^Failed keyboard-interactive for from/ ) or @@ -314,19 +200,24 @@ while (defined(my $ThisLine = )) { ($ThisLine =~ /Starting session: (forced-command|subsystem|shell|command)/ ) or ($ThisLine =~ /Found matching \w+ key:/ ) or ($ThisLine =~ /User child is on pid \d/ ) or - ($ThisLine =~ /Nasty PTR record .* is set up for [\da-fA-F.:]+, ignoring/) or + ($ThisLine =~ /Nasty PTR record .* is set up for [\da-fA-F.:]+(?:%\S+)?, ignoring/) or ($ThisLine =~ /Exiting on signal / ) or - ($ThisLine =~ /Disconnected from [\da-fA-F.:]* port \d*/ ) or - ($ThisLine =~ /Disconnected from user \S+ [\da-fA-F.:]* port \d*/ ) or - ($ThisLine =~ /Disconnected from (authenticating|invalid) user \S+ [\da-fA-F.:]* port \d*/ ) or + ($ThisLine =~ /Disconnected from [\da-fA-F.:]*(?:%\S+)? port \d*/ ) or + ($ThisLine =~ /Disconnected from user \S+ [\da-fA-F.:]*(?:%\S+)? port \d*/ ) or + ($ThisLine =~ /Disconnected from (authenticating|invalid) user \S+ [\da-fA-F.:]*(?:%\S+)? port \d*/ ) or ($ThisLine =~ /Disconnecting( (authenticating|invalid) user .* port \d+)?: Too many authentication failures \[preauth\]/ ) or ($ThisLine =~ /Disconnecting( (authenticating|invalid) user .* port \d+)?: Change of username or service not allowed: .* \[preauth\]/ ) or ($ThisLine =~ /Failed to release session: Interrupted system call/) or ($ThisLine =~ /Close session: user /) or + #($ThisLine =~ /error: .*: banner line contains invalid characters/) or + #($ThisLine =~ /past MaxStartups/) or + #($ThisLine =~ /exited MaxStartups throttling/) or + # user already accounted for in other statement + ($ThisLine =~ /^input_userauth_request: (illegal|invalid) user (.*)(?: \[preauth\])?$/ ) or 0 # This line prevents blame shifting as lines are added above ) { # Ignore these - } elsif ( my ($Method,$User,$Host,$Port,$Key,$FingerP) = ($ThisLine =~ /^Accepted (\S+) for ((?:invalid user )?\S+) from ([\d\.:a-f]+)(?:%\w+)? port (\d+) ssh[12](?:: (\w+) (.+))?/) ) { + } elsif ( ($Method,$User,$Host,$Port,$Key,$FingerP) = ($ThisLine =~ /^Accepted (\S+) for ((?:invalid user )?\S+) from ([\d\.:a-f]+)(?:%\w+)? port (\d+) ssh[12](?:: (\w+) (.+))?/) ) { if ($Debug >= 5) { print STDERR "DEBUG: Found -$User logged in from $Host using $Method ($Key)\n"; } @@ -339,23 +230,24 @@ while (defined(my $ThisLine = )) { $Users{$User}{$Host}{"(all)"}++; } } - } elsif ( my ($Method, undef,$User,$Host,$Port) = ($ThisLine =~ m/^Failed (\S+) for (illegal|invalid) user (.*) from ([^ ]+) port (\d+)/ ) ) { #openssh + } elsif ( ($Method, undef,$User,$Host,$Port) = ($ThisLine =~ m/^Failed (\S+) for (illegal|invalid) user (.*) from ([^ ]+) port (\d+)/ ) ) { #openssh $IllegalUsers{$Host}{$User}++; - } elsif ( my ($User) = ( $ThisLine =~ /Disconnecting: Too many authentication failures for ([^ ]+)/)) { + } elsif ( ($User) = ( $ThisLine =~ /Disconnecting: Too many authentication failures for ([^ ]+)/)) { $TooManyFailures{$User}++; - } elsif ( my ($User) = ( $ThisLine =~ /error: maximum authentication attempts exceeded for ([^ ]+) from [^ ]+ port \d+ ssh2 \[preauth\]/)) { + } elsif ( ($User) = ( $ThisLine =~ /error: maximum authentication attempts exceeded for ([^ ]+) from [^ ]+ port \d+ ssh2 \[preauth\]/)) { $TooManyFailures{$User}++; - } elsif ( my ($User,$Host) = ( $ThisLine =~ /error: maximum authentication attempts exceeded for invalid user ([^ ]+) from ([^ ]+) port \d+ ssh2 \[preauth\]/)) { + } elsif ( ($User,$Host) = ( $ThisLine =~ /error: maximum authentication attempts exceeded for invalid user ([^ ]+) from ([^ ]+) port \d+ ssh2 \[preauth\]/)) { $IllegalUsers{$Host}{$User}++; } elsif ( $ThisLine =~ m/^(fatal: )?Did not receive ident(ification)? string from (\S+)/ ) { # ssh/openssh my $name = LookupIP($3); $NoIdent{$name}++; - } elsif ( my ($Host) = ($ThisLine =~ /Could not write ident string to ([^ ]+)$/ )) { + } elsif ( ($Host) = ($ThisLine =~ /Could not write ident string to ([^ ]+)$/ )) { my $name = LookupIP($Host); $NoIdent{$name}++; } elsif ( - ($ThisLine =~ m/^fatal: Connection closed by remote host\./ ) or + ($ThisLine =~ m/^(?:error:.*|fatal:) Connection closed by remote host/ ) or ($ThisLine =~ m/^(|fatal: )Read error from remote host(| [^ ]+): Connection reset by peer/ ) or + ($ThisLine =~ m/^error: .*: read: Connection reset by peer/ ) or ($ThisLine =~ m/^Read error from remote host [^ ]+: (Connection timed out|No route to host)/ ) or ($ThisLine =~ m/^fatal: Read from socket failed: No route to host/) or ($ThisLine =~ m/^fatal: Write failed: Network is unreachable/ ) or @@ -377,7 +269,7 @@ while (defined(my $ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Listening on port 22- line\n"; } - } elsif ( my ($Port,$Address,$Reason) = ($ThisLine =~ /^error: Bind to port ([^ ]+) on ([^ ]+) failed: (.+).$/ )) { + } elsif ( ($Port,$Address,$Reason) = ($ThisLine =~ /^error: Bind to port ([^ ]+) on ([^ ]+) failed: (.+).$/ )) { my $Temp = "$Address port $Port ($Reason)"; # Failed to bind on 0.0.0.0 likely due to configured "ListenAddress" # on both IPv4 and IPv6 @@ -398,7 +290,7 @@ while (defined(my $ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Keygen complete- line\n"; } - } elsif ( my ($Method,$User,$Host,undef) = ( $ThisLine =~ m/^Failed (\S+) for (\S+) from ([^ ]+) port (\d+)/ ) ) { #openssh + } elsif ( ($Method,$User,$Host,undef) = ( $ThisLine =~ m/^Failed (\S+) for (\S+) from ([^ ]+) port (\d+)/ ) ) { #openssh # depending on log mode, openssh may not report these in connection context. if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Failed login- line\n"; @@ -406,122 +298,135 @@ while (defined(my $ThisLine = )) { $BadLogins{$Host}{"$User/$Method"}++; } elsif ($ThisLine =~ s/^(log: )?Could not reverse map address ([^ ]*).*$/$2/) { $NoRevMap{$ThisLine}++; - } elsif ( my ($Address) = ($ThisLine =~ /^reverse mapping checking getaddrinfo for (\S+( \[\S+\])?) failed - POSSIBLE BREAK-IN ATTEMPT!/)) { + } elsif ( ($Address) = ($ThisLine =~ /^reverse mapping checking getaddrinfo for (\S+( \[\S+\])?) failed - POSSIBLE BREAK-IN ATTEMPT!/)) { $NoRevMap{$Address}++; - } elsif ( my ($IP,$Address) = ($ThisLine =~ /^Address ([^ ]*) maps to ([^ ]*), but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT!/)) { + } elsif ( ($IP,$Address) = ($ThisLine =~ /^Address ([^ ]*) maps to ([^ ]*), but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT!/)) { $NoRevMap{"$Address($IP)"}++; - } elsif ( my (undef,$Address) = ($ThisLine =~ /^warning: ([^ ]*), line \d+: can't verify hostname: getaddrinfo\(([^ ]*), AF_INET\) failed$/)) { + } elsif ( (undef,$Address) = ($ThisLine =~ /^warning: ([^ ]*), line \d+: can't verify hostname: getaddrinfo\(([^ ]*), AF_INET\) failed$/)) { $NoRevMap{$Address}++; - } elsif ( my (undef,$Addresses) = ($ThisLine =~ /^warning: ([^ ]*), line \d+: host [^ ]* mismatch: (.*)$/)) { + } elsif ( (undef,$Addresses) = ($ThisLine =~ /^warning: ([^ ]*), line \d+: host [^ ]* mismatch: (.*)$/)) { $MisMatch{$Addresses}++; } elsif ( $ThisLine =~ m/subsystem request for sftp/ ) { $sftpRequests++; } elsif ( $ThisLine =~ m/refused connect from (.*)$/ ) { $RefusedConnections{$1}++; - } elsif ( my ($Reason) = ($ThisLine =~ /^Authentication refused: (.*)$/ ) ) { + } elsif ( ($Reason) = ($ThisLine =~ /^Authentication refused: (.*)$/ ) ) { $RefusedAuthentication{$Reason}++; - } elsif ( my (undef,$Host,$Port,$Reason,$Offer) = ($ThisLine =~ /^(fatal: )?Unable to negotiate with ([^ ]+)( port \d+)?: (.*)\. Their offer: (.*) \[preauth\]$/) ) { + } elsif ( (undef,$Host,$Port,$Reason,$Offer) = ($ThisLine =~ /^(fatal: )?Unable to negotiate with ([^ ]+)( port \d+)?: (.*)\. Their offer: (.*) \[preauth\]$/) ) { $NegotiationFailed{$Reason}{$Host}{$Offer}++; - } elsif ( my ($Reason,$Host,$Offer) = ($ThisLine =~ /^(Protocol major versions differ) for ([^ ]+)(?: port \d+): (.*)$/) ) { + } elsif ( ($Reason,$Host,$Offer) = ($ThisLine =~ /^(Protocol major versions differ) for ([^ ]+)(?: port \d+)?: (.*)$/) ) { $NegotiationFailed{$Reason}{$Host}{$Offer}++; - } elsif ( my ($Prio,$Host,$Port,$Code,$Reason) = ($ThisLine =~ /^(error: )?Received disconnect from ([^ ]*)( port \d+)?: ?(\d+): (.*)$/)) { + } elsif ( ($Reason,$Offer) = ($ThisLine =~ /^error: (Protocol major versions differ): (.*)$/) ) { + $multiline++; + } elsif ( ($Reason,$Offer) = ($ThisLine =~ /^error: (kex_exchange_identification): (.*)$/) ) { + $multiline++; + } elsif ( ($Reason,$Offer) = ($ThisLine =~ /^error: (kex protocol error): (.*)$/) ) { + $multiline++; + } elsif ( ($Prio,$Host,$Port,$Code,$Reason) = ($ThisLine =~ /^(error: )?Received disconnect from ([^ ]*)( port \d+)?: ?(\d+): (.*)$/)) { # Reason 11 ({SSH,SSH2}_DISCONNECT_BY_APPLICATION) is expected, and logged at severity level INFO if (($Reason =~ /preauth/) || ($Code != 11) || ($Detail >= 30)) { $DisconnectReceived{$Reason}{$Host}++; } - } elsif ( my ($Host) = ($ThisLine =~ /^ROOT LOGIN REFUSED FROM ([^ ]*)$/)) { + } elsif ( ($Host) = ($ThisLine =~ /^ROOT LOGIN REFUSED FROM ([^ ]*)$/)) { $RootLogin{$Host}++; - } elsif ( my ($Error) = ($ThisLine =~ /^Cannot release PAM authentication\[\d\]: (.*)$/)) { + } elsif ( ($Error) = ($ThisLine =~ /^Cannot release PAM authentication\[\d\]: (.*)$/)) { $PamReleaseFail{$Error}++; - } elsif ( my ($Error) = ($ThisLine =~ /^pam_systemd\(sshd:session\): Failed to release session: (.*)$/)) { + } elsif ( ($Error) = ($ThisLine =~ /^pam_systemd\(sshd:session\): Failed to release session: (.*)$/)) { $PamReleaseFail{$Error}++; - } elsif ( my ($Error) = ( $ThisLine =~ m/^error: PAM: (.*)$/)) { + } elsif ( ($Error) = ( $ThisLine =~ m/^error: PAM: (.*)$/)) { $PamError{$Error}++; - } elsif ( my ($Error) = ( $ThisLine =~ m/pam_systemd\(sshd:session\): (Failed to create session: .*)$/)) { + } elsif ( ($Error) = ( $ThisLine =~ m/pam_systemd\(sshd:session\): (Failed to create session: .*)$/)) { $PamError{$Error}++; - } elsif ( my ($Reason) = ( $ThisLine =~ m/pam_chroot\(.+\):\s+([^:])/)) { + } elsif ( ($Reason) = ( $ThisLine =~ m/pam_chroot\(.+\):\s+([^:])/)) { $PamChroot{$Reason}++; - } elsif ( my ($Error) = ( $ThisLine =~ m/^error: Could not get shadow information for (.*)$/)) { + } elsif ( ($Error) = ( $ThisLine =~ m/^error: Could not get shadow information for (.*)$/)) { $ShadowInfo{$Error}++; - } elsif ( my ($Reason) = ($ThisLine =~ /^Setting tty modes failed: (.*)$/)) { + } elsif ( ($Reason) = ($ThisLine =~ /^Setting tty modes failed: (.*)$/)) { $TTYModesFail{$Reason}++; - } elsif ( my ($User,undef) = ($ThisLine =~ /^User ([^ ]*) not allowed because ([^ ]*) exists$/)) { + } elsif ( ($User,undef) = ($ThisLine =~ /^User ([^ ]*) not allowed because ([^ ]*) exists$/)) { $LoginLock{$User}++; - } elsif ( my ($Method,$InvaUser,$IlegUser,$EmptyUser,$User,$Host) = ($ThisLine =~ /^Postponed ([^ ]*) for ((invalid user) [^ ]*|(illegal user) [^ ]*|([^ ]*)) from ([^ ]*) port \d+ ssh/)) { + } elsif ( ($Method,$InvaUser,$IlegUser,$EmptyUser,$User,$Host) = ($ThisLine =~ /^Postponed ([^ ]*) for ((invalid user) [^ ]*|(illegal user) [^ ]*|([^ ]*)) from ([^ ]*) port \d+ ssh/)) { $PostPonedAuth{"$User/$Method"}{$Host}++; if ($IlegUser =~ /illegal user/) {$IllegalUsers{$Host}{$User}++;} - } elsif ( my ($User) = ($ThisLine =~ /^User ([^ ]*) not allowed because account is locked/)) { + } elsif ( ($User) = ($ThisLine =~ /^User ([^ ]*) not allowed because account is locked/)) { $LockedAccount{$User}++; - } elsif ( my ($User) = ($ThisLine =~ /^User ([^ ]*) from (?:[^ ]*) not allowed because not listed in AllowUsers/)) { + } elsif ( ($User) = ($ThisLine =~ /^User ([^ ]*) from (?:[^ ]*) not allowed because not listed in AllowUsers/)) { $AllowUsers{$User}++; - } elsif ( my ($User) = ($ThisLine =~ /^User ([^ ]*)( from [0-9.]*)? not allowed because listed in DenyUsers/)){ + } elsif ( ($User) = ($ThisLine =~ /^User ([^ ]*)( from [0-9.]*)? not allowed because listed in DenyUsers/)){ $DenyUsers{$User}++; - } elsif ( my ($User) = ($ThisLine =~ /^User ([^ ]*)( from [0-9.]*)? not allowed because not in any group/)) { + } elsif ( ($User) = ($ThisLine =~ /^User ([^ ]*)( from [0-9.]*)? not allowed because not in any group/)) { $NoGroups{$User}++; - } elsif ( my ($User) = ($ThisLine =~ /^User ([^ ]*)( from [^ ]*)? not allowed because a group is listed in DenyGroups/)) { + } elsif ( ($User) = ($ThisLine =~ /^User ([^ ]*)( from [^ ]*)? not allowed because a group is listed in DenyGroups/)) { $DenyGroups{$User}++; - } elsif ( my ($User) = ($ThisLine =~ /^User ([^ ]*) from ([^ ]*) not allowed because none of user's groups are listed in AllowGroups/)) { + } elsif ( ($User) = ($ThisLine =~ /^User ([^ ]*) from ([^ ]*) not allowed because none of user's groups are listed in AllowGroups/)) { $AllowGroups{$User}++; - } elsif ( my ($User) = ($ThisLine =~ /^User ([^ ]*) not allowed because shell (\S+) does not exist/)) { + } elsif ( ($User) = ($ThisLine =~ /^User ([^ ]*) not allowed because shell (\S+) does not exist/)) { $NoShellUsers{$User}++; - } elsif ( my ($User) = ($ThisLine =~ /^User ([^ ]*) not allowed because shell (\S+) is not executable/)) { + } elsif ( ($User) = ($ThisLine =~ /^User ([^ ]*) not allowed because shell (\S+) is not executable/)) { $ShellNotExecutableUsers{$User}++; - } elsif ( my ($User) = ($ThisLine =~ /^fatal: Access denied for user ([^ ]+) by PAM account configuration \[preauth\]/)) { + } elsif ( ($User) = ($ThisLine =~ /^fatal: Access denied for user ([^ ]+) by PAM account configuration \[preauth\]/)) { $PamDeny{$User}++; - } elsif ( my ($IP) = ($ThisLine =~ /^scanned from ([^ ]*)/) ) { + } elsif ( ($IP) = ($ThisLine =~ /^scanned from ([^ ]*)/) ) { push @Scanned, $IP; - } elsif ( my (undef,$Line,$Option) = ($ThisLine =~ /^re(xec|process config) line (\d+): Deprecated option (.*)$/)) { + } elsif ( (undef,$Line,$Option) = ($ThisLine =~ /^re(xec|process config) line (\d+): Deprecated option (.*)$/)) { $DeprecatedOption{"$Option - line $Line"}++; - } elsif ( my ($Pom1,$Pom2,$User) = ($ThisLine =~ /pam_krb5(\[\d*\])?: authentication fails for (`|')([^ ]*)'/)) { + } elsif ( ($Pom1,$Pom2,$User) = ($ThisLine =~ /pam_krb5(\[\d*\])?: authentication fails for (`|')([^ ]*)'/)) { $KrbAutFail{$User}++; - } elsif ( my ($Error) = ($ThisLine =~ /pam_krb5: authenticate error: (.*)$/)) { + } elsif ( ($Error) = ($ThisLine =~ /pam_krb5: authenticate error: (.*)$/)) { $KrbAutErr{$Error}++; } elsif ( ($ThisLine =~ /pam_krb5: unable to determine uid\/gid for user$/)) { $KrbAutErr{"unable to determine uid/gid for user"}++; - } elsif ( my ($Error) = ($ThisLine =~ /pam_krb5: error removing file (.*)$/)) { + } elsif ( ($Error) = ($ThisLine =~ /pam_krb5: error removing file (.*)$/)) { $KrbErr{"error removing file " . $Error}++; - } elsif ( my ($Pom,$Error) = ($ThisLine =~ /pam_krb5(\[\d*\]): error resolving user name '[^ ]*' to uid\/gid pai/)) { + } elsif ( ($Pom,$Error) = ($ThisLine =~ /pam_krb5(\[\d*\]): error resolving user name '[^ ]*' to uid\/gid pai/)) { $KrbErr{"error resolving user name '$Error' to uid\/gid pai"}++; - } elsif ( my (undef,$User,$Host) = ($ThisLine =~ m/^(Illegal|Invalid) user (.*) from ([^ ]+)/ )) { - $PotentialIllegalUsers{$Host}{$User}++; - } elsif ( my (undef,$User) = ($ThisLine =~ /^input_userauth_request: (illegal|invalid) user (.*)$/ )) { - if ($User =~ m/(.*) \[preauth\]/) { - $User = $1; + } elsif ( (undef,$User,$Host) = ($ThisLine =~ m/^(Illegal|Invalid) user (.*) from ([^ ]+)/ )) { + if ($User eq "") { + $User = "{undefined}"; } - $PotentialIllegalUsers{"undef"}{$User}++; - } elsif (my ($File,$Perm,$Why) = ($ThisLine =~ /error: chmod (.*) (.*) failed: (.*)/)) { + $IllegalUsers{$Host}{$User}++; + } elsif (($File,$Perm,$Why) = ($ThisLine =~ /error: chmod (.*) (.*) failed: (.*)/)) { $ChmodErr{"$File,$Perm,$Why"}++; - } elsif (my ($File,$From,$To,$Why) = ($ThisLine =~ /error: chown (.*) (.*) (.*) failed: (.*)/)) { + } elsif (($File,$From,$To,$Why) = ($ThisLine =~ /error: chown (.*) (.*) (.*) failed: (.*)/)) { $ChownErr{"$File,$From,$To,$Why"}++; - } elsif (my ($user,$realm) = ($ThisLine =~ /Authorized to ([^ ]+), krb5 principal \1@([^ ]+) \((?:krb5_kuserok|ssh_gssapi_krb5_cmdok)\)/)) { + } elsif (($user,$realm) = ($ThisLine =~ /Authorized to ([^ ]+), krb5 principal \1@([^ ]+) \((?:krb5_kuserok|ssh_gssapi_krb5_cmdok)\)/)) { $Krb_realm{$realm}{$user}++; - } elsif (my ($Action,$User) = ($ThisLine =~ /^session ((?:open|clos)ed) for local user (\S+) from /)) { + } elsif (($Action,$User) = ($ThisLine =~ /^session ((?:open|clos)ed) for local user (\S+) from /)) { $Session{"Action,$User"}++; } elsif ($ThisLine =~ /^sent status No such file$/) { $StatusNoSuchFile++; - } elsif (my ($File,$Flags,$Mode) = ($ThisLine =~ /^open "(.*)" flags (\S+) mode (\d+)/ )) { + } elsif (($File,$Flags,$Mode) = ($ThisLine =~ /^open "(.*)" flags (\S+) mode (\d+)/ )) { $OpenFile{"$File:$Flags:$Mode"}++; - } elsif (my ($File,$BytesRead,$BytesWritten) = ($ThisLine =~ /^close "(.*)" bytes read (\d+) written (\d+)/ )) { + } elsif (($File,$BytesRead,$BytesWritten) = ($ThisLine =~ /^close "(.*)" bytes read (\d+) written (\d+)/ )) { $CloseFileReadWrite{"$File,$BytesRead,$BytesWritten"}++; - } elsif (my ($Sent,$Received) = ($ThisLine =~ /^Transferred: sent (\d+), received (\d+) bytes$/ )) { + } elsif (($Sent,$Received) = ($ThisLine =~ /^Transferred: sent (\d+), received (\d+) bytes$/ )) { $BytesSent += $Sent; $BytesReceived += $Received; - } elsif (my ($File,$Modtime) = ($ThisLine =~ /^set "(.*)" modtime (\d+-\d+:\d+:\d+)$/ )) { + } elsif (($File,$Modtime) = ($ThisLine =~ /^set "(.*)" modtime (\d+-\d+:\d+:\d+)$/ )) { $SetModtime{"$Modtime,$File"}++; - } elsif (my ($Dir) = ($ThisLine =~ /^opendir "(.*)"$/ )) { + } elsif (($Dir) = ($ThisLine =~ /^opendir "(.*)"$/ )) { $OpenDir{$Dir}++; - } elsif (my ($Dir) = ($ThisLine =~ /^closedir "(.*)"$/ )) { + } elsif (($Dir) = ($ThisLine =~ /^closedir "(.*)"$/ )) { $CloseDir{$Dir}++; - } elsif (my ($File) = ($ThisLine =~ /^realpath "(.*)"$/ )) { + } elsif (($File) = ($ThisLine =~ /^realpath "(.*)"$/ )) { $RealPath{$File}++; - } elsif (my ($File) = ($ThisLine =~ /^stat name "(.*)"$/ )) { + } elsif (($File) = ($ThisLine =~ /^stat name "(.*)"$/ )) { $Stat{$File}++; - } elsif (my ($Dir) = ($ThisLine =~ /^Changed root directory to "(.*)"/ )) { + } elsif (($Dir) = ($ThisLine =~ /^Changed root directory to "(.*)"/ )) { $Chroot{$Dir}++; - } elsif (my ($ClientVer) = ($ThisLine =~ /^received client version (\S+)/ )) { + } elsif (($ClientVer) = ($ThisLine =~ /^received client version (\S+)/ )) { $ClientVers{$ClientVer}++; - } elsif (my ($Host,$Port) = ($ThisLine =~ /^error: connect_to (\S+) port (\d+): failed\.$/)) { + } elsif (($Host,$Port) = ($ThisLine =~ /^error: connect_to (\S+) port (\d+): failed\.$/)) { $ConnectFailed{"$Host port $Port"}++; + } elsif ($ThisLine =~ /^fatal: no matching cipher found: /) { + $NoCipher++; + } elsif ($ThisLine =~ /beginning MaxStartups throttling/) { + $MaxStartupsThrottling++; + } elsif (($IP) = ($ThisLine =~ /drop connection #\d+ from \[(\S+)\]:\d+ on \[\S+\]:\d+ past MaxStartups/)) { + $MaxStartupsIPs{$IP}++; + } elsif (($hr, $min, $sec, $conn) = ($ThisLine =~ /exited MaxStartups throttling after (\d\d):(\d\d):(\d\d), (\d+) connections dropped/)) { + $MaxStartupsTime += (((($hr * 60) + $min) * 60) + $sec); + $MaxStartupsDrops += $conn; } else { # Report any unmatched entries... unless ($ThisLine =~ /fwd X11 connect/) { @@ -532,26 +437,6 @@ while (defined(my $ThisLine = )) { ########################################################### -foreach my $Host (sort keys %PotentialIllegalUsers) { - foreach my $User (sort keys %{$PotentialIllegalUsers{$Host}}) { - my @user_hosts = grep { $PotentialIllegalUsers{$_}{$User} } keys %PotentialIllegalUsers; - - if ($Host eq "undef") { - if ((scalar @user_hosts) == 1 && $user_hosts[0] == "undef") { - # Report illegal user from "undef" only if there are no other hosts - # for the given user - $IllegalUsers{"undef"}{$User}++; - } - } - else { - while ($IllegalUsers{$Host}{$User} < $PotentialIllegalUsers{$Host}{$User}) { - $IllegalUsers{$Host}{$User}++; - } - } - } -} - -########################################################### sub timesplural { my ($count) = @_; @@ -587,7 +472,7 @@ if (keys %RootLogin) { if (keys %BindFailed) { print "\nFailed to bind:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %BindFailed) { - print " $ThisOne : " . timesplural($BindFailed{$ThisOne}); + print " $ThisOne : " . timesplural($BindFailed{$ThisOne}); } } @@ -595,7 +480,7 @@ if ($Detail >= 30 && keys %ConnectFailed) { # SSH Socks Forwarding print "\nFailed to connect to:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %ConnectFailed) { - print " $ThisOne : " . timesplural($ConnectFailed{$ThisOne}); + print " $ThisOne : " . timesplural($ConnectFailed{$ThisOne}); } } @@ -650,6 +535,10 @@ if (keys %NegotiationFailed) { } } +if ($NoCipher && $Detail > 0) { + print "\nNo matching cipher offered: " . timesplural($NoCipher); +} + if (keys %TooManyFailures) { print "\nDisconnecting after too many authentication failures for user:\n"; foreach my $User (sort {$a cmp $b} keys %TooManyFailures) { @@ -677,19 +566,25 @@ if (keys %BadLogins) { } if (keys %IllegalUsers) { - print "\nIllegal users from:\n"; + print "\nIllegal users from"; + if ($IllegalUsersThreshold) { + print " (with threshold >= $IllegalUsersThreshold)"; + } + print ":\n"; foreach my $ip (sort SortIP keys %IllegalUsers) { my $name = LookupIP($ip); my $totcount = 0; foreach my $user (keys %{$IllegalUsers{$ip}}) { $totcount += $IllegalUsers{$ip}{$user}; } - print " $name: " . timesplural($totcount); - if ($Detail >= 5) { - my $sort = CountOrder(%{$IllegalUsers{$ip}}); - foreach my $user (sort $sort keys %{$IllegalUsers{$ip}}) { - my $val = $IllegalUsers{$ip}{$user}; - print " $user: " . timesplural($val); + if ($IllegalUsersThreshold == 0 || $totcount >= $IllegalUsersThreshold) { + print " $name: " . timesplural($totcount); + if ($Detail >= 5) { + my $sort = CountOrder(%{$IllegalUsers{$ip}}); + foreach my $user (sort $sort keys %{$IllegalUsers{$ip}}) { + my $val = $IllegalUsers{$ip}{$user}; + print " $user: " . timesplural($val); + } } } } @@ -828,14 +723,14 @@ if (keys %RefusedAuthentication) { } if (keys %KrbAutFail) { - print "\n\Failed pam_krb5 authentication:\n"; + print "\n Failed pam_krb5 authentication:\n"; foreach my $User (sort keys %KrbAutFail) { print " $User: " . timesplural($KrbAutFail{$User}); } } if (keys %KrbAutErr) { - print "\n\pam_krb5 authentication errors:\n"; + print "\n pam_krb5 authentication errors:\n"; foreach my $Error (sort keys %KrbAutErr) { print " $Error: " . timesplural($KrbAutErr{$Error}); } @@ -857,9 +752,9 @@ if (keys %DisconnectReceived) { print " $Reason"; foreach my $Host (sort {$a cmp $b} keys %{$DisconnectReceived{$Reason}}) { $Total += $DisconnectReceived{$Reason}{$Host}; - if( $Detail > 0 ) { + if( $Detail > 0 ) { print "\n $Host : $DisconnectReceived{$Reason}{$Host} Time(s)"; - } + } } if( $Detail > 0 ) { print "\n"; @@ -880,7 +775,7 @@ if (keys %RefusedConnections) { my $output; foreach my $badguy (sort {$a cmp $b} keys %RefusedConnections ) { if ($RefusedConnectionsThreshold == 0 || $Detail > 5 || $RefusedConnections{$badguy} >= $RefusedConnectionsThreshold) { - $output .= " $badguy: " . timesplural($RefusedConnections{$badguy}); + $output .= " $badguy: " . timesplural($RefusedConnections{$badguy}); } } if ($output ne '') { @@ -889,6 +784,23 @@ if (keys %RefusedConnections) { } } +if ($MaxStartupsThrottling) { + print "\nMaxStartups throttling begins: " . timesplural($MaxStartupsThrottling); + if ($Detail >= 5) { + print " Dropped connections total: " . timesplural($MaxStartupsDrops); + my $hr = $MaxStartupsTime / 3600; + my $min = ($MaxStartupsTime / 60) % 60; + my $sec = $MaxStartupsTime % 60; + printf " Throttling time total: %02d:%02d:%02d\n", $hr, $min, $sec; + } + if ($Detail >= 10) { + print " Initial dropped IP:\n"; + foreach my $ThisOne (sort SortIP keys %MaxStartupsIPs) { + print " " . LookupIP($ThisOne) . " : " . timesplural($MaxStartupsIPs{$ThisOne}); + } + } +} + if (keys %PamReleaseFail) { print "\nCannot release PAM authentication:\n"; foreach my $Error (sort {$a cmp $b} keys %PamReleaseFail) { @@ -990,33 +902,33 @@ if ($sftpRequests > 0) { } if (keys %ChmodErr) { - print "\nChmod errors:\n"; - foreach (sort keys %ChmodErr) { - my ($File,$Perm,$Why)= split ","; - print " " . $File . " " . $Perm . " failed(" . $Why . "): " . timesplural($ChmodErr{"$File,$Perm,$Why"}); - } + print "\nChmod errors:\n"; + foreach (sort keys %ChmodErr) { + my ($File,$Perm,$Why)= split ","; + print " " . $File . " " . $Perm . " failed(" . $Why . "): " . timesplural($ChmodErr{"$File,$Perm,$Why"}); + } } if (keys %ChownErr) { - print "\nChown errors:\n"; - foreach (keys %ChownErr) { - my ($File,$From,$To,$Why)= split ","; - print " " . $File . " " . $From . " " .$To . " failed(" . $Why . "): " . timesplural($ChmodErr{"$File,$From,$To,$Why"}); - } + print "\nChown errors:\n"; + foreach (keys %ChownErr) { + my ($File,$From,$To,$Why)= split ","; + print " " . $File . " " . $From . " " .$To . " failed(" . $Why . "): " . timesplural($ChmodErr{"$File,$From,$To,$Why"}); + } } -if ( ($Detail == 7 && keys %Krb_realm > 1) || ($Detail > 8 && keys %Krb_realm) ){ - print "\nSuccessful Kerberos Authentication from ",(scalar keys %Krb_realm)," realm:\n"; - foreach my $realm (sort keys %Krb_realm) { - if($Detail > 9){ - print " ",$realm,":\n"; - foreach my $user(sort keys %{$Krb_realm{$realm}}){ - print " ",$user,": " . timesplural($Krb_realm{$realm}{$user}); +if ( ($Detail == 7 && keys %Krb_realm > 1) || ($Detail > 7 && keys %Krb_realm) ){ + print "\nSuccessful Kerberos Authentication from ",(scalar keys %Krb_realm)," realm:\n"; + foreach my $realm (sort keys %Krb_realm) { + if($Detail > 9){ + print " ",$realm,":\n"; + foreach my $user(sort keys %{$Krb_realm{$realm}}) { + print " ",$user,": " . timesplural($Krb_realm{$realm}{$user}); + } + } else { + print " ",$realm,": ". (scalar keys %{$Krb_realm{$realm}}) . " User(s)\n"; } - }else{ - print " ",$realm,": ". (scalar keys %{$Krb_realm{$realm}}) . " User(s)\n"; - } - } + } } if (keys %OtherList) { -- cgit v1.2.3-70-g09d2