##########################################################################
# $Id: proftpd-messages 164 2013-08-19 10:22:38Z stefjakobs $
##########################################################################
# $Log: proftpd-messages,v $
# Revision 1.27  2008/06/30 23:07:51  kirk
# fixed copyright holders for files where I know who they should be
#
# Revision 1.26  2008/05/13 22:52:02  mike
# Fix for debian bug 480761 -mgt
#
# Revision 1.25  2008/03/24 23:31:26  kirk
# added copyright/license notice to each script
#
# Revision 1.24  2007/03/25 15:43:12  mike
# Fixed BadShell bug, wrong hash name -mgt
#
# Revision 1.23  2007/03/25 15:31:40  mike
# Added error and notice line reports, ignored chroot info -mgt
#
# Revision 1.22  2007/03/20 18:02:02  mike
# More cleanups for both log formats, added secure log group and filtered plain no such user -mgt
#
# Revision 1.21  2007/03/16 21:10:12  mike
# Some matching cleanups before the real work -mgt
#
# Revision 1.20  2005/12/30 18:40:30  bjorn
# Filtering "masquerading" statements, and corrected bug submission string,
# per B Wooster.
#
# Revision 1.19  2005/02/24 17:08:05  kirk
# Applying consolidated patches from Mike Tremaine
#
# Revision 1.6  2005/02/13 22:50:46  mgt
# patches from Pawel -mgt
#
# Revision 1.5  2005/02/13 20:28:42  mgt
# More init corrections -mgt
#
# Revision 1.4  2004/07/29 19:33:29  mgt
# Chmod and removed perl call -mgt
#
# Revision 1.3  2004/07/10 01:54:35  mgt
# sync with kirk -mgt
#
# Revision 1.16  2004/02/03 02:45:26  kirk
# Tons of patches, and new 'oidentd' and 'shaperd' filters from
# Pawe? Go?aszewski" <blues@ds.pg.gda.pl>
#
########################################################
# This was written by Simon Liddington for use with Logwatch
#
# Please send all comments, suggestions, bug reports,
#    etc, to logwatch-devel@lists.sourceforge.net
########################################################

#######################################################
## Copyright (c) 2008 Simon Liddington
## 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.
#########################################################

$Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
$IgnoreUnmatched = $ENV{'ftpd_ignore_unmatched'};

$NoEndpoints = 0;
$UnmatchedEntries = 0;

while (defined($ThisLine = <STDIN>)) {
   if (
         ( $ThisLine =~ /^FTP session closed/ ) or
         ( $ThisLine =~ /^(ANONYMOUS )?FTP login as \'.*\' from [^ ]+ \[.*\] to .*/ ) or
         ( $ThisLine =~ /(PAM|pam_unix)\(.*\): [Aa]uthentication failure/ ) or
         ( $ThisLine =~ /(PAM|pam_unix)\(.*\): session (opened|closed) for user/ ) or
         ( $ThisLine =~ /^data_sendfile/ ) or
         ( $ThisLine =~ /(:| \-) FTP session (closed|opened)/ ) or
         ( $ThisLine =~ /(:| \-) No certificate files found/ ) or
         ( $ThisLine =~ /FTP (no transfer|session idle) timeout, disconnected/ ) or
         ( $ThisLine =~ / masquerading as / ) or
         ( $ThisLine =~ /mod_delay\// ) or
         ( $ThisLine =~ /FTP login timed out, disconnected/ ) or
         ( $ThisLine =~ /Preparing to chroot to directory/ ) or
         ( $ThisLine =~ /\(.*\[.*\]\)(\:| \-) no such user '.*'/ )
      ) {
         #We don't care about these
   } elsif ( ($Host,$IP,$Email,) = ( $ThisLine =~ /^FTP session opened: ftp\/ftp (.*)\[(.*)\] (.*)$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . "): " . $Email . " - ";
      $AnonLogins{$Temp}++;
   } elsif ( ($Host, $IP) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) ANON .+: Login successful\./ ) ) {
      $Temp = "   " . $Host . " (" . $IP . ")";
      $AnonLogins{$Temp}++;
   } elsif ( ($User,$Host,$IP) = ( $ThisLine =~ /^FTP session opened: (.*\/.*) (.*)\[(.*)\] (.*)$/ ) ) {
      $Temp = "   $Host : $User - ";
      $UserLogins{$Temp}++;
   } elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) USER (.+): Login successful/ ) ) {
      $Temp = "   " . $Host . ": " . $User . " - ";
      $UserLogins{$Temp}++;
   } elsif ( ($User) = ( $ThisLine =~ /^failed login, can\'t find user \'(.*)\' $/ ) ) {
      $Temp = "   " . "Unknown" . " (" . "Unknown.IP" . "): " . $User . " - ";
      $BadUsers{$Temp}++;
   } elsif ( ($User,$Host,$IP) = ( $ThisLine =~ /USER (.*): no such user found from (.*) \[(.*)\] to/ ) ) {
      #$Temp = "   $Host : $User - ";
      #$BadUsers{$Temp}++;
      $BadUsers{$User}{$Host}++;
#   } elsif ( ($Host,$Ip,$User) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) no such user '(.*)'/ ) ) {
#      #$Temp = "$Host($Ip)";
#      $BadUsers{$User}{$Host}++;
   } elsif ( ($Host,$User) = ( $ThisLine =~ /\[(.*)\]\)(?:\:| \-) USER (.*) \(Login failed\): Incorrect password/ ) ) {
      $Temp = "   $Host : $User - ";
      $BadPasswds{$Temp}++;
   } elsif ( ($Host,$User) = ( $ThisLine =~ /\[(.*)\]\)(?:\:| \-) USER (.*) \(Login failed\): Invalid shell/ ) ) {
      $Temp = "   $Host : $User - ";
      $BadShell{$Temp}++;
   } elsif ( ($Host,$Ip) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) SECURITY VIOLATION: root login attempted/ ) ) {
      $RootLoginAttempt{$Host}++;
   } elsif ( ($Host) = ( $ThisLine =~ /\(((.*)\[(.*)\])\)(?:\:| \-) Maximum login attempts .*exceeded/ ) ) {
      $MaxLoginAttempts{$Host}++;
   } elsif ( ($Host,$Reason) = ( $ThisLine =~ /\[(.*)\]\)(?:\:| \-) Refused PORT [\d,]+ \((.*)\)/ ) ) {
      $Temp = "   " . $Host . ": " . $Reason . " - ";
      $RefusedPorts{$Temp}++;
   } elsif ( ($Host,$Reason) = ( $ThisLine =~ /\(((.*)\[(.*)\])\)(?:\:| \-) Connection refused \((.*)\)/ ) ) {
      $ConnectionRefused{$Reason}{$Host}++;
   } elsif ( ($Host) = ( $ThisLine =~ /\(((.*)\[(.*)\])\)(?:\:| \-) Data transfer stall timeout/ ) ) {
      $TransferTimeout{$Host}++;
   } elsif ( $ThisLine =~ m/[^ ]*(?:\:| \-) Fatal: Transport endpoint is not connected/ ) {
      $NoEndpoints++;
   } elsif ( ($Option) = ( $ThisLine =~ /warning: (.*) is deprecated/ ) ) {
      $DeprecatedOptions{$Option}++;
   } elsif ( ($Host,$IP,$Error) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) error: (.*)$/ ) ) {
      $ErrorLines{$Host}{$Error}++;
   } elsif ( ($Host,$IP,$Notice) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) notice: (.*)$/ ) ) {
      $NoticeLines{$Host}{$Notice}++;
   } else {
      # Report any unmatched entries...
      push @OtherList,$ThisLine;
   }
}

##############################################

if (keys %DeprecatedOptions) {
   print "\nDeprecated options in config:\n";
   foreach $Option (sort {$a cmp $b} keys %DeprecatedOptions) {
      print "   $Option\n";
   }
}

if ( (keys %AnonLogins) and ($Detail >= 5) ) {
   print "\nAnonymous FTP Logins:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %AnonLogins) {
      print $ThisOne . $AnonLogins{$ThisOne} . " Time(s)\n";
   }
}

if ( (keys %DeletedFiles) and ($Detail >= 10) ) {
   print "\nFiles deleted through FTP:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %DeletedFiles) {
      print $ThisOne;
      print @{$DeletedFiles{$ThisOne}};
   }
}

