#!/usr/bin/perl -w
##########################################################################
# $Id: sshd,v 1.11 2000/09/22 14:47:04 kirk Exp $
##########################################################################
# $Log: sshd,v $
# Revision 1.11  2000/09/22 14:47:04  kirk
# *** empty log message ***
#
# Revision 1.10  1999/01/23 18:10:55  kirk
# Prepping for Version 1.6.4
#
# Revision 1.9  1999/01/22 22:30:21  kirk
# Prepping for Version 1.6.1
#
# Revision 1.8  1999/01/22 22:22:04  kirk
# Prepping for Version 1.6
#
# Revision 1.7  1998/06/01 20:42:46  kirk
# Fixed bug found by Brian Aljian <brian@aljian.com>...
#
# Revision 1.6  1998/06/01 20:33:26  kirk
# Applied changes submitted by Bert de Bruijn <bob@ace.ulyssis.student.kuleuven.ac.be>...
#
# Revision 1.5  1998/03/19 03:12:54  kirk
# Fixed a few problems
#
# Revision 1.4  1998/02/26 08:47:17  kirk
# Added a fun 'fortune' module...
# Applied SSHD patch from Jonathan Stanton <jonathan@cs.jhu.edu>
#
# Revision 1.3  1998/02/23 01:17:00  kirk
# Getting ready for a first distribution
#
# Revision 1.2  1998/02/22 22:36:31  kirk
# Created named...
#
# Revision 1.1  1998/02/22 03:07:54  kirk
# Re-organization
#
# Revision 1.3  1998/02/12 06:07:22  kirk
# Fixed a few things...
#
# Revision 1.2  1998/02/12 02:23:24  kirk
# Finished the sshd filter...
#
# Revision 1.1  1998/01/25 04:07:48  kirk
# 'sshd' module started.
#
##########################################################################

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

$Debug = $ENV{'LOGWATCH_DEBUG'};
$Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'};

sub LookupIP {
   my ($name, $a1, $a2,$a3,$a4,$PackedAddr,$Addr);
   $Addr = $_[0];
   ($a1,$a2,$a3,$a4) = split /\./,$Addr;
   $PackedAddr = pack('C4',$a1,$a2,$a3,$a4);
   if ($name = gethostbyaddr ($PackedAddr,2)) {
      return ($name . " (" . $Addr . ")");
   } else {
      return ($Addr);
   }
}

# No sense in running if 'sshd' doesn't even exist on this system...
unless (( -f "/usr/sbin/sshd" ) or ( -f "/usr/local/sbin/sshd")) {
   exit (0);
}

if ( $Debug >= 5 ) {
   print STDERR "\n\nDEBUG: Inside SSHD Filter \n\n";
   $DebugCounter = 1;
}

$ThisLine = <STDIN>;
while (defined($ThisLine)) {
   if ( $Debug >= 5 ) {
      print STDERR "DEBUG: Line Number " . $DebugCounter . ":\n";
      print STDERR "DEBUG: " . $ThisLine;
   }
   $NeedNextLine = 1;
   if ( ($ThisLine =~ m/^(log: )?Connection from/ and   # ssh
            $ThisLine !~ m/not allowed/) or
         ($ThisLine =~ m/^Accepted \w+ for \S+ from ([\d.]+)/)) { #openssh
# Connected from host...
      $ThisLine =~ m/from ([\d.]+)/ and $ThisLine = $1; # ssh/openssh
         chomp($ThisLine);
      $ThisLine = LookupIP ($ThisLine);
      $ConnectFrom{$ThisLine}++;
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -Connection From- Line (" . $ThisLine . ") -- Reading another line\n";
         $DebugCounter++;
      }
      while (($NeedNextLine == 1) && (defined($NextLine = <STDIN>))) {
         if ( $Debug >= 5 ) {
            print STDERR "DEBUG: Line Number " . $DebugCounter . ":\n";
            print STDERR "DEBUG: " . $NextLine;
         }
         if ( $NextLine =~ s/^(log: )?RSA authentication for ([^ ]*) accepted\./$2/) { # ssh
            chomp($NextLine);
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -RSA Auth Accepted- line (" . $NextLine . ")\n";
            }
            $NextLine = "   " . $NextLine . " logged in from " . $ThisLine;
            $Users{$NextLine}++;;
         } elsif ($NextLine =~ /^Accepted (\S+) for (\S+) from ([\d\.]+) port (\d+)/) {  # OpenSSH
            if ($Debug >= 5) {
               print STDERR "DEBUG: Found -$2 logged in from $3 using $1\n";
            }
            $Users{$2}++;
            $NextLine = "   $2 logged in from $3 using $1";
         }
         elsif ( $NextLine =~ s/^(log: )?Rhosts with RSA host authentication accepted for ([^ ,]*), ([^ ]*) on (.*)\./$3 as ($2)/ ) {
            chomp($NextLine);
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Rhosts RSA host Auth Accepted- line (" . $NextLine . ")\n";
            }
            $NextLine = "   " . $NextLine . " logged in from " . $ThisLine;
            $Users{$NextLine}++;;
         }
         elsif ( $NextLine =~ s/^(log: )?Password authentication for ([^ ]*) accepted\./$2/ ) {
            chomp($NextLine);
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Password Auth Accepted- line (" . $NextLine . ")\n";
            }
            $NextLine = "   " . $NextLine . " logged in from " . $ThisLine;
            $Users{$NextLine}++;;
         }
         elsif ( $NextLine =~ s/^(log: )?Rhosts authentication refused for ([^ ]*) (.*)/$2 refused because: $3/ ) {
            chomp($NextLine);
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Rhosts Auth Refused- line (" . $NextLine . ")\n";
            }
            $NextLine = "   " . $NextLine . ".  Attempt from " . $ThisLine;
            $Users{$NextLine}++;;
         }
         elsif ( $NextLine =~ s/^(log: )?ROOT LOGIN as ([^ ]*) from ([^ ]*)/$2/ ) {
            chomp($NextLine);
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -ROOT LOGIN- line (" . $NextLine . ")\n";
            }
            $NextLine = "   " . $NextLine . " logged in as ROOT from " . $ThisLine;
            $Users{$NextLine}++;;
         }
         elsif ( $NextLine =~ s/^(log: )?executing remote command as (user)* ([^ ]*)/$3/ ) {
            chomp($NextLine);
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Remote Command Executed- line (" . $NextLine . ")\n";
            }
            $NextLine = "   " . $NextLine . " executed a command from " . $ThisLine;
            $Users{$NextLine}++;;
         }
         elsif ( $NextLine =~ s/^(log: )?executing remote command as root: (.*)/$2/ ) {
            chomp($NextLine);
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Remote Root Command Executed- line (" . $NextLine . ")\n";
            }
            $NextLine = "   " . "root executed: " . $NextLine . ", from " . $ThisLine;
            $Users{$NextLine}++;;
         }
         elsif ( $NextLine =~ m/^(log: )?Wrong response to RSA authentication challenge\./ ) { #ssh
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Did not receive ident- line\n";
            }
            push @BadRSA,$ThisLine;
         } elsif ( $NextLine =~ m/^Failed (\w+) for (\S+) from ([\d.]+) port (\d+)/ ) { #openssh
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Failed login- line\n";
            }
            $BadLogins{"$2/$1 from $3"}++;
         }
         elsif ( $NextLine =~ m/^(fatal: )?Did not receive ident string/ ) { # ssh/openssh
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Did not receive ident- line\n";
            }
            push @NoIdent,$ThisLine;
         }
         elsif ( $NextLine =~ m/Bad protocol version identification .*: ([\d.]+)/ ) { # ssh/openssh
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Did not receive ident- line\n";
            }
