+++ /dev/null
-diff -urN exim-4.73_RC1/src/malware.c exim-4.73_RC1-new/src/malware.c
---- exim-4.73_RC1/src/malware.c 2010-12-23 14:19:35.000000000 +0000
-+++ exim-4.73_RC1-new/src/malware.c 2011-01-05 09:58:34.000000000 +0000
-@@ -12,6 +12,18 @@
- #include "exim.h"
- #ifdef WITH_CONTENT_SCAN
-
-+/* The maximum number of clamd servers that are supported in the configuration */
-+#define MAX_CLAMD_SERVERS 32
-+#define MAX_CLAMD_SERVERS_S "32"
-+/* Maximum length of the hostname that can be specified in the clamd address list */
-+#define MAX_CLAMD_ADDRESS_LENGTH 64
-+#define MAX_CLAMD_ADDRESS_LENGTH_S "64"
-+
-+typedef struct clamd_address_container {
-+ uschar tcp_addr[MAX_CLAMD_ADDRESS_LENGTH];
-+ unsigned int tcp_port;
-+} clamd_address_container;
-+
- /* declaration of private routines */
- static int mksd_scan_packed(int sock, uschar *scan_filename);
- static int malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking);
-@@ -1295,7 +1307,7 @@
- * WITH_OLD_CLAMAV_STREAM is defined.
- * See Exim bug 926 for details. */
- else if (strcmpic(scanner_name,US"clamd") == 0) {
-- uschar *clamd_options;
-+ uschar *clamd_options = NULL;
- uschar clamd_options_buffer[1024];
- uschar clamd_options_default[] = "/tmp/clamd";
- uschar *p, *vname, *result_tag, *response_end;
-@@ -1304,16 +1316,16 @@
- unsigned int port;
- uschar file_name[1024];
- uschar av_buffer[1024];
-- uschar hostname[256];
-+ uschar *hostname = "";
- struct hostent *he;
- struct in_addr in;
-- uschar *clamd_options2;
-- uschar clamd_options2_buffer[1024];
-- uschar clamd_options2_default[] = "";
- uschar *clamav_fbuf;
- int clam_fd, result;
- unsigned int fsize;
-- BOOL use_scan_command, fits;
-+ BOOL use_scan_command = FALSE, fits;
-+ clamd_address_container * clamd_address_vector[MAX_CLAMD_SERVERS];
-+ int current_server;
-+ int num_servers = 0;
- #ifdef WITH_OLD_CLAMAV_STREAM
- uschar av_buffer2[1024];
- int sockData;
-@@ -1327,16 +1339,60 @@
- /* no options supplied, use default options */
- clamd_options = clamd_options_default;
- }
-- if ((clamd_options2 = string_nextinlist(&av_scanner_work, &sep,
-- clamd_options2_buffer,
-- sizeof(clamd_options2_buffer))) == NULL) {
-- clamd_options2 = clamd_options2_default;
-- }
-
-- if ((*clamd_options == '/') || (strcmpic(clamd_options2,US"local") == 0))
-+ if (*clamd_options == '/')
-+ /* Local file; so we def want to use_scan_command and don't want to try
-+ * passing IP/port combinations */
- use_scan_command = TRUE;
-- else
-- use_scan_command = FALSE;
-+ else {
-+ uschar *address = clamd_options;
-+ uschar address_buffer[MAX_CLAMD_ADDRESS_LENGTH + 20];
-+
-+ /* Go through the rest of the list of host/port and construct an array
-+ * of servers to try. The first one is the bit we just passed from
-+ * clamd_options so process that first and then scan the remainder of
-+ * the address buffer */
-+ do {
-+ clamd_address_container *this_clamd;
-+
-+ /* The 'local' option means use the SCAN command over the network
-+ * socket (ie common file storage in use) */
-+ if (strcmpic(address,US"local") == 0) {
-+ use_scan_command = TRUE;
-+ continue;
-+ }
-+
-+ /* XXX: If unsuccessful we should free this memory */
-+ this_clamd =
-+ (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 ) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: 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 );
-+ break;
-+ }
-+ } while ((address = string_nextinlist(&av_scanner_work, &sep,
-+ address_buffer,
-+ 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;
-+ }
-+ }
-
- /* See the discussion of response formats below to see why we really don't
- like colons in filenames when passing filenames to ClamAV. */
-@@ -1347,45 +1403,72 @@
- return DEFER;
- }
-
-- /* socket does not start with '/' -> network socket */
-- if (*clamd_options != '/') {
-+ /* We have some network servers specified */
-+ if (num_servers) {
-
- /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
- * only supports AF_INET, but we should probably be looking to the
- * future and rewriting this to be protocol-independent anyway. */
-
-- /* extract host and port part */
-- if( sscanf(CS clamd_options, "%s %u", hostname, &port) != 2 ) {
-- log_write(0, LOG_MAIN|LOG_PANIC,
-- "malware acl condition: clamd: invalid socket '%s'", clamd_options);
-- return DEFER;
-- };
-+ while ( num_servers > 0 ) {
-+ /* Randomly pick a server to start with */
-+ current_server = random_number( num_servers );
-+
-+ debug_printf("trying server name %s, port %u\n",
-+ clamd_address_vector[current_server]->tcp_addr,
-+ clamd_address_vector[current_server]->tcp_port);
-+
-+ /* Lookup the host. This is to ensure that we connect to the same IP
-+ * 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
-+ );
-+ goto try_next_server;
-+ }
-
-- /* Lookup the host */
-- if((he = gethostbyname(CS hostname)) == 0) {
-- log_write(0, LOG_MAIN|LOG_PANIC,
-- "malware acl condition: clamd: failed to lookup host '%s'", hostname);
-- return DEFER;
-- }
-+ in = *(struct in_addr *) he->h_addr_list[0];
-
-- in = *(struct in_addr *) he->h_addr_list[0];
-+ /* 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));
-+ goto try_next_server;
-+ }
-
-- /* 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));
-- return DEFER;
-- }
-+ if (ip_connect( sock,
-+ AF_INET,
-+ (uschar*)inet_ntoa(in),
-+ clamd_address_vector[current_server]->tcp_port,
-+ 5 ) > -1) {
-+ /* Connection successfully established with a server */
-+ hostname = clamd_address_vector[current_server]->tcp_addr;
-+ break;
-+ } else {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "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));
-
-- if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
-- (void)close(sock);
-- log_write(0, LOG_MAIN|LOG_PANIC,
-- "malware acl condition: clamd: connection to %s, port %u failed (%s)",
-- inet_ntoa(in), port, strerror(errno));
-- return DEFER;
-+ (void)close(sock);
-+ }
-+
-+try_next_server:
-+ /* Remove the server from the list. XXX We should free the memory */
-+ num_servers--;
-+ int i;
-+ for( i = current_server; i < num_servers; i++ )
-+ 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;
-+ }
- } else {
- /* open the local socket */
- if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {