PageRenderTime 59ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/src/malware.c

https://gitlab.com/Exim/exim
C | 2022 lines | 1452 code | 281 blank | 289 comment | 341 complexity | fa58a560c463bfe96723c16fb7913354 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file