7685554ae8c50ea80b50cdb1f7464b7b70e02be5
[exim.git] / src / src / malware.c
1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
4
5 /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-2014 */
6 /* License: GPL */
7
8 /* Code for calling virus (malware) scanners. Called from acl.c. */
9
10 #include "exim.h"
11 #ifdef WITH_CONTENT_SCAN
12
13 typedef enum {M_FPROTD, M_DRWEB, M_AVES, M_FSEC, M_KAVD, M_CMDL,
14 M_SOPHIE, M_CLAMD, M_SOCK, M_MKSD} scanner_t;
15 typedef enum {MC_NONE, MC_TCP, MC_UNIX, MC_STRM} contype_t;
16 static struct scan
17 {
18 scanner_t scancode;
19 const uschar * name;
20 const uschar * options_default;
21 contype_t conn;
22 } m_scans[] =
23 {
24 { M_FPROTD, US"f-protd", US"localhost 10200-10204", MC_TCP },
25 { M_DRWEB, US"drweb", US"/usr/local/drweb/run/drwebd.sock", MC_STRM },
26 { M_AVES, US"aveserver", US"/var/run/aveserver", MC_UNIX },
27 { M_FSEC, US"fsecure", US"/var/run/.fsav", MC_UNIX },
28 { M_KAVD, US"kavdaemon", US"/var/run/AvpCtl", MC_UNIX },
29 { M_CMDL, US"cmdline", NULL, MC_NONE },
30 { M_SOPHIE, US"sophie", US"/var/run/sophie", MC_UNIX },
31 { M_CLAMD, US"clamd", US"/tmp/clamd", MC_NONE },
32 { M_SOCK, US"sock", US"/tmp/malware.sock", MC_STRM },
33 { M_MKSD, US"mksd", NULL, MC_NONE },
34 { -1, NULL, NULL, MC_NONE } /* end-marker */
35 };
36
37 /* The maximum number of clamd servers that are supported in the configuration */
38 #define MAX_CLAMD_SERVERS 32
39 #define MAX_CLAMD_SERVERS_S "32"
40 /* Maximum length of the hostname that can be specified in the clamd address list */
41 #define MAX_CLAMD_ADDRESS_LENGTH 64
42 #define MAX_CLAMD_ADDRESS_LENGTH_S "64"
43
44 typedef struct clamd_address_container {
45 uschar tcp_addr[MAX_CLAMD_ADDRESS_LENGTH+1];
46 unsigned int tcp_port;
47 } clamd_address_container;
48
49 /* declaration of private routines */
50 static int mksd_scan_packed(struct scan * scanent, int sock, uschar *scan_filename);
51 static int malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking);
52
53 #ifndef nelements
54 # define nelements(arr) (sizeof(arr) / sizeof(arr[0]))
55 #endif
56
57
58 #define MALWARE_TIMEOUT 120
59
60
61 #define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */
62 #define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */
63 #define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */
64
65 #define DERR_READ_ERR (1<<0) /* read error */
66 #define DERR_NOMEMORY (1<<2) /* no memory */
67 #define DERR_TIMEOUT (1<<9) /* scan timeout has run out */
68 #define DERR_BAD_CALL (1<<15) /* wrong command */
69
70 /* Routine to check whether a system is big- or little-endian.
71 Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
72 Needed for proper kavdaemon implementation. Sigh. */
73 #define BIG_MY_ENDIAN 0
74 #define LITTLE_MY_ENDIAN 1
75 static int test_byte_order(void);
76 static inline int
77 test_byte_order()
78 {
79 short int word = 0x0001;
80 char *byte = (char *) &word;
81 return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
82 }
83
84 BOOL malware_ok = FALSE;
85
86 /* Gross hacks for the -bmalware option; perhaps we should just create
87 the scan directory normally for that case, but look into rigging up the
88 needed header variables if not already set on the command-line? */
89 extern int spool_mbox_ok;
90 extern uschar spooled_message_id[17];
91
92 /*************************************************
93 * Scan an email for malware *
94 *************************************************/
95
96 /* This is the normal interface for scanning an email, which doesn't need a
97 filename; it's a wrapper around the malware_file function.
98
99 Arguments:
100 listptr the list of options to the "malware = ..." ACL condition
101
102 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
103 where true means malware was found (condition applies)
104 */
105 int
106 malware(uschar **listptr)
107 {
108 uschar * scan_filename;
109 int ret;
110
111 scan_filename = string_sprintf("%s/scan/%s/%s.eml",
112 spool_directory, message_id, message_id);
113 ret = malware_internal(listptr, scan_filename, FALSE);
114 if (ret == DEFER) av_failed = TRUE;
115
116 return ret;
117 }
118
119
120 /*************************************************
121 * Scan a file for malware *
122 *************************************************/
123
124 /* This is a test wrapper for scanning an email, which is not used in
125 normal processing. Scan any file, using the Exim scanning interface.
126 This function tampers with various global variables so is unsafe to use
127 in any other context.
128
129 Arguments:
130 eml_filename a file holding the message to be scanned
131
132 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
133 where true means malware was found (condition applies)
134 */
135 int
136 malware_in_file(uschar *eml_filename)
137 {
138 uschar *scan_options[2];
139 uschar message_id_buf[64];
140 int ret;
141
142 scan_options[0] = US"*";
143 scan_options[1] = NULL;
144
145 /* spool_mbox() assumes various parameters exist, when creating
146 the relevant directory and the email within */
147 (void) string_format(message_id_buf, sizeof(message_id_buf),
148 "dummy-%d", vaguely_random_number(INT_MAX));
149 message_id = message_id_buf;
150 sender_address = US"malware-sender@example.net";
151 return_path = US"";
152 recipients_list = NULL;
153 receive_add_recipient(US"malware-victim@example.net", -1);
154 enable_dollar_recipients = TRUE;
155
156 ret = malware_internal(scan_options, eml_filename, TRUE);
157
158 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
159 spool_mbox_ok = 1;
160 /* don't set no_mbox_unspool; at present, there's no way for it to become
161 set, but if that changes, then it should apply to these tests too */
162 unspool_mbox();
163
164 /* silence static analysis tools */
165 message_id = NULL;
166
167 return ret;
168 }
169
170
171 static inline int
172 malware_errlog_defer(const uschar * str)
173 {
174 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
175 return DEFER;
176 }
177
178 static int
179 m_errlog_defer(struct scan * scanent, const uschar * str)
180 {
181 return malware_errlog_defer(string_sprintf("%s: %s", scanent->name, str));
182 }
183 static int
184 m_errlog_defer_3(struct scan * scanent, const uschar * str,
185 int fd_to_close)
186 {
187 (void) close(fd_to_close);
188 return m_errlog_defer(scanent, str);
189 }
190
191 /*************************************************/
192
193 /* Only used by the Clamav code, which is working from a list of servers and
194 uses the returned in_addr to get a second connection to the same system.
195 */
196 static inline int
197 m_tcpsocket(const uschar * hostname, unsigned int port,
198 host_item * host, uschar ** errstr)
199 {
200 return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5, host, errstr);
201 }
202
203 static int
204 m_tcpsocket_fromdef(const uschar * hostport, uschar ** errstr)
205 {
206 int scan;
207 uschar hostname[256];
208 unsigned int portlow, porthigh;
209
210 /* extract host and port part */
211 scan = sscanf(CS hostport, "%255s %u-%u", hostname, &portlow, &porthigh);
212 if ( scan != 3 ) {
213 if ( scan != 2 ) {
214 *errstr = string_sprintf("invalid socket '%s'", hostport);
215 return -1;
216 }
217 porthigh = portlow;
218 }
219
220 return ip_connectedsocket(SOCK_STREAM, hostname, portlow, porthigh,
221 5, NULL, errstr);
222 }
223
224 static int
225 m_unixsocket(const uschar * path, uschar ** errstr)
226 {
227 int sock;
228 struct sockaddr_un server;
229
230 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
231 *errstr = US"can't open UNIX socket.";
232 return -1;
233 }
234
235 server.sun_family = AF_UNIX;
236 Ustrncpy(server.sun_path, path, sizeof(server.sun_path)-1);
237 server.sun_path[sizeof(server.sun_path)-1] = '\0';
238 if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
239 int err = errno;
240 (void)close(sock);
241 *errstr = string_sprintf("unable to connect to UNIX socket (%s): %s",
242 path, strerror(err));
243 return -1;
244 }
245 return sock;
246 }
247
248 static inline int
249 m_streamsocket(const uschar * spec, uschar ** errstr)
250 {
251 return *spec == '/'
252 ? m_unixsocket(spec, errstr) : m_tcpsocket_fromdef(spec, errstr);
253 }
254
255 static int
256 m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
257 {
258 if (send(sock, buf, cnt, 0) < 0) {
259 int err = errno;
260 (void)close(sock);
261 *errstr = string_sprintf("unable to send to socket (%s): %s",
262 buf, strerror(err));
263 return -1;
264 }
265 return sock;
266 }
267
268 static const pcre *
269 m_pcre_compile(const uschar * re, uschar ** errstr)
270 {
271 const uschar * rerror;
272 int roffset;
273 const pcre * cre;
274
275 cre = pcre_compile(CS re, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
276 if (!cre)
277 *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
278 re, rerror, roffset);
279 return cre;
280 }
281
282 uschar *
283 m_pcre_exec(const pcre * cre, uschar * text)
284 {
285 int ovector[10*3];
286 int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
287 ovector, nelements(ovector));
288 uschar * substr = NULL;
289 if (i >= 2) /* Got it */
290 pcre_get_substring(CS text, ovector, i, 1, (const char **) &substr);
291 return substr;
292 }
293
294 static const pcre *
295 m_pcre_nextinlist(uschar ** list, int * sep, char * listerr, uschar ** errstr)
296 {
297 const uschar * list_ele;
298 const pcre * cre = NULL;
299
300 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
301 *errstr = US listerr;
302 else
303 cre = m_pcre_compile(CUS list_ele, errstr);
304 return cre;
305 }
306
307 /*************************************************
308 * Scan content for malware *
309 *************************************************/
310
311 /* This is an internal interface for scanning an email; the normal interface
312 is via malware(), or there's malware_in_file() used for testing/debugging.
313
314 Arguments:
315 listptr the list of options to the "malware = ..." ACL condition
316 eml_filename the file holding the email to be scanned
317 faking whether or not we're faking this up for the -bmalware test
318
319 Returns: Exim message processing code (OK, FAIL, DEFER, ...)
320 where true means malware was found (condition applies)
321 */
322 static int
323 malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
324 {
325 int sep = 0;
326 uschar *list = *listptr;
327 uschar *av_scanner_work = av_scanner;
328 uschar *scanner_name;
329 uschar *malware_regex;
330 uschar malware_regex_default[] = ".+";
331 unsigned long mbox_size;
332 FILE *mbox_file;
333 const pcre *re;
334 uschar * errstr;
335 struct scan * scanent;
336 const uschar * scanner_options;
337 int sock = -1;
338
339 /* make sure the eml mbox file is spooled up */
340 if (!(mbox_file = spool_mbox(&mbox_size, faking ? eml_filename : NULL)))
341 return malware_errlog_defer(US"error while creating mbox spool file");
342
343 /* none of our current scanners need the mbox
344 file as a stream, so we can close it right away */
345 (void)fclose(mbox_file);
346
347 /* extract the malware regex to match against from the option list */
348 if (!(malware_regex = string_nextinlist(&list, &sep, NULL, 0)))
349 return FAIL; /* empty means "don't match anything" */
350
351 /* parse 1st option */
352 if ( (strcmpic(malware_regex,US"false") == 0) ||
353 (Ustrcmp(malware_regex,"0") == 0) )
354 return FAIL; /* explicitly no matching */
355
356 /* special cases (match anything except empty) */
357 if ( (strcmpic(malware_regex,US"true") == 0) ||
358 (Ustrcmp(malware_regex,"*") == 0) ||
359 (Ustrcmp(malware_regex,"1") == 0) )
360 malware_regex = malware_regex_default;
361
362 /* Reset sep that is set by previous string_nextinlist() call */
363 sep = 0;
364
365 /* compile the regex, see if it works */
366 if (!(re = m_pcre_compile(malware_regex, &errstr)))
367 return malware_errlog_defer(errstr);
368
369 /* if av_scanner starts with a dollar, expand it first */
370 if (*av_scanner == '$') {
371 if (!(av_scanner_work = expand_string(av_scanner)))
372 return malware_errlog_defer(
373 string_sprintf("av_scanner starts with $, but expansion failed: %s",
374 expand_string_message));
375
376 debug_printf("Expanded av_scanner global: %s\n", av_scanner_work);
377 /* disable result caching in this case */
378 malware_name = NULL;
379 malware_ok = FALSE;
380 }
381
382 /* Do not scan twice (unless av_scanner is dynamic). */
383 if (!malware_ok) {
384
385 /* find the scanner type from the av_scanner option */
386 if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
387 return malware_errlog_defer(US"av_scanner configuration variable is empty");
388
389 for (scanent = m_scans; ; scanent++) {
390 if (!scanent->name)
391 return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
392 scanner_name));
393 if (strcmpic(scanner_name, US scanent->name) != 0)
394 continue;
395 if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
396 scanner_options = scanent->options_default;
397 if (scanent->conn == MC_NONE)
398 break;
399 switch(scanent->conn)
400 {
401 case MC_TCP: sock = m_tcpsocket_fromdef(scanner_options, &errstr); break;
402 case MC_UNIX: sock = m_unixsocket(scanner_options, &errstr); break;
403 case MC_STRM: sock = m_streamsocket(scanner_options, &errstr); break;
404 default: /* compiler quietening */ break;
405 }
406 if (sock < 0)
407 return m_errlog_defer(scanent, errstr);
408 break;
409 }
410 DEBUG(D_lookup) debug_printf("Malware scan: %s\n", scanner_name);
411
412 switch (scanent->scancode) {
413 case M_FPROTD: /* "f-protd" scanner type -------------------------------- */
414 {
415 uschar *fp_scan_option;
416 unsigned int detected=0, par_count=0;
417 uschar * scanrequest;
418 uschar buf[32768], *strhelper, *strhelper2;
419 uschar * malware_name_internal = NULL;
420
421 DEBUG(D_acl) debug_printf("Malware scan: issuing %s GET\n", scanner_name);
422 scanrequest = string_sprintf("GET %s", eml_filename);
423
424 while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
425 NULL, 0))) {
426 scanrequest = string_sprintf("%s%s%s", scanrequest,
427 par_count ? "%20" : "?", fp_scan_option);
428 par_count++;
429 }
430 scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
431
432 /* send scan request */
433 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
434 return m_errlog_defer(scanent, errstr);
435
436 /* We get a lot of empty lines, so we need this hack to check for any data at all */
437 while( recv(sock, buf, 1, MSG_PEEK) > 0 ) {
438 if ( recv_line(sock, buf, sizeof(buf)) > 0) {
439 if ( Ustrstr(buf, US"<detected type=\"") != NULL )
440 detected = 1;
441 else if ( detected && (strhelper = Ustrstr(buf, US"<name>")) ) {
442 if ((strhelper2 = Ustrstr(buf, US"</name>")) != NULL) {
443 *strhelper2 = '\0';
444 malware_name_internal = string_copy(strhelper+6);
445 }
446 } else if ( Ustrstr(buf, US"<summary code=\"") )
447 malware_name = Ustrstr(buf, US"<summary code=\"11\">")
448 ? malware_name_internal : NULL;
449 }
450 }
451 break;
452 } /* f-protd */
453
454 case M_DRWEB: /* "drweb" scanner type ----------------------------------- */
455 /* v0.1 - added support for tcp sockets */
456 /* v0.0 - initial release -- support for unix sockets */
457 {
458 int result;
459 unsigned int fsize;
460 uschar * tmpbuf, *drweb_fbuf;
461 int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
462 drweb_vnum, drweb_slen, drweb_fin = 0x0000;
463 unsigned long bread;
464 const pcre *drweb_re;
465
466 /* prepare variables */
467 drweb_cmd = htonl(DRWEBD_SCAN_CMD);
468 drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
469
470 if (*scanner_options != '/') {
471
472 /* calc file size */
473 if ((drweb_fd = open(CS eml_filename, O_RDONLY)) == -1)
474 return m_errlog_defer_3(scanent,
475 string_sprintf("can't open spool file %s: %s",
476 eml_filename, strerror(errno)),
477 sock);
478
479 if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1) {
480 int err = errno;
481 (void)close(drweb_fd);
482 return m_errlog_defer_3(scanent,
483 string_sprintf("can't seek spool file %s: %s",
484 eml_filename, strerror(err)),
485 sock);
486 }
487 drweb_slen = htonl(fsize);
488 lseek(drweb_fd, 0, SEEK_SET);
489
490 DEBUG(D_acl) debug_printf("Malware scan: issuing %s remote scan [%s]\n",
491 scanner_name, scanner_options);
492
493 /* send scan request */
494 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
495 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
496 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
497 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0)) {
498 (void)close(drweb_fd);
499 return m_errlog_defer_3(scanent,
500 string_sprintf("unable to send commands to socket (%s)", scanner_options),
501 sock);
502 }
503
504 if (!(drweb_fbuf = (uschar *) malloc (fsize))) {
505 (void)close(drweb_fd);
506 return m_errlog_defer_3(scanent,
507 string_sprintf("unable to allocate memory %u for file (%s)",
508 fsize, eml_filename),
509 sock);
510 }
511
512 if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1) {
513 int err = errno;
514 (void)close(drweb_fd);
515 free(drweb_fbuf);
516 return m_errlog_defer_3(scanent,
517 string_sprintf("can't read spool file %s: %s",
518 eml_filename, strerror(err)),
519 sock);
520 }
521 (void)close(drweb_fd);
522
523 /* send file body to socket */
524 if (send(sock, drweb_fbuf, fsize, 0) < 0) {
525 free(drweb_fbuf);
526 return m_errlog_defer_3(scanent,
527 string_sprintf("unable to send file body to socket (%s)", scanner_options),
528 sock);
529 }
530 (void)close(drweb_fd);
531
532 } else {
533
534 drweb_slen = htonl(Ustrlen(eml_filename));
535
536 DEBUG(D_acl) debug_printf("Malware scan: issuing %s local scan [%s]\n",
537 scanner_name, scanner_options);
538
539 /* send scan request */
540 if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
541 (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
542 (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
543 (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
544 (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
545 return m_errlog_defer_3(scanent,
546 string_sprintf("unable to send commands to socket (%s)", scanner_options),
547 sock);
548 }
549
550 /* wait for result */
551 if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc)))
552 return m_errlog_defer_3(scanent,
553 US"unable to read return code", sock);
554 drweb_rc = ntohl(drweb_rc);
555
556 if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum)))
557 return m_errlog_defer_3(scanent,
558 US"unable to read the number of viruses", sock);
559 drweb_vnum = ntohl(drweb_vnum);
560
561 /* "virus(es) found" if virus number is > 0 */
562 if (drweb_vnum) {
563 int i;
564
565 /* setup default virus name */
566 malware_name = US"unknown";
567
568 /* set up match regex */
569 drweb_re = m_pcre_compile(US"infected\\swith\\s*(.+?)$", &errstr);
570
571 /* read and concatenate virus names into one string */
572 for (i=0;i<drweb_vnum;i++)
573 {
574 int size = 0, off = 0, ovector[10*3];
575 /* read the size of report */
576 if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen)))
577 return m_errlog_defer_3(scanent,
578 US"cannot read report size", sock);
579 drweb_slen = ntohl(drweb_slen);
580 tmpbuf = store_get(drweb_slen);
581
582 /* read report body */
583 if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen)
584 return m_errlog_defer_3(scanent,
585 US"cannot read report string", sock);
586 tmpbuf[drweb_slen] = '\0';
587
588 /* try matcher on the line, grab substring */
589 result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
590 ovector, nelements(ovector));
591 if (result >= 2) {
592 const char * pre_malware_nb;
593
594 pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
595
596 if (i==0) /* the first name we just copy to malware_name */
597 malware_name = string_append(NULL, &size, &off,
598 1, pre_malware_nb);
599
600 else /* concatenate each new virus name to previous */
601 malware_name = string_append(malware_name, &size, &off,
602 2, "/", pre_malware_nb);
603
604 pcre_free_substring(pre_malware_nb);
605 }
606 }
607 }
608 else {
609 const char *drweb_s = NULL;
610
611 if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
612 if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
613 if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
614 if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
615 /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
616 * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
617 * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
618 * and others are ignored */
619 if (drweb_s)
620 return m_errlog_defer_3(scanent,
621 string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
622 sock);
623
624 /* no virus found */
625 malware_name = NULL;
626 }
627 break;
628 } /* drweb */
629
630 case M_AVES: /* "aveserver" scanner type -------------------------------- */
631 {
632 uschar buf[32768];
633 int result;
634
635 /* read aveserver's greeting and see if it is ready (2xx greeting) */
636 recv_line(sock, buf, sizeof(buf));
637
638 if (buf[0] != '2') /* aveserver is having problems */
639 return m_errlog_defer_3(scanent,
640 string_sprintf("unavailable (Responded: %s).",
641 ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
642 sock);
643
644 /* prepare our command */
645 (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
646 eml_filename);
647
648 DEBUG(D_acl) debug_printf("Malware scan: issuing %s SCAN\n", scanner_name);
649
650 /* and send it */
651 if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
652 return m_errlog_defer(scanent, errstr);
653
654 malware_name = NULL;
655 result = 0;
656 /* read response lines, find malware name and final response */
657 while (recv_line(sock, buf, sizeof(buf)) > 0) {
658 debug_printf("aveserver: %s\n", buf);
659 if (buf[0] == '2')
660 break;
661 if (buf[0] == '5') { /* aveserver is having problems */
662 result = m_errlog_defer(scanent,
663 string_sprintf("unable to scan file %s (Responded: %s).",
664 eml_filename, buf));
665 break;
666 } else if (Ustrncmp(buf,"322",3) == 0) {
667 uschar *p = Ustrchr(&buf[4],' ');
668 *p = '\0';
669 malware_name = string_copy(&buf[4]);
670 }
671 }
672
673 /* and send it */
674 if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
675 return m_errlog_defer(scanent, errstr);
676
677 /* read aveserver's greeting and see if it is ready (2xx greeting) */
678 recv_line(sock, buf, sizeof(buf));
679
680 if (buf[0] != '2') /* aveserver is having problems */
681 return m_errlog_defer_3(scanent,
682 string_sprintf("unable to quit dialogue (Responded: %s).",
683 ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
684 sock);
685
686 if (result == DEFER) {
687 (void)close(sock);
688 return DEFER;
689 }
690 break;
691 } /* aveserver */
692
693 case M_FSEC: /* "fsecure" scanner type ---------------------------------- */
694 {
695 int i, j, bread = 0;
696 uschar * file_name;
697 uschar av_buffer[1024];
698 const pcre * fs_inf;
699 static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
700 US"CONFIGURE\tTIMEOUT\t0\n",
701 US"CONFIGURE\tMAXARCH\t5\n",
702 US"CONFIGURE\tMIME\t1\n" };
703
704 malware_name = NULL;
705
706 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
707 scanner_name, scanner_options);
708
709 /* pass options */
710 memset(av_buffer, 0, sizeof(av_buffer));
711 for (i=0; i != nelements(cmdopt); i++) {
712
713 if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
714 return m_errlog_defer(scanent, errstr);
715
716 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT);
717 if (bread >0) av_buffer[bread]='\0';
718 if (bread < 0)
719 return m_errlog_defer_3(scanent,
720 string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
721 sock);
722 for (j=0;j<bread;j++)
723 if((av_buffer[j]=='\r')||(av_buffer[j]=='\n'))
724 av_buffer[j] ='@';
725 }
726
727 /* pass the mailfile to fsecure */
728 file_name = string_sprintf("SCAN\t%s\n", eml_filename);
729
730 if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
731 return m_errlog_defer(scanent, errstr);
732
733 /* set up match */
734 /* todo also SUSPICION\t */
735 fs_inf = m_pcre_compile(US"\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$", &errstr);
736
737 /* read report, linewise */
738 do {
739 i = 0;
740 memset(av_buffer, 0, sizeof(av_buffer));
741 do {
742 if ((bread= ip_recv(sock, &av_buffer[i], 1, MALWARE_TIMEOUT)) < 0)
743 return m_errlog_defer_3(scanent,
744 string_sprintf("unable to read result (%s)", strerror(errno)),
745 sock);
746 } while (++i < sizeof(av_buffer)-1 && av_buffer[i-1] != '\n');
747 av_buffer[i-1] = '\0';
748
749 /* Really search for virus again? */
750 if (malware_name == NULL)
751 /* try matcher on the line, grab substring */
752 malware_name = m_pcre_exec(fs_inf, av_buffer);
753 }
754 while (Ustrstr(av_buffer, "OK\tScan ok.") == NULL);
755 break;
756 } /* fsecure */
757
758 case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */
759 {
760 time_t t;
761 uschar tmpbuf[1024];
762 uschar * scanrequest;
763 int kav_rc;
764 unsigned long kav_reportlen, bread;
765 const pcre *kav_re;
766 uschar *p;
767
768 /* get current date and time, build scan request */
769 time(&t);
770 /* pdp note: before the eml_filename parameter, this scanned the
771 directory; not finding documentation, so we'll strip off the directory.
772 The side-effect is that the test framework scanning may end up in
773 scanning more than was requested, but for the normal interface, this is
774 fine. */
775
776 strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
777 scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
778 p = Ustrrchr(scanrequest, '/');
779 if (p)
780 *p = '\0';
781
782 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
783 scanner_name, scanner_options);
784
785 /* send scan request */
786 if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
787 return m_errlog_defer(scanent, errstr);
788
789 /* wait for result */
790 if ((bread = recv(sock, tmpbuf, 2, 0) != 2))
791 return m_errlog_defer_3(scanent,
792 US"unable to read 2 bytes from socket.", sock);
793
794 /* get errorcode from one nibble */
795 kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F;
796 switch(kav_rc)
797 {
798 case 5: case 6: /* improper kavdaemon configuration */
799 return m_errlog_defer_3(scanent,
800 US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
801 sock);
802 case 1:
803 return m_errlog_defer_3(scanent,
804 US"reported 'scanning not completed' (code 1).", sock);
805 case 7:
806 return m_errlog_defer_3(scanent,
807 US"reported 'kavdaemon damaged' (code 7).", sock);
808 }
809
810 /* code 8 is not handled, since it is ambigous. It appears mostly on
811 bounces where part of a file has been cut off */
812
813 /* "virus found" return codes (2-4) */
814 if ((kav_rc > 1) && (kav_rc < 5)) {
815 int report_flag = 0;
816
817 /* setup default virus name */
818 malware_name = US"unknown";
819
820 report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
821
822 /* read the report, if available */
823 if( report_flag == 1 ) {
824 /* read report size */
825 if ((bread = recv(sock, &kav_reportlen, 4, 0)) != 4)
826 return m_errlog_defer_3(scanent,
827 US"cannot read report size", sock);
828
829 /* it's possible that avp returns av_buffer[1] == 1 but the
830 reportsize is 0 (!?) */
831 if (kav_reportlen > 0) {
832 /* set up match regex, depends on retcode */
833 kav_re = m_pcre_compile( kav_rc == 3
834 ? US"suspicion:\\s*(.+?)\\s*$"
835 : US"infected:\\s*(.+?)\\s*$",
836 &errstr );
837
838 /* read report, linewise */
839 while (kav_reportlen > 0) {
840 bread = 0;
841 while ( recv(sock, &tmpbuf[bread], 1, 0) == 1 ) {
842 kav_reportlen--;
843 if ( (tmpbuf[bread] == '\n') || (bread > 1021) ) break;
844 bread++;
845 }
846 bread++;
847 tmpbuf[bread] = '\0';
848
849 /* try matcher on the line, grab substring */
850 if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
851 break;
852 }
853 }
854 }
855 }
856 else /* no virus found */
857 malware_name = NULL;
858
859 break;
860 }
861
862 case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
863 {
864 const uschar *cmdline_scanner = scanner_options;
865 const pcre *cmdline_trigger_re;
866 const pcre *cmdline_regex_re;
867 uschar * file_name;
868 uschar * commandline;
869 void (*eximsigchld)(int);
870 void (*eximsigpipe)(int);
871 FILE *scanner_out = NULL;
872 FILE *scanner_record = NULL;
873 uschar linebuffer[32767];
874 int trigger = 0;
875 uschar *p;
876
877 if (!cmdline_scanner)
878 return m_errlog_defer(scanent, errstr);
879
880 /* find scanner output trigger */
881 cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
882 "missing trigger specification", &errstr);
883 if (!cmdline_trigger_re)
884 return m_errlog_defer(scanent, errstr);
885
886 /* find scanner name regex */
887 cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
888 "missing virus name regex specification", &errstr);
889 if (!cmdline_regex_re)
890 return m_errlog_defer(scanent, errstr);
891
892 /* prepare scanner call; despite the naming, file_name holds a directory
893 name which is documented as the value given to %s. */
894
895 file_name = string_copy(eml_filename);
896 p = Ustrrchr(file_name, '/');
897 if (p)
898 *p = '\0';
899 commandline = string_sprintf(CS cmdline_scanner, file_name);
900
901 /* redirect STDERR too */
902 commandline = string_sprintf("%s 2>&1", commandline);
903
904 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n", scanner_name, commandline);
905
906 /* store exims signal handlers */
907 eximsigchld = signal(SIGCHLD,SIG_DFL);
908 eximsigpipe = signal(SIGPIPE,SIG_DFL);
909
910 if (!(scanner_out = popen(CS commandline,"r"))) {
911 int err = errno;
912 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
913 return m_errlog_defer(scanent,
914 string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
915 }
916
917 file_name = string_sprintf("%s/scan/%s/%s_scanner_output",
918 spool_directory, message_id, message_id);
919 scanner_record = modefopen(file_name, "wb", SPOOL_MODE);
920
921 if (scanner_record == NULL) {
922 int err = errno;
923 (void) pclose(scanner_out);
924 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
925 return m_errlog_defer(scanent,
926 string_sprintf("opening scanner output file (%s) failed: %s.",
927 file_name, strerror(err)));
928 }
929
930 /* look for trigger while recording output */
931 while(fgets(CS linebuffer, sizeof(linebuffer), scanner_out)) {
932 if ( Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record) ) {
933 /* short write */
934 (void) pclose(scanner_out);
935 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
936 return m_errlog_defer(scanent,
937 string_sprintf("short write on scanner output file (%s).", file_name));
938 }
939 /* try trigger match */
940 if (!trigger && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1))
941 trigger = 1;
942 }
943
944 (void)fclose(scanner_record);
945 sep = pclose(scanner_out);
946 signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
947 if (sep != 0)
948 return m_errlog_defer(scanent,
949 sep == -1
950 ? string_sprintf("running scanner failed: %s", strerror(sep))
951 : string_sprintf("scanner returned error code: %d", sep));
952
953 if (trigger) {
954 uschar * s;
955 /* setup default virus name */
956 malware_name = US"unknown";
957
958 /* re-open the scanner output file, look for name match */
959 scanner_record = fopen(CS file_name, "rb");
960 while(fgets(CS linebuffer, sizeof(linebuffer), scanner_record)) {
961 /* try match */
962 if ((s = m_pcre_exec(cmdline_regex_re, linebuffer)))
963 malware_name = s;
964 }
965 (void)fclose(scanner_record);
966 }
967 else /* no virus found */
968 malware_name = NULL;
969 break;
970 } /* cmdline */
971
972 case M_SOPHIE: /* "sophie" scanner type --------------------------------- */
973 {
974 int bread = 0;
975 uschar *p;
976 uschar * file_name;
977 uschar av_buffer[1024];
978
979 /* pass the scan directory to sophie */
980 file_name = string_copy(eml_filename);
981 if ((p = Ustrrchr(file_name, '/')))
982 *p = '\0';
983
984 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
985 scanner_name, scanner_options);
986
987 if ( write(sock, file_name, Ustrlen(file_name)) < 0
988 || write(sock, "\n", 1) != 1
989 )
990 return m_errlog_defer_3(scanent,
991 string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
992 sock);
993
994 /* wait for result */
995 memset(av_buffer, 0, sizeof(av_buffer));
996 if ((!(bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT)) > 0))
997 return m_errlog_defer_3(scanent,
998 string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
999 sock);
1000
1001 /* infected ? */
1002 if (av_buffer[0] == '1') {
1003 uschar * s = Ustrchr(av_buffer, '\n');
1004 if (s)
1005 *s = '\0';
1006 malware_name = string_copy(&av_buffer[2]);
1007 }
1008 else if (!strncmp(CS av_buffer, "-1", 2))
1009 return m_errlog_defer_3(scanent, US"scanner reported error", sock);
1010 else /* all ok, no virus */
1011 malware_name = NULL;
1012
1013 break;
1014 }
1015
1016 case M_CLAMD: /* "clamd" scanner type ----------------------------------- */
1017 {
1018 /* This code was originally contributed by David Saez */
1019 /* There are three scanning methods available to us:
1020 * (1) Use the SCAN command, pointing to a file in the filesystem
1021 * (2) Use the STREAM command, send the data on a separate port
1022 * (3) Use the zINSTREAM command, send the data inline
1023 * The zINSTREAM command was introduced with ClamAV 0.95, which marked
1024 * STREAM deprecated; see: http://wiki.clamav.net/bin/view/Main/UpgradeNotes095
1025 * In Exim, we use SCAN if using a Unix-domain socket or explicitly told that
1026 * the TCP-connected daemon is actually local; otherwise we use zINSTREAM unless
1027 * WITH_OLD_CLAMAV_STREAM is defined.
1028 * See Exim bug 926 for details. */
1029
1030 uschar *p, *vname, *result_tag, *response_end;
1031 int bread=0;
1032 uschar * file_name;
1033 uschar av_buffer[1024];
1034 uschar *hostname = US"";
1035 host_item connhost;
1036 uschar *clamav_fbuf;
1037 int clam_fd, result;
1038 unsigned int fsize;
1039 BOOL use_scan_command = FALSE;
1040 clamd_address_container * clamd_address_vector[MAX_CLAMD_SERVERS];
1041 int current_server;
1042 int num_servers = 0;
1043 #ifdef WITH_OLD_CLAMAV_STREAM
1044 unsigned int port;
1045 uschar av_buffer2[1024];
1046 int sockData;
1047 #else
1048 uint32_t send_size, send_final_zeroblock;
1049 #endif
1050
1051 if (*scanner_options == '/')
1052 /* Local file; so we def want to use_scan_command and don't want to try
1053 * passing IP/port combinations */
1054 use_scan_command = TRUE;
1055 else {
1056 const uschar *address = scanner_options;
1057 uschar address_buffer[MAX_CLAMD_ADDRESS_LENGTH + 20];
1058
1059 /* Go through the rest of the list of host/port and construct an array
1060 * of servers to try. The first one is the bit we just passed from
1061 * scanner_options so process that first and then scan the remainder of
1062 * the address buffer */
1063 do {
1064 clamd_address_container *this_clamd;
1065
1066 /* The 'local' option means use the SCAN command over the network
1067 * socket (ie common file storage in use) */
1068 if (strcmpic(address,US"local") == 0) {
1069 use_scan_command = TRUE;
1070 continue;
1071 }
1072
1073 /* XXX: If unsuccessful we should free this memory */
1074 this_clamd =
1075 (clamd_address_container *)store_get(sizeof(clamd_address_container));
1076
1077 /* extract host and port part */
1078 if( sscanf(CS address, "%" MAX_CLAMD_ADDRESS_LENGTH_S "s %u",
1079 this_clamd->tcp_addr, &(this_clamd->tcp_port)) != 2 ) {
1080 (void) m_errlog_defer(scanent,
1081 string_sprintf("invalid address '%s'", address));
1082 continue;
1083 }
1084
1085 clamd_address_vector[num_servers] = this_clamd;
1086 num_servers++;
1087 if (num_servers >= MAX_CLAMD_SERVERS) {
1088 (void) m_errlog_defer(scanent,
1089 US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
1090 "specified; only using the first " MAX_CLAMD_SERVERS_S );
1091 break;
1092 }
1093 } while ((address = string_nextinlist(&av_scanner_work, &sep,
1094 address_buffer,
1095 sizeof(address_buffer))) != NULL);
1096
1097 /* check if we have at least one server */
1098 if (!num_servers)
1099 return m_errlog_defer(scanent,
1100 US"no useable server addresses in malware configuration option.");
1101 }
1102
1103 /* See the discussion of response formats below to see why we really don't
1104 like colons in filenames when passing filenames to ClamAV. */
1105 if (use_scan_command && Ustrchr(eml_filename, ':'))
1106 return m_errlog_defer(scanent,
1107 string_sprintf("local/SCAN mode incompatible with" \
1108 " : in path to email filename [%s]", eml_filename));
1109
1110 /* We have some network servers specified */
1111 if (num_servers) {
1112
1113 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1114 * only supports AF_INET, but we should probably be looking to the
1115 * future and rewriting this to be protocol-independent anyway. */
1116
1117 while ( num_servers > 0 ) {
1118 /* Randomly pick a server to start with */
1119 current_server = random_number( num_servers );
1120
1121 debug_printf("trying server name %s, port %u\n",
1122 clamd_address_vector[current_server]->tcp_addr,
1123 clamd_address_vector[current_server]->tcp_port);
1124
1125 /* Lookup the host. This is to ensure that we connect to the same IP
1126 * on both connections (as one host could resolve to multiple ips) */
1127 sock= m_tcpsocket(clamd_address_vector[current_server]->tcp_addr,
1128 clamd_address_vector[current_server]->tcp_port,
1129 &connhost, &errstr);
1130 if (sock >= 0) {
1131 /* Connection successfully established with a server */
1132 hostname = clamd_address_vector[current_server]->tcp_addr;
1133 break;
1134 }
1135
1136 (void) m_errlog_defer(scanent, errstr);
1137
1138 /* Remove the server from the list. XXX We should free the memory */
1139 num_servers--;
1140 int i;
1141 for( i = current_server; i < num_servers; i++ )
1142 clamd_address_vector[i] = clamd_address_vector[i+1];
1143 }
1144
1145 if ( num_servers == 0 )
1146 return m_errlog_defer(scanent, US"all servers failed");
1147
1148 } else {
1149 if ((sock = m_unixsocket(scanner_options, &errstr)) < 0)
1150 return m_errlog_defer(scanent, errstr);
1151 }
1152
1153 /* have socket in variable "sock"; command to use is semi-independent of
1154 * the socket protocol. We use SCAN if is local (either Unix/local
1155 * domain socket, or explicitly told local) else we stream the data.
1156 * How we stream the data depends upon how we were built. */
1157
1158 if (!use_scan_command) {
1159
1160 #ifdef WITH_OLD_CLAMAV_STREAM
1161 /* "STREAM\n" command, get back a "PORT <N>\n" response, send data to
1162 * that port on a second connection; then in the scan-method-neutral
1163 * part, read the response back on the original connection. */
1164
1165 DEBUG(D_acl) debug_printf("Malware scan: issuing %s old-style remote scan (PORT)\n",
1166 scanner_name);
1167
1168 /* Pass the string to ClamAV (7 = "STREAM\n") */
1169 if (m_sock_send(sock, US"STREAM\n", 7, &errstr) < 0)
1170 return m_errlog_defer(scanent, errstr);
1171
1172 memset(av_buffer2, 0, sizeof(av_buffer2));
1173 bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), MALWARE_TIMEOUT);
1174
1175 if (bread < 0)
1176 return m_errlog_defer_3(scanent,
1177 string_sprintf("unable to read PORT from socket (%s)",
1178 strerror(errno)),
1179 sock);
1180
1181 if (bread == sizeof(av_buffer2))
1182 return m_errlog_defer_3(scanent, "buffer too small", sock);
1183
1184 if (!(*av_buffer2))
1185 return m_errlog_defer_3(scanent, "ClamAV returned null", sock);
1186
1187 av_buffer2[bread] = '\0';
1188 if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 )
1189 return m_errlog_defer_3(scanent,
1190 string_sprintf("Expected port information from clamd, got '%s'",
1191 av_buffer2),
1192 sock);
1193
1194 sockData = m_tcpsocket(connhost.address, port, NULL, &errstr);
1195 if (sockData < 0)
1196 return m_errlog_defer_3(scanent, errstr, sock);
1197
1198 #define CLOSE_SOCKDATA (void)close(sockData)
1199 #else /* WITH_OLD_CLAMAV_STREAM not defined */
1200 /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1201 chunks, <n> a 4-byte number (network order), terminated by a zero-length
1202 chunk. */
1203
1204 DEBUG(D_acl) debug_printf("Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1205 scanner_name);
1206
1207 /* Pass the string to ClamAV (10 = "zINSTREAM\0") */
1208 if (send(sock, "zINSTREAM", 10, 0) < 0)
1209 return m_errlog_defer_3(scanent,
1210 string_sprintf("unable to send zINSTREAM to socket (%s)",
1211 strerror(errno)),
1212 sock);
1213
1214 #define CLOSE_SOCKDATA /**/
1215 #endif
1216
1217 /* calc file size */
1218 if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0) {
1219 int err = errno;
1220 CLOSE_SOCKDATA;
1221 return m_errlog_defer_3(scanent,
1222 string_sprintf("can't open spool file %s: %s",
1223 eml_filename, strerror(err)),
1224 sock);
1225 }
1226 if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0) {
1227 int err = errno;
1228 CLOSE_SOCKDATA; (void)close(clam_fd);
1229 return m_errlog_defer_3(scanent,
1230 string_sprintf("can't seek spool file %s: %s",
1231 eml_filename, strerror(err)),
1232 sock);
1233 }
1234 lseek(clam_fd, 0, SEEK_SET);
1235
1236 if (!(clamav_fbuf = (uschar *) malloc (fsize))) {
1237 CLOSE_SOCKDATA; (void)close(clam_fd);
1238 return m_errlog_defer_3(scanent,
1239 string_sprintf("unable to allocate memory %u for file (%s)",
1240 fsize, eml_filename),
1241 sock);
1242 }
1243
1244 if ((result = read(clam_fd, clamav_fbuf, fsize)) < 0) {
1245 int err = errno;
1246 free(clamav_fbuf); CLOSE_SOCKDATA; (void)close(clam_fd);
1247 return m_errlog_defer_3(scanent,
1248 string_sprintf("can't read spool file %s: %s",
1249 eml_filename, strerror(err)),
1250 sock);
1251 }
1252 (void)close(clam_fd);
1253
1254 /* send file body to socket */
1255 #ifdef WITH_OLD_CLAMAV_STREAM
1256 if (send(sockData, clamav_fbuf, fsize, 0) < 0) {
1257 free(clamav_fbuf); CLOSE_SOCKDATA;
1258 return m_errlog_defer_3(scanent,
1259 string_sprintf("unable to send file body to socket (%s:%u)",
1260 hostname, port),
1261 sock);
1262 }
1263 #else
1264 send_size = htonl(fsize);
1265 send_final_zeroblock = 0;
1266 if ((send(sock, &send_size, sizeof(send_size), 0) < 0) ||
1267 (send(sock, clamav_fbuf, fsize, 0) < 0) ||
1268 (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1269 {
1270 free(clamav_fbuf);
1271 return m_errlog_defer_3(scanent,
1272 string_sprintf("unable to send file body to socket (%s)", hostname),
1273 sock);
1274 }
1275 #endif
1276
1277 free(clamav_fbuf);
1278
1279 CLOSE_SOCKDATA;
1280 #undef CLOSE_SOCKDATA
1281
1282 } else { /* use scan command */
1283 /* Send a SCAN command pointing to a filename; then in the then in the
1284 * scan-method-neutral part, read the response back */
1285
1286 /* ================================================================= */
1287
1288 /* Prior to the reworking post-Exim-4.72, this scanned a directory,
1289 which dates to when ClamAV needed us to break apart the email into the
1290 MIME parts (eg, with the now deprecated demime condition coming first).
1291 Some time back, ClamAV gained the ability to deconstruct the emails, so
1292 doing this would actually have resulted in the mail attachments being
1293 scanned twice, in the broken out files and from the original .eml.
1294 Since ClamAV now handles emails (and has for quite some time) we can
1295 just use the email file itself. */
1296 /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
1297 file_name = string_sprintf("SCAN %s\n", eml_filename);
1298
1299 DEBUG(D_acl) debug_printf("Malware scan: issuing %s local-path scan [%s]\n",
1300 scanner_name, scanner_options);
1301
1302 if (send(sock, file_name, Ustrlen(file_name), 0) < 0)
1303 return m_errlog_defer_3(scanent,
1304 string_sprintf("unable to write to socket (%s)", strerror(errno)),
1305 sock);
1306
1307 /* Do not shut down the socket for writing; a user report noted that
1308 * clamd 0.70 does not react well to this. */
1309 }
1310 /* Commands have been sent, no matter which scan method or connection
1311 * type we're using; now just read the result, independent of method. */
1312
1313 /* Read the result */
1314 memset(av_buffer, 0, sizeof(av_buffer));
1315 bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT);
1316 (void)close(sock);
1317 sock = -1;
1318
1319 if (!(bread > 0))
1320 return m_errlog_defer(scanent,
1321 string_sprintf("unable to read from socket (%s)", strerror(errno)));
1322
1323 if (bread == sizeof(av_buffer))
1324 return m_errlog_defer(scanent, US"buffer too small");
1325 /* We're now assured of a NULL at the end of av_buffer */
1326
1327 /* Check the result. ClamAV returns one of two result formats.
1328 In the basic mode, the response is of the form:
1329 infected: -> "<filename>: <virusname> FOUND"
1330 not-infected: -> "<filename>: OK"
1331 error: -> "<filename>: <errcode> ERROR
1332 If the ExtendedDetectionInfo option has been turned on, then we get:
1333 "<filename>: <virusname>(<virushash>:<virussize>) FOUND"
1334 for the infected case. Compare:
1335 /tmp/eicar.com: Eicar-Test-Signature FOUND
1336 /tmp/eicar.com: Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68) FOUND
1337
1338 In the streaming case, clamd uses the filename "stream" which you should
1339 be able to verify with { ktrace clamdscan --stream /tmp/eicar.com }. (The
1340 client app will replace "stream" with the original filename before returning
1341 results to stdout, but the trace shows the data).
1342
1343 We will assume that the pathname passed to clamd from Exim does not contain
1344 a colon. We will have whined loudly above if the eml_filename does (and we're
1345 passing a filename to clamd). */
1346
1347 if (!(*av_buffer))
1348 return m_errlog_defer(scanent, US"ClamAV returned null");
1349
1350 /* strip newline at the end (won't be present for zINSTREAM)
1351 (also any trailing whitespace, which shouldn't exist, but we depend upon
1352 this below, so double-check) */
1353 p = av_buffer + Ustrlen(av_buffer) - 1;
1354 if (*p == '\n') *p = '\0';
1355
1356 DEBUG(D_acl) debug_printf("Malware response: %s\n", av_buffer);
1357
1358 while (isspace(*--p) && (p > av_buffer))
1359 *p = '\0';
1360 if (*p) ++p;
1361 response_end = p;
1362
1363 /* colon in returned output? */
1364 if((p = Ustrchr(av_buffer,':')) == NULL)
1365 return m_errlog_defer(scanent,
1366 string_sprintf("ClamAV returned malformed result (missing colon): %s",
1367 av_buffer));
1368
1369 /* strip filename */
1370 while (*p && isspace(*++p)) /**/;
1371 vname = p;
1372
1373 /* It would be bad to encounter a virus with "FOUND" in part of the name,
1374 but we should at least be resistant to it. */
1375 p = Ustrrchr(vname, ' ');
1376 result_tag = p ? p+1 : vname;
1377
1378 if (Ustrcmp(result_tag, "FOUND") == 0) {
1379 /* p should still be the whitespace before the result_tag */
1380 while (isspace(*p)) --p;
1381 *++p = '\0';
1382 /* Strip off the extended information too, which will be in parens
1383 after the virus name, with no intervening whitespace. */
1384 if (*--p == ')') {
1385 /* "(hash:size)", so previous '(' will do; if not found, we have
1386 a curious virus name, but not an error. */
1387 p = Ustrrchr(vname, '(');
1388 if (p)
1389 *p = '\0';
1390 }
1391 malware_name = string_copy(vname);
1392 DEBUG(D_acl) debug_printf("Malware found, name \"%s\"\n", malware_name);
1393
1394 } else if (Ustrcmp(result_tag, "ERROR") == 0)
1395 return m_errlog_defer(scanent,
1396 string_sprintf("ClamAV returned: %s", av_buffer));
1397
1398 else if (Ustrcmp(result_tag, "OK") == 0) {
1399 /* Everything should be OK */
1400 malware_name = NULL;
1401 DEBUG(D_acl) debug_printf("Malware not found\n");
1402
1403 } else
1404 return m_errlog_defer(scanent,
1405 string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
1406
1407 break;
1408 } /* clamd */
1409
1410 case M_SOCK: /* "sock" scanner type ------------------------------------- */
1411 /* This code was derived by Martin Poole from the clamd code contributed
1412 by David Saez and the cmdline code
1413 */
1414 {
1415 int bread;
1416 uschar * commandline;
1417 uschar av_buffer[1024];
1418 uschar * linebuffer;
1419 uschar * sockline_scanner;
1420 uschar sockline_scanner_default[] = "%s\n";
1421 const pcre *sockline_trig_re;
1422 const pcre *sockline_name_re;
1423
1424 /* find scanner command line */
1425 if ((sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1426 NULL, 0)))
1427 { /* check for no expansions apart from one %s */
1428 char * s = index(CS sockline_scanner, '%');
1429 if (s++)
1430 if ((*s != 's' && *s != '%') || index(s+1, '%'))
1431 return m_errlog_defer_3(scanent,
1432 US"unsafe sock scanner call spec", sock);
1433 }
1434 else
1435 sockline_scanner = sockline_scanner_default;
1436
1437 /* find scanner output trigger */
1438 sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1439 "missing trigger specification", &errstr);
1440 if (!sockline_trig_re)
1441 return m_errlog_defer_3(scanent, errstr, sock);
1442
1443 /* find virus name regex */
1444 sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
1445 "missing virus name regex specification", &errstr);
1446 if (!sockline_name_re)
1447 return m_errlog_defer_3(scanent, errstr, sock);
1448
1449 /* prepare scanner call - security depends on expansions check above */
1450 commandline = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
1451 commandline = string_sprintf( CS sockline_scanner, CS commandline);
1452
1453
1454 /* Pass the command string to the socket */
1455 if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
1456 return m_errlog_defer(scanent, errstr);
1457
1458 /* Read the result */
1459 memset(av_buffer, 0, sizeof(av_buffer));
1460 bread = read(sock, av_buffer, sizeof(av_buffer));
1461
1462 if (!(bread > 0))
1463 return m_errlog_defer_3(scanent,
1464 string_sprintf("unable to read from socket (%s)", strerror(errno)),
1465 sock);
1466
1467 if (bread == sizeof(av_buffer))
1468 return m_errlog_defer_3(scanent, US"buffer too small", sock);
1469 linebuffer = string_copy(av_buffer);
1470
1471 /* try trigger match */
1472 if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1)) {
1473 if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
1474 malware_name = US "unknown";
1475 }
1476 else /* no virus found */
1477 malware_name = NULL;
1478 break;
1479 }
1480
1481 case M_MKSD: /* "mksd" scanner type ------------------------------------- */
1482 {
1483 char *mksd_options_end;
1484 int mksd_maxproc = 1; /* default, if no option supplied */
1485 int sock;
1486 int retval;
1487
1488 if (scanner_options) {
1489 mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10);
1490 if ( *scanner_options == '\0'
1491 || *mksd_options_end != '\0'
1492 || mksd_maxproc < 1
1493 || mksd_maxproc > 32
1494 )
1495 return m_errlog_defer(scanent,
1496 string_sprintf("invalid option '%s'", scanner_options));
1497 }
1498
1499 if((sock = m_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
1500 return m_errlog_defer(scanent, errstr);
1501
1502 malware_name = NULL;
1503
1504 DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan\n", scanner_name);
1505
1506 if ((retval = mksd_scan_packed(scanent, sock, eml_filename)) != OK) {
1507 close (sock);
1508 return retval;
1509 }
1510 break;
1511 }
1512 }
1513
1514 if (sock >= 0)
1515 (void) close (sock);
1516 malware_ok = TRUE; /* set "been here, done that" marker */
1517 }
1518
1519 /* match virus name against pattern (caseless ------->----------v) */
1520 if ( malware_name && (regex_match_and_setup(re, malware_name, 0, -1)) ) {
1521 DEBUG(D_acl) debug_printf("Matched regex to malware [%s] [%s]\n", malware_regex, malware_name);
1522 return OK;
1523 }
1524 else
1525 return FAIL;
1526 }
1527
1528
1529 /* simple wrapper for reading lines from sockets */
1530 int
1531 recv_line(int sock, uschar *buffer, int size)
1532 {
1533 uschar *p = buffer;
1534
1535 memset(buffer,0,size);
1536 /* read until \n */
1537 while(recv(sock,p,1,0) > -1) {
1538 if ((p-buffer) > (size-2)) break;
1539 if (*p == '\n') break;
1540 if (*p != '\r') p++;
1541 }
1542 *p = '\0';
1543
1544 return (p-buffer);
1545 }
1546
1547
1548 /* ============= private routines for the "mksd" scanner type ============== */
1549
1550 #include <sys/uio.h>
1551
1552 static inline int
1553 mksd_writev (int sock, struct iovec *iov, int iovcnt)
1554 {
1555 int i;
1556
1557 for (;;) {
1558 do
1559 i = writev (sock, iov, iovcnt);
1560 while ((i < 0) && (errno == EINTR));
1561 if (i <= 0) {
1562 (void) malware_errlog_defer(US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
1563 return -1;
1564 }
1565
1566 for (;;)
1567 if (i >= iov->iov_len) {
1568 if (--iovcnt == 0)
1569 return 0;
1570 i -= iov->iov_len;
1571 iov++;
1572 } else {
1573 iov->iov_len -= i;
1574 iov->iov_base = CS iov->iov_base + i;
1575 break;
1576 }
1577 }
1578 }
1579
1580 static inline int
1581 mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size)
1582 {
1583 int offset = 0;
1584 int i;
1585
1586 do {
1587 if ((i = recv (sock, av_buffer+offset, av_buffer_size-offset, 0)) <= 0) {
1588 (void) malware_errlog_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
1589 return -1;
1590 }
1591
1592 offset += i;
1593 /* offset == av_buffer_size -> buffer full */
1594 if (offset == av_buffer_size) {
1595 (void) malware_errlog_defer(US"malformed reply received from mksd");
1596 return -1;
1597 }
1598 } while (av_buffer[offset-1] != '\n');
1599
1600 av_buffer[offset] = '\0';
1601 return offset;
1602 }
1603
1604 static inline int
1605 mksd_parse_line(struct scan * scanent, char *line)
1606 {
1607 char *p;
1608
1609 switch (*line) {
1610 case 'O': /* OK */
1611 return OK;
1612
1613 case 'E':
1614 case 'A': /* ERR */
1615 if ((p = strchr (line, '\n')) != NULL)
1616 *p = '\0';
1617 return m_errlog_defer(scanent,
1618 string_sprintf("scanner failed: %s", line));
1619
1620 default: /* VIR */
1621 if ((p = strchr (line, '\n')) != NULL) {
1622 *p = '\0';
1623 if (((p-line) > 5) && (line[3] == ' '))
1624 if (((p = strchr (line+4, ' ')) != NULL) && ((p-line) > 4)) {
1625 *p = '\0';
1626 malware_name = string_copy(US line+4);
1627 return OK;
1628 }
1629 }
1630 return m_errlog_defer(scanent,
1631 string_sprintf("malformed reply received: %s", line));
1632 }
1633 }
1634
1635 static int
1636 mksd_scan_packed(struct scan * scanent, int sock, uschar *scan_filename)
1637 {
1638 struct iovec iov[3];
1639 const char *cmd = "MSQ\n";
1640 uschar av_buffer[1024];
1641
1642 iov[0].iov_base = (void *) cmd;
1643 iov[0].iov_len = 3;
1644 iov[1].iov_base = CS scan_filename;
1645 iov[1].iov_len = Ustrlen(scan_filename);
1646 iov[2].iov_base = (void *) (cmd + 3);
1647 iov[2].iov_len = 1;
1648
1649 if (mksd_writev (sock, iov, 3) < 0)
1650 return DEFER;
1651
1652 if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer)) < 0)
1653 return DEFER;
1654
1655 return mksd_parse_line (scanent, CS av_buffer);
1656 }
1657
1658 #endif /*WITH_CONTENT_SCAN*/
1659 /*
1660 * vi: aw ai sw=2
1661 */