Refactor socket comms
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 26 Jan 2014 22:49:30 +0000 (22:49 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 26 Jan 2014 22:49:30 +0000 (22:49 +0000)
src/src/malware.c

index fb99580a8697a7061242a458dab171ca3826325c..ece46f2b246323e45ebd55bc2e6fac1820028539 100644 (file)
@@ -220,6 +220,44 @@ clmd_errlog(const uschar * str)
   log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: clamd: %s", str);
 }
 
+/*************************************************/
+
+static int
+m_unixsocket(uschar * path, uschar ** errstr)
+{
+int sock;
+struct sockaddr_un server;
+
+if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+  *errstr = "can't open UNIX socket.";
+  return -1;
+}
+
+server.sun_family = AF_UNIX;
+Ustrcpy(server.sun_path, path);
+if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
+  int err = errno;
+  (void)close(sock);
+  *errstr =  string_sprintf("unable to connect to UNIX socket (%s): %s",
+               path, strerror(err));
+  return -1;
+  }
+return sock;
+}
+
+static int
+m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
+{
+if (send(sock, buf, cnt, 0) < 0) {
+  int err = errno;
+  (void)close(sock);
+  *errstr = string_sprintf("unable to send to socket (%s): %s",
+        buf, strerror(err));
+  return -1;
+  }
+return sock;
+}
+
 /*************************************************
 *          Scan content for malware              *
 *************************************************/
@@ -249,6 +287,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
   int roffset;
   const pcre *re;
   const uschar *rerror;
+  uschar * errstr;
 
   /* make sure the eml mbox file is spooled up */
   mbox_file = spool_mbox(&mbox_size, faking ? eml_filename : NULL);
@@ -325,10 +364,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     uschar * scanrequest;
     uschar buf[32768], *strhelper, *strhelper2;
 
-    if (!(fp_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) {
-      /* no options supplied, use default options */
+    if (!(fp_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
       fp_options = fp_options_default;
-    }
 
     /* extract host and port part */
     if ( sscanf(CS fp_options, "%255s %u-%u", hostname, &portlow, &porthigh) != 3 ) {
@@ -361,8 +398,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       int err = errno;
       (void)close(sock);
       return fprotd_errlog_defer(
-       string_sprintf("connection to %s, port %u-%u failed (%s)",
-        inet_ntoa(in), portlow, porthigh, strerror(err)));
+               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);
@@ -377,10 +414,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
     scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest);
 
     /* send scan request */
-    if (send(sock, &scanrequest, Ustrlen(scanrequest)+1, 0) < 0)
-      (void)close(sock);
-      return fprotd_errlog_defer(
-       string_sprintf("unable to send command to socket (%s)", scanrequest));
+    if (m_sock_send(sock, &scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
+      return fprotd_errlog_defer(errstr);
 
     /* 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 ) {
@@ -393,8 +428,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
            malware_name_internal = string_copy(strhelper+6);
           }
         } else if ( Ustrstr(buf, US"<summary code=\"") )
-         malware_name = Ustrstr(buf, US"<summary code=\"11\">")
-           ? malware_name_internal : NULL;
+           malware_name = Ustrstr(buf, US"<summary code=\"11\">")
+             ? malware_name_internal : NULL;
       }
     }
     (void)close(sock);
@@ -417,10 +452,8 @@ 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, NULL, 0))) {
-      /* no options supplied, use default options */
+    if (!(drweb_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
       drweb_options = drweb_options_default;
-    }
 
     if (*drweb_options != '/') {
 
@@ -519,18 +552,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       (void)close(drweb_fd);
     }
     else {
-      /* open the drwebd UNIX socket */
-      sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      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);
-       return drweb_errlog_defer(
-          string_sprintf("unable to connect to socket (%s). errno=%d", drweb_options, err));
-      }
+      if((sock = m_unixsocket(drweb_options, &errstr)) < 0)
+       return drweb_errlog_defer(errstr);
 
       /* prepare variables */
       drweb_cmd = htonl(DRWEBD_SCAN_CMD);
@@ -648,24 +671,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       int sock;
       int result;
 
-      if (!(kav_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) {
-        /* no options supplied, use default options */
+      if (!(kav_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
         kav_options = kav_options_default;
-      }
-
-      /* open the aveserver socket */
-      sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      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);
-       return aves_errlog_defer(
-          string_sprintf("unable to connect to UNIX socket (%s). errno=%d", kav_options, err));
-      }
+      if((sock = m_unixsocket(kav_options, &errstr)) < 0)
+       return aves_errlog_defer(errstr);
 
       /* read aveserver's greeting and see if it is ready (2xx greeting) */
       recv_line(sock, buf, sizeof(buf));
@@ -684,11 +694,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       DEBUG(D_acl) debug_printf("Malware scan: issuing %s SCAN\n", scanner_name);
 
       /* and send it */
-      if (send(sock, buf, Ustrlen(buf), 0) < 0) {
-        (void)close(sock);
-       return aves_errlog_defer(
-          string_sprintf("unable to write to UNIX socket (%s)", kav_options));
-      }
+      if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
+       return aves_errlog_defer(errstr);
 
       malware_name = NULL;
       result = 0;
@@ -716,11 +723,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       (void)string_format(buf, sizeof(buf), "quit\r\n");
 
       /* and send it */
-      if (send(sock, buf, Ustrlen(buf), 0) < 0) {
-        (void)close(sock);
-       return aves_errlog_defer(
-          string_sprintf("unable to write to UNIX socket (%s)", kav_options));
-      }
+      if (m_sock_send(sock, buf, Ustrlen(buf), &errstr) < 0)
+       return aves_errlog_defer(errstr);
 
       /* read aveserver's greeting and see if it is ready (2xx greeting) */
       recv_line(sock, buf, sizeof(buf));
@@ -739,56 +743,35 @@ 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_default[] = "/var/run/.fsav";
+      uschar *fsec_options;
+      uschar fsec_options_default[] = "/var/run/.fsav";
       struct sockaddr_un server;
       int sock, i, j, bread = 0;
       uschar * file_name;
       uschar av_buffer[1024];
-      pcre *fs_inf;
-      static uschar *cmdoptions[] = { US"CONFIGURE\tARCHIVE\t1\n",
+      pcre * fs_inf;
+      static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n",
                                       US"CONFIGURE\tTIMEOUT\t0\n",
                                       US"CONFIGURE\tMAXARCH\t5\n",
                                       US"CONFIGURE\tMIME\t1\n" };
 
       malware_name = NULL;
-      if (!(fsecure_options = string_nextinlist(&av_scanner_work, &sep,
-                                               NULL, 0))) {
-         /* 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)
-       return fsec_errlog_defer(
-          string_sprintf("unable to open socket %s (%s)",
-                  fsecure_options, strerror(errno)));
+      if (!(fsec_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
+         fsec_options = fsec_options_default;
 
-      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);
-       return fsec_errlog_defer(
-          string_sprintf("unable to connect to socket %s (%s)",
-                  fsecure_options, strerror(err)));
-      }
+      if((sock = m_unixsocket(fsec_options, &errstr)) < 0)
+       return fsec_errlog_defer(errstr);
 
       DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
-          scanner_name, fsecure_options);
+          scanner_name, fsec_options);
 
       /* pass options */
       memset(av_buffer, 0, sizeof(av_buffer));
-      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);
-         return fsec_errlog_defer(
-           string_sprintf("unable to write option %d to %s (%s)",
-                    i, fsecure_options, strerror(err)));
-        }
+      for (i=0; i != nelements(cmdopt); i++) {
+        /* debug_printf("send option \"%s\"",cmdopt[i]); */
+
+        if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0)
+         return fsec_errlog_defer(errstr);
 
         bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT);
         if (bread >0) av_buffer[bread]='\0';
@@ -807,14 +790,10 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
 
       /* pass the mailfile to fsecure */
       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);
-       return fsec_errlog_defer(
-          string_sprintf("unable to write scan to %s (%s)",
-                  fsecure_options, strerror(err)));
-      }
+      if (m_sock_send(sock, file_name, Ustrlen(file_name), &errstr) < 0)
+       return fsec_errlog_defer(errstr);
 
       /* set up match */
       /* todo also SUSPICION\t */
@@ -871,24 +850,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       pcre *kav_re;
       uschar *p;
 
-      if (!(kav_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) {
-        /* no options supplied, use default options */
+      if (!(kav_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
         kav_options = kav_options_default;
-      }
 
-      /* open the kavdaemon socket */
-      sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      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);
-       return kavd_errlog_defer(
-          string_sprintf("unable to connect to UNIX socket (%s). errno=%d", kav_options, err));
-      }
+      if((sock = m_unixsocket(kav_options, &errstr)) < 0)
+       return kavd_errlog_defer(errstr);
 
       /* get current date and time, build scan request */
       time(&t);
@@ -907,11 +873,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
           scanner_name, kav_options);
 
       /* send scan request */
-      if (send(sock, scanrequest, Ustrlen(scanrequest)+1, 0) < 0) {
-        (void)close(sock);
-       return kavd_errlog_defer(
-          string_sprintf("unable to write to UNIX socket (%s)", kav_options));
-      }
+      if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0)
+       return kavd_errlog_defer(errstr);
 
       /* wait for result */
       if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) {
@@ -1137,8 +1100,8 @@ 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_default[] = "/var/run/sophie";
+      uschar * soph_options;
+      uschar soph_default_options[] = "/var/run/sophie";
       int bread = 0;
       struct sockaddr_un server;
       int sock;
@@ -1146,42 +1109,26 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       uschar * file_name;
       uschar av_buffer[1024];
 
-      if (!(sophie_options = string_nextinlist(&av_scanner_work, &sep,
-                                          NULL, 0))) {
-        /* no options supplied, use default options */
-        sophie_options = sophie_options_default;
-      }
-
-      /* open the sophie socket */
-      sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      if (sock < 0)
-       return soph_errlog_defer("can't open UNIX socket.");
+      if (!(soph_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
+        soph_options = soph_default_options;
 
-      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);
-       return soph_errlog_defer(
-          string_sprintf("unable to connect to UNIX socket (%s). errno=%d",
-           sophie_options, err));
-      }
+      if((sock = m_unixsocket(soph_options, &errstr)) < 0)
+       return soph_errlog_defer(errstr);
 
       /* pass the scan directory to sophie */
       file_name = string_copy(eml_filename);
-      p = Ustrrchr(file_name, '/');
-      if (p)
+      if ((p = Ustrrchr(file_name, '/')))
         *p = '\0';
 
       DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n",
-          scanner_name, sophie_options);
+          scanner_name, soph_options);
 
       if (  write(sock, file_name, Ustrlen(file_name)) < 0
         || write(sock, "\n", 1) != 1
          ) {
         (void)close(sock);
        return soph_errlog_defer(
-          string_sprintf("unable to write to UNIX socket (%s)", sophie_options));
+          string_sprintf("unable to write to UNIX socket (%s)", soph_options));
       }
 
       /* wait for result */
@@ -1189,7 +1136,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
       if ((!(bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT)) > 0)) {
         (void)close(sock);
        return soph_errlog_defer(
-          string_sprintf("unable to read from UNIX socket (%s)", sophie_options));
+          string_sprintf("unable to read from UNIX socket (%s)", soph_options));
       }
 
       (void)close(sock);
@@ -1246,10 +1193,8 @@ 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, NULL, 0))) {
-        /* no options supplied, use default options */
+      if (!(clamd_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
         clamd_options = clamd_options_default;
-      }
 
       if (*clamd_options == '/')
         /* Local file; so we def want to use_scan_command and don't want to try
@@ -1278,8 +1223,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking)
               (clamd_address_container *)store_get(sizeof(clamd_address_container));
 
           /* 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 ) {
+          if( sscanf(CS address, "%" MAX_CLAMD_ADDRESS_LENGTH_S "s %u",
+                this_clamd->tcp_addr, &(this_clamd->tcp_port)) != 2 ) {
            clmd_errlog(string_sprintf("invalid address '%s'", address));
             continue;
           }
@@ -1370,21 +1315,8 @@ try_next_server:
          return clmd_errlog_defer("all servers failed");
 
       } else {
-        /* open the local socket */
-        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);
-         return clmd_errlog_defer(
-           string_sprintf("unable to connect to UNIX socket %s (%s)",
-                    clamd_options, strerror(err) ));
-        }
+        if((sock = m_unixsocket(clamd_options, &errstr)) < 0)
+         return clmd_errlog_defer(errstr);
       }
 
       /* have socket in variable "sock"; command to use is semi-independent of
@@ -1403,12 +1335,9 @@ try_next_server:
             scanner_name);
 
         /* Pass the string to ClamAV (7 = "STREAM\n") */
-        if (send(sock, "STREAM\n", 7, 0) < 0) {
-         int err = errno;
-          (void)close(sock);
-         return clmd_errlog_defer(
-           string_sprintf("unable to write to socket (%s)", strerror(err)));
-        }
+        if (m_sock_send(sock, "STREAM\n", 7, &errstr) < 0)
+         return clmd_errlog_defer(errstr);
+
         memset(av_buffer2, 0, sizeof(av_buffer2));
         bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), MALWARE_TIMEOUT);
 
@@ -1674,7 +1603,7 @@ try_next_server:
 
 
     /* "mksd" scanner type --------------------------------------------------- */
-    else if (strcmpic(scanner_name,US"mksd") == 0) {
+    else if (strcmpic(scanner_name, US"mksd") == 0) {
       uschar *mksd_options;
       char *mksd_options_end;
       int mksd_maxproc = 1;  /* default, if no option supplied */
@@ -1682,7 +1611,7 @@ try_next_server:
       int sock;
       int retval;
 
-      if (!(mksd_options = string_nextinlist(&av_scanner_work, &sep,
+      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'
@@ -1694,19 +1623,8 @@ try_next_server:
            string_sprintf("invalid option '%s'", mksd_options));
       }
 
-      /* open the mksd socket */
-      sock = socket(AF_UNIX, SOCK_STREAM, 0);
-      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);
-       return mksd_errlog_defer(
-         string_sprintf("unable to connect to mksd UNIX socket (/var/run/mksd/socket). errno=%d", err));
-      }
+      if((sock = m_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0)
+       return mksd_errlog_defer(errstr);
 
       malware_name = NULL;