# not terribly useful, really
         } else {
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: No matches... keeping current line.\n";
            }
            $ThisLine = $NextLine;
            $NeedNextLine = 0;
         }
      }
   }
   elsif ( $ThisLine =~ m/^(log: )?Closing connection to/ or # ssh
         $ThisLine =~ m/^Connection closed by/) { # openssh
# Don't care about this...
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -Closing Connection- line\n";
      }
   }
   elsif ( $ThisLine =~ m/^connect from \d+\.\d+\.\d+\.\d+/ ) {
      # Ignore this
   }
   elsif ( $ThisLine =~ m/^fatal: Connection closed by remote host\./ ) {
      $NetworkErrors++;
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -Connection Closed by Remote Host- line\n";
      }
   }
   elsif ( $ThisLine =~ m/^fatal: Timeout before authentication/ ) { # ssh/openssh
# Don't care about this...
   }
   elsif ( $ThisLine =~ m/^fatal: Read error from remote host: Connection reset by peer/ ) {
      $NetworkErrors++;
   }
   elsif ( $ThisLine =~ m/^fatal: Write failed: Network is unreachable/ ) {
      $NetworkErrors++;
   } elsif ($ThisLine =~ m/^fatal: Read from socket failed: No route to host/) {
      $NetworkErrors++;
   } elsif ($ThisLine =~ m/^error: chan_shutdown_read failed for .+/) {
      $NetworkErrors++;
   } elsif ( $ThisLine =~ m/^Did not receive ident string/ ) { # ssh/openssh
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -Did not receive ident- line\n";
      }
      push @NoIdent,$ThisLine;
   } elsif ( $ThisLine =~ m/^(log: )?Received (signal 15|SIG...); (terminating|restarting)\./) { #ssh/openssh
      $Kills++;
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -Signal 15 Terminating- line\n";
      }
   } elsif ($ThisLine =~ m/^Disconnecting: Command terminated on signal \d+/) {
# openssh emits thse, but they're not kills, oddly.
   }
   elsif ( $ThisLine =~ m/^(log: )?Server listening on( [\d\.]+)? port \d+/ ) { #ssh/openssh
      $Starts++;
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -Listening on port 22- line\n";
      }
   }
   elsif ( $ThisLine =~ m/^(log: )?Generating .* \w+ key\./ ) { # ssh/openssh
# Don't care about this...
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -Generating RSA key- line\n";
      }
   } elsif ( $ThisLine =~ m/^packet_set_maxsize: /) {
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -packet_set_maxsize- line\n";
      }

   }
   elsif ( $ThisLine =~ m/^(log: )?\w+ key generation complete\./ ) { # ssh/openssh
# Don't care about this...
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -Keygen complete- line\n";
      }
   } elsif ( $ThisLine =~ m/^Failed (\w+) for (\S+) from ([\d.]+) 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";
      }
      $BadLogins{"$2/$1 from $3"}++;
   } elsif ( $ThisLine =~ m/^(log: )?Could not reverse map address/ ) { # ssh/openssh
      $ThisLine =~ s/^(log: )?Could not reverse map address (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\.$/$2/ ;
      chomp($ThisLine);
      if ( $Debug >= 5 ) {
         print STDERR "DEBUG: Found -Could Not Reverse Map- line (" . $ThisLine . ") -- Reading next line\n";
         $DebugCounter++;
      }
      push @NoRevMap,$ThisLine;
      if (defined($NextLine = <STDIN>)) {
         if ( $Debug >= 5 ) {
            print STDERR "DEBUG: Line Number " . $DebugCounter . ":\n";
            print STDERR "DEBUG: " . $NextLine;
         }
         if ( $NextLine =~ m/^fatal: Did not receive ident string\./ ) {
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: Found -Did not receive ident- line\n";
            }
            push @NoIdent,$ThisLine;
         }
         else {
            if ( $Debug >= 5 ) {
               print STDERR "DEBUG: No matches... keeping current line.\n";
            }
            $ThisLine = $NextLine;
            $NeedNextLine = 0;
         }
      }
   }
   else {
# Report any unmatched entries...
      unless ($ThisLine =~ /fwd X11 connect/) {
         push @OtherList,$ThisLine;
      }
   }
   if ($NeedNextLine == 1) {
      if ( $Debug >= 5 ) {
         $DebugCounter++;
      }
      $ThisLine = <STDIN>;
   }
}

if ( ( ($Detail >= 5) and (keys %ConnectFrom) ) or
      ( ($Detail >= 10) and (@NoRevMap) ) or
      ( ($Detail >= 10) and (@NoIdent) ) or
      ( keys %Users ) or
      ( @OtherList )
   ) {

   print "\n\n --------------------- SSHD Begin ------------------------ \n";

   if ($NetworkErrors) {
      print "\nNetwork Read Write Errors: " . $NetworkErrors . "\n";
   }
   if ($Kills) {
      print "\nSSHD Killed: " . $Kills . " Time(s)\n";
   }
   if ($Starts) {
      print "\nSSHD Started: " . $Starts . " Time(s)\n";
   }


   if ( ( $Detail >= 5 ) or (keys %ConnectFrom) ) {
      print "\nConnections:\n";
      foreach $ThisOne (keys %ConnectFrom) {
         print "   " . $ThisOne . ": " . $ConnectFrom{$ThisOne} . " Connection(s)\n";
      }
   }

   if ( $Detail >= 10 ) {
      if ($#NoRevMap >= 0) {
         print "\nCouldn't resolve these IPs:\n";
         foreach $ThisOne (@NoRevMap) {
            print "   " . $ThisOne . "\n";
         }
      }
      if ($#NoIdent >= 0) {
         print "\nDid not get an ident string from these:\n";
         foreach $ThisOne (@NoIdent) {
            print "   " . $ThisOne . "\n";
         }
      }
   }

   if ($#BadRSA >= 0) {
      print "\nReceived a bad response to RSA challenge from these:\n";
      foreach $ThisOne (@BadRSA) {
         print "   " . $ThisOne . "\n";
      }
   }

   if (keys %BadLogins) {
      print "\nFailed logins from these:\n";
      for (sort keys %BadLogins) {
         print "   $_: $BadLogins{$_} time(s)\n";
      }
   }

   if (keys %Users) {
      print "\nUsers logging in through sshd:\n";
      foreach $ThisOne (keys %Users) {
         print '   '.$ThisOne . ": " . $Users{$ThisOne} . " Times(s)\n";
      }
   }

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

   print "\n\n ---------------------- SSHD End ------------------------- \n\n";

}

exit(0);
