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