~yolanda.robla/ubuntu/saucy/clamav/dep-8-tests

« back to all changes in this revision

Viewing changes to freshclam/manager.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Gran
  • Date: 2008-09-05 17:25:34 UTC
  • mfrom: (0.35.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080905172534-yi3f8fkye1o7u1r3
* New upstream version (closes: #497662, #497773)
  - lots of new options for clamd.conf
  - fixes CVEs CVE-2008-3912, CVE-2008-3913, CVE-2008-3914, and
    CVE-2008-1389
* No longer supports --unzip option, so typo is gone (closes: #496276)
* Translations:
  - sv (thanks Martin Bagge <brother@bsnet.se>) (closes: #491760)

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
 
33
33
#include <stdio.h>
34
34
#include <stdlib.h>
35
 
#ifdef  HAVE_UNISTD_H
 
35
#ifdef HAVE_UNISTD_H
36
36
#include <unistd.h>
37
37
#endif
38
38
#include <string.h>
39
39
#include <ctype.h>
40
 
#ifndef C_WINDOWS
 
40
#ifndef C_WINDOWS
41
41
#include <netinet/in.h>
42
42
#include <netdb.h>
 
43
#include <arpa/inet.h>
43
44
#endif
44
45
#include <sys/types.h>
45
 
#ifndef C_WINDOWS
 
46
#ifndef C_WINDOWS
46
47
#include <sys/socket.h>
47
48
#include <sys/time.h>
48
49
#endif
49
50
#include <time.h>
50
51
#include <fcntl.h>
51
52
#include <sys/stat.h>
 
53
#ifndef C_WINDOWS
52
54
#include <dirent.h>
 
55
#endif
53
56
#include <errno.h>
54
57
#include <zlib.h>
55
58
 
 
59
#include "target.h"
 
60
 
56
61
#include "manager.h"
57
62
#include "notify.h"
58
63
#include "dns.h"
76
81
#define O_BINARY        0
77
82
#endif
78
83
 
79
 
#ifndef C_WINDOWS
 
84
#ifndef C_WINDOWS
80
85
#define closesocket(s)  close(s)
81
86
#endif
82
87
 
83
 
static int getclientsock(const char *localip)
 
88
#define CHDIR_ERR(x)                            \
 
89
        if(chdir(x) == -1)                      \
 
90
            logg("!Can't chdir to %s\n", x);
 
91
 
 
92
#ifndef SUPPORT_IPv6
 
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)
84
115
{
85
116
        int socketfd = -1;
86
117
 
87
 
#ifdef PF_INET
 
118
#ifdef SUPPORT_IPv6
 
119
    if(prot == PF_INET6)
 
120
        socketfd = socket(PF_INET6, SOCK_STREAM, 0);
 
121
    else
 
122
        socketfd = socket(PF_INET, SOCK_STREAM, 0);
 
123
#else
88
124
    socketfd = socket(PF_INET, SOCK_STREAM, 0);
89
 
#else
90
 
    socketfd = socket(AF_INET, SOCK_STREAM, 0);
91
125
#endif
92
126
 
93
127
    if(socketfd < 0) {
96
130
    }
97
131
 
98
132
    if(localip) {
99
 
        struct hostent *he;
100
 
 
101
 
        if((he = gethostbyname(localip)) == NULL) {
102
 
            const char *herr;
103
 
            switch(h_errno) {
104
 
                case HOST_NOT_FOUND:
105
 
                    herr = "Host not found";
106
 
                    break;
107
 
 
108
 
                case NO_DATA:
109
 
                    herr = "No IP address";
110
 
                    break;
111
 
 
112
 
                case NO_RECOVERY:
113
 
                    herr = "Unrecoverable DNS error";
114
 
                    break;
115
 
 
116
 
                case TRY_AGAIN:
117
 
                    herr = "Temporary DNS error";
118
 
                    break;
119
 
 
120
 
                default:
121
 
                    herr = "Unknown error";
122
 
                    break;
 
133
#ifdef SUPPORT_IPv6
 
134
            struct addrinfo *res;
 
135
            int ret;
 
136
 
 
137
        ret = getaddrinfo(localip, NULL, NULL, &res);
 
138
        if(ret) {
 
139
            logg("!Could not resolve local ip address '%s': %s\n", localip, gai_strerror(ret));
 
140
            logg("^Using standard local ip address and port for fetching.\n");
 
141
        } else {
 
142
                char ipaddr[46];
 
143
 
 
144
            if(bind(socketfd, res->ai_addr, res->ai_addrlen) != 0) {
 
145
                logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
 
146
                logg("^Using default client ip.\n");
 
147
            } else {
 
148
                    void *addr;
 
149
 
 
150
                if(res->ai_family == AF_INET6)
 
151
                    addr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
 
152
                else
 
153
                    addr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
 
154
 
 
155
                if(inet_ntop(res->ai_family, addr, ipaddr, sizeof(ipaddr)))
 
156
                    logg("*Using ip '%s' for fetching.\n", ipaddr);
123
157
            }
124
 
            logg("!Could not resolve local ip address '%s': %s\n", localip, herr);
 
158
            freeaddrinfo(res);
 
159
        }
 
160
 
 
161
#else /* IPv4 */
 
162
            struct hostent *he;
 
163
 
 
164
        if(!(he = gethostbyname(localip))) {
 
165
            logg("!Could not resolve local ip address '%s': %s\n", localip, ghbn_err(h_errno));
125
166
            logg("^Using standard local ip address and port for fetching.\n");
126
167
        } else {
127
 
            struct sockaddr_in client;
128
 
            unsigned char *ia;
129
 
            char ipaddr[16];
 
168
                struct sockaddr_in client;
 
169
                unsigned char *ia;
 
170
                char ipaddr[16];
130
171
 
131
 
            memset ((char *) &client, 0, sizeof(struct sockaddr_in));
 
172
            memset((char *) &client, 0, sizeof(client));
132
173
            client.sin_family = AF_INET;
133
174
            client.sin_addr = *(struct in_addr *) he->h_addr_list[0];
134
 
            if (bind(socketfd, (struct sockaddr *) &client, sizeof(struct sockaddr_in)) != 0) {
 
175
            if(bind(socketfd, (struct sockaddr *) &client, sizeof(struct sockaddr_in)) != 0) {
135
176
                logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
136
177
                logg("^Using default client ip.\n");
137
178
            } else {
140
181
                logg("*Using ip '%s' for fetching.\n", ipaddr);
141
182
            }
142
183
        }
 
184
#endif
143
185
    }
144
186
 
145
187
    return socketfd;
146
188
}
147
189
 
148
 
static int wwwconnect(const char *server, const char *proxy, int pport, char *ip, const char *localip, int ctimeout, struct mirdat *mdat, int logerr)
 
190
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)
149
191
{
150
 
        int socketfd = -1, port, i, ret;
 
192
        int socketfd, port, ret;
 
193
        unsigned int ips = 0, ignored = 0;
 
194
#ifdef SUPPORT_IPv6
 
195
        struct addrinfo hints, *res = NULL, *rp, *loadbal_rp = NULL;
 
196
        char port_s[6], loadbal_ipaddr[46];
 
197
        uint32_t loadbal = 1, minsucc = 0xffffffff, minfail = 0xffffffff;
 
198
        struct mirdat_ip *md;
 
199
#else
151
200
        struct sockaddr_in name;
152
201
        struct hostent *host;
153
 
        char ipaddr[16];
154
202
        unsigned char *ia;
 
203
        int i;
 
204
#endif
 
205
        char ipaddr[46];
155
206
        const char *hostpt;
156
207
 
157
208
    if(ip)
158
209
        strcpy(ip, "???");
159
210
 
160
 
    socketfd = getclientsock(localip);
161
 
    if(socketfd < 0)
162
 
        return -1;
163
 
 
164
 
    name.sin_family = AF_INET;
165
 
 
166
211
    if(proxy) {
167
212
        hostpt = proxy;
168
213
 
169
214
        if(!(port = pport)) {
170
 
#ifndef C_CYGWIN
171
215
                const struct servent *webcache = getservbyname("webcache", "TCP");
172
216
 
173
217
                if(webcache)
178
222
#ifndef C_WINDOWS
179
223
                endservent();
180
224
#endif
181
 
#else
182
 
                port = 8080;
183
 
#endif
184
225
        }
185
226
 
186
227
    } else {
188
229
        port = 80;
189
230
    }
190
231
 
 
232
#ifdef SUPPORT_IPv6
 
233
    memset(&hints, 0, sizeof(hints));
 
234
    hints.ai_family = AF_UNSPEC;
 
235
    hints.ai_socktype = SOCK_STREAM;
 
236
    snprintf(port_s, sizeof(port_s), "%d", port);
 
237
    port_s[sizeof(port_s) - 1] = 0;
 
238
    ret = getaddrinfo(hostpt, port_s, &hints, &res);
 
239
    if(ret) {
 
240
        logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, gai_strerror(ret));
 
241
        return -1;
 
242
    }
 
243
 
 
244
    for(rp = res; rp; rp = rp->ai_next) {
 
245
            void *addr;
 
246
 
 
247
        ips++;
 
248
        if(rp->ai_family == AF_INET6)
 
249
            addr = &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr;
 
250
        else
 
251
            addr = &((struct sockaddr_in *) rp->ai_addr)->sin_addr;
 
252
 
 
253
        if(!inet_ntop(rp->ai_family, addr, ipaddr, sizeof(ipaddr))) {
 
254
            logg("%cinet_ntop() failed\n", logerr ? '!' : '^');
 
255
            freeaddrinfo(res);
 
256
            return -1;
 
257
        }
 
258
 
 
259
        if((ret = mirman_check(addr, rp->ai_family, mdat, &md))) {
 
260
            if(ret == 1)
 
261
                logg("Ignoring mirror %s (due to previous errors)\n", ipaddr);
 
262
            else
 
263
                logg("Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
 
264
 
 
265
            ignored++;
 
266
            if(!loadbal || rp->ai_next)
 
267
                continue;
 
268
        }
 
269
 
 
270
        if(loadbal) {
 
271
            if(!ret) {
 
272
                if(!md) {
 
273
                    loadbal_rp = rp;
 
274
                    strncpy(loadbal_ipaddr, ipaddr, sizeof(loadbal_ipaddr));
 
275
                } else {
 
276
                    if(md->succ < minsucc && md->fail <= minfail) {
 
277
                        minsucc = md->succ;
 
278
                        minfail = md->fail;
 
279
                        loadbal_rp = rp;
 
280
                        strncpy(loadbal_ipaddr, ipaddr, sizeof(loadbal_ipaddr));
 
281
                    }
 
282
                    if(rp->ai_next)
 
283
                        continue;
 
284
                }
 
285
            }
 
286
 
 
287
            if(!loadbal_rp) {
 
288
                if(!rp->ai_next) {
 
289
                    loadbal = 0;
 
290
                    rp = res;
 
291
                }
 
292
                continue;
 
293
            }
 
294
            rp = loadbal_rp;
 
295
            strncpy(ipaddr, loadbal_ipaddr, sizeof(ipaddr));
 
296
 
 
297
        } else if(loadbal_rp == rp) {
 
298
            continue;
 
299
        }
 
300
 
 
301
        if(ip)
 
302
            strcpy(ip, ipaddr);
 
303
 
 
304
        if(rp != res)
 
305
            logg("Trying host %s (%s)...\n", hostpt, ipaddr);
 
306
 
 
307
        socketfd = getclientsock(localip, rp->ai_family);
 
308
        if(socketfd < 0) {
 
309
            freeaddrinfo(res);
 
310
            return -1;
 
311
        }
 
312
 
 
313
#ifdef SO_ERROR
 
314
        if(wait_connect(socketfd, rp->ai_addr, rp->ai_addrlen, ctimeout) == -1) {
 
315
#else
 
316
        if(connect(socketfd, rp->ai_addr, rp->ai_addrlen) == -1) {
 
317
#endif
 
318
            logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
 
319
            closesocket(socketfd);
 
320
            if(loadbal) {
 
321
                loadbal = 0;
 
322
                rp = res;
 
323
            }
 
324
            continue;
 
325
        } else {
 
326
            if(rp->ai_family == AF_INET)
 
327
                mdat->currip[0] = *((uint32_t *) addr);
 
328
            else
 
329
                memcpy(mdat->currip, addr, 4 * sizeof(uint32_t));
 
330
            mdat->af = rp->ai_family;
 
331
            freeaddrinfo(res);
 
332
            return socketfd;
 
333
        }
 
334
    }
 
335
    freeaddrinfo(res);
 
336
 
 
337
#else /* IPv4 */
 
338
 
191
339
    if((host = gethostbyname(hostpt)) == NULL) {
192
 
        const char *herr;
193
 
        switch(h_errno) {
194
 
            case HOST_NOT_FOUND:
195
 
                herr = "Host not found";
196
 
                break;
197
 
 
198
 
            case NO_DATA:
199
 
                herr = "No IP address";
200
 
                break;
201
 
 
202
 
            case NO_RECOVERY:
203
 
                herr = "Unrecoverable DNS error";
204
 
                break;
205
 
 
206
 
            case TRY_AGAIN:
207
 
                herr = "Temporary DNS error";
208
 
                break;
209
 
 
210
 
            default:
211
 
                herr = "Unknown error";
212
 
                break;
213
 
        }
214
 
        logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, herr);
215
 
        close(socketfd);
 
340
        logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, ghbn_err(h_errno));
216
341
        return -1;
217
342
    }
218
343
 
221
346
        ia = (unsigned char *) host->h_addr_list[i];
222
347
        sprintf(ipaddr, "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]);
223
348
 
224
 
        if((ret = mirman_check(((struct in_addr *) ia)->s_addr, mdat))) {
 
349
        ips++;
 
350
        if((ret = mirman_check(&((struct in_addr *) ia)->s_addr, AF_INET, mdat, NULL))) {
225
351
            if(ret == 1)
226
352
                logg("Ignoring mirror %s (due to previous errors)\n", ipaddr);
227
353
            else
228
354
                logg("Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
 
355
            ignored++;
229
356
            continue;
230
357
        }
231
358
 
235
362
        if(i > 0)
236
363
            logg("Trying host %s (%s)...\n", hostpt, ipaddr);
237
364
 
 
365
        memset ((char *) &name, 0, sizeof(name));
 
366
        name.sin_family = AF_INET;
238
367
        name.sin_addr = *((struct in_addr *) host->h_addr_list[i]);
239
368
        name.sin_port = htons(port);
240
369
 
 
370
        socketfd = getclientsock(localip, AF_INET);
 
371
        if(socketfd < 0)
 
372
            return -1;
 
373
 
241
374
#ifdef SO_ERROR
242
375
        if(wait_connect(socketfd, (struct sockaddr *) &name, sizeof(struct sockaddr_in), ctimeout) == -1) {
243
376
#else
244
377
        if(connect(socketfd, (struct sockaddr *) &name, sizeof(struct sockaddr_in)) == -1) {
245
378
#endif
246
379
            logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
247
 
            close(socketfd);
248
 
            if((socketfd = getclientsock(localip)) == -1)
249
 
                return -1;
250
 
 
 
380
            closesocket(socketfd);
251
381
            continue;
252
382
        } else {
253
 
            mdat->currip = ((struct in_addr *) ia)->s_addr;
 
383
            mdat->currip[0] = ((struct in_addr *) ia)->s_addr;
 
384
            mdat->af = AF_INET;
254
385
            return socketfd;
255
386
        }
256
387
    }
257
 
 
258
 
    close(socketfd);
 
388
#endif
 
389
 
 
390
    if(can_whitelist && ips && (ips == ignored))
 
391
        mirman_whitelist(mdat);
 
392
 
259
393
    return -2;
260
394
}
261
395
 
325
459
    buf[len] = '\0';
326
460
    auth = malloc(strlen(buf) + 30);
327
461
    if(!auth) {
 
462
        free(buf);
328
463
        logg("!proxyauth: Can't allocate memory for 'authorization'\n");
329
464
        return NULL;
330
465
    }
335
470
    return auth;
336
471
}
337
472
 
338
 
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, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr)
 
473
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, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist)
339
474
{
340
 
        char cmd[512], head[513], buffer[FILEBUFF], ipaddr[16], *ch, *tmp;
 
475
        char cmd[512], head[513], buffer[FILEBUFF], ipaddr[46], *ch, *tmp;
341
476
        int bread, cnt, sd;
342
477
        unsigned int i, j;
343
478
        char *remotename = NULL, *authorization = NULL;
344
 
        const char *agent;
345
479
        struct cl_cvd *cvd;
346
 
        char last_modified[36];
 
480
        char last_modified[36], uastr[128];
347
481
        struct stat sb;
348
482
 
349
483
 
357
491
 
358
492
        if(user) {
359
493
            authorization = proxyauth(user, pass);
360
 
            if(!authorization)
 
494
            if(!authorization) {
 
495
                free(remotename);
361
496
                return NULL;
 
497
            }
362
498
        }
363
499
    }
364
500
 
376
512
    logg("Reading CVD header (%s): ", file);
377
513
 
378
514
    if(uas)
379
 
        agent = uas;
 
515
        strncpy(uastr, uas, sizeof(uastr));
380
516
    else
381
 
#ifdef CL_EXPERIMENTAL
382
 
        agent = PACKAGE"/"VERSION"-exp";
383
 
#else
384
 
        agent = PACKAGE"/"VERSION;
385
 
#endif
 
517
        snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")", get_version());
 
518
    uastr[sizeof(uastr) - 1] = 0;
386
519
 
387
520
    snprintf(cmd, sizeof(cmd),
388
521
        "GET %s/%s HTTP/1.0\r\n"
391
524
        "Connection: close\r\n"
392
525
        "Range: bytes=0-511\r\n"
393
526
        "If-Modified-Since: %s\r\n"
394
 
        "\r\n", (remotename != NULL) ? remotename : "", file, hostname, (authorization != NULL) ? authorization : "", agent, last_modified);
 
527
        "\r\n", (remotename != NULL) ? remotename : "", file, hostname, (authorization != NULL) ? authorization : "", uastr, last_modified);
395
528
 
396
529
    free(remotename);
397
530
    free(authorization);
399
532
    memset(ipaddr, 0, sizeof(ipaddr));
400
533
 
401
534
    if(ip[0]) /* use ip to connect */
402
 
        sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr);
 
535
        sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
403
536
    else
404
 
        sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr);
 
