32f2e9e492461fd4209e70570925df71a29bf4fb
[users/heiko/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)
151 {
152 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
153                           host, errstr, fastopen);
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
714         /* setup default virus name */
715         malware_name = US"unknown";
716
717         /* set up match regex */
718         if (!drweb_re)
719           drweb_re = m_pcre_compile(drweb_re_str, &errstr);
720
721         /* read and concatenate virus names into one string */
722         for (i = 0; i < drweb_vnum; i++)
723           {
724           int size = 0, off = 0, ovector[10*3];
725           /* read the size of report */
726           if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
727             return m_errlog_defer_3(scanent, CUS callout_address,
728                               US"cannot read report size", sock);
729           drweb_slen = ntohl(drweb_slen);
730           tmpbuf = store_get(drweb_slen);
731
732           /* read report body */
733           if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
734             return m_errlog_defer_3(scanent, CUS callout_address,
735                               US"cannot read report string", sock);
736           tmpbuf[drweb_slen] = '\0';
737
738           /* try matcher on the line, grab substring */
739           result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
740                                   ovector, nelements(ovector));
741           if (result >= 2)
742             {
743             const char * pre_malware_nb;
744
745             pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
746
747             if (i==0)   /* the first name we just copy to malware_name */
748               malware_name = string_append(NULL, &size, &off,
749                                           1, pre_malware_nb);
750
751             else        /* concatenate each new virus name to previous */
752               malware_name = string_append(malware_name, &size, &off,
753                                           2, "/", pre_malware_nb);
754
755             pcre_free_substring(pre_malware_nb);
756             }
757           }
758         }
759       else
760         {
761         const char *drweb_s = NULL;
762
763         if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
764         if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
765         if (drweb_rc & DERR_TIMEOUT)  drweb_s = "timeout";
766         if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
767         /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
768          * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
769          * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
770          * and others are ignored */
771         if (drweb_s)
772           return m_errlog_defer_3(scanent, CUS callout_address,
773             string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
774             sock);
775
776         /* no virus found */
777         malware_name = NULL;
778         }
779       break;
780       } /* drweb */
781
782     case M_AVES: /* "aveserver" scanner type -------------------------------- */
783       {
784       uschar buf[32768];
785       int result;
786
787       /* read aveserver's greeting and see if it is ready (2xx greeting) */
788       buf[0] = 0;
789       recv_line(sock, buf, sizeof(buf), tmo);
790
791       if (buf[0] != '2')                /* aveserver is having problems */
792         return m_errlog_defer_3(scanent, CUS callout_address,
793           string_sprintf("unavailable (Responded: %s).",
794                           ((buf[0] != 0) ? buf : US "nothing") ),
795           sock);
796
797       /* prepare our command */
798       (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
799                                                 eml_filename);
800
801       /* and send it */
802       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
803         scanner_name, buf);
804       if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
805         return m_errlog_defer(scanent, CUS callout_address, errstr);
806
807       malware_name = NULL;
808       result = 0;
809       /* read response lines, find malware name and final response */
810       while (recv_line(sock, buf, sizeof(buf), tmo) > 0)
811         {
812         if (buf[0] == '2')
813           break;
814         if (buf[0] == '5')              /* aveserver is having problems */
815           {
816           result = m_errlog_defer(scanent, CUS callout_address,
817              string_sprintf("unable to scan file %s (Responded: %s).",
818                              eml_filename, buf));
819           break;
820           }
821         if (Ustrncmp(buf,"322",3) == 0)
822           {
823           uschar *p = Ustrchr(&buf[4], ' ');
824           *p = '\0';
825           malware_name = string_copy(&buf[4]);
826           }
827         }
828
829       if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
830         return m_errlog_defer(scanent, CUS callout_address, errstr);
831
832       /* read aveserver's greeting and see if it is ready (2xx greeting) */
833       buf[0] = 0;
834       recv_line(sock, buf, sizeof(buf), tmo);
835
836       if (buf[0] != '2')                /* aveserver is having problems */
837         return m_errlog_defer_3(scanent, CUS callout_address,
838           string_sprintf("unable to quit dialogue (Responded: %s).",
839                         ((buf[0] != 0) ? buf : US "nothing") ),
840           sock);
841
842       if (result == DEFER)
843         {
844         (void)close(sock);
845         return DEFER;
846         }
847       break;
848       } /* aveserver */
849
850     case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
851       {
852       int i, j, bread = 0;
853       uschar * file_name;
854       uschar av_buffer[1024];
855       static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
856                                       US"CONFIGURE\tTIMEOUT\t0\n",
857                                       US"CONFIGURE\tMAXARCH\t5\n",
858                                       US"CONFIGURE\tMIME\t1\n" };
859
860       malware_name = NULL;
861
862       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
863           scanner_name, scanner_options);
864       /* pass options */
865       memset(av_buffer, 0, sizeof(av_buffer));
866       for (i = 0; i != nelements(cmdopt); i++)
867         {
868
869         if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
870           return m_errlog_defer(scanent, CUS callout_address, errstr);
871
872         bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
873         if (bread > 0) av_buffer[bread]='\0';
874         if (bread < 0)
875           return m_errlog_defer_3(scanent, CUS callout_address,
876             string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
877             sock);
878         for (j = 0; j < bread; j++)
879           if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
880             av_buffer[j] ='@';
881         }
882
883       /* pass the mailfile to fsecure */
884       file_name = string_sprintf("SCAN\t%s\n", eml_filename);
885
886       if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
887         return m_errlog_defer(scanent, CUS callout_address, errstr);
888
889       /* set up match */
890       /* todo also SUSPICION\t */
891       if (!fsec_re)
892         fsec_re = m_pcre_compile(fsec_re_str, &errstr);
893
894       /* read report, linewise. Apply a timeout as the Fsecure daemon
895       sometimes wants an answer to "PING" but they won't tell us what */
896         {
897         uschar * p = av_buffer;
898         uschar * q;
899
900         for (;;)
901           {
902           errno = ETIMEDOUT;
903           i =  av_buffer+sizeof(av_buffer)-p;
904           if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
905             return m_errlog_defer_3(scanent, CUS callout_address,
906               string_sprintf("unable to read result (%s)", strerror(errno)),
907               sock);
908
909           for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
910             {
911             *q = '\0';
912
913             /* Really search for virus again? */
914             if (!malware_name)
915               /* try matcher on the line, grab substring */
916               malware_name = m_pcre_exec(fsec_re, p);
917
918             if (Ustrstr(p, "OK\tScan ok."))
919               goto fsec_found;
920             }
921
922           /* copy down the trailing partial line then read another chunk */
923           i =  av_buffer+sizeof(av_buffer)-p;
924           memmove(av_buffer, p, i);
925           p = av_buffer+i;
926           }
927         }
928
929       fsec_found:
930         break;
931       } /* fsecure */
932
933     case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
934       {
935       time_t t;
936       uschar tmpbuf[1024];
937       uschar * scanrequest;
938       int kav_rc;
939       unsigned long kav_reportlen;
940       int bread;
941       const pcre *kav_re;
942       uschar *p;
943
944       /* get current date and time, build scan request */
945       time(&t);
946       /* pdp note: before the eml_filename parameter, this scanned the
947       directory; not finding documentation, so we'll strip off the directory.
948       The side-effect is that the test framework scanning may end up in
949       scanning more than was requested, but for the normal interface, this is
950       fine. */
951
952       strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
953       scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
954       p = Ustrrchr(scanrequest, '/');
955       if (p)
956         *p = '\0';
957
958       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
959           scanner_name, scanner_options);
960
961       /* send scan request */
962       if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
963         return m_errlog_defer(scanent, CUS callout_address, errstr);
964
965       /* wait for result */
966       if (!recv_len(sock, tmpbuf, 2, tmo))
967         return m_errlog_defer_3(scanent, CUS callout_address,
968                             US"unable to read 2 bytes from socket.", sock);
969
970       /* get errorcode from one nibble */
971       kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
972       switch(kav_rc)
973       {
974       case 5: case 6: /* improper kavdaemon configuration */
975         return m_errlog_defer_3(scanent, CUS callout_address,
976                 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
977                 sock);
978       case 1:
979         return m_errlog_defer_3(scanent, CUS callout_address,
980                 US"reported 'scanning not completed' (code 1).", sock);
981       case 7:
982         return m_errlog_defer_3(scanent, CUS callout_address,
983                 US"reported 'kavdaemon damaged' (code 7).", sock);
984       }
985
986       /* code 8 is not handled, since it is ambiguous. It appears mostly on
987       bounces where part of a file has been cut off */
988
989       /* "virus found" return codes (2-4) */
990       if (kav_rc > 1 && kav_rc < 5)
991         {
992         int report_flag = 0;
993
994         /* setup default virus name */
995         malware_name = US"unknown";
996
997         report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
998
999         /* read the report, if available */
1000         if (report_flag == 1)
1001           {
1002           /* read report size */
1003           if (!recv_len(sock, &kav_reportlen, 4, tmo))
1004             return m_errlog_defer_3(scanent, CUS callout_address,
1005                   US"cannot read report size", sock);
1006
1007           /* it's possible that avp returns av_buffer[1] == 1 but the
1008           reportsize is 0 (!?) */
1009           if (kav_reportlen > 0)
1010             {
1011             /* set up match regex, depends on retcode */
1012             if (kav_rc == 3)
1013               {
1014               if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1015               kav_re = kav_re_sus;
1016               }
1017             else
1018               {
1019               if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1020               kav_re = kav_re_inf;
1021               }
1022
1023             /* read report, linewise.  Using size from stream to read amount of data
1024             from same stream is safe enough. */
1025             /* coverity[tainted_data] */
1026             while (kav_reportlen > 0)
1027               {
1028               if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1029                 break;
1030               kav_reportlen -= bread+1;
1031
1032               /* try matcher on the line, grab substring */
1033               if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1034                 break;
1035               }
1036             }
1037           }
1038         }
1039       else /* no virus found */
1040         malware_name = NULL;
1041
1042       break;
1043       }
1044
1045     case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1046       {
1047       const uschar *cmdline_scanner = scanner_options;
1048       const pcre *cmdline_trigger_re;
1049       const pcre *cmdline_regex_re;
1050       uschar * file_name;
1051       uschar * commandline;
1052       void (*eximsigchld)(int);
1053       void (*eximsigpipe)(int);
1054       FILE *scanner_out = NULL;
1055       int scanner_fd;
1056       FILE *scanner_record = NULL;
1057       uschar linebuffer[32767];
1058       int rcnt;
1059       int trigger = 0;
1060       uschar *p;
1061
1062       if (!cmdline_scanner)
1063         return m_errlog_defer(scanent, NULL, errstr);
1064
1065       /* find scanner output trigger */
1066       cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1067                                 "missing trigger specification", &errstr);
1068       if (!cmdline_trigger_re)
1069         return m_errlog_defer(scanent, NULL, errstr);
1070
1071       /* find scanner name regex */
1072       cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1073                           "missing virus name regex specification", &errstr);
1074       if (!cmdline_regex_re)
1075         return m_errlog_defer(scanent, NULL, errstr);
1076
1077       /* prepare scanner call; despite the naming, file_name holds a directory
1078       name which is documented as the value given to %s. */
1079
1080       file_name = string_copy(eml_filename);
1081       p = Ustrrchr(file_name, '/');
1082       if (p)
1083         *p = '\0';
1084       commandline = string_sprintf(CS cmdline_scanner, file_name);
1085
1086       /* redirect STDERR too */
1087       commandline = string_sprintf("%s 2>&1", commandline);
1088
1089       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1090               scanner_name, commandline);
1091
1092       /* store exims signal handlers */
1093       eximsigchld = signal(SIGCHLD,SIG_DFL);
1094       eximsigpipe = signal(SIGPIPE,SIG_DFL);
1095
1096       if (!(scanner_out = popen(CS commandline,"r")))
1097         {
1098         int err = errno;
1099         signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1100         return m_errlog_defer(scanent, NULL,
1101           string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1102         }
1103       scanner_fd = fileno(scanner_out);
1104
1105       file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
1106
1107       if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1108         {
1109         int err = errno;
1110         (void) pclose(scanner_out);
1111         signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1112         return m_errlog_defer(scanent, NULL, string_sprintf(
1113             "opening scanner output file (%s) failed: %s.",
1114             file_name, strerror(err)));
1115         }
1116
1117       /* look for trigger while recording output */
1118       while ((rcnt = recv_line(scanner_fd, linebuffer,
1119                       sizeof(linebuffer), tmo)))
1120         {
1121         if (rcnt < 0)
1122           {
1123           int err = errno;
1124           if (rcnt == -1)
1125             break;
1126           (void) pclose(scanner_out);
1127           signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1128           return m_errlog_defer(scanent, NULL, string_sprintf(
1129               "unable to read from scanner (%s): %s",
1130               commandline, strerror(err)));
1131           }
1132
1133         if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1134           {
1135           /* short write */
1136           (void) pclose(scanner_out);
1137           signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1138           return m_errlog_defer(scanent, NULL, string_sprintf(
1139             "short write on scanner output file (%s).", file_name));
1140           }
1141         putc('\n', scanner_record);
1142         /* try trigger match */
1143         if (  !trigger
1144            && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1145            )
1146           trigger = 1;
1147         }
1148
1149       (void)fclose(scanner_record);
1150       sep = pclose(scanner_out);
1151       signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1152       if (sep != 0)
1153           return m_errlog_defer(scanent, NULL, 
1154               sep == -1
1155               ? string_sprintf("running scanner failed: %s", strerror(sep))
1156               : string_sprintf("scanner returned error code: %d", sep));
1157
1158       if (trigger)
1159         {
1160         uschar * s;
1161         /* setup default virus name */
1162         malware_name = US"unknown";
1163
1164         /* re-open the scanner output file, look for name match */
1165         scanner_record = fopen(CS file_name, "rb");
1166         while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1167           {
1168           /* try match */
1169           if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1170             malware_name = s;
1171           }
1172         (void)fclose(scanner_record);
1173         }
1174       else /* no virus found */
1175         malware_name = NULL;
1176       break;
1177       } /* cmdline */
1178
1179     case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1180       {
1181       int bread = 0;
1182       uschar *p;
1183       uschar * file_name;
1184       uschar av_buffer[1024];
1185
1186       /* pass the scan directory to sophie */
1187       file_name = string_copy(eml_filename);
1188       if ((p = Ustrrchr(file_name, '/')))
1189         *p = '\0';
1190
1191       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1192           scanner_name, scanner_options);
1193
1194       if (  write(sock, file_name, Ustrlen(file_name)) < 0
1195          || write(sock, "\n", 1) != 1
1196          )
1197         return m_errlog_defer_3(scanent, CUS callout_address,
1198           string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1199           sock);
1200
1201       /* wait for result */
1202       memset(av_buffer, 0, sizeof(av_buffer));
1203       if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1204         return m_errlog_defer_3(scanent, CUS callout_address,
1205           string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1206           sock);
1207
1208       /* infected ? */
1209       if (av_buffer[0] == '1') {
1210         uschar * s = Ustrchr(av_buffer, '\n');
1211         if (s)
1212           *s = '\0';
1213         malware_name = string_copy(&av_buffer[2]);
1214       }
1215       else if (!strncmp(CS av_buffer, "-1", 2))
1216         return m_errlog_defer_3(scanent, CUS callout_address,
1217                 US"scanner reported error", sock);
1218       else /* all ok, no virus */
1219         malware_name = NULL;
1220
1221       break;
1222       }
1223
1224     case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1225       {
1226 /* This code was originally contributed by David Saez */
1227 /* There are three scanning methods available to us:
1228 *  (1) Use the SCAN command, pointing to a file in the filesystem
1229 *  (2) Use the STREAM command, send the data on a separate port
1230 *  (3) Use the zINSTREAM command, send the data inline
1231 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1232 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1233 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1234 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless
1235 * WITH_OLD_CLAMAV_STREAM is defined.
1236 * See Exim bug 926 for details.  */
1237
1238       uschar *p, *vname, *result_tag;
1239       int bread=0;
1240       uschar * file_name;
1241       uschar av_buffer[1024];
1242       uschar *hostname = US"";
1243       host_item connhost;
1244       uschar *clamav_fbuf;
1245       int clam_fd, result;
1246       off_t fsize;
1247       unsigned int fsize_uint;
1248       BOOL use_scan_command = FALSE;
1249       clamd_address * cv[MAX_CLAMD_SERVERS];
1250       int num_servers = 0;
1251 #ifdef WITH_OLD_CLAMAV_STREAM
1252       unsigned int port;
1253       uschar av_buffer2[1024];
1254       int sockData;
1255 #else
1256       uint32_t send_size, send_final_zeroblock;
1257 #endif
1258       blob cmd_str;
1259
1260       /*XXX if unixdomain socket, only one server supported. Needs fixing;
1261       there's no reason we should not mix local and remote servers */
1262
1263       if (*scanner_options == '/')
1264         {
1265         clamd_address * cd;
1266         const uschar * sublist;
1267         int subsep = ' ';
1268
1269         /* Local file; so we def want to use_scan_command and don't want to try
1270          * passing IP/port combinations */
1271         use_scan_command = TRUE;
1272         cd = (clamd_address *) store_get(sizeof(clamd_address));
1273
1274         /* extract socket-path part */
1275         sublist = scanner_options;
1276         cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1277
1278         /* parse options */
1279         if (clamd_option(cd, sublist, &subsep) != OK)
1280           return m_errlog_defer(scanent, NULL,
1281             string_sprintf("bad option '%s'", scanner_options));
1282         cv[0] = cd;
1283         }
1284       else
1285         {
1286         /* Go through the rest of the list of host/port and construct an array
1287          * of servers to try. The first one is the bit we just passed from
1288          * scanner_options so process that first and then scan the remainder of
1289          * the address buffer */
1290         do
1291           {
1292           clamd_address * cd;
1293           const uschar * sublist;
1294           int subsep = ' ';
1295           uschar * s;
1296
1297           /* The 'local' option means use the SCAN command over the network
1298            * socket (ie common file storage in use) */
1299           /*XXX we could accept this also as a local option? */
1300           if (strcmpic(scanner_options, US"local") == 0)
1301             {
1302             use_scan_command = TRUE;
1303             continue;
1304             }
1305
1306           cd = (clamd_address *) store_get(sizeof(clamd_address));
1307
1308           /* extract host and port part */
1309           sublist = scanner_options;
1310           if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1311             {
1312             (void) m_errlog_defer(scanent, NULL, 
1313                       string_sprintf("missing address: '%s'", scanner_options));
1314             continue;
1315             }
1316           if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1317             {
1318             (void) m_errlog_defer(scanent, NULL, 
1319                       string_sprintf("missing port: '%s'", scanner_options));
1320             continue;
1321             }
1322           cd->tcp_port = atoi(CS s);
1323
1324           /* parse options */
1325           /*XXX should these options be common over scanner types? */
1326           if (clamd_option(cd, sublist, &subsep) != OK)
1327             return m_errlog_defer(scanent, NULL,
1328               string_sprintf("bad option '%s'", scanner_options));
1329
1330           cv[num_servers++] = cd;
1331           if (num_servers >= MAX_CLAMD_SERVERS)
1332             {
1333             (void) m_errlog_defer(scanent, NULL,
1334                   US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1335                   "specified; only using the first " MAX_CLAMD_SERVERS_S );
1336             break;
1337             }
1338           } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1339                                         NULL, 0)));
1340
1341         /* check if we have at least one server */
1342         if (!num_servers)
1343           return m_errlog_defer(scanent, NULL,
1344             US"no useable server addresses in malware configuration option.");
1345         }
1346
1347       /* See the discussion of response formats below to see why we really
1348       don't like colons in filenames when passing filenames to ClamAV. */
1349       if (use_scan_command && Ustrchr(eml_filename, ':'))
1350         return m_errlog_defer(scanent, NULL,
1351           string_sprintf("local/SCAN mode incompatible with" \
1352             " : in path to email filename [%s]", eml_filename));
1353
1354       /* Set up the very first data we will be sending */
1355       if (!use_scan_command)
1356 #ifdef WITH_OLD_CLAMAV_STREAM
1357         { cmd_str.data = US"STREAM\n"; cmd_str.len = 7; }
1358 #else
1359         { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1360 #endif
1361       else
1362         {
1363         cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
1364         cmd_str.len = Ustrlen(cmd_str.data);
1365         }
1366
1367       /* We have some network servers specified */
1368       if (num_servers)
1369         {
1370         /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1371          * only supports AF_INET, but we should probably be looking to the
1372          * future and rewriting this to be protocol-independent anyway. */
1373
1374         while (num_servers > 0)
1375           {
1376           int i = random_number(num_servers);
1377           clamd_address * cd = cv[i];
1378
1379           DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1380                          cd->hostspec, cd->tcp_port);
1381
1382           /* Lookup the host. This is to ensure that we connect to the same IP
1383            * on both connections (as one host could resolve to multiple ips) */
1384           for (;;)
1385             {
1386             if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1387                                     &connhost, &errstr, &cmd_str)) >= 0)
1388               {
1389               /* Connection successfully established with a server */
1390               hostname = cd->hostspec;
1391               cmd_str.len = 0;
1392               break;
1393               }
1394             if (cd->retry <= 0) break;
1395             while (cd->retry > 0) cd->retry = sleep(cd->retry);
1396             }
1397           if (sock >= 0)
1398             break;
1399
1400           (void) m_errlog_defer(scanent, CUS callout_address, errstr);
1401
1402           /* Remove the server from the list. XXX We should free the memory */
1403           num_servers--;
1404           for (; i < num_servers; i++)
1405             cv[i] = cv[i+1];
1406           }
1407
1408         if (num_servers == 0)
1409           return m_errlog_defer(scanent, NULL, US"all servers failed");
1410         }
1411       else
1412         for (;;)
1413           {
1414           if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1415             {
1416             hostname = cv[0]->hostspec;
1417             break;
1418             }
1419           if (cv[0]->retry <= 0)
1420             return m_errlog_defer(scanent, CUS callout_address, errstr);
1421           while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1422           }
1423
1424       /* have socket in variable "sock"; command to use is semi-independent of
1425        * the socket protocol.  We use SCAN if is local (either Unix/local
1426        * domain socket, or explicitly told local) else we stream the data.
1427        * How we stream the data depends upon how we were built.  */
1428
1429       if (!use_scan_command)
1430         {
1431 #ifdef WITH_OLD_CLAMAV_STREAM
1432         /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1433          * that port on a second connection; then in the scan-method-neutral
1434          * part, read the response back on the original connection. */
1435
1436         DEBUG(D_acl) debug_printf_indent(
1437             "Malware scan: issuing %s old-style remote scan (PORT)\n",
1438             scanner_name);
1439
1440         /* Pass the string to ClamAV (7 = "STREAM\n"), if not already sent */
1441         if (cmd_str.len)
1442           if (m_sock_send(sock, cmd_str.data, cmd_str.len, &errstr) < 0)
1443             return m_errlog_defer(scanent, CUS callout_address, errstr);
1444
1445         memset(av_buffer2, 0, sizeof(av_buffer2));
1446         bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
1447
1448         if (bread < 0)
1449           return m_errlog_defer_3(scanent, CUS callout_address,
1450             string_sprintf("unable to read PORT from socket (%s)",
1451                 strerror(errno)),
1452             sock);
1453
1454         if (bread == sizeof(av_buffer2))
1455           return m_errlog_defer_3(scanent, CUS callout_address,
1456                   "buffer too small", sock);
1457
1458         if (!(*av_buffer2))
1459           return m_errlog_defer_3(scanent, CUS callout_address,
1460                   "ClamAV returned null", sock);
1461
1462         av_buffer2[bread] = '\0';
1463         if(sscanf(CS av_buffer2, "PORT %u\n", &port) != 1)
1464           return m_errlog_defer_3(scanent, CUS callout_address,
1465             string_sprintf("Expected port information from clamd, got '%s'",
1466               av_buffer2),
1467             sock);
1468
1469         sockData = m_tcpsocket(connhost.address, port, NULL, &errstr, NULL);
1470         if (sockData < 0)
1471           return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock);
1472
1473 # define CLOSE_SOCKDATA (void)close(sockData)
1474 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1475         /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1476         chunks, <n> a 4-byte number (network order), terminated by a zero-length
1477         chunk. */
1478
1479         DEBUG(D_acl) debug_printf_indent(
1480             "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1481             scanner_name);
1482
1483         /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1484         if (cmd_str.len)
1485           if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1486             return m_errlog_defer_3(scanent, CUS hostname,
1487               string_sprintf("unable to send zINSTREAM to socket (%s)",
1488                 strerror(errno)),
1489               sock);
1490
1491 # define CLOSE_SOCKDATA /**/
1492 #endif
1493
1494         /* calc file size */
1495         if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1496           {
1497           int err = errno;
1498           CLOSE_SOCKDATA;
1499           return m_errlog_defer_3(scanent, NULL,
1500             string_sprintf("can't open spool file %s: %s",
1501               eml_filename, strerror(err)),
1502             sock);
1503           }
1504         if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1505           {
1506           int err;
1507 b_seek:   err = errno;
1508           CLOSE_SOCKDATA; (void)close(clam_fd);
1509           return m_errlog_defer_3(scanent, NULL,
1510             string_sprintf("can't seek spool file %s: %s",
1511               eml_filename, strerror(err)),
1512             sock);
1513           }
1514         fsize_uint = (unsigned int) fsize;
1515         if ((off_t)fsize_uint != fsize)
1516           {
1517           CLOSE_SOCKDATA; (void)close(clam_fd);
1518           return m_errlog_defer_3(scanent, NULL,
1519             string_sprintf("seeking spool file %s, size overflow",
1520               eml_filename),
1521             sock);
1522           }
1523         if (lseek(clam_fd, 0, SEEK_SET) < 0)
1524           goto b_seek;
1525
1526         if (!(clamav_fbuf = US malloc(fsize_uint)))
1527           {
1528           CLOSE_SOCKDATA; (void)close(clam_fd);
1529           return m_errlog_defer_3(scanent, NULL,
1530             string_sprintf("unable to allocate memory %u for file (%s)",
1531               fsize_uint, eml_filename),
1532             sock);
1533           }
1534
1535         if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1536           {
1537           int err = errno;
1538           free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd);
1539           return m_errlog_defer_3(scanent, NULL,
1540             string_sprintf("can't read spool file %s: %s",
1541               eml_filename, strerror(err)),
1542             sock);
1543           }
1544         (void)close(clam_fd);
1545
1546         /* send file body to socket */
1547 #ifdef WITH_OLD_CLAMAV_STREAM
1548         if (send(sockData, clamav_fbuf, fsize_uint, 0) < 0)
1549           {
1550           free(clamav_fbuf); CLOSE_SOCKDATA;
1551           return m_errlog_defer_3(scanent, NULL,
1552             string_sprintf("unable to send file body to socket (%s:%u)",
1553               hostname, port),
1554             sock);
1555           }
1556 #else
1557         send_size = htonl(fsize_uint);
1558         send_final_zeroblock = 0;
1559         if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1560             (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1561             (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1562           {
1563           free(clamav_fbuf);
1564           return m_errlog_defer_3(scanent, NULL,
1565             string_sprintf("unable to send file body to socket (%s)", hostname),
1566             sock);
1567           }
1568 #endif
1569
1570         free(clamav_fbuf);
1571
1572         CLOSE_SOCKDATA;
1573 #undef CLOSE_SOCKDATA
1574         }
1575       else
1576         { /* use scan command */
1577         /* Send a SCAN command pointing to a filename; then in the then in the
1578          * scan-method-neutral part, read the response back */
1579
1580 /* ================================================================= */
1581
1582         /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1583         which dates to when ClamAV needed us to break apart the email into the
1584         MIME parts (eg, with the now deprecated demime condition coming first).
1585         Some time back, ClamAV gained the ability to deconstruct the emails, so
1586         doing this would actually have resulted in the mail attachments being
1587         scanned twice, in the broken out files and from the original .eml.
1588         Since ClamAV now handles emails (and has for quite some time) we can
1589         just use the email file itself. */
1590         /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
1591
1592         DEBUG(D_acl) debug_printf_indent(
1593             "Malware scan: issuing %s local-path scan [%s]\n",
1594             scanner_name, scanner_options);
1595
1596         if (cmd_str.len)
1597           if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1598             return m_errlog_defer_3(scanent, CUS callout_address,
1599               string_sprintf("unable to write to socket (%s)", strerror(errno)),
1600               sock);
1601
1602         /* Do not shut down the socket for writing; a user report noted that
1603          * clamd 0.70 does not react well to this. */
1604         }
1605       /* Commands have been sent, no matter which scan method or connection
1606        * type we're using; now just read the result, independent of method. */
1607
1608       /* Read the result */
1609       memset(av_buffer, 0, sizeof(av_buffer));
1610       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1611       (void)close(sock);
1612       sock = -1;
1613
1614       if (bread <= 0)
1615         return m_errlog_defer(scanent, CUS callout_address,
1616           string_sprintf("unable to read from socket (%s)",
1617           errno == 0 ? "EOF" : strerror(errno)));
1618
1619       if (bread == sizeof(av_buffer))
1620         return m_errlog_defer(scanent, CUS callout_address,
1621                 US"buffer too small");
1622       /* We're now assured of a NULL at the end of av_buffer */
1623
1624       /* Check the result. ClamAV returns one of two result formats.
1625       In the basic mode, the response is of the form:
1626         infected: -> "<filename>: <virusname> FOUND"
1627         not-infected: -> "<filename>: OK"
1628         error: -> "<filename>: <errcode> ERROR
1629       If the ExtendedDetectionInfo option has been turned on, then we get:
1630         "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1631       for the infected case.  Compare:
1632 /tmp/eicar.com: Eicar-Test-Signature FOUND
1633 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1634
1635       In the streaming case, clamd uses the filename "stream" which you should
1636       be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }.  (The
1637       client app will replace "stream" with the original filename before returning
1638       results to stdout, but the trace shows the data).
1639
1640       We will assume that the pathname passed to clamd from Exim does not contain
1641       a colon.  We will have whined loudly above if the eml_filename does (and we're
1642       passing a filename to clamd). */
1643
1644       if (!(*av_buffer))
1645         return m_errlog_defer(scanent, CUS callout_address,
1646                 US"ClamAV returned null");
1647
1648       /* strip newline at the end (won't be present for zINSTREAM)
1649       (also any trailing whitespace, which shouldn't exist, but we depend upon
1650       this below, so double-check) */
1651       p = av_buffer + Ustrlen(av_buffer) - 1;
1652       if (*p == '\n') *p = '\0';
1653
1654       DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1655
1656       while (isspace(*--p) && (p > av_buffer))
1657         *p = '\0';
1658       if (*p) ++p;
1659
1660       /* colon in returned output? */
1661       if(!(p = Ustrchr(av_buffer,':')))
1662         return m_errlog_defer(scanent, CUS callout_address, string_sprintf(
1663                   "ClamAV returned malformed result (missing colon): %s",
1664                   av_buffer));
1665
1666       /* strip filename */
1667       while (*p && isspace(*++p)) /**/;
1668       vname = p;
1669
1670       /* It would be bad to encounter a virus with "FOUND" in part of the name,
1671       but we should at least be resistant to it. */
1672       p = Ustrrchr(vname, ' ');
1673       result_tag = p ? p+1 : vname;
1674
1675       if (Ustrcmp(result_tag, "FOUND") == 0)
1676         {
1677         /* p should still be the whitespace before the result_tag */
1678         while (isspace(*p)) --p;
1679         *++p = '\0';
1680         /* Strip off the extended information too, which will be in parens
1681         after the virus name, with no intervening whitespace. */
1682         if (*--p == ')')
1683           {
1684           /* "(hash:size)", so previous '(' will do; if not found, we have
1685           a curious virus name, but not an error. */
1686           p = Ustrrchr(vname, '(');
1687           if (p)
1688             *p = '\0';
1689           }
1690         malware_name = string_copy(vname);
1691         DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1692
1693         }
1694       else if (Ustrcmp(result_tag, "ERROR") == 0)
1695         return m_errlog_defer(scanent, CUS callout_address,
1696           string_sprintf("ClamAV returned: %s", av_buffer));
1697
1698       else if (Ustrcmp(result_tag, "OK") == 0)
1699         {
1700         /* Everything should be OK */
1701         malware_name = NULL;
1702         DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1703
1704         }
1705       else
1706         return m_errlog_defer(scanent, CUS callout_address,
1707           string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1708
1709       break;
1710       } /* clamd */
1711
1712     case M_SOCK: /* "sock" scanner type ------------------------------------- */
1713     /* This code was derived by Martin Poole from the clamd code contributed
1714        by David Saez and the cmdline code
1715     */
1716       {
1717       int bread;
1718       uschar * commandline;
1719       uschar av_buffer[1024];
1720       uschar * linebuffer;
1721       uschar * sockline_scanner;
1722       uschar sockline_scanner_default[] = "%s\n";
1723       const pcre *sockline_trig_re;
1724       const pcre *sockline_name_re;
1725
1726       /* find scanner command line */
1727       if (  (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1728                                           NULL, 0))
1729          && *sockline_scanner
1730          )
1731       { /* check for no expansions apart from one %s */
1732         uschar * s = Ustrchr(sockline_scanner, '%');
1733         if (s++)
1734           if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1735             return m_errlog_defer_3(scanent, NULL,
1736                                   US"unsafe sock scanner call spec", sock);
1737       }
1738       else
1739         sockline_scanner = sockline_scanner_default;
1740       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1741         string_printing(sockline_scanner));
1742
1743       /* find scanner output trigger */
1744       sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1745                                 "missing trigger specification", &errstr);
1746       if (!sockline_trig_re)
1747         return m_errlog_defer_3(scanent, NULL, errstr, sock);
1748
1749       /* find virus name regex */
1750       sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1751                           "missing virus name regex specification", &errstr);
1752       if (!sockline_name_re)
1753         return m_errlog_defer_3(scanent, NULL, errstr, sock);
1754
1755       /* prepare scanner call - security depends on expansions check above */
1756       commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1757       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1758         string_printing(commandline));
1759
1760       /* Pass the command string to the socket */
1761       if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1762         return m_errlog_defer(scanent, CUS callout_address, errstr);
1763
1764       /* Read the result */
1765       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1766
1767       if (bread <= 0)
1768         return m_errlog_defer_3(scanent, CUS callout_address,
1769           string_sprintf("unable to read from socket (%s)", strerror(errno)),
1770           sock);
1771
1772       if (bread == sizeof(av_buffer))
1773         return m_errlog_defer_3(scanent, CUS callout_address,
1774                 US"buffer too small", sock);
1775       av_buffer[bread] = '\0';
1776       linebuffer = string_copy(av_buffer);
1777       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1778         string_printing(linebuffer));
1779
1780       /* try trigger match */
1781       if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1782         {
1783         if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1784           malware_name = US "unknown";
1785         DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1786           string_printing(malware_name));
1787         }
1788       else /* no virus found */
1789         malware_name = NULL;
1790       break;
1791       }
1792
1793     case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1794       {
1795       char *mksd_options_end;
1796       int mksd_maxproc = 1;  /* default, if no option supplied */
1797       int retval;
1798
1799       if (scanner_options)
1800         {
1801         mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1802         if (  *scanner_options == '\0'
1803            || *mksd_options_end != '\0'
1804            || mksd_maxproc < 1
1805            || mksd_maxproc > 32
1806            )
1807           return m_errlog_defer(scanent, CUS callout_address,
1808             string_sprintf("invalid option '%s'", scanner_options));
1809         }
1810
1811       if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1812         return m_errlog_defer(scanent, CUS callout_address, errstr);
1813
1814       malware_name = NULL;
1815
1816       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1817
1818       if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1819         {
1820         close (sock);
1821         return retval;
1822         }
1823       break;
1824       }
1825
1826     case M_AVAST: /* "avast" scanner type ----------------------------------- */
1827       {
1828       int ovector[1*3];
1829       uschar buf[1024];
1830       uschar * scanrequest;
1831       enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1832       int nread;
1833
1834       /* According to Martin Tuma @avast the protocol uses "escaped
1835       whitespace", that is, every embedded whitespace is backslash
1836       escaped, as well as backslash is protected by backslash.
1837       The returned lines contain the name of the scanned file, a tab
1838       and the [ ] marker.
1839       [+] - not infected
1840       [L] - infected
1841       [E] - some error occured
1842       Such marker follows the first non-escaped TAB.  */
1843       if (  (  !ava_re_clean
1844             && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1845          || (  !ava_re_virus
1846             && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1847          )
1848         return malware_errlog_defer(errstr);
1849
1850       /* wait for result */
1851       for (avast_stage = AVA_HELO;
1852            (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1853           )
1854         {
1855         int slen = Ustrlen(buf);
1856         if (slen >= 1)
1857           {
1858           DEBUG(D_acl) debug_printf_indent("got from avast: %s\n", buf);
1859           switch (avast_stage)
1860             {
1861             case AVA_HELO:
1862               if (Ustrncmp(buf, "220", 3) != 0)
1863                 goto endloop;                   /* require a 220 */
1864               goto sendreq;
1865
1866             case AVA_OPT:
1867               if (Ustrncmp(buf, "210", 3) == 0)
1868                 break;                          /* ignore 210 responses */
1869               if (Ustrncmp(buf, "200", 3) != 0)
1870                 goto endloop;                   /* require a 200 */
1871
1872             sendreq:
1873               {
1874               int len;
1875               /* Check for another option to send. Newline-terminate it. */
1876               if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1877                                 NULL, 0)))
1878                 {
1879                 scanrequest = string_sprintf("%s\n", scanrequest);
1880                 avast_stage = AVA_OPT;          /* just sent option */
1881                 }
1882               else
1883                 {
1884                 scanrequest = string_sprintf("SCAN %s\n", eml_dir);
1885                 avast_stage = AVA_RSP;          /* just sent command */
1886                 }
1887
1888               /* send config-cmd or scan-request to socket */
1889               len = Ustrlen(scanrequest);
1890               if (send(sock, scanrequest, len, 0) < 0)
1891                 {
1892                 scanrequest[len-1] = '\0';
1893                 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
1894                       "unable to send request '%s' to socket (%s): %s",
1895                       scanrequest, scanner_options, strerror(errno)), sock);
1896                 }
1897               break;
1898               }
1899
1900             case AVA_RSP:
1901               if (Ustrncmp(buf, "210", 3) == 0)
1902                 break;  /* ignore the "210 SCAN DATA" message */
1903
1904               if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
1905                     0, 0, ovector, nelements(ovector)) > 0)
1906                 break;
1907
1908               if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
1909                 { /* remove backslash in front of [whitespace|backslash] */
1910                 uschar * p, * p0;
1911                 for (p = malware_name; *p; ++p)
1912                   if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
1913                     for (p0 = p; *p0; ++p0) *p0 = p0[1];
1914
1915                 avast_stage = AVA_DONE;
1916                 goto endloop;
1917                 }
1918
1919               if (Ustrncmp(buf, "200 SCAN OK", 11) == 0)
1920                 { /* we're done finally */
1921                 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1922                   return m_errlog_defer_3(scanent, CUS callout_address,
1923                           string_sprintf(
1924                               "unable to send quit request to socket (%s): %s",
1925                               scanner_options, strerror(errno)),
1926                               sock);
1927                 malware_name = NULL;
1928                 avast_stage = AVA_DONE;
1929                 goto endloop;
1930                 }
1931
1932               /* here for any unexpected response from the scanner */
1933               goto endloop;
1934
1935             case AVA_DONE:      log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
1936                             __FILE__, __LINE__, __FUNCTION__);
1937             }
1938           }
1939         }
1940       endloop:
1941
1942       switch(avast_stage)
1943         {
1944         case AVA_HELO:
1945         case AVA_OPT:
1946         case AVA_RSP:   return m_errlog_defer_3(scanent, CUS callout_address,
1947                             nread >= 0
1948                             ? string_sprintf(
1949                                 "invalid response from scanner: '%s'", buf)
1950                             : nread == -1
1951                             ? US"EOF from scanner"
1952                             : US"timeout from scanner",
1953                           sock);
1954         default:        break;
1955         }
1956       break;
1957       }
1958
1959     case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
1960       {
1961       int bread;
1962       uschar * e;
1963       uschar * linebuffer;
1964       uschar * scanrequest;
1965       uschar av_buffer[1024];
1966
1967       if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
1968         || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
1969         return malware_errlog_defer(errstr);
1970
1971       scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
1972       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
1973         scanner_name, scanrequest);
1974
1975       if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
1976         return m_errlog_defer(scanent, CUS callout_address, errstr);
1977
1978       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1979
1980       if (bread <= 0)
1981         return m_errlog_defer_3(scanent, CUS callout_address,
1982           string_sprintf("unable to read from socket (%s)", strerror(errno)),
1983           sock);
1984
1985       if (bread == sizeof(av_buffer))
1986         return m_errlog_defer_3(scanent, CUS callout_address,
1987           US"buffer too small", sock);
1988
1989       av_buffer[bread] = '\0';
1990       linebuffer = string_copy(av_buffer);
1991
1992       m_sock_send(sock, US"QUIT\n", 5, 0);
1993
1994       if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
1995         return m_errlog_defer_3(scanent, CUS callout_address,
1996           string_sprintf("scanner reported error (%s)", e), sock);
1997
1998       if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
1999         malware_name = NULL;
2000
2001       break;
2002       }  /* f-prot6d */
2003   }     /* scanner type switch */
2004
2005   if (sock >= 0)
2006     (void) close (sock);
2007   malware_ok = TRUE;                    /* set "been here, done that" marker */
2008   }
2009
2010 /* match virus name against pattern (caseless ------->----------v) */
2011 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
2012   {
2013   DEBUG(D_acl) debug_printf_indent(
2014       "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2015   return OK;
2016   }
2017 else
2018   return FAIL;
2019 }
2020
2021
2022 /*************************************************
2023 *          Scan an email for malware             *
2024 *************************************************/
2025
2026 /* This is the normal interface for scanning an email, which doesn't need a
2027 filename; it's a wrapper around the malware_file function.
2028
2029 Arguments:
2030   malware_re  match condition for "malware="
2031   timeout     if nonzero, timeout in seconds
2032
2033 Returns:      Exim message processing code (OK, FAIL, DEFER, ...)
2034               where true means malware was found (condition applies)
2035 */
2036 int
2037 malware(const uschar * malware_re, int timeout)
2038 {
2039 int ret = malware_internal(malware_re, NULL, timeout);
2040
2041 if (ret == DEFER) av_failed = TRUE;
2042 return ret;
2043 }
2044
2045
2046 /*************************************************
2047 *          Scan a file for malware               *
2048 *************************************************/
2049
2050 /* This is a test wrapper for scanning an email, which is not used in
2051 normal processing.  Scan any file, using the Exim scanning interface.
2052 This function tampers with various global variables so is unsafe to use
2053 in any other context.
2054
2055 Arguments:
2056   eml_filename  a file holding the message to be scanned
2057
2058 Returns:        Exim message processing code (OK, FAIL, DEFER, ...)
2059                 where true means malware was found (condition applies)
2060 */
2061 int
2062 malware_in_file(uschar *eml_filename)
2063 {
2064 uschar message_id_buf[64];
2065 int ret;
2066
2067 /* spool_mbox() assumes various parameters exist, when creating
2068 the relevant directory and the email within */
2069
2070 (void) string_format(message_id_buf, sizeof(message_id_buf),
2071     "dummy-%d", vaguely_random_number(INT_MAX));
2072 message_id = message_id_buf;
2073 sender_address = US"malware-sender@example.net";
2074 return_path = US"";
2075 recipients_list = NULL;
2076 receive_add_recipient(US"malware-victim@example.net", -1);
2077 enable_dollar_recipients = TRUE;
2078
2079 ret = malware_internal(US"*", eml_filename, 0);
2080
2081 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2082 spool_mbox_ok = 1;
2083
2084 /* don't set no_mbox_unspool; at present, there's no way for it to become
2085 set, but if that changes, then it should apply to these tests too */
2086
2087 unspool_mbox();
2088
2089 /* silence static analysis tools */
2090 message_id = NULL;
2091
2092 return ret;
2093 }
2094
2095
2096 void
2097 malware_init(void)
2098 {
2099 if (!malware_default_re)
2100   malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2101 if (!drweb_re)
2102   drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2103 if (!fsec_re)
2104   fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2105 if (!kav_re_sus)
2106   kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2107 if (!kav_re_inf)
2108   kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2109 if (!ava_re_clean)
2110   ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2111 if (!ava_re_virus)
2112   ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2113 if (!fprot6d_re_error)
2114   fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2115 if (!fprot6d_re_virus)
2116   fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2117 }
2118
2119 #endif /*WITH_CONTENT_SCAN*/
2120 /*
2121  * vi: aw ai sw=2
2122  */