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