X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fmalware.c;h=d24f09b88794035fd33c89ceed083de2e8022a81;hb=c9cf9ac495443d40a9196d9f402313a11a83fae9;hp=f9b99193d627bd6aef794f19a2219eb2e5b29da7;hpb=acec9514b1006e352ef283f205ecec75a9b6ff0d;p=exim.git diff --git a/src/src/malware.c b/src/src/malware.c index f9b99193d..d24f09b88 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -4,13 +4,13 @@ /* Copyright (c) Tom Kistner 2003 - 2015 * License: GPL - * Copyright (c) The Exim Maintainers 2016 + * Copyright (c) The Exim Maintainers 2015 - 2018 */ /* Code for calling virus (malware) scanners. Called from acl.c. */ #include "exim.h" -#ifdef WITH_CONTENT_SCAN +#ifdef WITH_CONTENT_SCAN /* entire file */ typedef enum {M_FPROTD, M_DRWEB, M_AVES, M_FSEC, M_KAVD, M_CMDL, M_SOPHIE, M_CLAMD, M_SOCK, M_MKSD, M_AVAST, M_FPROT6D} scanner_t; @@ -23,72 +23,131 @@ static struct scan contype_t conn; } m_scans[] = { +#ifndef DISABLE_MAL_FFROTD { M_FPROTD, US"f-protd", US"localhost 10200-10204", MC_TCP }, +#endif +#ifndef DISABLE_MAL_FFROT6D + { M_FPROT6D, US"f-prot6d", US"localhost 10200", MC_TCP }, +#endif +#ifndef DISABLE_MAL_DRWEB { M_DRWEB, US"drweb", US"/usr/local/drweb/run/drwebd.sock", MC_STRM }, +#endif +#ifndef DISABLE_MAL_AVE { M_AVES, US"aveserver", US"/var/run/aveserver", MC_UNIX }, +#endif +#ifndef DISABLE_MAL_FSECURE { M_FSEC, US"fsecure", US"/var/run/.fsav", MC_UNIX }, +#endif +#ifndef DISABLE_MAL_KAV { M_KAVD, US"kavdaemon", US"/var/run/AvpCtl", MC_UNIX }, - { M_CMDL, US"cmdline", NULL, MC_NONE }, +#endif +#ifndef DISABLE_MAL_SOPHIE { M_SOPHIE, US"sophie", US"/var/run/sophie", MC_UNIX }, +#endif +#ifndef DISABLE_MAL_CLAM { M_CLAMD, US"clamd", US"/tmp/clamd", MC_NONE }, - { M_SOCK, US"sock", US"/tmp/malware.sock", MC_STRM }, +#endif +#ifndef DISABLE_MAL_MKS { M_MKSD, US"mksd", NULL, MC_NONE }, +#endif +#ifndef DISABLE_MAL_AVAST { M_AVAST, US"avast", US"/var/run/avast/scan.sock", MC_STRM }, - { M_FPROT6D, US"f-prot6d", US"localhost 10200", MC_TCP }, +#endif +#ifndef DISABLE_MAL_SOCK + { M_SOCK, US"sock", US"/tmp/malware.sock", MC_STRM }, +#endif +#ifndef DISABLE_MAL_CMDLINE + { M_CMDL, US"cmdline", NULL, MC_NONE }, +#endif { -1, NULL, NULL, MC_NONE } /* end-marker */ }; +/******************************************************************************/ +# ifdef MACRO_PREDEF /* build solely to predefine macros */ + +# include "macro_predef.h" + +void +features_malware(void) +{ +const struct scan * sc; +const uschar * s; +uschar * t; +uschar buf[64]; + +spf(buf, sizeof(buf), US"_HAVE_MALWARE_"); + +for (sc = m_scans; sc->scancode != -1; sc++) + { + for(s = sc->name, t = buf+14; *s; s++) if (*s != '-') *t++ = toupper(*s); + *t = '\0'; + builtin_macro_create(buf); + } +} + +/******************************************************************************/ +# else /*!MACRO_PREDEF, main build*/ + + +#define MALWARE_TIMEOUT 120 /* default timeout, seconds */ + +static const uschar * malware_regex_default = US ".+"; +static const pcre * malware_default_re = NULL; + + + +#ifndef DISABLE_MAL_CLAM /* The maximum number of clamd servers that are supported in the configuration */ -#define MAX_CLAMD_SERVERS 32 -#define MAX_CLAMD_SERVERS_S "32" +# define MAX_CLAMD_SERVERS 32 +# define MAX_CLAMD_SERVERS_S "32" typedef struct clamd_address { uschar * hostspec; unsigned tcp_port; unsigned retry; } clamd_address; - -#ifndef nelements -# define nelements(arr) (sizeof(arr) / sizeof(arr[0])) #endif -#define MALWARE_TIMEOUT 120 /* default timeout, seconds */ - - -#define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */ -#define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */ -#define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */ - -#define DERR_READ_ERR (1<<0) /* read error */ -#define DERR_NOMEMORY (1<<2) /* no memory */ -#define DERR_TIMEOUT (1<<9) /* scan timeout has run out */ -#define DERR_BAD_CALL (1<<15) /* wrong command */ +#ifndef DISABLE_MAL_DRWEB +# define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */ +# define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */ +# define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */ - -static const uschar * malware_regex_default = US ".+"; -static const pcre * malware_default_re = NULL; +# define DERR_READ_ERR (1<<0) /* read error */ +# define DERR_NOMEMORY (1<<2) /* no memory */ +# define DERR_TIMEOUT (1<<9) /* scan timeout has run out */ +# define DERR_BAD_CALL (1<<15) /* wrong command */ static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$"; static const pcre * drweb_re = NULL; +#endif +#ifndef DISABLE_MAL_FSECURE static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$"; static const pcre * fsec_re = NULL; +#endif +#ifndef DISABLE_MAL_KAV static const uschar * kav_re_sus_str = US "suspicion:\\s*(.+?)\\s*$"; static const uschar * kav_re_inf_str = US "infected:\\s*(.+?)\\s*$"; static const pcre * kav_re_sus = NULL; static const pcre * kav_re_inf = NULL; +#endif +#ifndef DISABLE_MAL_AVAST static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]"; static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d\\.\\d\\t\\d\\s(.*)"; static const pcre * ava_re_clean = NULL; static const pcre * ava_re_virus = NULL; +#endif +#ifndef DISABLE_MAL_FFROT6D 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; +#endif @@ -142,6 +201,7 @@ return m_errlog_defer(scanent, hostport, str); /*************************************************/ +#ifndef DISABLE_MAL_CLAM /* Only used by the Clamav code, which is working from a list of servers and uses the returned in_addr to get a second connection to the same system. */ @@ -152,6 +212,7 @@ m_tcpsocket(const uschar * hostname, unsigned int port, return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5, host, errstr, fastopen_blob); } +#endif static int m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr) @@ -186,7 +247,7 @@ m_pcre_exec(const pcre * cre, uschar * text) { int ovector[10*3]; int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0, - ovector, nelements(ovector)); + ovector, nelem(ovector)); uschar * substr = NULL; if (i >= 2) /* Got it */ pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr); @@ -263,9 +324,10 @@ return fd_ready(sock, tmo-time(NULL)) +#ifndef DISABLE_MAL_MKS /* ============= private routines for the "mksd" scanner type ============== */ -#include +# include static inline int mksd_writev (int sock, struct iovec * iov, int iovcnt) @@ -388,8 +450,10 @@ if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0) return mksd_parse_line (scanent, CS av_buffer); } +#endif /* MKSD */ +#ifndef DISABLE_MAL_CLAM static int clamd_option(clamd_address * cd, const uschar * optstr, int * subsep) { @@ -408,6 +472,9 @@ while ((s = string_nextinlist(&optstr, subsep, NULL, 0))) return FAIL; return OK; } +#endif + + /************************************************* * Scan content for malware * @@ -531,6 +598,7 @@ if (!malware_ok) switch (scanent->scancode) { +#ifndef DISABLE_MAL_FFROTD case M_FPROTD: /* "f-protd" scanner type -------------------------------- */ { uschar *fp_scan_option; @@ -584,7 +652,56 @@ if (!malware_ok) } break; } /* f-protd */ +#endif + +#ifndef DISABLE_MAL_FFROT6D + 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 */ +#endif + +#ifndef DISABLE_MAL_DRWEB case M_DRWEB: /* "drweb" scanner type ----------------------------------- */ /* v0.1 - added support for tcp sockets */ /* v0.0 - initial release -- support for unix sockets */ @@ -739,7 +856,7 @@ badseek: err = errno; /* try matcher on the line, grab substring */ result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, - ovector, nelements(ovector)); + ovector, nelem(ovector)); if (result >= 2) { const char * pre_malware_nb; @@ -747,7 +864,7 @@ badseek: err = errno; pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb); if (i==0) /* the first name we just copy to malware_name */ - g = string_cat(NULL, pre_malware_nb); + g = string_cat(NULL, US pre_malware_nb); /*XXX could be string_append_listele? */ else /* concatenate each new virus name to previous */ @@ -780,7 +897,9 @@ badseek: err = errno; } break; } /* drweb */ +#endif +#ifndef DISABLE_MAL_AVE case M_AVES: /* "aveserver" scanner type -------------------------------- */ { uschar buf[32768]; @@ -848,7 +967,9 @@ badseek: err = errno; } break; } /* aveserver */ +#endif +#ifndef DISABLE_MAL_FSECURE case M_FSEC: /* "fsecure" scanner type ---------------------------------- */ { int i, j, bread = 0; @@ -865,7 +986,7 @@ badseek: err = errno; scanner_name, scanner_options); /* pass options */ memset(av_buffer, 0, sizeof(av_buffer)); - for (i = 0; i != nelements(cmdopt); i++) + for (i = 0; i != nelem(cmdopt); i++) { if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0) @@ -931,7 +1052,9 @@ badseek: err = errno; fsec_found: break; } /* fsecure */ +#endif +#ifndef DISABLE_MAL_KAV case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */ { time_t t; @@ -1043,7 +1166,9 @@ badseek: err = errno; break; } +#endif +#ifndef DISABLE_MAL_CMDLINE case M_CMDL: /* "cmdline" scanner type ---------------------------------- */ { const uschar *cmdline_scanner = scanner_options; @@ -1152,7 +1277,7 @@ badseek: err = errno; sep = pclose(scanner_out); signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe); if (sep != 0) - return m_errlog_defer(scanent, NULL, + return m_errlog_defer(scanent, NULL, sep == -1 ? string_sprintf("running scanner failed: %s", strerror(sep)) : string_sprintf("scanner returned error code: %d", sep)); @@ -1177,7 +1302,9 @@ badseek: err = errno; malware_name = NULL; break; } /* cmdline */ +#endif +#ifndef DISABLE_MAL_SOPHIE case M_SOPHIE: /* "sophie" scanner type --------------------------------- */ { int bread = 0; @@ -1222,7 +1349,9 @@ badseek: err = errno; break; } +#endif +#ifndef DISABLE_MAL_CLAM case M_CLAMD: /* "clamd" scanner type ----------------------------------- */ { /* This code was originally contributed by David Saez */ @@ -1233,13 +1362,11 @@ badseek: err = errno; * The zINSTREAM command was introduced with ClamAV 0.95, which marked * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that -* the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless -* WITH_OLD_CLAMAV_STREAM is defined. +* the TCP-connected daemon is actually local; otherwise we use zINSTREAM * See Exim bug 926 for details. */ uschar *p, *vname, *result_tag; int bread=0; - uschar * file_name; uschar av_buffer[1024]; uschar *hostname = US""; host_item connhost; @@ -1250,13 +1377,7 @@ badseek: err = errno; BOOL use_scan_command = FALSE; clamd_address * cv[MAX_CLAMD_SERVERS]; int num_servers = 0; -#ifdef WITH_OLD_CLAMAV_STREAM - unsigned int port; - uschar av_buffer2[1024]; - int sockData; -#else uint32_t send_size, send_final_zeroblock; -#endif blob cmd_str; /*XXX if unixdomain socket, only one server supported. Needs fixing; @@ -1311,13 +1432,13 @@ badseek: err = errno; sublist = scanner_options; if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0))) { - (void) m_errlog_defer(scanent, NULL, + (void) m_errlog_defer(scanent, NULL, string_sprintf("missing address: '%s'", scanner_options)); continue; } if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0))) { - (void) m_errlog_defer(scanent, NULL, + (void) m_errlog_defer(scanent, NULL, string_sprintf("missing port: '%s'", scanner_options)); continue; } @@ -1355,11 +1476,7 @@ badseek: err = errno; /* Set up the very first data we will be sending */ if (!use_scan_command) -#ifdef WITH_OLD_CLAMAV_STREAM - { cmd_str.data = US"STREAM\n"; cmd_str.len = 7; } -#else { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; } -#endif else { cmd_str.data = string_sprintf("SCAN %s\n", eml_filename); @@ -1430,50 +1547,6 @@ badseek: err = errno; if (!use_scan_command) { -#ifdef WITH_OLD_CLAMAV_STREAM - /* "STREAM\n" command, get back a "PORT \n" response, send data to - * that port on a second connection; then in the scan-method-neutral - * part, read the response back on the original connection. */ - - DEBUG(D_acl) debug_printf_indent( - "Malware scan: issuing %s old-style remote scan (PORT)\n", - scanner_name); - - /* Pass the string to ClamAV (7 = "STREAM\n"), if not already sent */ - if (cmd_str.len) - if (m_sock_send(sock, cmd_str.data, cmd_str.len, &errstr) < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); - - memset(av_buffer2, 0, sizeof(av_buffer2)); - bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL)); - - if (bread < 0) - return m_errlog_defer_3(scanent, CUS callout_address, - string_sprintf("unable to read PORT from socket (%s)", - strerror(errno)), - sock); - - if (bread == sizeof(av_buffer2)) - return m_errlog_defer_3(scanent, CUS callout_address, - "buffer too small", sock); - - if (!(*av_buffer2)) - return m_errlog_defer_3(scanent, CUS callout_address, - "ClamAV returned null", sock); - - av_buffer2[bread] = '\0'; - if(sscanf(CS av_buffer2, "PORT %u\n", &port) != 1) - return m_errlog_defer_3(scanent, CUS callout_address, - string_sprintf("Expected port information from clamd, got '%s'", - av_buffer2), - sock); - - sockData = m_tcpsocket(connhost.address, port, NULL, &errstr, NULL); - if (sockData < 0) - return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock); - -# define CLOSE_SOCKDATA (void)close(sockData) -#else /* WITH_OLD_CLAMAV_STREAM not defined */ /* New protocol: "zINSTREAM\n" followed by a sequence of chunks, a 4-byte number (network order), terminated by a zero-length chunk. */ @@ -1490,14 +1563,10 @@ badseek: err = errno; strerror(errno)), sock); -# define CLOSE_SOCKDATA /**/ -#endif - /* calc file size */ if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0) { int err = errno; - CLOSE_SOCKDATA; return m_errlog_defer_3(scanent, NULL, string_sprintf("can't open spool file %s: %s", eml_filename, strerror(err)), @@ -1507,7 +1576,7 @@ badseek: err = errno; { int err; b_seek: err = errno; - CLOSE_SOCKDATA; (void)close(clam_fd); + (void)close(clam_fd); return m_errlog_defer_3(scanent, NULL, string_sprintf("can't seek spool file %s: %s", eml_filename, strerror(err)), @@ -1516,7 +1585,7 @@ b_seek: err = errno; fsize_uint = (unsigned int) fsize; if ((off_t)fsize_uint != fsize) { - CLOSE_SOCKDATA; (void)close(clam_fd); + (void)close(clam_fd); return m_errlog_defer_3(scanent, NULL, string_sprintf("seeking spool file %s, size overflow", eml_filename), @@ -1527,7 +1596,7 @@ b_seek: err = errno; if (!(clamav_fbuf = US malloc(fsize_uint))) { - CLOSE_SOCKDATA; (void)close(clam_fd); + (void)close(clam_fd); return m_errlog_defer_3(scanent, NULL, string_sprintf("unable to allocate memory %u for file (%s)", fsize_uint, eml_filename), @@ -1537,7 +1606,7 @@ b_seek: err = errno; if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0) { int err = errno; - free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd); + free(clamav_fbuf); (void)close(clam_fd); return m_errlog_defer_3(scanent, NULL, string_sprintf("can't read spool file %s: %s", eml_filename, strerror(err)), @@ -1546,16 +1615,6 @@ b_seek: err = errno; (void)close(clam_fd); /* send file body to socket */ -#ifdef WITH_OLD_CLAMAV_STREAM - if (send(sockData, clamav_fbuf, fsize_uint, 0) < 0) - { - free(clamav_fbuf); CLOSE_SOCKDATA; - return m_errlog_defer_3(scanent, NULL, - string_sprintf("unable to send file body to socket (%s:%u)", - hostname, port), - sock); - } -#else send_size = htonl(fsize_uint); send_final_zeroblock = 0; if ((send(sock, &send_size, sizeof(send_size), 0) < 0) || @@ -1567,12 +1626,8 @@ b_seek: err = errno; string_sprintf("unable to send file body to socket (%s)", hostname), sock); } -#endif free(clamav_fbuf); - - CLOSE_SOCKDATA; -#undef CLOSE_SOCKDATA } else { /* use scan command */ @@ -1710,7 +1765,9 @@ b_seek: err = errno; break; } /* clamd */ +#endif +#ifndef DISABLE_MAL_SOCK case M_SOCK: /* "sock" scanner type ------------------------------------- */ /* This code was derived by Martin Poole from the clamd code contributed by David Saez and the cmdline code @@ -1791,7 +1848,9 @@ b_seek: err = errno; malware_name = NULL; break; } +#endif +#ifndef DISABLE_MAL_MKS case M_MKSD: /* "mksd" scanner type ------------------------------------- */ { char *mksd_options_end; @@ -1824,7 +1883,9 @@ b_seek: err = errno; } break; } +#endif +#ifndef DISABLE_MAL_AVAST case M_AVAST: /* "avast" scanner type ----------------------------------- */ { int ovector[1*3]; @@ -1832,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 @@ -1841,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 @@ -1857,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 */ @@ -1880,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 */ @@ -1900,41 +1974,42 @@ 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, nelements(ovector)) > 0) + 0, 0, ovector, nelem(ovector)) > 0) break; - if ((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) if (*p == '\\' && (isspace(p[1]) || p[1] == '\\')) for (p0 = p; *p0; ++p0) *p0 = p0[1]; - avast_stage = AVA_DONE; - goto endloop; - } - - 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); - malware_name = NULL; - avast_stage = AVA_DONE; - goto endloop; + DEBUG(D_acl) + debug_printf_indent("unescaped malware name: '%s'\n", malware_name); + break; } - /* here for any unexpected response from the scanner */ + /* here also for any unexpected response from the scanner */ goto endloop; - case AVA_DONE: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen", + default: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen", __FILE__, __LINE__, __FUNCTION__); } } @@ -1957,51 +2032,7 @@ b_seek: err = errno; } 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 */ +#endif } /* scanner type switch */ if (sock >= 0) @@ -2100,24 +2131,47 @@ malware_init(void) { if (!malware_default_re) malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE); + +#ifndef DISABLE_MAL_DRWEB if (!drweb_re) drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE); +#endif +#ifndef DISABLE_MAL_FSECURE if (!fsec_re) fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE); +#endif +#ifndef DISABLE_MAL_KAV if (!kav_re_sus) kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE); if (!kav_re_inf) kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE); +#endif +#ifndef DISABLE_MAL_AVAST 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); +#endif +#ifndef DISABLE_MAL_FFROT6D 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 } + +void +malware_show_supported(FILE * f) +{ +struct scan * sc; +fprintf(f, "Malware:"); +for (sc = m_scans; sc->scancode != -1; sc++) fprintf(f, " %s", sc->name); +fprintf(f, "\n"); +} + + +# endif /*!MACRO_PREDEF*/ #endif /*WITH_CONTENT_SCAN*/ /* * vi: aw ai sw=2