/[smeserver]/rpms/qmail/sme9/netqmail-1.06-tls-20190517.patch
ViewVC logotype

Annotation of /rpms/qmail/sme9/netqmail-1.06-tls-20190517.patch

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (hide annotations) (download)
Tue Sep 3 02:09:55 2019 UTC (4 years, 9 months ago) by jpp
Branch: MAIN
CVS Tags: qmail-1_03-24_el6_sme, HEAD
* Mon Sep 02 2019 Jean-Philipe Pialasse <tests@pialasse.com> 1.03-24.sme
- update to last version of patch [SME: 9349]

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

admin@koozali.org
ViewVC Help
Powered by ViewVC 1.2.1 RSS 2.0 feed