Index: ChangeLog.arctic.org
===================================================================
RCS file: /home/src/cvsroot/qmail/ChangeLog.arctic.org,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- ChangeLog.arctic.org	25 Dec 2003 22:49:59 -0000	1.15
+++ ChangeLog.arctic.org	25 Jan 2004 22:32:02 -0000	1.16
@@ -1,3 +1,9 @@
+Sun Jan 25 14:28:27 2004  dean gaudet <dean@arctic.org>
+
+	* Makefile qmail-qmtpd.c qmail-smtpd.c realrcptto.c: apply
+	  <http://multivac.cwru.edu/qmail/qmail-1.03-realrcptto-2003.12.23.patch>
+	  with some local mods for logging.
+
 Sun Nov 16 14:49:21 2003  dean gaudet <dean@arctic.org>
 
 	* error.h: need to include errno.h for most recent glibc
Index: Makefile
===================================================================
RCS file: /home/src/cvsroot/qmail/Makefile,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- Makefile	25 Dec 2003 22:49:59 -0000	1.6
+++ Makefile	25 Jan 2004 22:32:02 -0000	1.7
@@ -1371,14 +1371,15 @@
 	./compile qmail-qmqpd.c
 
 qmail-qmtpd: \
-load qmail-qmtpd.o rcpthosts.o control.o constmap.o received.o \
+load qmail-qmtpd.o realrcptto.o rcpthosts.o control.o constmap.o received.o \
 date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a open.a \
 getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a \
-str.a fs.a auto_qmail.o
-	./load qmail-qmtpd rcpthosts.o control.o constmap.o \
+str.a fs.a auto_qmail.o auto_break.o auto_usera.o
+	./load qmail-qmtpd realrcptto.o rcpthosts.o control.o constmap.o \
 	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
 	datetime.a open.a getln.a sig.a case.a env.a stralloc.a \
-	alloc.a substdio.a error.a str.a fs.a auto_qmail.o 
+	alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_break.o \
+	auto_usera.o
 
 qmail-qmtpd.0: \
 qmail-qmtpd.8
@@ -1537,17 +1538,17 @@
 	./compile qmail-showctl.c
 
 qmail-smtpd: \
-load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
+load qmail-smtpd.o realrcptto.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 \
-fs.a auto_qmail.o socket.lib dns.o dns.lib
-	./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
+fs.a auto_qmail.o auto_break.o auto_usera.o socket.lib dns.o dns.lib
+	./load qmail-smtpd realrcptto.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 fs.a auto_qmail.o  `cat \
-	socket.lib` dns.o `cat dns.lib` \
+	alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_break.o \
+	auto_usera.o `cat socket.lib` dns.o `cat dns.lib` \
 	-L/usr/local/ssl/lib -lssl -lcrypto
 
 qmail-smtpd.0: \
@@ -1692,6 +1693,11 @@
 auto_split.h
 	./compile readsubdir.c
 
+realrcptto.o: \
+compile realrcptto.c auto_break.h auto_usera.h byte.h case.h cdb.h \
+constmap.h error.h fmt.h open.h str.h stralloc.h uint32.h
+	./compile realrcptto.c
+
 received.o: \
 compile received.c fmt.h qmail.h substdio.h now.h datetime.h \
 datetime.h date822fmt.h received.h
Index: qmail-qmtpd.c
===================================================================
RCS file: /home/src/cvsroot/qmail/qmail-qmtpd.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- qmail-qmtpd.c	27 Nov 2001 02:20:07 -0000	1.1.1.1
+++ qmail-qmtpd.c	25 Jan 2004 22:32:02 -0000	1.2
@@ -11,9 +11,14 @@
 #include "readwrite.h"
 #include "control.h"
 #include "received.h"
+#include "constmap.h"
 
 void badproto() { _exit(100); }
 void resources() { _exit(111); }
+void die_nomem() { resources(); }
+void die_control() { resources(); }
+void die_cdb() { resources(); }
+void die_sys() { resources(); }
 
 int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
@@ -74,6 +79,14 @@
 char *relayclient;
 int relayclientlen;
 
