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