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