File netqmail-1.06-authentication075-pc.patch of Package netqmail

diff -rNU3 netqmail-1.06/base64.c netqmail-1.06.075/base64.c
--- netqmail-1.06/base64.c	1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06.075/base64.c	2012-11-30 14:25:04.000000000 +0100
@@ -0,0 +1,124 @@
+#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 p = 0;
+  int n;
+  unsigned int x;
+  int i, j;
+  char *s;
+  unsigned char b[3];
+
+  if (l == 0)
+  {
+    if (!stralloc_copys(out,"")) return -1;
+    return 0;
+  }
+
+  while(in[l-1] == B64PAD) {
+    p ++;
+    l--;
+  }
+
+  n = (l + p) / 4;
+  i = (n * 3) - p;
+  if (!stralloc_ready(out,i)) return -1;
+  out->len = i;
+  s = out->s;
+
+  for(i = 0; i < n - 1 ; i++) {
+    x = 0;
+    for(j = 0; j < 4; j++) {
+      if(in[j] >= 'A' && in[j] <= 'Z')
+        x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
+      else if(in[j] >= 'a' && in[j] <= 'z')
+        x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
+      else if(in[j] >= '0' && in[j] <= '9')
+        x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
+      else if(in[j] == '+')
+        x = (x << 6) + 62;
+      else if(in[j] == '/')
+        x = (x << 6) + 63;
+      else if(in[j] == '=')
+        x = (x << 6);
+    }
+
+    s[2] = (unsigned char)(x & 255); x >>= 8;
+    s[1] = (unsigned char)(x & 255); x >>= 8;
+    s[0] = (unsigned char)(x & 255); x >>= 8;
+    s += 3; in += 4;
+  }
+
+  x = 0;
+  for(j = 0; j < 4; j++) {
+    if(in[j] >= 'A' && in[j] <= 'Z')
+      x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
+    else if(in[j] >= 'a' && in[j] <= 'z')
+      x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
+    else if(in[j] >= '0' && in[j] <= '9')
+      x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
+    else if(in[j] == '+')
+      x = (x << 6) + 62;
+    else if(in[j] == '/')
+      x = (x << 6) + 63;
+    else if(in[j] == '=')
+      x = (x << 6);
+  }
+
+  b[2] = (unsigned char)(x & 255); x >>= 8;
+  b[1] = (unsigned char)(x & 255); x >>= 8;
+  b[0] = (unsigned char)(x & 255); x >>= 8;
+
+  for(i = 0; i < 3 - p; i++)
+    s[i] = b[i];
+
+  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;
+  }
+
+  i = in->len / 3 * 4 + 4;   
+  if (!stralloc_ready(out,i)) 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 -rNU3 netqmail-1.06/base64.h netqmail-1.06.075/base64.h
--- netqmail-1.06/base64.h	1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06.075/base64.h	2012-11-30 14:25:04.000000000 +0100
@@ -0,0 +1,9 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+#include "stralloc.h"
+
+extern int b64decode(const unsigned char *in, int l, stralloc *out);
+extern int b64encode(stralloc *in, stralloc *out);
+
+#endif
diff -rNU3 netqmail-1.06/FILES.auth netqmail-1.06.075/FILES.auth
--- netqmail-1.06/FILES.auth	1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06.075/FILES.auth	2012-11-30 14:25:04.000000000 +0100
@@ -0,0 +1,27 @@
+The qmail-smtpd Auth patch modifies the following QMAIL 1.03 files:
+
+= TARGETS
+= Makefile
+= qmail-smtpd.c
+= qmail-smtpd.8
+= qmail-remote.c
+= qmail-remote.8
+= qmail-showctl.c
+= qmail-control.9
+
+Added files:
+
++ base64.c
++ base64.h
++ case_startb.c
++ hmac_md5.h
++ hmac_md5.c
++ global.h
++ md5.h
++ md5c.c
+
+Informational files:
+
+% install_auth.sh  (Installation shell script)
+% LICENSE.authentication (some sort of ...)
+% README.auth
diff -rNU3 netqmail-1.06/hmac_md5.h netqmail-1.06.075/hmac_md5.h
--- netqmail-1.06/hmac_md5.h	1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06.075/hmac_md5.h	2012-11-30 14:26:09.000000000 +0100
@@ -0,0 +1,5 @@
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+
+#define hmac_md5(t, tl, k, kl, d)       \
+        HMAC(EVP_md5(), k, kl, t, tl, d, NULL)
diff -rNU3 netqmail-1.06/install_authentication.sh netqmail-1.06.075/install_authentication.sh
--- netqmail-1.06/install_authentication.sh	1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06.075/install_authentication.sh	2012-11-30 14:25:04.000000000 +0100
@@ -0,0 +1,101 @@
+#!/bin/sh
+#
+# qmail-smtpd AUTH (UN)INSTALL Script (install_authentication.sh)
+# -------------------------------------------------------------------------------------
+#
+# Purpose:      To install and uninstall the qmail-smtpd Authentication Patch
+#
+# Parameters:   -u (uninstall)
+#	        VRF (Version to be uninstalled)
+#
+# Usage:        ./install_authentication.sh [-u] [Version]
+#
+#		Installation: 	./install_authentication.sh
+# 		Uninstallation: ./install_authentication.sh -u 105
+#
+# Return Codes: 0 - Patches applied successfully
+#		1 - Original QMAIL files not found (Patch not extracted in QMAIL source directory)
+#		2 - Patch files not found 
+#
+# Output:	install_auth.log
+#
+# History:      1.0.0 - Erwin Hoffmann - Initial release
+#		1.0.1 - 	       - grep fix; Gentoo fix
+#		1.0.2 -			 removed '-v' optio for cp
+#		1.0.3 -			 mods for 'qmail authentication'
+#		1.0.4 -                  some renameing
+#
+#---------------------------------------------------------------------------------------
+#
+DATE=$(date)
+LOCDIR=${PWD}
+QMAILHOME=$(head -n 1 conf-qmail)
+SOLARIS=$(sh ./find-systype.sh | grep -ci "SunOS")
+LOGFILE=auth.log
+TARGETS=FILES.auth
+IFSKEEP=${IFS}
+REL=075 # Should be identical to qmail AUTH level
+BUILD=20121023222616
+
+
+if [ $# -eq 0 ] ; then
+
+	echo "Installing qmail AUTH $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1 
+
+	for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do
+		echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1
+		if [ -s ${FILE} ] ; then
+			cp ${FILE} ${FILE}.$REL | tee -a $LOGFILE 2>&1
+			echo "--> ${FILE} copied to ${FILE}.$REL" | tee -a $LOGFILE 2>&1
+		else
+			echo "${FILE} not found !"
+			exit 1
+		fi
+		if [ -s ${FILE}.patch ] ; then
+			if [ ${SOLARIS} -gt 0 ]; then
+				echo "--> Patching qmail source file ${FILE} for Solaris ...." | tee -a $LOGFILE 2>&1
+				patch -i ${FILE}.patch ${FILE} 2>&1 | tee -a $LOGFILE
+			else
+				echo "--> Patching qmail source file ${FILE}  ...." | tee -a $LOGFILE 2>&1
+				patch ${FILE} ${FILE}.patch 2>&1 | tee -a $LOGFILE
+			fi
+		else
+			echo "!! ${FILE}.patch not found !"
+			exit 2
+		fi
+	done 
+
+
+	echo "Copying documentation and samples to ${QMAILHOME}/doc/ ..." | tee -a $LOGFILE 2>&1 
+
+	cp README.auth* ${QMAILHOME}/doc/ | tee -a $LOGFILE 2>&1
+	echo ""
+	echo "If you dont wont CRAM-MD5 suport disable '#define CRAM_MD5' in qmail-smtpd !"
+	echo "Installation of qmail authentication $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1 
+
+# Now go for the uninstallation....
+
+elif [ "$1" = "-u" ] ; then
+
+# Get the Version Number from INPUT 
+
+	if [ $# -eq 2 ] ; then
+		REL=$2
+	fi
+
+	echo "De-installing qmail authentication $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1 
+
+	for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do
+		echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1
+		if [ -s ${FILE}.$REL ] ; then
+			mv ${FILE}.$REL ${FILE} | tee -a $LOGFILE 2>&1
+			touch ${FILE}
+			echo "--> ${FILE}.$REL moved to ${FILE}" | tee -a $LOGFILE 2>&1
+		else
+			echo "!! ${FILE}.$REL not found !"
+		fi
+	done
+	echo "De-installation of qmail authentication $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1 
+fi
+
+exit 0
diff -rNU3 netqmail-1.06/LICENSE.authentication netqmail-1.06.075/LICENSE.authentication
--- netqmail-1.06/LICENSE.authentication	1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06.075/LICENSE.authentication	2012-11-30 14:25:04.000000000 +0100
@@ -0,0 +1,43 @@
+AUTHOR
+======
+
+Author:
+	Dr. Erwin Hoffmann - FEHCom Germany
+Web-Site: 	
+	http://www.fehcom.de/qmail.html
+E-Mail: 	
+	feh@fehcom.de
+
+
+LICENSE
+=======
+
+qmail AUTHENTICATION is free software.
+This includes:
+	You can download and use qmail AUTHENTICATION (and parts of it) as you like.
+	You can modify the source code without notification to or permission by the author.
+Please check:
+	http://www.cr.yp.to/softwarelaw.html
+
+
+DEPENDENCIES
+============
+
+qmail AUTHENTICATION patches (modifies) parts of the qmail-1.03 source files.
+It should only be applied against the source as supplied by D.J. Bernstein.
+
+
+FITNESS
+=======
+
+The Author does not guarantee a specific fitness of qmail AUTHENTICATION.
+If you use qmail AUTHENTICATION, it's on your own risk.
+
+
+DISTRIBUTION
+============
+
+qmail AUTHENTICATION may be included in ports and packages under the following conditions:
+	The port/package has to show the current version number of qmail AUTHENTICATION.
+	All files (namely this) have to be included.
+
diff -rNU3 netqmail-1.06/Makefile netqmail-1.06.075/Makefile
--- netqmail-1.06/Makefile	2012-11-30 14:28:47.000000000 +0100
+++ netqmail-1.06.075/Makefile	2012-11-30 14:40:45.000000000 +0100
@@ -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 \
@@ -1446,13 +1450,13 @@
 load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \
 timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \
 ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \
-substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib
+substdio.a error.a str.a fs.a auto_qmail.o base64.o dns.lib socket.lib
 	./load qmail-remote control.o constmap.o timeoutread.o \
 	timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
 	tls.o ssl_timeoutio.o -L/usr/local/ssl/lib -lssl -lcrypto \
 	ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
 	lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
-	str.a fs.a auto_qmail.o  `cat dns.lib` `cat socket.lib`
+	str.a fs.a auto_qmail.o base64.o `cat dns.lib` `cat socket.lib`
 
 qmail-remote.0: \
 qmail-remote.8
@@ -1463,7 +1467,7 @@
 subfd.h substdio.h scan.h case.h error.h auto_qmail.h control.h dns.h \
 alloc.h quote.h ip.h ipalloc.h ip.h gen_alloc.h ipme.h ip.h ipalloc.h \
 gen_alloc.h gen_allocdefs.h str.h now.h datetime.h exit.h constmap.h \
-tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h
+tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h base64.h hmac_md5.h
 	./compile qmail-remote.c
 
 qmail-rspawn: \
@@ -1547,14 +1551,14 @@
 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 str.a qmail-spp.o socket.lib
+fs.a auto_qmail.o str.a qmail-spp.o base64.o socket.lib
 	./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
 	timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
 	tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \
 	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
 	datetime.a getln.a open.a sig.a case.a qmail-spp.o env.a stralloc.a \
 	alloc.a substdio.a error.a str.a fs.a auto_qmail.o \
-	str.a `cat socket.lib`
+	str.a base64.o `cat socket.lib`
 
 qmail-smtpd.0: \
 qmail-smtpd.8
@@ -1563,7 +1567,7 @@
 qmail-smtpd.o: \
 compile qmail-smtpd.c sig.h readwrite.h stralloc.h gen_alloc.h \
 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 \
+error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h base64.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 qmail-spp.h
 	./compile qmail-smtpd.c
diff -rNU3 netqmail-1.06/md5.h netqmail-1.06.075/md5.h
--- netqmail-1.06/md5.h	1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06.075/md5.h	2012-11-30 14:25:49.000000000 +0100
@@ -0,0 +1 @@
+#include <openssl/md5.h>
diff -rNU3 netqmail-1.06/qmail-control.9 netqmail-1.06.075/qmail-control.9
--- netqmail-1.06/qmail-control.9	2012-11-30 14:28:47.000000000 +0100
+++ netqmail-1.06.075/qmail-control.9	2012-11-30 14:43:11.000000000 +0100
@@ -40,6 +40,7 @@
 .ta 5c 10c
 control	default	used by
 
+.I authsender	\fR(none)	\fRqmail-remote
 .I badmailfrom	\fR(none)	\fRqmail-smtpd
 .I bouncefrom	\fRMAILER-DAEMON	\fRqmail-send
 .I bouncehost	\fIme	\fRqmail-send
diff -rNU3 netqmail-1.06/qmail-remote.8 netqmail-1.06.075/qmail-remote.8
--- netqmail-1.06/qmail-remote.8	2012-11-30 14:28:47.000000000 +0100
+++ netqmail-1.06.075/qmail-remote.8	2012-11-30 14:33:58.000000000 +0100
@@ -53,6 +53,7 @@
 and does not follow the
 .B getopt
 standard.
+
 .SH TRANSPARENCY
 End-of-file in SMTP is encoded as dot CR LF.
 A dot at the beginning of a line is encoded as dot dot.
@@ -100,6 +101,73 @@
 After this letter comes a human-readable description of
 what happened.
 
+.B qmail-remote
+may use SMTP Authenticaton of type CRAM-MD4, PLAIN, or LOGIN
+(in this order) to connect to remote hosts.
+The following reports are provided:
+.TP 5
+K
+no supported AUTH method found, continuing without authentication.
+.TP 5
+Z
+Connected to 
+.I host
+but authentication was rejected (AUTH PLAIN).
+.TP 5
+Z
+Connected to 
+.I host 
+but unable to base64encode (plain).
+.TP 5
+Z
+Connected to 
+.I host
+but authentication was rejected (plain)."
+.TP 5
+Z
+Connected to
+.I host
+but authentication was rejected (AUTH LOGIN).
+.TP 5
+Z
+Connected to 
+.I host
+but unable to base64encode user.
+.TP 5
+Z
+Connected to 
+.I host 
+but authentication was rejected (username).
+.TP 5
+Z
+Connected to 
+.I host 
+but unable to base64encode pass.
+.TP 5
+Z
+Connected to
+.I host
+but authentication was rejected (AUTH CRAM-MD5).
+Z
+Connected to 
+.I host
+but unable to base64decode challenge.
+.TP 5
+Z
+Connected to 
+.I host
+but unable to base64encode username+digest.
+.TP 5
+Z
+Connected to 
+.I host 
+but password expired.
+.TP 5
+Z
+Connected to 
+.I host 
+but authentication was rejected (username+digest).
+.PP
 The recipient reports will always be printed in the same order as
 .BR qmail-remote 's
 .I recip
@@ -118,6 +186,51 @@
 SSL certificate that is used to authenticate with the remote server
 during a TLS session.
 .TP 5
+.I authsenders
+Authenticated sender.
+For each
+.I sender 
+included in 
+.IR authsenders :
+.I sender\fB:\fIrelay\fB:\fIport\fB|\fIuser\fB|\fIpassword 
+.B qmail-remote
+will try SMTP Authentication 
+of type CRAM-MD5, LOGIN, or PLAIN 
+with the provided user name
+.I user 
+and password
+.I password 
+(the authentication information) 
+and eventually relay the 
+mail through
+.I relay
+on port
+.IR port .
+The use of 
+.I relay
+and 
+.I port 
+follows the same rules as for
+.IR smtproutes 
+Note: In case
+.I sender
+is empty, 
+.B qmail-remote
+will try to deliver each outgoing mail 
+SMTP authenticated. If the authentication
+information is missing, the mail is 
+delivered none-authenticated.
+.I authsenders
+can be constructed as follows:
+
+.EX
+   @example.com|generic|passwd
+   .subdomain.example.com|other|otherpw
+   mail@example.com|test|testpass
+   info@example.com:smtp.example.com:26|other|otherpw
+   :mailrelay.example.com:587|e=mc2|testpass
+.EE
+.TP 5
 .I helohost
 Current host name,
 for use solely in saying hello to the remote SMTP server.
diff -rNU3 netqmail-1.06/qmail-remote.c netqmail-1.06.075/qmail-remote.c
--- netqmail-1.06/qmail-remote.c	2012-11-30 14:28:47.000000000 +0100
+++ netqmail-1.06.075/qmail-remote.c	2012-11-30 14:53:34.000000000 +0100
@@ -28,6 +28,8 @@
 #include "timeoutconn.h"
 #include "timeoutread.h"
 #include "timeoutwrite.h"
+#include "base64.h"
+#include "hmac_md5.h"
 
 #define HUGESMTPTEXT 5000
 
@@ -44,6 +45,16 @@
 stralloc host = {0};
 stralloc sender = {0};
 
+stralloc authsenders = {0};
+struct constmap mapauthsenders;
+stralloc user = {0};
+stralloc pass = {0};
+stralloc auth = {0};
+stralloc plain = {0};
+stralloc chal  = {0};
+stralloc slop  = {0};
+char *authsender;
+
 saa reciplist = {0};
 
 struct ip_address partner;
@@ -99,6 +110,12 @@
 it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
 zerodie(); }
 
+void err_authprot() {
+  out("Kno supported AUTH method found, continuing without authentication.\n");
+  zero();
+  substdio_flush(subfdoutsmall);
+}
+
 void outhost()
 {
   char x[IPFMT];
@@ -531,6 +548,162 @@
 
 stralloc recip = {0};
 
+void mailfrom()
+{
+  substdio_puts(&smtpto,"MAIL FROM:<");
+  substdio_put(&smtpto,sender.s,sender.len);
+  substdio_puts(&smtpto,">\r\n");
+  substdio_flush(&smtpto);
+}
+
+stralloc xuser = {0};
+
+int xtext(sa,s,len)
+stralloc *sa;
+char *s;
+int len;
+{
+  int i;
+
+  if(!stralloc_copys(sa,"")) temp_nomem();
+  
+  for (i = 0; i < len; i++) {
+    if (s[i] == '=') {
+      if (!stralloc_cats(sa,"+3D")) temp_nomem();
+    } else if (s[i] == '+') {  
+        if (!stralloc_cats(sa,"+2B")) temp_nomem(); 
+    } else if ((int) s[i] < 33 || (int) s[i] > 126) {
+        if (!stralloc_cats(sa,"+3F")) temp_nomem(); /* ok. not correct */
+    } else if (!stralloc_catb(sa,s+i,1)) {
+        temp_nomem();
+    }
+  }
+
+  return sa->len;
+}
+
+void mailfrom_xtext()
+{
+  if (!xtext(&xuser,user.s,user.len)) temp_nomem();
+  substdio_puts(&smtpto,"MAIL FROM:<");
+  substdio_put(&smtpto,sender.s,sender.len);
+  substdio_puts(&smtpto,"> AUTH=");
+  substdio_put(&smtpto,xuser.s,xuser.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+}
+
+int mailfrom_plain()
+{
+  substdio_puts(&smtpto,"AUTH PLAIN\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH PLAIN)."); return -1; }
+
+  if (!stralloc_cat(&plain,&user)) temp_nomem(); /* <authorization-id> */
+  if (!stralloc_0(&plain)) temp_nomem();
+  if (!stralloc_cat(&plain,&user)) temp_nomem(); /* <authentication-id> */
+  if (!stralloc_0(&plain)) temp_nomem();
+  if (!stralloc_cat(&plain,&pass)) temp_nomem(); /* password */
+  if (b64encode(&plain,&auth)) quit("ZConnected to "," but unable to base64encode (plain).");
+  substdio_put(&smtpto,auth.s,auth.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() == 235) { mailfrom_xtext(); return 0; }
+  else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; }
+  else { quit("ZConnected to "," but authentication was rejected (plain)."); return 1; }
+  
+  return 0;
+}
+
+int mailfrom_login()
+{
+  substdio_puts(&smtpto,"AUTH LOGIN\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH LOGIN)."); return -1; }
+
+  if (!stralloc_copys(&auth,"")) temp_nomem();
+  if (b64encode(&user,&auth)) quit("ZConnected to "," but unable to base64encode user.");
+  substdio_put(&smtpto,auth.s,auth.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (username).");
+
+  if (!stralloc_copys(&auth,"")) temp_nomem();
+  if (b64encode(&pass,&auth)) quit("ZConnected to "," but unable to base64encode pass.");
+  substdio_put(&smtpto,auth.s,auth.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() == 235) { mailfrom_xtext(); return 0; }
+  else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; }
+  else { quit("ZConnected to "," but authentication was rejected (password)."); return 1; }
+}
+
+int mailfrom_cram()
+{
+  int j;
+  unsigned char h;
+  unsigned char digest[16];
+  unsigned char digascii[33];
+  static char hextab[]="0123456789abcdef";
+
+  substdio_puts(&smtpto,"AUTH CRAM-MD5\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH CRAM-MD5)."); return -1; }
+
+  if (str_chr(smtptext.s+4,' ')) { 			/* Challenge */
+    if(!stralloc_copys(&slop,"")) temp_nomem();
+    if (!stralloc_copyb(&slop,smtptext.s+4,smtptext.len-5)) temp_nomem();
+    if (b64decode(slop.s,slop.len,&chal)) quit("ZConnected to "," but unable to base64decode challenge.");
+  }
+   
+  hmac_md5(chal.s,chal.len,pass.s,pass.len,digest);
+
+  for (j = 0;j < 16;j++)				/* HEX => ASCII */
+  {
+    digascii[2*j] = hextab[digest[j] >> 4];  
+    digascii[2*j+1] = hextab[digest[j] & 0xf]; 
+  }
+  digascii[32]=0;
+
+  slop.len = 0;
+  if (!stralloc_copys(&slop,"")) temp_nomem();
+  if (!stralloc_cat(&slop,&user)) temp_nomem();		 /* user-id */
+  if (!stralloc_cats(&slop," ")) temp_nomem();
+  if (!stralloc_catb(&slop,digascii,32)) temp_nomem();   /* digest */ 
+
+  if (!stralloc_copys(&auth,"")) temp_nomem();
+  if (b64encode(&slop,&auth)) quit("ZConnected to "," but unable to base64encode username+digest.");
+  substdio_put(&smtpto,auth.s,auth.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() == 235) { mailfrom_xtext(); return 0; }
+  else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; }
+  else { quit("ZConnected to "," but authentication was rejected (username+digest)."); return 1; } 
+}
+
+void smtp_auth()
+{
+  int i, j; 
+
+  for (i = 0; i + 8 < smtptext.len; i += str_chr(smtptext.s+i,'\n')+1)
+    if (!str_diffn(smtptext.s+i+4,"AUTH",4)) {  
+      if (j = str_chr(smtptext.s+i+8,'C') > 0)
+        if (case_starts(smtptext.s+i+8+j,"CRAM"))
+          if (mailfrom_cram() >= 0) return;
+
+      if (j = str_chr(smtptext.s+i+8,'P') > 0)
+        if (case_starts(smtptext.s+i+8+j,"PLAIN")) 
+          if (mailfrom_plain() >= 0) return;
+
+      if (j = str_chr(smtptext.s+i+8,'L') > 0)
+        if (case_starts(smtptext.s+i+8+j,"LOGIN")) 
+          if (mailfrom_login() >= 0) return;
+
+      err_authprot();
+      mailfrom();
+    }
+}
+
 void smtp()
 {
   unsigned long code;
@@ -586,11 +759,12 @@
 #ifdef EHLO
   }
 #endif
