1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
7 * Copyright (c) The Exim Maintainers 2015 - 2018
10 /* Code for calling virus (malware) scanners. Called from acl.c. */
13 #ifdef WITH_CONTENT_SCAN /* entire file */
15 typedef enum {M_FPROTD, M_DRWEB, M_AVES, M_FSEC, M_KAVD, M_CMDL,
16 M_SOPHIE, M_CLAMD, M_SOCK, M_MKSD, M_AVAST, M_FPROT6D} scanner_t;
17 typedef enum {MC_NONE, MC_TCP, MC_UNIX, MC_STRM} contype_t;
22 const uschar * options_default;
26 #ifndef DISABLE_MAL_FFROTD
27 { M_FPROTD, US"f-protd", US"localhost 10200-10204", MC_TCP },
29 #ifndef DISABLE_MAL_FFROT6D
30 { M_FPROT6D, US"f-prot6d", US"localhost 10200", MC_TCP },
32 #ifndef DISABLE_MAL_DRWEB
33 { M_DRWEB, US"drweb", US"/usr/local/drweb/run/drwebd.sock", MC_STRM },
35 #ifndef DISABLE_MAL_AVE
36 { M_AVES, US"aveserver", US"/var/run/aveserver", MC_UNIX },
38 #ifndef DISABLE_MAL_FSECURE
39 { M_FSEC, US"fsecure", US"/var/run/.fsav", MC_UNIX },
41 #ifndef DISABLE_MAL_KAV
42 { M_KAVD, US"kavdaemon", US"/var/run/AvpCtl", MC_UNIX },
44 #ifndef DISABLE_MAL_SOPHIE
45 { M_SOPHIE, US"sophie", US"/var/run/sophie", MC_UNIX },
47 #ifndef DISABLE_MAL_CLAM
48 { M_CLAMD, US"clamd", US"/tmp/clamd", MC_NONE },
50 #ifndef DISABLE_MAL_MKS
51 { M_MKSD, US"mksd", NULL, MC_NONE },
53 #ifndef DISABLE_MAL_AVAST
54 { M_AVAST, US"avast", US"/var/run/avast/scan.sock", MC_STRM },
56 #ifndef DISABLE_MAL_SOCK
57 { M_SOCK, US"sock", US"/tmp/malware.sock", MC_STRM },
59 #ifndef DISABLE_MAL_CMDLINE
60 { M_CMDL, US"cmdline", NULL, MC_NONE },
62 { -1, NULL, NULL, MC_NONE } /* end-marker */
65 /******************************************************************************/
66 # ifdef MACRO_PREDEF /* build solely to predefine macros */
68 # include "macro_predef.h"
71 features_malware(void)
73 const struct scan * sc;
78 spf(buf, sizeof(buf), US"_HAVE_MALWARE_");
80 for (sc = m_scans; sc->scancode != -1; sc++)
82 for(s = sc->name, t = buf+14; *s; s++) if (*s != '-') *t++ = toupper(*s);
84 builtin_macro_create(buf);
88 /******************************************************************************/
89 # else /*!MACRO_PREDEF, main build*/
92 #define MALWARE_TIMEOUT 120 /* default timeout, seconds */
94 static const uschar * malware_regex_default = US ".+";
95 static const pcre * malware_default_re = NULL;
99 #ifndef DISABLE_MAL_CLAM
100 /* The maximum number of clamd servers that are supported in the configuration */
101 # define MAX_CLAMD_SERVERS 32
102 # define MAX_CLAMD_SERVERS_S "32"
104 typedef struct clamd_address {
112 #ifndef DISABLE_MAL_DRWEB
113 # define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */
114 # define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */
115 # define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */
117 # define DERR_READ_ERR (1<<0) /* read error */
118 # define DERR_NOMEMORY (1<<2) /* no memory */
119 # define DERR_TIMEOUT (1<<9) /* scan timeout has run out */
120 # define DERR_BAD_CALL (1<<15) /* wrong command */
122 static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$";
123 static const pcre * drweb_re = NULL;
126 #ifndef DISABLE_MAL_FSECURE
127 static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$";
128 static const pcre * fsec_re = NULL;
131 #ifndef DISABLE_MAL_KAV
132 static const uschar * kav_re_sus_str = US "suspicion:\\s*(.+?)\\s*$";
133 static const uschar * kav_re_inf_str = US "infected:\\s*(.+?)\\s*$";
134 static const pcre * kav_re_sus = NULL;
135 static const pcre * kav_re_inf = NULL;
138 #ifndef DISABLE_MAL_AVAST
139 static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]";
140 static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d+\\.0\\t0\\s(.*)";
141 static const uschar * ava_re_error_str = US "(?!\\\\)\\t\\[E\\]\\d+\\.0\\tError\\s\\d+\\s(.*)";
142 static const pcre * ava_re_clean = NULL;
143 static const pcre * ava_re_virus = NULL;
144 static const pcre * ava_re_error = NULL;
147 #ifndef DISABLE_MAL_FFROT6D
148 static const uschar * fprot6d_re_error_str = US "^\\d+\\s<(.+?)>$";
149 static const uschar * fprot6d_re_virus_str = US "^\\d+\\s<infected:\\s+(.+?)>\\s+.+$";
150 static const pcre * fprot6d_re_error = NULL;
151 static const pcre * fprot6d_re_virus = NULL;
156 /******************************************************************************/
158 /* Routine to check whether a system is big- or little-endian.
159 Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
160 Needed for proper kavdaemon implementation. Sigh. */
161 #define BIG_MY_ENDIAN 0
162 #define LITTLE_MY_ENDIAN 1
163 static int test_byte_order(void);
167 short int word = 0x0001;
168 char *byte = CS &word;
169 return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
172 BOOL malware_ok = FALSE;
174 /* Gross hacks for the -bmalware option; perhaps we should just create
175 the scan directory normally for that case, but look into rigging up the
176 needed header variables if not already set on the command-line? */
177 extern int spool_mbox_ok;
178 extern uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
181 /* Some (currently avast only) use backslash escaped whitespace,
182 this function undoes these escapes */
187 if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
188 for (p0 = p; *p0; ++p0) *p0 = p0[1];
191 /* --- malware_*_defer --- */
193 malware_panic_defer(const uschar * str)
195 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
199 malware_log_defer(const uschar * str)
201 log_write(0, LOG_MAIN, "malware acl condition: %s", str);
204 /* --- m_*_defer --- */
206 m_panic_defer(struct scan * scanent, const uschar * hostport,
209 return malware_panic_defer(string_sprintf("%s %s : %s",
210 scanent->name, hostport ? hostport : CUS"", str));
213 m_log_defer(struct scan * scanent, const uschar * hostport,
216 return malware_log_defer(string_sprintf("%s %s : %s",
217 scanent->name, hostport ? hostport : CUS"", str));
219 /* --- m_*_defer_3 */
221 m_panic_defer_3(struct scan * scanent, const uschar * hostport,
222 const uschar * str, int fd_to_close)
224 (void) close(fd_to_close);
225 return m_panic_defer(scanent, hostport, str);
228 m_log_defer_3(struct scan * scanent, const uschar * hostport,
229 const uschar * str, int fd_to_close)
231 (void) close(fd_to_close);
232 return m_log_defer(scanent, hostport, str);
235 /*************************************************/
237 #ifndef DISABLE_MAL_CLAM
238 /* Only used by the Clamav code, which is working from a list of servers and
239 uses the returned in_addr to get a second connection to the same system.
242 m_tcpsocket(const uschar * hostname, unsigned int port,
243 host_item * host, uschar ** errstr, const blob * fastopen_blob)
245 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
246 host, errstr, fastopen_blob);
251 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
253 if (send(sock, buf, cnt, 0) < 0)
257 *errstr = string_sprintf("unable to send to socket (%s): %s",
265 m_pcre_compile(const uschar * re, uschar ** errstr)
267 const uschar * rerror;
271 cre = pcre_compile(CS re, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
273 *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
274 re, rerror, roffset);
279 m_pcre_exec(const pcre * cre, uschar * text)
282 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
283 ovector, nelem(ovector));
284 uschar * substr = NULL;
285 if (i >= 2) /* Got it */
286 pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr);
291 m_pcre_nextinlist(const uschar ** list, int * sep,
292 char * listerr, uschar ** errstr)
294 const uschar * list_ele;
295 const pcre * cre = NULL;
297 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
298 *errstr = US listerr;
301 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
302 string_printing(list_ele));
303 cre = m_pcre_compile(CUS list_ele, errstr);
309 Simple though inefficient wrapper for reading a line. Drop CRs and the
310 trailing newline. Can return early on buffer full. Null-terminate.
311 Apply initial timeout if no data ready.
313 Return: number of chars - zero for an empty line
315 -2 on timeout or error
318 recv_line(int fd, uschar * buffer, int bsize, int tmo)
324 if (!fd_ready(fd, tmo-time(NULL)))
327 /*XXX tmo handling assumes we always get a whole line */
330 while ((rcv = read(fd, p, 1)) > 0)
333 if (p-buffer > bsize-2) break;
334 if (*p == '\n') break;
339 DEBUG(D_acl) debug_printf_indent("Malware scan: read %s (%s)\n",
340 rcv==0 ? "EOF" : "error", strerror(errno));
341 return rcv==0 ? -1 : -2;
345 DEBUG(D_acl) debug_printf_indent("Malware scan: read '%s'\n", buffer);
349 /* return TRUE iff size as requested */
351 recv_len(int sock, void * buf, int size, int tmo)
353 return fd_ready(sock, tmo-time(NULL))
354 ? recv(sock, buf, size, 0) == size
360 #ifndef DISABLE_MAL_MKS
361 /* ============= private routines for the "mksd" scanner type ============== */
363 # include <sys/uio.h>
366 mksd_writev (int sock, struct iovec * iov, int iovcnt)
373 i = writev (sock, iov, iovcnt);
374 while (i < 0 && errno == EINTR);
377 (void) malware_panic_defer(
378 US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
381 for (;;) /* check for short write */
382 if (i >= iov->iov_len)
392 iov->iov_base = CS iov->iov_base + i;
399 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, int tmo)
406 i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL));
409 (void) malware_panic_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
414 /* offset == av_buffer_size -> buffer full */
415 if (offset == av_buffer_size)
417 (void) malware_panic_defer(US"malformed reply received from mksd");
420 } while (av_buffer[offset-1] != '\n');
422 av_buffer[offset] = '\0';
427 mksd_parse_line(struct scan * scanent, char * line)
438 if ((p = strchr (line, '\n')) != NULL)
440 return m_panic_defer(scanent, NULL,
441 string_sprintf("scanner failed: %s", line));
444 if ((p = strchr (line, '\n')) != NULL)
449 && (p = strchr(line+4, ' ')) != NULL
454 malware_name = string_copy(US line+4);
458 return m_panic_defer(scanent, NULL,
459 string_sprintf("malformed reply received: %s", line));
464 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
468 const char *cmd = "MSQ\n";
469 uschar av_buffer[1024];
471 iov[0].iov_base = (void *) cmd;
473 iov[1].iov_base = (void *) scan_filename;
474 iov[1].iov_len = Ustrlen(scan_filename);
475 iov[2].iov_base = (void *) (cmd + 3);
478 if (mksd_writev (sock, iov, 3) < 0)
481 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
484 return mksd_parse_line (scanent, CS av_buffer);
489 #ifndef DISABLE_MAL_CLAM
491 clamd_option(clamd_address * cd, const uschar * optstr, int * subsep)
496 while ((s = string_nextinlist(&optstr, subsep, NULL, 0)))
497 if (Ustrncmp(s, "retry=", 6) == 0)
499 int sec = readconf_readtime((s += 6), '\0', FALSE);
512 /*************************************************
513 * Scan content for malware *
514 *************************************************/
516 /* This is an internal interface for scanning an email; the normal interface
517 is via malware(), or there's malware_in_file() used for testing/debugging.
520 malware_re match condition for "malware="
521 scan_filename the file holding the email to be scanned, if we're faking
522 this up for the -bmalware test, else NULL
523 timeout if nonzero, non-default timeoutl
525 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
526 where true means malware was found (condition applies)
529 malware_internal(const uschar * malware_re, const uschar * scan_filename,
533 const uschar *av_scanner_work = av_scanner;
534 uschar *scanner_name;
535 unsigned long mbox_size;
539 struct scan * scanent;
540 const uschar * scanner_options;
543 uschar * eml_filename, * eml_dir;
546 return FAIL; /* empty means "don't match anything" */
548 /* Ensure the eml mbox file is spooled up */
550 if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
551 return malware_panic_defer(US"error while creating mbox spool file");
553 /* None of our current scanners need the mbox file as a stream (they use
554 the name), so we can close it right away. Get the directory too. */
556 (void) fclose(mbox_file);
557 eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
559 /* parse 1st option */
560 if (strcmpic(malware_re, US"false") == 0 || Ustrcmp(malware_re,"0") == 0)
561 return FAIL; /* explicitly no matching */
563 /* special cases (match anything except empty) */
564 if ( strcmpic(malware_re,US"true") == 0
565 || Ustrcmp(malware_re,"*") == 0
566 || Ustrcmp(malware_re,"1") == 0
569 if ( !malware_default_re
570 && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
571 return malware_panic_defer(errstr);
572 malware_re = malware_regex_default;
573 re = malware_default_re;
576 /* compile the regex, see if it works */
577 else if (!(re = m_pcre_compile(malware_re, &errstr)))
578 return malware_panic_defer(errstr);
580 /* if av_scanner starts with a dollar, expand it first */
581 if (*av_scanner == '$')
583 if (!(av_scanner_work = expand_string(av_scanner)))
584 return malware_panic_defer(
585 string_sprintf("av_scanner starts with $, but expansion failed: %s",
586 expand_string_message));
589 debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work);
590 /* disable result caching in this case */
595 /* Do not scan twice (unless av_scanner is dynamic). */
598 /* find the scanner type from the av_scanner option */
599 if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
600 return malware_panic_defer(US"av_scanner configuration variable is empty");
601 if (!timeout) timeout = MALWARE_TIMEOUT;
602 tmo = time(NULL) + timeout;
604 for (scanent = m_scans; ; scanent++)
607 return malware_panic_defer(string_sprintf("unknown scanner type '%s'",
609 if (strcmpic(scanner_name, US scanent->name) != 0)
611 DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo=%s\n",
612 scanner_name, readconf_printtime(timeout));
614 if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
615 scanner_options = scanent->options_default;
616 if (scanent->conn == MC_NONE)
619 DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
620 switch(scanent->conn)
622 case MC_TCP: sock = ip_tcpsocket(scanner_options, &errstr, 5); break;
623 case MC_UNIX: sock = ip_unixsocket(scanner_options, &errstr); break;
624 case MC_STRM: sock = ip_streamsocket(scanner_options, &errstr, 5); break;
625 default: /* compiler quietening */ break;
628 return m_panic_defer(scanent, CUS callout_address, errstr);
632 switch (scanent->scancode)
634 #ifndef DISABLE_MAL_FFROTD
635 case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
637 uschar *fp_scan_option;
638 unsigned int detected=0, par_count=0;
639 uschar * scanrequest;
640 uschar buf[32768], *strhelper, *strhelper2;
641 uschar * malware_name_internal = NULL;
644 scanrequest = string_sprintf("GET %s", eml_filename);
646 while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
649 scanrequest = string_sprintf("%s%s%s", scanrequest,
650 par_count ? "%20" : "?", fp_scan_option);
653 scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
654 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
655 scanner_name, scanrequest);
657 /* send scan request */
658 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
659 return m_panic_defer(scanent, CUS callout_address, errstr);
661 while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0)
664 if (Ustrstr(buf, US"<detected type=\"") != NULL)
666 else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
668 if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
671 malware_name_internal = string_copy(strhelper+6);
674 else if (Ustrstr(buf, US"<summary code=\""))
676 malware_name = Ustrstr(buf, US"<summary code=\"11\">")
677 ? malware_name_internal : NULL;
690 #ifndef DISABLE_MAL_FFROT6D
691 case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
696 uschar * scanrequest;
697 uschar av_buffer[1024];
699 if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
700 || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
701 return malware_panic_defer(errstr);
703 scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
704 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
705 scanner_name, scanrequest);
707 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
708 return m_panic_defer(scanent, CUS callout_address, errstr);
710 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
713 return m_panic_defer_3(scanent, CUS callout_address,
714 string_sprintf("unable to read from socket (%s)", strerror(errno)),
717 if (bread == sizeof(av_buffer))
718 return m_panic_defer_3(scanent, CUS callout_address,
719 US"buffer too small", sock);
721 av_buffer[bread] = '\0';
722 linebuffer = string_copy(av_buffer);
724 m_sock_send(sock, US"QUIT\n", 5, 0);
726 if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
727 return m_panic_defer_3(scanent, CUS callout_address,
728 string_sprintf("scanner reported error (%s)", e), sock);
730 if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
737 #ifndef DISABLE_MAL_DRWEB
738 case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
739 /* v0.1 - added support for tcp sockets */
740 /* v0.0 - initial release -- support for unix sockets */
744 unsigned int fsize_uint;
745 uschar * tmpbuf, *drweb_fbuf;
746 int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
747 drweb_vnum, drweb_slen, drweb_fin = 0x0000;
749 /* prepare variables */
750 drweb_cmd = htonl(DRWEBD_SCAN_CMD);
751 drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
753 if (*scanner_options != '/')
756 if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1)
757 return m_panic_defer_3(scanent, NULL,
758 string_sprintf("can't open spool file %s: %s",
759 eml_filename, strerror(errno)),
762 if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
765 badseek: err = errno;
766 (void)close(drweb_fd);
767 return m_panic_defer_3(scanent, NULL,
768 string_sprintf("can't seek spool file %s: %s",
769 eml_filename, strerror(err)),
772 fsize_uint = (unsigned int) fsize;
773 if ((off_t)fsize_uint != fsize)
775 (void)close(drweb_fd);
776 return m_panic_defer_3(scanent, NULL,
777 string_sprintf("seeking spool file %s, size overflow",
781 drweb_slen = htonl(fsize);
782 if (lseek(drweb_fd, 0, SEEK_SET) < 0)
785 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
786 scanner_name, scanner_options);
788 /* send scan request */
789 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
790 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
791 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
792 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
794 (void)close(drweb_fd);
795 return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
796 "unable to send commands to socket (%s)", scanner_options),
800 if (!(drweb_fbuf = US malloc(fsize_uint)))
802 (void)close(drweb_fd);
803 return m_panic_defer_3(scanent, NULL,
804 string_sprintf("unable to allocate memory %u for file (%s)",
805 fsize_uint, eml_filename),
809 if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
812 (void)close(drweb_fd);
814 return m_panic_defer_3(scanent, NULL,
815 string_sprintf("can't read spool file %s: %s",
816 eml_filename, strerror(err)),
819 (void)close(drweb_fd);
821 /* send file body to socket */
822 if (send(sock, drweb_fbuf, fsize, 0) < 0)
825 return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
826 "unable to send file body to socket (%s)", scanner_options),
832 drweb_slen = htonl(Ustrlen(eml_filename));
834 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n",
835 scanner_name, scanner_options);
837 /* send scan request */
838 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
839 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
840 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
841 (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
842 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
843 return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
844 "unable to send commands to socket (%s)", scanner_options),
848 /* wait for result */
849 if (!recv_len(sock, &drweb_rc, sizeof(drweb_rc), tmo))
850 return m_panic_defer_3(scanent, CUS callout_address,
851 US"unable to read return code", sock);
852 drweb_rc = ntohl(drweb_rc);
854 if (!recv_len(sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
855 return m_panic_defer_3(scanent, CUS callout_address,
856 US"unable to read the number of viruses", sock);
857 drweb_vnum = ntohl(drweb_vnum);
859 /* "virus(es) found" if virus number is > 0 */
865 /* setup default virus name */
866 malware_name = US"unknown";
868 /* set up match regex */
870 drweb_re = m_pcre_compile(drweb_re_str, &errstr);
872 /* read and concatenate virus names into one string */
873 for (i = 0; i < drweb_vnum; i++)
877 /* read the size of report */
878 if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
879 return m_panic_defer_3(scanent, CUS callout_address,
880 US"cannot read report size", sock);
881 drweb_slen = ntohl(drweb_slen);
882 tmpbuf = store_get(drweb_slen);
884 /* read report body */
885 if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
886 return m_panic_defer_3(scanent, CUS callout_address,
887 US"cannot read report string", sock);
888 tmpbuf[drweb_slen] = '\0';
890 /* try matcher on the line, grab substring */
891 result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
892 ovector, nelem(ovector));
895 const char * pre_malware_nb;
897 pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
899 if (i==0) /* the first name we just copy to malware_name */
900 g = string_cat(NULL, US pre_malware_nb);
902 /*XXX could be string_append_listele? */
903 else /* concatenate each new virus name to previous */
904 g = string_append(g, 2, "/", pre_malware_nb);
906 pcre_free_substring(pre_malware_nb);
909 malware_name = string_from_gstring(g);
913 const char *drweb_s = NULL;
915 if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
916 if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
917 if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
918 if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
919 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
920 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
921 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
922 * and others are ignored */
924 return m_panic_defer_3(scanent, CUS callout_address,
925 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
935 #ifndef DISABLE_MAL_AVE
936 case M_AVES: /* "aveserver" scanner type -------------------------------- */
941 /* read aveserver's greeting and see if it is ready (2xx greeting) */
943 recv_line(sock, buf, sizeof(buf), tmo);
945 if (buf[0] != '2') /* aveserver is having problems */
946 return m_panic_defer_3(scanent, CUS callout_address,
947 string_sprintf("unavailable (Responded: %s).",
948 ((buf[0] != 0) ? buf : US "nothing") ),
951 /* prepare our command */
952 (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
956 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
958 if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
959 return m_panic_defer(scanent, CUS callout_address, errstr);
963 /* read response lines, find malware name and final response */
964 while (recv_line(sock, buf, sizeof(buf), tmo) > 0)
968 if (buf[0] == '5') /* aveserver is having problems */
970 result = m_panic_defer(scanent, CUS callout_address,
971 string_sprintf("unable to scan file %s (Responded: %s).",
975 if (Ustrncmp(buf,"322",3) == 0)
977 uschar *p = Ustrchr(&buf[4], ' ');
979 malware_name = string_copy(&buf[4]);
983 if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
984 return m_panic_defer(scanent, CUS callout_address, errstr);
986 /* read aveserver's greeting and see if it is ready (2xx greeting) */
988 recv_line(sock, buf, sizeof(buf), tmo);
990 if (buf[0] != '2') /* aveserver is having problems */
991 return m_panic_defer_3(scanent, CUS callout_address,
992 string_sprintf("unable to quit dialogue (Responded: %s).",
993 ((buf[0] != 0) ? buf : US "nothing") ),
1005 #ifndef DISABLE_MAL_FSECURE
1006 case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
1008 int i, j, bread = 0;
1010 uschar av_buffer[1024];
1011 static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
1012 US"CONFIGURE\tTIMEOUT\t0\n",
1013 US"CONFIGURE\tMAXARCH\t5\n",
1014 US"CONFIGURE\tMIME\t1\n" };
1016 malware_name = NULL;
1018 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1019 scanner_name, scanner_options);
1021 memset(av_buffer, 0, sizeof(av_buffer));
1022 for (i = 0; i != nelem(cmdopt); i++)
1025 if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
1026 return m_panic_defer(scanent, CUS callout_address, errstr);
1028 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1029 if (bread > 0) av_buffer[bread]='\0';
1031 return m_panic_defer_3(scanent, CUS callout_address,
1032 string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
1034 for (j = 0; j < bread; j++)
1035 if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
1039 /* pass the mailfile to fsecure */
1040 file_name = string_sprintf("SCAN\t%s\n", eml_filename);
1042 if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
1043 return m_panic_defer(scanent, CUS callout_address, errstr);
1046 /* todo also SUSPICION\t */
1048 fsec_re = m_pcre_compile(fsec_re_str, &errstr);
1050 /* read report, linewise. Apply a timeout as the Fsecure daemon
1051 sometimes wants an answer to "PING" but they won't tell us what */
1053 uschar * p = av_buffer;
1059 i = av_buffer+sizeof(av_buffer)-p;
1060 if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
1061 return m_panic_defer_3(scanent, CUS callout_address,
1062 string_sprintf("unable to read result (%s)", strerror(errno)),
1065 for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
1069 /* Really search for virus again? */
1071 /* try matcher on the line, grab substring */
1072 malware_name = m_pcre_exec(fsec_re, p);
1074 if (Ustrstr(p, "OK\tScan ok."))
1078 /* copy down the trailing partial line then read another chunk */
1079 i = av_buffer+sizeof(av_buffer)-p;
1080 memmove(av_buffer, p, i);
1090 #ifndef DISABLE_MAL_KAV
1091 case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
1094 uschar tmpbuf[1024];
1095 uschar * scanrequest;
1097 unsigned long kav_reportlen;
1102 /* get current date and time, build scan request */
1104 /* pdp note: before the eml_filename parameter, this scanned the
1105 directory; not finding documentation, so we'll strip off the directory.
1106 The side-effect is that the test framework scanning may end up in
1107 scanning more than was requested, but for the normal interface, this is
1110 strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
1111 scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
1112 p = Ustrrchr(scanrequest, '/');
1116 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1117 scanner_name, scanner_options);
1119 /* send scan request */
1120 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
1121 return m_panic_defer(scanent, CUS callout_address, errstr);
1123 /* wait for result */
1124 if (!recv_len(sock, tmpbuf, 2, tmo))
1125 return m_panic_defer_3(scanent, CUS callout_address,
1126 US"unable to read 2 bytes from socket.", sock);
1128 /* get errorcode from one nibble */
1129 kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
1132 case 5: case 6: /* improper kavdaemon configuration */
1133 return m_panic_defer_3(scanent, CUS callout_address,
1134 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
1137 return m_panic_defer_3(scanent, CUS callout_address,
1138 US"reported 'scanning not completed' (code 1).", sock);
1140 return m_panic_defer_3(scanent, CUS callout_address,
1141 US"reported 'kavdaemon damaged' (code 7).", sock);
1144 /* code 8 is not handled, since it is ambiguous. It appears mostly on
1145 bounces where part of a file has been cut off */
1147 /* "virus found" return codes (2-4) */
1148 if (kav_rc > 1 && kav_rc < 5)
1150 int report_flag = 0;
1152 /* setup default virus name */
1153 malware_name = US"unknown";
1155 report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
1157 /* read the report, if available */
1158 if (report_flag == 1)
1160 /* read report size */
1161 if (!recv_len(sock, &kav_reportlen, 4, tmo))
1162 return m_panic_defer_3(scanent, CUS callout_address,
1163 US"cannot read report size", sock);
1165 /* it's possible that avp returns av_buffer[1] == 1 but the
1166 reportsize is 0 (!?) */
1167 if (kav_reportlen > 0)
1169 /* set up match regex, depends on retcode */
1172 if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1173 kav_re = kav_re_sus;
1177 if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1178 kav_re = kav_re_inf;
1181 /* read report, linewise. Using size from stream to read amount of data
1182 from same stream is safe enough. */
1183 /* coverity[tainted_data] */
1184 while (kav_reportlen > 0)
1186 if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1188 kav_reportlen -= bread+1;
1190 /* try matcher on the line, grab substring */
1191 if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1197 else /* no virus found */
1198 malware_name = NULL;
1204 #ifndef DISABLE_MAL_CMDLINE
1205 case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1207 const uschar *cmdline_scanner = scanner_options;
1208 const pcre *cmdline_trigger_re;
1209 const pcre *cmdline_regex_re;
1211 uschar * commandline;
1212 void (*eximsigchld)(int);
1213 void (*eximsigpipe)(int);
1214 FILE *scanner_out = NULL;
1216 FILE *scanner_record = NULL;
1217 uschar linebuffer[32767];
1222 if (!cmdline_scanner)
1223 return m_panic_defer(scanent, NULL, errstr);
1225 /* find scanner output trigger */
1226 cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1227 "missing trigger specification", &errstr);
1228 if (!cmdline_trigger_re)
1229 return m_panic_defer(scanent, NULL, errstr);
1231 /* find scanner name regex */
1232 cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1233 "missing virus name regex specification", &errstr);
1234 if (!cmdline_regex_re)
1235 return m_panic_defer(scanent, NULL, errstr);
1237 /* prepare scanner call; despite the naming, file_name holds a directory
1238 name which is documented as the value given to %s. */
1240 file_name = string_copy(eml_filename);
1241 p = Ustrrchr(file_name, '/');
1244 commandline = string_sprintf(CS cmdline_scanner, file_name);
1246 /* redirect STDERR too */
1247 commandline = string_sprintf("%s 2>&1", commandline);
1249 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1250 scanner_name, commandline);
1252 /* store exims signal handlers */
1253 eximsigchld = signal(SIGCHLD,SIG_DFL);
1254 eximsigpipe = signal(SIGPIPE,SIG_DFL);
1256 if (!(scanner_out = popen(CS commandline,"r")))
1259 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1260 return m_panic_defer(scanent, NULL,
1261 string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1263 scanner_fd = fileno(scanner_out);
1265 file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
1267 if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1270 (void) pclose(scanner_out);
1271 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1272 return m_panic_defer(scanent, NULL, string_sprintf(
1273 "opening scanner output file (%s) failed: %s.",
1274 file_name, strerror(err)));
1277 /* look for trigger while recording output */
1278 while ((rcnt = recv_line(scanner_fd, linebuffer,
1279 sizeof(linebuffer), tmo)))
1286 (void) pclose(scanner_out);
1287 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1288 return m_panic_defer(scanent, NULL, string_sprintf(
1289 "unable to read from scanner (%s): %s",
1290 commandline, strerror(err)));
1293 if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1296 (void) pclose(scanner_out);
1297 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1298 return m_panic_defer(scanent, NULL, string_sprintf(
1299 "short write on scanner output file (%s).", file_name));
1301 putc('\n', scanner_record);
1302 /* try trigger match */
1304 && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1309 (void)fclose(scanner_record);
1310 sep = pclose(scanner_out);
1311 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1313 return m_panic_defer(scanent, NULL,
1315 ? string_sprintf("running scanner failed: %s", strerror(sep))
1316 : string_sprintf("scanner returned error code: %d", sep));
1321 /* setup default virus name */
1322 malware_name = US"unknown";
1324 /* re-open the scanner output file, look for name match */
1325 scanner_record = fopen(CS file_name, "rb");
1326 while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1329 if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1332 (void)fclose(scanner_record);
1334 else /* no virus found */
1335 malware_name = NULL;
1340 #ifndef DISABLE_MAL_SOPHIE
1341 case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1346 uschar av_buffer[1024];
1348 /* pass the scan directory to sophie */
1349 file_name = string_copy(eml_filename);
1350 if ((p = Ustrrchr(file_name, '/')))
1353 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1354 scanner_name, scanner_options);
1356 if ( write(sock, file_name, Ustrlen(file_name)) < 0
1357 || write(sock, "\n", 1) != 1
1359 return m_panic_defer_3(scanent, CUS callout_address,
1360 string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1363 /* wait for result */
1364 memset(av_buffer, 0, sizeof(av_buffer));
1365 if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1366 return m_panic_defer_3(scanent, CUS callout_address,
1367 string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1371 if (av_buffer[0] == '1') {
1372 uschar * s = Ustrchr(av_buffer, '\n');
1375 malware_name = string_copy(&av_buffer[2]);
1377 else if (!strncmp(CS av_buffer, "-1", 2))
1378 return m_panic_defer_3(scanent, CUS callout_address,
1379 US"scanner reported error", sock);
1380 else /* all ok, no virus */
1381 malware_name = NULL;
1387 #ifndef DISABLE_MAL_CLAM
1388 case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1390 /* This code was originally contributed by David Saez */
1391 /* There are three scanning methods available to us:
1392 * (1) Use the SCAN command, pointing to a file in the filesystem
1393 * (2) Use the STREAM command, send the data on a separate port
1394 * (3) Use the zINSTREAM command, send the data inline
1395 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1396 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1397 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1398 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM
1399 * See Exim bug 926 for details. */
1401 uschar *p, *vname, *result_tag;
1403 uschar av_buffer[1024];
1404 uschar *hostname = US"";
1406 uschar *clamav_fbuf;
1407 int clam_fd, result;
1409 unsigned int fsize_uint;
1410 BOOL use_scan_command = FALSE;
1411 clamd_address * cv[MAX_CLAMD_SERVERS];
1412 int num_servers = 0;
1413 uint32_t send_size, send_final_zeroblock;
1416 /*XXX if unixdomain socket, only one server supported. Needs fixing;
1417 there's no reason we should not mix local and remote servers */
1419 if (*scanner_options == '/')
1422 const uschar * sublist;
1425 /* Local file; so we def want to use_scan_command and don't want to try
1426 * passing IP/port combinations */
1427 use_scan_command = TRUE;
1428 cd = (clamd_address *) store_get(sizeof(clamd_address));
1430 /* extract socket-path part */
1431 sublist = scanner_options;
1432 cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1435 if (clamd_option(cd, sublist, &subsep) != OK)
1436 return m_panic_defer(scanent, NULL,
1437 string_sprintf("bad option '%s'", scanner_options));
1442 /* Go through the rest of the list of host/port and construct an array
1443 * of servers to try. The first one is the bit we just passed from
1444 * scanner_options so process that first and then scan the remainder of
1445 * the address buffer */
1449 const uschar * sublist;
1453 /* The 'local' option means use the SCAN command over the network
1454 * socket (ie common file storage in use) */
1455 /*XXX we could accept this also as a local option? */
1456 if (strcmpic(scanner_options, US"local") == 0)
1458 use_scan_command = TRUE;
1462 cd = (clamd_address *) store_get(sizeof(clamd_address));
1464 /* extract host and port part */
1465 sublist = scanner_options;
1466 if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1468 (void) m_panic_defer(scanent, NULL,
1469 string_sprintf("missing address: '%s'", scanner_options));
1472 if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1474 (void) m_panic_defer(scanent, NULL,
1475 string_sprintf("missing port: '%s'", scanner_options));
1478 cd->tcp_port = atoi(CS s);
1481 /*XXX should these options be common over scanner types? */
1482 if (clamd_option(cd, sublist, &subsep) != OK)
1483 return m_panic_defer(scanent, NULL,
1484 string_sprintf("bad option '%s'", scanner_options));
1486 cv[num_servers++] = cd;
1487 if (num_servers >= MAX_CLAMD_SERVERS)
1489 (void) m_panic_defer(scanent, NULL,
1490 US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1491 "specified; only using the first " MAX_CLAMD_SERVERS_S );
1494 } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1497 /* check if we have at least one server */
1499 return m_panic_defer(scanent, NULL,
1500 US"no useable server addresses in malware configuration option.");
1503 /* See the discussion of response formats below to see why we really
1504 don't like colons in filenames when passing filenames to ClamAV. */
1505 if (use_scan_command && Ustrchr(eml_filename, ':'))
1506 return m_panic_defer(scanent, NULL,
1507 string_sprintf("local/SCAN mode incompatible with" \
1508 " : in path to email filename [%s]", eml_filename));
1510 /* Set up the very first data we will be sending */
1511 if (!use_scan_command)
1512 { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1515 cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
1516 cmd_str.len = Ustrlen(cmd_str.data);
1519 /* We have some network servers specified */
1522 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1523 * only supports AF_INET, but we should probably be looking to the
1524 * future and rewriting this to be protocol-independent anyway. */
1526 while (num_servers > 0)
1528 int i = random_number(num_servers);
1529 clamd_address * cd = cv[i];
1531 DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1532 cd->hostspec, cd->tcp_port);
1534 /* Lookup the host. This is to ensure that we connect to the same IP
1535 * on both connections (as one host could resolve to multiple ips) */
1538 if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1539 &connhost, &errstr, &cmd_str)) >= 0)
1541 /* Connection successfully established with a server */
1542 hostname = cd->hostspec;
1546 if (cd->retry <= 0) break;
1547 while (cd->retry > 0) cd->retry = sleep(cd->retry);
1552 (void) m_panic_defer(scanent, CUS callout_address, errstr);
1554 /* Remove the server from the list. XXX We should free the memory */
1556 for (; i < num_servers; i++)
1560 if (num_servers == 0)
1561 return m_panic_defer(scanent, NULL, US"all servers failed");
1566 if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1568 hostname = cv[0]->hostspec;
1571 if (cv[0]->retry <= 0)
1572 return m_panic_defer(scanent, CUS callout_address, errstr);
1573 while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1576 /* have socket in variable "sock"; command to use is semi-independent of
1577 * the socket protocol. We use SCAN if is local (either Unix/local
1578 * domain socket, or explicitly told local) else we stream the data.
1579 * How we stream the data depends upon how we were built. */
1581 if (!use_scan_command)
1583 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1584 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1587 DEBUG(D_acl) debug_printf_indent(
1588 "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1591 /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1593 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1594 return m_panic_defer_3(scanent, CUS hostname,
1595 string_sprintf("unable to send zINSTREAM to socket (%s)",
1599 /* calc file size */
1600 if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1603 return m_panic_defer_3(scanent, NULL,
1604 string_sprintf("can't open spool file %s: %s",
1605 eml_filename, strerror(err)),
1608 if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1611 b_seek: err = errno;
1612 (void)close(clam_fd);
1613 return m_panic_defer_3(scanent, NULL,
1614 string_sprintf("can't seek spool file %s: %s",
1615 eml_filename, strerror(err)),
1618 fsize_uint = (unsigned int) fsize;
1619 if ((off_t)fsize_uint != fsize)
1621 (void)close(clam_fd);
1622 return m_panic_defer_3(scanent, NULL,
1623 string_sprintf("seeking spool file %s, size overflow",
1627 if (lseek(clam_fd, 0, SEEK_SET) < 0)
1630 if (!(clamav_fbuf = US malloc(fsize_uint)))
1632 (void)close(clam_fd);
1633 return m_panic_defer_3(scanent, NULL,
1634 string_sprintf("unable to allocate memory %u for file (%s)",
1635 fsize_uint, eml_filename),
1639 if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1642 free(clamav_fbuf); (void)close(clam_fd);
1643 return m_panic_defer_3(scanent, NULL,
1644 string_sprintf("can't read spool file %s: %s",
1645 eml_filename, strerror(err)),
1648 (void)close(clam_fd);
1650 /* send file body to socket */
1651 send_size = htonl(fsize_uint);
1652 send_final_zeroblock = 0;
1653 if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1654 (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1655 (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1658 return m_panic_defer_3(scanent, NULL,
1659 string_sprintf("unable to send file body to socket (%s)", hostname),
1666 { /* use scan command */
1667 /* Send a SCAN command pointing to a filename; then in the then in the
1668 * scan-method-neutral part, read the response back */
1670 /* ================================================================= */
1672 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1673 which dates to when ClamAV needed us to break apart the email into the
1674 MIME parts (eg, with the now deprecated demime condition coming first).
1675 Some time back, ClamAV gained the ability to deconstruct the emails, so
1676 doing this would actually have resulted in the mail attachments being
1677 scanned twice, in the broken out files and from the original .eml.
1678 Since ClamAV now handles emails (and has for quite some time) we can
1679 just use the email file itself. */
1680 /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
1682 DEBUG(D_acl) debug_printf_indent(
1683 "Malware scan: issuing %s local-path scan [%s]\n",
1684 scanner_name, scanner_options);
1687 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1688 return m_panic_defer_3(scanent, CUS callout_address,
1689 string_sprintf("unable to write to socket (%s)", strerror(errno)),
1692 /* Do not shut down the socket for writing; a user report noted that
1693 * clamd 0.70 does not react well to this. */
1695 /* Commands have been sent, no matter which scan method or connection
1696 * type we're using; now just read the result, independent of method. */
1698 /* Read the result */
1699 memset(av_buffer, 0, sizeof(av_buffer));
1700 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1705 return m_panic_defer(scanent, CUS callout_address,
1706 string_sprintf("unable to read from socket (%s)",
1707 errno == 0 ? "EOF" : strerror(errno)));
1709 if (bread == sizeof(av_buffer))
1710 return m_panic_defer(scanent, CUS callout_address,
1711 US"buffer too small");
1712 /* We're now assured of a NULL at the end of av_buffer */
1714 /* Check the result. ClamAV returns one of two result formats.
1715 In the basic mode, the response is of the form:
1716 infected: -> "<filename>: <virusname> FOUND"
1717 not-infected: -> "<filename>: OK"
1718 error: -> "<filename>: <errcode> ERROR
1719 If the ExtendedDetectionInfo option has been turned on, then we get:
1720 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1721 for the infected case. Compare:
1722 /tmp/eicar.com: Eicar-Test-Signature FOUND
1723 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1725 In the streaming case, clamd uses the filename "stream" which you should
1726 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1727 client app will replace "stream" with the original filename before returning
1728 results to stdout, but the trace shows the data).
1730 We will assume that the pathname passed to clamd from Exim does not contain
1731 a colon. We will have whined loudly above if the eml_filename does (and we're
1732 passing a filename to clamd). */
1735 return m_panic_defer(scanent, CUS callout_address,
1736 US"ClamAV returned null");
1738 /* strip newline at the end (won't be present for zINSTREAM)
1739 (also any trailing whitespace, which shouldn't exist, but we depend upon
1740 this below, so double-check) */
1741 p = av_buffer + Ustrlen(av_buffer) - 1;
1742 if (*p == '\n') *p = '\0';
1744 DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1746 while (isspace(*--p) && (p > av_buffer))
1750 /* colon in returned output? */
1751 if(!(p = Ustrchr(av_buffer,':')))
1752 return m_panic_defer(scanent, CUS callout_address, string_sprintf(
1753 "ClamAV returned malformed result (missing colon): %s",
1756 /* strip filename */
1757 while (*p && isspace(*++p)) /**/;
1760 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1761 but we should at least be resistant to it. */
1762 p = Ustrrchr(vname, ' ');
1763 result_tag = p ? p+1 : vname;
1765 if (Ustrcmp(result_tag, "FOUND") == 0)
1767 /* p should still be the whitespace before the result_tag */
1768 while (isspace(*p)) --p;
1770 /* Strip off the extended information too, which will be in parens
1771 after the virus name, with no intervening whitespace. */
1774 /* "(hash:size)", so previous '(' will do; if not found, we have
1775 a curious virus name, but not an error. */
1776 p = Ustrrchr(vname, '(');
1780 malware_name = string_copy(vname);
1781 DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1784 else if (Ustrcmp(result_tag, "ERROR") == 0)
1785 return m_panic_defer(scanent, CUS callout_address,
1786 string_sprintf("ClamAV returned: %s", av_buffer));
1788 else if (Ustrcmp(result_tag, "OK") == 0)
1790 /* Everything should be OK */
1791 malware_name = NULL;
1792 DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1796 return m_panic_defer(scanent, CUS callout_address,
1797 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1803 #ifndef DISABLE_MAL_SOCK
1804 case M_SOCK: /* "sock" scanner type ------------------------------------- */
1805 /* This code was derived by Martin Poole from the clamd code contributed
1806 by David Saez and the cmdline code
1810 uschar * commandline;
1811 uschar av_buffer[1024];
1812 uschar * linebuffer;
1813 uschar * sockline_scanner;
1814 uschar sockline_scanner_default[] = "%s\n";
1815 const pcre *sockline_trig_re;
1816 const pcre *sockline_name_re;
1818 /* find scanner command line */
1819 if ( (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1821 && *sockline_scanner
1823 { /* check for no expansions apart from one %s */
1824 uschar * s = Ustrchr(sockline_scanner, '%');
1826 if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1827 return m_panic_defer_3(scanent, NULL,
1828 US"unsafe sock scanner call spec", sock);
1831 sockline_scanner = sockline_scanner_default;
1832 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1833 string_printing(sockline_scanner));
1835 /* find scanner output trigger */
1836 sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1837 "missing trigger specification", &errstr);
1838 if (!sockline_trig_re)
1839 return m_panic_defer_3(scanent, NULL, errstr, sock);
1841 /* find virus name regex */
1842 sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1843 "missing virus name regex specification", &errstr);
1844 if (!sockline_name_re)
1845 return m_panic_defer_3(scanent, NULL, errstr, sock);
1847 /* prepare scanner call - security depends on expansions check above */
1848 commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1849 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1850 string_printing(commandline));
1852 /* Pass the command string to the socket */
1853 if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1854 return m_panic_defer(scanent, CUS callout_address, errstr);
1856 /* Read the result */
1857 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1860 return m_panic_defer_3(scanent, CUS callout_address,
1861 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1864 if (bread == sizeof(av_buffer))
1865 return m_panic_defer_3(scanent, CUS callout_address,
1866 US"buffer too small", sock);
1867 av_buffer[bread] = '\0';
1868 linebuffer = string_copy(av_buffer);
1869 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1870 string_printing(linebuffer));
1872 /* try trigger match */
1873 if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1875 if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1876 malware_name = US "unknown";
1877 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1878 string_printing(malware_name));
1880 else /* no virus found */
1881 malware_name = NULL;
1886 #ifndef DISABLE_MAL_MKS
1887 case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1889 char *mksd_options_end;
1890 int mksd_maxproc = 1; /* default, if no option supplied */
1893 if (scanner_options)
1895 mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1896 if ( *scanner_options == '\0'
1897 || *mksd_options_end != '\0'
1899 || mksd_maxproc > 32
1901 return m_panic_defer(scanent, CUS callout_address,
1902 string_sprintf("invalid option '%s'", scanner_options));
1905 if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1906 return m_panic_defer(scanent, CUS callout_address, errstr);
1908 malware_name = NULL;
1910 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1912 if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1921 #ifndef DISABLE_MAL_AVAST
1922 case M_AVAST: /* "avast" scanner type ----------------------------------- */
1926 uschar * scanrequest;
1927 enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1930 uschar * error_message = NULL;
1933 /* According to Martin Tuma @avast the protocol uses "escaped
1934 whitespace", that is, every embedded whitespace is backslash
1935 escaped, as well as backslash is protected by backslash.
1936 The returned lines contain the name of the scanned file, a tab
1940 [E] - some error occured
1941 Such marker follows the first non-escaped TAB. For more information
1942 see avast-protocol(5)
1944 We observed two cases:
1946 <- /file [E]0.0 Error 13 Permission denied
1947 <- 451 SCAN Engine error 13 permission denied
1950 <- /file… [E]3.0 Error 41120 The file is a decompression bomb
1952 <- /file… [+]2.0 0 Eicar Test Virus!!!
1955 If the scanner returns 4xx, DEFER is a good decision, combined
1956 with a panic log entry, to get the admin's attention.
1958 If the scanner returns 200, we reject it as malware, if found any,
1959 or, in case of an error, we set the malware message to the error
1962 Some of the >= 42000 errors are message related - usually some
1963 broken archives etc, but some of them are e.g. license related.
1964 Once the license expires the engine starts returning errors for
1965 every scanning attempt. I¹ have the full list of the error codes
1966 but it is not a public API and is subject to change. It is hard
1967 for me to say what you should do in case of an engine error. You
1968 can have a “Treat * unscanned file as infection” policy or “Treat
1969 unscanned file as clean” policy. ¹) Jakub Bednar
1973 if ( ( !ava_re_clean
1974 && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1976 && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1978 && !(ava_re_error = m_pcre_compile(ava_re_error_str, &errstr)))
1980 return malware_panic_defer(errstr);
1982 /* wait for result */
1983 for (avast_stage = AVA_HELO;
1984 (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1987 int slen = Ustrlen(buf);
1991 /* Multi line responses are bracketed between 210 … and nnn … */
1992 if (Ustrncmp(buf, "210", 3) == 0)
1997 else if (more_data && isdigit(buf[0])) more_data = 0;
1999 switch (avast_stage)
2002 if (more_data) continue;
2003 if (Ustrncmp(buf, "220", 3) != 0)
2004 goto endloop; /* require a 220 */
2008 if (more_data) continue;
2009 if (Ustrncmp(buf, "200", 3) != 0)
2010 goto endloop; /* require a 200 */
2015 /* Check for another option to send. Newline-terminate it. */
2016 if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
2019 if (Ustrcmp(scanrequest, "pass_unscanned") == 0)
2021 DEBUG(D_acl) debug_printf_indent("pass unscanned files as clean\n");
2025 scanrequest = string_sprintf("%s\n", scanrequest);
2026 avast_stage = AVA_OPT; /* just sent option */
2027 DEBUG(D_acl) debug_printf_indent("send to avast OPTION: %s", scanrequest);
2031 scanrequest = string_sprintf("SCAN %s\n", eml_dir);
2032 avast_stage = AVA_RSP; /* just sent command */
2033 DEBUG(D_acl) debug_printf_indent("send to avast REQUEST: SCAN %s\n", eml_dir);
2036 /* send config-cmd or scan-request to socket */
2037 len = Ustrlen(scanrequest);
2038 if (send(sock, scanrequest, len, 0) == -1)
2040 scanrequest[len-1] = '\0';
2041 return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
2042 "unable to send request '%s' to socket (%s): %s",
2043 scanrequest, scanner_options, strerror(errno)), sock);
2050 if (isdigit(buf[0])) /* We're done */
2053 if (malware_name) /* Nothing else matters, just read on */
2056 if (pcre_exec(ava_re_clean, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2059 if (malware_name = m_pcre_exec(ava_re_virus, buf))
2061 unescape(malware_name);
2063 debug_printf_indent("unescaped malware name: '%s'\n", malware_name);
2067 if (strict) /* treat scanner errors as malware */
2069 if (malware_name = m_pcre_exec(ava_re_error, buf))
2071 unescape(malware_name);
2073 debug_printf_indent("unescaped error message: '%s'\n", malware_name);
2077 else if (pcre_exec(ava_re_error, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2079 log_write(0, LOG_MAIN, "internal scanner error (ignored): %s", buf);
2083 /* here also for any unexpected response from the scanner */
2084 DEBUG(D_acl) debug_printf("avast response not handled: '%s'\n", buf);
2088 default: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
2089 __FILE__, __LINE__, __FUNCTION__);
2096 if (nread == -1) error_message = "EOF from scanner";
2097 else if (nread < 0) error_message = "timeout from scanner";
2098 else if (nread == 0) error_message = "got nothing from scanner";
2099 else if (buf[0] != '2') error_message = buf;
2101 DEBUG(D_acl) debug_printf_indent("sent to avast QUIT\n");
2102 if (send(sock, "QUIT\n", 5, 0) == -1)
2103 return m_panic_defer_3(scanent, CUS callout_address,
2104 string_sprintf("unable to send quit request to socket (%s): %s",
2105 scanner_options, strerror(errno)), sock);
2108 return m_panic_defer_3(scanent, CUS callout_address, error_message, sock);
2112 } /* scanner type switch */
2115 (void) close (sock);
2116 malware_ok = TRUE; /* set "been here, done that" marker */
2119 /* match virus name against pattern (caseless ------->----------v) */
2120 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
2122 DEBUG(D_acl) debug_printf_indent(
2123 "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2131 /*************************************************
2132 * Scan an email for malware *
2133 *************************************************/
2135 /* This is the normal interface for scanning an email, which doesn't need a
2136 filename; it's a wrapper around the malware_file function.
2139 malware_re match condition for "malware="
2140 timeout if nonzero, timeout in seconds
2142 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2143 where true means malware was found (condition applies)
2146 malware(const uschar * malware_re, int timeout)
2148 int ret = malware_internal(malware_re, NULL, timeout);
2150 if (ret == DEFER) av_failed = TRUE;
2155 /*************************************************
2156 * Scan a file for malware *
2157 *************************************************/
2159 /* This is a test wrapper for scanning an email, which is not used in
2160 normal processing. Scan any file, using the Exim scanning interface.
2161 This function tampers with various global variables so is unsafe to use
2162 in any other context.
2165 eml_filename a file holding the message to be scanned
2167 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2168 where true means malware was found (condition applies)
2171 malware_in_file(uschar *eml_filename)
2173 uschar message_id_buf[64];
2176 /* spool_mbox() assumes various parameters exist, when creating
2177 the relevant directory and the email within */
2179 (void) string_format(message_id_buf, sizeof(message_id_buf),
2180 "dummy-%d", vaguely_random_number(INT_MAX));
2181 message_id = message_id_buf;
2182 sender_address = US"malware-sender@example.net";
2184 recipients_list = NULL;
2185 receive_add_recipient(US"malware-victim@example.net", -1);
2186 enable_dollar_recipients = TRUE;
2188 ret = malware_internal(US"*", eml_filename, 0);
2190 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2193 /* don't set no_mbox_unspool; at present, there's no way for it to become
2194 set, but if that changes, then it should apply to these tests too */
2198 /* silence static analysis tools */
2208 if (!malware_default_re)
2209 malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2211 #ifndef DISABLE_MAL_DRWEB
2213 drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2215 #ifndef DISABLE_MAL_FSECURE
2217 fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2219 #ifndef DISABLE_MAL_KAV
2221 kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2223 kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2225 #ifndef DISABLE_MAL_AVAST
2227 ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2229 ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2231 ava_re_error = regex_must_compile(ava_re_error_str, FALSE, TRUE);
2233 #ifndef DISABLE_MAL_FFROT6D
2234 if (!fprot6d_re_error)
2235 fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2236 if (!fprot6d_re_virus)
2237 fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2243 malware_show_supported(FILE * f)
2246 fprintf(f, "Malware:");
2247 for (sc = m_scans; sc->scancode != -1; sc++) fprintf(f, " %s", sc->name);
2252 # endif /*!MACRO_PREDEF*/
2253 #endif /*WITH_CONTENT_SCAN*/