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