View | Details | Raw Unified | Return to bug 119954
Collapse All | Expand All

(-)qmail-tls/Makefile (-2 / +2 lines)
Lines 7-13 Link Here
7
7
8
PORTNAME=	qmail
8
PORTNAME=	qmail
9
PORTVERSION=	${QMAIL_VERSION}.${TLS_PATCH_DATE}
9
PORTVERSION=	${QMAIL_VERSION}.${TLS_PATCH_DATE}
10
PORTREVISION=	2
10
PORTREVISION=
11
CATEGORIES=	mail
11
CATEGORIES=	mail
12
PKGNAMESUFFIX=	-tls
12
PKGNAMESUFFIX=	-tls
13
13
Lines 17-23 Link Here
17
17
18
SLAVE_TLS=	yes
18
SLAVE_TLS=	yes
19
19
20
TLS_PATCH_DATE=	20021228
20
TLS_PATCH_DATE=	20070408
21
21
22
USE_OPENSSL=	yes
22
USE_OPENSSL=	yes
23
23
(-)qmail-tls/pkg-descr (-1 / +1 lines)
Lines 1-6 Link Here
1
What is is: [excerpt taken from tls patch]
1
What is is: [excerpt taken from tls patch]
2
2
3
Frederik Vermeulen <qmail-tls at inoa.net> 20021228
3
Frederik Vermeulen <qmail-tls at inoa.net> 20070408
4
http://inoa.net/qmail/qmail-1.03-tls.patch
4
http://inoa.net/qmail/qmail-1.03-tls.patch
5
5
6
This patch implements RFC2487 in qmail. This means you can
6
This patch implements RFC2487 in qmail. This means you can
(-)qmail/distinfo (-91 / +18 lines)
Lines 1-9 Link Here
1
MD5 (qmail/qmail-1.03.tar.gz) = 622f65f982e380dbe86e6574f3abcb7c
1
MD5 (qmail/qmail-1.03.tar.gz) = 622f65f982e380dbe86e6574f3abcb7c
2
SHA256 (qmail/qmail-1.03.tar.gz) = 21ed6c562cbb55092a66197c35c8222b84115d1acab0854fdb1ad1f301626f88
2
SHA256 (qmail/qmail-1.03.tar.gz) = 21ed6c562cbb55092a66197c35c8222b84115d1acab0854fdb1ad1f301626f88
3
SIZE (qmail/qmail-1.03.tar.gz) = 220668
3
SIZE (qmail/qmail-1.03.tar.gz) = 220668
4
MD5 (qmail/qmail-smtpd-auth-0.31.tar.gz) = 6b202f71a99fb41e9e32906017270ba0
5
SHA256 (qmail/qmail-smtpd-auth-0.31.tar.gz) = 1b439fa7e128de13fa80b86883f61a39d17b87b7e8916b6a0eab065bbe49b938
6
SIZE (qmail/qmail-smtpd-auth-0.31.tar.gz) = 8798
7
MD5 (qmail/qmail-smtpd-auth-close3.patch) = 0ba66d73dcba1c68ed714b07e47abd3e
8
SHA256 (qmail/qmail-smtpd-auth-close3.patch) = d933e871261d6740cebe5c21cad81146525cfe06a464e277979f61c1242b5ad4
9
SIZE (qmail/qmail-smtpd-auth-close3.patch) = 520
10
MD5 (qmail/auth.patch.diff-tls) = c152ec1a6cf9c78d0aede6c212736f2f
11
SHA256 (qmail/auth.patch.diff-tls) = ba875152d7b2e01d5e8a9b5d02719bc1a77c8f862cc3383cea778823d506f6d4
12
SIZE (qmail/auth.patch.diff-tls) = 3389
4
MD5 (qmail/qmail-103.patch) = 9140ad2b03017145cd7963c84bb24f16
13
MD5 (qmail/qmail-103.patch) = 9140ad2b03017145cd7963c84bb24f16
5
SHA256 (qmail/qmail-103.patch) = 4cad53c7a6628a600c74c36bfee327db5052ca24c222d4013e4dfcd7f427653d
14
SHA256 (qmail/qmail-103.patch) = 4cad53c7a6628a600c74c36bfee327db5052ca24c222d4013e4dfcd7f427653d
6
SIZE (qmail/qmail-103.patch) = 2104
15
SIZE (qmail/qmail-103.patch) = 2104
16
MD5 (qmail/sendmail-flagf.patch) = 4e1f2d8315e7e2a5482798c9d19fac4d
17
SHA256 (qmail/sendmail-flagf.patch) = 9b3951c22b98c0e5a6ebfa793f052d91dfe01d68a0ad8dc83b8e0bd60c01802e
18
SIZE (qmail/sendmail-flagf.patch) = 863
19
MD5 (qmail/qmail-1.03-tls-20070408-renato.patch) = 77a74dc9c771e25e026b8dd8c42e0063
20
SHA256 (qmail/qmail-1.03-tls-20070408-renato.patch) = 7a6289f4748d31a58bfdaf37018117fbbb6731652e59387c13facc9752801b2b
21
SIZE (qmail/qmail-1.03-tls-20070408-renato.patch) = 46613
22
MD5 (qmail/qmail-discard-double-bounces.patch) = 55d45bb8d2c3822a0e3544058aa5a3a3
23
SHA256 (qmail/qmail-discard-double-bounces.patch) = 14489eefd9908f60af13fadd574d0e9bb936e5d1b706690ce52efef68529a8d8
24
SIZE (qmail/qmail-discard-double-bounces.patch) = 1305
7
MD5 (qmail/qmailqueue-patch) = 5a8d7a5863b0c56236af945dedd45754
25
MD5 (qmail/qmailqueue-patch) = 5a8d7a5863b0c56236af945dedd45754
8
SHA256 (qmail/qmailqueue-patch) = 52e82aaa34e9f1308b063cc986a701f67e161662e9f789bb12af03a381530f94
26
SHA256 (qmail/qmailqueue-patch) = 52e82aaa34e9f1308b063cc986a701f67e161662e9f789bb12af03a381530f94
9
SIZE (qmail/qmailqueue-patch) = 2510
27
SIZE (qmail/qmailqueue-patch) = 2510
Lines 13-106 Link Here
13
MD5 (qmail/big-concurrency.patch) = 2ff58c3570870a8ff9a1d9eb9aec05a6
31
MD5 (qmail/big-concurrency.patch) = 2ff58c3570870a8ff9a1d9eb9aec05a6
14
SHA256 (qmail/big-concurrency.patch) = 0322991955878e86af495f7317c3a4bd2e60640f9a6dd70ad501fff27242ac2f
32
SHA256 (qmail/big-concurrency.patch) = 0322991955878e86af495f7317c3a4bd2e60640f9a6dd70ad501fff27242ac2f
15
SIZE (qmail/big-concurrency.patch) = 9331
33
SIZE (qmail/big-concurrency.patch) = 9331
16
MD5 (qmail/sendmail-flagf.patch) = 4e1f2d8315e7e2a5482798c9d19fac4d
17
SHA256 (qmail/sendmail-flagf.patch) = 9b3951c22b98c0e5a6ebfa793f052d91dfe01d68a0ad8dc83b8e0bd60c01802e
18
SIZE (qmail/sendmail-flagf.patch) = 863
19
MD5 (qmail/patch-qmail-1.03-rfc2821.diff) = 1b85f233ab5b9d7ec1a8da1188bf10ef
20
SHA256 (qmail/patch-qmail-1.03-rfc2821.diff) = c34b331e27882f0596529df14f0e9f24c4dff9f941d04e5df17cc158dddac426
21
SIZE (qmail/patch-qmail-1.03-rfc2821.diff) = 2564
22
MD5 (qmail/qmail-date-localtime.patch) = d566e8bd99b33efee0194e855b8d6995
23
SHA256 (qmail/qmail-date-localtime.patch) = 852aee7577edf8814c2429f82740da2a7e0b0b23516e10c4f3f7e845a47be2d5
24
SIZE (qmail/qmail-date-localtime.patch) = 2603
25
MD5 (qmail/qmail-1.03-qmtpc.patch) = 122664c38338e5ec35fcac43f33d6927
26
SHA256 (qmail/qmail-1.03-qmtpc.patch) = f704b6c0ca3515a4bb488d14f7c94910aba4daa87420db6cd5b7ea19f17f7449
27
SIZE (qmail/qmail-1.03-qmtpc.patch) = 6197
28
MD5 (qmail/outgoingip.patch) = 3c9277dcf5f9b4b6d3a270fb3abf7994
29
SHA256 (qmail/outgoingip.patch) = c117f5c41033f062cdc782a16403fc19725e98d92e73ab193dfd24f48c0ca5ac
30
SIZE (qmail/outgoingip.patch) = 6839
31
MD5 (qmail/outgoingip.patch-spamcontrol) = ed3ca1e309116647e9adb0a49194e2e5
32
SHA256 (qmail/outgoingip.patch-spamcontrol) = 721f5a1199867a26e69773608b07ec54fce1444cfa0679906592b60b7dd68abe
33
SIZE (qmail/outgoingip.patch-spamcontrol) = 6769
34
MD5 (qmail/qmail-1.03-qmtpc_outgoingip.patch) = 4b2623cbd9e9a4f137f7b16f78a43975
35
SHA256 (qmail/qmail-1.03-qmtpc_outgoingip.patch) = d8dc66a5057b5ffbab4a9e0a27a6392b1f29d3c6aadea1f13f2290918846e89c
36
SIZE (qmail/qmail-1.03-qmtpc_outgoingip.patch) = 10357
37
MD5 (qmail/qmail-maildir++.patch) = fd92b624ac1129a656eb1e567d1f0409
38
SHA256 (qmail/qmail-maildir++.patch) = 79e3f1f8f95b58b6d17e5469f125d873fe212d0a5a6d19b538ad57176fbafb52
39
SIZE (qmail/qmail-maildir++.patch) = 38088
40
MD5 (qmail/qmail-block-executables.patch) = e425b420e5251b4882fc699f7822f7a0
41
SHA256 (qmail/qmail-block-executables.patch) = 97512624eb02db51e10ab6d0dd834a8797a238d0e006bd1c6c94a183d291b456
42
SIZE (qmail/qmail-block-executables.patch) = 5070
43
MD5 (qmail/qmail-discard-double-bounces.patch) = 55d45bb8d2c3822a0e3544058aa5a3a3
44
SHA256 (qmail/qmail-discard-double-bounces.patch) = 14489eefd9908f60af13fadd574d0e9bb936e5d1b706690ce52efef68529a8d8
45
SIZE (qmail/qmail-discard-double-bounces.patch) = 1305
46
MD5 (qmail/qmail-spf-rc5.patch) = 434bd84b87e2027cfa643673c498bd6f
47
SHA256 (qmail/qmail-spf-rc5.patch) = 8ad251d779125e11422ae9bcbf619b0ba002c0893dd8c8fe55a34a8b5fc42640
48
SIZE (qmail/qmail-spf-rc5.patch) = 63582
49
MD5 (qmail/qmail-spf-rc5.patch-tls) = db126b4ac29ad83c1c219e5323cef452
50
SHA256 (qmail/qmail-spf-rc5.patch-tls) = c884665ff0bc5a5272efe3e09aed71e648a79d0279bc708d5a9df25c5758804f
51
SIZE (qmail/qmail-spf-rc5.patch-tls) = 63617
52
MD5 (qmail/qmail-spf-rc5.patch-auth-tls) = 262e381adc967df0a8ab4f15f2f6fe8f
53
SHA256 (qmail/qmail-spf-rc5.patch-auth-tls) = 16fe99894938c30ed1928a61dabf0a598ef7e08a766a76cf084fe658d6d50092
54
SIZE (qmail/qmail-spf-rc5.patch-auth-tls) = 63752
55
MD5 (qmail/qmail-ldap-1.03-20060201.patch.gz) = 55fa135415ee011f3f4234d7d52a3565
56
SHA256 (qmail/qmail-ldap-1.03-20060201.patch.gz) = 92ba895df1957109ad856cc1d1554ece4d25d59017e77127dd52d76afd05525a
57
SIZE (qmail/qmail-ldap-1.03-20060201.patch.gz) = 270788
58
MD5 (qmail/qmail-mysql-1.1.15.patch) = c0298550475f928e82881e574e905313
59
SHA256 (qmail/qmail-mysql-1.1.15.patch) = 3d2b6a08fb149d6c9fe6c8250e87edd6c4d4b2b0417f03adf5cf4202bbadc53f
60
SIZE (qmail/qmail-mysql-1.1.15.patch) = 67602
61
MD5 (qmail/spamcontrol-2418_tgz.bin) = a5502cd69e573a2753e532bce8fb6c3a
62
SHA256 (qmail/spamcontrol-2418_tgz.bin) = e9874f9961707cd15e135269796fbec7a2d417b18124d802a352d65b76e22d85
63
SIZE (qmail/spamcontrol-2418_tgz.bin) = 124059
64
MD5 (qmail/qmail-spf-rc5.patch-spamcontrol) = c7da17aa55896eae8c525d05c65387fd
65
MD5 (qmail/qmail-1.03-tls-20021228-renato.patch) = be15cd5eaff7aa3cd88aee962febadc6
66
SHA256 (qmail/qmail-1.03-tls-20021228-renato.patch) = ab0de8f744241dcb7f5ee207fc7eab4f067bf42812deb85f9eb0050ac49e6e23
67
SIZE (qmail/qmail-1.03-tls-20021228-renato.patch) = 42095
68
MD5 (qmail/qmail-smtpd-auth-0.31.tar.gz) = 6b202f71a99fb41e9e32906017270ba0
69
SHA256 (qmail/qmail-smtpd-auth-0.31.tar.gz) = 1b439fa7e128de13fa80b86883f61a39d17b87b7e8916b6a0eab065bbe49b938
70
SIZE (qmail/qmail-smtpd-auth-0.31.tar.gz) = 8798
71
MD5 (qmail/qmail-smtpd-auth-close3.patch) = 0ba66d73dcba1c68ed714b07e47abd3e
72
SHA256 (qmail/qmail-smtpd-auth-close3.patch) = d933e871261d6740cebe5c21cad81146525cfe06a464e277979f61c1242b5ad4
73
SIZE (qmail/qmail-smtpd-auth-close3.patch) = 520
74
MD5 (qmail/tarpit.patch) = 49a2c0a445981deb09f3af73041d75f5
75
SHA256 (qmail/tarpit.patch) = de94abbb71ef5d25e168725e435edd96ce3b14b7347440e0805dcb919b9d9604
76
SIZE (qmail/tarpit.patch) = 3089
77
MD5 (qmail/ext_todo-20030105.patch) = 99070bb55cac5ad61f8fb203422e651e
78
SHA256 (qmail/ext_todo-20030105.patch) = d46d0225360c0477f93e2990637ebf912b2a86e494f424ef2952ee11ab533ac7
79
SIZE (qmail/ext_todo-20030105.patch) = 33763
80
MD5 (qmail/ext_todo-20030105_spf.patch) = 4d760732c92c01bd14d9957257ca4c1a
81
SHA256 (qmail/ext_todo-20030105_spf.patch) = 544629c0003d01d27a5a45508e84332f247ed54ece57ff22c0c7c3a56ba086d6
82
SIZE (qmail/ext_todo-20030105_spf.patch) = 33781
83
MD5 (qmail/ext_todo-20030105_mysql.patch) = ecddff9ba6d725ec3be61843bc8007a7
84
SHA256 (qmail/ext_todo-20030105_mysql.patch) = 3fc65b91faaaae147dbf6264f9381664819ef2f236532764309d174f29919ff1
85
SIZE (qmail/ext_todo-20030105_mysql.patch) = 33797
86
MD5 (qmail/qmail-spf-rc5.patch-spamcontrol) = c7da17aa55896eae8c525d05c65387fd
87
SHA256 (qmail/qmail-spf-rc5.patch-spamcontrol) = 52a3e4a6c8ae0124be280b6c0d183d81f4a6bd10c23fc735d99f4f731d4f5c6d
88
SIZE (qmail/qmail-spf-rc5.patch-spamcontrol) = 64214
89
MD5 (qmail/auth.patch.diff) = 23e0509061cd5dda4a1abf9a7cb7596d
90
SHA256 (qmail/auth.patch.diff) = 1d0f8e0ce139cd00b86f056bc31c1422d30b88cb8b125023d534cc3664f827b8
91
SIZE (qmail/auth.patch.diff) = 4412
92
MD5 (qmail/auth.patch.diff-tls) = 7e706dd124deb9a25cecd91fe652a90b
93
SHA256 (qmail/auth.patch.diff-tls) = 467c5f68d5d332d2400f937c76311e5358b613923d64e68ae98d51d178c7de5e
94
SIZE (qmail/auth.patch.diff-tls) = 2993
95
MD5 (qmail/ext_todo-20030105+big-todo.103.patch) = 5878870ef85d6a83ba9465ce94d9cd42
96
SHA256 (qmail/ext_todo-20030105+big-todo.103.patch) = 4e44ad403b21f5910b6af11295b82296bc8c0f18bc40dcfecfb95c11e5a296f7
97
SIZE (qmail/ext_todo-20030105+big-todo.103.patch) = 2523
98
MD5 (qmail/smtpextfork-ldap-20060201.patch) = a359bf9aa2a2799e4ab0fb9cc2dd6593
99
SHA256 (qmail/smtpextfork-ldap-20060201.patch) = 554eb7879d26bb5a3f3dd671e91abc803a53d5ba2fee397ab248b52917ff2ffc
100
SIZE (qmail/smtpextfork-ldap-20060201.patch) = 6715
101
MD5 (qmail/smtpextfork-spamcontrol-2418_1.patch) = af5b96daaa2021e03712ada45e3b523c
102
SHA256 (qmail/smtpextfork-spamcontrol-2418_1.patch) = 59c03c8ec28aa32c7869b3b63d9d760712f983fc5b8d9723fddbdb9e95c9f650
103
SIZE (qmail/smtpextfork-spamcontrol-2418_1.patch) = 7609
104
MD5 (qmail/README.smtpextfork) = e783965f5a7510c38b30f0ba3cda1e11
105
SHA256 (qmail/README.smtpextfork) = c43122d27d4e20dd955c30ca402903d2e9a6a1820c3cf11902e2477316abdcbb
106
SIZE (qmail/README.smtpextfork) = 7618
(-)/usr/ports/distfiles/qmail/qmail-1.03-tls-20070408-renato.patch (+1525 lines)
Line 0 Link Here
1
Frederik Vermeulen <qmail-tls akrul inoa.net> 20070408
2
http://inoa.net/qmail-tls/
3
4
This patch implements RFC 3207 (was RFC 2487) in qmail. 
5
This means you can get SSL or TLS encrypted and 
6
authenticated SMTP between the MTAs and from MUA to MTA. 
7
The code is considered experimental (but has worked for
8
many since its first release on 1999-03-21).
9
10
Usage: - install OpenSSL-0.9.8 http://www.openssl.org/
11
         (any 0.9.6 to 0.9.8 version is presumed to work)
