diff options
Diffstat (limited to 'usr.sbin/sendmail/src/deliver.c')
-rw-r--r-- | usr.sbin/sendmail/src/deliver.c | 523 |
1 files changed, 403 insertions, 120 deletions
diff --git a/usr.sbin/sendmail/src/deliver.c b/usr.sbin/sendmail/src/deliver.c index 34c6c1a82f1b..f446f53b8a80 100644 --- a/usr.sbin/sendmail/src/deliver.c +++ b/usr.sbin/sendmail/src/deliver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)deliver.c 8.185.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)deliver.c 8.246 (Berkeley) 10/17/96"; #endif /* not lint */ #include "sendmail.h" @@ -69,7 +69,7 @@ extern char SmtpError[]; void sendall(e, mode) ENVELOPE *e; - char mode; + int mode; { register ADDRESS *q; char *owner; @@ -125,6 +125,8 @@ sendall(e, mode) */ CurEnv = e; + if (tTd(62, 1)) + checkfds(NULL); if (e->e_hopcount > MaxHopCount) { @@ -184,12 +186,21 @@ sendall(e, mode) q->q_owner = NULL; } + if (tTd(13, 25)) + { + printf("\nAfter first owner pass, sendq =\n"); + printaddr(e->e_sendqueue, TRUE); + } + owner = ""; otherowners = 1; while (owner != NULL && otherowners > 0) { + if (tTd(13, 28)) + printf("owner = \"%s\", otherowners = %d\n", + owner, otherowners); owner = NULL; - otherowners = 0; + otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0; for (q = e->e_sendqueue; q != NULL; q = q->q_next) { @@ -204,27 +215,49 @@ sendall(e, mode) printf(" ... QDONTSEND\n"); continue; } + if (tTd(13, 29) && !tTd(13, 30)) + { + printf("Checking "); + printaddr(q, FALSE); + } if (q->q_owner != NULL) { if (owner == NULL) + { + if (tTd(13, 40)) + printf(" ... First owner = \"%s\"\n", + q->q_owner); owner = q->q_owner; + } else if (owner != q->q_owner) { if (strcmp(owner, q->q_owner) == 0) { + if (tTd(13, 40)) + printf(" ... Same owner = \"%s\"\n", + owner); + /* make future comparisons cheap */ q->q_owner = owner; } else { + if (tTd(13, 40)) + printf(" ... Another owner \"%s\"\n", + q->q_owner); otherowners++; } owner = q->q_owner; } + else if (tTd(13, 40)) + printf(" ... Same owner = \"%s\"\n", + owner); } else { + if (tTd(13, 40)) + printf(" ... Null owner\n"); otherowners++; } @@ -273,8 +306,8 @@ sendall(e, mode) (void) queuename(ee, '\0'); if (tTd(13, 1)) - printf("sendall: split %s into %s\n", - e->e_id, ee->e_id); + printf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n", + e->e_id, ee->e_id, owner, otherowners); ee->e_header = copyheader(e->e_header); ee->e_sendqueue = copyqueue(e->e_sendqueue); @@ -299,7 +332,10 @@ sendall(e, mode) if (q->q_owner == owner) { q->q_flags |= QDONTSEND; - q->q_flags &= ~QQUEUEUP; + q->q_flags &= ~(QQUEUEUP|QBADADDR); + if (tTd(13, 6)) + printf("\t... stripping %s from original envelope\n", + q->q_paddr); } } for (q = ee->e_sendqueue; q != NULL; q = q->q_next) @@ -307,13 +343,19 @@ sendall(e, mode) if (q->q_owner != owner) { q->q_flags |= QDONTSEND; - q->q_flags &= ~QQUEUEUP; + q->q_flags &= ~(QQUEUEUP|QBADADDR); + if (tTd(13, 6)) + printf("\t... dropping %s from cloned envelope\n", + q->q_paddr); } else { /* clear DSN parameters */ - q->q_flags &= ~(QHASNOTIFY|QPINGONSUCCESS); - q->q_flags |= QPINGONFAILURE|QPINGONDELAY; + q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); + q->q_flags |= DefaultNotify & ~QPINGONSUCCESS; + if (tTd(13, 6)) + printf("\t... moving %s to cloned envelope\n", + q->q_paddr); } } @@ -368,6 +410,7 @@ sendall(e, mode) e->e_from.q_flags |= QDONTSEND; e->e_errormode = EM_MAIL; e->e_flags |= EF_NORECEIPT; + e->e_flags &= ~EF_FATALERRS; } /* if nothing to be delivered, just queue up everything */ @@ -382,7 +425,7 @@ sendall(e, mode) # ifdef QUEUE if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK || (mode != SM_VERIFY && SuperSafe)) && - !bitset(EF_INQUEUE, e->e_flags)) + (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) { /* be sure everything is instantiated in the queue */ queueup(e, mode == SM_QUEUE || mode == SM_DEFER); @@ -391,12 +434,31 @@ sendall(e, mode) } #endif /* QUEUE */ + if (tTd(62, 10)) + checkfds("after envelope splitting"); + /* ** If we belong in background, fork now. */ if (tTd(13, 20)) + { printf("sendall: final mode = %c\n", mode); + if (tTd(13, 21)) + { + printf("\n================ Final Send Queue(s) =====================\n"); + printf("\n *** Envelope %s, e_from=%s ***\n", + e->e_id, e->e_from.q_paddr); + printaddr(e->e_sendqueue, TRUE); + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + printf("\n *** Envelope %s, e_from=%s ***\n", + ee->e_id, ee->e_from.q_paddr); + printaddr(ee->e_sendqueue, TRUE); + } + printf("==========================================================\n\n"); + } + } switch (mode) { case SM_VERIFY: @@ -428,15 +490,26 @@ sendall(e, mode) /* now drop the envelope in the parent */ e->e_flags |= EF_INQUEUE; - dropenvelope(e); + dropenvelope(e, FALSE); - /* and reacquire in the child */ - (void) dowork(qid, TRUE, FALSE, e); + /* arrange to reacquire lock after fork */ + e->e_id = qid; } - return; + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + /* save id for future use */ + char *qid = ee->e_id; + + /* drop envelope in parent */ + ee->e_flags |= EF_INQUEUE; + dropenvelope(ee, FALSE); + + /* and save qid for reacquisition */ + ee->e_id = qid; + } -# else /* HASFLOCK */ +# endif /* !HASFLOCK */ pid = fork(); if (pid < 0) @@ -445,6 +518,7 @@ sendall(e, mode) } else if (pid > 0) { +# if HASFLOCK /* be sure we leave the temp files to our child */ /* can't call unlockqueue to avoid unlink of xfp */ if (e->e_lockfp != NULL) @@ -456,8 +530,11 @@ sendall(e, mode) if (e->e_dfp != NULL) (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id); e->e_dfp = NULL; - e->e_id = NULL; e->e_flags &= ~EF_HAS_DF; +# endif + + /* make sure the parent doesn't own the envelope */ + e->e_id = NULL; /* catch intermediate zombie */ (void) waitfor(pid); @@ -491,31 +568,33 @@ sendall(e, mode) mci_flush(FALSE, NULL); -# endif /* HASFLOCK */ - +# if HASFLOCK break; - } - - if (splitenv != NULL) - { - if (tTd(13, 2)) - { - printf("\nsendall: Split queue; remaining queue:\n"); - printaddr(e->e_sendqueue, TRUE); - } +# else - for (ee = splitenv; ee != NULL; ee = ee->e_sibling) - { - CurEnv = ee; - if (mode != SM_VERIFY) - openxscript(ee); - sendenvelope(ee, mode); - dropenvelope(ee); - } + /* + ** Now reacquire and run the various queue files. + */ - CurEnv = e; + for (ee = splitenv; ee != NULL; ee = e->e_sibling) + (void) dowork(ee->e_id, FALSE, FALSE, ee); + (void) dowork(e->e_id, FALSE, FALSE, e); + finis(); +# endif /* !HASFLOCK */ } + sendenvelope(e, mode); + dropenvelope(e, TRUE); + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + CurEnv = ee; + if (mode != SM_VERIFY) + openxscript(ee); + sendenvelope(ee, mode); + dropenvelope(ee, TRUE); + } + CurEnv = e; + Verbose = oldverbose; if (mode == SM_FORK) finis(); @@ -563,6 +642,8 @@ sendenvelope(e, mode) e->e_nsent = 0; e->e_flags |= EF_GLOBALERRS; + define(macid("{envid}", NULL), e->e_envid, e); + define(macid("{bodytype}", NULL), e->e_bodytype, e); didany = FALSE; /* now run through the queue */ @@ -593,6 +674,8 @@ sendenvelope(e, mode) } else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) { + extern int deliver __P((ENVELOPE *, ADDRESS *)); + # ifdef QUEUE /* ** Checkpoint the send list every few addresses @@ -704,6 +787,13 @@ dofork() ** The standard input is passed off to someone. */ +#ifndef NO_UID +# define NO_UID ((uid_t) -1) +#endif +#ifndef NO_GID +# define NO_GID ((gid_t) -1) +#endif + int deliver(e, firstto) register ENVELOPE *e; @@ -716,6 +806,7 @@ deliver(e, firstto) register char *p; register MAILER *m; /* mailer for this recipient */ ADDRESS *volatile ctladdr; + ADDRESS *volatile contextaddr = NULL; register MCI *volatile mci; register ADDRESS *to = firstto; volatile bool clever = FALSE; /* running user smtp to this mailer */ @@ -724,7 +815,9 @@ deliver(e, firstto) char *firstsig; /* signature of firstto */ int pid = -1; char *volatile curhost; + register volatile u_short port = 0; time_t xstart; + bool suidwarn; int mpvect[2]; int rpvect[2]; char *pv[MAXPV+1]; @@ -738,6 +831,8 @@ deliver(e, firstto) if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) return (0); + suidwarn = geteuid() == 0; + #if NAMED_BIND /* unless interactive, try twice, over a minute */ if (OpMode == MD_DAEMON || OpMode == MD_SMTP) @@ -888,7 +983,7 @@ deliver(e, firstto) /* compute effective uid/gid when sending */ if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) - ctladdr = getctladdr(to); + contextaddr = ctladdr = getctladdr(to); if (tTd(10, 2)) { @@ -921,7 +1016,15 @@ deliver(e, firstto) #if NAMED_BIND h_errno = 0; #endif - rcode = checkcompat(to, e); + + /* do config file checking of compatibility */ + rcode = rscheck("check_compat", + e->e_from.q_paddr, to->q_paddr, e); + if (rcode == EX_OK) + { + /* do in-code checking */ + rcode = checkcompat(to, e); + } if (rcode != EX_OK) { markfailure(e, to, NULL, rcode); @@ -956,9 +1059,6 @@ deliver(e, firstto) if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) continue; - /* save statistics.... */ - markstats(e, to); - /* ** See if this user name is "special". ** If the user name has a slash in it, assume that this @@ -975,9 +1075,9 @@ deliver(e, firstto) if (rcode == EX_OK) { to->q_flags |= QSENT; + markstats(e, to); if (bitnset(M_LOCALMAILER, m->m_flags) && - (e->e_receiptto != NULL || - bitset(QPINGONSUCCESS, to->q_flags))) + bitset(QPINGONSUCCESS, to->q_flags)) { to->q_flags |= QDELIVERED; to->q_status = "2.1.5"; @@ -1114,6 +1214,9 @@ deliver(e, firstto) goto give_up; } + if (tTd(62, 8)) + checkfds("before delivery"); + /* check for Local Person Communication -- not for mortals!!! */ if (strcmp(m->m_mailer, "[LPC]") == 0) { @@ -1129,7 +1232,6 @@ deliver(e, firstto) { #ifdef DAEMON register int i; - register volatile u_short port = 0; if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') { @@ -1172,11 +1274,12 @@ tryhost: { register char *p; static char hostbuf[MAXNAME + 1]; + extern int makeconnection __P((char *, u_short, MCI *, ENVELOPE *)); /* pull the next host from the signature */ p = strchr(curhost, ':'); if (p == NULL) - p = &curhost[strlen(curhost)]; + p = (char *) &curhost[strlen(curhost)]; if (p == curhost) { syserr("deliver: null host name in signature"); @@ -1209,12 +1312,21 @@ tryhost: if (mci->mci_exitstat != EX_OK) continue; + if (mci_lock_host(mci) != EX_OK) + { + mci->mci_exitstat = EX_TEMPFAIL; + continue; + } + /* try the connection */ setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); - message("Connecting to %s via %s...", - hostbuf, m->m_name); - i = makeconnection(hostbuf, port, mci, - bitnset(M_SECURE_PORT, m->m_flags)); + if (port == 0) + message("Connecting to %s via %s...", + hostbuf, m->m_name); + else + message("Connecting to %s port %d via %s...", + hostbuf, port, m->m_name); + i = makeconnection(hostbuf, port, mci, e); mci->mci_lastuse = curtime(); mci->mci_exitstat = i; mci->mci_errno = errno; @@ -1226,13 +1338,17 @@ tryhost: mci->mci_state = MCIS_OPENING; mci_cache(mci); if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d == CONNECT %s\n", + fprintf(TrafficLogFile, "%05d === CONNECT %s\n", getpid(), hostbuf); break; } - else if (tTd(11, 1)) - printf("openmailer: makeconnection => stat=%d, errno=%d\n", - i, errno); + else + { + if (tTd(11, 1)) + printf("openmailer: makeconnection => stat=%d, errno=%d\n", + i, errno); + mci_unlock_host(mci); + } /* enter status of this host */ setstat(i); @@ -1242,7 +1358,7 @@ tryhost: if (mci == NULL) { syserr("deliver: no host name"); - rcode = EX_OSERR; + rcode = EX_SOFTWARE; goto give_up; } mci->mci_pid = 0; @@ -1274,6 +1390,10 @@ tryhost: fprintf(TrafficLogFile, "\n"); } +#if XDEBUG + checkfd012("before creating mail pipe"); +#endif + /* create a pipe to shove the mail through */ if (pipe(mpvect) < 0) { @@ -1285,19 +1405,59 @@ tryhost: goto give_up; } - /* if this mailer speaks smtp, create a return pipe */ -#ifdef SMTP - if (clever && pipe(rpvect) < 0) +#if XDEBUG + /* make sure we didn't get one of the standard I/O files */ + if (mpvect[0] < 3 || mpvect[1] < 3) { - syserr("%s... openmailer(%s): pipe (from mailer)", - shortenstring(e->e_to, 203), m->m_name); - (void) close(mpvect[0]); - (void) close(mpvect[1]); + syserr("%s... openmailer(%s): bogus mpvect %d %d", + shortenstring(e->e_to, 203), m->m_name, + mpvect[0], mpvect[1]); + printopenfds(TRUE); if (tTd(11, 1)) printf("openmailer: NULL\n"); rcode = EX_OSERR; goto give_up; } + + /* make sure system call isn't dead meat */ + checkfdopen(mpvect[0], "mpvect[0]"); + checkfdopen(mpvect[1], "mpvect[1]"); + if (mpvect[0] == mpvect[1] || + (e->e_lockfp != NULL && + (mpvect[0] == fileno(e->e_lockfp) || + mpvect[1] == fileno(e->e_lockfp)))) + { + if (e->e_lockfp == NULL) + syserr("%s... openmailer(%s): overlapping mpvect %d %d", + shortenstring(e->e_to, 203), m->m_name, + mpvect[0], mpvect[1]); + else + syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d", + shortenstring(e->e_to, 203), m->m_name, + mpvect[0], mpvect[1], fileno(e->e_lockfp)); + } +#endif + + /* if this mailer speaks smtp, create a return pipe */ +#ifdef SMTP + if (clever) + { + if (pipe(rpvect) < 0) + { + syserr("%s... openmailer(%s): pipe (from mailer)", + shortenstring(e->e_to, 203), m->m_name); + (void) close(mpvect[0]); + (void) close(mpvect[1]); + if (tTd(11, 1)) + printf("openmailer: NULL\n"); + rcode = EX_OSERR; + goto give_up; + } +# if XDEBUG + checkfdopen(rpvect[0], "rpvect[0]"); + checkfdopen(rpvect[1], "rpvect[1]"); +# endif + } #endif /* @@ -1339,6 +1499,9 @@ tryhost: { int i; int saveerrno; + uid_t new_euid = NO_UID; + uid_t new_ruid = NO_UID; + gid_t new_gid = NO_GID; struct stat stb; extern int DtableSize; @@ -1353,58 +1516,96 @@ tryhost: if (m != FileMailer || stat(tochain->q_user, &stb) < 0) stb.st_mode = 0; +#if HASSETUSERCONTEXT + /* + ** Set user resources. + */ + + if (contextaddr != NULL) + { + struct passwd *pwd; + + if (contextaddr->q_ruser != NULL) + pwd = sm_getpwnam(contextaddr->q_ruser); + else + pwd = sm_getpwnam(contextaddr->q_user); + if (pwd != NULL) + (void) setusercontext(NULL, + pwd, pwd->m_uid, + LOGIN_SETRESOURCES|LOGIN_SETPRIORITY); + } +#endif + /* tweak niceness */ if (m->m_nice != 0) nice(m->m_nice); /* reset group id */ if (bitnset(M_SPECIFIC_UID, m->m_flags)) - (void) setgid(m->m_gid); + new_gid = m->m_gid; else if (bitset(S_ISGID, stb.st_mode)) - (void) setgid(stb.st_gid); + new_gid = stb.st_gid; else if (ctladdr != NULL && ctladdr->q_gid != 0) { if (!DontInitGroups) (void) initgroups(ctladdr->q_ruser != NULL ? ctladdr->q_ruser : ctladdr->q_user, ctladdr->q_gid); - (void) setgid(ctladdr->q_gid); + new_gid = ctladdr->q_gid; } else { if (!DontInitGroups) (void) initgroups(DefUser, DefGid); if (m->m_gid == 0) - (void) setgid(DefGid); + new_gid = DefGid; else - (void) setgid(m->m_gid); + new_gid = m->m_gid; } + if (new_gid != NO_GID && setgid(new_gid) < 0 && suidwarn) + syserr("openmailer: setgid(%ld) failed", + (long) new_gid); /* reset user id */ endpwent(); if (bitnset(M_SPECIFIC_UID, m->m_flags)) + new_euid = m->m_uid; + if (bitset(S_ISUID, stb.st_mode)) + new_ruid = stb.st_uid; + else if (ctladdr != NULL && ctladdr->q_uid != 0) + new_ruid = ctladdr->q_uid; + else { + if (m->m_uid == 0) + new_ruid = DefUid; + else + new_ruid = m->m_uid; + } + if (new_euid != NO_UID) + { + vendor_set_uid(new_euid); #if USESETEUID - (void) seteuid(m->m_uid); + if (seteuid(new_euid) < 0 && suidwarn) + syserr("openmailer: seteuid(%ld) failed", + (long) new_euid); #else # if HASSETREUID - (void) setreuid(-1, m->m_uid); + if (setreuid(new_ruid, new_euid) < 0 && suidwarn) + syserr("openmailer: setreuid(%ld, %ld) failed", + (long) new_ruid, (long) new_euid); # else - if (m->m_uid != geteuid()) - (void) setuid(m->m_uid); + if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) + syserr("openmailer: setuid(%ld) failed", + (long) new_euid); # endif #endif } - else if (bitset(S_ISUID, stb.st_mode)) - (void) setuid(stb.st_uid); - else if (ctladdr != NULL && ctladdr->q_uid != 0) - (void) setuid(ctladdr->q_uid); - else + else if (new_ruid != NO_UID) { - if (m->m_uid == 0) - (void) setuid(DefUid); - else - (void) setuid(m->m_uid); + vendor_set_uid(new_ruid); + if (setuid(new_ruid) < 0 && suidwarn) + syserr("openmailer: setuid(%ld) failed", + (long) new_ruid); } if (tTd(11, 2)) @@ -1559,7 +1760,11 @@ tryhost: mci->mci_flags |= MCIF_7BIT; #ifdef SMTP if (clever && mci->mci_state != MCIS_CLOSED) + { + extern void smtpinit __P((MAILER *, MCI *, ENVELOPE *)); + smtpinit(m, mci, e); + } #endif if (bitset(EF_HAS8BIT, e->e_flags) && @@ -1569,6 +1774,22 @@ tryhost: else mci->mci_flags &= ~MCIF_CVT8TO7; +#if MIME7TO8 + if (bitnset(M_MAKE8BIT, m->m_flags) && + !bitset(MCIF_7BIT, mci->mci_flags) && + (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && + (strcasecmp(p, "quoted-printable") == 0 || + strcasecmp(p, "base64") == 0) && + (p = hvalue("Content-Type", e->e_header)) != NULL) + { + /* may want to convert 7 -> 8 */ + /* XXX should really parse it here -- and use a class XXX */ + if (strncasecmp(p, "text/plain", 10) == 0 && + (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) + mci->mci_flags |= MCIF_CVT7TO8; + } +#endif + if (tTd(11, 1)) { printf("openmailer: "); @@ -1586,8 +1807,10 @@ tryhost: if (rcode == EX_OK) { /* shouldn't happen */ - syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", - rcode, mci->mci_state, firstsig); + syserr("554 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", + (long) mci, rcode, errno, mci->mci_state, + firstsig); + mci_dump_all(TRUE); rcode = EX_SOFTWARE; } #ifdef DAEMON @@ -1614,6 +1837,10 @@ tryhost: else #ifdef SMTP { + extern int smtpmailfrom __P((MAILER *, MCI *, ENVELOPE *)); + extern int smtprcpt __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *)); + extern int smtpdata __P((MAILER *, MCI *, ENVELOPE *)); + /* ** Send the MAIL FROM: protocol */ @@ -1661,7 +1888,7 @@ tryhost: if (!bitset(MCIF_CACHED, mci->mci_flags)) smtpquit(m, mci, e); } - if (rcode != EX_OK && curhost != NULL && *curhost != '\0') + if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0') { /* try next MX site */ goto tryhost; @@ -1679,13 +1906,8 @@ tryhost: _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? */ - } + if (tTd(62, 1)) + checkfds("after delivery"); /* ** Do final status disposal. @@ -1697,6 +1919,10 @@ tryhost: give_up: if (tobuf[0] != '\0') giveresponse(rcode, m, mci, ctladdr, xstart, e); + if (rcode == EX_OK) + markstats(e, tochain); + mci_store_persistent(mci); + for (to = tochain; to != NULL; to = to->q_tchain) { /* see if address already marked */ @@ -1715,8 +1941,7 @@ tryhost: to->q_statdate = curtime(); e->e_nsent++; if (bitnset(M_LOCALMAILER, m->m_flags) && - (e->e_receiptto != NULL || - bitset(QPINGONSUCCESS, to->q_flags))) + bitset(QPINGONSUCCESS, to->q_flags)) { to->q_flags |= QDELIVERED; to->q_status = "2.1.5"; @@ -1798,11 +2023,17 @@ markfailure(e, q, mci, rcode) } /* find most specific error code possible */ - if (q->q_status == NULL && mci != NULL) + if (mci != NULL && mci->mci_status != NULL) + { q->q_status = mci->mci_status; - if (q->q_status == NULL) + q->q_rstatus = mci->mci_rstatus; + } + else if (e->e_status != NULL) + { q->q_status = e->e_status; - if (q->q_status == NULL) + q->q_rstatus = NULL; + } + else { switch (rcode) { @@ -1903,6 +2134,10 @@ endmailer(mci, e, pv) if (mci->mci_pid == 0) return (EX_OK); +#ifdef FFR_TIMEOUT_WAIT + put a timeout around the wait +#endif + /* wait for the mailer process to die and collect status */ st = waitfor(mci->mci_pid); if (st == -1) @@ -2219,7 +2454,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) bp += strlen(bp); (void) strcpy(bp, shortenstring(stat, (STATLEN))); - + /* id, to: max 13 + TOBUFSIZE bytes */ l = SYSLOG_BUFSIZE - 100 - strlen(buf); p = e->e_to; @@ -2239,7 +2474,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) l = SYSLOG_BUFSIZE - 85; p = e->e_to; - while (strlen(p) >= l) + while (strlen(p) >= (SIZE_T) l) { register char *q = strchr(p + l, ','); @@ -2342,6 +2577,7 @@ putfromline(mci, e) { char *template = UnixFromLine; char buf[MAXLINE]; + char xbuf[MAXLINE]; if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) return; @@ -2349,14 +2585,29 @@ putfromline(mci, e) if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) { char *bang; - char xbuf[MAXLINE]; expand("\201g", buf, sizeof buf, e); bang = strchr(buf, '!'); if (bang == NULL) { - errno = 0; - syserr("554 No ! in UUCP From address! (%s given)", buf); + char *at; + char hname[MAXNAME]; + + /* + ** If we can construct a UUCP path, do so + */ + + at = strrchr(buf, '@'); + if (at == NULL) + { + expand( "\201k", hname, sizeof hname, e); + at = hname; + } + else + *at++ = '\0'; + (void) snprintf(xbuf, sizeof xbuf, + "From %.800s \201d remote from %.100s\n", + buf, at); } else { @@ -2461,6 +2712,12 @@ putbody(mci, e, separator) boundaries[0] = NULL; mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); } +# if MIME7TO8 + else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) + { + mime7to8(mci, e->e_header, e); + } +# endif else #endif { @@ -2593,6 +2850,7 @@ putbody(mci, e, separator) /* had a naked carriage return */ *pbp++ = c; c = '\r'; + ostate = OS_INLINE; goto putch; case OS_INLINE: @@ -2631,8 +2889,10 @@ putch: { *bp = '\0'; fputs(buf, mci->mci_out); - fputs(mci->mci_mailer->m_eol, mci->mci_out); + pos += bp - buf; } + if (pos > 0) + fputs(mci->mci_mailer->m_eol, mci->mci_out); } if (ferror(e->e_dfp)) @@ -2693,6 +2953,7 @@ mailfile(filename, ctladdr, sfflags, e) register FILE *f; register int pid = -1; int mode; + bool suidwarn = geteuid() == 0; if (tTd(11, 1)) { @@ -2704,6 +2965,14 @@ mailfile(filename, ctladdr, sfflags, e) fflush(e->e_xfp); /* + ** Special case /dev/null. This allows us to restrict file + ** delivery to regular files only. + */ + + if (strcmp(filename, "/dev/null") == 0) + return EX_OK; + + /* ** Fork so we can change permissions here. ** Note that we MUST use fork, not vfork, because of ** the complications of calling subroutines, etc. @@ -2717,7 +2986,6 @@ mailfile(filename, ctladdr, sfflags, e) { /* child -- actually write to file */ struct stat stb; - struct stat fsb; MCI mcibuf; int oflags = O_WRONLY|O_APPEND; @@ -2816,12 +3084,9 @@ mailfile(filename, ctladdr, sfflags, e) RealGid = DefGid; } - /* now set the group and user ids */ - endpwent(); + /* set group id list (needs /etc/group access) */ if (RealUserName != NULL && !DontInitGroups) (void) initgroups(RealUserName, RealGid); - (void) setgid(RealGid); - (void) setuid(RealUid); /* if you have a safe environment, go into it */ if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') @@ -2841,6 +3106,14 @@ mailfile(filename, ctladdr, sfflags, e) if (chdir("/") < 0) syserr("mailfile: cannot chdir(/)"); + /* now reset the group and user ids */ + endpwent(); + if (setgid(RealGid) < 0 && suidwarn) + syserr("mailfile: setgid(%ld) failed", (long) RealGid); + vendor_set_uid(RealUid); + if (setuid(RealUid) < 0 && suidwarn) + syserr("mailfile: setuid(%ld) failed", (long) RealUid); + sfflags |= SFF_NOPATHCHECK; sfflags &= ~SFF_OPENASROOT; f = safefopen(filename, oflags, FileMode, sfflags); @@ -2897,6 +3170,7 @@ mailfile(filename, ctladdr, sfflags, e) } /*NOTREACHED*/ } + return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ } /* ** HOSTSIGNATURE -- return the "signature" for a host. @@ -2929,7 +3203,6 @@ hostsignature(m, host, e) int len; #if NAMED_BIND int nmx; - auto int rcode; char *hp; char *endp; int oldoptions = _res.options; @@ -2969,23 +3242,33 @@ hostsignature(m, host, e) if (endp != NULL) *endp = '\0'; - nmx = getmxrr(hp, mxhosts, TRUE, &rcode); - - if (nmx <= 0) + if (bitnset(M_NOMX, m->m_flags)) { - register MCI *mci; - - /* update the connection info for this host */ - mci = mci_get(hp, m); - mci->mci_lastuse = curtime(); - mci->mci_exitstat = rcode; - mci->mci_errno = errno; - mci->mci_herrno = h_errno; - - /* and return the original host name as the signature */ + /* skip MX lookups */ nmx = 1; mxhosts[0] = hp; } + else + { + auto int rcode; + + 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_lastuse = curtime(); + mci->mci_exitstat = rcode; + mci->mci_errno = errno; + mci->mci_herrno = h_errno; + + /* use the original host name as signature */ + nmx = 1; + mxhosts[0] = hp; + } + } len = 0; for (i = 0; i < nmx; i++) |