- 
-  substdio_puts(&smtpto,"MAIL FROM:<");
-  substdio_put(&smtpto,sender.s,sender.len);
-  substdio_puts(&smtpto,">\r\n");
-  substdio_flush(&smtpto);
+
+  if (authsender)
+    smtp_auth();
+  else 
+    mailfrom();
+
   code = smtpcode();
   if (code >= 500) quit("DConnected to "," but sender was rejected");
   if (code >= 400) quit("ZConnected to "," but sender was rejected");
@@ -681,6 +855,15 @@
     case 1:
       if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
   }
+  
+  switch(control_readfile(&authsenders,"control/authsenders",0)) {
+    case -1:
+       temp_control();
+    case 0:
+      if (!constmap_init(&mapauthsenders,"",0,1)) temp_nomem(); break;
+    case 1:
+      if (!constmap_init(&mapauthsenders,authsenders.s,authsenders.len,1)) temp_nomem(); break;
+  }
   if (control_readint(&flagv6,"control/useipv6") == -1) {
     flagv6 = 0;
   }
@@ -691,7 +864,7 @@
 char **argv;
 {
   static ipalloc ip = {0};
-  int i;
+  int i, j;
   unsigned long random;
   char **recips;
   unsigned long prefme;
@@ -707,27 +890,61 @@
   dns_init(0, flagv6);
  
   if (!stralloc_copys(&host,argv[1])) temp_nomem();
- 
+
+  authsender = 0;
   relayhost = 0;
-  for (i = 0;i <= host.len;++i)
-    if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
-      if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
+
+  addrmangle(&sender,argv[2],&flagalias,0);
+
+  for (i = 0;i <= sender.len;++i)
+    if ((i == 0) || (i == sender.len) || (sender.s[i] == '.') || (sender.s[i] == '@'))
+      if (authsender = constmap(&mapauthsenders,sender.s + i,sender.len - i))
         break;
-  if (relayhost && !*relayhost) relayhost = 0;
- 
-  if (relayhost) {
-    int r_bracket = str_rchr(relayhost,']');
-    i = str_chr(relayhost,':');
-    if (relayhost[i] && (i > r_bracket || !relayhost[r_bracket])) {
-      scan_ulong(relayhost + i + 1,&port);
-      relayhost[i] = 0;
+
+  if (authsender && !*authsender) authsender = 0;
+
+  if (authsender) {
+    i = str_chr(authsender,'|');
+    if (authsender[i]) {
+      j = str_chr(authsender + i + 1,'|');
+      if (authsender[j]) {
+        authsender[i] = 0;
+        authsender[i + j + 1] = 0;
+        if (!stralloc_copys(&user,"")) temp_nomem();
+        if (!stralloc_copys(&user,authsender + i + 1)) temp_nomem();
+        if (!stralloc_copys(&pass,"")) temp_nomem();
+        if (!stralloc_copys(&pass,authsender + i + j + 2)) temp_nomem();
+      }
+    }
+    i = str_chr(authsender,':');
+    if (authsender[i]) {
+      scan_ulong(authsender + i + 1,&port);
+      authsender[i] = 0;
+    }
+
+    if (!stralloc_copys(&relayhost,authsender)) temp_nomem();
+    if (!stralloc_copys(&host,authsender)) temp_nomem();
+
+  }
+  else {					/* default smtproutes */
+    for (i = 0;i <= host.len;++i)
+      if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
+        if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
+          break;
+    if (relayhost && !*relayhost) relayhost = 0;
+
+    if (relayhost) {
+      int r_bracket = str_rchr(relayhost,']');
+      i = str_chr(relayhost,':');
+      if (relayhost[i] && (i > r_bracket || !relayhost[r_bracket])) {
+        scan_ulong(relayhost + i + 1,&port);
+        relayhost[i] = 0;
+      }
+      if (!stralloc_copys(&host,relayhost)) temp_nomem();
     }
-    if (!stralloc_copys(&host,relayhost)) temp_nomem();
   }
 
 
-  addrmangle(&sender,argv[2],&flagalias,0);
- 
   if (!saa_readyplus(&reciplist,0)) temp_nomem();
   if (ipme_init() != 1) temp_oserr();
  
diff -rNU3 netqmail-1.06/qmail-showctl.c netqmail-1.06.075/qmail-showctl.c
--- netqmail-1.06/qmail-showctl.c	1998-06-15 12:53:16.000000000 +0200
+++ netqmail-1.06.075/qmail-showctl.c	2012-11-30 14:33:58.000000000 +0100
@@ -214,6 +214,7 @@
     _exit(111);
   }
 
+  do_lst("authsenders","No authenticated SMTP sender.","Authenicated SMTP sender: ","");
   do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
   do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is ");
   do_str("bouncehost",1,"bouncehost","Bounce host name is ");
@@ -265,8 +266,7 @@
   while (d = readdir(dir)) {
     if (str_equal(d->d_name,".")) continue;
     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,"authsenders")) continue;
     if (str_equal(d->d_name,"badmailfrom")) continue;
     if (str_equal(d->d_name,"bouncefrom")) continue;
     if (str_equal(d->d_name,"bouncehost")) continue;
diff -rNU3 netqmail-1.06/qmail-smtpd.8 netqmail-1.06.075/qmail-smtpd.8
--- netqmail-1.06/qmail-smtpd.8	2012-11-30 14:28:47.000000000 +0100
+++ netqmail-1.06.075/qmail-smtpd.8	2012-11-30 14:45:06.000000000 +0100
@@ -32,7 +32,38 @@
 header fields.
 
 .B qmail-smtpd
-supports ESMTP, including the 8BITMIME and PIPELINING options.
+supports ESMTP, including the 8BITMIME, DATA, PIPELINING, SIZE, and AUTH options.
+.B qmail-smtpd
+includes a \'MAIL FROM:\' parameter parser and obeys \'Auth\' and \'Size\' advertisements.
+.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 CRAM-MD5 digest/response derived from the SMTP client,
+another 0 byte, a CRAM-MD5 challenge (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 .
+
+Binding
+.B qmail-smtpd
+to the SUBMISSION port (\'587\') instead of the standard SMTP port 25 will advice
+.B qmail-smtpd 
+to require SMTP authention prior of accepting the \'MAIL FROM:\' command.
+A different port can be chosen, populating the environment variable 
+.IR SUBMISSIONPORT .
+
 .SH TRANSPARENCY
 .B qmail-smtpd
 converts the SMTP newline convention into the UNIX newline convention
@@ -234,6 +265,64 @@
 .B TLSCIPHERS
 is set to such a string, it takes precedence.
 
+.SH "ENVIRONMENT VARIABLES READ"
+Environment variables may be defined globally in the
+.B qmail-smtpd
+startup script and/or individually as part of the
+.B tcpserver's
+cdb database.
+The environment variables may be quoted ("variable", or 'variable') and
+in case of global use, have to be exported.
+.B qmail-smtpd
+supports the following legacy environment variables, typically
+provided by
+.B tcpserver
+or
+.B sslserver
+or
+.BR tcp-env :
+.IR TCPREMOTEIP ,
+.IR TCPREMOTEHOST
+.IR TCPREMOTEINFO
+and
+.IR TCPLOCALPORT
+as well as
+.IR RELAYCLIENT .
+
+.B qmail-smtpd
+may use the following environment variables for SMTP authentication:
+.TP 5
+.IR SMTPAUTH
+is used to enable SMTP Authentication for the AUTH types
+LOGIN and PLAIN.
+In case
+.TP 5
+.IR SMTPAUTH='+cram'
+is defined,
+.B qmail-smtpd
+honors LOGIN, PLAIN, and additionally CRAM-MD5 authentication.
+Simply 
+.TP 5
+.IR SMTPAUTH='cram'
+restricts authentication just to CRAM-MD5.
+If however
+.TP 5
+.IR SMTPAUTH='!'
+starts with an exclamation mark, AUTH is required. In particular,
+.TP 5
+.IR SMTPAUTH='!cram'
+may be useful.
+In opposite, if
+.TP 5
+.IR SMTPAUTH='-'
+starts with a dash, AUTH is disabled for particular
+connections.
+.TP 5
+.IR SUBMISSIONPORT=587
+customizable SMTP submission port setting.
+
+Note: The use of 'cram' requires a CRAM-MD5 enabled PAM.
+
 .SH "SEE ALSO"
 tcp-env(1),
 tcp-environ(5),
diff -rNU3 netqmail-1.06/qmail-smtpd.c netqmail-1.06.075/qmail-smtpd.c
--- netqmail-1.06/qmail-smtpd.c	2012-11-30 14:28:47.000000000 +0100
+++ netqmail-1.06.075/qmail-smtpd.c	2012-11-30 15:04:27.000000000 +0100
@@ -24,6 +24,10 @@
 #include "timeoutwrite.h"
 #include "commands.h"
 #include "qmail-spp.h"
+#include "wait.h"
+
+#define AUTHSLEEP 5
+#define SUBMISSION "587"
 
 int spp_val;
 
@@ -31,8 +35,6 @@
 unsigned int databytes = 0;
 int timeout = 1200;
 
-static const char *protocol = "SMTP";
-
 #ifdef TLS
 #include <sys/stat.h>
 #include "tls.h"
@@ -69,6 +71,7 @@
 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_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); }
 void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
 #ifndef TLS
 void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
@@ -88,6 +91,17 @@
 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 canceled (#5.0.0)\r\n"); return -1; }
+int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
+void err_authfail() { out("535 authentication failed (#5.7.1)\r\n"); }
+void err_submission() { out("530 Authorization required (#5.7.1) \r\n"); }
 
 stralloc greeting = {0};
 
@@ -105,11 +119,15 @@
   smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
 }
 
+char *protocol;
 char *remoteip;
 char *remotehost;
 char *remoteinfo;
 char *local;
+char *localport;
+char *submission;
 char *relayclient;
+char *auth;
 
 stralloc helohost = {0};
 char *fakehelo; /* pointer into helohost, or 0 */
@@ -120,6 +138,7 @@
   fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
 }
 
