Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 561154 Details for
Bug 675060
mail-mta/netqmail-1.06-r5 fails to build against dev-libs/openssl-1.1.0j
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
a standalone patch that could replace netqmail-1.05-tls-smtpauth-20070417.patch
netqmail-1.05-tls-smtpauth-20160114.patch (text/plain), 66.46 KB, created by
Alexander Hof
on 2019-01-14 20:25:52 UTC
(
hide
)
Description:
a standalone patch that could replace netqmail-1.05-tls-smtpauth-20070417.patch
Filename:
MIME Type:
Creator:
Alexander Hof
Created:
2019-01-14 20:25:52 UTC
Size:
66.46 KB
patch
obsolete
>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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 675060
:
560604
|
561152
|
561154
|
561156
|
561158
|
576818
|
576820
|
589470