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