void write_ulong(unsigned long num,unsigned long cum,unsigned long dat, const char *fn,const char *fnn) /* write num to "fnn" add ':' & cum if cum <>0, then move "fnn" to "fn" */ { int fd; fd = open_trunc(fnn); if (fd == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CREATE,fnn)); substdio_fdbuf(&ssnum,write,fd,numbuf,sizeof(numbuf)); if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,num)) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn)); if (substdio_puts(&ssnum,":") == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn)); if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,cum)) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn)); if (dat) { if (substdio_puts(&ssnum,":") == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn)); if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,dat)) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn)); } if (substdio_puts(&ssnum,"\n") == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn)); if (substdio_flush(&ssnum) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_FLUSH,fnn)); if (fsync(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,fnn)); if (close(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,fnn)); wrap_rename(fnn,fn); }
void strerr_warn(const char *x1, const char *x2, const char *x3, const char *x4, const char *x5, const char *x6, const struct strerr *se) { strerr_sysinit(); if (x1) substdio_puts(subfderr,x1); if (x2) substdio_puts(subfderr,x2); if (x3) substdio_puts(subfderr,x3); if (x4) substdio_puts(subfderr,x4); if (x5) substdio_puts(subfderr,x5); if (x6) substdio_puts(subfderr,x6); while(se) { if (se->x) substdio_puts(subfderr,se->x); if (se->y) substdio_puts(subfderr,se->y); if (se->z) substdio_puts(subfderr,se->z); se = se->who; } substdio_puts(subfderr,"\n"); substdio_flush(subfderr); }
static void flushit(int fd) { if (fd > 0) if (substdio_flush(&ssarchive) == -1 || fchmod(fd,MODE_ARCHIVE|0700) == -1 || close(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnaf.s)); }
void die_alias() { substdio_puts(subfderr,"qmail-pw2u: fatal: unable to find "); substdio_puts(subfderr,auto_usera); substdio_puts(subfderr," user\n"); substdio_flush(subfderr); _exit(111); }
int main() { host[0] = 0; /* sigh */ gethostname(host,sizeof(host)); host[sizeof(host) - 1] = 0; substdio_puts(subfdoutsmall,host); substdio_puts(subfdoutsmall,"\n"); substdio_flush(subfdoutsmall); _exit(0); }
void f_close(void) { if (substdio_flush(&ss) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_FLUSH,dirplus.s)); if (fsync(ss.fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,dirplus.s)); if (close(ss.fd) == -1) /* NFS stupidity */ strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,dirplus.s)); keyaddtime(); }
int call_flush(struct call *cc) { if (cc->flagerr || cc->flagabort) return -1; if (substdio_flush(&cc->ssto) == -1) { cc->flagerr = 1; return -1; } return 0; }
void close_proper(substdio *ss,const char *s,const char *sn) /* flush,sync,close,move sn->s) */ { if (substdio_flush(ss) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_FLUSH,s)); if (flagsync) if (fsync(ss->fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,s)); if (close(ss->fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,s)); wrap_rename(sn,s); }
int substdio_bput(substdio *s,const char *buf,int len) { int n; while (len > (n = s->n - s->p)) { byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n; if (substdio_flush(s) == -1) return -1; } /* now len <= s->n - s->p */ byte_copy(s->x + s->p,len,buf); s->p += len; return 0; }
int main(int argc,char *argv[]) { const char* dir; int fd; int match; unsigned long msgsize = 0L; int opt; while ((opt = getopt(argc,argv,"vV")) != opteof) { switch(opt) { case 'v': case 'V': strerr_die2x(0, "ezmlm-import version: ",auto_version); default: die_usage(); } } if (argc - optind != 2) die_usage(); if ((fd = open_read(argv[optind+1])) == -1) strerr_die4sys(111,FATAL,ERR_OPEN,argv[optind+1],": "); substdio_fdbuf(&ssin,read,fd,inputbuf,sizeof inputbuf); startup(dir = argv[optind]); lockfile("lock"); getconf_ulong2(&msgnum,&cumsize,"num",0,dir); fd = 0; while (getln(&ssin,&line,&match,'\n') == 0 && match) { if (line.len > 5 && byte_diff(line.s,5,"From ") == 0) { if (fd > 0) { if (substdio_flush(&ssarchive) == -1 || fchmod(fd,MODE_ARCHIVE|0700) == -1 || close(fd) == -1) strerr_die4sys(111,FATAL,ERR_WRITE,fnaf.s,": "); fd = 0; } ++msgnum; cumsize += (msgsize + 128L) >> 8; msgsize = 0L; fd = openone(msgnum); } else if (fd > 0) { substdio_put(&ssarchive,line.s,line.len); msgsize += line.len; } }
void doanddie(char *user, unsigned int userlen /* including 0 byte */, char *pass) { int child; int wstat; int pi[2]; close(3); if (pipe(pi) == -1) die_pipe(); if (pi[0] != 3) die_pipe(); switch(child = fork()) { case -1: die_fork(); case 0: close(pi[1]); sig_pipedefault(); execvp(*childargs,childargs); _exit(1); } close(pi[0]); substdio_fdbuf(&ssup,subwrite,pi[1],upbuf,sizeof upbuf); if (substdio_put(&ssup,user,userlen) == -1) die_write(); if (substdio_put(&ssup,pass,str_len(pass) + 1) == -1) die_write(); if (substdio_puts(&ssup,"<") == -1) die_write(); if (substdio_puts(&ssup,unique) == -1) die_write(); if (substdio_puts(&ssup,hostname) == -1) die_write(); if (substdio_put(&ssup,">",2) == -1) die_write(); if (substdio_flush(&ssup) == -1) die_write(); close(pi[1]); byte_zero(pass,str_len(pass)); byte_zero(upbuf,sizeof upbuf); if (wait_pid(&wstat,child) == -1) die(); if (wait_crashed(wstat)) die_childcrashed(); switch (wait_exitcode(wstat)) { case 0: die(); case 1: die_1(); case 2: die_2(); case 25: die_25(); case 3: die_3(); case 4: die_4(); case 5: die_5(); case 6: die_6(); case 61: die_61(); case 62: die_62(); case 7: die_7(); case 8: die_nomem(); default: die_unknown(); } die(); }
void logend(unsigned long level, const char *fmt, ...) { va_list ap; char ch; va_start(ap, fmt); if ( ! ( loglevel & level ) ) return; va_output(&sslog, fmt, ap); va_end(ap); ch = 16; if ( addLOG ) if ( substdio_put(&sslog, &ch, 1) ) return; if ( substdio_flush(&sslog) == -1 ) return; }
void store_from(stralloc *frl, /* from line */ const char *adr) /* rewrites the from file removing all that is older than 1000000 secs */ /* and add the curent from line (frl). Forget it if there is none there.*/ /* NOTE: This is used only for subscribes to moderated lists! */ { int fdin; int fdout; unsigned long linetime; if (!flagstorefrom || !frl->len) return; /* nothing to store */ lock(); if ((fdout = open_trunc("fromn")) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,"fromn")); substdio_fdbuf(&ssfrom,write,fdout,frombuf,(int) sizeof(frombuf)); if ((fdin = open_read("from")) == -1) { if (errno != error_noent) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,"from")); } else { substdio_fdbuf(&sstext,read,fdin,textbuf,(int) sizeof(textbuf)); for (;;) { if (getln(&sstext,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,"from")); if (!match) break; (void) scan_ulong(line.s,&linetime); if (linetime + 1000000 > (unsigned long) when && linetime <= (unsigned long) when) if (substdio_bput(&ssfrom,line.s,line.len)) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"fromn")); } close(fdin); } /* build new entry */ stralloc_copyb(&line,strnum,fmt_ulong(strnum,when)); stralloc_append(&line,' '); stralloc_cats(&line,adr); stralloc_0(&line); stralloc_catb(&line,frl->s,frl->len); stralloc_append(&line,'\n'); if (substdio_bput(&ssfrom,line.s,line.len) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"fromn")); if (substdio_flush(&ssfrom) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"fromn")); if (fsync(fdout) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,"fromn")); if (close(fdout) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,"fromn")); wrap_rename("fromn","from"); unlock(); }
int main(int argc, char **argv) { char *name; char *env; char value[256]; int len; name = argv[1]; if (!name) _exit(100); env = argv[2]; if ((len = substdio_get(subfdin,value,sizeof value - 1)) <= 0) _exit(100); value[len] = 0; value[str_chr(value,'\n')] = 0; if (env) { subputs("#include \"env.h\"\n" "const char *"); subputs(name); subputs("(void)\n" "{\n" " const char *env;\n" " if ((env = env_get(\""); subputs(env); subputs("\")) == 0)\n" " env = \""); subputsbin(value); subputs("\";\n" " return env;\n" "}\n"); } else { subputs("const char "); subputs(name); subputs("[] = \""); subputsbin(value); subputs("\";\n"); } if (substdio_flush(subfdout) == -1) _exit(111); return 0; (void)argc; }
int substdio_put(substdio *s,const char *buf,int len) { int n; n = s->n; if (len > n - s->p) { if (substdio_flush(s) == -1) return -1; /* now s->p == 0 */ if (n < SUBSTDIO_OUTSIZE) n = SUBSTDIO_OUTSIZE; while (len > s->n) { if (n > len) n = len; if (allwrite(s->op,s->fd,buf,n) == -1) return -1; buf += n; len -= n; } } /* now len <= s->n - s->p */ byte_copy(s->x + s->p,len,buf); s->p += len; return 0; }
int main(int argc,char **argv) { const char *subdir; unsigned long n; int i; char strnum[FMT_ULONG]; i = getconfopt(argc,argv,options,1,0); initsub(flagsubdb); subdir = argv[i]; if (flagnumber) { n = putsubs(subdir,0L,52L,dummywrite); if (substdio_put(subfdout,strnum,fmt_ulong(strnum,n)) == -1) die_write(); if (substdio_put(subfdout,"\n",1) == -1) die_write(); } else (void) putsubs(subdir,0L,52L,subwrite); if (substdio_flush(subfdout) == -1) die_write(); closesub(); _exit(0); }
int main(int argc,char *argv[]) { int fd; int match; unsigned long msgsize = 0L; int opt; opt = getconfopt(argc,argv,options,1,0); if (argc - opt != 1) die_usage(); if ((fd = open_read(argv[opt])) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,argv[opt])); substdio_fdbuf(&ssin,read,fd,inputbuf,sizeof inputbuf); lockfile("lock"); getconf_ulong2(&msgnum,&cumsize,"num",0); fd = 0; while (getln(&ssin,&line,&match,'\n') == 0 && match) { if (line.len > 5 && byte_diff(line.s,5,"From ") == 0) { if (fd > 0) { if (substdio_flush(&ssarchive) == -1 || fchmod(fd,MODE_ARCHIVE|0700) == -1 || close(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnaf.s)); fd = 0; } ++msgnum; cumsize += (msgsize + 128L) >> 8; msgsize = 0L; fd = openone(msgnum); } else if (fd > 0) { substdio_put(&ssarchive,line.s,line.len); msgsize += line.len; } }
int main() { int fd; int i; if (chdir(auto_qmail) == -1) strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": "); if (chdir("queue/lock") == -1) strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,"/queue/lock: "); fd = open_write("tcpto"); if (fd == -1) strerr_die4sys(111,FATAL,"unable to write ",auto_qmail,"/queue/lock/tcpto: "); if (lock_ex(fd) == -1) strerr_die4sys(111,FATAL,"unable to lock ",auto_qmail,"/queue/lock/tcpto: "); substdio_fdbuf(&ss,write,fd,buf,sizeof buf); for (i = 0;i < sizeof buf;++i) substdio_put(&ss,"",1); if (substdio_flush(&ss) == -1) strerr_die4sys(111,FATAL,"unable to clear ",auto_qmail,"/queue/lock/tcpto: "); _exit(0); }
void main(int argc,char **argv) { char *dir; int fdlock; char *sender; int match; int flaginheader; int flagmodpost; int flagremote; const char *pmod; const char *err; int opt; unsigned int i; char szchar[2] = "-"; int child; (void) umask(022); sig_pipeignore(); if (!stralloc_copys(&sendopt,"-")) die_nomem(); while ((opt = getopt(argc,argv,"bBcCmMpPrRsSvVyY")) != opteof) switch(opt) { case 'b': flagbody = 1; break; case 'B': flagbody = 0; break; case 'm': flagmime = 1; break; case 'M': flagmime = 0; break; case 'p': flagpublic = 1; break; /* anyone can post (still moderated)*/ case 'P': flagpublic = 0; break; /* only moderators can post */ case 's': flagself = 1; break; /* modpost and DIR/mod diff fxns */ case 'S': flagself = 0; break; /* same fxn */ case 'y': flagconfirm = 1; break; /* force post confirmation */ case 'Y': flagconfirm = 0; break; /* disable post confirmation */ case 'c': /* ezmlm-send flags */ case 'C': case 'r': case 'R': szchar[0] = (char) opt & 0xff; if (!stralloc_append(&sendopt,szchar)) die_nomem(); break; case 'v': case 'V': strerr_die2x(0,"ezmlm-store version: ",auto_version); default: die_usage(); } sender = env_get("SENDER"); if (sender) { if (!*sender || str_equal(sender,"#@[]")) strerr_die2x(100,FATAL,ERR_BOUNCE); } startup(dir = argv[optind]); load_config(dir); if (flagconfirm == -1) flagconfirm = getconf_line(&confirmpost,"confirmpost",0,dir); else getconf_line(&confirmpost,"confirmpost",0,dir); flagmodpost = getconf_line(&moderators,"modpost",0,dir); flagremote = getconf_line(&line,"remote",0,dir); if (!flagmodpost && !flagconfirm) { /* not msg-mod. Pipe to ezmlm-send */ if ((child = wrap_fork()) == 0) wrap_execbin("/ezmlm-send", &sendopt, dir); /* parent */ wrap_exitcode(child); } if (!moderators.len || !(moderators.s[0] == '/')) { if (!stralloc_copys(&moderators,dir)) die_nomem(); if (!stralloc_cats(&moderators,"/mod")) die_nomem(); } if (!stralloc_0(&moderators)) die_nomem(); if (sender) { pmod = issub(moderators.s,0,sender); closesub(); /* sender = moderator? */ } else pmod = 0; if (!pmod && !flagpublic) strerr_die2x(100,FATAL,ERR_NO_POST); fdlock = lockfile("mod/lock"); if (!stralloc_copys(&mydtline, flagconfirm ? "Delivered-To: confirm to " : "Delivered-To: moderator for ")) die_nomem(); if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem(); if (!stralloc_append(&mydtline,"@")) die_nomem(); if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem(); if (!stralloc_cats(&mydtline,"\n")) die_nomem(); if (!stralloc_copys(&returnpath,"Return-Path: <")) die_nomem(); if (sender) { if (!stralloc_cats(&returnpath,sender)) die_nomem(); for (i = 14; i < returnpath.len;++i) if (returnpath.s[i] == '\n' || !returnpath.s[i] ) returnpath.s[i] = '_'; /* NUL and '\n' are bad, but we don't quote since this is */ /* only for ezmlm-moderate, NOT for SMTP */ } if (!stralloc_cats(&returnpath,">\n")) die_nomem(); pid = getpid(); /* unique file name */ for (i = 0;;++i) /* got lock - nobody else can add files */ { when = now(); /* when is also used later for date! */ if (!stralloc_copys(&fnmsg, flagconfirm?"mod/unconfirmed/":"mod/pending/")) die_nomem(); if (!stralloc_copyb(&fnbase,strnum,fmt_ulong(strnum,when))) die_nomem(); if (!stralloc_append(&fnbase,".")) die_nomem(); if (!stralloc_catb(&fnbase,strnum,fmt_ulong(strnum,pid))) die_nomem(); if (!stralloc_cat(&fnmsg,&fnbase)) die_nomem(); if (!stralloc_0(&fnmsg)) die_nomem(); if (stat(fnmsg.s,&st) == -1) if (errno == error_noent) break; /* really should never get to this point */ if (i == 2) strerr_die2x(111,FATAL,ERR_UNIQUE); sleep(2); } if (!stralloc_copys(&action,"-")) die_nomem(); if (!stralloc_cats(&action,flagconfirm?ACTION_DISCARD:ACTION_REJECT)) die_nomem(); if (!stralloc_cat(&action,&fnbase)) die_nomem(); if (!stralloc_0(&action)) die_nomem(); makeacthash(&action); if (!quote("ed,&outlocal)) die_nomem(); if (!stralloc_copy(&reject,"ed)) die_nomem(); if (!stralloc_cat(&reject,&action)) die_nomem(); if (!stralloc_0(&reject)) die_nomem(); if (!stralloc_copys(&action,"-")) die_nomem(); if (!stralloc_cats(&action,flagconfirm?ACTION_CONFIRM:ACTION_ACCEPT)) die_nomem(); if (!stralloc_cat(&action,&fnbase)) die_nomem(); if (!stralloc_0(&action)) die_nomem(); makeacthash(&action); if (!stralloc_copy(&accept,"ed)) die_nomem(); if (!stralloc_cat(&accept,&action)) die_nomem(); if (!stralloc_0(&accept)) die_nomem(); set_cptarget(accept.s); /* for copy () */ set_cpconfirm(reject.s,quoted.len); fdmsg = open_trunc(fnmsg.s); if (fdmsg == -1) strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnmsg.s,": "); substdio_fdbuf(&ssmsg,write,fdmsg,msgbuf,sizeof(msgbuf)); if (qmail_open(&qq, (stralloc *) 0) == -1) /* Open mailer */ strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE); hdr_add2("Mailing-List: ",mailinglist.s,mailinglist.len); if (listid.len > 0) hdr_add2("List-ID: ",listid.s,listid.len); hdr_datemsgid(when); if (flagconfirm) hdr_from("-owner"); else hdr_add2s("From: ",reject.s); hdr_add2s("Reply-To: ",accept.s); if (!flagconfirm && !pmod && flagremote) { /* if remote admin add -allow- address */ qmail_puts(&qq,"Cc: "); /* for ezmlm-gate users */ strnum[fmt_ulong(strnum,(unsigned long) when)] = 0; cookie(hash,key.s,key.len-FLD_ALLOW,strnum,sender,"t"); if (!stralloc_copy(&line,&outlocal)) die_nomem(); if (!stralloc_cats(&line,"-allow-tc.")) die_nomem(); if (!stralloc_cats(&line,strnum)) die_nomem(); if (!stralloc_append(&line,".")) die_nomem(); if (!stralloc_catb(&line,hash,COOKIE)) die_nomem(); if (!stralloc_append(&line,"-")) die_nomem(); i = str_rchr(sender,'@'); if (!stralloc_catb(&line,sender,i)) die_nomem(); if (sender[i]) { if (!stralloc_append(&line,"=")) die_nomem(); if (!stralloc_cats(&line,sender + i + 1)) die_nomem(); } qmail_put(&qq,line.s,line.len); qmail_puts(&qq,"@"); qmail_put(&qq,outhost.s,outhost.len); qmail_puts(&qq,"\n"); } qmail_puts(&qq,"To: <"); if (flagconfirm) { if (sender) qmail_puts(&qq, sender); } else { if (!quote("ed,&outlocal)) die_nomem(); qmail_put(&qq,quoted.s,quoted.len); qmail_puts(&qq,"-moderators@"); qmail_put(&qq,outhost.s,outhost.len); } qmail_puts(&qq,">\n"); /* FIXME: Drop the custom subject hack and use hdr_listsubject1 */ if (!stralloc_copys(&subject,"Subject: ")) die_nomem(); if (flagconfirm) { if (confirmpost.len) { if (!stralloc_cat(&subject,&confirmpost)) die_nomem(); if (!stralloc_cats(&subject," ")) die_nomem(); } else { if (!stralloc_cats(&subject,TXT_CONFIRM_POST)) die_nomem(); } } else { if (!stralloc_cats(&subject,TXT_MODERATE)) die_nomem(); } if (!quote("ed,&outlocal)) die_nomem(); if (!stralloc_cat(&subject,"ed)) die_nomem(); if (!stralloc_append(&subject,"@")) die_nomem(); if (!stralloc_cat(&subject,&outhost)) die_nomem(); if (flagmime) { hdr_mime(CTYPE_MULTIPART); qmail_put(&qq,subject.s,subject.len); hdr_boundary(0); hdr_ctype(CTYPE_TEXT); hdr_transferenc(); } else { qmail_put(&qq,subject.s,subject.len); qmail_puts(&qq,"\n\n"); } copy(&qq,flagconfirm?"text/post-confirm":"text/mod-request",flagcd); if (flagcd == 'B') { encodeB("",0,&line,2); qmail_put(&qq,line.s,line.len); } if (substdio_put(&ssmsg,returnpath.s,returnpath.len) == -1) die_msg(); if (substdio_put(&ssmsg,mydtline.s,mydtline.len) == -1) die_msg(); substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf)); if (flagmime) { hdr_boundary(0); hdr_ctype(CTYPE_MESSAGE); qmail_puts(&qq, "\n"); } qmail_put(&qq,returnpath.s,returnpath.len); qmail_put(&qq,mydtline.s,mydtline.len); flaginheader = 1; for (;;) { if (getln(&ssin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,ERR_READ_INPUT); if (!match) break; if (line.len == 1) flaginheader = 0; if (flaginheader) { if ((line.len == mydtline.len) && !byte_diff(line.s,line.len,mydtline.s)) { close(fdmsg); /* be nice - clean up */ unlink(fnmsg.s); strerr_die2x(100,FATAL,ERR_LOOPING); } if (case_startb(line.s,line.len,"mailing-list:")) { close(fdmsg); /* be nice - clean up */ unlink(fnmsg.s); strerr_die2x(100,FATAL,ERR_MAILING_LIST); } } if (flagbody || flaginheader) /* skip body if !flagbody */ qmail_put(&qq,line.s,line.len); if (substdio_put(&ssmsg,line.s,line.len) == -1) die_msg(); } if (flagmime) hdr_boundary(1); /* close archive before qmail. Loss of qmail will result in re-run, and */ /* worst case this results in a duplicate msg sitting orphaned until it's */ /* cleaned out. */ if (substdio_flush(&ssmsg) == -1) die_msg(); if (fsync(fdmsg) == -1) die_msg(); if (fchmod(fdmsg,MODE_MOD_MSG | 0700) == -1) die_msg(); if (close(fdmsg) == -1) die_msg(); /* NFS stupidity */ close(fdlock); if (flagconfirm) { qmail_from(&qq,reject.s); /* envelope sender */ } else { if (!stralloc_copy(&line,&outlocal)) die_nomem(); if (!stralloc_cats(&line,"-return-@")) die_nomem(); if (!stralloc_cat(&line,&outhost)) die_nomem(); if (!stralloc_0(&line)) die_nomem(); qmail_from(&qq,line.s); /* envelope sender */ } if (flagconfirm) /* to sender */ qmail_to(&qq,sender); else if (pmod) /* to moderator only */ qmail_to(&qq,pmod); else { if (flagself) { /* to all moderators */ if (!stralloc_copys(&moderators,dir)) die_nomem(); if (!stralloc_cats(&moderators,"/mod")) die_nomem(); if (!stralloc_0(&moderators)) die_nomem(); } putsubs(moderators.s,0,0,52,subto,1); } if (*(err = qmail_close(&qq)) == '\0') { strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_die2x(0,"ezmlm-store: info: qp ",strnum); } else strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err+1); }
int main(int argc,char **argv) { int child; const char *sendargs[4]; stralloc addr = {0}; unsigned int pos = 0,pos2,poslocal,len; const char *cp; unsigned long hh = 4L; /* default time 04:12 */ unsigned long mm = 12L; const char *dow = "*"; /* day of week */ const char *qmail_inject = "/bin/qmail-inject "; char strnum[FMT_ULONG]; unsigned long uid,euid = 0; stralloc rp = {0}; stralloc user = {0}; stralloc euser = {0}; stralloc dir = {0}; stralloc listaddr = {0}; stralloc line = {0}; struct passwd *ppasswd; int match; int hostmatch; int localmatch; unsigned long dh,t; int founduser = 0; int listmatch = 0; int flagdigit = 0; int flagours; int foundlocal = 0; int foundmatch = 0; unsigned int nolists = 0; unsigned long maxlists; unsigned int lenhost,lenlocal; int fdin,fdout = -1; char *local = (char *) 0; /* list = local@host */ const char *host = (char *) 0; char *code = (char *) 0; /* digest code */ char inbuf[512]; substdio ssin; char outbuf[512]; substdio ssout; (void) umask(077); sig_pipeignore(); optind = getconfopt(argc,argv,options,0,0); if (flagt != 0) { pos = scan_ulong(flagt,&hh); if (flagt[pos++] != ':') die_usage(); (void) scan_ulong(flagt + pos,&mm); } if (flagw != 0) { dow = flagw; cp = flagw - 1; while (*(++cp)) { if (*cp >= '0' && *cp <= '7') { if (flagdigit) die_dow(); flagdigit = 1; } else if (*cp == ',') { if (!flagdigit) die_dow(); flagdigit = 0; } else die_dow(); } } if (flaglist + flagdelete + flagconfig > 1) strerr_die2x(100,FATAL,MSG(ERR_EXCLUSIVE)); uid = getuid(); if (uid && !(euid = geteuid())) strerr_die2x(100,FATAL,MSG(ERR_SUID)); if (!(ppasswd = getpwuid(uid))) strerr_die2x(100,FATAL,MSG(ERR_UID)); if (!stralloc_copys(&user,ppasswd->pw_name)) die_nomem(); if (!stralloc_0(&user)) die_nomem(); if (!(ppasswd = getpwuid(euid))) strerr_die2x(100,FATAL,MSG(ERR_EUID)); if (!stralloc_copys(&dir,ppasswd->pw_dir)) die_nomem(); if (!stralloc_0(&dir)) die_nomem(); if (!stralloc_copys(&euser,ppasswd->pw_name)) die_nomem(); if (!stralloc_0(&euser)) die_nomem(); wrap_chdir(dir.s); local = argv[optind++]; /* list address, optional for -c & -l */ if (!local) { if (!flagconfig && !flaglist) die_usage(); lenlocal = 0; lenhost = 0; } else { if (!stralloc_copys(&listaddr,local)) die_nomem(); if (!isclean(local,1)) die_argument(); pos = str_chr(local,'@'); lenlocal = pos; local[pos] = '\0'; host = local + pos + 1; lenhost = str_len(host); code = argv[optind]; if (!code) { /* ignored for -l, -c, and -d */ if (flagdelete || flaglist || flagconfig) /* get away with not putting code for delete */ code = (char*)"a"; /* a hack - so what! */ else die_usage(); } else if (!isclean(code,0)) die_argument(); } if ((fdin = open_read(TXT_EZCRONRC)) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,TXT_EZCRONRC)); /* first line is special */ substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf)); if (getln(&ssin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,TXT_EZCRONRC)); if (!match) strerr_die2sys(111,FATAL,MSG1(ERR_READ,TXT_EZCRONRC)); /* (since we have match line.len has to be >= 1) */ line.s[line.len - 1] = '\0'; if (!isclean(line.s,0)) /* host for bounces */ strerr_die2x(100,FATAL,MSG1(ERR_CFHOST,TXT_EZCRONRC)); if (!stralloc_copys(&rp,line.s)) die_nomem(); match = 1; for(;;) { if (!match) break; /* to allow last line without '\n' */ if (getln(&ssin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,TXT_EZCRONRC)); if (!line.len) break; line.s[line.len-1] = '\0'; if (!case_startb(line.s,line.len,user.s)) continue; pos = user.len - 1; if (pos >= line.len || line.s[pos] != ':') continue; founduser = 1; /* got user line */ break; } close(fdin); if (!founduser) strerr_die2x(100,FATAL,MSG(ERR_BADUSER)); if (flagconfig) { line.s[line.len-1] = '\n'; /* not very elegant ;-) */ substdio_fdbuf(&ssout,write,1,outbuf,sizeof(outbuf)); if (substdio_put(&ssout,line.s,line.len) == -1) strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT)); if (substdio_flush(&ssout) == -1) strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT)); _exit(0); } ++pos; /* points to first ':' */ len = str_chr(line.s+pos,':'); /* second ':' */ if (!line.s[pos + len]) die_syntax(&line); if (!local) { /* only -d and std left */ localmatch = 1; hostmatch = 1; } else { hostmatch = 0; if (len <= str_len(local)) if (!str_diffn(line.s+pos,local,len)) localmatch = 1; } pos += len + 1; len = str_chr(line.s + pos,':'); /* third */ if (!line.s[pos + len]) die_syntax(&line); if (local) { /* check host */ if (len == 0) /* empty host => any host */ hostmatch = 1; else if (len == str_len(host)) if (!case_diffb(line.s+pos,len,host)) hostmatch = 1; } pos += len + 1; pos += scan_ulong(line.s+pos,&maxlists); if (line.s[pos]) { /* check additional lists */ if (line.s[pos] != ':') die_syntax(&line); if (line.s[pos+1+str_chr(line.s+pos+1,':')]) die_syntax(&line); /* reminder lists are not separated by ':' */ /* otherwise a ':' or arg miscount will die */ /* silently */ if (local) { while (++pos < line.len) { len = str_chr(line.s + pos,'@'); if (len == lenlocal && !str_diffn(line.s + pos,local,len)) { pos += len; if (!line.s[pos]) break; pos++; len = str_chr(line.s+pos,','); if (len == lenhost && !case_diffb(line.s+pos,len,host)) { listmatch = 1; break; } } pos += len; } } } if (!listmatch) { if (!hostmatch) strerr_die2x(100,FATAL,MSG(ERR_BADHOST)); if (!localmatch) strerr_die2x(100,FATAL,MSG(ERR_BADLOCAL)); } /* assemble correct line */ if (!flaglist) { if (!stralloc_copyb(&addr,strnum,fmt_ulong(strnum,mm))) die_nomem(); if (!stralloc_cats(&addr," ")) die_nomem(); dh = 0L; if (deltah <= 3L) dh = deltah; else if (deltah <= 6L) dh = 6L; else if (deltah <= 12L) dh = 12L; else if (deltah <= 24L) dh = 24L; else if (deltah <= 48L) { if (dow[0] == '*') dow = "1,3,5"; } else if (deltah <= 72L) { if (dow[0] == '*') dow = "1,4"; } else if (dow[0] == '*') dow = "1"; if (!dh) { if (!stralloc_cats(&addr,"*")) die_nomem(); } else { if (!stralloc_catb(&addr,strnum,fmt_ulong(strnum,hh))) die_nomem(); for (t = hh + dh; t < hh + 24L; t+=dh) { if (!stralloc_cats(&addr,",")) die_nomem(); if (!stralloc_catb(&addr,strnum,fmt_ulong(strnum,t % 24L))) die_nomem(); } } if (!stralloc_cats(&addr," * * ")) die_nomem(); if (!stralloc_cats(&addr,dow)) die_nomem(); if (!stralloc_cats(&addr," ")) die_nomem(); if (!stralloc_cats(&addr,auto_qmail)) die_nomem(); if (!stralloc_cats(&addr,qmail_inject)) die_nomem(); if (!stralloc_cats(&addr,local)) die_nomem(); if (!stralloc_cats(&addr,"-dig-")) die_nomem(); if (!stralloc_cats(&addr,code)) die_nomem(); if (!stralloc_cats(&addr,"@")) die_nomem(); if (!stralloc_cats(&addr,host)) die_nomem(); /* feed 'Return-Path: <user@host>' to qmail-inject */ if (!stralloc_cats(&addr,"%Return-path: <")) die_nomem(); if (!stralloc_cats(&addr,user.s)) die_nomem(); if (!stralloc_cats(&addr,"@")) die_nomem(); if (!stralloc_cat(&addr,&rp)) die_nomem(); if (!stralloc_cats(&addr,">\n")) die_nomem(); } if (!stralloc_0(&addr)) die_nomem(); if (!flaglist) { /* now to rewrite crontab we need to lock */ lockfile("crontabl"); } /* if !flaglist */ if ((fdin = open_read("crontab")) == -1) { if (errno != error_noent) strerr_die2sys(111,FATAL,MSG1(ERR_READ,"crontab")); } else substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf)); if (flaglist) substdio_fdbuf(&ssout,write,1,outbuf,sizeof(outbuf)); else { if ((fdout = open_trunc("crontabn")) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"crontabn")); substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf)); } line.len = 0; if (fdin != -1) { for (;;) { if (!flaglist && line.len) { line.s[line.len-1] = '\n'; if (substdio_put(&ssout,line.s,line.len) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"crontabn")); } if (getln(&ssin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,"crontab")); if (!match) break; flagours = 0; /* assume entry is not ours */ foundlocal = 0; line.s[line.len - 1] = '\0'; /* match so at least 1 char */ pos = 0; while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos; if (line.s[pos] == '#') continue; /* cron comment */ pos = str_chr(line.s,'/'); if (!str_start(line.s+pos,auto_qmail)) continue; pos += str_len(auto_qmail); if (!str_start(line.s+pos,qmail_inject)) continue; pos += str_len(qmail_inject); poslocal = pos; pos = byte_rchr(line.s,line.len,'<'); /* should be Return-Path: < */ if (pos == line.len) continue; /* not ezmlm-cron line */ pos++; len = str_chr(line.s+pos,'@'); if (len == user.len - 1 && !str_diffn(line.s+pos,user.s,len)) { flagours = 1; ++nolists; /* belongs to this user */ } if (!local) { foundlocal = 1; } else { pos = poslocal + str_chr(line.s+poslocal,'@'); if (pos + lenhost +1 >= line.len) continue; if (case_diffb(line.s+pos+1,lenhost,host)) continue; if (line.s[pos+lenhost+1] != '%') continue; /* check local */ if (poslocal + lenlocal + 5 >= line.len) continue; if (!str_start(line.s+poslocal,local)) continue; pos2 = poslocal+lenlocal; if (!str_start(line.s+pos2,"-dig-")) continue; foundlocal = 1; } if (foundlocal) { foundmatch = 1; if (flaglist && (local || flagours)) { if (substdio_put(&ssout,line.s,line.len) == -1) strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT)); if (substdio_put(&ssout,"\n",1) == -1) strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT)); } line.len = 0; /* same - kill line */ if (flagours) --nolists; } } close(fdin); } if (flaglist) { if (substdio_flush(&ssout) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_FLUSH,"stdout")); if (foundmatch) /* means we had a match */ _exit(0); else strerr_die2x(100,FATAL,MSG(ERR_NO_MATCH)); } /* only -d and regular use left */ if (nolists >= maxlists && !flagdelete) strerr_die2x(100,FATAL,MSG(ERR_LISTNO)); if (!flagdelete) if (substdio_put(&ssout,addr.s,addr.len-1) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"crontabn")); if (flagdelete && !foundlocal) strerr_die2x(111,FATAL,MSG(ERR_NO_MATCH)); if (substdio_flush(&ssout) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_FLUSH,"crontabn")); if (fsync(fdout) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,"crontabn++")); if (close(fdout) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,"crontabn")); wrap_rename("crontabn","crontab"); sendargs[0] = "sh"; sendargs[1] = "-c"; if (!stralloc_copys(&line,auto_cron)) die_nomem(); if (!stralloc_cats(&line,"/crontab '")) die_nomem(); if (!stralloc_cats(&line,dir.s)) die_nomem(); if (!stralloc_cats(&line,"/crontab'")) die_nomem(); if (!stralloc_0(&line)) die_nomem(); sendargs[2] = line.s; sendargs[3] = 0; if ((child = wrap_fork()) == 0) { if (setreuid(euid,euid) == -1) strerr_die2sys(100,FATAL,MSG(ERR_SETUID)); wrap_execvp(sendargs); } /* parent */ switch (wrap_waitpid(child)) { case 0: _exit(0); default: strerr_die2x(111,FATAL,MSG(ERR_CRONTAB)); } }
void flush(void) { substdio_flush(&ssout); }
int main(int argc,char **argv) { char strnum[FMT_ULONG]; char *action; char *dtline; char *nhost; const char *err; unsigned int i; int match; int opt; sig_pipeignore(); opt = getconfopt(argc,argv,options,1,0); if (!(split = argv[opt])) split = "split"; if (flagdo) { sender = get_sender(); if (!sender) die_sender(); if (!*sender) strerr_die2x(100,FATAL,MSG(ERR_BOUNCE)); if (!sender[str_chr(sender,'@')]) strerr_die2x(100,FATAL,MSG(ERR_ANONYMOUS)); if (str_equal(sender,"#@[]")) strerr_die2x(100,FATAL,MSG(ERR_BOUNCE)); action = env_get("DEFAULT"); if (!action) strerr_die2x(100,FATAL,MSG(ERR_NODEFAULT)); if (!stralloc_copys(&target,sender)) die_nomem(); if (action[0]) { i = str_chr(action,'-'); if (action[i]) { action[i] = '\0'; if (!stralloc_copys(&target,action + i + 1)) die_nomem(); i = byte_rchr(target.s,target.len,'='); if (i < target.len) target.s[i] = '@'; } } if (!stralloc_0(&target)) die_nomem(); if (case_diffs(action,ACTION_SUBSCRIBE) && case_diffs(action,ALT_SUBSCRIBE) && case_diffs(action,ACTION_UNSUBSCRIBE) && case_diffs(action,ALT_UNSUBSCRIBE)) _exit(0); /* not for us */ if (findname()) { /* new sender */ if (!stralloc_copy(&from,&outlocal)) die_nomem(); if (!stralloc_cats(&from,"-return-@")) die_nomem(); if (!stralloc_cat(&from,&outhost)) die_nomem(); if (!stralloc_0(&from)) die_nomem(); nhost = name.s + str_rchr(name.s,'@'); /* name must have '@'*/ *(nhost++) = '\0'; if (!stralloc_copys(&to,name.s)) die_nomem(); /* local */ if (!stralloc_append(&to,'-')) die_nomem(); /* - */ if (!stralloc_cats(&to,action)) die_nomem(); /* subscribe */ if (!stralloc_append(&to,'-')) die_nomem(); /* - */ if (target.s[i = str_rchr(target.s,'@')]) target.s[i] = '='; if (!stralloc_cats(&to,target.s)) die_nomem(); /* target */ if (!stralloc_append(&to,'@')) die_nomem(); /* - */ if (!stralloc_cats(&to,nhost)) die_nomem(); /* host */ if (!stralloc_0(&to)) die_nomem(); dtline = env_get("DTLINE"); if (!dtline) strerr_die2x(100,FATAL,MSG(ERR_NODTLINE)); if (qmail_open(&qq) == -1) strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE)); qmail_puts(&qq,dtline); /* delivered-to */ if (qmail_copy(&qq,subfdin,0) != 0) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); qmail_from(&qq,from.s); qmail_to(&qq,to.s); if (*(err = qmail_close(&qq)) != '\0') strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1); strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_die3x(99,INFO,"qp ",strnum); } _exit(0); } else { for (;;) { if (getln(subfdin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); if (!match) break; if (line.len == 1) continue; /* ignore blank lines */ if (line.s[0] == '#') continue; /* ignore comments */ if (!stralloc_copy(&target,&line)) die_nomem(); target.s[target.len - 1] = '\0'; (void) findname(); if (!stralloc_cats(&name,": ")) die_nomem(); if (!stralloc_cats(&name,target.s)) die_nomem(); if (!stralloc_append(&name,'\n')) die_nomem(); if (substdio_put(subfdout,name.s,name.len) == -1) strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT)); } if (substdio_flush(subfdout) == -1) strerr_die2sys(111,FATAL,MSG(ERR_FLUSH_STDOUT)); _exit(0); } (void)argc; }
static void do_ed(char *action) { datetime_sec u; int flaggoodfield; int fd; char *x, *y; char *cp,*cplast,*cpnext,*cpafter; int flagdone; unsigned int len; const char *fname; unsigned int i; x = action + LENGTH_ED; x += scan_ulong(x,&u); if ((u > when) || (u < when - 100000)) die_cookie(); if (*x == '.') ++x; fname = x; x += str_chr(x,'.'); if (!*x) die_cookie(); *x = (char) 0; ++x; stralloc_copys(&fnedit,"text/"); stralloc_cats(&fnedit,fname); stralloc_0(&fnedit); y = fnedit.s + 5; /* after "text/" */ while (*++y) { /* Name should be guaranteed by the cookie, */ /* but better safe than sorry ... */ if (((*y > 'z') || (*y < 'a')) && (*y != '_')) strerr_die2x(100,FATAL,MSG(ERR_BAD_NAME)); if (*y == '_') *y = '-'; } lock(); /* file must not change while here */ switch (slurp(fnedit.s,&text,1024)) { case -1: strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnedit.s)); case 0: strerr_die5x(100,FATAL,dir,"/",fnedit.s,MSG(ERR_NOEXIST)); } stralloc_copy(&line,&text); subst_nuls(&line); stralloc_cat(&line,&fnedit); /* including '\0' */ strnum[fmt_ulong(strnum,(unsigned long) u)] = 0; cookie(hash,key.s,key.len,strnum,line.s,"-e"); if (str_len(x) != COOKIE) die_cookie(); if (byte_diff(hash,COOKIE,x)) die_cookie(); /* cookie is ok, file exists, lock's on, new file ends in '_' */ stralloc_copys(&fneditn,fnedit.s); stralloc_append(&fneditn,'_'); stralloc_0(&fneditn); fd = open_trunc(fneditn.s); if (fd == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s)); substdio_fdbuf(&sstext,write,fd,textbuf,sizeof(textbuf)); stralloc_copys("ed,""); /* clear */ stralloc_copys(&text,""); for (;;) { /* get message body */ if (getln(&ssin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); if (!match) break; stralloc_cat(&text,&line); } if (encin) { /* decode if necessary */ if (encin == 'B') decodeB(text.s,text.len,&line); else decodeQ(text.s,text.len,&line); stralloc_copy(&text,&line); } cp = text.s; cpafter = text.s+text.len; flaggoodfield = 0; flagdone = 0; len = 0; while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) { i = byte_chr(cp,cpnext-cp,'%'); if (i != (unsigned int) (cpnext - cp)) { if (!flaggoodfield) { /* MSG(TXT_EDIT_START)/END */ if (case_startb(cp+i,cpnext-cp-i,MSG(TXT_EDIT_START))) { /* start tag. Store users 'quote characters', e.g. '> ' */ stralloc_copyb("ed,cp,i); flaggoodfield = 1; cp = cpnext + 1; continue; } } else if (case_startb(cp+i,cpnext-cp-i,MSG(TXT_EDIT_END))) { flagdone = 1; break; } } if (flaggoodfield) { if ((len += cpnext - cp - quoted.len + 1) > MAXEDIT) strerr_die1x(100,MSG(ERR_EDSIZE)); if (quoted.len && cpnext-cp >= (int) quoted.len && !str_diffn(cp,quoted.s,quoted.len)) cp += quoted.len; /* skip quoting characters */ cplast = cpnext - 1; if (*cplast == '\r') /* CRLF -> '\n' for base64 encoding */ *cplast = '\n'; else ++cplast; if (substdio_put(&sstext,cp,cplast-cp+1) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s)); } cp = cpnext + 1; } if (!flagdone) strerr_die2x(100,FATAL,MSG(ERR_NO_MARK)); if (substdio_flush(&sstext) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s)); if (fsync(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,fneditn.s)); if (fchmod(fd, 0600) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CHMOD,fneditn.s)); if (close(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,fneditn.s)); wrap_rename(fneditn.s,fnedit.s); unlock(); hdr_subject(MSG1(SUB_EDIT_SUCCESS,fname)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/edit-done"); copybottom(0); qmail_to(&qq,sender); /* not necessarily from mod */ }
void main(int argc,char **argv) { DIR *bouncedir, *bsdir, *hdir; direntry *d, *ds; unsigned long bouncedate; unsigned long bouncetimeout = BOUNCE_TIMEOUT; unsigned long lockout = 0L; unsigned long ld; unsigned long ddir,dfile; int fdlock,fd; int opt; char ch; (void) umask(022); sig_pipeignore(); when = (unsigned long) now(); while ((opt = getopt(argc,argv,"dDl:t:vV")) != opteof) switch(opt) { case 'd': flagdig = 1; break; case 'D': flagdig = 0; break; case 'l': if (optarg) { /* lockout in seconds */ (void) scan_ulong(optarg,&lockout); } break; case 't': if (optarg) { /* bouncetimeout in days */ (void) scan_ulong(optarg,&bouncetimeout); bouncetimeout *= 3600L * 24L; } break; case 'v': case 'V': strerr_die2x(0, "ezmlm-warn version: ",auto_version); default: die_usage(); } startup(dir = argv[optind]); load_config(dir); getconf_ulong(©lines,"copylines",0,dir); if (flagdig) { if (!stralloc_copys(&digdir,dir)) die_nomem(); if (!stralloc_cats(&digdir,"/digest")) die_nomem(); if (!stralloc_0(&digdir)) die_nomem(); workdir = digdir.s; } else workdir = dir; if (!stralloc_copys(&fnlastd,workdir)) die_nomem(); if (!stralloc_cats(&fnlastd,"/bounce/lastd")) die_nomem(); if (!stralloc_0(&fnlastd)) die_nomem(); if (slurp(fnlastd.s,&lastd,16) == -1) /* last time d was scanned */ strerr_die4sys(111,FATAL,ERR_READ,fnlastd.s,": "); if (!stralloc_0(&lastd)) die_nomem(); (void) scan_ulong(lastd.s,&ld); if (!lockout) lockout = bouncetimeout / 50; /* 5.6 h for default timeout */ if (ld + lockout > when && ld < when) _exit(0); /* exit silently. Second check is to prevent lockup */ /* if lastd gets corrupted */ if (!stralloc_copy(&fnlasth,&fnlastd)) die_nomem(); fnlasth.s[fnlasth.len - 2] = 'h'; /* bad, but feels good ... */ if (flagdig) if (!stralloc_cats(&outlocal,"-digest")) die_nomem(); ddir = when / 10000; dfile = when - 10000 * ddir; if (!stralloc_copys(&line,workdir)) die_nomem(); if (!stralloc_cats(&line,"/lockbounce")) die_nomem(); if (!stralloc_0(&line)) die_nomem(); fdlock = lockfile(line.s); if (!stralloc_copys(&line,workdir)) die_nomem(); if (!stralloc_cats(&line,"/bounce/d")) die_nomem(); if (!stralloc_0(&line)) die_nomem(); bouncedir = opendir(line.s); if (!bouncedir) { if (errno != error_noent) strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": "); else _exit(0); /* no bouncedir - no bounces! */ } while ((d = readdir(bouncedir))) { /* dxxx/ */ if (str_equal(d->d_name,".")) continue; if (str_equal(d->d_name,"..")) continue; scan_ulong(d->d_name,&bouncedate); /* since we do entire dir, we do files that are not old enough. */ /* to not do this and accept a delay of 10000s (2.8h) of the oldest */ /* bounce we add to bouncedate. We don't if bouncetimeout=0 so that */ /* that setting still processes _all_ bounces. */ if (bouncetimeout) ++bouncedate; if (when >= bouncedate * 10000 + bouncetimeout) { if (!stralloc_copys(&bdname,workdir)) die_nomem(); if (!stralloc_cats(&bdname,"/bounce/d/")) die_nomem(); if (!stralloc_cats(&bdname,d->d_name)) die_nomem(); if (!stralloc_0(&bdname)) die_nomem(); bsdir = opendir(bdname.s); if (!bsdir) { if (errno != error_notdir) strerr_die4sys(111,FATAL,ERR_OPEN,bdname.s,":y "); else { /* leftover nnnnn_dmmmmm file */ if (unlink(bdname.s) == -1) strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": "); continue; } } while ((ds = readdir(bsdir))) { /* dxxxx/yyyy */ if (str_equal(ds->d_name,".")) continue; if (str_equal(ds->d_name,"..")) continue; if (!stralloc_copy(&fn,&bdname)) die_nomem(); /* '\0' at end */ fn.s[fn.len - 1] = '/'; if (!stralloc_cats(&fn,ds->d_name)) die_nomem(); if (!stralloc_0(&fn)) die_nomem(); if ((ds->d_name[0] == 'd') || (ds->d_name[0] == 'w')) doit(ds->d_name[0] == 'w'); else /* other stuff is junk */ if (unlink(fn.s) == -1) strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": "); } closedir(bsdir); if (rmdir(bdname.s) == -1) /* the directory itself */ if (errno != error_noent) strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": "); } } closedir(bouncedir); if (!stralloc_copy(&line,&fnlastd)) die_nomem(); line.s[line.len - 2] = 'D'; fd = open_trunc(line.s); /* write lastd. Do safe */ /* since we read before lock*/ if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": "); substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); if (substdio_put(&ssout,strnum,fmt_ulong(strnum,when)) == -1) strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": "); if (substdio_put(&ssout,"\n",1) == -1) /* prettier */ strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": "); if (substdio_flush(&ssout) == -1) strerr_die4sys(111,FATAL,ERR_FLUSH,line.s,": "); if (fsync(fd) == -1) strerr_die4sys(111,FATAL,ERR_SYNC,line.s,": "); if (close(fd) == -1) strerr_die4sys(111,FATAL,ERR_CLOSE,line.s,": "); if (rename(line.s,fnlastd.s) == -1) strerr_die4sys(111,FATAL,ERR_MOVE,fnlastd.s,": "); /* no need to do h dir cleaning more than */ /* once per 1-2 days (17-30 days for all) */ if (stat(fnlasth.s,&st) == -1) { if (errno != error_noent) strerr_die4sys(111,FATAL,ERR_STAT,fnlasth.s,": "); } else if (when < (unsigned long)st.st_mtime + 100000 && when > (unsigned long)st.st_mtime) _exit(0); /* 2nd comp to guard against corruption */ if (slurp(fnlasth.s,&lasth,16) == -1) /* last h cleaned */ strerr_die4sys(111,FATAL,ERR_READ,fnlasth.s,": "); if (!stralloc_0(&lasth)) die_nomem(); ch = lasth.s[0]; /* clean h */ if (ch >= 'a' && ch <= 'o') ++ch; else ch = 'a'; lasth.s[0] = ch; if (!stralloc_copys(&line,workdir)) die_nomem(); if (!stralloc_cats(&line,"/bounce/h/")) die_nomem(); if (!stralloc_catb(&line,lasth.s,1)) die_nomem(); if (!stralloc_0(&line)) die_nomem(); hdir = opendir(line.s); /* clean ./h/xxxxxx */ if (!hdir) { if (errno != error_noent) strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": "); } else { while ((d = readdir(hdir))) { if (str_equal(d->d_name,".")) continue; if (str_equal(d->d_name,"..")) continue; if (!stralloc_copys(&fn,line.s)) die_nomem(); if (!stralloc_append(&fn,"/")) die_nomem(); if (!stralloc_cats(&fn,d->d_name)) die_nomem(); if (!stralloc_0(&fn)) die_nomem(); if (stat(fn.s,&st) == -1) { if (errno == error_noent) continue; strerr_die4sys(111,FATAL,ERR_STAT,fn.s,": "); } if (when > st.st_mtime + 3 * bouncetimeout) if (unlink(fn.s) == -1) strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": "); } closedir(hdir); } fd = open_trunc(fnlasth.s); /* write lasth */ if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": "); substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); if (substdio_put(&ssout,lasth.s,1) == -1) strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": "); if (substdio_put(&ssout,"\n",1) == -1) /* prettier */ strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": "); if (substdio_flush(&ssout) == -1) strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": "); (void) close(fd); /* no big loss. No reason to flush/sync */ /* See check of ld above to guard against */ /* it being corrupted and > when */ closesub(); _exit(0); }
int substdio_putflush(substdio *s,const char *buf,int len) { if (substdio_flush(s) == -1) return -1; return allwrite(s->op,s->fd,buf,len); }
int std_subscribe(const char *dir, const char *subdir, const char *userhost, int flagadd, const char *comment, const char *event, int forcehash) /* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database */ /* dbname. Comment is e.g. the subscriber from line or name. It is added to */ /* the log. Event is the action type, e.g. "probe", "manual", etc. The */ /* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0 */ /* on failure. If flagmysql is set and the file "sql" is found in the */ /* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */ /* >=0 it is used in place of the calculated hash. This makes it possible to */ /* add addresses with a hash that does not exist. forcehash has to be 0..99. */ /* for unsubscribes, the address is only removed if forcehash matches the */ /* actual hash. This way, ezmlm-manage can be prevented from touching certain*/ /* addresses that can only be removed by ezmlm-unsub. Usually, this would be */ /* used for sublist addresses (to avoid removal) and sublist aliases (to */ /* prevent users from subscribing them (although the cookie mechanism would */ /* prevent the resulting duplicate message from being distributed. */ { int fdlock; unsigned int j; unsigned char ch,lcch; int match; int flagwasthere; if (userhost[str_chr(userhost,'\n')]) strerr_die2x(100,FATAL,ERR_ADDR_NL); if (!stralloc_copys(&addr,"T")) die_nomem(); if (!stralloc_cats(&addr,userhost)) die_nomem(); if (addr.len > 401) strerr_die2x(100,FATAL,ERR_ADDR_LONG); j = byte_rchr(addr.s,addr.len,'@'); if (j == addr.len) strerr_die2x(100,FATAL,ERR_ADDR_AT); case_lowerb(addr.s + j + 1,addr.len - j - 1); if (!stralloc_copy(&lcaddr,&addr)) die_nomem(); case_lowerb(lcaddr.s + 1,j - 1); /* make all-lc version of address */ if (forcehash >= 0 && forcehash <= 52) { ch = lcch = 64 + (unsigned char) forcehash; } else { ch = 64 + subhashsa(&addr); lcch = 64 + subhashsa(&lcaddr); } if (!stralloc_0(&addr)) die_nomem(); if (!stralloc_0(&lcaddr)) die_nomem(); std_makepath(&fn,dir,subdir,"/subscribers/",lcch); std_makepath(&fnlock,dir,subdir,"/lock",0); if (!stralloc_copyb(&fnnew,fn.s,fn.len-1)) die_nomem(); /* code later depends on fnnew = fn + 'n' */ if (!stralloc_cats(&fnnew,"n")) die_nomem(); if (!stralloc_0(&fnnew)) die_nomem(); fdlock = lockfile(fnlock.s); /* do lower case hashed version first */ fdnew = open_trunc(fnnew.s); if (fdnew == -1) die_write(); substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); flagwasthere = 0; fd = open_read(fn.s); if (fd == -1) { if (errno != error_noent) { close(fdnew); die_read(); } } else { substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); for (;;) { if (getln(&ss,&line,&match,'\0') == -1) { close(fd); close(fdnew); die_read(); } if (!match) break; if (line.len == addr.len) if (!case_diffb(line.s,line.len,addr.s)) { flagwasthere = 1; if (!flagadd) continue; } if (substdio_bput(&ssnew,line.s,line.len) == -1) { close(fd); close(fdnew); die_write(); } } close(fd); } if (flagadd && !flagwasthere) if (substdio_bput(&ssnew,addr.s,addr.len) == -1) { close(fdnew); die_write(); } if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(); } if (fsync(fdnew) == -1) { close(fdnew); die_write(); } close(fdnew); if (rename(fnnew.s,fn.s) == -1) strerr_die6sys(111,FATAL,ERR_MOVE,fnnew.s," to ",fn.s,": "); if ((ch == lcch) || flagwasthere) { close(fdlock); if (flagadd ^ flagwasthere) { if (!stralloc_0(&addr)) die_nomem(); logaddr(dir,subdir,event,addr.s+1,comment); return 1; } return 0; } /* If unsub and not found and hashed differ, OR */ /* sub and not found (so added with new hash) */ /* do the 'case-dependent' hash */ fn.s[fn.len - 2] = ch; fnnew.s[fnnew.len - 3] = ch; fdnew = open_trunc(fnnew.s); if (fdnew == -1) die_write(); substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); fd = open_read(fn.s); if (fd == -1) { if (errno != error_noent) { close(fdnew); die_read(); } } else { substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); for (;;) { if (getln(&ss,&line,&match,'\0') == -1) { close(fd); close(fdnew); die_read(); } if (!match) break; if (line.len == addr.len) if (!case_diffb(line.s,line.len,addr.s)) { flagwasthere = 1; continue; /* always want to remove from case-sensitive hash */ } if (substdio_bput(&ssnew,line.s,line.len) == -1) { close(fd); close(fdnew); die_write(); } } close(fd); } if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(); } if (fsync(fdnew) == -1) { close(fdnew); die_write(); } close(fdnew); if (rename(fnnew.s,fn.s) == -1) strerr_die6sys(111,FATAL,ERR_MOVE,fnnew.s," to ",fn.s,": "); close(fdlock); if (flagadd ^ flagwasthere) { if (!stralloc_0(&addr)) die_nomem(); logaddr(dir,subdir,event,addr.s+1,comment); return 1; } return 0; }
void main(int argc,char **argv) { char *dir; char *action; char *dtline; char *nhost; const char *err; unsigned int i; int match; int opt; sig_pipeignore(); while ((opt = getopt(argc,argv,"dDvV")) != opteof) { switch (opt) { case 'd': flagdo = 1; break; case 'D': flagdo = 0; break; case 'v': case 'V': strerr_die2x(0, "ezmlm-split version: ",auto_version); default: die_usage(); } } startup(dir = argv[optind++]); load_config(dir); if (!(split = argv[optind])) split = "split"; if (flagdo) { sender = env_get("SENDER"); if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER); if (!*sender) strerr_die2x(100,FATAL,ERR_BOUNCE); if (!sender[str_chr(sender,'@')]) strerr_die2x(100,FATAL,ERR_ANONYMOUS); if (str_equal(sender,"#@[]")) strerr_die2x(100,FATAL,ERR_BOUNCE); action = env_get("DEFAULT"); if (!action) strerr_die2x(100,FATAL,ERR_NODEFAULT); if (!stralloc_copys(&target,sender)) die_nomem(); if (action[0]) { i = str_chr(action,'-'); if (action[i]) { action[i] = '\0'; if (!stralloc_copys(&target,action + i + 1)) die_nomem(); i = byte_rchr(target.s,target.len,'='); if (i < target.len) target.s[i] = '@'; } } if (!stralloc_0(&target)) die_nomem(); if (case_diffs(action,ACTION_SUBSCRIBE) && case_diffs(action,ALT_SUBSCRIBE) && case_diffs(action,ACTION_UNSUBSCRIBE) && case_diffs(action,ALT_UNSUBSCRIBE)) _exit(0); /* not for us */ if (findname()) { /* new sender */ if (!stralloc_copy(&from,&outlocal)) die_nomem(); if (!stralloc_cats(&from,"-return-@")) die_nomem(); if (!stralloc_cat(&from,&outhost)) die_nomem(); if (!stralloc_0(&from)) die_nomem(); nhost = name.s + str_rchr(name.s,'@'); /* name must have '@'*/ *(nhost++) = '\0'; if (!stralloc_copys(&to,name.s)) die_nomem(); /* local */ if (!stralloc_append(&to,"-")) die_nomem(); /* - */ if (!stralloc_cats(&to,action)) die_nomem(); /* subscribe */ if (!stralloc_append(&to,"-")) die_nomem(); /* - */ if (target.s[i = str_rchr(target.s,'@')]) target.s[i] = '='; if (!stralloc_cats(&to,target.s)) die_nomem(); /* target */ if (!stralloc_append(&to,"@")) die_nomem(); /* - */ if (!stralloc_cats(&to,nhost)) die_nomem(); /* host */ if (!stralloc_0(&to)) die_nomem(); dtline = env_get("DTLINE"); if (!dtline) strerr_die2x(100,FATAL,ERR_NODTLINE); if (qmail_open(&qq,(stralloc *) 0) == -1) strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE); qmail_puts(&qq,dtline); /* delivered-to */ if (qmail_copy(&qq,subfdin,0) != 0) strerr_die2sys(111,FATAL,ERR_READ_INPUT); qmail_from(&qq,from.s); qmail_to(&qq,to.s); if (*(err = qmail_close(&qq)) != '\0') strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1); strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_die3x(99,INFO,"qp ",strnum); } _exit(0); } else { for (;;) { if (getln(subfdin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,ERR_READ_INPUT); if (!match) break; if (line.len == 1) continue; /* ignore blank lines */ if (line.s[0] == '#') continue; /* ignore comments */ if (!stralloc_copy(&target,&line)) die_nomem(); target.s[target.len - 1] = '\0'; (void) findname(); if (!stralloc_cats(&name,": ")) die_nomem(); if (!stralloc_cats(&name,target.s)) die_nomem(); if (!stralloc_append(&name,"\n")) die_nomem(); if (substdio_put(subfdout,name.s,name.len) == -1) strerr_die2sys(111,ERR_WRITE,"output: "); } if (substdio_flush(subfdout) == -1) strerr_die2sys(111,ERR_FLUSH,"output: "); _exit(0); } (void)argc; }