diff -u --unidirectional-new-file netqmail-1.05-org/Makefile netqmail-1.05/Makefile
--- netqmail-1.05-org/Makefile	Tue Apr 20 10:28:41 2004
+++ netqmail-1.05/Makefile	Tue Apr 20 11:36:56 2004
@@ -136,6 +136,10 @@
 compile auto_usera.c
 	./compile auto_usera.c
 
+base64.o: \
+compile base64.c base64.h stralloc.h substdio.h str.h
+	./compile base64.c
+
 binm1: \
 binm1.sh conf-qmail
 	cat binm1.sh \
@@ -1532,16 +1536,16 @@
 	./compile qmail-showctl.c
 
 qmail-smtpd: \
-load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
+load qmail-smtpd.o rcpthosts.o qregex.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
-	./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
+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 base64.o socket.lib
+	./load qmail-smtpd qregex.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 \
+	alloc.a strerr.a substdio.a error.a str.a fs.a auto_qmail.o base64.o  `cat \
 	socket.lib`
 
 qmail-smtpd.0: \
@@ -1553,7 +1557,8 @@
 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 wait.h \
+fd.h base64.h
 	./compile qmail-smtpd.c
 
 qmail-start: \
@@ -1681,6 +1686,10 @@
 constmap.h stralloc.h gen_alloc.h rcpthosts.h
 	./compile rcpthosts.c
 
+qregex.o: \
+compile qregex.c qregex.h
+	./compile qregex.c
+
 readsubdir.o: \
 compile readsubdir.c readsubdir.h direntry.h fmt.h scan.h str.h \
 auto_split.h
diff -u --unidirectional-new-file netqmail-1.05-org/README.auth netqmail-1.05/README.auth
--- netqmail-1.05-org/README.auth	Thu Jan  1 09:00:00 1970
+++ netqmail-1.05/README.auth	Tue Apr 20 11:26:30 2004
@@ -0,0 +1,175 @@
+*** Warning! Cuidado! Vorsicht! ***
+===================================
+*** Version 0.30 of the patch changes the arguments which must be
+*** passed to qmail-smtpd.  If you are upgrading from a previous
+*** version of the patch, take care to ensure your invocation of
+*** qmail-smtpd uses the correct arguments.  Otherwise, your server
+*** may run as an open relay!
+===================================
+*** Warning! Cuidado! Vorsicht! ***
+
+
+This patch adds ESMTP AUTH authentication protocol support to
+qmail-1.03.  It's originally based on Mrs. Brisby's smtp-auth patch
+with many enhancements from Krzysztof Dabrowski <brush@elysium.pl>.
+
+Beginning with version 0.30, the patch was completely rewritten to
+use only djb's string functions by Eric M. Johnston <emj@postal.net>.
+
+You can always get the newest version from:
+http://members.elysium.pl/brush/qmail-smtpd-auth/
+
+To use all of it's functionality you will also have to obtain and
+install Krzysztof's cmd5checkpw utility available at:
+http://members.elysium.pl/brush/cmd5checkpw/
+
+If you need more information about SMTP-AUTH itself and the
+client/server support and configuration, visit:
+http://members.elysium.pl/brush/smtp-auth/
+
+---
+
+Detailed patch information:
+
+This patch adds the ESMTP AUTH option to qmail-1.03, allowing the
+LOGIN, PLAIN, and CRAM-MD5 AUTH types. An appropriate checkpassword
+tool is necessary to support the authentication.  See
+http://cr.yp.to/checkpwd.html for more information on the interface.
+Note that the checkpassword tool should support all of the AUTH types
+advertised by qmail-smtpd.
+
+As reflected in the modified qmail-smtpd(8) man page, qmail-smtpd
+must be invoked with three arguments: hostname, checkprogram, and
+subprogram.  If these arguments are missing, qmail-smtpd will still
+advertise availability of AUTH, but will fail with a permanent error
+when AUTH is used.
+
+hostname is simply used to form the CRAM-MD5 challenge.  qmail-smtpd
+invokes checkprogram, feeding it the username and password, in the
+case of LOGIN or PLAIN, or the username, challenge, and response, in
+the case of CRAM-MD5.  If the user is permitted, checkprogram invokes
+subprogram, which just has to exit with a status of 0 for the user to
+be authenticated.  Otherwise, checkprogram exits with a non-zero
+status.  subprogram can usually be /usr/bin/true (or /bin/true,
+depending on your flavor of OS).
+
+If the user is successfully authenticated, the RELAYCLIENT
+environment variable is effectively set for the SMTP session, and
+the TCPREMOTEINFO environment variable is set to the authenticated
+username, overriding any value that tcpserver may have set.  The
+value of TCPREMOTEINFO is reflected in a Received header.
+
+
+How to install it:
+
+Simply patch your qmail-1.03 distribution with the included patch
+file and recompile & install like usual.
+
+The steps to do this are as follows (assuming your virgin
+qmail-1.03 install is in "../qmail-1.03"):
+
+  cp README.auth base64.c base64.h ../qmail-1.03
+  patch -d ../qmail-1.03 < auth.patch
+
+Install qmail normally, with the exception of the new arguments
+to qmail-smtpd described elsewhere in this file.
+
+Also obtain, unpack, compile and install the cmd5checkpw utility
+(or some other checkpassword utility) and add a sample account to
+/etc/poppasswd file.  This file must be readable by the qmail-smtpd
+user, usually qmaild.
+
+
+How to use it:
+
+*** Warning: In version 0.30 the arguments have changed from
+*** previous versions of qmail-smtpd-auth.  Take care to make sure
+*** you update your startup scripts if updating!
+
+If you're running qmail-smtpd from inetd, you'll want to do the
+following:
+
+smtp stream tcp nowait qmaild /var/qmail/bin/tcp-env tcp-env \
+/var/qmail/bin/qmail-smtpd mail.acme.com /bin/cmd5checkpw /bin/true
+
+Replace mail.acme.com with your hostname.  The second argument to
+qmail-smtpd is your checkpassword utility (preferably cmd5checkpw
+or some alternative that can handle CRAM-MD5).  The third argument
+is the executable that the checkpassword utility execs when
+authentication is successful.  (Note that the location of "true"
+is OS dependent: you may need /usr/bin/true.)
+
+Invocations using tcpserver will require analagous changes.  Give
+your inetd a kill -HUP or restart tcpserver and away you go.
+
+
+Caveats:
+
+Please note that as authentication needs vary wildly across
+installations, no effort has been made to make this patch work ``out
+of the box.''  You'll have to procure or develop your own
+checkpassword program.  Also note that CRAM-MD5 will require you to
+keep plaintext passwords.  You'll probably want to disable this AUTH
+type if you're just using /etc/passwd (keeping in mind that PLAIN and
+LOGIN aren't quite as safe over the wire) -- just undefine AUTHCRAM
+in qmail-smtpd.
+
+Krzysztof Dabrowski's cmd5checkpw tool used as an example in this
+document supports the three AUTH types included in this patch.
+It's available at http://www.elysium.pl/members/brush/cmd5checkpw/.
+
+This patch has been generated against the stock qmail 1.03
+distribution.  The results of combining this patch with others are
+unknown.
+
+
+Features:
+
+This patch supports the following auth methods: LOGIN, PLAIN and
+CRAM-MD5.
+
+
+Compatibility:
+
+The following MUA's are confirmed to work with this patch:
+
+Eudora 4.2.2		-	CRAM-MD5
+Eudora 5.0.2 		- 	CRAM-MD5
+The Bat 1.39		-	LOGIN & CRAM-MD5
+Outlook Express 4	- 	LOGIN
+Outlook Express 5	-	LOGIN
+Outlook 2000 		- 	LOGIN
+Netscape 4.x		-	LOGIN & PLAIN
+Netscape 4.0x		-	LOGIN
+Pegasus Mail 3.1x	-	CRAM-MD5
+
+
+Various compatibility issues:
+
+Testing with Pegasus Mail 3.1 revealed that it requires the new style
+(RFC recommended) greeting message.  Both styles are now enabled to
+maintain the highest degree of compatibility with various clients.
+This fix was suggested by David Harris <David.Harris@pmail.gen.nz>,
+the developer of Pegasus Mail.
+
+
+Acknowledgments:
+
+This patch is based on work by Krzysztof Dabrowski at
+http://members.elysium.pl/brush/qmail-smtpd-auth/ and ``Mrs. Brisby''
+at http://www.nimh.org/hacks/qmail-smtpd.c which has been further
+developed by Eric M. Johnston <emj@postal.net>.
+
+---
+
+THIS SOFTWARE IS IN THE PUBLIC DOMAIN, IS PROVIDED BY THE AUTHOR
+``AS IS,'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff -u --unidirectional-new-file netqmail-1.05-org/README.qregex netqmail-1.05/README.qregex
--- netqmail-1.05-org/README.qregex	Thu Jan  1 09:00:00 1970
+++ netqmail-1.05/README.qregex	Tue Apr 20 11:29:04 2004
@@ -0,0 +1,164 @@
+QREGEX (v2) 20040317 - README March 17, 2004
+A Regular Expression matching patch for qmail 1.03
+
+
+OVERVIEW:
+
+qregex adds the ability to match address evelopes via Regular Expressions (REs)
+in the qmail-smtpd process. It has the abiltiy to match `helo/ehlo` (host name),
+`mail from` (envelope sender), and `rcpt to` (envelope recipient) commands with no load at all to the parent process. It follows all the base rules that are
+set out with qmail (ie using control files) so it makes for easy integretion
+into an existing setup (see the install instructions for more info). The v2 is
+specified because qregex was re-written to better conform to the security
+guarantee set forth by the author of qmail. The original version used stdio.h
+and stdlib.h for reading the control files whereas v2 now uses all stralloc
+functions which are much more regulated against buffer overruns and the like.
+See: http://cr.yp.to/qmail/guarantee.html
+
+NEW FEATURES:
+
+Features added to qregex since its creation are:
+
+1. Performs pattern matching on the helo/ehlo host name. Setting the
+   NOBADHELO environment variable prevents the host name from being
+   compared to the patterns in the badhelo control file.
+
+2. Matches to patterns in the badhelo, badmailfrom, and badmailto control
+   files are logged.
+
+3. Matching is case insensitive.
+
+4. Qregex ignores empty envelope senders. An empty envelope sender is not
+   compared to the patterns in the badmailfrom control file and is always
+   accepted.
+
+
+
+PLATFORMS:
+
+Qregex has been built and tested on the following platforms. I'm sure it won't
+have any problems on any platform that qmail will run on (providing they have
+a regex interface) but if you run into problems let me know.
+
+	- OpenBSD 3.x
+	- FreeBSD 4.x
+	- Mandrake Linux 9.x
+	- SuSE Linux 8.x
+
+
+
+INSTALLATION INSTRUCTIONS:
+
+Installation is very simple, there is only one requirement. You need to use the
+GNU version of the patch utility (http://www.gnu.org/software/patch/patch.html).
+(For Solaris 8 users like me it is installed as 'gpatch')
+
+- If this is a new setup.
+Uncompress and untar the qmail archive, copy the 'qregex.patch' file into the
+new qmail-1.03 directory and run "patch < qregex.patch"
+Follow the instructions as per the included qmail INSTALL file. Once you are
+done come back to this file and read the section on the control files.
+
+- If this is an existing setup.
+FIRST: create your control files (see below).
+Copy the 'qregex.patch' file into your existing qmail source directory.
+Run "patch < qregex.patch" then "make qmail-smtpd". Now run ./qmail-smtpd and
+test your new rules to make sure they work as expected.
+
+Install the new binary by cd'ing to /var/qmail/bin and as root (in one command)
+copy the existing binary to 'qmail-smtpd.old' and copy the new binary from the
+source directory to 'qmail-smtpd'.
+(ex. cp qmail-smtpd qmail-smtpd.old && cp ~/qmail-1.03/qmail-smtpd qmail-smtpd)
+
+You can also optionally just run "make setup check" as it will install the
+updated documentation and man pages provided with this patch. Stopping qmail
+before doing the "make setup check" is always a good idea.
+
+
+LOGGING:
+
+Qregex will log matches to the patterns in the badhelo, badmailfrom, and
+badmailto control files. Log messages will take these three forms depending
+on which control file was matched:
+
+qmail-smtpd: badhelo: <host> at <remote IP>
+
+qmail-smtpd: badmailfrom: <sender address> at <remote IP>
+
+qmail-smtpd: badmailto: <rcpt address> at <remote IP>
+
+
+CONTROL FILES:
+
+qregex provides you with three new control files.
+The first (which really isn't new) is "control/badmailfrom". This file
+originally matched addresses statically and now contains your REs for matching
+from the 'mail from' command.
+The other two are "control/badmailto" and "control/badhelo". They are exactly
+the same as the first except that they match against the 'rcpt to' and 
+'helo/ehlo' commands respectively.
+
+If you prefer you can symlink the badmailfrom and badmailto control files
+(ln -s badmailfrom badmailto) and only maintain two sets of rules. Beware
+this might cause problems in certain setups.
+        
+	Here's an example "badhelo" file.
+	-----------------------------------
+	# block host strings with no dot (not a FQDN)
+	!\.
+	-----------------------------------
+	
+	An example "badmailfrom" file.
+	-----------------------------------
+	# this will drop everything containing the string
+	# bad.domain.com or Bad.Domain.Com or BAD.domain.COM
+	bad\.domain\.com
+	# force users to fully qualify themselves
+	# (i.e. deny "user", accept "user@domain")
+	!@
+	-----------------------------------
+
+	And "badmailto" (a litte more interesting)
+	-----------------------------------
+	# must not contain invalid characters, brakets or multiple @'s
+	[!%#:*^(){}]
+	@.*@
+	-----------------------------------
+
+Also you can use the non-RE character '!' to start an RE as a signal to qregex
+to negate the action. As used above in the badmailfrom file, by negating the '@'
+symbol qregex will signal qmail-smtpd to deny the 'mail from' command whenever
+the address doesn't contain an @ symbol. When used inside a bracket expression,
+the '!' character looses this special meaning as shown by the badmailto example.
+
+
+INTERNALS:
+
+Qregex (or regexmatch as the function is called) will be called during the
+`helo/ehlo`, `rcpt to` and `mail from` handling routines in "qmail-smtpd.c".
+When called it will read the proper control file then one by one compile and
+execute the regex on the string passed into qmail-smtpd. If the regex matches
+it returns TRUE (1) and the qmail-smtpd process will deny the user the ability
+to continue. If you change anything and think it betters this patch please
+send me a new diff file so I can take a peek.
+
+
+CONTACT:
+This version of qregex was prepared by:
+	Andrew St. Jean
+	andrew@arda.homeunix.net
+	www.arda.homeunix.net/store/qmail/
+
+Documentation (manpage updates) and qmail-showctl patch added by:
+	Jeremy Kitchen	
+	kitchen at scriptkitchen dot com
+	http://www.scriptkitchen.com/qmail
+
+badhelo additions supplied by:
+	Alex Pleiner
+	alex@zeitform.de
+	zeitform Internet Dienste
+	http://www.zeitform.de/
+
+Original qregex patch can be found at:
+        www  : http://www.unixpimps.org/software/qregex
diff -u --unidirectional-new-file netqmail-1.05-org/TARGETS netqmail-1.05/TARGETS
--- netqmail-1.05-org/TARGETS	Mon Jun 15 19:53:16 1998
+++ netqmail-1.05/TARGETS	Tue Apr 20 11:29:04 2004
@@ -250,8 +250,10 @@
 qmail-qmtpd.o
 rcpthosts.o
 qmail-qmtpd
+base64.o
 qmail-smtpd.o
 qmail-smtpd
+qregex.o
 sendmail.o
 sendmail
 tcp-env.o
diff -u --unidirectional-new-file netqmail-1.05-org/base64.c netqmail-1.05/base64.c
--- netqmail-1.05-org/base64.c	Thu Jan  1 09:00:00 1970
+++ netqmail-1.05/base64.c	Tue Apr 20 11:26:30 2004
@@ -0,0 +1,90 @@
+#include "base64.h"
+#include "stralloc.h"
+#include "substdio.h"
+#include "str.h"
+
+static char *b64alpha =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+#define B64PAD '='
+
+/* returns 0 ok, 1 illegal, -1 problem */
+
+int b64decode(in,l,out)
+const unsigned char *in;
+int l;
+stralloc *out; /* not null terminated */
+{
+  int i, j;
+  unsigned char a[4];
+  unsigned char b[3];
+  char *s;
+
+  if (l == 0)
+  {
+    if (!stralloc_copys(out,"")) return -1;
+    return 0;
+  }
+
+  if (!stralloc_ready(out,l + 2)) return -1; /* XXX generous */
+  s = out->s;
+
+  for (i = 0;i < l;i += 4) {
+    for (j = 0;j < 4;j++)
+      if ((i + j) < l && in[i + j] != B64PAD)
+      {
+        a[j] = str_chr(b64alpha,in[i + j]);
+        if (a[j] > 63) return 1;
+      }
+      else a[j] = 0;
+
+    b[0] = (a[0] << 2) | (a[1] >> 4);
+    b[1] = (a[1] << 4) | (a[2] >> 2);
+    b[2] = (a[2] << 6) | (a[3]);
+
+    *s++ = b[0];
+
+    if (in[i + 1] == B64PAD) break;
+    *s++ = b[1];
+
+    if (in[i + 2] == B64PAD) break;
+    *s++ = b[2];
+  }
+  out->len = s - out->s;
+  while (out->len && !out->s[out->len - 1]) --out->len; /* XXX avoid? */
+  return 0;
+}
+
+int b64encode(in,out)
+stralloc *in;
+stralloc *out; /* not null terminated */
+{
+  unsigned char a, b, c;
+  int i;
+  char *s;
+
+  if (in->len == 0)
+  {
+    if (!stralloc_copys(out,"")) return -1;
+    return 0;
+  }
+
+  if (!stralloc_ready(out,in->len / 3 * 4 + 4)) return -1;
+  s = out->s;
+
+  for (i = 0;i < in->len;i += 3) {
+    a = in->s[i];
+    b = i + 1 < in->len ? in->s[i + 1] : 0;
+    c = i + 2 < in->len ? in->s[i + 2] : 0;
+
+    *s++ = b64alpha[a >> 2];
+    *s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)];
+
+    if (i + 1 >= in->len) *s++ = B64PAD;
+    else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)];
+
+    if (i + 2 >= in->len) *s++ = B64PAD;
+    else *s++ = b64alpha[c & 63];
+  }
+  out->len = s - out->s;
+  return 0;
+}
diff -u --unidirectional-new-file netqmail-1.05-org/base64.h netqmail-1.05/base64.h
--- netqmail-1.05-org/base64.h	Thu Jan  1 09:00:00 1970
+++ netqmail-1.05/base64.h	Tue Apr 20 11:26:30 2004
@@ -0,0 +1,7 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+extern int b64decode();
+extern int b64encode();
+
+#endif
diff -u --unidirectional-new-file netqmail-1.05-org/hier.c netqmail-1.05/hier.c
--- netqmail-1.05-org/hier.c	Mon Jun 15 19:53:16 1998
+++ netqmail-1.05/hier.c	Tue Apr 20 11:29:04 2004
@@ -76,6 +76,7 @@
   c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755);
 
   c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644);
diff -u --unidirectional-new-file netqmail-1.05-org/install-big.c netqmail-1.05/install-big.c
--- netqmail-1.05-org/install-big.c	Mon Jun 15 19:53:16 1998
+++ netqmail-1.05/install-big.c	Tue Apr 20 11:29:04 2004
@@ -76,6 +76,7 @@
   c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755);
 
   c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644);
diff -u --unidirectional-new-file netqmail-1.05-org/qmail-control.9 netqmail-1.05/qmail-control.9
--- netqmail-1.05-org/qmail-control.9	Mon Jun 15 19:53:16 1998
+++ netqmail-1.05/qmail-control.9	Tue Apr 20 11:29:04 2004
@@ -20,7 +20,9 @@
 
 Comments are allowed
 in
+.IR badhelo ,
 .IR badmailfrom ,
+.IR badmailto ,
 .IR locals ,
 .IR percenthack ,
 .IR qmqpservers ,
@@ -40,7 +42,9 @@
 .ta 5c 10c
 control	default	used by
 
+.I badhelo	\fR(none)	\fRqmail-smtpd
 .I badmailfrom	\fR(none)	\fRqmail-smtpd
+.I badmailto	\fR(none)	\fRqmail-smtpd
 .I bouncefrom	\fRMAILER-DAEMON	\fRqmail-send
 .I bouncehost	\fIme	\fRqmail-send
 .I concurrencylocal	\fR10	\fRqmail-send
diff -u --unidirectional-new-file netqmail-1.05-org/qmail-showctl.c netqmail-1.05/qmail-showctl.c
--- netqmail-1.05-org/qmail-showctl.c	Mon Jun 15 19:53:16 1998
+++ netqmail-1.05/qmail-showctl.c	Tue Apr 20 11:29:04 2004
@@ -214,7 +214,9 @@
     _exit(111);
   }
 
-  do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
+  do_lst("badhelo","Any HELO host name is allowed.",""," HELO host name denied if it matches this pattern.");
+  do_lst("badmailfrom","Any MAIL FROM is allowed.",""," MAIL FROM denied if it matches this pattern.");
+  do_lst("badmailto","No RCPT TO are specifically denied.",""," RCPT TO denied if it matches this pattern.");
   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 ","");
@@ -267,7 +269,9 @@
     if (str_equal(d->d_name,"..")) continue;
     if (str_equal(d->d_name,"bouncefrom")) continue;
     if (str_equal(d->d_name,"bouncehost")) continue;
+    if (str_equal(d->d_name,"badhelo")) continue;
     if (str_equal(d->d_name,"badmailfrom")) continue;
+    if (str_equal(d->d_name,"badmailto")) 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;
diff -u --unidirectional-new-file netqmail-1.05-org/qmail-smtpd.8 netqmail-1.05/qmail-smtpd.8
--- netqmail-1.05-org/qmail-smtpd.8	Mon Jun 15 19:53:16 1998
+++ netqmail-1.05/qmail-smtpd.8	Tue Apr 20 11:29:04 2004
@@ -3,6 +3,11 @@
 qmail-smtpd \- receive mail via SMTP
 .SH SYNOPSIS
 .B qmail-smtpd
+[
+.I hostname
+.I checkprogram
+.I subprogram
+]
 .SH DESCRIPTION
 .B qmail-smtpd
 receives mail messages via the Simple Mail Transfer Protocol (SMTP)
@@ -23,7 +28,29 @@
 header fields.
 
 .B qmail-smtpd
-supports ESMTP, including the 8BITMIME and PIPELINING options.
+supports ESMTP, including the 8BITMIME, PIPELINING, and AUTH options.
+
+.B qmail-smtpd
+can accept LOGIN, PLAIN, and CRAM-MD5 AUTH types.  It invokes
+.IR checkprogram ,
+which reads on file descriptor 3 the username, a 0 byte, the password
+or challenge derived from
+.IR hostname ,
+another 0 byte, a CRAM-MD5 response (if applicable to the AUTH type),
+and a final 0 byte.
+.I checkprogram
+invokes
+.I subprogram
+upon successful authentication, which should in turn return 0 to
+.BR qmail-smtpd ,
+effectively setting the environment variables RELAYCLIENT and TCPREMOTEINFO
+(any supplied value replaced with the authenticated username).
+.B qmail-smtpd
+will reject the authentication attempt if it receives a nonzero return
+value from
+.I checkprogram
+or
+.IR subprogram .
 .SH TRANSPARENCY
 .B qmail-smtpd
 converts the SMTP newline convention into the UNIX newline convention
@@ -37,11 +64,25 @@
 even though such messages violate the SMTP protocol.
 .SH "CONTROL FILES"
 .TP 5
+.I badhelo
+Unacceptable HELO/EHLO host names.
+.B qmail-smtpd
+will reject every recipient address for a message if
+the host name is listed in, 
+or matches a POSIX regular expression pattern listed in,
+.IR badhelo .
+If the NOBADHELO environment variable is set, then the 
+contents of 
+.IR badhelo 
+will be ignored.
+For more information, please have a look at doc/README.qregex.
+.TP 5
 .I badmailfrom
 Unacceptable envelope sender addresses.
 .B qmail-smtpd
 will reject every recipient address for a message
-if the envelope sender address is listed in
+if the envelope sender address is listed in, or matches a POSIX regular expression
+pattern listed in,
 .IR badmailfrom .
 A line in
 .I badmailfrom
@@ -49,6 +90,16 @@
 .BR @\fIhost ,
 meaning every address at
 .IR host .
+For more information, please have a look at doc/README.qregex.
+.TP 5
+.I badmailto
+Unacceptable recipient addresses.
+.B qmail-smtpd
+will reject every recipient address for a message if the recipient address
+is listed in,
+or matches a POSIX regular expression pattern listed in,
+.IR badmailto .
+For more information, please have a look at doc/README.qregex.
 .TP 5
 .I databytes
 Maximum number of bytes allowed in a message,
@@ -177,3 +228,6 @@
 qmail-newmrh(8),
 qmail-queue(8),
 qmail-remote(8)
+.SH "HISTORY"
+The patch enabling the ESMTP AUTH option is not part of the standard
+qmail-1.03 distribution.
diff -u --unidirectional-new-file netqmail-1.05-org/qmail-smtpd.c netqmail-1.05/qmail-smtpd.c
--- netqmail-1.05-org/qmail-smtpd.c	Tue Apr 20 10:28:41 2004
+++ netqmail-1.05/qmail-smtpd.c	Tue Apr 20 11:47:46 2004
@@ -23,7 +23,16 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 #include "commands.h"
+#include "wait.h"
+#include "fd.h"
+#include "qregex.h"
+#include "strerr.h"
+
+#define BMCHECK_BMF 0
+#define BMCHECK_BMT 1
+#define BMCHECK_BHELO 2
 
+#define AUTHCRAM
 #define MAXHOPS 100
 unsigned int databytes = 0;
 int timeout = 1200;
@@ -49,7 +58,9 @@
 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 err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\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_bhelo() { out("553 sorry, your HELO host name has been denied (#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(arg) char *arg; { out("502 unimplemented (#5.5.1)\r\n"); }
 void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
@@ -59,6 +70,15 @@
 void err_vrfy(arg) char *arg; { out("252 send some mail, i'll try my best\r\n"); }
 void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
 
+int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
+int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
+int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
+int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; }
+void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); }
+void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); }
+int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; }
+int err_authabrt() { out("501 auth exchange cancelled (#5.0.0)\r\n"); return -1; }
+int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
 
 stralloc greeting = {0};
 
@@ -93,9 +113,15 @@
 
 int liphostok = 0;
 stralloc liphost = {0};
+
 int bmfok = 0;
 stralloc bmf = {0};
-struct constmap mapbmf;
+
+int bmtok = 0;
+stralloc bmt = {0};
+
+int bhelook = 0;
+stralloc bhelo = {0};
 
 void setup()
 {
@@ -114,8 +140,13 @@
 
   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();
+
+  bmtok = control_readfile(&bmt,"control/badmailto",0);
+  if (bmtok == -1) die_control();
+
+  bhelook = control_readfile(&bhelo, "control/badhelo",0);
+  if (bhelook == -1) die_control();
+  if (env_get("NOBADHELO")) bhelook = 0;
  
   if (control_readint(&databytes,"control/databytes") == -1) die_control();
   x = env_get("DATABYTES");
@@ -197,14 +228,44 @@
   return 1;
 }
 
-int bmfcheck()
+int bmcheck(which) int which;
 {
-  int j;
-  if (!bmfok) return 0;
-  if (constmap(&mapbmf,addr.s,addr.len - 1)) 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;
+  int i = 0;
+  int j = 0;
+  int x = 0;
+  int negate = 0;
+  static stralloc bmb = {0};
+  static stralloc curregex = {0};
+
+  if (which == BMCHECK_BMF) {
+    if (!stralloc_copy(&bmb,&bmf)) die_nomem();
+  } else if (which == BMCHECK_BMT) {
+    if (!stralloc_copy(&bmb,&bmt)) die_nomem();
+  } else if (which == BMCHECK_BHELO) {
+    if (!stralloc_copy(&bmb,&bhelo)) die_nomem();
+  } else {
+    die_control();
+  }
+
+  while (j < bmb.len) {
+    i = j;
+    while ((bmb.s[i] != '\0') && (i < bmb.len)) i++;
+    if (bmb.s[j] == '!') {
+      negate = 1;
+      j++;
+    }
+    if (!stralloc_copyb(&curregex,bmb.s + j,(i - j))) die_nomem();
+    if (!stralloc_0(&curregex)) die_nomem();
+    if (which == BMCHECK_BHELO) {
+      x = matchregex(helohost.s, curregex.s);
+    } else {
+      x = matchregex(addr.s, curregex.s);
+    }
+    if ((negate) && (x == 0)) return 1;
+    if (!(negate) && (x > 0)) return 1;
+    j = i + 1;
+    negate = 0;
+  }
   return 0;
 }
 
@@ -218,7 +279,9 @@
 
 
 int seenmail = 0;
-int flagbarf; /* defined if seenmail */
+int flagbarfbmf; /* defined if seenmail */
+int flagbarfbmt;
+int flagbarfbhelo;
 stralloc mailfrom = {0};
 stralloc rcptto = {0};
 
