ports/119954: mail/qmail-tls is broken. qmail-smtpd does not accept ssl connections if /var/qmail/control/tlsserverchiphers does not exist.

Luiz Otavio O Souza loos.br at gmail.com
Thu Jan 24 23:00:03 UTC 2008


>Number:         119954
>Category:       ports
>Synopsis:       mail/qmail-tls is broken. qmail-smtpd does not accept ssl connections if /var/qmail/control/tlsserverchiphers does not exist.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan 24 23:00:03 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Luiz Otavio O Souza
>Release:        FreeBSD 6.2-STABLE i386
>Organization:
>Environment:
System: FreeBSD fw.ad.com.br 6.2-STABLE FreeBSD 6.2-STABLE #2: Tue Dec 4 13:49:44 BRST 2007 root at fw.ad.com.br:/usr/src/sys/i386/compile/FW i386


	
>Description:

	mail/qmail-tls is broken. qmail-smtpd does not accept ssl connections if /var/qmail/control/tlsserverchiphers does not exist.
	This patch(es) also update qmail-tls to 20070408

>How-To-Repeat:

	remove /var/qmail/control/tlsserverchipers and try to connect to qmail-smtpd with openssl:
	openssl s_client -starttls smtp -crlf -connect localhost:25
	all connections are refused.

	i don't know if /var/qmail/control/tlsserverchipers is installed by default.
>Fix:

	Caution ! Warning ! This patch changes both mail/qmail and mail/qmail-tls !
	Caution ! Warning ! This patch has 2 files that need to be updated on respective master site (maintainer url)

--- qmail-tls-orig/Makefile	2007-12-26 14:43:55.000000000 -0200
+++ qmail-tls/Makefile	2008-01-24 20:18:43.000000000 -0200
@@ -7,7 +7,7 @@
 
 PORTNAME=	qmail
 PORTVERSION=	${QMAIL_VERSION}.${TLS_PATCH_DATE}
-PORTREVISION=	2
+PORTREVISION=
 CATEGORIES=	mail
 PKGNAMESUFFIX=	-tls
 
@@ -17,7 +17,7 @@
 
 SLAVE_TLS=	yes
 
-TLS_PATCH_DATE=	20021228
+TLS_PATCH_DATE=	20070408
 
 USE_OPENSSL=	yes
 
--- qmail-tls-orig/pkg-descr	2005-06-01 19:22:46.000000000 -0300
+++ qmail-tls/pkg-descr	2008-01-24 20:18:43.000000000 -0200
@@ -1,6 +1,6 @@
 What is is: [excerpt taken from tls patch]
 
-Frederik Vermeulen <qmail-tls at inoa.net> 20021228
+Frederik Vermeulen <qmail-tls at inoa.net> 20070408
 http://inoa.net/qmail/qmail-1.03-tls.patch
 
 This patch implements RFC2487 in qmail. This means you can
--- qmail-orig/distinfo	2007-09-05 17:47:45.000000000 -0300
+++ qmail/distinfo	2008-01-24 20:18:43.000000000 -0200
@@ -1,9 +1,27 @@
 MD5 (qmail/qmail-1.03.tar.gz) = 622f65f982e380dbe86e6574f3abcb7c
 SHA256 (qmail/qmail-1.03.tar.gz) = 21ed6c562cbb55092a66197c35c8222b84115d1acab0854fdb1ad1f301626f88
 SIZE (qmail/qmail-1.03.tar.gz) = 220668
+MD5 (qmail/qmail-smtpd-auth-0.31.tar.gz) = 6b202f71a99fb41e9e32906017270ba0
+SHA256 (qmail/qmail-smtpd-auth-0.31.tar.gz) = 1b439fa7e128de13fa80b86883f61a39d17b87b7e8916b6a0eab065bbe49b938
+SIZE (qmail/qmail-smtpd-auth-0.31.tar.gz) = 8798
+MD5 (qmail/qmail-smtpd-auth-close3.patch) = 0ba66d73dcba1c68ed714b07e47abd3e
+SHA256 (qmail/qmail-smtpd-auth-close3.patch) = d933e871261d6740cebe5c21cad81146525cfe06a464e277979f61c1242b5ad4
+SIZE (qmail/qmail-smtpd-auth-close3.patch) = 520
+MD5 (qmail/auth.patch.diff-tls) = c152ec1a6cf9c78d0aede6c212736f2f
+SHA256 (qmail/auth.patch.diff-tls) = ba875152d7b2e01d5e8a9b5d02719bc1a77c8f862cc3383cea778823d506f6d4
+SIZE (qmail/auth.patch.diff-tls) = 3389
 MD5 (qmail/qmail-103.patch) = 9140ad2b03017145cd7963c84bb24f16
 SHA256 (qmail/qmail-103.patch) = 4cad53c7a6628a600c74c36bfee327db5052ca24c222d4013e4dfcd7f427653d
 SIZE (qmail/qmail-103.patch) = 2104
+MD5 (qmail/sendmail-flagf.patch) = 4e1f2d8315e7e2a5482798c9d19fac4d
+SHA256 (qmail/sendmail-flagf.patch) = 9b3951c22b98c0e5a6ebfa793f052d91dfe01d68a0ad8dc83b8e0bd60c01802e
+SIZE (qmail/sendmail-flagf.patch) = 863
+MD5 (qmail/qmail-1.03-tls-20070408-renato.patch) = 77a74dc9c771e25e026b8dd8c42e0063
+SHA256 (qmail/qmail-1.03-tls-20070408-renato.patch) = 7a6289f4748d31a58bfdaf37018117fbbb6731652e59387c13facc9752801b2b
+SIZE (qmail/qmail-1.03-tls-20070408-renato.patch) = 46613
+MD5 (qmail/qmail-discard-double-bounces.patch) = 55d45bb8d2c3822a0e3544058aa5a3a3
+SHA256 (qmail/qmail-discard-double-bounces.patch) = 14489eefd9908f60af13fadd574d0e9bb936e5d1b706690ce52efef68529a8d8
+SIZE (qmail/qmail-discard-double-bounces.patch) = 1305
 MD5 (qmail/qmailqueue-patch) = 5a8d7a5863b0c56236af945dedd45754
 SHA256 (qmail/qmailqueue-patch) = 52e82aaa34e9f1308b063cc986a701f67e161662e9f789bb12af03a381530f94
 SIZE (qmail/qmailqueue-patch) = 2510
@@ -13,94 +31,3 @@
 MD5 (qmail/big-concurrency.patch) = 2ff58c3570870a8ff9a1d9eb9aec05a6
 SHA256 (qmail/big-concurrency.patch) = 0322991955878e86af495f7317c3a4bd2e60640f9a6dd70ad501fff27242ac2f
 SIZE (qmail/big-concurrency.patch) = 9331
-MD5 (qmail/sendmail-flagf.patch) = 4e1f2d8315e7e2a5482798c9d19fac4d
-SHA256 (qmail/sendmail-flagf.patch) = 9b3951c22b98c0e5a6ebfa793f052d91dfe01d68a0ad8dc83b8e0bd60c01802e
-SIZE (qmail/sendmail-flagf.patch) = 863
-MD5 (qmail/patch-qmail-1.03-rfc2821.diff) = 1b85f233ab5b9d7ec1a8da1188bf10ef
-SHA256 (qmail/patch-qmail-1.03-rfc2821.diff) = c34b331e27882f0596529df14f0e9f24c4dff9f941d04e5df17cc158dddac426
-SIZE (qmail/patch-qmail-1.03-rfc2821.diff) = 2564
-MD5 (qmail/qmail-date-localtime.patch) = d566e8bd99b33efee0194e855b8d6995
-SHA256 (qmail/qmail-date-localtime.patch) = 852aee7577edf8814c2429f82740da2a7e0b0b23516e10c4f3f7e845a47be2d5
-SIZE (qmail/qmail-date-localtime.patch) = 2603
-MD5 (qmail/qmail-1.03-qmtpc.patch) = 122664c38338e5ec35fcac43f33d6927
-SHA256 (qmail/qmail-1.03-qmtpc.patch) = f704b6c0ca3515a4bb488d14f7c94910aba4daa87420db6cd5b7ea19f17f7449
-SIZE (qmail/qmail-1.03-qmtpc.patch) = 6197
-MD5 (qmail/outgoingip.patch) = 3c9277dcf5f9b4b6d3a270fb3abf7994
-SHA256 (qmail/outgoingip.patch) = c117f5c41033f062cdc782a16403fc19725e98d92e73ab193dfd24f48c0ca5ac
-SIZE (qmail/outgoingip.patch) = 6839
-MD5 (qmail/outgoingip.patch-spamcontrol) = ed3ca1e309116647e9adb0a49194e2e5
-SHA256 (qmail/outgoingip.patch-spamcontrol) = 721f5a1199867a26e69773608b07ec54fce1444cfa0679906592b60b7dd68abe
-SIZE (qmail/outgoingip.patch-spamcontrol) = 6769
-MD5 (qmail/qmail-1.03-qmtpc_outgoingip.patch) = 4b2623cbd9e9a4f137f7b16f78a43975
-SHA256 (qmail/qmail-1.03-qmtpc_outgoingip.patch) = d8dc66a5057b5ffbab4a9e0a27a6392b1f29d3c6aadea1f13f2290918846e89c
-SIZE (qmail/qmail-1.03-qmtpc_outgoingip.patch) = 10357
-MD5 (qmail/qmail-maildir++.patch) = fd92b624ac1129a656eb1e567d1f0409
-SHA256 (qmail/qmail-maildir++.patch) = 79e3f1f8f95b58b6d17e5469f125d873fe212d0a5a6d19b538ad57176fbafb52
-SIZE (qmail/qmail-maildir++.patch) = 38088
-MD5 (qmail/qmail-block-executables.patch) = e425b420e5251b4882fc699f7822f7a0
-SHA256 (qmail/qmail-block-executables.patch) = 97512624eb02db51e10ab6d0dd834a8797a238d0e006bd1c6c94a183d291b456
-SIZE (qmail/qmail-block-executables.patch) = 5070
-MD5 (qmail/qmail-discard-double-bounces.patch) = 55d45bb8d2c3822a0e3544058aa5a3a3
-SHA256 (qmail/qmail-discard-double-bounces.patch) = 14489eefd9908f60af13fadd574d0e9bb936e5d1b706690ce52efef68529a8d8
-SIZE (qmail/qmail-discard-double-bounces.patch) = 1305
-MD5 (qmail/qmail-spf-rc5.patch) = 434bd84b87e2027cfa643673c498bd6f
-SHA256 (qmail/qmail-spf-rc5.patch) = 8ad251d779125e11422ae9bcbf619b0ba002c0893dd8c8fe55a34a8b5fc42640
-SIZE (qmail/qmail-spf-rc5.patch) = 63582
-MD5 (qmail/qmail-spf-rc5.patch-tls) = db126b4ac29ad83c1c219e5323cef452
-SHA256 (qmail/qmail-spf-rc5.patch-tls) = c884665ff0bc5a5272efe3e09aed71e648a79d0279bc708d5a9df25c5758804f
-SIZE (qmail/qmail-spf-rc5.patch-tls) = 63617
-MD5 (qmail/qmail-spf-rc5.patch-auth-tls) = 262e381adc967df0a8ab4f15f2f6fe8f
-SHA256 (qmail/qmail-spf-rc5.patch-auth-tls) = 16fe99894938c30ed1928a61dabf0a598ef7e08a766a76cf084fe658d6d50092
-SIZE (qmail/qmail-spf-rc5.patch-auth-tls) = 63752
-MD5 (qmail/qmail-ldap-1.03-20060201.patch.gz) = 55fa135415ee011f3f4234d7d52a3565
-SHA256 (qmail/qmail-ldap-1.03-20060201.patch.gz) = 92ba895df1957109ad856cc1d1554ece4d25d59017e77127dd52d76afd05525a
-SIZE (qmail/qmail-ldap-1.03-20060201.patch.gz) = 270788
-MD5 (qmail/qmail-mysql-1.1.15.patch) = c0298550475f928e82881e574e905313
-SHA256 (qmail/qmail-mysql-1.1.15.patch) = 3d2b6a08fb149d6c9fe6c8250e87edd6c4d4b2b0417f03adf5cf4202bbadc53f
-SIZE (qmail/qmail-mysql-1.1.15.patch) = 67602
-MD5 (qmail/spamcontrol-2418_tgz.bin) = a5502cd69e573a2753e532bce8fb6c3a
-SHA256 (qmail/spamcontrol-2418_tgz.bin) = e9874f9961707cd15e135269796fbec7a2d417b18124d802a352d65b76e22d85
-SIZE (qmail/spamcontrol-2418_tgz.bin) = 124059
-MD5 (qmail/qmail-spf-rc5.patch-spamcontrol) = c7da17aa55896eae8c525d05c65387fd
-MD5 (qmail/qmail-1.03-tls-20021228-renato.patch) = be15cd5eaff7aa3cd88aee962febadc6
-SHA256 (qmail/qmail-1.03-tls-20021228-renato.patch) = ab0de8f744241dcb7f5ee207fc7eab4f067bf42812deb85f9eb0050ac49e6e23
-SIZE (qmail/qmail-1.03-tls-20021228-renato.patch) = 42095
-MD5 (qmail/qmail-smtpd-auth-0.31.tar.gz) = 6b202f71a99fb41e9e32906017270ba0
-SHA256 (qmail/qmail-smtpd-auth-0.31.tar.gz) = 1b439fa7e128de13fa80b86883f61a39d17b87b7e8916b6a0eab065bbe49b938
-SIZE (qmail/qmail-smtpd-auth-0.31.tar.gz) = 8798
-MD5 (qmail/qmail-smtpd-auth-close3.patch) = 0ba66d73dcba1c68ed714b07e47abd3e
-SHA256 (qmail/qmail-smtpd-auth-close3.patch) = d933e871261d6740cebe5c21cad81146525cfe06a464e277979f61c1242b5ad4
-SIZE (qmail/qmail-smtpd-auth-close3.patch) = 520
-MD5 (qmail/tarpit.patch) = 49a2c0a445981deb09f3af73041d75f5
-SHA256 (qmail/tarpit.patch) = de94abbb71ef5d25e168725e435edd96ce3b14b7347440e0805dcb919b9d9604
-SIZE (qmail/tarpit.patch) = 3089
-MD5 (qmail/ext_todo-20030105.patch) = 99070bb55cac5ad61f8fb203422e651e
-SHA256 (qmail/ext_todo-20030105.patch) = d46d0225360c0477f93e2990637ebf912b2a86e494f424ef2952ee11ab533ac7
-SIZE (qmail/ext_todo-20030105.patch) = 33763
-MD5 (qmail/ext_todo-20030105_spf.patch) = 4d760732c92c01bd14d9957257ca4c1a
-SHA256 (qmail/ext_todo-20030105_spf.patch) = 544629c0003d01d27a5a45508e84332f247ed54ece57ff22c0c7c3a56ba086d6
-SIZE (qmail/ext_todo-20030105_spf.patch) = 33781
-MD5 (qmail/ext_todo-20030105_mysql.patch) = ecddff9ba6d725ec3be61843bc8007a7
-SHA256 (qmail/ext_todo-20030105_mysql.patch) = 3fc65b91faaaae147dbf6264f9381664819ef2f236532764309d174f29919ff1
-SIZE (qmail/ext_todo-20030105_mysql.patch) = 33797
-MD5 (qmail/qmail-spf-rc5.patch-spamcontrol) = c7da17aa55896eae8c525d05c65387fd
-SHA256 (qmail/qmail-spf-rc5.patch-spamcontrol) = 52a3e4a6c8ae0124be280b6c0d183d81f4a6bd10c23fc735d99f4f731d4f5c6d
-SIZE (qmail/qmail-spf-rc5.patch-spamcontrol) = 64214
-MD5 (qmail/auth.patch.diff) = 23e0509061cd5dda4a1abf9a7cb7596d
-SHA256 (qmail/auth.patch.diff) = 1d0f8e0ce139cd00b86f056bc31c1422d30b88cb8b125023d534cc3664f827b8
-SIZE (qmail/auth.patch.diff) = 4412
-MD5 (qmail/auth.patch.diff-tls) = 7e706dd124deb9a25cecd91fe652a90b
-SHA256 (qmail/auth.patch.diff-tls) = 467c5f68d5d332d2400f937c76311e5358b613923d64e68ae98d51d178c7de5e
-SIZE (qmail/auth.patch.diff-tls) = 2993
-MD5 (qmail/ext_todo-20030105+big-todo.103.patch) = 5878870ef85d6a83ba9465ce94d9cd42
-SHA256 (qmail/ext_todo-20030105+big-todo.103.patch) = 4e44ad403b21f5910b6af11295b82296bc8c0f18bc40dcfecfb95c11e5a296f7
-SIZE (qmail/ext_todo-20030105+big-todo.103.patch) = 2523
-MD5 (qmail/smtpextfork-ldap-20060201.patch) = a359bf9aa2a2799e4ab0fb9cc2dd6593
-SHA256 (qmail/smtpextfork-ldap-20060201.patch) = 554eb7879d26bb5a3f3dd671e91abc803a53d5ba2fee397ab248b52917ff2ffc
-SIZE (qmail/smtpextfork-ldap-20060201.patch) = 6715
-MD5 (qmail/smtpextfork-spamcontrol-2418_1.patch) = af5b96daaa2021e03712ada45e3b523c
-SHA256 (qmail/smtpextfork-spamcontrol-2418_1.patch) = 59c03c8ec28aa32c7869b3b63d9d760712f983fc5b8d9723fddbdb9e95c9f650
-SIZE (qmail/smtpextfork-spamcontrol-2418_1.patch) = 7609
-MD5 (qmail/README.smtpextfork) = e783965f5a7510c38b30f0ba3cda1e11
-SHA256 (qmail/README.smtpextfork) = c43122d27d4e20dd955c30ca402903d2e9a6a1820c3cf11902e2477316abdcbb
-SIZE (qmail/README.smtpextfork) = 7618
--- /usr/ports/distfiles/qmail/qmail-1.03-tls-20070408-renato.patch.orig	2008-01-24 20:35:28.000000000 -0200
+++ /usr/ports/distfiles/qmail/qmail-1.03-tls-20070408-renato.patch	2008-01-24 18:19:51.000000000 -0200
@@ -0,0 +1,1525 @@
+Frederik Vermeulen <qmail-tls akrul inoa.net> 20070408
+http://inoa.net/qmail-tls/
+
+This patch implements RFC 3207 (was RFC 2487) in qmail. 
+This means you can get SSL or TLS encrypted and 
+authenticated SMTP between the MTAs and from MUA to MTA. 
+The code is considered experimental (but has worked for
+many since its first release on 1999-03-21).
+
+Usage: - install OpenSSL-0.9.8 http://www.openssl.org/
+         (any 0.9.6 to 0.9.8 version is presumed to work)
+       - apply patch to netqmail-1.05 http://qmail.org/netqmail
+         (should work on qmail-1.03 too).  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 (DHE-RSA-AES256-SHA encrypted) SMTP;")
+         If you don't have a server to test with, you can test
+         by sending mail to tag-ping at 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). 
+          - when a 512 bit RSA key is provided in /var/qmail/control/rsa512.pem,
+            this key will be used instead of (slow) on-the-fly generation by
+       	    qmail-smtpd. Idem for 512 and 1024 DH params in control/dh512.pem
+            and control/dh1024.pem. `make tmprsadh` does this.
+            Periodical replacement can be done by crontab:
+       	    01 01 * * * /var/qmail/bin/update_tmprsadh > /dev/null 2>&1
+          - 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.
+            One of the dNSName or the CommonName attributes have to match.
+            WARNING: this option may cause mail to be delayed, bounced,
+            doublebounced, and lost.
+            If /var/qmail/control/tlshosts/exhaustivelist is present,
+            the lists of hosts in /var/qmail/control/tlshosts is
+            an exhaustive list of hosts TLS is tried on.
+            If /var/qmail/control/notlshosts/host.dom.ain is present,
+            no TLS is tried on this host.
+          - client authentication:
+            when relay rules would reject an incoming mail, 
+            qmail-smtpd can allow the mail based on a presented cert.
+            Certs are verified against a CA list in 
+            /var/qmail/control/clientca.pem (eg. http://www.modssl.org/
+            source/cvs/exp/mod_ssl/pkg.mod_ssl/pkg.sslcfg/ca-bundle.crt)
+            and the cert email-address has to match a line in
+            /var/qmail/control/tlsclients. This email-address is logged
+            in the headers. CRLs can be provided through 
+            /var/qmail/control/clientcrl.pem.
+          - cipher selection:
+            qmail-remote: 
+              openssl cipher string (`man ciphers`) read from 
+              /var/qmail/control/tlsclientciphers
+            qmail-smtpd: 
+              openssl cipher string read from TLSCIPHERS environment variable
+              (can vary based on client IP address e.g.)
+              or if that is not available /var/qmail/control/tlsserverciphers
+          - smtps (deprecated SMTP over TLS via port 465):
+            qmail-remote: when connecting to port 465 
+            qmail-smtpd: when SMTPS environment variable is not empty
+
+Caveats: - do a `make clean` after patching
+         - 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).
+         - 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 (or EGD for openssl versions >0.9.7)
+           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 and first part of this patch
+           will fail. This error can be ignored. Packagers should
+           cut the first 12 lines of this patch to make a happy
+           patch
+         - `make tmprsadh` is recommended (or should I say required), 
+           otherwise DH generation can be unpredictably slow
+         - some need "-I/usr/kerberos/include" to be added in conf-cc
+
+Copyright: GPL
+           Links with OpenSSL
+           Inspiration and code from examples in SSLeay (E. Young
+           <eay at cryptsoft.com> and T. Hudson <tjh at cryptsoft.com>),
+           stunnel (M. Trojnara <mtrojnar at ddc.daewoo.com.pl>),
+           Postfix/TLS (L. Jaenicke <Lutz.Jaenicke at aet.tu-cottbus.de>),
+           modssl (R. Engelschall <rse at engelschall.com>),
+           openssl examples of E. Rescorla <ekr at rtfm.com>.
+
+Bug reports: mailto:<qmail-tls akrul inoa.net>
+
+
+--- qmail-1.03-orig/Makefile-cert.mk	1969-12-31 21:00:00.000000000 -0300
++++ qmail-1.03/Makefile-cert.mk	2008-01-24 14:34:28.000000000 -0200
+@@ -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 `head -2 conf-users | tail -1`:`head -1 conf-groups` $@
++
++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 `head -2 conf-users | tail -1`:`head -1 conf-groups` 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"
+--- qmail-1.03-orig/TARGETS	2008-01-24 15:54:07.000000000 -0200
++++ qmail-1.03/TARGETS	2008-01-24 14:36:13.000000000 -0200
+@@ -168,6 +168,8 @@
+ constmap.o
+ timeoutread.o
+ timeoutwrite.o
++tls.o
++ssl_timeoutio.o
+ timeoutconn.o
+ tcpto.o
+ dns.o
+@@ -321,6 +323,7 @@
+ binm2+df
+ binm3
+ binm3+df
++Makefile-cert
+ it
+ qmail-local.0
+ qmail-lspawn.0
+@@ -386,3 +389,4 @@
+ man
+ setup
+ check
++update_tmprsadh
+--- qmail-1.03-orig/conf-cc	2008-01-24 15:54:08.000000000 -0200
++++ qmail-1.03/conf-cc	2008-01-24 14:27:50.000000000 -0200
+@@ -1 +1 @@
+-cc -O2 
++cc -O2 -pipe -DTLS=20070408 -I/usr/local/ssl/include
+--- qmail-1.03-orig/dns.c	2008-01-24 15:54:11.000000000 -0200
++++ qmail-1.03/dns.c	2008-01-24 14:27:50.000000000 -0200
+@@ -286,12 +286,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;
+@@ -310,9 +309,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;
+ }
+ 
+@@ -332,7 +338,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;
+@@ -344,7 +350,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;
+--- qmail-1.03-orig/hier.c	2008-01-24 15:54:09.000000000 -0200
++++ qmail-1.03/hier.c	2008-01-24 14:37:02.000000000 -0200
+@@ -102,6 +102,9 @@
+   c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755);
++#ifdef TLS
++  c(auto_qmail,"bin","update_tmprsadh",auto_uido,auto_gidq,0755);
++#endif
+ 
+ 
+ 
+--- qmail-1.03-orig/ipalloc.h	2008-01-24 15:54:11.000000000 -0200
++++ qmail-1.03/ipalloc.h	2008-01-24 14:27:50.000000000 -0200
+@@ -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"
+ 
+--- qmail-1.03-orig/qmail-control.9	2008-01-24 15:54:07.000000000 -0200
++++ qmail-1.03/qmail-control.9	2008-01-24 14:38:13.000000000 -0200
+@@ -43,11 +43,15 @@
+ .I badmailfrom	\fR(none)	\fRqmail-smtpd
+ .I bouncefrom	\fRMAILER-DAEMON	\fRqmail-send
+ .I bouncehost	\fIme	\fRqmail-send
++.I clientca.pem	\fR(none)	\fRqmail-smtpd
++.I clientcert.pem	\fR(none)	\fRqmail-remote
+ .I concurrencylocal	\fR10	\fRqmail-send
+ .I concurrencyremote	\fR20	\fRqmail-send
+ .I defaultdomain	\fIme	\fRqmail-inject
+ .I defaulthost	\fIme	\fRqmail-inject
+ .I databytes	\fR0	\fRqmail-smtpd
++.I dh1024.pem	\fR(none)	\fRqmail-smtpd
++.I dh512.pem	\fR(none)	\fRqmail-smtpd
+ .I doublebouncehost	\fIme	\fRqmail-send
+ .I doublebounceto	\fRpostmaster	\fRqmail-send
+ .I envnoathost	\fIme	\fRqmail-send
+@@ -61,11 +65,17 @@
+ .I qmqpservers	\fR(none)	\fRqmail-qmqpc
+ .I queuelifetime	\fR604800	\fRqmail-send
+ .I rcpthosts	\fR(none)	\fRqmail-smtpd
++.I rsa512.pem	\fR(none)	\fRqmail-smtpd
++.I servercert.pem	\fR(none)	\fRqmail-smtpd
+ .I smtpgreeting	\fIme	\fRqmail-smtpd
+ .I smtproutes	\fR(none)	\fRqmail-remote
+ .I timeoutconnect	\fR60	\fRqmail-remote
+ .I timeoutremote	\fR1200	\fRqmail-remote
+ .I timeoutsmtpd	\fR1200	\fRqmail-smtpd
++.I tlsclients	\fR(none)	\fRqmail-smtpd
++.I tlsclientciphers	\fR(none)	\fRqmail-remote
++.I tlshosts/FQDN.pem	\fR(none)	\fRqmail-remote
++.I tlsserverciphers	\fR(none)	\fRqmail-smtpd
+ .I virtualdomains	\fR(none)	\fRqmail-send
+ .fi
+ .RE
+--- qmail-1.03-orig/qmail-remote.8	2008-01-24 15:54:07.000000000 -0200
++++ qmail-1.03/qmail-remote.8	2008-01-24 15:02:04.000000000 -0200
+@@ -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.
+@@ -123,6 +127,16 @@
+ otherwise
+ .B qmail-remote
+ refuses to run.
++
++.TP 5
++.I notlshosts/<FQDN>
++.B qmail-remote
++will not try TLS on servers for which this file exists
++.RB ( <FQDN>
++is the fully-qualified domain name of the server). 
++.IR (tlshosts/<FQDN>.pem 
++takes precedence over this file however).
++
+ .TP 5
+ .I smtproutes
+ Artificial SMTP routes.
+@@ -156,6 +170,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:
+ 
+@@ -195,6 +211,33 @@
+ .B qmail-remote
+ will wait for each response from the remote SMTP server.
+ Default: 1200.
++
++.TP 5
++.I tlsclientciphers
++A set of OpenSSL client cipher strings. Multiple ciphers
++contained in a string should be separated by a colon.
++
++.TP 5
++.I tlshosts/<FQDN>.pem
++.B qmail-remote
++requires TLS authentication from servers for which this file exists
++.RB ( <FQDN>
++is the fully-qualified domain name of the server). One of the
++.I dNSName
++or the
++.I CommonName
++attributes have to match. The file contains the trusted CA certificates.
++
++.B WARNING:
++this option may cause mail to be delayed, bounced, doublebounced, or lost.
++
++.TP 5
++.I tlshosts/exhaustivelist
++if this file exists
++no TLS will be tried on hosts other than those for which a file
++.B tlshosts/<FQDN>.pem
++exists.
++
+ .SH "SEE ALSO"
+ addresses(5),
+ envelopes(5),
+--- qmail-1.03-orig/qmail-smtpd.8	2008-01-24 15:54:07.000000000 -0200
++++ qmail-1.03/qmail-smtpd.8	2008-01-24 15:14:50.000000000 -0200
+@@ -19,6 +19,15 @@
+ see
+ .BR tcp-environ(5) .
+ 
++If the environment variable
++.B SMTPS
++is non-empty,
++.B qmail-smtpd
++starts a TLS session (to support the deprecated SMTPS protocol,
++normally on port 465). Otherwise,
++.B qmail-smtpd
++offers the STARTTLS extension to ESMTP.
++
+ .B qmail-smtpd
+ is responsible for counting hops.
+ It rejects any message with 100 or more 
+@@ -76,6 +85,19 @@
+ .BR @\fIhost ,
+ meaning every address at
+ .IR host .
++
++.TP 5
++.I clientca.pem
++A list of Certifying Authority (CA) certificates that are used to verify
++the client-presented certificates during a TLS-encrypted session.
++
++ .TP 5
++.I clientcrl.pem
++A list of Certificate Revocation Lists (CRLs). If present it
++should contain the CRLs of the CAs in 
++.I clientca.pem 
++and client certs will be checked for revocation.
++
+ .TP 5
+ .I databytes
+ Maximum number of bytes allowed in a message,
+@@ -103,6 +125,18 @@
+ .B DATABYTES
+ is set, it overrides
+ .IR databytes .
++
++.TP 5
++.I dh1024.pem
++If these 1024 bit DH parameters are provided,
++.B qmail-smtpd
++will use them for TLS sessions instead of generating one on-the-fly 
++(which is very timeconsuming).
++.TP 5
++.I dh512.pem
++512 bit counterpart for 
++.B dh1024.pem. 
++
+ .TP 5
+ .I localiphost
+ Replacement host name for local IP addresses.
+@@ -178,6 +212,19 @@
+ 
+ Envelope recipient addresses without @ signs are
+ always allowed through.
++
++.TP 5
++.I rsa512.pem
++If this 512 bit RSA key is provided,
++.B qmail-smtpd
++will use it for TLS sessions instead of generaring one on-the-fly.
++
++.TP 5
++.I servercert.pem
++SSL certificate to be presented to clients in TLS-encrypted sessions. 
++Should contain both the certificate and the private key. Certifying Authority
++(CA) and intermediate certificates can be added at the end of the file.
++
+ .TP 5
+ .I smtpgreeting
+ SMTP greeting message.
+@@ -196,6 +243,24 @@
+ .B qmail-smtpd
+ will wait for each new buffer of data from the remote SMTP client.
+ Default: 1200.
++
++.TP 5
++.I tlsclients
++A list of email addresses. When relay rules would reject an incoming message,
++.B qmail-smtpd
++can allow it if the client presents a certificate that can be verified against
++the CA list in
++.I clientca.pem
++and the certificate email address is in
++.IR tlsclients .
++
++.TP 5
++.I tlsserverciphers
++A set of OpenSSL cipher strings. Multiple ciphers contained in a
++string should be separated by a colon. If the environment variable
++.B TLSCIPHERS
++is set to such a string, it takes precedence.
++
+ .SH "SEE ALSO"
+ tcp-env(1),
+ tcp-environ(5),
+--- qmail-1.03-orig/ssl_timeoutio.c	1969-12-31 21:00:00.000000000 -0300
++++ qmail-1.03/ssl_timeoutio.c	2008-01-24 14:56:54.000000000 -0200
+@@ -0,0 +1,95 @@
++#include "select.h"
++#include "error.h"
++#include "ndelay.h"
++#include "now.h"
++#include "ssl_timeoutio.h"
++
++int ssl_timeoutio(int (*fun)(),
++  int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
++{
++  int n;
++  const datetime_sec end = (datetime_sec)t + now();
++
++  do {
++    fd_set fds;
++    struct timeval tv;
++
++    const int r = buf ? fun(ssl, buf, len) : fun(ssl);
++    if (r > 0) return r;
++
++    t = end - now();
++    if (t < 0) break;
++    tv.tv_sec = (time_t)t; tv.tv_usec = 0;
++
++    FD_ZERO(&fds);
++    switch (SSL_get_error(ssl, r))
++    {
++    default: return r; /* some other error */
++    case SSL_ERROR_WANT_READ:
++      FD_SET(rfd, &fds); n = select(rfd + 1, &fds, NULL, NULL, &tv);
++      break;
++    case SSL_ERROR_WANT_WRITE:
++      FD_SET(wfd, &fds); n = select(wfd + 1, NULL, &fds, NULL, &tv);
++      break;
++    }
++
++    /* n is the number of descriptors that changed status */
++  } while (n > 0);
++
++  if (n != -1) errno = error_timeout;
++  return -1;
++}
++
++int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl)
++{
++  int r;
++
++  /* if connection is established, keep NDELAY */
++  if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
++  r = ssl_timeoutio(SSL_accept, t, rfd, wfd, ssl, NULL, 0);
++
++  if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
++  else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
++
++  return r;
++}
++
++int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl)
++{
++  int r;
++
++  /* if connection is established, keep NDELAY */
++  if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
++  r = ssl_timeoutio(SSL_connect, t, rfd, wfd, ssl, NULL, 0);
++
++  if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
++  else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
++
++  return r;
++}
++
++int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl)
++{
++  int r;
++
++  SSL_renegotiate(ssl);
++  r = ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
++  if (r <= 0 || ssl->type == SSL_ST_CONNECT) return r;
++
++  /* this is for the server only */
++  ssl->state = SSL_ST_ACCEPT;
++  return ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
++}
++
++int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
++{
++  if (!buf) return 0;
++  if (SSL_pending(ssl)) return SSL_read(ssl, buf, len);
++  return ssl_timeoutio(SSL_read, t, rfd, wfd, ssl, buf, len);
++}
++
++int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
++{
++  if (!buf) return 0;
++  return ssl_timeoutio(SSL_write, t, rfd, wfd, ssl, buf, len);
++}
+diff -urN qmail-1.03-orig/ssl_timeoutio.h qmail-1.03/ssl_timeoutio.h
+--- qmail-1.03-orig/ssl_timeoutio.h	1969-12-31 21:00:00.000000000 -0300
++++ qmail-1.03/ssl_timeoutio.h	2008-01-24 14:57:40.000000000 -0200
+@@ -0,0 +1,21 @@
++#ifndef SSL_TIMEOUTIO_H
++#define SSL_TIMEOUTIO_H
++
++#include <openssl/ssl.h>
++
++/* the version is like this: 0xMNNFFPPS: major minor fix patch status */
++#if OPENSSL_VERSION_NUMBER < 0x00906000L
++# error "Need OpenSSL version at least 0.9.6"
++#endif
++
++int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl);
++int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl);
++int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl);
++
++int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
++int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
++
++int ssl_timeoutio(
++  int (*fun)(), int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
++
++#endif
+--- qmail-1.03-orig/tls.c	1969-12-31 21:00:00.000000000 -0300
++++ qmail-1.03/tls.c	2008-01-24 15:01:09.000000000 -0200
+@@ -0,0 +1,25 @@
++#include "exit.h"
++#include "error.h"
++#include <openssl/ssl.h>
++#include <openssl/err.h>
++
++int smtps = 0;
++SSL *ssl = NULL;
++
++void ssl_free(SSL *myssl) { SSL_shutdown(myssl); SSL_free(myssl); }
++void ssl_exit(int status) { if (ssl) ssl_free(ssl); _exit(status); }
++
++const char *ssl_error()
++{
++  int r = ERR_get_error();
++  if (!r) return NULL;
++  SSL_load_error_strings();
++  return ERR_error_string(r, NULL);
++}
++const char *ssl_error_str()
++{
++  const char *err = ssl_error();
++  if (err) return err;
++  if (!errno) return 0;
++  return (errno == error_timeout) ? "timed out" : error_str(errno);
++}
+--- qmail-1.03-orig/tls.h	1969-12-31 21:00:00.000000000 -0300
++++ qmail-1.03/tls.h	2008-01-24 14:58:30.000000000 -0200
+@@ -0,0 +1,16 @@
++#ifndef TLS_H
++#define TLS_H
++
++#include <openssl/ssl.h>
++
++extern int smtps;
++extern SSL *ssl;
++
++void ssl_free(SSL *myssl);
++void ssl_exit(int status);
++# define _exit ssl_exit
++
++const char *ssl_error();
++const char *ssl_error_str();
++
++#endif
+--- qmail-1.03-orig/update_tmprsadh.sh	1969-12-31 21:00:00.000000000 -0300
++++ qmail-1.03/update_tmprsadh.sh	2008-01-24 14:58:42.000000000 -0200
+@@ -0,0 +1,25 @@
++#!/bin/sh
++
++# Update temporary RSA and DH keys
++# Frederik Vermeulen 2004-05-31 GPL
++
++umask 0077 || exit 0
++
++export PATH="$PATH:/usr/local/bin/ssl:/usr/sbin"
++
++openssl genrsa -out QMAIL/control/rsa512.new 512 &&
++chmod 600 QMAIL/control/rsa512.new &&
++chown UGQMAILD QMAIL/control/rsa512.new &&
++mv -f QMAIL/control/rsa512.new QMAIL/control/rsa512.pem
++echo
++
++openssl dhparam -2 -out QMAIL/control/dh512.new 512 &&
++chmod 600 QMAIL/control/dh512.new &&
++chown UGQMAILD QMAIL/control/dh512.new &&
++mv -f QMAIL/control/dh512.new QMAIL/control/dh512.pem
++echo
++
++openssl dhparam -2 -out QMAIL/control/dh1024.new 1024 &&
++chmod 600 QMAIL/control/dh1024.new &&
++chown UGQMAILD QMAIL/control/dh1024.new &&
++mv -f QMAIL/control/dh1024.new QMAIL/control/dh1024.pem
+--- qmail-1.03-orig/Makefile	2008-01-24 17:10:07.000000000 -0200
++++ qmail-1.03/Makefile	2008-01-24 17:11:30.000000000 -0200
+@@ -808,7 +808,7 @@
+ forward preline condredirect bouncesaying except maildirmake \
+ maildir2mbox maildirwatch qail elq pinq idedit install-big install \
+ instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
+-binm3 binm3+df
++binm3 binm3+df update_tmprsadh
+ 
+ load: \
+ make-load warn-auto.sh systype
+@@ -1444,6 +1444,7 @@
+ substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib
+ 	./load qmail-remote control.o constmap.o timeoutread.o \
+ 	timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
++	tls.o ssl_timeoutio.o -L/usr/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`
+@@ -1539,6 +1540,7 @@
+ 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 \
++	tls.o ssl_timeoutio.o ndelay.a -L/usr/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 \
+@@ -1827,7 +1829,8 @@
+ ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \
+ ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \
+ prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \
+-maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c
++maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c \
++update_tmprsadh
+ 	shar -m `cat FILES` > shar
+ 	chmod 400 shar
+ 
+@@ -2108,6 +2111,19 @@
+ compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h
+ 	./compile timeoutwrite.c
+ 
++qmail-smtpd: tls.o ssl_timeoutio.o ndelay.a
++qmail-remote: tls.o ssl_timeoutio.o
++qmail-smtpd.o: tls.h ssl_timeoutio.h
++qmail-remote.o: tls.h ssl_timeoutio.h
++
++tls.o: \
++compile tls.c exit.h error.h
++	./compile tls.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 +2155,26 @@
+ 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 conf-users conf-groups Makefile-cert.mk
++	@cat Makefile-cert.mk \
++	| sed s}QMAIL}"`head -1 conf-qmail`"}g \
++	> $@
++
++update_tmprsadh: \
++conf-qmail conf-users conf-groups update_tmprsadh.sh
++	@cat update_tmprsadh.sh\
++	| sed s}UGQMAILD}"`head -2 conf-users|tail -1`:`head -1 conf-groups`"}g \
++	| sed s}QMAIL}"`head -1 conf-qmail`"}g \
++	> $@
++	chmod 755 update_tmprsadh
++
++tmprsadh: \
++update_tmprsadh
++	echo "Creating new temporary RSA and DH parameters"
++	./update_tmprsadh
+--- qmail-1.03-orig/qmail-remote.c	2008-01-24 17:36:23.000000000 -0200
++++ qmail-1.03/qmail-remote.c	2008-01-24 17:45:57.000000000 -0200
+@@ -48,6 +48,17 @@
+ 
+ struct ip_address partner;
+ 
++#ifdef TLS
++# include <sys/stat.h>
++# include "tls.h"
++# include "ssl_timeoutio.h"
++# include <openssl/x509v3.h>
++# define EHLO 1
++
++int tls_init();
++const char *ssl_err_str = 0;
++#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); }
+ void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); }
+@@ -99,6 +110,9 @@
+   outhost();
+   out(" but connection died. ");
+   if (flagcritical) out("Possible duplicate! ");
++#ifdef TLS
++  if (ssl_err_str) { out(ssl_err_str); out(" "); }
++#endif
+   out("(#4.4.2)\n");
+   zerodie();
+ }
+@@ -110,6 +124,12 @@
+ 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 < 0) ssl_err_str = ssl_error_str();
++  } else
++#endif
+   r = timeoutread(timeout,smtpfd,buf,len);
+   if (r <= 0) dropped();
+   return r;
+@@ -117,6 +137,12 @@
+ 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 < 0) ssl_err_str = ssl_error_str();
++  } else
++#endif 
+   r = timeoutwrite(timeout,smtpfd,buf,len);
+   if (r <= 0) dropped();
+   return r;
+@@ -163,6 +189,65 @@
+   return code;
+ }
+ 
++#ifdef EHLO
++saa ehlokw = {0}; /* list of EHLO keywords and parameters */
++int maxehlokwlen = 0;
++
++unsigned long ehlo()
++{
++  stralloc *sa;
++  char *s, *e, *p;
++  unsigned long code;
++
++  if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len;
++  ehlokw.len = 0;
++
++# ifdef MXPS
++  if (type == 's') return 0;
++# endif
++
++  substdio_puts(&smtpto, "EHLO ");
++  substdio_put(&smtpto, helohost.s, helohost.len);
++  substdio_puts(&smtpto, "\r\n");
++  substdio_flush(&smtpto);
++
++  code = smtpcode();
++  if (code != 250) return code;
++
++  s = smtptext.s;
++  while (*s++ != '\n') ; /* skip the first line: contains the domain */
++
++  e = smtptext.s + smtptext.len - 6; /* 250-?\n */
++  while (s <= e)
++  {
++    int wasspace = 0;
++
++    if (!saa_readyplus(&ehlokw, 1)) temp_nomem();
++    sa = ehlokw.sa + ehlokw.len++;
++    if (ehlokw.len > maxehlokwlen) *sa = sauninit; else sa->len = 0;
++
++    /* smtptext is known to end in a '\n' */
++    for (p = (s += 4); ; ++p)
++      if (*p == '\n' || *p == ' ' || *p == '\t') {
++        if (!wasspace)
++          if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem();
++        if (*p == '\n') break;
++        wasspace = 1;
++      } else if (wasspace == 1) {
++        wasspace = 0;
++        s = p;
++      }
++    s = ++p;
++
++    /* keyword should consist of alpha-num and '-'
++     * broken AUTH might use '=' instead of space */
++    for (p = sa->s; *p; ++p) if (*p == '=') { *p = 0; break; }
++  }
++
++  return 250;
++}
++#endif
++
+ void outsmtptext()
+ {
+   int i; 
+@@ -179,6 +264,11 @@
+ char *prepend;
+ char *append;
+ {
++#ifdef TLS
++  /* shouldn't talk to the client unless in an appropriate state */
++  int state = ssl ? ssl->state : SSL_ST_BEFORE;
++  if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE))
++#endif
+   substdio_putsflush(&smtpto,"QUIT\r\n");
+   /* waiting for remote side is just too ridiculous */
+   out(prepend);
+@@ -186,6 +276,30 @@
+   out(append);
+   out(".\n");
+   outsmtptext();
++
++#if defined(TLS) && defined(DEBUG)
++  if (ssl) {
++    X509 *peercert;
++
++    out("STARTTLS proto="); out(SSL_get_version(ssl));
++    out("; cipher="); out(SSL_get_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
++
+   zerodie();
+ }
+ 
+@@ -214,6 +328,194 @@
+   substdio_flush(&smtpto);
+ }
+ 
++#ifdef TLS
++char *partner_fqdn = 0;
++
++# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "")
++void tls_quit(const char *s1, const char *s2)
++{
++  out(s1); if (s2) { out(": "); out(s2); } TLS_QUIT;
++}
++# define tls_quit_error(s) tls_quit(s, ssl_error())
++
++int match_partner(const char *s, int len)
++{
++  if (!case_diffb(partner_fqdn, len, s) && !partner_fqdn[len]) return 1;
++  /* we also match if the name is *.domainname */
++  if (*s == '*') {
++    const char *domain = partner_fqdn + str_chr(partner_fqdn, '.');
++    if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1;
++  }
++  return 0;
++}
++
++/* don't want to fail handshake if certificate can't be verified */
++int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
++
++int tls_init()
++{
++  int i;
++  SSL *myssl;
++  SSL_CTX *ctx;
++  stralloc saciphers = {0};
++  const char *ciphers, *servercert = 0;
++
++  if (partner_fqdn) {
++    struct stat st;
++    stralloc tmp = {0};
++    if (!stralloc_copys(&tmp, "control/tlshosts/")
++      || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn))
++      || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem();
++    if (stat(tmp.s, &st) == 0)
++      servercert = tmp.s;
++    else {
++      if (!stralloc_copys(&tmp, "control/notlshosts/")
++        || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1))
++        temp_nomem();
++      if ((stat("control/tlshosts/exhaustivelist", &st) == 0) ||
++         (stat(tmp.s, &st) == 0)) {
++         alloc_free(tmp.s);
++         return 0;
++      }
++      alloc_free(tmp.s);
++    }
++  }
++ 
++  if (!smtps) {
++    stralloc *sa = ehlokw.sa;
++    unsigned int len = ehlokw.len;
++    /* look for STARTTLS among EHLO keywords */
++    for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ;
++    if (!len) {
++      if (!servercert) return 0;
++      out("ZNo TLS achieved while "); out(servercert);
++      out(" exists"); smtptext.len = 0; TLS_QUIT;
++    }
++  }
++
++  SSL_library_init();
++  ctx = SSL_CTX_new(SSLv23_client_method());
++  if (!ctx) {
++    if (!smtps && !servercert) return 0;
++    smtptext.len = 0;
++    tls_quit_error("ZTLS error initializing ctx");
++  }
++
++  if (servercert) {
++    if (!SSL_CTX_load_verify_locations(ctx, servercert, NULL)) {
++      SSL_CTX_free(ctx);
++      smtptext.len = 0;
++      out("ZTLS unable to load "); tls_quit_error(servercert);
++    }
++    /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
++    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
++  }
++
++  /* let the other side complain if it needs a cert and we don't have one */
++# define CLIENTCERT "control/clientcert.pem"
++  if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT))
++    SSL_CTX_use_RSAPrivateKey_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM);
++# undef CLIENTCERT
++
++  myssl = SSL_new(ctx);
++  SSL_CTX_free(ctx);
++  if (!myssl) {
++    if (!smtps && !servercert) return 0;
++    smtptext.len = 0;
++    tls_quit_error("ZTLS error initializing ssl");
++  }
++
++  if (!smtps) substdio_putsflush(&smtpto, "STARTTLS\r\n");
++
++  /* while the server is preparing a responce, do something else */
++  if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1)
++    { SSL_free(myssl); temp_control(); }
++  if (saciphers.len) {
++    for (i = 0; i < saciphers.len - 1; ++i)
++      if (!saciphers.s[i]) saciphers.s[i] = ':';
++    ciphers = saciphers.s;
++  }
++  else ciphers = "DEFAULT";
++  SSL_set_cipher_list(myssl, ciphers);
++  alloc_free(saciphers.s);
++
++  /* SSL_set_options(myssl, SSL_OP_NO_TLSv1); */
++  SSL_set_fd(myssl, smtpfd);
++
++  /* read the responce to STARTTLS */
++  if (!smtps) {
++    if (smtpcode() != 220) {
++      SSL_free(myssl);
++      if (!servercert) return 0;
++      out("ZSTARTTLS rejected while ");
++      out(servercert); out(" exists"); TLS_QUIT;
++    }
++    smtptext.len = 0;
++  }
++
++  ssl = myssl;
++  if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0)
++    tls_quit("ZTLS connect failed", ssl_error_str());
++
++  if (servercert) {
++    X509 *peercert;
++    STACK_OF(GENERAL_NAME) *gens;
++
++    int r = SSL_get_verify_result(ssl);
++    if (r != X509_V_OK) {
++      out("ZTLS unable to verify server with ");
++      tls_quit(servercert, X509_verify_cert_error_string(r));
++    }
++    alloc_free(servercert);
++
++    peercert = SSL_get_peer_certificate(ssl);
++    if (!peercert) {
++      out("ZTLS unable to verify server ");
++      tls_quit(partner_fqdn, "no certificate provided");
++    }
++
++    /* RFC 2595 section 2.4: find a matching name
++     * first find a match among alternative names */
++    gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
++    if (gens) {
++      for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i)
++      {
++        const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
++        if (gn->type == GEN_DNS)
++          if (match_partner(gn->d.ia5->data, gn->d.ia5->length)) break;
++      }
++      sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
++    }
++
++    /* no alternative name matched, look up commonName */
++    if (!gens || i >= r) {
++      stralloc peer = {0};
++      X509_NAME *subj = X509_get_subject_name(peercert);
++      i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
++      if (i >= 0) {
++        const ASN1_STRING *s = X509_NAME_get_entry(subj, i)->value;
++        if (s) { peer.len = s->length; peer.s = s->data; }
++      }
++      if (peer.len <= 0) {
++        out("ZTLS unable to verify server ");
++        tls_quit(partner_fqdn, "certificate contains no valid commonName");
++      }
++      if (!match_partner(peer.s, peer.len)) {
++        out("ZTLS unable to verify server "); out(partner_fqdn);
++        out(": received certificate for "); outsafe(&peer); TLS_QUIT;
++      }
++    }
++
++    X509_free(peercert);
++  }
++
++  if (smtps) if (smtpcode() != 220)
++    quit("ZTLS Connected to "," but greeting failed");
++
++  return 1;
++}
++#endif
++
+ stralloc recip = {0};
+ 
+ void smtp()
+@@ -221,15 +523,57 @@
+   unsigned long code;
+   int flagbother;
+   int i;
+- 
+-  if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
+- 
++
++#ifndef PORT_SMTP
++  /* the qmtpc patch uses smtp_port and undefines PORT_SMTP */
++# define port smtp_port
++#endif
++
++#ifdef TLS
++# ifdef MXPS
++  if (type == 'S') smtps = 1;
++  else if (type != 's')
++# endif
++    if (port == 465) smtps = 1;
++  if (!smtps)
++#endif
++
++    code = smtpcode();
++    if (code >= 500 && code < 600) quit("DConnected to "," but greeting failed");
++    if (code >= 400 && code < 500) return; /* try next MX, see RFC-2821 */
++    if (code != 220) quit("ZConnected to "," but greeting failed");
++
++#ifdef EHLO
++# ifdef TLS
++  if (!smtps)
++# endif
++  code = ehlo();
++
++# ifdef TLS
++  if (tls_init())
++    /* RFC2487 says we should issue EHLO (even if we might not need
++     * extensions); at the same time, it does not prohibit a server
++     * to reject the EHLO and make us fallback to HELO */
++    code = ehlo();
++# endif
++
++  if (code == 250) {
++    /* add EHLO response checks here */
++
++    /* and if EHLO failed, use HELO */
++  } else {
++#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");
+  
++#ifdef EHLO
++  }
++#endif
++
+   substdio_puts(&smtpto,"MAIL FROM:<");
+   substdio_put(&smtpto,sender.s,sender.len);
+   substdio_puts(&smtpto,">\r\n");
+@@ -417,7 +761,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;
+-      smtp(); /* does not return */
++#ifdef TLS
++      partner_fqdn = ip.ix[i].fqdn;
++#endif
++      smtp(); /* only returns when the next MX is to be tried */
+     }
+     tcpto_err(&ip.ix[i].ip,errno == error_timeout);
+     close(smtpfd);
+--- qmail-1.03-orig/qmail-smtpd.c	2008-01-24 18:15:42.000000000 -0200
++++ qmail-1.03/qmail-smtpd.c	2008-01-24 18:16:54.000000000 -0200
+@@ -28,9 +28,27 @@
+ unsigned int databytes = 0;
+ int timeout = 1200;
+ 
++const char *protocol = "SMTP";
++
++#ifdef TLS
++# include <sys/stat.h>
++# include "tls.h"
++# include "ssl_timeoutio.h"
++
++void tls_init();
++int tls_verify();
++void tls_nogateway();
++int ssl_rfd = -1, ssl_wfd = -1; /* SSL_get_Xfd() are broken */
++#endif
++
+ int safewrite(fd,buf,len) int fd; char *buf; int len;
+ {
+   int r;
++#ifdef TLS
++  if (ssl && fd == ssl_wfd)
++    r = ssl_timeoutwrite(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
++  else
++#endif
+   r = timeoutwrite(timeout,fd,buf,len);
+   if (r <= 0) _exit(1);
+   return r;
+@@ -50,7 +68,16 @@
+ void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
+ 
+ void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
++#ifndef TLS
+ void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
++#else
++void err_nogateway()
++{
++  out("553 sorry, that domain isn't in my list of allowed rcpthosts");
++  tls_nogateway();
++  out(" (#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"); }
+@@ -131,6 +158,11 @@
+   if (!remotehost) remotehost = "unknown";
+   remoteinfo = env_get("TCPREMOTEINFO");
+   relayclient = env_get("RELAYCLIENT");
++
++#ifdef TLS
++  if (env_get("SMTPS")) { smtps = 1; tls_init(); }
++  else
++#endif
+   dohelo(remotehost);
+ }
+ 
+@@ -213,6 +245,9 @@
+   int r;
+   r = rcpthosts(addr.s,str_len(addr.s));
+   if (r == -1) die_control();
++#ifdef TLS
++  if (r == 0) if (tls_verify()) r = -2;
++#endif
+   return r;
+ }
+ 
+@@ -227,9 +262,18 @@
+   smtp_greet("250 "); out("\r\n");
+   seenmail = 0; dohelo(arg);
+ }
++/* ESMTP extensions are published here */
+ void smtp_ehlo(arg) char *arg;
+ {
+-  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
++#ifdef TLS
++  struct stat st;
++#endif
++  smtp_greet("250-");
++#ifdef TLS
++  if (!ssl && (stat("control/servercert.pem",&st) == 0))
++    out("\r\n250-STARTTLS");
++#endif
++  out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+   seenmail = 0; dohelo(arg);
+ }
+ void smtp_rset()
+@@ -269,6 +313,11 @@
+ {
+   int r;
+   flush();
++#ifdef TLS
++  if (ssl && fd == ssl_rfd)
++    r = ssl_timeoutread(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
++  else
++#endif
+   r = timeoutread(timeout,fd,buf,len);
+   if (r == -1) if (errno == error_timeout) die_alarm();
+   if (r <= 0) die_read();
+@@ -378,7 +427,7 @@
+   qp = qmail_qp(&qqt);
+   out("354 go ahead\r\n");
+  
+-  received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
++  received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
+   blast(&hops);
+   hops = (hops >= MAXHOPS);
+   if (hops) qmail_fail(&qqt);
+@@ -394,6 +443,240 @@
+   out("\r\n");
+ }
+ 
++#ifdef TLS
++stralloc proto = {0};
++int ssl_verified = 0;
++const char *ssl_verify_err = 0;
++
++void smtp_tls(char *arg)
++{
++  if (ssl) err_unimpl();
++  else if (*arg) out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n");
++  else tls_init();
++}
++
++RSA *tmp_rsa_cb(SSL *ssl, int export, int keylen)
++{
++  if (!export) keylen = 512;
++  if (keylen == 512) {
++    FILE *in = fopen("control/rsa512.pem", "r");
++    if (in) {
++      RSA *rsa = PEM_read_RSAPrivateKey(in, NULL, NULL, NULL);
++      fclose(in);
++      if (rsa) return rsa;
++    }
++  }
++  return RSA_generate_key(keylen, RSA_F4, NULL, NULL);
++}
++
++DH *tmp_dh_cb(SSL *ssl, int export, int keylen)
++{
++  if (!export) keylen = 1024;
++  if (keylen == 512) {
++    FILE *in = fopen("control/dh512.pem", "r");
++    if (in) {
++      DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
++      fclose(in);
++      if (dh) return dh;
++    }
++  }
++  if (keylen == 1024) {
++    FILE *in = fopen("control/dh1024.pem", "r");
++    if (in) {
++      DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
++      fclose(in);
++      if (dh) return dh;
++    }
++  }
++  return DH_generate_parameters(keylen, DH_GENERATOR_2, NULL, NULL);
++}
++
++/* don't want to fail handshake if cert isn't verifiable */
++int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
++
++void tls_nogateway()
++{
++  /* there may be cases when relayclient is set */
++  if (!ssl || relayclient) return;
++  out("; no valid cert for gatewaying");
++  if (ssl_verify_err) { out(": "); out(ssl_verify_err); }
++}
++void tls_out(const char *s1, const char *s2)
++{
++  out("454 TLS "); out(s1);
++  if (s2) { out(": "); out(s2); }
++  out(" (#4.3.0)\r\n"); flush();
++}
++void tls_err(const char *s) { tls_out(s, ssl_error()); if (smtps) die_read(); }
++
++# define CLIENTCA "control/clientca.pem"
++# define CLIENTCRL "control/clientcrl.pem"
++# define SERVERCERT "control/servercert.pem"
++
++int tls_verify()
++{
++  stralloc clients = {0};
++  struct constmap mapclients;
++
++  if (!ssl || relayclient || ssl_verified) return 0;
++  ssl_verified = 1; /* don't do this twice */
++
++  /* request client cert to see if it can be verified by one of our CAs
++   * and the associated email address matches an entry in tlsclients */
++  switch (control_readfile(&clients, "control/tlsclients", 0))
++  {
++  case 1:
++    if (constmap_init(&mapclients, clients.s, clients.len, 0)) {
++      /* if CLIENTCA contains all the standard root certificates, a
++       * 0.9.6b client might fail with SSL_R_EXCESSIVE_MESSAGE_SIZE;
++       * it is probably due to 0.9.6b supporting only 8k key exchange
++       * data while the 0.9.6c release increases that limit to 100k */
++      STACK_OF(X509_NAME) *sk = SSL_load_client_CA_file(CLIENTCA);
++      if (sk) {
++        SSL_set_client_CA_list(ssl, sk);
++        SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
++        break;
++      }
++      constmap_free(&mapclients);
++    }
++  case 0: alloc_free(clients.s); return 0;
++  case -1: die_control();
++  }
++
++  if (ssl_timeoutrehandshake(timeout, ssl_rfd, ssl_wfd, ssl) <= 0) {
++    const char *err = ssl_error_str();
++    tls_out("rehandshake failed", err); die_read();
++  }
++
++  do { /* one iteration */
++    X509 *peercert;
++    X509_NAME *subj;
++    stralloc email = {0};
++
++    int n = SSL_get_verify_result(ssl);
++    if (n != X509_V_OK)
++      { ssl_verify_err = X509_verify_cert_error_string(n); break; }
++    peercert = SSL_get_peer_certificate(ssl);
++    if (!peercert) break;
++
++    subj = X509_get_subject_name(peercert);
++    n = X509_NAME_get_index_by_NID(subj, NID_pkcs9_emailAddress, -1);
++    if (n >= 0) {
++      const ASN1_STRING *s = X509_NAME_get_entry(subj, n)->value;
++      if (s) { email.len = s->length; email.s = s->data; }
++    }
++
++    if (email.len <= 0)
++      ssl_verify_err = "contains no email address";
++    else if (!constmap(&mapclients, email.s, email.len))
++      ssl_verify_err = "email address not in my list of tlsclients";
++    else {
++      /* add the cert email to the proto if it helped allow relaying */
++      --proto.len;
++      if (!stralloc_cats(&proto, "\n (cert ") /* continuation line */
++        || !stralloc_catb(&proto, email.s, email.len)
++        || !stralloc_cats(&proto, ")")
++        || !stralloc_0(&proto)) die_nomem();
++      relayclient = "";
++      protocol = proto.s;
++    }
++
++    X509_free(peercert);
++  } while (0);
++  constmap_free(&mapclients); alloc_free(clients.s);
++
++  /* we are not going to need this anymore: free the memory */
++  SSL_set_client_CA_list(ssl, NULL);
++  SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
++
++  return relayclient ? 1 : 0;
++}
++
++void tls_init()
++{
++  SSL *myssl;
++  SSL_CTX *ctx;
++  const char *ciphers;
++  stralloc saciphers = {0};
++  X509_STORE *store;
++  X509_LOOKUP *lookup;
++
++  SSL_library_init();
++
++  /* a new SSL context with the bare minimum of options */
++  ctx = SSL_CTX_new(SSLv23_server_method());
++  if (!ctx) { tls_err("unable to initialize ctx"); return; }
++
++  if (!SSL_CTX_use_certificate_chain_file(ctx, SERVERCERT))
++    { SSL_CTX_free(ctx); tls_err("missing certificate"); return; }
++  SSL_CTX_load_verify_locations(ctx, CLIENTCA, NULL);
++
++#if OPENSSL_VERSION_NUMBER >= 0x00907000L
++  /* crl checking */
++  store = SSL_CTX_get_cert_store(ctx);
++  if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) &&
++      (X509_load_crl_file(lookup, CLIENTCRL, X509_FILETYPE_PEM) == 1))
++    X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
++                                X509_V_FLAG_CRL_CHECK_ALL);
++#endif
++
++  /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
++  SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_cb);
++
++  /* a new SSL object, with the rest added to it directly to avoid copying */
++  myssl = SSL_new(ctx);
++  SSL_CTX_free(ctx);
++  if (!myssl) { tls_err("unable to initialize ssl"); return; }
++
++  /* this will also check whether public and private keys match */
++  if (!SSL_use_RSAPrivateKey_file(myssl, SERVERCERT, SSL_FILETYPE_PEM))
++    { SSL_free(myssl); tls_err("no valid RSA private key"); return; }
++
++  ciphers = env_get("TLSCIPHERS");
++  if (!ciphers) {
++    if (control_readfile(&saciphers, "control/tlsserverciphers", 0) == -1)
++      { SSL_free(myssl); die_control(); }
++    if (saciphers.len) { /* convert all '\0's except the last one to ':' */
++      int i;
++      for (i = 0; i < saciphers.len - 1; ++i)
++        if (!saciphers.s[i]) saciphers.s[i] = ':';
++      ciphers = saciphers.s;
++    }
++  }
++  if (!ciphers || !*ciphers) ciphers = "DEFAULT";
++  SSL_set_cipher_list(myssl, ciphers);
++  alloc_free(saciphers.s);
++
++  SSL_set_tmp_rsa_callback(myssl, tmp_rsa_cb);
++  SSL_set_tmp_dh_callback(myssl, tmp_dh_cb);
++  SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin));
++  SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout));
++
++  if (!smtps) { out("220 ready for tls\r\n"); flush(); }
++
++  if (ssl_timeoutaccept(timeout, ssl_rfd, ssl_wfd, myssl) <= 0) {
++    /* neither cleartext nor any other response here is part of a standard */
++    const char *err = ssl_error_str();
++    ssl_free(myssl); tls_out("connection failed", err); die_read();
++  }
++  ssl = myssl;
++
++  /* populate the protocol string, used in Received */
++  if (!stralloc_copys(&proto, SSL_get_cipher(ssl))
++    || !stralloc_cats(&proto, " encrypted SMTP")) die_nomem();
++  if (smtps) if (!stralloc_append(&proto, "S")) die_nomem();
++  if (!stralloc_0(&proto)) die_nomem();
++  protocol = proto.s;
++
++  /* have to discard the pre-STARTTLS HELO/EHLO argument, if any */
++  dohelo(remotehost);
++}
++
++# undef SERVERCERT
++# undef CLIENTCA
++
++#endif
++
+ struct commands smtpcommands[] = {
+   { "rcpt", smtp_rcpt, 0 }
+ , { "mail", smtp_mail, 0 }
+@@ -403,6 +686,9 @@
+ , { "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 }
--- /usr/ports/distfiles/qmail/auto.patch.diff-tls.orig	2008-01-24 20:35:28.000000000 -0200
+++ /usr/ports/distfiles/qmail/auth.patch.diff-tls	2008-01-24 20:13:16.000000000 -0200
@@ -0,0 +1,98 @@
+--- auth.patch.orig	2002-05-10 02:41:20.000000000 -0300
++++ auth.patch	2008-01-24 20:13:02.000000000 -0200
+@@ -14,34 +14,36 @@
+   binm1.sh conf-qmail
+   	cat binm1.sh \
+ ***************
+-*** 1536,1547 ****
++*** 1537,1549 ****
+   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
+   	./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/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 \
+   	socket.lib`
+   
+   qmail-smtpd.0: \
+---- 1540,1551 ----
++--- 1541,1553 ----
+   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 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/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 base64.o  `cat \
++! 	alloc.a substdio.a error.a str.a fs.a auto_qmail.o base64.o `cat \
+   	socket.lib`
+   
+   qmail-smtpd.0: \
+ ***************
+-*** 1553,1559 ****
++*** 1555,1561 ****
+   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 \
+@@ -49,7 +51,7 @@
+   	./compile qmail-smtpd.c
+   
+   qmail-start: \
+---- 1557,1564 ----
++--- 1559,1566 ----
+   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 \
+@@ -174,30 +176,21 @@
+   stralloc greeting = {0};
+   
+ ***************
+-*** 229,235 ****
+-  }
+-  void smtp_ehlo(arg) char *arg;
+-  {
+-!   smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+-    seenmail = 0; dohelo(arg);
+-  }
+-  void smtp_rset()
+---- 241,255 ----
+-  }
+-  void smtp_ehlo(arg) char *arg;
+-  {
+-!   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
+-!   out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+-    seenmail = 0; dohelo(arg);
+-  }
+-  void smtp_rset()
++*** 269,274 ****
++--- 281,293 ----
++    struct stat st;
++  #endif
++    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 && (stat("control/servercert.pem",&st) == 0))
++      out("\r\n250-STARTTLS");
+ ***************
+ *** 394,403 ****
+ --- 414,639 ----
>Release-Note:
>Audit-Trail:
>Unformatted:



More information about the freebsd-ports-bugs mailing list