<>I wrote this patch because I kept getting virus emails quarantined by amavisd (after passing through clamav-milter) which were not recognized as RFC822 mail files.
They are not recognized because their headers are mxed up a bit. For instance the messages can start with Date: or To: or any other header not recognized by the magic scan routine.


These messages were infected by viruses that clamscan detects after using munpack on them.

The messages all had a X-Scanned by clamav-milter header.
clamav-milter currently sends a pseudo "Received:" header to clamd, presumably this should force RFC822/Mbox processing.


Since I cant currently tell why amavis-milter/amavisd/uvscan catches them and clamav didnt, this patch will allow me to remove the uncertainty involved.

This patch
* updates libclamav to recognize a new option CL_UNKNOWN_MAIL which will treat the file as RFC822 if unrecognized.
* updates clamscan to recognize these new command line arguments (all equivalent) --mbox-force or --mail or -M which turns on above behavior.
* updates clamd to recognize new commands designed to ask for this behavior. MAILSCAN, CONTMAILSCAN, MAILSTREAM.
* updates clamd to recognize new configuration option "ScanUnknownAsMail" designed to ask for this behavior as a default.
* updates clamdscan to recognize the new command line arguments and use the above commands to clamd.
* updates clamav-milter to use the MAILSTREAM or MAILSCAN commands to clamd.


Some notes:
- clamd will reject with unknown command the new verbs if ScanMail is not in the config file.
- clamdscan will not use the new verbs if ScanMail is not in the config file.
- clamscan will treat the new arguments as implying -m (--mbox).


Its been 30 hours since and not a single new one of those messages has appeared with this patch.

Patches are on http://www.jmaimon.com/clamav

Attached are patches for 0.70 and clamav-devel

Joe
diff -ur clamav-devel-jm5/clamav-milter/clamav-milter.c 
clamav-devel-jm4/clamav-milter/clamav-milter.c
--- clamav-devel-jm5/clamav-milter/clamav-milter.c      Fri Apr 23 17:07:42 2004
+++ clamav-devel-jm4/clamav-milter/clamav-milter.c      Fri Apr 23 17:16:38 2004
@@ -2083,7 +2083,7 @@
                        return cl_error;
                }
 
-               snprintf(cmdbuf, sizeof(cmdbuf) - 1, "SCAN %s", privdata->filename);
+               snprintf(cmdbuf, sizeof(cmdbuf) - 1, "MAILSCAN %s", 
privdata->filename);
 
                nbytes = (int)strlen(cmdbuf);
 
@@ -2894,7 +2894,7 @@
 
                shutdown(privdata->dataSocket, SHUT_RD);
 
