TFO: on FreeBSD avoid client TFO-mode connects unless a TCP_FASTOPEN setsocketopt...
[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 - 2015
6 * License: GPL
7 * Copyright (c) The Exim Maintainers 2016
8 */
9
10 /* Code for calling virus (malware) scanners. Called from acl.c. */
11
12 #include "exim.h"
13 #ifdef WITH_CONTENT_SCAN
14
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;
18 static struct scan
19 {
20 scanner_t scancode;
21 const uschar * name;
22 const uschar * options_default;
23 contype_t conn;
24 } m_scans[] =
25 {
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 */
39 };
40
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"
44
45 typedef struct clamd_address {
46 uschar * hostspec;
47 unsigned tcp_port;
48 unsigned retry;
49 } clamd_address;
50
51 #ifndef nelements
52 # define nelements(arr) (sizeof(arr) / sizeof(arr[0]))
53 #endif
54
55
56 #define MALWARE_TIMEOUT 120 /* default timeout, seconds */
57
58
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" */
62
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 */
67
68
69 static const uschar * malware_regex_default = US ".+";
70 static const pcre * malware_default_re = NULL;
71
72 static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$";
73 static const pcre * drweb_re = NULL;
74
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;
77
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;
82
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;
87
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;
92
93
94
95 /******************************************************************************/
96
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);
103 static inline int
104 test_byte_order()
105 {
106 short int word = 0x0001;
107 char *byte = CS &word;
108 return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
109 }
110
111 BOOL malware_ok = FALSE;
112
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];
118
119
120
121 static inline int
122 malware_errlog_defer(const uschar * str)
123 {
124 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
125 return DEFER;
126 }
127
128 static int
129 m_errlog_defer(struct scan * scanent, const uschar * hostport,
130 const uschar * str)
131 {
132 return malware_errlog_defer(string_sprintf("%s %s : %s",
133 scanent->name, hostport ? hostport : CUS"", str));
134 }
135 static int
136 m_errlog_defer_3(struct scan * scanent, const uschar * hostport,
137 const uschar * str, int fd_to_close)
138 {
139 (void) close(fd_to_close);
140 return m_errlog_defer(scanent, hostport, str);
141 }
142
143 /*************************************************/
144
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.
147 */
148 static inline int
149 m_tcpsocket(const uschar * hostname, unsigned int port,
150 host_item * host, uschar ** errstr, const blob * fastopen_blob)
151 {
152 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
153 host, errstr, fastopen_blob);
154 }
155
156 static int
157 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
158 {
159 if (send(sock, buf, cnt, 0) < 0)
160 {
161 int err = errno;
162 (void)close(sock);
163 *errstr = string_sprintf("unable to send to socket (%s): %s",
164 buf, strerror(err));
165 return -1;
166 }
167 return sock;
168 }
169
170 static const pcre *
171 m_pcre_compile(const uschar * re, uschar ** errstr)
172 {
173 const uschar * rerror;
174 int roffset;
175 const pcre * cre;
176
177 cre = pcre_compile(CS re, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
178 if (!cre)
179 *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
180 re, rerror, roffset);
181 return cre;
182 }
183
184 uschar *
185 m_pcre_exec(const pcre * cre, uschar * text)
186 {
187 int ovector[10*3];
188 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
189 ovector, nelements(ovector));
190 uschar * substr = NULL;
191 if (i >= 2) /* Got it */
192 pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr);
193 return substr;
194 }
195
196 static const pcre *
197 m_pcre_nextinlist(const uschar ** list, int * sep,
198 char * listerr, uschar ** errstr)
199 {
200 const uschar * list_ele;
201 const pcre * cre = NULL;
202
203 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
204 *errstr = US listerr;
205 else
206 {
207 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
208 string_printing(list_ele));
209 cre = m_pcre_compile(CUS list_ele, errstr);
210 }
211 return cre;
212 }
213
214 /*
215 Simple though inefficient wrapper for reading a line. Drop CRs and the
216 trailing newline. Can return early on buffer full. Null-terminate.
217 Apply initial timeout if no data ready.
218
219 Return: number of chars - zero for an empty line
220 -1 on EOF
221 -2 on timeout or error
222 */
223 static int
224 recv_line(int fd, uschar * buffer, int bsize, int tmo)
225 {
226 uschar * p = buffer;
227 ssize_t rcv;
228 BOOL ok = FALSE;
229
230 if (!fd_ready(fd, tmo-time(NULL)))
231 return -2;
232
233 /*XXX tmo handling assumes we always get a whole line */
234 /* read until \n */
235 errno = 0;
236 while ((rcv = read(fd, p, 1)) > 0)
237 {
238 ok = TRUE;
239 if (p-buffer > bsize-2) break;
240 if (*p == '\n') break;
241 if (*p != '\r') p++;
242 }
243 if (!ok)
244 {
245 DEBUG(D_acl) debug_printf_indent("Malware scan: read %s (%s)\n",
246 rcv==0 ? "EOF" : "error", strerror(errno));
247 return rcv==0 ? -1 : -2;
248 }
249 *p = '\0';
250
251 DEBUG(D_acl) debug_printf_indent("Malware scan: read '%s'\n", buffer);
252 return p - buffer;
253 }
254
255 /* return TRUE iff size as requested */
256 static BOOL
257 recv_len(int sock, void * buf, int size, int tmo)
258 {
259 return fd_ready(sock, tmo-time(NULL))
260 ? recv(sock, buf, size, 0) == size
261 : FALSE;
262 }
263
264
265
266 /* ============= private routines for the "mksd" scanner type ============== */
267
268 #include <sys/uio.h>
269
270 static inline int
271 mksd_writev (int sock, struct iovec * iov, int iovcnt)
272 {
273 int i;
274
275 for (;;)
276 {
277 do
278 i = writev (sock, iov, iovcnt);
279 while (i < 0 && errno == EINTR);
280 if (i <= 0)
281 {
282 (void) malware_errlog_defer(
283 US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
284 return -1;
285 }
286 for (;;) /* check for short write */
287 if (i >= iov->iov_len)
288 {
289 if (--iovcnt == 0)
290 return 0;
291 i -= iov->iov_len;
292 iov++;
293 }
294 else
295 {
296 iov->iov_len -= i;
297 iov->iov_base = CS iov->iov_base + i;
298 break;
299 }
300 }
301 }
302
303 static inline int
304 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, int tmo)
305 {
306 int offset = 0;
307 int i;
308
309 do
310 {
311 i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL));
312 if (i <= 0)
313 {
314 (void) malware_errlog_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
315 return -1;
316 }
317
318 offset += i;
319 /* offset == av_buffer_size -> buffer full */
320 if (offset == av_buffer_size)
321 {
322 (void) malware_errlog_defer(US"malformed reply received from mksd");
323 return -1;
324 }
325 } while (av_buffer[offset-1] != '\n');
326
327 av_buffer[offset] = '\0';
328 return offset;
329 }
330
331 static inline int
332 mksd_parse_line(struct scan * scanent, char * line)
333 {
334 char *p;
335
336 switch (*line)
337 {
338 case 'O': /* OK */
339 return OK;
340
341 case 'E':
342 case 'A': /* ERR */
343 if ((p = strchr (line, '\n')) != NULL)
344 *p = '\0';
345 return m_errlog_defer(scanent, NULL,
346 string_sprintf("scanner failed: %s", line));
347
348 default: /* VIR */
349 if ((p = strchr (line, '\n')) != NULL)
350 {
351 *p = '\0';
352 if ( p-line > 5
353 && line[3] == ' '
354 && (p = strchr(line+4, ' ')) != NULL
355 && p-line > 4
356 )
357 {
358 *p = '\0';
359 malware_name = string_copy(US line+4);
360 return OK;
361 }
362 }
363 return m_errlog_defer(scanent, NULL,
364 string_sprintf("malformed reply received: %s", line));
365 }
366 }
367
368 static int
369 mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename,
370 int tmo)
371 {
372 struct iovec iov[3];
373 const char *cmd = "MSQ\n";
374 uschar av_buffer[1024];
375
376 iov[0].iov_base = (void *) cmd;
377 iov[0].iov_len = 3;
378 iov[1].iov_base = (void *) scan_filename;
379 iov[1].iov_len = Ustrlen(scan_filename);
380 iov[2].iov_base = (void *) (cmd + 3);
381 iov[2].iov_len = 1;
382
383 if (mksd_writev (sock, iov, 3) < 0)
384 return DEFER;
385
386 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0)
387 return DEFER;
388
389 return mksd_parse_line (scanent, CS av_buffer);
390 }
391
392
393 static int
394 clamd_option(clamd_address * cd, const uschar * optstr, int * subsep)
395 {
396 uschar * s;
397
398 cd->retry = 0;
399 while ((s = string_nextinlist(&optstr, subsep, NULL, 0)))
400 if (Ustrncmp(s, "retry=", 6) == 0)
401 {
402 int sec = readconf_readtime((s += 6), '\0', FALSE);
403 if (sec < 0)
404 return FAIL;
405 cd->retry = sec;
406 }
407 else
408 return FAIL;
409 return OK;
410 }
411
412 /*************************************************
413 * Scan content for malware *
414 *************************************************/
415
416 /* This is an internal interface for scanning an email; the normal interface
417 is via malware(), or there's malware_in_file() used for testing/debugging.
418
419 Arguments:
420 malware_re match condition for "malware="
421 scan_filename the file holding the email to be scanned, if we're faking
422 this up for the -bmalware test, else NULL
423 timeout if nonzero, non-default timeoutl
424
425 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
426 where true means malware was found (condition applies)
427 */
428 static int
429 malware_internal(const uschar * malware_re, const uschar * scan_filename,
430 int timeout)
431 {
432 int sep = 0;
433 const uschar *av_scanner_work = av_scanner;
434 uschar *scanner_name;
435 unsigned long mbox_size;
436 FILE *mbox_file;
437 const pcre *re;
438 uschar * errstr;
439 struct scan * scanent;
440 const uschar * scanner_options;
441 int sock = -1;
442 time_t tmo;
443 uschar * eml_filename, * eml_dir;
444
445 if (!malware_re)
446 return FAIL; /* empty means "don't match anything" */
447
448 /* Ensure the eml mbox file is spooled up */
449
450 if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
451 return malware_errlog_defer(US"error while creating mbox spool file");
452
453 /* None of our current scanners need the mbox file as a stream (they use
454 the name), so we can close it right away. Get the directory too. */
455
456 (void) fclose(mbox_file);
457 eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
458
459 /* parse 1st option */
460 if (strcmpic(malware_re, US"false") == 0 || Ustrcmp(malware_re,"0") == 0)
461 return FAIL; /* explicitly no matching */
462
463 /* special cases (match anything except empty) */
464 if ( strcmpic(malware_re,US"true") == 0
465 || Ustrcmp(malware_re,"*") == 0
466 || Ustrcmp(malware_re,"1") == 0
467 )
468 {
469 if ( !malware_default_re
470 && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
471 return malware_errlog_defer(errstr);
472 malware_re = malware_regex_default;
473 re = malware_default_re;
474 }
475
476 /* compile the regex, see if it works */
477 else if (!(re = m_pcre_compile(malware_re, &errstr)))
478 return malware_errlog_defer(errstr);
479
480 /* if av_scanner starts with a dollar, expand it first */
481 if (*av_scanner == '$')
482 {
483 if (!(av_scanner_work = expand_string(av_scanner)))
484 return malware_errlog_defer(
485 string_sprintf("av_scanner starts with $, but expansion failed: %s",
486 expand_string_message));
487
488 DEBUG(D_acl)
489 debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work);
490 /* disable result caching in this case */
491 malware_name = NULL;
492 malware_ok = FALSE;
493 }
494
495 /* Do not scan twice (unless av_scanner is dynamic). */
496 if (!malware_ok)
497 {
498 /* find the scanner type from the av_scanner option */
499 if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
500 return malware_errlog_defer(US"av_scanner configuration variable is empty");
501 if (!timeout) timeout = MALWARE_TIMEOUT;
502 tmo = time(NULL) + timeout;
503
504 for (scanent = m_scans; ; scanent++)
505 {
506 if (!scanent->name)
507 return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
508 scanner_name));
509 if (strcmpic(scanner_name, US scanent->name) != 0)
510 continue;
511 DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo=%s\n",
512 scanner_name, readconf_printtime(timeout));
513
514 if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
515 scanner_options = scanent->options_default;
516 if (scanent->conn == MC_NONE)
517 break;
518
519 DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
520 switch(scanent->conn)
521 {
522 case MC_TCP: sock = ip_tcpsocket(scanner_options, &errstr, 5); break;
523 case MC_UNIX: sock = ip_unixsocket(scanner_options, &errstr); break;
524 case MC_STRM: sock = ip_streamsocket(scanner_options, &errstr, 5); break;
525 default: /* compiler quietening */ break;
526 }
527 if (sock < 0)
528 return m_errlog_defer(scanent, CUS callout_address, errstr);
529 break;
530 }
531
532 switch (scanent->scancode)
533 {
534 case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
535 {
536 uschar *fp_scan_option;
537 unsigned int detected=0, par_count=0;
538 uschar * scanrequest;
539 uschar buf[32768], *strhelper, *strhelper2;
540 uschar * malware_name_internal = NULL;
541 int len;
542
543 scanrequest = string_sprintf("GET %s", eml_filename);
544
545 while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
546 NULL, 0)))
547 {
548 scanrequest = string_sprintf("%s%s%s", scanrequest,
549 par_count ? "%20" : "?", fp_scan_option);
550 par_count++;
551 }
552 scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
553 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
554 scanner_name, scanrequest);
555
556 /* send scan request */
557 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
558 return m_errlog_defer(scanent, CUS callout_address, errstr);
559
560 while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0)
561 if (len > 0)
562 {
563 if (Ustrstr(buf, US"<detected type=\"") != NULL)
564 detected = 1;
565 else if (detected && (strhelper = Ustrstr(buf, US"<name>")))
566 {
567 if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL)
568 {
569 *strhelper2 = '\0';
570 malware_name_internal = string_copy(strhelper+6);
571 }
572 }
573 else if (Ustrstr(buf, US"<summary code=\""))
574 {
575 malware_name = Ustrstr(buf, US"<summary code=\"11\">")
576 ? malware_name_internal : NULL;
577 break;
578 }
579 }
580 if (len < -1)
581 {
582 (void)close(sock);
583 return DEFER;
584 }
585 break;
586 } /* f-protd */
587
588 case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
589 /* v0.1 - added support for tcp sockets */
590 /* v0.0 - initial release -- support for unix sockets */
591 {
592 int result;
593 off_t fsize;
594 unsigned int fsize_uint;
595 uschar * tmpbuf, *drweb_fbuf;
596 int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
597 drweb_vnum, drweb_slen, drweb_fin = 0x0000;
598
599 /* prepare variables */
600 drweb_cmd = htonl(DRWEBD_SCAN_CMD);
601 drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
602
603 if (*scanner_options != '/')
604 {
605 /* calc file size */
606 if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1)
607 return m_errlog_defer_3(scanent, NULL,
608 string_sprintf("can't open spool file %s: %s",
609 eml_filename, strerror(errno)),
610 sock);
611
612 if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
613 {
614 int err;
615 badseek: err = errno;
616 (void)close(drweb_fd);
617 return m_errlog_defer_3(scanent, NULL,
618 string_sprintf("can't seek spool file %s: %s",
619 eml_filename, strerror(err)),
620 sock);
621 }
622 fsize_uint = (unsigned int) fsize;
623 if ((off_t)fsize_uint != fsize)
624 {
625 (void)close(drweb_fd);
626 return m_errlog_defer_3(scanent, NULL,
627 string_sprintf("seeking spool file %s, size overflow",
628 eml_filename),
629 sock);
630 }
631 drweb_slen = htonl(fsize);
632 if (lseek(drweb_fd, 0, SEEK_SET) < 0)
633 goto badseek;
634
635 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
636 scanner_name, scanner_options);
637
638 /* send scan request */
639 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
640 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
641 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
642 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
643 {
644 (void)close(drweb_fd);
645 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
646 "unable to send commands to socket (%s)", scanner_options),
647 sock);
648 }
649
650 if (!(drweb_fbuf = US malloc(fsize_uint)))
651 {
652 (void)close(drweb_fd);
653 return m_errlog_defer_3(scanent, NULL,
654 string_sprintf("unable to allocate memory %u for file (%s)",
655 fsize_uint, eml_filename),
656 sock);
657 }
658
659 if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1)
660 {
661 int err = errno;
662 (void)close(drweb_fd);
663 free(drweb_fbuf);
664 return m_errlog_defer_3(scanent, NULL,
665 string_sprintf("can't read spool file %s: %s",
666 eml_filename, strerror(err)),
667 sock);
668 }
669 (void)close(drweb_fd);
670
671 /* send file body to socket */
672 if (send(sock, drweb_fbuf, fsize, 0) < 0)
673 {
674 free(drweb_fbuf);
675 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
676 "unable to send file body to socket (%s)", scanner_options),
677 sock);
678 }
679 }
680 else
681 {
682 drweb_slen = htonl(Ustrlen(eml_filename));
683
684 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n",
685 scanner_name, scanner_options);
686
687 /* send scan request */
688 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
689 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
690 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
691 (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
692 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
693 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
694 "unable to send commands to socket (%s)", scanner_options),
695 sock);
696 }
697
698 /* wait for result */
699 if (!recv_len(sock, &drweb_rc, sizeof(drweb_rc), tmo))
700 return m_errlog_defer_3(scanent, CUS callout_address,
701 US"unable to read return code", sock);
702 drweb_rc = ntohl(drweb_rc);
703
704 if (!recv_len(sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
705 return m_errlog_defer_3(scanent, CUS callout_address,
706 US"unable to read the number of viruses", sock);
707 drweb_vnum = ntohl(drweb_vnum);
708
709 /* "virus(es) found" if virus number is > 0 */
710 if (drweb_vnum)
711 {
712 int i;
713
714 /* setup default virus name */
715 malware_name = US"unknown";
716
717 /* set up match regex */
718 if (!drweb_re)
719 drweb_re = m_pcre_compile(drweb_re_str, &errstr);
720
721 /* read and concatenate virus names into one string */
722 for (i = 0; i < drweb_vnum; i++)
723 {
724 int size = 0, off = 0, ovector[10*3];
725 /* read the size of report */
726 if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
727 return m_errlog_defer_3(scanent, CUS callout_address,
728 US"cannot read report size", sock);
729 drweb_slen = ntohl(drweb_slen);
730 tmpbuf = store_get(drweb_slen);
731
732 /* read report body */
733 if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
734 return m_errlog_defer_3(scanent, CUS callout_address,
735 US"cannot read report string", sock);
736 tmpbuf[drweb_slen] = '\0';
737
738 /* try matcher on the line, grab substring */
739 result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
740 ovector, nelements(ovector));
741 if (result >= 2)
742 {
743 const char * pre_malware_nb;
744
745 pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
746
747 if (i==0) /* the first name we just copy to malware_name */
748 malware_name = string_append(NULL, &size, &off,
749 1, pre_malware_nb);
750
751 else /* concatenate each new virus name to previous */
752 malware_name = string_append(malware_name, &size, &off,
753 2, "/", pre_malware_nb);
754
755 pcre_free_substring(pre_malware_nb);
756 }
757 }
758 }
759 else
760 {
761 const char *drweb_s = NULL;
762
763 if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
764 if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
765 if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
766 if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
767 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
768 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
769 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
770 * and others are ignored */
771 if (drweb_s)
772 return m_errlog_defer_3(scanent, CUS callout_address,
773 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
774 sock);
775
776 /* no virus found */
777 malware_name = NULL;
778 }
779 break;
780 } /* drweb */
781
782 case M_AVES: /* "aveserver" scanner type -------------------------------- */
783 {
784 uschar buf[32768];
785 int result;
786
787 /* read aveserver's greeting and see if it is ready (2xx greeting) */
788 buf[0] = 0;
789 recv_line(sock, buf, sizeof(buf), tmo);
790
791 if (buf[0] != '2') /* aveserver is having problems */
792 return m_errlog_defer_3(scanent, CUS callout_address,
793 string_sprintf("unavailable (Responded: %s).",
794 ((buf[0] != 0) ? buf : US "nothing") ),
795 sock);
796
797 /* prepare our command */
798 (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
799 eml_filename);
800
801 /* and send it */
802 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
803 scanner_name, buf);
804 if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
805 return m_errlog_defer(scanent, CUS callout_address, errstr);
806
807 malware_name = NULL;
808 result = 0;
809 /* read response lines, find malware name and final response */
810 while (recv_line(sock, buf, sizeof(buf), tmo) > 0)
811 {
812 if (buf[0] == '2')
813 break;
814 if (buf[0] == '5') /* aveserver is having problems */
815 {
816 result = m_errlog_defer(scanent, CUS callout_address,
817 string_sprintf("unable to scan file %s (Responded: %s).",
818 eml_filename, buf));
819 break;
820 }
821 if (Ustrncmp(buf,"322",3) == 0)
822 {
823 uschar *p = Ustrchr(&buf[4], ' ');
824 *p = '\0';
825 malware_name = string_copy(&buf[4]);
826 }
827 }
828
829 if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
830 return m_errlog_defer(scanent, CUS callout_address, errstr);
831
832 /* read aveserver's greeting and see if it is ready (2xx greeting) */
833 buf[0] = 0;
834 recv_line(sock, buf, sizeof(buf), tmo);
835
836 if (buf[0] != '2') /* aveserver is having problems */
837 return m_errlog_defer_3(scanent, CUS callout_address,
838 string_sprintf("unable to quit dialogue (Responded: %s).",
839 ((buf[0] != 0) ? buf : US "nothing") ),
840 sock);
841
842 if (result == DEFER)
843 {
844 (void)close(sock);
845 return DEFER;
846 }
847 break;
848 } /* aveserver */
849
850 case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
851 {
852 int i, j, bread = 0;
853 uschar * file_name;
854 uschar av_buffer[1024];
855 static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
856 US"CONFIGURE\tTIMEOUT\t0\n",
857 US"CONFIGURE\tMAXARCH\t5\n",
858 US"CONFIGURE\tMIME\t1\n" };
859
860 malware_name = NULL;
861
862 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
863 scanner_name, scanner_options);
864 /* pass options */
865 memset(av_buffer, 0, sizeof(av_buffer));
866 for (i = 0; i != nelements(cmdopt); i++)
867 {
868
869 if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
870 return m_errlog_defer(scanent, CUS callout_address, errstr);
871
872 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
873 if (bread > 0) av_buffer[bread]='\0';
874 if (bread < 0)
875 return m_errlog_defer_3(scanent, CUS callout_address,
876 string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
877 sock);
878 for (j = 0; j < bread; j++)
879 if (av_buffer[j] == '\r' || av_buffer[j] == '\n')
880 av_buffer[j] ='@';
881 }
882
883 /* pass the mailfile to fsecure */
884 file_name = string_sprintf("SCAN\t%s\n", eml_filename);
885
886 if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
887 return m_errlog_defer(scanent, CUS callout_address, errstr);
888
889 /* set up match */
890 /* todo also SUSPICION\t */
891 if (!fsec_re)
892 fsec_re = m_pcre_compile(fsec_re_str, &errstr);
893
894 /* read report, linewise. Apply a timeout as the Fsecure daemon
895 sometimes wants an answer to "PING" but they won't tell us what */
896 {
897 uschar * p = av_buffer;
898 uschar * q;
899
900 for (;;)
901 {
902 errno = ETIMEDOUT;
903 i = av_buffer+sizeof(av_buffer)-p;
904 if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
905 return m_errlog_defer_3(scanent, CUS callout_address,
906 string_sprintf("unable to read result (%s)", strerror(errno)),
907 sock);
908
909 for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
910 {
911 *q = '\0';
912
913 /* Really search for virus again? */
914 if (!malware_name)
915 /* try matcher on the line, grab substring */
916 malware_name = m_pcre_exec(fsec_re, p);
917
918 if (Ustrstr(p, "OK\tScan ok."))
919 goto fsec_found;
920 }
921
922 /* copy down the trailing partial line then read another chunk */
923 i = av_buffer+sizeof(av_buffer)-p;
924 memmove(av_buffer, p, i);
925 p = av_buffer+i;
926 }
927 }
928
929 fsec_found:
930 break;
931 } /* fsecure */
932
933 case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
934 {
935 time_t t;
936 uschar tmpbuf[1024];
937 uschar * scanrequest;
938 int kav_rc;
939 unsigned long kav_reportlen;
940 int bread;
941 const pcre *kav_re;
942 uschar *p;
943
944 /* get current date and time, build scan request */
945 time(&t);
946 /* pdp note: before the eml_filename parameter, this scanned the
947 directory; not finding documentation, so we'll strip off the directory.
948 The side-effect is that the test framework scanning may end up in
949 scanning more than was requested, but for the normal interface, this is
950 fine. */
951
952 strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
953 scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
954 p = Ustrrchr(scanrequest, '/');
955 if (p)
956 *p = '\0';
957
958 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
959 scanner_name, scanner_options);
960
961 /* send scan request */
962 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
963 return m_errlog_defer(scanent, CUS callout_address, errstr);
964
965 /* wait for result */
966 if (!recv_len(sock, tmpbuf, 2, tmo))
967 return m_errlog_defer_3(scanent, CUS callout_address,
968 US"unable to read 2 bytes from socket.", sock);
969
970 /* get errorcode from one nibble */
971 kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
972 switch(kav_rc)
973 {
974 case 5: case 6: /* improper kavdaemon configuration */
975 return m_errlog_defer_3(scanent, CUS callout_address,
976 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
977 sock);
978 case 1:
979 return m_errlog_defer_3(scanent, CUS callout_address,
980 US"reported 'scanning not completed' (code 1).", sock);
981 case 7:
982 return m_errlog_defer_3(scanent, CUS callout_address,
983 US"reported 'kavdaemon damaged' (code 7).", sock);
984 }
985
986 /* code 8 is not handled, since it is ambiguous. It appears mostly on
987 bounces where part of a file has been cut off */
988
989 /* "virus found" return codes (2-4) */
990 if (kav_rc > 1 && kav_rc < 5)
991 {
992 int report_flag = 0;
993
994 /* setup default virus name */
995 malware_name = US"unknown";
996
997 report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
998
999 /* read the report, if available */
1000 if (report_flag == 1)
1001 {
1002 /* read report size */
1003 if (!recv_len(sock, &kav_reportlen, 4, tmo))
1004 return m_errlog_defer_3(scanent, CUS callout_address,
1005 US"cannot read report size", sock);
1006
1007 /* it's possible that avp returns av_buffer[1] == 1 but the
1008 reportsize is 0 (!?) */
1009 if (kav_reportlen > 0)
1010 {
1011 /* set up match regex, depends on retcode */
1012 if (kav_rc == 3)
1013 {
1014 if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
1015 kav_re = kav_re_sus;
1016 }
1017 else
1018 {
1019 if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
1020 kav_re = kav_re_inf;
1021 }
1022
1023 /* read report, linewise. Using size from stream to read amount of data
1024 from same stream is safe enough. */
1025 /* coverity[tainted_data] */
1026 while (kav_reportlen > 0)
1027 {
1028 if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
1029 break;
1030 kav_reportlen -= bread+1;
1031
1032 /* try matcher on the line, grab substring */
1033 if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
1034 break;
1035 }
1036 }
1037 }
1038 }
1039 else /* no virus found */
1040 malware_name = NULL;
1041
1042 break;
1043 }
1044
1045 case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1046 {
1047 const uschar *cmdline_scanner = scanner_options;
1048 const pcre *cmdline_trigger_re;
1049 const pcre *cmdline_regex_re;
1050 uschar * file_name;
1051 uschar * commandline;
1052 void (*eximsigchld)(int);
1053 void (*eximsigpipe)(int);
1054 FILE *scanner_out = NULL;
1055 int scanner_fd;
1056 FILE *scanner_record = NULL;
1057 uschar linebuffer[32767];
1058 int rcnt;
1059 int trigger = 0;
1060 uschar *p;
1061
1062 if (!cmdline_scanner)
1063 return m_errlog_defer(scanent, NULL, errstr);
1064
1065 /* find scanner output trigger */
1066 cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1067 "missing trigger specification", &errstr);
1068 if (!cmdline_trigger_re)
1069 return m_errlog_defer(scanent, NULL, errstr);
1070
1071 /* find scanner name regex */
1072 cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1073 "missing virus name regex specification", &errstr);
1074 if (!cmdline_regex_re)
1075 return m_errlog_defer(scanent, NULL, errstr);
1076
1077 /* prepare scanner call; despite the naming, file_name holds a directory
1078 name which is documented as the value given to %s. */
1079
1080 file_name = string_copy(eml_filename);
1081 p = Ustrrchr(file_name, '/');
1082 if (p)
1083 *p = '\0';
1084 commandline = string_sprintf(CS cmdline_scanner, file_name);
1085
1086 /* redirect STDERR too */
1087 commandline = string_sprintf("%s 2>&1", commandline);
1088
1089 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1090 scanner_name, commandline);
1091
1092 /* store exims signal handlers */
1093 eximsigchld = signal(SIGCHLD,SIG_DFL);
1094 eximsigpipe = signal(SIGPIPE,SIG_DFL);
1095
1096 if (!(scanner_out = popen(CS commandline,"r")))
1097 {
1098 int err = errno;
1099 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1100 return m_errlog_defer(scanent, NULL,
1101 string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
1102 }
1103 scanner_fd = fileno(scanner_out);
1104
1105 file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
1106
1107 if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
1108 {
1109 int err = errno;
1110 (void) pclose(scanner_out);
1111 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1112 return m_errlog_defer(scanent, NULL, string_sprintf(
1113 "opening scanner output file (%s) failed: %s.",
1114 file_name, strerror(err)));
1115 }
1116
1117 /* look for trigger while recording output */
1118 while ((rcnt = recv_line(scanner_fd, linebuffer,
1119 sizeof(linebuffer), tmo)))
1120 {
1121 if (rcnt < 0)
1122 {
1123 int err = errno;
1124 if (rcnt == -1)
1125 break;
1126 (void) pclose(scanner_out);
1127 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1128 return m_errlog_defer(scanent, NULL, string_sprintf(
1129 "unable to read from scanner (%s): %s",
1130 commandline, strerror(err)));
1131 }
1132
1133 if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record))
1134 {
1135 /* short write */
1136 (void) pclose(scanner_out);
1137 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1138 return m_errlog_defer(scanent, NULL, string_sprintf(
1139 "short write on scanner output file (%s).", file_name));
1140 }
1141 putc('\n', scanner_record);
1142 /* try trigger match */
1143 if ( !trigger
1144 && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)
1145 )
1146 trigger = 1;
1147 }
1148
1149 (void)fclose(scanner_record);
1150 sep = pclose(scanner_out);
1151 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
1152 if (sep != 0)
1153 return m_errlog_defer(scanent, NULL,
1154 sep == -1
1155 ? string_sprintf("running scanner failed: %s", strerror(sep))
1156 : string_sprintf("scanner returned error code: %d", sep));
1157
1158 if (trigger)
1159 {
1160 uschar * s;
1161 /* setup default virus name */
1162 malware_name = US"unknown";
1163
1164 /* re-open the scanner output file, look for name match */
1165 scanner_record = fopen(CS file_name, "rb");
1166 while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record))
1167 {
1168 /* try match */
1169 if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
1170 malware_name = s;
1171 }
1172 (void)fclose(scanner_record);
1173 }
1174 else /* no virus found */
1175 malware_name = NULL;
1176 break;
1177 } /* cmdline */
1178
1179 case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
1180 {
1181 int bread = 0;
1182 uschar *p;
1183 uschar * file_name;
1184 uschar av_buffer[1024];
1185
1186 /* pass the scan directory to sophie */
1187 file_name = string_copy(eml_filename);
1188 if ((p = Ustrrchr(file_name, '/')))
1189 *p = '\0';
1190
1191 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
1192 scanner_name, scanner_options);
1193
1194 if ( write(sock, file_name, Ustrlen(file_name)) < 0
1195 || write(sock, "\n", 1) != 1
1196 )
1197 return m_errlog_defer_3(scanent, CUS callout_address,
1198 string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
1199 sock);
1200
1201 /* wait for result */
1202 memset(av_buffer, 0, sizeof(av_buffer));
1203 if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
1204 return m_errlog_defer_3(scanent, CUS callout_address,
1205 string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
1206 sock);
1207
1208 /* infected ? */
1209 if (av_buffer[0] == '1') {
1210 uschar * s = Ustrchr(av_buffer, '\n');
1211 if (s)
1212 *s = '\0';
1213 malware_name = string_copy(&av_buffer[2]);
1214 }
1215 else if (!strncmp(CS av_buffer, "-1", 2))
1216 return m_errlog_defer_3(scanent, CUS callout_address,
1217 US"scanner reported error", sock);
1218 else /* all ok, no virus */
1219 malware_name = NULL;
1220
1221 break;
1222 }
1223
1224 case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1225 {
1226 /* This code was originally contributed by David Saez */
1227 /* There are three scanning methods available to us:
1228 * (1) Use the SCAN command, pointing to a file in the filesystem
1229 * (2) Use the STREAM command, send the data on a separate port
1230 * (3) Use the zINSTREAM command, send the data inline
1231 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1232 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1233 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1234 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless
1235 * WITH_OLD_CLAMAV_STREAM is defined.
1236 * See Exim bug 926 for details. */
1237
1238 uschar *p, *vname, *result_tag;
1239 int bread=0;
1240 uschar * file_name;
1241 uschar av_buffer[1024];
1242 uschar *hostname = US"";
1243 host_item connhost;
1244 uschar *clamav_fbuf;
1245 int clam_fd, result;
1246 off_t fsize;
1247 unsigned int fsize_uint;
1248 BOOL use_scan_command = FALSE;
1249 clamd_address * cv[MAX_CLAMD_SERVERS];
1250 int num_servers = 0;
1251 #ifdef WITH_OLD_CLAMAV_STREAM
1252 unsigned int port;
1253 uschar av_buffer2[1024];
1254 int sockData;
1255 #else
1256 uint32_t send_size, send_final_zeroblock;
1257 #endif
1258 blob cmd_str;
1259
1260 /*XXX if unixdomain socket, only one server supported. Needs fixing;
1261 there's no reason we should not mix local and remote servers */
1262
1263 if (*scanner_options == '/')
1264 {
1265 clamd_address * cd;
1266 const uschar * sublist;
1267 int subsep = ' ';
1268
1269 /* Local file; so we def want to use_scan_command and don't want to try
1270 * passing IP/port combinations */
1271 use_scan_command = TRUE;
1272 cd = (clamd_address *) store_get(sizeof(clamd_address));
1273
1274 /* extract socket-path part */
1275 sublist = scanner_options;
1276 cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0);
1277
1278 /* parse options */
1279 if (clamd_option(cd, sublist, &subsep) != OK)
1280 return m_errlog_defer(scanent, NULL,
1281 string_sprintf("bad option '%s'", scanner_options));
1282 cv[0] = cd;
1283 }
1284 else
1285 {
1286 /* Go through the rest of the list of host/port and construct an array
1287 * of servers to try. The first one is the bit we just passed from
1288 * scanner_options so process that first and then scan the remainder of
1289 * the address buffer */
1290 do
1291 {
1292 clamd_address * cd;
1293 const uschar * sublist;
1294 int subsep = ' ';
1295 uschar * s;
1296
1297 /* The 'local' option means use the SCAN command over the network
1298 * socket (ie common file storage in use) */
1299 /*XXX we could accept this also as a local option? */
1300 if (strcmpic(scanner_options, US"local") == 0)
1301 {
1302 use_scan_command = TRUE;
1303 continue;
1304 }
1305
1306 cd = (clamd_address *) store_get(sizeof(clamd_address));
1307
1308 /* extract host and port part */
1309 sublist = scanner_options;
1310 if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
1311 {
1312 (void) m_errlog_defer(scanent, NULL,
1313 string_sprintf("missing address: '%s'", scanner_options));
1314 continue;
1315 }
1316 if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
1317 {
1318 (void) m_errlog_defer(scanent, NULL,
1319 string_sprintf("missing port: '%s'", scanner_options));
1320 continue;
1321 }
1322 cd->tcp_port = atoi(CS s);
1323
1324 /* parse options */
1325 /*XXX should these options be common over scanner types? */
1326 if (clamd_option(cd, sublist, &subsep) != OK)
1327 return m_errlog_defer(scanent, NULL,
1328 string_sprintf("bad option '%s'", scanner_options));
1329
1330 cv[num_servers++] = cd;
1331 if (num_servers >= MAX_CLAMD_SERVERS)
1332 {
1333 (void) m_errlog_defer(scanent, NULL,
1334 US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1335 "specified; only using the first " MAX_CLAMD_SERVERS_S );
1336 break;
1337 }
1338 } while ((scanner_options = string_nextinlist(&av_scanner_work, &sep,
1339 NULL, 0)));
1340
1341 /* check if we have at least one server */
1342 if (!num_servers)
1343 return m_errlog_defer(scanent, NULL,
1344 US"no useable server addresses in malware configuration option.");
1345 }
1346
1347 /* See the discussion of response formats below to see why we really
1348 don't like colons in filenames when passing filenames to ClamAV. */
1349 if (use_scan_command && Ustrchr(eml_filename, ':'))
1350 return m_errlog_defer(scanent, NULL,
1351 string_sprintf("local/SCAN mode incompatible with" \
1352 " : in path to email filename [%s]", eml_filename));
1353
1354 /* Set up the very first data we will be sending */
1355 if (!use_scan_command)
1356 #ifdef WITH_OLD_CLAMAV_STREAM
1357 { cmd_str.data = US"STREAM\n"; cmd_str.len = 7; }
1358 #else
1359 { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1360 #endif
1361 else
1362 {
1363 cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
1364 cmd_str.len = Ustrlen(cmd_str.data);
1365 }
1366
1367 /* We have some network servers specified */
1368 if (num_servers)
1369 {
1370 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1371 * only supports AF_INET, but we should probably be looking to the
1372 * future and rewriting this to be protocol-independent anyway. */
1373
1374 while (num_servers > 0)
1375 {
1376 int i = random_number(num_servers);
1377 clamd_address * cd = cv[i];
1378
1379 DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
1380 cd->hostspec, cd->tcp_port);
1381
1382 /* Lookup the host. This is to ensure that we connect to the same IP
1383 * on both connections (as one host could resolve to multiple ips) */
1384 for (;;)
1385 {
1386 if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1387 &connhost, &errstr, &cmd_str)) >= 0)
1388 {
1389 /* Connection successfully established with a server */
1390 hostname = cd->hostspec;
1391 cmd_str.len = 0;
1392 break;
1393 }
1394 if (cd->retry <= 0) break;
1395 while (cd->retry > 0) cd->retry = sleep(cd->retry);
1396 }
1397 if (sock >= 0)
1398 break;
1399
1400 (void) m_errlog_defer(scanent, CUS callout_address, errstr);
1401
1402 /* Remove the server from the list. XXX We should free the memory */
1403 num_servers--;
1404 for (; i < num_servers; i++)
1405 cv[i] = cv[i+1];
1406 }
1407
1408 if (num_servers == 0)
1409 return m_errlog_defer(scanent, NULL, US"all servers failed");
1410 }
1411 else
1412 for (;;)
1413 {
1414 if ((sock = ip_unixsocket(cv[0]->hostspec, &errstr)) >= 0)
1415 {
1416 hostname = cv[0]->hostspec;
1417 break;
1418 }
1419 if (cv[0]->retry <= 0)
1420 return m_errlog_defer(scanent, CUS callout_address, errstr);
1421 while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
1422 }
1423
1424 /* have socket in variable "sock"; command to use is semi-independent of
1425 * the socket protocol. We use SCAN if is local (either Unix/local
1426 * domain socket, or explicitly told local) else we stream the data.
1427 * How we stream the data depends upon how we were built. */
1428
1429 if (!use_scan_command)
1430 {
1431 #ifdef WITH_OLD_CLAMAV_STREAM
1432 /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1433 * that port on a second connection; then in the scan-method-neutral
1434 * part, read the response back on the original connection. */
1435
1436 DEBUG(D_acl) debug_printf_indent(
1437 "Malware scan: issuing %s old-style remote scan (PORT)\n",
1438 scanner_name);
1439
1440 /* Pass the string to ClamAV (7 = "STREAM\n"), if not already sent */
1441 if (cmd_str.len)
1442 if (m_sock_send(sock, cmd_str.data, cmd_str.len, &errstr) < 0)
1443 return m_errlog_defer(scanent, CUS callout_address, errstr);
1444
1445 memset(av_buffer2, 0, sizeof(av_buffer2));
1446 bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
1447
1448 if (bread < 0)
1449 return m_errlog_defer_3(scanent, CUS callout_address,
1450 string_sprintf("unable to read PORT from socket (%s)",
1451 strerror(errno)),
1452 sock);
1453
1454 if (bread == sizeof(av_buffer2))
1455 return m_errlog_defer_3(scanent, CUS callout_address,
1456 "buffer too small", sock);
1457
1458 if (!(*av_buffer2))
1459 return m_errlog_defer_3(scanent, CUS callout_address,
1460 "ClamAV returned null", sock);
1461
1462 av_buffer2[bread] = '\0';
1463 if(sscanf(CS av_buffer2, "PORT %u\n", &port) != 1)
1464 return m_errlog_defer_3(scanent, CUS callout_address,
1465 string_sprintf("Expected port information from clamd, got '%s'",
1466 av_buffer2),
1467 sock);
1468
1469 sockData = m_tcpsocket(connhost.address, port, NULL, &errstr, NULL);
1470 if (sockData < 0)
1471 return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock);
1472
1473 # define CLOSE_SOCKDATA (void)close(sockData)
1474 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1475 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1476 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1477 chunk. */
1478
1479 DEBUG(D_acl) debug_printf_indent(
1480 "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1481 scanner_name);
1482
1483 /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1484 if (cmd_str.len)
1485 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1486 return m_errlog_defer_3(scanent, CUS hostname,
1487 string_sprintf("unable to send zINSTREAM to socket (%s)",
1488 strerror(errno)),
1489 sock);
1490
1491 # define CLOSE_SOCKDATA /**/
1492 #endif
1493
1494 /* calc file size */
1495 if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
1496 {
1497 int err = errno;
1498 CLOSE_SOCKDATA;
1499 return m_errlog_defer_3(scanent, NULL,
1500 string_sprintf("can't open spool file %s: %s",
1501 eml_filename, strerror(err)),
1502 sock);
1503 }
1504 if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1505 {
1506 int err;
1507 b_seek: err = errno;
1508 CLOSE_SOCKDATA; (void)close(clam_fd);
1509 return m_errlog_defer_3(scanent, NULL,
1510 string_sprintf("can't seek spool file %s: %s",
1511 eml_filename, strerror(err)),
1512 sock);
1513 }
1514 fsize_uint = (unsigned int) fsize;
1515 if ((off_t)fsize_uint != fsize)
1516 {
1517 CLOSE_SOCKDATA; (void)close(clam_fd);
1518 return m_errlog_defer_3(scanent, NULL,
1519 string_sprintf("seeking spool file %s, size overflow",
1520 eml_filename),
1521 sock);
1522 }
1523 if (lseek(clam_fd, 0, SEEK_SET) < 0)
1524 goto b_seek;
1525
1526 if (!(clamav_fbuf = US malloc(fsize_uint)))
1527 {
1528 CLOSE_SOCKDATA; (void)close(clam_fd);
1529 return m_errlog_defer_3(scanent, NULL,
1530 string_sprintf("unable to allocate memory %u for file (%s)",
1531 fsize_uint, eml_filename),
1532 sock);
1533 }
1534
1535 if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1536 {
1537 int err = errno;
1538 free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd);
1539 return m_errlog_defer_3(scanent, NULL,
1540 string_sprintf("can't read spool file %s: %s",
1541 eml_filename, strerror(err)),
1542 sock);
1543 }
1544 (void)close(clam_fd);
1545
1546 /* send file body to socket */
1547 #ifdef WITH_OLD_CLAMAV_STREAM
1548 if (send(sockData, clamav_fbuf, fsize_uint, 0) < 0)
1549 {
1550 free(clamav_fbuf); CLOSE_SOCKDATA;
1551 return m_errlog_defer_3(scanent, NULL,
1552 string_sprintf("unable to send file body to socket (%s:%u)",
1553 hostname, port),
1554 sock);
1555 }
1556 #else
1557 send_size = htonl(fsize_uint);
1558 send_final_zeroblock = 0;
1559 if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1560 (send(sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1561 (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1562 {
1563 free(clamav_fbuf);
1564 return m_errlog_defer_3(scanent, NULL,
1565 string_sprintf("unable to send file body to socket (%s)", hostname),
1566 sock);
1567 }
1568 #endif
1569
1570 free(clamav_fbuf);
1571
1572 CLOSE_SOCKDATA;
1573 #undef CLOSE_SOCKDATA
1574 }
1575 else
1576 { /* use scan command */
1577 /* Send a SCAN command pointing to a filename; then in the then in the
1578 * scan-method-neutral part, read the response back */
1579
1580 /* ================================================================= */
1581
1582 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1583 which dates to when ClamAV needed us to break apart the email into the
1584 MIME parts (eg, with the now deprecated demime condition coming first).
1585 Some time back, ClamAV gained the ability to deconstruct the emails, so
1586 doing this would actually have resulted in the mail attachments being
1587 scanned twice, in the broken out files and from the original .eml.
1588 Since ClamAV now handles emails (and has for quite some time) we can
1589 just use the email file itself. */
1590 /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
1591
1592 DEBUG(D_acl) debug_printf_indent(
1593 "Malware scan: issuing %s local-path scan [%s]\n",
1594 scanner_name, scanner_options);
1595
1596 if (cmd_str.len)
1597 if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
1598 return m_errlog_defer_3(scanent, CUS callout_address,
1599 string_sprintf("unable to write to socket (%s)", strerror(errno)),
1600 sock);
1601
1602 /* Do not shut down the socket for writing; a user report noted that
1603 * clamd 0.70 does not react well to this. */
1604 }
1605 /* Commands have been sent, no matter which scan method or connection
1606 * type we're using; now just read the result, independent of method. */
1607
1608 /* Read the result */
1609 memset(av_buffer, 0, sizeof(av_buffer));
1610 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1611 (void)close(sock);
1612 sock = -1;
1613
1614 if (bread <= 0)
1615 return m_errlog_defer(scanent, CUS callout_address,
1616 string_sprintf("unable to read from socket (%s)",
1617 errno == 0 ? "EOF" : strerror(errno)));
1618
1619 if (bread == sizeof(av_buffer))
1620 return m_errlog_defer(scanent, CUS callout_address,
1621 US"buffer too small");
1622 /* We're now assured of a NULL at the end of av_buffer */
1623
1624 /* Check the result. ClamAV returns one of two result formats.
1625 In the basic mode, the response is of the form:
1626 infected: -> "<filename>: <virusname> FOUND"
1627 not-infected: -> "<filename>: OK"
1628 error: -> "<filename>: <errcode> ERROR
1629 If the ExtendedDetectionInfo option has been turned on, then we get:
1630 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1631 for the infected case. Compare:
1632 /tmp/eicar.com: Eicar-Test-Signature FOUND
1633 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1634
1635 In the streaming case, clamd uses the filename "stream" which you should
1636 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1637 client app will replace "stream" with the original filename before returning
1638 results to stdout, but the trace shows the data).
1639
1640 We will assume that the pathname passed to clamd from Exim does not contain
1641 a colon. We will have whined loudly above if the eml_filename does (and we're
1642 passing a filename to clamd). */
1643
1644 if (!(*av_buffer))
1645 return m_errlog_defer(scanent, CUS callout_address,
1646 US"ClamAV returned null");
1647
1648 /* strip newline at the end (won't be present for zINSTREAM)
1649 (also any trailing whitespace, which shouldn't exist, but we depend upon
1650 this below, so double-check) */
1651 p = av_buffer + Ustrlen(av_buffer) - 1;
1652 if (*p == '\n') *p = '\0';
1653
1654 DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer);
1655
1656 while (isspace(*--p) && (p > av_buffer))
1657 *p = '\0';
1658 if (*p) ++p;
1659
1660 /* colon in returned output? */
1661 if(!(p = Ustrchr(av_buffer,':')))
1662 return m_errlog_defer(scanent, CUS callout_address, string_sprintf(
1663 "ClamAV returned malformed result (missing colon): %s",
1664 av_buffer));
1665
1666 /* strip filename */
1667 while (*p && isspace(*++p)) /**/;
1668 vname = p;
1669
1670 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1671 but we should at least be resistant to it. */
1672 p = Ustrrchr(vname, ' ');
1673 result_tag = p ? p+1 : vname;
1674
1675 if (Ustrcmp(result_tag, "FOUND") == 0)
1676 {
1677 /* p should still be the whitespace before the result_tag */
1678 while (isspace(*p)) --p;
1679 *++p = '\0';
1680 /* Strip off the extended information too, which will be in parens
1681 after the virus name, with no intervening whitespace. */
1682 if (*--p == ')')
1683 {
1684 /* "(hash:size)", so previous '(' will do; if not found, we have
1685 a curious virus name, but not an error. */
1686 p = Ustrrchr(vname, '(');
1687 if (p)
1688 *p = '\0';
1689 }
1690 malware_name = string_copy(vname);
1691 DEBUG(D_acl) debug_printf_indent("Malware found, name \"%s\"\n", malware_name);
1692
1693 }
1694 else if (Ustrcmp(result_tag, "ERROR") == 0)
1695 return m_errlog_defer(scanent, CUS callout_address,
1696 string_sprintf("ClamAV returned: %s", av_buffer));
1697
1698 else if (Ustrcmp(result_tag, "OK") == 0)
1699 {
1700 /* Everything should be OK */
1701 malware_name = NULL;
1702 DEBUG(D_acl) debug_printf_indent("Malware not found\n");
1703
1704 }
1705 else
1706 return m_errlog_defer(scanent, CUS callout_address,
1707 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1708
1709 break;
1710 } /* clamd */
1711
1712 case M_SOCK: /* "sock" scanner type ------------------------------------- */
1713 /* This code was derived by Martin Poole from the clamd code contributed
1714 by David Saez and the cmdline code
1715 */
1716 {
1717 int bread;
1718 uschar * commandline;
1719 uschar av_buffer[1024];
1720 uschar * linebuffer;
1721 uschar * sockline_scanner;
1722 uschar sockline_scanner_default[] = "%s\n";
1723 const pcre *sockline_trig_re;
1724 const pcre *sockline_name_re;
1725
1726 /* find scanner command line */
1727 if ( (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1728 NULL, 0))
1729 && *sockline_scanner
1730 )
1731 { /* check for no expansions apart from one %s */
1732 uschar * s = Ustrchr(sockline_scanner, '%');
1733 if (s++)
1734 if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
1735 return m_errlog_defer_3(scanent, NULL,
1736 US"unsafe sock scanner call spec", sock);
1737 }
1738 else
1739 sockline_scanner = sockline_scanner_default;
1740 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
1741 string_printing(sockline_scanner));
1742
1743 /* find scanner output trigger */
1744 sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1745 "missing trigger specification", &errstr);
1746 if (!sockline_trig_re)
1747 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1748
1749 /* find virus name regex */
1750 sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1751 "missing virus name regex specification", &errstr);
1752 if (!sockline_name_re)
1753 return m_errlog_defer_3(scanent, NULL, errstr, sock);
1754
1755 /* prepare scanner call - security depends on expansions check above */
1756 commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
1757 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
1758 string_printing(commandline));
1759
1760 /* Pass the command string to the socket */
1761 if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1762 return m_errlog_defer(scanent, CUS callout_address, errstr);
1763
1764 /* Read the result */
1765 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1766
1767 if (bread <= 0)
1768 return m_errlog_defer_3(scanent, CUS callout_address,
1769 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1770 sock);
1771
1772 if (bread == sizeof(av_buffer))
1773 return m_errlog_defer_3(scanent, CUS callout_address,
1774 US"buffer too small", sock);
1775 av_buffer[bread] = '\0';
1776 linebuffer = string_copy(av_buffer);
1777 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
1778 string_printing(linebuffer));
1779
1780 /* try trigger match */
1781 if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
1782 {
1783 if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1784 malware_name = US "unknown";
1785 DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
1786 string_printing(malware_name));
1787 }
1788 else /* no virus found */
1789 malware_name = NULL;
1790 break;
1791 }
1792
1793 case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1794 {
1795 char *mksd_options_end;
1796 int mksd_maxproc = 1; /* default, if no option supplied */
1797 int retval;
1798
1799 if (scanner_options)
1800 {
1801 mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1802 if ( *scanner_options == '\0'
1803 || *mksd_options_end != '\0'
1804 || mksd_maxproc < 1
1805 || mksd_maxproc > 32
1806 )
1807 return m_errlog_defer(scanent, CUS callout_address,
1808 string_sprintf("invalid option '%s'", scanner_options));
1809 }
1810
1811 if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1812 return m_errlog_defer(scanent, CUS callout_address, errstr);
1813
1814 malware_name = NULL;
1815
1816 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name);
1817
1818 if ((retval = mksd_scan_packed(scanent, sock, eml_filename, tmo)) != OK)
1819 {
1820 close (sock);
1821 return retval;
1822 }
1823 break;
1824 }
1825
1826 case M_AVAST: /* "avast" scanner type ----------------------------------- */
1827 {
1828 int ovector[1*3];
1829 uschar buf[1024];
1830 uschar * scanrequest;
1831 enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
1832 int nread;
1833
1834 /* According to Martin Tuma @avast the protocol uses "escaped
1835 whitespace", that is, every embedded whitespace is backslash
1836 escaped, as well as backslash is protected by backslash.
1837 The returned lines contain the name of the scanned file, a tab
1838 and the [ ] marker.
1839 [+] - not infected
1840 [L] - infected
1841 [E] - some error occured
1842 Such marker follows the first non-escaped TAB. */
1843 if ( ( !ava_re_clean
1844 && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
1845 || ( !ava_re_virus
1846 && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
1847 )
1848 return malware_errlog_defer(errstr);
1849
1850 /* wait for result */
1851 for (avast_stage = AVA_HELO;
1852 (nread = recv_line(sock, buf, sizeof(buf), tmo)) > 0;
1853 )
1854 {
1855 int slen = Ustrlen(buf);
1856 if (slen >= 1)
1857 {
1858 DEBUG(D_acl) debug_printf_indent("got from avast: %s\n", buf);
1859 switch (avast_stage)
1860 {
1861 case AVA_HELO:
1862 if (Ustrncmp(buf, "220", 3) != 0)
1863 goto endloop; /* require a 220 */
1864 goto sendreq;
1865
1866 case AVA_OPT:
1867 if (Ustrncmp(buf, "210", 3) == 0)
1868 break; /* ignore 210 responses */
1869 if (Ustrncmp(buf, "200", 3) != 0)
1870 goto endloop; /* require a 200 */
1871
1872 sendreq:
1873 {
1874 int len;
1875 /* Check for another option to send. Newline-terminate it. */
1876 if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
1877 NULL, 0)))
1878 {
1879 scanrequest = string_sprintf("%s\n", scanrequest);
1880 avast_stage = AVA_OPT; /* just sent option */
1881 }
1882 else
1883 {
1884 scanrequest = string_sprintf("SCAN %s\n", eml_dir);
1885 avast_stage = AVA_RSP; /* just sent command */
1886 }
1887
1888 /* send config-cmd or scan-request to socket */
1889 len = Ustrlen(scanrequest);
1890 if (send(sock, scanrequest, len, 0) < 0)
1891 {
1892 scanrequest[len-1] = '\0';
1893 return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
1894 "unable to send request '%s' to socket (%s): %s",
1895 scanrequest, scanner_options, strerror(errno)), sock);
1896 }
1897 break;
1898 }
1899
1900 case AVA_RSP:
1901 if (Ustrncmp(buf, "210", 3) == 0)
1902 break; /* ignore the "210 SCAN DATA" message */
1903
1904 if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
1905 0, 0, ovector, nelements(ovector)) > 0)
1906 break;
1907
1908 if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
1909 { /* remove backslash in front of [whitespace|backslash] */
1910 uschar * p, * p0;
1911 for (p = malware_name; *p; ++p)
1912 if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
1913 for (p0 = p; *p0; ++p0) *p0 = p0[1];
1914
1915 avast_stage = AVA_DONE;
1916 goto endloop;
1917 }
1918
1919 if (Ustrncmp(buf, "200 SCAN OK", 11) == 0)
1920 { /* we're done finally */
1921 if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
1922 return m_errlog_defer_3(scanent, CUS callout_address,
1923 string_sprintf(
1924 "unable to send quit request to socket (%s): %s",
1925 scanner_options, strerror(errno)),
1926 sock);
1927 malware_name = NULL;
1928 avast_stage = AVA_DONE;
1929 goto endloop;
1930 }
1931
1932 /* here for any unexpected response from the scanner */
1933 goto endloop;
1934
1935 case AVA_DONE: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
1936 __FILE__, __LINE__, __FUNCTION__);
1937 }
1938 }
1939 }
1940 endloop:
1941
1942 switch(avast_stage)
1943 {
1944 case AVA_HELO:
1945 case AVA_OPT:
1946 case AVA_RSP: return m_errlog_defer_3(scanent, CUS callout_address,
1947 nread >= 0
1948 ? string_sprintf(
1949 "invalid response from scanner: '%s'", buf)
1950 : nread == -1
1951 ? US"EOF from scanner"
1952 : US"timeout from scanner",
1953 sock);
1954 default: break;
1955 }
1956 break;
1957 }
1958
1959 case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
1960 {
1961 int bread;
1962 uschar * e;
1963 uschar * linebuffer;
1964 uschar * scanrequest;
1965 uschar av_buffer[1024];
1966
1967 if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
1968 || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
1969 return malware_errlog_defer(errstr);
1970
1971 scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
1972 DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
1973 scanner_name, scanrequest);
1974
1975 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
1976 return m_errlog_defer(scanent, CUS callout_address, errstr);
1977
1978 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
1979
1980 if (bread <= 0)
1981 return m_errlog_defer_3(scanent, CUS callout_address,
1982 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1983 sock);
1984
1985 if (bread == sizeof(av_buffer))
1986 return m_errlog_defer_3(scanent, CUS callout_address,
1987 US"buffer too small", sock);
1988
1989 av_buffer[bread] = '\0';
1990 linebuffer = string_copy(av_buffer);
1991
1992 m_sock_send(sock, US"QUIT\n", 5, 0);
1993
1994 if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
1995 return m_errlog_defer_3(scanent, CUS callout_address,
1996 string_sprintf("scanner reported error (%s)", e), sock);
1997
1998 if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
1999 malware_name = NULL;
2000
2001 break;
2002 } /* f-prot6d */
2003 } /* scanner type switch */
2004
2005 if (sock >= 0)
2006 (void) close (sock);
2007 malware_ok = TRUE; /* set "been here, done that" marker */
2008 }
2009
2010 /* match virus name against pattern (caseless ------->----------v) */
2011 if (malware_name && regex_match_and_setup(re, malware_name, 0, -1))
2012 {
2013 DEBUG(D_acl) debug_printf_indent(
2014 "Matched regex to malware [%s] [%s]\n", malware_re, malware_name);
2015 return OK;
2016 }
2017 else
2018 return FAIL;
2019 }
2020
2021
2022 /*************************************************
2023 * Scan an email for malware *
2024 *************************************************/
2025
2026 /* This is the normal interface for scanning an email, which doesn't need a
2027 filename; it's a wrapper around the malware_file function.
2028
2029 Arguments:
2030 malware_re match condition for "malware="
2031 timeout if nonzero, timeout in seconds
2032
2033 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2034 where true means malware was found (condition applies)
2035 */
2036 int
2037 malware(const uschar * malware_re, int timeout)
2038 {
2039 int ret = malware_internal(malware_re, NULL, timeout);
2040
2041 if (ret == DEFER) av_failed = TRUE;
2042 return ret;
2043 }
2044
2045
2046 /*************************************************
2047 * Scan a file for malware *
2048 *************************************************/
2049
2050 /* This is a test wrapper for scanning an email, which is not used in
2051 normal processing. Scan any file, using the Exim scanning interface.
2052 This function tampers with various global variables so is unsafe to use
2053 in any other context.
2054
2055 Arguments:
2056 eml_filename a file holding the message to be scanned
2057
2058 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
2059 where true means malware was found (condition applies)
2060 */
2061 int
2062 malware_in_file(uschar *eml_filename)
2063 {
2064 uschar message_id_buf[64];
2065 int ret;
2066
2067 /* spool_mbox() assumes various parameters exist, when creating
2068 the relevant directory and the email within */
2069
2070 (void) string_format(message_id_buf, sizeof(message_id_buf),
2071 "dummy-%d", vaguely_random_number(INT_MAX));
2072 message_id = message_id_buf;
2073 sender_address = US"malware-sender@example.net";
2074 return_path = US"";
2075 recipients_list = NULL;
2076 receive_add_recipient(US"malware-victim@example.net", -1);
2077 enable_dollar_recipients = TRUE;
2078
2079 ret = malware_internal(US"*", eml_filename, 0);
2080
2081 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
2082 spool_mbox_ok = 1;
2083
2084 /* don't set no_mbox_unspool; at present, there's no way for it to become
2085 set, but if that changes, then it should apply to these tests too */
2086
2087 unspool_mbox();
2088
2089 /* silence static analysis tools */
2090 message_id = NULL;
2091
2092 return ret;
2093 }
2094
2095
2096 void
2097 malware_init(void)
2098 {
2099 if (!malware_default_re)
2100 malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
2101 if (!drweb_re)
2102 drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
2103 if (!fsec_re)
2104 fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
2105 if (!kav_re_sus)
2106 kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
2107 if (!kav_re_inf)
2108 kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
2109 if (!ava_re_clean)
2110 ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
2111 if (!ava_re_virus)
2112 ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
2113 if (!fprot6d_re_error)
2114 fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
2115 if (!fprot6d_re_virus)
2116 fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
2117 }
2118
2119 #endif /*WITH_CONTENT_SCAN*/
2120 /*
2121 * vi: aw ai sw=2
2122 */