#!/usr/bin/perl
##########################################################################
# $Id: secure,v 1.38 2003/11/26 14:36:30 kirk Exp $
##########################################################################

########################################################
# 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'};

use Logwatch ':ip';

while (defined($ThisLine = <STDIN>)) {
	chomp($ThisLine);
	$ThisLine =~ s/^... .. ..:..:.. [^ ]+ //;
	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 =~ /^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 ($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 ( $ThisLine =~ /^login: ROOT LOGIN ON tty[0-9]+/) {
      $RootLoginTTY++
   } 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.]+)/)) {
	  $Refused->{$service}->{$from}++;
  } 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 (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 (keys %{$FailedLogins}) {
      print "   User " . $ThisOne . ":\n";
      foreach $OtherOne (keys %{$FailedLogins->{$ThisOne}}) {
         print "      " . $OtherOne . ": " . $FailedLogins->{$ThisOne}->{$OtherOne} . " Time(s)\n";
      }
   }
}

if (keys %{$FailedSaver}) {
	print "\nFailed screensaver disable:\n";
	foreach $ThisOne (keys %{$FailedSaver}) {
		print "   User " . $ThisOne . " on displays:\n";
		foreach $OtherOne (keys %{$FailedSaver>{$ThisOne}}) {
			# Why it does not work?
			print "      " . $FailedLogins->{$ThisOne}->{$OtherOne} . " Time(s)\n";
		}
	}
}

if (keys %{$NoIP}) {
   print "\nCouldn't get client IPs for connections to:\n";
   foreach $ThisOne (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 ($#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=4 tabstop=4
