From 71bb51e08dc03f768d19f237fed415bc74246de3 Mon Sep 17 00:00:00 2001 From: "Heiko Schlittermann (HS12-RIPE)" Date: Sat, 10 Mar 2018 04:30:56 +0100 Subject: [PATCH] Update to protocol used by avast 2.2.0 (Multiline responses) (Bug 2112) Based on a patch by Victor Ustugov. --- doc/doc-docbook/spec.xfpt | 8 +- doc/doc-txt/ChangeLog | 3 + src/src/malware.c | 55 +++++++----- test/confs/4017 | 1 + test/log/4017 | 7 ++ test/paniclog/4017 | 1 + test/rejectlog/4017 | 24 ++++++ test/scripts/4017_scan_avast_multiline/4017 | 86 +++++++++++++++++++ .../4017_scan_avast_multiline/REQUIRES | 2 + test/stderr/4017 | 7 ++ test/stdout/4017 | 76 ++++++++++++++++ 11 files changed, 246 insertions(+), 24 deletions(-) create mode 120000 test/confs/4017 create mode 100644 test/log/4017 create mode 100644 test/paniclog/4017 create mode 100644 test/rejectlog/4017 create mode 100644 test/scripts/4017_scan_avast_multiline/4017 create mode 100644 test/scripts/4017_scan_avast_multiline/REQUIRES create mode 100644 test/stderr/4017 create mode 100644 test/stdout/4017 diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index f950a4dac..cf80e92f7 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -31806,9 +31806,9 @@ though individual ones can be included or not at build time: .vitem &%avast%& .cindex "virus scanners" "avast" This is the scanner daemon of Avast. It has been tested with Avast Core -Security (currently at version 1.1.7). -You can get a trial version at &url(http://www.avast.com) or for Linux -at &url(http://www.avast.com/linux-server-antivirus). +Security (currently at version 2.2.0). +You can get a trial version at &url(https://www.avast.com) or for Linux +at &url(https://www.avast.com/linux-server-antivirus). This scanner type takes one option, which can be either a full path to a UNIX socket, or host and port specifiers separated by white space. @@ -31835,6 +31835,8 @@ $ socat UNIX:/var/run/avast/scan.sock STDIO: PACK .endd +Only the first virus detected will be reported. + .vitem &%aveserver%& .cindex "virus scanners" "Kaspersky" diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index e4ad9f0c5..786df0506 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -138,6 +138,9 @@ JH/26 Bug 2253: For logging delivery lines under PRDR, append the overall JH/27 Bug 2251: Fix ldap lookups that return a single attribute having zero- length value. Previously this would segfault. +HS/02 Support Avast multiline protoocol, this allows passing flags to + newer versions of the scanner. + Exim version 4.90 ----------------- diff --git a/src/src/malware.c b/src/src/malware.c index 5b9d5ad58..948aedea1 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -1893,6 +1893,7 @@ b_seek: err = errno; uschar * scanrequest; enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage; int nread; + int more_data; /* According to Martin Tuma @avast the protocol uses "escaped whitespace", that is, every embedded whitespace is backslash @@ -1902,7 +1903,9 @@ b_seek: err = errno; [+] - not infected [L] - infected [E] - some error occured - Such marker follows the first non-escaped TAB. */ + Such marker follows the first non-escaped TAB. For more information + see avast-protocol(5) + */ if ( ( !ava_re_clean && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr))) || ( !ava_re_virus @@ -1918,17 +1921,25 @@ b_seek: err = errno; int slen = Ustrlen(buf); if (slen >= 1) { - DEBUG(D_acl) debug_printf_indent("got from avast: %s\n", buf); + + /* Multi line responses are bracketed between 210 … and nnn … */ + if (Ustrncmp(buf, "210", 3) == 0) + { + more_data = 1; + continue; + } + else if (more_data && isdigit(buf[0])) more_data = 0; + switch (avast_stage) { case AVA_HELO: + if (more_data) continue; if (Ustrncmp(buf, "220", 3) != 0) goto endloop; /* require a 220 */ goto sendreq; case AVA_OPT: - if (Ustrncmp(buf, "210", 3) == 0) - break; /* ignore 210 responses */ + if (more_data) continue; if (Ustrncmp(buf, "200", 3) != 0) goto endloop; /* require a 200 */ @@ -1941,11 +1952,13 @@ b_seek: err = errno; { 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); } else { scanrequest = string_sprintf("SCAN %s\n", eml_dir); avast_stage = AVA_RSP; /* just sent command */ + DEBUG(D_acl) debug_printf_indent("send to avast REQUEST: SCAN %s\n", eml_dir); } /* send config-cmd or scan-request to socket */ @@ -1961,15 +1974,27 @@ b_seek: err = errno; } case AVA_RSP: - if (Ustrncmp(buf, "210", 3) == 0) - break; /* ignore the "210 SCAN DATA" message */ + + if (Ustrncmp(buf, "200", 3) == 0) + { /* we're done finally */ + if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */ + return m_errlog_defer_3(scanent, CUS callout_address, + string_sprintf( + "unable to send quit request to socket (%s): %s", + scanner_options, strerror(errno)), + sock); + + avast_stage = AVA_DONE; + goto endloop; + } + + if (malware_name) break; /* found malware already, nothing to do anymore */ if (pcre_exec(ava_re_clean, NULL, CS buf, slen, 0, 0, ovector, nelem(ovector)) > 0) break; - if ( !malware_name - && (malware_name = m_pcre_exec(ava_re_virus, buf))) + if (malware_name = m_pcre_exec(ava_re_virus, buf)) { /* remove backslash in front of [whitespace|backslash] */ uschar * p, * p0; for (p = malware_name; *p; ++p) @@ -1977,22 +2002,10 @@ b_seek: err = errno; for (p0 = p; *p0; ++p0) *p0 = p0[1]; DEBUG(D_acl) - debug_printf_indent("unescaped m-name: '%s'\n", malware_name); + debug_printf_indent("unescaped malware name: '%s'\n", malware_name); break; } - if (Ustrncmp(buf, "200 SCAN OK", 11) == 0) - { /* we're done finally */ - if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */ - return m_errlog_defer_3(scanent, CUS callout_address, - string_sprintf( - "unable to send quit request to socket (%s): %s", - scanner_options, strerror(errno)), - sock); - - avast_stage = AVA_DONE; - } - /* here also for any unexpected response from the scanner */ goto endloop; diff --git a/test/confs/4017 b/test/confs/4017 new file mode 120000 index 000000000..cf237193b --- /dev/null +++ b/test/confs/4017 @@ -0,0 +1 @@ +4007 \ No newline at end of file diff --git a/test/log/4017 b/test/log/4017 new file mode 100644 index 000000000..cd53a5c39 --- /dev/null +++ b/test/log/4017 @@ -0,0 +1,7 @@ +1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss T="message should be accepted" +1999-03-02 09:44:33 10HmaZ-0005vi-00 => :blackhole: R=r +1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed +1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : invalid response from scanner: '/bin/error [E]0.0' +1999-03-02 09:44:33 10HmaX-0005vi-00 U=CALLER F= temporarily rejected after DATA +1999-03-02 09:44:33 10HmaY-0005vi-00 malware_name This ist not even an EICAR test virus. +1999-03-02 09:44:33 10HmaY-0005vi-00 U=CALLER F= rejected after DATA diff --git a/test/paniclog/4017 b/test/paniclog/4017 new file mode 100644 index 000000000..b6fcc0527 --- /dev/null +++ b/test/paniclog/4017 @@ -0,0 +1 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : invalid response from scanner: '/bin/error [E]0.0' diff --git a/test/rejectlog/4017 b/test/rejectlog/4017 new file mode 100644 index 000000000..f14a316b7 --- /dev/null +++ b/test/rejectlog/4017 @@ -0,0 +1,24 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 U=CALLER F= temporarily rejected after DATA +Envelope-from: +Envelope-to: +P Received: from CALLER (helo=test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmaX-0005vi-00 + for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000 + Date: Tue, 2 Mar 1999 09:44:33 +0000 + Subject: defer this one, the scanner had an error +I Message-Id: +F From: CALLER_NAME +1999-03-02 09:44:33 10HmaY-0005vi-00 U=CALLER F= rejected after DATA +Envelope-from: +Envelope-to: +P Received: from CALLER (helo=test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmaY-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: +F From: CALLER_NAME diff --git a/test/scripts/4017_scan_avast_multiline/4017 b/test/scripts/4017_scan_avast_multiline/4017 new file mode 100644 index 000000000..d075825b8 --- /dev/null +++ b/test/scripts/4017_scan_avast_multiline/4017 @@ -0,0 +1,86 @@ +# content scan interface: avast +### clean | multiline response +server DIR/eximdir/avast_sock +>LF>220 ready +LF>210 FLAGS DATA +>LF>FLAGS -fullfiles +>LF>FLAGS +extra +>LF>200 FLAGS OK +LF>210 SCAN DATA +>LF>/bin/clean1 [+] +>LF>/bin/clean2 [+] +>LF>200 SCAN OK + +rcpt to: +data +Date: Fri, 17 Dec 2004 14:35:01 +0100 +Subject: message should be accepted + +. +quit +**** +# +# +### clean and error | multiline response +server DIR/eximdir/avast_sock +>LF>220 ready +LF>210 SCAN DATA +>LF>/bin/ok [+] +>LF>/bin/error [E]0.0 +>LF>/bin/infected [L]0.0 0 This is not even EICAR! +>LF>200 SCAN OK + +rcpt to: +data +Date: Fri, 17 Dec 2004 14:35:01 +0100 +Subject: defer this one, the scanner had an error + +. +quit +**** +# +# +# clean and infected | multiline response +server DIR/eximdir/avast_sock +>LF>220 ready +LF>210 SCAN DATA +>LF>/bin/clean [+] +>LF>v\\ i\\ a\\ r\\ u\\ s [L]9.9 9 This ist not even an EICAR test virus. +>LF>200 SCAN OK + +rcpt to: +data +Date: Fri, 17 Dec 2004 14:35:01 +0100 +Subject: message should be rejected + +. +quit +**** diff --git a/test/scripts/4017_scan_avast_multiline/REQUIRES b/test/scripts/4017_scan_avast_multiline/REQUIRES new file mode 100644 index 000000000..d5a69793c --- /dev/null +++ b/test/scripts/4017_scan_avast_multiline/REQUIRES @@ -0,0 +1,2 @@ +support Content_Scanning +malware avast diff --git a/test/stderr/4017 b/test/stderr/4017 new file mode 100644 index 000000000..22157c3d1 --- /dev/null +++ b/test/stderr/4017 @@ -0,0 +1,7 @@ +### clean | multiline response +### clean and error | multiline response +1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : invalid response from scanner: '/bin/error [E]0.0' + +******** SERVER ******** +### clean | multiline response +### clean and error | multiline response diff --git a/test/stdout/4017 b/test/stdout/4017 new file mode 100644 index 000000000..e46e8f3fd --- /dev/null +++ b/test/stdout/4017 @@ -0,0 +1,76 @@ +### clean | multiline response +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmaZ-0005vi-00 +221 myhost.test.ex closing connection +### clean and error | multiline response +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +354 Enter message, ending with "." on a line by itself +451 Temporary local problem - please try later +221 myhost.test.ex closing connection +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +354 Enter message, ending with "." on a line by itself +550 Administrative prohibition +221 myhost.test.ex closing connection + +******** SERVER ******** +### clean | multiline response +Listening on TESTSUITE/eximdir/avast_sock ... +Connection request +>LF>220 ready +LF>210 FLAGS DATA +>LF>FLAGS -fullfiles +>LF>FLAGS +extra +>LF>200 FLAGS OK +LF>210 SCAN DATA +>LF>/bin/clean1\x09[+] +>LF>/bin/clean2\x09[+] +>LF>200 SCAN OK +LF>220 ready +LF>210 SCAN DATA +>LF>/bin/ok\x09[+] +>LF>/bin/error\x09[E]0.0 +>LF>/bin/infected\x09[L]0.0\x090 This is not even EICAR! +>LF>200 SCAN OK +Unexpected EOF read from client +Listening on TESTSUITE/eximdir/avast_sock ... +Connection request +>LF>220 ready +LF>210 SCAN DATA +>LF>/bin/clean\x09[+] +>LF>v\\ i\\ a\\ r\\ u\\ s\x09[L]9.9\x099 This ist not even an EICAR test virus. +>LF>200 SCAN OK +