For documentation on this see: http://www.davideous.com/misc/qmail-smtpd-viruscan-1.3-with-zip-subject-0.2.patch diff -rNu3 qmail-1.03.viruscan/qmail-smtpd.c qmail-1.03.viruscan.zipsubject/qmail-smtpd.c --- qmail-1.03.viruscan/qmail-smtpd.c Thu Feb 5 12:28:25 2004 +++ qmail-1.03.viruscan.zipsubject/qmail-smtpd.c Thu Feb 5 15:02:02 2004 @@ -98,6 +98,11 @@ struct constmap mapbmf; int sigsok = 0; stralloc sigs = {0}; +int sigzipsok = 0; +stralloc sigzips = {0}; +int sigzipsubjsok = 0; +stralloc sigzipsubjs = {0}; +struct constmap mapsigzipsubjs; void setup() { @@ -121,6 +126,16 @@ sigsok = control_readfile(&sigs,"control/signatures",0); if (sigsok == -1) die_control(); + + sigzipsok = control_readfile(&sigzips,"control/signatures.zip",0); + if (sigzipsok == -1) die_control(); + + sigzipsubjsok = control_readfile(&sigzipsubjs,"control/signatures.zip.subjects",0); + if (sigzipsubjsok == -1) die_control(); + if (sigzipsubjsok) { + case_lowerb(sigzipsubjs.s,sigzipsubjs.len); /* make matching case-insensetive */ + if (!constmap_init(&mapsigzipsubjs,sigzipsubjs.s,sigzipsubjs.len,0)) die_nomem(); + } if (control_readint(&databytes,"control/databytes") == -1) die_control(); x = env_get("DATABYTES"); @@ -213,19 +228,32 @@ return 0; } -int sigscheck(stralloc *line) { +int matchline(stralloc *line, stralloc *controlfile) { int i, j; j = 0; - for (i = 0; i < sigs.len; i++) if (!sigs.s[i]) { + for (i = 0; i < controlfile->len; i++) if (!controlfile->s[i]) { if (i-j < line->len) - if (!str_diffn(line->s,sigs.s+j,i-j)) + if (!str_diffn(line->s,controlfile->s+j,i-j)) return 1; j = i+1; } return 0; } +int sigscheck(stralloc *line) { + if (!sigsok) return 0; + return matchline(line, &sigs); +} + +int sigzipscheck(stralloc *line, stralloc *subject) { + if (!sigzipsok) return 0; + if (!sigzipsubjsok) return 0; + if (!constmap(&mapsigzipsubjs,subject->s,subject->len)) return 0; + if (!matchline(line, &sigzips)) return 0; + return 1; +} + int addrallowed() { int r; @@ -303,10 +331,12 @@ /* until blank line */ char linetype; int flagexecutable; +int flagbadzip; int flagqsbmf; stralloc line = {0}; stralloc content = {0}; +stralloc subject = {0}; stralloc boundary = {0}; int boundary_start; @@ -400,6 +430,14 @@ if (case_startb(line.s,line.len,"content-type:")) { if (!stralloc_copyb(&content,line.s+13,line.len-14)) die_nomem(); linetype = 'C'; + } else if (case_startb(line.s,line.len,"subject:")) { + cp = line.s+8; + len = line.len-9; + while (len && (*cp == ' ' || *cp == '\t')) { ++cp; --len; } + if (!stralloc_copyb(&subject,cp,len)) die_nomem(); + /* this subject line parser is broken in that it does not handle heards that + continue onto new lines, but it will do for now */ + case_lowerb(subject.s,subject.len); /* make matching case-insensetive */ } else { linetype = ' '; } @@ -431,6 +469,10 @@ flagexecutable = 1; qmail_fail(&qqt); } + else if (sigzipscheck(&line, &subject)) { + flagbadzip = 1; + qmail_fail(&qqt); + } linespastheader = 2; } if (flagqsbmf && str_start(line.s,"---")) { @@ -533,8 +575,10 @@ boundary.len = 0; boundary_start = 0; content.len = 0; + subject.len = 0; linespastheader = 0; flagexecutable = 0; + flagbadzip = 0; flagqsbmf = 0; linetype = ' '; if (qmail_open(&qqt) == -1) { err_qqt(); return; } @@ -553,6 +597,7 @@ if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; } if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; } if (flagexecutable) { out("552 we don't accept email with executable content (#5.3.4)\r\n"); return; } + if (flagbadzip) { out("552 we don't accept zip files with this subject; looks like a virus (#5.3.4)\r\n"); return; } if (*qqx == 'D') out("554 "); else out("451 "); out(qqx + 1); out("\r\n");