Avast: improve compliance with avast-protocol(5)
authorHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Fri, 30 Mar 2018 22:06:47 +0000 (00:06 +0200)
committerHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Mon, 2 Apr 2018 20:00:36 +0000 (22:00 +0200)
Treat scanner errors as malware. Defer on scanner tmpfail
only.

15 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
src/src/malware.c
test/log/4007
test/log/4017
test/paniclog/4007
test/paniclog/4017
test/rejectlog/4007
test/rejectlog/4017
test/scripts/4007_scan_avast/4007
test/scripts/4017_scan_avast_multiline/4017
test/stderr/4007
test/stderr/4017
test/stdout/4007
test/stdout/4017

index 16d276e..6353e29 100644 (file)
@@ -31895,7 +31895,12 @@ $ socat UNIX:/var/run/avast/scan.sock STDIO:
     PACK
 .endd
 
-Only the first virus detected will be reported.
+A paniclog entry is logged and the message is deferred (except the
+malware condition uses "defer_ok") if the scanner returns a tmpfail
+(e.g. on license issues, or permission problems). If the scanner can't
+scan a file for internal reasons (e.g. decompression bomb), this is
+treated as an infection and malware_name is set to the error message.
+We do this err on the safe side.
 
 
 .vitem &%aveserver%&
index 221c808..837b380 100644 (file)
@@ -190,6 +190,12 @@ JH/35 Cutthrough: for a final-dot response timeout (and nonunderstood responses)
 PP/02 DANE: add dane_require_tls_ciphers SMTP Transport option; if unset,
       tls_require_ciphers is used as before.
 
+HS/03 Malware Avast: Better match the Avast multiline protocol.
+      Only tmpfails from the scanner are written to the paniclog, as
+      they may require admin intervention (permission denied, license
+      issues). Other scanner errors (like decompression bombs) do not
+      cause a paniclog entry.
+
 
 Exim version 4.90
 -----------------
index d24f09b..7c57c00 100644 (file)
@@ -137,9 +137,11 @@ static const pcre * kav_re_inf = NULL;
 
 #ifndef DISABLE_MAL_AVAST
 static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]";
-static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d\\.\\d\\t\\d\\s(.*)";
+static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d+\\.0\\t0\\s(.*)";
+static const uschar * ava_re_error_str = US "(?!\\\\)\\t\\[E\\]\\d+\\.0\\tError\\s\\d+\\s(.*)";
 static const pcre * ava_re_clean = NULL;
 static const pcre * ava_re_virus = NULL;
+static const pcre * ava_re_error = NULL;
 #endif
 
 #ifndef DISABLE_MAL_FFROT6D
@@ -176,27 +178,58 @@ extern int spool_mbox_ok;
 extern uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
 
 
+/* Some (currently avast only) use backslash escaped whitespace,
+this function undoes these escapes */
+static inline void
+unescape(char *p) {
+  uschar *p0;
+  for (; *p; ++p)
+    if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
+      for (p0 = p; *p0; ++p0) *p0 = p0[1];
+}
 
+/* --- malware_*_defer --- */
 static inline int
-malware_errlog_defer(const uschar * str)
+malware_panic_defer(const uschar * str)
 {
 log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
 return DEFER;
 }
-
-static int
-m_errlog_defer(struct scan * scanent, const uschar * hostport,
+static inline int
+malware_log_defer(const uschar * str)
+{
+log_write(0, LOG_MAIN, "malware acl condition: %s", str);
+return DEFER;
+}
+/* --- m_*_defer --- */
+static inline int
+m_panic_defer(struct scan * scanent, const uschar * hostport,
   const uschar * str)
 {
-return malware_errlog_defer(string_sprintf("%s %s : %s",
+return malware_panic_defer(string_sprintf("%s %s : %s",
   scanent->name, hostport ? hostport : CUS"", str));
 }
-static int
-m_errlog_defer_3(struct scan * scanent, const uschar * hostport,
+static inline int
+m_log_defer(struct scan * scanent, const uschar * hostport,
+  const uschar * str)
+{
+return malware_log_defer(string_sprintf("%s %s : %s",
+  scanent->name, hostport ? hostport : CUS"", str));
+}
+/* --- m_*_defer_3 */
+static inline int
+m_panic_defer_3(struct scan * scanent, const uschar * hostport,
+  const uschar * str, int fd_to_close)
+{
+(void) close(fd_to_close);
+return m_panic_defer(scanent, hostport, str);
+}
+static inline int
+m_log_defer_3(struct scan * scanent, const uschar * hostport,
   const uschar * str, int fd_to_close)
 {
 (void) close(fd_to_close);
-return m_errlog_defer(scanent, hostport, str);
+return m_log_defer(scanent, hostport, str);
 }
 
 /*************************************************/
@@ -341,7 +374,7 @@ for (;;)
   while (i < 0 && errno == EINTR);
   if (i <= 0)
     {
-    (void) malware_errlog_defer(
+    (void) malware_panic_defer(
            US"unable to write to mksd UNIX socket (/var/run/mksd/socket)");
     return -1;
     }
@@ -373,7 +406,7 @@ do
   i = ip_recv(sock, av_buffer+offset, av_buffer_size-offset, tmo-time(NULL));
   if (i <= 0)
     {
-    (void) malware_errlog_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
+    (void) malware_panic_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)");
     return -1;
     }
 
@@ -381,7 +414,7 @@ do
   /* offset == av_buffer_size -> buffer full */
   if (offset == av_buffer_size)
     {
-    (void) malware_errlog_defer(US"malformed reply received from mksd");
+    (void) malware_panic_defer(US"malformed reply received from mksd");
     return -1;
     }
   } while (av_buffer[offset-1] != '\n');
@@ -404,7 +437,7 @@ switch (*line)
   case 'A': /* ERR */
     if ((p = strchr (line, '\n')) != NULL)
       *p = '\0';
-    return m_errlog_defer(scanent, NULL,
+    return m_panic_defer(scanent, NULL,
       string_sprintf("scanner failed: %s", line));
 
   default: /* VIR */
@@ -422,7 +455,7 @@ switch (*line)
        return OK;
        }
       }
-    return m_errlog_defer(scanent, NULL,
+    return m_panic_defer(scanent, NULL,
       string_sprintf("malformed reply received: %s", line));
   }
 }
@@ -515,7 +548,7 @@ if (!malware_re)
 /* Ensure the eml mbox file is spooled up */
 
 if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
-  return malware_errlog_defer(US"error while creating mbox spool file");
+  return malware_panic_defer(US"error while creating mbox spool file");
 
 /* None of our current scanners need the mbox file as a stream (they use
 the name), so we can close it right away.  Get the directory too. */
@@ -535,20 +568,20 @@ if (  strcmpic(malware_re,US"true") == 0
   {
   if (  !malware_default_re
      && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
-    return malware_errlog_defer(errstr);
+    return malware_panic_defer(errstr);
   malware_re = malware_regex_default;
   re = malware_default_re;
   }
 
 /* compile the regex, see if it works */
 else if (!(re = m_pcre_compile(malware_re, &errstr)))
-  return malware_errlog_defer(errstr);
+  return malware_panic_defer(errstr);
 
 /* if av_scanner starts with a dollar, expand it first */
 if (*av_scanner == '$')
   {
   if (!(av_scanner_work = expand_string(av_scanner)))
-    return malware_errlog_defer(
+    return malware_panic_defer(
         string_sprintf("av_scanner starts with $, but expansion failed: %s",
         expand_string_message));
 
@@ -564,14 +597,14 @@ if (!malware_ok)
   {
   /* find the scanner type from the av_scanner option */
   if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
-    return malware_errlog_defer(US"av_scanner configuration variable is empty");
+    return malware_panic_defer(US"av_scanner configuration variable is empty");
   if (!timeout) timeout = MALWARE_TIMEOUT;
   tmo = time(NULL) + timeout;
 
   for (scanent = m_scans; ; scanent++)
     {
     if (!scanent->name)
-      return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
+      return malware_panic_defer(string_sprintf("unknown scanner type '%s'",
        scanner_name));
     if (strcmpic(scanner_name, US scanent->name) != 0)
       continue;
@@ -592,7 +625,7 @@ if (!malware_ok)
     default: /* compiler quietening */ break;
     }
     if (sock < 0)
-      return m_errlog_defer(scanent, CUS callout_address, errstr);
+      return m_panic_defer(scanent, CUS callout_address, errstr);
     break;
   }
 
@@ -623,7 +656,7 @@ if (!malware_ok)
 
       /* send scan request */
       if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
-       return m_errlog_defer(scanent, CUS callout_address, errstr);
+       return m_panic_defer(scanent, CUS callout_address, errstr);
 
       while ((len = recv_line(sock, buf, sizeof(buf), tmo)) >= 0)
        if (len > 0)
@@ -665,24 +698,24 @@ if (!malware_ok)
 
       if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
         || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
-        return malware_errlog_defer(errstr);
+        return malware_panic_defer(errstr);
 
       scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n",
         scanner_name, scanrequest);
 
       if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0)
-        return m_errlog_defer(scanent, CUS callout_address, errstr);
+        return m_panic_defer(scanent, CUS callout_address, errstr);
 
       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
 
       if (bread <= 0)
-        return m_errlog_defer_3(scanent, CUS callout_address,
+        return m_panic_defer_3(scanent, CUS callout_address,
           string_sprintf("unable to read from socket (%s)", strerror(errno)),
           sock);
 
       if (bread == sizeof(av_buffer))
-        return m_errlog_defer_3(scanent, CUS callout_address,
+        return m_panic_defer_3(scanent, CUS callout_address,
           US"buffer too small", sock);
 
       av_buffer[bread] = '\0';
@@ -691,7 +724,7 @@ if (!malware_ok)
       m_sock_send(sock, US"QUIT\n", 5, 0);
 
       if ((e = m_pcre_exec(fprot6d_re_error, linebuffer)))
-        return m_errlog_defer_3(scanent, CUS callout_address,
+        return m_panic_defer_3(scanent, CUS callout_address,
           string_sprintf("scanner reported error (%s)", e), sock);
 
       if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer)))
@@ -721,7 +754,7 @@ if (!malware_ok)
        {
        /* calc file size */
        if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1)
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("can't open spool file %s: %s",
              eml_filename, strerror(errno)),
            sock);
@@ -731,7 +764,7 @@ if (!malware_ok)
          int err;
 badseek:  err = errno;
          (void)close(drweb_fd);
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("can't seek spool file %s: %s",
              eml_filename, strerror(err)),
            sock);
@@ -740,7 +773,7 @@ badseek:  err = errno;
        if ((off_t)fsize_uint != fsize)
          {
          (void)close(drweb_fd);
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("seeking spool file %s, size overflow",
              eml_filename),
            sock);
@@ -759,7 +792,7 @@ badseek:  err = errno;
            (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0))
          {
          (void)close(drweb_fd);
-         return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
+         return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
            "unable to send commands to socket (%s)", scanner_options),
            sock);
          }
@@ -767,7 +800,7 @@ badseek:  err = errno;
        if (!(drweb_fbuf = US malloc(fsize_uint)))
          {
          (void)close(drweb_fd);
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("unable to allocate memory %u for file (%s)",
              fsize_uint, eml_filename),
            sock);
@@ -778,7 +811,7 @@ badseek:  err = errno;
          int err = errno;
          (void)close(drweb_fd);
          free(drweb_fbuf);
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("can't read spool file %s: %s",
              eml_filename, strerror(err)),
            sock);
@@ -789,7 +822,7 @@ badseek:  err = errno;
        if (send(sock, drweb_fbuf, fsize, 0) < 0)
          {
          free(drweb_fbuf);
-         return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
+         return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
            "unable to send file body to socket (%s)", scanner_options),
            sock);
          }
@@ -807,19 +840,19 @@ badseek:  err = errno;
            (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
            (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
            (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0))
-         return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
+         return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
            "unable to send commands to socket (%s)", scanner_options),
            sock);
        }
 
       /* wait for result */
       if (!recv_len(sock, &drweb_rc, sizeof(drweb_rc), tmo))
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
                    US"unable to read return code", sock);
       drweb_rc = ntohl(drweb_rc);
 
       if (!recv_len(sock, &drweb_vnum, sizeof(drweb_vnum), tmo))
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
                            US"unable to read the number of viruses", sock);
       drweb_vnum = ntohl(drweb_vnum);
 
@@ -843,14 +876,14 @@ badseek:  err = errno;
 
          /* read the size of report */
          if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo))
-           return m_errlog_defer_3(scanent, CUS callout_address,
+           return m_panic_defer_3(scanent, CUS callout_address,
                              US"cannot read report size", sock);
          drweb_slen = ntohl(drweb_slen);
          tmpbuf = store_get(drweb_slen);
 
          /* read report body */
          if (!recv_len(sock, tmpbuf, drweb_slen, tmo))
-           return m_errlog_defer_3(scanent, CUS callout_address,
+           return m_panic_defer_3(scanent, CUS callout_address,
                              US"cannot read report string", sock);
          tmpbuf[drweb_slen] = '\0';
 
@@ -888,7 +921,7 @@ badseek:  err = errno;
         * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
         * and others are ignored */
        if (drweb_s)
-         return m_errlog_defer_3(scanent, CUS callout_address,
+         return m_panic_defer_3(scanent, CUS callout_address,
            string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s),
            sock);
 
@@ -910,7 +943,7 @@ badseek:  err = errno;
       recv_line(sock, buf, sizeof(buf), tmo);
 
       if (buf[0] != '2')               /* aveserver is having problems */
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
          string_sprintf("unavailable (Responded: %s).",
                          ((buf[0] != 0) ? buf : US "nothing") ),
          sock);
@@ -923,7 +956,7 @@ badseek:  err = errno;
       DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n",
        scanner_name, buf);
       if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
