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