--- 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 20021228 +Frederik Vermeulen 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 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@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 + and T. Hudson ), + stunnel (M. Trojnara ), + Postfix/TLS (L. Jaenicke ), + modssl (R. Engelschall ), + openssl examples of E. Rescorla . + +Bug reports: mailto: + + +--- 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/ ++.B qmail-remote ++will not try TLS on servers for which this file exists ++.RB ( ++is the fully-qualified domain name of the server). ++.IR (tlshosts/.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/.pem ++.B qmail-remote ++requires TLS authentication from servers for which this file exists ++.RB ( ++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/.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 ++ ++/* 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 ++#include ++ ++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 ++ ++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 ++# include "tls.h" ++# include "ssl_timeoutio.h" ++# include ++# 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 ++# 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 ----