Replace more fixed-size buffers with allocated strings
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 26 Jan 2014 21:03:59 +0000 (21:03 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 26 Jan 2014 21:03:59 +0000 (21:03 +0000)
src/src/malware.c

index 75c0ad21de7be4ef3fd100082c8268d735c5ebe7..fb99580a8697a7061242a458dab171ca3826325c 100644 (file)
@@ -28,7 +28,11 @@ static int malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
 /* SHUT_WR seems to be undefined on Unixware? */
 #ifndef SHUT_WR
-#define SHUT_WR 1
+# define SHUT_WR 1
+#endif
+
+#ifndef nelements
+# define nelements(arr) (sizeof(arr) / sizeof(arr[0]))
 #endif
 
 
@@ -83,20 +87,11 @@ Returns:      Exim message processing code (OK, FAIL, DEFER, ...)
 int
 malware(uschar **listptr)
 {
-  uschar scan_filename[1024];
-  BOOL fits;
+  uschar * scan_filename;
   int ret;
 
-  fits = string_format(scan_filename, sizeof(scan_filename),
-      CS"%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
-  if (!fits)
-    {
-    av_failed = TRUE;
-    log_write(0, LOG_MAIN|LOG_PANIC,
-        "malware filename does not fit in buffer [malware()]");
-    return DEFER;
-  }
-
+  scan_filename = string_sprintf("%s/scan/%s/%s.eml",
+                                                               spool_directory, message_id, message_id);
   ret = malware_internal(listptr, scan_filename, FALSE);
   if (ret == DEFER) av_failed = TRUE;
 
@@ -247,9 +242,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
   uschar *list = *listptr;
   uschar *av_scanner_work = av_scanner;
   uschar *scanner_name;
-  uschar scanner_name_buffer[16];
   uschar *malware_regex;
-  uschar malware_regex_buffer[64];
   uschar malware_regex_default[] = ".+";
   unsigned long mbox_size;
   FILE *mbox_file;
@@ -267,28 +260,24 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
   (void)fclose(mbox_file);
 
   /* extract the malware regex to match against from the option list */
-  if ((malware_regex = string_nextinlist(&list, &sep,
-                                         malware_regex_buffer,
-                                         sizeof(malware_regex_buffer))) != NULL) {
+  if (!(malware_regex = string_nextinlist(&list, &sep, NULL, 0))) {
 
     /* parse 1st option */
     if ( (strcmpic(malware_regex,US"false") == 0) ||
          (Ustrcmp(malware_regex,"0") == 0) ) {
       /* explicitly no matching */
       return FAIL;
-    };
+    }
 
     /* special cases (match anything except empty) */
     if ( (strcmpic(malware_regex,US"true") == 0) ||
          (Ustrcmp(malware_regex,"*") == 0) ||
          (Ustrcmp(malware_regex,"1") == 0) ) {
       malware_regex = malware_regex_default;
-    };
+    }
   }
-  else {
-    /* empty means "don't match anything" */
+  else /* empty means "don't match anything" */
     return FAIL;
-  };
 
   /* Reset sep that is set by previous string_nextinlist() call */
   sep = 0;
@@ -312,16 +301,14 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       /* disable result caching in this case */
       malware_name = NULL;
       malware_ok = 0;
-    };
+    }
   }
 
   /* Do not scan twice. */
   if (malware_ok == 0) {
 
     /* find the scanner type from the av_scanner option */
-    if ((scanner_name = string_nextinlist(&av_scanner_work, &sep,
-                                     scanner_name_buffer,
-                                     sizeof(scanner_name_buffer))) == NULL) {
+    if (!(scanner_name = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) {
       /* no scanner given */
       return malware_errlog_defer("av_scanner configuration variable is empty");
     }
@@ -329,24 +316,22 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
   /* "f-protd" scanner type ----------------------------------------------- */
   if (strcmpic(scanner_name, US"f-protd") == 0) {
     uschar *fp_options, *fp_scan_option;
-    uschar fp_scan_option_buffer[1024];
-    uschar fp_options_buffer[1024];
     uschar fp_options_default[] = "localhost 10200-10204";
     uschar hostname[256];
     unsigned int port, portlow, porthigh, connect_ok=0, detected=0, par_count = 0;
     struct hostent *he;
     struct in_addr in;
     int sock;
-    uschar scanrequest[2048], buf[32768], *strhelper, *strhelper2;
+    uschar * scanrequest;
+    uschar buf[32768], *strhelper, *strhelper2;
 
-    if ((fp_options = string_nextinlist(&av_scanner_work, &sep,
-      fp_options_buffer, sizeof(fp_options_buffer))) == NULL) {
+    if (!(fp_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) {
       /* no options supplied, use default options */
       fp_options = fp_options_default;
-    };
+    }
 
     /* extract host and port part */
-    if ( sscanf(CS fp_options, "%s %u-%u", hostname, &portlow, &porthigh) != 3 ) {
+    if ( sscanf(CS fp_options, "%255s %u-%u", hostname, &portlow, &porthigh) != 3 ) {
       if ( sscanf(CS fp_options, "%s %u", hostname, &portlow) != 2 )
        return fprotd_errlog_defer(
           string_sprintf("invalid socket '%s'", fp_options));
@@ -381,19 +366,15 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     }
 
     DEBUG(D_acl) debug_printf("Malware scan: issuing %s GET\n", scanner_name);
-    (void)string_format(scanrequest, 1024, CS"GET %s", eml_filename);
+    scanrequest = string_sprintf("GET %s", eml_filename);
 
     while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep,
-      fp_scan_option_buffer, sizeof(fp_scan_option_buffer))) != NULL) {
-      if ( par_count ) {
-        Ustrcat(scanrequest, "%20");
-      } else {
-        Ustrcat(scanrequest, "?");
-      }
-      Ustrcat(scanrequest, fp_scan_option);
+                         NULL, 0))) {
+      scanrequest = string_sprintf("%s%s%s", scanrequest,
+                               par_count ? "%20" : "?", fp_scan_option);
       par_count++;
     }
-    Ustrcat(scanrequest, " HTTP/1.0\r\n\r\n");
+    scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
 
     /* send scan request */
     if (send(sock, &scanrequest, Ustrlen(scanrequest)+1, 0) < 0)
@@ -423,12 +404,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
   /* v0.0 - initial release -- support for unix sockets      */
   else if (strcmpic(scanner_name,US"drweb") == 0) {
     uschar *drweb_options;
-    uschar drweb_options_buffer[1024];
     uschar drweb_options_default[] = "/usr/local/drweb/run/drwebd.sock";
     struct sockaddr_un server;
-    int sock, result, ovector[30];
+    int sock, result, ovector[10*3];
     unsigned int port, fsize;
-    uschar tmpbuf[1024], *drweb_fbuf;
+    uschar * tmpbuf, *drweb_fbuf;
     int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
         drweb_vnum, drweb_slen, drweb_fin = 0x0000;
     unsigned long bread;
@@ -437,16 +417,15 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     struct in_addr in;
     pcre *drweb_re;
 
-    if ((drweb_options = string_nextinlist(&av_scanner_work, &sep,
-      drweb_options_buffer, sizeof(drweb_options_buffer))) == NULL) {
+    if (!(drweb_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) {
       /* no options supplied, use default options */
       drweb_options = drweb_options_default;
-    };
+    }
 
     if (*drweb_options != '/') {
 
       /* extract host and port part */
-      if( sscanf(CS drweb_options, "%s %u", hostname, &port) != 2 )
+      if( sscanf(CS drweb_options, "%255s %u", hostname, &port) != 2 )
        return drweb_errlog_defer(
           string_sprintf("invalid socket '%s'", drweb_options));
 
@@ -607,18 +586,20 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
         if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) {
           (void)close(sock);
          return drweb_errlog_defer("cannot read report size");
-        };
+        }
         drweb_slen = ntohl(drweb_slen);
+       tmpbuf = store_get(drweb_slen);
 
         /* read report body */
         if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) {
           (void)close(sock);
          return drweb_errlog_defer("cannot read report string");
-        };
+        }
         tmpbuf[drweb_slen] = '\0';
 
         /* try matcher on the line, grab substring */