537
        sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
405
538
 
406
539
    if(sd < 0) {
407
540
        return NULL;
435
568
 
436
569
    if(bread == -1) {
437
570
        logg("%cremote_cvdhead: Error while reading CVD header from %s\n", logerr ? '!' : '^', hostname);
438
 
        mirman_update(mdat->currip, mdat, 1);
 
571
        mirman_update(mdat->currip, mdat->af, mdat, 1);
439
572
        return NULL;
440
573
    }
441
574
 
449
582
    if((strstr(buffer, "HTTP/1.1 304")) != NULL || (strstr(buffer, "HTTP/1.0 304")) != NULL) { 
450
583
        *ims = 0;
451
584
        logg("OK (IMS)\n");
452
 
        mirman_update(mdat->currip, mdat, 0);
 
585
        mirman_update(mdat->currip, mdat->af, mdat, 0);
453
586
        return NULL;
454
587
    } else {
455
588
        *ims = 1;
458
591
    if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
459
592
       !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
460
593
        logg("%cUnknown response from remote server\n", logerr ? '!' : '^');
461
 
        mirman_update(mdat->currip, mdat, 1);
 
594
        mirman_update(mdat->currip, mdat->af, mdat, 1);
462
595
        return NULL;
463
596
    }
464
597
 
476
609
 
477
610
    if(sizeof(buffer) - i < 512) {
478
611
        logg("%cremote_cvdhead: Malformed CVD header (too short)\n", logerr ? '!' : '^');
479
 
        mirman_update(mdat->currip, mdat, 1);
 
612
        mirman_update(mdat->currip, mdat->af, mdat, 1);
480
613
        return NULL;
481
614
    }
482
615
 
485
618
    for(j = 0; j < 512; j++) {
486
619
        if(!ch || (ch && !*ch) || (ch && !isprint(ch[j]))) {
487
620
            logg("%cremote_cvdhead: Malformed CVD header (bad chars)\n", logerr ? '!' : '^');
488
 
            mirman_update(mdat->currip, mdat, 1);
 
621
            mirman_update(mdat->currip, mdat->af, mdat, 1);
489
622
            return NULL;
490
623
        }
491
624
        head[j] = ch[j];
493
626
 
494
627
    if(!(cvd = cl_cvdparse(head))) {
495
628
        logg("%cremote_cvdhead: Malformed CVD header (can't parse)\n", logerr ? '!' : '^');
496
 
        mirman_update(mdat->currip, mdat, 1);
 
629
        mirman_update(mdat->currip, mdat->af, mdat, 1);
497
630
    } else {
498
631
        logg("OK\n");
499
 
        mirman_update(mdat->currip, mdat, 0);
 
632
        mirman_update(mdat->currip, mdat->af, mdat, 0);
500
633
    }
501
634
 
502
635
    return cvd;
503
636
}
504
637
 
505
 
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)
 
