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