/* * Run a command to authorize or refuse entry. Return status 0 means * authorize, -1 means refuse. */ void authorize(dest *dp) { process *pp; String *errstr; dp->authorized = 1; pp = proc_start(s_to_c(dp->repl1), (stream *)0, (stream *)0, outstream(), 1, 0); if (pp == 0){ dp->status = d_noforward; return; } errstr = s_new(); while(s_read_line(pp->std[2]->fp, errstr)) ; if ((dp->pstat = proc_wait(pp)) != 0) { dp->repl2 = errstr; dp->status = d_noforward; } else s_free(errstr); proc_free(pp); }
/* pipe an address through a command to translate it */ extern dest * translate(dest *dp) { process *pp; String *line; dest *rv; char *cp; int n; pp = proc_start(s_to_c(dp->repl1), (stream *)0, outstream(), outstream(), 1, 0); if (pp == 0) { dp->status = d_resource; return 0; } line = s_new(); for(;;) { cp = Brdline(pp->std[1]->fp, '\n'); if(cp == 0) break; if(strncmp(cp, "_nosummary_", 11) == 0){ nosummary = 1; continue; } n = Blinelen(pp->std[1]->fp); cp[n-1] = ' '; s_nappend(line, cp, n); } rv = s_to_dest(s_restart(line), dp); s_restart(line); while(s_read_line(pp->std[2]->fp, line)) ; if ((dp->pstat = proc_wait(pp)) != 0) { dp->repl2 = line; rv = 0; } else s_free(line); proc_free(pp); return rv; }
void data(void) { int status, nbytes; char *cp, *ep; char errx[ERRMAX]; Link *l; String *cmd, *err; if(rejectcheck()) return; if(senders.last == 0){ reply("503 2.5.2 Data without MAIL FROM:\r\n"); rejectcount++; return; } if(rcvers.last == 0){ reply("503 2.5.2 Data without RCPT TO:\r\n"); rejectcount++; return; } if(!trusted && sendermxcheck()){ rerrstr(errx, sizeof errx); if(strncmp(errx, "rejected:", 9) == 0) reply("554 5.7.1 %s\r\n", errx); else reply("450 4.7.0 %s\r\n", errx); for(l=rcvers.first; l; l=l->next) syslog(0, "smtpd", "[%s/%s] %s -> %s sendercheck: %s", him, nci->rsys, s_to_c(senders.first->p), s_to_c(l->p), errx); rejectcount++; return; } cmd = startcmd(); if(cmd == 0) return; reply("354 Input message; end with <CRLF>.<CRLF>\r\n"); if(debug){ seek(2, 0, 2); stamp(); fprint(2, "# sent 354; accepting DATA %s\n", thedate()); } /* * allow 145 more minutes to move the data */ alarm(145*60*1000); status = pipemsg(&nbytes); /* * read any error messages */ err = s_new(); if (debug) { stamp(); fprint(2, "waiting for upas/send to close stderr\n"); } while(s_read_line(pp->std[2]->fp, err)) ; alarm(0); atnotify(catchalarm, 0); if (debug) { stamp(); fprint(2, "waiting for upas/send to exit\n"); } status |= proc_wait(pp); if(debug){ seek(2, 0, 2); stamp(); fprint(2, "# %d upas/send status %#ux at %s\n", getpid(), status, thedate()); if(*s_to_c(err)) fprint(2, "# %d error %s\n", getpid(), s_to_c(err)); } /* * if process terminated abnormally, send back error message */ if(status){ int code; char *ecode; if(strstr(s_to_c(err), "mail refused")){ syslog(0, "smtpd", "++[%s/%s] %s %s refused: %s", him, nci->rsys, s_to_c(senders.first->p), s_to_c(cmd), firstline(s_to_c(err))); code = 554; ecode = "5.0.0"; } else { syslog(0, "smtpd", "++[%s/%s] %s %s %s%s%sreturned %#q %s", him, nci->rsys, s_to_c(senders.first->p), s_to_c(cmd), piperror? "error during pipemsg: ": "", piperror? piperror: "", piperror? "; ": "", pp->waitmsg->msg, firstline(s_to_c(err))); code = 450; ecode = "4.0.0"; } for(cp = s_to_c(err); ep = strchr(cp, '\n'); cp = ep){ *ep++ = 0; reply("%d-%s %s\r\n", code, ecode, cp); } reply("%d %s mail process terminated abnormally\r\n", code, ecode); } else { /* * if a message appeared on stderr, despite good status, * log it. this can happen if rewrite.in contains a bad * r.e., for example. */ if(*s_to_c(err)) syslog(0, "smtpd", "%s returned good status, but said: %s", s_to_c(mailer), s_to_c(err)); if(filterstate == BLOCKED) reply("554 5.7.1 we believe this is spam. " "we don't accept it.\r\n"); else if(filterstate == DELAY) reply("450 4.3.0 There will be a delay in delivery " "of this message.\r\n"); else { reply("250 2.5.0 sent\r\n"); logcall(nbytes); if(debug){ seek(2, 0, 2); stamp(); fprint(2, "# %d sent 250 reply %s\n", getpid(), thedate()); } } } proc_free(pp); pp = 0; s_free(cmd); s_free(err); listfree(&senders); listfree(&rcvers); }
void main(int argc, char **argv) { String *msg; String *firstline; char *listname, *alfile; Waitmsg *w; int fd; char *replytoname = nil; ARGBEGIN{ case 'r': replytoname = ARGF(); break; }ARGEND; rfork(RFENVG|RFREND); if(argc < 2) usage(); alfile = argv[0]; listname = argv[1]; if(replytoname == nil) replytoname = listname; readaddrs(alfile); if(Binit(&in, 0, OREAD) < 0) sysfatal("opening input: %r"); msg = s_new(); firstline = s_new(); /* discard the 'From ' line */ if(s_read_line(&in, firstline) == nil) sysfatal("reading input: %r"); /* read up to the first 128k of the message. more is ridiculous. Not if word documents are distributed. Upped it to 2MB (pb) */ if(s_read(&in, msg, 2*1024*1024) <= 0) sysfatal("reading input: %r"); /* parse the header */ yyinit(s_to_c(msg), s_len(msg)); yyparse(); /* get the sender */ getaddrs(); if(from == nil) from = sender; if(from == nil) sysfatal("message must contain From: or Sender:"); if(strcmp(listname, s_to_c(from)) == 0) sysfatal("can't remail messages from myself"); addaddr(s_to_c(from)); /* start the mailer up and return a pipe to it */ fd = startmailer(listname); /* send message adding our own reply-to and precedence */ printmsg(fd, msg, replytoname, listname); close(fd); /* wait for mailer to end */ while(w = wait()){ if(w->msg != nil && w->msg[0]) sysfatal("%s", w->msg); free(w); } /* if the mailbox exists, cat the mail to the end of it */ appendtoarchive(listname, firstline, msg); exits(0); }
/* read in a message, interpret the 'From' header */ extern message * m_read(Biobuf *fp, int rmail, int interactive) { message *mp; Resub subexp[10]; char *line; int first; int n; mp = m_new(); /* parse From lines if remote */ if (rmail) { /* get remote address */ String *sender=s_new(); if (rfprog == 0) rfprog = regcomp(REMFROMRE); first = 1; while(s_read_line(fp, s_restart(mp->body)) != 0) { memset(subexp, 0, sizeof(subexp)); if (regexec(rfprog, s_to_c(mp->body), subexp, 10) == 0){ if(first == 0) break; if (fprog == 0) fprog = regcomp(FROMRE); memset(subexp, 0, sizeof(subexp)); if(regexec(fprog, s_to_c(mp->body), subexp,10) == 0) break; s_restart(mp->body); append_match(subexp, s_restart(sender), SENDERMATCH); append_match(subexp, s_restart(mp->date), DATEMATCH); break; } append_match(subexp, s_restart(sender), REMSENDERMATCH); append_match(subexp, s_restart(mp->date), REMDATEMATCH); if(subexp[REMSYSMATCH].sp!=subexp[REMSYSMATCH].ep){ append_match(subexp, mp->sender, REMSYSMATCH); s_append(mp->sender, "!"); } first = 0; } s_append(mp->sender, s_to_c(sender)); s_free(sender); } if(*s_to_c(mp->sender)=='\0') default_from(mp); /* if sender address is unreturnable, treat message as bulk mail */ if(!returnable(s_to_c(mp->sender))) mp->bulk = 1; /* get body */ if(interactive && !rmail){ /* user typing on terminal: terminator == '.' or EOF */ for(;;) { line = s_read_line(fp, mp->body); if (line == 0) break; if (strcmp(".\n", line)==0) { mp->body->ptr -= 2; *mp->body->ptr = '\0'; break; } } mp->size = mp->body->ptr - mp->body->base; } else { /* * read up to VMLIMIT bytes (more or less) into main memory. * if message is longer put the rest in a tmp file. */ mp->size = mp->body->ptr - mp->body->base; n = s_read(fp, mp->body, VMLIMIT); if(n < 0){ perror("m_read"); exit(1); } mp->size += n; if(n == VMLIMIT){ if(m_read_to_file(fp, mp) < 0){ perror("m_read"); exit(1); } } } /* * ignore 0 length messages from a terminal */ if (!rmail && mp->size == 0) return 0; rfc822cruft(mp); return mp; }