]> git.pld-linux.org Git - packages/exim.git/blame - exim-bug-1057.patch
- rel 3; run tidydb daily (not weekly) because on some systems databases grow too...
[packages/exim.git] / exim-bug-1057.patch
CommitLineData
db3fcec6
AM
1diff -urN exim-4.73_RC1/src/malware.c exim-4.73_RC1-new/src/malware.c
2--- exim-4.73_RC1/src/malware.c 2010-12-23 14:19:35.000000000 +0000
3+++ exim-4.73_RC1-new/src/malware.c 2011-01-05 09:58:34.000000000 +0000
f1cebd6b 4@@ -12,6 +12,18 @@
db3fcec6
AM
5 #include "exim.h"
6 #ifdef WITH_CONTENT_SCAN
7
8+/* The maximum number of clamd servers that are supported in the configuration */
9+#define MAX_CLAMD_SERVERS 32
f1cebd6b 10+#define MAX_CLAMD_SERVERS_S "32"
db3fcec6
AM
11+/* Maximum length of the hostname that can be specified in the clamd address list */
12+#define MAX_CLAMD_ADDRESS_LENGTH 64
f1cebd6b 13+#define MAX_CLAMD_ADDRESS_LENGTH_S "64"
db3fcec6
AM
14+
15+typedef struct clamd_address_container {
16+ uschar tcp_addr[MAX_CLAMD_ADDRESS_LENGTH];
17+ unsigned int tcp_port;
18+} clamd_address_container;
19+
20 /* declaration of private routines */
21 static int mksd_scan_packed(int sock, uschar *scan_filename);
22 static int malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking);
f1cebd6b 23@@ -1295,7 +1307,7 @@
db3fcec6
AM
24 * WITH_OLD_CLAMAV_STREAM is defined.
25 * See Exim bug 926 for details. */
26 else if (strcmpic(scanner_name,US"clamd") == 0) {
27- uschar *clamd_options;
28+ uschar *clamd_options = NULL;
29 uschar clamd_options_buffer[1024];
30 uschar clamd_options_default[] = "/tmp/clamd";
31 uschar *p, *vname, *result_tag, *response_end;
f1cebd6b 32@@ -1304,16 +1316,16 @@
db3fcec6
AM
33 unsigned int port;
34 uschar file_name[1024];
35 uschar av_buffer[1024];
36- uschar hostname[256];
37+ uschar *hostname = "";
38 struct hostent *he;
39 struct in_addr in;
40- uschar *clamd_options2;
41- uschar clamd_options2_buffer[1024];
42- uschar clamd_options2_default[] = "";
43 uschar *clamav_fbuf;
44 int clam_fd, result;
45 unsigned int fsize;
46- BOOL use_scan_command, fits;
47+ BOOL use_scan_command = FALSE, fits;
48+ clamd_address_container * clamd_address_vector[MAX_CLAMD_SERVERS];
49+ int current_server;
50+ int num_servers = 0;
51 #ifdef WITH_OLD_CLAMAV_STREAM
52 uschar av_buffer2[1024];
53 int sockData;
f1cebd6b 54@@ -1327,16 +1339,60 @@
db3fcec6
AM
55 /* no options supplied, use default options */
56 clamd_options = clamd_options_default;
57 }
58- if ((clamd_options2 = string_nextinlist(&av_scanner_work, &sep,
59- clamd_options2_buffer,
60- sizeof(clamd_options2_buffer))) == NULL) {
61- clamd_options2 = clamd_options2_default;
62- }
63
64- if ((*clamd_options == '/') || (strcmpic(clamd_options2,US"local") == 0))
65+ if (*clamd_options == '/')
66+ /* Local file; so we def want to use_scan_command and don't want to try
67+ * passing IP/port combinations */
68 use_scan_command = TRUE;
69- else
70- use_scan_command = FALSE;
71+ else {
72+ uschar *address = clamd_options;
73+ uschar address_buffer[MAX_CLAMD_ADDRESS_LENGTH + 20];
74+
75+ /* Go through the rest of the list of host/port and construct an array
76+ * of servers to try. The first one is the bit we just passed from
77+ * clamd_options so process that first and then scan the remainder of
78+ * the address buffer */
79+ do {
80+ clamd_address_container *this_clamd;
81+
82+ /* The 'local' option means use the SCAN command over the network
83+ * socket (ie common file storage in use) */
84+ if (strcmpic(address,US"local") == 0) {
85+ use_scan_command = TRUE;
86+ continue;
87+ }
88+
89+ /* XXX: If unsuccessful we should free this memory */
90+ this_clamd =
91+ (clamd_address_container *)store_get(sizeof(clamd_address_container));
92+
93+ /* extract host and port part */
f1cebd6b 94+ if( sscanf(CS address, "%" MAX_CLAMD_ADDRESS_LENGTH_S "s %u", this_clamd->tcp_addr,
db3fcec6
AM
95+ &(this_clamd->tcp_port)) != 2 ) {
96+ log_write(0, LOG_MAIN|LOG_PANIC,
97+ "malware acl condition: clamd: invalid address '%s'", address);
98+ continue;
99+ }
100+
101+ clamd_address_vector[num_servers] = this_clamd;
102+ num_servers++;
103+ if (num_servers >= MAX_CLAMD_SERVERS) {
104+ log_write(0, LOG_MAIN|LOG_PANIC,
f1cebd6b
AM
105+ "More than " MAX_CLAMD_SERVERS_S " clamd servers specified; "
106+ "only using the first " MAX_CLAMD_SERVERS_S );
db3fcec6
AM
107+ break;
108+ }
109+ } while ((address = string_nextinlist(&av_scanner_work, &sep,
110+ address_buffer,
111+ sizeof(address_buffer))) != NULL);
112+
113+ /* check if we have at least one server */
114+ if (!num_servers) {
115+ log_write(0, LOG_MAIN|LOG_PANIC,
116+ "malware acl condition: clamd: no useable clamd server addresses in malware configuration option.");
117+ return DEFER;
118+ }
119+ }
120
121 /* See the discussion of response formats below to see why we really don't
122 like colons in filenames when passing filenames to ClamAV. */
f1cebd6b 123@@ -1347,45 +1403,72 @@
db3fcec6
AM
124 return DEFER;
125 }
126
127- /* socket does not start with '/' -> network socket */
128- if (*clamd_options != '/') {
129+ /* We have some network servers specified */
130+ if (num_servers) {
131
132 /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
133 * only supports AF_INET, but we should probably be looking to the
134 * future and rewriting this to be protocol-independent anyway. */
135
136- /* extract host and port part */
137- if( sscanf(CS clamd_options, "%s %u", hostname, &port) != 2 ) {
138- log_write(0, LOG_MAIN|LOG_PANIC,
139- "malware acl condition: clamd: invalid socket '%s'", clamd_options);
140- return DEFER;
141- };
142+ while ( num_servers > 0 ) {
143+ /* Randomly pick a server to start with */
144+ current_server = random_number( num_servers );
145+
146+ debug_printf("trying server name %s, port %u\n",
147+ clamd_address_vector[current_server]->tcp_addr,
148+ clamd_address_vector[current_server]->tcp_port);
149+
150+ /* Lookup the host. This is to ensure that we connect to the same IP
151+ * on both connections (as one host could resolve to multiple ips) */
152+ if((he = gethostbyname(CS clamd_address_vector[current_server]->tcp_addr))
153+ == 0) {
154+ log_write(0, LOG_MAIN|LOG_PANIC,
155+ "malware acl condition: clamd: failed to lookup host '%s'",
156+ clamd_address_vector[current_server]->tcp_addr
157+ );
158+ goto try_next_server;
159+ }
160
161- /* Lookup the host */
162- if((he = gethostbyname(CS hostname)) == 0) {
163- log_write(0, LOG_MAIN|LOG_PANIC,
164- "malware acl condition: clamd: failed to lookup host '%s'", hostname);
165- return DEFER;
166- }
167+ in = *(struct in_addr *) he->h_addr_list[0];
168
169- in = *(struct in_addr *) he->h_addr_list[0];
170+ /* Open the ClamAV Socket */
171+ if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
172+ log_write(0, LOG_MAIN|LOG_PANIC,
173+ "malware acl condition: clamd: unable to acquire socket (%s)",
174+ strerror(errno));
175+ goto try_next_server;
176+ }
177
178- /* Open the ClamAV Socket */
179- if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
180- log_write(0, LOG_MAIN|LOG_PANIC,
181- "malware acl condition: clamd: unable to acquire socket (%s)",
182- strerror(errno));
183- return DEFER;
184- }
185+ if (ip_connect( sock,
186+ AF_INET,
187+ (uschar*)inet_ntoa(in),
188+ clamd_address_vector[current_server]->tcp_port,
189+ 5 ) > -1) {
190+ /* Connection successfully established with a server */
191+ hostname = clamd_address_vector[current_server]->tcp_addr;
192+ break;
193+ } else {
194+ log_write(0, LOG_MAIN|LOG_PANIC,
195+ "malware acl condition: clamd: connection to %s, port %u failed (%s)",
196+ clamd_address_vector[current_server]->tcp_addr,
197+ clamd_address_vector[current_server]->tcp_port,
198+ strerror(errno));
199
200- if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
201- (void)close(sock);
202- log_write(0, LOG_MAIN|LOG_PANIC,
203- "malware acl condition: clamd: connection to %s, port %u failed (%s)",
204- inet_ntoa(in), port, strerror(errno));
205- return DEFER;
206+ (void)close(sock);
207+ }
208+
209+try_next_server:
210+ /* Remove the server from the list. XXX We should free the memory */
211+ num_servers--;
212+ int i;
213+ for( i = current_server; i < num_servers; i++ )
214+ clamd_address_vector[i] = clamd_address_vector[i+1];
215 }
216
217+ if ( num_servers == 0 ) {
218+ log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: all clamd servers failed");
219+ return DEFER;
220+ }
221 } else {
222 /* open the local socket */
223 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
This page took 0.072588 seconds and 4 git commands to generate.