638
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)
506
639
{
507
 
        char cmd[512], buffer[FILEBUFF], *ch;
 
640
        char cmd[512], uastr[128], buffer[FILEBUFF], *ch;
508
641
        int bread, fd, totalsize = 0,  rot = 0, totaldownloaded = 0,
509
642
            percentage = 0, sd;
510
643
        unsigned int i;
511
 
        char *remotename = NULL, *authorization = NULL, *headerline, ipaddr[16];
512
 
        const char *rotation = "|/-\\", *agent;
 
644
        char *remotename = NULL, *authorization = NULL, *headerline, ipaddr[46];
 
645
        const char *rotation = "|/-\\";
513
646
 
514
647
 
515
648
    if(proxy) {
522
655
 
523
656
        if(user) {
524
657
            authorization = proxyauth(user, pass);
525
 
            if(!authorization)
 
658
            if(!authorization) {
 
659
                free(remotename);
526
660
                return 75; /* FIXME */
 
661
            }
527
662
        }
528
663
    }
529
664
 
530
665
    if(uas)
531
 
        agent = uas;
 
666
        strncpy(uastr, uas, sizeof(uastr));
532
667
    else
533
 
#ifdef CL_EXPERIMENTAL
534
 
        agent = PACKAGE"/"VERSION"-exp";
535
 
#else
536
 
        agent = PACKAGE"/"VERSION;
537
 
#endif
 
668
        snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")", get_version());
 
