git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@972 77e5149b-7576-45b1-b177-96237e5ba77b
Nigel Horne authored on 2004/10/06 00:48:47... | ... |
@@ -1,3 +1,13 @@ |
1 |
+Tue Oct 5 16:45:28 BST 2004 (njh) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav: First draft of RFC1341 code. It is not enabled by |
|
4 |
+ default. To enable it, locate PARTIAL_DIR |
|
5 |
+ in libclamav/mbox.c, uncomment the line and set |
|
6 |
+ that to some nice place. |
|
7 |
+ Note that it is up to YOU to ensure that the PARTIAL_DIR |
|
8 |
+ directory is secure and to trim out old files |
|
9 |
+ in there from time to time. |
|
10 |
+ |
|
1 | 11 |
Tue Oct 5 11:59:09 BST 2004 (njh) |
2 | 12 |
---------------------------------- |
3 | 13 |
* libclamav/message.c: Faster base64 decoding |
... | ... |
@@ -60,7 +70,7 @@ Fri Oct 1 02:28:08 CEST 2004 (tk) |
60 | 60 |
---------------------------------- |
61 | 61 |
* clamd: add new directive IdleTimeout (patch by Andrey J. Melnikoff (TEMHOTA) |
62 | 62 |
<temnota*kmv.ru>) |
63 |
- * clamscan/others.c: preserve Mac OS X resource forks in filecopy() |
|
63 |
+ * clamscan/others.c: preserve Mac OS X resource forks in filecopy() |
|
64 | 64 |
(thanks to Remi Mommsen <remigius.mommsen*cern.ch>) |
65 | 65 |
* cosmetic fixes (thanks to Damian Menscher <menscherr*uiuc.edu>) |
66 | 66 |
|
... | ... |
@@ -17,6 +17,9 @@ |
17 | 17 |
* |
18 | 18 |
* Change History: |
19 | 19 |
* $Log: mbox.c,v $ |
20 |
+ * Revision 1.148 2004/10/05 15:41:53 nigelhorne |
|
21 |
+ * First draft of code to handle RFC1341 |
|
22 |
+ * |
|
20 | 23 |
* Revision 1.147 2004/10/04 12:18:09 nigelhorne |
21 | 24 |
* Better warning message about PGP attachments not being scanned |
22 | 25 |
* |
... | ... |
@@ -429,7 +432,7 @@ |
429 | 429 |
* Compilable under SCO; removed duplicate code with message.c |
430 | 430 |
* |
431 | 431 |
*/ |
432 |
-static char const rcsid[] = "$Id: mbox.c,v 1.147 2004/10/04 12:18:09 nigelhorne Exp $"; |
|
432 |
+static char const rcsid[] = "$Id: mbox.c,v 1.148 2004/10/05 15:41:53 nigelhorne Exp $"; |
|
433 | 433 |
|
434 | 434 |
#if HAVE_CONFIG_H |
435 | 435 |
#include "clamav-config.h" |
... | ... |
@@ -459,6 +462,7 @@ static char const rcsid[] = "$Id: mbox.c,v 1.147 2004/10/04 12:18:09 nigelhorne |
459 | 459 |
#include <sys/types.h> |
460 | 460 |
#include <sys/param.h> |
461 | 461 |
#include <clamav.h> |
462 |
+#include <dirent.h> |
|
462 | 463 |
|
463 | 464 |
#ifdef CL_THREAD_SAFE |
464 | 465 |
#include <pthread.h> |
... | ... |
@@ -538,6 +542,13 @@ typedef enum { FALSE = 0, TRUE = 1 } bool; |
538 | 538 |
#undef WITH_CURL |
539 | 539 |
#endif |
540 | 540 |
|
541 |
+/* |
|
542 |
+ * Define this to handle RFC1341 messages. |
|
543 |
+ * This is experimental code so it is up to YOU to (1) ensure it's secure |
|
544 |
+ * (2) peridically trim the directory of old files |
|
545 |
+ */ |
|
546 |
+/*#define PARTIAL_DIR "/tmp/partial" /* FIXME: should be config based on TMPDIR */ |
|
547 |
+ |
|
541 | 548 |
static message *parseEmailHeaders(const message *m, const table_t *rfc821Table); |
542 | 549 |
static int parseEmailHeader(message *m, const char *line, const table_t *rfc821Table); |
543 | 550 |
static int parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t *rfc821Table, const table_t *subtypeTable, unsigned int options); |
... | ... |
@@ -551,6 +562,9 @@ static int parseMimeHeader(message *m, const char *cmd, const table_t *rfc821Tab |
551 | 551 |
static void saveTextPart(message *m, const char *dir); |
552 | 552 |
static char *rfc2047(const char *in); |
553 | 553 |
static char *rfc822comments(const char *in); |
554 |
+#ifdef PARTIAL_DIR |
|
555 |
+static int rfc1341(message *m, const char *dir); |
|
556 |
+#endif |
|
554 | 557 |
|
555 | 558 |
static void checkURLs(message *m, const char *dir); |
556 | 559 |
#ifdef WITH_CURL |
... | ... |
@@ -876,9 +890,6 @@ parseEmailHeaders(const message *m, const table_t *rfc821) |
876 | 876 |
|
877 | 877 |
for(t = messageGetBody(m); t; t = t->t_next) { |
878 | 878 |
const char *buffer; |
879 |
-#ifdef CL_THREAD_SAFE |
|
880 |
- char *strptr; |
|
881 |
-#endif |
|
882 | 879 |
|
883 | 880 |
if(t->t_line) |
884 | 881 |
buffer = lineGetData(t->t_line); |
... | ... |
@@ -903,6 +914,9 @@ parseEmailHeaders(const message *m, const table_t *rfc821) |
903 | 903 |
*/ |
904 | 904 |
const char *ptr; |
905 | 905 |
char copy[LINE_LENGTH + 1]; |
906 |
+#ifdef CL_THREAD_SAFE |
|
907 |
+ char *strptr; |
|
908 |
+#endif |
|
906 | 909 |
|
907 | 910 |
assert(strlen(buffer) < sizeof(copy)); |
908 | 911 |
strcpy(copy, buffer); |
... | ... |
@@ -1787,6 +1801,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t |
1787 | 1787 |
cli_warnmsg("MIME type 'message' cannot be decoded\n"); |
1788 | 1788 |
break; |
1789 | 1789 |
} |
1790 |
+ rc = 0; |
|
1790 | 1791 |
if((strcasecmp(mimeSubtype, "rfc822") == 0) || |
1791 | 1792 |
(strcasecmp(mimeSubtype, "delivery-status") == 0)) { |
1792 | 1793 |
message *m = parseEmailHeaders(mainMessage, rfc821Table); |
... | ... |
@@ -1807,26 +1822,27 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t |
1807 | 1807 |
} else if(strcasecmp(mimeSubtype, "disposition-notification") == 0) |
1808 | 1808 |
/* RFC 2298 - handle like a normal email */ |
1809 | 1809 |
break; |
1810 |
- else if(strcasecmp(mimeSubtype, "partial") == 0) |
|
1811 |
- /* |
|
1812 |
- * How can we be expected to reassemble a message when in |
|
1813 |
- * practice we'll be called once for each email so we won't |
|
1814 |
- * have all the parts for reassembly. It is up to the |
|
1815 |
- * calling program to reassemble full messages and pass |
|
1816 |
- * them on to us for scanning |
|
1817 |
- */ |
|
1810 |
+ else if(strcasecmp(mimeSubtype, "partial") == 0) { |
|
1811 |
+#ifdef PARTIAL_DIR |
|
1812 |
+ /* RFC1341 message split over many emails */ |
|
1813 |
+ if(rfc1341(mainMessage, dir) >= 0) |
|
1814 |
+ rc = 1; |
|
1815 |
+#else |
|
1818 | 1816 |
cli_warnmsg("Partial message received from MUA/MTA - message cannot be scanned\n"); |
1819 |
- else if(strcasecmp(mimeSubtype, "external-body") == 0) |
|
1817 |
+ rc = 0; |
|
1818 |
+#endif |
|
1819 |
+ } else if(strcasecmp(mimeSubtype, "external-body") == 0) |
|
1820 | 1820 |
/* TODO */ |
1821 | 1821 |
cli_warnmsg("Attempt to send Content-type message/external-body trapped"); |
1822 | 1822 |
else |
1823 | 1823 |
cli_warnmsg("Unsupported message format `%s' - please report to bugs@clamav.net\n", mimeSubtype); |
1824 | 1824 |
|
1825 |
+ |
|
1825 | 1826 |
if(mainMessage && (mainMessage != messageIn)) |
1826 | 1827 |
messageDestroy(mainMessage); |
1827 | 1828 |
if(messages) |
1828 | 1829 |
free(messages); |
1829 |
- return 0; |
|
1830 |
+ return rc; |
|
1830 | 1831 |
|
1831 | 1832 |
case APPLICATION: |
1832 | 1833 |
cptr = messageGetMimeSubtype(mainMessage); |
... | ... |
@@ -2584,6 +2600,157 @@ rfc2047(const char *in) |
2584 | 2584 |
return out; |
2585 | 2585 |
} |
2586 | 2586 |
|
2587 |
+#ifdef PARTIAL_DIR |
|
2588 |
+/* |
|
2589 |
+ * Handle partial messages |
|
2590 |
+ */ |
|
2591 |
+static int |
|
2592 |
+rfc1341(message *m, const char *dir) |
|
2593 |
+{ |
|
2594 |
+ fileblob *fb; |
|
2595 |
+ char *arg; |
|
2596 |
+ char *id; |
|
2597 |
+ char *number; |
|
2598 |
+ char *total; |
|
2599 |
+ char *oldfilename; |
|
2600 |
+ |
|
2601 |
+ if((mkdir(PARTIAL_DIR, 0700) < 0) && (errno != EEXIST)) { |
|
2602 |
+ /*perror(PARTIAL_DIR);*/ |
|
2603 |
+ return -1; |
|
2604 |
+ } |
|
2605 |
+ |
|
2606 |
+ id = (char *)messageFindArgument(m, "id"); |
|
2607 |
+ if(id == NULL) |
|
2608 |
+ return -1; |
|
2609 |
+ number = (char *)messageFindArgument(m, "number"); |
|
2610 |
+ if(number == NULL) { |
|
2611 |
+ free(id); |
|
2612 |
+ return -1; |
|
2613 |
+ } |
|
2614 |
+ |
|
2615 |
+ oldfilename = (char *)messageFindArgument(m, "filename"); |
|
2616 |
+ if(oldfilename == NULL) |
|
2617 |
+ oldfilename = (char *)messageFindArgument(m, "name"); |
|
2618 |
+ |
|
2619 |
+ arg = cli_malloc(10 + strlen(id) + strlen(number)); |
|
2620 |
+ sprintf(arg, "filename=%s%s", id, number); |
|
2621 |
+ messageAddArgument(m, arg); |
|
2622 |
+ free(arg); |
|
2623 |
+ |
|
2624 |
+ if(oldfilename) { |
|
2625 |
+ cli_warnmsg("Must reset to %s\n", oldfilename); |
|
2626 |
+ free(oldfilename); |
|
2627 |
+ } |
|
2628 |
+ |
|
2629 |
+ if((fb = messageToFileblob(m, PARTIAL_DIR)) == NULL) { |
|
2630 |
+ free(id); |
|
2631 |
+ free(number); |
|
2632 |
+ return -1; |
|
2633 |
+ } |
|
2634 |
+ |
|
2635 |
+ fileblobDestroy(fb); |
|
2636 |
+ |
|
2637 |
+ total = (char *)messageFindArgument(m, "total"); |
|
2638 |
+ cli_dbgmsg("rfc1341: %s, %s of %s\n", id, number, (total) ? total : "?"); |
|
2639 |
+ if(total) { |
|
2640 |
+ int n = atoi(number); |
|
2641 |
+ int t = atoi(total); |
|
2642 |
+ DIR *dd = NULL; |
|
2643 |
+ struct dirent *dent; |
|
2644 |
+#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2) |
|
2645 |
+ struct dirent result; |
|
2646 |
+#endif |
|
2647 |
+ |
|
2648 |
+ /* |
|
2649 |
+ * If it's the last one - reassemble it |
|
2650 |
+ */ |
|
2651 |
+ if((n == t) && ((dd = opendir(PARTIAL_DIR)) != NULL)) { |
|
2652 |
+ FILE *fout; |
|
2653 |
+ char outname[NAME_MAX + 1]; |
|
2654 |
+ |
|
2655 |
+ snprintf(outname, sizeof(outname) - 1, "%s/%s", dir, id); |
|
2656 |
+ |
|
2657 |
+ cli_dbgmsg("outname: %s\n", outname); |
|
2658 |
+ |
|
2659 |
+ fout = fopen(outname, "wb"); |
|
2660 |
+ if(fout == NULL) { |
|
2661 |
+ /*perror(outname);*/ |
|
2662 |
+ free(id); |
|
2663 |
+ free(total); |
|
2664 |
+ free(number); |
|
2665 |
+ closedir(dd); |
|
2666 |
+ return -1; |
|
2667 |
+ } |
|
2668 |
+ |
|
2669 |
+ for(n = 1; n <= t; n++) { |
|
2670 |
+ char filename[NAME_MAX + 1]; |
|
2671 |
+ |
|
2672 |
+ snprintf(filename, sizeof(filename), "%s%d", id, n); |
|
2673 |
+#ifdef HAVE_READDIR_R_3 |
|
2674 |
+ while((readdir_r(dd, &result, &dent) == 0) && dent) { |
|
2675 |
+#elif defined(HAVE_READDIR_R_2) |
|
2676 |
+ while((dent = (struct dirent *)readdir_r(dd, &result))) { |
|
2677 |
+#else |
|
2678 |
+ while((dent = readdir(dd))) { |
|
2679 |
+#endif |
|
2680 |
+ char fullname[NAME_MAX + 1]; |
|
2681 |
+ FILE *fin; |
|
2682 |
+ char buffer[BUFSIZ]; |
|
2683 |
+ int nblanks; |
|
2684 |
+ |
|
2685 |
+ if(dent->d_ino == 0) |
|
2686 |
+ continue; |
|
2687 |
+ |
|
2688 |
+ if(strncmp(filename, dent->d_name, strlen(filename)) != 0) |
|
2689 |
+ continue; |
|
2690 |
+ |
|
2691 |
+ sprintf(fullname, "%s/%s", PARTIAL_DIR, dent->d_name); |
|
2692 |
+ fin = fopen(fullname, "rb"); |
|
2693 |
+ if(fin == NULL) { |
|
2694 |
+ /*perror(fullname);*/ |
|
2695 |
+ fclose(fout); |
|
2696 |
+ unlink(outname); |
|
2697 |
+ free(id); |
|
2698 |
+ free(total); |
|
2699 |
+ free(number); |
|
2700 |
+ closedir(dd); |
|
2701 |
+ |
|
2702 |
+ return -1; |
|
2703 |
+ } |
|
2704 |
+ nblanks = 0; |
|
2705 |
+ while(fgets(buffer, sizeof(buffer), fin) != NULL) |
|
2706 |
+ /* |
|
2707 |
+ * Ensure that trailing newlines |
|
2708 |
+ * aren't copied |
|
2709 |
+ */ |
|
2710 |
+ if(buffer[0] == '\n') { |
|
2711 |
+ nblanks++; |
|
2712 |
+ } else { |
|
2713 |
+ if(nblanks) |
|
2714 |
+ do |
|
2715 |
+ putc('\n', fout); |
|
2716 |
+ while(--nblanks > 0); |
|
2717 |
+ fputs(buffer, fout); |
|
2718 |
+ } |
|
2719 |
+ fclose(fin); |
|
2720 |
+ /* FIXME: don't unlink if leave temps */ |
|
2721 |
+ unlink(fullname); |
|
2722 |
+ break; |
|
2723 |
+ } |
|
2724 |
+ rewinddir(dd); |
|
2725 |
+ } |
|
2726 |
+ closedir(dd); |
|
2727 |
+ fclose(fout); |
|
2728 |
+ } |
|
2729 |
+ free(number); |
|
2730 |
+ } |
|
2731 |
+ free(id); |
|
2732 |
+ free(total); |
|
2733 |
+ |
|
2734 |
+ return 0; |
|
2735 |
+} |
|
2736 |
+#endif |
|
2737 |
+ |
|
2587 | 2738 |
#ifdef FOLLOWURLS |
2588 | 2739 |
static void |
2589 | 2740 |
checkURLs(message *m, const char *dir) |
... | ... |
@@ -2783,7 +2950,7 @@ getURL(struct arg *arg) |
2783 | 2783 |
fp = fopen(fout, "w"); |
2784 | 2784 |
|
2785 | 2785 |
if(fp == NULL) { |
2786 |
- perror(fout); |
|
2786 |
+ /*perror(fout);*/ |
|
2787 | 2787 |
free(fout); |
2788 | 2788 |
curl_easy_cleanup(curl); |
2789 | 2789 |
return NULL; |
... | ... |
@@ -17,6 +17,9 @@ |
17 | 17 |
* |
18 | 18 |
* Change History: |
19 | 19 |
* $Log: message.c,v $ |
20 |
+ * Revision 1.96 2004/10/05 15:46:18 nigelhorne |
|
21 |
+ * First draft of code to handle RFC1341 |
|
22 |
+ * |
|
20 | 23 |
* Revision 1.95 2004/10/05 10:58:00 nigelhorne |
21 | 24 |
* Table driven base64 decoding |
22 | 25 |
* |
... | ... |
@@ -282,7 +285,7 @@ |
282 | 282 |
* uuencodebegin() no longer static |
283 | 283 |
* |
284 | 284 |
*/ |
285 |
-static char const rcsid[] = "$Id: message.c,v 1.95 2004/10/05 10:58:00 nigelhorne Exp $"; |
|
285 |
+static char const rcsid[] = "$Id: message.c,v 1.96 2004/10/05 15:46:18 nigelhorne Exp $"; |
|
286 | 286 |
|
287 | 287 |
#if HAVE_CONFIG_H |
288 | 288 |
#include "clamav-config.h" |
... | ... |
@@ -2333,6 +2336,9 @@ usefulArg(const char *arg) |
2333 | 2333 |
(strncasecmp(arg, "filename", 8) != 0) && |
2334 | 2334 |
(strncasecmp(arg, "boundary", 8) != 0) && |
2335 | 2335 |
(strncasecmp(arg, "protocol", 8) != 0) && |
2336 |
+ (strncasecmp(arg, "id", 2) != 0) && |
|
2337 |
+ (strncasecmp(arg, "number", 6) != 0) && |
|
2338 |
+ (strncasecmp(arg, "total", 5) != 0) && |
|
2336 | 2339 |
(strncasecmp(arg, "type", 4) != 0)) { |
2337 | 2340 |
cli_dbgmsg("Discarding unwanted argument '%s'\n", arg); |
2338 | 2341 |
return 0; |