--- 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