This is a more complete "badrcptto" patch for systems that have a lot of addresses they want to reject. Addresses to reject go in control/badrcptto and control/morebadrcptto, one per line, just like badmailfrom. control/morebadrcptto is compiled into control/morebadrcptto.cdb with the new program qmail-newbrt. I'd suggest putting all of your bad addresses into morebadrcptto since it's a lot faster to look something up in a CDB than in a text file. Unlike the previous badrcptto patch, this one does not reject the message at RCPT TO time. Instead, it waits until the DATA command to issue a 550 rejection. This has two effects: one is to deter dictionary attackers which are perversely encouraged by RCPT TO rejections. (If some of the addresses are bad, the rest must be good.) The other is that if a message has a mixture of bad and good addresses, the message will be rejected anyway. That's a feature, since in my experience, any message addressed to a spam-only address is spam even if it's also addressed to legit addresses. This version also does not let you list domains in the badrcptto files. There's no point in doing so, since all domains not in rcpthosts are rejected, anyway. This patch contains the entire new source file for qmail-newbrt.c as a diff against an empty file. If patch gets mad at you, just create the empty file. No warranty expressed or implied. If you find bugs, feel free to fix them and please send me the fix. John Levine, johnl@iecc.com, 4/03 diff -u qmail-1.03-dist/Makefile qmail-1.03/Makefile --- qmail-1.03-dist/Makefile Mon Jun 15 06:53:16 1998 +++ qmail-1.03/Makefile Wed Apr 9 01:30:20 2003 @@ -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-newbrt 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 \ @@ -1241,6 +1241,19 @@ uint32.h substdio.h ./compile qmail-newmrh.c +qmail-newbrt: \ +load qmail-newbrt.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-newbrt 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-newbrt.o: \ +compile qmail-newbrt.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-newbrt.c + qmail-newu: \ load qmail-newu.o cdbmss.o getln.a open.a seek.a cdbmake.a case.a \ stralloc.a alloc.a substdio.a error.a str.a auto_qmail.o diff -u qmail-1.03-dist/qmail-newbrt.c qmail-1.03/qmail-newbrt.c --- qmail-1.03-dist/qmail-newbrt.c Wed Apr 9 16:31:27 2003 +++ qmail-1.03/qmail-newbrt.c Wed Apr 9 16:18:50 2003 @@ -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-newbrt: fatal: " + +void die_read() +{ + strerr_die2sys(111,FATAL,"unable to read control/morebadrcptto: "); +} +void die_write() +{ + strerr_die2sys(111,FATAL,"unable to write to control/morebadrcptto.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/morebadrcptto"); + if (fd == -1) die_read(); + + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf); + + fdtemp = open_trunc("control/morebadrcptto.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/morebadrcptto.tmp","control/morebadrcptto.cdb") == -1) + strerr_die2sys(111,FATAL,"unable to move control/morebadrcpto.tmp to control/morebadrcptto.cdb"); + + _exit(0); +} diff -u qmail-1.03-dist/qmail-smtpd.c qmail-1.03/qmail-smtpd.c --- qmail-1.03-dist/qmail-smtpd.c Mon Jun 15 06:53:16 1998 +++ qmail-1.03/qmail-smtpd.c Wed Apr 9 16:17:13 2003 @@ -23,6 +23,7 @@ #include "timeoutread.h" #include "timeoutwrite.h" #include "commands.h" +#include "cdb.h" #define MAXHOPS 100 unsigned int databytes = 0; @@ -50,6 +51,7 @@ void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); } void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); } +void err_brt() { out("550 sorry, this message is not deliverable (#5.7.1)\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"); } @@ -96,6 +98,10 @@ int bmfok = 0; stralloc bmf = {0}; struct constmap mapbmf; +int brtok = 0; +stralloc brt = {0}; +struct constmap mapbrt; +int fdmbrt; void setup() { @@ -116,7 +122,16 @@ if (bmfok == -1) die_control(); if (bmfok) if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem(); + + brtok = control_readfile(&brt,"control/badrcptto",0); + if (brtok == -1) die_control(); + if (brtok) + if (!constmap_init(&mapbrt,brt.s,brt.len,0)) die_nomem(); + fdmbrt = open_read("control/morebadrcptto.cdb"); + if (fdmbrt == -1) if (errno != error_noent) die_control(); + + if (control_readint(&databytes,"control/databytes") == -1) die_control(); x = env_get("DATABYTES"); if (x) { scan_ulong(x,&u); databytes = u; } @@ -208,6 +223,19 @@ return 0; } +int brtcheck() +{ + int j; + if (brtok) if (constmap(&mapbrt,addr.s,addr.len - 1)) return 1; + if (fdmbrt) { + uint32 dlen; + j = cdb_seek(fdmbrt, addr.s, addr.len - 1, &dlen); + if (j == -1) die_control(); + if (j) return j; + } + return 0; +} + int addrallowed() { int r; @@ -219,6 +247,7 @@ int seenmail = 0; int flagbarf; /* defined if seenmail */ +int flagbrt; /* defined if any bad rcpts */ stralloc mailfrom = {0}; stralloc rcptto = {0}; @@ -258,6 +287,7 @@ } else if (!addrallowed()) { err_nogateway(); return; } + if (!env_get("RELAYCLIENT") && brtcheck()) { flagbrt = 1; } if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem(); @@ -372,6 +402,7 @@ if (!seenmail) { err_wantmail(); return; } if (!rcptto.len) { err_wantrcpt(); return; } + if (flagbrt) { err_brt(); return; } seenmail = 0; if (databytes) bytestooverflow = databytes + 1; if (qmail_open(&qqt) == -1) { err_qqt(); return; }