12
       - apply patch to netqmail-1.05 http://qmail.org/netqmail
13
         (should work on qmail-1.03 too).  The patches to 
14
         qmail-remote.c and qmail-smtpd.c can be applied separately.
15
       - provide a server certificate in /var/qmail/control/servercert.pem.
16
         "make cert" makes a self-signed certificate.
17
         "make cert-req" makes a certificate request.
18
         Note: you can add the CA certificate and intermediate
19
         certs to the end of servercert.pem.
20
       - replace qmail-smtpd and/or qmail-remote binary
21
       - verify operation (header information should show
22
         something like
23
         "Received [..] with (DHE-RSA-AES256-SHA encrypted) SMTP;")
24
         If you don't have a server to test with, you can test
25
         by sending mail to tag-ping@tbs-internet.com,
26
         which will bounce your mail.
27
28
Optional: - when DEBUG is defined, some extra TLS info will be logged
29
          - qmail-remote will authenticate with the certificate in
30
            /var/qmail/control/clientcert.pem. By preference this is
31
            the same as servercert.pem, where nsCertType should be 
32
            == server,client or be a generic certificate (no usage specified). 
33
          - when a 512 bit RSA key is provided in /var/qmail/control/rsa512.pem,
34
            this key will be used instead of (slow) on-the-fly generation by
