Log/return-defer: de-repeat strings
authorJeremy Harris <jgh146exb@wizmail.org>
Mon, 20 Jan 2014 01:41:34 +0000 (01:41 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Mon, 20 Jan 2014 01:41:34 +0000 (01:41 +0000)
src/src/malware.c

index 9d459bf3f607521e774f7ec20cc42131180a6a89..75c0ad21de7be4ef3fd100082c8268d735c5ebe7 100644 (file)
@@ -155,6 +155,76 @@ malware_in_file(uschar *eml_filename)
 }
 
 
+static void
+malware_errlog(const uschar * str)
+{
+  log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str);
+}
+static int
+malware_errlog_defer(const uschar * str)
+{
+  malware_errlog(str);
+  return DEFER;
+}
+
+static int
+m_scanner_errlog_defer(const uschar * scanner, const uschar * str)
+{
+  return malware_errlog_defer(string_sprintf("%s: %s", scanner, str));
+}
+
+static int
+fprotd_errlog_defer(const uschar * str)
+{
+  return m_scanner_errlog_defer("f-protd", str);
+}
+static int
+drweb_errlog_defer(const uschar * str)
+{
+  return m_scanner_errlog_defer("drweb", str);
+}
+static int
+aves_errlog_defer(const uschar * str)
+{
+  return m_scanner_errlog_defer("aveserver", str);
+}
+static int
+fsec_errlog_defer(const uschar * str)
+{
+  return m_scanner_errlog_defer("fsecure", str);
+}
+static int
+kavd_errlog_defer(const uschar * str)
+{
+  return m_scanner_errlog_defer("kavdaemon", str);
+}
+static int
+cmdl_errlog_defer(const uschar * str)
+{
+  return m_scanner_errlog_defer("commandline", str);
+}
+static int
+soph_errlog_defer(const uschar * str)
+{
+  return m_scanner_errlog_defer("sophie", str);
+}
+static int
+clmd_errlog_defer(const uschar * str)
+{
+  return m_scanner_errlog_defer("clamd", str);
+}
+static int
+mksd_errlog_defer(const uschar * str)
+{
+  return m_scanner_errlog_defer("mksd", str);
+}
+
+static void
+clmd_errlog(const uschar * str)
+{
+  log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: clamd: %s", str);
+}
+
 /*************************************************
 *          Scan content for malware              *
 *************************************************/
@@ -189,12 +259,9 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
   /* make sure the eml mbox file is spooled up */
   mbox_file = spool_mbox(&mbox_size, faking ? eml_filename : NULL);
-  if (mbox_file == NULL) {
-    /* error while spooling */
-    log_write(0, LOG_MAIN|LOG_PANIC,
-           "malware acl condition: error while creating mbox spool file");
-    return DEFER;
-  };
+  if (mbox_file == NULL)  /* error while spooling */
+    return malware_errlog_defer("error while creating mbox spool file");
+
   /* none of our current scanners need the mbox
      file as a stream, so we can close it right away */
   (void)fclose(mbox_file);
@@ -228,20 +295,18 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
   /* compile the regex, see if it works */
   re = pcre_compile(CS malware_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
-  if (re == NULL) {
-    log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: regular expression error in '%s': %s at offset %d", malware_regex, rerror, roffset);
-    return DEFER;
-  };
+  if (!re)
+    return malware_errlog_defer(
+        string_sprintf("regular expression error in '%s': %s at offset %d",
+            malware_regex, rerror, roffset));
 
   /* if av_scanner starts with a dollar, expand it first */
   if (*av_scanner == '$') {
     av_scanner_work = expand_string(av_scanner);
-    if (av_scanner_work == NULL) {
-      log_write(0, LOG_MAIN|LOG_PANIC,
-           "malware acl condition: av_scanner starts with $, but expansion failed: %s", expand_string_message);
-      return DEFER;
-    }
+    if (!av_scanner_work)
+      return malware_errlog_defer(
+           string_sprintf("av_scanner starts with $, but expansion failed: %s",
+          expand_string_message));
     else {
       debug_printf("Expanded av_scanner global: %s\n", av_scanner_work);
       /* disable result caching in this case */
@@ -255,13 +320,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
     /* 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) {
+                                     scanner_name_buffer,
+                                     sizeof(scanner_name_buffer))) == NULL) {
       /* no scanner given */
-      log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: av_scanner configuration variable is empty");
-      return DEFER;
-    };
+      return malware_errlog_defer("av_scanner configuration variable is empty");
+    }
 
   /* "f-protd" scanner type ----------------------------------------------- */
   if (strcmpic(scanner_name, US"f-protd") == 0) {
@@ -284,46 +347,37 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
     /* extract host and port part */
     if ( sscanf(CS fp_options, "%s %u-%u", hostname, &portlow, &porthigh) != 3 ) {
-      if ( sscanf(CS fp_options, "%s %u", hostname, &portlow) != 2 ) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: f-protd: invalid socket '%s'", fp_options);
-        return DEFER;
-      }
+      if ( sscanf(CS fp_options, "%s %u", hostname, &portlow) != 2 )
+       return fprotd_errlog_defer(
+          string_sprintf("invalid socket '%s'", fp_options));
       porthigh = portlow;
     }
 
     /* Lookup the host */
-    if((he = gethostbyname(CS hostname)) == 0) {
-      log_write(0, LOG_MAIN|LOG_PANIC,
-        "malware acl condition: f-protd: failed to lookup host '%s'", hostname);
-      return DEFER;
-    }
+    if((he = gethostbyname(CS hostname)) == 0)
+      return fprotd_errlog_defer(
+       string_sprintf("failed to lookup host '%s'", hostname));
 
     in = *(struct in_addr *) he->h_addr_list[0];
     port = portlow;
 
 
     /* Open the f-protd TCP socket */
-    if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
-      log_write(0, LOG_MAIN|LOG_PANIC,
-        "malware acl condition: f-protd: unable to acquire socket (%s)",
-        strerror(errno));
-      return DEFER;
-    }
+    if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0)
+      return fprotd_errlog_defer(
+       string_sprintf("unable to acquire socket (%s)", strerror(errno)));
 
     /* Try to connect to all portslow-high until connection is established */
