Browse code

initial support for incremental updates

git-svn: trunk@2083

Tomasz Kojm authored on 2006/07/15 07:16:27
Showing 3 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sat Jul 15 00:15:17 CEST 2006 (tk)
2
+----------------------------------
3
+  * freshclam/manager.c: initial support for incremental updates
4
+
1 5
 Fri Jul 14 13:14:13 BST 2006 (njh)
2 6
 ----------------------------------
3 7
   * libclamav/table.c:	Added tableIterate
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net>
2
+ *  Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
3 3
  *  HTTP/1.1 compliance by Arkadiusz Miskiewicz <misiek@pld.org.pl>
4 4
  *  Proxy support by Nigel Horne <njh@bandsman.co.uk>
5 5
  *  Proxy authorization support by Gernot Tenchio <g.tenchio@telco-tech.de>
... ...
@@ -41,422 +41,29 @@
41 41
 #include <clamav.h>
42 42
 #include <errno.h>
43 43
 
44
-#include "options.h"
45 44
 #include "defaults.h"
46 45
 #include "manager.h"
47 46
 #include "notify.h"
48
-#include "memory.h"
49
-#include "output.h"
50
-#include "misc.h"
51
-#include "../libclamav/others.h"
52
-#include "../libclamav/str.h" /* cli_strtok */
53 47
 #include "dns.h"
54 48
 #include "execute.h"
55 49
 
50
+#include "shared/options.h"
51
+#include "shared/cfgparser.h"
52
+#include "shared/output.h"
53
+#include "shared/misc.h"
54
+#include "shared/memory.h"
55
+#include "shared/cdiff.h"
56 56
 
57
+#include "libclamav/others.h"
58
+#include "libclamav/str.h"
59
+#include "libclamav/cvd.h"
57 60
 
