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