-    for (port = portlow; !connect_ok && port < porthigh; port++) {
-      if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) >= 0) {
+    for (port = portlow; !connect_ok && port < porthigh; port++)
+      if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) >= 0)
         connect_ok = 1;
-      }
-    }
 
     if ( !connect_ok ) {
-      log_write(0, LOG_MAIN|LOG_PANIC,
-        "malware acl condition: f-protd: connection to %s, port %u-%u failed (%s)",
-        inet_ntoa(in), portlow, porthigh, strerror(errno));
+      int err = errno;
       (void)close(sock);
-      return DEFER;
+      return fprotd_errlog_defer(
+       string_sprintf("connection to %s, port %u-%u failed (%s)",
+        inet_ntoa(in), portlow, porthigh, strerror(err)));
     }
 
     DEBUG(D_acl) debug_printf("Malware scan: issuing %s GET\n", scanner_name);
@@ -342,13 +396,10 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     Ustrcat(scanrequest, " HTTP/1.0\r\n\r\n");
 
     /* send scan request */
-    if (send(sock, &scanrequest, Ustrlen(scanrequest)+1, 0) < 0) {
+    if (send(sock, &scanrequest, Ustrlen(scanrequest)+1, 0) < 0)
       (void)close(sock);
-      log_write(0, LOG_MAIN|LOG_PANIC,
-        "%s f-protd: unable to send command to socket (%s)",
-       mal_err, scanrequest);
-      return DEFER;
-    }
+      return fprotd_errlog_defer(
+       string_sprintf("unable to send command to socket (%s)", scanrequest));
 
     /* We get a lot of empty lines, so we need this hack to check for any data at all */
     while( recv(sock, buf, 1, MSG_PEEK) > 0 ) {
@@ -395,35 +446,28 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     if (*drweb_options != '/') {
 
       /* extract host and port part */
-      if( sscanf(CS drweb_options, "%s %u", hostname, &port) != 2 ) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: invalid socket '%s'", drweb_options);
-        return DEFER;
-      }
+      if( sscanf(CS drweb_options, "%s %u", hostname, &port) != 2 )
+       return drweb_errlog_defer(
+          string_sprintf("invalid socket '%s'", drweb_options));
 
       /* Lookup the host */
-      if((he = gethostbyname(CS hostname)) == 0) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: failed to lookup host '%s'", hostname);
-        return DEFER;
-      }
+      if((he = gethostbyname(CS hostname)) == 0)
+       return drweb_errlog_defer(
+          string_sprintf("failed to lookup host '%s'", hostname));
 
       in = *(struct in_addr *) he->h_addr_list[0];
 
       /* Open the drwebd TCP socket */
-      if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: unable to acquire socket (%s)",
-          strerror(errno));
-        return DEFER;
-      }
+      if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0)
+       return drweb_errlog_defer(
+          string_sprintf("unable to acquire socket (%s)", strerror(errno)));
 
       if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
+       int err = errno;
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: connection to %s, port %u failed (%s)",
-          inet_ntoa(in), port, strerror(errno));
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("connection to %s, port %u failed (%s)",
+           inet_ntoa(in), port, strerror(err)));
       }
 
       /* prepare variables */
@@ -433,20 +477,20 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       /* calc file size */
       drweb_fd = open(CS eml_filename, O_RDONLY);
       if (drweb_fd == -1) {
+       int err = errno;
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: can't open spool file %s: %s",
-          eml_filename, strerror(errno));
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("can't open spool file %s: %s",
+           eml_filename, strerror(err)));
       }
       fsize = lseek(drweb_fd, 0, SEEK_END);
       if (fsize == -1) {
+       int err = errno;
         (void)close(sock);
         (void)close(drweb_fd);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: can't seek spool file %s: %s",
-          eml_filename, strerror(errno));
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("can't seek spool file %s: %s",
+           eml_filename, strerror(err)));
       }
       drweb_slen = htonl(fsize);
       lseek(drweb_fd, 0, SEEK_SET);
@@ -461,30 +505,28 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
           (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0)) {
         (void)close(sock);
         (void)close(drweb_fd);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options);
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("unable to send commands to socket (%s)", drweb_options));
       }
 
       drweb_fbuf = (uschar *) malloc (fsize);
       if (!drweb_fbuf) {
         (void)close(sock);
         (void)close(drweb_fd);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: unable to allocate memory %u for file (%s)",
-          fsize, eml_filename);
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("unable to allocate memory %u for file (%s)",
+           fsize, eml_filename));
       }
 
       result = read (drweb_fd, drweb_fbuf, fsize);
       if (result == -1) {
+       int err = errno;
         (void)close(sock);
         (void)close(drweb_fd);
         free(drweb_fbuf);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: can't read spool file %s: %s",
-          eml_filename, strerror(errno));
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("can't read spool file %s: %s",
+           eml_filename, strerror(err)));
       }
       (void)close(drweb_fd);
 
@@ -492,27 +534,23 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       if (send(sock, drweb_fbuf, fsize, 0) < 0) {
         (void)close(sock);
         free(drweb_fbuf);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: unable to send file body to socket (%s)", drweb_options);
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("unable to send file body to socket (%s)", drweb_options));
       }
       (void)close(drweb_fd);
     }
     else {
       /* open the drwebd UNIX socket */
       sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      if (sock < 0) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: can't open UNIX socket");
-        return DEFER;
-      }
+      if (sock < 0)
+       return drweb_errlog_defer("can't open UNIX socket");
       server.sun_family = AF_UNIX;
       Ustrcpy(server.sun_path, drweb_options);
       if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
