--- qmail-remote.c.orig  1998-06-15
+++ qmail-remote.c       2007-03-21
--- .././qmail-1.03/qmail-remote.c	Mon Jun 15 12:53:16 1998
+++ ../qmail-1.03.2418/qmail-remote.c	Wed Mar 21 10:33:29 2007
@@ -28,6 +28,7 @@
 #include "timeoutconn.h"
 #include "timeoutread.h"
 #include "timeoutwrite.h"
+#include "base64.h"
 
 #define HUGESMTPTEXT 5000
 
@@ -44,6 +45,14 @@
 stralloc host = {0};
 stralloc sender = {0};
 
+stralloc authsenders = {0};
+struct constmap mapauthsenders;
+stralloc user = {0};
+stralloc pass = {0};
+stralloc auth = {0};
+stralloc plain = {0};
+char *authsender;
+
 saa reciplist = {0};
 
 struct ip_address partner;
@@ -86,6 +95,12 @@
 it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
 zerodie(); }
 
+void err_authprot() {
+  out("Kno supported AUTH method found, continuing without authentication.\n");
+  zero();
+  substdio_flush(subfdoutsmall);
+}
+
 void outhost()
 {
   char x[IPFMT];
@@ -192,23 +207,39 @@
 void blast()
 {
   int r;
+  int i;
+  int o;
   char ch;
+  char in[4096];
+  char out[4096*2+1];
+  int sol;
 
-  for (;;) {
-    r = substdio_get(&ssin,&ch,1);
+  for (sol = 1;;) {
+    r = substdio_get(&ssin,in,sizeof in);
     if (r == 0) break;
     if (r == -1) temp_read();
-    if (ch == '.')
-      substdio_put(&smtpto,".",1);
-    while (ch != '\n') {
-      substdio_put(&smtpto,&ch,1);
-      r = substdio_get(&ssin,&ch,1);
-      if (r == 0) perm_partialline();
-      if (r == -1) temp_read();
+
+    for (i = o = 0; i < r; ) {
+      if (sol && in[i] == '.') {
+	out[o++] = '.';
+	out[o++] = in[i++];
+      }
+      sol = 0;
+      while (i < r) {
+	if (in[i] == '\n') {
+	  sol = 1;
+	  ++i;
+	  out[o++] = '\r';
+	  out[o++] = '\n';
+	  break;
+	}
+	out[o++] = in[i++];
+      }
     }
-    substdio_put(&smtpto,"\r\n",2);
+    substdio_put(&smtpto,out,o);
   }
  
+  if (!sol) perm_partialline();
   flagcritical = 1;
   substdio_put(&smtpto,".\r\n",3);
   substdio_flush(&smtpto);
@@ -216,24 +247,144 @@
 
 stralloc recip = {0};
 
+void mailfrom()
+{
+  substdio_puts(&smtpto,"MAIL FROM:<");
+  substdio_put(&smtpto,sender.s,sender.len);
+  substdio_puts(&smtpto,">\r\n");
+  substdio_flush(&smtpto);
+}
+
+stralloc xuser = {0};
+
+int xtext(sa,s,len)
+stralloc *sa;
+char *s;
+int len;
+{
+  int i;
+
+  if(!stralloc_copys(sa,"")) temp_nomem();
+
+  for (i = 0; i < len; i++) {
+    if (s[i] == '+') {
+      if (!stralloc_cats(sa,"+3D")) temp_nomem();
+    } else if (s[i] == '=') {
+        if (!stralloc_cats(sa,"+2B")) temp_nomem();
+    } else if ((int) s[i] < 33 || (int) s[i] > 126) {
+        if (!stralloc_cats(sa,"+3F")) temp_nomem(); /* ok. not correct */
+    } else if (!stralloc_catb(sa,s+i,1)) {
+        temp_nomem();
+    }
+  }
+
+  return sa->len;
+}
+
+void mailfrom_plain()
+{
+  substdio_puts(&smtpto,"AUTH PLAIN\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (AUTH PLAIN).");
+
+  if(!stralloc_cat(&plain,&sender)) temp_nomem(); /* Mail From: <authorize-id> */
+  if(!stralloc_0(&plain)) temp_nomem();
+  if(!stralloc_cat(&plain,&user)) temp_nomem(); /* user-id */
+  if(!stralloc_0(&plain)) temp_nomem();
+  if(!stralloc_cat(&plain,&pass)) temp_nomem(); /* password */
+  if (b64encode(&plain,&auth)) quit("ZConnected to "," but unable to base64encode (plain).");
+  substdio_put(&smtpto,auth.s,auth.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 235) quit("ZConnected to "," but authentication was rejected (plain).");
+
+  if (!xtext(&xuser,user.s,user.len)) temp_nomem();
+  substdio_puts(&smtpto,"MAIL FROM:<");
+  substdio_put(&smtpto,sender.s,sender.len);
+  substdio_puts(&smtpto,"> AUTH=");
+  substdio_put(&smtpto,xuser.s,xuser.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+}
+
+void mailfrom_login()
+{
+  substdio_puts(&smtpto,"AUTH LOGIN\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (AUTH LOGIN).");
+
+  if (!stralloc_copys(&auth,"")) temp_nomem();
+  if (b64encode(&user,&auth)) quit("ZConnected to "," but unable to base64encode user.");
+  substdio_put(&smtpto,auth.s,auth.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (username).");
+
+  if (!stralloc_copys(&auth,"")) temp_nomem();
+  if (b64encode(&pass,&auth)) quit("ZConnected to "," but unable to base64encode pass.");
+  substdio_put(&smtpto,auth.s,auth.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 235) quit("ZConnected to "," but authentication was rejected (password)");
+
+  if (!xtext(&xuser,user.s,user.len)) temp_nomem();
+  substdio_puts(&smtpto,"MAIL FROM:<");
+  substdio_put(&smtpto,sender.s,sender.len);
+  substdio_puts(&smtpto,"> AUTH=");
+  substdio_put(&smtpto,xuser.s,xuser.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+}
+
+void smtp_auth()
+{
+  int i = 0;
+  int j;
+  while ((i += str_chr(smtptext.s+i,'\n') + 1) &&
+         (i+8 < smtptext.len) &&
+         str_diffn(smtptext.s+i+4,"AUTH",4)); {
+    j = str_chr(smtptext.s+i+8,'L');		/* AUTH LOGIN */
+    if (j > 0) 
+      if (case_starts(smtptext.s+i+8+j,"LOGIN")) { mailfrom_login(); return; }
+    j = str_chr(smtptext.s+i+8,'P');		/* AUTH PLAIN */
+    if (j > 0) 
+      if (case_starts(smtptext.s+i+8+j,"PLAIN")) { mailfrom_plain(); return; }
+    err_authprot();
+    mailfrom();
+  }
+}
+
 void smtp()
 {
   unsigned long code;
   int flagbother;
   int i;
  
-  if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
+  code = smtpcode();
+  if (code >= 400) return;	/* try next MX */
+  if (code != 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");
- 
-  substdio_puts(&smtpto,"MAIL FROM:<");
-  substdio_put(&smtpto,sender.s,sender.len);
-  substdio_puts(&smtpto,">\r\n");
-  substdio_flush(&smtpto);
+
+  if (smtpcode() != 250) {
+    substdio_puts(&smtpto,"HELO ");
+    substdio_put(&smtpto,helohost.s,helohost.len);
+    substdio_puts(&smtpto,"\r\n");
+    substdio_flush(&smtpto);
+    code = smtpcode();
+    authsender = 0;
+    if (code >= 500) quit("DConnected to "," but my name was rejected");
+    if (code != 250) quit("ZConnected to "," but my name was rejected");
+  }
+
+  if (authsender)
+    smtp_auth();
+  else 
+    mailfrom();
+
   code = smtpcode();
   if (code >= 500) quit("DConnected to "," but sender was rejected");
   if (code >= 400) quit("ZConnected to "," but sender was rejected");
@@ -324,6 +475,15 @@
     case 1:
       if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
   }
+  
+  switch(control_readfile(&authsenders,"control/authsenders",0)) {
+    case -1:
+       temp_control();
+    case 0:
+      if (!constmap_init(&mapauthsenders,"",0,1)) temp_nomem(); break;
+    case 1:
+      if (!constmap_init(&mapauthsenders,authsenders.s,authsenders.len,1)) temp_nomem(); break;
+  }
 }
 
 void main(argc,argv)
@@ -331,41 +491,74 @@
 char **argv;
 {
   static ipalloc ip = {0};
-  int i;
+  int i, j;
   unsigned long random;
   char **recips;
   unsigned long prefme;
   int flagallaliases;
   int flagalias;
   char *relayhost;
- 
+   
   sig_pipeignore();
   if (argc < 4) perm_usage();
   if (chdir(auto_qmail) == -1) temp_chdir();
   getcontrols();
  
- 
   if (!stralloc_copys(&host,argv[1])) temp_nomem();
- 
+
+  authsender = 0;
   relayhost = 0;
-  for (i = 0;i <= host.len;++i)
-    if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
-      if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
+
+  addrmangle(&sender,argv[2],&flagalias,0);
+
+  for (i = 0;i <= sender.len;++i)
+    if ((i == 0) || (i == sender.len) || (sender.s[i] == '.') || (sender.s[i] == '@'))
+      if (authsender = constmap(&mapauthsenders,sender.s + i,sender.len - i))
         break;
-  if (relayhost && !*relayhost) relayhost = 0;
- 
-  if (relayhost) {
-    i = str_chr(relayhost,':');
-    if (relayhost[i]) {
-      scan_ulong(relayhost + i + 1,&port);
-      relayhost[i] = 0;
+
+  if (authsender && !*authsender) authsender = 0;
+
+  if (authsender) {
+    i = str_chr(authsender,'|');
+    if (authsender[i]) {
+      j = str_chr(authsender + i + 1,'|');
+      if (authsender[j]) {
+        authsender[i] = 0;
+        authsender[i + j + 1] = 0;
+        if (!stralloc_copys(&user,"")) temp_nomem();
+        if (!stralloc_copys(&user,authsender + i + 1)) temp_nomem();
+        if (!stralloc_copys(&pass,"")) temp_nomem();
+        if (!stralloc_copys(&pass,authsender + i + j + 2)) temp_nomem();
+      }
+    }
+    i = str_chr(authsender,':');
+    if (authsender[i]) {
+      scan_ulong(authsender + i + 1,&port);
+      authsender[i] = 0;
     }
-    if (!stralloc_copys(&host,relayhost)) temp_nomem();
-  }
 
+    if (!stralloc_copys(&relayhost,authsender)) temp_nomem();
+    if (!stralloc_copys(&host,authsender)) temp_nomem();
+
+  }
+  else {					/* default smtproutes */
+    for (i = 0;i <= host.len;++i)
+      if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
+        if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
+          break;
+
+    if (relayhost && !*relayhost) relayhost = 0;
+
+    if (relayhost) {
+      i = str_chr(relayhost,':');
+      if (relayhost[i]) {
+        scan_ulong(relayhost + i + 1,&port);
+        relayhost[i] = 0;
+      }
+      if (!stralloc_copys(&host,relayhost)) temp_nomem();
+    }
+  }
 
-  addrmangle(&sender,argv[2],&flagalias,0);
- 
   if (!saa_readyplus(&reciplist,0)) temp_nomem();
   if (ipme_init() != 1) temp_oserr();
  
@@ -417,7 +610,7 @@
     if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
       tcpto_err(&ip.ix[i].ip,0);
       partner = ip.ix[i].ip;
-      smtp(); /* does not return */
+      smtp(); /* read THOUGHTS; section 6 */
     }
     tcpto_err(&ip.ix[i].ip,errno == error_timeout);
     close(smtpfd);


syntax highlighted by Code2HTML, v. 0.9.1