Fix ClamAV command send
[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[EXIM_DRIVERNAME_MAX];
113
114 spf(buf, sizeof(buf), US"_HAVE_MALWARE_");
115
116 for (const struct scan * sc = m_scans; sc->scancode != -1; sc++)
117   {
118   for (s = sc->name, t = buf+14; *s; s++) if (*s != '-')
119     *t++ = toupper(*s);
120   *t = '\0';
121   builtin_macro_create(buf);
122   }
123 }
124
125 /******************************************************************************/
126 # else  /*!MACRO_PREDEF, main build*/
127
128
129 #define MALWARE_TIMEOUT 120     /* default timeout, seconds */
130
131 static const uschar * malware_regex_default = US ".+";
132 static const pcre * malware_default_re = NULL;
133
134
135 #ifndef DISABLE_MAL_CLAM
136 /* The maximum number of clamd servers that are supported in the configuration */
137 # define MAX_CLAMD_SERVERS 32
138 # define MAX_CLAMD_SERVERS_S "32"
139
140 typedef struct clamd_address {
141   uschar * hostspec;
142   unsigned tcp_port;
143   unsigned retry;
144 } clamd_address;
145 #endif
146
147
148 #ifndef DISABLE_MAL_DRWEB
149 # define DRWEBD_SCAN_CMD             (1)     /* scan file, buffer or diskfile */
150 # define DRWEBD_RETURN_VIRUSES       (1<<0)   /* ask daemon return to us viruses names from report */
151 # define DRWEBD_IS_MAIL              (1<<19)  /* say to daemon that format is "archive MAIL" */
152
153 # define DERR_READ_ERR               (1<<0)   /* read error */
154 # define DERR_NOMEMORY               (1<<2)   /* no memory */
155 # define DERR_TIMEOUT                (1<<9)   /* scan timeout has run out */
156 # define DERR_BAD_CALL               (1<<15)  /* wrong command */
157
158 static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$";
159 static const pcre * drweb_re = NULL;
160 #endif
161
162 #ifndef DISABLE_MAL_FSECURE
163 static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$";
164 static const pcre * fsec_re = NULL;
165 #endif
166
167 #ifndef DISABLE_MAL_KAV
168 static const uschar * kav_re_sus_str = US "suspicion:\\s*(.+?)\\s*$";
169 static const uschar * kav_re_inf_str = US "infected:\\s*(.+?)\\s*$";
170 static const pcre * kav_re_sus = NULL;
171 static const pcre * kav_re_inf = NULL;
172 #endif
173
174 #ifndef DISABLE_MAL_AVAST
175 static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]";
176 static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d+\\.0\\t0\\s(.*)";
177 static const uschar * ava_re_error_str = US "(?!\\\\)\\t\\[E\\]\\d+\\.0\\tError\\s\\d+\\s(.*)";
178 static const pcre * ava_re_clean = NULL;
179 static const pcre * ava_re_virus = NULL;
180 static const pcre * ava_re_error = NULL;
181 #endif
182
183 #ifndef DISABLE_MAL_FFROT6D
184 static const uschar * fprot6d_re_error_str = US "^\\d+\\s<(.+?)>$";
185 static const uschar * fprot6d_re_virus_str = US "^\\d+\\s<infected:\\s+(.+?)>\\s+.+$";
186 static const pcre * fprot6d_re_error = NULL;
187 static const pcre * fprot6d_re_virus = NULL;
188 #endif
189
190
191
192 /******************************************************************************/
193
194 #ifndef DISABLE_MAL_KAV
195 /* Routine to check whether a system is big- or little-endian.
196    Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
197    Needed for proper kavdaemon implementation. Sigh. */
198 # define BIG_MY_ENDIAN      0
199 # define LITTLE_MY_ENDIAN   1
200 static int test_byte_order(void);
201 static inline int
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         {
1563         int n;
1564         cmd_str.data = string_sprintf("SCAN %s\n%n", eml_filename, &n);
1565         cmd_str.len = n;                /* .len is a size_t */
1566         }
1567
1568       /* We have some network servers specified */
1569       if (num_servers)
1570         {
1571         /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1572         only supports AF_INET, but we should probably be looking to the
1573         future and rewriting this to be protocol-independent anyway. */
1574
1575         while (num_servers > 0)
1576           {
1577           int i = random_number(num_servers);
1578           clamd_address * cd = cv[i];
1579
1580           DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1581                          cd->hostspec, cd->tcp_port);
1582
1583           /* Lookup the host. This is to ensure that we connect to the same IP
1584           on both connections (as one host could resolve to multiple ips) */
1585           for (;;)
1586             {
1587             /*XXX we trust that the cmd_str is idempotent */
1588             if ((malware_daemon_ctx.sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1589                                     &connhost, &errstr,
1590                                     use_scan_command ? &cmd_str : NULL)) >= 0)
1591               {
1592               /* Connection successfully established with a server */
1593               hostname = cd->hostspec;
1594               if (use_scan_command) cmd_str.len = 0;
1595               break;
1596               }
1597             if (cd->retry <= 0) break;
1598             while (cd->retry > 0) cd->retry = sleep(cd->retry);
1599             }
1600           if (malware_daemon_ctx.sock >= 0)
1601             break;
1602
1603           (void) m_panic_defer(scanent, CUS callout_address, errstr);
1604
1605           /* Remove the server from the list. XXX We should free the memory */
1606           num_servers--;
1607           for (; i < num_servers; i++)
1608             cv[i] = cv[i+1];
1609           }
1610
1611         if (num_servers == 0)
1612           return m_panic_defer(scanent, NULL, US"all servers failed");
1613         }
1614       else
1615         for (;;)
1616           {
1617           if ((malware_daemon_ctx.sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1618             {
1619             hostname = cv[0]->hostspec;
1620             break;
1621             }
1622           if (cv[0]->retry <= 0)
1623             return m_panic_defer(scanent, CUS callout_address, errstr);
1624           while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1625           }
1626
1627       /* have socket in variable "sock"; command to use is semi-independent of
1628       the socket protocol.  We use SCAN if is local (either Unix/local
1629       domain socket, or explicitly told local) else we stream the data.
1630       How we stream the data depends upon how we were built.  */
1631
1632       if (!use_scan_command)
1633         {
1634         struct stat st;
1635 #if defined(EXIM_TCP_CORK) && !defined(OS_SENDFILE)
1636         BOOL corked = TRUE;
1637 #endif
1638         /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1639         chunks, <n> a 4-byte number (network order), terminated by a zero-length
1640         chunk. We only send one chunk. */
1641
1642         DEBUG(D_acl) debug_printf_indent(
1643             "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1644             scanner_name);
1645
1646 #if defined(EXIM_TCP_CORK)
1647         (void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
1648                           US &on, sizeof(on));
1649 #endif
1650         /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1651         if (cmd_str.len)
1652           if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0)
1653             return m_panic_defer_3(scanent, CUS hostname,
1654               string_sprintf("unable to send zINSTREAM to socket (%s)",
1655                 strerror(errno)),
1656               malware_daemon_ctx.sock);
1657
1658         if ((clam_fd = exim_open2(CS eml_filename, O_RDONLY)) < 0)
1659           {
1660           int err = errno;
1661           return m_panic_defer_3(scanent, NULL,
1662             string_sprintf("can't open spool file %s: %s",
1663               eml_filename, strerror(err)),
1664             malware_daemon_ctx.sock);
1665           }
1666         if (fstat(clam_fd, &st) < 0)
1667           {
1668           int err = errno;
1669           (void)close(clam_fd);
1670           return m_panic_defer_3(scanent, NULL,
1671             string_sprintf("can't stat spool file %s: %s",
1672               eml_filename, strerror(err)),
1673             malware_daemon_ctx.sock);
1674           }
1675         fsize_uint = (unsigned int) st.st_size;
1676         if ((off_t)fsize_uint != st.st_size)
1677           {
1678           (void)close(clam_fd);
1679           return m_panic_defer_3(scanent, NULL,
1680             string_sprintf("stat spool file %s, size overflow", eml_filename),
1681             malware_daemon_ctx.sock);
1682           }
1683
1684         /* send file size */
1685         send_size = htonl(fsize_uint);
1686         if (send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0)
1687           return m_panic_defer_3(scanent, NULL,
1688             string_sprintf("unable to send file size to socket (%s)", hostname),
1689             malware_daemon_ctx.sock);
1690
1691         /* send file body */
1692         while (fsize_uint)
1693           {
1694 #ifdef OS_SENDFILE
1695           int n = os_sendfile(malware_daemon_ctx.sock, clam_fd, NULL, (size_t)fsize_uint);
1696           if (n < 0)
1697             return m_panic_defer_3(scanent, NULL,
1698               string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
1699               malware_daemon_ctx.sock);
1700           fsize_uint -= n;
1701 #else
1702           int n = MIN(fsize_uint, big_buffer_size);
1703           if ((n = read(clam_fd, big_buffer, n)) < 0)
1704             return m_panic_defer_3(scanent, NULL,
1705               string_sprintf("can't read spool file %s: %s",
1706                 eml_filename, strerror(errno)),
1707               malware_daemon_ctx.sock);
1708           if (send(malware_daemon_ctx.sock, big_buffer, (size_t)n, 0) < 0)
1709             return m_panic_defer_3(scanent, NULL,
1710               string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
1711               malware_daemon_ctx.sock);
1712           fsize_uint -= n;
1713 # ifdef EXIM_TCP_CORK
1714           if (corked)
1715             {
1716             corked = FALSE;
1717             (void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
1718                               US &off, sizeof(off));
1719             }
1720 # endif
1721 #endif  /*!OS_SENDFILE*/
1722
1723           }
1724
1725         send_final_zeroblock = 0;
1726         if (send(malware_daemon_ctx.sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0)
1727           return m_panic_defer_3(scanent, NULL,
1728             string_sprintf("unable to send file terminator to socket (%s)", hostname),
1729             malware_daemon_ctx.sock);
1730 #ifdef OS_SENDFILE
1731         (void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
1732                           US &off, sizeof(off));
1733 #endif
1734         }
1735       else
1736         { /* use scan command */
1737         /* Send a SCAN command pointing to a filename; then in the then in the
1738         scan-method-neutral part, read the response back */
1739
1740 /* ================================================================= */
1741
1742         /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1743         which dates to when ClamAV needed us to break apart the email into the
1744         MIME parts (eg, with the now deprecated demime condition coming first).
1745         Some time back, ClamAV gained the ability to deconstruct the emails, so
1746         doing this would actually have resulted in the mail attachments being
1747         scanned twice, in the broken out files and from the original .eml.
1748         Since ClamAV now handles emails (and has for quite some time) we can
1749         just use the email file itself. */
1750         /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
1751
1752         DEBUG(D_acl) debug_printf_indent(
1753             "Malware scan: issuing %s local-path scan [%s]\n",
1754             scanner_name, scanner_options);
1755
1756         if (cmd_str.len)
1757           if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0)
1758             return m_panic_defer_3(scanent, CUS callout_address,
1759               string_sprintf("unable to write to socket (%s)", strerror(errno)),
1760               malware_daemon_ctx.sock);
1761
1762         /* Do not shut down the socket for writing; a user report noted that
1763         clamd 0.70 does not react well to this. */
1764         }
1765       /* Commands have been sent, no matter which scan method or connection
1766       type we're using; now just read the result, independent of method. */
1767
1768       /* Read the result */
1769       memset(av_buffer, 0, sizeof(av_buffer));
1770       bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo);
1771       (void)close(malware_daemon_ctx.sock);
1772       malware_daemon_ctx.sock = -1;
1773       malware_daemon_ctx.tls_ctx = NULL;
1774
1775       if (bread <= 0)
1776         return m_panic_defer(scanent, CUS callout_address,
1777           string_sprintf("unable to read from socket (%s)",
1778           errno == 0 ? "EOF" : strerror(errno)));
1779
1780       if (bread == sizeof(av_buffer))
1781         return m_panic_defer(scanent, CUS callout_address,
1782                 US"buffer too small");
1783       /* We're now assured of a NULL at the end of av_buffer */
1784
1785       /* Check the result. ClamAV returns one of two result formats.
1786       In the basic mode, the response is of the form:
1787         infected: -> "<filename>: <virusname> FOUND"
1788         not-infected: -> "<filename>: OK"
1789         error: -> "<filename>: <errcode> ERROR
1790       If the ExtendedDetectionInfo option has been turned on, then we get:
1791         "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1792       for the infected case.  Compare:
1793 /tmp/eicar.com: Eicar-Test-Signature FOUND
1794 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1795
1796       In the streaming case, clamd uses the filename "stream" which you should
1797       be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }.  (The
1798       client app will replace "stream" with the original filename before returning
1799       results to stdout, but the trace shows the data).
1800
1801       We will assume that the pathname passed to clamd from Exim does not contain
1802       a colon.  We will have whined loudly above if the eml_filename does (and we're
1803       passing a filename to clamd). */
1804
1805       if (!(*av_buffer))
1806         return m_panic_defer(scanent, CUS callout_address,
1807                 US"ClamAV returned null");
1808
1809       /* strip newline at the end (won't be present for zINSTREAM)
1810       (also any trailing whitespace, which shouldn't exist, but we depend upon
1811       this below, so double-check) */
1812
1813       p = av_buffer + Ustrlen(av_buffer) - 1;
1814       if (*p == '\n') *p = '\0';
1815
1816       DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1817
1818       while (isspace(*--p) && (p > av_buffer))
1819         *p = '\0';
1820       if (*p) ++p;
1821
1822       /* colon in returned output? */
1823       if (!(p = Ustrchr(av_buffer,':')))
1824         return m_panic_defer(scanent, CUS callout_address, string_sprintf(
1825                   "ClamAV returned malformed result (missing colon): %s",
1826                   av_buffer));
1827
1828       /* strip filename */
1829       while (*p && isspace(*++p)) /**/;
1830       vname = p;
1831
1832       /* It would be bad to encounter a virus with "FOUND" in part of the name,
1833       but we should at least be resistant to it. */
1834       p = Ustrrchr(vname, ' ');
1835       result_tag = p ? p+1 : vname;
1836
1837       if (Ustrcmp(result_tag, "FOUND") == 0)
1838         {
1839         /* p should still be the whitespace before the result_tag */
1840         while (isspace(*p)) --p;
1841         *++p = '\0';
1842         /* Strip off the extended information too, which will be in parens
1843         after the virus name, with no intervening whitespace. */
1844         if (*--p == ')')
1845           {
1846           /* "(hash:size)", so previous '(' will do; if not found, we have
1847           a curious virus name, but not an error. */
1848           p = Ustrrchr(vname, '(');
1849           if (p)
1850             *p = '\0';
1851           }
1852         malware_name = string_copy(vname);
1853         DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1854
1855         }
1856       else if (Ustrcmp(result_tag, "ERROR") == 0)
1857         return m_panic_defer(scanent, CUS callout_address,
1858           string_sprintf("ClamAV returned: %s", av_buffer));
1859
1860       else if (Ustrcmp(result_tag, "OK") == 0)
1861         {
1862         /* Everything should be OK */
1863         malware_name = NULL;
1864         DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1865
1866         }
1867       else
1868         return m_panic_defer(scanent, CUS callout_address,
1869           string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1870
1871       break;
1872       } /* clamd */
1873 #endif
1874
1875 #ifndef DISABLE_MAL_SOCK
1876     case M_SOCK: /* "sock" scanner type ------------------------------------- */
1877     /* This code was derived by Martin Poole from the clamd code contributed
1878        by David Saez and the cmdline code
1879     */
1880       {
1881       int bread;
1882       uschar * commandline;
1883       uschar av_buffer[1024];
1884       uschar * linebuffer;
1885       uschar * sockline_scanner;
1886       uschar sockline_scanner_default[] = "%s\n";
1887       const pcre *sockline_trig_re;
1888       const pcre *sockline_name_re;
1889
1890       /* find scanner command line */
1891       if (  (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1892                                           NULL, 0))
1893          && *sockline_scanner
1894          )
1895       { /* check for no expansions apart from one %s */
1896         uschar * s = Ustrchr(sockline_scanner, '%');
1897         if (s++)
1898           if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1899             return m_panic_defer_3(scanent, NULL,
1900                                   US"unsafe sock scanner call spec", malware_daemon_ctx.sock);
1901       }
1902       else
1903         sockline_scanner = sockline_scanner_default;
1904       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1905         string_printing(sockline_scanner));
1906
1907       /* find scanner output trigger */
1908       sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1909                                 "missing trigger specification", &errstr);
1910       if (!sockline_trig_re)
1911         return m_panic_defer_3(scanent, NULL, errstr, malware_daemon_ctx.sock);
1912
1913       /* find virus name regex */
1914       sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1915                           "missing virus name regex specification", &errstr);
1916       if (!sockline_name_re)
1917         return m_panic_defer_3(scanent, NULL, errstr, malware_daemon_ctx.sock);
1918
1919       /* prepare scanner call - security depends on expansions check above */
1920       commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1921       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1922         string_printing(commandline));
1923
1924       /* Pass the command string to the socket */
1925       if (m_sock_send(malware_daemon_ctx.sock, commandline, Ustrlen(commandline), &errstr) < 0)
1926         return m_panic_defer(scanent, CUS callout_address, errstr);
1927
1928       /* Read the result */
1929       bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo);
1930
1931       if (bread <= 0)
1932         return m_panic_defer_3(scanent, CUS callout_address,
1933           string_sprintf("unable to read from socket (%s)", strerror(errno)),
1934           malware_daemon_ctx.sock);
1935
1936       if (bread == sizeof(av_buffer))
1937         return m_panic_defer_3(scanent, CUS callout_address,
1938                 US"buffer too small", malware_daemon_ctx.sock);
1939       av_buffer[bread] = '\0';
1940       linebuffer = string_copy(av_buffer);
1941       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1942         string_printing(linebuffer));
1943
1944       /* try trigger match */
1945       if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1946         {
1947         if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1948           malware_name = US "unknown";
1949         DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1950           string_printing(malware_name));
1951         }
1952       else /* no virus found */
1953         malware_name = NULL;
1954       break;
1955       }
1956 #endif
1957
1958 #ifndef DISABLE_MAL_MKS
1959     case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1960       {
1961       char *mksd_options_end;
1962       int mksd_maxproc = 1;  /* default, if no option supplied */
1963       int retval;
1964
1965       if (scanner_options)
1966         {
1967         mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1968         if (  *scanner_options == '\0'
1969            || *mksd_options_end != '\0'
1970            || mksd_maxproc < 1
1971            || mksd_maxproc > 32
1972            )
1973           return m_panic_defer(scanent, CUS callout_address,
1974             string_sprintf("invalid option '%s'", scanner_options));
1975         }
1976
1977       if((malware_daemon_ctx.sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1978         return m_panic_defer(scanent, CUS callout_address, errstr);
1979
1980       malware_name = NULL;
1981
1982       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1983
1984       if ((retval = mksd_scan_packed(scanent, malware_daemon_ctx.sock, eml_filename, tmo)) != OK)
1985         {
1986         close (malware_daemon_ctx.sock);
1987         return retval;
1988         }
1989       break;
1990       }
1991 #endif
1992
1993 #ifndef DISABLE_MAL_AVAST
1994     case M_AVAST: /* "avast" scanner type ----------------------------------- */
1995       {
1996       uschar buf[1024];
1997       uschar * scanrequest;
1998       enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1999       int nread;
2000       uschar * error_message = NULL;
2001       BOOL more_data = FALSE;
2002       BOOL strict = TRUE;
2003
2004       /* According to Martin Tuma @avast the protocol uses "escaped
2005       whitespace", that is, every embedded whitespace is backslash
2006       escaped, as well as backslash is protected by backslash.
2007       The returned lines contain the name of the scanned file, a tab
2008       and the [ ] marker.
2009       [+] - not infected
2010       [L] - infected
2011       [E] - some error occurred
2012       Such marker follows the first non-escaped TAB.  For more information
2013       see avast-protocol(5)
2014
2015       We observed two cases:
2016       -> SCAN /file
2017       <- /file [E]0.0 Error 13 Permission denied
2018       <- 451 SCAN Engine error 13 permission denied
2019
2020       -> SCAN /file
2021       <- /file… [E]3.0 Error 41120 The file is a decompression bomb
2022       <- /file… [+]2.0
2023       <- /file… [+]2.0 0 Eicar Test Virus!!!
2024       <- 200 SCAN OK
2025
2026       If the scanner returns 4xx, DEFER is a good decision, combined
2027       with a panic log entry, to get the admin's attention.
2028
2029       If the scanner returns 200, we reject it as malware, if found any,
2030       or, in case of an error, we set the malware message to the error
2031       string.
2032
2033       Some of the >= 42000 errors are message related - usually some
2034       broken archives etc, but some of them are e.g. license related.
2035       Once the license expires the engine starts returning errors for
2036       every scanning attempt.  I¹ have the full list of the error codes
2037       but it is not a public API and is subject to change. It is hard
2038       for me to say what you should do in case of an engine error. You
2039       can have a “Treat * unscanned file as infection” policy or “Treat
2040       unscanned file as clean” policy.  ¹) Jakub Bednar
2041
2042        */
2043
2044       if (  (  !ava_re_clean
2045             && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
2046          || (  !ava_re_virus
2047             && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
2048          || (  !ava_re_error
2049             && !(ava_re_error = m_pcre_compile(ava_re_error_str, &errstr)))
2050          )
2051         return malware_panic_defer(errstr);
2052
2053       /* wait for result */
2054       for (avast_stage = AVA_HELO;
2055            (nread = recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo)) > 0;
2056           )
2057         {
2058         int slen = Ustrlen(buf);
2059         if (slen >= 1)
2060           {
2061
2062           /* Multi line responses are bracketed between 210 … and nnn … */
2063           if (Ustrncmp(buf, "210", 3) == 0)
2064             {
2065             more_data = 1;
2066             continue;
2067             }
2068           else if (more_data && isdigit(buf[0])) more_data = 0;
2069
2070           switch (avast_stage)
2071             {
2072             case AVA_HELO:
2073               if (more_data) continue;
2074               if (Ustrncmp(buf, "220", 3) != 0)
2075                 goto endloop;                   /* require a 220 */
2076               goto sendreq;
2077
2078             case AVA_OPT:
2079               if (more_data) continue;
2080               if (Ustrncmp(buf, "200", 3) != 0)
2081                 goto endloop;                   /* require a 200 */
2082
2083             sendreq:
2084               {
2085               int len;
2086               /* Check for another option to send. Newline-terminate it. */
2087               if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
2088                                 NULL, 0)))
2089                 {
2090                 if (Ustrcmp(scanrequest, "pass_unscanned") == 0)
2091                   {
2092                   DEBUG(D_acl) debug_printf_indent("pass unscanned files as clean\n");
2093                   strict = FALSE;
2094                   goto sendreq;
2095                   }
2096                 scanrequest = string_sprintf("%s\n", scanrequest);
2097                 avast_stage = AVA_OPT;          /* just sent option */
2098                 DEBUG(D_acl) debug_printf_indent("send to avast OPTION: %s", scanrequest);
2099                 }
2100               else
2101                 {
2102                 scanrequest = string_sprintf("SCAN %s\n", eml_dir);
2103                 avast_stage = AVA_RSP;          /* just sent command */
2104                 DEBUG(D_acl) debug_printf_indent("send to avast REQUEST: SCAN %s\n", eml_dir);
2105                 }
2106
2107               /* send config-cmd or scan-request to socket */
2108               len = Ustrlen(scanrequest);
2109               if (send(malware_daemon_ctx.sock, scanrequest, len, 0) == -1)
2110                 {
2111                 scanrequest[len-1] = '\0';
2112                 return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
2113                       "unable to send request '%s' to socket (%s): %s",
2114                       scanrequest, scanner_options, strerror(errno)), malware_daemon_ctx.sock);
2115                 }
2116               break;
2117               }
2118
2119             case AVA_RSP:
2120
2121               if (isdigit(buf[0]))  /* We're done */
2122                 goto endloop;
2123
2124               if (malware_name)     /* Nothing else matters, just read on */
2125                 break;
2126
2127               if (pcre_exec(ava_re_clean, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2128                 break;
2129
2130               if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
2131                 {
2132                 unescape(malware_name);
2133                 DEBUG(D_acl)
2134                   debug_printf_indent("unescaped malware name: '%s'\n", malware_name);
2135                 break;
2136                 }
2137
2138               if (strict)           /* treat scanner errors as malware */
2139                 {
2140                 if ((malware_name = m_pcre_exec(ava_re_error, buf)))
2141                   {
2142                   unescape(malware_name);
2143                   DEBUG(D_acl)
2144                     debug_printf_indent("unescaped error message: '%s'\n", malware_name);
2145                   break;
2146                   }
2147                 }
2148               else if (pcre_exec(ava_re_error, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2149                 {
2150                 log_write(0, LOG_MAIN, "internal scanner error (ignored): %s", buf);
2151                 break;
2152                 }
2153
2154               /* here also for any unexpected response from the scanner */
2155               DEBUG(D_acl) debug_printf("avast response not handled: '%s'\n", buf);
2156
2157               goto endloop;
2158
2159             default:    log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
2160                             __FILE__, __LINE__, __FUNCTION__);
2161             }
2162           }
2163         }
2164
2165       endloop:
2166
2167       if (nread == -1) error_message = US"EOF from scanner";
2168       else if (nread < 0) error_message = US"timeout from scanner";
2169       else if (nread == 0) error_message = US"got nothing from scanner";
2170       else if (buf[0] != '2') error_message = buf;
2171
2172       DEBUG(D_acl) debug_printf_indent("sent to avast QUIT\n");
2173       if (send(malware_daemon_ctx.sock, "QUIT\n", 5, 0) == -1)
2174         return m_panic_defer_3(scanent, CUS callout_address,
2175           string_sprintf("unable to send quit request to socket (%s): %s",
2176             scanner_options, strerror(errno)), malware_daemon_ctx.sock);
2177
2178       if (error_message)
2179         return m_panic_defer_3(scanent, CUS callout_address, error_message, malware_daemon_ctx.sock);
2180
2181       }
2182 #endif
2183   }     /* scanner type switch */
2184
2185   if (malware_daemon_ctx.sock >= 0)
2186     (void) close (malware_daemon_ctx.sock);
2187   malware_ok = TRUE;                    /* set "been here, done that" marker */
2188   }
2189
2190 /* match virus name against pattern (caseless ------->----------v) */
2191 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
2192   {
2193   DEBUG(D_acl) debug_printf_indent(
2194       "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2195   return OK;
2196   }
2197 else
2198   return FAIL;
2199 }
2200
2201
2202 /*************************************************
2203 *          Scan an email for malware             *
2204 *************************************************/
2205
2206 /* This is the normal interface for scanning an email, which doesn't need a
2207 filename; it's a wrapper around the malware_file function.
2208
2209 Arguments:
2210   malware_re  match condition for "malware="
2211   timeout     if nonzero, timeout in seconds
2212
2213 Returns:      Exim message processing code (OK, FAIL, DEFER, ...)
2214               where true means malware was found (condition applies)
2215 */
2216 int
2217 malware(const uschar * malware_re, int timeout)
2218 {
2219 int ret = malware_internal(malware_re, NULL, timeout);
2220
2221 if (ret == DEFER) av_failed = TRUE;
2222 return ret;
2223 }
2224
2225
2226 /*************************************************
2227 *          Scan a file for malware               *
2228 *************************************************/
2229
2230 /* This is a test wrapper for scanning an email, which is not used in
2231 normal processing.  Scan any file, using the Exim scanning interface.
2232 This function tampers with various global variables so is unsafe to use
2233 in any other context.
2234
2235 Arguments:
2236   eml_filename  a file holding the message to be scanned
2237
2238 Returns:        Exim message processing code (OK, FAIL, DEFER, ...)
2239                 where true means malware was found (condition applies)
2240 */
2241 int
2242 malware_in_file(uschar *eml_filename)
2243 {
2244 uschar message_id_buf[64];
2245 int ret;
2246
2247 /* spool_mbox() assumes various parameters exist, when creating
2248 the relevant directory and the email within */
2249
2250 (void) string_format(message_id_buf, sizeof(message_id_buf),
2251     "dummy-%d", vaguely_random_number(INT_MAX));
2252 message_id = message_id_buf;
2253 sender_address = US"malware-sender@example.net";
2254 return_path = US"";
2255 recipients_list = NULL;
2256 receive_add_recipient(US"malware-victim@example.net", -1);
2257 f.enable_dollar_recipients = TRUE;
2258
2259 ret = malware_internal(US"*", eml_filename, 0);
2260
2261 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2262 spool_mbox_ok = 1;
2263
2264 /* don't set no_mbox_unspool; at present, there's no way for it to become
2265 set, but if that changes, then it should apply to these tests too */
2266
2267 unspool_mbox();
2268
2269 /* silence static analysis tools */
2270 message_id = NULL;
2271
2272 return ret;
2273 }
2274
2275
2276 void
2277 malware_init(void)
2278 {
2279 if (!malware_default_re)
2280   malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2281
2282 #ifndef DISABLE_MAL_DRWEB
2283 if (!drweb_re)
2284   drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2285 #endif
2286 #ifndef DISABLE_MAL_FSECURE
2287 if (!fsec_re)
2288   fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2289 #endif
2290 #ifndef DISABLE_MAL_KAV
2291 if (!kav_re_sus)
2292   kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2293 if (!kav_re_inf)
2294   kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2295 #endif
2296 #ifndef DISABLE_MAL_AVAST
2297 if (!ava_re_clean)
2298   ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2299 if (!ava_re_virus)
2300   ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2301 if (!ava_re_error)
2302   ava_re_error = regex_must_compile(ava_re_error_str, FALSE, TRUE);
2303 #endif
2304 #ifndef DISABLE_MAL_FFROT6D
2305 if (!fprot6d_re_error)
2306   fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2307 if (!fprot6d_re_virus)
2308   fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2309 #endif
2310 }
2311
2312
2313 gstring *
2314 malware_show_supported(gstring * g)
2315 {
2316 g = string_cat(g, US"Malware:");
2317 for (struct scan * sc = m_scans; sc->scancode != (scanner_t)-1; sc++)
2318   g = string_fmt_append(g, " %s", sc->name);
2319 return string_cat(g, US"\n");
2320 }
2321
2322
2323 # endif /*!MACRO_PREDEF*/
2324 #endif /*WITH_CONTENT_SCAN*/
2325 /*
2326  * vi: aw ai sw=2
2327  */