+       int err = errno;
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: unable to connect to socket (%s). errno=%d", drweb_options, errno);
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("unable to connect to socket (%s). errno=%d", drweb_options, err));
       }
 
       /* prepare variables */
@@ -530,26 +568,21 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
           (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) ||
           (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0)) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options);
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("unable to send commands to socket (%s)", drweb_options));
       }
     }
 
     /* wait for result */
     if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc))) {
       (void)close(sock);
-      log_write(0, LOG_MAIN|LOG_PANIC,
-        "malware acl condition: drweb: unable to read return code");
-      return DEFER;
+      return drweb_errlog_defer("unable to read return code");
     }
     drweb_rc = ntohl(drweb_rc);
 
     if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum))) {
       (void)close(sock);
-      log_write(0, LOG_MAIN|LOG_PANIC,
-        "malware acl condition: drweb: unable to read the number of viruses");
-      return DEFER;
+      return drweb_errlog_defer("unable to read the number of viruses");
     }
     drweb_vnum = ntohl(drweb_vnum);
 
@@ -573,18 +606,14 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
         /* read the size of report */
         if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) {
           (void)close(sock);
-          log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware acl condition: drweb: cannot read report size");
-          return DEFER;
+         return drweb_errlog_defer("cannot read report size");
         };
         drweb_slen = ntohl(drweb_slen);
 
         /* read report body */
         if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) {
           (void)close(sock);
-          log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware acl condition: drweb: cannot read report string");
-          return DEFER;
+         return drweb_errlog_defer("cannot read report string");
         };
         tmpbuf[drweb_slen] = '\0';
 
@@ -620,10 +649,9 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
        * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
        * and others are ignored */
       if (drweb_s) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "malware acl condition: drweb: drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s);
         (void)close(sock);
-        return DEFER;
+       return drweb_errlog_defer(
+          string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s));
       }
       /* no virus found */
       malware_name = NULL;
@@ -649,18 +677,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
       /* open the aveserver socket */
       sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      if (sock < 0) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: can't open UNIX socket.");
-        return DEFER;
-      }
+      if (sock < 0)
+       return aves_errlog_defer("can't open UNIX socket.");
+
       server.sun_family = AF_UNIX;
       Ustrcpy(server.sun_path, kav_options);
       if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
+       int err = errno;
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to connect to aveserver UNIX socket (%s). errno=%d", kav_options, errno);
-        return DEFER;
+       return aves_errlog_defer(
+          string_sprintf("unable to connect to UNIX socket (%s). errno=%d", kav_options, err));
       }
 
       /* read aveserver's greeting and see if it is ready (2xx greeting) */
@@ -669,10 +695,9 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       if (buf[0] != '2') {
         /* aveserver is having problems */
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: aveserver is unavailable (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") );
-        return DEFER;
-      };
+       return aves_errlog_defer(
+          string_sprintf("unavailable (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") ));
+      }
 
       /* prepare our command */
       (void)string_format(buf, 32768, "SCAN bPQRSTUW %s\r\n", eml_filename);
@@ -682,9 +707,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       /* and send it */
       if (send(sock, buf, Ustrlen(buf), 0) < 0) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to write to aveserver UNIX socket (%s)", kav_options);
-        return DEFER;
+       return aves_errlog_defer(
+          string_sprintf("unable to write to UNIX socket (%s)", kav_options));
       }
 
       malware_name = NULL;
@@ -715,9 +739,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       /* and send it */
       if (send(sock, buf, Ustrlen(buf), 0) < 0) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to write to aveserver UNIX socket (%s)", kav_options);
-        return DEFER;
+       return aves_errlog_defer(
+          string_sprintf("unable to write to UNIX socket (%s)", kav_options));
       }
 
       /* read aveserver's greeting and see if it is ready (2xx greeting) */
@@ -726,10 +749,9 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       if (buf[0] != '2') {
         /* aveserver is having problems */
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to quit aveserver dialogue (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") );
-        return DEFER;
-      };
+       return aves_errlog_defer(
+          string_sprintf("unable to quit dialogue (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") ));
+      }
 
       (void)close(sock);
 
@@ -756,24 +778,23 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
                                                sizeof(fsecure_options_buffer))) == NULL) {
          /* no options supplied, use default options */
          fsecure_options = fsecure_options_default;
-      };
+      }
 
       /* open the fsecure socket */
       sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      if (sock < 0) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: unable to open fsecure socket %s (%s)",
-                  fsecure_options, strerror(errno));
-        return DEFER;
-      }
+      if (sock < 0)
+       return fsec_errlog_defer(
+          string_sprintf("unable to open socket %s (%s)",
+                  fsecure_options, strerror(errno)));
+
       server.sun_family = AF_UNIX;
       Ustrcpy(server.sun_path, fsecure_options);
       if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
+       int err = errno;
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: unable to connect to fsecure socket %s (%s)",
-                  fsecure_options, strerror(errno));
-        return DEFER;
+       return fsec_errlog_defer(
+          string_sprintf("unable to connect to socket %s (%s)",
+                  fsecure_options, strerror(err)));
       }
 
       DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
@@ -784,21 +805,21 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       for (i=0; i != 4; i++) {
         /* debug_printf("send option \"%s\"",cmdoptions[i]); */
         if (write(sock, cmdoptions[i], Ustrlen(cmdoptions[i])) < 0) {
+         int err = errno;
           (void)close(sock);
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                    "malware acl condition: unable to write fsecure option %d to %s (%s)",
-                    i, fsecure_options, strerror(errno));
-          return DEFER;
-        };
+         return fsec_errlog_defer(
+           string_sprintf("unable to write option %d to %s (%s)",
+                    i, fsecure_options, strerror(err)));
+        }
 
         bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT);
         if (bread >0) av_buffer[bread]='\0';
         if (bread < 0) {
+         int err = errno;
           (void)close(sock);
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                    "malware acl condition: unable to read fsecure answer %d (%s)", i, strerror(errno));
-          return DEFER;
-        };
+         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] ='@';
         /* debug_printf("read answer %d read=%d \"%s\"\n", i, bread, av_buffer ); */
         /* while (Ustrstr(av_buffer, "OK\tServer configured.@") == NULL); */
