214 spelling fixes
[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 ambiguous. 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.  Using size from stream to read amount of data
1007             from same stream is safe enough. */
1008             /* coverity[tainted_data] */
1009             while (kav_reportlen > 0)
1010               {
1011               if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1012                 break;
1013               kav_reportlen -= bread+1;
1014
1015               /* try matcher on the line, grab substring */
1016               if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1017                 break;
1018               }
1019             }
1020           }
1021         }
1022       else /* no virus found */
1023         malware_name = NULL;
1024
1025       break;
1026       }
1027
1028     case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1029       {
1030       const uschar *cmdline_scanner = scanner_options;
1031       const pcre *cmdline_trigger_re;
1032       const pcre *cmdline_regex_re;
1033       uschar * file_name;
1034       uschar * commandline;
1035       void (*eximsigchld)(int);
1036       void (*eximsigpipe)(int);
1037       FILE *scanner_out = NULL;
1038       int scanner_fd;
1039       FILE *scanner_record = NULL;
1040       uschar linebuffer[32767];
1041       int rcnt;
1042       int trigger = 0;
1043       uschar *p;
1044
1045       if (!cmdline_scanner)
1046         return m_errlog_defer(scanent, NULL, errstr);
1047
1048       /* find scanner output trigger */
1049       cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1050                                 "missing trigger specification", &errstr);
1051       if (!cmdline_trigger_re)
1052         return m_errlog_defer(scanent, NULL, errstr);
1053
1054       /* find scanner name regex */
1055       cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1056                           "missing virus name regex specification", &errstr);
1057       if (!cmdline_regex_re)
1058         return m_errlog_defer(scanent, NULL, errstr);
1059
1060       /* prepare scanner call; despite the naming, file_name holds a directory
1061       name which is documented as the value given to %s. */
1062
1063       file_name = string_copy(eml_filename);
1064       p = Ustrrchr(file_name, '/');
1065       if (p)
1066         *p = '\0';
1067       commandline = string_sprintf(CS cmdline_scanner, file_name);
1068
1069       /* redirect STDERR too */
1070       commandline = string_sprintf("%s 2>&1", commandline);
1071
1072       DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
1073               scanner_name, commandline);
1074
1075       /* store exims signal handlers */
1076       eximsigchld = signal(SIGCHLD,SIG_DFL);
1077       eximsigpipe = signal(SIGPIPE,SIG_DFL);
1078
1079       if (!(scanner_out = popen(CS commandline,"r")))
1080         {
1081         int err = errno;
1082         signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1083         return m_errlog_defer(scanent, NULL,
1084           string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1085         }
1086       scanner_fd = fileno(scanner_out);
1087
1088       file_name = string_sprintf("%s/scan/%s/%s_scanner_output",
1089                                 spool_directory, message_id, message_id);
1090
1091       if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1092         {
1093         int err = errno;
1094         (void) pclose(scanner_out);
1095         signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1096         return m_errlog_defer(scanent, NULL, string_sprintf(
1097             "opening scanner output file (%s) failed: %s.",
1098             file_name, strerror(err)));
1099         }
1100
1101       /* look for trigger while recording output */
1102       while ((rcnt = recv_line(scanner_fd, linebuffer,
1103                       sizeof(linebuffer), tmo)))
1104         {
1105         if (rcnt < 0)
1106           {
1107           int err = errno;
1108           if (rcnt == -1)
1109             break;
1110           (void) pclose(scanner_out);
1111           signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1112           return m_errlog_defer(scanent, NULL, string_sprintf(
1113               "unable to read from scanner (%s): %s",
1114               commandline, strerror(err)));
1115           }
1116
1117         if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1118           {
1119           /* short write */
1120           (void) pclose(scanner_out);
1121           signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1122           return m_errlog_defer(scanent, NULL, string_sprintf(
1123             "short write on scanner output file (%s).", file_name));
1124           }
1125         putc('\n', scanner_record);
1126         /* try trigger match */
1127         if (  !trigger
1128            && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1129            )
1130           trigger = 1;
1131         }
1132
1133       (void)fclose(scanner_record);
1134       sep = pclose(scanner_out);
1135       signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1136       if (sep != 0)
1137           return m_errlog_defer(scanent, NULL, 
1138               sep == -1
1139               ? string_sprintf("running scanner failed: %s", strerror(sep))
1140               : string_sprintf("scanner returned error code: %d", sep));
1141
1142       if (trigger)
1143         {
1144         uschar * s;
1145         /* setup default virus name */
1146         malware_name = US"unknown";
1147
1148         /* re-open the scanner output file, look for name match */
1149         scanner_record = fopen(CS file_name, "rb");
1150         while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1151           {
1152           /* try match */
1153           if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1154             malware_name = s;
1155           }
1156         (void)fclose(scanner_record);
1157         }
1158       else /* no virus found */
1159         malware_name = NULL;
1160       break;
1161       } /* cmdline */
1162
1163     case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1164       {
1165       int bread = 0;
1166       uschar *p;
1167       uschar * file_name;
1168       uschar av_buffer[1024];
1169
1170       /* pass the scan directory to sophie */
1171       file_name = string_copy(eml_filename);
1172       if ((p = Ustrrchr(file_name, '/')))
1173         *p = '\0';
1174
1175       DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
1176           scanner_name, scanner_options);
1177
1178       if (  write(sock, file_name, Ustrlen(file_name)) < 0
1179          || write(sock, "\n", 1) != 1
1180          )
1181         return m_errlog_defer_3(scanent, CUS callout_address,
1182           string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1183           sock);
1184
1185       /* wait for result */
1186       memset(av_buffer, 0, sizeof(av_buffer));
1187       if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1188         return m_errlog_defer_3(scanent, CUS callout_address,
1189           string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1190           sock);
1191
1192       /* infected ? */
1193       if (av_buffer[0] == '1') {
1194         uschar * s = Ustrchr(av_buffer, '\n');
1195         if (s)
1196           *s = '\0';
1197         malware_name = string_copy(&av_buffer[2]);
1198       }
1199       else if (!strncmp(CS av_buffer, "-1", 2))
1200         return m_errlog_defer_3(scanent, CUS callout_address,
1201                 US"scanner reported error", sock);
1202       else /* all ok, no virus */
1203         malware_name = NULL;
1204
1205       break;
1206       }
1207
1208     case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1209       {
1210 /* This code was originally contributed by David Saez */
1211 /* There are three scanning methods available to us:
1212 *  (1) Use the SCAN command, pointing to a file in the filesystem
1213 *  (2) Use the STREAM command, send the data on a separate port
1214 *  (3) Use the zINSTREAM command, send the data inline
1215 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1216 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1217 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1218 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless
1219 * WITH_OLD_CLAMAV_STREAM is defined.
1220 * See Exim bug 926 for details.  */
1221
1222       uschar *p, *vname, *result_tag;
1223       int bread=0;
1224       uschar * file_name;
1225       uschar av_buffer[1024];
1226       uschar *hostname = US"";
1227       host_item connhost;
1228       uschar *clamav_fbuf;
1229       int clam_fd, result;
1230       off_t fsize;
1231       unsigned int fsize_uint;
1232       BOOL use_scan_command = FALSE;
1233       clamd_address * cv[MAX_CLAMD_SERVERS];
1234       int num_servers = 0;
1235 #ifdef WITH_OLD_CLAMAV_STREAM
1236       unsigned int port;
1237       uschar av_buffer2[1024];
1238       int sockData;
1239 #else
1240       uint32_t send_size, send_final_zeroblock;
1241 #endif
1242
1243       /*XXX if unixdomain socket, only one server supported. Needs fixing;
1244       there's no reason we should not mix local and remote servers */
1245
1246       if (*scanner_options == '/')
1247         {
1248         clamd_address * cd;
1249         const uschar * sublist;
1250         int subsep = ' ';
1251
1252         /* Local file; so we def want to use_scan_command and don't want to try
1253          * passing IP/port combinations */
1254         use_scan_command = TRUE;
1255         cd = (clamd_address *) store_get(sizeof(clamd_address));
1256
1257         /* extract socket-path part */
1258         sublist = scanner_options;
1259         cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1260
1261         /* parse options */
1262         if (clamd_option(cd, sublist, &subsep) != OK)
1263           return m_errlog_defer(scanent, NULL,
1264             string_sprintf("bad option '%s'", scanner_options));
1265         cv[0] = cd;
1266         }
1267       else
1268         {
1269         /* Go through the rest of the list of host/port and construct an array
1270          * of servers to try. The first one is the bit we just passed from
1271          * scanner_options so process that first and then scan the remainder of
1272          * the address buffer */
1273         do
1274           {
1275           clamd_address * cd;
1276           const uschar * sublist;
1277           int subsep = ' ';
1278           uschar * s;
1279
1280           /* The 'local' option means use the SCAN command over the network
1281            * socket (ie common file storage in use) */
1282           /*XXX we could accept this also as a local option? */
1283           if (strcmpic(scanner_options, US"local") == 0)
1284             {
1285             use_scan_command = TRUE;
1286             continue;
1287             }
1288
1289           cd = (clamd_address *) store_get(sizeof(clamd_address));
1290
1291           /* extract host and port part */
1292           sublist = scanner_options;
1293           if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1294             {
1295             (void) m_errlog_defer(scanent, NULL, 
1296                       string_sprintf("missing address: '%s'", scanner_options));
1297             continue;
1298             }
1299           if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1300             {
1301             (void) m_errlog_defer(scanent, NULL, 
1302                       string_sprintf("missing port: '%s'", scanner_options));
1303             continue;
1304             }
1305           cd->tcp_port = atoi(CS s);
1306
1307           /* parse options */
1308           /*XXX should these options be common over scanner types? */
1309           if (clamd_option(cd, sublist, &subsep) != OK)
1310             return m_errlog_defer(scanent, NULL,
1311               string_sprintf("bad option '%s'", scanner_options));
1312
1313           cv[num_servers++] = cd;
1314           if (num_servers >= MAX_CLAMD_SERVERS)
1315             {
1316             (void) m_errlog_defer(scanent, NULL,
1317                   US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1318                   "specified; only using the first " MAX_CLAMD_SERVERS_S );
1319             break;
1320             }
1321           } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1322                                         NULL, 0)));
1323
1324         /* check if we have at least one server */
1325         if (!num_servers)
1326           return m_errlog_defer(scanent, NULL,
1327             US"no useable server addresses in malware configuration option.");
1328         }
1329
1330       /* See the discussion of response formats below to see why we really
1331       don't like colons in filenames when passing filenames to ClamAV. */
1332       if (use_scan_command && Ustrchr(eml_filename, ':'))
1333         return m_errlog_defer(scanent, NULL,
1334           string_sprintf("local/SCAN mode incompatible with" \
1335             " : in path to email filename [%s]", eml_filename));
1336
1337       /* We have some network servers specified */
1338       if (num_servers)
1339         {
1340         /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1341          * only supports AF_INET, but we should probably be looking to the
1342          * future and rewriting this to be protocol-independent anyway. */
1343
1344         while (num_servers > 0)
1345           {
1346           int i = random_number( num_servers );
1347           clamd_address * cd = cv[i];
1348
1349           DEBUG(D_acl) debug_printf("trying server name %s, port %u\n",
1350                          cd->hostspec, cd->tcp_port);
1351
1352           /* Lookup the host. This is to ensure that we connect to the same IP
1353            * on both connections (as one host could resolve to multiple ips) */
1354           for (;;)
1355             {
1356             sock= m_tcpsocket(cd->hostspec, cd->tcp_port, &connhost, &errstr);
1357             if (sock >= 0)
1358               {
1359               /* Connection successfully established with a server */
1360               hostname = cd->hostspec;
1361               break;
1362               }
1363             if (cd->retry <= 0) break;
1364             while (cd->retry > 0) cd->retry = sleep(cd->retry);
1365             }
1366           if (sock >= 0)
1367             break;
1368
1369           (void) m_errlog_defer(scanent, CUS callout_address, errstr);
1370
1371           /* Remove the server from the list. XXX We should free the memory */
1372           num_servers--;
1373           for (; i < num_servers; i++)
1374             cv[i] = cv[i+1];
1375           }
1376
1377         if (num_servers == 0)
1378           return m_errlog_defer(scanent, NULL, US"all servers failed");
1379         }
1380       else
1381         for (;;)
1382           {
1383           if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1384             {
1385             hostname = cv[0]->hostspec;
1386             break;
1387             }
1388           if (cv[0]->retry <= 0)
1389             return m_errlog_defer(scanent, CUS callout_address, errstr);
1390           while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1391           }
1392
1393       /* have socket in variable "sock"; command to use is semi-independent of
1394        * the socket protocol.  We use SCAN if is local (either Unix/local
1395        * domain socket, or explicitly told local) else we stream the data.
1396        * How we stream the data depends upon how we were built.  */
1397
1398       if (!use_scan_command)
1399         {
1400 #ifdef WITH_OLD_CLAMAV_STREAM
1401         /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1402          * that port on a second connection; then in the scan-method-neutral
1403          * part, read the response back on the original connection. */
1404
1405         DEBUG(D_acl) debug_printf(
1406             "Malware scan: issuing %s old-style remote scan (PORT)\n",
1407             scanner_name);
1408
1409         /* Pass the string to ClamAV (7 = "STREAM\n") */
1410         if (m_sock_send(sock, US"STREAM\n", 7, &errstr) < 0)
1411           return m_errlog_defer(scanent, CUS callout_address, errstr);
1412
1413         memset(av_buffer2, 0, sizeof(av_buffer2));
1414         bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
1415
1416         if (bread < 0)
1417           return m_errlog_defer_3(scanent, CUS callout_address,
1418             string_sprintf("unable to read PORT from socket (%s)",
1419                 strerror(errno)),
1420             sock);
1421
1422         if (bread == sizeof(av_buffer2))
1423           return m_errlog_defer_3(scanent, CUS callout_address,
1424                   "buffer too small", sock);
1425
1426         if (!(*av_buffer2))
1427           return m_errlog_defer_3(scanent, CUS callout_address,
1428                   "ClamAV returned null", sock);
1429
1430         av_buffer2[bread] = '\0';
1431         if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 )
1432           return m_errlog_defer_3(scanent, CUS callout_address,
1433             string_sprintf("Expected port information from clamd, got '%s'",
1434               av_buffer2),
1435             sock);
1436
1437         sockData = m_tcpsocket(connhost.address, port, NULL, &errstr);
1438         if (sockData < 0)
1439           return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock);
1440
1441 # define CLOSE_SOCKDATA (void)close(sockData)
1442 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1443         /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1444         chunks, <n> a 4-byte number (network order), terminated by a zero-length
1445         chunk. */
1446
1447         DEBUG(D_acl) debug_printf(
1448             "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1449             scanner_name);
1450
1451         /* Pass the string to ClamAV (10 = "zINSTREAM\0") */
1452         if (send(sock, "zINSTREAM", 10, 0) < 0)
1453           return m_errlog_defer_3(scanent, CUS hostname,
1454             string_sprintf("unable to send zINSTREAM to socket (%s)",
1455               strerror(errno)),
1456             sock);
1457
1458 # define CLOSE_SOCKDATA /**/
1459 #endif
1460
1461         /* calc file size */
1462         if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1463           {
1464           int err = errno;
1465           CLOSE_SOCKDATA;
1466           return m_errlog_defer_3(scanent, NULL,
1467             string_sprintf("can't open spool file %s: %s",
1468               eml_filename, strerror(err)),
1469             sock);
1470           }
1471         if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1472           {
1473           int err = errno;
1474           CLOSE_SOCKDATA; (void)close(clam_fd);
1475           return m_errlog_defer_3(scanent, NULL,
1476             string_sprintf("can't seek spool file %s: %s",
1477               eml_filename, strerror(err)),
1478             sock);
1479           }
1480         fsize_uint = (unsigned int) fsize;
1481         if ((off_t)fsize_uint != fsize)
1482           {
1483           CLOSE_SOCKDATA; (void)close(clam_fd);
1484           return m_errlog_defer_3(scanent, NULL,
1485             string_sprintf("seeking spool file %s, size overflow",
1486               eml_filename),
1487             sock);
1488           }
1489         lseek(clam_fd, 0, SEEK_SET);
1490
1491         if (!(clamav_fbuf = US malloc(fsize_uint)))
1492           {
1493           CLOSE_SOCKDATA; (void)close(clam_fd);
1494           return m_errlog_defer_3(scanent, NULL,
1495             string_sprintf("unable to allocate memory %u for file (%s)",
1496               fsize_uint, eml_filename),
1497             sock);
1498           }
1499
1500         if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1501           {
1502           int err = errno;
1503           free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd);
1504           return m_errlog_defer_3(scanent, NULL,
1505             string_sprintf("can't read spool file %s: %s",
1506               eml_filename, strerror(err)),
1507             sock);
1508           }
1509         (void)close(clam_fd);
1510
1511         /* send file body to socket */
1512 #ifdef WITH_OLD_CLAMAV_STREAM
1513         if (send(sockData, clamav_fbuf, fsize_uint, 0) < 0)
1514           {
1515           free(clamav_fbuf); CLOSE_SOCKDATA;
1516           return m_errlog_defer_3(scanent, NULL,
1517             string_sprintf("unable to send file body to socket (%s:%u)",
1518               hostname, port),
1519             sock);
1520           }
1521 #else
1522         send_size = htonl(fsize_uint);
1523         send_final_zeroblock = 0;
1524         if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1525             (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1526             (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1527           {
1528           free(clamav_fbuf);
1529           return m_errlog_defer_3(scanent, NULL,
1530             string_sprintf("unable to send file body to socket (%s)", hostname),
1531             sock);
1532           }
1533 #endif
1534
1535         free(clamav_fbuf);
1536
1537         CLOSE_SOCKDATA;
1538 #undef CLOSE_SOCKDATA
1539         }
1540       else
1541         { /* use scan command */
1542         /* Send a SCAN command pointing to a filename; then in the then in the
1543          * scan-method-neutral part, read the response back */
1544
1545 /* ================================================================= */
1546
1547         /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1548         which dates to when ClamAV needed us to break apart the email into the
1549         MIME parts (eg, with the now deprecated demime condition coming first).
1550         Some time back, ClamAV gained the ability to deconstruct the emails, so
1551         doing this would actually have resulted in the mail attachments being
1552         scanned twice, in the broken out files and from the original .eml.
1553         Since ClamAV now handles emails (and has for quite some time) we can
1554         just use the email file itself. */
1555         /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
1556         file_name = string_sprintf("SCAN %s\n", eml_filename);
1557
1558         DEBUG(D_acl) debug_printf(
1559             "Malware scan: issuing %s local-path scan [%s]\n",
1560             scanner_name, scanner_options);
1561
1562         if (send(sock, file_name, Ustrlen(file_name), 0) < 0)
1563           return m_errlog_defer_3(scanent, CUS callout_address,
1564             string_sprintf("unable to write to socket (%s)", strerror(errno)),
1565             sock);
1566
1567         /* Do not shut down the socket for writing; a user report noted that
1568          * clamd 0.70 does not react well to this. */
1569         }
1570       /* Commands have been sent, no matter which scan method or connection
1571        * type we're using; now just read the result, independent of method. */
1572
1573       /* Read the result */
1574       memset(av_buffer, 0, sizeof(av_buffer));
1575       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1576       (void)close(sock);
1577       sock = -1;
1578
1579       if (bread <= 0)
1580         return m_errlog_defer(scanent, CUS callout_address,
1581           string_sprintf("unable to read from socket (%s)",
1582           errno == 0 ? "EOF" : strerror(errno)));
1583
1584       if (bread == sizeof(av_buffer))
1585         return m_errlog_defer(scanent, CUS callout_address,
1586                 US"buffer too small");
1587       /* We're now assured of a NULL at the end of av_buffer */
1588
1589       /* Check the result. ClamAV returns one of two result formats.
1590       In the basic mode, the response is of the form:
1591         infected: -> "<filename>: <virusname> FOUND"
1592         not-infected: -> "<filename>: OK"
1593         error: -> "<filename>: <errcode> ERROR
1594       If the ExtendedDetectionInfo option has been turned on, then we get:
1595         "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1596       for the infected case.  Compare:
1597 /tmp/eicar.com: Eicar-Test-Signature FOUND
1598 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1599
1600       In the streaming case, clamd uses the filename "stream" which you should
1601       be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }.  (The
1602       client app will replace "stream" with the original filename before returning
1603       results to stdout, but the trace shows the data).
1604
1605       We will assume that the pathname passed to clamd from Exim does not contain
1606       a colon.  We will have whined loudly above if the eml_filename does (and we're
1607       passing a filename to clamd). */
1608
1609       if (!(*av_buffer))
1610         return m_errlog_defer(scanent, CUS callout_address,
1611                 US"ClamAV returned null");
1612
1613       /* strip newline at the end (won't be present for zINSTREAM)
1614       (also any trailing whitespace, which shouldn't exist, but we depend upon
1615       this below, so double-check) */
1616       p = av_buffer + Ustrlen(av_buffer) - 1;
1617       if (*p == '\n') *p = '\0';
1618
1619       DEBUG(D_acl) debug_printf("Malware response: %s\n", av_buffer);
1620
1621       while (isspace(*--p) && (p > av_buffer))
1622         *p = '\0';
1623       if (*p) ++p;
1624
1625       /* colon in returned output? */
1626       if(!(p = Ustrchr(av_buffer,':')))
1627         return m_errlog_defer(scanent, CUS callout_address, string_sprintf(
1628                   "ClamAV returned malformed result (missing colon): %s",
1629                   av_buffer));
1630
1631       /* strip filename */
1632       while (*p && isspace(*++p)) /**/;
1633       vname = p;
1634
1635       /* It would be bad to encounter a virus with "FOUND" in part of the name,
1636       but we should at least be resistant to it. */
1637       p = Ustrrchr(vname, ' ');
1638       result_tag = p ? p+1 : vname;
1639
1640       if (Ustrcmp(result_tag, "FOUND") == 0)
1641         {
1642         /* p should still be the whitespace before the result_tag */
1643         while (isspace(*p)) --p;
1644         *++p = '\0';
1645         /* Strip off the extended information too, which will be in parens
1646         after the virus name, with no intervening whitespace. */
1647         if (*--p == ')')
1648           {
1649           /* "(hash:size)", so previous '(' will do; if not found, we have
1650           a curious virus name, but not an error. */
1651           p = Ustrrchr(vname, '(');
1652           if (p)
1653             *p = '\0';
1654           }
1655         malware_name = string_copy(vname);
1656         DEBUG(D_acl) debug_printf("Malware found, name \"%s\"\n", malware_name);
1657
1658         }
1659       else if (Ustrcmp(result_tag, "ERROR") == 0)
1660         return m_errlog_defer(scanent, CUS callout_address,
1661           string_sprintf("ClamAV returned: %s", av_buffer));
1662
1663       else if (Ustrcmp(result_tag, "OK") == 0)
1664         {
1665         /* Everything should be OK */
1666         malware_name = NULL;
1667         DEBUG(D_acl) debug_printf("Malware not found\n");
1668
1669         }
1670       else
1671         return m_errlog_defer(scanent, CUS callout_address,
1672           string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1673
1674       break;
1675       } /* clamd */
1676
1677     case M_SOCK: /* "sock" scanner type ------------------------------------- */
1678     /* This code was derived by Martin Poole from the clamd code contributed
1679        by David Saez and the cmdline code
1680     */
1681       {
1682       int bread;
1683       uschar * commandline;
1684       uschar av_buffer[1024];
1685       uschar * linebuffer;
1686       uschar * sockline_scanner;
1687       uschar sockline_scanner_default[] = "%s\n";
1688       const pcre *sockline_trig_re;
1689       const pcre *sockline_name_re;
1690
1691       /* find scanner command line */
1692       if ((sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1693                                           NULL, 0)))
1694       { /* check for no expansions apart from one %s */
1695         uschar * s = Ustrchr(sockline_scanner, '%');
1696         if (s++)
1697           if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1698             return m_errlog_defer_3(scanent, NULL,
1699                                   US"unsafe sock scanner call spec", sock);
1700       }
1701       else
1702         sockline_scanner = sockline_scanner_default;
1703
1704       /* find scanner output trigger */
1705       sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1706                                 "missing trigger specification", &errstr);
1707       if (!sockline_trig_re)
1708         return m_errlog_defer_3(scanent, NULL, errstr, sock);
1709
1710       /* find virus name regex */
1711       sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1712                           "missing virus name regex specification", &errstr);
1713       if (!sockline_name_re)
1714         return m_errlog_defer_3(scanent, NULL, errstr, sock);
1715
1716       /* prepare scanner call - security depends on expansions check above */
1717       commandline = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
1718       commandline = string_sprintf( CS sockline_scanner, CS commandline);
1719
1720
1721       /* Pass the command string to the socket */
1722       if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1723         return m_errlog_defer(scanent, CUS callout_address, errstr);
1724
1725       /* Read the result */
1726       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1727
1728       if (bread <= 0)
1729         return m_errlog_defer_3(scanent, CUS callout_address,
1730           string_sprintf("unable to read from socket (%s)", strerror(errno)),
1731           sock);
1732
1733       if (bread == sizeof(av_buffer))
1734         return m_errlog_defer_3(scanent, CUS callout_address,
1735                 US"buffer too small", sock);
1736       av_buffer[bread] = '\0';
1737       linebuffer = string_copy(av_buffer);
1738
1739       /* try trigger match */
1740       if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1741         {
1742         if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1743           malware_name = US "unknown";
1744         }
1745       else /* no virus found */
1746         malware_name = NULL;
1747       break;
1748       }
1749
1750     case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1751       {
1752       char *mksd_options_end;
1753       int mksd_maxproc = 1;  /* default, if no option supplied */
1754       int retval;
1755
1756       if (scanner_options)
1757         {
1758         mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1759         if (  *scanner_options == '\0'
1760            || *mksd_options_end != '\0'
1761            || mksd_maxproc < 1
1762            || mksd_maxproc > 32
1763            )
1764           return m_errlog_defer(scanent, CUS callout_address,
1765             string_sprintf("invalid option '%s'", scanner_options));
1766         }
1767
1768       if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1769         return m_errlog_defer(scanent, CUS callout_address, errstr);
1770
1771       malware_name = NULL;
1772
1773       DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan\n", scanner_name);
1774
1775       if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1776         {
1777         close (sock);
1778         return retval;
1779         }
1780       break;
1781       }
1782
1783     case M_AVAST: /* "avast" scanner type ----------------------------------- */
1784       {
1785       int ovector[1*3];
1786       uschar buf[1024];
1787       uschar * scanrequest;
1788       enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1789       int nread;
1790
1791       /* According to Martin Tuma @avast the protocol uses "escaped
1792       whitespace", that is, every embedded whitespace is backslash
1793       escaped, as well as backslash is protected by backslash.
1794       The returned lines contain the name of the scanned file, a tab
1795       and the [ ] marker.
1796       [+] - not infected
1797       [L] - infected
1798       [E] - some error occured
1799       Such marker follows the first non-escaped TAB.  */
1800       if (  (  !ava_re_clean
1801             && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1802          || (  !ava_re_virus
1803             && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1804          )
1805         return malware_errlog_defer(errstr);
1806
1807       /* wait for result */
1808       for (avast_stage = AVA_HELO;
1809            (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1810           )
1811         {
1812         int slen = Ustrlen(buf);
1813         if (slen >= 1)
1814           {
1815           DEBUG(D_acl) debug_printf("got from avast: %s\n", buf);
1816           switch (avast_stage)
1817             {
1818             case AVA_HELO:
1819               if (Ustrncmp(buf, "220", 3) != 0)
1820                 goto endloop;                   /* require a 220 */
1821               goto sendreq;
1822
1823             case AVA_OPT:
1824               if (Ustrncmp(buf, "210", 3) == 0)
1825                 break;                          /* ignore 210 responses */
1826               if (Ustrncmp(buf, "200", 3) != 0)
1827                 goto endloop;                   /* require a 200 */
1828
1829             sendreq:
1830               {
1831               int len;
1832               /* Check for another option to send. Newline-terminate it. */
1833               if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1834                                 NULL, 0)))
1835                 {
1836                 scanrequest = string_sprintf("%s\n", scanrequest);
1837                 avast_stage = AVA_OPT;          /* just sent option */
1838                 }
1839               else
1840                 {
1841                 scanrequest = string_sprintf("SCAN %s/scan/%s\n",
1842                     spool_directory, message_id);
1843                 avast_stage = AVA_RSP;          /* just sent command */
1844                 }
1845
1846               /* send config-cmd or scan-request to socket */
1847               len = Ustrlen(scanrequest);
1848               if (send(sock, scanrequest, len, 0) < 0)
1849                 {
1850                 scanrequest[len-1] = '\0';
1851                 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
1852                       "unable to send request '%s' to socket (%s): %s",
1853                       scanrequest, scanner_options, strerror(errno)), sock);
1854                 }
1855               break;
1856               }
1857
1858             case AVA_RSP:
1859               if (Ustrncmp(buf, "210", 3) == 0)
1860                 break;  /* ignore the "210 SCAN DATA" message */
1861
1862               if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
1863                     0, 0, ovector, nelements(ovector)) > 0)
1864                 break;
1865
1866               if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
1867                 { /* remove backslash in front of [whitespace|backslash] */
1868                 uschar * p, * p0;
1869                 for (p = malware_name; *p; ++p)
1870                   if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
1871                     for (p0 = p; *p0; ++p0) *p0 = p0[1];
1872
1873                 avast_stage = AVA_DONE;
1874                 goto endloop;
1875                 }
1876
1877               if (Ustrncmp(buf, "200 SCAN OK", 11) == 0)
1878                 { /* we're done finally */
1879                 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1880                   return m_errlog_defer_3(scanent, CUS callout_address,
1881                           string_sprintf(
1882                               "unable to send quit request to socket (%s): %s",
1883                               scanner_options, strerror(errno)),
1884                               sock);
1885                 malware_name = NULL;
1886                 avast_stage = AVA_DONE;
1887                 goto endloop;
1888                 }
1889
1890               /* here for any unexpected response from the scanner */
1891               goto endloop;
1892
1893             case AVA_DONE:      log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
1894                             __FILE__, __LINE__, __FUNCTION__);
1895             }
1896           }
1897         }
1898       endloop:
1899
1900       switch(avast_stage)
1901         {
1902         case AVA_HELO:
1903         case AVA_OPT:
1904         case AVA_RSP:   return m_errlog_defer_3(scanent, CUS callout_address,
1905                             nread >= 0
1906                             ? string_sprintf(
1907                                 "invalid response from scanner: '%s'", buf)
1908                             : nread == -1
1909                             ? US"EOF from scanner"
1910                             : US"timeout from scanner",
1911                           sock);
1912         default:        break;
1913         }
1914       }
1915       break;
1916   }     /* scanner type switch */
1917
1918   if (sock >= 0)
1919     (void) close (sock);
1920   malware_ok = TRUE;                    /* set "been here, done that" marker */
1921   }
1922
1923 /* match virus name against pattern (caseless ------->----------v) */
1924 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
1925   {
1926   DEBUG(D_acl) debug_printf(
1927       "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
1928   return OK;
1929   }
1930 else
1931   return FAIL;
1932 }
1933
1934
1935 /*************************************************
1936 *          Scan an email for malware             *
1937 *************************************************/
1938
1939 /* This is the normal interface for scanning an email, which doesn't need a
1940 filename; it's a wrapper around the malware_file function.
1941
1942 Arguments:
1943   malware_re  match condition for "malware="
1944   timeout     if nonzero, timeout in seconds
1945
1946 Returns:      Exim message processing code (OK, FAIL, DEFER, ...)
1947               where true means malware was found (condition applies)
1948 */
1949 int
1950 malware(const uschar * malware_re, int timeout)
1951 {
1952 uschar * scan_filename;
1953 int ret;
1954
1955 scan_filename = string_sprintf("%s/scan/%s/%s.eml",
1956                   spool_directory, message_id, message_id);
1957 ret = malware_internal(malware_re, scan_filename, timeout, FALSE);
1958 if (ret == DEFER) av_failed = TRUE;
1959
1960 return ret;
1961 }
1962
1963
1964 /*************************************************
1965 *          Scan a file for malware               *
1966 *************************************************/
1967
1968 /* This is a test wrapper for scanning an email, which is not used in
1969 normal processing.  Scan any file, using the Exim scanning interface.
1970 This function tampers with various global variables so is unsafe to use
1971 in any other context.
1972
1973 Arguments:
1974   eml_filename  a file holding the message to be scanned
1975
1976 Returns:        Exim message processing code (OK, FAIL, DEFER, ...)
1977                 where true means malware was found (condition applies)
1978 */
1979 int
1980 malware_in_file(uschar *eml_filename)
1981 {
1982 uschar message_id_buf[64];
1983 int ret;
1984
1985 /* spool_mbox() assumes various parameters exist, when creating
1986 the relevant directory and the email within */
1987
1988 (void) string_format(message_id_buf, sizeof(message_id_buf),
1989     "dummy-%d", vaguely_random_number(INT_MAX));
1990 message_id = message_id_buf;
1991 sender_address = US"malware-sender@example.net";
1992 return_path = US"";
1993 recipients_list = NULL;
1994 receive_add_recipient(US"malware-victim@example.net", -1);
1995 enable_dollar_recipients = TRUE;
1996
1997 ret = malware_internal(US"*", eml_filename, 0,  TRUE);
1998
1999 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2000 spool_mbox_ok = 1;
2001
2002 /* don't set no_mbox_unspool; at present, there's no way for it to become
2003 set, but if that changes, then it should apply to these tests too */
2004
2005 unspool_mbox();
2006
2007 /* silence static analysis tools */
2008 message_id = NULL;
2009
2010 return ret;
2011 }
2012
2013
2014 void
2015 malware_init(void)
2016 {
2017 if (!malware_default_re)
2018   malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2019 if (!drweb_re)
2020   drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2021 if (!fsec_re)
2022   fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2023 if (!kav_re_sus)
2024   kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2025 if (!kav_re_inf)
2026   kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2027 if (!ava_re_clean)
2028   ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2029 if (!ava_re_virus)
2030   ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2031 }
2032
2033 #endif /*WITH_CONTENT_SCAN*/
2034 /*
2035  * vi: aw ai sw=2
2036  */