#!/usr/bin/perl -w # Clam-AV plugin. use File::Temp qw(tempfile); sub register { my ($self, $qp, @args) = @_; $self->register_hook("data_post", "clam_scan"); if (@args > 0) { # Untaint scanner location if ($args[0] =~ /^(\/[\/\-\_\.a-z0-9A-Z]*)$/) { $self->{_clamscan_loc} = $1; } else { $self->log(LOGERROR, "FATAL ERROR: Unexpected characters in clamav argument 1"); exit 3; } $self->log(LOGWARN, "WARNING: Ignoring additional arguments.") if (@args > 1); } else { $self->{_clamscan_loc} = "/usr/local/bin/clamscan"; } } sub clam_scan { my ($self, $transaction) = @_; my ($temp_fh, $filename) = tempfile(); print $temp_fh $transaction->header->as_string; print $temp_fh "\n"; $transaction->body_resetpos; while (my $line = $transaction->body_getline) { print $temp_fh $line; } seek($temp_fh, 0, 0); # Now do the actual scanning! my $cmd = $self->{_clamscan_loc}." --stdout -i --max-recursion=50 --disable-summary $filename 2>&1"; $self->log(LOGDEBUG, "Running: $cmd"); my $output = `$cmd`; my $result = ($? >> 8); my $signal = ($? & 127); unlink($filename); chomp($output); $output =~ s/^.* (.*) FOUND$/$1 /mg; $self->log(LOGDEBUG, "clamscan results: $output"); if ($signal) { $self->log(LOGINFO, "clamscan exited with signal: $signal"); return (DECLINED); } if ($result == 1) { $self->log(LOGINFO, "Virus(es) found"); # return (DENY, "Virus Found: $output"); $transaction->header->add('X-Virus-Found', 'Yes'); $transaction->header->add('X-Virus-Details', $output); } elsif ($result) { $self->log(LOGWARN, "ClamAV error: $result\n"); } $transaction->header->add('X-Virus-Checked', 'Checked'); return (DECLINED); }