1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-2014 */
8 /* Code for calling virus (malware) scanners. Called from acl.c. */
11 #ifdef WITH_CONTENT_SCAN
13 typedef enum {M_FPROTD, M_DRWEB, M_AVES, M_FSEC, M_KAVD, M_CMDL,
14 M_SOPHIE, M_CLAMD, M_SOCK, M_MKSD, M_AVAST} scanner_t;
15 typedef enum {MC_NONE, MC_TCP, MC_UNIX, MC_STRM} contype_t;
20 const uschar * options_default;
24 { M_FPROTD, US"f-protd", US"localhost 10200-10204", MC_TCP },
25 { M_DRWEB, US"drweb", US"/usr/local/drweb/run/drwebd.sock", MC_STRM },
26 { M_AVES, US"aveserver", US"/var/run/aveserver", MC_UNIX },
27 { M_FSEC, US"fsecure", US"/var/run/.fsav", MC_UNIX },
28 { M_KAVD, US"kavdaemon", US"/var/run/AvpCtl", MC_UNIX },
29 { M_CMDL, US"cmdline", NULL, MC_NONE },
30 { M_SOPHIE, US"sophie", US"/var/run/sophie", MC_UNIX },
31 { M_CLAMD, US"clamd", US"/tmp/clamd", MC_NONE },
32 { M_SOCK, US"sock", US"/tmp/malware.sock", MC_STRM },
33 { M_MKSD, US"mksd", NULL, MC_NONE },
34 { M_AVAST, US"avast", US"/var/run/avast/scan.sock", MC_STRM },
35 { -1, NULL, NULL, MC_NONE } /* end-marker */
38 /* The maximum number of clamd servers that are supported in the configuration */
39 #define MAX_CLAMD_SERVERS 32
40 #define MAX_CLAMD_SERVERS_S "32"
41 /* Maximum length of the hostname that can be specified in the clamd address list */
42 #define MAX_CLAMD_ADDRESS_LENGTH 64
43 #define MAX_CLAMD_ADDRESS_LENGTH_S "64"
45 typedef struct clamd_address_container {
46 uschar tcp_addr[MAX_CLAMD_ADDRESS_LENGTH+1];
47 unsigned int tcp_port;
48 } clamd_address_container;
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 */
67 /* Routine to check whether a system is big- or little-endian.
68 Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
69 Needed for proper kavdaemon implementation. Sigh. */
70 #define BIG_MY_ENDIAN 0
71 #define LITTLE_MY_ENDIAN 1
72 static int test_byte_order(void);
76 short int word = 0x0001;
77 char *byte = (char *) &word;
78 return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
81 BOOL malware_ok = FALSE;
83 /* Gross hacks for the -bmalware option; perhaps we should just create
84 the scan directory normally for that case, but look into rigging up the
85 needed header variables if not already set on the command-line? */
86 extern int spool_mbox_ok;
87 extern uschar spooled_message_id[17];
92 malware_errlog_defer(const uschar * str)
94 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
99 m_errlog_defer(struct scan * scanent, const uschar * str)
101 return malware_errlog_defer(string_sprintf("%s: %s", scanent->name, str));
104 m_errlog_defer_3(struct scan * scanent, const uschar * str,
107 (void) close(fd_to_close);
108 return m_errlog_defer(scanent, str);
111 /*************************************************/
113 /* Only used by the Clamav code, which is working from a list of servers and
114 uses the returned in_addr to get a second connection to the same system.
117 m_tcpsocket(const uschar * hostname, unsigned int port,
118 host_item * host, uschar ** errstr)
120 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5, host, errstr);
124 m_tcpsocket_fromdef(const uschar * hostport, uschar ** errstr)
127 uschar hostname[256];
128 unsigned int portlow, porthigh;
130 /* extract host and port part */
131 scan = sscanf(CS hostport, "%255s %u-%u", hostname, &portlow, &porthigh);
134 *errstr = string_sprintf("invalid socket '%s'", hostport);
140 return ip_connectedsocket(SOCK_STREAM, hostname, portlow, porthigh,
145 m_unixsocket(const uschar * path, uschar ** errstr)
148 struct sockaddr_un server;
150 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
151 *errstr = US"can't open UNIX socket.";
155 server.sun_family = AF_UNIX;
156 Ustrncpy(server.sun_path, path, sizeof(server.sun_path)-1);
157 server.sun_path[sizeof(server.sun_path)-1] = '\0';
158 if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
161 *errstr = string_sprintf("unable to connect to UNIX socket (%s): %s",
162 path, strerror(err));
169 m_streamsocket(const uschar * spec, uschar ** errstr)
172 ? m_unixsocket(spec, errstr) : m_tcpsocket_fromdef(spec, errstr);
176 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
178 if (send(sock, buf, cnt, 0) < 0) {
181 *errstr = string_sprintf("unable to send to socket (%s): %s",
189 m_pcre_compile(const uschar * re, uschar ** errstr)
191 const uschar * rerror;
195 cre = pcre_compile(CS re, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
197 *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
198 re, rerror, roffset);
203 m_pcre_exec(const pcre * cre, uschar * text)
206 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
207 ovector, nelements(ovector));
208 uschar * substr = NULL;
209 if (i >= 2) /* Got it */
210 pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr);
215 m_pcre_nextinlist(uschar ** list, int * sep, char * listerr, uschar ** errstr)
217 const uschar * list_ele;
218 const pcre * cre = NULL;
220 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
221 *errstr = US listerr;
223 cre = m_pcre_compile(CUS list_ele, errstr);
228 Simple though inefficient wrapper for reading a line. Drop CRs and the
229 trailing newline. Can return early on buffer full. Null-terminate.
230 Apply initial timeout if no data ready.
232 Return: number of chars - zero for an empty line
234 -2 on timeout or error
237 recv_line(int fd, uschar * buffer, int bsize, int tmo)
243 if (!fd_ready(fd, tmo-time(NULL)))
246 /*XXX tmo handling assumes we always get a whole line */
249 while ((rcv = read(fd, p, 1)) > 0)
252 if (p-buffer > bsize-2) break;
253 if (*p == '\n') break;
258 DEBUG(D_acl) debug_printf("Malware scan: read %s (%s)\n",
259 rcv==0 ? "EOF" : "error", strerror(errno));
260 return rcv==0 ? -1 : -2;
264 DEBUG(D_acl) debug_printf("Malware scan: read '%s'\n", buffer);
268 /* return TRUE iff size as requested */
270 recv_len(int sock, void * buf, int size, int tmo)
272 return fd_ready(sock, tmo-time(NULL))
273 ? recv(sock, buf, size, 0) == size
279 /* ============= private routines for the "mksd" scanner type ============== */
284 mksd_writev (int sock, struct iovec * iov, int iovcnt)
291 i = writev (sock, iov, iovcnt);
292 while (i < 0 && errno == EINTR);
295 (void) malware_errlog_defer(
296 US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
299 for (;;) /* check for short write */
300 if (i >= iov->iov_len)
310 iov->iov_base = CS iov->iov_base + i;
317 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, int tmo)
324 i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL));
327 (void) malware_errlog_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
332 /* offset == av_buffer_size -> buffer full */
333 if (offset == av_buffer_size)
335 (void) malware_errlog_defer(US"malformed reply received from mksd");
338 } while (av_buffer[offset-1] != '\n');
340 av_buffer[offset] = '\0';
345 mksd_parse_line(struct scan * scanent, char * line)
356 if ((p = strchr (line, '\n')) != NULL)
358 return m_errlog_defer(scanent,
359 string_sprintf("scanner failed: %s", line));
362 if ((p = strchr (line, '\n')) != NULL)
367 && (p = strchr(line+4, ' ')) != NULL
372 malware_name = string_copy(US line+4);
376 return m_errlog_defer(scanent,
377 string_sprintf("malformed reply received: %s", line));
382 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
386 const char *cmd = "MSQ\n";
387 uschar av_buffer[1024];
389 iov[0].iov_base = (void *) cmd;
391 iov[1].iov_base = (void *) scan_filename;
392 iov[1].iov_len = Ustrlen(scan_filename);
393 iov[2].iov_base = (void *) (cmd + 3);
396 if (mksd_writev (sock, iov, 3) < 0)
399 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
402 return mksd_parse_line (scanent, CS av_buffer);
405 /*************************************************
406 * Scan content for malware *
407 *************************************************/
409 /* This is an internal interface for scanning an email; the normal interface
410 is via malware(), or there's malware_in_file() used for testing/debugging.
413 malware_re match condition for "malware="
414 eml_filename the file holding the email to be scanned
415 timeout if nonzero, non-default timeoutl
416 faking whether or not we're faking this up for the -bmalware test
418 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
419 where true means malware was found (condition applies)
422 malware_internal(const uschar * malware_re, const uschar * eml_filename,
423 int timeout, BOOL faking)
426 uschar *av_scanner_work = av_scanner;
427 uschar *scanner_name;
428 uschar malware_regex_default[] = ".+";
429 unsigned long mbox_size;
433 struct scan * scanent;
434 const uschar * scanner_options;
438 /* make sure the eml mbox file is spooled up */
439 if (!(mbox_file = spool_mbox(&mbox_size, faking ? eml_filename : NULL)))
440 return malware_errlog_defer(US"error while creating mbox spool file");
442 /* none of our current scanners need the mbox
443 file as a stream, so we can close it right away */
444 (void)fclose(mbox_file);
447 return FAIL; /* empty means "don't match anything" */
449 /* parse 1st option */
450 if ( (strcmpic(malware_re, US"false") == 0) ||
451 (Ustrcmp(malware_re,"0") == 0) )
452 return FAIL; /* explicitly no matching */
454 /* special cases (match anything except empty) */
455 if ( (strcmpic(malware_re,US"true") == 0) ||
456 (Ustrcmp(malware_re,"*") == 0) ||
457 (Ustrcmp(malware_re,"1") == 0) )
458 malware_re = malware_regex_default;
460 /* Reset sep that is set by previous string_nextinlist() call */
463 /* compile the regex, see if it works */
464 if (!(re = m_pcre_compile(malware_re, &errstr)))
465 return malware_errlog_defer(errstr);
467 /* if av_scanner starts with a dollar, expand it first */
468 if (*av_scanner == '$')
470 if (!(av_scanner_work = expand_string(av_scanner)))
471 return malware_errlog_defer(
472 string_sprintf("av_scanner starts with $, but expansion failed: %s",
473 expand_string_message));
476 debug_printf("Expanded av_scanner global: %s\n", av_scanner_work);
477 /* disable result caching in this case */
482 /* Do not scan twice (unless av_scanner is dynamic). */
485 /* find the scanner type from the av_scanner option */
486 if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
487 return malware_errlog_defer(US"av_scanner configuration variable is empty");
488 if (!timeout) timeout = MALWARE_TIMEOUT;
489 tmo = time(NULL) + timeout;
491 for (scanent = m_scans; ; scanent++) {
493 return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
495 if (strcmpic(scanner_name, US scanent->name) != 0)
497 if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
498 scanner_options = scanent->options_default;
499 if (scanent->conn == MC_NONE)
501 switch(scanent->conn)
503 case MC_TCP: sock = m_tcpsocket_fromdef(scanner_options, &errstr); break;
504 case MC_UNIX: sock = m_unixsocket(scanner_options, &errstr); break;
505 case MC_STRM: sock = m_streamsocket(scanner_options, &errstr); break;
506 default: /* compiler quietening */ break;
509 return m_errlog_defer(scanent, errstr);
512 DEBUG(D_acl) debug_printf("Malware scan: %s tmo %s\n", scanner_name, readconf_printtime(timeout));
514 switch (scanent->scancode)
516 case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
518 uschar *fp_scan_option;
519 unsigned int detected=0, par_count=0;
520 uschar * scanrequest;
521 uschar buf[32768], *strhelper, *strhelper2;
522 uschar * malware_name_internal = NULL;
525 scanrequest = string_sprintf("GET %s", eml_filename);
527 while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
530 scanrequest = string_sprintf("%s%s%s", scanrequest,
531 par_count ? "%20" : "?", fp_scan_option);
534 scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
535 DEBUG(D_acl) debug_printf("Malware scan: issuing %s: %s\n",
536 scanner_name, scanrequest);
538 /* send scan request */
539 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
540 return m_errlog_defer(scanent, errstr);
542 while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0)
545 if (Ustrstr(buf, US"<detected type=\"") != NULL)
547 else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
549 if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
552 malware_name_internal = string_copy(strhelper+6);
555 else if (Ustrstr(buf, US"<summary code=\""))
557 malware_name = Ustrstr(buf, US"<summary code=\"11\">")
558 ? malware_name_internal : NULL;
570 case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
571 /* v0.1 - added support for tcp sockets */
572 /* v0.0 - initial release -- support for unix sockets */
576 unsigned int fsize_uint;
577 uschar * tmpbuf, *drweb_fbuf;
578 int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
579 drweb_vnum, drweb_slen, drweb_fin = 0x0000;
580 const pcre *drweb_re;
582 /* prepare variables */
583 drweb_cmd = htonl(DRWEBD_SCAN_CMD);
584 drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
586 if (*scanner_options != '/')
589 if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1)
590 return m_errlog_defer_3(scanent,
591 string_sprintf("can't open spool file %s: %s",
592 eml_filename, strerror(errno)),
595 if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
598 (void)close(drweb_fd);
599 return m_errlog_defer_3(scanent,
600 string_sprintf("can't seek spool file %s: %s",
601 eml_filename, strerror(err)),
604 fsize_uint = (unsigned int) fsize;
605 if ((off_t)fsize_uint != fsize)
607 (void)close(drweb_fd);
608 return m_errlog_defer_3(scanent,
609 string_sprintf("seeking spool file %s, size overflow",
613 drweb_slen = htonl(fsize);
614 lseek(drweb_fd, 0, SEEK_SET);
616 DEBUG(D_acl) debug_printf("Malware scan: issuing %s remote scan [%s]\n",
617 scanner_name, scanner_options);
619 /* send scan request */
620 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
621 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
622 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
623 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
625 (void)close(drweb_fd);
626 return m_errlog_defer_3(scanent, string_sprintf(
627 "unable to send commands to socket (%s)", scanner_options),
631 if (!(drweb_fbuf = (uschar *) malloc (fsize_uint)))
633 (void)close(drweb_fd);
634 return m_errlog_defer_3(scanent,
635 string_sprintf("unable to allocate memory %u for file (%s)",
636 fsize_uint, eml_filename),
640 if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
643 (void)close(drweb_fd);
645 return m_errlog_defer_3(scanent,
646 string_sprintf("can't read spool file %s: %s",
647 eml_filename, strerror(err)),
650 (void)close(drweb_fd);
652 /* send file body to socket */
653 if (send(sock, drweb_fbuf, fsize, 0) < 0)
656 return m_errlog_defer_3(scanent, string_sprintf(
657 "unable to send file body to socket (%s)", scanner_options),
660 (void)close(drweb_fd);
664 drweb_slen = htonl(Ustrlen(eml_filename));
666 DEBUG(D_acl) debug_printf("Malware scan: issuing %s local scan [%s]\n",
667 scanner_name, scanner_options);
669 /* send scan request */
670 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
671 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
672 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
673 (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
674 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
675 return m_errlog_defer_3(scanent, string_sprintf(
676 "unable to send commands to socket (%s)", scanner_options),
680 /* wait for result */
681 if (!recv_len(sock, &drweb_rc, sizeof(drweb_rc), tmo))
682 return m_errlog_defer_3(scanent,
683 US"unable to read return code", sock);
684 drweb_rc = ntohl(drweb_rc);
686 if (!recv_len(sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
687 return m_errlog_defer_3(scanent,
688 US"unable to read the number of viruses", sock);
689 drweb_vnum = ntohl(drweb_vnum);
691 /* "virus(es) found" if virus number is > 0 */
696 /* setup default virus name */
697 malware_name = US"unknown";
699 /* set up match regex */
700 drweb_re = m_pcre_compile(US"infected\\swith\\s*(.+?)$", &errstr);
702 /* read and concatenate virus names into one string */
703 for (i = 0; i < drweb_vnum; i++)
705 int size = 0, off = 0, ovector[10*3];
706 /* read the size of report */
707 if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
708 return m_errlog_defer_3(scanent,
709 US"cannot read report size", sock);
710 drweb_slen = ntohl(drweb_slen);
711 tmpbuf = store_get(drweb_slen);
713 /* read report body */
714 if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
715 return m_errlog_defer_3(scanent,
716 US"cannot read report string", sock);
717 tmpbuf[drweb_slen] = '\0';
719 /* try matcher on the line, grab substring */
720 result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
721 ovector, nelements(ovector));
724 const char * pre_malware_nb;
726 pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
728 if (i==0) /* the first name we just copy to malware_name */
729 malware_name = string_append(NULL, &size, &off,
732 else /* concatenate each new virus name to previous */
733 malware_name = string_append(malware_name, &size, &off,
734 2, "/", pre_malware_nb);
736 pcre_free_substring(pre_malware_nb);
742 const char *drweb_s = NULL;
744 if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
745 if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
746 if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
747 if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
748 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
749 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
750 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
751 * and others are ignored */
753 return m_errlog_defer_3(scanent,
754 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
763 case M_AVES: /* "aveserver" scanner type -------------------------------- */
768 /* read aveserver's greeting and see if it is ready (2xx greeting) */
770 recv_line(sock, buf, sizeof(buf), tmo);
772 if (buf[0] != '2') /* aveserver is having problems */
773 return m_errlog_defer_3(scanent,
774 string_sprintf("unavailable (Responded: %s).",
775 ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
778 /* prepare our command */
779 (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
783 DEBUG(D_acl) debug_printf("Malware scan: issuing %s %s\n",
785 if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
786 return m_errlog_defer(scanent, errstr);
790 /* read response lines, find malware name and final response */
791 while (recv_line(sock, buf, sizeof(buf), tmo) > 0)
795 if (buf[0] == '5') /* aveserver is having problems */
797 result = m_errlog_defer(scanent,
798 string_sprintf("unable to scan file %s (Responded: %s).",
802 if (Ustrncmp(buf,"322",3) == 0)
804 uschar *p = Ustrchr(&buf[4], ' ');
806 malware_name = string_copy(&buf[4]);
810 if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
811 return m_errlog_defer(scanent, errstr);
813 /* read aveserver's greeting and see if it is ready (2xx greeting) */
815 recv_line(sock, buf, sizeof(buf), tmo);
817 if (buf[0] != '2') /* aveserver is having problems */
818 return m_errlog_defer_3(scanent,
819 string_sprintf("unable to quit dialogue (Responded: %s).",
820 ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
831 case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
835 uschar av_buffer[1024];
837 static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
838 US"CONFIGURE\tTIMEOUT\t0\n",
839 US"CONFIGURE\tMAXARCH\t5\n",
840 US"CONFIGURE\tMIME\t1\n" };
844 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
845 scanner_name, scanner_options);
847 memset(av_buffer, 0, sizeof(av_buffer));
848 for (i = 0; i != nelements(cmdopt); i++)
851 if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
852 return m_errlog_defer(scanent, errstr);
854 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
855 if (bread > 0) av_buffer[bread]='\0';
857 return m_errlog_defer_3(scanent,
858 string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
860 for (j = 0; j < bread; j++)
861 if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
865 /* pass the mailfile to fsecure */
866 file_name = string_sprintf("SCAN\t%s\n", eml_filename);
868 if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
869 return m_errlog_defer(scanent, errstr);
872 /* todo also SUSPICION\t */
873 fs_inf = m_pcre_compile(US"\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$", &errstr);
875 /* read report, linewise. Apply a timeout as the Fsecure daemon
876 sometimes wants an answer to "PING" but they won't tell us what */
878 uschar * p = av_buffer;
884 i = av_buffer+sizeof(av_buffer)-p;
885 if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
886 return m_errlog_defer_3(scanent,
887 string_sprintf("unable to read result (%s)", strerror(errno)),
890 for (p[bread] = '\0'; q = strchr(p, '\n'); p = q+1)
894 /* Really search for virus again? */
896 /* try matcher on the line, grab substring */
897 malware_name = m_pcre_exec(fs_inf, p);
899 if (Ustrstr(p, "OK\tScan ok."))
903 /* copy down the trailing partial line then read another chunk */
904 i = av_buffer+sizeof(av_buffer)-p;
905 memmove(av_buffer, p, i);
914 case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
918 uschar * scanrequest;
920 unsigned long kav_reportlen, bread;
924 /* get current date and time, build scan request */
926 /* pdp note: before the eml_filename parameter, this scanned the
927 directory; not finding documentation, so we'll strip off the directory.
928 The side-effect is that the test framework scanning may end up in
929 scanning more than was requested, but for the normal interface, this is
932 strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
933 scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
934 p = Ustrrchr(scanrequest, '/');
938 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
939 scanner_name, scanner_options);
941 /* send scan request */
942 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
943 return m_errlog_defer(scanent, errstr);
945 /* wait for result */
946 if (!recv_len(sock, tmpbuf, 2, tmo))
947 return m_errlog_defer_3(scanent,
948 US"unable to read 2 bytes from socket.", sock);
950 /* get errorcode from one nibble */
951 kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
954 case 5: case 6: /* improper kavdaemon configuration */
955 return m_errlog_defer_3(scanent,
956 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
959 return m_errlog_defer_3(scanent,
960 US"reported 'scanning not completed' (code 1).", sock);
962 return m_errlog_defer_3(scanent,
963 US"reported 'kavdaemon damaged' (code 7).", sock);
966 /* code 8 is not handled, since it is ambigous. It appears mostly on
967 bounces where part of a file has been cut off */
969 /* "virus found" return codes (2-4) */
970 if (kav_rc > 1 && kav_rc < 5)
974 /* setup default virus name */
975 malware_name = US"unknown";
977 report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
979 /* read the report, if available */
980 if (report_flag == 1)
982 /* read report size */
983 if (!recv_len(sock, &kav_reportlen, 4, tmo))
984 return m_errlog_defer_3(scanent,
985 US"cannot read report size", sock);
987 /* it's possible that avp returns av_buffer[1] == 1 but the
988 reportsize is 0 (!?) */
989 if (kav_reportlen > 0)
991 /* set up match regex, depends on retcode */
992 kav_re = m_pcre_compile( kav_rc == 3
993 ? US"suspicion:\\s*(.+?)\\s*$"
994 : US"infected:\\s*(.+?)\\s*$",
997 /* read report, linewise */
998 while (kav_reportlen > 0)
1000 if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1002 kav_reportlen -= bread+1;
1004 /* try matcher on the line, grab substring */
1005 if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1011 else /* no virus found */
1012 malware_name = NULL;
1017 case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1019 const uschar *cmdline_scanner = scanner_options;
1020 const pcre *cmdline_trigger_re;
1021 const pcre *cmdline_regex_re;
1023 uschar * commandline;
1024 void (*eximsigchld)(int);
1025 void (*eximsigpipe)(int);
1026 FILE *scanner_out = NULL;
1028 FILE *scanner_record = NULL;
1029 uschar linebuffer[32767];
1034 if (!cmdline_scanner)
1035 return m_errlog_defer(scanent, errstr);
1037 /* find scanner output trigger */
1038 cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1039 "missing trigger specification", &errstr);
1040 if (!cmdline_trigger_re)
1041 return m_errlog_defer(scanent, errstr);
1043 /* find scanner name regex */
1044 cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1045 "missing virus name regex specification", &errstr);
1046 if (!cmdline_regex_re)
1047 return m_errlog_defer(scanent, errstr);
1049 /* prepare scanner call; despite the naming, file_name holds a directory
1050 name which is documented as the value given to %s. */
1052 file_name = string_copy(eml_filename);
1053 p = Ustrrchr(file_name, '/');
1056 commandline = string_sprintf(CS cmdline_scanner, file_name);
1058 /* redirect STDERR too */
1059 commandline = string_sprintf("%s 2>&1", commandline);
1061 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
1062 scanner_name, commandline);
1064 /* store exims signal handlers */
1065 eximsigchld = signal(SIGCHLD,SIG_DFL);
1066 eximsigpipe = signal(SIGPIPE,SIG_DFL);
1068 if (!(scanner_out = popen(CS commandline,"r")))
1071 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1072 return m_errlog_defer(scanent,
1073 string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1075 scanner_fd = fileno(scanner_out);
1077 file_name = string_sprintf("%s/scan/%s/%s_scanner_output",
1078 spool_directory, message_id, message_id);
1080 if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1083 (void) pclose(scanner_out);
1084 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1085 return m_errlog_defer(scanent, string_sprintf(
1086 "opening scanner output file (%s) failed: %s.",
1087 file_name, strerror(err)));
1090 /* look for trigger while recording output */
1091 while ((rcnt = recv_line(scanner_fd, linebuffer,
1092 sizeof(linebuffer), tmo)))
1100 (void) pclose(scanner_out);
1101 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1102 return m_errlog_defer(scanent, string_sprintf(
1103 "unable to read from scanner (%s): %s",
1104 commandline, strerror(err)));
1107 if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1110 (void) pclose(scanner_out);
1111 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1112 return m_errlog_defer(scanent, string_sprintf(
1113 "short write on scanner output file (%s).", file_name));
1115 putc('\n', scanner_record);
1116 /* try trigger match */
1118 && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1123 (void)fclose(scanner_record);
1124 sep = pclose(scanner_out);
1125 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1127 return m_errlog_defer(scanent,
1129 ? string_sprintf("running scanner failed: %s", strerror(sep))
1130 : string_sprintf("scanner returned error code: %d", sep));
1135 /* setup default virus name */
1136 malware_name = US"unknown";
1138 /* re-open the scanner output file, look for name match */
1139 scanner_record = fopen(CS file_name, "rb");
1140 while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1143 if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1146 (void)fclose(scanner_record);
1148 else /* no virus found */
1149 malware_name = NULL;
1153 case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1158 uschar av_buffer[1024];
1160 /* pass the scan directory to sophie */
1161 file_name = string_copy(eml_filename);
1162 if ((p = Ustrrchr(file_name, '/')))
1165 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
1166 scanner_name, scanner_options);
1168 if ( write(sock, file_name, Ustrlen(file_name)) < 0
1169 || write(sock, "\n", 1) != 1
1171 return m_errlog_defer_3(scanent,
1172 string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1175 /* wait for result */
1176 memset(av_buffer, 0, sizeof(av_buffer));
1177 if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1178 return m_errlog_defer_3(scanent,
1179 string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1183 if (av_buffer[0] == '1') {
1184 uschar * s = Ustrchr(av_buffer, '\n');
1187 malware_name = string_copy(&av_buffer[2]);
1189 else if (!strncmp(CS av_buffer, "-1", 2))
1190 return m_errlog_defer_3(scanent, US"scanner reported error", sock);
1191 else /* all ok, no virus */
1192 malware_name = NULL;
1197 case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1199 /* This code was originally contributed by David Saez */
1200 /* There are three scanning methods available to us:
1201 * (1) Use the SCAN command, pointing to a file in the filesystem
1202 * (2) Use the STREAM command, send the data on a separate port
1203 * (3) Use the zINSTREAM command, send the data inline
1204 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1205 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1206 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1207 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless
1208 * WITH_OLD_CLAMAV_STREAM is defined.
1209 * See Exim bug 926 for details. */
1211 uschar *p, *vname, *result_tag, *response_end;
1214 uschar av_buffer[1024];
1215 uschar *hostname = US"";
1217 uschar *clamav_fbuf;
1218 int clam_fd, result;
1220 unsigned int fsize_uint;
1221 BOOL use_scan_command = FALSE;
1222 clamd_address_container * clamd_address_vector[MAX_CLAMD_SERVERS];
1224 int num_servers = 0;
1225 #ifdef WITH_OLD_CLAMAV_STREAM
1227 uschar av_buffer2[1024];
1230 uint32_t send_size, send_final_zeroblock;
1233 if (*scanner_options == '/')
1234 /* Local file; so we def want to use_scan_command and don't want to try
1235 * passing IP/port combinations */
1236 use_scan_command = TRUE;
1239 const uschar *address = scanner_options;
1240 uschar address_buffer[MAX_CLAMD_ADDRESS_LENGTH + 20];
1242 /* Go through the rest of the list of host/port and construct an array
1243 * of servers to try. The first one is the bit we just passed from
1244 * scanner_options so process that first and then scan the remainder of
1245 * the address buffer */
1248 clamd_address_container *this_clamd;
1250 /* The 'local' option means use the SCAN command over the network
1251 * socket (ie common file storage in use) */
1252 if (strcmpic(address,US"local") == 0)
1254 use_scan_command = TRUE;
1258 /* XXX: If unsuccessful we should free this memory */
1260 (clamd_address_container *)store_get(sizeof(clamd_address_container));
1262 /* extract host and port part */
1263 if( sscanf(CS address, "%" MAX_CLAMD_ADDRESS_LENGTH_S "s %u",
1264 this_clamd->tcp_addr, &(this_clamd->tcp_port)) != 2 )
1266 (void) m_errlog_defer(scanent,
1267 string_sprintf("invalid address '%s'", address));
1271 clamd_address_vector[num_servers] = this_clamd;
1273 if (num_servers >= MAX_CLAMD_SERVERS)
1275 (void) m_errlog_defer(scanent,
1276 US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1277 "specified; only using the first " MAX_CLAMD_SERVERS_S );
1280 } while ((address = string_nextinlist(&av_scanner_work, &sep,
1282 sizeof(address_buffer))) != NULL);
1284 /* check if we have at least one server */
1286 return m_errlog_defer(scanent,
1287 US"no useable server addresses in malware configuration option.");
1290 /* See the discussion of response formats below to see why we really
1291 don't like colons in filenames when passing filenames to ClamAV. */
1292 if (use_scan_command && Ustrchr(eml_filename, ':'))
1293 return m_errlog_defer(scanent,
1294 string_sprintf("local/SCAN mode incompatible with" \
1295 " : in path to email filename [%s]", eml_filename));
1297 /* We have some network servers specified */
1300 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1301 * only supports AF_INET, but we should probably be looking to the
1302 * future and rewriting this to be protocol-independent anyway. */
1304 while (num_servers > 0)
1307 /* Randomly pick a server to start with */
1308 current_server = random_number( num_servers );
1311 debug_printf("trying server name %s, port %u\n",
1312 clamd_address_vector[current_server]->tcp_addr,
1313 clamd_address_vector[current_server]->tcp_port);
1315 /* Lookup the host. This is to ensure that we connect to the same IP
1316 * on both connections (as one host could resolve to multiple ips) */
1317 sock= m_tcpsocket(clamd_address_vector[current_server]->tcp_addr,
1318 clamd_address_vector[current_server]->tcp_port,
1319 &connhost, &errstr);
1322 /* Connection successfully established with a server */
1323 hostname = clamd_address_vector[current_server]->tcp_addr;
1327 (void) m_errlog_defer(scanent, errstr);
1329 /* Remove the server from the list. XXX We should free the memory */
1331 for (i = current_server; i < num_servers; i++)
1332 clamd_address_vector[i] = clamd_address_vector[i+1];
1335 if (num_servers == 0)
1336 return m_errlog_defer(scanent, US"all servers failed");
1340 if ((sock = m_unixsocket(scanner_options, &errstr)) < 0)
1341 return m_errlog_defer(scanent, errstr);
1344 /* have socket in variable "sock"; command to use is semi-independent of
1345 * the socket protocol. We use SCAN if is local (either Unix/local
1346 * domain socket, or explicitly told local) else we stream the data.
1347 * How we stream the data depends upon how we were built. */
1349 if (!use_scan_command)
1351 #ifdef WITH_OLD_CLAMAV_STREAM
1352 /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1353 * that port on a second connection; then in the scan-method-neutral
1354 * part, read the response back on the original connection. */
1356 DEBUG(D_acl) debug_printf(
1357 "Malware scan: issuing %s old-style remote scan (PORT)\n",
1360 /* Pass the string to ClamAV (7 = "STREAM\n") */
1361 if (m_sock_send(sock, US"STREAM\n", 7, &errstr) < 0)
1362 return m_errlog_defer(scanent, errstr);
1364 memset(av_buffer2, 0, sizeof(av_buffer2));
1365 bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
1368 return m_errlog_defer_3(scanent,
1369 string_sprintf("unable to read PORT from socket (%s)",
1373 if (bread == sizeof(av_buffer2))
1374 return m_errlog_defer_3(scanent, "buffer too small", sock);
1377 return m_errlog_defer_3(scanent, "ClamAV returned null", sock);
1379 av_buffer2[bread] = '\0';
1380 if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 )
1381 return m_errlog_defer_3(scanent,
1382 string_sprintf("Expected port information from clamd, got '%s'",
1386 sockData = m_tcpsocket(connhost.address, port, NULL, &errstr);
1388 return m_errlog_defer_3(scanent, errstr, sock);
1390 # define CLOSE_SOCKDATA (void)close(sockData)
1391 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1392 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1393 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1396 DEBUG(D_acl) debug_printf(
1397 "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1400 /* Pass the string to ClamAV (10 = "zINSTREAM\0") */
1401 if (send(sock, "zINSTREAM", 10, 0) < 0)
1402 return m_errlog_defer_3(scanent,
1403 string_sprintf("unable to send zINSTREAM to socket (%s)",
1407 # define CLOSE_SOCKDATA /**/
1410 /* calc file size */
1411 if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1415 return m_errlog_defer_3(scanent,
1416 string_sprintf("can't open spool file %s: %s",
1417 eml_filename, strerror(err)),
1420 if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1423 CLOSE_SOCKDATA; (void)close(clam_fd);
1424 return m_errlog_defer_3(scanent,
1425 string_sprintf("can't seek spool file %s: %s",
1426 eml_filename, strerror(err)),
1429 fsize_uint = (unsigned int) fsize;
1430 if ((off_t)fsize_uint != fsize)
1432 CLOSE_SOCKDATA; (void)close(clam_fd);
1433 return m_errlog_defer_3(scanent,
1434 string_sprintf("seeking spool file %s, size overflow",
1438 lseek(clam_fd, 0, SEEK_SET);
1440 if (!(clamav_fbuf = (uschar *) malloc (fsize_uint)))
1442 CLOSE_SOCKDATA; (void)close(clam_fd);
1443 return m_errlog_defer_3(scanent,
1444 string_sprintf("unable to allocate memory %u for file (%s)",
1445 fsize_uint, eml_filename),
1449 if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1452 free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd);
1453 return m_errlog_defer_3(scanent,
1454 string_sprintf("can't read spool file %s: %s",
1455 eml_filename, strerror(err)),
1458 (void)close(clam_fd);
1460 /* send file body to socket */
1461 #ifdef WITH_OLD_CLAMAV_STREAM
1462 if (send(sockData, clamav_fbuf, fsize_uint, 0) < 0)
1464 free(clamav_fbuf); CLOSE_SOCKDATA;
1465 return m_errlog_defer_3(scanent,
1466 string_sprintf("unable to send file body to socket (%s:%u)",
1471 send_size = htonl(fsize_uint);
1472 send_final_zeroblock = 0;
1473 if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1474 (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1475 (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1478 return m_errlog_defer_3(scanent,
1479 string_sprintf("unable to send file body to socket (%s)", hostname),
1487 #undef CLOSE_SOCKDATA
1490 { /* use scan command */
1491 /* Send a SCAN command pointing to a filename; then in the then in the
1492 * scan-method-neutral part, read the response back */
1494 /* ================================================================= */
1496 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1497 which dates to when ClamAV needed us to break apart the email into the
1498 MIME parts (eg, with the now deprecated demime condition coming first).
1499 Some time back, ClamAV gained the ability to deconstruct the emails, so
1500 doing this would actually have resulted in the mail attachments being
1501 scanned twice, in the broken out files and from the original .eml.
1502 Since ClamAV now handles emails (and has for quite some time) we can
1503 just use the email file itself. */
1504 /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
1505 file_name = string_sprintf("SCAN %s\n", eml_filename);
1507 DEBUG(D_acl) debug_printf(
1508 "Malware scan: issuing %s local-path scan [%s]\n",
1509 scanner_name, scanner_options);
1511 if (send(sock, file_name, Ustrlen(file_name), 0) < 0)
1512 return m_errlog_defer_3(scanent,
1513 string_sprintf("unable to write to socket (%s)", strerror(errno)),
1516 /* Do not shut down the socket for writing; a user report noted that
1517 * clamd 0.70 does not react well to this. */
1519 /* Commands have been sent, no matter which scan method or connection
1520 * type we're using; now just read the result, independent of method. */
1522 /* Read the result */
1523 memset(av_buffer, 0, sizeof(av_buffer));
1524 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1529 return m_errlog_defer(scanent,
1530 string_sprintf("unable to read from socket (%s)",
1531 errno == 0 ? "EOF" : strerror(errno)));
1533 if (bread == sizeof(av_buffer))
1534 return m_errlog_defer(scanent, US"buffer too small");
1535 /* We're now assured of a NULL at the end of av_buffer */
1537 /* Check the result. ClamAV returns one of two result formats.
1538 In the basic mode, the response is of the form:
1539 infected: -> "<filename>: <virusname> FOUND"
1540 not-infected: -> "<filename>: OK"
1541 error: -> "<filename>: <errcode> ERROR
1542 If the ExtendedDetectionInfo option has been turned on, then we get:
1543 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1544 for the infected case. Compare:
1545 /tmp/eicar.com: Eicar-Test-Signature FOUND
1546 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1548 In the streaming case, clamd uses the filename "stream" which you should
1549 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1550 client app will replace "stream" with the original filename before returning
1551 results to stdout, but the trace shows the data).
1553 We will assume that the pathname passed to clamd from Exim does not contain
1554 a colon. We will have whined loudly above if the eml_filename does (and we're
1555 passing a filename to clamd). */
1558 return m_errlog_defer(scanent, US"ClamAV returned null");
1560 /* strip newline at the end (won't be present for zINSTREAM)
1561 (also any trailing whitespace, which shouldn't exist, but we depend upon
1562 this below, so double-check) */
1563 p = av_buffer + Ustrlen(av_buffer) - 1;
1564 if (*p == '\n') *p = '\0';
1566 DEBUG(D_acl) debug_printf("Malware response: %s\n", av_buffer);
1568 while (isspace(*--p) && (p > av_buffer))
1573 /* colon in returned output? */
1574 if((p = Ustrchr(av_buffer,':')) == NULL)
1575 return m_errlog_defer(scanent, string_sprintf(
1576 "ClamAV returned malformed result (missing colon): %s",
1579 /* strip filename */
1580 while (*p && isspace(*++p)) /**/;
1583 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1584 but we should at least be resistant to it. */
1585 p = Ustrrchr(vname, ' ');
1586 result_tag = p ? p+1 : vname;
1588 if (Ustrcmp(result_tag, "FOUND") == 0)
1590 /* p should still be the whitespace before the result_tag */
1591 while (isspace(*p)) --p;
1593 /* Strip off the extended information too, which will be in parens
1594 after the virus name, with no intervening whitespace. */
1597 /* "(hash:size)", so previous '(' will do; if not found, we have
1598 a curious virus name, but not an error. */
1599 p = Ustrrchr(vname, '(');
1603 malware_name = string_copy(vname);
1604 DEBUG(D_acl) debug_printf("Malware found, name \"%s\"\n", malware_name);
1607 else if (Ustrcmp(result_tag, "ERROR") == 0)
1608 return m_errlog_defer(scanent,
1609 string_sprintf("ClamAV returned: %s", av_buffer));
1611 else if (Ustrcmp(result_tag, "OK") == 0)
1613 /* Everything should be OK */
1614 malware_name = NULL;
1615 DEBUG(D_acl) debug_printf("Malware not found\n");
1619 return m_errlog_defer(scanent,
1620 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1625 case M_SOCK: /* "sock" scanner type ------------------------------------- */
1626 /* This code was derived by Martin Poole from the clamd code contributed
1627 by David Saez and the cmdline code
1631 uschar * commandline;
1632 uschar av_buffer[1024];
1633 uschar * linebuffer;
1634 uschar * sockline_scanner;
1635 uschar sockline_scanner_default[] = "%s\n";
1636 const pcre *sockline_trig_re;
1637 const pcre *sockline_name_re;
1639 /* find scanner command line */
1640 if ((sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1642 { /* check for no expansions apart from one %s */
1643 uschar * s = Ustrchr(sockline_scanner, '%');
1645 if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1646 return m_errlog_defer_3(scanent,
1647 US"unsafe sock scanner call spec", sock);
1650 sockline_scanner = sockline_scanner_default;
1652 /* find scanner output trigger */
1653 sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1654 "missing trigger specification", &errstr);
1655 if (!sockline_trig_re)
1656 return m_errlog_defer_3(scanent, errstr, sock);
1658 /* find virus name regex */
1659 sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1660 "missing virus name regex specification", &errstr);
1661 if (!sockline_name_re)
1662 return m_errlog_defer_3(scanent, errstr, sock);
1664 /* prepare scanner call - security depends on expansions check above */
1665 commandline = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
1666 commandline = string_sprintf( CS sockline_scanner, CS commandline);
1669 /* Pass the command string to the socket */
1670 if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1671 return m_errlog_defer(scanent, errstr);
1673 /* Read the result */
1674 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1677 return m_errlog_defer_3(scanent,
1678 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1681 if (bread == sizeof(av_buffer))
1682 return m_errlog_defer_3(scanent, US"buffer too small", sock);
1683 av_buffer[bread] = '\0';
1684 linebuffer = string_copy(av_buffer);
1686 /* try trigger match */
1687 if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1689 if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1690 malware_name = US "unknown";
1692 else /* no virus found */
1693 malware_name = NULL;
1697 case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1699 char *mksd_options_end;
1700 int mksd_maxproc = 1; /* default, if no option supplied */
1703 if (scanner_options)
1705 mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1706 if ( *scanner_options == '\0'
1707 || *mksd_options_end != '\0'
1709 || mksd_maxproc > 32
1711 return m_errlog_defer(scanent,
1712 string_sprintf("invalid option '%s'", scanner_options));
1715 if((sock = m_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1716 return m_errlog_defer(scanent, errstr);
1718 malware_name = NULL;
1720 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan\n", scanner_name);
1722 if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1730 case M_AVAST: /* "avast" scanner type ----------------------------------- */
1734 uschar * scanrequest;
1735 const pcre * avast_clean_re, * avast_virus_re;
1736 enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1739 /* According to Martin Tuma @avast the protocol uses "escaped
1740 whitespace", that is, every embedded whitespace is backslash
1741 escaped, as well as backslash is protected by backslash.
1742 The returned lines contain the name of the scanned file, a tab
1746 [E] - some error occured
1747 Such marker follows the first non-escaped TAB. */
1748 if ( !(avast_clean_re =
1749 m_pcre_compile(US"(?!\\\\)\\t\\[\\+\\]", &errstr))
1750 || !(avast_virus_re =
1751 m_pcre_compile(US"(?!\\\\)\\t\\[L\\]\\d\\.\\d\\t\\d\\s(.*)",
1754 return malware_errlog_defer(errstr);
1756 /* wait for result */
1757 for (avast_stage = AVA_HELO;
1758 (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1761 int slen = Ustrlen(buf);
1764 DEBUG(D_acl) debug_printf("got from avast: %s\n", buf);
1765 switch (avast_stage)
1768 if (Ustrncmp(buf, "220", 3) != 0)
1769 goto endloop; /* require a 220 */
1773 if (Ustrncmp(buf, "210", 3) == 0)
1774 break; /* ignore 210 responses */
1775 if (Ustrncmp(buf, "200", 3) != 0)
1776 goto endloop; /* require a 200 */
1781 /* Check for another option to send. Newline-terminate it. */
1782 if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1785 scanrequest = string_sprintf("%s\n", scanrequest);
1786 avast_stage = AVA_OPT; /* just sent option */
1790 scanrequest = string_sprintf("SCAN %s/scan/%s\n",
1791 spool_directory, message_id);
1792 avast_stage = AVA_RSP; /* just sent command */
1795 /* send config-cmd or scan-request to socket */
1796 len = Ustrlen(scanrequest);
1797 if (send(sock, scanrequest, len, 0) < 0)
1799 scanrequest[len-1] = '\0';
1800 return m_errlog_defer_3(scanent, string_sprintf(
1801 "unable to send request '%s' to socket (%s): %s",
1802 scanrequest, scanner_options, strerror(errno)), sock);
1808 if (Ustrncmp(buf, "210", 3) == 0)
1809 break; /* ignore the "210 SCAN DATA" message */
1811 if (pcre_exec(avast_clean_re, NULL, CS buf, slen,
1812 0, 0, ovector, nelements(ovector)) > 0)
1815 if ((malware_name = m_pcre_exec(avast_virus_re, buf)))
1816 { /* remove backslash in front of [whitespace|backslash] */
1818 for (p = malware_name; *p; ++p)
1819 if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
1820 for (p0 = p; *p0; ++p0) *p0 = p0[1];
1822 avast_stage = AVA_DONE;
1826 if (Ustrncmp(buf, "200 SCAN OK", 11) == 0)
1827 { /* we're done finally */
1828 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1829 return m_errlog_defer_3(scanent, string_sprintf(
1830 "unable to send quit request to socket (%s): %s",
1831 scanner_options, strerror(errno)),
1833 malware_name = NULL;
1834 avast_stage = AVA_DONE;
1838 /* here for any unexpected response from the scanner */
1849 case AVA_RSP: return m_errlog_defer_3(scanent,
1852 "invalid response from scanner: '%s'", buf)
1854 ? US"EOF from scanner"
1855 : US"timeout from scanner",
1861 } /* scanner type switch */
1864 (void) close (sock);
1865 malware_ok = TRUE; /* set "been here, done that" marker */
1868 /* match virus name against pattern (caseless ------->----------v) */
1869 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
1871 DEBUG(D_acl) debug_printf(
1872 "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
1880 /*************************************************
1881 * Scan an email for malware *
1882 *************************************************/
1884 /* This is the normal interface for scanning an email, which doesn't need a
1885 filename; it's a wrapper around the malware_file function.
1888 malware_re match condition for "malware="
1889 timeout if nonzero, timeout in seconds
1891 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
1892 where true means malware was found (condition applies)
1895 malware(const uschar * malware_re, int timeout)
1897 uschar * scan_filename;
1900 scan_filename = string_sprintf("%s/scan/%s/%s.eml",
1901 spool_directory, message_id, message_id);
1902 ret = malware_internal(malware_re, scan_filename, timeout, FALSE);
1903 if (ret == DEFER) av_failed = TRUE;
1909 /*************************************************
1910 * Scan a file for malware *
1911 *************************************************/
1913 /* This is a test wrapper for scanning an email, which is not used in
1914 normal processing. Scan any file, using the Exim scanning interface.
1915 This function tampers with various global variables so is unsafe to use
1916 in any other context.
1919 eml_filename a file holding the message to be scanned
1921 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
1922 where true means malware was found (condition applies)
1925 malware_in_file(uschar *eml_filename)
1927 uschar message_id_buf[64];
1930 /* spool_mbox() assumes various parameters exist, when creating
1931 the relevant directory and the email within */
1932 (void) string_format(message_id_buf, sizeof(message_id_buf),
1933 "dummy-%d", vaguely_random_number(INT_MAX));
1934 message_id = message_id_buf;
1935 sender_address = US"malware-sender@example.net";
1937 recipients_list = NULL;
1938 receive_add_recipient(US"malware-victim@example.net", -1);
1939 enable_dollar_recipients = TRUE;
1941 ret = malware_internal(US"*", eml_filename, 0, TRUE);
1943 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
1945 /* don't set no_mbox_unspool; at present, there's no way for it to become
1946 set, but if that changes, then it should apply to these tests too */
1949 /* silence static analysis tools */
1955 #endif /*WITH_CONTENT_SCAN*/