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