X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Fmalware.c;h=2e783e398eb9784ae58caddf4c0708a6a9804077;hp=c18cd95be93e173a93cfdb60d9d920c24a86c06d;hb=1f20760b17087817459e6c6baffa28de4b7d5aa2;hpb=2b8b8e4ed5cbebd3884c301d438d72ea24fbfd70 diff --git a/src/src/malware.c b/src/src/malware.c index c18cd95be..2e783e398 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -4,7 +4,7 @@ /* Copyright (c) Tom Kistner 2003 - 2015 * License: GPL - * Copyright (c) The Exim Maintainers 2017 - 2018 + * Copyright (c) The Exim Maintainers 2015 - 2018 */ /* Code for calling virus (malware) scanners. Called from acl.c. */ @@ -12,8 +12,45 @@ #include "exim.h" #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; +typedef enum { +#ifndef DISABLE_MAL_FFROTD + M_FPROTD, +#endif +#ifndef DISABLE_MAL_FFROT6D + M_FPROT6D, +#endif +#ifndef DISABLE_MAL_DRWEB + M_DRWEB, +#endif +#ifndef DISABLE_MAL_AVE + M_AVES, +#endif +#ifndef DISABLE_MAL_FSECURE + M_FSEC, +#endif +#ifndef DISABLE_MAL_KAV + M_KAVD, +#endif +#ifndef DISABLE_MAL_SOPHIE + M_SOPHIE, +#endif +#ifndef DISABLE_MAL_CLAM + M_CLAMD, +#endif +#ifndef DISABLE_MAL_MKS + M_MKSD, +#endif +#ifndef DISABLE_MAL_AVAST + M_AVAST, +#endif +#ifndef DISABLE_MAL_SOCK + M_SOCK, +#endif +#ifndef DISABLE_MAL_CMDLINE + M_CMDL, +#endif + M_DUMMY + } scanner_t; typedef enum {MC_NONE, MC_TCP, MC_UNIX, MC_STRM} contype_t; static struct scan { @@ -70,16 +107,16 @@ static struct scan 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 (const struct scan * sc = m_scans; sc->scancode != -1; sc++) { - for(s = sc->name, t = buf+14; *s; s++) if (*s != '-') *t++ = toupper(*s); + for (s = sc->name, t = buf+14; *s; s++) if (*s != '-') + *t++ = toupper(*s); *t = '\0'; builtin_macro_create(buf); } @@ -137,9 +174,11 @@ static const pcre * kav_re_inf = NULL; #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 uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d+\\.0\\t0\\s(.*)"; +static const uschar * ava_re_error_str = US "(?!\\\\)\\t\\[E\\]\\d+\\.0\\tError\\s\\d+\\s(.*)"; static const pcre * ava_re_clean = NULL; static const pcre * ava_re_virus = NULL; +static const pcre * ava_re_error = NULL; #endif #ifndef DISABLE_MAL_FFROT6D @@ -153,11 +192,12 @@ static const pcre * fprot6d_re_virus = NULL; /******************************************************************************/ +#ifndef DISABLE_MAL_KAV /* Routine to check whether a system is big- or little-endian. Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html Needed for proper kavdaemon implementation. Sigh. */ -#define BIG_MY_ENDIAN 0 -#define LITTLE_MY_ENDIAN 1 +# define BIG_MY_ENDIAN 0 +# define LITTLE_MY_ENDIAN 1 static int test_byte_order(void); static inline int test_byte_order() @@ -166,6 +206,7 @@ test_byte_order() char *byte = CS &word; return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN); } +#endif BOOL malware_ok = FALSE; @@ -176,27 +217,53 @@ extern int spool_mbox_ok; extern uschar spooled_message_id[MESSAGE_ID_LENGTH+1]; +/* Some (currently avast only) use backslash escaped whitespace, +this function undoes these escapes */ +static inline void +unescape(uschar *p) +{ +uschar *p0; +for (; *p; ++p) + if (*p == '\\' && (isspace(p[1]) || p[1] == '\\')) + for (p0 = p; *p0; ++p0) *p0 = p0[1]; +} + +/* --- malware_*_defer --- */ static inline int -malware_errlog_defer(const uschar * str) +malware_panic_defer(const uschar * str) { log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str); return DEFER; } - -static int -m_errlog_defer(struct scan * scanent, const uschar * hostport, +static inline int +malware_log_defer(const uschar * str) +{ +log_write(0, LOG_MAIN, "malware acl condition: %s", str); +return DEFER; +} +/* --- m_*_defer --- */ +static inline int +m_panic_defer(struct scan * scanent, const uschar * hostport, const uschar * str) { -return malware_errlog_defer(string_sprintf("%s %s : %s", +return malware_panic_defer(string_sprintf("%s %s : %s", scanent->name, hostport ? hostport : CUS"", str)); } -static int -m_errlog_defer_3(struct scan * scanent, const uschar * hostport, +static inline int +m_log_defer(struct scan * scanent, const uschar * hostport, + const uschar * str) +{ +return malware_log_defer(string_sprintf("%s %s : %s", + scanent->name, hostport ? hostport : CUS"", str)); +} +/* --- m_*_defer_3 */ +static inline int +m_panic_defer_3(struct scan * scanent, const uschar * hostport, const uschar * str, int fd_to_close) { (void) close(fd_to_close); -return m_errlog_defer(scanent, hostport, str); +return m_panic_defer(scanent, hostport, str); } /*************************************************/ @@ -341,7 +408,7 @@ for (;;) while (i < 0 && errno == EINTR); if (i <= 0) { - (void) malware_errlog_defer( + (void) malware_panic_defer( US"unable to write to mksd UNIX socket (/var/run/mksd/socket)"); return -1; } @@ -365,15 +432,16 @@ for (;;) static inline int mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, int tmo) { +client_conn_ctx cctx = {.sock = sock}; int offset = 0; int i; do { - i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL)); + i = ip_recv(&cctx, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL)); if (i <= 0) { - (void) malware_errlog_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)"); + (void) malware_panic_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)"); return -1; } @@ -381,7 +449,7 @@ do /* offset == av_buffer_size -> buffer full */ if (offset == av_buffer_size) { - (void) malware_errlog_defer(US"malformed reply received from mksd"); + (void) malware_panic_defer(US"malformed reply received from mksd"); return -1; } } while (av_buffer[offset-1] != '\n'); @@ -404,7 +472,7 @@ switch (*line) case 'A': /* ERR */ if ((p = strchr (line, '\n')) != NULL) *p = '\0'; - return m_errlog_defer(scanent, NULL, + return m_panic_defer(scanent, NULL, string_sprintf("scanner failed: %s", line)); default: /* VIR */ @@ -422,7 +490,7 @@ switch (*line) return OK; } } - return m_errlog_defer(scanent, NULL, + return m_panic_defer(scanent, NULL, string_sprintf("malformed reply received: %s", line)); } } @@ -505,7 +573,7 @@ const pcre *re; uschar * errstr; struct scan * scanent; const uschar * scanner_options; -int sock = -1; +client_conn_ctx malware_daemon_ctx = {.sock = -1}; time_t tmo; uschar * eml_filename, * eml_dir; @@ -515,7 +583,7 @@ if (!malware_re) /* Ensure the eml mbox file is spooled up */ if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename))) - return malware_errlog_defer(US"error while creating mbox spool file"); + return malware_panic_defer(US"error while creating mbox spool file"); /* None of our current scanners need the mbox file as a stream (they use the name), so we can close it right away. Get the directory too. */ @@ -535,20 +603,20 @@ if ( strcmpic(malware_re,US"true") == 0 { if ( !malware_default_re && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr))) - return malware_errlog_defer(errstr); + return malware_panic_defer(errstr); malware_re = malware_regex_default; re = malware_default_re; } /* compile the regex, see if it works */ else if (!(re = m_pcre_compile(malware_re, &errstr))) - return malware_errlog_defer(errstr); + return malware_panic_defer(errstr); /* if av_scanner starts with a dollar, expand it first */ if (*av_scanner == '$') { if (!(av_scanner_work = expand_string(av_scanner))) - return malware_errlog_defer( + return malware_panic_defer( string_sprintf("av_scanner starts with $, but expansion failed: %s", expand_string_message)); @@ -564,14 +632,14 @@ if (!malware_ok) { /* find the scanner type from the av_scanner option */ if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) - return malware_errlog_defer(US"av_scanner configuration variable is empty"); + return malware_panic_defer(US"av_scanner configuration variable is empty"); if (!timeout) timeout = MALWARE_TIMEOUT; tmo = time(NULL) + timeout; for (scanent = m_scans; ; scanent++) { if (!scanent->name) - return malware_errlog_defer(string_sprintf("unknown scanner type '%s'", + return malware_panic_defer(string_sprintf("unknown scanner type '%s'", scanner_name)); if (strcmpic(scanner_name, US scanent->name) != 0) continue; @@ -586,13 +654,17 @@ if (!malware_ok) DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options); switch(scanent->conn) { - case MC_TCP: sock = ip_tcpsocket(scanner_options, &errstr, 5); break; - case MC_UNIX: sock = ip_unixsocket(scanner_options, &errstr); break; - case MC_STRM: sock = ip_streamsocket(scanner_options, &errstr, 5); break; - default: /* compiler quietening */ break; + case MC_TCP: + malware_daemon_ctx.sock = ip_tcpsocket(scanner_options, &errstr, 5); break; + case MC_UNIX: + malware_daemon_ctx.sock = ip_unixsocket(scanner_options, &errstr); break; + case MC_STRM: + malware_daemon_ctx.sock = ip_streamsocket(scanner_options, &errstr, 5); break; + default: + /* compiler quietening */ break; } - if (sock < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + if (malware_daemon_ctx.sock < 0) + return m_panic_defer(scanent, CUS callout_address, errstr); break; } @@ -622,10 +694,10 @@ if (!malware_ok) scanner_name, scanrequest); /* send scan request */ - if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0) + return m_panic_defer(scanent, CUS callout_address, errstr); - while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0) + while ((len = recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo)) >= 0) if (len > 0) { if (Ustrstr(buf, US" 0 */ if (drweb_vnum) { - int i; gstring * g = NULL; /* setup default virus name */ @@ -837,21 +908,21 @@ badseek: err = errno; drweb_re = m_pcre_compile(drweb_re_str, &errstr); /* read and concatenate virus names into one string */ - for (i = 0; i < drweb_vnum; i++) + for (int i = 0; i < drweb_vnum; i++) { int ovector[10*3]; /* read the size of report */ - if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo)) - return m_errlog_defer_3(scanent, CUS callout_address, - US"cannot read report size", sock); + if (!recv_len(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), tmo)) + return m_panic_defer_3(scanent, CUS callout_address, + US"cannot read report size", malware_daemon_ctx.sock); drweb_slen = ntohl(drweb_slen); tmpbuf = store_get(drweb_slen); /* read report body */ - if (!recv_len(sock, tmpbuf, drweb_slen, tmo)) - return m_errlog_defer_3(scanent, CUS callout_address, - US"cannot read report string", sock); + if (!recv_len(malware_daemon_ctx.sock, tmpbuf, drweb_slen, tmo)) + return m_panic_defer_3(scanent, CUS callout_address, + US"cannot read report string", malware_daemon_ctx.sock); tmpbuf[drweb_slen] = '\0'; /* try matcher on the line, grab substring */ @@ -888,9 +959,9 @@ badseek: err = errno; * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR * and others are ignored */ if (drweb_s) - return m_errlog_defer_3(scanent, CUS callout_address, + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s), - sock); + malware_daemon_ctx.sock); /* no virus found */ malware_name = NULL; @@ -907,13 +978,13 @@ badseek: err = errno; /* read aveserver's greeting and see if it is ready (2xx greeting) */ buf[0] = 0; - recv_line(sock, buf, sizeof(buf), tmo); + recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo); if (buf[0] != '2') /* aveserver is having problems */ - return m_errlog_defer_3(scanent, CUS callout_address, + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("unavailable (Responded: %s).", ((buf[0] != 0) ? buf : US "nothing") ), - sock); + malware_daemon_ctx.sock); /* prepare our command */ (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n", @@ -922,19 +993,19 @@ badseek: err = errno; /* and send it */ DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n", scanner_name, buf); - if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + if (m_sock_send(malware_daemon_ctx.sock, buf, Ustrlen(buf), &errstr) < 0) + return m_panic_defer(scanent, CUS callout_address, errstr); malware_name = NULL; result = 0; /* read response lines, find malware name and final response */ - while (recv_line(sock, buf, sizeof(buf), tmo) > 0) + while (recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo) > 0) { if (buf[0] == '2') break; if (buf[0] == '5') /* aveserver is having problems */ { - result = m_errlog_defer(scanent, CUS callout_address, + result = m_panic_defer(scanent, CUS callout_address, string_sprintf("unable to scan file %s (Responded: %s).", eml_filename, buf)); break; @@ -947,22 +1018,22 @@ badseek: err = errno; } } - if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + if (m_sock_send(malware_daemon_ctx.sock, US"quit\r\n", 6, &errstr) < 0) + return m_panic_defer(scanent, CUS callout_address, errstr); /* read aveserver's greeting and see if it is ready (2xx greeting) */ buf[0] = 0; - recv_line(sock, buf, sizeof(buf), tmo); + recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo); if (buf[0] != '2') /* aveserver is having problems */ - return m_errlog_defer_3(scanent, CUS callout_address, + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("unable to quit dialogue (Responded: %s).", ((buf[0] != 0) ? buf : US "nothing") ), - sock); + malware_daemon_ctx.sock); if (result == DEFER) { - (void)close(sock); + (void)close(malware_daemon_ctx.sock); return DEFER; } break; @@ -972,7 +1043,7 @@ badseek: err = errno; #ifndef DISABLE_MAL_FSECURE case M_FSEC: /* "fsecure" scanner type ---------------------------------- */ { - int i, j, bread = 0; + int i, bread = 0; uschar * file_name; uschar av_buffer[1024]; static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n", @@ -989,16 +1060,16 @@ badseek: err = errno; for (i = 0; i != nelem(cmdopt); i++) { - if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + if (m_sock_send(malware_daemon_ctx.sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0) + return m_panic_defer(scanent, CUS callout_address, errstr); - bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL)); + bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo-time(NULL)); if (bread > 0) av_buffer[bread]='\0'; if (bread < 0) - return m_errlog_defer_3(scanent, CUS callout_address, + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("unable to read answer %d (%s)", i, strerror(errno)), - sock); - for (j = 0; j < bread; j++) + malware_daemon_ctx.sock); + for (int j = 0; j < bread; j++) if (av_buffer[j] == '\r' || av_buffer[j] == '\n') av_buffer[j] ='@'; } @@ -1006,8 +1077,8 @@ badseek: err = errno; /* pass the mailfile to fsecure */ file_name = string_sprintf("SCAN\t%s\n", eml_filename); - if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + if (m_sock_send(malware_daemon_ctx.sock, file_name, Ustrlen(file_name), &errstr) < 0) + return m_panic_defer(scanent, CUS callout_address, errstr); /* set up match */ /* todo also SUSPICION\t */ @@ -1024,10 +1095,10 @@ badseek: err = errno; { errno = ETIMEDOUT; i = av_buffer+sizeof(av_buffer)-p; - if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0) - return m_errlog_defer_3(scanent, CUS callout_address, + if ((bread= ip_recv(&malware_daemon_ctx, p, i-1, tmo-time(NULL))) < 0) + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("unable to read result (%s)", strerror(errno)), - sock); + malware_daemon_ctx.sock); for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1) { @@ -1084,28 +1155,28 @@ badseek: err = errno; scanner_name, scanner_options); /* send scan request */ - if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0) + return m_panic_defer(scanent, CUS callout_address, errstr); /* wait for result */ - if (!recv_len(sock, tmpbuf, 2, tmo)) - return m_errlog_defer_3(scanent, CUS callout_address, - US"unable to read 2 bytes from socket.", sock); + if (!recv_len(malware_daemon_ctx.sock, tmpbuf, 2, tmo)) + return m_panic_defer_3(scanent, CUS callout_address, + US"unable to read 2 bytes from socket.", malware_daemon_ctx.sock); /* get errorcode from one nibble */ kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F; switch(kav_rc) { case 5: case 6: /* improper kavdaemon configuration */ - return m_errlog_defer_3(scanent, CUS callout_address, + return m_panic_defer_3(scanent, CUS callout_address, US"please reconfigure kavdaemon to NOT disinfect or remove infected files.", - sock); + malware_daemon_ctx.sock); case 1: - return m_errlog_defer_3(scanent, CUS callout_address, - US"reported 'scanning not completed' (code 1).", sock); + return m_panic_defer_3(scanent, CUS callout_address, + US"reported 'scanning not completed' (code 1).", malware_daemon_ctx.sock); case 7: - return m_errlog_defer_3(scanent, CUS callout_address, - US"reported 'kavdaemon damaged' (code 7).", sock); + return m_panic_defer_3(scanent, CUS callout_address, + US"reported 'kavdaemon damaged' (code 7).", malware_daemon_ctx.sock); } /* code 8 is not handled, since it is ambiguous. It appears mostly on @@ -1125,9 +1196,9 @@ badseek: err = errno; if (report_flag == 1) { /* read report size */ - if (!recv_len(sock, &kav_reportlen, 4, tmo)) - return m_errlog_defer_3(scanent, CUS callout_address, - US"cannot read report size", sock); + if (!recv_len(malware_daemon_ctx.sock, &kav_reportlen, 4, tmo)) + return m_panic_defer_3(scanent, CUS callout_address, + US"cannot read report size", malware_daemon_ctx.sock); /* it's possible that avp returns av_buffer[1] == 1 but the reportsize is 0 (!?) */ @@ -1150,7 +1221,7 @@ badseek: err = errno; /* coverity[tainted_data] */ while (kav_reportlen > 0) { - if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0) + if ((bread = recv_line(malware_daemon_ctx.sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0) break; kav_reportlen -= bread+1; @@ -1187,19 +1258,19 @@ badseek: err = errno; uschar *p; if (!cmdline_scanner) - return m_errlog_defer(scanent, NULL, errstr); + return m_panic_defer(scanent, NULL, errstr); /* find scanner output trigger */ cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep, "missing trigger specification", &errstr); if (!cmdline_trigger_re) - return m_errlog_defer(scanent, NULL, errstr); + return m_panic_defer(scanent, NULL, errstr); /* find scanner name regex */ cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep, "missing virus name regex specification", &errstr); if (!cmdline_regex_re) - return m_errlog_defer(scanent, NULL, errstr); + return m_panic_defer(scanent, NULL, errstr); /* prepare scanner call; despite the naming, file_name holds a directory name which is documented as the value given to %s. */ @@ -1224,7 +1295,7 @@ badseek: err = errno; { int err = errno; signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe); - return m_errlog_defer(scanent, NULL, + return m_panic_defer(scanent, NULL, string_sprintf("call (%s) failed: %s.", commandline, strerror(err))); } scanner_fd = fileno(scanner_out); @@ -1236,7 +1307,7 @@ badseek: err = errno; int err = errno; (void) pclose(scanner_out); signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe); - return m_errlog_defer(scanent, NULL, string_sprintf( + return m_panic_defer(scanent, NULL, string_sprintf( "opening scanner output file (%s) failed: %s.", file_name, strerror(err))); } @@ -1252,7 +1323,7 @@ badseek: err = errno; break; (void) pclose(scanner_out); signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe); - return m_errlog_defer(scanent, NULL, string_sprintf( + return m_panic_defer(scanent, NULL, string_sprintf( "unable to read from scanner (%s): %s", commandline, strerror(err))); } @@ -1262,7 +1333,7 @@ badseek: err = errno; /* short write */ (void) pclose(scanner_out); signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe); - return m_errlog_defer(scanent, NULL, string_sprintf( + return m_panic_defer(scanent, NULL, string_sprintf( "short write on scanner output file (%s).", file_name)); } putc('\n', scanner_record); @@ -1277,7 +1348,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_panic_defer(scanent, NULL, sep == -1 ? string_sprintf("running scanner failed: %s", strerror(sep)) : string_sprintf("scanner returned error code: %d", sep)); @@ -1320,19 +1391,19 @@ badseek: err = errno; DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", scanner_name, scanner_options); - if ( write(sock, file_name, Ustrlen(file_name)) < 0 - || write(sock, "\n", 1) != 1 + if ( write(malware_daemon_ctx.sock, file_name, Ustrlen(file_name)) < 0 + || write(malware_daemon_ctx.sock, "\n", 1) != 1 ) - return m_errlog_defer_3(scanent, CUS callout_address, + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("unable to write to UNIX socket (%s)", scanner_options), - sock); + malware_daemon_ctx.sock); /* wait for result */ memset(av_buffer, 0, sizeof(av_buffer)); - if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0) - return m_errlog_defer_3(scanent, CUS callout_address, + if ((bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0) + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("unable to read from UNIX socket (%s)", scanner_options), - sock); + malware_daemon_ctx.sock); /* infected ? */ if (av_buffer[0] == '1') { @@ -1342,8 +1413,8 @@ badseek: err = errno; malware_name = string_copy(&av_buffer[2]); } else if (!strncmp(CS av_buffer, "-1", 2)) - return m_errlog_defer_3(scanent, CUS callout_address, - US"scanner reported error", sock); + return m_panic_defer_3(scanent, CUS callout_address, + US"scanner reported error", malware_daemon_ctx.sock); else /* all ok, no virus */ malware_name = NULL; @@ -1400,7 +1471,7 @@ badseek: err = errno; /* parse options */ if (clamd_option(cd, sublist, &subsep) != OK) - return m_errlog_defer(scanent, NULL, + return m_panic_defer(scanent, NULL, string_sprintf("bad option '%s'", scanner_options)); cv[0] = cd; } @@ -1432,13 +1503,13 @@ badseek: err = errno; sublist = scanner_options; if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0))) { - (void) m_errlog_defer(scanent, NULL, + (void) m_panic_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_panic_defer(scanent, NULL, string_sprintf("missing port: '%s'", scanner_options)); continue; } @@ -1447,13 +1518,13 @@ badseek: err = errno; /* parse options */ /*XXX should these options be common over scanner types? */ if (clamd_option(cd, sublist, &subsep) != OK) - return m_errlog_defer(scanent, NULL, + return m_panic_defer(scanent, NULL, string_sprintf("bad option '%s'", scanner_options)); cv[num_servers++] = cd; if (num_servers >= MAX_CLAMD_SERVERS) { - (void) m_errlog_defer(scanent, NULL, + (void) m_panic_defer(scanent, NULL, US"More than " MAX_CLAMD_SERVERS_S " clamd servers " "specified; only using the first " MAX_CLAMD_SERVERS_S ); break; @@ -1463,14 +1534,14 @@ badseek: err = errno; /* check if we have at least one server */ if (!num_servers) - return m_errlog_defer(scanent, NULL, + return m_panic_defer(scanent, NULL, US"no useable server addresses in malware configuration option."); } /* See the discussion of response formats below to see why we really don't like colons in filenames when passing filenames to ClamAV. */ if (use_scan_command && Ustrchr(eml_filename, ':')) - return m_errlog_defer(scanent, NULL, + return m_panic_defer(scanent, NULL, string_sprintf("local/SCAN mode incompatible with" \ " : in path to email filename [%s]", eml_filename)); @@ -1502,7 +1573,8 @@ badseek: err = errno; * on both connections (as one host could resolve to multiple ips) */ for (;;) { - if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port, + /*XXX we trust that the cmd_str is ideempotent */ + if ((malware_daemon_ctx.sock = m_tcpsocket(cd->hostspec, cd->tcp_port, &connhost, &errstr, &cmd_str)) >= 0) { /* Connection successfully established with a server */ @@ -1513,10 +1585,10 @@ badseek: err = errno; if (cd->retry <= 0) break; while (cd->retry > 0) cd->retry = sleep(cd->retry); } - if (sock >= 0) + if (malware_daemon_ctx.sock >= 0) break; - (void) m_errlog_defer(scanent, CUS callout_address, errstr); + (void) m_panic_defer(scanent, CUS callout_address, errstr); /* Remove the server from the list. XXX We should free the memory */ num_servers--; @@ -1525,18 +1597,18 @@ badseek: err = errno; } if (num_servers == 0) - return m_errlog_defer(scanent, NULL, US"all servers failed"); + return m_panic_defer(scanent, NULL, US"all servers failed"); } else for (;;) { - if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0) + if ((malware_daemon_ctx.sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0) { hostname = cv[0]->hostspec; break; } if (cv[0]->retry <= 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + return m_panic_defer(scanent, CUS callout_address, errstr); while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry); } @@ -1557,39 +1629,39 @@ badseek: err = errno; /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */ if (cmd_str.len) - if (send(sock, cmd_str.data, cmd_str.len, 0) < 0) - return m_errlog_defer_3(scanent, CUS hostname, + if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0) + return m_panic_defer_3(scanent, CUS hostname, string_sprintf("unable to send zINSTREAM to socket (%s)", strerror(errno)), - sock); + malware_daemon_ctx.sock); /* calc file size */ if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0) { int err = errno; - return m_errlog_defer_3(scanent, NULL, + return m_panic_defer_3(scanent, NULL, string_sprintf("can't open spool file %s: %s", eml_filename, strerror(err)), - sock); + malware_daemon_ctx.sock); } if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0) { int err; b_seek: err = errno; (void)close(clam_fd); - return m_errlog_defer_3(scanent, NULL, + return m_panic_defer_3(scanent, NULL, string_sprintf("can't seek spool file %s: %s", eml_filename, strerror(err)), - sock); + malware_daemon_ctx.sock); } fsize_uint = (unsigned int) fsize; if ((off_t)fsize_uint != fsize) { (void)close(clam_fd); - return m_errlog_defer_3(scanent, NULL, + return m_panic_defer_3(scanent, NULL, string_sprintf("seeking spool file %s, size overflow", eml_filename), - sock); + malware_daemon_ctx.sock); } if (lseek(clam_fd, 0, SEEK_SET) < 0) goto b_seek; @@ -1597,34 +1669,34 @@ b_seek: err = errno; if (!(clamav_fbuf = US malloc(fsize_uint))) { (void)close(clam_fd); - return m_errlog_defer_3(scanent, NULL, + return m_panic_defer_3(scanent, NULL, string_sprintf("unable to allocate memory %u for file (%s)", fsize_uint, eml_filename), - sock); + malware_daemon_ctx.sock); } if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0) { int err = errno; free(clamav_fbuf); (void)close(clam_fd); - return m_errlog_defer_3(scanent, NULL, + return m_panic_defer_3(scanent, NULL, string_sprintf("can't read spool file %s: %s", eml_filename, strerror(err)), - sock); + malware_daemon_ctx.sock); } (void)close(clam_fd); /* send file body to socket */ send_size = htonl(fsize_uint); send_final_zeroblock = 0; - if ((send(sock, &send_size, sizeof(send_size), 0) < 0) || - (send(sock, clamav_fbuf, fsize_uint, 0) < 0) || - (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0)) + if ((send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0) || + (send(malware_daemon_ctx.sock, clamav_fbuf, fsize_uint, 0) < 0) || + (send(malware_daemon_ctx.sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0)) { free(clamav_fbuf); - return m_errlog_defer_3(scanent, NULL, + return m_panic_defer_3(scanent, NULL, string_sprintf("unable to send file body to socket (%s)", hostname), - sock); + malware_daemon_ctx.sock); } free(clamav_fbuf); @@ -1651,10 +1723,10 @@ b_seek: err = errno; scanner_name, scanner_options); if (cmd_str.len) - if (send(sock, cmd_str.data, cmd_str.len, 0) < 0) - return m_errlog_defer_3(scanent, CUS callout_address, + if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0) + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("unable to write to socket (%s)", strerror(errno)), - sock); + malware_daemon_ctx.sock); /* Do not shut down the socket for writing; a user report noted that * clamd 0.70 does not react well to this. */ @@ -1664,17 +1736,18 @@ b_seek: err = errno; /* Read the result */ memset(av_buffer, 0, sizeof(av_buffer)); - bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL)); - (void)close(sock); - sock = -1; + bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo-time(NULL)); + (void)close(malware_daemon_ctx.sock); + malware_daemon_ctx.sock = -1; + malware_daemon_ctx.tls_ctx = NULL; if (bread <= 0) - return m_errlog_defer(scanent, CUS callout_address, + return m_panic_defer(scanent, CUS callout_address, string_sprintf("unable to read from socket (%s)", errno == 0 ? "EOF" : strerror(errno))); if (bread == sizeof(av_buffer)) - return m_errlog_defer(scanent, CUS callout_address, + return m_panic_defer(scanent, CUS callout_address, US"buffer too small"); /* We're now assured of a NULL at the end of av_buffer */ @@ -1699,7 +1772,7 @@ b_seek: err = errno; passing a filename to clamd). */ if (!(*av_buffer)) - return m_errlog_defer(scanent, CUS callout_address, + return m_panic_defer(scanent, CUS callout_address, US"ClamAV returned null"); /* strip newline at the end (won't be present for zINSTREAM) @@ -1716,7 +1789,7 @@ b_seek: err = errno; /* colon in returned output? */ if(!(p = Ustrchr(av_buffer,':'))) - return m_errlog_defer(scanent, CUS callout_address, string_sprintf( + return m_panic_defer(scanent, CUS callout_address, string_sprintf( "ClamAV returned malformed result (missing colon): %s", av_buffer)); @@ -1749,7 +1822,7 @@ b_seek: err = errno; } else if (Ustrcmp(result_tag, "ERROR") == 0) - return m_errlog_defer(scanent, CUS callout_address, + return m_panic_defer(scanent, CUS callout_address, string_sprintf("ClamAV returned: %s", av_buffer)); else if (Ustrcmp(result_tag, "OK") == 0) @@ -1760,7 +1833,7 @@ b_seek: err = errno; } else - return m_errlog_defer(scanent, CUS callout_address, + return m_panic_defer(scanent, CUS callout_address, string_sprintf("unparseable response from ClamAV: {%s}", av_buffer)); break; @@ -1791,8 +1864,8 @@ b_seek: err = errno; uschar * s = Ustrchr(sockline_scanner, '%'); if (s++) if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%')) - return m_errlog_defer_3(scanent, NULL, - US"unsafe sock scanner call spec", sock); + return m_panic_defer_3(scanent, NULL, + US"unsafe sock scanner call spec", malware_daemon_ctx.sock); } else sockline_scanner = sockline_scanner_default; @@ -1803,13 +1876,13 @@ b_seek: err = errno; sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep, "missing trigger specification", &errstr); if (!sockline_trig_re) - return m_errlog_defer_3(scanent, NULL, errstr, sock); + return m_panic_defer_3(scanent, NULL, errstr, malware_daemon_ctx.sock); /* find virus name regex */ sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep, "missing virus name regex specification", &errstr); if (!sockline_name_re) - return m_errlog_defer_3(scanent, NULL, errstr, sock); + return m_panic_defer_3(scanent, NULL, errstr, malware_daemon_ctx.sock); /* prepare scanner call - security depends on expansions check above */ commandline = string_sprintf( CS sockline_scanner, CS eml_filename); @@ -1817,20 +1890,20 @@ b_seek: err = errno; string_printing(commandline)); /* Pass the command string to the socket */ - if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + if (m_sock_send(malware_daemon_ctx.sock, commandline, Ustrlen(commandline), &errstr) < 0) + return m_panic_defer(scanent, CUS callout_address, errstr); /* Read the result */ - bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL)); + bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo-time(NULL)); if (bread <= 0) - return m_errlog_defer_3(scanent, CUS callout_address, + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("unable to read from socket (%s)", strerror(errno)), - sock); + malware_daemon_ctx.sock); if (bread == sizeof(av_buffer)) - return m_errlog_defer_3(scanent, CUS callout_address, - US"buffer too small", sock); + return m_panic_defer_3(scanent, CUS callout_address, + US"buffer too small", malware_daemon_ctx.sock); av_buffer[bread] = '\0'; linebuffer = string_copy(av_buffer); DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ", @@ -1865,20 +1938,20 @@ b_seek: err = errno; || mksd_maxproc < 1 || mksd_maxproc > 32 ) - return m_errlog_defer(scanent, CUS callout_address, + return m_panic_defer(scanent, CUS callout_address, string_sprintf("invalid option '%s'", scanner_options)); } - if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0) - return m_errlog_defer(scanent, CUS callout_address, errstr); + if((malware_daemon_ctx.sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0) + return m_panic_defer(scanent, CUS callout_address, errstr); malware_name = NULL; DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name); - if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK) + if ((retval = mksd_scan_packed(scanent, malware_daemon_ctx.sock, eml_filename, tmo)) != OK) { - close (sock); + close (malware_daemon_ctx.sock); return retval; } break; @@ -1888,11 +1961,13 @@ b_seek: err = errno; #ifndef DISABLE_MAL_AVAST case M_AVAST: /* "avast" scanner type ----------------------------------- */ { - int ovector[1*3]; uschar buf[1024]; uschar * scanrequest; enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage; int nread; + uschar * error_message = NULL; + BOOL more_data = FALSE; + BOOL strict = TRUE; /* According to Martin Tuma @avast the protocol uses "escaped whitespace", that is, every embedded whitespace is backslash @@ -1901,34 +1976,75 @@ b_seek: err = errno; and the [ ] marker. [+] - not infected [L] - infected - [E] - some error occured - Such marker follows the first non-escaped TAB. */ + [E] - some error occurred + Such marker follows the first non-escaped TAB. For more information + see avast-protocol(5) + + We observed two cases: + -> SCAN /file + <- /file [E]0.0 Error 13 Permission denied + <- 451 SCAN Engine error 13 permission denied + + -> SCAN /file + <- /file… [E]3.0 Error 41120 The file is a decompression bomb + <- /file… [+]2.0 + <- /file… [+]2.0 0 Eicar Test Virus!!! + <- 200 SCAN OK + + If the scanner returns 4xx, DEFER is a good decision, combined + with a panic log entry, to get the admin's attention. + + If the scanner returns 200, we reject it as malware, if found any, + or, in case of an error, we set the malware message to the error + string. + + Some of the >= 42000 errors are message related - usually some + broken archives etc, but some of them are e.g. license related. + Once the license expires the engine starts returning errors for + every scanning attempt. I¹ have the full list of the error codes + but it is not a public API and is subject to change. It is hard + for me to say what you should do in case of an engine error. You + can have a “Treat * unscanned file as infection” policy or “Treat + unscanned file as clean” policy. ¹) Jakub Bednar + + */ + if ( ( !ava_re_clean && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr))) || ( !ava_re_virus && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr))) + || ( !ava_re_error + && !(ava_re_error = m_pcre_compile(ava_re_error_str, &errstr))) ) - return malware_errlog_defer(errstr); + return malware_panic_defer(errstr); /* wait for result */ for (avast_stage = AVA_HELO; - (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0; + (nread = recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo)) > 0; ) { 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 */ @@ -1939,90 +2055,103 @@ 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); } 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 */ len = Ustrlen(scanrequest); - if (send(sock, scanrequest, len, 0) < 0) + if (send(malware_daemon_ctx.sock, scanrequest, len, 0) == -1) { scanrequest[len-1] = '\0'; - return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf( + return m_panic_defer_3(scanent, CUS callout_address, string_sprintf( "unable to send request '%s' to socket (%s): %s", - scanrequest, scanner_options, strerror(errno)), sock); + scanrequest, scanner_options, strerror(errno)), malware_daemon_ctx.sock); } break; } case AVA_RSP: - if (Ustrncmp(buf, "210", 3) == 0) - break; /* ignore the "210 SCAN DATA" message */ - if (pcre_exec(ava_re_clean, NULL, CS buf, slen, - 0, 0, ovector, nelem(ovector)) > 0) - break; + if (isdigit(buf[0])) /* We're done */ + goto endloop; - 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]; + if (malware_name) /* Nothing else matters, just read on */ + break; - avast_stage = AVA_DONE; - goto endloop; - } + if (pcre_exec(ava_re_clean, NULL, CS buf, slen, 0, 0, NULL, 0) == 0) + 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); - malware_name = NULL; - avast_stage = AVA_DONE; - goto endloop; - } + if ((malware_name = m_pcre_exec(ava_re_virus, buf))) + { + unescape(malware_name); + DEBUG(D_acl) + debug_printf_indent("unescaped malware name: '%s'\n", malware_name); + break; + } + + if (strict) /* treat scanner errors as malware */ + { + if ((malware_name = m_pcre_exec(ava_re_error, buf))) + { + unescape(malware_name); + DEBUG(D_acl) + debug_printf_indent("unescaped error message: '%s'\n", malware_name); + break; + } + } + else 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); - /* here 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__); } } } + endloop: - switch(avast_stage) - { - case AVA_HELO: - case AVA_OPT: - case AVA_RSP: return m_errlog_defer_3(scanent, CUS callout_address, - nread >= 0 - ? string_sprintf( - "invalid response from scanner: '%s'", buf) - : nread == -1 - ? US"EOF from scanner" - : US"timeout from scanner", - sock); - default: break; - } - break; + if (nread == -1) error_message = US"EOF from scanner"; + else if (nread < 0) error_message = US"timeout from scanner"; + else if (nread == 0) error_message = US"got nothing from scanner"; + else if (buf[0] != '2') error_message = buf; + + DEBUG(D_acl) debug_printf_indent("sent to avast QUIT\n"); + if (send(malware_daemon_ctx.sock, "QUIT\n", 5, 0) == -1) + return m_panic_defer_3(scanent, CUS callout_address, + string_sprintf("unable to send quit request to socket (%s): %s", + scanner_options, strerror(errno)), malware_daemon_ctx.sock); + + if (error_message) + return m_panic_defer_3(scanent, CUS callout_address, error_message, malware_daemon_ctx.sock); + } #endif } /* scanner type switch */ - if (sock >= 0) - (void) close (sock); + if (malware_daemon_ctx.sock >= 0) + (void) close (malware_daemon_ctx.sock); malware_ok = TRUE; /* set "been here, done that" marker */ } @@ -2093,7 +2222,7 @@ sender_address = US"malware-sender@example.net"; return_path = US""; recipients_list = NULL; receive_add_recipient(US"malware-victim@example.net", -1); -enable_dollar_recipients = TRUE; +f.enable_dollar_recipients = TRUE; ret = malware_internal(US"*", eml_filename, 0); @@ -2132,13 +2261,15 @@ if (!kav_re_sus) if (!kav_re_inf) kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE); #endif -#ifndef DISABLE_MAL_AVA +#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); +if (!ava_re_error) + ava_re_error = regex_must_compile(ava_re_error_str, FALSE, TRUE); #endif -#ifndef DISABLE_MAL_FPROT6D +#ifndef DISABLE_MAL_FFROT6D if (!fprot6d_re_error) fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE); if (!fprot6d_re_virus) @@ -2150,9 +2281,8 @@ if (!fprot6d_re_virus) 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); +for (struct scan * sc = m_scans; sc->scancode != (scanner_t)-1; sc++) fprintf(f, " %s", sc->name); fprintf(f, "\n"); }