1151 lines
35 KiB
Diff
1151 lines
35 KiB
Diff
Frederik Vermeulen <qmail-tls akrul inoa.net> 20190517
|
|
http://inoa.net/qmail-tls/
|
|
|
|
This patch implements RFC 3207 in qmail.
|
|
This means you can get SSL or TLS encrypted and
|
|
authenticated SMTP between the MTAs and from MUA to MTA.
|
|
The code is considered experimental (but has worked for
|
|
many since its first release on 1999-03-21).
|
|
|
|
Usage: - install OpenSSL-1.1.0 http://www.openssl.org/ or later
|
|
(any version since 0.9.8 is presumed to work)
|
|
- apply patch to netqmail-1.06 http://qmail.org/netqmail
|
|
The patches to qmail-remote.c and qmail-smtpd.c can be applied
|
|
separately.
|
|
- provide a server certificate in /var/qmail/control/servercert.pem.
|
|
"make cert" makes a self-signed certificate.
|
|
"make cert-req" makes a certificate request.
|
|
Note: you can add the CA certificate and intermediate
|
|
certs to the end of servercert.pem.
|
|
- replace qmail-smtpd and/or qmail-remote binary
|
|
- verify operation (header information should show
|
|
something like
|
|
"Received [..] with (DHE-RSA-AES256-SHA encrypted) SMTP;")
|
|
|
|
Optional: - when DEBUG is defined, some extra TLS info will be logged
|
|
- qmail-remote will authenticate with the certificate in
|
|
/var/qmail/control/clientcert.pem. By preference this is
|
|
the same as servercert.pem, where nsCertType should be
|
|
== server,client or be a generic certificate (no usage specified).
|
|
- when a 2048 bit RSA key is provided in /var/qmail/control/rsa2048.pem,
|
|
this key will be used instead of (slow) on-the-fly generation by
|
|
qmail-smtpd. Idem for 2048 DH param in control/dh2048.pem.
|
|
`make tmprsadh` does this.
|
|
Periodical replacement can be done by crontab:
|
|
01 01 * * * /var/qmail/bin/update_tmprsadh > /dev/null 2>&1
|
|
- server authentication:
|
|
qmail-remote requires authentication from servers for which
|
|
/var/qmail/control/tlshosts/host.dom.ain.pem exists.
|
|
The .pem file contains the validating CA certificates.
|
|
One of the dNSName or the CommonName attributes have to match.
|
|
WARNING: this option may cause mail to be delayed, bounced,
|
|
doublebounced, and lost.
|
|
If /var/qmail/control/tlshosts/exhaustivelist is present,
|
|
the lists of hosts in /var/qmail/control/tlshosts is
|
|
an exhaustive list of hosts TLS is tried on.
|
|
If /var/qmail/control/notlshosts/host.dom.ain is present,
|
|
no TLS is tried on this host.
|
|
- client authentication:
|
|
when relay rules would reject an incoming mail,
|
|
qmail-smtpd can allow the mail based on a presented cert.
|
|
Certs are verified against a CA list in
|
|
/var/qmail/control/clientca.pem (eg. from
|
|
http://curl.haxx.se/ca/cacert.pem)
|
|
and the cert email-address has to match a line in
|
|
/var/qmail/control/tlsclients. This email-address is logged
|
|
in the headers. CRLs can be provided through
|
|
/var/qmail/control/clientcrl.pem.
|
|
- cipher selection:
|
|
qmail-remote:
|
|
openssl cipher string (`man ciphers`) read from
|
|
/var/qmail/control/tlsclientciphers
|
|
qmail-smtpd:
|
|
openssl cipher string read from TLSCIPHERS environment variable
|
|
(can vary based on client IP address e.g.)
|
|
or if that is not available /var/qmail/control/tlsserverciphers
|
|
- smtps (deprecated SMTP over TLS via port 465):
|
|
qmail-remote: when connecting to port 465
|
|
qmail-smtpd: when SMTPS environment variable is not empty
|
|
|
|
Caveats: - do a `make clean` after patching
|
|
- binaries dynamically linked with current openssl versions need
|
|
recompilation when the shared openssl libs are upgraded.
|
|
- this patch could conflict with other patches (notably those
|
|
replacing \n with \r\n, which is a bad idea on encrypted links).
|
|
- needs working /dev/urandom (or EGD for openssl versions >0.9.7)
|
|
for seeding random number generator.
|
|
- packagers should make sure that installing without a valid
|
|
servercert is impossible
|
|
- when applied in combination with AUTH patch, AUTH patch
|
|
should be applied first and first part of this patch
|
|
will fail. This error can be ignored. Packagers should
|
|
cut the first 12 lines of this patch to make a happy
|
|
patch
|
|
- `make tmprsadh` is recommended (or should I say required),
|
|
otherwise DH generation can be unpredictably slow
|
|
- some need "-I/usr/kerberos/include" to be added in conf-cc
|
|
|
|
Copyright: GPL
|
|
Links with OpenSSL
|
|
Inspiration and code from examples in SSLeay (E. Young
|
|
<eay@cryptsoft.com> and T. Hudson <tjh@cryptsoft.com>),
|
|
stunnel (M. Trojnara <mtrojnar@ddc.daewoo.com.pl>),
|
|
Postfix/TLS (L. Jaenicke <Lutz.Jaenicke@aet.tu-cottbus.de>),
|
|
modssl (R. Engelschall <rse@engelschall.com>),
|
|
openssl examples of E. Rescorla <ekr@rtfm.com>.
|
|
|
|
Bug reports: mailto:<qmail-tls akrul inoa.net>
|
|
|
|
|
|
>----< Cut the next 12 lines if applying over AUTH server patch >---<
|
|
--- qmail-1.03/qmail-smtpd.c Mon Jun 15 03:53:16 1998
|
|
+++ qmail-1.03-tls/qmail-smtpd.c Tue Jun 18 09:49:38 2002
|
|
@@ -229,7 +229,8 @@
|
|
}
|
|
void smtp_ehlo(arg) char *arg;
|
|
{
|
|
- smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
|
|
+ smtp_greet("250-");
|
|
+ out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
|
|
seenmail = 0; dohelo(arg);
|
|
}
|
|
void smtp_rset()
|
|
>----< Cut previous 12 lines if applying over AUTH server patch >---<
|
|
|
|
|
|
|
|
>----< The next 89 lines are the qmail-remote EHLO patch >---<
|
|
--- qmail-1.03/qmail-remote.c Mon Jun 15 03:53:16 1998
|
|
+++ qmail-1.03-tls/qmail-remote.c Sun Nov 24 13:05:20 2002
|
|
@@ -163,6 +163,59 @@ unsigned long smtpcode()
|
|
return code;
|
|
}
|
|
|
|
+#ifdef EHLO
|
|
+saa ehlokw = {0}; /* list of EHLO keywords and parameters */
|
|
+int maxehlokwlen = 0;
|
|
+
|
|
+unsigned long ehlo()
|
|
+{
|
|
+ stralloc *sa;
|
|
+ char *s, *e, *p;
|
|
+ unsigned long code;
|
|
+
|
|
+ if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len;
|
|
+ ehlokw.len = 0;
|
|
+
|
|
+# ifdef MXPS
|
|
+ if (type == 's') return 0;
|
|
+# endif
|
|
+
|
|
+ substdio_puts(&smtpto, "EHLO ");
|
|
+ substdio_put(&smtpto, helohost.s, helohost.len);
|
|
+ substdio_puts(&smtpto, "\r\n");
|
|
+ substdio_flush(&smtpto);
|
|
+
|
|
+ code = smtpcode();
|
|
+ if (code != 250) return code;
|
|
+
|
|
+ s = smtptext.s;
|
|
+ while (*s++ != '\n') ; /* skip the first line: contains the domain */
|
|
+
|
|
+ e = smtptext.s + smtptext.len - 6; /* 250-?\n */
|
|
+ while (s <= e)
|
|
+ {
|
|
+ if (!saa_readyplus(&ehlokw, 1)) temp_nomem();
|
|
+ sa = ehlokw.sa + ehlokw.len++;
|
|
+ if (ehlokw.len > maxehlokwlen) *sa = sauninit; else sa->len = 0;
|
|
+
|
|
+ /* smtptext is known to end in a '\n' */
|
|
+ for (p = (s += 4); ; ++p)
|
|
+ if (*p == '\n' || *p == ' ' || *p == '\t') {
|
|
+ if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem();
|
|
+ if (*p++ == '\n') break;
|
|
+ while (*p == ' ' || *p == '\t') ;
|
|
+ s = p;
|
|
+ }
|
|
+ s = p;
|
|
+ /* keyword should consist of alpha-num and '-'
|
|
+ * broken AUTH might use '=' instead of space */
|
|
+ for (p = sa->s; *p; ++p) if (*p == '=') { *p = 0; break; }
|
|
+ }
|
|
+
|
|
+ return 250;
|
|
+}
|
|
+#endif
|
|
+
|
|
void outsmtptext()
|
|
{
|
|
int i;
|
|
@@ -224,12 +277,26 @@ void smtp()
|
|
|
|
if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
|
|
|
|
+#ifdef EHLO
|
|
+ code = ehlo();
|
|
+
|
|
+ if (code == 250) {
|
|
+ /* add EHLO response checks here */
|
|
+
|
|
+ /* and if EHLO failed, use HELO */
|
|
+ } else {
|
|
+#endif
|
|
+
|
|
substdio_puts(&smtpto,"HELO ");
|
|
substdio_put(&smtpto,helohost.s,helohost.len);
|
|
substdio_puts(&smtpto,"\r\n");
|
|
substdio_flush(&smtpto);
|
|
if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
|
|
|
|
+#ifdef EHLO
|
|
+ }
|
|
+#endif
|
|
+
|
|
substdio_puts(&smtpto,"MAIL FROM:<");
|
|
substdio_put(&smtpto,sender.s,sender.len);
|
|
substdio_puts(&smtpto,">\r\n");
|
|
>----< Previous 89 lines are the qmail-remote EHLO patch >---<
|
|
|
|
|
|
|
|
|
|
--- netqmail-1.06-orig/qmail-remote.c 2019-04-08 15:26:13.100123364 +0000
|
|
+++ netqmail-1.06/qmail-remote.c 2019-04-02 08:01:50.176790637 +0000
|
|
@@ -48,6 +48,17 @@ saa reciplist = {0};
|
|
|
|
struct ip_address partner;
|
|
|
|
+#ifdef TLS
|
|
+# include <sys/stat.h>
|
|
+# include "tls.h"
|
|
+# include "ssl_timeoutio.h"
|
|
+# include <openssl/x509v3.h>
|
|
+# define EHLO 1
|
|
+
|
|
+int tls_init();
|
|
+const char *ssl_err_str = 0;
|
|
+#endif
|
|
+
|
|
void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
|
|
void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
|
|
void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); }
|
|
@@ -99,6 +110,9 @@ void dropped() {
|
|
outhost();
|
|
out(" but connection died. ");
|
|
if (flagcritical) out("Possible duplicate! ");
|
|
+#ifdef TLS
|
|
+ if (ssl_err_str) { out((char *)ssl_err_str); out(" "); }
|
|
+#endif
|
|
out("(#4.4.2)\n");
|
|
zerodie();
|
|
}
|
|
@@ -110,6 +124,12 @@ int timeout = 1200;
|
|
int saferead(fd,buf,len) int fd; char *buf; int len;
|
|
{
|
|
int r;
|
|
+#ifdef TLS
|
|
+ if (ssl) {
|
|
+ r = ssl_timeoutread(timeout, smtpfd, smtpfd, ssl, buf, len);
|
|
+ if (r < 0) ssl_err_str = ssl_error_str();
|
|
+ } else
|
|
+#endif
|
|
r = timeoutread(timeout,smtpfd,buf,len);
|
|
if (r <= 0) dropped();
|
|
return r;
|
|
@@ -117,6 +137,12 @@ int saferead(fd,buf,len) int fd; char *b
|
|
int safewrite(fd,buf,len) int fd; char *buf; int len;
|
|
{
|
|
int r;
|
|
+#ifdef TLS
|
|
+ if (ssl) {
|
|
+ r = ssl_timeoutwrite(timeout, smtpfd, smtpfd, ssl, buf, len);
|
|
+ if (r < 0) ssl_err_str = ssl_error_str();
|
|
+ } else
|
|
+#endif
|
|
r = timeoutwrite(timeout,smtpfd,buf,len);
|
|
if (r <= 0) dropped();
|
|
return r;
|
|
@@ -194,19 +220,25 @@ unsigned long ehlo()
|
|
e = smtptext.s + smtptext.len - 6; /* 250-?\n */
|
|
while (s <= e)
|
|
{
|
|
+ int wasspace = 0;
|
|
+
|
|
if (!saa_readyplus(&ehlokw, 1)) temp_nomem();
|
|
sa = ehlokw.sa + ehlokw.len++;
|
|
if (ehlokw.len > maxehlokwlen) *sa = sauninit; else sa->len = 0;
|
|
|
|
- /* smtptext is known to end in a '\n' */
|
|
- for (p = (s += 4); ; ++p)
|
|
- if (*p == '\n' || *p == ' ' || *p == '\t') {
|
|
- if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem();
|
|
- if (*p++ == '\n') break;
|
|
- while (*p == ' ' || *p == '\t') ;
|
|
- s = p;
|
|
- }
|
|
- s = p;
|
|
+ /* smtptext is known to end in a '\n' */
|
|
+ for (p = (s += 4); ; ++p)
|
|
+ if (*p == '\n' || *p == ' ' || *p == '\t') {
|
|
+ if (!wasspace)
|
|
+ if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem();
|
|
+ if (*p == '\n') break;
|
|
+ wasspace = 1;
|
|
+ } else if (wasspace == 1) {
|
|
+ wasspace = 0;
|
|
+ s = p;
|
|
+ }
|
|
+ s = ++p;
|
|
+
|
|
/* keyword should consist of alpha-num and '-'
|
|
* broken AUTH might use '=' instead of space */
|
|
for (p = sa->s; *p; ++p) if (*p == '=') { *p = 0; break; }
|
|
@@ -232,6 +264,17 @@ void quit(prepend,append)
|
|
char *prepend;
|
|
char *append;
|
|
{
|
|
+#ifdef TLS
|
|
+ /* shouldn't talk to the client unless in an appropriate state */
|
|
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
+ OSSL_HANDSHAKE_STATE state = ssl ? SSL_get_state(ssl) : TLS_ST_BEFORE;
|
|
+ if (state & TLS_ST_OK || (!smtps && state & TLS_ST_BEFORE))
|
|
+
|
|
+#else
|
|
+ int state = ssl ? ssl->state : SSL_ST_BEFORE;
|
|
+ if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE))
|
|
+#endif
|
|
+#endif
|
|
substdio_putsflush(&smtpto,"QUIT\r\n");
|
|
/* waiting for remote side is just too ridiculous */
|
|
out(prepend);
|
|
@@ -239,6 +282,30 @@ char *append;
|
|
out(append);
|
|
out(".\n");
|
|
outsmtptext();
|
|
+
|
|
+#if defined(TLS) && defined(DEBUG)
|
|
+ if (ssl) {
|
|
+ X509 *peercert;
|
|
+
|
|
+ out("STARTTLS proto="); out(SSL_get_version(ssl));
|
|
+ out("; cipher="); out(SSL_get_cipher(ssl));
|
|
+
|
|
+ /* we want certificate details */
|
|
+ if (peercert = SSL_get_peer_certificate(ssl)) {
|
|
+ char *str;
|
|
+
|
|
+ str = X509_NAME_oneline(X509_get_subject_name(peercert), NULL, 0);
|
|
+ out("; subject="); out(str); OPENSSL_free(str);
|
|
+
|
|
+ str = X509_NAME_oneline(X509_get_issuer_name(peercert), NULL, 0);
|
|
+ out("; issuer="); out(str); OPENSSL_free(str);
|
|
+
|
|
+ X509_free(peercert);
|
|
+ }
|
|
+ out(";\n");
|
|
+ }
|
|
+#endif
|
|
+
|
|
zerodie();
|
|
}
|
|
|
|
@@ -267,6 +334,206 @@ void blast()
|
|
substdio_flush(&smtpto);
|
|
}
|
|
|
|
+#ifdef TLS
|
|
+char *partner_fqdn = 0;
|
|
+
|
|
+# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "")
|
|
+void tls_quit(const char *s1, const char *s2)
|
|
+{
|
|
+ out((char *)s1); if (s2) { out(": "); out((char *)s2); } TLS_QUIT;
|
|
+}
|
|
+# define tls_quit_error(s) tls_quit(s, ssl_error())
|
|
+
|
|
+int match_partner(const char *s, int len)
|
|
+{
|
|
+ if (!case_diffb(partner_fqdn, len, s) && !partner_fqdn[len]) return 1;
|
|
+ /* we also match if the name is *.domainname */
|
|
+ if (*s == '*') {
|
|
+ const char *domain = partner_fqdn + str_chr(partner_fqdn, '.');
|
|
+ if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* don't want to fail handshake if certificate can't be verified */
|
|
+int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
|
|
+
|
|
+int tls_init()
|
|
+{
|
|
+ int i;
|
|
+ SSL *myssl;
|
|
+ SSL_CTX *ctx;
|
|
+ stralloc saciphers = {0};
|
|
+ const char *ciphers, *servercert = 0;
|
|
+
|
|
+ if (partner_fqdn) {
|
|
+ struct stat st;
|
|
+ stralloc tmp = {0};
|
|
+ if (!stralloc_copys(&tmp, "control/tlshosts/")
|
|
+ || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn))
|
|
+ || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem();
|
|
+ if (stat(tmp.s, &st) == 0)
|
|
+ servercert = tmp.s;
|
|
+ else {
|
|
+ if (!stralloc_copys(&tmp, "control/notlshosts/")
|
|
+ || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1))
|
|
+ temp_nomem();
|
|
+ if ((stat("control/tlshosts/exhaustivelist", &st) == 0) ||
|
|
+ (stat(tmp.s, &st) == 0)) {
|
|
+ alloc_free(tmp.s);
|
|
+ return 0;
|
|
+ }
|
|
+ alloc_free(tmp.s);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!smtps) {
|
|
+ stralloc *sa = ehlokw.sa;
|
|
+ unsigned int len = ehlokw.len;
|
|
+ /* look for STARTTLS among EHLO keywords */
|
|
+ for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ;
|
|
+ if (!len) {
|
|
+ if (!servercert) return 0;
|
|
+ out("ZNo TLS achieved while "); out((char *)servercert);
|
|
+ out(" exists"); smtptext.len = 0; TLS_QUIT;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ SSL_library_init();
|
|
+ ctx = SSL_CTX_new(SSLv23_client_method());
|
|
+ if (!ctx) {
|
|
+ if (!smtps && !servercert) return 0;
|
|
+ smtptext.len = 0;
|
|
+ tls_quit_error("ZTLS error initializing ctx");
|
|
+ }
|
|
+
|
|
+ /* POODLE vulnerability */
|
|
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
|
+
|
|
+ if (servercert) {
|
|
+ if (!SSL_CTX_load_verify_locations(ctx, servercert, NULL)) {
|
|
+ SSL_CTX_free(ctx);
|
|
+ smtptext.len = 0;
|
|
+ out("ZTLS unable to load "); tls_quit_error(servercert);
|
|
+ }
|
|
+ /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
|
|
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
|
|
+ }
|
|
+
|
|
+ /* let the other side complain if it needs a cert and we don't have one */
|
|
+# define CLIENTCERT "control/clientcert.pem"
|
|
+ if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT))
|
|
+ SSL_CTX_use_RSAPrivateKey_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM);
|
|
+# undef CLIENTCERT
|
|
+
|
|
+ myssl = SSL_new(ctx);
|
|
+ SSL_CTX_free(ctx);
|
|
+ if (!myssl) {
|
|
+ if (!smtps && !servercert) return 0;
|
|
+ smtptext.len = 0;
|
|
+ tls_quit_error("ZTLS error initializing ssl");
|
|
+ }
|
|
+
|
|
+ if (!smtps) substdio_putsflush(&smtpto, "STARTTLS\r\n");
|
|
+
|
|
+ /* while the server is preparing a response, do something else */
|
|
+ if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1)
|
|
+ { SSL_free(myssl); temp_control(); }
|
|
+ if (saciphers.len) {
|
|
+ for (i = 0; i < saciphers.len - 1; ++i)
|
|
+ if (!saciphers.s[i]) saciphers.s[i] = ':';
|
|
+ ciphers = saciphers.s;
|
|
+ }
|
|
+ else ciphers = "DEFAULT";
|
|
+ SSL_set_cipher_list(myssl, ciphers);
|
|
+ alloc_free(saciphers.s);
|
|
+
|
|
+ SSL_set_fd(myssl, smtpfd);
|
|
+
|
|
+ /* read the response to STARTTLS */
|
|
+ if (!smtps) {
|
|
+ if (smtpcode() != 220) {
|
|
+ SSL_free(myssl);
|
|
+ if (!servercert) return 0;
|
|
+ out("ZSTARTTLS rejected while ");
|
|
+ out((char *)servercert); out(" exists"); TLS_QUIT;
|
|
+ }
|
|
+ smtptext.len = 0;
|
|
+ }
|
|
+
|
|
+ ssl = myssl;
|
|
+ if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0)
|
|
+ tls_quit("ZTLS connect failed", ssl_error_str());
|
|
+
|
|
+ if (servercert) {
|
|
+ X509 *peercert;
|
|
+ STACK_OF(GENERAL_NAME) *gens;
|
|
+ int found_gen_dns = 0;
|
|
+ int matched_gen_dns = 0;
|
|
+
|
|
+ int r = SSL_get_verify_result(ssl);
|
|
+ if (r != X509_V_OK) {
|
|
+ out("ZTLS unable to verify server with ");
|
|
+ tls_quit(servercert, X509_verify_cert_error_string(r));
|
|
+ }
|
|
+ alloc_free(servercert);
|
|
+
|
|
+ peercert = SSL_get_peer_certificate(ssl);
|
|
+ if (!peercert) {
|
|
+ out("ZTLS unable to verify server ");
|
|
+ tls_quit(partner_fqdn, "no certificate provided");
|
|
+ }
|
|
+
|
|
+ /* RFC 2595 section 2.4: find a matching name
|
|
+ * first find a match among alternative names */
|
|
+ gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
|
|
+ if (gens) {
|
|
+ for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i)
|
|
+ {
|
|
+ const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
|
|
+ if (gn->type == GEN_DNS){
|
|
+ found_gen_dns = 1;
|
|
+ if (match_partner(gn->d.ia5->data, gn->d.ia5->length)){
|
|
+ matched_gen_dns = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
|
|
+ }
|
|
+
|
|
+ /* no SubjectAltName of type DNS found, look up commonName */
|
|
+ if (!found_gen_dns) {
|
|
+ stralloc peer = {0};
|
|
+ X509_NAME *subj = X509_get_subject_name(peercert);
|
|
+ i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
|
|
+ if (i >= 0) {
|
|
+ const ASN1_STRING *s = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subj, i));
|
|
+ if (s) { peer.len = s->length; peer.s = s->data; }
|
|
+ }
|
|
+ if (peer.len <= 0) {
|
|
+ out("ZTLS unable to verify server ");
|
|
+ tls_quit(partner_fqdn, "certificate contains no valid commonName");
|
|
+ }
|
|
+ if (!match_partner(peer.s, peer.len)) {
|
|
+ out("ZTLS unable to verify server "); out(partner_fqdn);
|
|
+ out(": received certificate for "); outsafe(&peer); TLS_QUIT;
|
|
+ }
|
|
+ } else if (!matched_gen_dns) {
|
|
+ out("ZTLS unable to verify server ");
|
|
+ tls_quit(partner_fqdn, "certificate contains no matching dNSNnames");
|
|
+ }
|
|
+
|
|
+ X509_free(peercert);
|
|
+ }
|
|
+
|
|
+ if (smtps) if (smtpcode() != 220)
|
|
+ quit("ZTLS Connected to "," but greeting failed");
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+#endif
|
|
+
|
|
stralloc recip = {0};
|
|
|
|
void smtp()
|
|
@@ -274,12 +541,37 @@ void smtp()
|
|
unsigned long code;
|
|
int flagbother;
|
|
int i;
|
|
+
|
|
+#ifndef PORT_SMTP
|
|
+ /* the qmtpc patch uses smtp_port and undefines PORT_SMTP */
|
|
+# define port smtp_port
|
|
+#endif
|
|
+
|
|
+#ifdef TLS
|
|
+# ifdef MXPS
|
|
+ if (type == 'S') smtps = 1;
|
|
+ else if (type != 's')
|
|
+# endif
|
|
+ if (port == 465) smtps = 1;
|
|
+ if (!smtps)
|
|
+#endif
|
|
|
|
if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
|
|
|
|
#ifdef EHLO
|
|
+# ifdef TLS
|
|
+ if (!smtps)
|
|
+# endif
|
|
code = ehlo();
|
|
|
|
+# ifdef TLS
|
|
+ if (tls_init())
|
|
+ /* RFC2487 says we should issue EHLO (even if we might not need
|
|
+ * extensions); at the same time, it does not prohibit a server
|
|
+ * to reject the EHLO and make us fallback to HELO */
|
|
+ code = ehlo();
|
|
+# endif
|
|
+
|
|
if (code == 250) {
|
|
/* add EHLO response checks here */
|
|
|
|
@@ -484,6 +776,9 @@ char **argv;
|
|
if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
|
|
tcpto_err(&ip.ix[i].ip,0);
|
|
partner = ip.ix[i].ip;
|
|
+#ifdef TLS
|
|
+ partner_fqdn = ip.ix[i].fqdn;
|
|
+#endif
|
|
smtp(); /* does not return */
|
|
}
|
|
tcpto_err(&ip.ix[i].ip,errno == error_timeout);
|
|
--- netqmail-1.06-orig/qmail-remote.8 1998-06-15 10:53:16.000000000 +0000
|
|
+++ netqmail-1.06/qmail-remote.8 2015-12-01 15:54:59.029940779 +0000
|
|
@@ -114,6 +114,10 @@ arguments.
|
|
always exits zero.
|
|
.SH "CONTROL FILES"
|
|
.TP 5
|
|
+.I clientcert.pem
|
|
+SSL certificate that is used to authenticate with the remote server
|
|
+during a TLS session.
|
|
+.TP 5
|
|
.I helohost
|
|
Current host name,
|
|
for use solely in saying hello to the remote SMTP server.
|
|
@@ -123,6 +127,16 @@ if that is supplied;
|
|
otherwise
|
|
.B qmail-remote
|
|
refuses to run.
|
|
+
|
|
+.TP 5
|
|
+.I notlshosts/<FQDN>
|
|
+.B qmail-remote
|
|
+will not try TLS on servers for which this file exists
|
|
+.RB ( <FQDN>
|
|
+is the fully-qualified domain name of the server).
|
|
+.IR (tlshosts/<FQDN>.pem
|
|
+takes precedence over this file however).
|
|
+
|
|
.TP 5
|
|
.I smtproutes
|
|
Artificial SMTP routes.
|
|
@@ -156,6 +170,8 @@ may be empty;
|
|
this tells
|
|
.B qmail-remote
|
|
to look up MX records as usual.
|
|
+.I port
|
|
+value of 465 (deprecated smtps port) causes TLS session to be started.
|
|
.I smtproutes
|
|
may include wildcards:
|
|
|
|
@@ -195,6 +211,33 @@ Number of seconds
|
|
.B qmail-remote
|
|
will wait for each response from the remote SMTP server.
|
|
Default: 1200.
|
|
+
|
|
+.TP 5
|
|
+.I tlsclientciphers
|
|
+A set of OpenSSL client cipher strings. Multiple ciphers
|
|
+contained in a string should be separated by a colon.
|
|
+
|
|
+.TP 5
|
|
+.I tlshosts/<FQDN>.pem
|
|
+.B qmail-remote
|
|
+requires TLS authentication from servers for which this file exists
|
|
+.RB ( <FQDN>
|
|
+is the fully-qualified domain name of the server). One of the
|
|
+.I dNSName
|
|
+or the
|
|
+.I CommonName
|
|
+attributes have to match. The file contains the trusted CA certificates.
|
|
+
|
|
+.B WARNING:
|
|
+this option may cause mail to be delayed, bounced, doublebounced, or lost.
|
|
+
|
|
+.TP 5
|
|
+.I tlshosts/exhaustivelist
|
|
+if this file exists
|
|
+no TLS will be tried on hosts other than those for which a file
|
|
+.B tlshosts/<FQDN>.pem
|
|
+exists.
|
|
+
|
|
.SH "SEE ALSO"
|
|
addresses(5),
|
|
envelopes(5),
|
|
--- netqmail-1.06-orig/qmail-control.9 1998-06-15 10:53:16.000000000 +0000
|
|
+++ netqmail-1.06/qmail-control.9 2015-12-08 00:33:06.248714330 +0000
|
|
@@ -43,11 +43,14 @@ control default used by
|
|
.I badmailfrom \fR(none) \fRqmail-smtpd
|
|
.I bouncefrom \fRMAILER-DAEMON \fRqmail-send
|
|
.I bouncehost \fIme \fRqmail-send
|
|
+.I clientca.pem \fR(none) \fRqmail-smtpd
|
|
+.I clientcert.pem \fR(none) \fRqmail-remote
|
|
.I concurrencylocal \fR10 \fRqmail-send
|
|
.I concurrencyremote \fR20 \fRqmail-send
|
|
.I defaultdomain \fIme \fRqmail-inject
|
|
.I defaulthost \fIme \fRqmail-inject
|
|
.I databytes \fR0 \fRqmail-smtpd
|
|
+.I dh2048.pem \fR(none) \fRqmail-smtpd
|
|
.I doublebouncehost \fIme \fRqmail-send
|
|
.I doublebounceto \fRpostmaster \fRqmail-send
|
|
.I envnoathost \fIme \fRqmail-send
|
|
@@ -61,11 +64,17 @@ control default used by
|
|
.I qmqpservers \fR(none) \fRqmail-qmqpc
|
|
.I queuelifetime \fR604800 \fRqmail-send
|
|
.I rcpthosts \fR(none) \fRqmail-smtpd
|
|
+.I rsa2048.pem \fR(none) \fRqmail-smtpd
|
|
+.I servercert.pem \fR(none) \fRqmail-smtpd
|
|
.I smtpgreeting \fIme \fRqmail-smtpd
|
|
.I smtproutes \fR(none) \fRqmail-remote
|
|
.I timeoutconnect \fR60 \fRqmail-remote
|
|
.I timeoutremote \fR1200 \fRqmail-remote
|
|
.I timeoutsmtpd \fR1200 \fRqmail-smtpd
|
|
+.I tlsclients \fR(none) \fRqmail-smtpd
|
|
+.I tlsclientciphers \fR(none) \fRqmail-remote
|
|
+.I tlshosts/FQDN.pem \fR(none) \fRqmail-remote
|
|
+.I tlsserverciphers \fR(none) \fRqmail-smtpd
|
|
.I virtualdomains \fR(none) \fRqmail-send
|
|
.fi
|
|
.RE
|
|
--- netqmail-1.06-orig/dns.c 2007-11-30 20:22:54.000000000 +0000
|
|
+++ netqmail-1.06/dns.c 2019-04-08 15:22:04.390598941 +0000
|
|
@@ -267,12 +267,14 @@ stralloc *sa;
|
|
int pref;
|
|
{
|
|
int r;
|
|
- struct ip_mx ix;
|
|
+ struct ip_mx ix = {0};
|
|
|
|
if (!stralloc_copy(&glue,sa)) return DNS_MEM;
|
|
if (!stralloc_0(&glue)) return DNS_MEM;
|
|
if (glue.s[0]) {
|
|
+#ifndef IX_FQDN
|
|
ix.pref = 0;
|
|
+#endif
|
|
if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
|
|
{
|
|
if (!ipalloc_append(ia,&ix)) return DNS_MEM;
|
|
@@ -291,9 +293,16 @@ int pref;
|
|
ix.ip = ip;
|
|
ix.pref = pref;
|
|
if (r == DNS_SOFT) return DNS_SOFT;
|
|
- if (r == 1)
|
|
+ if (r == 1) {
|
|
+#ifdef IX_FQDN
|
|
+ ix.fqdn = glue.s;
|
|
+#endif
|
|
if (!ipalloc_append(ia,&ix)) return DNS_MEM;
|
|
}
|
|
+ }
|
|
+#ifdef IX_FQDN
|
|
+ glue.s = 0;
|
|
+#endif
|
|
return 0;
|
|
}
|
|
|
|
@@ -313,7 +322,7 @@ unsigned long random;
|
|
{
|
|
int r;
|
|
struct mx { stralloc sa; unsigned short p; } *mx;
|
|
- struct ip_mx ix;
|
|
+ struct ip_mx ix = {0};
|
|
int nummx;
|
|
int i;
|
|
int j;
|
|
@@ -325,7 +334,9 @@ unsigned long random;
|
|
if (!stralloc_copy(&glue,sa)) return DNS_MEM;
|
|
if (!stralloc_0(&glue)) return DNS_MEM;
|
|
if (glue.s[0]) {
|
|
+#ifndef IX_FQDN
|
|
ix.pref = 0;
|
|
+#endif
|
|
if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
|
|
{
|
|
if (!ipalloc_append(ia,&ix)) return DNS_MEM;
|
|
--- netqmail-1.06-orig/hier.c 1998-06-15 10:53:16.000000000 +0000
|
|
+++ netqmail-1.06/hier.c 2015-12-01 15:54:59.033940812 +0000
|
|
@@ -143,6 +143,9 @@ void hier()
|
|
c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755);
|
|
c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755);
|
|
c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755);
|
|
+#ifdef TLS
|
|
+ c(auto_qmail,"bin","update_tmprsadh",auto_uido,auto_gidq,0755);
|
|
+#endif
|
|
|
|
c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644);
|
|
c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644);
|
|
--- netqmail-1.06-orig/ipalloc.h 1998-06-15 10:53:16.000000000 +0000
|
|
+++ netqmail-1.06/ipalloc.h 2015-12-01 15:54:59.033940812 +0000
|
|
@@ -3,7 +3,15 @@
|
|
|
|
#include "ip.h"
|
|
|
|
+#ifdef TLS
|
|
+# define IX_FQDN 1
|
|
+#endif
|
|
+
|
|
+#ifdef IX_FQDN
|
|
+struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ;
|
|
+#else
|
|
struct ip_mx { struct ip_address ip; int pref; } ;
|
|
+#endif
|
|
|
|
#include "gen_alloc.h"
|
|
|
|
--- netqmail-1.06-orig/tls.c 2019-04-08 15:26:13.112123436 +0000
|
|
+++ netqmail-1.06/tls.c 2019-04-08 15:17:31.924930725 +0000
|
|
@@ -0,0 +1,27 @@
|
|
+#ifdef TLS
|
|
+#include "exit.h"
|
|
+#include "error.h"
|
|
+#include <openssl/ssl.h>
|
|
+#include <openssl/err.h>
|
|
+
|
|
+int smtps = 0;
|
|
+SSL *ssl = NULL;
|
|
+
|
|
+void ssl_free(SSL *myssl) { SSL_shutdown(myssl); SSL_free(myssl); }
|
|
+void ssl_exit(int status) { if (ssl) ssl_free(ssl); _exit(status); }
|
|
+
|
|
+const char *ssl_error()
|
|
+{
|
|
+ int r = ERR_get_error();
|
|
+ if (!r) return NULL;
|
|
+ SSL_load_error_strings();
|
|
+ return ERR_error_string(r, NULL);
|
|
+}
|
|
+const char *ssl_error_str()
|
|
+{
|
|
+ const char *err = ssl_error();
|
|
+ if (err) return err;
|
|
+ if (!errno) return 0;
|
|
+ return (errno == error_timeout) ? "timed out" : error_str(errno);
|
|
+}
|
|
+#endif
|
|
--- netqmail-1.06-orig/tls.h 2019-04-08 15:26:13.112123436 +0000
|
|
+++ netqmail-1.06/tls.h 2015-12-01 15:54:59.033940812 +0000
|
|
@@ -0,0 +1,16 @@
|
|
+#ifndef TLS_H
|
|
+#define TLS_H
|
|
+
|
|
+#include <openssl/ssl.h>
|
|
+
|
|
+extern int smtps;
|
|
+extern SSL *ssl;
|
|
+
|
|
+void ssl_free(SSL *myssl);
|
|
+void ssl_exit(int status);
|
|
+# define _exit ssl_exit
|
|
+
|
|
+const char *ssl_error();
|
|
+const char *ssl_error_str();
|
|
+
|
|
+#endif
|
|
--- netqmail-1.06-orig/ssl_timeoutio.c 2019-04-08 15:26:13.112123436 +0000
|
|
+++ netqmail-1.06/ssl_timeoutio.c 2019-04-08 15:17:14.324823036 +0000
|
|
@@ -0,0 +1,114 @@
|
|
+#ifdef TLS
|
|
+#include "select.h"
|
|
+#include "error.h"
|
|
+#include "ndelay.h"
|
|
+#include "now.h"
|
|
+#include "ssl_timeoutio.h"
|
|
+
|
|
+int ssl_timeoutio(int (*fun)(),
|
|
+ int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
|
|
+{
|
|
+ int n;
|
|
+ const datetime_sec end = (datetime_sec)t + now();
|
|
+
|
|
+ do {
|
|
+ fd_set fds;
|
|
+ struct timeval tv;
|
|
+
|
|
+ const int r = buf ? fun(ssl, buf, len) : fun(ssl);
|
|
+ if (r > 0) return r;
|
|
+
|
|
+ t = end - now();
|
|
+ if (t < 0) break;
|
|
+ tv.tv_sec = (time_t)t; tv.tv_usec = 0;
|
|
+
|
|
+ FD_ZERO(&fds);
|
|
+ switch (SSL_get_error(ssl, r))
|
|
+ {
|
|
+ default: return r; /* some other error */
|
|
+ case SSL_ERROR_WANT_READ:
|
|
+ FD_SET(rfd, &fds); n = select(rfd + 1, &fds, NULL, NULL, &tv);
|
|
+ break;
|
|
+ case SSL_ERROR_WANT_WRITE:
|
|
+ FD_SET(wfd, &fds); n = select(wfd + 1, NULL, &fds, NULL, &tv);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* n is the number of descriptors that changed status */
|
|
+ } while (n > 0);
|
|
+
|
|
+ if (n != -1) errno = error_timeout;
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl)
|
|
+{
|
|
+ int r;
|
|
+
|
|
+ /* if connection is established, keep NDELAY */
|
|
+ if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
|
|
+ r = ssl_timeoutio(SSL_accept, t, rfd, wfd, ssl, NULL, 0);
|
|
+
|
|
+ if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
|
|
+ else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
|
+
|
|
+ return r;
|
|
+}
|
|
+
|
|
+int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl)
|
|
+{
|
|
+ int r;
|
|
+
|
|
+ /* if connection is established, keep NDELAY */
|
|
+ if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
|
|
+ r = ssl_timeoutio(SSL_connect, t, rfd, wfd, ssl, NULL, 0);
|
|
+
|
|
+ if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
|
|
+ else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
|
+
|
|
+ return r;
|
|
+}
|
|
+
|
|
+int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl)
|
|
+{
|
|
+ int r=0;
|
|
+
|
|
+ SSL_renegotiate(ssl);
|
|
+
|
|
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
+ char buf[1]; /* dummy read buffer */
|
|
+ struct timeval tv;
|
|
+ fd_set fds;
|
|
+ r = ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
|
|
+ if (r <=0) return r;
|
|
+
|
|
+ tv.tv_sec = (time_t)t; tv.tv_usec = 0;
|
|
+ FD_ZERO(&fds); FD_SET(rfd, &fds);
|
|
+ if ((r = select(rfd + 1, &fds, NULL, NULL, &tv)>0) && FD_ISSET(rfd, &fds)){
|
|
+ r = SSL_read(ssl, buf, 1);
|
|
+ if (SSL_get_error(ssl, r) == SSL_ERROR_WANT_READ) r = 1; /*ignore */
|
|
+ }
|
|
+ if (r <=0) return r;
|
|
+#else
|
|
+ r = ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
|
|
+ if (r <= 0 || ssl->type == SSL_ST_CONNECT) return r;
|
|
+
|
|
+ /* this is for the server only */
|
|
+ ssl->state = SSL_ST_ACCEPT;
|
|
+#endif
|
|
+ return ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
|
|
+}
|
|
+
|
|
+int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
|
|
+{
|
|
+ if (!buf) return 0;
|
|
+ if (SSL_pending(ssl)) return SSL_read(ssl, buf, len);
|
|
+ return ssl_timeoutio(SSL_read, t, rfd, wfd, ssl, buf, len);
|
|
+}
|
|
+
|
|
+int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
|
|
+{
|
|
+ if (!buf) return 0;
|
|
+ return ssl_timeoutio(SSL_write, t, rfd, wfd, ssl, buf, len);
|
|
+}
|
|
+#endif
|
|
--- netqmail-1.06-orig/ssl_timeoutio.h 2019-04-08 15:26:13.112123436 +0000
|
|
+++ netqmail-1.06/ssl_timeoutio.h 2019-03-22 21:11:16.610440636 +0000
|
|
@@ -0,0 +1,21 @@
|
|
+#ifndef SSL_TIMEOUTIO_H
|
|
+#define SSL_TIMEOUTIO_H
|
|
+
|
|
+#include <openssl/ssl.h>
|
|
+
|
|
+/* the version is like this: 0xMNNFFPPS: major minor fix patch status */
|
|
+#if OPENSSL_VERSION_NUMBER < 0x00908000L
|
|
+# error "Need OpenSSL version at least 0.9.8"
|
|
+#endif
|
|
+
|
|
+int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl);
|
|
+int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl);
|
|
+int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl);
|
|
+
|
|
+int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
|
|
+int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
|
|
+
|
|
+int ssl_timeoutio(
|
|
+ int (*fun)(), int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
|
|
+
|
|
+#endif
|
|
--- netqmail-1.06-orig/TARGETS 1998-06-15 10:53:16.000000000 +0000
|
|
+++ netqmail-1.06/TARGETS 2015-12-01 15:54:59.033940812 +0000
|
|
@@ -168,6 +168,8 @@ control.o
|
|
constmap.o
|
|
timeoutread.o
|
|
timeoutwrite.o
|
|
+tls.o
|
|
+ssl_timeoutio.o
|
|
timeoutconn.o
|
|
tcpto.o
|
|
dns.o
|
|
@@ -320,6 +322,7 @@ binm2
|
|
binm2+df
|
|
binm3
|
|
binm3+df
|
|
+Makefile-cert
|
|
it
|
|
qmail-local.0
|
|
qmail-lspawn.0
|
|
@@ -385,3 +388,4 @@ forgeries.0
|
|
man
|
|
setup
|
|
check
|
|
+update_tmprsadh
|
|
--- netqmail-1.06-orig/Makefile-cert.mk 2019-04-08 15:26:13.112123436 +0000
|
|
+++ netqmail-1.06/Makefile-cert.mk 2015-12-01 15:54:59.033940812 +0000
|
|
@@ -0,0 +1,21 @@
|
|
+cert-req: req.pem
|
|
+cert cert-req: QMAIL/control/clientcert.pem
|
|
+ @:
|
|
+
|
|
+QMAIL/control/clientcert.pem: QMAIL/control/servercert.pem
|
|
+ ln -s $< $@
|
|
+
|
|
+QMAIL/control/servercert.pem:
|
|
+ PATH=$$PATH:/usr/local/ssl/bin \
|
|
+ openssl req -new -x509 -nodes -days 366 -out $@ -keyout $@
|
|
+ chmod 640 $@
|
|
+ chown `head -2 conf-users | tail -1`:`head -1 conf-groups` $@
|
|
+
|
|
+req.pem:
|
|
+ PATH=$$PATH:/usr/local/ssl/bin openssl req \
|
|
+ -new -nodes -out $@ -keyout QMAIL/control/servercert.pem
|
|
+ chmod 640 QMAIL/control/servercert.pem
|
|
+ chown `head -2 conf-users | tail -1`:`head -1 conf-groups` QMAIL/control/servercert.pem
|
|
+ @echo
|
|
+ @echo "Send req.pem to your CA to obtain signed_req.pem, and do:"
|
|
+ @echo "cat signed_req.pem >> QMAIL/control/servercert.pem"
|
|
--- netqmail-1.06-orig/conf-cc 1998-06-15 10:53:16.000000000 +0000
|
|
+++ netqmail-1.06/conf-cc 2019-04-08 15:25:56.312020413 +0000
|
|
@@ -1,3 +1,3 @@
|
|
-cc -O2
|
|
+cc -O2 -DTLS=20190517 -I/usr/local/ssl/include
|
|
|
|
This will be used to compile .c files.
|
|
--- netqmail-1.06-orig/Makefile 2007-11-30 20:22:54.000000000 +0000
|
|
+++ netqmail-1.06/Makefile 2015-12-01 15:54:59.033940812 +0000
|
|
@@ -808,7 +808,7 @@ dnsptr dnsip dnsmxip dnsfq hostname ipme
|
|
forward preline condredirect bouncesaying except maildirmake \
|
|
maildir2mbox maildirwatch qail elq pinq idedit install-big install \
|
|
instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
|
|
-binm3 binm3+df
|
|
+binm3 binm3+df update_tmprsadh
|
|
|
|
load: \
|
|
make-load warn-auto.sh systype
|
|
@@ -1444,6 +1444,7 @@ ndelay.a case.a sig.a open.a lock.a seek
|
|
substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib
|
|
./load qmail-remote control.o constmap.o timeoutread.o \
|
|
timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
|
|
+ tls.o ssl_timeoutio.o -L/usr/local/ssl/lib -lssl -lcrypto \
|
|
ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
|
|
lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
|
|
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
|
|
@@ -1539,6 +1540,7 @@ open.a sig.a case.a env.a stralloc.a all
|
|
fs.a auto_qmail.o socket.lib
|
|
./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
|
|
timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
|
|
+ tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \
|
|
received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
|
|
datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
|
|
alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \
|
|
@@ -1827,7 +1829,8 @@ date822fmt.h date822fmt.c dns.h dns.c tr
|
|
ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \
|
|
ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \
|
|
prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \
|
|
-maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c
|
|
+maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c \
|
|
+update_tmprsadh
|
|
shar -m `cat FILES` > shar
|
|
chmod 400 shar
|
|
|
|
@@ -2108,6 +2111,19 @@ timeoutwrite.o: \
|
|
compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h
|
|
./compile timeoutwrite.c
|
|
|
|
+qmail-smtpd: tls.o ssl_timeoutio.o ndelay.a
|
|
+qmail-remote: tls.o ssl_timeoutio.o
|
|
+qmail-smtpd.o: tls.h ssl_timeoutio.h
|
|
+qmail-remote.o: tls.h ssl_timeoutio.h
|
|
+
|
|
+tls.o: \
|
|
+compile tls.c exit.h error.h
|
|
+ ./compile tls.c
|
|
+
|
|
+ssl_timeoutio.o: \
|
|
+compile ssl_timeoutio.c ssl_timeoutio.h select.h error.h ndelay.h
|
|
+ ./compile ssl_timeoutio.c
|
|
+
|
|
token822.o: \
|
|
compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \
|
|
gen_alloc.h gen_allocdefs.h
|
|
@@ -2139,3 +2155,26 @@ compile wait_nohang.c haswaitp.h
|
|
wait_pid.o: \
|
|
compile wait_pid.c error.h haswaitp.h
|
|
./compile wait_pid.c
|
|
+
|
|
+cert cert-req: \
|
|
+Makefile-cert
|
|
+ @$(MAKE) -sf $< $@
|
|
+
|
|
+Makefile-cert: \
|
|
+conf-qmail conf-users conf-groups Makefile-cert.mk
|
|
+ @cat Makefile-cert.mk \
|
|
+ | sed s}QMAIL}"`head -1 conf-qmail`"}g \
|
|
+ > $@
|
|
+
|
|
+update_tmprsadh: \
|
|
+conf-qmail conf-users conf-groups update_tmprsadh.sh
|
|
+ @cat update_tmprsadh.sh\
|
|
+ | sed s}UGQMAILD}"`head -2 conf-users|tail -1`:`head -1 conf-groups`"}g \
|
|
+ | sed s}QMAIL}"`head -1 conf-qmail`"}g \
|
|
+ > $@
|
|
+ chmod 755 update_tmprsadh
|
|
+
|
|
+tmprsadh: \
|
|
+update_tmprsadh
|
|
+ echo "Creating new temporary RSA and DH parameters"
|
|
+ ./update_tmprsadh
|
|
--- netqmail-1.06-orig/update_tmprsadh.sh 2019-04-08 15:26:13.112123436 +0000
|
|
+++ netqmail-1.06/update_tmprsadh.sh 2015-12-08 00:32:33.936474103 +0000
|
|
@@ -0,0 +1,19 @@
|
|
+#!/bin/sh
|
|
+
|
|
+# Update temporary RSA and DH keys
|
|
+# Frederik Vermeulen 2004-05-31 GPL
|
|
+
|
|
+umask 0077 || exit 0
|
|
+
|
|
+export PATH="$PATH:/usr/local/bin/ssl:/usr/sbin"
|
|
+
|
|
+openssl genrsa -out QMAIL/control/rsa2048.new 2048 &&
|
|
+chmod 600 QMAIL/control/rsa2048.new &&
|
|
+chown UGQMAILD QMAIL/control/rsa2048.new &&
|
|
+mv -f QMAIL/control/rsa2048.new QMAIL/control/rsa2048.pem
|
|
+echo
|
|
+
|
|
+openssl dhparam -2 -out QMAIL/control/dh2048.new 2048 &&
|
|
+chmod 600 QMAIL/control/dh2048.new &&
|
|
+chown UGQMAILD QMAIL/control/dh2048.new &&
|
|
+mv -f QMAIL/control/dh2048.new QMAIL/control/dh2048.pem
|