From 71b32d412ac4792ca5e8d4a697afddb46c407bd9 Mon Sep 17 00:00:00 2001 From: Andrew Colin Kissa Date: Sun, 12 Mar 2017 19:14:47 +0000 Subject: [PATCH] Malware: new connection type "f-prot6d" for FPSCAND protocol over TCP --- doc/doc-docbook/spec.xfpt | 12 +++++ doc/doc-txt/NewStuff | 2 + src/src/malware.c | 57 ++++++++++++++++++++- test/confs/4011 | 29 +++++++++++ test/log/4011 | 11 +++++ test/paniclog/4011 | 2 + test/rejectlog/4011 | 24 +++++++++ test/scripts/4000-scanning/4011 | 88 +++++++++++++++++++++++++++++++++ test/stderr/4011 | 2 + test/stdout/4011 | 68 +++++++++++++++++++++++++ 10 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 test/confs/4011 create mode 100644 test/log/4011 create mode 100644 test/paniclog/4011 create mode 100644 test/rejectlog/4011 create mode 100644 test/scripts/4000-scanning/4011 create mode 100644 test/stderr/4011 create mode 100644 test/stdout/4011 diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 44f9d26ff..be93cf670 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -31539,6 +31539,18 @@ av_scanner = f-protd:localhost 10200-10204 .endd If you omit the argument, the default values show above are used. +.new +.vitem &%f-prot6d%& +.cindex "virus scanners" "f-prot6d" +The f-prot6d scanner is accessed using the FPSCAND protocol over TCP. +One argument is taken, being a space-separated hostname and port number. +For example: +.code +av_scanner = f-prot6d:localhost 10200 +.endd +If you omit the argument, the default values show above are used. +.wen + .vitem &%fsecure%& .cindex "virus scanners" "F-Secure" The F-Secure daemon scanner (&url(http://www.f-secure.com)) takes one diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 3594d1d6a..872371fcb 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -21,6 +21,8 @@ Version 4.90 making new TLS sessions, at the cost of having to proxy the data via another process. Logging is also affected. + 4. A malware connection type for the FPSCAND protocol. + Version 4.89 ------------ diff --git a/src/src/malware.c b/src/src/malware.c index 549422ebb..f9c4c414f 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -13,7 +13,7 @@ #ifdef WITH_CONTENT_SCAN typedef enum {M_FPROTD, M_DRWEB, M_AVES, M_FSEC, M_KAVD, M_CMDL, - M_SOPHIE, M_CLAMD, M_SOCK, M_MKSD, M_AVAST} scanner_t; + M_SOPHIE, M_CLAMD, M_SOCK, M_MKSD, M_AVAST, M_FPROT6D} scanner_t; typedef enum {MC_NONE, MC_TCP, MC_UNIX, MC_STRM} contype_t; static struct scan { @@ -34,6 +34,7 @@ static struct scan { M_SOCK, US"sock", US"/tmp/malware.sock", MC_STRM }, { M_MKSD, US"mksd", NULL, MC_NONE }, { M_AVAST, US"avast", US"/var/run/avast/scan.sock", MC_STRM }, + { M_FPROT6D, US"f-prot6d", US"localhost 10200", MC_TCP }, { -1, NULL, NULL, MC_NONE } /* end-marker */ }; @@ -84,6 +85,11 @@ static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d\\.\\d\\t\\d\\ static const pcre * ava_re_clean = NULL; static const pcre * ava_re_virus = NULL; +static const uschar * fprot6d_re_error_str = US "^\\d+\\s<(.+?)>$"; +static const uschar * fprot6d_re_virus_str = US "^\\d+\\s\\s+.+$"; +static const pcre * fprot6d_re_error = NULL; +static const pcre * fprot6d_re_virus = NULL; + /******************************************************************************/ @@ -1911,8 +1917,53 @@ if (!malware_ok) sock); default: break; } + break; } + + case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */ + { + int bread; + uschar * e; + uschar * linebuffer; + uschar * scanrequest; + uschar av_buffer[1024]; + + if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr))) + || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr)))) + return malware_errlog_defer(errstr); + + scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename); + DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n", + scanner_name, scanrequest); + + if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0) + return m_errlog_defer(scanent, CUS callout_address, errstr); + + bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL)); + + if (bread <= 0) + return m_errlog_defer_3(scanent, CUS callout_address, + string_sprintf("unable to read from socket (%s)", strerror(errno)), + sock); + + if (bread == sizeof(av_buffer)) + return m_errlog_defer_3(scanent, CUS callout_address, + US"buffer too small", sock); + + av_buffer[bread] = '\0'; + linebuffer = string_copy(av_buffer); + + m_sock_send(sock, US"QUIT\n", 5, 0); + + if ((e = m_pcre_exec(fprot6d_re_error, linebuffer))) + return m_errlog_defer_3(scanent, CUS callout_address, + string_sprintf("scanner reported error (%s)", e), sock); + + if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer))) + malware_name = NULL; + break; + } /* f-prot6d */ } /* scanner type switch */ if (sock >= 0) @@ -2028,6 +2079,10 @@ if (!ava_re_clean) ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE); if (!ava_re_virus) ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE); +if (!fprot6d_re_error) + fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE); +if (!fprot6d_re_virus) + fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE); } #endif /*WITH_CONTENT_SCAN*/ diff --git a/test/confs/4011 b/test/confs/4011 new file mode 100644 index 000000000..7be64dc6d --- /dev/null +++ b/test/confs/4011 @@ -0,0 +1,29 @@ +# Exim test configuration 4011 +# Content-scan: f-prot6d interface + +.include DIR/aux-var/std_conf_prefix + +primary_hostname = myhost.test.ex + +av_scanner = f-prot6d : localhost4 PORT_S + +# ----- Main settings ----- + +acl_smtp_rcpt = accept +acl_smtp_data = c_data + +begin acl + +c_data: + accept !malware = * OPT + deny logwrite = $callout_address malware_name $malware_name + +# ----- Routers ----- + +begin routers + +r: + driver = redirect + data = :blackhole: + +# End diff --git a/test/log/4011 b/test/log/4011 new file mode 100644 index 000000000..48f0f886c --- /dev/null +++ b/test/log/4011 @@ -0,0 +1,11 @@ +1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss +1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: R=r +1999-03-02 09:44:33 10HmbA-0005vi-00 Completed +1999-03-02 09:44:33 10HmaZ-0005vi-00 [127.0.0.1]:1111 malware_name EICAR_Test_File +1999-03-02 09:44:33 10HmaZ-0005vi-00 U=CALLER F= rejected after DATA +1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: f-prot6d [127.0.0.1]:1111 : unable to read from socket (Connection timed out) +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 acl condition: f-prot6d [127.0.0.1]:1111 : unable to read from socket (Connection timed out) +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss +1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: R=r +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed diff --git a/test/paniclog/4011 b/test/paniclog/4011 new file mode 100644 index 000000000..73c3c0111 --- /dev/null +++ b/test/paniclog/4011 @@ -0,0 +1,2 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: f-prot6d [127.0.0.1]:1111 : unable to read from socket (Connection timed out) +1999-03-02 09:44:33 10HmaY-0005vi-00 malware acl condition: f-prot6d [127.0.0.1]:1111 : unable to read from socket (Connection timed out) diff --git a/test/rejectlog/4011 b/test/rejectlog/4011 new file mode 100644 index 000000000..adeded6fb --- /dev/null +++ b/test/rejectlog/4011 @@ -0,0 +1,24 @@ +1999-03-02 09:44:33 10HmaZ-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 10HmaZ-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 +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: message should be deferred due to timeout +I Message-Id: +F From: CALLER_NAME diff --git a/test/scripts/4000-scanning/4011 b/test/scripts/4000-scanning/4011 new file mode 100644 index 000000000..20e6ab2b8 --- /dev/null +++ b/test/scripts/4000-scanning/4011 @@ -0,0 +1,88 @@ +# content scan interface: f-prot6d +need_ipv4 +munge loopback +# +server PORT_S +0 +>*eof +**** +# +# +# +exim -odi -bs -DOPT= +ehlo test.ex +mail from:<> +rcpt to: +data +Date: Fri, 17 Dec 2004 14:35:01 +0100 +Subject: message should be accepted + +. +quit +**** +# +# +# +server PORT_S +0 DIR/spool/scan/1clxBT-0003I9-8y/1clxBT-0003I9-8y.eml +>*eof +**** +# +# +# +exim -odi -bs -DOPT= +ehlo test.ex +mail from:<> +rcpt to: +data +Date: Fri, 17 Dec 2004 14:35:01 +0100 +Subject: message should be rejected + +due to the server response (above) +. +quit +**** +# +# +# +server PORT_S + +rcpt to: +data +Date: Fri, 17 Dec 2004 14:35:01 +0100 +Subject: message should be deferred due to timeout + +. +quit +**** +# +# +# +server PORT_S + +rcpt to: +data +Date: Fri, 17 Dec 2004 14:35:01 +0100 +Subject: message should be accepted despite timeout + +. +quit +**** diff --git a/test/stderr/4011 b/test/stderr/4011 new file mode 100644 index 000000000..73c3c0111 --- /dev/null +++ b/test/stderr/4011 @@ -0,0 +1,2 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: f-prot6d [127.0.0.1]:1111 : unable to read from socket (Connection timed out) +1999-03-02 09:44:33 10HmaY-0005vi-00 malware acl condition: f-prot6d [127.0.0.1]:1111 : unable to read from socket (Connection timed out) diff --git a/test/stdout/4011 b/test/stdout/4011 new file mode 100644 index 000000000..dd4eddeee --- /dev/null +++ b/test/stdout/4011 @@ -0,0 +1,68 @@ +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=10HmbA-0005vi-00 +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 +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 +250 OK id=10HmaY-0005vi-00 +221 myhost.test.ex closing connection + +******** SERVER ******** +Listening on port 1224 ... +Connection request from [IP_LOOPBACK_ADDR] +0 +>*eof +End of script +Listening on port 1224 ... +Connection request from [IP_LOOPBACK_ADDR] +0 DIR/spool/scan/10HmbB-0005vi-00/10HmbB-0005vi-00.eml +>*eof +End of script +Listening on port 1224 ... +Connection request from [IP_LOOPBACK_ADDR] +