1 |
Frederik Vermeulen <qmail-tls akrul inoa.net> 20160918 |
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-1.0.2 http://www.openssl.org/ or later |
11 |
(any version since 0.9.6 is presumed to work) |
12 |
- apply patch to netqmail-1.06 http://qmail.org/netqmail |
13 |
The patches to qmail-remote.c and qmail-smtpd.c can be applied |
14 |
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 |
|
25 |
Optional: - when DEBUG is defined, some extra TLS info will be logged |
26 |
- qmail-remote will authenticate with the certificate in |
27 |
/var/qmail/control/clientcert.pem. By preference this is |
28 |
the same as servercert.pem, where nsCertType should be |
29 |
== server,client or be a generic certificate (no usage specified). |
30 |
- when a 2048 bit RSA key is provided in /var/qmail/control/rsa2048.pem, |
31 |
this key will be used instead of (slow) on-the-fly generation by |
32 |
qmail-smtpd. Idem for 2048 DH param in control/dh2048.pem. |
33 |
`make tmprsadh` does this. |
34 |
Periodical replacement can be done by crontab: |
35 |
01 01 * * * /var/qmail/bin/update_tmprsadh > /dev/null 2>&1 |
36 |
- server authentication: |
37 |
qmail-remote requires authentication from servers for which |
38 |
/var/qmail/control/tlshosts/host.dom.ain.pem exists. |
39 |
The .pem file contains the validating CA certificates. |
40 |
One of the dNSName or the CommonName attributes have to match. |
41 |
WARNING: this option may cause mail to be delayed, bounced, |
42 |
doublebounced, and lost. |
43 |
If /var/qmail/control/tlshosts/exhaustivelist is present, |
44 |
the lists of hosts in /var/qmail/control/tlshosts is |
45 |
an exhaustive list of hosts TLS is tried on. |
46 |
If /var/qmail/control/notlshosts/host.dom.ain is present, |
47 |
no TLS is tried on this host. |
48 |
- client authentication: |
49 |
when relay rules would reject an incoming mail, |
50 |
qmail-smtpd can allow the mail based on a presented cert. |
51 |
Certs are verified against a CA list in |
52 |
/var/qmail/control/clientca.pem (eg. from |
53 |
http://curl.haxx.se/ca/cacert.pem) |
54 |
and the cert email-address has to match a line in |
55 |
/var/qmail/control/tlsclients. This email-address is logged |
56 |
in the headers. CRLs can be provided through |
57 |
/var/qmail/control/clientcrl.pem. |
58 |
- cipher selection: |
59 |
qmail-remote: |
60 |
openssl cipher string (`man ciphers`) read from |
61 |
/var/qmail/control/tlsclientciphers |
62 |
qmail-smtpd: |
63 |
openssl cipher string read from TLSCIPHERS environment variable |
64 |
(can vary based on client IP address e.g.) |
65 |
or if that is not available /var/qmail/control/tlsserverciphers |
66 |
- smtps (deprecated SMTP over TLS via port 465): |
67 |
qmail-remote: when connecting to port 465 |
68 |
qmail-smtpd: when SMTPS environment variable is not empty |
69 |
|
70 |
Caveats: - do a `make clean` after patching |
71 |
- binaries dynamically linked with current openssl versions need |
72 |
recompilation when the shared openssl libs are upgraded. |
73 |
- this patch could conflict with other patches (notably those |
74 |
replacing \n with \r\n, which is a bad idea on encrypted links). |
75 |
- some broken servers have a problem with TLSv1 compatibility. |
76 |
Uncomment the line where we set the SSL_OP_NO_TLSv1 option. |
77 |
- needs working /dev/urandom (or EGD for openssl versions >0.9.7) |
78 |
for seeding random number generator. |
79 |
- packagers should make sure that installing without a valid |
80 |
servercert is impossible |
81 |
- when applied in combination with AUTH patch, AUTH patch |
82 |
should be applied first and first part of this patch |
83 |
will fail. This error can be ignored. Packagers should |
84 |
cut the first 12 lines of this patch to make a happy |
85 |
patch |
86 |
- `make tmprsadh` is recommended (or should I say required), |
87 |
otherwise DH generation can be unpredictably slow |
88 |
- some need "-I/usr/kerberos/include" to be added in conf-cc |
89 |
|
90 |
Copyright: GPL |
91 |
Links with OpenSSL |
92 |
Inspiration and code from examples in SSLeay (E. Young |
93 |
<eay@cryptsoft.com> and T. Hudson <tjh@cryptsoft.com>), |
94 |
stunnel (M. Trojnara <mtrojnar@ddc.daewoo.com.pl>), |
95 |
Postfix/TLS (L. Jaenicke <Lutz.Jaenicke@aet.tu-cottbus.de>), |
96 |
modssl (R. Engelschall <rse@engelschall.com>), |
97 |
openssl examples of E. Rescorla <ekr@rtfm.com>. |
98 |
|
99 |
Bug reports: mailto:<qmail-tls akrul inoa.net> |
100 |
|
101 |
|
102 |
>----< Cut the next 12 lines if applying over AUTH server patch >---< |
103 |
--- qmail-1.03/qmail-smtpd.c Mon Jun 15 03:53:16 1998 |
104 |
+++ qmail-1.03-tls/qmail-smtpd.c Tue Jun 18 09:49:38 2002 |
105 |
@@ -229,7 +229,8 @@ |
106 |
} |
107 |
void smtp_ehlo(arg) char *arg; |
108 |
{ |
109 |
- smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); |
110 |
+ smtp_greet("250-"); |
111 |
+ out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); |
112 |
seenmail = 0; dohelo(arg); |
113 |
} |
114 |
void smtp_rset() |
115 |
>----< Cut previous 12 lines if applying over AUTH server patch >---< |
116 |
|
117 |
|
118 |
|
119 |
>----< The next 89 lines are the qmail-remote EHLO patch >---< |
120 |
--- qmail-1.03/qmail-remote.c Mon Jun 15 03:53:16 1998 |
121 |
+++ qmail-1.03-tls/qmail-remote.c Sun Nov 24 13:05:20 2002 |
122 |
@@ -163,6 +163,59 @@ unsigned long smtpcode() |
123 |
return code; |
124 |
} |
125 |
|
126 |
+#ifdef EHLO |
127 |
+saa ehlokw = {0}; /* list of EHLO keywords and parameters */ |
128 |
+int maxehlokwlen = 0; |
129 |
+ |
130 |
+unsigned long ehlo() |
131 |
+{ |
132 |
+ stralloc *sa; |
133 |
+ char *s, *e, *p; |
134 |
+ unsigned long code; |
135 |
+ |
136 |
+ if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len; |
137 |
+ ehlokw.len = 0; |
138 |
+ |
139 |
+# ifdef MXPS |
140 |
+ if (type == 's') return 0; |
141 |
+# endif |
142 |
+ |
143 |
+ substdio_puts(&smtpto, "EHLO "); |
144 |
+ substdio_put(&smtpto, helohost.s, helohost.len); |
145 |
+ substdio_puts(&smtpto, "\r\n"); |
146 |
+ substdio_flush(&smtpto); |
147 |
+ |
148 |
+ code = smtpcode(); |
149 |
+ if (code != 250) return code; |
150 |
+ |
151 |
+ s = smtptext.s; |
152 |
+ while (*s++ != '\n') ; /* skip the first line: contains the domain */ |
153 |
+ |
154 |
+ e = smtptext.s + smtptext.len - 6; /* 250-?\n */ |
155 |
+ while (s <= e) |
156 |
+ { |
157 |
+ if (!saa_readyplus(&ehlokw, 1)) temp_nomem(); |
158 |
+ sa = ehlokw.sa + ehlokw.len++; |
159 |
+ if (ehlokw.len > maxehlokwlen) *sa = sauninit; else sa->len = 0; |
160 |
+ |
161 |
+ /* smtptext is known to end in a '\n' */ |
162 |
+ for (p = (s += 4); ; ++p) |
163 |
+ if (*p == '\n' || *p == ' ' || *p == '\t') { |
164 |
+ if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem(); |
165 |
+ if (*p++ == '\n') break; |
166 |
+ while (*p == ' ' || *p == '\t') ; |
167 |
+ s = p; |
168 |
+ } |
169 |
+ s = p; |
170 |
+ /* keyword should consist of alpha-num and '-' |
171 |
+ * broken AUTH might use '=' instead of space */ |
172 |
+ for (p = sa->s; *p; ++p) if (*p == '=') { *p = 0; break; } |
173 |
+ } |
174 |
+ |
175 |
+ return 250; |
176 |
+} |
177 |
+#endif |
178 |
+ |
179 |
void outsmtptext() |
180 |
{ |
181 |
int i; |
182 |
@@ -224,12 +277,26 @@ void smtp() |
183 |
|
184 |
if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); |
185 |
|
186 |
+#ifdef EHLO |
187 |
+ code = ehlo(); |
188 |
+ |
189 |
+ if (code == 250) { |
190 |
+ /* add EHLO response checks here */ |
191 |
+ |
192 |
+ /* and if EHLO failed, use HELO */ |
193 |
+ } else { |
194 |
+#endif |
195 |
+ |
196 |
substdio_puts(&smtpto,"HELO "); |
197 |
substdio_put(&smtpto,helohost.s,helohost.len); |
198 |
substdio_puts(&smtpto,"\r\n"); |
199 |
substdio_flush(&smtpto); |
200 |
if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); |
201 |
|
202 |
+#ifdef EHLO |
203 |
+ } |
204 |
+#endif |
205 |
+ |
206 |
substdio_puts(&smtpto,"MAIL FROM:<"); |
207 |
substdio_put(&smtpto,sender.s,sender.len); |
208 |
substdio_puts(&smtpto,">\r\n"); |
209 |
>----< Previous 89 lines are the qmail-remote EHLO patch >---< |
210 |
|
211 |
|
212 |
|
213 |
--- netqmail-1.06-orig/qmail-remote.c 2016-09-18 10:04:24.690101666 +0000 |
214 |
+++ netqmail-1.06/qmail-remote.c 2016-09-18 09:49:43.206842686 +0000 |
215 |
@@ -48,6 +48,17 @@ saa reciplist = {0}; |
216 |
|
217 |
struct ip_address partner; |
218 |
|
219 |
+#ifdef TLS |
220 |
+# include <sys/stat.h> |
221 |
+# include "tls.h" |
222 |
+# include "ssl_timeoutio.h" |
223 |
+# include <openssl/x509v3.h> |
224 |
+# define EHLO 1 |
225 |
+ |
226 |
+int tls_init(); |
227 |
+const char *ssl_err_str = 0; |
228 |
+#endif |
229 |
+ |
230 |
void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } |
231 |
void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } |
232 |
void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); } |
233 |
@@ -99,6 +110,9 @@ void dropped() { |
234 |
outhost(); |
235 |
out(" but connection died. "); |
236 |
if (flagcritical) out("Possible duplicate! "); |
237 |
+#ifdef TLS |
238 |
+ if (ssl_err_str) { out(ssl_err_str); out(" "); } |
239 |
+#endif |
240 |
out("(#4.4.2)\n"); |
241 |
zerodie(); |
242 |
} |
243 |
@@ -110,6 +124,12 @@ int timeout = 1200; |
244 |
int saferead(fd,buf,len) int fd; char *buf; int len; |
245 |
{ |
246 |
int r; |
247 |
+#ifdef TLS |
248 |
+ if (ssl) { |
249 |
+ r = ssl_timeoutread(timeout, smtpfd, smtpfd, ssl, buf, len); |
250 |
+ if (r < 0) ssl_err_str = ssl_error_str(); |
251 |
+ } else |
252 |
+#endif |
253 |
r = timeoutread(timeout,smtpfd,buf,len); |
254 |
if (r <= 0) dropped(); |
255 |
return r; |
256 |
@@ -117,6 +137,12 @@ int saferead(fd,buf,len) int fd; char *b |
257 |
int safewrite(fd,buf,len) int fd; char *buf; int len; |
258 |
{ |
259 |
int r; |
260 |
+#ifdef TLS |
261 |
+ if (ssl) { |
262 |
+ r = ssl_timeoutwrite(timeout, smtpfd, smtpfd, ssl, buf, len); |
263 |
+ if (r < 0) ssl_err_str = ssl_error_str(); |
264 |
+ } else |
265 |
+#endif |
266 |
r = timeoutwrite(timeout,smtpfd,buf,len); |
267 |
if (r <= 0) dropped(); |
268 |
return r; |
269 |
@@ -194,19 +220,25 @@ unsigned long ehlo() |
270 |
e = smtptext.s + smtptext.len - 6; /* 250-?\n */ |
271 |
while (s <= e) |
272 |
{ |
273 |
+ int wasspace = 0; |
274 |
+ |
275 |
if (!saa_readyplus(&ehlokw, 1)) temp_nomem(); |
276 |
sa = ehlokw.sa + ehlokw.len++; |
277 |
if (ehlokw.len > maxehlokwlen) *sa = sauninit; else sa->len = 0; |
278 |
|
279 |
- /* smtptext is known to end in a '\n' */ |
280 |
- for (p = (s += 4); ; ++p) |
281 |
- if (*p == '\n' || *p == ' ' || *p == '\t') { |
282 |
- if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem(); |
283 |
- if (*p++ == '\n') break; |
284 |
- while (*p == ' ' || *p == '\t') ; |
285 |
- s = p; |
286 |
- } |
287 |
- s = p; |
288 |
+ /* smtptext is known to end in a '\n' */ |
289 |
+ for (p = (s += 4); ; ++p) |
290 |
+ if (*p == '\n' || *p == ' ' || *p == '\t') { |
291 |
+ if (!wasspace) |
292 |
+ if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem(); |
293 |
+ if (*p == '\n') break; |
294 |
+ wasspace = 1; |
295 |
+ } else if (wasspace == 1) { |
296 |
+ wasspace = 0; |
297 |
+ s = p; |
298 |
+ } |
299 |
+ s = ++p; |
300 |
+ |
301 |
/* keyword should consist of alpha-num and '-' |
302 |
* broken AUTH might use '=' instead of space */ |
303 |
for (p = sa->s; *p; ++p) if (*p == '=') { *p = 0; break; } |
304 |
@@ -232,6 +264,11 @@ void quit(prepend,append) |
305 |
char *prepend; |
306 |
char *append; |
307 |
{ |
308 |
+#ifdef TLS |
309 |
+ /* shouldn't talk to the client unless in an appropriate state */ |
310 |
+ int state = ssl ? ssl->state : SSL_ST_BEFORE; |
311 |
+ if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE)) |
312 |
+#endif |
313 |
substdio_putsflush(&smtpto,"QUIT\r\n"); |
314 |
/* waiting for remote side is just too ridiculous */ |
315 |
out(prepend); |
316 |
@@ -239,6 +276,30 @@ char *append; |
317 |
out(append); |
318 |
out(".\n"); |
319 |
outsmtptext(); |
320 |
+ |
321 |
+#if defined(TLS) && defined(DEBUG) |
322 |
+ if (ssl) { |
323 |
+ X509 *peercert; |
324 |
+ |
325 |
+ out("STARTTLS proto="); out(SSL_get_version(ssl)); |
326 |
+ out("; cipher="); out(SSL_get_cipher(ssl)); |
327 |
+ |
328 |
+ /* we want certificate details */ |
329 |
+ if (peercert = SSL_get_peer_certificate(ssl)) { |
330 |
+ char *str; |
331 |
+ |
332 |
+ str = X509_NAME_oneline(X509_get_subject_name(peercert), NULL, 0); |
333 |
+ out("; subject="); out(str); OPENSSL_free(str); |
334 |
+ |
335 |
+ str = X509_NAME_oneline(X509_get_issuer_name(peercert), NULL, 0); |
336 |
+ out("; issuer="); out(str); OPENSSL_free(str); |
337 |
+ |
338 |
+ X509_free(peercert); |
339 |
+ } |
340 |
+ out(";\n"); |
341 |
+ } |
342 |
+#endif |
343 |
+ |
344 |
zerodie(); |
345 |
} |
346 |
|
347 |
@@ -267,6 +328,206 @@ void blast() |
348 |
substdio_flush(&smtpto); |
349 |
} |
350 |
|
351 |
+#ifdef TLS |
352 |
+char *partner_fqdn = 0; |
353 |
+ |
354 |
+# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "") |
355 |
+void tls_quit(const char *s1, const char *s2) |
356 |
+{ |
357 |
+ out(s1); if (s2) { out(": "); out(s2); } TLS_QUIT; |
358 |
+} |
359 |
+# define tls_quit_error(s) tls_quit(s, ssl_error()) |
360 |
+ |
361 |
+int match_partner(const char *s, int len) |
362 |
+{ |
363 |
+ if (!case_diffb(partner_fqdn, len, s) && !partner_fqdn[len]) return 1; |
364 |
+ /* we also match if the name is *.domainname */ |
365 |
+ if (*s == '*') { |
366 |
+ const char *domain = partner_fqdn + str_chr(partner_fqdn, '.'); |
367 |
+ if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1; |
368 |
+ } |
369 |
+ return 0; |
370 |
+} |
371 |
+ |
372 |
+/* don't want to fail handshake if certificate can't be verified */ |
373 |
+int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } |
374 |
+ |
375 |
+int tls_init() |
376 |
+{ |
377 |
+ int i; |
378 |
+ SSL *myssl; |
379 |
+ SSL_CTX *ctx; |
380 |
+ stralloc saciphers = {0}; |
381 |
+ const char *ciphers, *servercert = 0; |
382 |
+ |
383 |
+ if (partner_fqdn) { |
384 |
+ struct stat st; |
385 |
+ stralloc tmp = {0}; |
386 |
+ if (!stralloc_copys(&tmp, "control/tlshosts/") |
387 |
+ || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)) |
388 |
+ || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem(); |
389 |
+ if (stat(tmp.s, &st) == 0) |
390 |
+ servercert = tmp.s; |
391 |
+ else { |
392 |
+ if (!stralloc_copys(&tmp, "control/notlshosts/") |
393 |
+ || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1)) |
394 |
+ temp_nomem(); |
395 |
+ if ((stat("control/tlshosts/exhaustivelist", &st) == 0) || |
396 |
+ (stat(tmp.s, &st) == 0)) { |
397 |
+ alloc_free(tmp.s); |
398 |
+ return 0; |
399 |
+ } |
400 |
+ alloc_free(tmp.s); |
401 |
+ } |
402 |
+ } |
403 |
+ |
404 |
+ if (!smtps) { |
405 |
+ stralloc *sa = ehlokw.sa; |
406 |
+ unsigned int len = ehlokw.len; |
407 |
+ /* look for STARTTLS among EHLO keywords */ |
408 |
+ for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ; |
409 |
+ if (!len) { |
410 |
+ if (!servercert) return 0; |
411 |
+ out("ZNo TLS achieved while "); out(servercert); |
412 |
+ out(" exists"); smtptext.len = 0; TLS_QUIT; |
413 |
+ } |
414 |
+ } |
415 |
+ |
416 |
+ SSL_library_init(); |
417 |
+ ctx = SSL_CTX_new(SSLv23_client_method()); |
418 |
+ if (!ctx) { |
419 |
+ if (!smtps && !servercert) return 0; |
420 |
+ smtptext.len = 0; |
421 |
+ tls_quit_error("ZTLS error initializing ctx"); |
422 |
+ } |
423 |
+ |
424 |
+ /* POODLE vulnerability */ |
425 |
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); |
426 |
+ |
427 |
+ if (servercert) { |
428 |
+ if (!SSL_CTX_load_verify_locations(ctx, servercert, NULL)) { |
429 |
+ SSL_CTX_free(ctx); |
430 |
+ smtptext.len = 0; |
431 |
+ out("ZTLS unable to load "); tls_quit_error(servercert); |
432 |
+ } |
433 |
+ /* set the callback here; SSL_set_verify didn't work before 0.9.6c */ |
434 |
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb); |
435 |
+ } |
436 |
+ |
437 |
+ /* let the other side complain if it needs a cert and we don't have one */ |
438 |
+# define CLIENTCERT "control/clientcert.pem" |
439 |
+ if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT)) |
440 |
+ SSL_CTX_use_RSAPrivateKey_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM); |
441 |
+# undef CLIENTCERT |
442 |
+ |
443 |
+ myssl = SSL_new(ctx); |
444 |
+ SSL_CTX_free(ctx); |
445 |
+ if (!myssl) { |
446 |
+ if (!smtps && !servercert) return 0; |
447 |
+ smtptext.len = 0; |
448 |
+ tls_quit_error("ZTLS error initializing ssl"); |
449 |
+ } |
450 |
+ |
451 |
+ if (!smtps) substdio_putsflush(&smtpto, "STARTTLS\r\n"); |
452 |
+ |
453 |
+ /* while the server is preparing a response, do something else */ |
454 |
+ if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1) |
455 |
+ { SSL_free(myssl); temp_control(); } |
456 |
+ if (saciphers.len) { |
457 |
+ for (i = 0; i < saciphers.len - 1; ++i) |
458 |
+ if (!saciphers.s[i]) saciphers.s[i] = ':'; |
459 |
+ ciphers = saciphers.s; |
460 |
+ } |
461 |
+ else ciphers = "DEFAULT"; |
462 |
+ SSL_set_cipher_list(myssl, ciphers); |
463 |
+ alloc_free(saciphers.s); |
464 |
+ |
465 |
+ SSL_set_fd(myssl, smtpfd); |
466 |
+ |
467 |
+ /* read the response to STARTTLS */ |
468 |
+ if (!smtps) { |
469 |
+ if (smtpcode() != 220) { |
470 |
+ SSL_free(myssl); |
471 |
+ if (!servercert) return 0; |
472 |
+ out("ZSTARTTLS rejected while "); |
473 |
+ out(servercert); out(" exists"); TLS_QUIT; |
474 |
+ } |
475 |
+ smtptext.len = 0; |
476 |
+ } |
477 |
+ |
478 |
+ ssl = myssl; |
479 |
+ if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0) |
480 |
+ tls_quit("ZTLS connect failed", ssl_error_str()); |
481 |
+ |
482 |
+ if (servercert) { |
483 |
+ X509 *peercert; |
484 |
+ STACK_OF(GENERAL_NAME) *gens; |
485 |
+ int found_gen_dns = 0; |
486 |
+ int matched_gen_dns = 0; |
487 |
+ |
488 |
+ int r = SSL_get_verify_result(ssl); |
489 |
+ if (r != X509_V_OK) { |
490 |
+ out("ZTLS unable to verify server with "); |
491 |
+ tls_quit(servercert, X509_verify_cert_error_string(r)); |
492 |
+ } |
493 |
+ alloc_free(servercert); |
494 |
+ |
495 |
+ peercert = SSL_get_peer_certificate(ssl); |
496 |
+ if (!peercert) { |
497 |
+ out("ZTLS unable to verify server "); |
498 |
+ tls_quit(partner_fqdn, "no certificate provided"); |
499 |
+ } |
500 |
+ |
501 |
+ /* RFC 2595 section 2.4: find a matching name |
502 |
+ * first find a match among alternative names */ |
503 |
+ gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0); |
504 |
+ if (gens) { |
505 |
+ for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i) |
506 |
+ { |
507 |
+ const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i); |
508 |
+ if (gn->type == GEN_DNS){ |
509 |
+ found_gen_dns = 1; |
510 |
+ if (match_partner(gn->d.ia5->data, gn->d.ia5->length)){ |
511 |
+ matched_gen_dns = 1; |
512 |
+ break; |
513 |
+ } |
514 |
+ } |
515 |
+ } |
516 |
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); |
517 |
+ } |
518 |
+ |
519 |
+ /* no SubjectAltName of type DNS found, look up commonName */ |
520 |
+ if (!found_gen_dns) { |
521 |
+ stralloc peer = {0}; |
522 |
+ X509_NAME *subj = X509_get_subject_name(peercert); |
523 |
+ i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1); |
524 |
+ if (i >= 0) { |
525 |
+ const ASN1_STRING *s = X509_NAME_get_entry(subj, i)->value; |
526 |
+ if (s) { peer.len = s->length; peer.s = s->data; } |
527 |
+ } |
528 |
+ if (peer.len <= 0) { |
529 |
+ out("ZTLS unable to verify server "); |
530 |
+ tls_quit(partner_fqdn, "certificate contains no valid commonName"); |
531 |
+ } |
532 |
+ if (!match_partner(peer.s, peer.len)) { |
533 |
+ out("ZTLS unable to verify server "); out(partner_fqdn); |
534 |
+ out(": received certificate for "); outsafe(&peer); TLS_QUIT; |
535 |
+ } |
536 |
+ } else if (!matched_gen_dns) { |
537 |
+ out("ZTLS unable to verify server "); |
538 |
+ tls_quit(partner_fqdn, "certificate contains no matching dNSNnames"); |
539 |
+ } |
540 |
+ |
541 |
+ X509_free(peercert); |
542 |
+ } |
543 |
+ |
544 |
+ if (smtps) if (smtpcode() != 220) |
545 |
+ quit("ZTLS Connected to "," but greeting failed"); |
546 |
+ |
547 |
+ return 1; |
548 |
+} |
549 |
+#endif |
550 |
+ |
551 |
stralloc recip = {0}; |
552 |
|
553 |
void smtp() |
554 |
@@ -274,12 +535,37 @@ void smtp() |
555 |
unsigned long code; |
556 |
int flagbother; |
557 |
int i; |
558 |
+ |
559 |
+#ifndef PORT_SMTP |
560 |
+ /* the qmtpc patch uses smtp_port and undefines PORT_SMTP */ |
561 |
+# define port smtp_port |
562 |
+#endif |
563 |
+ |
564 |
+#ifdef TLS |
565 |
+# ifdef MXPS |
566 |
+ if (type == 'S') smtps = 1; |
567 |
+ else if (type != 's') |
568 |
+# endif |
569 |
+ if (port == 465) smtps = 1; |
570 |
+ if (!smtps) |
571 |
+#endif |
572 |
|
573 |
if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); |
574 |
|
575 |
#ifdef EHLO |
576 |
+# ifdef TLS |
577 |
+ if (!smtps) |
578 |
+# endif |
579 |
code = ehlo(); |
580 |
|
581 |
+# ifdef TLS |
582 |
+ if (tls_init()) |
583 |
+ /* RFC2487 says we should issue EHLO (even if we might not need |
584 |
+ * extensions); at the same time, it does not prohibit a server |
585 |
+ * to reject the EHLO and make us fallback to HELO */ |
586 |
+ code = ehlo(); |
587 |
+# endif |
588 |
+ |
589 |
if (code == 250) { |
590 |
/* add EHLO response checks here */ |
591 |
|
592 |
@@ -484,6 +770,9 @@ char **argv; |
593 |
if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { |
594 |
tcpto_err(&ip.ix[i].ip,0); |
595 |
partner = ip.ix[i].ip; |
596 |
+#ifdef TLS |
597 |
+ partner_fqdn = ip.ix[i].fqdn; |
598 |
+#endif |
599 |
smtp(); /* does not return */ |
600 |
} |
601 |
tcpto_err(&ip.ix[i].ip,errno == error_timeout); |
602 |
--- netqmail-1.06-orig/qmail-remote.8 1998-06-15 10:53:16.000000000 +0000 |
603 |
+++ netqmail-1.06/qmail-remote.8 2015-12-01 15:54:59.029940779 +0000 |
604 |
@@ -114,6 +114,10 @@ arguments. |
605 |
always exits zero. |
606 |
.SH "CONTROL FILES" |
607 |
.TP 5 |
608 |
+.I clientcert.pem |
609 |
+SSL certificate that is used to authenticate with the remote server |
610 |
+during a TLS session. |
611 |
+.TP 5 |
612 |
.I helohost |
613 |
Current host name, |
614 |
for use solely in saying hello to the remote SMTP server. |
615 |
@@ -123,6 +127,16 @@ if that is supplied; |
616 |
otherwise |
617 |
.B qmail-remote |
618 |
refuses to run. |
619 |
+ |
620 |
+.TP 5 |
621 |
+.I notlshosts/<FQDN> |
622 |
+.B qmail-remote |
623 |
+will not try TLS on servers for which this file exists |
624 |
+.RB ( <FQDN> |
625 |
+is the fully-qualified domain name of the server). |
626 |
+.IR (tlshosts/<FQDN>.pem |
627 |
+takes precedence over this file however). |
628 |
+ |
629 |
.TP 5 |
630 |
.I smtproutes |
631 |
Artificial SMTP routes. |
632 |
@@ -156,6 +170,8 @@ may be empty; |
633 |
this tells |
634 |
.B qmail-remote |
635 |
to look up MX records as usual. |
636 |
+.I port |
637 |
+value of 465 (deprecated smtps port) causes TLS session to be started. |
638 |
.I smtproutes |
639 |
may include wildcards: |
640 |
|
641 |
@@ -195,6 +211,33 @@ Number of seconds |
642 |
.B qmail-remote |
643 |
will wait for each response from the remote SMTP server. |
644 |
Default: 1200. |
645 |
+ |
646 |
+.TP 5 |
647 |
+.I tlsclientciphers |
648 |
+A set of OpenSSL client cipher strings. Multiple ciphers |
649 |
+contained in a string should be separated by a colon. |
650 |
+ |
651 |
+.TP 5 |
652 |
+.I tlshosts/<FQDN>.pem |
653 |
+.B qmail-remote |
654 |
+requires TLS authentication from servers for which this file exists |
655 |
+.RB ( <FQDN> |
656 |
+is the fully-qualified domain name of the server). One of the |
657 |
+.I dNSName |
658 |
+or the |
659 |
+.I CommonName |
660 |
+attributes have to match. The file contains the trusted CA certificates. |
661 |
+ |
662 |
+.B WARNING: |
663 |
+this option may cause mail to be delayed, bounced, doublebounced, or lost. |
664 |
+ |
665 |
+.TP 5 |
666 |
+.I tlshosts/exhaustivelist |
667 |
+if this file exists |
668 |
+no TLS will be tried on hosts other than those for which a file |
669 |
+.B tlshosts/<FQDN>.pem |
670 |
+exists. |
671 |
+ |
672 |
.SH "SEE ALSO" |
673 |
addresses(5), |
674 |
envelopes(5), |
675 |
--- netqmail-1.06-orig/qmail-control.9 1998-06-15 10:53:16.000000000 +0000 |
676 |
+++ netqmail-1.06/qmail-control.9 2015-12-08 00:33:06.248714330 +0000 |
677 |
@@ -43,11 +43,14 @@ control default used by |
678 |
.I badmailfrom \fR(none) \fRqmail-smtpd |
679 |
.I bouncefrom \fRMAILER-DAEMON \fRqmail-send |
680 |
.I bouncehost \fIme \fRqmail-send |
681 |
+.I clientca.pem \fR(none) \fRqmail-smtpd |
682 |
+.I clientcert.pem \fR(none) \fRqmail-remote |
683 |
.I concurrencylocal \fR10 \fRqmail-send |
684 |
.I concurrencyremote \fR20 \fRqmail-send |
685 |
.I defaultdomain \fIme \fRqmail-inject |
686 |
.I defaulthost \fIme \fRqmail-inject |
687 |
.I databytes \fR0 \fRqmail-smtpd |
688 |
+.I dh2048.pem \fR(none) \fRqmail-smtpd |
689 |
.I doublebouncehost \fIme \fRqmail-send |
690 |
.I doublebounceto \fRpostmaster \fRqmail-send |
691 |
.I envnoathost \fIme \fRqmail-send |
692 |
@@ -61,11 +64,17 @@ control default used by |
693 |
.I qmqpservers \fR(none) \fRqmail-qmqpc |
694 |
.I queuelifetime \fR604800 \fRqmail-send |
695 |
.I rcpthosts \fR(none) \fRqmail-smtpd |
696 |
+.I rsa2048.pem \fR(none) \fRqmail-smtpd |
697 |
+.I servercert.pem \fR(none) \fRqmail-smtpd |
698 |
.I smtpgreeting \fIme \fRqmail-smtpd |
699 |
.I smtproutes \fR(none) \fRqmail-remote |
700 |
.I timeoutconnect \fR60 \fRqmail-remote |
701 |
.I timeoutremote \fR1200 \fRqmail-remote |
702 |
.I timeoutsmtpd \fR1200 \fRqmail-smtpd |
703 |
+.I tlsclients \fR(none) \fRqmail-smtpd |
704 |
+.I tlsclientciphers \fR(none) \fRqmail-remote |
705 |
+.I tlshosts/FQDN.pem \fR(none) \fRqmail-remote |
706 |
+.I tlsserverciphers \fR(none) \fRqmail-smtpd |
707 |
.I virtualdomains \fR(none) \fRqmail-send |
708 |
.fi |
709 |
.RE |
710 |
--- netqmail-1.06-orig/dns.c 2007-11-30 20:22:54.000000000 +0000 |
711 |
+++ netqmail-1.06/dns.c 2015-12-01 15:54:59.033940812 +0000 |
712 |
@@ -267,12 +267,11 @@ stralloc *sa; |
713 |
int pref; |
714 |
{ |
715 |
int r; |
716 |
- struct ip_mx ix; |
717 |
+ struct ip_mx ix = {0}; |
718 |
|
719 |
if (!stralloc_copy(&glue,sa)) return DNS_MEM; |
720 |
if (!stralloc_0(&glue)) return DNS_MEM; |
721 |
if (glue.s[0]) { |
722 |
- ix.pref = 0; |
723 |
if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) |
724 |
{ |
725 |
if (!ipalloc_append(ia,&ix)) return DNS_MEM; |
726 |
@@ -291,9 +290,16 @@ int pref; |
727 |
ix.ip = ip; |
728 |
ix.pref = pref; |
729 |
if (r == DNS_SOFT) return DNS_SOFT; |
730 |
- if (r == 1) |
731 |
+ if (r == 1) { |
732 |
+#ifdef IX_FQDN |
733 |
+ ix.fqdn = glue.s; |
734 |
+#endif |
735 |
if (!ipalloc_append(ia,&ix)) return DNS_MEM; |
736 |
} |
737 |
+ } |
738 |
+#ifdef IX_FQDN |
739 |
+ glue.s = 0; |
740 |
+#endif |
741 |
return 0; |
742 |
} |
743 |
|
744 |
@@ -313,7 +319,7 @@ unsigned long random; |
745 |
{ |
746 |
int r; |
747 |
struct mx { stralloc sa; unsigned short p; } *mx; |
748 |
- struct ip_mx ix; |
749 |
+ struct ip_mx ix = {0}; |
750 |
int nummx; |
751 |
int i; |
752 |
int j; |
753 |
@@ -325,7 +331,6 @@ unsigned long random; |
754 |
if (!stralloc_copy(&glue,sa)) return DNS_MEM; |
755 |
if (!stralloc_0(&glue)) return DNS_MEM; |
756 |
if (glue.s[0]) { |
757 |
- ix.pref = 0; |
758 |
if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) |
759 |
{ |
760 |
if (!ipalloc_append(ia,&ix)) return DNS_MEM; |
761 |
--- netqmail-1.06-orig/hier.c 1998-06-15 10:53:16.000000000 +0000 |
762 |
+++ netqmail-1.06/hier.c 2015-12-01 15:54:59.033940812 +0000 |
763 |
@@ -143,6 +143,9 @@ void hier() |
764 |
c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755); |
765 |
c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755); |
766 |
c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755); |
767 |
+#ifdef TLS |
768 |
+ c(auto_qmail,"bin","update_tmprsadh",auto_uido,auto_gidq,0755); |
769 |
+#endif |
770 |
|
771 |
c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644); |
772 |
c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644); |
773 |
--- netqmail-1.06-orig/ipalloc.h 1998-06-15 10:53:16.000000000 +0000 |
774 |
+++ netqmail-1.06/ipalloc.h 2015-12-01 15:54:59.033940812 +0000 |
775 |
@@ -3,7 +3,15 @@ |
776 |
|
777 |
#include "ip.h" |
778 |
|
779 |
+#ifdef TLS |
780 |
+# define IX_FQDN 1 |
781 |
+#endif |
782 |
+ |
783 |
+#ifdef IX_FQDN |
784 |
+struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ; |
785 |
+#else |
786 |
struct ip_mx { struct ip_address ip; int pref; } ; |
787 |
+#endif |
788 |
|
789 |
#include "gen_alloc.h" |
790 |
|
791 |
--- netqmail-1.06-orig/tls.c 2016-09-18 10:04:24.698101731 +0000 |
792 |
+++ netqmail-1.06/tls.c 2015-12-01 15:54:59.033940812 +0000 |
793 |
@@ -0,0 +1,25 @@ |
794 |
+#include "exit.h" |
795 |
+#include "error.h" |
796 |
+#include <openssl/ssl.h> |
797 |
+#include <openssl/err.h> |
798 |
+ |
799 |
+int smtps = 0; |
800 |
+SSL *ssl = NULL; |
801 |
+ |
802 |
+void ssl_free(SSL *myssl) { SSL_shutdown(myssl); SSL_free(myssl); } |
803 |
+void ssl_exit(int status) { if (ssl) ssl_free(ssl); _exit(status); } |
804 |
+ |
805 |
+const char *ssl_error() |
806 |
+{ |
807 |
+ int r = ERR_get_error(); |
808 |
+ if (!r) return NULL; |
809 |
+ SSL_load_error_strings(); |
810 |
+ return ERR_error_string(r, NULL); |
811 |
+} |
812 |
+const char *ssl_error_str() |
813 |
+{ |
814 |
+ const char *err = ssl_error(); |
815 |
+ if (err) return err; |
816 |
+ if (!errno) return 0; |
817 |
+ return (errno == error_timeout) ? "timed out" : error_str(errno); |
818 |
+} |
819 |
--- netqmail-1.06-orig/tls.h 2016-09-18 10:04:24.698101731 +0000 |
820 |
+++ netqmail-1.06/tls.h 2015-12-01 15:54:59.033940812 +0000 |
821 |
@@ -0,0 +1,16 @@ |
822 |
+#ifndef TLS_H |
823 |
+#define TLS_H |
824 |
+ |
825 |
+#include <openssl/ssl.h> |
826 |
+ |
827 |
+extern int smtps; |
828 |
+extern SSL *ssl; |
829 |
+ |
830 |
+void ssl_free(SSL *myssl); |
831 |
+void ssl_exit(int status); |
832 |
+# define _exit ssl_exit |
833 |
+ |
834 |
+const char *ssl_error(); |
835 |
+const char *ssl_error_str(); |
836 |
+ |
837 |
+#endif |
838 |
--- netqmail-1.06-orig/ssl_timeoutio.c 2016-09-18 10:04:24.698101731 +0000 |
839 |
+++ netqmail-1.06/ssl_timeoutio.c 2015-12-01 15:54:59.033940812 +0000 |
840 |
@@ -0,0 +1,95 @@ |
841 |
+#include "select.h" |
842 |
+#include "error.h" |
843 |
+#include "ndelay.h" |
844 |
+#include "now.h" |
845 |
+#include "ssl_timeoutio.h" |
846 |
+ |
847 |
+int ssl_timeoutio(int (*fun)(), |
848 |
+ int t, int rfd, int wfd, SSL *ssl, char *buf, int len) |
849 |
+{ |
850 |
+ int n; |
851 |
+ const datetime_sec end = (datetime_sec)t + now(); |
852 |
+ |
853 |
+ do { |
854 |
+ fd_set fds; |
855 |
+ struct timeval tv; |
856 |
+ |
857 |
+ const int r = buf ? fun(ssl, buf, len) : fun(ssl); |
858 |
+ if (r > 0) return r; |
859 |
+ |
860 |
+ t = end - now(); |
861 |
+ if (t < 0) break; |
862 |
+ tv.tv_sec = (time_t)t; tv.tv_usec = 0; |
863 |
+ |
864 |
+ FD_ZERO(&fds); |
865 |
+ switch (SSL_get_error(ssl, r)) |
866 |
+ { |
867 |
+ default: return r; /* some other error */ |
868 |
+ case SSL_ERROR_WANT_READ: |
869 |
+ FD_SET(rfd, &fds); n = select(rfd + 1, &fds, NULL, NULL, &tv); |
870 |
+ break; |
871 |
+ case SSL_ERROR_WANT_WRITE: |
872 |
+ FD_SET(wfd, &fds); n = select(wfd + 1, NULL, &fds, NULL, &tv); |
873 |
+ break; |
874 |
+ } |
875 |
+ |
876 |
+ /* n is the number of descriptors that changed status */ |
877 |
+ } while (n > 0); |
878 |
+ |
879 |
+ if (n != -1) errno = error_timeout; |
880 |
+ return -1; |
881 |
+} |
882 |
+ |
883 |
+int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl) |
884 |
+{ |
885 |
+ int r; |
886 |
+ |
887 |
+ /* if connection is established, keep NDELAY */ |
888 |
+ if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1; |
889 |
+ r = ssl_timeoutio(SSL_accept, t, rfd, wfd, ssl, NULL, 0); |
890 |
+ |
891 |
+ if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); } |
892 |
+ else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); |
893 |
+ |
894 |
+ return r; |
895 |
+} |
896 |
+ |
897 |
+int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl) |
898 |
+{ |
899 |
+ int r; |
900 |
+ |
901 |
+ /* if connection is established, keep NDELAY */ |
902 |
+ if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1; |
903 |
+ r = ssl_timeoutio(SSL_connect, t, rfd, wfd, ssl, NULL, 0); |
904 |
+ |
905 |
+ if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); } |
906 |
+ else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); |
907 |
+ |
908 |
+ return r; |
909 |
+} |
910 |
+ |
911 |
+int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl) |
912 |
+{ |
913 |
+ int r; |
914 |
+ |
915 |
+ SSL_renegotiate(ssl); |
916 |
+ r = ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0); |
917 |
+ if (r <= 0 || ssl->type == SSL_ST_CONNECT) return r; |
918 |
+ |
919 |
+ /* this is for the server only */ |
920 |
+ ssl->state = SSL_ST_ACCEPT; |
921 |
+ return ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0); |
922 |
+} |
923 |
+ |
924 |
+int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len) |
925 |
+{ |
926 |
+ if (!buf) return 0; |
927 |
+ if (SSL_pending(ssl)) return SSL_read(ssl, buf, len); |
928 |
+ return ssl_timeoutio(SSL_read, t, rfd, wfd, ssl, buf, len); |
929 |
+} |
930 |
+ |
931 |
+int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len) |
932 |
+{ |
933 |
+ if (!buf) return 0; |
934 |
+ return ssl_timeoutio(SSL_write, t, rfd, wfd, ssl, buf, len); |
935 |
+} |
936 |
--- netqmail-1.06-orig/ssl_timeoutio.h 2016-09-18 10:04:24.698101731 +0000 |
937 |
+++ netqmail-1.06/ssl_timeoutio.h 2015-12-01 15:54:59.033940812 +0000 |
938 |
@@ -0,0 +1,21 @@ |
939 |
+#ifndef SSL_TIMEOUTIO_H |
940 |
+#define SSL_TIMEOUTIO_H |
941 |
+ |
942 |
+#include <openssl/ssl.h> |
943 |
+ |
944 |
+/* the version is like this: 0xMNNFFPPS: major minor fix patch status */ |
945 |
+#if OPENSSL_VERSION_NUMBER < 0x00906000L |
946 |
+# error "Need OpenSSL version at least 0.9.6" |
947 |
+#endif |
948 |
+ |
949 |
+int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl); |
950 |
+int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl); |
951 |
+int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl); |
952 |
+ |
953 |
+int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len); |
954 |
+int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len); |
955 |
+ |
956 |
+int ssl_timeoutio( |
957 |
+ int (*fun)(), int t, int rfd, int wfd, SSL *ssl, char *buf, int len); |
958 |
+ |
959 |
+#endif |
960 |
--- netqmail-1.06-orig/TARGETS 1998-06-15 10:53:16.000000000 +0000 |
961 |
+++ netqmail-1.06/TARGETS 2015-12-01 15:54:59.033940812 +0000 |
962 |
@@ -168,6 +168,8 @@ control.o |
963 |
constmap.o |
964 |
timeoutread.o |
965 |
timeoutwrite.o |
966 |
+tls.o |
967 |
+ssl_timeoutio.o |
968 |
timeoutconn.o |
969 |
tcpto.o |
970 |
dns.o |
971 |
@@ -320,6 +322,7 @@ binm2 |
972 |
binm2+df |
973 |
binm3 |
974 |
binm3+df |
975 |
+Makefile-cert |
976 |
it |
977 |
qmail-local.0 |
978 |
qmail-lspawn.0 |
979 |
@@ -385,3 +388,4 @@ forgeries.0 |
980 |
man |
981 |
setup |
982 |
check |
983 |
+update_tmprsadh |
984 |
--- netqmail-1.06-orig/Makefile-cert.mk 2016-09-18 10:04:24.698101731 +0000 |
985 |
+++ netqmail-1.06/Makefile-cert.mk 2015-12-01 15:54:59.033940812 +0000 |
986 |
@@ -0,0 +1,21 @@ |
987 |
+cert-req: req.pem |
988 |
+cert cert-req: QMAIL/control/clientcert.pem |
989 |
+ @: |
990 |
+ |
991 |
+QMAIL/control/clientcert.pem: QMAIL/control/servercert.pem |
992 |
+ ln -s $< $@ |
993 |
+ |
994 |
+QMAIL/control/servercert.pem: |
995 |
+ PATH=$$PATH:/usr/local/ssl/bin \ |
996 |
+ openssl req -new -x509 -nodes -days 366 -out $@ -keyout $@ |
997 |
+ chmod 640 $@ |
998 |
+ chown `head -2 conf-users | tail -1`:`head -1 conf-groups` $@ |
999 |
+ |
1000 |
+req.pem: |
1001 |
+ PATH=$$PATH:/usr/local/ssl/bin openssl req \ |
1002 |
+ -new -nodes -out $@ -keyout QMAIL/control/servercert.pem |
1003 |
+ chmod 640 QMAIL/control/servercert.pem |
1004 |
+ chown `head -2 conf-users | tail -1`:`head -1 conf-groups` QMAIL/control/servercert.pem |
1005 |
+ @echo |
1006 |
+ @echo "Send req.pem to your CA to obtain signed_req.pem, and do:" |
1007 |
+ @echo "cat signed_req.pem >> QMAIL/control/servercert.pem" |
1008 |
--- netqmail-1.06-orig/conf-cc 1998-06-15 10:53:16.000000000 +0000 |
1009 |
+++ netqmail-1.06/conf-cc 2015-12-08 00:59:12.688312582 +0000 |
1010 |
@@ -1,3 +1,3 @@ |
1011 |
-cc -O2 |
1012 |
+cc -O2 -DTLS=20160918 -I/usr/local/ssl/include |
1013 |
|
1014 |
This will be used to compile .c files. |
1015 |
--- netqmail-1.06-orig/Makefile 2007-11-30 20:22:54.000000000 +0000 |
1016 |
+++ netqmail-1.06/Makefile 2015-12-01 15:54:59.033940812 +0000 |
1017 |
@@ -808,7 +808,7 @@ dnsptr dnsip dnsmxip dnsfq hostname ipme |
1018 |
forward preline condredirect bouncesaying except maildirmake \ |
1019 |
maildir2mbox maildirwatch qail elq pinq idedit install-big install \ |
1020 |
instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \ |
1021 |
-binm3 binm3+df |
1022 |
+binm3 binm3+df update_tmprsadh |
1023 |
|
1024 |
load: \ |
1025 |
make-load warn-auto.sh systype |
1026 |
@@ -1444,6 +1444,7 @@ ndelay.a case.a sig.a open.a lock.a seek |
1027 |
substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib |
1028 |
./load qmail-remote control.o constmap.o timeoutread.o \ |
1029 |
timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \ |
1030 |
+ tls.o ssl_timeoutio.o -L/usr/local/ssl/lib -lssl -lcrypto \ |
1031 |
ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \ |
1032 |
lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \ |
1033 |
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` |
1034 |
@@ -1539,6 +1540,7 @@ open.a sig.a case.a env.a stralloc.a all |
1035 |
fs.a auto_qmail.o socket.lib |
1036 |
./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \ |
1037 |
timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \ |
1038 |
+ tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \ |
1039 |
received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \ |
1040 |
datetime.a getln.a open.a sig.a case.a env.a stralloc.a \ |
1041 |
alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \ |
1042 |
@@ -1827,7 +1829,8 @@ date822fmt.h date822fmt.c dns.h dns.c tr |
1043 |
ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \ |
1044 |
ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \ |
1045 |
prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \ |
1046 |
-maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c |
1047 |
+maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c \ |
1048 |
+update_tmprsadh |
1049 |
shar -m `cat FILES` > shar |
1050 |
chmod 400 shar |
1051 |
|
1052 |
@@ -2108,6 +2111,19 @@ timeoutwrite.o: \ |
1053 |
compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h |
1054 |
./compile timeoutwrite.c |
1055 |
|
1056 |
+qmail-smtpd: tls.o ssl_timeoutio.o ndelay.a |
1057 |
+qmail-remote: tls.o ssl_timeoutio.o |
1058 |
+qmail-smtpd.o: tls.h ssl_timeoutio.h |
1059 |
+qmail-remote.o: tls.h ssl_timeoutio.h |
1060 |
+ |
1061 |
+tls.o: \ |
1062 |
+compile tls.c exit.h error.h |
1063 |
+ ./compile tls.c |
1064 |
+ |
1065 |
+ssl_timeoutio.o: \ |
1066 |
+compile ssl_timeoutio.c ssl_timeoutio.h select.h error.h ndelay.h |
1067 |
+ ./compile ssl_timeoutio.c |
1068 |
+ |
1069 |
token822.o: \ |
1070 |
compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \ |
1071 |
gen_alloc.h gen_allocdefs.h |
1072 |
@@ -2139,3 +2155,26 @@ compile wait_nohang.c haswaitp.h |
1073 |
wait_pid.o: \ |
1074 |
compile wait_pid.c error.h haswaitp.h |
1075 |
./compile wait_pid.c |
1076 |
+ |
1077 |
+cert cert-req: \ |
1078 |
+Makefile-cert |
1079 |
+ @$(MAKE) -sf $< $@ |
1080 |
+ |
1081 |
+Makefile-cert: \ |
1082 |
+conf-qmail conf-users conf-groups Makefile-cert.mk |
1083 |
+ @cat Makefile-cert.mk \ |
1084 |
+ | sed s}QMAIL}"`head -1 conf-qmail`"}g \ |
1085 |
+ > $@ |
1086 |
+ |
1087 |
+update_tmprsadh: \ |
1088 |
+conf-qmail conf-users conf-groups update_tmprsadh.sh |
1089 |
+ @cat update_tmprsadh.sh\ |
1090 |
+ | sed s}UGQMAILD}"`head -2 conf-users|tail -1`:`head -1 conf-groups`"}g \ |
1091 |
+ | sed s}QMAIL}"`head -1 conf-qmail`"}g \ |
1092 |
+ > $@ |
1093 |
+ chmod 755 update_tmprsadh |
1094 |
+ |
1095 |
+tmprsadh: \ |
1096 |
+update_tmprsadh |
1097 |
+ echo "Creating new temporary RSA and DH parameters" |
1098 |
+ ./update_tmprsadh |
1099 |
--- netqmail-1.06-orig/update_tmprsadh.sh 2016-09-18 10:04:24.698101731 +0000 |
1100 |
+++ netqmail-1.06/update_tmprsadh.sh 2015-12-08 00:32:33.936474103 +0000 |
1101 |
@@ -0,0 +1,19 @@ |
1102 |
+#!/bin/sh |
1103 |
+ |
1104 |
+# Update temporary RSA and DH keys |
1105 |
+# Frederik Vermeulen 2004-05-31 GPL |
1106 |
+ |
1107 |
+umask 0077 || exit 0 |
1108 |
+ |
1109 |
+export PATH="$PATH:/usr/local/bin/ssl:/usr/sbin" |
1110 |
+ |
1111 |
+openssl genrsa -out QMAIL/control/rsa2048.new 2048 && |
1112 |
+chmod 600 QMAIL/control/rsa2048.new && |
1113 |
+chown UGQMAILD QMAIL/control/rsa2048.new && |
1114 |
+mv -f QMAIL/control/rsa2048.new QMAIL/control/rsa2048.pem |
1115 |
+echo |
1116 |
+ |
1117 |
+openssl dhparam -2 -out QMAIL/control/dh2048.new 2048 && |
1118 |
+chmod 600 QMAIL/control/dh2048.new && |
1119 |
+chown UGQMAILD QMAIL/control/dh2048.new && |
1120 |
+mv -f QMAIL/control/dh2048.new QMAIL/control/dh2048.pem |