669
    uastr[sizeof(uastr) - 1] = 0;
538
670
 
539
671
    snprintf(cmd, sizeof(cmd),
540
672
        "GET %s/%s HTTP/1.0\r\n"
544
676
        "Cache-Control: no-cache\r\n"
545
677
#endif
546
678
        "Connection: close\r\n"
547
 
        "\r\n", (remotename != NULL) ? remotename : "", srcfile, hostname, (authorization != NULL) ? authorization : "", agent);
548
 
 
549
 
    memset(ipaddr, 0, sizeof(ipaddr));
550
 
 
551
 
    if(ip[0]) /* use ip to connect */
552
 
        sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr);
553
 
    else
554
 
        sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr);
555
 
 
556
 
    if(sd < 0) {
557
 
        return 52;
558
 
    } else {
559
 
        logg("*Trying to download http://%s/%s (IP: %s)\n", hostname, srcfile, ipaddr);
560
 
    }
561
 
 
562
 
    if(!ip[0])
563
 
        strcpy(ip, ipaddr);
564
 
 
565
 
    if(send(sd, cmd, strlen(cmd), 0) < 0) {
566
 
        logg("%cgetfile: Can't write to socket\n", logerr ? '!' : '^');
567
 
        closesocket(sd);
568
 
        return 52;
569
 
    }
 