@@ -808,12 +829,12 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       (void)string_format(file_name,1024,"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);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: unable to write fsecure scan to %s (%s)",
-                  fsecure_options, strerror(errno));
-        return DEFER;
-      };
+       return fsec_errlog_defer(
+          string_sprintf("unable to write scan to %s (%s)",
+                  fsecure_options, strerror(err)));
+      }
 
       /* set up match */
       /* todo also SUSPICION\t */
@@ -827,11 +848,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
         do {
           bread=ip_recv(sock, &av_buffer[i], 1, MALWARE_TIMEOUT);
           if (bread < 0) {
+           int err = errno;
             (void)close(sock);
-            log_write(0, LOG_MAIN|LOG_PANIC,
-                      "malware acl condition: unable to read fsecure result (%s)", strerror(errno));
-            return DEFER;
-          };
+           return fsec_errlog_defer(
+             string_sprintf("unable to read result (%s)", strerror(err)));
+          }
           i++;
         }
         while ((i < sizeof(av_buffer)-1 ) && (av_buffer[i-1] != '\n'));
@@ -880,18 +901,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
       /* open the kavdaemon socket */
       sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      if (sock < 0) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: can't open UNIX socket.");
-        return DEFER;
-      }
+      if (sock < 0)
+       return kavd_errlog_defer("can't open UNIX socket.");
+
       server.sun_family = AF_UNIX;
       Ustrcpy(server.sun_path, kav_options);
       if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
+       int err = errno;
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to connect to kavdaemon UNIX socket (%s). errno=%d", kav_options, errno);
-        return DEFER;
+       return kavd_errlog_defer(
+          string_sprintf("unable to connect to UNIX socket (%s). errno=%d", kav_options, err));
       }
 
       /* get current date and time, build scan request */
@@ -918,17 +937,14 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       /* send scan request */
       if (send(sock, scanrequest, Ustrlen(scanrequest)+1, 0) < 0) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to write to kavdaemon UNIX socket (%s)", kav_options);
-        return DEFER;
+       return kavd_errlog_defer(
+          string_sprintf("unable to write to UNIX socket (%s)", kav_options));
       }
 
       /* wait for result */
       if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to read 2 bytes from kavdaemon socket.");
-        return DEFER;
+       return kavd_errlog_defer("unable to read 2 bytes from socket.");
       }
 
       /* get errorcode from one nibble */
@@ -937,24 +953,18 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       /* improper kavdaemon configuration */
       if ( (kav_rc == 5) || (kav_rc == 6) ) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: please reconfigure kavdaemon to NOT disinfect or remove infected files.");
-        return DEFER;
-      };
+       return kavd_errlog_defer("please reconfigure kavdaemon to NOT disinfect or remove infected files.");
+      }
 
       if (kav_rc == 1) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: kavdaemon reported 'scanning not completed' (code 1).");
-        return DEFER;
-      };
+       return kavd_errlog_defer("reported 'scanning not completed' (code 1).");
+      }
 
       if (kav_rc == 7) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: kavdaemon reported 'kavdaemon damaged' (code 7).");
-        return DEFER;
-      };
+       return kavd_errlog_defer("reported 'kavdaemon damaged' (code 7).");
+      }
 
       /* code 8 is not handled, since it is ambigous. It appears mostly on
       bounces where part of a file has been cut off */
@@ -974,10 +984,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
           /* read report size */
           if ((bread = recv(sock, &kav_reportlen, 4, 0)) != 4) {
             (void)close(sock);
-            log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: cannot read report size from kavdaemon");
-            return DEFER;
-          };
+           return kavd_errlog_defer("cannot read report size");
+          }
 
           /* it's possible that avp returns av_buffer[1] == 1 but the
           reportsize is 0 (!?) */
@@ -1052,76 +1060,51 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       /* find scanner command line */
       if ((cmdline_scanner = string_nextinlist(&av_scanner_work, &sep,
                                           cmdline_scanner_buffer,
-                                          sizeof(cmdline_scanner_buffer))) == NULL) {
-        /* no command line supplied */
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: missing commandline specification for cmdline scanner type.");
-        return DEFER;
-      };
+                                          sizeof(cmdline_scanner_buffer))) == NULL)
+       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) {
-        /* no trigger regex supplied */
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: missing trigger specification for cmdline scanner type.");
-        return DEFER;
-      };
+                                          sizeof(cmdline_trigger_buffer))) == NULL)
+       return cmdl_errlog_defer("missing trigger specification");
 
       /* precompile trigger regex */
       cmdline_trigger_re = pcre_compile(CS cmdline_trigger, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
-      if (cmdline_trigger_re == NULL) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                 "malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_trigger, rerror, roffset);
-        return DEFER;
-      };
+      if (cmdline_trigger_re == NULL)
+       return cmdl_errlog_defer(
+          string_sprintf("regular expression error in '%s': %s at offset %d",
+           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) {
-        /* no name regex supplied */
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: missing virus name regex specification for cmdline scanner type.");
-        return DEFER;
-      };
+                                             sizeof(cmdline_regex_buffer))) == NULL)
+       return cmdl_errlog_defer("missing virus name regex specification");
 
       /* precompile name regex */
       cmdline_regex_re = pcre_compile(CS cmdline_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
-      if (cmdline_regex_re == NULL) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                 "malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_regex, rerror, roffset);
-        return DEFER;
-      };
+      if (cmdline_regex_re == NULL)
+       return cmdl_errlog_defer(
+          string_sprintf("regular expression error in '%s': %s at offset %d",
+           cmdline_regex, rerror, roffset));
 
       /* 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)
-        {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware filename does not fit in buffer [malware_internal() cmdline]");
-        return DEFER;
-        }
+       return cmdl_errlog_defer("filename does not fit in buffer");
+
       Ustrcpy(file_name, eml_filename);
       p = Ustrrchr(file_name, '/');
       if (p)
         *p = '\0';
       fits = string_format(commandline, sizeof(commandline), CS cmdline_scanner, file_name);
       if (!fits)
-        {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-            "cmdline scanner command-line does not fit in buffer");
-        return DEFER;
-        }
+       return cmdl_errlog_defer("command-line does not fit in buffer");
 
       /* redirect STDERR too */
       if (Ustrlen(commandline) + 5 > sizeof(commandline))
