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