Avast: implement pass_unscanned option
authorHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Mon, 2 Apr 2018 15:39:39 +0000 (17:39 +0200)
committerHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Mon, 2 Apr 2018 20:12:44 +0000 (22:12 +0200)
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/src/malware.c
test/log/4017
test/rejectlog/4017
test/scripts/4017_scan_avast_multiline/4017
test/stdout/4017

index 6353e29fb8f4edb1ddf4ee7df08367992fa6c1a8..f455c9f0c7515fae848739872e8977fdba1ec830 100644 (file)
@@ -31858,9 +31858,7 @@ If the value of &%av_scanner%& starts with a dollar character, it is expanded
 before use.
 The usual list-parsing of the content (see &<<SECTlistconstruct>>&) applies.
 The following scanner types are supported in this release,
-.new
 though individual ones can be included or not at build time:
-.wen
 
 .vlist
 .vitem &%avast%&
@@ -31874,11 +31872,22 @@ which can be either a full path to a UNIX socket,
 or host and port specifiers separated by white space.
 The host may be a name or an IP address; the port is either a
 single number or a pair of numbers with a dash between.
-Any further options are given, on separate lines,
-to the daemon as options before the main scan command.
+A list of options may follow. These options are interpreted on the
+Exim's side of the malware scanner, or are given on separate lines to
+the daemon as options before the main scan command.
+
+.new
+.cindex &`pass_unscanned`& "avast"
+If &`pass_unscanned`&
+is set, any files the Avast scanner can't scan (e.g.
+decompression bombs, or invalid archives) are considered clean. Use with
+care.
+.wen
+
 For example:
 .code
 av_scanner = avast:/var/run/avast/scan.sock:FLAGS -fullfiles:SENSITIVITY -pup
+av_scanner = avast:/var/run/avast/scan.sock:pass_unscanned:FLAGS -fullfiles:SENSITIVITY -pup
 av_scanner = avast:192.168.2.22 5036
 .endd
 If you omit the argument, the default path
@@ -31895,13 +31904,9 @@ $ socat UNIX:/var/run/avast/scan.sock STDIO:
     PACK
 .endd
 
-A paniclog entry is logged and the message is deferred (except the
-malware condition uses "defer_ok") if the scanner returns a tmpfail
-(e.g. on license issues, or permission problems). If the scanner can't
-scan a file for internal reasons (e.g. decompression bomb), this is
-treated as an infection and malware_name is set to the error message.
-We do this err on the safe side.
-
+If the scanner returns a temporary failure (e.g. license issues, or
+permission problems), the message is deferred and a paniclog entry is
+written.  The usual &`defer_ok`& option is available.
 
 .vitem &%aveserver%&
 .cindex "virus scanners" "Kaspersky"
@@ -31952,7 +31957,7 @@ av_scanner = clamd:192.0.2.3 1234 : 192.0.2.4 1234
 If the value of av_scanner points to a UNIX socket file or contains the
 &`local`&
 option, 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
+to be scanned, which 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.
 
index 837b38083b729b73ab2c23d3da87d29a6a230cb6..a18c57e3cec16ec8f7f062d3b63e506cbea5e02e 100644 (file)
@@ -190,11 +190,11 @@ JH/35 Cutthrough: for a final-dot response timeout (and nonunderstood responses)
 PP/02 DANE: add dane_require_tls_ciphers SMTP Transport option; if unset,
       tls_require_ciphers is used as before.
 
-HS/03 Malware Avast: Better match the Avast multiline protocol.
-      Only tmpfails from the scanner are written to the paniclog, as
-      they may require admin intervention (permission denied, license
-      issues). Other scanner errors (like decompression bombs) do not
-      cause a paniclog entry.
+HS/03 Malware Avast: Better match the Avast multiline protocol. Add
+      "pass_unscanned".  Only tmpfails from the scanner are written to
+      the paniclog, as they may require admin intervention (permission
+      denied, license issues). Other scanner errors (like decompression
+      bombs) do not cause a paniclog entry.
 
 
 Exim version 4.90
index 4bf04ec8ddbaf9de7e28bd030411c3ec33337093..ea190aafb3e5f480ca83230d81ea24291a120c87 100644 (file)
@@ -54,6 +54,10 @@ Version 4.91
     the running exim instance. If the cluster has master/slave replication, the
     list must contain all the master and slave servers.
 
+16. Add an option to the Avast scanner interface: "pass_unscanned". This
+    allows to treat unscanned files as clean. Files may be unscanned for
+    several reasons: decompression bombs, broken archives.
+
 
 Version 4.90
 ------------
