diff -r 2ce477411646 -r 0a8afafb5d3e FILES.auth --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FILES.auth Wed Oct 29 17:27:18 2014 +0900 @@ -0,0 +1,17 @@ +The qmail-smtpd Auth patch modifies the following QMAIL 1.03 files: + += TARGETS += Makefile += qmail-smtpd.c += qmail-smtpd.8 + +Added files: + +& base64.c +& base64.h + +Informational files: + +% install_auth.sh (Installation shell script) +% README.auth +% README.auth.old (old description of SMTP Auth) diff -r 2ce477411646 -r 0a8afafb5d3e Makefile --- a/Makefile Wed Oct 29 11:34:37 2014 +0900 +++ b/Makefile Wed Oct 29 17:27:18 2014 +0900 @@ -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 \ @@ -1537,13 +1541,13 @@ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \ date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \ open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \ -fs.a auto_qmail.o socket.lib +fs.a auto_qmail.o 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 env.a stralloc.a \ - alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \ + alloc.a substdio.a error.a str.a fs.a auto_qmail.o base64.o `cat \ socket.lib` qmail-smtpd.0: \ @@ -1555,7 +1559,7 @@ substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \ error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \ substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \ -exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h +exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h base64.h ./compile qmail-smtpd.c qmail-start: \ @@ -2158,7 +2162,7 @@ cert cert-req: \ Makefile-cert - @$(MAKE) -sf $< $@ + @$(MAKE) -sf Makefile-cert $@ Makefile-cert: \ conf-qmail conf-users conf-groups Makefile-cert.mk diff -r 2ce477411646 -r 0a8afafb5d3e Makefile-cert.mk --- a/Makefile-cert.mk Wed Oct 29 11:34:37 2014 +0900 +++ b/Makefile-cert.mk Wed Oct 29 17:27:18 2014 +0900 @@ -3,7 +3,7 @@ @: QMAIL/control/clientcert.pem: QMAIL/control/servercert.pem - ln -s $< $@ + ln -s QMAIL/control/servercert.pem $@ QMAIL/control/servercert.pem: PATH=$$PATH:/usr/local/ssl/bin \ diff -r 2ce477411646 -r 0a8afafb5d3e README.auth --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.auth Wed Oct 29 17:27:18 2014 +0900 @@ -0,0 +1,58 @@ +README qmail-smtpd SMTP Authentication +====================================== + + +History: +-------- + +This patch is based on Krzysztof Dabrowski's qmail-smtpd-auth-0.31 patch +which itself uses "Mrs. Brisby's" initial code. +Version 0.41 of this patch fixes the "CAPS-LOCK" typo announcing +'CRAM_MD5' instead of 'CRAM-MD5' (german keyboard) - tx to Mike Garrison. +Version 0.42 fixes the '421 unable to read controls (#4.3.0)' problem +(can't read control/morercpthosts.cdb) because FD 3 was already closed - tx Richard Lyons. +Version 0.43 fixes the ba64decode() failure in case CRAM_MD5 is not enabled - tx Vladimir Zidar. + + +Scope: +------ + +This patch supports partly RFC 2554 "SMTP Service Extension for Authentication". +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. +* Modify the compile time option "#define CRAM_MD5" to your needs. +* Re-make qmail. + + +Setup: +------ + +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. + + +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'. + + +Erwin Hoffmann - Cologne 2004-04-03 (www.fehcom.de) + + diff -r 2ce477411646 -r 0a8afafb5d3e README.auth-ext --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.auth-ext Wed Oct 29 17:27:18 2014 +0900 @@ -0,0 +1,88 @@ +========================================================================= + README netqmail-1.06-smtpd SMTP-AUTH Extension + http://www.gentei.org/~yuuji/software/qmail-smtpd-auth-ext/ +========================================================================= + + +Description: +------------ + +This patch is modified version of patches of Erwin Hoffmann - Hoehn's +qmail-smtpd SMTP Authentication 0.51(2010-02-08). +This patch is modifed to be applied to the source of +netqmail-1.06 + netqmail-1.06-tls-20110119.patch(*). + +(*) http://inoa.net/qmail-tls/ - Qmail-TLS patch + + +Installation: +------------- + +# tar zxpf netqmail-1.06.tar.gz +# cd netqmail-1.06 +# cat /netqmail-1.06-tls-20110119.patch | patch -p2 +# cat /qmail-smtpd-auth-ext-5.diff | patch -p1 + +And then, follow the instructions in the file netqmail-1.06-tls-20110119.patch +and README.auth. + +Setup: +------ +You should read document of TLS patch and README.auth. +Here is a digest. + +* CERTS +# cd /var/qmail/control +# openssl req -new -x509 -nodes -out servercert.pem \ + -keyout servercert.pem -days 3650 +# openssl ciphers tlsclientchiphers +# openssl ciphers tlsserverchiphers + +* Invocation with daemontools +Here is a typical `run' script. +----------------------------------------------- +#!/bin/sh +exec env - \ +PATH=/var/qmail/bin:$PATH \ +AUTHTLS=1 \ +envuidgid qmaild softlimit -d3000000 \ +tcpserver -vR -p -c40 -U 0 submission qmail-smtpd cmd5apoppw /usr/bin/true 2>&1 +----------------------------------------------- + +The cmd5apoppw command is described in the section "cmd5*" below. +AUTHTLS=1 inhibit plain text transport of password, that is +client should activate TLS for auth-login. +If the administrator doesn't care about plain text communication, +omit AUTHTLS=1 line. Note that if the system uses cmd5apoppw, +password drain doesn't have DIRECT impact on system security +because mail password is independent from system password. Of course, +it brings privacy breakage and has indirect impact on system security, +in such case as that an user always exchange administrative information +in plain-text email. That is a matter of literacy but of internet +protocol. + + +cmd5*: +------ +You might want to use smtp-auth with qmail-smtpd. You also need to install +cmd5checkpw or cmd5apoppw(*2). + +(*2) http://www.gentei.org/~yuuji/software/qmapop-smtp-auth/ + +We recommend to use cmd5apoppw program, by which users can manipulate +mail password by themselves and can have separate password for each +extensional mail address. + +* User mail password manipulation in cmd5apoppw schema +All users' mail password should be stored into their own ~/.apop file. +The ~/.apop password file can be created by `apoppasswd' command. + % apoppasswd + (New password twice) +If an user want to use mail extension `user-ext', its password can +be set by as follows: + % apoppasswd -e ext +Password file for `user-ext' is ~/.apop-ext. + + +-- +HIROSE, Yuuji yuuji_at_yatex.org 2014-10-29 diff -r 2ce477411646 -r 0a8afafb5d3e TARGETS --- a/TARGETS Wed Oct 29 11:34:37 2014 +0900 +++ b/TARGETS Wed Oct 29 17:27:18 2014 +0900 @@ -10,6 +10,7 @@ qmail.o quote.o now.o +base64.o gfrom.o myctime.o slurpclose.o diff -r 2ce477411646 -r 0a8afafb5d3e base64.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base64.c Wed Oct 29 17:27:18 2014 +0900 @@ -0,0 +1,122 @@ +#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; + out->len = (n * 3) - p; + if (!stralloc_ready(out,out->len)) return -1; + 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; + } + + if (!stralloc_ready(out,in->len / 3 * 4 + 4)) return -1; + s = out->s; + + for (i = 0;i < in->len;i += 3) { + a = in->s[i]; + b = i + 1 < in->len ? in->s[i + 1] : 0; + c = i + 2 < in->len ? in->s[i + 2] : 0; + + *s++ = b64alpha[a >> 2]; + *s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)]; + + if (i + 1 >= in->len) *s++ = B64PAD; + else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)]; + + if (i + 2 >= in->len) *s++ = B64PAD; + else *s++ = b64alpha[c & 63]; + } + out->len = s - out->s; + return 0; +} diff -r 2ce477411646 -r 0a8afafb5d3e base64.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base64.h Wed Oct 29 17:27:18 2014 +0900 @@ -0,0 +1,7 @@ +#ifndef BASE64_H +#define BASE64_H + +extern int b64decode(); +extern int b64encode(); + +#endif diff -r 2ce477411646 -r 0a8afafb5d3e install_auth.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/install_auth.sh Wed Oct 29 17:27:18 2014 +0900 @@ -0,0 +1,97 @@ +#!/bin/sh +# +# qmail-smtpd AUTH (UN)INSTALL Script (install_auth.sh) +# ----------------------------------------------------- +# +# Purpose: To install and uninstall the qmail-smtpd Authentication Patch +# +# Parameters: -u (uninstall) +# VRF (Version to be uninstalled) +# +# Usage: ./install_auth.sh [-u] [Version] +# +# Installation: ./install_auth.sh +# Uninstallation: ./install_auth.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 +# +#--------------------------------------------------------------------------------------- +# +DATE=$(date) +LOCDIR=${PWD} +QMAILHOME=$(head -1 conf-qmail) +SOLARIS=$(sh ./find-systype.sh | grep -ciq "SunOS") +LOGFILE=auth.log +TARGETS=FILES.auth +IFSKEEP=${IFS} +REL=043 # Should be identical to qmail-smtpd AUTH level +BUILD=2004094213621 + + +if [ $# -eq 0 ] ; then + + echo "Installing qmail-smtpd 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 -v 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-smtpd AUTH $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-smtpd 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}.$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-smtpd AUTH $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1 +fi + +exit 0 diff -r 2ce477411646 -r 0a8afafb5d3e qmail-smtpd.8 --- a/qmail-smtpd.8 Wed Oct 29 11:34:37 2014 +0900 +++ b/qmail-smtpd.8 Wed Oct 29 17:27:18 2014 +0900 @@ -32,7 +32,29 @@ header fields. .B qmail-smtpd -supports ESMTP, including the 8BITMIME and PIPELINING options. +supports ESMTP, including the 8BITMIME, DATA, PIPELINING, and AUTH options. + +.B qmail-smtpd +can accept LOGIN, PLAIN, and CRAM-MD5 AUTH types. It invokes +.IR checkprogram , +which reads on file descriptor 3 the username, a 0 byte, the password +or 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 . + .SH TRANSPARENCY .B qmail-smtpd converts the SMTP newline convention into the UNIX newline convention diff -r 2ce477411646 -r 0a8afafb5d3e qmail-smtpd.c --- a/qmail-smtpd.c Wed Oct 29 11:34:37 2014 +0900 +++ b/qmail-smtpd.c Wed Oct 29 17:27:18 2014 +0900 @@ -23,6 +23,10 @@ #include "timeoutread.h" #include "timeoutwrite.h" #include "commands.h" +#include "wait.h" + +#define CRAM_MD5 +#define AUTHSLEEP 5 #define MAXHOPS 100 unsigned int databytes = 0; @@ -86,6 +90,16 @@ 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"); } stralloc greeting = {0}; @@ -273,7 +287,12 @@ if (!ssl && (stat("control/servercert.pem",&st) == 0)) out("\r\n250-STARTTLS"); #endif - out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); + out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n"); +#ifdef CRAM_MD5 + out("250 AUTH LOGIN PLAIN CRAM-MD5\r\n"); +#else + out("250 AUTH LOGIN PLAIN\r\n"); +#endif seenmail = 0; dohelo(arg); } void smtp_rset(arg) char *arg; @@ -680,10 +699,240 @@ #endif +/* 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}; /* plain userid */ +static stralloc pass = {0}; /* plain passwd or digest */ +static stralloc resp = {0}; /* b64 response */ +#ifdef CRAM_MD5 +static stralloc chal = {0}; /* plain challenge */ +static stralloc slop = {0}; /* b64 challenge */ +#endif + +int flagauth; + +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(); +#ifdef CRAM_MD5 + if (!stralloc_0(&chal)) die_nomem(); +#endif + + if (pipe(pi) == -1) return err_pipe(); + switch(child = fork()) { + case -1: + return err_fork(); + case 0: + close(pi[1]); + dup2(pi[0],3); + 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(); +#ifdef CRAM_MD5 + if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write(); +#endif + if (substdio_flush(&ssauth) == -1) return err_write(); + + close(pi[1]); +#ifdef CRAM_MD5 + byte_zero(chal.s,chal.len); + byte_zero(slop.s,slop.len); +#endif + 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(); +} + +#ifdef CRAM_MD5 +int auth_cram() +{ + int i, r; + char *s; + + s = unique; + s += fmt_uint(s,getpid()); + *s++ = '.'; + s += fmt_ulong(s,(unsigned long) now()); + *s++ = '@'; + *s++ = 0; + + if (!stralloc_copys(&chal,"<")) die_nomem(); /* generate challenge */ + 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 mychallenge \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_chr(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(); +} +#endif + +struct authcmd { + char *text; + int (*fun)(); +} authcmds[] = { + { "login",auth_login } +, { "plain",auth_plain } +#ifdef CRAM_MD5 +, { "cram-md5",auth_cram } +#endif +, { 0,err_noauth } +}; + +void smtp_auth(arg) +char *arg; +{ + int i; + char *cmd = arg; + + if (!*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; } + if (env_get("AUTHTLS") && !str_diff(protocol, "SMTP")) { + out("503 need TLS for AUTH (#5.5.1)\r\n"); + return; + } + if (flagauth) { 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(); +#ifdef CRAM_MD5 + if (!stralloc_copys(&chal,"")) die_nomem(); +#endif + + 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: + flagauth = 1; + 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 */ + struct commands smtpcommands[] = { { "rcpt", smtp_rcpt, 0 } , { "mail", smtp_mail, 0 } , { "data", smtp_data, flush } +, { "auth", smtp_auth, flush } , { "quit", smtp_quit, flush } , { "helo", smtp_helo, flush } , { "ehlo", smtp_ehlo, flush } @@ -697,8 +946,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();