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)

Reply via email to