35
       	    qmail-smtpd. Idem for 512 and 1024 DH params in control/dh512.pem
36
            and control/dh1024.pem. `make tmprsadh` does this.
37
            Periodical replacement can be done by crontab:
38
       	    01 01 * * * /var/qmail/bin/update_tmprsadh > /dev/null 2>&1
39
          - server authentication:
40
            qmail-remote requires authentication from servers for which
41
            /var/qmail/control/tlshosts/host.dom.ain.pem exists.
42
            The .pem file contains the validating CA certificates.
43
            One of the dNSName or the CommonName attributes have to match.
44
            WARNING: this option may cause mail to be delayed, bounced,
45
            doublebounced, and lost.
46
            If /var/qmail/control/tlshosts/exhaustivelist is present,
47
            the lists of hosts in /var/qmail/control/tlshosts is
48
            an exhaustive list of hosts TLS is tried on.
49
            If /var/qmail/control/notlshosts/host.dom.ain is present,
50
            no TLS is tried on this host.
51
          - client authentication:
52
            when relay rules would reject an incoming mail, 
53
            qmail-smtpd can allow the mail based on a presented cert.
54
            Certs are verified against a CA list in 
55
            /var/qmail/control/clientca.pem (eg. http://www.modssl.org/
56
            source/cvs/exp/mod_ssl/pkg.mod_ssl/pkg.sslcfg/ca-bundle.crt)
57
            and the cert email-address has to match a line in
58
            /var/qmail/control/tlsclients. This email-address is logged
59
            in the headers. CRLs can be provided through 
60
            /var/qmail/control/clientcrl.pem.
61
          - cipher selection:
62
            qmail-remote: 
63
              openssl cipher string (`man ciphers`) read from 
64
              /var/qmail/control/tlsclientciphers
65
            qmail-smtpd: 
66
              openssl cipher string read from TLSCIPHERS environment variable
67
              (can vary based on client IP address e.g.)
68
              or if that is not available /var/qmail/control/tlsserverciphers
69
          - smtps (deprecated SMTP over TLS via port 465):
70
            qmail-remote: when connecting to port 465 
71
            qmail-smtpd: when SMTPS environment variable is not empty
72
73
Caveats: - do a `make clean` after patching
74
         - binaries dynamically linked with current openssl versions need
75
           recompilation when the shared openssl libs are upgraded.
76
         - this patch could conflict with other patches (notably those
77
           replacing \n with \r\n, which is a bad idea on encrypted links).
78
         - some broken servers have a problem with TLSv1 compatibility.
79
           Uncomment the line where we set the SSL_OP_NO_TLSv1 option.
80
         - needs working /dev/urandom (or EGD for openssl versions >0.9.7)
81
           for seeding random number generator.
82
         - packagers should make sure that installing without a valid 
83
           servercert is impossible
84
         - when applied in combination with AUTH patch, AUTH patch
85
           should be applied first and first part of this patch
86
           will fail. This error can be ignored. Packagers should
87
           cut the first 12 lines of this patch to make a happy
88
           patch
89
         - `make tmprsadh` is recommended (or should I say required), 
90
           otherwise DH generation can be unpredictably slow
91
         - some need "-I/usr/kerberos/include" to be added in conf-cc
92
93
Copyright: GPL
94
           Links with OpenSSL
95
           Inspiration and code from examples in SSLeay (E. Young
96
           <eay@cryptsoft.com> and T. Hudson <tjh@cryptsoft.com>),
97
           stunnel (M. Trojnara <mtrojnar@ddc.daewoo.com.pl>),
98
           Postfix/TLS (L. Jaenicke <Lutz.Jaenicke@aet.tu-cottbus.de>),
99
           modssl (R. Engelschall <rse@engelschall.com>),
100
           openssl examples of E. Rescorla <ekr@rtfm.com>.
101
102
Bug reports: mailto:<qmail-tls akrul inoa.net>
103
104
105
--- qmail-1.03-orig/Makefile-cert.mk	1969-12-31 21:00:00.000000000 -0300
106
+++ qmail-1.03/Makefile-cert.mk	2008-01-24 14:34:28.000000000 -0200
107
@@ -0,0 +1,21 @@
108
+cert-req: req.pem
109
+cert cert-req: QMAIL/control/clientcert.pem
110
+	@:
111
+
112
+QMAIL/control/clientcert.pem: QMAIL/control/servercert.pem
113
+	ln -s $< $@
114
+
115
+QMAIL/control/servercert.pem:
116
+	PATH=$$PATH:/usr/local/ssl/bin \
117
+		openssl req -new -x509 -nodes -days 366 -out $@ -keyout $@
118
+	chmod 640 $@
119
+	chown `head -2 conf-users | tail -1`:`head -1 conf-groups` $@
120
+
121
+req.pem:
122
+	PATH=$$PATH:/usr/local/ssl/bin openssl req \
123
+		-new -nodes -out $@ -keyout QMAIL/control/servercert.pem
124
+	chmod 640 QMAIL/control/servercert.pem
125
+	chown `head -2 conf-users | tail -1`:`head -1 conf-groups` QMAIL/control/servercert.pem
126
+	@echo
127
+	@echo "Send req.pem to your CA to obtain signed_req.pem, and do:"
128
+	@echo "cat signed_req.pem >> QMAIL/control/servercert.pem"
129
--- qmail-1.03-orig/TARGETS	2008-01-24 15:54:07.000000000 -0200
130
+++ qmail-1.03/TARGETS	2008-01-24 14:36:13.000000000 -0200
131
@@ -168,6 +168,8 @@
132
 constmap.o
133
 timeoutread.o
134
 timeoutwrite.o
135
+tls.o
136
+ssl_timeoutio.o
137
 timeoutconn.o
138
 tcpto.o
139
 dns.o
140
@@ -321,6 +323,7 @@
141
 binm2+df
142
 binm3
143
 binm3+df
144
+Makefile-cert
145
 it
146
 qmail-local.0
147
 qmail-lspawn.0
148
@@ -386,3 +389,4 @@
149
 man
150
 setup
151
 check
152
+update_tmprsadh
153
--- qmail-1.03-orig/conf-cc	2008-01-24 15:54:08.000000000 -0200
154
+++ qmail-1.03/conf-cc	2008-01-24 14:27:50.000000000 -0200
155
@@ -1 +1 @@
156
-cc -O2 
157
+cc -O2 -pipe -DTLS=20070408 -I/usr/local/ssl/include
158
--- qmail-1.03-orig/dns.c	2008-01-24 15:54:11.000000000 -0200
159
+++ qmail-1.03/dns.c	2008-01-24 14:27:50.000000000 -0200
160
@@ -286,12 +286,11 @@
161
 int pref;
