Q0713 - Exim/exim GitHub Wiki
I'd like to pass all messages through a virus-scanning system before delivery. Can Exim do this?
With the integration of Tom Kistner's original exiscan-acl patch into the main Exim codebase, an interface to a number of virus-scanning engines is now available. Chapter 41 of the Exim Specification contains more details on the use of the "malware" ACL condition to submit content to a number of support virus scanners including ClamAV's clamd, DrWeb_, and Sophos's sophie, at SMTP time. The result of the scan can then be used to determine whether to accept or refuse the message.
For example, to use ClamAV's clamd, first declare the type of virus scanner and a local socket to use to connect to it:
av_scanner = clamd:/var/run/clamd
and then in the DATA ACL the following would call the virus scanner and reject if the message is infected:
deny message = This message contains malware ($malware_name)
malware = *
It is expected that the virus scanner will understand how to unpack and
process MIME parts of a message. If not, the demime
condition may be
used but this is now deprecated and must be explicitly enabled in Exim
at build-time using WITH_OLD_DEMIME
.
For historical reasons, the following note is preserved, which describes a method of performing content scanning and pre-dates the availability of the above mechanism. It may be useful for other types of message manipulation that are not currently natively supported in Exim:
One way of achieving a form of content scanning is to deliver all
messages via a pipe to a checking program that resubmits them for
delivery in some private way that can be checked (e.g. on a specific
SMTP port, or IP address). One possibility is to use the
received protocol
field that can be set for locally submitted mail via
the -oMr command line option. This router sends all messages that
are not from the local host and whose received protocol is not
scanned-ok
to the virus_scan transport:
vircheck:
driver = accept
transport = virus_scan
condition = ${if or {{eq {$received_protocol}{scanned-ok}} \
{eq {$sender_host_address}{127.0.0.1}} }\
{0}{1}}
One problem is that this approach, by default, scans the message for
each recipient, not just once per message. However, you can set the
batch_max
option on the transport to allow it to send a single copy
for multiple recipients. The virus_scan transport should be set up to
pipe the message to a suitable checking program or script which runs as
a trusted user. This can then re-submit the message to Exim, using
-oMr to set the received protocol to scanned-ok
. It is probably
easiest to use the Batch SMTP (BSMTP) facilities for passing the sender
address and the recipient addresses to the checker and then back to Exim
(using the -bS command line option). Warning: If you forget to
make the resubmitting process run as a trusted user, the sender address
will be incorrect and what is worse, the received protocol does not get
set, and you are likely to generate a loop.