From fd404641357a4a3bc0a55cb31deb3d4bad4ec2ee Mon Sep 17 00:00:00 2001 From: manuel Date: Mon, 4 Feb 2013 02:55:38 +0100 Subject: [PATCH] badrcptto support qmail-gentoo-1.03-r16-badrcptto-morebadrcptto-accdias --- Makefile | 29 +++++++++++++++-- TARGETS | 4 +++ qmail-newbrt.9 | 41 ++++++++++++++++++++++++ qmail-newbrt.c | 70 ++++++++++++++++++++++++++++++++++++++++ qmail-showctl.c | 22 +++++++++++++ qmail-smtpd.8 | 24 ++++++++++++++ qmail-smtpd.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 7 files changed, 276 insertions(+), 13 deletions(-) create mode 100644 qmail-newbrt.9 create mode 100644 qmail-newbrt.c diff --git a/Makefile b/Makefile index 5f676dd..10e8255 100644 --- a/Makefile +++ b/Makefile @@ -807,7 +807,7 @@ qmail-clean qmail-send qmail-start splogger qmail-queue qmail-inject \ 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 \ @@ -963,7 +963,7 @@ make-makelib warn-auto.sh systype man: \ qmail-local.0 qmail-lspawn.0 qmail-getpw.0 qmail-remote.0 \ qmail-rspawn.0 qmail-clean.0 qmail-send.0 qmail-start.0 splogger.0 \ -qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newu.0 \ +qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newbrt.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 \ @@ -1280,6 +1280,31 @@ getln.h exit.h readwrite.h open.h auto_qmail.h cdbmss.h cdbmake.h \ 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-newbrt.0: \ +qmail-newbrt.8 + nroff -man qmail-newbrt.8 > qmail-newbrt.0 + +qmail-newbrt.8: \ +qmail-newbrt.9 conf-break conf-spawn + cat qmail-newbrt.9 \ + | sed s}QMAILHOME}"`head -n 1 conf-qmail`"}g \ + | sed s}BREAK}"`head -n 1 conf-break`"}g \ + | sed s}SPAWN}"`head -n 1 conf-spawn`"}g \ + > qmail-newbrt.8 + 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 --git a/TARGETS b/TARGETS index 949bc46..27706f3 100644 --- a/TARGETS +++ b/TARGETS @@ -238,6 +238,8 @@ cdbmake_hash.o cdbmake_add.o cdbmake.a qmail-newu +qmail-newbrt.o +qmail-newbrt qmail-pw2u.o qmail-pw2u qmail-qread.o @@ -350,6 +352,8 @@ qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 +qmail-newbrt.8 +qmail-newbrt.0 qmail-newu.8 qmail-newu.0 qmail-pw2u.8 diff --git a/qmail-newbrt.9 b/qmail-newbrt.9 new file mode 100644 index 0000000..d1798d0 --- /dev/null +++ b/qmail-newbrt.9 @@ -0,0 +1,41 @@ +.TH qmail-newbrt 8 +.SH NAME +qmail-newbrt \- prepare morebadrcptto for qmail-smtpd +.SH SYNOPSIS +.B qmail-newbrt +.SH DESCRIPTION +.B qmail-newbrt +reads the instructions in +.B QMAILHOME/control/morebadrcptto +and writes them into +.B QMAILHOME/control/morebadrcptto.cdb +in a binary format suited +for quick access by +.BR qmail-smtpd . + +If there is a problem with +.BR control/morebadrcptto , +.B qmail-newbrt +complains and leaves +.B control/morebadrcptto.cdb +alone. + +.B qmail-newbrt +ensures that +.B control/morebadrcptto.cdb +is updated atomically, +so +.B qmail-smtpd +never has to wait for +.B qmail-newbrt +to finish. +However, +.B qmail-newbrt +makes no attempt to protect against two simultaneous updates of +.BR control/morebadrcptto.cdb . + +The binary +.B control/morebadrcptto.cdb +format is portable across machines. +.SH "SEE ALSO" +qmail-smtpd(8) diff --git a/qmail-newbrt.c b/qmail-newbrt.c new file mode 100644 index 0000000..9344444 --- /dev/null +++ b/qmail-newbrt.c @@ -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 --git a/qmail-showctl.c b/qmail-showctl.c index bbaa2bc..9d4e1bc 100644 --- a/qmail-showctl.c +++ b/qmail-showctl.c @@ -219,6 +219,25 @@ void main() do_lst("badmailfromnorelay","Any MAIL FROM is allowed.",""," MAIL FROM denied if it matches this pattern and RELAYCLIENT is not set."); do_lst("badmailto","No RCPT TO are specifically denied.",""," RCPT TO denied if it matches this pattern."); do_lst("badmailtonorelay","No RCPT TO are specifically denied.",""," RCPT TO denied if it matches this pattern and RELAYCLIENT is not set."); + if (do_lst("badrcptto","Any RCPT TO is allowed."," not accepted in RCPT TO ",".")) + do_lst("morebadrcptto","No effect."," no accepted in RCPT TO ","."); + else + do_lst("morebadrcptto","No badrcptto; morebadrcpto is irrelevant.","No badrcptto; doesn't matter that morebadrcptto has ","."); + /* XXX: check badrcptto.cdb contents */ + substdio_puts(subfdout,"\nmorebadrcptto.cdb: "); + if (stat("morebadrcptto",&stmrh) == -1) + if (stat("morebadrcptto.cdb",&stmrhcdb) == -1) + substdio_puts(subfdout,"(Default.) No effect.\n"); + else + substdio_puts(subfdout,"Oops! morebadrcptto.cdb exists but morebadrcptto doesn't.\n"); + else + if (stat("morebadrcptto.cdb",&stmrhcdb) == -1) + substdio_puts(subfdout,"Oops! morebadrcptto exists but morebadrcptto.cdb doesn't.\n"); + else + if (stmrh.st_mtime > stmrhcdb.st_mtime) + substdio_puts(subfdout,"Oops! morebadrcptto.cdb is older than morebadrcptto.\n"); + else + substdio_puts(subfdout,"Modified recently enough; hopefully up to date.\n"); 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 ",""); @@ -276,6 +295,7 @@ void main() if (str_equal(d->d_name,"badmailfromnorelay")) continue; if (str_equal(d->d_name,"badmailto")) continue; if (str_equal(d->d_name,"badmailtonorelay")) continue; + if (str_equal(d->d_name,"badrcptto")) 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; @@ -291,6 +311,8 @@ void main() if (str_equal(d->d_name,"localiphost")) continue; if (str_equal(d->d_name,"locals")) continue; if (str_equal(d->d_name,"me")) continue; + if (str_equal(d->d_name,"morebadrcptto")) continue; + if (str_equal(d->d_name,"morebadrcptto.cdb")) continue; if (str_equal(d->d_name,"morercpthosts")) continue; if (str_equal(d->d_name,"morercpthosts.cdb")) continue; if (str_equal(d->d_name,"percenthack")) continue; diff --git a/qmail-smtpd.8 b/qmail-smtpd.8 index ce0dc02..0103984 100644 --- a/qmail-smtpd.8 +++ b/qmail-smtpd.8 @@ -135,6 +135,13 @@ should contain the CRLs of the CAs in .I clientca.pem and client certs will be checked for revocation. +.TP 5 +.I badrcptto +Unacceptable envelope recipient addresses. +.B qmail-smtpd +will reject every recipient address for a message +if the envelope recipient address is listed in +.IR badrcptto . .TP 5 .I databytes Maximum number of bytes allowed in a message, @@ -195,6 +202,23 @@ with This is done before .IR rcpthosts . .TP 5 +.I morebadrcptto +Extra not allowed RCPT TO addresses. +If +.I badrcptto +and +.I morebadrcptto +both exist, +.I morebardrcptto +is effectively appended to +.IR badrcptto . + +You must run +.B qmail-newbrt +whenever +.I morebadrcptto +changes. +.TP 5 .I morercpthosts Extra allowed RCPT domains. If diff --git a/qmail-smtpd.c b/qmail-smtpd.c index 86c5bd9..4466168 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c @@ -26,6 +26,7 @@ #include "wait.h" #include "qregex.h" #include "strerr.h" +#include "cdb.h" #define BMCHECK_BMF 0 #define BMCHECK_BMFNR 1 @@ -42,6 +43,12 @@ int timeout = 1200; const char *protocol = "SMTP"; +char *remoteip; +char *remotehost; +char *remoteinfo; +char *local; +char *relayclient; + #ifdef TLS #include #include "tls.h" @@ -69,19 +76,52 @@ int safewrite(fd,buf,len) int fd; char *buf; int len; char ssoutbuf[512]; substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); +/* write errors to stderr */ +char erroutbuf[512]; +substdio errout = SUBSTDIO_FDBUF(safewrite,2,erroutbuf,sizeof erroutbuf); + void flush() { substdio_flush(&ssout); } void out(s) char *s; { substdio_puts(&ssout,s); } +void eflush() { substdio_flush(&errout); } +void eout(s) char *s; { substdio_puts(&errout,s); } +void enew() { substdio_puts(&errout,"qmail-smtpd: "); } + 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() +{ + enew(); eout("Connection to "); eout(remoteip); eout(" timed out.\n"); + out("451 timeout (#4.4.2)\r\n"); flush(); eflush(); _exit(1); +} +void die_nomem() +{ + enew(); eout("Out of memory while connected to "); eout(remoteip); eout("!\n"); + out("421 out of memory (#4.3.0)\r\n"); flush(); eflush(); _exit(1); +} +void die_control() +{ + enew(); eout("Unable to read controls!\n"); + out("421 unable to read controls (#4.3.0)\r\n"); flush(); eflush(); + _exit(1); +} +void die_ipme() +{ + enew(); eout("Unable to figure out my IP addresses!\n"); + out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); + eflush(); _exit(1); +} +void straynewline() +{ + enew(); eout("Stray newline from "); eout(remoteip); eout(".\n"); + out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); + eflush(); _exit(1); +} void err_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); } void err_bmf() { out("553 sorry, your envelope sender has been denied (#5.7.1)\r\n"); } void err_bmt() { out("553 sorry, your envelope recipient has been denied (#5.7.1)\r\n"); } +void err_brt() { out("550 sorry, this message is not deliverable (#5.7.1)\r\n"); } void err_bhelo() { out("553 sorry, your HELO host name has been denied (#5.7.1)\r\n"); } #ifndef TLS void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); } @@ -129,12 +169,6 @@ void smtp_quit() 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 */ @@ -159,6 +193,11 @@ stralloc bmt = {0}; int bmtnrok = 0; stralloc bmtnr = {0}; +int brtok = 0; +stralloc brt = {0}; +struct constmap mapbrt; +int fdmbrt; + int bhelook = 0; stralloc bhelo = {0}; @@ -197,6 +236,17 @@ void setup() if (env_get("LOGREGEX")) logregex = 1; + + 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; } @@ -282,6 +332,14 @@ char *arg; return 1; } +static void log_deny(m,f,t) char *m,*f,*t; +{ + enew(); eout(m); eout(" check failed ("); eout(f); eout(") -> ("); + eout(t); eout(") ["); eout(remoteip); eout("] (HELO "); + eout(helohost.s); eout(")\n"); + eflush(); +} + int bmcheck(which) int which; { int i = 0; @@ -335,6 +393,19 @@ int bmcheck(which) int which; return 0; } +int brtcheck() +{ + int j; + if (brtok) if (constmap(&mapbrt,addr.s,addr.len - 1)) return 1; + if (fdmbrt != -1) { + 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; @@ -364,6 +435,7 @@ int addrrelay() int seenmail = 0; int flagbarfbmf; /* defined if seenmail */ int flagbarfbmt; +int flagbrt; /* defined if any bad rcpts */ int flagbarfbhelo; int flagsize; stralloc mailfrom = {0}; @@ -523,6 +595,10 @@ void smtp_rcpt(arg) char *arg; { } else if (!addrallowed()) { err_nogateway(); return; } + if (!env_get("RELAYCLIENT") && brtcheck()) { + flagbrt = 1; + log_deny("BAD RCPT TO", mailfrom.s,addr.s); + } if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem(); @@ -642,6 +718,7 @@ void smtp_data() { 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; } -- cgit v1.2.3