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