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