📄 deliver.c
字号:
if (tTd(11, 2)) printf("openmailer: running as r/euid=%d/%d\n", getuid(), geteuid()); /* move into some "safe" directory */ if (m->m_execdir != NULL) { char *p, *q; char buf[MAXLINE]; for (p = m->m_execdir; p != NULL; p = q) { q = strchr(p, ':'); if (q != NULL) *q = '\0'; expand(p, buf, &buf[sizeof buf] - 1, e); if (q != NULL) *q++ = ':'; if (tTd(11, 20)) printf("openmailer: trydir %s\n", buf); if (buf[0] != '\0' && chdir(buf) >= 0) break; } } /* arrange to filter std & diag output of command */ if (clever) { (void) close(rpvect[0]); if (dup2(rpvect[1], STDOUT_FILENO) < 0) { syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", e->e_to, m->m_name, rpvect[1]); _exit(EX_OSERR); } (void) close(rpvect[1]); } else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || HoldErrs || DisConnected) { /* put mailer output in transcript */ if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) { syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", e->e_to, m->m_name, fileno(e->e_xfp)); _exit(EX_OSERR); } } if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) { syserr("%s... openmailer(%s): cannot dup stdout for stderr", e->e_to, m->m_name); _exit(EX_OSERR); } /* arrange to get standard input */ (void) close(mpvect[1]); if (dup2(mpvect[0], STDIN_FILENO) < 0) { syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", e->e_to, m->m_name, mpvect[0]); _exit(EX_OSERR); } (void) close(mpvect[0]); /* arrange for all the files to be closed */ for (i = 3; i < DtableSize; i++) { register int j; if ((j = fcntl(i, F_GETFD, 0)) != -1) (void) fcntl(i, F_SETFD, j | 1); } /* ** Set up the mailer environment ** TZ is timezone information. ** SYSTYPE is Apollo software sys type (required). ** ISP is Apollo hardware system type (required). */ i = 0; env[i++] = "AGENT=sendmail"; for (ep = environ; *ep != NULL; ep++) { if (strncmp(*ep, "TZ=", 3) == 0 || strncmp(*ep, "ISP=", 4) == 0 || strncmp(*ep, "SYSTYPE=", 8) == 0) env[i++] = *ep; } env[i++] = NULL; /* run disconnected from terminal */ (void) setsid(); /* try to execute the mailer */ execve(m->m_mailer, pv, env); saveerrno = errno; syserr("Cannot exec %s", m->m_mailer); if (m == LocalMailer || transienterror(saveerrno)) _exit(EX_OSERR); _exit(EX_UNAVAILABLE); } /* ** Set up return value. */ mci = (MCI *) xalloc(sizeof *mci); bzero((char *) mci, sizeof *mci); mci->mci_mailer = m; mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; mci->mci_pid = pid; (void) close(mpvect[0]); mci->mci_out = fdopen(mpvect[1], "w"); if (mci->mci_out == NULL) { syserr("deliver: cannot create mailer output channel, fd=%d", mpvect[1]); (void) close(mpvect[1]); if (clever) { (void) close(rpvect[0]); (void) close(rpvect[1]); } rcode = EX_OSERR; goto give_up; } if (clever) { (void) close(rpvect[1]); mci->mci_in = fdopen(rpvect[0], "r"); if (mci->mci_in == NULL) { syserr("deliver: cannot create mailer input channel, fd=%d", mpvect[1]); (void) close(rpvect[0]); fclose(mci->mci_out); mci->mci_out = NULL; rcode = EX_OSERR; goto give_up; } } else { mci->mci_flags |= MCIF_TEMP; mci->mci_in = NULL; } } /* ** If we are in SMTP opening state, send initial protocol. */ if (clever && mci->mci_state != MCIS_CLOSED) { smtpinit(m, mci, e); } if (tTd(11, 1)) { printf("openmailer: "); mci_dump(mci, FALSE); } if (mci->mci_state != MCIS_OPEN) { /* couldn't open the mailer */ rcode = mci->mci_exitstat; errno = mci->mci_errno;#if NAMED_BIND h_errno = mci->mci_herrno;#endif if (rcode == EX_OK) { /* shouldn't happen */ syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", rcode, mci->mci_state, firstsig); rcode = EX_SOFTWARE; } else if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0') { /* try next MX site */ goto tryhost; } } else if (!clever) { /* ** Format and send message. */ putfromline(mci, e); (*e->e_puthdr)(mci, e); putline("\n", mci); (*e->e_putbody)(mci, e, NULL); /* get the exit status */ rcode = endmailer(mci, e, pv); } else#ifdef SMTP { /* ** Send the MAIL FROM: protocol */ rcode = smtpmailfrom(m, mci, e); if (rcode == EX_OK) { register char *t = tobuf; register int i; /* send the recipient list */ tobuf[0] = '\0'; for (to = tochain; to != NULL; to = to->q_tchain) { e->e_to = to->q_paddr; if ((i = smtprcpt(to, m, mci, e)) != EX_OK) { markfailure(e, to, i); giveresponse(i, m, mci, ctladdr, e); } else { *t++ = ','; for (p = to->q_paddr; *p; *t++ = *p++) continue; *t = '\0'; } } /* now send the data */ if (tobuf[0] == '\0') { rcode = EX_OK; e->e_to = NULL; if (bitset(MCIF_CACHED, mci->mci_flags)) smtprset(m, mci, e); } else { e->e_to = tobuf + 1; rcode = smtpdata(m, mci, e); } /* now close the connection */ if (!bitset(MCIF_CACHED, mci->mci_flags)) smtpquit(m, mci, e); } if (rcode != EX_OK && curhost != NULL && *curhost != '\0') { /* try next MX site */ goto tryhost; } }#else /* not SMTP */ { syserr("554 deliver: need SMTP compiled to use clever mailer"); rcode = EX_CONFIG; goto give_up; }#endif /* SMTP */#if NAMED_BIND if (ConfigLevel < 2) _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */#endif /* arrange a return receipt if requested */ if (rcode == EX_OK && e->e_receiptto != NULL && bitnset(M_LOCALMAILER, m->m_flags)) { e->e_flags |= EF_SENDRECEIPT; /* do we want to send back more info? */ } /* ** Do final status disposal. ** We check for something in tobuf for the SMTP case. ** If we got a temporary failure, arrange to queue the ** addressees. */ give_up: if (tobuf[0] != '\0') giveresponse(rcode, m, mci, ctladdr, e); for (to = tochain; to != NULL; to = to->q_tchain) { if (rcode != EX_OK) markfailure(e, to, rcode); else { to->q_flags |= QSENT; e->e_nsent++; if (e->e_receiptto != NULL && bitnset(M_LOCALMAILER, m->m_flags)) { fprintf(e->e_xfp, "%s... Successfully delivered\n", to->q_paddr); } } } /* ** Restore state and return. */#ifdef XDEBUG { char wbuf[MAXLINE]; /* make absolutely certain 0, 1, and 2 are in use */ sprintf(wbuf, "%s... end of deliver(%s)", e->e_to == NULL ? "NO-TO-LIST" : e->e_to, m->m_name); checkfd012(wbuf); }#endif errno = 0; define('g', (char *) NULL, e); return (rcode);}/*** MARKFAILURE -- mark a failure on a specific address.**** Parameters:** e -- the envelope we are sending.** q -- the address to mark.** rcode -- the code signifying the particular failure.**** Returns:** none.**** Side Effects:** marks the address (and possibly the envelope) with the** failure so that an error will be returned or** the message will be queued, as appropriate.*/markfailure(e, q, rcode) register ENVELOPE *e; register ADDRESS *q; int rcode;{ char buf[MAXLINE]; switch (rcode) { case EX_OK: break; case EX_TEMPFAIL: case EX_IOERR: case EX_OSERR: q->q_flags |= QQUEUEUP; break; default: q->q_flags |= QBADADDR; break; }}/*** ENDMAILER -- Wait for mailer to terminate.**** We should never get fatal errors (e.g., segmentation** violation), so we report those specially. For other** errors, we choose a status message (into statmsg),** and if it represents an error, we print it.**** Parameters:** pid -- pid of mailer.** e -- the current envelope.** pv -- the parameter vector that invoked the mailer** (for error messages).**** Returns:** exit code of mailer.**** Side Effects:** none.*/endmailer(mci, e, pv) register MCI *mci; register ENVELOPE *e; char **pv;{ int st; /* close any connections */ if (mci->mci_in != NULL) (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in"); if (mci->mci_out != NULL) (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out"); mci->mci_in = mci->mci_out = NULL; mci->mci_state = MCIS_CLOSED; /* in the IPC case there is nothing to wait for */ if (mci->mci_pid == 0) return (EX_OK); /* wait for the mailer process to die and collect status */ st = waitfor(mci->mci_pid); if (st == -1) { syserr("endmailer %s: wait", pv[0]); return (EX_SOFTWARE); } if (WIFEXITED(st)) { /* normal death -- return status */ return (WEXITSTATUS(st)); } /* it died a horrid death */ syserr("451 mailer %s died with signal %o", mci->mci_mailer->m_name, st); /* log the arguments */ if (pv != NULL && e->e_xfp != NULL) { register char **av; fprintf(e->e_xfp, "Arguments:"); for (av = pv; *av != NULL; av++) fprintf(e->e_xfp, " %s", *av); fprintf(e->e_xfp, "\n"); } ExitStat = EX_TEMPFAIL; return (EX_TEMPFAIL);}/*** GIVERESPONSE -- Interpret an error response from a mailer**** Parameters:** stat -- the status code from the mailer (high byte** only; core dumps must have been taken care of** already).** m -- the mailer info for this mailer.** mci -- the mailer connection info -- can be NULL if the** response is given before the connection is made.** ctladdr -- the controlling address for the recipient** address(es).** e -- the current envelope.**** Returns:** none.**** Side Effects:** Errors may be incremented.** ExitStat may be set.*/giveresponse(stat, m, mci, ctladdr, e) int stat; register MAILER *m; register MCI *mci; ADDRESS *ctladdr; ENVELOPE *e;{ register const char *statmsg; extern char *SysExMsg[]; register int i; extern int N_SysEx; char buf[MAXLINE]; /* ** Compute status message from code. */ i = stat - EX__BASE; if (stat == 0) { statmsg = "250 Sent"; if (e->e_statmsg != NULL) { (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); statmsg = buf; } } else if (i < 0 || i > N_SysEx) { (void) sprintf(buf, "554 unknown mailer error %d", stat); stat = EX_UNAVAILABLE; statmsg = buf; } else if (stat == EX_TEMPFAIL) { (void) strcpy(buf, SysExMsg[i] + 1);#if NAMED_BIND if (h_errno == TRY_AGAIN) statmsg = errstring(h_errno+E_DNSBASE); else#endif { if (errno != 0) statmsg = errstring(errno); else {#ifdef SMTP statmsg = SmtpError;#else /* SMTP */ statmsg = NULL;#endif /* SMTP */ } } if (statmsg != NULL && statmsg[0] != '\0') { (void) strcat(buf, ": "); (void) strcat(buf, statmsg); } statmsg = buf; }#if NAMED_BIND else if (stat == EX_NOHOST && h_errno != 0) { statmsg = errstring(h_errno + E_DNSBASE); (void) sprintf(buf, "%s (%s)", SysExMsg[i], statmsg); statmsg = buf; }#endif else { statmsg = SysExMsg[i]; if (*statmsg++ == ':') { (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); statmsg = buf; } } /* ** Print the message as appropriate */ if (stat == EX_OK || stat == EX_TEMPFAIL) { extern char MsgBuf[]; message("%s", &statmsg[4]); if (stat == EX_TEMPFAIL && e->e_xfp != NULL) fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); } else { Errors++; usrerr(statmsg, errstring(errno)); } /* ** Final cleanup. ** Log a record of the transaction. Compute the new ** ExitStat -- if we already had an error, stick with ** that. */ if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) logdelivery(m, mci, &statmsg[4], ctladdr, e); if (tTd(11, 2)) printf("giveresponse: stat=%d, e->e_message=%s\n", stat, e->e_message); if (stat != EX_TEMPFAIL) setstat(stat); if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) { if (e->e_message != NULL) free(e->e_message); e->e_message = newstr(&statmsg[4]); } errno = 0;#if NAMED_BIND h_errno = 0;#endif}/*** LOGDELIVERY -- log the delivery in the system log**** Care is taken to avoid logging lines that are too long, because** some versions of syslog have an unfortunate proclivity for core** dumping. This is a hack, to be sure, that is at best empirical.**** Parameters:** m -- the mailer info. Can be NULL for initial queue.** mci -- the mailer connection info -- can be NULL if the** log is occuring when no connection is active.** stat -- the message to print for the status.** ctladdr -- the controlling address for the to list.** e -- the current envelope.**** Returns:** none**** Side Effects:** none*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -