One of a number of similar changes I've made lately, this adds a maximum size constraint on clamav. This eliminates the situation where clamav doesn't finish its scan before the SMTP timeout alarm goes off, which (a) wastes CPU time and blocks large email, and (b) leaves big files in the tmpdir. Viruses are seldom if ever found in large files these days, so scanning them is largely a waste of time anyway.
On this subject, given the number of plugins that write the mail out to a tempfile before passing it to something external (clamav, spamc, etc), I'd like to suggest an addition to Qpsmtpd::Transaction. It'd be good to have a call to (a) guarantee that the mail is on disk, and (b) return a filename for it (with the expectation that it won't be altered). Then we could skip out on repetitive tmpfile generation and cleanup in various plugins (in which it's lots simpler to snag stdin from a file than to deal with getting stdin+stdout pipes set up.) (this is a merge from my own copy of the clamav plugin, since my production qpsmtpd is a ways behind CVS; it looks sane but I haven't tested the merged copy) -- Devin \ aqua(at)devin.com, 1024D/E9ABFCD2; http://www.devin.com Carraway \ IRC: Requiem GCS/CC/L s-:--- !a !tv C++++$ ULB+++$ O+@ P L+++
Index: clamav =================================================================== RCS file: /cvs/public/qpsmtpd/plugins/clamav,v retrieving revision 1.3 diff -u -r1.3 clamav --- clamav 5 Mar 2004 12:46:24 -0000 1.3 +++ clamav 15 Jun 2004 15:54:54 -0000 @@ -7,6 +7,9 @@ my ($self, $qp, @args) = @_; $self->register_hook("data_post", "clam_scan"); + # default scan size limit of 512k + $self->{_max_size} = 1024 * 512; + if (@args > 0) { # Untaint scanner location if ($args[0] =~ /^(\/[\/\-\_\.a-z0-9A-Z]*)$/) { @@ -15,16 +18,36 @@ $self->log(LOGERROR, "FATAL ERROR: Unexpected characters in clamav argument 1"); exit 3; } - $self->log(LOGWARN, "WARNING: Ignoring additional arguments.") if (@args > 1); + if (@args > 2) { + if ($args[0] =~ /^(\d+)$/) { + $self->{_max_size} = $1; + } else { + $self->log(LOGERROR, "FATAL ERROR: Unexpected characters in clamav argument 2"); + exit 3; + } + } + $self->log(LOGWARN, "WARNING: Ignoring additional arguments.") if (@args > 2); } else { $self->{_clamscan_loc} = "/usr/local/bin/clamscan"; } + } sub clam_scan { my ($self, $transaction) = @_; - my ($temp_fh, $filename) = tempfile(); + if ($transaction->body_size > $self->{_max_size}) { + $self->log(2, 'Mail too large to scan ('. + $transaction->body_size . " vs $self->{_max_size})" ); + return (DECLINED); + } + + my $spool_dir = $self->qp->config('spool_dir') ? + $self->qp->config('spool_dir') + : Qpsmtpd::Utils::tildeexp('~/tmp/'); + + my ($temp_fh, $filename) = tempfile("qpsmtpd.clamav.XXXXXX", + DIR => $spool_dir); print $temp_fh $transaction->header->as_string; print $temp_fh "\n"; $transaction->body_resetpos;
signature.asc
Description: Digital signature