index 7c57c0090058fd0d66f7e086a7a8352acc28d0f0..730a2be22389330608576d7c5c6d6532db64eff9 100644 (file)
@@ -1921,13 +1921,14 @@ b_seek:   err = errno;
 #ifndef DISABLE_MAL_AVAST
     case M_AVAST: /* "avast" scanner type ----------------------------------- */
       {
-      int ovector[10*3];
+      int ovector[3*3];
       uschar buf[1024];
       uschar * scanrequest;
       enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
       int nread;
       int more_data;
       uschar * error_message = NULL;
+      int strict = TRUE;
 
       /* According to Martin Tuma @avast the protocol uses "escaped
       whitespace", that is, every embedded whitespace is backslash
@@ -2015,6 +2016,12 @@ b_seek:   err = errno;
              if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
                                NULL, 0)))
                {
+                if (Ustrcmp(scanrequest, "pass_unscanned") == 0)
+                  {
+                  DEBUG(D_acl) debug_printf_indent("pass unscanned files as clean\n");
+                  strict = FALSE;
+                  goto sendreq;
+                  }
                scanrequest = string_sprintf("%s\n", scanrequest);
                avast_stage = AVA_OPT;          /* just sent option */
                DEBUG(D_acl) debug_printf_indent("send to avast OPTION: %s", scanrequest);
@@ -2055,19 +2062,13 @@ b_seek:   err = errno;
                 goto endloop;
                }
 
-              #if 0
-              /* found malware or another error already, nothing to do anymore, just read on */
-              if (malware_name || error_message)
+              if (malware_name) /* nothing else matters, just read on */
                 break;
-              #endif
 
              if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
                    0, 0, ovector, nelem(ovector)) > 0)
                break;
 
-             if (malware_name)
-                break;
-
               if (malware_name = m_pcre_exec(ava_re_virus, buf))
                 {
                 unescape(malware_name);
@@ -2076,10 +2077,7 @@ b_seek:   err = errno;
                 break;
                 }
 
-              /*if (pcre_exec(ava_re_error, NULL, CS buf, nread, 0, 0, ovector, nelem(ovector)) == 2)
-              unescape(malware_name = buf + ovector[1*2]);
-              */
-              if (malware_name = m_pcre_exec(ava_re_error, buf))
+              if (strict && (malware_name = m_pcre_exec(ava_re_error, buf)))
                 {
                 unescape(malware_name);
                 DEBUG(D_acl)
@@ -2087,7 +2085,15 @@ b_seek:   err = errno;
                 break;
                 }
 