679
        "\r\n", (remotename != NULL) ? remotename : "", srcfile, hostname, (authorization != NULL) ? authorization : "", uastr);
570
680
 
571
681
    if(remotename)
572
682
        free(remotename);
574
684
    if(authorization)
575
685
        free(authorization);
576
686
 
 
687
    memset(ipaddr, 0, sizeof(ipaddr));
 
688
    if(ip[0]) /* use ip to connect */
 
689
        sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
 
690
    else
 
691
        sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
 
692
 
 
693
    if(sd < 0) {
 
694
        return 52;
 
695
    } else {
 
696
        logg("*Trying to download http://%s/%s (IP: %s)\n", hostname, srcfile, ipaddr);
 
697
    }
 
698
 
 
699
    if(!ip[0])
 
700
        strcpy(ip, ipaddr);
 
701
 
 
702
    if(send(sd, cmd, strlen(cmd), 0) < 0) {
 
703
        logg("%cgetfile: Can't write to socket\n", logerr ? '!' : '^');
 
704
        closesocket(sd);
 
705
        return 52;
 
706
    }
 
707
 
577
708
    /* read http headers */
578
709
    ch = buffer;
579
710
    i = 0;
585
716
        if((i >= sizeof(buffer) - 1) || recv(sd, buffer + i, 1, 0) == -1) {
586
717
#endif
587
718
            logg("%cgetfile: Error while reading database from %s (IP: %s)\n", logerr ? '!' : '^', hostname, ipaddr);
588
 
            mirman_update(mdat->currip, mdat, 1);
 
719
            mirman_update(mdat->currip, mdat->af, mdat, 1);
589
720
            closesocket(sd);
590
721
            return 52;
591
722
        }
