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