+stralloc envnoathost = {0};
+static stralloc percenthack = {0};
+struct constmap mappercenthack;
+static stralloc locals = {0};
+struct constmap maplocals;
+static stralloc vdoms = {0};
+struct constmap mapvdoms;
+
 main()
 {
   char ch;
@@ -98,6 +111,24 @@
   if (rcpthosts_init() == -1) resources();
   relayclient = env_get("RELAYCLIENT");
   relayclientlen = relayclient ? str_len(relayclient) : 0;
+
+  if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1)
+    die_control();
+
+  if (control_readfile(&locals,"control/locals",1) != 1) die_control();
+  if (!constmap_init(&maplocals,locals.s,locals.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();
+  }
+  switch(control_readfile(&vdoms,"control/virtualdomains",0)) {
+    case -1: die_control();
+    case 0: if (!constmap_init(&mapvdoms,"",0,1)) die_nomem();
+    case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) die_nomem();
+  }
  
   if (control_readint(&databytes,"control/databytes") == -1) resources();
   x = env_get("DATABYTES");
@@ -216,6 +247,10 @@
             case -1: resources();
             case 0: failure.s[failure.len - 1] = 'D';
           }
+
+        if (!failure.s[failure.len - 1])
+          if (!realrcptto(buf))
+            failure.s[failure.len - 1] = 'D';
  
         if (!failure.s[failure.len - 1]) {
           qmail_to(&qq,buf);
Index: qmail-smtpd.c
===================================================================
RCS file: /home/src/cvsroot/qmail/qmail-smtpd.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- qmail-smtpd.c	18 Jun 2003 17:42:41 -0000	1.12
+++ qmail-smtpd.c	25 Jan 2004 22:32:02 -0000	1.13
@@ -120,7 +120,7 @@
 char sserrbuf[512];
 substdio sserr = SUBSTDIO_FDBUF(errwrite,2,sserrbuf,sizeof sserrbuf);
 
-static stralloc err;
+static stralloc err = {0};
 char strnum[FMT_ULONG];
 
 void flush() { substdio_flush(&ssout); }
@@ -133,6 +133,8 @@
 void die_fork() { out("421 unable to start checkpassword.\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 die_cdb() { out("421 unable to read cdb user database (#4.3.0)\r\n"); flush(); _exit(1); }
+void die_sys() { out("421 unable to read system user database (#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 err_nodomain() { out("553 sorry, your envelope sender must include a domain (#5.7.1)\r\n"); }
@@ -153,7 +155,6 @@
 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"); }
 
-
 stralloc greeting = {0};
 
 void smtp_greet(code) char *code;
@@ -196,6 +197,13 @@
 int brtok = 0;
 stralloc brt = {0};
 struct constmap mapbrt;
+stralloc envnoathost = {0};
+static stralloc percenthack = {0};
+struct constmap mappercenthack;
+static stralloc locals = {0};
+struct constmap maplocals;
+static stralloc vdoms = {0};
+struct constmap mapvdoms;
 
 void setup()
 {
@@ -228,6 +236,24 @@
   if (brtok == -1) die_control();
   if (brtok)
     if (!constmap_init(&mapbrt,brt.s,brt.len,0)) die_nomem();
+
+  if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1)
+    die_control();
+
+  if (control_readfile(&locals,"control/locals",1) != 1) die_control();
+  if (!constmap_init(&maplocals,locals.s,locals.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();
+  }
+  switch(control_readfile(&vdoms,"control/virtualdomains",0)) {
+    case -1: die_control();
+    case 0: if (!constmap_init(&mapvdoms,"",0,1)) die_nomem();
+    case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) die_nomem();
+  }
  
   if (control_readint(&databytes,"control/databytes") == -1) die_control();
   x = env_get("DATABYTES");
@@ -563,6 +589,17 @@
       else { err_nogateway(); return; }
      }
 #endif
+  if (!realrcptto(addr.s)) {
+    if (!stralloc_copys(&err,"qmail-smtpd: pid ")) die_nomem();
+    if (!stralloc_catb(&err,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+    if (!stralloc_cats(&err," realrcptto ")) die_nomem();
+    if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
+    if (!stralloc_cats(&err,"\n")) die_nomem();
+    substdio_put(&sserr,err.s,err.len);
+    substdio_flush(&sserr);
+    out("550 sorry, no mailbox here by that name. (#5.1.1)\r\n");
+    return;
+  }
   if (!env_get("RELAYCLIENT") && brtcheck()) { err_brt(); return; }
   if (!stralloc_cats(&rcptto,"T")) die_nomem();
   if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
Index: realrcptto.c
===================================================================
RCS file: realrcptto.c
diff -N realrcptto.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ realrcptto.c	25 Jan 2004 22:32:02 -0000	1.1
@@ -0,0 +1,232 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include "substdio.h"
+#include "auto_break.h"
+#include "auto_usera.h"
+#include "byte.h"
+#include "case.h"
+#include "cdb.h"
+#include "constmap.h"
+#include "error.h"
+#include "fmt.h"
+#include "open.h"
+#include "str.h"
+#include "stralloc.h"
+#include "uint32.h"
+
+extern stralloc envnoathost;
+extern struct constmap mappercenthack;
+extern struct constmap maplocals;
+extern struct constmap mapvdoms;
+extern void die_nomem();
+extern void die_control();
+extern void die_cdb();
+extern void die_sys();
+
+static char *dash;
+static char *extension;
+static char *local;
+static struct passwd *pw;
+
+#define GETPW_USERLEN 32
+
+static int userext()
+{
+  char username[GETPW_USERLEN];
+  struct stat st;
+
+  extension = local + str_len(local);
+  for (;;) {
+    if (extension - local < sizeof(username))
+      if (!*extension || (*extension == *auto_break)) {
+	byte_copy(username,extension - local,local);
+	username[extension - local] = 0;
+	case_lowers(username);
+	errno = 0;
+	pw = getpwnam(username);
+	if (errno == error_txtbsy) die_sys();
+	if (pw)
+	  if (pw->pw_uid)
+	    if (stat(pw->pw_dir,&st) == 0) {
+	      if (st.st_uid == pw->pw_uid) {
+		dash = "";
+		if (*extension) { ++extension; dash = "-"; }
+		return 1;
+	      }
+	    }
+	    else
+	      if (error_temp(errno)) die_sys();
+      }
+    if (extension == local) return 0;
+    --extension;
+  }
+}
+
+int realrcptto(addr)
+char* addr;
+{
+  char *homedir;
+  static stralloc localpart = {0};
+  static stralloc lower = {0};
+  static stralloc nughde = {0};
+  static stralloc wildchars = {0};
+  static stralloc safeext = {0};
+  static stralloc qme = {0};
+  /* qmail-send:rewrite */
+  unsigned int i,at;
+  if (!stralloc_copys(&localpart,addr)) die_nomem();
+  i = byte_rchr(localpart.s,localpart.len,'@');
+  if (i == localpart.len) {
+    if (!stralloc_cats(&localpart,"@")) die_nomem();
+    if (!stralloc_cat(&localpart,&envnoathost)) die_nomem();
+  }
+  while (constmap(&mappercenthack,localpart.s + i + 1,localpart.len - i - 1)) {
+    unsigned int j = byte_rchr(localpart.s,i,'%');
+    if (j == i) break;
+    localpart.len = i;
+    i = j;
+    localpart.s[i] = '@';
+  }
+  at = byte_rchr(localpart.s,localpart.len,'@');
+  if (constmap(&maplocals,localpart.s + at + 1,localpart.len - at - 1)) {
+    localpart.len = at;
+    localpart.s[at] = '\0';
+  } else {
+    unsigned int xlen,newlen;
+    char *x;
+    for (i = 0;;++i) {
+      if (i > localpart.len) return 1;
+      if (!i || (i == at + 1) || (i == localpart.len) ||
+          ((i > at) && (localpart.s[i] == '.'))) {
+        x = constmap(&mapvdoms,localpart.s + i,localpart.len - i);
+        if (x) break;
+      }
+    }
+    if (!*x) return 1;
+    xlen = str_len(x) + 1;  /* +1 for '-' */
+    newlen = xlen + at + 1; /* +1 for \0 */
+    if (xlen < 1 || newlen - 1 < xlen || newlen < 1 ||
+        !stralloc_ready(&localpart,newlen))
+      die_nomem();
+    localpart.s[newlen - 1] = '\0';
+    byte_copyr(localpart.s + xlen,at,localpart.s);
+    localpart.s[xlen - 1] = '-';
+    byte_copy(localpart.s,xlen - 1,x);
+    localpart.len = newlen;
+  }
+
+  /* qmail-lspawn:nughde_get */
+  {
+    int r,fd,flagwild;
+    if (!stralloc_copys(&lower,"!")) die_nomem();
+    if (!stralloc_cats(&lower,localpart.s)) die_nomem();
+    if (!stralloc_0(&lower)) die_nomem();
+    case_lowerb(lower.s,lower.len);
+    if (!stralloc_copys(&nughde,"")) die_nomem();
+    fd = open_read("users/cdb");
+    if (fd == -1) {
+      if (errno != error_noent) die_cdb();
+    } else {
+      uint32 dlen;
+      r = cdb_seek(fd,"",0,&dlen);
+      if (r != 1) die_cdb();
+      if (!stralloc_ready(&wildchars,(unsigned int) dlen)) die_nomem();
+      wildchars.len = dlen;
+      if (cdb_bread(fd,wildchars.s,wildchars.len) == -1) die_cdb();
+      i = lower.len;
+      flagwild = 0;
+      do { /* i > 0 */
+        if (!flagwild || (i == 1) ||
+            (byte_chr(wildchars.s,wildchars.len,lower.s[i - 1])
+             < wildchars.len)) {
+          r = cdb_seek(fd,lower.s,i,&dlen);
+          if (r == -1) die_cdb();
+          if (r == 1) {
+            char* x;
+            if (!stralloc_ready(&nughde,(unsigned int) dlen)) die_nomem();
+            nughde.len = dlen;
+            if (cdb_bread(fd,nughde.s,nughde.len) == -1) die_cdb();
+            if (flagwild)
+              if (!stralloc_cats(&nughde,localpart.s + i - 1)) die_nomem();
+            if (!stralloc_0(&nughde)) die_nomem();
+            close(fd);
+            x=nughde.s;
+            /* skip username */
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            /* skip uid */
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            /* skip gid */
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            /* skip homedir */
+            homedir=x;
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            /* skip dash */
+            dash=x;
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            extension=x;
+            goto got_nughde;
+          }
+        }
+        --i;
+        flagwild = 1;
+      } while (i);
+      close(fd);
+    }
+  }
+
+  /* qmail-getpw */
+  local = localpart.s;
+  if (!userext()) {
+    extension = local;
+    dash = "-";
+    pw = getpwnam(auto_usera);
+  }
+  if (!pw) return 0;
+  if (!stralloc_copys(&nughde,pw->pw_dir)) die_nomem();
+  if (!stralloc_0(&nughde)) die_nomem();
+  homedir=nughde.s;
+
+  got_nughde:
+
+  /* qmail-local:qmesearch */
+  if (!stralloc_copys(&safeext,extension)) die_nomem();
+  case_lowerb(safeext.s,safeext.len);
+  for (i = 0;i < safeext.len;++i)
+    if (safeext.s[i] == '.')
+      safeext.s[i] = ':';
+  {
+    struct stat st;
+    int i;
+    if (!stralloc_copys(&qme,homedir)) die_nomem();
+    if (!stralloc_cats(&qme,"/.qmail")) die_nomem();
+    if (!stralloc_cats(&qme,dash)) die_nomem();
+    if (!stralloc_cat(&qme,&safeext)) die_nomem();
+    if (!stralloc_0(&qme)) die_nomem();
+    if (stat(qme.s, &st) == 0 || errno != error_noent)
+      return 1;
+    for (i = safeext.len;i >= 0;--i)
+      if (!i || (safeext.s[i - 1] == '-')) {
+        if (!stralloc_copys(&qme,homedir)) die_nomem();
+        if (!stralloc_cats(&qme,"/.qmail")) die_nomem();
+        if (!stralloc_cats(&qme,dash)) die_nomem();
+        if (!stralloc_catb(&qme,safeext.s,i)) die_nomem();
+        if (!stralloc_cats(&qme,"default")) die_nomem();
+        if (!stralloc_0(&qme)) die_nomem();
+        if (stat(qme.s, &st) == 0 || errno != error_noent)
+	  return 1;
+      }
+    if (*dash) return 0;
+    return 1;
+  }
+}
