diff -ruN qmail-1.03-factory/Makefile qmail-1.03-patched/Makefile
--- qmail-1.03-factory/Makefile	1998-06-15 06:53:16.000000000 -0400
+++ qmail-1.03-patched/Makefile	2005-05-16 19:13:06.000000000 -0400
@@ -1535,13 +1535,13 @@
 load qmail-smtpd.o 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 \
+open.a sig.a case.a env.a stralloc.a alloc.a strerr.a substdio.a error.a str.a \
 fs.a auto_qmail.o socket.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 \
+	alloc.a strerr.a substdio.a error.a str.a fs.a auto_qmail.o  `cat \
 	socket.lib`
 
 qmail-smtpd.0: \
@@ -1553,7 +1553,7 @@
 substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \
 error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \
 substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \
-exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h
+exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h cdb.h uint32.h
 	./compile qmail-smtpd.c
 
 qmail-start: \
diff -ruN qmail-1.03-factory/qmail-smtpd.c qmail-1.03-patched/qmail-smtpd.c
--- qmail-1.03-factory/qmail-smtpd.c	1998-06-15 06:53:16.000000000 -0400
+++ qmail-1.03-patched/qmail-smtpd.c	2005-05-16 19:14:01.000000000 -0400
@@ -23,6 +23,8 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 #include "commands.h"
+#include "strerr.h"
+#include "cdb.h"
 
 #define MAXHOPS 100
 unsigned int databytes = 0;
@@ -59,6 +61,8 @@
 void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
 void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
 
+void err_vrt() { out("553 sorry, this recipient is not in my validrcptto list (#5.7.1)\r\n"); }
+void die_vrt() { out("421 too many invalid addresses, goodbye (#4.3.0)\r\n"); flush(); _exit(1); }
 
 stralloc greeting = {0};
 
@@ -97,6 +101,11 @@
 stralloc bmf = {0};
 struct constmap mapbmf;
 
+int vrtfd = -1;
+int vrtcount = 0;
+int vrtlimit = 10;
+int vrtlog_do = 0;
+
 void setup()
 {
   char *x;
@@ -116,6 +125,9 @@
   if (bmfok == -1) die_control();
   if (bmfok)
     if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
+
+    vrtfd = open_read("control/validrcptto.cdb");
+    if (-1 == vrtfd) if (errno != error_noent) die_control();
  
   if (control_readint(&databytes,"control/databytes") == -1) die_control();
   x = env_get("DATABYTES");
@@ -208,6 +220,71 @@
   return 0;
 }
 
+void vrtlog(a,b)
+const char *a;
+const char *b;
+{
+  if (vrtlog_do) strerr_warn2(a,b,0);
+}
+
+int vrtcheck()
+{
+  static char *rcptto = "qmail-smtpd: validrcptto RCPT TO: ";
+  static char *found = "qmail-smtpd: validrcptto found: ";
+  int j,k,r;
+  uint32 dlen;
+  stralloc laddr = {0};
+
+  stralloc user = {0};
+  stralloc adom = {0};
+  stralloc utry = {0};
+
+  if (-1 == vrtfd) return 1;
+
+  /* lowercase whatever we were sent */
+  if (!stralloc_copy(&laddr,&addr)) die_nomem() ;
+  case_lowerb(laddr.s,laddr.len);
+
+  vrtlog(rcptto,laddr.s,0);
+
+  /* exact match? */
+  r = cdb_seek(vrtfd,laddr.s,laddr.len-1,&dlen) ;
+  if (r>0) { vrtlog(found,laddr.s,0); return r; }
+
+  j = byte_rchr(laddr.s,laddr.len,'@');
+  if (j < laddr.len)
+  {
+    /* start "-default" search loop */
+    stralloc_copyb(&user,laddr.s,j) ;
+    stralloc_copyb(&adom,laddr.s+j,laddr.len-j-1);
+
+    while(1)
+    {
+      k = byte_rchr(user.s,user.len,'-');
+      if (k >= user.len) break ;
+
+      user.len = k+1;
+      stralloc_cats(&user,"default");
+
+      stralloc_copy(&utry,&user);
+      stralloc_cat (&utry,&adom);
+      stralloc_0(&utry);
+
+      r = cdb_seek(vrtfd,utry.s,utry.len-1,&dlen);
+      if (r>0) { vrtlog(found,utry.s,0); return r; }
+
+      user.len = k ;
+    }
+
+    /* try "@domain" */
+
+    r = cdb_seek(vrtfd,laddr.s+j,laddr.len-j-1,&dlen) ;
+    if (r>0) { vrtlog(found,laddr.s+j,0); return r; }
+  }
+
+  return 0;
+}
+
 int addrallowed()
 {
   int r;
@@ -258,6 +335,17 @@
   }
   else
     if (!addrallowed()) { err_nogateway(); return; }
+  if (!env_get("RELAYCLIENT") && !vrtcheck()) {
+    strerr_warn4("qmail-smtpd: not in validrcptto: ",addr.s,
+      " at ",remoteip,0);
+    if(vrtlimit && (++vrtcount >= vrtlimit)) {
+      strerr_warn2("qmail-smtpd: excessive validrcptto violations,"
+        " hanging up on ",remoteip,0);
+      die_vrt();
+    }
+    err_vrt();
+    return;
+  }
   if (!stralloc_cats(&rcptto,"T")) die_nomem();
   if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
   if (!stralloc_0(&rcptto)) die_nomem();
@@ -410,8 +498,16 @@
 
 void main()
 {
+  char *x ;
+  uint32 u;
   sig_pipeignore();
   if (chdir(auto_qmail) == -1) die_control();
+
+  x = env_get("VALIDRCPTTO_LIMIT");
+  if(x) { scan_ulong(x,&u); vrtlimit = (int) u; }
+  x = env_get("VALIDRCPTTO_LOG");
+  if(x) { scan_ulong(x,&u); vrtlog_do = (int) u; }
+
   setup();
   if (ipme_init() != 1) die_ipme();
   smtp_greet("220 ");
