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