tidying
[exim.git] / src / src / malware.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-2014 */
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 = ETIME;
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, *response_end;
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       response_end = p;
1618
1619       /* colon in returned output? */
1620       if((p = Ustrchr(av_buffer,':')) == NULL)
1621         return m_errlog_defer(scanent, string_sprintf(
1622                   "ClamAV returned malformed result (missing colon): %s",
1623                   av_buffer));
1624
1625       /* strip filename */
1626       while (*p && isspace(*++p)) /**/;
1627       vname = p;
1628
1629       /* It would be bad to encounter a virus with "FOUND" in part of the name,
1630       but we should at least be resistant to it. */
1631       p = Ustrrchr(vname, ' ');
1632       result_tag = p ? p+1 : vname;
1633
1634       if (Ustrcmp(result_tag, "FOUND") == 0)
1635         {
1636         /* p should still be the whitespace before the result_tag */
1637         while (isspace(*p)) --p;
1638         *++p = '\0';
1639         /* Strip off the extended information too, which will be in parens
1640         after the virus name, with no intervening whitespace. */
1641         if (*--p == ')')
1642           {
1643           /* "(hash:size)", so previous '(' will do; if not found, we have
1644           a curious virus name, but not an error. */
1645           p = Ustrrchr(vname, '(');
1646           if (p)
1647             *p = '\0';
1648           }
1649         malware_name = string_copy(vname);
1650         DEBUG(D_acl) debug_printf("Malware found, name \"%s\"\n", malware_name);
1651
1652         }
1653       else if (Ustrcmp(result_tag, "ERROR") == 0)
1654         return m_errlog_defer(scanent,
1655           string_sprintf("ClamAV returned: %s", av_buffer));
1656
1657       else if (Ustrcmp(result_tag, "OK") == 0)
1658         {
1659         /* Everything should be OK */
1660         malware_name = NULL;
1661         DEBUG(D_acl) debug_printf("Malware not found\n");
1662
1663         }
1664       else
1665         return m_errlog_defer(scanent,
1666           string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1667
1668       break;
1669       } /* clamd */
1670
1671     case M_SOCK: /* "sock" scanner type ------------------------------------- */
1672     /* This code was derived by Martin Poole from the clamd code contributed
1673        by David Saez and the cmdline code
1674     */
1675       {
1676       int bread;
1677       uschar * commandline;
1678       uschar av_buffer[1024];
1679       uschar * linebuffer;
1680       uschar * sockline_scanner;
1681       uschar sockline_scanner_default[] = "%s\n";
1682       const pcre *sockline_trig_re;
1683       const pcre *sockline_name_re;
1684
1685       /* find scanner command line */
1686       if ((sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1687                                           NULL, 0)))
1688       { /* check for no expansions apart from one %s */
1689         uschar * s = Ustrchr(sockline_scanner, '%');
1690         if (s++)
1691           if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1692             return m_errlog_defer_3(scanent,
1693                                   US"unsafe sock scanner call spec", sock);
1694       }
1695       else
1696         sockline_scanner = sockline_scanner_default;
1697
1698       /* find scanner output trigger */
1699       sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1700                                 "missing trigger specification", &errstr);
1701       if (!sockline_trig_re)
1702         return m_errlog_defer_3(scanent, errstr, sock);
1703
1704       /* find virus name regex */
1705       sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1706                           "missing virus name regex specification", &errstr);
1707       if (!sockline_name_re)
1708         return m_errlog_defer_3(scanent, errstr, sock);
1709
1710       /* prepare scanner call - security depends on expansions check above */
1711       commandline = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
1712       commandline = string_sprintf( CS sockline_scanner, CS commandline);
1713
1714
1715       /* Pass the command string to the socket */
1716       if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1717         return m_errlog_defer(scanent, errstr);
1718
1719       /* Read the result */
1720       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1721
1722       if (bread <= 0)
1723         return m_errlog_defer_3(scanent,
1724           string_sprintf("unable to read from socket (%s)", strerror(errno)),
1725           sock);
1726
1727       if (bread == sizeof(av_buffer))
1728         return m_errlog_defer_3(scanent, US"buffer too small", sock);
1729       av_buffer[bread] = '\0';
1730       linebuffer = string_copy(av_buffer);
1731
1732       /* try trigger match */
1733       if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1734         {
1735         if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1736           malware_name = US "unknown";
1737         }
1738       else /* no virus found */
1739         malware_name = NULL;
1740       break;
1741       }
1742
1743     case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1744       {
1745       char *mksd_options_end;
1746       int mksd_maxproc = 1;  /* default, if no option supplied */
1747       int retval;
1748
1749       if (scanner_options)
1750         {
1751         mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1752         if (  *scanner_options == '\0'
1753            || *mksd_options_end != '\0'
1754            || mksd_maxproc < 1
1755            || mksd_maxproc > 32
1756            )
1757           return m_errlog_defer(scanent,
1758             string_sprintf("invalid option '%s'", scanner_options));
1759         }
1760
1761       if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1762         return m_errlog_defer(scanent, errstr);
1763
1764       malware_name = NULL;
1765
1766       DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan\n", scanner_name);
1767
1768       if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1769         {
1770         close (sock);
1771         return retval;
1772         }
1773       break;
1774       }
1775
1776     case M_AVAST: /* "avast" scanner type ----------------------------------- */
1777       {
1778       int ovector[1*3];
1779       uschar buf[1024];
1780       uschar * scanrequest;
1781       enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1782       int nread;
1783
1784       /* According to Martin Tuma @avast the protocol uses "escaped
1785       whitespace", that is, every embedded whitespace is backslash
1786       escaped, as well as backslash is protected by backslash.
1787       The returned lines contain the name of the scanned file, a tab
1788       and the [ ] marker.
1789       [+] - not infected
1790       [L] - infected
1791       [E] - some error occured
1792       Such marker follows the first non-escaped TAB.  */
1793       if (  (  !ava_re_clean
1794             && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1795          || (  !ava_re_virus
1796             && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1797          )
1798         return malware_errlog_defer(errstr);
1799
1800       /* wait for result */
1801       for (avast_stage = AVA_HELO;
1802            (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1803           )
1804         {
1805         int slen = Ustrlen(buf);
1806         if (slen >= 1) 
1807           {
1808           DEBUG(D_acl) debug_printf("got from avast: %s\n", buf);
1809           switch (avast_stage)
1810             {
1811             case AVA_HELO:
1812               if (Ustrncmp(buf, "220", 3) != 0)
1813                 goto endloop;                   /* require a 220 */
1814               goto sendreq;
1815
1816             case AVA_OPT:
1817               if (Ustrncmp(buf, "210", 3) == 0)
1818                 break;                          /* ignore 210 responses */
1819               if (Ustrncmp(buf, "200", 3) != 0)
1820                 goto endloop;                   /* require a 200 */
1821
1822             sendreq:
1823               {
1824               int len;
1825               /* Check for another option to send. Newline-terminate it. */
1826               if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1827                                 NULL, 0)))
1828                 {
1829                 scanrequest = string_sprintf("%s\n", scanrequest);
1830                 avast_stage = AVA_OPT;          /* just sent option */
1831                 }
1832               else
1833                 {
1834                 scanrequest = string_sprintf("SCAN %s/scan/%s\n",
1835                     spool_directory, message_id);
1836                 avast_stage = AVA_RSP;          /* just sent command */
1837                 }
1838
1839               /* send config-cmd or scan-request to socket */
1840               len = Ustrlen(scanrequest);
1841               if (send(sock, scanrequest, len, 0) < 0)
1842                 {
1843                 scanrequest[len-1] = '\0';
1844                 return m_errlog_defer_3(scanent, string_sprintf(
1845                       "unable to send request '%s' to socket (%s): %s",
1846                       scanrequest, scanner_options, strerror(errno)), sock);
1847                 }
1848               break;
1849               }
1850
1851             case AVA_RSP:
1852               if (Ustrncmp(buf, "210", 3) == 0)
1853                 break;  /* ignore the "210 SCAN DATA" message */
1854
1855               if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
1856                     0, 0, ovector, nelements(ovector)) > 0)
1857                 break;
1858
1859               if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
1860                 { /* remove backslash in front of [whitespace|backslash] */
1861                 uschar * p, * p0;
1862                 for (p = malware_name; *p; ++p) 
1863                   if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
1864                     for (p0 = p; *p0; ++p0) *p0 = p0[1];
1865                 
1866                 avast_stage = AVA_DONE;
1867                 goto endloop;
1868                 }
1869
1870               if (Ustrncmp(buf, "200 SCAN OK", 11) == 0) 
1871                 { /* we're done finally */
1872                 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1873                   return m_errlog_defer_3(scanent, string_sprintf(
1874                               "unable to send quit request to socket (%s): %s",
1875                               scanner_options, strerror(errno)),
1876                               sock);
1877                 malware_name = NULL;
1878                 avast_stage = AVA_DONE;
1879                 goto endloop;
1880                 }
1881
1882               /* here for any unexpected response from the scanner */
1883               goto endloop;
1884             }
1885           }
1886         }
1887       endloop:
1888
1889       switch(avast_stage)
1890         {
1891         case AVA_HELO:  
1892         case AVA_OPT:
1893         case AVA_RSP:   return m_errlog_defer_3(scanent,
1894                             nread >= 0
1895                             ? string_sprintf(
1896                                 "invalid response from scanner: '%s'", buf)
1897                             : nread == -1
1898                             ? US"EOF from scanner"
1899                             : US"timeout from scanner",
1900                           sock);
1901         default:        break;
1902         }
1903       }
1904       break;
1905   }     /* scanner type switch */
1906
1907   if (sock >= 0)
1908     (void) close (sock);
1909   malware_ok = TRUE;                    /* set "been here, done that" marker */
1910   }
1911
1912 /* match virus name against pattern (caseless ------->----------v) */
1913 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
1914   {
1915   DEBUG(D_acl) debug_printf(
1916       "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
1917   return OK;
1918   }
1919 else
1920   return FAIL;
1921 }
1922
1923
1924 /*************************************************
1925 *          Scan an email for malware             *
1926 *************************************************/
1927
1928 /* This is the normal interface for scanning an email, which doesn't need a
1929 filename; it's a wrapper around the malware_file function.
1930
1931 Arguments:
1932   malware_re  match condition for "malware="
1933   timeout     if nonzero, timeout in seconds
1934
1935 Returns:      Exim message processing code (OK, FAIL, DEFER, ...)
1936               where true means malware was found (condition applies)
1937 */
1938 int
1939 malware(const uschar * malware_re, int timeout)
1940 {
1941   uschar * scan_filename;
1942   int ret;
1943
1944   scan_filename = string_sprintf("%s/scan/%s/%s.eml",
1945                     spool_directory, message_id, message_id);
1946   ret = malware_internal(malware_re, scan_filename, timeout, FALSE);
1947   if (ret == DEFER) av_failed = TRUE;
1948
1949   return ret;
1950 }
1951
1952
1953 /*************************************************
1954 *          Scan a file for malware               *
1955 *************************************************/
1956
1957 /* This is a test wrapper for scanning an email, which is not used in
1958 normal processing.  Scan any file, using the Exim scanning interface.
1959 This function tampers with various global variables so is unsafe to use
1960 in any other context.
1961
1962 Arguments:
1963   eml_filename  a file holding the message to be scanned
1964
1965 Returns:        Exim message processing code (OK, FAIL, DEFER, ...)
1966                 where true means malware was found (condition applies)
1967 */
1968 int
1969 malware_in_file(uschar *eml_filename)
1970 {
1971   uschar message_id_buf[64];
1972   int ret;
1973
1974   /* spool_mbox() assumes various parameters exist, when creating
1975   the relevant directory and the email within */
1976   (void) string_format(message_id_buf, sizeof(message_id_buf),
1977       "dummy-%d", vaguely_random_number(INT_MAX));
1978   message_id = message_id_buf;
1979   sender_address = US"malware-sender@example.net";
1980   return_path = US"";
1981   recipients_list = NULL;
1982   receive_add_recipient(US"malware-victim@example.net", -1);
1983   enable_dollar_recipients = TRUE;
1984
1985   ret = malware_internal(US"*", eml_filename, 0,  TRUE);
1986
1987   Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
1988   spool_mbox_ok = 1;
1989   /* don't set no_mbox_unspool; at present, there's no way for it to become
1990   set, but if that changes, then it should apply to these tests too */
1991   unspool_mbox();
1992
1993   /* silence static analysis tools */
1994   message_id = NULL;
1995
1996   return ret;
1997 }
1998
1999
2000 void
2001 malware_init(void)
2002 {
2003 if (!malware_default_re)
2004   malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2005 if (!drweb_re)
2006   drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2007 if (!fsec_re)
2008   fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2009 if (!kav_re_sus)
2010   kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2011 if (!kav_re_inf)
2012   kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2013 if (!ava_re_clean)
2014   ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2015 if (!ava_re_virus)
2016   ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2017 }
2018
2019 #endif /*WITH_CONTENT_SCAN*/
2020 /*
2021  * vi: aw ai sw=2
2022  */