-        {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-            "cmdline scanner command-line does not fit in buffer (STDERR redirect)");
-        return DEFER;
-        }
+       return cmdl_errlog_defer("command-line does not fit in buffer (STDERR redirect)");
       Ustrcat(commandline," 2>&1");
 
       DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n", scanner_name, commandline);
@@ -1132,40 +1115,40 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
       scanner_out = popen(CS commandline,"r");
       if (scanner_out == NULL) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                 "malware acl condition: calling cmdline scanner (%s) failed: %s.", commandline, strerror(errno));
+       int err = errno;
         signal(SIGCHLD,eximsigchld);
         signal(SIGPIPE,eximsigpipe);
-        return DEFER;
-      };
+       return cmdl_errlog_defer(
+          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);
 
       if (scanner_record == NULL) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                 "malware acl condition: opening scanner output file (%s) failed: %s.", file_name, strerror(errno));
+       int err = errno;
         pclose(scanner_out);
         signal(SIGCHLD,eximsigchld);
         signal(SIGPIPE,eximsigpipe);
-        return DEFER;
-      };
+       return cmdl_errlog_defer(
+          string_sprintf("opening scanner output file (%s) failed: %s.",
+           file_name, strerror(err)));
+      }
 
       /* look for trigger while recording output */
       while(fgets(CS linebuffer,32767,scanner_out) != NULL) {
         if ( Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record) ) {
           /* short write */
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                 "malware acl condition: short write on scanner output file (%s).", file_name);
           pclose(scanner_out);
           signal(SIGCHLD,eximsigchld);
           signal(SIGPIPE,eximsigpipe);
-          return DEFER;
-        };
+         return cmdl_errlog_defer(
+           string_sprintf("short write on scanner output file (%s).", file_name));
+        }
         /* try trigger match */
         if (!trigger && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1))
           trigger = 1;
-      };
+      }
 
       (void)fclose(scanner_record);
       pclose(scanner_out);
@@ -1184,7 +1167,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
           if (result >= 2)
             pcre_get_substring(CS linebuffer, ovector, result, 1,
                                (const char **) &malware_name_internal);
-        };
+        }
         (void)fclose(scanner_record);
       }
       else /* no virus found */
@@ -1214,18 +1197,17 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
       /* open the sophie socket */
       sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      if (sock < 0) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: can't open UNIX socket.");
-        return DEFER;
-      }
+      if (sock < 0)
+       return soph_errlog_defer("can't open UNIX socket.");
+
       server.sun_family = AF_UNIX;
       Ustrcpy(server.sun_path, sophie_options);
       if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
+       int err = errno;
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to connect to sophie UNIX socket (%s). errno=%d", sophie_options, errno);
-        return DEFER;
+       return soph_errlog_defer(
+          string_sprintf("unable to connect to UNIX socket (%s). errno=%d",
+           sophie_options, err));
       }
 
       /* pass the scan directory to sophie */
@@ -1233,9 +1215,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       if (len > sizeof(file_name))
         {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware filename does not fit in buffer [malware_internal() sophie]");
-        return DEFER;
+       return soph_errlog_defer("malware filename does not fit in buffer");
         }
       memcpy(file_name, eml_filename, len);
       p = Ustrrchr(file_name, '/');
@@ -1249,18 +1229,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
         || write(sock, "\n", 1) != 1
          ) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to write to sophie UNIX socket (%s)", sophie_options);
-        return DEFER;
+       return soph_errlog_defer(
+          string_sprintf("unable to write to UNIX socket (%s)", sophie_options));
       }
 
       /* wait for result */
       memset(av_buffer, 0, sizeof(av_buffer));
       if ((!(bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT)) > 0)) {
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to read from sophie UNIX socket (%s)", sophie_options);
-        return DEFER;
+       return soph_errlog_defer(
+          string_sprintf("unable to read from UNIX socket (%s)", sophie_options));
       }
 
       (void)close(sock);
@@ -1271,11 +1249,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
         malware_name_internal = string_copy(&av_buffer[2]);
         malware_name = malware_name_internal;
       }
-      else if (!strncmp(CS av_buffer, "-1", 2)) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: malware acl condition: sophie reported error");
-        return DEFER;
-      }
+      else if (!strncmp(CS av_buffer, "-1", 2))
+       return soph_errlog_defer("scanner reported error");
       else /* all ok, no virus */
         malware_name = NULL;
     }
