tidying
[exim.git] / src / src / malware.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
6  * License: GPL
7  * Copyright (c) The Exim Maintainers 2017
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, US 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 av_buffer[1024];
1243       uschar *hostname = US"";
1244       host_item connhost;
1245       uschar *clamav_fbuf;
1246       int clam_fd, result;
1247       off_t fsize;
1248       unsigned int fsize_uint;
1249       BOOL use_scan_command = FALSE;
1250       clamd_address * cv[MAX_CLAMD_SERVERS];
1251       int num_servers = 0;
1252 #ifdef WITH_OLD_CLAMAV_STREAM
1253       unsigned int port;
1254       uschar av_buffer2[1024];
1255       int sockData;
1256 #else
1257       uint32_t send_size, send_final_zeroblock;
1258 #endif
1259       blob cmd_str;
1260
1261       /*XXX if unixdomain socket, only one server supported. Needs fixing;
1262       there's no reason we should not mix local and remote servers */
1263
1264       if (*scanner_options == '/')
1265         {
1266         clamd_address * cd;
1267         const uschar * sublist;
1268         int subsep = ' ';
1269
1270         /* Local file; so we def want to use_scan_command and don't want to try
1271          * passing IP/port combinations */
1272         use_scan_command = TRUE;
1273         cd = (clamd_address *) store_get(sizeof(clamd_address));
1274
1275         /* extract socket-path part */
1276         sublist = scanner_options;
1277         cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1278
1279         /* parse options */
1280         if (clamd_option(cd, sublist, &subsep) != OK)
1281           return m_errlog_defer(scanent, NULL,
1282             string_sprintf("bad option '%s'", scanner_options));
1283         cv[0] = cd;
1284         }
1285       else
1286         {
1287         /* Go through the rest of the list of host/port and construct an array
1288          * of servers to try. The first one is the bit we just passed from
1289          * scanner_options so process that first and then scan the remainder of
1290          * the address buffer */
1291         do
1292           {
1293           clamd_address * cd;
1294           const uschar * sublist;
1295           int subsep = ' ';
1296           uschar * s;
1297
1298           /* The 'local' option means use the SCAN command over the network
1299            * socket (ie common file storage in use) */
1300           /*XXX we could accept this also as a local option? */
1301           if (strcmpic(scanner_options, US"local") == 0)
1302             {
1303             use_scan_command = TRUE;
1304             continue;
1305             }
1306
1307           cd = (clamd_address *) store_get(sizeof(clamd_address));
1308
1309           /* extract host and port part */
1310           sublist = scanner_options;
1311           if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1312             {
1313             (void) m_errlog_defer(scanent, NULL, 
1314                       string_sprintf("missing address: '%s'", scanner_options));
1315             continue;
1316             }
1317           if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1318             {
1319             (void) m_errlog_defer(scanent, NULL, 
1320                       string_sprintf("missing port: '%s'", scanner_options));
1321             continue;
1322             }
1323           cd->tcp_port = atoi(CS s);
1324
1325           /* parse options */
1326           /*XXX should these options be common over scanner types? */
1327           if (clamd_option(cd, sublist, &subsep) != OK)
1328             return m_errlog_defer(scanent, NULL,
1329               string_sprintf("bad option '%s'", scanner_options));
1330
1331           cv[num_servers++] = cd;
1332           if (num_servers >= MAX_CLAMD_SERVERS)
1333             {
1334             (void) m_errlog_defer(scanent, NULL,
1335                   US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1336                   "specified; only using the first " MAX_CLAMD_SERVERS_S );
1337             break;
1338             }
1339           } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1340                                         NULL, 0)));
1341
1342         /* check if we have at least one server */
1343         if (!num_servers)
1344           return m_errlog_defer(scanent, NULL,
1345             US"no useable server addresses in malware configuration option.");
1346         }
1347
1348       /* See the discussion of response formats below to see why we really
1349       don't like colons in filenames when passing filenames to ClamAV. */
1350       if (use_scan_command && Ustrchr(eml_filename, ':'))
1351         return m_errlog_defer(scanent, NULL,
1352           string_sprintf("local/SCAN mode incompatible with" \
1353             " : in path to email filename [%s]", eml_filename));
1354
1355       /* Set up the very first data we will be sending */
1356       if (!use_scan_command)
1357 #ifdef WITH_OLD_CLAMAV_STREAM
1358         { cmd_str.data = US"STREAM\n"; cmd_str.len = 7; }
1359 #else
1360         { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1361 #endif
1362       else
1363         {
1364         cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
1365         cmd_str.len = Ustrlen(cmd_str.data);
1366         }
1367
1368       /* We have some network servers specified */
1369       if (num_servers)
1370         {
1371         /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1372          * only supports AF_INET, but we should probably be looking to the
1373          * future and rewriting this to be protocol-independent anyway. */
1374
1375         while (num_servers > 0)
1376           {
1377           int i = random_number(num_servers);
1378           clamd_address * cd = cv[i];
1379
1380           DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1381                          cd->hostspec, cd->tcp_port);
1382
1383           /* Lookup the host. This is to ensure that we connect to the same IP
1384            * on both connections (as one host could resolve to multiple ips) */
1385           for (;;)
1386             {
1387             if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1388                                     &connhost, &errstr, &cmd_str)) >= 0)
1389               {
1390               /* Connection successfully established with a server */
1391               hostname = cd->hostspec;
1392               cmd_str.len = 0;
1393               break;
1394               }
1395             if (cd->retry <= 0) break;
1396             while (cd->retry > 0) cd->retry = sleep(cd->retry);
1397             }
1398           if (sock >= 0)
1399             break;
1400
1401           (void) m_errlog_defer(scanent, CUS callout_address, errstr);
1402
1403           /* Remove the server from the list. XXX We should free the memory */
1404           num_servers--;
1405           for (; i < num_servers; i++)
1406             cv[i] = cv[i+1];
1407           }
1408
1409         if (num_servers == 0)
1410           return m_errlog_defer(scanent, NULL, US"all servers failed");
1411         }
1412       else
1413         for (;;)
1414           {
1415           if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1416             {
1417             hostname = cv[0]->hostspec;
1418             break;
1419             }
1420           if (cv[0]->retry <= 0)
1421             return m_errlog_defer(scanent, CUS callout_address, errstr);
1422           while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1423           }
1424
1425       /* have socket in variable "sock"; command to use is semi-independent of
1426        * the socket protocol.  We use SCAN if is local (either Unix/local
1427        * domain socket, or explicitly told local) else we stream the data.
1428        * How we stream the data depends upon how we were built.  */
1429
1430       if (!use_scan_command)
1431         {
1432 #ifdef WITH_OLD_CLAMAV_STREAM
1433         /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1434          * that port on a second connection; then in the scan-method-neutral
1435          * part, read the response back on the original connection. */
1436
1437         DEBUG(D_acl) debug_printf_indent(
1438             "Malware scan: issuing %s old-style remote scan (PORT)\n",
1439             scanner_name);
1440
1441         /* Pass the string to ClamAV (7 = "STREAM\n"), if not already sent */
1442         if (cmd_str.len)
1443           if (m_sock_send(sock, cmd_str.data, cmd_str.len, &errstr) < 0)
1444             return m_errlog_defer(scanent, CUS callout_address, errstr);
1445
1446         memset(av_buffer2, 0, sizeof(av_buffer2));
1447         bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
1448
1449         if (bread < 0)
1450           return m_errlog_defer_3(scanent, CUS callout_address,
1451             string_sprintf("unable to read PORT from socket (%s)",
1452                 strerror(errno)),
1453             sock);
1454
1455         if (bread == sizeof(av_buffer2))
1456           return m_errlog_defer_3(scanent, CUS callout_address,
1457                   "buffer too small", sock);
1458
1459         if (!(*av_buffer2))
1460           return m_errlog_defer_3(scanent, CUS callout_address,
1461                   "ClamAV returned null", sock);
1462
1463         av_buffer2[bread] = '\0';
1464         if(sscanf(CS av_buffer2, "PORT %u\n", &port) != 1)
1465           return m_errlog_defer_3(scanent, CUS callout_address,
1466             string_sprintf("Expected port information from clamd, got '%s'",
1467               av_buffer2),
1468             sock);
1469
1470         sockData = m_tcpsocket(connhost.address, port, NULL, &errstr, NULL);
1471         if (sockData < 0)
1472           return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock);
1473
1474 # define CLOSE_SOCKDATA (void)close(sockData)
1475 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1476         /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1477         chunks, <n> a 4-byte number (network order), terminated by a zero-length
1478         chunk. */
1479
1480         DEBUG(D_acl) debug_printf_indent(
1481             "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1482             scanner_name);
1483
1484         /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1485         if (cmd_str.len)
1486           if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1487             return m_errlog_defer_3(scanent, CUS hostname,
1488               string_sprintf("unable to send zINSTREAM to socket (%s)",
1489                 strerror(errno)),
1490               sock);
1491
1492 # define CLOSE_SOCKDATA /**/
1493 #endif
1494
1495         /* calc file size */
1496         if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1497           {
1498           int err = errno;
1499           CLOSE_SOCKDATA;
1500           return m_errlog_defer_3(scanent, NULL,
1501             string_sprintf("can't open spool file %s: %s",
1502               eml_filename, strerror(err)),
1503             sock);
1504           }
1505         if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1506           {
1507           int err;
1508 b_seek:   err = errno;
1509           CLOSE_SOCKDATA; (void)close(clam_fd);
1510           return m_errlog_defer_3(scanent, NULL,
1511             string_sprintf("can't seek spool file %s: %s",
1512               eml_filename, strerror(err)),
1513             sock);
1514           }
1515         fsize_uint = (unsigned int) fsize;
1516         if ((off_t)fsize_uint != fsize)
1517           {
1518           CLOSE_SOCKDATA; (void)close(clam_fd);
1519           return m_errlog_defer_3(scanent, NULL,
1520             string_sprintf("seeking spool file %s, size overflow",
1521               eml_filename),
1522             sock);
1523           }
1524         if (lseek(clam_fd, 0, SEEK_SET) < 0)
1525           goto b_seek;
1526
1527         if (!(clamav_fbuf = US malloc(fsize_uint)))
1528           {
1529           CLOSE_SOCKDATA; (void)close(clam_fd);
1530           return m_errlog_defer_3(scanent, NULL,
1531             string_sprintf("unable to allocate memory %u for file (%s)",
1532               fsize_uint, eml_filename),
1533             sock);
1534           }
1535
1536         if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1537           {
1538           int err = errno;
1539           free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd);
1540           return m_errlog_defer_3(scanent, NULL,
1541             string_sprintf("can't read spool file %s: %s",
1542               eml_filename, strerror(err)),
1543             sock);
1544           }
1545         (void)close(clam_fd);
1546
1547         /* send file body to socket */
1548 #ifdef WITH_OLD_CLAMAV_STREAM
1549         if (send(sockData, clamav_fbuf, fsize_uint, 0) < 0)
1550           {
1551           free(clamav_fbuf); CLOSE_SOCKDATA;
1552           return m_errlog_defer_3(scanent, NULL,
1553             string_sprintf("unable to send file body to socket (%s:%u)",
1554               hostname, port),
1555             sock);
1556           }
1557 #else
1558         send_size = htonl(fsize_uint);
1559         send_final_zeroblock = 0;
1560         if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1561             (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1562             (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1563           {
1564           free(clamav_fbuf);
1565           return m_errlog_defer_3(scanent, NULL,
1566             string_sprintf("unable to send file body to socket (%s)", hostname),
1567             sock);
1568           }
1569 #endif
1570
1571         free(clamav_fbuf);
1572
1573         CLOSE_SOCKDATA;
1574 #undef CLOSE_SOCKDATA
1575         }
1576       else
1577         { /* use scan command */
1578         /* Send a SCAN command pointing to a filename; then in the then in the
1579          * scan-method-neutral part, read the response back */
1580
1581 /* ================================================================= */
1582
1583         /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1584         which dates to when ClamAV needed us to break apart the email into the
1585         MIME parts (eg, with the now deprecated demime condition coming first).
1586         Some time back, ClamAV gained the ability to deconstruct the emails, so
1587         doing this would actually have resulted in the mail attachments being
1588         scanned twice, in the broken out files and from the original .eml.
1589         Since ClamAV now handles emails (and has for quite some time) we can
1590         just use the email file itself. */
1591         /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
1592
1593         DEBUG(D_acl) debug_printf_indent(
1594             "Malware scan: issuing %s local-path scan [%s]\n",
1595             scanner_name, scanner_options);
1596
1597         if (cmd_str.len)
1598           if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1599             return m_errlog_defer_3(scanent, CUS callout_address,
1600               string_sprintf("unable to write to socket (%s)", strerror(errno)),
1601               sock);
1602
1603         /* Do not shut down the socket for writing; a user report noted that
1604          * clamd 0.70 does not react well to this. */
1605         }
1606       /* Commands have been sent, no matter which scan method or connection
1607        * type we're using; now just read the result, independent of method. */
1608
1609       /* Read the result */
1610       memset(av_buffer, 0, sizeof(av_buffer));
1611       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1612       (void)close(sock);
1613       sock = -1;
1614
1615       if (bread <= 0)
1616         return m_errlog_defer(scanent, CUS callout_address,
1617           string_sprintf("unable to read from socket (%s)",
1618           errno == 0 ? "EOF" : strerror(errno)));
1619
1620       if (bread == sizeof(av_buffer))
1621         return m_errlog_defer(scanent, CUS callout_address,
1622                 US"buffer too small");
1623       /* We're now assured of a NULL at the end of av_buffer */
1624
1625       /* Check the result. ClamAV returns one of two result formats.
1626       In the basic mode, the response is of the form:
1627         infected: -> "<filename>: <virusname> FOUND"
1628         not-infected: -> "<filename>: OK"
1629         error: -> "<filename>: <errcode> ERROR
1630       If the ExtendedDetectionInfo option has been turned on, then we get:
1631         "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1632       for the infected case.  Compare:
1633 /tmp/eicar.com: Eicar-Test-Signature FOUND
1634 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1635
1636       In the streaming case, clamd uses the filename "stream" which you should
1637       be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }.  (The
1638       client app will replace "stream" with the original filename before returning
1639       results to stdout, but the trace shows the data).
1640
1641       We will assume that the pathname passed to clamd from Exim does not contain
1642       a colon.  We will have whined loudly above if the eml_filename does (and we're
1643       passing a filename to clamd). */
1644
1645       if (!(*av_buffer))
1646         return m_errlog_defer(scanent, CUS callout_address,
1647                 US"ClamAV returned null");
1648
1649       /* strip newline at the end (won't be present for zINSTREAM)
1650       (also any trailing whitespace, which shouldn't exist, but we depend upon
1651       this below, so double-check) */
1652       p = av_buffer + Ustrlen(av_buffer) - 1;
1653       if (*p == '\n') *p = '\0';
1654
1655       DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1656
1657       while (isspace(*--p) && (p > av_buffer))
1658         *p = '\0';
1659       if (*p) ++p;
1660
1661       /* colon in returned output? */
1662       if(!(p = Ustrchr(av_buffer,':')))
1663         return m_errlog_defer(scanent, CUS callout_address, string_sprintf(
1664                   "ClamAV returned malformed result (missing colon): %s",
1665                   av_buffer));
1666
1667       /* strip filename */
1668       while (*p && isspace(*++p)) /**/;
1669       vname = p;
1670
1671       /* It would be bad to encounter a virus with "FOUND" in part of the name,
1672       but we should at least be resistant to it. */
1673       p = Ustrrchr(vname, ' ');
1674       result_tag = p ? p+1 : vname;
1675
1676       if (Ustrcmp(result_tag, "FOUND") == 0)
1677         {
1678         /* p should still be the whitespace before the result_tag */
1679         while (isspace(*p)) --p;
1680         *++p = '\0';
1681         /* Strip off the extended information too, which will be in parens
1682         after the virus name, with no intervening whitespace. */
1683         if (*--p == ')')
1684           {
1685           /* "(hash:size)", so previous '(' will do; if not found, we have
1686           a curious virus name, but not an error. */
1687           p = Ustrrchr(vname, '(');
1688           if (p)
1689             *p = '\0';
1690           }
1691         malware_name = string_copy(vname);
1692         DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1693
1694         }
1695       else if (Ustrcmp(result_tag, "ERROR") == 0)
1696         return m_errlog_defer(scanent, CUS callout_address,
1697           string_sprintf("ClamAV returned: %s", av_buffer));
1698
1699       else if (Ustrcmp(result_tag, "OK") == 0)
1700         {
1701         /* Everything should be OK */
1702         malware_name = NULL;
1703         DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1704
1705         }
1706       else
1707         return m_errlog_defer(scanent, CUS callout_address,
1708           string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1709
1710       break;
1711       } /* clamd */
1712
1713     case M_SOCK: /* "sock" scanner type ------------------------------------- */
1714     /* This code was derived by Martin Poole from the clamd code contributed
1715        by David Saez and the cmdline code
1716     */
1717       {
1718       int bread;
1719       uschar * commandline;
1720       uschar av_buffer[1024];
1721       uschar * linebuffer;
1722       uschar * sockline_scanner;
1723       uschar sockline_scanner_default[] = "%s\n";
1724       const pcre *sockline_trig_re;
1725       const pcre *sockline_name_re;
1726
1727       /* find scanner command line */
1728       if (  (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1729                                           NULL, 0))
1730          && *sockline_scanner
1731          )
1732       { /* check for no expansions apart from one %s */
1733         uschar * s = Ustrchr(sockline_scanner, '%');
1734         if (s++)
1735           if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1736             return m_errlog_defer_3(scanent, NULL,
1737                                   US"unsafe sock scanner call spec", sock);
1738       }
1739       else
1740         sockline_scanner = sockline_scanner_default;
1741       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1742         string_printing(sockline_scanner));
1743
1744       /* find scanner output trigger */
1745       sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1746                                 "missing trigger specification", &errstr);
1747       if (!sockline_trig_re)
1748         return m_errlog_defer_3(scanent, NULL, errstr, sock);
1749
1750       /* find virus name regex */
1751       sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1752                           "missing virus name regex specification", &errstr);
1753       if (!sockline_name_re)
1754         return m_errlog_defer_3(scanent, NULL, errstr, sock);
1755
1756       /* prepare scanner call - security depends on expansions check above */
1757       commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1758       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1759         string_printing(commandline));
1760
1761       /* Pass the command string to the socket */
1762       if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1763         return m_errlog_defer(scanent, CUS callout_address, errstr);
1764
1765       /* Read the result */
1766       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1767
1768       if (bread <= 0)
1769         return m_errlog_defer_3(scanent, CUS callout_address,
1770           string_sprintf("unable to read from socket (%s)", strerror(errno)),
1771           sock);
1772
1773       if (bread == sizeof(av_buffer))
1774         return m_errlog_defer_3(scanent, CUS callout_address,
1775                 US"buffer too small", sock);
1776       av_buffer[bread] = '\0';
1777       linebuffer = string_copy(av_buffer);
1778       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1779         string_printing(linebuffer));
1780
1781       /* try trigger match */
1782       if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1783         {
1784         if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1785           malware_name = US "unknown";
1786         DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1787           string_printing(malware_name));
1788         }
1789       else /* no virus found */
1790         malware_name = NULL;
1791       break;
1792       }
1793
1794     case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1795       {
1796       char *mksd_options_end;
1797       int mksd_maxproc = 1;  /* default, if no option supplied */
1798       int retval;
1799
1800       if (scanner_options)
1801         {
1802         mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1803         if (  *scanner_options == '\0'
1804            || *mksd_options_end != '\0'
1805            || mksd_maxproc < 1
1806            || mksd_maxproc > 32
1807            )
1808           return m_errlog_defer(scanent, CUS callout_address,
1809             string_sprintf("invalid option '%s'", scanner_options));
1810         }
1811
1812       if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1813         return m_errlog_defer(scanent, CUS callout_address, errstr);
1814
1815       malware_name = NULL;
1816
1817       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1818
1819       if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1820         {
1821         close (sock);
1822         return retval;
1823         }
1824       break;
1825       }
1826
1827     case M_AVAST: /* "avast" scanner type ----------------------------------- */
1828       {
1829       int ovector[1*3];
1830       uschar buf[1024];
1831       uschar * scanrequest;
1832       enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1833       int nread;
1834
1835       /* According to Martin Tuma @avast the protocol uses "escaped
1836       whitespace", that is, every embedded whitespace is backslash
1837       escaped, as well as backslash is protected by backslash.
1838       The returned lines contain the name of the scanned file, a tab
1839       and the [ ] marker.
1840       [+] - not infected
1841       [L] - infected
1842       [E] - some error occured
1843       Such marker follows the first non-escaped TAB.  */
1844       if (  (  !ava_re_clean
1845             && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1846          || (  !ava_re_virus
1847             && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1848          )
1849         return malware_errlog_defer(errstr);
1850
1851       /* wait for result */
1852       for (avast_stage = AVA_HELO;
1853            (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1854           )
1855         {
1856         int slen = Ustrlen(buf);
1857         if (slen >= 1)
1858           {
1859           DEBUG(D_acl) debug_printf_indent("got from avast: %s\n", buf);
1860           switch (avast_stage)
1861             {
1862             case AVA_HELO:
1863               if (Ustrncmp(buf, "220", 3) != 0)
1864                 goto endloop;                   /* require a 220 */
1865               goto sendreq;
1866
1867             case AVA_OPT:
1868               if (Ustrncmp(buf, "210", 3) == 0)
1869                 break;                          /* ignore 210 responses */
1870               if (Ustrncmp(buf, "200", 3) != 0)
1871                 goto endloop;                   /* require a 200 */
1872
1873             sendreq:
1874               {
1875               int len;
1876               /* Check for another option to send. Newline-terminate it. */
1877               if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1878                                 NULL, 0)))
1879                 {
1880                 scanrequest = string_sprintf("%s\n", scanrequest);
1881                 avast_stage = AVA_OPT;          /* just sent option */
1882                 }
1883               else
1884                 {
1885                 scanrequest = string_sprintf("SCAN %s\n", eml_dir);
1886                 avast_stage = AVA_RSP;          /* just sent command */
1887                 }
1888
1889               /* send config-cmd or scan-request to socket */
1890               len = Ustrlen(scanrequest);
1891               if (send(sock, scanrequest, len, 0) < 0)
1892                 {
1893                 scanrequest[len-1] = '\0';
1894                 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
1895                       "unable to send request '%s' to socket (%s): %s",
1896                       scanrequest, scanner_options, strerror(errno)), sock);
1897                 }
1898               break;
1899               }
1900
1901             case AVA_RSP:
1902               if (Ustrncmp(buf, "210", 3) == 0)
1903                 break;  /* ignore the "210 SCAN DATA" message */
1904
1905               if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
1906                     0, 0, ovector, nelements(ovector)) > 0)
1907                 break;
1908
1909               if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
1910                 { /* remove backslash in front of [whitespace|backslash] */
1911                 uschar * p, * p0;
1912                 for (p = malware_name; *p; ++p)
1913                   if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
1914                     for (p0 = p; *p0; ++p0) *p0 = p0[1];
1915
1916                 avast_stage = AVA_DONE;
1917                 goto endloop;
1918                 }
1919
1920               if (Ustrncmp(buf, "200 SCAN OK", 11) == 0)
1921                 { /* we're done finally */
1922                 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1923                   return m_errlog_defer_3(scanent, CUS callout_address,
1924                           string_sprintf(
1925                               "unable to send quit request to socket (%s): %s",
1926                               scanner_options, strerror(errno)),
1927                               sock);
1928                 malware_name = NULL;
1929                 avast_stage = AVA_DONE;
1930                 goto endloop;
1931                 }
1932
1933               /* here for any unexpected response from the scanner */
1934               goto endloop;
1935
1936             case AVA_DONE:      log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
1937                             __FILE__, __LINE__, __FUNCTION__);
1938             }
1939           }
1940         }
1941       endloop:
1942
1943       switch(avast_stage)
1944         {
1945         case AVA_HELO:
1946         case AVA_OPT:
1947         case AVA_RSP:   return m_errlog_defer_3(scanent, CUS callout_address,
1948                             nread >= 0
1949                             ? string_sprintf(
1950                                 "invalid response from scanner: '%s'", buf)
1951                             : nread == -1
1952                             ? US"EOF from scanner"
1953                             : US"timeout from scanner",
1954                           sock);
1955         default:        break;
1956         }
1957       break;
1958       }
1959
1960     case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
1961       {
1962       int bread;
1963       uschar * e;
1964       uschar * linebuffer;
1965       uschar * scanrequest;
1966       uschar av_buffer[1024];
1967
1968       if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
1969         || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
1970         return malware_errlog_defer(errstr);
1971
1972       scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
1973       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
1974         scanner_name, scanrequest);
1975
1976       if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
1977         return m_errlog_defer(scanent, CUS callout_address, errstr);
1978
1979       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1980
1981       if (bread <= 0)
1982         return m_errlog_defer_3(scanent, CUS callout_address,
1983           string_sprintf("unable to read from socket (%s)", strerror(errno)),
1984           sock);
1985
1986       if (bread == sizeof(av_buffer))
1987         return m_errlog_defer_3(scanent, CUS callout_address,
1988           US"buffer too small", sock);
1989
1990       av_buffer[bread] = '\0';
1991       linebuffer = string_copy(av_buffer);
1992
1993       m_sock_send(sock, US"QUIT\n", 5, 0);
1994
1995       if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
1996         return m_errlog_defer_3(scanent, CUS callout_address,
1997           string_sprintf("scanner reported error (%s)", e), sock);
1998
1999       if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
2000         malware_name = NULL;
2001
2002       break;
2003       }  /* f-prot6d */
2004   }     /* scanner type switch */
2005
2006   if (sock >= 0)
2007     (void) close (sock);
2008   malware_ok = TRUE;                    /* set "been here, done that" marker */
2009   }
2010
2011 /* match virus name against pattern (caseless ------->----------v) */
2012 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
2013   {
2014   DEBUG(D_acl) debug_printf_indent(
2015       "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2016   return OK;
2017   }
2018 else
2019   return FAIL;
2020 }
2021
2022
2023 /*************************************************
2024 *          Scan an email for malware             *
2025 *************************************************/
2026
2027 /* This is the normal interface for scanning an email, which doesn't need a
2028 filename; it's a wrapper around the malware_file function.
2029
2030 Arguments:
2031   malware_re  match condition for "malware="
2032   timeout     if nonzero, timeout in seconds
2033
2034 Returns:      Exim message processing code (OK, FAIL, DEFER, ...)
2035               where true means malware was found (condition applies)
2036 */
2037 int
2038 malware(const uschar * malware_re, int timeout)
2039 {
2040 int ret = malware_internal(malware_re, NULL, timeout);
2041
2042 if (ret == DEFER) av_failed = TRUE;
2043 return ret;
2044 }
2045
2046
2047 /*************************************************
2048 *          Scan a file for malware               *
2049 *************************************************/
2050
2051 /* This is a test wrapper for scanning an email, which is not used in
2052 normal processing.  Scan any file, using the Exim scanning interface.
2053 This function tampers with various global variables so is unsafe to use
2054 in any other context.
2055
2056 Arguments:
2057   eml_filename  a file holding the message to be scanned
2058
2059 Returns:        Exim message processing code (OK, FAIL, DEFER, ...)
2060                 where true means malware was found (condition applies)
2061 */
2062 int
2063 malware_in_file(uschar *eml_filename)
2064 {
2065 uschar message_id_buf[64];
2066 int ret;
2067
2068 /* spool_mbox() assumes various parameters exist, when creating
2069 the relevant directory and the email within */
2070
2071 (void) string_format(message_id_buf, sizeof(message_id_buf),
2072     "dummy-%d", vaguely_random_number(INT_MAX));
2073 message_id = message_id_buf;
2074 sender_address = US"malware-sender@example.net";
2075 return_path = US"";
2076 recipients_list = NULL;
2077 receive_add_recipient(US"malware-victim@example.net", -1);
2078 enable_dollar_recipients = TRUE;
2079
2080 ret = malware_internal(US"*", eml_filename, 0);
2081
2082 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2083 spool_mbox_ok = 1;
2084
2085 /* don't set no_mbox_unspool; at present, there's no way for it to become
2086 set, but if that changes, then it should apply to these tests too */
2087
2088 unspool_mbox();
2089
2090 /* silence static analysis tools */
2091 message_id = NULL;
2092
2093 return ret;
2094 }
2095
2096
2097 void
2098 malware_init(void)
2099 {
2100 if (!malware_default_re)
2101   malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2102 if (!drweb_re)
2103   drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2104 if (!fsec_re)
2105   fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2106 if (!kav_re_sus)
2107   kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2108 if (!kav_re_inf)
2109   kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2110 if (!ava_re_clean)
2111   ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2112 if (!ava_re_virus)
2113   ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2114 if (!fprot6d_re_error)
2115   fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2116 if (!fprot6d_re_virus)
2117   fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2118 }
2119
2120 #endif /*WITH_CONTENT_SCAN*/
2121 /*
2122  * vi: aw ai sw=2
2123  */