diff -durN qmail-1.03.orig/Makefile qmail-1.03/Makefile
--- qmail-1.03.orig/Makefile	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/Makefile	Fri Sep 13 17:35:22 2002
@@ -1439,14 +1439,16 @@
 
 qmail-remote: \
 load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \
+ssl_timeoutio.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 dns.lib socket.lib base64.o
 	./load qmail-remote control.o constmap.o timeoutread.o \
 	timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.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
@@ -1534,11 +1536,13 @@
 qmail-smtpd: \
 load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
 timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
+ssl_timeoutio.o ndelay.a \
 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
 	./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
 	timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.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 \
@@ -2108,6 +2112,10 @@
 compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h
 	./compile timeoutwrite.c
 
+ssl_timeoutio.o: \
+compile ssl_timeoutio.c ssl_timeoutio.h select.h error.h ndelay.h
+	./compile ssl_timeoutio.c
+
 token822.o: \
 compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \
 gen_alloc.h gen_allocdefs.h
@@ -2139,3 +2147,13 @@
 wait_pid.o: \
 compile wait_pid.c error.h haswaitp.h
 	./compile wait_pid.c
+
+cert cert-req: \
+Makefile-cert
+	@$(MAKE) -sf $< $@
+
+Makefile-cert: \
+conf-qmail Makefile-cert.mk
+	@cat Makefile-cert.mk \
+	| sed s}QMAIL}"`head -1 conf-qmail`"}g \
+	> $@
diff -durN qmail-1.03.orig/Makefile-cert.mk qmail-1.03/Makefile-cert.mk
--- qmail-1.03.orig/Makefile-cert.mk	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/Makefile-cert.mk	Fri Sep 13 11:01:48 2002
@@ -0,0 +1,21 @@
+cert-req: req.pem
+cert cert-req: QMAIL/control/clientcert.pem
+	@:
+
+QMAIL/control/clientcert.pem: QMAIL/control/servercert.pem
+	ln -s $< $@
+
+QMAIL/control/servercert.pem:
+	PATH=$$PATH:/usr/local/ssl/bin \
+		openssl req -new -x509 -nodes -days 366 -out $@ -keyout $@
+	chmod 640 $@
+	chown qmaild.qmail $@
+
+req.pem:
+	PATH=$$PATH:/usr/local/ssl/bin openssl req \
+		-new -nodes -out $@ -keyout QMAIL/control/servercert.pem
+	chmod 640 QMAIL/control/servercert.pem
+	chown qmaild.qmail QMAIL/control/servercert.pem
+	@echo
+	@echo "Send req.pem to your CA to obtain signed_req.pem, and do:"
+	@echo "cat signed_req.pem >> QMAIL/control/servercert.pem"
diff -durN qmail-1.03.orig/README.1st qmail-1.03/README.1st
--- qmail-1.03.orig/README.1st	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/README.1st	Mon Sep 23 14:55:41 2002
@@ -0,0 +1,82 @@
+This is qmail-auth-send-tls.
+
+This is a patch for Daniel Bernstein's qmail-1.03 (
+http://cr.yp.to/qmail.html), combining Frederik Vermeulen's GPL'ed tls.patch (
+http://www.esat.kuleuven.ac.be/~vermeule/qmail/tls.patch , see README.tls) with
+Bjoern Kalkbrenner's qmail-smtp-auth-send-0.0.1 patch (
+http://www.cyberphoria.org/?display=projects_qmail_smtp_auth_send_patch , see
+README.smtp-auth-send).
+
+It changes qmail-remote, so that it uses TLS when talking to hosts supporting
+this, by issuing SMTP's STARTTLS command.  If a mail serveroffers SMTP AUTH
+LOGIN (SASL) after having setup a TLS connection, this can be used via
+qmail-smtp-auth-send's /var/qmail/control/smtproutes_users .
+
+This is typically needed by people dumping their mail on an ISP's mailhub,
+which asks for AUTH and TLS.
+
+qmail-smtpd is _not_ changed by this patch.
+
+I don't think this patch offers AUTH facility without TLS (i.e. on clear-text
+channels).
+
+
+OTHER PATCHES
+
+Neal Groothuis's qmail-1.03-starttls-smtp-auth.patch (
+http://students.imsa.edu/~ngroot/qmail-1.03-starttls-smtp-auth.patch ) does
+something slightly different: it does not offer AUTH for clients, just for
+qmail-smtpd.  It combines Frederik Vermeulen's tls.patch with Krzysztof
+Dabrowski's qmail-smtpd-auth (
+http://members.elysium.pl/brush/qmail-smtpd-auth/ ).
+
+See also http://www.qmail.org/ .
+
+
+COPYRIGHT AND LICENSE
+
+Copyright (C) 2002 Frederik Vermeulen <jos-tls@kotnet.org> e.a.
+Copyright (C) 2002 Bjoern Kalkbrenner e.a.
+Copyright (C) 2002 Joost van Baal <joostvb-qmail-auth-send-tls-14@mdcc.cx>
+
+See README.tls and README.smtp-auth-send for other people who've contributed,
+and have copyrights on this code.
+ 
+     This patch is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+ 
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+     GNU General Public License for more details.
+ 
+     A copy of the GNU General Public License is available from
+     http://www.gnu.org/copyleft/gpl.html, or write to the Free Software 
+     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+
+
+CHANGES
+
+qmail-auth-send-tls (20020923)
+
+  * qmail-remote.c: Fixed bug which caused qmail-remote to segfault when no
+    /var/qmail/control/smtproutes file is present, and a mail is sent with a sender
+    address not listed in smtproutes_users.
+  * qmail-remote.c: Fixed bug which caused mail-remote to not pass ip address of 
+    the remote host to the log file.
+  * qmail-remote.c: Fixed bug which caused qmail-remote to segfaults when no 
+    smtproutes_users file is present.
+  * README.1st: updated
+
+ -- Joost van Baal,  Mon Sep 23 14:54:27 CEST 2002
+
+qmail-auth-send-tls (qmail-auth-send-tls.patch, 13 Sep 2002)
+
+  * Initial release, announced in 
+    http://www.ornl.gov/its/archives/mailing-lists/qmail/2002/09/msg00555.html .
+
+ -- Joost van Baal,  Fri Sep 13 16:31:59 CEST 2002
+
+
diff -durN qmail-1.03.orig/README.smtp-auth-send qmail-1.03/README.smtp-auth-send
--- qmail-1.03.orig/README.smtp-auth-send	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/README.smtp-auth-send	Fri Sep 13 16:16:09 2002
@@ -0,0 +1,52 @@
+Qmail 1.03 qmail-remote.c SMTP-AUTH send patch
+
+  * Date: 20020715
+  * Version: 0.0.1 ;)
+  * Author: Bjoern Kalkbrenner
+  * Location: Home | Download
+
+Quick install:
+
+ 1. Copy the base64.c and base64.h to your qmail source and chdir into it.
+ 2. Patch the source with patch -p1 <smtp-auth-send.patch
+ 3. make setup check
+ 4. ...follow the qmail-installation or copy your new qmail-remote to /var/
+    qmail/bin
+ 5. create your /var/qmail/control/smtproutes_users
+
+Quick info:
+
+This patch is based on Robert Sander's AUTH LOGIN patch which is based on the 
+qmail-smtpd-auth patch which itself is based on the patch from Mrs. Brisby...
+Confusing ;)
+
+I made this patch because my ISP also switched to AUTH LOGIN on his SMTP relay
+and we are using an internal linux qmail server in our company, but the patch
+Robert wrote was only working for 1 user. . Several users use this ISP for
+outgoing mail, mails are fetched with fetchmail, (scanned for viruses) and send
+to the local mailaccounts which is used as relay. Now it is easy for us to
+internal mailaccounts mapped to the external mailservers. You can even select
+the outgoing mailserver with the smtproutes_users file.
+
+The username and password for the remote smtp relay are stored in /var/qmail/
+control/smtproutes_users (new controlfile!) separated with pipes after the
+entry for the relay server.
+For example:
+
+#mailuser-example
+mail@example.com:smtp.example.com|example.com1|examplePasswd
+info@example.com:smtp.example.com|example.com2|anotherPasswd
+
+mailuser-examples sending to port 26
+anotherport@example.com:smtp.example.com:26|example.com3|justfoobar
+
+#default, not sure if this entry is used, untested!!!!!! Maybe i had to code
+this.
+:relay.provider.com|username|password
+
+Password has to be stored in cleartext. This is maybe not bug-free, but like
+Robert said:
+
+It works for me, no guarantee...
+
+
diff -durN qmail-1.03.orig/README.tls qmail-1.03/README.tls
--- qmail-1.03.orig/README.tls	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/README.tls	Fri Sep 13 16:16:09 2002
@@ -0,0 +1,87 @@
+Frederik Vermeulen <jos-tls@kotnet.org> 20020825
+http://www.esat.kuleuven.ac.be/~vermeule/qmail/qmail-1.03-tls.patch
+
+Hacked on Fri, 13 Sep 2002 00:02:46 +0200 by Joost van Baal:
+no longer offers TLS in qmail-smtpd; only in qmail-remote.
+no -I/usr/local/ssl/include : my unixen have openssl installed
+in the systemdirectory ( /usr/include ).  Enabled DEBUG.
+
+This patch implements RFC2487 in qmail. This means you can 
+get SSL or TLS encrypted and authenticated SMTP between 
+the MTAs and between MTA and an MUA like Netscape. 
+The code is considered experimental (but has worked for
+many since its first release on 1999-03-21).
+
+Usage: - install OpenSSL-0.9.6e http://www.openssl.org/
+         (any 0.9.[567] version should work)
+       - apply patch to qmail-1.03 http://www.qmail.org/ 
+         The patches to qmail-remote.c
+         and qmail-smtpd.c can be applied separately.
+       - provide a server certificate in /var/qmail/control/servercert.pem.
+         "make cert" makes a self-signed certificate.
+         "make cert-req" makes a certificate request.
+         Note: you can add the CA certificate and intermediate
+         certs to the end of servercert.pem.
+       - replace qmail-smtpd and/or qmail-remote binary
+       - verify operation (header information should show
+         something like
+         "Received [..] with DES-CBC3-SHA encrypted SMTP;")
+         If you don't have a server to test with, you can test
+         by sending mail to tag-ping@tbs-internet.com,
+         which will bounce your mail.
+
+Optional: - when DEBUG is defined, some extra TLS info will be logged
+          - qmail-remote will authenticate with the certificate in
+            /var/qmail/control/clientcert.pem. By preference this is
+            the same as servercert.pem, where nsCertType should be 
+            == server,client or be a generic certificate (no usage specified). 
+          - server authentication:
+            qmail-remote requires authentication from servers for which
+            /var/qmail/control/tlshosts/host.dom.ain.pem exists.
+            The .pem file contains the validating CA certificates
+            (or self-signed server certificate with openssl-0.9.5).
+            CommonName has to match.
+            WARNING: this option may cause mail to be delayed, bounced,
+            doublebounced, and lost.
+          - cipher selection:
+            qmail-remote: 
+              openssl cipher string read from 
+              /var/qmail/control/tlsclientciphers
+          - smtps (deprecated SMTP over TLS via port 465):
+            qmail-remote: when connecting to port 465 
+
+Caveats: - binaries dynamically linked with current openssl versions need
+           recompilation when the shared openssl libs are upgraded.
+         - this patch could conflict with other patches (notably those
+           replacing \n with \r\n, which is a bad idea on encrypted links).
+           Qmail.org has a link to a combined tls+auth patch.
+         - some broken servers have a problem with TLSv1 compatibility.
+           Uncomment the line where we set the SSL_OP_NO_TLSv1 option.
+         - needs working /dev/urandom for seeding random number generator.
+         - packagers should make sure that installing without a valid 
+           servercert is impossible
+         - when applied in combination with AUTH patch, AUTH patch
+           should be applied first.
+
+Copyright: GPL
+           Links with OpenSSL
+           Inspiration and code from examples in SSLeay (E. Young
+           <eay@cryptsoft.com> and T. Hudson <tjh@cryptsoft.com>),
+           stunnel (M. Trojnara <mtrojnar@ddc.daewoo.com.pl>),
+           Postfix/TLS (L. Jaenicke <Lutz.Jaenicke@aet.tu-cottbus.de>),
+           modssl (R. Engelschall <rse@engelschall.com>),
+           openssl examples of E. Rescorla <ekr@rtfm.com>.
+           Debug code, tlscipher selection, many feature suggestions,
+           French docs https://www.TBS-internet.com/ssl/qmail-tls.html 
+           from Jean-Philippe Donnio <tag-ssl@tbs-internet.com>.
+           Openssl usage consulting from B. M"oller <bmoeller@acm.org>.
+           Bug report from A. Dustman <adustman@comstar.net>.
+           Ssl_timeoutio functions (non-blocking io, timeouts), smtps, 
+           auth and qmtp patch compatibility, man pages, code cleanup 
+           from A. Meltzer <albertm-qmail-tls@gpo.stanford.edu>.
+           Bug report from Niall Richard Murphy.
+
+Bug reports: mailto:<jos-tls@kotnet.org>
+
+
+
diff -durN qmail-1.03.orig/TARGETS qmail-1.03/TARGETS
--- qmail-1.03.orig/TARGETS	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/TARGETS	Fri Sep 13 17:07:56 2002
@@ -168,6 +168,7 @@
 constmap.o
 timeoutread.o
 timeoutwrite.o
