Q0713

Nigel Metheringham edited this page Nov 29, 2012 · 2 revisions
Clone this wiki locally

Q0713

Question

I'd like to pass all messages through a virus-scanning system before delivery. Can Exim do this?

Answer

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.