diff -urN qmail-1.03.orig/Makefile qmail-1.03/Makefile
--- qmail-1.03.orig/Makefile	Mon Jun 15 04:53:16 1998
+++ qmail-1.03/Makefile	Fri Mar 11 15:42:59 2005
@@ -217,9 +217,9 @@
 
 case.a: \
 makelib case_diffb.o case_diffs.o case_lowerb.o case_lowers.o \
-case_starts.o
+case_starts.o case_startb.o
 	./makelib case.a case_diffb.o case_diffs.o case_lowerb.o \
-	case_lowers.o case_starts.o
+	case_lowers.o case_starts.o case_startb.o
 
 case_diffb.o: \
 compile case_diffb.c case.h
@@ -237,6 +237,10 @@
 compile case_lowers.c case.h
 	./compile case_lowers.c
 
+case_startb.o: \
+compile case_startb.c case.h
+	./compile case_startb.c
+
 case_starts.o: \
 compile case_starts.c case.h
 	./compile case_starts.c
@@ -1536,13 +1540,13 @@
 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
+fs.a auto_qmail.o socket.lib dns.o dns.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 \
-	socket.lib`
+	socket.lib` dns.o `cat dns.lib`
 
 qmail-smtpd.0: \
 qmail-smtpd.8
diff -urN qmail-1.03.orig/case_startb.c qmail-1.03/case_startb.c
--- qmail-1.03.orig/case_startb.c	Wed Dec 31 18:00:00 1969
+++ qmail-1.03/case_startb.c	Fri Mar 11 15:42:59 2005
@@ -0,0 +1,21 @@
+#include "case.h"
+
+int case_startb(s,len,t)
+register char *s;
+unsigned int len;
+register char *t;
+{
+  register unsigned char x;
+  register unsigned char y;
+
+  for (;;) {
+    y = *t++ - 'A';
+    if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
+    if (!y) return 1;
+    if (!len) return 0;
+    --len;
+    x = *s++ - 'A';
+    if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
+    if (x != y) return 0;
+  }
+}
diff -urN qmail-1.03.orig/qmail-smtpd.c qmail-1.03/qmail-smtpd.c
--- qmail-1.03.orig/qmail-smtpd.c	Mon Jun 15 04:53:16 1998
+++ qmail-1.03/qmail-smtpd.c	Fri Mar 11 16:56:04 2005
@@ -23,10 +23,15 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 #include "commands.h"
+#include "dns.h"
 
 #define MAXHOPS 100
 unsigned int databytes = 0;
+unsigned int mfchk = 1;
+char *rhsbl;
 int timeout = 1200;
+#define BADIP -4
+#define RHSBL -5
 
 int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
@@ -38,9 +43,26 @@
 
 char ssoutbuf[512];
 substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
+char sserrbuf[512];
+substdio sserr = SUBSTDIO_FDBUF(safewrite,2,sserrbuf,sizeof sserrbuf);
 
 void flush() { substdio_flush(&ssout); }
 void out(s) char *s; { substdio_puts(&ssout,s); }
+void log1(s1) char *s1; {
+ substdio_putsflush(&sserr,s1); }
+void log2(s1,s2) char *s1; char *s2; {
+ substdio_putsflush(&sserr,s1);
+ substdio_putsflush(&sserr,s2); }
+void log3(s1,s2,s3) char *s1; char *s2; char *s3; {
+ substdio_putsflush(&sserr,s1);
+ substdio_putsflush(&sserr,s2);
+ substdio_putsflush(&sserr,s3); }
+void log5(s1,s2,s3,s4,s5) char *s1; char *s2; char *s3; char *s4; char *s5; {
+ substdio_putsflush(&sserr,s1);
+ substdio_putsflush(&sserr,s2);
+ substdio_putsflush(&sserr,s3);
+ substdio_putsflush(&sserr,s4);
+ substdio_putsflush(&sserr,s5); }
 
 void die_read() { _exit(1); }
 void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
@@ -50,6 +72,15 @@
 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_bh() { out("553 sorry, your helo parameter is in my badhelo list (#5.7.1)\r\n"); }
+void err_hmf() { out("553 sorry, your envelope sender domain must exist (#5.7.1)\r\n"); }
+void err_smf() { out("451 DNS temporary failure (#4.3.0)\r\n"); }
+void err_badip() { out("553 sorry, your envelope sender domain must resolve to a routeable IP address (#5.7.1)\r\n"); }
+void err_rhsbl() { 
+  out("553 sorry, your envelope sender domain is listed in the ");
+  out(rhsbl);
+  out(" RHSBL (#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 +127,21 @@
 int bmfok = 0;
 stralloc bmf = {0};
 struct constmap mapbmf;
+int sigsok = 0;
+stralloc sigs = {0};
+int executableok = 0;
+int bhok = 0;
+stralloc bh = {0};
+struct constmap mapbh;
+char mypid[FMT_ULONG];
+
+void smtp_nohttp(code) char *code;
+{
+  out("221 I am not an HTTP server. (#5.5.5)\r\n"); 
+  flush();
+  log3("pid ",mypid," attempted HTTP\n");
+  _exit(0);
+}
 
 void setup()
 {
@@ -112,11 +158,30 @@
 
   if (rcpthosts_init() == -1) die_control();
 
+  x = env_get("NOMFCHECK");
+  if (x) { mfchk = 0; }
+
   bmfok = control_readfile(&bmf,"control/badmailfrom",0);
   if (bmfok == -1) die_control();
   if (bmfok)
     if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
  
+  bhok = control_readfile(&bh,"control/badhelo",0);
+  if (bhok == -1) die_control();
+  x = env_get("NOBADHELO");
+  if (x) { bhok = 0; }
+  if (bhok)
+    if (!constmap_init(&mapbh,bh.s,bh.len,0)) die_nomem();
+ 
+  if (env_get("EXECUTABLEOK")) {
+  	executableok = 1;
+  } else { 
+    sigsok = control_readfile(&sigs,"control/signatures",0);
+    if (sigsok == -1) die_control();
+  }
+
+  rhsbl = env_get("RHSBL");
+
   if (control_readint(&databytes,"control/databytes") == -1) die_control();
   x = env_get("DATABYTES");
   if (x) { scan_ulong(x,&u); databytes = u; }
@@ -132,6 +197,7 @@
   remoteinfo = env_get("TCPREMOTEINFO");
   relayclient = env_get("RELAYCLIENT");
   dohelo(remotehost);
+  mypid[fmt_ulong(mypid,getpid())] = 0;
 }
 
 
@@ -197,14 +263,104 @@
   return 1;
 }
 
+int helocheck()
+{
+  int j;
+  if (!bhok) return 0;
+  if (constmap(&mapbh,helohost.s,helohost.len - 1)) {
+    log5("pid ",mypid," badhelo ",helohost.s,"\n");
+    return 1;
+  }
+  return 0;
+}
+
 int bmfcheck()
 {
   int j;
   if (!bmfok) return 0;
-  if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
+  if (constmap(&mapbmf,addr.s,addr.len - 1)) {
+    log5("pid ",mypid," badmailfrom ",addr.s,"\n");
+    return 1;
+  }
   j = byte_rchr(addr.s,addr.len,'@');
   if (j < addr.len)
-    if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
+    if (constmap(&mapbmf,addr.s + j,addr.len - j - 1))  {
+      log5("pid ",mypid," badmailfrom ",addr.s,"\n");
+      return 1;
+    }
+  return 0;
+}
+
+int mfcheck()
+{
+  stralloc sa = {0};
+  ipalloc ia = {0};
+  unsigned int random;
+  int j;
+  char ipbuf[IPFMT];
+  unsigned char *o;
+  int z;
+
+  j = byte_rchr(addr.s,addr.len,'@') + 1;
+  if (!(j < addr.len)) return 0;
+  if (!stralloc_copys(&sa, addr.s + j)) die_nomem();
+  if (mfchk) {
+    random = now() + (getpid() << 16);
+    dns_init(0);
+    j = dns_mxip(&ia,&sa,random);
+    if (j < 0) {
+      log3("pid ",mypid," mfcheck ");
+      switch(j) {
+        case DNS_HARD: log1("permanent "); break;
+        case DNS_SOFT: log1("temporary "); break;
+        case DNS_MEM: die_nomem();
+      }
+      log2(addr.s,"\n");
+      return j;
+    }
+    o = ia.ix->ip.d;
+    if ((*o == 127) || (*o == 10)
+      || ((*o == 192) && (*(o+1) == 168))
+      || ((*o == 172) && ((*(o+1) & 0xF0) == 0x10))) {
+      ipbuf[ip_fmt(ipbuf,o)] = 0;
+      log5("pid ",mypid," ",addr.s, " mfcheck MX nonrouteable IP ");
+      log2(ipbuf, "\n");
+      return BADIP;
+    }
+  }
+  if (rhsbl) {
+    if (!stralloc_cats(&sa, ".")) die_nomem();
+    if (!stralloc_cats(&sa, rhsbl)) die_nomem();
+    if (!stralloc_0(&sa)) die_nomem();
+    dns_init(0);
+    j = dns_ip(&ia,&sa);
+    ipbuf[ip_fmt(ipbuf,ia.ix->ip.d)] = 0;
+    if (j < 0) {
+      /* not listed (good) or an error -- don't block mail */
+      return 0;
+    }
+    if (*(ia.ix->ip.d) == 127) {
+      /* listed in RHSBL */
+      log5("pid ",mypid," rhsbl ",rhsbl," ");
+      log2(ipbuf, "\n");
+      return RHSBL;
+    }
+  }
+  return 0;
+}
+
+int sigscheck(stralloc *line) {
+  int i, j;
+
+  j = 0;
+  for (i = 0; i < sigs.len; i++) if (!sigs.s[i]) {
+    if (i-j < line->len)
+      if (!str_diffn(line->s,sigs.s+j,i-j)) {
+        log5("pid ",mypid," rejected_signature ",sigs.s+j,"\n");
+		return 1;
+	  }
+    j = i+1;
+  }
   return 0;
 }
 
@@ -219,6 +375,7 @@
 
 int seenmail = 0;
 int flagbarf; /* defined if seenmail */
+int flagbarfhelo;
 stralloc mailfrom = {0};
 stralloc rcptto = {0};
 
@@ -226,11 +383,13 @@
 {
   smtp_greet("250 "); out("\r\n");
   seenmail = 0; dohelo(arg);
+  flagbarfhelo = helocheck();
 }
 void smtp_ehlo(arg) char *arg;
 {
   smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
   seenmail = 0; dohelo(arg);
+  flagbarfhelo = helocheck();
 }
 void smtp_rset()
 {
@@ -241,6 +400,13 @@
 {
   if (!addrparse(arg)) { err_syntax(); return; }
   flagbarf = bmfcheck();
+  switch(mfcheck()) {
+    case DNS_HARD: err_hmf(); return;
+    case DNS_SOFT: err_smf(); return;
+    case BADIP: err_badip(); return;
+    case RHSBL: err_rhsbl(); return;
+    case DNS_MEM: die_nomem();
+  }
   seenmail = 1;
   if (!stralloc_copys(&rcptto,"")) die_nomem();
   if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
@@ -250,6 +416,7 @@
 void smtp_rcpt(arg) char *arg; {
   if (!seenmail) { err_wantmail(); return; }
   if (!addrparse(arg)) { err_syntax(); return; }
+  if (flagbarfhelo) { err_bh(); return; }
   if (flagbarf) { err_bmf(); return; }
   if (relayclient) {
     --addr.len;
@@ -281,9 +448,147 @@
 struct qmail qqt;
 unsigned int bytestooverflow = 0;
 
+int linespastheader;		/* =0 after boundary is found in body, */
+                                /* until blank line */
+char linetype;
+int flagexecutable;
+int flagqsbmf;
+
+stralloc line = {0};
+stralloc content = {0};
+stralloc boundary = {0};
+int boundary_start;
+
+/*
+
+def put(ch):
+    line.append(ch)
+    if ch == '\n':
+        if linepastheader == 0:
+            if line.startswith('Content-Type:'):
+                content = 
+
+ put() puts characters into the queue.  We remember those characters
+   and form them into a line.  When we get a newline, we examine the
+   line.  If we're currently in a header (0 linespastheader), we look
+   for Content-Type.  If we're at the newline that ends a header, we
+   look to see if the content is multipart.  If it is, then we push
+   the current boundary, remember the boundary, otherwise we set the
+   boundary to the empty string.  Set the linespastheader to 1.  When
+   linespastheader is 1, and the boundary is empty, scan the line for
+   signatures.  If the boundary is non-empty, look for a match against
+   the boundary.  If it matches and is followed by two dashes, pop the
+   boundary, otherwise set linespastheader to 0.
+*/
+
 void put(ch)
 char *ch;
 {
+  char *cp, *cpstart, *cpafter;
+  unsigned int len;
+
+  if (line.len < 1024)
+    if (!stralloc_catb(&line,ch,1)) die_nomem();
+
+  if (*ch == '\n') {
+    if (linespastheader == 0) {
+      if (line.len == 1) {
+	linespastheader = 1;	
+	if (flagqsbmf) {
+          flagqsbmf = 0;
+          linespastheader = 0;
+        }
+	if (content.len) {			/* MIME header */
+	  cp = content.s;
+	  len = content.len;
+	  while (len && (*cp == ' ' || *cp == '\t')) { ++cp; --len; }
+	  cpstart = cp;
+	  if (len && *cp == '"') {			/* might be commented */
+	    ++cp; --len; cpstart = cp;
+	    while (len && *cp != '"') { ++cp; --len; }
+	  } else {
+	    while (len && *cp != ' ' && *cp != '\t' && *cp != ';') {
+	      ++cp; --len;
+	    }
+	  }
+	  if (!case_diffb(cpstart,cp-cpstart,"message/rfc822"))
+	    linespastheader = 0;
+
+	  cpafter = content.s+content.len;
+	  while((cp += byte_chr(cp,cpafter-cp,';')) != cpafter) {
+	    ++cp;
+	    while (cp < cpafter && (*cp == ' ' || *cp == '\t')) ++cp;
+	    if (case_startb(cp,cpafter - cp,"boundary=")) {
+	      cp += 9;			/* after boundary= */
+	      if (cp < cpafter && *cp == '"') {
+		++cp;
+		cpstart = cp;
+		while (cp < cpafter && *cp != '"') ++cp;
+	      } else {
+		cpstart = cp;
+		while (cp < cpafter &&
+		   *cp != ';' && *cp != ' ' && *cp != '\t') ++cp;
+	      }
+	      /* push the current boundary.  Append a null and remember start. */
+	      if (!stralloc_0(&boundary)) die_nomem();
+	      boundary_start = boundary.len;
+	      if (!stralloc_cats(&boundary,"--")) die_nomem();
+	      if (!stralloc_catb(&boundary,cpstart,cp-cpstart))
+		      die_nomem();
+	      break;
+	    }
+	  }
+	}
+      } else { /* non-blank header line */
+	if ((*line.s == ' ' || *line.s == '\t')) {
+	  switch(linetype) {
+	    case 'C': if (!stralloc_catb(&content,line.s,line.len-1)) die_nomem(); break;
+	    default: break;
+	  }
+	} else {
+	  if (case_startb(line.s,line.len,"content-type:")) {
+	    if (!stralloc_copyb(&content,line.s+13,line.len-14)) die_nomem();
+	    linetype = 'C';
+	  } else {
+	    linetype = ' ';
+	  }
+	}
+      }
+    } else {      /* non-header line */
+      if (boundary.len-boundary_start && *line.s == '-' && line.len > (boundary.len-boundary_start) &&
+	  !str_diffn(line.s,boundary.s+boundary_start,boundary.len-boundary_start)) { /* matches a boundary */
+	if (line.len > boundary.len-boundary_start + 2 &&
+            line.s[boundary.len-boundary_start+0] == '-' &&
+            line.s[boundary.len-boundary_start+1] == '-') {
+	  /* XXXX - pop the boundary here */
+	  if (boundary_start) boundary.len = boundary_start - 1;
+	  boundary_start = boundary.len;
+	  while(boundary_start--) if (!boundary.s[boundary_start]) break;
+	  boundary_start++;
+	  linespastheader = 2;
+	} else {
+	  linespastheader = 0;
+	}
+      } else if (linespastheader == 1) { /* first line -- match a signature? */
+        if (/*mailfrom.s[0] == '\0' && */
+            str_start(line.s,"Hi. This is the "))
+	  flagqsbmf = 1;
+        else if (/*mailfrom.s[0] == '\0' && */
+            str_start(line.s,"This message was created automatically by mail delivery software"))
+	  flagqsbmf = 1;
+	else if (!executableok && sigscheck(&line)) {
+	  flagexecutable = 1;
+	  qmail_fail(&qqt);
+	}
+	linespastheader = 2;
+      }
+      if (flagqsbmf && str_start(line.s,"---")) {
+	linespastheader = 0;
+      }
+    }
+    line.len = 0;
+  }
+
   if (bytestooverflow)
     if (!--bytestooverflow)
       qmail_fail(&qqt);
@@ -374,6 +679,13 @@
   if (!rcptto.len) { err_wantrcpt(); return; }
   seenmail = 0;
   if (databytes) bytestooverflow = databytes + 1;
+  boundary.len = 0;
+  boundary_start = 0;
+  content.len = 0;
+  linespastheader = 0;
+  flagexecutable = 0;
+  flagqsbmf = 0;
+  linetype = ' ';
   if (qmail_open(&qqt) == -1) { err_qqt(); return; }
   qp = qmail_qp(&qqt);
   out("354 go ahead\r\n");
@@ -389,6 +701,7 @@
   if (!*qqx) { acceptmessage(qp); return; }
   if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
   if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
+  if (flagexecutable) { out("552 we don't accept email with executable content (#5.3.4)\r\n"); return; }
   if (*qqx == 'D') out("554 "); else out("451 ");
   out(qqx + 1);
   out("\r\n");
@@ -405,6 +718,9 @@
 , { "help", smtp_help, flush }
 , { "noop", err_noop, flush }
 , { "vrfy", err_vrfy, flush }
+, { "get", smtp_nohttp, flush }
+, { "post", smtp_nohttp, flush }
+, { "head", smtp_nohttp, flush }
 , { 0, err_unimpl, flush }
 } ;
 

