#!/usr/bin/perl
##########################################################################
# $Id: ftpd-messages,v 1.11 2002/03/28 05:00:00 kirk Exp $
##########################################################################
# $Log: ftpd-messages,v $
# Revision 1.11  2002/03/28 05:00:00  kirk
# - Implemented several bug fixes and patches that have been sent in
# - Fixed a possible root exploit using a race condition in /tmp
# - Fixed bugs 46371, 56191, 58578, 61202, 61829, 61831, 61832 from bugzilla.redhat.com
#
# Revision 1.10  2000/09/22 15:59:05  kirk
# Prepping for Version 2.0.1
#
# Revision 1.9  2000/09/22 14:19:06  kirk
# *** empty log message ***
#
# Revision 1.8  2000/09/22 14:47:04  kirk
# *** empty log message ***
#
# Revision 1.6  1999/02/23 01:24:31  kirk
# Improved LookupIP in named/secure.
# Applied ftp-messages patch from Simon Liddington <sjl96v@ecs.soton.ac.uk>.
#
# Revision 1.5  1999/01/23 18:10:55  kirk
# Prepping for Version 1.6.4
#
# Revision 1.4  1998/03/10 05:21:48  kirk
# Added support for refused logins and ignoring unmatched entries...
#
# Revision 1.3  1998/02/23 01:16:55  kirk
# Getting ready for a first distribution
#
# Revision 1.2  1998/02/22 20:55:02  kirk
# Finalized FTP filters...
#
# Revision 1.1  1998/02/22 20:02:34  kirk
# Finished PAM_pwdb, split ftpd into 2 filters...
#
##########################################################################

########################################################
# This was written and is maintained by:
#    Kirk Bauer <kirk@kaybee.org>
#
# Please send all comments, suggestions, bug reports,
#    etc, to kirk@kaybee.org.
#
########################################################

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

while (defined($ThisLine = <STDIN>)) {
   if ( ( $ThisLine =~ /FTP session closed$/ ) or
         ( $ThisLine =~ /^getpeername \(in.ftpd\): Transport endpoint is not connected$/ ) or
         ( $ThisLine =~ /^QUIT$/ ) or
         ( $ThisLine =~ /^[\w\.]+: connected: IDLE\s\[\d+\]: failed login from/ ) or
         ( $ThisLine =~ /^lost connection to / ) or
         ( $ThisLine =~ /^User .* timed out after .* seconds at .*$/ )   ) {
      # We don't care about these
   }				 
   elsif ( ($Host,$IP,$Email) = ( $ThisLine =~ /^ANONYMOUS FTP LOGIN FROM ([^ ]+) \[(.*)\], (.*)$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . "): " . $Email . " - ";
      $AnonLogins{$Temp}++;
   }
   elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /^FTP LOGIN FROM ([^ ]+) \[(.*)\], (.*)$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . "): " . $User . " - ";
      $UserLogins{$Temp}++;
   }
   elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /^FTP LOGIN REFUSED \(.+\) FROM ([^ ]+) \[(.*)\], (.*)$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . "): " . $User . " - ";
      $FailedLogins{$Temp}++;
   }
   elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /^REFUSED \(.+\) FROM ([^ ]+) \[(.*)\], (.*)$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . "): " . $User . " - ";
      $FailedLogins{$Temp}++;
   }
   elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /REFUSED .+ from ([^ ]+) \[(.*)\], (.*)$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . "): " . $User . " - ";
      $FailedLogins{$Temp}++;
   }
   elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /^failed login from ([^ ]+) \[(.*)\], (.*)$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . "): " . $User . " - ";
      $FailedLogins{$Temp}++;
   }
   elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /failed login from ([^ ]+) \[(.*)\]$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . ") - ";
      $FailedLogins{$Temp}++;
   }
   elsif ( ($IP,$Host) = ( $ThisLine =~ /^refused PORT ([0123456789.]+),[0123456789]+ from (.*)$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . ") - ";
      $RefusedPorts{$Temp}++;
   }
   elsif ( $ThisLine =~ /^exiting on signal 11: Segmentation fault$/ ) {
      $SegFault++;
   }
   elsif ( ($User,$Host,$IP,$File) = ( $ThisLine =~ /^([^ ]+) of ([^ ]*) \[(.*)\] deleted (.*)$/ ) ) {
      $Temp = "   " . $Host . " (" . $IP . "): " . $User . "\n";
      $Temp2 = "      " . $File . "\n";
      push @{$DeletedFiles{$Temp}}, $Temp2;
   }			 
   else {
# Report any unmatched entries...
      push @OtherList,$ThisLine;
   }
}

if ( 
      ( (keys %AnonLogins) and ($Detail >= 5 ) ) or
      ( (keys %FailedLogins) and ($Detail >= 5 ) ) or
      ( (keys %DeletedFiles) and ($Detail >= 10 ) ) or
      ( (keys %RefusedPorts) and ($Detail >= 5 ) ) or
      ( @OtherList ) or
      ( keys %UserLogins )
   ) {		

   print "\n\n --------------------- ftpd-messages Begin ------------------------ \n";

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

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

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

   if (keys %FailedLogins) {
      print "\nFailed FTP Logins:\n";
      foreach $ThisOne (keys %FailedLogins) {
         print $ThisOne . $FailedLogins{$ThisOne} . " Time(s)\n";
      }
   }

   if (keys %RefusedPorts) {
      print "\nRefused PORTs:\n";
      foreach $ThisOne (keys %RefusedPorts) {
         print $ThisOne . $RefusedPorts{$ThisOne} . " Time(s)\n";
      }
   }

   if ($SegFault > 0){
      print "\nexiting on signal 11: Segmentation fault: $SegFault Time(s)\n";
   }

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

   print "\n\n ---------------------- ftpd-messages End ------------------------- \n\n";

}

exit(0);



