1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
7 * Copyright (c) The Exim Maintainers 2016
10 /* Code for calling virus (malware) scanners. Called from acl.c. */
13 #ifdef WITH_CONTENT_SCAN
15 typedef enum {M_FPROTD
, M_DRWEB
, M_AVES
, M_FSEC
, M_KAVD
, M_CMDL
,
16 M_SOPHIE
, M_CLAMD
, M_SOCK
, M_MKSD
, M_AVAST
, M_FPROT6D
} scanner_t
;
17 typedef enum {MC_NONE
, MC_TCP
, MC_UNIX
, MC_STRM
} contype_t
;
22 const uschar
* options_default
;
26 { M_FPROTD
, US
"f-protd", US
"localhost 10200-10204", MC_TCP
},
27 { M_DRWEB
, US
"drweb", US
"/usr/local/drweb/run/drwebd.sock", MC_STRM
},
28 { M_AVES
, US
"aveserver", US
"/var/run/aveserver", MC_UNIX
},
29 { M_FSEC
, US
"fsecure", US
"/var/run/.fsav", MC_UNIX
},
30 { M_KAVD
, US
"kavdaemon", US
"/var/run/AvpCtl", MC_UNIX
},
31 { M_CMDL
, US
"cmdline", NULL
, MC_NONE
},
32 { M_SOPHIE
, US
"sophie", US
"/var/run/sophie", MC_UNIX
},
33 { M_CLAMD
, US
"clamd", US
"/tmp/clamd", MC_NONE
},
34 { M_SOCK
, US
"sock", US
"/tmp/malware.sock", MC_STRM
},
35 { M_MKSD
, US
"mksd", NULL
, MC_NONE
},
36 { M_AVAST
, US
"avast", US
"/var/run/avast/scan.sock", MC_STRM
},
37 { M_FPROT6D
, US
"f-prot6d", US
"localhost 10200", MC_TCP
},
38 { -1, NULL
, NULL
, MC_NONE
} /* end-marker */
41 /* The maximum number of clamd servers that are supported in the configuration */
42 #define MAX_CLAMD_SERVERS 32
43 #define MAX_CLAMD_SERVERS_S "32"
45 typedef struct clamd_address
{
52 # define nelements(arr) (sizeof(arr) / sizeof(arr[0]))
56 #define MALWARE_TIMEOUT 120 /* default timeout, seconds */
59 #define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */
60 #define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */
61 #define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */
63 #define DERR_READ_ERR (1<<0) /* read error */
64 #define DERR_NOMEMORY (1<<2) /* no memory */
65 #define DERR_TIMEOUT (1<<9) /* scan timeout has run out */
66 #define DERR_BAD_CALL (1<<15) /* wrong command */
69 static const uschar
* malware_regex_default
= US
".+";
70 static const pcre
* malware_default_re
= NULL
;
72 static const uschar
* drweb_re_str
= US
"infected\\swith\\s*(.+?)$";
73 static const pcre
* drweb_re
= NULL
;
75 static const uschar
* fsec_re_str
= US
"\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$";
76 static const pcre
* fsec_re
= NULL
;
78 static const uschar
* kav_re_sus_str
= US
"suspicion:\\s*(.+?)\\s*$";
79 static const uschar
* kav_re_inf_str
= US
"infected:\\s*(.+?)\\s*$";
80 static const pcre
* kav_re_sus
= NULL
;
81 static const pcre
* kav_re_inf
= NULL
;
83 static const uschar
* ava_re_clean_str
= US
"(?!\\\\)\\t\\[\\+\\]";
84 static const uschar
* ava_re_virus_str
= US
"(?!\\\\)\\t\\[L\\]\\d\\.\\d\\t\\d\\s(.*)";
85 static const pcre
* ava_re_clean
= NULL
;
86 static const pcre
* ava_re_virus
= NULL
;
88 static const uschar
* fprot6d_re_error_str
= US
"^\\d+\\s<(.+?)>$";
89 static const uschar
* fprot6d_re_virus_str
= US
"^\\d+\\s<infected:\\s+(.+?)>\\s+.+$";
90 static const pcre
* fprot6d_re_error
= NULL
;
91 static const pcre
* fprot6d_re_virus
= NULL
;
95 /******************************************************************************/
97 /* Routine to check whether a system is big- or little-endian.
98 Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
99 Needed for proper kavdaemon implementation. Sigh. */
100 #define BIG_MY_ENDIAN 0
101 #define LITTLE_MY_ENDIAN 1
102 static int test_byte_order(void);
106 short int word
= 0x0001;
107 char *byte
= (char *) &word
;
108 return(byte
[0] ? LITTLE_MY_ENDIAN
: BIG_MY_ENDIAN
);
111 BOOL malware_ok
= FALSE
;
113 /* Gross hacks for the -bmalware option; perhaps we should just create
114 the scan directory normally for that case, but look into rigging up the
115 needed header variables if not already set on the command-line? */
116 extern int spool_mbox_ok
;
117 extern uschar spooled_message_id
[MESSAGE_ID_LENGTH
+1];
122 malware_errlog_defer(const uschar
* str
)
124 log_write(0, LOG_MAIN
|LOG_PANIC
, "malware acl condition: %s", str
);
129 m_errlog_defer(struct scan
* scanent
, const uschar
* hostport
,
132 return malware_errlog_defer(string_sprintf("%s %s : %s",
133 scanent
->name
, hostport
? hostport
: CUS
"", str
));
136 m_errlog_defer_3(struct scan
* scanent
, const uschar
* hostport
,
137 const uschar
* str
, int fd_to_close
)
139 (void) close(fd_to_close
);
140 return m_errlog_defer(scanent
, hostport
, str
);
143 /*************************************************/
145 /* Only used by the Clamav code, which is working from a list of servers and
146 uses the returned in_addr to get a second connection to the same system.
149 m_tcpsocket(const uschar
* hostname
, unsigned int port
,
150 host_item
* host
, uschar
** errstr
)
152 return ip_connectedsocket(SOCK_STREAM
, hostname
, port
, port
, 5, host
, errstr
);
156 m_sock_send(int sock
, uschar
* buf
, int cnt
, uschar
** errstr
)
158 if (send(sock
, buf
, cnt
, 0) < 0)
162 *errstr
= string_sprintf("unable to send to socket (%s): %s",
170 m_pcre_compile(const uschar
* re
, uschar
** errstr
)
172 const uschar
* rerror
;
176 cre
= pcre_compile(CS re
, PCRE_COPT
, (const char **)&rerror
, &roffset
, NULL
);
178 *errstr
= string_sprintf("regular expression error in '%s': %s at offset %d",
179 re
, rerror
, roffset
);
184 m_pcre_exec(const pcre
* cre
, uschar
* text
)
187 int i
= pcre_exec(cre
, NULL
, CS text
, Ustrlen(text
), 0, 0,
188 ovector
, nelements(ovector
));
189 uschar
* substr
= NULL
;
190 if (i
>= 2) /* Got it */
191 pcre_get_substring(CS text
, ovector
, i
, 1, (const char **) &substr
);
196 m_pcre_nextinlist(const uschar
** list
, int * sep
,
197 char * listerr
, uschar
** errstr
)
199 const uschar
* list_ele
;
200 const pcre
* cre
= NULL
;
202 if (!(list_ele
= string_nextinlist(list
, sep
, NULL
, 0)))
203 *errstr
= US listerr
;
205 cre
= m_pcre_compile(CUS list_ele
, errstr
);
210 Simple though inefficient wrapper for reading a line. Drop CRs and the
211 trailing newline. Can return early on buffer full. Null-terminate.
212 Apply initial timeout if no data ready.
214 Return: number of chars - zero for an empty line
216 -2 on timeout or error
219 recv_line(int fd
, uschar
* buffer
, int bsize
, int tmo
)
225 if (!fd_ready(fd
, tmo
-time(NULL
)))
228 /*XXX tmo handling assumes we always get a whole line */
231 while ((rcv
= read(fd
, p
, 1)) > 0)
234 if (p
-buffer
> bsize
-2) break;
235 if (*p
== '\n') break;
240 DEBUG(D_acl
) debug_printf_indent("Malware scan: read %s (%s)\n",
241 rcv
==0 ? "EOF" : "error", strerror(errno
));
242 return rcv
==0 ? -1 : -2;
246 DEBUG(D_acl
) debug_printf_indent("Malware scan: read '%s'\n", buffer
);
250 /* return TRUE iff size as requested */
252 recv_len(int sock
, void * buf
, int size
, int tmo
)
254 return fd_ready(sock
, tmo
-time(NULL
))
255 ? recv(sock
, buf
, size
, 0) == size
261 /* ============= private routines for the "mksd" scanner type ============== */
266 mksd_writev (int sock
, struct iovec
* iov
, int iovcnt
)
273 i
= writev (sock
, iov
, iovcnt
);
274 while (i
< 0 && errno
== EINTR
);
277 (void) malware_errlog_defer(
278 US
"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
281 for (;;) /* check for short write */
282 if (i
>= iov
->iov_len
)
292 iov
->iov_base
= CS iov
->iov_base
+ i
;
299 mksd_read_lines (int sock
, uschar
*av_buffer
, int av_buffer_size
, int tmo
)
306 i
= ip_recv(sock
, av_buffer
+offset
, av_buffer_size
-offset
, tmo
-time(NULL
));
309 (void) malware_errlog_defer(US
"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
314 /* offset == av_buffer_size -> buffer full */
315 if (offset
== av_buffer_size
)
317 (void) malware_errlog_defer(US
"malformed reply received from mksd");
320 } while (av_buffer
[offset
-1] != '\n');
322 av_buffer
[offset
] = '\0';
327 mksd_parse_line(struct scan
* scanent
, char * line
)
338 if ((p
= strchr (line
, '\n')) != NULL
)
340 return m_errlog_defer(scanent
, NULL
,
341 string_sprintf("scanner failed: %s", line
));
344 if ((p
= strchr (line
, '\n')) != NULL
)
349 && (p
= strchr(line
+4, ' ')) != NULL
354 malware_name
= string_copy(US line
+4);
358 return m_errlog_defer(scanent
, NULL
,
359 string_sprintf("malformed reply received: %s", line
));
364 mksd_scan_packed(struct scan
* scanent
, int sock
, const uschar
* scan_filename
,
368 const char *cmd
= "MSQ\n";
369 uschar av_buffer
[1024];
371 iov
[0].iov_base
= (void *) cmd
;
373 iov
[1].iov_base
= (void *) scan_filename
;
374 iov
[1].iov_len
= Ustrlen(scan_filename
);
375 iov
[2].iov_base
= (void *) (cmd
+ 3);
378 if (mksd_writev (sock
, iov
, 3) < 0)
381 if (mksd_read_lines (sock
, av_buffer
, sizeof (av_buffer
), tmo
) < 0)
384 return mksd_parse_line (scanent
, CS av_buffer
);
389 clamd_option(clamd_address
* cd
, const uschar
* optstr
, int * subsep
)
394 while ((s
= string_nextinlist(&optstr
, subsep
, NULL
, 0)))
395 if (Ustrncmp(s
, "retry=", 6) == 0)
397 int sec
= readconf_readtime((s
+= 6), '\0', FALSE
);
407 /*************************************************
408 * Scan content for malware *
409 *************************************************/
411 /* This is an internal interface for scanning an email; the normal interface
412 is via malware(), or there's malware_in_file() used for testing/debugging.
415 malware_re match condition for "malware="
416 scan_filename the file holding the email to be scanned, if we're faking
417 this up for the -bmalware test, else NULL
418 timeout if nonzero, non-default timeoutl
420 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
421 where true means malware was found (condition applies)
424 malware_internal(const uschar
* malware_re
, const uschar
* scan_filename
,
428 const uschar
*av_scanner_work
= av_scanner
;
429 uschar
*scanner_name
;
430 unsigned long mbox_size
;
434 struct scan
* scanent
;
435 const uschar
* scanner_options
;
438 uschar
* eml_filename
, * eml_dir
;
441 return FAIL
; /* empty means "don't match anything" */
443 /* Ensure the eml mbox file is spooled up */
445 if (!(mbox_file
= spool_mbox(&mbox_size
, scan_filename
, &eml_filename
)))
446 return malware_errlog_defer(US
"error while creating mbox spool file");
448 /* None of our current scanners need the mbox file as a stream (they use
449 the name), so we can close it right away. Get the directory too. */
451 (void) fclose(mbox_file
);
452 eml_dir
= string_copyn(eml_filename
, Ustrrchr(eml_filename
, '/') - eml_filename
);
454 /* parse 1st option */
455 if (strcmpic(malware_re
, US
"false") == 0 || Ustrcmp(malware_re
,"0") == 0)
456 return FAIL
; /* explicitly no matching */
458 /* special cases (match anything except empty) */
459 if ( strcmpic(malware_re
,US
"true") == 0
460 || Ustrcmp(malware_re
,"*") == 0
461 || Ustrcmp(malware_re
,"1") == 0
464 if ( !malware_default_re
465 && !(malware_default_re
= m_pcre_compile(malware_regex_default
, &errstr
)))
466 return malware_errlog_defer(errstr
);
467 malware_re
= malware_regex_default
;
468 re
= malware_default_re
;
471 /* compile the regex, see if it works */
472 else if (!(re
= m_pcre_compile(malware_re
, &errstr
)))
473 return malware_errlog_defer(errstr
);
475 /* Reset sep that is set by previous string_nextinlist() call */
478 /* if av_scanner starts with a dollar, expand it first */
479 if (*av_scanner
== '$')
481 if (!(av_scanner_work
= expand_string(av_scanner
)))
482 return malware_errlog_defer(
483 string_sprintf("av_scanner starts with $, but expansion failed: %s",
484 expand_string_message
));
487 debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work
);
488 /* disable result caching in this case */
493 /* Do not scan twice (unless av_scanner is dynamic). */
496 /* find the scanner type from the av_scanner option */
497 if (!(scanner_name
= string_nextinlist(&av_scanner_work
, &sep
, NULL
, 0)))
498 return malware_errlog_defer(US
"av_scanner configuration variable is empty");
499 if (!timeout
) timeout
= MALWARE_TIMEOUT
;
500 tmo
= time(NULL
) + timeout
;
502 for (scanent
= m_scans
; ; scanent
++)
505 return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
507 if (strcmpic(scanner_name
, US scanent
->name
) != 0)
509 if (!(scanner_options
= string_nextinlist(&av_scanner_work
, &sep
, NULL
, 0)))
510 scanner_options
= scanent
->options_default
;
511 if (scanent
->conn
== MC_NONE
)
513 switch(scanent
->conn
)
515 case MC_TCP
: sock
= ip_tcpsocket(scanner_options
, &errstr
, 5); break;
516 case MC_UNIX
: sock
= ip_unixsocket(scanner_options
, &errstr
); break;
517 case MC_STRM
: sock
= ip_streamsocket(scanner_options
, &errstr
, 5); break;
518 default: /* compiler quietening */ break;
521 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
524 DEBUG(D_acl
) debug_printf_indent("Malware scan: %s tmo %s\n", scanner_name
, readconf_printtime(timeout
));
526 switch (scanent
->scancode
)
528 case M_FPROTD
: /* "f-protd" scanner type -------------------------------- */
530 uschar
*fp_scan_option
;
531 unsigned int detected
=0, par_count
=0;
532 uschar
* scanrequest
;
533 uschar buf
[32768], *strhelper
, *strhelper2
;
534 uschar
* malware_name_internal
= NULL
;
537 scanrequest
= string_sprintf("GET %s", eml_filename
);
539 while ((fp_scan_option
= string_nextinlist(&av_scanner_work
, &sep
,
542 scanrequest
= string_sprintf("%s%s%s", scanrequest
,
543 par_count
? "%20" : "?", fp_scan_option
);
546 scanrequest
= string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest
);
547 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s: %s\n",
548 scanner_name
, scanrequest
);
550 /* send scan request */
551 if (m_sock_send(sock
, scanrequest
, Ustrlen(scanrequest
)+1, &errstr
) < 0)
552 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
554 while ((len
= recv_line(sock
, buf
, sizeof(buf
), tmo
)) >= 0)
557 if (Ustrstr(buf
, US
"<detected type=\"") != NULL
)
559 else if (detected
&& (strhelper
= Ustrstr(buf
, US
"<name>")))
561 if ((strhelper2
= Ustrstr(buf
, US
"</name>")) != NULL
)
564 malware_name_internal
= string_copy(strhelper
+6);
567 else if (Ustrstr(buf
, US
"<summary code=\""))
569 malware_name
= Ustrstr(buf
, US
"<summary code=\"11\">")
570 ? malware_name_internal
: NULL
;
582 case M_DRWEB
: /* "drweb" scanner type ----------------------------------- */
583 /* v0.1 - added support for tcp sockets */
584 /* v0.0 - initial release -- support for unix sockets */
588 unsigned int fsize_uint
;
589 uschar
* tmpbuf
, *drweb_fbuf
;
590 int drweb_rc
, drweb_cmd
, drweb_flags
= 0x0000, drweb_fd
,
591 drweb_vnum
, drweb_slen
, drweb_fin
= 0x0000;
593 /* prepare variables */
594 drweb_cmd
= htonl(DRWEBD_SCAN_CMD
);
595 drweb_flags
= htonl(DRWEBD_RETURN_VIRUSES
| DRWEBD_IS_MAIL
);
597 if (*scanner_options
!= '/')
600 if ((drweb_fd
= open(CCS eml_filename
, O_RDONLY
)) == -1)
601 return m_errlog_defer_3(scanent
, NULL
,
602 string_sprintf("can't open spool file %s: %s",
603 eml_filename
, strerror(errno
)),
606 if ((fsize
= lseek(drweb_fd
, 0, SEEK_END
)) == -1)
609 badseek
: err
= errno
;
610 (void)close(drweb_fd
);
611 return m_errlog_defer_3(scanent
, NULL
,
612 string_sprintf("can't seek spool file %s: %s",
613 eml_filename
, strerror(err
)),
616 fsize_uint
= (unsigned int) fsize
;
617 if ((off_t
)fsize_uint
!= fsize
)
619 (void)close(drweb_fd
);
620 return m_errlog_defer_3(scanent
, NULL
,
621 string_sprintf("seeking spool file %s, size overflow",
625 drweb_slen
= htonl(fsize
);
626 if (lseek(drweb_fd
, 0, SEEK_SET
) < 0)
629 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
630 scanner_name
, scanner_options
);
632 /* send scan request */
633 if ((send(sock
, &drweb_cmd
, sizeof(drweb_cmd
), 0) < 0) ||
634 (send(sock
, &drweb_flags
, sizeof(drweb_flags
), 0) < 0) ||
635 (send(sock
, &drweb_fin
, sizeof(drweb_fin
), 0) < 0) ||
636 (send(sock
, &drweb_slen
, sizeof(drweb_slen
), 0) < 0))
638 (void)close(drweb_fd
);
639 return m_errlog_defer_3(scanent
, CUS callout_address
, string_sprintf(
640 "unable to send commands to socket (%s)", scanner_options
),
644 if (!(drweb_fbuf
= US
malloc(fsize_uint
)))
646 (void)close(drweb_fd
);
647 return m_errlog_defer_3(scanent
, NULL
,
648 string_sprintf("unable to allocate memory %u for file (%s)",
649 fsize_uint
, eml_filename
),
653 if ((result
= read (drweb_fd
, drweb_fbuf
, fsize
)) == -1)
656 (void)close(drweb_fd
);
658 return m_errlog_defer_3(scanent
, NULL
,
659 string_sprintf("can't read spool file %s: %s",
660 eml_filename
, strerror(err
)),
663 (void)close(drweb_fd
);
665 /* send file body to socket */
666 if (send(sock
, drweb_fbuf
, fsize
, 0) < 0)
669 return m_errlog_defer_3(scanent
, CUS callout_address
, string_sprintf(
670 "unable to send file body to socket (%s)", scanner_options
),
676 drweb_slen
= htonl(Ustrlen(eml_filename
));
678 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n",
679 scanner_name
, scanner_options
);
681 /* send scan request */
682 if ((send(sock
, &drweb_cmd
, sizeof(drweb_cmd
), 0) < 0) ||
683 (send(sock
, &drweb_flags
, sizeof(drweb_flags
), 0) < 0) ||
684 (send(sock
, &drweb_slen
, sizeof(drweb_slen
), 0) < 0) ||
685 (send(sock
, eml_filename
, Ustrlen(eml_filename
), 0) < 0) ||
686 (send(sock
, &drweb_fin
, sizeof(drweb_fin
), 0) < 0))
687 return m_errlog_defer_3(scanent
, CUS callout_address
, string_sprintf(
688 "unable to send commands to socket (%s)", scanner_options
),
692 /* wait for result */
693 if (!recv_len(sock
, &drweb_rc
, sizeof(drweb_rc
), tmo
))
694 return m_errlog_defer_3(scanent
, CUS callout_address
,
695 US
"unable to read return code", sock
);
696 drweb_rc
= ntohl(drweb_rc
);
698 if (!recv_len(sock
, &drweb_vnum
, sizeof(drweb_vnum
), tmo
))
699 return m_errlog_defer_3(scanent
, CUS callout_address
,
700 US
"unable to read the number of viruses", sock
);
701 drweb_vnum
= ntohl(drweb_vnum
);
703 /* "virus(es) found" if virus number is > 0 */
708 /* setup default virus name */
709 malware_name
= US
"unknown";
711 /* set up match regex */
713 drweb_re
= m_pcre_compile(drweb_re_str
, &errstr
);
715 /* read and concatenate virus names into one string */
716 for (i
= 0; i
< drweb_vnum
; i
++)
718 int size
= 0, off
= 0, ovector
[10*3];
719 /* read the size of report */
720 if (!recv_len(sock
, &drweb_slen
, sizeof(drweb_slen
), tmo
))
721 return m_errlog_defer_3(scanent
, CUS callout_address
,
722 US
"cannot read report size", sock
);
723 drweb_slen
= ntohl(drweb_slen
);
724 tmpbuf
= store_get(drweb_slen
);
726 /* read report body */
727 if (!recv_len(sock
, tmpbuf
, drweb_slen
, tmo
))
728 return m_errlog_defer_3(scanent
, CUS callout_address
,
729 US
"cannot read report string", sock
);
730 tmpbuf
[drweb_slen
] = '\0';
732 /* try matcher on the line, grab substring */
733 result
= pcre_exec(drweb_re
, NULL
, CS tmpbuf
, Ustrlen(tmpbuf
), 0, 0,
734 ovector
, nelements(ovector
));
737 const char * pre_malware_nb
;
739 pcre_get_substring(CS tmpbuf
, ovector
, result
, 1, &pre_malware_nb
);
741 if (i
==0) /* the first name we just copy to malware_name */
742 malware_name
= string_append(NULL
, &size
, &off
,
745 else /* concatenate each new virus name to previous */
746 malware_name
= string_append(malware_name
, &size
, &off
,
747 2, "/", pre_malware_nb
);
749 pcre_free_substring(pre_malware_nb
);
755 const char *drweb_s
= NULL
;
757 if (drweb_rc
& DERR_READ_ERR
) drweb_s
= "read error";
758 if (drweb_rc
& DERR_NOMEMORY
) drweb_s
= "no memory";
759 if (drweb_rc
& DERR_TIMEOUT
) drweb_s
= "timeout";
760 if (drweb_rc
& DERR_BAD_CALL
) drweb_s
= "wrong command";
761 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
762 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
763 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
764 * and others are ignored */
766 return m_errlog_defer_3(scanent
, CUS callout_address
,
767 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc
, drweb_s
),
776 case M_AVES
: /* "aveserver" scanner type -------------------------------- */
781 /* read aveserver's greeting and see if it is ready (2xx greeting) */
783 recv_line(sock
, buf
, sizeof(buf
), tmo
);
785 if (buf
[0] != '2') /* aveserver is having problems */
786 return m_errlog_defer_3(scanent
, CUS callout_address
,
787 string_sprintf("unavailable (Responded: %s).",
788 ((buf
[0] != 0) ? buf
: (uschar
*)"nothing") ),
791 /* prepare our command */
792 (void)string_format(buf
, sizeof(buf
), "SCAN bPQRSTUW %s\r\n",
796 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s %s\n",
798 if (m_sock_send(sock
, buf
, Ustrlen(buf
), &errstr
) < 0)
799 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
803 /* read response lines, find malware name and final response */
804 while (recv_line(sock
, buf
, sizeof(buf
), tmo
) > 0)
808 if (buf
[0] == '5') /* aveserver is having problems */
810 result
= m_errlog_defer(scanent
, CUS callout_address
,
811 string_sprintf("unable to scan file %s (Responded: %s).",
815 if (Ustrncmp(buf
,"322",3) == 0)
817 uschar
*p
= Ustrchr(&buf
[4], ' ');
819 malware_name
= string_copy(&buf
[4]);
823 if (m_sock_send(sock
, US
"quit\r\n", 6, &errstr
) < 0)
824 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
826 /* read aveserver's greeting and see if it is ready (2xx greeting) */
828 recv_line(sock
, buf
, sizeof(buf
), tmo
);
830 if (buf
[0] != '2') /* aveserver is having problems */
831 return m_errlog_defer_3(scanent
, CUS callout_address
,
832 string_sprintf("unable to quit dialogue (Responded: %s).",
833 ((buf
[0] != 0) ? buf
: (uschar
*)"nothing") ),
844 case M_FSEC
: /* "fsecure" scanner type ---------------------------------- */
848 uschar av_buffer
[1024];
849 static uschar
*cmdopt
[] = { US
"CONFIGURE\tARCHIVE\t1\n",
850 US
"CONFIGURE\tTIMEOUT\t0\n",
851 US
"CONFIGURE\tMAXARCH\t5\n",
852 US
"CONFIGURE\tMIME\t1\n" };
856 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
857 scanner_name
, scanner_options
);
859 memset(av_buffer
, 0, sizeof(av_buffer
));
860 for (i
= 0; i
!= nelements(cmdopt
); i
++)
863 if (m_sock_send(sock
, cmdopt
[i
], Ustrlen(cmdopt
[i
]), &errstr
) < 0)
864 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
866 bread
= ip_recv(sock
, av_buffer
, sizeof(av_buffer
), tmo
-time(NULL
));
867 if (bread
> 0) av_buffer
[bread
]='\0';
869 return m_errlog_defer_3(scanent
, CUS callout_address
,
870 string_sprintf("unable to read answer %d (%s)", i
, strerror(errno
)),
872 for (j
= 0; j
< bread
; j
++)
873 if (av_buffer
[j
] == '\r' || av_buffer
[j
] == '\n')
877 /* pass the mailfile to fsecure */
878 file_name
= string_sprintf("SCAN\t%s\n", eml_filename
);
880 if (m_sock_send(sock
, file_name
, Ustrlen(file_name
), &errstr
) < 0)
881 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
884 /* todo also SUSPICION\t */
886 fsec_re
= m_pcre_compile(fsec_re_str
, &errstr
);
888 /* read report, linewise. Apply a timeout as the Fsecure daemon
889 sometimes wants an answer to "PING" but they won't tell us what */
891 uschar
* p
= av_buffer
;
897 i
= av_buffer
+sizeof(av_buffer
)-p
;
898 if ((bread
= ip_recv(sock
, p
, i
-1, tmo
-time(NULL
))) < 0)
899 return m_errlog_defer_3(scanent
, CUS callout_address
,
900 string_sprintf("unable to read result (%s)", strerror(errno
)),
903 for (p
[bread
] = '\0'; (q
= Ustrchr(p
, '\n')); p
= q
+1)
907 /* Really search for virus again? */
909 /* try matcher on the line, grab substring */
910 malware_name
= m_pcre_exec(fsec_re
, p
);
912 if (Ustrstr(p
, "OK\tScan ok."))
916 /* copy down the trailing partial line then read another chunk */
917 i
= av_buffer
+sizeof(av_buffer
)-p
;
918 memmove(av_buffer
, p
, i
);
927 case M_KAVD
: /* "kavdaemon" scanner type -------------------------------- */
931 uschar
* scanrequest
;
933 unsigned long kav_reportlen
;
938 /* get current date and time, build scan request */
940 /* pdp note: before the eml_filename parameter, this scanned the
941 directory; not finding documentation, so we'll strip off the directory.
942 The side-effect is that the test framework scanning may end up in
943 scanning more than was requested, but for the normal interface, this is
946 strftime(CS tmpbuf
, sizeof(tmpbuf
), "%d %b %H:%M:%S", localtime(&t
));
947 scanrequest
= string_sprintf("<0>%s:%s", CS tmpbuf
, eml_filename
);
948 p
= Ustrrchr(scanrequest
, '/');
952 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
953 scanner_name
, scanner_options
);
955 /* send scan request */
956 if (m_sock_send(sock
, scanrequest
, Ustrlen(scanrequest
)+1, &errstr
) < 0)
957 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
959 /* wait for result */
960 if (!recv_len(sock
, tmpbuf
, 2, tmo
))
961 return m_errlog_defer_3(scanent
, CUS callout_address
,
962 US
"unable to read 2 bytes from socket.", sock
);
964 /* get errorcode from one nibble */
965 kav_rc
= tmpbuf
[ test_byte_order()==LITTLE_MY_ENDIAN
? 0 : 1 ] & 0x0F;
968 case 5: case 6: /* improper kavdaemon configuration */
969 return m_errlog_defer_3(scanent
, CUS callout_address
,
970 US
"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
973 return m_errlog_defer_3(scanent
, CUS callout_address
,
974 US
"reported 'scanning not completed' (code 1).", sock
);
976 return m_errlog_defer_3(scanent
, CUS callout_address
,
977 US
"reported 'kavdaemon damaged' (code 7).", sock
);
980 /* code 8 is not handled, since it is ambiguous. It appears mostly on
981 bounces where part of a file has been cut off */
983 /* "virus found" return codes (2-4) */
984 if (kav_rc
> 1 && kav_rc
< 5)
988 /* setup default virus name */
989 malware_name
= US
"unknown";
991 report_flag
= tmpbuf
[ test_byte_order() == LITTLE_MY_ENDIAN
? 1 : 0 ];
993 /* read the report, if available */
994 if (report_flag
== 1)
996 /* read report size */
997 if (!recv_len(sock
, &kav_reportlen
, 4, tmo
))
998 return m_errlog_defer_3(scanent
, CUS callout_address
,
999 US
"cannot read report size", sock
);
1001 /* it's possible that avp returns av_buffer[1] == 1 but the
1002 reportsize is 0 (!?) */
1003 if (kav_reportlen
> 0)
1005 /* set up match regex, depends on retcode */
1008 if (!kav_re_sus
) kav_re_sus
= m_pcre_compile(kav_re_sus_str
, &errstr
);
1009 kav_re
= kav_re_sus
;
1013 if (!kav_re_inf
) kav_re_inf
= m_pcre_compile(kav_re_inf_str
, &errstr
);
1014 kav_re
= kav_re_inf
;
1017 /* read report, linewise. Using size from stream to read amount of data
1018 from same stream is safe enough. */
1019 /* coverity[tainted_data] */
1020 while (kav_reportlen
> 0)
1022 if ((bread
= recv_line(sock
, tmpbuf
, sizeof(tmpbuf
), tmo
)) < 0)
1024 kav_reportlen
-= bread
+1;
1026 /* try matcher on the line, grab substring */
1027 if ((malware_name
= m_pcre_exec(kav_re
, tmpbuf
)))
1033 else /* no virus found */
1034 malware_name
= NULL
;
1039 case M_CMDL
: /* "cmdline" scanner type ---------------------------------- */
1041 const uschar
*cmdline_scanner
= scanner_options
;
1042 const pcre
*cmdline_trigger_re
;
1043 const pcre
*cmdline_regex_re
;
1045 uschar
* commandline
;
1046 void (*eximsigchld
)(int);
1047 void (*eximsigpipe
)(int);
1048 FILE *scanner_out
= NULL
;
1050 FILE *scanner_record
= NULL
;
1051 uschar linebuffer
[32767];
1056 if (!cmdline_scanner
)
1057 return m_errlog_defer(scanent
, NULL
, errstr
);
1059 /* find scanner output trigger */
1060 cmdline_trigger_re
= m_pcre_nextinlist(&av_scanner_work
, &sep
,
1061 "missing trigger specification", &errstr
);
1062 if (!cmdline_trigger_re
)
1063 return m_errlog_defer(scanent
, NULL
, errstr
);
1065 /* find scanner name regex */
1066 cmdline_regex_re
= m_pcre_nextinlist(&av_scanner_work
, &sep
,
1067 "missing virus name regex specification", &errstr
);
1068 if (!cmdline_regex_re
)
1069 return m_errlog_defer(scanent
, NULL
, errstr
);
1071 /* prepare scanner call; despite the naming, file_name holds a directory
1072 name which is documented as the value given to %s. */
1074 file_name
= string_copy(eml_filename
);
1075 p
= Ustrrchr(file_name
, '/');
1078 commandline
= string_sprintf(CS cmdline_scanner
, file_name
);
1080 /* redirect STDERR too */
1081 commandline
= string_sprintf("%s 2>&1", commandline
);
1083 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1084 scanner_name
, commandline
);
1086 /* store exims signal handlers */
1087 eximsigchld
= signal(SIGCHLD
,SIG_DFL
);
1088 eximsigpipe
= signal(SIGPIPE
,SIG_DFL
);
1090 if (!(scanner_out
= popen(CS commandline
,"r")))
1093 signal(SIGCHLD
,eximsigchld
); signal(SIGPIPE
,eximsigpipe
);
1094 return m_errlog_defer(scanent
, NULL
,
1095 string_sprintf("call (%s) failed: %s.", commandline
, strerror(err
)));
1097 scanner_fd
= fileno(scanner_out
);
1099 file_name
= string_sprintf("%s/%s_scanner_output", eml_dir
, message_id
);
1101 if (!(scanner_record
= modefopen(file_name
, "wb", SPOOL_MODE
)))
1104 (void) pclose(scanner_out
);
1105 signal(SIGCHLD
,eximsigchld
); signal(SIGPIPE
,eximsigpipe
);
1106 return m_errlog_defer(scanent
, NULL
, string_sprintf(
1107 "opening scanner output file (%s) failed: %s.",
1108 file_name
, strerror(err
)));
1111 /* look for trigger while recording output */
1112 while ((rcnt
= recv_line(scanner_fd
, linebuffer
,
1113 sizeof(linebuffer
), tmo
)))
1120 (void) pclose(scanner_out
);
1121 signal(SIGCHLD
,eximsigchld
); signal(SIGPIPE
,eximsigpipe
);
1122 return m_errlog_defer(scanent
, NULL
, string_sprintf(
1123 "unable to read from scanner (%s): %s",
1124 commandline
, strerror(err
)));
1127 if (Ustrlen(linebuffer
) > fwrite(linebuffer
, 1, Ustrlen(linebuffer
), scanner_record
))
1130 (void) pclose(scanner_out
);
1131 signal(SIGCHLD
,eximsigchld
); signal(SIGPIPE
,eximsigpipe
);
1132 return m_errlog_defer(scanent
, NULL
, string_sprintf(
1133 "short write on scanner output file (%s).", file_name
));
1135 putc('\n', scanner_record
);
1136 /* try trigger match */
1138 && regex_match_and_setup(cmdline_trigger_re
, linebuffer
, 0, -1)
1143 (void)fclose(scanner_record
);
1144 sep
= pclose(scanner_out
);
1145 signal(SIGCHLD
,eximsigchld
); signal(SIGPIPE
,eximsigpipe
);
1147 return m_errlog_defer(scanent
, NULL
,
1149 ? string_sprintf("running scanner failed: %s", strerror(sep
))
1150 : string_sprintf("scanner returned error code: %d", sep
));
1155 /* setup default virus name */
1156 malware_name
= US
"unknown";
1158 /* re-open the scanner output file, look for name match */
1159 scanner_record
= fopen(CS file_name
, "rb");
1160 while (fgets(CS linebuffer
, sizeof(linebuffer
), scanner_record
))
1163 if ((s
= m_pcre_exec(cmdline_regex_re
, linebuffer
)))
1166 (void)fclose(scanner_record
);
1168 else /* no virus found */
1169 malware_name
= NULL
;
1173 case M_SOPHIE
: /* "sophie" scanner type --------------------------------- */
1178 uschar av_buffer
[1024];
1180 /* pass the scan directory to sophie */
1181 file_name
= string_copy(eml_filename
);
1182 if ((p
= Ustrrchr(file_name
, '/')))
1185 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1186 scanner_name
, scanner_options
);
1188 if ( write(sock
, file_name
, Ustrlen(file_name
)) < 0
1189 || write(sock
, "\n", 1) != 1
1191 return m_errlog_defer_3(scanent
, CUS callout_address
,
1192 string_sprintf("unable to write to UNIX socket (%s)", scanner_options
),
1195 /* wait for result */
1196 memset(av_buffer
, 0, sizeof(av_buffer
));
1197 if ((bread
= ip_recv(sock
, av_buffer
, sizeof(av_buffer
), tmo
-time(NULL
))) <= 0)
1198 return m_errlog_defer_3(scanent
, CUS callout_address
,
1199 string_sprintf("unable to read from UNIX socket (%s)", scanner_options
),
1203 if (av_buffer
[0] == '1') {
1204 uschar
* s
= Ustrchr(av_buffer
, '\n');
1207 malware_name
= string_copy(&av_buffer
[2]);
1209 else if (!strncmp(CS av_buffer
, "-1", 2))
1210 return m_errlog_defer_3(scanent
, CUS callout_address
,
1211 US
"scanner reported error", sock
);
1212 else /* all ok, no virus */
1213 malware_name
= NULL
;
1218 case M_CLAMD
: /* "clamd" scanner type ----------------------------------- */
1220 /* This code was originally contributed by David Saez */
1221 /* There are three scanning methods available to us:
1222 * (1) Use the SCAN command, pointing to a file in the filesystem
1223 * (2) Use the STREAM command, send the data on a separate port
1224 * (3) Use the zINSTREAM command, send the data inline
1225 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1226 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1227 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1228 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless
1229 * WITH_OLD_CLAMAV_STREAM is defined.
1230 * See Exim bug 926 for details. */
1232 uschar
*p
, *vname
, *result_tag
;
1235 uschar av_buffer
[1024];
1236 uschar
*hostname
= US
"";
1238 uschar
*clamav_fbuf
;
1239 int clam_fd
, result
;
1241 unsigned int fsize_uint
;
1242 BOOL use_scan_command
= FALSE
;
1243 clamd_address
* cv
[MAX_CLAMD_SERVERS
];
1244 int num_servers
= 0;
1245 #ifdef WITH_OLD_CLAMAV_STREAM
1247 uschar av_buffer2
[1024];
1250 uint32_t send_size
, send_final_zeroblock
;
1253 /*XXX if unixdomain socket, only one server supported. Needs fixing;
1254 there's no reason we should not mix local and remote servers */
1256 if (*scanner_options
== '/')
1259 const uschar
* sublist
;
1262 /* Local file; so we def want to use_scan_command and don't want to try
1263 * passing IP/port combinations */
1264 use_scan_command
= TRUE
;
1265 cd
= (clamd_address
*) store_get(sizeof(clamd_address
));
1267 /* extract socket-path part */
1268 sublist
= scanner_options
;
1269 cd
->hostspec
= string_nextinlist(&sublist
, &subsep
, NULL
, 0);
1272 if (clamd_option(cd
, sublist
, &subsep
) != OK
)
1273 return m_errlog_defer(scanent
, NULL
,
1274 string_sprintf("bad option '%s'", scanner_options
));
1279 /* Go through the rest of the list of host/port and construct an array
1280 * of servers to try. The first one is the bit we just passed from
1281 * scanner_options so process that first and then scan the remainder of
1282 * the address buffer */
1286 const uschar
* sublist
;
1290 /* The 'local' option means use the SCAN command over the network
1291 * socket (ie common file storage in use) */
1292 /*XXX we could accept this also as a local option? */
1293 if (strcmpic(scanner_options
, US
"local") == 0)
1295 use_scan_command
= TRUE
;
1299 cd
= (clamd_address
*) store_get(sizeof(clamd_address
));
1301 /* extract host and port part */
1302 sublist
= scanner_options
;
1303 if (!(cd
->hostspec
= string_nextinlist(&sublist
, &subsep
, NULL
, 0)))
1305 (void) m_errlog_defer(scanent
, NULL
,
1306 string_sprintf("missing address: '%s'", scanner_options
));
1309 if (!(s
= string_nextinlist(&sublist
, &subsep
, NULL
, 0)))
1311 (void) m_errlog_defer(scanent
, NULL
,
1312 string_sprintf("missing port: '%s'", scanner_options
));
1315 cd
->tcp_port
= atoi(CS s
);
1318 /*XXX should these options be common over scanner types? */
1319 if (clamd_option(cd
, sublist
, &subsep
) != OK
)
1320 return m_errlog_defer(scanent
, NULL
,
1321 string_sprintf("bad option '%s'", scanner_options
));
1323 cv
[num_servers
++] = cd
;
1324 if (num_servers
>= MAX_CLAMD_SERVERS
)
1326 (void) m_errlog_defer(scanent
, NULL
,
1327 US
"More than " MAX_CLAMD_SERVERS_S
" clamd servers "
1328 "specified; only using the first " MAX_CLAMD_SERVERS_S
);
1331 } while ((scanner_options
= string_nextinlist(&av_scanner_work
, &sep
,
1334 /* check if we have at least one server */
1336 return m_errlog_defer(scanent
, NULL
,
1337 US
"no useable server addresses in malware configuration option.");
1340 /* See the discussion of response formats below to see why we really
1341 don't like colons in filenames when passing filenames to ClamAV. */
1342 if (use_scan_command
&& Ustrchr(eml_filename
, ':'))
1343 return m_errlog_defer(scanent
, NULL
,
1344 string_sprintf("local/SCAN mode incompatible with" \
1345 " : in path to email filename [%s]", eml_filename
));
1347 /* We have some network servers specified */
1350 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1351 * only supports AF_INET, but we should probably be looking to the
1352 * future and rewriting this to be protocol-independent anyway. */
1354 while (num_servers
> 0)
1356 int i
= random_number( num_servers
);
1357 clamd_address
* cd
= cv
[i
];
1359 DEBUG(D_acl
) debug_printf_indent("trying server name %s, port %u\n",
1360 cd
->hostspec
, cd
->tcp_port
);
1362 /* Lookup the host. This is to ensure that we connect to the same IP
1363 * on both connections (as one host could resolve to multiple ips) */
1366 sock
= m_tcpsocket(cd
->hostspec
, cd
->tcp_port
, &connhost
, &errstr
);
1369 /* Connection successfully established with a server */
1370 hostname
= cd
->hostspec
;
1373 if (cd
->retry
<= 0) break;
1374 while (cd
->retry
> 0) cd
->retry
= sleep(cd
->retry
);
1379 (void) m_errlog_defer(scanent
, CUS callout_address
, errstr
);
1381 /* Remove the server from the list. XXX We should free the memory */
1383 for (; i
< num_servers
; i
++)
1387 if (num_servers
== 0)
1388 return m_errlog_defer(scanent
, NULL
, US
"all servers failed");
1393 if ((sock
= ip_unixsocket(cv
[0]->hostspec
, &errstr
)) >= 0)
1395 hostname
= cv
[0]->hostspec
;
1398 if (cv
[0]->retry
<= 0)
1399 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
1400 while (cv
[0]->retry
> 0) cv
[0]->retry
= sleep(cv
[0]->retry
);
1403 /* have socket in variable "sock"; command to use is semi-independent of
1404 * the socket protocol. We use SCAN if is local (either Unix/local
1405 * domain socket, or explicitly told local) else we stream the data.
1406 * How we stream the data depends upon how we were built. */
1408 if (!use_scan_command
)
1410 #ifdef WITH_OLD_CLAMAV_STREAM
1411 /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1412 * that port on a second connection; then in the scan-method-neutral
1413 * part, read the response back on the original connection. */
1415 DEBUG(D_acl
) debug_printf_indent(
1416 "Malware scan: issuing %s old-style remote scan (PORT)\n",
1419 /* Pass the string to ClamAV (7 = "STREAM\n") */
1420 if (m_sock_send(sock
, US
"STREAM\n", 7, &errstr
) < 0)
1421 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
1423 memset(av_buffer2
, 0, sizeof(av_buffer2
));
1424 bread
= ip_recv(sock
, av_buffer2
, sizeof(av_buffer2
), tmo
-time(NULL
));
1427 return m_errlog_defer_3(scanent
, CUS callout_address
,
1428 string_sprintf("unable to read PORT from socket (%s)",
1432 if (bread
== sizeof(av_buffer2
))
1433 return m_errlog_defer_3(scanent
, CUS callout_address
,
1434 "buffer too small", sock
);
1437 return m_errlog_defer_3(scanent
, CUS callout_address
,
1438 "ClamAV returned null", sock
);
1440 av_buffer2
[bread
] = '\0';
1441 if( sscanf(CS av_buffer2
, "PORT %u\n", &port
) != 1 )
1442 return m_errlog_defer_3(scanent
, CUS callout_address
,
1443 string_sprintf("Expected port information from clamd, got '%s'",
1447 sockData
= m_tcpsocket(connhost
.address
, port
, NULL
, &errstr
);
1449 return m_errlog_defer_3(scanent
, CUS callout_address
, errstr
, sock
);
1451 # define CLOSE_SOCKDATA (void)close(sockData)
1452 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1453 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1454 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1457 DEBUG(D_acl
) debug_printf_indent(
1458 "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1461 /* Pass the string to ClamAV (10 = "zINSTREAM\0") */
1462 if (send(sock
, "zINSTREAM", 10, 0) < 0)
1463 return m_errlog_defer_3(scanent
, CUS hostname
,
1464 string_sprintf("unable to send zINSTREAM to socket (%s)",
1468 # define CLOSE_SOCKDATA /**/
1471 /* calc file size */
1472 if ((clam_fd
= open(CS eml_filename
, O_RDONLY
)) < 0)
1476 return m_errlog_defer_3(scanent
, NULL
,
1477 string_sprintf("can't open spool file %s: %s",
1478 eml_filename
, strerror(err
)),
1481 if ((fsize
= lseek(clam_fd
, 0, SEEK_END
)) < 0)
1484 b_seek
: err
= errno
;
1485 CLOSE_SOCKDATA
; (void)close(clam_fd
);
1486 return m_errlog_defer_3(scanent
, NULL
,
1487 string_sprintf("can't seek spool file %s: %s",
1488 eml_filename
, strerror(err
)),
1491 fsize_uint
= (unsigned int) fsize
;
1492 if ((off_t
)fsize_uint
!= fsize
)
1494 CLOSE_SOCKDATA
; (void)close(clam_fd
);
1495 return m_errlog_defer_3(scanent
, NULL
,
1496 string_sprintf("seeking spool file %s, size overflow",
1500 if (lseek(clam_fd
, 0, SEEK_SET
) < 0)
1503 if (!(clamav_fbuf
= US
malloc(fsize_uint
)))
1505 CLOSE_SOCKDATA
; (void)close(clam_fd
);
1506 return m_errlog_defer_3(scanent
, NULL
,
1507 string_sprintf("unable to allocate memory %u for file (%s)",
1508 fsize_uint
, eml_filename
),
1512 if ((result
= read(clam_fd
, clamav_fbuf
, fsize_uint
)) < 0)
1515 free(clamav_fbuf
); CLOSE_SOCKDATA
; (void)close(clam_fd
);
1516 return m_errlog_defer_3(scanent
, NULL
,
1517 string_sprintf("can't read spool file %s: %s",
1518 eml_filename
, strerror(err
)),
1521 (void)close(clam_fd
);
1523 /* send file body to socket */
1524 #ifdef WITH_OLD_CLAMAV_STREAM
1525 if (send(sockData
, clamav_fbuf
, fsize_uint
, 0) < 0)
1527 free(clamav_fbuf
); CLOSE_SOCKDATA
;
1528 return m_errlog_defer_3(scanent
, NULL
,
1529 string_sprintf("unable to send file body to socket (%s:%u)",
1534 send_size
= htonl(fsize_uint
);
1535 send_final_zeroblock
= 0;
1536 if ((send(sock
, &send_size
, sizeof(send_size
), 0) < 0) ||
1537 (send(sock
, clamav_fbuf
, fsize_uint
, 0) < 0) ||
1538 (send(sock
, &send_final_zeroblock
, sizeof(send_final_zeroblock
), 0) < 0))
1541 return m_errlog_defer_3(scanent
, NULL
,
1542 string_sprintf("unable to send file body to socket (%s)", hostname
),
1550 #undef CLOSE_SOCKDATA
1553 { /* use scan command */
1554 /* Send a SCAN command pointing to a filename; then in the then in the
1555 * scan-method-neutral part, read the response back */
1557 /* ================================================================= */
1559 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1560 which dates to when ClamAV needed us to break apart the email into the
1561 MIME parts (eg, with the now deprecated demime condition coming first).
1562 Some time back, ClamAV gained the ability to deconstruct the emails, so
1563 doing this would actually have resulted in the mail attachments being
1564 scanned twice, in the broken out files and from the original .eml.
1565 Since ClamAV now handles emails (and has for quite some time) we can
1566 just use the email file itself. */
1567 /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
1568 file_name
= string_sprintf("SCAN %s\n", eml_filename
);
1570 DEBUG(D_acl
) debug_printf_indent(
1571 "Malware scan: issuing %s local-path scan [%s]\n",
1572 scanner_name
, scanner_options
);
1574 if (send(sock
, file_name
, Ustrlen(file_name
), 0) < 0)
1575 return m_errlog_defer_3(scanent
, CUS callout_address
,
1576 string_sprintf("unable to write to socket (%s)", strerror(errno
)),
1579 /* Do not shut down the socket for writing; a user report noted that
1580 * clamd 0.70 does not react well to this. */
1582 /* Commands have been sent, no matter which scan method or connection
1583 * type we're using; now just read the result, independent of method. */
1585 /* Read the result */
1586 memset(av_buffer
, 0, sizeof(av_buffer
));
1587 bread
= ip_recv(sock
, av_buffer
, sizeof(av_buffer
), tmo
-time(NULL
));
1592 return m_errlog_defer(scanent
, CUS callout_address
,
1593 string_sprintf("unable to read from socket (%s)",
1594 errno
== 0 ? "EOF" : strerror(errno
)));
1596 if (bread
== sizeof(av_buffer
))
1597 return m_errlog_defer(scanent
, CUS callout_address
,
1598 US
"buffer too small");
1599 /* We're now assured of a NULL at the end of av_buffer */
1601 /* Check the result. ClamAV returns one of two result formats.
1602 In the basic mode, the response is of the form:
1603 infected: -> "<filename>: <virusname> FOUND"
1604 not-infected: -> "<filename>: OK"
1605 error: -> "<filename>: <errcode> ERROR
1606 If the ExtendedDetectionInfo option has been turned on, then we get:
1607 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1608 for the infected case. Compare:
1609 /tmp/eicar.com: Eicar-Test-Signature FOUND
1610 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1612 In the streaming case, clamd uses the filename "stream" which you should
1613 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1614 client app will replace "stream" with the original filename before returning
1615 results to stdout, but the trace shows the data).
1617 We will assume that the pathname passed to clamd from Exim does not contain
1618 a colon. We will have whined loudly above if the eml_filename does (and we're
1619 passing a filename to clamd). */
1622 return m_errlog_defer(scanent
, CUS callout_address
,
1623 US
"ClamAV returned null");
1625 /* strip newline at the end (won't be present for zINSTREAM)
1626 (also any trailing whitespace, which shouldn't exist, but we depend upon
1627 this below, so double-check) */
1628 p
= av_buffer
+ Ustrlen(av_buffer
) - 1;
1629 if (*p
== '\n') *p
= '\0';
1631 DEBUG(D_acl
) debug_printf_indent("Malware response: %s\n", av_buffer
);
1633 while (isspace(*--p
) && (p
> av_buffer
))
1637 /* colon in returned output? */
1638 if(!(p
= Ustrchr(av_buffer
,':')))
1639 return m_errlog_defer(scanent
, CUS callout_address
, string_sprintf(
1640 "ClamAV returned malformed result (missing colon): %s",
1643 /* strip filename */
1644 while (*p
&& isspace(*++p
)) /**/;
1647 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1648 but we should at least be resistant to it. */
1649 p
= Ustrrchr(vname
, ' ');
1650 result_tag
= p
? p
+1 : vname
;
1652 if (Ustrcmp(result_tag
, "FOUND") == 0)
1654 /* p should still be the whitespace before the result_tag */
1655 while (isspace(*p
)) --p
;
1657 /* Strip off the extended information too, which will be in parens
1658 after the virus name, with no intervening whitespace. */
1661 /* "(hash:size)", so previous '(' will do; if not found, we have
1662 a curious virus name, but not an error. */
1663 p
= Ustrrchr(vname
, '(');
1667 malware_name
= string_copy(vname
);
1668 DEBUG(D_acl
) debug_printf_indent("Malware found, name \"%s\"\n", malware_name
);
1671 else if (Ustrcmp(result_tag
, "ERROR") == 0)
1672 return m_errlog_defer(scanent
, CUS callout_address
,
1673 string_sprintf("ClamAV returned: %s", av_buffer
));
1675 else if (Ustrcmp(result_tag
, "OK") == 0)
1677 /* Everything should be OK */
1678 malware_name
= NULL
;
1679 DEBUG(D_acl
) debug_printf_indent("Malware not found\n");
1683 return m_errlog_defer(scanent
, CUS callout_address
,
1684 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer
));
1689 case M_SOCK
: /* "sock" scanner type ------------------------------------- */
1690 /* This code was derived by Martin Poole from the clamd code contributed
1691 by David Saez and the cmdline code
1695 uschar
* commandline
;
1696 uschar av_buffer
[1024];
1697 uschar
* linebuffer
;
1698 uschar
* sockline_scanner
;
1699 uschar sockline_scanner_default
[] = "%s\n";
1700 const pcre
*sockline_trig_re
;
1701 const pcre
*sockline_name_re
;
1703 /* find scanner command line */
1704 if ((sockline_scanner
= string_nextinlist(&av_scanner_work
, &sep
,
1706 { /* check for no expansions apart from one %s */
1707 uschar
* s
= Ustrchr(sockline_scanner
, '%');
1709 if ((*s
!= 's' && *s
!= '%') || Ustrchr(s
+1, '%'))
1710 return m_errlog_defer_3(scanent
, NULL
,
1711 US
"unsafe sock scanner call spec", sock
);
1714 sockline_scanner
= sockline_scanner_default
;
1716 /* find scanner output trigger */
1717 sockline_trig_re
= m_pcre_nextinlist(&av_scanner_work
, &sep
,
1718 "missing trigger specification", &errstr
);
1719 if (!sockline_trig_re
)
1720 return m_errlog_defer_3(scanent
, NULL
, errstr
, sock
);
1722 /* find virus name regex */
1723 sockline_name_re
= m_pcre_nextinlist(&av_scanner_work
, &sep
,
1724 "missing virus name regex specification", &errstr
);
1725 if (!sockline_name_re
)
1726 return m_errlog_defer_3(scanent
, NULL
, errstr
, sock
);
1728 /* prepare scanner call - security depends on expansions check above */
1729 commandline
= string_sprintf( CS sockline_scanner
, CS eml_filename
);
1732 /* Pass the command string to the socket */
1733 if (m_sock_send(sock
, commandline
, Ustrlen(commandline
), &errstr
) < 0)
1734 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
1736 /* Read the result */
1737 bread
= ip_recv(sock
, av_buffer
, sizeof(av_buffer
), tmo
-time(NULL
));
1740 return m_errlog_defer_3(scanent
, CUS callout_address
,
1741 string_sprintf("unable to read from socket (%s)", strerror(errno
)),
1744 if (bread
== sizeof(av_buffer
))
1745 return m_errlog_defer_3(scanent
, CUS callout_address
,
1746 US
"buffer too small", sock
);
1747 av_buffer
[bread
] = '\0';
1748 linebuffer
= string_copy(av_buffer
);
1750 /* try trigger match */
1751 if (regex_match_and_setup(sockline_trig_re
, linebuffer
, 0, -1))
1753 if (!(malware_name
= m_pcre_exec(sockline_name_re
, av_buffer
)))
1754 malware_name
= US
"unknown";
1756 else /* no virus found */
1757 malware_name
= NULL
;
1761 case M_MKSD
: /* "mksd" scanner type ------------------------------------- */
1763 char *mksd_options_end
;
1764 int mksd_maxproc
= 1; /* default, if no option supplied */
1767 if (scanner_options
)
1769 mksd_maxproc
= (int)strtol(CS scanner_options
, &mksd_options_end
, 10);
1770 if ( *scanner_options
== '\0'
1771 || *mksd_options_end
!= '\0'
1773 || mksd_maxproc
> 32
1775 return m_errlog_defer(scanent
, CUS callout_address
,
1776 string_sprintf("invalid option '%s'", scanner_options
));
1779 if((sock
= ip_unixsocket(US
"/var/run/mksd/socket", &errstr
)) < 0)
1780 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
1782 malware_name
= NULL
;
1784 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name
);
1786 if ((retval
= mksd_scan_packed(scanent
, sock
, eml_filename
, tmo
)) != OK
)
1794 case M_AVAST
: /* "avast" scanner type ----------------------------------- */
1798 uschar
* scanrequest
;
1799 enum {AVA_HELO
, AVA_OPT
, AVA_RSP
, AVA_DONE
} avast_stage
;
1802 /* According to Martin Tuma @avast the protocol uses "escaped
1803 whitespace", that is, every embedded whitespace is backslash
1804 escaped, as well as backslash is protected by backslash.
1805 The returned lines contain the name of the scanned file, a tab
1809 [E] - some error occured
1810 Such marker follows the first non-escaped TAB. */
1811 if ( ( !ava_re_clean
1812 && !(ava_re_clean
= m_pcre_compile(ava_re_clean_str
, &errstr
)))
1814 && !(ava_re_virus
= m_pcre_compile(ava_re_virus_str
, &errstr
)))
1816 return malware_errlog_defer(errstr
);
1818 /* wait for result */
1819 for (avast_stage
= AVA_HELO
;
1820 (nread
= recv_line(sock
, buf
, sizeof(buf
), tmo
)) > 0;
1823 int slen
= Ustrlen(buf
);
1826 DEBUG(D_acl
) debug_printf_indent("got from avast: %s\n", buf
);
1827 switch (avast_stage
)
1830 if (Ustrncmp(buf
, "220", 3) != 0)
1831 goto endloop
; /* require a 220 */
1835 if (Ustrncmp(buf
, "210", 3) == 0)
1836 break; /* ignore 210 responses */
1837 if (Ustrncmp(buf
, "200", 3) != 0)
1838 goto endloop
; /* require a 200 */
1843 /* Check for another option to send. Newline-terminate it. */
1844 if ((scanrequest
= string_nextinlist(&av_scanner_work
, &sep
,
1847 scanrequest
= string_sprintf("%s\n", scanrequest
);
1848 avast_stage
= AVA_OPT
; /* just sent option */
1852 scanrequest
= string_sprintf("SCAN %s\n", eml_dir
);
1853 avast_stage
= AVA_RSP
; /* just sent command */
1856 /* send config-cmd or scan-request to socket */
1857 len
= Ustrlen(scanrequest
);
1858 if (send(sock
, scanrequest
, len
, 0) < 0)
1860 scanrequest
[len
-1] = '\0';
1861 return m_errlog_defer_3(scanent
, CUS callout_address
, string_sprintf(
1862 "unable to send request '%s' to socket (%s): %s",
1863 scanrequest
, scanner_options
, strerror(errno
)), sock
);
1869 if (Ustrncmp(buf
, "210", 3) == 0)
1870 break; /* ignore the "210 SCAN DATA" message */
1872 if (pcre_exec(ava_re_clean
, NULL
, CS buf
, slen
,
1873 0, 0, ovector
, nelements(ovector
)) > 0)
1876 if ((malware_name
= m_pcre_exec(ava_re_virus
, buf
)))
1877 { /* remove backslash in front of [whitespace|backslash] */
1879 for (p
= malware_name
; *p
; ++p
)
1880 if (*p
== '\\' && (isspace(p
[1]) || p
[1] == '\\'))
1881 for (p0
= p
; *p0
; ++p0
) *p0
= p0
[1];
1883 avast_stage
= AVA_DONE
;
1887 if (Ustrncmp(buf
, "200 SCAN OK", 11) == 0)
1888 { /* we're done finally */
1889 if (send(sock
, "QUIT\n", 5, 0) < 0) /* courtesy */
1890 return m_errlog_defer_3(scanent
, CUS callout_address
,
1892 "unable to send quit request to socket (%s): %s",
1893 scanner_options
, strerror(errno
)),
1895 malware_name
= NULL
;
1896 avast_stage
= AVA_DONE
;
1900 /* here for any unexpected response from the scanner */
1903 case AVA_DONE
: log_write(0, LOG_PANIC
, "%s:%d:%s: should not happen",
1904 __FILE__
, __LINE__
, __FUNCTION__
);
1914 case AVA_RSP
: return m_errlog_defer_3(scanent
, CUS callout_address
,
1917 "invalid response from scanner: '%s'", buf
)
1919 ? US
"EOF from scanner"
1920 : US
"timeout from scanner",
1927 case M_FPROT6D
: /* "f-prot6d" scanner type ----------------------------------- */
1931 uschar
* linebuffer
;
1932 uschar
* scanrequest
;
1933 uschar av_buffer
[1024];
1935 if ((!fprot6d_re_virus
&& !(fprot6d_re_virus
= m_pcre_compile(fprot6d_re_virus_str
, &errstr
)))
1936 || (!fprot6d_re_error
&& !(fprot6d_re_error
= m_pcre_compile(fprot6d_re_error_str
, &errstr
))))
1937 return malware_errlog_defer(errstr
);
1939 scanrequest
= string_sprintf("SCAN FILE %s\n", eml_filename
);
1940 DEBUG(D_acl
) debug_printf_indent("Malware scan: issuing %s: %s\n",
1941 scanner_name
, scanrequest
);
1943 if (m_sock_send(sock
, scanrequest
, Ustrlen(scanrequest
), &errstr
) < 0)
1944 return m_errlog_defer(scanent
, CUS callout_address
, errstr
);
1946 bread
= ip_recv(sock
, av_buffer
, sizeof(av_buffer
), tmo
-time(NULL
));
1949 return m_errlog_defer_3(scanent
, CUS callout_address
,
1950 string_sprintf("unable to read from socket (%s)", strerror(errno
)),
1953 if (bread
== sizeof(av_buffer
))
1954 return m_errlog_defer_3(scanent
, CUS callout_address
,
1955 US
"buffer too small", sock
);
1957 av_buffer
[bread
] = '\0';
1958 linebuffer
= string_copy(av_buffer
);
1960 m_sock_send(sock
, US
"QUIT\n", 5, 0);
1962 if ((e
= m_pcre_exec(fprot6d_re_error
, linebuffer
)))
1963 return m_errlog_defer_3(scanent
, CUS callout_address
,
1964 string_sprintf("scanner reported error (%s)", e
), sock
);
1966 if (!(malware_name
= m_pcre_exec(fprot6d_re_virus
, linebuffer
)))
1967 malware_name
= NULL
;
1971 } /* scanner type switch */
1974 (void) close (sock
);
1975 malware_ok
= TRUE
; /* set "been here, done that" marker */
1978 /* match virus name against pattern (caseless ------->----------v) */
1979 if (malware_name
&& regex_match_and_setup(re
, malware_name
, 0, -1))
1981 DEBUG(D_acl
) debug_printf_indent(
1982 "Matched regex to malware [%s] [%s]\n", malware_re
, malware_name
);
1990 /*************************************************
1991 * Scan an email for malware *
1992 *************************************************/
1994 /* This is the normal interface for scanning an email, which doesn't need a
1995 filename; it's a wrapper around the malware_file function.
1998 malware_re match condition for "malware="
1999 timeout if nonzero, timeout in seconds
2001 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2002 where true means malware was found (condition applies)
2005 malware(const uschar
* malware_re
, int timeout
)
2007 int ret
= malware_internal(malware_re
, NULL
, timeout
);
2009 if (ret
== DEFER
) av_failed
= TRUE
;
2014 /*************************************************
2015 * Scan a file for malware *
2016 *************************************************/
2018 /* This is a test wrapper for scanning an email, which is not used in
2019 normal processing. Scan any file, using the Exim scanning interface.
2020 This function tampers with various global variables so is unsafe to use
2021 in any other context.
2024 eml_filename a file holding the message to be scanned
2026 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2027 where true means malware was found (condition applies)
2030 malware_in_file(uschar
*eml_filename
)
2032 uschar message_id_buf
[64];
2035 /* spool_mbox() assumes various parameters exist, when creating
2036 the relevant directory and the email within */
2038 (void) string_format(message_id_buf
, sizeof(message_id_buf
),
2039 "dummy-%d", vaguely_random_number(INT_MAX
));
2040 message_id
= message_id_buf
;
2041 sender_address
= US
"malware-sender@example.net";
2043 recipients_list
= NULL
;
2044 receive_add_recipient(US
"malware-victim@example.net", -1);
2045 enable_dollar_recipients
= TRUE
;
2047 ret
= malware_internal(US
"*", eml_filename
, 0);
2049 Ustrncpy(spooled_message_id
, message_id
, sizeof(spooled_message_id
));
2052 /* don't set no_mbox_unspool; at present, there's no way for it to become
2053 set, but if that changes, then it should apply to these tests too */
2057 /* silence static analysis tools */
2067 if (!malware_default_re
)
2068 malware_default_re
= regex_must_compile(malware_regex_default
, FALSE
, TRUE
);
2070 drweb_re
= regex_must_compile(drweb_re_str
, FALSE
, TRUE
);
2072 fsec_re
= regex_must_compile(fsec_re_str
, FALSE
, TRUE
);
2074 kav_re_sus
= regex_must_compile(kav_re_sus_str
, FALSE
, TRUE
);
2076 kav_re_inf
= regex_must_compile(kav_re_inf_str
, FALSE
, TRUE
);
2078 ava_re_clean
= regex_must_compile(ava_re_clean_str
, FALSE
, TRUE
);
2080 ava_re_virus
= regex_must_compile(ava_re_virus_str
, FALSE
, TRUE
);
2081 if (!fprot6d_re_error
)
2082 fprot6d_re_error
= regex_must_compile(fprot6d_re_error_str
, FALSE
, TRUE
);
2083 if (!fprot6d_re_virus
)
2084 fprot6d_re_virus
= regex_must_compile(fprot6d_re_virus_str
, FALSE
, TRUE
);
2087 #endif /*WITH_CONTENT_SCAN*/