
   *** qmail-goodrcptto+rcptcheck-20070418.patch ***

Author: Fabio Busatto <fbusatto@users.sourceforge.net>

Applies to: qmail-1.03, netqmail-1.05

   *** qmail-goodrcptto+rcptcheck-20070418.patch ***



diff -uNr qmail-1.03-orig/qmail-control.9 qmail-1.03/qmail-control.9
--- qmail-1.03-orig/qmail-control.9	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/qmail-control.9	2007-04-18 15:15:15.000000000 +0200
@@ -21,6 +21,7 @@
 Comments are allowed
 in
 .IR badmailfrom ,
+.IR goodrcptto ,
 .IR locals ,
 .IR percenthack ,
 .IR qmqpservers ,
@@ -51,6 +52,7 @@
 .I doublebouncehost	\fIme	\fRqmail-send
 .I doublebounceto	\fRpostmaster	\fRqmail-send
 .I envnoathost	\fIme	\fRqmail-send
+.I goodrcptto	\fR(none)	\fRqmail-smtpd
 .I helohost	\fIme	\fRqmail-remote
 .I idhost	\fIme	\fRqmail-inject
 .I localiphost	\fIme	\fRqmail-smtpd
@@ -61,6 +63,7 @@
 .I qmqpservers	\fR(none)	\fRqmail-qmqpc
 .I queuelifetime	\fR604800	\fRqmail-send
 .I rcpthosts	\fR(none)	\fRqmail-smtpd
+.I rcptcheck	\fR(none)	\fRqmail-smtpd
 .I smtpgreeting	\fIme	\fRqmail-smtpd
 .I smtproutes	\fR(none)	\fRqmail-remote
 .I timeoutconnect	\fR60	\fRqmail-remote
diff -uNr qmail-1.03-orig/qmail-showctl.c qmail-1.03/qmail-showctl.c
--- qmail-1.03-orig/qmail-showctl.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/qmail-showctl.c	2007-04-18 15:15:15.000000000 +0200
@@ -225,6 +225,7 @@
   do_str("doublebouncehost",1,"doublebouncehost","2B recipient host: ");
   do_str("doublebounceto",0,"postmaster","2B recipient user: ");
   do_str("envnoathost",1,"envnoathost","Presumed domain name is ");
+  do_lst("goodrcptto","Any RCPT TO is allowed.",""," accepted in RCPT TO.");
   do_str("helohost",1,"helohost","SMTP client HELO host name is ");
   do_str("idhost",1,"idhost","Message-ID host name is ");
   do_str("localiphost",1,"localiphost","Local IP address becomes ");
@@ -234,6 +235,7 @@
   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_str("rcptcheck",0,"disabled","Recipient check helper is ");
 
   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 ",".");
@@ -278,6 +280,7 @@
     if (str_equal(d->d_name,"doublebouncehost")) continue;
     if (str_equal(d->d_name,"doublebounceto")) continue;
     if (str_equal(d->d_name,"envnoathost")) continue;
+    if (str_equal(d->d_name,"goodrcptto")) continue;
     if (str_equal(d->d_name,"helohost")) continue;
     if (str_equal(d->d_name,"idhost")) continue;
     if (str_equal(d->d_name,"localiphost")) continue;
@@ -289,6 +292,7 @@
     if (str_equal(d->d_name,"plusdomain")) continue;
     if (str_equal(d->d_name,"qmqpservers")) continue;
     if (str_equal(d->d_name,"queuelifetime")) continue;
+    if (str_equal(d->d_name,"rcptcheck")) continue;
     if (str_equal(d->d_name,"rcpthosts")) continue;
     if (str_equal(d->d_name,"smtpgreeting")) continue;
     if (str_equal(d->d_name,"smtproutes")) continue;
diff -uNr qmail-1.03-orig/qmail-smtpd.8 qmail-1.03/qmail-smtpd.8
--- qmail-1.03-orig/qmail-smtpd.8	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/qmail-smtpd.8	2007-04-18 15:15:15.000000000 +0200
@@ -77,6 +77,20 @@
 is set, it overrides
 .IR databytes .
 .TP 5
+.I goodrcptto
+Acceptable recipient addresses.
+.B qmail-smtpd
+will reject every recipient address for a message
+if the recipient isn't listed in
+.I goodrcptto
+and no other recipient check authorizes the delivery.
+A line in
+.I goodrcptto
+may be of the form
+.BR @\fIhost ,
+meaning every address at
+.IR host .
+.TP 5
 .I localiphost
 Replacement host name for local IP addresses.
 Default:
@@ -120,6 +134,16 @@
 and the rest into
 .IR morercpthosts .
 .TP 5
+.I rcptcheck
+Recipient check program.
+If
+.I rcptcheck
+is supplied,
+.B qmail-smtpd
+will reject every recipient address for a message
+if the program exits non-zero
+and no other recipient check authorizes the delivery.
+.TP 5
 .I rcpthosts
 Allowed RCPT domains.
 If
diff -uNr qmail-1.03-orig/qmail-smtpd.c qmail-1.03/qmail-smtpd.c
--- qmail-1.03-orig/qmail-smtpd.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/qmail-smtpd.c	2007-04-18 15:15:15.000000000 +0200
@@ -23,6 +23,7 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 #include "commands.h"
+#include "wait.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_nomailbox() { out("553 sorry, no mailbox here by that name (#5.1.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,11 @@
 int bmfok = 0;
 stralloc bmf = {0};
 struct constmap mapbmf;
+int grtok = 0;
+stralloc grt = {0};
+struct constmap mapgrt;
+int rcptcheckok = 0;
+stralloc rcptcheckbin = {0};
 
 void setup()
 {
@@ -116,6 +123,12 @@
   if (bmfok == -1) die_control();
   if (bmfok)
     if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
+  grtok = control_readfile(&grt,"control/goodrcptto",0);
+  if (grtok == -1) die_control();
+  if (grtok)
+    if (!constmap_init(&mapgrt,grt.s,grt.len,0)) die_nomem();
+  rcptcheckok = control_readline(&rcptcheckbin,"control/rcptcheck");
+  if (rcptcheckok == -1) die_control();
  
   if (control_readint(&databytes,"control/databytes") == -1) die_control();
   x = env_get("DATABYTES");
@@ -208,6 +221,53 @@
   return 0;
 }
 
+int grtcheck()
+{
+  int j;
+  if (!grtok) return 0;
+  if (constmap(&mapgrt,addr.s,addr.len - 1)) return 0;
+  j = byte_rchr(addr.s,addr.len,'@');
+  if (j < addr.len)
+    if (constmap(&mapgrt,addr.s + j,addr.len - j - 1)) return 0;
+  return 1;
+}
+
+stralloc rcptcheckcmd = {0};
+
+int rcptcheck()
+{
+  int child;
+  char *(args[4]);
+  int wstat;
+
+  if (!rcptcheckok) return 0;
+  if (!addr.s[0]) return 1;
+
+  switch(child = fork())
+  {
+    case -1:
+      return 0;
+    case 0:
+      if (!stralloc_copys(&rcptcheckcmd,"")) die_nomem();
+      if (!stralloc_copy(&rcptcheckcmd,&rcptcheckbin)) die_nomem();
+      if (!stralloc_cats(&rcptcheckcmd," ")) die_nomem();
+      if (!stralloc_cat(&rcptcheckcmd,&addr)) die_nomem();
+      if (!stralloc_0(&rcptcheckcmd)) die_nomem();
+      close(0);
+      close(1);
+      close(2);
+      args[0] = "/bin/sh";
+      args[1] = "-c";
+      args[2] = rcptcheckcmd.s;
+      args[3] = 0;
+      execv(*args,args);
+      _exit(1);
+  }
+
+  wait_pid(&wstat,child);
+  return wait_exitcode(wstat);
+}
+
 int addrallowed()
 {
   int r;
@@ -256,8 +316,10 @@
     if (!stralloc_cats(&addr,relayclient)) die_nomem();
     if (!stralloc_0(&addr)) die_nomem();
   }
-  else
+  else {
     if (!addrallowed()) { err_nogateway(); return; }
+    if (grtcheck() && rcptcheck()) { err_nomailbox(); return; }
+  }
   if (!stralloc_cats(&rcptto,"T")) die_nomem();
   if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
   if (!stralloc_0(&rcptto)) die_nomem();