+ssl_timeoutio.o
 timeoutconn.o
 tcpto.o
 dns.o
@@ -178,6 +179,7 @@
 ndelay.o
 ndelay_off.o
 ndelay.a
+base64.o
 dns.lib
 qmail-remote
 qmail-rspawn.o
@@ -320,6 +322,7 @@
 binm2+df
 binm3
 binm3+df
+Makefile-cert
 it
 qmail-local.0
 qmail-lspawn.0
diff -durN qmail-1.03.orig/base64.c qmail-1.03/base64.c
--- qmail-1.03.orig/base64.c	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/base64.c	Fri Sep 13 12:59:30 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 -durN qmail-1.03.orig/base64.h qmail-1.03/base64.h
--- qmail-1.03.orig/base64.h	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/base64.h	Fri Sep 13 12:59:29 2002
@@ -0,0 +1,7 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+extern int b64decode();
+extern int b64encode();
+
+#endif
diff -durN qmail-1.03.orig/conf-cc qmail-1.03/conf-cc
--- qmail-1.03.orig/conf-cc	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/conf-cc	Fri Sep 13 11:01:48 2002
@@ -1,3 +1,3 @@
-cc -O2
+cc -O2 -DTLS -DDEBUG
 
 This will be used to compile .c files.
diff -durN qmail-1.03.orig/dns.c qmail-1.03/dns.c
--- qmail-1.03.orig/dns.c	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/dns.c	Fri Sep 13 11:01:47 2002
@@ -269,12 +269,11 @@
 int pref;
 {
  int r;
- struct ip_mx ix;
+ struct ip_mx ix = {0};
 
  if (!stralloc_copy(&glue,sa)) return DNS_MEM;
  if (!stralloc_0(&glue)) return DNS_MEM;
  if (glue.s[0]) {
-   ix.pref = 0;
    if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
     {
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
@@ -293,9 +292,16 @@
    ix.ip = ip;
    ix.pref = pref;
    if (r == DNS_SOFT) return DNS_SOFT;
-   if (r == 1)
+   if (r == 1) {
+#ifdef IX_FQDN
+     ix.fqdn = glue.s;
+#endif
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
   }
+  }
+#ifdef IX_FQDN
+ glue.s = 0;
+#endif
  return 0;
 }
 
@@ -315,7 +321,7 @@
 {
  int r;
  struct mx { stralloc sa; unsigned short p; } *mx;
- struct ip_mx ix;
+ struct ip_mx ix = {0};
  int nummx;
  int i;
  int j;
@@ -327,7 +333,6 @@
  if (!stralloc_copy(&glue,sa)) return DNS_MEM;
  if (!stralloc_0(&glue)) return DNS_MEM;
  if (glue.s[0]) {
-   ix.pref = 0;
    if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
     {
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
diff -durN qmail-1.03.orig/ipalloc.h qmail-1.03/ipalloc.h
--- qmail-1.03.orig/ipalloc.h	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/ipalloc.h	Fri Sep 13 11:01:47 2002
@@ -3,7 +3,15 @@
 
 #include "ip.h"
 
+#ifdef TLS
+# define IX_FQDN 1
+#endif
+
+#ifdef IX_FQDN
+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 -durN qmail-1.03.orig/qmail-control.9 qmail-1.03/qmail-control.9
--- qmail-1.03.orig/qmail-control.9	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/qmail-control.9	Fri Sep 13 17:10:06 2002
@@ -43,6 +43,7 @@
 .I badmailfrom	\fR(none)	\fRqmail-smtpd
 .I bouncefrom	\fRMAILER-DAEMON	\fRqmail-send
 .I bouncehost	\fIme	\fRqmail-send
+.I clientcert.pem       \fR(none)       \fRqmail-remote
 .I concurrencylocal	\fR10	\fRqmail-send
 .I concurrencyremote	\fR20	\fRqmail-send
 .I defaultdomain	\fIme	\fRqmail-inject
@@ -66,6 +67,8 @@
 .I timeoutconnect	\fR60	\fRqmail-remote
 .I timeoutremote	\fR1200	\fRqmail-remote
 .I timeoutsmtpd	\fR1200	\fRqmail-smtpd
+.I tlsclientciphers     \fR(none)       \fRqmail-remote
+.I tlshosts/FQDN.pem    \fR(none)       \fRqmail-remote
 .I virtualdomains	\fR(none)	\fRqmail-send
 .fi
 .RE
diff -durN qmail-1.03.orig/qmail-remote.8 qmail-1.03/qmail-remote.8
--- qmail-1.03.orig/qmail-remote.8	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/qmail-remote.8	Fri Sep 13 17:18:10 2002
@@ -114,6 +114,10 @@
 always exits zero.
 .SH "CONTROL FILES"
 .TP 5
+.I clientcert.pem
+SSL certificate that is used to authenticate with the remote server
+during a TLS session.
+.TP 5
 .I helohost
 Current host name,
 for use solely in saying hello to the remote SMTP server.
@@ -156,6 +160,8 @@
 this tells
 .B qmail-remote
 to look up MX records as usual.
+.I port 
+value of 465 (deprecated smtps port) causes TLS session to be started.
 .I smtproutes
 may include wildcards:
 
@@ -183,6 +189,16 @@
 .I smtproutes
 if you do not accept mail from the network.
 .TP 5
+.I smtproutes_users
+Per sender AUTH LOGIN and relay information.  A mapping from sender address
+to relayhost, with username and password (in cleartext).
+
+.EX
+   joe@home.example.com:smtp.example.com|joe|JoEsPa55w0rd
+   ann@home.example.com:smtp.example.com:26|asmith|AnnPaSSwOrd
+.EE
+
+.TP 5
 .I timeoutconnect
 Number of seconds
 .B qmail-remote
@@ -195,6 +211,23 @@
 .B qmail-remote
 will wait for each response from the remote SMTP server.
 Default: 1200.
+
+.TP 5
+.I tlsclientciphers
+An OpenSSL client cipher string.
+
+.TP 5
+.I tlshosts/<FQDN>.pem
+.B qmail-remote
+requires authentication from servers for which this certificate exists
+.RB ( <FQDN>
+is the fully-qualified domain name of the server). The
+.I CommonName
+attributes have to match.
+
+.B WARNING:
+this option may cause mail to be delayed, bounced, doublebounced, or lost.
+
 .SH "SEE ALSO"
 addresses(5),
 envelopes(5),
diff -durN qmail-1.03.orig/qmail-remote.c qmail-1.03/qmail-remote.c
--- qmail-1.03.orig/qmail-remote.c	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/qmail-remote.c	Mon Sep 23 14:59:22 2002
@@ -1,3 +1,13 @@
+/*
+ * qmail-remote.c : djb's qmail-1.03 source, patched with Frederik Vermeulen's
+ * tls.patch ( http://www.esat.kuleuven.ac.be/~vermeule/qmail/tls.patch ), 
+ * manually applied Bjoern Kalkbrenner's qmail-smtp-auth-send-0.0.1 patch
+ * ( http://www.cyberphoria.org/?display=projects_qmail_smtp_auth_send_patch )
+ *
+ * patching and tweaking by Joost van Baal, Fri, 13 Sep 2002 12:57:11 +0200
+ *
+ */
+
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -28,6 +38,7 @@
 #include "timeoutconn.h"
 #include "timeoutread.h"
 #include "timeoutwrite.h"
+#include "base64.h" /* smtp auth */
 
 #define HUGESMTPTEXT 5000
 
@@ -40,13 +51,25 @@
 
 stralloc helohost = {0};
 stralloc routes = {0};
+stralloc routes_users = {0};
 struct constmap maproutes;
+struct constmap maproutes_users;
 stralloc host = {0};
+stralloc user = {0};
 stralloc sender = {0};
 
+stralloc auth_smtp_user = {0};
+stralloc auth_smtp_pass = {0};
+stralloc auth_b64_user = {0};
+stralloc auth_b64_pass = {0};
+
 saa reciplist = {0};
 
 struct ip_address partner;
+#ifdef TLS
+char *partner_fqdn = 0;
+#define PORT_SMTPS 465
+#endif
 
 void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
 void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
@@ -107,9 +130,58 @@
 int smtpfd;
 int timeout = 1200;
 
+#ifdef TLS
+
+#include <sys/stat.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include "ssl_timeoutio.h"
+
+SSL *ssl = NULL;
+
+stralloc tlsclientciphers = {0};
+
+void ssl_shutdie()
+{
+  SSL_shutdown(ssl);
+  SSL_free(ssl);
+  zerodie();
+}
+void ssl_zerodie()
+{
+  char buf[1024];
+  SSL_load_error_strings();
+  out(ERR_error_string(ERR_get_error(), buf));
+  out("\n");
+  ssl_shutdie();
+}
+
+static int client_cert_cb(SSL *s,X509 **x509, EVP_PKEY **pkey)
+{
+  out("ZTLS found no client cert in control/clientcert.pem\n");
+  ssl_shutdie();
+  return 0; /* isn't reached but... */
+}
+
+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
+  if (ssl) {
+    r = ssl_timeoutread(timeout,smtpfd,smtpfd,ssl,buf,len);
+    if (r == -2) {
+      out("ZTLS connection to "); outhost(); out(" died: ");
+      ssl_zerodie();
+    }
+  } else
+#endif
   r = timeoutread(timeout,smtpfd,buf,len);
   if (r <= 0) dropped();
   return r;
@@ -117,6 +189,15 @@
 int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
   int r;
+#ifdef TLS
+  if (ssl) {
+    r = ssl_timeoutwrite(timeout,smtpfd,smtpfd,ssl,buf,len);
+    if (r == -2) {
+      out("ZTLS connection to "); outhost(); out(" died: ");
+      ssl_zerodie();
+    }
+  } else
+#endif 
   r = timeoutwrite(timeout,smtpfd,buf,len);
   if (r <= 0) dropped();
   return r;
@@ -186,6 +267,36 @@
   out(append);
   out(".\n");
   outsmtptext();
+
+/* TAG */
+#ifdef TLS
+  if (ssl) {
+# ifdef DEBUG
+    X509 *peercert;
+
+    out("STARTTLS proto="); out(SSL_get_version(ssl));
+    out("; cipher="); out(SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
+
+    /* we want certificate details */
+    if (peercert = SSL_get_peer_certificate(ssl)) {
+      char *str;
+
+      str = X509_NAME_oneline(X509_get_subject_name(peercert),NULL,0);
+      out("; subject="); out(str);
+      OPENSSL_free(str);
+
+      str = X509_NAME_oneline(X509_get_issuer_name(peercert),NULL,0);
+      out("; issuer="); out(str);
+      OPENSSL_free(str);
+
+      X509_free(peercert);
+    }
+    out(";\n");
+# endif
+    ssl_shutdie();
+  } else
+#endif
+
   zerodie();
 }
 
@@ -216,24 +327,223 @@
 
 stralloc recip = {0};
 
+void mail_without_auth()
+{
+  substdio_puts(&smtpto,"MAIL FROM:<");
+  substdio_put(&smtpto,sender.s,sender.len);
+  substdio_puts(&smtpto,">\r\n");
+  substdio_flush(&smtpto);
+}
+
 void smtp()
 {
   unsigned long code;
   int flagbother;
-  int i;
+  int i, j;
+#ifdef TLS
+  char *starttls;
+  char *servercert = 0;
+  struct stat st;
+  /* ifdef PORT_SMTP to go along with qmtp patch */
+#ifdef PORT_SMTP
+  int smtps = (PORT_SMTPS == port);
+#else
+  int smtps = (PORT_SMTPS == smtp_port);
+#endif
+
+  if (smtps)
+    starttls = "";
+  else {
+#endif
  
   if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
  
+#ifdef TLS
+    substdio_puts(&smtpto,"EHLO ");
+    substdio_put(&smtpto,helohost.s,helohost.len);
+    substdio_puts(&smtpto,"\r\n");
+    substdio_flush(&smtpto);
+    if (smtpcode() != 250) {
+#endif
+
   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");
  
-  substdio_puts(&smtpto,"MAIL FROM:<");
-  substdio_put(&smtpto,sender.s,sender.len);
-  substdio_puts(&smtpto,">\r\n");
-  substdio_flush(&smtpto);
+#ifdef TLS
+    } else {
+      starttls = smtptext.s + 4; /* skipping "250 " */
+      do {
+        starttls += str_chr(starttls, '\n') + 5;
+        if (starttls + 9 > smtptext.s + smtptext.len) { starttls = 0; break; }
+      } while (str_diffn(starttls,"STARTTLS\n",9));
+
+      if (starttls) { /* found STARTTLS */
+        substdio_puts(&smtpto,"STARTTLS\r\n");
+        substdio_flush(&smtpto);
+        if (smtpcode() != 220) starttls = 0;
+      }
+    }
+  }
+
+  if (partner_fqdn) {
+    stralloc tmp = {0};
+    if (!stralloc_copys(&tmp, "control/tlshosts/")) temp_nomem();
+    if (!stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn))) temp_nomem();
+    if (!stralloc_catb(&tmp, ".pem", 4)) temp_nomem();
+    if (!stralloc_0(&tmp)) temp_nomem();
+    if (stat(tmp.s,&st)) /* no such file */
+      alloc_free(tmp.s);
+    else if (starttls)
+      servercert = tmp.s;
+    else {
+      out("ZNo TLS achieved while "); out(tmp.s); out(" exists.\n");
+      quit();
+    }
+  }
+ 
+  if (starttls) {
+    SSL_CTX *ctx;
+
+    SSL_library_init();
+    if (!(ctx = SSL_CTX_new(SSLv23_client_method()))) {
+      out("ZTLS not available: error initializing ctx: ");
+      ssl_zerodie();
+    }
+    /* 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 */
+    if (stat("control/clientcert.pem",&st) == 0)
+      if (
+        1 != SSL_CTX_use_RSAPrivateKey_file(ctx,
+          "control/clientcert.pem",SSL_FILETYPE_PEM) ||
+        1 != SSL_CTX_use_certificate_chain_file(ctx,"control/clientcert.pem") ||
+        1 != SSL_CTX_check_private_key(ctx)
+      )
+        SSL_CTX_set_client_cert_cb(ctx, client_cert_cb);
+
+    if (servercert && !SSL_CTX_load_verify_locations(ctx,servercert,NULL)) {
+      out("ZTLS unable to load "); out(servercert); out("\n");
+      zerodie();
+    }
+
+    if (!(ssl = SSL_new(ctx))) {
+      out("ZTLS not available: error initializing ssl: "); 
+      ssl_zerodie();
+    }
+    SSL_CTX_free(ctx);
+    if (servercert) SSL_set_verify(ssl,SSL_VERIFY_PEER,verify_cb);
+    /*SSL_set_options(ssl, SSL_OP_NO_TLSv1);*/
+    SSL_set_cipher_list(ssl,tlsclientciphers.s);
+    SSL_set_fd(ssl,smtpfd);
+
+    if (ssl_timeoutconn(timeout,smtpfd,smtpfd,ssl) <= 0) {
+      out("ZTLS not available: connect ");
+      if (errno == error_timeout)
+        { out("timed out\n"); ssl_shutdie(); }
+      else
+        { out("failed: "); ssl_zerodie(); }
+    }
+    if (servercert) {
+      /* should also check alternate names */
+      char commonName[256];
+      X509 *peercert;
+      int r;
+
+      if ((r = SSL_get_verify_result(ssl)) != X509_V_OK) {
+        out("ZTLS unable to verify server with ");
+        out(servercert); out(": ");
+        out(X509_verify_cert_error_string(r)); out("\n");
+        ssl_shutdie();
+      }
+      alloc_free(servercert);
+
+      peercert = SSL_get_peer_certificate(ssl);
+      X509_NAME_get_text_by_NID(
+        X509_get_subject_name(peercert), NID_commonName, commonName, 256);
+      X509_free(peercert);
+
+      r = case_diffs(partner_fqdn,commonName);
+      /* we also match if the cert has commonName *.domainname */
+      /* instead, i would like an implementation of RFC2595, part2.4 */
+      if (r && commonName[0] == '*' && commonName[1] == '.') {
+        char *partner_domain = partner_fqdn + str_chr(partner_fqdn,'.');
+        if (*partner_domain) r = case_diffs(partner_domain+1,commonName+2);
+      }
+      if (r) {
+        out("ZTLS connection to "); out(partner_fqdn);
+        out(" wanted, certificate for "); out(commonName);
+        out(" received\n");
+        ssl_shutdie();
+      }
+    }
+
+    if (smtps) if (smtpcode() != 220)
+      quit("ZTLS Connected to "," but greeting failed");
+
+    /* RFC2487 says we should issue EHLO (even if we do not need extensions) */
+    /* at the same time, it does not prohibit a server to reject the EHLO */
+    /* and make us fallback to HELO */  
+    substdio_puts(&smtpto,"EHLO ");
+    substdio_put(&smtpto,helohost.s,helohost.len);
+    substdio_puts(&smtpto,"\r\n");
+    substdio_flush(&smtpto);
+
+    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("ZTLS connected to "," but my name was rejected");
+    }
+  }
+#endif
+
+  /* begin auth */
+
+  i = 0;
+  if (auth_smtp_user.len && auth_smtp_pass.len) {
+    while((i += str_chr(smtptext.s+i,'\n') + 1) &&
+         (i+8 < smtptext.len) &&
+         str_diffn(smtptext.s+i+4,"AUTH",4));
+    if (((i+9 < smtptext.len) &&
+        (str_diffn(smtptext.s+i+9," ",1) ||
+         str_diffn(smtptext.s+i+9,"=",1))) &&
+       ( i += str_chr(smtptext.s+i,'L') + 1 ) &&
+       str_diffn(smtptext.s+i+1,"OGIN",4)) {
+
+      if (b64encode(&auth_smtp_user,&auth_b64_user)) quit("ZConnected to "," but unable to base64encode user");
+      if (b64encode(&auth_smtp_pass,&auth_b64_pass)) quit("ZConnected to "," but unable to base64encode pass");
+
+      substdio_puts(&smtpto,"AUTH LOGIN\r\n");
+      substdio_flush(&smtpto);
+      if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (AUTH LOGIN)");
+      substdio_put(&smtpto,auth_b64_user.s,auth_b64_user.len);
+      substdio_puts(&smtpto,"\r\n");
+      substdio_flush(&smtpto);
+      if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (username)");
+      substdio_put(&smtpto,auth_b64_pass.s,auth_b64_pass.len);
+      substdio_puts(&smtpto,"\r\n");
+      substdio_flush(&smtpto);
+      if (smtpcode() != 235) quit("ZConnected to "," but authentication was rejected (password)");
+      substdio_puts(&smtpto,"MAIL FROM:<");
+      substdio_put(&smtpto,sender.s,sender.len);
+      substdio_puts(&smtpto,"> AUTH=<");
+      substdio_put(&smtpto,sender.s,sender.len);
+      substdio_puts(&smtpto,">\r\n");
+      substdio_flush(&smtpto);
+    }
+    else {
+      mail_without_auth();
+    }
+  }
+  else {
+    mail_without_auth();
+  }
+  /* end auth */
+
   code = smtpcode();
   if (code >= 500) quit("DConnected to "," but sender was rejected");
   if (code >= 400) quit("ZConnected to "," but sender was rejected");
@@ -324,6 +634,24 @@
     case 1:
       if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
   }
+#ifdef TLS
+  if (1 !=
+    control_rldef(&tlsclientciphers, "control/tlsclientciphers",0,"DEFAULT")
+  ) temp_control();
+  if (!stralloc_0(&tlsclientciphers)) temp_nomem();
+#endif
+
+  /* start auth */
+  switch(control_readfile(&routes_users,"control/smtproutes_users",0)) {
+    case -1:
+       temp_control();
+    case 0:
+      if (!constmap_init(&maproutes_users,"",0,1)) temp_nomem(); break;
+    case 1:
+      if (!constmap_init(&maproutes_users,routes_users.s,routes_users.len,1)) temp_nomem(); break;
+  }
+  /* end auth */
+
 }
 
 void main(argc,argv)
