Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:p_conrad
netqmail
netqmail-1.06-authentication075-pc.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor