static int execute_line(const char *fn,const char *line) { int child; int code; if (seek_begin(0) == -1) strerr_die2sys(111,FATAL,MSG(ERR_SEEK_INPUT)); while (*line && (*line == '\t' || *line == ' ')) ++line; switch (*line) { case '#': /* ignore comments */ return 0; case '|': if ((child = wrap_fork()) == 0) wrap_execsh(line+1); code = wrap_waitpid(child); ++did_program; return code; case '/': case '.': strerr_die5x(100,FATAL,basedir.s,"/",fn,": Delivery to files is not supported."); return 100; default: if (*line == '&') ++line; forward(line); return 0; } }
static void do_ed(char *action) { datetime_sec u; int flaggoodfield; int fd; char *x, *y; char *cp,*cplast,*cpnext,*cpafter; int flagdone; unsigned int len; const char *fname; unsigned int i; x = action + LENGTH_ED; x += scan_ulong(x,&u); if ((u > when) || (u < when - 100000)) die_cookie(); if (*x == '.') ++x; fname = x; x += str_chr(x,'.'); if (!*x) die_cookie(); *x = (char) 0; ++x; stralloc_copys(&fnedit,"text/"); stralloc_cats(&fnedit,fname); stralloc_0(&fnedit); y = fnedit.s + 5; /* after "text/" */ while (*++y) { /* Name should be guaranteed by the cookie, */ /* but better safe than sorry ... */ if (((*y > 'z') || (*y < 'a')) && (*y != '_')) strerr_die2x(100,FATAL,MSG(ERR_BAD_NAME)); if (*y == '_') *y = '-'; } lock(); /* file must not change while here */ switch (slurp(fnedit.s,&text,1024)) { case -1: strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnedit.s)); case 0: strerr_die5x(100,FATAL,dir,"/",fnedit.s,MSG(ERR_NOEXIST)); } stralloc_copy(&line,&text); subst_nuls(&line); stralloc_cat(&line,&fnedit); /* including '\0' */ strnum[fmt_ulong(strnum,(unsigned long) u)] = 0; cookie(hash,key.s,key.len,strnum,line.s,"-e"); if (str_len(x) != COOKIE) die_cookie(); if (byte_diff(hash,COOKIE,x)) die_cookie(); /* cookie is ok, file exists, lock's on, new file ends in '_' */ stralloc_copys(&fneditn,fnedit.s); stralloc_append(&fneditn,'_'); stralloc_0(&fneditn); fd = open_trunc(fneditn.s); if (fd == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s)); substdio_fdbuf(&sstext,write,fd,textbuf,sizeof(textbuf)); stralloc_copys("ed,""); /* clear */ stralloc_copys(&text,""); for (;;) { /* get message body */ if (getln(&ssin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); if (!match) break; stralloc_cat(&text,&line); } if (encin) { /* decode if necessary */ if (encin == 'B') decodeB(text.s,text.len,&line); else decodeQ(text.s,text.len,&line); stralloc_copy(&text,&line); } cp = text.s; cpafter = text.s+text.len; flaggoodfield = 0; flagdone = 0; len = 0; while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) { i = byte_chr(cp,cpnext-cp,'%'); if (i != (unsigned int) (cpnext - cp)) { if (!flaggoodfield) { /* MSG(TXT_EDIT_START)/END */ if (case_startb(cp+i,cpnext-cp-i,MSG(TXT_EDIT_START))) { /* start tag. Store users 'quote characters', e.g. '> ' */ stralloc_copyb("ed,cp,i); flaggoodfield = 1; cp = cpnext + 1; continue; } } else if (case_startb(cp+i,cpnext-cp-i,MSG(TXT_EDIT_END))) { flagdone = 1; break; } } if (flaggoodfield) { if ((len += cpnext - cp - quoted.len + 1) > MAXEDIT) strerr_die1x(100,MSG(ERR_EDSIZE)); if (quoted.len && cpnext-cp >= (int) quoted.len && !str_diffn(cp,quoted.s,quoted.len)) cp += quoted.len; /* skip quoting characters */ cplast = cpnext - 1; if (*cplast == '\r') /* CRLF -> '\n' for base64 encoding */ *cplast = '\n'; else ++cplast; if (substdio_put(&sstext,cp,cplast-cp+1) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s)); } cp = cpnext + 1; } if (!flagdone) strerr_die2x(100,FATAL,MSG(ERR_NO_MARK)); if (substdio_flush(&sstext) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s)); if (fsync(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,fneditn.s)); if (fchmod(fd, 0600) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CHMOD,fneditn.s)); if (close(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,fneditn.s)); wrap_rename(fneditn.s,fnedit.s); unlock(); hdr_subject(MSG1(SUB_EDIT_SUCCESS,fname)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/edit-done"); copybottom(0); qmail_to(&qq,sender); /* not necessarily from mod */ }
static void do_edit(const char *action) { unsigned int i; unsigned int len; char ch; /* only remote admins and only if -e is specified may edit */ if (!flagedit || remote.s == 0) strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE)); if (!ismod) strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED)); len = str_len(ACTION_EDIT); if (!case_starts(action,ACTION_EDIT)) len = str_len(ALT_EDIT); if (action[len]) { /* -edit.file, not just -edit */ if (action[len] != '.') strerr_die2x(100,FATAL,MSG(ERR_BAD_REQUEST)); showsend2("edit ",action+len+1); stralloc_copys(&fnedit,"text/"); stralloc_cats(&fnedit,action+len+1); stralloc_0(&fnedit); case_lowerb(fnedit.s,fnedit.len); i = 5; /* after the "text/" */ while ((ch = fnedit.s[i++])) { if (((ch > 'z') || (ch < 'a')) && (ch != '_')) strerr_die2x(100,FATAL,MSG(ERR_BAD_NAME)); if (ch == '_') fnedit.s[i-1] = '-'; } switch(slurp(fnedit.s,&text,1024)) { /* entire file! */ case -1: strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnedit.s)); case 0: strerr_die5x(100,FATAL,dir,"/",fnedit.s,MSG(ERR_NOEXIST)); } stralloc_copy(&line,&text); subst_nuls(&line); stralloc_cat(&line,&fnedit); /* including '\0' */ strnum[fmt_ulong(strnum,(unsigned long) when)] = 0; cookie(hash,key.s,key.len,strnum,line.s,"-e"); stralloc_copy(&confirm,&outlocal); stralloc_append(&confirm,'-'); stralloc_catb(&confirm,ACTION_ED,LENGTH_ED); stralloc_cats(&confirm,strnum); stralloc_append(&confirm,'.'); /* action part has been checked for bad chars */ stralloc_cats(&confirm,action + len + 1); stralloc_append(&confirm,'.'); stralloc_catb(&confirm,hash,COOKIE); stralloc_append(&confirm,'@'); stralloc_cat(&confirm,&outhost); stralloc_0(&confirm); set_cpconfirm(confirm.s,outlocal.len); set_cpaction(ACTION_ED); set_cphash(hash); set_cpwhen(when); qmail_puts(&qq,"Reply-To: "); quote2("ed,confirm.s); qmail_put(&qq,quoted.s,quoted.len); qmail_puts(&qq,"\n"); hdr_subject(MSG1(SUB_EDIT_REQUEST,action+len+1)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy(&qq,"text/edit-do",flagcd); (void) code_qputs(MSG(TXT_EDIT_START)); (void) code_qput(text.s,text.len); (void) code_qputs(MSG(TXT_EDIT_END)); } else { /* -edit only, so output list of editable files */ hdr_subject(MSG(SUB_EDIT_LIST)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/edit-list"); } qmail_puts(&qq,"\n\n"); copybottom(0); qmail_to(&qq,mod.s); }