--- qmail-smtpd.c.orig 1998-06-15
+++ qmail-smtpd.c 2007-03-21
--- .././qmail-1.03/qmail-smtpd.c Mon Jun 15 12:53:16 1998
+++ ../qmail-1.03.2418/qmail-smtpd.c Sat Jan 6 21:33:00 2007
@@ -1,4 +1,3 @@
-#include "sig.h"
#include "readwrite.h"
#include "stralloc.h"
#include "substdio.h"
@@ -20,14 +19,52 @@
#include "now.h"
#include "exit.h"
#include "rcpthosts.h"
+#include "recipients.h"
+#include "mfrules.h"
+#include "ucspitls.h"
#include "timeoutread.h"
#include "timeoutwrite.h"
#include "commands.h"
+#include "cdb.h"
+#include "dns.h"
+#include "wait.h"
+
+#define RELAYMAILFROM
+#define REQBRACKETS
+#define AUTHSLEEP 5
+
+#define MIMETYPE_LEN 9
+#define LOADER_LEN 5
+#define FDLOG 2
#define MAXHOPS 100
-unsigned int databytes = 0;
+unsigned long databytes = 0;
int timeout = 1200;
+char *reply554;
+char *replymav;
+
+/* this file is too long -------------------------------------- logging */
+
+char sslogbuf[512];
+substdio sslog = SUBSTDIO_FDBUF(write,FDLOG,sslogbuf,sizeof(sslogbuf));
+void logc(s) char *s; { if(substdio_puts(&sslog,s) == -1) _exit(1); } /* single string */
+void logp(s1) char *s1; { logc(" P:"); logc(s1); } /* protocol */
+void logh(s1,s2,s3) char *s1, *s2, *s3; { logc(" S:"); logc(s1); logc(":"); logc(s2); logc(" H:"); logc(s3); } /* host */
+void logf(s) char *s; { logc(" F:"); logc(s); } /* mailfrom */
+void logt(s) char *s; { logc(" T:"); logc(s); } /* rcptto */
+void logi(s) char *s; { logc(" '"); logc(s); logc("'"); } /* information */
+void logn(s) char *s; { if(substdio_puts(&sslog,s) == -1) _exit(1); if(substdio_flush(&sslog) == -1) _exit(1); } /* end */
+
+void loga(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7;
+ { logc(s1); logc(s2), logh(s3,s4,s5); logi(s7); logc(" ?="); logi(s6); logn("\n"); }
+void logb(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7;
+ { logc(s1); logc(s2), logh(s3,s4,s5); logi(s7); logc(" !="); logi(s6); logn("\n"); }
+void logs(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7;
+ { logc(s1); logp(s2); logh(s3,s4,s5); logf(s6); logt(s7); logn("\n"); }
+void logd(s1,s2,s3,s4,s5,s6,s7,s8) char *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8;
+ { logc(s1); logp(s2); logh(s3,s4,s5); logf(s6); logt(s7); logi(s8); logn("\n"); }
+
int safewrite(fd,buf,len) int fd; char *buf; int len;
{
int r;
@@ -42,15 +79,15 @@
void flush() { substdio_flush(&ssout); }
void out(s) char *s; { substdio_puts(&ssout,s); }
+/* this file is too long -------------------------------------- Exit codes */
+
void die_read() { _exit(1); }
void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
+void die_starttls() { out("454 TLS not available due to temporary reason (#5.7.3)\r\n"); flush(); _exit(1); }
void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
-
-void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
-void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
@@ -58,7 +95,79 @@
void err_noop() { out("250 ok\r\n"); }
void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
+void err_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); }
+void err_helo(s1,s2,s3,s4,s5,s6,s7,s8) char *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8; {
+ out("550 sorry, invalid HELO/EHLO greeting (#5.7.1)\r\n");
+ logd(s1,s2,s3,s4,s5,s6,s7,s8);
+ return;
+ }
+void err_bmf(s1,s2,s3,s4,s5,s6,s7,s8) char *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8; {
+ out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n");
+ logd(s1,s2,s3,s4,s5,s6,s7,s8);
+ return;
+ }
+void err_mav(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7; {
+ out("553 sorry, invalid sender address specified ");
+ if (replymav) out(replymav);
+ out(" (#5.7.1)\r\n");
+ logs(s1,s2,s3,s4,s5,s6,s7);
+ return;
+ }
+void err_nogateway(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7; {
+ out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n");
+ logs(s1,s2,s3,s4,s5,s6,s7);
+ return;
+ }
+void err_mfdns(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7; {
+ out("553 sorry, your envelope sender must exist (#5.7.1)\r\n");
+ logs(s1,s2,s3,s4,s5,s6,s7);
+ return;
+ }
+void err_rcpts(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7; {
+ out("550 sorry, too many recipients (#5.7.1)\r\n");
+ logs(s1,s2,s3,s4,s5,s6,s7);
+ return;
+ }
+void err_brcptto(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7; {
+ out("550 sorry, your envelope recipient is in my badrcptto list (#5.7.1)\r\n");
+ logs(s1,s2,s3,s4,s5,s6,s7);
+ return;
+ }
+void err_recipient(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7; {
+ if (env_get("RECIPIENTS450"))
+ out("450 sorry, mailbox currently unavailable (#4.2.1)\r\n");
+ else
+ out("550 sorry, no mailbox by that name (#5.7.1)\r\n");
+ logs(s1,s2,s3,s4,s5,s6,s7);
+ return;
+ }
+void err_data(s1,s2,s3,s4,s5,s6,s7,s8) char *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8; {
+ out("554 sorry, invalid message content ");
+ if (reply554) out(reply554);
+ out(" (#5.3.2)\r\n");
+ logd(s1,s2,s3,s4,s5,s6,s7,s8);
+ return;
+ }
+
+int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
+int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
+int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
+int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; }
+void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); }
+void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); }
+int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; }
+int err_authabrt() { out("501 auth exchange canceled (#5.0.0)\r\n"); return -1; }
+int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
+void err_authfail(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7; {
+ out("535 authentication failed (#5.7.1)\r\n"); loga(s1,s2,s3,s4,s5,s6,s7); }
+void err_authreq(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7; {
+ out("535 authentication required (#5.7.1)\r\n"); logs(s1,s2,s3,s4,s5,s6,s7); }
+int err_starttls() { out("454 TLS not available due to temporary reason (#5.7.3)\r\n"); return -1; }
+void err_tlsreq(s1,s2,s3,s4,s5,s6,s7) char *s1, *s2, *s3, *s4, *s5, *s6, *s7; {
+ out("535 STARTTLS required (#5.7.1)\r\n"); logs(s1,s2,s3,s4,s5,s6,s7); }
+
+/* this file is too long -------------------------------------- Greeting */
stralloc greeting = {0};
@@ -82,21 +191,99 @@
char *local;
char *relayclient;
+stralloc protocol = {0};
stralloc helohost = {0};
char *fakehelo; /* pointer into helohost, or 0 */
+stralloc tlsinfo = {0};
+
+char *helocheck;
+int flagbadhelo;
+int flagdnshelo;
+int seenhelo = 0;
+
+char *badmailcond;
+char *badhelocond;
-void dohelo(arg) char *arg; {
+void dohelo(arg) char *arg;
+{
if (!stralloc_copys(&helohost,arg)) die_nomem();
if (!stralloc_0(&helohost)) die_nomem();
fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
+ if (helocheck) {
+ if (str_len(helocheck) == 1) {
+ switch (*helocheck) {
+ case '=': flagbadhelo = bhelocheck(); if (fakehelo) { flagdnshelo = 1; badhelocond = "="; } break;
+ case 'A': flagdnshelo = dnsq(helohost.s,"A"); badhelocond = "A"; flagbadhelo = bhelocheck(); break;
+ case 'M': flagdnshelo = dnsq(helohost.s,"M"); badhelocond = "M"; flagbadhelo = bhelocheck(); break;
+ case '.': flagbadhelo = bhelocheck(); if (!str_len(arg)) flagbadhelo = -2; break;
+ case '!': if (!str_len(arg)) flagbadhelo = -2; break;
+ }
+ }
+ else
+ flagbadhelo = bhelocheck();
+ }
}
int liphostok = 0;
stralloc liphost = {0};
+
int bmfok = 0;
stralloc bmf = {0};
struct constmap mapbmf;
+int brtok= 0;
+stralloc brt = {0};
+struct constmap mapbrt;
+
+int badhelook = 0;
+stralloc badhelo = {0};
+struct constmap mapbadhelo;
+
+#ifdef RELAYMAILFROM
+int relaymailfromok = 0;
+stralloc relaymailfrom = {0};
+struct constmap maprmf;
+#endif
+
+static int fdbmt;
+int flagmimetype = 0;
+
+static int fdblt;
+int flagloadertype = 0;
+char *badloaderinit;
+
+static int fdmav;
+int flagmav = 0;
+int localmf = 0;
+int flaglocal = -1;
+char *localmfcheck;
+
+char *mfdnscheck;
+char *qhpsi;
+char *base64;
+
+int maxrcptcount = 0;
+int flagerrcpts = 0;
+
+int tarpitcount = 0;
+int tarpitdelay = 5;
+
+unsigned int greetdelay = 0;
+
+char *auth;
+char *reqauth;
+int smtpauth = 0;
+int seenauth = 0;
+
+int starttls = 0;
+int seenttls = 0;
+char *reqttls;
+char *tlsversion;
+char *cipher;
+char *cipherperm;
+char *cipherused;
+char *clientdn;
+
void setup()
{
char *x;
@@ -111,17 +298,24 @@
if (timeout <= 0) timeout = 1;
if (rcpthosts_init() == -1) die_control();
+ if (recipients_init() == -1) die_control();
bmfok = control_readfile(&bmf,"control/badmailfrom",0);
if (bmfok == -1) die_control();
if (bmfok)
if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
+ brtok = control_readfile(&brt,"control/badrcptto",0);
+ if (brtok == -1) die_control();
+ if (brtok)
+ if (!constmap_init(&mapbrt,brt.s,brt.len,0)) die_nomem();
+
if (control_readint(&databytes,"control/databytes") == -1) die_control();
x = env_get("DATABYTES");
if (x) { scan_ulong(x,&u); databytes = u; }
if (!(databytes + 1)) --databytes;
-
+
+ if (!stralloc_copys(&protocol,"ESMTP")) die_nomem(); /* RFC 3848 */
remoteip = env_get("TCPREMOTEIP");
if (!remoteip) remoteip = "unknown";
local = env_get("TCPLOCALHOST");
@@ -131,11 +325,93 @@
if (!remotehost) remotehost = "unknown";
remoteinfo = env_get("TCPREMOTEINFO");
relayclient = env_get("RELAYCLIENT");
- dohelo(remotehost);
+
+ mfdnscheck = env_get("MFDNSCHECK");
+
+ x = env_get("MAXRECIPIENTS");
+ if (x) { scan_ulong(x,&u); maxrcptcount = u; };
+ if (!(maxrcptcount + 1)) --maxrcptcount;
+
+ helocheck = env_get("HELOCHECK");
+ if (helocheck) {
+ badhelook = control_readfile(&badhelo,"control/badhelo",0);
+ if (badhelook == -1) die_control();
+ if (badhelook)
+ if (!constmap_init(&mapbadhelo,badhelo.s,badhelo.len,0)) die_nomem();
+ }
+
+ if (control_readint(&tarpitcount,"control/tarpitcount") == -1) die_control();
+ if (tarpitcount < 0) tarpitcount = 0;
+ x = env_get("TARPITCOUNT");
+ if (x) { scan_ulong(x,&u); tarpitcount = u; };
+ if (control_readint(&tarpitdelay,"control/tarpitdelay") == -1) die_control();
+ if (tarpitdelay < 0) tarpitdelay = 0;
+ x = env_get("TARPITDELAY");
+ if (x) { scan_ulong(x,&u); tarpitdelay = u; };
+ x = env_get("GREETDELAY");
+ if (x) { scan_ulong(x,&u); greetdelay = u; };
+
+ localmfcheck = env_get("LOCALMFCHECK");
+ if (localmfcheck) {
+ localmf = 1;
+ replymav = env_get("REPLYMAV");
+ if (str_len(localmfcheck) == 1 && *localmfcheck == '!') {
+ localmf = 2;
+ fdmav = open_read("control/mailfromrules.cdb");
+ if (fdmav == -1 ) localmf = 1;
+ }
+ }
+
+ if (env_get("BADMIMETYPE")) {
+ flagmimetype = 1;
+ fdbmt = open_read("control/badmimetypes.cdb");
+ if (fdbmt == -1 ) flagmimetype = 0;
+ }
+
+ badloaderinit = env_get("BADLOADERTYPE");
+ if (badloaderinit) {
+ if (str_len(badloaderinit) == 1) {
+ flagloadertype = 1;
+ fdblt = open_read("control/badloadertypes.cdb");
+ if (fdblt == -1 ) flagloadertype = 0;
+ }
+ }
+
+ base64 = env_get("BASE64");
+ reply554 = env_get("REPLY554");
+ qhpsi = env_get("QHPSI");
+ if (!qhpsi) qhpsi = "unknown";
+
+ auth = env_get("SMTPAUTH");
+ if (auth) {
+ smtpauth = 2;
+ if (case_starts(auth,"cram") || case_starts(auth,"CRAM")) smtpauth = 3;
+ reqauth = env_get("REQUIREAUTH");
+ }
+
+ if(env_get("UCSPITLS")) starttls = 1;
+ if(starttls) reqttls = env_get("REQUIRETLS");
+
+#ifdef RELAYMAILFROM
+ if (!relayclient) {
+ relaymailfromok = control_readfile(&relaymailfrom,"control/relaymailfrom",0);
+ if (relaymailfromok == -1) die_control();
+ if (relaymailfromok)
+ if (!constmap_init(&maprmf,relaymailfrom.s,relaymailfrom.len,0)) die_nomem();
+ }
+#endif
+
+ if (!stralloc_copys(&helohost,"")) die_nomem(); /* helohost is empty */
+ if (!stralloc_0(&helohost)) die_nomem();
+ fakehelo = 0;
}
+/* this file is too long -------------------------------------- SMTP ADDRESSES */
stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
+stralloc eddr = {0}; /* extended address; used for smart address recognition */
+stralloc sa = {0};
+ipalloc ia = {0};
int addrparse(arg)
char *arg;
@@ -151,12 +427,17 @@
i = str_chr(arg,'<');
if (arg[i])
arg += i + 1;
+#ifdef REQBRACKETS
+ else
+ return 0;
+#else
else { /* partner should go read rfc 821 */
terminator = ' ';
arg += str_chr(arg,':');
if (*arg == ':') ++arg;
while (*arg == ' ') ++arg;
}
+#endif
/* strip source route */
if (*arg == '@') while (*arg) if (*arg++ == ':') break;
@@ -199,71 +480,489 @@
int bmfcheck()
{
+ int i;
int j;
- if (!bmfok) return 0;
- if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
- j = byte_rchr(addr.s,addr.len,'@');
- if (j < addr.len)
- if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
+ int k = 0;
+ char subvalue;
+
+ if (bmfok) {
+
+ if (!relayclient) { /* '+' address for none-RELAYCLIENTS */
+ eddr.len = 0;
+ if (!stralloc_copyb(&eddr,addr.s,addr.len - 1)) die_nomem();
+ if (!stralloc_append(&eddr,"+")) die_nomem();
+ if (!stralloc_0(&eddr)) die_nomem();
+
+ if (constmap(&mapbmf,eddr.s,eddr.len - 1)) return -6;
+ j = byte_rchr(eddr.s,eddr.len,'@');
+ if (j < eddr.len)
+ if (constmap(&mapbmf,eddr.s + j,eddr.len - j - 1)) return -5;
+ }
+
+ if (!case_diffs(remotehost,"unknown")) { /* '-' address from UNKNOWN */
+ eddr.len = 0;
+ if (!stralloc_copyb(&eddr,addr.s,addr.len - 1)) die_nomem();
+ if (!stralloc_append(&eddr,"-")) die_nomem();
+ if (!stralloc_0(&eddr)) die_nomem();
+
+ if (constmap(&mapbmf,eddr.s,eddr.len - 1)) return -4;
+ j = byte_rchr(eddr.s,eddr.len,'@');
+ if (j < eddr.len)
+ if (constmap(&mapbmf,eddr.s + j,eddr.len - j - 1)) return -3;
+ }
+
+ if (constmap(&mapbmf,addr.s,addr.len - 1)) return -2;
+ j = byte_rchr(addr.s,addr.len,'@');
+ if (j < addr.len)
+ if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return -1;
+
+ i = 0;
+ for (j = 0;j < bmf.len;++j)
+ if (!bmf.s[j]) {
+ subvalue = bmf.s[i] != '!';
+ if (!subvalue) i++;
+ if ((k != subvalue) && wildmat(addr.s,bmf.s + i)) k = subvalue;
+ i = j + 1;
+ }
+ return k;
+ }
return 0;
}
+int brtcheck()
+{
+ int i;
+ int j;
+ int k = 0;
+ char subvalue;
-int addrallowed()
+ if (brtok) {
+ if (constmap(&mapbrt,addr.s,addr.len - 1)) return -2;
+ j = byte_rchr(addr.s,addr.len,'@');
+ if (j < addr.len)
+ if (constmap(&mapbrt,addr.s + j,addr.len - j - 1)) return -1;
+
+ i = 0;
+ for (j = 0;j < brt.len;++j)
+ if (!brt.s[j]) {
+ subvalue = brt.s[i] != '!';
+ if (!subvalue) i++;
+ if ((k != subvalue) && wildmat(addr.s,brt.s + i)) k = subvalue;
+ i = j + 1;
+ }
+ return k;
+ }
+ return 0;
+}
+
+int bhelocheck()
+{
+ int i;
+ int j;
+ int k = 0;
+ char subvalue;
+
+ if (badhelook) {
+
+ eddr.len = 0; /* helohost! */
+ if (!stralloc_copyb(&eddr,helohost.s,helohost.len - 1)) die_nomem();
+ if (!stralloc_append(&eddr,"!")) die_nomem();
+ if (!stralloc_0(&eddr)) die_nomem();
+ if (constmap(&mapbadhelo,eddr.s,eddr.len - 1)) return -3;
+
+ if (constmap(&mapbadhelo,helohost.s,helohost.len - 1)) return -1;
+
+ i = 0;
+ for (j = 0;j < badhelo.len;++j)
+ if (!badhelo.s[j]) {
+ subvalue = badhelo.s[i] != '!';
+ if (!subvalue) i++;
+ if ((k != subvalue) && wildmat(helohost.s,badhelo.s + i)) k = subvalue;
+ i = j + 1;
+ }
+ return k;
+ }
+ return 0;
+}
+int dnsq(arg,type) char *arg, *type;
+{
+ unsigned int random;
+ int i;
+ int len;
+
+ len = str_len(arg);
+ if (len < 1) return -2;
+
+ sa.len = 0;
+ if (arg[len-1] == ' ') len--; /* trailing blank */
+ i = byte_rchr(arg,len,'@');
+ if (i < len) {
+ if (!stralloc_copyb(&sa,arg+i+1,len-i-1)) die_nomem();
+ } else
+ if (!stralloc_copyb(&sa,arg,len)) die_nomem();
+
+ dns_init(0);
+ random = now() + (getpid() << 16);
+ switch(*type) {
+ case 'A': i = dns_ip(&ia,&sa); break;
+ case 'M': i = dns_mxip(&ia,&sa,random); break;
+ }
+ switch(i) {
+ case DNS_HARD: return 1;
+ case DNS_SOFT: out("451 DNS temporary failure (#4.3.0)\r\n"); return -1;
+ case DNS_MEM: die_nomem();
+ }
+
+ return 0;
+}
+
+int addrallowed(char *add)
{
int r;
- r = rcpthosts(addr.s,str_len(addr.s));
+ r = rcpthosts(add,str_len(add));
if (r == -1) die_control();
return r;
}
+int rcptallowed()
+{
+ int r;
+ r = recipients(addr.s,str_len(addr.s));
+ if (r == -2) die_nomem();
+ if (r == -1) die_control();
+ return r;
+}
+
+int localaddr(char *mf)
+{
+ int j;
+ int mflen;
+
+ mflen = str_len(mf);
+ if (localmf == 2) return mfrules(fdmav,remoteip,remotehost,remoteinfo,mf);
+ else {
+ if (str_len(localmfcheck) > 1) {
+ case_lowerb(localmfcheck,str_len(localmfcheck));
+ j = byte_rchr(mf,mflen,'@');
+ if (j < mflen)
+ if (!str_diffn(localmfcheck,mf+j+1,mflen-j-1)) return 2;
+ }
+ if(addrallowed(mf)) return 3;
+ return -2;
+ }
+}
int seenmail = 0;
int flagbarf; /* defined if seenmail */
+int flagrcpt;
+int flagdnsmf;
+int flagsize;
+int rcptcount = 0;
+
stralloc mailfrom = {0};
stralloc rcptto = {0};
+stralloc user = {0};
+stralloc fuser = {0};
+stralloc mfparms = {0};
+
+int mailfrom_size(arg) char *arg;
+{
+ long r;
+ unsigned long sizebytes = 0;
+
+ scan_ulong(arg,&r);
+ sizebytes = r;
+ if (databytes) if (sizebytes > databytes) return 1;
+ return 0;
+}
+
+void mailfrom_auth(arg,len)
+char *arg;
+int len;
+{
+ if (!stralloc_copys(&fuser,"")) die_nomem();
+ if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); }
+ else
+ while (len) {
+ if (*arg == '+') {
+ if (case_starts(arg,"+3D")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"=")) die_nomem(); }
+ if (case_starts(arg,"+2B")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"+")) die_nomem(); }
+ }
+ else
+ if (!stralloc_catb(&fuser,arg,1)) die_nomem();
+ arg++; len--;
+ }
+ if (!stralloc_0(&fuser)) die_nomem();
+ if (!remoteinfo) {
+ remoteinfo = fuser.s;
+ if (!env_unset("TCPREMOTEINFO")) die_read();
+ if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
+ }
+}
+
+void mailfrom_parms(arg) char *arg;
+{
+ int i;
+ int len;
+
+ len = str_len(arg);
+ if (!stralloc_copys(&mfparms,"")) die_nomem;
+ i = byte_chr(arg,len,'>');
+ if (i > 4 && i < len) {
+ while (len) {
+ arg++; len--;
+ if (*arg == ' ' || *arg == '\0' ) {
+ if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; }
+ if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5);
+ if (!stralloc_copys(&mfparms,"")) die_nomem;
+ }
+ else
+ if (!stralloc_catb(&mfparms,arg,1)) die_nomem;
+ }
+ }
+}
+
+#ifdef RELAYMAILFROM
+int rmfcheck()
+{
+ if (!relaymailfromok) return 0;
+ if (constmap(&maprmf,addr.s,addr.len - 1)) return 1;
+ return 0;
+}
+#endif
+
+/* this file is too long ----------------------------------------- SMTP DIALOG */
void smtp_helo(arg) char *arg;
{
smtp_greet("250 "); out("\r\n");
- seenmail = 0; dohelo(arg);
+ seenmail = 0; rcptcount = 0; seenhelo++; dohelo(arg);
}
void smtp_ehlo(arg) char *arg;
{
- smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
- seenmail = 0; dohelo(arg);
+ char size[FMT_ULONG];
+ size[fmt_ulong(size,(unsigned long) databytes)] = 0;
+ smtp_greet("250-"); out("\r\n");
+ out("250-PIPELINING\r\n250-8BITMIME\r\n");
+ out("250");
+ if (smtpauth || (starttls && !seenttls)) out("-");
+ else out(" ");
+ out("SIZE "); out(size); out("\r\n");
+ if (smtpauth) {
+ if(starttls && !seenttls) out("250-");
+ else out("250 ");
+ if (smtpauth <= 2) out("AUTH LOGIN PLAIN\r\n");
+ if (smtpauth == 3) out("AUTH LOGIN PLAIN CRAM-MD5\r\n");
+ }
+ if (starttls && !seenttls) out("250 STARTTLS\r\n");
+ seenhelo++; seenmail = 0; rcptcount = 0; dohelo(arg);
}
void smtp_rset()
{
- seenmail = 0;
+ seenmail = 0; rcptcount = 0; seenauth = 0; seenttls = 0;
+ mailfrom.len = 0; rcptto.len = 0; tlsinfo.len = 0;
out("250 flushed\r\n");
}
+void smtp_starttls()
+{
+ if (starttls != 1) err_unimpl;
+ out("220 Ready to start TLS (#5.7.0)\r\n");
+ flush();
+
+ if(!ucspitls()) die_starttls();
+ seenttls = 1;
+
+ if(!ucspitlsinfo()) die_starttls();
+
+ tlsversion = env_get("SSL_PROTOCOL");
+ if (!tlsversion) tlsversion = "unknown";
+ cipher = env_get("SSL_CIPHER");
+ if (!cipher) cipher = "unknown";
+ cipherperm = env_get("SSL_CIPHER_ALGKEYSIZE");
+ if (!cipherperm) cipherperm = "unknown";
+ cipherused = env_get("SSL_CIPHER_USEKEYSIZE");
+ if (!cipherused) cipherused = "unknown";
+ clientdn = env_get("SSL_CLIENT_S_DN");
+ if (!clientdn) clientdn = "unknown";
+
+ if (!stralloc_copys(&tlsinfo,tlsversion)) die_nomem();
+ if (!stralloc_cats(&tlsinfo,": ")) die_nomem();
+ if (!stralloc_cats(&tlsinfo,cipher)) die_nomem();
+ if (!stralloc_cats(&tlsinfo," [")) die_nomem();
+ if (!stralloc_cats(&tlsinfo,cipherused)) die_nomem();
+ if (!stralloc_cats(&tlsinfo,"/")) die_nomem();
+ if (!stralloc_cats(&tlsinfo,cipherperm)) die_nomem();
+ if (!stralloc_cats(&tlsinfo,"] ")) die_nomem();
+ if (!stralloc_cats(&tlsinfo,"DN=")) die_nomem();
+ if (!stralloc_cats(&tlsinfo,clientdn)) die_nomem();
+ if (!stralloc_0(&tlsinfo)) die_nomem();
+
+ if (!stralloc_cats(&protocol,"S")) die_nomem();
+ logb("Accept::SNDR::Start_TLS:"," P:ESMTPS",remoteip,remotehost,helohost.s,clientdn,cipher);
+
+ /* reset SMTP state */
+ seenhelo = 0; seenmail = 0; rcptcount = 0; seenauth = 0;
+ helohost.len = 0; mailfrom.len = 0; rcptto.len = 0;
+}
void smtp_mail(arg) char *arg;
{
if (!addrparse(arg)) { err_syntax(); return; }
- flagbarf = bmfcheck();
- seenmail = 1;
+ flagsize = 0;
+ rcptcount = 0;
+ mailfrom_parms(arg);
+ seenmail++;
+ if (relayclient) {
+ if(localmf) flagmav = localaddr(addr.s);
+ switch(flagmav) {
+ case -9: die_nomem(); break;
+ case 2: if (!stralloc_cats(&protocol,"M")) die_nomem(); break;
+ default: break;
+ }
+ }
+ else {
+#ifdef RELAYMAILFROM
+ if (rmfcheck()) { relayclient = ""; flaglocal = -2; } else relayclient = 0;
+#endif
+ }
if (!stralloc_copys(&rcptto,"")) die_nomem();
if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
if (!stralloc_0(&mailfrom)) die_nomem();
+ flagbarf = bmfcheck();
+ if (mfdnscheck) flagdnsmf = dnsq(mailfrom.s,"M");
+ if (!stralloc_0(&protocol)) die_nomem();
out("250 ok\r\n");
}
void smtp_rcpt(arg) char *arg; {
if (!seenmail) { err_wantmail(); return; }
if (!addrparse(arg)) { err_syntax(); return; }
- if (flagbarf) { err_bmf(); return; }
- if (relayclient) {
+ rcptcount++;
+
+/* this file is too long --------------------------------- Sesssion checks */
+
+ if (reqttls) /* STTARTTLS rejects */
+ if (!seenttls) {
+ err_tlsreq("Reject::SNDR::Missing_TLS:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+
+ if (reqauth) /* Auth rejects */
+ if (!seenauth) {
+ err_authreq("Reject::ORIG::Missing_Auth:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+
+/* this file is too long --------------------------------- Split Horizon envelope checks */
+
+ if (!relayclient) {
+ if (!seenhelo && helocheck) /* Helo rejects */
+ if (str_len(helocheck) == 1) {
+ err_helo("Reject::SNDR::Bad_Helo:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+ if (flagbadhelo) {
+ switch(flagbadhelo) {
+ case -2: badhelocond = "!"; break;
+ case -1: badhelocond = "."; break;
+ default: badhelocond = "*"; break;
+ }
+ err_helo("Reject::SNDR::Bad_Helo:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,badhelocond);
+ return;
+ }
+ if (flagdnshelo > 0) {
+ err_helo("Reject::SNDR::DNS_Helo:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,badhelocond);
+ return;
+ }
+ if (flagdnsmf > 0) { /* Mail from rejects */
+ err_mfdns("Reject::ORIG::DNS_MF:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+ if (!addrallowed(addr.s)) { /* Relaying rejects */
+ err_nogateway("Reject::SNDR::Invalid_Relay:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+ flagrcpt = rcptallowed(); /* Rcpt to rejects */
+ if (!flagrcpt) {
+ err_recipient("Reject::RCPT::Failed_Rcptto:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ flagerrcpts++;
+ return;
+ }
+ if (tarpitcount && flagerrcpts >= tarpitcount) { /* Tarpitting et al. */
+ err_rcpts("Reject::RCPT::Toomany_Rcptto:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+ if (maxrcptcount && rcptcount > maxrcptcount) {
+ err_rcpts("Reject::RCPT::Toomany_Rcptto:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+ if (tarpitcount && rcptcount >= tarpitcount) {
+ unsigned int rest = tarpitdelay;
+ while (rest = sleep(rest));
+ }
+ }
+
+/* this file is too long --------------------------------- Local checks */
+
+ else {
+ if (flagmav < 0) {
+ err_mav("Reject::ORIG::Invalid_Mailfrom:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
--addr.len;
if (!stralloc_cats(&addr,relayclient)) die_nomem();
if (!stralloc_0(&addr)) die_nomem();
+ }
+
+/* this file is too long --------------------------------- Common checks */
+
+ if (flagbarf) {
+ switch(flagbarf) {
+ case -1: badmailcond = "@"; break;
+ case -2: badmailcond = "@"; break;
+ case -3: badmailcond = "-"; break;
+ case -4: badmailcond = "-"; break;
+ case -5: badmailcond = "+"; break;
+ case -6: badmailcond = "+"; break;
+ default: badmailcond = "*"; break;
+ }
+ err_bmf("Reject::ORIG::Bad_Mailfrom:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,badmailcond);
+ return;
}
- else
- if (!addrallowed()) { err_nogateway(); return; }
+
+ flagrcpt = brtcheck();
+ if (flagrcpt) {
+ err_brcptto("Reject::RCPT::Bad_Rcptto:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+
+ if (flagsize) {
+ err_size();
+ logs("Reject::DATA::Invalid_Size:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+
+/* this file is too long --------------------------------- Checks done; mailfrom/recipient accepted */
+
if (!stralloc_cats(&rcptto,"T")) die_nomem();
if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
if (!stralloc_0(&rcptto)) die_nomem();
out("250 ok\r\n");
-}
+/* this file is too long --------------------------------- Additional logging */
+
+ if (flaglocal > 0)
+ logs("Accept::ORIG::Local_Sender:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ else if (relayclient)
+ if (flaglocal == -2)
+ logs("Accept::ORIG::Relay_Mailfrom:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ else
+ logs("Accept::SNDR::Relay_Client:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ else
+ switch(flagrcpt) {
+ case 1: logs("Accept::RCPT::Recipients_Rcptto:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s); break;
+ case 2: logs("Accept::RCPT::Recipients_Verp:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s); break;
+ case 3: logs("Accept::RCPT::Recipients_Domain:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s); break;
+ default: logs("Accept::RCPT::Rcpthosts_Rcptto:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s); break;
+ }
+}
int saferead(fd,buf,len) int fd; char *buf; int len;
{
@@ -279,11 +978,69 @@
substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
struct qmail qqt;
-unsigned int bytestooverflow = 0;
+unsigned long bytestooverflow = 0;
+
+stralloc line = {0};
+stralloc base64types = {0};
+stralloc badmimetype = {0};
+stralloc badloadertype = {0};
+
+unsigned int nolines = 0;
+unsigned int flag64 = 0;
+unsigned int flagbase = 0;
+unsigned int flagblank = 0;
void put(ch)
char *ch;
{
+ uint32 dlen;
+ int i;
+
+ if (line.len < 1025)
+ if (!stralloc_catb(&line,ch,1)) die_nomem(); /* Reassamble chars to line; prepend with 'L' */
+
+ if (*ch == '\n') {
+ nolines++;
+
+ if (line.len == 2) { flagblank = nolines; flagbase = 0; } /* trigger */
+ if (*(line.s+1) == 'C' || *(line.s+1) == 'c')
+ if (case_startb(line.s+1,line.len-2,"content-transfer-encoding: base64")) flag64 = nolines; /* base64 attachments */
+ if (flag64 && nolines == flagblank+1 && line.len > MIMETYPE_LEN+2) {
+ flagbase = nolines;
+ if (!stralloc_catb(&base64types,line.s+1,MIMETYPE_LEN)) die_nomem();
+ if (!stralloc_0(&base64types)) die_nomem();
+ if (flagmimetype == 1) {
+ if (cdb_seek(fdbmt,line.s+1,MIMETYPE_LEN,&dlen)) {
+ if (!stralloc_copyb(&badmimetype,line.s+1,MIMETYPE_LEN)) die_nomem();
+ if (!stralloc_0(&badmimetype)) die_nomem();
+ if (!stralloc_cats(&rcptto,"M")) die_nomem();
+ if (!stralloc_0(&rcptto)) die_nomem();
+ qmail_fail(&qqt);
+ flagmimetype = -1;
+ }
+ }
+ }
+
+ if (flagloadertype == 1 && flagmimetype != -1) {
+ if (line.len > MIMETYPE_LEN + 2 && flagbase > flagblank) {
+ for ( i = 0; i < line.len - LOADER_LEN; ++i ) {
+ if (*(line.s+i) == *badloaderinit) {
+ if (cdb_seek(fdblt,line.s+i,LOADER_LEN,&dlen)) {
+ if (!stralloc_copyb(&badloadertype,line.s+i,LOADER_LEN)) die_nomem();
+ if (!stralloc_0(&badloadertype)) die_nomem();
+ if (!stralloc_cats(&rcptto,"L")) die_nomem();
+ if (!stralloc_0(&rcptto)) die_nomem();
+ qmail_fail(&qqt);
+ flagloadertype = -1;
+ }
+ }
+ }
+ }
+ }
+ line.len = 0;
+ if(!stralloc_copys(&line,"L")) die_nomem();
+ }
+
if (bytestooverflow)
if (!--bytestooverflow)
qmail_fail(&qqt);
@@ -316,8 +1073,8 @@
if (flagmaybex) if (pos == 7) ++*hops;
if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0;
if (flagmaybey) if (pos == 1) flaginheader = 0;
+ ++pos;
}
- ++pos;
if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; }
}
switch(state) {
@@ -378,26 +1135,251 @@
qp = qmail_qp(&qqt);
out("354 go ahead\r\n");
- received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
+ received(&qqt,protocol.s,local,remoteip,remotehost,remoteinfo,fakehelo,tlsinfo.s);
blast(&hops);
hops = (hops >= MAXHOPS);
if (hops) qmail_fail(&qqt);
+ if (base64 && base64types.len == 0) {
+ if (!stralloc_cats(&rcptto,"Q")) die_nomem();
+ if (!stralloc_0(&rcptto)) die_nomem();
+ }
qmail_from(&qqt,mailfrom.s);
qmail_put(&qqt,rcptto.s,rcptto.len);
qqx = qmail_close(&qqt);
if (!*qqx) { acceptmessage(qp); return; }
if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
- if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
- if (*qqx == 'D') out("554 "); else out("451 ");
- out(qqx + 1);
+ if (databytes)
+ if (!bytestooverflow) {
+ err_size();
+ logs("Reject::DATA::Invalid_Size:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+ return;
+ }
+ if (flagmimetype == -1) {
+ err_data("Reject::DATA::Bad_MIME:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,badmimetype.s);
+ return;
+ }
+ if (flagloadertype == -1) {
+ err_data("Reject::DATA::Bad_Loader:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,badloadertype.s);
+ return;
+ }
+ if (*qqx == 'D') {
+ err_data("Reject::DATA::Virus_Infected:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,qhpsi);
+ return;
+ }
+ else { out("451 "); out(qqx + 1); out("\r\n"); }
+}
+
+
+/* this file is too long ----------------------------------------- SMTP AUTH */
+
+char unique[FMT_ULONG + FMT_ULONG + 3];
+static stralloc authin = {0}; /* input from SMTP client */
+static stralloc pass = {0}; /* plain passwd or digest */
+static stralloc resp = {0}; /* b64 response */
+static stralloc chal = {0}; /* CRAM-MD5 plain challenge */
+static stralloc slop = {0}; /* CRAM-MD5 b64 challenge */
+
+char **childargs;
+char ssauthbuf[512];
+substdio ssauth = SUBSTDIO_FDBUF(safewrite,3,ssauthbuf,sizeof(ssauthbuf));
+
+int authgetl(void) {
+ int i;
+
+ if (!stralloc_copys(&authin,"")) die_nomem();
+ for (;;) {
+ if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
+ i = substdio_get(&ssin,authin.s + authin.len,1);
+ if (i != 1) die_read();
+ if (authin.s[authin.len] == '\n') break;
+ ++authin.len;
+ }
+
+ if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
+ authin.s[authin.len] = 0;
+ if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
+ if (authin.len == 0) { return err_input(); }
+ return authin.len;
+}
+
+int authenticate(void)
+{
+ int child;
+ int wstat;
+ int pi[2];
+
+ if (!stralloc_0(&user)) die_nomem();
+ if (!stralloc_0(&pass)) die_nomem();
+ if (!stralloc_0(&chal)) die_nomem();
+
+ if (pipe(pi) == -1) return err_pipe();
+ switch(child = fork()) {
+ case -1:
+ return err_fork();
+ case 0:
+ close(pi[1]);
+ if (fd_copy(3,pi[0]) == -1) return err_pipe();
+ sig_pipedefault();
+ execvp(*childargs, childargs);
+ _exit(1);
+ }
+ close(pi[0]);
+
+ substdio_fdbuf(&ssauth,write,pi[1],ssauthbuf,sizeof ssauthbuf);
+ if (substdio_put(&ssauth,user.s,user.len) == -1) return err_write();
+ if (substdio_put(&ssauth,pass.s,pass.len) == -1) return err_write();
+ if (smtpauth == 3) if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write();
+ if (substdio_flush(&ssauth) == -1) return err_write();
+
+ close(pi[1]);
+ if (!stralloc_copys(&chal,"")) die_nomem();
+ if (!stralloc_copys(&slop,"")) die_nomem();
+ byte_zero(ssauthbuf,sizeof ssauthbuf);
+ if (wait_pid(&wstat,child) == -1) return err_child();
+ if (wait_crashed(wstat)) return err_child();
+ if (wait_exitcode(wstat)) { sleep(AUTHSLEEP); return 1; } /* no */
+ return 0; /* yes */
+}
+
+int auth_login(arg) char *arg;
+{
+ int r;
+
+ if (*arg) {
+ if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
+ }
+ else {
+ out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
+ if (authgetl() < 0) return -1;
+ if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
+ }
+ if (r == -1) die_nomem();
+
+ out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */
+
+ if (authgetl() < 0) return -1;
+ if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
+ if (r == -1) die_nomem();
+
+ if (!user.len || !pass.len) return err_input();
+ return authenticate();
+}
+
+int auth_plain(arg) char *arg;
+{
+ int r, id = 0;
+
+ if (*arg) {
+ if (r = b64decode(arg,str_len(arg),&resp) == 1) return err_input();
+ }
+ else {
+ out("334 \r\n"); flush();
+ if (authgetl() < 0) return -1;
+ if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
+ }
+ if (r == -1 || !stralloc_0(&resp)) die_nomem();
+ while (resp.s[id]) id++; /* "authorize-id\0userid\0passwd\0" */
+
+ if (resp.len > id + 1)
+ if (!stralloc_copys(&user,resp.s + id + 1)) die_nomem();
+ if (resp.len > id + user.len + 2)
+ if (!stralloc_copys(&pass,resp.s + id + user.len + 2)) die_nomem();
+
+ if (!user.len || !pass.len) return err_input();
+ return authenticate();
+}
+
+int auth_cram()
+{
+ int i, r;
+ char *s;
+
+ s = unique; /* generate challenge */
+ s += fmt_uint(s,getpid());
+ *s++ = '.';
+ s += fmt_ulong(s,(unsigned long) now());
+ *s++ = '@';
+ *s++ = 0;
+ if (!stralloc_copys(&chal,"<")) die_nomem();
+ if (!stralloc_cats(&chal,unique)) die_nomem();
+ if (!stralloc_cats(&chal,local)) die_nomem();
+ if (!stralloc_cats(&chal,">")) die_nomem();
+ if (b64encode(&chal,&slop) < 0) die_nomem();
+ if (!stralloc_0(&slop)) die_nomem();
+
+ out("334 "); /* "334 base64_challenge \r\n" */
+ out(slop.s);
out("\r\n");
+ flush();
+
+ if (authgetl() < 0) return -1; /* got response */
+ if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
+ if (r == -1 || !stralloc_0(&resp)) die_nomem();
+
+ i = str_chr(resp.s,' ');
+ s = resp.s + i;
+ while (*s == ' ') ++s;
+ resp.s[i] = 0;
+ if (!stralloc_copys(&user,resp.s)) die_nomem(); /* userid */
+ if (!stralloc_copys(&pass,s)) die_nomem(); /* digest */
+
+ if (!user.len || !pass.len) return err_input();
+ return authenticate();
+}
+
+struct authcmd {
+ char *text;
+ int (*fun)();
+} authcmds[] = { { "login",auth_login }, { "plain",auth_plain }, { "cram-md5",auth_cram }, { 0,err_noauth } };
+
+void smtp_auth(arg)
+char *arg;
+{
+ int i;
+ char *cmd = arg;
+
+ if (!*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; }
+ if (seenauth) { err_authd(); return; }
+ if (seenmail) { err_authmail(); return; }
+
+ if (!stralloc_copys(&user,"")) die_nomem();
+ if (!stralloc_copys(&pass,"")) die_nomem();
+ if (!stralloc_copys(&resp,"")) die_nomem();
+ if (!stralloc_copys(&chal,"")) die_nomem(); /* only needed for CRAM-MD5 */
+
+ i = str_chr(cmd,' '); /* get AUTH type */
+ arg = cmd + i;
+ while (*arg == ' ') ++arg;
+ cmd[i] = 0;
+
+ for (i = 0;authcmds[i].text;++i)
+ if (case_equals(authcmds[i].text,cmd)) break;
+
+ switch (authcmds[i].fun(arg)) {
+ case 0:
+ seenauth = 1;
+ if (!stralloc_cats(&protocol,"A")) die_nomem();
+ relayclient = "";
+ remoteinfo = user.s;
+ if (!env_unset("TCPREMOTEINFO")) die_read();
+ if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
+ if (!env_put2("RELAYCLIENT",relayclient)) die_nomem();
+ out("235 ok, go ahead (#2.0.0)\r\n");
+ loga("Accept::ORIG::Valid_Auth:"," P:EMSTPA",remoteip,remotehost,helohost.s,user.s,authcmds[i].text);
+ break;
+ case 1:
+ err_authfail("Reject::ORIG::Failed_Auth:"," P:ESMTPA",remoteip,remotehost,helohost.s,user.s,authcmds[i].text);
+ }
}
+/* this file is too long --------------------------------------------- GO ON */
+
struct commands smtpcommands[] = {
{ "rcpt", smtp_rcpt, 0 }
, { "mail", smtp_mail, 0 }
, { "data", smtp_data, flush }
+, { "auth", smtp_auth, flush }
, { "quit", smtp_quit, flush }
, { "helo", smtp_helo, flush }
, { "ehlo", smtp_ehlo, flush }
@@ -405,15 +1387,20 @@
, { "help", smtp_help, flush }
, { "noop", err_noop, flush }
, { "vrfy", err_vrfy, flush }
+, { "starttls", smtp_starttls, flush }
, { 0, err_unimpl, flush }
} ;
-void main()
+void main(argc,argv)
+int argc;
+char **argv;
{
+ childargs = argv + 1;
sig_pipeignore();
if (chdir(auto_qmail) == -1) die_control();
setup();
if (ipme_init() != 1) die_ipme();
+ if (greetdelay) sleep(greetdelay);
smtp_greet("220 ");
out(" ESMTP\r\n");
if (commands(&ssin,&smtpcommands) == 0) die_read();
syntax highlighted by Code2HTML, v. 0.9.1