@@ -1357,17 +1332,15 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
           /* extract host and port part */
           if( sscanf(CS address, "%" MAX_CLAMD_ADDRESS_LENGTH_S "s %u", this_clamd->tcp_addr,
                                             &(this_clamd->tcp_port)) != 2 ) {
-            log_write(0, LOG_MAIN|LOG_PANIC,
-                      "malware acl condition: clamd: invalid address '%s'", address);
+           clmd_errlog(string_sprintf("invalid address '%s'", address));
             continue;
           }
 
           clamd_address_vector[num_servers] = this_clamd;
           num_servers++;
           if (num_servers >= MAX_CLAMD_SERVERS) {
-            log_write(0, LOG_MAIN|LOG_PANIC,
-                  "More than " MAX_CLAMD_SERVERS_S " clamd servers specified; "
-                  "only using the first " MAX_CLAMD_SERVERS_S );
+           clmd_errlog("More than " MAX_CLAMD_SERVERS_S " clamd servers "
+                  "specified; only using the first " MAX_CLAMD_SERVERS_S );
             break;
           }
         } while ((address = string_nextinlist(&av_scanner_work, &sep,
@@ -1375,21 +1348,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
                                         sizeof(address_buffer))) != NULL);
 
         /* check if we have at least one server */
-        if (!num_servers) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: clamd: no useable clamd server addresses in malware configuration option.");
-          return DEFER;
-        }
+        if (!num_servers)
+         return clmd_errlog_defer("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, ':')) {
-       log_write(0, LOG_MAIN|LOG_PANIC,
-           "malware acl condition: clamd: local/SCAN mode incompatible with" \
-           " : in path to email filename [%s]", eml_filename);
-       return DEFER;
-      }
+      if (use_scan_command && Ustrchr(eml_filename, ':'))
+       return clmd_errlog_defer(
+          string_sprintf("local/SCAN mode incompatible with" \
+           " : in path to email filename [%s]", eml_filename));
 
       /* We have some network servers specified */
       if (num_servers) {
@@ -1410,10 +1378,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
            * on both connections (as one host could resolve to multiple ips) */
           if((he = gethostbyname(CS clamd_address_vector[current_server]->tcp_addr))
                           == 0) {
-            log_write(0, LOG_MAIN|LOG_PANIC,
-                    "malware acl condition: clamd: failed to lookup host '%s'",
-                    clamd_address_vector[current_server]->tcp_addr
-                    );
+           clmd_errlog(string_sprintf("failed to lookup host '%s'",
+                    clamd_address_vector[current_server]->tcp_addr));
             goto try_next_server;
           }
 
@@ -1421,9 +1387,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
           /* Open the ClamAV Socket */
           if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
-            log_write(0, LOG_MAIN|LOG_PANIC,
-                      "malware acl condition: clamd: unable to acquire socket (%s)",
-                      strerror(errno));
+           clmd_errlog(string_sprintf("unable to acquire socket (%s)",
+                      strerror(errno)));
             goto try_next_server;
           }
 
@@ -1436,11 +1401,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
             hostname = clamd_address_vector[current_server]->tcp_addr;
             break;
           } else {
-            log_write(0, LOG_MAIN|LOG_PANIC,
+           clmd_errlog(string_sprintf(
                "malware acl condition: clamd: connection to %s, port %u failed (%s)",
                clamd_address_vector[current_server]->tcp_addr,
                clamd_address_vector[current_server]->tcp_port,
-               strerror(errno));
+               strerror(errno)));
 
             (void)close(sock);
           }
@@ -1453,28 +1418,24 @@ try_next_server:
             clamd_address_vector[i] = clamd_address_vector[i+1];
         }
 
-        if ( num_servers == 0 ) {
-          log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: all clamd servers failed");
-            return DEFER;
-        }
+        if ( num_servers == 0 )
+         return clmd_errlog_defer("all servers failed");
+
       } else {
         /* open the local socket */
-        if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                    "malware acl condition: clamd: unable to acquire socket (%s)",
-                    strerror(errno));
-          return DEFER;
-        }
+        if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+         return clmd_errlog_defer(
+           string_sprintf("unable to acquire socket (%s)", strerror(errno)));
 
         server.sun_family = AF_UNIX;
         Ustrcpy(server.sun_path, clamd_options);
 
         if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
+         int err = errno;
           (void)close(sock);
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                    "malware acl condition: clamd: unable to connect to UNIX socket %s (%s)",
-                    clamd_options, strerror(errno) );
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("unable to connect to UNIX socket %s (%s)",
+                    clamd_options, strerror(err) ));
         }
       }
 
@@ -1495,58 +1456,53 @@ try_next_server:
 
         /* Pass the string to ClamAV (7 = "STREAM\n") */
         if (send(sock, "STREAM\n", 7, 0) < 0) {
-          log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
-                strerror(errno));
+         int err = errno;
           (void)close(sock);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("unable to write to socket (%s)", strerror(err)));
         }
         memset(av_buffer2, 0, sizeof(av_buffer2));
         bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), MALWARE_TIMEOUT);
 
         if (bread < 0) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                "malware acl condition: clamd: unable to read PORT from socket (%s)",
-                strerror(errno));
+         int err = errno;
           (void)close(sock);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("unable to read PORT from socket (%s)",
+                strerror(err)));
         }
 
         if (bread == sizeof(av_buffer)) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                "malware acl condition: clamd: buffer too small");
           (void)close(sock);
-          return DEFER;
+         return clmd_errlog_defer("buffer too small");
         }
 
         if (!(*av_buffer2)) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                "malware acl condition: clamd: ClamAV returned null");
           (void)close(sock);
-          return DEFER;
+         return clmd_errlog_defer("ClamAV returned null");
         }
 
         av_buffer2[bread] = '\0';
         if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 ) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: clamd: Expected port information from clamd, got '%s'", av_buffer2);
           (void)close(sock);
-          return DEFER;
-        };
+         return clmd_errlog_defer(
+           string_sprintf("Expected port information from clamd, got '%s'",
+             av_buffer2));
+        }
 
         if ( (sockData = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: clamd: unable to acquire socket (%s)",
-                  strerror(errno));
+         int err = errno;
           (void)close(sock);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("unable to acquire socket (%s)", strerror(err)));
         }
 
         if (ip_connect(sockData, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: clamd: connection to %s, port %u failed (%s)",
-                  inet_ntoa(in), port, strerror(errno));
+         int err = errno;
           (void)close(sockData); (void)close(sock);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("connection to %s, port %u failed (%s)",
+                  inet_ntoa(in), port, strerror(err)));
         }
 
 #define CLOSE_SOCKDATA (void)close(sockData)
@@ -1560,11 +1516,11 @@ try_next_server:
 
         /* Pass the string to ClamAV (10 = "zINSTREAM\0") */
         if (send(sock, "zINSTREAM", 10, 0) < 0) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-              "malware acl condition: clamd: unable to send zINSTREAM to socket (%s)",
-              strerror(errno));
+         int err = errno;
           (void)close(sock);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("unable to send zINSTREAM to socket (%s)",
+              strerror(err)));
         }
 
 #define CLOSE_SOCKDATA /**/
@@ -1573,50 +1529,49 @@ try_next_server:
         /* calc file size */
         clam_fd = open(CS eml_filename, O_RDONLY);
         if (clam_fd == -1) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware acl condition: clamd: can't open spool file %s: %s",
-            eml_filename, strerror(errno));
+         int err = errno;
           CLOSE_SOCKDATA; (void)close(sock);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("can't open spool file %s: %s",
+             eml_filename, strerror(err)));
         }
         fsize = lseek(clam_fd, 0, SEEK_END);
         if (fsize == -1) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware acl condition: clamd: can't seek spool file %s: %s",
-            eml_filename, strerror(errno));
-          CLOSE_SOCKDATA; (void)close(sock);
-          return DEFER;
+         int err = errno;
+          CLOSE_SOCKDATA; (void)close(sock); (void)close(clam_fd);
+         return clmd_errlog_defer(
+           string_sprintf("can't seek spool file %s: %s",
+             eml_filename, strerror(errno)));
         }
         lseek(clam_fd, 0, SEEK_SET);
 
         clamav_fbuf = (uschar *) malloc (fsize);
         if (!clamav_fbuf) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware acl condition: clamd: unable to allocate memory %u for file (%s)",
-            fsize, eml_filename);
           CLOSE_SOCKDATA; (void)close(sock); (void)close(clam_fd);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("unable to allocate memory %u for file (%s)",
+             fsize, eml_filename));
         }
 
         result = read (clam_fd, clamav_fbuf, fsize);
         if (result == -1) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware acl condition: clamd: can't read spool file %s: %s",
-            eml_filename, strerror(errno));
+         int err = errno;
           CLOSE_SOCKDATA; (void)close(sock); (void)close(clam_fd);
           free(clamav_fbuf);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("can't read spool file %s: %s",
+             eml_filename, strerror(err)));
         }
         (void)close(clam_fd);
 
         /* send file body to socket */
 #ifdef WITH_OLD_CLAMAV_STREAM
         if (send(sockData, clamav_fbuf, fsize, 0) < 0) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware acl condition: clamd: unable to send file body to socket (%s:%u)", hostname, port);
           CLOSE_SOCKDATA; (void)close(sock);
           free(clamav_fbuf);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("unable to send file body to socket (%s:%u)",
+             hostname, port);
         }
 #else
         send_size = htonl(fsize);
@@ -1625,11 +1580,11 @@ try_next_server:
             (send(sock, clamav_fbuf, fsize, 0) < 0) ||
             (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
           {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-            "malware acl condition: clamd: unable to send file body to socket (%s:%u)", hostname, port);
           (void)close(sock);
           free(clamav_fbuf);
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("unable to send file body to socket (%s:%u)",
+             hostname, port));
           }
 #endif
 
@@ -1657,18 +1612,17 @@ try_next_server:
             eml_filename);
         if (!fits) {
           (void)close(sock);
-          log_write(0, LOG_MAIN|LOG_PANIC,
-              "malware filename does not fit in buffer [malware_internal() clamd]");
+         clmd_errlog("filename does not fit in buffer");
         }
 
         DEBUG(D_acl) debug_printf("Malware scan: issuing %s local-path scan [%s]\n",
             scanner_name, clamd_options);
 
         if (send(sock, file_name, Ustrlen(file_name), 0) < 0) {
+         int err = errno;
           (void)close(sock);
-          log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
-                    strerror(errno));
-          return DEFER;
+         return clmd_errlog_defer(
+           string_sprintf("unable to write to socket (%s)", strerror(err)));
         }
 
         /* Do not shut down the socket for writing; a user report noted that
@@ -1682,18 +1636,12 @@ try_next_server:
       bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT);
       (void)close(sock);
 
-      if (!(bread  > 0)) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: clamd: unable to read from socket (%s)",
-                  strerror(errno));
-        return DEFER;
-      }
+      if (!(bread > 0))
+       return clmd_errlog_defer(
+         string_sprintf("unable to read from socket (%s)", strerror(errno)));
 
-      if (bread == sizeof(av_buffer)) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: clamd: buffer too small");
-        return DEFER;
-      }
+      if (bread == sizeof(av_buffer))
+       return clmd_errlog_defer("buffer too small");
       /* We're now assured of a NULL at the end of av_buffer */
 
       /* Check the result. ClamAV returns one of two result formats.
@@ -1716,11 +1664,8 @@ try_next_server:
       a colon.  We will have whined loudly above if the eml_filename does (and we're
       passing a filename to clamd). */
 
-      if (!(*av_buffer)) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: clamd: ClamAV returned null");
-        return DEFER;
-      }
+      if (!(*av_buffer))
+       return clmd_errlog_defer("ClamAV returned null");
 
       /* strip newline at the end (won't be present for zINSTREAM)
       (also any trailing whitespace, which shouldn't exist, but we depend upon
@@ -1736,12 +1681,10 @@ try_next_server:
       response_end = p;
 
       /* colon in returned output? */
