]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/malware.c
Safer handling of argument-logging memory of cwd
[user/henk/code/exim.git] / src / src / malware.c
index 7c57c0090058fd0d66f7e086a7a8352acc28d0f0..a5de8a93834253e9ab4781673923193c8c840922 100644 (file)
 #include "exim.h"
 #ifdef WITH_CONTENT_SCAN       /* entire file */
 
-typedef enum {M_FPROTD, M_DRWEB, M_AVES, M_FSEC, M_KAVD, M_CMDL,
-               M_SOPHIE, M_CLAMD, M_SOCK, M_MKSD, M_AVAST, M_FPROT6D} scanner_t;
+typedef enum {
+#ifndef DISABLE_MAL_FFROTD
+       M_FPROTD,
+#endif
+#ifndef DISABLE_MAL_FFROT6D
+       M_FPROT6D,
+#endif
+#ifndef DISABLE_MAL_DRWEB
+       M_DRWEB,
+#endif
+#ifndef DISABLE_MAL_AVE
+       M_AVES,
+#endif
+#ifndef DISABLE_MAL_FSECURE
+       M_FSEC,
+#endif
+#ifndef DISABLE_MAL_KAV
+       M_KAVD,
+#endif
+#ifndef DISABLE_MAL_SOPHIE
+       M_SOPHIE,
+#endif
+#ifndef DISABLE_MAL_CLAM
+       M_CLAMD,
+#endif
+#ifndef DISABLE_MAL_MKS
+       M_MKSD,
+#endif
+#ifndef DISABLE_MAL_AVAST
+       M_AVAST,
+#endif
+#ifndef DISABLE_MAL_SOCK
+       M_SOCK,
+#endif
+#ifndef DISABLE_MAL_CMDLINE
+       M_CMDL,
+#endif
+       } scanner_t;
 typedef enum {MC_NONE, MC_TCP, MC_UNIX, MC_STRM} contype_t;
 static struct scan
 {
@@ -180,12 +216,14 @@ 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];
+unescape(uschar *p)
+{
+uschar *p0;
+for (; *p; ++p)
+  if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
+    for (p0 = p; *p0; ++p0) *p0 = p0[1];
 }
 
 /* --- malware_*_defer --- */
@@ -1921,13 +1959,13 @@ b_seek:   err = errno;
 #ifndef DISABLE_MAL_AVAST
     case M_AVAST: /* "avast" scanner type ----------------------------------- */
       {
-      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;
+      BOOL more_data = FALSE;
+      BOOL strict = TRUE;
 
       /* According to Martin Tuma @avast the protocol uses "escaped
       whitespace", that is, every embedded whitespace is backslash
@@ -2015,6 +2053,12 @@ b_seek:   err = errno;
              if ((scanrequest = string_nextinlist(&av_scanner_work, &sep,
                                NULL, 0)))
                {
+                if (Ustrcmp(scanrequest, "pass_unscanned") == 0)
+                  {
+                  DEBUG(D_acl) debug_printf_indent("pass unscanned files as clean\n");
+                  strict = FALSE;
+                  goto sendreq;
+                  }
                scanrequest = string_sprintf("%s\n", scanrequest);
                avast_stage = AVA_OPT;          /* just sent option */
                DEBUG(D_acl) debug_printf_indent("send to avast OPTION: %s", scanrequest);
@@ -2040,35 +2084,16 @@ b_seek:   err = errno;
 
            case AVA_RSP:
 
-             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;
+             if (isdigit(buf[0]))  /* We're done */
                 goto endloop;
-               }
 
-              #if 0
-              /* found malware or another error already, nothing to do anymore, just read on */
-              if (malware_name || error_message)
+              if (malware_name)     /* Nothing else matters, just read on */
                 break;
-              #endif
 
-             if (pcre_exec(ava_re_clean, NULL, CS buf, slen,
-                   0, 0, ovector, nelem(ovector)) > 0)
+             if (pcre_exec(ava_re_clean, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
                break;
 
-             if (malware_name)
-                break;
-
-              if (malware_name = m_pcre_exec(ava_re_virus, buf))
+              if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
                 {
                 unescape(malware_name);
                 DEBUG(D_acl)
@@ -2076,18 +2101,25 @@ b_seek:   err = errno;
                 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))
+              if (strict)           /* treat scanner errors as malware */
                 {
-                unescape(malware_name);
-                DEBUG(D_acl)
-                  debug_printf_indent("unescaped error message: '%s'\n", malware_name);
+                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;
+                  }
+                }
+              else if (pcre_exec(ava_re_error, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
+                {
+                log_write(0, LOG_MAIN, "internal scanner error (ignored): %s", buf);
                 break;
                 }
 
              /* here also for any unexpected response from the scanner */
+              DEBUG(D_acl) debug_printf("avast response not handled: '%s'\n", buf);
+
              goto endloop;
 
            default:    log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
@@ -2095,23 +2127,23 @@ b_seek:   err = errno;
            }
          }
        }
+
       endloop:
 
-      switch(avast_stage)
-       {
-       case AVA_HELO:
-       case AVA_OPT:
-       case AVA_RSP:
-                        if (nread == -1) error_message = "EOF from scanner";
-                        else if (nread < 0) error_message = "timeout from scanner";
+      if (nread == -1) error_message = US"EOF from scanner";
+      else if (nread < 0) error_message = US"timeout from scanner";
+      else if (nread == 0) error_message = US"got nothing from scanner";
+      else if (buf[0] != '2') error_message = buf;
 
-        case AVA_DONE:
-                        if (error_message)
-                          return m_panic_defer_3(scanent, CUS callout_address, error_message, sock);
+      DEBUG(D_acl) debug_printf_indent("sent to avast QUIT\n");
+      if (send(sock, "QUIT\n", 5, 0) == -1)
+        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 (error_message)
+        return m_panic_defer_3(scanent, CUS callout_address, error_message, sock);
 
-       default:        break;
-       }
-      break;
       }
 #endif
   }    /* scanner type switch */