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