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