611
742
    if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
612
743
       !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
613
744
        logg("%cgetfile: Unknown response from remote server (IP: %s)\n", logerr ? '!' : '^', ipaddr);
614
 
        mirman_update(mdat->currip, mdat, 1);
 
745
        mirman_update(mdat->currip, mdat->af, mdat, 1);
615
746
        closesocket(sd);
616
747
        return 58;
617
748
    }
632
763
    if((fd = open(destfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) == -1) {
633
764
            char currdir[512];
634
765
 
635
 
        getcwd(currdir, sizeof(currdir));
636
 
        logg("!getfile: Can't create new file %s in %s\n", destfile, currdir);
 
766
        if(getcwd(currdir, sizeof(currdir)))
 
767
            logg("!getfile: Can't create new file %s in %s\n", destfile, currdir);
 
768
        else
 
769
            logg("!getfile: Can't create new file %s in the current directory\n", destfile);
 
770
 
637
771
        logg("Hint: The database directory must be writable for UID %d or GID %d\n", getuid(), getgid());
638
772
        closesocket(sd);
639
773
        return 57;
676
810
    else
677
811
        logg("Downloading %s [*]\n", srcfile);
678
812
 
679
 
    mirman_update(mdat->currip, mdat, 0);
 
813
    mirman_update(mdat->currip, mdat->af, mdat, 0);
680
814
    return 0;
681
815
}
682
816
 
683
 
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, int nodb, unsigned int newver, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr)
 
817
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, int nodb, unsigned int newver, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist)
684
818
{
685
819
        struct cl_cvd *cvd;
686
820
        int ret;
687
821
 
688
822
 
689
823
    logg("*Retrieving http://%s/%s\n", hostname, cvdfile);
690
 
    if((ret = getfile(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr))) {
 
824
    if((ret = getfile(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist))) {
691
825
        logg("%cCan't download %s from %s\n", logerr ? '!' : '^', cvdfile, hostname);
692
826
        unlink(newfile);
693
827
        return ret;
751
885
    return 0;
752
886
}
753
887
 
754
 
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)
 
888
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)
755
889
{
756
890
        char *tempname, patch[32], olddir[512];
757
891
        int ret, fd;
769
903
    snprintf(patch, sizeof(patch), "%s-%d.cdiff", dbname, version);
770
904
 
771
905
    logg("*Retrieving http://%s/%s\n", hostname, patch);
772
 
    if((ret = getfile(patch, tempname, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr))) {
 
906
    if((ret = getfile(patch, tempname, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist))) {
773
907
        logg("%cgetpatch: Can't download %s from %s\n", logerr ? '!' : '^', patch, hostname);
774
908
        unlink(tempname);
775
909
        free(tempname);
776
 
        chdir(olddir);
 
910
        CHDIR_ERR(olddir);
777
911
        return ret;
778
912
    }
779
913
 
781
915
        logg("!getpatch: Can't open %s for reading\n", tempname);
782
916
        unlink(tempname);
783
917
        free(tempname);
784
 
        chdir(olddir);
 
918
        CHDIR_ERR(olddir);
785
919
        return 55;
786
920
    }
787
921
 
790
924
        close(fd);
791
925
        unlink(tempname);
792
926
        free(tempname);
793
 
        chdir(olddir);
 
927
        CHDIR_ERR(olddir);
794
928
        return 70; /* FIXME */
795
929
    }
796
930
 
797
931
    close(fd);
798
932
    unlink(tempname);
799
933
    free(tempname);
800
 
    chdir(olddir);
 
934
    if(chdir(olddir) == -1) {
 
935
        logg("!getpatch: Can't chdir to %s\n", olddir);
 
936
        return 50; /* FIXME */
 
937
    }
801
938
    return 0;
802
939
}
803
940
 
