On Fri, Aug 29, 2003 at 01:44:38PM +0200, Oskar Eyb wrote:
> what available patches (is there any?) for SMTP-Auth to remote servers
> works with qmail-ldap?
I have an ugly hacked up qmail-remote for that here...
DISCLAIMER: I didn't touch it in ags, it is quick and dirty and
ugly, but it works for me.
you need a smtproutesentry like this:
:smtp.whatever.de user pass
where user and pass are the base64-encoded username and password.
diff qmail-1.03/Makefile qmail-local/Makefile
--- qmail-1.03/Makefile Mon Jun 15 12:52:55 1998
+++ qmail-local/Makefile Fri May 17 12:44:50 2002
@@ -1,6 +1,9 @@
# Don't edit Makefile! Use conf-* for configuration.
SHELL=/bin/sh
+TLSON=-DTLS
+#TLSINCLUDES=-I/usr/local/include
+TLSLIBS=-lssl -lcrypto
default: it
@@ -1446,8 +1449,8 @@
timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
- str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
-
+ str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` ${TLSLIBS}
+
qmail-remote.0: \
qmail-remote.8
nroff -man qmail-remote.8 > qmail-remote.0
@@ -1458,7 +1461,7 @@
alloc.h quote.h ip.h ipalloc.h ip.h gen_alloc.h ipme.h ip.h ipalloc.h \
gen_alloc.h gen_allocdefs.h str.h now.h datetime.h exit.h constmap.h \
tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h
- ./compile qmail-remote.c
+ ./compile ${TLSON} ${TLSINCLUDES} qmail-remote.c
qmail-rspawn: \
load qmail-rspawn.o spawn.o tcpto_clean.o now.o coe.o sig.a open.a \
diff qmail-1.03/ipalloc.h qmail-local/ipalloc.h
--- qmail-1.03/ipalloc.h Mon Jun 15 12:52:55 1998
+++ qmail-local/ipalloc.h Fri May 17 12:48:31 2002
@@ -3,7 +3,11 @@
#include "ip.h"
+#ifdef TLS
+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 qmail-1.03/qmail-remote.c qmail-local/qmail-remote.c
--- qmail-1.03/qmail-remote.c Mon Jun 15 12:52:55 1998
+++ qmail-local/qmail-remote.c Fri May 17 15:57:53 2002
@@ -1,7 +1,10 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <openssl/ssl.h>
#include "sig.h"
#include "stralloc.h"
#include "substdio.h"
@@ -26,13 +29,15 @@
#include "tcpto.h"
#include "readwrite.h"
#include "timeoutconn.h"
-#include "timeoutread.h"
-#include "timeoutwrite.h"
+
+
+SSL *ssl = 0;
+char *fqdn = 0;
+
#define HUGESMTPTEXT 5000
-#define PORT_SMTP 25 /* silly rabbit, /etc/services is for users */
-unsigned long port = PORT_SMTP;
+unsigned long smtp_port = 25; /* silly rabbit, /etc/services is for users */
GEN_ALLOC_typedef(saa,stralloc,sa,len,a)
GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus)
@@ -43,6 +48,8 @@
struct constmap maproutes;
stralloc host = {0};
stralloc sender = {0};
+stralloc auth_smtp_user = {0};
+stralloc auth_smtp_pass = {0};
saa reciplist = {0};
@@ -70,6 +77,10 @@
Unable to switch to home directory. (#4.3.0)\n"); zerodie(); }
void temp_control() { out("Z\
Unable to read control files. (#4.3.0)\n"); zerodie(); }
+#ifdef MXPS
+void temp_proto() { out("Z\
+recipient did not talk proper QMTP (#4.3.0)\n"); zerodie(); }
+#endif
void perm_partialline() { out("D\
SMTP cannot transfer messages with partial final lines. (#5.6.2)\n"); zerodie(); }
void perm_usage() { out("D\
@@ -107,10 +118,41 @@
int smtpfd;
int timeout = 1200;
+
+int flagtimedout = 0;
+void sigalrm()
+{
+ flagtimedout = 1;
+}
+int ssl_timeoutread(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
+{
+ int r; int saveerrno;
+ if (flagtimedout) { errno = error_timeout; return -1; }
+ alarm(timeout);
+ if (ssl) r = SSL_read(ssl,buf,n); else r = read(fd,buf,n);
+ saveerrno = errno;
+ alarm(0);
+ if (flagtimedout) { errno = error_timeout; return -1; }
+ errno = saveerrno;
+ return r;
+}
+int ssl_timeoutwrite(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
+{
+ int r; int saveerrno;
+ if (flagtimedout) { errno = error_timeout; return -1; }
+ alarm(timeout);
+ if (ssl) r = SSL_write(ssl,buf,n); else r = write(fd,buf,n);
+ saveerrno = errno;
+ alarm(0);
+ if (flagtimedout) { errno = error_timeout; return -1; }
+ errno = saveerrno;
+ return r;
+}
+
int saferead(fd,buf,len) int fd; char *buf; int len;
{
int r;
- r = timeoutread(timeout,smtpfd,buf,len);
+ r = ssl_timeoutread(timeout,smtpfd,buf,len);
if (r <= 0) dropped();
return r;
}
@@ -117,14 +159,13 @@
int safewrite(fd,buf,len) int fd; char *buf; int len;
{
int r;
- r = timeoutwrite(timeout,smtpfd,buf,len);
+ r = ssl_timeoutwrite(timeout,smtpfd,buf,len);
if (r <= 0) dropped();
return r;
}
-
char inbuf[1024];
-substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf);
char smtptobuf[1024];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf);
substdio smtpto = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof smtptobuf);
char smtpfrombuf[128];
substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf);
@@ -179,6 +220,7 @@
char *prepend;
char *append;
{
+/* TAG */
substdio_putsflush(&smtpto,"QUIT\r\n");
/* waiting for remote side is just too ridiculous */
out(prepend);
@@ -221,19 +263,128 @@
unsigned long code;
int flagbother;
int i;
-
+ int needtlsauth = 0;
+ SSL_CTX *ctx;
+ int saveerrno, r;
+ stralloc servercert = {0};
+ struct stat st;
+
+ if( fqdn && *fqdn ) {
+ if(!stralloc_copys(&servercert, "control/tlshosts/")) temp_nomem();
+ if(!stralloc_cats(&servercert, fqdn)) temp_nomem();
+ if(!stralloc_cats(&servercert, ".pem")) temp_nomem();
+ if(!stralloc_0(&servercert)) temp_nomem();
+ if (stat(servercert.s,&st) == 0) needtlsauth = 1;
+ }
+
if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
- substdio_puts(&smtpto,"HELO ");
+ substdio_puts(&smtpto,"EHLO ");
substdio_put(&smtpto,helohost.s,helohost.len);
substdio_puts(&smtpto,"\r\n");
substdio_flush(&smtpto);
- if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
+ if (smtpcode() != 250) quit("ZConnected to "," but no ESMTP available");
+ i = 0;
+ while((i += str_chr(smtptext.s+i,'\n') + 1) && (i+12 < smtptext.len) &&
+ str_diffn(smtptext.s+i+4,"STARTTLS\n",9));
+ if (i+12 < smtptext.len)
+ {
+ substdio_puts(&smtpto,"STARTTLS\r\n");
+ substdio_flush(&smtpto);
+ if (smtpcode() == 220)
+ {
+ SSLeay_add_ssl_algorithms();
+ if(!(ctx=SSL_CTX_new(SSLv23_client_method())))
+ {out("ZTLS not available: error initializing ctx\n");
+ out("\n");
+ zerodie();}
+
+ SSL_CTX_use_RSAPrivateKey_file(ctx, "control/cert.pem", SSL_FILETYPE_PEM);
+ SSL_CTX_use_certificate_file(ctx, "control/cert.pem", SSL_FILETYPE_PEM);
+ /*SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);*/
+
+ if (needtlsauth){
+ if (!SSL_CTX_load_verify_locations(ctx, servercert.s, NULL))
+ {out("ZTLS unable to load "); out(servercert.s); out("\n");
+ zerodie();}
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+ }
- substdio_puts(&smtpto,"MAIL FROM:<");
- substdio_put(&smtpto,sender.s,sender.len);
- substdio_puts(&smtpto,">\r\n");
- substdio_flush(&smtpto);
+ if(!(ssl=SSL_new(ctx)))
+ {out("ZTLS not available: error initializing ssl");
+ out("\n");
+ zerodie();}
+ SSL_set_fd(ssl,smtpfd);
+
+ alarm(timeout);
+ r = SSL_connect(ssl); saveerrno = errno;
+ alarm(0);
+ if (flagtimedout)
+ {out("ZTLS not available: connect timed out\n");
+ zerodie();}
+ errno = saveerrno;
+ if (r<=0)
+ {if (needtlsauth && (r=SSL_get_verify_result(ssl)) != X509_V_OK)
+ {out("ZTLS unable to verify server with ");
+ out(servercert.s); out(": ");
+ out(X509_verify_cert_error_string(r)); out("\n");}
+ else
+ out("ZTLS not available: connect failed\n");
+ zerodie();}
+ if (needtlsauth)
+ /* should also check alternate names */
+ {char commonName[256];
+ X509_NAME_get_text_by_NID(X509_get_subject_name(
+ SSL_get_peer_certificate(ssl)),
+ NID_commonName, commonName, 256);
+ if (case_diffs(fqdn,commonName)){
+ out("ZTLS connection to "); out(fqdn);
+ out(" wanted, certificate for "); out(commonName);
+ out(" received\n");
+ zerodie();}
+ }
+
+ substdio_puts(&smtpto,"EHLO ");
+ substdio_put(&smtpto,helohost.s,helohost.len);
+ substdio_puts(&smtpto,"\r\n");
+ substdio_flush(&smtpto);
+
+ if (smtpcode() != 250)
+ {
+ quit("ZTLS connected to "," but my name was rejected");
+ }
+
+ }
+ }
+ if ((!ssl) && needtlsauth)
+ {out("ZNo TLS achieved while "); out(servercert.s); out(" exists.\n");
+ zerodie();}
+
+ i = 0;
+ while((i += str_chr(smtptext.s+i,'\n') + 1) && (i+14 < smtptext.len) &&
+ str_diffn(smtptext.s+i+4,"AUTH LOGIN",10));
+ if ((i+14 < smtptext.len) && auth_smtp_user.len && auth_smtp_pass.len) {
+ substdio_puts(&smtpto,"AUTH LOGIN\r\n");
+ substdio_flush(&smtpto);
+ if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected
(AUTH LOGIN)");
+ substdio_put(&smtpto,auth_smtp_user.s,auth_smtp_user.len);
+ substdio_puts(&smtpto,"\r\n");
+ substdio_flush(&smtpto);
+ if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected
(username)");
+ substdio_put(&smtpto,auth_smtp_pass.s,auth_smtp_pass.len);
+ substdio_puts(&smtpto,"\r\n");
+ substdio_flush(&smtpto);
+ if (smtpcode() != 235) quit("ZConnected to "," but authentication was rejected
(password)");
+ substdio_puts(&smtpto,"MAIL FROM:<");
+ substdio_put(&smtpto,sender.s,sender.len);
+ substdio_puts(&smtpto,"> AUTH=<");
+ substdio_put(&smtpto,sender.s,sender.len);
+ substdio_puts(&smtpto,">\r\n");
+ substdio_flush(&smtpto);
+ } else {
+ quit("ZConnected to","but no SMTP AUTH support detected.");
+ }
+
code = smtpcode();
if (code >= 500) quit("DConnected to "," but sender was rejected");
if (code >= 400) quit("ZConnected to "," but sender was rejected");
@@ -272,7 +423,7 @@
if (code >= 400) quit("Z"," failed after I sent the message");
quit("K"," accepted message");
}
-
+
stralloc canonhost = {0};
stralloc canonbox = {0};
@@ -331,7 +482,8 @@
char **argv;
{
static ipalloc ip = {0};
- int i;
+ int i, j;
+ int tcpnodelay = 1;
unsigned long random;
char **recips;
unsigned long prefme;
@@ -338,7 +490,8 @@
int flagallaliases;
int flagalias;
char *relayhost;
-
+
+ sig_alarmcatch(sigalrm);
sig_pipeignore();
if (argc < 4) perm_usage();
if (chdir(auto_qmail) == -1) temp_chdir();
@@ -346,6 +499,8 @@
if (!stralloc_copys(&host,argv[1])) temp_nomem();
+ if (!stralloc_copys(&auth_smtp_user,"")) temp_nomem();
+ if (!stralloc_copys(&auth_smtp_pass,"")) temp_nomem();
relayhost = 0;
for (i = 0;i <= host.len;++i)
@@ -355,9 +510,19 @@
if (relayhost && !*relayhost) relayhost = 0;
if (relayhost) {
+ i = str_chr(relayhost,' ');
+ if (relayhost[i]) {
+ j = str_chr(relayhost + i + 1,' ');
+ if (relayhost[j]) {
+ relayhost[i] = 0;
+ relayhost[i + j + 1] = 0;
+ if (!stralloc_copys(&auth_smtp_user,relayhost + i + 1)) temp_nomem();
+ if (!stralloc_copys(&auth_smtp_pass,relayhost + i + j + 2)) temp_nomem();
+ }
+ }
i = str_chr(relayhost,':');
if (relayhost[i]) {
- scan_ulong(relayhost + i + 1,&port);
+ scan_ulong(relayhost + i + 1,&smtp_port);
relayhost[i] = 0;
}
if (!stralloc_copys(&host,relayhost)) temp_nomem();
@@ -413,10 +578,14 @@
smtpfd = socket(AF_INET,SOCK_STREAM,0);
if (smtpfd == -1) temp_oserr();
-
- if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
+
+ /* performace hack to send TCP ACK's without delay */
+ setsockopt(smtpfd, IPPROTO_TCP, TCP_NODELAY, &tcpnodelay, sizeof(tcpnodelay));
+
+ if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) smtp_port,timeoutconnect) ==
0) {
tcpto_err(&ip.ix[i].ip,0);
partner = ip.ix[i].ip;
+/* fqdn = ip.ix[i].fqdn; */
smtp(); /* does not return */
}
tcpto_err(&ip.ix[i].ip,errno == error_timeout);
--
http://2suck.net/hhwl.html - http://www.bsws.de/
Unix is very simple, but it takes a genius to understand the simplicity.
(Dennis Ritchie)