-      if((p = Ustrchr(av_buffer,':')) == NULL) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-                  "malware acl condition: clamd: ClamAV returned malformed result (missing colon): %s",
-                  av_buffer);
-        return DEFER;
-      }
+      if((p = Ustrchr(av_buffer,':')) == NULL)
+       return clmd_errlog_defer(
+         string_sprintf("ClamAV returned malformed result (missing colon): %s",
+                  av_buffer));
 
       /* strip filename */
       while (*p && isspace(*++p)) /**/;
@@ -1769,23 +1712,18 @@ try_next_server:
        malware_name = malware_name_internal;
        DEBUG(D_acl) debug_printf("Malware found, name \"%s\"\n", malware_name);
 
-      } else if (Ustrcmp(result_tag, "ERROR") == 0) {
-       log_write(0, LOG_MAIN|LOG_PANIC,
-                 "malware acl condition: clamd: ClamAV returned: %s",
-                 av_buffer);
-       return DEFER;
+      } else if (Ustrcmp(result_tag, "ERROR") == 0)
+       return clmd_errlog_defer(
+         string_sprintf("ClamAV returned: %s", av_buffer));
 
-      else if (Ustrcmp(result_tag, "OK") == 0) {
+      else if (Ustrcmp(result_tag, "OK") == 0) {
        /* Everything should be OK */
        malware_name = NULL;
        DEBUG(D_acl) debug_printf("Malware not found\n");
 
-      } else {
-       log_write(0, LOG_MAIN|LOG_PANIC,
-                 "malware acl condition: clamd: unparseable response from ClamAV: {%s}",
-                 av_buffer);
-       return DEFER;
-      }
+      } else
+       return clmd_errlog_defer(
+         string_sprintf("unparseable response from ClamAV: {%s}", av_buffer));
 
     } /* clamd */
 
@@ -1807,27 +1745,23 @@ try_next_server:
                                             sizeof(mksd_options_buffer))) != NULL) {
         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)) {
-          log_write(0, LOG_MAIN|LOG_PANIC,
-                    "malware acl condition: mksd: invalid option '%s'", mksd_options);
-          return DEFER;
-        }
+      (mksd_maxproc < 1) || (mksd_maxproc > 32))
+         return mksd_errlog_defer(
+           string_sprintf("invalid option '%s'", mksd_options));
       }
 
       /* open the mksd socket */
       sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      if (sock < 0) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: can't open UNIX socket.");
-        return DEFER;
-      }
+      if (sock < 0)
+       return mksd_errlog_defer("can't open UNIX socket.");
+
       server.sun_family = AF_UNIX;
       Ustrcpy(server.sun_path, "/var/run/mksd/socket");
       if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
+       int err = errno;
         (void)close(sock);
-        log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware acl condition: unable to connect to mksd UNIX socket (/var/run/mksd/socket). errno=%d", errno);
-        return DEFER;
+       return mksd_errlog_defer(
+         string_sprintf("unable to connect to mksd UNIX socket (/var/run/mksd/socket). errno=%d", err));
       }
 
       malware_name = NULL;
@@ -1842,11 +1776,9 @@ try_next_server:
     /* ----------------------------------------------------------------------- */
 
     /* "unknown" scanner type ------------------------------------------------- */
-    else {
-      log_write(0, LOG_MAIN|LOG_PANIC,
-             "malware condition: unknown scanner type '%s'", scanner_name);
-      return DEFER;
-    };
+    else
+      return malware_errlog_defer(string_sprintf("unknown scanner type '%s'",
+       scanner_name));
     /* ----------------------------------------------------------------------- */
 
     /* set "been here, done that" marker */
@@ -1899,8 +1831,7 @@ mksd_writev (int sock, struct iovec *iov, int iovcnt)
     while ((i < 0) && (errno == EINTR));
     if (i <= 0) {
       close (sock);
-      log_write(0, LOG_MAIN|LOG_PANIC,
-                "malware acl condition: unable to write to mksd UNIX socket (/var/run/mksd/socket)");
+      malware_errlog("unable to write to mksd UNIX socket (/var/run/mksd/socket)");
       return -1;
     }
 
@@ -1927,8 +1858,7 @@ mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size)
   do {
     if ((i = recv (sock, av_buffer+offset, av_buffer_size-offset, 0)) <= 0) {
       close (sock);
-      log_write(0, LOG_MAIN|LOG_PANIC,
-                "malware acl condition: unable to read from mksd UNIX socket (/var/run/mksd/socket)");
+      malware_errlog("unable to read from mksd UNIX socket (/var/run/mksd/socket)");
       return -1;
     }
 
@@ -1936,8 +1866,7 @@ mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size)
     /* offset == av_buffer_size -> buffer full */
     if (offset == av_buffer_size) {
       close (sock);
-      log_write(0, LOG_MAIN|LOG_PANIC,
-                "malware acl condition: malformed reply received from mksd");
+      malware_errlog("malformed reply received from mksd");
       return -1;
     }
   } while (av_buffer[offset-1] != '\n');
@@ -1959,9 +1888,7 @@ mksd_parse_line (char *line)
     case 'A': /* ERR */
       if ((p = strchr (line, '\n')) != NULL)
         *p = '\0';
-      log_write(0, LOG_MAIN|LOG_PANIC,
-                "malware acl condition: mksd scanner failed: %s", line);
-      return DEFER;
+      return mksd_errlog_defer(string_sprintf("scanner failed: %s", line));
 
     default: /* VIR */
       if ((p = strchr (line, '\n')) != NULL) {
@@ -1974,9 +1901,8 @@ mksd_parse_line (char *line)
             return OK;
           }
       }
-      log_write(0, LOG_MAIN|LOG_PANIC,
-                "malware acl condition: malformed reply received from mksd: %s", line);
-      return DEFER;
+      return mksd_errlog_defer(
+       string_sprintf("malformed reply received from mksd: %s", line));
   }
 }