diff options
Diffstat (limited to 'src/deliver.c')
-rw-r--r-- | src/deliver.c | 526 |
1 files changed, 399 insertions, 127 deletions
diff --git a/src/deliver.c b/src/deliver.c index 9575515..ed03328 100644 --- a/src/deliver.c +++ b/src/deliver.c @@ -1,47 +1,24 @@ /* - * Copyright (c) 1983, 1995-1997 Eric P. Allman + * Copyright (c) 1998 Sendmail, Inc. All rights reserved. + * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. */ #ifndef lint -static char sccsid[] = "@(#)deliver.c 8.296 (Berkeley) 10/22/97"; +static char sccsid[] = "@(#)deliver.c 8.367 (Berkeley) 1/18/1999"; #endif /* not lint */ #include "sendmail.h" #include <errno.h> +#include <grp.h> #if NAMED_BIND #include <resolv.h> - -extern int h_errno; #endif #if HASSETUSERCONTEXT @@ -83,7 +60,23 @@ sendall(e, mode) int oldverbose = Verbose; bool somedeliveries = FALSE, expensive = FALSE; pid_t pid; - extern void sendenvelope(); + void sendenvelope __P((ENVELOPE *, int)); + + /* + ** If this message is to be discarded, don't bother sending + ** the message at all. + */ + + if (bitset(EF_DISCARD, e->e_flags)) + { + if (tTd(13, 1)) + printf("sendall: discarding id %s\n", e->e_id); + e->e_flags |= EF_CLRQUEUE; + if (LogLevel > 4) + sm_syslog(LOG_INFO, e->e_id, "discarded"); + markstats(e, NULL, TRUE); + return; + } /* ** If we have had global, fatal errors, don't bother sending @@ -110,7 +103,7 @@ sendall(e, mode) if (tTd(13, 1)) { - extern void printenvflags(); + extern void printenvflags __P((ENVELOPE *)); printf("\n===== SENDALL: mode %c, id %s, e_from ", mode, e->e_id); @@ -297,8 +290,8 @@ sendall(e, mode) if (owner != NULL && otherowners > 0) { - extern HDR *copyheader(); - extern ADDRESS *copyqueue(); + extern HDR *copyheader __P((HDR *)); + extern ADDRESS *copyqueue __P((ADDRESS *)); extern void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int)); /* @@ -367,7 +360,7 @@ sendall(e, mode) if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) dup_queue_file(e, ee, 'd'); openxscript(ee); - if (LogLevel > 4) + if (mode != SM_VERIFY && LogLevel > 4) sm_syslog(LOG_INFO, ee->e_id, "clone %s, owner=%s", e->e_id, owner); @@ -453,10 +446,12 @@ sendall(e, mode) case SM_QUEUE: case SM_DEFER: +# if HASFLOCK queueonly: +# endif if (e->e_nrcpts > 0) e->e_flags |= EF_INQUEUE; - dropenvelope(e, FALSE); + dropenvelope(e, splitenv != NULL); for (ee = splitenv; ee != NULL; ee = ee->e_sibling) { if (ee->e_nrcpts > 0) @@ -473,36 +468,64 @@ sendall(e, mode) /* ** Since fcntl locking has the interesting semantic that ** the lock is owned by a process, not by an open file - ** descriptor, we have to unlock this envelope, and + ** descriptor, we have to flush this to the queue, and ** then restart from scratch in the child. */ - unlockqueue(e); + { + /* save id for future use */ + char *qid = e->e_id; + + /* now drop the envelope in the parent */ + e->e_flags |= EF_INQUEUE; + dropenvelope(e, splitenv != NULL); + + /* arrange to reacquire lock after fork */ + e->e_id = qid; + } + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) - unlockqueue(ee); + { + /* 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; + } # endif /* !HASFLOCK */ pid = fork(); if (pid < 0) { +# if HASFLOCK goto queueonly; +# else + e->e_id = NULL; + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + ee->e_id = NULL; + return; +# endif /* HASFLOCK */ } 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) - (void) xfclose(e->e_lockfp, "sendenvelope lockfp", e->e_id); - e->e_lockfp = NULL; - /* close any random open files in the envelope */ closexscript(e); if (e->e_dfp != NULL) (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id); e->e_dfp = NULL; e->e_flags &= ~EF_HAS_DF; + + /* can't call unlockqueue to avoid unlink of xfp */ + if (e->e_lockfp != NULL) + (void) xfclose(e->e_lockfp, "sendenvelope lockfp", e->e_id); + e->e_lockfp = NULL; # endif /* make sure the parent doesn't own the envelope */ @@ -524,8 +547,12 @@ sendall(e, mode) /* prevent parent from waiting if there was an error */ if (pid < 0) { +# if HASFLOCK e->e_flags |= EF_INQUEUE; - finis(); +# else + e->e_id = NULL; +# endif /* HASFLOCK */ + finis(TRUE, ExitStat); } /* be sure to give error messages in child */ @@ -543,6 +570,15 @@ sendall(e, mode) mci_flush(FALSE, NULL); + /* + ** Since the delivery may happen in a child and the parent + ** does not wait, the parent may close the maps thereby + ** removing any shared memory used by the map. Therefore, + ** open a copy of the maps for the delivery process. + */ + + initmaps(FALSE, e); + # if HASFLOCK break; # else @@ -551,10 +587,15 @@ sendall(e, mode) ** Now reacquire and run the various queue files. */ - for (ee = splitenv; ee != NULL; ee = e->e_sibling) + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + ENVELOPE *sibling = ee->e_sibling; + (void) dowork(ee->e_id, FALSE, FALSE, ee); + ee->e_sibling = sibling; + } (void) dowork(e->e_id, FALSE, FALSE, e); - finis(); + finis(TRUE, ExitStat); # endif /* !HASFLOCK */ } @@ -572,13 +613,13 @@ sendall(e, mode) Verbose = oldverbose; if (mode == SM_FORK) - finis(); + finis(TRUE, ExitStat); } void sendenvelope(e, mode) register ENVELOPE *e; - char mode; + int mode; { register ADDRESS *q; bool didany; @@ -830,10 +871,11 @@ deliver(e, firstto) volatile bool clever = FALSE; /* running user smtp to this mailer */ ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */ int rcode; /* response code */ + int lmtp_rcode = EX_OK; char *firstsig; /* signature of firstto */ pid_t pid = -1; char *volatile curhost; - register volatile u_short port = 0; + register u_short port = 0; time_t xstart; bool suidwarn; bool anyok; /* at least one address was OK */ @@ -844,7 +886,7 @@ deliver(e, firstto) char tobuf[TOBUFSIZE]; /* text line of to people */ char buf[MAXNAME + 1]; char rpathbuf[MAXNAME + 1]; /* translated return path */ - extern int checkcompat(); + extern int checkcompat __P((ADDRESS *, ENVELOPE *)); extern void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int)); errno = 0; @@ -878,6 +920,18 @@ deliver(e, firstto) printopenfds(FALSE); /* + ** Clear $&{client_*} macros if this is a bounce message to + ** prevent rejection by check_compat ruleset. + */ + + if (bitset(EF_RESPONSE, e->e_flags)) + { + define(macid("{client_name}", NULL), "", e); + define(macid("{client_addr}", NULL), "", e); + define(macid("{client_port}", NULL), "", e); + } + + /* ** Do initial argv setup. ** Insert the mailer name. Notice that $x expansion is ** NOT done on the mailer name. Then, if the mailer has @@ -897,7 +951,7 @@ deliver(e, firstto) p = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e); if (strlen(p) >= (SIZE_T) sizeof rpathbuf) { - p = shortenstring(p, 203); + p = shortenstring(p, MAXSHORTSTR); syserr("remotename: huge return %s", p); } snprintf(rpathbuf, sizeof rpathbuf, "%s", p); @@ -1028,7 +1082,10 @@ deliver(e, firstto) if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) { e->e_flags |= EF_NO_BODY_RETN; - to->q_status = "5.2.3"; + if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags)) + to->q_status = "5.2.3"; + else + to->q_status = "5.3.4"; usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); markfailure(e, to, NULL, EX_UNAVAILABLE); giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e); @@ -1043,8 +1100,9 @@ deliver(e, firstto) e->e_from.q_paddr, to->q_paddr, e); if (rcode == EX_OK) { - /* do in-code checking */ - rcode = checkcompat(to, e); + /* do in-code checking if not discarding */ + if (!bitset(EF_DISCARD, e->e_flags)) + rcode = checkcompat(to, e); } if (rcode != EX_OK) { @@ -1052,6 +1110,22 @@ deliver(e, firstto) giveresponse(rcode, m, NULL, ctladdr, xstart, e); continue; } + if (bitset(EF_DISCARD, e->e_flags)) + { + if (tTd(10, 5)) + { + printf("deliver: discarding recipient "); + printaddr(to, FALSE); + } + + /* + ** Remove discard bit to prevent discard of + ** future recipients + */ + e->e_flags &= ~EF_DISCARD; + + continue; + } /* ** Strip quote bits from names if the mailer is dumb @@ -1090,13 +1164,26 @@ deliver(e, firstto) if (strcmp(m->m_mailer, "[FILE]") == 0) { - rcode = mailfile(user, ctladdr, SFF_CREAT, e); + define('u', user, e); /* to user */ + p = to->q_home; + if (p == NULL && ctladdr != NULL) + p = ctladdr->q_home; + define('z', p, e); /* user's home */ + expand(m->m_argv[1], buf, sizeof buf, e); + if (strlen(buf) > 0) + rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e); + else + { + syserr("empty filename specification for mailer %s", + m->m_name); + rcode = EX_CONFIG; + } giveresponse(rcode, m, NULL, ctladdr, xstart, e); + markfailure(e, to, NULL, rcode); e->e_nsent++; if (rcode == EX_OK) { to->q_flags |= QSENT; - markstats(e, to); if (bitnset(M_LOCALMAILER, m->m_flags) && bitset(QPINGONSUCCESS, to->q_flags)) { @@ -1107,6 +1194,7 @@ deliver(e, firstto) } } to->q_statdate = curtime(); + markstats(e, to, FALSE); continue; } @@ -1216,7 +1304,7 @@ deliver(e, firstto) /* make absolutely certain 0, 1, and 2 are in use */ snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)", - shortenstring(e->e_to, 203), m->m_name); + shortenstring(e->e_to, MAXSHORTSTR), m->m_name); checkfd012(wbuf); } #endif @@ -1293,7 +1381,6 @@ deliver(e, firstto) tryhost: while (*curhost != '\0') { - register char *p; static char hostbuf[MAXNAME + 1]; extern int makeconnection __P((char *, u_short, MCI *, ENVELOPE *)); @@ -1348,7 +1435,7 @@ tryhost: } /* try the connection */ - setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); + sm_setproctitle(TRUE, "%s %s: %s", e->e_id, hostbuf, "user open"); if (port == 0) message("Connecting to %s via %s...", hostbuf, m->m_name); @@ -1406,6 +1493,24 @@ tryhost: { /* flush any expired connections */ (void) mci_scan(NULL); + mci = NULL; + +#if SMTP + if (bitnset(M_LMTP, m->m_flags)) + { + /* try to get a cached connection */ + mci = mci_get(m->m_name, m); + if (mci->mci_host == NULL) + mci->mci_host = m->m_name; + CurHostName = mci->mci_host; + if (mci->mci_state != MCIS_CLOSED) + { + message("Using cached LMTP connection for %s...", + m->m_name); + goto do_transfer; + } + } +#endif /* announce the connection to verbose listeners */ if (host == NULL || host[0] == '\0') @@ -1430,7 +1535,7 @@ tryhost: if (pipe(mpvect) < 0) { syserr("%s... openmailer(%s): pipe (to mailer)", - shortenstring(e->e_to, 203), m->m_name); + shortenstring(e->e_to, MAXSHORTSTR), m->m_name); if (tTd(11, 1)) printf("openmailer: NULL\n"); rcode = EX_OSERR; @@ -1442,7 +1547,7 @@ tryhost: if (mpvect[0] < 3 || mpvect[1] < 3) { syserr("%s... openmailer(%s): bogus mpvect %d %d", - shortenstring(e->e_to, 203), m->m_name, + shortenstring(e->e_to, MAXSHORTSTR), m->m_name, mpvect[0], mpvect[1]); printopenfds(TRUE); if (tTd(11, 1)) @@ -1461,12 +1566,13 @@ tryhost: { 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]); + shortenstring(e->e_to, MAXSHORTSTR), + 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)); + shortenstring(e->e_to, MAXSHORTSTR), + m->m_name, mpvect[0], mpvect[1], + fileno(e->e_lockfp)); } #endif @@ -1477,7 +1583,8 @@ tryhost: if (pipe(rpvect) < 0) { syserr("%s... openmailer(%s): pipe (from mailer)", - shortenstring(e->e_to, 203), m->m_name); + shortenstring(e->e_to, MAXSHORTSTR), + m->m_name); (void) close(mpvect[0]); (void) close(mpvect[1]); if (tTd(11, 1)) @@ -1503,16 +1610,14 @@ tryhost: if (e->e_xfp != NULL) (void) fflush(e->e_xfp); /* for debugging */ (void) fflush(stdout); -# ifdef SIGCHLD (void) setsignal(SIGCHLD, SIG_DFL); -# endif /* SIGCHLD */ DOFORK(FORK); /* pid is set by DOFORK */ if (pid < 0) { /* failure */ syserr("%s... openmailer(%s): cannot fork", - shortenstring(e->e_to, 203), m->m_name); + shortenstring(e->e_to, MAXSHORTSTR), m->m_name); (void) close(mpvect[0]); (void) close(mpvect[1]); #if SMTP @@ -1580,15 +1685,42 @@ tryhost: 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); + { + char *u = ctladdr->q_ruser; + + if (u == NULL) + u = ctladdr->q_user; + + if (initgroups(u, ctladdr->q_gid) == -1 && suidwarn) + syserr("openmailer: initgroups(%s, %d) failed", + u, ctladdr->q_gid); + } + else + { + GIDSET_T gidset[1]; + + gidset[0] = ctladdr->q_gid; + if (setgroups(1, gidset) == -1 && suidwarn) + syserr("openmailer: setgroups() failed"); + } new_gid = ctladdr->q_gid; } else { if (!DontInitGroups) - (void) initgroups(DefUser, DefGid); + { + if (initgroups(DefUser, DefGid) == -1 && suidwarn) + syserr("openmailer: initgroups(%s, %d) failed", + DefUser, DefGid); + } + else + { + GIDSET_T gidset[1]; + + gidset[0] = DefGid; + if (setgroups(1, gidset) == -1 && suidwarn) + syserr("openmailer: setgroups() failed"); + } if (m->m_gid == 0) new_gid = DefGid; else @@ -1602,13 +1734,13 @@ tryhost: endpwent(); if (bitnset(M_SPECIFIC_UID, m->m_flags)) new_euid = m->m_uid; - if (bitset(S_ISUID, stb.st_mode)) + else 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 = m->m_uid; - else if (!bitnset(M_SPECIFIC_UID, m->m_flags)) + else new_ruid = DefUid; if (new_euid != NO_UID) { @@ -1644,7 +1776,7 @@ tryhost: /* move into some "safe" directory */ if (m->m_execdir != NULL) { - char *p, *q; + char *q; char buf[MAXLINE + 1]; for (p = m->m_execdir; p != NULL; p = q) @@ -1671,20 +1803,19 @@ tryhost: if (dup2(rpvect[1], STDOUT_FILENO) < 0) { syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", - shortenstring(e->e_to, 203), + shortenstring(e->e_to, MAXSHORTSTR), m->m_name, rpvect[1]); _exit(EX_OSERR); } (void) close(rpvect[1]); } - else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || - HoldErrs || DisConnected) + else { /* put mailer output in transcript */ if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) { syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", - shortenstring(e->e_to, 203), + shortenstring(e->e_to, MAXSHORTSTR), m->m_name, fileno(e->e_xfp)); _exit(EX_OSERR); } @@ -1693,7 +1824,8 @@ tryhost: if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) { syserr("%s... openmailer(%s): cannot dup stdout for stderr", - shortenstring(e->e_to, 203), m->m_name); + shortenstring(e->e_to, MAXSHORTSTR), + m->m_name); _exit(EX_OSERR); } @@ -1702,7 +1834,7 @@ tryhost: if (dup2(mpvect[0], STDIN_FILENO) < 0) { syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", - shortenstring(e->e_to, 203), + shortenstring(e->e_to, MAXSHORTSTR), m->m_name, mpvect[0]); _exit(EX_OSERR); } @@ -1734,10 +1866,21 @@ tryhost: ** Set up return value. */ - mci = (MCI *) xalloc(sizeof *mci); - bzero((char *) mci, sizeof *mci); + if (mci == NULL) + { + mci = (MCI *) xalloc(sizeof *mci); + bzero((char *) mci, sizeof *mci); + } mci->mci_mailer = m; - mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; + if (clever) + { + mci->mci_state = MCIS_OPENING; + mci_cache(mci); + } + else + { + mci->mci_state = MCIS_OPEN; + } mci->mci_pid = pid; (void) close(mpvect[0]); mci->mci_out = fdopen(mpvect[1], "w"); @@ -1796,6 +1939,7 @@ tryhost: } #endif +do_transfer: /* clear out per-message flags from connection structure */ mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); @@ -1857,8 +2001,9 @@ tryhost: ** Format and send message. */ + mci->mci_contentlen = 0; putfromline(mci, e); - (*e->e_puthdr)(mci, e->e_header, e); + (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); (*e->e_putbody)(mci, e, NULL); /* get the exit status */ @@ -1870,7 +2015,6 @@ tryhost: extern int smtpmailfrom __P((MAILER *, MCI *, ENVELOPE *)); extern int smtprcpt __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *)); extern int smtpdata __P((MAILER *, MCI *, ENVELOPE *)); - extern int smtpgetstat __P((MAILER *, MCI *, ENVELOPE *)); /* ** Send the MAIL FROM: protocol @@ -1952,14 +2096,13 @@ tryhost: give_up: #if SMTP -# if _FFR_LMTP if (bitnset(M_LMTP, m->m_flags)) { + lmtp_rcode = rcode; tobuf[0] = '\0'; anyok = FALSE; } else -# endif #endif anyok = rcode == EX_OK; @@ -1970,14 +2113,16 @@ tryhost: continue; #if SMTP -# if _FFR_LMTP /* if running LMTP, get the status for each address */ if (bitnset(M_LMTP, m->m_flags)) { - rcode = smtpgetstat(m, mci, e); + extern int smtpgetstat __P((MAILER *, MCI *, ENVELOPE *)); + + if (lmtp_rcode == EX_OK) + rcode = smtpgetstat(m, mci, e); if (rcode == EX_OK) { - if (strlen(to->q_paddr) + strlen(tobuf) + 2 >= sizeof tobuf) + if (strlen(to->q_paddr) + strlen(tobuf) + 2 > sizeof tobuf) { syserr("LMTP tobuf overflow"); } @@ -1998,7 +2143,6 @@ tryhost: } } else -# endif #endif { /* mark bad addresses */ @@ -2034,7 +2178,6 @@ tryhost: } #if SMTP -# if _FFR_LMTP if (bitnset(M_LMTP, m->m_flags)) { /* @@ -2049,13 +2192,12 @@ tryhost: if (mci != NULL && mci->mci_state == MCIS_ACTIVE) mci->mci_state = MCIS_OPEN; } -# endif #endif if (tobuf[0] != '\0') giveresponse(rcode, m, mci, ctladdr, xstart, e); if (anyok) - markstats(e, tochain); + markstats(e, tochain, FALSE); mci_store_persistent(mci); #if SMTP @@ -2076,7 +2218,7 @@ tryhost: /* make absolutely certain 0, 1, and 2 are in use */ snprintf(wbuf, sizeof wbuf, "%s... end of deliver(%s)", e->e_to == NULL ? "NO-TO-LIST" - : shortenstring(e->e_to, 203), + : shortenstring(e->e_to, MAXSHORTSTR), m->m_name); checkfd012(wbuf); } @@ -2134,7 +2276,10 @@ markfailure(e, q, mci, rcode) if (mci != NULL && mci->mci_status != NULL) { q->q_status = mci->mci_status; - q->q_rstatus = mci->mci_rstatus; + if (mci->mci_rstatus != NULL) + q->q_rstatus = newstr(mci->mci_rstatus); + else + q->q_rstatus = NULL; } else if (e->e_status != NULL) { @@ -2337,7 +2482,7 @@ giveresponse(stat, m, mci, ctladdr, xstart, e) statmsg = buf; } } - else if (i < 0 || i > N_SysEx) + else if (i < 0 || i >= N_SysEx) { (void) snprintf(buf, sizeof buf, "554 unknown mailer error %d", stat); @@ -2383,7 +2528,7 @@ giveresponse(stat, m, mci, ctladdr, xstart, e) else { statmsg = SysExMsg[i]; - if (*statmsg++ == ':') + if (*statmsg++ == ':' && errno != 0) { (void) snprintf(buf, sizeof buf, "%s: %s", statmsg, errstring(errno)); @@ -2534,8 +2679,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) } else if (strcmp(stat, "queued") != 0) { - char *p = macvalue('h', e); - + p = macvalue('h', e); if (p != NULL && p[0] != '\0') { snprintf(bp, SPACELEFT(buf, bp), ", relay=%s", @@ -2652,8 +2796,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) } else if (strcmp(stat, "queued") != 0) { - char *p = macvalue('h', e); - + p = macvalue('h', e); if (p != NULL && p[0] != '\0') snprintf(buf, sizeof buf, "relay=%.100s", p); } @@ -2696,6 +2839,8 @@ putfromline(mci, e) if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) return; + mci->mci_flags |= MCIF_INHEADER; + if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) { char *bang; @@ -2708,7 +2853,7 @@ putfromline(mci, e) char hname[MAXNAME]; /* - ** If we can construct a UUCP path, do so + ** If we can construct a UUCP path, do so */ at = strrchr(buf, '@'); @@ -2763,6 +2908,7 @@ putbody(mci, e, separator) char *separator; { char buf[MAXLINE]; + char *boundaries[MAXMIMENESTING + 1]; /* ** Output the body of the message @@ -2804,8 +2950,6 @@ putbody(mci, e, separator) #if MIME8TO7 if (bitset(MCIF_CVT8TO7, mci->mci_flags)) { - char *boundaries[MAXMIMENESTING + 1]; - /* ** Do 8 to 7 bit MIME conversion. */ @@ -2824,6 +2968,7 @@ putbody(mci, e, separator) /* now do the hard work */ boundaries[0] = NULL; + mci->mci_flags |= MCIF_INHEADER; mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); } # if MIME7TO8 @@ -2832,6 +2977,13 @@ putbody(mci, e, separator) mime7to8(mci, e->e_header, e); } # endif + else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0) + { + /* Use mime8to7 to check multipart for MIME header overflows */ + boundaries[0] = NULL; + mci->mci_flags |= MCIF_INHEADER; + mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER|M87F_NO8TO7); + } else #endif { @@ -2843,9 +2995,9 @@ putbody(mci, e, separator) int padc; char *buflim; int pos = 0; + size_t eol_len; char peekbuf[10]; - /* we can pass it through unmodified */ if (bitset(MCIF_INHEADER, mci->mci_flags)) { putline("", mci); @@ -2857,6 +3009,7 @@ putbody(mci, e, separator) if (mci->mci_mailer->m_linelimit > 0 && mci->mci_mailer->m_linelimit < sizeof buf - 1) buflim = &buf[mci->mci_mailer->m_linelimit - 1]; + eol_len = strlen(mci->mci_mailer->m_eol); /* copy temp file to output with mapping */ ostate = OS_HEAD; @@ -2925,14 +3078,19 @@ putbody(mci, e, separator) if (padc != EOF) { putc(padc, mci->mci_out); + mci->mci_contentlen++; pos++; } for (xp = buf; xp < bp; xp++) + { putc(*xp, mci->mci_out); + mci->mci_contentlen++; + } if (c == '\n') { fputs(mci->mci_mailer->m_eol, mci->mci_out); + mci->mci_contentlen += eol_len; pos = 0; } else @@ -2957,6 +3115,7 @@ putbody(mci, e, separator) { /* got CRLF */ fputs(mci->mci_mailer->m_eol, mci->mci_out); + mci->mci_contentlen += eol_len; if (TrafficLogFile != NULL) { fputs(mci->mci_mailer->m_eol, @@ -2989,7 +3148,9 @@ putch: c != '\n') { putc('!', mci->mci_out); + mci->mci_contentlen++; fputs(mci->mci_mailer->m_eol, mci->mci_out); + mci->mci_contentlen += eol_len; if (TrafficLogFile != NULL) { fprintf(TrafficLogFile, "!%s", @@ -3005,6 +3166,7 @@ putch: fputs(mci->mci_mailer->m_eol, TrafficLogFile); fputs(mci->mci_mailer->m_eol, mci->mci_out); + mci->mci_contentlen += eol_len; pos = 0; ostate = OS_HEAD; } @@ -3013,6 +3175,7 @@ putch: if (TrafficLogFile != NULL) putc(c, TrafficLogFile); putc(c, mci->mci_out); + mci->mci_contentlen++; pos++; ostate = OS_INLINE; } @@ -3029,7 +3192,10 @@ putch: putc(*xp, TrafficLogFile); } for (xp = buf; xp < bp; xp++) + { putc(*xp, mci->mci_out); + mci->mci_contentlen++; + } pos += bp - buf; } if (pos > 0) @@ -3037,6 +3203,7 @@ putch: if (TrafficLogFile != NULL) fputs(mci->mci_mailer->m_eol, TrafficLogFile); fputs(mci->mci_mailer->m_eol, mci->mci_out); + mci->mci_contentlen += eol_len; } } @@ -3076,6 +3243,8 @@ endofmessage: ** ** Parameters: ** filename -- the name of the file to send to. +** mailer -- mailer definition for recipient -- if NULL, +** use FileMailer. ** ctladdr -- the controlling address header -- includes ** the userid/groupid to be when sending. ** sfflags -- flags for opening. @@ -3089,11 +3258,12 @@ endofmessage: */ static jmp_buf CtxMailfileTimeout; -static void mailfiletimeout(); +static void mailfiletimeout __P((void)); int -mailfile(filename, ctladdr, sfflags, e) +mailfile(filename, mailer, ctladdr, sfflags, e) char *volatile filename; + MAILER *volatile mailer; ADDRESS *ctladdr; volatile int sfflags; register ENVELOPE *e; @@ -3102,6 +3272,7 @@ mailfile(filename, ctladdr, sfflags, e) register pid_t pid = -1; volatile int mode = ST_MODE_NOFILE; bool suidwarn = geteuid() == 0; + char *p; EVENT *ev; if (tTd(11, 1)) @@ -3110,6 +3281,9 @@ mailfile(filename, ctladdr, sfflags, e) printaddr(ctladdr, FALSE); } + if (mailer == NULL) + mailer = FileMailer; + if (e->e_xfp != NULL) fflush(e->e_xfp); @@ -3121,6 +3295,19 @@ mailfile(filename, ctladdr, sfflags, e) if (strcmp(filename, "/dev/null") == 0) return EX_OK; + /* check for 8-bit available */ + if (bitset(EF_HAS8BIT, e->e_flags) && + bitnset(M_7BITS, mailer->m_flags) && + (bitset(EF_DONT_MIME, e->e_flags) || + !(bitset(MM_MIME8BIT, MimeMode) || + (bitset(EF_IS_MIME, e->e_flags) && + bitset(MM_CVTMIME, MimeMode))))) + { + usrerr("554 Cannot send 8-bit data to 7-bit destination"); + e->e_status = "5.6.3"; + return(EX_DATAERR); + } + /* ** Fork so we can change permissions here. ** Note that we MUST use fork, not vfork, because of @@ -3136,6 +3323,7 @@ mailfile(filename, ctladdr, sfflags, e) /* child -- actually write to file */ struct stat stb; MCI mcibuf; + int err; volatile int oflags = O_WRONLY|O_APPEND; if (e->e_lockfp != NULL) @@ -3159,7 +3347,11 @@ mailfile(filename, ctladdr, sfflags, e) ev = NULL; #ifdef HASLSTAT - if (lstat(filename, &stb) < 0) + if (bitset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) + err = stat(filename, &stb); + else + err = lstat(filename, &stb); + if (err < 0) #else if (stat(filename, &stb) < 0) #endif @@ -3168,7 +3360,9 @@ mailfile(filename, ctladdr, sfflags, e) mode = FileMode; oflags |= O_CREAT|O_EXCL; } - else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 || + else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, stb.st_mode) || + (!bitset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail) && + stb.st_nlink != 1) || (SafeFileEnv != NULL && !S_ISREG(stb.st_mode))) exit(EX_CANTCREAT); if (mode == ST_MODE_NOFILE) @@ -3200,7 +3394,12 @@ mailfile(filename, ctladdr, sfflags, e) /* select a new user to run as */ if (!bitset(SFF_RUNASREALUID, sfflags)) { - if (bitset(S_ISUID, mode)) + if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) + { + RealUserName = NULL; + RealUid = mailer->m_uid; + } + else if (bitset(S_ISUID, mode)) { RealUserName = NULL; RealUid = stb.st_uid; @@ -3213,10 +3412,10 @@ mailfile(filename, ctladdr, sfflags, e) RealUserName = ctladdr->q_user; RealUid = ctladdr->q_uid; } - else if (FileMailer != NULL && FileMailer->m_uid != 0) + else if (mailer != NULL && mailer->m_uid != 0) { RealUserName = DefUser; - RealUid = FileMailer->m_uid; + RealUid = mailer->m_uid; } else { @@ -3225,12 +3424,14 @@ mailfile(filename, ctladdr, sfflags, e) } /* select a new group to run as */ - if (bitset(S_ISGID, mode)) + if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) + RealGid = mailer->m_gid; + else if (bitset(S_ISGID, mode)) RealGid = stb.st_gid; else if (ctladdr != NULL && ctladdr->q_uid != 0) RealGid = ctladdr->q_gid; - else if (FileMailer != NULL && FileMailer->m_gid != 0) - RealGid = FileMailer->m_gid; + else if (mailer != NULL && mailer->m_gid != 0) + RealGid = mailer->m_gid; else RealGid = DefGid; } @@ -3246,7 +3447,19 @@ mailfile(filename, ctladdr, sfflags, e) /* set group id list (needs /etc/group access) */ if (RealUserName != NULL && !DontInitGroups) - (void) initgroups(RealUserName, RealGid); + { + if (initgroups(RealUserName, RealGid) == -1 && suidwarn) + syserr("mailfile: initgroups(%s, %d) failed", + RealUserName, RealGid); + } + else + { + GIDSET_T gidset[1]; + + gidset[0] = RealGid; + if (setgroups(1, gidset) == -1 && suidwarn) + syserr("mailfile: setgroups() failed"); + } /* if you have a safe environment, go into it */ if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') @@ -3274,15 +3487,43 @@ mailfile(filename, ctladdr, sfflags, e) if (setuid(RealUid) < 0 && suidwarn) syserr("mailfile: setuid(%ld) failed", (long) RealUid); - sfflags |= SFF_NOPATHCHECK|SFF_NOLINK; + /* move into some "safe" directory */ + if (mailer->m_execdir != NULL) + { + char *q; + char buf[MAXLINE + 1]; + + for (p = mailer->m_execdir; p != NULL; p = q) + { + q = strchr(p, ':'); + if (q != NULL) + *q = '\0'; + expand(p, buf, sizeof buf, e); + if (q != NULL) + *q++ = ':'; + if (tTd(11, 20)) + printf("mailfile: trydir %s\n", + buf); + if (buf[0] != '\0' && chdir(buf) >= 0) + break; + } + } + + sfflags |= SFF_NOPATHCHECK; + if (!bitset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) + sfflags |= SFF_NOSLINK; + if (!bitset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) + sfflags |= SFF_NOHLINK; sfflags &= ~SFF_OPENASROOT; f = safefopen(filename, oflags, FileMode, sfflags); if (f == NULL) { - message("554 cannot open: %s", errstring(errno)); + message("554 cannot open %s: %s", + shortenstring(filename, MAXSHORTSTR), + errstring(errno)); exit(EX_CANTCREAT); } - if (filechanged(filename, fileno(f), &stb, sfflags)) + if (filechanged(filename, fileno(f), &stb)) { message("554 file changed after open"); exit(EX_CANTCREAT); @@ -3297,13 +3538,38 @@ mailfile(filename, ctladdr, sfflags, e) clrevent(ev); bzero(&mcibuf, sizeof mcibuf); - mcibuf.mci_mailer = FileMailer; + mcibuf.mci_mailer = mailer; mcibuf.mci_out = f; - if (bitnset(M_7BITS, FileMailer->m_flags)) + mcibuf.mci_contentlen = 0; + if (bitnset(M_7BITS, mailer->m_flags)) mcibuf.mci_flags |= MCIF_7BIT; + /* clear out per-message flags from connection structure */ + mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); + + if (bitset(EF_HAS8BIT, e->e_flags) && + !bitset(EF_DONT_MIME, e->e_flags) && + bitnset(M_7BITS, mailer->m_flags)) + mcibuf.mci_flags |= MCIF_CVT8TO7; + +#if MIME7TO8 + if (bitnset(M_MAKE8BIT, mailer->m_flags) && + !bitset(MCIF_7BIT, mcibuf.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] == ';')) + mcibuf.mci_flags |= MCIF_CVT7TO8; + } +#endif + putfromline(&mcibuf, e); - (*e->e_puthdr)(&mcibuf, e->e_header, e); + (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER); (*e->e_putbody)(&mcibuf, e, NULL); putline("\n", &mcibuf); if (fflush(f) < 0 || ferror(f)) @@ -3330,11 +3596,17 @@ mailfile(filename, ctladdr, sfflags, e) int st; st = waitfor(pid); + if (st == -1) + { + syserr("mailfile: %s: wait", mailer->m_name); + return (EX_SOFTWARE); + } if (WIFEXITED(st)) return (WEXITSTATUS(st)); else { - syserr("child died on signal %d", st); + syserr("mailfile: %s: child died on signal %d", + mailer->m_name, st); return (EX_UNAVAILABLE); } /*NOTREACHED*/ |