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