#!/usr/bin/perl
##########################################################################
# $Id: secure,v 1.44 2004/02/03 04:26:36 kirk Exp $
##########################################################################
# $Log: secure,v $
# Revision 1.44  2004/02/03 04:26:36  kirk
# Solaris patch from Mike Tremaine <mgt@stellarcore.net>
#
# Revision 1.43  2004/02/03 03:55:28  kirk
# Patch from M. B. Heath <malcolm@indeterminate.net>
#
# Revision 1.42  2004/02/03 03:52:20  kirk
# Added mailscanner filter and more Solaris support from Mike Tremaine <mgt@stellarcore.net>
#
# Revision 1.41  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 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'} || 0;
$DoLookup = $ENV{'secure_ip_lookup'};
$Ignore = $ENV{'ignore_services'};
$Summarize = $ENV{'summarize_connections'};
$ConsoleLock = 0;
use Logwatch ':ip';

while (defined($ThisLine = <STDIN>)) {
   chomp($ThisLine);
   $ThisLine =~ s/^... .. ..:..:.. [^ ]+ //;
   #Solaris ID filter -mgt
   $ThisLine =~ s/\[ID [0-9]+ [a-z]+\.[a-z]+\] //;
   my $temp = $ThisLine;
   $temp =~ s/^([^[]+).*/$1/;
   if ($Ignore =~ /\b\Q$temp\E\b/i) { next; }
   if (
      ( $ThisLine =~ m/^[^ ]+\[\d+\]: connect from localhost$/ ) or
      ( $ThisLine =~ /^\/usr\/bin\/sudo:/) or
      ( $ThisLine =~ /^sudo:/) or
      ( $ThisLine =~ /^halt:/) or
      ( $ThisLine =~ /^reboot:/) or
      ( $ThisLine =~ /^passwd\[\d+\]:/) or
      ( $ThisLine =~ /warning: can.t get client address: Connection refused/) or
      ( $ThisLine =~ /^xinetd\[\d+\]: USERID: ([^ ]+) (.+)$/ ) or
      ( $ThisLine =~ /^(xinetd|xinetd-ipv6)\[\d+\]: EXIT: ([^ ]+) pid=\d+/)
   ) {
      # Ignore these entries
   } elsif ( ($Host,$User) = ($ThisLine =~ /^login: FAILED LOGIN \d+ FROM ([^ ]+) FOR ([^,]+),/ ) ) {
      $FailedLogins->{$User}->{$Host}++;
   } elsif ( ($Service,$IP) = ($ThisLine =~ /^([^ ]+)\[\d+\]: connect(ion)? from "?(\d+\.\d+\.\d+\.\d+).*/) ) {
      $Name = LookupIP($IP);
      if ($Summarize =~ /\Q$Service\E/) { 
         $Connections->{$Service}++;
      } else {
         $Connections->{$Service}->{$Name}++;
      }
   } elsif ( ($Service,$IP) = ($ThisLine =~ /^([^ ]+)\[\d+\]: refused connect from (\d+\.\d+\.\d+\.\d+)$/) ) {
      $Name = LookupIP($IP);
      $Refused->{$Service}->{$Name}++;
   } elsif ( ($Service,$Name) = ($ThisLine =~ /^([^ ]+)\[\d+\]: refused connect from (.*)$/) ) {
      $Refused->{$Service}->{$Name}++;
   } elsif ( ($Service,$Name) = ($ThisLine =~ /^([^ ]+)\[\d+\]: connect from ([^\n]+)$/) ) {
      if ($Summarize =~ /\Q$Service\E/) { 
         $Connections->{$Service}++;
      } else {
         $Connections->{$Service}->{$Name}++;
      }
   } elsif ( (undef, $Service, $IP) = ($ThisLine =~ /^(xinetd|xinetd-ipv6)\[\d+\]: START: ([^ ]+) pid=\d+ from=((<no address>)|([^ \n]+)) ?$/) ) {
      if ($Ignore =~ /\b\Q$Service\E\b/i) { next; }
      if ($Summarize =~ /\Q$Service\E/) { 
         $Connections->{$Service}++;
      } else {
         $Name = LookupIP($IP);
         $Connections->{$Service}->{$Name}++;
      }
   #Solaris inetd this works if you start "inetd -s -t" then send daemon.notice to authlog -mgt
   } elsif ( ($Service, $IP) = ($ThisLine =~ /^inetd\[\d+\]: (\w+)\[\d+\] from ([^ \n]+) \d+$/) ) {
      if ($Ignore =~ /\b\Q$Service\E\b/i) { next; }
      if ($Summarize =~ /\Q$Service\E/) {
         $Connections->{$Service}++;
      } else {
         $Name = LookupIP($IP);
         $Connections->{$Service}->{$Name}++;
      }
   } elsif ( ($Display, $User) = ($ThisLine =~ /^xscreensaver\[\d+\]: FAILED LOGIN \d ON DISPLAY \"([^ ]+)\", FOR \"([^ ]+)\"$/) ) {
      $FailedSaver{$User}{$Display}++;
   } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: warning: can\'t get client address: No route to host$/$1/ ) {
      $NoIP->{$ThisLine}++;
   } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: warning: can\'t get client address: Network is unreachable$/$1/ ) {
      $NoIP->{$ThisLine}++;
   } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: warning: can\'t get client address: Connection reset by peer$/$1/ ) {
      $NoIP->{$ThisLine}++;
   } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: warning: can\'t get client address: Connection timed out$/$1/ ) {
      $NoIP->{$ThisLine}++;
   } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: connect from unknown$/$1/ ) {
      $NoIP->{$ThisLine}++;
   } elsif ( ($Service,$Err) = ($ThisLine =~ /^([^ ]+)\[\d+\]: error: (.+)$/) ) {
      $Error{$Service}{$Err}++;
   } elsif ( ($Service,$Err) = ($ThisLine =~ /^([^ ]+): (FAILED LOGIN SESSION FROM [^ ]+ FOR , .*)$/ ) ) {
      $Error{$Service}{$Err}++;
   } elsif ( ($Service,$Err) = ($ThisLine =~ /^([^ ]+): (password mismatch for [^ ]+ in [^ ]+):.*$/ ) ) {
      $Error{$Service}{$Err}++;
   } elsif ( $ThisLine =~ /^login: ROOT LOGIN/) {
      $RootLoginTTY++
   } elsif ( (undef,$User) = ($ThisLine =~ /^login: LOGIN ON (tty|pts\/)[0-9]+ BY ([^ ]+)/ )) {
      $UserLogin{$User}++;
   } elsif ( $ThisLine =~ s/^userdel\[\d+\]: delete user `(.+)'/$1/ ) {
      push @DeletedUsers, "   $ThisLine\n";
   } elsif ( $ThisLine =~ s/^(useradd|adduser)\[\d+\]: new user: name=(.+), uid=(\d+).*$/$1 ($2)/ ) {
      push @NewUsers, "   $ThisLine\n";
   } elsif ( $ThisLine =~ s/^userdel\[\d+\]: remove group `(.+)'/$1/ ) {
      push @DeletedGroups, "   $ThisLine\n";
   } elsif ( $ThisLine =~ s/^groupdel\[\d+\]: remove group `(.+)'/$1/ ) {
      push @DeletedGroups, "   $ThisLine\n";
   } elsif ( $ThisLine =~ s/^(useradd|adduser)\[\d+\]: new group: name=(.+), gid=(\d+).*$/$1 ($2)/ ) {
      push @NewGroups, "   $ThisLine\n";
   } elsif ( ($User,$Group) =~ /useradd\[\d+\]: add `([^ ]+)' to group `([^ ]+)'$/ ) {
      $AddToGroup{$Group}{$User}++;
   } elsif ( $ThisLine =~ s/^groupadd\[\d+\]: new group: name=(.+), gid=(\d+).*$/$1 ($2)/ ) {
      push @NewGroups, "   $ThisLine\n";
   } elsif ( $ThisLine =~ /^userdel\[\d+\]: delete `(.*)' from (shadow|group) `(.*)'\s*$/ ) {
      push @RemoveFromGroup, "    user $1 from group $3\n";
      # This is an inetd lookup... $1 is the service (i.e. ftp), $2 is the response
      # I don't think these are important to log at this time
   } elsif ( $ThisLine =~ /^sudo: ([^\s]+) : (command not allowed)?.+ ; COMMAND=(.*)$/ ) {
      # sudo unauthorized commands
      push @SudoList, "$1: $3\n" unless ($2 eq "");
   } elsif ( $ThisLine =~ /^\/usr\/bin\/sudo: ([^\s]+) : (command not allowed)?.+ ; COMMAND=(.*)$/ ) {
      # sudo unauthorized commands
      push @SudoList, "$1: $3\n" unless ($2 eq "");
   } elsif ( ($service, $from) = ($ThisLine =~ /^xinetd\[\d+\]: FAIL: (.+) (?:address|libwrap) from=([\d.]+)/)) {
      if ($Ignore =~ /\b\Q$service\E\b/i) { next; }    
      $Refused->{$service}->{$from}++;
   } elsif ( ($User) = ($ThisLine =~ /^chage\[\d+\]: changed password expiry for ([^ ]+)/)) {
      $PasswordExpiry{$User}++;
   } elsif ( (undef) = ($ThisLine =~ /^pam_console\[\d+\]: console file lock already in place ([^ ]+)/)) {
      $ConsoleLock++;
   } else {
      # Unmatched entries...
      push @OtherList, "$ThisLine\n";
   }
}

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