-        result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30);
+        result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
+                               ovector, nelements(ovector));
         if (result >= 2) {
          const char * pre_malware_nb;
 
@@ -655,25 +636,22 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       }
       /* no virus found */
       malware_name = NULL;
-    };
+    }
     (void)close(sock);
   }
   /* ----------------------------------------------------------------------- */
     else if (strcmpic(scanner_name,US"aveserver") == 0) {
       uschar *kav_options;
-      uschar kav_options_buffer[1024];
       uschar kav_options_default[] = "/var/run/aveserver";
       uschar buf[32768];
       struct sockaddr_un server;
       int sock;
       int result;
 
-      if ((kav_options = string_nextinlist(&av_scanner_work, &sep,
-                                           kav_options_buffer,
-                                           sizeof(kav_options_buffer))) == NULL) {
+      if (!(kav_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) {
         /* no options supplied, use default options */
         kav_options = kav_options_default;
-      };
+      }
 
       /* open the aveserver socket */
       sock = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -690,7 +668,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       }
 
       /* read aveserver's greeting and see if it is ready (2xx greeting) */
-      recv_line(sock, buf, 32768);
+      recv_line(sock, buf, sizeof(buf));
 
       if (buf[0] != '2') {
         /* aveserver is having problems */
@@ -700,7 +678,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       }
 
       /* prepare our command */
-      (void)string_format(buf, 32768, "SCAN bPQRSTUW %s\r\n", eml_filename);
+      (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n",
+                                               eml_filename);
 
       DEBUG(D_acl) debug_printf("Malware scan: issuing %s SCAN\n", scanner_name);
 
@@ -714,11 +693,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       malware_name = NULL;
       result = 0;
       /* read response lines, find malware name and final response */
-      while (recv_line(sock, buf, 32768) > 0) {
+      while (recv_line(sock, buf, sizeof(buf)) > 0) {
         debug_printf("aveserver: %s\n", buf);
-        if (buf[0] == '2') {
+        if (buf[0] == '2')
          break;
-       } else if (buf[0] == '5') {
+       if (buf[0] == '5') {
           /* aveserver is having problems */
           log_write(0, LOG_MAIN|LOG_PANIC,
              "malware acl condition: unable to scan file %s (Responded: %s).",
@@ -734,7 +713,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       }
 
       /* prepare our command */
-      (void)string_format(buf, 32768, "quit\r\n");
+      (void)string_format(buf, sizeof(buf), "quit\r\n");
 
       /* and send it */
       if (send(sock, buf, Ustrlen(buf), 0) < 0) {
@@ -744,13 +723,14 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       }
 
       /* read aveserver's greeting and see if it is ready (2xx greeting) */
-      recv_line(sock, buf, 32768);
+      recv_line(sock, buf, sizeof(buf));
 
       if (buf[0] != '2') {
         /* aveserver is having problems */
         (void)close(sock);
        return aves_errlog_defer(
-          string_sprintf("unable to quit dialogue (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") ));
+          string_sprintf("unable to quit dialogue (Responded: %s).",
+                       ((buf[0] != 0) ? buf : (uschar *)"nothing") ));
       }
 
       (void)close(sock);
@@ -760,11 +740,10 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     /* "fsecure" scanner type ------------------------------------------------- */
     else if (strcmpic(scanner_name,US"fsecure") == 0) {
       uschar *fsecure_options;
-      uschar fsecure_options_buffer[1024];
       uschar fsecure_options_default[] = "/var/run/.fsav";
       struct sockaddr_un server;
       int sock, i, j, bread = 0;
-      uschar file_name[1024];
+      uschar * file_name;
       uschar av_buffer[1024];
       pcre *fs_inf;
       static uschar *cmdoptions[] = { US"CONFIGURE\tARCHIVE\t1\n",
@@ -773,9 +752,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
                                       US"CONFIGURE\tMIME\t1\n" };
 
       malware_name = NULL;
-      if ((fsecure_options = string_nextinlist(&av_scanner_work, &sep,
-                                               fsecure_options_buffer,
-                                               sizeof(fsecure_options_buffer))) == NULL) {
+      if (!(fsecure_options = string_nextinlist(&av_scanner_work, &sep,
+                                               NULL, 0))) {
          /* no options supplied, use default options */
          fsecure_options = fsecure_options_default;
       }
@@ -820,14 +798,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
          return fsec_errlog_defer(
            string_sprintf("unable to read answer %d (%s)", i, strerror(errno)));
         }
-        for (j=0;j<bread;j++) if((av_buffer[j]=='\r')||(av_buffer[j]=='\n')) av_buffer[j] ='@';
+        for (j=0;j<bread;j++)
+         if((av_buffer[j]=='\r')||(av_buffer[j]=='\n'))
+           av_buffer[j] ='@';
         /* debug_printf("read answer %d read=%d \"%s\"\n", i, bread, av_buffer ); */
         /* while (Ustrstr(av_buffer, "OK\tServer configured.@") == NULL); */
-      };
+      }
 
       /* pass the mailfile to fsecure */
-      (void)string_format(file_name,1024,"SCAN\t%s\n", eml_filename);
-      /* debug_printf("send scan %s",file_name); */
+      file_name = string_sprintf("SCAN\t%s\n", eml_filename);
+      /* debug_printf("send scan %s", file_name); */
       if (write(sock, file_name, Ustrlen(file_name)) < 0) {
        int err = errno;
         (void)close(sock);
@@ -842,7 +822,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
       /* read report, linewise */
       do {
-        int ovector[30];
+        int ovector[10*3];
         i = 0;
         memset(av_buffer, 0, sizeof(av_buffer));
         do {
@@ -862,14 +842,15 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
         /* Really search for virus again? */
         if (malware_name == NULL) {
           /* try matcher on the line, grab substring */
-          i = pcre_exec(fs_inf, NULL, CS av_buffer, Ustrlen(av_buffer), 0, 0, ovector, 30);
+          i = pcre_exec(fs_inf, NULL, CS av_buffer, Ustrlen(av_buffer), 0, 0,
+                       ovector, nelements(ovector));
           if (i >= 2) {
             /* Got it */
             pcre_get_substring(CS av_buffer, ovector, i, 1,
                                (const char **) &malware_name_internal);
             malware_name = malware_name_internal;
-          };
-        };
+          }
+        }
       }
       while (Ustrstr(av_buffer, "OK\tScan ok.") == NULL);
       (void)close(sock);
@@ -879,25 +860,21 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     /* "kavdaemon" scanner type ------------------------------------------------ */
     else if (strcmpic(scanner_name,US"kavdaemon") == 0) {
       uschar *kav_options;
-      uschar kav_options_buffer[1024];
       uschar kav_options_default[] = "/var/run/AvpCtl";
       struct sockaddr_un server;
       int sock;
       time_t t;
       uschar tmpbuf[1024];
-      uschar scanrequest[1024];
+      uschar * scanrequest;
       int kav_rc;
       unsigned long kav_reportlen, bread;
       pcre *kav_re;
       uschar *p;
-      int fits;
 
-      if ((kav_options = string_nextinlist(&av_scanner_work, &sep,
-                                           kav_options_buffer,
-                                           sizeof(kav_options_buffer))) == NULL) {
+      if (!(kav_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) {
         /* no options supplied, use default options */
         kav_options = kav_options_default;
-      };
+      }
 
       /* open the kavdaemon socket */
       sock = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -920,13 +897,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       The side-effect is that the test framework scanning may end up in
       scanning more than was requested, but for the normal interface, this is
       fine. */
-      strftime(CS tmpbuf, sizeof(tmpbuf), "<0>%d %b %H:%M:%S:%%s", localtime(&t));
-      fits = string_format(scanrequest, 1024,CS tmpbuf, eml_filename);
-      if (!fits) {
-        (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware filename does not fit in buffer [malware_internal() kavdaemon]");
-      }
+      strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t));
+      scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename);
       p = Ustrrchr(scanrequest, '/');
       if (p)
         *p = '\0';
@@ -1002,32 +974,31 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
             /* read report, linewise */
             while (kav_reportlen > 0) {
               int result = 0;
-              int ovector[30];
+              int ovector[10*3];
 
               bread = 0;
               while ( recv(sock, &tmpbuf[bread], 1, 0) == 1 ) {
                 kav_reportlen--;
                 if ( (tmpbuf[bread] == '\n') || (bread > 1021) ) break;
                 bread++;
-              };
+              }
               bread++;
               tmpbuf[bread] = '\0';
 
               /* try matcher on the line, grab substring */
-              result = pcre_exec(kav_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30);
+              result = pcre_exec(kav_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
+                               ovector, nelements(ovector));
               if (result >= 2) {
                 pcre_get_substring(CS tmpbuf, ovector, result, 1,
                                    (const char **) &malware_name_internal);
                 break;
-              };
-            };
-          };
-        };
+              }
+            }
+          }
+        }
       }
