summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/src/deliver.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/sendmail/src/deliver.c')
-rw-r--r--contrib/sendmail/src/deliver.c2860
1 files changed, 1793 insertions, 1067 deletions
diff --git a/contrib/sendmail/src/deliver.c b/contrib/sendmail/src/deliver.c
index 70b774d..402eac4 100644
--- a/contrib/sendmail/src/deliver.c
+++ b/contrib/sendmail/src/deliver.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,34 +11,35 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: deliver.c,v 8.600.2.1.2.86 2001/07/20 21:52:55 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+#include <sys/time.h>
+SM_RCSID("@(#)$Id: deliver.c,v 8.928 2002/01/10 03:23:29 gshapiro Exp $")
#if HASSETUSERCONTEXT
# include <login_cap.h>
#endif /* HASSETUSERCONTEXT */
-#if STARTTLS || (SASL && SFIO)
+#if STARTTLS || SASL
# include "sfsasl.h"
-#endif /* STARTTLS || (SASL && SFIO) */
+#endif /* STARTTLS || SASL */
+void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool));
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 *));
+extern MCI *mci_new __P((SM_RPOOL_T *));
+static int coloncmp __P((const char *, const char *));
-#if SMTP
-# if STARTTLS
+#if STARTTLS
static int starttls __P((MAILER *, MCI *, ENVELOPE *));
-# endif /* STARTTLS */
-#endif /* SMTP */
+static int endtlsclt __P((MCI *));
+#endif /* STARTTLS */
+# if STARTTLS || SASL
+static bool iscltflgset __P((ENVELOPE *, int));
+# endif /* STARTTLS || SASL */
/*
** SENDALL -- actually send all the messages.
@@ -70,7 +71,7 @@ sendall(e, mode)
register ENVELOPE *ee;
ENVELOPE *splitenv = NULL;
int oldverbose = Verbose;
- bool somedeliveries = FALSE, expensive = FALSE;
+ bool somedeliveries = false, expensive = false;
pid_t pid;
/*
@@ -81,11 +82,13 @@ sendall(e, mode)
if (bitset(EF_DISCARD, e->e_flags))
{
if (tTd(13, 1))
- dprintf("sendall: discarding id %s\n", e->e_id);
+ sm_dprintf("sendall: discarding id %s\n", e->e_id);
e->e_flags |= EF_CLRQUEUE;
- if (LogLevel > 4)
+ if (LogLevel > 9)
+ logundelrcpts(e, "discarded", 9, true);
+ else if (LogLevel > 4)
sm_syslog(LOG_INFO, e->e_id, "discarded");
- markstats(e, NULL, TRUE);
+ markstats(e, NULL, STATS_REJECT);
return;
}
@@ -114,13 +117,13 @@ sendall(e, mode)
if (tTd(13, 1))
{
- dprintf("\n===== SENDALL: mode %c, id %s, e_from ",
+ sm_dprintf("\n===== SENDALL: mode %c, id %s, e_from ",
mode, e->e_id);
- printaddr(&e->e_from, FALSE);
- dprintf("\te_flags = ");
+ printaddr(&e->e_from, false);
+ sm_dprintf("\te_flags = ");
printenvflags(e);
- dprintf("sendqueue:\n");
- printaddr(e->e_sendqueue, TRUE);
+ sm_dprintf("sendqueue:\n");
+ printaddr(e->e_sendqueue, true);
}
/*
@@ -144,9 +147,7 @@ sendall(e, mode)
recip = "(nobody)";
errno = 0;
-#if QUEUE
- queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
-#endif /* QUEUE */
+ queueup(e, WILL_BE_QUEUED(mode), false);
e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
ExitStat = EX_UNAVAILABLE;
syserr("554 5.4.6 Too many hops %d (%d max): from %s via %s, to %s",
@@ -178,8 +179,8 @@ sendall(e, mode)
{
if (tTd(13, 5))
{
- dprintf("sendall: QS_SENDER ");
- printaddr(&e->e_from, FALSE);
+ sm_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);
@@ -209,8 +210,8 @@ sendall(e, mode)
if (tTd(13, 25))
{
- dprintf("\nAfter first owner pass, sendq =\n");
- printaddr(e->e_sendqueue, TRUE);
+ sm_dprintf("\nAfter first owner pass, sendq =\n");
+ printaddr(e->e_sendqueue, true);
}
owner = "";
@@ -218,8 +219,8 @@ sendall(e, mode)
while (owner != NULL && otherowners > 0)
{
if (tTd(13, 28))
- dprintf("owner = \"%s\", otherowners = %d\n",
- owner, otherowners);
+ sm_dprintf("owner = \"%s\", otherowners = %d\n",
+ owner, otherowners);
owner = NULL;
otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0;
@@ -227,19 +228,19 @@ sendall(e, mode)
{
if (tTd(13, 30))
{
- dprintf("Checking ");
- printaddr(q, FALSE);
+ sm_dprintf("Checking ");
+ printaddr(q, false);
}
if (QS_IS_DEAD(q->q_state))
{
if (tTd(13, 30))
- dprintf(" ... QS_IS_DEAD\n");
+ sm_dprintf(" ... QS_IS_DEAD\n");
continue;
}
if (tTd(13, 29) && !tTd(13, 30))
{
- dprintf("Checking ");
- printaddr(q, FALSE);
+ sm_dprintf("Checking ");
+ printaddr(q, false);
}
if (q->q_owner != NULL)
@@ -247,8 +248,8 @@ sendall(e, mode)
if (owner == NULL)
{
if (tTd(13, 40))
- dprintf(" ... First owner = \"%s\"\n",
- q->q_owner);
+ sm_dprintf(" ... First owner = \"%s\"\n",
+ q->q_owner);
owner = q->q_owner;
}
else if (owner != q->q_owner)
@@ -256,8 +257,8 @@ sendall(e, mode)
if (strcmp(owner, q->q_owner) == 0)
{
if (tTd(13, 40))
- dprintf(" ... Same owner = \"%s\"\n",
- owner);
+ sm_dprintf(" ... Same owner = \"%s\"\n",
+ owner);
/* make future comparisons cheap */
q->q_owner = owner;
@@ -265,27 +266,27 @@ sendall(e, mode)
else
{
if (tTd(13, 40))
- dprintf(" ... Another owner \"%s\"\n",
- q->q_owner);
+ sm_dprintf(" ... Another owner \"%s\"\n",
+ q->q_owner);
otherowners++;
}
owner = q->q_owner;
}
else if (tTd(13, 40))
- dprintf(" ... Same owner = \"%s\"\n",
- owner);
+ sm_dprintf(" ... Same owner = \"%s\"\n",
+ owner);
}
else
{
if (tTd(13, 40))
- dprintf(" ... Null owner\n");
+ sm_dprintf(" ... Null owner\n");
otherowners++;
}
if (QS_IS_BADADDR(q->q_state))
{
if (tTd(13, 30))
- dprintf(" ... QS_IS_BADADDR\n");
+ sm_dprintf(" ... QS_IS_BADADDR\n");
continue;
}
@@ -302,28 +303,27 @@ sendall(e, mode)
if (FallBackMX != NULL &&
!wordinclass(FallBackMX, 'w') &&
mode != SM_VERIFY &&
- (strcmp(m->m_mailer, "[IPC]") == 0 ||
- strcmp(m->m_mailer, "[TCP]") == 0) &&
+ !bitnset(M_NOMX, m->m_flags) &&
+ strcmp(m->m_mailer, "[IPC]") == 0 &&
m->m_argv[0] != NULL &&
- (strcmp(m->m_argv[0], "TCP") == 0 ||
- strcmp(m->m_argv[0], "IPC") == 0))
+ strcmp(m->m_argv[0], "TCP") == 0)
{
int len;
char *p;
if (tTd(13, 30))
- dprintf(" ... FallBackMX\n");
+ sm_dprintf(" ... FallBackMX\n");
- len = strlen(FallBackMX) + 3;
- p = xalloc(len);
- snprintf(p, len, "[%s]", FallBackMX);
+ len = strlen(FallBackMX) + 1;
+ p = sm_rpool_malloc_x(e->e_rpool, len);
+ (void) sm_strlcpy(p, FallBackMX, len);
q->q_state = QS_OK;
q->q_host = p;
}
else
{
if (tTd(13, 30))
- dprintf(" ... QS_IS_QUEUEUP\n");
+ sm_dprintf(" ... QS_IS_QUEUEUP\n");
continue;
}
}
@@ -341,9 +341,9 @@ sendall(e, mode)
bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
{
if (tTd(13, 30))
- dprintf(" ... expensive\n");
+ sm_dprintf(" ... expensive\n");
q->q_state = QS_QUEUEUP;
- expensive = TRUE;
+ expensive = true;
}
else if (bitnset(M_HOLD, q->q_mailer->m_flags) &&
QueueLimitId == NULL &&
@@ -351,15 +351,26 @@ sendall(e, mode)
QueueLimitRecipient == NULL)
{
if (tTd(13, 30))
- dprintf(" ... hold\n");
+ sm_dprintf(" ... hold\n");
+ q->q_state = QS_QUEUEUP;
+ expensive = true;
+ }
+#if _FFR_QUARANTINE
+ else if (QueueMode != QM_QUARANTINE &&
+ e->e_quarmsg != NULL)
+ {
+ if (tTd(13, 30))
+ sm_dprintf(" ... quarantine: %s\n",
+ e->e_quarmsg);
q->q_state = QS_QUEUEUP;
- expensive = TRUE;
+ expensive = true;
}
+#endif /* _FFR_QUARANTINE */
else
{
if (tTd(13, 30))
- dprintf(" ... deliverable\n");
- somedeliveries = TRUE;
+ sm_dprintf(" ... deliverable\n");
+ somedeliveries = true;
}
}
@@ -369,35 +380,45 @@ sendall(e, mode)
** Split this envelope into two.
*/
- ee = (ENVELOPE *) xalloc(sizeof *ee);
- *ee = *e;
+ ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool,
+ sizeof *ee);
+ STRUCTCOPY(*e, *ee);
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);
+ sm_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_rpool);
+ ee->e_sendqueue = copyqueue(e->e_sendqueue,
+ ee->e_rpool);
+ ee->e_errorqueue = copyqueue(e->e_errorqueue,
+ ee->e_rpool);
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);
+ setsender(owner, ee, NULL, '\0', true);
if (tTd(13, 5))
{
- dprintf("sendall(split): QS_SENDER ");
- printaddr(&ee->e_from, FALSE);
+ sm_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_qgrp = e->e_qgrp;
+ ee->e_qdir = e->e_qdir;
ee->e_errormode = EM_MAIL;
ee->e_sibling = splitenv;
ee->e_statmsg = NULL;
+#if _FFR_QUARANTINE
+ if (e->e_quarmsg != NULL)
+ ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
+ e->e_quarmsg);
+#endif /* _FFR_QUARANTINE */
splitenv = ee;
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
@@ -406,8 +427,8 @@ sendall(e, mode)
{
q->q_state = QS_CLONED;
if (tTd(13, 6))
- dprintf("\t... stripping %s from original envelope\n",
- q->q_paddr);
+ sm_dprintf("\t... stripping %s from original envelope\n",
+ q->q_paddr);
}
}
for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
@@ -416,8 +437,8 @@ sendall(e, mode)
{
q->q_state = QS_CLONED;
if (tTd(13, 6))
- dprintf("\t... dropping %s from cloned envelope\n",
- q->q_paddr);
+ sm_dprintf("\t... dropping %s from cloned envelope\n",
+ q->q_paddr);
}
else
{
@@ -425,13 +446,13 @@ sendall(e, mode)
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);
+ sm_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');
+ dup_queue_file(e, ee, DATAFL_LETTER);
/*
** Give the split envelope access to the parent
@@ -441,26 +462,26 @@ sendall(e, mode)
*/
if (e->e_xfp != NULL)
- ee->e_xfp = bfdup(e->e_xfp);
+ ee->e_xfp = sm_io_dup(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);
+ sm_syslog(LOG_INFO, e->e_id,
+ "%s: clone: owner=%s",
+ ee->e_id, owner);
}
}
if (owner != NULL)
{
- setsender(owner, e, NULL, '\0', TRUE);
+ setsender(owner, e, NULL, '\0', true);
if (tTd(13, 5))
{
- dprintf("sendall(owner): QS_SENDER ");
- printaddr(&e->e_from, FALSE);
+ sm_dprintf("sendall(owner): QS_SENDER ");
+ printaddr(&e->e_from, false);
}
e->e_from.q_state = QS_SENDER;
e->e_errormode = EM_MAIL;
@@ -469,14 +490,15 @@ sendall(e, mode)
}
/* if nothing to be delivered, just queue up everything */
- if (!somedeliveries && mode != SM_QUEUE && mode != SM_DEFER &&
+ if (!somedeliveries && !WILL_BE_QUEUED(mode) &&
mode != SM_VERIFY)
{
- time_t now = curtime();
+ time_t now;
if (tTd(13, 29))
- dprintf("No deliveries: auto-queuing\n");
+ sm_dprintf("No deliveries: auto-queuing\n");
mode = SM_QUEUE;
+ now = curtime();
/* treat this as a delivery in terms of counting tries */
e->e_dtime = now;
@@ -490,11 +512,12 @@ sendall(e, mode)
}
}
-#if QUEUE
- if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK ||
- (mode != SM_VERIFY && SuperSafe)) &&
+ if ((WILL_BE_QUEUED(mode) || mode == SM_FORK ||
+ (mode != SM_VERIFY && SuperSafe == SAFE_REALLY)) &&
(!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL))
{
+ bool msync;
+
/*
** Be sure everything is instantiated in the queue.
** Split envelopes first in case the machine crashes.
@@ -502,11 +525,16 @@ sendall(e, mode)
** recipients.
*/
+#if !HASFLOCK
+ msync = false;
+#else /* !HASFLOCK */
+ msync = mode == SM_FORK;
+#endif /* !HASFLOCK */
+
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);
+ queueup(ee, WILL_BE_QUEUED(mode), msync);
+ queueup(e, WILL_BE_QUEUED(mode), msync);
}
-#endif /* QUEUE */
if (tTd(62, 10))
checkfds("after envelope splitting");
@@ -517,20 +545,20 @@ sendall(e, mode)
if (tTd(13, 20))
{
- dprintf("sendall: final mode = %c\n", mode);
+ sm_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);
+ sm_dprintf("\n================ Final Send Queue(s) =====================\n");
+ sm_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);
+ sm_dprintf("\n *** Envelope %s, e_from=%s ***\n",
+ ee->e_id, ee->e_from.q_paddr);
+ printaddr(ee->e_sendqueue, true);
}
- dprintf("==========================================================\n\n");
+ sm_dprintf("==========================================================\n\n");
}
}
switch (mode)
@@ -546,18 +574,18 @@ sendall(e, mode)
#endif /* HASFLOCK */
if (e->e_nrcpts > 0)
e->e_flags |= EF_INQUEUE;
- dropenvelope(e, splitenv != NULL);
+ dropenvelope(e, splitenv != NULL, true);
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
{
if (ee->e_nrcpts > 0)
ee->e_flags |= EF_INQUEUE;
- dropenvelope(ee, FALSE);
+ dropenvelope(ee, false, true);
}
return;
case SM_FORK:
if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp);
+ (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
#if !HASFLOCK
/*
@@ -573,7 +601,7 @@ sendall(e, mode)
/* now drop the envelope in the parent */
e->e_flags |= EF_INQUEUE;
- dropenvelope(e, splitenv != NULL);
+ dropenvelope(e, splitenv != NULL, false);
/* arrange to reacquire lock after fork */
e->e_id = qid;
@@ -586,7 +614,7 @@ sendall(e, mode)
/* drop envelope in parent */
ee->e_flags |= EF_INQUEUE;
- dropenvelope(ee, FALSE);
+ dropenvelope(ee, false, false);
/* and save qid for reacquisition */
ee->e_id = qid;
@@ -602,7 +630,7 @@ sendall(e, mode)
** them if necessary.
*/
- closemaps();
+ closemaps(false);
pid = fork();
if (pid < 0)
@@ -624,13 +652,13 @@ sendall(e, mode)
/* close any random open files in the envelope */
closexscript(e);
if (e->e_dfp != NULL)
- (void) bfclose(e->e_dfp);
+ (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
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) fclose(e->e_lockfp);
+ (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
else
syserr("%s: sendall: null lockfp", e->e_id);
e->e_lockfp = NULL;
@@ -639,30 +667,44 @@ sendall(e, mode)
/* make sure the parent doesn't own the envelope */
e->e_id = NULL;
+#if USE_DOUBLE_FORK
/* catch intermediate zombie */
(void) waitfor(pid);
+#endif /* USE_DOUBLE_FORK */
return;
}
/* Reset global flags */
RestartRequest = NULL;
+ RestartWorkGroup = false;
ShutdownRequest = NULL;
PendingSignal = 0;
/*
+ ** Initialize exception stack and default exception
+ ** handler for child process.
+ */
+
+ sm_exc_newthread(fatal_error);
+
+ /*
** Since we have accepted responsbility for the message,
** change the SIGTERM handler. intsig() (the old handler)
** would remove the envelope if this was a command line
** message submission.
*/
- (void) setsignal(SIGTERM, SIG_DFL);
+ (void) sm_signal(SIGTERM, SIG_DFL);
+#if USE_DOUBLE_FORK
/* double fork to avoid zombies */
pid = fork();
if (pid > 0)
exit(EX_OK);
save_errno = errno;
+#endif /* USE_DOUBLE_FORK */
+
+ CurrentPid = getpid();
/* be sure we are immune from the terminal */
disconnect(2, e);
@@ -678,11 +720,11 @@ sendall(e, mode)
#else /* HASFLOCK */
e->e_id = NULL;
#endif /* HASFLOCK */
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
}
/* be sure to give error messages in child */
- QuickAbort = FALSE;
+ QuickAbort = false;
/*
** Close any cached connections.
@@ -694,7 +736,7 @@ sendall(e, mode)
** message.
*/
- mci_flush(FALSE, NULL);
+ mci_flush(false, NULL);
#if HASFLOCK
break;
@@ -708,31 +750,31 @@ sendall(e, mode)
{
ENVELOPE *sibling = ee->e_sibling;
- (void) dowork(ee->e_queuedir, ee->e_id,
- FALSE, FALSE, ee);
+ (void) dowork(ee->e_qgrp, ee->e_qdir, ee->e_id,
+ false, false, ee);
ee->e_sibling = sibling;
}
- (void) dowork(e->e_queuedir, e->e_id,
- FALSE, FALSE, e);
- finis(TRUE, ExitStat);
+ (void) dowork(e->e_qgrp, e->e_qdir, e->e_id,
+ false, false, e);
+ finis(true, true, ExitStat);
#endif /* HASFLOCK */
}
sendenvelope(e, mode);
- dropenvelope(e, TRUE);
+ dropenvelope(e, true, true);
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
{
CurEnv = ee;
if (mode != SM_VERIFY)
openxscript(ee);
sendenvelope(ee, mode);
- dropenvelope(ee, TRUE);
+ dropenvelope(ee, true, true);
}
CurEnv = e;
Verbose = oldverbose;
if (mode == SM_FORK)
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
}
static void
@@ -744,9 +786,9 @@ sendenvelope(e, mode)
bool didany;
if (tTd(13, 10))
- dprintf("sendenvelope(%s) e_flags=0x%lx\n",
- e->e_id == NULL ? "[NOQUEUE]" : e->e_id,
- e->e_flags);
+ sm_dprintf("sendenvelope(%s) e_flags=0x%lx\n",
+ e->e_id == NULL ? "[NOQUEUE]" : e->e_id,
+ e->e_flags);
if (LogLevel > 80)
sm_syslog(LOG_DEBUG, e->e_id,
"sendenvelope, flags=0x%lx",
@@ -766,9 +808,15 @@ sendenvelope(e, mode)
return;
}
- /* Don't attempt deliveries if we want to bounce now */
+ /*
+ ** Don't attempt deliveries if we want to bounce now
+ ** or if deliver-by time is exceeded.
+ */
+
if (!bitset(EF_RESPONSE, e->e_flags) &&
- TimeOuts.to_q_return[e->e_timeoutclass] == NOW)
+ (TimeOuts.to_q_return[e->e_timeoutclass] == NOW ||
+ (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 &&
+ curtime() > e->e_ctime + e->e_deliver_by)))
return;
/*
@@ -781,9 +829,52 @@ 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;
+ macdefine(&e->e_macro, A_PERM, macid("{envid}"), e->e_envid);
+ macdefine(&e->e_macro, A_PERM, macid("{bodytype}"), e->e_bodytype);
+ didany = false;
+
+ if (!bitset(EF_SPLIT, e->e_flags))
+ {
+ ENVELOPE *oldsib;
+ ENVELOPE *ee;
+
+ /*
+ ** Save old sibling and set it to NULL to avoid
+ ** queueing up the same envelopes again.
+ ** This requires that envelopes in that list have
+ ** been take care of before (or at some other place).
+ */
+
+ oldsib = e->e_sibling;
+ e->e_sibling = NULL;
+ if (!split_by_recipient(e) &&
+ bitset(EF_FATALERRS, e->e_flags))
+ {
+ if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
+ e->e_flags |= EF_CLRQUEUE;
+ return;
+ }
+ for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
+ queueup(ee, false, true);
+
+ /* clean up */
+ for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
+ {
+ /* now unlock the job */
+ closexscript(ee);
+ unlockqueue(ee);
+
+ /* this envelope is marked unused */
+ if (ee->e_dfp != NULL)
+ {
+ (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT);
+ ee->e_dfp = NULL;
+ }
+ ee->e_id = NULL;
+ ee->e_flags &= ~EF_HAS_DF;
+ }
+ e->e_sibling = oldsib;
+ }
/* now run through the queue */
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
@@ -791,8 +882,8 @@ sendenvelope(e, mode)
#if XDEBUG
char wbuf[MAXNAME + 20];
- (void) snprintf(wbuf, sizeof wbuf, "sendall(%.*s)",
- MAXNAME, q->q_paddr);
+ (void) sm_snprintf(wbuf, sizeof wbuf, "sendall(%.*s)",
+ MAXNAME, q->q_paddr);
checkfd012(wbuf);
#endif /* XDEBUG */
if (mode == SM_VERIFY)
@@ -813,7 +904,6 @@ sendenvelope(e, mode)
}
else if (QS_IS_OK(q->q_state))
{
-#if QUEUE
/*
** Checkpoint the send list every few addresses
*/
@@ -821,12 +911,11 @@ sendenvelope(e, mode)
if (CheckpointInterval > 0 &&
e->e_nsent >= CheckpointInterval)
{
- queueup(e, FALSE);
+ queueup(e, false, false);
e->e_nsent = 0;
}
-#endif /* QUEUE */
(void) deliver(e, q);
- didany = TRUE;
+ didany = true;
}
}
if (didany)
@@ -839,13 +928,66 @@ sendenvelope(e, mode)
checkfd012("end of sendenvelope");
#endif /* XDEBUG */
}
- /*
+
+#if REQUIRES_DIR_FSYNC
+/*
+** SYNC_DIR -- fsync a directory based on a filename
+**
+** Parameters:
+** filename -- path of file
+** panic -- panic?
+**
+** Returns:
+** none
+*/
+
+void
+sync_dir(filename, panic)
+ char *filename;
+ bool panic;
+{
+ int dirfd;
+ char *dirp;
+ char dir[MAXPATHLEN];
+
+ /* filesystems which require the directory be synced */
+ dirp = strrchr(filename, '/');
+ if (dirp != NULL)
+ {
+ if (sm_strlcpy(dir, filename, sizeof dir) >= sizeof dir)
+ return;
+ dir[dirp - filename] = '\0';
+ dirp = dir;
+ }
+ else
+ dirp = ".";
+ dirfd = open(dirp, O_RDONLY, 0700);
+ if (tTd(40,32))
+ sm_syslog(LOG_INFO, NOQID, "sync_dir: %s: fsync(%d)",
+ dirp, dirfd);
+ if (dirfd >= 0)
+ {
+ if (fsync(dirfd) < 0)
+ {
+ if (panic)
+ syserr("!sync_dir: cannot fsync directory %s",
+ dirp);
+ else if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID,
+ "sync_dir: cannot fsync directory %s: %s",
+ dirp, sm_errstring(errno));
+ }
+ (void) close(dirfd);
+ }
+}
+#endif /* REQUIRES_DIR_FSYNC */
+/*
** DUP_QUEUE_FILE -- duplicate a queue file into a split queue
**
** Parameters:
** e -- the existing envelope
** ee -- the new envelope
-** type -- the queue file type (e.g., 'd')
+** type -- the queue file type (e.g., DATAFL_LETTER)
**
** Returns:
** none
@@ -853,7 +995,7 @@ sendenvelope(e, mode)
static void
dup_queue_file(e, ee, type)
- struct envelope *e, *ee;
+ ENVELOPE *e, *ee;
int type;
{
char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN];
@@ -865,8 +1007,8 @@ dup_queue_file(e, ee, type)
** Make sure both are in the same directory.
*/
- snprintf(f1buf, sizeof f1buf, "%s", queuename(e, type));
- snprintf(f2buf, sizeof f2buf, "%s", queuename(ee, type));
+ (void) sm_strlcpy(f1buf, queuename(e, type), sizeof f1buf);
+ (void) sm_strlcpy(f2buf, queuename(ee, type), sizeof f2buf);
if (link(f1buf, f2buf) < 0)
{
int save_errno = errno;
@@ -877,19 +1019,20 @@ dup_queue_file(e, ee, type)
if (unlink(f2buf) < 0)
{
syserr("!sendall: unlink(%s): permanent",
- f2buf);
+ f2buf);
/* NOTREACHED */
}
if (link(f1buf, f2buf) < 0)
{
syserr("!sendall: link(%s, %s): permanent",
- f1buf, f2buf);
+ f1buf, f2buf);
/* NOTREACHED */
}
}
}
+ SYNC_DIR(f2buf, true);
}
- /*
+/*
** DOFORK -- do a fork, retrying a couple of times on failure.
**
** This MUST be a macro, since after a vfork we are running
@@ -930,7 +1073,7 @@ dup_queue_file(e, ee, type)
(void) sleep((unsigned) NFORKTRIES - i);\
}\
}
- /*
+/*
** DOFORK -- simple fork interface to DOFORK.
**
** Parameters:
@@ -953,7 +1096,73 @@ dofork()
DOFORK(fork);
return pid;
}
- /*
+
+/*
+** COLONCMP -- compare host-signatures up to first ':' or EOS
+**
+** This takes two strings which happen to be host-signatures and
+** compares them. If the lowest preference portions of the MX-RR's
+** match (up to ':' or EOS, whichever is first), then we have
+** match. This is used for coattail-piggybacking messages during
+** message delivery.
+** If the signatures are the same up to the first ':' the remainder of
+** the signatures are then compared with a normal strcmp(). This saves
+** re-examining the first part of the signatures.
+**
+** Parameters:
+** a - first host-signature
+** b - second host-signature
+**
+** Returns:
+** HS_MATCH_NO -- no "match".
+** HS_MATCH_FIRST -- "match" for the first MX preference
+** (up to the first colon (':')).
+** HS_MATCH_FULL -- match for the entire MX record.
+**
+** Side Effects:
+** none.
+*/
+
+#define HS_MATCH_NO 0
+#define HS_MATCH_FIRST 1
+#define HS_MATCH_FULL 2
+
+static int
+coloncmp(a, b)
+ register const char *a;
+ register const char *b;
+{
+ int ret = HS_MATCH_NO;
+ int braclev = 0;
+
+ while (*a == *b++)
+ {
+ /* Need to account for IPv6 bracketed addresses */
+ if (*a == '[')
+ braclev++;
+ else if (*a == '[' && braclev > 0)
+ braclev--;
+ else if (*a == ':' && braclev <= 0)
+ {
+ ret = HS_MATCH_FIRST;
+ a++;
+ break;
+ }
+ else if (*a == '\0')
+ return HS_MATCH_FULL; /* a full match */
+ a++;
+ }
+ if (ret == HS_MATCH_NO &&
+ braclev <= 0 &&
+ ((*a == '\0' && *(b - 1) == ':') ||
+ (*a == ':' && *(b - 1) == '\0')))
+ return HS_MATCH_FIRST;
+ if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0)
+ return HS_MATCH_FULL;
+
+ return ret;
+}
+/*
** DELIVER -- Deliver a message to a list of addresses.
**
** This routine delivers to everyone on the same host as the
@@ -962,6 +1171,45 @@ dofork()
** that it will deliver to all these addresses however -- so
** deliver should be called once for each address on the
** list.
+** Deliver tries to be as opportunistic as possible about piggybacking
+** messages. Some definitions to make understanding easier follow below.
+** Piggybacking occurs when an existing connection to a mail host can
+** be used to send the same message to more than one recipient at the
+** same time. So "no piggybacking" means one message for one recipient
+** per connection. "Intentional piggybacking" happens when the
+** recipients' host address (not the mail host address) is used to
+** attempt piggybacking. Recipients with the same host address
+** have the same mail host. "Coincidental piggybacking" relies on
+** piggybacking based on all the mail host addresses in the MX-RR. This
+** is "coincidental" in the fact it could not be predicted until the
+** MX Resource Records for the hosts were obtained and examined. For
+** example (preference order and equivalence is important, not values):
+** domain1 IN MX 10 mxhost-A
+** IN MX 20 mxhost-B
+** domain2 IN MX 4 mxhost-A
+** IN MX 8 mxhost-B
+** Domain1 and domain2 can piggyback the same message to mxhost-A or
+** mxhost-B (if mxhost-A cannot be reached).
+** "Coattail piggybacking" relaxes the strictness of "coincidental
+** piggybacking" in the hope that most significant (lowest value)
+** MX preference host(s) can create more piggybacking. For example
+** (again, preference order and equivalence is important, not values):
+** domain3 IN MX 100 mxhost-C
+** IN MX 100 mxhost-D
+** IN MX 200 mxhost-E
+** domain4 IN MX 50 mxhost-C
+** IN MX 50 mxhost-D
+** IN MX 80 mxhost-F
+** A message for domain3 and domain4 can piggyback to mxhost-C if mxhost-C
+** is available. Same with mxhost-D because in both RR's the preference
+** value is the same as mxhost-C, respectively.
+** So deliver attempts coattail piggybacking when possible. If the
+** first MX preference level hosts cannot be used then the piggybacking
+** reverts to coincidental piggybacking. Using the above example you
+** cannot deliver to mxhost-F for domain3 regardless of preference value.
+** ("Coattail" from "riding on the coattails of your predecessor" meaning
+** gaining benefit from a predecessor effort with no or little addition
+** effort. The predecessor here being the preceding MX RR).
**
** Parameters:
** e -- the envelope to deliver.
@@ -994,41 +1242,44 @@ deliver(e, firstto)
register char *p;
register MAILER *m; /* mailer for this recipient */
ADDRESS *volatile ctladdr;
+#if HASSETUSERCONTEXT
ADDRESS *volatile contextaddr = NULL;
+#endif /* HASSETUSERCONTEXT */
register MCI *volatile mci;
- register ADDRESS *to = firstto;
- volatile bool clever = FALSE; /* running user smtp to this mailer */
+ register ADDRESS *SM_NONVOLATILE to = 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;
- int nummxhosts = 0; /* number of MX hosts available */
- int hostnum = 0; /* current MX host index */
+ SM_NONVOLATILE int lmtp_rcode = EX_OK;
+ SM_NONVOLATILE int nummxhosts = 0; /* number of MX hosts available */
+ SM_NONVOLATILE int hostnum = 0; /* current MX host index */
char *firstsig; /* signature of firstto */
- pid_t pid = -1;
+ volatile pid_t pid = -1;
char *volatile curhost;
- register u_short port = 0;
+ SM_NONVOLATILE unsigned short port = 0;
+ SM_NONVOLATILE time_t enough = 0;
#if NETUNIX
- char *mux_path = NULL; /* path to UNIX domain socket */
+ char *SM_NONVOLATILE mux_path = NULL; /* path to UNIX domain socket */
#endif /* NETUNIX */
time_t xstart;
bool suidwarn;
bool anyok; /* at least one address was OK */
- bool goodmxfound = FALSE; /* at least one MX was OK */
+ SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */
bool ovr;
-#if _FFR_DYNAMIC_TOBUF
+#if _FFR_QUARANTINE
+ bool quarantine;
+#endif /* _FFR_QUARANTINE */
int strsize;
int rcptcount;
+ int ret;
static int tobufsize = 0;
static char *tobuf = NULL;
-#else /* _FFR_DYNAMIC_TOBUF */
- char tobuf[TOBUFSIZE]; /* text line of to people */
-#endif /* _FFR_DYNAMIC_TOBUF */
+ char *rpath; /* translated return path */
int mpvect[2];
int rpvect[2];
char *mxhosts[MAXMXHOSTS + 1];
char *pv[MAXPV + 1];
char buf[MAXNAME + 1];
- char rpathbuf[MAXNAME + 1]; /* translated return path */
errno = 0;
if (!QS_IS_OK(to->q_state))
@@ -1040,29 +1291,32 @@ deliver(e, firstto)
host = to->q_host;
CurEnv = e; /* just in case */
e->e_statmsg = NULL;
-#if SMTP
SmtpError[0] = '\0';
-#endif /* SMTP */
xstart = curtime();
if (tTd(10, 1))
- dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
+ sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
e->e_id, m->m_name, host, to->q_user);
if (tTd(10, 100))
- printopenfds(FALSE);
+ printopenfds(false);
/*
- ** Clear $&{client_*} macros if this is a bounce message to
+ ** 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);
+ macdefine(&e->e_macro, A_PERM, macid("{client_name}"), "");
+ macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), "");
+ macdefine(&e->e_macro, A_PERM, macid("{client_port}"), "");
+ macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), "");
}
+ SM_TRY
+ {
+ ADDRESS *skip_back = NULL;
+
/*
** Do initial argv setup.
** Insert the mailer name. Notice that $x expansion is
@@ -1080,15 +1334,18 @@ deliver(e, firstto)
p = e->e_sender;
else
p = e->e_from.q_paddr;
- p = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e);
- if (strlen(p) >= (SIZE_T) sizeof rpathbuf)
+ rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e);
+ if (strlen(rpath) > MAXSHORTSTR)
{
- p = shortenstring(p, MAXSHORTSTR);
- syserr("remotename: huge return %s", p);
+ rpath = shortenstring(rpath, MAXSHORTSTR);
+
+ /* avoid bogus errno */
+ errno = 0;
+ syserr("remotename: huge return path %s", rpath);
}
- snprintf(rpathbuf, sizeof rpathbuf, "%s", p);
- define('g', rpathbuf, e); /* translated return path */
- define('h', host, e); /* to host */
+ rpath = sm_rpool_strdup_x(e->e_rpool, rpath);
+ macdefine(&e->e_macro, A_PERM, 'g', rpath);
+ macdefine(&e->e_macro, A_PERM, 'h', host);
Errors = 0;
pvp = pv;
*pvp++ = m->m_argv[0];
@@ -1102,7 +1359,7 @@ deliver(e, firstto)
*pvp++ = "-f";
else
*pvp++ = "-r";
- *pvp++ = newstr(rpathbuf);
+ *pvp++ = rpath;
}
/*
@@ -1129,12 +1386,13 @@ deliver(e, firstto)
/* this entry is safe -- go ahead and process it */
expand(*mvp, buf, sizeof buf, e);
- *pvp++ = newstr(buf);
+ *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf);
if (pvp >= &pv[MAXPV - 3])
{
syserr("554 5.3.5 Too many parameters to %s before $u",
pv[0]);
- return -1;
+ rcode = -1;
+ goto cleanup;
}
}
@@ -1147,14 +1405,8 @@ deliver(e, firstto)
if (*mvp == NULL)
{
/* running LMTP or SMTP */
-#if SMTP
- clever = TRUE;
+ clever = true;
*pvp = NULL;
-#else /* SMTP */
- /* oops! we don't implement SMTP */
- syserr("554 5.3.5 SMTP style mailer not implemented");
- return EX_SOFTWARE;
-#endif /* SMTP */
}
else if (bitnset(M_LMTP, m->m_flags))
{
@@ -1172,62 +1424,85 @@ deliver(e, firstto)
** always send another copy later.
*/
-#if _FFR_DYNAMIC_TOBUF
e->e_to = NULL;
strsize = 2;
rcptcount = 0;
-#else /* _FFR_DYNAMIC_TOBUF */
- tobuf[0] = '\0';
- e->e_to = tobuf;
-#endif /* _FFR_DYNAMIC_TOBUF */
-
ctladdr = NULL;
- firstsig = hostsignature(firstto->q_mailer, firstto->q_host);
+ if (firstto->q_signature == NULL)
+ firstto->q_signature = hostsignature(firstto->q_mailer,
+ firstto->q_host);
+ firstsig = firstto->q_signature;
+
for (; to != NULL; to = to->q_next)
{
/* avoid sending multiple recipients to dumb mailers */
-#if _FFR_DYNAMIC_TOBUF
if (tochain != NULL && !bitnset(M_MUSER, m->m_flags))
break;
-#else /* _FFR_DYNAMIC_TOBUF */
- if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))
- break;
-#endif /* _FFR_DYNAMIC_TOBUF */
/* if already sent or not for this host, don't send */
- if (!QS_IS_OK(to->q_state) ||
- to->q_mailer != firstto->q_mailer ||
- strcmp(hostsignature(to->q_mailer, to->q_host),
- firstsig) != 0)
+ if (!QS_IS_OK(to->q_state)) /* already sent; look at next */
continue;
- /* avoid overflowing tobuf */
-#if _FFR_DYNAMIC_TOBUF
- strsize += strlen(to->q_paddr) + 1;
- if (!clever && strsize > TOBUFSIZE)
+ /*
+ ** Must be same mailer to keep grouping rcpts.
+ ** If mailers don't match: continue; sendqueue is not
+ ** sorted by mailers, so don't break;
+ */
+
+ if (to->q_mailer != firstto->q_mailer)
+ continue;
+
+ if (to->q_signature == NULL) /* for safety */
+ to->q_signature = hostsignature(to->q_mailer,
+ to->q_host);
+
+ /*
+ ** This is for coincidental and tailcoat piggybacking messages
+ ** to the same mail host. While the signatures are identical
+ ** (that's the MX-RR's are identical) we can do coincidental
+ ** piggybacking. We try hard for coattail piggybacking
+ ** with the same mail host when the next recipient has the
+ ** same host at lowest preference. It may be that this
+ ** won't work out, so 'skip_back' is maintained if a backup
+ ** to coincidental piggybacking or full signature must happen.
+ */
+
+ ret = firstto == to ? HS_MATCH_FULL :
+ coloncmp(to->q_signature, firstsig);
+ if (ret == HS_MATCH_FULL)
+ skip_back = to;
+ else if (ret == HS_MATCH_NO)
break;
+ if (!clever)
+ {
+ /* avoid overflowing tobuf */
+ strsize += strlen(to->q_paddr) + 1;
+ if (strsize > TOBUFSIZE)
+ break;
+ }
+
if (++rcptcount > to->q_mailer->m_maxrcpt)
break;
-#else /* _FFR_DYNAMIC_TOBUF */
- if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))
- break;
-#endif /* _FFR_DYNAMIC_TOBUF */
if (tTd(10, 1))
{
- dprintf("\nsend to ");
- printaddr(to, FALSE);
+ sm_dprintf("\nsend to ");
+ printaddr(to, false);
}
/* compute effective uid/gid when sending */
if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
+# if HASSETUSERCONTEXT
contextaddr = ctladdr = getctladdr(to);
+# else /* HASSETUSERCONTEXT */
+ ctladdr = getctladdr(to);
+# endif /* HASSETUSERCONTEXT */
if (tTd(10, 2))
{
- dprintf("ctladdr=");
- printaddr(ctladdr, FALSE);
+ sm_dprintf("ctladdr=");
+ printaddr(ctladdr, false);
}
user = to->q_user;
@@ -1247,45 +1522,61 @@ deliver(e, firstto)
to->q_status = "5.2.3";
else
to->q_status = "5.3.4";
+
/* set to->q_rstatus = NULL; or to the following? */
usrerrenh(to->q_status,
"552 Message is too large; %ld bytes max",
m->m_maxsize);
- markfailure(e, to, NULL, EX_UNAVAILABLE, FALSE);
+ markfailure(e, to, NULL, EX_UNAVAILABLE, false);
giveresponse(EX_UNAVAILABLE, to->q_status, m,
- NULL, ctladdr, xstart, e);
+ NULL, ctladdr, xstart, e, to);
continue;
}
-#if NAMED_BIND
SM_SET_H_ERRNO(0);
-#endif /* NAMED_BIND */
+ ovr = true;
- ovr = TRUE;
/* do config file checking of compatibility */
+#if _FFR_QUARANTINE
+ quarantine = (e->e_quarmsg != NULL);
+#endif /* _FFR_QUARANTINE */
rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr,
- e, TRUE, TRUE, 4, NULL);
+ e, true, true, 3, NULL, e->e_id);
if (rcode == EX_OK)
{
/* do in-code checking if not discarding */
if (!bitset(EF_DISCARD, e->e_flags))
{
rcode = checkcompat(to, e);
- ovr = FALSE;
+ ovr = false;
}
}
if (rcode != EX_OK)
{
markfailure(e, to, NULL, rcode, ovr);
giveresponse(rcode, to->q_status, m,
- NULL, ctladdr, xstart, e);
+ NULL, ctladdr, xstart, e, to);
continue;
}
+#if _FFR_QUARANTINE
+ if (!quarantine && e->e_quarmsg != NULL)
+ {
+ /*
+ ** check_compat or checkcompat() has tried
+ ** to quarantine but that isn't supported.
+ ** Revert the attempt.
+ */
+
+ e->e_quarmsg = NULL;
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), "");
+ }
+#endif /* _FFR_QUARANTINE */
if (bitset(EF_DISCARD, e->e_flags))
{
if (tTd(10, 5))
{
- dprintf("deliver: discarding recipient ");
- printaddr(to, FALSE);
+ sm_dprintf("deliver: discarding recipient ");
+ printaddr(to, false);
}
/* pretend the message was sent */
@@ -1340,11 +1631,11 @@ deliver(e, firstto)
if (strcmp(m->m_mailer, "[FILE]") == 0)
{
- define('u', user, e); /* to user */
+ macdefine(&e->e_macro, A_PERM, 'u', user);
p = to->q_home;
if (p == NULL && ctladdr != NULL)
p = ctladdr->q_home;
- define('z', p, e); /* user's home */
+ macdefine(&e->e_macro, A_PERM, 'z', p);
expand(m->m_argv[1], buf, sizeof buf, e);
if (strlen(buf) > 0)
rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e);
@@ -1355,8 +1646,8 @@ deliver(e, firstto)
rcode = EX_CONFIG;
}
giveresponse(rcode, to->q_status, m, NULL,
- ctladdr, xstart, e);
- markfailure(e, to, NULL, rcode, TRUE);
+ ctladdr, xstart, e, to);
+ markfailure(e, to, NULL, rcode, true);
e->e_nsent++;
if (rcode == EX_OK)
{
@@ -1366,12 +1657,14 @@ deliver(e, firstto)
{
to->q_flags |= QDELIVERED;
to->q_status = "2.1.5";
- fprintf(e->e_xfp, "%s... Successfully delivered\n",
- to->q_paddr);
+ (void) sm_io_fprintf(e->e_xfp,
+ SM_TIME_DEFAULT,
+ "%s... Successfully delivered\n",
+ to->q_paddr);
}
}
to->q_statdate = curtime();
- markstats(e, to, FALSE);
+ markstats(e, to, STATS_NORMAL);
continue;
}
@@ -1383,20 +1676,13 @@ deliver(e, firstto)
/* link together the chain of recipients */
to->q_tchain = tochain;
tochain = to;
-
-#if _FFR_DYNAMIC_TOBUF
e->e_to = "[CHAIN]";
-#else /* _FFR_DYNAMIC_TOBUF */
- /* create list of users for error messages */
- (void) strlcat(tobuf, ",", sizeof tobuf);
- (void) strlcat(tobuf, to->q_paddr, sizeof tobuf);
-#endif /* _FFR_DYNAMIC_TOBUF */
- define('u', user, e); /* to user */
+ macdefine(&e->e_macro, A_PERM, 'u', user); /* to user */
p = to->q_home;
if (p == NULL && ctladdr != NULL)
p = ctladdr->q_home;
- define('z', p, e); /* user's home */
+ macdefine(&e->e_macro, A_PERM, 'z', p); /* user's home */
/* set the ${dsn_notify} macro if applicable */
if (bitset(QHASNOTIFY, to->q_flags))
@@ -1405,24 +1691,28 @@ deliver(e, firstto)
notify[0] = '\0';
if (bitset(QPINGONSUCCESS, to->q_flags))
- (void) strlcat(notify, "SUCCESS,",
- sizeof notify);
+ (void) sm_strlcat(notify, "SUCCESS,",
+ sizeof notify);
if (bitset(QPINGONFAILURE, to->q_flags))
- (void) strlcat(notify, "FAILURE,",
- sizeof notify);
+ (void) sm_strlcat(notify, "FAILURE,",
+ sizeof notify);
if (bitset(QPINGONDELAY, to->q_flags))
- (void) strlcat(notify, "DELAY,", sizeof notify);
+ (void) sm_strlcat(notify, "DELAY,",
+ sizeof notify);
/* Set to NEVER or drop trailing comma */
if (notify[0] == '\0')
- (void) strlcat(notify, "NEVER", sizeof notify);
+ (void) sm_strlcat(notify, "NEVER",
+ sizeof notify);
else
notify[strlen(notify) - 1] = '\0';
- define(macid("{dsn_notify}", NULL), newstr(notify), e);
+ macdefine(&e->e_macro, A_TEMP,
+ macid("{dsn_notify}"), notify);
}
else
- define(macid("{dsn_notify}", NULL), NULL, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{dsn_notify}"), NULL);
/*
** Expand out this user into argument list.
@@ -1431,7 +1721,7 @@ deliver(e, firstto)
if (!clever)
{
expand(*mvp, buf, sizeof buf, e);
- *pvp++ = newstr(buf);
+ *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf);
if (pvp >= &pv[MAXPV - 2])
{
/* allow some space for trailing parms */
@@ -1441,57 +1731,48 @@ deliver(e, firstto)
}
/* see if any addresses still exist */
-#if _FFR_DYNAMIC_TOBUF
if (tochain == NULL)
-#else /* _FFR_DYNAMIC_TOBUF */
- if (tobuf[0] == '\0')
-#endif /* _FFR_DYNAMIC_TOBUF */
{
- define('g', (char *) NULL, e);
- e->e_to = NULL;
- return 0;
+ rcode = 0;
+ goto cleanup;
}
/* print out messages as full list */
-#if _FFR_DYNAMIC_TOBUF
+ strsize = 1;
+ for (to = tochain; to != NULL; to = to->q_tchain)
+ strsize += strlen(to->q_paddr) + 1;
+ if (strsize < TOBUFSIZE)
+ strsize = TOBUFSIZE;
+ if (strsize > tobufsize)
{
- int l = 1;
- char *tobufptr;
-
- for (to = tochain; to != NULL; to = to->q_tchain)
- l += strlen(to->q_paddr) + 1;
- if (l < TOBUFSIZE)
- l = TOBUFSIZE;
- if (l > tobufsize)
- {
- if (tobuf != NULL)
- sm_free(tobuf);
- tobufsize = l;
- tobuf = xalloc(tobufsize);
- }
- tobufptr = tobuf;
- *tobufptr = '\0';
- for (to = tochain; to != NULL; to = to->q_tchain)
- {
- snprintf(tobufptr, tobufsize - (tobufptr - tobuf),
- ",%s", to->q_paddr);
- tobufptr += strlen(tobufptr);
- }
+ SM_FREE_CLR(tobuf);
+ tobuf = sm_pmalloc_x(strsize);
+ tobufsize = strsize;
+ }
+ p = tobuf;
+ *p = '\0';
+ for (to = tochain; to != NULL; to = to->q_tchain)
+ {
+ (void) sm_strlcpyn(p, tobufsize - (p - tobuf), 2,
+ ",", to->q_paddr);
+ p += strlen(p);
}
-#endif /* _FFR_DYNAMIC_TOBUF */
e->e_to = tobuf + 1;
/*
** Fill out any parameters after the $u parameter.
*/
- while (!clever && *++mvp != NULL)
+ if (!clever)
{
- expand(*mvp, buf, sizeof buf, e);
- *pvp++ = newstr(buf);
- if (pvp >= &pv[MAXPV])
- syserr("554 5.3.0 deliver: pv overflow after $u for %s",
- pv[0]);
+ while (*++mvp != NULL)
+ {
+ expand(*mvp, buf, sizeof buf, e);
+ *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf);
+ if (pvp >= &pv[MAXPV])
+ syserr("554 5.3.0 deliver: pv overflow after $u for %s",
+ pv[0]);
+ }
}
*pvp++ = NULL;
@@ -1515,14 +1796,11 @@ deliver(e, firstto)
if (tTd(11, 1))
{
- dprintf("openmailer:");
+ sm_dprintf("openmailer:");
printav(pv);
}
errno = 0;
-#if NAMED_BIND
SM_SET_H_ERRNO(0);
-#endif /* NAMED_BIND */
-
CurHostName = NULL;
/*
@@ -1543,8 +1821,9 @@ deliver(e, firstto)
char wbuf[MAXLINE];
/* make absolutely certain 0, 1, and 2 are in use */
- snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
+ (void) sm_snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)",
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name);
checkfd012(wbuf);
}
#endif /* XDEBUG */
@@ -1559,7 +1838,7 @@ deliver(e, firstto)
{
e->e_status = "5.6.3";
usrerrenh(e->e_status,
- "554 Cannot send 8-bit data to 7-bit destination");
+ "554 Cannot send 8-bit data to 7-bit destination");
rcode = EX_DATAERR;
goto give_up;
}
@@ -1570,17 +1849,50 @@ deliver(e, firstto)
/* check for Local Person Communication -- not for mortals!!! */
if (strcmp(m->m_mailer, "[LPC]") == 0)
{
- mci = (MCI *) xalloc(sizeof *mci);
- memset((char *) mci, '\0', sizeof *mci);
- mci->mci_in = stdin;
- mci->mci_out = stdout;
+#if _FFR_CACHE_LPC
+ if (clever)
+ {
+ /* flush any expired connections */
+ (void) mci_scan(NULL);
+
+ /* try to get a cached connection or just a slot */
+ 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 SMTP/LPC connection for %s...",
+ m->m_name);
+ mci->mci_deliveries++;
+ goto do_transfer;
+ }
+ }
+ else
+ {
+ mci = mci_new(e->e_rpool);
+ }
+ mci->mci_in = smioin;
+ mci->mci_out = smioout;
+ mci->mci_mailer = m;
+ mci->mci_host = m->m_name;
+ if (clever)
+ {
+ mci->mci_state = MCIS_OPENING;
+ mci_cache(mci);
+ }
+ else
+ mci->mci_state = MCIS_OPEN;
+#else /* _FFR_CACHE_LPC */
+ mci = mci_new(e->e_rpool);
+ mci->mci_in = smioin;
+ mci->mci_out = smioout;
mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
mci->mci_mailer = m;
+#endif /* _FFR_CACHE_LPC */
}
- else if (strcmp(m->m_mailer, "[IPC]") == 0 ||
- strcmp(m->m_mailer, "[TCP]") == 0)
+ else if (strcmp(m->m_mailer, "[IPC]") == 0)
{
-#if DAEMON
register int i;
if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
@@ -1622,7 +1934,7 @@ deliver(e, firstto)
# endif /* NETUNIX */
)
{
- port = htons((u_short)atoi(pv[2]));
+ port = htons((unsigned short) atoi(pv[2]));
if (port == 0)
{
# ifdef NO_GETSERVBYNAME
@@ -1639,6 +1951,8 @@ deliver(e, firstto)
}
nummxhosts = parse_hostsignature(curhost, mxhosts, m);
+ if (TimeOuts.to_aconnect > 0)
+ enough = curtime() + TimeOuts.to_aconnect;
tryhost:
while (hostnum < nummxhosts)
{
@@ -1664,6 +1978,24 @@ tryhost:
*endp = '\0';
}
+ if (hostnum == 1 && skip_back != NULL)
+ {
+ /*
+ ** Coattail piggybacking is no longer an
+ ** option with the mail host next to be tried
+ ** no longer the lowest MX preference
+ ** (hostnum == 1 meaning we're on the second
+ ** preference). We do not try to coattail
+ ** piggyback more than the first MX preference.
+ ** Revert 'tochain' to last location for
+ ** coincidental piggybacking. This works this
+ ** easily because the q_tchain kept getting
+ ** added to the top of the linked list.
+ */
+
+ tochain = skip_back;
+ }
+
if (*mxhosts[hostnum] == '\0')
{
syserr("deliver: null host name in signature");
@@ -1672,8 +2004,8 @@ tryhost:
*endp = sep;
continue;
}
- (void) strlcpy(hostbuf, mxhosts[hostnum],
- sizeof hostbuf);
+ (void) sm_strlcpy(hostbuf, mxhosts[hostnum],
+ sizeof hostbuf);
hostnum++;
if (endp != NULL)
*endp = sep;
@@ -1683,15 +2015,22 @@ tryhost:
mci = mci_get(hostbuf, m);
if (mci->mci_state != MCIS_CLOSED)
{
+ char *type;
+
if (tTd(11, 1))
{
- dprintf("openmailer: ");
- mci_dump(mci, FALSE);
+ sm_dprintf("openmailer: ");
+ mci_dump(mci, false);
}
CurHostName = mci->mci_host;
- message("Using cached %sSMTP connection to %s via %s...",
- bitset(MCIF_ESMTP, mci->mci_flags) ? "E" : "",
- hostbuf, m->m_name);
+ if (bitnset(M_LMTP, m->m_flags))
+ type = "L";
+ else if (bitset(MCIF_ESMTP, mci->mci_flags))
+ type = "ES";
+ else
+ type = "S";
+ message("Using cached %sMTP connection to %s via %s...",
+ type, hostbuf, m->m_name);
mci->mci_deliveries++;
break;
}
@@ -1699,19 +2038,19 @@ tryhost:
if (mci->mci_exitstat != EX_OK)
{
if (mci->mci_exitstat == EX_TEMPFAIL)
- goodmxfound = TRUE;
+ goodmxfound = true;
continue;
}
if (mci_lock_host(mci) != EX_OK)
{
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
- goodmxfound = TRUE;
+ goodmxfound = true;
continue;
}
/* try the connection */
- sm_setproctitle(TRUE, e, "%s %s: %s",
+ sm_setproctitle(true, e, "%s %s: %s",
qid_printname(e),
hostbuf, "user open");
# if NETUNIX
@@ -1719,7 +2058,7 @@ tryhost:
{
message("Connecting to %s via %s...",
mux_path, m->m_name);
- i = makeconnection_ds(mux_path, mci);
+ i = makeconnection_ds((char *) mux_path, mci);
}
else
# endif /* NETUNIX */
@@ -1731,7 +2070,8 @@ tryhost:
message("Connecting to %s port %d via %s...",
hostbuf, ntohs(port),
m->m_name);
- i = makeconnection(hostbuf, port, mci, e);
+ i = makeconnection(hostbuf, port, mci, e,
+ enough);
}
mci->mci_errno = errno;
mci->mci_lastuse = curtime();
@@ -1740,23 +2080,55 @@ tryhost:
# if NAMED_BIND
mci->mci_herrno = h_errno;
# endif /* NAMED_BIND */
+
+ /*
+ ** Have we tried long enough to get a connection?
+ ** If yes, skip to the fallback MX hosts
+ ** (if existent).
+ */
+
+ if (enough > 0 && mci->mci_lastuse >= enough)
+ {
+ int h;
+# if NAMED_BIND
+ extern int NumFallBackMXHosts;
+# else /* NAMED_BIND */
+ const int NumFallBackMXHosts = 0;
+# endif /* NAMED_BIND */
+
+ if (hostnum < nummxhosts && LogLevel > 9)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Timeout.to_aconnect occurred before exhausting all addresses");
+
+ /* turn off timeout if fallback available */
+ if (NumFallBackMXHosts > 0)
+ enough = 0;
+
+ /* skip to a fallback MX host */
+ h = nummxhosts - NumFallBackMXHosts;
+ if (hostnum < h)
+ hostnum = h;
+ }
if (i == EX_OK)
{
- goodmxfound = TRUE;
+ goodmxfound = true;
mci->mci_state = MCIS_OPENING;
mci_cache(mci);
if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d === CONNECT %s\n",
- (int) getpid(), hostbuf);
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "%05d === CONNECT %s\n",
+ (int) CurrentPid,
+ hostbuf);
break;
}
else
{
if (tTd(11, 1))
- dprintf("openmailer: makeconnection => stat=%d, errno=%d\n",
- i, errno);
+ sm_dprintf("openmailer: makeconnection => stat=%d, errno=%d\n",
+ i, errno);
if (i == EX_TEMPFAIL)
- goodmxfound = TRUE;
+ goodmxfound = true;
mci_unlock_host(mci);
}
@@ -1772,13 +2144,6 @@ tryhost:
goto give_up;
}
mci->mci_pid = 0;
-#else /* DAEMON */
- syserr("554 5.3.5 openmailer: no IPC");
- if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
- rcode = EX_UNAVAILABLE;
- goto give_up;
-#endif /* DAEMON */
}
else
{
@@ -1786,7 +2151,6 @@ tryhost:
(void) mci_scan(NULL);
mci = NULL;
-#if SMTP
if (bitnset(M_LMTP, m->m_flags))
{
/* try to get a cached connection */
@@ -1802,7 +2166,6 @@ tryhost:
goto do_transfer;
}
}
-#endif /* SMTP */
/* announce the connection to verbose listeners */
if (host == NULL || host[0] == '\0')
@@ -1813,10 +2176,14 @@ tryhost:
{
char **av;
- fprintf(TrafficLogFile, "%05d === EXEC", (int) getpid());
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d === EXEC", (int) CurrentPid);
for (av = pv; *av != NULL; av++)
- fprintf(TrafficLogFile, " %s", *av);
- fprintf(TrafficLogFile, "\n");
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT, " %s",
+ *av);
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "\n");
}
#if XDEBUG
@@ -1827,9 +2194,9 @@ tryhost:
if (pipe(mpvect) < 0)
{
syserr("%s... openmailer(%s): pipe (to mailer)",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
+ shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
+ sm_dprintf("openmailer: NULL\n");
rcode = EX_OSERR;
goto give_up;
}
@@ -1839,11 +2206,11 @@ tryhost:
if (mpvect[0] < 3 || mpvect[1] < 3)
{
syserr("%s... openmailer(%s): bogus mpvect %d %d",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name,
- mpvect[0], mpvect[1]);
- printopenfds(TRUE);
+ shortenstring(e->e_to, MAXSHORTSTR), m->m_name,
+ mpvect[0], mpvect[1]);
+ printopenfds(true);
if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
+ sm_dprintf("openmailer: NULL\n");
rcode = EX_OSERR;
goto give_up;
}
@@ -1853,18 +2220,21 @@ tryhost:
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))))
+ (mpvect[0] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
+ NULL) ||
+ mpvect[1] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
+ NULL))))
{
if (e->e_lockfp == NULL)
syserr("%s... openmailer(%s): overlapping mpvect %d %d",
- shortenstring(e->e_to, MAXSHORTSTR),
- 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, MAXSHORTSTR),
- m->m_name, mpvect[0], mpvect[1],
- fileno(e->e_lockfp));
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name, mpvect[0], mpvect[1],
+ sm_io_getinfo(e->e_lockfp,
+ SM_IO_WHAT_FD, NULL));
}
#endif /* XDEBUG */
@@ -1872,12 +2242,12 @@ tryhost:
if (pipe(rpvect) < 0)
{
syserr("%s... openmailer(%s): pipe (from mailer)",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name);
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name);
(void) close(mpvect[0]);
(void) close(mpvect[1]);
if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
+ sm_dprintf("openmailer: NULL\n");
rcode = EX_OSERR;
goto give_up;
}
@@ -1894,10 +2264,10 @@ tryhost:
** around so that endmailer will get it.
*/
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp); /* for debugging */
- (void) fflush(stdout);
- (void) setsignal(SIGCHLD, SIG_DFL);
+ if (e->e_xfp != NULL) /* for debugging */
+ (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
+ (void) sm_signal(SIGCHLD, SIG_DFL);
DOFORK(FORK);
@@ -1907,13 +2277,13 @@ tryhost:
{
/* failure */
syserr("%s... openmailer(%s): cannot fork",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
+ shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
(void) close(mpvect[0]);
(void) close(mpvect[1]);
(void) close(rpvect[0]);
(void) close(rpvect[1]);
if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
+ sm_dprintf("openmailer: NULL\n");
rcode = EX_OSERR;
goto give_up;
}
@@ -1921,31 +2291,38 @@ tryhost:
{
int i;
int save_errno;
+ int sff;
int new_euid = NO_UID;
int new_ruid = NO_UID;
int new_gid = NO_GID;
+ char *user = NULL;
struct stat stb;
extern int DtableSize;
+ CurrentPid = getpid();
+
/* clear the events to turn off SIGALRMs */
- clear_events();
+ sm_clear_events();
/* Reset global flags */
RestartRequest = NULL;
+ RestartWorkGroup = false;
ShutdownRequest = NULL;
PendingSignal = 0;
if (e->e_lockfp != NULL)
- (void) close(fileno(e->e_lockfp));
+ (void) close(sm_io_getinfo(e->e_lockfp,
+ SM_IO_WHAT_FD,
+ NULL));
/* child -- set up input & exec mailer */
- (void) setsignal(SIGALRM, sm_signal_noop);
- (void) setsignal(SIGCHLD, SIG_DFL);
- (void) setsignal(SIGHUP, SIG_IGN);
- (void) setsignal(SIGINT, SIG_IGN);
- (void) setsignal(SIGTERM, SIG_DFL);
+ (void) sm_signal(SIGALRM, sm_signal_noop);
+ (void) sm_signal(SIGCHLD, SIG_DFL);
+ (void) sm_signal(SIGHUP, SIG_IGN);
+ (void) sm_signal(SIGINT, SIG_IGN);
+ (void) sm_signal(SIGTERM, SIG_DFL);
# ifdef SIGUSR1
- (void) setsignal(SIGUSR1, sm_signal_noop);
+ (void) sm_signal(SIGUSR1, sm_signal_noop);
# endif /* SIGUSR1 */
if (m != FileMailer || stat(tochain->q_user, &stb) < 0)
@@ -1966,14 +2343,16 @@ tryhost:
pwd = sm_getpwnam(contextaddr->q_user);
if (pwd != NULL)
(void) setusercontext(NULL,
- pwd, pwd->pw_uid,
- LOGIN_SETRESOURCES|LOGIN_SETPRIORITY);
+ pwd, pwd->pw_uid,
+ LOGIN_SETRESOURCES|LOGIN_SETPRIORITY);
}
# endif /* HASSETUSERCONTEXT */
+#if HASNICE
/* tweak niceness */
if (m->m_nice != 0)
(void) nice(m->m_nice);
+#endif /* HASNICE */
/* reset group id */
if (bitnset(M_SPECIFIC_UID, m->m_flags))
@@ -1984,15 +2363,16 @@ tryhost:
{
if (!DontInitGroups)
{
- char *u = ctladdr->q_ruser;
-
- if (u == NULL)
- u = ctladdr->q_user;
+ user = ctladdr->q_ruser;
+ if (user == NULL)
+ user = ctladdr->q_user;
- if (initgroups(u, ctladdr->q_gid) == -1 && suidwarn)
+ if (initgroups(user,
+ ctladdr->q_gid) == -1
+ && suidwarn)
{
syserr("openmailer: initgroups(%s, %d) failed",
- u, ctladdr->q_gid);
+ user, ctladdr->q_gid);
exit(EX_TEMPFAIL);
}
}
@@ -2001,7 +2381,8 @@ tryhost:
GIDSET_T gidset[1];
gidset[0] = ctladdr->q_gid;
- if (setgroups(1, gidset) == -1 && suidwarn)
+ if (setgroups(1, gidset) == -1
+ && suidwarn)
{
syserr("openmailer: setgroups() failed");
exit(EX_TEMPFAIL);
@@ -2013,10 +2394,12 @@ tryhost:
{
if (!DontInitGroups)
{
- if (initgroups(DefUser, DefGid) == -1 && suidwarn)
+ user = DefUser;
+ if (initgroups(DefUser, DefGid) == -1 &&
+ suidwarn)
{
syserr("openmailer: initgroups(%s, %d) failed",
- DefUser, DefGid);
+ DefUser, DefGid);
exit(EX_TEMPFAIL);
}
}
@@ -2025,7 +2408,8 @@ tryhost:
GIDSET_T gidset[1];
gidset[0] = DefGid;
- if (setgroups(1, gidset) == -1 && suidwarn)
+ if (setgroups(1, gidset) == -1
+ && suidwarn)
{
syserr("openmailer: setgroups() failed");
exit(EX_TEMPFAIL);
@@ -2044,7 +2428,9 @@ tryhost:
new_gid != getegid())
{
/* Only root can change the gid */
- syserr("openmailer: insufficient privileges to change gid");
+ syserr("openmailer: insufficient privileges to change gid, RunAsUid=%d, new_gid=%d, gid=%d, egid=%d",
+ (int) RunAsUid, (int) new_gid,
+ (int) getgid(), (int) getegid());
exit(EX_TEMPFAIL);
}
@@ -2061,12 +2447,12 @@ tryhost:
{
expand(m->m_rootdir, buf, sizeof buf, e);
if (tTd(11, 20))
- dprintf("openmailer: chroot %s\n",
- buf);
+ sm_dprintf("openmailer: chroot %s\n",
+ buf);
if (chroot(buf) < 0)
{
syserr("openmailer: Cannot chroot(%s)",
- buf);
+ buf);
exit(EX_TEMPFAIL);
}
if (chdir("/") < 0)
@@ -2078,6 +2464,7 @@ tryhost:
/* reset user id */
endpwent();
+ sm_mbdb_terminate();
if (bitnset(M_SPECIFIC_UID, m->m_flags))
{
new_euid = m->m_uid;
@@ -2090,7 +2477,21 @@ tryhost:
*/
if (RealUid != 0 && RealUid != getuid())
+ {
+# if MAILER_SETUID_METHOD == USE_SETEUID
+# if HASSETREUID
+ if (setreuid(RealUid, geteuid()) < 0)
+ {
+ syserr("openmailer: setreuid(%d, %d) failed",
+ (int) RealUid, (int) geteuid());
+ exit(EX_OSERR);
+ }
+# endif /* HASSETREUID */
+# endif /* MAILER_SETUID_METHOD == USE_SETEUID */
+# if MAILER_SETUID_METHOD == USE_SETREUID
new_ruid = RealUid;
+# endif /* MAILER_SETUID_METHOD == USE_SETREUID */
+ }
}
else if (bitset(S_ISUID, stb.st_mode))
new_ruid = stb.st_uid;
@@ -2105,32 +2506,17 @@ tryhost:
if (RunAsUid != 0 && new_euid != RunAsUid)
{
/* Only root can change the uid */
- syserr("openmailer: insufficient privileges to change uid");
+ syserr("openmailer: insufficient privileges to change uid, new_euid=%d, RunAsUid=%d",
+ (int) new_euid, (int) RunAsUid);
exit(EX_TEMPFAIL);
}
vendor_set_uid(new_euid);
# if MAILER_SETUID_METHOD == USE_SETEUID
-# if HASSETREUID
- /*
- ** Undo the effects of the uid change in main
- ** for signal handling. The real uid may
- ** be used by mailer in adding a "From "
- ** line.
- */
-
- if (new_ruid != NO_UID &&
- setreuid(RealUid, geteuid()) < 0)
- {
- syserr("openmailer: setreuid(%d, %d) failed",
- (int) new_ruid, (int) geteuid());
- exit(EX_OSERR);
- }
-# endif /* HASSETREUID */
if (seteuid(new_euid) < 0 && suidwarn)
{
syserr("openmailer: seteuid(%ld) failed",
- (long) new_euid);
+ (long) new_euid);
exit(EX_TEMPFAIL);
}
# endif /* MAILER_SETUID_METHOD == USE_SETEUID */
@@ -2138,7 +2524,7 @@ tryhost:
if (setreuid(new_ruid, new_euid) < 0 && suidwarn)
{
syserr("openmailer: setreuid(%ld, %ld) failed",
- (long) new_ruid, (long) new_euid);
+ (long) new_ruid, (long) new_euid);
exit(EX_TEMPFAIL);
}
# endif /* MAILER_SETUID_METHOD == USE_SETREUID */
@@ -2146,7 +2532,7 @@ tryhost:
if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn)
{
syserr("openmailer: setuid(%ld) failed",
- (long) new_euid);
+ (long) new_euid);
exit(EX_TEMPFAIL);
}
# endif /* MAILER_SETUID_METHOD == USE_SETUID */
@@ -2157,15 +2543,15 @@ tryhost:
if (setuid(new_ruid) < 0 && suidwarn)
{
syserr("openmailer: setuid(%ld) failed",
- (long) new_ruid);
+ (long) new_ruid);
exit(EX_TEMPFAIL);
}
}
if (tTd(11, 2))
- dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n",
- (int) getuid(), (int) geteuid(),
- (int) getgid(), (int) getegid());
+ sm_dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n",
+ (int) getuid(), (int) geteuid(),
+ (int) getgid(), (int) getegid());
/* move into some "safe" directory */
if (m->m_execdir != NULL)
@@ -2181,13 +2567,30 @@ tryhost:
if (q != NULL)
*q++ = ':';
if (tTd(11, 20))
- dprintf("openmailer: trydir %s\n",
- buf);
+ sm_dprintf("openmailer: trydir %s\n",
+ buf);
if (buf[0] != '\0' && chdir(buf) >= 0)
break;
}
}
+ /* Check safety of program to be run */
+ sff = SFF_ROOTOK|SFF_EXECOK;
+ if (!bitnset(DBS_RUNWRITABLEPROGRAM,
+ DontBlameSendmail))
+ sff |= SFF_NOGWFILES|SFF_NOWWFILES;
+ if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH,
+ DontBlameSendmail))
+ sff |= SFF_NOPATHCHECK;
+ else
+ sff |= SFF_SAFEDIRPATH;
+ ret = safefile(m->m_mailer, getuid(), getgid(),
+ user, sff, 0, NULL);
+ if (ret != 0)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Warning: program %s unsafe: %s",
+ m->m_mailer, sm_errstring(ret));
+
/* arrange to filter std & diag output of command */
(void) close(rpvect[0]);
if (dup2(rpvect[1], STDOUT_FILENO) < 0)
@@ -2202,8 +2605,8 @@ tryhost:
if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
{
syserr("%s... openmailer(%s): cannot dup stdout for stderr",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name);
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name);
_exit(EX_OSERR);
}
@@ -2212,8 +2615,8 @@ tryhost:
if (dup2(mpvect[0], STDIN_FILENO) < 0)
{
syserr("%s... openmailer(%s): cannot dup pipe %d for stdin",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name, mpvect[0]);
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name, mpvect[0]);
_exit(EX_OSERR);
}
(void) close(mpvect[0]);
@@ -2248,8 +2651,25 @@ tryhost:
if (mci == NULL)
{
- mci = (MCI *) xalloc(sizeof *mci);
- memset((char *) mci, '\0', sizeof *mci);
+ if (clever)
+ {
+ /*
+ ** Allocate from general heap, not
+ ** envelope rpool, because this mci
+ ** is going to be cached.
+ */
+
+ mci = mci_new(NULL);
+ }
+ else
+ {
+ /*
+ ** Prevent a storage leak by allocating
+ ** this from the envelope rpool.
+ */
+
+ mci = mci_new(e->e_rpool);
+ }
}
mci->mci_mailer = m;
if (clever)
@@ -2263,11 +2683,13 @@ tryhost:
}
mci->mci_pid = pid;
(void) close(mpvect[0]);
- mci->mci_out = fdopen(mpvect[1], "w");
+ mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &(mpvect[1]), SM_IO_WRONLY,
+ NULL);
if (mci->mci_out == NULL)
{
syserr("deliver: cannot create mailer output channel, fd=%d",
- mpvect[1]);
+ mpvect[1]);
(void) close(mpvect[1]);
(void) close(rpvect[0]);
(void) close(rpvect[1]);
@@ -2276,21 +2698,19 @@ tryhost:
}
(void) close(rpvect[1]);
- mci->mci_in = fdopen(rpvect[0], "r");
+ mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &(rpvect[0]), SM_IO_RDONLY,
+ NULL);
if (mci->mci_in == NULL)
{
syserr("deliver: cannot create mailer input channel, fd=%d",
mpvect[1]);
(void) close(rpvect[0]);
- (void) fclose(mci->mci_out);
+ (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
mci->mci_out = NULL;
rcode = EX_OSERR;
goto give_up;
}
-
- /* Don't cache non-clever connections */
- if (!clever)
- mci->mci_flags |= MCIF_TEMP;
}
/*
@@ -2300,12 +2720,17 @@ tryhost:
if (bitnset(M_7BITS, m->m_flags) &&
(!clever || mci->mci_state == MCIS_OPENING))
mci->mci_flags |= MCIF_7BIT;
-#if SMTP
if (clever && mci->mci_state != MCIS_CLOSED)
{
-# if SASL && SFIO
+# if STARTTLS || SASL
+ int dotpos;
+ char *srvname;
+ extern SOCKADDR CurHostAddr;
+# endif /* STARTTLS || SASL */
+
+# if SASL
# define DONE_AUTH(f) bitset(MCIF_AUTHACT, f)
-# endif /* SASL && SFIO */
+# endif /* SASL */
# if STARTTLS
# define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f)
# endif /* STARTTLS */
@@ -2313,97 +2738,130 @@ tryhost:
# define SET_HELO(f) f |= MCIF_ONLY_EHLO
# define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO
+# if STARTTLS || SASL
+ /* don't use CurHostName, it is changed in many places */
+ if (mci->mci_host != NULL)
+ {
+ srvname = mci->mci_host;
+ dotpos = strlen(srvname) - 1;
+ if (dotpos >= 0)
+ {
+ if (srvname[dotpos] == '.')
+ srvname[dotpos] = '\0';
+ else
+ dotpos = -1;
+ }
+ }
+ else if (mci->mci_mailer != NULL)
+ {
+ srvname = mci->mci_mailer->m_name;
+ dotpos = -1;
+ }
+ else
+ {
+ srvname = "local";
+ dotpos = -1;
+ }
+
+ /* don't set {server_name} to NULL or "": see getauth() */
+ macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"),
+ srvname);
+
+ /* CurHostAddr is set by makeconnection() and mci_get() */
+ if (CurHostAddr.sa.sa_family != 0)
+ {
+ macdefine(&mci->mci_macro, A_TEMP,
+ macid("{server_addr}"),
+ anynet_ntoa(&CurHostAddr));
+ }
+ else if (mci->mci_mailer != NULL)
+ {
+ /* mailer name is unique, use it as address */
+ macdefine(&mci->mci_macro, A_PERM,
+ macid("{server_addr}"),
+ mci->mci_mailer->m_name);
+ }
+ else
+ {
+ /* don't set it to NULL or "": see getauth() */
+ macdefine(&mci->mci_macro, A_PERM,
+ macid("{server_addr}"), "0");
+ }
-# if STARTTLS || (SASL && SFIO)
-reconnect: /* after switching to an authenticated connection */
-# endif /* STARTTLS || (SASL && SFIO) */
+ /* undo change of srvname (mci->mci_host) */
+ if (dotpos >= 0)
+ srvname[dotpos] = '.';
+reconnect: /* after switching to an encrypted connection */
+# endif /* STARTTLS || SASL */
+
+ /* set the current connection information */
+ e->e_mci = mci;
# if SASL
mci->mci_saslcap = NULL;
# endif /* SASL */
smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags));
CLR_HELO(mci->mci_flags);
+ if (IS_DLVR_RETURN(e))
+ {
+ /*
+ ** Check whether other side can deliver e-mail
+ ** fast enough
+ */
+
+ if (!bitset(MCIF_DLVR_BY, mci->mci_flags))
+ {
+ e->e_status = "5.4.7";
+ usrerrenh(e->e_status,
+ "554 Server does not support Deliver By");
+ rcode = EX_UNAVAILABLE;
+ goto give_up;
+ }
+ if (e->e_deliver_by > 0 &&
+ e->e_deliver_by - (curtime() - e->e_ctime) <
+ mci->mci_min_by)
+ {
+ e->e_status = "5.4.7";
+ usrerrenh(e->e_status,
+ "554 Message can't be delivered in time; %ld < %ld",
+ e->e_deliver_by - (curtime() - e->e_ctime),
+ mci->mci_min_by);
+ rcode = EX_UNAVAILABLE;
+ goto give_up;
+ }
+ }
+
# if STARTTLS
/* first TLS then AUTH to provide a security layer */
if (mci->mci_state != MCIS_CLOSED &&
!DONE_STARTTLS(mci->mci_flags))
{
int olderrors;
- int dotpos;
bool usetls;
bool saveQuickAbort = QuickAbort;
bool saveSuprErrs = SuprErrs;
char *host = NULL;
-# if _FFR_TLS_CLT1
- char *p;
-# endif /* _FFR_TLS_CLT1 */
- char *srvname;
- extern SOCKADDR CurHostAddr;
rcode = EX_OK;
usetls = bitset(MCIF_TLS, mci->mci_flags);
-# if _FFR_TLS_CLT1
- if (usetls &&
- (p = macvalue(macid("{client_flags}", NULL), e))
- != NULL)
- {
- for (; *p != '\0'; p++)
- {
- /* look for just this one flag */
- if (*p == D_CLTNOTLS)
- {
- usetls = FALSE;
- break;
- }
- }
- }
-# endif /* _FFR_TLS_CLT1 */
+ if (usetls)
+ usetls = !iscltflgset(e, D_NOTLS);
- if (mci->mci_host != NULL)
- {
- srvname = mci->mci_host;
- dotpos = strlen(srvname) - 1;
- if (dotpos >= 0)
- {
- if (srvname[dotpos] == '.')
- srvname[dotpos] = '\0';
- else
- dotpos = -1;
- }
- }
- else
- {
- srvname = "";
- dotpos = -1;
- }
- define(macid("{server_name}", NULL),
- newstr(srvname), e);
- if (CurHostAddr.sa.sa_family != 0)
- define(macid("{server_addr}", NULL),
- newstr(anynet_ntoa(&CurHostAddr)), e);
- else
- define(macid("{server_addr}", NULL), NULL, e);
if (usetls)
{
- host = macvalue(macid("{server_name}", NULL),
- e);
-# if _FFR_TLS_O_T
+ host = macvalue(macid("{server_name}"), e);
olderrors = Errors;
- QuickAbort = FALSE;
- SuprErrs = TRUE;
- if (rscheck("try_tls", srvname, NULL,
- e, TRUE, FALSE, 8, host) != EX_OK
+ QuickAbort = false;
+ SuprErrs = true;
+ if (rscheck("try_tls", host, NULL, e, true,
+ false, 7, host, NOQID) != EX_OK
|| Errors > olderrors)
- usetls = FALSE;
+ usetls = false;
SuprErrs = saveSuprErrs;
QuickAbort = saveQuickAbort;
-# endif /* _FFR_TLS_O_T */
}
- /* undo change of srvname */
- if (dotpos >= 0)
- srvname[dotpos] = '.';
if (usetls)
{
if ((rcode = starttls(m, mci, e)) == EX_OK)
@@ -2421,6 +2879,7 @@ reconnect: /* after switching to an authenticated connection */
** or abort? How to decide?
** set a macro and call a ruleset.
*/
+
mci->mci_flags &= ~MCIF_TLS;
switch (rcode)
{
@@ -2442,21 +2901,16 @@ reconnect: /* after switching to an authenticated connection */
s = "FAILURE";
rcode = EX_TEMPFAIL;
}
- define(macid("{verify}", NULL),
- newstr(s), e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{verify}"), s);
}
}
- else if (mci->mci_ssl != NULL)
- {
- /* active TLS connection, use that data */
- (void) tls_get_info(mci->mci_ssl, e, FALSE,
- mci->mci_host, FALSE);
- }
else
- define(macid("{verify}", NULL), "NONE", e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{verify}"), "NONE");
olderrors = Errors;
- QuickAbort = FALSE;
- SuprErrs = TRUE;
+ QuickAbort = false;
+ SuprErrs = true;
/*
** rcode == EX_SOFTWARE is special:
@@ -2466,9 +2920,11 @@ reconnect: /* after switching to an authenticated connection */
** to log the problem and return an appropriate
** error code.
*/
+
if (rscheck("tls_server",
- macvalue(macid("{verify}", NULL), e),
- NULL, e, TRUE, TRUE, 6, host) != EX_OK ||
+ macvalue(macid("{verify}"), e),
+ NULL, e, true, true, 5, host,
+ NOQID) != EX_OK ||
Errors > olderrors ||
rcode == EX_SOFTWARE)
{
@@ -2478,13 +2934,14 @@ reconnect: /* after switching to an authenticated connection */
if (ISSMTPCODE(MsgBuf) &&
extenhsc(MsgBuf + 4, ' ', enhsc) > 0)
{
- p = newstr(MsgBuf);
+ p = sm_rpool_strdup_x(e->e_rpool,
+ MsgBuf);
}
else
{
p = "403 4.7.0 server not authenticated.";
- (void) strlcpy(enhsc, "4.7.0",
- sizeof enhsc);
+ (void) sm_strlcpy(enhsc, "4.7.0",
+ sizeof enhsc);
}
SuprErrs = saveSuprErrs;
QuickAbort = saveQuickAbort;
@@ -2495,7 +2952,8 @@ reconnect: /* after switching to an authenticated connection */
mci->mci_state = MCIS_QUITING;
if (mci->mci_in != NULL)
{
- (void) fclose(mci->mci_in);
+ (void) sm_io_close(mci->mci_in,
+ SM_TIME_DEFAULT);
mci->mci_in = NULL;
}
mci->mci_flags &= ~MCIF_TLSACT;
@@ -2513,13 +2971,15 @@ reconnect: /* after switching to an authenticated connection */
/* temp or permanent failure? */
rcode = (*p == '4') ? EX_TEMPFAIL
: EX_UNAVAILABLE;
- mci_setstat(mci, rcode, newstr(enhsc), p);
+ mci_setstat(mci, rcode, enhsc, p);
/*
** hack to get the error message into
** the envelope (done in giveresponse())
*/
- (void) strlcpy(SmtpError, p, sizeof SmtpError);
+
+ (void) sm_strlcpy(SmtpError, p,
+ sizeof SmtpError);
}
QuickAbort = saveQuickAbort;
SuprErrs = saveSuprErrs;
@@ -2531,79 +2991,85 @@ reconnect: /* after switching to an authenticated connection */
goto reconnect;
}
}
- else if (mci->mci_ssl != NULL)
- {
- /* active TLS connection, use that data */
- (void) tls_get_info(mci->mci_ssl, e, FALSE,
- mci->mci_host, FALSE);
- }
# endif /* STARTTLS */
# if SASL
/* if other server supports authentication let's authenticate */
if (mci->mci_state != MCIS_CLOSED &&
mci->mci_saslcap != NULL &&
-# if SFIO
- !DONE_AUTH(mci->mci_flags) &&
-# endif /* SFIO */
- SASLInfo != NULL)
+ !DONE_AUTH(mci->mci_flags) && !iscltflgset(e, D_NOAUTH))
{
- /*
- ** should we require some minimum authentication?
- ** XXX ignore result?
- */
- if (smtpauth(m, mci, e) == EX_OK)
+ /* Should we require some minimum authentication? */
+ if ((ret = smtpauth(m, mci, e)) == EX_OK)
{
-# if SFIO
int result;
- sasl_ssf_t *ssf;
+ sasl_ssf_t *ssf = NULL;
- /* get security strength (features) */
+ /* Get security strength (features) */
result = sasl_getprop(mci->mci_conn, SASL_SSF,
(void **) &ssf);
+
+ /* XXX authid? */
if (LogLevel > 9)
sm_syslog(LOG_INFO, NOQID,
- "SASL: outgoing connection to %.64s: mech=%.16s, bits=%d",
+ "AUTH=client, relay=%.100s, mech=%.16s, bits=%d",
mci->mci_host,
- macvalue(macid("{auth_type}",
- NULL), e),
- result == SASL_OK ? *ssf
- : 0);
+ macvalue(macid("{auth_type}"), e),
+ result == SASL_OK ? *ssf : 0);
/*
- ** only switch to encrypted connection
+ ** Only switch to encrypted connection
** if a security layer has been negotiated
*/
+
if (result == SASL_OK && *ssf > 0)
{
/*
- ** convert sfio stuff to use SASL
- ** check return values
- ** if the call fails,
- ** fall back to unencrypted version
- ** unless some cf option requires
- ** encryption then the connection must
- ** be aborted
+ ** Convert I/O layer to use SASL.
+ ** If the call fails, the connection
+ ** is aborted.
*/
- if (sfdcsasl(mci->mci_in, mci->mci_out,
+
+ if (sfdcsasl(&mci->mci_in,
+ &mci->mci_out,
mci->mci_conn) == 0)
{
- SET_HELO(mci->mci_flags);
mci->mci_flags &= ~MCIF_EXTENS;
- mci->mci_flags |= MCIF_AUTHACT;
+ mci->mci_flags |= MCIF_AUTHACT|
+ MCIF_ONLY_EHLO;
goto reconnect;
}
- syserr("SASL TLS switch failed in client");
+ syserr("AUTH TLS switch failed in client");
}
/* else? XXX */
-# endif /* SFIO */
mci->mci_flags |= MCIF_AUTHACT;
}
+ else if (ret == EX_TEMPFAIL)
+ {
+ if (LogLevel > 8)
+ sm_syslog(LOG_ERR, NOQID,
+ "AUTH=client, relay=%.100s, temporary failure, connection abort",
+ mci->mci_host);
+ smtpquit(m, mci, e);
+
+ /* avoid bogus error msg */
+ mci->mci_errno = 0;
+ rcode = EX_TEMPFAIL;
+ mci_setstat(mci, rcode, "4.7.1", p);
+
+ /*
+ ** hack to get the error message into
+ ** the envelope (done in giveresponse())
+ */
+
+ (void) sm_strlcpy(SmtpError,
+ "Temporary AUTH failure",
+ sizeof SmtpError);
+ }
}
# endif /* SASL */
}
-#endif /* SMTP */
do_transfer:
/* clear out per-message flags from connection structure */
@@ -2618,13 +3084,13 @@ do_transfer:
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) &&
+ (sm_strcasecmp(p, "quoted-printable") == 0 ||
+ sm_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 &&
+ if (sm_strncasecmp(p, "text/plain", 10) == 0 &&
(p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
mci->mci_flags |= MCIF_CVT7TO8;
}
@@ -2632,34 +3098,61 @@ do_transfer:
if (tTd(11, 1))
{
- dprintf("openmailer: ");
- mci_dump(mci, FALSE);
+ sm_dprintf("openmailer: ");
+ mci_dump(mci, false);
}
+#if _FFR_CLIENT_SIZE
+ /*
+ ** See if we know the maximum size and
+ ** abort if the message is too big.
+ **
+ ** NOTE: _FFR_CLIENT_SIZE is untested.
+ */
+
+ if (bitset(MCIF_SIZE, mci->mci_flags) &&
+ mci->mci_maxsize > 0 &&
+ e->e_msgsize > mci->mci_maxsize)
+ {
+ e->e_flags |= EF_NO_BODY_RETN;
+ if (bitnset(M_LOCALMAILER, m->m_flags))
+ e->e_status = "5.2.3";
+ else
+ e->e_status = "5.3.4";
+
+ usrerrenh(e->e_status,
+ "552 Message is too large; %ld bytes max",
+ mci->mci_maxsize);
+ rcode = EX_DATAERR;
+
+ /* Need an e_message for error */
+ (void) sm_snprintf(SmtpError, sizeof SmtpError,
+ "Message is too large; %ld bytes max",
+ mci->mci_maxsize);
+ goto give_up;
+ }
+#endif /* _FFR_CLIENT_SIZE */
+
if (mci->mci_state != MCIS_OPEN)
{
/* couldn't open the mailer */
rcode = mci->mci_exitstat;
errno = mci->mci_errno;
-#if NAMED_BIND
SM_SET_H_ERRNO(mci->mci_herrno);
-#endif /* NAMED_BIND */
if (rcode == EX_OK)
{
/* shouldn't happen */
syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s",
- (u_long) mci, rcode, errno, mci->mci_state,
- firstsig);
- mci_dump_all(TRUE);
+ (unsigned long) mci, rcode, errno,
+ mci->mci_state, firstsig);
+ mci_dump_all(true);
rcode = EX_SOFTWARE;
}
-#if DAEMON
else if (nummxhosts > hostnum)
{
/* try next MX site */
goto tryhost;
}
-#endif /* DAEMON */
}
else if (!clever)
{
@@ -2673,80 +3166,106 @@ do_transfer:
/* get the exit status */
rcode = endmailer(mci, e, pv);
- if (rcode == EX_TEMPFAIL &&
- SmtpError[0] == '\0')
+ if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0')
{
/*
** Need an e_message for mailq display.
** We set SmtpError as
*/
- snprintf(SmtpError, sizeof SmtpError,
- "%s mailer (%s) exited with EX_TEMPFAIL",
- m->m_name, m->m_mailer);
+ (void) sm_snprintf(SmtpError, sizeof SmtpError,
+ "%s mailer (%s) exited with EX_TEMPFAIL",
+ m->m_name, m->m_mailer);
}
}
else
-#if SMTP
{
/*
** Send the MAIL FROM: protocol
*/
+ /* XXX this isn't pipelined... */
rcode = smtpmailfrom(m, mci, e);
if (rcode == EX_OK)
{
- register char *t = tobuf;
register int i;
+# if PIPELINING
+ ADDRESS *volatile pchain;
+# endif /* PIPELINING */
/* send the recipient list */
tobuf[0] = '\0';
+ mci->mci_retryrcpt = false;
+ mci->mci_tolist = tobuf;
+# if PIPELINING
+ pchain = NULL;
+ mci->mci_nextaddr = NULL;
+# endif /* PIPELINING */
for (to = tochain; to != NULL; to = to->q_tchain)
{
- e->e_to = to->q_paddr;
-#if !_FFR_DYNAMIC_TOBUF
- if (strlen(to->q_paddr) +
- (t - tobuf) + 2 > sizeof tobuf)
- {
- /* not enough room */
+ if (!QS_IS_UNMARKED(to->q_state))
continue;
- }
-#endif /* !_FFR_DYNAMIC_TOBUF */
+ /* mark recipient state as "ok so far" */
+ to->q_state = QS_OK;
+ e->e_to = to->q_paddr;
# if STARTTLS
-# if _FFR_TLS_RCPT
i = rscheck("tls_rcpt", to->q_user, NULL, e,
- TRUE, TRUE, 4, mci->mci_host);
+ true, true, 3, mci->mci_host,
+ e->e_id);
if (i != EX_OK)
{
- /* avoid bogus error msg */
- errno = 0;
- markfailure(e, to, mci, i, FALSE);
- giveresponse(i, to->q_status, m,
- mci, ctladdr, xstart, e);
+ markfailure(e, to, mci, i, false);
+ giveresponse(i, to->q_status, m, mci,
+ ctladdr, xstart, e, to);
+ if (i == EX_TEMPFAIL)
+ {
+ mci->mci_retryrcpt = true;
+ to->q_state = QS_RETRY;
+ }
continue;
}
-# endif /* _FFR_TLS_RCPT */
# endif /* STARTTLS */
- if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
+ i = smtprcpt(to, m, mci, e, ctladdr, xstart);
+# if PIPELINING
+ if (i == EX_OK &&
+ bitset(MCIF_PIPELINED, mci->mci_flags))
{
- markfailure(e, to, mci, i, FALSE);
- giveresponse(i, to->q_status, m,
- mci, ctladdr, xstart, e);
+ /*
+ ** Add new element to list of
+ ** recipients for pipelining.
+ */
+
+ to->q_pchain = NULL;
+ if (mci->mci_nextaddr == NULL)
+ mci->mci_nextaddr = to;
+ if (pchain == NULL)
+ pchain = to;
+ else
+ {
+ pchain->q_pchain = to;
+ pchain = pchain->q_pchain;
+ }
}
- else
+# endif /* PIPELINING */
+ if (i != EX_OK)
{
- *t++ = ',';
- for (p = to->q_paddr; *p; *t++ = *p++)
- continue;
- *t = '\0';
+ markfailure(e, to, mci, i, false);
+ giveresponse(i, to->q_status, m, mci,
+ ctladdr, xstart, e, to);
+ if (i == EX_TEMPFAIL)
+ to->q_state = QS_RETRY;
}
}
- /* now send the data */
- if (tobuf[0] == '\0')
+ /* No recipients in list and no missing responses? */
+ if (tobuf[0] == '\0'
+# if PIPELINING
+ && mci->mci_nextaddr == NULL
+# endif /* PIPELINING */
+ )
{
rcode = EX_OK;
e->e_to = NULL;
@@ -2756,24 +3275,15 @@ do_transfer:
else
{
e->e_to = tobuf + 1;
- rcode = smtpdata(m, mci, e);
+ rcode = smtpdata(m, mci, e, ctladdr, xstart);
}
}
-# if DAEMON
if (rcode == EX_TEMPFAIL && nummxhosts > hostnum)
{
/* try next MX site */
goto tryhost;
}
-# endif /* DAEMON */
- }
-#else /* SMTP */
- {
- syserr("554 5.3.5 deliver: need SMTP compiled to use clever mailer");
- rcode = EX_CONFIG;
- goto give_up;
}
-#endif /* SMTP */
#if NAMED_BIND
if (ConfigLevel < 2)
_res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */
@@ -2790,15 +3300,14 @@ do_transfer:
*/
give_up:
-#if SMTP
if (bitnset(M_LMTP, m->m_flags))
{
lmtp_rcode = rcode;
tobuf[0] = '\0';
- anyok = FALSE;
+ anyok = false;
+ strsize = 0;
}
else
-#endif /* SMTP */
anyok = rcode == EX_OK;
for (to = tochain; to != NULL; to = to->q_tchain)
@@ -2807,7 +3316,6 @@ do_transfer:
if (!QS_IS_OK(to->q_state))
continue;
-#if SMTP
/* if running LMTP, get the status for each address */
if (bitnset(M_LMTP, m->m_flags))
{
@@ -2815,44 +3323,30 @@ do_transfer:
rcode = smtpgetstat(m, mci, e);
if (rcode == EX_OK)
{
-#if _FFR_DYNAMIC_TOBUF
- (void) strlcat(tobuf, ",", tobufsize);
- (void) strlcat(tobuf, to->q_paddr, tobufsize);
-#else /* _FFR_DYNAMIC_TOBUF */
- if (strlen(to->q_paddr) +
- strlen(tobuf) + 2 > sizeof tobuf)
- {
- syserr("LMTP tobuf overflow");
- }
- else
- {
- (void) strlcat(tobuf, ",",
- sizeof tobuf);
- (void) strlcat(tobuf, to->q_paddr,
- sizeof tobuf);
- }
-#endif /* _FFR_DYNAMIC_TOBUF */
- anyok = TRUE;
+ strsize += sm_strlcat2(tobuf + strsize, ",",
+ to->q_paddr,
+ tobufsize - strsize);
+ SM_ASSERT(strsize < tobufsize);
+ anyok = true;
}
else
{
e->e_to = to->q_paddr;
- markfailure(e, to, mci, rcode, TRUE);
+ markfailure(e, to, mci, rcode, true);
giveresponse(rcode, to->q_status, m, mci,
- ctladdr, xstart, e);
+ ctladdr, xstart, e, to);
e->e_to = tobuf + 1;
continue;
}
}
else
-#endif /* SMTP */
{
/* mark bad addresses */
if (rcode != EX_OK)
{
if (goodmxfound && rcode == EX_NOHOST)
rcode = EX_TEMPFAIL;
- markfailure(e, to, mci, rcode, TRUE);
+ markfailure(e, to, mci, rcode, true);
continue;
}
}
@@ -2862,37 +3356,63 @@ do_transfer:
to->q_statdate = curtime();
e->e_nsent++;
-#if QUEUE
/*
** Checkpoint the send list every few addresses
*/
if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval)
{
- queueup(e, FALSE);
+ queueup(e, false, false);
e->e_nsent = 0;
}
-#endif /* QUEUE */
if (bitnset(M_LOCALMAILER, m->m_flags) &&
bitset(QPINGONSUCCESS, to->q_flags))
{
to->q_flags |= QDELIVERED;
to->q_status = "2.1.5";
- fprintf(e->e_xfp, "%s... Successfully delivered\n",
- to->q_paddr);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... Successfully delivered\n",
+ to->q_paddr);
}
else if (bitset(QPINGONSUCCESS, to->q_flags) &&
bitset(QPRIMARY, to->q_flags) &&
!bitset(MCIF_DSN, mci->mci_flags))
{
to->q_flags |= QRELAYED;
- fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n",
- to->q_paddr);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... relayed; expect no further notifications\n",
+ to->q_paddr);
+ }
+ else if (IS_DLVR_NOTIFY(e) &&
+ !bitset(MCIF_DLVR_BY, mci->mci_flags) &&
+ bitset(QPRIMARY, to->q_flags) &&
+ (!bitset(QHASNOTIFY, to->q_flags) ||
+ bitset(QPINGONSUCCESS, to->q_flags) ||
+ bitset(QPINGONFAILURE, to->q_flags) ||
+ bitset(QPINGONDELAY, to->q_flags)))
+ {
+ /* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */
+ to->q_flags |= QBYNRELAY;
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... Deliver-by notify: relayed\n",
+ to->q_paddr);
+ }
+ else if (IS_DLVR_TRACE(e) &&
+ (!bitset(QHASNOTIFY, to->q_flags) ||
+ bitset(QPINGONSUCCESS, to->q_flags) ||
+ bitset(QPINGONFAILURE, to->q_flags) ||
+ bitset(QPINGONDELAY, to->q_flags)) &&
+ bitset(QPRIMARY, to->q_flags))
+ {
+ /* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */
+ to->q_flags |= QBYTRACE;
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... Deliver-By trace: relayed\n",
+ to->q_paddr);
}
}
-#if SMTP
if (bitnset(M_LMTP, m->m_flags))
{
/*
@@ -2904,48 +3424,90 @@ do_transfer:
e->e_statmsg = NULL;
/* reset the mci state for the next transaction */
- if (mci != NULL && mci->mci_state == MCIS_ACTIVE)
+ if (mci != NULL &&
+ (mci->mci_state == MCIS_MAIL ||
+ mci->mci_state == MCIS_RCPT ||
+ mci->mci_state == MCIS_DATA))
mci->mci_state = MCIS_OPEN;
}
-#endif /* SMTP */
if (tobuf[0] != '\0')
- giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e);
+ {
+ giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, tochain);
+#if 0
+ /*
+ ** This code is disabled for now because I am not
+ ** sure that copying status from the first recipient
+ ** to all non-status'ed recipients is a good idea.
+ */
+
+ if (tochain->q_message != NULL &&
+ !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK)
+ {
+ for (to = tochain->q_tchain; to != NULL;
+ to = to->q_tchain)
+ {
+ /* see if address already marked */
+ if (QS_IS_QUEUEUP(to->q_state) &&
+ to->q_message == NULL)
+ to->q_message = sm_rpool_strdup_x(e->e_rpool,
+ tochain->q_message);
+ }
+ }
+#endif /* 0 */
+ }
if (anyok)
- markstats(e, tochain, FALSE);
+ markstats(e, tochain, STATS_NORMAL);
mci_store_persistent(mci);
-#if SMTP
+ /* Some recipients were tempfailed, try them on the next host */
+ if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum)
+ {
+ /* try next MX site */
+ goto tryhost;
+ }
+
/* now close the connection */
if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED &&
!bitset(MCIF_CACHED, mci->mci_flags))
smtpquit(m, mci, e);
-#endif /* SMTP */
-
- /*
- ** Restore state and return.
- */
-#if XDEBUG
+cleanup: ;
+ }
+ SM_FINALLY
{
+ /*
+ ** Restore state and return.
+ */
+#if XDEBUG
char wbuf[MAXLINE];
/* 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, MAXSHORTSTR),
- m->m_name);
+ (void) sm_snprintf(wbuf, sizeof wbuf,
+ "%s... end of deliver(%s)",
+ e->e_to == NULL ? "NO-TO-LIST"
+ : shortenstring(e->e_to,
+ MAXSHORTSTR),
+ m->m_name);
checkfd012(wbuf);
- }
#endif /* XDEBUG */
- errno = 0;
- define('g', (char *) NULL, e);
- e->e_to = NULL;
+ errno = 0;
+
+ /*
+ ** It was originally necessary to set macro 'g' to NULL
+ ** because it previously pointed to an auto buffer.
+ ** We don't do this any more, so this may be unnecessary.
+ */
+
+ macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL);
+ e->e_to = NULL;
+ }
+ SM_END_TRY
return rcode;
}
- /*
+/*
** MARKFAILURE -- mark a failure on a specific address.
**
** Parameters:
@@ -2964,7 +3526,7 @@ do_transfer:
** the message will be queued, as appropriate.
*/
-static void
+void
markfailure(e, q, mci, rcode, ovr)
register ENVELOPE *e;
register ADDRESS *q;
@@ -2972,6 +3534,7 @@ markfailure(e, q, mci, rcode, ovr)
int rcode;
bool ovr;
{
+ int save_errno = errno;
char *status = NULL;
char *rstatus = NULL;
@@ -2994,9 +3557,10 @@ markfailure(e, q, mci, rcode, ovr)
/* find most specific error code possible */
if (mci != NULL && mci->mci_status != NULL)
{
- status = mci->mci_status;
+ status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status);
if (mci->mci_rstatus != NULL)
- rstatus = newstr(mci->mci_rstatus);
+ rstatus = sm_rpool_strdup_x(e->e_rpool,
+ mci->mci_rstatus);
else
rstatus = NULL;
}
@@ -3059,20 +3623,23 @@ markfailure(e, q, mci, rcode, ovr)
}
if (rcode != EX_OK && q->q_rstatus == NULL &&
q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL &&
- strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0)
+ sm_strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0)
{
char buf[16];
- (void) snprintf(buf, sizeof buf, "%d", rcode);
- q->q_rstatus = newstr(buf);
+ (void) sm_snprintf(buf, sizeof buf, "%d", rcode);
+ q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf);
}
q->q_statdate = curtime();
if (CurHostName != NULL && CurHostName[0] != '\0' &&
mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags))
- q->q_statmta = newstr(CurHostName);
+ q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName);
+
+ /* restore errno */
+ errno = save_errno;
}
- /*
+/*
** ENDMAILER -- Wait for mailer to terminate.
**
** We should never get fatal errors (e.g., segmentation
@@ -3117,26 +3684,26 @@ endmailer(mci, e, pv)
int st;
int save_errno = errno;
char buf[MAXLINE];
- EVENT *ev = NULL;
+ SM_EVENT *ev = NULL;
mci_unlock_host(mci);
/* close output to mailer */
if (mci->mci_out != NULL)
- (void) fclose(mci->mci_out);
+ (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
/* copy any remaining input to transcript */
if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR &&
e->e_xfp != NULL)
{
while (sfgets(buf, sizeof buf, mci->mci_in,
- TimeOuts.to_quit, "Draining Input") != NULL)
- (void) fputs(buf, e->e_xfp);
+ TimeOuts.to_quit, "Draining Input") != NULL)
+ (void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf);
}
#if SASL
- /* shutdown SASL */
+ /* close SASL connection */
if (bitset(MCIF_AUTHACT, mci->mci_flags))
{
sasl_dispose(&mci->mci_conn);
@@ -3151,7 +3718,7 @@ endmailer(mci, e, pv)
/* now close the input */
if (mci->mci_in != NULL)
- (void) fclose(mci->mci_in);
+ (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT);
mci->mci_in = mci->mci_out = NULL;
mci->mci_state = MCIS_CLOSED;
@@ -3165,8 +3732,8 @@ endmailer(mci, e, pv)
if (mci->mci_mailer->m_wait > 0)
{
if (setjmp(EndWaitTimeout) == 0)
- ev = setevent(mci->mci_mailer->m_wait,
- endwaittimeout, 0);
+ ev = sm_setevent(mci->mci_mailer->m_wait,
+ endwaittimeout, 0);
else
{
syserr("endmailer %s: wait timeout (%ld)",
@@ -3180,7 +3747,7 @@ endmailer(mci, e, pv)
st = waitfor(mci->mci_pid);
save_errno = errno;
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
errno = save_errno;
if (st == -1)
@@ -3206,16 +3773,17 @@ endmailer(mci, e, pv)
{
register char **av;
- fprintf(e->e_xfp, "Arguments:");
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:");
for (av = pv; *av != NULL; av++)
- fprintf(e->e_xfp, " %s", *av);
- fprintf(e->e_xfp, "\n");
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s",
+ *av);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n");
}
ExitStat = EX_TEMPFAIL;
return EX_TEMPFAIL;
}
- /*
+/*
** GIVERESPONSE -- Interpret an error response from a mailer
**
** Parameters:
@@ -3231,6 +3799,7 @@ endmailer(mci, e, pv)
** xstart -- the transaction start time, for computing
** transaction delays.
** e -- the current envelope.
+** to -- the current recipient (NULL if none).
**
** Returns:
** none.
@@ -3241,7 +3810,7 @@ endmailer(mci, e, pv)
*/
void
-giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
+giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
int status;
char *dsn;
register MAILER *m;
@@ -3249,15 +3818,15 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
ADDRESS *ctladdr;
time_t xstart;
ENVELOPE *e;
+ ADDRESS *to;
{
register const char *statmsg;
- extern char *SysExMsg[];
- register int i;
int errnum = errno;
int off = 4;
- extern int N_SysEx;
+ bool usestat = false;
char dsnbuf[ENHSCLEN];
char buf[MAXLINE];
+ char *exmsg;
if (e == NULL)
syserr("giveresponse: null envelope");
@@ -3266,48 +3835,43 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
** Compute status message from code.
*/
- i = status - EX__BASE;
+ exmsg = sm_sysexmsg(status);
if (status == 0)
{
statmsg = "250 2.0.0 Sent";
if (e->e_statmsg != NULL)
{
- (void) snprintf(buf, sizeof buf, "%s (%s)",
- statmsg,
- shortenstring(e->e_statmsg, 403));
+ (void) sm_snprintf(buf, sizeof buf, "%s (%s)",
+ statmsg,
+ shortenstring(e->e_statmsg, 403));
statmsg = buf;
}
}
- else if (i < 0 || i >= N_SysEx)
+ else if (exmsg == NULL)
{
- (void) snprintf(buf, sizeof buf,
- "554 5.3.0 unknown mailer error %d",
- status);
+ (void) sm_snprintf(buf, sizeof buf,
+ "554 5.3.0 unknown mailer error %d",
+ status);
status = EX_UNAVAILABLE;
statmsg = buf;
+ usestat = true;
}
else if (status == EX_TEMPFAIL)
{
char *bp = buf;
- snprintf(bp, SPACELEFT(buf, bp), "%s", SysExMsg[i] + 1);
+ (void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp));
bp += strlen(bp);
#if NAMED_BIND
if (h_errno == TRY_AGAIN)
- statmsg = errstring(h_errno+E_DNSBASE);
+ statmsg = sm_errstring(h_errno + E_DNSBASE);
else
#endif /* NAMED_BIND */
{
if (errnum != 0)
- statmsg = errstring(errnum);
+ statmsg = sm_errstring(errnum);
else
- {
-#if SMTP
statmsg = SmtpError;
-#else /* SMTP */
- statmsg = NULL;
-#endif /* SMTP */
- }
}
if (statmsg != NULL && statmsg[0] != '\0')
{
@@ -3333,33 +3897,39 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
#endif /* EHOSTUNREACH */
if (mci->mci_host != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp),
- ": %s", mci->mci_host);
+ (void) sm_strlcpyn(bp,
+ SPACELEFT(buf, bp),
+ 2, ": ",
+ mci->mci_host);
bp += strlen(bp);
}
break;
}
- snprintf(bp, SPACELEFT(buf, bp), ": %s", statmsg);
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ",
+ statmsg);
+ usestat = true;
}
statmsg = buf;
}
#if NAMED_BIND
else if (status == EX_NOHOST && h_errno != 0)
{
- statmsg = errstring(h_errno + E_DNSBASE);
- (void) snprintf(buf, sizeof buf, "%s (%s)",
- SysExMsg[i] + 1, statmsg);
+ statmsg = sm_errstring(h_errno + E_DNSBASE);
+ (void) sm_snprintf(buf, sizeof buf, "%s (%s)", exmsg + 1,
+ statmsg);
statmsg = buf;
+ usestat = true;
}
#endif /* NAMED_BIND */
else
{
- statmsg = SysExMsg[i];
+ statmsg = exmsg;
if (*statmsg++ == ':' && errnum != 0)
{
- (void) snprintf(buf, sizeof buf, "%s: %s",
- statmsg, errstring(errnum));
+ (void) sm_snprintf(buf, sizeof buf, "%s: %s", statmsg,
+ sm_errstring(errnum));
statmsg = buf;
+ usestat = true;
}
}
@@ -3375,8 +3945,8 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
{
if (dsn == NULL)
{
- snprintf(dsnbuf, sizeof dsnbuf,
- "%.*s", off, statmsg + 4);
+ (void) sm_snprintf(dsnbuf, sizeof dsnbuf,
+ "%.*s", off, statmsg + 4);
dsn = dsnbuf;
}
off += 5;
@@ -3387,7 +3957,8 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
}
message("%s", statmsg + off);
if (status == EX_TEMPFAIL && e->e_xfp != NULL)
- fprintf(e->e_xfp, "%s\n", &MsgBuf[4]);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n",
+ &MsgBuf[4]);
}
else
{
@@ -3399,18 +3970,21 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
{
if (dsn == NULL)
{
- snprintf(dsnbuf, sizeof dsnbuf,
- "%.*s", off, statmsg + 4);
+ (void) sm_snprintf(dsnbuf, sizeof dsnbuf,
+ "%.*s", off, statmsg + 4);
dsn = dsnbuf;
}
off += 5;
- (void) strlcpy(mbuf, statmsg, off);
- (void) strlcat(mbuf, " %s", sizeof mbuf);
+
+ /* copy only part of statmsg to mbuf */
+ (void) sm_strlcpy(mbuf, statmsg, off);
+ (void) sm_strlcat(mbuf, " %s", sizeof mbuf);
}
else
{
dsnbuf[0] = '\0';
- (void) snprintf(mbuf, sizeof mbuf, "%.3s %%s", statmsg);
+ (void) sm_snprintf(mbuf, sizeof mbuf, "%.3s %%s",
+ statmsg);
off = 4;
}
usrerr(mbuf, &statmsg[off]);
@@ -3428,25 +4002,29 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e);
if (tTd(11, 2))
- dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s\n",
- status,
- dsn == NULL ? "<NULL>" : dsn,
- e->e_message == NULL ? "<NULL>" : e->e_message);
+ sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d\n",
+ status,
+ dsn == NULL ? "<NULL>" : dsn,
+ e->e_message == NULL ? "<NULL>" : e->e_message,
+ errnum);
if (status != EX_TEMPFAIL)
setstat(status);
if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL))
+ e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off);
+ if (status != EX_OK && to != NULL && to->q_message == NULL)
{
- if (e->e_message != NULL)
- sm_free(e->e_message);
- e->e_message = newstr(statmsg + off);
+ if (!usestat && e->e_message != NULL)
+ to->q_message = sm_rpool_strdup_x(e->e_rpool,
+ e->e_message);
+ else
+ to->q_message = sm_rpool_strdup_x(e->e_rpool,
+ statmsg + off);
}
errno = 0;
-#if NAMED_BIND
SM_SET_H_ERRNO(0);
-#endif /* NAMED_BIND */
}
- /*
+/*
** LOGDELIVERY -- log the delivery in the system log
**
** Care is taken to avoid logging lines that are too long, because
@@ -3484,7 +4062,7 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
register char *bp;
register char *p;
int l;
- time_t now;
+ time_t now = curtime();
char buf[1024];
#if (SYSLOG_BUFSIZE) >= 256
@@ -3492,68 +4070,74 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
bp = buf;
if (ctladdr != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp), ", ctladdr=%s",
- shortenstring(ctladdr->q_paddr, 83));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=",
+ shortenstring(ctladdr->q_paddr, 83));
bp += strlen(bp);
if (bitset(QGOODUID, ctladdr->q_flags))
{
- (void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
- (int) ctladdr->q_uid,
- (int) ctladdr->q_gid);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
+ (int) ctladdr->q_uid,
+ (int) ctladdr->q_gid);
bp += strlen(bp);
}
}
/* delay & xdelay: max 41 bytes */
- now = curtime();
- snprintf(bp, SPACELEFT(buf, bp), ", delay=%s",
- pintvl(now - e->e_ctime, TRUE));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=",
+ pintvl(now - e->e_ctime, true));
bp += strlen(bp);
if (xstart != (time_t) 0)
{
- snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s",
- pintvl(now - xstart, TRUE));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=",
+ pintvl(now - xstart, true));
bp += strlen(bp);
}
/* mailer: assume about 19 bytes (max 10 byte mailer name) */
if (m != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name);
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=",
+ m->m_name);
bp += strlen(bp);
}
/* pri: changes with each delivery attempt */
- snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", e->e_msgpriority);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld",
+ e->e_msgpriority);
bp += strlen(bp);
/* relay: max 66 bytes for IPv4 addresses */
if (mci != NULL && mci->mci_host != NULL)
{
-# if DAEMON
extern SOCKADDR CurHostAddr;
-# endif /* DAEMON */
- snprintf(bp, SPACELEFT(buf, bp), ", relay=%s",
- shortenstring(mci->mci_host, 40));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=",
+ shortenstring(mci->mci_host, 40));
bp += strlen(bp);
-# if DAEMON
if (CurHostAddr.sa.sa_family != 0)
{
- snprintf(bp, SPACELEFT(buf, bp), " [%s]",
- anynet_ntoa(&CurHostAddr));
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]",
+ anynet_ntoa(&CurHostAddr));
}
-# endif /* DAEMON */
}
+#if _FFR_QUARANTINE
+ else if (strcmp(status, "quarantined") == 0)
+ {
+ if (e->e_quarmsg != NULL)
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", quarantine=%s",
+ shortenstring(e->e_quarmsg, 40));
+ }
+#endif /* _FFR_QUARANTINE */
else if (strcmp(status, "queued") != 0)
{
p = macvalue('h', e);
if (p != NULL && p[0] != '\0')
{
- snprintf(bp, SPACELEFT(buf, bp), ", relay=%s",
- shortenstring(p, 40));
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", relay=%s", shortenstring(p, 40));
}
}
bp += strlen(bp);
@@ -3561,8 +4145,8 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
/* dsn */
if (dsn != NULL && *dsn != '\0')
{
- snprintf(bp, SPACELEFT(buf, bp), ", dsn=%s",
- shortenstring(dsn, ENHSCLEN));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=",
+ shortenstring(dsn, ENHSCLEN));
bp += strlen(bp);
}
@@ -3581,23 +4165,25 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
{
/* desperation move -- truncate data */
bp = buf + sizeof buf - ((STATLEN) + 17);
- (void) strlcpy(bp, "...", SPACELEFT(buf, bp));
+ (void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp));
bp += 3;
}
- (void) strlcpy(bp, ", stat=", SPACELEFT(buf, bp));
+ (void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp));
bp += strlen(bp);
- (void) strlcpy(bp, shortenstring(status, STATLEN), SPACELEFT(buf, bp));
+ (void) sm_strlcpy(bp, shortenstring(status, STATLEN),
+ SPACELEFT(buf, bp));
/* id, to: max 13 + TOBUFSIZE bytes */
l = SYSLOG_BUFSIZE - 100 - strlen(buf);
+ if (l < 0)
+ l = 0;
p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
- while (strlen(p) >= (SIZE_T) l)
+ while (strlen(p) >= l)
{
register char *q;
-#if _FFR_DYNAMIC_TOBUF
for (q = p + l; q > p; q--)
{
if (*q == ',')
@@ -3605,32 +4191,22 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
}
if (p == q)
break;
-#else /* _FFR_DYNAMIC_TOBUF */
- q = strchr(p + l, ',');
- if (q == NULL)
- break;
-#endif /* _FFR_DYNAMIC_TOBUF */
-
- sm_syslog(LOG_INFO, e->e_id,
- "to=%.*s [more]%s",
+ sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s",
(int) (++q - p), p, buf);
p = q;
}
-#if _FFR_DYNAMIC_TOBUF
sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf);
-#else /* _FFR_DYNAMIC_TOBUF */
- sm_syslog(LOG_INFO, e->e_id, "to=%s%s", p, buf);
-#endif /* _FFR_DYNAMIC_TOBUF */
#else /* (SYSLOG_BUFSIZE) >= 256 */
l = SYSLOG_BUFSIZE - 85;
+ if (l < 0)
+ l = 0;
p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
- while (strlen(p) >= (SIZE_T) l)
+ while (strlen(p) >= l)
{
register char *q;
-#if _FFR_DYNAMIC_TOBUF
for (q = p + l; q > p; q--)
{
if (*q == ',')
@@ -3638,51 +4214,42 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
}
if (p == q)
break;
-#else /* _FFR_DYNAMIC_TOBUF */
- q = strchr(p + l, ',');
- if (q == NULL)
- break;
-#endif /* _FFR_DYNAMIC_TOBUF */
- sm_syslog(LOG_INFO, e->e_id,
- "to=%.*s [more]",
+ sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]",
(int) (++q - p), p);
p = q;
}
-#if _FFR_DYNAMIC_TOBUF
sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p);
-#else /* _FFR_DYNAMIC_TOBUF */
- sm_syslog(LOG_INFO, e->e_id, "to=%s", p);
-#endif /* _FFR_DYNAMIC_TOBUF */
if (ctladdr != NULL)
{
bp = buf;
- snprintf(bp, SPACELEFT(buf, bp), "ctladdr=%s",
- shortenstring(ctladdr->q_paddr, 83));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=",
+ shortenstring(ctladdr->q_paddr, 83));
bp += strlen(bp);
if (bitset(QGOODUID, ctladdr->q_flags))
{
- (void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
- ctladdr->q_uid, ctladdr->q_gid);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
+ ctladdr->q_uid, ctladdr->q_gid);
bp += strlen(bp);
}
sm_syslog(LOG_INFO, e->e_id, "%s", buf);
}
bp = buf;
- snprintf(bp, SPACELEFT(buf, bp), "delay=%s",
- pintvl(now - e->e_ctime, TRUE));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=",
+ pintvl(now - e->e_ctime, true));
bp += strlen(bp);
if (xstart != (time_t) 0)
{
- snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s",
- pintvl(now - xstart, TRUE));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=",
+ pintvl(now - xstart, true));
bp += strlen(bp);
}
if (m != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name);
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=",
+ m->m_name);
bp += strlen(bp);
}
sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
@@ -3691,24 +4258,31 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
bp = buf;
if (mci != NULL && mci->mci_host != NULL)
{
-# if DAEMON
extern SOCKADDR CurHostAddr;
-# endif /* DAEMON */
- snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", mci->mci_host);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s",
+ mci->mci_host);
bp += strlen(bp);
-# if DAEMON
if (CurHostAddr.sa.sa_family != 0)
- snprintf(bp, SPACELEFT(buf, bp), " [%.100s]",
- anynet_ntoa(&CurHostAddr));
-# endif /* DAEMON */
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ " [%.100s]",
+ anynet_ntoa(&CurHostAddr));
+ }
+#if _FFR_QUARANTINE
+ else if (strcmp(status, "quarantined") == 0)
+ {
+ if (e->e_quarmsg != NULL)
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", quarantine=%.100s",
+ e->e_quarmsg);
}
+#endif /* _FFR_QUARANTINE */
else if (strcmp(status, "queued") != 0)
{
p = macvalue('h', e);
if (p != NULL && p[0] != '\0')
- snprintf(buf, sizeof buf, "relay=%.100s", p);
+ (void) sm_snprintf(buf, sizeof buf, "relay=%.100s", p);
}
if (buf[0] != '\0')
sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
@@ -3716,7 +4290,7 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63));
#endif /* (SYSLOG_BUFSIZE) >= 256 */
}
- /*
+/*
** PUTFROMLINE -- output a UNIX-style from line (or whatever)
**
** This can be made an arbitrary message separator by changing $l
@@ -3774,23 +4348,23 @@ putfromline(mci, e)
}
else
*at++ = '\0';
- (void) snprintf(xbuf, sizeof xbuf,
- "From %.800s \201d remote from %.100s\n",
- buf, at);
+ (void) sm_snprintf(xbuf, sizeof xbuf,
+ "From %.800s \201d remote from %.100s\n",
+ buf, at);
}
else
{
*bang++ = '\0';
- (void) snprintf(xbuf, sizeof xbuf,
- "From %.800s \201d remote from %.100s\n",
- bang, buf);
+ (void) sm_snprintf(xbuf, sizeof xbuf,
+ "From %.800s \201d remote from %.100s\n",
+ bang, buf);
template = xbuf;
}
}
expand(template, buf, sizeof buf, e);
putxline(buf, strlen(buf), mci, PXLF_HEADER);
}
- /*
+/*
** PUTBODY -- put the body of a message.
**
** Parameters:
@@ -3817,9 +4391,11 @@ putbody(mci, e, separator)
register ENVELOPE *e;
char *separator;
{
- bool dead = FALSE;
+ bool dead = false;
char buf[MAXLINE];
+#if MIME8TO7
char *boundaries[MAXMIMENESTING + 1];
+#endif /* MIME8TO7 */
/*
** Output the body of the message
@@ -3827,9 +4403,10 @@ putbody(mci, e, separator)
if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
{
- char *df = queuename(e, 'd');
+ char *df = queuename(e, DATAFL_LETTER);
- e->e_dfp = fopen(df, "r");
+ e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df,
+ SM_IO_RDONLY, NULL);
if (e->e_dfp == NULL)
{
char *msg = "!putbody: Cannot open %s for %s from %s";
@@ -3838,6 +4415,7 @@ putbody(mci, e, separator)
msg++;
syserr(msg, df, e->e_to, e->e_from.q_paddr);
}
+
}
if (e->e_dfp == NULL)
{
@@ -3854,7 +4432,8 @@ putbody(mci, e, separator)
{
struct stat stbuf;
- if (fstat(fileno(e->e_dfp), &stbuf) < 0)
+ if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf)
+ < 0)
e->e_dfino = -1;
else
{
@@ -3863,7 +4442,7 @@ putbody(mci, e, separator)
}
}
- /* paranoia: the df file should always be in a rewound state */
+ /* paranoia: the data file should always be in a rewound state */
(void) bfrewind(e->e_dfp);
#if MIME8TO7
@@ -3879,9 +4458,9 @@ putbody(mci, e, separator)
if (hvalue("Content-Type", e->e_header) == NULL)
{
- snprintf(buf, sizeof buf,
- "Content-Type: text/plain; charset=%s",
- defcharset(e));
+ (void) sm_snprintf(buf, sizeof buf,
+ "Content-Type: text/plain; charset=%s",
+ defcharset(e));
putline(buf, mci);
}
@@ -3913,7 +4492,7 @@ putbody(mci, e, separator)
*/
if (bitset(EF_DONT_MIME, e->e_flags))
- SuprErrs = TRUE;
+ SuprErrs = true;
(void) mime8to7(mci, e->e_header, e, boundaries,
M87F_OUTER|M87F_NO8TO7);
@@ -3950,22 +4529,22 @@ putbody(mci, e, separator)
ostate = OS_HEAD;
bp = buf;
pbp = peekbuf;
- while (!ferror(mci->mci_out) && !dead)
+ while (!sm_io_error(mci->mci_out) && !dead)
{
if (pbp > peekbuf)
c = *--pbp;
- else if ((c = getc(e->e_dfp)) == EOF)
+ else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT))
+ == SM_IO_EOF)
break;
if (bitset(MCIF_7BIT, mci->mci_flags))
c &= 0x7f;
switch (ostate)
{
case OS_HEAD:
-#if _FFR_NONULLS
if (c == '\0' &&
- bitnset(M_NONULLS, mci->mci_mailer->m_flags))
+ bitnset(M_NONULLS,
+ mci->mci_mailer->m_flags))
break;
-#endif /* _FFR_NONULLS */
if (c != '\r' && c != '\n' && bp < buflim)
{
*bp++ = c;
@@ -3975,10 +4554,10 @@ putbody(mci, e, separator)
/* check beginning of line for special cases */
*bp = '\0';
pos = 0;
- padc = EOF;
+ padc = SM_IO_EOF;
if (buf[0] == 'F' &&
- bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
- strncmp(buf, "From ", 5) == 0)
+ bitnset(M_ESCFROM, mci->mci_mailer->m_flags)
+ && strncmp(buf, "From ", 5) == 0)
{
padc = '>';
}
@@ -3988,7 +4567,8 @@ putbody(mci, e, separator)
/* possible separator */
int sl = strlen(separator);
- if (strncmp(&buf[2], separator, sl) == 0)
+ if (strncmp(&buf[2], separator, sl)
+ == 0)
padc = ' ';
}
if (buf[0] == '.' &&
@@ -4000,57 +4580,68 @@ putbody(mci, e, separator)
/* now copy out saved line */
if (TrafficLogFile != NULL)
{
- fprintf(TrafficLogFile, "%05d >>> ",
- (int) getpid());
- if (padc != EOF)
- (void) putc(padc,
- TrafficLogFile);
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "%05d >>> ",
+ (int) CurrentPid);
+ if (padc != SM_IO_EOF)
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ padc);
for (xp = buf; xp < bp; xp++)
- (void) putc((unsigned char) *xp,
- TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char) *xp);
if (c == '\n')
- (void) fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
+ (void) sm_io_fputs(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
}
- if (padc != EOF)
+ if (padc != SM_IO_EOF)
{
- if (putc(padc, mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT, padc)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
continue;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos++;
}
for (xp = buf; xp < bp; xp++)
{
- if (putc((unsigned char) *xp,
- mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT,
+ (unsigned char) *xp)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
break;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
}
if (dead)
continue;
if (c == '\n')
{
- if (fputs(mci->mci_mailer->m_eol,
- mci->mci_out) == EOF)
+ if (sm_io_fputs(mci->mci_out,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
break;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos = 0;
}
@@ -4076,19 +4667,22 @@ putbody(mci, e, separator)
if (c == '\n')
{
/* got CRLF */
- if (fputs(mci->mci_mailer->m_eol,
- mci->mci_out) == EOF)
+ if (sm_io_fputs(mci->mci_out,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
continue;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (TrafficLogFile != NULL)
{
- (void) fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
+ (void) sm_io_fputs(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
}
ostate = OS_HEAD;
continue;
@@ -4106,11 +4700,10 @@ putbody(mci, e, separator)
ostate = OS_CR;
continue;
}
-#if _FFR_NONULLS
if (c == '\0' &&
- bitnset(M_NONULLS, mci->mci_mailer->m_flags))
+ bitnset(M_NONULLS,
+ mci->mci_mailer->m_flags))
break;
-#endif /* _FFR_NONULLS */
putch:
if (mci->mci_mailer->m_linelimit > 0 &&
pos >= mci->mci_mailer->m_linelimit - 1 &&
@@ -4121,46 +4714,57 @@ putch:
/* check next character for EOL */
if (pbp > peekbuf)
d = *(pbp - 1);
- else if ((d = getc(e->e_dfp)) != EOF)
+ else if ((d = sm_io_getc(e->e_dfp,
+ SM_TIME_DEFAULT))
+ != SM_IO_EOF)
*pbp++ = d;
- if (d == '\n' || d == EOF)
+ if (d == '\n' || d == SM_IO_EOF)
{
if (TrafficLogFile != NULL)
- (void) putc((unsigned char) c,
- TrafficLogFile);
- if (putc((unsigned char) c,
- mci->mci_out) == EOF)
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char) c);
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT,
+ (unsigned char) c)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
continue;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos++;
continue;
}
- if (putc('!', mci->mci_out) == EOF ||
- fputs(mci->mci_mailer->m_eol,
- mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT, '!')
+ == SM_IO_EOF ||
+ sm_io_fputs(mci->mci_out,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
continue;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (TrafficLogFile != NULL)
{
- fprintf(TrafficLogFile, "!%s",
- mci->mci_mailer->m_eol);
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "!%s",
+ mci->mci_mailer->m_eol);
}
ostate = OS_HEAD;
*pbp++ = c;
@@ -4169,15 +4773,18 @@ putch:
if (c == '\n')
{
if (TrafficLogFile != NULL)
- (void) fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
- if (fputs(mci->mci_mailer->m_eol,
- mci->mci_out) == EOF)
+ (void) sm_io_fputs(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
+ if (sm_io_fputs(mci->mci_out,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
continue;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos = 0;
ostate = OS_HEAD;
@@ -4185,18 +4792,21 @@ putch:
else
{
if (TrafficLogFile != NULL)
- (void) putc((unsigned char) c,
- TrafficLogFile);
- if (putc((unsigned char) c,
- mci->mci_out) == EOF)
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char) c);
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT,
+ (unsigned char) c)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
continue;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos++;
ostate = OS_INLINE;
@@ -4211,21 +4821,23 @@ putch:
if (TrafficLogFile != NULL)
{
for (xp = buf; xp < bp; xp++)
- (void) putc((unsigned char) *xp,
- TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char) *xp);
}
for (xp = buf; xp < bp; xp++)
{
- if (putc((unsigned char) *xp, mci->mci_out) ==
- EOF)
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ (unsigned char) *xp)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
break;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
}
pos += bp - buf;
@@ -4233,19 +4845,22 @@ putch:
if (!dead && pos > 0)
{
if (TrafficLogFile != NULL)
- (void) fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
- (void) fputs(mci->mci_mailer->m_eol, mci->mci_out);
+ (void) sm_io_fputs(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
+ (void) sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
}
- if (ferror(e->e_dfp))
+ if (sm_io_error(e->e_dfp))
{
- syserr("putbody: %s/df%s: read error",
- qid_printqueue(e->e_queuedir), e->e_id);
+ syserr("putbody: %s/%cf%s: read error",
+ qid_printqueue(e->e_dfqgrp, e->e_dfqdir),
+ DATAFL_LETTER, e->e_id);
ExitStat = EX_IOERR;
}
@@ -4269,8 +4884,8 @@ endofmessage:
buf[0] != '\0' && buf[0] != '\n')
putline("", mci);
- (void) fflush(mci->mci_out);
- if (ferror(mci->mci_out) && errno != EPIPE)
+ (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
+ if (sm_io_error(mci->mci_out) && errno != EPIPE)
{
syserr("putbody: write error");
ExitStat = EX_IOERR;
@@ -4278,11 +4893,11 @@ endofmessage:
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
+** If the file has the set-user-ID/set-group-ID 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.
**
@@ -4308,6 +4923,8 @@ endofmessage:
** none.
*/
+# define RETURN(st) exit(st);
+
static jmp_buf CtxMailfileTimeout;
int
@@ -4318,7 +4935,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
volatile long sfflags;
register ENVELOPE *e;
{
- register FILE *f;
+ register SM_FILE_T *f;
register pid_t pid = -1;
volatile int mode;
int len;
@@ -4326,28 +4943,28 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
bool suidwarn = geteuid() == 0;
char *p;
char *volatile realfile;
- EVENT *ev;
+ SM_EVENT *ev;
char buf[MAXLINE + 1];
char targetfile[MAXPATHLEN + 1];
if (tTd(11, 1))
{
- dprintf("mailfile %s\n ctladdr=", filename);
- printaddr(ctladdr, FALSE);
+ sm_dprintf("mailfile %s\n ctladdr=", filename);
+ printaddr(ctladdr, false);
}
if (mailer == NULL)
mailer = FileMailer;
if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp);
+ (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
/*
** Special case /dev/null. This allows us to restrict file
** delivery to regular files only.
*/
- if (strcmp(filename, "/dev/null") == 0)
+ if (sm_path_isdevnull(filename))
return EX_OK;
/* check for 8-bit available */
@@ -4360,7 +4977,8 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
{
e->e_status = "5.6.3";
usrerrenh(e->e_status,
- "554 Cannot send 8-bit data to 7-bit destination");
+ "554 Cannot send 8-bit data to 7-bit destination");
+ errno = 0;
return EX_DATAERR;
}
@@ -4372,19 +4990,19 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (strncmp(SafeFileEnv, filename, len) == 0)
filename += len;
- if (len + strlen(filename) + 1 > MAXPATHLEN)
+ if (len + strlen(filename) + 1 >= sizeof targetfile)
{
syserr("mailfile: filename too long (%s/%s)",
SafeFileEnv, filename);
return EX_CANTCREAT;
}
- (void) strlcpy(targetfile, SafeFileEnv, sizeof targetfile);
+ (void) sm_strlcpy(targetfile, SafeFileEnv, sizeof targetfile);
realfile = targetfile + len;
if (targetfile[len - 1] != '/')
- (void) strlcat(targetfile, "/", sizeof targetfile);
+ (void) sm_strlcat(targetfile, "/", sizeof targetfile);
if (*filename == '/')
filename++;
- (void) strlcat(targetfile, filename, sizeof targetfile);
+ (void) sm_strlcat(targetfile, filename, sizeof targetfile);
}
else if (mailer->m_rootdir != NULL)
{
@@ -4394,7 +5012,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (strncmp(targetfile, filename, len) == 0)
filename += len;
- if (len + strlen(filename) + 1 > MAXPATHLEN)
+ if (len + strlen(filename) + 1 >= sizeof targetfile)
{
syserr("mailfile: filename too long (%s/%s)",
targetfile, filename);
@@ -4402,21 +5020,22 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
}
realfile = targetfile + len;
if (targetfile[len - 1] != '/')
- (void) strlcat(targetfile, "/", sizeof targetfile);
+ (void) sm_strlcat(targetfile, "/", sizeof targetfile);
if (*filename == '/')
- (void) strlcat(targetfile, filename + 1,
- sizeof targetfile);
+ (void) sm_strlcat(targetfile, filename + 1,
+ sizeof targetfile);
else
- (void) strlcat(targetfile, filename, sizeof targetfile);
+ (void) sm_strlcat(targetfile, filename,
+ sizeof targetfile);
}
else
{
- if (strlen(filename) > MAXPATHLEN)
+ if (sm_strlcpy(targetfile, filename, sizeof targetfile) >=
+ sizeof targetfile)
{
syserr("mailfile: filename too long (%s)", filename);
return EX_CANTCREAT;
}
- (void) strlcpy(targetfile, filename, sizeof targetfile);
realfile = targetfile;
}
@@ -4440,31 +5059,34 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
/* Reset global flags */
RestartRequest = NULL;
+ RestartWorkGroup = false;
ShutdownRequest = NULL;
PendingSignal = 0;
+ CurrentPid = getpid();
if (e->e_lockfp != NULL)
- (void) close(fileno(e->e_lockfp));
+ (void) close(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
+ NULL));
- (void) setsignal(SIGINT, SIG_DFL);
- (void) setsignal(SIGHUP, SIG_DFL);
- (void) setsignal(SIGTERM, SIG_DFL);
+ (void) sm_signal(SIGINT, SIG_DFL);
+ (void) sm_signal(SIGHUP, SIG_DFL);
+ (void) sm_signal(SIGTERM, SIG_DFL);
(void) umask(OldUmask);
e->e_to = filename;
ExitStat = EX_OK;
if (setjmp(CtxMailfileTimeout) != 0)
{
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
if (TimeOuts.to_fileopen > 0)
- ev = setevent(TimeOuts.to_fileopen,
- mailfiletimeout, 0);
+ ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout,
+ 0);
else
ev = NULL;
- /* check file mode to see if setuid */
+ /* check file mode to see if set-user-ID */
if (stat(targetfile, &stb) < 0)
mode = FileMode;
else
@@ -4478,18 +5100,19 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) ||
bitset(SFF_RUNASREALUID, sfflags))
{
- /* ignore setuid and setgid bits */
+ /* ignore set-user-ID and set-group-ID bits */
mode &= ~(S_ISGID|S_ISUID);
if (tTd(11, 20))
- dprintf("mailfile: ignoring setuid/setgid bits\n");
+ sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n");
}
- /* we have to open the dfile BEFORE setuid */
+ /* we have to open the data file BEFORE setuid() */
if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
{
- char *df = queuename(e, 'd');
+ char *df = queuename(e, DATAFL_LETTER);
- e->e_dfp = fopen(df, "r");
+ e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df,
+ SM_IO_RDONLY, NULL);
if (e->e_dfp == NULL)
{
syserr("mailfile: Cannot open %s for %s from %s",
@@ -4507,8 +5130,9 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (RunAsUid != 0 && RealUid != RunAsUid)
{
/* Only root can change the uid */
- syserr("mailfile: insufficient privileges to change uid");
- exit(EX_TEMPFAIL);
+ syserr("mailfile: insufficient privileges to change uid, RunAsUid=%d, RealUid=%d",
+ (int) RunAsUid, (int) RealUid);
+ RETURN(EX_TEMPFAIL);
}
}
else if (bitset(S_ISUID, mode))
@@ -4544,8 +5168,10 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
RealGid != getegid()))
{
/* Only root can change the gid */
- syserr("mailfile: insufficient privileges to change gid");
- exit(EX_TEMPFAIL);
+ syserr("mailfile: insufficient privileges to change gid, RealGid=%d, RunAsUid=%d, gid=%d, egid=%d",
+ (int) RealGid, (int) RunAsUid,
+ (int) getgid(), (int) getegid());
+ RETURN(EX_TEMPFAIL);
}
}
else if (bitset(S_ISGID, mode))
@@ -4587,7 +5213,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
{
syserr("mailfile: initgroups(%s, %d) failed",
RealUserName, RealGid);
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
}
else
@@ -4598,7 +5224,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (setgroups(1, gidset) == -1 && suidwarn)
{
syserr("mailfile: setgroups() failed");
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
}
@@ -4610,41 +5236,42 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
{
*realfile = '\0';
if (tTd(11, 20))
- dprintf("mailfile: chroot %s\n", targetfile);
+ sm_dprintf("mailfile: chroot %s\n", targetfile);
if (chroot(targetfile) < 0)
{
syserr("mailfile: Cannot chroot(%s)",
targetfile);
- exit(EX_CANTCREAT);
+ RETURN(EX_CANTCREAT);
}
*realfile = '/';
}
if (tTd(11, 40))
- dprintf("mailfile: deliver to %s\n", realfile);
+ sm_dprintf("mailfile: deliver to %s\n", realfile);
if (chdir("/") < 0)
{
syserr("mailfile: cannot chdir(/)");
- exit(EX_CANTCREAT);
+ RETURN(EX_CANTCREAT);
}
/* now reset the group and user ids */
endpwent();
+ sm_mbdb_terminate();
if (setgid(RealGid) < 0 && suidwarn)
{
syserr("mailfile: setgid(%ld) failed", (long) RealGid);
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
vendor_set_uid(RealUid);
if (setuid(RealUid) < 0 && suidwarn)
{
syserr("mailfile: setuid(%ld) failed", (long) RealUid);
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
if (tTd(11, 2))
- dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n",
+ sm_dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n",
(int) getuid(), (int) geteuid(),
(int) getgid(), (int) getegid());
@@ -4663,7 +5290,8 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (q != NULL)
*q++ = ':';
if (tTd(11, 20))
- dprintf("mailfile: trydir %s\n", buf);
+ sm_dprintf("mailfile: trydir %s\n",
+ buf);
if (buf[0] != '\0' && chdir(buf) >= 0)
break;
}
@@ -4713,32 +5341,34 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
{
usrerr("454 4.3.0 cannot open %s: %s",
shortenstring(realfile, MAXSHORTSTR),
- errstring(errno));
- exit(EX_TEMPFAIL);
+ sm_errstring(errno));
+ RETURN(EX_TEMPFAIL);
}
else
{
usrerr("554 5.3.0 cannot open %s: %s",
shortenstring(realfile, MAXSHORTSTR),
- errstring(errno));
- exit(EX_CANTCREAT);
+ sm_errstring(errno));
+ RETURN(EX_CANTCREAT);
}
}
- if (filechanged(realfile, fileno(f), &stb))
+ if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
+ &stb))
{
syserr("554 5.3.0 file changed after open");
- exit(EX_CANTCREAT);
+ RETURN(EX_CANTCREAT);
}
- if (fstat(fileno(f), &stb) < 0)
+ if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0)
{
- syserr("554 5.3.0 cannot fstat %s", errstring(errno));
- exit(EX_CANTCREAT);
+ syserr("554 5.3.0 cannot fstat %s",
+ sm_errstring(errno));
+ RETURN(EX_CANTCREAT);
}
curoff = stb.st_size;
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
memset(&mcibuf, '\0', sizeof mcibuf);
mcibuf.mci_mailer = mailer;
@@ -4758,13 +5388,13 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
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) &&
+ (sm_strcasecmp(p, "quoted-printable") == 0 ||
+ sm_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 &&
+ if (sm_strncasecmp(p, "text/plain", 10) == 0 &&
(p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
mcibuf.mci_flags |= MCIF_CVT7TO8;
}
@@ -4774,25 +5404,28 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
(*e->e_putbody)(&mcibuf, e, NULL);
putline("\n", &mcibuf);
- if (fflush(f) != 0 ||
- (SuperSafe && fsync(fileno(f)) < 0) ||
- ferror(f))
+ if (sm_io_flush(f, SM_TIME_DEFAULT) != 0 ||
+ (SuperSafe != SAFE_NO &&
+ fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) ||
+ sm_io_error(f))
{
setstat(EX_IOERR);
#if !NOFTRUNCATE
- (void) ftruncate(fileno(f), curoff);
+ (void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
+ curoff);
#endif /* !NOFTRUNCATE */
}
/* reset ISUID & ISGID bits for paranoid systems */
#if HASFCHMOD
- (void) fchmod(fileno(f), (MODE_T) mode);
+ (void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
+ (MODE_T) mode);
#else /* HASFCHMOD */
(void) chmod(filename, (MODE_T) mode);
#endif /* HASFCHMOD */
- if (fclose(f) < 0)
+ if (sm_io_close(f, SM_TIME_DEFAULT) < 0)
setstat(EX_IOERR);
- (void) fflush(stdout);
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
(void) setuid(RealUid);
exit(ExitStat);
/* NOTREACHED */
@@ -4809,7 +5442,10 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
return EX_SOFTWARE;
}
if (WIFEXITED(st))
+ {
+ errno = 0;
return (WEXITSTATUS(st));
+ }
else
{
syserr("mailfile: %s: child died on signal %d",
@@ -4833,7 +5469,7 @@ mailfiletimeout()
errno = ETIMEDOUT;
longjmp(CtxMailfileTimeout, 1);
}
- /*
+/*
** HOSTSIGNATURE -- return the "signature" for a host.
**
** The signature describes how we are going to send this -- it
@@ -4850,15 +5486,17 @@ mailfiletimeout()
** Side Effects:
** Can tweak the symbol table.
*/
+
#define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */
-static char *
+char *
hostsignature(m, host)
register MAILER *m;
char *host;
{
register char *p;
register STAB *s;
+ time_t now;
#if NAMED_BIND
char sep = ':';
char prevsep = ':';
@@ -4866,35 +5504,33 @@ hostsignature(m, host)
int len;
int nmx;
int hl;
- time_t now;
char *hp;
char *endp;
int oldoptions = _res.options;
char *mxhosts[MAXMXHOSTS + 1];
- u_short mxprefs[MAXMXHOSTS + 1];
+ unsigned short mxprefs[MAXMXHOSTS + 1];
#endif /* NAMED_BIND */
if (tTd(17, 3))
- dprintf("hostsignature(%s)\n", host);
+ sm_dprintf("hostsignature(%s)\n", host);
/*
** If local delivery (and not remote), just return a constant.
*/
- p = m->m_mailer;
if (bitnset(M_LOCALMAILER, m->m_flags) &&
- strcmp(p, "[IPC]") != 0 &&
- strcmp(p, "[TCP]") != 0)
+ strcmp(m->m_mailer, "[IPC]") != 0 &&
+ !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0))
return "localhost";
/*
** Check to see if this uses IPC -- if not, it can't have MX records.
*/
- if (strcmp(p, "[IPC]") != 0 &&
- strcmp(p, "[TCP]") != 0)
+ if (strcmp(m->m_mailer, "[IPC]") != 0 ||
+ CurEnv->e_sendmode == SM_DEFER)
{
- /* just an ordinary mailer */
+ /* just an ordinary mailer or deferred mode */
return host;
}
#if NETUNIX
@@ -4910,24 +5546,34 @@ hostsignature(m, host)
** Look it up in the symbol table.
*/
+ now = curtime();
s = stab(host, ST_HOSTSIG, ST_ENTER);
- if (s->s_hostsig != NULL)
+ if (s->s_hostsig.hs_sig != NULL)
{
- if (tTd(17, 3))
- dprintf("hostsignature(): stab(%s) found %s\n", host,
- s->s_hostsig);
- return s->s_hostsig;
+ if (s->s_hostsig.hs_exp >= now)
+ {
+ if (tTd(17, 3))
+ sm_dprintf("hostsignature(): stab(%s) found %s\n", host,
+ s->s_hostsig.hs_sig);
+ return s->s_hostsig.hs_sig;
+ }
+
+ /* signature is expired: clear it */
+ sm_free(s->s_hostsig.hs_sig);
+ s->s_hostsig.hs_sig = NULL;
}
+ /* set default TTL */
+ s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL;
+
/*
- ** Not already there -- create a signature.
+ ** Not already there or expired -- create a signature.
*/
#if NAMED_BIND
if (ConfigLevel < 2)
_res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
- now = curtime();
for (hp = host; hp != NULL; hp = endp)
{
#if NETINET6
@@ -4957,8 +5603,10 @@ hostsignature(m, host)
else
{
auto int rcode;
+ int ttl;
- nmx = getmxrr(hp, mxhosts, mxprefs, TRUE, &rcode);
+ nmx = getmxrr(hp, mxhosts, mxprefs, true, &rcode, true,
+ &ttl);
if (nmx <= 0)
{
int save_errno;
@@ -4972,7 +5620,7 @@ hostsignature(m, host)
mci->mci_lastuse = now;
if (rcode == EX_NOHOST)
mci_setstat(mci, rcode, "5.1.2",
- "550 Host unknown");
+ "550 Host unknown");
else
mci_setstat(mci, rcode, NULL, NULL);
@@ -4981,34 +5629,41 @@ hostsignature(m, host)
mxhosts[0] = hp;
}
if (tTd(17, 3))
- dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n",
- nmx, mxhosts[0]);
+ sm_dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n",
+ nmx, mxhosts[0]);
+
+ /*
+ ** Set new TTL: we use only one!
+ ** We could try to use the minimum instead.
+ */
+
+ s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL);
}
len = 0;
for (i = 0; i < nmx; i++)
len += strlen(mxhosts[i]) + 1;
- if (s->s_hostsig != NULL)
- len += strlen(s->s_hostsig) + 1;
- if (len >= MAXHOSTSIGNATURE)
+ if (s->s_hostsig.hs_sig != NULL)
+ len += strlen(s->s_hostsig.hs_sig) + 1;
+ if (len < 0 || len >= MAXHOSTSIGNATURE)
{
sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d",
host, MAXHOSTSIGNATURE, len);
len = MAXHOSTSIGNATURE;
}
- p = xalloc(len);
- if (s->s_hostsig != NULL)
+ p = sm_pmalloc_x(len);
+ if (s->s_hostsig.hs_sig != NULL)
{
- (void) strlcpy(p, s->s_hostsig, len);
- sm_free(s->s_hostsig);
- s->s_hostsig = p;
+ (void) sm_strlcpy(p, s->s_hostsig.hs_sig, len);
+ sm_free(s->s_hostsig.hs_sig); /* XXX */
+ s->s_hostsig.hs_sig = p;
hl = strlen(p);
p += hl;
*p++ = prevsep;
len -= hl + 1;
}
else
- s->s_hostsig = p;
+ s->s_hostsig.hs_sig = p;
for (i = 0; i < nmx; i++)
{
hl = strlen(mxhosts[i]);
@@ -5026,7 +5681,7 @@ hostsignature(m, host)
*p++ = ':';
len--;
}
- (void) strlcpy(p, mxhosts[i], len);
+ (void) sm_strlcpy(p, mxhosts[i], len);
p += hl;
len -= hl;
}
@@ -5043,18 +5698,22 @@ hostsignature(m, host)
*endp++ = sep;
prevsep = sep;
}
- makelower(s->s_hostsig);
+ makelower(s->s_hostsig.hs_sig);
if (ConfigLevel < 2)
_res.options = oldoptions;
#else /* NAMED_BIND */
/* not using BIND -- the signature is just the host name */
- s->s_hostsig = host;
+ /*
+ ** 'host' points to storage that will be freed after we are
+ ** done processing the current envelope, so we copy it.
+ */
+ s->s_hostsig.hs_sig = sm_pstrdup_x(host);
#endif /* NAMED_BIND */
if (tTd(17, 1))
- dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig);
- return s->s_hostsig;
+ sm_dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig.hs_sig);
+ return s->s_hostsig.hs_sig;
}
- /*
+/*
** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array.
**
** The signature describes how we are going to send this -- it
@@ -5065,6 +5724,7 @@ hostsignature(m, host)
** Parameters:
** sig -- the host signature.
** mxhosts -- array to populate.
+** mailer -- mailer.
**
** Returns:
** The number of hosts inserted into mxhosts array.
@@ -5079,11 +5739,10 @@ parse_hostsignature(sig, mxhosts, mailer)
char **mxhosts;
MAILER *mailer;
{
- int nmx = 0;
- int curpref = 0;
- int i, j;
+ unsigned short curpref = 0;
+ int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */
char *hp, *endp;
- u_short prefer[MAXMXHOSTS];
+ unsigned short prefer[MAXMXHOSTS];
long rndm[MAXMXHOSTS];
for (hp = sig; hp != NULL; hp = endp)
@@ -5149,7 +5808,7 @@ parse_hostsignature(sig, mxhosts, mailer)
if (prefer[i] > prefer[j] ||
(prefer[i] == prefer[j] && rndm[i] > rndm[j]))
{
- register u_short tempp;
+ register unsigned short tempp;
register long tempr;
register char *temp1;
@@ -5168,30 +5827,60 @@ parse_hostsignature(sig, mxhosts, mailer)
return nmx;
}
-#if SMTP
# if STARTTLS
static SSL_CTX *clt_ctx = NULL;
+static bool tls_ok_clt = true;
- /*
-** INITCLTTLS -- initialize client side TLS
+/*
+** SETCLTTLS -- client side TLS: allow/disallow.
**
** Parameters:
+** tls_ok -- should tls be done?
+**
+** Returns:
** none.
**
+** Side Effects:
+** sets tls_ok_clt (static variable in this module)
+*/
+
+void
+setclttls(tls_ok)
+ bool tls_ok;
+{
+ tls_ok_clt = tls_ok;
+ return;
+}
+/*
+** INITCLTTLS -- initialize client side TLS
+**
+** Parameters:
+** tls_ok -- should tls initialization be done?
+**
** Returns:
** succeeded?
+**
+** Side Effects:
+** sets tls_ok_clt (static variable in this module)
*/
bool
-initclttls()
+initclttls(tls_ok)
+ bool tls_ok;
{
+ if (!tls_ok_clt)
+ return false;
+ tls_ok_clt = tls_ok;
+ if (!tls_ok_clt)
+ return false;
if (clt_ctx != NULL)
- return TRUE; /* already done */
- return inittls(&clt_ctx, TLS_I_CLT, FALSE, CltCERTfile, Cltkeyfile,
- CACERTpath, CACERTfile, DHParams);
+ return true; /* already done */
+ tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, false, CltCERTfile,
+ Cltkeyfile, CACERTpath, CACERTfile, DHParams);
+ return tls_ok_clt;
}
- /*
+/*
** STARTTLS -- try to start secure connection (client side)
**
** Parameters:
@@ -5215,14 +5904,14 @@ starttls(m, mci, e)
int result = 0;
int rfd, wfd;
SSL *clt_ssl = NULL;
+ time_t tlsstart;
- if (clt_ctx == NULL && !initclttls())
+ if (clt_ctx == NULL && !initclttls(true))
return EX_TEMPFAIL;
smtpmessage("STARTTLS", m, mci);
/* get the reply */
- smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, NULL, NULL);
- /* which timeout? XXX */
+ smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL);
/* check return code from server */
if (smtpresult == 454)
@@ -5235,78 +5924,127 @@ starttls(m, mci, e)
return EX_PROTOCOL;
if (LogLevel > 13)
- sm_syslog(LOG_INFO, e->e_id, "TLS: start client");
+ sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok");
/* start connection */
if ((clt_ssl = SSL_new(clt_ctx)) == NULL)
{
if (LogLevel > 5)
{
- sm_syslog(LOG_ERR, e->e_id,
- "TLS: error: client: SSL_new failed");
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=client, error: SSL_new failed");
if (LogLevel > 9)
- tlslogerr();
+ tlslogerr("client");
}
return EX_SOFTWARE;
}
- rfd = fileno(mci->mci_in);
- wfd = fileno(mci->mci_out);
+ rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL);
+ wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL);
/* SSL_clear(clt_ssl); ? */
if (rfd < 0 || wfd < 0 ||
- (result = SSL_set_rfd(clt_ssl, rfd)) <= 0 ||
- (result = SSL_set_wfd(clt_ssl, wfd)) <= 0)
+ (result = SSL_set_rfd(clt_ssl, rfd)) != 1 ||
+ (result = SSL_set_wfd(clt_ssl, wfd)) != 1)
{
if (LogLevel > 5)
{
- sm_syslog(LOG_ERR, e->e_id,
- "TLS: error: SSL_set_xfd failed=%d", result);
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=client, error: SSL_set_xfd failed=%d",
+ result);
if (LogLevel > 9)
- tlslogerr();
+ tlslogerr("client");
}
return EX_SOFTWARE;
}
SSL_set_connect_state(clt_ssl);
+ tlsstart = curtime();
+
+ssl_retry:
if ((result = SSL_connect(clt_ssl)) <= 0)
{
int i;
+ bool timedout;
+ time_t left;
+ time_t now = curtime();
+ struct timeval tv;
/* what to do in this case? */
i = SSL_get_error(clt_ssl, result);
+
+ /*
+ ** For SSL_ERROR_WANT_{READ,WRITE}:
+ ** There is not a complete SSL record available yet
+ ** or there is only a partial SSL record removed from
+ ** the network (socket) buffer into the SSL buffer.
+ ** The SSL_connect will only succeed when a full
+ ** SSL record is available (assuming a "real" error
+ ** doesn't happen). To handle when a "real" error
+ ** does happen the select is set for exceptions too.
+ ** The connection may be re-negotiated during this time
+ ** so both read and write "want errors" need to be handled.
+ ** A select() exception loops back so that a proper SSL
+ ** error message can be gotten.
+ */
+
+ left = TimeOuts.to_starttls - (now - tlsstart);
+ timedout = left <= 0;
+ if (!timedout)
+ {
+ tv.tv_sec = left;
+ tv.tv_usec = 0;
+ }
+
+ if (!timedout && i == SSL_ERROR_WANT_READ)
+ {
+ fd_set ssl_maskr, ssl_maskx;
+
+ FD_ZERO(&ssl_maskr);
+ FD_SET(rfd, &ssl_maskr);
+ FD_ZERO(&ssl_maskx);
+ FD_SET(rfd, &ssl_maskx);
+ if (select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx, &tv)
+ > 0)
+ goto ssl_retry;
+ }
+ if (!timedout && i == SSL_ERROR_WANT_WRITE)
+ {
+ fd_set ssl_maskw, ssl_maskx;
+
+ FD_ZERO(&ssl_maskw);
+ FD_SET(wfd, &ssl_maskw);
+ FD_ZERO(&ssl_maskx);
+ FD_SET(rfd, &ssl_maskx);
+ if (select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx, &tv)
+ > 0)
+ goto ssl_retry;
+ }
if (LogLevel > 5)
{
sm_syslog(LOG_ERR, e->e_id,
- "TLS: error: SSL_connect failed=%d (%d)",
- result, i);
- if (LogLevel > 9)
- tlslogerr();
+ "STARTTLS=client, error: connect failed=%d, SSL_error=%d, timedout=%d",
+ result, i, (int) timedout);
+ if (LogLevel > 8)
+ tlslogerr("client");
}
SSL_free(clt_ssl);
clt_ssl = NULL;
return EX_SOFTWARE;
}
mci->mci_ssl = clt_ssl;
- result = tls_get_info(clt_ssl, e, FALSE, mci->mci_host, TRUE);
+ result = tls_get_info(mci->mci_ssl, false, mci->mci_host,
+ &mci->mci_macro, true);
- /* switch to use SSL... */
-#if SFIO
- if (sfdctls(mci->mci_in, mci->mci_out, mci->mci_ssl) == 0)
- return EX_OK;
-#else /* SFIO */
-# if _FFR_TLS_TOREK
+ /* switch to use TLS... */
if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0)
return EX_OK;
-# endif /* _FFR_TLS_TOREK */
-#endif /* SFIO */
/* failure */
SSL_free(clt_ssl);
clt_ssl = NULL;
return EX_SOFTWARE;
}
-
- /*
+/*
** ENDTLSCLT -- shutdown secure connection (client side)
**
** Parameters:
@@ -5315,7 +6053,8 @@ starttls(m, mci, e)
** Returns:
** success?
*/
-int
+
+static int
endtlsclt(mci)
MCI *mci;
{
@@ -5327,48 +6066,35 @@ endtlsclt(mci)
mci->mci_flags &= ~MCIF_TLSACT;
return r;
}
- /*
-** ENDTLS -- shutdown secure connection
+# endif /* STARTTLS */
+# if STARTTLS || SASL
+/*
+** ISCLTFLGSET -- check whether client flag is set.
**
** Parameters:
-** ssl -- SSL connection information.
-** side -- srv/clt (for logging).
+** e -- envelope.
+** flag -- flag to check in {client_flags}
**
** Returns:
-** success?
+** true iff flag is set.
*/
-int
-endtls(ssl, side)
- SSL *ssl;
- char *side;
+static bool
+iscltflgset(e, flag)
+ ENVELOPE *e;
+ int flag;
{
- int ret = EX_OK;
+ char *p;
- if (ssl != NULL)
+ p = macvalue(macid("{client_flags}"), e);
+ if (p == NULL)
+ return false;
+ for (; *p != '\0'; p++)
{
- int r;
-
- if ((r = SSL_shutdown(ssl)) < 0)
- {
- if (LogLevel > 11)
- sm_syslog(LOG_WARNING, NOQID,
- "SSL_shutdown %s failed: %d",
- side, r);
- ret = EX_SOFTWARE;
- }
- else if (r == 0)
- {
- if (LogLevel > 13)
- sm_syslog(LOG_WARNING, NOQID,
- "SSL_shutdown %s not done",
- side);
- ret = EX_SOFTWARE;
- }
- SSL_free(ssl);
- ssl = NULL;
+ /* look for just this one flag */
+ if (*p == (char) flag)
+ return true;
}
- return ret;
+ return false;
}
-# endif /* STARTTLS */
-#endif /* SMTP */
+# endif /* STARTTLS || SASL */
OpenPOWER on IntegriCloud