]> git.pld-linux.org Git - packages/exim.git/blob - exim-bug-1057.patch
- build fix
[packages/exim.git] / exim-bug-1057.patch
1 diff -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
4 @@ -12,6 +12,18 @@
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
10 +#define MAX_CLAMD_SERVERS_S "32"
11 +/* Maximum length of the hostname that can be specified in the clamd address list */
12 +#define MAX_CLAMD_ADDRESS_LENGTH 64
13 +#define MAX_CLAMD_ADDRESS_LENGTH_S "64"
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);
23 @@ -1295,7 +1307,7 @@
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;
32 @@ -1304,16 +1316,16 @@
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;
54 @@ -1327,16 +1339,60 @@
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 */
94 +          if( sscanf(CS address, "%" MAX_CLAMD_ADDRESS_LENGTH_S "s %u", this_clamd->tcp_addr,
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,
105 +                  "More than " MAX_CLAMD_SERVERS_S " clamd servers specified; "
106 +                  "only using the first " MAX_CLAMD_SERVERS_S );
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. */
123 @@ -1347,45 +1403,72 @@
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.047661 seconds and 3 git commands to generate.