+int smtpauth = 0;
 int liphostok = 0;
 stralloc liphost = {0};
 int bmfok = 0;
@@ -152,15 +171,30 @@
   if (x) { scan_ulong(x,&u); databytes = u; }
   if (!(databytes + 1)) --databytes;
  
+  protocol = "SMTP";
   remoteip = env_get("TCPREMOTEIP");
   if (!remoteip) remoteip = "unknown";
   local = env_get("TCPLOCALHOST");
   if (!local) local = env_get("TCPLOCALIP");
   if (!local) local = "unknown";
+  localport = env_get("TCPLOCALPORT");
+  if (!localport) localport = "0";
   remotehost = env_get("TCPREMOTEHOST");
   if (!remotehost) remotehost = "unknown";
   remoteinfo = env_get("TCPREMOTEINFO");
   relayclient = env_get("RELAYCLIENT");
+  submission = env_get("SUBMISSIONPORT");
+  if (!submission) submission = SUBMISSION;
+  auth = env_get("SMTPAUTH");
+  if (auth) {
+    smtpauth = 1;
+    case_lowers(auth);
+    if (!case_diffs(auth,"-")) smtpauth = 0;
+    if (!case_diffs(auth,"!")) smtpauth = 11;
+    if (case_starts(auth,"cram")) smtpauth = 2;
+    if (case_starts(auth,"+cram")) smtpauth = 3;
+    if (case_starts(auth,"!cram")) smtpauth = 12;
+  }
 
 #ifdef TLS
   if (env_get("SMTPS")) { smtps = 1; tls_init(); }