-               if(send(privdata->cmdSocket, "STREAM\n", 7, 0) < 7) {
+               if(send(privdata->cmdSocket, "MAILSTREAM\n", 11, 0) < 7) {
                        perror("send");
                        if(use_syslog)
                                syslog(LOG_ERR, "send failed to clamd");
diff -ur clamav-devel-jm5/clamd/session.c clamav-devel-jm4/clamd/session.c
--- clamav-devel-jm5/clamd/session.c    Fri Apr 23 17:07:43 2004
+++ clamav-devel-jm4/clamd/session.c    Fri Apr 23 17:16:38 2004
@@ -54,6 +54,9 @@
 #define CMD9 "SESSION"
 #define CMD10 "END"
 #define CMD11 "SHUTDOWN"
+#define CMD12 "MAILSTREAM"
+#define CMD13 "MAILSCAN"
+#define CMD14 "CONTMAILSCAN"
 
 
 int command(int desc, const struct cl_node *root, const struct cl_limits *limits, int 
options, const struct cfgstruct *copt)
@@ -150,6 +153,27 @@
     } else if(!strncmp(buff, CMD11, strlen(CMD11))) { /* SHUTDOWN */
        return COMMAND_QUIT;
 
+    } else if(!strncmp(buff, CMD12, strlen(CMD12))) { /* MAILSTREAM */
+       if((cpt = cfgopt(copt,"ScanMail"))) {
+           options |= CL_UNKNOWN_MAIL;
+           scanstream(desc, NULL, root, limits, options, copt);
+       } else {
+           mdprintf(desc, "UNKNOWN COMMAND\n");
+       }
+    } else if(!strncmp(buff, CMD13, strlen(CMD13))) { /* MAILSCAN */
+       if((cpt = cfgopt(copt,"ScanMail"))) {
+           options |= CL_UNKNOWN_MAIL;
+           scan(buff + strlen(CMD13) + 1, NULL, root, limits, options, copt, desc, 0);
+       } else {
+           mdprintf(desc, "UNKNOWN COMMAND\n");
+       }
+    } else if(!strncmp(buff, CMD14, strlen(CMD14))) { /* CONTMAILSCAN */
+       if((cpt = cfgopt(copt,"ScanMail"))) {
+           options |= CL_UNKNOWN_MAIL;
+           scan(buff + strlen(CMD14) + 1, NULL, root, limits, options, copt, desc, 1);
+       } else {
+           mdprintf(desc, "UNKNOWN COMMAND\n");
+       }
     } else {
        mdprintf(desc, "UNKNOWN COMMAND\n");
     }
diff -ur clamav-devel-jm5/clamdscan/clamdscan.c clamav-devel-jm4/clamdscan/clamdscan.c
--- clamav-devel-jm5/clamdscan/clamdscan.c      Fri Apr 23 17:07:43 2004
+++ clamav-devel-jm4/clamdscan/clamdscan.c      Fri Apr 23 17:16:38 2004
@@ -126,6 +126,8 @@
     mprintf("    --verbose           -v             Be verbose\n");
     mprintf("    --quiet                            Be quiet, only output error 
messages\n");
     mprintf("    --stdout                           Write to stdout instead of 
stderr\n");
+    mprintf("    --mail, --mbox-force, -M           All unknown file type will be a 
RFC822 mail file\n");
+    mprintf("    --stdout                           Write to stdout instead of 
stderr\n");
     mprintf("                                       (this help is always written to 
stdout)\n");
     mprintf("    --log=FILE          -l FILE        Save scan report in FILE\n");
     mprintf("    --log-verbose                      Log additional messages\n");
diff -ur clamav-devel-jm5/clamdscan/client.c clamav-devel-jm4/clamdscan/client.c
--- clamav-devel-jm5/clamdscan/client.c Fri Apr 23 17:07:43 2004
+++ clamav-devel-jm4/clamdscan/client.c Fri Apr 23 17:16:38 2004
@@ -55,6 +55,7 @@
        int sockd, wsockd, loopw = 60, bread, port;
        const char *clamav_conf = getargl(opt, "config-file");
        FILE *fd;
+       short unknown_mail = 0;
 
     if(!clamav_conf)
        clamav_conf = DEFAULT_CFG;
@@ -64,6 +65,15 @@
        return 2;
     }
 
+     if((cfgopt(copt, "ScanMail")) &&
+       (
+           (optl(opt, "mbox-force")) ||
+           (optl(opt, "mail")) ||
+           (optc(opt, 'M'))
+         )
+        ) 
+       unknown_mail = 1;           
+
     /* Set default address to connect to; needed for scanning a stream and no TCP 
address specified */
     server2.sin_addr.s_addr = inet_addr("127.0.0.1");    
     if(cfgopt(copt, "ScannerDaemonOutputFormat")) {
@@ -137,7 +147,7 @@
        file = (char *) strdup(cwd);
 
     } else if(!strcmp(opt->filename, "-")) { /* scan data from stdin */
-       if(write(sockd, "STREAM", 6) <= 0) {
+       if(write(sockd, (unknown_mail) ? "MAILSTREAM" : "STREAM", (unknown_mail) ? 10 
: 6) <= 0) {
            mprintf("@Can't write to the socket.\n");
            close(sockd);
            return 2;
@@ -229,7 +239,7 @@
 
 
     scancmd = mcalloc(strlen(file) + 20, sizeof(char));
-    sprintf(scancmd, "CONTSCAN %s", file);
+    sprintf(scancmd, "%s %s", (unknown_mail)? "CONTMAILSCAN" : "CONTSCAN", file);
     free(file);
 
     if(write(sockd, scancmd, strlen(scancmd)) <= 0) {
diff -ur clamav-devel-jm5/clamscan/clamscan.c clamav-devel-jm4/clamscan/clamscan.c
--- clamav-devel-jm5/clamscan/clamscan.c        Fri Apr 23 17:07:43 2004
+++ clamav-devel-jm4/clamscan/clamscan.c        Fri Apr 23 17:16:38 2004
@@ -208,6 +208,10 @@
     mprintf("    --bell                               Sound bell on virus 
detection\n");
     mprintf("    --no-summary                         Disable summary at end of 
scanning\n");
     mprintf("    --mbox                -m             Treat stdin as a mailbox\n");
+    mprintf("    --mbox-force          -M\n");
+    mprintf("    --mail                -M             Unrecognized filetypes  will be 
be treated\n");
+    mprintf("                                         as RFC822 mail file.\n");
+    mprintf("                                         This implies --mbox (-m)\n");
     mprintf("\n");
     mprintf("    --no-ole2                            Disable OLE2 support\n");
     mprintf("    --no-archive                         Disable libclamav archive 
support\n");
diff -ur clamav-devel-jm5/clamscan/manager.c clamav-devel-jm4/clamscan/manager.c
--- clamav-devel-jm5/clamscan/manager.c Fri Apr 23 17:07:43 2004
+++ clamav-devel-jm4/clamscan/manager.c Fri Apr 23 17:16:38 2004
@@ -373,6 +373,12 @@
     if(optc(opt, 'm'))
        options |= CL_MAIL;
 
+    if(optc(opt, 'M') || optl(opt,"mail")) {
+       options |= CL_MAIL;
+       options |= CL_UNKNOWN_MAIL;
+    }
+       
+
     /* 
      * check the extension  - this is a special case, normally we don't need to
      * do this (libclamav detects archive by its magic string), but here we
diff -ur clamav-devel-jm5/clamscan/options.c clamav-devel-jm4/clamscan/options.c
--- clamav-devel-jm5/clamscan/options.c Fri Apr 23 17:07:43 2004
+++ clamav-devel-jm4/clamscan/options.c Fri Apr 23 17:16:38 2004
@@ -43,7 +43,7 @@
        int ret, opt_index, i, len;
        struct optstruct *opt;
 
-       const char *getopt_parameters = "hvd:wriVl:m";
+       const char *getopt_parameters = "hvd:wriVl:mM";
 
        static struct option long_options[] = {
            /* 
@@ -82,6 +82,8 @@
            {"block-encrypted", 0, 0, 0},
            {"no-ole2", 0, 0, 0},
            {"mbox", 0, 0, 'm'},
+           {"mbox-force", 0, 0, 'M'},
+           {"mail", 0, 0, 0},
            {"stdout", 0, 0, 0},
            {"unzip", 2, 0, 0},
            {"unrar", 2, 0, 0},
diff -ur clamav-devel-jm5/libclamav/clamav.h clamav-devel-jm4/libclamav/clamav.h
--- clamav-devel-jm5/libclamav/clamav.h Fri Apr 23 17:07:46 2004
+++ clamav-devel-jm4/libclamav/clamav.h Fri Apr 23 17:16:38 2004
@@ -69,6 +69,7 @@
 #define CL_DISABLERAR  4
 #define CL_OLE2                8
 #define CL_ENCRYPTED    16
+#define CL_UNKNOWN_MAIL        32
 
 struct cli_patt {
     short int *pattern;
diff -ur clamav-devel-jm5/libclamav/scanners.c clamav-devel-jm4/libclamav/scanners.c
--- clamav-devel-jm5/libclamav/scanners.c       Fri Apr 23 17:07:46 2004
+++ clamav-devel-jm4/libclamav/scanners.c       Fri Apr 23 17:16:38 2004
@@ -58,6 +58,7 @@
 #define SCAN_OLE2          (options & CL_OLE2)
 #define DISABLE_RAR        (options & CL_DISABLERAR)
 #define DETECT_ENCRYPTED    (options & CL_ENCRYPTED)
+#define SCAN_UNKNOWN_MAIL    (options & CL_UNKNOWN_MAIL)
 
 struct cli_magic_s {
     int offset;
@@ -882,6 +883,9 @@
     }
 
     type = cli_filetype(magic, bread);
+
+       if(type == CL_UNKNOWN_TYPE && SCAN_UNKNOWN_MAIL)
+               type = CL_MAILFILE;
 
     switch(type) {
        case CL_RARFILE:
diff -ur clamav-devel-jm5/shared/cfgparser.c clamav-devel-jm4/shared/cfgparser.c
--- clamav-devel-jm5/shared/cfgparser.c Fri Apr 23 17:07:46 2004
+++ clamav-devel-jm4/shared/cfgparser.c Fri Apr 23 17:16:38 2004
@@ -62,6 +62,7 @@
            {"TemporaryDirectory", OPT_STR},
            {"MaxFileSize", OPT_COMPSIZE},
            {"ScanMail", OPT_NOARG},
+           {"ScanUnknownAsMail", OPT_NOARG},
            {"ScanOLE2", OPT_NOARG},
            {"ScanArchive", OPT_NOARG},
            {"ScanRAR", OPT_NOARG},
diff -urwN clamav-0.70-orig/clamav-milter/clamav-milter.c 
clamav-0.70-virus-skips/clamav-milter/clamav-milter.c
--- clamav-0.70-orig/clamav-milter/clamav-milter.c      Thu Apr 15 10:24:32 2004
+++ clamav-0.70-virus-skips/clamav-milter/clamav-milter.c       Fri Apr 23 14:50:10 
2004
@@ -1947,7 +1947,7 @@
                        return cl_error;
                }
 
-               snprintf(cmdbuf, sizeof(cmdbuf) - 1, "SCAN %s", privdata->filename);
+               snprintf(cmdbuf, sizeof(cmdbuf) - 1, "MAILSCAN %s", 
privdata->filename);
 
                nbytes = (int)strlen(cmdbuf);
 
@@ -2662,7 +2662,7 @@
 
                shutdown(privdata->dataSocket, SHUT_RD);
 
-               if(send(privdata->cmdSocket, "STREAM\n", 7, 0) < 7) {
+               if(send(privdata->cmdSocket, "MAILSTREAM\n", 11, 0) < 7) {
                        perror("send");
                        if(use_syslog)
                                syslog(LOG_ERR, "send failed to clamd");
diff -urwN clamav-0.70-orig/clamd/session.c clamav-0.70-virus-skips/clamd/session.c
--- clamav-0.70-orig/clamd/session.c    Mon Mar 29 11:09:15 2004
+++ clamav-0.70-virus-skips/clamd/session.c     Fri Apr 23 14:52:37 2004
@@ -54,6 +54,9 @@
 #define CMD9 "SESSION"
 #define CMD10 "END"
 #define CMD11 "SHUTDOWN"
+#define CMD12 "MAILSTREAM"
+#define CMD13 "MAILSCAN"
+#define CMD14 "CONTMAILSCAN"
 
 
 int command(int desc, const struct cl_node *root, const struct cl_limits *limits, int 
options, const struct cfgstruct *copt)
@@ -150,6 +153,27 @@
     } else if(!strncmp(buff, CMD11, strlen(CMD11))) { /* SHUTDOWN */
        return COMMAND_QUIT;
 
+    } else if(!strncmp(buff, CMD12, strlen(CMD12))) { /* MAILSTREAM */
+       if((cpt = cfgopt(copt,"ScanMail"))) {
+           options |= CL_UNKNOWN_MAIL;
+           scanstream(desc, NULL, root, limits, options, copt);
+       } else {
+           mdprintf(desc, "UNKNOWN COMMAND\n");
+       }
+    } else if(!strncmp(buff, CMD13, strlen(CMD13))) { /* MAILSCAN */
+       if((cpt = cfgopt(copt,"ScanMail"))) {
+           options |= CL_UNKNOWN_MAIL;
+           scan(buff + strlen(CMD13) + 1, NULL, root, limits, options, copt, desc, 0);
+       } else {
+           mdprintf(desc, "UNKNOWN COMMAND\n");
+       }
+    } else if(!strncmp(buff, CMD14, strlen(CMD14))) { /* CONTMAILSCAN */
+       if((cpt = cfgopt(copt,"ScanMail"))) {
+           options |= CL_UNKNOWN_MAIL;
+           scan(buff + strlen(CMD14) + 1, NULL, root, limits, options, copt, desc, 1);
+       } else {
+           mdprintf(desc, "UNKNOWN COMMAND\n");
+       }
     } else {
        mdprintf(desc, "UNKNOWN COMMAND\n");
     }
diff -urwN clamav-0.70-orig/clamdscan/clamdscan.c 
clamav-0.70-virus-skips/clamdscan/clamdscan.c
--- clamav-0.70-orig/clamdscan/clamdscan.c      Sat Apr 10 18:55:45 2004
+++ clamav-0.70-virus-skips/clamdscan/clamdscan.c       Fri Apr 23 12:38:24 2004
@@ -126,6 +126,8 @@
     mprintf("    --verbose           -v             Be verbose\n");
     mprintf("    --quiet                            Be quiet, only output error 
messages\n");
     mprintf("    --stdout                           Write to stdout instead of 
stderr\n");
+    mprintf("    --mail, --mbox-force, -M           All unknown file type will be a 
RFC822 mail file\n");
+    mprintf("    --stdout                           Write to stdout instead of 
stderr\n");
     mprintf("                                       (this help is always written to 
stdout)\n");
     mprintf("    --log=FILE          -l FILE        Save scan report in FILE\n");
     mprintf("    --log-verbose                      Log additional messages\n");
diff -urwN clamav-0.70-orig/clamdscan/client.c 
clamav-0.70-virus-skips/clamdscan/client.c
--- clamav-0.70-orig/clamdscan/client.c Tue Apr  6 18:38:40 2004
+++ clamav-0.70-virus-skips/clamdscan/client.c  Fri Apr 23 14:52:17 2004
@@ -55,6 +55,7 @@
        int sockd, wsockd, loopw = 60, bread, port;
        const char *clamav_conf = getargl(opt, "config-file");
        FILE *fd;
+       short unknown_mail = 0;
 
     if(!clamav_conf)
        clamav_conf = DEFAULT_CFG;
@@ -64,6 +65,15 @@
        return 2;
     }
 
+     if((cfgopt(copt, "ScanMail")) &&
+       (
+           (optl(opt, "mbox-force")) ||
+           (optl(opt, "mail")) ||
+           (optc(opt, 'M'))
+         )
+        ) 
+       unknown_mail = 1;           
+
     /* Set default address to connect to; needed for scanning a stream and no TCP 
address specified */
     server2.sin_addr.s_addr = inet_addr("127.0.0.1");    
     if(cfgopt(copt, "ScannerDaemonOutputFormat")) {
@@ -137,7 +147,7 @@
        file = (char *) strdup(cwd);
 
     } else if(!strcmp(opt->filename, "-")) { /* scan data from stdin */
-       if(write(sockd, "STREAM", 6) <= 0) {
+       if(write(sockd, (unknown_mail) ? "MAILSTREAM" : "STREAM", (unknown_mail) ? 10 
: 6) <= 0) {
            mprintf("@Can't write to the socket.\n");
            close(sockd);
            return 2;
@@ -229,7 +239,7 @@
 
 
     scancmd = mcalloc(strlen(file) + 20, sizeof(char));
-    sprintf(scancmd, "CONTSCAN %s", file);
+    sprintf(scancmd, "%s %s", (unknown_mail)? "CONTMAILSCAN" : "CONTSCAN", file);
     free(file);
 
     if(write(sockd, scancmd, strlen(scancmd)) <= 0) {
diff -urwN clamav-0.70-orig/clamscan/clamscan.c 
clamav-0.70-virus-skips/clamscan/clamscan.c
--- clamav-0.70-orig/clamscan/clamscan.c        Fri Apr 16 11:26:18 2004
+++ clamav-0.70-virus-skips/clamscan/clamscan.c Fri Apr 23 12:37:51 2004
@@ -208,6 +208,10 @@
     mprintf("    --bell                               Sound bell on virus 
detection\n");
     mprintf("    --no-summary                         Disable summary at end of 
scanning\n");
     mprintf("    --mbox                -m             Treat stdin as a mailbox\n");
+    mprintf("    --mbox-force          -M\n");
+    mprintf("    --mail                -M             Unrecognized filetypes  will be 
be treated\n");
+    mprintf("                                         as RFC822 mail file.\n");
+    mprintf("                                         This implies --mbox (-m)\n");
     mprintf("\n");
     mprintf("    --no-ole2                            Disable OLE2 support\n");
     mprintf("    --no-archive                         Disable libclamav archive 
support\n");
diff -urwN clamav-0.70-orig/clamscan/manager.c 
clamav-0.70-virus-skips/clamscan/manager.c
--- clamav-0.70-orig/clamscan/manager.c Fri Apr 16 11:26:54 2004
+++ clamav-0.70-virus-skips/clamscan/manager.c  Fri Apr 23 14:46:15 2004
@@ -369,6 +369,12 @@
     if(optc(opt, 'm'))
        options |= CL_MAIL;
 
+    if(optc(opt, 'M') || optl(opt,"mail")) {
+       options |= CL_MAIL;
+       options |= CL_UNKNOWN_MAIL;
+    }
+       
+
     /* 
      * check the extension  - this is a special case, normally we don't need to
      * do this (libclamav detects archive by its magic string), but here we
diff -urwN clamav-0.70-orig/clamscan/options.c 
clamav-0.70-virus-skips/clamscan/options.c
--- clamav-0.70-orig/clamscan/options.c Fri Apr 16 11:30:35 2004
+++ clamav-0.70-virus-skips/clamscan/options.c  Fri Apr 23 10:32:38 2004
@@ -43,7 +43,7 @@
        int ret, opt_index, i, len;
        struct optstruct *opt;
 
-       const char *getopt_parameters = "hvd:wriVl:m";
+       const char *getopt_parameters = "hvd:wriVl:mM";
 
        static struct option long_options[] = {
            /* 
@@ -81,6 +81,8 @@
            {"block-encrypted", 0, 0, 0},
            {"no-ole2", 0, 0, 0},
            {"mbox", 0, 0, 'm'},
+           {"mbox-force", 0, 0, 'M'},
+           {"mail", 0, 0, 0},
            {"stdout", 0, 0, 0},
            {"unzip", 2, 0, 0},
            {"unrar", 2, 0, 0},
diff -urwN clamav-0.70-orig/libclamav/clamav.h 
clamav-0.70-virus-skips/libclamav/clamav.h
--- clamav-0.70-orig/libclamav/clamav.h Wed Mar 31 02:03:35 2004
+++ clamav-0.70-virus-skips/libclamav/clamav.h  Fri Apr 23 14:41:22 2004
@@ -69,6 +69,7 @@
 #define CL_DISABLERAR  4
 #define CL_OLE2                8
 #define CL_ENCRYPTED    16
+#define CL_UNKNOWN_MAIL        32
 
 struct cli_patt {
     short int *pattern;
diff -urwN clamav-0.70-orig/libclamav/scanners.c 
clamav-0.70-virus-skips/libclamav/scanners.c
--- clamav-0.70-orig/libclamav/scanners.c       Fri Apr 16 08:12:09 2004
+++ clamav-0.70-virus-skips/libclamav/scanners.c        Fri Apr 23 14:42:12 2004
@@ -58,6 +58,7 @@
 #define SCAN_OLE2          (options & CL_OLE2)
 #define DISABLE_RAR        (options & CL_DISABLERAR)
 #define DETECT_ENCRYPTED    (options & CL_ENCRYPTED)
+#define SCAN_UNKNOWN_MAIL    (options & CL_UNKNOWN_MAIL)
 
 struct cli_magic_s {
     int offset;
@@ -822,6 +823,10 @@
        }
 
        type = cli_filetype(magic, bread);
+
+       if(type == CL_UNKNOWN_TYPE && SCAN_UNKNOWN_MAIL)
+               type = CL_MAILFILE;
+               
 
        switch(type) {
            case CL_RARFILE:
diff -urwN clamav-0.70-orig/shared/cfgparser.c 
clamav-0.70-virus-skips/shared/cfgparser.c
--- clamav-0.70-orig/shared/cfgparser.c Fri Apr 16 11:25:02 2004
+++ clamav-0.70-virus-skips/shared/cfgparser.c  Fri Apr 23 14:31:31 2004
@@ -62,6 +62,7 @@
            {"TemporaryDirectory", OPT_STR},
            {"MaxFileSize", OPT_COMPSIZE},
            {"ScanMail", OPT_NOARG},
+           {"ScanUnknownAsMail", OPT_NOARG},
            {"ScanOLE2", OPT_NOARG},
            {"ScanArchive", OPT_NOARG},
            {"ScanRAR", OPT_NOARG},

Reply via email to