dbaa9dbd6c
on files in plugins dir: fixed a number of POD errors formatted some # comments into POD removed bare 1; (these are plugins, not perl modules) most instances of this were copy/pasted from a previous plugin that had it removed instances of # vim ts=N ... they weren't consistent, many didn't match .perltidyrc on modules that failed perl -c tests, added 'use Qpsmtpd::Constants;' Conflicts: plugins/async/check_earlytalker plugins/async/dns_whitelist_soft plugins/async/dnsbl plugins/async/queue/smtp-forward plugins/async/require_resolvable_fromhost plugins/async/rhsbl plugins/async/uribl plugins/auth/auth_checkpassword plugins/auth/auth_cvm_unix_local plugins/auth/auth_flat_file plugins/auth/auth_ldap_bind plugins/auth/auth_vpopmail plugins/auth/auth_vpopmail_sql plugins/auth/authdeny plugins/check_badmailfromto plugins/check_badrcptto_patterns plugins/check_bogus_bounce plugins/check_earlytalker plugins/check_norelay plugins/check_spamhelo plugins/connection_time plugins/dns_whitelist_soft plugins/dnsbl plugins/domainkeys plugins/greylisting plugins/hosts_allow plugins/http_config plugins/logging/adaptive plugins/logging/apache plugins/logging/connection_id plugins/logging/transaction_id plugins/logging/warn plugins/milter plugins/queue/exim-bsmtp plugins/queue/maildir plugins/queue/postfix-queue plugins/queue/smtp-forward plugins/quit_fortune plugins/random_error plugins/rcpt_map plugins/rcpt_regexp plugins/relay_only plugins/require_resolvable_fromhost plugins/rhsbl plugins/sender_permitted_from plugins/spamassassin plugins/tls plugins/tls_cert plugins/uribl plugins/virus/aveclient plugins/virus/bitdefender plugins/virus/clamav plugins/virus/clamdscan plugins/virus/hbedv plugins/virus/kavscanner plugins/virus/klez_filter plugins/virus/sophie plugins/virus/uvscan
159 lines
4.2 KiB
Perl
159 lines
4.2 KiB
Perl
#!perl -Tw
|
|
# H+B EDV-AV plugin.
|
|
|
|
=head1 NAME
|
|
|
|
hbedv - plugin for qpsmtpd which calls the H+BEDV anti virus scanner
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
The B<hbedv> plugin checks a mail for viruses with the H+BEDV anti virus
|
|
scanner (see L<http://www.antivir.de/> for info). It can deny mails if a
|
|
virus was found with a configurable deny list.
|
|
|
|
=head1 VERSION
|
|
|
|
this is B<hbedv> version 1.1
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
Add (perl-)regexps to the F<hbedv_deny> configuration file, one per line for the
|
|
virii you want to block, e.g.:
|
|
|
|
Worm\/Sober\..*
|
|
Worm\/NetSky\..*
|
|
|
|
or just
|
|
|
|
.*
|
|
|
|
to block any virus ;)
|
|
|
|
Set the location of the binary with
|
|
|
|
hbedv hbedvscanner /path/to/antivir
|
|
|
|
in the plugin config if qpsmtpd, the location defaults to I</usr/bin/antivir>.
|
|
|
|
=head1 NOTES
|
|
|
|
If the hbedv_deny config file is empty or could not be found, any virus
|
|
will be blocked.
|
|
|
|
This plugin started life as a copy of the B<clamav> plugin.
|
|
|
|
=head1 LICENCE
|
|
|
|
Written by Hanno Hecker E<lt>hah@uu-x.deE<gt>.
|
|
|
|
The B<hbedv> plugin is published under the same licence as qpsmtpd itself.
|
|
|
|
=cut
|
|
|
|
sub register {
|
|
my ($self, $qp, @args) = @_;
|
|
|
|
if (@args % 2) {
|
|
$self->log(LOGERROR, "FATAL ERROR: odd number of arguments");
|
|
exit 3;
|
|
}
|
|
my %args = @args;
|
|
if (!exists $args{hbedvscanner}) {
|
|
$self->{_hbedvscan_loc} = "/usr/bin/antivir";
|
|
} else {
|
|
if ($args{hbedvscanner} =~ /^(\/[\/\-\_\.a-z0-9A-Z]*)$/) {
|
|
$self->{_hbedvscan_loc} = $1;
|
|
} else {
|
|
$self->log(LOGERROR, "FATAL ERROR: Unexpected characters in hbedvscanner argument");
|
|
exit 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
sub hook_data_post {
|
|
my ($self, $transaction) = @_;
|
|
|
|
my $filename = $transaction->body_filename;
|
|
unless (defined $filename) {
|
|
$self->log(LOGWARN, "didn't get a file name");
|
|
return (DECLINED);
|
|
}
|
|
|
|
# Now do the actual scanning!
|
|
my $cmd = $self->{_hbedvscan_loc}." --archive-max-recursion=50 --alltypes -z -noboot -nombr -rs $filename 2>&1";
|
|
$self->log(LOGDEBUG, "Running: $cmd");
|
|
my @output = `$cmd`;
|
|
|
|
my $result = ($? >> 8);
|
|
my $signal = ($? & 127);
|
|
|
|
chomp(@output);
|
|
my @virii = ();
|
|
foreach my $line (@output) {
|
|
next unless $line =~ /^ALERT: \[([^\]]+)\s+(\w+)?\]/; # $2 =~ /^(virus|worm)$/;
|
|
push @virii, $1;
|
|
}
|
|
@virii = unique(@virii);
|
|
|
|
$self->log(LOGDEBUG, "results: ".join("//",@output));
|
|
|
|
if ($signal) {
|
|
$self->log(LOGWARN, "scanner exited with signal: $signal");
|
|
return (DECLINED);
|
|
}
|
|
my $output = join(", ", @virii);
|
|
$output = substr($output, 0, 60);
|
|
if ($result == 1 || $result == 3) {
|
|
$self->log(LOGWARN, "Virus(es) found: $output");
|
|
# return (DENY, "Virus Found: $output");
|
|
# $transaction->header->add('X-Virus-Found', 'Yes', 0);
|
|
# $transaction->header->add('X-Virus-Details', $output, 0);
|
|
$transaction->header->add('X-H+BEDV-Virus-Found', 'Yes', 0);
|
|
$transaction->header->add('X-H+BEDV-Virus-Details', $output, 0);
|
|
}
|
|
elsif ($result == 200) {
|
|
$self->log(LOGWARN, "Program aborted, not enough memory available");
|
|
}
|
|
elsif ($result == 211) {
|
|
$self->log(LOGWARN, "Programm aborted, because the self check failed");
|
|
}
|
|
elsif ($result == 214) {
|
|
$self->log(LOGWARN, "License key not found");
|
|
}
|
|
elsif ($result) {
|
|
$self->log(LOGWARN, "Error: $result, look for exit codes in the output of '"
|
|
.$self->{_hbedvscan_loc}." --help' for more info\n");
|
|
}
|
|
|
|
# $transaction->header->add('X-Virus-Checked', 'Checked', 0);
|
|
$transaction->header->add('X-H+BEDV-Virus-Checked', 'Checked', 0);
|
|
return (DECLINED) unless $result;
|
|
|
|
if (@virii) {
|
|
return(DENY, "Virus found: $output")
|
|
unless $self->qp->config("hbedv_deny");
|
|
foreach my $d ($self->qp->config("hbedv_deny")) {
|
|
foreach my $v (@virii) {
|
|
if ($v =~ /^$d$/i) {
|
|
$self->log(LOGWARN, "Denying mail with virus '$v'");
|
|
return(DENY, "Virus found: $output");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (DECLINED);
|
|
}
|
|
|
|
sub unique {
|
|
## This is the short version, I haven't tried if any warnings
|
|
## are generated by perl if you use just this... if you need
|
|
## every cpu cycle, try this:
|
|
## my %h;foreach (@_) { ++$h{$_}; }; return keys(%h);
|
|
my @list = @_;
|
|
my %hash;
|
|
foreach my $item (@list) {
|
|
exists $hash{$item} || ($hash{$item} = 1);
|
|
}
|
|
return keys(%hash)
|
|
}
|