@@ -251,12 +285,73 @@
   return r;
 }
 
-
+char *auth;
+int seenauth = 0;
 int seenmail = 0;
 int flagbarf; /* defined if seenmail */
+int flagsize;
 static int allowed;
 stralloc mailfrom = {0};
 stralloc rcptto = {0};
+stralloc fuser = {0};
+stralloc mfparms = {0};
+
+int mailfrom_size(arg) char *arg;
+{
+  long r;
+  unsigned long sizebytes = 0;
+
+  scan_ulong(arg,&r);
+  sizebytes = r;
+  if (databytes) if (sizebytes > databytes) return 1;
+  return 0;
+}
+
+void mailfrom_auth(arg,len) 
+char *arg; 
+int len;
+{
+  if (!stralloc_copys(&fuser,"")) die_nomem();
+  if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); }
+  else 
+    while (len) {
+      if (*arg == '+') {
+        if (case_starts(arg,"+3D")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"=")) die_nomem(); }
+        if (case_starts(arg,"+2B")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"+")) die_nomem(); }
+      }
+      else
+        if (!stralloc_catb(&fuser,arg,1)) die_nomem();
+      arg++; len--;
+    }
+  if(!stralloc_0(&fuser)) die_nomem();
+  if (!remoteinfo) {
+    remoteinfo = fuser.s;
+    if (!env_unset("TCPREMOTEINFO")) die_read();
+    if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
+  }
+}
+
+void mailfrom_parms(arg) char *arg;
+{
+  int i;
+  int len;
+
+    len = str_len(arg);
+    if (!stralloc_copys(&mfparms,"")) die_nomem;
+    i = byte_chr(arg,len,'>');
+    if (i > 4 && i < len) {
+      while (len) {
+        arg++; len--; 
+        if (*arg == ' ' || *arg == '\0' ) {
+           if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; }
+           if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5);  
+           if (!stralloc_copys(&mfparms,"")) die_nomem;
+        }
+        else
+          if (!stralloc_catb(&mfparms,arg,1)) die_nomem; 
+      }
+    }
+}
 
 void smtp_helo(arg) char *arg;
 {
@@ -267,6 +362,7 @@
 /* ESMTP extensions are published here */
 void smtp_ehlo(arg) char *arg;
 {
+  char size[FMT_ULONG];
   if(!spp_helo(arg)) return;
 #ifdef TLS
   struct stat st;
@@ -276,20 +372,37 @@
   if (!ssl && (stat("control/servercert.pem",&st) == 0))
     out("\r\n250-STARTTLS");
 #endif
-  out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+  size[fmt_ulong(size,(unsigned int) databytes)] = 0;
+  out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n");
+#ifdef TLS
+ if (ssl) {
+#endif
+  if (smtpauth == 1 || smtpauth == 11) out("250-AUTH LOGIN PLAIN\r\n");
+  if (smtpauth == 3) out("250-AUTH LOGIN PLAIN CRAM-MD5\r\n");
+  if (smtpauth == 2 || smtpauth == 12) out("250-AUTH CRAM-MD5\r\n");
+#ifdef TLS
+ }
+#endif
+  out("250 SIZE "); out(size); out("\r\n");
   seenmail = 0; dohelo(arg);
 }
 void smtp_rset(arg) char *arg;
 {
   spp_rset();
-  seenmail = 0;
+  seenmail = 0; seenauth = 0; 
+  mailfrom.len = 0; rcptto.len = 0;
   out("250 flushed\r\n");
 }
 void smtp_mail(arg) char *arg;
 {
+  if (!case_diffs(localport,submission) || smtpauth > 10) 
+    if (!seenauth) { err_submission(); return; }
   if (!addrparse(arg)) { err_syntax(); return; }
   if (!(spp_val = spp_mail())) return;
   if (spp_val == 1)
+  flagsize = 0;
+  mailfrom_parms(arg);
+  if (flagsize) { err_size(); return; }
   flagbarf = bmfcheck();
   seenmail = 1;
   if (!stralloc_copys(&rcptto,"")) die_nomem();
@@ -454,12 +567,225 @@
   qqx = qmail_close(&qqt);
   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 (databytes) if (!bytestooverflow) { err_size(); return; }
   if (*qqx == 'D') out("554 "); else out("451 ");
   out(qqx + 1);
   out("\r\n");
 }
 
+/* this file is too long ----------------------------------------- SMTP AUTH */
+
+char unique[FMT_ULONG + FMT_ULONG + 3];
+static stralloc authin = {0};   /* input from SMTP client */
+static stralloc user = {0};     /* authorization user-id */
+static stralloc pass = {0};     /* plain passwd or digest */
+static stralloc resp = {0};     /* b64 response */
+static stralloc chal = {0};     /* plain challenge */
+static stralloc slop = {0};     /* b64 challenge */
+
+char **childargs;
+char ssauthbuf[512];
+substdio ssauth = SUBSTDIO_FDBUF(safewrite,3,ssauthbuf,sizeof(ssauthbuf));
+
+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(&chal)) die_nomem();
+
+  if (pipe(pi) == -1) return err_pipe();
+  switch(child = fork()) {
+    case -1:
+      return err_fork();
+    case 0:
+      close(pi[1]);
+      if(fd_copy(3,pi[0]) == -1) return err_pipe();
+      sig_pipedefault();
+        execvp(*childargs, childargs);
+      _exit(1);
+  }
+  close(pi[0]);
+
+  substdio_fdbuf(&ssauth,write,pi[1],ssauthbuf,sizeof ssauthbuf);
+  if (substdio_put(&ssauth,user.s,user.len) == -1) return err_write();
+  if (substdio_put(&ssauth,pass.s,pass.len) == -1) return err_write();
+  if (smtpauth == 2 || smtpauth == 3 || smtpauth == 12)  
+    if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write();
+  if (substdio_flush(&ssauth) == -1) return err_write();
+
+  close(pi[1]);
+  if (!stralloc_copys(&chal,"")) die_nomem();
+  if (!stralloc_copys(&slop,"")) die_nomem();
+  byte_zero(ssauthbuf,sizeof ssauthbuf);
+  if (wait_pid(&wstat,child) == -1) return err_child();
+  if (wait_crashed(wstat)) return err_child();
+  if (wait_exitcode(wstat)) { sleep(AUTHSLEEP); 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),&resp) == 1) return err_input();
+  }
+  else {
+    out("334 \r\n"); flush();
+    if (authgetl() < 0) return -1;
+    if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
+  }
+  if (r == -1 || !stralloc_0(&resp)) die_nomem();
+  while (resp.s[id]) id++;                       /* "authorize-id\0userid\0passwd\0" */
+
+  if (resp.len > id + 1)
+    if (!stralloc_copys(&user,resp.s + id + 1)) die_nomem();
+  if (resp.len > id + user.len + 2)
+    if (!stralloc_copys(&pass,resp.s + id + user.len + 2)) die_nomem();
+
+  if (!user.len || !pass.len) return err_input();
+  return authenticate();
+}
+
+int auth_cram()
+{
+  int i, r;
+  char *s;
+
+  s = unique;                                           /* generate challenge */
+  s += fmt_uint(s,getpid());
+  *s++ = '.';
+  s += fmt_ulong(s,(unsigned long) now());
+  *s++ = '@';
+  *s++ = 0;
+  if (!stralloc_copys(&chal,"<")) die_nomem();
+  if (!stralloc_cats(&chal,unique)) die_nomem();
+  if (!stralloc_cats(&chal,local)) die_nomem();
+  if (!stralloc_cats(&chal,">")) die_nomem();
+  if (b64encode(&chal,&slop) < 0) die_nomem();
+  if (!stralloc_0(&slop)) die_nomem();
+
+  out("334 ");                                          /* "334 base64_challenge \r\n" */
+  out(slop.s);
+  out("\r\n");
+  flush();
+
+  if (authgetl() < 0) return -1;                        /* got response */
+  if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
+  if (r == -1 || !stralloc_0(&resp)) die_nomem();
+
+  i = str_rchr(resp.s,' ');
+  s = resp.s + i;
+  while (*s == ' ') ++s;
+  resp.s[i] = 0;
+  if (!stralloc_copys(&user,resp.s)) die_nomem();       /* userid */
+  if (!stralloc_copys(&pass,s)) die_nomem();            /* digest */
+
+  if (!user.len || !pass.len) return err_input();
+  return authenticate();
+}
+
+struct authcmd {
+  char *text;
+  int (*fun)();
+} authcmds[] = {
+  { "login",auth_login }
+, { "plain",auth_plain }
+, { "cram-md5",auth_cram }
+, { 0,err_noauth }
+};
+
+void smtp_auth(arg)
+char *arg;
+{
+  int i;
+  char *cmd = arg;
+
+  if (!ssl) { err_unimpl(); return; }
+
+  if (!*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; }
+  if (seenauth) { 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();
+  if (!stralloc_copys(&chal,"")) 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:
+      seenauth = 1;
+      protocol = "ESMTPA";
+      relayclient = "";
+      remoteinfo = user.s;
+      if (!env_unset("TCPREMOTEINFO")) die_read();
+      if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
+      if (!env_put2("RELAYCLIENT",relayclient)) die_nomem();
+      out("235 ok, go ahead (#2.0.0)\r\n");
+      break;
+    case 1:
+      err_authfail(user.s,authcmds[i].text);
+  }
+}
+
+
+/* this file is too long --------------------------------------------- GO ON */
+
 #ifdef TLS
 stralloc proto = {0};
 int ssl_verified = 0;
