#!/usr/bin/perl
##########################################################################
# $Id: samba,v 1.17 2003/12/15 22:03:55 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.
########################################################

$Debug = $ENV{'LOGWATCH_DEBUG'};
$Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
$SocketReadError=0;
$DbOpenFail=0;
$GetDomainMasterStatusFail=0;

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

while (defined($ThisLine = <STDIN>)) {
	chomp($ThisLine);
	if ( 
		($ThisLine =~ /Currently not implemented/) or
		($ThisLine =~ /version .+ started/) or
		($ThisLine =~ /oplock[_ ]break/) or
		($ThisLine =~ /No route to host/) or
		($ThisLine =~ /SIGTERM: going down/) or
		($ThisLine =~ /response packet id \d+ received with no matching record/) or
		($ThisLine =~ /matchname/i) or
		# Ignore entries in smbmount logfile
		($ThisLine =~ /smbmount/) or
		($ThisLine =~ /become_local_master/) or
		($ThisLine =~ /become_domain_master/) or
		($ThisLine =~ /add_domain_logon_names/) or
		($ThisLine =~ /become_logon_server/) or
		($ThisLine =~ /start_async_dns/) or
		($ThisLine =~ /timeout connecting to/) or
		($ThisLine =~ /Operation not permitted/) or
		($ThisLine =~ /Record does not exist/) or
		($ThisLine =~ /Connection reset by peer/) or
		($ThisLine =~ /Multiple .+ responses received for a query/) or
		($ThisLine =~ /Connection timed out/) or
		($ThisLine =~ /closed connection to/) or
		($ThisLine =~ /Got SIGHUP/) or
		($ThisLine =~ /current master browser/) or
		($ThisLine =~ /debug_message/) or
      ($ThisLine =~ /process_name_refresh_request\(184\)  Error - should be sent to WINS server$/) or
      ($ThisLine =~ /cli_connect\(783\)  Error connecting to [^ ]+ \(Operation already in progress\)$/) or
		($ThisLine =~ /===============================================================/)
	) {
		#Don't care about these...
	} elsif ( ($Host, $Service, $User) = ( $ThisLine =~ /([^ ]+ \([^ ]+\)) connect to service ([^ ]+) as user ([^ ]+)/ ) ) {
		$Connect{$Service}{$User}{$Host}++;
	} elsif ( ($NoService) = ( $ThisLine =~ /couldn't find service (\S+)/ ) ) {
		$NoServ{$NoService}++;
	} elsif ($ThisLine =~ s/Denied connection from\s+(\S+)$/$1/) {
		$Denied{$ThisLine}++;
   } elsif ($ThisLine =~ s/ Connection denied from\s+(\S+)$/$1/) {
      $Denied{$ThisLine}++;
   } elsif ( ($Where,$Ip,$Browser) = ($ThisLine =~ /(.*)  Denied connection from  \(([^ ]+)\)  Doing a node status request to the domain master browser at IP ([^ ]+) failed.  Cannot get workgroup name./ ) ) {
      $Temp = "$Where  ($Ip)";
      $Denied{$Temp}++;
      $CantGetGroup{$Browser}++;
   } elsif ( ($Where,$Ip,$Name,$Group,$Subnet) = ($ThisLine =~ /(.*)  Denied connection from  \(([^ ]+)\)  Samba name server ([^ ]+) is now a local master browser for workgroup ([^ ]+) on subnet ([^ ]+)/ ) ) {
      $Temp = "$Where  ($Ip)";
      $Denied{$Temp}++;
      $BeLocalMaster{$Subnet}{$Group}{$Name}++;
	} elsif (($User) = $ThisLine =~ /rejected invalid user ([^ ]+)/ ) {
		$InvalidUser{$User}++;
	} elsif (($User) = $ThisLine =~ /Couldn't find user '([^ ]+)'/) {
		$NotFoundUser{$User}++;
	} elsif (($User) = $ThisLine =~ /Rejecting user '([^ ]+)'/) {
		$RejectedUser{$User}++;
	} elsif ( ( $ThisLine =~ /^\[[^\]]+\] lib\/util_sock.c:read_data\(436\)/ ) ) {
		# This is due to a nasty bug in samba which causes it to drop connections :-(
		$SocketReadError++;
	} elsif ( ( $ThisLine =~ /unable to open passdb database.$/ ) ) {
		$DbOpenFail++;
	} elsif ( ($Server,$Ip,$Group) = ($ThisLine =~ /Server ([^ ]+) at IP ([^ ]+) is announcing itself as a local master browser for workgroup ([^ ]+) and we think we are master. Forcing election.$/ ) ) {
		$Temp = $Server . "(" . $Ip . ")";
		$ForceElection{$Group}{$Temp}++;
   } elsif ( (undef,$Command,$Server,$Ip,undef) = ($ThisLine =~ /([^ ]+): unicast name ([^ ]+) request received for name ([^ ]+) from IP ([^ ]+) on subnet (.*)\./ ) ) {     $Temp = "$Command on subnet $Subnet : $Server ($Ip)";
      $Temp = "$Command on subnet $Subnet : $Server ($Ip)";
      $UnicastRegister{$Temp}++;
	} elsif ( ($Group,$Subnet) = ($ThisLine =~ /standard_fail_register: Failed to register\/refresh name ([^ ]+) on subnet ([^ ]+)$/ ) ) {
		$FailedRegister{$Subnet}{$Group}++;
	} elsif ( ($Ip,$Group,undef) = ($ThisLine =~ /register_name_response: server at IP ([^ ]+) rejected our name registration of ([^ ]+) with error code ([^ ]+)\.$/ ) ) {
		$RejectRegister{$Group}{$Ip}++;
	} elsif ( ($Ip) = ($ThisLine =~ /get_domain_master_name_node_status_fail:  Doing a node status request to the domain master browser at IP ([^ ]+) failed\.  Cannot get workgroup name\.$/ ) ) {
		$CantGetGroup{$Ip}++;
	} elsif ( ($Signal,undef,$Version) = ($ThisLine =~ /INTERNAL ERROR: Signal ([^ ]+) in pid ([^ ]+) \(([^ ]+)\)  Please read the file BUGS.txt in the distribution$/ ) ) {
		$Temp = "Version $Version with signal $Signal";
		$Crash{$Temp}++;
	} elsif ( ( $ThisLine =~ /get_domain_master_name_node_status_fail\(([^ ]+)\)/ ) ) {
		$GetDomainMasterStatusFail++;
   } elsif ( ($User) = ($ThisLine =~ /pass_check_smb\(552\)  Account for user '([^ ]+)' was disabled.$/) ) {
      $AccountDisabled{$User}++;
   } elsif ( ($Version) = ($ThisLine =~ /Discarding invalid wins\.dat file \[(.*)\]$/) ) {
      $DiscardWins{$Version}++;
	} elsif ( ($user,$ip,$dir) = ($ThisLine =~ /smbd\/service.c:make_connection\([0-9]+\)  ([a-zA-Z]+) \(([\d.]+)\) Can't change directory to ([a-zA-Z_\/]+) \(Permission denied\)$/)) {
		$PermissionDenied{$user}{$ip}{$dir}++;
	} elsif ( ($user) = ($ThisLine =~ /smbd\/service.c:make_connection\([0-9]+\)  make_connection: ([a-zA-Z_-]+) logged in as admin user \(root privileges\)$/)) {
		$RootLoggedIn{$user}++;
	} elsif ( ($file,$function) = ($ThisLine =~ /([a-zA-Z_\/():\.0-9-]+)  ([a-zA-Z0-9_-]+): Not yet implemented.$/)) {
		$NotImplemented{$file}{$function}++;
	} else {
		# Report any unmatched entries...
		$OtherList{$ThisLine}++;

      #TODO:
      #lib/util_sock.c:get_socket_addr(1012)  getpeername failed. Error was Transport endpoint is not connected
      #lib/util_sock.c:send_smb(704)  Error writing 4 bytes to client. -1. (Broken pipe)
      #lib/util_sock.c:write_socket(524)  write_socket: Error writing 4 bytes to socket 5: ERRNO = Broken pipe
      #lib/util_sock.c:write_socket_data(499)  write_socket_data: write failure. Error = Broken pipe
      #lib/util_sock.c:read_data(436)  read_data: read failure for 4. Error = Brak drogi do systemu
	}
}

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

if (keys %Crash) {
	print "\nWARNING!!!!!!\n";
	print "Server crashed:\n";
	foreach $Dead (sort {$a cmp $b} keys %Crash) {
		print "   $Dead : $Crash{$Dead} Time(s)\n";
	}
}

if (keys %DiscardWins) {
   print "\nDiscarded invalid wins.dat file with version:\n";
   foreach $Version (sort {$a cmp $b} keys %DiscardWins) {
      print "   $Version : $DiscardWins{$Version} Time(s)\n";
   }
}

if (($Detail >= 5) and (keys %Connect)) {
   print "\nOpened Sessions:\n";
   foreach $Serv (sort {$a cmp $b} keys %Connect) {
      print "   Service $Serv as user:\n";
      foreach $Us (sort {$a cmp $b} keys %{$Connect{$Serv}}) {
         print "      $Us from host:\n";
         foreach $Ho (sort {$a cmp $b} keys %{$Connect{$Serv}{$Us}}) {
            print "         $Ho : $Connect{$Serv}{$Us}{$Ho} Time(s)\n";
         }
      }
   }
}

if (keys %Denied) {
   print "\nConnections Denied:\n";
   foreach $Line (sort {$a cmp $b} keys %Denied) {
      print "   $Line : $Denied{$Line} Time(s)\n";
   }
}

if (($Detail >= 5) and (keys %PermissionDenied)) {
   print "\nPermission denied:\n";
   foreach $user (sort {$a cmp $b} keys %PermissionDenied) {
      foreach $ip (sort {$a cmp $b} keys %{$PermissionDenied{$user}}) {
         foreach $dir (sort {$a cmp $b} keys %{$PermissionDenied{$user}{$ip}}) {
	    print "   Permission denied (user $user from $ip) directory $dir: $PermissionDenied{$user}{$ip}{$dir} Time(s)\n";
         }
      }
   }
}

if (($Detail >= 5) and (keys %RootLoggedIn)) {
   print "\nAdmin logins (root privileges):\n";
   foreach $user (sort {$a cmp $b} keys %RootLoggedIn) {
      print "   User $user: $RootLoggedIn{$user} Time(s)\n";
   }
}

if (($Detail >= 9) and (keys %NotImplemented)) {
   print "\nNot implemented functions:\n";
   foreach $file (sort {$a cmp $b} keys %NotImplemented) {
      foreach $func (sort {$a cmp $b} keys %{$NotImplemented{$file}}) {
          print "   Function $func in $file: $NotImplemented{$file}{$func} Time(s)\n";
      }
   }
}
     

if (keys %Denied) {
   print "\nConnections Denied:\n";
   foreach $Line (sort {$a cmp $b} keys %Denied) {
      print "   $Line : $Denied{$Line} Time(s)\n";
   }
}

if (keys %ForceElection) {
	print "\nForced Election:\n";
	foreach $Group (sort {$a cmp $b} keys %ForceElection) {
		print "   In workgroup $Group when announced server was:\n";
		foreach $Host (sort {$a cmp $b} keys %{$ForceElection{$Group}}) {
			print "      $Host : $ForceElection{$Group}{$Host} Time(s)\n";
		}
	}
}

if (keys %BeLocalMaster) {
	print "\nChanged Local Master Browser:\n";
	foreach $Subnet (sort {$a cmp $b} keys %BeLocalMaster) {
		print "   On subnet $Subnet:\n";
		foreach $Group (sort {$a cmp $b} keys %{$BeLocalMaster{$Subnet}}) {
			print "      For workgroup $Group:\n";
			foreach $Name (sort {$a cmp $b} keys %{$BeLocalMaster{$Subnet}{$Group}}) {
				print "         $Name : $BeLocalMaster{$Subnet}{$Group}{$Name} Time(s)\n";
			}
		}
	}
}

if (keys %CantGetGroup) {
	print "\nCannot get workgroup name from domain name browser:\n";
	foreach $Ip (sort {$a cmp $b} keys %CantGetGroup) {
		print "   $Ip : $CantGetGroup{$Ip} Time(s)\n";
	}
}

if ($GetDomainMasterStatusFail > 0) {
	print "\nFailed to get Domain Master node name: $GetDomainMasterStatusFail Time(s)\n";
}

if (($Detail >= 5) and (keys %NoServ)) {
   print "\nCouldn't find services:\n";
   foreach $ThisOne (sort {$a cmp $b} keys %NoServ) {
      print "   $ThisOne : $NoServ{$ThisOne} Time(s)\n";
   }
}

if (($Detail >= 5) and (keys %UnicastRegister)) {
	print "\nUnicast name requests:\n";
	foreach $ThisOne (sort {$a cmp $b} keys %UnicastRegister) {
		print "   $ThisOne : $UnicastRegister{$ThisOne} Time(s)\n";
	}
}

if (keys %FailedRegister) {
	print "\nFailed to register/refresh:\n";
	foreach $Subnet (sort {$a cmp $b} keys %FailedRegister) {
		print "   On subnet $Subnet:\n";
		foreach $Group (sort {$a cmp $b} keys %{$FailedRegister{$Subnet}}) {
			print "      $Group : $FailedRegister{$Subnet}{$Group} Time(s)\n";
		}
	}
}

if (keys %RejectRegister) {
	print "\nRejected our name registration:\n";
	foreach $Group (sort {$a cmp $b} keys %RejectRegister) {
		print "   Name $Group at IP:\n";
		foreach $Ip (sort {$a cmp $b} keys %{$RejectRegister{$Group}}) {
			print "      $Ip : $RejectRegister{$Group}{$Ip} Time(s)\n";
		}
	}
}

if ($DbOpenFail > 0) {
	print "\nFailed to open passwd database: $DbOpenFail Time(s)\n";
}

if (keys %InvalidUser) {
   print "\nInvalid Users:\n";
   foreach $Line (sort {$a cmp $b} keys %InvalidUser) {
      print "   $Line : $InvalidUser{$Line} Time(s)\n";
   }
}

if (keys %NotFoundUser) {
   print "\nUsers not found in UNIX Database:\n";
   foreach $Line (sort {$a cmp $b} keys %NotFoundUser) {
      print "   $Line : $NotFoundUser{$Line} Time(s)\n";
   }
}

if (keys %RejectedUser) {
   print "\nRejected Users:\n";
   foreach $Line (sort {$a cmp $b} keys %RejectedUser) {
      print "   $Line : $RejectedUser{$Line} Time(s)\n";
   }
}

if (keys %AccountDisabled) {
    print "\nAccounts disabled:\n";
    foreach $User (sort {$a cmp $b} keys %AccountDisabled) {
        print "   $User : $AccountDisabled{$User} Time(s)\n";
    }
}

if ($SocketReadError > 0) {
	print "\nSocket Read Error (Samba bug): $SocketReadError Time(s)\n";
}

if (keys %OtherList) {
	print "\n**Unmatched Entries**\n";
	foreach $Line (sort {$a cmp $b} keys %OtherList) {
		print "$Line : $OtherList{$Line} Time(s)\n";
	}
}

exit(0);

# vi: shiftwidth=3 tabstop=3 et
