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