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