-       return m_errlog_defer(scanent, CUS callout_address, errstr);
+       return m_panic_defer(scanent, CUS callout_address, errstr);
 
       malware_name = NULL;
       result = 0;
@@ -934,7 +967,7 @@ badseek:  err = errno;
          break;
        if (buf[0] == '5')              /* aveserver is having problems */
          {
-         result = m_errlog_defer(scanent, CUS callout_address,
+         result = m_panic_defer(scanent, CUS callout_address,
             string_sprintf("unable to scan file %s (Responded: %s).",
                             eml_filename, buf));
          break;
@@ -948,14 +981,14 @@ badseek:  err = errno;
        }
 
       if (m_sock_send(sock, US"quit\r\n", 6, &errstr) < 0)
-       return m_errlog_defer(scanent, CUS callout_address, errstr);
+       return m_panic_defer(scanent, CUS callout_address, errstr);
 
       /* read aveserver's greeting and see if it is ready (2xx greeting) */
       buf[0] = 0;
       recv_line(sock, buf, sizeof(buf), tmo);
 
       if (buf[0] != '2')               /* aveserver is having problems */
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
          string_sprintf("unable to quit dialogue (Responded: %s).",
                        ((buf[0] != 0) ? buf : US "nothing") ),
          sock);
@@ -990,12 +1023,12 @@ badseek:  err = errno;
        {
 
        if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
-         return m_errlog_defer(scanent, CUS callout_address, errstr);
+         return m_panic_defer(scanent, CUS callout_address, errstr);
 
        bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
        if (bread > 0) av_buffer[bread]='\0';
        if (bread < 0)
-         return m_errlog_defer_3(scanent, CUS callout_address,
+         return m_panic_defer_3(scanent, CUS callout_address,
            string_sprintf("unable to read answer %d (%s)", i, strerror(errno)),
            sock);
        for (j = 0; j < bread; j++)
@@ -1007,7 +1040,7 @@ badseek:  err = errno;
       file_name = string_sprintf("SCAN\t%s\n", eml_filename);
 
       if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
-       return m_errlog_defer(scanent, CUS callout_address, errstr);
+       return m_panic_defer(scanent, CUS callout_address, errstr);
 
       /* set up match */
       /* todo also SUSPICION\t */
@@ -1025,7 +1058,7 @@ badseek:  err = errno;
          errno = ETIMEDOUT;
          i =  av_buffer+sizeof(av_buffer)-p;
          if ((bread= ip_recv(sock, p, i-1, tmo-time(NULL))) < 0)
-           return m_errlog_defer_3(scanent, CUS callout_address,
+           return m_panic_defer_3(scanent, CUS callout_address,
              string_sprintf("unable to read result (%s)", strerror(errno)),
              sock);
 
@@ -1085,11 +1118,11 @@ badseek:  err = errno;
 
       /* send scan request */
       if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
-       return m_errlog_defer(scanent, CUS callout_address, errstr);
+       return m_panic_defer(scanent, CUS callout_address, errstr);
 
       /* wait for result */
       if (!recv_len(sock, tmpbuf, 2, tmo))
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
                            US"unable to read 2 bytes from socket.", sock);
 
       /* get errorcode from one nibble */
@@ -1097,14 +1130,14 @@ badseek:  err = errno;
       switch(kav_rc)
       {
       case 5: case 6: /* improper kavdaemon configuration */
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
                US"please reconfigure kavdaemon to NOT disinfect or remove infected files.",
                sock);
       case 1:
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
                US"reported 'scanning not completed' (code 1).", sock);
       case 7:
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
                US"reported 'kavdaemon damaged' (code 7).", sock);
       }
 
@@ -1126,7 +1159,7 @@ badseek:  err = errno;
          {
          /* read report size */
          if (!recv_len(sock, &kav_reportlen, 4, tmo))
-           return m_errlog_defer_3(scanent, CUS callout_address,
+           return m_panic_defer_3(scanent, CUS callout_address,
                  US"cannot read report size", sock);
 
          /* it's possible that avp returns av_buffer[1] == 1 but the
@@ -1187,19 +1220,19 @@ badseek:  err = errno;
       uschar *p;
 
       if (!cmdline_scanner)
-       return m_errlog_defer(scanent, NULL, errstr);
+       return m_panic_defer(scanent, NULL, errstr);
 
       /* find scanner output trigger */
       cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
                                "missing trigger specification", &errstr);
       if (!cmdline_trigger_re)
-       return m_errlog_defer(scanent, NULL, errstr);
+       return m_panic_defer(scanent, NULL, errstr);
 
       /* find scanner name regex */
       cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
                          "missing virus name regex specification", &errstr);
       if (!cmdline_regex_re)
-       return m_errlog_defer(scanent, NULL, errstr);
+       return m_panic_defer(scanent, NULL, errstr);
 
       /* prepare scanner call; despite the naming, file_name holds a directory
       name which is documented as the value given to %s. */
