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