@@ -226,11 +289,21 @@
 {
   smtp_greet("250 "); out("\r\n");
   seenmail = 0; dohelo(arg);
+  if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
 }
 void smtp_ehlo(arg) char *arg;
 {
-  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+  smtp_greet("250-");
+#ifdef AUTHCRAM
+  out("\r\n250-AUTH LOGIN CRAM-MD5 PLAIN");
+  out("\r\n250-AUTH=LOGIN CRAM-MD5 PLAIN");
+#else
+  out("\r\n250-AUTH LOGIN PLAIN");
+  out("\r\n250-AUTH=LOGIN PLAIN");
+#endif
+  out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
   seenmail = 0; dohelo(arg);
+  if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
 }
 void smtp_rset(arg) char *arg;
 {
@@ -240,7 +313,8 @@
 void smtp_mail(arg) char *arg;
 {
   if (!addrparse(arg)) { err_syntax(); return; }
-  flagbarf = bmfcheck();
+  flagbarfbmf = 0; /* bmcheck is skipped for empty envelope senders */
+  if ((addr.len != 1) && (bmfok)) flagbarfbmf = bmcheck(BMCHECK_BMF);
   seenmail = 1;
   if (!stralloc_copys(&rcptto,"")) die_nomem();
   if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
@@ -250,7 +324,22 @@
 void smtp_rcpt(arg) char *arg; {
   if (!seenmail) { err_wantmail(); return; }
   if (!addrparse(arg)) { err_syntax(); return; }
-  if (flagbarf) { err_bmf(); return; }
+  if (flagbarfbhelo) {
+    strerr_warn4("qmail-smtpd: badhelo: ",helohost.s," at ",remoteip,0);
+    err_bhelo();
+    return;
+  }
+  if (flagbarfbmf) {
+    strerr_warn4("qmail-smtpd: badmailfrom: ",mailfrom.s," at ",remoteip,0);
+    err_bmf();
+    return;
+  }
+  if (bmtok) { flagbarfbmt = bmcheck(BMCHECK_BMT); }
+  if (flagbarfbmt) {
+    strerr_warn4("qmail-smtpd: badmailto: ",addr.s," at ",remoteip,0);
+    err_bmt();
+    return;
+  }
   if (relayclient) {
     --addr.len;
     if (!stralloc_cats(&addr,relayclient)) die_nomem();
@@ -394,10 +483,226 @@
   out("\r\n");
 }
 
+
+char unique[FMT_ULONG + FMT_ULONG + 3];
+static stralloc authin = {0};
+static stralloc user = {0};
+static stralloc pass = {0};
+static stralloc resp = {0};
+static stralloc slop = {0};
+char *hostname;
+char **childargs;
+substdio ssup;
+char upbuf[128];
+int authd = 0;
+
+int authgetl(void) {
+  int i;
+
+  if (!stralloc_copys(&authin, "")) die_nomem();
+
+  for (;;) {
+    if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
+    i = substdio_get(&ssin,authin.s + authin.len,1);
+    if (i != 1) die_read();
+    if (authin.s[authin.len] == '\n') break;
+    ++authin.len;
+  }
+
+  if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
+  authin.s[authin.len] = 0;
+
+  if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
+  if (authin.len == 0) { return err_input(); }
+  return authin.len;
+}
+
+int authenticate(void)
+{
+  int child;
+  int wstat;
+  int pi[2];
+
+  if (!stralloc_0(&user)) die_nomem();
+  if (!stralloc_0(&pass)) die_nomem();
+  if (!stralloc_0(&resp)) die_nomem();
+
+  if (fd_copy(2,1) == -1) return err_pipe();
+  close(3);
+  if (pipe(pi) == -1) return err_pipe();
+  if (pi[0] != 3) return err_pipe();
+  switch(child = fork()) {
+    case -1:
+      return err_fork();
+    case 0:
+      close(pi[1]);
+      sig_pipedefault();
+      execvp(*childargs, childargs);
+      _exit(1);
+  }
+  close(pi[0]);
+
+  substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf);
+  if (substdio_put(&ssup,user.s,user.len) == -1) return err_write();
+  if (substdio_put(&ssup,pass.s,pass.len) == -1) return err_write();
+  if (substdio_put(&ssup,resp.s,resp.len) == -1) return err_write();
+  if (substdio_flush(&ssup) == -1) return err_write();
+
+  close(pi[1]);
+  byte_zero(pass.s,pass.len);
+  byte_zero(upbuf,sizeof upbuf);
+  if (wait_pid(&wstat,child) == -1) return err_child();
+  if (wait_crashed(wstat)) return err_child();
+  if (wait_exitcode(wstat)) { sleep(5); return 1; } /* no */
+  return 0; /* yes */
+}
+
+int auth_login(arg) char *arg;
+{
+  int r;
+
+  if (*arg) {
+    if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
+  }
+  else {
+    out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
+    if (authgetl() < 0) return -1;
+    if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
+  }
+  if (r == -1) die_nomem();
+
+  out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */
+
+  if (authgetl() < 0) return -1;
+  if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
+  if (r == -1) die_nomem();
+
+  if (!user.len || !pass.len) return err_input();
+  return authenticate();  
+}
+
+int auth_plain(arg) char *arg;
+{
+  int r, id = 0;
+
+  if (*arg) {
+    if (r = b64decode(arg,str_len(arg),&slop) == 1) return err_input();
+  }
+  else {
+    out("334 \r\n"); flush();
+    if (authgetl() < 0) return -1;
+    if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input();
+  }
+  if (r == -1 || !stralloc_0(&slop)) die_nomem();
+  while (slop.s[id]) id++; /* ignore authorize-id */
+
+  if (slop.len > id + 1)
+    if (!stralloc_copys(&user,slop.s + id + 1)) die_nomem();
+  if (slop.len > id + user.len + 2)
+    if (!stralloc_copys(&pass,slop.s + id + user.len + 2)) die_nomem();
+
+  if (!user.len || !pass.len) return err_input();
+  return authenticate();
+}
+
+#ifdef AUTHCRAM
+int auth_cram()
+{
+  int i, r;
+  char *s;
+
+  s = unique;
+  s += fmt_uint(s,getpid());
+  *s++ = '.';
+  s += fmt_ulong(s,(unsigned long) now());
+  *s++ = '@';
+  *s++ = 0;
+
+  if (!stralloc_copys(&pass,"<")) die_nomem();
+  if (!stralloc_cats(&pass,unique)) die_nomem();
+  if (!stralloc_cats(&pass,hostname)) die_nomem();
+  if (!stralloc_cats(&pass,">")) die_nomem();
+  if (b64encode(&pass,&slop) < 0) die_nomem();
+  if (!stralloc_0(&slop)) die_nomem();
+
+  out("334 ");
+  out(slop.s);
+  out("\r\n");
+  flush();
+
+  if (authgetl() < 0) return -1;
+  if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input();
+  if (r == -1 || !stralloc_0(&slop)) die_nomem();
+
+  i = str_chr(slop.s,' ');
+  s = slop.s + i;
+  while (*s == ' ') ++s;
+  slop.s[i] = 0;
+  if (!stralloc_copys(&user,slop.s)) die_nomem();
+  if (!stralloc_copys(&resp,s)) die_nomem();
+
+  if (!user.len || !resp.len) return err_input();
+  return authenticate();
+}
+#endif
+
+struct authcmd {
+  char *text;
+  int (*fun)();
+} authcmds[] = {
+  { "login", auth_login }
+, { "plain", auth_plain }
+#ifdef AUTHCRAM
+, { "cram-md5", auth_cram }
+#endif
+, { 0, err_noauth }
+};
+
+void smtp_auth(arg)
+char *arg;
+{
+  int i;
+  char *cmd = arg;
+
+  if (!hostname || !*childargs)
+  {
+    out("503 auth not available (#5.3.3)\r\n");
+    return;
+  }
+  if (authd) { err_authd(); return; }
+  if (seenmail) { err_authmail(); return; }
+
+  if (!stralloc_copys(&user,"")) die_nomem();
+  if (!stralloc_copys(&pass,"")) die_nomem();
+  if (!stralloc_copys(&resp,"")) die_nomem();
+
+  i = str_chr(cmd,' ');   
+  arg = cmd + i;
+  while (*arg == ' ') ++arg;
+  cmd[i] = 0;
+
+  for (i = 0;authcmds[i].text;++i)
+    if (case_equals(authcmds[i].text,cmd)) break;
+
+  switch (authcmds[i].fun(arg)) {
+    case 0:
+      authd = 1;
+      relayclient = "";
+      remoteinfo = user.s;
+      if (!env_unset("TCPREMOTEINFO")) die_read();
+      if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
+      out("235 ok, go ahead (#2.0.0)\r\n");
+      break;
+    case 1:
+      out("535 authorization failed (#5.7.0)\r\n");
+  }
+}
+
 struct commands smtpcommands[] = {
   { "rcpt", smtp_rcpt, 0 }
 , { "mail", smtp_mail, 0 }
 , { "data", smtp_data, flush }
+, { "auth", smtp_auth, flush }
 , { "quit", smtp_quit, flush }
 , { "helo", smtp_helo, flush }
 , { "ehlo", smtp_ehlo, flush }
@@ -408,8 +713,13 @@
 , { 0, err_unimpl, flush }
 } ;
 
-void main()
+void main(argc,argv)
+int argc;
+char **argv;
 {
+  hostname = argv[1];
+  childargs = argv + 2;
+
   sig_pipeignore();
   if (chdir(auto_qmail) == -1) die_control();
   setup();
diff -u --unidirectional-new-file netqmail-1.05-org/qregex.c netqmail-1.05/qregex.c
--- netqmail-1.05-org/qregex.c	Thu Jan  1 09:00:00 1970
+++ netqmail-1.05/qregex.c	Tue Apr 20 11:29:04 2004
@@ -0,0 +1,57 @@
+/*
+ * qregex (v2)
+ * $Id: qregex.c,v 2.1 2001/12/28 07:05:21 evan Exp $
+ *
+ * Author  : Evan Borgstrom (evan at unixpimps dot org)
+ * Created : 2001/12/14 23:08:16
+ * Modified: $Date: 2001/12/28 07:05:21 $
+ * Revision: $Revision: 2.1 $
+ *
+ * Do POSIX regex matching on addresses for anti-relay / spam control.
+ * It logs to the maillog
+ * See the qregex-readme file included with this tarball.
+ * If you didn't get this file in a tarball please see the following URL:
+ *  http://www.unixpimps.org/software/qregex
+ *
+ * qregex.c is released under a BSD style copyright.
+ * See http://www.unixpimps.org/software/qregex/copyright.html
+ *
+ * Note: this revision follows the coding guidelines set forth by the rest of
+ *       the qmail code and that described at the following URL.
+ *       http://cr.yp.to/qmail/guarantee.html
+ * 
+ */
+
+#include <sys/types.h>
+#include <regex.h>
+#include "qregex.h"
+
+#define REGCOMP(X,Y)    regcomp(&X, Y, REG_EXTENDED|REG_ICASE)
+#define REGEXEC(X,Y)    regexec(&X, Y, (size_t)0, (regmatch_t *)0, (int)0)
+
+int matchregex(char *text, char *regex) {
+  regex_t qreg;
+  int retval = 0;
+
+
+  /* build the regex */
+  if ((retval = REGCOMP(qreg, regex)) != 0) {
+    regfree(&qreg);
+    return(-retval);
+  }
+
+  /* execute the regex */
+  if ((retval = REGEXEC(qreg, text)) != 0) {
+    /* did we just not match anything? */
+    if (retval == REG_NOMATCH) {
+      regfree(&qreg);
+      return(0);
+    }
+    regfree(&qreg);
+    return(-retval);
+  }
+
+  /* signal the match */
+  regfree(&qreg);
+  return(1);
+}
diff -u --unidirectional-new-file netqmail-1.05-org/qregex.h netqmail-1.05/qregex.h
--- netqmail-1.05-org/qregex.h	Thu Jan  1 09:00:00 1970
+++ netqmail-1.05/qregex.h	Tue Apr 20 11:29:04 2004
@@ -0,0 +1,5 @@
+/* simple header file for the matchregex prototype */
+#ifndef _QREGEX_H_
+#define _QREGEX_H_
+int matchregex(char *text, char *regex);
+#endif