@@ -699,6 +1025,7 @@
   { "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 }
@@ -712,8 +1039,11 @@
 , { 0, err_unimpl, flush }
 } ;
 
-void main()
+void main(argc,argv)
+int argc;
+char **argv;
 {
+  childargs = argv + 1;
   sig_pipeignore();
   if (chdir(auto_qmail) == -1) die_control();
   setup();
diff -rNU3 netqmail-1.06/README.auth netqmail-1.06.075/README.auth
--- netqmail-1.06/README.auth	1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06.075/README.auth	2012-11-30 14:25:04.000000000 +0100
@@ -0,0 +1,139 @@
+README qmail SMTP Authentication
+================================
+
+Scope:
+------
+
+This patch supports RFC 2554 "SMTP Service Extension for Authentication" and 
+RFC 4409 "Message Submission for Mail" for 
+
+* qmail-smtpd and
+* qmail-remote
+
+and supports commonly the AUTH methods
+
+- CRAM-MD5
+- LOGIN (unsecure)
+- PLAIN (unsecure)
+
+Additionally, RFC 1870 is honoured ("SMTP Service Extension for Message Size Declaration").
+For more technical details see: http://www.fehcom.de/qmail/docu/smtpauth.html.
+
+
+Installation:
+-------------
+
+* Untar the source in the qmail-1.03 home direcotry.
+* Run ./install_auth.
+* Re-make qmail.
+
+
+Setup for qmail-smtpd:
+----------------------
+
+1. Prereqs:
+
+In order to use SMTP Authentication you have to use a 'Pluggable Authentication Module'
+PAM to be called by qmail-smtpd; typically
+
+	/var/qmail/bin/qmail-smtpd /bin/checkpassword true 2>&1
+
+Since qmail-smtpd does not run as root, checkpassword has to be made sticky.
+There is no need to include additionally the hostname in the call.
+In order to compute the CRAM-MD5 challenge, qmail-smtpd uses the 'tcplocalhost' information.
+
+2. Invocation:
+
+In order activate SMTP authentication, you need to provide the environment
+variable 'SMTPAUTH' to qmail-smtpd.
+
+Possible choices:
+	
+	a) SMTPAUTH=""; 	qmail-smtpd supports auth of type PLAIN and/or LOGIN.
+	b) SMTPAUTH="+cram";	qmail-smtpd will additionally annonce CRAM-MD5,
+				this requires a CRAM-MD5 supporting PAM.
+	c) SMTPAUTH="cram";	qmail-smtpd will only annonce CRAM-MD5.
+	d) SMTPAUTH="!";	this instructs qmail-smtpd to require (any type) authentication for this connection.
+	e) SMTPAUTH="!cram";	same as d) but now CRAM-MD5 is the only method instead.
+
+3. Submission:
+
+You can setup a special qmail-smtpd instance on the SUBMISSION port 587. 
+If qmail-smtpd receives SMTP connections on this port, it requires SMTP Authentication.
+
+Alternatively, you can employ the environment variable 
+
+	e) SUBMISSIONPORT=123;	 while setting it to some specific (port) value.
+
+
+Setup for qmail-remote:
+-----------------------
+
+SMTP Authentication with qmail-remote is activated by means of the 
+control file 'authsenders' which works similar to 'control/smtproutes'
+but with additional authentication information (username + password):
+
+    @example.com:relay.example.com|user|passwd
+    info@example.com:relay.example.com:26|infouser|infopasswd
+    :mailrelay.example.com:587|e=mc2|testpass
+
+Note: The choice of the AUTH method depends on the capabilities of the server.
+
+
+Historical Notes:
+-----------------
+
+SMTP authentication for qmail-smtpd was initially provided by Krysztof Dabrowski (version 0.31):
+
+
+Changes wrt. Krysztof Dabrowski's patch:
+
+* Avoid the 'hostname' in the call of the PAM.
+* Confirm to Dan Bernstein's checkpassword interface even for CRAM-MD5.
+* Doesn't close FD 2; thus not inhibiting logging to STDERR.
+* Fixed bugs in base64.c.
+* Modified unconditional close of FD 3 in order to sustain reading of 'control/morecpthosts.cdb'.
+* Evaluation of the (informational) Mail From: < > Auth=username.
+* Additional support for the advertised "Size" via 'Mail From: <return-path> SIZE=123456780' (RFC 1870).
+* RFC 3848 conformance for Received header in case of SMTP Auth (keyword ESMTPA).
+* Added SUBMISSION port feature.
+* Added SMTPAUTH environment variable.
+
+
+SMTP authentication for qmail-remote is taken from Bjoern Kalkbrenner.
+
+Changes wrt. Bjoern Kalkbrenner's patch (version 0.0.1 / 20020715):
+
+* Uniform, modular support for LOGIN and PLAIN.
+* Added 'Mail From: < > Auth=username' information in provisionally XTEXT format.
+* Added CRAM-MD5 support.
+
+
+Release Notes:
+--------------
+
+Version:	Notes:					Date:
+-------------------------------------------------------------------
+0.5.9		qmail-smtpd AUTH (only)			25.3.2008
+0.6.9		qmail-authentication			1.2.2010
+0.7.0		Based on qmail-authentication 0.69
+		including now CRAM-MD5 support
+		for qmail-remote			31.7.2010
+0.7.1		cosmetics for qmail-remote		5.8.2010
+0.7.2		authorization-id = authentication-id
+		for qmail-remote;
+		added SMTPAUTH environment variable 
+		for qmail-smtpd; backport from SC 2.7	29.4.2012
+0.7.3		Fixed missing AUTH for qmai-smtpd announcement.
+		Improved SUBMISSION port handling.	2.5.2012
+0.7.4		Fixed missing 250 statements for AUTH.
+		Changed SMTPAUTH settings for cram-md5 	18.5.2012
+0.7.5		Fixed bug in qmail-remote not respecting
+		announced AUTH types. Tx. Callum Gibson.
+		Added '432' server code evaluation for
+	 	AUTH password expired in qmail-remote. 	23.10.2012
+
+
+Erwin Hoffmann - Hoehn 2012-10-23 (www.fehcom.de)
+
+
diff -rNU3 netqmail-1.06/TARGETS netqmail-1.06.075/TARGETS
--- netqmail-1.06/TARGETS	2012-11-30 14:28:47.000000000 +0100
+++ netqmail-1.06.075/TARGETS	2012-11-30 14:34:42.000000000 +0100
@@ -10,6 +10,7 @@
 qmail.o
 quote.o
 now.o
+base64.o
 gfrom.o
 myctime.o
 slurpclose.o
openSUSE Build Service is sponsored by