📄 deliver.c
字号:
{ (void) sprintf(buf, "554 unknown mailer error %d", stat); stat = EX_UNAVAILABLE; statmsg = buf; } else if (stat == EX_TEMPFAIL) { (void) strcpy(buf, SysExMsg[i]); if (h_errno == TRY_AGAIN) { extern char *errstring(); statmsg = errstring(h_errno+MAX_ERRNO); } else { if (errno != 0) { extern char *errstring(); statmsg = errstring(errno); } else {#ifdef SMTP extern char SmtpError[]; statmsg = SmtpError;#else SMTP statmsg = NULL;#endif SMTP } } if (statmsg != NULL && statmsg[0] != '\0') { (void) strcat(buf, ": "); (void) strcat(buf, statmsg); } statmsg = buf; } else { statmsg = SysExMsg[i]; } /* ** Print the message as appropriate */ if (stat == EX_OK || stat == EX_TEMPFAIL) message(Arpa_Info, &statmsg[4]); else { Errors++; usrerr(statmsg); } /* ** Final cleanup. ** Log a record of the transaction. Compute the new ** ExitStat -- if we already had an error, stick with ** that. */ if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) logdelivery(&statmsg[4]); if (stat != EX_TEMPFAIL) setstat(stat); if (stat != EX_OK) { if (e->e_message != NULL) free(e->e_message); e->e_message = newstr(&statmsg[4]); } errno = 0; h_errno = 0;}/*** LOGDELIVERY -- log the delivery in the system log**** Parameters:** stat -- the message to print for the status**** Returns:** none**** Side Effects:** none*/#define LOG_MAXTO 100logdelivery(stat) char *stat;{# ifdef LOG extern char *pintvl(); char *tp; char *delay; int len; /* * imcd/jch - fix to long log lines * * The syslog V2.4 facility is brain dead. It only handles * 5 arguments to sprintf! It core dumps if the message is * longer that 1000 bytes... The daemon corrupts its time counter... * * Thus this code: */ delay = pintvl(curtime() - CurEnv->e_ctime, TRUE); len=strlen(CurEnv->e_to); if (len <= LOG_MAXTO) return(syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, CurEnv->e_to, delay, stat)); for (tp=CurEnv->e_to; len>0; len -= LOG_MAXTO, tp += LOG_MAXTO) syslog(LOG_INFO, "%s: to=%s%.*s", CurEnv->e_id, (tp==CurEnv->e_to)?"":"(cont) ", LOG_MAXTO, tp); syslog(LOG_INFO, "%s: delay=%s, stat=%s", CurEnv->e_id, delay, stat);# 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:** fp -- the file to output to.** m -- the mailer describing this entry.**** Returns:** none**** Side Effects:** outputs some text to fp.*/putfromline(fp, m) register FILE *fp; register MAILER *m;{ char *template = "\001l\n"; char buf[MAXLINE]; if (bitnset(M_NHDR, m->m_flags)) return;# ifdef UGLYUUCP if (bitnset(M_UGLYUUCP, m->m_flags)) { char *bang; char xbuf[MAXLINE]; expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); bang = index(buf, '!'); if (bang == NULL) syserr("No ! in UUCP! (%s)", buf); else { *bang++ = '\0'; (void) sprintf(xbuf, "From %s \001d remote from %s\n", bang, buf); template = xbuf; } }# endif UGLYUUCP expand(template, buf, &buf[sizeof buf - 1], CurEnv); putline(buf, fp, m);}/*** PUTBODY -- put the body of a message.**** Parameters:** fp -- file to output onto.** m -- a mailer descriptor to control output format.** e -- the envelope to put out.**** Returns:** none.**** Side Effects:** The message is written onto fp.*/putbody(fp, m, e) FILE *fp; MAILER *m; register ENVELOPE *e;{ 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("Cannot open %s", e->e_df); } else putline("<<< No Message Collected >>>", fp, m); } if (e->e_dfp != NULL) { rewind(e->e_dfp); while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) { if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && strncmp(buf, "From", 4) == 0) (void) putc('>', fp); putline(buf, fp, m); } if (ferror(e->e_dfp)) { syserr("putbody: read error"); ExitStat = EX_IOERR; } } (void) fflush(fp); if (ferror(fp) && 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) char *filename; ADDRESS *ctladdr;{ register FILE *f; register int pid; /* ** 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; (void) signal(SIGINT, SIG_DFL); (void) signal(SIGHUP, SIG_DFL); (void) signal(SIGTERM, SIG_DFL); (void) umask(OldUmask); if (stat(filename, &stb) < 0) { errno = 0; stb.st_mode = 0666; } if (bitset(0111, stb.st_mode)) exit(EX_CANTCREAT); if (ctladdr == NULL) ctladdr = &CurEnv->e_from; if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) { if (ctladdr->q_uid == 0) { (void) setgid(DefGid); (void) initgroups(DefUser, DefGid); } else { (void) setgid(ctladdr->q_gid); (void) initgroups(ctladdr->q_ruser ? ctladdr->q_ruser : ctladdr->q_user, ctladdr->q_gid); } } if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) { if (ctladdr->q_uid == 0) (void) setuid(DefUid); else (void) setuid(ctladdr->q_uid); } f = dfopen(filename, "a"); if (f == NULL) exit(EX_CANTCREAT); putfromline(f, ProgMailer); (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); putline("\n", f, ProgMailer); (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); putline("\n", f, ProgMailer); (void) fclose(f); (void) fflush(stdout); /* reset ISUID & ISGID bits for paranoid systems */ (void) chmod(filename, (int) stb.st_mode); exit(EX_OK); /*NOTREACHED*/ } else { /* parent -- wait for exit status */ int st; st = waitfor(pid); if ((st & 0377) != 0) return (EX_UNAVAILABLE); else return ((st >> 8) & 0377); }}/*** SENDALL -- actually send all the messages.**** Parameters:** e -- the envelope to send.** mode -- the delivery mode to use. If SM_DEFAULT, use** the current SendMode.**** Returns:** none.**** Side Effects:** Scans the send lists and sends everything it finds.** Delivers any appropriate error messages.** If we are running in a non-interactive mode, takes the** appropriate action.*/sendall(e, mode) ENVELOPE *e; char mode;{ register ADDRESS *q; bool oldverbose; int pid; /* determine actual delivery mode */ if (mode == SM_DEFAULT) { extern bool shouldqueue(); if (shouldqueue(e->e_msgpriority)) mode = SM_QUEUE; else mode = SendMode; }#ifdef DEBUG if (tTd(13, 1)) { printf("\nSENDALL: mode %c, sendqueue:\n", mode); printaddr(e->e_sendqueue, TRUE); }#endif DEBUG /* ** Do any preprocessing necessary for the mode we are running. ** Check to make sure the hop count is reasonable. ** Delete sends to the sender in mailing lists. */ CurEnv = e; if (e->e_hopcount > MAXHOP) { syserr("sendall: too many hops (%d max)", MAXHOP); return; } if (!MeToo) { extern ADDRESS *recipient(); e->e_from.q_flags |= QDONTSEND; (void) recipient(&e->e_from, &e->e_sendqueue); }# ifdef QUEUE if ((mode == SM_QUEUE || mode == SM_FORK || (mode != SM_VERIFY && SuperSafe)) && !bitset(EF_INQUEUE, e->e_flags)) queueup(e, TRUE, mode == SM_QUEUE);#endif QUEUE oldverbose = Verbose; switch (mode) { case SM_VERIFY: Verbose = TRUE; break; case SM_QUEUE: e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; return; case SM_FORK: if (e->e_xfp != NULL) (void) fflush(e->e_xfp); pid = fork(); if (pid < 0) { mode = SM_DELIVER; break; } else if (pid > 0) { /* be sure we leave the temp files to our child */ e->e_id = e->e_df = NULL; return; } /* double fork to avoid zombies */ if (fork() > 0) exit(EX_OK); /* be sure we are immune from the terminal */ disconnect(FALSE); break; } /* ** Run through the list and send everything. */ for (q = e->e_sendqueue; q != NULL; q = q->q_next) { if (mode == SM_VERIFY) { e->e_to = q->q_paddr; if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) message(Arpa_Info, "deliverable"); } else (void) deliver(e, q); } Verbose = oldverbose; /* ** Now run through and check for errors. */ if (mode == SM_VERIFY) return; for (q = e->e_sendqueue; q != NULL; q = q->q_next) { register ADDRESS *qq;# ifdef DEBUG if (tTd(13, 3)) { printf("Checking "); printaddr(q, FALSE); }# endif DEBUG /* only send errors if the message failed */ if (!bitset(QBADADDR, q->q_flags)) continue; /* we have an address that failed -- find the parent */ for (qq = q; qq != NULL; qq = qq->q_alias) { char obuf[MAXNAME + 6]; extern char *aliaslookup(); /* we can only have owners for local addresses */ if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) continue; /* see if the owner list exists */ (void) strcpy(obuf, "owner-"); if (strncmp(qq->q_user, "owner-", 6) == 0) (void) strcat(obuf, "owner"); else (void) strcat(obuf, qq->q_user); if (aliaslookup(obuf) == NULL) continue;# ifdef DEBUG if (tTd(13, 4)) printf("Errors to %s\n", obuf);# endif DEBUG /* owner list exists -- add it to the error queue */ sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); ErrorMode = EM_MAIL; break; } /* if we did not find an owner, send to the sender */ if (qq == NULL && bitset(QBADADDR, q->q_flags)) sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); } if (mode == SM_FORK) finis();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -