#!/usr/bin/perl ########################################################################## # $Id: imapd,v 1.1 2004/06/21 14:59:05 kirk Exp $ ########################################################################## ######################################################## # Logwatch was written and is maintained by: # Kirk Bauer # # The imap script was written by: # Paweł Gołaszewski # # Updated to work with Courier-IMAP 4.1.0+ by: # Brian Ghidinelli # ######################################################## use Socket; my $Debug = $ENV{'LOGWATCH_DEBUG'}; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; my $DoHostLookup = $ENV{'courier_ip_lookup'}; #Make pseudo IPv6 to IPv4 sub LookupIPv46 { my $IPv4Addr; my $Addr = $_[0]; if ( ($IPv4Addr) = ($Addr =~ /::ffff:([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/ ) ) { # print "$IPv4Addr\n"; return $IPv4Addr; } else { # print $Addr; return $Addr; } } 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 ($DoLookup) { if ($name = gethostbyaddr ($PackedAddr,2)) { return ($name . " (" . $Addr . ")"); } else { return ($Addr); } } else { return ($Addr); } } if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG \n\n"; } while (defined($ThisLine = )) { chomp($ThisLine); if ( ($ThisLine =~ /^Initializing */) or ($ThisLine =~ /^spgetpwnam: can't find user: */) ) { # Don't care about these... } elsif ( ($User, $Host) = ( $ThisLine =~ /^LOGIN, user=(.*?), ip=\[::ffff:(.*)\], protocol=IMAP$/ ) ) { $Login{$User}{$Host}++; $Login2{$User}++; } elsif ( ($User,$Host) = ( $ThisLine =~ /^DISCONNECTED, user=(.*?), ip=\[::ffff:(.*?)\]/ ) ) { $Disconnects{$User}{$Host}++; } elsif ( ($Host) = ( $ThisLine =~ /^Connection, ip=\[::ffff:(.*)\]$/ ) ) { $Connection{$Host}++; } elsif ( ($User, $Host) = ( $ThisLine =~ /^LOGOUT, user=(.*?), ip=\[::ffff:(.*)\]/) ) { $Logout{$User}{$Host}++; $Logout2{$User}++; } elsif ( ($User, $Host) = ( $ThisLine =~ /^TIMEOUT, user=(.*?), ip=\[::ffff:(.*)\]/ ) ) { $Timeout{$User}{$Host}++; } elsif ( ($User,$Host) = ( $ThisLine =~ /^Autologout user=(.*) host=(.* \[.*\])$/ ) ) { $AutoLogout{$User}{$Host}++; $Logout{$User}{$Host}++; $Logout2{$User}++; } elsif ( ($Reason,$User,$Host) = ( $ThisLine =~ /^Killed (.*) user=(.*) host=(.* \[.*\])$/ ) ) { $Logout{$User}{$Host}++; $Logout2{$User}++; $KilledSession{$User}{$Reason}++; } elsif ( (($User,$Host) = ( $ThisLine =~ /^Broken pipe, while reading line user=(.*) host=(.* \[.*\])$/ )) or (($User,$Host) = ( $ThisLine =~ /^Command stream end of file, while reading line user=(.*) host=(.* \[.*\])$/ )) or (($User,$Host) = ( $ThisLine =~ /^Connection reset by peer, while reading line user=(.*) host=(.* \[.*\])$/ )) ) { $SocketErrors{$Host}++; } else { # Report any unmatched entries... # remove PID from named messages $ThisLine =~ s/^(client [.0-9]+)\S+/$1/; $OtherList{$ThisLine}++; } $LastLine = $ThisLine; } ################################################ if ( ( $Detail >= 0 ) and (keys %LoginFailed)) { print "\n\n[IMAPd] Login failures:". "\n=========================". "\n Host (user) | # ". "\n------------------------------------------------------------- | -----------"; $ConnCount = 0; foreach $Host (sort keys %LoginFailed) { $Conns = $LoginFailed{$Host}; $HostLength = length($Host); $HostSpaceLength = 61 - $HostLength; $CountLength = length("$Conns"); $CountSpaceLength = 12 - $CountLength; print "\n" ." " x $HostSpaceLength . $Host . " |" . " " x $CountSpaceLength . $Conns . ""; $ConnCount += $Conns; } $CountLength = length("$ConnCount"); $CountSpaceLength = 75 - $CountLength; print "\n" . "-" x 75; print "\n" . " " x $CountSpaceLength . "$ConnCount\n\n\n"; } if ( ( $Detail >= 5 ) and (keys %Connection)) { print "\n[IMAPd] Connections:". "\n=========================". "\n Host | Connections | SSL | Total ". "\n-------------------------------------- | ----------- | -------- | ---------"; $ConnCount = 0; $SSLConn = 0; $TotalConn = 0; foreach $Host (sort keys %Connection) { $Total = $Connection{$Host}; if (defined ($ConnectionNonSSL{$Host})) { $Conns = $ConnectionNonSSL{$Host}; } else { $Conns = 0; } if (defined ($ConnectionSSL{$Host})) { $SSL = $ConnectionSSL{$Host}; } else { $SSL = 0; } if ($DoHostLookup == 1) { $HostOut = gethostbyaddr(inet_aton(LookupIPv46($Host)),AF_INET); if (!length($HostOut)) { $HostOut = $Host; } } else { $HostOut = $Host; } $HostLength = length($HostOut); $HostSpaceLength = 38 - $HostLength; $CountLength = length("$Conns"); $CountSpaceLength = 12 - $CountLength; $SSLLength = length("$SSL"); $SSLSpaceLength = 9 - $SSLLength; $TotalLenght = length("$Total"); $TotalSpaceLength = 10 - $TotalLenght; print "\n" ." " x $HostSpaceLength . $HostOut . " |" . " " x $CountSpaceLength . $Conns . " |" . " " x $SSLSpaceLength . $SSL . " |" . " " x $TotalSpaceLength . $Total; $NonSSLCount += $Conns; $SSLCount += $SSL; $TotalCount += $Total; } $NonSSLLength = length("$NonSSLCount"); $NonSSLSpaceLength = 52 - $NonSSLLength; $SSLLength = length("$SSLCount"); $SSLSpaceLength = 9 - $SSLLength; $TotalLength = length("$TotalCount"); $totalSpaceLength = 10 - $TotalLength; print "\n" . "-" x 75; print "\n" . " " x $NonSSLSpaceLength . $NonSSLCount . " |" . " " x $SSLSpaceLength . $SSLCount . " |" . " " x $totalSpaceLength . $TotalCount . "\n\n\n"; } if ( ( $Detail > 5 ) and (keys %Logout2) ) { print "\n[IMAPd] Logout stats:". "\n====================". "\n User | Logouts". "\n--------------------------------------- | -------"; $ConnCount = 0; foreach $User (sort keys %Logout2) { $Conns = $Logout2{$User}; $UserLength = length($User); $UserSpaceLength = 39 - $UserLength; $CountLength = length("$Conns"); $CountSpaceLength = 8 - $CountLength; print "\n" ." " x $UserSpaceLength . $User . " |" . " " x $CountSpaceLength . $Conns; $ConnCount += $Conns; } $CountLength = length("$ConnCount"); $CountSpaceLength = 49 - $CountLength; print "\n" . "-" x 49; print "\n" . " " x $CountSpaceLength . "$ConnCount\n\n\n"; } # This is basic login information if ( ( $Detail == 5 ) and (keys %Login2) ) { print "\n[IMAPd] Login stats:". "\n====================". "\n User | Logins ". "\n--------------------------------------- | ------- "; $ConnCount = 0; $SizeAll = 0; $DownAll = 0; foreach $User (sort keys %Login2) { $Conns = $Login2{$User}; $UserLength = length($User); $UserSpaceLength = 39 - $UserLength; $CountLength = length("$Conns"); $CountSpaceLength = 8 - $CountLength; print "\n" ." " x $UserSpaceLength . $User . " |" . " " x $CountSpaceLength . $Conns; $ConnCount += $Conns; } $CountLength = length("$ConnCount"); $CountSpaceLength = 49 - $CountLength; print "\n" . "-" x 49; print "\n" . " " x $CountSpaceLength . "$ConnCount\n\n\n"; } # This is more detailed login information if ( ( $Detail > 5 ) and (keys %Login)) { print "\nSuccessful Logins:\n"; $LoginCount = 0; foreach my $User (keys %Login) { print " User $User: \n"; $UserCount = 0; foreach $Host (keys %{$Login{$User}}) { $HostCount = $Login{$User}{$Host}; print " From $Host: $HostCount Time(s)\n"; $UserCount += $HostCount; } $LoginCount += $UserCount; print " Total $UserCount Time(s)\n"; print "\n"; } print "Total $LoginCount successful logins\n\n"; } if ( ( $Detail >= 10 ) and (keys %AutoLogout)) { print "\nAutologout:\n"; foreach $User (sort {$a cmp $b} keys %AutoLogout) { print " $User:\n"; foreach $Host (sort {$a cmp $b} keys %{$AutoLogout{$User}}) { print " $Host: $AutoLogout{$User}{$Host} Time(s)\n"; } } } if ( ( $Detail >= 10 ) and (keys %KilledSession)) { print "\nKilled IMAP sessions:\n"; foreach $User (sort {$a cmp $b} keys %KilledSession) { print " $User:\n"; foreach $Reason (sort {$a cmp $b} keys %{$KilledSession{$User}}) { print " $Reason: $KilledSession{$User}{$Reason} Time(s)\n"; } } } if ( ( $Detail >= 10 ) and (keys %SocketErrors)) { print "\nSocket Errors in connections with:\n"; foreach $Host (sort {$a cmp $b} keys %SocketErrors) { print " $Host: $SocketErrors{$Host} 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