826
963
static int buildcld(const char *tmpdir, const char *dbname, const char *newfile, unsigned int compr)
827
964
{
828
965
        DIR *dir;
829
 
        char cwd[512], info[32], buff[512], *pt;
 
966
        char cwd[512], info[32], buff[513], *pt;
830
967
        struct dirent *dent;
831
968
        int fd, err = 0;
832
969
        gzFile *gzs = NULL;
833
970
 
 
971
    if(!getcwd(cwd, sizeof(cwd))) {
 
972
        logg("!buildcld: Can't get path of current working directory\n");
 
973
        return -1;
 
974
    }
834
975
 
835
 
    getcwd(cwd, sizeof(cwd));
836
976
    if(chdir(tmpdir) == -1) {
837
977
        logg("!buildcld: Can't access directory %s\n", tmpdir);
838
978
        return -1;
841
981
    snprintf(info, sizeof(info), "%s.info", dbname);
842
982
    if((fd = open(info, O_RDONLY|O_BINARY)) == -1) {
843
983
        logg("!buildcld: Can't open %s\n", info);
844
 
        chdir(cwd);
 
984
        CHDIR_ERR(cwd);
845
985
        return -1;
846
986
    }
847
987
 
848
988
    if(read(fd, buff, 512) == -1) {
849
989
        logg("!buildcld: Can't read %s\n", info);
850
 
        chdir(cwd);
 
990
        CHDIR_ERR(cwd);
851
991
        close(fd);
852
992
        return -1;
853
993
    }
 
994
    buff[512] = 0;
854
995
    close(fd);
855
996
 
856
997
    if(!(pt = strchr(buff, '\n'))) {
857
998
        logg("!buildcld: Bad format of %s\n", info);
858
 
        chdir(cwd);
 
999
        CHDIR_ERR(cwd);
859
1000
        return -1;
860
1001
    }
861
1002
    memset(pt, ' ', 512 + buff - pt);
862
1003
 
863
1004
    if((fd = open(newfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) == -1) {
864
1005
        logg("!buildcld: Can't open %s for writing\n", newfile);
865
 
        chdir(cwd);
 
1006
        CHDIR_ERR(cwd);
866
1007
        return -1;
867
1008
    }
868
1009
    if(write(fd, buff, 512) != 512) {
869
1010
        logg("!buildcld: Can't write to %s\n", newfile);
870
 
        chdir(cwd);
 
1011
        CHDIR_ERR(cwd);
871
1012
        unlink(newfile);
872
1013
        close(fd);
873
1014
        return -1;
875
1016
 
876
1017
    if((dir = opendir(".")) == NULL) {
877
1018
        logg("!buildcld: Can't open directory %s\n", tmpdir);
878
 
        chdir(cwd);
 
1019
        CHDIR_ERR(cwd);
879
1020
        unlink(newfile);
880
1021
        close(fd);
881
1022
        return -1;
885
1026
        close(fd);
886
1027
        if(!(gzs = gzopen(newfile, "ab"))) {
887
1028
            logg("!buildcld: gzopen() failed for %s\n", newfile);
888
 
            chdir(cwd);
 
1029
            CHDIR_ERR(cwd);
889
1030
            unlink(newfile);
890
1031
            closedir(dir);
891
1032
            return -1;
910
1051
    }
911
1052
 
912
1053
    if(err) {
913
 
        chdir(cwd);
 
1054
        CHDIR_ERR(cwd);
914
1055
        if(gzs)
915
1056
            gzclose(gzs);
916
1057
        else
920
1061
    }
921
1062
 
922
1063
    while((dent = readdir(dir))) {
923
 
#ifndef C_INTERIX
 
1064
#if !defined(C_INTERIX) && !defined(C_WINDOWS)
924
1065
        if(dent->d_ino)
925
1066
#endif
926
1067
        {
929
1070
 
930
1071
            if(tar_addfile(fd, gzs, dent->d_name) == -1) {
931
1072
                logg("!buildcld: Can't add %s to .cld file\n", dent->d_name);
932
 
                chdir(cwd);
 
1073
                CHDIR_ERR(cwd);
933
1074
                if(gzs)
934
1075
                    gzclose(gzs);
935
1076
                else
972
1113
        int ret, ims = -1;
973
1114
        char *pt, cvdfile[32], localname[32], *tmpdir = NULL, *newfile, newdb[32], cwd[512];
974
1115
        const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL;
975
 
        unsigned int flevel = cl_retflevel(), maxattempts;
 
1116
        unsigned int flevel = cl_retflevel(), remote_flevel = 0, maxattempts;
 
1117
        unsigned int can_whitelist = 0;
976
1118
        int ctimeout, rtimeout;
977
1119
 
978
1120
 
1010
1152
        }
1011
1153
    }
1012
1154
 
 
1155
    if(dnsreply) {
 
1156
        if((pt = cli_strtok(dnsreply, 5, ":"))) {
 
1157
            remote_flevel = atoi(pt);
 
1158
            free(pt);
 
1159
            if(remote_flevel && (remote_flevel - flevel < 4))
 
1160
                can_whitelist = 1;
 
1161
        }
 
1162
    }
 
1163
 
1013
1164
    /* Initialize proxy settings */
1014
1165
    if((cpt = cfgopt(copt, "HTTPProxyServer"))->enabled) {
1015
1166
        proxy = cpt->strarg;
1042
1193
 
1043
1194
    if(!nodb && !newver) {
1044
1195
 
1045
 
        remote = remote_cvdhead(cvdfile, hostname, ip, localip, proxy, port, user, pass, uas, &ims, ctimeout, rtimeout, mdat, logerr);
 
1196
        remote = remote_cvdhead(cvdfile, hostname, ip, localip, proxy, port, user, pass, uas, &ims, ctimeout, rtimeout, mdat, logerr, can_whitelist);
1046
1197
 
1047
1198
        if(!nodb && !ims) {
1048
1199
            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);
1103
1254
    if(!cfgopt(copt, "ScriptedUpdates")->enabled)
1104
1255
        nodb = 1;
1105
1256
 
1106
 
    getcwd(cwd, sizeof(cwd));
 
1257
    if(!getcwd(cwd, sizeof(cwd))) {
 
1258
        logg("!updatedb: Can't get path of current working directory\n");
 
1259
        return 50; /* FIXME */
 
1260
    }
1107
1261
    newfile = cli_gentemp(cwd);
1108
1262
 
1109
1263
    if(nodb) {
1110
 
        ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, nodb, newver, ctimeout, rtimeout, mdat, logerr);
 
1264
        ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, nodb, newver, ctimeout, rtimeout, mdat, logerr, can_whitelist);
1111
1265
        if(ret) {
1112
1266
            memset(ip, 0, 16);
1113
1267
            free(newfile);
1125
1279
                    int llogerr = logerr;
1126
1280
                if(logerr)
1127
1281
                    llogerr = (j == maxattempts - 1);
1128
 
                ret = getpatch(dbname, tmpdir, i, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, llogerr);
 
1282
                ret = getpatch(dbname, tmpdir, i, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, llogerr, can_whitelist);
1129
1283
                if(ret == 52 || ret == 58) {
1130
1284
                    memset(ip, 0, 16);
1131
1285
                    continue;
1141
1295
            cli_rmdirs(tmpdir);
1142
1296
            free(tmpdir);
1143
1297
            logg("^Incremental update failed, trying to download %s\n", cvdfile);
1144
 
            ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, 1, newver, ctimeout, rtimeout, mdat, logerr);
 
1298
            ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, 1, newver, ctimeout, rtimeout, mdat, logerr, can_whitelist);
1145
1299
            if(ret) {
1146
1300
                free(newfile);
1147
1301
                return ret;
1175
1329
        return 53;
1176
1330
    }
1177
1331
 
 
1332
#ifdef C_WINDOWS
 
1333
    if(!access(newdb, R_OK) && unlink(newdb)) {
 
1334
        logg("!Can't unlink %s. Please fix the problem manually and try again.\n", newdb);
 
1335
        unlink(newfile);
 
1336
        free(newfile);
 
1337
        return 53;
 
1338
    }
 
1339
#endif
 
1340
 
1178
1341
    if(rename(newfile, newdb) == -1) {
1179
1342
        logg("!Can't rename %s to %s: %s\n", newfile, newdb, strerror(errno));
1180
1343
        unlink(newfile);
1201
1364
        time_t currtime;
1202
1365
        int ret, updated = 0, outdated = 0, signo = 0;
1203
1366
        unsigned int ttl;
1204
 
        char ipaddr[16], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
 
1367
        char ipaddr[46], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
1205
1368
        const char *arg = NULL;
1206
1369
        const struct cfgstruct *cpt;
1207
1370
        struct mirdat mdat;
1211
1374
 
1212
1375
    time(&currtime);
1213
1376
    logg("ClamAV update process started at %s", ctime(&currtime));
 
1377
#ifdef SUPPORT_IPv6
 
1378
    logg("*Using IPv6 aware code\n");
 
1379
#endif
1214
1380
 
1215
1381
#ifndef HAVE_LIBGMP
1216
1382
    logg("SECURITY WARNING: NO SUPPORT FOR DIGITAL SIGNATURES\n");
1258
1424
 
1259
1425
                    logg("*Software version from DNS: %s\n", newver);
1260
1426
 
1261
 
                    if(vwarning && !strstr(cl_retver(), "devel") && !strstr(cl_retver(), "rc")) {
1262
 
                        if(strcmp(cl_retver(), newver)) {
 
1427
                    if(vwarning && !strstr(get_version(), "devel") && !strstr(get_version(), "rc")) {
 
1428
                        if(strcmp(get_version(), newver)) {
1263
1429
                            logg("^Your ClamAV installation is OUTDATED!\n");
1264
 
                            logg("^Local version: %s Recommended version: %s\n", cl_retver(), newver);
 
1430
                            logg("^Local version: %s Recommended version: %s\n", get_version(), newver);
1265
1431
                            logg("DON'T PANIC! Read http://www.clamav.net/support/faq\n");
1266
1432
                            outdated = 1;
1267
1433
                        }
1268
1434
                    }
1269
1435
                }
1270
1436
 
1271
 
            } else {
1272
 
                if(dnsreply) {
1273
 
                    free(dnsreply);
1274
 
                    dnsreply = NULL;
1275
 
                }
1276
1437
            }
1277
1438
        }
1278
1439
 
1351
1512
        else if((cpt = cfgopt(copt, "OnUpdateExecute"))->enabled)
1352
1513
            arg = cpt->strarg;
1353
1514
 
1354
 
        if(arg) {
1355
 
            if(opt_check(opt, "daemon"))
1356
 
                execute("OnUpdateExecute", arg);
1357
 
            else if(system(arg) == -1)
1358
 
                logg("!system(%s) failed\n", arg);
1359
 
        }
 
1515
        if(arg)
 
1516
            execute("OnUpdateExecute", arg, opt);
1360
1517
    }
1361
1518
 
1362
1519
    if(outdated) {
1400
1557
                free(buffer);
1401
1558
            }
1402
1559
 
1403
 
            if(newver) {
1404
 
                if(opt_check(opt, "daemon"))
1405
 
                    execute("OnOutdatedExecute", cmd);
1406
 
                else if(system(cmd) == -1)
1407
 
                logg("!system(%s) failed\n", cmd);
1408
 
            }
 
1560
            if(newver)
 
1561
                execute("OnOutdatedExecute", cmd, opt);
 
1562
 
1409
1563
            free(cmd);
1410
1564
        }
1411
1565
    }
1415
1569
 
1416
1570
    return updated ? 0 : 1;
1417
1571
}
1418