void main(int argc,char **argv) { int fdlock; unsigned long delay; (void) umask(022); sig_pipeignore(); when = now(); getconfopt(argc,argv,options,1,0); if (flagreturn < 0) /* default to returning timed-out messages */ flagreturn = !getconf_isset("noreturnposts"); getconf_line(&modtime,"modtime",0); if (!stralloc_0(&modtime)) die_nomem(); scan_ulong(modtime.s,&delay); if (!delay) delay = DELAY_DEFAULT; else if (delay < DELAY_MIN) delay = DELAY_MIN; else if (delay > DELAY_MAX) delay = DELAY_MAX; older = (unsigned long) when - 3600L * delay; /* delay is in hours */ fdlock = lockfile("mod/lock"); dodir("mod/pending/",flagreturn); dodir("mod/accepted/",0); dodir("mod/rejected/",0); dodir("mod/unconfirmed/",0); _exit(0); }
int main(int argc, char **argv) { sig_alarmcatch(die); sig_pipeignore(); hostname = argv[1]; if (!hostname) die_usage(); childargs = argv + 2; if (!*childargs) die_usage(); pop3_greet(); commands(&ssin,pop3commands); return 1; }
int main(int argc,char **argv) { const char *dir; const char *sender; const char *moddir; int opt; int ret = 0; unsigned int i,j; const char *program; stralloc *opts; stralloc cmds = {0}; int child; int ismod; umask(022); sig_pipeignore(); if (!stralloc_copys(&sendopt,"-")) die_nomem(); if (!stralloc_copys(&storeopt,"-")) die_nomem(); opt = getconfopt(argc,argv,options,1,&dir); /* storeopts to ezmlm-store only. Others to both (ezmlm-store may */ /* pass them on to ezmlm-send. */ if (!stralloc_catb(&storeopt,sendopt.s+1,sendopt.len-1)) die_nomem(); initsub(0); sender = get_sender(); ismod = 0; if (queryext) { getconf(&cmds,queryext,1); i = 0; for (j = 0;j < cmds.len; ++j) if (!cmds.s[j]) { switch (cmds.s[i]) { case '\0': case '#': break; /* ignore blank/comment */ case '|': ret = mailprog(cmds.s + i + 1); break; default: ret = mailprog(cmds.s + i); break; } if (ret) break; i = j + 1; } if (!ret || ret == 99) /* 111 => temp error */ ismod = 1; /* 0, 99 => post */ /* other => moderate */ } moddir = argv[opt++]; if (moddir && !ret) { /* if exit 0 and moddir, add issub */ ismod = 0; while (moddir && !ismod && sender) { ismod = issub(moddir,sender,0); closesub(); moddir = argv[opt++]; } } if (ismod) { program = "/ezmlm-send"; opts = &sendopt; } else { program = "/ezmlm-store"; opts = &storeopt; } if (dontact) { substdio_puts(subfderr, auto_bin()); substdio_puts(subfderr, program); substdio_put(subfderr, " ", 1); substdio_put(subfderr, opts->s, opts->len); substdio_put(subfderr, " ", 1); substdio_puts(subfderr, dir); substdio_putsflush(subfderr, "\n"); _exit(0); } if ((child = wrap_fork()) == 0) wrap_execbin(program, opts, dir); /* parent */ wrap_exitcode(child); _exit(0); }
int main(int argc,char **argv) { char *action; const char *err; unsigned int i; int act = AC_NONE; /* desired action */ unsigned int actlen = 0;/* str_len of above */ (void) umask(022); sig_pipeignore(); when = now(); getconfopt(argc,argv,options,1,&dir); initsub(0); sender = get_sender(); if (!sender) die_sender(); action = env_get("DEFAULT"); if (!action) strerr_die2x(100,FATAL,MSG(ERR_NODEFAULT)); 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 = set_workdir(action); stralloc_copys(&target,sender); if (action[0]) { i = str_chr(action,'-'); if (action[i]) { action[i] = 0; stralloc_copys(&target,action + i + 1); i = byte_rchr(target.s,target.len,'='); if (i < target.len) target.s[i] = '@'; } } stralloc_0(&target); set_cptarget(target.s); /* for copy() */ make_verptarget(); act = get_act_ismod(action,&actlen); stralloc_copy(&from,&outlocal); stralloc_cats(&from,"-return-@"); stralloc_cat(&from,&outhost); stralloc_0(&from); if (qmail_open(&qq) == -1) strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE)); msg_headers(act); if (act == AC_SUBSCRIBE) do_subscribe(action); else if (act == AC_SC) do_sc(action); else if (str_start(action,ACTION_RC)) do_rc_tc(action,ACTION_RC); else if(str_start(action,ACTION_TC)) do_rc_tc(action,ACTION_TC); else if (act == AC_UNSUBSCRIBE) do_unsubscribe(action); else if (str_start(action,ACTION_UC)) do_uc(action); else if (str_start(action,ACTION_VC)) do_vc_wc(action,ACTION_VC); else if (str_start(action,ACTION_WC)) do_vc_wc(action,ACTION_WC); else if (act == AC_LIST || act == AC_LISTN) do_list(act); else if (act == AC_LOG) do_log(action,actlen); else if (act == AC_EDIT) do_edit(action); else if (str_start(action,ACTION_ED)) do_ed(action); else if (act == AC_GET) do_get(action); else if (case_starts(action,ACTION_QUERY) || case_starts(action,ALT_QUERY)) do_query(); else if (case_starts(action,ACTION_INFO) || case_starts(action,ALT_INFO)) do_info(); else if (case_starts(action,ACTION_FAQ) || case_starts(action,ALT_FAQ)) do_faq(); else if (ismod && (act == AC_HELP)) do_mod_help(); else do_help(); err = qmail_close(&qq); closesub(); if (*err != '\0') strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1); strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_die3x(0,INFO,"qp ",strnum); }
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 main(int argc,char **argv) { char *def; char *local; const char *action = ""; char *psz; const char *err; int fd; unsigned int i,j; int flagremote; int match; int goodexit = 0; /* exit code for normal exit */ /* in manager this will be set to 0 */ unsigned long from,u,to,issue,prevmax; unsigned long mno = 0; unsigned long chunk; unsigned long subs = 0; unsigned int pos,pos1; unsigned int len; int opt; char outformat = 0; msgentry *msgtable; subentry *subtable; authentry *authtable; dateentry *datetable; struct datetime dt; char date[DATE822FMT]; (void) umask(022); sig_pipeignore(); when = now(); datetime_tai(&dt,when); opt = getconfopt(argc,argv,options,1,0); initsub(0); if (flagformat != 0) if (FORMATS[str_chr(FORMATS,flagformat[0])]) outformat = flagformat[0]; if (outformat == 0) { outformat = (getconf_line(&line,"digformat",0) && FORMATS[str_chr(FORMATS,line.s[0])]) ? line.s[0] : DEFAULT_FORMAT; } /* code to activate digest (-digest-code)*/ if ((digestcode = argv[opt]) == 0) { if (getconf_line(&digestcodefile,"digestcode",0) && digestcodefile.len > 0) { if (!stralloc_0(&digestcodefile)) die_nomem(); digestcode = digestcodefile.s; } } /* ignore any extra args */ if (!stralloc_copy(&subject,&outlocal)) die_nomem(); /* for subjects */ if (!stralloc_copy(&listname,&outlocal)) die_nomem(); /* for content disp */ local = env_get("LOCAL"); def = env_get("DEFAULT"); sender = get_sender(); if (local && *local) { /* in editor local = outlocal */ if (!sender) strerr_die2x(100,FATAL,MSG(ERR_NOSENDER)); if (!*sender) strerr_die2x(100,FATAL,MSG(ERR_BOUNCE)); if (str_equal(sender,"#@[]")) strerr_die2x(100,FATAL,MSG(ERR_BOUNCE)); if (!sender[str_chr(sender,'@')]) strerr_die2x(100,FATAL,MSG(ERR_ANONYMOUS)); if (def) { if (*def) { action = def; goodexit = 99; } else _exit(0); /* list-@host should do -help from manager */ } else { /* editor */ act = AC_DIGEST; /* on list-@host ! */ flageditor = 1; /* to avoid Mailing-list error on sublists */ /* when running out of dir/editor. */ } if (case_starts(action,"dig")) { action += 3; if (action[0] == '-' || action [0] == '.') { action++; if (!digestcode) strerr_die2x(100,FATAL,MSG(ERR_BAD_DIGCODE)); len = str_len(digestcode); if (len <= str_len(action) && case_startb(action,len,digestcode)) { if (FORMATS[str_chr(FORMATS,*(action+len))]) outformat = *(action+len); act = AC_DIGEST; } else strerr_die2x(100,FATAL,MSG(ERR_BAD_DIGCODE)); } } } else /* Command line operation */ act = AC_DIGEST; /* Things we deal with. If anything else just die with success! */ /* At the moment this is -index, -thread, and -get. */ /* If flagdo = 0 we only service -dig commands. This is to support*/ /* "secret" lists that are still archived and digested. -c on */ /* cmd line. */ if (act == AC_NONE) { if (case_equals(action,ACTION_DIGEST)) { act = AC_GET; /* list-digest@ => msg since last digest */ action = ACTION_GET; } else if (case_starts(action,ACTION_GET) || case_starts(action,ALT_GET)) act = AC_GET; else if (case_starts(action,ACTION_INDEX) || case_starts(action,ALT_INDEX)) act = AC_INDEX; else if (case_starts(action,ACTION_THREAD) || case_starts(action,ALT_THREAD)) act = AC_THREAD; } if (act == AC_NONE) /* not for us. Pass the buck. */ _exit(0); if (act != AC_INDEX) { /* need to do header processing */ if(!getconf(&digheaders,"digheaders",0)) { if(!stralloc_copys(&digheaders,digsz)) die_nomem(); if (!stralloc_0(&digheaders)) die_nomem(); psz = digheaders.s; while (*psz) { if (*psz == '\\') *psz = '\0'; ++psz; } } if (!constmap_init(&digheadersmap,digheaders.s,digheaders.len,0)) die_nomem(); } if (act != AC_DIGEST) { if (!flagdo) /* only do digests */ strerr_die2x(100,FATAL,MSG(ERR_NOCMD)); if (flagpublic < 0) flagpublic = !getconf_isset("modgetonly") && getconf_isset("public"); if (!flagpublic) { /* This all to take care of non-public lists. They should*/ /* still do digests, but do other things only for */ /* moderators that have remote access. Since this is rare*/ /* efforts have been made to keep everything that's not */ /* needed elsewhere in here. */ getconf_line(&moddir,"modsub",0); flagremote = getconf_line(&line,"remote",0); if (!flagremote) strerr_die2x(100,FATAL,MSG(ERR_NOT_PUBLIC)); if (!moddir.len) { if (line.len) { if (!stralloc_copy(&moddir,&line)) die_nomem(); } else { if (!stralloc_copys(&moddir,"mod")) die_nomem(); } } if (!stralloc_0(&moddir)) die_nomem(); ismod = issub(moddir.s,sender,&mod); if (!ismod) /* sender = moderator? */ strerr_die2x(100,FATAL,MSG(ERR_NOT_PUBLIC)); } } if (act == AC_DIGEST) { workdir = "digest"; if (!stralloc_cats(&outlocal,"-digest")) die_nomem(); if (getconf_line(&line,"chunk",0)) { if (!stralloc_0(&line)) die_nomem(); (void) scan_ulong(line.s,&chunk); /* same chunk as main list */ if (chunk == 0) /* limit range to 1-53 */ chunk = 1L; else if (chunk > 52) chunk = 52L; } else { chunk = 0L; } } else workdir = "."; if (!flagarchived) strerr_die2x(100,FATAL,MSG(ERR_NOT_ARCHIVED)); if (qmail_open(&qq) == -1) strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE)); set_cpnum(""); /* default for <#n#> replacement */ switch (act) { case AC_DIGEST: /* -dig{.|-}'digestcode'[f] returns an rfc1153 digest */ /* of messages from the archive. Messages */ /* dignum+1 through the last message received by the list are processed and */ /* dignum is updated to the last message processed. digissue is advanced. */ get_num(); /* max = last successful message */ to = max; lockup(); /* another digest could corrupt dignum */ /* but will be saved only if flagdigrange==0 */ if(getconf_line(&num,"dignum",0)) { if(!stralloc_0(&num)) die_nomem(); pos = scan_ulong(num.s,&prevmax); if (num.s[pos] == ':') pos++; pos += 1 + scan_ulong(num.s+pos,&cumsize); /* last cumsize */ if (num.s[pos] == ':') pos++; scan_ulong(num.s+pos,&digwhen); /* last reg dig */ } else { prevmax = 0L; cumsize = 0L; digwhen = 0L; } mno = prevmax + 1L; if(!max || mno > max) /* if a digest-list is "sending" the request, */ /* don't make noise: errors go to postmaster!*/ strerr_die2x(goodexit,FATAL,MSG(ERR_EMPTY_DIGEST)); szmsgnum[fmt_ulong(szmsgnum,mno)] = '\0'; set_cpnum(szmsgnum); /* for copy */ /* prepare subject to get entropy for tagmsg*/ if (!stralloc_cats(&subject," Digest ")) die_nomem(); if (!stralloc_catb(&subject,date,date822fmt(date,&dt)-1)) die_nomem(); /* skip trailing in date '\n' */ if (!stralloc_cats(&subject," Issue ")) die_nomem(); if (getconf_line(&num,"digissue",0)) { if(!stralloc_0(&num)) die_nomem(); scan_ulong(num.s,&issue); issue++; } else { issue = 1; } if (!stralloc_catb(&subject,strnum,fmt_ulong(strnum,issue))) die_nomem(); /* use the subject as entropy */ if (!stralloc_copy(&line,&subject)) die_nomem(); if (!stralloc_0(&line)) die_nomem(); if (!stralloc_ready(&seed,HASHLEN+1)) die_nomem(); seed.len = HASHLEN + 1; seed.s[HASHLEN] = '\0'; makehash(line.s,line.len,seed.s); if (chunk) { /* only if slaves are used */ qmail_puts(&qq,"Ezauth: "); qmail_put(&qq,seed.s,HASHLEN); qmail_puts(&qq,"\n"); } doheaders(); qmail_puts(&qq,"To: "); if (!quote("ed,&listname)) die_nomem(); qmail_put(&qq,quoted.s,quoted.len); qmail_puts(&qq,"@"); qmail_put(&qq,outhost.s,outhost.len); qmail_puts(&qq,"\n"); if (flagindexed && (outformat != NATIVE)) idx_mkthreads(&msgtable,&subtable,&authtable,&datetable, mno,to,max,flaglocked); else idx_mklist(&msgtable,&subtable,&authtable,mno,to); digest(msgtable,subtable,authtable,mno,to,&subject,AC_DIGEST,outformat); write_ulong(issue,0L,0L,"digissue","digissuen"); write_ulong(max,cumsizen, (unsigned long) when,"dignum","dignumn"); break; case AC_GET: /* -get[-|\.][[num].num2] copies archive num-num2. num & num2 are adjusted */ /* to be > 0 and <= last message, to num2 >= num and to num2-num <= MAXGET. */ zapnonsub(ACTION_GET); /* restrict to subs if requested */ tosender(); /* for rfc1153 */ if (!stralloc_cats(&subject," Digest of: ")) die_nomem(); if (!stralloc_cats(&subject,action)) die_nomem(); to = 0; pos = str_len(ACTION_GET); if (!case_starts(action,ACTION_GET)) pos = str_len(ALT_GET); if (FORMATS[str_chr(FORMATS,action[pos])]) { outformat = action[pos]; ++pos; } /* optional - or . after '-get' */ if (action[pos] == '-' || action[pos] == '.') pos++; get_num(); /* max = last successful message */ /* accept any separator. It may be */ /* the terminal '\n', but then */ /* scan will = 0 on the \0 so should*/ /* be safe */ if (!max) strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST)); szmsgnum[fmt_ulong(szmsgnum,max)] = '\0'; set_cpnum(szmsgnum); /* for copy this is the latest message arch'd*/ doheaders(); if(action[pos += scan_ulong(action + pos,&u)]) scan_ulong(action + pos + 1, &to); if (u == 0 && to == 0) { /* default: messages since last */ /* digest, or last MAXGET if too many */ to= max; u = dignum(); if (u == 0) { /* no digest => last up to HISTGET msgs */ to = max; if (max > HISTGET) u = max - HISTGET; else u = 1; } if (to - u >= MAXGET) u = to - MAXGET + 1; /* max MAXGET */ } else if (u > max) { if (to) { /* -get.999999_x returns 30 and msg since last*/ to = max; /* digest 30*/ u = dignum(); if (u > HISTGET) u -= HISTGET; else u = 1; if (to - u >= MAXGET) u = to - MAXGET + 1; } else u = max; } if (u == 0) u = 1; /* -get.5 => 1-5 */ if (to < u) to = u; /* -get23_2 => 23 */ if (to >= u + MAXGET) to = u + MAXGET - 1; /* no more than MAXGET at a time */ if (to > max) to = max; if (flagindexed && (outformat != NATIVE)) /* fake out threading */ idx_mkthreads(&msgtable,&subtable,&authtable,&datetable, u,to,max,0); else idx_mklist(&msgtable,&subtable,&authtable,u,to); digest(msgtable,subtable,authtable,u,to,&subject,AC_GET,outformat); break; case AC_INDEX: /* -index[f][#|-|\.][[num][.num2] Show subject index for messages num-num2 in*/ /* sets of 100. */ /* Default last 2 sets. num and num2 are made reasonable as for get. num2 is */ /* limited to num+MAXINDEX to limit the amount of data sent. */ if (!flagindexed) strerr_die2x(100,FATAL,MSG(ERR_NOT_INDEXED)); zapnonsub(ACTION_INDEX); /* restrict to subs if requested */ to = 0; pos = str_len(ACTION_INDEX); if (!case_starts(action,ACTION_INDEX)) pos = str_len(ALT_INDEX); if (FORMATS[str_chr(FORMATS,action[pos])]) { outformat = action[pos]; /* ignored, but be nice ... */ ++pos; } get_num(); /* max = last successful message */ if (!max) strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST)); szmsgnum[fmt_ulong(szmsgnum,max)] = '\0'; set_cpnum(szmsgnum); /* for copy this is the latest message arch'd*/ doheaders(); tosender(); if (!stralloc_cats(&subject," Result of: ")) die_nomem(); if (!stralloc_cats(&subject,action)) die_nomem(); presub(1,1,&subject,AC_INDEX,outformat); if (action[pos] == '-' || action[pos] == '.') pos++; if(action[pos += scan_ulong(action + pos,&u)]) scan_ulong(action + pos + 1, &to); if (u == 0 && to == 0) { to = max; u = max - 100; } if (u <= 0) u = 1; if (u > max) u = max; if (to < u) to = u; if (to > u + MAXINDEX) to = u+MAXINDEX; /* max MAXINDEX index files */ if (to > max) to = max; u /= 100; to /= 100; while (u <= to) { if (!stralloc_copys(&fn,"archive/")) die_nomem(); if (!stralloc_catb(&fn,strnum,fmt_ulong(strnum,u))) die_nomem(); if (!stralloc_cats(&fn,"/index")) die_nomem(); if (!stralloc_0(&fn)) die_nomem(); if (u == max/100) /* lock if last index file in archive */ lockup(); fd = open_read(fn.s); if (fd == -1) if (errno != error_noent) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fn.s)); else code_qputs(MSG(TXT_NOINDEX)); else { substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); for (;;) { if (getln(&sstext,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,fn.s)); if (match) { if (line.s[0] != '\t') { /* subject line */ pos = byte_chr(line.s,line.len,' '); pos1 = 0; if (pos && pos != line.len && line.s[pos - 1] == ':') pos1 = pos + HASHLEN + 1; /* after hash */ if (pos1 >= line.len) { /* bad! */ pos = 0; pos1 = 0; /* output as is */ } if (!stralloc_copyb(&line2,line.s,pos)) die_nomem(); if (!stralloc_catb(&line2,line.s+pos1,line.len-pos1)) die_nomem(); } else { pos = byte_chr(line.s,line.len,';'); if (pos + HASHLEN + 1 < line.len && pos > 15 && line.s[pos + 1] != ' ') { if (!stralloc_copyb(&line2,line.s,pos - 15)) die_nomem(); pos++; if (!stralloc_catb(&line2,line.s + pos + HASHLEN, line.len - pos - HASHLEN)) die_nomem(); } else /* old format - no author hash */ if (!stralloc_copyb(&line2,line.s,line.len)) die_nomem(); } code_qput(line2.s,line2.len); } else break; } close(fd); } if (u == max/100) /* unlock if last index in archive file */ unlock(); u++; } normal_bottom(outformat); postmsg(outformat); break; case AC_THREAD: /* -thread[f][-|.]num returns messages with subject matching message */ /* 'num' in the subject index. If 'num' is not in[1..last_message] an error */ /* message is returned. */ if (!flagindexed) strerr_die2x(100,FATAL,MSG(ERR_NOT_INDEXED)); zapnonsub(ACTION_THREAD); /* restrict to subs if requested*/ get_num(); /* max = last successful message */ if (!max) strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST)); szmsgnum[fmt_ulong(szmsgnum,max)] = '\0'; set_cpnum(szmsgnum); /* for copy this is the latest message arch'd*/ doheaders(); tosender(); /* for rfc1153 */ if (!stralloc_cats(&subject," Digest of: ")) die_nomem(); if (!stralloc_cats(&subject,action)) die_nomem(); to = 0; pos = str_len(ACTION_THREAD); if (!case_starts(action,ACTION_THREAD)) pos = str_len(ALT_THREAD); if (FORMATS[str_chr(FORMATS,action[pos])]) { outformat = action[pos]; ++pos; } if (action[pos] == '-' || action[pos] == '.') pos++; if(action[pos += scan_ulong(action + pos,&u)]) scan_ulong(action + pos + 1, &to); if(u == 0 || u > max) { hdr_add2("Subject: ",subject.s,subject.len); qmail_puts(&qq,"\n"); copy(&qq,"text/get-bad",flagcd); } else { /* limit range to at most u-THREAD_BEFORE to u+THREAD_AFTER */ if (u > THREAD_BEFORE) from = u-THREAD_BEFORE; else from = 1L; if (u + THREAD_AFTER > max) { idx_mkthread(&msgtable,&subtable,&authtable,from,max,u,max,0); digest(msgtable,subtable,authtable,from,max,&subject, AC_THREAD,outformat); } else { idx_mkthread(&msgtable,&subtable,&authtable, from,u+THREAD_AFTER,u,max,0); digest(msgtable,subtable,authtable,from,u+THREAD_AFTER, &subject,AC_THREAD,outformat); } } break; default: /* This happens if the initial check at the beginning of 'main' */ /* matches something that isn't matched here. Conversely, just */ /* adding an action here is not enough - it has to be added to the */ /* initial check as well. */ strerr_die2x(100,FATAL, "Program error: I'm supposed to deal with this but I didn't"); } if (!stralloc_copy(&line,&outlocal)) die_nomem(); if (act == AC_DIGEST) { if (chunk) { if (!stralloc_cats(&line,"-return-g-")) die_nomem(); } else if (!stralloc_cats(&line,"-return-")) die_nomem(); strnum[fmt_ulong(strnum,mno)] = '\0'; if (!stralloc_cats(&line,strnum)) die_nomem(); if (!stralloc_cats(&line,"-@")) die_nomem(); if (!stralloc_cat(&line,&outhost)) die_nomem(); if (!stralloc_cats(&line,"-@[]")) die_nomem(); } else { 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); if (act == AC_DIGEST) { /* Do recipients */ tagmsg(mno,seed.s,"d",hashout,qq.msgbytes,chunk); if (chunk) { if (!stralloc_copys(&line,"T")) die_nomem(); if (!stralloc_cat(&line,&outlocal)) die_nomem(); if (!stralloc_cats(&line,"-s-d-")) die_nomem(); if (!stralloc_catb(&line,hashout,COOKIE)) die_nomem(); if (!stralloc_cats(&line,"-")) die_nomem(); if (!stralloc_cats(&line,strnum)) die_nomem(); if (!stralloc_cats(&line,"-")) die_nomem(); if (!stralloc_copys(&line2,"@")) die_nomem(); if (!stralloc_cat(&line2,&outhost)) die_nomem(); if (!stralloc_0(&line2)) die_nomem(); j = 0; for (i = 0; i <= 52; i += chunk) { /* To slaves */ qmail_put(&qq,line.s,line.len); schar[0] = '0' + i / 10; schar[1] = '0' + (i % 10); qmail_put(&qq,schar,3); j += (chunk - 1); if (j > 52) j = 52; schar[0] = '0' + j / 10; schar[1] = '0' + (j % 10); qmail_put(&qq,schar,2); qmail_put(&qq,line2.s,line2.len); } } else subs = putsubs(workdir,0L,52L,&subto); } else { /* if local is set, sender is checked */ if (ismod) qmail_to(&qq,mod.s); else qmail_to(&qq,sender); } if (*(err = qmail_close(&qq)) == '\0') { /* Done. Skip rest. */ if (act == AC_DIGEST) { if (chunk) (void) logmsg(mno,0L,0L,2); else (void) logmsg(mno,0L,subs,4); } closesub(); /* close db connection */ unlock(); /* NOP if nothing locked */ strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_die2x(goodexit,"ezmlm-get: info: qp ",strnum); } else { /* failed. Reset last msg & issue for digest */ if(act == AC_DIGEST) { issue--; write_ulong(issue,0L,0L,"digissue","digissuen"); write_ulong(prevmax,cumsize,(unsigned long) digwhen,"dignum","dignumn"); } unlock(); /* NOP if nothing locked */ strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1); } }
int main(int argc, char **argv) { if (argc != 3 && argc != 4) { usage(argv[0]); exit(0); } char cfg_file[MAX_LINE] = {0}; int make_deamon = 0; int ch; const char *args = "c:dh"; while ((ch = getopt(argc, argv, args)) != -1) { switch (ch) { case 'c': snprintf(cfg_file, sizeof(cfg_file), "%s", optarg); break; case 'd': make_deamon = 1; break; case 'h': default: usage(argv[0]); exit(0); break; } } if (make_deamon == 1) { // create deamon create_daemon(config_st.chdir_path); } // init log ctlog("ctserver", LOG_PID|LOG_NDELAY, LOG_MAIL); // read config dict_conf = open_config(cfg_file); if (dict_conf == NULL) { printf("parse config fail"); return 1; } if (read_config(dict_conf) != 0) { return 1; } log_level = atoi(config_st.log_level); if (chdir(config_st.chdir_path) == -1) { log_error("can not start: unable to change directory:%s", config_st.chdir_path); return 1; } log_debug("bind_port:%s", config_st.bind_port); log_debug("log_level:%s", config_st.log_level); log_debug("chdir_path:%s", config_st.chdir_path); log_debug("max_childs:%s", config_st.max_childs); log_debug("child_prog:%s", config_st.child_prog); log_debug("child_cf:%s", config_st.child_cf); // Get Local Host Name char local_hostname[MAX_LINE] = {0}; if (gethostname(local_hostname, sizeof(local_hostname)) != 0) { snprintf(local_hostname, sizeof(local_hostname), "unknown"); } log_debug("local_hostname:%s", local_hostname); // ---------- ---------- childs_st = (struct childs_t *)malloc((atoi(config_st.max_childs) + 1) * sizeof(struct childs_t)); if (childs_st == NULL) { log_error("malloc childs [%d] faild:[%d]:%s", (atoi(config_st.max_childs) + 1), errno, strerror(errno)); exit(1); } int i = 0; for (i=0; i<(atoi(config_st.max_childs) +1); i++) { init_child_with_idx(i); } // Start Server int connfd, epfd, sockfd, n, nread, nwrite; struct sockaddr_in local, remote; socklen_t addrlen; // Create Listen Socket int bind_port = atoi(config_st.bind_port); if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { log_error("socket fail:[%d]:%s", errno, strerror(errno)); exit(1); } // 设置套接字选项避免地址使用错误,解决: Address already in use int on = 1; if ((setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) { log_error("setsockopt failed"); exit(1); } // Set Listen FD Nonblock if (set_nonblocking(listen_fd) != 0) { exit(1); } bzero(&local, sizeof(local)); local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(bind_port); if (bind(listen_fd, (struct sockaddr *)&local, sizeof(local)) < 0) { log_error("bind local %d failed:[%d]%s", bind_port, errno, strerror(errno)); exit(1); } log_info("bind local %d succ", bind_port); if (listen(listen_fd, atoi(config_st.max_childs)) != 0) { log_error("listen fd[%d] max_number[%d] failed:[%d]%s", listen_fd, atoi(config_st.max_childs), errno, strerror(errno)); exit(1); } // Ignore pipe signal sig_pipeignore(); // Catch signal which is child program exit sig_catch(SIGCHLD, sigchld_exit); // epoll create fd epoll_event_num = atoi(config_st.max_childs) + 1; epoll_evts = NULL; epoll_fd = -1; epoll_nfds = -1; int epoll_i = 0; epoll_evts = (struct epoll_event *)malloc(epoll_event_num * sizeof(struct epoll_event)); if (epoll_evts == NULL) { log_error("malloc for epoll event fail"); exit(1); } epoll_fd = epoll_create(epoll_event_num); if (epoll_fd == -1) { log_error("epoll_create max_number[%d] failed:[%d]%s", epoll_event_num, errno, strerror(errno)); exit(1); } struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = listen_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) { log_error("epoll_ctl: listen_socket failed:[%d]%s", errno, strerror(errno)); exit(1); } epoll_num_running = 0; for (;;) { epoll_nfds = epoll_wait(epoll_fd, epoll_evts, epoll_event_num, -1); if (epoll_nfds == -1) { if (errno == EINTR) { // 收到中断信号 log_info("epoll_wait recive EINTR signal, continue"); continue; } exit(1); } log_debug("epoll_num_running:%d nfds:%d", epoll_num_running, epoll_nfds); for (epoll_i = 0; epoll_i < epoll_nfds; epoll_i++) { sig_childblock(); int evt_fd = epoll_evts[epoll_i].data.fd; if (evt_fd == listen_fd) { // new connect if ((connfd = accept(listen_fd, (struct sockaddr *)&remote, &addrlen)) > 0) { char *ipaddr = inet_ntoa(remote.sin_addr); log_debug("accept client:%s", ipaddr); char greet_buf[MAX_LINE] = {0}; // get a new index from child list int i = get_idle_idx_from_childs(); if (i == -1) { log_error("get_idle_idx_from_childs_t fail: maybe client queue is full."); // send to client error information n = snprintf(greet_buf, sizeof(greet_buf), "%s ERR %s%s", FAIL_CODE, local_hostname, DATA_END); nwrite = write(connfd, greet_buf, n); log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf); continue; } childs_st[i].used = 1; // get client ip and port. struct sockaddr_in sa; int len = sizeof(sa); if (!getpeername(connfd, (struct sockaddr *)&sa, &len)) { n = snprintf(childs_st[i].client_info.ip, sizeof(childs_st[i].client_info.ip), "%s", inet_ntoa(sa.sin_addr)); n = snprintf(childs_st[i].client_info.port, sizeof(childs_st[i].client_info.port), "%d", ntohs(sa.sin_port)); log_info("accept client:%s:%s", childs_st[i].client_info.ip, childs_st[i].client_info.port); } int pi1[2]; int pi2[2]; if (pipe(pi1) == -1) { log_error("unable to create pipe:[%d]%s", errno, strerror(errno)); // send to client error information n = snprintf(greet_buf, sizeof(greet_buf), "%s ERR %s%s", FAIL_CODE, local_hostname, DATA_END); nwrite = write(connfd, greet_buf, n); log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf); continue; } if (pipe(pi2) == -1) { log_error("unable to create pipe:[%d]%s", errno, strerror(errno)); close(pi1[0]); close(pi1[1]); pi1[0] = -1; pi1[1] = -1; // send to client error information n = snprintf(greet_buf, sizeof(greet_buf), "%s ERR %s%s", FAIL_CODE, local_hostname, DATA_END); nwrite = write(connfd, greet_buf, n); log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf); continue; } log_debug("create pi1[0]:%d pi1[1]:%d", pi1[0], pi1[1]); log_debug("create pi2[0]:%d pi2[1]:%d", pi2[0], pi2[1]); // create unique id n = create_unique_id(childs_st[i].sid, sizeof(childs_st[i].sid)); if (n != 16) { log_error("create unique id fail"); close(pi1[0]); close(pi1[1]); close(pi2[0]); close(pi2[1]); // send to client error information n = snprintf(greet_buf, sizeof(greet_buf), "%s SYSTEM ERR %s%s", FAIL_CODE, local_hostname, DATA_END); nwrite = write(connfd, greet_buf, n); log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf); continue; } log_debug("create mid:%s", childs_st[i].sid); // 当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程 fcntl(pi1[1], F_SETFD, FD_CLOEXEC); fcntl(pi2[0], F_SETFD, FD_CLOEXEC); fcntl(listen_fd, F_SETFD, FD_CLOEXEC); int f = fork(); if (f < 0) { log_error("fork fail:[%d]%s", errno, strerror(errno)); close(pi1[0]); close(pi1[1]); pi1[0] = -1; pi1[1] = -1; close(pi2[0]); close(pi2[1]); pi2[0] = -1; pi2[1] = -1; // send to client error information n = snprintf(greet_buf, sizeof(greet_buf), "%s SYSTEM ERR %s%s", FAIL_CODE, local_hostname, DATA_END); nwrite = write(connfd, greet_buf, n); log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf); continue; } else if (f == 0) { // 子进程 close(pi1[1]); close(pi2[0]); pi1[1] = -1; pi2[0] = -1; close(listen_fd); listen_fd = -1; if (fd_move(2, connfd) == -1) { log_error("%s fd_move(2, %d) failed:[%d]%s", childs_st[i].sid, connfd, errno, strerror(errno)); _exit(111); } // read from 0 if (fd_move(0, pi1[0])) { log_error("%s fd_move(0, %d) failed:[%d]%s", childs_st[i].sid, pi1[0], errno, strerror(errno)); _exit(111); } // write to 1 if (fd_move(1, pi2[1])) { log_error("%s fd_move(1, %d) failed:[%d]%s", childs_st[i].sid, pi2[1], errno, strerror(errno)); _exit(111); } // lunach child program char exe_sid[MAX_LINE] = {0}; char exe_cfg[MAX_LINE] = {0}; char exe_remote[MAX_LINE] = {0}; snprintf(exe_sid, sizeof(exe_sid), "-m%s", childs_st[i].sid); snprintf(exe_cfg, sizeof(exe_cfg), "-c%s", config_st.child_cf); snprintf(exe_remote, sizeof(exe_remote), "-r%s:%s", childs_st[i].client_info.ip, childs_st[i].client_info.port); char *args[5]; args[0] = config_st.child_prog; args[1] = exe_sid; args[2] = exe_cfg; args[3] = exe_remote; args[4] = 0; char log_exec[MAX_LINE*3] = {0}; char *plog_exec = log_exec; int len = 0; int i=0; while (args[i] != 0) { int n = snprintf(plog_exec + len, sizeof(log_exec) - len, "%s ", args[i]); len += n; i++; } log_info("Exec:[%s]", log_exec); if (execvp(*args, args) == -1) { log_error("execvp fail:[%d]%s", errno, strerror(errno)); _exit(111); } _exit(100); } // 父进程 log_debug("add child index:%d pid:%lu", i, f); childs_st[i].pid = f; close(pi1[0]); close(pi2[1]); pi1[0] = -1; pi2[1] = -1; close(connfd); connfd = -1; childs_st[i].pfd_r = pi2[0]; childs_st[i].pfd_w = pi1[1]; if (set_nonblocking(childs_st[i].pfd_r)) { log_error("set nonblocking fd[%d] fail", childs_st[i].pfd_r); } struct epoll_event pipe_r_ev; pipe_r_ev.events = EPOLLIN | EPOLLET; pipe_r_ev.data.fd = childs_st[i].pfd_r; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_r_ev.data.fd, &pipe_r_ev) == -1) { log_error("epoll_ctl client fd[%d] EPOLL_CTL_ADD failed:[%d]%s", pipe_r_ev.data.fd, errno, strerror(errno)); } log_debug("epoll_add fd[%d]", pipe_r_ev.data.fd); epoll_num_running++; } else if (connfd == -1) { if (errno != EAGAIN && errno != ECONNABORTED && errno != EPROTO && errno != EINTR) { log_error("accept failed:[%d]%s", errno, strerror(errno)); } continue; } } else if (epoll_evts[epoll_i].events & EPOLLIN) { // 有可读事件从子进程过来 int idx = get_idx_with_sockfd(evt_fd); if (idx < 0) { log_error("get_idx_with_sockfd(%d) fail, so not process", evt_fd); continue; } log_debug("%s get event EPOLLIN: epoll_i[%d] fd[%d] get fd[%d], used[%d]", childs_st[idx].sid, epoll_i, epoll_evts[epoll_i].data.fd, childs_st[idx].pfd_r, childs_st[idx].used); // 读取内容 char cbuf[MAX_LINE] = {0}; nread = read(childs_st[idx].pfd_r, cbuf, sizeof(cbuf)); log_debug("read buf:'[%d]%s' from child", n, cbuf); } else if ((epoll_evts[epoll_i].events & EPOLLHUP) && (epoll_evts[epoll_i].data.fd != listen_fd)) { // 有子进程退出 int idx = get_idx_with_sockfd(evt_fd); if (idx < 0) { log_error("get_idx_with_sockfd(%d) fail, so not process", evt_fd); continue; } log_debug("%s get event EPOLLHUP: epoll_i[%d] fd[%d] get fd[%d], used[%d]", childs_st[idx].sid, epoll_i, epoll_evts[epoll_i].data.fd, childs_st[idx].pfd_r, childs_st[idx].used); epoll_delete_evt(epoll_fd, childs_st[idx].pfd_r); // 子进程清理 clean_child_with_idx(idx); continue; } } sig_childunblock(); } close(epoll_fd); close(listen_fd); epoll_fd = -1; listen_fd = -1; if (childs_st != NULL) { free(childs_st); childs_st = NULL; } if (epoll_evts != NULL) { free(epoll_evts); epoll_evts = NULL; } log_info("I'm finish"); return 0; }
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 main(int argc, char **argv) { liao_log("liao_server", LOG_PID|LOG_NDELAY, LOG_MAIL); if (argc != 3) { usage(argv[0]); exit(0); } if (chdir(LIAO_HOME) == -1) { log_alert("cannot start: unable to switch to home directory"); exit(0); } snprintf(msg_id, sizeof(msg_id), "00000000"); char cfg_file[MAX_LINE] = CFG_FILE; int c; const char *args = "c:h"; while ((c = getopt(argc, argv, args)) != -1) { switch (c) { case 'c': snprintf(cfg_file, sizeof(cfg_file), "%s", optarg); break; case 'h': default: usage(argv[0]); exit(0); } } // 处理配置文件 if (conf_init(cfg_file)) { fprintf(stderr, "Unable to read control files:%s\n", cfg_file); log_error("Unable to read control files:%s", cfg_file); exit(1); } /* // 检查队列目录 if (strlen(config_st.queue_path) <= 0) { fprintf(stderr, "Unable to read queue path.\n"); log_error("Unable to read queue path."); exit(1); } if ( access(config_st.queue_path, F_OK) ) { fprintf(stderr, "Queue path:%s not exists:%s, so create it.\n", config_st.queue_path, strerror(errno)); log_error("Queue path:%s not exists:%s, so create it.", config_st.queue_path, strerror(errno)); umask(0); mkdir(config_st.queue_path, 0777); }*/ online_d = dictionary_new(atoi(config_st.max_works) + 1); child_st = (struct childs *)malloc((atoi(config_st.max_works) + 1) * sizeof(struct childs)); if (!child_st) { log_error("malloc childs [%d] failed:[%d]%s", (atoi(config_st.max_works) + 1), errno, strerror(errno)); exit(1); } int i = 0; for (i=0; i<(atoi(config_st.max_works) + 1); i++) { child_st[i].used = 0; child_st[i].pid = -1; child_st[i].client_fd = -1; child_st[i].pipe_r_in = -1; child_st[i].pipe_r_out = -1; child_st[i].pipe_w_in = -1; child_st[i].pipe_w_out = -1; memset(child_st[i].mid, 0, sizeof(child_st[i].mid)); child_st[i].mfp_out = NULL; } // 开始服务 int connfd, epfd, sockfd, n, nread; struct sockaddr_in local, remote; socklen_t addrlen; // 初始化buffer char buf[BUF_SIZE]; size_t pbuf_len = 0; size_t pbuf_size = BUF_SIZE + 1; char *pbuf = (char *)calloc(1, pbuf_size); if (pbuf == NULL) { log_error("calloc fail: size[%d]", pbuf_size); exit(1); } // 创建listen socket int bind_port = atoi(config_st.bind_port); if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { log_error("socket failed:[%d]:%s", errno, strerror(errno)); exit(1); } if (setnonblocking(listenfd) > 0) { exit(1); } bzero(&local, sizeof(local)); local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(bind_port); if (bind(listenfd, (struct sockaddr *)&local, sizeof(local)) < 0) { log_error("bind local %d failed:[%d]%s", bind_port, errno, strerror(errno)); exit(1); } log_info("bind local %d succ", bind_port); if (listen(listenfd, atoi(config_st.max_works)) != 0) { log_error("listen fd[%d] max_number[%d] failed:[%d]%s", listenfd, atoi(config_st.max_works), errno, strerror(errno)); exit(1); } // 忽略pipe信号 sig_pipeignore(); // 捕抓子进程退出信号 sig_catch(SIGCHLD, sigchld); // epoll create fd epoll_event_num = atoi(config_st.max_works) + 1; epoll_evts = NULL; epoll_fd = -1; epoll_nfds = -1; int epoll_i = 0; epoll_evts = (struct epoll_event *)malloc(epoll_event_num * sizeof(struct epoll_event)); if (epoll_evts == NULL) { log_error("alloc epoll event failed"); _exit(111); } epoll_fd = epoll_create(epoll_event_num); if (epoll_fd == -1) { log_error("epoll_create max_number[%d] failed:[%d]%s", epoll_event_num, errno, strerror(errno)); exit(1); } struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = listenfd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) { log_error("epoll_ctl: listen_socket failed:[%d]%s", errno, strerror(errno)); exit(1); } epoll_num_running = 1; for (;;) { epoll_nfds = epoll_wait(epoll_fd, epoll_evts, epoll_event_num, -1); if (epoll_nfds == -1) { if (errno == EINTR) { // 收到中断信号 log_info("epoll_wait recive EINTR signal, continue"); continue; } _exit(111); } log_debug("epoll_num_running:%d nfds:%d", epoll_num_running, epoll_nfds); for (epoll_i = 0; epoll_i < epoll_nfds; epoll_i++) { sig_childblock(); int evt_fd = epoll_evts[epoll_i].data.fd; if (evt_fd == listenfd) { if ((connfd = accept(listenfd, (struct sockaddr *) &remote, &addrlen)) > 0) { char *ipaddr = inet_ntoa(remote.sin_addr); log_info("accept client:%s", ipaddr); char greetting[512] = {0}; char hostname[1024] = {0}; if (gethostname(hostname, sizeof(hostname)) != 0) { snprintf(hostname, sizeof(hostname), "unknown"); } // 取客户端IP,Port char client_ip[20] = {0}; char client_port[20] = {0}; struct sockaddr_in sa; int len = sizeof(sa); if (!getpeername(connfd, (struct sockaddr *)&sa, &len)) { snprintf(client_ip, sizeof(client_ip), "%s", inet_ntoa(sa.sin_addr)); snprintf(client_port, sizeof(client_port), "%d", ntohs(sa.sin_port)); } // 取一个新的client int i = new_idx_from_child_st(); if (i == -1) { log_error("new_idx_from_client_st fail: maybe client queue is full."); // send error snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END); write(connfd, greetting, strlen(greetting)); log_debug("send fd[%d]:%s", connfd, greetting); continue; } child_st[i].used = 1; int pir[2]; int piw[2]; if (pipe(pir) == -1) { log_error("unable to create pipe:%s", strerror(errno)); // send error snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END); write(connfd, greetting, strlen(greetting)); log_debug("send fd[%d]:%s", connfd, greetting); continue; } if (pipe(piw) == -1) { log_error("unable to create pipe:%s", strerror(errno)); close(pir[0]); close(pir[1]); pir[0] = -1; pir[1] = -1; // send error snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END); write(connfd, greetting, strlen(greetting)); log_debug("send fd[%d]:%s", connfd, greetting); continue; } log_debug("create pir[0]:%d pir[1]:%d", pir[0], pir[1]); log_debug("create piw[0]:%d piw[1]:%d", piw[0], piw[1]); // 当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程 //fcntl(pir[0], F_SETFD, FD_CLOEXEC); //fcntl(piw[1], F_SETFD, FD_CLOEXEC); int f = fork(); if (f < 0) { log_error("fork fail:%s", strerror(errno)); close(pir[0]); close(pir[1]); pir[0] = -1; pir[1] = -1; close(piw[0]); close(piw[1]); piw[0] = -1; piw[1] = -1; child_st[i].used = 0; // send error snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END); write(connfd, greetting, strlen(greetting)); log_debug("send fd[%d]:%s", connfd, greetting); continue; } struct timeval tm; gettimeofday(&tm, NULL); snprintf(child_st[i].mid, sizeof(child_st[i].mid), "%05u%u", (uint32_t)tm.tv_usec, (uint32_t)f); snprintf(msg_id, sizeof(msg_id), "%s", child_st[i].mid); if (f == 0) { // 子进程 close(pir[0]); close(piw[1]); close(listenfd); char _cmid[512] = {0}; char _cchild_st[512] = {0}; char _ccip[20] = {0}; char _ccport[20] = {0}; snprintf(_cmid, sizeof(_cmid), "-m%s", child_st[i].mid); snprintf(_cchild_st, sizeof(_cchild_st), "-c%s", config_st.child_cf); snprintf(_ccip, sizeof(_ccip), "-i%s", client_ip); snprintf(_ccport, sizeof(_ccport), "-p%s", client_port); char *args[6]; args[0] = "./liao_command"; args[1] = _cmid; args[2] = _cchild_st; args[3] = _ccip; args[4] = _ccport; args[5] = 0; if (fd_move(0, connfd) == -1) { log_info("%s fd_move(0, %d) failed:%d %s", child_st[i].mid, connfd, errno, strerror(errno)); _exit(111); } if (fd_move(1, pir[1]) == -1) { log_info("%s fd_move(pipe_w, %d) failed:%d %s", child_st[i].mid, pir[1], errno, strerror(errno)); _exit(111); } if (fd_move(2, piw[0]) == -1) { log_info("%s fd_move(pipe_r, %d) failed:%d %s", child_st[i].mid, piw[0], errno, strerror(errno)); _exit(111); } if (execvp(*args, args) == -1) { log_error("execp fail:%s", strerror(errno)); _exit(111); } //if (error_temp(errno)) // _exit(111); log_debug("execp succ"); _exit(100); } close(connfd); child_st[i].pipe_r_in = pir[0]; close(pir[1]); pir[1] = -1; child_st[i].pipe_r_out = -1; child_st[i].pipe_w_out = piw[1]; close(piw[0]); piw[0] = -1; child_st[i].pipe_w_in = -1; child_st[i].pid = f; if (setnonblocking(child_st[i].pipe_r_in) != 0) { log_error("setnonblocking fd[%d] failed", child_st[i].pipe_r_in); } struct epoll_event pipe_in_ev; pipe_in_ev.events = EPOLLIN | EPOLLET; pipe_in_ev.data.fd = child_st[i].pipe_r_in; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_in_ev.data.fd, &pipe_in_ev) == -1) { log_error("epoll_ctl client fd[%d] EPOLL_CTL_ADD failed:[%d]%s", pipe_in_ev.data.fd, errno, strerror(errno)); } log_debug("epoll_add fd[%d]", pipe_in_ev.data.fd); } else if (connfd == -1) { if (errno != EAGAIN && errno != ECONNABORTED && errno != EPROTO && errno != EINTR) { log_error("accept failed:[%d]%s", errno, strerror(errno)); } continue; } } else if (epoll_evts[epoll_i].events & EPOLLIN) { int ci = get_idx_with_sockfd(evt_fd); if (ci < 0) { log_error("socket fd[%d] get_idx_with_sockfd fail", evt_fd); continue; } log_debug("%s get event EPOLLIN: epoll_i[%d] fd[%d] get d_i[%d] fd[%d], used[%d]", child_st[ci].mid, epoll_i, epoll_evts[epoll_i].data.fd, child_st[ci].pipe_r_in, child_st[ci].used); // 读取内容 ---------------------- char inbuf[BUF_SIZE] = {0}; char *pinbuf = inbuf; int inbuf_size = BUF_SIZE; int inbuf_len = 0; char ch; do { i = 0; nread = read(child_st[ci].pipe_r_in, inbuf, inbuf_size); log_debug("%s read from liao_command:[%d]", child_st[ci].mid, nread); if (nread == -1) { // read error on a readable pipe? be serious //log_error("it is failed from fd[%d] read. error:%d %s", child_st[ci].fd_in, errno, strerror(errno)); //log_debug("it is failed from fd[%d] read. error:%d %s", child_st[ci].pipe_r_in, errno, strerror(errno)); break; } else if (nread > 0) { if (child_st[ci].mfp_out == NULL) { child_st[ci].mfp_out = mopen(MAX_BLOCK_SIZE, NULL, NULL); if (child_st[ci].mfp_out == NULL) { log_debug("%s mopen for body fail", child_st[ci].mid); break; } } while (i < nread) { ch = inbuf[i]; if ((inbuf_size - inbuf_len) < 2) { int r = fast_write(child_st[ci].mfp_out, inbuf, inbuf_len); if (r == 0) { log_error("%s fast_write fail", child_st[ci].mid); break; } memset(inbuf, 0, inbuf_size); inbuf_len = 0; } mybyte_copy(pinbuf + inbuf_len, 1, &ch); inbuf_len++; if (ch == '\n') { if (inbuf_len > 0) { int r = fast_write(child_st[ci].mfp_out, inbuf, inbuf_len); if (r == 0) { log_error("%s fast_write fail", child_st[ci].mid); break; } memset(inbuf, 0, inbuf_size); inbuf_len = 0; } // 处理当前指令 // ... process_system(&child_st[ci]); // ... // 处理完成后 if (child_st[ci].mfp_out != NULL) { mclose(child_st[ci].mfp_out); child_st[ci].mfp_out = NULL; child_st[ci].mfp_out = mopen(MAX_BLOCK_SIZE, NULL, NULL); if (child_st[ci].mfp_out == NULL) { log_error("mopen fail for mfp_out"); break; } } pinbuf = inbuf + 0; } i++; } } else { break; } } while (1); } else if ((epoll_evts[epoll_i].events & EPOLLHUP) && (epoll_evts[epoll_i].data.fd != listenfd)) { int ci = get_idx_with_sockfd(evt_fd); if ( ci < 0 ) { log_error("get_idx_with_sockfd(%d) fail, so not write", evt_fd); continue; } log_debug("%s get event EPOLLHUP: epoll_i[%d] fd[%d] get d_i[%d] fd[%d], used[%d]", child_st[ci].mid, epoll_i, epoll_evts[epoll_i].data.fd, child_st[ci].pipe_r_in, child_st[ci].used); epoll_delete_evt(epoll_fd, child_st[ci].pipe_r_in); continue; } } sig_childunblock(); } close(epoll_fd); close(listenfd); log_info("i'm finish"); return 0; }
void main(int argc,char **argv) { char *sender; char *def; char *local; char *action; int flaginheader; int flagcomment; int flaggoodfield; int flagdone; int fd, fdlock; int match; const char *err; char encin = '\0'; unsigned int start,confnum; unsigned int pos,i; int child; int opt; char *cp,*cpnext,*cpfirst,*cplast,*cpafter; (void) umask(022); sig_pipeignore(); when = now(); if (!stralloc_copys(&sendopt,"-")) die_nomem(); opt = getconfopt(argc,argv,options,1,&dir); sender = get_sender(); if (!sender) strerr_die2x(100,FATAL,MSG(ERR_NOSENDER)); local = env_get("LOCAL"); if (!local) strerr_die2x(100,FATAL,MSG(ERR_NOLOCAL)); def = env_get("DEFAULT"); if (!def) strerr_die2x(100,FATAL,MSG(ERR_NODEFAULT)); 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)); /* local should be >= def, but who knows ... */ cp = local + str_len(local) - str_len(def) - 2; if (cp < local) die_badformat(); action = local + byte_rchr(local,cp - local,'-'); if (action == cp) die_badformat(); action++; if (!action[0]) die_badformat(); if (!str_start(action,ACTION_ACCEPT) && !str_start(action,ACTION_REJECT)) die_badformat(); start = str_chr(action,'-'); if (!action[start]) die_badformat(); confnum = 1 + start + str_chr(action + start + 1,'.'); if (!action[confnum]) die_badformat(); confnum += 1 + str_chr(action + confnum + 1,'.'); if (!action[confnum]) die_badformat(); if (!stralloc_copyb(&fnbase,action+start+1,confnum-start-1)) die_nomem(); if (!stralloc_0(&fnbase)) die_nomem(); cookie(hash,key.s,key.len,fnbase.s,"","a"); if (byte_diff(hash,COOKIE,action+confnum+1)) die_badformat(); fdlock = lockfile("mod/lock"); switch(checkfile(fnbase.s)) { case 0: strerr_die2x(100,FATAL,MSG(ERR_MOD_TIMEOUT)); case -1: /* only error if new request != action taken */ if (str_start(action,ACTION_ACCEPT)) strerr_die2x(0,INFO,MSG(ERR_MOD_ACCEPTED)); else strerr_die2x(100,FATAL,MSG(ERR_MOD_ACCEPTED)); case -2: if (str_start(action,ACTION_REJECT)) strerr_die2x(0,INFO,MSG(ERR_MOD_REJECTED)); else strerr_die2x(100,FATAL,MSG(ERR_MOD_REJECTED)); default: break; } /* Here, we have an existing filename in fnbase with the complete path */ /* from the current dir in fnmsg. */ if (str_start(action,ACTION_REJECT)) { if (qmail_open(&qq, (stralloc *) 0) == -1) strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE)); /* Build recipient from msg return-path */ fd = open_read(fnmsg.s); if (fd == -1) { if (errno != error_noent) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fnmsg.s)); else strerr_die2x(100,FATAL,MSG(ERR_MOD_TIMEOUT)); } substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); if (getln(&sstext,&line,&match,'\n') == -1 || !match) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); maketo(); /* extract SENDER from return-path */ /* Build message */ hdr_add2s("Mailing-List: ",MSG(TXT_MAILING_LIST)); if (listid.len > 0) hdr_add2("List-ID: ",listid.s,listid.len); hdr_datemsgid(when); hdr_from("-owner"); if (replyto) hdr_add2s("Reply-To: ",replyto); hdr_add2s("To: ",to.s); hdr_subject(MSG(SUB_RETURNED_POST)); if (flagmime) { hdr_mime(CTYPE_MULTIPART); hdr_boundary(0); hdr_ctype(CTYPE_TEXT); hdr_transferenc(); } copy(&qq,"text/top",flagcd); copy(&qq,"text/mod-reject",flagcd); flagcomment = 0; flaginheader = 1; if (!stralloc_copys(&text,"")) die_nomem(); if (!stralloc_ready(&text,1024)) die_nomem(); for (;;) { /* copy moderator's rejection comment */ if (getln(subfdin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); if (!match) break; if (flaginheader) { if (case_startb(line.s,line.len,"Content-Transfer-Encoding:")) { pos = 26; while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos; if (case_startb(line.s+pos,line.len-pos,"base64")) encin = 'B'; else if (case_startb(line.s+pos,line.len-pos,"quoted-printable")) encin = 'Q'; } if (line.len == 1) flaginheader = 0; } else if (!stralloc_cat(&text,&line)) die_nomem(); } /* got body */ if (encin) { if (encin == 'B') decodeB(text.s,text.len,&line); else decodeQ(text.s,text.len,&line); if (!stralloc_copy(&text,&line)) die_nomem(); } cp = text.s; cpafter = text.s + text.len; if (!stralloc_copys(&line,"\n>>>>> -------------------- >>>>>\n")) die_nomem(); flaggoodfield = 0; flagdone = 0; while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) { i = byte_chr(cp,cpnext-cp,'%'); if (i <= 5 && cpnext-cp-i >= 3) { /* max 5 "quote characters" and space for %%% */ if (cp[i+1] == '%' && cp[i+2] == '%') { if (!flaggoodfield) { /* Start tag */ if (!stralloc_copyb("ed,cp,i)) die_nomem(); /* quote chars*/ flaggoodfield = 1; cp = cpnext + 1; cpfirst = cp; continue; } else { /* end tag */ if (flagdone) /* 0 no comment lines, 1 comment line */ flagdone = 2; /* 2 at least 1 comment line & end tag */ break; } } } if (flaggoodfield) { cplast = cpnext - 1; if (*cplast == '\r') /* CRLF -> '\n' for base64 encoding */ *cplast = '\n'; else ++cplast; /* NUL is now ok, so the test for it was removed */ flagdone = 1; i = cplast - cp + 1; if (quoted.len && quoted.len <= i && !str_diffn(cp,quoted.s,quoted.len)) { /* quote chars */ if (!stralloc_catb(&line,cp+quoted.len,i-quoted.len)) die_nomem(); } else if (!stralloc_catb(&line,cp,i)) die_nomem(); /* no quote chars */ } cp = cpnext + 1; } if (flagdone == 2) { if (!stralloc_cats(&line,"<<<<< -------------------- <<<<<\n")) die_nomem(); code_qput(line.s,line.len); } if (flagcd == 'B') { encodeB("",0,&line,2); qmail_put(&qq,line.s,line.len); } if (flagmime) { hdr_boundary(0); hdr_ctype(CTYPE_MESSAGE); } qmail_puts(&qq,"\n"); if (seek_begin(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,fnmsg.s)); substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); if (qmail_copy(&qq,&sstext,-1) != 0) strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnmsg.s)); close(fd); if (flagmime) hdr_boundary(1); 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); if (to.len) qmail_to(&qq,to.s); if (!stralloc_copys(&fnnew,"mod/rejected/")) die_nomem(); if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem(); if (!stralloc_0(&fnnew)) die_nomem(); /* this is strictly to track what happended to a message to give informative */ /* messages to the 2nd-nth moderator that acts on the same message. Since */ /* this isn't vital we ignore errors. Also, it is no big ideal if unlinking */ /* the old file fails. In the worst case it gets acted on again. If we issue */ /* a temp error the reject will be redone, which is slightly worse. */ if (*(err = qmail_close(&qq)) == '\0') { fd = open_trunc(fnnew.s); if (fd != -1) close(fd); unlink(fnmsg.s); strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_die2x(0,"ezmlm-moderate: info: qp ",strnum); } else strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1); } else if (str_start(action,ACTION_ACCEPT)) { fd = open_read(fnmsg.s); if (fd == -1) { if (errno !=error_noent) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fnmsg.s)); else /* shouldn't happen since we've got lock */ strerr_die3x(100,FATAL,fnmsg.s,MSG(ERR_MOD_TIMEOUT)); } substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); /* read "Return-Path:" line */ if (getln(&sstext,&line,&match,'\n') == -1 || !match) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); maketo(); /* extract SENDER to "to" */ env_put2("SENDER",to.s); /* set SENDER */ if (seek_begin(fd) == -1) /* rewind, since we read an entire buffer */ strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,fnmsg.s)); if ((child = wrap_fork()) == 0) { close(0); dup(fd); /* make fnmsg.s stdin */ if (argc > opt + 1) wrap_execvp((const char **)argv + opt); else if (argc > opt) wrap_execsh(argv[opt]); else wrap_execbin("/ezmlm-send", &sendopt, dir); } /* parent */ close(fd); wrap_exitcode(child); if (!stralloc_copys(&fnnew,"mod/accepted/")) die_nomem(); if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem(); if (!stralloc_0(&fnnew)) die_nomem(); /* ignore errors */ fd = open_trunc(fnnew.s); if (fd != -1) close(fd); unlink(fnmsg.s); _exit(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; }
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) { 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; }
void main(int argc,char **argv) { char *dir; char *sender; char *moddir; const char *queryext = (char *) 0; int opt; int ret = 0; int dontact = 0; unsigned int i,j; const char *program; stralloc *opts; umask(022); sig_pipeignore(); /* storeopts to ezmlm-store only. Others to both (ezmlm-store may */ /* pass them on to ezmlm-send. */ if (!stralloc_copys(&sendopt,"-")) die_nomem(); if (!stralloc_copys(&storeopt,"-")) die_nomem(); while ((opt = getopt(argc,argv, "0cCmMpPq:Q:sSrRt:T:vVyY")) != opteof) switch(opt) { /* pass on unrecognized options */ case 'c': /* ezmlm-send flags */ case 'C': case 'r': case 'Q': case 'R': szchar[0] = opt; if (!stralloc_append(&sendopt,szchar)) die_nomem(); if (!stralloc_append(&storeopt,szchar)) die_nomem(); break; case 'm': /* ezmlm-store flags */ case 'M': case 'p': case 'P': case 's': case 'S': case 'y': case 'Y': szchar[0] = opt; if (!stralloc_append(&storeopt,szchar)) die_nomem(); break; case 'q': if (optarg) queryext = optarg; break; case 'v': case 'V': strerr_die2x(0,"ezmlm-gate version: ",auto_version); case '0': dontact = 1; break; default: /* ezmlm-store flags */ die_usage(); } startup(dir = argv[optind++]); sender = env_get("SENDER"); pmod = (char *) 0; if (queryext) { getconf(&cmds,queryext,1,dir); i = 0; for (j = 0;j < cmds.len; ++j) if (!cmds.s[j]) { switch (cmds.s[i]) { case '\0': case '#': break; /* ignore blank/comment */ case '|': ret = mailprog(cmds.s + i + 1); break; default: ret = mailprog(cmds.s + i); break; } if (ret) break; i = j + 1; } if (!ret || ret == 99) /* 111 => temp error */ pmod = ""; /* 0, 99 => post */ /* other => moderate */ } moddir = argv[optind++]; if (moddir && !ret) { /* if exit 0 and moddir, add issub */ pmod = (char *) 0; while (moddir && !pmod && sender) { pmod = (moddir[0] == '/') ? issub(moddir,0,sender) : issub(dir,moddir,sender); closesub(); moddir = argv[optind++]; } } if (pmod) { program = "/ezmlm-send"; opts = &sendopt; } else { program = "/ezmlm-store"; opts = &storeopt; } if (dontact) { substdio_puts(subfderr, auto_bin); substdio_puts(subfderr, program); substdio_put(subfderr, " ", 1); substdio_put(subfderr, opts->s, opts->len); substdio_put(subfderr, " ", 1); substdio_puts(subfderr, dir); substdio_putsflush(subfderr, "\n"); _exit(0); } if ((child = wrap_fork()) == 0) wrap_execbin(program, opts, dir); /* parent */ wrap_exitcode(child); _exit(0); }
int main(int argc,char *argv[]) //int argc; //char *argv[]; { int dummy; char *proto; int opt; int flagremoteinfo; unsigned long timeout; // struct sockaddr_in *v4; sig_pipeignore(); flagremoteinfo = 1; timeout = 30; while ((opt = getopt(argc,argv,"rRt:")) != opteof) switch(opt) { case 'r': flagremoteinfo = 1; break; case 'R': flagremoteinfo = 0; break; case 't': scan_ulong(subgetoptarg,&timeout); break; } argv += subgetoptind; argc -= subgetoptind; if (argc < 1) die(); if (!env_init()) die(); proto = env_get("PROTO"); if (!proto || str_diff(proto,"TCP")) { if (!env_puts("PROTO=TCP")) die(); dummy = sizeof(salocal); if (getsockname(0,(struct sockaddr *) &salocal, (socklen_t *) &dummy) == -1) die(); mappedtov4(&salocal); switch(salocal.sa.sa_family) { case AF_INET: localport = ntohs(salocal.sa4.sin_port); temp[fmt_ulong(temp,localport)] = 0; if (!env_put("TCPLOCALPORT",temp)) die(); temp[ip4_fmt(temp,(char *) &salocal.sa4.sin_addr)] = 0; if (!env_put("TCPLOCALIP",temp)) die(); switch(dns_ptr(&localname,&salocal.sa4.sin_addr)) { case DNS_MEM: die(); case DNS_SOFT: if (!stralloc_copys(&localname,"softdnserror")) die(); case 0: if (!stralloc_0(&localname)) die(); case_lowers(localname.s); if (!env_put("TCPLOCALHOST",localname.s)) die(); break; default: if (!env_unset("TCPLOCALHOST")) die(); } break; #ifdef INET6 case AF_INET6: localport = ntohs(salocal.sa6.sin6_port); temp[fmt_ulong(temp,localport)] = 0; if (!env_put("TCPLOCALPORT",temp)) die(); temp[ip6_fmt(temp,(char *) &salocal.sa6.sin6_addr)] = 0; if (!env_put("TCPLOCALIP",temp)) die(); switch(dns_ptr6(&localname,&salocal.sa6.sin6_addr)) { case DNS_MEM: die(); case DNS_SOFT: if (!stralloc_copys(&localname,"softdnserror")) die(); case 0: if (!stralloc_0(&localname)) die(); case_lowers(localname.s); if (!env_put("TCPLOCALHOST",localname.s)) die(); break; default: if (!env_unset("TCPLOCALHOST")) die(); } break; #endif default: die(); } dummy = sizeof(saremote); if (getpeername(0,(struct sockaddr *) &saremote, (socklen_t *) &dummy) == -1) die(); mappedtov4(&saremote); switch(saremote.sa.sa_family) { case AF_INET: remoteport = ntohs(saremote.sa4.sin_port); temp[fmt_ulong(temp,remoteport)] = 0; if (!env_put("TCPREMOTEPORT",temp)) die(); temp[ip4_fmt(temp,(char *)&saremote.sa4.sin_addr)] = 0; if (!env_put("TCPREMOTEIP",temp)) die(); switch(dns_ptr(&remotename,&saremote.sa4.sin_addr)) { case DNS_MEM: die(); case DNS_SOFT: if (!stralloc_copys(&remotename,"softdnserror")) die(); case 0: if (!stralloc_0(&remotename)) die(); case_lowers(remotename.s); if (!env_put("TCPREMOTEHOST",remotename.s)) die(); break; default: if (!env_unset("TCPREMOTEHOST")) die(); } break; #ifdef INET6 case AF_INET6: remoteport = ntohs(saremote.sa6.sin6_port); temp[fmt_ulong(temp,remoteport)] = 0; if (!env_put("TCPREMOTEPORT",temp)) die(); temp[ip6_fmt(temp,(char *) &saremote.sa6.sin6_addr)] = 0; if (!env_put("TCPREMOTEIP",temp)) die(); switch(dns_ptr6(&remotename,&saremote.sa6.sin6_addr)) { case DNS_MEM: die(); case DNS_SOFT: if (!stralloc_copys(&remotename,"softdnserror")) die(); case 0: if (!stralloc_0(&remotename)) die(); case_lowers(remotename.s); if (!env_put("TCPREMOTEHOST",remotename.s)) die(); break; default: if (!env_unset("TCPREMOTEHOST")) die(); } break; #endif default: die(); } if (!env_unset("TCPREMOTEINFO")) die(); if (flagremoteinfo) { char *rinfo; rinfo = remoteinfo_get(&saremote, &salocal,(int) timeout); if (rinfo) if (!env_put("TCPREMOTEINFO",rinfo)) die(); } } sig_pipedefault(); execvp(*argv,argv); die(); return(0); /* never reached */ }
int main(int argc,char **argv) { unsigned long max; int fd; int fdlock; msgentry *msgtable; subentry *subtable; authentry *authtable; dateentry *datetable; (void) umask(022); sig_pipeignore(); getconfopt(argc,argv,options,1,0); if (flagsyncall) flagsync = 1; else if (flagcreate) flagsync = 0; archnum = (archnum / 100) * 100; /* Lock list to assure that no ezmlm-send is working on it */ /* and that the "num" message is final */ fdlock = lockfile("lock"); /* get num */ if (!getconf_ulong(&max,"num",0) || max == 0) strerr_die1x(100,MSG(ERR_EMPTY_LIST)); (void) close(fdlock); if (!optto || optto > max) optto = max; fdlock = lockfile("archive/lock"); /* lock index */ if (!flagcreate && !archnum) { /* adjust archnum (from) / to */ if (getconf_ulong(&archnum,"archnum",0)) ++archnum; else archnum = 0; } if (archnum > optto) _exit(0); /* nothing to do */ if (mkdir("archive/threads",0755) == -1) if (errno != error_exist) strerr_die2sys(111,FATAL,MSG1(ERR_CREATE,"archive/threads")); if (mkdir("archive/subjects",0755) == -1) if (errno != error_exist) strerr_die2sys(111,FATAL,MSG1(ERR_CREATE,"archive/subjects")); if (mkdir("archive/authors",0755) == -1) if (errno != error_exist) strerr_die2sys(111,FATAL,MSG1(ERR_CREATE,"archive/authors")); /* do the subject threading */ idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,archnum,optto,max,0); /* update the index */ write_threads(msgtable,subtable,authtable,datetable,archnum,optto); /* update archnum */ if ((fd = open_trunc("archnumn")) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CREATE,"archnumn")); substdio_fdbuf(&ssnum,write,fd,numbuf,sizeof(numbuf)); if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,optto)) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn.s)); if (substdio_puts(&ssnum,"\n") == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn.s)); close_proper(&ssnum,"archnum","archnumn"); switch (flagerror) { case 0: _exit(0); /* go bye-bye */ case -1: strerr_die2x(99,WARNING,"threads entry with illegal format"); case -2: strerr_die2x(99,WARNING,"thread in index, but threadfile missing"); case -3: strerr_die2x(99,WARNING,"a subject file lacks subject"); case -4: strerr_die2x(99,WARNING,"an author file lacks author/hash"); case -5: strerr_die2x(99,WARNING,"threads entry lacks message count"); default: strerr_die2x(99,WARNING,"something happened that isn't quite right"); } }