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