7c134d7597e8baaa2d9fd8b128c71ad0d42aedb7
[users/heiko/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 - 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
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 #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
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
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
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
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
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
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
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   {
281   struct timeval tv = {.tv_sec = 5};
282   fd_set fds;
283   FD_ZERO(fds); FD_SET(fd, &fds); (void) select(fd+1, NULL, &fds, NULL, &tv);
284   }
285 #endif
286 return fd;
287 }
288 #endif
289
290 static int
291 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
292 {
293 if (send(sock, buf, cnt, 0) < 0)
294   {
295   int err = errno;
296   (void)close(sock);
297   *errstr = string_sprintf("unable to send to socket (%s): %s",
298          buf, strerror(err));
299   return -1;
300   }
301 return sock;
302 }
303
304 static const pcre *
305 m_pcre_compile(const uschar * re, uschar ** errstr)
306 {
307 const uschar * rerror;
308 int roffset;
309 const pcre * cre;
310
311 if (!(cre = pcre_compile(CS re, PCRE_COPT, CCSS &rerror, &roffset, NULL)))
312   *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
313       re, rerror, roffset);
314 return cre;
315 }
316
317 uschar *
318 m_pcre_exec(const pcre * cre, uschar * text)
319 {
320 int ovector[10*3];
321 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
322               ovector, nelem(ovector));
323 uschar * substr = NULL;
324 if (i >= 2)                             /* Got it */
325   pcre_get_substring(CS text, ovector, i, 1, CCSS &substr);
326 return substr;
327 }
328
329 static const pcre *
330 m_pcre_nextinlist(const uschar ** list, int * sep,
331  char * listerr, uschar ** errstr)
332 {
333 const uschar * list_ele;
334 const pcre * cre = NULL;
335
336 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
337   *errstr = US listerr;
338 else
339   {
340   DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
341     string_printing(list_ele));
342   cre = m_pcre_compile(CUS list_ele, errstr);
343   }
344 return cre;
345 }
346
347
348 /*
349  Simple though inefficient wrapper for reading a line.  Drop CRs and the
350  trailing newline. Can return early on buffer full. Null-terminate.
351  Apply initial timeout if no data ready.
352
353  Return: number of chars - zero for an empty line
354          -1 on EOF
355          -2 on timeout or error
356 */
357 static int
358 recv_line(int fd, uschar * buffer, int bsize, time_t tmo)
359 {
360 uschar * p = buffer;
361 ssize_t rcv;
362 BOOL ok = FALSE;
363
364 if (!fd_ready(fd, tmo))
365   return -2;
366
367 /*XXX tmo handling assumes we always get a whole line */
368 /* read until \n */
369 errno = 0;
370 while ((rcv = read(fd, p, 1)) > 0)
371   {
372   ok = TRUE;
373   if (p-buffer > bsize-2) break;
374   if (*p == '\n') break;
375   if (*p != '\r') p++;
376   }
377 if (!ok)
378   {
379   DEBUG(D_acl)
380     {
381     debug_printf_indent("Malware scan: read %s (%s)\n",
382                 rcv==0 ? "EOF" : "error", strerror(errno));
383     debug_print_socket(fd);
384     }
385   return rcv==0 ? -1 : -2;
386   }
387 *p = '\0';
388
389 DEBUG(D_acl) debug_printf_indent("Malware scan: read '%s'\n", buffer);
390 return p - buffer;
391 }
392
393 /* return TRUE iff size as requested */
394 #ifndef DISABLE_MAL_DRWEB
395 static BOOL
396 recv_len(int sock, void * buf, int size, time_t tmo)
397 {
398 return fd_ready(sock, tmo)
399   ? recv(sock, buf, size, 0) == size
400   : FALSE;
401 }
402 #endif
403
404
405
406 #ifndef DISABLE_MAL_MKS
407 /* ============= private routines for the "mksd" scanner type ============== */
408
409 # include <sys/uio.h>
410
411 static inline int
412 mksd_writev (int sock, struct iovec * iov, int iovcnt)
413 {
414 int i;
415
416 for (;;)
417   {
418   do
419     i = writev (sock, iov, iovcnt);
420   while (i < 0 && errno == EINTR);
421   if (i <= 0)
422     {
423     (void) malware_panic_defer(
424             US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
425     return -1;
426     }
427   for (;;)      /* check for short write */
428     if (i >= iov->iov_len)
429       {
430       if (--iovcnt == 0)
431         return 0;
432       i -= iov->iov_len;
433       iov++;
434       }
435     else
436       {
437       iov->iov_len -= i;
438       iov->iov_base = CS iov->iov_base + i;
439       break;
440       }
441   }
442 }
443
444 static inline int
445 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, time_t tmo)
446 {
447 client_conn_ctx cctx = {.sock = sock};
448 int offset = 0;
449 int i;
450
451 do
452   {
453   i = ip_recv(&cctx, av_buffer+offset, av_buffer_size-offset, tmo);
454   if (i <= 0)
455     {
456     (void) malware_panic_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
457     return -1;
458     }
459
460   offset += i;
461   /* offset == av_buffer_size -> buffer full */
462   if (offset == av_buffer_size)
463     {
464     (void) malware_panic_defer(US"malformed reply received from mksd");
465     return -1;
466     }
467   } while (av_buffer[offset-1] != '\n');
468
469 av_buffer[offset] = '\0';
470 return offset;
471 }
472
473 static inline int
474 mksd_parse_line(struct scan * scanent, char * line)
475 {
476 char *p;
477
478 switch (*line)
479   {
480   case 'O': /* OK */
481     return OK;
482
483   case 'E':
484   case 'A': /* ERR */
485     if ((p = strchr (line, '\n')) != NULL)
486       *p = '\0';
487     return m_panic_defer(scanent, NULL,
488       string_sprintf("scanner failed: %s", line));
489
490   default: /* VIR */
491     if ((p = strchr (line, '\n')) != NULL)
492       {
493       *p = '\0';
494       if (  p-line > 5
495          && line[3] == ' '
496          && (p = strchr(line+4, ' ')) != NULL
497          && p-line > 4
498          )
499         {
500         *p = '\0';
501         malware_name = string_copy(US line+4);
502         return OK;
503         }
504       }
505     return m_panic_defer(scanent, NULL,
506       string_sprintf("malformed reply received: %s", line));
507   }
508 }
509
510 static int
511 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
512   time_t tmo)
513 {
514 struct iovec iov[3];
515 const char *cmd = "MSQ\n";
516 uschar av_buffer[1024];
517
518 iov[0].iov_base = (void *) cmd;
519 iov[0].iov_len = 3;
520 iov[1].iov_base = (void *) scan_filename;
521 iov[1].iov_len = Ustrlen(scan_filename);
522 iov[2].iov_base = (void *) (cmd + 3);
523 iov[2].iov_len = 1;
524
525 if (mksd_writev (sock, iov, 3) < 0)
526   return DEFER;
527
528 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
529   return DEFER;
530
531 return mksd_parse_line (scanent, CS av_buffer);
532 }
533 #endif  /* MKSD */
534
535
536 #ifndef DISABLE_MAL_CLAM
537 static int
538 clamd_option(clamd_address * cd, const uschar * optstr, int * subsep)
539 {
540 uschar * s;
541
542 cd->retry = 0;
543 while ((s = string_nextinlist(&optstr, subsep, NULL, 0)))
544   if (Ustrncmp(s, "retry=", 6) == 0)
545     {
546     int sec = readconf_readtime((s += 6), '\0', FALSE);
547     if (sec < 0)
548       return FAIL;
549     cd->retry = sec;
550     }
551   else
552     return FAIL;
553 return OK;
554 }
555 #endif
556
557
558
559 /*************************************************
560 *          Scan content for malware              *
561 *************************************************/
562
563 /* This is an internal interface for scanning an email; the normal interface
564 is via malware(), or there's malware_in_file() used for testing/debugging.
565
566 Arguments:
567   malware_re    match condition for "malware="
568   scan_filename  the file holding the email to be scanned, if we're faking
569                 this up for the -bmalware test, else NULL
570   timeout       if nonzero, non-default timeoutl
571
572 Returns:        Exim message processing code (OK, FAIL, DEFER, ...)
573                 where true means malware was found (condition applies)
574 */
575 static int
576 malware_internal(const uschar * malware_re, const uschar * scan_filename,
577   int timeout)
578 {
579 int sep = 0;
580 const uschar *av_scanner_work = av_scanner;
581 uschar *scanner_name;
582 unsigned long mbox_size;
583 FILE *mbox_file;
584 const pcre *re;
585 uschar * errstr;
586 struct scan * scanent;
587 const uschar * scanner_options;
588 client_conn_ctx malware_daemon_ctx = {.sock = -1};
589 time_t tmo;
590 uschar * eml_filename, * eml_dir;
591
592 if (!malware_re)
593   return FAIL;          /* empty means "don't match anything" */
594
595 /* Ensure the eml mbox file is spooled up */
596
597 if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
598   return malware_panic_defer(US"error while creating mbox spool file");
599
600 /* None of our current scanners need the mbox file as a stream (they use
601 the name), so we can close it right away.  Get the directory too. */
602
603 (void) fclose(mbox_file);
604 eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
605
606 /* parse 1st option */
607 if (strcmpic(malware_re, US"false") == 0  ||  Ustrcmp(malware_re,"0") == 0)
608   return FAIL;          /* explicitly no matching */
609
610 /* special cases (match anything except empty) */
611 if (  strcmpic(malware_re,US"true") == 0
612    || Ustrcmp(malware_re,"*") == 0
613    || Ustrcmp(malware_re,"1") == 0
614    )
615   {
616   if (  !malware_default_re
617      && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
618     return malware_panic_defer(errstr);
619   malware_re = malware_regex_default;
620   re = malware_default_re;
621   }
622
623 /* compile the regex, see if it works */
624 else if (!(re = m_pcre_compile(malware_re, &errstr)))
625   return malware_panic_defer(errstr);
626
627 /* if av_scanner starts with a dollar, expand it first */
628 if (*av_scanner == '$')
629   {
630   if (!(av_scanner_work = expand_string(av_scanner)))
631     return malware_panic_defer(
632          string_sprintf("av_scanner starts with $, but expansion failed: %s",
633          expand_string_message));
634
635   DEBUG(D_acl)
636     debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work);
637   /* disable result caching in this case */
638   malware_name = NULL;
639   malware_ok = FALSE;
640   }
641
642 /* Do not scan twice (unless av_scanner is dynamic). */
643 if (!malware_ok)
644   {
645   /* find the scanner type from the av_scanner option */
646   if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
647     return malware_panic_defer(US"av_scanner configuration variable is empty");
648   if (!timeout) timeout = MALWARE_TIMEOUT;
649   tmo = time(NULL) + timeout;
650
651   for (scanent = m_scans; ; scanent++)
652     {
653     if (!scanent->name)
654       return malware_panic_defer(string_sprintf("unknown scanner type '%s'",
655         scanner_name));
656     if (strcmpic(scanner_name, US scanent->name) != 0)
657       continue;
658     DEBUG(D_acl) debug_printf_indent("Malware scan:  %s tmo=%s\n",
659       scanner_name, readconf_printtime(timeout));
660
661     if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
662       scanner_options = scanent->options_default;
663     if (scanent->conn == MC_NONE)
664       break;
665
666     DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
667     switch(scanent->conn)
668     {
669     case MC_TCP:
670       malware_daemon_ctx.sock = ip_tcpsocket(scanner_options, &errstr, 5, NULL); break;
671     case MC_UNIX:
672       malware_daemon_ctx.sock = ip_unixsocket(scanner_options, &errstr);        break;
673     case MC_STRM:
674       malware_daemon_ctx.sock = ip_streamsocket(scanner_options, &errstr, 5, NULL); break;
675     default:
676       /* compiler quietening */ break;
677     }
678     if (malware_daemon_ctx.sock < 0)
679       return m_panic_defer(scanent, CUS callout_address, errstr);
680     break;
681   }
682
683   switch (scanent->scancode)
684     {
685 #ifndef DISABLE_MAL_FFROTD
686     case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
687       {
688       uschar *fp_scan_option;
689       unsigned int detected=0, par_count=0;
690       uschar * scanrequest;
691       uschar buf[32768], *strhelper, *strhelper2;
692       uschar * malware_name_internal = NULL;
693       int len;
694
695       scanrequest = string_sprintf("GET %s", eml_filename);
696
697       while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
698                             NULL, 0)))
699         {
700         scanrequest = string_sprintf("%s%s%s", scanrequest,
701                                   par_count ? "%20" : "?", fp_scan_option);
702         par_count++;
703         }
704       scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
705       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
706         scanner_name, scanrequest);
707
708       /* send scan request */
709       if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
710         return m_panic_defer(scanent, CUS callout_address, errstr);
711
712       while ((len = recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo)) >= 0)
713         if (len > 0)
714           {
715           if (Ustrstr(buf, US"<detected type=\"") != NULL)
716             detected = 1;
717           else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
718             {
719             if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
720               {
721               *strhelper2 = '\0';
722               malware_name_internal = string_copy(strhelper+6);
723               }
724             }
725           else if (Ustrstr(buf, US"<summary code=\""))
726             {
727             malware_name = Ustrstr(buf, US"<summary code=\"11\">")
728                 ? malware_name_internal : NULL;
729             break;
730             }
731           }
732       if (len < -1)
733         {
734         (void)close(malware_daemon_ctx.sock);
735         return DEFER;
736         }
737       break;
738       } /* f-protd */
739 #endif
740
741 #ifndef DISABLE_MAL_FFROT6D
742     case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
743       {
744       int bread;
745       uschar * e;
746       uschar * linebuffer;
747       uschar * scanrequest;
748       uschar av_buffer[1024];
749
750       if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
751         || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
752         return malware_panic_defer(errstr);
753
754       scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
755       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
756         scanner_name, scanrequest);
757
758       if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
759         return m_panic_defer(scanent, CUS callout_address, errstr);
760
761       bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo);
762
763       if (bread <= 0)
764         return m_panic_defer_3(scanent, CUS callout_address,
765           string_sprintf("unable to read from socket (%s)", strerror(errno)),
766           malware_daemon_ctx.sock);
767
768       if (bread == sizeof(av_buffer))
769         return m_panic_defer_3(scanent, CUS callout_address,
770           US"buffer too small", malware_daemon_ctx.sock);
771
772       av_buffer[bread] = '\0';
773       linebuffer = string_copy(av_buffer);
774
775       m_sock_send(malware_daemon_ctx.sock, US"QUIT\n", 5, 0);
776
777       if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
778         return m_panic_defer_3(scanent, CUS callout_address,
779           string_sprintf("scanner reported error (%s)", e), malware_daemon_ctx.sock);
780
781       if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
782         malware_name = NULL;
783
784       break;
785       }  /* f-prot6d */
786 #endif
787
788 #ifndef DISABLE_MAL_DRWEB
789     case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
790   /* v0.1 - added support for tcp sockets          */
791   /* v0.0 - initial release -- support for unix sockets      */
792       {
793       int result;
794       off_t fsize;
795       unsigned int fsize_uint;
796       uschar * tmpbuf, *drweb_fbuf;
797       int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
798           drweb_vnum, drweb_slen, drweb_fin = 0x0000;
799
800       /* prepare variables */
801       drweb_cmd = htonl(DRWEBD_SCAN_CMD);
802       drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
803
804       if (*scanner_options != '/')
805         {
806         /* calc file size */
807         if ((drweb_fd = exim_open2(CCS eml_filename, O_RDONLY)) == -1)
808           return m_panic_defer_3(scanent, NULL,
809             string_sprintf("can't open spool file %s: %s",
810               eml_filename, strerror(errno)),
811             malware_daemon_ctx.sock);
812
813         if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
814           {
815           int err;
816 badseek:  err = errno;
817           (void)close(drweb_fd);
818           return m_panic_defer_3(scanent, NULL,
819             string_sprintf("can't seek spool file %s: %s",
820               eml_filename, strerror(err)),
821             malware_daemon_ctx.sock);
822           }
823         fsize_uint = (unsigned int) fsize;
824         if ((off_t)fsize_uint != fsize)
825           {
826           (void)close(drweb_fd);
827           return m_panic_defer_3(scanent, NULL,
828             string_sprintf("seeking spool file %s, size overflow",
829               eml_filename),
830             malware_daemon_ctx.sock);
831           }
832         drweb_slen = htonl(fsize);
833         if (lseek(drweb_fd, 0, SEEK_SET) < 0)
834           goto badseek;
835
836         DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
837             scanner_name, scanner_options);
838
839         /* send scan request */
840         if ((send(malware_daemon_ctx.sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
841             (send(malware_daemon_ctx.sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
842             (send(malware_daemon_ctx.sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
843             (send(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
844           {
845           (void)close(drweb_fd);
846           return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
847             "unable to send commands to socket (%s)", scanner_options),
848             malware_daemon_ctx.sock);
849           }
850
851         if (!(drweb_fbuf = store_malloc(fsize_uint)))
852           {
853           (void)close(drweb_fd);
854           return m_panic_defer_3(scanent, NULL,
855             string_sprintf("unable to allocate memory %u for file (%s)",
856               fsize_uint, eml_filename),
857             malware_daemon_ctx.sock);
858           }
859
860         if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
861           {
862           int err = errno;
863           (void)close(drweb_fd);
864           store_free(drweb_fbuf);
865           return m_panic_defer_3(scanent, NULL,
866             string_sprintf("can't read spool file %s: %s",
867               eml_filename, strerror(err)),
868             malware_daemon_ctx.sock);
869           }
870         (void)close(drweb_fd);
871
872         /* send file body to socket */
873         if (send(malware_daemon_ctx.sock, drweb_fbuf, fsize, 0) < 0)
874           {
875           store_free(drweb_fbuf);
876           return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
877             "unable to send file body to socket (%s)", scanner_options),
878             malware_daemon_ctx.sock);
879           }
880         store_free(drweb_fbuf);
881         }
882       else
883         {
884         drweb_slen = htonl(Ustrlen(eml_filename));
885
886         DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n",
887             scanner_name, scanner_options);
888
889         /* send scan request */
890         if ((send(malware_daemon_ctx.sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
891             (send(malware_daemon_ctx.sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
892             (send(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
893             (send(malware_daemon_ctx.sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
894             (send(malware_daemon_ctx.sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
895           return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
896             "unable to send commands to socket (%s)", scanner_options),
897             malware_daemon_ctx.sock);
898         }
899
900       /* wait for result */
901       if (!recv_len(malware_daemon_ctx.sock, &drweb_rc, sizeof(drweb_rc), tmo))
902         return m_panic_defer_3(scanent, CUS callout_address,
903                     US"unable to read return code", malware_daemon_ctx.sock);
904       drweb_rc = ntohl(drweb_rc);
905
906       if (!recv_len(malware_daemon_ctx.sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
907         return m_panic_defer_3(scanent, CUS callout_address,
908                             US"unable to read the number of viruses", malware_daemon_ctx.sock);
909       drweb_vnum = ntohl(drweb_vnum);
910
911       /* "virus(es) found" if virus number is > 0 */
912       if (drweb_vnum)
913         {
914         gstring * g = NULL;
915
916         /* setup default virus name */
917         malware_name = US"unknown";
918
919         /* set up match regex */
920         if (!drweb_re)
921           drweb_re = m_pcre_compile(drweb_re_str, &errstr);
922
923         /* read and concatenate virus names into one string */
924         for (int i = 0; i < drweb_vnum; i++)
925           {
926           int ovector[10*3];
927
928           /* read the size of report */
929           if (!recv_len(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), tmo))
930             return m_panic_defer_3(scanent, CUS callout_address,
931                               US"cannot read report size", malware_daemon_ctx.sock);
932           drweb_slen = ntohl(drweb_slen);
933
934           /* assume tainted, since it is external input */
935           tmpbuf = store_get(drweb_slen, TRUE);
936
937           /* read report body */
938           if (!recv_len(malware_daemon_ctx.sock, tmpbuf, drweb_slen, tmo))
939             return m_panic_defer_3(scanent, CUS callout_address,
940                               US"cannot read report string", malware_daemon_ctx.sock);
941           tmpbuf[drweb_slen] = '\0';
942
943           /* try matcher on the line, grab substring */
944           result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
945                                   ovector, nelem(ovector));
946           if (result >= 2)
947             {
948             const char * pre_malware_nb;
949
950             pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
951
952             if (i==0)   /* the first name we just copy to malware_name */
953               g = string_cat(NULL, US pre_malware_nb);
954
955             /*XXX could be string_append_listele? */
956             else        /* concatenate each new virus name to previous */
957               g = string_append(g, 2, "/", pre_malware_nb);
958
959             pcre_free_substring(pre_malware_nb);
960             }
961           }
962           malware_name = string_from_gstring(g);
963         }
964       else
965         {
966         const char *drweb_s = NULL;
967
968         if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
969         if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
970         if (drweb_rc & DERR_TIMEOUT)  drweb_s = "timeout";
971         if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
972         /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
973          * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
974          * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
975          * and others are ignored */
976         if (drweb_s)
977           return m_panic_defer_3(scanent, CUS callout_address,
978             string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
979             malware_daemon_ctx.sock);
980
981         /* no virus found */
982         malware_name = NULL;
983         }
984       break;
985       } /* drweb */
986 #endif
987
988 #ifndef DISABLE_MAL_AVE
989     case M_AVES: /* "aveserver" scanner type -------------------------------- */
990       {
991       uschar buf[32768];
992       int result;
993
994       /* read aveserver's greeting and see if it is ready (2xx greeting) */
995       buf[0] = 0;
996       recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo);
997
998       if (buf[0] != '2')                /* aveserver is having problems */
999         return m_panic_defer_3(scanent, CUS callout_address,
1000           string_sprintf("unavailable (Responded: %s).",
1001                           ((buf[0] != 0) ? buf : US "nothing") ),
1002           malware_daemon_ctx.sock);
1003
1004       /* prepare our command */
1005       (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
1006                                                 eml_filename);
1007
1008       /* and send it */
1009       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
1010         scanner_name, buf);
1011       if (m_sock_send(malware_daemon_ctx.sock, buf, Ustrlen(buf), &errstr) < 0)
1012         return m_panic_defer(scanent, CUS callout_address, errstr);
1013
1014       malware_name = NULL;
1015       result = 0;
1016       /* read response lines, find malware name and final response */
1017       while (recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo) > 0)
1018         {
1019         if (buf[0] == '2')
1020           break;
1021         if (buf[0] == '5')              /* aveserver is having problems */
1022           {
1023           result = m_panic_defer(scanent, CUS callout_address,
1024              string_sprintf("unable to scan file %s (Responded: %s).",
1025                              eml_filename, buf));
1026           break;
1027           }
1028         if (Ustrncmp(buf,"322",3) == 0)
1029           {
1030           uschar *p = Ustrchr(&buf[4], ' ');
1031           *p = '\0';
1032           malware_name = string_copy(&buf[4]);
1033           }
1034         }
1035
1036       if (m_sock_send(malware_daemon_ctx.sock, US"quit\r\n", 6, &errstr) < 0)
1037         return m_panic_defer(scanent, CUS callout_address, errstr);
1038
1039       /* read aveserver's greeting and see if it is ready (2xx greeting) */
1040       buf[0] = 0;
1041       recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo);
1042
1043       if (buf[0] != '2')                /* aveserver is having problems */
1044         return m_panic_defer_3(scanent, CUS callout_address,
1045           string_sprintf("unable to quit dialogue (Responded: %s).",
1046                         ((buf[0] != 0) ? buf : US "nothing") ),
1047           malware_daemon_ctx.sock);
1048
1049       if (result == DEFER)
1050         {
1051         (void)close(malware_daemon_ctx.sock);
1052         return DEFER;
1053         }
1054       break;
1055       } /* aveserver */
1056 #endif
1057
1058 #ifndef DISABLE_MAL_FSECURE
1059     case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
1060       {
1061       int i, bread = 0;
1062       uschar * file_name;
1063       uschar av_buffer[1024];
1064       static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
1065                                       US"CONFIGURE\tTIMEOUT\t0\n",
1066                                       US"CONFIGURE\tMAXARCH\t5\n",
1067                                       US"CONFIGURE\tMIME\t1\n" };
1068
1069       malware_name = NULL;
1070
1071       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1072           scanner_name, scanner_options);
1073       /* pass options */
1074       memset(av_buffer, 0, sizeof(av_buffer));
1075       for (i = 0; i != nelem(cmdopt); i++)
1076         {
1077
1078         if (m_sock_send(malware_daemon_ctx.sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
1079           return m_panic_defer(scanent, CUS callout_address, errstr);
1080
1081         bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo);
1082         if (bread > 0) av_buffer[bread]='\0';
1083         if (bread < 0)
1084           return m_panic_defer_3(scanent, CUS callout_address,
1085             string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
1086             malware_daemon_ctx.sock);
1087         for (int j = 0; j < bread; j++)
1088           if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
1089             av_buffer[j] ='@';
1090         }
1091
1092       /* pass the mailfile to fsecure */
1093       file_name = string_sprintf("SCAN\t%s\n", eml_filename);
1094
1095       if (m_sock_send(malware_daemon_ctx.sock, file_name, Ustrlen(file_name), &errstr) < 0)
1096         return m_panic_defer(scanent, CUS callout_address, errstr);
1097
1098       /* set up match */
1099       /* todo also SUSPICION\t */
1100       if (!fsec_re)
1101         fsec_re = m_pcre_compile(fsec_re_str, &errstr);
1102
1103       /* read report, linewise. Apply a timeout as the Fsecure daemon
1104       sometimes wants an answer to "PING" but they won't tell us what */
1105         {
1106         uschar * p = av_buffer;
1107         uschar * q;
1108
1109         for (;;)
1110           {
1111           errno = ETIMEDOUT;
1112           i =  av_buffer+sizeof(av_buffer)-p;
1113           if ((bread= ip_recv(&malware_daemon_ctx, p, i-1, tmo)) < 0)
1114             return m_panic_defer_3(scanent, CUS callout_address,
1115               string_sprintf("unable to read result (%s)", strerror(errno)),
1116               malware_daemon_ctx.sock);
1117
1118           for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
1119             {
1120             *q = '\0';
1121
1122             /* Really search for virus again? */
1123             if (!malware_name)
1124               /* try matcher on the line, grab substring */
1125               malware_name = m_pcre_exec(fsec_re, p);
1126
1127             if (Ustrstr(p, "OK\tScan ok."))
1128               goto fsec_found;
1129             }
1130
1131           /* copy down the trailing partial line then read another chunk */
1132           i =  av_buffer+sizeof(av_buffer)-p;
1133           memmove(av_buffer, p, i);
1134           p = av_buffer+i;
1135           }
1136         }
1137
1138       fsec_found:
1139         break;
1140       } /* fsecure */
1141 #endif
1142
1143 #ifndef DISABLE_MAL_KAV
1144     case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
1145       {
1146       time_t t;
1147       uschar tmpbuf[1024];
1148       uschar * scanrequest;
1149       int kav_rc;
1150       unsigned long kav_reportlen;
1151       int bread;
1152       const pcre *kav_re;
1153       uschar *p;
1154
1155       /* get current date and time, build scan request */
1156       time(&t);
1157       /* pdp note: before the eml_filename parameter, this scanned the
1158       directory; not finding documentation, so we'll strip off the directory.
1159       The side-effect is that the test framework scanning may end up in
1160       scanning more than was requested, but for the normal interface, this is
1161       fine. */
1162
1163       strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
1164       scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
1165       p = Ustrrchr(scanrequest, '/');
1166       if (p)
1167         *p = '\0';
1168
1169       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1170           scanner_name, scanner_options);
1171
1172       /* send scan request */
1173       if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
1174         return m_panic_defer(scanent, CUS callout_address, errstr);
1175
1176       /* wait for result */
1177       if (!recv_len(malware_daemon_ctx.sock, tmpbuf, 2, tmo))
1178         return m_panic_defer_3(scanent, CUS callout_address,
1179                             US"unable to read 2 bytes from socket.", malware_daemon_ctx.sock);
1180
1181       /* get errorcode from one nibble */
1182       kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
1183       switch(kav_rc)
1184       {
1185       case 5: case 6: /* improper kavdaemon configuration */
1186         return m_panic_defer_3(scanent, CUS callout_address,
1187                 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
1188                 malware_daemon_ctx.sock);
1189       case 1:
1190         return m_panic_defer_3(scanent, CUS callout_address,
1191                 US"reported 'scanning not completed' (code 1).", malware_daemon_ctx.sock);
1192       case 7:
1193         return m_panic_defer_3(scanent, CUS callout_address,
1194                 US"reported 'kavdaemon damaged' (code 7).", malware_daemon_ctx.sock);
1195       }
1196
1197       /* code 8 is not handled, since it is ambiguous. It appears mostly on
1198       bounces where part of a file has been cut off */
1199
1200       /* "virus found" return codes (2-4) */
1201       if (kav_rc > 1 && kav_rc < 5)
1202         {
1203         int report_flag = 0;
1204
1205         /* setup default virus name */
1206         malware_name = US"unknown";
1207
1208         report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
1209
1210         /* read the report, if available */
1211         if (report_flag == 1)
1212           {
1213           /* read report size */
1214           if (!recv_len(malware_daemon_ctx.sock, &kav_reportlen, 4, tmo))
1215             return m_panic_defer_3(scanent, CUS callout_address,
1216                   US"cannot read report size", malware_daemon_ctx.sock);
1217
1218           /* it's possible that avp returns av_buffer[1] == 1 but the
1219           reportsize is 0 (!?) */
1220           if (kav_reportlen > 0)
1221             {
1222             /* set up match regex, depends on retcode */
1223             if (kav_rc == 3)
1224               {
1225               if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1226               kav_re = kav_re_sus;
1227               }
1228             else
1229               {
1230               if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1231               kav_re = kav_re_inf;
1232               }
1233
1234             /* read report, linewise.  Using size from stream to read amount of data
1235             from same stream is safe enough. */
1236             /* coverity[tainted_data] */
1237             while (kav_reportlen > 0)
1238               {
1239               if ((bread = recv_line(malware_daemon_ctx.sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1240                 break;
1241               kav_reportlen -= bread+1;
1242
1243               /* try matcher on the line, grab substring */
1244               if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1245                 break;
1246               }
1247             }
1248           }
1249         }
1250       else /* no virus found */
1251         malware_name = NULL;
1252
1253       break;
1254       }
1255 #endif
1256
1257 #ifndef DISABLE_MAL_CMDLINE
1258     case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1259       {
1260       const uschar *cmdline_scanner = scanner_options;
1261       const pcre *cmdline_trigger_re;
1262       const pcre *cmdline_regex_re;
1263       uschar * file_name;
1264       uschar * commandline;
1265       void (*eximsigchld)(int);
1266       void (*eximsigpipe)(int);
1267       FILE *scanner_out = NULL;
1268       int scanner_fd;
1269       FILE *scanner_record = NULL;
1270       uschar linebuffer[32767];
1271       int rcnt;
1272       int trigger = 0;
1273       uschar *p;
1274
1275       if (!cmdline_scanner)
1276         return m_panic_defer(scanent, NULL, errstr);
1277
1278       /* find scanner output trigger */
1279       cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1280                                 "missing trigger specification", &errstr);
1281       if (!cmdline_trigger_re)
1282         return m_panic_defer(scanent, NULL, errstr);
1283
1284       /* find scanner name regex */
1285       cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1286                           "missing virus name regex specification", &errstr);
1287       if (!cmdline_regex_re)
1288         return m_panic_defer(scanent, NULL, errstr);
1289
1290       /* prepare scanner call; despite the naming, file_name holds a directory
1291       name which is documented as the value given to %s. */
1292
1293       file_name = string_copy(eml_filename);
1294       p = Ustrrchr(file_name, '/');
1295       if (p)
1296         *p = '\0';
1297       commandline = string_sprintf(CS cmdline_scanner, file_name);
1298
1299       /* redirect STDERR too */
1300       commandline = string_sprintf("%s 2>&1", commandline);
1301
1302       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1303               scanner_name, commandline);
1304
1305       /* store exims signal handlers */
1306       eximsigchld = signal(SIGCHLD,SIG_DFL);
1307       eximsigpipe = signal(SIGPIPE,SIG_DFL);
1308
1309       if (!(scanner_out = popen(CS commandline,"r")))
1310         {
1311         int err = errno;
1312         signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1313         return m_panic_defer(scanent, NULL,
1314           string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1315         }
1316       scanner_fd = fileno(scanner_out);
1317
1318       file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
1319
1320       if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1321         {
1322         int err = errno;
1323         (void) pclose(scanner_out);
1324         signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1325         return m_panic_defer(scanent, NULL, string_sprintf(
1326             "opening scanner output file (%s) failed: %s.",
1327             file_name, strerror(err)));
1328         }
1329
1330       /* look for trigger while recording output */
1331       while ((rcnt = recv_line(scanner_fd, linebuffer,
1332                       sizeof(linebuffer), tmo)))
1333         {
1334         if (rcnt < 0)
1335           {
1336           int err = errno;
1337           if (rcnt == -1)
1338             break;
1339           (void) pclose(scanner_out);
1340           signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1341           return m_panic_defer(scanent, NULL, string_sprintf(
1342               "unable to read from scanner (%s): %s",
1343               commandline, strerror(err)));
1344           }
1345
1346         if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1347           {
1348           /* short write */
1349           (void) pclose(scanner_out);
1350           signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1351           return m_panic_defer(scanent, NULL, string_sprintf(
1352             "short write on scanner output file (%s).", file_name));
1353           }
1354         putc('\n', scanner_record);
1355         /* try trigger match */
1356         if (  !trigger
1357            && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1358            )
1359           trigger = 1;
1360         }
1361
1362       (void)fclose(scanner_record);
1363       sep = pclose(scanner_out);
1364       signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1365       if (sep != 0)
1366           return m_panic_defer(scanent, NULL,
1367               sep == -1
1368               ? string_sprintf("running scanner failed: %s", strerror(sep))
1369               : string_sprintf("scanner returned error code: %d", sep));
1370
1371       if (trigger)
1372         {
1373         uschar * s;
1374         /* setup default virus name */
1375         malware_name = US"unknown";
1376
1377         /* re-open the scanner output file, look for name match */
1378         scanner_record = Ufopen(file_name, "rb");
1379         while (Ufgets(linebuffer, sizeof(linebuffer), scanner_record))
1380           if ((s = m_pcre_exec(cmdline_regex_re, linebuffer))) /* try match */
1381             malware_name = s;
1382         (void)fclose(scanner_record);
1383         }
1384       else /* no virus found */
1385         malware_name = NULL;
1386       break;
1387       } /* cmdline */
1388 #endif
1389
1390 #ifndef DISABLE_MAL_SOPHIE
1391     case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1392       {
1393       int bread = 0;
1394       uschar *p;
1395       uschar * file_name;
1396       uschar av_buffer[1024];
1397
1398       /* pass the scan directory to sophie */
1399       file_name = string_copy(eml_filename);
1400       if ((p = Ustrrchr(file_name, '/')))
1401         *p = '\0';
1402
1403       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1404           scanner_name, scanner_options);
1405
1406       if (  write(malware_daemon_ctx.sock, file_name, Ustrlen(file_name)) < 0
1407          || write(malware_daemon_ctx.sock, "\n", 1) != 1
1408          )
1409         return m_panic_defer_3(scanent, CUS callout_address,
1410           string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1411           malware_daemon_ctx.sock);
1412
1413       /* wait for result */
1414       memset(av_buffer, 0, sizeof(av_buffer));
1415       if ((bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo)) <= 0)
1416         return m_panic_defer_3(scanent, CUS callout_address,
1417           string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1418           malware_daemon_ctx.sock);
1419
1420       /* infected ? */
1421       if (av_buffer[0] == '1') {
1422         uschar * s = Ustrchr(av_buffer, '\n');
1423         if (s)
1424           *s = '\0';
1425         malware_name = string_copy(&av_buffer[2]);
1426       }
1427       else if (!strncmp(CS av_buffer, "-1", 2))
1428         return m_panic_defer_3(scanent, CUS callout_address,
1429                 US"scanner reported error", malware_daemon_ctx.sock);
1430       else /* all ok, no virus */
1431         malware_name = NULL;
1432
1433       break;
1434       }
1435 #endif
1436
1437 #ifndef DISABLE_MAL_CLAM
1438     case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1439       {
1440 /* This code was originally contributed by David Saez */
1441 /* There are three scanning methods available to us:
1442 *  (1) Use the SCAN command, pointing to a file in the filesystem
1443 *  (2) Use the STREAM command, send the data on a separate port
1444 *  (3) Use the zINSTREAM command, send the data inline
1445 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1446 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1447 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1448 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM
1449 * See Exim bug 926 for details.  */
1450
1451       uschar *p, *vname, *result_tag;
1452       int bread=0;
1453       uschar av_buffer[1024];
1454       uschar *hostname = US"";
1455       host_item connhost;
1456       int clam_fd, result;
1457       unsigned int fsize_uint;
1458       BOOL use_scan_command = FALSE;
1459       clamd_address * cv[MAX_CLAMD_SERVERS];
1460       int num_servers = 0;
1461       uint32_t send_size, send_final_zeroblock;
1462       blob cmd_str;
1463
1464       /*XXX if unixdomain socket, only one server supported. Needs fixing;
1465       there's no reason we should not mix local and remote servers */
1466
1467       if (*scanner_options == '/')
1468         {
1469         clamd_address * cd;
1470         const uschar * sublist;
1471         int subsep = ' ';
1472
1473         /* Local file; so we def want to use_scan_command and don't want to try
1474          * passing IP/port combinations */
1475         use_scan_command = TRUE;
1476         cd = (clamd_address *) store_get(sizeof(clamd_address), FALSE);
1477
1478         /* extract socket-path part */
1479         sublist = scanner_options;
1480         cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1481
1482         /* parse options */
1483         if (clamd_option(cd, sublist, &subsep) != OK)
1484           return m_panic_defer(scanent, NULL,
1485             string_sprintf("bad option '%s'", scanner_options));
1486         cv[0] = cd;
1487         }
1488       else
1489         {
1490         /* Go through the rest of the list of host/port and construct an array
1491          * of servers to try. The first one is the bit we just passed from
1492          * scanner_options so process that first and then scan the remainder of
1493          * the address buffer */
1494         do
1495           {
1496           clamd_address * cd;
1497           const uschar * sublist;
1498           int subsep = ' ';
1499           uschar * s;
1500
1501           /* The 'local' option means use the SCAN command over the network
1502            * socket (ie common file storage in use) */
1503           /*XXX we could accept this also as a local option? */
1504           if (strcmpic(scanner_options, US"local") == 0)
1505             {
1506             use_scan_command = TRUE;
1507             continue;
1508             }
1509
1510           cd = (clamd_address *) store_get(sizeof(clamd_address), FALSE);
1511
1512           /* extract host and port part */
1513           sublist = scanner_options;
1514           if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1515             {
1516             (void) m_panic_defer(scanent, NULL,
1517                       string_sprintf("missing address: '%s'", scanner_options));
1518             continue;
1519             }
1520           if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1521             {
1522             (void) m_panic_defer(scanent, NULL,
1523                       string_sprintf("missing port: '%s'", scanner_options));
1524             continue;
1525             }
1526           cd->tcp_port = atoi(CS s);
1527
1528           /* parse options */
1529           /*XXX should these options be common over scanner types? */
1530           if (clamd_option(cd, sublist, &subsep) != OK)
1531             return m_panic_defer(scanent, NULL,
1532               string_sprintf("bad option '%s'", scanner_options));
1533
1534           cv[num_servers++] = cd;
1535           if (num_servers >= MAX_CLAMD_SERVERS)
1536             {
1537             (void) m_panic_defer(scanent, NULL,
1538                   US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1539                   "specified; only using the first " MAX_CLAMD_SERVERS_S );
1540             break;
1541             }
1542           } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1543                                         NULL, 0)));
1544
1545         /* check if we have at least one server */
1546         if (!num_servers)
1547           return m_panic_defer(scanent, NULL,
1548             US"no useable server addresses in malware configuration option.");
1549         }
1550
1551       /* See the discussion of response formats below to see why we really
1552       don't like colons in filenames when passing filenames to ClamAV. */
1553       if (use_scan_command && Ustrchr(eml_filename, ':'))
1554         return m_panic_defer(scanent, NULL,
1555           string_sprintf("local/SCAN mode incompatible with" \
1556             " : in path to email filename [%s]", eml_filename));
1557
1558       /* Set up the very first data we will be sending */
1559       if (!use_scan_command)
1560         { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1561       else
1562         cmd_str.data = string_sprintf("SCAN %s\n%n", eml_filename, &cmd_str.len);
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
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
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
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 *
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  */