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