diff options
author | Nick Hadaway <raker@gentoo.org> | 2002-09-11 21:22:25 +0000 |
---|---|---|
committer | Nick Hadaway <raker@gentoo.org> | 2002-09-11 21:22:25 +0000 |
commit | bc411a17e3ac765250f3a2cd365645f4ba35bae9 (patch) | |
tree | 4237b8da2e61ffd1ba44cc75fb3c1def01cc5f50 /net-mail/qmail | |
parent | added more USE flag dont's (diff) | |
download | gentoo-2-bc411a17e3ac765250f3a2cd365645f4ba35bae9.tar.gz gentoo-2-bc411a17e3ac765250f3a2cd365645f4ba35bae9.tar.bz2 gentoo-2-bc411a17e3ac765250f3a2cd365645f4ba35bae9.zip |
new qmail ebuild! :)
Diffstat (limited to 'net-mail/qmail')
-rw-r--r-- | net-mail/qmail/files/1.03-r8/qmail-1.03-starttls-smtp-auth.patch | 1408 |
1 files changed, 1408 insertions, 0 deletions
diff --git a/net-mail/qmail/files/1.03-r8/qmail-1.03-starttls-smtp-auth.patch b/net-mail/qmail/files/1.03-r8/qmail-1.03-starttls-smtp-auth.patch new file mode 100644 index 000000000000..683aac888516 --- /dev/null +++ b/net-mail/qmail/files/1.03-r8/qmail-1.03-starttls-smtp-auth.patch @@ -0,0 +1,1408 @@ + +A word of warning: the TLS part of this patch is not type-safe at +at least one point (hey, I didn't write it.) I don't think this +causes problems on i386 architectures, but it made qmail-smtpd +crash frequently on an Alpha. Commenting out the substdio_fdbuf(...); +call in qmail-smtpd appears to fix the issue. + +diff -urP qmail-1.03-vanilla/Makefile qmail-1.03-tls-auth/Makefile +--- qmail-1.03-vanilla/Makefile Mon Jun 15 05:53:16 1998 ++++ qmail-1.03-tls-auth/Makefile Wed Jun 19 16:09:58 2002 +@@ -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,7 +1450,8 @@ + 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 `cat dns.lib` `cat socket.lib` ++ str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` \ ++ -lssl -lcrypto + + qmail-remote.0: \ + qmail-remote.8 +@@ -1536,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 \ + 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 \ +- socket.lib` ++ alloc.a substdio.a error.a str.a fs.a auto_qmail.o base64.o `cat \ ++ socket.lib` -lssl -lcrypto + + qmail-smtpd.0: \ + qmail-smtpd.8 +@@ -1553,7 +1558,8 @@ + substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \ + error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \ + substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \ +-exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h ++exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h wait.h \ ++fd.h base64.h + ./compile qmail-smtpd.c + + qmail-start: \ +@@ -2139,3 +2145,23 @@ + wait_pid.o: \ + compile wait_pid.c error.h haswaitp.h + ./compile wait_pid.c ++ ++cert: ++ openssl req -new -x509 -nodes \ ++ -out /var/qmail/control/servercert.pem -days 366 \ ++ -keyout /var/qmail/control/servercert.pem ++ chmod 640 /var/qmail/control/servercert.pem ++ chown qmaild.qmail /var/qmail/control/servercert.pem ++ ln -s /var/qmail/control/servercert.pem /var/qmail/control/clientcert.pem ++ ++cert-req: ++ openssl req -new -nodes \ ++ -out req.pem \ ++ -keyout /var/qmail/control/servercert.pem ++ chmod 640 /var/qmail/control/servercert.pem ++ chown qmaild.qmail /var/qmail/control/servercert.pem ++ ln -s /var/qmail/control/servercert.pem /var/qmail/control/clientcert.pem ++ @echo ++ @echo "Send req.pem to your CA to obtain signed_req.pem, and do:" ++ @echo "cat signed_req.pem >> /var/qmail/control/servercert.pem" ++ +diff -urP qmail-1.03-vanilla/README.auth qmail-1.03-tls-auth/README.auth +--- qmail-1.03-vanilla/README.auth Wed Dec 31 18:00:00 1969 ++++ qmail-1.03-tls-auth/README.auth Wed Jun 19 15:31:37 2002 +@@ -0,0 +1,175 @@ ++*** Warning! Cuidado! Vorsicht! *** ++=================================== ++*** Version 0.30 of the patch changes the arguments which must be ++*** passed to qmail-smtpd. If you are upgrading from a previous ++*** version of the patch, take care to ensure your invocation of ++*** qmail-smtpd uses the correct arguments. Otherwise, your server ++*** may run as an open relay! ++=================================== ++*** Warning! Cuidado! Vorsicht! *** ++ ++ ++This patch adds ESMTP AUTH authentication protocol support to ++qmail-1.03. It's originally based on Mrs. Brisby's smtp-auth patch ++with many enhancements from Krzysztof Dabrowski <brush@elysium.pl>. ++ ++Beginning with version 0.30, the patch was completely rewritten to ++use only djb's string functions by Eric M. Johnston <emj@postal.net>. ++ ++You can always get the newest version from: ++http://members.elysium.pl/brush/qmail-smtpd-auth/ ++ ++To use all of it's functionality you will also have to obtain and ++install Krzysztof's cmd5checkpw utility available at: ++http://members.elysium.pl/brush/cmd5checkpw/ ++ ++If you need more information about SMTP-AUTH itself and the ++client/server support and configuration, visit: ++http://members.elysium.pl/brush/smtp-auth/ ++ ++--- ++ ++Detailed patch information: ++ ++This patch adds the ESMTP AUTH option to qmail-1.03, allowing the ++LOGIN, PLAIN, and CRAM-MD5 AUTH types. An appropriate checkpassword ++tool is necessary to support the authentication. See ++http://cr.yp.to/checkpwd.html for more information on the interface. ++Note that the checkpassword tool should support all of the AUTH types ++advertised by qmail-smtpd. ++ ++As reflected in the modified qmail-smtpd(8) man page, qmail-smtpd ++must be invoked with three arguments: hostname, checkprogram, and ++subprogram. If these arguments are missing, qmail-smtpd will still ++advertise availability of AUTH, but will fail with a permanent error ++when AUTH is used. ++ ++hostname is simply used to form the CRAM-MD5 challenge. qmail-smtpd ++invokes checkprogram, feeding it the username and password, in the ++case of LOGIN or PLAIN, or the username, challenge, and response, in ++the case of CRAM-MD5. If the user is permitted, checkprogram invokes ++subprogram, which just has to exit with a status of 0 for the user to ++be authenticated. Otherwise, checkprogram exits with a non-zero ++status. subprogram can usually be /usr/bin/true (or /bin/true, ++depending on your flavor of OS). ++ ++If the user is successfully authenticated, the RELAYCLIENT ++environment variable is effectively set for the SMTP session, and ++the TCPREMOTEINFO environment variable is set to the authenticated ++username, overriding any value that tcpserver may have set. The ++value of TCPREMOTEINFO is reflected in a Received header. ++ ++ ++How to install it: ++ ++Simply patch your qmail-1.03 distribution with the included patch ++file and recompile & install like usual. ++ ++The steps to do this are as follows (assuming your virgin ++qmail-1.03 install is in "../qmail-1.03"): ++ ++ cp README.auth base64.c base64.h ../qmail-1.03 ++ patch -d ../qmail-1.03 < auth.patch ++ ++Install qmail normally, with the exception of the new arguments ++to qmail-smtpd described elsewhere in this file. ++ ++Also obtain, unpack, compile and install the cmd5checkpw utility ++(or some other checkpassword utility) and add a sample account to ++/etc/poppasswd file. This file must be readable by the qmail-smtpd ++user, usually qmaild. ++ ++ ++How to use it: ++ ++*** Warning: In version 0.30 the arguments have changed from ++*** previous versions of qmail-smtpd-auth. Take care to make sure ++*** you update your startup scripts if updating! ++ ++If you're running qmail-smtpd from inetd, you'll want to do the ++following: ++ ++smtp stream tcp nowait qmaild /var/qmail/bin/tcp-env tcp-env \ ++/var/qmail/bin/qmail-smtpd mail.acme.com /bin/cmd5checkpw /bin/true ++ ++Replace mail.acme.com with your hostname. The second argument to ++qmail-smtpd is your checkpassword utility (preferably cmd5checkpw ++or some alternative that can handle CRAM-MD5). The third argument ++is the executable that the checkpassword utility execs when ++authentication is successful. (Note that the location of "true" ++is OS dependent: you may need /usr/bin/true.) ++ ++Invocations using tcpserver will require analagous changes. Give ++your inetd a kill -HUP or restart tcpserver and away you go. ++ ++ ++Caveats: ++ ++Please note that as authentication needs vary wildly across ++installations, no effort has been made to make this patch work ``out ++of the box.'' You'll have to procure or develop your own ++checkpassword program. Also note that CRAM-MD5 will require you to ++keep plaintext passwords. You'll probably want to disable this AUTH ++type if you're just using /etc/passwd (keeping in mind that PLAIN and ++LOGIN aren't quite as safe over the wire) -- just undefine AUTHCRAM ++in qmail-smtpd. ++ ++Krzysztof Dabrowski's cmd5checkpw tool used as an example in this ++document supports the three AUTH types included in this patch. ++It's available at http://www.elysium.pl/members/brush/cmd5checkpw/. ++ ++This patch has been generated against the stock qmail 1.03 ++distribution. The results of combining this patch with others are ++unknown. ++ ++ ++Features: ++ ++This patch supports the following auth methods: LOGIN, PLAIN and ++CRAM-MD5. ++ ++ ++Compatibility: ++ ++The following MUA's are confirmed to work with this patch: ++ ++Eudora 4.2.2 - CRAM-MD5 ++Eudora 5.0.2 - CRAM-MD5 ++The Bat 1.39 - LOGIN & CRAM-MD5 ++Outlook Express 4 - LOGIN ++Outlook Express 5 - LOGIN ++Outlook 2000 - LOGIN ++Netscape 4.x - LOGIN & PLAIN ++Netscape 4.0x - LOGIN ++Pegasus Mail 3.1x - CRAM-MD5 ++ ++ ++Various compatibility issues: ++ ++Testing with Pegasus Mail 3.1 revealed that it requires the new style ++(RFC recommended) greeting message. Both styles are now enabled to ++maintain the highest degree of compatibility with various clients. ++This fix was suggested by David Harris <David.Harris@pmail.gen.nz>, ++the developer of Pegasus Mail. ++ ++ ++Acknowledgments: ++ ++This patch is based on work by Krzysztof Dabrowski at ++http://members.elysium.pl/brush/qmail-smtpd-auth/ and ``Mrs. Brisby'' ++at http://www.nimh.org/hacks/qmail-smtpd.c which has been further ++developed by Eric M. Johnston <emj@postal.net>. ++ ++--- ++ ++THIS SOFTWARE IS IN THE PUBLIC DOMAIN, IS PROVIDED BY THE AUTHOR ++``AS IS,'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE ++OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, ++EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +diff -urP qmail-1.03-vanilla/TARGETS qmail-1.03-tls-auth/TARGETS +--- qmail-1.03-vanilla/TARGETS Mon Jun 15 05:53:16 1998 ++++ qmail-1.03-tls-auth/TARGETS Wed Jun 19 15:30:20 2002 +@@ -250,6 +250,7 @@ + qmail-qmtpd.o + rcpthosts.o + qmail-qmtpd ++base64.o + qmail-smtpd.o + qmail-smtpd + sendmail.o +diff -urP qmail-1.03-vanilla/base64.c qmail-1.03-tls-auth/base64.c +--- qmail-1.03-vanilla/base64.c Wed Dec 31 18:00:00 1969 ++++ qmail-1.03-tls-auth/base64.c Wed Jun 19 15:29:53 2002 +@@ -0,0 +1,90 @@ ++#include "base64.h" ++#include "stralloc.h" ++#include "substdio.h" ++#include "str.h" ++ ++static char *b64alpha = ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; ++#define B64PAD '=' ++ ++/* returns 0 ok, 1 illegal, -1 problem */ ++ ++int b64decode(in,l,out) ++const unsigned char *in; ++int l; ++stralloc *out; /* not null terminated */ ++{ ++ int i, j; ++ unsigned char a[4]; ++ unsigned char b[3]; ++ char *s; ++ ++ if (l == 0) ++ { ++ if (!stralloc_copys(out,"")) return -1; ++ return 0; ++ } ++ ++ if (!stralloc_ready(out,l + 2)) return -1; /* XXX generous */ ++ s = out->s; ++ ++ for (i = 0;i < l;i += 4) { ++ for (j = 0;j < 4;j++) ++ if ((i + j) < l && in[i + j] != B64PAD) ++ { ++ a[j] = str_chr(b64alpha,in[i + j]); ++ if (a[j] > 63) return 1; ++ } ++ else a[j] = 0; ++ ++ b[0] = (a[0] << 2) | (a[1] >> 4); ++ b[1] = (a[1] << 4) | (a[2] >> 2); ++ b[2] = (a[2] << 6) | (a[3]); ++ ++ *s++ = b[0]; ++ ++ if (in[i + 1] == B64PAD) break; ++ *s++ = b[1]; ++ ++ if (in[i + 2] == B64PAD) break; ++ *s++ = b[2]; ++ } ++ out->len = s - out->s; ++ while (out->len && !out->s[out->len - 1]) --out->len; /* XXX avoid? */ ++ return 0; ++} ++ ++int b64encode(in,out) ++stralloc *in; ++stralloc *out; /* not null terminated */ ++{ ++ unsigned char a, b, c; ++ int i; ++ char *s; ++ ++ if (in->len == 0) ++ { ++ if (!stralloc_copys(out,"")) return -1; ++ return 0; ++ } ++ ++ if (!stralloc_ready(out,in->len / 3 * 4 + 4)) return -1; ++ s = out->s; ++ ++ for (i = 0;i < in->len;i += 3) { ++ a = in->s[i]; ++ b = i + 1 < in->len ? in->s[i + 1] : 0; ++ c = i + 2 < in->len ? in->s[i + 2] : 0; ++ ++ *s++ = b64alpha[a >> 2]; ++ *s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)]; ++ ++ if (i + 1 >= in->len) *s++ = B64PAD; ++ else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)]; ++ ++ if (i + 2 >= in->len) *s++ = B64PAD; ++ else *s++ = b64alpha[c & 63]; ++ } ++ out->len = s - out->s; ++ return 0; ++} +diff -urP qmail-1.03-vanilla/base64.h qmail-1.03-tls-auth/base64.h +--- qmail-1.03-vanilla/base64.h Wed Dec 31 18:00:00 1969 ++++ qmail-1.03-tls-auth/base64.h Wed Jun 19 15:29:53 2002 +@@ -0,0 +1,7 @@ ++#ifndef BASE64_H ++#define BASE64_H ++ ++extern int b64decode(); ++extern int b64encode(); ++ ++#endif +diff -urP qmail-1.03-vanilla/conf-cc qmail-1.03-tls-auth/conf-cc +--- qmail-1.03-vanilla/conf-cc Mon Jun 15 05:53:16 1998 ++++ qmail-1.03-tls-auth/conf-cc Wed Jun 19 15:35:59 2002 +@@ -1,3 +1,3 @@ +-cc -O2 ++cc -O2 -DTLS -I/usr/local/ssl/include + + This will be used to compile .c files. +diff -urP qmail-1.03-vanilla/dns.c qmail-1.03-tls-auth/dns.c +--- qmail-1.03-vanilla/dns.c Mon Jun 15 05:53:16 1998 ++++ qmail-1.03-tls-auth/dns.c Wed Jun 19 15:36:06 2002 +@@ -270,6 +270,14 @@ + { + int r; + struct ip_mx ix; ++#ifdef TLS ++ stralloc fqdn = {0}; ++ ++ if (!stralloc_copy(&fqdn,sa)) return DNS_MEM; ++ if (!stralloc_0(&fqdn)) return DNS_MEM; ++ ix.fqdn = fqdn.s; ++ alloc_free(fqdn); ++#endif + + if (!stralloc_copy(&glue,sa)) return DNS_MEM; + if (!stralloc_0(&glue)) return DNS_MEM; +@@ -330,6 +338,9 @@ + ix.pref = 0; + if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) + { ++#ifdef TLS ++ ix.fqdn = NULL; ++#endif + if (!ipalloc_append(ia,&ix)) return DNS_MEM; + return 0; + } +diff -urP qmail-1.03-vanilla/ipalloc.h qmail-1.03-tls-auth/ipalloc.h +--- qmail-1.03-vanilla/ipalloc.h Mon Jun 15 05:53:16 1998 ++++ qmail-1.03-tls-auth/ipalloc.h Wed Jun 19 15:36:15 2002 +@@ -3,7 +3,12 @@ + + #include "ip.h" + ++#ifdef TLS ++#include "stralloc.h" ++struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ; ++#else + struct ip_mx { struct ip_address ip; int pref; } ; ++#endif + + #include "gen_alloc.h" + +diff -urP qmail-1.03-vanilla/qmail-remote.c qmail-1.03-tls-auth/qmail-remote.c +--- qmail-1.03-vanilla/qmail-remote.c Mon Jun 15 05:53:16 1998 ++++ qmail-1.03-tls-auth/qmail-remote.c Wed Jun 19 15:36:38 2002 +@@ -26,8 +26,18 @@ + #include "tcpto.h" + #include "readwrite.h" + #include "timeoutconn.h" ++#ifndef TLS + #include "timeoutread.h" + #include "timeoutwrite.h" ++#endif ++ ++#ifdef TLS ++#include <sys/stat.h> ++#include <openssl/ssl.h> ++SSL *ssl = NULL; ++ ++stralloc tlsclientciphers = {0}; ++#endif + + #define HUGESMTPTEXT 5000 + +@@ -107,17 +117,94 @@ + int smtpfd; + int timeout = 1200; + ++#ifdef TLS ++int flagtimedout = 0; ++void sigalrm() ++{ ++ flagtimedout = 1; ++} ++ ++int ssl_timeoutread(timeout,fd,buf,n) int timeout; int fd; char *buf; int n; ++{ ++ int r; int saveerrno; ++ if (flagtimedout) { errno = error_timeout; return -1; } ++ alarm(timeout); ++ if (ssl) { ++ while(((r = SSL_read(ssl,buf,n)) <= 0) ++ && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_READ)); ++ if (SSL_get_error(ssl, r) != SSL_ERROR_NONE) ++ {char buf[1024]; ++ ++ out("ZTLS connection to "); outhost(); out(" died: "); ++ SSL_load_error_strings(); ++ out(ERR_error_string(ERR_get_error(), buf)); out("\n"); ++ SSL_shutdown(ssl); ++ zerodie(); ++ } ++ }else r = read(fd,buf,n); ++ saveerrno = errno; ++ alarm(0); ++ if (flagtimedout) { errno = error_timeout; return -1; } ++ errno = saveerrno; ++ return r; ++} ++ ++int ssl_timeoutwrite(timeout,fd,buf,n) int timeout; int fd; char *buf; int n; ++{ ++ int r; int saveerrno; ++ if (flagtimedout) { errno = error_timeout; return -1; } ++ alarm(timeout); ++ if (ssl) { ++ while(((r = SSL_write(ssl,buf,n)) <= 0) ++ && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_WRITE)); ++ if (SSL_get_error(ssl, r) != SSL_ERROR_NONE) ++ {char buf[1024]; ++ ++ out("ZTLS connection to "); outhost(); out(" died: "); ++ SSL_load_error_strings(); ++ out(ERR_error_string(ERR_get_error(), buf)); out("\n"); ++ SSL_shutdown(ssl); ++ zerodie(); ++ } ++ }else r = write(fd,buf,n); ++ saveerrno = errno; ++ alarm(0); ++ if (flagtimedout) { errno = error_timeout; return -1; } ++ errno = saveerrno; ++ return r; ++} ++ ++static int client_cert_cb(SSL *s,X509 **x509, EVP_PKEY **pkey) ++{ ++ out("ZTLS found no client cert in control/clientcert.pem\n"); ++ zerodie(NULL,NULL); ++} ++ ++static int verify_cb(int ok, X509_STORE_CTX * ctx) ++{ ++ return (1); ++} ++#endif ++ + int saferead(fd,buf,len) int fd; char *buf; int len; + { + int r; ++#ifdef TLS ++ r = ssl_timeoutread(timeout,smtpfd,buf,len); ++#else + r = timeoutread(timeout,smtpfd,buf,len); ++#endif + if (r <= 0) dropped(); + return r; + } + int safewrite(fd,buf,len) int fd; char *buf; int len; + { + int r; ++#ifdef TLS ++ r = ssl_timeoutwrite(timeout,smtpfd,buf,len); ++#else + r = timeoutwrite(timeout,smtpfd,buf,len); ++#endif + if (r <= 0) dropped(); + return r; + } +@@ -186,6 +273,34 @@ + out(append); + out(".\n"); + outsmtptext(); ++ ++/* TAG */ ++#if defined(TLS) && defined(DEBUG) ++#define ONELINE_NAME(X) X509_NAME_oneline(X,NULL,0) ++ ++ if(ssl){ ++ X509 *peer; ++ ++ out("STARTTLS proto="); out(SSL_get_version(ssl)); ++ out("; cipher="); out(SSL_CIPHER_get_name(SSL_get_current_cipher(ssl))); ++ ++ /* we want certificate details */ ++ peer=SSL_get_peer_certificate(ssl); ++ if (peer != NULL) { ++ char *str; ++ ++ str=ONELINE_NAME(X509_get_subject_name(peer)); ++ out("; subject="); out(str); ++ OPENSSL_free(str); ++ str=ONELINE_NAME(X509_get_issuer_name(peer)); ++ out("; issuer="); out(str); ++ OPENSSL_free(str); ++ X509_free(peer); ++ } ++ out(";\n"); ++ } ++#endif ++ + zerodie(); + } + +@@ -216,20 +331,158 @@ + + stralloc recip = {0}; + ++#ifdef TLS ++void smtp(fqdn) ++char *fqdn; ++#else + void smtp() ++#endif + { + unsigned long code; + int flagbother; + int i; +- ++#ifdef TLS ++ int needtlsauth = 0; ++ SSL_CTX *ctx; ++ int saveerrno, r; ++ ++ stralloc servercert = {0}; ++ struct stat st; ++ if(fqdn){ ++ if(!stralloc_copys(&servercert, "control/tlshosts/")) temp_nomem(); ++ if(!stralloc_catb(&servercert, fqdn, str_len(fqdn))) temp_nomem(); ++ if(!stralloc_catb(&servercert, ".pem", 4)) temp_nomem(); ++ if(!stralloc_0(&servercert)) temp_nomem(); ++ if (stat(servercert.s,&st) == 0) needtlsauth = 1; ++ } ++#endif ++ + if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); + ++#ifdef TLS ++ substdio_puts(&smtpto,"EHLO "); ++#else + substdio_puts(&smtpto,"HELO "); ++#endif + substdio_put(&smtpto,helohost.s,helohost.len); + substdio_puts(&smtpto,"\r\n"); + substdio_flush(&smtpto); ++#ifdef TLS ++ if (smtpcode() != 250){ ++ substdio_puts(&smtpto,"HELO "); ++ substdio_put(&smtpto,helohost.s,helohost.len); ++ substdio_puts(&smtpto,"\r\n"); ++ substdio_flush(&smtpto); ++ if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); ++ } ++#else + if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); +- ++#endif ++ ++#ifdef TLS ++ i = 0; ++ while((i += str_chr(smtptext.s+i,'\n') + 1) && (i+12 < smtptext.len) && ++ str_diffn(smtptext.s+i+4,"STARTTLS\n",9)); ++ if (i+12 < smtptext.len) ++ { ++ substdio_puts(&smtpto,"STARTTLS\r\n"); ++ substdio_flush(&smtpto); ++ if (smtpcode() == 220) ++ { ++ SSL_library_init(); ++ if(!(ctx=SSL_CTX_new(SSLv23_client_method()))) ++ {char buf[1024]; ++ ++ out("ZTLS not available: error initializing ctx: "); ++ SSL_load_error_strings(); ++ out(ERR_error_string(ERR_get_error(), buf)); ++ out("\n"); ++ SSL_shutdown(ssl); ++ zerodie(); ++ } ++ if((stat("control/clientcert.pem", &st) == 0) && ++ ((SSL_CTX_use_RSAPrivateKey_file(ctx, "control/clientcert.pem", SSL_FILETYPE_PEM) <= 0) || ++ (SSL_CTX_use_certificate_chain_file(ctx, "control/clientcert.pem") <= 0) || ++ (SSL_CTX_check_private_key(ctx) <= 0))) ++ /* if there is a cert and it is bad, I fail ++ if there is no cert, I leave it to the other side to complain */ ++ SSL_CTX_set_client_cert_cb(ctx, client_cert_cb); ++ ++ /*SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);*/ ++ SSL_CTX_set_cipher_list(ctx,tlsclientciphers.s); ++ ++ if (needtlsauth){ ++ if (!SSL_CTX_load_verify_locations(ctx, servercert.s, NULL)) ++ {out("ZTLS unable to load "); out(servercert.s); out("\n"); ++ zerodie();} ++ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb); ++ } ++ ++ if(!(ssl=SSL_new(ctx))) ++ {char buf[1024]; ++ ++ out("ZTLS not available: error initializing ssl: "); ++ SSL_load_error_strings(); ++ out(ERR_error_string(ERR_get_error(), buf)); ++ out("\n"); ++ SSL_shutdown(ssl); ++ zerodie(); ++ } ++ SSL_set_fd(ssl,smtpfd); ++ ++ alarm(timeout); ++ r = SSL_connect(ssl); saveerrno = errno; ++ alarm(0); ++ if (flagtimedout) ++ {out("ZTLS not available: connect timed out\n"); ++ zerodie();} ++ errno = saveerrno; ++ if (r<=0) ++ {char buf[1024]; ++ ++ out("ZTLS not available: connect failed: "); ++ SSL_load_error_strings(); ++ out(ERR_error_string(ERR_get_error(), buf)); ++ out("\n"); ++ SSL_shutdown(ssl); ++ zerodie(); ++ } ++ if (needtlsauth) ++ /* should also check alternate names */ ++ {char commonName[256]; ++ ++ if ((r=SSL_get_verify_result(ssl)) != X509_V_OK) ++ {out("ZTLS unable to verify server with "); ++ out(servercert.s); out(": "); ++ out(X509_verify_cert_error_string(r)); out("\n"); ++ zerodie(); ++ } ++ X509_NAME_get_text_by_NID(X509_get_subject_name( ++ SSL_get_peer_certificate(ssl)), ++ NID_commonName, commonName, 256); ++ if (strcasecmp(fqdn,commonName)){ ++ out("ZTLS connection to "); out(fqdn); ++ out(" wanted, certificate for "); out(commonName); ++ out(" received\n"); ++ zerodie();} ++ } ++ ++ substdio_puts(&smtpto,"EHLO "); ++ substdio_put(&smtpto,helohost.s,helohost.len); ++ substdio_puts(&smtpto,"\r\n"); ++ substdio_flush(&smtpto); ++ ++ if (smtpcode() != 250) ++ { ++ quit("ZTLS connected to "," but my name was rejected"); ++ } ++ } ++ } ++ if ((!ssl) && needtlsauth) ++ {out("ZNo TLS achieved while "); out(servercert.s); out(" exists.\n"); ++ quit();} ++#endif ++ + substdio_puts(&smtpto,"MAIL FROM:<"); + substdio_put(&smtpto,sender.s,sender.len); + substdio_puts(&smtpto,">\r\n"); +@@ -324,6 +577,11 @@ + case 1: + if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break; + } ++#ifdef TLS ++ if (control_rldef(&tlsclientciphers,"control/tlsclientciphers",0,"DEFAULT") != 1) ++ temp_control(); ++ if(!stralloc_0(&tlsclientciphers)) temp_nomem(); ++#endif + } + + void main(argc,argv) +@@ -338,7 +596,10 @@ + int flagallaliases; + int flagalias; + char *relayhost; +- ++ ++#ifdef TLS ++ sig_alarmcatch(sigalrm); ++#endif + sig_pipeignore(); + if (argc < 4) perm_usage(); + if (chdir(auto_qmail) == -1) temp_chdir(); +@@ -417,7 +678,11 @@ + if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { + tcpto_err(&ip.ix[i].ip,0); + partner = ip.ix[i].ip; ++#ifdef TLS ++ smtp(ip.ix[i].fqdn); /* does not return */ ++#else + smtp(); /* does not return */ ++#endif + } + tcpto_err(&ip.ix[i].ip,errno == error_timeout); + close(smtpfd); +diff -urP qmail-1.03-vanilla/qmail-smtpd.8 qmail-1.03-tls-auth/qmail-smtpd.8 +--- qmail-1.03-vanilla/qmail-smtpd.8 Mon Jun 15 05:53:16 1998 ++++ qmail-1.03-tls-auth/qmail-smtpd.8 Wed Jun 19 15:30:20 2002 +@@ -3,6 +3,11 @@ + qmail-smtpd \- receive mail via SMTP + .SH SYNOPSIS + .B qmail-smtpd ++[ ++.I hostname ++.I checkprogram ++.I subprogram ++] + .SH DESCRIPTION + .B qmail-smtpd + receives mail messages via the Simple Mail Transfer Protocol (SMTP) +@@ -23,7 +28,29 @@ + header fields. + + .B qmail-smtpd +-supports ESMTP, including the 8BITMIME and PIPELINING options. ++supports ESMTP, including the 8BITMIME, PIPELINING, and AUTH options. ++ ++.B qmail-smtpd ++can accept LOGIN, PLAIN, and CRAM-MD5 AUTH types. It invokes ++.IR checkprogram , ++which reads on file descriptor 3 the username, a 0 byte, the password ++or challenge derived from ++.IR hostname , ++another 0 byte, a CRAM-MD5 response (if applicable to the AUTH type), ++and a final 0 byte. ++.I checkprogram ++invokes ++.I subprogram ++upon successful authentication, which should in turn return 0 to ++.BR qmail-smtpd , ++effectively setting the environment variables RELAYCLIENT and TCPREMOTEINFO ++(any supplied value replaced with the authenticated username). ++.B qmail-smtpd ++will reject the authentication attempt if it receives a nonzero return ++value from ++.I checkprogram ++or ++.IR subprogram . + .SH TRANSPARENCY + .B qmail-smtpd + converts the SMTP newline convention into the UNIX newline convention +@@ -177,3 +204,6 @@ + qmail-newmrh(8), + qmail-queue(8), + qmail-remote(8) ++.SH "HISTORY" ++The patch enabling the ESMTP AUTH option is not part of the standard ++qmail-1.03 distribution. +diff -urP qmail-1.03-vanilla/qmail-smtpd.c qmail-1.03-tls-auth/qmail-smtpd.c +--- qmail-1.03-vanilla/qmail-smtpd.c Mon Jun 15 05:53:16 1998 ++++ qmail-1.03-tls-auth/qmail-smtpd.c Wed Jun 19 16:05:56 2002 +@@ -20,18 +20,75 @@ + #include "now.h" + #include "exit.h" + #include "rcpthosts.h" ++#ifndef TLS + #include "timeoutread.h" + #include "timeoutwrite.h" ++#endif + #include "commands.h" ++#include "wait.h" ++#include "fd.h" + ++#ifdef TLS ++#include <openssl/ssl.h> ++SSL *ssl = NULL; ++ ++stralloc clientcert = {0}; ++stralloc tlsserverciphers = {0}; ++#endif ++ ++#define AUTHCRAM + #define MAXHOPS 100 + unsigned int databytes = 0; + int timeout = 1200; + ++#ifdef TLS ++int flagtimedout = 0; ++void sigalrm() ++{ ++ flagtimedout = 1; ++} ++int ssl_timeoutread(timeout,fd,buf,n) int timeout; int fd; char *buf; int n; ++{ ++ int r; int saveerrno; ++ if (flagtimedout) { errno = error_timeout; return -1; } ++ alarm(timeout); ++ if (ssl) { ++ while(((r = SSL_read(ssl,buf,n)) <= 0) ++ && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_READ)); ++ }else r = read(fd,buf,n); ++ saveerrno = errno; ++ alarm(0); ++ if (flagtimedout) { errno = error_timeout; return -1; } ++ errno = saveerrno; ++ return r; ++} ++ ++ ++int ssl_timeoutwrite(timeout,fd,buf,n) int timeout; int fd; char *buf; int n; ++{ ++ int r; int saveerrno; ++ if (flagtimedout) { errno = error_timeout; return -1; } ++ alarm(timeout); ++ if (ssl) { ++ while(((r = SSL_write(ssl,buf,n)) <= 0) ++ && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_WRITE)); ++ }else r = write(fd,buf,n); ++ saveerrno = errno; ++ alarm(0); ++ if (flagtimedout) { errno = error_timeout; return -1; } ++ errno = saveerrno; ++ return r; ++} ++#endif ++ + int safewrite(fd,buf,len) int fd; char *buf; int len; + { + int r; ++#ifdef TLS ++ r = ssl_timeoutwrite(timeout,fd,buf,len); ++#else + r = timeoutwrite(timeout,fd,buf,len); ++#endif + if (r <= 0) _exit(1); + return r; + } +@@ -51,6 +108,9 @@ + + void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); } + void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); } ++#ifdef TLS ++void err_nogwcert() { out("553 no valid cert for gatewaying (#5.7.1)\r\n"); } ++#endif + void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); } + void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); } + void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); } +@@ -59,6 +119,15 @@ + void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); } + void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); } + ++int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; } ++int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; } ++int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; } ++int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; } ++void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); } ++void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); } ++int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; } ++int err_authabrt() { out("501 auth exchange cancelled (#5.0.0)\r\n"); return -1; } ++int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; } + + stralloc greeting = {0}; + +@@ -81,6 +150,9 @@ + char *remoteinfo; + char *local; + char *relayclient; ++#ifdef TLS ++char *tlsciphers; ++#endif + + stralloc helohost = {0}; + char *fakehelo; /* pointer into helohost, or 0 */ +@@ -101,6 +173,9 @@ + { + char *x; + unsigned long u; ++#ifdef TLS ++ char *tlsciphers; ++#endif + + if (control_init() == -1) die_control(); + if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1) +@@ -131,6 +206,17 @@ + if (!remotehost) remotehost = "unknown"; + remoteinfo = env_get("TCPREMOTEINFO"); + relayclient = env_get("RELAYCLIENT"); ++#ifdef TLS ++ if (tlsciphers = env_get("TLSCIPHERS")){ ++ if (!stralloc_copys(&tlsserverciphers,tlsciphers)) die_nomem(); ++ } ++ else { ++ if (control_rldef(&tlsserverciphers,"control/tlsserverciphers",0,"DEFAULT") != 1) ++ die_control(); ++ } ++ if (!stralloc_0(&tlsserverciphers)) die_nomem(); ++#endif ++ + dohelo(remotehost); + } + +@@ -229,7 +315,18 @@ + } + void smtp_ehlo(arg) char *arg; + { +- smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); ++ smtp_greet("250-"); ++#ifdef AUTHCRAM ++ out("\r\n250-AUTH LOGIN CRAM-MD5 PLAIN"); ++ out("\r\n250-AUTH=LOGIN CRAM-MD5 PLAIN"); ++#else ++ out("\r\n250-AUTH LOGIN PLAIN"); ++ out("\r\n250-AUTH=LOGIN PLAIN"); ++#endif ++#ifdef TLS ++ if (!ssl) out("\r\n250-STARTTLS"); ++#endif ++ out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); + seenmail = 0; dohelo(arg); + } + void smtp_rset() +@@ -247,6 +344,12 @@ + if (!stralloc_0(&mailfrom)) die_nomem(); + out("250 ok\r\n"); + } ++#ifdef TLS ++static int verify_cb(int ok, X509_STORE_CTX * ctx) ++{ ++ return (1); ++} ++#endif + void smtp_rcpt(arg) char *arg; { + if (!seenmail) { err_wantmail(); return; } + if (!addrparse(arg)) { err_syntax(); return; } +@@ -257,7 +360,54 @@ + if (!stralloc_0(&addr)) die_nomem(); + } + else ++#ifndef TLS + if (!addrallowed()) { err_nogateway(); return; } ++#else ++ if (!addrallowed()) ++ { ++ if (ssl) ++ { STACK_OF(X509_NAME) *sk; ++ X509 *peercert; ++ stralloc tlsclients = {0}; ++ struct constmap maptlsclients; ++ int r; ++ ++ SSL_set_verify(ssl, ++ SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, ++ verify_cb); ++ if ((sk = SSL_load_client_CA_file("control/clientca.pem")) == NULL) ++ { err_nogateway(); return; } ++ SSL_set_client_CA_list(ssl, sk); ++ if((control_readfile(&tlsclients,"control/tlsclients",0) != 1) || ++ !constmap_init(&maptlsclients,tlsclients.s,tlsclients.len,0)) ++ { err_nogateway(); return; } ++ ++ SSL_renegotiate(ssl); ++ SSL_do_handshake(ssl); ++ ssl->state = SSL_ST_ACCEPT; ++ SSL_do_handshake(ssl); ++ if ((r = SSL_get_verify_result(ssl)) != X509_V_OK) ++ {out("553 no valid cert for gatewaying: "); ++ out(X509_verify_cert_error_string(r)); ++ out(" (#5.7.1)\r\n"); ++ return; ++ } ++ ++ if (peercert = SSL_get_peer_certificate(ssl)) ++ {char emailAddress[256]; ++ ++ X509_NAME_get_text_by_NID(X509_get_subject_name( ++ SSL_get_peer_certificate(ssl)), ++ NID_pkcs9_emailAddress, emailAddress, 256); if (!stralloc_copys(&clientcert, emailAddress)) die_nomem(); ++ if (!constmap(&maptlsclients,clientcert.s,clientcert.len)) ++ { err_nogwcert(); return; } ++ relayclient = ""; ++ } ++ else { err_nogwcert(); return; } ++ } ++ else { err_nogateway(); return; } ++ } ++#endif + if (!stralloc_cats(&rcptto,"T")) die_nomem(); + if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); + if (!stralloc_0(&rcptto)) die_nomem(); +@@ -269,7 +419,11 @@ + { + int r; + flush(); ++#ifdef TLS ++ r = ssl_timeoutread(timeout,fd,buf,len); ++#else + r = timeoutread(timeout,fd,buf,len); ++#endif + if (r == -1) if (errno == error_timeout) die_alarm(); + if (r <= 0) die_read(); + return r; +@@ -369,6 +523,9 @@ + int hops; + unsigned long qp; + char *qqx; ++#ifdef TLS ++ stralloc protocolinfo = {0}; ++#endif + + if (!seenmail) { err_wantmail(); return; } + if (!rcptto.len) { err_wantrcpt(); return; } +@@ -377,8 +534,20 @@ + if (qmail_open(&qqt) == -1) { err_qqt(); return; } + qp = qmail_qp(&qqt); + out("354 go ahead\r\n"); +- ++#ifdef TLS ++ if(ssl){ ++ if (!stralloc_copys(&protocolinfo, SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)))) die_nomem(); ++ if (!stralloc_catb(&protocolinfo, " encrypted SMTP", 15)) die_nomem(); ++ if (clientcert.len){ ++ if (!stralloc_catb(&protocolinfo," cert ", 6)) die_nomem(); ++ if (!stralloc_catb(&protocolinfo,clientcert.s, clientcert.len)) die_nomem(); ++ } ++ if (!stralloc_0(&protocolinfo)) die_nomem(); ++ } else if (!stralloc_copyb(&protocolinfo,"SMTP",5)) die_nomem(); ++ received(&qqt,protocolinfo.s,local,remoteip,remotehost,remoteinfo,case_diffs(remotehost,helohost.s) ? helohost.s : 0); ++#else + received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo); ++#endif + blast(&hops); + hops = (hops >= MAXHOPS); + if (hops) qmail_fail(&qqt); +@@ -393,23 +562,299 @@ + out(qqx + 1); + out("\r\n"); + } ++#ifdef TLS ++static RSA *tmp_rsa_cb(ssl,export,keylength) SSL *ssl; int export; int keylength; ++{ ++ RSA* rsa; ++ BIO* in; ++ ++ if (!export || keylength == 512) ++ if (in=BIO_new(BIO_s_file_internal())) ++ if (BIO_read_filename(in,"control/rsa512.pem") > 0) ++ if (rsa=PEM_read_bio_RSAPrivateKey(in,NULL,NULL,NULL)) ++ return rsa; ++ return (RSA_generate_key(export?keylength:512,RSA_F4,NULL,NULL)); ++} ++ ++void smtp_tls(arg) char *arg; ++{ ++ SSL_CTX *ctx; ++ ++ if (*arg) ++ {out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n"); ++ return;} ++ ++ SSL_library_init(); ++ if(!(ctx=SSL_CTX_new(SSLv23_server_method()))) ++ {out("454 TLS not available: unable to initialize ctx (#4.3.0)\r\n"); ++ return;} ++ if(!SSL_CTX_use_RSAPrivateKey_file(ctx, "control/servercert.pem", SSL_FILETYPE_PEM)) ++ {out("454 TLS not available: missing RSA private key (#4.3.0)\r\n"); ++ return;} ++ if(!SSL_CTX_use_certificate_chain_file(ctx, "control/servercert.pem")) ++ {out("454 TLS not available: missing certificate (#4.3.0)\r\n"); ++ return;} ++ SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb); ++ SSL_CTX_set_cipher_list(ctx,tlsserverciphers.s); ++ SSL_CTX_load_verify_locations(ctx, "control/clientca.pem",NULL); ++ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_cb); ++ ++ out("220 ready for tls\r\n"); flush(); ++ ++ if(!(ssl=SSL_new(ctx))) die_read(); ++ SSL_set_fd(ssl,0); ++ if(SSL_accept(ssl)<=0) die_read(); ++ substdio_fdbuf(&ssout,SSL_write,ssl,ssoutbuf,sizeof(ssoutbuf)); ++ ++ remotehost = env_get("TCPREMOTEHOST"); ++ if (!remotehost) remotehost = "unknown"; ++ dohelo(remotehost); ++} ++#endif ++ ++ ++char unique[FMT_ULONG + FMT_ULONG + 3]; ++static stralloc authin = {0}; ++static stralloc user = {0}; ++static stralloc pass = {0}; ++static stralloc resp = {0}; ++static stralloc slop = {0}; ++char *hostname; ++char **childargs; ++substdio ssup; ++char upbuf[128]; ++int authd = 0; ++ ++int authgetl(void) { ++ int i; ++ ++ if (!stralloc_copys(&authin, "")) die_nomem(); ++ ++ for (;;) { ++ if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */ ++ i = substdio_get(&ssin,authin.s + authin.len,1); ++ if (i != 1) die_read(); ++ if (authin.s[authin.len] == '\n') break; ++ ++authin.len; ++ } ++ ++ if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len; ++ authin.s[authin.len] = 0; ++ ++ if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); } ++ if (authin.len == 0) { return err_input(); } ++ return authin.len; ++} ++ ++int authenticate(void) ++{ ++ int child; ++ int wstat; ++ int pi[2]; ++ ++ if (!stralloc_0(&user)) die_nomem(); ++ if (!stralloc_0(&pass)) die_nomem(); ++ if (!stralloc_0(&resp)) die_nomem(); ++ ++ if (fd_copy(2,1) == -1) return err_pipe(); ++ close(3); ++ if (pipe(pi) == -1) return err_pipe(); ++ if (pi[0] != 3) return err_pipe(); ++ switch(child = fork()) { ++ case -1: ++ return err_fork(); ++ case 0: ++ close(pi[1]); ++ sig_pipedefault(); ++ execvp(*childargs, childargs); ++ _exit(1); ++ } ++ close(pi[0]); ++ ++ substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf); ++ if (substdio_put(&ssup,user.s,user.len) == -1) return err_write(); ++ if (substdio_put(&ssup,pass.s,pass.len) == -1) return err_write(); ++ if (substdio_put(&ssup,resp.s,resp.len) == -1) return err_write(); ++ if (substdio_flush(&ssup) == -1) return err_write(); ++ ++ close(pi[1]); ++ byte_zero(pass.s,pass.len); ++ byte_zero(upbuf,sizeof upbuf); ++ if (wait_pid(&wstat,child) == -1) return err_child(); ++ if (wait_crashed(wstat)) return err_child(); ++ if (wait_exitcode(wstat)) { sleep(5); return 1; } /* no */ ++ return 0; /* yes */ ++} ++ ++int auth_login(arg) char *arg; ++{ ++ int r; ++ ++ if (*arg) { ++ if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input(); ++ } ++ else { ++ out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */ ++ if (authgetl() < 0) return -1; ++ if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input(); ++ } ++ if (r == -1) die_nomem(); ++ ++ out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */ ++ ++ if (authgetl() < 0) return -1; ++ if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input(); ++ if (r == -1) die_nomem(); ++ ++ if (!user.len || !pass.len) return err_input(); ++ return authenticate(); ++} ++ ++int auth_plain(arg) char *arg; ++{ ++ int r, id = 0; ++ ++ if (*arg) { ++ if (r = b64decode(arg,str_len(arg),&slop) == 1) return err_input(); ++ } ++ else { ++ out("334 \r\n"); flush(); ++ if (authgetl() < 0) return -1; ++ if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input(); ++ } ++ if (r == -1 || !stralloc_0(&slop)) die_nomem(); ++ while (slop.s[id]) id++; /* ignore authorize-id */ ++ ++ if (slop.len > id + 1) ++ if (!stralloc_copys(&user,slop.s + id + 1)) die_nomem(); ++ if (slop.len > id + user.len + 2) ++ if (!stralloc_copys(&pass,slop.s + id + user.len + 2)) die_nomem(); ++ ++ if (!user.len || !pass.len) return err_input(); ++ return authenticate(); ++} ++ ++#ifdef AUTHCRAM ++int auth_cram() ++{ ++ int i, r; ++ char *s; ++ ++ s = unique; ++ s += fmt_uint(s,getpid()); ++ *s++ = '.'; ++ s += fmt_ulong(s,(unsigned long) now()); ++ *s++ = '@'; ++ *s++ = 0; ++ ++ if (!stralloc_copys(&pass,"<")) die_nomem(); ++ if (!stralloc_cats(&pass,unique)) die_nomem(); ++ if (!stralloc_cats(&pass,hostname)) die_nomem(); ++ if (!stralloc_cats(&pass,">")) die_nomem(); ++ if (b64encode(&pass,&slop) < 0) die_nomem(); ++ if (!stralloc_0(&slop)) die_nomem(); ++ ++ out("334 "); ++ out(slop.s); ++ out("\r\n"); ++ flush(); ++ ++ if (authgetl() < 0) return -1; ++ if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input(); ++ if (r == -1 || !stralloc_0(&slop)) die_nomem(); ++ ++ i = str_chr(slop.s,' '); ++ s = slop.s + i; ++ while (*s == ' ') ++s; ++ slop.s[i] = 0; ++ if (!stralloc_copys(&user,slop.s)) die_nomem(); ++ if (!stralloc_copys(&resp,s)) die_nomem(); ++ ++ if (!user.len || !resp.len) return err_input(); ++ return authenticate(); ++} ++#endif ++ ++struct authcmd { ++ char *text; ++ int (*fun)(); ++} authcmds[] = { ++ { "login", auth_login } ++, { "plain", auth_plain } ++#ifdef AUTHCRAM ++, { "cram-md5", auth_cram } ++#endif ++, { 0, err_noauth } ++}; ++ ++void smtp_auth(arg) ++char *arg; ++{ ++ int i; ++ char *cmd = arg; ++ ++ if (!hostname || !*childargs) ++ { ++ out("503 auth not available (#5.3.3)\r\n"); ++ return; ++ } ++ if (authd) { err_authd(); return; } ++ if (seenmail) { err_authmail(); return; } ++ ++ if (!stralloc_copys(&user,"")) die_nomem(); ++ if (!stralloc_copys(&pass,"")) die_nomem(); ++ if (!stralloc_copys(&resp,"")) die_nomem(); ++ ++ i = str_chr(cmd,' '); ++ arg = cmd + i; ++ while (*arg == ' ') ++arg; ++ cmd[i] = 0; ++ ++ for (i = 0;authcmds[i].text;++i) ++ if (case_equals(authcmds[i].text,cmd)) break; ++ ++ switch (authcmds[i].fun(arg)) { ++ case 0: ++ authd = 1; ++ relayclient = ""; ++ remoteinfo = user.s; ++ if (!env_unset("TCPREMOTEINFO")) die_read(); ++ if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem(); ++ out("235 ok, go ahead (#2.0.0)\r\n"); ++ break; ++ case 1: ++ out("535 authorization failed (#5.7.0)\r\n"); ++ } ++} + + struct commands smtpcommands[] = { + { "rcpt", smtp_rcpt, 0 } + , { "mail", smtp_mail, 0 } + , { "data", smtp_data, flush } ++, { "auth", smtp_auth, flush } + , { "quit", smtp_quit, flush } + , { "helo", smtp_helo, flush } + , { "ehlo", smtp_ehlo, flush } + , { "rset", smtp_rset, 0 } + , { "help", smtp_help, flush } ++#ifdef TLS ++, { "starttls", smtp_tls, flush } ++#endif + , { "noop", err_noop, flush } + , { "vrfy", err_vrfy, flush } + , { 0, err_unimpl, flush } + } ; + +-void main() +-{ ++void main(argc,argv) ++int argc; ++char **argv; ++{ ++ hostname = argv[1]; ++ childargs = argv + 2; ++ ++#ifdef TLS ++ sig_alarmcatch(sigalrm); ++#endif + sig_pipeignore(); + if (chdir(auto_qmail) == -1) die_control(); + setup(); |