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