@@ -331,14 +659,15 @@
 char **argv;
 {
   static ipalloc ip = {0};
-  int i;
+  int i, j;
   unsigned long random;
   char **recips;
   unsigned long prefme;
   int flagallaliases;
   int flagalias;
   char *relayhost;
- 
+  char *relayuser;
+
   sig_pipeignore();
   if (argc < 4) perm_usage();
   if (chdir(auto_qmail) == -1) temp_chdir();
@@ -346,25 +675,67 @@
  
  
   if (!stralloc_copys(&host,argv[1])) temp_nomem();
- 
+  if (!stralloc_copys(&auth_smtp_user,"")) temp_nomem();
+  if (!stralloc_copys(&auth_smtp_pass,"")) temp_nomem();
+
+  addrmangle(&sender,argv[2],&flagalias,0);
+
+  relayuser = 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))
+
+  /* begin auth */
+
+  for (i = 0;i <= sender.len;++i)
+    if ((i == 0) || (i == sender.len) || (sender.s[i] == '.'))
+      if (relayuser = constmap(&maproutes_users,sender.s + i,sender.len - i))
         break;
-  if (relayhost && !*relayhost) relayhost = 0;
- 
-  if (relayhost) {
-    i = str_chr(relayhost,':');
-    if (relayhost[i]) {
-      scan_ulong(relayhost + i + 1,&port);
+
+  if (relayuser && !*relayuser) relayuser = 0;
+
+  i = 0;
+  if (relayuser) {
+    i = str_chr(relayuser,'|');
+    if (relayuser[i]) {
+      j = str_chr(relayuser + i + 1,'|');
+
+      if (relayuser[j]) {
+       relayuser[i] = 0;
+       relayuser[i + j + 1] = 0;
+       if (!stralloc_copys(&auth_smtp_user,relayuser + i + 1)) temp_nomem();
+       if (!stralloc_copys(&auth_smtp_pass,relayuser + i + j + 2)) temp_nomem();
+      }
+    }
+
+    i = str_chr(relayuser,':');
+    if (relayuser[i]) {
+      scan_ulong(relayuser + i + 1,&port);
       relayhost[i] = 0;
     }
-    if (!stralloc_copys(&host,relayhost)) temp_nomem();
+
+    if (!stralloc_copys(&relayhost,relayuser)) temp_nomem();
+    if (!stralloc_copys(&host,relayuser)) temp_nomem();
   }
 
+  if (!relayuser) {
+    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;
 
-  addrmangle(&sender,argv[2],&flagalias,0);
+    if (relayhost && !*relayhost) relayhost = 0;
+
+    if (relayhost) {
+       i = str_chr(relayhost,':');
+       if (relayhost[i]) {
+           scan_ulong(relayhost + i + 1,&port);
+           relayhost[i] = 0;
+       }
+
+       if (!stralloc_copys(&host,relayhost)) temp_nomem();
+    }
+
+  }
+  /* end auth */
  
   if (!saa_readyplus(&reciplist,0)) temp_nomem();
   if (ipme_init() != 1) temp_oserr();
@@ -417,6 +788,10 @@
     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
+      partner_fqdn = ip.ix[i].fqdn;
+#endif
+
       smtp(); /* does not return */
     }
     tcpto_err(&ip.ix[i].ip,errno == error_timeout);
diff -durN qmail-1.03.orig/ssl_timeoutio.c qmail-1.03/ssl_timeoutio.c
--- qmail-1.03.orig/ssl_timeoutio.c	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/ssl_timeoutio.c	Fri Sep 13 11:01:47 2002
@@ -0,0 +1,244 @@
+#include "select.h"
+#include "error.h"
+#include "ndelay.h"
+#include <openssl/ssl.h>
+
+int ssl_timeoutaccept(t,rfd,wfd,ssl) long t; int rfd; int wfd; SSL *ssl;
+{
+  int r;
+  int n = rfd + 1;
+  int maxfd = (rfd > wfd ? rfd : wfd) + 1;
+
+  fd_set rfds, wfds;
+  fd_set *pwfds = (fd_set *) 0;
+  struct timeval tv;
+  long end = t + time((long *) 0);
+
+  /* if connection is established, keep it that way */
+  if (ndelay_on(rfd) == -1) return -1;
+  if (ndelay_on(wfd) == -1) return -1;
+
+  tv.tv_sec = t;
+  tv.tv_usec = 0;
+
+  FD_ZERO(&rfds);
+  FD_SET(rfd,&rfds);
+
+  /* number of descriptors that changes status */
+  while (0 < (n = select(n,&rfds,pwfds,(fd_set *) 0,&tv)))
+  {
+    r = SSL_accept(ssl);
+    if (r > 0) {
+      SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+      return r;
+    }
+
+    switch (SSL_get_error(ssl, r))
+    {
+    case SSL_ERROR_WANT_READ:
+      pwfds = (fd_set *) 0;
+      n = rfd + 1;
+      break;
+    case SSL_ERROR_WANT_WRITE:
+      pwfds = &wfds;
+      FD_ZERO(&wfds);
+      FD_SET(wfd,&wfds);
+      n = maxfd;
+      break;
+    default:
+      /* some other error */
+      ndelay_off(rfd);
+      ndelay_off(wfd);
+      return -2;
+    }
+
+    if ((t = end - time((long *)0)) < 0) break;
+
+    tv.tv_sec = t;
+    tv.tv_usec = 0;
+
+    FD_ZERO(&rfds);
+    FD_SET(rfd,&rfds);
+  }
+
+  ndelay_off(rfd);
+  ndelay_off(wfd);
+  if (n != -1) errno = error_timeout;
+  return -1;
+}
+
+int ssl_timeoutconn(t,rfd,wfd,ssl) long t; int rfd; int wfd; SSL *ssl;
+{
+  int r;
+  int n = wfd + 1;
+  int maxfd = (rfd > wfd ? rfd : wfd) + 1;
+
+  fd_set rfds, wfds;
+  fd_set *prfds = (fd_set *) 0;
+  struct timeval tv;
+  long end = t + time((long *) 0);
+
+  /* if connection is established, keep it that way */
+  if (ndelay_on(rfd) == -1) return -1;
+  if (ndelay_on(wfd) == -1) return -1;
+
+  tv.tv_sec = t;
+  tv.tv_usec = 0;
+
+  FD_ZERO(&wfds);
+  FD_SET(wfd,&wfds);
+
+  /* number of descriptors that changes status */
+  while (0 < (n = select(n,prfds,&wfds,(fd_set *) 0,&tv)))
+  {
+    r = SSL_connect(ssl);
+    if (r > 0) {
+      SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+      return r;
+    }
+
+    switch (SSL_get_error(ssl, r))
+    {
+    case SSL_ERROR_WANT_READ:
+      /* try again as SSL_write() might be re-negotiating */
+      prfds = &rfds;
+      FD_ZERO(&rfds);
+      FD_SET(rfd,&rfds);
+      n = maxfd;
+      break;
+    case SSL_ERROR_WANT_WRITE:
+      /* try again as network write operation would block */
+      prfds = (fd_set *) 0;
+      n = wfd + 1;
+      break;
+    default:
+      /* some other error */
+      ndelay_off(rfd);
+      ndelay_off(wfd);
+      return -2;
+    }
+
+    if ((t = end - time((long *)0)) < 0) break;
+
+    tv.tv_sec = t;
+    tv.tv_usec = 0;
+
+    FD_ZERO(&wfds);
+    FD_SET(wfd,&wfds);
+  }
+
+  ndelay_off(rfd);
+  ndelay_off(wfd);
+  if (n != -1) errno = error_timeout;
+  return -1;
+}
+
+int ssl_timeoutread(t,rfd,wfd,ssl,buf,len)
+long t; int rfd; int wfd; SSL *ssl; char *buf; int len;
+{
+  int r, n, maxfd;
+  fd_set rfds, wfds;
+  fd_set *pwfds = (fd_set *) 0;
+  struct timeval tv;
+  long end;
+
+  if (SSL_pending(ssl))
+    return SSL_read(ssl,buf,len);
+
+  n = rfd + 1;
+  maxfd = (rfd > wfd ? rfd : wfd) + 1;
+  end = t + time((long *)0);
+
+  do {
+    tv.tv_sec = t;
+    tv.tv_usec = 0;
+
+    FD_ZERO(&rfds);
+    FD_SET(rfd,&rfds);
+
+    n = select(n,&rfds,pwfds,(fd_set *) 0,&tv);
+    if (n == -1) return -1;
+    if (n == 0) break; /* timed out */
+
+    r = SSL_read(ssl,buf,len);
+    if (r > 0) return r;
+
+    switch (SSL_get_error(ssl, r))
+    {
+    case SSL_ERROR_WANT_READ:
+      /* try again as an incomplete record has been read */
+      pwfds = (fd_set *) 0;
+      n = rfd + 1;
+      break;
+    case SSL_ERROR_WANT_WRITE:
+      /* try again as SSL_read() might be re-negotiating */
+      pwfds = &wfds;
+      FD_ZERO(&wfds);
+      FD_SET(wfd,&wfds);
+      n = maxfd;
+      break;
+    default:
+      /* some other error */
+      return -2;
+    }
+  } while (0 < (t = end - time((long *)0)));
+
+  errno = error_timeout;
+  return -1;
+}
+
+int ssl_timeoutwrite(t,rfd,wfd,ssl,buf,len)
+long t; int rfd; int wfd; SSL* ssl; char *buf; int len;
+{
+  int r;
+  int n = wfd + 1;
+  int maxfd = (rfd > wfd ? rfd : wfd) + 1;
+
+  fd_set rfds, wfds;
+  fd_set *prfds = (fd_set *) 0;
+  struct timeval tv;
+  long end = t + time((long *) 0);
+
+  tv.tv_sec = t;
+  tv.tv_usec = 0;
+
+  FD_ZERO(&wfds);
+  FD_SET(wfd,&wfds);
+
+  /* number of descriptors that changes status */
+  while (0 < (n = select(n,prfds,&wfds,(fd_set *) 0,&tv)))
+  {
+    r = SSL_write(ssl,buf,len);
+    if (r > 0) return r;
+
+    switch (SSL_get_error(ssl, r))
+    {
+    case SSL_ERROR_WANT_READ:
+      /* try again as SSL_write() might be re-negotiating */
+      prfds = &rfds;
+      FD_ZERO(&rfds);
+      FD_SET(rfd,&rfds);
+      n = maxfd;
+      break;
+    case SSL_ERROR_WANT_WRITE:
+      /* try again as network write operation would block */
+      prfds = (fd_set *) 0;
+      n = wfd + 1;
+      break;
+    default:
+      /* some other error */
+      return -2;
+    }
+
+    if ((t = end - time((long *)0)) < 0) break;
+
+    tv.tv_sec = t;
+    tv.tv_usec = 0;
+
+    FD_ZERO(&wfds);
+    FD_SET(wfd,&wfds);
+  }
+
+  if (n != -1) errno = error_timeout;
+  return -1;
+}
diff -durN qmail-1.03.orig/ssl_timeoutio.h qmail-1.03/ssl_timeoutio.h
--- qmail-1.03.orig/ssl_timeoutio.h	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/ssl_timeoutio.h	Fri Sep 13 11:01:47 2002
@@ -0,0 +1,9 @@
+#ifndef SSL_TIMEOUTIO_H
+#define SSL_TIMEOUTIO_H
+
+extern int ssl_timeoutaccept();
+extern int ssl_timeoutconn();
+extern int ssl_timeoutread();
+extern int ssl_timeoutwrite();
+
+#endif
