--- 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: */ + 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);