if (@NewUsers) {
   print "\nNew Users:\n@NewUsers\n";
}

if (@DeletedUsers) {
   print "\nDeleted Users:\n@DeletedUsers\n";
}

if (@NewGroups) {
   print "\nNew Groups:\n@NewGroups\n";
}

if (@DeletedGroups) {
   print "\nDeleted Groups:\n@DeletedUsers\n";
}

if (keys %AddToGroup) {
   print "\nAdded User to group:\n";
   foreach $Group (sort {$a cmp $b} keys %AddToGroup) {
      print "   Group $Group:\n";
      foreach $User (sort {$a cmp $b} keys %{$AddToGroup{$User}}) {
         print "      $User\n";
      }
   }
}

if (@RemoveFromGroup) {
   print "\nRemoved From Group:\n@RemoveFromGroup\n";
}

if (keys %{$Connections}) {
   print "\nConnections:\n";
   foreach $ThisOne (keys %{$Connections}) {
      if ($Summarize =~ /\Q$ThisOne\E/) { 
         print "   Service " . $ThisOne . ": " . $Connections->{$ThisOne} . " Connection(s)\n";
      } else {
         print "   Service " . $ThisOne . ":\n";
         foreach $OtherOne (sort SortIP keys %{$Connections->{$ThisOne}}) {
            print "      " . $OtherOne . ": " . $Connections->{$ThisOne}->{$OtherOne} . " Time(s)\n";
         }
      }
   }
}

if (keys %{$Refused}) {
   print "\nRefused Connections:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %{$Refused}) {
      print "   Service " . $ThisOne . ":\n";
      foreach $OtherOne (sort SortIP keys %{$Refused->{$ThisOne}}) {
         print "      " . $OtherOne . ": " . $Refused->{$ThisOne}->{$OtherOne} . " Time(s)\n";
      }
   }
}

if (keys %{$FailedLogins}) {
   print "\nFailed logins:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %{$FailedLogins}) {
      print "   User " . $ThisOne . ":\n";
      foreach $OtherOne (sort {$a cmp $b} keys %{$FailedLogins->{$ThisOne}}) {
         print "      " . $OtherOne . ": " . $FailedLogins->{$ThisOne}->{$OtherOne} . " Time(s)\n";
      }
   }
}

if (keys %{$FailedSaver}) {
   print "\nFailed screensaver disable:\n";
   foreach $User (sort {$a cmp $b} keys %{$FailedSaver}) {
      print "   User $User on displays:\n";
      foreach $Display (sort {$a cmp $b} keys %{$FailedSaver{$User}}) {
         print "      $Display : $FailedSaver{$User}{$Display} Time(s)\n";
      }
   }
}

if (keys %{$NoIP}) {
   print "\nCouldn't get client IPs for connections to:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %{$NoIP}) {
      print "   $ThisOne: $NoIP{$ThisOne} Time(s)\n";
   }
}

if (keys %Error) {
   print "\nErrors:\n";
   foreach $Service (sort {$a cmp $b} keys %Error) {
      print "   Service $Service:\n";
      foreach $Err (sort {$a cmp $b} keys %{$Error{$Service}}) {
         print "      $Err: $Error{$Service}{$Err} Time(s)\n";
      }
   }
}

if ($RootLoginTTY) {
   print "\nRoot logins on tty\'s: $RootLoginTTY Time(s).\n";
}

if (keys %UserLogin) {
   print "\nUser Login's:\n";
   foreach $User (sort {$a cmp $b} keys %UserLogin) {
      print "   $User : $UserLogin{$User} Time(s)\n";
   }
}

if ($ConsoleLock > 0) {
   print "\nConsole file lock already in place: $ConsoleLock Time(s).\n";
}

if (keys %PasswordExpiry) {
   print "\nChanged password expiry for users:\n";
   foreach $User (sort {$a cmp $b} keys %PasswordExpiry) {
      print "   $User : $PasswordExpiry{$User} Time(s)\n";
   }
}

if ($#SudoList >= 0) {
   print "\nUnauthorized sudo commands attempted (" . ($#SudoList + 1) . "):\n";
   print @SudoList;
}

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

exit(0);

# vi: shiftwidth=3 tabstop=3 et

