1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4 
5 /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
6  * License: GPL
7  * Copyright (c) The Exim Maintainers 2015 - 2020
8  */
9 
10 /* Code for calling virus (malware) scanners. Called from acl.c. */
11 
12 #include "exim.h"
13 #ifdef WITH_CONTENT_SCAN	/* entire file */
14 
15 typedef enum {
16 #ifndef DISABLE_MAL_FFROTD
17 	M_FPROTD,
18 #endif
19 #ifndef DISABLE_MAL_FFROT6D
20 	M_FPROT6D,
21 #endif
22 #ifndef DISABLE_MAL_DRWEB
23 	M_DRWEB,
24 #endif
25 #ifndef DISABLE_MAL_AVE
26 	M_AVES,
27 #endif
28 #ifndef DISABLE_MAL_FSECURE
29 	M_FSEC,
30 #endif
31 #ifndef DISABLE_MAL_KAV
32 	M_KAVD,
33 #endif
34 #ifndef DISABLE_MAL_SOPHIE
35 	M_SOPHIE,
36 #endif
37 #ifndef DISABLE_MAL_CLAM
38 	M_CLAMD,
39 #endif
40 #ifndef DISABLE_MAL_MKS
41 	M_MKSD,
42 #endif
43 #ifndef DISABLE_MAL_AVAST
44 	M_AVAST,
45 #endif
46 #ifndef DISABLE_MAL_SOCK
47 	M_SOCK,
48 #endif
49 #ifndef DISABLE_MAL_CMDLINE
50 	M_CMDL,
51 #endif
52 	M_DUMMY
53 	} scanner_t;
54 typedef enum {MC_NONE, MC_TCP, MC_UNIX, MC_STRM} contype_t;
55 static struct scan
56 {
57   scanner_t	scancode;
58   const uschar * name;
59   const uschar * options_default;
60   contype_t	conn;
61 } m_scans[] =
62 {
63 #ifndef DISABLE_MAL_FFROTD
64   { M_FPROTD,	US"f-protd",	US"localhost 10200-10204",	      MC_TCP },
65 #endif
66 #ifndef DISABLE_MAL_FFROT6D
67   { M_FPROT6D,	US"f-prot6d",	US"localhost 10200",		      MC_TCP },
68 #endif
69 #ifndef DISABLE_MAL_DRWEB
70   { M_DRWEB,	US"drweb",	US"/usr/local/drweb/run/drwebd.sock", MC_STRM },
71 #endif
72 #ifndef DISABLE_MAL_AVE
73   { M_AVES,	US"aveserver",	US"/var/run/aveserver",		      MC_UNIX },
74 #endif
75 #ifndef DISABLE_MAL_FSECURE
76   { M_FSEC,	US"fsecure",	US"/var/run/.fsav",		      MC_UNIX },
77 #endif
78 #ifndef DISABLE_MAL_KAV
79   { M_KAVD,	US"kavdaemon",	US"/var/run/AvpCtl",		      MC_UNIX },
80 #endif
81 #ifndef DISABLE_MAL_SOPHIE
82   { M_SOPHIE,	US"sophie",	US"/var/run/sophie",		      MC_UNIX },
83 #endif
84 #ifndef DISABLE_MAL_CLAM
85   { M_CLAMD,	US"clamd",	US"/tmp/clamd",			      MC_NONE },
86 #endif
87 #ifndef DISABLE_MAL_MKS
88   { M_MKSD,	US"mksd",	NULL,				      MC_NONE },
89 #endif
90 #ifndef DISABLE_MAL_AVAST
91   { M_AVAST,	US"avast",	US"/var/run/avast/scan.sock",	      MC_STRM },
92 #endif
93 #ifndef DISABLE_MAL_SOCK
94   { M_SOCK,	US"sock",	US"/tmp/malware.sock",		      MC_STRM },
95 #endif
96 #ifndef DISABLE_MAL_CMDLINE
97   { M_CMDL,	US"cmdline",	NULL,				      MC_NONE },
98 #endif
99   { -1,		NULL,		NULL, MC_NONE }		/* end-marker */
100 };
101 
102 /******************************************************************************/
103 # ifdef MACRO_PREDEF		/* build solely to predefine macros */
104 
105 #  include "macro_predef.h"
106 
107 void
features_malware(void)108 features_malware(void)
109 {
110 const uschar * s;
111 uschar * t;
112 uschar buf[EXIM_DRIVERNAME_MAX];
113 
114 spf(buf, sizeof(buf), US"_HAVE_MALWARE_");
115 
116 for (const struct scan * sc = m_scans; sc->scancode != -1; sc++)
117   {
118   for (s = sc->name, t = buf+14; *s; s++) if (*s != '-')
119     *t++ = toupper(*s);
120   *t = '\0';
121   builtin_macro_create(buf);
122   }
123 }
124 
125 /******************************************************************************/
126 # else	/*!MACRO_PREDEF, main build*/
127 
128 
129 #define MALWARE_TIMEOUT 120	/* default timeout, seconds */
130 
131 static const uschar * malware_regex_default = US ".+";
132 static const pcre * malware_default_re = NULL;
133 
134 
135 #ifndef DISABLE_MAL_CLAM
136 /* The maximum number of clamd servers that are supported in the configuration */
137 # define MAX_CLAMD_SERVERS 32
138 # define MAX_CLAMD_SERVERS_S "32"
139 
140 typedef struct clamd_address {
141   uschar * hostspec;
142   unsigned tcp_port;
143   unsigned retry;
144 } clamd_address;
145 #endif
146 
147 
148 #ifndef DISABLE_MAL_DRWEB
149 # define DRWEBD_SCAN_CMD             (1)     /* scan file, buffer or diskfile */
150 # define DRWEBD_RETURN_VIRUSES       (1<<0)   /* ask daemon return to us viruses names from report */
151 # define DRWEBD_IS_MAIL              (1<<19)  /* say to daemon that format is "archive MAIL" */
152 
153 # define DERR_READ_ERR               (1<<0)   /* read error */
154 # define DERR_NOMEMORY               (1<<2)   /* no memory */
155 # define DERR_TIMEOUT                (1<<9)   /* scan timeout has run out */
156 # define DERR_BAD_CALL               (1<<15)  /* wrong command */
157 
158 static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$";
159 static const pcre * drweb_re = NULL;
160 #endif
161 
162 #ifndef DISABLE_MAL_FSECURE
163 static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$";
164 static const pcre * fsec_re = NULL;
165 #endif
166 
167 #ifndef DISABLE_MAL_KAV
168 static const uschar * kav_re_sus_str = US "suspicion:\\s*(.+?)\\s*$";
169 static const uschar * kav_re_inf_str = US "infected:\\s*(.+?)\\s*$";
170 static const pcre * kav_re_sus = NULL;
171 static const pcre * kav_re_inf = NULL;
172 #endif
173 
174 #ifndef DISABLE_MAL_AVAST
175 static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]";
176 static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d+\\.0\\t0\\s(.*)";
177 static const uschar * ava_re_error_str = US "(?!\\\\)\\t\\[E\\]\\d+\\.0\\tError\\s\\d+\\s(.*)";
178 static const pcre * ava_re_clean = NULL;
179 static const pcre * ava_re_virus = NULL;
180 static const pcre * ava_re_error = NULL;
181 #endif
182 
183 #ifndef DISABLE_MAL_FFROT6D
184 static const uschar * fprot6d_re_error_str = US "^\\d+\\s<(.+?)>$";
185 static const uschar * fprot6d_re_virus_str = US "^\\d+\\s<infected:\\s+(.+?)>\\s+.+$";
186 static const pcre * fprot6d_re_error = NULL;
187 static const pcre * fprot6d_re_virus = NULL;
188 #endif
189 
190 
191 
192 /******************************************************************************/
193 
194 #ifndef DISABLE_MAL_KAV
195 /* Routine to check whether a system is big- or little-endian.
196    Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
197    Needed for proper kavdaemon implementation. Sigh. */
198 # define BIG_MY_ENDIAN      0
199 # define LITTLE_MY_ENDIAN   1
200 static int test_byte_order(void);
201 static inline int
test_byte_order()202 test_byte_order()
203 {
204   short int word = 0x0001;
205   char *byte = CS  &word;
206   return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
207 }
208 #endif
209 
210 BOOL malware_ok = FALSE;
211 
212 /* Gross hacks for the -bmalware option; perhaps we should just create
213 the scan directory normally for that case, but look into rigging up the
214 needed header variables if not already set on the command-line? */
215 extern int spool_mbox_ok;
216 extern uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
217 
218 
219 /* Some (currently avast only) use backslash escaped whitespace,
220 this function undoes these escapes */
221 
222 #ifndef DISABLE_MAL_AVAST
223 static inline void
unescape(uschar * p)224 unescape(uschar *p)
225 {
226 uschar *p0;
227 for (; *p; ++p)
228   if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
229     for (p0 = p; *p0; ++p0) *p0 = p0[1];
230 }
231 #endif
232 
233 /* --- malware_*_defer --- */
234 static inline int
malware_panic_defer(const uschar * str)235 malware_panic_defer(const uschar * str)
236 {
237 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
238 return DEFER;
239 }
240 static inline int
malware_log_defer(const uschar * str)241 malware_log_defer(const uschar * str)
242 {
243 log_write(0, LOG_MAIN, "malware acl condition: %s", str);
244 return DEFER;
245 }
246 /* --- m_*_defer --- */
247 static inline int
m_panic_defer(struct scan * scanent,const uschar * hostport,const uschar * str)248 m_panic_defer(struct scan * scanent, const uschar * hostport,
249   const uschar * str)
250 {
251 return malware_panic_defer(string_sprintf("%s %s : %s",
252   scanent->name, hostport ? hostport : CUS"", str));
253 }
254 /* --- m_*_defer_3 */
255 static inline int
m_panic_defer_3(struct scan * scanent,const uschar * hostport,const uschar * str,int fd_to_close)256 m_panic_defer_3(struct scan * scanent, const uschar * hostport,
257   const uschar * str, int fd_to_close)
258 {
259 DEBUG(D_acl) debug_print_socket(fd_to_close);
260 (void) close(fd_to_close);
261 return m_panic_defer(scanent, hostport, str);
262 }
263 
264 /*************************************************/
265 
266 #ifndef DISABLE_MAL_CLAM
267 /* Only used by the Clamav code, which is working from a list of servers and
268 uses the returned in_addr to get a second connection to the same system.
269 */
270 static inline int
m_tcpsocket(const uschar * hostname,unsigned int port,host_item * host,uschar ** errstr,const blob * fastopen_blob)271 m_tcpsocket(const uschar * hostname, unsigned int port,
272 	host_item * host, uschar ** errstr, const blob * fastopen_blob)
273 {
274 int fd = ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
275 			  host, errstr, fastopen_blob);
276 #ifdef EXIM_TFO_FREEBSD
277 /* Under some fault conditions, FreeBSD 12.2 seen to send a (non-TFO) SYN
278 and, getting no response, wait for a long time.  Impose a 5s max. */
279 if (fd >= 0)
280   (void) poll_one_fd(fd, POLLOUT, 5 * 1000);
281 #endif
282 return fd;
283 }
284 #endif
285 
286 static int
m_sock_send(int sock,uschar * buf,int cnt,uschar ** errstr)287 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
288 {
289 if (send(sock, buf, cnt, 0) < 0)
290   {
291   int err = errno;
292   (void)close(sock);
293   *errstr = string_sprintf("unable to send to socket (%s): %s",
294 	 buf, strerror(err));
295   return -1;
296   }
297 return sock;
298 }
299 
300 static const pcre *
m_pcre_compile(const uschar * re,uschar ** errstr)301 m_pcre_compile(const uschar * re, uschar ** errstr)
302 {
303 const uschar * rerror;
304 int roffset;
305 const pcre * cre;
306 
307 if (!(cre = pcre_compile(CS re, PCRE_COPT, CCSS &rerror, &roffset, NULL)))
308   *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
309       re, rerror, roffset);
310 return cre;
311 }
312 
313 uschar *
m_pcre_exec(const pcre * cre,uschar * text)314 m_pcre_exec(const pcre * cre, uschar * text)
315 {
316 int ovector[10*3];
317 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
318 	      ovector, nelem(ovector));
319 uschar * substr = NULL;
320 if (i >= 2)				/* Got it */
321   pcre_get_substring(CS text, ovector, i, 1, CCSS &substr);
322 return substr;
323 }
324 
325 static const pcre *
m_pcre_nextinlist(const uschar ** list,int * sep,char * listerr,uschar ** errstr)326 m_pcre_nextinlist(const uschar ** list, int * sep,
327  char * listerr, uschar ** errstr)
328 {
329 const uschar * list_ele;
330 const pcre * cre = NULL;
331 
332 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
333   *errstr = US listerr;
334 else
335   {
336   DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
337     string_printing(list_ele));
338   cre = m_pcre_compile(CUS list_ele, errstr);
339   }
340 return cre;
341 }
342 
343 
344 /*
345  Simple though inefficient wrapper for reading a line.  Drop CRs and the
346  trailing newline. Can return early on buffer full. Null-terminate.
347  Apply initial timeout if no data ready.
348 
349  Return: number of chars - zero for an empty line
350 	 -1 on EOF
351          -2 on timeout or error
352 */
353 static int
recv_line(int fd,uschar * buffer,int bsize,time_t tmo)354 recv_line(int fd, uschar * buffer, int bsize, time_t tmo)
355 {
356 uschar * p = buffer;
357 ssize_t rcv;
358 BOOL ok = FALSE;
359 
360 if (!fd_ready(fd, tmo))
361   return -2;
362 
363 /*XXX tmo handling assumes we always get a whole line */
364 /* read until \n */
365 errno = 0;
366 while ((rcv = read(fd, p, 1)) > 0)
367   {
368   ok = TRUE;
369   if (p-buffer > bsize-2) break;
370   if (*p == '\n') break;
371   if (*p != '\r') p++;
372   }
373 if (!ok)
374   {
375   DEBUG(D_acl)
376     {
377     debug_printf_indent("Malware scan: read %s (%s)\n",
378 		rcv==0 ? "EOF" : "error", strerror(errno));
379     debug_print_socket(fd);
380     }
381   return rcv==0 ? -1 : -2;
382   }
383 *p = '\0';
384 
385 DEBUG(D_acl) debug_printf_indent("Malware scan: read '%s'\n", buffer);
386 return p - buffer;
387 }
388 
389 /* return TRUE iff size as requested */
390 #ifndef DISABLE_MAL_DRWEB
391 static BOOL
recv_len(int sock,void * buf,int size,time_t tmo)392 recv_len(int sock, void * buf, int size, time_t tmo)
393 {
394 return fd_ready(sock, tmo)
395   ? recv(sock, buf, size, 0) == size
396   : FALSE;
397 }
398 #endif
399 
400 
401 
402 #ifndef DISABLE_MAL_MKS
403 /* ============= private routines for the "mksd" scanner type ============== */
404 
405 # include <sys/uio.h>
406 
407 static inline int
mksd_writev(int sock,struct iovec * iov,int iovcnt)408 mksd_writev (int sock, struct iovec * iov, int iovcnt)
409 {
410 int i;
411 
412 for (;;)
413   {
414   do
415     i = writev (sock, iov, iovcnt);
416   while (i < 0 && errno == EINTR);
417   if (i <= 0)
418     {
419     (void) malware_panic_defer(
420 	    US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
421     return -1;
422     }
423   for (;;)	/* check for short write */
424     if (i >= iov->iov_len)
425       {
426       if (--iovcnt == 0)
427 	return 0;
428       i -= iov->iov_len;
429       iov++;
430       }
431     else
432       {
433       iov->iov_len -= i;
434       iov->iov_base = CS iov->iov_base + i;
435       break;
436       }
437   }
438 }
439 
440 static inline int
mksd_read_lines(int sock,uschar * av_buffer,int av_buffer_size,time_t tmo)441 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, time_t tmo)
442 {
443 client_conn_ctx cctx = {.sock = sock};
444 int offset = 0;
445 int i;
446 
447 do
448   {
449   i = ip_recv(&cctx, av_buffer+offset, av_buffer_size-offset, tmo);
450   if (i <= 0)
451     {
452     (void) malware_panic_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
453     return -1;
454     }
455 
456   offset += i;
457   /* offset == av_buffer_size -> buffer full */
458   if (offset == av_buffer_size)
459     {
460     (void) malware_panic_defer(US"malformed reply received from mksd");
461     return -1;
462     }
463   } while (av_buffer[offset-1] != '\n');
464 
465 av_buffer[offset] = '\0';
466 return offset;
467 }
468 
469 static inline int
mksd_parse_line(struct scan * scanent,char * line)470 mksd_parse_line(struct scan * scanent, char * line)
471 {
472 char *p;
473 
474 switch (*line)
475   {
476   case 'O': /* OK */
477     return OK;
478 
479   case 'E':
480   case 'A': /* ERR */
481     if ((p = strchr (line, '\n')) != NULL)
482       *p = '\0';
483     return m_panic_defer(scanent, NULL,
484       string_sprintf("scanner failed: %s", line));
485 
486   default: /* VIR */
487     if ((p = strchr (line, '\n')) != NULL)
488       {
489       *p = '\0';
490       if (  p-line > 5
491          && line[3] == ' '
492 	 && (p = strchr(line+4, ' ')) != NULL
493 	 && p-line > 4
494 	 )
495 	{
496 	*p = '\0';
497 	malware_name = string_copy(US line+4);
498 	return OK;
499 	}
500       }
501     return m_panic_defer(scanent, NULL,
502       string_sprintf("malformed reply received: %s", line));
503   }
504 }
505 
506 static int
mksd_scan_packed(struct scan * scanent,int sock,const uschar * scan_filename,time_t tmo)507 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
508   time_t tmo)
509 {
510 struct iovec iov[3];
511 const char *cmd = "MSQ\n";
512 uschar av_buffer[1024];
513 
514 iov[0].iov_base = (void *) cmd;
515 iov[0].iov_len = 3;
516 iov[1].iov_base = (void *) scan_filename;
517 iov[1].iov_len = Ustrlen(scan_filename);
518 iov[2].iov_base = (void *) (cmd + 3);
519 iov[2].iov_len = 1;
520 
521 if (mksd_writev (sock, iov, 3) < 0)
522   return DEFER;
523 
524 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
525   return DEFER;
526 
527 return mksd_parse_line (scanent, CS av_buffer);
528 }
529 #endif	/* MKSD */
530 
531 
532 #ifndef DISABLE_MAL_CLAM
533 static int
clamd_option(clamd_address * cd,const uschar * optstr,int * subsep)534 clamd_option(clamd_address * cd, const uschar * optstr, int * subsep)
535 {
536 uschar * s;
537 
538 cd->retry = 0;
539 while ((s = string_nextinlist(&optstr, subsep, NULL, 0)))
540   if (Ustrncmp(s, "retry=", 6) == 0)
541     {
542     int sec = readconf_readtime((s += 6), '\0', FALSE);
543     if (sec < 0)
544       return FAIL;
545     cd->retry = sec;
546     }
547   else
548     return FAIL;
549 return OK;
550 }
551 #endif
552 
553 
554 
555 /*************************************************
556 *          Scan content for malware              *
557 *************************************************/
558 
559 /* This is an internal interface for scanning an email; the normal interface
560 is via malware(), or there's malware_in_file() used for testing/debugging.
561 
562 Arguments:
563   malware_re    match condition for "malware="
564   scan_filename  the file holding the email to be scanned, if we're faking
565 		this up for the -bmalware test, else NULL
566   timeout	if nonzero, non-default timeoutl
567 
568 Returns:        Exim message processing code (OK, FAIL, DEFER, ...)
569                 where true means malware was found (condition applies)
570 */
571 static int
malware_internal(const uschar * malware_re,const uschar * scan_filename,int timeout)572 malware_internal(const uschar * malware_re, const uschar * scan_filename,
573   int timeout)
574 {
575 int sep = 0;
576 const uschar *av_scanner_work = av_scanner;
577 uschar *scanner_name;
578 unsigned long mbox_size;
579 FILE *mbox_file;
580 const pcre *re;
581 uschar * errstr;
582 struct scan * scanent;
583 const uschar * scanner_options;
584 client_conn_ctx malware_daemon_ctx = {.sock = -1};
585 time_t tmo;
586 uschar * eml_filename, * eml_dir;
587 
588 if (!malware_re)
589   return FAIL;		/* empty means "don't match anything" */
590 
591 /* Ensure the eml mbox file is spooled up */
592 
593 if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
594   return malware_panic_defer(US"error while creating mbox spool file");
595 
596 /* None of our current scanners need the mbox file as a stream (they use
597 the name), so we can close it right away.  Get the directory too. */
598 
599 (void) fclose(mbox_file);
600 eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
601 
602 /* parse 1st option */
603 if (strcmpic(malware_re, US"false") == 0  ||  Ustrcmp(malware_re,"0") == 0)
604   return FAIL;		/* explicitly no matching */
605 
606 /* special cases (match anything except empty) */
607 if (  strcmpic(malware_re,US"true") == 0
608    || Ustrcmp(malware_re,"*") == 0
609    || Ustrcmp(malware_re,"1") == 0
610    )
611   {
612   if (  !malware_default_re
613      && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
614     return malware_panic_defer(errstr);
615   malware_re = malware_regex_default;
616   re = malware_default_re;
617   }
618 
619 /* compile the regex, see if it works */
620 else if (!(re = m_pcre_compile(malware_re, &errstr)))
621   return malware_panic_defer(errstr);
622 
623 /* if av_scanner starts with a dollar, expand it first */
624 if (*av_scanner == '$')
625   {
626   if (!(av_scanner_work = expand_string(av_scanner)))
627     return malware_panic_defer(
628 	 string_sprintf("av_scanner starts with $, but expansion failed: %s",
629 	 expand_string_message));
630 
631   DEBUG(D_acl)
632     debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work);
633   /* disable result caching in this case */
634   malware_name = NULL;
635   malware_ok = FALSE;
636   }
637 
638 /* Do not scan twice (unless av_scanner is dynamic). */
639 if (!malware_ok)
640   {
641   /* find the scanner type from the av_scanner option */
642   if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
643     return malware_panic_defer(US"av_scanner configuration variable is empty");
644   if (!timeout) timeout = MALWARE_TIMEOUT;
645   tmo = time(NULL) + timeout;
646 
647   for (scanent = m_scans; ; scanent++)
648     {
649     if (!scanent->name)
650       return malware_panic_defer(string_sprintf("unknown scanner type '%s'",
651 	scanner_name));
652     if (strcmpic(scanner_name, US scanent->name) != 0)
653       continue;
654     DEBUG(D_acl) debug_printf_indent("Malware scan:  %s tmo=%s\n",
655       scanner_name, readconf_printtime(timeout));
656 
657     if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
658       scanner_options = scanent->options_default;
659     if (scanent->conn == MC_NONE)
660       break;
661 
662     DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
663     switch(scanent->conn)
664     {
665     case MC_TCP:
666       malware_daemon_ctx.sock = ip_tcpsocket(scanner_options, &errstr, 5, NULL); break;
667     case MC_UNIX:
668       malware_daemon_ctx.sock = ip_unixsocket(scanner_options, &errstr);	break;
669     case MC_STRM:
670       malware_daemon_ctx.sock = ip_streamsocket(scanner_options, &errstr, 5, NULL); break;
671     default:
672       /* compiler quietening */ break;
673     }
674     if (malware_daemon_ctx.sock < 0)
675       return m_panic_defer(scanent, CUS callout_address, errstr);
676     break;
677   }
678 
679   switch (scanent->scancode)
680     {
681 #ifndef DISABLE_MAL_FFROTD
682     case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
683       {
684       uschar *fp_scan_option;
685       unsigned int detected=0, par_count=0;
686       uschar * scanrequest;
687       uschar buf[32768], *strhelper, *strhelper2;
688       uschar * malware_name_internal = NULL;
689       int len;
690 
691       scanrequest = string_sprintf("GET %s", eml_filename);
692 
693       while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
694 			    NULL, 0)))
695 	{
696 	scanrequest = string_sprintf("%s%s%s", scanrequest,
697 				  par_count ? "%20" : "?", fp_scan_option);
698 	par_count++;
699 	}
700       scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
701       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
702 	scanner_name, scanrequest);
703 
704       /* send scan request */
705       if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
706 	return m_panic_defer(scanent, CUS callout_address, errstr);
707 
708       while ((len = recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo)) >= 0)
709 	if (len > 0)
710 	  {
711 	  if (Ustrstr(buf, US"<detected type=\"") != NULL)
712 	    detected = 1;
713 	  else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
714 	    {
715 	    if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
716 	      {
717 	      *strhelper2 = '\0';
718 	      malware_name_internal = string_copy(strhelper+6);
719 	      }
720 	    }
721 	  else if (Ustrstr(buf, US"<summary code=\""))
722 	    {
723 	    malware_name = Ustrstr(buf, US"<summary code=\"11\">")
724 		? malware_name_internal : NULL;
725 	    break;
726 	    }
727 	  }
728       if (len < -1)
729 	{
730 	(void)close(malware_daemon_ctx.sock);
731 	return DEFER;
732 	}
733       break;
734       }	/* f-protd */
735 #endif
736 
737 #ifndef DISABLE_MAL_FFROT6D
738     case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
739       {
740       int bread;
741       uschar * e;
742       uschar * linebuffer;
743       uschar * scanrequest;
744       uschar av_buffer[1024];
745 
746       if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
747         || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
748         return malware_panic_defer(errstr);
749 
750       scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
751       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
752         scanner_name, scanrequest);
753 
754       if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
755         return m_panic_defer(scanent, CUS callout_address, errstr);
756 
757       bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo);
758 
759       if (bread <= 0)
760         return m_panic_defer_3(scanent, CUS callout_address,
761           string_sprintf("unable to read from socket (%s)", strerror(errno)),
762           malware_daemon_ctx.sock);
763 
764       if (bread == sizeof(av_buffer))
765         return m_panic_defer_3(scanent, CUS callout_address,
766           US"buffer too small", malware_daemon_ctx.sock);
767 
768       av_buffer[bread] = '\0';
769       linebuffer = string_copy(av_buffer);
770 
771       m_sock_send(malware_daemon_ctx.sock, US"QUIT\n", 5, 0);
772 
773       if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
774         return m_panic_defer_3(scanent, CUS callout_address,
775           string_sprintf("scanner reported error (%s)", e), malware_daemon_ctx.sock);
776 
777       if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
778         malware_name = NULL;
779 
780       break;
781       }  /* f-prot6d */
782 #endif
783 
784 #ifndef DISABLE_MAL_DRWEB
785     case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
786   /* v0.1 - added support for tcp sockets          */
787   /* v0.0 - initial release -- support for unix sockets      */
788       {
789       int result;
790       off_t fsize;
791       unsigned int fsize_uint;
792       uschar * tmpbuf, *drweb_fbuf;
793       int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
794 	  drweb_vnum, drweb_slen, drweb_fin = 0x0000;
795 
796       /* prepare variables */
797       drweb_cmd = htonl(DRWEBD_SCAN_CMD);
798       drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
799 
800       if (*scanner_options != '/')
801 	{
802 	/* calc file size */
803 	if ((drweb_fd = exim_open2(CCS eml_filename, O_RDONLY)) == -1)
804 	  return m_panic_defer_3(scanent, NULL,
805 	    string_sprintf("can't open spool file %s: %s",
806 	      eml_filename, strerror(errno)),
807 	    malware_daemon_ctx.sock);
808 
809 	if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
810 	  {
811 	  int err;
812 badseek:  err = errno;
813 	  (void)close(drweb_fd);
814 	  return m_panic_defer_3(scanent, NULL,
815 	    string_sprintf("can't seek spool file %s: %s",
816 	      eml_filename, strerror(err)),
817 	    malware_daemon_ctx.sock);
818 	  }
819 	fsize_uint = (unsigned int) fsize;
820 	if ((off_t)fsize_uint != fsize)
821 	  {
822 	  (void)close(drweb_fd);
823 	  return m_panic_defer_3(scanent, NULL,
824 	    string_sprintf("seeking spool file %s, size overflow",
825 	      eml_filename),
826 	    malware_daemon_ctx.sock);
827 	  }
828 	drweb_slen = htonl(fsize);
829 	if (lseek(drweb_fd, 0, SEEK_SET) < 0)
830 	  goto badseek;
831 
832 	DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
833 	    scanner_name, scanner_options);
834 
835 	/* send scan request */
836 	if ((send(malware_daemon_ctx.sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
837 	    (send(malware_daemon_ctx.sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
838 	    (send(malware_daemon_ctx.sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
839 	    (send(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
840 	  {
841 	  (void)close(drweb_fd);
842 	  return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
843 	    "unable to send commands to socket (%s)", scanner_options),
844 	    malware_daemon_ctx.sock);
845 	  }
846 
847 	if (!(drweb_fbuf = store_malloc(fsize_uint)))
848 	  {
849 	  (void)close(drweb_fd);
850 	  return m_panic_defer_3(scanent, NULL,
851 	    string_sprintf("unable to allocate memory %u for file (%s)",
852 	      fsize_uint, eml_filename),
853 	    malware_daemon_ctx.sock);
854 	  }
855 
856 	if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
857 	  {
858 	  int err = errno;
859 	  (void)close(drweb_fd);
860 	  store_free(drweb_fbuf);
861 	  return m_panic_defer_3(scanent, NULL,
862 	    string_sprintf("can't read spool file %s: %s",
863 	      eml_filename, strerror(err)),
864 	    malware_daemon_ctx.sock);
865 	  }
866 	(void)close(drweb_fd);
867 
868 	/* send file body to socket */
869 	if (send(malware_daemon_ctx.sock, drweb_fbuf, fsize, 0) < 0)
870 	  {
871 	  store_free(drweb_fbuf);
872 	  return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
873 	    "unable to send file body to socket (%s)", scanner_options),
874 	    malware_daemon_ctx.sock);
875 	  }
876 	store_free(drweb_fbuf);
877 	}
878       else
879 	{
880 	drweb_slen = htonl(Ustrlen(eml_filename));
881 
882 	DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n",
883 	    scanner_name, scanner_options);
884 
885 	/* send scan request */
886 	if ((send(malware_daemon_ctx.sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
887 	    (send(malware_daemon_ctx.sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
888 	    (send(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
889 	    (send(malware_daemon_ctx.sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
890 	    (send(malware_daemon_ctx.sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
891 	  return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
892 	    "unable to send commands to socket (%s)", scanner_options),
893 	    malware_daemon_ctx.sock);
894 	}
895 
896       /* wait for result */
897       if (!recv_len(malware_daemon_ctx.sock, &drweb_rc, sizeof(drweb_rc), tmo))
898 	return m_panic_defer_3(scanent, CUS callout_address,
899 		    US"unable to read return code", malware_daemon_ctx.sock);
900       drweb_rc = ntohl(drweb_rc);
901 
902       if (!recv_len(malware_daemon_ctx.sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
903 	return m_panic_defer_3(scanent, CUS callout_address,
904 			    US"unable to read the number of viruses", malware_daemon_ctx.sock);
905       drweb_vnum = ntohl(drweb_vnum);
906 
907       /* "virus(es) found" if virus number is > 0 */
908       if (drweb_vnum)
909 	{
910 	gstring * g = NULL;
911 
912 	/* setup default virus name */
913 	malware_name = US"unknown";
914 
915 	/* set up match regex */
916 	if (!drweb_re)
917 	  drweb_re = m_pcre_compile(drweb_re_str, &errstr);
918 
919 	/* read and concatenate virus names into one string */
920 	for (int i = 0; i < drweb_vnum; i++)
921 	  {
922 	  int ovector[10*3];
923 
924 	  /* read the size of report */
925 	  if (!recv_len(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), tmo))
926 	    return m_panic_defer_3(scanent, CUS callout_address,
927 			      US"cannot read report size", malware_daemon_ctx.sock);
928 	  drweb_slen = ntohl(drweb_slen);
929 
930 	  /* assume tainted, since it is external input */
931 	  tmpbuf = store_get(drweb_slen, TRUE);
932 
933 	  /* read report body */
934 	  if (!recv_len(malware_daemon_ctx.sock, tmpbuf, drweb_slen, tmo))
935 	    return m_panic_defer_3(scanent, CUS callout_address,
936 			      US"cannot read report string", malware_daemon_ctx.sock);
937 	  tmpbuf[drweb_slen] = '\0';
938 
939 	  /* try matcher on the line, grab substring */
940 	  result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
941 				  ovector, nelem(ovector));
942 	  if (result >= 2)
943 	    {
944 	    const char * pre_malware_nb;
945 
946 	    pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
947 
948 	    if (i==0)	/* the first name we just copy to malware_name */
949 	      g = string_cat(NULL, US pre_malware_nb);
950 
951 	    /*XXX could be string_append_listele? */
952 	    else	/* concatenate each new virus name to previous */
953 	      g = string_append(g, 2, "/", pre_malware_nb);
954 
955 	    pcre_free_substring(pre_malware_nb);
956 	    }
957 	  }
958 	  malware_name = string_from_gstring(g);
959 	}
960       else
961 	{
962 	const char *drweb_s = NULL;
963 
964 	if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
965 	if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
966 	if (drweb_rc & DERR_TIMEOUT)  drweb_s = "timeout";
967 	if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
968 	/* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
969 	 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
970 	 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
971 	 * and others are ignored */
972 	if (drweb_s)
973 	  return m_panic_defer_3(scanent, CUS callout_address,
974 	    string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
975 	    malware_daemon_ctx.sock);
976 
977 	/* no virus found */
978 	malware_name = NULL;
979 	}
980       break;
981       }	/* drweb */
982 #endif
983 
984 #ifndef DISABLE_MAL_AVE
985     case M_AVES: /* "aveserver" scanner type -------------------------------- */
986       {
987       uschar buf[32768];
988       int result;
989 
990       /* read aveserver's greeting and see if it is ready (2xx greeting) */
991       buf[0] = 0;
992       recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo);
993 
994       if (buf[0] != '2')		/* aveserver is having problems */
995 	return m_panic_defer_3(scanent, CUS callout_address,
996 	  string_sprintf("unavailable (Responded: %s).",
997 			  ((buf[0] != 0) ? buf : US "nothing") ),
998 	  malware_daemon_ctx.sock);
999 
1000       /* prepare our command */
1001       (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
1002 						eml_filename);
1003 
1004       /* and send it */
1005       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
1006 	scanner_name, buf);
1007       if (m_sock_send(malware_daemon_ctx.sock, buf, Ustrlen(buf), &errstr) < 0)
1008 	return m_panic_defer(scanent, CUS callout_address, errstr);
1009 
1010       malware_name = NULL;
1011       result = 0;
1012       /* read response lines, find malware name and final response */
1013       while (recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo) > 0)
1014 	{
1015 	if (buf[0] == '2')
1016 	  break;
1017 	if (buf[0] == '5')		/* aveserver is having problems */
1018 	  {
1019 	  result = m_panic_defer(scanent, CUS callout_address,
1020 	     string_sprintf("unable to scan file %s (Responded: %s).",
1021 			     eml_filename, buf));
1022 	  break;
1023 	  }
1024 	if (Ustrncmp(buf,"322",3) == 0)
1025 	  {
1026 	  uschar *p = Ustrchr(&buf[4], ' ');
1027 	  *p = '\0';
1028 	  malware_name = string_copy(&buf[4]);
1029 	  }
1030 	}
1031 
1032       if (m_sock_send(malware_daemon_ctx.sock, US"quit\r\n", 6, &errstr) < 0)
1033 	return m_panic_defer(scanent, CUS callout_address, errstr);
1034 
1035       /* read aveserver's greeting and see if it is ready (2xx greeting) */
1036       buf[0] = 0;
1037       recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo);
1038 
1039       if (buf[0] != '2')		/* aveserver is having problems */
1040 	return m_panic_defer_3(scanent, CUS callout_address,
1041 	  string_sprintf("unable to quit dialogue (Responded: %s).",
1042 			((buf[0] != 0) ? buf : US "nothing") ),
1043 	  malware_daemon_ctx.sock);
1044 
1045       if (result == DEFER)
1046 	{
1047 	(void)close(malware_daemon_ctx.sock);
1048 	return DEFER;
1049 	}
1050       break;
1051       }	/* aveserver */
1052 #endif
1053 
1054 #ifndef DISABLE_MAL_FSECURE
1055     case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
1056       {
1057       int i, bread = 0;
1058       uschar * file_name;
1059       uschar av_buffer[1024];
1060       static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
1061 				      US"CONFIGURE\tTIMEOUT\t0\n",
1062 				      US"CONFIGURE\tMAXARCH\t5\n",
1063 				      US"CONFIGURE\tMIME\t1\n" };
1064 
1065       malware_name = NULL;
1066 
1067       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1068 	  scanner_name, scanner_options);
1069       /* pass options */
1070       memset(av_buffer, 0, sizeof(av_buffer));
1071       for (i = 0; i != nelem(cmdopt); i++)
1072 	{
1073 
1074 	if (m_sock_send(malware_daemon_ctx.sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
1075 	  return m_panic_defer(scanent, CUS callout_address, errstr);
1076 
1077 	bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo);
1078 	if (bread > 0) av_buffer[bread]='\0';
1079 	if (bread < 0)
1080 	  return m_panic_defer_3(scanent, CUS callout_address,
1081 	    string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
1082 	    malware_daemon_ctx.sock);
1083 	for (int j = 0; j < bread; j++)
1084 	  if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
1085 	    av_buffer[j] ='@';
1086 	}
1087 
1088       /* pass the mailfile to fsecure */
1089       file_name = string_sprintf("SCAN\t%s\n", eml_filename);
1090 
1091       if (m_sock_send(malware_daemon_ctx.sock, file_name, Ustrlen(file_name), &errstr) < 0)
1092 	return m_panic_defer(scanent, CUS callout_address, errstr);
1093 
1094       /* set up match */
1095       /* todo also SUSPICION\t */
1096       if (!fsec_re)
1097 	fsec_re = m_pcre_compile(fsec_re_str, &errstr);
1098 
1099       /* read report, linewise. Apply a timeout as the Fsecure daemon
1100       sometimes wants an answer to "PING" but they won't tell us what */
1101 	{
1102 	uschar * p = av_buffer;
1103 	uschar * q;
1104 
1105 	for (;;)
1106 	  {
1107 	  errno = ETIMEDOUT;
1108 	  i =  av_buffer+sizeof(av_buffer)-p;
1109 	  if ((bread= ip_recv(&malware_daemon_ctx, p, i-1, tmo)) < 0)
1110 	    return m_panic_defer_3(scanent, CUS callout_address,
1111 	      string_sprintf("unable to read result (%s)", strerror(errno)),
1112 	      malware_daemon_ctx.sock);
1113 
1114 	  for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
1115 	    {
1116 	    *q = '\0';
1117 
1118 	    /* Really search for virus again? */
1119 	    if (!malware_name)
1120 	      /* try matcher on the line, grab substring */
1121 	      malware_name = m_pcre_exec(fsec_re, p);
1122 
1123 	    if (Ustrstr(p, "OK\tScan ok."))
1124 	      goto fsec_found;
1125 	    }
1126 
1127 	  /* copy down the trailing partial line then read another chunk */
1128 	  i =  av_buffer+sizeof(av_buffer)-p;
1129 	  memmove(av_buffer, p, i);
1130 	  p = av_buffer+i;
1131 	  }
1132 	}
1133 
1134       fsec_found:
1135 	break;
1136       }	/* fsecure */
1137 #endif
1138 
1139 #ifndef DISABLE_MAL_KAV
1140     case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
1141       {
1142       time_t t;
1143       uschar tmpbuf[1024];
1144       uschar * scanrequest;
1145       int kav_rc;
1146       unsigned long kav_reportlen;
1147       int bread;
1148       const pcre *kav_re;
1149       uschar *p;
1150 
1151       /* get current date and time, build scan request */
1152       time(&t);
1153       /* pdp note: before the eml_filename parameter, this scanned the
1154       directory; not finding documentation, so we'll strip off the directory.
1155       The side-effect is that the test framework scanning may end up in
1156       scanning more than was requested, but for the normal interface, this is
1157       fine. */
1158 
1159       strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
1160       scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
1161       p = Ustrrchr(scanrequest, '/');
1162       if (p)
1163 	*p = '\0';
1164 
1165       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1166 	  scanner_name, scanner_options);
1167 
1168       /* send scan request */
1169       if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
1170 	return m_panic_defer(scanent, CUS callout_address, errstr);
1171 
1172       /* wait for result */
1173       if (!recv_len(malware_daemon_ctx.sock, tmpbuf, 2, tmo))
1174 	return m_panic_defer_3(scanent, CUS callout_address,
1175 			    US"unable to read 2 bytes from socket.", malware_daemon_ctx.sock);
1176 
1177       /* get errorcode from one nibble */
1178       kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
1179       switch(kav_rc)
1180       {
1181       case 5: case 6: /* improper kavdaemon configuration */
1182 	return m_panic_defer_3(scanent, CUS callout_address,
1183 		US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
1184 		malware_daemon_ctx.sock);
1185       case 1:
1186 	return m_panic_defer_3(scanent, CUS callout_address,
1187 		US"reported 'scanning not completed' (code 1).", malware_daemon_ctx.sock);
1188       case 7:
1189 	return m_panic_defer_3(scanent, CUS callout_address,
1190 		US"reported 'kavdaemon damaged' (code 7).", malware_daemon_ctx.sock);
1191       }
1192 
1193       /* code 8 is not handled, since it is ambiguous. It appears mostly on
1194       bounces where part of a file has been cut off */
1195 
1196       /* "virus found" return codes (2-4) */
1197       if (kav_rc > 1 && kav_rc < 5)
1198 	{
1199 	int report_flag = 0;
1200 
1201 	/* setup default virus name */
1202 	malware_name = US"unknown";
1203 
1204 	report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
1205 
1206 	/* read the report, if available */
1207 	if (report_flag == 1)
1208 	  {
1209 	  /* read report size */
1210 	  if (!recv_len(malware_daemon_ctx.sock, &kav_reportlen, 4, tmo))
1211 	    return m_panic_defer_3(scanent, CUS callout_address,
1212 		  US"cannot read report size", malware_daemon_ctx.sock);
1213 
1214 	  /* it's possible that avp returns av_buffer[1] == 1 but the
1215 	  reportsize is 0 (!?) */
1216 	  if (kav_reportlen > 0)
1217 	    {
1218 	    /* set up match regex, depends on retcode */
1219 	    if (kav_rc == 3)
1220 	      {
1221 	      if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1222 	      kav_re = kav_re_sus;
1223 	      }
1224 	    else
1225 	      {
1226 	      if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1227 	      kav_re = kav_re_inf;
1228 	      }
1229 
1230 	    /* read report, linewise.  Using size from stream to read amount of data
1231 	    from same stream is safe enough. */
1232 	    /* coverity[tainted_data] */
1233 	    while (kav_reportlen > 0)
1234 	      {
1235 	      if ((bread = recv_line(malware_daemon_ctx.sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1236 		break;
1237 	      kav_reportlen -= bread+1;
1238 
1239 	      /* try matcher on the line, grab substring */
1240 	      if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1241 		break;
1242 	      }
1243 	    }
1244 	  }
1245 	}
1246       else /* no virus found */
1247 	malware_name = NULL;
1248 
1249       break;
1250       }
1251 #endif
1252 
1253 #ifndef DISABLE_MAL_CMDLINE
1254     case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1255       {
1256       const uschar *cmdline_scanner = scanner_options;
1257       const pcre *cmdline_trigger_re;
1258       const pcre *cmdline_regex_re;
1259       uschar * file_name;
1260       uschar * commandline;
1261       void (*eximsigchld)(int);
1262       void (*eximsigpipe)(int);
1263       FILE *scanner_out = NULL;
1264       int scanner_fd;
1265       FILE *scanner_record = NULL;
1266       uschar linebuffer[32767];
1267       int rcnt;
1268       int trigger = 0;
1269       uschar *p;
1270 
1271       if (!cmdline_scanner)
1272 	return m_panic_defer(scanent, NULL, errstr);
1273 
1274       /* find scanner output trigger */
1275       cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1276 				"missing trigger specification", &errstr);
1277       if (!cmdline_trigger_re)
1278 	return m_panic_defer(scanent, NULL, errstr);
1279 
1280       /* find scanner name regex */
1281       cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1282 			  "missing virus name regex specification", &errstr);
1283       if (!cmdline_regex_re)
1284 	return m_panic_defer(scanent, NULL, errstr);
1285 
1286       /* prepare scanner call; despite the naming, file_name holds a directory
1287       name which is documented as the value given to %s. */
1288 
1289       file_name = string_copy(eml_filename);
1290       p = Ustrrchr(file_name, '/');
1291       if (p)
1292 	*p = '\0';
1293       commandline = string_sprintf(CS cmdline_scanner, file_name);
1294 
1295       /* redirect STDERR too */
1296       commandline = string_sprintf("%s 2>&1", commandline);
1297 
1298       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1299 	      scanner_name, commandline);
1300 
1301       /* store exims signal handlers */
1302       eximsigchld = signal(SIGCHLD,SIG_DFL);
1303       eximsigpipe = signal(SIGPIPE,SIG_DFL);
1304 
1305       if (!(scanner_out = popen(CS commandline,"r")))
1306 	{
1307 	int err = errno;
1308 	signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1309 	return m_panic_defer(scanent, NULL,
1310 	  string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1311 	}
1312       scanner_fd = fileno(scanner_out);
1313 
1314       file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
1315 
1316       if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1317 	{
1318 	int err = errno;
1319 	(void) pclose(scanner_out);
1320 	signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1321 	return m_panic_defer(scanent, NULL, string_sprintf(
1322 	    "opening scanner output file (%s) failed: %s.",
1323 	    file_name, strerror(err)));
1324 	}
1325 
1326       /* look for trigger while recording output */
1327       while ((rcnt = recv_line(scanner_fd, linebuffer,
1328 		      sizeof(linebuffer), tmo)))
1329 	{
1330 	if (rcnt < 0)
1331 	  {
1332 	  int err = errno;
1333 	  if (rcnt == -1)
1334 	    break;
1335 	  (void) pclose(scanner_out);
1336 	  signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1337 	  return m_panic_defer(scanent, NULL, string_sprintf(
1338 	      "unable to read from scanner (%s): %s",
1339 	      commandline, strerror(err)));
1340 	  }
1341 
1342 	if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1343 	  {
1344 	  /* short write */
1345 	  (void) pclose(scanner_out);
1346 	  signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1347 	  return m_panic_defer(scanent, NULL, string_sprintf(
1348 	    "short write on scanner output file (%s).", file_name));
1349 	  }
1350 	putc('\n', scanner_record);
1351 	/* try trigger match */
1352 	if (  !trigger
1353 	   && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1354 	   )
1355 	  trigger = 1;
1356 	}
1357 
1358       (void)fclose(scanner_record);
1359       sep = pclose(scanner_out);
1360       signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1361       if (sep != 0)
1362 	  return m_panic_defer(scanent, NULL,
1363 	      sep == -1
1364 	      ? string_sprintf("running scanner failed: %s", strerror(sep))
1365 	      : string_sprintf("scanner returned error code: %d", sep));
1366 
1367       if (trigger)
1368 	{
1369 	uschar * s;
1370 	/* setup default virus name */
1371 	malware_name = US"unknown";
1372 
1373 	/* re-open the scanner output file, look for name match */
1374 	scanner_record = Ufopen(file_name, "rb");
1375 	while (Ufgets(linebuffer, sizeof(linebuffer), scanner_record))
1376 	  if ((s = m_pcre_exec(cmdline_regex_re, linebuffer))) /* try match */
1377 	    malware_name = s;
1378 	(void)fclose(scanner_record);
1379 	}
1380       else /* no virus found */
1381 	malware_name = NULL;
1382       break;
1383       }	/* cmdline */
1384 #endif
1385 
1386 #ifndef DISABLE_MAL_SOPHIE
1387     case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1388       {
1389       int bread = 0;
1390       uschar *p;
1391       uschar * file_name;
1392       uschar av_buffer[1024];
1393 
1394       /* pass the scan directory to sophie */
1395       file_name = string_copy(eml_filename);
1396       if ((p = Ustrrchr(file_name, '/')))
1397 	*p = '\0';
1398 
1399       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1400 	  scanner_name, scanner_options);
1401 
1402       if (  write(malware_daemon_ctx.sock, file_name, Ustrlen(file_name)) < 0
1403 	 || write(malware_daemon_ctx.sock, "\n", 1) != 1
1404 	 )
1405 	return m_panic_defer_3(scanent, CUS callout_address,
1406 	  string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1407 	  malware_daemon_ctx.sock);
1408 
1409       /* wait for result */
1410       memset(av_buffer, 0, sizeof(av_buffer));
1411       if ((bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo)) <= 0)
1412 	return m_panic_defer_3(scanent, CUS callout_address,
1413 	  string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1414 	  malware_daemon_ctx.sock);
1415 
1416       /* infected ? */
1417       if (av_buffer[0] == '1') {
1418 	uschar * s = Ustrchr(av_buffer, '\n');
1419 	if (s)
1420 	  *s = '\0';
1421 	malware_name = string_copy(&av_buffer[2]);
1422       }
1423       else if (!strncmp(CS av_buffer, "-1", 2))
1424 	return m_panic_defer_3(scanent, CUS callout_address,
1425 		US"scanner reported error", malware_daemon_ctx.sock);
1426       else /* all ok, no virus */
1427 	malware_name = NULL;
1428 
1429       break;
1430       }
1431 #endif
1432 
1433 #ifndef DISABLE_MAL_CLAM
1434     case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1435       {
1436 /* This code was originally contributed by David Saez */
1437 /* There are three scanning methods available to us:
1438 *  (1) Use the SCAN command, pointing to a file in the filesystem
1439 *  (2) Use the STREAM command, send the data on a separate port
1440 *  (3) Use the zINSTREAM command, send the data inline
1441 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1442 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1443 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1444 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM
1445 * See Exim bug 926 for details.  */
1446 
1447       uschar *p, *vname, *result_tag;
1448       int bread=0;
1449       uschar av_buffer[1024];
1450       uschar *hostname = US"";
1451       host_item connhost;
1452       int clam_fd, result;
1453       unsigned int fsize_uint;
1454       BOOL use_scan_command = FALSE;
1455       clamd_address * cv[MAX_CLAMD_SERVERS];
1456       int num_servers = 0;
1457       uint32_t send_size, send_final_zeroblock;
1458       blob cmd_str;
1459 
1460       /*XXX if unixdomain socket, only one server supported. Needs fixing;
1461       there's no reason we should not mix local and remote servers */
1462 
1463       if (*scanner_options == '/')
1464 	{
1465 	clamd_address * cd;
1466 	const uschar * sublist;
1467 	int subsep = ' ';
1468 
1469 	/* Local file; so we def want to use_scan_command and don't want to try
1470 	 * passing IP/port combinations */
1471 	use_scan_command = TRUE;
1472 	cd = (clamd_address *) store_get(sizeof(clamd_address), FALSE);
1473 
1474 	/* extract socket-path part */
1475 	sublist = scanner_options;
1476 	cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1477 
1478 	/* parse options */
1479 	if (clamd_option(cd, sublist, &subsep) != OK)
1480 	  return m_panic_defer(scanent, NULL,
1481 	    string_sprintf("bad option '%s'", scanner_options));
1482 	cv[0] = cd;
1483 	}
1484       else
1485 	{
1486 	/* Go through the rest of the list of host/port and construct an array
1487 	 * of servers to try. The first one is the bit we just passed from
1488 	 * scanner_options so process that first and then scan the remainder of
1489 	 * the address buffer */
1490 	do
1491 	  {
1492 	  clamd_address * cd;
1493 	  const uschar * sublist;
1494 	  int subsep = ' ';
1495 	  uschar * s;
1496 
1497 	  /* The 'local' option means use the SCAN command over the network
1498 	   * socket (ie common file storage in use) */
1499 	  /*XXX we could accept this also as a local option? */
1500 	  if (strcmpic(scanner_options, US"local") == 0)
1501 	    {
1502 	    use_scan_command = TRUE;
1503 	    continue;
1504 	    }
1505 
1506 	  cd = (clamd_address *) store_get(sizeof(clamd_address), FALSE);
1507 
1508 	  /* extract host and port part */
1509 	  sublist = scanner_options;
1510 	  if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1511 	    {
1512 	    (void) m_panic_defer(scanent, NULL,
1513 		      string_sprintf("missing address: '%s'", scanner_options));
1514 	    continue;
1515 	    }
1516 	  if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1517 	    {
1518 	    (void) m_panic_defer(scanent, NULL,
1519 		      string_sprintf("missing port: '%s'", scanner_options));
1520 	    continue;
1521 	    }
1522 	  cd->tcp_port = atoi(CS s);
1523 
1524 	  /* parse options */
1525 	  /*XXX should these options be common over scanner types? */
1526 	  if (clamd_option(cd, sublist, &subsep) != OK)
1527 	    return m_panic_defer(scanent, NULL,
1528 	      string_sprintf("bad option '%s'", scanner_options));
1529 
1530 	  cv[num_servers++] = cd;
1531 	  if (num_servers >= MAX_CLAMD_SERVERS)
1532 	    {
1533 	    (void) m_panic_defer(scanent, NULL,
1534 		  US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1535 		  "specified; only using the first " MAX_CLAMD_SERVERS_S );
1536 	    break;
1537 	    }
1538 	  } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1539 					NULL, 0)));
1540 
1541 	/* check if we have at least one server */
1542 	if (!num_servers)
1543 	  return m_panic_defer(scanent, NULL,
1544 	    US"no useable server addresses in malware configuration option.");
1545 	}
1546 
1547       /* See the discussion of response formats below to see why we really
1548       don't like colons in filenames when passing filenames to ClamAV. */
1549       if (use_scan_command && Ustrchr(eml_filename, ':'))
1550 	return m_panic_defer(scanent, NULL,
1551 	  string_sprintf("local/SCAN mode incompatible with" \
1552 	    " : in path to email filename [%s]", eml_filename));
1553 
1554       /* Set up the very first data we will be sending */
1555       if (!use_scan_command)
1556 	{ cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1557       else
1558 	{
1559 	int n;
1560 	cmd_str.data = string_sprintf("SCAN %s\n%n", eml_filename, &n);
1561 	cmd_str.len = n;		/* .len is a size_t */
1562 	}
1563 
1564       /* We have some network servers specified */
1565       if (num_servers)
1566 	{
1567 	/* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1568 	only supports AF_INET, but we should probably be looking to the
1569 	future and rewriting this to be protocol-independent anyway. */
1570 
1571 	while (num_servers > 0)
1572 	  {
1573 	  int i = random_number(num_servers);
1574 	  clamd_address * cd = cv[i];
1575 
1576 	  DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1577 			 cd->hostspec, cd->tcp_port);
1578 
1579 	  /* Lookup the host. This is to ensure that we connect to the same IP
1580 	  on both connections (as one host could resolve to multiple ips) */
1581 	  for (;;)
1582 	    {
1583 	    /*XXX we trust that the cmd_str is idempotent */
1584 	    if ((malware_daemon_ctx.sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1585 				    &connhost, &errstr,
1586 				    use_scan_command ? &cmd_str : NULL)) >= 0)
1587 	      {
1588 	      /* Connection successfully established with a server */
1589 	      hostname = cd->hostspec;
1590 	      if (use_scan_command) cmd_str.len = 0;
1591 	      break;
1592 	      }
1593 	    if (cd->retry <= 0) break;
1594 	    while (cd->retry > 0) cd->retry = sleep(cd->retry);
1595 	    }
1596 	  if (malware_daemon_ctx.sock >= 0)
1597 	    break;
1598 
1599 	  (void) m_panic_defer(scanent, CUS callout_address, errstr);
1600 
1601 	  /* Remove the server from the list. XXX We should free the memory */
1602 	  num_servers--;
1603 	  for (; i < num_servers; i++)
1604 	    cv[i] = cv[i+1];
1605 	  }
1606 
1607 	if (num_servers == 0)
1608 	  return m_panic_defer(scanent, NULL, US"all servers failed");
1609 	}
1610       else
1611 	for (;;)
1612 	  {
1613 	  if ((malware_daemon_ctx.sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1614 	    {
1615 	    hostname = cv[0]->hostspec;
1616 	    break;
1617 	    }
1618 	  if (cv[0]->retry <= 0)
1619 	    return m_panic_defer(scanent, CUS callout_address, errstr);
1620 	  while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1621 	  }
1622 
1623       /* have socket in variable "sock"; command to use is semi-independent of
1624       the socket protocol.  We use SCAN if is local (either Unix/local
1625       domain socket, or explicitly told local) else we stream the data.
1626       How we stream the data depends upon how we were built.  */
1627 
1628       if (!use_scan_command)
1629 	{
1630 	struct stat st;
1631 #if defined(EXIM_TCP_CORK) && !defined(OS_SENDFILE)
1632 	BOOL corked = TRUE;
1633 #endif
1634 	/* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1635 	chunks, <n> a 4-byte number (network order), terminated by a zero-length
1636 	chunk. We only send one chunk. */
1637 
1638 	DEBUG(D_acl) debug_printf_indent(
1639 	    "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1640 	    scanner_name);
1641 
1642 #if defined(EXIM_TCP_CORK)
1643 	(void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
1644 			  US &on, sizeof(on));
1645 #endif
1646 	/* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1647 	if (cmd_str.len)
1648 	  if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0)
1649 	    return m_panic_defer_3(scanent, CUS hostname,
1650 	      string_sprintf("unable to send zINSTREAM to socket (%s)",
1651 		strerror(errno)),
1652 	      malware_daemon_ctx.sock);
1653 
1654 	if ((clam_fd = exim_open2(CS eml_filename, O_RDONLY)) < 0)
1655 	  {
1656 	  int err = errno;
1657 	  return m_panic_defer_3(scanent, NULL,
1658 	    string_sprintf("can't open spool file %s: %s",
1659 	      eml_filename, strerror(err)),
1660 	    malware_daemon_ctx.sock);
1661 	  }
1662 	if (fstat(clam_fd, &st) < 0)
1663 	  {
1664 	  int err = errno;
1665 	  (void)close(clam_fd);
1666 	  return m_panic_defer_3(scanent, NULL,
1667 	    string_sprintf("can't stat spool file %s: %s",
1668 	      eml_filename, strerror(err)),
1669 	    malware_daemon_ctx.sock);
1670 	  }
1671 	fsize_uint = (unsigned int) st.st_size;
1672 	if ((off_t)fsize_uint != st.st_size)
1673 	  {
1674 	  (void)close(clam_fd);
1675 	  return m_panic_defer_3(scanent, NULL,
1676 	    string_sprintf("stat spool file %s, size overflow", eml_filename),
1677 	    malware_daemon_ctx.sock);
1678 	  }
1679 
1680 	/* send file size */
1681 	send_size = htonl(fsize_uint);
1682 	if (send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0)
1683 	  return m_panic_defer_3(scanent, NULL,
1684 	    string_sprintf("unable to send file size to socket (%s)", hostname),
1685 	    malware_daemon_ctx.sock);
1686 
1687 	/* send file body */
1688 	while (fsize_uint)
1689 	  {
1690 #ifdef OS_SENDFILE
1691 	  int n = os_sendfile(malware_daemon_ctx.sock, clam_fd, NULL, (size_t)fsize_uint);
1692 	  if (n < 0)
1693 	    return m_panic_defer_3(scanent, NULL,
1694 	      string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
1695 	      malware_daemon_ctx.sock);
1696 	  fsize_uint -= n;
1697 #else
1698 	  int n = MIN(fsize_uint, big_buffer_size);
1699 	  if ((n = read(clam_fd, big_buffer, n)) < 0)
1700 	    return m_panic_defer_3(scanent, NULL,
1701 	      string_sprintf("can't read spool file %s: %s",
1702 		eml_filename, strerror(errno)),
1703 	      malware_daemon_ctx.sock);
1704 	  if (send(malware_daemon_ctx.sock, big_buffer, (size_t)n, 0) < 0)
1705 	    return m_panic_defer_3(scanent, NULL,
1706 	      string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
1707 	      malware_daemon_ctx.sock);
1708 	  fsize_uint -= n;
1709 # ifdef EXIM_TCP_CORK
1710 	  if (corked)
1711 	    {
1712 	    corked = FALSE;
1713 	    (void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
1714 			      US &off, sizeof(off));
1715 	    }
1716 # endif
1717 #endif	/*!OS_SENDFILE*/
1718 
1719 	  }
1720 
1721 	send_final_zeroblock = 0;
1722 	if (send(malware_daemon_ctx.sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0)
1723 	  return m_panic_defer_3(scanent, NULL,
1724 	    string_sprintf("unable to send file terminator to socket (%s)", hostname),
1725 	    malware_daemon_ctx.sock);
1726 #ifdef OS_SENDFILE
1727 	(void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
1728 			  US &off, sizeof(off));
1729 #endif
1730 	}
1731       else
1732 	{ /* use scan command */
1733 	/* Send a SCAN command pointing to a filename; then in the then in the
1734 	scan-method-neutral part, read the response back */
1735 
1736 /* ================================================================= */
1737 
1738 	/* Prior to the reworking post-Exim-4.72, this scanned a directory,
1739 	which dates to when ClamAV needed us to break apart the email into the
1740 	MIME parts (eg, with the now deprecated demime condition coming first).
1741 	Some time back, ClamAV gained the ability to deconstruct the emails, so
1742 	doing this would actually have resulted in the mail attachments being
1743 	scanned twice, in the broken out files and from the original .eml.
1744 	Since ClamAV now handles emails (and has for quite some time) we can
1745 	just use the email file itself. */
1746 	/* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
1747 
1748 	DEBUG(D_acl) debug_printf_indent(
1749 	    "Malware scan: issuing %s local-path scan [%s]\n",
1750 	    scanner_name, scanner_options);
1751 
1752 	if (cmd_str.len)
1753 	  if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0)
1754 	    return m_panic_defer_3(scanent, CUS callout_address,
1755 	      string_sprintf("unable to write to socket (%s)", strerror(errno)),
1756 	      malware_daemon_ctx.sock);
1757 
1758 	/* Do not shut down the socket for writing; a user report noted that
1759 	clamd 0.70 does not react well to this. */
1760 	}
1761       /* Commands have been sent, no matter which scan method or connection
1762       type we're using; now just read the result, independent of method. */
1763 
1764       /* Read the result */
1765       memset(av_buffer, 0, sizeof(av_buffer));
1766       bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo);
1767       (void)close(malware_daemon_ctx.sock);
1768       malware_daemon_ctx.sock = -1;
1769       malware_daemon_ctx.tls_ctx = NULL;
1770 
1771       if (bread <= 0)
1772 	return m_panic_defer(scanent, CUS callout_address,
1773 	  string_sprintf("unable to read from socket (%s)",
1774 	  errno == 0 ? "EOF" : strerror(errno)));
1775 
1776       if (bread == sizeof(av_buffer))
1777 	return m_panic_defer(scanent, CUS callout_address,
1778 		US"buffer too small");
1779       /* We're now assured of a NULL at the end of av_buffer */
1780 
1781       /* Check the result. ClamAV returns one of two result formats.
1782       In the basic mode, the response is of the form:
1783 	infected: -> "<filename>: <virusname> FOUND"
1784 	not-infected: -> "<filename>: OK"
1785 	error: -> "<filename>: <errcode> ERROR
1786       If the ExtendedDetectionInfo option has been turned on, then we get:
1787 	"<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1788       for the infected case.  Compare:
1789 /tmp/eicar.com: Eicar-Test-Signature FOUND
1790 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1791 
1792       In the streaming case, clamd uses the filename "stream" which you should
1793       be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }.  (The
1794       client app will replace "stream" with the original filename before returning
1795       results to stdout, but the trace shows the data).
1796 
1797       We will assume that the pathname passed to clamd from Exim does not contain
1798       a colon.  We will have whined loudly above if the eml_filename does (and we're
1799       passing a filename to clamd). */
1800 
1801       if (!(*av_buffer))
1802 	return m_panic_defer(scanent, CUS callout_address,
1803 		US"ClamAV returned null");
1804 
1805       /* strip newline at the end (won't be present for zINSTREAM)
1806       (also any trailing whitespace, which shouldn't exist, but we depend upon
1807       this below, so double-check) */
1808 
1809       p = av_buffer + Ustrlen(av_buffer) - 1;
1810       if (*p == '\n') *p = '\0';
1811 
1812       DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1813 
1814       while (isspace(*--p) && (p > av_buffer))
1815 	*p = '\0';
1816       if (*p) ++p;
1817 
1818       /* colon in returned output? */
1819       if (!(p = Ustrchr(av_buffer,':')))
1820 	return m_panic_defer(scanent, CUS callout_address, string_sprintf(
1821 		  "ClamAV returned malformed result (missing colon): %s",
1822 		  av_buffer));
1823 
1824       /* strip filename */
1825       while (*p && isspace(*++p)) /**/;
1826       vname = p;
1827 
1828       /* It would be bad to encounter a virus with "FOUND" in part of the name,
1829       but we should at least be resistant to it. */
1830       p = Ustrrchr(vname, ' ');
1831       result_tag = p ? p+1 : vname;
1832 
1833       if (Ustrcmp(result_tag, "FOUND") == 0)
1834 	{
1835 	/* p should still be the whitespace before the result_tag */
1836 	while (isspace(*p)) --p;
1837 	*++p = '\0';
1838 	/* Strip off the extended information too, which will be in parens
1839 	after the virus name, with no intervening whitespace. */
1840 	if (*--p == ')')
1841 	  {
1842 	  /* "(hash:size)", so previous '(' will do; if not found, we have
1843 	  a curious virus name, but not an error. */
1844 	  p = Ustrrchr(vname, '(');
1845 	  if (p)
1846 	    *p = '\0';
1847 	  }
1848 	malware_name = string_copy(vname);
1849 	DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1850 
1851 	}
1852       else if (Ustrcmp(result_tag, "ERROR") == 0)
1853 	return m_panic_defer(scanent, CUS callout_address,
1854 	  string_sprintf("ClamAV returned: %s", av_buffer));
1855 
1856       else if (Ustrcmp(result_tag, "OK") == 0)
1857 	{
1858 	/* Everything should be OK */
1859 	malware_name = NULL;
1860 	DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1861 
1862 	}
1863       else
1864 	return m_panic_defer(scanent, CUS callout_address,
1865 	  string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1866 
1867       break;
1868       } /* clamd */
1869 #endif
1870 
1871 #ifndef DISABLE_MAL_SOCK
1872     case M_SOCK: /* "sock" scanner type ------------------------------------- */
1873     /* This code was derived by Martin Poole from the clamd code contributed
1874        by David Saez and the cmdline code
1875     */
1876       {
1877       int bread;
1878       uschar * commandline;
1879       uschar av_buffer[1024];
1880       uschar * linebuffer;
1881       uschar * sockline_scanner;
1882       uschar sockline_scanner_default[] = "%s\n";
1883       const pcre *sockline_trig_re;
1884       const pcre *sockline_name_re;
1885 
1886       /* find scanner command line */
1887       if (  (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1888 					  NULL, 0))
1889 	 && *sockline_scanner
1890 	 )
1891       {	/* check for no expansions apart from one %s */
1892 	uschar * s = Ustrchr(sockline_scanner, '%');
1893 	if (s++)
1894 	  if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1895 	    return m_panic_defer_3(scanent, NULL,
1896 				  US"unsafe sock scanner call spec", malware_daemon_ctx.sock);
1897       }
1898       else
1899 	sockline_scanner = sockline_scanner_default;
1900       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1901 	string_printing(sockline_scanner));
1902 
1903       /* find scanner output trigger */
1904       sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1905 				"missing trigger specification", &errstr);
1906       if (!sockline_trig_re)
1907 	return m_panic_defer_3(scanent, NULL, errstr, malware_daemon_ctx.sock);
1908 
1909       /* find virus name regex */
1910       sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1911 			  "missing virus name regex specification", &errstr);
1912       if (!sockline_name_re)
1913 	return m_panic_defer_3(scanent, NULL, errstr, malware_daemon_ctx.sock);
1914 
1915       /* prepare scanner call - security depends on expansions check above */
1916       commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1917       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1918 	string_printing(commandline));
1919 
1920       /* Pass the command string to the socket */
1921       if (m_sock_send(malware_daemon_ctx.sock, commandline, Ustrlen(commandline), &errstr) < 0)
1922 	return m_panic_defer(scanent, CUS callout_address, errstr);
1923 
1924       /* Read the result */
1925       bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo);
1926 
1927       if (bread <= 0)
1928 	return m_panic_defer_3(scanent, CUS callout_address,
1929 	  string_sprintf("unable to read from socket (%s)", strerror(errno)),
1930 	  malware_daemon_ctx.sock);
1931 
1932       if (bread == sizeof(av_buffer))
1933 	return m_panic_defer_3(scanent, CUS callout_address,
1934 		US"buffer too small", malware_daemon_ctx.sock);
1935       av_buffer[bread] = '\0';
1936       linebuffer = string_copy(av_buffer);
1937       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1938 	string_printing(linebuffer));
1939 
1940       /* try trigger match */
1941       if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1942 	{
1943 	if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1944 	  malware_name = US "unknown";
1945 	DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1946 	  string_printing(malware_name));
1947 	}
1948       else /* no virus found */
1949 	malware_name = NULL;
1950       break;
1951       }
1952 #endif
1953 
1954 #ifndef DISABLE_MAL_MKS
1955     case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1956       {
1957       char *mksd_options_end;
1958       int mksd_maxproc = 1;  /* default, if no option supplied */
1959       int retval;
1960 
1961       if (scanner_options)
1962 	{
1963 	mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1964 	if (  *scanner_options == '\0'
1965 	   || *mksd_options_end != '\0'
1966 	   || mksd_maxproc < 1
1967 	   || mksd_maxproc > 32
1968 	   )
1969 	  return m_panic_defer(scanent, CUS callout_address,
1970 	    string_sprintf("invalid option '%s'", scanner_options));
1971 	}
1972 
1973       if((malware_daemon_ctx.sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1974 	return m_panic_defer(scanent, CUS callout_address, errstr);
1975 
1976       malware_name = NULL;
1977 
1978       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1979 
1980       if ((retval = mksd_scan_packed(scanent, malware_daemon_ctx.sock, eml_filename, tmo)) != OK)
1981 	{
1982 	close (malware_daemon_ctx.sock);
1983 	return retval;
1984 	}
1985       break;
1986       }
1987 #endif
1988 
1989 #ifndef DISABLE_MAL_AVAST
1990     case M_AVAST: /* "avast" scanner type ----------------------------------- */
1991       {
1992       uschar buf[1024];
1993       uschar * scanrequest;
1994       enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1995       int nread;
1996       uschar * error_message = NULL;
1997       BOOL more_data = FALSE;
1998       BOOL strict = TRUE;
1999 
2000       /* According to Martin Tuma @avast the protocol uses "escaped
2001       whitespace", that is, every embedded whitespace is backslash
2002       escaped, as well as backslash is protected by backslash.
2003       The returned lines contain the name of the scanned file, a tab
2004       and the [ ] marker.
2005       [+] - not infected
2006       [L] - infected
2007       [E] - some error occurred
2008       Such marker follows the first non-escaped TAB.  For more information
2009       see avast-protocol(5)
2010 
2011       We observed two cases:
2012       -> SCAN /file
2013       <- /file [E]0.0 Error 13 Permission denied
2014       <- 451 SCAN Engine error 13 permission denied
2015 
2016       -> SCAN /file
2017       <- /file… [E]3.0 Error 41120 The file is a decompression bomb
2018       <- /file… [+]2.0
2019       <- /file… [+]2.0 0 Eicar Test Virus!!!
2020       <- 200 SCAN OK
2021 
2022       If the scanner returns 4xx, DEFER is a good decision, combined
2023       with a panic log entry, to get the admin's attention.
2024 
2025       If the scanner returns 200, we reject it as malware, if found any,
2026       or, in case of an error, we set the malware message to the error
2027       string.
2028 
2029       Some of the >= 42000 errors are message related - usually some
2030       broken archives etc, but some of them are e.g. license related.
2031       Once the license expires the engine starts returning errors for
2032       every scanning attempt.  I¹ have the full list of the error codes
2033       but it is not a public API and is subject to change. It is hard
2034       for me to say what you should do in case of an engine error. You
2035       can have a “Treat * unscanned file as infection” policy or “Treat
2036       unscanned file as clean” policy.  ¹) Jakub Bednar
2037 
2038        */
2039 
2040       if (  (  !ava_re_clean
2041             && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
2042 	 || (  !ava_re_virus
2043 	    && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
2044 	 || (  !ava_re_error
2045 	    && !(ava_re_error = m_pcre_compile(ava_re_error_str, &errstr)))
2046 	 )
2047 	return malware_panic_defer(errstr);
2048 
2049       /* wait for result */
2050       for (avast_stage = AVA_HELO;
2051 	   (nread = recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo)) > 0;
2052 	  )
2053 	{
2054 	int slen = Ustrlen(buf);
2055 	if (slen >= 1)
2056 	  {
2057 
2058           /* Multi line responses are bracketed between 210 … and nnn … */
2059           if (Ustrncmp(buf, "210", 3) == 0)
2060             {
2061             more_data = 1;
2062             continue;
2063             }
2064           else if (more_data && isdigit(buf[0])) more_data = 0;
2065 
2066 	  switch (avast_stage)
2067 	    {
2068 	    case AVA_HELO:
2069               if (more_data) continue;
2070 	      if (Ustrncmp(buf, "220", 3) != 0)
2071 		goto endloop;			/* require a 220 */
2072 	      goto sendreq;
2073 
2074 	    case AVA_OPT:
2075               if (more_data) continue;
2076 	      if (Ustrncmp(buf, "200", 3) != 0)
2077 		goto endloop;			/* require a 200 */
2078 
2079 	    sendreq:
2080 	      {
2081 	      int len;
2082 	      /* Check for another option to send. Newline-terminate it. */
2083 	      if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
2084 				NULL, 0)))
2085 		{
2086                 if (Ustrcmp(scanrequest, "pass_unscanned") == 0)
2087                   {
2088                   DEBUG(D_acl) debug_printf_indent("pass unscanned files as clean\n");
2089                   strict = FALSE;
2090                   goto sendreq;
2091                   }
2092 		scanrequest = string_sprintf("%s\n", scanrequest);
2093 		avast_stage = AVA_OPT;		/* just sent option */
2094 		DEBUG(D_acl) debug_printf_indent("send to avast OPTION: %s", scanrequest);
2095 		}
2096 	      else
2097 		{
2098 		scanrequest = string_sprintf("SCAN %s\n", eml_dir);
2099 		avast_stage = AVA_RSP;		/* just sent command */
2100 		DEBUG(D_acl) debug_printf_indent("send to avast REQUEST: SCAN %s\n", eml_dir);
2101 		}
2102 
2103 	      /* send config-cmd or scan-request to socket */
2104 	      len = Ustrlen(scanrequest);
2105 	      if (send(malware_daemon_ctx.sock, scanrequest, len, 0) == -1)
2106 		{
2107 		scanrequest[len-1] = '\0';
2108 		return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
2109 		      "unable to send request '%s' to socket (%s): %s",
2110 		      scanrequest, scanner_options, strerror(errno)), malware_daemon_ctx.sock);
2111 		}
2112 	      break;
2113 	      }
2114 
2115 	    case AVA_RSP:
2116 
2117 	      if (isdigit(buf[0]))  /* We're done */
2118                 goto endloop;
2119 
2120               if (malware_name)     /* Nothing else matters, just read on */
2121                 break;
2122 
2123 	      if (pcre_exec(ava_re_clean, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2124 		break;
2125 
2126               if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
2127                 {
2128                 unescape(malware_name);
2129                 DEBUG(D_acl)
2130                   debug_printf_indent("unescaped malware name: '%s'\n", malware_name);
2131                 break;
2132                 }
2133 
2134               if (strict)           /* treat scanner errors as malware */
2135                 {
2136                 if ((malware_name = m_pcre_exec(ava_re_error, buf)))
2137                   {
2138                   unescape(malware_name);
2139                   DEBUG(D_acl)
2140                     debug_printf_indent("unescaped error message: '%s'\n", malware_name);
2141                   break;
2142                   }
2143                 }
2144               else if (pcre_exec(ava_re_error, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2145                 {
2146                 log_write(0, LOG_MAIN, "internal scanner error (ignored): %s", buf);
2147                 break;
2148                 }
2149 
2150 	      /* here also for any unexpected response from the scanner */
2151               DEBUG(D_acl) debug_printf("avast response not handled: '%s'\n", buf);
2152 
2153 	      goto endloop;
2154 
2155 	    default:	log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
2156 			    __FILE__, __LINE__, __FUNCTION__);
2157 	    }
2158 	  }
2159 	}
2160 
2161       endloop:
2162 
2163       if (nread == -1) error_message = US"EOF from scanner";
2164       else if (nread < 0) error_message = US"timeout from scanner";
2165       else if (nread == 0) error_message = US"got nothing from scanner";
2166       else if (buf[0] != '2') error_message = buf;
2167 
2168       DEBUG(D_acl) debug_printf_indent("sent to avast QUIT\n");
2169       if (send(malware_daemon_ctx.sock, "QUIT\n", 5, 0) == -1)
2170         return m_panic_defer_3(scanent, CUS callout_address,
2171           string_sprintf("unable to send quit request to socket (%s): %s",
2172             scanner_options, strerror(errno)), malware_daemon_ctx.sock);
2173 
2174       if (error_message)
2175         return m_panic_defer_3(scanent, CUS callout_address, error_message, malware_daemon_ctx.sock);
2176 
2177       }
2178 #endif
2179   }	/* scanner type switch */
2180 
2181   if (malware_daemon_ctx.sock >= 0)
2182     (void) close (malware_daemon_ctx.sock);
2183   malware_ok = TRUE;			/* set "been here, done that" marker */
2184   }
2185 
2186 /* match virus name against pattern (caseless ------->----------v) */
2187 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
2188   {
2189   DEBUG(D_acl) debug_printf_indent(
2190       "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2191   return OK;
2192   }
2193 else
2194   return FAIL;
2195 }
2196 
2197 
2198 /*************************************************
2199 *          Scan an email for malware             *
2200 *************************************************/
2201 
2202 /* This is the normal interface for scanning an email, which doesn't need a
2203 filename; it's a wrapper around the malware_file function.
2204 
2205 Arguments:
2206   malware_re  match condition for "malware="
2207   timeout     if nonzero, timeout in seconds
2208 
2209 Returns:      Exim message processing code (OK, FAIL, DEFER, ...)
2210               where true means malware was found (condition applies)
2211 */
2212 int
malware(const uschar * malware_re,int timeout)2213 malware(const uschar * malware_re, int timeout)
2214 {
2215 int ret = malware_internal(malware_re, NULL, timeout);
2216 
2217 if (ret == DEFER) av_failed = TRUE;
2218 return ret;
2219 }
2220 
2221 
2222 /*************************************************
2223 *          Scan a file for malware               *
2224 *************************************************/
2225 
2226 /* This is a test wrapper for scanning an email, which is not used in
2227 normal processing.  Scan any file, using the Exim scanning interface.
2228 This function tampers with various global variables so is unsafe to use
2229 in any other context.
2230 
2231 Arguments:
2232   eml_filename  a file holding the message to be scanned
2233 
2234 Returns:        Exim message processing code (OK, FAIL, DEFER, ...)
2235                 where true means malware was found (condition applies)
2236 */
2237 int
malware_in_file(uschar * eml_filename)2238 malware_in_file(uschar *eml_filename)
2239 {
2240 uschar message_id_buf[64];
2241 int ret;
2242 
2243 /* spool_mbox() assumes various parameters exist, when creating
2244 the relevant directory and the email within */
2245 
2246 (void) string_format(message_id_buf, sizeof(message_id_buf),
2247     "dummy-%d", vaguely_random_number(INT_MAX));
2248 message_id = message_id_buf;
2249 sender_address = US"malware-sender@example.net";
2250 return_path = US"";
2251 recipients_list = NULL;
2252 receive_add_recipient(US"malware-victim@example.net", -1);
2253 f.enable_dollar_recipients = TRUE;
2254 
2255 ret = malware_internal(US"*", eml_filename, 0);
2256 
2257 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2258 spool_mbox_ok = 1;
2259 
2260 /* don't set no_mbox_unspool; at present, there's no way for it to become
2261 set, but if that changes, then it should apply to these tests too */
2262 
2263 unspool_mbox();
2264 
2265 /* silence static analysis tools */
2266 message_id = NULL;
2267 
2268 return ret;
2269 }
2270 
2271 
2272 void
malware_init(void)2273 malware_init(void)
2274 {
2275 if (!malware_default_re)
2276   malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2277 
2278 #ifndef DISABLE_MAL_DRWEB
2279 if (!drweb_re)
2280   drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2281 #endif
2282 #ifndef DISABLE_MAL_FSECURE
2283 if (!fsec_re)
2284   fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2285 #endif
2286 #ifndef DISABLE_MAL_KAV
2287 if (!kav_re_sus)
2288   kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2289 if (!kav_re_inf)
2290   kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2291 #endif
2292 #ifndef DISABLE_MAL_AVAST
2293 if (!ava_re_clean)
2294   ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2295 if (!ava_re_virus)
2296   ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2297 if (!ava_re_error)
2298   ava_re_error = regex_must_compile(ava_re_error_str, FALSE, TRUE);
2299 #endif
2300 #ifndef DISABLE_MAL_FFROT6D
2301 if (!fprot6d_re_error)
2302   fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2303 if (!fprot6d_re_virus)
2304   fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2305 #endif
2306 }
2307 
2308 
2309 gstring *
malware_show_supported(gstring * g)2310 malware_show_supported(gstring * g)
2311 {
2312 g = string_cat(g, US"Malware:");
2313 for (struct scan * sc = m_scans; sc->scancode != (scanner_t)-1; sc++)
2314   g = string_fmt_append(g, " %s", sc->name);
2315 return string_cat(g, US"\n");
2316 }
2317 
2318 
2319 # endif	/*!MACRO_PREDEF*/
2320 #endif /*WITH_CONTENT_SCAN*/
2321 /*
2322  * vi: aw ai sw=2
2323  */
2324