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 */
189 if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
190 for (p0 = p; *p0; ++p0) *p0 = p0[1];
193 /* --- malware_*_defer --- */
195 malware_panic_defer(const uschar * str)
197 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
201 malware_log_defer(const uschar * str)
203 log_write(0, LOG_MAIN, "malware acl condition: %s", str);
206 /* --- m_*_defer --- */
208 m_panic_defer(struct scan * scanent, const uschar * hostport,
211 return malware_panic_defer(string_sprintf("%s %s : %s",
212 scanent->name, hostport ? hostport : CUS"", str));
215 m_log_defer(struct scan * scanent, const uschar * hostport,
218 return malware_log_defer(string_sprintf("%s %s : %s",
219 scanent->name, hostport ? hostport : CUS"", str));
221 /* --- m_*_defer_3 */
223 m_panic_defer_3(struct scan * scanent, const uschar * hostport,
224 const uschar * str, int fd_to_close)
226 (void) close(fd_to_close);
227 return m_panic_defer(scanent, hostport, str);
230 m_log_defer_3(struct scan * scanent, const uschar * hostport,
231 const uschar * str, int fd_to_close)
233 (void) close(fd_to_close);
234 return m_log_defer(scanent, hostport, str);
237 /*************************************************/
239 #ifndef DISABLE_MAL_CLAM
240 /* Only used by the Clamav code, which is working from a list of servers and
241 uses the returned in_addr to get a second connection to the same system.
244 m_tcpsocket(const uschar * hostname, unsigned int port,
245 host_item * host, uschar ** errstr, const blob * fastopen_blob)
247 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
248 host, errstr, fastopen_blob);
253 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
255 if (send(sock, buf, cnt, 0) < 0)
259 *errstr = string_sprintf("unable to send to socket (%s): %s",
267 m_pcre_compile(const uschar * re, uschar ** errstr)
269 const uschar * rerror;
273 cre = pcre_compile(CS re, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
275 *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
276 re, rerror, roffset);
281 m_pcre_exec(const pcre * cre, uschar * text)
284 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
285 ovector, nelem(ovector));
286 uschar * substr = NULL;
287 if (i >= 2) /* Got it */
288 pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr);
293 m_pcre_nextinlist(const uschar ** list, int * sep,
294 char * listerr, uschar ** errstr)
296 const uschar * list_ele;
297 const pcre * cre = NULL;
299 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
300 *errstr = US listerr;
303 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
304 string_printing(list_ele));
305 cre = m_pcre_compile(CUS list_ele, errstr);
311 Simple though inefficient wrapper for reading a line. Drop CRs and the
312 trailing newline. Can return early on buffer full. Null-terminate.
313 Apply initial timeout if no data ready.
315 Return: number of chars - zero for an empty line
317 -2 on timeout or error
320 recv_line(int fd, uschar * buffer, int bsize, int tmo)
326 if (!fd_ready(fd, tmo-time(NULL)))
329 /*XXX tmo handling assumes we always get a whole line */
332 while ((rcv = read(fd, p, 1)) > 0)
335 if (p-buffer > bsize-2) break;
336 if (*p == '\n') break;
341 DEBUG(D_acl) debug_printf_indent("Malware scan: read %s (%s)\n",
342 rcv==0 ? "EOF" : "error", strerror(errno));
343 return rcv==0 ? -1 : -2;
347 DEBUG(D_acl) debug_printf_indent("Malware scan: read '%s'\n", buffer);
351 /* return TRUE iff size as requested */
353 recv_len(int sock, void * buf, int size, int tmo)
355 return fd_ready(sock, tmo-time(NULL))
356 ? recv(sock, buf, size, 0) == size
362 #ifndef DISABLE_MAL_MKS
363 /* ============= private routines for the "mksd" scanner type ============== */
365 # include <sys/uio.h>
368 mksd_writev (int sock, struct iovec * iov, int iovcnt)
375 i = writev (sock, iov, iovcnt);
376 while (i < 0 && errno == EINTR);
379 (void) malware_panic_defer(
380 US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
383 for (;;) /* check for short write */
384 if (i >= iov->iov_len)
394 iov->iov_base = CS iov->iov_base + i;
401 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, int tmo)
408 i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL));
411 (void) malware_panic_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
416 /* offset == av_buffer_size -> buffer full */
417 if (offset == av_buffer_size)
419 (void) malware_panic_defer(US"malformed reply received from mksd");
422 } while (av_buffer[offset-1] != '\n');
424 av_buffer[offset] = '\0';
429 mksd_parse_line(struct scan * scanent, char * line)
440 if ((p = strchr (line, '\n')) != NULL)
442 return m_panic_defer(scanent, NULL,
443 string_sprintf("scanner failed: %s", line));
446 if ((p = strchr (line, '\n')) != NULL)
451 && (p = strchr(line+4, ' ')) != NULL
456 malware_name = string_copy(US line+4);
460 return m_panic_defer(scanent, NULL,
461 string_sprintf("malformed reply received: %s", line));
466 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
470 const char *cmd = "MSQ\n";
471 uschar av_buffer[1024];
473 iov[0].iov_base = (void *) cmd;
475 iov[1].iov_base = (void *) scan_filename;
476 iov[1].iov_len = Ustrlen(scan_filename);
477 iov[2].iov_base = (void *) (cmd + 3);
480 if (mksd_writev (sock, iov, 3) < 0)
483 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
486 return mksd_parse_line (scanent, CS av_buffer);
491 #ifndef DISABLE_MAL_CLAM
493 clamd_option(clamd_address * cd, const uschar * optstr, int * subsep)
498 while ((s = string_nextinlist(&optstr, subsep, NULL, 0)))
499 if (Ustrncmp(s, "retry=", 6) == 0)
501 int sec = readconf_readtime((s += 6), '\0', FALSE);
514 /*************************************************
515 * Scan content for malware *
516 *************************************************/
518 /* This is an internal interface for scanning an email; the normal interface
519 is via malware(), or there's malware_in_file() used for testing/debugging.
522 malware_re match condition for "malware="
523 scan_filename the file holding the email to be scanned, if we're faking
524 this up for the -bmalware test, else NULL
525 timeout if nonzero, non-default timeoutl
527 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
528 where true means malware was found (condition applies)
531 malware_internal(const uschar * malware_re, const uschar * scan_filename,
535 const uschar *av_scanner_work = av_scanner;
536 uschar *scanner_name;
537 unsigned long mbox_size;
541 struct scan * scanent;
542 const uschar * scanner_options;
545 uschar * eml_filename, * eml_dir;
548 return FAIL; /* empty means "don't match anything" */
550 /* Ensure the eml mbox file is spooled up */
552 if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
553 return malware_panic_defer(US"error while creating mbox spool file");
555 /* None of our current scanners need the mbox file as a stream (they use
556 the name), so we can close it right away. Get the directory too. */
558 (void) fclose(mbox_file);
559 eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
561 /* parse 1st option */
562 if (strcmpic(malware_re, US"false") == 0 || Ustrcmp(malware_re,"0") == 0)
563 return FAIL; /* explicitly no matching */
565 /* special cases (match anything except empty) */
566 if ( strcmpic(malware_re,US"true") == 0
567 || Ustrcmp(malware_re,"*") == 0
568 || Ustrcmp(malware_re,"1") == 0
571 if ( !malware_default_re
572 && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
573 return malware_panic_defer(errstr);
574 malware_re = malware_regex_default;
575 re = malware_default_re;
578 /* compile the regex, see if it works */
579 else if (!(re = m_pcre_compile(malware_re, &errstr)))
580 return malware_panic_defer(errstr);
582 /* if av_scanner starts with a dollar, expand it first */
583 if (*av_scanner == '$')
585 if (!(av_scanner_work = expand_string(av_scanner)))
586 return malware_panic_defer(
587 string_sprintf("av_scanner starts with $, but expansion failed: %s",
588 expand_string_message));
591 debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work);
592 /* disable result caching in this case */
597 /* Do not scan twice (unless av_scanner is dynamic). */
600 /* find the scanner type from the av_scanner option */
601 if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
602 return malware_panic_defer(US"av_scanner configuration variable is empty");
603 if (!timeout) timeout = MALWARE_TIMEOUT;
604 tmo = time(NULL) + timeout;
606 for (scanent = m_scans; ; scanent++)
609 return malware_panic_defer(string_sprintf("unknown scanner type '%s'",
611 if (strcmpic(scanner_name, US scanent->name) != 0)
613 DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo=%s\n",
614 scanner_name, readconf_printtime(timeout));
616 if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
617 scanner_options = scanent->options_default;
618 if (scanent->conn == MC_NONE)
621 DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
622 switch(scanent->conn)
624 case MC_TCP: sock = ip_tcpsocket(scanner_options, &errstr, 5); break;
625 case MC_UNIX: sock = ip_unixsocket(scanner_options, &errstr); break;
626 case MC_STRM: sock = ip_streamsocket(scanner_options, &errstr, 5); break;
627 default: /* compiler quietening */ break;
630 return m_panic_defer(scanent, CUS callout_address, errstr);
634 switch (scanent->scancode)
636 #ifndef DISABLE_MAL_FFROTD
637 case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
639 uschar *fp_scan_option;
640 unsigned int detected=0, par_count=0;
641 uschar * scanrequest;
642 uschar buf[32768], *strhelper, *strhelper2;
643 uschar * malware_name_internal = NULL;
646 scanrequest = string_sprintf("GET %s", eml_filename);
648 while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
651 scanrequest = string_sprintf("%s%s%s", scanrequest,
652 par_count ? "%20" : "?", fp_scan_option);
655 scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
656 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
657 scanner_name, scanrequest);
659 /* send scan request */
660 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
661 return m_panic_defer(scanent, CUS callout_address, errstr);
663 while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0)
666 if (Ustrstr(buf, US"<detected type=\"") != NULL)
668 else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
670 if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
673 malware_name_internal = string_copy(strhelper+6);
676 else if (Ustrstr(buf, US"<summary code=\""))
678 malware_name = Ustrstr(buf, US"<summary code=\"11\">")
679 ? malware_name_internal : NULL;
692 #ifndef DISABLE_MAL_FFROT6D
693 case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
698 uschar * scanrequest;
699 uschar av_buffer[1024];
701 if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
702 || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
703 return malware_panic_defer(errstr);
705 scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
706 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
707 scanner_name, scanrequest);
709 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
710 return m_panic_defer(scanent, CUS callout_address, errstr);
712 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
715 return m_panic_defer_3(scanent, CUS callout_address,
716 string_sprintf("unable to read from socket (%s)", strerror(errno)),
719 if (bread == sizeof(av_buffer))
720 return m_panic_defer_3(scanent, CUS callout_address,
721 US"buffer too small", sock);
723 av_buffer[bread] = '\0';
724 linebuffer = string_copy(av_buffer);
726 m_sock_send(sock, US"QUIT\n", 5, 0);
728 if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
729 return m_panic_defer_3(scanent, CUS callout_address,
730 string_sprintf("scanner reported error (%s)", e), sock);
732 if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
739 #ifndef DISABLE_MAL_DRWEB
740 case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
741 /* v0.1 - added support for tcp sockets */
742 /* v0.0 - initial release -- support for unix sockets */
746 unsigned int fsize_uint;
747 uschar * tmpbuf, *drweb_fbuf;
748 int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
749 drweb_vnum, drweb_slen, drweb_fin = 0x0000;
751 /* prepare variables */
752 drweb_cmd = htonl(DRWEBD_SCAN_CMD);
753 drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
755 if (*scanner_options != '/')
758 if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1)
759 return m_panic_defer_3(scanent, NULL,
760 string_sprintf("can't open spool file %s: %s",
761 eml_filename, strerror(errno)),
764 if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
767 badseek: err = errno;
768 (void)close(drweb_fd);
769 return m_panic_defer_3(scanent, NULL,
770 string_sprintf("can't seek spool file %s: %s",
771 eml_filename, strerror(err)),
774 fsize_uint = (unsigned int) fsize;
775 if ((off_t)fsize_uint != fsize)
777 (void)close(drweb_fd);
778 return m_panic_defer_3(scanent, NULL,
779 string_sprintf("seeking spool file %s, size overflow",
783 drweb_slen = htonl(fsize);
784 if (lseek(drweb_fd, 0, SEEK_SET) < 0)
787 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
788 scanner_name, scanner_options);
790 /* send scan request */
791 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
792 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
793 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
794 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
796 (void)close(drweb_fd);
797 return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
798 "unable to send commands to socket (%s)", scanner_options),
802 if (!(drweb_fbuf = US malloc(fsize_uint)))
804 (void)close(drweb_fd);
805 return m_panic_defer_3(scanent, NULL,
806 string_sprintf("unable to allocate memory %u for file (%s)",
807 fsize_uint, eml_filename),
811 if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
814 (void)close(drweb_fd);
816 return m_panic_defer_3(scanent, NULL,
817 string_sprintf("can't read spool file %s: %s",
818 eml_filename, strerror(err)),
821 (void)close(drweb_fd);
823 /* send file body to socket */
824 if (send(sock, drweb_fbuf, fsize, 0) < 0)
827 return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
828 "unable to send file body to socket (%s)", scanner_options),
834 drweb_slen = htonl(Ustrlen(eml_filename));
836 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n",
837 scanner_name, scanner_options);
839 /* send scan request */
840 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
841 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
842 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
843 (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
844 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
845 return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
846 "unable to send commands to socket (%s)", scanner_options),
850 /* wait for result */
851 if (!recv_len(sock, &drweb_rc, sizeof(drweb_rc), tmo))
852 return m_panic_defer_3(scanent, CUS callout_address,
853 US"unable to read return code", sock);
854 drweb_rc = ntohl(drweb_rc);
856 if (!recv_len(sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
857 return m_panic_defer_3(scanent, CUS callout_address,
858 US"unable to read the number of viruses", sock);
859 drweb_vnum = ntohl(drweb_vnum);
861 /* "virus(es) found" if virus number is > 0 */
867 /* setup default virus name */
868 malware_name = US"unknown";
870 /* set up match regex */
872 drweb_re = m_pcre_compile(drweb_re_str, &errstr);
874 /* read and concatenate virus names into one string */
875 for (i = 0; i < drweb_vnum; i++)
879 /* read the size of report */
880 if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
881 return m_panic_defer_3(scanent, CUS callout_address,
882 US"cannot read report size", sock);
883 drweb_slen = ntohl(drweb_slen);
884 tmpbuf = store_get(drweb_slen);
886 /* read report body */
887 if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
888 return m_panic_defer_3(scanent, CUS callout_address,
889 US"cannot read report string", sock);
890 tmpbuf[drweb_slen] = '\0';
892 /* try matcher on the line, grab substring */
893 result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
894 ovector, nelem(ovector));
897 const char * pre_malware_nb;
899 pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
901 if (i==0) /* the first name we just copy to malware_name */
902 g = string_cat(NULL, US pre_malware_nb);
904 /*XXX could be string_append_listele? */
905 else /* concatenate each new virus name to previous */
906 g = string_append(g, 2, "/", pre_malware_nb);
908 pcre_free_substring(pre_malware_nb);
911 malware_name = string_from_gstring(g);
915 const char *drweb_s = NULL;
917 if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
918 if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
919 if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
920 if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
921 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
922 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
923 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
924 * and others are ignored */
926 return m_panic_defer_3(scanent, CUS callout_address,
927 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
937 #ifndef DISABLE_MAL_AVE
938 case M_AVES: /* "aveserver" scanner type -------------------------------- */
943 /* read aveserver's greeting and see if it is ready (2xx greeting) */
945 recv_line(sock, buf, sizeof(buf), tmo);
947 if (buf[0] != '2') /* aveserver is having problems */
948 return m_panic_defer_3(scanent, CUS callout_address,
949 string_sprintf("unavailable (Responded: %s).",
950 ((buf[0] != 0) ? buf : US "nothing") ),
953 /* prepare our command */
954 (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
958 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
960 if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
961 return m_panic_defer(scanent, CUS callout_address, errstr);
965 /* read response lines, find malware name and final response */
966 while (recv_line(sock, buf, sizeof(buf), tmo) > 0)
970 if (buf[0] == '5') /* aveserver is having problems */
972 result = m_panic_defer(scanent, CUS callout_address,
973 string_sprintf("unable to scan file %s (Responded: %s).",
977 if (Ustrncmp(buf,"322",3) == 0)
979 uschar *p = Ustrchr(&buf[4], ' ');
981 malware_name = string_copy(&buf[4]);
985 if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
986 return m_panic_defer(scanent, CUS callout_address, errstr);
988 /* read aveserver's greeting and see if it is ready (2xx greeting) */
990 recv_line(sock, buf, sizeof(buf), tmo);
992 if (buf[0] != '2') /* aveserver is having problems */
993 return m_panic_defer_3(scanent, CUS callout_address,
994 string_sprintf("unable to quit dialogue (Responded: %s).",
995 ((buf[0] != 0) ? buf : US "nothing") ),
1007 #ifndef DISABLE_MAL_FSECURE
1008 case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
1010 int i, j, bread = 0;
1012 uschar av_buffer[1024];
1013 static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
1014 US"CONFIGURE\tTIMEOUT\t0\n",
1015 US"CONFIGURE\tMAXARCH\t5\n",
1016 US"CONFIGURE\tMIME\t1\n" };
1018 malware_name = NULL;
1020 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1021 scanner_name, scanner_options);
1023 memset(av_buffer, 0, sizeof(av_buffer));
1024 for (i = 0; i != nelem(cmdopt); i++)
1027 if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
1028 return m_panic_defer(scanent, CUS callout_address, errstr);
1030 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1031 if (bread > 0) av_buffer[bread]='\0';
1033 return m_panic_defer_3(scanent, CUS callout_address,
1034 string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
1036 for (j = 0; j < bread; j++)
1037 if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
1041 /* pass the mailfile to fsecure */
1042 file_name = string_sprintf("SCAN\t%s\n", eml_filename);
1044 if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
1045 return m_panic_defer(scanent, CUS callout_address, errstr);
1048 /* todo also SUSPICION\t */
1050 fsec_re = m_pcre_compile(fsec_re_str, &errstr);
1052 /* read report, linewise. Apply a timeout as the Fsecure daemon
1053 sometimes wants an answer to "PING" but they won't tell us what */
1055 uschar * p = av_buffer;
1061 i = av_buffer+sizeof(av_buffer)-p;
1062 if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
1063 return m_panic_defer_3(scanent, CUS callout_address,
1064 string_sprintf("unable to read result (%s)", strerror(errno)),
1067 for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
1071 /* Really search for virus again? */
1073 /* try matcher on the line, grab substring */
1074 malware_name = m_pcre_exec(fsec_re, p);
1076 if (Ustrstr(p, "OK\tScan ok."))
1080 /* copy down the trailing partial line then read another chunk */
1081 i = av_buffer+sizeof(av_buffer)-p;
1082 memmove(av_buffer, p, i);
1092 #ifndef DISABLE_MAL_KAV
1093 case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
1096 uschar tmpbuf[1024];
1097 uschar * scanrequest;
1099 unsigned long kav_reportlen;
1104 /* get current date and time, build scan request */
1106 /* pdp note: before the eml_filename parameter, this scanned the
1107 directory; not finding documentation, so we'll strip off the directory.
1108 The side-effect is that the test framework scanning may end up in
1109 scanning more than was requested, but for the normal interface, this is
1112 strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
1113 scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
1114 p = Ustrrchr(scanrequest, '/');
1118 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1119 scanner_name, scanner_options);
1121 /* send scan request */
1122 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
1123 return m_panic_defer(scanent, CUS callout_address, errstr);
1125 /* wait for result */
1126 if (!recv_len(sock, tmpbuf, 2, tmo))
1127 return m_panic_defer_3(scanent, CUS callout_address,
1128 US"unable to read 2 bytes from socket.", sock);
1130 /* get errorcode from one nibble */
1131 kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
1134 case 5: case 6: /* improper kavdaemon configuration */
1135 return m_panic_defer_3(scanent, CUS callout_address,
1136 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
1139 return m_panic_defer_3(scanent, CUS callout_address,
1140 US"reported 'scanning not completed' (code 1).", sock);
1142 return m_panic_defer_3(scanent, CUS callout_address,
1143 US"reported 'kavdaemon damaged' (code 7).", sock);
1146 /* code 8 is not handled, since it is ambiguous. It appears mostly on
1147 bounces where part of a file has been cut off */
1149 /* "virus found" return codes (2-4) */
1150 if (kav_rc > 1 && kav_rc < 5)
1152 int report_flag = 0;
1154 /* setup default virus name */
1155 malware_name = US"unknown";
1157 report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
1159 /* read the report, if available */
1160 if (report_flag == 1)
1162 /* read report size */
1163 if (!recv_len(sock, &kav_reportlen, 4, tmo))
1164 return m_panic_defer_3(scanent, CUS callout_address,
1165 US"cannot read report size", sock);
1167 /* it's possible that avp returns av_buffer[1] == 1 but the
1168 reportsize is 0 (!?) */
1169 if (kav_reportlen > 0)
1171 /* set up match regex, depends on retcode */
1174 if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1175 kav_re = kav_re_sus;
1179 if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1180 kav_re = kav_re_inf;
1183 /* read report, linewise. Using size from stream to read amount of data
1184 from same stream is safe enough. */
1185 /* coverity[tainted_data] */
1186 while (kav_reportlen > 0)
1188 if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1190 kav_reportlen -= bread+1;
1192 /* try matcher on the line, grab substring */
1193 if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1199 else /* no virus found */
1200 malware_name = NULL;
1206 #ifndef DISABLE_MAL_CMDLINE
1207 case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1209 const uschar *cmdline_scanner = scanner_options;
1210 const pcre *cmdline_trigger_re;
1211 const pcre *cmdline_regex_re;
1213 uschar * commandline;
1214 void (*eximsigchld)(int);
1215 void (*eximsigpipe)(int);
1216 FILE *scanner_out = NULL;
1218 FILE *scanner_record = NULL;
1219 uschar linebuffer[32767];
1224 if (!cmdline_scanner)
1225 return m_panic_defer(scanent, NULL, errstr);
1227 /* find scanner output trigger */
1228 cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1229 "missing trigger specification", &errstr);
1230 if (!cmdline_trigger_re)
1231 return m_panic_defer(scanent, NULL, errstr);
1233 /* find scanner name regex */
1234 cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1235 "missing virus name regex specification", &errstr);
1236 if (!cmdline_regex_re)
1237 return m_panic_defer(scanent, NULL, errstr);
1239 /* prepare scanner call; despite the naming, file_name holds a directory
1240 name which is documented as the value given to %s. */
1242 file_name = string_copy(eml_filename);
1243 p = Ustrrchr(file_name, '/');
1246 commandline = string_sprintf(CS cmdline_scanner, file_name);
1248 /* redirect STDERR too */
1249 commandline = string_sprintf("%s 2>&1", commandline);
1251 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1252 scanner_name, commandline);
1254 /* store exims signal handlers */
1255 eximsigchld = signal(SIGCHLD,SIG_DFL);
1256 eximsigpipe = signal(SIGPIPE,SIG_DFL);
1258 if (!(scanner_out = popen(CS commandline,"r")))
1261 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1262 return m_panic_defer(scanent, NULL,
1263 string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1265 scanner_fd = fileno(scanner_out);
1267 file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
1269 if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1272 (void) pclose(scanner_out);
1273 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1274 return m_panic_defer(scanent, NULL, string_sprintf(
1275 "opening scanner output file (%s) failed: %s.",
1276 file_name, strerror(err)));
1279 /* look for trigger while recording output */
1280 while ((rcnt = recv_line(scanner_fd, linebuffer,
1281 sizeof(linebuffer), tmo)))
1288 (void) pclose(scanner_out);
1289 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1290 return m_panic_defer(scanent, NULL, string_sprintf(
1291 "unable to read from scanner (%s): %s",
1292 commandline, strerror(err)));
1295 if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1298 (void) pclose(scanner_out);
1299 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1300 return m_panic_defer(scanent, NULL, string_sprintf(
1301 "short write on scanner output file (%s).", file_name));
1303 putc('\n', scanner_record);
1304 /* try trigger match */
1306 && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1311 (void)fclose(scanner_record);
1312 sep = pclose(scanner_out);
1313 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1315 return m_panic_defer(scanent, NULL,
1317 ? string_sprintf("running scanner failed: %s", strerror(sep))
1318 : string_sprintf("scanner returned error code: %d", sep));
1323 /* setup default virus name */
1324 malware_name = US"unknown";
1326 /* re-open the scanner output file, look for name match */
1327 scanner_record = fopen(CS file_name, "rb");
1328 while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1331 if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1334 (void)fclose(scanner_record);
1336 else /* no virus found */
1337 malware_name = NULL;
1342 #ifndef DISABLE_MAL_SOPHIE
1343 case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1348 uschar av_buffer[1024];
1350 /* pass the scan directory to sophie */
1351 file_name = string_copy(eml_filename);
1352 if ((p = Ustrrchr(file_name, '/')))
1355 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1356 scanner_name, scanner_options);
1358 if ( write(sock, file_name, Ustrlen(file_name)) < 0
1359 || write(sock, "\n", 1) != 1
1361 return m_panic_defer_3(scanent, CUS callout_address,
1362 string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1365 /* wait for result */
1366 memset(av_buffer, 0, sizeof(av_buffer));
1367 if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1368 return m_panic_defer_3(scanent, CUS callout_address,
1369 string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1373 if (av_buffer[0] == '1') {
1374 uschar * s = Ustrchr(av_buffer, '\n');
1377 malware_name = string_copy(&av_buffer[2]);
1379 else if (!strncmp(CS av_buffer, "-1", 2))
1380 return m_panic_defer_3(scanent, CUS callout_address,
1381 US"scanner reported error", sock);
1382 else /* all ok, no virus */
1383 malware_name = NULL;
1389 #ifndef DISABLE_MAL_CLAM
1390 case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1392 /* This code was originally contributed by David Saez */
1393 /* There are three scanning methods available to us:
1394 * (1) Use the SCAN command, pointing to a file in the filesystem
1395 * (2) Use the STREAM command, send the data on a separate port
1396 * (3) Use the zINSTREAM command, send the data inline
1397 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1398 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1399 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1400 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM
1401 * See Exim bug 926 for details. */
1403 uschar *p, *vname, *result_tag;
1405 uschar av_buffer[1024];
1406 uschar *hostname = US"";
1408 uschar *clamav_fbuf;
1409 int clam_fd, result;
1411 unsigned int fsize_uint;
1412 BOOL use_scan_command = FALSE;
1413 clamd_address * cv[MAX_CLAMD_SERVERS];
1414 int num_servers = 0;
1415 uint32_t send_size, send_final_zeroblock;
1418 /*XXX if unixdomain socket, only one server supported. Needs fixing;
1419 there's no reason we should not mix local and remote servers */
1421 if (*scanner_options == '/')
1424 const uschar * sublist;
1427 /* Local file; so we def want to use_scan_command and don't want to try
1428 * passing IP/port combinations */
1429 use_scan_command = TRUE;
1430 cd = (clamd_address *) store_get(sizeof(clamd_address));
1432 /* extract socket-path part */
1433 sublist = scanner_options;
1434 cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1437 if (clamd_option(cd, sublist, &subsep) != OK)
1438 return m_panic_defer(scanent, NULL,
1439 string_sprintf("bad option '%s'", scanner_options));
1444 /* Go through the rest of the list of host/port and construct an array
1445 * of servers to try. The first one is the bit we just passed from
1446 * scanner_options so process that first and then scan the remainder of
1447 * the address buffer */
1451 const uschar * sublist;
1455 /* The 'local' option means use the SCAN command over the network
1456 * socket (ie common file storage in use) */
1457 /*XXX we could accept this also as a local option? */
1458 if (strcmpic(scanner_options, US"local") == 0)
1460 use_scan_command = TRUE;
1464 cd = (clamd_address *) store_get(sizeof(clamd_address));
1466 /* extract host and port part */
1467 sublist = scanner_options;
1468 if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1470 (void) m_panic_defer(scanent, NULL,
1471 string_sprintf("missing address: '%s'", scanner_options));
1474 if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1476 (void) m_panic_defer(scanent, NULL,
1477 string_sprintf("missing port: '%s'", scanner_options));
1480 cd->tcp_port = atoi(CS s);
1483 /*XXX should these options be common over scanner types? */
1484 if (clamd_option(cd, sublist, &subsep) != OK)
1485 return m_panic_defer(scanent, NULL,
1486 string_sprintf("bad option '%s'", scanner_options));
1488 cv[num_servers++] = cd;
1489 if (num_servers >= MAX_CLAMD_SERVERS)
1491 (void) m_panic_defer(scanent, NULL,
1492 US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1493 "specified; only using the first " MAX_CLAMD_SERVERS_S );
1496 } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1499 /* check if we have at least one server */
1501 return m_panic_defer(scanent, NULL,
1502 US"no useable server addresses in malware configuration option.");
1505 /* See the discussion of response formats below to see why we really
1506 don't like colons in filenames when passing filenames to ClamAV. */
1507 if (use_scan_command && Ustrchr(eml_filename, ':'))
1508 return m_panic_defer(scanent, NULL,
1509 string_sprintf("local/SCAN mode incompatible with" \
1510 " : in path to email filename [%s]", eml_filename));
1512 /* Set up the very first data we will be sending */
1513 if (!use_scan_command)
1514 { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1517 cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
1518 cmd_str.len = Ustrlen(cmd_str.data);
1521 /* We have some network servers specified */
1524 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1525 * only supports AF_INET, but we should probably be looking to the
1526 * future and rewriting this to be protocol-independent anyway. */
1528 while (num_servers > 0)
1530 int i = random_number(num_servers);
1531 clamd_address * cd = cv[i];
1533 DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1534 cd->hostspec, cd->tcp_port);
1536 /* Lookup the host. This is to ensure that we connect to the same IP
1537 * on both connections (as one host could resolve to multiple ips) */
1540 if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1541 &connhost, &errstr, &cmd_str)) >= 0)
1543 /* Connection successfully established with a server */
1544 hostname = cd->hostspec;
1548 if (cd->retry <= 0) break;
1549 while (cd->retry > 0) cd->retry = sleep(cd->retry);
1554 (void) m_panic_defer(scanent, CUS callout_address, errstr);
1556 /* Remove the server from the list. XXX We should free the memory */
1558 for (; i < num_servers; i++)
1562 if (num_servers == 0)
1563 return m_panic_defer(scanent, NULL, US"all servers failed");
1568 if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1570 hostname = cv[0]->hostspec;
1573 if (cv[0]->retry <= 0)
1574 return m_panic_defer(scanent, CUS callout_address, errstr);
1575 while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1578 /* have socket in variable "sock"; command to use is semi-independent of
1579 * the socket protocol. We use SCAN if is local (either Unix/local
1580 * domain socket, or explicitly told local) else we stream the data.
1581 * How we stream the data depends upon how we were built. */
1583 if (!use_scan_command)
1585 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1586 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1589 DEBUG(D_acl) debug_printf_indent(
1590 "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1593 /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1595 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1596 return m_panic_defer_3(scanent, CUS hostname,
1597 string_sprintf("unable to send zINSTREAM to socket (%s)",
1601 /* calc file size */
1602 if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1605 return m_panic_defer_3(scanent, NULL,
1606 string_sprintf("can't open spool file %s: %s",
1607 eml_filename, strerror(err)),
1610 if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1613 b_seek: err = errno;
1614 (void)close(clam_fd);
1615 return m_panic_defer_3(scanent, NULL,
1616 string_sprintf("can't seek spool file %s: %s",
1617 eml_filename, strerror(err)),
1620 fsize_uint = (unsigned int) fsize;
1621 if ((off_t)fsize_uint != fsize)
1623 (void)close(clam_fd);
1624 return m_panic_defer_3(scanent, NULL,
1625 string_sprintf("seeking spool file %s, size overflow",
1629 if (lseek(clam_fd, 0, SEEK_SET) < 0)
1632 if (!(clamav_fbuf = US malloc(fsize_uint)))
1634 (void)close(clam_fd);
1635 return m_panic_defer_3(scanent, NULL,
1636 string_sprintf("unable to allocate memory %u for file (%s)",
1637 fsize_uint, eml_filename),
1641 if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1644 free(clamav_fbuf); (void)close(clam_fd);
1645 return m_panic_defer_3(scanent, NULL,
1646 string_sprintf("can't read spool file %s: %s",
1647 eml_filename, strerror(err)),
1650 (void)close(clam_fd);
1652 /* send file body to socket */
1653 send_size = htonl(fsize_uint);
1654 send_final_zeroblock = 0;
1655 if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1656 (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1657 (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1660 return m_panic_defer_3(scanent, NULL,
1661 string_sprintf("unable to send file body to socket (%s)", hostname),
1668 { /* use scan command */
1669 /* Send a SCAN command pointing to a filename; then in the then in the
1670 * scan-method-neutral part, read the response back */
1672 /* ================================================================= */
1674 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1675 which dates to when ClamAV needed us to break apart the email into the
1676 MIME parts (eg, with the now deprecated demime condition coming first).
1677 Some time back, ClamAV gained the ability to deconstruct the emails, so
1678 doing this would actually have resulted in the mail attachments being
1679 scanned twice, in the broken out files and from the original .eml.
1680 Since ClamAV now handles emails (and has for quite some time) we can
1681 just use the email file itself. */
1682 /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
1684 DEBUG(D_acl) debug_printf_indent(
1685 "Malware scan: issuing %s local-path scan [%s]\n",
1686 scanner_name, scanner_options);
1689 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1690 return m_panic_defer_3(scanent, CUS callout_address,
1691 string_sprintf("unable to write to socket (%s)", strerror(errno)),
1694 /* Do not shut down the socket for writing; a user report noted that
1695 * clamd 0.70 does not react well to this. */
1697 /* Commands have been sent, no matter which scan method or connection
1698 * type we're using; now just read the result, independent of method. */
1700 /* Read the result */
1701 memset(av_buffer, 0, sizeof(av_buffer));
1702 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1707 return m_panic_defer(scanent, CUS callout_address,
1708 string_sprintf("unable to read from socket (%s)",
1709 errno == 0 ? "EOF" : strerror(errno)));
1711 if (bread == sizeof(av_buffer))
1712 return m_panic_defer(scanent, CUS callout_address,
1713 US"buffer too small");
1714 /* We're now assured of a NULL at the end of av_buffer */
1716 /* Check the result. ClamAV returns one of two result formats.
1717 In the basic mode, the response is of the form:
1718 infected: -> "<filename>: <virusname> FOUND"
1719 not-infected: -> "<filename>: OK"
1720 error: -> "<filename>: <errcode> ERROR
1721 If the ExtendedDetectionInfo option has been turned on, then we get:
1722 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1723 for the infected case. Compare:
1724 /tmp/eicar.com: Eicar-Test-Signature FOUND
1725 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1727 In the streaming case, clamd uses the filename "stream" which you should
1728 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1729 client app will replace "stream" with the original filename before returning
1730 results to stdout, but the trace shows the data).
1732 We will assume that the pathname passed to clamd from Exim does not contain
1733 a colon. We will have whined loudly above if the eml_filename does (and we're
1734 passing a filename to clamd). */
1737 return m_panic_defer(scanent, CUS callout_address,
1738 US"ClamAV returned null");
1740 /* strip newline at the end (won't be present for zINSTREAM)
1741 (also any trailing whitespace, which shouldn't exist, but we depend upon
1742 this below, so double-check) */
1743 p = av_buffer + Ustrlen(av_buffer) - 1;
1744 if (*p == '\n') *p = '\0';
1746 DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1748 while (isspace(*--p) && (p > av_buffer))
1752 /* colon in returned output? */
1753 if(!(p = Ustrchr(av_buffer,':')))
1754 return m_panic_defer(scanent, CUS callout_address, string_sprintf(
1755 "ClamAV returned malformed result (missing colon): %s",
1758 /* strip filename */
1759 while (*p && isspace(*++p)) /**/;
1762 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1763 but we should at least be resistant to it. */
1764 p = Ustrrchr(vname, ' ');
1765 result_tag = p ? p+1 : vname;
1767 if (Ustrcmp(result_tag, "FOUND") == 0)
1769 /* p should still be the whitespace before the result_tag */
1770 while (isspace(*p)) --p;
1772 /* Strip off the extended information too, which will be in parens
1773 after the virus name, with no intervening whitespace. */
1776 /* "(hash:size)", so previous '(' will do; if not found, we have
1777 a curious virus name, but not an error. */
1778 p = Ustrrchr(vname, '(');
1782 malware_name = string_copy(vname);
1783 DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1786 else if (Ustrcmp(result_tag, "ERROR") == 0)
1787 return m_panic_defer(scanent, CUS callout_address,
1788 string_sprintf("ClamAV returned: %s", av_buffer));
1790 else if (Ustrcmp(result_tag, "OK") == 0)
1792 /* Everything should be OK */
1793 malware_name = NULL;
1794 DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1798 return m_panic_defer(scanent, CUS callout_address,
1799 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1805 #ifndef DISABLE_MAL_SOCK
1806 case M_SOCK: /* "sock" scanner type ------------------------------------- */
1807 /* This code was derived by Martin Poole from the clamd code contributed
1808 by David Saez and the cmdline code
1812 uschar * commandline;
1813 uschar av_buffer[1024];
1814 uschar * linebuffer;
1815 uschar * sockline_scanner;
1816 uschar sockline_scanner_default[] = "%s\n";
1817 const pcre *sockline_trig_re;
1818 const pcre *sockline_name_re;
1820 /* find scanner command line */
1821 if ( (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1823 && *sockline_scanner
1825 { /* check for no expansions apart from one %s */
1826 uschar * s = Ustrchr(sockline_scanner, '%');
1828 if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1829 return m_panic_defer_3(scanent, NULL,
1830 US"unsafe sock scanner call spec", sock);
1833 sockline_scanner = sockline_scanner_default;
1834 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1835 string_printing(sockline_scanner));
1837 /* find scanner output trigger */
1838 sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1839 "missing trigger specification", &errstr);
1840 if (!sockline_trig_re)
1841 return m_panic_defer_3(scanent, NULL, errstr, sock);
1843 /* find virus name regex */
1844 sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1845 "missing virus name regex specification", &errstr);
1846 if (!sockline_name_re)
1847 return m_panic_defer_3(scanent, NULL, errstr, sock);
1849 /* prepare scanner call - security depends on expansions check above */
1850 commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1851 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1852 string_printing(commandline));
1854 /* Pass the command string to the socket */
1855 if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1856 return m_panic_defer(scanent, CUS callout_address, errstr);
1858 /* Read the result */
1859 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1862 return m_panic_defer_3(scanent, CUS callout_address,
1863 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1866 if (bread == sizeof(av_buffer))
1867 return m_panic_defer_3(scanent, CUS callout_address,
1868 US"buffer too small", sock);
1869 av_buffer[bread] = '\0';
1870 linebuffer = string_copy(av_buffer);
1871 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1872 string_printing(linebuffer));
1874 /* try trigger match */
1875 if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1877 if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1878 malware_name = US "unknown";
1879 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1880 string_printing(malware_name));
1882 else /* no virus found */
1883 malware_name = NULL;
1888 #ifndef DISABLE_MAL_MKS
1889 case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1891 char *mksd_options_end;
1892 int mksd_maxproc = 1; /* default, if no option supplied */
1895 if (scanner_options)
1897 mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1898 if ( *scanner_options == '\0'
1899 || *mksd_options_end != '\0'
1901 || mksd_maxproc > 32
1903 return m_panic_defer(scanent, CUS callout_address,
1904 string_sprintf("invalid option '%s'", scanner_options));
1907 if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1908 return m_panic_defer(scanent, CUS callout_address, errstr);
1910 malware_name = NULL;
1912 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1914 if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1923 #ifndef DISABLE_MAL_AVAST
1924 case M_AVAST: /* "avast" scanner type ----------------------------------- */
1927 uschar * scanrequest;
1928 enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1931 uschar * error_message = NULL;
1934 /* According to Martin Tuma @avast the protocol uses "escaped
1935 whitespace", that is, every embedded whitespace is backslash
1936 escaped, as well as backslash is protected by backslash.
1937 The returned lines contain the name of the scanned file, a tab
1941 [E] - some error occured
1942 Such marker follows the first non-escaped TAB. For more information
1943 see avast-protocol(5)
1945 We observed two cases:
1947 <- /file [E]0.0 Error 13 Permission denied
1948 <- 451 SCAN Engine error 13 permission denied
1951 <- /file… [E]3.0 Error 41120 The file is a decompression bomb
1953 <- /file… [+]2.0 0 Eicar Test Virus!!!
1956 If the scanner returns 4xx, DEFER is a good decision, combined
1957 with a panic log entry, to get the admin's attention.
1959 If the scanner returns 200, we reject it as malware, if found any,
1960 or, in case of an error, we set the malware message to the error
1963 Some of the >= 42000 errors are message related - usually some
1964 broken archives etc, but some of them are e.g. license related.
1965 Once the license expires the engine starts returning errors for
1966 every scanning attempt. I¹ have the full list of the error codes
1967 but it is not a public API and is subject to change. It is hard
1968 for me to say what you should do in case of an engine error. You
1969 can have a “Treat * unscanned file as infection” policy or “Treat
1970 unscanned file as clean” policy. ¹) Jakub Bednar
1974 if ( ( !ava_re_clean
1975 && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1977 && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1979 && !(ava_re_error = m_pcre_compile(ava_re_error_str, &errstr)))
1981 return malware_panic_defer(errstr);
1983 /* wait for result */
1984 for (avast_stage = AVA_HELO;
1985 (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1988 int slen = Ustrlen(buf);
1992 /* Multi line responses are bracketed between 210 … and nnn … */
1993 if (Ustrncmp(buf, "210", 3) == 0)
1998 else if (more_data && isdigit(buf[0])) more_data = 0;
2000 switch (avast_stage)
2003 if (more_data) continue;
2004 if (Ustrncmp(buf, "220", 3) != 0)
2005 goto endloop; /* require a 220 */
2009 if (more_data) continue;
2010 if (Ustrncmp(buf, "200", 3) != 0)
2011 goto endloop; /* require a 200 */
2016 /* Check for another option to send. Newline-terminate it. */
2017 if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
2020 if (Ustrcmp(scanrequest, "pass_unscanned") == 0)
2022 DEBUG(D_acl) debug_printf_indent("pass unscanned files as clean\n");
2026 scanrequest = string_sprintf("%s\n", scanrequest);
2027 avast_stage = AVA_OPT; /* just sent option */
2028 DEBUG(D_acl) debug_printf_indent("send to avast OPTION: %s", scanrequest);
2032 scanrequest = string_sprintf("SCAN %s\n", eml_dir);
2033 avast_stage = AVA_RSP; /* just sent command */
2034 DEBUG(D_acl) debug_printf_indent("send to avast REQUEST: SCAN %s\n", eml_dir);
2037 /* send config-cmd or scan-request to socket */
2038 len = Ustrlen(scanrequest);
2039 if (send(sock, scanrequest, len, 0) == -1)
2041 scanrequest[len-1] = '\0';
2042 return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
2043 "unable to send request '%s' to socket (%s): %s",
2044 scanrequest, scanner_options, strerror(errno)), sock);
2051 if (isdigit(buf[0])) /* We're done */
2054 if (malware_name) /* Nothing else matters, just read on */
2057 if (pcre_exec(ava_re_clean, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2060 if (malware_name = m_pcre_exec(ava_re_virus, buf))
2062 unescape(malware_name);
2064 debug_printf_indent("unescaped malware name: '%s'\n", malware_name);
2068 if (strict) /* treat scanner errors as malware */
2070 if (malware_name = m_pcre_exec(ava_re_error, buf))
2072 unescape(malware_name);
2074 debug_printf_indent("unescaped error message: '%s'\n", malware_name);
2078 else if (pcre_exec(ava_re_error, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2080 log_write(0, LOG_MAIN, "internal scanner error (ignored): %s", buf);
2084 /* here also for any unexpected response from the scanner */
2085 DEBUG(D_acl) debug_printf("avast response not handled: '%s'\n", buf);
2089 default: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
2090 __FILE__, __LINE__, __FUNCTION__);
2097 if (nread == -1) error_message = US"EOF from scanner";
2098 else if (nread < 0) error_message = US"timeout from scanner";
2099 else if (nread == 0) error_message = US"got nothing from scanner";
2100 else if (buf[0] != '2') error_message = buf;
2102 DEBUG(D_acl) debug_printf_indent("sent to avast QUIT\n");
2103 if (send(sock, "QUIT\n", 5, 0) == -1)
2104 return m_panic_defer_3(scanent, CUS callout_address,
2105 string_sprintf("unable to send quit request to socket (%s): %s",
2106 scanner_options, strerror(errno)), sock);
2109 return m_panic_defer_3(scanent, CUS callout_address, error_message, sock);
2113 } /* scanner type switch */
2116 (void) close (sock);
2117 malware_ok = TRUE; /* set "been here, done that" marker */
2120 /* match virus name against pattern (caseless ------->----------v) */
2121 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
2123 DEBUG(D_acl) debug_printf_indent(
2124 "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2132 /*************************************************
2133 * Scan an email for malware *
2134 *************************************************/
2136 /* This is the normal interface for scanning an email, which doesn't need a
2137 filename; it's a wrapper around the malware_file function.
2140 malware_re match condition for "malware="
2141 timeout if nonzero, timeout in seconds
2143 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2144 where true means malware was found (condition applies)
2147 malware(const uschar * malware_re, int timeout)
2149 int ret = malware_internal(malware_re, NULL, timeout);
2151 if (ret == DEFER) av_failed = TRUE;
2156 /*************************************************
2157 * Scan a file for malware *
2158 *************************************************/
2160 /* This is a test wrapper for scanning an email, which is not used in
2161 normal processing. Scan any file, using the Exim scanning interface.
2162 This function tampers with various global variables so is unsafe to use
2163 in any other context.
2166 eml_filename a file holding the message to be scanned
2168 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2169 where true means malware was found (condition applies)
2172 malware_in_file(uschar *eml_filename)
2174 uschar message_id_buf[64];
2177 /* spool_mbox() assumes various parameters exist, when creating
2178 the relevant directory and the email within */
2180 (void) string_format(message_id_buf, sizeof(message_id_buf),
2181 "dummy-%d", vaguely_random_number(INT_MAX));
2182 message_id = message_id_buf;
2183 sender_address = US"malware-sender@example.net";
2185 recipients_list = NULL;
2186 receive_add_recipient(US"malware-victim@example.net", -1);
2187 enable_dollar_recipients = TRUE;
2189 ret = malware_internal(US"*", eml_filename, 0);
2191 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2194 /* don't set no_mbox_unspool; at present, there's no way for it to become
2195 set, but if that changes, then it should apply to these tests too */
2199 /* silence static analysis tools */
2209 if (!malware_default_re)
2210 malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2212 #ifndef DISABLE_MAL_DRWEB
2214 drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2216 #ifndef DISABLE_MAL_FSECURE
2218 fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2220 #ifndef DISABLE_MAL_KAV
2222 kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2224 kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2226 #ifndef DISABLE_MAL_AVAST
2228 ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2230 ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2232 ava_re_error = regex_must_compile(ava_re_error_str, FALSE, TRUE);
2234 #ifndef DISABLE_MAL_FFROT6D
2235 if (!fprot6d_re_error)
2236 fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2237 if (!fprot6d_re_virus)
2238 fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2244 malware_show_supported(FILE * f)
2247 fprintf(f, "Malware:");
2248 for (sc = m_scans; sc->scancode != -1; sc++) fprintf(f, " %s", sc->name);
2253 # endif /*!MACRO_PREDEF*/
2254 #endif /*WITH_CONTENT_SCAN*/