@@ -1224,7 +1257,7 @@ badseek:  err = errno;
        {
        int err = errno;
        signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
-       return m_errlog_defer(scanent, NULL,
+       return m_panic_defer(scanent, NULL,
          string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
        }
       scanner_fd = fileno(scanner_out);
@@ -1236,7 +1269,7 @@ badseek:  err = errno;
        int err = errno;
        (void) pclose(scanner_out);
        signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
-       return m_errlog_defer(scanent, NULL, string_sprintf(
+       return m_panic_defer(scanent, NULL, string_sprintf(
            "opening scanner output file (%s) failed: %s.",
            file_name, strerror(err)));
        }
@@ -1252,7 +1285,7 @@ badseek:  err = errno;
            break;
          (void) pclose(scanner_out);
          signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
-         return m_errlog_defer(scanent, NULL, string_sprintf(
+         return m_panic_defer(scanent, NULL, string_sprintf(
              "unable to read from scanner (%s): %s",
              commandline, strerror(err)));
          }
@@ -1262,7 +1295,7 @@ badseek:  err = errno;
          /* short write */
          (void) pclose(scanner_out);
          signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
-         return m_errlog_defer(scanent, NULL, string_sprintf(
+         return m_panic_defer(scanent, NULL, string_sprintf(
            "short write on scanner output file (%s).", file_name));
          }
        putc('\n', scanner_record);
@@ -1277,7 +1310,7 @@ badseek:  err = errno;
       sep = pclose(scanner_out);
       signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
       if (sep != 0)
-         return m_errlog_defer(scanent, NULL,
+         return m_panic_defer(scanent, NULL,
              sep == -1
              ? string_sprintf("running scanner failed: %s", strerror(sep))
              : string_sprintf("scanner returned error code: %d", sep));
@@ -1323,14 +1356,14 @@ badseek:  err = errno;
       if (  write(sock, file_name, Ustrlen(file_name)) < 0
         || write(sock, "\n", 1) != 1
         )
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
          string_sprintf("unable to write to UNIX socket (%s)", scanner_options),
          sock);
 
       /* wait for result */
       memset(av_buffer, 0, sizeof(av_buffer));
       if ((bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL))) <= 0)
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
          string_sprintf("unable to read from UNIX socket (%s)", scanner_options),
          sock);
 
@@ -1342,7 +1375,7 @@ badseek:  err = errno;
        malware_name = string_copy(&av_buffer[2]);
       }
       else if (!strncmp(CS av_buffer, "-1", 2))
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
                US"scanner reported error", sock);
       else /* all ok, no virus */
        malware_name = NULL;
@@ -1400,7 +1433,7 @@ badseek:  err = errno;
 
        /* parse options */
        if (clamd_option(cd, sublist, &subsep) != OK)
-         return m_errlog_defer(scanent, NULL,
+         return m_panic_defer(scanent, NULL,
            string_sprintf("bad option '%s'", scanner_options));
        cv[0] = cd;
        }
