git-svn: trunk@3193
Nigel Horne authored on 2007/08/30 03:21:39... | ... |
@@ -1,3 +1,7 @@ |
1 |
+Wed Aug 29 18:27:55 BST 2007 (njh) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav: mbox optimisation to reduce the lifetime of temporary files |
|
4 |
+ |
|
1 | 5 |
Tue Aug 28 16:08:13 BST 2007 (njh) |
2 | 6 |
---------------------------------- |
3 | 7 |
* libclamav/mbox.c: MailFollowURLS: improved debugging |
... | ... |
@@ -48,6 +48,7 @@ static char const rcsid[] = "$Id: blob.c,v 1.64 2007/02/12 22:25:14 njh Exp $"; |
48 | 48 |
#include "others.h" |
49 | 49 |
#include "mbox.h" |
50 | 50 |
#include "matcher.h" |
51 |
+#include "scanners.h" |
|
51 | 52 |
|
52 | 53 |
#ifndef CL_DEBUG |
53 | 54 |
#define NDEBUG /* map CLAMAV debug onto standard */ |
... | ... |
@@ -214,7 +215,7 @@ blobAddData(blob *b, const unsigned char *data, size_t len) |
214 | 214 |
assert(b->len == 0); |
215 | 215 |
assert(b->size == 0); |
216 | 216 |
|
217 |
- b->size = len * 4; |
|
217 |
+ b->size = (off_t)len * 4; |
|
218 | 218 |
b->data = cli_malloc(b->size); |
219 | 219 |
} else if(b->size < b->len + (off_t)len) { |
220 | 220 |
unsigned char *p = cli_realloc(b->data, b->size + (len * 4)); |
... | ... |
@@ -222,14 +223,14 @@ blobAddData(blob *b, const unsigned char *data, size_t len) |
222 | 222 |
if(p == NULL) |
223 | 223 |
return -1; |
224 | 224 |
|
225 |
- b->size += len * 4; |
|
225 |
+ b->size += (off_t)len * 4; |
|
226 | 226 |
b->data = p; |
227 | 227 |
} |
228 | 228 |
#endif |
229 | 229 |
|
230 | 230 |
if(b->data) { |
231 | 231 |
memcpy(&b->data[b->len], data, len); |
232 |
- b->len += len; |
|
232 |
+ b->len += (off_t)len; |
|
233 | 233 |
} |
234 | 234 |
return 0; |
235 | 235 |
} |
... | ... |
@@ -344,12 +345,12 @@ blobGrow(blob *b, size_t len) |
344 | 344 |
|
345 | 345 |
b->data = cli_malloc(len); |
346 | 346 |
if(b->data) |
347 |
- b->size = len; |
|
347 |
+ b->size = (off_t)len; |
|
348 | 348 |
} else { |
349 | 349 |
unsigned char *ptr = cli_realloc(b->data, b->size + len); |
350 | 350 |
|
351 | 351 |
if(ptr) { |
352 |
- b->size += len; |
|
352 |
+ b->size += (off_t)len; |
|
353 | 353 |
b->data = ptr; |
354 | 354 |
} |
355 | 355 |
} |
... | ... |
@@ -371,6 +372,52 @@ fileblobCreate(void) |
371 | 371 |
#endif |
372 | 372 |
} |
373 | 373 |
|
374 |
+/* |
|
375 |
+ * Returns CL_CLEAN or CL_VIRUS. Destroys the fileblob and removes the file |
|
376 |
+ * if possible |
|
377 |
+ */ |
|
378 |
+int |
|
379 |
+fileblobScanAndDestroy(fileblob *fb) |
|
380 |
+{ |
|
381 |
+ switch(fileblobScan(fb)) { |
|
382 |
+ case CL_VIRUS: |
|
383 |
+ fileblobDestructiveDestroy(fb); |
|
384 |
+ return CL_VIRUS; |
|
385 |
+ case CL_BREAK: |
|
386 |
+ fileblobDestructiveDestroy(fb); |
|
387 |
+ return CL_CLEAN; |
|
388 |
+ default: |
|
389 |
+ fileblobDestroy(fb); |
|
390 |
+ return CL_CLEAN; |
|
391 |
+ } |
|
392 |
+} |
|
393 |
+ |
|
394 |
+/* |
|
395 |
+ * Destroy the fileblob, and remove the file associated with it |
|
396 |
+ */ |
|
397 |
+void |
|
398 |
+fileblobDestructiveDestroy(fileblob *fb) |
|
399 |
+{ |
|
400 |
+ if(fb->fp && fb->fullname) { |
|
401 |
+ fclose(fb->fp); |
|
402 |
+ cli_dbgmsg("fileblobDestructiveDestroy: %s\n", fb->fullname); |
|
403 |
+ if(unlink(fb->fullname) < 0) |
|
404 |
+ cli_warnmsg("fileblobDestructiveDestroy: Can't delete file %s\n", fb->fullname); |
|
405 |
+ free(fb->fullname); |
|
406 |
+ fb->fp = NULL; |
|
407 |
+ fb->fullname = NULL; |
|
408 |
+ } |
|
409 |
+ if(fb->b.name) { |
|
410 |
+ free(fb->b.name); |
|
411 |
+ fb->b.name = NULL; |
|
412 |
+ } |
|
413 |
+ fileblobDestroy(fb); |
|
414 |
+} |
|
415 |
+ |
|
416 |
+/* |
|
417 |
+ * Destroy the fileblob, and remove the file associated with it if that file is |
|
418 |
+ * empty |
|
419 |
+ */ |
|
374 | 420 |
void |
375 | 421 |
fileblobDestroy(fileblob *fb) |
376 | 422 |
{ |
... | ... |
@@ -384,7 +431,7 @@ fileblobDestroy(fileblob *fb) |
384 | 384 |
if(!fb->isNotEmpty) { |
385 | 385 |
cli_dbgmsg("fileblobDestroy: not saving empty file\n"); |
386 | 386 |
if(unlink(fb->fullname) < 0) |
387 |
- cli_warnmsg("fileblobDestroy: Can't delete empty files %s\n", fb->fullname); |
|
387 |
+ cli_warnmsg("fileblobDestroy: Can't delete empty file %s\n", fb->fullname); |
|
388 | 388 |
} |
389 | 389 |
} |
390 | 390 |
free(fb->b.name); |
... | ... |
@@ -571,10 +618,62 @@ fileblobSetCTX(fileblob *fb, cli_ctx *ctx) |
571 | 571 |
fb->ctx = ctx; |
572 | 572 |
} |
573 | 573 |
|
574 |
+/* |
|
575 |
+ * Performs a full scan on the fileblob, returning ClamAV status: |
|
576 |
+ * CL_BREAK means clean |
|
577 |
+ * CL_CLEAN means unknown |
|
578 |
+ * CL_VIRUS means infected |
|
579 |
+ */ |
|
580 |
+int |
|
581 |
+fileblobScan(const fileblob *fb) |
|
582 |
+{ |
|
583 |
+ int rc, fd; |
|
584 |
+ |
|
585 |
+ if(fb->isInfected) |
|
586 |
+ return CL_VIRUS; |
|
587 |
+ if(fb->fullname == NULL) { |
|
588 |
+ /* shouldn't happen, scan called before fileblobSetFilename */ |
|
589 |
+ cli_warnmsg("fileblobScan, fullname == NULL\n"); |
|
590 |
+ return CL_CLEAN; /* there is no CL_UNKNOWN */ |
|
591 |
+ } |
|
592 |
+ if(fb->ctx == NULL) { |
|
593 |
+ /* fileblobSetCTX hasn't been called */ |
|
594 |
+ cli_dbgmsg("fileblobScan, ctx == NULL\n"); |
|
595 |
+ return CL_CLEAN; /* there is no CL_UNKNOWN */ |
|
596 |
+ } |
|
597 |
+ |
|
598 |
+ fflush(fb->fp); |
|
599 |
+ fd = dup(fileno(fb->fp)); |
|
600 |
+ if(fd == -1) { |
|
601 |
+ cli_warnmsg("%s: dup failed\n", fb->fullname); |
|
602 |
+ return CL_CLEAN; |
|
603 |
+ } |
|
604 |
+ /* cli_scanfile is static :-( */ |
|
605 |
+ /*if(cli_scanfile(fb->fullname, fb->ctx) == CL_VIRUS) { |
|
606 |
+ printf("%s is infected\n", fb->fullname); |
|
607 |
+ return CL_VIRUS; |
|
608 |
+ }*/ |
|
609 |
+ |
|
610 |
+ rc = cli_magic_scandesc(fd, fb->ctx); |
|
611 |
+ close(fd); |
|
612 |
+ if(rc == CL_VIRUS) { |
|
613 |
+ cli_dbgmsg("%s is infected\n", fb->fullname); |
|
614 |
+ return CL_VIRUS; |
|
615 |
+ } |
|
616 |
+ cli_dbgmsg("%s is clean\n", fb->fullname); |
|
617 |
+ return CL_BREAK; |
|
618 |
+ |
|
619 |
+ /*return cli_scanfile(fb->fullname, fb->ctx);*/ |
|
620 |
+} |
|
621 |
+ |
|
622 |
+/* |
|
623 |
+ * Doesn't perform a full scan just lets the caller know if something suspicious has |
|
624 |
+ * been seen yet |
|
625 |
+ */ |
|
574 | 626 |
int |
575 |
-fileblobContainsVirus(const fileblob *fb) |
|
627 |
+fileblobInfected(const fileblob *fb) |
|
576 | 628 |
{ |
577 |
- return fb->isInfected ? TRUE : FALSE; |
|
629 |
+ return fb->isInfected; |
|
578 | 630 |
} |
579 | 631 |
|
580 | 632 |
/* |
... | ... |
@@ -62,12 +62,15 @@ typedef struct fileblob { |
62 | 62 |
} fileblob; |
63 | 63 |
|
64 | 64 |
fileblob *fileblobCreate(void); |
65 |
+int fileblobScanAndDestroy(fileblob *fb); |
|
66 |
+void fileblobDestructiveDestroy(fileblob *fb); |
|
65 | 67 |
void fileblobDestroy(fileblob *fb); |
66 | 68 |
void fileblobSetFilename(fileblob *fb, const char *dir, const char *filename); |
67 | 69 |
const char *fileblobGetFilename(const fileblob *fb); |
68 | 70 |
void fileblobSetCTX(fileblob *fb, cli_ctx *ctx); |
69 | 71 |
int fileblobAddData(fileblob *fb, const unsigned char *data, size_t len); |
70 |
-int fileblobContainsVirus(const fileblob *fb); |
|
72 |
+int fileblobScan(const fileblob *fb); |
|
73 |
+int fileblobInfected(const fileblob *fb); |
|
71 | 74 |
void sanitiseName(char *name); |
72 | 75 |
|
73 | 76 |
#endif /*_BLOB_H*/ |
... | ... |
@@ -257,7 +257,7 @@ static void *getURL(struct arg *arg); |
257 | 257 |
#endif |
258 | 258 |
static long nonblock_fcntl(int sock); |
259 | 259 |
static void restore_fcntl(int sock, long fcntl_flags); |
260 |
-static int nonblock_connect(const char *url, int sock, const struct sockaddr *addr, socklen_t addrlen, int secs); |
|
260 |
+static int nonblock_connect(const char *url, int sock, const struct sockaddr *addr); |
|
261 | 261 |
static int connect_error(const char *url, int sock); |
262 | 262 |
static int my_r_gethostbyname(const char *hostname, struct hostent *hp, char *buf, size_t len); |
263 | 263 |
|
... | ... |
@@ -2475,7 +2475,7 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re |
2475 | 2475 |
|
2476 | 2476 |
cli_dbgmsg("The message has %d parts\n", multiparts); |
2477 | 2477 |
|
2478 |
- if(((multiparts == 0) || infected) && (aText == NULL)) { |
|
2478 |
+ if(infected || ((multiparts == 0) && (aText == NULL))) { |
|
2479 | 2479 |
if(messages) { |
2480 | 2480 |
for(i = 0; i < multiparts; i++) |
2481 | 2481 |
if(messages[i]) |
... | ... |
@@ -2537,6 +2537,10 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re |
2537 | 2537 |
messageDestroy(aMessage); |
2538 | 2538 |
messages[htmltextPart] = NULL; |
2539 | 2539 |
} |
2540 |
+ else if(rc == VIRUS) { |
|
2541 |
+ infected = TRUE; |
|
2542 |
+ break; |
|
2543 |
+ } |
|
2540 | 2544 |
} |
2541 | 2545 |
|
2542 | 2546 |
/* |
... | ... |
@@ -2751,7 +2755,8 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re |
2751 | 2751 |
|
2752 | 2752 |
if(fb) { |
2753 | 2753 |
cli_dbgmsg("Saving main message as attachment\n"); |
2754 |
- fileblobDestroy(fb); |
|
2754 |
+ if(fileblobScanAndDestroy(fb) == CL_VIRUS) |
|
2755 |
+ rc = VIRUS; |
|
2755 | 2756 |
if(mainMessage != messageIn) { |
2756 | 2757 |
messageDestroy(mainMessage); |
2757 | 2758 |
mainMessage = NULL; |
... | ... |
@@ -2783,7 +2788,7 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re |
2783 | 2783 |
/* Look for a bounce in the text (non mime encoded) portion */ |
2784 | 2784 |
const text *t; |
2785 | 2785 |
|
2786 |
- for(t = aText; t; t = t->t_next) { |
|
2786 |
+ for(t = aText; t && (rc != VIRUS); t = t->t_next) { |
|
2787 | 2787 |
const line_t *l = t->t_line; |
2788 | 2788 |
const text *lookahead, *topofbounce; |
2789 | 2789 |
const char *s; |
... | ... |
@@ -2896,9 +2901,11 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re |
2896 | 2896 |
break; |
2897 | 2897 |
} |
2898 | 2898 |
} |
2899 |
- } while(!fileblobContainsVirus(fb)); |
|
2899 |
+ } while(!fileblobInfected(fb)); |
|
2900 |
+ |
|
2901 |
+ if(fileblobScanAndDestroy(fb) == CL_VIRUS) |
|
2902 |
+ rc = VIRUS; |
|
2900 | 2903 |
|
2901 |
- fileblobDestroy(fb); |
|
2902 | 2904 |
if(topofbounce) |
2903 | 2905 |
t = topofbounce; |
2904 | 2906 |
/* |
... | ... |
@@ -4197,13 +4204,13 @@ getURL(struct arg *arg) |
4197 | 4197 |
|
4198 | 4198 |
memcpy((char *)&ip, h.h_addr, sizeof(ip)); |
4199 | 4199 |
} |
4200 |
- server.sin_addr.s_addr = ip; |
|
4201 | 4200 |
if((sd = socket(AF_INET, SOCK_STREAM, tcp)) < 0) { |
4202 | 4201 |
fclose(fp); |
4203 | 4202 |
return NULL; |
4204 | 4203 |
} |
4204 |
+ server.sin_addr.s_addr = ip; |
|
4205 | 4205 |
flags = nonblock_fcntl(sd); |
4206 |
- if(nonblock_connect(url, sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in), URL_TIMEOUT) < 0) { |
|
4206 |
+ if(nonblock_connect(url, sd, (struct sockaddr *)&server) < 0) { |
|
4207 | 4207 |
closesocket(sd); |
4208 | 4208 |
fclose(fp); |
4209 | 4209 |
return NULL; |
... | ... |
@@ -4440,7 +4447,7 @@ restore_fcntl(int sock, long fcntl_flags) |
4440 | 4440 |
} |
4441 | 4441 |
|
4442 | 4442 |
static int |
4443 |
-nonblock_connect(const char *url, int sock, const struct sockaddr *addr, socklen_t addrlen, int secs) |
|
4443 |
+nonblock_connect(const char *url, int sock, const struct sockaddr *addr) |
|
4444 | 4444 |
{ |
4445 | 4445 |
int select_failures; /* Max. of unexpected select() failures */ |
4446 | 4446 |
int bogus_loops; /* Max. of useless loops */ |
... | ... |
@@ -4450,7 +4457,7 @@ nonblock_connect(const char *url, int sock, const struct sockaddr *addr, socklen |
4450 | 4450 |
/* Calculate into 'timeout' when we should time out */ |
4451 | 4451 |
gettimeofday(&timeout, 0); |
4452 | 4452 |
|
4453 |
- if(connect(sock, addr, addrlen)) |
|
4453 |
+ if(connect(sock, addr, sizeof(struct sockaddr_in)) != 0) |
|
4454 | 4454 |
switch(errno) { |
4455 | 4455 |
case EALREADY: |
4456 | 4456 |
case EINPROGRESS: |
... | ... |
@@ -4468,7 +4475,7 @@ nonblock_connect(const char *url, int sock, const struct sockaddr *addr, socklen |
4468 | 4468 |
numfd = sock + 1; /* Highest fdset fd plus 1 */ |
4469 | 4469 |
select_failures = NONBLOCK_SELECT_MAX_FAILURES; |
4470 | 4470 |
bogus_loops = NONBLOCK_MAX_BOGUS_LOOPS; |
4471 |
- timeout.tv_sec += secs; |
|
4471 |
+ timeout.tv_sec += URL_TIMEOUT; |
|
4472 | 4472 |
|
4473 | 4473 |
for (;;) { |
4474 | 4474 |
int n, t; |
... | ... |
@@ -4483,7 +4490,7 @@ nonblock_connect(const char *url, int sock, const struct sockaddr *addr, socklen |
4483 | 4483 |
|
4484 | 4484 |
if(t) { |
4485 | 4485 |
cli_warnmsg("%s: connect timeout (%d secs)\n", |
4486 |
- url, secs); |
|
4486 |
+ url, URL_TIMEOUT); |
|
4487 | 4487 |
break; |
4488 | 4488 |
} |
4489 | 4489 |
|
... | ... |
@@ -4716,12 +4723,11 @@ exportBinhexMessage(const char *dir, message *m) |
4716 | 4716 |
fb = messageToFileblob(m, dir, 0); |
4717 | 4717 |
|
4718 | 4718 |
if(fb) { |
4719 |
- if(fileblobContainsVirus(fb)) |
|
4720 |
- infected = TRUE; |
|
4721 |
- |
|
4722 | 4719 |
cli_dbgmsg("Binhex file decoded to %s\n", |
4723 | 4720 |
fileblobGetFilename(fb)); |
4724 |
- fileblobDestroy(fb); |
|
4721 |
+ |
|
4722 |
+ if(fileblobScanAndDestroy(fb) == CL_VIRUS) |
|
4723 |
+ infected = TRUE; |
|
4725 | 4724 |
} else |
4726 | 4725 |
cli_errmsg("Couldn't decode binhex file to %s\n", dir); |
4727 | 4726 |
|
... | ... |
@@ -5011,20 +5017,20 @@ do_multipart(message *mainMessage, message **messages, int i, mbox_status *rc, m |
5011 | 5011 |
return mainMessage; |
5012 | 5012 |
} |
5013 | 5013 |
|
5014 |
- if(addToText) { |
|
5015 |
- cli_dbgmsg("Adding to non mime-part\n"); |
|
5016 |
- *tptr = textAdd(*tptr, messageGetBody(aMessage)); |
|
5017 |
- } else { |
|
5018 |
- fileblob *fb = messageToFileblob(aMessage, mctx->dir, 1); |
|
5014 |
+ if(*rc != VIRUS) { |
|
5015 |
+ if(addToText) { |
|
5016 |
+ cli_dbgmsg("Adding to non mime-part\n"); |
|
5017 |
+ *tptr = textAdd(*tptr, messageGetBody(aMessage)); |
|
5018 |
+ } else { |
|
5019 |
+ fileblob *fb = messageToFileblob(aMessage, mctx->dir, 1); |
|
5019 | 5020 |
|
5020 |
- if(fb) { |
|
5021 |
- if(fileblobContainsVirus(fb)) |
|
5022 |
- *rc = VIRUS; |
|
5023 |
- fileblobDestroy(fb); |
|
5021 |
+ if(fb) |
|
5022 |
+ if(fileblobScanAndDestroy(fb) == CL_VIRUS) |
|
5023 |
+ *rc = VIRUS; |
|
5024 | 5024 |
} |
5025 |
+ if(messageContainsVirus(aMessage)) |
|
5026 |
+ *rc = VIRUS; |
|
5025 | 5027 |
} |
5026 |
- if(messageContainsVirus(aMessage)) |
|
5027 |
- *rc = VIRUS; |
|
5028 | 5028 |
messageDestroy(aMessage); |
5029 | 5029 |
messages[i] = NULL; |
5030 | 5030 |
|