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