@@ -1432,13 +1465,13 @@ badseek:  err = errno;
          sublist = scanner_options;
          if (!(cd->hostspec = string_nextinlist(&sublist, &subsep, NULL, 0)))
            {
-           (void) m_errlog_defer(scanent, NULL,
+           (void) m_panic_defer(scanent, NULL,
                      string_sprintf("missing address: '%s'", scanner_options));
            continue;
            }
          if (!(s = string_nextinlist(&sublist, &subsep, NULL, 0)))
            {
-           (void) m_errlog_defer(scanent, NULL,
+           (void) m_panic_defer(scanent, NULL,
                      string_sprintf("missing port: '%s'", scanner_options));
            continue;
            }
@@ -1447,13 +1480,13 @@ badseek:  err = errno;
          /* parse options */
          /*XXX should these options be common over scanner types? */
          if (clamd_option(cd, sublist, &subsep) != OK)
-           return m_errlog_defer(scanent, NULL,
+           return m_panic_defer(scanent, NULL,
              string_sprintf("bad option '%s'", scanner_options));
 
          cv[num_servers++] = cd;
          if (num_servers >= MAX_CLAMD_SERVERS)
            {
-           (void) m_errlog_defer(scanent, NULL,
+           (void) m_panic_defer(scanent, NULL,
                  US"More than " MAX_CLAMD_SERVERS_S " clamd servers "
                  "specified; only using the first " MAX_CLAMD_SERVERS_S );
            break;
@@ -1463,14 +1496,14 @@ badseek:  err = errno;
 
        /* check if we have at least one server */
        if (!num_servers)
-         return m_errlog_defer(scanent, NULL,
+         return m_panic_defer(scanent, NULL,
            US"no useable server addresses in malware configuration option.");
        }
 
       /* See the discussion of response formats below to see why we really
       don't like colons in filenames when passing filenames to ClamAV. */
       if (use_scan_command && Ustrchr(eml_filename, ':'))
-       return m_errlog_defer(scanent, NULL,
+       return m_panic_defer(scanent, NULL,
          string_sprintf("local/SCAN mode incompatible with" \
            " : in path to email filename [%s]", eml_filename));
 
@@ -1516,7 +1549,7 @@ badseek:  err = errno;
          if (sock >= 0)
            break;
 
-         (void) m_errlog_defer(scanent, CUS callout_address, errstr);
+         (void) m_panic_defer(scanent, CUS callout_address, errstr);
 
          /* Remove the server from the list. XXX We should free the memory */
          num_servers--;
@@ -1525,7 +1558,7 @@ badseek:  err = errno;
          }
 
        if (num_servers == 0)
-         return m_errlog_defer(scanent, NULL, US"all servers failed");
+         return m_panic_defer(scanent, NULL, US"all servers failed");
        }
       else
        for (;;)
@@ -1536,7 +1569,7 @@ badseek:  err = errno;
            break;
            }
          if (cv[0]->retry <= 0)
-           return m_errlog_defer(scanent, CUS callout_address, errstr);
+           return m_panic_defer(scanent, CUS callout_address, errstr);
          while (cv[0]->retry > 0) cv[0]->retry = sleep(cv[0]->retry);
          }
 
@@ -1558,7 +1591,7 @@ badseek:  err = errno;
        /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
        if (cmd_str.len)
          if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
-           return m_errlog_defer_3(scanent, CUS hostname,
+           return m_panic_defer_3(scanent, CUS hostname,
              string_sprintf("unable to send zINSTREAM to socket (%s)",
                strerror(errno)),
              sock);
@@ -1567,7 +1600,7 @@ badseek:  err = errno;
        if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0)
          {
          int err = errno;
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("can't open spool file %s: %s",
              eml_filename, strerror(err)),
            sock);
@@ -1577,7 +1610,7 @@ badseek:  err = errno;
          int err;
 b_seek:   err = errno;
          (void)close(clam_fd);
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("can't seek spool file %s: %s",
              eml_filename, strerror(err)),
            sock);
@@ -1586,7 +1619,7 @@ b_seek:   err = errno;
        if ((off_t)fsize_uint != fsize)
          {
          (void)close(clam_fd);
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("seeking spool file %s, size overflow",
              eml_filename),
            sock);
@@ -1597,7 +1630,7 @@ b_seek:   err = errno;
        if (!(clamav_fbuf = US malloc(fsize_uint)))
          {
          (void)close(clam_fd);
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("unable to allocate memory %u for file (%s)",
              fsize_uint, eml_filename),
            sock);
@@ -1607,7 +1640,7 @@ b_seek:   err = errno;
          {
          int err = errno;
          free(clamav_fbuf); (void)close(clam_fd);
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("can't read spool file %s: %s",
              eml_filename, strerror(err)),
            sock);
@@ -1622,7 +1655,7 @@ b_seek:   err = errno;
            (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
          {
          free(clamav_fbuf);
-         return m_errlog_defer_3(scanent, NULL,
+         return m_panic_defer_3(scanent, NULL,
            string_sprintf("unable to send file body to socket (%s)", hostname),
            sock);
          }
@@ -1652,7 +1685,7 @@ b_seek:   err = errno;
 
        if (cmd_str.len)
          if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
-           return m_errlog_defer_3(scanent, CUS callout_address,
+           return m_panic_defer_3(scanent, CUS callout_address,
              string_sprintf("unable to write to socket (%s)", strerror(errno)),
              sock);
 
@@ -1669,12 +1702,12 @@ b_seek:   err = errno;
       sock = -1;
 
       if (bread <= 0)
-       return m_errlog_defer(scanent, CUS callout_address,
+       return m_panic_defer(scanent, CUS callout_address,
          string_sprintf("unable to read from socket (%s)",
          errno == 0 ? "EOF" : strerror(errno)));
 
       if (bread == sizeof(av_buffer))
-       return m_errlog_defer(scanent, CUS callout_address,
+       return m_panic_defer(scanent, CUS callout_address,
                US"buffer too small");
       /* We're now assured of a NULL at the end of av_buffer */
 
@@ -1699,7 +1732,7 @@ b_seek:   err = errno;
       passing a filename to clamd). */
 
       if (!(*av_buffer))
-       return m_errlog_defer(scanent, CUS callout_address,
+       return m_panic_defer(scanent, CUS callout_address,
                US"ClamAV returned null");
 
       /* strip newline at the end (won't be present for zINSTREAM)
@@ -1716,7 +1749,7 @@ b_seek:   err = errno;
 
       /* colon in returned output? */
       if(!(p = Ustrchr(av_buffer,':')))
-       return m_errlog_defer(scanent, CUS callout_address, string_sprintf(
+       return m_panic_defer(scanent, CUS callout_address, string_sprintf(
                  "ClamAV returned malformed result (missing colon): %s",
                  av_buffer));
 
@@ -1749,7 +1782,7 @@ b_seek:   err = errno;
 
        }
       else if (Ustrcmp(result_tag, "ERROR") == 0)
-       return m_errlog_defer(scanent, CUS callout_address,
+       return m_panic_defer(scanent, CUS callout_address,
          string_sprintf("ClamAV returned: %s", av_buffer));
 
       else if (Ustrcmp(result_tag, "OK") == 0)
@@ -1760,7 +1793,7 @@ b_seek:   err = errno;
 
        }
       else
-       return m_errlog_defer(scanent, CUS callout_address,
+       return m_panic_defer(scanent, CUS callout_address,
          string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
 
       break;
@@ -1791,7 +1824,7 @@ b_seek:   err = errno;
        uschar * s = Ustrchr(sockline_scanner, '%');
        if (s++)
          if ((*s != 's' && *s != '%') || Ustrchr(s+1, '%'))
-           return m_errlog_defer_3(scanent, NULL,
+           return m_panic_defer_3(scanent, NULL,
                                  US"unsafe sock scanner call spec", sock);
       }
       else
@@ -1803,13 +1836,13 @@ b_seek:   err = errno;
       sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
                                "missing trigger specification", &errstr);
       if (!sockline_trig_re)
-       return m_errlog_defer_3(scanent, NULL, errstr, sock);
+       return m_panic_defer_3(scanent, NULL, errstr, sock);
 
       /* find virus name regex */
       sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
                          "missing virus name regex specification", &errstr);
       if (!sockline_name_re)
-       return m_errlog_defer_3(scanent, NULL, errstr, sock);
+       return m_panic_defer_3(scanent, NULL, errstr, sock);
 
       /* prepare scanner call - security depends on expansions check above */
       commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
@@ -1818,18 +1851,18 @@ b_seek:   err = errno;
 
       /* Pass the command string to the socket */
       if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
-       return m_errlog_defer(scanent, CUS callout_address, errstr);
+       return m_panic_defer(scanent, CUS callout_address, errstr);
 
       /* Read the result */
       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), tmo-time(NULL));
 
       if (bread <= 0)
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
          string_sprintf("unable to read from socket (%s)", strerror(errno)),
          sock);
 
       if (bread == sizeof(av_buffer))
-       return m_errlog_defer_3(scanent, CUS callout_address,
+       return m_panic_defer_3(scanent, CUS callout_address,
                US"buffer too small", sock);
       av_buffer[bread] = '\0';
       linebuffer = string_copy(av_buffer);
@@ -1865,12 +1898,12 @@ b_seek:   err = errno;
           || mksd_maxproc < 1
           || mksd_maxproc > 32
           )
-         return m_errlog_defer(scanent, CUS callout_address,
+         return m_panic_defer(scanent, CUS callout_address,
            string_sprintf("invalid option '%s'", scanner_options));
        }
 
       if((sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
-       return m_errlog_defer(scanent, CUS callout_address, errstr);
+       return m_panic_defer(scanent, CUS callout_address, errstr);
 
       malware_name = NULL;
 
@@ -1888,12 +1921,13 @@ b_seek:   err = errno;
 #ifndef DISABLE_MAL_AVAST
     case M_AVAST: /* "avast" scanner type ----------------------------------- */
       {
-      int ovector[1*3];
+      int ovector[10*3];
       uschar buf[1024];
       uschar * scanrequest;
       enum {AVA_HELO, AVA_OPT, AVA_RSP, AVA_DONE} avast_stage;
       int nread;
       int more_data;
+      uschar * error_message = NULL;
 
       /* According to Martin Tuma @avast the protocol uses "escaped
       whitespace", that is, every embedded whitespace is backslash
@@ -1905,13 +1939,44 @@ b_seek:   err = errno;
       [E] - some error occured
       Such marker follows the first non-escaped TAB.  For more information
       see avast-protocol(5)
-      */
+
+      We observed two cases:
+      -> SCAN /file
+      <- /file [E]0.0 Error 13 Permission denied
+      <- 451 SCAN Engine error 13 permission denied
+
+      -> SCAN /file
+      <- /file… [E]3.0 Error 41120 The file is a decompression bomb
+      <- /file… [+]2.0
+      <- /file… [+]2.0 0 Eicar Test Virus!!!
+      <- 200 SCAN OK
+
+      If the scanner returns 4xx, DEFER is a good decision, combined
+      with a panic log entry, to get the admin's attention.
+
+      If the scanner returns 200, we reject it as malware, if found any,
+      or, in case of an error, we set the malware message to the error
+      string.
+
+      Some of the >= 42000 errors are message related - usually some
+      broken archives etc, but some of them are e.g. license related.
+      Once the license expires the engine starts returning errors for
+      every scanning attempt.  I¹ have the full list of the error codes
+      but it is not a public API and is subject to change. It is hard
+      for me to say what you should do in case of an engine error. You
+      can have a “Treat * unscanned file as infection” policy or “Treat
+      unscanned file as clean” policy.  ¹) Jakub Bednar
+
+       */
+
       if (  (  !ava_re_clean
             && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
         || (  !ava_re_virus
            && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
+        || (  !ava_re_error
+           && !(ava_re_error = m_pcre_compile(ava_re_error_str, &errstr)))
         )
-       return malware_errlog_defer(errstr);
+       return malware_panic_defer(errstr);
 
       /* wait for result */
       for (avast_stage = AVA_HELO;
@@ -1963,10 +2028,10 @@ b_seek:   err = errno;
 
              /* send config-cmd or scan-request to socket */
              len = Ustrlen(scanrequest);
-             if (send(sock, scanrequest, len, 0) < 0)
+             if (send(sock, scanrequest, len, 0) == -1)
                {
                scanrequest[len-1] = '\0';
-               return m_errlog_defer_3(scanent, CUS callout_address, string_sprintf(
+               return m_panic_defer_3(scanent, CUS callout_address, string_sprintf(
                      "unable to send request '%s' to socket (%s): %s",
                      scanrequest, scanner_options, strerror(errno)), sock);
                }
@@ -1975,36 +2040,52 @@ b_seek:   err = errno;
 
            case AVA_RSP:
 
-             if (Ustrncmp(buf, "200", 3) == 0)
-               { /* we're done finally */
-               if (send(sock, "QUIT\n", 5, 0) < 0) /* courtesy */
-                 return m_errlog_defer_3(scanent, CUS callout_address,
+             if (isdigit(buf[0]))
+               { /* we're done, this is the last response line from the scanner */
+                DEBUG(D_acl) debug_printf_indent("sent to avast QUIT\n");
+               if (send(sock, "QUIT\n", 5, 0) == -1) /* courtesy */
+                 return m_panic_defer_3(scanent, CUS callout_address,
                          string_sprintf(
                              "unable to send quit request to socket (%s): %s",
                              scanner_options, strerror(errno)),
                              sock);
 
+                if (buf[0] != '2') error_message = buf;
                avast_stage = AVA_DONE;
                 goto endloop;
                }
 
-              if (malware_name) break;  /* found malware already, nothing to do anymore */
+              #if 0
+              /* found malware or another error already, nothing to do anymore, just read on */
+              if (malware_name || error_message)
+                break;
+              #endif
 
              if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
                    0, 0, ovector, nelem(ovector)) > 0)
                break;
 
-             if (malware_name = m_pcre_exec(ava_re_virus, buf))
-               { /* remove backslash in front of [whitespace|backslash] */
-               uschar * p, * p0;
-               for (p = malware_name; *p; ++p)
-                 if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
-                   for (p0 = p; *p0; ++p0) *p0 = p0[1];
-
-               DEBUG(D_acl)
-                 debug_printf_indent("unescaped malware name: '%s'\n", malware_name);
-               break;
-               }
+             if (malware_name)
+                break;
+
+              if (malware_name = m_pcre_exec(ava_re_virus, buf))
+                {
+                unescape(malware_name);
+                DEBUG(D_acl)
+                  debug_printf_indent("unescaped malware name: '%s'\n", malware_name);
+                break;
+                }
+
+              /*if (pcre_exec(ava_re_error, NULL, CS buf, nread, 0, 0, ovector, nelem(ovector)) == 2)
+              unescape(malware_name = buf + ovector[1*2]);
+              */
+              if (malware_name = m_pcre_exec(ava_re_error, buf))
+                {
+                unescape(malware_name);
+                DEBUG(D_acl)
+                  debug_printf_indent("unescaped error message: '%s'\n", malware_name);
+                break;
+                }
 
              /* here also for any unexpected response from the scanner */
              goto endloop;
@@ -2020,14 +2101,14 @@ b_seek:   err = errno;
        {
        case AVA_HELO:
        case AVA_OPT:
-       case AVA_RSP:   return m_errlog_defer_3(scanent, CUS callout_address,
-                           nread >= 0
-                           ? string_sprintf(
-                               "invalid response from scanner: '%s'", buf)
-                           : nread == -1
-                           ? US"EOF from scanner"
-                           : US"timeout from scanner",
-                         sock);
+       case AVA_RSP:
+                        if (nread == -1) error_message = "EOF from scanner";
+                        else if (nread < 0) error_message = "timeout from scanner";
+
+        case AVA_DONE:
+                        if (error_message)
+                          return m_panic_defer_3(scanent, CUS callout_address, error_message, sock);
+
        default:        break;
        }
       break;
@@ -2151,6 +2232,8 @@ if (!ava_re_clean)
   ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
 if (!ava_re_virus)
   ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
+if (!ava_re_error)
+  ava_re_error = regex_must_compile(ava_re_error_str, FALSE, TRUE);
 #endif
 #ifndef DISABLE_MAL_FFROT6D
 if (!fprot6d_re_error)
index bd0ec87..960d6ba 100644 (file)
@@ -1,7 +1,7 @@
-1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss T="message should be accepted"
-1999-03-02 09:44:33 10HmbB-0005vi-00 => :blackhole: <userx@test.ex> R=r
-1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : invalid response from scanner: 'blah  [E]'
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss T="message should be accepted"
+1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <userx@test.ex> R=r
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : 451 SCAN Engine error 13 Permission denied
 1999-03-02 09:44:33 10HmaX-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> temporarily rejected after DATA
 1999-03-02 09:44:33 10HmbA-0005vi-00 malware_name VNAME
 1999-03-02 09:44:33 10HmbA-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
@@ -11,3 +11,5 @@
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss T="message should be accepted despite timeout"
 1999-03-02 09:44:33 10HmaZ-0005vi-00 => :blackhole: <userx@test.ex> R=r
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 malware_name The file is a decompression bomb
+1999-03-02 09:44:33 10HmbB-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
index cd53a5c..480ac5d 100644 (file)
@@ -1,7 +1,9 @@
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss T="message should be accepted"
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => :blackhole: <userx@test.ex> R=r
-1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : invalid response from scanner: '/bin/error    [E]0.0'
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss T="message should be accepted"
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <userx@test.ex> R=r
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : 451 SCAN Engine error 13 Permission denied
 1999-03-02 09:44:33 10HmaX-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> temporarily rejected after DATA
-1999-03-02 09:44:33 10HmaY-0005vi-00 malware_name This ist not even an EICAR test virus.
+1999-03-02 09:44:33 10HmaY-0005vi-00 malware_name This is not even an EICAR test virus.
 1999-03-02 09:44:33 10HmaY-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
+1999-03-02 09:44:33 10HmaZ-0005vi-00 malware_name The file is a decompression bomb
+1999-03-02 09:44:33 10HmaZ-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
index 5236f07..9a02ead 100644 (file)
@@ -1,3 +1,3 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : invalid response from scanner: 'blah  [E]'
+1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : 451 SCAN Engine error 13 Permission denied
 1999-03-02 09:44:33 10HmaY-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : timeout from scanner
 1999-03-02 09:44:33 10HmaZ-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : timeout from scanner
index b6fcc05..de97faf 100644 (file)
@@ -1 +1 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : invalid response from scanner: '/bin/error    [E]0.0'
+1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : 451 SCAN Engine error 13 Permission denied
index 6ba3a26..f46e9e7 100644 (file)
@@ -34,3 +34,15 @@ P Received: from CALLER (helo=test.ex)
   Subject: message should be tmp-rejected due to timeout
 I Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
 F From: CALLER_NAME <CALLER@myhost.test.ex>
+1999-03-02 09:44:33 10HmbB-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
+Envelope-from: <CALLER@myhost.test.ex>
+Envelope-to: <userx@test.ex>
+P Received: from CALLER (helo=test.ex)
+       by myhost.test.ex with local-esmtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbB-0005vi-00
+       for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+  Date: Tue, 2 Mar 1999 09:44:33 +0000
+  Subject: defer this one, the scanner had an error
+I Message-Id: <E10HmbB-0005vi-00@myhost.test.ex>
+F From: CALLER_NAME <CALLER@myhost.test.ex>
index f14a316..ca3f388 100644 (file)
@@ -22,3 +22,15 @@ P Received: from CALLER (helo=test.ex)
   Subject: message should be rejected
 I Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
 F From: CALLER_NAME <CALLER@myhost.test.ex>
+1999-03-02 09:44:33 10HmaZ-0005vi-00 U=CALLER F=<CALLER@myhost.test.ex> rejected after DATA
+Envelope-from: <CALLER@myhost.test.ex>
+Envelope-to: <userx@test.ex>
+P Received: from CALLER (helo=test.ex)
+       by myhost.test.ex with local-esmtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaZ-0005vi-00
+       for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+  Date: Tue, 2 Mar 1999 09:44:33 +0000
+  Subject: message should be rejected
+I Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+F From: CALLER_NAME <CALLER@myhost.test.ex>
index 0611f2a..fc6c627 100644 (file)
@@ -28,13 +28,13 @@ quit
 ****
 #
 #
-#
+### (non-internal) scanner error -> paniclog
 server DIR/eximdir/avast_sock
 >LF>220 ready
 <SCAN
 >LF>210 SCAN DATA
->LF>blah       [E]
->LF>200 SCAN OK
+>LF>blah       [E]0.0  Error 13 Permission\\ denied
+>LF>451 SCAN Engine error 13 Permission denied
 <QUIT
 *eof
 ****
@@ -59,7 +59,7 @@ server DIR/eximdir/avast_sock
 >LF>220 ready
 <SCAN
 >LF>210 SCAN DATA
->LF>b\\ l\\ a\\ h      [L]9.9  9 VNAME
+>LF>b\\ l\\ a\\ h      [L]9.0  0 VNAME
 >LF>200 SCAN OK
 <QUIT
 *eof
@@ -118,3 +118,29 @@ Subject: message should be accepted despite timeout
 .
 quit
 ****
+#
+#
+### internal scanner error, no panic log
+server DIR/eximdir/avast_sock
+>LF>220 ready
+<SCAN
+>LF>210 SCAN DATA
+>LF>blah       [E]0.0  Error 42110 The\\ file\\ is\\ a\\ decompression\\ bomb
+>LF>200 SCAN OK
+<QUIT
+*eof
+****
+#
+#
+#
+exim -odi -bs -DOPTION= -DINSERT=
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: defer this one, the scanner had an error
+
+.
+quit
+****
index d075825..3e6b067 100644 (file)
@@ -31,15 +31,13 @@ quit
 ****
 #
 #
-### clean and error | multiline response
+### scanner tmpfail -> defer
 server DIR/eximdir/avast_sock
 >LF>220 ready
 <SCAN
 >LF>210 SCAN DATA
->LF>/bin/ok    [+]
->LF>/bin/error [E]0.0
->LF>/bin/infected      [L]0.0  0 This is not even EICAR!
->LF>200 SCAN OK
+>LF>/bin/error [E]0.0  Error 13 Permission\\ denied
+>LF>451 SCAN Engine error 13 Permission denied
 <QUIT
 *eof
 ****
@@ -59,13 +57,41 @@ quit
 ****
 #
 #
-# clean and infected | multiline response
+# clean and infected -> reject
+server DIR/eximdir/avast_sock
+>LF>220 ready
+<SCAN
+>LF>210 SCAN DATA
+>LF>/bin/clean [+]
+>LF>v\\ i\\ a\\ r\\ u\\ s      [L]9.0  0 This\\ is\\ not\\ even\\ an\\ EICAR\\ test\\ virus.
+>LF>200 SCAN OK
+<QUIT
+*eof
+****
+#
+#
+#
+exim -odi -bs -DOPTION= -DINSERT="/defer_ok"
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be rejected
+
+.
+quit
+****
+#
+#
+# clean, error, infected -> reject
 server DIR/eximdir/avast_sock
 >LF>220 ready
 <SCAN
 >LF>210 SCAN DATA
 >LF>/bin/clean [+]
->LF>v\\ i\\ a\\ r\\ u\\ s      [L]9.9  9 This ist not even an EICAR test virus.
+>LF>/bin/error [E]0.0  Error 42110 The\\ file\\ is\\ a\\ decompression\\ bomb
+>LF>v\\ i\\ a\\ r\\ u\\ s      [L]9.0  0 This\\ is\\ not\\ even\\ an\\ EICAR\\ test\\ virus.
 >LF>200 SCAN OK
 <QUIT
 *eof
index 5236f07..2a5493e 100644 (file)
@@ -1,3 +1,9 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : invalid response from scanner: 'blah  [E]'
+### (non-internal) scanner error -> paniclog
+1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : 451 SCAN Engine error 13 Permission denied
 1999-03-02 09:44:33 10HmaY-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : timeout from scanner
 1999-03-02 09:44:33 10HmaZ-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : timeout from scanner
+### internal scanner error, no panic log
+
+******** SERVER ********
+### (non-internal) scanner error -> paniclog
+### internal scanner error, no panic log
index 22157c3..287cd30 100644 (file)
@@ -1,7 +1,7 @@
 ### clean |  multiline response
-### clean and error | multiline response
-1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : invalid response from scanner: '/bin/error    [E]0.0'
+### scanner tmpfail -> defer
+1999-03-02 09:44:33 10HmaX-0005vi-00 malware acl condition: avast TESTSUITE/eximdir/avast_sock : 451 SCAN Engine error 13 Permission denied
 
 ******** SERVER ********
 ### clean |  multiline response
-### clean and error | multiline response
+### scanner tmpfail -> defer
index 603de15..32adb09 100644 (file)
@@ -7,8 +7,9 @@
 250 OK\r
 250 Accepted\r
 354 Enter message, ending with "." on a line by itself\r
-250 OK id=10HmbB-0005vi-00\r
+250 OK id=10HmbC-0005vi-00\r
 221 myhost.test.ex closing connection\r
+### (non-internal) scanner error -> paniclog
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250-myhost.test.ex Hello CALLER at test.ex\r
 250-SIZE 52428800\r
 354 Enter message, ending with "." on a line by itself\r
 250 OK id=10HmaZ-0005vi-00\r
 221 myhost.test.ex closing connection\r
+### internal scanner error, no panic log
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+550 Administrative prohibition\r
+221 myhost.test.ex closing connection\r
 
 ******** SERVER ********
 Listening on TESTSUITE/eximdir/avast_sock ... 
@@ -61,27 +74,30 @@ Connection request
 <FLAGS -fullfiles
 >LF>210 FLAGS DATA
 >LF>200 FLAGS OK
-<SCAN TESTSUITE/spool/scan/10HmbB-0005vi-00
+<SCAN TESTSUITE/spool/scan/10HmbC-0005vi-00
 >LF>210 SCAN DATA
 >LF>blah\x09[+]
 >LF>200 SCAN OK
 <QUIT
 Expected EOF read from client
 End of script
+### (non-internal) scanner error -> paniclog
 Listening on TESTSUITE/eximdir/avast_sock ... 
 Connection request
 >LF>220 ready
 <SCAN TESTSUITE/spool/scan/10HmaX-0005vi-00
 >LF>210 SCAN DATA
->LF>blah\x09[E]
->LF>200 SCAN OK
-Unexpected EOF read from client
+>LF>blah\x09[E]0.0\x09Error 13 Permission\\ denied
+>LF>451 SCAN Engine error 13 Permission denied
+<QUIT
+Expected EOF read from client
+End of script
 Listening on TESTSUITE/eximdir/avast_sock ... 
 Connection request
 >LF>220 ready
 <SCAN TESTSUITE/spool/scan/10HmbA-0005vi-00
 >LF>210 SCAN DATA
->LF>b\\ l\\ a\\ h\x09[L]9.9\x099 VNAME
+>LF>b\\ l\\ a\\ h\x09[L]9.0\x090 VNAME
 >LF>200 SCAN OK
 <QUIT
 Expected EOF read from client
@@ -94,3 +110,14 @@ Listening on TESTSUITE/eximdir/avast_sock ...
 Connection request
 *sleep 3
 End of script
+### internal scanner error, no panic log
+Listening on TESTSUITE/eximdir/avast_sock ... 
+Connection request
+>LF>220 ready
+<SCAN TESTSUITE/spool/scan/10HmbB-0005vi-00
+>LF>210 SCAN DATA
+>LF>blah\x09[E]0.0\x09Error 42110 The\\ file\\ is\\ a\\ decompression\\ bomb
+>LF>200 SCAN OK
+<QUIT
+Expected EOF read from client
+End of script
index e46e8f3..388af3d 100644 (file)
@@ -8,9 +8,9 @@
 250 OK\r
 250 Accepted\r
 354 Enter message, ending with "." on a line by itself\r
-250 OK id=10HmaZ-0005vi-00\r
+250 OK id=10HmbA-0005vi-00\r
 221 myhost.test.ex closing connection\r
-### clean and error | multiline response
+### scanner tmpfail -> defer
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250-myhost.test.ex Hello CALLER at test.ex\r
 250-SIZE 52428800\r
 354 Enter message, ending with "." on a line by itself\r
 550 Administrative prohibition\r
 221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+550 Administrative prohibition\r
+221 myhost.test.ex closing connection\r
 
 ******** SERVER ********
 ### clean |  multiline response
@@ -44,7 +55,7 @@ Connection request
 >LF>FLAGS -fullfiles
 >LF>FLAGS +extra
 >LF>200 FLAGS OK
-<SCAN TESTSUITE/spool/scan/10HmaZ-0005vi-00
+<SCAN TESTSUITE/spool/scan/10HmbA-0005vi-00
 >LF>210 SCAN DATA
 >LF>/bin/clean1\x09[+]
 >LF>/bin/clean2\x09[+]
@@ -52,24 +63,36 @@ Connection request
 <QUIT
 Expected EOF read from client
 End of script
-### clean and error | multiline response
+### scanner tmpfail -> defer
 Listening on TESTSUITE/eximdir/avast_sock ... 
 Connection request
 >LF>220 ready
 <SCAN TESTSUITE/spool/scan/10HmaX-0005vi-00
 >LF>210 SCAN DATA
->LF>/bin/ok\x09[+]
->LF>/bin/error\x09[E]0.0
->LF>/bin/infected\x09[L]0.0\x090 This is not even EICAR!
->LF>200 SCAN OK
-Unexpected EOF read from client
+>LF>/bin/error\x09[E]0.0\x09Error 13 Permission\\ denied
+>LF>451 SCAN Engine error 13 Permission denied
+<QUIT
+Expected EOF read from client
+End of script
 Listening on TESTSUITE/eximdir/avast_sock ... 
 Connection request
 >LF>220 ready
 <SCAN TESTSUITE/spool/scan/10HmaY-0005vi-00
 >LF>210 SCAN DATA
 >LF>/bin/clean\x09[+]
->LF>v\\ i\\ a\\ r\\ u\\ s\x09[L]9.9\x099 This ist not even an EICAR test virus.
+>LF>v\\ i\\ a\\ r\\ u\\ s\x09[L]9.0\x090 This\\ is\\ not\\ even\\ an\\ EICAR\\ test\\ virus.
+>LF>200 SCAN OK
+<QUIT
+Expected EOF read from client
+End of script
+Listening on TESTSUITE/eximdir/avast_sock ... 
+Connection request
+>LF>220 ready
+<SCAN TESTSUITE/spool/scan/10HmaZ-0005vi-00
+>LF>210 SCAN DATA
+>LF>/bin/clean\x09[+]
+>LF>/bin/error\x09[E]0.0\x09Error 42110 The\\ file\\ is\\ a\\ decompression\\ bomb
+>LF>v\\ i\\ a\\ r\\ u\\ s\x09[L]9.0\x090 This\\ is\\ not\\ even\\ an\\ EICAR\\ test\\ virus.
 >LF>200 SCAN OK
 <QUIT
 Expected EOF read from client