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