58
-int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, const char *hostname)
59
-{
60
-	time_t currtime;
61
-	int ret, updated = 0, outdated = 0, signo = 0, ttl = -1;
62
-	char ipaddr[16], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
63
-	const char *arg = NULL;
64
-	struct cfgstruct *cpt;
65
-#ifdef HAVE_RESOLV_H
66
-	const char *dnsdbinfo;
67
-#endif
68
-
69
-    time(&currtime);
70
-    logg("ClamAV update process started at %s", ctime(&currtime));
71
-
72
-#ifndef HAVE_GMP
73
-    logg("SECURITY WARNING: NO SUPPORT FOR DIGITAL SIGNATURES\n");
74
-    logg("See the FAQ at http://www.clamav.net/faq.html for an explanation.\n");
75
-#endif
76
-
77
-#ifdef HAVE_RESOLV_H
78
-    dnsdbinfo = cfgopt(copt, "DNSDatabaseInfo")->strarg;
79
-
80
-    if(opt_check(opt, "no-dns")) {
81
-	dnsreply = NULL;
82
-    } else {
83
-	if((dnsreply = txtquery(dnsdbinfo, &ttl))) {
84
-	    logg("*TTL: %d\n", ttl);
85
-
86
-	    if((pt = cli_strtok(dnsreply, 3, ":"))) {
87
-		    int rt;
88
-		    time_t ct;
89
-
90
-		rt = atoi(pt);
91
-		free(pt);
92
-		time(&ct);
93
-		if((int) ct - rt > 10800) {
94
-		    logg("^DNS record is older than 3 hours.\n");
95
-		    free(dnsreply);
96
-		    dnsreply = NULL;
97
-		}
98
-
99
-	    } else {
100
-		free(dnsreply);
101
-		dnsreply = NULL;
102
-	    }
103
-
104
-	    if(dnsreply) {
105
-		    int vwarning = 1;
106
-
107
-		if((pt = cli_strtok(dnsreply, 4, ":"))) {
108
-		    if(*pt == '0')
109
-			vwarning = 0;
110
-
111
-		    free(pt);
112
-		}
113
-
114
-		if((newver = cli_strtok(dnsreply, 0, ":"))) {
115
-
116
-		    logg("*Software version from DNS: %s\n", newver);
117
-
118
-		    if(vwarning && !strstr(cl_retver(), "devel") && !strstr(cl_retver(), "rc")) {
119
-			if(strcmp(cl_retver(), newver)) {
120
-			    logg("^Your ClamAV installation is OUTDATED!\n");
121
-			    logg("^Local version: %s Recommended version: %s\n", cl_retver(), pt);
122
-			    logg("DON'T PANIC! Read http://www.clamav.net/faq.html\n");
123
-			    outdated = 1;
124
-			}
125
-		    }
126
-		}
127
-
128
-	    } else {
129
-		if(dnsreply) {
130
-		    free(dnsreply);
131
-		    dnsreply = NULL;
132
-		}
133
-	    }
134
-	}
135
-
136
-	if(!dnsreply) {
137
-	    logg("^Invalid DNS reply. Falling back to HTTP mode.\n");
138
-	}
139
-    }
140
-#endif /* HAVE_RESOLV_H */
141
-
142
-    if(opt_check(opt, "local-address")) {
143
-        localip = opt_arg(opt, "local-address");
144
-    } else if((cpt = cfgopt(copt, "LocalIPAddress"))->enabled) {
145
-	localip = cpt->strarg;
146
-    }
147
-
148
-    memset(ipaddr, 0, sizeof(ipaddr));
149
-
150
-    if((ret = downloaddb(DB1NAME, "main.cvd", hostname, ipaddr, &signo, copt, dnsreply, localip, outdated)) > 50) {
151
-	if(dnsreply)
152
-	    free(dnsreply);
153
-
154
-	if(newver)
155
-	    free(newver);
156
-
157
-	return ret;
158
-
159
-    } else if(ret == 0)
160
-	updated = 1;
161
-
162
-    /* if ipaddr[0] != 0 it will use it to connect to the web host */
163
-    if((ret = downloaddb(DB2NAME, "daily.cvd", hostname, ipaddr, &signo, copt, dnsreply, localip, outdated)) > 50) {
164
-	if(dnsreply)
165
-	    free(dnsreply);
166
-
167
-	if(newver)
168
-	    free(newver);
169
-
170
-	return ret;
171
-
172
-    } else if(ret == 0)
173
-	updated = 1;
174
-
175
-    if(dnsreply)
176
-	free(dnsreply);
177
-
178
-    if(updated) {
179
-	if(cfgopt(copt, "HTTPProxyServer")->enabled) {
180
-	    logg("Database updated (%d signatures) from %s\n", signo, hostname);
181
-	} else {
182
-	    logg("Database updated (%d signatures) from %s (IP: %s)\n", signo, hostname, ipaddr);
183
-	}
184
-
185
-#ifdef BUILD_CLAMD
186
-	if(opt_check(opt, "daemon-notify")) {
187
-		const char *clamav_conf = opt_arg(opt, "daemon-notify");
188
-	    if(!clamav_conf)
189
-		clamav_conf = CONFDIR"/clamd.conf";
190
-
191
-	    notify(clamav_conf);
192
-	} else if((cpt = cfgopt(copt, "NotifyClamd"))->enabled) {
193
-	    notify(cpt->strarg);
194
-	}
61
+#ifndef	O_BINARY
62
+#define	O_BINARY	0
195 63
 #endif
196 64
 
197
-	if(opt_check(opt, "on-update-execute"))
198
-	    arg = opt_arg(opt, "on-update-execute");
199
-	else if((cpt = cfgopt(copt, "OnUpdateExecute"))->enabled)
200
-	    arg = cpt->strarg;
201
-
202
-	if(arg) {
203
-	    if(opt_check(opt, "daemon"))
204
-		execute("OnUpdateExecute", arg);
205
-            else
206
-		system(arg);
207
-	}
208
-    }
209 65
 
210
-    if(outdated) {
211
-	if(opt_check(opt, "on-outdated-execute"))
212
-	    arg = opt_arg(opt, "on-outdated-execute");
213
-	else if((cpt = cfgopt(copt, "OnOutdatedExecute"))->enabled)
214
-	    arg = cpt->strarg;
215
-
216
-	if(arg) {
217
-		char *cmd = strdup(arg);
218
-
219
-	    if((pt = strstr(cmd, "%v")) && newver && isdigit(*newver)) {
220
-		    char *buffer = (char *) mcalloc(strlen(cmd) + strlen(newver) + 10, sizeof(char));
221
-		*pt = 0; pt += 2;
222
-		strcpy(buffer, cmd);
223
-		strcat(buffer, newver);
224
-		strcat(buffer, pt);
225
-		free(cmd);
226
-		cmd = strdup(buffer);
227
-		free(buffer);
228
-	    }
229
-
230
-	    if(opt_check(opt, "daemon"))
231
-		execute("OnOutdatedExecute", cmd);
232
-	    else
233
-		system(cmd);
234
-
235
-	    free(cmd);
236
-	}
237
-    }
238
-
239
-    if(newver)
240
-	free(newver);
241
-
242
-    return updated ? 0 : 1;
243
-}
244
-
245
-int downloaddb(const char *localname, const char *remotename, const char *hostname, char *ip, int *signo, const struct cfgstruct *copt, const char *dnsreply, char *localip, int outdated)
246
-{
247
-	struct cl_cvd *current, *remote;
248
-	struct cfgstruct *cpt;
249
-	int hostfd, nodb = 0, dbver = -1, ret, port = 0, ims = -1;
250
-	char  *tempname, ipaddr[16], *pt;
251
-	const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL;
252
-	int flevel = cl_retflevel();
253
-
254
-
255
-    if((current = cl_cvdhead(localname)) == NULL)
256
-	nodb = 1;
257
-
258
-    if(!nodb && dnsreply) {
259
-	    int field = 0;
260
-
261
-	if(!strcmp(remotename, "main.cvd")) {
262
-	    field = 1;
263
-	} else if(!strcmp(remotename, "daily.cvd")) {
264
-	    field = 2;
265
-	} else {
266
-	    logg("^Unknown database name (%s) passed.\n", remotename);
267
-	}
268
-
269
-	if(field && (pt = cli_strtok(dnsreply, field, ":"))) {
270
-	    if(!isnumb(pt)) {
271
-		logg("^Broken database version in TXT record.\n");
272
-	    } else {
273
-		dbver = atoi(pt);
274
-		logg("*%s version from DNS: %d\n", remotename, dbver);
275
-	    }
276
-	    free(pt);
277
-	} else {
278
-	    logg("^Invalid DNS reply. Falling back to HTTP mode.\n");
279
-	}
280
-
281
-    }
282
-
283
-    /* Initialize proxy settings */
284
-    if((cpt = cfgopt(copt, "HTTPProxyServer"))->enabled) {
285
-	proxy = cpt->strarg;
286
-	if(strncasecmp(proxy, "http://", 7) == 0)
287
-	    proxy += 7;
288
-
289
-	if((cpt = cfgopt(copt, "HTTPProxyUsername"))->enabled) {
290
-	    user = cpt->strarg;
291
-	    if((cpt = cfgopt(copt, "HTTPProxyPassword"))->enabled) {
292
-		pass = cpt->strarg;
293
-	    } else {
294
-		logg("HTTPProxyUsername requires HTTPProxyPassword\n");
295
-		if(current)
296
-		    cl_cvdfree(current);
297
-		return 56;
298
-	    }
299
-	}
300
-
301
-	if((cpt = cfgopt(copt, "HTTPProxyPort"))->enabled)
302
-	    port = cpt->numarg;
303
-
304
-	logg("Connecting via %s\n", proxy);
305
-    }
306
-
307
-    if((cpt = cfgopt(copt, "HTTPUserAgent"))->enabled)
308
-	uas = cpt->strarg;
309
-
310
-    memset(ipaddr, 0, sizeof(ipaddr));
311
-
312
-    if(!nodb && dbver == -1) {
313
-	if(ip[0]) /* use ip to connect */
314
-	    hostfd = wwwconnect(ip, proxy, port, ipaddr, localip);
315
-	else
316
-	    hostfd = wwwconnect(hostname, proxy, port, ipaddr, localip);
317
-
318
-	if(hostfd < 0) {
319
-	    if(current)
320
-		cl_cvdfree(current);
321
-	    return 52;
322
-	} else {
323
-	    logg("*Connected to %s (IP: %s).\n", hostname, ipaddr);
324
-	    logg("*Trying to retrieve http://%s/%s\n", hostname, remotename);
325
-	}
326
-
327
-	if(!ip[0])
328
-	    strcpy(ip, ipaddr);
329
-
330
-	remote = remote_cvdhead(remotename, hostfd, hostname, proxy, user, pass, uas, &ims);
331
-
332
-	if(!nodb && !ims) {
333
-	    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);
334
-	    *signo += current->sigs;
335
-	    close(hostfd);
336
-	    cl_cvdfree(current);
337
-	    return 1;
338
-	}
339
-
340
-	if(!remote) {
341
-	    logg("^Can't read %s header from %s (IP: %s)\n", remotename, hostname, ipaddr);
342
-	    close(hostfd);
343
-	    if(current)
344
-		cl_cvdfree(current);
345
-	    return 58;
346
-	}
347
-
348
-	dbver = remote->version;
349
-	cl_cvdfree(remote);
350
-	close(hostfd);
351
-    }
352
-
353
-    if(!nodb && (current->version >= dbver)) {
354
-	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);
355
-
356
-	if(!outdated && flevel < current->fl) {
357
-	    /* display warning even for already installed database */
358
-	    logg("^Current functionality level = %d, recommended = %d\n", flevel, current->fl);
359
-	    logg("Please check if ClamAV tools are linked against proper version of libclamav\n");
360
-	    logg("DON'T PANIC! Read http://www.clamav.net/faq.html\n");
361
-	}
362
-
363
-	*signo += current->sigs;
364
-	cl_cvdfree(current);
365
-	return 1;
366
-    }
367
-
368
-    if(current)
369
-	cl_cvdfree(current);
370
-
371
-    if(ipaddr[0]) {
372
-	/* use ipaddr in order to connect to the same mirror */
373
-	hostfd = wwwconnect(ipaddr, proxy, port, NULL, localip);
374
-    } else {
375
-	hostfd = wwwconnect(hostname, proxy, port, ipaddr, localip);
376
-	if(!ip[0])
377
-	    strcpy(ip, ipaddr);
378
-    }
379
-
380
-    if(hostfd < 0) {
381
-	if(ipaddr[0])
382
-	    logg("Connection with %s (IP: %s) failed.\n", hostname, ipaddr);
383
-	else
384
-	    logg("Connection with %s failed.\n", hostname);
385
-	return 52;
386
-    };
387
-
388
-    /* the temporary file is created in a directory owned by clamav so race
389
-     * conditions are not possible
390
-     */
391
-    tempname = cli_gentemp(".");
392
-
393
-    logg("*Retrieving http://%s/%s\n", hostname, remotename);
394
-    if((ret = get_database(remotename, hostfd, tempname, hostname, proxy, user, pass, uas))) {
395
-        logg("^Can't download %s from %s (IP: %s)\n", remotename, hostname, ipaddr);
396
-        unlink(tempname);
397
-        free(tempname);
398
-        close(hostfd);
399
-        return ret;
400
-    }
401
-
402
-    close(hostfd);
403
-
404
-    if((ret = cl_cvdverify(tempname))) {
405
-        logg("^Verification: %s\n", cl_strerror(ret));
406
-        unlink(tempname);
407
-        free(tempname);
408
-        return 54;
409
-    }
410
-
411
-    if((current = cl_cvdhead(tempname)) == NULL) {
412
-	logg("^Can't read CVD header of new %s database.\n", localname);
413
-	unlink(tempname);
414
-	free(tempname);
415
-	return 54;
416
-    }
417
-
418
-    if(current->version < dbver) {
419
-	logg("^Mirrors are not fully synchronized. Please try again later.\n");
420
-    	cl_cvdfree(current);
421
-	unlink(tempname);
422
-	free(tempname);
423
-	return 59;
424
-    }
425
-
426
-    if(!nodb && unlink(localname)) {
427
-	logg("^Can't unlink %s. Please fix it and try again.\n", localname);
428
-    	cl_cvdfree(current);
429
-	unlink(tempname);
430
-	free(tempname);
431
-	return 53;
432
-    } else {
433
-    	if(rename(tempname, localname) == -1) {
434
-    	    logg("^Can't rename %s to %s: %s\n", tempname, localname, strerror(errno));
435
-    	    if(errno == EEXIST) {
436
-    	        unlink(localname);
437
-    	        if(rename(tempname, localname) == -1)
438
-                   logg("^All attempts to rename the temporary file failed: %s\n", strerror(errno));
439
-            }
440
-        }
441
-    }
442
-
443
-    logg("%s updated (version: %d, sigs: %d, f-level: %d, builder: %s)\n", localname, current->version, current->sigs, current->fl, current->builder);
444
-
445
-    if(flevel < current->fl) {
446
-	logg("^Your ClamAV installation is OUTDATED!\n");
447
-	logg("^Current functionality level = %d, recommended = %d\n", flevel, current->fl);
448
-	logg("DON'T PANIC! Read http://www.clamav.net/faq.html\n");
449
-    }
450
-
451
-    *signo += current->sigs;
452
-    cl_cvdfree(current);
453
-    free(tempname);
454
-    return 0;
455
-}
456
-
457
-/* this function returns socket descriptor */
458
-/* proxy support finshed by njh@bandsman.co.uk */
459
-int wwwconnect(const char *server, const char *proxy, int pport, char *ip, char *localip)
66
+static int wwwconnect(const char *server, const char *proxy, int pport, char *ip, const char *localip)
460 67
 {
461 68
 	int socketfd = -1, port, i;
462 69
 	struct sockaddr_in name;
... ...
@@ -482,8 +89,8 @@ int wwwconnect(const char *server, const char *proxy, int pport, char *ip, char
482 482
 	return -1;
483 483
     }
484 484
 
485
-    if (localip) {
486
-	if ((he = gethostbyname(localip)) == NULL) {
485
+    if(localip) {
486
+	if((he = gethostbyname(localip)) == NULL) {
487 487
 	    char *herr;
488 488
 	    switch(h_errno) {
489 489
 	        case HOST_NOT_FOUND:
... ...
@@ -608,10 +215,79 @@ static int Rfc2822DateTime(char *buf, time_t mtime)
608 608
     return strftime(buf, 36, "%a, %d %b %Y %X GMT", time);
609 609
 }
610 610
 
611
-struct cl_cvd *remote_cvdhead(const char *file, int socketfd, const char *hostname, const char *proxy, const char *user, const char *pass, const char *uas, int *ims)
611
+static unsigned int fmt_base64(char *dest, const char *src, unsigned int len)
612 612
 {
613
-	char cmd[512], head[513], buffer[FILEBUFF], *ch, *tmp;
614
-	int i, j, bread, cnt;
613
+	unsigned short bits = 0,temp = 0;
614
+	unsigned long written = 0;
615
+	unsigned int i;
616
+	const char base64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
617
+
618
+
619
+    for(i = 0; i < len; i++) {
620
+	temp <<= 8;
621
+	temp += src[i];
622
+	bits += 8;
623
+	while(bits > 6) {
624
+	    dest[written] = base64[((temp >> (bits - 6)) & 63)];
625
+	    written++;
626
+	    bits -= 6;
627
+	}
628
+    }
629
+
630
+    if(bits) {
631
+	temp <<= (6 - bits);
632
+	dest[written] = base64[temp & 63];
633
+	written++;
634
+    }
635
+
636
+    while(written & 3) {
637
+	dest[written] = '=';
638
+	written++;
639
+    }
640
+
641
+    return written;
642
+}
643
+
644
+static char *proxyauth(const char *user, const char *pass)
645
+{
646
+	int len;
647
+	char *buf, *userpass, *auth;
648
+
649
+
650
+    userpass = mmalloc(strlen(user) + strlen(pass) + 2);
651
+    if(!userpass) {
652
+	logg("!proxyauth: Can't allocate memory for 'userpass'\n");
653
+	return NULL;
654
+    }
655
+    sprintf(userpass, "%s:%s", user, pass);
656
+
657
+    buf = mmalloc((strlen(pass) + strlen(user)) * 2 + 4);
658
+    if(!buf) {
659
+	logg("!proxyauth: Can't allocate memory for 'buf'\n");
660
+	free(userpass);
661
+	return NULL;
662
+    }
663
+
664
+    len = fmt_base64(buf, userpass, strlen(userpass));
665
+    free(userpass);
666
+    buf[len] = '\0';
667
+    auth = mmalloc(strlen(buf) + 30);
668
+    if(!auth) {
669
+	logg("!proxyauth: Can't allocate memory for 'authorization'\n");
670
+	return NULL;
671
+    }
672
+
673
+    sprintf(auth, "Proxy-Authorization: Basic %s\r\n", buf);
674
+    free(buf);
675
+
676
+    return auth;
677
+}
678
+
679
+static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int *ims)
680
+{
681
+	char cmd[512], head[513], buffer[FILEBUFF], ipaddr[16], *ch, *tmp;
682
+	int bread, cnt, sd;
683
+	unsigned int i, j;
615 684
 	char *remotename = NULL, *authorization = NULL;
616 685
 	const char *agent;
617 686
 	struct cl_cvd *cvd;
... ...
@@ -621,26 +297,24 @@ struct cl_cvd *remote_cvdhead(const char *file, int socketfd, const char *hostna
621 621
 
622 622
     if(proxy) {
623 623
         remotename = mmalloc(strlen(hostname) + 8);
624
+	if(!remotename) {
625
+	    logg("!remote_cvdhead: Can't allocate memory for 'remotename'\n");
626
+	    return NULL;
627
+	}
624 628
         sprintf(remotename, "http://%s", hostname);
625 629
 
626
-        if(user) {
627
-            int len;
628
-	    char *buf = mmalloc((strlen(pass) + strlen(user)) * 2 + 4);
629
-	    char *userpass = mmalloc(strlen(user) + strlen(pass) + 2);
630
-	    sprintf(userpass, "%s:%s", user, pass);
631
-            len=fmt_base64(buf,userpass,strlen(userpass));
632
-	    free(userpass);
633
-            buf[len]='\0';
634
-            authorization = mmalloc(strlen(buf) + 30);
635
-            sprintf(authorization, "Proxy-Authorization: Basic %s\r\n", buf);
636
-            free(buf);
637
-        }
630
+	if(user) {
631
+	    authorization = proxyauth(user, pass);
632
+	    if(!authorization)
633
+		return NULL;
634
+	}
638 635
     }
639 636
 
640 637
     if(stat(file, &sb) != -1 && sb.st_mtime < time(NULL)) {
641 638
 	Rfc2822DateTime(last_modified, sb.st_mtime);
642 639
     } else {
643 640
 	    time_t mtime = 1104119530;
641
+
644 642
 	Rfc2822DateTime(last_modified, mtime);
645 643
 	logg("*Assuming modification time in the past\n");
646 644
     }
... ...
@@ -654,49 +328,63 @@ struct cl_cvd *remote_cvdhead(const char *file, int socketfd, const char *hostna
654 654
     else
655 655
 	agent = PACKAGE"/"VERSION;
656 656
 
657
-#ifdef	NO_SNPRINTF
658
-    sprintf(cmd, "GET %s/%s HTTP/1.1\r\n"
659
-	"Host: %s\r\n%s"
660
-	"User-Agent: %s\r\n"
661
-	"Connection: close\r\n"
662
-	"Range: bytes=0-511\r\n"
663
-        "If-Modified-Since: %s\r\n"
664
-        "\r\n", (remotename != NULL)?remotename:"", file, hostname, (authorization != NULL)?authorization:"", agent, last_modified);
665
-#else
666
-    snprintf(cmd, sizeof(cmd), "GET %s/%s HTTP/1.1\r\n"
657
+    snprintf(cmd, sizeof(cmd),
658
+	"GET %s/%s HTTP/1.1\r\n"
667 659
 	"Host: %s\r\n%s"
668 660
 	"User-Agent: %s\r\n"
669 661
 	"Connection: close\r\n"
670 662
 	"Range: bytes=0-511\r\n"
671 663
         "If-Modified-Since: %s\r\n"
672
-        "\r\n", (remotename != NULL)?remotename:"", file, hostname, (authorization != NULL)?authorization:"", agent, last_modified);
673
-#endif
674
-    write(socketfd, cmd, strlen(cmd));
664
+        "\r\n", (remotename != NULL) ? remotename : "", file, hostname, (authorization != NULL) ? authorization : "", agent, last_modified);
675 665
 
676 666
     free(remotename);
677 667
     free(authorization);
678 668
 
669
+    memset(ipaddr, 0, sizeof(ipaddr));
670
+
671
+    if(ip[0]) /* use ip to connect */
672
+	sd = wwwconnect(ip, proxy, port, ipaddr, localip);
673
+    else
674
+	sd = wwwconnect(hostname, proxy, port, ipaddr, localip);
675
+
676
+    if(sd < 0) {
677
+	return NULL;
678
+    } else {
679
+	logg("*Connected to %s (IP: %s).\n", hostname, ipaddr);
680
+	logg("*Trying to retrieve CVD header of http://%s/%s\n", hostname, file);
681
+    }
682
+
683
+    if(!ip[0])
684
+	strcpy(ip, ipaddr);
685
+
686
+    if(write(sd, cmd, strlen(cmd)) < 0) {
687
+	logg("!remote_cvdhead: write failed\n");
688
+	close(sd);
689
+	return NULL;
690
+    }
691
+
679 692
     tmp = buffer;
680 693
     cnt = FILEBUFF;
681
-    while ((bread = recv(socketfd, tmp, cnt, 0)) > 0) {
682
-	tmp+=bread;
683
-	cnt-=bread;
684
-	if (cnt <= 0) break;
694
+    while((bread = recv(sd, tmp, cnt, 0)) > 0) {
695
+	tmp += bread;
696
+	cnt -= bread;
697
+	if(cnt <= 0)
698
+	    break;
685 699
     }
700
+    close(sd);
686 701
 
687 702
     if(bread == -1) {
688
-	logg("^Error while reading CVD header of database from %s\n", hostname);
703
+	logg("!remote_cvdhead: Error while reading CVD header from %s\n", hostname);
689 704
 	return NULL;
690 705
     }
691 706
 
692 707
     if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) { 
693
-	logg("^CVD file not found on remote server\n");
708
+	logg("!CVD file not found on remote server\n");
694 709
 	return NULL;
695 710
     }
696 711
 
697 712
     /* check whether the resource is up-to-date */
698 713
     if((strstr(buffer, "HTTP/1.1 304")) != NULL || (strstr(buffer, "HTTP/1.0 304")) != NULL) { 
699
-
700 714
 	*ims = 0;
701 715
 	logg("OK (IMS)\n");
702 716
 	return NULL;
... ...
@@ -707,75 +395,61 @@ struct cl_cvd *remote_cvdhead(const char *file, int socketfd, const char *hostna
707 707
     i = 3;
708 708
     ch = buffer + i;
709 709
     while(i < sizeof(buffer)) {
710
-      if (*ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') {
710
+	if (*ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') {
711
+	    ch++;
712
+	    i++;
713
+	    break;
714
+	}
711 715
 	ch++;
712 716
 	i++;
713
-	break;
714
-      }
715
-      ch++;
716
-      i++;
717 717
     }
718 718
 
719 719
     if(sizeof(buffer) - i < 512) {
720
-	mprintf("@Malformed CVD header detected.\n");
720
+	logg("!remote_cvdhead: Malformed CVD header (too short)\n");
721 721
 	return NULL;
722 722
     }
723 723
 
724 724
     memset(head, 0, sizeof(head));
725 725
 
726
-    for (j=0; j<512; j++) {
727
-      if (!ch || (ch && !*ch) || (ch && !isprint(ch[j]))) {
728
-	logg("^Malformed CVD header detected.\n");
729
-	return NULL;
730
-      }
731
-      head[j] = ch[j];
726
+    for(j = 0; j < 512; j++) {
727
+	if(!ch || (ch && !*ch) || (ch && !isprint(ch[j]))) {
728
+	    logg("!remote_cvdhead: Malformed CVD header (bad chars)\n");
729
+	    return NULL;
730
+	}
731
+	head[j] = ch[j];
732 732
     }
733 733
 
734
-    if((cvd = cl_cvdparse(head)) == NULL)
735
-	logg("^Broken CVD header.\n");
734
+    if(!(cvd = cl_cvdparse(head)))
735
+	logg("!Malformed CVD header (can't parser)\n");
736 736
     else
737 737
 	logg("OK\n");
738 738
 
739 739
     return cvd;
740 740
 }
741 741
 
742
-int get_database(const char *dbfile, int socketfd, const char *file, const char *hostname, const char *proxy, const char *user, const char *pass, const char *uas)
742
+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)
743 743
 {
744 744
 	char cmd[512], buffer[FILEBUFF], *ch;
745
-	int bread, fd, i, totalsize = 0,  rot = 0, totaldownloaded = 0, percentage;
746
-	char *remotename = NULL, *authorization = NULL;
747
-	const char *rotation = "|/-\\", *agent, *headerline;
745
+	int bread, fd, totalsize = 0,  rot = 0, totaldownloaded = 0,
746
+	    percentage = 0, sd;
747
+	unsigned int i;
748
+	char *remotename = NULL, *authorization = NULL, *headerline, ipaddr[16];
749
+	const char *rotation = "|/-\\", *agent;
748 750
 
749 751
 
750 752
     if(proxy) {
751 753
         remotename = mmalloc(strlen(hostname) + 8);
754
+	if(!remotename) {
755
+	    logg("!getfile: Can't allocate memory for 'remotename'\n");
756
+	    return 75; /* FIXME */
757
+	}
752 758
         sprintf(remotename, "http://%s", hostname);
753 759
 
754
-        if(user) {
755
-            int len;
756
-	    char *buf = mmalloc((strlen(pass) + strlen(user)) * 2 + 4);
757
-	    char *userpass = mmalloc(strlen(user) + strlen(pass) + 2);
758
-	    sprintf(userpass, "%s:%s", user, pass);
759
-            len=fmt_base64(buf,userpass,strlen(userpass));
760
-	    free(userpass);
761
-            buf[len]='\0';
762
-            authorization = mmalloc(strlen(buf) + 30);
763
-            sprintf(authorization, "Proxy-Authorization: Basic %s\r\n", buf);
764
-            free(buf);
765
-        }
766
-    }
767
-
768
-#if defined(C_CYGWIN) || defined(C_OS2)
769
-    if((fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) == -1) {
770
-#else
771
-    if((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0644)) == -1) {
772
-#endif
773
-	    char currdir[512];
774
-
775
-	getcwd(currdir, sizeof(currdir));
776
-	logg("^Can't create new file %s in %s\n", file, currdir);
777
-	logg("^The database directory must be writable for UID %d or GID %d\n", getuid(), getgid());
778
-	return 57;
760
+	if(user) {
761
+	    authorization = proxyauth(user, pass);
762
+	    if(!authorization)
763
+		return 75; /* FIXME */
764
+	}
779 765
     }
780 766
 
781 767
     if(uas)
... ...
@@ -783,111 +457,665 @@ int get_database(const char *dbfile, int socketfd, const char *file, const char
783 783
     else
784 784
 	agent = PACKAGE"/"VERSION;
785 785
 
786
-#ifdef NO_SNPRINTF
787
-    sprintf(cmd, "GET %s/%s HTTP/1.1\r\n"
788
-	     "Host: %s\r\n%s"
789
-	     "User-Agent: %s\r\n"
790
-	     "Cache-Control: no-cache\r\n"
791
-	     "Connection: close\r\n"
792
-	     "\r\n", (remotename != NULL)?remotename:"", dbfile, hostname, (authorization != NULL)?authorization:"", agent);
793
-#else
794
-    snprintf(cmd, sizeof(cmd), "GET %s/%s HTTP/1.1\r\n"
795
-	     "Host: %s\r\n%s"
796
-	     "User-Agent: %s\r\n"
797
-	     "Cache-Control: no-cache\r\n"
798
-	     "Connection: close\r\n"
799
-	     "\r\n", (remotename != NULL)?remotename:"", dbfile, hostname, (authorization != NULL)?authorization:"", agent);
800
-#endif
801
-    write(socketfd, cmd, strlen(cmd));
786
+    snprintf(cmd, sizeof(cmd),
787
+	"GET %s/%s HTTP/1.1\r\n"
788
+	"Host: %s\r\n%s"
789
+	"User-Agent: %s\r\n"
790
+	"Cache-Control: no-cache\r\n"
791
+	"Connection: close\r\n"
792
+	"\r\n", (remotename != NULL) ? remotename : "", srcfile, hostname, (authorization != NULL) ? authorization : "", agent);
802 793
 
803
-    free(remotename);
804
-    free(authorization);
794
+    memset(ipaddr, 0, sizeof(ipaddr));
795
+
796
+    if(ip[0]) /* use ip to connect */
797
+	sd = wwwconnect(ip, proxy, port, ipaddr, localip);
798
+    else
799
+	sd = wwwconnect(hostname, proxy, port, ipaddr, localip);
805 800
 
806
-    /* read all the http headers */
801
+    if(sd < 0) {
802
+	return 52;
803
+    } else {
804
+	logg("*Trying to download http://%s/%s (IP: %s)\n", hostname, srcfile, ipaddr);
805
+    }
806
+
807
+    if(!ip[0])
808
+	strcpy(ip, ipaddr);
809
+
810
+    if(write(sd, cmd, strlen(cmd)) < 0) {
811
+	logg("!getfile: Can't write to socket\n");
812
+	return 52;
813
+    }
807 814
 
815
+    if(remotename)
816
+	free(remotename);
817
+
818
+    if(authorization)
819
+	free(authorization);
820
+
821
+    /* read http headers */
808 822
     ch = buffer;
809 823
     i = 0;
810
-    while (1) {
811
-      /* recv one byte at a time, until we reach \r\n\r\n */
812
-
813
-      if((i >= sizeof(buffer)) || recv(socketfd, buffer + i, 1, 0) == -1) {
814
-        logg("^Error while reading database from %s\n", hostname);
815
-        close(fd);
816
-        unlink(file);
817
-        return 52;
818
-      }
824
+    while(1) {
825
+	/* recv one byte at a time, until we reach \r\n\r\n */
826
+	if((i >= sizeof(buffer) - 1) || recv(sd, buffer + i, 1, 0) == -1) {
827
+	    logg("!getfile: Error while reading database from %s\n", hostname);
828
+	    return 52;
829
+	}
819 830
 
820
-      if (i>2 && *ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') {
831
+	if(i > 2 && *ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') {
832
+	    i++;
833
+	    break;
834
+	}
835
+	ch++;
821 836
 	i++;
822
-	break;
823
-      }
824
-      ch++;
825
-      i++;
826 837
     }
827 838
 
828 839
     buffer[i] = 0;
829 840
 
830 841
     /* check whether the resource actually existed or not */
831
-
832 842
     if(strstr(buffer, "HTTP/1.1 404")) { 
833
-      logg("^%s not found on remote server\n", dbfile);
834
-      close(fd);
835
-      unlink(file);
836
-      return 58;
843
+	logg("!getfile: %s not found on remote server\n", srcfile);
844
+	close(sd);
845
+	return 58;
837 846
     }
838 847
 
839 848
     /* get size of resource */
840 849
     for(i = 0; (headerline = cli_strtok(buffer, i, "\n")); i++){
841 850
         if(strstr(headerline, "Content-Length:")) { 
842
-            totalsize = atoi(cli_strtok(headerline, 1, ": "));
851
+	    if((ch = cli_strtok(headerline, 1, ": "))) {
852
+		totalsize = atoi(ch);
853
+		free(ch);
854
+	    } else {
855
+		totalsize = 0;
856
+	    }
843 857
         }
858
+	free(headerline);
859
+    }
860
+
861
+    if((fd = open(destfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) == -1) {
862
+	    char currdir[512];
863
+
864
+	getcwd(currdir, sizeof(currdir));
865
+	logg("!getfile: Can't create new file %s in %s\n", destfile, currdir);
866
+	logg("Hint: The database directory must be writable for UID %d or GID %d\n", getuid(), getgid());
867
+	close(sd);
868
+	return 57;
844 869
     }
845 870
 
846
-    /* receive body and write it to disk */
871
+    while((bread = read(sd, buffer, FILEBUFF))) {
872
+        if(write(fd, buffer, bread) != bread) {
873
+	    logg("getfile: Can't write %d bytes to %s\n", bread, destfile);
874
+	    unlink(destfile);
875
+	    close(fd);
876
+	    close(sd);
877
+	    return 57; /* FIXME */
878
+	}
847 879
 
848
-    while((bread = read(socketfd, buffer, FILEBUFF))) {
849
-        write(fd, buffer, bread);
850 880
         if(!mprintf_quiet) {
851 881
             if(totalsize > 0) {
852
-                totaldownloaded = totaldownloaded + bread;
853
-                percentage = (int)(100 * (float)totaldownloaded/totalsize);
854
-                mprintf("Downloading %s [%3i%%]\r", dbfile, percentage);
882
+                totaldownloaded += bread;
883
+                percentage = (int) (100 * (float) totaldownloaded / totalsize);
884
+                mprintf("Downloading %s [%3i%%]\r", srcfile, percentage);
855 885
             } else {
856
-                mprintf("Downloading %s [%c]\r", dbfile, rotation[rot]);
886
+                mprintf("Downloading %s [%c]\r", srcfile, rotation[rot]);
857 887
                 rot++;
858 888
                 rot %= 4;
859 889
             }
860 890
             fflush(stdout);
861 891
         }
862 892
     }
893
+    close(sd);
894
+    close(fd);
863 895
 
864 896
     if(totalsize > 0)
865
-        logg("Downloading %s [%i%]\n", dbfile, percentage);
897
+        logg("Downloading %s [%i%]\n", srcfile, percentage);
866 898
     else
867
-        logg("Downloading %s [*]\n", dbfile);
899
+        logg("Downloading %s [*]\n", srcfile);
900
+
901
+    return 0;
902
+}
903
+
904
+static int getcvd(const char *dbfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int nodb, int newver)
905
+{
906
+	char *tempname;
907
+	struct cl_cvd *cvd;
908
+	int ret;
909
+
910
+
911
+    tempname = cli_gentemp(".");
912
+
913
+    logg("*Retrieving http://%s/%s\n", hostname, dbfile);
914
+    if((ret = getfile(dbfile, tempname, hostname, ip, localip, proxy, port, user, pass, uas))) {
915
+        logg("!Can't download %s from %s (IP: %s)\n", dbfile, hostname, ip);
916
+        unlink(tempname);
917
+        free(tempname);
918
+        return ret;
919
+    }
920
+
921
+    if((ret = cl_cvdverify(tempname))) {
922
+        logg("!Verification: %s\n", cl_strerror(ret));
923
+        unlink(tempname);
924
+        free(tempname);
925
+        return 54;
926
+    }
927
+
928
+    if(!(cvd = cl_cvdhead(tempname))) {
929
+	logg("!Can't read CVD header of new %s database.\n", dbfile);
930
+	unlink(tempname);
931
+	free(tempname);
932
+	return 54;
933
+    }
934
+
935
+    if(cvd->version < newver) {
936
+	logg("!Mirrors are not fully synchronized. Please try again later.\n");
937
+    	cl_cvdfree(cvd);
938
+	unlink(tempname);
939
+	free(tempname);
940
+	return 59;
941
+    }
942
+
943
+    if(!nodb && unlink(dbfile)) {
944
+	logg("!Can't unlink %s. Please fix it and try again.\n", dbfile);
945
+    	cl_cvdfree(cvd);
946
+	unlink(tempname);
947
+	free(tempname);
948
+	return 53;
949
+    } else {
950
+    	if(rename(tempname, dbfile) == -1) {
951
+    	    if(errno == EEXIST) {
952
+    	        unlink(dbfile);
953
+    	        if(rename(tempname, dbfile) == -1) {
954
+                   logg("!All attempts to rename the temporary file failed: %s\n", strerror(errno));
955
+		   return 57;
956
+		}
957
+            }
958
+        }
959
+    }
868 960
 
869
-    close(fd);
870 961
     return 0;
871 962
 }
872 963
 
873
-const char base64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
874
-
875
-unsigned int fmt_base64(char* dest,const char* src,unsigned int len) {
876
-    register const unsigned char* s=(const unsigned char*) src;
877
-    unsigned short bits=0,temp=0;
878
-    unsigned long written=0,i;
879
-    for (i=0; i< len; ++i) {
880
-	temp<<=8; temp+=s[i]; bits+=8;
881
-	while (bits>6) {
882
-	    if (dest) dest[written]=base64[((temp>>(bits-6))&63)];
883
-	    ++written; bits-=6;
964
+static int chdir_inc(const char *dbname)
965
+{
966
+	struct stat sb;
967
+	char path[32], dbfile[32];
968
+
969
+
970
+    sprintf(path, "%s.inc", dbname);
971
+    sprintf(dbfile, "%s.cvd", dbname);
972
+
973
+    if(stat(path, &sb) == -1) {
974
+	if(mkdir(path, 0755) == -1) {
975
+	    logg("!chdir_inc: Can't create directory %s\n", path);
976
+	    return -1;
977
+	}
978
+
979
+	if(cvd_unpack(dbfile, path) == -1) {
980
+	    logg("!chdir_inc: Can't unpack %s into %s\n", path);
981
+	    rmdirs(path);
982
+	    return -1;
884 983
 	}
885 984
     }
886
-    if (bits) {
887
-	temp<<=(6-bits);
888
-	if (dest) dest[written]=base64[temp&63];
889
-	++written;
985
+
986
+    if(chdir(path) == -1) {
987
+	logg("!chdir_inc: Can't change directory to %s\n", path);
988
+	return -1;
890 989
     }
891
-    while (written&3) { if (dest) dest[written]='='; ++written; }
892
-    return written;
990
+
991
+    return 0;
992
+}
993
+
994
+static int getpatch(const char *dbname, int version, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas)
995
+{
996
+	char *tempname, patch[32], olddir[512];
997
+	int ret, fd;
998
+
999
+
1000
+    if(!getcwd(olddir, sizeof(olddir))) {
1001
+	logg("!getpatch: Can't get path of current working directory\n");
1002
+	return 50; /* FIXME */
1003
+    }
1004
+
1005
+    if(chdir_inc(dbname) == -1)
1006
+	return 50;
1007
+
1008
+    tempname = cli_gentemp(".");
1009
+    snprintf(patch, sizeof(patch), "%s-%d.cdiff", dbname, version);
1010
+
1011
+    logg("*Retrieving http://%s/%s\n", hostname, patch);
1012
+    if((ret = getfile(patch, tempname, hostname, ip, localip, proxy, port, user, pass, uas))) {
1013
+        logg("!getpatch: Can't download %s from %s (IP: %s)\n", patch, hostname, ip);
1014
+        unlink(tempname);
1015
+        free(tempname);
1016
+	chdir(olddir);
1017
+        return ret;
1018
+    }
1019
+
1020
+    if((fd = open(tempname, O_RDONLY)) == -1) {
1021
+	logg("!getpatch: Can't open %s for reading\n", tempname);
1022
+        unlink(tempname);
1023
+        free(tempname);
1024
+	chdir(olddir);
1025
+	return 55;
1026
+    }
1027
+
1028
+    if(cdiff_apply(fd) == -1) {
1029
+	logg("!getpatch: Can't apply patch\n");
1030
+        unlink(tempname);
1031
+        free(tempname);
1032
+	chdir(olddir);
1033
+	return 70; /* FIXME */
1034
+    }
1035
+
1036
+    chdir(olddir);
1037
+    return 0;
1038
+}
1039
+
1040
+static struct cl_cvd *currentdb(const char *dbname)
1041
+{
1042
+	struct stat sb;
1043
+	char path[512];
1044
+	struct cl_cvd *cvd;
1045
+	short inc = 0;
1046
+
1047
+
1048
+    snprintf(path, sizeof(path), "%s.inc", dbname);
1049
+    if(stat(path, &sb) != -1) {
1050
+	snprintf(path, sizeof(path), "%s.inc/%s.info", dbname, dbname);
1051
+	inc = 1;
1052
+    } else
1053
+	snprintf(path, sizeof(path), "%s.cvd", dbname);
1054
+
1055
+    cvd = cl_cvdhead(path);
1056
+
1057
+    return cvd;
1058
+}
1059
+
1060
+int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, const struct cfgstruct *copt, const char *dnsreply, char *localip, int outdated)
1061
+{
1062
+	struct cl_cvd *current, *remote;
1063
+	struct cfgstruct *cpt;
1064
+	int nodb = 0, currver, newver = -1, ret, port = 0, ims = -1, i;
1065
+	char *pt, dbfile[32], dbinc[32];
1066
+	const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL;
1067
+	int flevel = cl_retflevel();
1068
+	struct stat sb;
1069
+
1070
+
1071
+    snprintf(dbfile, sizeof(dbfile), "%s.cvd", dbname);
1072
+    snprintf(dbinc, sizeof(dbinc), "%s.inc", dbname);
1073
+
1074
+    if(!(current = currentdb(dbname))) {
1075
+	nodb = 1;
1076
+	if(stat(dbinc, &sb) != -1) {
1077
+	    logg("^Removing corrupted incremental directory %s\n", dbinc);
1078
+	    if(rmdirs(dbinc)) {
1079
+		logg("!Can't remove incremental directory\n");
1080
+		return 53;
1081
+	    }
1082
+
1083
+	    if(stat(dbfile, &sb) != -1) {
1084
+		logg("^Removing obsolete %s\n", dbfile);
1085
+		if(unlink(dbfile)) {
1086
+		    logg("!Can't unlink %s\n", dbfile);
1087
+		    return 53;
1088
+		}
1089
+	    }
1090
+	}
1091
+    }
1092
+
1093
+    if(!nodb && dnsreply) {
1094
+	    int field = 0;
1095
+
1096
+	if(!strcmp(dbname, "main")) {
1097
+	    field = 1;
1098
+	} else if(!strcmp(dbname, "daily")) {
1099
+	    field = 2;
1100
+	} else {
1101
+	    logg("!updatedb: Unknown database name (%s) passed.\n", dbname);
1102
+	    cl_cvdfree(current);
1103
+	    return 70;
1104
+	}
1105
+
1106
+	if(field && (pt = cli_strtok(dnsreply, field, ":"))) {
1107
+	    if(!isnumb(pt)) {
1108
+		logg("^Broken database version in TXT record.\n");
1109
+	    } else {
1110
+		newver = atoi(pt);
1111
+		logg("*%s version from DNS: %d\n", dbfile, newver);
1112
+	    }
1113
+	    free(pt);
1114
+	} else {
1115
+	    logg("^Invalid DNS reply. Falling back to HTTP mode.\n");
1116
+	}
1117
+    }
1118
+
1119
+    /* Initialize proxy settings */
1120
+    if((cpt = cfgopt(copt, "HTTPProxyServer"))->enabled) {
1121
+	proxy = cpt->strarg;
1122
+	if(strncasecmp(proxy, "http://", 7) == 0)
1123
+	    proxy += 7;
1124
+
1125
+	if((cpt = cfgopt(copt, "HTTPProxyUsername"))->enabled) {
1126
+	    user = cpt->strarg;
1127
+	    if((cpt = cfgopt(copt, "HTTPProxyPassword"))->enabled) {
1128
+		pass = cpt->strarg;
1129
+	    } else {
1130
+		logg("HTTPProxyUsername requires HTTPProxyPassword\n");
1131
+		if(current)
1132
+		    cl_cvdfree(current);
1133
+		return 56;
1134
+	    }
1135
+	}
1136
+
1137
+	if((cpt = cfgopt(copt, "HTTPProxyPort"))->enabled)
1138
+	    port = cpt->numarg;
1139
+
1140
+	logg("Connecting via %s\n", proxy);
1141
+    }
1142
+
1143
+    if((cpt = cfgopt(copt, "HTTPUserAgent"))->enabled)
1144
+	uas = cpt->strarg;
1145
+
1146
+
1147
+    if(!nodb && newver == -1) {
1148
+
1149
+	remote = remote_cvdhead(dbfile, hostname, ip, localip, proxy, port, user, pass, uas, &ims);
1150
+
1151
+	if(!nodb && !ims) {
1152
+	    logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", dbfile, current->version, current->sigs, current->fl, current->builder);
1153
+	    *signo += current->sigs;
1154
+	    cl_cvdfree(current);
1155
+	    return 1;
1156
+	}
1157
+
1158
+	if(!remote) {
1159
+	    logg("^Can't read %s header from %s (IP: %s)\n", dbfile, hostname, ip);
1160
+	    cl_cvdfree(current);
1161
+	    return 58;
1162
+	}
1163
+
1164
+	newver = remote->version;
1165
+	cl_cvdfree(remote);
1166
+    }
1167
+
1168
+    if(!nodb && (current->version >= newver)) {
1169
+	logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", dbfile, current->version, current->sigs, current->fl, current->builder);
1170
+
1171
+	if(!outdated && flevel < current->fl) {
1172
+	    /* display warning even for already installed database */
1173
+	    logg("^Current functionality level = %d, recommended = %d\n", flevel, current->fl);
1174
+	    logg("Please check if ClamAV tools are linked against proper version of libclamav\n");
1175
+	    logg("DON'T PANIC! Read http://www.clamav.net/faq.html\n");
1176
+	}
1177
+
1178
+	*signo += current->sigs;
1179
+	cl_cvdfree(current);
1180
+	return 1;
1181
+    }
1182
+
1183
+    currver = current->version;
1184
+
1185
+    if(current)
1186
+	cl_cvdfree(current);
1187
+
1188
+    /*
1189
+    if(ipaddr[0]) {
1190
+	hostfd = wwwconnect(ipaddr, proxy, port, NULL, localip);
1191
+    } else {
1192
+	hostfd = wwwconnect(hostname, proxy, port, ipaddr, localip);
1193
+	if(!ip[0])
1194
+	    strcpy(ip, ipaddr);
1195
+    }
1196
+
1197
+    if(hostfd < 0) {
1198
+	if(ipaddr[0])
1199
+	    logg("Connection with %s (IP: %s) failed.\n", hostname, ipaddr);
1200
+	else
1201
+	    logg("Connection with %s failed.\n", hostname);
1202
+	return 52;
1203
+    };
1204
+    */
1205
+
1206
+    if(nodb) {
1207
+	ret = getcvd(dbfile, hostname, ip, localip, proxy, port, user, pass, uas, nodb, newver);
1208
+	if(ret)
1209
+	    return ret;
1210
+
1211
+    } else {
1212
+	ret = 0;
1213
+
1214
+	for(i = currver + 1; i <= newver; i++) {
1215
+	    ret = getpatch(dbname, i, hostname, ip, localip, proxy, port, user, pass, uas);
1216
+	    if(ret) {
1217
+		logg("^Removing incremental directory %s\n", dbinc);
1218
+		rmdirs(dbinc);
1219
+		break;
1220
+	    }
1221
+	}
1222
+
1223
+	if(ret) {
1224
+	    logg("^Incremental update failed, downloading complete database\n");
1225
+
1226
+	    ret = getcvd(dbfile, hostname, ip, localip, proxy, port, user, pass, uas, nodb, newver);
1227
+	    if(ret)
1228
+		return ret;
1229
+	}
1230
+    }
1231
+
1232
+    if(!(current = currentdb(dbname))) {
1233
+	/* should never be reached */
1234
+	logg("!Can't parse new database\n");
1235
+	return 55; /* FIXME */
1236
+    }
1237
+
1238
+    logg("%s updated (version: %d, sigs: %d, f-level: %d, builder: %s)\n", dbfile, current->version, current->sigs, current->fl, current->builder);
1239
+
1240
+    if(flevel < current->fl) {
1241
+	logg("^Your ClamAV installation is OUTDATED!\n");
1242
+	logg("^Current functionality level = %d, recommended = %d\n", flevel, current->fl);
1243
+	logg("DON'T PANIC! Read http://www.clamav.net/faq.html\n");
1244
+    }
1245
+
1246
+    *signo += current->sigs;
1247
+    cl_cvdfree(current);
1248
+    return 0;
893 1249
 }
1250
+
1251
+int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, const char *hostname)
1252
+{
1253
+	time_t currtime;
1254
+	int ret, updated = 0, outdated = 0, signo = 0;
1255
+	unsigned int ttl;
1256
+	char ipaddr[16], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
1257
+	const char *arg = NULL;
1258
+	struct cfgstruct *cpt;
1259
+#ifdef HAVE_RESOLV_H
1260
+	const char *dnsdbinfo;
1261
+#endif
1262
+
1263
+    time(&currtime);
1264
+    logg("ClamAV update process started at %s", ctime(&currtime));
1265
+
1266
+#ifndef HAVE_GMP
1267
+    logg("SECURITY WARNING: NO SUPPORT FOR DIGITAL SIGNATURES\n");
1268
+    logg("See the FAQ at http://www.clamav.net/faq.html for an explanation.\n");
1269
+#endif
1270
+
1271
+#ifdef HAVE_RESOLV_H
1272
+    dnsdbinfo = cfgopt(copt, "DNSDatabaseInfo")->strarg;
1273
+
1274
+    if(opt_check(opt, "no-dns")) {
1275
+	dnsreply = NULL;
1276
+    } else {
1277
+	if((dnsreply = txtquery(dnsdbinfo, &ttl))) {
1278
+	    logg("*TTL: %d\n", ttl);
1279
+
1280
+	    if((pt = cli_strtok(dnsreply, 3, ":"))) {
1281
+		    int rt;
1282
+		    time_t ct;
1283
+
1284
+		rt = atoi(pt);
1285
+		free(pt);
1286
+		time(&ct);
1287
+		if((int) ct - rt > 10800) {
1288
+		    logg("^DNS record is older than 3 hours.\n");
1289
+		    free(dnsreply);
1290
+		    dnsreply = NULL;
1291
+		}
1292
+
1293
+	    } else {
1294
+		free(dnsreply);
1295
+		dnsreply = NULL;
1296
+	    }
1297
+
1298
+	    if(dnsreply) {
1299
+		    int vwarning = 1;
1300
+
1301
+		if((pt = cli_strtok(dnsreply, 4, ":"))) {
1302
+		    if(*pt == '0')
1303
+			vwarning = 0;
1304
+
1305
+		    free(pt);
1306
+		}
1307
+
1308
+		if((newver = cli_strtok(dnsreply, 0, ":"))) {
1309
+
1310
+		    logg("*Software version from DNS: %s\n", newver);
1311
+
1312
+		    if(vwarning && !strstr(cl_retver(), "devel") && !strstr(cl_retver(), "rc")) {
1313
+			if(strcmp(cl_retver(), newver)) {
1314
+			    logg("^Your ClamAV installation is OUTDATED!\n");
1315
+			    logg("^Local version: %s Recommended version: %s\n", cl_retver(), pt);
1316
+			    logg("DON'T PANIC! Read http://www.clamav.net/faq.html\n");
1317
+			    outdated = 1;
1318
+			}
1319
+		    }
1320
+		}
1321
+
1322
+	    } else {
1323
+		if(dnsreply) {
1324
+		    free(dnsreply);
1325
+		    dnsreply = NULL;
1326
+		}
1327
+	    }
1328
+	}
1329
+
1330
+	if(!dnsreply) {
1331
+	    logg("^Invalid DNS reply. Falling back to HTTP mode.\n");
1332
+	}
1333
+    }
1334
+#endif /* HAVE_RESOLV_H */
1335
+
1336
+    if(opt_check(opt, "local-address")) {
1337
+        localip = opt_arg(opt, "local-address");
1338
+    } else if((cpt = cfgopt(copt, "LocalIPAddress"))->enabled) {
1339
+	localip = cpt->strarg;
1340
+    }
1341
+
1342
+    memset(ipaddr, 0, sizeof(ipaddr));
1343
+
1344
+    if((ret = updatedb("main", hostname, ipaddr, &signo, copt, dnsreply, localip, outdated)) > 50) {
1345
+	if(dnsreply)
1346
+	    free(dnsreply);
1347
+
1348
+	if(newver)
1349
+	    free(newver);
1350
+
1351
+	return ret;
1352
+
1353
+    } else if(ret == 0)
1354
+	updated = 1;
1355
+
1356
+    /* if ipaddr[0] != 0 it will use it to connect to the web host */
1357
+    if((ret = updatedb("daily", hostname, ipaddr, &signo, copt, dnsreply, localip, outdated)) > 50) {
1358
+	if(dnsreply)
1359
+	    free(dnsreply);
1360
+
1361
+	if(newver)
1362
+	    free(newver);
1363
+
1364
+	return ret;
1365
+
1366
+    } else if(ret == 0)
1367
+	updated = 1;
1368
+
1369
+    if(dnsreply)
1370
+	free(dnsreply);
1371
+
1372
+    if(updated) {
1373
+	if(cfgopt(copt, "HTTPProxyServer")->enabled) {
1374
+	    logg("Database updated (%d signatures) from %s\n", signo, hostname);
1375
+	} else {
1376
+	    logg("Database updated (%d signatures) from %s (IP: %s)\n", signo, hostname, ipaddr);
1377
+	}
1378
+
1379
+#ifdef BUILD_CLAMD
1380
+	if(opt_check(opt, "daemon-notify")) {
1381
+		const char *clamav_conf = opt_arg(opt, "daemon-notify");
1382
+	    if(!clamav_conf)
1383
+		clamav_conf = CONFDIR"/clamd.conf";
1384
+
1385
+	    notify(clamav_conf);
1386
+	} else if((cpt = cfgopt(copt, "NotifyClamd"))->enabled) {
1387
+	    notify(cpt->strarg);
1388
+	}
1389
+#endif
1390
+
1391
+	if(opt_check(opt, "on-update-execute"))
1392
+	    arg = opt_arg(opt, "on-update-execute");
1393
+	else if((cpt = cfgopt(copt, "OnUpdateExecute"))->enabled)
1394
+	    arg = cpt->strarg;
1395
+
1396
+	if(arg) {
1397
+	    if(opt_check(opt, "daemon"))
1398
+		execute("OnUpdateExecute", arg);
1399
+            else
1400
+		system(arg);
1401
+	}
1402
+    }
1403
+
1404
+    if(outdated) {
1405
+	if(opt_check(opt, "on-outdated-execute"))
1406
+	    arg = opt_arg(opt, "on-outdated-execute");
1407
+	else if((cpt = cfgopt(copt, "OnOutdatedExecute"))->enabled)
1408
+	    arg = cpt->strarg;
1409
+
1410
+	if(arg) {
1411
+		char *cmd = strdup(arg);
1412
+
1413
+	    if((pt = strstr(cmd, "%v")) && newver && isdigit(*newver)) {
1414
+		    char *buffer = (char *) mcalloc(strlen(cmd) + strlen(newver) + 10, sizeof(char));
1415
+
1416
+		if(!buffer) {
1417
+		    logg("!downloadmanager: Can't allocate memory for buffer\n");
1418
+		    free(cmd);
1419
+		    if(newver)
1420
+			free(newver);
1421
+		    return 0;
1422
+		}
1423
+
1424
+		*pt = 0; pt += 2;
1425
+		strcpy(buffer, cmd);
1426
+		strcat(buffer, newver);
1427
+		strcat(buffer, pt);
1428
+		free(cmd);
1429
+		cmd = strdup(buffer);
1430
+		free(buffer);
1431
+	    }
1432
+
1433
+	    if(opt_check(opt, "daemon"))
1434
+		execute("OnOutdatedExecute", cmd);
1435
+	    else
1436
+		system(cmd);
1437
+
1438
+	    free(cmd);
1439
+	}
1440
+    }
1441
+
1442
+    if(newver)
1443
+	free(newver);
1444
+
1445
+    return updated ? 0 : 1;
1446
+}
1447
+
... ...
@@ -20,19 +20,9 @@
20 20
 #ifndef __MANAGER_H
21 21
 #define __MANAGER_H
22 22
 
23
-#include "cfgparser.h"
24
-#include "clamav.h"
23
+#include "shared/cfgparser.h"
24
+#include "shared/options.h"
25 25
 
26 26
 int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, const char *hostname);
27 27
 
28
-int downloaddb(const char *localname, const char *remotename, const char *hostname, char *ip, int *signo, const struct cfgstruct *copt, const char *dnsreply, char *localip, int outdated);
29
-
30
-int wwwconnect(const char *server, const char *proxy, int pport, char *remoteip, char *localip);
31
-
32
-struct cl_cvd *remote_cvdhead(const char *file, int socketfd, const char *hostname, const char *proxy, const char *user, const char *pass, const char *uas, int *ims);
33
-
34
-int get_database(const char *dbfile, int socketfd, const char *file, const char *hostname, const char *proxy, const char *user, const char *pass, const char *uas);
35
-
36
-unsigned int fmt_base64(char* dest,const char* src,unsigned int len);
37
-
38 28
 #endif