Hari Kurup wrote at 9:32 am (+0300) on Thu 28 Apr 2005:

>Thanks Ben. It works but as you mentioned, my CPU utilisation is
>always not less than 80%.
>I do not require to check for authenticated sessions as I don't do any
>authenticated smtp so could you kindly send me the earlier version of
>your filter that does not have this?

Certainly -- attached.

I suspect that the high load situation is caused by the header-parsing
bit looping indefinitely on an EOF condition in some circumstances; I
suspect it can be solved by changing the while(1) to while(eof()) on line
63 but I have not verified this yet.

In the mean time here is the simpler version with the auth check rolled
back which seems to work reliably.

-ben

-- 
Ben Kennedy, chief magician
zygoat creative technical services
613-228-3392 | 1-866-466-4628
http://www.zygoat.ca
# ClamAV and etc filter for Courier perlfitler. See the perlfilter-example that
# comes with Courier for the comments.

# Installed by BRK on 07 July 2004 from http://karmak.org/2004/courier-clamav/
# BRK also altered return status from 500 to 577 which seems more consistent 
with rfc1893.

# 05 Nov 2004: BRK modified to first scan the incoming message and reject if
# there is no From: header provided.  Seems there are spammy things getting 
through
# with no header, so by virtue of maildrop etc. it ends up misleadingly with the
# recipient user's own address.

# 13 Dec 2004: BRK modified again to also call spamc and check for an egregious 
spam score
# following a successful virus check.  This is an effort to cull out the most 
obvious
# crap before it even gets to the maildrop process.

# 20 Apr 2005: BRK modified; we now check the first Received: header to see 
whether the
# message came from an authenticated session.  If so, we bypass the virus and 
spam checks.
# 27 Apr - rolled back; somehow this is getting stuck and eating lots of cpu.

use IO::File;

my $filedesc=shift @ARGV;
my $socket=new IO::File "+<&$filedesc";
die "$!" unless defined $socket;

my $line;
my $first=1;
my $errmsg="200 Ok";

while (defined ($line=<$socket>)) {
        my $msg;
        chomp $line;
        last unless $line;
        if ($first) {
                $msg=filterdata($line);
        }
        else {
                $msg=filtercontrol($line);
        }
        $first=0;
        $errmsg=$msg if $msg;
}

$errmsg .= "\n" unless $errmsg =~ /\n$/;
print $socket $errmsg;

$socket->close;

sub filterdata {
        my $filename=shift;

        # BRK: First scan the input file to ensure there is a From: header.

        my $goodfrom = 0;               # whether we have found presence of a 
From: header
        
        open(FILE, "<${filename}");
        my $nextline = <FILE>;                          # fetch first line
        while(<FILE>)
                {
                my $p = $_;
                
                # If this is a From header, make note of its presence.
                if ($p =~ /^From\: /)
                { $goodfrom = 1; }

                # If this is the end of the headers, or if we've found the 
From:,
                # no need to continue parsing.
                if ($p eq '' || ($goodfrom))
                        { last; }
                }

        close FILE;


        if (!$goodfrom)         # If no From: header existed, barf up with the 
error.
        { return '550 Please provide a From: header in the message.'; }

        # We passed; now see if it smells like fish.

# diag: dump env.
#open(E, '>/tmp/msg.env');
#my $key;
#foreach $key (sort(keys %ENV))
#       { print E, $key . ' = ' . $ENV{$key} . "\n"; }
#close E;

        open(SPAMOUT, "cat ${filename} | spamc -c -U /var/run/spamd.sock |");
        my $result = <SPAMOUT>;
        close(SPAMOUT);
        # Fetch result which will be "score/threshold", e.g. "6.9/4.0".
        $result =~ m/^([0-9.]+)/;       # Extract the score.
        $result = $1;
        # Fail if the score is reasonably large.
        if ($result > 4.9)
                {
                return "571 Identified spam ($result). Contact [EMAIL 
PROTECTED] if this is in error.";
                }

        # Now, carry on with the original CLAMAV scanning.

        open(CLAMOUT, "cat ${filename} | clamdscan --stdout - |");
        my $result = <CLAMOUT>;
        close(CLAMOUT);
        if ( $result =~ m/ FOUND$/ )
                {
                $result =~ s/.*stream: (.*) FOUND/$1/;
                chomp $result;  # strip trailing newline (?)
                return "577 Virus detected (${result}).";
                }

        # Otherwise all looks good, so return usual.

        return "";
}

sub filtercontrol {
        my $filename=shift;
        return "";
}

Reply via email to