📄 deliver.c
字号:
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* 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.
*
* 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.
*
*/
#ifndef lint
static char id[] = "@(#)$Id: deliver.c,v 8.600.2.1.2.44 2000/09/21 21:52:17 ca Exp $";
#endif /* ! lint */
#include <sendmail.h>
#if HASSETUSERCONTEXT
# include <login_cap.h>
#endif /* HASSETUSERCONTEXT */
#if STARTTLS || (SASL && SFIO)
# include "sfsasl.h"
#endif /* STARTTLS || (SASL && SFIO) */
static int deliver __P((ENVELOPE *, ADDRESS *));
static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int));
static void mailfiletimeout __P((void));
static void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool));
static int parse_hostsignature __P((char *, char **, MAILER *));
static void sendenvelope __P((ENVELOPE *, int));
static char *hostsignature __P((MAILER *, char *));
#if SMTP
# if STARTTLS
static int starttls __P((MAILER *, MCI *, ENVELOPE *));
# endif /* STARTTLS */
#endif /* SMTP */
/*
** SENDALL -- actually send all the messages.
**
** Parameters:
** e -- the envelope to send.
** mode -- the delivery mode to use. If SM_DEFAULT, use
** the current e->e_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.
*/
void
sendall(e, mode)
ENVELOPE *e;
int mode;
{
register ADDRESS *q;
char *owner;
int otherowners;
int save_errno;
register ENVELOPE *ee;
ENVELOPE *splitenv = NULL;
int oldverbose = Verbose;
bool somedeliveries = FALSE, expensive = FALSE;
pid_t pid;
/*
** 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))
dprintf("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
** the message at all if we are in SMTP mode. Local errors
** (e.g., a single address failing) will still cause the other
** addresses to be sent.
*/
if (bitset(EF_FATALERRS, e->e_flags) &&
(OpMode == MD_SMTP || OpMode == MD_DAEMON))
{
e->e_flags |= EF_CLRQUEUE;
return;
}
/* determine actual delivery mode */
if (mode == SM_DEFAULT)
{
mode = e->e_sendmode;
if (mode != SM_VERIFY && mode != SM_DEFER &&
shouldqueue(e->e_msgpriority, e->e_ctime))
mode = SM_QUEUE;
}
if (tTd(13, 1))
{
dprintf("\n===== SENDALL: mode %c, id %s, e_from ",
mode, e->e_id);
printaddr(&e->e_from, FALSE);
dprintf("\te_flags = ");
printenvflags(e);
dprintf("sendqueue:\n");
printaddr(e->e_sendqueue, TRUE);
}
/*
** 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 (tTd(62, 1))
checkfds(NULL);
if (e->e_hopcount > MaxHopCount)
{
errno = 0;
#if QUEUE
queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
#endif /* QUEUE */
e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
ExitStat = EX_UNAVAILABLE;
syserr("554 5.0.0 Too many hops %d (%d max): from %s via %s, to %s",
e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
RealHostName == NULL ? "localhost" : RealHostName,
e->e_sendqueue->q_paddr);
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_DEAD(q->q_state))
continue;
q->q_state = QS_BADADDR;
q->q_status = "5.4.6";
}
return;
}
/*
** Do sender deletion.
**
** If the sender should be queued up, skip this.
** This can happen if the name server is hosed when you
** are trying to send mail. The result is that the sender
** is instantiated in the queue as a recipient.
*/
if (!bitset(EF_METOO, e->e_flags) &&
!QS_IS_QUEUEUP(e->e_from.q_state))
{
if (tTd(13, 5))
{
dprintf("sendall: QS_SENDER ");
printaddr(&e->e_from, FALSE);
}
e->e_from.q_state = QS_SENDER;
(void) recipient(&e->e_from, &e->e_sendqueue, 0, e);
}
/*
** Handle alias owners.
**
** We scan up the q_alias chain looking for owners.
** We discard owners that are the same as the return path.
*/
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
register struct address *a;
for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias)
continue;
if (a != NULL)
q->q_owner = a->q_owner;
if (q->q_owner != NULL &&
!QS_IS_DEAD(q->q_state) &&
strcmp(q->q_owner, e->e_from.q_paddr) == 0)
q->q_owner = NULL;
}
if (tTd(13, 25))
{
dprintf("\nAfter first owner pass, sendq =\n");
printaddr(e->e_sendqueue, TRUE);
}
owner = "";
otherowners = 1;
while (owner != NULL && otherowners > 0)
{
if (tTd(13, 28))
dprintf("owner = \"%s\", otherowners = %d\n",
owner, otherowners);
owner = NULL;
otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0;
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if (tTd(13, 30))
{
dprintf("Checking ");
printaddr(q, FALSE);
}
if (QS_IS_DEAD(q->q_state))
{
if (tTd(13, 30))
dprintf(" ... QS_IS_DEAD\n");
continue;
}
if (tTd(13, 29) && !tTd(13, 30))
{
dprintf("Checking ");
printaddr(q, FALSE);
}
if (q->q_owner != NULL)
{
if (owner == NULL)
{
if (tTd(13, 40))
dprintf(" ... 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))
dprintf(" ... Same owner = \"%s\"\n",
owner);
/* make future comparisons cheap */
q->q_owner = owner;
}
else
{
if (tTd(13, 40))
dprintf(" ... Another owner \"%s\"\n",
q->q_owner);
otherowners++;
}
owner = q->q_owner;
}
else if (tTd(13, 40))
dprintf(" ... Same owner = \"%s\"\n",
owner);
}
else
{
if (tTd(13, 40))
dprintf(" ... Null owner\n");
otherowners++;
}
if (QS_IS_BADADDR(q->q_state))
{
if (tTd(13, 30))
dprintf(" ... QS_IS_BADADDR\n");
continue;
}
if (QS_IS_QUEUEUP(q->q_state))
{
MAILER *m = q->q_mailer;
/*
** If we have temporary address failures
** (e.g., dns failure) and a fallback MX is
** set, send directly to the fallback MX host.
*/
if (FallBackMX != NULL &&
!wordinclass(FallBackMX, 'w') &&
mode != SM_VERIFY &&
(strcmp(m->m_mailer, "[IPC]") == 0 ||
strcmp(m->m_mailer, "[TCP]") == 0) &&
m->m_argv[0] != NULL &&
(strcmp(m->m_argv[0], "TCP") == 0 ||
strcmp(m->m_argv[0], "IPC") == 0))
{
int len;
char *p;
if (tTd(13, 30))
dprintf(" ... FallBackMX\n");
len = strlen(FallBackMX) + 3;
p = xalloc(len);
snprintf(p, len, "[%s]", FallBackMX);
q->q_state = QS_OK;
q->q_host = p;
}
else
{
if (tTd(13, 30))
dprintf(" ... QS_IS_QUEUEUP\n");
continue;
}
}
/*
** If this mailer is expensive, and if we don't
** want to make connections now, just mark these
** addresses and return. This is useful if we
** want to batch connections to reduce load. This
** will cause the messages to be queued up, and a
** daemon will come along to send the messages later.
*/
if (NoConnect && !Verbose &&
bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
{
if (tTd(13, 30))
dprintf(" ... expensive\n");
q->q_state = QS_QUEUEUP;
expensive = TRUE;
}
else if (bitnset(M_HOLD, q->q_mailer->m_flags) &&
QueueLimitId == NULL &&
QueueLimitSender == NULL &&
QueueLimitRecipient == NULL)
{
if (tTd(13, 30))
dprintf(" ... hold\n");
q->q_state = QS_QUEUEUP;
expensive = TRUE;
}
else
{
if (tTd(13, 30))
dprintf(" ... deliverable\n");
somedeliveries = TRUE;
}
}
if (owner != NULL && otherowners > 0)
{
/*
** Split this envelope into two.
*/
ee = (ENVELOPE *) xalloc(sizeof *ee);
*ee = *e;
ee->e_message = NULL;
ee->e_id = NULL;
assign_queueid(ee);
if (tTd(13, 1))
dprintf("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);
ee->e_errorqueue = copyqueue(e->e_errorqueue);
ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM);
ee->e_flags |= EF_NORECEIPT;
setsender(owner, ee, NULL, '\0', TRUE);
if (tTd(13, 5))
{
dprintf("sendall(split): QS_SENDER ");
printaddr(&ee->e_from, FALSE);
}
ee->e_from.q_state = QS_SENDER;
ee->e_dfp = NULL;
ee->e_lockfp = NULL;
ee->e_xfp = NULL;
ee->e_queuedir = e->e_queuedir;
ee->e_errormode = EM_MAIL;
ee->e_sibling = splitenv;
ee->e_statmsg = NULL;
splitenv = ee;
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if (q->q_owner == owner)
{
q->q_state = QS_CLONED;
if (tTd(13, 6))
dprintf("\t... stripping %s from original envelope\n",
q->q_paddr);
}
}
for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
{
if (q->q_owner != owner)
{
q->q_state = QS_CLONED;
if (tTd(13, 6))
dprintf("\t... dropping %s from cloned envelope\n",
q->q_paddr);
}
else
{
/* clear DSN parameters */
q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
q->q_flags |= DefaultNotify & ~QPINGONSUCCESS;
if (tTd(13, 6))
dprintf("\t... moving %s to cloned envelope\n",
q->q_paddr);
}
}
if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags))
dup_queue_file(e, ee, 'd');
/*
** Give the split envelope access to the parent
** transcript file for errors obtained while
** processing the recipients (done before the
** envelope splitting).
*/
if (e->e_xfp != NULL)
ee->e_xfp = bfdup(e->e_xfp);
/* failed to dup e->e_xfp, start a new transcript */
if (ee->e_xfp == NULL)
openxscript(ee);
if (mode != SM_VERIFY && LogLevel > 4)
sm_syslog(LOG_INFO, ee->e_id,
"clone %s, owner=%s",
e->e_id, owner);
}
}
if (owner != NULL)
{
setsender(owner, e, NULL, '\0', TRUE);
if (tTd(13, 5))
{
dprintf("sendall(owner): QS_SENDER ");
printaddr(&e->e_from, FALSE);
}
e->e_from.q_state = QS_SENDER;
e->e_errormode = EM_MAIL;
e->e_flags |= EF_NORECEIPT;
e->e_flags &= ~EF_FATALERRS;
}
/* if nothing to be delivered, just queue up everything */
if (!somedeliveries && mode != SM_QUEUE && mode != SM_DEFER &&
mode != SM_VERIFY)
{
if (tTd(13, 29))
dprintf("No deliveries: auto-queuing\n");
mode = SM_QUEUE;
/* treat this as a delivery in terms of counting tries */
e->e_dtime = curtime();
if (!expensive)
e->e_ntries++;
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
{
ee->e_dtime = curtime();
if (!expensive)
ee->e_ntries++;
}
}
#if QUEUE
if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK ||
(mode != SM_VERIFY && SuperSafe)) &&
(!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL))
{
/*
** Be sure everything is instantiated in the queue.
** Split envelopes first in case the machine crashes.
** If the original were done first, we may lose
** recipients.
*/
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
queueup(ee, mode == SM_QUEUE || mode == SM_DEFER);
queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
}
#endif /* QUEUE */
if (tTd(62, 10))
checkfds("after envelope splitting");
/*
** If we belong in background, fork now.
*/
if (tTd(13, 20))
{
dprintf("sendall: final mode = %c\n", mode);
if (tTd(13, 21))
{
dprintf("\n================ Final Send Queue(s) =====================\n");
dprintf("\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)
{
dprintf("\n *** Envelope %s, e_from=%s ***\n",
ee->e_id, ee->e_from.q_paddr);
printaddr(ee->e_sendqueue, TRUE);
}
dprintf("==========================================================\n\n");
}
}
switch (mode)
{
case SM_VERIFY:
Verbose = 2;
break;
case SM_QUEUE:
case SM_DEFER:
#if HASFLOCK
queueonly:
#endif /* HASFLOCK */
if (e->e_nrcpts > 0)
e->e_flags |= EF_INQUEUE;
dropenvelope(e, splitenv != NULL);
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
{
if (ee->e_nrcpts > 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -