📄 deliver.c
字号:
logdelivery(m, mci, stat, ctladdr, e) MAILER *m; register MCI *mci; char *stat; ADDRESS *ctladdr; register ENVELOPE *e;{# ifdef LOG register char *bp; register char *p; int l; char buf[512];# if (SYSLOG_BUFSIZE) >= 256 bp = buf; if (ctladdr != NULL) { strcpy(bp, ", ctladdr="); strcat(bp, shortenstring(ctladdr->q_paddr, 83)); bp += strlen(bp); if (bitset(QGOODUID, ctladdr->q_flags)) { (void) sprintf(bp, " (%d/%d)", ctladdr->q_uid, ctladdr->q_gid); bp += strlen(bp); } } (void) sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); bp += strlen(bp); if (m != NULL) { (void) strcpy(bp, ", mailer="); (void) strcat(bp, m->m_name); bp += strlen(bp); } if (mci != NULL && mci->mci_host != NULL) {# ifdef DAEMON extern SOCKADDR CurHostAddr;# endif (void) strcpy(bp, ", relay="); (void) strcat(bp, mci->mci_host);# ifdef DAEMON (void) strcat(bp, " ["); (void) strcat(bp, anynet_ntoa(&CurHostAddr)); (void) strcat(bp, "]");# endif } else if (strcmp(stat, "queued") != 0) { char *p = macvalue('h', e); if (p != NULL && p[0] != '\0') { (void) strcpy(bp, ", relay="); (void) strcat(bp, p); } } bp += strlen(bp);#define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4)#if (STATLEN) < 63# undef STATLEN# define STATLEN 63#endif#if (STATLEN) > 203# undef STATLEN# define STATLEN 203#endif if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) { /* desperation move -- truncate data */ bp = buf + sizeof buf - ((STATLEN) + 17); strcpy(bp, "..."); bp += 3; } (void) strcpy(bp, ", stat="); bp += strlen(bp); (void) strcpy(bp, shortenstring(stat, (STATLEN))); l = SYSLOG_BUFSIZE - 100 - strlen(buf); p = e->e_to; while (strlen(p) >= l) { register char *q = strchr(p + l, ','); if (q == NULL) break; syslog(LOG_INFO, "%s: to=%.*s [more]%s", e->e_id, ++q - p, p, buf); p = q; } syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf);# else /* we have a very short log buffer size */ l = SYSLOG_BUFSIZE - 85; p = e->e_to; while (strlen(p) >= l) { register char *q = strchr(p + l, ','); if (q == NULL) break; syslog(LOG_INFO, "%s: to=%.*s [more]", e->e_id, ++q - p, p); p = q; } syslog(LOG_INFO, "%s: to=%s", e->e_id, p); if (ctladdr != NULL) { bp = buf; strcpy(buf, "ctladdr="); bp += strlen(buf); strcpy(bp, shortenstring(ctladdr->q_paddr, 83)); bp += strlen(buf); if (bitset(QGOODUID, ctladdr->q_flags)) { (void) sprintf(bp, " (%d/%d)", ctladdr->q_uid, ctladdr->q_gid); bp += strlen(bp); } syslog(LOG_INFO, "%s: %s", e->e_id, buf); } bp = buf; sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); bp += strlen(bp); if (m != NULL) { sprintf(bp, ", mailer=%s", m->m_name); bp += strlen(bp); } syslog(LOG_INFO, "%s: %s", e->e_id, buf); buf[0] = '\0'; if (mci != NULL && mci->mci_host != NULL) {# ifdef DAEMON extern SOCKADDR CurHostAddr;# endif sprintf(buf, "relay=%s", mci->mci_host);# ifdef DAEMON (void) strcat(buf, " ["); (void) strcat(buf, anynet_ntoa(&CurHostAddr)); (void) strcat(buf, "]");# endif } else if (strcmp(stat, "queued") != 0) { char *p = macvalue('h', e); if (p != NULL && p[0] != '\0') sprintf(buf, "relay=%s", p); } if (buf[0] != '\0') syslog(LOG_INFO, "%s: %s", e->e_id, buf); syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63));# endif /* short log buffer */# endif /* LOG */}/*** PUTFROMLINE -- output a UNIX-style from line (or whatever)**** This can be made an arbitrary message separator by changing $l**** One of the ugliest hacks seen by human eyes is contained herein:** UUCP wants those stupid "remote from <host>" lines. Why oh why** does a well-meaning programmer such as myself have to deal with** this kind of antique garbage????**** Parameters:** mci -- the connection information.** e -- the envelope.**** Returns:** none**** Side Effects:** outputs some text to fp.*/putfromline(mci, e) register MCI *mci; ENVELOPE *e;{ char *template = "\201l\n"; char buf[MAXLINE]; if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) return;# ifdef UGLYUUCP if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) { char *bang; char xbuf[MAXLINE]; expand("\201g", buf, &buf[sizeof buf - 1], e); bang = strchr(buf, '!'); if (bang == NULL) { errno = 0; syserr("554 No ! in UUCP From address! (%s given)", buf); } else { *bang++ = '\0'; (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); template = xbuf; } }# endif /* UGLYUUCP */ expand(template, buf, &buf[sizeof buf - 1], e); putline(buf, mci);}/*** PUTBODY -- put the body of a message.**** Parameters:** mci -- the connection information.** e -- the envelope to put out.** separator -- if non-NULL, a message separator that must** not be permitted in the resulting message.**** Returns:** none.**** Side Effects:** The message is written onto fp.*/putbody(mci, e, separator) register MCI *mci; register ENVELOPE *e; char *separator;{ char buf[MAXLINE]; /* ** Output the body of the message */ if (e->e_dfp == NULL) { if (e->e_df != NULL) { e->e_dfp = fopen(e->e_df, "r"); if (e->e_dfp == NULL) syserr("putbody: Cannot open %s for %s from %s", e->e_df, e->e_to, e->e_from.q_paddr); } else putline("<<< No Message Collected >>>", mci); } if (e->e_dfp != NULL) { rewind(e->e_dfp); while (!ferror(mci->mci_out) && fgets(buf, sizeof buf, e->e_dfp) != NULL) { if (buf[0] == 'F' && bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && strncmp(buf, "From ", 5) == 0) (void) putc('>', mci->mci_out); if (buf[0] == '-' && buf[1] == '-' && separator != NULL) { /* possible separator */ int sl = strlen(separator); if (strncmp(&buf[2], separator, sl) == 0) (void) putc(' ', mci->mci_out); } putline(buf, mci); } if (ferror(e->e_dfp)) { syserr("putbody: %s: read error", e->e_df); ExitStat = EX_IOERR; } } /* some mailers want extra blank line at end of message */ if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && buf[0] != '\0' && buf[0] != '\n') putline("", mci); (void) fflush(mci->mci_out); if (ferror(mci->mci_out) && errno != EPIPE) { syserr("putbody: write error"); ExitStat = EX_IOERR; } errno = 0;}/*** MAILFILE -- Send a message to a file.**** If the file has the setuid/setgid bits set, but NO execute** bits, sendmail will try to become the owner of that file** rather than the real user. Obviously, this only works if** sendmail runs as root.**** This could be done as a subordinate mailer, except that it** is used implicitly to save messages in ~/dead.letter. We** view this as being sufficiently important as to include it** here. For example, if the system is dying, we shouldn't have** to create another process plus some pipes to save the message.**** Parameters:** filename -- the name of the file to send to.** ctladdr -- the controlling address header -- includes** the userid/groupid to be when sending.**** Returns:** The exit code associated with the operation.**** Side Effects:** none.*/mailfile(filename, ctladdr, e) char *filename; ADDRESS *ctladdr; register ENVELOPE *e;{ register FILE *f; register int pid; int mode; if (tTd(11, 1)) { printf("mailfile %s\n ctladdr=", filename); printaddr(ctladdr, FALSE); } if (e->e_xfp != NULL) fflush(e->e_xfp); /* ** Fork so we can change permissions here. ** Note that we MUST use fork, not vfork, because of ** the complications of calling subroutines, etc. */ DOFORK(fork); if (pid < 0) return (EX_OSERR); else if (pid == 0) { /* child -- actually write to file */ struct stat stb; MCI mcibuf; (void) setsignal(SIGINT, SIG_DFL); (void) setsignal(SIGHUP, SIG_DFL); (void) setsignal(SIGTERM, SIG_DFL); (void) umask(OldUmask); if (stat(filename, &stb) < 0) stb.st_mode = FileMode; mode = stb.st_mode; /* limit the errors to those actually caused in the child */ errno = 0; ExitStat = EX_OK; if (bitset(0111, stb.st_mode)) exit(EX_CANTCREAT); if (ctladdr != NULL) { /* ignore setuid and setgid bits */ mode &= ~(S_ISGID|S_ISUID); } /* we have to open the dfile BEFORE setuid */ if (e->e_dfp == NULL && e->e_df != NULL) { e->e_dfp = fopen(e->e_df, "r"); if (e->e_dfp == NULL) { syserr("mailfile: Cannot open %s for %s from %s", e->e_df, e->e_to, e->e_from.q_paddr); } } if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) { if (ctladdr == NULL || ctladdr->q_uid == 0) { (void) initgroups(DefUser, DefGid); } else { (void) initgroups(ctladdr->q_ruser ? ctladdr->q_ruser : ctladdr->q_user, ctladdr->q_gid); } } if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) { if (ctladdr == NULL || ctladdr->q_uid == 0) (void) setuid(DefUid); else (void) setuid(ctladdr->q_uid); } FileName = filename; LineNumber = 0; f = dfopen(filename, O_WRONLY|O_CREAT|O_APPEND, FileMode); if (f == NULL) { message("554 cannot open: %s", errstring(errno)); exit(EX_CANTCREAT); } bzero(&mcibuf, sizeof mcibuf); mcibuf.mci_mailer = FileMailer; mcibuf.mci_out = f; if (bitnset(M_7BITS, FileMailer->m_flags)) mcibuf.mci_flags |= MCIF_7BIT; putfromline(&mcibuf, e); (*e->e_puthdr)(&mcibuf, e); putline("\n", &mcibuf); (*e->e_putbody)(&mcibuf, e, NULL); putline("\n", &mcibuf); if (ferror(f)) { message("451 I/O error: %s", errstring(errno)); setstat(EX_IOERR); } (void) xfclose(f, "mailfile", filename); (void) fflush(stdout); /* reset ISUID & ISGID bits for paranoid systems */ (void) chmod(filename, (int) stb.st_mode); exit(ExitStat); /*NOTREACHED*/ } else { /* parent -- wait for exit status */ int st; st = waitfor(pid); if (WIFEXITED(st)) return (WEXITSTATUS(st)); else { syserr("child died on signal %d", st); return (EX_UNAVAILABLE); } /*NOTREACHED*/ }}/*** HOSTSIGNATURE -- return the "signature" for a host.**** The signature describes how we are going to send this -- it** can be just the hostname (for non-Internet hosts) or can be** an ordered list of MX hosts.**** Parameters:** m -- the mailer describing this host.** host -- the host name.** e -- the current envelope.**** Returns:** The signature for this host.**** Side Effects:** Can tweak the symbol table.*/char *hostsignature(m, host, e) register MAILER *m; char *host; ENVELOPE *e;{ register char *p; register STAB *s; int i; int len;#if NAMED_BIND int nmx; auto int rcode; char *hp; char *endp; int oldoptions; char *mxhosts[MAXMXHOSTS + 1];#endif /* ** Check to see if this uses IPC -- if not, it can't have MX records. */ p = m->m_mailer; if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) { /* just an ordinary mailer */ return host; } /* ** Look it up in the symbol table. */ s = stab(host, ST_HOSTSIG, ST_ENTER); if (s->s_hostsig != NULL) return s->s_hostsig; /* ** Not already there -- create a signature. */#if NAMED_BIND if (ConfigLevel < 2) { oldoptions = _res.options; _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ } for (hp = host; hp != NULL; hp = endp) { endp = strchr(hp, ':'); if (endp != NULL) *endp = '\0'; nmx = getmxrr(hp, mxhosts, TRUE, &rcode); if (nmx <= 0) { register MCI *mci; /* update the connection info for this host */ mci = mci_get(hp, m); mci->mci_exitstat = rcode; mci->mci_errno = errno;#if NAMED_BIND mci->mci_herrno = h_errno;#endif /* and return the original host name as the signature */ nmx = 1; mxhosts[0] = hp; } len = 0; for (i = 0; i < nmx; i++) { len += strlen(mxhosts[i]) + 1; } if (s->s_hostsig != NULL) len += strlen(s->s_hostsig) + 1; p = xalloc(len); if (s->s_hostsig != NULL) { (void) strcpy(p, s->s_hostsig); free(s->s_hostsig); s->s_hostsig = p; p += strlen(p); *p++ = ':'; } else s->s_hostsig = p; for (i = 0; i < nmx; i++) { if (i != 0) *p++ = ':'; strcpy(p, mxhosts[i]); p += strlen(p); } if (endp != NULL) *endp++ = ':'; } makelower(s->s_hostsig); if (ConfigLevel < 2) _res.options = oldoptions;#else /* not using BIND -- the signature is just the host name */ s->s_hostsig = host;#endif if (tTd(17, 1)) printf("hostsignature(%s) = %s\n", host, s->s_hostsig); return s->s_hostsig;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -