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