X-Git-Url: https://git.distorted.org.uk/~mdw/ezmlm/blobdiff_plain/5b62e993b0af39700031c2875d7f6654e6a02850..f8beb284087c279acfb30506f5bb32baa4949b44:/ezmlm-return.c diff --git a/ezmlm-return.c b/ezmlm-return.c index 3bc2421..7ca3fb2 100644 --- a/ezmlm-return.c +++ b/ezmlm-return.c @@ -1,3 +1,7 @@ +/*$Id: ezmlm-return.c,v 1.26 1999/08/07 20:50:52 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include +#include "direntry.h" #include "stralloc.h" #include "str.h" #include "env.h" @@ -16,18 +20,21 @@ #include "now.h" #include "cookie.h" #include "subscribe.h" -#include "issub.h" +#include "errtxt.h" +#include "idx.h" #define FATAL "ezmlm-return: fatal: " -void die_usage() { strerr_die1x(100,"ezmlm-return: usage: ezmlm-return dir"); } -void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } +#define INFO "ezmlm-return: info: " +void die_usage() +{ strerr_die1x(100,"ezmlm-return: usage: ezmlm-return [-dD] dir"); } +void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); } void die_badaddr() { - strerr_die2x(100,FATAL,"I do not accept messages at this address (#5.1.1)"); + strerr_die2x(100,FATAL,ERR_BAD_RETURN_ADDRESS); } void die_trash() { - strerr_die1x(0,"ezmlm-return: info: trash address"); + strerr_die2x(99,INFO,"trash address"); } char outbuf[1024]; @@ -38,21 +45,37 @@ substdio ssin; char strnum[FMT_ULONG]; char hash[COOKIE]; char hashcopy[COOKIE]; +char *hashp = (char *) 0; unsigned long cookiedate; +unsigned long addrno = 0L; +unsigned long addrno1 = 0L; +stralloc fndir = {0}; stralloc fndate = {0}; stralloc fndatenew = {0}; stralloc fnhash = {0}; stralloc fnhashnew = {0}; +void *psql = (void *) 0; stralloc quoted = {0}; +stralloc ddir = {0}; char *sender; +char *dir; +char *workdir; void die_hashnew() -{ strerr_die4sys(111,FATAL,"unable to write ",fnhashnew.s,": "); } +{ strerr_die4sys(111,FATAL,ERR_WRITE,fnhashnew.s,": "); } void die_datenew() -{ strerr_die4sys(111,FATAL,"unable to write ",fndatenew.s,": "); } +{ strerr_die4sys(111,FATAL,ERR_WRITE,fndatenew.s,": "); } void die_msgin() -{ strerr_die2sys(111,FATAL,"unable to read input: "); } +{ strerr_die2sys(111,FATAL,ERR_READ_INPUT); } + +void makedir(s) +char *s; +{ + if (mkdir(s,0755) == -1) + if (errno != error_exist) + strerr_die4x(111,FATAL,ERR_CREATE,s,": "); +} void dowit(addr,when,bounce) char *addr; @@ -60,16 +83,31 @@ unsigned long when; stralloc *bounce; { int fd; + unsigned int wpos; + unsigned long wdir,wfile; - if (!issub(addr)) return; + if (!issub(workdir,addr,(char *) 0,FATAL)) return; - if (!stralloc_copys(&fndate,"bounce/w")) die_nomem(); - if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem(); + if (!stralloc_copys(&fndate,workdir)) die_nomem(); + if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem(); + if (!stralloc_0(&fndate)) die_nomem(); + fndate.s[fndate.len - 1] = '/'; /* replace '\0' */ + wpos = fndate.len - 1; + wdir = when / 10000; + wfile = when - 10000 * wdir; + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,wdir))) die_nomem(); + if (!stralloc_0(&fndate)) die_nomem(); + makedir(fndate.s); + --fndate.len; /* remove terminal '\0' */ + if (!stralloc_cats(&fndate,"/w")) die_nomem(); + wpos = fndate.len - 1; + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,wfile))) die_nomem(); if (!stralloc_cats(&fndate,".")) die_nomem(); - if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) + die_nomem(); if (!stralloc_0(&fndate)) die_nomem(); if (!stralloc_copy(&fndatenew,&fndate)) die_nomem(); - fndatenew.s[7] = 'W'; + fndatenew.s[wpos] = 'W'; fd = open_trunc(fndatenew.s); if (fd == -1) die_datenew(); @@ -86,7 +124,7 @@ stralloc *bounce; if (close(fd) == -1) die_datenew(); /* NFS stupidity */ if (rename(fndatenew.s,fndate.s) == -1) - strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": "); + strerr_die6sys(111,FATAL,ERR_MOVE,fndatenew.s," to ",fndate.s,": "); } void doit(addr,msgnum,when,bounce) @@ -97,16 +135,37 @@ stralloc *bounce; { int fd; int fdnew; + unsigned int pos; + unsigned long ddir,dfile; - if (!issub(addr)) return; + if (!issub(workdir,addr,(char *) 0,FATAL)) return; - if (!stralloc_copys(&fndate,"bounce/d")) die_nomem(); - if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem(); + if (!stralloc_copys(&fndate,workdir)) die_nomem(); + if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem(); + if (!stralloc_0(&fndate)) die_nomem(); + makedir(fndate.s); + fndate.s[fndate.len-1] = '/'; /* replace terminal '\0' */ + ddir = when / 10000; + dfile = when - 10000 * ddir; + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,ddir))) die_nomem(); + if (!stralloc_copy(&fndir,&fndate)) die_nomem(); + if (!stralloc_0(&fndir)) die_nomem(); /* make later if necessary (new addr)*/ + if (!stralloc_cats(&fndate,"/d")) die_nomem(); + pos = fndate.len - 2; + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,dfile))) die_nomem(); if (!stralloc_cats(&fndate,".")) die_nomem(); - if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) + die_nomem(); + if (addrno) { /* so that pre-VERP bounces make a d... file per address */ + /* for the first one we use the std-style fname */ + if (!stralloc_cats(&fndate,".")) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,addrno))) die_nomem(); + } + addrno++; /* get ready for next */ if (!stralloc_0(&fndate)) die_nomem(); if (!stralloc_copy(&fndatenew,&fndate)) die_nomem(); - fndatenew.s[7] = 'D'; + fndatenew.s[pos] = '_'; /* fndate = bounce/d/nnnn/dmmmmmm */ + /* fndatenew = bounce/d/nnnn_dmmmmmm */ fd = open_trunc(fndatenew.s); if (fd == -1) die_datenew(); @@ -123,11 +182,21 @@ stralloc *bounce; if (close(fd) == -1) die_datenew(); /* NFS stupidity */ cookie(hash,"",0,"",addr,""); - if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem(); - if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem(); + if (!stralloc_copys(&fnhash,workdir)) die_nomem(); + if (!stralloc_cats(&fnhash,"/bounce/h")) die_nomem(); + if (!stralloc_0(&fnhash)) die_nomem(); + makedir(fnhash.s); + fnhash.s[fnhash.len - 1] = '/'; /* replace terminal '\0' */ + if (!stralloc_catb(&fnhash,hash,1)) die_nomem(); + if (!stralloc_0(&fnhash)) die_nomem(); + makedir(fnhash.s); + --fnhash.len; /* remove terminal '\0' */ + if (!stralloc_cats(&fnhash,"/h")) die_nomem(); + pos = fnhash.len - 1; + if (!stralloc_catb(&fnhash,hash+1,COOKIE-1)) die_nomem(); if (!stralloc_0(&fnhash)) die_nomem(); if (!stralloc_copy(&fnhashnew,&fnhash)) die_nomem(); - fnhashnew.s[7] = 'H'; + fnhashnew.s[pos] = 'H'; fdnew = open_trunc(fnhashnew.s); if (fdnew == -1) die_hashnew(); @@ -136,9 +205,10 @@ stralloc *bounce; fd = open_read(fnhash.s); if (fd == -1) { if (errno != error_noent) - strerr_die4sys(111,FATAL,"unable to read ",fnhash.s,": "); + strerr_die4sys(111,FATAL,ERR_READ,fnhash.s,": "); + makedir(fndir.s); if (rename(fndatenew.s,fndate.s) == -1) - strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": "); + strerr_die6sys(111,FATAL,ERR_MOVE,fndatenew.s," to ",fndate.s,": "); } else { substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); @@ -148,7 +218,7 @@ stralloc *bounce; } close(fd); if (unlink(fndatenew.s) == -1) - strerr_die4sys(111,FATAL,"unable to unlink ",fndatenew.s,": "); + strerr_die4sys(111,FATAL,ERR_DELETE,fndatenew.s,": "); } if (substdio_puts(&ssout," ") == -1) die_hashnew(); if (substdio_put(&ssout,strnum,fmt_ulong(strnum,msgnum)) == -1) die_hashnew(); @@ -158,7 +228,7 @@ stralloc *bounce; if (close(fdnew) == -1) die_hashnew(); /* NFS stupidity */ if (rename(fnhashnew.s,fnhash.s) == -1) - strerr_die6sys(111,FATAL,"unable to rename ",fnhashnew.s," to ",fnhash.s,": "); + strerr_die6sys(111,FATAL,ERR_MOVE,fnhashnew.s," to ",fnhash.s,": "); } stralloc bounce = {0}; @@ -167,14 +237,11 @@ stralloc header = {0}; stralloc intro = {0}; stralloc failure = {0}; stralloc paragraph = {0}; +int flagmasterbounce = 0; int flaghaveheader; int flaghaveintro; stralloc key = {0}; -stralloc inhost = {0}; -stralloc outhost = {0}; -stralloc inlocal = {0}; -stralloc outlocal = {0}; char msginbuf[1024]; substdio ssmsgin; @@ -183,16 +250,22 @@ void main(argc,argv) int argc; char **argv; { - char *dir; - char *host; char *local; char *action; + char *def; + char *ret; + char *cp; unsigned long msgnum; unsigned long cookiedate; unsigned long when; + unsigned long listno = 0L; int match; - int i; + unsigned int i; + int flagdig = 0; + int flagmaster = 0; + int flagreceipt = 0; int fdlock; + register char ch; umask(022); sig_pipeignore(); @@ -200,104 +273,158 @@ char **argv; dir = argv[1]; if (!dir) die_usage(); + if (*dir == '-') { /* for normal use */ + if (dir[1] == 'd') { + flagdig = 1; + } else if (dir[1] == 'D') { + flagdig = 0; + } else + die_usage(); + dir = argv[2]; + if (!dir) die_usage(); + } sender = env_get("SENDER"); - if (!sender) strerr_die2x(100,FATAL,"SENDER not set"); + if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER); local = env_get("LOCAL"); - if (!local) strerr_die2x(100,FATAL,"LOCAL not set"); - host = env_get("HOST"); - if (!host) strerr_die2x(100,FATAL,"HOST not set"); + if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL); + def = env_get("DEFAULT"); /* qmail-1.02 */ if (chdir(dir) == -1) - strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": "); switch(slurp("key",&key,32)) { case -1: - strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: "); + strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: "); case 0: - strerr_die3x(100,FATAL,dir,"/key does not exist"); + strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST); } - getconf_line(&inhost,"inhost",1,FATAL,dir); - getconf_line(&inlocal,"inlocal",1,FATAL,dir); - getconf_line(&outhost,"outhost",1,FATAL,dir); - getconf_line(&outlocal,"outlocal",1,FATAL,dir); - - if (inhost.len != str_len(host)) die_badaddr(); - if (case_diffb(inhost.s,inhost.len,host)) die_badaddr(); - if (inlocal.len > str_len(local)) die_badaddr(); - if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr(); + workdir = dir; + action = def; - action = local + inlocal.len; - - if (!str_start(action,"-return-")) die_badaddr(); - action += 8; + if (str_start(action,"receipt-")) { + flagreceipt = 1; + action += 8; + } + ch = *action; /* -d -digest, -m -master, -g -getmaster */ + if (ch && action[1] == '-') { + switch (ch) { + case 'g': flagmaster = 1; flagdig = 1; action += 2; break; + case 'm': flagmaster = 1; action += 2; break; + default: break; + } + } + if (flagdig) { + if (!stralloc_copys(&ddir,dir)) die_nomem(); + if (!stralloc_cats(&ddir,"/digest")) die_nomem(); + if (!stralloc_0(&ddir)) die_nomem(); + workdir = ddir.s; + } if (!*action) die_trash(); - if (str_start(action,"probe-")) { - action += 6; - action += scan_ulong(action,&cookiedate); - if (now() - cookiedate > 3000000) die_trash(); - if (*action++ != '.') die_trash(); - i = str_chr(action,'-'); - if (i != COOKIE) die_trash(); - byte_copy(hashcopy,COOKIE,action); - action += COOKIE; - if (*action++ != '-') die_trash(); - i = str_rchr(action,'='); - if (!stralloc_copyb(&line,action,i)) die_nomem(); - if (action[i]) { - if (!stralloc_cats(&line,"@")) die_nomem(); - if (!stralloc_cats(&line,action + i + 1)) die_nomem(); - } - if (!stralloc_0(&line)) die_nomem(); - strnum[fmt_ulong(strnum,cookiedate)] = 0; - cookie(hash,key.s,key.len,strnum,line.s,"P"); - if (byte_diff(hash,COOKIE,hashcopy)) die_trash(); - - if (subscribe(line.s,0) == 1) log("-probe",line.s); - _exit(0); + if (flagreceipt || flagmaster) /* check cookie */ + if (str_chr(action,'-') == COOKIE) { + action[COOKIE] = '\0'; + hashp = action; + action += COOKIE + 1; } - fdlock = open_append("lockbounce"); - if (fdlock == -1) - strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: "); - if (lock_ex(fdlock) == -1) - strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: "); - - if (str_start(action,"warn-")) { - action += 5; - action += scan_ulong(action,&cookiedate); - if (now() - cookiedate > 3000000) die_trash(); - if (*action++ != '.') die_trash(); - i = str_chr(action,'-'); - if (i != COOKIE) die_trash(); - byte_copy(hashcopy,COOKIE,action); - action += COOKIE; - if (*action++ != '-') die_trash(); - i = str_rchr(action,'='); - if (!stralloc_copyb(&line,action,i)) die_nomem(); - if (action[i]) { - if (!stralloc_cats(&line,"@")) die_nomem(); - if (!stralloc_cats(&line,action + i + 1)) die_nomem(); + if (!flagreceipt) { + if (!flagmaster && str_start(action,"probe-")) { + action += 6; + action += scan_ulong(action,&cookiedate); + if (now() - cookiedate > 3000000) die_trash(); + if (*action++ != '.') die_trash(); + i = str_chr(action,'-'); + if (i != COOKIE) die_trash(); + byte_copy(hashcopy,COOKIE,action); + action += COOKIE; + if (*action++ != '-') die_trash(); + i = str_rchr(action,'='); + if (!stralloc_copyb(&line,action,i)) die_nomem(); + if (action[i]) { + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cats(&line,action + i + 1)) die_nomem(); + } + if (!stralloc_0(&line)) die_nomem(); + strnum[fmt_ulong(strnum,cookiedate)] = 0; + cookie(hash,key.s,key.len,strnum,line.s,"P"); + if (byte_diff(hash,COOKIE,hashcopy)) die_trash(); + + (void) subscribe(workdir,line.s,0,"","-probe",1,-1,(char *) 0,FATAL); + _exit(99); } + + if (!stralloc_copys(&line,workdir)) die_nomem(); + if (!stralloc_cats(&line,"/lockbounce")) die_nomem(); if (!stralloc_0(&line)) die_nomem(); - strnum[fmt_ulong(strnum,cookiedate)] = 0; - cookie(hash,key.s,key.len,strnum,line.s,"W"); - if (byte_diff(hash,COOKIE,hashcopy)) die_trash(); - if (slurpclose(0,&bounce,1024) == -1) die_msgin(); - dowit(line.s,when,&bounce); - _exit(0); + fdlock = open_append(line.s); + if (fdlock == -1) + strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": "); + if (lock_ex(fdlock) == -1) + strerr_die4sys(111,FATAL,ERR_OBTAIN,line.s,": "); + + if (!flagmaster && str_start(action,"warn-")) { + action += 5; + action += scan_ulong(action,&cookiedate); + if (now() - cookiedate > 3000000) die_trash(); + if (*action++ != '.') die_trash(); + i = str_chr(action,'-'); + if (i != COOKIE) die_trash(); + byte_copy(hashcopy,COOKIE,action); + action += COOKIE; + if (*action++ != '-') die_trash(); + i = str_rchr(action,'='); + if (!stralloc_copyb(&line,action,i)) die_nomem(); + if (action[i]) { + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cats(&line,action + i + 1)) die_nomem(); + } + if (!stralloc_0(&line)) die_nomem(); + strnum[fmt_ulong(strnum,cookiedate)] = 0; + cookie(hash,key.s,key.len,strnum,line.s,"W"); + if (byte_diff(hash,COOKIE,hashcopy)) die_trash(); + + if (slurpclose(0,&bounce,1024) == -1) die_msgin(); + dowit(line.s,when,&bounce); + _exit(99); + } } - action += scan_ulong(action,&msgnum); - if (*action != '-') die_badaddr(); - ++action; + if (*action++ != '-') die_badaddr(); + cp = action; + if (*action >= '0' && *action <= '9') { /* listno */ + action += scan_ulong(action,&listno); + listno++; /* logging is 1-53, not 0-52 */ + } - if (*action) { - if (slurpclose(0,&bounce,1024) == -1) die_msgin(); + if (hashp) { /* scrap bad cookies */ + if ((ret = checktag(workdir,msgnum,0L,"x",(char *) 0,hashp))) { + if (*ret) + strerr_die2x(111,FATAL,*ret); + else + die_trash(); + } else if (flagreceipt) { + if (!(ret = logmsg(dir,msgnum,listno,0L,5))) { + closesql(); + strerr_die6x(99,INFO,"receipt:",cp," [",hashp,"]"); + } + if (*ret) strerr_die2x(111,FATAL,ret); + else strerr_die2x(0,INFO,ERR_DONE); + } else if (*action) { /* post VERP master bounce */ + if ((ret = logmsg(dir,msgnum,listno,0L,-1))) { + closesql(); + strerr_die4x(0,INFO,"bounce [",hashp,"]"); + } + if (*ret) strerr_die2x(111,FATAL,ret); + else strerr_die2x(99,INFO,ERR_DONE); + } + } else if (flagreceipt || flagmaster) + die_badaddr(); + if (*action) { i = str_rchr(action,'='); if (!stralloc_copyb(&line,action,i)) die_nomem(); if (action[i]) { @@ -305,11 +432,12 @@ char **argv; if (!stralloc_cats(&line,action + i + 1)) die_nomem(); } if (!stralloc_0(&line)) die_nomem(); + if (slurpclose(0,&bounce,1024) == -1) die_msgin(); doit(line.s,msgnum,when,&bounce); - _exit(0); + _exit(99); } - /* pre-VERP bounce, in QSBMF format */ + /* pre-VERP bounce, in QSBMF format. Receipts are never pre-VERP */ substdio_fdbuf(&ssmsgin,read,0,msginbuf,sizeof(msginbuf)); @@ -332,6 +460,8 @@ char **argv; } if (!flaghaveintro) { + if (paragraph.s[0] == '-' && paragraph.s[1] == '-') + continue; /* skip MIME boundary if it exists */ if (paragraph.len < 15) die_trash(); if (str_diffn(paragraph.s,"Hi. This is the",15)) die_trash(); if (!stralloc_copy(&intro,¶graph)) die_nomem(); @@ -355,10 +485,23 @@ char **argv; if (!stralloc_copyb(&line,failure.s + 1,i - 3)) die_nomem(); if (byte_chr(line.s,line.len,'\0') == line.len) { if (!stralloc_0(&line)) die_nomem(); - doit(line.s,msgnum,when,&bounce); + if (flagmaster) { /* bounced msg slave! */ + if ((i = str_rchr(line.s,'@')) >= 5) { /* 00_52@host */ + line.s[i] = '\0'; /* 00_52 */ + (void) scan_ulong(line.s + i - 5,&listno); + if ((ret = logmsg(dir,msgnum,listno + 1,0L,-1)) && *ret) + strerr_die2x(111,FATAL,ret); + strerr_warn3(INFO,"bounce ",line.s + i - 5,(struct strerr *) 0); + flagmasterbounce = 1; + } + } else + doit(line.s,msgnum,when,&bounce); } } } - - _exit(0); + closesql(); + if (flagmasterbounce) + strerr_die3x(0,"[",hashp,"]"); + else + _exit(99); }