diff -Naur qmail-1.03/FILES qmail-1.03-jbuce/FILES --- qmail-1.03/FILES Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/FILES Tue Aug 18 16:22:34 1998 @@ -80,6 +80,7 @@ qmail-log.5 qmail-lspawn.8 qmail-newmrh.9 +qmail-newbmf.9 qmail-newu.9 qmail-pop3d.8 qmail-popup.8 @@ -111,6 +112,7 @@ qmail-local.c qmail-lspawn.c qmail-newmrh.c +qmail-newbmf.c qmail-newu.c qmail-pop3d.c qmail-popup.c diff -Naur qmail-1.03/Makefile qmail-1.03-jbuce/Makefile --- qmail-1.03/Makefile Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/Makefile Tue Aug 18 16:22:17 1998 @@ -803,7 +803,7 @@ predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \ qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \ qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \ -qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \ +qmail-smtpd sendmail tcp-env qmail-newmrh qmail-newbmf config config-fast dnscname \ dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \ forward preline condredirect bouncesaying except maildirmake \ maildir2mbox maildirwatch qail elq pinq idedit install-big install \ @@ -930,7 +930,7 @@ qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newu.0 \ qmail-pw2u.0 qmail-qread.0 qmail-qstat.0 qmail-tcpto.0 qmail-tcpok.0 \ qmail-pop3d.0 qmail-popup.0 qmail-qmqpc.0 qmail-qmqpd.0 qmail-qmtpd.0 \ -qmail-smtpd.0 tcp-env.0 qmail-newmrh.0 qreceipt.0 qbiff.0 forward.0 \ +qmail-smtpd.0 tcp-env.0 qmail-newmrh.0 qmail-newbmf.0 qreceipt.0 qbiff.0 forward.0 \ preline.0 condredirect.0 bouncesaying.0 except.0 maildirmake.0 \ maildir2mbox.0 maildirwatch.0 qmail.0 qmail-limits.0 qmail-log.0 \ qmail-control.0 qmail-header.0 qmail-users.0 dot-qmail.0 \ @@ -1216,6 +1216,31 @@ slurpclose.h auto_qmail.h auto_uids.h qlx.h ./compile qmail-lspawn.c +qmail-newbmf: \ +load qmail-newbmf.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \ +stralloc.a alloc.a strerr.a substdio.a error.a str.a auto_qmail.o + ./load qmail-newbmf cdbmss.o getln.a open.a cdbmake.a \ + seek.a case.a stralloc.a alloc.a strerr.a substdio.a \ + error.a str.a auto_qmail.o + +qmail-newbmf.0: \ +qmail-newbmf.8 + nroff -man qmail-newbmf.8 > qmail-newbmf.0 + +qmail-newbmf.8: \ +qmail-newbmf.9 conf-break conf-spawn + cat qmail-newbmf.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-newbmf.8 + +qmail-newbmf.o: \ +compile qmail-newbmf.c strerr.h stralloc.h gen_alloc.h substdio.h \ +getln.h exit.h readwrite.h open.h auto_qmail.h cdbmss.h cdbmake.h \ +uint32.h substdio.h + ./compile qmail-newbmf.c + qmail-newmrh: \ load qmail-newmrh.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \ stralloc.a alloc.a strerr.a substdio.a error.a str.a auto_qmail.o @@ -1536,13 +1561,13 @@ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \ date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \ open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \ -fs.a auto_qmail.o socket.lib +fs.a auto_qmail.o dns.o dns.lib socket.lib syslog.lib ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \ received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \ datetime.a getln.a open.a sig.a case.a env.a stralloc.a \ - alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \ - socket.lib` + alloc.a substdio.a error.a str.a fs.a auto_qmail.o dns.o \ + `cat dns.lib` `cat socket.lib` `cat syslog.lib` qmail-smtpd.0: \ qmail-smtpd.8 diff -Naur qmail-1.03/README.jbuce qmail-1.03-jbuce/README.jbuce --- qmail-1.03/README.jbuce Wed Dec 31 19:00:00 1969 +++ qmail-1.03-jbuce/README.jbuce Fri Oct 2 22:03:09 1998 @@ -0,0 +1,54 @@ +From: Jonathan@NrgUp.Com +Subject: UCE patches for QMAIL 1.03 (Rev A) +Date: October 1, 1998 + +Qmail is an excellent MTA and once you start seeing the possibilities +that Dan has provided you want more. These patches combine existing +patches and my own additions to do the following: + +date822fmt.c: + o Use local date instead of GMT in envelope + +dns.c: + o Allow large DNS responses + o Allow MAPS RBL lookups + +qmail-newbmf.c: + o Creates badmailfrom.cdb used by qmail-smtpd. This allows for large + badmailfrom files without the performance overhead issues + +qmail-send.c: + o Restrict bounces to 50,000 bytes (can be set in control/bouncemaxbytes) + +qmail-smtpd.c: + o Use syslog for mail session diagnostics instead of STDERR + o Use badmailfrom.cdb instead of badmailfrom if exists + o All domains in MAIL FROM are checked to ensure MX record exists + o Built in exceptions for "abuse" and "postmaster" accounts + o Restrict use of "%" in RCPT TO unless percenthack file has domain listed + o Checks BOUNCEMAIL environment variable (set in tcp-env) for RBL + o New file 'control/badmailpatterns' allows use of regular expressions to + restrict MAIL FROM:. Use "!" at the beginning of the line to reverse + the match. Example: + !@compuserve.com + ^[0-9]+@aol.com + ^[0-9][0-9][0-9]+ + +tcp-env.c: + o Check connecting host against RBL (maps.vix.com) and set BOUNCEMAIL + o Check connecting host against Dorkslayers (.orbs.dorkslayers.com) and set + BOUCEMAIL (this is disabled by default, uncomment to enable). + +Thanks to Andrew Pam for modifying the patch for qmail 1.02. + +This patch is freely distributable. However, by implementing it you agree +that if it breaks ANYTHING, you get to keep both halves. I am NOT responsible +for your use of this patch. Test it on a non-production system FIRST etc. + +Many thanks to the original authors of Qmail patches for their work and +to Dan for the great QMAIL product (http://www.qmail.org/) + +For an example badmailfrom file, check you can check out: + + ftp://garbo.nrgup.com/pub/badmailfrom + diff -Naur qmail-1.03/TARGETS qmail-1.03-jbuce/TARGETS --- qmail-1.03/TARGETS Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/TARGETS Tue Aug 18 16:21:33 1998 @@ -259,6 +259,8 @@ tcp-env qmail-newmrh.o qmail-newmrh +qmail-newbmf.o +qmail-newbmf config config-fast dnscname.o diff -Naur qmail-1.03/date822fmt.c qmail-1.03-jbuce/date822fmt.c --- qmail-1.03/date822fmt.c Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/date822fmt.c Fri Jul 17 21:00:31 1998 @@ -1,3 +1,4 @@ +#include #include "datetime.h" #include "fmt.h" #include "date822fmt.h" @@ -12,18 +13,51 @@ { unsigned int i; unsigned int len; + time_t now; + datetime_sec utc; + datetime_sec local; + struct tm *tm; + struct datetime new_dt; + int minutes; + + utc = datetime_untai(dt); + now = (time_t)utc; + tm = localtime(&now); + new_dt.year = tm->tm_year; + new_dt.mon = tm->tm_mon; + new_dt.mday = tm->tm_mday; + new_dt.hour = tm->tm_hour; + new_dt.min = tm->tm_min; + new_dt.sec = tm->tm_sec; + local = datetime_untai(&new_dt); + len = 0; - i = fmt_uint(s,dt->mday); len += i; if (s) s += i; + i = fmt_uint(s,new_dt.mday); len += i; if (s) s += i; i = fmt_str(s," "); len += i; if (s) s += i; - i = fmt_str(s,montab[dt->mon]); len += i; if (s) s += i; + i = fmt_str(s,montab[new_dt.mon]); len += i; if (s) s += i; i = fmt_str(s," "); len += i; if (s) s += i; - i = fmt_uint(s,dt->year + 1900); len += i; if (s) s += i; + i = fmt_uint(s,new_dt.year + 1900); len += i; if (s) s += i; i = fmt_str(s," "); len += i; if (s) s += i; - i = fmt_uint0(s,dt->hour,2); len += i; if (s) s += i; + i = fmt_uint0(s,new_dt.hour,2); len += i; if (s) s += i; i = fmt_str(s,":"); len += i; if (s) s += i; - i = fmt_uint0(s,dt->min,2); len += i; if (s) s += i; + i = fmt_uint0(s,new_dt.min,2); len += i; if (s) s += i; i = fmt_str(s,":"); len += i; if (s) s += i; - i = fmt_uint0(s,dt->sec,2); len += i; if (s) s += i; - i = fmt_str(s," -0000\n"); len += i; if (s) s += i; + i = fmt_uint0(s,new_dt.sec,2); len += i; if (s) s += i; + + if (local < utc) { + minutes = (utc - local + 30) / 60; + i = fmt_str(s," -"); len += i; if (s) s += i; + i = fmt_uint0(s,minutes / 60,2); len += i; if (s) s += i; + i = fmt_uint0(s,minutes % 60,2); len += i; if (s) s += i; + } + else { + minutes = (local - utc + 30) / 60; + i = fmt_str(s," +"); len += i; if (s) s += i; + i = fmt_uint0(s,minutes / 60,2); len += i; if (s) s += i; + i = fmt_uint0(s,minutes % 60,2); len += i; if (s) s += i; + } + + i = fmt_str(s,"\n"); len += i; if (s) s += i; + return len; } diff -Naur qmail-1.03/dns.c qmail-1.03-jbuce/dns.c --- qmail-1.03/dns.c Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/dns.c Fri Oct 2 21:46:01 1998 @@ -21,10 +21,12 @@ static unsigned short getshort(c) unsigned char *c; { unsigned short u; u = c[0]; return (u << 8) + c[1]; } -static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response; +static struct { unsigned char *buf; } response; +static int responsebuflen = 0; static int responselen; static unsigned char *responseend; static unsigned char *responsepos; +static u_long saveresoptions; static int numanswers; static char name[MAXDNAME]; @@ -45,18 +47,31 @@ errno = 0; if (!stralloc_copy(&glue,domain)) return DNS_MEM; if (!stralloc_0(&glue)) return DNS_MEM; - responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response)); + if (!responsebuflen) + if (response.buf = (unsigned char *)alloc(PACKETSZ+1)) + responsebuflen = PACKETSZ+1; + else return DNS_MEM; + responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); + if ((responselen > PACKETSZ) || (((HEADER *)response.buf)->tc)) + { + if (responsebuflen < 65536) + if (alloc_re(&response.buf, responsebuflen, 65536)) + responsebuflen = 65536; + else return DNS_MEM; + saveresoptions = _res.options; + _res.options |= RES_USEVC; + responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); + _res.options = saveresoptions; + } if (responselen <= 0) { if (errno == ECONNREFUSED) return DNS_SOFT; if (h_errno == TRY_AGAIN) return DNS_SOFT; return DNS_HARD; } - if (responselen >= sizeof(response)) - responselen = sizeof(response); responseend = response.buf + responselen; responsepos = response.buf + sizeof(HEADER); - n = ntohs(response.hdr.qdcount); + n = ntohs(((HEADER *)response.buf)->qdcount); while (n-- > 0) { i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); @@ -66,7 +81,7 @@ if (i < QFIXEDSZ) return DNS_SOFT; responsepos += QFIXEDSZ; } - numanswers = ntohs(response.hdr.ancount); + numanswers = ntohs(((HEADER *)response.buf)->ancount); return 0; } @@ -104,6 +119,43 @@ return 0; } +static int findstring(wanttype) +int wanttype; +{ + unsigned short rrtype; + unsigned short rrdlen; + int i; + + if (numanswers <= 0) return 2; + --numanswers; + if (responsepos == responseend) return DNS_SOFT; + + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + + i = responseend - responsepos; + if (i < 4 + 3 * 2) return DNS_SOFT; + + rrtype = getshort(responsepos); + rrdlen = getshort(responsepos + 8); + responsepos += 10; + + if (rrtype == wanttype) + { + i = *responsepos; + if (i > MAXDNAME - 1) return DNS_SOFT; + if (responsepos + i > responseend) return DNS_SOFT; + byte_copy(name, i, responsepos+1); + name[i] = '\0'; + responsepos += rrdlen; + return 1; + } + + responsepos += rrdlen; + return 0; +} + static int findip(wanttype) int wanttype; { @@ -219,9 +271,10 @@ #define FMT_IAA 40 -static int iaafmt(s,ip) +static int iaafmt(s,ip,dom) char *s; struct ip_address *ip; +const char *dom; { unsigned int i; unsigned int len; @@ -233,7 +286,7 @@ i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i; i = fmt_str(s,"."); len += i; if (s) s += i; i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i; - i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i; + i = fmt_str(s,dom); len += i; if (s) s += i; return len; } @@ -243,8 +296,8 @@ { int r; - if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM; - sa->len = iaafmt(sa->s,ip); + if (!stralloc_ready(sa,iaafmt((char *) 0,ip,".in-addr.arpa."))) return DNS_MEM; + sa->len = iaafmt(sa->s,ip,".in-addr.arpa."); switch(resolve(sa,T_PTR)) { case DNS_MEM: return DNS_MEM; @@ -252,6 +305,33 @@ case DNS_HARD: return DNS_HARD; } while ((r = findname(T_PTR)) != 2) + { + if (r == DNS_SOFT) return DNS_SOFT; + if (r == 1) + { + if (!stralloc_copys(sa,name)) return DNS_MEM; + return 0; + } + } + return DNS_HARD; +} + +int dns_maps(sa,ip,dom) +stralloc *sa; +struct ip_address *ip; +const char *dom; +{ + int r; + + if (!stralloc_ready(sa,iaafmt((char *) 0,ip,dom))) return DNS_MEM; + sa->len = iaafmt(sa->s,ip,dom); + switch(resolve(sa,T_TXT)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return DNS_HARD; + } + while ((r = findstring(T_TXT)) != 2) { if (r == DNS_SOFT) return DNS_SOFT; if (r == 1) diff -Naur qmail-1.03/hier.c qmail-1.03-jbuce/hier.c --- qmail-1.03/hier.c Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/hier.c Tue Aug 18 16:34:21 1998 @@ -111,6 +111,7 @@ c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711); c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700); c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-newbmf",auto_uido,auto_gidq,0700); c(auto_qmail,"bin","qmail-pw2u",auto_uido,auto_gidq,0711); c(auto_qmail,"bin","qmail-inject",auto_uido,auto_gidq,0755); c(auto_qmail,"bin","predate",auto_uido,auto_gidq,0755); diff -Naur qmail-1.03/install-big.c qmail-1.03-jbuce/install-big.c --- qmail-1.03/install-big.c Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/install-big.c Tue Aug 18 16:32:28 1998 @@ -111,6 +111,7 @@ c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711); c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700); c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-newbmf",auto_uido,auto_gidq,0700); c(auto_qmail,"bin","qmail-pw2u",auto_uido,auto_gidq,0711); c(auto_qmail,"bin","qmail-inject",auto_uido,auto_gidq,0755); c(auto_qmail,"bin","predate",auto_uido,auto_gidq,0755); diff -Naur qmail-1.03/qmail-control.9 qmail-1.03-jbuce/qmail-control.9 --- qmail-1.03/qmail-control.9 Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/qmail-control.9 Wed Jun 24 03:59:12 1998 @@ -21,6 +21,8 @@ Comments are allowed in .IR badmailfrom , +.IR badmailpatterns , +.IR badrcptto , .IR locals , .IR percenthack , .IR qmqpservers , @@ -41,6 +43,8 @@ control default used by .I badmailfrom \fR(none) \fRqmail-smtpd +.I badmailpatterns \fR(none) \fRqmail-smtpd +.I badrcptto \fR(none) \fRqmail-smtpd .I bouncefrom \fRMAILER-DAEMON \fRqmail-send .I bouncehost \fIme \fRqmail-send .I concurrencylocal \fR10 \fRqmail-send diff -Naur qmail-1.03/qmail-newbmf.0 qmail-1.03-jbuce/qmail-newbmf.0 --- qmail-1.03/qmail-newbmf.0 Wed Dec 31 19:00:00 1969 +++ qmail-1.03-jbuce/qmail-newbmf.0 Tue Aug 18 16:30:49 1998 @@ -0,0 +1,66 @@ + + + +qmail-newbmf(8) qmail-newbmf(8) + + +NNAAMMEE + qmail-newbmf - prepare morebadmailfrom for qmail-smtpd + +SSYYNNOOPPSSIISS + qqmmaaiill--nneewwbbmmff + +DDEESSCCRRIIPPTTIIOONN + qqmmaaiill--nneewwbbmmff reads the instructions in //vvaarr//qqmmaaiill//ccoonn-- + ttrrooll//bbaaddmmaaiillffrroomm and writes them into //vvaarr//qqmmaaiill//ccoonn-- + ttrrooll//bbaaddmmaaiillffrroomm..ccddbb in a binary format suited for quick + access by qqmmaaiill--ssmmttppdd. + + If there is a problem with ccoonnttrrooll//bbaaddmmaaiillffrroomm, qqmmaaiill-- + nneewwbbmmff complains and leaves ccoonnttrrooll//bbaaddmmaaiillffrroomm..ccddbb alone. + + qqmmaaiill--nneewwbbmmff ensures that ccoonnttrrooll//bbaaddmmaaiillffrroomm..ccddbb is + updated atomically, so qqmmaaiill--ssmmttppdd never has to wait for + qqmmaaiill--nneewwbbmmff to finish. However, qqmmaaiill--nneewwbbmmff makes no + attempt to protect against two simultaneous updates of + ccoonnttrrooll//bbaaddmmaaiillffrroomm..ccddbb. + + The binary ccoonnttrrooll//bbaaddmmaaiillffrroomm..ccddbb format is portable + across machines. + +SSEEEE AALLSSOO + qmail-smtpd(8) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + diff -Naur qmail-1.03/qmail-newbmf.8 qmail-1.03-jbuce/qmail-newbmf.8 --- qmail-1.03/qmail-newbmf.8 Wed Dec 31 19:00:00 1969 +++ qmail-1.03-jbuce/qmail-newbmf.8 Tue Aug 18 16:30:48 1998 @@ -0,0 +1,41 @@ +.TH qmail-newbmf 8 +.SH NAME +qmail-newbmf \- prepare morebadmailfrom for qmail-smtpd +.SH SYNOPSIS +.B qmail-newbmf +.SH DESCRIPTION +.B qmail-newbmf +reads the instructions in +.B /var/qmail/control/badmailfrom +and writes them into +.B /var/qmail/control/badmailfrom.cdb +in a binary format suited +for quick access by +.BR qmail-smtpd . + +If there is a problem with +.BR control/badmailfrom , +.B qmail-newbmf +complains and leaves +.B control/badmailfrom.cdb +alone. + +.B qmail-newbmf +ensures that +.B control/badmailfrom.cdb +is updated atomically, +so +.B qmail-smtpd +never has to wait for +.B qmail-newbmf +to finish. +However, +.B qmail-newbmf +makes no attempt to protect against two simultaneous updates of +.BR control/badmailfrom.cdb . + +The binary +.B control/badmailfrom.cdb +format is portable across machines. +.SH "SEE ALSO" +qmail-smtpd(8) diff -Naur qmail-1.03/qmail-newbmf.9 qmail-1.03-jbuce/qmail-newbmf.9 --- qmail-1.03/qmail-newbmf.9 Wed Dec 31 19:00:00 1969 +++ qmail-1.03-jbuce/qmail-newbmf.9 Tue Aug 18 16:22:56 1998 @@ -0,0 +1,41 @@ +.TH qmail-newbmf 8 +.SH NAME +qmail-newbmf \- prepare morebadmailfrom for qmail-smtpd +.SH SYNOPSIS +.B qmail-newbmf +.SH DESCRIPTION +.B qmail-newbmf +reads the instructions in +.B /var/qmail/control/badmailfrom +and writes them into +.B /var/qmail/control/badmailfrom.cdb +in a binary format suited +for quick access by +.BR qmail-smtpd . + +If there is a problem with +.BR control/badmailfrom , +.B qmail-newbmf +complains and leaves +.B control/badmailfrom.cdb +alone. + +.B qmail-newbmf +ensures that +.B control/badmailfrom.cdb +is updated atomically, +so +.B qmail-smtpd +never has to wait for +.B qmail-newbmf +to finish. +However, +.B qmail-newbmf +makes no attempt to protect against two simultaneous updates of +.BR control/badmailfrom.cdb . + +The binary +.B control/badmailfrom.cdb +format is portable across machines. +.SH "SEE ALSO" +qmail-smtpd(8) diff -Naur qmail-1.03/qmail-newbmf.c qmail-1.03-jbuce/qmail-newbmf.c --- qmail-1.03/qmail-newbmf.c Wed Dec 31 19:00:00 1969 +++ qmail-1.03-jbuce/qmail-newbmf.c Tue Aug 18 16:18:25 1998 @@ -0,0 +1,70 @@ +#include "strerr.h" +#include "stralloc.h" +#include "substdio.h" +#include "getln.h" +#include "exit.h" +#include "readwrite.h" +#include "open.h" +#include "auto_qmail.h" +#include "cdbmss.h" + +#define FATAL "qmail-newbmf: fatal: " + +void die_read() +{ + strerr_die2sys(111,FATAL,"unable to read control/badmailfrom: "); +} +void die_write() +{ + strerr_die2sys(111,FATAL,"unable to write to control/badmailfrom.tmp: "); +} + +char inbuf[1024]; +substdio ssin; + +int fd; +int fdtemp; + +struct cdbmss cdbmss; +stralloc line = {0}; +int match; + +void main() +{ + umask(033); + if (chdir(auto_qmail) == -1) + strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": "); + + fd = open_read("control/badmailfrom"); + if (fd == -1) die_read(); + + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf); + + fdtemp = open_trunc("control/badmailfrom.tmp"); + if (fdtemp == -1) die_write(); + + if (cdbmss_start(&cdbmss,fdtemp) == -1) die_write(); + + for (;;) { + if (getln(&ssin,&line,&match,'\n') != 0) die_read(); + case_lowerb(line.s,line.len); + while (line.len) { + if (line.s[line.len - 1] == ' ') { --line.len; continue; } + if (line.s[line.len - 1] == '\n') { --line.len; continue; } + if (line.s[line.len - 1] == '\t') { --line.len; continue; } + if (line.s[0] != '#') + if (cdbmss_add(&cdbmss,line.s,line.len,"",0) == -1) + die_write(); + break; + } + if (!match) break; + } + + if (cdbmss_finish(&cdbmss) == -1) die_write(); + if (fsync(fdtemp) == -1) die_write(); + if (close(fdtemp) == -1) die_write(); /* NFS stupidity */ + if (rename("control/badmailfrom.tmp","control/badmailfrom.cdb") == -1) + strerr_die2sys(111,FATAL,"unable to move control/badmailfrom.tmp to control/badmailfrom.cdb"); + + _exit(0); +} diff -Naur qmail-1.03/qmail-send.c qmail-1.03-jbuce/qmail-send.c --- qmail-1.03/qmail-send.c Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/qmail-send.c Wed Jun 24 18:13:39 1998 @@ -44,6 +44,8 @@ int lifetime = 604800; +int bouncemaxbytes = 50000; + stralloc percenthack = {0}; struct constmap mappercenthack; stralloc locals = {0}; @@ -740,9 +742,17 @@ qmail_fail(&qqt); else { + int bytestogo = bouncemaxbytes; + int bytestoget = (bytestogo < sizeof buf) ? bytestogo : sizeof buf; substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf)); - while ((r = substdio_get(&ssread,buf,sizeof(buf))) > 0) + while (bytestoget > 0 && (r = substdio_get(&ssread,buf,bytestoget)) > 0) { qmail_put(&qqt,buf,r); + bytestogo -= bytestoget; + bytestoget = (bytestogo < sizeof buf) ? bytestogo : sizeof buf; + } + if (r > 0) { + qmail_puts(&qqt,"\n\n--- End of message stripped.\n"); + } close(fd); if (r == -1) qmail_fail(&qqt); @@ -1442,6 +1452,7 @@ /* this file is too long ---------------------------------------------- MAIN */ int getcontrols() { if (control_init() == -1) return 0; + if (control_readint(&bouncemaxbytes,"control/bouncemaxbytes") == -1) return 0; if (control_readint(&lifetime,"control/queuelifetime") == -1) return 0; if (control_readint(&concurrency[0],"control/concurrencylocal") == -1) return 0; if (control_readint(&concurrency[1],"control/concurrencyremote") == -1) return 0; diff -Naur qmail-1.03/qmail-showctl.c qmail-1.03-jbuce/qmail-showctl.c --- qmail-1.03/qmail-showctl.c Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/qmail-showctl.c Tue Aug 18 16:06:48 1998 @@ -142,6 +142,7 @@ direntry *d; struct stat stmrh; struct stat stmrhcdb; + struct stat stbmf; substdio_puts(subfdout,"qmail home directory: "); substdio_puts(subfdout,auto_qmail); @@ -214,12 +215,12 @@ _exit(111); } - do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM."); do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is "); do_str("bouncehost",1,"bouncehost","Bounce host name is "); do_int("concurrencylocal","10","Local concurrency is ",""); do_int("concurrencyremote","20","Remote concurrency is ",""); do_int("databytes","0","SMTP DATA limit is "," bytes"); + do_int("maxbouncebytes","50000","Bounce DATA limit is "," bytes"); do_str("defaultdomain",1,"defaultdomain","Default domain name is "); do_str("defaulthost",1,"defaulthost","Default host name is "); do_str("doublebouncehost",1,"doublebouncehost","2B recipient host: "); @@ -234,6 +235,12 @@ do_str("plusdomain",1,"plusdomain","Plus domain name is "); do_lst("qmqpservers","No QMQP servers.","QMQP server: ","."); do_int("queuelifetime","604800","Message lifetime in the queue is "," seconds"); + /* do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM."); */ + if (stat("badmailfrom",&stbmf) == -1) + substdio_puts(subfdout,"\nbadmailfrom: Any MAIL FROM is allowed.\n"); + else + substdio_puts(subfdout,"\nbadmailfrom: MAIL FROM in badmailfrom file is not allowed.\n"); + do_lst("badmailpatterns","Any MAIL FROM pattern is allowed.",""," pattern not accepted in MAIL FROM."); if (do_lst("rcpthosts","SMTP clients may send messages to any recipient.","SMTP clients may send messages to recipients at ",".")) do_lst("morercpthosts","No effect.","SMTP clients may send messages to recipients at ","."); @@ -262,17 +269,20 @@ do_int("timeoutsmtpd","1200","SMTP server data timeout is "," seconds"); do_lst("virtualdomains","No virtual domains.","Virtual domain: ",""); + while (d = readdir(dir)) { if (str_equal(d->d_name,".")) continue; if (str_equal(d->d_name,"..")) continue; if (str_equal(d->d_name,"bouncefrom")) continue; if (str_equal(d->d_name,"bouncehost")) continue; if (str_equal(d->d_name,"badmailfrom")) continue; + if (str_equal(d->d_name,"badmailpatterns")) continue; if (str_equal(d->d_name,"bouncefrom")) continue; if (str_equal(d->d_name,"bouncehost")) continue; if (str_equal(d->d_name,"concurrencylocal")) continue; if (str_equal(d->d_name,"concurrencyremote")) continue; if (str_equal(d->d_name,"databytes")) continue; + if (str_equal(d->d_name,"maxbouncebytes")) continue; if (str_equal(d->d_name,"defaultdomain")) continue; if (str_equal(d->d_name,"defaulthost")) continue; if (str_equal(d->d_name,"doublebouncehost")) continue; diff -Naur qmail-1.03/qmail-smtpd.c qmail-1.03-jbuce/qmail-smtpd.c --- qmail-1.03/qmail-smtpd.c Fri Oct 2 21:54:50 1998 +++ qmail-1.03-jbuce/qmail-smtpd.c Fri Oct 2 21:55:00 1998 @@ -19,10 +19,20 @@ #include "env.h" #include "now.h" #include "exit.h" +#include "dns.h" #include "rcpthosts.h" #include "timeoutread.h" #include "timeoutwrite.h" #include "commands.h" +#include "cdb.h" + +/* Include support for syslog and regular expression matching */ +#ifdef __amigaos__ /* Work around syslog.h bug. */ +#include +#endif +#include +#include +#include #define MAXHOPS 100 unsigned int databytes = 0; @@ -39,17 +49,50 @@ char ssoutbuf[512]; substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); +char *remoteip; +char *remotehost; +char *remoteinfo; +char *local; +char *relayclient; +char *bouncemail; /* for new BOUNCEMAIL environment variable */ + void flush() { substdio_flush(&ssout); } void out(s) char *s; { substdio_puts(&ssout,s); } void die_read() { _exit(1); } -void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); } -void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); } -void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); } -void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); } -void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); } +void die_alarm() +{ + syslog (LOG_INFO, "Connection to %s timed out.\n", remoteip); + out("451 timeout (#4.4.2)\r\n"); flush(); closelog(); _exit(1); +} +void die_nomem() +{ + syslog (LOG_ERR, "Out of memory while connected to %s!\n", remoteip); + out("421 out of memory (#4.3.0)\r\n"); flush(); closelog(); _exit(1); +} +void die_control() +{ + syslog (LOG_ERR, "Unable to read controls!\n"); + out("421 unable to read controls (#4.3.0)\r\n"); flush(); closelog(); + _exit(1); +} +void die_ipme() +{ + syslog (LOG_ERR, "Unable to figure out my IP addresses!\n"); + out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); + closelog(); _exit(1); +} +void straynewline() +{ + syslog (LOG_INFO, "Stray newline while connected to %s.\n", remoteip); + out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); + closelog(); _exit(1); +} -void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); } +void err_mailfrom() { out("553 sorry, envelope sender must have a valid domain name (#5.7.1)\r\n"); } +void err_bmf() { out("553 sorry, envelope sender is blocked, please contact postmaster (#5.7.1)\r\n"); } +void err_dns() { out("451 DNS temporary failure (#4.3.0)\r\n"); } +void err_maps(char *m) { out("553 "); out(m);out("\r\n"); } void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); } void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); } void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); } @@ -76,12 +119,6 @@ smtp_greet("221 "); out("\r\n"); flush(); _exit(0); } -char *remoteip; -char *remotehost; -char *remoteinfo; -char *local; -char *relayclient; - stralloc helohost = {0}; char *fakehelo; /* pointer into helohost, or 0 */ @@ -96,6 +133,11 @@ int bmfok = 0; stralloc bmf = {0}; struct constmap mapbmf; +int bmpok = 0; /* for new control/badmailpatterns file using regex */ +stralloc bmp = {0}; +int fdbmf; /* cdb version for morebadmailfrom.cdb */ +stralloc percenthack = {0}; +struct constmap mappercenthack; void setup() { @@ -112,10 +154,22 @@ if (rcpthosts_init() == -1) die_control(); - bmfok = control_readfile(&bmf,"control/badmailfrom",0); - if (bmfok == -1) die_control(); - if (bmfok) - if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem(); + fdbmf = open_read("control/badmailfrom.cdb"); + if (fdbmf == -1) { + bmfok = control_readfile(&bmf,"control/badmailfrom",0); + if (bmfok == -1) die_control(); + if (bmfok) + if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem(); + } + + switch(control_readfile(&percenthack,"control/percenthack",0)) { + case -1: die_control(); + case 0: if (!constmap_init(&mappercenthack,"",0,0)) die_nomem(); + case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) die_nomem(); + } + + bmpok = control_readfile(&bmp,"control/badmailpatterns",0); + if (bmpok == -1) die_control(); if (control_readint(&databytes,"control/databytes") == -1) die_control(); x = env_get("DATABYTES"); @@ -131,6 +185,7 @@ if (!remotehost) remotehost = "unknown"; remoteinfo = env_get("TCPREMOTEINFO"); relayclient = env_get("RELAYCLIENT"); + bouncemail = env_get("BOUNCEMAIL"); dohelo(remotehost); } @@ -197,31 +252,121 @@ return 1; } +static void log_deny(m,f,t) char *m,*f,*t; +{ + syslog (LOG_WARNING, "%s check failed (%s) -> (%s) [%s] (HELO %s)", + m, f, t, remoteip, helohost.s); +} + +int nomxcheck(dom) char *dom; +{ + ipalloc checkip = {0}; + int ret=0; + stralloc checkhost = {0}; + + if (!*dom) return (DNS_HARD); + if (!stralloc_copys(&checkhost,dom)) return (DNS_SOFT); + + switch (dns_mxip(&checkip,&checkhost,1)) + { + case DNS_MEM: + case DNS_SOFT: + ret=DNS_SOFT; + break; + + case DNS_HARD: + ret=DNS_HARD; + break; + case 1: + if (checkip.len <= 0) ret=DNS_HARD; + break; + } + + return (ret); +} + +int seenmail = 0; +stralloc mailfrom = {0}; +stralloc rcptto = {0}; + + int bmfcheck() { - int j; - if (!bmfok) return 0; - if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1; + int i,j,err; + char subvalue; + regex_t re; + + /* bounce messages are allowed */ + if (str_len(mailfrom) == 0) return 0; + if (str_equal(mailfrom.s, "#@[]")) return 0; + + /* do not block any mail for postmaster@ or abuse@ */ j = byte_rchr(addr.s,addr.len,'@'); - if (j < addr.len) - if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1; + if (!str_diffn(addr.s, "postmaster@", j)) return 0; + if (!str_diffn(addr.s, "abuse@", j)) return 0; + + /* check for @ in from address */ + if ((i=byte_rchr(mailfrom.s,mailfrom.len,'@')) >= mailfrom.len) return 1; + /* check for . in domain.TLD */ + if ((j=byte_rchr(mailfrom.s+i,mailfrom.len-i,'.')) >=mailfrom.len-i) return 1; + /* check top domain is 2 or 3 characters (country or TLD) */ + j=mailfrom.len-(i+1+j+1); if (j < 2 || j > 3) return 1; + + if (bmpok) { + for (i=0;i < bmp.len;++i) { + j = (bmp.s[i] == '!'); + if (!regcomp(&re, &bmp.s[i+j], REG_EXTENDED|REG_ICASE|REG_NOSUB)) { + err = regexec(&re, mailfrom.s, (size_t) 0, 0, 0); + regfree(&re); + if (err == 0) return j ? 0 : 2; + } + i = i + str_len(&bmp.s[i]); + } + } + + if (bmfok) + { + if (constmap(&mapbmf,mailfrom.s,mailfrom.len - 1)) return 2; + j = byte_rchr(mailfrom.s,mailfrom.len,'@'); + if (j < mailfrom.len) + if (constmap(&mapbmf,mailfrom.s + j,mailfrom.len-j-1)) return 2; + } + + if (fdbmf != -1) + { + uint32 dlen; + if (cdb_seek(fdbmf,mailfrom.s,mailfrom.len-1,&dlen)) return 2; + j = byte_rchr(mailfrom.s,mailfrom.len,'@'); + if (j < mailfrom.len) + if (cdb_seek(fdbmf,mailfrom.s + j,mailfrom.len-j-1,&dlen)) return 2; + } + + /* Look for a valid MX record for domain */ + switch (nomxcheck(&mailfrom.s[byte_rchr(mailfrom.s,mailfrom.len,'@')+1])) + { + case 0: + break; /*valid*/ + case DNS_SOFT: + return 3; + case DNS_HARD: + return 4; + } return 0; } int addrallowed() { - int r; + int i, r; r = rcpthosts(addr.s,str_len(addr.s)); if (r == -1) die_control(); + + if (byte_chr(addr.s,str_len(addr.s),'%') < str_len(addr.s) ) { + i = byte_rchr(addr.s,str_len(addr.s),'@'); + if (!constmap(&mappercenthack,addr.s+i+1,str_len(addr.s)-i-1)) r = 0; + } return r; } - -int seenmail = 0; -int flagbarf; /* defined if seenmail */ -stralloc mailfrom = {0}; -stralloc rcptto = {0}; - void smtp_helo(arg) char *arg; { smtp_greet("250 "); out("\r\n"); @@ -240,24 +385,47 @@ void smtp_mail(arg) char *arg; { if (!addrparse(arg)) { err_syntax(); return; } - flagbarf = bmfcheck(); seenmail = 1; if (!stralloc_copys(&rcptto,"")) die_nomem(); if (!stralloc_copys(&mailfrom,addr.s)) die_nomem(); if (!stralloc_0(&mailfrom)) die_nomem(); out("250 ok\r\n"); } + void smtp_rcpt(arg) char *arg; { if (!seenmail) { err_wantmail(); return; } if (!addrparse(arg)) { err_syntax(); return; } - if (flagbarf) { err_bmf(); return; } + if (bouncemail) { log_deny("Realtime Blacklist (RBL)", mailfrom.s,addr.s); + err_maps(bouncemail); return; } + switch(bmfcheck()) { + case 0: + break; /* valid */ + case 1: + log_deny("MAIL FROM SYNTAX", mailfrom.s,addr.s); + err_mailfrom(); + return; + case 2: + log_deny("BAD MAIL FROM", mailfrom.s,addr.s); + err_bmf(); + return; + case 3: + log_deny("MAIL FROM MX (temporary)", mailfrom.s,addr.s); + err_dns(); + return; + case 4: + log_deny("MAIL FROM MX", mailfrom.s,addr.s); + err_mailfrom(); + return; + } + if (relayclient) { --addr.len; if (!stralloc_cats(&addr,relayclient)) die_nomem(); if (!stralloc_0(&addr)) die_nomem(); } else - if (!addrallowed()) { err_nogateway(); return; } + if (!addrallowed()) { log_deny("Relayclient",mailfrom.s,addr.s); + err_nogateway(); return; } if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem(); @@ -411,6 +579,7 @@ void main() { sig_pipeignore(); + openlog ("qmail-smtpd", 0, LOG_MAIL); if (chdir(auto_qmail) == -1) die_control(); setup(); if (ipme_init() != 1) die_ipme(); diff -Naur qmail-1.03/tcp-env.c qmail-1.03-jbuce/tcp-env.c --- qmail-1.03/tcp-env.c Mon Jun 15 05:53:16 1998 +++ qmail-1.03-jbuce/tcp-env.c Fri Oct 2 22:05:26 1998 @@ -27,6 +27,7 @@ unsigned long remoteport; struct ip_address ipremote; stralloc remotename = {0}; +stralloc bouncemail = {0}; char temp[IPFMT + FMT_ULONG]; @@ -122,6 +123,30 @@ if (!env_put2("TCPREMOTEINFO",rinfo)) die(); } } + +/* Use Vixie's RBL to blackhole known mass e-mail hosts + * See http://maps.vix.com/rbl/ for more ifnormation */ + + switch(dns_maps(&bouncemail,&ipremote,".rbl.maps.vix.com.")) + { + case DNS_MEM: die(); + case 0: + if (!stralloc_0(&bouncemail)) die(); + if (!env_put2("BOUNCEMAIL",bouncemail.s)) die(); + } + +/* Uncomment this section to enable Dorkslayers + * See http://www.dorkslayers.com/ for more information */ + +/* + switch(dns_maps(&bouncemail,&ipremote,".orbs.dorkslayers.com.")) + { + case DNS_MEM: die(); + case 0: + if (!stralloc_0(&bouncemail)) die(); + if (!env_put2("BOUNCEMAIL",bouncemail.s)) die(); + } +*/ sig_pipedefault(); execvp(*argv,argv);