<!DOCTYPE html PUBLIC "XSLT-compat"> <html lang="en-GB"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" type="text/css" href="../../../../common.css"> <meta name="author" content="The Exim Project. <http://www.exim.org/>"> <meta name="copyright" content="Copyright ©2010 The Exim Project. All rights reserved"> <meta name="description" content="Exim is a message transfer agent (MTA) developed at the University of Cambridge for use on Unix systems connected to the Internet."> <meta name="keywords" content="exim,smtp,mta,email"> <meta name="robots" content="noodp,noydir,index,follow"> <meta name="viewport" content="width=device-width"> <title>41. Content scanning at ACL time</title> <link rel="stylesheet" type="text/css" href="../../../../doc/chapter.css"> <link rel="canonical" href="http://www.exim.org/exim-html-current/doc/html/spec_html/ch41.html"> </head> <body> <h1 id="header"><a href="../../../..">Exim Internet Mailer</a></h1> <div id="outer"> <ul id="nav_flow" class="nav"> <li><a href="../../../../index.html">Home</a></li> <li><a href="../../../../mirrors.html">Download</a></li> <li><a href="../../../../docs.html">Documentation</a></li> <li><a href="../../../../maillist.html">Mailing Lists</a></li> <li><a href="http://wiki.exim.org/">Wiki</a></li> <li><a href="http://www.exim.org/bugzilla/">Bugs</a></li> <li><a href="../../../../credits.html">Credits</a></li> <li class="search"><form action="http://www.google.com/search" method="get"> <span class="search_field_container"><input type="search" name="q" placeholder="Search Docs" class="search_field"></span><input type="hidden" name="hl" value="en"><input type="hidden" name="ie" value="UTF-8"><input type="hidden" name="as_qdr" value="all"><input type="hidden" name="q" value="site:www.exim.org"><input type="hidden" name="q" value="inurl:exim-html-current"> </form></li> </ul> <div id="inner"><div id="content"> <a class="previous_page" href="ch40.html"><-previous</a><a class="next_page" href="ch42.html">next-></a><div id="chapter" class="chapter"> <h2 id="CHAPexiscan" class="">Chapter 41 - Content scanning at ACL time</h2> <p> The extension of Exim to include content scanning at ACL time, formerly known as “exiscan”, was originally implemented as a patch by Tom Kistner. The code was integrated into the main source for Exim release 4.50, and Tom continues to maintain it. Most of the wording of this chapter is taken from Tom’s specification. </p> <p> It is also possible to scan the content of messages at other times. The <span class="docbook_function">local_scan()</span> function (see chapter <a href="ch42.html" title="42. Adding a local scan function to Exim">42</a>) allows for content scanning after all the ACLs have run. A transport filter can be used to scan messages at delivery time (see the <span class="docbook_option">transport_filter</span> option, described in chapter <a href="ch24.html" title="24. Generic options for transports">24</a>). </p> <p> If you want to include the ACL-time content-scanning features when you compile Exim, you need to arrange for WITH_CONTENT_SCAN to be defined in your <span class="docbook_filename">Local/Makefile</span>. When you do that, the Exim binary is built with: </p> <ul> <li> <p> Two additional ACLs (<span class="docbook_option">acl_smtp_mime</span> and <span class="docbook_option">acl_not_smtp_mime</span>) that are run for all MIME parts for SMTP and non-SMTP messages, respectively. </p> </li> <li> <p> Additional ACL conditions and modifiers: <span class="docbook_option">decode</span>, <span class="docbook_option">malware</span>, <span class="docbook_option">mime_regex</span>, <span class="docbook_option">regex</span>, and <span class="docbook_option">spam</span>. These can be used in the ACL that is run at the end of message reception (the <span class="docbook_option">acl_smtp_data</span> ACL). </p> </li> <li> <p> An additional control feature (“no_mbox_unspool”) that saves spooled copies of messages, or parts of messages, for debugging purposes. </p> </li> <li> <p> Additional expansion variables that are set in the new ACL and by the new conditions. </p> </li> <li> <p> Two new main configuration options: <span class="docbook_option">av_scanner</span> and <span class="docbook_option">spamd_address</span>. </p> </li> </ul> <p> There is another content-scanning configuration option for <span class="docbook_filename">Local/Makefile</span>, called WITH_OLD_DEMIME. If this is set, the old, deprecated <span class="docbook_option">demime</span> ACL condition is compiled, in addition to all the other content-scanning features. </p> <p> Content-scanning is continually evolving, and new features are still being added. While such features are still unstable and liable to incompatible changes, they are made available in Exim by setting options whose names begin EXPERIMENTAL_ in <span class="docbook_filename">Local/Makefile</span>. Such features are not documented in this manual. You can find out about them by reading the file called <span class="docbook_filename">doc/experimental.txt</span>. </p> <p> All the content-scanning facilities work on a MBOX copy of the message that is temporarily created in a file called: </p> <div class="docbook_literallayout"><pre> <<span class="docbook_emphasis">spool_directory</span>><code class="docbook_literal">/scan/</code><<span class="docbook_emphasis">message_id</span>>/<<span class="docbook_emphasis">message_id</span>><code class="docbook_literal">.eml</code> </pre></div> <p> The <span class="docbook_filename">.eml</span> extension is a friendly hint to virus scanners that they can expect an MBOX-like structure inside that file. The file is created when the first content scanning facility is called. Subsequent calls to content scanning conditions open the same file again. The directory is recursively removed when the <span class="docbook_option">acl_smtp_data</span> ACL has finished running, unless </p> <div class="docbook_literallayout"><pre> control = no_mbox_unspool </pre></div> <p> has been encountered. When the MIME ACL decodes files, they are put into the same directory by default. </p> <div class="section"> <h3 id="SECTscanvirus" class="">1. Scanning for viruses</h3> <p> The <span class="docbook_option">malware</span> ACL condition lets you connect virus scanner software to Exim. It supports a “generic” interface to scanners called via the shell, and specialized interfaces for “daemon” type virus scanners, which are resident in memory and thus are much faster. </p> <p> You can set the <span class="docbook_option">av_scanner</span> option in first part of the Exim configuration file to specify which scanner to use, together with any additional options that are needed. The basic syntax is as follows: </p> <div class="docbook_literallayout"><pre> <code class="docbook_literal">av_scanner = <</code><span class="docbook_emphasis">scanner-type</span><code class="docbook_literal">>:<</code><span class="docbook_emphasis">option1</span><code class="docbook_literal">>:<</code><span class="docbook_emphasis">option2</span><code class="docbook_literal">>:[...]</code> </pre></div> <p> If you do not set <span class="docbook_option">av_scanner</span>, it defaults to </p> <div class="docbook_literallayout"><pre> av_scanner = sophie:/var/run/sophie </pre></div> <p> If the value of <span class="docbook_option">av_scanner</span> starts with a dollar character, it is expanded before use. The following scanner types are supported in this release: </p> <dl> <dt><span class="docbook_option">aveserver</span></dt> <dd> <p> This is the scanner daemon of Kaspersky Version 5. You can get a trial version at <span class="docbook_emphasis"><a href="http://www.kaspersky.com">http://www.kaspersky.com</a></span>. This scanner type takes one option, which is the path to the daemon’s UNIX socket. The default is shown in this example: </p> <div class="docbook_literallayout"><pre> av_scanner = aveserver:/var/run/aveserver </pre></div> </dd> <dt><span class="docbook_option">clamd</span></dt> <dd> <p> This daemon-type scanner is GPL and free. You can get it at <span class="docbook_emphasis"><a href="http://www.clamav.net/">http://www.clamav.net/</a></span>. Some older versions of clamd do not seem to unpack MIME containers, so it used to be recommended to unpack MIME attachments in the MIME ACL. This no longer believed to be necessary. One option is required: either the path and name of a UNIX socket file, or a hostname or IP number, and a port, separated by space, as in the second of these examples: </p> <div class="docbook_literallayout"><pre> av_scanner = clamd:/opt/clamd/socket av_scanner = clamd:192.0.2.3 1234 av_scanner = clamd:192.0.2.3 1234:local </pre></div> <p> If the value of av_scanner points to a UNIX socket file or contains the local keyword, then the ClamAV interface will pass a filename containing the data to be scanned, which will should normally result in less I/O happening and be more efficient. Normally in the TCP case, the data is streamed to ClamAV as Exim does not assume that there is a common filesystem with the remote host. There is an option WITH_OLD_CLAMAV_STREAM in <span class="docbook_filename">src/EDITME</span> available, should you be running a version of ClamAV prior to 0.95. If the option is unset, the default is <span class="docbook_filename">/tmp/clamd</span>. Thanks to David Saez for contributing the code for this scanner. </p> </dd> <dt><span class="docbook_option">cmdline</span></dt> <dd> <p> This is the keyword for the generic command line scanner interface. It can be used to attach virus scanners that are invoked from the shell. This scanner type takes 3 mandatory options: </p> <ol> <li> <p> The full path and name of the scanner binary, with all command line options, and a placeholder (<code class="docbook_literal">%s</code>) for the directory to scan. </p> </li> <li> <p> A regular expression to match against the STDOUT and STDERR output of the virus scanner. If the expression matches, a virus was found. You must make absolutely sure that this expression matches on “virus found”. This is called the “trigger” expression. </p> </li> <li> <p> Another regular expression, containing exactly one pair of parentheses, to match the name of the virus found in the scanners output. This is called the “name” expression. </p> </li> </ol> <p> For example, Sophos Sweep reports a virus on a line like this: </p> <div class="docbook_literallayout"><pre> Virus 'W32/Magistr-B' found in file ./those.bat </pre></div> <p> For the trigger expression, we can match the phrase “found in file”. For the name expression, we want to extract the W32/Magistr-B string, so we can match for the single quotes left and right of it. Altogether, this makes the configuration setting: </p> <div class="docbook_literallayout"><pre> av_scanner = cmdline:\ /path/to/sweep -ss -all -rec -archive %s:\ found in file:'(.+)' </pre></div> </dd> <dt><span class="docbook_option">drweb</span></dt> <dd> <p> The DrWeb daemon scanner (<span class="docbook_emphasis"><a href="http://www.sald.com/">http://www.sald.com/</a></span>) interface takes one argument, either a full path to a UNIX socket, or an IP address and port separated by white space, as in these examples: </p> <div class="docbook_literallayout"><pre> av_scanner = drweb:/var/run/drwebd.sock av_scanner = drweb:192.168.2.20 31337 </pre></div> <p> If you omit the argument, the default path <span class="docbook_filename">/usr/local/drweb/run/drwebd.sock</span> is used. Thanks to Alex Miller for contributing the code for this scanner. </p> </dd> <dt><span class="docbook_option">fsecure</span></dt> <dd> <p> The F-Secure daemon scanner (<span class="docbook_emphasis"><a href="http://www.f-secure.com">http://www.f-secure.com</a></span>) takes one argument which is the path to a UNIX socket. For example: </p> <div class="docbook_literallayout"><pre> av_scanner = fsecure:/path/to/.fsav </pre></div> <p> If no argument is given, the default is <span class="docbook_filename">/var/run/.fsav</span>. Thanks to Johan Thelmen for contributing the code for this scanner. </p> </dd> <dt><span class="docbook_option">kavdaemon</span></dt> <dd> <p> This is the scanner daemon of Kaspersky Version 4. This version of the Kaspersky scanner is outdated. Please upgrade (see <span class="docbook_option">aveserver</span> above). This scanner type takes one option, which is the path to the daemon’s UNIX socket. For example: </p> <div class="docbook_literallayout"><pre> av_scanner = kavdaemon:/opt/AVP/AvpCtl </pre></div> <p> The default path is <span class="docbook_filename">/var/run/AvpCtl</span>. </p> </dd> <dt><span class="docbook_option">mksd</span></dt> <dd> <p> This is a daemon type scanner that is aimed mainly at Polish users, though some parts of documentation are now available in English. You can get it at <span class="docbook_emphasis"><a href="http://linux.mks.com.pl/">http://linux.mks.com.pl/</a></span>. The only option for this scanner type is the maximum number of processes used simultaneously to scan the attachments, provided that the demime facility is employed and also provided that mksd has been run with at least the same number of child processes. For example: </p> <div class="docbook_literallayout"><pre> av_scanner = mksd:2 </pre></div> <p> You can safely omit this option (the default value is 1). </p> </dd> <dt><span class="docbook_option">sophie</span></dt> <dd> <p> Sophie is a daemon that uses Sophos’ <span class="docbook_option">libsavi</span> library to scan for viruses. You can get Sophie at <span class="docbook_emphasis"><a href="http://www.clanfield.info/sophie/">http://www.clanfield.info/sophie/</a></span>. The only option for this scanner type is the path to the UNIX socket that Sophie uses for client communication. For example: </p> <div class="docbook_literallayout"><pre> av_scanner = sophie:/tmp/sophie </pre></div> <p> The default path is <span class="docbook_filename">/var/run/sophie</span>, so if you are using this, you can omit the option. </p> </dd> </dl> <p> When <span class="docbook_option">av_scanner</span> is correctly set, you can use the <span class="docbook_option">malware</span> condition in the DATA ACL. <span class="docbook_emphasis">Note</span>: You cannot use the <span class="docbook_option">malware</span> condition in the MIME ACL. </p> <p> The <span class="docbook_option">av_scanner</span> option is expanded each time <span class="docbook_option">malware</span> is called. This makes it possible to use different scanners. See further below for an example. The <span class="docbook_option">malware</span> condition caches its results, so when you use it multiple times for the same message, the actual scanning process is only carried out once. However, using expandable items in <span class="docbook_option">av_scanner</span> disables this caching, in which case each use of the <span class="docbook_option">malware</span> condition causes a new scan of the message. </p> <p> The <span class="docbook_option">malware</span> condition takes a right-hand argument that is expanded before use. It can then be one of </p> <ul> <li> <p> “true”, “*”, or “1”, in which case the message is scanned for viruses. The condition succeeds if a virus was found, and fail otherwise. This is the recommended usage. </p> </li> <li> <p> “false” or “0” or an empty string, in which case no scanning is done and the condition fails immediately. </p> </li> <li> <p> A regular expression, in which case the message is scanned for viruses. The condition succeeds if a virus is found and its name matches the regular expression. This allows you to take special actions on certain types of virus. </p> </li> </ul> <p> You can append <code class="docbook_literal">/defer_ok</code> to the <span class="docbook_option">malware</span> condition to accept messages even if there is a problem with the virus scanner. Otherwise, such a problem causes the ACL to defer. </p> <p> When a virus is found, the condition sets up an expansion variable called $malware_name that contains the name of the virus. You can use it in a <span class="docbook_option">message</span> modifier that specifies the error returned to the sender, and/or in logging data. </p> <p> If your virus scanner cannot unpack MIME and TNEF containers itself, you should use the <span class="docbook_option">demime</span> condition (see section <a href="ch41.html#SECTdemimecond" title="41. Content scanning at ACL time">41.6</a>) before the <span class="docbook_option">malware</span> condition. </p> <p class="changed"> Beware the interaction of Exim’s <span class="docbook_option">message_size_limit</span> with any size limits imposed by your anti-virus scanner. </p> <p> Here is a very simple scanning example: </p> <div class="docbook_literallayout"><pre> deny message = This message contains malware ($malware_name) demime = * malware = * </pre></div> <p> The next example accepts messages when there is a problem with the scanner: </p> <div class="docbook_literallayout"><pre> deny message = This message contains malware ($malware_name) demime = * malware = */defer_ok </pre></div> <p> The next example shows how to use an ACL variable to scan with both sophie and aveserver. It assumes you have set: </p> <div class="docbook_literallayout"><pre> av_scanner = $acl_m0 </pre></div> <p> in the main Exim configuration. </p> <div class="docbook_literallayout"><pre> deny message = This message contains malware ($malware_name) set acl_m0 = sophie malware = * deny message = This message contains malware ($malware_name) set acl_m0 = aveserver malware = * </pre></div> </div> <div class="section"> <h3 id="SECTscanspamass" class="">2. Scanning with SpamAssassin</h3> <p> The <span class="docbook_option">spam</span> ACL condition calls SpamAssassin’s <span class="docbook_option">spamd</span> daemon to get a spam score and a report for the message. You can get SpamAssassin at <span class="docbook_emphasis"><a href="http://www.spamassassin.org">http://www.spamassassin.org</a></span>, or, if you have a working Perl installation, you can use CPAN by running: </p> <div class="docbook_literallayout"><pre> perl -MCPAN -e 'install Mail::SpamAssassin' </pre></div> <p> SpamAssassin has its own set of configuration files. Please review its documentation to see how you can tweak it. The default installation should work nicely, however. </p> <p> After having installed and configured SpamAssassin, start the <span class="docbook_option">spamd</span> daemon. By default, it listens on 127.0.0.1, TCP port 783. If you use another host or port for <span class="docbook_option">spamd</span>, you must set the <span class="docbook_option">spamd_address</span> option in the global part of the Exim configuration as follows (example): </p> <div class="docbook_literallayout"><pre> spamd_address = 192.168.99.45 387 </pre></div> <p> You do not need to set this option if you use the default. As of version 2.60, <span class="docbook_option">spamd</span> also supports communication over UNIX sockets. If you want to use these, supply <span class="docbook_option">spamd_address</span> with an absolute file name instead of a address/port pair: </p> <div class="docbook_literallayout"><pre> spamd_address = /var/run/spamd_socket </pre></div> <p> You can have multiple <span class="docbook_option">spamd</span> servers to improve scalability. These can reside on other hardware reachable over the network. To specify multiple <span class="docbook_option">spamd</span> servers, put multiple address/port pairs in the <span class="docbook_option">spamd_address</span> option, separated with colons: </p> <div class="docbook_literallayout"><pre> spamd_address = 192.168.2.10 783 : \ 192.168.2.11 783 : \ 192.168.2.12 783 </pre></div> <p> Up to 32 <span class="docbook_option">spamd</span> servers are supported. The servers are queried in a random fashion. When a server fails to respond to the connection attempt, all other servers are tried until one succeeds. If no server responds, the <span class="docbook_option">spam</span> condition defers. </p> <p> <span class="docbook_emphasis">Warning</span>: It is not possible to use the UNIX socket connection method with multiple <span class="docbook_option">spamd</span> servers. </p> <p> The <span class="docbook_option">spamd_address</span> variable is expanded before use if it starts with a dollar sign. In this case, the expansion may return a string that is used as the list so that multiple spamd servers can be the result of an expansion. </p> </div> <div class="section"> <h3 id="SECID206" class="">3. Calling SpamAssassin from an Exim ACL</h3> <p> Here is a simple example of the use of the <span class="docbook_option">spam</span> condition in a DATA ACL: </p> <div class="docbook_literallayout"><pre> deny message = This message was classified as SPAM spam = joe </pre></div> <p> The right-hand side of the <span class="docbook_option">spam</span> condition specifies a name. This is relevant if you have set up multiple SpamAssassin profiles. If you do not want to scan using a specific profile, but rather use the SpamAssassin system-wide default profile, you can scan for an unknown name, or simply use “nobody”. However, you must put something on the right-hand side. </p> <p> The name allows you to use per-domain or per-user antispam profiles in principle, but this is not straightforward in practice, because a message may have multiple recipients, not necessarily all in the same domain. Because the <span class="docbook_option">spam</span> condition has to be called from a DATA ACL in order to be able to read the contents of the message, the variables $local_part and $domain are not set. </p> <p> The right-hand side of the <span class="docbook_option">spam</span> condition is expanded before being used, so you can put lookups or conditions there. When the right-hand side evaluates to “0” or “false”, no scanning is done and the condition fails immediately. </p> <p> Scanning with SpamAssassin uses a lot of resources. If you scan every message, large ones may cause significant performance degradation. As most spam messages are quite small, it is recommended that you do not scan the big ones. For example: </p> <div class="docbook_literallayout"><pre> deny message = This message was classified as SPAM condition = ${if < {$message_size}{10K}} spam = nobody </pre></div> <p> The <span class="docbook_option">spam</span> condition returns true if the threshold specified in the user’s SpamAssassin profile has been matched or exceeded. If you want to use the <span class="docbook_option">spam</span> condition for its side effects (see the variables below), you can make it always return “true” by appending <code class="docbook_literal">:true</code> to the username. </p> <p class="changed"> When the <span class="docbook_option">spam</span> condition is run, it sets up a number of expansion variables. These variables are saved with the received message, thus they are available for use at delivery time. </p> <dl> <dt>$spam_score</dt> <dd> <p> The spam score of the message, for example “3.4” or “30.5”. This is useful for inclusion in log or reject messages. </p> </dd> <dt>$spam_score_int</dt> <dd> <p> The spam score of the message, multiplied by ten, as an integer value. For example “34” or “305”. It may appear to disagree with $spam_score because $spam_score is rounded and $spam_score_int is truncated. The integer value is useful for numeric comparisons in conditions. </p> </dd> <dt>$spam_bar</dt> <dd> <p> A string consisting of a number of “+” or “-” characters, representing the integer part of the spam score value. A spam score of 4.4 would have a $spam_bar value of “++++”. This is useful for inclusion in warning headers, since MUAs can match on such strings. </p> </dd> <dt>$spam_report</dt> <dd> <p> A multiline text table, containing the full SpamAssassin report for the message. Useful for inclusion in headers or reject messages. </p> </dd> </dl> <p> The <span class="docbook_option">spam</span> condition caches its results unless expansion in spamd_address was used. If you call it again with the same user name, it does not scan again, but rather returns the same values as before. </p> <p> The <span class="docbook_option">spam</span> condition returns DEFER if there is any error while running the message through SpamAssassin or if the expansion of spamd_address failed. If you want to treat DEFER as FAIL (to pass on to the next ACL statement block), append <code class="docbook_literal">/defer_ok</code> to the right-hand side of the spam condition, like this: </p> <div class="docbook_literallayout"><pre> deny message = This message was classified as SPAM spam = joe/defer_ok </pre></div> <p> This causes messages to be accepted even if there is a problem with <span class="docbook_option">spamd</span>. </p> <p> Here is a longer, commented example of the use of the <span class="docbook_option">spam</span> condition: </p> <div class="docbook_literallayout"><pre> # put headers in all messages (no matter if spam or not) warn spam = nobody:true add_header = X-Spam-Score: $spam_score ($spam_bar) add_header = X-Spam-Report: $spam_report # add second subject line with *SPAM* marker when message # is over threshold warn spam = nobody add_header = Subject: *SPAM* $h_Subject: # reject spam at high scores (> 12) deny message = This message scored $spam_score spam points. spam = nobody:true condition = ${if >{$spam_score_int}{120}{1}{0}} </pre></div> </div> <div class="section"> <h3 id="SECTscanmimepart" class="">4. Scanning MIME parts</h3> <p> The <span class="docbook_option">acl_smtp_mime</span> global option specifies an ACL that is called once for each MIME part of an SMTP message, including multipart types, in the sequence of their position in the message. Similarly, the <span class="docbook_option">acl_not_smtp_mime</span> option specifies an ACL that is used for the MIME parts of non-SMTP messages. These options may both refer to the same ACL if you want the same processing in both cases. </p> <p> These ACLs are called (possibly many times) just before the <span class="docbook_option">acl_smtp_data</span> ACL in the case of an SMTP message, or just before the <span class="docbook_option">acl_not_smtp</span> ACL in the case of a non-SMTP message. However, a MIME ACL is called only if the message contains a <span class="docbook_emphasis">Content-Type:</span> header line. When a call to a MIME ACL does not yield “accept”, ACL processing is aborted and the appropriate result code is sent to the client. In the case of an SMTP message, the <span class="docbook_option">acl_smtp_data</span> ACL is not called when this happens. </p> <p> You cannot use the <span class="docbook_option">malware</span> or <span class="docbook_option">spam</span> conditions in a MIME ACL; these can only be used in the DATA or non-SMTP ACLs. However, you can use the <span class="docbook_option">regex</span> condition to match against the raw MIME part. You can also use the <span class="docbook_option">mime_regex</span> condition to match against the decoded MIME part (see section <a href="ch41.html#SECTscanregex" title="41. Content scanning at ACL time">41.5</a>). </p> <p> At the start of a MIME ACL, a number of variables are set from the header information for the relevant MIME part. These are described below. The contents of the MIME part are not by default decoded into a disk file except for MIME parts whose content-type is “message/rfc822”. If you want to decode a MIME part into a disk file, you can use the <span class="docbook_option">decode</span> condition. The general syntax is: </p> <div class="docbook_literallayout"><pre> <code class="docbook_literal">decode = [/</code><<span class="docbook_emphasis">path</span>><code class="docbook_literal">/]</code><<span class="docbook_emphasis">filename</span>> </pre></div> <p> The right hand side is expanded before use. After expansion, the value can be: </p> <ol> <li> <p> “0” or “false”, in which case no decoding is done. </p> </li> <li> <p> The string “default”. In that case, the file is put in the temporary “default” directory <<span class="docbook_emphasis">spool_directory</span>><span class="docbook_filename">/scan/</span><<span class="docbook_emphasis">message_id</span>><span class="docbook_filename">/</span> with a sequential file name consisting of the message id and a sequence number. The full path and name is available in $mime_decoded_filename after decoding. </p> </li> <li> <p> A full path name starting with a slash. If the full name is an existing directory, it is used as a replacement for the default directory. The filename is then sequentially assigned. If the path does not exist, it is used as the full path and file name. </p> </li> <li> <p> If the string does not start with a slash, it is used as the filename, and the default path is then used. </p> </li> </ol> <p> The <span class="docbook_option">decode</span> condition normally succeeds. It is only false for syntax errors or unusual circumstances such as memory shortages. You can easily decode a file with its original, proposed filename using </p> <div class="docbook_literallayout"><pre> decode = $mime_filename </pre></div> <p> However, you should keep in mind that $mime_filename might contain anything. If you place files outside of the default path, they are not automatically unlinked. </p> <p> For RFC822 attachments (these are messages attached to messages, with a content-type of “message/rfc822”), the ACL is called again in the same manner as for the primary message, only that the $mime_is_rfc822 expansion variable is set (see below). Attached messages are always decoded to disk before being checked, and the files are unlinked once the check is done. </p> <p> The MIME ACL supports the <span class="docbook_option">regex</span> and <span class="docbook_option">mime_regex</span> conditions. These can be used to match regular expressions against raw and decoded MIME parts, respectively. They are described in section <a href="ch41.html#SECTscanregex" title="41. Content scanning at ACL time">41.5</a>. </p> <p> The following list describes all expansion variables that are available in the MIME ACL: </p> <dl> <dt>$mime_boundary</dt> <dd> <p> If the current part is a multipart (see $mime_is_multipart) below, it should have a boundary string, which is stored in this variable. If the current part has no boundary parameter in the <span class="docbook_emphasis">Content-Type:</span> header, this variable contains the empty string. </p> </dd> <dt>$mime_charset</dt> <dd> <p> This variable contains the character set identifier, if one was found in the <span class="docbook_emphasis">Content-Type:</span> header. Examples for charset identifiers are: </p> <div class="docbook_literallayout"><pre> us-ascii gb2312 (Chinese) iso-8859-1 </pre></div> <p> Please note that this value is not normalized, so you should do matches case-insensitively. </p> </dd> <dt>$mime_content_description</dt> <dd> <p> This variable contains the normalized content of the <span class="docbook_emphasis">Content-Description:</span> header. It can contain a human-readable description of the parts content. Some implementations repeat the filename for attachments here, but they are usually only used for display purposes. </p> </dd> <dt>$mime_content_disposition</dt> <dd> <p> This variable contains the normalized content of the <span class="docbook_emphasis">Content-Disposition:</span> header. You can expect strings like “attachment” or “inline” here. </p> </dd> <dt>$mime_content_id</dt> <dd> <p> This variable contains the normalized content of the <span class="docbook_emphasis">Content-ID:</span> header. This is a unique ID that can be used to reference a part from another part. </p> </dd> <dt>$mime_content_size</dt> <dd> <p> This variable is set only after the <span class="docbook_option">decode</span> modifier (see above) has been successfully run. It contains the size of the decoded part in kilobytes. The size is always rounded up to full kilobytes, so only a completely empty part has a $mime_content_size of zero. </p> </dd> <dt>$mime_content_transfer_encoding</dt> <dd> <p> This variable contains the normalized content of the <span class="docbook_emphasis">Content-transfer-encoding:</span> header. This is a symbolic name for an encoding type. Typical values are “base64” and “quoted-printable”. </p> </dd> <dt>$mime_content_type</dt> <dd> <p> If the MIME part has a <span class="docbook_emphasis">Content-Type:</span> header, this variable contains its value, lowercased, and without any options (like “name” or “charset”). Here are some examples of popular MIME types, as they may appear in this variable: </p> <div class="docbook_literallayout"><pre> text/plain text/html application/octet-stream image/jpeg audio/midi </pre></div> <p> If the MIME part has no <span class="docbook_emphasis">Content-Type:</span> header, this variable contains the empty string. </p> </dd> <dt>$mime_decoded_filename</dt> <dd> <p> This variable is set only after the <span class="docbook_option">decode</span> modifier (see above) has been successfully run. It contains the full path and file name of the file containing the decoded data. </p> </dd> </dl> <p> </p> <dl> <dt>$mime_filename</dt> <dd> <p> This is perhaps the most important of the MIME variables. It contains a proposed filename for an attachment, if one was found in either the <span class="docbook_emphasis">Content-Type:</span> or <span class="docbook_emphasis">Content-Disposition:</span> headers. The filename will be RFC2047 decoded, but no additional sanity checks are done. If no filename was found, this variable contains the empty string. </p> </dd> <dt>$mime_is_coverletter</dt> <dd> <p> This variable attempts to differentiate the “cover letter” of an e-mail from attached data. It can be used to clamp down on flashy or unnecessarily encoded content in the cover letter, while not restricting attachments at all. </p> <p> The variable contains 1 (true) for a MIME part believed to be part of the cover letter, and 0 (false) for an attachment. At present, the algorithm is as follows: </p> <ol> <li> <p> The outermost MIME part of a message is always a cover letter. </p> </li> <li> <p> If a multipart/alternative or multipart/related MIME part is a cover letter, so are all MIME subparts within that multipart. </p> </li> <li> <p> If any other multipart is a cover letter, the first subpart is a cover letter, and the rest are attachments. </p> </li> <li> <p> All parts contained within an attachment multipart are attachments. </p> </li> </ol> <p> As an example, the following will ban “HTML mail” (including that sent with alternative plain text), while allowing HTML files to be attached. HTML coverletter mail attached to non-HMTL coverletter mail will also be allowed: </p> <div class="docbook_literallayout"><pre> deny message = HTML mail is not accepted here !condition = $mime_is_rfc822 condition = $mime_is_coverletter condition = ${if eq{$mime_content_type}{text/html}{1}{0}} </pre></div> </dd> <dt>$mime_is_multipart</dt> <dd> <p> This variable has the value 1 (true) when the current part has the main type “multipart”, for example “multipart/alternative” or “multipart/mixed”. Since multipart entities only serve as containers for other parts, you may not want to carry out specific actions on them. </p> </dd> <dt>$mime_is_rfc822</dt> <dd> <p> This variable has the value 1 (true) if the current part is not a part of the checked message itself, but part of an attached message. Attached message decoding is fully recursive. </p> </dd> <dt>$mime_part_count</dt> <dd> <p> This variable is a counter that is raised for each processed MIME part. It starts at zero for the very first part (which is usually a multipart). The counter is per-message, so it is reset when processing RFC822 attachments (see $mime_is_rfc822). The counter stays set after <span class="docbook_option">acl_smtp_mime</span> is complete, so you can use it in the DATA ACL to determine the number of MIME parts of a message. For non-MIME messages, this variable contains the value -1. </p> </dd> </dl> </div> <div class="section"> <h3 id="SECTscanregex" class="">5. Scanning with regular expressions</h3> <p> You can specify your own custom regular expression matches on the full body of the message, or on individual MIME parts. </p> <p> The <span class="docbook_option">regex</span> condition takes one or more regular expressions as arguments and matches them against the full message (when called in the DATA ACL) or a raw MIME part (when called in the MIME ACL). The <span class="docbook_option">regex</span> condition matches linewise, with a maximum line length of 32K characters. That means you cannot have multiline matches with the <span class="docbook_option">regex</span> condition. </p> <p> The <span class="docbook_option">mime_regex</span> condition can be called only in the MIME ACL. It matches up to 32K of decoded content (the whole content at once, not linewise). If the part has not been decoded with the <span class="docbook_option">decode</span> modifier earlier in the ACL, it is decoded automatically when <span class="docbook_option">mime_regex</span> is executed (using default path and filename values). If the decoded data is larger than 32K, only the first 32K characters are checked. </p> <p> The regular expressions are passed as a colon-separated list. To include a literal colon, you must double it. Since the whole right-hand side string is expanded before being used, you must also escape dollar signs and backslashes with more backslashes, or use the <code class="docbook_literal">\N</code> facility to disable expansion. Here is a simple example that contains two regular expressions: </p> <div class="docbook_literallayout"><pre> deny message = contains blacklisted regex ($regex_match_string) regex = [Mm]ortgage : URGENT BUSINESS PROPOSAL </pre></div> <p> The conditions returns true if any one of the regular expressions matches. The $regex_match_string expansion variable is then set up and contains the matching regular expression. </p> <p> <span class="docbook_emphasis">Warning</span>: With large messages, these conditions can be fairly CPU-intensive. </p> </div> <div class="section"> <h3 id="SECTdemimecond" class="">6. The demime condition</h3> <p> The <span class="docbook_option">demime</span> ACL condition provides MIME unpacking, sanity checking and file extension blocking. It is usable only in the DATA and non-SMTP ACLs. The <span class="docbook_option">demime</span> condition uses a simpler interface to MIME decoding than the MIME ACL functionality, but provides no additional facilities. Please note that this condition is deprecated and kept only for backward compatibility. You must set the WITH_OLD_DEMIME option in <span class="docbook_filename">Local/Makefile</span> at build time to be able to use the <span class="docbook_option">demime</span> condition. </p> <p> The <span class="docbook_option">demime</span> condition unpacks MIME containers in the message. It detects errors in MIME containers and can match file extensions found in the message against a list. Using this facility produces files containing the unpacked MIME parts of the message in the temporary scan directory. If you do antivirus scanning, it is recommended that you use the <span class="docbook_option">demime</span> condition before the antivirus (<span class="docbook_option">malware</span>) condition. </p> <p> On the right-hand side of the <span class="docbook_option">demime</span> condition you can pass a colon-separated list of file extensions that it should match against. For example: </p> <div class="docbook_literallayout"><pre> deny message = Found blacklisted file attachment demime = vbs:com:bat:pif:prf:lnk </pre></div> <p> If one of the file extensions is found, the condition is true, otherwise it is false. If there is a temporary error while demimeing (for example, “disk full”), the condition defers, and the message is temporarily rejected (unless the condition is on a <span class="docbook_option">warn</span> verb). </p> <p> The right-hand side is expanded before being treated as a list, so you can have conditions and lookups there. If it expands to an empty string, “false”, or zero (“0”), no demimeing is done and the condition is false. </p> <p> The <span class="docbook_option">demime</span> condition set the following variables: </p> <dl> <dt>$demime_errorlevel</dt> <dd> <p> When an error is detected in a MIME container, this variable contains the severity of the error, as an integer number. The higher the value, the more severe the error (the current maximum value is 3). If this variable is unset or zero, no error occurred. </p> </dd> <dt>$demime_reason</dt> <dd> <p> When $demime_errorlevel is greater than zero, this variable contains a human-readable text string describing the MIME error that occurred. </p> </dd> </dl> <dl> <dt>$found_extension</dt> <dd> <p> When the <span class="docbook_option">demime</span> condition is true, this variable contains the file extension it found. </p> </dd> </dl> <p> Both $demime_errorlevel and $demime_reason are set by the first call of the <span class="docbook_option">demime</span> condition, and are not changed on subsequent calls. </p> <p> If you do not want to check for file extensions, but rather use the <span class="docbook_option">demime</span> condition for unpacking or error checking purposes, pass “*” as the right-hand side value. Here is a more elaborate example of how to use this facility: </p> <div class="docbook_literallayout"><pre> # Reject messages with serious MIME container errors deny message = Found MIME error ($demime_reason). demime = * condition = ${if >{$demime_errorlevel}{2}{1}{0}} # Reject known virus spreading file extensions. # Accepting these is pretty much braindead. deny message = contains $found_extension file (blacklisted). demime = com:vbs:bat:pif:scr # Freeze .exe and .doc files. Postmaster can # examine them and eventually thaw them. deny log_message = Another $found_extension file. demime = exe:doc control = freeze </pre></div> <p> </p> </div> </div> <a class="previous_page" href="ch40.html"><-previous</a><a class="next_page" href="ch42.html">next-></a> </div></div> <iframe id="branding" name="branding" src="../../../../branding/branding.html" height="0" frameborder="no" scrolling="no"></iframe><div id="footer">Website design by <a href="https://secure.grepular.com/">Mike Cardwell</a>, of <a href="http://cardwellit.com/">Cardwell IT Ltd.</a> </div> <div class="left_bar"></div> <div class="right_bar"></div> <div id="toc"> <ul class="hidden"></ul> <img src="../../../../doc/contents.png" width="16" height="155"> </div> </div> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script><script type="text/javascript" src="../../../../common.js"></script><script type="text/javascript" src="../../../../doc/chapter.js"></script> </body> </html>