162
 {
163
  int r;
164
- struct ip_mx ix;
165
+ struct ip_mx ix = {0};
166
 
167
  if (!stralloc_copy(&glue,sa)) return DNS_MEM;
168
  if (!stralloc_0(&glue)) return DNS_MEM;
169
  if (glue.s[0]) {
170
-   ix.pref = 0;
171
    if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
172
     {
173
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
174
@@ -310,9 +309,16 @@
175
    ix.ip = ip;
176
    ix.pref = pref;
177
    if (r == DNS_SOFT) return DNS_SOFT;
178
-   if (r == 1)
179
+   if (r == 1) {
180
+#ifdef IX_FQDN
181
+     ix.fqdn = glue.s;
182
+#endif
183
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
184
   }
185
+  }
186
+#ifdef IX_FQDN
187
+ glue.s = 0;
188
+#endif
189
  return 0;
190
 }
191
 
192
@@ -332,7 +338,7 @@
193
 {
194
  int r;
195
  struct mx { stralloc sa; unsigned short p; } *mx;
196
- struct ip_mx ix;
197
+ struct ip_mx ix = {0};
198
  int nummx;
199
  int i;
200
  int j;
201
@@ -344,7 +350,6 @@
202
  if (!stralloc_copy(&glue,sa)) return DNS_MEM;
203
  if (!stralloc_0(&glue)) return DNS_MEM;
204
  if (glue.s[0]) {
205
-   ix.pref = 0;
206
    if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
207
     {
208
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
209
--- qmail-1.03-orig/hier.c	2008-01-24 15:54:09.000000000 -0200
210
+++ qmail-1.03/hier.c	2008-01-24 14:37:02.000000000 -0200
211
@@ -102,6 +102,9 @@
212
   c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755);
213
   c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755);
214
   c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755);
215
+#ifdef TLS
216
+  c(auto_qmail,"bin","update_tmprsadh",auto_uido,auto_gidq,0755);
217
+#endif
218
 
219
 
220
 
221
--- qmail-1.03-orig/ipalloc.h	2008-01-24 15:54:11.000000000 -0200
222
+++ qmail-1.03/ipalloc.h	2008-01-24 14:27:50.000000000 -0200
223
@@ -3,7 +3,15 @@
224
 
225
 #include "ip.h"
226
 
227
+#ifdef TLS
228
+# define IX_FQDN 1
229
+#endif
230
+
231
+#ifdef IX_FQDN
232
+struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ;
233
+#else
234
 struct ip_mx { struct ip_address ip; int pref; } ;
235
+#endif
236
 
237
 #include "gen_alloc.h"
238
 
239
--- qmail-1.03-orig/qmail-control.9	2008-01-24 15:54:07.000000000 -0200
240
+++ qmail-1.03/qmail-control.9	2008-01-24 14:38:13.000000000 -0200
241
@@ -43,11 +43,15 @@
242
 .I badmailfrom	\fR(none)	\fRqmail-smtpd
243
 .I bouncefrom	\fRMAILER-DAEMON	\fRqmail-send
244
 .I bouncehost	\fIme	\fRqmail-send
245
+.I clientca.pem	\fR(none)	\fRqmail-smtpd
246
+.I clientcert.pem	\fR(none)	\fRqmail-remote
247
 .I concurrencylocal	\fR10	\fRqmail-send
248
 .I concurrencyremote	\fR20	\fRqmail-send
249
 .I defaultdomain	\fIme	\fRqmail-inject
250
 .I defaulthost	\fIme	\fRqmail-inject
251
 .I databytes	\fR0	\fRqmail-smtpd
252
+.I dh1024.pem	\fR(none)	\fRqmail-smtpd
253
+.I dh512.pem	\fR(none)	\fRqmail-smtpd
254
 .I doublebouncehost	\fIme	\fRqmail-send
255
 .I doublebounceto	\fRpostmaster	\fRqmail-send
256
 .I envnoathost	\fIme	\fRqmail-send
257
@@ -61,11 +65,17 @@
258
 .I qmqpservers	\fR(none)	\fRqmail-qmqpc
259
 .I queuelifetime	\fR604800	\fRqmail-send
260
 .I rcpthosts	\fR(none)	\fRqmail-smtpd
261
+.I rsa512.pem	\fR(none)	\fRqmail-smtpd
262
+.I servercert.pem	\fR(none)	\fRqmail-smtpd
263
 .I smtpgreeting	\fIme	\fRqmail-smtpd
264
 .I smtproutes	\fR(none)	\fRqmail-remote
265
 .I timeoutconnect	\fR60	\fRqmail-remote
266
 .I timeoutremote	\fR1200	\fRqmail-remote
267
 .I timeoutsmtpd	\fR1200	\fRqmail-smtpd
268
+.I tlsclients	\fR(none)	\fRqmail-smtpd
269
+.I tlsclientciphers	\fR(none)	\fRqmail-remote
270
+.I tlshosts/FQDN.pem	\fR(none)	\fRqmail-remote
271
+.I tlsserverciphers	\fR(none)	\fRqmail-smtpd
272
 .I virtualdomains	\fR(none)	\fRqmail-send
273
 .fi
274
 .RE
275
--- qmail-1.03-orig/qmail-remote.8	2008-01-24 15:54:07.000000000 -0200
276
+++ qmail-1.03/qmail-remote.8	2008-01-24 15:02:04.000000000 -0200
277
@@ -114,6 +114,10 @@
278
 always exits zero.
279
 .SH "CONTROL FILES"
280
 .TP 5
281
+.I clientcert.pem
282
+SSL certificate that is used to authenticate with the remote server
283
+during a TLS session.
284
+.TP 5
285
 .I helohost
286
 Current host name,
287
 for use solely in saying hello to the remote SMTP server.
288
@@ -123,6 +127,16 @@
289
 otherwise
290
 .B qmail-remote
291
 refuses to run.
292
+
293
+.TP 5
294
+.I notlshosts/<FQDN>
295
+.B qmail-remote
296
+will not try TLS on servers for which this file exists
297
+.RB ( <FQDN>
298
+is the fully-qualified domain name of the server). 
299
+.IR (tlshosts/<FQDN>.pem 
300
+takes precedence over this file however).
301
+
302
 .TP 5
303
 .I smtproutes
304
 Artificial SMTP routes.
305
@@ -156,6 +170,8 @@
306
 this tells
307
 .B qmail-remote
308
 to look up MX records as usual.
309
+.I port 
310
+value of 465 (deprecated smtps port) causes TLS session to be started.
311
 .I smtproutes
312
 may include wildcards:
313
 
314
@@ -195,6 +211,33 @@
315
 .B qmail-remote
316
 will wait for each response from the remote SMTP server.
317
 Default: 1200.
318
+
319
+.TP 5
320
+.I tlsclientciphers
321
+A set of OpenSSL client cipher strings. Multiple ciphers
322
+contained in a string should be separated by a colon.
323
+
324
+.TP 5
325
+.I tlshosts/<FQDN>.pem
326
+.B qmail-remote
327
+requires TLS authentication from servers for which this file exists
328
+.RB ( <FQDN>
329
+is the fully-qualified domain name of the server). One of the
330
+.I dNSName
331
+or the
332
+.I CommonName
333
+attributes have to match. The file contains the trusted CA certificates.
334
+
335
+.B WARNING:
336
+this option may cause mail to be delayed, bounced, doublebounced, or lost.
337
+
338
+.TP 5
339
+.I tlshosts/exhaustivelist
340
+if this file exists
341
+no TLS will be tried on hosts other than those for which a file
342
+.B tlshosts/<FQDN>.pem
343
+exists.
344
+
345
 .SH "SEE ALSO"
346
 addresses(5),
347
 envelopes(5),
348
--- qmail-1.03-orig/qmail-smtpd.8	2008-01-24 15:54:07.000000000 -0200
349
+++ qmail-1.03/qmail-smtpd.8	2008-01-24 15:14:50.000000000 -0200
350
@@ -19,6 +19,15 @@
351
 see
352
 .BR tcp-environ(5) .
353
 
354
+If the environment variable
355
+.B SMTPS
356
+is non-empty,
357
+.B qmail-smtpd
358
+starts a TLS session (to support the deprecated SMTPS protocol,
359
+normally on port 465). Otherwise,
360
+.B qmail-smtpd
361
+offers the STARTTLS extension to ESMTP.
362
+
363
 .B qmail-smtpd
364
 is responsible for counting hops.
365
 It rejects any message with 100 or more 
366
@@ -76,6 +85,19 @@
367
 .BR @\fIhost ,
368
 meaning every address at
369
 .IR host .
370
+
371
+.TP 5
372
+.I clientca.pem
373
+A list of Certifying Authority (CA) certificates that are used to verify
374
+the client-presented certificates during a TLS-encrypted session.
375
+
376
+ .TP 5
377
+.I clientcrl.pem
378
+A list of Certificate Revocation Lists (CRLs). If present it
379
+should contain the CRLs of the CAs in 
380
+.I clientca.pem 
381
+and client certs will be checked for revocation.
382
+
383
 .TP 5
384
 .I databytes
385
 Maximum number of bytes allowed in a message,
386
@@ -103,6 +125,18 @@
387
 .B DATABYTES
388
 is set, it overrides
389
 .IR databytes .
390
+
391
+.TP 5
392
+.I dh1024.pem
393
+If these 1024 bit DH parameters are provided,
394
+.B qmail-smtpd
395
+will use them for TLS sessions instead of generating one on-the-fly 
396
+(which is very timeconsuming).
397
+.TP 5
398
+.I dh512.pem
399
+512 bit counterpart for 
400
+.B dh1024.pem. 
401
+
402
 .TP 5
403
 .I localiphost
404
 Replacement host name for local IP addresses.
405
@@ -178,6 +212,19 @@
406
 
407
 Envelope recipient addresses without @ signs are
408
 always allowed through.
409
+
410
+.TP 5
411
+.I rsa512.pem
412
+If this 512 bit RSA key is provided,
413
+.B qmail-smtpd
414
+will use it for TLS sessions instead of generaring one on-the-fly.
415
+
416
+.TP 5
417
+.I servercert.pem
418
+SSL certificate to be presented to clients in TLS-encrypted sessions. 
419
+Should contain both the certificate and the private key. Certifying Authority
420
+(CA) and intermediate certificates can be added at the end of the file.
421
+
422
 .TP 5
423
 .I smtpgreeting
424
 SMTP greeting message.
425
@@ -196,6 +243,24 @@
426
 .B qmail-smtpd
427
 will wait for each new buffer of data from the remote SMTP client.
428
 Default: 1200.
429
+
430
+.TP 5
431
+.I tlsclients
432
+A list of email addresses. When relay rules would reject an incoming message,
433
+.B qmail-smtpd
434
+can allow it if the client presents a certificate that can be verified against
435
+the CA list in
436
+.I clientca.pem
437
+and the certificate email address is in
438
+.IR tlsclients .
439
+
440
+.TP 5
441
+.I tlsserverciphers
442
+A set of OpenSSL cipher strings. Multiple ciphers contained in a
443
+string should be separated by a colon. If the environment variable
444
+.B TLSCIPHERS
445
+is set to such a string, it takes precedence.
446
+
447
 .SH "SEE ALSO"
448
 tcp-env(1),
449
 tcp-environ(5),
450
--- qmail-1.03-orig/ssl_timeoutio.c	1969-12-31 21:00:00.000000000 -0300
451
+++ qmail-1.03/ssl_timeoutio.c	2008-01-24 14:56:54.000000000 -0200
452
@@ -0,0 +1,95 @@
453
+#include "select.h"
454
+#include "error.h"
455
+#include "ndelay.h"
456
+#include "now.h"
457
+#include "ssl_timeoutio.h"
458
+
459
+int ssl_timeoutio(int (*fun)(),
460
+  int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
461
+{
462
+  int n;
463
+  const datetime_sec end = (datetime_sec)t + now();
464
+
465
+  do {
466
+    fd_set fds;
467
+    struct timeval tv;
468
+
469
+    const int r = buf ? fun(ssl, buf, len) : fun(ssl);
470
+    if (r > 0) return r;
471
+
472
+    t = end - now();
473
+    if (t < 0) break;
474
+    tv.tv_sec = (time_t)t; tv.tv_usec = 0;
475
+
476
+    FD_ZERO(&fds);
477
+    switch (SSL_get_error(ssl, r))
478
+    {
479
+    default: return r; /* some other error */
480
+    case SSL_ERROR_WANT_READ:
481
+      FD_SET(rfd, &fds); n = select(rfd + 1, &fds, NULL, NULL, &tv);
482
+      break;
483
+    case SSL_ERROR_WANT_WRITE:
484
+      FD_SET(wfd, &fds); n = select(wfd + 1, NULL, &fds, NULL, &tv);
485
+      break;
486
+    }
487
+
488
+    /* n is the number of descriptors that changed status */
489
+  } while (n > 0);
490
+
491
+  if (n != -1) errno = error_timeout;
492
+  return -1;
493
+}
494
+
495
+int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl)
496
+{
497
+  int r;
498
+
499
+  /* if connection is established, keep NDELAY */
500
+  if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
501
+  r = ssl_timeoutio(SSL_accept, t, rfd, wfd, ssl, NULL, 0);
502
+
503
+  if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
504
+  else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
505
+
506
+  return r;
507
+}
508
+
509
+int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl)
510
+{
511
+  int r;
512
+
513
+  /* if connection is established, keep NDELAY */
514
+  if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
515
+  r = ssl_timeoutio(SSL_connect, t, rfd, wfd, ssl, NULL, 0);
516
+
517
+  if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
518
+  else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
519
+
520
+  return r;
521
+}
522
+
523
+int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl)
524
+{
525
+  int r;
526
+
527
+  SSL_renegotiate(ssl);
528
+  r = ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
529
+  if (r <= 0 || ssl->type == SSL_ST_CONNECT) return r;
530
+
531
+  /* this is for the server only */
532
+  ssl->state = SSL_ST_ACCEPT;
533
+  return ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
534
+}
535
+
536
+int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
537
+{
538
+  if (!buf) return 0;
539
+  if (SSL_pending(ssl)) return SSL_read(ssl, buf, len);
540
+  return ssl_timeoutio(SSL_read, t, rfd, wfd, ssl, buf, len);
541
+}
542
+
543
+int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
544
+{
545
+  if (!buf) return 0;
546
+  return ssl_timeoutio(SSL_write, t, rfd, wfd, ssl, buf, len);
547
+}
548
diff -urN qmail-1.03-orig/ssl_timeoutio.h qmail-1.03/ssl_timeoutio.h
549
--- qmail-1.03-orig/ssl_timeoutio.h	1969-12-31 21:00:00.000000000 -0300
550
+++ qmail-1.03/ssl_timeoutio.h	2008-01-24 14:57:40.000000000 -0200
551
@@ -0,0 +1,21 @@
552
+#ifndef SSL_TIMEOUTIO_H
553
+#define SSL_TIMEOUTIO_H
554
+
555
+#include <openssl/ssl.h>
556
+
557
+/* the version is like this: 0xMNNFFPPS: major minor fix patch status */
558
+#if OPENSSL_VERSION_NUMBER < 0x00906000L
559
+# error "Need OpenSSL version at least 0.9.6"
560
+#endif
561
+
562
+int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl);
563
+int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl);
564
+int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl);
565
+
566
+int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
567
+int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
568
+
569
+int ssl_timeoutio(
570
+  int (*fun)(), int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
571
+
572
+#endif
573
--- qmail-1.03-orig/tls.c	1969-12-31 21:00:00.000000000 -0300
574
+++ qmail-1.03/tls.c	2008-01-24 15:01:09.000000000 -0200
575
@@ -0,0 +1,25 @@
576
+#include "exit.h"
577
+#include "error.h"
578
+#include <openssl/ssl.h>
579
+#include <openssl/err.h>
580
+
581
+int smtps = 0;
582
+SSL *ssl = NULL;
583
+
584
+void ssl_free(SSL *myssl) { SSL_shutdown(myssl); SSL_free(myssl); }
585
+void ssl_exit(int status) { if (ssl) ssl_free(ssl); _exit(status); }
586
+
587
+const char *ssl_error()
588
+{
589
+  int r = ERR_get_error();
590
+  if (!r) return NULL;
591
+  SSL_load_error_strings();
592
+  return ERR_error_string(r, NULL);
593
+}
594
+const char *ssl_error_str()
595
+{
596
+  const char *err = ssl_error();
597
+  if (err) return err;
598
+  if (!errno) return 0;
599
+  return (errno == error_timeout) ? "timed out" : error_str(errno);
600
+}
601
--- qmail-1.03-orig/tls.h	1969-12-31 21:00:00.000000000 -0300
602
+++ qmail-1.03/tls.h	2008-01-24 14:58:30.000000000 -0200
603
@@ -0,0 +1,16 @@
604
+#ifndef TLS_H
605
+#define TLS_H
606
+
607
+#include <openssl/ssl.h>
608
+
609
+extern int smtps;
610
+extern SSL *ssl;
611
+
612
+void ssl_free(SSL *myssl);
613
+void ssl_exit(int status);
614
+# define _exit ssl_exit
615
+
616
+const char *ssl_error();
617
+const char *ssl_error_str();
618
+
619
+#endif
620
--- qmail-1.03-orig/update_tmprsadh.sh	1969-12-31 21:00:00.000000000 -0300
621
+++ qmail-1.03/update_tmprsadh.sh	2008-01-24 14:58:42.000000000 -0200
622
@@ -0,0 +1,25 @@
623
+#!/bin/sh
624
+
625
+# Update temporary RSA and DH keys
626
+# Frederik Vermeulen 2004-05-31 GPL
627
+
628
+umask 0077 || exit 0
629
+
630
+export PATH="$PATH:/usr/local/bin/ssl:/usr/sbin"
631
+
632
+openssl genrsa -out QMAIL/control/rsa512.new 512 &&
633
+chmod 600 QMAIL/control/rsa512.new &&
634
+chown UGQMAILD QMAIL/control/rsa512.new &&
635
+mv -f QMAIL/control/rsa512.new QMAIL/control/rsa512.pem
636
+echo
637
+
638
+openssl dhparam -2 -out QMAIL/control/dh512.new 512 &&
639
+chmod 600 QMAIL/control/dh512.new &&
640
+chown UGQMAILD QMAIL/control/dh512.new &&
641
+mv -f QMAIL/control/dh512.new QMAIL/control/dh512.pem
642
+echo
643
+
644
+openssl dhparam -2 -out QMAIL/control/dh1024.new 1024 &&
645
+chmod 600 QMAIL/control/dh1024.new &&
646
+chown UGQMAILD QMAIL/control/dh1024.new &&
647
+mv -f QMAIL/control/dh1024.new QMAIL/control/dh1024.pem
648
--- qmail-1.03-orig/Makefile	2008-01-24 17:10:07.000000000 -0200
649
+++ qmail-1.03/Makefile	2008-01-24 17:11:30.000000000 -0200
650
@@ -808,7 +808,7 @@
651
 forward preline condredirect bouncesaying except maildirmake \
652
 maildir2mbox maildirwatch qail elq pinq idedit install-big install \
653
 instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
654
-binm3 binm3+df
655
+binm3 binm3+df update_tmprsadh
656
 
657
 load: \
658
 make-load warn-auto.sh systype
659
@@ -1444,6 +1444,7 @@
660
 substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib
661
 	./load qmail-remote control.o constmap.o timeoutread.o \
662
 	timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
663
+	tls.o ssl_timeoutio.o -L/usr/lib -lssl -lcrypto \
664
 	ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
665
 	lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
666
 	str.a fs.a auto_qmail.o  `cat dns.lib` `cat socket.lib`
667
@@ -1539,6 +1540,7 @@
668
 fs.a auto_qmail.o socket.lib
669
 	./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
670
 	timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
671
+	tls.o ssl_timeoutio.o ndelay.a -L/usr/lib -lssl -lcrypto \
672
 	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
673
 	datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
674
 	alloc.a substdio.a error.a str.a fs.a auto_qmail.o  `cat \
675
@@ -1827,7 +1829,8 @@
676
 ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \
677
 ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \
678
 prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \
679
-maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c
680
+maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c \
681
+update_tmprsadh
682
 	shar -m `cat FILES` > shar
683
 	chmod 400 shar
684
 
685
@@ -2108,6 +2111,19 @@
686
 compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h
687
 	./compile timeoutwrite.c
688
 
689
+qmail-smtpd: tls.o ssl_timeoutio.o ndelay.a
690
+qmail-remote: tls.o ssl_timeoutio.o
691
+qmail-smtpd.o: tls.h ssl_timeoutio.h
692
+qmail-remote.o: tls.h ssl_timeoutio.h
693
+
694
+tls.o: \
695
+compile tls.c exit.h error.h
696
+	./compile tls.c
697
+
698
+ssl_timeoutio.o: \
699
+compile ssl_timeoutio.c ssl_timeoutio.h select.h error.h ndelay.h
700
+	./compile ssl_timeoutio.c
701
+
702
 token822.o: \
703
 compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \
704
 gen_alloc.h gen_allocdefs.h
705
@@ -2139,3 +2155,26 @@
706
 wait_pid.o: \
707
 compile wait_pid.c error.h haswaitp.h
708
 	./compile wait_pid.c
709
+
710
+cert cert-req: \
711
+Makefile-cert
712
+	@$(MAKE) -sf $< $@
713
+
714
+Makefile-cert: \
715
+conf-qmail conf-users conf-groups Makefile-cert.mk
716
+	@cat Makefile-cert.mk \
717
+	| sed s}QMAIL}"`head -1 conf-qmail`"}g \
718
+	> $@
719
+
720
+update_tmprsadh: \
721
+conf-qmail conf-users conf-groups update_tmprsadh.sh
722
+	@cat update_tmprsadh.sh\
723
+	| sed s}UGQMAILD}"`head -2 conf-users|tail -1`:`head -1 conf-groups`"}g \
724
+	| sed s}QMAIL}"`head -1 conf-qmail`"}g \
725
+	> $@
726
+	chmod 755 update_tmprsadh
727
+
728
+tmprsadh: \
729
+update_tmprsadh
730
+	echo "Creating new temporary RSA and DH parameters"
731
+	./update_tmprsadh
732
--- qmail-1.03-orig/qmail-remote.c	2008-01-24 17:36:23.000000000 -0200
733
+++ qmail-1.03/qmail-remote.c	2008-01-24 17:45:57.000000000 -0200
734
@@ -48,6 +48,17 @@
735
 
736
 struct ip_address partner;
737
 
738
+#ifdef TLS
739
+# include <sys/stat.h>
740
+# include "tls.h"
741
+# include "ssl_timeoutio.h"
742
+# include <openssl/x509v3.h>
743
+# define EHLO 1
744
+
745
+int tls_init();
746
+const char *ssl_err_str = 0;
747
+#endif 
748
+
749
 void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
750
 void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
751
 void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); }
752
@@ -99,6 +110,9 @@
753
   outhost();
754
   out(" but connection died. ");
755
   if (flagcritical) out("Possible duplicate! ");
756
+#ifdef TLS
757
+  if (ssl_err_str) { out(ssl_err_str); out(" "); }
758
+#endif
759
   out("(#4.4.2)\n");
760
   zerodie();
761
 }
762
@@ -110,6 +124,12 @@
763
 int saferead(fd,buf,len) int fd; char *buf; int len;
764
 {
765
   int r;
766
+#ifdef TLS
767
+  if (ssl) {
768
+    r = ssl_timeoutread(timeout, smtpfd, smtpfd, ssl, buf, len);
769
+    if (r < 0) ssl_err_str = ssl_error_str();
770
+  } else
771
+#endif
772
   r = timeoutread(timeout,smtpfd,buf,len);
773
   if (r <= 0) dropped();
774
   return r;
775
@@ -117,6 +137,12 @@
776
 int safewrite(fd,buf,len) int fd; char *buf; int len;
777
 {
778
   int r;
779
+#ifdef TLS
780
+  if (ssl) {
781
+    r = ssl_timeoutwrite(timeout, smtpfd, smtpfd, ssl, buf, len);
782
+    if (r < 0) ssl_err_str = ssl_error_str();
783
+  } else
784
+#endif 
785
   r = timeoutwrite(timeout,smtpfd,buf,len);
786
   if (r <= 0) dropped();
787
   return r;
788
@@ -163,6 +189,65 @@
789
   return code;
790
 }
791
 
792
+#ifdef EHLO
793
+saa ehlokw = {0}; /* list of EHLO keywords and parameters */
794
+int maxehlokwlen = 0;
795
+
796
+unsigned long ehlo()
797
+{
798
+  stralloc *sa;
799
+  char *s, *e, *p;
800
+  unsigned long code;
801
+
802
+  if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len;
803
+  ehlokw.len = 0;
804
+
805
+# ifdef MXPS
806
+  if (type == 's') return 0;
807
+# endif
808
+
809
+  substdio_puts(&smtpto, "EHLO ");
810
+  substdio_put(&smtpto, helohost.s, helohost.len);
811
+  substdio_puts(&smtpto, "\r\n");
812
+  substdio_flush(&smtpto);
813
+
814
+  code = smtpcode();
815
+  if (code != 250) return code;
816
+
817
+  s = smtptext.s;
818
+  while (*s++ != '\n') ; /* skip the first line: contains the domain */
819
+
820
+  e = smtptext.s + smtptext.len - 6; /* 250-?\n */
821
+  while (s <= e)
822
+  {
823
+    int wasspace = 0;
824
+
825
+    if (!saa_readyplus(&ehlokw, 1)) temp_nomem();
826
+    sa = ehlokw.sa + ehlokw.len++;
827
+    if (ehlokw.len > maxehlokwlen) *sa = sauninit; else sa->len = 0;
828
+
829
+    /* smtptext is known to end in a '\n' */
830
+    for (p = (s += 4); ; ++p)
831
+      if (*p == '\n' || *p == ' ' || *p == '\t') {
832
+        if (!wasspace)
833
+          if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem();
834
+        if (*p == '\n') break;
835
+        wasspace = 1;
836
+      } else if (wasspace == 1) {
837
+        wasspace = 0;
838
+        s = p;
839
+      }
840
+    s = ++p;
841
+
842
+    /* keyword should consist of alpha-num and '-'
843
+     * broken AUTH might use '=' instead of space */
844
+    for (p = sa->s; *p; ++p) if (*p == '=') { *p = 0; break; }
845
+  }
846
+
847
+  return 250;
848
+}
849
+#endif
850
+
851
 void outsmtptext()
852
 {
853
   int i; 
854
@@ -179,6 +264,11 @@
855
 char *prepend;
856
 char *append;
857
 {
858
+#ifdef TLS
859
+  /* shouldn't talk to the client unless in an appropriate state */
860
+  int state = ssl ? ssl->state : SSL_ST_BEFORE;
861
+  if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE))
862
+#endif
863
   substdio_putsflush(&smtpto,"QUIT\r\n");
864
   /* waiting for remote side is just too ridiculous */
865
   out(prepend);
866
@@ -186,6 +276,30 @@
867
   out(append);
868
   out(".\n");
869
   outsmtptext();
870
+
871
+#if defined(TLS) && defined(DEBUG)
872
+  if (ssl) {
873
+    X509 *peercert;
874
+
875
+    out("STARTTLS proto="); out(SSL_get_version(ssl));
876
+    out("; cipher="); out(SSL_get_cipher(ssl));
877
+
878
+    /* we want certificate details */
879
+    if (peercert = SSL_get_peer_certificate(ssl)) {
880
+      char *str;
881
+
882
+      str = X509_NAME_oneline(X509_get_subject_name(peercert), NULL, 0);
883
+      out("; subject="); out(str); OPENSSL_free(str);
884
+
885
+      str = X509_NAME_oneline(X509_get_issuer_name(peercert), NULL, 0);
886
+      out("; issuer="); out(str); OPENSSL_free(str);
887
+
888
+      X509_free(peercert);
889
+    }
890
+    out(";\n");
891
+  }
892
+#endif
893
+
894
   zerodie();
895
 }
896
 
897
@@ -214,6 +328,194 @@
898
   substdio_flush(&smtpto);
899
 }
900
 
901
+#ifdef TLS
902
+char *partner_fqdn = 0;
903
+
904
+# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "")
905
+void tls_quit(const char *s1, const char *s2)
906
+{
907
+  out(s1); if (s2) { out(": "); out(s2); } TLS_QUIT;
908
+}
909
+# define tls_quit_error(s) tls_quit(s, ssl_error())
910
+
911
+int match_partner(const char *s, int len)
912
+{
913
+  if (!case_diffb(partner_fqdn, len, s) && !partner_fqdn[len]) return 1;
914
+  /* we also match if the name is *.domainname */
915
+  if (*s == '*') {
916
+    const char *domain = partner_fqdn + str_chr(partner_fqdn, '.');
917
+    if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1;
918
+  }
919
+  return 0;
920
+}
921
+
922
+/* don't want to fail handshake if certificate can't be verified */
923
+int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
924
+
925
+int tls_init()
926
+{
927
+  int i;
928
+  SSL *myssl;
929
+  SSL_CTX *ctx;
930
+  stralloc saciphers = {0};
931
+  const char *ciphers, *servercert = 0;
932
+
933
+  if (partner_fqdn) {
934
+    struct stat st;
935
+    stralloc tmp = {0};
936
+    if (!stralloc_copys(&tmp, "control/tlshosts/")
937
+      || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn))
938
+      || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem();
939
+    if (stat(tmp.s, &st) == 0)
940
+      servercert = tmp.s;
941
+    else {
942
+      if (!stralloc_copys(&tmp, "control/notlshosts/")
943
+        || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1))
944
+        temp_nomem();
945
+      if ((stat("control/tlshosts/exhaustivelist", &st) == 0) ||
946
+         (stat(tmp.s, &st) == 0)) {
947
+         alloc_free(tmp.s);
948
+         return 0;
949
+      }
950
+      alloc_free(tmp.s);
951
+    }
952
+  }
953
+ 
954
+  if (!smtps) {
955
+    stralloc *sa = ehlokw.sa;
956
+    unsigned int len = ehlokw.len;
957
+    /* look for STARTTLS among EHLO keywords */
958
+    for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ;
959
+    if (!len) {
960
+      if (!servercert) return 0;
961
+      out("ZNo TLS achieved while "); out(servercert);
962
+      out(" exists"); smtptext.len = 0; TLS_QUIT;
963
+    }
964
+  }
965
+
966
+  SSL_library_init();
967
+  ctx = SSL_CTX_new(SSLv23_client_method());
968
+  if (!ctx) {
969
+    if (!smtps && !servercert) return 0;
970
+    smtptext.len = 0;
971
+    tls_quit_error("ZTLS error initializing ctx");
972
+  }
973
+
974
+  if (servercert) {
975
+    if (!SSL_CTX_load_verify_locations(ctx, servercert, NULL)) {
976
+      SSL_CTX_free(ctx);
977
+      smtptext.len = 0;
978
+      out("ZTLS unable to load "); tls_quit_error(servercert);
979
+    }
980
+    /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
981
+    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
982
+  }
983
+
984
+  /* let the other side complain if it needs a cert and we don't have one */
985
+# define CLIENTCERT "control/clientcert.pem"
986
+  if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT))
987
+    SSL_CTX_use_RSAPrivateKey_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM);
988
+# undef CLIENTCERT
989
+
990
+  myssl = SSL_new(ctx);
991
+  SSL_CTX_free(ctx);
992
+  if (!myssl) {
993
+    if (!smtps && !servercert) return 0;
994
+    smtptext.len = 0;
995
+    tls_quit_error("ZTLS error initializing ssl");
996
+  }
997
+
998
+  if (!smtps) substdio_putsflush(&smtpto, "STARTTLS\r\n");
999
+
1000
+  /* while the server is preparing a responce, do something else */
1001
+  if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1)
1002
+    { SSL_free(myssl); temp_control(); }
1003
+  if (saciphers.len) {
1004
+    for (i = 0; i < saciphers.len - 1; ++i)
1005
+      if (!saciphers.s[i]) saciphers.s[i] = ':';
1006
+    ciphers = saciphers.s;
1007
+  }
1008
+  else ciphers = "DEFAULT";
1009
+  SSL_set_cipher_list(myssl, ciphers);
1010
+  alloc_free(saciphers.s);
1011
+
1012
+  /* SSL_set_options(myssl, SSL_OP_NO_TLSv1); */
1013
+  SSL_set_fd(myssl, smtpfd);
1014
+
1015
+  /* read the responce to STARTTLS */
1016
+  if (!smtps) {
1017
+    if (smtpcode() != 220) {
1018
+      SSL_free(myssl);
1019
+      if (!servercert) return 0;
1020
+      out("ZSTARTTLS rejected while ");
1021
+      out(servercert); out(" exists"); TLS_QUIT;
1022
+    }
1023
+    smtptext.len = 0;
1024
+  }
1025
+
1026
+  ssl = myssl;
1027
+  if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0)
1028
+    tls_quit("ZTLS connect failed", ssl_error_str());
1029
+
1030
+  if (servercert) {
1031
+    X509 *peercert;
1032
+    STACK_OF(GENERAL_NAME) *gens;
1033
+
1034
+    int r = SSL_get_verify_result(ssl);
1035
+    if (r != X509_V_OK) {
1036
+      out("ZTLS unable to verify server with ");
1037
+      tls_quit(servercert, X509_verify_cert_error_string(r));
1038
+    }
1039
+    alloc_free(servercert);
1040
+
1041
+    peercert = SSL_get_peer_certificate(ssl);
1042
+    if (!peercert) {
1043
+      out("ZTLS unable to verify server ");
1044
+      tls_quit(partner_fqdn, "no certificate provided");
1045
+    }
1046
+
1047
+    /* RFC 2595 section 2.4: find a matching name
1048
+     * first find a match among alternative names */
1049
+    gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
1050
+    if (gens) {
1051
+      for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i)
1052
+      {
1053
+        const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
1054
+        if (gn->type == GEN_DNS)
1055
+          if (match_partner(gn->d.ia5->data, gn->d.ia5->length)) break;
1056
+      }
1057
+      sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
1058
+    }
1059
+
1060
+    /* no alternative name matched, look up commonName */
1061
+    if (!gens || i >= r) {
1062
+      stralloc peer = {0};
1063
+      X509_NAME *subj = X509_get_subject_name(peercert);
1064
+      i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
1065
+      if (i >= 0) {
1066
+        const ASN1_STRING *s = X509_NAME_get_entry(subj, i)->value;
1067
+        if (s) { peer.len = s->length; peer.s = s->data; }
1068
+      }
1069
+      if (peer.len <= 0) {
1070
+        out("ZTLS unable to verify server ");
1071
+        tls_quit(partner_fqdn, "certificate contains no valid commonName");
1072
+      }
1073
+      if (!match_partner(peer.s, peer.len)) {
1074
+        out("ZTLS unable to verify server "); out(partner_fqdn);
1075
+        out(": received certificate for "); outsafe(&peer); TLS_QUIT;
1076
+      }
1077
+    }
1078
+
1079
+    X509_free(peercert);
1080
+  }
1081
+
1082
+  if (smtps) if (smtpcode() != 220)
1083
+    quit("ZTLS Connected to "," but greeting failed");
1084
+
1085
+  return 1;
1086
+}
1087
+#endif
1088
+
1089
 stralloc recip = {0};
1090
 
1091
 void smtp()
1092
@@ -221,15 +523,57 @@
1093
   unsigned long code;
1094
   int flagbother;
1095
   int i;
1096
- 
1097
-  if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
1098
- 
1099
+
1100
+#ifndef PORT_SMTP
1101
+  /* the qmtpc patch uses smtp_port and undefines PORT_SMTP */
1102
+# define port smtp_port
1103
+#endif
1104
+
1105
+#ifdef TLS
1106
+# ifdef MXPS
1107
+  if (type == 'S') smtps = 1;
1108
+  else if (type != 's')
1109
+# endif
1110
+    if (port == 465) smtps = 1;
1111
+  if (!smtps)
1112
+#endif
1113
+
1114
+    code = smtpcode();
1115
+    if (code >= 500 && code < 600) quit("DConnected to "," but greeting failed");
1116
+    if (code >= 400 && code < 500) return; /* try next MX, see RFC-2821 */
1117
+    if (code != 220) quit("ZConnected to "," but greeting failed");
1118
+
1119
+#ifdef EHLO
1120
+# ifdef TLS
1121
+  if (!smtps)
1122
+# endif
1123
+  code = ehlo();
1124
+
1125
+# ifdef TLS
1126
+  if (tls_init())
1127
+    /* RFC2487 says we should issue EHLO (even if we might not need
1128
+     * extensions); at the same time, it does not prohibit a server
1129
+     * to reject the EHLO and make us fallback to HELO */
1130
+    code = ehlo();
1131
+# endif
1132
+
1133
+  if (code == 250) {
1134
+    /* add EHLO response checks here */
1135
+
1136
+    /* and if EHLO failed, use HELO */
1137
+  } else {
1138
+#endif
1139
+
1140
   substdio_puts(&smtpto,"HELO ");
1141
   substdio_put(&smtpto,helohost.s,helohost.len);
1142
   substdio_puts(&smtpto,"\r\n");
1143
   substdio_flush(&smtpto);
1144
   if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
1145
  
1146
+#ifdef EHLO
1147
+  }
1148
+#endif
1149
+
1150
   substdio_puts(&smtpto,"MAIL FROM:<");
1151
   substdio_put(&smtpto,sender.s,sender.len);
1152
   substdio_puts(&smtpto,">\r\n");
1153
@@ -417,7 +761,10 @@
1154
     if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
1155
       tcpto_err(&ip.ix[i].ip,0);
1156
       partner = ip.ix[i].ip;
1157
-      smtp(); /* does not return */
1158
+#ifdef TLS
1159
+      partner_fqdn = ip.ix[i].fqdn;
1160
+#endif
1161
+      smtp(); /* only returns when the next MX is to be tried */
1162
     }
1163
     tcpto_err(&ip.ix[i].ip,errno == error_timeout);
1164
     close(smtpfd);
1165
--- qmail-1.03-orig/qmail-smtpd.c	2008-01-24 18:15:42.000000000 -0200
1166
+++ qmail-1.03/qmail-smtpd.c	2008-01-24 18:16:54.000000000 -0200
1167
@@ -28,9 +28,27 @@
1168
 unsigned int databytes = 0;
1169
 int timeout = 1200;
1170
 
1171
+const char *protocol = "SMTP";
1172
+
1173
+#ifdef TLS
1174
+# include <sys/stat.h>
1175
+# include "tls.h"
1176
+# include "ssl_timeoutio.h"
1177
+
1178
+void tls_init();
1179
+int tls_verify();
1180
+void tls_nogateway();
1181
+int ssl_rfd = -1, ssl_wfd = -1; /* SSL_get_Xfd() are broken */
1182
+#endif
1183
+
1184
 int safewrite(fd,buf,len) int fd; char *buf; int len;
1185
 {
1186
   int r;
1187
+#ifdef TLS
1188
+  if (ssl && fd == ssl_wfd)
1189
+    r = ssl_timeoutwrite(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
1190
+  else
1191
+#endif
1192
   r = timeoutwrite(timeout,fd,buf,len);
1193
   if (r <= 0) _exit(1);
1194
   return r;
1195
@@ -50,7 +68,16 @@
1196
 void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
1197
 
1198
 void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
1199
+#ifndef TLS
1200
 void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
1201
+#else
1202
+void err_nogateway()
1203
+{
1204
+  out("553 sorry, that domain isn't in my list of allowed rcpthosts");
1205
+  tls_nogateway();
1206
+  out(" (#5.7.1)\r\n");
1207
+}
1208
+#endif
1209
 void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
1210
 void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
1211
 void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
1212
@@ -131,6 +158,11 @@
1213
   if (!remotehost) remotehost = "unknown";
1214
   remoteinfo = env_get("TCPREMOTEINFO");
1215
   relayclient = env_get("RELAYCLIENT");
1216
+
1217
+#ifdef TLS
1218
+  if (env_get("SMTPS")) { smtps = 1; tls_init(); }
1219
+  else
1220
+#endif
1221
   dohelo(remotehost);
1222
 }
1223
 
1224
@@ -213,6 +245,9 @@
1225
   int r;
1226
   r = rcpthosts(addr.s,str_len(addr.s));
1227
   if (r == -1) die_control();
1228
+#ifdef TLS
1229
+  if (r == 0) if (tls_verify()) r = -2;
1230
+#endif
1231
   return r;
1232
 }
1233
 
1234
@@ -227,9 +262,18 @@
1235
   smtp_greet("250 "); out("\r\n");
1236
   seenmail = 0; dohelo(arg);
1237
 }
1238
+/* ESMTP extensions are published here */
1239
 void smtp_ehlo(arg) char *arg;
1240
 {
1241
-  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
1242
+#ifdef TLS
1243
+  struct stat st;
1244
+#endif
1245
+  smtp_greet("250-");
1246
+#ifdef TLS
1247
+  if (!ssl && (stat("control/servercert.pem",&st) == 0))
1248
+    out("\r\n250-STARTTLS");
1249
+#endif
1250
+  out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
1251
   seenmail = 0; dohelo(arg);
1252
 }
1253
 void smtp_rset()
1254
@@ -269,6 +313,11 @@
1255
 {
1256
   int r;
1257
   flush();
1258
+#ifdef TLS
1259
+  if (ssl && fd == ssl_rfd)
1260
+    r = ssl_timeoutread(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
1261
+  else
1262
+#endif
1263
   r = timeoutread(timeout,fd,buf,len);
1264
   if (r == -1) if (errno == error_timeout) die_alarm();
1265
   if (r <= 0) die_read();
1266
@@ -378,7 +427,7 @@
1267
   qp = qmail_qp(&qqt);
1268
   out("354 go ahead\r\n");
1269
  
1270
-  received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
1271
+  received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
1272
   blast(&hops);
1273
   hops = (hops >= MAXHOPS);
1274
   if (hops) qmail_fail(&qqt);
1275
@@ -394,6 +443,240 @@
1276
   out("\r\n");
1277
 }
1278
 
1279
+#ifdef TLS
1280
+stralloc proto = {0};
1281
+int ssl_verified = 0;
1282
+const char *ssl_verify_err = 0;
1283
+
1284
+void smtp_tls(char *arg)
1285
+{
1286
+  if (ssl) err_unimpl();
1287
+  else if (*arg) out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n");
1288
+  else tls_init();
1289
+}
1290
+
1291
+RSA *tmp_rsa_cb(SSL *ssl, int export, int keylen)
1292
+{
1293
+  if (!export) keylen = 512;
1294
+  if (keylen == 512) {
1295
+    FILE *in = fopen("control/rsa512.pem", "r");
1296
+    if (in) {
1297
+      RSA *rsa = PEM_read_RSAPrivateKey(in, NULL, NULL, NULL);
1298
+      fclose(in);
1299
+      if (rsa) return rsa;
1300
+    }
1301
+  }
1302
+  return RSA_generate_key(keylen, RSA_F4, NULL, NULL);
1303
+}
1304
+
1305
+DH *tmp_dh_cb(SSL *ssl, int export, int keylen)
1306
+{
1307
+  if (!export) keylen = 1024;
1308
+  if (keylen == 512) {
1309
+    FILE *in = fopen("control/dh512.pem", "r");
1310
+    if (in) {
1311
+      DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
1312
+      fclose(in);
1313
+      if (dh) return dh;
1314
+    }
1315
+  }
1316
+  if (keylen == 1024) {
1317
+    FILE *in = fopen("control/dh1024.pem", "r");
1318
+    if (in) {
1319
+      DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
1320
+      fclose(in);
1321
+      if (dh) return dh;
1322
+    }
1323
+  }
1324
+  return DH_generate_parameters(keylen, DH_GENERATOR_2, NULL, NULL);
1325
+}
1326
+
1327
+/* don't want to fail handshake if cert isn't verifiable */
1328
+int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
1329
+
1330
+void tls_nogateway()
1331
+{
1332
+  /* there may be cases when relayclient is set */
1333
+  if (!ssl || relayclient) return;
1334
+  out("; no valid cert for gatewaying");
1335
+  if (ssl_verify_err) { out(": "); out(ssl_verify_err); }
1336
+}
1337
+void tls_out(const char *s1, const char *s2)
1338
+{
1339
+  out("454 TLS "); out(s1);
1340
+  if (s2) { out(": "); out(s2); }
1341
+  out(" (#4.3.0)\r\n"); flush();
1342
+}
1343
+void tls_err(const char *s) { tls_out(s, ssl_error()); if (smtps) die_read(); }
1344
+
1345
+# define CLIENTCA "control/clientca.pem"
1346
+# define CLIENTCRL "control/clientcrl.pem"
1347
+# define SERVERCERT "control/servercert.pem"
1348
+
1349
+int tls_verify()
1350
+{
1351
+  stralloc clients = {0};
1352
+  struct constmap mapclients;
1353
+
1354
+  if (!ssl || relayclient || ssl_verified) return 0;
1355
+  ssl_verified = 1; /* don't do this twice */
1356
+
1357
+  /* request client cert to see if it can be verified by one of our CAs
1358
+   * and the associated email address matches an entry in tlsclients */
1359
+  switch (control_readfile(&clients, "control/tlsclients", 0))
1360
+  {
1361
+  case 1:
1362
+    if (constmap_init(&mapclients, clients.s, clients.len, 0)) {
1363
+      /* if CLIENTCA contains all the standard root certificates, a
1364
+       * 0.9.6b client might fail with SSL_R_EXCESSIVE_MESSAGE_SIZE;
1365
+       * it is probably due to 0.9.6b supporting only 8k key exchange
1366
+       * data while the 0.9.6c release increases that limit to 100k */
1367
+      STACK_OF(X509_NAME) *sk = SSL_load_client_CA_file(CLIENTCA);
1368
+      if (sk) {
1369
+        SSL_set_client_CA_list(ssl, sk);
1370
+        SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
1371
+        break;
1372
+      }
1373
+      constmap_free(&mapclients);
1374
+    }
1375
+  case 0: alloc_free(clients.s); return 0;
1376
+  case -1: die_control();
1377
+  }
1378
+
1379
+  if (ssl_timeoutrehandshake(timeout, ssl_rfd, ssl_wfd, ssl) <= 0) {
1380
+    const char *err = ssl_error_str();
1381
+    tls_out("rehandshake failed", err); die_read();
1382
+  }
1383
+
1384
+  do { /* one iteration */
1385
+    X509 *peercert;
1386
+    X509_NAME *subj;
1387
+    stralloc email = {0};
1388
+
1389
+    int n = SSL_get_verify_result(ssl);
1390
+    if (n != X509_V_OK)
1391
+      { ssl_verify_err = X509_verify_cert_error_string(n); break; }
1392
+    peercert = SSL_get_peer_certificate(ssl);
1393
+    if (!peercert) break;
1394
+
1395
+    subj = X509_get_subject_name(peercert);
1396
+    n = X509_NAME_get_index_by_NID(subj, NID_pkcs9_emailAddress, -1);
1397
+    if (n >= 0) {
1398
+      const ASN1_STRING *s = X509_NAME_get_entry(subj, n)->value;
1399
+      if (s) { email.len = s->length; email.s = s->data; }
1400
+    }
1401
+
1402
+    if (email.len <= 0)
1403
+      ssl_verify_err = "contains no email address";
1404
+    else if (!constmap(&mapclients, email.s, email.len))
1405
+      ssl_verify_err = "email address not in my list of tlsclients";
1406
+    else {
1407
+      /* add the cert email to the proto if it helped allow relaying */
1408
+      --proto.len;
1409
+      if (!stralloc_cats(&proto, "\n (cert ") /* continuation line */
1410
+        || !stralloc_catb(&proto, email.s, email.len)
1411
+        || !stralloc_cats(&proto, ")")
1412
+        || !stralloc_0(&proto)) die_nomem();
1413
+      relayclient = "";
1414
+      protocol = proto.s;
1415
+    }
1416
+
1417
+    X509_free(peercert);
1418
+  } while (0);
1419
+  constmap_free(&mapclients); alloc_free(clients.s);
1420
+
1421
+  /* we are not going to need this anymore: free the memory */
1422
+  SSL_set_client_CA_list(ssl, NULL);
1423
+  SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
1424
+
1425
+  return relayclient ? 1 : 0;
1426
+}
1427
+
1428
+void tls_init()
1429
+{
1430
+  SSL *myssl;
1431
+  SSL_CTX *ctx;
1432
+  const char *ciphers;
1433
+  stralloc saciphers = {0};
1434
+  X509_STORE *store;
1435
+  X509_LOOKUP *lookup;
1436
+
1437
+  SSL_library_init();
1438
+
1439
+  /* a new SSL context with the bare minimum of options */
1440
+  ctx = SSL_CTX_new(SSLv23_server_method());
1441
+  if (!ctx) { tls_err("unable to initialize ctx"); return; }
1442
+
1443
+  if (!SSL_CTX_use_certificate_chain_file(ctx, SERVERCERT))
1444
+    { SSL_CTX_free(ctx); tls_err("missing certificate"); return; }
1445
+  SSL_CTX_load_verify_locations(ctx, CLIENTCA, NULL);
1446
+
1447
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
1448
+  /* crl checking */
1449
+  store = SSL_CTX_get_cert_store(ctx);
1450
+  if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) &&
1451
+      (X509_load_crl_file(lookup, CLIENTCRL, X509_FILETYPE_PEM) == 1))
1452
+    X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1453
+                                X509_V_FLAG_CRL_CHECK_ALL);
1454
+#endif
1455
+
1456
+  /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
1457
+  SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_cb);
1458
+
1459
+  /* a new SSL object, with the rest added to it directly to avoid copying */
1460
+  myssl = SSL_new(ctx);
1461
+  SSL_CTX_free(ctx);
1462
+  if (!myssl) { tls_err("unable to initialize ssl"); return; }
1463
+
1464
+  /* this will also check whether public and private keys match */
1465
+  if (!SSL_use_RSAPrivateKey_file(myssl, SERVERCERT, SSL_FILETYPE_PEM))
1466
+    { SSL_free(myssl); tls_err("no valid RSA private key"); return; }
1467
+
1468
+  ciphers = env_get("TLSCIPHERS");
1469
+  if (!ciphers) {
1470
+    if (control_readfile(&saciphers, "control/tlsserverciphers", 0) == -1)
1471
+      { SSL_free(myssl); die_control(); }
1472
+    if (saciphers.len) { /* convert all '\0's except the last one to ':' */
1473
+      int i;
1474
+      for (i = 0; i < saciphers.len - 1; ++i)
1475
+        if (!saciphers.s[i]) saciphers.s[i] = ':';
1476
+      ciphers = saciphers.s;
1477
+    }
1478
+  }
1479
+  if (!ciphers || !*ciphers) ciphers = "DEFAULT";
1480
+  SSL_set_cipher_list(myssl, ciphers);
1481
+  alloc_free(saciphers.s);
1482
+
1483
+  SSL_set_tmp_rsa_callback(myssl, tmp_rsa_cb);
1484
+  SSL_set_tmp_dh_callback(myssl, tmp_dh_cb);
1485
+  SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin));
1486
+  SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout));
1487
+
1488
+  if (!smtps) { out("220 ready for tls\r\n"); flush(); }
1489
+
1490
+  if (ssl_timeoutaccept(timeout, ssl_rfd, ssl_wfd, myssl) <= 0) {
1491
+    /* neither cleartext nor any other response here is part of a standard */
1492
+    const char *err = ssl_error_str();
1493
+    ssl_free(myssl); tls_out("connection failed", err); die_read();
1494
+  }
1495
+  ssl = myssl;
1496
+
1497
+  /* populate the protocol string, used in Received */
1498
+  if (!stralloc_copys(&proto, SSL_get_cipher(ssl))
1499
+    || !stralloc_cats(&proto, " encrypted SMTP")) die_nomem();
1500
+  if (smtps) if (!stralloc_append(&proto, "S")) die_nomem();
1501
+  if (!stralloc_0(&proto)) die_nomem();
1502
+  protocol = proto.s;
1503
+
1504
+  /* have to discard the pre-STARTTLS HELO/EHLO argument, if any */
1505
+  dohelo(remotehost);
1506
+}
1507
+
1508
+# undef SERVERCERT
1509
+# undef CLIENTCA
1510
+
1511
+#endif
1512
+
1513
 struct commands smtpcommands[] = {
1514
   { "rcpt", smtp_rcpt, 0 }
1515
 , { "mail", smtp_mail, 0 }
1516
@@ -403,6 +686,9 @@
1517
 , { "ehlo", smtp_ehlo, flush }
1518
 , { "rset", smtp_rset, 0 }
1519
 , { "help", smtp_help, flush }
1520
+#ifdef TLS
1521
+, { "starttls", smtp_tls, flush }
1522
+#endif
1523
 , { "noop", err_noop, flush }
1524
 , { "vrfy", err_vrfy, flush }
1525
 , { 0, err_unimpl, flush }

Return to bug 119954