+              if (pcre_exec(ava_re_error, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
+                {
+                log_write(0, LOG_MAIN, "internal scanner error (ignored): %s", buf);
+                break;
+                }
+
              /* here also for any unexpected response from the scanner */
+              DEBUG(D_acl) debug_printf("avast response not handled: '%s'\n", buf);
+              error_message = string_sprintf(string_sprintf("unexpected response from scanner: '%s'", buf));
              goto endloop;
 
            default:    log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
index 480ac5d19cdc15fb0ee7a58215bcf2145670e1a3..9d07f31bf861a6b195ac1a44fb1620c0a763abdc 100644 (file)
@@ -1,9 +1,15 @@
-1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss T="message should be accepted"
-1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <userx@test.ex> R=r
-1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss T="message should be accepted"
+1999-03-02 09:44:33 10HmbB-0005vi-00 => :blackhole: <userx@test.ex> R=r
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : 451 SCAN Engine error 13 Permission denied
 1999-03-02 09:44:33 10HmaX-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> temporarily rejected after DATA
 1999-03-02 09:44:33 10HmaY-0005vi-00 malware_name This is not even an EICAR test virus.
 1999-03-02 09:44:33 10HmaY-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
 1999-03-02 09:44:33 10HmaZ-0005vi-00 malware_name The file is a decompression bomb
 1999-03-02 09:44:33 10HmaZ-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
+1999-03-02 09:44:33 10HmbA-0005vi-00 malware_name The file is a decompression bomb
+1999-03-02 09:44:33 10HmbA-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
+1999-03-02 09:44:33 10HmbC-0005vi-00 internal scanner error (ignored): /bin/error      [E]0.0  Error 42110 The\ file\ is\ a\ decompression\ bomb
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss T="message should be accepted"
+1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <userx@test.ex> R=r
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
index ca3f3888f1867b53dfcc89bc77a8adb1fe4bdcca..670b9057bb6a3ebe73a5bf508478bc30c880edae 100644 (file)
@@ -34,3 +34,15 @@ P Received: from CALLER (helo=test.ex)
   Subject: message should be rejected
 I Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
 F From: CALLER_NAME <CALLER@myhost.test.ex>
+1999-03-02 09:44:33 10HmbA-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
+Envelope-from: <CALLER@myhost.test.ex>
+Envelope-to: <userx@test.ex>
+P Received: from CALLER (helo=test.ex)
+       by myhost.test.ex with local-esmtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbA-0005vi-00
+       for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+  Date: Tue, 2 Mar 1999 09:44:33 +0000
+  Subject: message should be rejected
+I Message-Id: <E10HmbA-0005vi-00@myhost.test.ex>
+F From: CALLER_NAME <CALLER@myhost.test.ex>
index 3e6b067131016fff7cb24559ef03016de884b068..3f888ea63794ff300c31434463254468ee590549 100644 (file)
@@ -110,3 +110,57 @@ Subject: message should be rejected
 .
 quit
 ****
+#
+#
+# clean, error -> reject
+server DIR/eximdir/avast_sock
+>LF>220 ready
+<SCAN
+>LF>210 SCAN DATA
+>LF>/bin/clean [+]
+>LF>/bin/error [E]0.0  Error 42110 The\\ file\\ is\\ a\\ decompression\\ bomb
+>LF>200 SCAN OK
+<QUIT
+*eof
+****
+#
+#
+#
+exim -odi -bs -DOPTION= -DINSERT=
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be rejected
+
+.
+quit
+****
+#
+#
+# clean, error (pass_unscanned) -> accept
+server DIR/eximdir/avast_sock
+>LF>220 ready
+<SCAN
+>LF>210 SCAN DATA
+>LF>/bin/clean [+]
+>LF>/bin/error [E]0.0  Error 42110 The\\ file\\ is\\ a\\ decompression\\ bomb
+>LF>200 SCAN OK
+<QUIT
+*eof
+****
+#
+#
+#
+exim -odi -bs -DOPTION=pass_unscanned -DINSERT=
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be accepted
+
+.
+quit
+****
index 388af3dd435c62c58f39fdd1601003d2d29f866a..7d731ae90d49c66437fcfddf9c30ac09032e67ba 100644 (file)
@@ -8,7 +8,7 @@
 250 OK\r
 250 Accepted\r
 354 Enter message, ending with "." on a line by itself\r
-250 OK id=10HmbA-0005vi-00\r
+250 OK id=10HmbB-0005vi-00\r
 221 myhost.test.ex closing connection\r
 ### scanner tmpfail -> defer
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 354 Enter message, ending with "." on a line by itself\r
 550 Administrative prohibition\r
 221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+550 Administrative prohibition\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmbC-0005vi-00\r
+221 myhost.test.ex closing connection\r
 
 ******** SERVER ********
 ### clean |  multiline response
@@ -55,7 +77,7 @@ Connection request
 >LF>FLAGS -fullfiles
 >LF>FLAGS +extra
 >LF>200 FLAGS OK
-<SCAN TESTSUITE/spool/scan/10HmbA-0005vi-00
+<SCAN TESTSUITE/spool/scan/10HmbB-0005vi-00
 >LF>210 SCAN DATA
 >LF>/bin/clean1\x09[+]
 >LF>/bin/clean2\x09[+]
@@ -97,3 +119,25 @@ Connection request
 <QUIT
 Expected EOF read from client
 End of script
+Listening on TESTSUITE/eximdir/avast_sock ... 
+Connection request
+>LF>220 ready
+<SCAN TESTSUITE/spool/scan/10HmbA-0005vi-00
+>LF>210 SCAN DATA
+>LF>/bin/clean\x09[+]
+>LF>/bin/error\x09[E]0.0\x09Error 42110 The\\ file\\ is\\ a\\ decompression\\ bomb
+>LF>200 SCAN OK
+<QUIT
+Expected EOF read from client
+End of script
+Listening on TESTSUITE/eximdir/avast_sock ... 
+Connection request
+>LF>220 ready
+<SCAN TESTSUITE/spool/scan/10HmbC-0005vi-00
+>LF>210 SCAN DATA
+>LF>/bin/clean\x09[+]
+>LF>/bin/error\x09[E]0.0\x09Error 42110 The\\ file\\ is\\ a\\ decompression\\ bomb
+>LF>200 SCAN OK
+<QUIT
+Expected EOF read from client
+End of script