-      else {
-        /* no virus found */
+      else /* no virus found */
         malware_name = NULL;
-      };
 
       (void)close(sock);
     }
@@ -1037,15 +1008,12 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     /* "cmdline" scanner type ------------------------------------------------ */
     else if (strcmpic(scanner_name,US"cmdline") == 0) {
       uschar *cmdline_scanner;
-      uschar cmdline_scanner_buffer[1024];
       uschar *cmdline_trigger;
-      uschar cmdline_trigger_buffer[1024];
       const pcre *cmdline_trigger_re;
       uschar *cmdline_regex;
-      uschar cmdline_regex_buffer[1024];
       const pcre *cmdline_regex_re;
-      uschar file_name[1024];
-      uschar commandline[1024];
+      uschar * file_name;
+      uschar * commandline;
       void (*eximsigchld)(int);
       void (*eximsigpipe)(int);
       FILE *scanner_out = NULL;
@@ -1053,20 +1021,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       uschar linebuffer[32767];
       int trigger = 0;
       int result;
-      int ovector[30];
+      int ovector[10*3];
       uschar *p;
       BOOL fits;
 
       /* find scanner command line */
-      if ((cmdline_scanner = string_nextinlist(&av_scanner_work, &sep,
-                                          cmdline_scanner_buffer,
-                                          sizeof(cmdline_scanner_buffer))) == NULL)
+      if (!(cmdline_scanner = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
        return cmdl_errlog_defer("missing commandline specification");
 
       /* find scanner output trigger */
-      if ((cmdline_trigger = string_nextinlist(&av_scanner_work, &sep,
-                                          cmdline_trigger_buffer,
-                                          sizeof(cmdline_trigger_buffer))) == NULL)
+      if (!(cmdline_trigger = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
        return cmdl_errlog_defer("missing trigger specification");
 
       /* precompile trigger regex */
@@ -1077,9 +1041,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
            cmdline_trigger, rerror, roffset));
 
       /* find scanner name regex */
-      if ((cmdline_regex = string_nextinlist(&av_scanner_work, &sep,
-                                             cmdline_regex_buffer,
-                                             sizeof(cmdline_regex_buffer))) == NULL)
+      if (!(cmdline_regex = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
        return cmdl_errlog_defer("missing virus name regex specification");
 
       /* precompile name regex */
@@ -1091,21 +1053,15 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
       /* prepare scanner call; despite the naming, file_name holds a directory
       name which is documented as the value given to %s. */
-      if (Ustrlen(eml_filename) > sizeof(file_name) - 1)
-       return cmdl_errlog_defer("filename does not fit in buffer");
 
-      Ustrcpy(file_name, eml_filename);
+      file_name = string_copy(eml_filename);
       p = Ustrrchr(file_name, '/');
       if (p)
         *p = '\0';
-      fits = string_format(commandline, sizeof(commandline), CS cmdline_scanner, file_name);
-      if (!fits)
-       return cmdl_errlog_defer("command-line does not fit in buffer");
+      commandline = string_sprintf(CS cmdline_scanner, file_name);
 
       /* redirect STDERR too */
-      if (Ustrlen(commandline) + 5 > sizeof(commandline))
-       return cmdl_errlog_defer("command-line does not fit in buffer (STDERR redirect)");
-      Ustrcat(commandline," 2>&1");
+      commandline = string_sprintf("%s 2>&1", commandline);
 
       DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n", scanner_name, commandline);
 
@@ -1122,8 +1078,9 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
           string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));
       }
 
-      (void)string_format(file_name,1024,"%s/scan/%s/%s_scanner_output", spool_directory, message_id, message_id);
-      scanner_record = modefopen(file_name,"wb",SPOOL_MODE);
+      file_name = string_sprintf("%s/scan/%s/%s_scanner_output",
+                               spool_directory, message_id, message_id);
+      scanner_record = modefopen(file_name, "wb", SPOOL_MODE);
 
       if (scanner_record == NULL) {
        int err = errno;
@@ -1136,7 +1093,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       }
 
       /* look for trigger while recording output */
-      while(fgets(CS linebuffer,32767,scanner_out) != NULL) {
+      while(fgets(CS linebuffer, sizeof(linebuffer), scanner_out) != NULL) {
         if ( Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record) ) {
           /* short write */
           pclose(scanner_out);
@@ -1160,10 +1117,12 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
        malware_name = US"unknown";
 
         /* re-open the scanner output file, look for name match */
-        scanner_record = fopen(CS file_name,"rb");
+        scanner_record = fopen(CS file_name, "rb");
         while(fgets(CS linebuffer,32767,scanner_record) != NULL) {
           /* try match */
-          result = pcre_exec(cmdline_regex_re, NULL, CS linebuffer, Ustrlen(linebuffer), 0, 0, ovector, 30);
+          result = pcre_exec(cmdline_regex_re, NULL,
+                               CS linebuffer, Ustrlen(linebuffer), 0, 0,
+                               ovector, nelements(ovector));
           if (result >= 2)
             pcre_get_substring(CS linebuffer, ovector, result, 1,
                                (const char **) &malware_name_internal);
@@ -1179,18 +1138,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     /* "sophie" scanner type ------------------------------------------------- */
     else if (strcmpic(scanner_name,US"sophie") == 0) {
       uschar *sophie_options;
-      uschar sophie_options_buffer[1024];
       uschar sophie_options_default[] = "/var/run/sophie";
       int bread = 0;
       struct sockaddr_un server;
-      int sock, len;
+      int sock;
       uschar *p;
-      uschar file_name[1024];
+      uschar * file_name;
       uschar av_buffer[1024];
 
-      if ((sophie_options = string_nextinlist(&av_scanner_work, &sep,
-                                          sophie_options_buffer,
-                                          sizeof(sophie_options_buffer))) == NULL) {
+      if (!(sophie_options = string_nextinlist(&av_scanner_work, &sep,
+                                          NULL, 0))) {
         /* no options supplied, use default options */
         sophie_options = sophie_options_default;
       }
@@ -1211,13 +1168,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       }
 
       /* pass the scan directory to sophie */
-      len = Ustrlen(eml_filename) + 1;
-      if (len > sizeof(file_name))
-        {
-        (void)close(sock);
-       return soph_errlog_defer("malware filename does not fit in buffer");
-        }
-      memcpy(file_name, eml_filename, len);
+      file_name = string_copy(eml_filename);
       p = Ustrrchr(file_name, '/');
       if (p)
         *p = '\0';
@@ -1271,13 +1222,12 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
      * See Exim bug 926 for details.  */
     else if (strcmpic(scanner_name,US"clamd") == 0) {
       uschar *clamd_options = NULL;
-      uschar clamd_options_buffer[1024];
       uschar clamd_options_default[] = "/tmp/clamd";
       uschar *p, *vname, *result_tag, *response_end;
       struct sockaddr_un server;
       int sock,bread=0;
       unsigned int port;
-      uschar file_name[1024];
+      uschar * file_name;
       uschar av_buffer[1024];
       uschar *hostname = "";
       struct hostent *he;
@@ -1285,7 +1235,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       uschar *clamav_fbuf;
       int clam_fd, result;
       unsigned int fsize;
-      BOOL use_scan_command = FALSE, fits;
+      BOOL use_scan_command = FALSE;
       clamd_address_container * clamd_address_vector[MAX_CLAMD_SERVERS];
       int current_server;
       int num_servers = 0;
@@ -1296,9 +1246,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       uint32_t send_size, send_final_zeroblock;
 #endif
 
-      if ((clamd_options = string_nextinlist(&av_scanner_work, &sep,
-                                             clamd_options_buffer,
-                                             sizeof(clamd_options_buffer))) == NULL) {
+      if (!(clamd_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) {
         /* no options supplied, use default options */
         clamd_options = clamd_options_default;
       }
@@ -1472,7 +1420,7 @@ try_next_server:
                 strerror(err)));
         }
 
-        if (bread == sizeof(av_buffer)) {
+        if (bread == sizeof(av_buffer2)) {
           (void)close(sock);
          return clmd_errlog_defer("buffer too small");
         }
@@ -1608,12 +1556,7 @@ try_next_server:
         Since ClamAV now handles emails (and has for quite some time) we can
         just use the email file itself. */
         /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
-        fits = string_format(file_name, sizeof(file_name), "SCAN %s\n",
-            eml_filename);
-        if (!fits) {
-          (void)close(sock);
-         clmd_errlog("filename does not fit in buffer");
-        }
+        file_name = string_sprintf("SCAN %s\n", eml_filename);
 
         DEBUG(D_acl) debug_printf("Malware scan: issuing %s local-path scan [%s]\n",
             scanner_name, clamd_options);
@@ -1734,18 +1677,19 @@ try_next_server:
     else if (strcmpic(scanner_name,US"mksd") == 0) {
       uschar *mksd_options;
       char *mksd_options_end;
-      uschar mksd_options_buffer[32];
       int mksd_maxproc = 1;  /* default, if no option supplied */
       struct sockaddr_un server;
       int sock;
       int retval;
 
-      if ((mksd_options = string_nextinlist(&av_scanner_work, &sep,
-                                            mksd_options_buffer,
-                                            sizeof(mksd_options_buffer))) != NULL) {
+      if (!(mksd_options = string_nextinlist(&av_scanner_work, &sep,
+                                            NULL, 0))) {
         mksd_maxproc = (int) strtol(CS mksd_options, &mksd_options_end, 10);
-        if ((*mksd_options == '\0') || (*mksd_options_end != '\0') ||
-      (mksd_maxproc < 1) || (mksd_maxproc > 32))
+        if (  *mksd_options == '\0'
+          || *mksd_options_end != '\0'
+          || mksd_maxproc < 1
+          || mksd_maxproc > 32
+          )
          return mksd_errlog_defer(
            string_sprintf("invalid option '%s'", mksd_options));
       }
@@ -1783,7 +1727,7 @@ try_next_server:
 
     /* set "been here, done that" marker */
     malware_ok = 1;
-  };
+  }
 
   /* match virus name against pattern (caseless ------->----------v) */
   if ( (malware_name != NULL) &&
@@ -1791,9 +1735,8 @@ try_next_server:
     DEBUG(D_acl) debug_printf("Matched regex to malware [%s] [%s]\n", malware_regex, malware_name);
     return OK;
   }
-  else {
+  else
     return FAIL;
-  };
 }
 
 
@@ -1809,7 +1752,7 @@ recv_line(int sock, uschar *buffer, int size)
     if ((p-buffer) > (size-2)) break;
     if (*p == '\n') break;
     if (*p != '\r') p++;
-  };
+  }
   *p = '\0';
 
   return (p-buffer);