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},