v. 2016.05.15 auth+tls+force-tls patch for netqmail-1.06 ==================================================================== = This patch puts together * Erwin Hoffmann's qmail-authentication patch v. 0.8.3, which updates the patches provided by Krysztof Dabrowski and Bjoern Kalkbrenner. It provides cram-md5, login, plain authentication support. (http://www.fehcom.de/qmail/smtpauth.html##PATCHES) * Frederik Vermeulen's qmail-tls patch v. 20151215 implements SSL or TLS encrypted and authenticated SMTP. (http://inoa.net/qmail-tls/) * Marcel Telka's force-tls patch v. 2016-05-15 optionally gets qmail to require TLS before authentication You can avoid to force tls declaring FORCETLS=0 in your run file (http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/roberto-netqmail-1.06_force-tls/force-tls_marcel.patch) = Disclaimer This patch comes with the usual warranty: it works for me, it may not work for you, use at your own risk etc. etc. :-) = Comments, suggestions, criticisms are always welcome! The packager is Roberto Puzzanghera - roberto dot puzzanghera at sagredo dot eu http://notes.sagredo.eu/node/84 = Usage wget http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/roberto-netqmail-1.06_auth_tls_force-tls.patch-latest wget http://qmail.org/netqmail-1.06.tar.gz tar xzf netqmail-1.06.tar.gz cd netqmail-1.06 chown -R root.root . patch < ../roberto-netqmail-1.06_auth_tls_force-tls.patch-latest make make setup check = You have to export SMTPAUTH="!" in your qmail-submission/run file. Look at README.auth for further details. =================================================================== diff -ruN ../../netqmail-1.06-original/FILES.auth netqmail-1.06/FILES.auth --- ../../netqmail-1.06-original/FILES.auth 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/FILES.auth 2016-05-15 11:27:32.051944607 +0000 @@ -0,0 +1,27 @@ +The qmail-smtpd Auth patch modifies the following QMAIL 1.03 files: + += TARGETS += Makefile += qmail-smtpd.c += qmail-smtpd.8 += qmail-remote.c += qmail-remote.8 += qmail-showctl.c += qmail-control.9 + +Added files: + ++ base64.c ++ base64.h ++ case_startb.c ++ hmac_md5.h ++ hmac_md5.c ++ global.h ++ md5.h ++ md5c.c + +Informational files: + +% install_auth.sh (Installation shell script) +% LICENSE.authentication (some sort of ...) +% README.auth diff -ruN ../../netqmail-1.06-original/LICENSE.authentication netqmail-1.06/LICENSE.authentication --- ../../netqmail-1.06-original/LICENSE.authentication 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/LICENSE.authentication 2016-05-15 11:27:32.051944607 +0000 @@ -0,0 +1,43 @@ +AUTHOR +====== + +Author: + Dr. Erwin Hoffmann - FEHCom Germany +Web-Site: + http://www.fehcom.de/qmail.html +E-Mail: + feh@fehcom.de + + +LICENSE +======= + +qmail AUTHENTICATION is free software. +This includes: + You can download and use qmail AUTHENTICATION (and parts of it) as you like. + You can modify the source code without notification to or permission by the author. +Please check: + http://www.cr.yp.to/softwarelaw.html + + +DEPENDENCIES +============ + +qmail AUTHENTICATION patches (modifies) parts of the qmail-1.03 source files. +It should only be applied against the source as supplied by D.J. Bernstein. + + +FITNESS +======= + +The Author does not guarantee a specific fitness of qmail AUTHENTICATION. +If you use qmail AUTHENTICATION, it's on your own risk. + + +DISTRIBUTION +============ + +qmail AUTHENTICATION may be included in ports and packages under the following conditions: + The port/package has to show the current version number of qmail AUTHENTICATION. + All files (namely this) have to be included. + diff -ruN ../../netqmail-1.06-original/Makefile netqmail-1.06/Makefile --- ../../netqmail-1.06-original/Makefile 2007-11-30 20:22:54.000000000 +0000 +++ netqmail-1.06/Makefile 2016-05-15 11:27:32.052944574 +0000 @@ -136,6 +136,18 @@ compile auto_usera.c ./compile auto_usera.c +base64.o: \ +compile base64.c base64.h stralloc.h substdio.h str.h + ./compile base64.c + +md5c.o : \ +compile md5c.c md5.h + ./compile md5c.c + +hmac_md5.o : \ +compile hmac_md5.c hmac_md5.h global.h + ./compile hmac_md5.c + binm1: \ binm1.sh conf-qmail cat binm1.sh \ @@ -808,7 +820,7 @@ 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 @@ -1441,12 +1453,16 @@ load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \ timeoutconn.o tcpto.o now.o dns.o ip.o 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 dns.lib socket.lib +substdio.a error.a str.a fs.a auto_qmail.o \ +base64.o md5c.o hmac_md5.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` + base64.o md5c.o hmac_md5.o \ + str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` qmail-remote.0: \ qmail-remote.8 @@ -1536,12 +1552,13 @@ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o 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 socket.lib +fs.a auto_qmail.o base64.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 \ + alloc.a substdio.a error.a str.a fs.a auto_qmail.o base64.o `cat \ socket.lib` qmail-smtpd.0: \ @@ -1553,7 +1570,7 @@ substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \ error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \ substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \ -exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h +exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h base64.h ./compile qmail-smtpd.c qmail-start: \ @@ -1827,7 +1844,8 @@ 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 +2126,19 @@ 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 +2170,26 @@ 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 diff -ruN ../../netqmail-1.06-original/Makefile-cert.mk netqmail-1.06/Makefile-cert.mk --- ../../netqmail-1.06-original/Makefile-cert.mk 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/Makefile-cert.mk 2016-05-15 11:27:32.096943112 +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" diff -ruN ../../netqmail-1.06-original/README.auth netqmail-1.06/README.auth --- ../../netqmail-1.06-original/README.auth 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/README.auth 2016-05-15 11:27:32.096943112 +0000 @@ -0,0 +1,154 @@ +README qmail SMTP Authentication +================================ + +Scope: +------ + +This patch supports RFC 2554 "SMTP Service Extension for Authentication" and +RFC 4409 "Message Submission for Mail" for + +* qmail-smtpd and +* qmail-remote + +and supports commonly the AUTH methods + +- CRAM-MD5 +- LOGIN (unsecure) +- PLAIN (unsecure) + +Additionally, RFC 1870 is honoured ("SMTP Service Extension for Message Size Declaration"). +For more technical details see: http://www.fehcom.de/qmail/docu/smtpauth.html. + + +Installation: +------------- + +* Untar the source in the qmail-1.03 home direcotry. +* Run ./install_auth. +* Re-make qmail. + + +Setup for qmail-smtpd: +---------------------- + +1. Prereqs: + +In order to use SMTP Authentication you have to use a 'Pluggable Authentication Module' +PAM to be called by qmail-smtpd; typically + + /var/qmail/bin/qmail-smtpd /bin/checkpassword true 2>&1 + +Since qmail-smtpd does not run as root, checkpassword has to be made sticky. +There is no need to include additionally the hostname in the call. +In order to compute the CRAM-MD5 challenge, qmail-smtpd uses the 'tcplocalhost' information. + +2. Invocation: + +In order activate SMTP authentication, you need to provide the environment +variable 'SMTPAUTH' to qmail-smtpd. + +Possible choices: + + a) SMTPAUTH=""; qmail-smtpd supports auth of type PLAIN and/or LOGIN. + b) SMTPAUTH="+cram"; qmail-smtpd will additionally annonce CRAM-MD5, + this requires a CRAM-MD5 supporting PAM. + c) SMTPAUTH="cram"; qmail-smtpd will only annonce CRAM-MD5. + d) SMTPAUTH="!"; this instructs qmail-smtpd to require (any type) authentication for this connection. + This behavior is equivalent to the Submission feaure. + e) SMTPAUTH="!cram"; same as d) but now CRAM-MD5 is the only method instead. + + +Setup for qmail-remote: +----------------------- + +SMTP Authentication with qmail-remote is faclitated by two means: + +a) SMTP Authentication by sender/sending domain as provided in the 'Mail From:' + +The control file 'authsenders' which works similar to 'control/smtproutes' +but with additional authentication information (username + password): + + @example.com:relay.example.com|user|passwd + info@example.com:relay.example.com:26|infouser|infopasswd + :mailrelay.example.com:587|e=mc2|testpass + +Note: The choice of the AUTH method depends on the capabilities of the server. + +b) SMTP Authentication by recipient domain: + +The control file 'smtproutes' is enhanced with the authentication information: + + authdomain.com:mx.authdomain.com:125|myuserid|mypassword + :mailrelay.example.com:587|e=mc2|testpass + + +Historical Notes: +----------------- + +SMTP authentication for qmail-smtpd was initially provided by Krysztof Dabrowski (version 0.31): + + +Changes wrt. Krysztof Dabrowski's patch: + +* Avoid the 'hostname' in the call of the PAM. +* Confirm to Dan Bernstein's checkpassword interface even for CRAM-MD5. +* Doesn't close FD 2; thus not inhibiting logging to STDERR. +* Fixed bugs in base64.c. +* Modified unconditional close of FD 3 in order to sustain reading of 'control/morecpthosts.cdb'. +* Evaluation of the (informational) Mail From: < > Auth=username. +* Additional support for the advertised "Size" via 'Mail From: SIZE=123456780' (RFC 1870). +* RFC 3848 conformance for Received header in case of SMTP Auth (keyword ESMTPA). +* Added SMTPAUTH environment variable. +* The particular Submission feature has been removed; obsolete. + + +SMTP authentication for qmail-remote is taken from Bjoern Kalkbrenner. + +Changes wrt. Bjoern Kalkbrenner's patch (version 0.0.1 / 20020715): + +* Uniform, modular support for LOGIN and PLAIN. +* Added 'Mail From: < > Auth=username' information in provisionally XTEXT format. +* Added CRAM-MD5 support. +* Added authentication by recipient domain. + + +Release Notes: +-------------- + +Version: Notes: Date: +------------------------------------------------------------------- +0.5.9 qmail-smtpd AUTH (only) 25.3.2008 +0.6.9 qmail-authentication 1.2.2010 +0.7.0 Based on qmail-authentication 0.69 + including now CRAM-MD5 support + for qmail-remote 31.7.2010 +0.7.1 cosmetics for qmail-remote 5.8.2010 +0.7.2 authorization-id = authentication-id + for qmail-remote; + added SMTPAUTH environment variable + for qmail-smtpd; backport from SC 2.7 29.4.2012 +0.7.3 Fixed missing AUTH for qmai-smtpd announcement. + Improved SUBMISSION port handling. 2.5.2012 +0.7.4 Fixed missing 250 statements for AUTH. + Changed SMTPAUTH settings for cram-md5 18.5.2012 +0.7.5 Fixed bug in qmail-remote not respecting + announced AUTH types. Tx. Callum Gibson. + Added '432' server code evaluation for + AUTH password expired in qmail-remote. 23.10.2012 +0.7.6 Fixed order of SMTP commands (tx roberto). + 02.02.2013 +0.8.0 Added authentication by recipient domain + for qmail-remote. + Removed SUBMISSION port feature for + qmail-smtpd. 22.03.2013 +0.8.1 Added SMTPAUTH="!+crom" feature. 24.03.2013 +0.8.2 Bug fix: qmail-smtpd ACCEPTS auth commands + even if SMTPAUTH="-". (tx chris). 21.01.2015 +0.8.3 Fixed bug in MD5 calculation for AMD64. + Fixed 'die_nomem' bug in qmail-smtpd. 23.08.2015 + + + +Erwin Hoffmann - Hoehn 2015-08-23 (www.fehcom.de) + + diff -ruN ../../netqmail-1.06-original/TARGETS netqmail-1.06/TARGETS --- ../../netqmail-1.06-original/TARGETS 1998-06-15 10:53:16.000000000 +0000 +++ netqmail-1.06/TARGETS 2016-05-15 11:27:32.096943112 +0000 @@ -10,6 +10,7 @@ qmail.o quote.o now.o +base64.o gfrom.o myctime.o slurpclose.o @@ -168,6 +169,8 @@ constmap.o timeoutread.o timeoutwrite.o +tls.o +ssl_timeoutio.o timeoutconn.o tcpto.o dns.o @@ -182,6 +185,8 @@ qmail-remote qmail-rspawn.o tcpto_clean.o +md5c.o +hmac_md5.o qmail-rspawn direntry.h qmail-clean.o @@ -320,6 +325,7 @@ binm2+df binm3 binm3+df +Makefile-cert it qmail-local.0 qmail-lspawn.0 @@ -385,3 +391,4 @@ man setup check +update_tmprsadh diff -ruN ../../netqmail-1.06-original/base64.c netqmail-1.06/base64.c --- ../../netqmail-1.06-original/base64.c 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/base64.c 2016-05-15 11:27:32.097943078 +0000 @@ -0,0 +1,124 @@ +#include "base64.h" +#include "stralloc.h" +#include "substdio.h" +#include "str.h" + +static char *b64alpha = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +#define B64PAD '=' + +/* returns 0 ok, 1 illegal, -1 problem */ + +int b64decode(in,l,out) +const unsigned char *in; +int l; +stralloc *out; /* not null terminated */ +{ + int p = 0; + int n; + unsigned int x; + int i, j; + char *s; + unsigned char b[3]; + + if (l == 0) + { + if (!stralloc_copys(out,"")) return -1; + return 0; + } + + while(in[l-1] == B64PAD) { + p ++; + l--; + } + + n = (l + p) / 4; + i = (n * 3) - p; + if (!stralloc_ready(out,i)) return -1; + out->len = i; + s = out->s; + + for(i = 0; i < n - 1 ; i++) { + x = 0; + for(j = 0; j < 4; j++) { + if(in[j] >= 'A' && in[j] <= 'Z') + x = (x << 6) + (unsigned int)(in[j] - 'A' + 0); + else if(in[j] >= 'a' && in[j] <= 'z') + x = (x << 6) + (unsigned int)(in[j] - 'a' + 26); + else if(in[j] >= '0' && in[j] <= '9') + x = (x << 6) + (unsigned int)(in[j] - '0' + 52); + else if(in[j] == '+') + x = (x << 6) + 62; + else if(in[j] == '/') + x = (x << 6) + 63; + else if(in[j] == '=') + x = (x << 6); + } + + s[2] = (unsigned char)(x & 255); x >>= 8; + s[1] = (unsigned char)(x & 255); x >>= 8; + s[0] = (unsigned char)(x & 255); x >>= 8; + s += 3; in += 4; + } + + x = 0; + for(j = 0; j < 4; j++) { + if(in[j] >= 'A' && in[j] <= 'Z') + x = (x << 6) + (unsigned int)(in[j] - 'A' + 0); + else if(in[j] >= 'a' && in[j] <= 'z') + x = (x << 6) + (unsigned int)(in[j] - 'a' + 26); + else if(in[j] >= '0' && in[j] <= '9') + x = (x << 6) + (unsigned int)(in[j] - '0' + 52); + else if(in[j] == '+') + x = (x << 6) + 62; + else if(in[j] == '/') + x = (x << 6) + 63; + else if(in[j] == '=') + x = (x << 6); + } + + b[2] = (unsigned char)(x & 255); x >>= 8; + b[1] = (unsigned char)(x & 255); x >>= 8; + b[0] = (unsigned char)(x & 255); x >>= 8; + + for(i = 0; i < 3 - p; i++) + s[i] = b[i]; + + return 0; +} + +int b64encode(in,out) +stralloc *in; +stralloc *out; /* not null terminated */ +{ + unsigned char a, b, c; + int i; + char *s; + + if (in->len == 0) + { + if (!stralloc_copys(out,"")) return -1; + return 0; + } + + i = in->len / 3 * 4 + 4; + if (!stralloc_ready(out,i)) return -1; + s = out->s; + + for (i = 0;i < in->len;i += 3) { + a = in->s[i]; + b = i + 1 < in->len ? in->s[i + 1] : 0; + c = i + 2 < in->len ? in->s[i + 2] : 0; + + *s++ = b64alpha[a >> 2]; + *s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)]; + + if (i + 1 >= in->len) *s++ = B64PAD; + else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)]; + + if (i + 2 >= in->len) *s++ = B64PAD; + else *s++ = b64alpha[c & 63]; + } + out->len = s - out->s; + return 0; +} diff -ruN ../../netqmail-1.06-original/base64.h netqmail-1.06/base64.h --- ../../netqmail-1.06-original/base64.h 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/base64.h 2016-05-15 11:27:32.097943078 +0000 @@ -0,0 +1,7 @@ +#ifndef BASE64_H +#define BASE64_H + +extern int b64decode(); +extern int b64encode(); + +#endif diff -ruN ../../netqmail-1.06-original/case_startb.c netqmail-1.06/case_startb.c --- ../../netqmail-1.06-original/case_startb.c 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/case_startb.c 2016-05-15 11:27:32.097943078 +0000 @@ -0,0 +1,21 @@ +#include "case.h" + +int case_startb(s,len,t) +register char *s; +unsigned int len; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + for (;;) { + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (!y) return 1; + if (!len) return 0; + --len; + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + if (x != y) return 0; + } +} diff -ruN ../../netqmail-1.06-original/conf-cc netqmail-1.06/conf-cc --- ../../netqmail-1.06-original/conf-cc 1998-06-15 10:53:16.000000000 +0000 +++ netqmail-1.06/conf-cc 2016-05-15 11:27:32.097943078 +0000 @@ -1,3 +1,3 @@ -cc -O2 +cc -O2 -DTLS=20151215 -I/usr/local/ssl/include This will be used to compile .c files. diff -ruN ../../netqmail-1.06-original/dns.c netqmail-1.06/dns.c --- ../../netqmail-1.06-original/dns.c 2007-11-30 20:22:54.000000000 +0000 +++ netqmail-1.06/dns.c 2016-05-15 11:27:32.097943078 +0000 @@ -267,12 +267,11 @@ 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]) { - ix.pref = 0; 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 +290,16 @@ 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 +319,7 @@ { 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 +331,6 @@ if (!stralloc_copy(&glue,sa)) return DNS_MEM; if (!stralloc_0(&glue)) return DNS_MEM; if (glue.s[0]) { - ix.pref = 0; 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; diff -ruN ../../netqmail-1.06-original/global.h netqmail-1.06/global.h --- ../../netqmail-1.06-original/global.h 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/global.h 2016-05-15 11:27:32.097943078 +0000 @@ -0,0 +1,51 @@ +/* GLOBAL.H - RSAREF types and constants */ + +#include +#include "uint32.h" + +/* Copyright (C) RSA Laboratories, a division of RSA Data Security, + Inc., created 1991. All rights reserved. + */ + +#ifndef _GLOBAL_H_ +#define _GLOBAL_H_ 1 + +/* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. + The following makes PROTOTYPES default to 1 if it has not already been + defined as 0 with C compiler flags. + */ +#ifndef PROTOTYPES +#define PROTOTYPES 1 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +/* UINT4 defines a four byte word */ +#ifdef UINT32_H +#define UINT4 uint32 +#endif + +#ifndef NULL_PTR +#define NULL_PTR ((POINTER)0) +#endif + +#ifndef UNUSED_ARG +#define UNUSED_ARG(x) x = *(&x); +#endif + +/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. + If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif + +#endif /* end _GLOBAL_H_ */ diff -ruN ../../netqmail-1.06-original/hier.c netqmail-1.06/hier.c --- ../../netqmail-1.06-original/hier.c 1998-06-15 10:53:16.000000000 +0000 +++ netqmail-1.06/hier.c 2016-05-15 11:27:32.097943078 +0000 @@ -143,6 +143,9 @@ 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); diff -ruN ../../netqmail-1.06-original/hmac_md5.c netqmail-1.06/hmac_md5.c --- ../../netqmail-1.06-original/hmac_md5.c 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/hmac_md5.c 2016-05-15 11:27:32.098943044 +0000 @@ -0,0 +1,76 @@ +#include "global.h" +#include "md5.h" + +/* +** Function: hmac_md5 +*/ + +void hmac_md5(text, text_len, key, key_len, digest) +unsigned char* text; /* pointer to data stream */ +int text_len; /* length of data stream */ +unsigned char* key; /* pointer to authentication key */ +int key_len; /* length of authentication key */ +unsigned char *digest; /* caller digest to be filled in */ + +{ + MD5_CTX context; + unsigned char k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + unsigned char k_opad[65]; /* outer padding - + * key XORd with opad + */ + unsigned char tk[16]; + int i; + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + + MD5_CTX tctx; + + MD5Init(&tctx); + MD5Update(&tctx, key, key_len); + MD5Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + bzero( k_ipad, sizeof k_ipad); + bzero( k_opad, sizeof k_opad); + bcopy( key, k_ipad, key_len); + bcopy( key, k_opad, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + /* + * perform inner MD5 + */ + MD5Init(&context); /* init context for 1st pass */ + MD5Update(&context, k_ipad, 64); /* start with inner pad */ + MD5Update(&context, text, text_len); /* then text of datagram */ + MD5Final(digest, &context); /* finish up 1st pass */ + /* + * perform outer MD5 + */ + MD5Init(&context); /* init context for 2nd + * pass */ + MD5Update(&context, k_opad, 64); /* start with outer pad */ + MD5Update(&context, digest, 16); /* then results of 1st + * hash */ + MD5Final(digest, &context); /* finish up 2nd pass */ +} diff -ruN ../../netqmail-1.06-original/hmac_md5.h netqmail-1.06/hmac_md5.h --- ../../netqmail-1.06-original/hmac_md5.h 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/hmac_md5.h 2016-05-15 11:27:32.098943044 +0000 @@ -0,0 +1,11 @@ + +/* prototypes */ + +void hmac_md5( unsigned char* text, int text_len, unsigned char* key, int key_len, unsigned char* digest); + +/* pointer to data stream */ +/* length of data stream */ +/* pointer to authentication key */ +/* length of authentication key */ +/* caller digest to be filled in */ + diff -ruN ../../netqmail-1.06-original/ipalloc.h netqmail-1.06/ipalloc.h --- ../../netqmail-1.06-original/ipalloc.h 1998-06-15 10:53:16.000000000 +0000 +++ netqmail-1.06/ipalloc.h 2016-05-15 11:27:32.098943044 +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" diff -ruN ../../netqmail-1.06-original/md5.h netqmail-1.06/md5.h --- ../../netqmail-1.06-original/md5.h 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/md5.h 2016-05-15 11:27:32.098943044 +0000 @@ -0,0 +1,49 @@ +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + +#ifndef _MD5_H_ +#define _MD5_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init PROTO_LIST ((MD5_CTX *)); +void MD5Update PROTO_LIST + ((MD5_CTX *, unsigned char *, unsigned int)); +void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); + +#ifdef __cplusplus +} +#endif + +#endif diff -ruN ../../netqmail-1.06-original/md5c.c netqmail-1.06/md5c.c --- ../../netqmail-1.06-original/md5c.c 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/md5c.c 2016-05-15 11:27:32.098943044 +0000 @@ -0,0 +1,334 @@ +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + +#include "global.h" +#include "md5.h" + +/* Constants for MD5Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); +static void Encode PROTO_LIST + ((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST + ((UINT4 *, unsigned char *, unsigned int)); +static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (context) +MD5_CTX *context; /* context */ +{ + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update (context, input, inputLen) +MD5_CTX *context; /* context */ +unsigned char *input; /* input block */ +unsigned int inputLen; /* length of input block */ +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. + */ + if (inputLen >= partLen) { + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final (digest, context) +unsigned char digest[16]; /* message digest */ +MD5_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +UINT4 state[4]; +unsigned char block[64]; +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (output, input, len) +unsigned char *output; +UINT4 *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (output, input, len) +UINT4 *output; +unsigned char *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ +static void MD5_memcpy (output, input, len) +POINTER output; +POINTER input; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset (output, value, len) +POINTER output; +int value; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} diff -ruN ../../netqmail-1.06-original/qmail-control.9 netqmail-1.06/qmail-control.9 --- ../../netqmail-1.06-original/qmail-control.9 1998-06-15 10:53:16.000000000 +0000 +++ netqmail-1.06/qmail-control.9 2016-05-15 11:27:32.098943044 +0000 @@ -40,14 +40,18 @@ .ta 5c 10c control default used by +.I authsender \fR(none) \fRqmail-remote .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 +65,17 @@ .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 diff -ruN ../../netqmail-1.06-original/qmail-remote.8 netqmail-1.06/qmail-remote.8 --- ../../netqmail-1.06-original/qmail-remote.8 1998-06-15 10:53:16.000000000 +0000 +++ netqmail-1.06/qmail-remote.8 2016-05-15 11:27:32.099943010 +0000 @@ -53,6 +53,7 @@ and does not follow the .B getopt standard. + .SH TRANSPARENCY End-of-file in SMTP is encoded as dot CR LF. A dot at the beginning of a line is encoded as dot dot. @@ -100,6 +101,73 @@ After this letter comes a human-readable description of what happened. +.B qmail-remote +may use SMTP Authenticaton of type CRAM-MD4, PLAIN, or LOGIN +(in this order) to connect to remote hosts. +The following reports are provided: +.TP 5 +K +no supported AUTH method found, continuing without authentication. +.TP 5 +Z +Connected to +.I host +but authentication was rejected (AUTH PLAIN). +.TP 5 +Z +Connected to +.I host +but unable to base64encode (plain). +.TP 5 +Z +Connected to +.I host +but authentication was rejected (plain)." +.TP 5 +Z +Connected to +.I host +but authentication was rejected (AUTH LOGIN). +.TP 5 +Z +Connected to +.I host +but unable to base64encode user. +.TP 5 +Z +Connected to +.I host +but authentication was rejected (username). +.TP 5 +Z +Connected to +.I host +but unable to base64encode pass. +.TP 5 +Z +Connected to +.I host +but authentication was rejected (AUTH CRAM-MD5). +Z +Connected to +.I host +but unable to base64decode challenge. +.TP 5 +Z +Connected to +.I host +but unable to base64encode username+digest. +.TP 5 +Z +Connected to +.I host +but password expired. +.TP 5 +Z +Connected to +.I host +but authentication was rejected (username+digest). +.PP The recipient reports will always be printed in the same order as .BR qmail-remote 's .I recip @@ -114,6 +182,55 @@ always exits zero. .SH "CONTROL FILES" .TP 5 +.I authsenders +Authenticated sender. +For each +.I sender +included in +.IR authsenders : +.I sender\fB:\fIrelay\fB:\fIport\fB|\fIuser\fB|\fIpassword +.B qmail-remote +will try SMTP Authentication +of type CRAM-MD5, LOGIN, or PLAIN +with the provided user name +.I user +and password +.I password +(the authentication information) +and eventually relay the +mail through +.I relay +on port +.IR port . +The use of +.I relay +and +.I port +follows the same rules as for +.IR smtproutes +Note: In case +.I sender +is empty, +.B qmail-remote +will try to deliver each outgoing mail +SMTP authenticated. If the authentication +information is missing, the mail is +delivered none-authenticated. +.I authsenders +can be constructed as follows: + +.EX + @example.com|generic|passwd + .subdomain.example.com|other|otherpw + mail@example.com|test|testpass + info@example.com:smtp.example.com:26|other|otherpw + :mailrelay.example.com:587|e=mc2|testpass +.EE +.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,12 +240,24 @@ otherwise .B qmail-remote refuses to run. + +.TP 5 +.I notlshosts/ +.B qmail-remote +will not try TLS on servers for which this file exists +.RB ( +is the fully-qualified domain name of the server). +.IR (tlshosts/.pem +takes precedence over this file however). + .TP 5 .I smtproutes Artificial SMTP routes. Each route has the form .IR domain\fB:\fIrelay , -without any extra spaces. +or +.IR domain\fB:\fIrelay\fB|\fIuser\fB|\fIpassword +in case of authenticated routes without any extra spaces. If .I domain matches @@ -149,6 +278,7 @@ .EX inside.af.mil:firewall.af.mil:26 + :submission.myrelay.com:587|myuserid|mypasswd .EE .I relay @@ -156,6 +286,8 @@ 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: @@ -177,11 +309,15 @@ The .B qmail system does not protect you if you create an artificial -mail loop between machines. +mail loop between machines. However, you are always safe using .I smtproutes if you do not accept mail from the network. +Note: +.I authsender +routes have precedence over +.IR smtproutes . .TP 5 .I timeoutconnect Number of seconds @@ -195,6 +331,33 @@ .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/.pem +.B qmail-remote +requires TLS authentication from servers for which this file exists +.RB ( +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/.pem +exists. + .SH "SEE ALSO" addresses(5), envelopes(5), diff -ruN ../../netqmail-1.06-original/qmail-remote.c netqmail-1.06/qmail-remote.c --- ../../netqmail-1.06-original/qmail-remote.c 1998-06-15 10:53:16.000000000 +0000 +++ netqmail-1.06/qmail-remote.c 2016-05-15 11:27:32.099943010 +0000 @@ -28,6 +28,7 @@ #include "timeoutconn.h" #include "timeoutread.h" #include "timeoutwrite.h" +#include "base64.h" #define HUGESMTPTEXT 5000 @@ -44,10 +45,31 @@ stralloc host = {0}; stralloc sender = {0}; +stralloc authsenders = {0}; +struct constmap mapauthsenders; +stralloc user = {0}; +stralloc pass = {0}; +stralloc auth = {0}; +stralloc plain = {0}; +stralloc chal = {0}; +stralloc slop = {0}; +char *authsender; + saa reciplist = {0}; struct ip_address partner; +#ifdef TLS +# include +# include "tls.h" +# include "ssl_timeoutio.h" +# include +# 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); } @@ -86,6 +108,12 @@ it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n"); zerodie(); } +void err_authprot() { + out("Kno supported AUTH method found, continuing without authentication.\n"); + zero(); + substdio_flush(subfdoutsmall); +} + void outhost() { char x[IPFMT]; @@ -99,6 +127,9 @@ outhost(); out(" but connection died. "); if (flagcritical) out("Possible duplicate! "); +#ifdef TLS + if (ssl_err_str) { out(ssl_err_str); out(" "); } +#endif out("(#4.4.2)\n"); zerodie(); } @@ -110,6 +141,12 @@ 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 +154,12 @@ 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; @@ -163,6 +206,65 @@ 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) + { + 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 (!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; } + } + + return 250; +} +#endif + void outsmtptext() { int i; @@ -179,6 +281,11 @@ char *prepend; char *append; { +#ifdef TLS + /* shouldn't talk to the client unless in an appropriate state */ + int state = ssl ? ssl->state : SSL_ST_BEFORE; + if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE)) +#endif substdio_putsflush(&smtpto,"QUIT\r\n"); /* waiting for remote side is just too ridiculous */ out(prepend); @@ -186,6 +293,30 @@ 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(); } @@ -214,30 +345,425 @@ substdio_flush(&smtpto); } -stralloc recip = {0}; +#ifdef TLS +char *partner_fqdn = 0; -void smtp() +# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "") +void tls_quit(const char *s1, const char *s2) +{ + out(s1); if (s2) { out(": "); out(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() { - unsigned long code; - int flagbother; 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 (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); - - 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"); - + 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(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(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 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)) 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_get_entry(subj, i)->value; + 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; + } + } + + X509_free(peercert); + } + + if (smtps) if (smtpcode() != 220) + quit("ZTLS Connected to "," but greeting failed"); + + return 1; +} +#endif + +stralloc recip = {0}; + +void mailfrom() +{ substdio_puts(&smtpto,"MAIL FROM:<"); substdio_put(&smtpto,sender.s,sender.len); substdio_puts(&smtpto,">\r\n"); substdio_flush(&smtpto); +} + +stralloc xuser = {0}; + +int xtext(sa,s,len) +stralloc *sa; +char *s; +int len; +{ + int i; + + if(!stralloc_copys(sa,"")) temp_nomem(); + + for (i = 0; i < len; i++) { + if (s[i] == '=') { + if (!stralloc_cats(sa,"+3D")) temp_nomem(); + } else if (s[i] == '+') { + if (!stralloc_cats(sa,"+2B")) temp_nomem(); + } else if ((int) s[i] < 33 || (int) s[i] > 126) { + if (!stralloc_cats(sa,"+3F")) temp_nomem(); /* ok. not correct */ + } else if (!stralloc_catb(sa,s+i,1)) { + temp_nomem(); + } + } + + return sa->len; +} + +void mailfrom_xtext() +{ + if (!xtext(&xuser,user.s,user.len)) temp_nomem(); + substdio_puts(&smtpto,"MAIL FROM:<"); + substdio_put(&smtpto,sender.s,sender.len); + substdio_puts(&smtpto,"> AUTH="); + substdio_put(&smtpto,xuser.s,xuser.len); + substdio_puts(&smtpto,"\r\n"); + substdio_flush(&smtpto); +} + +int mailfrom_plain() +{ + substdio_puts(&smtpto,"AUTH PLAIN\r\n"); + substdio_flush(&smtpto); + if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH PLAIN)."); return -1; } + + if (!stralloc_cat(&plain,&user)) temp_nomem(); /* */ + if (!stralloc_0(&plain)) temp_nomem(); + if (!stralloc_cat(&plain,&user)) temp_nomem(); /* */ + if (!stralloc_0(&plain)) temp_nomem(); + if (!stralloc_cat(&plain,&pass)) temp_nomem(); /* password */ + if (b64encode(&plain,&auth)) quit("ZConnected to "," but unable to base64encode (plain)."); + substdio_put(&smtpto,auth.s,auth.len); + substdio_puts(&smtpto,"\r\n"); + substdio_flush(&smtpto); + if (smtpcode() == 235) { mailfrom_xtext(); return 0; } + else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; } + else { quit("ZConnected to "," but authentication was rejected (plain)."); return 1; } + + return 0; +} + +int mailfrom_login() +{ + substdio_puts(&smtpto,"AUTH LOGIN\r\n"); + substdio_flush(&smtpto); + if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH LOGIN)."); return -1; } + + if (!stralloc_copys(&auth,"")) temp_nomem(); + if (b64encode(&user,&auth)) quit("ZConnected to "," but unable to base64encode user."); + substdio_put(&smtpto,auth.s,auth.len); + substdio_puts(&smtpto,"\r\n"); + substdio_flush(&smtpto); + if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (username)."); + + if (!stralloc_copys(&auth,"")) temp_nomem(); + if (b64encode(&pass,&auth)) quit("ZConnected to "," but unable to base64encode pass."); + substdio_put(&smtpto,auth.s,auth.len); + substdio_puts(&smtpto,"\r\n"); + substdio_flush(&smtpto); + if (smtpcode() == 235) { mailfrom_xtext(); return 0; } + else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; } + else { quit("ZConnected to "," but authentication was rejected (password)."); return 1; } +} + +int mailfrom_cram() +{ + int j; + unsigned char h; + unsigned char digest[16]; + unsigned char digascii[33]; + static char hextab[]="0123456789abcdef"; + + substdio_puts(&smtpto,"AUTH CRAM-MD5\r\n"); + substdio_flush(&smtpto); + if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH CRAM-MD5)."); return -1; } + + if (str_chr(smtptext.s+4,' ')) { /* Challenge */ + if(!stralloc_copys(&slop,"")) temp_nomem(); + if (!stralloc_copyb(&slop,smtptext.s+4,smtptext.len-5)) temp_nomem(); + if (b64decode(slop.s,slop.len,&chal)) quit("ZConnected to "," but unable to base64decode challenge."); + } + + hmac_md5(chal.s,chal.len,pass.s,pass.len,digest); + + for (j = 0;j < 16;j++) /* HEX => ASCII */ + { + digascii[2*j] = hextab[digest[j] >> 4]; + digascii[2*j+1] = hextab[digest[j] & 0xf]; + } + digascii[32]=0; + + slop.len = 0; + if (!stralloc_copys(&slop,"")) temp_nomem(); + if (!stralloc_cat(&slop,&user)) temp_nomem(); /* user-id */ + if (!stralloc_cats(&slop," ")) temp_nomem(); + if (!stralloc_catb(&slop,digascii,32)) temp_nomem(); /* digest */ + + if (!stralloc_copys(&auth,"")) temp_nomem(); + if (b64encode(&slop,&auth)) quit("ZConnected to "," but unable to base64encode username+digest."); + substdio_put(&smtpto,auth.s,auth.len); + substdio_puts(&smtpto,"\r\n"); + substdio_flush(&smtpto); + if (smtpcode() == 235) { mailfrom_xtext(); return 0; } + else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; } + else { quit("ZConnected to "," but authentication was rejected (username+digest)."); return 1; } +} + +void smtp_auth() +{ + int i, j; + + for (i = 0; i + 8 < smtptext.len; i += str_chr(smtptext.s+i,'\n')+1) + if (!str_diffn(smtptext.s+i+4,"AUTH",4)) { + if (j = str_chr(smtptext.s+i+8,'C') > 0) + if (case_starts(smtptext.s+i+8+j,"CRAM")) + if (mailfrom_cram() >= 0) return; + + if (j = str_chr(smtptext.s+i+8,'P') > 0) + if (case_starts(smtptext.s+i+8+j,"PLAIN")) + if (mailfrom_plain() >= 0) return; + + if (j = str_chr(smtptext.s+i+8,'L') > 0) + if (case_starts(smtptext.s+i+8+j,"LOGIN")) + if (mailfrom_login() >= 0) return; + + err_authprot(); + mailfrom(); + } +} + +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 + + code = smtpcode(); + if (code >= 500) quit("DConnected to "," but greeting failed"); + if (code != 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 */ + + /* and if EHLO failed, use HELO */ + } else { +#endif + + if (smtpcode() != 250) { + substdio_puts(&smtpto,"HELO "); + substdio_put(&smtpto,helohost.s,helohost.len); + substdio_puts(&smtpto,"\r\n"); + substdio_flush(&smtpto); + code = smtpcode(); + if (code >= 500) quit("DConnected to "," but my name was rejected"); + if (code != 250) quit("ZConnected to "," but my name was rejected"); + } + +#ifdef EHLO + } +#endif + + if (user.len && pass.len) + smtp_auth(); + else + mailfrom(); + code = smtpcode(); if (code >= 500) quit("DConnected to "," but sender was rejected"); if (code >= 400) quit("ZConnected to "," but sender was rejected"); - + flagbother = 0; for (i = 0;i < reciplist.len;++i) { substdio_puts(&smtpto,"RCPT TO:<"); @@ -324,48 +850,102 @@ case 1: if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break; } + + switch(control_readfile(&authsenders,"control/authsenders",0)) { + case -1: + temp_control(); + case 0: + if (!constmap_init(&mapauthsenders,"",0,1)) temp_nomem(); break; + case 1: + if (!constmap_init(&mapauthsenders,authsenders.s,authsenders.len,1)) temp_nomem(); break; + } } -void main(argc,argv) +int main(argc,argv) int argc; char **argv; { static ipalloc ip = {0}; - int i; + int i, j; unsigned long random; char **recips; unsigned long prefme; int flagallaliases; int flagalias; char *relayhost; - + sig_pipeignore(); if (argc < 4) perm_usage(); if (chdir(auto_qmail) == -1) temp_chdir(); getcontrols(); - if (!stralloc_copys(&host,argv[1])) temp_nomem(); - + + authsender = 0; relayhost = 0; - for (i = 0;i <= host.len;++i) - if ((i == 0) || (i == host.len) || (host.s[i] == '.')) - if (relayhost = constmap(&maproutes,host.s + i,host.len - i)) + + addrmangle(&sender,argv[2],&flagalias,0); + + for (i = 0;i <= sender.len;++i) + if ((i == 0) || (i == sender.len) || (sender.s[i] == '.') || (sender.s[i] == '@')) + if (authsender = constmap(&mapauthsenders,sender.s + i,sender.len - i)) break; - if (relayhost && !*relayhost) relayhost = 0; - - if (relayhost) { - i = str_chr(relayhost,':'); - if (relayhost[i]) { - scan_ulong(relayhost + i + 1,&port); - relayhost[i] = 0; + + if (authsender && !*authsender) authsender = 0; + + if (authsender) { + i = str_chr(authsender,'|'); + if (authsender[i]) { + j = str_chr(authsender + i + 1,'|'); + if (authsender[j]) { + authsender[i] = 0; + authsender[i + j + 1] = 0; + if (!stralloc_copys(&user,"")) temp_nomem(); + if (!stralloc_copys(&user,authsender + i + 1)) temp_nomem(); + if (!stralloc_copys(&pass,"")) temp_nomem(); + if (!stralloc_copys(&pass,authsender + i + j + 2)) temp_nomem(); + } + } + i = str_chr(authsender,':'); + if (authsender[i]) { + scan_ulong(authsender + i + 1,&port); + authsender[i] = 0; } - if (!stralloc_copys(&host,relayhost)) temp_nomem(); - } + if (!stralloc_copys(&relayhost,authsender)) temp_nomem(); + if (!stralloc_copys(&host,authsender)) temp_nomem(); + + } + else { /* default smtproutes -- authenticated */ + for (i = 0;i <= host.len;++i) + if ((i == 0) || (i == host.len) || (host.s[i] == '.')) + if (relayhost = constmap(&maproutes,host.s + i,host.len - i)) + break; + + if (relayhost && !*relayhost) relayhost = 0; + + if (relayhost) { + i = str_chr(relayhost,'|'); + if (relayhost[i]) { + j = str_chr(relayhost + i + 1,'|'); + if (relayhost[j]) { + relayhost[i] = 0; + relayhost[i + j + 1] = 0; + if (!stralloc_copys(&user,"")) temp_nomem(); + if (!stralloc_copys(&user,relayhost + i + 1)) temp_nomem(); + if (!stralloc_copys(&pass,"")) temp_nomem(); + if (!stralloc_copys(&pass,relayhost + i + j + 2)) temp_nomem(); + } + } + i = str_chr(relayhost,':'); + if (relayhost[i]) { + scan_ulong(relayhost + i + 1,&port); + relayhost[i] = 0; + } + if (!stralloc_copys(&host,relayhost)) temp_nomem(); + } + } - addrmangle(&sender,argv[2],&flagalias,0); - if (!saa_readyplus(&reciplist,0)) temp_nomem(); if (ipme_init() != 1) temp_oserr(); @@ -417,6 +997,9 @@ 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); diff -ruN ../../netqmail-1.06-original/qmail-showctl.c netqmail-1.06/qmail-showctl.c --- ../../netqmail-1.06-original/qmail-showctl.c 1998-06-15 10:53:16.000000000 +0000 +++ netqmail-1.06/qmail-showctl.c 2016-05-15 11:27:32.099943010 +0000 @@ -214,6 +214,7 @@ _exit(111); } + do_lst("authsenders","No authenticated SMTP sender.","Authenicated SMTP sender: ",""); do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM."); do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is "); do_str("bouncehost",1,"bouncehost","Bounce host name is "); @@ -265,8 +266,7 @@ while (d = readdir(dir)) { if (str_equal(d->d_name,".")) continue; if (str_equal(d->d_name,"..")) continue; - if (str_equal(d->d_name,"bouncefrom")) continue; - if (str_equal(d->d_name,"bouncehost")) continue; + if (str_equal(d->d_name,"authsenders")) continue; if (str_equal(d->d_name,"badmailfrom")) continue; if (str_equal(d->d_name,"bouncefrom")) continue; if (str_equal(d->d_name,"bouncehost")) continue; diff -ruN ../../netqmail-1.06-original/qmail-smtpd.8 netqmail-1.06/qmail-smtpd.8 --- ../../netqmail-1.06-original/qmail-smtpd.8 1998-06-15 10:53:16.000000000 +0000 +++ netqmail-1.06/qmail-smtpd.8 2016-05-15 11:27:32.100942976 +0000 @@ -14,6 +14,15 @@ see .BR tcp-environ(5) . +If the environment variable +.B SMTPS +is non-empty, +.B qmail-smtpd +starts a TLS session (to support the deprecated SMTPS protocol, +normally on port 465). Otherwise, +.B qmail-smtpd +offers the STARTTLS extension to ESMTP. + .B qmail-smtpd is responsible for counting hops. It rejects any message with 100 or more @@ -23,7 +32,30 @@ header fields. .B qmail-smtpd -supports ESMTP, including the 8BITMIME and PIPELINING options. +supports ESMTP, including the 8BITMIME, DATA, PIPELINING, SIZE, and AUTH options. +.B qmail-smtpd +includes a \'MAIL FROM:\' parameter parser and obeys \'Auth\' and \'Size\' advertisements. +.B qmail-smtpd +can accept LOGIN, PLAIN, and CRAM-MD5 AUTH types. It invokes +.IR checkprogram , +which reads on file descriptor 3 the username, a 0 byte, the password +or CRAM-MD5 digest/response derived from the SMTP client, +another 0 byte, a CRAM-MD5 challenge (if applicable to the AUTH type), +and a final 0 byte. +.I checkprogram +invokes +.I subprogram +upon successful authentication, which should in turn return 0 to +.BR qmail-smtpd , +effectively setting the environment variables $RELAYCLIENT and $TCPREMOTEINFO +(any supplied value replaced with the authenticated username). +.B qmail-smtpd +will reject the authentication attempt if it receives a nonzero return +value from +.I checkprogram +or +.IR subprogram . + .SH TRANSPARENCY .B qmail-smtpd converts the SMTP newline convention into the UNIX newline convention @@ -49,6 +81,19 @@ .BR @\fIhost , meaning every address at .IR host . + +.TP 5 +.I clientca.pem +A list of Certifying Authority (CA) certificates that are used to verify +the client-presented certificates during a TLS-encrypted session. + +.TP 5 +.I clientcrl.pem +A list of Certificate Revocation Lists (CRLs). If present it +should contain the CRLs of the CAs in +.I clientca.pem +and client certs will be checked for revocation. + .TP 5 .I databytes Maximum number of bytes allowed in a message, @@ -76,6 +121,18 @@ .B DATABYTES is set, it overrides .IR databytes . + +.TP 5 +.I dh2048.pem +If these 2048 bit DH parameters are provided, +.B qmail-smtpd +will use them for TLS sessions instead of generating one on-the-fly +(which is very timeconsuming). +.TP 5 +.I dh2048.pem +2048 bit counterpart for +.B dh2048.pem. + .TP 5 .I localiphost Replacement host name for local IP addresses. @@ -151,6 +208,19 @@ Envelope recipient addresses without @ signs are always allowed through. + +.TP 5 +.I rsa512.pem +If this 512 bit RSA key is provided, +.B qmail-smtpd +will use it for TLS sessions instead of generating one on-the-fly. + +.TP 5 +.I servercert.pem +SSL certificate to be presented to clients in TLS-encrypted sessions. +Should contain both the certificate and the private key. Certifying Authority +(CA) and intermediate certificates can be added at the end of the file. + .TP 5 .I smtpgreeting SMTP greeting message. @@ -169,6 +239,84 @@ .B qmail-smtpd will wait for each new buffer of data from the remote SMTP client. Default: 1200. + +.SH "ENVIRONMENT VARIABLES READ" +Environment variables may be defined globally in the +.B qmail-smtpd +startup script and/or individually as part of the +.B tcpserver's +cdb database. +The environment variables may be quoted ("variable", or 'variable') and +in case of global use, have to be exported. +.B qmail-smtpd +supports the following legacy environment variables, typically +provided by +.B tcpserver +or +.B sslserver +or +.BR tcp-env : +.IR TCPREMOTEIP , +.IR TCPREMOTEHOST +.IR TCPREMOTEINFO +and +.IR TCPLOCALPORT +as well as +.IR RELAYCLIENT . + +.B qmail-smtpd +may use the following environment variables for SMTP authentication: +.TP 5 +.IR SMTPAUTH +is used to enable SMTP Authentication for the AUTH types +LOGIN and PLAIN. +In case +.TP 5 +.IR SMTPAUTH='+cram' +is defined, +.B qmail-smtpd +honors LOGIN, PLAIN, and additionally CRAM-MD5 authentication. +Simply +.TP 5 +.IR SMTPAUTH='cram' +restricts authentication just to CRAM-MD5. +If however +.TP 5 +.IR SMTPAUTH='!' +starts with an exclamation mark, AUTH is required. +You can enforce 'Submission' using this option +and binding +.B qmail-smtpd +to the SUBMISSION port \'587'\. +In particular, +.TP 5 +.IR SMTPAUTH='!cram' +may be useful. +In opposite, if +.TP 5 +.IR SMTPAUTH='-' +starts with a dash, AUTH is disabled for particular +connections. + +Note: The use of 'cram' requires a CRAM-MD5 enabled PAM. + +.TP 5 +.I tlsclients +A list of email addresses. When relay rules would reject an incoming message, +.B qmail-smtpd +can allow it if the client presents a certificate that can be verified against +the CA list in +.I clientca.pem +and the certificate email address is in +.IR tlsclients . + +.TP 5 +.I tlsserverciphers +A set of OpenSSL cipher strings. Multiple ciphers contained in a +string should be separated by a colon. If the environment variable +.B TLSCIPHERS +is set to such a string, it takes precedence. + .SH "SEE ALSO" tcp-env(1), tcp-environ(5), diff -ruN ../../netqmail-1.06-original/qmail-smtpd.c netqmail-1.06/qmail-smtpd.c --- ../../netqmail-1.06-original/qmail-smtpd.c 2007-11-30 20:22:54.000000000 +0000 +++ netqmail-1.06/qmail-smtpd.c 2016-05-15 11:37:58.817078763 +0000 @@ -23,14 +23,36 @@ #include "timeoutread.h" #include "timeoutwrite.h" #include "commands.h" +#include "wait.h" + +#define AUTHSLEEP 5 #define MAXHOPS 100 unsigned int databytes = 0; int timeout = 1200; +const char *protocol = "SMTP"; + +#ifdef TLS +#include +#include "tls.h" +#include "ssl_timeoutio.h" + +void tls_init(); +int tls_verify(); +void tls_nogateway(); +int ssl_rfd = -1, ssl_wfd = -1; /* SSL_get_Xfd() are broken */ +int forcetls = 1; +#endif + int safewrite(fd,buf,len) int fd; char *buf; int len; { int r; +#ifdef TLS + if (ssl && fd == ssl_wfd) + r = ssl_timeoutwrite(timeout, ssl_rfd, ssl_wfd, ssl, buf, len); + else +#endif r = timeoutwrite(timeout,fd,buf,len); if (r <= 0) _exit(1); return r; @@ -49,8 +71,18 @@ void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); } void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); } +void err_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); } void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); } +#ifndef TLS void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); } +#else +void err_nogateway() +{ + out("553 sorry, that domain isn't in my list of allowed rcpthosts"); + tls_nogateway(); + out(" (#5.7.1)\r\n"); +} +#endif void err_unimpl(arg) char *arg; { out("502 unimplemented (#5.5.1)\r\n"); } void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); } void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); } @@ -59,6 +91,17 @@ void err_vrfy(arg) char *arg; { out("252 send some mail, i'll try my best\r\n"); } void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); } +int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; } +int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; } +int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; } +int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; } +void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); } +void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); } +int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; } +int err_authabrt() { out("501 auth exchange canceled (#5.0.0)\r\n"); return -1; } +int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; } +void err_authfail() { out("535 authentication failed (#5.7.1)\r\n"); } +void err_submission() { out("530 Authorization required (#5.7.1) \r\n"); } stralloc greeting = {0}; @@ -76,11 +119,14 @@ smtp_greet("221 "); out("\r\n"); flush(); _exit(0); } +/* char *protocol; */ char *remoteip; char *remotehost; char *remoteinfo; char *local; +char *localport; char *relayclient; +char *auth; stralloc helohost = {0}; char *fakehelo; /* pointer into helohost, or 0 */ @@ -91,6 +137,7 @@ fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0; } +int smtpauth = 0; int liphostok = 0; stralloc liphost = {0}; int bmfok = 0; @@ -109,7 +156,6 @@ if (liphostok == -1) die_control(); if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control(); if (timeout <= 0) timeout = 1; - if (rcpthosts_init() == -1) die_control(); bmfok = control_readfile(&bmf,"control/badmailfrom",0); @@ -122,19 +168,38 @@ if (x) { scan_ulong(x,&u); databytes = u; } if (!(databytes + 1)) --databytes; + protocol = "SMTP"; remoteip = env_get("TCPREMOTEIP"); if (!remoteip) remoteip = "unknown"; local = env_get("TCPLOCALHOST"); if (!local) local = env_get("TCPLOCALIP"); if (!local) local = "unknown"; + localport = env_get("TCPLOCALPORT"); + if (!localport) localport = "0"; remotehost = env_get("TCPREMOTEHOST"); if (!remotehost) remotehost = "unknown"; remoteinfo = env_get("TCPREMOTEINFO"); relayclient = env_get("RELAYCLIENT"); + auth = env_get("SMTPAUTH"); + if (auth) { + smtpauth = 1; + case_lowers(auth); + if (!case_diffs(auth,"-")) smtpauth = 0; + if (!case_diffs(auth,"!")) smtpauth = 11; + if (case_starts(auth,"cram")) smtpauth = 2; + if (case_starts(auth,"+cram")) smtpauth = 3; + if (case_starts(auth,"!cram")) smtpauth = 12; + if (case_starts(auth,"!+cram")) smtpauth = 13; + } +#ifdef TLS + x = env_get("FORCETLS"); + if (x && !str_diff(x, "0")) forcetls = 0; + if (env_get("SMTPS")) { smtps = 1; tls_init(); } + else +#endif dohelo(remotehost); } - stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */ int addrparse(arg) @@ -213,33 +278,124 @@ int r; r = rcpthosts(addr.s,str_len(addr.s)); if (r == -1) die_control(); +#ifdef TLS + if (r == 0) if (tls_verify()) r = -2; +#endif return r; } - +char *auth; +int seenauth = 0; int seenmail = 0; int flagbarf; /* defined if seenmail */ +int flagsize; stralloc mailfrom = {0}; stralloc rcptto = {0}; +stralloc fuser = {0}; +stralloc mfparms = {0}; + +int mailfrom_size(arg) char *arg; +{ + long r; + unsigned long sizebytes = 0; + + scan_ulong(arg,&r); + sizebytes = r; + if (databytes) if (sizebytes > databytes) return 1; + return 0; +} + +void mailfrom_auth(arg,len) +char *arg; +int len; +{ + if (!stralloc_copys(&fuser,"")) die_nomem(); + if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); } + else + while (len) { + if (*arg == '+') { + if (case_starts(arg,"+3D")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"=")) die_nomem(); } + if (case_starts(arg,"+2B")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"+")) die_nomem(); } + } + else + if (!stralloc_catb(&fuser,arg,1)) die_nomem(); + arg++; len--; + } + if(!stralloc_0(&fuser)) die_nomem(); + if (!remoteinfo) { + remoteinfo = fuser.s; + if (!env_unset("TCPREMOTEINFO")) die_read(); + if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem(); + } +} + +void mailfrom_parms(arg) char *arg; +{ + int i; + int len; + + len = str_len(arg); + if (!stralloc_copys(&mfparms,"")) die_nomem(); + i = byte_chr(arg,len,'>'); + if (i > 4 && i < len) { + while (len) { + arg++; len--; + if (*arg == ' ' || *arg == '\0' ) { + if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; } + if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5); + if (!stralloc_copys(&mfparms,"")) die_nomem(); + } + else + if (!stralloc_catb(&mfparms,arg,1)) die_nomem(); + } + } +} void smtp_helo(arg) char *arg; { smtp_greet("250 "); out("\r\n"); seenmail = 0; dohelo(arg); } +/* ESMTP extensions are published here */ void smtp_ehlo(arg) char *arg; { - smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); + char size[FMT_ULONG]; +#ifdef TLS + struct stat st; +#endif + size[fmt_ulong(size,(unsigned int) databytes)] = 0; + smtp_greet("250-"); +#ifdef TLS + if (!ssl && (stat("control/servercert.pem",&st) == 0)) + out("\r\n250-STARTTLS"); +#endif + out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n"); +#ifdef TLS + if (!forcetls || ssl) { +#endif + if (smtpauth == 1 || smtpauth == 11) out("250-AUTH LOGIN PLAIN\r\n"); + if (smtpauth == 2 || smtpauth == 12) out("250-AUTH CRAM-MD5\r\n"); + if (smtpauth == 3 || smtpauth == 13) out("250-AUTH LOGIN PLAIN CRAM-MD5\r\n"); +#ifdef TLS + } +#endif + out("250 SIZE "); out(size); out("\r\n"); seenmail = 0; dohelo(arg); } void smtp_rset(arg) char *arg; { - seenmail = 0; + seenmail = 0; seenauth = 0; + mailfrom.len = 0; rcptto.len = 0; out("250 flushed\r\n"); } void smtp_mail(arg) char *arg; { + if (smtpauth) + if (smtpauth > 10 && !seenauth) { err_submission(); return; } if (!addrparse(arg)) { err_syntax(); return; } + flagsize = 0; + mailfrom_parms(arg); + if (flagsize) { err_size(); return; } flagbarf = bmfcheck(); seenmail = 1; if (!stralloc_copys(&rcptto,"")) die_nomem(); @@ -269,6 +425,11 @@ { int r; flush(); +#ifdef TLS + if (ssl && fd == ssl_rfd) + r = ssl_timeoutread(timeout, ssl_rfd, ssl_wfd, ssl, buf, len); + else +#endif r = timeoutread(timeout,fd,buf,len); if (r == -1) if (errno == error_timeout) die_alarm(); if (r <= 0) die_read(); @@ -277,6 +438,9 @@ char ssinbuf[1024]; substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); +#ifdef TLS +void flush_io() { ssin.p = 0; flush(); } +#endif struct qmail qqt; unsigned int bytestooverflow = 0; @@ -378,7 +542,7 @@ qp = qmail_qp(&qqt); out("354 go ahead\r\n"); - received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo); + received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo); blast(&hops); hops = (hops >= MAXHOPS); if (hops) qmail_fail(&qqt); @@ -388,28 +552,486 @@ qqx = qmail_close(&qqt); if (!*qqx) { acceptmessage(qp); return; } if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; } - if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; } + if (databytes) if (!bytestooverflow) { err_size(); return; } if (*qqx == 'D') out("554 "); else out("451 "); out(qqx + 1); out("\r\n"); } +/* this file is too long ----------------------------------------- SMTP AUTH */ + +char unique[FMT_ULONG + FMT_ULONG + 3]; +static stralloc authin = {0}; /* input from SMTP client */ +static stralloc user = {0}; /* authorization user-id */ +static stralloc pass = {0}; /* plain passwd or digest */ +static stralloc resp = {0}; /* b64 response */ +static stralloc chal = {0}; /* plain challenge */ +static stralloc slop = {0}; /* b64 challenge */ + +char **childargs; +char ssauthbuf[512]; +substdio ssauth = SUBSTDIO_FDBUF(safewrite,3,ssauthbuf,sizeof(ssauthbuf)); + +int authgetl(void) { + int i; + + if (!stralloc_copys(&authin,"")) die_nomem(); + for (;;) { + if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */ + i = substdio_get(&ssin,authin.s + authin.len,1); + if (i != 1) die_read(); + if (authin.s[authin.len] == '\n') break; + ++authin.len; + } + + if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len; + authin.s[authin.len] = 0; + if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); } + if (authin.len == 0) { return err_input(); } + return authin.len; +} + +int authenticate(void) +{ + int child; + int wstat; + int pi[2]; + + if (!stralloc_0(&user)) die_nomem(); + if (!stralloc_0(&pass)) die_nomem(); + if (!stralloc_0(&chal)) die_nomem(); + + if (pipe(pi) == -1) return err_pipe(); + switch(child = fork()) { + case -1: + return err_fork(); + case 0: + close(pi[1]); + if(fd_copy(3,pi[0]) == -1) return err_pipe(); + sig_pipedefault(); + execvp(*childargs, childargs); + _exit(1); + } + close(pi[0]); + + substdio_fdbuf(&ssauth,write,pi[1],ssauthbuf,sizeof ssauthbuf); + if (substdio_put(&ssauth,user.s,user.len) == -1) return err_write(); + if (substdio_put(&ssauth,pass.s,pass.len) == -1) return err_write(); + if (smtpauth == 2 || smtpauth == 3 || smtpauth == 12 || smtpauth == 13) + if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write(); + if (substdio_flush(&ssauth) == -1) return err_write(); + + close(pi[1]); + if (!stralloc_copys(&chal,"")) die_nomem(); + if (!stralloc_copys(&slop,"")) die_nomem(); + byte_zero(ssauthbuf,sizeof ssauthbuf); + if (wait_pid(&wstat,child) == -1) return err_child(); + if (wait_crashed(wstat)) return err_child(); + if (wait_exitcode(wstat)) { sleep(AUTHSLEEP); return 1; } /* no */ + return 0; /* yes */ +} + +int auth_login(arg) char *arg; +{ + int r; + + if (*arg) { + if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input(); + } + else { + out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */ + if (authgetl() < 0) return -1; + if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input(); + } + if (r == -1) die_nomem(); + + out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */ + + if (authgetl() < 0) return -1; + if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input(); + if (r == -1) die_nomem(); + + if (!user.len || !pass.len) return err_input(); + return authenticate(); +} + +int auth_plain(arg) char *arg; +{ + int r, id = 0; + + if (*arg) { + if (r = b64decode(arg,str_len(arg),&resp) == 1) return err_input(); + } + else { + out("334 \r\n"); flush(); + if (authgetl() < 0) return -1; + if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input(); + } + if (r == -1 || !stralloc_0(&resp)) die_nomem(); + while (resp.s[id]) id++; /* "authorize-id\0userid\0passwd\0" */ + + if (resp.len > id + 1) + if (!stralloc_copys(&user,resp.s + id + 1)) die_nomem(); + if (resp.len > id + user.len + 2) + if (!stralloc_copys(&pass,resp.s + id + user.len + 2)) die_nomem(); + + if (!user.len || !pass.len) return err_input(); + return authenticate(); +} + +int auth_cram() +{ + int i, r; + char *s; + + s = unique; /* generate challenge */ + s += fmt_uint(s,getpid()); + *s++ = '.'; + s += fmt_ulong(s,(unsigned long) now()); + *s++ = '@'; + *s++ = 0; + if (!stralloc_copys(&chal,"<")) die_nomem(); + if (!stralloc_cats(&chal,unique)) die_nomem(); + if (!stralloc_cats(&chal,local)) die_nomem(); + if (!stralloc_cats(&chal,">")) die_nomem(); + if (b64encode(&chal,&slop) < 0) die_nomem(); + if (!stralloc_0(&slop)) die_nomem(); + + out("334 "); /* "334 base64_challenge \r\n" */ + out(slop.s); + out("\r\n"); + flush(); + + if (authgetl() < 0) return -1; /* got response */ + if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input(); + if (r == -1 || !stralloc_0(&resp)) die_nomem(); + + i = str_rchr(resp.s,' '); + s = resp.s + i; + while (*s == ' ') ++s; + resp.s[i] = 0; + if (!stralloc_copys(&user,resp.s)) die_nomem(); /* userid */ + if (!stralloc_copys(&pass,s)) die_nomem(); /* digest */ + + if (!user.len || !pass.len) return err_input(); + return authenticate(); +} + +struct authcmd { + char *text; + int (*fun)(); +} authcmds[] = { + { "login",auth_login } +, { "plain",auth_plain } +, { "cram-md5",auth_cram } +, { 0,err_noauth } +}; + +void smtp_auth(arg) +char *arg; +{ + int i; + char *cmd = arg; + + if (!smtpauth || !*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; } + if (seenauth) { err_authd(); return; } + if (seenmail) { err_authmail(); return; } + +#ifdef TLS + if (forcetls && !ssl) { out("538 auth not available without TLS (#5.3.3)\r\n"); return; } +#endif + + if (!stralloc_copys(&user,"")) die_nomem(); + if (!stralloc_copys(&pass,"")) die_nomem(); + if (!stralloc_copys(&resp,"")) die_nomem(); + if (!stralloc_copys(&chal,"")) die_nomem(); + + i = str_chr(cmd,' '); + arg = cmd + i; + while (*arg == ' ') ++arg; + cmd[i] = 0; + + for (i = 0;authcmds[i].text;++i) + if (case_equals(authcmds[i].text,cmd)) break; + + switch (authcmds[i].fun(arg)) { + case 0: + seenauth = 1; + protocol = "ESMTPA"; + relayclient = ""; + remoteinfo = user.s; + if (!env_unset("TCPREMOTEINFO")) die_read(); + if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem(); + if (!env_put2("RELAYCLIENT",relayclient)) die_nomem(); + out("235 ok, go ahead (#2.0.0)\r\n"); + break; + case 1: + err_authfail(user.s,authcmds[i].text); + } +} + + +/* this file is too long --------------------------------------------- GO ON */ + +#ifdef TLS +stralloc proto = {0}; +int ssl_verified = 0; +const char *ssl_verify_err = 0; + +void smtp_tls(char *arg) +{ + if (ssl) err_unimpl(); + else if (*arg) out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n"); + else tls_init(); +} + +RSA *tmp_rsa_cb(SSL *ssl, int export, int keylen) +{ + if (!export) keylen = 2048; + if (keylen == 2048) { + FILE *in = fopen("control/rsa2048.pem", "r"); + if (in) { + RSA *rsa = PEM_read_RSAPrivateKey(in, NULL, NULL, NULL); + fclose(in); + if (rsa) return rsa; + } + } + return RSA_generate_key(keylen, RSA_F4, NULL, NULL); +} + +DH *tmp_dh_cb(SSL *ssl, int export, int keylen) +{ + if (!export) keylen = 2048; + if (keylen == 2048) { + FILE *in = fopen("control/dh2048.pem", "r"); + if (in) { + DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL); + fclose(in); + if (dh) return dh; + } + } + return DH_generate_parameters(keylen, DH_GENERATOR_2, NULL, NULL); +} + +/* don't want to fail handshake if cert isn't verifiable */ +int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } + +void tls_nogateway() +{ + /* there may be cases when relayclient is set */ + if (!ssl || relayclient) return; + out("; no valid cert for gatewaying"); + if (ssl_verify_err) { out(": "); out(ssl_verify_err); } +} +void tls_out(const char *s1, const char *s2) +{ + out("454 TLS "); out(s1); + if (s2) { out(": "); out(s2); } + out(" (#4.3.0)\r\n"); flush(); +} +void tls_err(const char *s) { tls_out(s, ssl_error()); if (smtps) die_read(); } + +# define CLIENTCA "control/clientca.pem" +# define CLIENTCRL "control/clientcrl.pem" +# define SERVERCERT "control/servercert.pem" + +int tls_verify() +{ + stralloc clients = {0}; + struct constmap mapclients; + + if (!ssl || relayclient || ssl_verified) return 0; + ssl_verified = 1; /* don't do this twice */ + + /* request client cert to see if it can be verified by one of our CAs + * and the associated email address matches an entry in tlsclients */ + switch (control_readfile(&clients, "control/tlsclients", 0)) + { + case 1: + if (constmap_init(&mapclients, clients.s, clients.len, 0)) { + /* if CLIENTCA contains all the standard root certificates, a + * 0.9.6b client might fail with SSL_R_EXCESSIVE_MESSAGE_SIZE; + * it is probably due to 0.9.6b supporting only 8k key exchange + * data while the 0.9.6c release increases that limit to 100k */ + STACK_OF(X509_NAME) *sk = SSL_load_client_CA_file(CLIENTCA); + if (sk) { + SSL_set_client_CA_list(ssl, sk); + SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL); + break; + } + constmap_free(&mapclients); + } + case 0: alloc_free(clients.s); return 0; + case -1: die_control(); + } + + if (ssl_timeoutrehandshake(timeout, ssl_rfd, ssl_wfd, ssl) <= 0) { + const char *err = ssl_error_str(); + tls_out("rehandshake failed", err); die_read(); + } + + do { /* one iteration */ + X509 *peercert; + X509_NAME *subj; + stralloc email = {0}; + + int n = SSL_get_verify_result(ssl); + if (n != X509_V_OK) + { ssl_verify_err = X509_verify_cert_error_string(n); break; } + peercert = SSL_get_peer_certificate(ssl); + if (!peercert) break; + + subj = X509_get_subject_name(peercert); + n = X509_NAME_get_index_by_NID(subj, NID_pkcs9_emailAddress, -1); + if (n >= 0) { + const ASN1_STRING *s = X509_NAME_get_entry(subj, n)->value; + if (s) { email.len = s->length; email.s = s->data; } + } + + if (email.len <= 0) + ssl_verify_err = "contains no email address"; + else if (!constmap(&mapclients, email.s, email.len)) + ssl_verify_err = "email address not in my list of tlsclients"; + else { + /* add the cert email to the proto if it helped allow relaying */ + --proto.len; + if (!stralloc_cats(&proto, "\n (cert ") /* continuation line */ + || !stralloc_catb(&proto, email.s, email.len) + || !stralloc_cats(&proto, ")") + || !stralloc_0(&proto)) die_nomem(); + protocol = proto.s; + relayclient = ""; + /* also inform qmail-queue */ + if (!env_put("RELAYCLIENT=")) die_nomem(); + } + + X509_free(peercert); + } while (0); + constmap_free(&mapclients); alloc_free(clients.s); + + /* we are not going to need this anymore: free the memory */ + SSL_set_client_CA_list(ssl, NULL); + SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); + + return relayclient ? 1 : 0; +} + +void tls_init() +{ + SSL *myssl; + SSL_CTX *ctx; + const char *ciphers; + stralloc saciphers = {0}; + X509_STORE *store; + X509_LOOKUP *lookup; + + SSL_library_init(); + + /* a new SSL context with the bare minimum of options */ + ctx = SSL_CTX_new(SSLv23_server_method()); + if (!ctx) { tls_err("unable to initialize ctx"); return; } + + /* POODLE vulnerability */ + SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + + if (!SSL_CTX_use_certificate_chain_file(ctx, SERVERCERT)) + { SSL_CTX_free(ctx); tls_err("missing certificate"); return; } + SSL_CTX_load_verify_locations(ctx, CLIENTCA, NULL); + +#if OPENSSL_VERSION_NUMBER >= 0x00907000L + /* crl checking */ + store = SSL_CTX_get_cert_store(ctx); + if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) && + (X509_load_crl_file(lookup, CLIENTCRL, X509_FILETYPE_PEM) == 1)) + X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | + X509_V_FLAG_CRL_CHECK_ALL); +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + /* support ECDH */ + SSL_CTX_set_ecdh_auto(ctx,1); +#endif + + /* set the callback here; SSL_set_verify didn't work before 0.9.6c */ + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_cb); + + /* a new SSL object, with the rest added to it directly to avoid copying */ + myssl = SSL_new(ctx); + SSL_CTX_free(ctx); + if (!myssl) { tls_err("unable to initialize ssl"); return; } + + /* this will also check whether public and private keys match */ + if (!SSL_use_RSAPrivateKey_file(myssl, SERVERCERT, SSL_FILETYPE_PEM)) + { SSL_free(myssl); tls_err("no valid RSA private key"); return; } + + ciphers = env_get("TLSCIPHERS"); + if (!ciphers) { + if (control_readfile(&saciphers, "control/tlsserverciphers", 0) == -1) + { SSL_free(myssl); die_control(); } + if (saciphers.len) { /* convert all '\0's except the last one to ':' */ + int i; + for (i = 0; i < saciphers.len - 1; ++i) + if (!saciphers.s[i]) saciphers.s[i] = ':'; + ciphers = saciphers.s; + } + } + if (!ciphers || !*ciphers) ciphers = "DEFAULT"; + SSL_set_cipher_list(myssl, ciphers); + alloc_free(saciphers.s); + + SSL_set_tmp_rsa_callback(myssl, tmp_rsa_cb); + SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); + SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); + SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); + + if (!smtps) { out("220 ready for tls\r\n"); flush(); } + + if (ssl_timeoutaccept(timeout, ssl_rfd, ssl_wfd, myssl) <= 0) { + /* neither cleartext nor any other response here is part of a standard */ + const char *err = ssl_error_str(); + ssl_free(myssl); tls_out("connection failed", err); die_read(); + } + ssl = myssl; + + /* populate the protocol string, used in Received */ + if (!stralloc_copys(&proto, "ESMTPS (") + || !stralloc_cats(&proto, SSL_get_cipher(ssl)) + || !stralloc_cats(&proto, " encrypted)")) die_nomem(); + if (!stralloc_0(&proto)) die_nomem(); + protocol = proto.s; + + /* have to discard the pre-STARTTLS HELO/EHLO argument, if any */ + dohelo(remotehost); +} + +# undef SERVERCERT +# undef CLIENTCA + +#endif + struct commands smtpcommands[] = { { "rcpt", smtp_rcpt, 0 } , { "mail", smtp_mail, 0 } , { "data", smtp_data, flush } +, { "auth", smtp_auth, flush } , { "quit", smtp_quit, flush } , { "helo", smtp_helo, flush } , { "ehlo", smtp_ehlo, flush } , { "rset", smtp_rset, 0 } , { "help", smtp_help, flush } +#ifdef TLS +, { "starttls", smtp_tls, flush_io } +#endif , { "noop", err_noop, flush } , { "vrfy", err_vrfy, flush } , { 0, err_unimpl, flush } } ; -void main() +void main(argc,argv) +int argc; +char **argv; { + childargs = argv + 1; sig_pipeignore(); if (chdir(auto_qmail) == -1) die_control(); setup(); diff -ruN ../../netqmail-1.06-original/ssl_timeoutio.c netqmail-1.06/ssl_timeoutio.c --- ../../netqmail-1.06-original/ssl_timeoutio.c 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/ssl_timeoutio.c 2016-05-15 11:27:32.100942976 +0000 @@ -0,0 +1,95 @@ +#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; + + SSL_renegotiate(ssl); + 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; + 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); +} diff -ruN ../../netqmail-1.06-original/ssl_timeoutio.h netqmail-1.06/ssl_timeoutio.h --- ../../netqmail-1.06-original/ssl_timeoutio.h 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/ssl_timeoutio.h 2016-05-15 11:27:32.100942976 +0000 @@ -0,0 +1,21 @@ +#ifndef SSL_TIMEOUTIO_H +#define SSL_TIMEOUTIO_H + +#include + +/* the version is like this: 0xMNNFFPPS: major minor fix patch status */ +#if OPENSSL_VERSION_NUMBER < 0x00906000L +# error "Need OpenSSL version at least 0.9.6" +#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 diff -ruN ../../netqmail-1.06-original/tls.c netqmail-1.06/tls.c --- ../../netqmail-1.06-original/tls.c 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/tls.c 2016-05-15 11:27:32.101942943 +0000 @@ -0,0 +1,25 @@ +#include "exit.h" +#include "error.h" +#include +#include + +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); +} diff -ruN ../../netqmail-1.06-original/tls.h netqmail-1.06/tls.h --- ../../netqmail-1.06-original/tls.h 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/tls.h 2016-05-15 11:27:32.101942943 +0000 @@ -0,0 +1,16 @@ +#ifndef TLS_H +#define TLS_H + +#include + +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 diff -ruN ../../netqmail-1.06-original/update_tmprsadh.sh netqmail-1.06/update_tmprsadh.sh --- ../../netqmail-1.06-original/update_tmprsadh.sh 1970-01-01 00:00:00.000000000 +0000 +++ netqmail-1.06/update_tmprsadh.sh 2016-05-15 11:27:32.101942943 +0000 @@ -0,0 +1,18 @@ +#!/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 + +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