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 2016
10 /* Code for calling virus (malware) scanners. Called from acl.c. */
13 #ifdef WITH_CONTENT_SCAN
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 { M_FPROTD, US"f-protd", US"localhost 10200-10204", MC_TCP },
27 { M_DRWEB, US"drweb", US"/usr/local/drweb/run/drwebd.sock", MC_STRM },
28 { M_AVES, US"aveserver", US"/var/run/aveserver", MC_UNIX },
29 { M_FSEC, US"fsecure", US"/var/run/.fsav", MC_UNIX },
30 { M_KAVD, US"kavdaemon", US"/var/run/AvpCtl", MC_UNIX },
31 { M_CMDL, US"cmdline", NULL, MC_NONE },
32 { M_SOPHIE, US"sophie", US"/var/run/sophie", MC_UNIX },
33 { M_CLAMD, US"clamd", US"/tmp/clamd", MC_NONE },
34 { M_SOCK, US"sock", US"/tmp/malware.sock", MC_STRM },
35 { M_MKSD, US"mksd", NULL, MC_NONE },
36 { M_AVAST, US"avast", US"/var/run/avast/scan.sock", MC_STRM },
37 { M_FPROT6D, US"f-prot6d", US"localhost 10200", MC_TCP },
38 { -1, NULL, NULL, MC_NONE } /* end-marker */
41 /* The maximum number of clamd servers that are supported in the configuration */
42 #define MAX_CLAMD_SERVERS 32
43 #define MAX_CLAMD_SERVERS_S "32"
45 typedef struct clamd_address {
52 # define nelements(arr) (sizeof(arr) / sizeof(arr[0]))
56 #define MALWARE_TIMEOUT 120 /* default timeout, seconds */
59 #define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */
60 #define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */
61 #define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */
63 #define DERR_READ_ERR (1<<0) /* read error */
64 #define DERR_NOMEMORY (1<<2) /* no memory */
65 #define DERR_TIMEOUT (1<<9) /* scan timeout has run out */
66 #define DERR_BAD_CALL (1<<15) /* wrong command */
69 static const uschar * malware_regex_default = US ".+";
70 static const pcre * malware_default_re = NULL;
72 static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$";
73 static const pcre * drweb_re = NULL;
75 static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$";
76 static const pcre * fsec_re = NULL;
78 static const uschar * kav_re_sus_str = US "suspicion:\\s*(.+?)\\s*$";
79 static const uschar * kav_re_inf_str = US "infected:\\s*(.+?)\\s*$";
80 static const pcre * kav_re_sus = NULL;
81 static const pcre * kav_re_inf = NULL;
83 static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]";
84 static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d\\.\\d\\t\\d\\s(.*)";
85 static const pcre * ava_re_clean = NULL;
86 static const pcre * ava_re_virus = NULL;
88 static const uschar * fprot6d_re_error_str = US "^\\d+\\s<(.+?)>$";
89 static const uschar * fprot6d_re_virus_str = US "^\\d+\\s<infected:\\s+(.+?)>\\s+.+$";
90 static const pcre * fprot6d_re_error = NULL;
91 static const pcre * fprot6d_re_virus = NULL;
95 /******************************************************************************/
97 /* Routine to check whether a system is big- or little-endian.
98 Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
99 Needed for proper kavdaemon implementation. Sigh. */
100 #define BIG_MY_ENDIAN 0
101 #define LITTLE_MY_ENDIAN 1
102 static int test_byte_order(void);
106 short int word = 0x0001;
107 char *byte = CS &word;
108 return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
111 BOOL malware_ok = FALSE;
113 /* Gross hacks for the -bmalware option; perhaps we should just create
114 the scan directory normally for that case, but look into rigging up the
115 needed header variables if not already set on the command-line? */
116 extern int spool_mbox_ok;
117 extern uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
122 malware_errlog_defer(const uschar * str)
124 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
129 m_errlog_defer(struct scan * scanent, const uschar * hostport,
132 return malware_errlog_defer(string_sprintf("%s %s : %s",
133 scanent->name, hostport ? hostport : CUS"", str));
136 m_errlog_defer_3(struct scan * scanent, const uschar * hostport,
137 const uschar * str, int fd_to_close)
139 (void) close(fd_to_close);
140 return m_errlog_defer(scanent, hostport, str);
143 /*************************************************/
145 /* Only used by the Clamav code, which is working from a list of servers and
146 uses the returned in_addr to get a second connection to the same system.
149 m_tcpsocket(const uschar * hostname, unsigned int port,
150 host_item * host, uschar ** errstr, const blob * fastopen)
152 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
153 host, errstr, fastopen);
157 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
159 if (send(sock, buf, cnt, 0) < 0)
163 *errstr = string_sprintf("unable to send to socket (%s): %s",
171 m_pcre_compile(const uschar * re, uschar ** errstr)
173 const uschar * rerror;
177 cre = pcre_compile(CS re, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
179 *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
180 re, rerror, roffset);
185 m_pcre_exec(const pcre * cre, uschar * text)
188 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
189 ovector, nelements(ovector));
190 uschar * substr = NULL;
191 if (i >= 2) /* Got it */
192 pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr);
197 m_pcre_nextinlist(const uschar ** list, int * sep,
198 char * listerr, uschar ** errstr)
200 const uschar * list_ele;
201 const pcre * cre = NULL;
203 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
204 *errstr = US listerr;
207 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
208 string_printing(list_ele));
209 cre = m_pcre_compile(CUS list_ele, errstr);
215 Simple though inefficient wrapper for reading a line. Drop CRs and the
216 trailing newline. Can return early on buffer full. Null-terminate.
217 Apply initial timeout if no data ready.
219 Return: number of chars - zero for an empty line
221 -2 on timeout or error
224 recv_line(int fd, uschar * buffer, int bsize, int tmo)
230 if (!fd_ready(fd, tmo-time(NULL)))
233 /*XXX tmo handling assumes we always get a whole line */
236 while ((rcv = read(fd, p, 1)) > 0)
239 if (p-buffer > bsize-2) break;
240 if (*p == '\n') break;
245 DEBUG(D_acl) debug_printf_indent("Malware scan: read %s (%s)\n",
246 rcv==0 ? "EOF" : "error", strerror(errno));
247 return rcv==0 ? -1 : -2;
251 DEBUG(D_acl) debug_printf_indent("Malware scan: read '%s'\n", buffer);
255 /* return TRUE iff size as requested */
257 recv_len(int sock, void * buf, int size, int tmo)
259 return fd_ready(sock, tmo-time(NULL))
260 ? recv(sock, buf, size, 0) == size
266 /* ============= private routines for the "mksd" scanner type ============== */
271 mksd_writev (int sock, struct iovec * iov, int iovcnt)
278 i = writev (sock, iov, iovcnt);
279 while (i < 0 && errno == EINTR);
282 (void) malware_errlog_defer(
283 US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
286 for (;;) /* check for short write */
287 if (i >= iov->iov_len)
297 iov->iov_base = CS iov->iov_base + i;
304 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, int tmo)
311 i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL));
314 (void) malware_errlog_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
319 /* offset == av_buffer_size -> buffer full */
320 if (offset == av_buffer_size)
322 (void) malware_errlog_defer(US"malformed reply received from mksd");
325 } while (av_buffer[offset-1] != '\n');
327 av_buffer[offset] = '\0';
332 mksd_parse_line(struct scan * scanent, char * line)
343 if ((p = strchr (line, '\n')) != NULL)
345 return m_errlog_defer(scanent, NULL,
346 string_sprintf("scanner failed: %s", line));
349 if ((p = strchr (line, '\n')) != NULL)
354 && (p = strchr(line+4, ' ')) != NULL
359 malware_name = string_copy(US line+4);
363 return m_errlog_defer(scanent, NULL,
364 string_sprintf("malformed reply received: %s", line));
369 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
373 const char *cmd = "MSQ\n";
374 uschar av_buffer[1024];
376 iov[0].iov_base = (void *) cmd;
378 iov[1].iov_base = (void *) scan_filename;
379 iov[1].iov_len = Ustrlen(scan_filename);
380 iov[2].iov_base = (void *) (cmd + 3);
383 if (mksd_writev (sock, iov, 3) < 0)
386 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
389 return mksd_parse_line (scanent, CS av_buffer);
394 clamd_option(clamd_address * cd, const uschar * optstr, int * subsep)
399 while ((s = string_nextinlist(&optstr, subsep, NULL, 0)))
400 if (Ustrncmp(s, "retry=", 6) == 0)
402 int sec = readconf_readtime((s += 6), '\0', FALSE);
412 /*************************************************
413 * Scan content for malware *
414 *************************************************/
416 /* This is an internal interface for scanning an email; the normal interface
417 is via malware(), or there's malware_in_file() used for testing/debugging.
420 malware_re match condition for "malware="
421 scan_filename the file holding the email to be scanned, if we're faking
422 this up for the -bmalware test, else NULL
423 timeout if nonzero, non-default timeoutl
425 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
426 where true means malware was found (condition applies)
429 malware_internal(const uschar * malware_re, const uschar * scan_filename,
433 const uschar *av_scanner_work = av_scanner;
434 uschar *scanner_name;
435 unsigned long mbox_size;
439 struct scan * scanent;
440 const uschar * scanner_options;
443 uschar * eml_filename, * eml_dir;
446 return FAIL; /* empty means "don't match anything" */
448 /* Ensure the eml mbox file is spooled up */
450 if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
451 return malware_errlog_defer(US"error while creating mbox spool file");
453 /* None of our current scanners need the mbox file as a stream (they use
454 the name), so we can close it right away. Get the directory too. */
456 (void) fclose(mbox_file);
457 eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
459 /* parse 1st option */
460 if (strcmpic(malware_re, US"false") == 0 || Ustrcmp(malware_re,"0") == 0)
461 return FAIL; /* explicitly no matching */
463 /* special cases (match anything except empty) */
464 if ( strcmpic(malware_re,US"true") == 0
465 || Ustrcmp(malware_re,"*") == 0
466 || Ustrcmp(malware_re,"1") == 0
469 if ( !malware_default_re
470 && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
471 return malware_errlog_defer(errstr);
472 malware_re = malware_regex_default;
473 re = malware_default_re;
476 /* compile the regex, see if it works */
477 else if (!(re = m_pcre_compile(malware_re, &errstr)))
478 return malware_errlog_defer(errstr);
480 /* if av_scanner starts with a dollar, expand it first */
481 if (*av_scanner == '$')
483 if (!(av_scanner_work = expand_string(av_scanner)))
484 return malware_errlog_defer(
485 string_sprintf("av_scanner starts with $, but expansion failed: %s",
486 expand_string_message));
489 debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work);
490 /* disable result caching in this case */
495 /* Do not scan twice (unless av_scanner is dynamic). */
498 /* find the scanner type from the av_scanner option */
499 if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
500 return malware_errlog_defer(US"av_scanner configuration variable is empty");
501 if (!timeout) timeout = MALWARE_TIMEOUT;
502 tmo = time(NULL) + timeout;
504 for (scanent = m_scans; ; scanent++)
507 return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
509 if (strcmpic(scanner_name, US scanent->name) != 0)
511 DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo=%s\n",
512 scanner_name, readconf_printtime(timeout));
514 if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
515 scanner_options = scanent->options_default;
516 if (scanent->conn == MC_NONE)
519 DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
520 switch(scanent->conn)
522 case MC_TCP: sock = ip_tcpsocket(scanner_options, &errstr, 5); break;
523 case MC_UNIX: sock = ip_unixsocket(scanner_options, &errstr); break;
524 case MC_STRM: sock = ip_streamsocket(scanner_options, &errstr, 5); break;
525 default: /* compiler quietening */ break;
528 return m_errlog_defer(scanent, CUS callout_address, errstr);
532 switch (scanent->scancode)
534 case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
536 uschar *fp_scan_option;
537 unsigned int detected=0, par_count=0;
538 uschar * scanrequest;
539 uschar buf[32768], *strhelper, *strhelper2;
540 uschar * malware_name_internal = NULL;
543 scanrequest = string_sprintf("GET %s", eml_filename);
545 while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
548 scanrequest = string_sprintf("%s%s%s", scanrequest,
549 par_count ? "%20" : "?", fp_scan_option);
552 scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
553 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
554 scanner_name, scanrequest);
556 /* send scan request */
557 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
558 return m_errlog_defer(scanent, CUS callout_address, errstr);
560 while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0)
563 if (Ustrstr(buf, US"<detected type=\"") != NULL)
565 else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
567 if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
570 malware_name_internal = string_copy(strhelper+6);
573 else if (Ustrstr(buf, US"<summary code=\""))
575 malware_name = Ustrstr(buf, US"<summary code=\"11\">")
576 ? malware_name_internal : NULL;
588 case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
589 /* v0.1 - added support for tcp sockets */
590 /* v0.0 - initial release -- support for unix sockets */
594 unsigned int fsize_uint;
595 uschar * tmpbuf, *drweb_fbuf;
596 int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
597 drweb_vnum, drweb_slen, drweb_fin = 0x0000;
599 /* prepare variables */
600 drweb_cmd = htonl(DRWEBD_SCAN_CMD);
601 drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
603 if (*scanner_options != '/')
606 if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1)
607 return m_errlog_defer_3(scanent, NULL,
608 string_sprintf("can't open spool file %s: %s",
609 eml_filename, strerror(errno)),
612 if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
615 badseek: err = errno;
616 (void)close(drweb_fd);
617 return m_errlog_defer_3(scanent, NULL,
618 string_sprintf("can't seek spool file %s: %s",
619 eml_filename, strerror(err)),
622 fsize_uint = (unsigned int) fsize;
623 if ((off_t)fsize_uint != fsize)
625 (void)close(drweb_fd);
626 return m_errlog_defer_3(scanent, NULL,
627 string_sprintf("seeking spool file %s, size overflow",
631 drweb_slen = htonl(fsize);
632 if (lseek(drweb_fd, 0, SEEK_SET) < 0)
635 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
636 scanner_name, scanner_options);
638 /* send scan request */
639 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
640 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
641 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
642 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
644 (void)close(drweb_fd);
645 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
646 "unable to send commands to socket (%s)", scanner_options),
650 if (!(drweb_fbuf = US malloc(fsize_uint)))
652 (void)close(drweb_fd);
653 return m_errlog_defer_3(scanent, NULL,
654 string_sprintf("unable to allocate memory %u for file (%s)",
655 fsize_uint, eml_filename),
659 if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
662 (void)close(drweb_fd);
664 return m_errlog_defer_3(scanent, NULL,
665 string_sprintf("can't read spool file %s: %s",
666 eml_filename, strerror(err)),
669 (void)close(drweb_fd);
671 /* send file body to socket */
672 if (send(sock, drweb_fbuf, fsize, 0) < 0)
675 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
676 "unable to send file body to socket (%s)", scanner_options),
682 drweb_slen = htonl(Ustrlen(eml_filename));
684 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n",
685 scanner_name, scanner_options);
687 /* send scan request */
688 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
689 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
690 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
691 (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
692 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
693 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
694 "unable to send commands to socket (%s)", scanner_options),
698 /* wait for result */
699 if (!recv_len(sock, &drweb_rc, sizeof(drweb_rc), tmo))
700 return m_errlog_defer_3(scanent, CUS callout_address,
701 US"unable to read return code", sock);
702 drweb_rc = ntohl(drweb_rc);
704 if (!recv_len(sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
705 return m_errlog_defer_3(scanent, CUS callout_address,
706 US"unable to read the number of viruses", sock);
707 drweb_vnum = ntohl(drweb_vnum);
709 /* "virus(es) found" if virus number is > 0 */
714 /* setup default virus name */
715 malware_name = US"unknown";
717 /* set up match regex */
719 drweb_re = m_pcre_compile(drweb_re_str, &errstr);
721 /* read and concatenate virus names into one string */
722 for (i = 0; i < drweb_vnum; i++)
724 int size = 0, off = 0, ovector[10*3];
725 /* read the size of report */
726 if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
727 return m_errlog_defer_3(scanent, CUS callout_address,
728 US"cannot read report size", sock);
729 drweb_slen = ntohl(drweb_slen);
730 tmpbuf = store_get(drweb_slen);
732 /* read report body */
733 if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
734 return m_errlog_defer_3(scanent, CUS callout_address,
735 US"cannot read report string", sock);
736 tmpbuf[drweb_slen] = '\0';
738 /* try matcher on the line, grab substring */
739 result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
740 ovector, nelements(ovector));
743 const char * pre_malware_nb;
745 pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
747 if (i==0) /* the first name we just copy to malware_name */
748 malware_name = string_append(NULL, &size, &off,
751 else /* concatenate each new virus name to previous */
752 malware_name = string_append(malware_name, &size, &off,
753 2, "/", pre_malware_nb);
755 pcre_free_substring(pre_malware_nb);
761 const char *drweb_s = NULL;
763 if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
764 if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
765 if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
766 if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
767 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
768 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
769 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
770 * and others are ignored */
772 return m_errlog_defer_3(scanent, CUS callout_address,
773 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
782 case M_AVES: /* "aveserver" scanner type -------------------------------- */
787 /* read aveserver's greeting and see if it is ready (2xx greeting) */
789 recv_line(sock, buf, sizeof(buf), tmo);
791 if (buf[0] != '2') /* aveserver is having problems */
792 return m_errlog_defer_3(scanent, CUS callout_address,
793 string_sprintf("unavailable (Responded: %s).",
794 ((buf[0] != 0) ? buf : US "nothing") ),
797 /* prepare our command */
798 (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
802 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
804 if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
805 return m_errlog_defer(scanent, CUS callout_address, errstr);
809 /* read response lines, find malware name and final response */
810 while (recv_line(sock, buf, sizeof(buf), tmo) > 0)
814 if (buf[0] == '5') /* aveserver is having problems */
816 result = m_errlog_defer(scanent, CUS callout_address,
817 string_sprintf("unable to scan file %s (Responded: %s).",
821 if (Ustrncmp(buf,"322",3) == 0)
823 uschar *p = Ustrchr(&buf[4], ' ');
825 malware_name = string_copy(&buf[4]);
829 if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
830 return m_errlog_defer(scanent, CUS callout_address, errstr);
832 /* read aveserver's greeting and see if it is ready (2xx greeting) */
834 recv_line(sock, buf, sizeof(buf), tmo);
836 if (buf[0] != '2') /* aveserver is having problems */
837 return m_errlog_defer_3(scanent, CUS callout_address,
838 string_sprintf("unable to quit dialogue (Responded: %s).",
839 ((buf[0] != 0) ? buf : US "nothing") ),
850 case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
854 uschar av_buffer[1024];
855 static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
856 US"CONFIGURE\tTIMEOUT\t0\n",
857 US"CONFIGURE\tMAXARCH\t5\n",
858 US"CONFIGURE\tMIME\t1\n" };
862 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
863 scanner_name, scanner_options);
865 memset(av_buffer, 0, sizeof(av_buffer));
866 for (i = 0; i != nelements(cmdopt); i++)
869 if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
870 return m_errlog_defer(scanent, CUS callout_address, errstr);
872 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
873 if (bread > 0) av_buffer[bread]='\0';
875 return m_errlog_defer_3(scanent, CUS callout_address,
876 string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
878 for (j = 0; j < bread; j++)
879 if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
883 /* pass the mailfile to fsecure */
884 file_name = string_sprintf("SCAN\t%s\n", eml_filename);
886 if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
887 return m_errlog_defer(scanent, CUS callout_address, errstr);
890 /* todo also SUSPICION\t */
892 fsec_re = m_pcre_compile(fsec_re_str, &errstr);
894 /* read report, linewise. Apply a timeout as the Fsecure daemon
895 sometimes wants an answer to "PING" but they won't tell us what */
897 uschar * p = av_buffer;
903 i = av_buffer+sizeof(av_buffer)-p;
904 if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
905 return m_errlog_defer_3(scanent, CUS callout_address,
906 string_sprintf("unable to read result (%s)", strerror(errno)),
909 for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
913 /* Really search for virus again? */
915 /* try matcher on the line, grab substring */
916 malware_name = m_pcre_exec(fsec_re, p);
918 if (Ustrstr(p, "OK\tScan ok."))
922 /* copy down the trailing partial line then read another chunk */
923 i = av_buffer+sizeof(av_buffer)-p;
924 memmove(av_buffer, p, i);
933 case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
937 uschar * scanrequest;
939 unsigned long kav_reportlen;
944 /* get current date and time, build scan request */
946 /* pdp note: before the eml_filename parameter, this scanned the
947 directory; not finding documentation, so we'll strip off the directory.
948 The side-effect is that the test framework scanning may end up in
949 scanning more than was requested, but for the normal interface, this is
952 strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
953 scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
954 p = Ustrrchr(scanrequest, '/');
958 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
959 scanner_name, scanner_options);
961 /* send scan request */
962 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
963 return m_errlog_defer(scanent, CUS callout_address, errstr);
965 /* wait for result */
966 if (!recv_len(sock, tmpbuf, 2, tmo))
967 return m_errlog_defer_3(scanent, CUS callout_address,
968 US"unable to read 2 bytes from socket.", sock);
970 /* get errorcode from one nibble */
971 kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
974 case 5: case 6: /* improper kavdaemon configuration */
975 return m_errlog_defer_3(scanent, CUS callout_address,
976 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
979 return m_errlog_defer_3(scanent, CUS callout_address,
980 US"reported 'scanning not completed' (code 1).", sock);
982 return m_errlog_defer_3(scanent, CUS callout_address,
983 US"reported 'kavdaemon damaged' (code 7).", sock);
986 /* code 8 is not handled, since it is ambiguous. It appears mostly on
987 bounces where part of a file has been cut off */
989 /* "virus found" return codes (2-4) */
990 if (kav_rc > 1 && kav_rc < 5)
994 /* setup default virus name */
995 malware_name = US"unknown";
997 report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
999 /* read the report, if available */
1000 if (report_flag == 1)
1002 /* read report size */
1003 if (!recv_len(sock, &kav_reportlen, 4, tmo))
1004 return m_errlog_defer_3(scanent, CUS callout_address,
1005 US"cannot read report size", sock);
1007 /* it's possible that avp returns av_buffer[1] == 1 but the
1008 reportsize is 0 (!?) */
1009 if (kav_reportlen > 0)
1011 /* set up match regex, depends on retcode */
1014 if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1015 kav_re = kav_re_sus;
1019 if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1020 kav_re = kav_re_inf;
1023 /* read report, linewise. Using size from stream to read amount of data
1024 from same stream is safe enough. */
1025 /* coverity[tainted_data] */
1026 while (kav_reportlen > 0)
1028 if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1030 kav_reportlen -= bread+1;
1032 /* try matcher on the line, grab substring */
1033 if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1039 else /* no virus found */
1040 malware_name = NULL;
1045 case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1047 const uschar *cmdline_scanner = scanner_options;
1048 const pcre *cmdline_trigger_re;
1049 const pcre *cmdline_regex_re;
1051 uschar * commandline;
1052 void (*eximsigchld)(int);
1053 void (*eximsigpipe)(int);
1054 FILE *scanner_out = NULL;
1056 FILE *scanner_record = NULL;
1057 uschar linebuffer[32767];
1062 if (!cmdline_scanner)
1063 return m_errlog_defer(scanent, NULL, errstr);
1065 /* find scanner output trigger */
1066 cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1067 "missing trigger specification", &errstr);
1068 if (!cmdline_trigger_re)
1069 return m_errlog_defer(scanent, NULL, errstr);
1071 /* find scanner name regex */
1072 cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1073 "missing virus name regex specification", &errstr);
1074 if (!cmdline_regex_re)
1075 return m_errlog_defer(scanent, NULL, errstr);
1077 /* prepare scanner call; despite the naming, file_name holds a directory
1078 name which is documented as the value given to %s. */
1080 file_name = string_copy(eml_filename);
1081 p = Ustrrchr(file_name, '/');
1084 commandline = string_sprintf(CS cmdline_scanner, file_name);
1086 /* redirect STDERR too */
1087 commandline = string_sprintf("%s 2>&1", commandline);
1089 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1090 scanner_name, commandline);
1092 /* store exims signal handlers */
1093 eximsigchld = signal(SIGCHLD,SIG_DFL);
1094 eximsigpipe = signal(SIGPIPE,SIG_DFL);
1096 if (!(scanner_out = popen(CS commandline,"r")))
1099 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1100 return m_errlog_defer(scanent, NULL,
1101 string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1103 scanner_fd = fileno(scanner_out);
1105 file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
1107 if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1110 (void) pclose(scanner_out);
1111 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1112 return m_errlog_defer(scanent, NULL, string_sprintf(
1113 "opening scanner output file (%s) failed: %s.",
1114 file_name, strerror(err)));
1117 /* look for trigger while recording output */
1118 while ((rcnt = recv_line(scanner_fd, linebuffer,
1119 sizeof(linebuffer), tmo)))
1126 (void) pclose(scanner_out);
1127 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1128 return m_errlog_defer(scanent, NULL, string_sprintf(
1129 "unable to read from scanner (%s): %s",
1130 commandline, strerror(err)));
1133 if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1136 (void) pclose(scanner_out);
1137 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1138 return m_errlog_defer(scanent, NULL, string_sprintf(
1139 "short write on scanner output file (%s).", file_name));
1141 putc('\n', scanner_record);
1142 /* try trigger match */
1144 && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1149 (void)fclose(scanner_record);
1150 sep = pclose(scanner_out);
1151 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1153 return m_errlog_defer(scanent, NULL,
1155 ? string_sprintf("running scanner failed: %s", strerror(sep))
1156 : string_sprintf("scanner returned error code: %d", sep));
1161 /* setup default virus name */
1162 malware_name = US"unknown";
1164 /* re-open the scanner output file, look for name match */
1165 scanner_record = fopen(CS file_name, "rb");
1166 while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1169 if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1172 (void)fclose(scanner_record);
1174 else /* no virus found */
1175 malware_name = NULL;
1179 case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1184 uschar av_buffer[1024];
1186 /* pass the scan directory to sophie */
1187 file_name = string_copy(eml_filename);
1188 if ((p = Ustrrchr(file_name, '/')))
1191 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1192 scanner_name, scanner_options);
1194 if ( write(sock, file_name, Ustrlen(file_name)) < 0
1195 || write(sock, "\n", 1) != 1
1197 return m_errlog_defer_3(scanent, CUS callout_address,
1198 string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1201 /* wait for result */
1202 memset(av_buffer, 0, sizeof(av_buffer));
1203 if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1204 return m_errlog_defer_3(scanent, CUS callout_address,
1205 string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1209 if (av_buffer[0] == '1') {
1210 uschar * s = Ustrchr(av_buffer, '\n');
1213 malware_name = string_copy(&av_buffer[2]);
1215 else if (!strncmp(CS av_buffer, "-1", 2))
1216 return m_errlog_defer_3(scanent, CUS callout_address,
1217 US"scanner reported error", sock);
1218 else /* all ok, no virus */
1219 malware_name = NULL;
1224 case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1226 /* This code was originally contributed by David Saez */
1227 /* There are three scanning methods available to us:
1228 * (1) Use the SCAN command, pointing to a file in the filesystem
1229 * (2) Use the STREAM command, send the data on a separate port
1230 * (3) Use the zINSTREAM command, send the data inline
1231 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1232 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1233 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1234 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless
1235 * WITH_OLD_CLAMAV_STREAM is defined.
1236 * See Exim bug 926 for details. */
1238 uschar *p, *vname, *result_tag;
1241 uschar av_buffer[1024];
1242 uschar *hostname = US"";
1244 uschar *clamav_fbuf;
1245 int clam_fd, result;
1247 unsigned int fsize_uint;
1248 BOOL use_scan_command = FALSE;
1249 clamd_address * cv[MAX_CLAMD_SERVERS];
1250 int num_servers = 0;
1251 #ifdef WITH_OLD_CLAMAV_STREAM
1253 uschar av_buffer2[1024];
1256 uint32_t send_size, send_final_zeroblock;
1260 /*XXX if unixdomain socket, only one server supported. Needs fixing;
1261 there's no reason we should not mix local and remote servers */
1263 if (*scanner_options == '/')
1266 const uschar * sublist;
1269 /* Local file; so we def want to use_scan_command and don't want to try
1270 * passing IP/port combinations */
1271 use_scan_command = TRUE;
1272 cd = (clamd_address *) store_get(sizeof(clamd_address));
1274 /* extract socket-path part */
1275 sublist = scanner_options;
1276 cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1279 if (clamd_option(cd, sublist, &subsep) != OK)
1280 return m_errlog_defer(scanent, NULL,
1281 string_sprintf("bad option '%s'", scanner_options));
1286 /* Go through the rest of the list of host/port and construct an array
1287 * of servers to try. The first one is the bit we just passed from
1288 * scanner_options so process that first and then scan the remainder of
1289 * the address buffer */
1293 const uschar * sublist;
1297 /* The 'local' option means use the SCAN command over the network
1298 * socket (ie common file storage in use) */
1299 /*XXX we could accept this also as a local option? */
1300 if (strcmpic(scanner_options, US"local") == 0)
1302 use_scan_command = TRUE;
1306 cd = (clamd_address *) store_get(sizeof(clamd_address));
1308 /* extract host and port part */
1309 sublist = scanner_options;
1310 if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1312 (void) m_errlog_defer(scanent, NULL,
1313 string_sprintf("missing address: '%s'", scanner_options));
1316 if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1318 (void) m_errlog_defer(scanent, NULL,
1319 string_sprintf("missing port: '%s'", scanner_options));
1322 cd->tcp_port = atoi(CS s);
1325 /*XXX should these options be common over scanner types? */
1326 if (clamd_option(cd, sublist, &subsep) != OK)
1327 return m_errlog_defer(scanent, NULL,
1328 string_sprintf("bad option '%s'", scanner_options));
1330 cv[num_servers++] = cd;
1331 if (num_servers >= MAX_CLAMD_SERVERS)
1333 (void) m_errlog_defer(scanent, NULL,
1334 US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1335 "specified; only using the first " MAX_CLAMD_SERVERS_S );
1338 } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1341 /* check if we have at least one server */
1343 return m_errlog_defer(scanent, NULL,
1344 US"no useable server addresses in malware configuration option.");
1347 /* See the discussion of response formats below to see why we really
1348 don't like colons in filenames when passing filenames to ClamAV. */
1349 if (use_scan_command && Ustrchr(eml_filename, ':'))
1350 return m_errlog_defer(scanent, NULL,
1351 string_sprintf("local/SCAN mode incompatible with" \
1352 " : in path to email filename [%s]", eml_filename));
1354 /* Set up the very first data we will be sending */
1355 if (!use_scan_command)
1356 #ifdef WITH_OLD_CLAMAV_STREAM
1357 { cmd_str.data = US"STREAM\n"; cmd_str.len = 7; }
1359 { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1363 cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
1364 cmd_str.len = Ustrlen(cmd_str.data);
1367 /* We have some network servers specified */
1370 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1371 * only supports AF_INET, but we should probably be looking to the
1372 * future and rewriting this to be protocol-independent anyway. */
1374 while (num_servers > 0)
1376 int i = random_number(num_servers);
1377 clamd_address * cd = cv[i];
1379 DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1380 cd->hostspec, cd->tcp_port);
1382 /* Lookup the host. This is to ensure that we connect to the same IP
1383 * on both connections (as one host could resolve to multiple ips) */
1386 if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1387 &connhost, &errstr, &cmd_str)) >= 0)
1389 /* Connection successfully established with a server */
1390 hostname = cd->hostspec;
1394 if (cd->retry <= 0) break;
1395 while (cd->retry > 0) cd->retry = sleep(cd->retry);
1400 (void) m_errlog_defer(scanent, CUS callout_address, errstr);
1402 /* Remove the server from the list. XXX We should free the memory */
1404 for (; i < num_servers; i++)
1408 if (num_servers == 0)
1409 return m_errlog_defer(scanent, NULL, US"all servers failed");
1414 if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1416 hostname = cv[0]->hostspec;
1419 if (cv[0]->retry <= 0)
1420 return m_errlog_defer(scanent, CUS callout_address, errstr);
1421 while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1424 /* have socket in variable "sock"; command to use is semi-independent of
1425 * the socket protocol. We use SCAN if is local (either Unix/local
1426 * domain socket, or explicitly told local) else we stream the data.
1427 * How we stream the data depends upon how we were built. */
1429 if (!use_scan_command)
1431 #ifdef WITH_OLD_CLAMAV_STREAM
1432 /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1433 * that port on a second connection; then in the scan-method-neutral
1434 * part, read the response back on the original connection. */
1436 DEBUG(D_acl) debug_printf_indent(
1437 "Malware scan: issuing %s old-style remote scan (PORT)\n",
1440 /* Pass the string to ClamAV (7 = "STREAM\n"), if not already sent */
1442 if (m_sock_send(sock, cmd_str.data, cmd_str.len, &errstr) < 0)
1443 return m_errlog_defer(scanent, CUS callout_address, errstr);
1445 memset(av_buffer2, 0, sizeof(av_buffer2));
1446 bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
1449 return m_errlog_defer_3(scanent, CUS callout_address,
1450 string_sprintf("unable to read PORT from socket (%s)",
1454 if (bread == sizeof(av_buffer2))
1455 return m_errlog_defer_3(scanent, CUS callout_address,
1456 "buffer too small", sock);
1459 return m_errlog_defer_3(scanent, CUS callout_address,
1460 "ClamAV returned null", sock);
1462 av_buffer2[bread] = '\0';
1463 if(sscanf(CS av_buffer2, "PORT %u\n", &port) != 1)
1464 return m_errlog_defer_3(scanent, CUS callout_address,
1465 string_sprintf("Expected port information from clamd, got '%s'",
1469 sockData = m_tcpsocket(connhost.address, port, NULL, &errstr, NULL);
1471 return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock);
1473 # define CLOSE_SOCKDATA (void)close(sockData)
1474 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1475 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1476 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1479 DEBUG(D_acl) debug_printf_indent(
1480 "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1483 /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1485 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1486 return m_errlog_defer_3(scanent, CUS hostname,
1487 string_sprintf("unable to send zINSTREAM to socket (%s)",
1491 # define CLOSE_SOCKDATA /**/
1494 /* calc file size */
1495 if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1499 return m_errlog_defer_3(scanent, NULL,
1500 string_sprintf("can't open spool file %s: %s",
1501 eml_filename, strerror(err)),
1504 if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1507 b_seek: err = errno;
1508 CLOSE_SOCKDATA; (void)close(clam_fd);
1509 return m_errlog_defer_3(scanent, NULL,
1510 string_sprintf("can't seek spool file %s: %s",
1511 eml_filename, strerror(err)),
1514 fsize_uint = (unsigned int) fsize;
1515 if ((off_t)fsize_uint != fsize)
1517 CLOSE_SOCKDATA; (void)close(clam_fd);
1518 return m_errlog_defer_3(scanent, NULL,
1519 string_sprintf("seeking spool file %s, size overflow",
1523 if (lseek(clam_fd, 0, SEEK_SET) < 0)
1526 if (!(clamav_fbuf = US malloc(fsize_uint)))
1528 CLOSE_SOCKDATA; (void)close(clam_fd);
1529 return m_errlog_defer_3(scanent, NULL,
1530 string_sprintf("unable to allocate memory %u for file (%s)",
1531 fsize_uint, eml_filename),
1535 if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1538 free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd);
1539 return m_errlog_defer_3(scanent, NULL,
1540 string_sprintf("can't read spool file %s: %s",
1541 eml_filename, strerror(err)),
1544 (void)close(clam_fd);
1546 /* send file body to socket */
1547 #ifdef WITH_OLD_CLAMAV_STREAM
1548 if (send(sockData, clamav_fbuf, fsize_uint, 0) < 0)
1550 free(clamav_fbuf); CLOSE_SOCKDATA;
1551 return m_errlog_defer_3(scanent, NULL,
1552 string_sprintf("unable to send file body to socket (%s:%u)",
1557 send_size = htonl(fsize_uint);
1558 send_final_zeroblock = 0;
1559 if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1560 (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1561 (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1564 return m_errlog_defer_3(scanent, NULL,
1565 string_sprintf("unable to send file body to socket (%s)", hostname),
1573 #undef CLOSE_SOCKDATA
1576 { /* use scan command */
1577 /* Send a SCAN command pointing to a filename; then in the then in the
1578 * scan-method-neutral part, read the response back */
1580 /* ================================================================= */
1582 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1583 which dates to when ClamAV needed us to break apart the email into the
1584 MIME parts (eg, with the now deprecated demime condition coming first).
1585 Some time back, ClamAV gained the ability to deconstruct the emails, so
1586 doing this would actually have resulted in the mail attachments being
1587 scanned twice, in the broken out files and from the original .eml.
1588 Since ClamAV now handles emails (and has for quite some time) we can
1589 just use the email file itself. */
1590 /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
1592 DEBUG(D_acl) debug_printf_indent(
1593 "Malware scan: issuing %s local-path scan [%s]\n",
1594 scanner_name, scanner_options);
1597 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1598 return m_errlog_defer_3(scanent, CUS callout_address,
1599 string_sprintf("unable to write to socket (%s)", strerror(errno)),
1602 /* Do not shut down the socket for writing; a user report noted that
1603 * clamd 0.70 does not react well to this. */
1605 /* Commands have been sent, no matter which scan method or connection
1606 * type we're using; now just read the result, independent of method. */
1608 /* Read the result */
1609 memset(av_buffer, 0, sizeof(av_buffer));
1610 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1615 return m_errlog_defer(scanent, CUS callout_address,
1616 string_sprintf("unable to read from socket (%s)",
1617 errno == 0 ? "EOF" : strerror(errno)));
1619 if (bread == sizeof(av_buffer))
1620 return m_errlog_defer(scanent, CUS callout_address,
1621 US"buffer too small");
1622 /* We're now assured of a NULL at the end of av_buffer */
1624 /* Check the result. ClamAV returns one of two result formats.
1625 In the basic mode, the response is of the form:
1626 infected: -> "<filename>: <virusname> FOUND"
1627 not-infected: -> "<filename>: OK"
1628 error: -> "<filename>: <errcode> ERROR
1629 If the ExtendedDetectionInfo option has been turned on, then we get:
1630 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1631 for the infected case. Compare:
1632 /tmp/eicar.com: Eicar-Test-Signature FOUND
1633 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1635 In the streaming case, clamd uses the filename "stream" which you should
1636 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1637 client app will replace "stream" with the original filename before returning
1638 results to stdout, but the trace shows the data).
1640 We will assume that the pathname passed to clamd from Exim does not contain
1641 a colon. We will have whined loudly above if the eml_filename does (and we're
1642 passing a filename to clamd). */
1645 return m_errlog_defer(scanent, CUS callout_address,
1646 US"ClamAV returned null");
1648 /* strip newline at the end (won't be present for zINSTREAM)
1649 (also any trailing whitespace, which shouldn't exist, but we depend upon
1650 this below, so double-check) */
1651 p = av_buffer + Ustrlen(av_buffer) - 1;
1652 if (*p == '\n') *p = '\0';
1654 DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1656 while (isspace(*--p) && (p > av_buffer))
1660 /* colon in returned output? */
1661 if(!(p = Ustrchr(av_buffer,':')))
1662 return m_errlog_defer(scanent, CUS callout_address, string_sprintf(
1663 "ClamAV returned malformed result (missing colon): %s",
1666 /* strip filename */
1667 while (*p && isspace(*++p)) /**/;
1670 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1671 but we should at least be resistant to it. */
1672 p = Ustrrchr(vname, ' ');
1673 result_tag = p ? p+1 : vname;
1675 if (Ustrcmp(result_tag, "FOUND") == 0)
1677 /* p should still be the whitespace before the result_tag */
1678 while (isspace(*p)) --p;
1680 /* Strip off the extended information too, which will be in parens
1681 after the virus name, with no intervening whitespace. */
1684 /* "(hash:size)", so previous '(' will do; if not found, we have
1685 a curious virus name, but not an error. */
1686 p = Ustrrchr(vname, '(');
1690 malware_name = string_copy(vname);
1691 DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1694 else if (Ustrcmp(result_tag, "ERROR") == 0)
1695 return m_errlog_defer(scanent, CUS callout_address,
1696 string_sprintf("ClamAV returned: %s", av_buffer));
1698 else if (Ustrcmp(result_tag, "OK") == 0)
1700 /* Everything should be OK */
1701 malware_name = NULL;
1702 DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1706 return m_errlog_defer(scanent, CUS callout_address,
1707 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1712 case M_SOCK: /* "sock" scanner type ------------------------------------- */
1713 /* This code was derived by Martin Poole from the clamd code contributed
1714 by David Saez and the cmdline code
1718 uschar * commandline;
1719 uschar av_buffer[1024];
1720 uschar * linebuffer;
1721 uschar * sockline_scanner;
1722 uschar sockline_scanner_default[] = "%s\n";
1723 const pcre *sockline_trig_re;
1724 const pcre *sockline_name_re;
1726 /* find scanner command line */
1727 if ( (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1729 && *sockline_scanner
1731 { /* check for no expansions apart from one %s */
1732 uschar * s = Ustrchr(sockline_scanner, '%');
1734 if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1735 return m_errlog_defer_3(scanent, NULL,
1736 US"unsafe sock scanner call spec", sock);
1739 sockline_scanner = sockline_scanner_default;
1740 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1741 string_printing(sockline_scanner));
1743 /* find scanner output trigger */
1744 sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1745 "missing trigger specification", &errstr);
1746 if (!sockline_trig_re)
1747 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1749 /* find virus name regex */
1750 sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1751 "missing virus name regex specification", &errstr);
1752 if (!sockline_name_re)
1753 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1755 /* prepare scanner call - security depends on expansions check above */
1756 commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1757 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1758 string_printing(commandline));
1760 /* Pass the command string to the socket */
1761 if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1762 return m_errlog_defer(scanent, CUS callout_address, errstr);
1764 /* Read the result */
1765 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1768 return m_errlog_defer_3(scanent, CUS callout_address,
1769 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1772 if (bread == sizeof(av_buffer))
1773 return m_errlog_defer_3(scanent, CUS callout_address,
1774 US"buffer too small", sock);
1775 av_buffer[bread] = '\0';
1776 linebuffer = string_copy(av_buffer);
1777 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1778 string_printing(linebuffer));
1780 /* try trigger match */
1781 if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1783 if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1784 malware_name = US "unknown";
1785 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1786 string_printing(malware_name));
1788 else /* no virus found */
1789 malware_name = NULL;
1793 case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1795 char *mksd_options_end;
1796 int mksd_maxproc = 1; /* default, if no option supplied */
1799 if (scanner_options)
1801 mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1802 if ( *scanner_options == '\0'
1803 || *mksd_options_end != '\0'
1805 || mksd_maxproc > 32
1807 return m_errlog_defer(scanent, CUS callout_address,
1808 string_sprintf("invalid option '%s'", scanner_options));
1811 if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1812 return m_errlog_defer(scanent, CUS callout_address, errstr);
1814 malware_name = NULL;
1816 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1818 if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1826 case M_AVAST: /* "avast" scanner type ----------------------------------- */
1830 uschar * scanrequest;
1831 enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1834 /* According to Martin Tuma @avast the protocol uses "escaped
1835 whitespace", that is, every embedded whitespace is backslash
1836 escaped, as well as backslash is protected by backslash.
1837 The returned lines contain the name of the scanned file, a tab
1841 [E] - some error occured
1842 Such marker follows the first non-escaped TAB. */
1843 if ( ( !ava_re_clean
1844 && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1846 && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1848 return malware_errlog_defer(errstr);
1850 /* wait for result */
1851 for (avast_stage = AVA_HELO;
1852 (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1855 int slen = Ustrlen(buf);
1858 DEBUG(D_acl) debug_printf_indent("got from avast: %s\n", buf);
1859 switch (avast_stage)
1862 if (Ustrncmp(buf, "220", 3) != 0)
1863 goto endloop; /* require a 220 */
1867 if (Ustrncmp(buf, "210", 3) == 0)
1868 break; /* ignore 210 responses */
1869 if (Ustrncmp(buf, "200", 3) != 0)
1870 goto endloop; /* require a 200 */
1875 /* Check for another option to send. Newline-terminate it. */
1876 if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1879 scanrequest = string_sprintf("%s\n", scanrequest);
1880 avast_stage = AVA_OPT; /* just sent option */
1884 scanrequest = string_sprintf("SCAN %s\n", eml_dir);
1885 avast_stage = AVA_RSP; /* just sent command */
1888 /* send config-cmd or scan-request to socket */
1889 len = Ustrlen(scanrequest);
1890 if (send(sock, scanrequest, len, 0) < 0)
1892 scanrequest[len-1] = '\0';
1893 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
1894 "unable to send request '%s' to socket (%s): %s",
1895 scanrequest, scanner_options, strerror(errno)), sock);
1901 if (Ustrncmp(buf, "210", 3) == 0)
1902 break; /* ignore the "210 SCAN DATA" message */
1904 if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
1905 0, 0, ovector, nelements(ovector)) > 0)
1908 if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
1909 { /* remove backslash in front of [whitespace|backslash] */
1911 for (p = malware_name; *p; ++p)
1912 if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
1913 for (p0 = p; *p0; ++p0) *p0 = p0[1];
1915 avast_stage = AVA_DONE;
1919 if (Ustrncmp(buf, "200 SCAN OK", 11) == 0)
1920 { /* we're done finally */
1921 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1922 return m_errlog_defer_3(scanent, CUS callout_address,
1924 "unable to send quit request to socket (%s): %s",
1925 scanner_options, strerror(errno)),
1927 malware_name = NULL;
1928 avast_stage = AVA_DONE;
1932 /* here for any unexpected response from the scanner */
1935 case AVA_DONE: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
1936 __FILE__, __LINE__, __FUNCTION__);
1946 case AVA_RSP: return m_errlog_defer_3(scanent, CUS callout_address,
1949 "invalid response from scanner: '%s'", buf)
1951 ? US"EOF from scanner"
1952 : US"timeout from scanner",
1959 case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
1963 uschar * linebuffer;
1964 uschar * scanrequest;
1965 uschar av_buffer[1024];
1967 if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
1968 || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
1969 return malware_errlog_defer(errstr);
1971 scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
1972 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
1973 scanner_name, scanrequest);
1975 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
1976 return m_errlog_defer(scanent, CUS callout_address, errstr);
1978 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1981 return m_errlog_defer_3(scanent, CUS callout_address,
1982 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1985 if (bread == sizeof(av_buffer))
1986 return m_errlog_defer_3(scanent, CUS callout_address,
1987 US"buffer too small", sock);
1989 av_buffer[bread] = '\0';
1990 linebuffer = string_copy(av_buffer);
1992 m_sock_send(sock, US"QUIT\n", 5, 0);
1994 if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
1995 return m_errlog_defer_3(scanent, CUS callout_address,
1996 string_sprintf("scanner reported error (%s)", e), sock);
1998 if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
1999 malware_name = NULL;
2003 } /* scanner type switch */
2006 (void) close (sock);
2007 malware_ok = TRUE; /* set "been here, done that" marker */
2010 /* match virus name against pattern (caseless ------->----------v) */
2011 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
2013 DEBUG(D_acl) debug_printf_indent(
2014 "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2022 /*************************************************
2023 * Scan an email for malware *
2024 *************************************************/
2026 /* This is the normal interface for scanning an email, which doesn't need a
2027 filename; it's a wrapper around the malware_file function.
2030 malware_re match condition for "malware="
2031 timeout if nonzero, timeout in seconds
2033 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2034 where true means malware was found (condition applies)
2037 malware(const uschar * malware_re, int timeout)
2039 int ret = malware_internal(malware_re, NULL, timeout);
2041 if (ret == DEFER) av_failed = TRUE;
2046 /*************************************************
2047 * Scan a file for malware *
2048 *************************************************/
2050 /* This is a test wrapper for scanning an email, which is not used in
2051 normal processing. Scan any file, using the Exim scanning interface.
2052 This function tampers with various global variables so is unsafe to use
2053 in any other context.
2056 eml_filename a file holding the message to be scanned
2058 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2059 where true means malware was found (condition applies)
2062 malware_in_file(uschar *eml_filename)
2064 uschar message_id_buf[64];
2067 /* spool_mbox() assumes various parameters exist, when creating
2068 the relevant directory and the email within */
2070 (void) string_format(message_id_buf, sizeof(message_id_buf),
2071 "dummy-%d", vaguely_random_number(INT_MAX));
2072 message_id = message_id_buf;
2073 sender_address = US"malware-sender@example.net";
2075 recipients_list = NULL;
2076 receive_add_recipient(US"malware-victim@example.net", -1);
2077 enable_dollar_recipients = TRUE;
2079 ret = malware_internal(US"*", eml_filename, 0);
2081 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2084 /* don't set no_mbox_unspool; at present, there's no way for it to become
2085 set, but if that changes, then it should apply to these tests too */
2089 /* silence static analysis tools */
2099 if (!malware_default_re)
2100 malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2102 drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2104 fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2106 kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2108 kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2110 ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2112 ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2113 if (!fprot6d_re_error)
2114 fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2115 if (!fprot6d_re_virus)
2116 fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2119 #endif /*WITH_CONTENT_SCAN*/