1 | /*
|
---|
2 | * Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
|
---|
3 | * HTTP/1.1 compliance by Arkadiusz Miskiewicz <misiek@pld.org.pl>
|
---|
4 | * Proxy support by Nigel Horne <njh@bandsman.co.uk>
|
---|
5 | * Proxy authorization support by Gernot Tenchio <g.tenchio@telco-tech.de>
|
---|
6 | * (uses fmt_base64() from libowfat (http://www.fefe.de))
|
---|
7 | * CDIFF code (C) 2006 Sensory Networks, Inc.
|
---|
8 | *
|
---|
9 | * This program is free software; you can redistribute it and/or modify
|
---|
10 | * it under the terms of the GNU General Public License as published by
|
---|
11 | * the Free Software Foundation; either version 2 of the License, or
|
---|
12 | * (at your option) any later version.
|
---|
13 | *
|
---|
14 | * This program is distributed in the hope that it will be useful,
|
---|
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
17 | * GNU General Public License for more details.
|
---|
18 | *
|
---|
19 | * You should have received a copy of the GNU General Public License
|
---|
20 | * along with this program; if not, write to the Free Software
|
---|
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
---|
22 | * MA 02110-1301, USA.
|
---|
23 | */
|
---|
24 |
|
---|
25 | #if HAVE_CONFIG_H
|
---|
26 | #include "clamav-config.h"
|
---|
27 | #endif
|
---|
28 |
|
---|
29 | /* for strptime, it is POSIX, but defining _XOPEN_SOURCE to 600
|
---|
30 | * fails on Solaris because it would require a c99 compiler,
|
---|
31 | * 500 fails completely on Solaris, and FreeBSD, and w/o _XOPEN_SOURCE
|
---|
32 | * strptime is not defined on Linux */
|
---|
33 | #define _GNU_SOURCE
|
---|
34 | #define __EXTENSIONS
|
---|
35 |
|
---|
36 | #include <stdio.h>
|
---|
37 | #include <stdlib.h>
|
---|
38 | #ifdef HAVE_UNISTD_H
|
---|
39 | #include <unistd.h>
|
---|
40 | #endif
|
---|
41 | #include <string.h>
|
---|
42 | #ifdef HAVE_STRINGS_H
|
---|
43 | #include <strings.h>
|
---|
44 | #endif
|
---|
45 | #include <ctype.h>
|
---|
46 | #ifndef _WIN32
|
---|
47 | #include <netinet/in.h>
|
---|
48 | #include <netdb.h>
|
---|
49 | #include <arpa/inet.h>
|
---|
50 | #include <sys/socket.h>
|
---|
51 | #include <sys/time.h>
|
---|
52 | #endif
|
---|
53 | #include <sys/types.h>
|
---|
54 | #include <time.h>
|
---|
55 | #include <fcntl.h>
|
---|
56 | #ifndef _WIN32
|
---|
57 | #include <sys/wait.h>
|
---|
58 | #endif
|
---|
59 | #include <sys/stat.h>
|
---|
60 | #include <dirent.h>
|
---|
61 | #include <errno.h>
|
---|
62 | #include <zlib.h>
|
---|
63 |
|
---|
64 | #include "target.h"
|
---|
65 |
|
---|
66 | #include "manager.h"
|
---|
67 | #include "notify.h"
|
---|
68 | #include "dns.h"
|
---|
69 | #include "execute.h"
|
---|
70 | #include "nonblock.h"
|
---|
71 | #include "mirman.h"
|
---|
72 |
|
---|
73 | #include "shared/optparser.h"
|
---|
74 | #include "shared/output.h"
|
---|
75 | #include "shared/misc.h"
|
---|
76 | #include "shared/cdiff.h"
|
---|
77 | #include "shared/tar.h"
|
---|
78 | #include "shared/clamdcom.h"
|
---|
79 |
|
---|
80 | #include "libclamav/clamav.h"
|
---|
81 | #include "libclamav/others.h"
|
---|
82 | #include "libclamav/str.h"
|
---|
83 | #include "libclamav/cvd.h"
|
---|
84 | #include "libclamav/regex_list.h"
|
---|
85 |
|
---|
86 | extern char updtmpdir[512], dbdir[512];
|
---|
87 |
|
---|
88 | #define CHDIR_ERR(x) \
|
---|
89 | if(chdir(x) == -1) \
|
---|
90 | logg("!Can't chdir to %s\n", x);
|
---|
91 |
|
---|
92 | #ifndef HAVE_GETADDRINFO
|
---|
93 | static const char *ghbn_err(int err) /* hstrerror() */
|
---|
94 | {
|
---|
95 | switch(err) {
|
---|
96 | case HOST_NOT_FOUND:
|
---|
97 | return "Host not found";
|
---|
98 |
|
---|
99 | case NO_DATA:
|
---|
100 | return "No IP address";
|
---|
101 |
|
---|
102 | case NO_RECOVERY:
|
---|
103 | return "Unrecoverable DNS error";
|
---|
104 |
|
---|
105 | case TRY_AGAIN:
|
---|
106 | return "Temporary DNS error";
|
---|
107 |
|
---|
108 | default:
|
---|
109 | return "Unknown error";
|
---|
110 | }
|
---|
111 | }
|
---|
112 | #endif
|
---|
113 |
|
---|
114 | static int getclientsock(const char *localip, int prot)
|
---|
115 | {
|
---|
116 | int socketfd = -1;
|
---|
117 |
|
---|
118 | #ifdef SUPPORT_IPv6
|
---|
119 | if(prot == AF_INET6)
|
---|
120 | socketfd = socket(AF_INET6, SOCK_STREAM, 0);
|
---|
121 | else
|
---|
122 | #endif
|
---|
123 | socketfd = socket(AF_INET, SOCK_STREAM, 0);
|
---|
124 | if(socketfd < 0) {
|
---|
125 | logg("!Can't create new socket\n");
|
---|
126 | return -1;
|
---|
127 | }
|
---|
128 |
|
---|
129 | if(localip) {
|
---|
130 | #ifdef HAVE_GETADDRINFO
|
---|
131 | struct addrinfo *res;
|
---|
132 | int ret;
|
---|
133 |
|
---|
134 | ret = getaddrinfo(localip, NULL, NULL, &res);
|
---|
135 | if(ret) {
|
---|
136 | logg("!Could not resolve local ip address '%s': %s\n", localip, gai_strerror(ret));
|
---|
137 | logg("^Using standard local ip address and port for fetching.\n");
|
---|
138 | } else {
|
---|
139 | char ipaddr[46];
|
---|
140 |
|
---|
141 | if(bind(socketfd, res->ai_addr, res->ai_addrlen) != 0) {
|
---|
142 | logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
|
---|
143 | logg("^Using default client ip.\n");
|
---|
144 | } else {
|
---|
145 | void *addr;
|
---|
146 |
|
---|
147 | #ifdef SUPPORT_IPv6
|
---|
148 | if(res->ai_family == AF_INET6)
|
---|
149 | addr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
|
---|
150 | else
|
---|
151 | #endif
|
---|
152 | addr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
|
---|
153 |
|
---|
154 | if(inet_ntop(res->ai_family, addr, ipaddr, sizeof(ipaddr)))
|
---|
155 | logg("*Using ip '%s' for fetching.\n", ipaddr);
|
---|
156 | }
|
---|
157 | freeaddrinfo(res);
|
---|
158 | }
|
---|
159 |
|
---|
160 | #else /* IPv4 */
|
---|
161 | struct hostent *he;
|
---|
162 |
|
---|
163 | if(!(he = gethostbyname(localip))) {
|
---|
164 | logg("!Could not resolve local ip address '%s': %s\n", localip, ghbn_err(h_errno));
|
---|
165 | logg("^Using standard local ip address and port for fetching.\n");
|
---|
166 | } else {
|
---|
167 | struct sockaddr_in client;
|
---|
168 | unsigned char *ia;
|
---|
169 | char ipaddr[16];
|
---|
170 |
|
---|
171 | memset((char *) &client, 0, sizeof(client));
|
---|
172 | client.sin_family = AF_INET;
|
---|
173 | client.sin_addr = *(struct in_addr *) he->h_addr_list[0];
|
---|
174 | if(bind(socketfd, (struct sockaddr *) &client, sizeof(struct sockaddr_in)) != 0) {
|
---|
175 | logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
|
---|
176 | logg("^Using default client ip.\n");
|
---|
177 | } else {
|
---|
178 | ia = (unsigned char *) he->h_addr_list[0];
|
---|
179 | sprintf(ipaddr, "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]);
|
---|
180 | logg("*Using ip '%s' for fetching.\n", ipaddr);
|
---|
181 | }
|
---|
182 | }
|
---|
183 | #endif
|
---|
184 | }
|
---|
185 |
|
---|
186 | return socketfd;
|
---|
187 | }
|
---|
188 |
|
---|
189 | #ifdef HAVE_GETADDRINFO
|
---|
190 | static int qcompare(const void *a, const void *b)
|
---|
191 | {
|
---|
192 | return (*(const struct addrinfo **) a)->ai_flags - (*(const struct addrinfo **) b)->ai_flags;
|
---|
193 | }
|
---|
194 | #endif
|
---|
195 |
|
---|
196 | static int wwwconnect(const char *server, const char *proxy, int pport, char *ip, const char *localip, int ctimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist)
|
---|
197 | {
|
---|
198 | int socketfd, port, ret;
|
---|
199 | unsigned int ips = 0, ignored = 0, i;
|
---|
200 | #ifdef HAVE_GETADDRINFO
|
---|
201 | struct addrinfo hints, *res = NULL, *rp, *loadbal_rp = NULL, *addrs[128];
|
---|
202 | char port_s[6], loadbal_ipaddr[46];
|
---|
203 | uint32_t loadbal = 1, minsucc = 0xffffffff, minfail = 0xffffffff, addrnum = 0;
|
---|
204 | int ipv4start = -1, ipv4end = -1;
|
---|
205 | struct mirdat_ip *md;
|
---|
206 | #else
|
---|
207 | struct sockaddr_in name;
|
---|
208 | struct hostent *host;
|
---|
209 | unsigned char *ia;
|
---|
210 | #endif
|
---|
211 | char ipaddr[46];
|
---|
212 | const char *hostpt;
|
---|
213 |
|
---|
214 | if(ip)
|
---|
215 | strcpy(ip, "UNKNOWN");
|
---|
216 |
|
---|
217 | if(proxy) {
|
---|
218 | hostpt = proxy;
|
---|
219 |
|
---|
220 | if(!(port = pport)) {
|
---|
221 | const struct servent *webcache = getservbyname("webcache", "TCP");
|
---|
222 |
|
---|
223 | if(webcache)
|
---|
224 | port = ntohs(webcache->s_port);
|
---|
225 | else
|
---|
226 | port = 8080;
|
---|
227 |
|
---|
228 | endservent();
|
---|
229 | }
|
---|
230 |
|
---|
231 | } else {
|
---|
232 | hostpt = server;
|
---|
233 | port = 80;
|
---|
234 | }
|
---|
235 |
|
---|
236 | #ifdef HAVE_GETADDRINFO
|
---|
237 | memset(&hints, 0, sizeof(hints));
|
---|
238 | #ifdef SUPPORT_IPv6
|
---|
239 | hints.ai_family = AF_UNSPEC;
|
---|
240 | #else
|
---|
241 | hints.ai_family = AF_INET;
|
---|
242 | #endif
|
---|
243 | hints.ai_socktype = SOCK_STREAM;
|
---|
244 | snprintf(port_s, sizeof(port_s), "%d", port);
|
---|
245 | port_s[sizeof(port_s) - 1] = 0;
|
---|
246 | ret = getaddrinfo(hostpt, port_s, &hints, &res);
|
---|
247 | if(ret) {
|
---|
248 | logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, gai_strerror(ret));
|
---|
249 | return -1;
|
---|
250 | }
|
---|
251 |
|
---|
252 | for(rp = res; rp && addrnum < 128; rp = rp->ai_next) {
|
---|
253 | rp->ai_flags = cli_rndnum(1024);
|
---|
254 | addrs[addrnum] = rp;
|
---|
255 | if(rp->ai_family == AF_INET) {
|
---|
256 | if(ipv4start == -1)
|
---|
257 | ipv4start = addrnum;
|
---|
258 | } else if(ipv4end == -1 && ipv4start != -1) {
|
---|
259 | ipv4end = addrnum - 1;
|
---|
260 | }
|
---|
261 | if(!rp->ai_next && ipv4end == -1)
|
---|
262 | ipv4end = addrnum;
|
---|
263 | addrnum++;
|
---|
264 | }
|
---|
265 | if(ipv4end != -1 && ipv4start != -1 && ipv4end - ipv4start + 1 > 1)
|
---|
266 | qsort(&addrs[ipv4start], ipv4end - ipv4start + 1, sizeof(struct addrinfo *), qcompare);
|
---|
267 |
|
---|
268 | for(i = 0; i < addrnum; ) {
|
---|
269 | void *addr;
|
---|
270 |
|
---|
271 | rp = addrs[i];
|
---|
272 | ips++;
|
---|
273 | #ifdef SUPPORT_IPv6
|
---|
274 | if(rp->ai_family == AF_INET6)
|
---|
275 | addr = &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr;
|
---|
276 | else
|
---|
277 | #endif
|
---|
278 | addr = &((struct sockaddr_in *) rp->ai_addr)->sin_addr;
|
---|
279 |
|
---|
280 | if(!inet_ntop(rp->ai_family, addr, ipaddr, sizeof(ipaddr))) {
|
---|
281 | logg("%cinet_ntop() failed\n", logerr ? '!' : '^');
|
---|
282 | freeaddrinfo(res);
|
---|
283 | return -1;
|
---|
284 | }
|
---|
285 |
|
---|
286 | if(mdat && (ret = mirman_check(addr, rp->ai_family, mdat, &md))) {
|
---|
287 | if(ret == 1)
|
---|
288 | logg("*Ignoring mirror %s (due to previous errors)\n", ipaddr);
|
---|
289 | else
|
---|
290 | logg("*Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
|
---|
291 |
|
---|
292 | ignored++;
|
---|
293 | if(!loadbal || i + 1 < addrnum) {
|
---|
294 | i++;
|
---|
295 | continue;
|
---|
296 | }
|
---|
297 | }
|
---|
298 |
|
---|
299 | if(mdat && loadbal) {
|
---|
300 | if(!ret) {
|
---|
301 | if(!md) {
|
---|
302 | loadbal_rp = rp;
|
---|
303 | strncpy(loadbal_ipaddr, ipaddr, sizeof(loadbal_ipaddr));
|
---|
304 | } else {
|
---|
305 | if(md->succ <= minsucc && md->fail <= minfail) {
|
---|
306 | minsucc = md->succ;
|
---|
307 | minfail = md->fail;
|
---|
308 | loadbal_rp = rp;
|
---|
309 | strncpy(loadbal_ipaddr, ipaddr, sizeof(loadbal_ipaddr));
|
---|
310 | }
|
---|
311 | if(i + 1 < addrnum) {
|
---|
312 | i++;
|
---|
313 | continue;
|
---|
314 | }
|
---|
315 | }
|
---|
316 | }
|
---|
317 |
|
---|
318 | if(!loadbal_rp) {
|
---|
319 | if(i + 1 == addrnum) {
|
---|
320 | loadbal = 0;
|
---|
321 | i = 0;
|
---|
322 | }
|
---|
323 | continue;
|
---|
324 | }
|
---|
325 | rp = loadbal_rp;
|
---|
326 | strncpy(ipaddr, loadbal_ipaddr, sizeof(ipaddr));
|
---|
327 | #ifdef SUPPORT_IPv6
|
---|
328 | if(rp->ai_family == AF_INET6)
|
---|
329 | addr = &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr;
|
---|
330 | else
|
---|
331 | #endif
|
---|
332 | addr = &((struct sockaddr_in *) rp->ai_addr)->sin_addr;
|
---|
333 | } else if(loadbal_rp == rp) {
|
---|
334 | i++;
|
---|
335 | continue;
|
---|
336 | }
|
---|
337 |
|
---|
338 | if(ip)
|
---|
339 | strcpy(ip, ipaddr);
|
---|
340 |
|
---|
341 | if(rp != loadbal_rp && rp != addrs[0])
|
---|
342 | logg("Trying host %s (%s)...\n", hostpt, ipaddr);
|
---|
343 |
|
---|
344 | socketfd = getclientsock(localip, rp->ai_family);
|
---|
345 | if(socketfd < 0) {
|
---|
346 | freeaddrinfo(res);
|
---|
347 | return -1;
|
---|
348 | }
|
---|
349 |
|
---|
350 | #ifdef SO_ERROR
|
---|
351 | if(wait_connect(socketfd, rp->ai_addr, rp->ai_addrlen, ctimeout) == -1) {
|
---|
352 | #else
|
---|
353 | if(connect(socketfd, rp->ai_addr, rp->ai_addrlen) == -1) {
|
---|
354 | #endif
|
---|
355 | logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
|
---|
356 | closesocket(socketfd);
|
---|
357 | if(loadbal) {
|
---|
358 | loadbal = 0;
|
---|
359 | i = 0;
|
---|
360 | } else i++;
|
---|
361 | continue;
|
---|
362 | } else {
|
---|
363 | if(mdat) {
|
---|
364 | if(rp->ai_family == AF_INET)
|
---|
365 | mdat->currip[0] = *((uint32_t *) addr);
|
---|
366 | else
|
---|
367 | memcpy(mdat->currip, addr, 4 * sizeof(uint32_t));
|
---|
368 | mdat->af = rp->ai_family;
|
---|
369 | }
|
---|
370 | freeaddrinfo(res);
|
---|
371 | return socketfd;
|
---|
372 | }
|
---|
373 | i++;
|
---|
374 | }
|
---|
375 | freeaddrinfo(res);
|
---|
376 |
|
---|
377 | #else /* IPv4 */
|
---|
378 |
|
---|
379 | if((host = gethostbyname(hostpt)) == NULL) {
|
---|
380 | logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, ghbn_err(h_errno));
|
---|
381 | return -1;
|
---|
382 | }
|
---|
383 |
|
---|
384 | for(i = 0; host->h_addr_list[i] != 0; i++) {
|
---|
385 | /* this dirty hack comes from pink - Nosuid TCP/IP ping 1.6 */
|
---|
386 | ia = (unsigned char *) host->h_addr_list[i];
|
---|
387 | sprintf(ipaddr, "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]);
|
---|
388 |
|
---|
389 | ips++;
|
---|
390 | if(mdat && (ret = mirman_check(&((struct in_addr *) ia)->s_addr, AF_INET, mdat, NULL))) {
|
---|
391 | if(ret == 1)
|
---|
392 | logg("*Ignoring mirror %s (due to previous errors)\n", ipaddr);
|
---|
393 | else
|
---|
394 | logg("*Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
|
---|
395 | ignored++;
|
---|
396 | continue;
|
---|
397 | }
|
---|
398 |
|
---|
399 | if(ip)
|
---|
400 | strcpy(ip, ipaddr);
|
---|
401 |
|
---|
402 | if(i > 0)
|
---|
403 | logg("Trying host %s (%s)...\n", hostpt, ipaddr);
|
---|
404 |
|
---|
405 | memset ((char *) &name, 0, sizeof(name));
|
---|
406 | name.sin_family = AF_INET;
|
---|
407 | name.sin_addr = *((struct in_addr *) host->h_addr_list[i]);
|
---|
408 | name.sin_port = htons(port);
|
---|
409 |
|
---|
410 | socketfd = getclientsock(localip, AF_INET);
|
---|
411 | if(socketfd < 0)
|
---|
412 | return -1;
|
---|
413 |
|
---|
414 | #ifdef SO_ERROR
|
---|
415 | if(wait_connect(socketfd, (struct sockaddr *) &name, sizeof(struct sockaddr_in), ctimeout) == -1) {
|
---|
416 | #else
|
---|
417 | if(connect(socketfd, (struct sockaddr *) &name, sizeof(struct sockaddr_in)) == -1) {
|
---|
418 | #endif
|
---|
419 | logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
|
---|
420 | closesocket(socketfd);
|
---|
421 | continue;
|
---|
422 | } else {
|
---|
423 | if(mdat) {
|
---|
424 | mdat->currip[0] = ((struct in_addr *) ia)->s_addr;
|
---|
425 | mdat->af = AF_INET;
|
---|
426 | }
|
---|
427 | return socketfd;
|
---|
428 | }
|
---|
429 | }
|
---|
430 | #endif
|
---|
431 |
|
---|
432 | if(mdat && can_whitelist && ips && (ips == ignored))
|
---|
433 | mirman_whitelist(mdat, 1);
|
---|
434 |
|
---|
435 | return -2;
|
---|
436 | }
|
---|
437 |
|
---|
438 | /*
|
---|
439 | static const char *readblineraw(int fd, char *buf, int bufsize, int filesize, int *bread)
|
---|
440 | {
|
---|
441 | char *pt;
|
---|
442 | int ret, end;
|
---|
443 |
|
---|
444 | if(!*bread) {
|
---|
445 | if(bufsize < filesize)
|
---|
446 | lseek(fd, 1 - bufsize, SEEK_END);
|
---|
447 | *bread = read(fd, buf, bufsize - 1);
|
---|
448 | if(!*bread || *bread == -1)
|
---|
449 | return NULL;
|
---|
450 | buf[*bread] = 0;
|
---|
451 | }
|
---|
452 |
|
---|
453 | pt = strrchr(buf, '\n');
|
---|
454 | if(!pt)
|
---|
455 | return NULL;
|
---|
456 | *pt = 0;
|
---|
457 | pt = strrchr(buf, '\n');
|
---|
458 | if(pt) {
|
---|
459 | return ++pt;
|
---|
460 | } else if(*bread == filesize) {
|
---|
461 | return buf;
|
---|
462 | } else {
|
---|
463 | *bread -= strlen(buf) + 1;
|
---|
464 | end = filesize - *bread;
|
---|
465 | if(end < bufsize) {
|
---|
466 | if((ret = lseek(fd, 0, SEEK_SET)) != -1)
|
---|
467 | ret = read(fd, buf, end);
|
---|
468 | } else {
|
---|
469 | if((ret = lseek(fd, end - bufsize + 1, SEEK_SET)) != -1)
|
---|
470 | ret = read(fd, buf, bufsize - 1);
|
---|
471 | }
|
---|
472 | if(!ret || ret == -1)
|
---|
473 | return NULL;
|
---|
474 | buf[ret] = 0;
|
---|
475 | *bread += ret;
|
---|
476 | pt = strrchr(buf, '\n');
|
---|
477 | if(!pt)
|
---|
478 | return buf;
|
---|
479 | *pt = 0;
|
---|
480 | pt = strrchr(buf, '\n');
|
---|
481 | if(pt)
|
---|
482 | return ++pt;
|
---|
483 | else if(strlen(buf))
|
---|
484 | return buf;
|
---|
485 | else
|
---|
486 | return NULL;
|
---|
487 | }
|
---|
488 | }
|
---|
489 |
|
---|
490 | static const char *readbline(int fd, char *buf, int bufsize, int filesize, int *bread)
|
---|
491 | {
|
---|
492 | const char *line = readblineraw(fd, buf, bufsize, filesize, bread);
|
---|
493 |
|
---|
494 | if(line)
|
---|
495 | cli_chomp(buf + (line - buf));
|
---|
496 |
|
---|
497 | return line;
|
---|
498 | }
|
---|
499 | */
|
---|
500 |
|
---|
501 | static unsigned int fmt_base64(char *dest, const char *src, unsigned int len)
|
---|
502 | {
|
---|
503 | unsigned short bits = 0,temp = 0;
|
---|
504 | unsigned long written = 0;
|
---|
505 | unsigned int i;
|
---|
506 | const char base64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
---|
507 |
|
---|
508 |
|
---|
509 | for(i = 0; i < len; i++) {
|
---|
510 | temp <<= 8;
|
---|
511 | temp += src[i];
|
---|
512 | bits += 8;
|
---|
513 | while(bits > 6) {
|
---|
514 | dest[written] = base64[((temp >> (bits - 6)) & 63)];
|
---|
515 | written++;
|
---|
516 | bits -= 6;
|
---|
517 | }
|
---|
518 | }
|
---|
519 |
|
---|
520 | if(bits) {
|
---|
521 | temp <<= (6 - bits);
|
---|
522 | dest[written] = base64[temp & 63];
|
---|
523 | written++;
|
---|
524 | }
|
---|
525 |
|
---|
526 | while(written & 3) {
|
---|
527 | dest[written] = '=';
|
---|
528 | written++;
|
---|
529 | }
|
---|
530 |
|
---|
531 | return written;
|
---|
532 | }
|
---|
533 |
|
---|
534 | static char *proxyauth(const char *user, const char *pass)
|
---|
535 | {
|
---|
536 | int len;
|
---|
537 | char *buf, *userpass, *auth;
|
---|
538 |
|
---|
539 |
|
---|
540 | userpass = malloc(strlen(user) + strlen(pass) + 2);
|
---|
541 | if(!userpass) {
|
---|
542 | logg("!proxyauth: Can't allocate memory for 'userpass'\n");
|
---|
543 | return NULL;
|
---|
544 | }
|
---|
545 | sprintf(userpass, "%s:%s", user, pass);
|
---|
546 |
|
---|
547 | buf = malloc((strlen(pass) + strlen(user)) * 2 + 4);
|
---|
548 | if(!buf) {
|
---|
549 | logg("!proxyauth: Can't allocate memory for 'buf'\n");
|
---|
550 | free(userpass);
|
---|
551 | return NULL;
|
---|
552 | }
|
---|
553 |
|
---|
554 | len = fmt_base64(buf, userpass, strlen(userpass));
|
---|
555 | free(userpass);
|
---|
556 | buf[len] = '\0';
|
---|
557 | auth = malloc(strlen(buf) + 30);
|
---|
558 | if(!auth) {
|
---|
559 | free(buf);
|
---|
560 | logg("!proxyauth: Can't allocate memory for 'authorization'\n");
|
---|
561 | return NULL;
|
---|
562 | }
|
---|
563 |
|
---|
564 | sprintf(auth, "Proxy-Authorization: Basic %s\r\n", buf);
|
---|
565 | free(buf);
|
---|
566 |
|
---|
567 | return auth;
|
---|
568 | }
|
---|
569 |
|
---|
570 | #if BUILD_CLAMD
|
---|
571 | int submitstats(const char *clamdcfg, const struct optstruct *opts)
|
---|
572 | {
|
---|
573 | int sd, clamsockd, bread, cnt, ret;
|
---|
574 | char post[SUBMIT_MIN_ENTRIES * 256 + 512];
|
---|
575 | char query[SUBMIT_MIN_ENTRIES * 256];
|
---|
576 | char uastr[128], *line;
|
---|
577 | char *pt, *auth = NULL;
|
---|
578 | const char *country = NULL, *user, *proxy = NULL, *hostid = NULL;
|
---|
579 | const struct optstruct *opt;
|
---|
580 | unsigned int qcnt, entries, submitted = 0, permfail = 0, port = 0;
|
---|
581 | struct RCVLN rcv;
|
---|
582 | const char *tokens[5];
|
---|
583 |
|
---|
584 |
|
---|
585 | if((opt = optget(opts, "DetectionStatsCountry"))->enabled) {
|
---|
586 | if(strlen(opt->strarg) != 2 || !isalpha(opt->strarg[0]) || !isalpha(opt->strarg[1])) {
|
---|
587 | logg("!SubmitDetectionStats: DetectionStatsCountry requires a two-letter country code\n");
|
---|
588 | return 56;
|
---|
589 | }
|
---|
590 | country = opt->strarg;
|
---|
591 | }
|
---|
592 |
|
---|
593 | if((opt = optget(opts, "DetectionStatsHostID"))->enabled) {
|
---|
594 | if(strlen(opt->strarg) != 32) {
|
---|
595 | logg("!SubmitDetectionStats: The unique ID must be 32 characters long\n");
|
---|
596 | return 56;
|
---|
597 | }
|
---|
598 | hostid = opt->strarg;
|
---|
599 | }
|
---|
600 |
|
---|
601 | if((opt = optget(opts, "HTTPUserAgent"))->enabled)
|
---|
602 | strncpy(uastr, opt->strarg, sizeof(uastr));
|
---|
603 | else
|
---|
604 | snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE"):%s:%s", get_version(), country ? country : "", hostid ? hostid : "");
|
---|
605 | uastr[sizeof(uastr) - 1] = 0;
|
---|
606 |
|
---|
607 | if((opt = optget(opts, "HTTPProxyServer"))->enabled) {
|
---|
608 | proxy = opt->strarg;
|
---|
609 | if(!strncasecmp(proxy, "http://", 7))
|
---|
610 | proxy += 7;
|
---|
611 |
|
---|
612 | if((opt = optget(opts, "HTTPProxyUsername"))->enabled) {
|
---|
613 | user = opt->strarg;
|
---|
614 | if(!(opt = optget(opts, "HTTPProxyPassword"))->enabled) {
|
---|
615 | logg("!SubmitDetectionStats: HTTPProxyUsername requires HTTPProxyPassword\n");
|
---|
616 | return 56;
|
---|
617 | }
|
---|
618 | auth = proxyauth(user, opt->strarg);
|
---|
619 | if(!auth)
|
---|
620 | return 56;
|
---|
621 | }
|
---|
622 |
|
---|
623 | if((opt = optget(opts, "HTTPProxyPort"))->enabled)
|
---|
624 | port = opt->numarg;
|
---|
625 |
|
---|
626 | logg("*Connecting via %s\n", proxy);
|
---|
627 | }
|
---|
628 |
|
---|
629 | if((clamsockd = clamd_connect(clamdcfg, "SubmitDetectionStats")) < 0)
|
---|
630 | return 52;
|
---|
631 |
|
---|
632 | recvlninit(&rcv, clamsockd);
|
---|
633 | if(sendln(clamsockd, "zDETSTATS", 10)) {
|
---|
634 | closesocket(clamsockd);
|
---|
635 | return 52;
|
---|
636 | }
|
---|
637 |
|
---|
638 | ret = 0;
|
---|
639 | memset(query, 0, sizeof(query));
|
---|
640 | qcnt = 0;
|
---|
641 | entries = 0;
|
---|
642 | while(recvln(&rcv, &line, NULL) > 0) {
|
---|
643 | if(cli_strtokenize(line, ':', 5, tokens) != 5) {
|
---|
644 | logg("!SubmitDetectionStats: Invalid data format\n");
|
---|
645 | ret = 52;
|
---|
646 | break;
|
---|
647 | }
|
---|
648 |
|
---|
649 | qcnt += snprintf(&query[qcnt], sizeof(query) - qcnt, "ts[]=%s&fname[]=%s&virus[]=%s(%s:%s)&", tokens[0], tokens[4], tokens[3], tokens[1], tokens[2]);
|
---|
650 | entries++;
|
---|
651 |
|
---|
652 | if(entries == SUBMIT_MIN_ENTRIES) {
|
---|
653 | sd = wwwconnect("stats.clamav.net", proxy, port, NULL, optget(opts, "LocalIPAddress")->strarg, optget(opts, "ConnectTimeout")->numarg, NULL, 0, 0);
|
---|
654 | if(sd < 0) {
|
---|
655 | logg("!SubmitDetectionStats: Can't connect to server\n");
|
---|
656 | ret = 52;
|
---|
657 | break;
|
---|
658 | }
|
---|
659 | query[sizeof(query) - 1] = 0;
|
---|
660 | if(mdprintf(sd,
|
---|
661 | "POST http://stats.clamav.net/submit.php HTTP/1.0\r\n"
|
---|
662 | "Host: stats.clamav.net\r\n%s%s%s%s"
|
---|
663 | "Content-Type: application/x-www-form-urlencoded\r\n"
|
---|
664 | "User-Agent: %s\r\n"
|
---|
665 | "Content-Length: %u\r\n\r\n"
|
---|
666 | "%s",
|
---|
667 | auth ? auth : "", hostid ? "X-HostID: " : "", hostid ? hostid : "", hostid ? "\r\n" : "", uastr, (unsigned int) strlen(query), query) < 0)
|
---|
668 | {
|
---|
669 | logg("!SubmitDetectionStats: Can't write to socket\n");
|
---|
670 | ret = 52;
|
---|
671 | closesocket(sd);
|
---|
672 | break;
|
---|
673 | }
|
---|
674 |
|
---|
675 | pt = post;
|
---|
676 | cnt = sizeof(post) - 1;
|
---|
677 | #ifdef SO_ERROR
|
---|
678 | while((bread = wait_recv(sd, pt, cnt, 0, optget(opts, "ReceiveTimeout")->numarg)) > 0) {
|
---|
679 | #else
|
---|
680 | while((bread = recv(sd, pt, cnt, 0)) > 0) {
|
---|
681 | #endif
|
---|
682 | pt += bread;
|
---|
683 | cnt -= bread;
|
---|
684 | if(cnt <= 0)
|
---|
685 | break;
|
---|
686 | }
|
---|
687 | *pt = 0;
|
---|
688 | closesocket(sd);
|
---|
689 |
|
---|
690 | if(bread < 0) {
|
---|
691 | logg("!SubmitDetectionStats: Can't read from socket\n");
|
---|
692 | ret = 52;
|
---|
693 | break;
|
---|
694 | }
|
---|
695 |
|
---|
696 | if(strstr(post, "SUBMIT_OK")) {
|
---|
697 | submitted += entries;
|
---|
698 | if(submitted + SUBMIT_MIN_ENTRIES > SUBMIT_MAX_ENTRIES)
|
---|
699 | break;
|
---|
700 | qcnt = 0;
|
---|
701 | entries = 0;
|
---|
702 | memset(query, 0, sizeof(query));
|
---|
703 | continue;
|
---|
704 | }
|
---|
705 |
|
---|
706 | ret = 52;
|
---|
707 | if((pt = strstr(post, "SUBMIT_PERMANENT_FAILURE"))) {
|
---|
708 | if(!submitted) {
|
---|
709 | permfail = 1;
|
---|
710 | if((pt + 32 <= post + sizeof(post)) && pt[24] == ':')
|
---|
711 | logg("!SubmitDetectionStats: Remote server reported permanent failure: %s\n", &pt[25]);
|
---|
712 | else
|
---|
713 | logg("!SubmitDetectionStats: Remote server reported permanent failure\n");
|
---|
714 | }
|
---|
715 | } else if((pt = strstr(post, "SUBMIT_TEMPORARY_FAILURE"))) {
|
---|
716 | if(!submitted) {
|
---|
717 | if((pt + 32 <= post + sizeof(post)) && pt[24] == ':')
|
---|
718 | logg("!SubmitDetectionStats: Remote server reported temporary failure: %s\n", &pt[25]);
|
---|
719 | else
|
---|
720 | logg("!SubmitDetectionStats: Remote server reported temporary failure\n");
|
---|
721 | }
|
---|
722 | } else {
|
---|
723 | if(!submitted)
|
---|
724 | logg("!SubmitDetectionStats: Incorrect answer from server\n");
|
---|
725 | }
|
---|
726 |
|
---|
727 | break;
|
---|
728 | }
|
---|
729 | }
|
---|
730 | closesocket(clamsockd);
|
---|
731 | if(auth)
|
---|
732 | free(auth);
|
---|
733 |
|
---|
734 | if(ret == 0) {
|
---|
735 | if(!submitted) {
|
---|
736 | logg("SubmitDetectionStats: Not enough recent data for submission\n");
|
---|
737 | } else {
|
---|
738 | logg("SubmitDetectionStats: Submitted %u records\n", submitted);
|
---|
739 | if((clamsockd = clamd_connect(clamdcfg, "SubmitDetectionStats")) != -1) {
|
---|
740 | sendln(clamsockd, "DETSTATSCLEAR", 14);
|
---|
741 | recv(clamsockd, query, sizeof(query), 0);
|
---|
742 | closesocket(clamsockd);
|
---|
743 | }
|
---|
744 | }
|
---|
745 | }
|
---|
746 | return ret;
|
---|
747 | }
|
---|
748 | #else
|
---|
749 | int submitstats(const char *clamdcfg, const struct optstruct *opts)
|
---|
750 | {
|
---|
751 | logg("clamd not built, no statistics");
|
---|
752 | return 52;
|
---|
753 | }
|
---|
754 | #endif
|
---|
755 |
|
---|
756 | static int Rfc2822DateTime(char *buf, time_t mtime)
|
---|
757 | {
|
---|
758 | struct tm *gmt;
|
---|
759 |
|
---|
760 | gmt = gmtime(&mtime);
|
---|
761 | if (!gmt) {
|
---|
762 | logg("gmtime: %s\n", strerror(errno));
|
---|
763 | strcpy(buf, "ERROR");
|
---|
764 | return -1;
|
---|
765 | }
|
---|
766 | return strftime(buf, 36, "%a, %d %b %Y %X GMT", gmt);
|
---|
767 | }
|
---|
768 |
|
---|
769 | static struct cl_cvd *remote_cvdhead(const char *cvdfile, const char *localfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int *ims, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist)
|
---|
770 | {
|
---|
771 | char cmd[512], head[513], buffer[FILEBUFF], ipaddr[46], *ch, *tmp;
|
---|
772 | int bread, cnt, sd;
|
---|
773 | unsigned int i, j;
|
---|
774 | char *remotename = NULL, *authorization = NULL;
|
---|
775 | struct cl_cvd *cvd;
|
---|
776 | char last_modified[36], uastr[128];
|
---|
777 |
|
---|
778 |
|
---|
779 | if(proxy) {
|
---|
780 | remotename = malloc(strlen(hostname) + 8);
|
---|
781 | if(!remotename) {
|
---|
782 | logg("!remote_cvdhead: Can't allocate memory for 'remotename'\n");
|
---|
783 | return NULL;
|
---|
784 | }
|
---|
785 | sprintf(remotename, "http://%s", hostname);
|
---|
786 |
|
---|
787 | if(user) {
|
---|
788 | authorization = proxyauth(user, pass);
|
---|
789 | if(!authorization) {
|
---|
790 | free(remotename);
|
---|
791 | return NULL;
|
---|
792 | }
|
---|
793 | }
|
---|
794 | }
|
---|
795 |
|
---|
796 | if(!access(localfile, R_OK)) {
|
---|
797 | cvd = cl_cvdhead(localfile);
|
---|
798 | if(!cvd) {
|
---|
799 | logg("!remote_cvdhead: Can't parse file %s\n", localfile);
|
---|
800 | free(remotename);
|
---|
801 | free(authorization);
|
---|
802 | return NULL;
|
---|
803 | }
|
---|
804 | Rfc2822DateTime(last_modified, (time_t) cvd->stime);
|
---|
805 | cl_cvdfree(cvd);
|
---|
806 | } else {
|
---|
807 | time_t mtime = 1104119530;
|
---|
808 |
|
---|
809 | Rfc2822DateTime(last_modified, mtime);
|
---|
810 | logg("*Assuming modification time in the past\n");
|
---|
811 | }
|
---|
812 |
|
---|
813 | logg("*If-Modified-Since: %s\n", last_modified);
|
---|
814 |
|
---|
815 | logg("Reading CVD header (%s): ", cvdfile);
|
---|
816 |
|
---|
817 | if(uas)
|
---|
818 | strncpy(uastr, uas, sizeof(uastr));
|
---|
819 | else
|
---|
820 | snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")", get_version());
|
---|
821 | uastr[sizeof(uastr) - 1] = 0;
|
---|
822 |
|
---|
823 | snprintf(cmd, sizeof(cmd),
|
---|
824 | "GET %s/%s HTTP/1.0\r\n"
|
---|
825 | "Host: %s\r\n%s"
|
---|
826 | "User-Agent: %s\r\n"
|
---|
827 | "Connection: close\r\n"
|
---|
828 | "Range: bytes=0-511\r\n"
|
---|
829 | "If-Modified-Since: %s\r\n"
|
---|
830 | "\r\n", (remotename != NULL) ? remotename : "", cvdfile, hostname, (authorization != NULL) ? authorization : "", uastr, last_modified);
|
---|
831 |
|
---|
832 | free(remotename);
|
---|
833 | free(authorization);
|
---|
834 |
|
---|
835 | memset(ipaddr, 0, sizeof(ipaddr));
|
---|
836 |
|
---|
837 | if(ip[0]) /* use ip to connect */
|
---|
838 | sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
|
---|
839 | else
|
---|
840 | sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
|
---|
841 |
|
---|
842 | if(sd < 0) {
|
---|
843 | return NULL;
|
---|
844 | } else {
|
---|
845 | logg("*Connected to %s (IP: %s).\n", hostname, ipaddr);
|
---|
846 | logg("*Trying to retrieve CVD header of http://%s/%s\n", hostname, cvdfile);
|
---|
847 | }
|
---|
848 |
|
---|
849 | if(!ip[0])
|
---|
850 | strcpy(ip, ipaddr);
|
---|
851 |
|
---|
852 | if(send(sd, cmd, strlen(cmd), 0) < 0) {
|
---|
853 | logg("%cremote_cvdhead: write failed\n", logerr ? '!' : '^');
|
---|
854 | closesocket(sd);
|
---|
855 | return NULL;
|
---|
856 | }
|
---|
857 |
|
---|
858 | tmp = buffer;
|
---|
859 | cnt = FILEBUFF;
|
---|
860 | #ifdef SO_ERROR
|
---|
861 | while((bread = wait_recv(sd, tmp, cnt, 0, rtimeout)) > 0) {
|
---|
862 | #else
|
---|
863 | while((bread = recv(sd, tmp, cnt, 0)) > 0) {
|
---|
864 | #endif
|
---|
865 | tmp += bread;
|
---|
866 | cnt -= bread;
|
---|
867 | if(cnt <= 0)
|
---|
868 | break;
|
---|
869 | }
|
---|
870 | closesocket(sd);
|
---|
871 |
|
---|
872 | if(bread == -1) {
|
---|
873 | logg("%cremote_cvdhead: Error while reading CVD header from %s\n", logerr ? '!' : '^', hostname);
|
---|
874 | mirman_update(mdat->currip, mdat->af, mdat, 1);
|
---|
875 | return NULL;
|
---|
876 | }
|
---|
877 |
|
---|
878 | if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) {
|
---|
879 | logg("%cCVD file not found on remote server\n", logerr ? '!' : '^');
|
---|
880 | mirman_update(mdat->currip, mdat->af, mdat, 2);
|
---|
881 | return NULL;
|
---|
882 | }
|
---|
883 |
|
---|
884 | /* check whether the resource is up-to-date */
|
---|
885 | if((strstr(buffer, "HTTP/1.1 304")) != NULL || (strstr(buffer, "HTTP/1.0 304")) != NULL) {
|
---|
886 | *ims = 0;
|
---|
887 | logg("OK (IMS)\n");
|
---|
888 | mirman_update(mdat->currip, mdat->af, mdat, 0);
|
---|
889 | return NULL;
|
---|
890 | } else {
|
---|
891 | *ims = 1;
|
---|
892 | }
|
---|
893 |
|
---|
894 | if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
|
---|
895 | !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
|
---|
896 | logg("%cUnknown response from remote server\n", logerr ? '!' : '^');
|
---|
897 | mirman_update(mdat->currip, mdat->af, mdat, 1);
|
---|
898 | return NULL;
|
---|
899 | }
|
---|
900 |
|
---|
901 | i = 3;
|
---|
902 | ch = buffer + i;
|
---|
903 | while(i < sizeof(buffer)) {
|
---|
904 | if (*ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') {
|
---|
905 | ch++;
|
---|
906 | i++;
|
---|
907 | break;
|
---|
908 | }
|
---|
909 | ch++;
|
---|
910 | i++;
|
---|
911 | }
|
---|
912 |
|
---|
913 | if(sizeof(buffer) - i < 512) {
|
---|
914 | logg("%cremote_cvdhead: Malformed CVD header (too short)\n", logerr ? '!' : '^');
|
---|
915 | mirman_update(mdat->currip, mdat->af, mdat, 1);
|
---|
916 | return NULL;
|
---|
917 | }
|
---|
918 |
|
---|
919 | memset(head, 0, sizeof(head));
|
---|
920 |
|
---|
921 | for(j = 0; j < 512; j++) {
|
---|
922 | if(!ch || (ch && !*ch) || (ch && !isprint(ch[j]))) {
|
---|
923 | logg("%cremote_cvdhead: Malformed CVD header (bad chars)\n", logerr ? '!' : '^');
|
---|
924 | mirman_update(mdat->currip, mdat->af, mdat, 1);
|
---|
925 | return NULL;
|
---|
926 | }
|
---|
927 | head[j] = ch[j];
|
---|
928 | }
|
---|
929 |
|
---|
930 | if(!(cvd = cl_cvdparse(head))) {
|
---|
931 | logg("%cremote_cvdhead: Malformed CVD header (can't parse)\n", logerr ? '!' : '^');
|
---|
932 | mirman_update(mdat->currip, mdat->af, mdat, 1);
|
---|
933 | } else {
|
---|
934 | logg("OK\n");
|
---|
935 | mirman_update(mdat->currip, mdat->af, mdat, 0);
|
---|
936 | }
|
---|
937 |
|
---|
938 | return cvd;
|
---|
939 | }
|
---|
940 |
|
---|
941 | static int getfile_mirman(const char *srcfile, const char *destfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist, const char *ims, const char *ipaddr, int sd)
|
---|
942 | {
|
---|
943 | char cmd[512], uastr[128], buffer[FILEBUFF], *ch;
|
---|
944 | int bread, fd, totalsize = 0, rot = 0, totaldownloaded = 0,
|
---|
945 | percentage = 0;
|
---|
946 | unsigned int i;
|
---|
947 | char *remotename = NULL, *authorization = NULL, *headerline;
|
---|
948 | const char *rotation = "|/-\\", *fname;
|
---|
949 |
|
---|
950 |
|
---|
951 | if(proxy) {
|
---|
952 | remotename = malloc(strlen(hostname) + 8);
|
---|
953 | if(!remotename) {
|
---|
954 | logg("!getfile: Can't allocate memory for 'remotename'\n");
|
---|
955 | return 75; /* FIXME */
|
---|
956 | }
|
---|
957 | sprintf(remotename, "http://%s", hostname);
|
---|
958 |
|
---|
959 | if(user) {
|
---|
960 | authorization = proxyauth(user, pass);
|
---|
961 | if(!authorization) {
|
---|
962 | free(remotename);
|
---|
963 | return 75; /* FIXME */
|
---|
964 | }
|
---|
965 | }
|
---|
966 | }
|
---|
967 |
|
---|
968 | if(ims)
|
---|
969 | logg("*If-Modified-Since: %s\n", ims);
|
---|
970 |
|
---|
971 | if(uas)
|
---|
972 | strncpy(uastr, uas, sizeof(uastr));
|
---|
973 | else
|
---|
974 | snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")", get_version());
|
---|
975 | uastr[sizeof(uastr) - 1] = 0;
|
---|
976 |
|
---|
977 | snprintf(cmd, sizeof(cmd),
|
---|
978 | "GET %s/%s HTTP/1.0\r\n"
|
---|
979 | "Host: %s\r\n%s"
|
---|
980 | "User-Agent: %s\r\n"
|
---|
981 | #ifdef FRESHCLAM_NO_CACHE
|
---|
982 | "Cache-Control: no-cache\r\n"
|
---|
983 | #endif
|
---|
984 | "Connection: close\r\n"
|
---|
985 | "%s%s%s"
|
---|
986 | "\r\n", (remotename != NULL) ? remotename : "", srcfile, hostname, (authorization != NULL) ? authorization : "", uastr, ims ? "If-Modified-Since: " : "", ims ? ims : "", ims ? "\r\n": "");
|
---|
987 |
|
---|
988 | if(remotename)
|
---|
989 | free(remotename);
|
---|
990 |
|
---|
991 | if(authorization)
|
---|
992 | free(authorization);
|
---|
993 |
|
---|
994 | logg("*Trying to download http://%s/%s (IP: %s)\n", hostname, srcfile, ipaddr);
|
---|
995 |
|
---|
996 | if(ip && !ip[0])
|
---|
997 | strcpy(ip, ipaddr);
|
---|
998 |
|
---|
999 | if(send(sd, cmd, strlen(cmd), 0) < 0) {
|
---|
1000 | logg("%cgetfile: Can't write to socket\n", logerr ? '!' : '^');
|
---|
1001 | return 52;
|
---|
1002 | }
|
---|
1003 |
|
---|
1004 | /* read http headers */
|
---|
1005 | ch = buffer;
|
---|
1006 | i = 0;
|
---|
1007 | while(1) {
|
---|
1008 | /* recv one byte at a time, until we reach \r\n\r\n */
|
---|
1009 | #ifdef SO_ERROR
|
---|
1010 | if((i >= sizeof(buffer) - 1) || wait_recv(sd, buffer + i, 1, 0, rtimeout) == -1) {
|
---|
1011 | #else
|
---|
1012 | if((i >= sizeof(buffer) - 1) || recv(sd, buffer + i, 1, 0) == -1) {
|
---|
1013 | #endif
|
---|
1014 | logg("%cgetfile: Error while reading database from %s (IP: %s): %s\n", logerr ? '!' : '^', hostname, ipaddr, strerror(errno));
|
---|
1015 | if(mdat)
|
---|
1016 | mirman_update(mdat->currip, mdat->af, mdat, 1);
|
---|
1017 | return 52;
|
---|
1018 | }
|
---|
1019 |
|
---|
1020 | if(i > 2 && *ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') {
|
---|
1021 | i++;
|
---|
1022 | break;
|
---|
1023 | }
|
---|
1024 | ch++;
|
---|
1025 | i++;
|
---|
1026 | }
|
---|
1027 |
|
---|
1028 | buffer[i] = 0;
|
---|
1029 |
|
---|
1030 | /* check whether the resource actually existed or not */
|
---|
1031 | if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) {
|
---|
1032 | logg("^getfile: %s not found on remote server (IP: %s)\n", srcfile, ipaddr);
|
---|
1033 | if(mdat)
|
---|
1034 | mirman_update(mdat->currip, mdat->af, mdat, 2);
|
---|
1035 | return 58;
|
---|
1036 | }
|
---|
1037 |
|
---|
1038 | /* If-Modified-Since */
|
---|
1039 | if(strstr(buffer, "HTTP/1.1 304") || strstr(buffer, "HTTP/1.0 304")) {
|
---|
1040 | if(mdat)
|
---|
1041 | mirman_update(mdat->currip, mdat->af, mdat, 0);
|
---|
1042 | return 1;
|
---|
1043 | }
|
---|
1044 |
|
---|
1045 | if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
|
---|
1046 | !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
|
---|
1047 | logg("%cgetfile: Unknown response from remote server (IP: %s)\n", logerr ? '!' : '^', ipaddr);
|
---|
1048 | if(mdat)
|
---|
1049 | mirman_update(mdat->currip, mdat->af, mdat, 1);
|
---|
1050 | return 58;
|
---|
1051 | }
|
---|
1052 |
|
---|
1053 | /* get size of resource */
|
---|
1054 | for(i = 0; (headerline = cli_strtok(buffer, i, "\n")); i++){
|
---|
1055 | if(strstr(headerline, "Content-Length:")) {
|
---|
1056 | if((ch = cli_strtok(headerline, 1, ": "))) {
|
---|
1057 | totalsize = atoi(ch);
|
---|
1058 | free(ch);
|
---|
1059 | } else {
|
---|
1060 | totalsize = 0;
|
---|
1061 | }
|
---|
1062 | }
|
---|
1063 | free(headerline);
|
---|
1064 | }
|
---|
1065 |
|
---|
1066 | if((fd = open(destfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) == -1) {
|
---|
1067 | char currdir[512];
|
---|
1068 |
|
---|
1069 | if(getcwd(currdir, sizeof(currdir)))
|
---|
1070 | logg("!getfile: Can't create new file %s in %s\n", destfile, currdir);
|
---|
1071 | else
|
---|
1072 | logg("!getfile: Can't create new file %s in the current directory\n", destfile);
|
---|
1073 |
|
---|
1074 | logg("Hint: The database directory must be writable for UID %d or GID %d\n", getuid(), getgid());
|
---|
1075 | return 57;
|
---|
1076 | }
|
---|
1077 |
|
---|
1078 | if((fname = strrchr(srcfile, '/')))
|
---|
1079 | fname++;
|
---|
1080 | else
|
---|
1081 | fname = srcfile;
|
---|
1082 |
|
---|
1083 | #ifdef SO_ERROR
|
---|
1084 | while((bread = wait_recv(sd, buffer, FILEBUFF, 0, rtimeout)) > 0) {
|
---|
1085 | #else
|
---|
1086 | while((bread = recv(sd, buffer, FILEBUFF, 0)) > 0) {
|
---|
1087 | #endif
|
---|
1088 | if(write(fd, buffer, bread) != bread) {
|
---|
1089 | logg("getfile: Can't write %d bytes to %s\n", bread, destfile);
|
---|
1090 | close(fd);
|
---|
1091 | unlink(destfile);
|
---|
1092 | return 57; /* FIXME */
|
---|
1093 | }
|
---|
1094 |
|
---|
1095 | totaldownloaded += bread;
|
---|
1096 | if(totalsize > 0)
|
---|
1097 | percentage = (int) (100 * (float) totaldownloaded / totalsize);
|
---|
1098 |
|
---|
1099 | if(!mprintf_quiet) {
|
---|
1100 | if(totalsize > 0) {
|
---|
1101 | mprintf("Downloading %s [%3i%%]\r", fname, percentage);
|
---|
1102 | } else {
|
---|
1103 | mprintf("Downloading %s [%c]\r", fname, rotation[rot]);
|
---|
1104 | rot++;
|
---|
1105 | rot %= 4;
|
---|
1106 | }
|
---|
1107 | fflush(stdout);
|
---|
1108 | }
|
---|
1109 | }
|
---|
1110 | close(fd);
|
---|
1111 |
|
---|
1112 | if(bread == -1) {
|
---|
1113 | logg("%cgetfile: Download interrupted: %s (IP: %s)\n", logerr ? '!' : '^', strerror(errno), ipaddr);
|
---|
1114 | if(mdat)
|
---|
1115 | mirman_update(mdat->currip, mdat->af, mdat, 2);
|
---|
1116 | return 52;
|
---|
1117 | }
|
---|
1118 |
|
---|
1119 | if(!totaldownloaded)
|
---|
1120 | return 53;
|
---|
1121 |
|
---|
1122 | if(totalsize > 0)
|
---|
1123 | logg("Downloading %s [100%%]\n", fname);
|
---|
1124 | else
|
---|
1125 | logg("Downloading %s [*]\n", fname);
|
---|
1126 |
|
---|
1127 | if(mdat)
|
---|
1128 | mirman_update(mdat->currip, mdat->af, mdat, 0);
|
---|
1129 | return 0;
|
---|
1130 | }
|
---|
1131 |
|
---|
1132 | static int getfile(const char *srcfile, const char *destfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist, const char *ims, const struct optstruct *opts)
|
---|
1133 | {
|
---|
1134 | int ret, sd;
|
---|
1135 | char ipaddr[46];
|
---|
1136 |
|
---|
1137 | memset(ipaddr, 0, sizeof(ipaddr));
|
---|
1138 | if(ip && ip[0]) /* use ip to connect */
|
---|
1139 | sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
|
---|
1140 | else
|
---|
1141 | sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
|
---|
1142 |
|
---|
1143 | if(sd < 0)
|
---|
1144 | return 52;
|
---|
1145 |
|
---|
1146 | if(mdat) {
|
---|
1147 | mirman_update_sf(mdat->currip, mdat->af, mdat, 0, 1);
|
---|
1148 | mirman_write("mirrors.dat", dbdir, mdat);
|
---|
1149 | }
|
---|
1150 |
|
---|
1151 | ret = getfile_mirman(srcfile, destfile, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist, ims, ipaddr, sd);
|
---|
1152 | closesocket(sd);
|
---|
1153 |
|
---|
1154 | if(mdat) {
|
---|
1155 | mirman_update_sf(mdat->currip, mdat->af, mdat, 0, -1);
|
---|
1156 | mirman_write("mirrors.dat", dbdir, mdat);
|
---|
1157 | }
|
---|
1158 |
|
---|
1159 | return ret;
|
---|
1160 | }
|
---|
1161 |
|
---|
1162 | static int getcvd(const char *cvdfile, const char *newfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, unsigned int newver, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist, const struct optstruct *opts)
|
---|
1163 | {
|
---|
1164 | struct cl_cvd *cvd;
|
---|
1165 | int ret;
|
---|
1166 |
|
---|
1167 |
|
---|
1168 | logg("*Retrieving http://%s/%s\n", hostname, cvdfile);
|
---|
1169 |
|
---|
1170 | if((ret = getfile(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist, NULL, opts))) {
|
---|
1171 | logg("%cCan't download %s from %s\n", logerr ? '!' : '^', cvdfile, hostname);
|
---|
1172 | unlink(newfile);
|
---|
1173 | return ret;
|
---|
1174 | }
|
---|
1175 |
|
---|
1176 | if((ret = cl_cvdverify(newfile))) {
|
---|
1177 | logg("!Verification: %s\n", cl_strerror(ret));
|
---|
1178 | unlink(newfile);
|
---|
1179 | return 54;
|
---|
1180 | }
|
---|
1181 |
|
---|
1182 | if(!(cvd = cl_cvdhead(newfile))) {
|
---|
1183 | logg("!Can't read CVD header of new %s database.\n", cvdfile);
|
---|
1184 | unlink(newfile);
|
---|
1185 | return 54;
|
---|
1186 | }
|
---|
1187 |
|
---|
1188 | if(cvd->version < newver) {
|
---|
1189 | logg("^Mirror %s is not synchronized.\n", ip);
|
---|
1190 | mirman_update(mdat->currip, mdat->af, mdat, 2);
|
---|
1191 | cl_cvdfree(cvd);
|
---|
1192 | unlink(newfile);
|
---|
1193 | return 59;
|
---|
1194 | }
|
---|
1195 |
|
---|
1196 | cl_cvdfree(cvd);
|
---|
1197 | return 0;
|
---|
1198 | }
|
---|
1199 |
|
---|
1200 | static int chdir_tmp(const char *dbname, const char *tmpdir)
|
---|
1201 | {
|
---|
1202 | char cvdfile[32];
|
---|
1203 |
|
---|
1204 |
|
---|
1205 | if(access(tmpdir, R_OK|W_OK) == -1) {
|
---|
1206 | sprintf(cvdfile, "%s.cvd", dbname);
|
---|
1207 | if(access(cvdfile, R_OK) == -1) {
|
---|
1208 | sprintf(cvdfile, "%s.cld", dbname);
|
---|
1209 | if(access(cvdfile, R_OK) == -1) {
|
---|
1210 | logg("!chdir_tmp: Can't access local %s database\n", dbname);
|
---|
1211 | return -1;
|
---|
1212 | }
|
---|
1213 | }
|
---|
1214 |
|
---|
1215 | if(mkdir(tmpdir, 0755) == -1) {
|
---|
1216 | logg("!chdir_tmp: Can't create directory %s\n", tmpdir);
|
---|
1217 | return -1;
|
---|
1218 | }
|
---|
1219 |
|
---|
1220 | if(cli_cvdunpack(cvdfile, tmpdir) == -1) {
|
---|
1221 | logg("!chdir_tmp: Can't unpack %s into %s\n", cvdfile, tmpdir);
|
---|
1222 | cli_rmdirs(tmpdir);
|
---|
1223 | return -1;
|
---|
1224 | }
|
---|
1225 | }
|
---|
1226 |
|
---|
1227 | if(chdir(tmpdir) == -1) {
|
---|
1228 | logg("!chdir_tmp: Can't change directory to %s\n", tmpdir);
|
---|
1229 | return -1;
|
---|
1230 | }
|
---|
1231 |
|
---|
1232 | return 0;
|
---|
1233 | }
|
---|
1234 |
|
---|
1235 | static int getpatch(const char *dbname, const char *tmpdir, int version, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist, const struct optstruct *opts)
|
---|
1236 | {
|
---|
1237 | char *tempname, patch[32], olddir[512];
|
---|
1238 | int ret, fd;
|
---|
1239 |
|
---|
1240 |
|
---|
1241 | if(!getcwd(olddir, sizeof(olddir))) {
|
---|
1242 | logg("!getpatch: Can't get path of current working directory\n");
|
---|
1243 | return 50; /* FIXME */
|
---|
1244 | }
|
---|
1245 |
|
---|
1246 | if(chdir_tmp(dbname, tmpdir) == -1)
|
---|
1247 | return 50;
|
---|
1248 |
|
---|
1249 | tempname = cli_gentemp(".");
|
---|
1250 | snprintf(patch, sizeof(patch), "%s-%d.cdiff", dbname, version);
|
---|
1251 |
|
---|
1252 | logg("*Retrieving http://%s/%s\n", hostname, patch);
|
---|
1253 | if((ret = getfile(patch, tempname, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist, NULL, opts))) {
|
---|
1254 | if(ret == 53)
|
---|
1255 | logg("Empty script %s, need to download entire database\n", patch);
|
---|
1256 | else
|
---|
1257 | logg("%cgetpatch: Can't download %s from %s\n", logerr ? '!' : '^', patch, hostname);
|
---|
1258 | unlink(tempname);
|
---|
1259 | free(tempname);
|
---|
1260 | CHDIR_ERR(olddir);
|
---|
1261 | return ret;
|
---|
1262 | }
|
---|
1263 |
|
---|
1264 | if((fd = open(tempname, O_RDONLY|O_BINARY)) == -1) {
|
---|
1265 | logg("!getpatch: Can't open %s for reading\n", tempname);
|
---|
1266 | unlink(tempname);
|
---|
1267 | free(tempname);
|
---|
1268 | CHDIR_ERR(olddir);
|
---|
1269 | return 55;
|
---|
1270 | }
|
---|
1271 |
|
---|
1272 | if(cdiff_apply(fd, 1) == -1) {
|
---|
1273 | logg("!getpatch: Can't apply patch\n");
|
---|
1274 | close(fd);
|
---|
1275 | unlink(tempname);
|
---|
1276 | free(tempname);
|
---|
1277 | CHDIR_ERR(olddir);
|
---|
1278 | return 70; /* FIXME */
|
---|
1279 | }
|
---|
1280 |
|
---|
1281 | close(fd);
|
---|
1282 | unlink(tempname);
|
---|
1283 | free(tempname);
|
---|
1284 | if(chdir(olddir) == -1) {
|
---|
1285 | logg("!getpatch: Can't chdir to %s\n", olddir);
|
---|
1286 | return 50; /* FIXME */
|
---|
1287 | }
|
---|
1288 | return 0;
|
---|
1289 | }
|
---|
1290 |
|
---|
1291 | static struct cl_cvd *currentdb(const char *dbname, char *localname)
|
---|
1292 | {
|
---|
1293 | char db[32];
|
---|
1294 | struct cl_cvd *cvd = NULL;
|
---|
1295 |
|
---|
1296 |
|
---|
1297 | snprintf(db, sizeof(db), "%s.cvd", dbname);
|
---|
1298 | if(localname)
|
---|
1299 | strcpy(localname, db);
|
---|
1300 |
|
---|
1301 | if(access(db, R_OK) == -1) {
|
---|
1302 | snprintf(db, sizeof(db), "%s.cld", dbname);
|
---|
1303 | if(localname)
|
---|
1304 | strcpy(localname, db);
|
---|
1305 | }
|
---|
1306 |
|
---|
1307 | if(!access(db, R_OK))
|
---|
1308 | cvd = cl_cvdhead(db);
|
---|
1309 |
|
---|
1310 | return cvd;
|
---|
1311 | }
|
---|
1312 |
|
---|
1313 | static int buildcld(const char *tmpdir, const char *dbname, const char *newfile, unsigned int compr)
|
---|
1314 | {
|
---|
1315 | DIR *dir;
|
---|
1316 | char cwd[512], info[32], buff[513], *pt;
|
---|
1317 | struct dirent *dent;
|
---|
1318 | int fd, err = 0;
|
---|
1319 | gzFile *gzs = NULL;
|
---|
1320 |
|
---|
1321 | if(!getcwd(cwd, sizeof(cwd))) {
|
---|
1322 | logg("!buildcld: Can't get path of current working directory\n");
|
---|
1323 | return -1;
|
---|
1324 | }
|
---|
1325 |
|
---|
1326 | if(chdir(tmpdir) == -1) {
|
---|
1327 | logg("!buildcld: Can't access directory %s\n", tmpdir);
|
---|
1328 | return -1;
|
---|
1329 | }
|
---|
1330 |
|
---|
1331 | snprintf(info, sizeof(info), "%s.info", dbname);
|
---|
1332 | if((fd = open(info, O_RDONLY|O_BINARY)) == -1) {
|
---|
1333 | logg("!buildcld: Can't open %s\n", info);
|
---|
1334 | CHDIR_ERR(cwd);
|
---|
1335 | return -1;
|
---|
1336 | }
|
---|
1337 |
|
---|
1338 | if(read(fd, buff, 512) == -1) {
|
---|
1339 | logg("!buildcld: Can't read %s\n", info);
|
---|
1340 | CHDIR_ERR(cwd);
|
---|
1341 | close(fd);
|
---|
1342 | return -1;
|
---|
1343 | }
|
---|
1344 | buff[512] = 0;
|
---|
1345 | close(fd);
|
---|
1346 |
|
---|
1347 | if(!(pt = strchr(buff, '\n'))) {
|
---|
1348 | logg("!buildcld: Bad format of %s\n", info);
|
---|
1349 | CHDIR_ERR(cwd);
|
---|
1350 | return -1;
|
---|
1351 | }
|
---|
1352 | memset(pt, ' ', 512 + buff - pt);
|
---|
1353 |
|
---|
1354 | if((fd = open(newfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) == -1) {
|
---|
1355 | logg("!buildcld: Can't open %s for writing\n", newfile);
|
---|
1356 | CHDIR_ERR(cwd);
|
---|
1357 | return -1;
|
---|
1358 | }
|
---|
1359 | if(write(fd, buff, 512) != 512) {
|
---|
1360 | logg("!buildcld: Can't write to %s\n", newfile);
|
---|
1361 | CHDIR_ERR(cwd);
|
---|
1362 | close(fd);
|
---|
1363 | unlink(newfile);
|
---|
1364 | return -1;
|
---|
1365 | }
|
---|
1366 |
|
---|
1367 | if((dir = opendir(".")) == NULL) {
|
---|
1368 | logg("!buildcld: Can't open directory %s\n", tmpdir);
|
---|
1369 | CHDIR_ERR(cwd);
|
---|
1370 | close(fd);
|
---|
1371 | unlink(newfile);
|
---|
1372 | return -1;
|
---|
1373 | }
|
---|
1374 |
|
---|
1375 | if(compr) {
|
---|
1376 | close(fd);
|
---|
1377 | if(!(gzs = gzopen(newfile, "ab9f"))) {
|
---|
1378 | logg("!buildcld: gzopen() failed for %s\n", newfile);
|
---|
1379 | CHDIR_ERR(cwd);
|
---|
1380 | closedir(dir);
|
---|
1381 | unlink(newfile);
|
---|
1382 | return -1;
|
---|
1383 | }
|
---|
1384 | }
|
---|
1385 |
|
---|
1386 | if(access("COPYING", R_OK)) {
|
---|
1387 | logg("!buildcld: COPYING file not found\n");
|
---|
1388 | err = 1;
|
---|
1389 | } else {
|
---|
1390 | if(tar_addfile(fd, gzs, "COPYING") == -1) {
|
---|
1391 | logg("!buildcld: Can't add COPYING to .cld file\n");
|
---|
1392 | err = 1;
|
---|
1393 | }
|
---|
1394 | }
|
---|
1395 |
|
---|
1396 | if(!err && !access(info, R_OK)) {
|
---|
1397 | if(tar_addfile(fd, gzs, info) == -1) {
|
---|
1398 | logg("!buildcld: Can't add %s to .cld file\n", info);
|
---|
1399 | err = 1;
|
---|
1400 | }
|
---|
1401 | }
|
---|
1402 |
|
---|
1403 | if(!err && !access("daily.cfg", R_OK)) {
|
---|
1404 | if(tar_addfile(fd, gzs, "daily.cfg") == -1) {
|
---|
1405 | logg("!buildcld: Can't add daily.cfg to .cld file\n");
|
---|
1406 | err = 1;
|
---|
1407 | }
|
---|
1408 | }
|
---|
1409 |
|
---|
1410 | if(err) {
|
---|
1411 | CHDIR_ERR(cwd);
|
---|
1412 | if(gzs)
|
---|
1413 | gzclose(gzs);
|
---|
1414 | else
|
---|
1415 | close(fd);
|
---|
1416 | closedir(dir);
|
---|
1417 | unlink(newfile);
|
---|
1418 | return -1;
|
---|
1419 | }
|
---|
1420 |
|
---|
1421 | while((dent = readdir(dir))) {
|
---|
1422 | if(dent->d_ino)
|
---|
1423 | {
|
---|
1424 | if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..") || !strcmp(dent->d_name, "COPYING") || !strcmp(dent->d_name, "daily.cfg") || !strcmp(dent->d_name, info))
|
---|
1425 | continue;
|
---|
1426 |
|
---|
1427 | if(tar_addfile(fd, gzs, dent->d_name) == -1) {
|
---|
1428 | logg("!buildcld: Can't add %s to .cld file\n", dent->d_name);
|
---|
1429 | CHDIR_ERR(cwd);
|
---|
1430 | if(gzs)
|
---|
1431 | gzclose(gzs);
|
---|
1432 | else
|
---|
1433 | close(fd);
|
---|
1434 | closedir(dir);
|
---|
1435 | unlink(newfile);
|
---|
1436 | return -1;
|
---|
1437 | }
|
---|
1438 | }
|
---|
1439 | }
|
---|
1440 | closedir(dir);
|
---|
1441 |
|
---|
1442 | if(gzs) {
|
---|
1443 | if(gzclose(gzs)) {
|
---|
1444 | logg("!buildcld: gzclose() failed for %s\n", newfile);
|
---|
1445 | unlink(newfile);
|
---|
1446 | return -1;
|
---|
1447 | }
|
---|
1448 | } else {
|
---|
1449 | if(close(fd) == -1) {
|
---|
1450 | logg("!buildcld: close() failed for %s\n", newfile);
|
---|
1451 | unlink(newfile);
|
---|
1452 | return -1;
|
---|
1453 | }
|
---|
1454 | }
|
---|
1455 |
|
---|
1456 | if(chdir(cwd) == -1) {
|
---|
1457 | logg("!buildcld: Can't return to previous directory %s\n", cwd);
|
---|
1458 | return -1;
|
---|
1459 | }
|
---|
1460 |
|
---|
1461 | return 0;
|
---|
1462 | }
|
---|
1463 |
|
---|
1464 | static int test_database(const char *newfile, const char *newdb, int bytecode)
|
---|
1465 | {
|
---|
1466 | struct cl_engine *engine;
|
---|
1467 | unsigned newsigs = 0;
|
---|
1468 | int ret;
|
---|
1469 |
|
---|
1470 | logg("*Loading signatures from %s\n", newdb);
|
---|
1471 | if(!(engine = cl_engine_new())) {
|
---|
1472 | return 55;
|
---|
1473 | }
|
---|
1474 |
|
---|
1475 | if((ret = cl_load(newfile, engine, &newsigs, CL_DB_PHISHING | CL_DB_PHISHING_URLS | CL_DB_BYTECODE | CL_DB_PUA)) != CL_SUCCESS) {
|
---|
1476 | logg("!Failed to load new database: %s\n", cl_strerror(ret));
|
---|
1477 | cl_engine_free(engine);
|
---|
1478 | return 55;
|
---|
1479 | }
|
---|
1480 | if(bytecode && (ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode/*FIXME: dconf has no sense here*/))) {
|
---|
1481 | logg("!Failed to compile/load bytecode: %s\n", cl_strerror(ret));
|
---|
1482 | cl_engine_free(engine);
|
---|
1483 | return 55;
|
---|
1484 | }
|
---|
1485 | logg("*Properly loaded %u signatures from new %s\n", newsigs, newdb);
|
---|
1486 | if(engine->domainlist_matcher && engine->domainlist_matcher->sha256_pfx_set.keys)
|
---|
1487 | cli_hashset_destroy(&engine->domainlist_matcher->sha256_pfx_set);
|
---|
1488 | cl_engine_free(engine);
|
---|
1489 | return 0;
|
---|
1490 | }
|
---|
1491 |
|
---|
1492 | #ifndef WIN32
|
---|
1493 | static int test_database_wrap(const char *file, const char *newdb, int bytecode)
|
---|
1494 | {
|
---|
1495 | char firstline[256];
|
---|
1496 | char lastline[256];
|
---|
1497 | int pipefd[2];
|
---|
1498 | pid_t pid;
|
---|
1499 | int status = 0, ret;
|
---|
1500 | FILE *f;
|
---|
1501 |
|
---|
1502 | if (pipe(pipefd) == -1) {
|
---|
1503 | logg("^pipe() failed: %s\n", strerror(errno));
|
---|
1504 | return test_database(file, newdb, bytecode);
|
---|
1505 | }
|
---|
1506 |
|
---|
1507 | switch ( pid = fork() ) {
|
---|
1508 | case 0:
|
---|
1509 | close(pipefd[0]);
|
---|
1510 | dup2(pipefd[1], 2);
|
---|
1511 | exit(test_database(file, newdb, bytecode));
|
---|
1512 | case -1:
|
---|
1513 | close(pipefd[0]);
|
---|
1514 | close(pipefd[1]);
|
---|
1515 | logg("^fork() failed: %s\n", strerror(errno));
|
---|
1516 | return test_database(file, newdb, bytecode);
|
---|
1517 | default:
|
---|
1518 | /* read first / last line printed by child*/
|
---|
1519 | close(pipefd[1]);
|
---|
1520 | f = fdopen(pipefd[0], "r");
|
---|
1521 | firstline[0] = 0;
|
---|
1522 | lastline[0] = 0;
|
---|
1523 | do {
|
---|
1524 | if (!fgets(firstline, sizeof(firstline), f))
|
---|
1525 | break;
|
---|
1526 | /* ignore warning messages, otherwise the outdated warning will
|
---|
1527 | * make us miss the important part of the error message */
|
---|
1528 | } while (!strncmp(firstline, "LibClamAV Warning:", 18));
|
---|
1529 | /* must read entire output, child doesn't like EPIPE */
|
---|
1530 | while (fgets(lastline, sizeof(firstline), f)) {
|
---|
1531 | /* print the full output only when LogVerbose or -v is given */
|
---|
1532 | logg("*%s", lastline);
|
---|
1533 | }
|
---|
1534 | fclose(f);
|
---|
1535 |
|
---|
1536 | while ((ret = waitpid(pid, &status, 0)) == -1 && errno == EINTR);
|
---|
1537 | if (ret == -1 && errno != ECHILD)
|
---|
1538 | logg("^waitpid() failed: %s\n", strerror(errno));
|
---|
1539 | cli_chomp(firstline);
|
---|
1540 | cli_chomp(lastline);
|
---|
1541 | if (firstline[0]) {
|
---|
1542 | logg("!During database load : %s%s%s\n",
|
---|
1543 | firstline, lastline[0] ? " [...] " : "",
|
---|
1544 | lastline);
|
---|
1545 | }
|
---|
1546 | if (WIFEXITED(status)) {
|
---|
1547 | ret = WEXITSTATUS(status);
|
---|
1548 | if (ret) {
|
---|
1549 | logg("^Database load exited with status %d\n", ret);
|
---|
1550 | return ret;
|
---|
1551 | }
|
---|
1552 | if (firstline[0])
|
---|
1553 | logg("^Database successfully loaded, but there is stderr output\n");
|
---|
1554 | return 0;
|
---|
1555 | }
|
---|
1556 | if (WIFSIGNALED(status)) {
|
---|
1557 | logg("!Database load killed by signal %d\n", WTERMSIG(status));
|
---|
1558 | return 55;
|
---|
1559 | }
|
---|
1560 | logg("^Unknown status from wait: %d\n", status);
|
---|
1561 | return 55;
|
---|
1562 | }
|
---|
1563 | }
|
---|
1564 | #else
|
---|
1565 | static int test_database_wrap(const char *file, const char *newdb, int bytecode)
|
---|
1566 | {
|
---|
1567 | int ret = 55;
|
---|
1568 | __try
|
---|
1569 | {
|
---|
1570 | ret = test_database(file, newdb, bytecode);
|
---|
1571 | }
|
---|
1572 | __except (logg("!Exception during database testing, code %08x\n",
|
---|
1573 | GetExceptionCode()),
|
---|
1574 | EXCEPTION_CONTINUE_SEARCH)
|
---|
1575 | { }
|
---|
1576 | return ret;
|
---|
1577 | }
|
---|
1578 | #endif
|
---|
1579 |
|
---|
1580 | static int checkdbdir(void)
|
---|
1581 | {
|
---|
1582 | DIR *dir;
|
---|
1583 | struct dirent *dent;
|
---|
1584 | char fname[512], broken[513];
|
---|
1585 | int ret, fret = 0;
|
---|
1586 |
|
---|
1587 | if(!(dir = opendir(dbdir))) {
|
---|
1588 | logg("!checkdbdir: Can't open directory %s\n", dbdir);
|
---|
1589 | return -1;
|
---|
1590 | }
|
---|
1591 |
|
---|
1592 | while((dent = readdir(dir))) {
|
---|
1593 | if(dent->d_ino) {
|
---|
1594 | if(cli_strbcasestr(dent->d_name, ".cld") || cli_strbcasestr(dent->d_name, ".cvd")) {
|
---|
1595 | snprintf(fname, sizeof(fname), "%s"PATHSEP"%s", dbdir, dent->d_name);
|
---|
1596 | if((ret = cl_cvdverify(fname))) {
|
---|
1597 | fret = -1;
|
---|
1598 | mprintf("!Corrupted database file %s: %s\n", fname, cl_strerror(ret));
|
---|
1599 | snprintf(broken, sizeof(broken), "%s.broken", fname);
|
---|
1600 | if(!access(broken, R_OK))
|
---|
1601 | unlink(broken);
|
---|
1602 | if(rename(fname, broken)) {
|
---|
1603 | if(unlink(fname))
|
---|
1604 | mprintf("!Can't remove broken database file %s, please delete it manually and restart freshclam\n", fname);
|
---|
1605 | } else {
|
---|
1606 | mprintf("Corrupted database file renamed to %s\n", broken);
|
---|
1607 | }
|
---|
1608 | }
|
---|
1609 | }
|
---|
1610 | }
|
---|
1611 | }
|
---|
1612 |
|
---|
1613 | closedir(dir);
|
---|
1614 | return fret;
|
---|
1615 | }
|
---|
1616 |
|
---|
1617 | extern int sigchld_wait;
|
---|
1618 |
|
---|
1619 | static int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, const struct optstruct *opts, const char *dnsreply, char *localip, int outdated, struct mirdat *mdat, int logerr, int extra)
|
---|
1620 | {
|
---|
1621 | struct cl_cvd *current, *remote;
|
---|
1622 | const struct optstruct *opt;
|
---|
1623 | unsigned int nodb = 0, currver = 0, newver = 0, port = 0, i, j;
|
---|
1624 | int ret, ims = -1;
|
---|
1625 | char *pt, cvdfile[32], localname[32], *tmpdir = NULL, *newfile, *newfile2, newdb[32];
|
---|
1626 | char extradbinfo[64], *extradnsreply = NULL, squery[64];
|
---|
1627 | const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL;
|
---|
1628 | unsigned int flevel = cl_retflevel(), remote_flevel = 0, maxattempts;
|
---|
1629 | unsigned int can_whitelist = 0, mirror_stats = 0;
|
---|
1630 | #ifdef _WIN32
|
---|
1631 | unsigned int w32 = 1;
|
---|
1632 | #else
|
---|
1633 | unsigned int w32 = 0;
|
---|
1634 | #endif
|
---|
1635 | int ctimeout, rtimeout;
|
---|
1636 |
|
---|
1637 |
|
---|
1638 | if(cli_strbcasestr(hostname, ".clamav.net"))
|
---|
1639 | mirror_stats = 1;
|
---|
1640 |
|
---|
1641 | snprintf(cvdfile, sizeof(cvdfile), "%s.cvd", dbname);
|
---|
1642 |
|
---|
1643 | if(!(current = currentdb(dbname, localname))) {
|
---|
1644 | nodb = 1;
|
---|
1645 | } else {
|
---|
1646 | mdat->dbflevel = current->fl;
|
---|
1647 | }
|
---|
1648 |
|
---|
1649 | if(!nodb && !extra && dnsreply) {
|
---|
1650 | int field = 0;
|
---|
1651 |
|
---|
1652 | if(!strcmp(dbname, "main")) {
|
---|
1653 | field = 1;
|
---|
1654 | } else if(!strcmp(dbname, "daily")) {
|
---|
1655 | field = 2;
|
---|
1656 | } else if(!strcmp(dbname, "safebrowsing")) {
|
---|
1657 | field = 6;
|
---|
1658 | } else if(!strcmp(dbname, "bytecode")) {
|
---|
1659 | field = 7;
|
---|
1660 | } else {
|
---|
1661 | logg("!updatedb: Unknown database name (%s) passed.\n", dbname);
|
---|
1662 | cl_cvdfree(current);
|
---|
1663 | return 70;
|
---|
1664 | }
|
---|
1665 |
|
---|
1666 | if(field && (pt = cli_strtok(dnsreply, field, ":"))) {
|
---|
1667 | if(!cli_isnumber(pt)) {
|
---|
1668 | logg("^Broken database version in TXT record.\n");
|
---|
1669 | } else {
|
---|
1670 | newver = atoi(pt);
|
---|
1671 | logg("*%s version from DNS: %d\n", cvdfile, newver);
|
---|
1672 | }
|
---|
1673 | free(pt);
|
---|
1674 | } else {
|
---|
1675 | logg("^Invalid DNS reply. Falling back to HTTP mode.\n");
|
---|
1676 | }
|
---|
1677 | }
|
---|
1678 | #ifdef HAVE_RESOLV_H
|
---|
1679 | else if(!nodb && extra && !optget(opts, "no-dns")->enabled) {
|
---|
1680 | snprintf(extradbinfo, sizeof(extradbinfo), "%s.cvd.clamav.net", dbname);
|
---|
1681 | if((extradnsreply = dnsquery(extradbinfo, T_TXT, NULL))) {
|
---|
1682 | if((pt = cli_strtok(extradnsreply, 1, ":"))) {
|
---|
1683 | int rt;
|
---|
1684 | time_t ct;
|
---|
1685 |
|
---|
1686 | rt = atoi(pt);
|
---|
1687 | free(pt);
|
---|
1688 | time(&ct);
|
---|
1689 | if((int) ct - rt > 10800) {
|
---|
1690 | logg("^DNS record is older than 3 hours.\n");
|
---|
1691 | free(extradnsreply);
|
---|
1692 | extradnsreply = NULL;
|
---|
1693 | }
|
---|
1694 | } else {
|
---|
1695 | logg("^No timestamp in TXT record for %s\n", cvdfile);
|
---|
1696 | free(extradnsreply);
|
---|
1697 | extradnsreply = NULL;
|
---|
1698 | }
|
---|
1699 | if((pt = cli_strtok(extradnsreply, 0, ":"))) {
|
---|
1700 | if(!cli_isnumber(pt)) {
|
---|
1701 | logg("^Broken database version in TXT record for %s\n", cvdfile);
|
---|
1702 | } else {
|
---|
1703 | newver = atoi(pt);
|
---|
1704 | logg("*%s version from DNS: %d\n", cvdfile, newver);
|
---|
1705 | }
|
---|
1706 | free(pt);
|
---|
1707 | } else {
|
---|
1708 | logg("^Invalid DNS reply. Falling back to HTTP mode.\n");
|
---|
1709 | }
|
---|
1710 | }
|
---|
1711 | }
|
---|
1712 | #endif
|
---|
1713 |
|
---|
1714 | if(dnsreply && !extra) {
|
---|
1715 | if((pt = cli_strtok(dnsreply, 5, ":"))) {
|
---|
1716 | remote_flevel = atoi(pt);
|
---|
1717 | free(pt);
|
---|
1718 | if(remote_flevel && (remote_flevel - flevel < 4))
|
---|
1719 | can_whitelist = 1;
|
---|
1720 | }
|
---|
1721 | }
|
---|
1722 |
|
---|
1723 | /* Initialize proxy settings */
|
---|
1724 | if((opt = optget(opts, "HTTPProxyServer"))->enabled) {
|
---|
1725 | proxy = opt->strarg;
|
---|
1726 | if(strncasecmp(proxy, "http://", 7) == 0)
|
---|
1727 | proxy += 7;
|
---|
1728 |
|
---|
1729 | if((opt = optget(opts, "HTTPProxyUsername"))->enabled) {
|
---|
1730 | user = opt->strarg;
|
---|
1731 | if((opt = optget(opts, "HTTPProxyPassword"))->enabled) {
|
---|
1732 | pass = opt->strarg;
|
---|
1733 | } else {
|
---|
1734 | logg("HTTPProxyUsername requires HTTPProxyPassword\n");
|
---|
1735 | if(current)
|
---|
1736 | cl_cvdfree(current);
|
---|
1737 | return 56;
|
---|
1738 | }
|
---|
1739 | }
|
---|
1740 |
|
---|
1741 | if((opt = optget(opts, "HTTPProxyPort"))->enabled)
|
---|
1742 | port = opt->numarg;
|
---|
1743 |
|
---|
1744 | logg("Connecting via %s\n", proxy);
|
---|
1745 | }
|
---|
1746 |
|
---|
1747 | if((opt = optget(opts, "HTTPUserAgent"))->enabled)
|
---|
1748 | uas = opt->strarg;
|
---|
1749 |
|
---|
1750 | ctimeout = optget(opts, "ConnectTimeout")->numarg;
|
---|
1751 | rtimeout = optget(opts, "ReceiveTimeout")->numarg;
|
---|
1752 |
|
---|
1753 | if(!nodb && !newver) {
|
---|
1754 |
|
---|
1755 | remote = remote_cvdhead(cvdfile, localname, hostname, ip, localip, proxy, port, user, pass, uas, &ims, ctimeout, rtimeout, mdat, logerr, can_whitelist);
|
---|
1756 |
|
---|
1757 | if(!nodb && !ims) {
|
---|
1758 | logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", localname, current->version, current->sigs, current->fl, current->builder);
|
---|
1759 | *signo += current->sigs;
|
---|
1760 | if(mirror_stats && strlen(ip)) {
|
---|
1761 | snprintf(squery, sizeof(squery), "%s.%u.%u.%u.%u.%s.ping.clamav.net", dbname, current->version, flevel, 1, w32, ip);
|
---|
1762 | dnsquery(squery, T_A, NULL);
|
---|
1763 | }
|
---|
1764 | cl_cvdfree(current);
|
---|
1765 | return 1;
|
---|
1766 | }
|
---|
1767 |
|
---|
1768 | if(!remote) {
|
---|
1769 | logg("^Can't read %s header from %s (IP: %s)\n", cvdfile, hostname, ip);
|
---|
1770 | if(mirror_stats && strlen(ip)) {
|
---|
1771 | snprintf(squery, sizeof(squery), "%s.%u.%u.%u.%u.%s.ping.clamav.net", dbname, current->version + 1, flevel, 0, w32, ip);
|
---|
1772 | dnsquery(squery, T_A, NULL);
|
---|
1773 | }
|
---|
1774 | cl_cvdfree(current);
|
---|
1775 | return 58;
|
---|
1776 | }
|
---|
1777 |
|
---|
1778 | newver = remote->version;
|
---|
1779 | cl_cvdfree(remote);
|
---|
1780 | }
|
---|
1781 |
|
---|
1782 | if(!nodb && (current->version >= newver)) {
|
---|
1783 | logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", localname, current->version, current->sigs, current->fl, current->builder);
|
---|
1784 |
|
---|
1785 | if(!outdated && flevel < current->fl) {
|
---|
1786 | /* display warning even for already installed database */
|
---|
1787 | logg("^Current functionality level = %d, recommended = %d\n", flevel, current->fl);
|
---|
1788 | logg("Please check if ClamAV tools are linked against the proper version of libclamav\n");
|
---|
1789 | logg("DON'T PANIC! Read http://www.clamav.net/support/faq\n");
|
---|
1790 | }
|
---|
1791 |
|
---|
1792 | *signo += current->sigs;
|
---|
1793 | cl_cvdfree(current);
|
---|
1794 | return 1;
|
---|
1795 | }
|
---|
1796 |
|
---|
1797 | if(current) {
|
---|
1798 | currver = current->version;
|
---|
1799 | cl_cvdfree(current);
|
---|
1800 | }
|
---|
1801 |
|
---|
1802 | /*
|
---|
1803 | if(ipaddr[0]) {
|
---|
1804 | hostfd = wwwconnect(ipaddr, proxy, port, NULL, localip);
|
---|
1805 | } else {
|
---|
1806 | hostfd = wwwconnect(hostname, proxy, port, ipaddr, localip);
|
---|
1807 | if(!ip[0])
|
---|
1808 | strcpy(ip, ipaddr);
|
---|
1809 | }
|
---|
1810 |
|
---|
1811 | if(hostfd < 0) {
|
---|
1812 | if(ipaddr[0])
|
---|
1813 | logg("Connection with %s (IP: %s) failed.\n", hostname, ipaddr);
|
---|
1814 | else
|
---|
1815 | logg("Connection with %s failed.\n", hostname);
|
---|
1816 | return 52;
|
---|
1817 | };
|
---|
1818 | */
|
---|
1819 |
|
---|
1820 | if(!optget(opts, "ScriptedUpdates")->enabled)
|
---|
1821 | nodb = 1;
|
---|
1822 |
|
---|
1823 | newfile = cli_gentemp(updtmpdir);
|
---|
1824 | if(nodb) {
|
---|
1825 | ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, newver, ctimeout, rtimeout, mdat, logerr, can_whitelist, opts);
|
---|
1826 | if(ret) {
|
---|
1827 | if(mirror_stats && strlen(ip)) {
|
---|
1828 | snprintf(squery, sizeof(squery), "%s.%u.%u.%u.%u.%s.ping.clamav.net", dbname, 0, flevel, 0, w32, ip);
|
---|
1829 | dnsquery(squery, T_A, NULL);
|
---|
1830 | }
|
---|
1831 | memset(ip, 0, 16);
|
---|
1832 | free(newfile);
|
---|
1833 | return ret;
|
---|
1834 | }
|
---|
1835 | snprintf(newdb, sizeof(newdb), "%s.cvd", dbname);
|
---|
1836 |
|
---|
1837 | } else {
|
---|
1838 | ret = 0;
|
---|
1839 |
|
---|
1840 | tmpdir = cli_gentemp(updtmpdir);
|
---|
1841 | maxattempts = optget(opts, "MaxAttempts")->numarg;
|
---|
1842 | for(i = currver + 1; i <= newver; i++) {
|
---|
1843 | for(j = 0; j < maxattempts; j++) {
|
---|
1844 | int llogerr = logerr;
|
---|
1845 | if(logerr)
|
---|
1846 | llogerr = (j == maxattempts - 1);
|
---|
1847 | ret = getpatch(dbname, tmpdir, i, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, llogerr, can_whitelist, opts);
|
---|
1848 | if(ret == 52 || ret == 58) {
|
---|
1849 | if(mirror_stats && strlen(ip)) {
|
---|
1850 | snprintf(squery, sizeof(squery), "%s.%u.%u.%u.%u.%s.ping.clamav.net", dbname, i, flevel, 0, w32, ip);
|
---|
1851 | dnsquery(squery, T_A, NULL);
|
---|
1852 | }
|
---|
1853 | memset(ip, 0, 16);
|
---|
1854 | continue;
|
---|
1855 | } else {
|
---|
1856 | break;
|
---|
1857 | }
|
---|
1858 | }
|
---|
1859 | if(ret)
|
---|
1860 | break;
|
---|
1861 | }
|
---|
1862 |
|
---|
1863 | if(ret) {
|
---|
1864 | cli_rmdirs(tmpdir);
|
---|
1865 | free(tmpdir);
|
---|
1866 | if(ret != 53)
|
---|
1867 | logg("^Incremental update failed, trying to download %s\n", cvdfile);
|
---|
1868 | mirman_whitelist(mdat, 2);
|
---|
1869 | ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, newver, ctimeout, rtimeout, mdat, logerr, can_whitelist, opts);
|
---|
1870 | if(ret) {
|
---|
1871 | if(mirror_stats && strlen(ip)) {
|
---|
1872 | snprintf(squery, sizeof(squery), "%s.%u.%u.%u.%u.%s.ping.clamav.net", dbname, 0, flevel, 0, w32, ip);
|
---|
1873 | dnsquery(squery, T_A, NULL);
|
---|
1874 | }
|
---|
1875 | free(newfile);
|
---|
1876 | return ret;
|
---|
1877 | }
|
---|
1878 | snprintf(newdb, sizeof(newdb), "%s.cvd", dbname);
|
---|
1879 | } else {
|
---|
1880 | if(buildcld(tmpdir, dbname, newfile, optget(opts, "CompressLocalDatabase")->enabled) == -1) {
|
---|
1881 | logg("!Can't create local database\n");
|
---|
1882 | cli_rmdirs(tmpdir);
|
---|
1883 | free(tmpdir);
|
---|
1884 | free(newfile);
|
---|
1885 | return 70; /* FIXME */
|
---|
1886 | }
|
---|
1887 | snprintf(newdb, sizeof(newdb), "%s.cld", dbname);
|
---|
1888 | cli_rmdirs(tmpdir);
|
---|
1889 | free(tmpdir);
|
---|
1890 | }
|
---|
1891 | }
|
---|
1892 |
|
---|
1893 | if(!(current = cl_cvdhead(newfile))) {
|
---|
1894 | logg("!Can't parse new database %s\n", newfile);
|
---|
1895 | unlink(newfile);
|
---|
1896 | free(newfile);
|
---|
1897 | return 55; /* FIXME */
|
---|
1898 | }
|
---|
1899 |
|
---|
1900 | if(optget(opts, "TestDatabases")->enabled && strlen(newfile) > 4) {
|
---|
1901 | newfile2 = strdup(newfile);
|
---|
1902 | if(!newfile2) {
|
---|
1903 | logg("!Can't allocate memory for filename!\n");
|
---|
1904 | unlink(newfile);
|
---|
1905 | free(newfile);
|
---|
1906 | return 55;
|
---|
1907 | }
|
---|
1908 | newfile2[strlen(newfile2) - 4] = '.';
|
---|
1909 | newfile2[strlen(newfile2) - 3] = 'c';
|
---|
1910 | newfile2[strlen(newfile2) - 2] = strstr(newdb, ".cld") ? 'l' : 'v';
|
---|
1911 | newfile2[strlen(newfile2) - 1] = 'd';
|
---|
1912 | if(rename(newfile, newfile2) == -1) {
|
---|
1913 | logg("!Can't rename %s to %s: %s\n", newfile, newfile2, strerror(errno));
|
---|
1914 | unlink(newfile);
|
---|
1915 | free(newfile);
|
---|
1916 | free(newfile2);
|
---|
1917 | return 57;
|
---|
1918 | }
|
---|
1919 | free(newfile);
|
---|
1920 | newfile = newfile2;
|
---|
1921 | sigchld_wait = 0;/* we need to wait() for the child ourselves */
|
---|
1922 | if (test_database_wrap(newfile, newdb, optget(opts, "Bytecode")->enabled)) {
|
---|
1923 | logg("!Failed to load new database: %s\n", cl_strerror(ret));
|
---|
1924 | unlink(newfile);
|
---|
1925 | free(newfile);
|
---|
1926 | return 55;
|
---|
1927 | }
|
---|
1928 | sigchld_wait = 1;
|
---|
1929 | }
|
---|
1930 |
|
---|
1931 | #if defined(_WIN32) || defined(C_OS2)
|
---|
1932 | if(!access(newdb, R_OK) && unlink(newdb)) {
|
---|
1933 | logg("!Can't unlink %s. Please fix the problem manually and try again.\n", newdb);
|
---|
1934 | unlink(newfile);
|
---|
1935 | free(newfile);
|
---|
1936 | cl_cvdfree(current);
|
---|
1937 | return 53;
|
---|
1938 | }
|
---|
1939 | #endif
|
---|
1940 |
|
---|
1941 | if(rename(newfile, newdb) == -1) {
|
---|
1942 | logg("!Can't rename %s to %s: %s\n", newfile, newdb, strerror(errno));
|
---|
1943 | unlink(newfile);
|
---|
1944 | free(newfile);
|
---|
1945 | cl_cvdfree(current);
|
---|
1946 | return 57;
|
---|
1947 | }
|
---|
1948 | free(newfile);
|
---|
1949 |
|
---|
1950 | if(!nodb && !access(localname, R_OK) && strcmp(newdb, localname))
|
---|
1951 | if(unlink(localname))
|
---|
1952 | logg("^Can't unlink the old database file %s. Please remove it manually.\n", localname);
|
---|
1953 |
|
---|
1954 | if(!optget(opts, "ScriptedUpdates")->enabled) {
|
---|
1955 | snprintf(localname, sizeof(localname), "%s.cld", dbname);
|
---|
1956 | if(!access(localname, R_OK))
|
---|
1957 | if(unlink(localname))
|
---|
1958 | logg("^Can't unlink the old database file %s. Please remove it manually.\n", localname);
|
---|
1959 | }
|
---|
1960 |
|
---|
1961 | logg("%s updated (version: %d, sigs: %d, f-level: %d, builder: %s)\n", newdb, current->version, current->sigs, current->fl, current->builder);
|
---|
1962 |
|
---|
1963 | if(flevel < current->fl) {
|
---|
1964 | logg("^Your ClamAV installation is OUTDATED!\n");
|
---|
1965 | logg("^Current functionality level = %d, recommended = %d\n", flevel, current->fl);
|
---|
1966 | logg("DON'T PANIC! Read http://www.clamav.net/support/faq\n");
|
---|
1967 | }
|
---|
1968 |
|
---|
1969 | *signo += current->sigs;
|
---|
1970 | if(mirror_stats && strlen(ip)) {
|
---|
1971 | snprintf(squery, sizeof(squery), "%s.%u.%u.%u.%u.%s.ping.clamav.net", dbname, current->version, flevel, 1, w32, ip);
|
---|
1972 | dnsquery(squery, T_A, NULL);
|
---|
1973 | }
|
---|
1974 | cl_cvdfree(current);
|
---|
1975 | return 0;
|
---|
1976 | }
|
---|
1977 |
|
---|
1978 | static int updatecustomdb(const char *url, int *signo, const struct optstruct *opts, char *localip, int logerr)
|
---|
1979 | {
|
---|
1980 | const struct optstruct *opt;
|
---|
1981 | unsigned int port = 0, sigs = 0;
|
---|
1982 | int ret;
|
---|
1983 | char *pt, *host, urlcpy[256], *newfile = NULL, mtime[36], *newfile2;
|
---|
1984 | const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL, *rpath, *dbname;
|
---|
1985 | int ctimeout, rtimeout;
|
---|
1986 | struct stat sb;
|
---|
1987 | struct cl_cvd *cvd;
|
---|
1988 |
|
---|
1989 | if(!strncasecmp(url, "http://", 7)) {
|
---|
1990 | strncpy(urlcpy, url, sizeof(urlcpy));
|
---|
1991 | host = &urlcpy[7];
|
---|
1992 | if(!(pt = strchr(host, '/'))) {
|
---|
1993 | logg("!DatabaseCustomURL: Incorrect URL\n");
|
---|
1994 | return 70;
|
---|
1995 | }
|
---|
1996 | *pt = 0;
|
---|
1997 | rpath = &url[pt - urlcpy + 1];
|
---|
1998 | dbname = strrchr(url, '/') + 1;
|
---|
1999 | if(!dbname || strlen(dbname) < 4) {
|
---|
2000 | logg("DatabaseCustomURL: Incorrect URL\n");
|
---|
2001 | return 70;
|
---|
2002 | }
|
---|
2003 |
|
---|
2004 | /* Initialize proxy settings */
|
---|
2005 | if((opt = optget(opts, "HTTPProxyServer"))->enabled) {
|
---|
2006 | proxy = opt->strarg;
|
---|
2007 | if(strncasecmp(proxy, "http://", 7) == 0)
|
---|
2008 | proxy += 7;
|
---|
2009 |
|
---|
2010 | if((opt = optget(opts, "HTTPProxyUsername"))->enabled) {
|
---|
2011 | user = opt->strarg;
|
---|
2012 | if((opt = optget(opts, "HTTPProxyPassword"))->enabled) {
|
---|
2013 | pass = opt->strarg;
|
---|
2014 | } else {
|
---|
2015 | logg("HTTPProxyUsername requires HTTPProxyPassword\n");
|
---|
2016 | return 56;
|
---|
2017 | }
|
---|
2018 | }
|
---|
2019 | if((opt = optget(opts, "HTTPProxyPort"))->enabled)
|
---|
2020 | port = opt->numarg;
|
---|
2021 | logg("Connecting via %s\n", proxy);
|
---|
2022 | }
|
---|
2023 |
|
---|
2024 | if((opt = optget(opts, "HTTPUserAgent"))->enabled)
|
---|
2025 | uas = opt->strarg;
|
---|
2026 |
|
---|
2027 | ctimeout = optget(opts, "ConnectTimeout")->numarg;
|
---|
2028 | rtimeout = optget(opts, "ReceiveTimeout")->numarg;
|
---|
2029 |
|
---|
2030 | *mtime = 0;
|
---|
2031 | if(stat(dbname, &sb) != -1)
|
---|
2032 | Rfc2822DateTime(mtime, sb.st_mtime);
|
---|
2033 |
|
---|
2034 | newfile = cli_gentemp(updtmpdir);
|
---|
2035 | ret = getfile(rpath, newfile, host, NULL, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, NULL, logerr, 0, *mtime ? mtime : NULL, opts);
|
---|
2036 | if(ret == 1) {
|
---|
2037 | logg("%s is up to date (version: custom database)\n", dbname);
|
---|
2038 | unlink(newfile);
|
---|
2039 | free(newfile);
|
---|
2040 | return 1;
|
---|
2041 | } else if(ret > 1) {
|
---|
2042 | logg("%cCan't download %s from %s\n", logerr ? '!' : '^', dbname, host);
|
---|
2043 | unlink(newfile);
|
---|
2044 | free(newfile);
|
---|
2045 | return ret;
|
---|
2046 | }
|
---|
2047 |
|
---|
2048 | } else if(!strncasecmp(url, "file://", 7)) {
|
---|
2049 | rpath = &url[7];
|
---|
2050 | #ifdef _WIN32
|
---|
2051 | dbname = strrchr(rpath, '\\');
|
---|
2052 | #else
|
---|
2053 | dbname = strrchr(rpath, '/');
|
---|
2054 | #endif
|
---|
2055 | if(!dbname || strlen(dbname++) < 5) {
|
---|
2056 | logg("DatabaseCustomURL: Incorrect URL\n");
|
---|
2057 | return 70;
|
---|
2058 | }
|
---|
2059 |
|
---|
2060 | newfile = cli_gentemp(updtmpdir);
|
---|
2061 | if(!newfile)
|
---|
2062 | return 70;
|
---|
2063 |
|
---|
2064 | /* FIXME: preserve file permissions, calculate % */
|
---|
2065 | logg("Downloading %s [ 0%%]\r", dbname);
|
---|
2066 | if(cli_filecopy(rpath, newfile) == -1) {
|
---|
2067 | logg("DatabaseCustomURL: Can't copy file %s into database directory\n", rpath);
|
---|
2068 | free(newfile);
|
---|
2069 | return 70;
|
---|
2070 | }
|
---|
2071 | logg("Downloading %s [100%%]\n", dbname);
|
---|
2072 | } else {
|
---|
2073 | logg("!DatabaseCustomURL: Not supported protocol\n");
|
---|
2074 | return 70;
|
---|
2075 | }
|
---|
2076 |
|
---|
2077 | if(optget(opts, "TestDatabases")->enabled && strlen(newfile) > 4) {
|
---|
2078 | newfile2 = malloc(strlen(newfile) + strlen(dbname) + 1);
|
---|
2079 | if(!newfile2) {
|
---|
2080 | unlink(newfile);
|
---|
2081 | free(newfile);
|
---|
2082 | return 55;
|
---|
2083 | }
|
---|
2084 | sprintf(newfile2, "%s%s", newfile, dbname);
|
---|
2085 | newfile2[strlen(newfile) + strlen(dbname)] = 0;
|
---|
2086 | if(rename(newfile, newfile2) == -1) {
|
---|
2087 | logg("!Can't rename %s to %s: %s\n", newfile, newfile2, strerror(errno));
|
---|
2088 | unlink(newfile);
|
---|
2089 | free(newfile);
|
---|
2090 | free(newfile2);
|
---|
2091 | return 57;
|
---|
2092 | }
|
---|
2093 | free(newfile);
|
---|
2094 | newfile = newfile2;
|
---|
2095 | sigchld_wait = 0;/* we need to wait() for the child ourselves */
|
---|
2096 | if (test_database_wrap(newfile, dbname, optget(opts, "Bytecode")->enabled)) {
|
---|
2097 | logg("!Failed to load new database: %s\n", cl_strerror(ret));
|
---|
2098 | unlink(newfile);
|
---|
2099 | free(newfile);
|
---|
2100 | return 55;
|
---|
2101 | }
|
---|
2102 | sigchld_wait = 1;
|
---|
2103 | }
|
---|
2104 |
|
---|
2105 | #ifdef _WIN32
|
---|
2106 | if(!access(dbname, R_OK) && unlink(dbname)) {
|
---|
2107 | logg("!Can't unlink %s. Please fix the problem manually and try again.\n", dbname);
|
---|
2108 | unlink(newfile);
|
---|
2109 | free(newfile);
|
---|
2110 | return 53;
|
---|
2111 | }
|
---|
2112 | #endif
|
---|
2113 |
|
---|
2114 | if(rename(newfile, dbname) == -1) {
|
---|
2115 | logg("!Can't rename %s to %s: %s\n", newfile, dbname, strerror(errno));
|
---|
2116 | unlink(newfile);
|
---|
2117 | free(newfile);
|
---|
2118 | return 57;
|
---|
2119 | }
|
---|
2120 | free(newfile);
|
---|
2121 |
|
---|
2122 | if(cli_strbcasestr(dbname, ".cld") || cli_strbcasestr(dbname, ".cvd")) {
|
---|
2123 | if((cvd = cl_cvdhead(dbname))) {
|
---|
2124 | sigs = cvd->sigs;
|
---|
2125 | cl_cvdfree(cvd);
|
---|
2126 | }
|
---|
2127 | } else if(cli_strbcasestr(dbname, ".cbc")) {
|
---|
2128 | sigs = 1;
|
---|
2129 | } else {
|
---|
2130 | sigs = countlines(dbname);
|
---|
2131 | }
|
---|
2132 |
|
---|
2133 | logg("%s updated (version: custom database, sigs: %u)\n", dbname, sigs);
|
---|
2134 | *signo += sigs;
|
---|
2135 | return 0;
|
---|
2136 | }
|
---|
2137 |
|
---|
2138 | int downloadmanager(const struct optstruct *opts, const char *hostname, int logerr)
|
---|
2139 | {
|
---|
2140 | time_t currtime;
|
---|
2141 | int ret, updated = 0, outdated = 0, signo = 0;
|
---|
2142 | unsigned int ttl;
|
---|
2143 | char ipaddr[46], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
|
---|
2144 | const struct optstruct *opt;
|
---|
2145 | struct mirdat mdat;
|
---|
2146 | #ifdef HAVE_RESOLV_H
|
---|
2147 | const char *dnsdbinfo;
|
---|
2148 | #endif
|
---|
2149 |
|
---|
2150 | pt = cli_gentemp(dbdir);
|
---|
2151 | if(!pt)
|
---|
2152 | return 57;
|
---|
2153 | strncpy(updtmpdir, pt, sizeof(updtmpdir));
|
---|
2154 | free(pt);
|
---|
2155 | if(mkdir(updtmpdir, 0755)) {
|
---|
2156 | logg("!Can't create temporary directory %s\n", updtmpdir);
|
---|
2157 | logg("Hint: The database directory must be writable for UID %d or GID %d\n", getuid(), getgid());
|
---|
2158 | return 57;
|
---|
2159 | }
|
---|
2160 |
|
---|
2161 | time(&currtime);
|
---|
2162 | logg("ClamAV update process started at %s", ctime(&currtime));
|
---|
2163 | #ifdef HAVE_GETADDRINFO
|
---|
2164 | logg("*Using IPv6 aware code\n");
|
---|
2165 | #endif
|
---|
2166 |
|
---|
2167 | #ifdef HAVE_RESOLV_H
|
---|
2168 | dnsdbinfo = optget(opts, "DNSDatabaseInfo")->strarg;
|
---|
2169 |
|
---|
2170 | if(optget(opts, "no-dns")->enabled) {
|
---|
2171 | dnsreply = NULL;
|
---|
2172 | } else {
|
---|
2173 | if((dnsreply = dnsquery(dnsdbinfo, T_TXT, &ttl))) {
|
---|
2174 | logg("*TTL: %d\n", ttl);
|
---|
2175 |
|
---|
2176 | if((pt = cli_strtok(dnsreply, 3, ":"))) {
|
---|
2177 | int rt;
|
---|
2178 | time_t ct;
|
---|
2179 |
|
---|
2180 | rt = atoi(pt);
|
---|
2181 | free(pt);
|
---|
2182 | time(&ct);
|
---|
2183 | if((int) ct - rt > 10800) {
|
---|
2184 | logg("^DNS record is older than 3 hours.\n");
|
---|
2185 | free(dnsreply);
|
---|
2186 | dnsreply = NULL;
|
---|
2187 | }
|
---|
2188 |
|
---|
2189 | } else {
|
---|
2190 | free(dnsreply);
|
---|
2191 | dnsreply = NULL;
|
---|
2192 | }
|
---|
2193 |
|
---|
2194 | if(dnsreply) {
|
---|
2195 | int vwarning = 1;
|
---|
2196 |
|
---|
2197 | if((pt = cli_strtok(dnsreply, 4, ":"))) {
|
---|
2198 | if(*pt == '0')
|
---|
2199 | vwarning = 0;
|
---|
2200 |
|
---|
2201 | free(pt);
|
---|
2202 | }
|
---|
2203 |
|
---|
2204 | if((newver = cli_strtok(dnsreply, 0, ":"))) {
|
---|
2205 | char vstr[32];
|
---|
2206 |
|
---|
2207 | logg("*Software version from DNS: %s\n", newver);
|
---|
2208 | strncpy(vstr, get_version(), 32);
|
---|
2209 | vstr[31] = 0;
|
---|
2210 | if(vwarning && !strstr(vstr, "devel") && !strstr(vstr, "rc")) {
|
---|
2211 | pt = strchr(vstr, '-');
|
---|
2212 | if((pt && strncmp(vstr, newver, pt - vstr)) || (!pt && strcmp(vstr, newver))) {
|
---|
2213 | logg("^Your ClamAV installation is OUTDATED!\n");
|
---|
2214 | logg("^Local version: %s Recommended version: %s\n", vstr, newver);
|
---|
2215 | logg("DON'T PANIC! Read http://www.clamav.net/support/faq\n");
|
---|
2216 | outdated = 1;
|
---|
2217 | }
|
---|
2218 | }
|
---|
2219 | }
|
---|
2220 | }
|
---|
2221 | }
|
---|
2222 |
|
---|
2223 | if(!dnsreply) {
|
---|
2224 | logg("^Invalid DNS reply. Falling back to HTTP mode.\n");
|
---|
2225 | }
|
---|
2226 | }
|
---|
2227 | #endif /* HAVE_RESOLV_H */
|
---|
2228 |
|
---|
2229 | if((opt = optget(opts, "LocalIPAddress"))->enabled)
|
---|
2230 | localip = opt->strarg;
|
---|
2231 |
|
---|
2232 | if(optget(opts, "HTTPProxyServer")->enabled)
|
---|
2233 | mirman_read("mirrors.dat", &mdat, 0);
|
---|
2234 | else
|
---|
2235 | mirman_read("mirrors.dat", &mdat, 1);
|
---|
2236 |
|
---|
2237 | memset(ipaddr, 0, sizeof(ipaddr));
|
---|
2238 |
|
---|
2239 | if((ret = updatedb("main", hostname, ipaddr, &signo, opts, dnsreply, localip, outdated, &mdat, logerr, 0)) > 50) {
|
---|
2240 | if(dnsreply)
|
---|
2241 | free(dnsreply);
|
---|
2242 |
|
---|
2243 | if(newver)
|
---|
2244 | free(newver);
|
---|
2245 |
|
---|
2246 | mirman_write("mirrors.dat", dbdir, &mdat);
|
---|
2247 | mirman_free(&mdat);
|
---|
2248 | cli_rmdirs(updtmpdir);
|
---|
2249 | return ret;
|
---|
2250 |
|
---|
2251 | } else if(ret == 0)
|
---|
2252 | updated = 1;
|
---|
2253 |
|
---|
2254 | /* if ipaddr[0] != 0 it will use it to connect to the web host */
|
---|
2255 | if((ret = updatedb("daily", hostname, ipaddr, &signo, opts, dnsreply, localip, outdated, &mdat, logerr, 0)) > 50) {
|
---|
2256 | if(dnsreply)
|
---|
2257 | free(dnsreply);
|
---|
2258 |
|
---|
2259 | if(newver)
|
---|
2260 | free(newver);
|
---|
2261 |
|
---|
2262 | mirman_write("mirrors.dat", dbdir, &mdat);
|
---|
2263 | mirman_free(&mdat);
|
---|
2264 | cli_rmdirs(updtmpdir);
|
---|
2265 | return ret;
|
---|
2266 |
|
---|
2267 | } else if(ret == 0)
|
---|
2268 | updated = 1;
|
---|
2269 |
|
---|
2270 | /* if ipaddr[0] != 0 it will use it to connect to the web host */
|
---|
2271 | if(!optget(opts, "SafeBrowsing")->enabled) {
|
---|
2272 | const char *safedb = NULL;
|
---|
2273 |
|
---|
2274 | if(!access("safebrowsing.cvd", R_OK))
|
---|
2275 | safedb = "safebrowsing.cvd";
|
---|
2276 | else if(!access("safebrowsing.cld", R_OK))
|
---|
2277 | safedb = "safebrowsing.cld";
|
---|
2278 |
|
---|
2279 | if(safedb) {
|
---|
2280 | if(unlink(safedb))
|
---|
2281 | logg("^SafeBrowsing is disabled but can't remove old %s\n", safedb);
|
---|
2282 | else
|
---|
2283 | logg("*%s removed\n", safedb);
|
---|
2284 | }
|
---|
2285 | } else if((ret = updatedb("safebrowsing", hostname, ipaddr, &signo, opts, dnsreply, localip, outdated, &mdat, logerr, 0)) > 50) {
|
---|
2286 | if(dnsreply)
|
---|
2287 | free(dnsreply);
|
---|
2288 |
|
---|
2289 | if(newver)
|
---|
2290 | free(newver);
|
---|
2291 |
|
---|
2292 | mirman_write("mirrors.dat", dbdir, &mdat);
|
---|
2293 | mirman_free(&mdat);
|
---|
2294 | cli_rmdirs(updtmpdir);
|
---|
2295 | return ret;
|
---|
2296 | } else if(ret == 0)
|
---|
2297 | updated = 1;
|
---|
2298 |
|
---|
2299 | if(!optget(opts, "Bytecode")->enabled) {
|
---|
2300 | const char *dbname = NULL;
|
---|
2301 |
|
---|
2302 | if(!access("bytecode.cvd", R_OK))
|
---|
2303 | dbname = "bytecode.cvd";
|
---|
2304 | else if(!access("bytecode.cld", R_OK))
|
---|
2305 | dbname = "bytecode.cld";
|
---|
2306 |
|
---|
2307 | if(dbname) {
|
---|
2308 | if(unlink(dbname))
|
---|
2309 | logg("^Bytecode is disabled but can't remove old %s\n", dbname);
|
---|
2310 | else
|
---|
2311 | logg("*%s removed\n", dbname);
|
---|
2312 | }
|
---|
2313 | } else if((ret = updatedb("bytecode", hostname, ipaddr, &signo, opts, dnsreply, localip, outdated, &mdat, logerr, 0)) > 50) {
|
---|
2314 | if(dnsreply)
|
---|
2315 | free(dnsreply);
|
---|
2316 |
|
---|
2317 | if(newver)
|
---|
2318 | free(newver);
|
---|
2319 |
|
---|
2320 | mirman_write("mirrors.dat", dbdir, &mdat);
|
---|
2321 | mirman_free(&mdat);
|
---|
2322 | cli_rmdirs(updtmpdir);
|
---|
2323 | return ret;
|
---|
2324 | } else if(ret == 0)
|
---|
2325 | updated = 1;
|
---|
2326 | if(dnsreply)
|
---|
2327 | free(dnsreply);
|
---|
2328 |
|
---|
2329 | /* handle extra dbs */
|
---|
2330 | if((opt = optget(opts, "ExtraDatabase"))->enabled) {
|
---|
2331 | while(opt) {
|
---|
2332 | if((ret = updatedb(opt->strarg, hostname, ipaddr, &signo, opts, NULL, localip, outdated, &mdat, logerr, 1)) > 50) {
|
---|
2333 | if(newver)
|
---|
2334 | free(newver);
|
---|
2335 | mirman_write("mirrors.dat", dbdir, &mdat);
|
---|
2336 | mirman_free(&mdat);
|
---|
2337 | cli_rmdirs(updtmpdir);
|
---|
2338 | return ret;
|
---|
2339 | } else if(ret == 0)
|
---|
2340 | updated = 1;
|
---|
2341 | opt = opt->nextarg;
|
---|
2342 | }
|
---|
2343 | }
|
---|
2344 |
|
---|
2345 | mirman_write("mirrors.dat", dbdir, &mdat);
|
---|
2346 | mirman_free(&mdat);
|
---|
2347 |
|
---|
2348 | /* custom dbs */
|
---|
2349 | if((opt = optget(opts, "DatabaseCustomURL"))->enabled) {
|
---|
2350 | while(opt) {
|
---|
2351 | if(updatecustomdb(opt->strarg, &signo, opts, localip, logerr) == 0)
|
---|
2352 | updated = 1;
|
---|
2353 | opt = opt->nextarg;
|
---|
2354 | }
|
---|
2355 | }
|
---|
2356 |
|
---|
2357 | cli_rmdirs(updtmpdir);
|
---|
2358 |
|
---|
2359 | if(checkdbdir() < 0) {
|
---|
2360 | if(newver)
|
---|
2361 | free(newver);
|
---|
2362 | return 54;
|
---|
2363 | }
|
---|
2364 |
|
---|
2365 | if(updated) {
|
---|
2366 | if(optget(opts, "HTTPProxyServer")->enabled || !ipaddr[0]) {
|
---|
2367 | logg("Database updated (%d signatures) from %s\n", signo, hostname);
|
---|
2368 | } else {
|
---|
2369 | logg("Database updated (%d signatures) from %s (IP: %s)\n", signo, hostname, ipaddr);
|
---|
2370 | }
|
---|
2371 |
|
---|
2372 | #ifdef BUILD_CLAMD
|
---|
2373 | if((opt = optget(opts, "NotifyClamd"))->active)
|
---|
2374 | notify(opt->strarg);
|
---|
2375 | #endif
|
---|
2376 |
|
---|
2377 | if((opt = optget(opts, "OnUpdateExecute"))->enabled)
|
---|
2378 | execute("OnUpdateExecute", opt->strarg, opts);
|
---|
2379 | }
|
---|
2380 |
|
---|
2381 | if(outdated) {
|
---|
2382 | if((opt = optget(opts, "OnOutdatedExecute"))->enabled) {
|
---|
2383 | char *cmd = strdup(opt->strarg);
|
---|
2384 |
|
---|
2385 | if((pt = newver)) {
|
---|
2386 | while(*pt) {
|
---|
2387 | if(!strchr("0123456789.", *pt)) {
|
---|
2388 | logg("!downloadmanager: OnOutdatedExecute: Incorrect version number string\n");
|
---|
2389 | free(newver);
|
---|
2390 | newver = NULL;
|
---|
2391 | break;
|
---|
2392 | }
|
---|
2393 | pt++;
|
---|
2394 | }
|
---|
2395 | }
|
---|
2396 |
|
---|
2397 | if(newver && (pt = strstr(cmd, "%v"))) {
|
---|
2398 | char *buffer = (char *) malloc(strlen(cmd) + strlen(newver) + 10);
|
---|
2399 |
|
---|
2400 | if(!buffer) {
|
---|
2401 | logg("!downloadmanager: Can't allocate memory for buffer\n");
|
---|
2402 | free(cmd);
|
---|
2403 | if(newver)
|
---|
2404 | free(newver);
|
---|
2405 | return 75;
|
---|
2406 | }
|
---|
2407 |
|
---|
2408 | *pt = 0; pt += 2;
|
---|
2409 | strcpy(buffer, cmd);
|
---|
2410 | strcat(buffer, newver);
|
---|
2411 | strcat(buffer, pt);
|
---|
2412 | free(cmd);
|
---|
2413 | cmd = strdup(buffer);
|
---|
2414 | free(buffer);
|
---|
2415 | }
|
---|
2416 |
|
---|
2417 | if(newver)
|
---|
2418 | execute("OnOutdatedExecute", cmd, opts);
|
---|
2419 |
|
---|
2420 | free(cmd);
|
---|
2421 | }
|
---|
2422 | }
|
---|
2423 |
|
---|
2424 | if(newver)
|
---|
2425 | free(newver);
|
---|
2426 |
|
---|
2427 | return 0;
|
---|
2428 | }
|
---|