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\\.\\d\\t\\d\\s(.*)";
141 static const pcre * ava_re_clean = NULL;
142 static const pcre * ava_re_virus = NULL;
145 #ifndef DISABLE_MAL_FFROT6D
146 static const uschar * fprot6d_re_error_str = US "^\\d+\\s<(.+?)>$";
147 static const uschar * fprot6d_re_virus_str = US "^\\d+\\s<infected:\\s+(.+?)>\\s+.+$";
148 static const pcre * fprot6d_re_error = NULL;
149 static const pcre * fprot6d_re_virus = NULL;
154 /******************************************************************************/
156 /* Routine to check whether a system is big- or little-endian.
157 Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
158 Needed for proper kavdaemon implementation. Sigh. */
159 #define BIG_MY_ENDIAN 0
160 #define LITTLE_MY_ENDIAN 1
161 static int test_byte_order(void);
165 short int word = 0x0001;
166 char *byte = CS &word;
167 return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
170 BOOL malware_ok = FALSE;
172 /* Gross hacks for the -bmalware option; perhaps we should just create
173 the scan directory normally for that case, but look into rigging up the
174 needed header variables if not already set on the command-line? */
175 extern int spool_mbox_ok;
176 extern uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
181 malware_errlog_defer(const uschar * str)
183 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
188 m_errlog_defer(struct scan * scanent, const uschar * hostport,
191 return malware_errlog_defer(string_sprintf("%s %s : %s",
192 scanent->name, hostport ? hostport : CUS"", str));
195 m_errlog_defer_3(struct scan * scanent, const uschar * hostport,
196 const uschar * str, int fd_to_close)
198 (void) close(fd_to_close);
199 return m_errlog_defer(scanent, hostport, str);
202 /*************************************************/
204 #ifndef DISABLE_MAL_CLAM
205 /* Only used by the Clamav code, which is working from a list of servers and
206 uses the returned in_addr to get a second connection to the same system.
209 m_tcpsocket(const uschar * hostname, unsigned int port,
210 host_item * host, uschar ** errstr, const blob * fastopen_blob)
212 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
213 host, errstr, fastopen_blob);
218 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
220 if (send(sock, buf, cnt, 0) < 0)
224 *errstr = string_sprintf("unable to send to socket (%s): %s",
232 m_pcre_compile(const uschar * re, uschar ** errstr)
234 const uschar * rerror;
238 cre = pcre_compile(CS re, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
240 *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
241 re, rerror, roffset);
246 m_pcre_exec(const pcre * cre, uschar * text)
249 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
250 ovector, nelem(ovector));
251 uschar * substr = NULL;
252 if (i >= 2) /* Got it */
253 pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr);
258 m_pcre_nextinlist(const uschar ** list, int * sep,
259 char * listerr, uschar ** errstr)
261 const uschar * list_ele;
262 const pcre * cre = NULL;
264 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
265 *errstr = US listerr;
268 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
269 string_printing(list_ele));
270 cre = m_pcre_compile(CUS list_ele, errstr);
276 Simple though inefficient wrapper for reading a line. Drop CRs and the
277 trailing newline. Can return early on buffer full. Null-terminate.
278 Apply initial timeout if no data ready.
280 Return: number of chars - zero for an empty line
282 -2 on timeout or error
285 recv_line(int fd, uschar * buffer, int bsize, int tmo)
291 if (!fd_ready(fd, tmo-time(NULL)))
294 /*XXX tmo handling assumes we always get a whole line */
297 while ((rcv = read(fd, p, 1)) > 0)
300 if (p-buffer > bsize-2) break;
301 if (*p == '\n') break;
306 DEBUG(D_acl) debug_printf_indent("Malware scan: read %s (%s)\n",
307 rcv==0 ? "EOF" : "error", strerror(errno));
308 return rcv==0 ? -1 : -2;
312 DEBUG(D_acl) debug_printf_indent("Malware scan: read '%s'\n", buffer);
316 /* return TRUE iff size as requested */
318 recv_len(int sock, void * buf, int size, int tmo)
320 return fd_ready(sock, tmo-time(NULL))
321 ? recv(sock, buf, size, 0) == size
327 #ifndef DISABLE_MAL_MKS
328 /* ============= private routines for the "mksd" scanner type ============== */
330 # include <sys/uio.h>
333 mksd_writev (int sock, struct iovec * iov, int iovcnt)
340 i = writev (sock, iov, iovcnt);
341 while (i < 0 && errno == EINTR);
344 (void) malware_errlog_defer(
345 US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
348 for (;;) /* check for short write */
349 if (i >= iov->iov_len)
359 iov->iov_base = CS iov->iov_base + i;
366 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, int tmo)
373 i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL));
376 (void) malware_errlog_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
381 /* offset == av_buffer_size -> buffer full */
382 if (offset == av_buffer_size)
384 (void) malware_errlog_defer(US"malformed reply received from mksd");
387 } while (av_buffer[offset-1] != '\n');
389 av_buffer[offset] = '\0';
394 mksd_parse_line(struct scan * scanent, char * line)
405 if ((p = strchr (line, '\n')) != NULL)
407 return m_errlog_defer(scanent, NULL,
408 string_sprintf("scanner failed: %s", line));
411 if ((p = strchr (line, '\n')) != NULL)
416 && (p = strchr(line+4, ' ')) != NULL
421 malware_name = string_copy(US line+4);
425 return m_errlog_defer(scanent, NULL,
426 string_sprintf("malformed reply received: %s", line));
431 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
435 const char *cmd = "MSQ\n";
436 uschar av_buffer[1024];
438 iov[0].iov_base = (void *) cmd;
440 iov[1].iov_base = (void *) scan_filename;
441 iov[1].iov_len = Ustrlen(scan_filename);
442 iov[2].iov_base = (void *) (cmd + 3);
445 if (mksd_writev (sock, iov, 3) < 0)
448 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
451 return mksd_parse_line (scanent, CS av_buffer);
456 #ifndef DISABLE_MAL_CLAM
458 clamd_option(clamd_address * cd, const uschar * optstr, int * subsep)
463 while ((s = string_nextinlist(&optstr, subsep, NULL, 0)))
464 if (Ustrncmp(s, "retry=", 6) == 0)
466 int sec = readconf_readtime((s += 6), '\0', FALSE);
479 /*************************************************
480 * Scan content for malware *
481 *************************************************/
483 /* This is an internal interface for scanning an email; the normal interface
484 is via malware(), or there's malware_in_file() used for testing/debugging.
487 malware_re match condition for "malware="
488 scan_filename the file holding the email to be scanned, if we're faking
489 this up for the -bmalware test, else NULL
490 timeout if nonzero, non-default timeoutl
492 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
493 where true means malware was found (condition applies)
496 malware_internal(const uschar * malware_re, const uschar * scan_filename,
500 const uschar *av_scanner_work = av_scanner;
501 uschar *scanner_name;
502 unsigned long mbox_size;
506 struct scan * scanent;
507 const uschar * scanner_options;
510 uschar * eml_filename, * eml_dir;
513 return FAIL; /* empty means "don't match anything" */
515 /* Ensure the eml mbox file is spooled up */
517 if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
518 return malware_errlog_defer(US"error while creating mbox spool file");
520 /* None of our current scanners need the mbox file as a stream (they use
521 the name), so we can close it right away. Get the directory too. */
523 (void) fclose(mbox_file);
524 eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
526 /* parse 1st option */
527 if (strcmpic(malware_re, US"false") == 0 || Ustrcmp(malware_re,"0") == 0)
528 return FAIL; /* explicitly no matching */
530 /* special cases (match anything except empty) */
531 if ( strcmpic(malware_re,US"true") == 0
532 || Ustrcmp(malware_re,"*") == 0
533 || Ustrcmp(malware_re,"1") == 0
536 if ( !malware_default_re
537 && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
538 return malware_errlog_defer(errstr);
539 malware_re = malware_regex_default;
540 re = malware_default_re;
543 /* compile the regex, see if it works */
544 else if (!(re = m_pcre_compile(malware_re, &errstr)))
545 return malware_errlog_defer(errstr);
547 /* if av_scanner starts with a dollar, expand it first */
548 if (*av_scanner == '$')
550 if (!(av_scanner_work = expand_string(av_scanner)))
551 return malware_errlog_defer(
552 string_sprintf("av_scanner starts with $, but expansion failed: %s",
553 expand_string_message));
556 debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work);
557 /* disable result caching in this case */
562 /* Do not scan twice (unless av_scanner is dynamic). */
565 /* find the scanner type from the av_scanner option */
566 if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
567 return malware_errlog_defer(US"av_scanner configuration variable is empty");
568 if (!timeout) timeout = MALWARE_TIMEOUT;
569 tmo = time(NULL) + timeout;
571 for (scanent = m_scans; ; scanent++)
574 return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
576 if (strcmpic(scanner_name, US scanent->name) != 0)
578 DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo=%s\n",
579 scanner_name, readconf_printtime(timeout));
581 if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
582 scanner_options = scanent->options_default;
583 if (scanent->conn == MC_NONE)
586 DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
587 switch(scanent->conn)
589 case MC_TCP: sock = ip_tcpsocket(scanner_options, &errstr, 5); break;
590 case MC_UNIX: sock = ip_unixsocket(scanner_options, &errstr); break;
591 case MC_STRM: sock = ip_streamsocket(scanner_options, &errstr, 5); break;
592 default: /* compiler quietening */ break;
595 return m_errlog_defer(scanent, CUS callout_address, errstr);
599 switch (scanent->scancode)
601 #ifndef DISABLE_MAL_FFROTD
602 case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
604 uschar *fp_scan_option;
605 unsigned int detected=0, par_count=0;
606 uschar * scanrequest;
607 uschar buf[32768], *strhelper, *strhelper2;
608 uschar * malware_name_internal = NULL;
611 scanrequest = string_sprintf("GET %s", eml_filename);
613 while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
616 scanrequest = string_sprintf("%s%s%s", scanrequest,
617 par_count ? "%20" : "?", fp_scan_option);
620 scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
621 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
622 scanner_name, scanrequest);
624 /* send scan request */
625 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
626 return m_errlog_defer(scanent, CUS callout_address, errstr);
628 while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0)
631 if (Ustrstr(buf, US"<detected type=\"") != NULL)
633 else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
635 if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
638 malware_name_internal = string_copy(strhelper+6);
641 else if (Ustrstr(buf, US"<summary code=\""))
643 malware_name = Ustrstr(buf, US"<summary code=\"11\">")
644 ? malware_name_internal : NULL;
657 #ifndef DISABLE_MAL_FFROT6D
658 case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
663 uschar * scanrequest;
664 uschar av_buffer[1024];
666 if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
667 || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
668 return malware_errlog_defer(errstr);
670 scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
671 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
672 scanner_name, scanrequest);
674 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
675 return m_errlog_defer(scanent, CUS callout_address, errstr);
677 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
680 return m_errlog_defer_3(scanent, CUS callout_address,
681 string_sprintf("unable to read from socket (%s)", strerror(errno)),
684 if (bread == sizeof(av_buffer))
685 return m_errlog_defer_3(scanent, CUS callout_address,
686 US"buffer too small", sock);
688 av_buffer[bread] = '\0';
689 linebuffer = string_copy(av_buffer);
691 m_sock_send(sock, US"QUIT\n", 5, 0);
693 if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
694 return m_errlog_defer_3(scanent, CUS callout_address,
695 string_sprintf("scanner reported error (%s)", e), sock);
697 if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
704 #ifndef DISABLE_MAL_DRWEB
705 case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
706 /* v0.1 - added support for tcp sockets */
707 /* v0.0 - initial release -- support for unix sockets */
711 unsigned int fsize_uint;
712 uschar * tmpbuf, *drweb_fbuf;
713 int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
714 drweb_vnum, drweb_slen, drweb_fin = 0x0000;
716 /* prepare variables */
717 drweb_cmd = htonl(DRWEBD_SCAN_CMD);
718 drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
720 if (*scanner_options != '/')
723 if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1)
724 return m_errlog_defer_3(scanent, NULL,
725 string_sprintf("can't open spool file %s: %s",
726 eml_filename, strerror(errno)),
729 if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
732 badseek: err = errno;
733 (void)close(drweb_fd);
734 return m_errlog_defer_3(scanent, NULL,
735 string_sprintf("can't seek spool file %s: %s",
736 eml_filename, strerror(err)),
739 fsize_uint = (unsigned int) fsize;
740 if ((off_t)fsize_uint != fsize)
742 (void)close(drweb_fd);
743 return m_errlog_defer_3(scanent, NULL,
744 string_sprintf("seeking spool file %s, size overflow",
748 drweb_slen = htonl(fsize);
749 if (lseek(drweb_fd, 0, SEEK_SET) < 0)
752 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
753 scanner_name, scanner_options);
755 /* send scan request */
756 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
757 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
758 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
759 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
761 (void)close(drweb_fd);
762 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
763 "unable to send commands to socket (%s)", scanner_options),
767 if (!(drweb_fbuf = US malloc(fsize_uint)))
769 (void)close(drweb_fd);
770 return m_errlog_defer_3(scanent, NULL,
771 string_sprintf("unable to allocate memory %u for file (%s)",
772 fsize_uint, eml_filename),
776 if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
779 (void)close(drweb_fd);
781 return m_errlog_defer_3(scanent, NULL,
782 string_sprintf("can't read spool file %s: %s",
783 eml_filename, strerror(err)),
786 (void)close(drweb_fd);
788 /* send file body to socket */
789 if (send(sock, drweb_fbuf, fsize, 0) < 0)
792 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
793 "unable to send file body to socket (%s)", scanner_options),
799 drweb_slen = htonl(Ustrlen(eml_filename));
801 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n",
802 scanner_name, scanner_options);
804 /* send scan request */
805 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
806 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
807 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
808 (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
809 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
810 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
811 "unable to send commands to socket (%s)", scanner_options),
815 /* wait for result */
816 if (!recv_len(sock, &drweb_rc, sizeof(drweb_rc), tmo))
817 return m_errlog_defer_3(scanent, CUS callout_address,
818 US"unable to read return code", sock);
819 drweb_rc = ntohl(drweb_rc);
821 if (!recv_len(sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
822 return m_errlog_defer_3(scanent, CUS callout_address,
823 US"unable to read the number of viruses", sock);
824 drweb_vnum = ntohl(drweb_vnum);
826 /* "virus(es) found" if virus number is > 0 */
832 /* setup default virus name */
833 malware_name = US"unknown";
835 /* set up match regex */
837 drweb_re = m_pcre_compile(drweb_re_str, &errstr);
839 /* read and concatenate virus names into one string */
840 for (i = 0; i < drweb_vnum; i++)
844 /* read the size of report */
845 if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
846 return m_errlog_defer_3(scanent, CUS callout_address,
847 US"cannot read report size", sock);
848 drweb_slen = ntohl(drweb_slen);
849 tmpbuf = store_get(drweb_slen);
851 /* read report body */
852 if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
853 return m_errlog_defer_3(scanent, CUS callout_address,
854 US"cannot read report string", sock);
855 tmpbuf[drweb_slen] = '\0';
857 /* try matcher on the line, grab substring */
858 result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
859 ovector, nelem(ovector));
862 const char * pre_malware_nb;
864 pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
866 if (i==0) /* the first name we just copy to malware_name */
867 g = string_cat(NULL, US pre_malware_nb);
869 /*XXX could be string_append_listele? */
870 else /* concatenate each new virus name to previous */
871 g = string_append(g, 2, "/", pre_malware_nb);
873 pcre_free_substring(pre_malware_nb);
876 malware_name = string_from_gstring(g);
880 const char *drweb_s = NULL;
882 if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
883 if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
884 if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
885 if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
886 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
887 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
888 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
889 * and others are ignored */
891 return m_errlog_defer_3(scanent, CUS callout_address,
892 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
902 #ifndef DISABLE_MAL_AVE
903 case M_AVES: /* "aveserver" scanner type -------------------------------- */
908 /* read aveserver's greeting and see if it is ready (2xx greeting) */
910 recv_line(sock, buf, sizeof(buf), tmo);
912 if (buf[0] != '2') /* aveserver is having problems */
913 return m_errlog_defer_3(scanent, CUS callout_address,
914 string_sprintf("unavailable (Responded: %s).",
915 ((buf[0] != 0) ? buf : US "nothing") ),
918 /* prepare our command */
919 (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
923 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
925 if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
926 return m_errlog_defer(scanent, CUS callout_address, errstr);
930 /* read response lines, find malware name and final response */
931 while (recv_line(sock, buf, sizeof(buf), tmo) > 0)
935 if (buf[0] == '5') /* aveserver is having problems */
937 result = m_errlog_defer(scanent, CUS callout_address,
938 string_sprintf("unable to scan file %s (Responded: %s).",
942 if (Ustrncmp(buf,"322",3) == 0)
944 uschar *p = Ustrchr(&buf[4], ' ');
946 malware_name = string_copy(&buf[4]);
950 if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
951 return m_errlog_defer(scanent, CUS callout_address, errstr);
953 /* read aveserver's greeting and see if it is ready (2xx greeting) */
955 recv_line(sock, buf, sizeof(buf), tmo);
957 if (buf[0] != '2') /* aveserver is having problems */
958 return m_errlog_defer_3(scanent, CUS callout_address,
959 string_sprintf("unable to quit dialogue (Responded: %s).",
960 ((buf[0] != 0) ? buf : US "nothing") ),
972 #ifndef DISABLE_MAL_FSECURE
973 case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
977 uschar av_buffer[1024];
978 static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
979 US"CONFIGURE\tTIMEOUT\t0\n",
980 US"CONFIGURE\tMAXARCH\t5\n",
981 US"CONFIGURE\tMIME\t1\n" };
985 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
986 scanner_name, scanner_options);
988 memset(av_buffer, 0, sizeof(av_buffer));
989 for (i = 0; i != nelem(cmdopt); i++)
992 if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
993 return m_errlog_defer(scanent, CUS callout_address, errstr);
995 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
996 if (bread > 0) av_buffer[bread]='\0';
998 return m_errlog_defer_3(scanent, CUS callout_address,
999 string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
1001 for (j = 0; j < bread; j++)
1002 if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
1006 /* pass the mailfile to fsecure */
1007 file_name = string_sprintf("SCAN\t%s\n", eml_filename);
1009 if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
1010 return m_errlog_defer(scanent, CUS callout_address, errstr);
1013 /* todo also SUSPICION\t */
1015 fsec_re = m_pcre_compile(fsec_re_str, &errstr);
1017 /* read report, linewise. Apply a timeout as the Fsecure daemon
1018 sometimes wants an answer to "PING" but they won't tell us what */
1020 uschar * p = av_buffer;
1026 i = av_buffer+sizeof(av_buffer)-p;
1027 if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
1028 return m_errlog_defer_3(scanent, CUS callout_address,
1029 string_sprintf("unable to read result (%s)", strerror(errno)),
1032 for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
1036 /* Really search for virus again? */
1038 /* try matcher on the line, grab substring */
1039 malware_name = m_pcre_exec(fsec_re, p);
1041 if (Ustrstr(p, "OK\tScan ok."))
1045 /* copy down the trailing partial line then read another chunk */
1046 i = av_buffer+sizeof(av_buffer)-p;
1047 memmove(av_buffer, p, i);
1057 #ifndef DISABLE_MAL_KAV
1058 case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
1061 uschar tmpbuf[1024];
1062 uschar * scanrequest;
1064 unsigned long kav_reportlen;
1069 /* get current date and time, build scan request */
1071 /* pdp note: before the eml_filename parameter, this scanned the
1072 directory; not finding documentation, so we'll strip off the directory.
1073 The side-effect is that the test framework scanning may end up in
1074 scanning more than was requested, but for the normal interface, this is
1077 strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
1078 scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
1079 p = Ustrrchr(scanrequest, '/');
1083 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1084 scanner_name, scanner_options);
1086 /* send scan request */
1087 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
1088 return m_errlog_defer(scanent, CUS callout_address, errstr);
1090 /* wait for result */
1091 if (!recv_len(sock, tmpbuf, 2, tmo))
1092 return m_errlog_defer_3(scanent, CUS callout_address,
1093 US"unable to read 2 bytes from socket.", sock);
1095 /* get errorcode from one nibble */
1096 kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
1099 case 5: case 6: /* improper kavdaemon configuration */
1100 return m_errlog_defer_3(scanent, CUS callout_address,
1101 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
1104 return m_errlog_defer_3(scanent, CUS callout_address,
1105 US"reported 'scanning not completed' (code 1).", sock);
1107 return m_errlog_defer_3(scanent, CUS callout_address,
1108 US"reported 'kavdaemon damaged' (code 7).", sock);
1111 /* code 8 is not handled, since it is ambiguous. It appears mostly on
1112 bounces where part of a file has been cut off */
1114 /* "virus found" return codes (2-4) */
1115 if (kav_rc > 1 && kav_rc < 5)
1117 int report_flag = 0;
1119 /* setup default virus name */
1120 malware_name = US"unknown";
1122 report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
1124 /* read the report, if available */
1125 if (report_flag == 1)
1127 /* read report size */
1128 if (!recv_len(sock, &kav_reportlen, 4, tmo))
1129 return m_errlog_defer_3(scanent, CUS callout_address,
1130 US"cannot read report size", sock);
1132 /* it's possible that avp returns av_buffer[1] == 1 but the
1133 reportsize is 0 (!?) */
1134 if (kav_reportlen > 0)
1136 /* set up match regex, depends on retcode */
1139 if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1140 kav_re = kav_re_sus;
1144 if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1145 kav_re = kav_re_inf;
1148 /* read report, linewise. Using size from stream to read amount of data
1149 from same stream is safe enough. */
1150 /* coverity[tainted_data] */
1151 while (kav_reportlen > 0)
1153 if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1155 kav_reportlen -= bread+1;
1157 /* try matcher on the line, grab substring */
1158 if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1164 else /* no virus found */
1165 malware_name = NULL;
1171 #ifndef DISABLE_MAL_CMDLINE
1172 case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1174 const uschar *cmdline_scanner = scanner_options;
1175 const pcre *cmdline_trigger_re;
1176 const pcre *cmdline_regex_re;
1178 uschar * commandline;
1179 void (*eximsigchld)(int);
1180 void (*eximsigpipe)(int);
1181 FILE *scanner_out = NULL;
1183 FILE *scanner_record = NULL;
1184 uschar linebuffer[32767];
1189 if (!cmdline_scanner)
1190 return m_errlog_defer(scanent, NULL, errstr);
1192 /* find scanner output trigger */
1193 cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1194 "missing trigger specification", &errstr);
1195 if (!cmdline_trigger_re)
1196 return m_errlog_defer(scanent, NULL, errstr);
1198 /* find scanner name regex */
1199 cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1200 "missing virus name regex specification", &errstr);
1201 if (!cmdline_regex_re)
1202 return m_errlog_defer(scanent, NULL, errstr);
1204 /* prepare scanner call; despite the naming, file_name holds a directory
1205 name which is documented as the value given to %s. */
1207 file_name = string_copy(eml_filename);
1208 p = Ustrrchr(file_name, '/');
1211 commandline = string_sprintf(CS cmdline_scanner, file_name);
1213 /* redirect STDERR too */
1214 commandline = string_sprintf("%s 2>&1", commandline);
1216 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1217 scanner_name, commandline);
1219 /* store exims signal handlers */
1220 eximsigchld = signal(SIGCHLD,SIG_DFL);
1221 eximsigpipe = signal(SIGPIPE,SIG_DFL);
1223 if (!(scanner_out = popen(CS commandline,"r")))
1226 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1227 return m_errlog_defer(scanent, NULL,
1228 string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1230 scanner_fd = fileno(scanner_out);
1232 file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
1234 if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1237 (void) pclose(scanner_out);
1238 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1239 return m_errlog_defer(scanent, NULL, string_sprintf(
1240 "opening scanner output file (%s) failed: %s.",
1241 file_name, strerror(err)));
1244 /* look for trigger while recording output */
1245 while ((rcnt = recv_line(scanner_fd, linebuffer,
1246 sizeof(linebuffer), tmo)))
1253 (void) pclose(scanner_out);
1254 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1255 return m_errlog_defer(scanent, NULL, string_sprintf(
1256 "unable to read from scanner (%s): %s",
1257 commandline, strerror(err)));
1260 if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1263 (void) pclose(scanner_out);
1264 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1265 return m_errlog_defer(scanent, NULL, string_sprintf(
1266 "short write on scanner output file (%s).", file_name));
1268 putc('\n', scanner_record);
1269 /* try trigger match */
1271 && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1276 (void)fclose(scanner_record);
1277 sep = pclose(scanner_out);
1278 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1280 return m_errlog_defer(scanent, NULL,
1282 ? string_sprintf("running scanner failed: %s", strerror(sep))
1283 : string_sprintf("scanner returned error code: %d", sep));
1288 /* setup default virus name */
1289 malware_name = US"unknown";
1291 /* re-open the scanner output file, look for name match */
1292 scanner_record = fopen(CS file_name, "rb");
1293 while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1296 if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1299 (void)fclose(scanner_record);
1301 else /* no virus found */
1302 malware_name = NULL;
1307 #ifndef DISABLE_MAL_SOPHIE
1308 case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1313 uschar av_buffer[1024];
1315 /* pass the scan directory to sophie */
1316 file_name = string_copy(eml_filename);
1317 if ((p = Ustrrchr(file_name, '/')))
1320 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1321 scanner_name, scanner_options);
1323 if ( write(sock, file_name, Ustrlen(file_name)) < 0
1324 || write(sock, "\n", 1) != 1
1326 return m_errlog_defer_3(scanent, CUS callout_address,
1327 string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1330 /* wait for result */
1331 memset(av_buffer, 0, sizeof(av_buffer));
1332 if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1333 return m_errlog_defer_3(scanent, CUS callout_address,
1334 string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1338 if (av_buffer[0] == '1') {
1339 uschar * s = Ustrchr(av_buffer, '\n');
1342 malware_name = string_copy(&av_buffer[2]);
1344 else if (!strncmp(CS av_buffer, "-1", 2))
1345 return m_errlog_defer_3(scanent, CUS callout_address,
1346 US"scanner reported error", sock);
1347 else /* all ok, no virus */
1348 malware_name = NULL;
1354 #ifndef DISABLE_MAL_CLAM
1355 case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1357 /* This code was originally contributed by David Saez */
1358 /* There are three scanning methods available to us:
1359 * (1) Use the SCAN command, pointing to a file in the filesystem
1360 * (2) Use the STREAM command, send the data on a separate port
1361 * (3) Use the zINSTREAM command, send the data inline
1362 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1363 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1364 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1365 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM
1366 * See Exim bug 926 for details. */
1368 uschar *p, *vname, *result_tag;
1370 uschar av_buffer[1024];
1371 uschar *hostname = US"";
1373 uschar *clamav_fbuf;
1374 int clam_fd, result;
1376 unsigned int fsize_uint;
1377 BOOL use_scan_command = FALSE;
1378 clamd_address * cv[MAX_CLAMD_SERVERS];
1379 int num_servers = 0;
1380 uint32_t send_size, send_final_zeroblock;
1383 /*XXX if unixdomain socket, only one server supported. Needs fixing;
1384 there's no reason we should not mix local and remote servers */
1386 if (*scanner_options == '/')
1389 const uschar * sublist;
1392 /* Local file; so we def want to use_scan_command and don't want to try
1393 * passing IP/port combinations */
1394 use_scan_command = TRUE;
1395 cd = (clamd_address *) store_get(sizeof(clamd_address));
1397 /* extract socket-path part */
1398 sublist = scanner_options;
1399 cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1402 if (clamd_option(cd, sublist, &subsep) != OK)
1403 return m_errlog_defer(scanent, NULL,
1404 string_sprintf("bad option '%s'", scanner_options));
1409 /* Go through the rest of the list of host/port and construct an array
1410 * of servers to try. The first one is the bit we just passed from
1411 * scanner_options so process that first and then scan the remainder of
1412 * the address buffer */
1416 const uschar * sublist;
1420 /* The 'local' option means use the SCAN command over the network
1421 * socket (ie common file storage in use) */
1422 /*XXX we could accept this also as a local option? */
1423 if (strcmpic(scanner_options, US"local") == 0)
1425 use_scan_command = TRUE;
1429 cd = (clamd_address *) store_get(sizeof(clamd_address));
1431 /* extract host and port part */
1432 sublist = scanner_options;
1433 if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1435 (void) m_errlog_defer(scanent, NULL,
1436 string_sprintf("missing address: '%s'", scanner_options));
1439 if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1441 (void) m_errlog_defer(scanent, NULL,
1442 string_sprintf("missing port: '%s'", scanner_options));
1445 cd->tcp_port = atoi(CS s);
1448 /*XXX should these options be common over scanner types? */
1449 if (clamd_option(cd, sublist, &subsep) != OK)
1450 return m_errlog_defer(scanent, NULL,
1451 string_sprintf("bad option '%s'", scanner_options));
1453 cv[num_servers++] = cd;
1454 if (num_servers >= MAX_CLAMD_SERVERS)
1456 (void) m_errlog_defer(scanent, NULL,
1457 US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1458 "specified; only using the first " MAX_CLAMD_SERVERS_S );
1461 } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1464 /* check if we have at least one server */
1466 return m_errlog_defer(scanent, NULL,
1467 US"no useable server addresses in malware configuration option.");
1470 /* See the discussion of response formats below to see why we really
1471 don't like colons in filenames when passing filenames to ClamAV. */
1472 if (use_scan_command && Ustrchr(eml_filename, ':'))
1473 return m_errlog_defer(scanent, NULL,
1474 string_sprintf("local/SCAN mode incompatible with" \
1475 " : in path to email filename [%s]", eml_filename));
1477 /* Set up the very first data we will be sending */
1478 if (!use_scan_command)
1479 { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1482 cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
1483 cmd_str.len = Ustrlen(cmd_str.data);
1486 /* We have some network servers specified */
1489 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1490 * only supports AF_INET, but we should probably be looking to the
1491 * future and rewriting this to be protocol-independent anyway. */
1493 while (num_servers > 0)
1495 int i = random_number(num_servers);
1496 clamd_address * cd = cv[i];
1498 DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1499 cd->hostspec, cd->tcp_port);
1501 /* Lookup the host. This is to ensure that we connect to the same IP
1502 * on both connections (as one host could resolve to multiple ips) */
1505 if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1506 &connhost, &errstr, &cmd_str)) >= 0)
1508 /* Connection successfully established with a server */
1509 hostname = cd->hostspec;
1513 if (cd->retry <= 0) break;
1514 while (cd->retry > 0) cd->retry = sleep(cd->retry);
1519 (void) m_errlog_defer(scanent, CUS callout_address, errstr);
1521 /* Remove the server from the list. XXX We should free the memory */
1523 for (; i < num_servers; i++)
1527 if (num_servers == 0)
1528 return m_errlog_defer(scanent, NULL, US"all servers failed");
1533 if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1535 hostname = cv[0]->hostspec;
1538 if (cv[0]->retry <= 0)
1539 return m_errlog_defer(scanent, CUS callout_address, errstr);
1540 while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1543 /* have socket in variable "sock"; command to use is semi-independent of
1544 * the socket protocol. We use SCAN if is local (either Unix/local
1545 * domain socket, or explicitly told local) else we stream the data.
1546 * How we stream the data depends upon how we were built. */
1548 if (!use_scan_command)
1550 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1551 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1554 DEBUG(D_acl) debug_printf_indent(
1555 "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1558 /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1560 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1561 return m_errlog_defer_3(scanent, CUS hostname,
1562 string_sprintf("unable to send zINSTREAM to socket (%s)",
1566 /* calc file size */
1567 if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1570 return m_errlog_defer_3(scanent, NULL,
1571 string_sprintf("can't open spool file %s: %s",
1572 eml_filename, strerror(err)),
1575 if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1578 b_seek: err = errno;
1579 (void)close(clam_fd);
1580 return m_errlog_defer_3(scanent, NULL,
1581 string_sprintf("can't seek spool file %s: %s",
1582 eml_filename, strerror(err)),
1585 fsize_uint = (unsigned int) fsize;
1586 if ((off_t)fsize_uint != fsize)
1588 (void)close(clam_fd);
1589 return m_errlog_defer_3(scanent, NULL,
1590 string_sprintf("seeking spool file %s, size overflow",
1594 if (lseek(clam_fd, 0, SEEK_SET) < 0)
1597 if (!(clamav_fbuf = US malloc(fsize_uint)))
1599 (void)close(clam_fd);
1600 return m_errlog_defer_3(scanent, NULL,
1601 string_sprintf("unable to allocate memory %u for file (%s)",
1602 fsize_uint, eml_filename),
1606 if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1609 free(clamav_fbuf); (void)close(clam_fd);
1610 return m_errlog_defer_3(scanent, NULL,
1611 string_sprintf("can't read spool file %s: %s",
1612 eml_filename, strerror(err)),
1615 (void)close(clam_fd);
1617 /* send file body to socket */
1618 send_size = htonl(fsize_uint);
1619 send_final_zeroblock = 0;
1620 if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1621 (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1622 (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1625 return m_errlog_defer_3(scanent, NULL,
1626 string_sprintf("unable to send file body to socket (%s)", hostname),
1633 { /* use scan command */
1634 /* Send a SCAN command pointing to a filename; then in the then in the
1635 * scan-method-neutral part, read the response back */
1637 /* ================================================================= */
1639 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1640 which dates to when ClamAV needed us to break apart the email into the
1641 MIME parts (eg, with the now deprecated demime condition coming first).
1642 Some time back, ClamAV gained the ability to deconstruct the emails, so
1643 doing this would actually have resulted in the mail attachments being
1644 scanned twice, in the broken out files and from the original .eml.
1645 Since ClamAV now handles emails (and has for quite some time) we can
1646 just use the email file itself. */
1647 /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
1649 DEBUG(D_acl) debug_printf_indent(
1650 "Malware scan: issuing %s local-path scan [%s]\n",
1651 scanner_name, scanner_options);
1654 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1655 return m_errlog_defer_3(scanent, CUS callout_address,
1656 string_sprintf("unable to write to socket (%s)", strerror(errno)),
1659 /* Do not shut down the socket for writing; a user report noted that
1660 * clamd 0.70 does not react well to this. */
1662 /* Commands have been sent, no matter which scan method or connection
1663 * type we're using; now just read the result, independent of method. */
1665 /* Read the result */
1666 memset(av_buffer, 0, sizeof(av_buffer));
1667 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1672 return m_errlog_defer(scanent, CUS callout_address,
1673 string_sprintf("unable to read from socket (%s)",
1674 errno == 0 ? "EOF" : strerror(errno)));
1676 if (bread == sizeof(av_buffer))
1677 return m_errlog_defer(scanent, CUS callout_address,
1678 US"buffer too small");
1679 /* We're now assured of a NULL at the end of av_buffer */
1681 /* Check the result. ClamAV returns one of two result formats.
1682 In the basic mode, the response is of the form:
1683 infected: -> "<filename>: <virusname> FOUND"
1684 not-infected: -> "<filename>: OK"
1685 error: -> "<filename>: <errcode> ERROR
1686 If the ExtendedDetectionInfo option has been turned on, then we get:
1687 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1688 for the infected case. Compare:
1689 /tmp/eicar.com: Eicar-Test-Signature FOUND
1690 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1692 In the streaming case, clamd uses the filename "stream" which you should
1693 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1694 client app will replace "stream" with the original filename before returning
1695 results to stdout, but the trace shows the data).
1697 We will assume that the pathname passed to clamd from Exim does not contain
1698 a colon. We will have whined loudly above if the eml_filename does (and we're
1699 passing a filename to clamd). */
1702 return m_errlog_defer(scanent, CUS callout_address,
1703 US"ClamAV returned null");
1705 /* strip newline at the end (won't be present for zINSTREAM)
1706 (also any trailing whitespace, which shouldn't exist, but we depend upon
1707 this below, so double-check) */
1708 p = av_buffer + Ustrlen(av_buffer) - 1;
1709 if (*p == '\n') *p = '\0';
1711 DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1713 while (isspace(*--p) && (p > av_buffer))
1717 /* colon in returned output? */
1718 if(!(p = Ustrchr(av_buffer,':')))
1719 return m_errlog_defer(scanent, CUS callout_address, string_sprintf(
1720 "ClamAV returned malformed result (missing colon): %s",
1723 /* strip filename */
1724 while (*p && isspace(*++p)) /**/;
1727 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1728 but we should at least be resistant to it. */
1729 p = Ustrrchr(vname, ' ');
1730 result_tag = p ? p+1 : vname;
1732 if (Ustrcmp(result_tag, "FOUND") == 0)
1734 /* p should still be the whitespace before the result_tag */
1735 while (isspace(*p)) --p;
1737 /* Strip off the extended information too, which will be in parens
1738 after the virus name, with no intervening whitespace. */
1741 /* "(hash:size)", so previous '(' will do; if not found, we have
1742 a curious virus name, but not an error. */
1743 p = Ustrrchr(vname, '(');
1747 malware_name = string_copy(vname);
1748 DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1751 else if (Ustrcmp(result_tag, "ERROR") == 0)
1752 return m_errlog_defer(scanent, CUS callout_address,
1753 string_sprintf("ClamAV returned: %s", av_buffer));
1755 else if (Ustrcmp(result_tag, "OK") == 0)
1757 /* Everything should be OK */
1758 malware_name = NULL;
1759 DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1763 return m_errlog_defer(scanent, CUS callout_address,
1764 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1770 #ifndef DISABLE_MAL_SOCK
1771 case M_SOCK: /* "sock" scanner type ------------------------------------- */
1772 /* This code was derived by Martin Poole from the clamd code contributed
1773 by David Saez and the cmdline code
1777 uschar * commandline;
1778 uschar av_buffer[1024];
1779 uschar * linebuffer;
1780 uschar * sockline_scanner;
1781 uschar sockline_scanner_default[] = "%s\n";
1782 const pcre *sockline_trig_re;
1783 const pcre *sockline_name_re;
1785 /* find scanner command line */
1786 if ( (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1788 && *sockline_scanner
1790 { /* check for no expansions apart from one %s */
1791 uschar * s = Ustrchr(sockline_scanner, '%');
1793 if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1794 return m_errlog_defer_3(scanent, NULL,
1795 US"unsafe sock scanner call spec", sock);
1798 sockline_scanner = sockline_scanner_default;
1799 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1800 string_printing(sockline_scanner));
1802 /* find scanner output trigger */
1803 sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1804 "missing trigger specification", &errstr);
1805 if (!sockline_trig_re)
1806 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1808 /* find virus name regex */
1809 sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1810 "missing virus name regex specification", &errstr);
1811 if (!sockline_name_re)
1812 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1814 /* prepare scanner call - security depends on expansions check above */
1815 commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1816 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1817 string_printing(commandline));
1819 /* Pass the command string to the socket */
1820 if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1821 return m_errlog_defer(scanent, CUS callout_address, errstr);
1823 /* Read the result */
1824 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1827 return m_errlog_defer_3(scanent, CUS callout_address,
1828 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1831 if (bread == sizeof(av_buffer))
1832 return m_errlog_defer_3(scanent, CUS callout_address,
1833 US"buffer too small", sock);
1834 av_buffer[bread] = '\0';
1835 linebuffer = string_copy(av_buffer);
1836 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1837 string_printing(linebuffer));
1839 /* try trigger match */
1840 if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1842 if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1843 malware_name = US "unknown";
1844 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1845 string_printing(malware_name));
1847 else /* no virus found */
1848 malware_name = NULL;
1853 #ifndef DISABLE_MAL_MKS
1854 case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1856 char *mksd_options_end;
1857 int mksd_maxproc = 1; /* default, if no option supplied */
1860 if (scanner_options)
1862 mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1863 if ( *scanner_options == '\0'
1864 || *mksd_options_end != '\0'
1866 || mksd_maxproc > 32
1868 return m_errlog_defer(scanent, CUS callout_address,
1869 string_sprintf("invalid option '%s'", scanner_options));
1872 if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1873 return m_errlog_defer(scanent, CUS callout_address, errstr);
1875 malware_name = NULL;
1877 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1879 if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1888 #ifndef DISABLE_MAL_AVAST
1889 case M_AVAST: /* "avast" scanner type ----------------------------------- */
1893 uschar * scanrequest;
1894 enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1898 /* According to Martin Tuma @avast the protocol uses "escaped
1899 whitespace", that is, every embedded whitespace is backslash
1900 escaped, as well as backslash is protected by backslash.
1901 The returned lines contain the name of the scanned file, a tab
1905 [E] - some error occured
1906 Such marker follows the first non-escaped TAB. For more information
1907 see avast-protocol(5)
1909 if ( ( !ava_re_clean
1910 && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1912 && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1914 return malware_errlog_defer(errstr);
1916 /* wait for result */
1917 for (avast_stage = AVA_HELO;
1918 (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1921 int slen = Ustrlen(buf);
1925 /* Multi line responses are bracketed between 210 … and nnn … */
1926 if (Ustrncmp(buf, "210", 3) == 0)
1931 else if (more_data && isdigit(buf[0])) more_data = 0;
1933 switch (avast_stage)
1936 if (more_data) continue;
1937 if (Ustrncmp(buf, "220", 3) != 0)
1938 goto endloop; /* require a 220 */
1942 if (more_data) continue;
1943 if (Ustrncmp(buf, "200", 3) != 0)
1944 goto endloop; /* require a 200 */
1949 /* Check for another option to send. Newline-terminate it. */
1950 if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1953 scanrequest = string_sprintf("%s\n", scanrequest);
1954 avast_stage = AVA_OPT; /* just sent option */
1955 DEBUG(D_acl) debug_printf_indent("send to avast OPTION: %s", scanrequest);
1959 scanrequest = string_sprintf("SCAN %s\n", eml_dir);
1960 avast_stage = AVA_RSP; /* just sent command */
1961 DEBUG(D_acl) debug_printf_indent("send to avast REQUEST: SCAN %s\n", eml_dir);
1964 /* send config-cmd or scan-request to socket */
1965 len = Ustrlen(scanrequest);
1966 if (send(sock, scanrequest, len, 0) < 0)
1968 scanrequest[len-1] = '\0';
1969 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
1970 "unable to send request '%s' to socket (%s): %s",
1971 scanrequest, scanner_options, strerror(errno)), sock);
1978 if (Ustrncmp(buf, "200", 3) == 0)
1979 { /* we're done finally */
1980 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1981 return m_errlog_defer_3(scanent, CUS callout_address,
1983 "unable to send quit request to socket (%s): %s",
1984 scanner_options, strerror(errno)),
1987 avast_stage = AVA_DONE;
1991 if (malware_name) break; /* found malware already, nothing to do anymore */
1993 if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
1994 0, 0, ovector, nelem(ovector)) > 0)
1997 if (malware_name = m_pcre_exec(ava_re_virus, buf))
1998 { /* remove backslash in front of [whitespace|backslash] */
2000 for (p = malware_name; *p; ++p)
2001 if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
2002 for (p0 = p; *p0; ++p0) *p0 = p0[1];
2005 debug_printf_indent("unescaped malware name: '%s'\n", malware_name);
2009 /* here also for any unexpected response from the scanner */
2012 default: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
2013 __FILE__, __LINE__, __FUNCTION__);
2023 case AVA_RSP: return m_errlog_defer_3(scanent, CUS callout_address,
2026 "invalid response from scanner: '%s'", buf)
2028 ? US"EOF from scanner"
2029 : US"timeout from scanner",
2036 } /* scanner type switch */
2039 (void) close (sock);
2040 malware_ok = TRUE; /* set "been here, done that" marker */
2043 /* match virus name against pattern (caseless ------->----------v) */
2044 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
2046 DEBUG(D_acl) debug_printf_indent(
2047 "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2055 /*************************************************
2056 * Scan an email for malware *
2057 *************************************************/
2059 /* This is the normal interface for scanning an email, which doesn't need a
2060 filename; it's a wrapper around the malware_file function.
2063 malware_re match condition for "malware="
2064 timeout if nonzero, timeout in seconds
2066 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2067 where true means malware was found (condition applies)
2070 malware(const uschar * malware_re, int timeout)
2072 int ret = malware_internal(malware_re, NULL, timeout);
2074 if (ret == DEFER) av_failed = TRUE;
2079 /*************************************************
2080 * Scan a file for malware *
2081 *************************************************/
2083 /* This is a test wrapper for scanning an email, which is not used in
2084 normal processing. Scan any file, using the Exim scanning interface.
2085 This function tampers with various global variables so is unsafe to use
2086 in any other context.
2089 eml_filename a file holding the message to be scanned
2091 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2092 where true means malware was found (condition applies)
2095 malware_in_file(uschar *eml_filename)
2097 uschar message_id_buf[64];
2100 /* spool_mbox() assumes various parameters exist, when creating
2101 the relevant directory and the email within */
2103 (void) string_format(message_id_buf, sizeof(message_id_buf),
2104 "dummy-%d", vaguely_random_number(INT_MAX));
2105 message_id = message_id_buf;
2106 sender_address = US"malware-sender@example.net";
2108 recipients_list = NULL;
2109 receive_add_recipient(US"malware-victim@example.net", -1);
2110 enable_dollar_recipients = TRUE;
2112 ret = malware_internal(US"*", eml_filename, 0);
2114 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2117 /* don't set no_mbox_unspool; at present, there's no way for it to become
2118 set, but if that changes, then it should apply to these tests too */
2122 /* silence static analysis tools */
2132 if (!malware_default_re)
2133 malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2135 #ifndef DISABLE_MAL_DRWEB
2137 drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2139 #ifndef DISABLE_MAL_FSECURE
2141 fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2143 #ifndef DISABLE_MAL_KAV
2145 kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2147 kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2149 #ifndef DISABLE_MAL_AVAST
2151 ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2153 ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2155 #ifndef DISABLE_MAL_FFROT6D
2156 if (!fprot6d_re_error)
2157 fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2158 if (!fprot6d_re_virus)
2159 fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2165 malware_show_supported(FILE * f)
2168 fprintf(f, "Malware:");
2169 for (sc = m_scans; sc->scancode != -1; sc++) fprintf(f, " %s", sc->name);
2174 # endif /*!MACRO_PREDEF*/
2175 #endif /*WITH_CONTENT_SCAN*/