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} 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 { -1, NULL, NULL, MC_NONE } /* end-marker */
40 /* The maximum number of clamd servers that are supported in the configuration */
41 #define MAX_CLAMD_SERVERS 32
42 #define MAX_CLAMD_SERVERS_S "32"
44 typedef struct clamd_address {
51 # define nelements(arr) (sizeof(arr) / sizeof(arr[0]))
55 #define MALWARE_TIMEOUT 120 /* default timeout, seconds */
58 #define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */
59 #define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */
60 #define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */
62 #define DERR_READ_ERR (1<<0) /* read error */
63 #define DERR_NOMEMORY (1<<2) /* no memory */
64 #define DERR_TIMEOUT (1<<9) /* scan timeout has run out */
65 #define DERR_BAD_CALL (1<<15) /* wrong command */
68 static const uschar * malware_regex_default = US ".+";
69 static const pcre * malware_default_re = NULL;
71 static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$";
72 static const pcre * drweb_re = NULL;
74 static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$";
75 static const pcre * fsec_re = NULL;
77 static const uschar * kav_re_sus_str = US "suspicion:\\s*(.+?)\\s*$";
78 static const uschar * kav_re_inf_str = US "infected:\\s*(.+?)\\s*$";
79 static const pcre * kav_re_sus = NULL;
80 static const pcre * kav_re_inf = NULL;
82 static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]";
83 static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d\\.\\d\\t\\d\\s(.*)";
84 static const pcre * ava_re_clean = NULL;
85 static const pcre * ava_re_virus = NULL;
89 /******************************************************************************/
91 /* Routine to check whether a system is big- or little-endian.
92 Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
93 Needed for proper kavdaemon implementation. Sigh. */
94 #define BIG_MY_ENDIAN 0
95 #define LITTLE_MY_ENDIAN 1
96 static int test_byte_order(void);
100 short int word = 0x0001;
101 char *byte = (char *) &word;
102 return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
105 BOOL malware_ok = FALSE;
107 /* Gross hacks for the -bmalware option; perhaps we should just create
108 the scan directory normally for that case, but look into rigging up the
109 needed header variables if not already set on the command-line? */
110 extern int spool_mbox_ok;
111 extern uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
116 malware_errlog_defer(const uschar * str)
118 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
123 m_errlog_defer(struct scan * scanent, const uschar * hostport,
126 return malware_errlog_defer(string_sprintf("%s %s : %s",
127 scanent->name, hostport ? hostport : CUS"", str));
130 m_errlog_defer_3(struct scan * scanent, const uschar * hostport,
131 const uschar * str, int fd_to_close)
133 (void) close(fd_to_close);
134 return m_errlog_defer(scanent, hostport, str);
137 /*************************************************/
139 /* Only used by the Clamav code, which is working from a list of servers and
140 uses the returned in_addr to get a second connection to the same system.
143 m_tcpsocket(const uschar * hostname, unsigned int port,
144 host_item * host, uschar ** errstr)
146 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5, host, errstr);
150 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
152 if (send(sock, buf, cnt, 0) < 0)
156 *errstr = string_sprintf("unable to send to socket (%s): %s",
164 m_pcre_compile(const uschar * re, uschar ** errstr)
166 const uschar * rerror;
170 cre = pcre_compile(CS re, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
172 *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
173 re, rerror, roffset);
178 m_pcre_exec(const pcre * cre, uschar * text)
181 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
182 ovector, nelements(ovector));
183 uschar * substr = NULL;
184 if (i >= 2) /* Got it */
185 pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr);
190 m_pcre_nextinlist(const uschar ** list, int * sep,
191 char * listerr, uschar ** errstr)
193 const uschar * list_ele;
194 const pcre * cre = NULL;
196 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
197 *errstr = US listerr;
199 cre = m_pcre_compile(CUS list_ele, errstr);
204 Simple though inefficient wrapper for reading a line. Drop CRs and the
205 trailing newline. Can return early on buffer full. Null-terminate.
206 Apply initial timeout if no data ready.
208 Return: number of chars - zero for an empty line
210 -2 on timeout or error
213 recv_line(int fd, uschar * buffer, int bsize, int tmo)
219 if (!fd_ready(fd, tmo-time(NULL)))
222 /*XXX tmo handling assumes we always get a whole line */
225 while ((rcv = read(fd, p, 1)) > 0)
228 if (p-buffer > bsize-2) break;
229 if (*p == '\n') break;
234 DEBUG(D_acl) debug_printf("Malware scan: read %s (%s)\n",
235 rcv==0 ? "EOF" : "error", strerror(errno));
236 return rcv==0 ? -1 : -2;
240 DEBUG(D_acl) debug_printf("Malware scan: read '%s'\n", buffer);
244 /* return TRUE iff size as requested */
246 recv_len(int sock, void * buf, int size, int tmo)
248 return fd_ready(sock, tmo-time(NULL))
249 ? recv(sock, buf, size, 0) == size
255 /* ============= private routines for the "mksd" scanner type ============== */
260 mksd_writev (int sock, struct iovec * iov, int iovcnt)
267 i = writev (sock, iov, iovcnt);
268 while (i < 0 && errno == EINTR);
271 (void) malware_errlog_defer(
272 US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
275 for (;;) /* check for short write */
276 if (i >= iov->iov_len)
286 iov->iov_base = CS iov->iov_base + i;
293 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, int tmo)
300 i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL));
303 (void) malware_errlog_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
308 /* offset == av_buffer_size -> buffer full */
309 if (offset == av_buffer_size)
311 (void) malware_errlog_defer(US"malformed reply received from mksd");
314 } while (av_buffer[offset-1] != '\n');
316 av_buffer[offset] = '\0';
321 mksd_parse_line(struct scan * scanent, char * line)
332 if ((p = strchr (line, '\n')) != NULL)
334 return m_errlog_defer(scanent, NULL,
335 string_sprintf("scanner failed: %s", line));
338 if ((p = strchr (line, '\n')) != NULL)
343 && (p = strchr(line+4, ' ')) != NULL
348 malware_name = string_copy(US line+4);
352 return m_errlog_defer(scanent, NULL,
353 string_sprintf("malformed reply received: %s", line));
358 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
362 const char *cmd = "MSQ\n";
363 uschar av_buffer[1024];
365 iov[0].iov_base = (void *) cmd;
367 iov[1].iov_base = (void *) scan_filename;
368 iov[1].iov_len = Ustrlen(scan_filename);
369 iov[2].iov_base = (void *) (cmd + 3);
372 if (mksd_writev (sock, iov, 3) < 0)
375 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
378 return mksd_parse_line (scanent, CS av_buffer);
383 clamd_option(clamd_address * cd, const uschar * optstr, int * subsep)
388 while ((s = string_nextinlist(&optstr, subsep, NULL, 0)))
389 if (Ustrncmp(s, "retry=", 6) == 0)
391 int sec = readconf_readtime((s += 6), '\0', FALSE);
401 /*************************************************
402 * Scan content for malware *
403 *************************************************/
405 /* This is an internal interface for scanning an email; the normal interface
406 is via malware(), or there's malware_in_file() used for testing/debugging.
409 malware_re match condition for "malware="
410 eml_filename the file holding the email to be scanned
411 timeout if nonzero, non-default timeoutl
412 faking whether or not we're faking this up for the -bmalware test
414 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
415 where true means malware was found (condition applies)
418 malware_internal(const uschar * malware_re, const uschar * eml_filename,
419 int timeout, BOOL faking)
422 const uschar *av_scanner_work = av_scanner;
423 uschar *scanner_name;
424 unsigned long mbox_size;
428 struct scan * scanent;
429 const uschar * scanner_options;
433 /* make sure the eml mbox file is spooled up */
434 if (!(mbox_file = spool_mbox(&mbox_size, faking ? eml_filename : NULL)))
435 return malware_errlog_defer(US"error while creating mbox spool file");
437 /* none of our current scanners need the mbox
438 file as a stream, so we can close it right away */
439 (void)fclose(mbox_file);
442 return FAIL; /* empty means "don't match anything" */
444 /* parse 1st option */
445 if ( (strcmpic(malware_re, US"false") == 0) ||
446 (Ustrcmp(malware_re,"0") == 0) )
447 return FAIL; /* explicitly no matching */
449 /* special cases (match anything except empty) */
450 if ( strcmpic(malware_re,US"true") == 0
451 || Ustrcmp(malware_re,"*") == 0
452 || Ustrcmp(malware_re,"1") == 0
455 if ( !malware_default_re
456 && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
457 return malware_errlog_defer(errstr);
458 malware_re = malware_regex_default;
459 re = malware_default_re;
462 /* compile the regex, see if it works */
463 else if (!(re = m_pcre_compile(malware_re, &errstr)))
464 return malware_errlog_defer(errstr);
466 /* Reset sep that is set by previous string_nextinlist() call */
469 /* if av_scanner starts with a dollar, expand it first */
470 if (*av_scanner == '$')
472 if (!(av_scanner_work = expand_string(av_scanner)))
473 return malware_errlog_defer(
474 string_sprintf("av_scanner starts with $, but expansion failed: %s",
475 expand_string_message));
478 debug_printf("Expanded av_scanner global: %s\n", av_scanner_work);
479 /* disable result caching in this case */
484 /* Do not scan twice (unless av_scanner is dynamic). */
487 /* find the scanner type from the av_scanner option */
488 if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
489 return malware_errlog_defer(US"av_scanner configuration variable is empty");
490 if (!timeout) timeout = MALWARE_TIMEOUT;
491 tmo = time(NULL) + timeout;
493 for (scanent = m_scans; ; scanent++)
496 return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
498 if (strcmpic(scanner_name, US scanent->name) != 0)
500 if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
501 scanner_options = scanent->options_default;
502 if (scanent->conn == MC_NONE)
504 switch(scanent->conn)
506 case MC_TCP: sock = ip_tcpsocket(scanner_options, &errstr, 5); break;
507 case MC_UNIX: sock = ip_unixsocket(scanner_options, &errstr); break;
508 case MC_STRM: sock = ip_streamsocket(scanner_options, &errstr, 5); break;
509 default: /* compiler quietening */ break;
512 return m_errlog_defer(scanent, CUS callout_address, errstr);
515 DEBUG(D_acl) debug_printf("Malware scan: %s tmo %s\n", scanner_name, readconf_printtime(timeout));
517 switch (scanent->scancode)
519 case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
521 uschar *fp_scan_option;
522 unsigned int detected=0, par_count=0;
523 uschar * scanrequest;
524 uschar buf[32768], *strhelper, *strhelper2;
525 uschar * malware_name_internal = NULL;
528 scanrequest = string_sprintf("GET %s", eml_filename);
530 while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
533 scanrequest = string_sprintf("%s%s%s", scanrequest,
534 par_count ? "%20" : "?", fp_scan_option);
537 scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
538 DEBUG(D_acl) debug_printf("Malware scan: issuing %s: %s\n",
539 scanner_name, scanrequest);
541 /* send scan request */
542 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
543 return m_errlog_defer(scanent, CUS callout_address, errstr);
545 while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0)
548 if (Ustrstr(buf, US"<detected type=\"") != NULL)
550 else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
552 if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
555 malware_name_internal = string_copy(strhelper+6);
558 else if (Ustrstr(buf, US"<summary code=\""))
560 malware_name = Ustrstr(buf, US"<summary code=\"11\">")
561 ? malware_name_internal : NULL;
573 case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
574 /* v0.1 - added support for tcp sockets */
575 /* v0.0 - initial release -- support for unix sockets */
579 unsigned int fsize_uint;
580 uschar * tmpbuf, *drweb_fbuf;
581 int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
582 drweb_vnum, drweb_slen, drweb_fin = 0x0000;
584 /* prepare variables */
585 drweb_cmd = htonl(DRWEBD_SCAN_CMD);
586 drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
588 if (*scanner_options != '/')
591 if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1)
592 return m_errlog_defer_3(scanent, NULL,
593 string_sprintf("can't open spool file %s: %s",
594 eml_filename, strerror(errno)),
597 if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
600 (void)close(drweb_fd);
601 return m_errlog_defer_3(scanent, NULL,
602 string_sprintf("can't seek spool file %s: %s",
603 eml_filename, strerror(err)),
606 fsize_uint = (unsigned int) fsize;
607 if ((off_t)fsize_uint != fsize)
609 (void)close(drweb_fd);
610 return m_errlog_defer_3(scanent, NULL,
611 string_sprintf("seeking spool file %s, size overflow",
615 drweb_slen = htonl(fsize);
616 lseek(drweb_fd, 0, SEEK_SET);
618 DEBUG(D_acl) debug_printf("Malware scan: issuing %s remote scan [%s]\n",
619 scanner_name, scanner_options);
621 /* send scan request */
622 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
623 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
624 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
625 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
627 (void)close(drweb_fd);
628 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
629 "unable to send commands to socket (%s)", scanner_options),
633 if (!(drweb_fbuf = US malloc(fsize_uint)))
635 (void)close(drweb_fd);
636 return m_errlog_defer_3(scanent, NULL,
637 string_sprintf("unable to allocate memory %u for file (%s)",
638 fsize_uint, eml_filename),
642 if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
645 (void)close(drweb_fd);
647 return m_errlog_defer_3(scanent, NULL,
648 string_sprintf("can't read spool file %s: %s",
649 eml_filename, strerror(err)),
652 (void)close(drweb_fd);
654 /* send file body to socket */
655 if (send(sock, drweb_fbuf, fsize, 0) < 0)
658 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
659 "unable to send file body to socket (%s)", scanner_options),
665 drweb_slen = htonl(Ustrlen(eml_filename));
667 DEBUG(D_acl) debug_printf("Malware scan: issuing %s local scan [%s]\n",
668 scanner_name, scanner_options);
670 /* send scan request */
671 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
672 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
673 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
674 (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
675 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
676 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
677 "unable to send commands to socket (%s)", scanner_options),
681 /* wait for result */
682 if (!recv_len(sock, &drweb_rc, sizeof(drweb_rc), tmo))
683 return m_errlog_defer_3(scanent, CUS callout_address,
684 US"unable to read return code", sock);
685 drweb_rc = ntohl(drweb_rc);
687 if (!recv_len(sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
688 return m_errlog_defer_3(scanent, CUS callout_address,
689 US"unable to read the number of viruses", sock);
690 drweb_vnum = ntohl(drweb_vnum);
692 /* "virus(es) found" if virus number is > 0 */
697 /* setup default virus name */
698 malware_name = US"unknown";
700 /* set up match regex */
702 drweb_re = m_pcre_compile(drweb_re_str, &errstr);
704 /* read and concatenate virus names into one string */
705 for (i = 0; i < drweb_vnum; i++)
707 int size = 0, off = 0, ovector[10*3];
708 /* read the size of report */
709 if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
710 return m_errlog_defer_3(scanent, CUS callout_address,
711 US"cannot read report size", sock);
712 drweb_slen = ntohl(drweb_slen);
713 tmpbuf = store_get(drweb_slen);
715 /* read report body */
716 if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
717 return m_errlog_defer_3(scanent, CUS callout_address,
718 US"cannot read report string", sock);
719 tmpbuf[drweb_slen] = '\0';
721 /* try matcher on the line, grab substring */
722 result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
723 ovector, nelements(ovector));
726 const char * pre_malware_nb;
728 pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
730 if (i==0) /* the first name we just copy to malware_name */
731 malware_name = string_append(NULL, &size, &off,
734 else /* concatenate each new virus name to previous */
735 malware_name = string_append(malware_name, &size, &off,
736 2, "/", pre_malware_nb);
738 pcre_free_substring(pre_malware_nb);
744 const char *drweb_s = NULL;
746 if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
747 if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
748 if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
749 if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
750 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
751 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
752 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
753 * and others are ignored */
755 return m_errlog_defer_3(scanent, CUS callout_address,
756 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
765 case M_AVES: /* "aveserver" scanner type -------------------------------- */
770 /* read aveserver's greeting and see if it is ready (2xx greeting) */
772 recv_line(sock, buf, sizeof(buf), tmo);
774 if (buf[0] != '2') /* aveserver is having problems */
775 return m_errlog_defer_3(scanent, CUS callout_address,
776 string_sprintf("unavailable (Responded: %s).",
777 ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
780 /* prepare our command */
781 (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
785 DEBUG(D_acl) debug_printf("Malware scan: issuing %s %s\n",
787 if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
788 return m_errlog_defer(scanent, CUS callout_address, errstr);
792 /* read response lines, find malware name and final response */
793 while (recv_line(sock, buf, sizeof(buf), tmo) > 0)
797 if (buf[0] == '5') /* aveserver is having problems */
799 result = m_errlog_defer(scanent, CUS callout_address,
800 string_sprintf("unable to scan file %s (Responded: %s).",
804 if (Ustrncmp(buf,"322",3) == 0)
806 uschar *p = Ustrchr(&buf[4], ' ');
808 malware_name = string_copy(&buf[4]);
812 if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
813 return m_errlog_defer(scanent, CUS callout_address, errstr);
815 /* read aveserver's greeting and see if it is ready (2xx greeting) */
817 recv_line(sock, buf, sizeof(buf), tmo);
819 if (buf[0] != '2') /* aveserver is having problems */
820 return m_errlog_defer_3(scanent, CUS callout_address,
821 string_sprintf("unable to quit dialogue (Responded: %s).",
822 ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
833 case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
837 uschar av_buffer[1024];
838 static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
839 US"CONFIGURE\tTIMEOUT\t0\n",
840 US"CONFIGURE\tMAXARCH\t5\n",
841 US"CONFIGURE\tMIME\t1\n" };
845 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
846 scanner_name, scanner_options);
848 memset(av_buffer, 0, sizeof(av_buffer));
849 for (i = 0; i != nelements(cmdopt); i++)
852 if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
853 return m_errlog_defer(scanent, CUS callout_address, errstr);
855 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
856 if (bread > 0) av_buffer[bread]='\0';
858 return m_errlog_defer_3(scanent, CUS callout_address,
859 string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
861 for (j = 0; j < bread; j++)
862 if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
866 /* pass the mailfile to fsecure */
867 file_name = string_sprintf("SCAN\t%s\n", eml_filename);
869 if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
870 return m_errlog_defer(scanent, CUS callout_address, errstr);
873 /* todo also SUSPICION\t */
875 fsec_re = m_pcre_compile(fsec_re_str, &errstr);
877 /* read report, linewise. Apply a timeout as the Fsecure daemon
878 sometimes wants an answer to "PING" but they won't tell us what */
880 uschar * p = av_buffer;
886 i = av_buffer+sizeof(av_buffer)-p;
887 if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
888 return m_errlog_defer_3(scanent, CUS callout_address,
889 string_sprintf("unable to read result (%s)", strerror(errno)),
892 for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
896 /* Really search for virus again? */
898 /* try matcher on the line, grab substring */
899 malware_name = m_pcre_exec(fsec_re, p);
901 if (Ustrstr(p, "OK\tScan ok."))
905 /* copy down the trailing partial line then read another chunk */
906 i = av_buffer+sizeof(av_buffer)-p;
907 memmove(av_buffer, p, i);
916 case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
920 uschar * scanrequest;
922 unsigned long kav_reportlen;
927 /* get current date and time, build scan request */
929 /* pdp note: before the eml_filename parameter, this scanned the
930 directory; not finding documentation, so we'll strip off the directory.
931 The side-effect is that the test framework scanning may end up in
932 scanning more than was requested, but for the normal interface, this is
935 strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
936 scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
937 p = Ustrrchr(scanrequest, '/');
941 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
942 scanner_name, scanner_options);
944 /* send scan request */
945 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
946 return m_errlog_defer(scanent, CUS callout_address, errstr);
948 /* wait for result */
949 if (!recv_len(sock, tmpbuf, 2, tmo))
950 return m_errlog_defer_3(scanent, CUS callout_address,
951 US"unable to read 2 bytes from socket.", sock);
953 /* get errorcode from one nibble */
954 kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
957 case 5: case 6: /* improper kavdaemon configuration */
958 return m_errlog_defer_3(scanent, CUS callout_address,
959 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
962 return m_errlog_defer_3(scanent, CUS callout_address,
963 US"reported 'scanning not completed' (code 1).", sock);
965 return m_errlog_defer_3(scanent, CUS callout_address,
966 US"reported 'kavdaemon damaged' (code 7).", sock);
969 /* code 8 is not handled, since it is ambiguous. It appears mostly on
970 bounces where part of a file has been cut off */
972 /* "virus found" return codes (2-4) */
973 if (kav_rc > 1 && kav_rc < 5)
977 /* setup default virus name */
978 malware_name = US"unknown";
980 report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
982 /* read the report, if available */
983 if (report_flag == 1)
985 /* read report size */
986 if (!recv_len(sock, &kav_reportlen, 4, tmo))
987 return m_errlog_defer_3(scanent, CUS callout_address,
988 US"cannot read report size", sock);
990 /* it's possible that avp returns av_buffer[1] == 1 but the
991 reportsize is 0 (!?) */
992 if (kav_reportlen > 0)
994 /* set up match regex, depends on retcode */
997 if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1002 if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1003 kav_re = kav_re_inf;
1006 /* read report, linewise. Using size from stream to read amount of data
1007 from same stream is safe enough. */
1008 /* coverity[tainted_data] */
1009 while (kav_reportlen > 0)
1011 if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1013 kav_reportlen -= bread+1;
1015 /* try matcher on the line, grab substring */
1016 if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1022 else /* no virus found */
1023 malware_name = NULL;
1028 case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1030 const uschar *cmdline_scanner = scanner_options;
1031 const pcre *cmdline_trigger_re;
1032 const pcre *cmdline_regex_re;
1034 uschar * commandline;
1035 void (*eximsigchld)(int);
1036 void (*eximsigpipe)(int);
1037 FILE *scanner_out = NULL;
1039 FILE *scanner_record = NULL;
1040 uschar linebuffer[32767];
1045 if (!cmdline_scanner)
1046 return m_errlog_defer(scanent, NULL, errstr);
1048 /* find scanner output trigger */
1049 cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1050 "missing trigger specification", &errstr);
1051 if (!cmdline_trigger_re)
1052 return m_errlog_defer(scanent, NULL, errstr);
1054 /* find scanner name regex */
1055 cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1056 "missing virus name regex specification", &errstr);
1057 if (!cmdline_regex_re)
1058 return m_errlog_defer(scanent, NULL, errstr);
1060 /* prepare scanner call; despite the naming, file_name holds a directory
1061 name which is documented as the value given to %s. */
1063 file_name = string_copy(eml_filename);
1064 p = Ustrrchr(file_name, '/');
1067 commandline = string_sprintf(CS cmdline_scanner, file_name);
1069 /* redirect STDERR too */
1070 commandline = string_sprintf("%s 2>&1", commandline);
1072 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
1073 scanner_name, commandline);
1075 /* store exims signal handlers */
1076 eximsigchld = signal(SIGCHLD,SIG_DFL);
1077 eximsigpipe = signal(SIGPIPE,SIG_DFL);
1079 if (!(scanner_out = popen(CS commandline,"r")))
1082 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1083 return m_errlog_defer(scanent, NULL,
1084 string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1086 scanner_fd = fileno(scanner_out);
1088 file_name = string_sprintf("%s/scan/%s/%s_scanner_output",
1089 spool_directory, message_id, message_id);
1091 if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1094 (void) pclose(scanner_out);
1095 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1096 return m_errlog_defer(scanent, NULL, string_sprintf(
1097 "opening scanner output file (%s) failed: %s.",
1098 file_name, strerror(err)));
1101 /* look for trigger while recording output */
1102 while ((rcnt = recv_line(scanner_fd, linebuffer,
1103 sizeof(linebuffer), tmo)))
1110 (void) pclose(scanner_out);
1111 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1112 return m_errlog_defer(scanent, NULL, string_sprintf(
1113 "unable to read from scanner (%s): %s",
1114 commandline, strerror(err)));
1117 if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1120 (void) pclose(scanner_out);
1121 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1122 return m_errlog_defer(scanent, NULL, string_sprintf(
1123 "short write on scanner output file (%s).", file_name));
1125 putc('\n', scanner_record);
1126 /* try trigger match */
1128 && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1133 (void)fclose(scanner_record);
1134 sep = pclose(scanner_out);
1135 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1137 return m_errlog_defer(scanent, NULL,
1139 ? string_sprintf("running scanner failed: %s", strerror(sep))
1140 : string_sprintf("scanner returned error code: %d", sep));
1145 /* setup default virus name */
1146 malware_name = US"unknown";
1148 /* re-open the scanner output file, look for name match */
1149 scanner_record = fopen(CS file_name, "rb");
1150 while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1153 if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1156 (void)fclose(scanner_record);
1158 else /* no virus found */
1159 malware_name = NULL;
1163 case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1168 uschar av_buffer[1024];
1170 /* pass the scan directory to sophie */
1171 file_name = string_copy(eml_filename);
1172 if ((p = Ustrrchr(file_name, '/')))
1175 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
1176 scanner_name, scanner_options);
1178 if ( write(sock, file_name, Ustrlen(file_name)) < 0
1179 || write(sock, "\n", 1) != 1
1181 return m_errlog_defer_3(scanent, CUS callout_address,
1182 string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1185 /* wait for result */
1186 memset(av_buffer, 0, sizeof(av_buffer));
1187 if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1188 return m_errlog_defer_3(scanent, CUS callout_address,
1189 string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1193 if (av_buffer[0] == '1') {
1194 uschar * s = Ustrchr(av_buffer, '\n');
1197 malware_name = string_copy(&av_buffer[2]);
1199 else if (!strncmp(CS av_buffer, "-1", 2))
1200 return m_errlog_defer_3(scanent, CUS callout_address,
1201 US"scanner reported error", sock);
1202 else /* all ok, no virus */
1203 malware_name = NULL;
1208 case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1210 /* This code was originally contributed by David Saez */
1211 /* There are three scanning methods available to us:
1212 * (1) Use the SCAN command, pointing to a file in the filesystem
1213 * (2) Use the STREAM command, send the data on a separate port
1214 * (3) Use the zINSTREAM command, send the data inline
1215 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1216 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1217 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1218 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless
1219 * WITH_OLD_CLAMAV_STREAM is defined.
1220 * See Exim bug 926 for details. */
1222 uschar *p, *vname, *result_tag;
1225 uschar av_buffer[1024];
1226 uschar *hostname = US"";
1228 uschar *clamav_fbuf;
1229 int clam_fd, result;
1231 unsigned int fsize_uint;
1232 BOOL use_scan_command = FALSE;
1233 clamd_address * cv[MAX_CLAMD_SERVERS];
1234 int num_servers = 0;
1235 #ifdef WITH_OLD_CLAMAV_STREAM
1237 uschar av_buffer2[1024];
1240 uint32_t send_size, send_final_zeroblock;
1243 /*XXX if unixdomain socket, only one server supported. Needs fixing;
1244 there's no reason we should not mix local and remote servers */
1246 if (*scanner_options == '/')
1249 const uschar * sublist;
1252 /* Local file; so we def want to use_scan_command and don't want to try
1253 * passing IP/port combinations */
1254 use_scan_command = TRUE;
1255 cd = (clamd_address *) store_get(sizeof(clamd_address));
1257 /* extract socket-path part */
1258 sublist = scanner_options;
1259 cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1262 if (clamd_option(cd, sublist, &subsep) != OK)
1263 return m_errlog_defer(scanent, NULL,
1264 string_sprintf("bad option '%s'", scanner_options));
1269 /* Go through the rest of the list of host/port and construct an array
1270 * of servers to try. The first one is the bit we just passed from
1271 * scanner_options so process that first and then scan the remainder of
1272 * the address buffer */
1276 const uschar * sublist;
1280 /* The 'local' option means use the SCAN command over the network
1281 * socket (ie common file storage in use) */
1282 /*XXX we could accept this also as a local option? */
1283 if (strcmpic(scanner_options, US"local") == 0)
1285 use_scan_command = TRUE;
1289 cd = (clamd_address *) store_get(sizeof(clamd_address));
1291 /* extract host and port part */
1292 sublist = scanner_options;
1293 if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1295 (void) m_errlog_defer(scanent, NULL,
1296 string_sprintf("missing address: '%s'", scanner_options));
1299 if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1301 (void) m_errlog_defer(scanent, NULL,
1302 string_sprintf("missing port: '%s'", scanner_options));
1305 cd->tcp_port = atoi(CS s);
1308 /*XXX should these options be common over scanner types? */
1309 if (clamd_option(cd, sublist, &subsep) != OK)
1310 return m_errlog_defer(scanent, NULL,
1311 string_sprintf("bad option '%s'", scanner_options));
1313 cv[num_servers++] = cd;
1314 if (num_servers >= MAX_CLAMD_SERVERS)
1316 (void) m_errlog_defer(scanent, NULL,
1317 US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1318 "specified; only using the first " MAX_CLAMD_SERVERS_S );
1321 } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1324 /* check if we have at least one server */
1326 return m_errlog_defer(scanent, NULL,
1327 US"no useable server addresses in malware configuration option.");
1330 /* See the discussion of response formats below to see why we really
1331 don't like colons in filenames when passing filenames to ClamAV. */
1332 if (use_scan_command && Ustrchr(eml_filename, ':'))
1333 return m_errlog_defer(scanent, NULL,
1334 string_sprintf("local/SCAN mode incompatible with" \
1335 " : in path to email filename [%s]", eml_filename));
1337 /* We have some network servers specified */
1340 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1341 * only supports AF_INET, but we should probably be looking to the
1342 * future and rewriting this to be protocol-independent anyway. */
1344 while (num_servers > 0)
1346 int i = random_number( num_servers );
1347 clamd_address * cd = cv[i];
1349 DEBUG(D_acl) debug_printf("trying server name %s, port %u\n",
1350 cd->hostspec, cd->tcp_port);
1352 /* Lookup the host. This is to ensure that we connect to the same IP
1353 * on both connections (as one host could resolve to multiple ips) */
1356 sock= m_tcpsocket(cd->hostspec, cd->tcp_port, &connhost, &errstr);
1359 /* Connection successfully established with a server */
1360 hostname = cd->hostspec;
1363 if (cd->retry <= 0) break;
1364 while (cd->retry > 0) cd->retry = sleep(cd->retry);
1369 (void) m_errlog_defer(scanent, CUS callout_address, errstr);
1371 /* Remove the server from the list. XXX We should free the memory */
1373 for (; i < num_servers; i++)
1377 if (num_servers == 0)
1378 return m_errlog_defer(scanent, NULL, US"all servers failed");
1383 if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1385 hostname = cv[0]->hostspec;
1388 if (cv[0]->retry <= 0)
1389 return m_errlog_defer(scanent, CUS callout_address, errstr);
1390 while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1393 /* have socket in variable "sock"; command to use is semi-independent of
1394 * the socket protocol. We use SCAN if is local (either Unix/local
1395 * domain socket, or explicitly told local) else we stream the data.
1396 * How we stream the data depends upon how we were built. */
1398 if (!use_scan_command)
1400 #ifdef WITH_OLD_CLAMAV_STREAM
1401 /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1402 * that port on a second connection; then in the scan-method-neutral
1403 * part, read the response back on the original connection. */
1405 DEBUG(D_acl) debug_printf(
1406 "Malware scan: issuing %s old-style remote scan (PORT)\n",
1409 /* Pass the string to ClamAV (7 = "STREAM\n") */
1410 if (m_sock_send(sock, US"STREAM\n", 7, &errstr) < 0)
1411 return m_errlog_defer(scanent, CUS callout_address, errstr);
1413 memset(av_buffer2, 0, sizeof(av_buffer2));
1414 bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
1417 return m_errlog_defer_3(scanent, CUS callout_address,
1418 string_sprintf("unable to read PORT from socket (%s)",
1422 if (bread == sizeof(av_buffer2))
1423 return m_errlog_defer_3(scanent, CUS callout_address,
1424 "buffer too small", sock);
1427 return m_errlog_defer_3(scanent, CUS callout_address,
1428 "ClamAV returned null", sock);
1430 av_buffer2[bread] = '\0';
1431 if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 )
1432 return m_errlog_defer_3(scanent, CUS callout_address,
1433 string_sprintf("Expected port information from clamd, got '%s'",
1437 sockData = m_tcpsocket(connhost.address, port, NULL, &errstr);
1439 return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock);
1441 # define CLOSE_SOCKDATA (void)close(sockData)
1442 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1443 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1444 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1447 DEBUG(D_acl) debug_printf(
1448 "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1451 /* Pass the string to ClamAV (10 = "zINSTREAM\0") */
1452 if (send(sock, "zINSTREAM", 10, 0) < 0)
1453 return m_errlog_defer_3(scanent, CUS hostname,
1454 string_sprintf("unable to send zINSTREAM to socket (%s)",
1458 # define CLOSE_SOCKDATA /**/
1461 /* calc file size */
1462 if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1466 return m_errlog_defer_3(scanent, NULL,
1467 string_sprintf("can't open spool file %s: %s",
1468 eml_filename, strerror(err)),
1471 if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1474 CLOSE_SOCKDATA; (void)close(clam_fd);
1475 return m_errlog_defer_3(scanent, NULL,
1476 string_sprintf("can't seek spool file %s: %s",
1477 eml_filename, strerror(err)),
1480 fsize_uint = (unsigned int) fsize;
1481 if ((off_t)fsize_uint != fsize)
1483 CLOSE_SOCKDATA; (void)close(clam_fd);
1484 return m_errlog_defer_3(scanent, NULL,
1485 string_sprintf("seeking spool file %s, size overflow",
1489 lseek(clam_fd, 0, SEEK_SET);
1491 if (!(clamav_fbuf = US malloc(fsize_uint)))
1493 CLOSE_SOCKDATA; (void)close(clam_fd);
1494 return m_errlog_defer_3(scanent, NULL,
1495 string_sprintf("unable to allocate memory %u for file (%s)",
1496 fsize_uint, eml_filename),
1500 if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1503 free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd);
1504 return m_errlog_defer_3(scanent, NULL,
1505 string_sprintf("can't read spool file %s: %s",
1506 eml_filename, strerror(err)),
1509 (void)close(clam_fd);
1511 /* send file body to socket */
1512 #ifdef WITH_OLD_CLAMAV_STREAM
1513 if (send(sockData, clamav_fbuf, fsize_uint, 0) < 0)
1515 free(clamav_fbuf); CLOSE_SOCKDATA;
1516 return m_errlog_defer_3(scanent, NULL,
1517 string_sprintf("unable to send file body to socket (%s:%u)",
1522 send_size = htonl(fsize_uint);
1523 send_final_zeroblock = 0;
1524 if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1525 (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1526 (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1529 return m_errlog_defer_3(scanent, NULL,
1530 string_sprintf("unable to send file body to socket (%s)", hostname),
1538 #undef CLOSE_SOCKDATA
1541 { /* use scan command */
1542 /* Send a SCAN command pointing to a filename; then in the then in the
1543 * scan-method-neutral part, read the response back */
1545 /* ================================================================= */
1547 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1548 which dates to when ClamAV needed us to break apart the email into the
1549 MIME parts (eg, with the now deprecated demime condition coming first).
1550 Some time back, ClamAV gained the ability to deconstruct the emails, so
1551 doing this would actually have resulted in the mail attachments being
1552 scanned twice, in the broken out files and from the original .eml.
1553 Since ClamAV now handles emails (and has for quite some time) we can
1554 just use the email file itself. */
1555 /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
1556 file_name = string_sprintf("SCAN %s\n", eml_filename);
1558 DEBUG(D_acl) debug_printf(
1559 "Malware scan: issuing %s local-path scan [%s]\n",
1560 scanner_name, scanner_options);
1562 if (send(sock, file_name, Ustrlen(file_name), 0) < 0)
1563 return m_errlog_defer_3(scanent, CUS callout_address,
1564 string_sprintf("unable to write to socket (%s)", strerror(errno)),
1567 /* Do not shut down the socket for writing; a user report noted that
1568 * clamd 0.70 does not react well to this. */
1570 /* Commands have been sent, no matter which scan method or connection
1571 * type we're using; now just read the result, independent of method. */
1573 /* Read the result */
1574 memset(av_buffer, 0, sizeof(av_buffer));
1575 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1580 return m_errlog_defer(scanent, CUS callout_address,
1581 string_sprintf("unable to read from socket (%s)",
1582 errno == 0 ? "EOF" : strerror(errno)));
1584 if (bread == sizeof(av_buffer))
1585 return m_errlog_defer(scanent, CUS callout_address,
1586 US"buffer too small");
1587 /* We're now assured of a NULL at the end of av_buffer */
1589 /* Check the result. ClamAV returns one of two result formats.
1590 In the basic mode, the response is of the form:
1591 infected: -> "<filename>: <virusname> FOUND"
1592 not-infected: -> "<filename>: OK"
1593 error: -> "<filename>: <errcode> ERROR
1594 If the ExtendedDetectionInfo option has been turned on, then we get:
1595 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1596 for the infected case. Compare:
1597 /tmp/eicar.com: Eicar-Test-Signature FOUND
1598 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1600 In the streaming case, clamd uses the filename "stream" which you should
1601 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1602 client app will replace "stream" with the original filename before returning
1603 results to stdout, but the trace shows the data).
1605 We will assume that the pathname passed to clamd from Exim does not contain
1606 a colon. We will have whined loudly above if the eml_filename does (and we're
1607 passing a filename to clamd). */
1610 return m_errlog_defer(scanent, CUS callout_address,
1611 US"ClamAV returned null");
1613 /* strip newline at the end (won't be present for zINSTREAM)
1614 (also any trailing whitespace, which shouldn't exist, but we depend upon
1615 this below, so double-check) */
1616 p = av_buffer + Ustrlen(av_buffer) - 1;
1617 if (*p == '\n') *p = '\0';
1619 DEBUG(D_acl) debug_printf("Malware response: %s\n", av_buffer);
1621 while (isspace(*--p) && (p > av_buffer))
1625 /* colon in returned output? */
1626 if(!(p = Ustrchr(av_buffer,':')))
1627 return m_errlog_defer(scanent, CUS callout_address, string_sprintf(
1628 "ClamAV returned malformed result (missing colon): %s",
1631 /* strip filename */
1632 while (*p && isspace(*++p)) /**/;
1635 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1636 but we should at least be resistant to it. */
1637 p = Ustrrchr(vname, ' ');
1638 result_tag = p ? p+1 : vname;
1640 if (Ustrcmp(result_tag, "FOUND") == 0)
1642 /* p should still be the whitespace before the result_tag */
1643 while (isspace(*p)) --p;
1645 /* Strip off the extended information too, which will be in parens
1646 after the virus name, with no intervening whitespace. */
1649 /* "(hash:size)", so previous '(' will do; if not found, we have
1650 a curious virus name, but not an error. */
1651 p = Ustrrchr(vname, '(');
1655 malware_name = string_copy(vname);
1656 DEBUG(D_acl) debug_printf("Malware found, name \"%s\"\n", malware_name);
1659 else if (Ustrcmp(result_tag, "ERROR") == 0)
1660 return m_errlog_defer(scanent, CUS callout_address,
1661 string_sprintf("ClamAV returned: %s", av_buffer));
1663 else if (Ustrcmp(result_tag, "OK") == 0)
1665 /* Everything should be OK */
1666 malware_name = NULL;
1667 DEBUG(D_acl) debug_printf("Malware not found\n");
1671 return m_errlog_defer(scanent, CUS callout_address,
1672 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1677 case M_SOCK: /* "sock" scanner type ------------------------------------- */
1678 /* This code was derived by Martin Poole from the clamd code contributed
1679 by David Saez and the cmdline code
1683 uschar * commandline;
1684 uschar av_buffer[1024];
1685 uschar * linebuffer;
1686 uschar * sockline_scanner;
1687 uschar sockline_scanner_default[] = "%s\n";
1688 const pcre *sockline_trig_re;
1689 const pcre *sockline_name_re;
1691 /* find scanner command line */
1692 if ((sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1694 { /* check for no expansions apart from one %s */
1695 uschar * s = Ustrchr(sockline_scanner, '%');
1697 if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1698 return m_errlog_defer_3(scanent, NULL,
1699 US"unsafe sock scanner call spec", sock);
1702 sockline_scanner = sockline_scanner_default;
1704 /* find scanner output trigger */
1705 sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1706 "missing trigger specification", &errstr);
1707 if (!sockline_trig_re)
1708 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1710 /* find virus name regex */
1711 sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1712 "missing virus name regex specification", &errstr);
1713 if (!sockline_name_re)
1714 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1716 /* prepare scanner call - security depends on expansions check above */
1717 commandline = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
1718 commandline = string_sprintf( CS sockline_scanner, CS commandline);
1721 /* Pass the command string to the socket */
1722 if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1723 return m_errlog_defer(scanent, CUS callout_address, errstr);
1725 /* Read the result */
1726 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1729 return m_errlog_defer_3(scanent, CUS callout_address,
1730 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1733 if (bread == sizeof(av_buffer))
1734 return m_errlog_defer_3(scanent, CUS callout_address,
1735 US"buffer too small", sock);
1736 av_buffer[bread] = '\0';
1737 linebuffer = string_copy(av_buffer);
1739 /* try trigger match */
1740 if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1742 if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1743 malware_name = US "unknown";
1745 else /* no virus found */
1746 malware_name = NULL;
1750 case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1752 char *mksd_options_end;
1753 int mksd_maxproc = 1; /* default, if no option supplied */
1756 if (scanner_options)
1758 mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1759 if ( *scanner_options == '\0'
1760 || *mksd_options_end != '\0'
1762 || mksd_maxproc > 32
1764 return m_errlog_defer(scanent, CUS callout_address,
1765 string_sprintf("invalid option '%s'", scanner_options));
1768 if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1769 return m_errlog_defer(scanent, CUS callout_address, errstr);
1771 malware_name = NULL;
1773 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan\n", scanner_name);
1775 if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1783 case M_AVAST: /* "avast" scanner type ----------------------------------- */
1787 uschar * scanrequest;
1788 enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1791 /* According to Martin Tuma @avast the protocol uses "escaped
1792 whitespace", that is, every embedded whitespace is backslash
1793 escaped, as well as backslash is protected by backslash.
1794 The returned lines contain the name of the scanned file, a tab
1798 [E] - some error occured
1799 Such marker follows the first non-escaped TAB. */
1800 if ( ( !ava_re_clean
1801 && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1803 && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1805 return malware_errlog_defer(errstr);
1807 /* wait for result */
1808 for (avast_stage = AVA_HELO;
1809 (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1812 int slen = Ustrlen(buf);
1815 DEBUG(D_acl) debug_printf("got from avast: %s\n", buf);
1816 switch (avast_stage)
1819 if (Ustrncmp(buf, "220", 3) != 0)
1820 goto endloop; /* require a 220 */
1824 if (Ustrncmp(buf, "210", 3) == 0)
1825 break; /* ignore 210 responses */
1826 if (Ustrncmp(buf, "200", 3) != 0)
1827 goto endloop; /* require a 200 */
1832 /* Check for another option to send. Newline-terminate it. */
1833 if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1836 scanrequest = string_sprintf("%s\n", scanrequest);
1837 avast_stage = AVA_OPT; /* just sent option */
1841 scanrequest = string_sprintf("SCAN %s/scan/%s\n",
1842 spool_directory, message_id);
1843 avast_stage = AVA_RSP; /* just sent command */
1846 /* send config-cmd or scan-request to socket */
1847 len = Ustrlen(scanrequest);
1848 if (send(sock, scanrequest, len, 0) < 0)
1850 scanrequest[len-1] = '\0';
1851 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
1852 "unable to send request '%s' to socket (%s): %s",
1853 scanrequest, scanner_options, strerror(errno)), sock);
1859 if (Ustrncmp(buf, "210", 3) == 0)
1860 break; /* ignore the "210 SCAN DATA" message */
1862 if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
1863 0, 0, ovector, nelements(ovector)) > 0)
1866 if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
1867 { /* remove backslash in front of [whitespace|backslash] */
1869 for (p = malware_name; *p; ++p)
1870 if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
1871 for (p0 = p; *p0; ++p0) *p0 = p0[1];
1873 avast_stage = AVA_DONE;
1877 if (Ustrncmp(buf, "200 SCAN OK", 11) == 0)
1878 { /* we're done finally */
1879 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1880 return m_errlog_defer_3(scanent, CUS callout_address,
1882 "unable to send quit request to socket (%s): %s",
1883 scanner_options, strerror(errno)),
1885 malware_name = NULL;
1886 avast_stage = AVA_DONE;
1890 /* here for any unexpected response from the scanner */
1893 case AVA_DONE: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
1894 __FILE__, __LINE__, __FUNCTION__);
1904 case AVA_RSP: return m_errlog_defer_3(scanent, CUS callout_address,
1907 "invalid response from scanner: '%s'", buf)
1909 ? US"EOF from scanner"
1910 : US"timeout from scanner",
1916 } /* scanner type switch */
1919 (void) close (sock);
1920 malware_ok = TRUE; /* set "been here, done that" marker */
1923 /* match virus name against pattern (caseless ------->----------v) */
1924 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
1926 DEBUG(D_acl) debug_printf(
1927 "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
1935 /*************************************************
1936 * Scan an email for malware *
1937 *************************************************/
1939 /* This is the normal interface for scanning an email, which doesn't need a
1940 filename; it's a wrapper around the malware_file function.
1943 malware_re match condition for "malware="
1944 timeout if nonzero, timeout in seconds
1946 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
1947 where true means malware was found (condition applies)
1950 malware(const uschar * malware_re, int timeout)
1952 uschar * scan_filename;
1955 scan_filename = string_sprintf("%s/scan/%s/%s.eml",
1956 spool_directory, message_id, message_id);
1957 ret = malware_internal(malware_re, scan_filename, timeout, FALSE);
1958 if (ret == DEFER) av_failed = TRUE;
1964 /*************************************************
1965 * Scan a file for malware *
1966 *************************************************/
1968 /* This is a test wrapper for scanning an email, which is not used in
1969 normal processing. Scan any file, using the Exim scanning interface.
1970 This function tampers with various global variables so is unsafe to use
1971 in any other context.
1974 eml_filename a file holding the message to be scanned
1976 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
1977 where true means malware was found (condition applies)
1980 malware_in_file(uschar *eml_filename)
1982 uschar message_id_buf[64];
1985 /* spool_mbox() assumes various parameters exist, when creating
1986 the relevant directory and the email within */
1988 (void) string_format(message_id_buf, sizeof(message_id_buf),
1989 "dummy-%d", vaguely_random_number(INT_MAX));
1990 message_id = message_id_buf;
1991 sender_address = US"malware-sender@example.net";
1993 recipients_list = NULL;
1994 receive_add_recipient(US"malware-victim@example.net", -1);
1995 enable_dollar_recipients = TRUE;
1997 ret = malware_internal(US"*", eml_filename, 0, TRUE);
1999 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2002 /* don't set no_mbox_unspool; at present, there's no way for it to become
2003 set, but if that changes, then it should apply to these tests too */
2007 /* silence static analysis tools */
2017 if (!malware_default_re)
2018 malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2020 drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2022 fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2024 kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2026 kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2028 ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2030 ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2033 #endif /*WITH_CONTENT_SCAN*/