if (keys %UserLogins) {
   print "\nUser FTP Logins:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %UserLogins) {
      print $ThisOne . $UserLogins{$ThisOne} . " Time(s)\n";
   }
}

if (keys %RootLoginAttempt) {
   print "\nSECURITY VIOLATION!!!!\n";
   print "Root login attempt from:\n";
   foreach $Host (sort {$a cmp $b} keys %RootLoginAttempt) {
      print "  $Host : $RootLoginAttempt{$Host} Time(s)\n";
   }
}

if (keys %MaxLoginAttempts) {
   print "\nMaximum login attempts exceeded from hosts:\n";
   foreach $Host (sort {$a cmp $b} keys %MaxLoginAttempts) {
      print "  $Host : $MaxLoginAttempts{$Host} Time(s)\n";
   }
}

if (keys %ConnectionRefused) {
   print "\nConnection refused with reason:\n";
   foreach $Reason (sort {$a cmp $b} keys %ConnectionRefused) {
      print "  $Reason :\n";
      foreach $Host (sort {$a cmp $b} keys %{$ConnectionRefused{$Reason}}) {
         print "      $Host : $ConnectionRefused{$Reason}{$Host} Time(s)\n";
      }
   }
}

if ( ( (keys %BadUsers) or (keys %BadPasswds) ) and ($Detail >= 5) ) {
   print "\nFailed FTP Logins:\n";
   if ( (keys %BadUsers) and ($Detail >= 5) ) {
      print "\n  Invalid Username:\n";
      foreach $User (sort {$a cmp $b} keys %BadUsers) {
         print "    $User:\n";
         foreach $Host (sort {$a cmp $b} keys %{$BadUsers{$User}}) {
            print "      $Host : $BadUsers{$User}{$Host} Time(s)\n";
         }
      }
   }

   if ( (keys %BadPasswds) and ($Detail >= 5) ) {
      print "\n  Incorrect Password:\n";
      foreach $ThisOne (sort {$a cmp $b} keys %BadPasswds) {
         print $ThisOne . $BadPasswds{$ThisOne} . " Time(s)\n";
      }
   }

   if ( (keys %BadShell) and ($Detail >= 5) ) {
      print "\n  Invalid Shell:\n";
      foreach $ThisOne (sort {$a cmp $b} keys %BadShell) {
         print $ThisOne . $BadShell{$ThisOne} . " Time(s)\n";
      }
   }
}

if ( (keys %RefusedPorts) and ($Detail >= 5) ) {
   print "\nRefused PORTs:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %RefusedPorts) {
      print $ThisOne . $RefusedPorts{$ThisOne} . " Time(s)\n";
   }
}

if ( (keys %TransferTimeout) and ($Detail >= 5) ) {
   print "\nData transfer stall timeout:\n";
   foreach $Host (sort {$a cmp $b} keys %TransferTimeout) {
      print "   $Host : $TransferTimeout{$Host} Time(s)\n";
   }
}

if ( (keys %NoticeLines) and ($Detail >= 10) ) {
   print "\nNotices Reported by Host:\n";
   foreach $Host (sort {$a cmp $b} keys %NoticeLines) {
      print "    $Host:\n";
         foreach $Notice (sort {$a cmp $b} keys %{$NoticeLines{$Host}}) {
            print "      $Notices : $NoticeLines{$Host}{$Notice} Time(s)\n";
         }
      }
}

if ( (keys %ErrorLines) and ($Detail >= 5) ) {
   print "\nErrors Reported by Host:\n";
   foreach $Host (sort {$a cmp $b} keys %ErrorLines) {
      print "    $Host:\n";
         foreach $Errors (sort {$a cmp $b} keys %{$ErrorLines{$Host}}) {
            print "      $Errors : $ErrorLines{$Host}{$Errors} Time(s)\n";
         }
      }
}

if ($NoEndpoints > 0) {
   print "\nTransport endpoint is not connected error $NoEndpoints Time(s)\n";
}

if (($#OtherList >= 0) and (not $IgnoreUnmatched)) {
   print "\n**Unmatched Entries**\n";
   print @OtherList;
}

exit(0);

# vi: shiftwidth=3 tabstop=3 syntax=perl et
# Local Variables:
# mode: perl
# perl-indent-level: 3
# indent-tabs-mode: nil
# End:
