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 = (char *) &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)
152 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5, host, errstr);
156 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
158 if (send(sock, buf, cnt, 0) < 0)
162 *errstr = string_sprintf("unable to send to socket (%s): %s",
170 m_pcre_compile(const uschar * re, uschar ** errstr)
172 const uschar * rerror;
176 cre = pcre_compile(CS re, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
178 *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
179 re, rerror, roffset);
184 m_pcre_exec(const pcre * cre, uschar * text)
187 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
188 ovector, nelements(ovector));
189 uschar * substr = NULL;
190 if (i >= 2) /* Got it */
191 pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr);
196 m_pcre_nextinlist(const uschar ** list, int * sep,
197 char * listerr, uschar ** errstr)
199 const uschar * list_ele;
200 const pcre * cre = NULL;
202 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
203 *errstr = US listerr;
206 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
207 string_printing(list_ele));
208 cre = m_pcre_compile(CUS list_ele, errstr);
214 Simple though inefficient wrapper for reading a line. Drop CRs and the
215 trailing newline. Can return early on buffer full. Null-terminate.
216 Apply initial timeout if no data ready.
218 Return: number of chars - zero for an empty line
220 -2 on timeout or error
223 recv_line(int fd, uschar * buffer, int bsize, int tmo)
229 if (!fd_ready(fd, tmo-time(NULL)))
232 /*XXX tmo handling assumes we always get a whole line */
235 while ((rcv = read(fd, p, 1)) > 0)
238 if (p-buffer > bsize-2) break;
239 if (*p == '\n') break;
244 DEBUG(D_acl) debug_printf_indent("Malware scan: read %s (%s)\n",
245 rcv==0 ? "EOF" : "error", strerror(errno));
246 return rcv==0 ? -1 : -2;
250 DEBUG(D_acl) debug_printf_indent("Malware scan: read '%s'\n", buffer);
254 /* return TRUE iff size as requested */
256 recv_len(int sock, void * buf, int size, int tmo)
258 return fd_ready(sock, tmo-time(NULL))
259 ? recv(sock, buf, size, 0) == size
265 /* ============= private routines for the "mksd" scanner type ============== */
270 mksd_writev (int sock, struct iovec * iov, int iovcnt)
277 i = writev (sock, iov, iovcnt);
278 while (i < 0 && errno == EINTR);
281 (void) malware_errlog_defer(
282 US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
285 for (;;) /* check for short write */
286 if (i >= iov->iov_len)
296 iov->iov_base = CS iov->iov_base + i;
303 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, int tmo)
310 i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL));
313 (void) malware_errlog_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
318 /* offset == av_buffer_size -> buffer full */
319 if (offset == av_buffer_size)
321 (void) malware_errlog_defer(US"malformed reply received from mksd");
324 } while (av_buffer[offset-1] != '\n');
326 av_buffer[offset] = '\0';
331 mksd_parse_line(struct scan * scanent, char * line)
342 if ((p = strchr (line, '\n')) != NULL)
344 return m_errlog_defer(scanent, NULL,
345 string_sprintf("scanner failed: %s", line));
348 if ((p = strchr (line, '\n')) != NULL)
353 && (p = strchr(line+4, ' ')) != NULL
358 malware_name = string_copy(US line+4);
362 return m_errlog_defer(scanent, NULL,
363 string_sprintf("malformed reply received: %s", line));
368 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
372 const char *cmd = "MSQ\n";
373 uschar av_buffer[1024];
375 iov[0].iov_base = (void *) cmd;
377 iov[1].iov_base = (void *) scan_filename;
378 iov[1].iov_len = Ustrlen(scan_filename);
379 iov[2].iov_base = (void *) (cmd + 3);
382 if (mksd_writev (sock, iov, 3) < 0)
385 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
388 return mksd_parse_line (scanent, CS av_buffer);
393 clamd_option(clamd_address * cd, const uschar * optstr, int * subsep)
398 while ((s = string_nextinlist(&optstr, subsep, NULL, 0)))
399 if (Ustrncmp(s, "retry=", 6) == 0)
401 int sec = readconf_readtime((s += 6), '\0', FALSE);
411 /*************************************************
412 * Scan content for malware *
413 *************************************************/
415 /* This is an internal interface for scanning an email; the normal interface
416 is via malware(), or there's malware_in_file() used for testing/debugging.
419 malware_re match condition for "malware="
420 scan_filename the file holding the email to be scanned, if we're faking
421 this up for the -bmalware test, else NULL
422 timeout if nonzero, non-default timeoutl
424 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
425 where true means malware was found (condition applies)
428 malware_internal(const uschar * malware_re, const uschar * scan_filename,
432 const uschar *av_scanner_work = av_scanner;
433 uschar *scanner_name;
434 unsigned long mbox_size;
438 struct scan * scanent;
439 const uschar * scanner_options;
442 uschar * eml_filename, * eml_dir;
445 return FAIL; /* empty means "don't match anything" */
447 /* Ensure the eml mbox file is spooled up */
449 if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
450 return malware_errlog_defer(US"error while creating mbox spool file");
452 /* None of our current scanners need the mbox file as a stream (they use
453 the name), so we can close it right away. Get the directory too. */
455 (void) fclose(mbox_file);
456 eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
458 /* parse 1st option */
459 if (strcmpic(malware_re, US"false") == 0 || Ustrcmp(malware_re,"0") == 0)
460 return FAIL; /* explicitly no matching */
462 /* special cases (match anything except empty) */
463 if ( strcmpic(malware_re,US"true") == 0
464 || Ustrcmp(malware_re,"*") == 0
465 || Ustrcmp(malware_re,"1") == 0
468 if ( !malware_default_re
469 && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
470 return malware_errlog_defer(errstr);
471 malware_re = malware_regex_default;
472 re = malware_default_re;
475 /* compile the regex, see if it works */
476 else if (!(re = m_pcre_compile(malware_re, &errstr)))
477 return malware_errlog_defer(errstr);
479 /* if av_scanner starts with a dollar, expand it first */
480 if (*av_scanner == '$')
482 if (!(av_scanner_work = expand_string(av_scanner)))
483 return malware_errlog_defer(
484 string_sprintf("av_scanner starts with $, but expansion failed: %s",
485 expand_string_message));
488 debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work);
489 /* disable result caching in this case */
494 /* Do not scan twice (unless av_scanner is dynamic). */
497 /* find the scanner type from the av_scanner option */
498 if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
499 return malware_errlog_defer(US"av_scanner configuration variable is empty");
500 if (!timeout) timeout = MALWARE_TIMEOUT;
501 tmo = time(NULL) + timeout;
503 for (scanent = m_scans; ; scanent++)
506 return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
508 if (strcmpic(scanner_name, US scanent->name) != 0)
510 DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo=%s\n",
511 scanner_name, readconf_printtime(timeout));
513 if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
514 scanner_options = scanent->options_default;
515 if (scanent->conn == MC_NONE)
518 DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
519 switch(scanent->conn)
521 case MC_TCP: sock = ip_tcpsocket(scanner_options, &errstr, 5); break;
522 case MC_UNIX: sock = ip_unixsocket(scanner_options, &errstr); break;
523 case MC_STRM: sock = ip_streamsocket(scanner_options, &errstr, 5); break;
524 default: /* compiler quietening */ break;
527 return m_errlog_defer(scanent, CUS callout_address, errstr);
531 switch (scanent->scancode)
533 case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
535 uschar *fp_scan_option;
536 unsigned int detected=0, par_count=0;
537 uschar * scanrequest;
538 uschar buf[32768], *strhelper, *strhelper2;
539 uschar * malware_name_internal = NULL;
542 scanrequest = string_sprintf("GET %s", eml_filename);
544 while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
547 scanrequest = string_sprintf("%s%s%s", scanrequest,
548 par_count ? "%20" : "?", fp_scan_option);
551 scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
552 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
553 scanner_name, scanrequest);
555 /* send scan request */
556 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
557 return m_errlog_defer(scanent, CUS callout_address, errstr);
559 while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0)
562 if (Ustrstr(buf, US"<detected type=\"") != NULL)
564 else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
566 if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
569 malware_name_internal = string_copy(strhelper+6);
572 else if (Ustrstr(buf, US"<summary code=\""))
574 malware_name = Ustrstr(buf, US"<summary code=\"11\">")
575 ? malware_name_internal : NULL;
587 case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
588 /* v0.1 - added support for tcp sockets */
589 /* v0.0 - initial release -- support for unix sockets */
593 unsigned int fsize_uint;
594 uschar * tmpbuf, *drweb_fbuf;
595 int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
596 drweb_vnum, drweb_slen, drweb_fin = 0x0000;
598 /* prepare variables */
599 drweb_cmd = htonl(DRWEBD_SCAN_CMD);
600 drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
602 if (*scanner_options != '/')
605 if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1)
606 return m_errlog_defer_3(scanent, NULL,
607 string_sprintf("can't open spool file %s: %s",
608 eml_filename, strerror(errno)),
611 if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
614 badseek: err = errno;
615 (void)close(drweb_fd);
616 return m_errlog_defer_3(scanent, NULL,
617 string_sprintf("can't seek spool file %s: %s",
618 eml_filename, strerror(err)),
621 fsize_uint = (unsigned int) fsize;
622 if ((off_t)fsize_uint != fsize)
624 (void)close(drweb_fd);
625 return m_errlog_defer_3(scanent, NULL,
626 string_sprintf("seeking spool file %s, size overflow",
630 drweb_slen = htonl(fsize);
631 if (lseek(drweb_fd, 0, SEEK_SET) < 0)
634 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
635 scanner_name, scanner_options);
637 /* send scan request */
638 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
639 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
640 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
641 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
643 (void)close(drweb_fd);
644 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
645 "unable to send commands to socket (%s)", scanner_options),
649 if (!(drweb_fbuf = US malloc(fsize_uint)))
651 (void)close(drweb_fd);
652 return m_errlog_defer_3(scanent, NULL,
653 string_sprintf("unable to allocate memory %u for file (%s)",
654 fsize_uint, eml_filename),
658 if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
661 (void)close(drweb_fd);
663 return m_errlog_defer_3(scanent, NULL,
664 string_sprintf("can't read spool file %s: %s",
665 eml_filename, strerror(err)),
668 (void)close(drweb_fd);
670 /* send file body to socket */
671 if (send(sock, drweb_fbuf, fsize, 0) < 0)
674 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
675 "unable to send file body to socket (%s)", scanner_options),
681 drweb_slen = htonl(Ustrlen(eml_filename));
683 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n",
684 scanner_name, scanner_options);
686 /* send scan request */
687 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
688 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
689 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
690 (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
691 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
692 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
693 "unable to send commands to socket (%s)", scanner_options),
697 /* wait for result */
698 if (!recv_len(sock, &drweb_rc, sizeof(drweb_rc), tmo))
699 return m_errlog_defer_3(scanent, CUS callout_address,
700 US"unable to read return code", sock);
701 drweb_rc = ntohl(drweb_rc);
703 if (!recv_len(sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
704 return m_errlog_defer_3(scanent, CUS callout_address,
705 US"unable to read the number of viruses", sock);
706 drweb_vnum = ntohl(drweb_vnum);
708 /* "virus(es) found" if virus number is > 0 */
713 /* setup default virus name */
714 malware_name = US"unknown";
716 /* set up match regex */
718 drweb_re = m_pcre_compile(drweb_re_str, &errstr);
720 /* read and concatenate virus names into one string */
721 for (i = 0; i < drweb_vnum; i++)
723 int size = 0, off = 0, ovector[10*3];
724 /* read the size of report */
725 if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
726 return m_errlog_defer_3(scanent, CUS callout_address,
727 US"cannot read report size", sock);
728 drweb_slen = ntohl(drweb_slen);
729 tmpbuf = store_get(drweb_slen);
731 /* read report body */
732 if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
733 return m_errlog_defer_3(scanent, CUS callout_address,
734 US"cannot read report string", sock);
735 tmpbuf[drweb_slen] = '\0';
737 /* try matcher on the line, grab substring */
738 result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
739 ovector, nelements(ovector));
742 const char * pre_malware_nb;
744 pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
746 if (i==0) /* the first name we just copy to malware_name */
747 malware_name = string_append(NULL, &size, &off,
750 else /* concatenate each new virus name to previous */
751 malware_name = string_append(malware_name, &size, &off,
752 2, "/", pre_malware_nb);
754 pcre_free_substring(pre_malware_nb);
760 const char *drweb_s = NULL;
762 if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
763 if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
764 if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
765 if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
766 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
767 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
768 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
769 * and others are ignored */
771 return m_errlog_defer_3(scanent, CUS callout_address,
772 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
781 case M_AVES: /* "aveserver" scanner type -------------------------------- */
786 /* read aveserver's greeting and see if it is ready (2xx greeting) */
788 recv_line(sock, buf, sizeof(buf), tmo);
790 if (buf[0] != '2') /* aveserver is having problems */
791 return m_errlog_defer_3(scanent, CUS callout_address,
792 string_sprintf("unavailable (Responded: %s).",
793 ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
796 /* prepare our command */
797 (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
801 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
803 if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
804 return m_errlog_defer(scanent, CUS callout_address, errstr);
808 /* read response lines, find malware name and final response */
809 while (recv_line(sock, buf, sizeof(buf), tmo) > 0)
813 if (buf[0] == '5') /* aveserver is having problems */
815 result = m_errlog_defer(scanent, CUS callout_address,
816 string_sprintf("unable to scan file %s (Responded: %s).",
820 if (Ustrncmp(buf,"322",3) == 0)
822 uschar *p = Ustrchr(&buf[4], ' ');
824 malware_name = string_copy(&buf[4]);
828 if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
829 return m_errlog_defer(scanent, CUS callout_address, errstr);
831 /* read aveserver's greeting and see if it is ready (2xx greeting) */
833 recv_line(sock, buf, sizeof(buf), tmo);
835 if (buf[0] != '2') /* aveserver is having problems */
836 return m_errlog_defer_3(scanent, CUS callout_address,
837 string_sprintf("unable to quit dialogue (Responded: %s).",
838 ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
849 case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
853 uschar av_buffer[1024];
854 static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
855 US"CONFIGURE\tTIMEOUT\t0\n",
856 US"CONFIGURE\tMAXARCH\t5\n",
857 US"CONFIGURE\tMIME\t1\n" };
861 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
862 scanner_name, scanner_options);
864 memset(av_buffer, 0, sizeof(av_buffer));
865 for (i = 0; i != nelements(cmdopt); i++)
868 if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
869 return m_errlog_defer(scanent, CUS callout_address, errstr);
871 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
872 if (bread > 0) av_buffer[bread]='\0';
874 return m_errlog_defer_3(scanent, CUS callout_address,
875 string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
877 for (j = 0; j < bread; j++)
878 if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
882 /* pass the mailfile to fsecure */
883 file_name = string_sprintf("SCAN\t%s\n", eml_filename);
885 if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
886 return m_errlog_defer(scanent, CUS callout_address, errstr);
889 /* todo also SUSPICION\t */
891 fsec_re = m_pcre_compile(fsec_re_str, &errstr);
893 /* read report, linewise. Apply a timeout as the Fsecure daemon
894 sometimes wants an answer to "PING" but they won't tell us what */
896 uschar * p = av_buffer;
902 i = av_buffer+sizeof(av_buffer)-p;
903 if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
904 return m_errlog_defer_3(scanent, CUS callout_address,
905 string_sprintf("unable to read result (%s)", strerror(errno)),
908 for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
912 /* Really search for virus again? */
914 /* try matcher on the line, grab substring */
915 malware_name = m_pcre_exec(fsec_re, p);
917 if (Ustrstr(p, "OK\tScan ok."))
921 /* copy down the trailing partial line then read another chunk */
922 i = av_buffer+sizeof(av_buffer)-p;
923 memmove(av_buffer, p, i);
932 case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
936 uschar * scanrequest;
938 unsigned long kav_reportlen;
943 /* get current date and time, build scan request */
945 /* pdp note: before the eml_filename parameter, this scanned the
946 directory; not finding documentation, so we'll strip off the directory.
947 The side-effect is that the test framework scanning may end up in
948 scanning more than was requested, but for the normal interface, this is
951 strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
952 scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
953 p = Ustrrchr(scanrequest, '/');
957 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
958 scanner_name, scanner_options);
960 /* send scan request */
961 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
962 return m_errlog_defer(scanent, CUS callout_address, errstr);
964 /* wait for result */
965 if (!recv_len(sock, tmpbuf, 2, tmo))
966 return m_errlog_defer_3(scanent, CUS callout_address,
967 US"unable to read 2 bytes from socket.", sock);
969 /* get errorcode from one nibble */
970 kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
973 case 5: case 6: /* improper kavdaemon configuration */
974 return m_errlog_defer_3(scanent, CUS callout_address,
975 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
978 return m_errlog_defer_3(scanent, CUS callout_address,
979 US"reported 'scanning not completed' (code 1).", sock);
981 return m_errlog_defer_3(scanent, CUS callout_address,
982 US"reported 'kavdaemon damaged' (code 7).", sock);
985 /* code 8 is not handled, since it is ambiguous. It appears mostly on
986 bounces where part of a file has been cut off */
988 /* "virus found" return codes (2-4) */
989 if (kav_rc > 1 && kav_rc < 5)
993 /* setup default virus name */
994 malware_name = US"unknown";
996 report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
998 /* read the report, if available */
999 if (report_flag == 1)
1001 /* read report size */
1002 if (!recv_len(sock, &kav_reportlen, 4, tmo))
1003 return m_errlog_defer_3(scanent, CUS callout_address,
1004 US"cannot read report size", sock);
1006 /* it's possible that avp returns av_buffer[1] == 1 but the
1007 reportsize is 0 (!?) */
1008 if (kav_reportlen > 0)
1010 /* set up match regex, depends on retcode */
1013 if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1014 kav_re = kav_re_sus;
1018 if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1019 kav_re = kav_re_inf;
1022 /* read report, linewise. Using size from stream to read amount of data
1023 from same stream is safe enough. */
1024 /* coverity[tainted_data] */
1025 while (kav_reportlen > 0)
1027 if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1029 kav_reportlen -= bread+1;
1031 /* try matcher on the line, grab substring */
1032 if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1038 else /* no virus found */
1039 malware_name = NULL;
1044 case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1046 const uschar *cmdline_scanner = scanner_options;
1047 const pcre *cmdline_trigger_re;
1048 const pcre *cmdline_regex_re;
1050 uschar * commandline;
1051 void (*eximsigchld)(int);
1052 void (*eximsigpipe)(int);
1053 FILE *scanner_out = NULL;
1055 FILE *scanner_record = NULL;
1056 uschar linebuffer[32767];
1061 if (!cmdline_scanner)
1062 return m_errlog_defer(scanent, NULL, errstr);
1064 /* find scanner output trigger */
1065 cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1066 "missing trigger specification", &errstr);
1067 if (!cmdline_trigger_re)
1068 return m_errlog_defer(scanent, NULL, errstr);
1070 /* find scanner name regex */
1071 cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1072 "missing virus name regex specification", &errstr);
1073 if (!cmdline_regex_re)
1074 return m_errlog_defer(scanent, NULL, errstr);
1076 /* prepare scanner call; despite the naming, file_name holds a directory
1077 name which is documented as the value given to %s. */
1079 file_name = string_copy(eml_filename);
1080 p = Ustrrchr(file_name, '/');
1083 commandline = string_sprintf(CS cmdline_scanner, file_name);
1085 /* redirect STDERR too */
1086 commandline = string_sprintf("%s 2>&1", commandline);
1088 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1089 scanner_name, commandline);
1091 /* store exims signal handlers */
1092 eximsigchld = signal(SIGCHLD,SIG_DFL);
1093 eximsigpipe = signal(SIGPIPE,SIG_DFL);
1095 if (!(scanner_out = popen(CS commandline,"r")))
1098 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1099 return m_errlog_defer(scanent, NULL,
1100 string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1102 scanner_fd = fileno(scanner_out);
1104 file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
1106 if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1109 (void) pclose(scanner_out);
1110 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1111 return m_errlog_defer(scanent, NULL, string_sprintf(
1112 "opening scanner output file (%s) failed: %s.",
1113 file_name, strerror(err)));
1116 /* look for trigger while recording output */
1117 while ((rcnt = recv_line(scanner_fd, linebuffer,
1118 sizeof(linebuffer), tmo)))
1125 (void) pclose(scanner_out);
1126 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1127 return m_errlog_defer(scanent, NULL, string_sprintf(
1128 "unable to read from scanner (%s): %s",
1129 commandline, strerror(err)));
1132 if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1135 (void) pclose(scanner_out);
1136 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1137 return m_errlog_defer(scanent, NULL, string_sprintf(
1138 "short write on scanner output file (%s).", file_name));
1140 putc('\n', scanner_record);
1141 /* try trigger match */
1143 && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1148 (void)fclose(scanner_record);
1149 sep = pclose(scanner_out);
1150 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1152 return m_errlog_defer(scanent, NULL,
1154 ? string_sprintf("running scanner failed: %s", strerror(sep))
1155 : string_sprintf("scanner returned error code: %d", sep));
1160 /* setup default virus name */
1161 malware_name = US"unknown";
1163 /* re-open the scanner output file, look for name match */
1164 scanner_record = fopen(CS file_name, "rb");
1165 while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1168 if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1171 (void)fclose(scanner_record);
1173 else /* no virus found */
1174 malware_name = NULL;
1178 case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1183 uschar av_buffer[1024];
1185 /* pass the scan directory to sophie */
1186 file_name = string_copy(eml_filename);
1187 if ((p = Ustrrchr(file_name, '/')))
1190 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1191 scanner_name, scanner_options);
1193 if ( write(sock, file_name, Ustrlen(file_name)) < 0
1194 || write(sock, "\n", 1) != 1
1196 return m_errlog_defer_3(scanent, CUS callout_address,
1197 string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1200 /* wait for result */
1201 memset(av_buffer, 0, sizeof(av_buffer));
1202 if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1203 return m_errlog_defer_3(scanent, CUS callout_address,
1204 string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1208 if (av_buffer[0] == '1') {
1209 uschar * s = Ustrchr(av_buffer, '\n');
1212 malware_name = string_copy(&av_buffer[2]);
1214 else if (!strncmp(CS av_buffer, "-1", 2))
1215 return m_errlog_defer_3(scanent, CUS callout_address,
1216 US"scanner reported error", sock);
1217 else /* all ok, no virus */
1218 malware_name = NULL;
1223 case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1225 /* This code was originally contributed by David Saez */
1226 /* There are three scanning methods available to us:
1227 * (1) Use the SCAN command, pointing to a file in the filesystem
1228 * (2) Use the STREAM command, send the data on a separate port
1229 * (3) Use the zINSTREAM command, send the data inline
1230 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1231 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1232 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1233 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless
1234 * WITH_OLD_CLAMAV_STREAM is defined.
1235 * See Exim bug 926 for details. */
1237 uschar *p, *vname, *result_tag;
1240 uschar av_buffer[1024];
1241 uschar *hostname = US"";
1243 uschar *clamav_fbuf;
1244 int clam_fd, result;
1246 unsigned int fsize_uint;
1247 BOOL use_scan_command = FALSE;
1248 clamd_address * cv[MAX_CLAMD_SERVERS];
1249 int num_servers = 0;
1250 #ifdef WITH_OLD_CLAMAV_STREAM
1252 uschar av_buffer2[1024];
1255 uint32_t send_size, send_final_zeroblock;
1258 /*XXX if unixdomain socket, only one server supported. Needs fixing;
1259 there's no reason we should not mix local and remote servers */
1261 if (*scanner_options == '/')
1264 const uschar * sublist;
1267 /* Local file; so we def want to use_scan_command and don't want to try
1268 * passing IP/port combinations */
1269 use_scan_command = TRUE;
1270 cd = (clamd_address *) store_get(sizeof(clamd_address));
1272 /* extract socket-path part */
1273 sublist = scanner_options;
1274 cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1277 if (clamd_option(cd, sublist, &subsep) != OK)
1278 return m_errlog_defer(scanent, NULL,
1279 string_sprintf("bad option '%s'", scanner_options));
1284 /* Go through the rest of the list of host/port and construct an array
1285 * of servers to try. The first one is the bit we just passed from
1286 * scanner_options so process that first and then scan the remainder of
1287 * the address buffer */
1291 const uschar * sublist;
1295 /* The 'local' option means use the SCAN command over the network
1296 * socket (ie common file storage in use) */
1297 /*XXX we could accept this also as a local option? */
1298 if (strcmpic(scanner_options, US"local") == 0)
1300 use_scan_command = TRUE;
1304 cd = (clamd_address *) store_get(sizeof(clamd_address));
1306 /* extract host and port part */
1307 sublist = scanner_options;
1308 if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1310 (void) m_errlog_defer(scanent, NULL,
1311 string_sprintf("missing address: '%s'", scanner_options));
1314 if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1316 (void) m_errlog_defer(scanent, NULL,
1317 string_sprintf("missing port: '%s'", scanner_options));
1320 cd->tcp_port = atoi(CS s);
1323 /*XXX should these options be common over scanner types? */
1324 if (clamd_option(cd, sublist, &subsep) != OK)
1325 return m_errlog_defer(scanent, NULL,
1326 string_sprintf("bad option '%s'", scanner_options));
1328 cv[num_servers++] = cd;
1329 if (num_servers >= MAX_CLAMD_SERVERS)
1331 (void) m_errlog_defer(scanent, NULL,
1332 US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1333 "specified; only using the first " MAX_CLAMD_SERVERS_S );
1336 } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1339 /* check if we have at least one server */
1341 return m_errlog_defer(scanent, NULL,
1342 US"no useable server addresses in malware configuration option.");
1345 /* See the discussion of response formats below to see why we really
1346 don't like colons in filenames when passing filenames to ClamAV. */
1347 if (use_scan_command && Ustrchr(eml_filename, ':'))
1348 return m_errlog_defer(scanent, NULL,
1349 string_sprintf("local/SCAN mode incompatible with" \
1350 " : in path to email filename [%s]", eml_filename));
1352 /* We have some network servers specified */
1355 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1356 * only supports AF_INET, but we should probably be looking to the
1357 * future and rewriting this to be protocol-independent anyway. */
1359 while (num_servers > 0)
1361 int i = random_number( num_servers );
1362 clamd_address * cd = cv[i];
1364 DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1365 cd->hostspec, cd->tcp_port);
1367 /* Lookup the host. This is to ensure that we connect to the same IP
1368 * on both connections (as one host could resolve to multiple ips) */
1371 sock= m_tcpsocket(cd->hostspec, cd->tcp_port, &connhost, &errstr);
1374 /* Connection successfully established with a server */
1375 hostname = cd->hostspec;
1378 if (cd->retry <= 0) break;
1379 while (cd->retry > 0) cd->retry = sleep(cd->retry);
1384 (void) m_errlog_defer(scanent, CUS callout_address, errstr);
1386 /* Remove the server from the list. XXX We should free the memory */
1388 for (; i < num_servers; i++)
1392 if (num_servers == 0)
1393 return m_errlog_defer(scanent, NULL, US"all servers failed");
1398 if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1400 hostname = cv[0]->hostspec;
1403 if (cv[0]->retry <= 0)
1404 return m_errlog_defer(scanent, CUS callout_address, errstr);
1405 while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1408 /* have socket in variable "sock"; command to use is semi-independent of
1409 * the socket protocol. We use SCAN if is local (either Unix/local
1410 * domain socket, or explicitly told local) else we stream the data.
1411 * How we stream the data depends upon how we were built. */
1413 if (!use_scan_command)
1415 #ifdef WITH_OLD_CLAMAV_STREAM
1416 /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1417 * that port on a second connection; then in the scan-method-neutral
1418 * part, read the response back on the original connection. */
1420 DEBUG(D_acl) debug_printf_indent(
1421 "Malware scan: issuing %s old-style remote scan (PORT)\n",
1424 /* Pass the string to ClamAV (7 = "STREAM\n") */
1425 if (m_sock_send(sock, US"STREAM\n", 7, &errstr) < 0)
1426 return m_errlog_defer(scanent, CUS callout_address, errstr);
1428 memset(av_buffer2, 0, sizeof(av_buffer2));
1429 bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
1432 return m_errlog_defer_3(scanent, CUS callout_address,
1433 string_sprintf("unable to read PORT from socket (%s)",
1437 if (bread == sizeof(av_buffer2))
1438 return m_errlog_defer_3(scanent, CUS callout_address,
1439 "buffer too small", sock);
1442 return m_errlog_defer_3(scanent, CUS callout_address,
1443 "ClamAV returned null", sock);
1445 av_buffer2[bread] = '\0';
1446 if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 )
1447 return m_errlog_defer_3(scanent, CUS callout_address,
1448 string_sprintf("Expected port information from clamd, got '%s'",
1452 sockData = m_tcpsocket(connhost.address, port, NULL, &errstr);
1454 return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock);
1456 # define CLOSE_SOCKDATA (void)close(sockData)
1457 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1458 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1459 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1462 DEBUG(D_acl) debug_printf_indent(
1463 "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1466 /* Pass the string to ClamAV (10 = "zINSTREAM\0") */
1467 if (send(sock, "zINSTREAM", 10, 0) < 0)
1468 return m_errlog_defer_3(scanent, CUS hostname,
1469 string_sprintf("unable to send zINSTREAM to socket (%s)",
1473 # define CLOSE_SOCKDATA /**/
1476 /* calc file size */
1477 if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1481 return m_errlog_defer_3(scanent, NULL,
1482 string_sprintf("can't open spool file %s: %s",
1483 eml_filename, strerror(err)),
1486 if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1489 b_seek: err = errno;
1490 CLOSE_SOCKDATA; (void)close(clam_fd);
1491 return m_errlog_defer_3(scanent, NULL,
1492 string_sprintf("can't seek spool file %s: %s",
1493 eml_filename, strerror(err)),
1496 fsize_uint = (unsigned int) fsize;
1497 if ((off_t)fsize_uint != fsize)
1499 CLOSE_SOCKDATA; (void)close(clam_fd);
1500 return m_errlog_defer_3(scanent, NULL,
1501 string_sprintf("seeking spool file %s, size overflow",
1505 if (lseek(clam_fd, 0, SEEK_SET) < 0)
1508 if (!(clamav_fbuf = US malloc(fsize_uint)))
1510 CLOSE_SOCKDATA; (void)close(clam_fd);
1511 return m_errlog_defer_3(scanent, NULL,
1512 string_sprintf("unable to allocate memory %u for file (%s)",
1513 fsize_uint, eml_filename),
1517 if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1520 free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd);
1521 return m_errlog_defer_3(scanent, NULL,
1522 string_sprintf("can't read spool file %s: %s",
1523 eml_filename, strerror(err)),
1526 (void)close(clam_fd);
1528 /* send file body to socket */
1529 #ifdef WITH_OLD_CLAMAV_STREAM
1530 if (send(sockData, clamav_fbuf, fsize_uint, 0) < 0)
1532 free(clamav_fbuf); CLOSE_SOCKDATA;
1533 return m_errlog_defer_3(scanent, NULL,
1534 string_sprintf("unable to send file body to socket (%s:%u)",
1539 send_size = htonl(fsize_uint);
1540 send_final_zeroblock = 0;
1541 if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1542 (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1543 (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1546 return m_errlog_defer_3(scanent, NULL,
1547 string_sprintf("unable to send file body to socket (%s)", hostname),
1555 #undef CLOSE_SOCKDATA
1558 { /* use scan command */
1559 /* Send a SCAN command pointing to a filename; then in the then in the
1560 * scan-method-neutral part, read the response back */
1562 /* ================================================================= */
1564 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1565 which dates to when ClamAV needed us to break apart the email into the
1566 MIME parts (eg, with the now deprecated demime condition coming first).
1567 Some time back, ClamAV gained the ability to deconstruct the emails, so
1568 doing this would actually have resulted in the mail attachments being
1569 scanned twice, in the broken out files and from the original .eml.
1570 Since ClamAV now handles emails (and has for quite some time) we can
1571 just use the email file itself. */
1572 /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
1573 file_name = string_sprintf("SCAN %s\n", eml_filename);
1575 DEBUG(D_acl) debug_printf_indent(
1576 "Malware scan: issuing %s local-path scan [%s]\n",
1577 scanner_name, scanner_options);
1579 if (send(sock, file_name, Ustrlen(file_name), 0) < 0)
1580 return m_errlog_defer_3(scanent, CUS callout_address,
1581 string_sprintf("unable to write to socket (%s)", strerror(errno)),
1584 /* Do not shut down the socket for writing; a user report noted that
1585 * clamd 0.70 does not react well to this. */
1587 /* Commands have been sent, no matter which scan method or connection
1588 * type we're using; now just read the result, independent of method. */
1590 /* Read the result */
1591 memset(av_buffer, 0, sizeof(av_buffer));
1592 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1597 return m_errlog_defer(scanent, CUS callout_address,
1598 string_sprintf("unable to read from socket (%s)",
1599 errno == 0 ? "EOF" : strerror(errno)));
1601 if (bread == sizeof(av_buffer))
1602 return m_errlog_defer(scanent, CUS callout_address,
1603 US"buffer too small");
1604 /* We're now assured of a NULL at the end of av_buffer */
1606 /* Check the result. ClamAV returns one of two result formats.
1607 In the basic mode, the response is of the form:
1608 infected: -> "<filename>: <virusname> FOUND"
1609 not-infected: -> "<filename>: OK"
1610 error: -> "<filename>: <errcode> ERROR
1611 If the ExtendedDetectionInfo option has been turned on, then we get:
1612 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1613 for the infected case. Compare:
1614 /tmp/eicar.com: Eicar-Test-Signature FOUND
1615 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1617 In the streaming case, clamd uses the filename "stream" which you should
1618 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1619 client app will replace "stream" with the original filename before returning
1620 results to stdout, but the trace shows the data).
1622 We will assume that the pathname passed to clamd from Exim does not contain
1623 a colon. We will have whined loudly above if the eml_filename does (and we're
1624 passing a filename to clamd). */
1627 return m_errlog_defer(scanent, CUS callout_address,
1628 US"ClamAV returned null");
1630 /* strip newline at the end (won't be present for zINSTREAM)
1631 (also any trailing whitespace, which shouldn't exist, but we depend upon
1632 this below, so double-check) */
1633 p = av_buffer + Ustrlen(av_buffer) - 1;
1634 if (*p == '\n') *p = '\0';
1636 DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1638 while (isspace(*--p) && (p > av_buffer))
1642 /* colon in returned output? */
1643 if(!(p = Ustrchr(av_buffer,':')))
1644 return m_errlog_defer(scanent, CUS callout_address, string_sprintf(
1645 "ClamAV returned malformed result (missing colon): %s",
1648 /* strip filename */
1649 while (*p && isspace(*++p)) /**/;
1652 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1653 but we should at least be resistant to it. */
1654 p = Ustrrchr(vname, ' ');
1655 result_tag = p ? p+1 : vname;
1657 if (Ustrcmp(result_tag, "FOUND") == 0)
1659 /* p should still be the whitespace before the result_tag */
1660 while (isspace(*p)) --p;
1662 /* Strip off the extended information too, which will be in parens
1663 after the virus name, with no intervening whitespace. */
1666 /* "(hash:size)", so previous '(' will do; if not found, we have
1667 a curious virus name, but not an error. */
1668 p = Ustrrchr(vname, '(');
1672 malware_name = string_copy(vname);
1673 DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1676 else if (Ustrcmp(result_tag, "ERROR") == 0)
1677 return m_errlog_defer(scanent, CUS callout_address,
1678 string_sprintf("ClamAV returned: %s", av_buffer));
1680 else if (Ustrcmp(result_tag, "OK") == 0)
1682 /* Everything should be OK */
1683 malware_name = NULL;
1684 DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1688 return m_errlog_defer(scanent, CUS callout_address,
1689 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1694 case M_SOCK: /* "sock" scanner type ------------------------------------- */
1695 /* This code was derived by Martin Poole from the clamd code contributed
1696 by David Saez and the cmdline code
1700 uschar * commandline;
1701 uschar av_buffer[1024];
1702 uschar * linebuffer;
1703 uschar * sockline_scanner;
1704 uschar sockline_scanner_default[] = "%s\n";
1705 const pcre *sockline_trig_re;
1706 const pcre *sockline_name_re;
1708 /* find scanner command line */
1709 if ( (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1711 && *sockline_scanner
1713 { /* check for no expansions apart from one %s */
1714 uschar * s = Ustrchr(sockline_scanner, '%');
1716 if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1717 return m_errlog_defer_3(scanent, NULL,
1718 US"unsafe sock scanner call spec", sock);
1721 sockline_scanner = sockline_scanner_default;
1722 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1723 string_printing(sockline_scanner));
1725 /* find scanner output trigger */
1726 sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1727 "missing trigger specification", &errstr);
1728 if (!sockline_trig_re)
1729 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1731 /* find virus name regex */
1732 sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1733 "missing virus name regex specification", &errstr);
1734 if (!sockline_name_re)
1735 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1737 /* prepare scanner call - security depends on expansions check above */
1738 commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1739 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1740 string_printing(commandline));
1742 /* Pass the command string to the socket */
1743 if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1744 return m_errlog_defer(scanent, CUS callout_address, errstr);
1746 /* Read the result */
1747 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1750 return m_errlog_defer_3(scanent, CUS callout_address,
1751 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1754 if (bread == sizeof(av_buffer))
1755 return m_errlog_defer_3(scanent, CUS callout_address,
1756 US"buffer too small", sock);
1757 av_buffer[bread] = '\0';
1758 linebuffer = string_copy(av_buffer);
1759 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1760 string_printing(linebuffer));
1762 /* try trigger match */
1763 if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1765 if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1766 malware_name = US "unknown";
1767 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1768 string_printing(malware_name));
1770 else /* no virus found */
1771 malware_name = NULL;
1775 case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1777 char *mksd_options_end;
1778 int mksd_maxproc = 1; /* default, if no option supplied */
1781 if (scanner_options)
1783 mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1784 if ( *scanner_options == '\0'
1785 || *mksd_options_end != '\0'
1787 || mksd_maxproc > 32
1789 return m_errlog_defer(scanent, CUS callout_address,
1790 string_sprintf("invalid option '%s'", scanner_options));
1793 if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1794 return m_errlog_defer(scanent, CUS callout_address, errstr);
1796 malware_name = NULL;
1798 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1800 if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1808 case M_AVAST: /* "avast" scanner type ----------------------------------- */
1812 uschar * scanrequest;
1813 enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1816 /* According to Martin Tuma @avast the protocol uses "escaped
1817 whitespace", that is, every embedded whitespace is backslash
1818 escaped, as well as backslash is protected by backslash.
1819 The returned lines contain the name of the scanned file, a tab
1823 [E] - some error occured
1824 Such marker follows the first non-escaped TAB. */
1825 if ( ( !ava_re_clean
1826 && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1828 && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1830 return malware_errlog_defer(errstr);
1832 /* wait for result */
1833 for (avast_stage = AVA_HELO;
1834 (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1837 int slen = Ustrlen(buf);
1840 DEBUG(D_acl) debug_printf_indent("got from avast: %s\n", buf);
1841 switch (avast_stage)
1844 if (Ustrncmp(buf, "220", 3) != 0)
1845 goto endloop; /* require a 220 */
1849 if (Ustrncmp(buf, "210", 3) == 0)
1850 break; /* ignore 210 responses */
1851 if (Ustrncmp(buf, "200", 3) != 0)
1852 goto endloop; /* require a 200 */
1857 /* Check for another option to send. Newline-terminate it. */
1858 if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1861 scanrequest = string_sprintf("%s\n", scanrequest);
1862 avast_stage = AVA_OPT; /* just sent option */
1866 scanrequest = string_sprintf("SCAN %s\n", eml_dir);
1867 avast_stage = AVA_RSP; /* just sent command */
1870 /* send config-cmd or scan-request to socket */
1871 len = Ustrlen(scanrequest);
1872 if (send(sock, scanrequest, len, 0) < 0)
1874 scanrequest[len-1] = '\0';
1875 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
1876 "unable to send request '%s' to socket (%s): %s",
1877 scanrequest, scanner_options, strerror(errno)), sock);
1883 if (Ustrncmp(buf, "210", 3) == 0)
1884 break; /* ignore the "210 SCAN DATA" message */
1886 if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
1887 0, 0, ovector, nelements(ovector)) > 0)
1890 if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
1891 { /* remove backslash in front of [whitespace|backslash] */
1893 for (p = malware_name; *p; ++p)
1894 if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
1895 for (p0 = p; *p0; ++p0) *p0 = p0[1];
1897 avast_stage = AVA_DONE;
1901 if (Ustrncmp(buf, "200 SCAN OK", 11) == 0)
1902 { /* we're done finally */
1903 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1904 return m_errlog_defer_3(scanent, CUS callout_address,
1906 "unable to send quit request to socket (%s): %s",
1907 scanner_options, strerror(errno)),
1909 malware_name = NULL;
1910 avast_stage = AVA_DONE;
1914 /* here for any unexpected response from the scanner */
1917 case AVA_DONE: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
1918 __FILE__, __LINE__, __FUNCTION__);
1928 case AVA_RSP: return m_errlog_defer_3(scanent, CUS callout_address,
1931 "invalid response from scanner: '%s'", buf)
1933 ? US"EOF from scanner"
1934 : US"timeout from scanner",
1941 case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
1945 uschar * linebuffer;
1946 uschar * scanrequest;
1947 uschar av_buffer[1024];
1949 if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
1950 || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
1951 return malware_errlog_defer(errstr);
1953 scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
1954 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
1955 scanner_name, scanrequest);
1957 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
1958 return m_errlog_defer(scanent, CUS callout_address, errstr);
1960 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1963 return m_errlog_defer_3(scanent, CUS callout_address,
1964 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1967 if (bread == sizeof(av_buffer))
1968 return m_errlog_defer_3(scanent, CUS callout_address,
1969 US"buffer too small", sock);
1971 av_buffer[bread] = '\0';
1972 linebuffer = string_copy(av_buffer);
1974 m_sock_send(sock, US"QUIT\n", 5, 0);
1976 if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
1977 return m_errlog_defer_3(scanent, CUS callout_address,
1978 string_sprintf("scanner reported error (%s)", e), sock);
1980 if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
1981 malware_name = NULL;
1985 } /* scanner type switch */
1988 (void) close (sock);
1989 malware_ok = TRUE; /* set "been here, done that" marker */
1992 /* match virus name against pattern (caseless ------->----------v) */
1993 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
1995 DEBUG(D_acl) debug_printf_indent(
1996 "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2004 /*************************************************
2005 * Scan an email for malware *
2006 *************************************************/
2008 /* This is the normal interface for scanning an email, which doesn't need a
2009 filename; it's a wrapper around the malware_file function.
2012 malware_re match condition for "malware="
2013 timeout if nonzero, timeout in seconds
2015 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2016 where true means malware was found (condition applies)
2019 malware(const uschar * malware_re, int timeout)
2021 int ret = malware_internal(malware_re, NULL, timeout);
2023 if (ret == DEFER) av_failed = TRUE;
2028 /*************************************************
2029 * Scan a file for malware *
2030 *************************************************/
2032 /* This is a test wrapper for scanning an email, which is not used in
2033 normal processing. Scan any file, using the Exim scanning interface.
2034 This function tampers with various global variables so is unsafe to use
2035 in any other context.
2038 eml_filename a file holding the message to be scanned
2040 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2041 where true means malware was found (condition applies)
2044 malware_in_file(uschar *eml_filename)
2046 uschar message_id_buf[64];
2049 /* spool_mbox() assumes various parameters exist, when creating
2050 the relevant directory and the email within */
2052 (void) string_format(message_id_buf, sizeof(message_id_buf),
2053 "dummy-%d", vaguely_random_number(INT_MAX));
2054 message_id = message_id_buf;
2055 sender_address = US"malware-sender@example.net";
2057 recipients_list = NULL;
2058 receive_add_recipient(US"malware-victim@example.net", -1);
2059 enable_dollar_recipients = TRUE;
2061 ret = malware_internal(US"*", eml_filename, 0);
2063 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2066 /* don't set no_mbox_unspool; at present, there's no way for it to become
2067 set, but if that changes, then it should apply to these tests too */
2071 /* silence static analysis tools */
2081 if (!malware_default_re)
2082 malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2084 drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2086 fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2088 kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2090 kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2092 ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2094 ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2095 if (!fprot6d_re_error)
2096 fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2097 if (!fprot6d_re_virus)
2098 fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2101 #endif /*WITH_CONTENT_SCAN*/