Last active
March 19, 2022 22:25
-
-
Save alexh-name/ad365b9ca3613c06f726f7890e301a96 to your computer and use it in GitHub Desktop.
a standalone patch that could replace netqmail-1.05-tls-smtpauth-20070417.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
VERSION: 20190114 | |
This patch for netqmail 1.05 is a composite of the latest versions of Frederik | |
Vermulen's TLS patch (20070408) and Erwin Hoffmann's SMTP-AUTH (0.5.8) update | |
to Eric M. Johnston's and Krzysztof Dabrowski's qmail-smtpd-auth-0.31 patch. | |
It was later ported to openssl 1.1 by Alex H. (git@alexh.name). | |
To install, get netqmail 1.05, put it in the same directory as this patch, and | |
then set it up: | |
wget http://qmail.org/netqmail-1.05.tar.gz | |
tar -xzf netqmail-1.05.tar.gz | |
cd netqmail-1.05 | |
./collate.sh | |
cd netqmail-1.05 | |
patch -p0 < ../../netqmail-1.05-tls-smtpauth-20070417.patch | |
cd netqmail-1.05 | |
make | |
make setup check | |
make cert | |
make tmprsadh | |
Voila! You should now have TLS and SMTP-AUTH support working in qmail-smtpd. | |
VPOPMAIL NOTE: This version will only work with vpopmail versions 5.4.0 and | |
later | |
Here are the relevant URLs: | |
Netqmail: | |
http://www.qmail.org/netqmail/ | |
TLS: | |
http://inoa.net/qmail-tls/ | |
Qmail SMTP-AUTH: | |
http://www.fehcom.de/qmail/smtpauth.html | |
This composite patch was put together by Bill Shupp (hostmaster@shupp.org) | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/base64.c ./base64.c | |
--- ../../netqmail-1.05-orig/netqmail-1.05/base64.c 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./base64.c 2007-04-17 17:44:12.572978320 -0500 | |
@@ -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 -urN ../../netqmail-1.05-orig/netqmail-1.05/base64.h ./base64.h | |
--- ../../netqmail-1.05-orig/netqmail-1.05/base64.h 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./base64.h 2007-04-17 17:44:12.572978320 -0500 | |
@@ -0,0 +1,7 @@ | |
+#ifndef BASE64_H | |
+#define BASE64_H | |
+ | |
+extern int b64decode(); | |
+extern int b64encode(); | |
+ | |
+#endif | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/case_startb.c ./case_startb.c | |
--- ../../netqmail-1.05-orig/netqmail-1.05/case_startb.c 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./case_startb.c 2007-04-17 17:44:12.573978168 -0500 | |
@@ -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 -urN ../../netqmail-1.05-orig/netqmail-1.05/conf-cc ./conf-cc | |
--- ../../netqmail-1.05-orig/netqmail-1.05/conf-cc 1998-06-15 05:53:16.000000000 -0500 | |
+++ ./conf-cc 2007-04-17 17:44:27.666683728 -0500 | |
@@ -1,3 +1,3 @@ | |
-cc -O2 | |
+cc -O2 -DTLS=20070408 -I/usr/local/ssl/include | |
This will be used to compile .c files. | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/dns.c ./dns.c | |
--- ../../netqmail-1.05-orig/netqmail-1.05/dns.c 2007-04-17 17:41:58.087423232 -0500 | |
+++ ./dns.c 2007-04-17 17:44:12.574978016 -0500 | |
@@ -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 -urN ../../netqmail-1.05-orig/netqmail-1.05/FILES.auth ./FILES.auth | |
--- ../../netqmail-1.05-orig/netqmail-1.05/FILES.auth 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./FILES.auth 2007-04-17 17:44:12.575977864 -0500 | |
@@ -0,0 +1,18 @@ | |
+The qmail-smtpd Auth patch modifies the following QMAIL 1.03 files: | |
+ | |
+= TARGETS | |
+= Makefile | |
+= qmail-smtpd.c | |
+= qmail-smtpd.8 | |
+ | |
+Added files: | |
+ | |
++ base64.c | |
++ base64.h | |
++ case_startb.c | |
+ | |
+Informational files: | |
+ | |
+% install_smtpd-auth.sh (Installation shell script) | |
+% README.auth | |
+% README.auth.old (old description of SMTP Auth) | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/hier.c ./hier.c | |
--- ../../netqmail-1.05-orig/netqmail-1.05/hier.c 1998-06-15 05:53:16.000000000 -0500 | |
+++ ./hier.c 2007-04-17 17:44:12.576977712 -0500 | |
@@ -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 -urN ../../netqmail-1.05-orig/netqmail-1.05/install_auth.sh ./install_auth.sh | |
--- ../../netqmail-1.05-orig/netqmail-1.05/install_auth.sh 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./install_auth.sh 2007-04-17 17:44:12.577977560 -0500 | |
@@ -0,0 +1,99 @@ | |
+#!/bin/sh | |
+# | |
+# qmail-smtpd AUTH (UN)INSTALL Script (install_auth.sh) | |
+# ----------------------------------------------------- | |
+# | |
+# Purpose: To install and uninstall the qmail-smtpd Authentication Patch | |
+# | |
+# Parameters: -u (uninstall) | |
+# VRF (Version to be uninstalled) | |
+# | |
+# Usage: ./install_auth.sh [-u] [Version] | |
+# | |
+# Installation: ./install_auth.sh | |
+# Uninstallation: ./install_auth.sh -u 105 | |
+# | |
+# Return Codes: 0 - Patches applied successfully | |
+# 1 - Original QMAIL files not found (Patch not extracted in QMAIL source directory) | |
+# 2 - Patch files not found | |
+# | |
+# Output: install_auth.log | |
+# | |
+# History: 1.0.0 - Erwin Hoffmann - Initial release | |
+# 1.0.1 - - grep fix; Gentoo fix | |
+# 1.0.2 - removed '-v' optio for cp | |
+# | |
+#--------------------------------------------------------------------------------------- | |
+# | |
+DATE=$(date) | |
+LOCDIR=${PWD} | |
+QMAILHOME=$(head -n 1 conf-qmail) | |
+SOLARIS=$(sh ./find-systype.sh | grep -ci "SunOS") | |
+LOGFILE=auth.log | |
+TARGETS=FILES.auth | |
+IFSKEEP=${IFS} | |
+REL=057 # Should be identical to qmail-smtpd AUTH level | |
+BUILD=2005024212941 | |
+ | |
+ | |
+if [ $# -eq 0 ] ; then | |
+ | |
+ echo "Installing qmail-smtpd AUTH $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1 | |
+ | |
+ for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do | |
+ echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1 | |
+ if [ -s ${FILE} ] ; then | |
+ cp ${FILE} ${FILE}.$REL | tee -a $LOGFILE 2>&1 | |
+ echo "--> ${FILE} copied to ${FILE}.$REL" | tee -a $LOGFILE 2>&1 | |
+ else | |
+ echo "${FILE} not found !" | |
+ exit 1 | |
+ fi | |
+ if [ -s ${FILE}.patch ] ; then | |
+ if [ ${SOLARIS} -gt 0 ]; then | |
+ echo "--> Patching qmail source file ${FILE} for Solaris ...." | tee -a $LOGFILE 2>&1 | |
+ patch -i ${FILE}.patch ${FILE} 2>&1 | tee -a $LOGFILE | |
+ else | |
+ echo "--> Patching qmail source file ${FILE} ...." | tee -a $LOGFILE 2>&1 | |
+ patch ${FILE} ${FILE}.patch 2>&1 | tee -a $LOGFILE | |
+ fi | |
+ else | |
+ echo "!! ${FILE}.patch not found !" | |
+ exit 2 | |
+ fi | |
+ done | |
+ | |
+ | |
+ echo "Copying documentation and samples to ${QMAILHOME}/doc/ ..." | tee -a $LOGFILE 2>&1 | |
+ | |
+ cp README.auth* ${QMAILHOME}/doc/ | tee -a $LOGFILE 2>&1 | |
+ echo "" | |
+ echo "If you dont wont CRAM-MD5 suport disable '#define CRAM_MD5' in qmail-smtpd !" | |
+ echo "Installation of qmail-smtpd AUTH $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1 | |
+ | |
+# Now go for the uninstallation.... | |
+ | |
+elif [ "$1" = "-u" ] ; then | |
+ | |
+# Get the Version Number from INPUT | |
+ | |
+ if [ $# -eq 2 ] ; then | |
+ REL=$2 | |
+ fi | |
+ | |
+ echo "De-installing qmail-smtpd AUTH $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1 | |
+ | |
+ for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do | |
+ echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1 | |
+ if [ -s ${FILE}.$REL ] ; then | |
+ mv ${FILE}.$REL ${FILE} | tee -a $LOGFILE 2>&1 | |
+ touch ${FILE} | |
+ echo "--> ${FILE}.$REL moved to ${FILE}" | tee -a $LOGFILE 2>&1 | |
+ else | |
+ echo "!! ${FILE}.$REL not found !" | |
+ fi | |
+ done | |
+ echo "De-installation of qmail-smtpd AUTH $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1 | |
+fi | |
+ | |
+exit 0 | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/ipalloc.h ./ipalloc.h | |
--- ../../netqmail-1.05-orig/netqmail-1.05/ipalloc.h 1998-06-15 05:53:16.000000000 -0500 | |
+++ ./ipalloc.h 2007-04-17 17:44:12.578977408 -0500 | |
@@ -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 -urN ../../netqmail-1.05-orig/netqmail-1.05/Makefile ./Makefile | |
--- ../../netqmail-1.05-orig/netqmail-1.05/Makefile 2007-04-17 17:41:58.083423840 -0500 | |
+++ ./Makefile 2007-04-17 17:44:12.581976952 -0500 | |
@@ -136,6 +136,10 @@ | |
compile auto_usera.c | |
./compile auto_usera.c | |
+base64.o: \ | |
+compile base64.c base64.h stralloc.h substdio.h str.h | |
+ ./compile base64.c | |
+ | |
binm1: \ | |
binm1.sh conf-qmail | |
cat binm1.sh \ | |
@@ -808,7 +812,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 | |
@@ -1444,6 +1448,7 @@ | |
substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib | |
./load qmail-remote control.o constmap.o timeoutread.o \ | |
timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \ | |
+ tls.o ssl_timeoutio.o -L/usr/local/ssl/lib -lssl -lcrypto \ | |
ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \ | |
lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \ | |
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` | |
@@ -1536,12 +1541,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 +1559,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 +1833,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 +2115,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 +2159,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 -urN ../../netqmail-1.05-orig/netqmail-1.05/Makefile-cert.mk ./Makefile-cert.mk | |
--- ../../netqmail-1.05-orig/netqmail-1.05/Makefile-cert.mk 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./Makefile-cert.mk 2007-04-17 17:44:12.582976800 -0500 | |
@@ -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 -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-control.9 ./qmail-control.9 | |
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-control.9 1998-06-15 05:53:16.000000000 -0500 | |
+++ ./qmail-control.9 2007-04-17 17:44:12.583976648 -0500 | |
@@ -43,11 +43,15 @@ | |
.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 dh1024.pem \fR(none) \fRqmail-smtpd | |
+.I dh512.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 rsa512.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 -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-remote.8 ./qmail-remote.8 | |
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-remote.8 1998-06-15 05:53:16.000000000 -0500 | |
+++ ./qmail-remote.8 2007-04-17 17:44:27.666683728 -0500 | |
@@ -114,6 +114,10 @@ | |
always exits zero. | |
.SH "CONTROL FILES" | |
.TP 5 | |
+.I clientcert.pem | |
+SSL certificate that is used to authenticate with the remote server | |
+during a TLS session. | |
+.TP 5 | |
.I helohost | |
Current host name, | |
for use solely in saying hello to the remote SMTP server. | |
@@ -123,6 +127,16 @@ | |
otherwise | |
.B qmail-remote | |
refuses to run. | |
+ | |
+.TP 5 | |
+.I notlshosts/<FQDN> | |
+.B qmail-remote | |
+will not try TLS on servers for which this file exists | |
+.RB ( <FQDN> | |
+is the fully-qualified domain name of the server). | |
+.IR (tlshosts/<FQDN>.pem | |
+takes precedence over this file however). | |
+ | |
.TP 5 | |
.I smtproutes | |
Artificial SMTP routes. | |
@@ -156,6 +170,8 @@ | |
this tells | |
.B qmail-remote | |
to look up MX records as usual. | |
+.I port | |
+value of 465 (deprecated smtps port) causes TLS session to be started. | |
.I smtproutes | |
may include wildcards: | |
@@ -195,6 +211,33 @@ | |
.B qmail-remote | |
will wait for each response from the remote SMTP server. | |
Default: 1200. | |
+ | |
+.TP 5 | |
+.I tlsclientciphers | |
+A set of OpenSSL client cipher strings. Multiple ciphers | |
+contained in a string should be separated by a colon. | |
+ | |
+.TP 5 | |
+.I tlshosts/<FQDN>.pem | |
+.B qmail-remote | |
+requires TLS authentication from servers for which this file exists | |
+.RB ( <FQDN> | |
+is the fully-qualified domain name of the server). One of the | |
+.I dNSName | |
+or the | |
+.I CommonName | |
+attributes have to match. The file contains the trusted CA certificates. | |
+ | |
+.B WARNING: | |
+this option may cause mail to be delayed, bounced, doublebounced, or lost. | |
+ | |
+.TP 5 | |
+.I tlshosts/exhaustivelist | |
+if this file exists | |
+no TLS will be tried on hosts other than those for which a file | |
+.B tlshosts/<FQDN>.pem | |
+exists. | |
+ | |
.SH "SEE ALSO" | |
addresses(5), | |
envelopes(5), | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-remote.c ./qmail-remote.c | |
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-remote.c 1998-06-15 05:53:16.000000000 -0500 | |
+++ ./qmail-remote.c 2007-04-17 17:44:12.586976192 -0500 | |
@@ -48,6 +48,17 @@ | |
struct ip_address partner; | |
+#ifdef TLS | |
+# include <sys/stat.h> | |
+# include "tls.h" | |
+# include "ssl_timeoutio.h" | |
+# include <openssl/x509v3.h> | |
+# define EHLO 1 | |
+ | |
+int tls_init(); | |
+const char *ssl_err_str = 0; | |
+#endif | |
+ | |
void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } | |
void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } | |
void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); } | |
@@ -99,6 +110,9 @@ | |
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 +124,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 +137,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 +189,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 +264,11 @@ | |
char *prepend; | |
char *append; | |
{ | |
+#ifdef TLS | |
+ /* shouldn't talk to the client unless in an appropriate state */ | |
+ int state = ssl ? SSL_get_state(ssl) : TLS_ST_BEFORE; | |
+ if (state & TLS_ST_OK || (!smtps && state & TLS_ST_BEFORE)) | |
+#endif | |
substdio_putsflush(&smtpto,"QUIT\r\n"); | |
/* waiting for remote side is just too ridiculous */ | |
out(prepend); | |
@@ -186,6 +276,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,6 +328,194 @@ | |
substdio_flush(&smtpto); | |
} | |
+#ifdef TLS | |
+char *partner_fqdn = 0; | |
+ | |
+# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "") | |
+void tls_quit(const char *s1, const char *s2) | |
+{ | |
+ out(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() | |
+{ | |
+ int i; | |
+ SSL *myssl; | |
+ SSL_CTX *ctx; | |
+ stralloc saciphers = {0}; | |
+ const char *ciphers, *servercert = 0; | |
+ | |
+ if (partner_fqdn) { | |
+ struct stat st; | |
+ stralloc tmp = {0}; | |
+ if (!stralloc_copys(&tmp, "control/tlshosts/") | |
+ || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)) | |
+ || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem(); | |
+ if (stat(tmp.s, &st) == 0) | |
+ servercert = tmp.s; | |
+ else { | |
+ if (!stralloc_copys(&tmp, "control/notlshosts/") | |
+ || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1)) | |
+ temp_nomem(); | |
+ if ((stat("control/tlshosts/exhaustivelist", &st) == 0) || | |
+ (stat(tmp.s, &st) == 0)) { | |
+ alloc_free(tmp.s); | |
+ return 0; | |
+ } | |
+ alloc_free(tmp.s); | |
+ } | |
+ } | |
+ | |
+ if (!smtps) { | |
+ stralloc *sa = ehlokw.sa; | |
+ unsigned int len = ehlokw.len; | |
+ /* look for STARTTLS among EHLO keywords */ | |
+ for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ; | |
+ if (!len) { | |
+ if (!servercert) return 0; | |
+ out("ZNo TLS achieved while "); out(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"); | |
+ } | |
+ | |
+ 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 responce, 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_options(myssl, SSL_OP_NO_TLSv1); */ | |
+ SSL_set_fd(myssl, smtpfd); | |
+ | |
+ /* read the responce 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 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) | |
+ if (match_partner(gn->d.ia5->data, gn->d.ia5->length)) break; | |
+ } | |
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); | |
+ } | |
+ | |
+ /* no alternative name matched, look up commonName */ | |
+ if (!gens || i >= r) { | |
+ stralloc peer = {0}; | |
+ X509_NAME *subj = X509_get_subject_name(peercert); | |
+ i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1); | |
+ if (i >= 0) { | |
+ const ASN1_STRING *s = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subj, i)); | |
+ if (s) { peer.len = s->length; peer.s = s->data; } | |
+ } | |
+ if (peer.len <= 0) { | |
+ out("ZTLS unable to verify server "); | |
+ tls_quit(partner_fqdn, "certificate contains no valid commonName"); | |
+ } | |
+ if (!match_partner(peer.s, peer.len)) { | |
+ out("ZTLS unable to verify server "); out(partner_fqdn); | |
+ out(": received certificate for "); outsafe(&peer); TLS_QUIT; | |
+ } | |
+ } | |
+ | |
+ X509_free(peercert); | |
+ } | |
+ | |
+ if (smtps) if (smtpcode() != 220) | |
+ quit("ZTLS Connected to "," but greeting failed"); | |
+ | |
+ return 1; | |
+} | |
+#endif | |
+ | |
stralloc recip = {0}; | |
void smtp() | |
@@ -221,15 +523,54 @@ | |
unsigned long code; | |
int flagbother; | |
int i; | |
+ | |
+#ifndef PORT_SMTP | |
+ /* the qmtpc patch uses smtp_port and undefines PORT_SMTP */ | |
+# define port smtp_port | |
+#endif | |
+ | |
+#ifdef TLS | |
+# ifdef MXPS | |
+ if (type == 'S') smtps = 1; | |
+ else if (type != 's') | |
+# endif | |
+ if (port == 465) smtps = 1; | |
+ if (!smtps) | |
+#endif | |
if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); | |
+#ifdef EHLO | |
+# ifdef TLS | |
+ if (!smtps) | |
+# endif | |
+ code = ehlo(); | |
+ | |
+# ifdef TLS | |
+ if (tls_init()) | |
+ /* RFC2487 says we should issue EHLO (even if we might not need | |
+ * extensions); at the same time, it does not prohibit a server | |
+ * to reject the EHLO and make us fallback to HELO */ | |
+ code = ehlo(); | |
+# endif | |
+ | |
+ if (code == 250) { | |
+ /* add EHLO response checks here */ | |
+ | |
+ /* and if EHLO failed, use HELO */ | |
+ } else { | |
+#endif | |
+ | |
substdio_puts(&smtpto,"HELO "); | |
substdio_put(&smtpto,helohost.s,helohost.len); | |
substdio_puts(&smtpto,"\r\n"); | |
substdio_flush(&smtpto); | |
if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); | |
+#ifdef EHLO | |
+ } | |
+#endif | |
+ | |
substdio_puts(&smtpto,"MAIL FROM:<"); | |
substdio_put(&smtpto,sender.s,sender.len); | |
substdio_puts(&smtpto,">\r\n"); | |
@@ -417,6 +758,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 -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-smtpd.8 ./qmail-smtpd.8 | |
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-smtpd.8 1998-06-15 05:53:16.000000000 -0500 | |
+++ ./qmail-smtpd.8 2007-04-17 17:44:12.587976040 -0500 | |
@@ -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 dh1024.pem | |
+If these 1024 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 dh512.pem | |
+512 bit counterpart for | |
+.B dh1024.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,24 @@ | |
.B qmail-smtpd | |
will wait for each new buffer of data from the remote SMTP client. | |
Default: 1200. | |
+ | |
+.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 -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-smtpd.c ./qmail-smtpd.c | |
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-smtpd.c 2007-04-17 17:41:58.094422168 -0500 | |
+++ ./qmail-smtpd.c 2007-04-17 17:44:27.668683424 -0500 | |
@@ -23,14 +23,34 @@ | |
#include "timeoutread.h" | |
#include "timeoutwrite.h" | |
#include "commands.h" | |
+#include "wait.h" | |
+ | |
+#define CRAM_MD5 | |
+#define AUTHSLEEP 5 | |
#define MAXHOPS 100 | |
unsigned int databytes = 0; | |
int timeout = 1200; | |
+#ifdef TLS | |
+#include <sys/stat.h> | |
+#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 */ | |
+#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 +69,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 +89,16 @@ | |
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"); } | |
stralloc greeting = {0}; | |
@@ -76,6 +116,7 @@ | |
smtp_greet("221 "); out("\r\n"); flush(); _exit(0); | |
} | |
+char *protocol; | |
char *remoteip; | |
char *remotehost; | |
char *remoteinfo; | |
@@ -109,7 +150,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,6 +162,7 @@ | |
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"); | |
@@ -131,6 +172,11 @@ | |
if (!remotehost) remotehost = "unknown"; | |
remoteinfo = env_get("TCPREMOTEINFO"); | |
relayclient = env_get("RELAYCLIENT"); | |
+ | |
+#ifdef TLS | |
+ if (env_get("SMTPS")) { smtps = 1; tls_init(); } | |
+ else | |
+#endif | |
dohelo(remotehost); | |
} | |
@@ -213,23 +259,105 @@ | |
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; | |
} | |
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; | |
+{ | |
+ int j; | |
+ | |
+ 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"); | |
+#ifdef TLS | |
+ struct stat st; | |
+#endif | |
+ char size[FMT_ULONG]; | |
+ smtp_greet("250-"); | |
+#ifdef TLS | |
+ if (!ssl && (stat("control/servercert.pem",&st) == 0)) | |
+ out("\r\n250-STARTTLS"); | |
+#endif | |
+ size[fmt_ulong(size,(unsigned int) databytes)] = 0; | |
+ out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n"); | |
+ out("250-SIZE "); out(size); out("\r\n"); | |
+#ifdef CRAM_MD5 | |
+ out("250 AUTH LOGIN PLAIN CRAM-MD5\r\n"); | |
+#else | |
+ out("250 AUTH LOGIN PLAIN\r\n"); | |
+#endif | |
seenmail = 0; dohelo(arg); | |
} | |
void smtp_rset(arg) char *arg; | |
@@ -240,6 +368,9 @@ | |
void smtp_mail(arg) char *arg; | |
{ | |
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 +400,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(); | |
@@ -378,7 +514,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 +524,494 @@ | |
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 */ | |
+#ifdef CRAM_MD5 | |
+static stralloc chal = {0}; /* plain challenge */ | |
+static stralloc slop = {0}; /* b64 challenge */ | |
+#endif | |
+ | |
+int flagauth = 0; | |
+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(); | |
+#ifdef CRAM_MD5 | |
+ if (!stralloc_0(&chal)) die_nomem(); | |
+#endif | |
+ | |
+ 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(); | |
+#ifdef CRAM_MD5 | |
+ if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write(); | |
+#endif | |
+ if (substdio_flush(&ssauth) == -1) return err_write(); | |
+ | |
+ close(pi[1]); | |
+#ifdef CRAM_MD5 | |
+ if (!stralloc_copys(&chal,"")) die_nomem(); | |
+ if (!stralloc_copys(&slop,"")) die_nomem(); | |
+#endif | |
+ 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(); | |
+} | |
+ | |
+#ifdef CRAM_MD5 | |
+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_chr(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(); | |
+} | |
+#endif | |
+ | |
+struct authcmd { | |
+ char *text; | |
+ int (*fun)(); | |
+} authcmds[] = { | |
+ { "login",auth_login } | |
+, { "plain",auth_plain } | |
+#ifdef CRAM_MD5 | |
+, { "cram-md5",auth_cram } | |
+#endif | |
+, { 0,err_noauth } | |
+}; | |
+ | |
+void smtp_auth(arg) | |
+char *arg; | |
+{ | |
+ int i; | |
+ char *cmd = arg; | |
+ | |
+ if (!*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; } | |
+ if (flagauth) { err_authd(); return; } | |
+ if (seenmail) { err_authmail(); return; } | |
+ | |
+ if (!stralloc_copys(&user,"")) die_nomem(); | |
+ if (!stralloc_copys(&pass,"")) die_nomem(); | |
+ if (!stralloc_copys(&resp,"")) die_nomem(); | |
+#ifdef CRAM_MD5 | |
+ if (!stralloc_copys(&chal,"")) die_nomem(); | |
+#endif | |
+ | |
+ 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: | |
+ flagauth = 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 = 512; | |
+ if (keylen == 512) { | |
+ FILE *in = fopen("control/rsa512.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 = 1024; | |
+ if (keylen == 512) { | |
+ FILE *in = fopen("control/dh512.pem", "r"); | |
+ if (in) { | |
+ DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL); | |
+ fclose(in); | |
+ if (dh) return dh; | |
+ } | |
+ } | |
+ if (keylen == 1024) { | |
+ FILE *in = fopen("control/dh1024.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_ENTRY_get_data(X509_NAME_get_entry(subj, n)); | |
+ 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(); | |
+ relayclient = ""; | |
+ protocol = proto.s; | |
+ } | |
+ | |
+ 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; } | |
+ | |
+ 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 | |
+ | |
+ /* 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 } | |
+#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 -urN ../../netqmail-1.05-orig/netqmail-1.05/README.auth ./README.auth | |
--- ../../netqmail-1.05-orig/netqmail-1.05/README.auth 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./README.auth 2007-04-17 17:44:12.590975584 -0500 | |
@@ -0,0 +1,67 @@ | |
+README qmail-smtpd SMTP Authentication | |
+====================================== | |
+ | |
+ | |
+History: | |
+-------- | |
+ | |
+This patch is based on Krzysztof Dabrowski's qmail-smtpd-auth-0.31 patch | |
+which itself uses "Mrs. Brisby's" initial code. | |
+Version 0.41 of this patch fixes the "CAPS-LOCK" typo announcing | |
+'CRAM_MD5' instead of 'CRAM-MD5' (german keyboard) - tx to Mike Garrison. | |
+Version 0.42 fixes the '421 unable to read controls (#4.3.0)' problem | |
+(can't read control/morercpthosts.cdb) because FD 3 was already closed - tx Richard Lyons. | |
+Version 0.43 fixes the ba64decode() failure in case CRAM_MD5 is not enabled - tx Vladimir Zidar. | |
+Version 0.51 includes the evaluation of the 'Auth' and the 'Size' parameter in the 'Mail From:' command. | |
+Version 0.52 uses DJB functions to copy FDs. | |
+Version 0.56 corrects some minor mistakes displaying the 'Auth' userid. | |
+Version 0.57 uses keyword "ESMTPA" in Received header in case of authentication to comply with RFC 3848. | |
+Version 0.58 fixes a potential problem with cc -O2 optimization within base64.c - tx John Simpson. | |
+ | |
+ | |
+Scope: | |
+------ | |
+ | |
+This patch supports RFC 2554 "SMTP Service Extension for Authentication" for qmail-smtpd. | |
+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. | |
+* Modify the compile time option "#define CRAM_MD5" to your needs. | |
+* Re-make qmail. | |
+ | |
+ | |
+Setup: | |
+------ | |
+ | |
+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. | |
+ | |
+ | |
+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: <return-path> SIZE=123456780' (RFC 1870). | |
+* RFC 3848 conformance for Received header in case of SMTP Auth. | |
+ | |
+ | |
+Erwin Hoffmann - Cologne 2006-12-28 (www.fehcom.de) | |
+ | |
+ | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/ssl_timeoutio.c ./ssl_timeoutio.c | |
--- ../../netqmail-1.05-orig/netqmail-1.05/ssl_timeoutio.c 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./ssl_timeoutio.c 2007-04-17 17:44:27.669683272 -0500 | |
@@ -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_get_state(ssl) == SSL_ST_CONNECT) return r; | |
+ | |
+ /* this is for the server only */ | |
+ SSL_set_accept_state(ssl); | |
+ 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 -urN ../../netqmail-1.05-orig/netqmail-1.05/ssl_timeoutio.h ./ssl_timeoutio.h | |
--- ../../netqmail-1.05-orig/netqmail-1.05/ssl_timeoutio.h 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./ssl_timeoutio.h 2007-04-17 17:44:27.670683120 -0500 | |
@@ -0,0 +1,21 @@ | |
+#ifndef SSL_TIMEOUTIO_H | |
+#define SSL_TIMEOUTIO_H | |
+ | |
+#include <openssl/ssl.h> | |
+ | |
+/* the version is like this: 0xMNNFFPPS: major minor fix patch status */ | |
+#if OPENSSL_VERSION_NUMBER < 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 -urN ../../netqmail-1.05-orig/netqmail-1.05/TARGETS ./TARGETS | |
--- ../../netqmail-1.05-orig/netqmail-1.05/TARGETS 1998-06-15 05:53:16.000000000 -0500 | |
+++ ./TARGETS 2007-04-17 17:44:12.593975128 -0500 | |
@@ -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 | |
@@ -320,6 +323,7 @@ | |
binm2+df | |
binm3 | |
binm3+df | |
+Makefile-cert | |
it | |
qmail-local.0 | |
qmail-lspawn.0 | |
@@ -385,3 +389,4 @@ | |
man | |
setup | |
check | |
+update_tmprsadh | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/tls.c ./tls.c | |
--- ../../netqmail-1.05-orig/netqmail-1.05/tls.c 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./tls.c 2007-04-17 17:44:12.593975128 -0500 | |
@@ -0,0 +1,25 @@ | |
+#include "exit.h" | |
+#include "error.h" | |
+#include <openssl/ssl.h> | |
+#include <openssl/err.h> | |
+ | |
+int smtps = 0; | |
+SSL *ssl = NULL; | |
+ | |
+void ssl_free(SSL *myssl) { SSL_shutdown(myssl); SSL_free(myssl); } | |
+void ssl_exit(int status) { if (ssl) ssl_free(ssl); _exit(status); } | |
+ | |
+const char *ssl_error() | |
+{ | |
+ int r = ERR_get_error(); | |
+ if (!r) return NULL; | |
+ SSL_load_error_strings(); | |
+ return ERR_error_string(r, NULL); | |
+} | |
+const char *ssl_error_str() | |
+{ | |
+ const char *err = ssl_error(); | |
+ if (err) return err; | |
+ if (!errno) return 0; | |
+ return (errno == error_timeout) ? "timed out" : error_str(errno); | |
+} | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/tls.h ./tls.h | |
--- ../../netqmail-1.05-orig/netqmail-1.05/tls.h 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./tls.h 2007-04-17 17:44:12.594974976 -0500 | |
@@ -0,0 +1,16 @@ | |
+#ifndef TLS_H | |
+#define TLS_H | |
+ | |
+#include <openssl/ssl.h> | |
+ | |
+extern int smtps; | |
+extern SSL *ssl; | |
+ | |
+void ssl_free(SSL *myssl); | |
+void ssl_exit(int status); | |
+# define _exit ssl_exit | |
+ | |
+const char *ssl_error(); | |
+const char *ssl_error_str(); | |
+ | |
+#endif | |
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/update_tmprsadh.sh ./update_tmprsadh.sh | |
--- ../../netqmail-1.05-orig/netqmail-1.05/update_tmprsadh.sh 1969-12-31 18:00:00.000000000 -0600 | |
+++ ./update_tmprsadh.sh 2007-04-17 17:44:12.595974824 -0500 | |
@@ -0,0 +1,25 @@ | |
+#!/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/rsa512.new 512 && | |
+chmod 600 QMAIL/control/rsa512.new && | |
+chown UGQMAILD QMAIL/control/rsa512.new && | |
+mv -f QMAIL/control/rsa512.new QMAIL/control/rsa512.pem | |
+echo | |
+ | |
+openssl dhparam -2 -out QMAIL/control/dh512.new 512 && | |
+chmod 600 QMAIL/control/dh512.new && | |
+chown UGQMAILD QMAIL/control/dh512.new && | |
+mv -f QMAIL/control/dh512.new QMAIL/control/dh512.pem | |
+echo | |
+ | |
+openssl dhparam -2 -out QMAIL/control/dh1024.new 1024 && | |
+chmod 600 QMAIL/control/dh1024.new && | |
+chown UGQMAILD QMAIL/control/dh1024.new && | |
+mv -f QMAIL/control/dh1024.new QMAIL/control/dh1024.pem |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment