xref: /freebsd/contrib/sendmail/src/deliver.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
1c2aa98e2SPeter Wemm /*
2*d39bd2c1SGregory Neil Shapiro  * Copyright (c) 1998-2010, 2012, 2020-2023 Proofpoint, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
154e4196cbSGregory Neil Shapiro #include <sm/time.h>
1606f25ae9SGregory Neil Shapiro 
174313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: deliver.c,v 8.1030 2013-11-22 20:51:55 ca Exp $")
18c2aa98e2SPeter Wemm 
192fb4f839SGregory Neil Shapiro #include <sm/sendmail.h>
202fb4f839SGregory Neil Shapiro 
21c2aa98e2SPeter Wemm #if HASSETUSERCONTEXT
22c2aa98e2SPeter Wemm # include <login_cap.h>
235b0945b5SGregory Neil Shapiro #endif
2406f25ae9SGregory Neil Shapiro 
25605302a5SGregory Neil Shapiro #if NETINET || NETINET6
26605302a5SGregory Neil Shapiro # include <arpa/inet.h>
275b0945b5SGregory Neil Shapiro #endif
28605302a5SGregory Neil Shapiro 
2940266059SGregory Neil Shapiro #if STARTTLS || SASL
3006f25ae9SGregory Neil Shapiro # include "sfsasl.h"
315b0945b5SGregory Neil Shapiro # include "tls.h"
325b0945b5SGregory Neil Shapiro #endif
3306f25ae9SGregory Neil Shapiro 
34*d39bd2c1SGregory Neil Shapiro #if !_FFR_DMTRIGGER
3506f25ae9SGregory Neil Shapiro static int	deliver __P((ENVELOPE *, ADDRESS *));
36*d39bd2c1SGregory Neil Shapiro #endif
3706f25ae9SGregory Neil Shapiro static void	dup_queue_file __P((ENVELOPE *, ENVELOPE *, int));
38b6bacd31SGregory Neil Shapiro static void	mailfiletimeout __P((int));
39b6bacd31SGregory Neil Shapiro static void	endwaittimeout __P((int));
40*d39bd2c1SGregory Neil Shapiro static int	parse_hostsignature __P((char *, char **, MAILER *
41*d39bd2c1SGregory Neil Shapiro #if DANE
42*d39bd2c1SGregory Neil Shapiro 		, BITMAP256
43*d39bd2c1SGregory Neil Shapiro #endif
44*d39bd2c1SGregory Neil Shapiro 		));
4506f25ae9SGregory Neil Shapiro static void	sendenvelope __P((ENVELOPE *, int));
4640266059SGregory Neil Shapiro static int	coloncmp __P((const char *, const char *));
47c2aa98e2SPeter Wemm 
48*d39bd2c1SGregory Neil Shapiro 
4906f25ae9SGregory Neil Shapiro #if STARTTLS
50ba00ec3dSGregory Neil Shapiro # include <openssl/err.h>
515b0945b5SGregory Neil Shapiro # if DANE
52*d39bd2c1SGregory Neil Shapiro static int	starttls __P((MAILER *, MCI *, ENVELOPE *, bool, dane_vrfy_ctx_P));
53*d39bd2c1SGregory Neil Shapiro 
54*d39bd2c1SGregory Neil Shapiro # define MXADS_ISSET(mxads, i)	(0 != bitnset(bitidx(i), mxads))
55*d39bd2c1SGregory Neil Shapiro # define MXADS_SET(mxads, i)	setbitn(bitidx(i), mxads)
56*d39bd2c1SGregory Neil Shapiro 
57*d39bd2c1SGregory Neil Shapiro /* use "marks" in hostsignature for "had ad"? (WIP) */
58*d39bd2c1SGregory Neil Shapiro #  ifndef HSMARKS
59*d39bd2c1SGregory Neil Shapiro #   define HSMARKS 1
605b0945b5SGregory Neil Shapiro #  endif
61*d39bd2c1SGregory Neil Shapiro #  if HSMARKS
62*d39bd2c1SGregory Neil Shapiro #   define HSM_AD	'+'	/* mark for hostsignature: ad flag */
63*d39bd2c1SGregory Neil Shapiro #   define DANE_SEC(dane)	(DANE_SECURE == DANEMODE((dane)))
64*d39bd2c1SGregory Neil Shapiro #  endif
65*d39bd2c1SGregory Neil Shapiro # else /* DANE */
66*d39bd2c1SGregory Neil Shapiro static int	starttls __P((MAILER *, MCI *, ENVELOPE *, bool));
67*d39bd2c1SGregory Neil Shapiro # define MXADS_ISSET(mxads, i)	0
68*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
6940266059SGregory Neil Shapiro static int	endtlsclt __P((MCI *));
7006f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
7140266059SGregory Neil Shapiro #if STARTTLS || SASL
7240266059SGregory Neil Shapiro static bool	iscltflgset __P((ENVELOPE *, int));
735b0945b5SGregory Neil Shapiro #endif
745b0945b5SGregory Neil Shapiro 
75*d39bd2c1SGregory Neil Shapiro #define SEP_MXHOSTS(endp, sep)	\
76*d39bd2c1SGregory Neil Shapiro 		if (endp != NULL)	\
77*d39bd2c1SGregory Neil Shapiro 		{	\
78*d39bd2c1SGregory Neil Shapiro 			sep = *endp;	\
79*d39bd2c1SGregory Neil Shapiro 			*endp = '\0';	\
80*d39bd2c1SGregory Neil Shapiro 		}
81*d39bd2c1SGregory Neil Shapiro 
82*d39bd2c1SGregory Neil Shapiro #if NETINET6
83*d39bd2c1SGregory Neil Shapiro # define FIX_MXHOSTS(hp, endp, sep)	\
84*d39bd2c1SGregory Neil Shapiro 	do {	\
85*d39bd2c1SGregory Neil Shapiro 		if (*hp == '[')	\
86*d39bd2c1SGregory Neil Shapiro 		{	\
87*d39bd2c1SGregory Neil Shapiro 			endp = strchr(hp + 1, ']'); \
88*d39bd2c1SGregory Neil Shapiro 			if (endp != NULL)	\
89*d39bd2c1SGregory Neil Shapiro 				endp = strpbrk(endp + 1, ":,");	\
90*d39bd2c1SGregory Neil Shapiro 		}	\
91*d39bd2c1SGregory Neil Shapiro 		else	\
92*d39bd2c1SGregory Neil Shapiro 			endp = strpbrk(hp, ":,"); \
93*d39bd2c1SGregory Neil Shapiro 		SEP_MXHOSTS(endp, sep);	\
94*d39bd2c1SGregory Neil Shapiro 	} while (0)
95*d39bd2c1SGregory Neil Shapiro #else /* NETINET6 */
96*d39bd2c1SGregory Neil Shapiro # define FIX_MXHOSTS(hp, endp, sep)	\
97*d39bd2c1SGregory Neil Shapiro 	do {	\
98*d39bd2c1SGregory Neil Shapiro 		endp = strpbrk(hp, ":,"); \
99*d39bd2c1SGregory Neil Shapiro 		SEP_MXHOSTS(endp, sep);	\
100*d39bd2c1SGregory Neil Shapiro 	} while (0)
101*d39bd2c1SGregory Neil Shapiro #endif /* NETINET6 */
102*d39bd2c1SGregory Neil Shapiro 
1035b0945b5SGregory Neil Shapiro #if _FFR_OCC
1045b0945b5SGregory Neil Shapiro # include <ratectrl.h>
1055b0945b5SGregory Neil Shapiro #endif
106c2aa98e2SPeter Wemm 
1072fb4f839SGregory Neil Shapiro #define ESCNULLMXRCPT "5.1.10"
1082fb4f839SGregory Neil Shapiro #define ERRNULLMX "556 Host does not accept mail: MX 0 ."
1092fb4f839SGregory Neil Shapiro 
110*d39bd2c1SGregory Neil Shapiro #if _FFR_LOG_FAILOVER
111*d39bd2c1SGregory Neil Shapiro /*
112*d39bd2c1SGregory Neil Shapiro **  These are not very useful to show the protocol stage,
113*d39bd2c1SGregory Neil Shapiro **  but it's better than nothing right now.
114*d39bd2c1SGregory Neil Shapiro **  XXX the actual values must be 0..N, otherwise a lookup
115*d39bd2c1SGregory Neil Shapiro **  table must be used!
116*d39bd2c1SGregory Neil Shapiro */
117*d39bd2c1SGregory Neil Shapiro 
118*d39bd2c1SGregory Neil Shapiro static char *mcis[] =
119*d39bd2c1SGregory Neil Shapiro {
120*d39bd2c1SGregory Neil Shapiro 	"CLOSED",
121*d39bd2c1SGregory Neil Shapiro 	"GREET",
122*d39bd2c1SGregory Neil Shapiro 	"OPEN",
123*d39bd2c1SGregory Neil Shapiro 	"MAIL",
124*d39bd2c1SGregory Neil Shapiro 	"RCPT",
125*d39bd2c1SGregory Neil Shapiro 	"DATA",
126*d39bd2c1SGregory Neil Shapiro 	"QUITING",
127*d39bd2c1SGregory Neil Shapiro 	"SSD",
128*d39bd2c1SGregory Neil Shapiro 	"ERROR",
129*d39bd2c1SGregory Neil Shapiro 	NULL
130*d39bd2c1SGregory Neil Shapiro };
131*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_LOG_FAILOVER */
132*d39bd2c1SGregory Neil Shapiro 
133*d39bd2c1SGregory Neil Shapiro #if _FFR_LOG_STAGE
134*d39bd2c1SGregory Neil Shapiro static char *xs_states[] =
135*d39bd2c1SGregory Neil Shapiro {
136*d39bd2c1SGregory Neil Shapiro 	"none",
137*d39bd2c1SGregory Neil Shapiro 	"STARTTLS",
138*d39bd2c1SGregory Neil Shapiro 	"AUTH",
139*d39bd2c1SGregory Neil Shapiro 	"GREET",
140*d39bd2c1SGregory Neil Shapiro 	"EHLO",
141*d39bd2c1SGregory Neil Shapiro 	"MAIL",
142*d39bd2c1SGregory Neil Shapiro 	"RCPT",
143*d39bd2c1SGregory Neil Shapiro 	"DATA",
144*d39bd2c1SGregory Neil Shapiro 	"EOM",
145*d39bd2c1SGregory Neil Shapiro 	"DATA2",
146*d39bd2c1SGregory Neil Shapiro 	"QUIT",
147*d39bd2c1SGregory Neil Shapiro 	NULL
148*d39bd2c1SGregory Neil Shapiro };
149*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_LOG_STAGE */
150*d39bd2c1SGregory Neil Shapiro 
151c2aa98e2SPeter Wemm /*
152c2aa98e2SPeter Wemm **  SENDALL -- actually send all the messages.
153c2aa98e2SPeter Wemm **
154c2aa98e2SPeter Wemm **	Parameters:
155c2aa98e2SPeter Wemm **		e -- the envelope to send.
156c2aa98e2SPeter Wemm **		mode -- the delivery mode to use.  If SM_DEFAULT, use
157c2aa98e2SPeter Wemm **			the current e->e_sendmode.
158c2aa98e2SPeter Wemm **
159c2aa98e2SPeter Wemm **	Returns:
160c2aa98e2SPeter Wemm **		none.
161c2aa98e2SPeter Wemm **
162c2aa98e2SPeter Wemm **	Side Effects:
163c2aa98e2SPeter Wemm **		Scans the send lists and sends everything it finds.
164c2aa98e2SPeter Wemm **		Delivers any appropriate error messages.
165c2aa98e2SPeter Wemm **		If we are running in a non-interactive mode, takes the
166c2aa98e2SPeter Wemm **			appropriate action.
167c2aa98e2SPeter Wemm */
168c2aa98e2SPeter Wemm 
169c2aa98e2SPeter Wemm void
sendall(e,mode)170c2aa98e2SPeter Wemm sendall(e, mode)
171c2aa98e2SPeter Wemm 	ENVELOPE *e;
172c2aa98e2SPeter Wemm 	int mode;
173c2aa98e2SPeter Wemm {
174c2aa98e2SPeter Wemm 	register ADDRESS *q;
175c2aa98e2SPeter Wemm 	char *owner;
176c2aa98e2SPeter Wemm 	int otherowners;
17706f25ae9SGregory Neil Shapiro 	int save_errno;
178c2aa98e2SPeter Wemm 	register ENVELOPE *ee;
179c2aa98e2SPeter Wemm 	ENVELOPE *splitenv = NULL;
180c2aa98e2SPeter Wemm 	int oldverbose = Verbose;
18140266059SGregory Neil Shapiro 	bool somedeliveries = false, expensive = false;
182c2aa98e2SPeter Wemm 	pid_t pid;
183c2aa98e2SPeter Wemm 
184c2aa98e2SPeter Wemm 	/*
185c2aa98e2SPeter Wemm 	**  If this message is to be discarded, don't bother sending
186c2aa98e2SPeter Wemm 	**  the message at all.
187c2aa98e2SPeter Wemm 	*/
188c2aa98e2SPeter Wemm 
189c2aa98e2SPeter Wemm 	if (bitset(EF_DISCARD, e->e_flags))
190c2aa98e2SPeter Wemm 	{
191c2aa98e2SPeter Wemm 		if (tTd(13, 1))
19240266059SGregory Neil Shapiro 			sm_dprintf("sendall: discarding id %s\n", e->e_id);
193c2aa98e2SPeter Wemm 		e->e_flags |= EF_CLRQUEUE;
19440266059SGregory Neil Shapiro 		if (LogLevel > 9)
19540266059SGregory Neil Shapiro 			logundelrcpts(e, "discarded", 9, true);
19640266059SGregory Neil Shapiro 		else if (LogLevel > 4)
197c2aa98e2SPeter Wemm 			sm_syslog(LOG_INFO, e->e_id, "discarded");
19840266059SGregory Neil Shapiro 		markstats(e, NULL, STATS_REJECT);
199c2aa98e2SPeter Wemm 		return;
200c2aa98e2SPeter Wemm 	}
201c2aa98e2SPeter Wemm 
202c2aa98e2SPeter Wemm 	/*
203c2aa98e2SPeter Wemm 	**  If we have had global, fatal errors, don't bother sending
204c2aa98e2SPeter Wemm 	**  the message at all if we are in SMTP mode.  Local errors
205c2aa98e2SPeter Wemm 	**  (e.g., a single address failing) will still cause the other
206c2aa98e2SPeter Wemm 	**  addresses to be sent.
207c2aa98e2SPeter Wemm 	*/
208c2aa98e2SPeter Wemm 
209c2aa98e2SPeter Wemm 	if (bitset(EF_FATALERRS, e->e_flags) &&
210c2aa98e2SPeter Wemm 	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
211c2aa98e2SPeter Wemm 	{
212c2aa98e2SPeter Wemm 		e->e_flags |= EF_CLRQUEUE;
213c2aa98e2SPeter Wemm 		return;
214c2aa98e2SPeter Wemm 	}
215c2aa98e2SPeter Wemm 
216c2aa98e2SPeter Wemm 	/* determine actual delivery mode */
217c2aa98e2SPeter Wemm 	if (mode == SM_DEFAULT)
218c2aa98e2SPeter Wemm 	{
219c2aa98e2SPeter Wemm 		mode = e->e_sendmode;
220c2aa98e2SPeter Wemm 		if (mode != SM_VERIFY && mode != SM_DEFER &&
221c2aa98e2SPeter Wemm 		    shouldqueue(e->e_msgpriority, e->e_ctime))
222c2aa98e2SPeter Wemm 			mode = SM_QUEUE;
223c2aa98e2SPeter Wemm 	}
224c2aa98e2SPeter Wemm 
225c2aa98e2SPeter Wemm 	if (tTd(13, 1))
226c2aa98e2SPeter Wemm 	{
22740266059SGregory Neil Shapiro 		sm_dprintf("\n===== SENDALL: mode %c, id %s, e_from ",
228c2aa98e2SPeter Wemm 			mode, e->e_id);
229e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), &e->e_from, false);
23040266059SGregory Neil Shapiro 		sm_dprintf("\te_flags = ");
231c2aa98e2SPeter Wemm 		printenvflags(e);
23240266059SGregory Neil Shapiro 		sm_dprintf("sendqueue:\n");
233e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), e->e_sendqueue, true);
234c2aa98e2SPeter Wemm 	}
235c2aa98e2SPeter Wemm 
236c2aa98e2SPeter Wemm 	/*
237c2aa98e2SPeter Wemm 	**  Do any preprocessing necessary for the mode we are running.
238c2aa98e2SPeter Wemm 	**	Check to make sure the hop count is reasonable.
239c2aa98e2SPeter Wemm 	**	Delete sends to the sender in mailing lists.
240c2aa98e2SPeter Wemm 	*/
241c2aa98e2SPeter Wemm 
242c2aa98e2SPeter Wemm 	CurEnv = e;
243c2aa98e2SPeter Wemm 	if (tTd(62, 1))
244c2aa98e2SPeter Wemm 		checkfds(NULL);
245c2aa98e2SPeter Wemm 
246c2aa98e2SPeter Wemm 	if (e->e_hopcount > MaxHopCount)
247c2aa98e2SPeter Wemm 	{
2488774250cSGregory Neil Shapiro 		char *recip;
2498774250cSGregory Neil Shapiro 
2508774250cSGregory Neil Shapiro 		if (e->e_sendqueue != NULL &&
2518774250cSGregory Neil Shapiro 		    e->e_sendqueue->q_paddr != NULL)
2528774250cSGregory Neil Shapiro 			recip = e->e_sendqueue->q_paddr;
2538774250cSGregory Neil Shapiro 		else
2548774250cSGregory Neil Shapiro 			recip = "(nobody)";
2558774250cSGregory Neil Shapiro 
256c2aa98e2SPeter Wemm 		errno = 0;
2572fb4f839SGregory Neil Shapiro 		queueup(e, WILL_BE_QUEUED(mode) ? QUP_FL_ANNOUNCE : QUP_FL_NONE);
258c2aa98e2SPeter Wemm 		e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
25906f25ae9SGregory Neil Shapiro 		ExitStat = EX_UNAVAILABLE;
2608774250cSGregory Neil Shapiro 		syserr("554 5.4.6 Too many hops %d (%d max): from %s via %s, to %s",
261c2aa98e2SPeter Wemm 		       e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
262c2aa98e2SPeter Wemm 		       RealHostName == NULL ? "localhost" : RealHostName,
2638774250cSGregory Neil Shapiro 		       recip);
26406f25ae9SGregory Neil Shapiro 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
26506f25ae9SGregory Neil Shapiro 		{
26606f25ae9SGregory Neil Shapiro 			if (QS_IS_DEAD(q->q_state))
26706f25ae9SGregory Neil Shapiro 				continue;
26806f25ae9SGregory Neil Shapiro 			q->q_state = QS_BADADDR;
26906f25ae9SGregory Neil Shapiro 			q->q_status = "5.4.6";
2708774250cSGregory Neil Shapiro 			q->q_rstatus = "554 5.4.6 Too many hops";
27106f25ae9SGregory Neil Shapiro 		}
272c2aa98e2SPeter Wemm 		return;
273c2aa98e2SPeter Wemm 	}
274c2aa98e2SPeter Wemm 
275c2aa98e2SPeter Wemm 	/*
276c2aa98e2SPeter Wemm 	**  Do sender deletion.
277c2aa98e2SPeter Wemm 	**
27806f25ae9SGregory Neil Shapiro 	**	If the sender should be queued up, skip this.
279c2aa98e2SPeter Wemm 	**	This can happen if the name server is hosed when you
280c2aa98e2SPeter Wemm 	**	are trying to send mail.  The result is that the sender
281c2aa98e2SPeter Wemm 	**	is instantiated in the queue as a recipient.
282c2aa98e2SPeter Wemm 	*/
283c2aa98e2SPeter Wemm 
284c2aa98e2SPeter Wemm 	if (!bitset(EF_METOO, e->e_flags) &&
28506f25ae9SGregory Neil Shapiro 	    !QS_IS_QUEUEUP(e->e_from.q_state))
286c2aa98e2SPeter Wemm 	{
287c2aa98e2SPeter Wemm 		if (tTd(13, 5))
288c2aa98e2SPeter Wemm 		{
28940266059SGregory Neil Shapiro 			sm_dprintf("sendall: QS_SENDER ");
290e92d3f3fSGregory Neil Shapiro 			printaddr(sm_debug_file(), &e->e_from, false);
291c2aa98e2SPeter Wemm 		}
29206f25ae9SGregory Neil Shapiro 		e->e_from.q_state = QS_SENDER;
293c2aa98e2SPeter Wemm 		(void) recipient(&e->e_from, &e->e_sendqueue, 0, e);
294c2aa98e2SPeter Wemm 	}
295c2aa98e2SPeter Wemm 
296c2aa98e2SPeter Wemm 	/*
297c2aa98e2SPeter Wemm 	**  Handle alias owners.
298c2aa98e2SPeter Wemm 	**
299c2aa98e2SPeter Wemm 	**	We scan up the q_alias chain looking for owners.
300c2aa98e2SPeter Wemm 	**	We discard owners that are the same as the return path.
301c2aa98e2SPeter Wemm 	*/
302c2aa98e2SPeter Wemm 
303c2aa98e2SPeter Wemm 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
304c2aa98e2SPeter Wemm 	{
305c2aa98e2SPeter Wemm 		register struct address *a;
306c2aa98e2SPeter Wemm 
307c2aa98e2SPeter Wemm 		for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias)
308c2aa98e2SPeter Wemm 			continue;
309c2aa98e2SPeter Wemm 		if (a != NULL)
310c2aa98e2SPeter Wemm 			q->q_owner = a->q_owner;
311c2aa98e2SPeter Wemm 
312c2aa98e2SPeter Wemm 		if (q->q_owner != NULL &&
31306f25ae9SGregory Neil Shapiro 		    !QS_IS_DEAD(q->q_state) &&
314c2aa98e2SPeter Wemm 		    strcmp(q->q_owner, e->e_from.q_paddr) == 0)
315c2aa98e2SPeter Wemm 			q->q_owner = NULL;
316c2aa98e2SPeter Wemm 	}
317c2aa98e2SPeter Wemm 
318c2aa98e2SPeter Wemm 	if (tTd(13, 25))
319c2aa98e2SPeter Wemm 	{
32040266059SGregory Neil Shapiro 		sm_dprintf("\nAfter first owner pass, sendq =\n");
321e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), e->e_sendqueue, true);
322c2aa98e2SPeter Wemm 	}
323c2aa98e2SPeter Wemm 
324c2aa98e2SPeter Wemm 	owner = "";
325c2aa98e2SPeter Wemm 	otherowners = 1;
326c2aa98e2SPeter Wemm 	while (owner != NULL && otherowners > 0)
327c2aa98e2SPeter Wemm 	{
328c2aa98e2SPeter Wemm 		if (tTd(13, 28))
32940266059SGregory Neil Shapiro 			sm_dprintf("owner = \"%s\", otherowners = %d\n",
330c2aa98e2SPeter Wemm 				   owner, otherowners);
331c2aa98e2SPeter Wemm 		owner = NULL;
332c2aa98e2SPeter Wemm 		otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0;
333c2aa98e2SPeter Wemm 
334c2aa98e2SPeter Wemm 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
335c2aa98e2SPeter Wemm 		{
336c2aa98e2SPeter Wemm 			if (tTd(13, 30))
337c2aa98e2SPeter Wemm 			{
33840266059SGregory Neil Shapiro 				sm_dprintf("Checking ");
339e92d3f3fSGregory Neil Shapiro 				printaddr(sm_debug_file(), q, false);
340c2aa98e2SPeter Wemm 			}
34106f25ae9SGregory Neil Shapiro 			if (QS_IS_DEAD(q->q_state))
342c2aa98e2SPeter Wemm 			{
343c2aa98e2SPeter Wemm 				if (tTd(13, 30))
34440266059SGregory Neil Shapiro 					sm_dprintf("    ... QS_IS_DEAD\n");
345c2aa98e2SPeter Wemm 				continue;
346c2aa98e2SPeter Wemm 			}
347c2aa98e2SPeter Wemm 			if (tTd(13, 29) && !tTd(13, 30))
348c2aa98e2SPeter Wemm 			{
34940266059SGregory Neil Shapiro 				sm_dprintf("Checking ");
350e92d3f3fSGregory Neil Shapiro 				printaddr(sm_debug_file(), q, false);
351c2aa98e2SPeter Wemm 			}
352c2aa98e2SPeter Wemm 
353c2aa98e2SPeter Wemm 			if (q->q_owner != NULL)
354c2aa98e2SPeter Wemm 			{
355c2aa98e2SPeter Wemm 				if (owner == NULL)
356c2aa98e2SPeter Wemm 				{
357c2aa98e2SPeter Wemm 					if (tTd(13, 40))
35840266059SGregory Neil Shapiro 						sm_dprintf("    ... First owner = \"%s\"\n",
359c2aa98e2SPeter Wemm 							   q->q_owner);
360c2aa98e2SPeter Wemm 					owner = q->q_owner;
361c2aa98e2SPeter Wemm 				}
362c2aa98e2SPeter Wemm 				else if (owner != q->q_owner)
363c2aa98e2SPeter Wemm 				{
364c2aa98e2SPeter Wemm 					if (strcmp(owner, q->q_owner) == 0)
365c2aa98e2SPeter Wemm 					{
366c2aa98e2SPeter Wemm 						if (tTd(13, 40))
36740266059SGregory Neil Shapiro 							sm_dprintf("    ... Same owner = \"%s\"\n",
368c2aa98e2SPeter Wemm 								   owner);
369c2aa98e2SPeter Wemm 
370c2aa98e2SPeter Wemm 						/* make future comparisons cheap */
371c2aa98e2SPeter Wemm 						q->q_owner = owner;
372c2aa98e2SPeter Wemm 					}
373c2aa98e2SPeter Wemm 					else
374c2aa98e2SPeter Wemm 					{
375c2aa98e2SPeter Wemm 						if (tTd(13, 40))
37640266059SGregory Neil Shapiro 							sm_dprintf("    ... Another owner \"%s\"\n",
377c2aa98e2SPeter Wemm 								   q->q_owner);
378c2aa98e2SPeter Wemm 						otherowners++;
379c2aa98e2SPeter Wemm 					}
380c2aa98e2SPeter Wemm 					owner = q->q_owner;
381c2aa98e2SPeter Wemm 				}
382c2aa98e2SPeter Wemm 				else if (tTd(13, 40))
38340266059SGregory Neil Shapiro 					sm_dprintf("    ... Same owner = \"%s\"\n",
384c2aa98e2SPeter Wemm 						   owner);
385c2aa98e2SPeter Wemm 			}
386c2aa98e2SPeter Wemm 			else
387c2aa98e2SPeter Wemm 			{
388c2aa98e2SPeter Wemm 				if (tTd(13, 40))
38940266059SGregory Neil Shapiro 					sm_dprintf("    ... Null owner\n");
390c2aa98e2SPeter Wemm 				otherowners++;
391c2aa98e2SPeter Wemm 			}
392c2aa98e2SPeter Wemm 
39306f25ae9SGregory Neil Shapiro 			if (QS_IS_BADADDR(q->q_state))
39406f25ae9SGregory Neil Shapiro 			{
39506f25ae9SGregory Neil Shapiro 				if (tTd(13, 30))
39640266059SGregory Neil Shapiro 					sm_dprintf("    ... QS_IS_BADADDR\n");
39706f25ae9SGregory Neil Shapiro 				continue;
39806f25ae9SGregory Neil Shapiro 			}
39906f25ae9SGregory Neil Shapiro 
40006f25ae9SGregory Neil Shapiro 			if (QS_IS_QUEUEUP(q->q_state))
40106f25ae9SGregory Neil Shapiro 			{
40206f25ae9SGregory Neil Shapiro 				MAILER *m = q->q_mailer;
40306f25ae9SGregory Neil Shapiro 
40406f25ae9SGregory Neil Shapiro 				/*
40506f25ae9SGregory Neil Shapiro 				**  If we have temporary address failures
40606f25ae9SGregory Neil Shapiro 				**  (e.g., dns failure) and a fallback MX is
40706f25ae9SGregory Neil Shapiro 				**  set, send directly to the fallback MX host.
40806f25ae9SGregory Neil Shapiro 				*/
40906f25ae9SGregory Neil Shapiro 
410e92d3f3fSGregory Neil Shapiro 				if (FallbackMX != NULL &&
411e92d3f3fSGregory Neil Shapiro 				    !wordinclass(FallbackMX, 'w') &&
41206f25ae9SGregory Neil Shapiro 				    mode != SM_VERIFY &&
41340266059SGregory Neil Shapiro 				    !bitnset(M_NOMX, m->m_flags) &&
41440266059SGregory Neil Shapiro 				    strcmp(m->m_mailer, "[IPC]") == 0 &&
41506f25ae9SGregory Neil Shapiro 				    m->m_argv[0] != NULL &&
41640266059SGregory Neil Shapiro 				    strcmp(m->m_argv[0], "TCP") == 0)
41706f25ae9SGregory Neil Shapiro 				{
41806f25ae9SGregory Neil Shapiro 					int len;
41906f25ae9SGregory Neil Shapiro 					char *p;
42006f25ae9SGregory Neil Shapiro 
42106f25ae9SGregory Neil Shapiro 					if (tTd(13, 30))
422e92d3f3fSGregory Neil Shapiro 						sm_dprintf("    ... FallbackMX\n");
42306f25ae9SGregory Neil Shapiro 
424e92d3f3fSGregory Neil Shapiro 					len = strlen(FallbackMX) + 1;
42540266059SGregory Neil Shapiro 					p = sm_rpool_malloc_x(e->e_rpool, len);
426e92d3f3fSGregory Neil Shapiro 					(void) sm_strlcpy(p, FallbackMX, len);
42706f25ae9SGregory Neil Shapiro 					q->q_state = QS_OK;
42806f25ae9SGregory Neil Shapiro 					q->q_host = p;
42906f25ae9SGregory Neil Shapiro 				}
43006f25ae9SGregory Neil Shapiro 				else
43106f25ae9SGregory Neil Shapiro 				{
43206f25ae9SGregory Neil Shapiro 					if (tTd(13, 30))
43340266059SGregory Neil Shapiro 						sm_dprintf("    ... QS_IS_QUEUEUP\n");
43406f25ae9SGregory Neil Shapiro 					continue;
43506f25ae9SGregory Neil Shapiro 				}
43606f25ae9SGregory Neil Shapiro 			}
43706f25ae9SGregory Neil Shapiro 
438c2aa98e2SPeter Wemm 			/*
439c2aa98e2SPeter Wemm 			**  If this mailer is expensive, and if we don't
440c2aa98e2SPeter Wemm 			**  want to make connections now, just mark these
441c2aa98e2SPeter Wemm 			**  addresses and return.  This is useful if we
442c2aa98e2SPeter Wemm 			**  want to batch connections to reduce load.  This
443c2aa98e2SPeter Wemm 			**  will cause the messages to be queued up, and a
444c2aa98e2SPeter Wemm 			**  daemon will come along to send the messages later.
445c2aa98e2SPeter Wemm 			*/
446c2aa98e2SPeter Wemm 
447c2aa98e2SPeter Wemm 			if (NoConnect && !Verbose &&
448c2aa98e2SPeter Wemm 			    bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
449c2aa98e2SPeter Wemm 			{
450c2aa98e2SPeter Wemm 				if (tTd(13, 30))
45140266059SGregory Neil Shapiro 					sm_dprintf("    ... expensive\n");
45206f25ae9SGregory Neil Shapiro 				q->q_state = QS_QUEUEUP;
45340266059SGregory Neil Shapiro 				expensive = true;
45406f25ae9SGregory Neil Shapiro 			}
45506f25ae9SGregory Neil Shapiro 			else if (bitnset(M_HOLD, q->q_mailer->m_flags) &&
45606f25ae9SGregory Neil Shapiro 				 QueueLimitId == NULL &&
45706f25ae9SGregory Neil Shapiro 				 QueueLimitSender == NULL &&
45806f25ae9SGregory Neil Shapiro 				 QueueLimitRecipient == NULL)
45906f25ae9SGregory Neil Shapiro 			{
46006f25ae9SGregory Neil Shapiro 				if (tTd(13, 30))
46140266059SGregory Neil Shapiro 					sm_dprintf("    ... hold\n");
46206f25ae9SGregory Neil Shapiro 				q->q_state = QS_QUEUEUP;
46340266059SGregory Neil Shapiro 				expensive = true;
464c2aa98e2SPeter Wemm 			}
46540266059SGregory Neil Shapiro 			else if (QueueMode != QM_QUARANTINE &&
46640266059SGregory Neil Shapiro 				 e->e_quarmsg != NULL)
46740266059SGregory Neil Shapiro 			{
46840266059SGregory Neil Shapiro 				if (tTd(13, 30))
46940266059SGregory Neil Shapiro 					sm_dprintf("    ... quarantine: %s\n",
47040266059SGregory Neil Shapiro 						   e->e_quarmsg);
47140266059SGregory Neil Shapiro 				q->q_state = QS_QUEUEUP;
47240266059SGregory Neil Shapiro 				expensive = true;
47340266059SGregory Neil Shapiro 			}
474c2aa98e2SPeter Wemm 			else
475c2aa98e2SPeter Wemm 			{
476c2aa98e2SPeter Wemm 				if (tTd(13, 30))
47740266059SGregory Neil Shapiro 					sm_dprintf("    ... deliverable\n");
47840266059SGregory Neil Shapiro 				somedeliveries = true;
479c2aa98e2SPeter Wemm 			}
480c2aa98e2SPeter Wemm 		}
481c2aa98e2SPeter Wemm 
482c2aa98e2SPeter Wemm 		if (owner != NULL && otherowners > 0)
483c2aa98e2SPeter Wemm 		{
484c2aa98e2SPeter Wemm 			/*
485c2aa98e2SPeter Wemm 			**  Split this envelope into two.
486c2aa98e2SPeter Wemm 			*/
487c2aa98e2SPeter Wemm 
48840266059SGregory Neil Shapiro 			ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool,
489d0cef73dSGregory Neil Shapiro 							    sizeof(*ee));
49040266059SGregory Neil Shapiro 			STRUCTCOPY(*e, *ee);
49106f25ae9SGregory Neil Shapiro 			ee->e_message = NULL;
492c2aa98e2SPeter Wemm 			ee->e_id = NULL;
49306f25ae9SGregory Neil Shapiro 			assign_queueid(ee);
494c2aa98e2SPeter Wemm 
495c2aa98e2SPeter Wemm 			if (tTd(13, 1))
49640266059SGregory Neil Shapiro 				sm_dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n",
49740266059SGregory Neil Shapiro 					   e->e_id, ee->e_id, owner,
49840266059SGregory Neil Shapiro 					   otherowners);
499c2aa98e2SPeter Wemm 
50040266059SGregory Neil Shapiro 			ee->e_header = copyheader(e->e_header, ee->e_rpool);
50140266059SGregory Neil Shapiro 			ee->e_sendqueue = copyqueue(e->e_sendqueue,
50240266059SGregory Neil Shapiro 						    ee->e_rpool);
50340266059SGregory Neil Shapiro 			ee->e_errorqueue = copyqueue(e->e_errorqueue,
50440266059SGregory Neil Shapiro 						     ee->e_rpool);
505c2aa98e2SPeter Wemm 			ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM);
506c2aa98e2SPeter Wemm 			ee->e_flags |= EF_NORECEIPT;
50740266059SGregory Neil Shapiro 			setsender(owner, ee, NULL, '\0', true);
508c2aa98e2SPeter Wemm 			if (tTd(13, 5))
509c2aa98e2SPeter Wemm 			{
51040266059SGregory Neil Shapiro 				sm_dprintf("sendall(split): QS_SENDER ");
511e92d3f3fSGregory Neil Shapiro 				printaddr(sm_debug_file(), &ee->e_from, false);
512c2aa98e2SPeter Wemm 			}
51306f25ae9SGregory Neil Shapiro 			ee->e_from.q_state = QS_SENDER;
514c2aa98e2SPeter Wemm 			ee->e_dfp = NULL;
51506f25ae9SGregory Neil Shapiro 			ee->e_lockfp = NULL;
516c2aa98e2SPeter Wemm 			ee->e_xfp = NULL;
51740266059SGregory Neil Shapiro 			ee->e_qgrp = e->e_qgrp;
51840266059SGregory Neil Shapiro 			ee->e_qdir = e->e_qdir;
519c2aa98e2SPeter Wemm 			ee->e_errormode = EM_MAIL;
520c2aa98e2SPeter Wemm 			ee->e_sibling = splitenv;
52106f25ae9SGregory Neil Shapiro 			ee->e_statmsg = NULL;
52240266059SGregory Neil Shapiro 			if (e->e_quarmsg != NULL)
52340266059SGregory Neil Shapiro 				ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
52440266059SGregory Neil Shapiro 								  e->e_quarmsg);
525c2aa98e2SPeter Wemm 			splitenv = ee;
526c2aa98e2SPeter Wemm 
527c2aa98e2SPeter Wemm 			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
528c2aa98e2SPeter Wemm 			{
529c2aa98e2SPeter Wemm 				if (q->q_owner == owner)
530c2aa98e2SPeter Wemm 				{
53106f25ae9SGregory Neil Shapiro 					q->q_state = QS_CLONED;
532c2aa98e2SPeter Wemm 					if (tTd(13, 6))
53340266059SGregory Neil Shapiro 						sm_dprintf("\t... stripping %s from original envelope\n",
534c2aa98e2SPeter Wemm 							   q->q_paddr);
535c2aa98e2SPeter Wemm 				}
536c2aa98e2SPeter Wemm 			}
537c2aa98e2SPeter Wemm 			for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
538c2aa98e2SPeter Wemm 			{
539c2aa98e2SPeter Wemm 				if (q->q_owner != owner)
540c2aa98e2SPeter Wemm 				{
54106f25ae9SGregory Neil Shapiro 					q->q_state = QS_CLONED;
542c2aa98e2SPeter Wemm 					if (tTd(13, 6))
54340266059SGregory Neil Shapiro 						sm_dprintf("\t... dropping %s from cloned envelope\n",
544c2aa98e2SPeter Wemm 							   q->q_paddr);
545c2aa98e2SPeter Wemm 				}
546c2aa98e2SPeter Wemm 				else
547c2aa98e2SPeter Wemm 				{
548c2aa98e2SPeter Wemm 					/* clear DSN parameters */
549c2aa98e2SPeter Wemm 					q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
550c2aa98e2SPeter Wemm 					q->q_flags |= DefaultNotify & ~QPINGONSUCCESS;
551c2aa98e2SPeter Wemm 					if (tTd(13, 6))
55240266059SGregory Neil Shapiro 						sm_dprintf("\t... moving %s to cloned envelope\n",
553c2aa98e2SPeter Wemm 							   q->q_paddr);
554c2aa98e2SPeter Wemm 				}
555c2aa98e2SPeter Wemm 			}
556c2aa98e2SPeter Wemm 
557c2aa98e2SPeter Wemm 			if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags))
55840266059SGregory Neil Shapiro 				dup_queue_file(e, ee, DATAFL_LETTER);
55906f25ae9SGregory Neil Shapiro 
56006f25ae9SGregory Neil Shapiro 			/*
56106f25ae9SGregory Neil Shapiro 			**  Give the split envelope access to the parent
56206f25ae9SGregory Neil Shapiro 			**  transcript file for errors obtained while
56306f25ae9SGregory Neil Shapiro 			**  processing the recipients (done before the
56406f25ae9SGregory Neil Shapiro 			**  envelope splitting).
56506f25ae9SGregory Neil Shapiro 			*/
56606f25ae9SGregory Neil Shapiro 
56706f25ae9SGregory Neil Shapiro 			if (e->e_xfp != NULL)
56840266059SGregory Neil Shapiro 				ee->e_xfp = sm_io_dup(e->e_xfp);
56906f25ae9SGregory Neil Shapiro 
57006f25ae9SGregory Neil Shapiro 			/* failed to dup e->e_xfp, start a new transcript */
57106f25ae9SGregory Neil Shapiro 			if (ee->e_xfp == NULL)
572c2aa98e2SPeter Wemm 				openxscript(ee);
57306f25ae9SGregory Neil Shapiro 
574065a643dSPeter Wemm 			if (mode != SM_VERIFY && LogLevel > 4)
57540266059SGregory Neil Shapiro 				sm_syslog(LOG_INFO, e->e_id,
57640266059SGregory Neil Shapiro 					  "%s: clone: owner=%s",
57740266059SGregory Neil Shapiro 					  ee->e_id, owner);
578c2aa98e2SPeter Wemm 		}
579c2aa98e2SPeter Wemm 	}
580c2aa98e2SPeter Wemm 
581c2aa98e2SPeter Wemm 	if (owner != NULL)
582c2aa98e2SPeter Wemm 	{
58340266059SGregory Neil Shapiro 		setsender(owner, e, NULL, '\0', true);
584c2aa98e2SPeter Wemm 		if (tTd(13, 5))
585c2aa98e2SPeter Wemm 		{
58640266059SGregory Neil Shapiro 			sm_dprintf("sendall(owner): QS_SENDER ");
587e92d3f3fSGregory Neil Shapiro 			printaddr(sm_debug_file(), &e->e_from, false);
588c2aa98e2SPeter Wemm 		}
58906f25ae9SGregory Neil Shapiro 		e->e_from.q_state = QS_SENDER;
590c2aa98e2SPeter Wemm 		e->e_errormode = EM_MAIL;
591c2aa98e2SPeter Wemm 		e->e_flags |= EF_NORECEIPT;
592c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_FATALERRS;
593c2aa98e2SPeter Wemm 	}
594c2aa98e2SPeter Wemm 
595c2aa98e2SPeter Wemm 	/* if nothing to be delivered, just queue up everything */
59640266059SGregory Neil Shapiro 	if (!somedeliveries && !WILL_BE_QUEUED(mode) &&
597c2aa98e2SPeter Wemm 	    mode != SM_VERIFY)
598c2aa98e2SPeter Wemm 	{
59940266059SGregory Neil Shapiro 		time_t now;
600193538b7SGregory Neil Shapiro 
601c2aa98e2SPeter Wemm 		if (tTd(13, 29))
602ffb83623SGregory Neil Shapiro 			sm_dprintf("No deliveries: auto-queueing\n");
603c2aa98e2SPeter Wemm 		mode = SM_QUEUE;
60440266059SGregory Neil Shapiro 		now = curtime();
605c2aa98e2SPeter Wemm 
606c2aa98e2SPeter Wemm 		/* treat this as a delivery in terms of counting tries */
607193538b7SGregory Neil Shapiro 		e->e_dtime = now;
608c2aa98e2SPeter Wemm 		if (!expensive)
609c2aa98e2SPeter Wemm 			e->e_ntries++;
610c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
611c2aa98e2SPeter Wemm 		{
612193538b7SGregory Neil Shapiro 			ee->e_dtime = now;
613c2aa98e2SPeter Wemm 			if (!expensive)
614c2aa98e2SPeter Wemm 				ee->e_ntries++;
615c2aa98e2SPeter Wemm 		}
616c2aa98e2SPeter Wemm 	}
617c2aa98e2SPeter Wemm 
61840266059SGregory Neil Shapiro 	if ((WILL_BE_QUEUED(mode) || mode == SM_FORK ||
619e92d3f3fSGregory Neil Shapiro 	     (mode != SM_VERIFY &&
620e92d3f3fSGregory Neil Shapiro 	      (SuperSafe == SAFE_REALLY ||
621e92d3f3fSGregory Neil Shapiro 	       SuperSafe == SAFE_REALLY_POSTMILTER))) &&
622c2aa98e2SPeter Wemm 	    (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL))
623c2aa98e2SPeter Wemm 	{
6242fb4f839SGregory Neil Shapiro 		unsigned int qup_flags;
62540266059SGregory Neil Shapiro 
62642e5d165SGregory Neil Shapiro 		/*
62742e5d165SGregory Neil Shapiro 		**  Be sure everything is instantiated in the queue.
62842e5d165SGregory Neil Shapiro 		**  Split envelopes first in case the machine crashes.
62942e5d165SGregory Neil Shapiro 		**  If the original were done first, we may lose
63042e5d165SGregory Neil Shapiro 		**  recipients.
63142e5d165SGregory Neil Shapiro 		*/
63242e5d165SGregory Neil Shapiro 
6332fb4f839SGregory Neil Shapiro 		if (WILL_BE_QUEUED(mode))
6342fb4f839SGregory Neil Shapiro 			qup_flags = QUP_FL_ANNOUNCE;
6352fb4f839SGregory Neil Shapiro 		else
6362fb4f839SGregory Neil Shapiro 			qup_flags = QUP_FL_NONE;
6372fb4f839SGregory Neil Shapiro #if HASFLOCK
6382fb4f839SGregory Neil Shapiro 		if (mode == SM_FORK)
6392fb4f839SGregory Neil Shapiro 			qup_flags |= QUP_FL_MSYNC;
6405b0945b5SGregory Neil Shapiro #endif
64140266059SGregory Neil Shapiro 
642c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
6432fb4f839SGregory Neil Shapiro 			queueup(ee, qup_flags);
6442fb4f839SGregory Neil Shapiro 		queueup(e, qup_flags);
645c2aa98e2SPeter Wemm 	}
646c2aa98e2SPeter Wemm 
647c2aa98e2SPeter Wemm 	if (tTd(62, 10))
648c2aa98e2SPeter Wemm 		checkfds("after envelope splitting");
649c2aa98e2SPeter Wemm 
650c2aa98e2SPeter Wemm 	/*
651c2aa98e2SPeter Wemm 	**  If we belong in background, fork now.
652c2aa98e2SPeter Wemm 	*/
653c2aa98e2SPeter Wemm 
654c2aa98e2SPeter Wemm 	if (tTd(13, 20))
655c2aa98e2SPeter Wemm 	{
65640266059SGregory Neil Shapiro 		sm_dprintf("sendall: final mode = %c\n", mode);
657c2aa98e2SPeter Wemm 		if (tTd(13, 21))
658c2aa98e2SPeter Wemm 		{
65940266059SGregory Neil Shapiro 			sm_dprintf("\n================ Final Send Queue(s) =====================\n");
66040266059SGregory Neil Shapiro 			sm_dprintf("\n  *** Envelope %s, e_from=%s ***\n",
661c2aa98e2SPeter Wemm 				   e->e_id, e->e_from.q_paddr);
662e92d3f3fSGregory Neil Shapiro 			printaddr(sm_debug_file(), e->e_sendqueue, true);
663c2aa98e2SPeter Wemm 			for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
664c2aa98e2SPeter Wemm 			{
66540266059SGregory Neil Shapiro 				sm_dprintf("\n  *** Envelope %s, e_from=%s ***\n",
666c2aa98e2SPeter Wemm 					   ee->e_id, ee->e_from.q_paddr);
667e92d3f3fSGregory Neil Shapiro 				printaddr(sm_debug_file(), ee->e_sendqueue, true);
668c2aa98e2SPeter Wemm 			}
66940266059SGregory Neil Shapiro 			sm_dprintf("==========================================================\n\n");
670c2aa98e2SPeter Wemm 		}
671c2aa98e2SPeter Wemm 	}
672c2aa98e2SPeter Wemm 	switch (mode)
673c2aa98e2SPeter Wemm 	{
674c2aa98e2SPeter Wemm 	  case SM_VERIFY:
675c2aa98e2SPeter Wemm 		Verbose = 2;
676c2aa98e2SPeter Wemm 		break;
677c2aa98e2SPeter Wemm 
678c2aa98e2SPeter Wemm 	  case SM_QUEUE:
679c2aa98e2SPeter Wemm 	  case SM_DEFER:
680c2aa98e2SPeter Wemm #if HASFLOCK
681c2aa98e2SPeter Wemm   queueonly:
6825b0945b5SGregory Neil Shapiro #endif
683c2aa98e2SPeter Wemm 		if (e->e_nrcpts > 0)
684c2aa98e2SPeter Wemm 			e->e_flags |= EF_INQUEUE;
6859bd497b8SGregory Neil Shapiro 		(void) dropenvelope(e, splitenv != NULL, true);
686c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
687c2aa98e2SPeter Wemm 		{
688c2aa98e2SPeter Wemm 			if (ee->e_nrcpts > 0)
689c2aa98e2SPeter Wemm 				ee->e_flags |= EF_INQUEUE;
6909bd497b8SGregory Neil Shapiro 			(void) dropenvelope(ee, false, true);
691c2aa98e2SPeter Wemm 		}
692c2aa98e2SPeter Wemm 		return;
693c2aa98e2SPeter Wemm 
694c2aa98e2SPeter Wemm 	  case SM_FORK:
695c2aa98e2SPeter Wemm 		if (e->e_xfp != NULL)
69640266059SGregory Neil Shapiro 			(void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
697c2aa98e2SPeter Wemm 
698c2aa98e2SPeter Wemm #if !HASFLOCK
699c2aa98e2SPeter Wemm 		/*
700c2aa98e2SPeter Wemm 		**  Since fcntl locking has the interesting semantic that
701c2aa98e2SPeter Wemm 		**  the lock is owned by a process, not by an open file
702c2aa98e2SPeter Wemm 		**  descriptor, we have to flush this to the queue, and
703c2aa98e2SPeter Wemm 		**  then restart from scratch in the child.
704c2aa98e2SPeter Wemm 		*/
705c2aa98e2SPeter Wemm 
706c2aa98e2SPeter Wemm 		{
707c2aa98e2SPeter Wemm 			/* save id for future use */
708c2aa98e2SPeter Wemm 			char *qid = e->e_id;
709c2aa98e2SPeter Wemm 
710c2aa98e2SPeter Wemm 			/* now drop the envelope in the parent */
711c2aa98e2SPeter Wemm 			e->e_flags |= EF_INQUEUE;
7129bd497b8SGregory Neil Shapiro 			(void) dropenvelope(e, splitenv != NULL, false);
713c2aa98e2SPeter Wemm 
714c2aa98e2SPeter Wemm 			/* arrange to reacquire lock after fork */
715c2aa98e2SPeter Wemm 			e->e_id = qid;
716c2aa98e2SPeter Wemm 		}
717c2aa98e2SPeter Wemm 
718c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
719c2aa98e2SPeter Wemm 		{
720c2aa98e2SPeter Wemm 			/* save id for future use */
721c2aa98e2SPeter Wemm 			char *qid = ee->e_id;
722c2aa98e2SPeter Wemm 
723c2aa98e2SPeter Wemm 			/* drop envelope in parent */
724c2aa98e2SPeter Wemm 			ee->e_flags |= EF_INQUEUE;
7259bd497b8SGregory Neil Shapiro 			(void) dropenvelope(ee, false, false);
726c2aa98e2SPeter Wemm 
727c2aa98e2SPeter Wemm 			/* and save qid for reacquisition */
728c2aa98e2SPeter Wemm 			ee->e_id = qid;
729c2aa98e2SPeter Wemm 		}
730e92d3f3fSGregory Neil Shapiro 
731c2aa98e2SPeter Wemm #endif /* !HASFLOCK */
732c2aa98e2SPeter Wemm 
73306f25ae9SGregory Neil Shapiro 		/*
73406f25ae9SGregory Neil Shapiro 		**  Since the delivery may happen in a child and the parent
73506f25ae9SGregory Neil Shapiro 		**  does not wait, the parent may close the maps thereby
73606f25ae9SGregory Neil Shapiro 		**  removing any shared memory used by the map.  Therefore,
73706f25ae9SGregory Neil Shapiro 		**  close the maps now so the child will dynamically open
73806f25ae9SGregory Neil Shapiro 		**  them if necessary.
73906f25ae9SGregory Neil Shapiro 		*/
74006f25ae9SGregory Neil Shapiro 
74140266059SGregory Neil Shapiro 		closemaps(false);
74206f25ae9SGregory Neil Shapiro 
743c2aa98e2SPeter Wemm 		pid = fork();
744c2aa98e2SPeter Wemm 		if (pid < 0)
745c2aa98e2SPeter Wemm 		{
74606f25ae9SGregory Neil Shapiro 			syserr("deliver: fork 1");
747c2aa98e2SPeter Wemm #if HASFLOCK
748c2aa98e2SPeter Wemm 			goto queueonly;
74906f25ae9SGregory Neil Shapiro #else /* HASFLOCK */
750c2aa98e2SPeter Wemm 			e->e_id = NULL;
751c2aa98e2SPeter Wemm 			for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
752c2aa98e2SPeter Wemm 				ee->e_id = NULL;
753c2aa98e2SPeter Wemm 			return;
754c2aa98e2SPeter Wemm #endif /* HASFLOCK */
755c2aa98e2SPeter Wemm 		}
756c2aa98e2SPeter Wemm 		else if (pid > 0)
757c2aa98e2SPeter Wemm 		{
758c2aa98e2SPeter Wemm #if HASFLOCK
759c2aa98e2SPeter Wemm 			/* be sure we leave the temp files to our child */
760c2aa98e2SPeter Wemm 			/* close any random open files in the envelope */
761c2aa98e2SPeter Wemm 			closexscript(e);
7622fb4f839SGregory Neil Shapiro 			SM_CLOSE_FP(e->e_dfp);
763c2aa98e2SPeter Wemm 			e->e_flags &= ~EF_HAS_DF;
764c2aa98e2SPeter Wemm 
765c2aa98e2SPeter Wemm 			/* can't call unlockqueue to avoid unlink of xfp */
766c2aa98e2SPeter Wemm 			if (e->e_lockfp != NULL)
76740266059SGregory Neil Shapiro 				(void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
76806f25ae9SGregory Neil Shapiro 			else
76906f25ae9SGregory Neil Shapiro 				syserr("%s: sendall: null lockfp", e->e_id);
770c2aa98e2SPeter Wemm 			e->e_lockfp = NULL;
77106f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */
772c2aa98e2SPeter Wemm 
773c2aa98e2SPeter Wemm 			/* make sure the parent doesn't own the envelope */
774c2aa98e2SPeter Wemm 			e->e_id = NULL;
775c2aa98e2SPeter Wemm 
77640266059SGregory Neil Shapiro #if USE_DOUBLE_FORK
777c2aa98e2SPeter Wemm 			/* catch intermediate zombie */
778c2aa98e2SPeter Wemm 			(void) waitfor(pid);
7795b0945b5SGregory Neil Shapiro #endif
780c2aa98e2SPeter Wemm 			return;
781c2aa98e2SPeter Wemm 		}
782c2aa98e2SPeter Wemm 
7838774250cSGregory Neil Shapiro 		/* Reset global flags */
7848774250cSGregory Neil Shapiro 		RestartRequest = NULL;
78540266059SGregory Neil Shapiro 		RestartWorkGroup = false;
7868774250cSGregory Neil Shapiro 		ShutdownRequest = NULL;
7878774250cSGregory Neil Shapiro 		PendingSignal = 0;
7888774250cSGregory Neil Shapiro 
78942e5d165SGregory Neil Shapiro 		/*
79040266059SGregory Neil Shapiro 		**  Initialize exception stack and default exception
79140266059SGregory Neil Shapiro 		**  handler for child process.
79240266059SGregory Neil Shapiro 		*/
79340266059SGregory Neil Shapiro 
79440266059SGregory Neil Shapiro 		sm_exc_newthread(fatal_error);
79540266059SGregory Neil Shapiro 
79640266059SGregory Neil Shapiro 		/*
79742e5d165SGregory Neil Shapiro 		**  Since we have accepted responsbility for the message,
79842e5d165SGregory Neil Shapiro 		**  change the SIGTERM handler.  intsig() (the old handler)
79942e5d165SGregory Neil Shapiro 		**  would remove the envelope if this was a command line
80042e5d165SGregory Neil Shapiro 		**  message submission.
80142e5d165SGregory Neil Shapiro 		*/
80242e5d165SGregory Neil Shapiro 
80340266059SGregory Neil Shapiro 		(void) sm_signal(SIGTERM, SIG_DFL);
80442e5d165SGregory Neil Shapiro 
80540266059SGregory Neil Shapiro #if USE_DOUBLE_FORK
806c2aa98e2SPeter Wemm 		/* double fork to avoid zombies */
807c2aa98e2SPeter Wemm 		pid = fork();
808c2aa98e2SPeter Wemm 		if (pid > 0)
809c2aa98e2SPeter Wemm 			exit(EX_OK);
81006f25ae9SGregory Neil Shapiro 		save_errno = errno;
81140266059SGregory Neil Shapiro #endif /* USE_DOUBLE_FORK */
81240266059SGregory Neil Shapiro 
81340266059SGregory Neil Shapiro 		CurrentPid = getpid();
814c2aa98e2SPeter Wemm 
815c2aa98e2SPeter Wemm 		/* be sure we are immune from the terminal */
816c2aa98e2SPeter Wemm 		disconnect(2, e);
81706f25ae9SGregory Neil Shapiro 		clearstats();
818c2aa98e2SPeter Wemm 
819c2aa98e2SPeter Wemm 		/* prevent parent from waiting if there was an error */
820c2aa98e2SPeter Wemm 		if (pid < 0)
821c2aa98e2SPeter Wemm 		{
82206f25ae9SGregory Neil Shapiro 			errno = save_errno;
82306f25ae9SGregory Neil Shapiro 			syserr("deliver: fork 2");
824c2aa98e2SPeter Wemm #if HASFLOCK
825c2aa98e2SPeter Wemm 			e->e_flags |= EF_INQUEUE;
8265b0945b5SGregory Neil Shapiro #else
827c2aa98e2SPeter Wemm 			e->e_id = NULL;
8285b0945b5SGregory Neil Shapiro #endif
82940266059SGregory Neil Shapiro 			finis(true, true, ExitStat);
830c2aa98e2SPeter Wemm 		}
831c2aa98e2SPeter Wemm 
832c2aa98e2SPeter Wemm 		/* be sure to give error messages in child */
83340266059SGregory Neil Shapiro 		QuickAbort = false;
834c2aa98e2SPeter Wemm 
835c2aa98e2SPeter Wemm 		/*
836c2aa98e2SPeter Wemm 		**  Close any cached connections.
837c2aa98e2SPeter Wemm 		**
838c2aa98e2SPeter Wemm 		**	We don't send the QUIT protocol because the parent
839c2aa98e2SPeter Wemm 		**	still knows about the connection.
840c2aa98e2SPeter Wemm 		**
841c2aa98e2SPeter Wemm 		**	This should only happen when delivering an error
842c2aa98e2SPeter Wemm 		**	message.
843c2aa98e2SPeter Wemm 		*/
844c2aa98e2SPeter Wemm 
84540266059SGregory Neil Shapiro 		mci_flush(false, NULL);
846c2aa98e2SPeter Wemm 
847c2aa98e2SPeter Wemm #if HASFLOCK
848c2aa98e2SPeter Wemm 		break;
84906f25ae9SGregory Neil Shapiro #else /* HASFLOCK */
850c2aa98e2SPeter Wemm 
851c2aa98e2SPeter Wemm 		/*
852c2aa98e2SPeter Wemm 		**  Now reacquire and run the various queue files.
853c2aa98e2SPeter Wemm 		*/
854c2aa98e2SPeter Wemm 
855c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
856c2aa98e2SPeter Wemm 		{
857c2aa98e2SPeter Wemm 			ENVELOPE *sibling = ee->e_sibling;
858c2aa98e2SPeter Wemm 
85940266059SGregory Neil Shapiro 			(void) dowork(ee->e_qgrp, ee->e_qdir, ee->e_id,
86040266059SGregory Neil Shapiro 				      false, false, ee);
861c2aa98e2SPeter Wemm 			ee->e_sibling = sibling;
862c2aa98e2SPeter Wemm 		}
86340266059SGregory Neil Shapiro 		(void) dowork(e->e_qgrp, e->e_qdir, e->e_id,
86440266059SGregory Neil Shapiro 			      false, false, e);
86540266059SGregory Neil Shapiro 		finis(true, true, ExitStat);
86606f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */
867c2aa98e2SPeter Wemm 	}
868c2aa98e2SPeter Wemm 
869c2aa98e2SPeter Wemm 	sendenvelope(e, mode);
8709bd497b8SGregory Neil Shapiro 	(void) dropenvelope(e, true, true);
871c2aa98e2SPeter Wemm 	for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
872c2aa98e2SPeter Wemm 	{
873c2aa98e2SPeter Wemm 		CurEnv = ee;
874c2aa98e2SPeter Wemm 		if (mode != SM_VERIFY)
875c2aa98e2SPeter Wemm 			openxscript(ee);
876c2aa98e2SPeter Wemm 		sendenvelope(ee, mode);
8779bd497b8SGregory Neil Shapiro 		(void) dropenvelope(ee, true, true);
878c2aa98e2SPeter Wemm 	}
879c2aa98e2SPeter Wemm 	CurEnv = e;
880c2aa98e2SPeter Wemm 
881c2aa98e2SPeter Wemm 	Verbose = oldverbose;
882c2aa98e2SPeter Wemm 	if (mode == SM_FORK)
88340266059SGregory Neil Shapiro 		finis(true, true, ExitStat);
884c2aa98e2SPeter Wemm }
885c2aa98e2SPeter Wemm 
88606f25ae9SGregory Neil Shapiro static void
sendenvelope(e,mode)887c2aa98e2SPeter Wemm sendenvelope(e, mode)
888c2aa98e2SPeter Wemm 	register ENVELOPE *e;
889c2aa98e2SPeter Wemm 	int mode;
890c2aa98e2SPeter Wemm {
891c2aa98e2SPeter Wemm 	register ADDRESS *q;
892c2aa98e2SPeter Wemm 	bool didany;
893c2aa98e2SPeter Wemm 
894c2aa98e2SPeter Wemm 	if (tTd(13, 10))
89540266059SGregory Neil Shapiro 		sm_dprintf("sendenvelope(%s) e_flags=0x%lx\n",
896c2aa98e2SPeter Wemm 			   e->e_id == NULL ? "[NOQUEUE]" : e->e_id,
897c2aa98e2SPeter Wemm 			   e->e_flags);
898c2aa98e2SPeter Wemm 	if (LogLevel > 80)
899c2aa98e2SPeter Wemm 		sm_syslog(LOG_DEBUG, e->e_id,
90006f25ae9SGregory Neil Shapiro 			  "sendenvelope, flags=0x%lx",
901c2aa98e2SPeter Wemm 			  e->e_flags);
902c2aa98e2SPeter Wemm 
903c2aa98e2SPeter Wemm 	/*
904c2aa98e2SPeter Wemm 	**  If we have had global, fatal errors, don't bother sending
905c2aa98e2SPeter Wemm 	**  the message at all if we are in SMTP mode.  Local errors
906c2aa98e2SPeter Wemm 	**  (e.g., a single address failing) will still cause the other
907c2aa98e2SPeter Wemm 	**  addresses to be sent.
908c2aa98e2SPeter Wemm 	*/
909c2aa98e2SPeter Wemm 
910c2aa98e2SPeter Wemm 	if (bitset(EF_FATALERRS, e->e_flags) &&
911c2aa98e2SPeter Wemm 	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
912c2aa98e2SPeter Wemm 	{
913c2aa98e2SPeter Wemm 		e->e_flags |= EF_CLRQUEUE;
914c2aa98e2SPeter Wemm 		return;
915c2aa98e2SPeter Wemm 	}
916c2aa98e2SPeter Wemm 
91740266059SGregory Neil Shapiro 	/*
91840266059SGregory Neil Shapiro 	**  Don't attempt deliveries if we want to bounce now
91940266059SGregory Neil Shapiro 	**  or if deliver-by time is exceeded.
92040266059SGregory Neil Shapiro 	*/
92140266059SGregory Neil Shapiro 
92206f25ae9SGregory Neil Shapiro 	if (!bitset(EF_RESPONSE, e->e_flags) &&
92340266059SGregory Neil Shapiro 	    (TimeOuts.to_q_return[e->e_timeoutclass] == NOW ||
92440266059SGregory Neil Shapiro 	     (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 &&
92540266059SGregory Neil Shapiro 	      curtime() > e->e_ctime + e->e_deliver_by)))
92606f25ae9SGregory Neil Shapiro 		return;
92706f25ae9SGregory Neil Shapiro 
928c2aa98e2SPeter Wemm 	/*
929c2aa98e2SPeter Wemm 	**  Run through the list and send everything.
930c2aa98e2SPeter Wemm 	**
931c2aa98e2SPeter Wemm 	**	Set EF_GLOBALERRS so that error messages during delivery
932c2aa98e2SPeter Wemm 	**	result in returned mail.
933c2aa98e2SPeter Wemm 	*/
934c2aa98e2SPeter Wemm 
935c2aa98e2SPeter Wemm 	e->e_nsent = 0;
936c2aa98e2SPeter Wemm 	e->e_flags |= EF_GLOBALERRS;
93706f25ae9SGregory Neil Shapiro 
93840266059SGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, macid("{envid}"), e->e_envid);
93940266059SGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, macid("{bodytype}"), e->e_bodytype);
94040266059SGregory Neil Shapiro 	didany = false;
94140266059SGregory Neil Shapiro 
94240266059SGregory Neil Shapiro 	if (!bitset(EF_SPLIT, e->e_flags))
94340266059SGregory Neil Shapiro 	{
94440266059SGregory Neil Shapiro 		ENVELOPE *oldsib;
94540266059SGregory Neil Shapiro 		ENVELOPE *ee;
94640266059SGregory Neil Shapiro 
94740266059SGregory Neil Shapiro 		/*
94840266059SGregory Neil Shapiro 		**  Save old sibling and set it to NULL to avoid
94940266059SGregory Neil Shapiro 		**  queueing up the same envelopes again.
95040266059SGregory Neil Shapiro 		**  This requires that envelopes in that list have
95140266059SGregory Neil Shapiro 		**  been take care of before (or at some other place).
95240266059SGregory Neil Shapiro 		*/
95340266059SGregory Neil Shapiro 
95440266059SGregory Neil Shapiro 		oldsib = e->e_sibling;
95540266059SGregory Neil Shapiro 		e->e_sibling = NULL;
95640266059SGregory Neil Shapiro 		if (!split_by_recipient(e) &&
95740266059SGregory Neil Shapiro 		    bitset(EF_FATALERRS, e->e_flags))
95840266059SGregory Neil Shapiro 		{
95940266059SGregory Neil Shapiro 			if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
96040266059SGregory Neil Shapiro 				e->e_flags |= EF_CLRQUEUE;
96140266059SGregory Neil Shapiro 			return;
96240266059SGregory Neil Shapiro 		}
96340266059SGregory Neil Shapiro 		for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
9642fb4f839SGregory Neil Shapiro 			queueup(ee, QUP_FL_MSYNC);
96540266059SGregory Neil Shapiro 
96640266059SGregory Neil Shapiro 		/* clean up */
96740266059SGregory Neil Shapiro 		for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
96840266059SGregory Neil Shapiro 		{
96940266059SGregory Neil Shapiro 			/* now unlock the job */
97040266059SGregory Neil Shapiro 			closexscript(ee);
97140266059SGregory Neil Shapiro 			unlockqueue(ee);
97240266059SGregory Neil Shapiro 
97340266059SGregory Neil Shapiro 			/* this envelope is marked unused */
9742fb4f839SGregory Neil Shapiro 			SM_CLOSE_FP(ee->e_dfp);
97540266059SGregory Neil Shapiro 			ee->e_id = NULL;
97640266059SGregory Neil Shapiro 			ee->e_flags &= ~EF_HAS_DF;
97740266059SGregory Neil Shapiro 		}
97840266059SGregory Neil Shapiro 		e->e_sibling = oldsib;
97940266059SGregory Neil Shapiro 	}
980c2aa98e2SPeter Wemm 
981c2aa98e2SPeter Wemm 	/* now run through the queue */
982c2aa98e2SPeter Wemm 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
983c2aa98e2SPeter Wemm 	{
984c2aa98e2SPeter Wemm #if XDEBUG
9852fb4f839SGregory Neil Shapiro 		char wbuf[MAXNAME + 20]; /* EAI: might be too short, but that's ok for debugging */
986c2aa98e2SPeter Wemm 
987d0cef73dSGregory Neil Shapiro 		(void) sm_snprintf(wbuf, sizeof(wbuf), "sendall(%.*s)",
9882fb4f839SGregory Neil Shapiro 				   MAXNAME, q->q_paddr); /* EAI: see above */
989c2aa98e2SPeter Wemm 		checkfd012(wbuf);
99006f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
991c2aa98e2SPeter Wemm 		if (mode == SM_VERIFY)
992c2aa98e2SPeter Wemm 		{
993c2aa98e2SPeter Wemm 			e->e_to = q->q_paddr;
99406f25ae9SGregory Neil Shapiro 			if (QS_IS_SENDABLE(q->q_state))
995c2aa98e2SPeter Wemm 			{
996c2aa98e2SPeter Wemm 				if (q->q_host != NULL && q->q_host[0] != '\0')
997c2aa98e2SPeter Wemm 					message("deliverable: mailer %s, host %s, user %s",
998c2aa98e2SPeter Wemm 						q->q_mailer->m_name,
999c2aa98e2SPeter Wemm 						q->q_host,
1000c2aa98e2SPeter Wemm 						q->q_user);
1001c2aa98e2SPeter Wemm 				else
1002c2aa98e2SPeter Wemm 					message("deliverable: mailer %s, user %s",
1003c2aa98e2SPeter Wemm 						q->q_mailer->m_name,
1004c2aa98e2SPeter Wemm 						q->q_user);
1005c2aa98e2SPeter Wemm 			}
1006c2aa98e2SPeter Wemm 		}
100706f25ae9SGregory Neil Shapiro 		else if (QS_IS_OK(q->q_state))
1008c2aa98e2SPeter Wemm 		{
1009c2aa98e2SPeter Wemm 			/*
1010c2aa98e2SPeter Wemm 			**  Checkpoint the send list every few addresses
1011c2aa98e2SPeter Wemm 			*/
1012c2aa98e2SPeter Wemm 
101342e5d165SGregory Neil Shapiro 			if (CheckpointInterval > 0 &&
101442e5d165SGregory Neil Shapiro 			    e->e_nsent >= CheckpointInterval)
1015c2aa98e2SPeter Wemm 			{
10162fb4f839SGregory Neil Shapiro 				queueup(e, QUP_FL_NONE);
1017c2aa98e2SPeter Wemm 				e->e_nsent = 0;
1018c2aa98e2SPeter Wemm 			}
1019c2aa98e2SPeter Wemm 			(void) deliver(e, q);
102040266059SGregory Neil Shapiro 			didany = true;
1021c2aa98e2SPeter Wemm 		}
1022c2aa98e2SPeter Wemm 	}
1023c2aa98e2SPeter Wemm 	if (didany)
1024c2aa98e2SPeter Wemm 	{
1025c2aa98e2SPeter Wemm 		e->e_dtime = curtime();
1026c2aa98e2SPeter Wemm 		e->e_ntries++;
1027c2aa98e2SPeter Wemm 	}
1028c2aa98e2SPeter Wemm 
1029c2aa98e2SPeter Wemm #if XDEBUG
1030c2aa98e2SPeter Wemm 	checkfd012("end of sendenvelope");
10315b0945b5SGregory Neil Shapiro #endif
1032c2aa98e2SPeter Wemm }
103340266059SGregory Neil Shapiro 
103440266059SGregory Neil Shapiro #if REQUIRES_DIR_FSYNC
103540266059SGregory Neil Shapiro /*
103640266059SGregory Neil Shapiro **  SYNC_DIR -- fsync a directory based on a filename
103740266059SGregory Neil Shapiro **
103840266059SGregory Neil Shapiro **	Parameters:
103940266059SGregory Neil Shapiro **		filename -- path of file
104040266059SGregory Neil Shapiro **		panic -- panic?
104140266059SGregory Neil Shapiro **
104240266059SGregory Neil Shapiro **	Returns:
104340266059SGregory Neil Shapiro **		none
104440266059SGregory Neil Shapiro */
104540266059SGregory Neil Shapiro 
104640266059SGregory Neil Shapiro void
sync_dir(filename,panic)104740266059SGregory Neil Shapiro sync_dir(filename, panic)
104840266059SGregory Neil Shapiro 	char *filename;
104940266059SGregory Neil Shapiro 	bool panic;
105040266059SGregory Neil Shapiro {
105140266059SGregory Neil Shapiro 	int dirfd;
105240266059SGregory Neil Shapiro 	char *dirp;
105340266059SGregory Neil Shapiro 	char dir[MAXPATHLEN];
105440266059SGregory Neil Shapiro 
105513bd1963SGregory Neil Shapiro 	if (!RequiresDirfsync)
105613bd1963SGregory Neil Shapiro 		return;
105713bd1963SGregory Neil Shapiro 
105840266059SGregory Neil Shapiro 	/* filesystems which require the directory be synced */
105940266059SGregory Neil Shapiro 	dirp = strrchr(filename, '/');
106040266059SGregory Neil Shapiro 	if (dirp != NULL)
106140266059SGregory Neil Shapiro 	{
1062d0cef73dSGregory Neil Shapiro 		if (sm_strlcpy(dir, filename, sizeof(dir)) >= sizeof(dir))
106340266059SGregory Neil Shapiro 			return;
106440266059SGregory Neil Shapiro 		dir[dirp - filename] = '\0';
106540266059SGregory Neil Shapiro 		dirp = dir;
106640266059SGregory Neil Shapiro 	}
106740266059SGregory Neil Shapiro 	else
106840266059SGregory Neil Shapiro 		dirp = ".";
106940266059SGregory Neil Shapiro 	dirfd = open(dirp, O_RDONLY, 0700);
107040266059SGregory Neil Shapiro 	if (tTd(40,32))
107140266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, NOQID, "sync_dir: %s: fsync(%d)",
107240266059SGregory Neil Shapiro 			  dirp, dirfd);
107340266059SGregory Neil Shapiro 	if (dirfd >= 0)
107440266059SGregory Neil Shapiro 	{
107540266059SGregory Neil Shapiro 		if (fsync(dirfd) < 0)
107640266059SGregory Neil Shapiro 		{
107740266059SGregory Neil Shapiro 			if (panic)
107840266059SGregory Neil Shapiro 				syserr("!sync_dir: cannot fsync directory %s",
107940266059SGregory Neil Shapiro 				       dirp);
108040266059SGregory Neil Shapiro 			else if (LogLevel > 1)
108140266059SGregory Neil Shapiro 				sm_syslog(LOG_ERR, NOQID,
108240266059SGregory Neil Shapiro 					  "sync_dir: cannot fsync directory %s: %s",
108340266059SGregory Neil Shapiro 					  dirp, sm_errstring(errno));
108440266059SGregory Neil Shapiro 		}
108540266059SGregory Neil Shapiro 		(void) close(dirfd);
108640266059SGregory Neil Shapiro 	}
108740266059SGregory Neil Shapiro }
108840266059SGregory Neil Shapiro #endif /* REQUIRES_DIR_FSYNC */
108940266059SGregory Neil Shapiro /*
1090c2aa98e2SPeter Wemm **  DUP_QUEUE_FILE -- duplicate a queue file into a split queue
1091c2aa98e2SPeter Wemm **
1092c2aa98e2SPeter Wemm **	Parameters:
1093c2aa98e2SPeter Wemm **		e -- the existing envelope
1094c2aa98e2SPeter Wemm **		ee -- the new envelope
109540266059SGregory Neil Shapiro **		type -- the queue file type (e.g., DATAFL_LETTER)
1096c2aa98e2SPeter Wemm **
1097c2aa98e2SPeter Wemm **	Returns:
1098c2aa98e2SPeter Wemm **		none
1099c2aa98e2SPeter Wemm */
1100c2aa98e2SPeter Wemm 
110106f25ae9SGregory Neil Shapiro static void
dup_queue_file(e,ee,type)1102c2aa98e2SPeter Wemm dup_queue_file(e, ee, type)
110340266059SGregory Neil Shapiro 	ENVELOPE *e, *ee;
1104c2aa98e2SPeter Wemm 	int type;
1105c2aa98e2SPeter Wemm {
110606f25ae9SGregory Neil Shapiro 	char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN];
1107c2aa98e2SPeter Wemm 
1108c2aa98e2SPeter Wemm 	ee->e_dfp = NULL;
1109c2aa98e2SPeter Wemm 	ee->e_xfp = NULL;
111006f25ae9SGregory Neil Shapiro 
111106f25ae9SGregory Neil Shapiro 	/*
111206f25ae9SGregory Neil Shapiro 	**  Make sure both are in the same directory.
111306f25ae9SGregory Neil Shapiro 	*/
111406f25ae9SGregory Neil Shapiro 
1115d0cef73dSGregory Neil Shapiro 	(void) sm_strlcpy(f1buf, queuename(e, type), sizeof(f1buf));
1116d0cef73dSGregory Neil Shapiro 	(void) sm_strlcpy(f2buf, queuename(ee, type), sizeof(f2buf));
1117959366dcSGregory Neil Shapiro 
1118959366dcSGregory Neil Shapiro 	/* Force the df to disk if it's not there yet */
1119959366dcSGregory Neil Shapiro 	if (type == DATAFL_LETTER && e->e_dfp != NULL &&
1120959366dcSGregory Neil Shapiro 	    sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 &&
1121959366dcSGregory Neil Shapiro 	    errno != EINVAL)
1122959366dcSGregory Neil Shapiro 	{
1123959366dcSGregory Neil Shapiro 		syserr("!dup_queue_file: can't commit %s", f1buf);
1124959366dcSGregory Neil Shapiro 		/* NOTREACHED */
1125959366dcSGregory Neil Shapiro 	}
1126959366dcSGregory Neil Shapiro 
1127c2aa98e2SPeter Wemm 	if (link(f1buf, f2buf) < 0)
1128c2aa98e2SPeter Wemm 	{
112906f25ae9SGregory Neil Shapiro 		int save_errno = errno;
1130c2aa98e2SPeter Wemm 
1131c2aa98e2SPeter Wemm 		syserr("sendall: link(%s, %s)", f1buf, f2buf);
113206f25ae9SGregory Neil Shapiro 		if (save_errno == EEXIST)
1133c2aa98e2SPeter Wemm 		{
1134c2aa98e2SPeter Wemm 			if (unlink(f2buf) < 0)
1135c2aa98e2SPeter Wemm 			{
1136c2aa98e2SPeter Wemm 				syserr("!sendall: unlink(%s): permanent",
1137c2aa98e2SPeter Wemm 				       f2buf);
1138c2aa98e2SPeter Wemm 				/* NOTREACHED */
1139c2aa98e2SPeter Wemm 			}
1140c2aa98e2SPeter Wemm 			if (link(f1buf, f2buf) < 0)
1141c2aa98e2SPeter Wemm 			{
1142c2aa98e2SPeter Wemm 				syserr("!sendall: link(%s, %s): permanent",
1143c2aa98e2SPeter Wemm 				       f1buf, f2buf);
1144c2aa98e2SPeter Wemm 				/* NOTREACHED */
1145c2aa98e2SPeter Wemm 			}
1146c2aa98e2SPeter Wemm 		}
1147c2aa98e2SPeter Wemm 	}
114840266059SGregory Neil Shapiro 	SYNC_DIR(f2buf, true);
1149c2aa98e2SPeter Wemm }
115040266059SGregory Neil Shapiro /*
1151c2aa98e2SPeter Wemm **  DOFORK -- do a fork, retrying a couple of times on failure.
1152c2aa98e2SPeter Wemm **
1153c2aa98e2SPeter Wemm **	This MUST be a macro, since after a vfork we are running
1154c2aa98e2SPeter Wemm **	two processes on the same stack!!!
1155c2aa98e2SPeter Wemm **
1156c2aa98e2SPeter Wemm **	Parameters:
1157c2aa98e2SPeter Wemm **		none.
1158c2aa98e2SPeter Wemm **
1159c2aa98e2SPeter Wemm **	Returns:
1160c2aa98e2SPeter Wemm **		From a macro???  You've got to be kidding!
1161c2aa98e2SPeter Wemm **
1162c2aa98e2SPeter Wemm **	Side Effects:
1163c2aa98e2SPeter Wemm **		Modifies the ==> LOCAL <== variable 'pid', leaving:
1164c2aa98e2SPeter Wemm **			pid of child in parent, zero in child.
1165c2aa98e2SPeter Wemm **			-1 on unrecoverable error.
1166c2aa98e2SPeter Wemm **
1167c2aa98e2SPeter Wemm **	Notes:
1168c2aa98e2SPeter Wemm **		I'm awfully sorry this looks so awful.  That's
1169c2aa98e2SPeter Wemm **		vfork for you.....
1170c2aa98e2SPeter Wemm */
1171c2aa98e2SPeter Wemm 
1172c2aa98e2SPeter Wemm #define NFORKTRIES	5
1173c2aa98e2SPeter Wemm 
1174c2aa98e2SPeter Wemm #ifndef FORK
1175c2aa98e2SPeter Wemm # define FORK	fork
11765b0945b5SGregory Neil Shapiro #endif
1177c2aa98e2SPeter Wemm 
1178c2aa98e2SPeter Wemm #define DOFORK(fORKfN) \
1179c2aa98e2SPeter Wemm {\
1180c2aa98e2SPeter Wemm 	register int i;\
1181c2aa98e2SPeter Wemm \
1182c2aa98e2SPeter Wemm 	for (i = NFORKTRIES; --i >= 0; )\
1183c2aa98e2SPeter Wemm 	{\
1184c2aa98e2SPeter Wemm 		pid = fORKfN();\
1185c2aa98e2SPeter Wemm 		if (pid >= 0)\
1186c2aa98e2SPeter Wemm 			break;\
1187c2aa98e2SPeter Wemm 		if (i > 0)\
118806f25ae9SGregory Neil Shapiro 			(void) sleep((unsigned) NFORKTRIES - i);\
1189c2aa98e2SPeter Wemm 	}\
1190c2aa98e2SPeter Wemm }
119140266059SGregory Neil Shapiro /*
1192c2aa98e2SPeter Wemm **  DOFORK -- simple fork interface to DOFORK.
1193c2aa98e2SPeter Wemm **
1194c2aa98e2SPeter Wemm **	Parameters:
1195c2aa98e2SPeter Wemm **		none.
1196c2aa98e2SPeter Wemm **
1197c2aa98e2SPeter Wemm **	Returns:
1198c2aa98e2SPeter Wemm **		pid of child in parent.
1199c2aa98e2SPeter Wemm **		zero in child.
1200c2aa98e2SPeter Wemm **		-1 on error.
1201c2aa98e2SPeter Wemm **
1202c2aa98e2SPeter Wemm **	Side Effects:
1203c2aa98e2SPeter Wemm **		returns twice, once in parent and once in child.
1204c2aa98e2SPeter Wemm */
1205c2aa98e2SPeter Wemm 
12068774250cSGregory Neil Shapiro pid_t
dofork()1207c2aa98e2SPeter Wemm dofork()
1208c2aa98e2SPeter Wemm {
1209c2aa98e2SPeter Wemm 	register pid_t pid = -1;
1210c2aa98e2SPeter Wemm 
1211c2aa98e2SPeter Wemm 	DOFORK(fork);
121206f25ae9SGregory Neil Shapiro 	return pid;
1213c2aa98e2SPeter Wemm }
121440266059SGregory Neil Shapiro 
121540266059SGregory Neil Shapiro /*
121640266059SGregory Neil Shapiro **  COLONCMP -- compare host-signatures up to first ':' or EOS
121740266059SGregory Neil Shapiro **
121840266059SGregory Neil Shapiro **	This takes two strings which happen to be host-signatures and
121940266059SGregory Neil Shapiro **	compares them. If the lowest preference portions of the MX-RR's
122040266059SGregory Neil Shapiro **	match (up to ':' or EOS, whichever is first), then we have
122140266059SGregory Neil Shapiro **	match. This is used for coattail-piggybacking messages during
122240266059SGregory Neil Shapiro **	message delivery.
122340266059SGregory Neil Shapiro **	If the signatures are the same up to the first ':' the remainder of
122440266059SGregory Neil Shapiro **	the signatures are then compared with a normal strcmp(). This saves
122540266059SGregory Neil Shapiro **	re-examining the first part of the signatures.
122640266059SGregory Neil Shapiro **
122740266059SGregory Neil Shapiro **	Parameters:
122840266059SGregory Neil Shapiro **		a - first host-signature
122940266059SGregory Neil Shapiro **		b - second host-signature
123040266059SGregory Neil Shapiro **
123140266059SGregory Neil Shapiro **	Returns:
123240266059SGregory Neil Shapiro **		HS_MATCH_NO -- no "match".
123340266059SGregory Neil Shapiro **		HS_MATCH_FIRST -- "match" for the first MX preference
123440266059SGregory Neil Shapiro **			(up to the first colon (':')).
123540266059SGregory Neil Shapiro **		HS_MATCH_FULL -- match for the entire MX record.
1236*d39bd2c1SGregory Neil Shapiro **		HS_MATCH_SKIP -- match but only one of the entries has a "mark"
123740266059SGregory Neil Shapiro **
123840266059SGregory Neil Shapiro **	Side Effects:
123940266059SGregory Neil Shapiro **		none.
124040266059SGregory Neil Shapiro */
124140266059SGregory Neil Shapiro 
124240266059SGregory Neil Shapiro #define HS_MATCH_NO	0
124340266059SGregory Neil Shapiro #define HS_MATCH_FIRST	1
124440266059SGregory Neil Shapiro #define HS_MATCH_FULL	2
1245*d39bd2c1SGregory Neil Shapiro #define HS_MATCH_SKIP	4
124640266059SGregory Neil Shapiro 
124740266059SGregory Neil Shapiro static int
coloncmp(a,b)124840266059SGregory Neil Shapiro coloncmp(a, b)
124940266059SGregory Neil Shapiro 	register const char *a;
125040266059SGregory Neil Shapiro 	register const char *b;
125140266059SGregory Neil Shapiro {
125240266059SGregory Neil Shapiro 	int ret = HS_MATCH_NO;
125340266059SGregory Neil Shapiro 	int braclev = 0;
1254*d39bd2c1SGregory Neil Shapiro # if HSMARKS
1255*d39bd2c1SGregory Neil Shapiro 	bool a_hsmark = false;
1256*d39bd2c1SGregory Neil Shapiro 	bool b_hsmark = false;
125740266059SGregory Neil Shapiro 
1258*d39bd2c1SGregory Neil Shapiro 	if (HSM_AD == *a)
1259*d39bd2c1SGregory Neil Shapiro 	{
1260*d39bd2c1SGregory Neil Shapiro 		a_hsmark = true;
1261*d39bd2c1SGregory Neil Shapiro 		++a;
1262*d39bd2c1SGregory Neil Shapiro 	}
1263*d39bd2c1SGregory Neil Shapiro 	if (HSM_AD == *b)
1264*d39bd2c1SGregory Neil Shapiro 	{
1265*d39bd2c1SGregory Neil Shapiro 		b_hsmark = true;
1266*d39bd2c1SGregory Neil Shapiro 		++b;
1267*d39bd2c1SGregory Neil Shapiro 	}
1268*d39bd2c1SGregory Neil Shapiro # endif
126940266059SGregory Neil Shapiro 	while (*a == *b++)
127040266059SGregory Neil Shapiro 	{
127140266059SGregory Neil Shapiro 		/* Need to account for IPv6 bracketed addresses */
127240266059SGregory Neil Shapiro 		if (*a == '[')
127340266059SGregory Neil Shapiro 			braclev++;
12745ef517c0SGregory Neil Shapiro 		else if (*a == ']' && braclev > 0)
127540266059SGregory Neil Shapiro 			braclev--;
127640266059SGregory Neil Shapiro 		else if (*a == ':' && braclev <= 0)
127740266059SGregory Neil Shapiro 		{
127840266059SGregory Neil Shapiro 			ret = HS_MATCH_FIRST;
127940266059SGregory Neil Shapiro 			a++;
128040266059SGregory Neil Shapiro 			break;
128140266059SGregory Neil Shapiro 		}
128240266059SGregory Neil Shapiro 		else if (*a == '\0')
1283*d39bd2c1SGregory Neil Shapiro 		{
1284*d39bd2c1SGregory Neil Shapiro # if HSMARKS
1285*d39bd2c1SGregory Neil Shapiro 			/* exactly one mark */
1286*d39bd2c1SGregory Neil Shapiro 			if (a_hsmark != b_hsmark)
1287*d39bd2c1SGregory Neil Shapiro 				return HS_MATCH_SKIP;
1288*d39bd2c1SGregory Neil Shapiro # endif
128940266059SGregory Neil Shapiro 			return HS_MATCH_FULL; /* a full match */
1290*d39bd2c1SGregory Neil Shapiro 		}
129140266059SGregory Neil Shapiro 		a++;
129240266059SGregory Neil Shapiro 	}
129340266059SGregory Neil Shapiro 	if (ret == HS_MATCH_NO &&
129440266059SGregory Neil Shapiro 	    braclev <= 0 &&
129540266059SGregory Neil Shapiro 	    ((*a == '\0' && *(b - 1) == ':') ||
129640266059SGregory Neil Shapiro 	     (*a == ':' && *(b - 1) == '\0')))
129740266059SGregory Neil Shapiro 		return HS_MATCH_FIRST;
129840266059SGregory Neil Shapiro 	if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0)
1299*d39bd2c1SGregory Neil Shapiro 	{
1300*d39bd2c1SGregory Neil Shapiro # if HSMARKS
1301*d39bd2c1SGregory Neil Shapiro 		/* exactly one mark */
1302*d39bd2c1SGregory Neil Shapiro 		if (a_hsmark != b_hsmark)
1303*d39bd2c1SGregory Neil Shapiro 			return HS_MATCH_SKIP;
1304*d39bd2c1SGregory Neil Shapiro # endif
130540266059SGregory Neil Shapiro 		return HS_MATCH_FULL;
1306*d39bd2c1SGregory Neil Shapiro 	}
130740266059SGregory Neil Shapiro 
130840266059SGregory Neil Shapiro 	return ret;
130940266059SGregory Neil Shapiro }
1310e92d3f3fSGregory Neil Shapiro 
1311e92d3f3fSGregory Neil Shapiro /*
1312e92d3f3fSGregory Neil Shapiro **  SHOULD_TRY_FBSH -- Should try FallbackSmartHost?
1313e92d3f3fSGregory Neil Shapiro **
1314e92d3f3fSGregory Neil Shapiro **	Parameters:
1315e92d3f3fSGregory Neil Shapiro **		e -- envelope
1316e92d3f3fSGregory Neil Shapiro **		tried_fallbacksmarthost -- has been tried already? (in/out)
1317e92d3f3fSGregory Neil Shapiro **		hostbuf -- buffer for hostname (expand FallbackSmartHost) (out)
1318e92d3f3fSGregory Neil Shapiro **		hbsz -- size of hostbuf
1319e92d3f3fSGregory Neil Shapiro **		status -- current delivery status
1320e92d3f3fSGregory Neil Shapiro **
1321e92d3f3fSGregory Neil Shapiro **	Returns:
1322e92d3f3fSGregory Neil Shapiro **		true iff FallbackSmartHost should be tried.
1323e92d3f3fSGregory Neil Shapiro */
1324e92d3f3fSGregory Neil Shapiro 
1325d0cef73dSGregory Neil Shapiro static bool should_try_fbsh __P((ENVELOPE *, bool *, char *, size_t, int));
1326d0cef73dSGregory Neil Shapiro 
1327e92d3f3fSGregory Neil Shapiro static bool
should_try_fbsh(e,tried_fallbacksmarthost,hostbuf,hbsz,status)1328e92d3f3fSGregory Neil Shapiro should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status)
1329e92d3f3fSGregory Neil Shapiro 	ENVELOPE *e;
1330e92d3f3fSGregory Neil Shapiro 	bool *tried_fallbacksmarthost;
1331e92d3f3fSGregory Neil Shapiro 	char *hostbuf;
1332e92d3f3fSGregory Neil Shapiro 	size_t hbsz;
1333e92d3f3fSGregory Neil Shapiro 	int status;
1334e92d3f3fSGregory Neil Shapiro {
1335e92d3f3fSGregory Neil Shapiro 	/*
13364e4196cbSGregory Neil Shapiro 	**  If the host was not found or a temporary failure occurred
13374e4196cbSGregory Neil Shapiro 	**  and a FallbackSmartHost is defined (and we have not yet
13384e4196cbSGregory Neil Shapiro 	**  tried it), then make one last try with it as the host.
1339e92d3f3fSGregory Neil Shapiro 	*/
1340e92d3f3fSGregory Neil Shapiro 
13414e4196cbSGregory Neil Shapiro 	if ((status == EX_NOHOST || status == EX_TEMPFAIL) &&
13424e4196cbSGregory Neil Shapiro 	    FallbackSmartHost != NULL && !*tried_fallbacksmarthost)
1343e92d3f3fSGregory Neil Shapiro 	{
1344e92d3f3fSGregory Neil Shapiro 		*tried_fallbacksmarthost = true;
1345e92d3f3fSGregory Neil Shapiro 		expand(FallbackSmartHost, hostbuf, hbsz, e);
1346e92d3f3fSGregory Neil Shapiro 		if (!wordinclass(hostbuf, 'w'))
1347e92d3f3fSGregory Neil Shapiro 		{
1348e92d3f3fSGregory Neil Shapiro 			if (tTd(11, 1))
1349e92d3f3fSGregory Neil Shapiro 				sm_dprintf("one last try with FallbackSmartHost %s\n",
1350e92d3f3fSGregory Neil Shapiro 					   hostbuf);
1351e92d3f3fSGregory Neil Shapiro 			return true;
1352e92d3f3fSGregory Neil Shapiro 		}
1353e92d3f3fSGregory Neil Shapiro 	}
1354e92d3f3fSGregory Neil Shapiro 	return false;
1355e92d3f3fSGregory Neil Shapiro }
1356da7d7b9cSGregory Neil Shapiro 
1357*d39bd2c1SGregory Neil Shapiro #if STARTTLS || SASL
135840266059SGregory Neil Shapiro /*
13592fb4f839SGregory Neil Shapiro **  CLTFEATURES -- Get features for SMTP client
13602fb4f839SGregory Neil Shapiro **
13612fb4f839SGregory Neil Shapiro **	Parameters:
13622fb4f839SGregory Neil Shapiro **		e -- envelope
1363*d39bd2c1SGregory Neil Shapiro **		servername -- name of server.
13642fb4f839SGregory Neil Shapiro **
13652fb4f839SGregory Neil Shapiro **	Returns:
13662fb4f839SGregory Neil Shapiro **		EX_OK or EX_TEMPFAIL
13672fb4f839SGregory Neil Shapiro */
13682fb4f839SGregory Neil Shapiro 
13692fb4f839SGregory Neil Shapiro static int cltfeatures __P((ENVELOPE *, char *));
13702fb4f839SGregory Neil Shapiro static int
cltfeatures(e,servername)1371*d39bd2c1SGregory Neil Shapiro cltfeatures(e, servername)
13722fb4f839SGregory Neil Shapiro 	ENVELOPE *e;
1373*d39bd2c1SGregory Neil Shapiro 	char *servername;
13742fb4f839SGregory Neil Shapiro {
13752fb4f839SGregory Neil Shapiro 	int r, i, idx;
13762fb4f839SGregory Neil Shapiro 	char **pvp, c;
13772fb4f839SGregory Neil Shapiro 	char pvpbuf[PSBUFSIZE];
13782fb4f839SGregory Neil Shapiro 	char flags[64];	/* XXX */
13792fb4f839SGregory Neil Shapiro 
13802fb4f839SGregory Neil Shapiro 	SM_ASSERT(e != NULL);
13812fb4f839SGregory Neil Shapiro 	SM_ASSERT(e->e_mci != NULL);
13822fb4f839SGregory Neil Shapiro 	macdefine(&e->e_mci->mci_macro, A_PERM, macid("{client_flags}"), "");
13832fb4f839SGregory Neil Shapiro 	pvp = NULL;
1384*d39bd2c1SGregory Neil Shapiro 	r = rscap("clt_features", servername, NULL, e, &pvp, pvpbuf,
13852fb4f839SGregory Neil Shapiro 		  sizeof(pvpbuf));
13862fb4f839SGregory Neil Shapiro 	if (r != EX_OK)
13872fb4f839SGregory Neil Shapiro 		return EX_OK;
13882fb4f839SGregory Neil Shapiro 	if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
13892fb4f839SGregory Neil Shapiro 		return EX_OK;
13902fb4f839SGregory Neil Shapiro 	if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
13912fb4f839SGregory Neil Shapiro 		return EX_TEMPFAIL;
13922fb4f839SGregory Neil Shapiro 
13932fb4f839SGregory Neil Shapiro 	/* XXX Note: this does not inherit defaults! */
13942fb4f839SGregory Neil Shapiro 	for (idx = 0, i = 1; pvp[i] != NULL; i++)
13952fb4f839SGregory Neil Shapiro 	{
13962fb4f839SGregory Neil Shapiro 		c = pvp[i][0];
13972fb4f839SGregory Neil Shapiro 		if (!(isascii(c) && !isspace(c) && isprint(c)))
13982fb4f839SGregory Neil Shapiro 			continue;
13992fb4f839SGregory Neil Shapiro 		if (idx >= sizeof(flags) - 4)
14002fb4f839SGregory Neil Shapiro 			break;
14012fb4f839SGregory Neil Shapiro 		flags[idx++] = c;
14022fb4f839SGregory Neil Shapiro 		if (isupper(c))
14032fb4f839SGregory Neil Shapiro 			flags[idx++] = c;
14042fb4f839SGregory Neil Shapiro 		flags[idx++] = ' ';
14052fb4f839SGregory Neil Shapiro 	}
14062fb4f839SGregory Neil Shapiro 	flags[idx] = '\0';
14072fb4f839SGregory Neil Shapiro 
14082fb4f839SGregory Neil Shapiro 	macdefine(&e->e_mci->mci_macro, A_TEMP, macid("{client_flags}"), flags);
14092fb4f839SGregory Neil Shapiro 	if (tTd(10, 30))
1410*d39bd2c1SGregory Neil Shapiro 		sm_dprintf("cltfeatures: server=%s, mci=%p, flags=%s, {client_flags}=%s\n",
1411*d39bd2c1SGregory Neil Shapiro 			servername, e->e_mci, flags,
1412*d39bd2c1SGregory Neil Shapiro 			macvalue(macid("{client_flags}"), e));
14132fb4f839SGregory Neil Shapiro 	return EX_OK;
14142fb4f839SGregory Neil Shapiro }
1415*d39bd2c1SGregory Neil Shapiro #endif /* STARTTLS || SASL */
1416*d39bd2c1SGregory Neil Shapiro 
1417*d39bd2c1SGregory Neil Shapiro #if _FFR_LOG_FAILOVER
1418*d39bd2c1SGregory Neil Shapiro /*
1419*d39bd2c1SGregory Neil Shapiro **  LOGFAILOVER -- log reason why trying another host
1420*d39bd2c1SGregory Neil Shapiro **
1421*d39bd2c1SGregory Neil Shapiro **	Parameters:
1422*d39bd2c1SGregory Neil Shapiro **		e -- envelope
1423*d39bd2c1SGregory Neil Shapiro **		m -- the mailer info for this mailer
1424*d39bd2c1SGregory Neil Shapiro **		mci -- mailer connection information
1425*d39bd2c1SGregory Neil Shapiro **		rcode -- the code signifying the particular failure
1426*d39bd2c1SGregory Neil Shapiro **		rcpt -- current RCPT
1427*d39bd2c1SGregory Neil Shapiro **
1428*d39bd2c1SGregory Neil Shapiro **	Returns:
1429*d39bd2c1SGregory Neil Shapiro **		none.
1430*d39bd2c1SGregory Neil Shapiro */
1431*d39bd2c1SGregory Neil Shapiro 
1432*d39bd2c1SGregory Neil Shapiro static void logfailover __P((ENVELOPE *, MAILER *, MCI *, int, ADDRESS *));
1433*d39bd2c1SGregory Neil Shapiro static void
logfailover(e,m,mci,rcode,rcpt)1434*d39bd2c1SGregory Neil Shapiro logfailover(e, m, mci, rcode, rcpt)
1435*d39bd2c1SGregory Neil Shapiro 	ENVELOPE *e;
1436*d39bd2c1SGregory Neil Shapiro 	MAILER *m;
1437*d39bd2c1SGregory Neil Shapiro 	MCI *mci;
1438*d39bd2c1SGregory Neil Shapiro 	int rcode;
1439*d39bd2c1SGregory Neil Shapiro 	ADDRESS *rcpt;
1440*d39bd2c1SGregory Neil Shapiro {
1441*d39bd2c1SGregory Neil Shapiro 	char buf[MAXNAME];
1442*d39bd2c1SGregory Neil Shapiro 	char cbuf[SM_MAX(SYSLOG_BUFSIZE, MAXNAME)];
1443*d39bd2c1SGregory Neil Shapiro 
1444*d39bd2c1SGregory Neil Shapiro 	buf[0] = '\0';
1445*d39bd2c1SGregory Neil Shapiro 	cbuf[0] = '\0';
1446*d39bd2c1SGregory Neil Shapiro 	sm_strlcat(cbuf, "deliver: ", sizeof(cbuf));
1447*d39bd2c1SGregory Neil Shapiro 	if (m != NULL && m->m_name != NULL)
1448*d39bd2c1SGregory Neil Shapiro 	{
1449*d39bd2c1SGregory Neil Shapiro 		sm_snprintf(buf, sizeof(buf),
1450*d39bd2c1SGregory Neil Shapiro 			"mailer=%s, ", m->m_name);
1451*d39bd2c1SGregory Neil Shapiro 		sm_strlcat(cbuf, buf, sizeof(cbuf));
1452*d39bd2c1SGregory Neil Shapiro 	}
1453*d39bd2c1SGregory Neil Shapiro 	if (mci != NULL && mci->mci_host != NULL)
1454*d39bd2c1SGregory Neil Shapiro 	{
1455*d39bd2c1SGregory Neil Shapiro 		extern SOCKADDR CurHostAddr;
1456*d39bd2c1SGregory Neil Shapiro 
1457*d39bd2c1SGregory Neil Shapiro 		sm_snprintf(buf, sizeof(buf),
1458*d39bd2c1SGregory Neil Shapiro 			"relay=%.100s", mci->mci_host);
1459*d39bd2c1SGregory Neil Shapiro 		sm_strlcat(cbuf, buf, sizeof(cbuf));
1460*d39bd2c1SGregory Neil Shapiro 		if (CurHostAddr.sa.sa_family != 0)
1461*d39bd2c1SGregory Neil Shapiro 		{
1462*d39bd2c1SGregory Neil Shapiro 			sm_snprintf(buf, sizeof(buf),
1463*d39bd2c1SGregory Neil Shapiro 				" [%.100s]",
1464*d39bd2c1SGregory Neil Shapiro 				anynet_ntoa(&CurHostAddr));
1465*d39bd2c1SGregory Neil Shapiro 			sm_strlcat(cbuf, buf, sizeof(cbuf));
1466*d39bd2c1SGregory Neil Shapiro 		}
1467*d39bd2c1SGregory Neil Shapiro 		sm_strlcat(cbuf, ", ", sizeof(cbuf));
1468*d39bd2c1SGregory Neil Shapiro 	}
1469*d39bd2c1SGregory Neil Shapiro 	if (mci != NULL)
1470*d39bd2c1SGregory Neil Shapiro 	{
1471*d39bd2c1SGregory Neil Shapiro 		if (mci->mci_state >= 0 && mci->mci_state < SM_ARRAY_SIZE(mcis))
1472*d39bd2c1SGregory Neil Shapiro 			sm_snprintf(buf, sizeof(buf),
1473*d39bd2c1SGregory Neil Shapiro 				"state=%s, ", mcis[mci->mci_state]);
1474*d39bd2c1SGregory Neil Shapiro 		else
1475*d39bd2c1SGregory Neil Shapiro 			sm_snprintf(buf, sizeof(buf),
1476*d39bd2c1SGregory Neil Shapiro 				"state=%d, ", mci->mci_state);
1477*d39bd2c1SGregory Neil Shapiro 		sm_strlcat(cbuf, buf, sizeof(cbuf));
1478*d39bd2c1SGregory Neil Shapiro 	}
1479*d39bd2c1SGregory Neil Shapiro 	if (tTd(11, 64))
1480*d39bd2c1SGregory Neil Shapiro 	{
1481*d39bd2c1SGregory Neil Shapiro 		sm_snprintf(buf, sizeof(buf),
1482*d39bd2c1SGregory Neil Shapiro 			"rcode=%d, okrcpts=%d, retryrcpt=%d, e_rcode=%d, ",
1483*d39bd2c1SGregory Neil Shapiro 			rcode, mci->mci_okrcpts, mci->mci_retryrcpt,
1484*d39bd2c1SGregory Neil Shapiro 			e->e_rcode);
1485*d39bd2c1SGregory Neil Shapiro 		sm_strlcat(cbuf, buf, sizeof(cbuf));
1486*d39bd2c1SGregory Neil Shapiro 	}
1487*d39bd2c1SGregory Neil Shapiro 	if (rcode != EX_OK && rcpt != NULL
1488*d39bd2c1SGregory Neil Shapiro 	    && !SM_IS_EMPTY(rcpt->q_rstatus)
1489*d39bd2c1SGregory Neil Shapiro 	    && !bitset(QINTREPLY, rcpt->q_flags))
1490*d39bd2c1SGregory Neil Shapiro 	{
1491*d39bd2c1SGregory Neil Shapiro 		sm_snprintf(buf, sizeof(buf),
1492*d39bd2c1SGregory Neil Shapiro 			"q_rstatus=%s, ", rcpt->q_rstatus);
1493*d39bd2c1SGregory Neil Shapiro 		sm_strlcat(cbuf, buf, sizeof(cbuf));
1494*d39bd2c1SGregory Neil Shapiro 	}
1495*d39bd2c1SGregory Neil Shapiro 	else if (e->e_text != NULL)
1496*d39bd2c1SGregory Neil Shapiro 	{
1497*d39bd2c1SGregory Neil Shapiro 		sm_snprintf(buf, sizeof(buf),
1498*d39bd2c1SGregory Neil Shapiro 			"reply=%d %s%s%s, ",
1499*d39bd2c1SGregory Neil Shapiro 			e->e_rcode,
1500*d39bd2c1SGregory Neil Shapiro 			e->e_renhsc,
1501*d39bd2c1SGregory Neil Shapiro 			(e->e_renhsc[0] != '\0') ? " " : "",
1502*d39bd2c1SGregory Neil Shapiro 			e->e_text);
1503*d39bd2c1SGregory Neil Shapiro 		sm_strlcat(cbuf, buf, sizeof(cbuf));
1504*d39bd2c1SGregory Neil Shapiro 	}
1505*d39bd2c1SGregory Neil Shapiro 	sm_strlcat(cbuf,
1506*d39bd2c1SGregory Neil Shapiro 		"stat=tempfail: trying next host",
1507*d39bd2c1SGregory Neil Shapiro 		sizeof(cbuf));
1508*d39bd2c1SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "%s", cbuf);
1509*d39bd2c1SGregory Neil Shapiro }
1510*d39bd2c1SGregory Neil Shapiro #else /* _FFR_LOG_FAILOVER */
1511*d39bd2c1SGregory Neil Shapiro # define logfailover(e, m, mci, rcode, rcpt)	((void) 0)
1512*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_LOG_FAILOVER */
1513*d39bd2c1SGregory Neil Shapiro 
1514*d39bd2c1SGregory Neil Shapiro #if STARTTLS || SASL
1515*d39bd2c1SGregory Neil Shapiro # define RM_TRAIL_DOT(name)				\
1516*d39bd2c1SGregory Neil Shapiro 	do {						\
1517*d39bd2c1SGregory Neil Shapiro 		dotpos = strlen(name) - 1;		\
1518*d39bd2c1SGregory Neil Shapiro 		if (dotpos >= 0)			\
1519*d39bd2c1SGregory Neil Shapiro 		{					\
1520*d39bd2c1SGregory Neil Shapiro 			if (name[dotpos] == '.')	\
1521*d39bd2c1SGregory Neil Shapiro 				name[dotpos] = '\0';	\
1522*d39bd2c1SGregory Neil Shapiro 			else				\
1523*d39bd2c1SGregory Neil Shapiro 				dotpos = -1;		\
1524*d39bd2c1SGregory Neil Shapiro 		}					\
1525*d39bd2c1SGregory Neil Shapiro 	} while (0)
1526*d39bd2c1SGregory Neil Shapiro 
1527*d39bd2c1SGregory Neil Shapiro # define FIX_TRAIL_DOT(name)				\
1528*d39bd2c1SGregory Neil Shapiro 	do {						\
1529*d39bd2c1SGregory Neil Shapiro 		if (dotpos >= 0)			\
1530*d39bd2c1SGregory Neil Shapiro 			name[dotpos] = '.';		\
1531*d39bd2c1SGregory Neil Shapiro 	} while (0)
1532*d39bd2c1SGregory Neil Shapiro 
1533*d39bd2c1SGregory Neil Shapiro 
1534*d39bd2c1SGregory Neil Shapiro /*
1535*d39bd2c1SGregory Neil Shapiro **  SETSERVERMACROS -- set ${server_addr} and ${server_name}
1536*d39bd2c1SGregory Neil Shapiro **
1537*d39bd2c1SGregory Neil Shapiro **	Parameters:
1538*d39bd2c1SGregory Neil Shapiro **		mci -- mailer connection information
1539*d39bd2c1SGregory Neil Shapiro **		pdotpos -- return pointer to former dot position in hostname
1540*d39bd2c1SGregory Neil Shapiro **
1541*d39bd2c1SGregory Neil Shapiro **	Returns:
1542*d39bd2c1SGregory Neil Shapiro **		server name
1543*d39bd2c1SGregory Neil Shapiro */
1544*d39bd2c1SGregory Neil Shapiro 
1545*d39bd2c1SGregory Neil Shapiro static char *setservermacros __P((MCI *, int *));
1546*d39bd2c1SGregory Neil Shapiro 
1547*d39bd2c1SGregory Neil Shapiro static char *
setservermacros(mci,pdotpos)1548*d39bd2c1SGregory Neil Shapiro setservermacros(mci, pdotpos)
1549*d39bd2c1SGregory Neil Shapiro 	MCI *mci;
1550*d39bd2c1SGregory Neil Shapiro 	int *pdotpos;
1551*d39bd2c1SGregory Neil Shapiro {
1552*d39bd2c1SGregory Neil Shapiro 	char *srvname;
1553*d39bd2c1SGregory Neil Shapiro 	int dotpos;
1554*d39bd2c1SGregory Neil Shapiro 	extern SOCKADDR CurHostAddr;
1555*d39bd2c1SGregory Neil Shapiro 
1556*d39bd2c1SGregory Neil Shapiro 	/* don't use CurHostName, it is changed in many places */
1557*d39bd2c1SGregory Neil Shapiro 	if (mci->mci_host != NULL)
1558*d39bd2c1SGregory Neil Shapiro 	{
1559*d39bd2c1SGregory Neil Shapiro 		srvname = mci->mci_host;
1560*d39bd2c1SGregory Neil Shapiro 		RM_TRAIL_DOT(srvname);
1561*d39bd2c1SGregory Neil Shapiro 	}
1562*d39bd2c1SGregory Neil Shapiro 	else if (mci->mci_mailer != NULL)
1563*d39bd2c1SGregory Neil Shapiro 	{
1564*d39bd2c1SGregory Neil Shapiro 		srvname = mci->mci_mailer->m_name;
1565*d39bd2c1SGregory Neil Shapiro 		dotpos = -1;
1566*d39bd2c1SGregory Neil Shapiro 	}
1567*d39bd2c1SGregory Neil Shapiro 	else
1568*d39bd2c1SGregory Neil Shapiro 	{
1569*d39bd2c1SGregory Neil Shapiro 		srvname = "local";
1570*d39bd2c1SGregory Neil Shapiro 		dotpos = -1;
1571*d39bd2c1SGregory Neil Shapiro 	}
1572*d39bd2c1SGregory Neil Shapiro 
1573*d39bd2c1SGregory Neil Shapiro 	/* don't set {server_name} to NULL or "": see getauth() */
1574*d39bd2c1SGregory Neil Shapiro 	macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"),
1575*d39bd2c1SGregory Neil Shapiro 		  srvname);
1576*d39bd2c1SGregory Neil Shapiro 
1577*d39bd2c1SGregory Neil Shapiro 	/* CurHostAddr is set by makeconnection() and mci_get() */
1578*d39bd2c1SGregory Neil Shapiro 	if (CurHostAddr.sa.sa_family != 0)
1579*d39bd2c1SGregory Neil Shapiro 	{
1580*d39bd2c1SGregory Neil Shapiro 		macdefine(&mci->mci_macro, A_TEMP,
1581*d39bd2c1SGregory Neil Shapiro 			  macid("{server_addr}"),
1582*d39bd2c1SGregory Neil Shapiro 			  anynet_ntoa(&CurHostAddr));
1583*d39bd2c1SGregory Neil Shapiro 	}
1584*d39bd2c1SGregory Neil Shapiro 	else if (mci->mci_mailer != NULL)
1585*d39bd2c1SGregory Neil Shapiro 	{
1586*d39bd2c1SGregory Neil Shapiro 		/* mailer name is unique, use it as address */
1587*d39bd2c1SGregory Neil Shapiro 		macdefine(&mci->mci_macro, A_PERM,
1588*d39bd2c1SGregory Neil Shapiro 			  macid("{server_addr}"),
1589*d39bd2c1SGregory Neil Shapiro 			  mci->mci_mailer->m_name);
1590*d39bd2c1SGregory Neil Shapiro 	}
1591*d39bd2c1SGregory Neil Shapiro 	else
1592*d39bd2c1SGregory Neil Shapiro 	{
1593*d39bd2c1SGregory Neil Shapiro 		/* don't set it to NULL or "": see getauth() */
1594*d39bd2c1SGregory Neil Shapiro 		macdefine(&mci->mci_macro, A_PERM,
1595*d39bd2c1SGregory Neil Shapiro 			  macid("{server_addr}"), "0");
1596*d39bd2c1SGregory Neil Shapiro 	}
1597*d39bd2c1SGregory Neil Shapiro 
1598*d39bd2c1SGregory Neil Shapiro 	if (pdotpos != NULL)
1599*d39bd2c1SGregory Neil Shapiro 		*pdotpos = dotpos;
1600*d39bd2c1SGregory Neil Shapiro 	else
1601*d39bd2c1SGregory Neil Shapiro 		FIX_TRAIL_DOT(srvname);
1602*d39bd2c1SGregory Neil Shapiro 	return srvname;
1603*d39bd2c1SGregory Neil Shapiro }
1604*d39bd2c1SGregory Neil Shapiro #endif /* STARTTLS || SASL */
16052fb4f839SGregory Neil Shapiro 
16062fb4f839SGregory Neil Shapiro /*
1607c2aa98e2SPeter Wemm **  DELIVER -- Deliver a message to a list of addresses.
1608c2aa98e2SPeter Wemm **
1609c2aa98e2SPeter Wemm **	This routine delivers to everyone on the same host as the
1610c2aa98e2SPeter Wemm **	user on the head of the list.  It is clever about mailers
1611c2aa98e2SPeter Wemm **	that don't handle multiple users.  It is NOT guaranteed
1612c2aa98e2SPeter Wemm **	that it will deliver to all these addresses however -- so
16135b0945b5SGregory Neil Shapiro **	deliver should be called once for each address on the list.
161440266059SGregory Neil Shapiro **	Deliver tries to be as opportunistic as possible about piggybacking
161540266059SGregory Neil Shapiro **	messages. Some definitions to make understanding easier follow below.
161640266059SGregory Neil Shapiro **	Piggybacking occurs when an existing connection to a mail host can
161740266059SGregory Neil Shapiro **	be used to send the same message to more than one recipient at the
161840266059SGregory Neil Shapiro **	same time. So "no piggybacking" means one message for one recipient
161940266059SGregory Neil Shapiro **	per connection. "Intentional piggybacking" happens when the
162040266059SGregory Neil Shapiro **	recipients' host address (not the mail host address) is used to
162140266059SGregory Neil Shapiro **	attempt piggybacking. Recipients with the same host address
162240266059SGregory Neil Shapiro **	have the same mail host. "Coincidental piggybacking" relies on
162340266059SGregory Neil Shapiro **	piggybacking based on all the mail host addresses in the MX-RR. This
162440266059SGregory Neil Shapiro **	is "coincidental" in the fact it could not be predicted until the
162540266059SGregory Neil Shapiro **	MX Resource Records for the hosts were obtained and examined. For
162640266059SGregory Neil Shapiro **	example (preference order and equivalence is important, not values):
162740266059SGregory Neil Shapiro **		domain1 IN MX 10 mxhost-A
162840266059SGregory Neil Shapiro **			IN MX 20 mxhost-B
162940266059SGregory Neil Shapiro **		domain2 IN MX  4 mxhost-A
163040266059SGregory Neil Shapiro **			IN MX  8 mxhost-B
163140266059SGregory Neil Shapiro **	Domain1 and domain2 can piggyback the same message to mxhost-A or
163240266059SGregory Neil Shapiro **	mxhost-B (if mxhost-A cannot be reached).
163340266059SGregory Neil Shapiro **	"Coattail piggybacking" relaxes the strictness of "coincidental
163440266059SGregory Neil Shapiro **	piggybacking" in the hope that most significant (lowest value)
163540266059SGregory Neil Shapiro **	MX preference host(s) can create more piggybacking. For example
163640266059SGregory Neil Shapiro **	(again, preference order and equivalence is important, not values):
163740266059SGregory Neil Shapiro **		domain3 IN MX 100 mxhost-C
163840266059SGregory Neil Shapiro **			IN MX 100 mxhost-D
163940266059SGregory Neil Shapiro **			IN MX 200 mxhost-E
164040266059SGregory Neil Shapiro **		domain4 IN MX  50 mxhost-C
164140266059SGregory Neil Shapiro **			IN MX  50 mxhost-D
164240266059SGregory Neil Shapiro **			IN MX  80 mxhost-F
164340266059SGregory Neil Shapiro **	A message for domain3 and domain4 can piggyback to mxhost-C if mxhost-C
164440266059SGregory Neil Shapiro **	is available. Same with mxhost-D because in both RR's the preference
164540266059SGregory Neil Shapiro **	value is the same as mxhost-C, respectively.
164640266059SGregory Neil Shapiro **	So deliver attempts coattail piggybacking when possible. If the
164740266059SGregory Neil Shapiro **	first MX preference level hosts cannot be used then the piggybacking
164840266059SGregory Neil Shapiro **	reverts to coincidental piggybacking. Using the above example you
164940266059SGregory Neil Shapiro **	cannot deliver to mxhost-F for domain3 regardless of preference value.
165040266059SGregory Neil Shapiro **	("Coattail" from "riding on the coattails of your predecessor" meaning
165140266059SGregory Neil Shapiro **	gaining benefit from a predecessor effort with no or little addition
165240266059SGregory Neil Shapiro **	effort. The predecessor here being the preceding MX RR).
1653c2aa98e2SPeter Wemm **
1654c2aa98e2SPeter Wemm **	Parameters:
1655c2aa98e2SPeter Wemm **		e -- the envelope to deliver.
1656c2aa98e2SPeter Wemm **		firstto -- head of the address list to deliver to.
1657c2aa98e2SPeter Wemm **
1658c2aa98e2SPeter Wemm **	Returns:
1659c2aa98e2SPeter Wemm **		zero -- successfully delivered.
1660c2aa98e2SPeter Wemm **		else -- some failure, see ExitStat for more info.
1661c2aa98e2SPeter Wemm **
1662c2aa98e2SPeter Wemm **	Side Effects:
1663c2aa98e2SPeter Wemm **		The standard input is passed off to someone.
1664c2aa98e2SPeter Wemm */
1665c2aa98e2SPeter Wemm 
1666*d39bd2c1SGregory Neil Shapiro #if !_FFR_DMTRIGGER
1667*d39bd2c1SGregory Neil Shapiro static
1668*d39bd2c1SGregory Neil Shapiro #endif
1669*d39bd2c1SGregory Neil Shapiro int
deliver(e,firstto)1670c2aa98e2SPeter Wemm deliver(e, firstto)
1671c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1672c2aa98e2SPeter Wemm 	ADDRESS *firstto;
1673c2aa98e2SPeter Wemm {
1674c2aa98e2SPeter Wemm 	char *host;			/* host being sent to */
1675c2aa98e2SPeter Wemm 	char *user;			/* user being sent to */
1676c2aa98e2SPeter Wemm 	char **pvp;
1677c2aa98e2SPeter Wemm 	register char **mvp;
1678c2aa98e2SPeter Wemm 	register char *p;
1679c2aa98e2SPeter Wemm 	register MAILER *m;		/* mailer for this recipient */
1680c2aa98e2SPeter Wemm 	ADDRESS *volatile ctladdr;
168140266059SGregory Neil Shapiro #if HASSETUSERCONTEXT
1682c2aa98e2SPeter Wemm 	ADDRESS *volatile contextaddr = NULL;
16835b0945b5SGregory Neil Shapiro #endif
1684c2aa98e2SPeter Wemm 	register MCI *volatile mci;
168540266059SGregory Neil Shapiro 	register ADDRESS *SM_NONVOLATILE to = firstto;
168640266059SGregory Neil Shapiro 	volatile bool clever = false;	/* running user smtp to this mailer */
1687c2aa98e2SPeter Wemm 	ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */
1688c2aa98e2SPeter Wemm 	int rcode;			/* response code */
168940266059SGregory Neil Shapiro 	SM_NONVOLATILE int lmtp_rcode = EX_OK;
169040266059SGregory Neil Shapiro 	SM_NONVOLATILE int nummxhosts = 0; /* number of MX hosts available */
169140266059SGregory Neil Shapiro 	SM_NONVOLATILE int hostnum = 0;	/* current MX host index */
1692c2aa98e2SPeter Wemm 	char *firstsig;			/* signature of firstto */
169340266059SGregory Neil Shapiro 	volatile pid_t pid = -1;
1694c2aa98e2SPeter Wemm 	char *volatile curhost;
169540266059SGregory Neil Shapiro 	SM_NONVOLATILE unsigned short port = 0;
169640266059SGregory Neil Shapiro 	SM_NONVOLATILE time_t enough = 0;
169706f25ae9SGregory Neil Shapiro #if NETUNIX
169840266059SGregory Neil Shapiro 	char *SM_NONVOLATILE mux_path = NULL;	/* path to UNIX domain socket */
16995b0945b5SGregory Neil Shapiro #endif
1700c2aa98e2SPeter Wemm 	time_t xstart;
1701c2aa98e2SPeter Wemm 	bool suidwarn;
1702c2aa98e2SPeter Wemm 	bool anyok;			/* at least one address was OK */
170340266059SGregory Neil Shapiro 	SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */
170406f25ae9SGregory Neil Shapiro 	bool ovr;
170540266059SGregory Neil Shapiro 	bool quarantine;
17065b0945b5SGregory Neil Shapiro #if STARTTLS
1707*d39bd2c1SGregory Neil Shapiro 	bool implicittls = false;
1708*d39bd2c1SGregory Neil Shapiro # if _FFR_SMTPS_CLIENT
1709*d39bd2c1SGregory Neil Shapiro 	bool smtptls = false;
1710*d39bd2c1SGregory Neil Shapiro # endif
17115b0945b5SGregory Neil Shapiro 	/* 0: try TLS, 1: try without TLS again, >1: don't try again */
17125b0945b5SGregory Neil Shapiro 	int tlsstate;
17135b0945b5SGregory Neil Shapiro # if DANE
17145b0945b5SGregory Neil Shapiro 	dane_vrfy_ctx_T	dane_vrfy_ctx;
17155b0945b5SGregory Neil Shapiro 	STAB *ste;
1716*d39bd2c1SGregory Neil Shapiro 	char *vrfy;
1717*d39bd2c1SGregory Neil Shapiro 	int dane_req;
17185b0945b5SGregory Neil Shapiro 
1719*d39bd2c1SGregory Neil Shapiro /* should this allow DANE_ALWAYS == DANEMODE(dane)? */
1720*d39bd2c1SGregory Neil Shapiro #  define RCPT_MXSECURE(rcpt)	(0 != ((rcpt)->q_flags & QMXSECURE))
17215b0945b5SGregory Neil Shapiro 
1722*d39bd2c1SGregory Neil Shapiro #  define STE_HAS_TLSA(ste) ((ste) != NULL && (ste)->s_tlsa != NULL)
17235b0945b5SGregory Neil Shapiro 
1724*d39bd2c1SGregory Neil Shapiro /* NOTE: the following macros use some local variables directly! */
1725*d39bd2c1SGregory Neil Shapiro #  define RCPT_HAS_DANE(rcpt)	(RCPT_MXSECURE(rcpt) \
1726*d39bd2c1SGregory Neil Shapiro 	&& !iscltflgset(e, D_NODANE)	\
1727*d39bd2c1SGregory Neil Shapiro 	&& STE_HAS_TLSA(ste)	\
1728*d39bd2c1SGregory Neil Shapiro 	&& (0 == (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLTEMPVRFY))	\
1729*d39bd2c1SGregory Neil Shapiro 	&& (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLADIP))	\
1730*d39bd2c1SGregory Neil Shapiro 	&& CHK_DANE(dane_vrfy_ctx.dane_vrfy_chk)	\
1731*d39bd2c1SGregory Neil Shapiro 	)
1732*d39bd2c1SGregory Neil Shapiro 
1733*d39bd2c1SGregory Neil Shapiro #  define RCPT_REQ_DANE(rcpt)	(RCPT_HAS_DANE(rcpt) \
1734*d39bd2c1SGregory Neil Shapiro 	&& TLSA_IS_FL(ste->s_tlsa, TLSAFLSUP))
1735*d39bd2c1SGregory Neil Shapiro 
1736*d39bd2c1SGregory Neil Shapiro #  define RCPT_REQ_TLS(rcpt)	(RCPT_HAS_DANE(rcpt) \
1737*d39bd2c1SGregory Neil Shapiro 	&& TLSA_IS_FL(ste->s_tlsa, TLSAFLUNS))
1738*d39bd2c1SGregory Neil Shapiro 
1739*d39bd2c1SGregory Neil Shapiro #  define CHK_DANE_RCPT(dane, rcpt) (CHK_DANE(dane) && \
1740*d39bd2c1SGregory Neil Shapiro 	 (RCPT_MXSECURE(rcpt) || DANE_ALWAYS == DANEMODE(dane)))
1741*d39bd2c1SGregory Neil Shapiro 
1742*d39bd2c1SGregory Neil Shapiro 	BITMAP256 mxads;
1743*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
1744*d39bd2c1SGregory Neil Shapiro #endif /* STARTTLS */
174506f25ae9SGregory Neil Shapiro 	int strsize;
174606f25ae9SGregory Neil Shapiro 	int rcptcount;
174740266059SGregory Neil Shapiro 	int ret;
174806f25ae9SGregory Neil Shapiro 	static int tobufsize = 0;
174906f25ae9SGregory Neil Shapiro 	static char *tobuf = NULL;
175040266059SGregory Neil Shapiro 	char *rpath;	/* translated return path */
1751c2aa98e2SPeter Wemm 	int mpvect[2];
1752c2aa98e2SPeter Wemm 	int rpvect[2];
175306f25ae9SGregory Neil Shapiro 	char *mxhosts[MAXMXHOSTS + 1];
1754c2aa98e2SPeter Wemm 	char *pv[MAXPV + 1];
17552fb4f839SGregory Neil Shapiro 	char buf[MAXNAME + 1];	/* EAI:ok */
175694c01205SGregory Neil Shapiro 	char cbuf[MAXPATHLEN];
1757*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
1758*d39bd2c1SGregory Neil Shapiro 	char xbuf[SM_MAX(SYSLOG_BUFSIZE, MAXNAME)];
1759*d39bd2c1SGregory Neil Shapiro #endif
1760c2aa98e2SPeter Wemm 
1761c2aa98e2SPeter Wemm 	errno = 0;
1762d0cef73dSGregory Neil Shapiro 	SM_REQUIRE(firstto != NULL);	/* same as to */
176306f25ae9SGregory Neil Shapiro 	if (!QS_IS_OK(to->q_state))
176406f25ae9SGregory Neil Shapiro 		return 0;
1765c2aa98e2SPeter Wemm 
1766c2aa98e2SPeter Wemm 	suidwarn = geteuid() == 0;
1767c2aa98e2SPeter Wemm 
1768d0cef73dSGregory Neil Shapiro 	SM_REQUIRE(e != NULL);
1769c2aa98e2SPeter Wemm 	m = to->q_mailer;
1770c2aa98e2SPeter Wemm 	host = to->q_host;
1771c2aa98e2SPeter Wemm 	CurEnv = e;			/* just in case */
1772c2aa98e2SPeter Wemm 	e->e_statmsg = NULL;
1773c2aa98e2SPeter Wemm 	SmtpError[0] = '\0';
1774c2aa98e2SPeter Wemm 	xstart = curtime();
17755b0945b5SGregory Neil Shapiro #if STARTTLS
17765b0945b5SGregory Neil Shapiro 	tlsstate = 0;
17775b0945b5SGregory Neil Shapiro # if DANE
17785b0945b5SGregory Neil Shapiro 	memset(&dane_vrfy_ctx, '\0', sizeof(dane_vrfy_ctx));
17795b0945b5SGregory Neil Shapiro 	ste = NULL;
17805b0945b5SGregory Neil Shapiro # endif
17815b0945b5SGregory Neil Shapiro #endif
1782c2aa98e2SPeter Wemm 
1783c2aa98e2SPeter Wemm 	if (tTd(10, 1))
178440266059SGregory Neil Shapiro 		sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
1785c2aa98e2SPeter Wemm 			e->e_id, m->m_name, host, to->q_user);
1786c2aa98e2SPeter Wemm 	if (tTd(10, 100))
178740266059SGregory Neil Shapiro 		printopenfds(false);
1788*d39bd2c1SGregory Neil Shapiro 	maps_reset_chged("deliver");
1789c2aa98e2SPeter Wemm 
1790c2aa98e2SPeter Wemm 	/*
179140266059SGregory Neil Shapiro 	**  Clear {client_*} macros if this is a bounce message to
1792c2aa98e2SPeter Wemm 	**  prevent rejection by check_compat ruleset.
1793c2aa98e2SPeter Wemm 	*/
1794c2aa98e2SPeter Wemm 
1795c2aa98e2SPeter Wemm 	if (bitset(EF_RESPONSE, e->e_flags))
1796c2aa98e2SPeter Wemm 	{
179740266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, macid("{client_name}"), "");
1798e92d3f3fSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, macid("{client_ptr}"), "");
179940266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), "");
180040266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, macid("{client_port}"), "");
180140266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), "");
1802c2aa98e2SPeter Wemm 	}
1803c2aa98e2SPeter Wemm 
180440266059SGregory Neil Shapiro 	SM_TRY
180540266059SGregory Neil Shapiro 	{
180640266059SGregory Neil Shapiro 	ADDRESS *skip_back = NULL;
180740266059SGregory Neil Shapiro 
1808c2aa98e2SPeter Wemm 	/*
1809c2aa98e2SPeter Wemm 	**  Do initial argv setup.
1810c2aa98e2SPeter Wemm 	**	Insert the mailer name.  Notice that $x expansion is
1811c2aa98e2SPeter Wemm 	**	NOT done on the mailer name.  Then, if the mailer has
1812c2aa98e2SPeter Wemm 	**	a picky -f flag, we insert it as appropriate.  This
1813c2aa98e2SPeter Wemm 	**	code does not check for 'pv' overflow; this places a
1814c2aa98e2SPeter Wemm 	**	manifest lower limit of 4 for MAXPV.
1815c2aa98e2SPeter Wemm 	**		The from address rewrite is expected to make
1816c2aa98e2SPeter Wemm 	**		the address relative to the other end.
1817c2aa98e2SPeter Wemm 	*/
1818c2aa98e2SPeter Wemm 
1819c2aa98e2SPeter Wemm 	/* rewrite from address, using rewriting rules */
1820c2aa98e2SPeter Wemm 	rcode = EX_OK;
1821d0cef73dSGregory Neil Shapiro 	SM_ASSERT(e->e_from.q_mailer != NULL);
1822c2aa98e2SPeter Wemm 	if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
1823c2aa98e2SPeter Wemm 		p = e->e_sender;
1824c2aa98e2SPeter Wemm 	else
1825c2aa98e2SPeter Wemm 		p = e->e_from.q_paddr;
182640266059SGregory Neil Shapiro 	rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e);
1827da7d7b9cSGregory Neil Shapiro 	if (rcode != EX_OK && bitnset(M_xSMTP, m->m_flags))
1828da7d7b9cSGregory Neil Shapiro 		goto cleanup;
18292fb4f839SGregory Neil Shapiro 
18302fb4f839SGregory Neil Shapiro 	/* need to check external format, not internal! */
18312fb4f839SGregory Neil Shapiro 	if (strlen(rpath) > MAXNAME_I)
1832c2aa98e2SPeter Wemm 	{
183340266059SGregory Neil Shapiro 		rpath = shortenstring(rpath, MAXSHORTSTR);
183440266059SGregory Neil Shapiro 
183540266059SGregory Neil Shapiro 		/* avoid bogus errno */
183640266059SGregory Neil Shapiro 		errno = 0;
183740266059SGregory Neil Shapiro 		syserr("remotename: huge return path %s", rpath);
1838c2aa98e2SPeter Wemm 	}
183940266059SGregory Neil Shapiro 	rpath = sm_rpool_strdup_x(e->e_rpool, rpath);
184040266059SGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'g', rpath);
1841*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
1842*d39bd2c1SGregory Neil Shapiro 	host = quote_internal_chars(host, NULL, &strsize, NULL);
1843*d39bd2c1SGregory Neil Shapiro #endif
184440266059SGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'h', host);
1845c2aa98e2SPeter Wemm 	Errors = 0;
1846c2aa98e2SPeter Wemm 	pvp = pv;
1847c2aa98e2SPeter Wemm 	*pvp++ = m->m_argv[0];
1848c2aa98e2SPeter Wemm 
1849e92d3f3fSGregory Neil Shapiro 	/* ignore long term host status information if mailer flag W is set */
1850e92d3f3fSGregory Neil Shapiro 	if (bitnset(M_NOHOSTSTAT, m->m_flags))
1851e92d3f3fSGregory Neil Shapiro 		IgnoreHostStatus = true;
1852e92d3f3fSGregory Neil Shapiro 
1853c2aa98e2SPeter Wemm 	/* insert -f or -r flag as appropriate */
185406f25ae9SGregory Neil Shapiro 	if (FromFlag &&
185506f25ae9SGregory Neil Shapiro 	    (bitnset(M_FOPT, m->m_flags) ||
185606f25ae9SGregory Neil Shapiro 	     bitnset(M_ROPT, m->m_flags)))
1857c2aa98e2SPeter Wemm 	{
1858c2aa98e2SPeter Wemm 		if (bitnset(M_FOPT, m->m_flags))
1859c2aa98e2SPeter Wemm 			*pvp++ = "-f";
1860c2aa98e2SPeter Wemm 		else
1861c2aa98e2SPeter Wemm 			*pvp++ = "-r";
186240266059SGregory Neil Shapiro 		*pvp++ = rpath;
1863c2aa98e2SPeter Wemm 	}
1864c2aa98e2SPeter Wemm 
1865c2aa98e2SPeter Wemm 	/*
1866c2aa98e2SPeter Wemm 	**  Append the other fixed parts of the argv.  These run
1867c2aa98e2SPeter Wemm 	**  up to the first entry containing "$u".  There can only
1868c2aa98e2SPeter Wemm 	**  be one of these, and there are only a few more slots
1869c2aa98e2SPeter Wemm 	**  in the pv after it.
1870c2aa98e2SPeter Wemm 	*/
1871c2aa98e2SPeter Wemm 
1872c2aa98e2SPeter Wemm 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
1873c2aa98e2SPeter Wemm 	{
1874c2aa98e2SPeter Wemm 		/* can't use strchr here because of sign extension problems */
1875c2aa98e2SPeter Wemm 		while (*p != '\0')
1876c2aa98e2SPeter Wemm 		{
1877c2aa98e2SPeter Wemm 			if ((*p++ & 0377) == MACROEXPAND)
1878c2aa98e2SPeter Wemm 			{
1879c2aa98e2SPeter Wemm 				if (*p == 'u')
1880c2aa98e2SPeter Wemm 					break;
1881c2aa98e2SPeter Wemm 			}
1882c2aa98e2SPeter Wemm 		}
1883c2aa98e2SPeter Wemm 
1884c2aa98e2SPeter Wemm 		if (*p != '\0')
1885c2aa98e2SPeter Wemm 			break;
1886c2aa98e2SPeter Wemm 
1887c2aa98e2SPeter Wemm 		/* this entry is safe -- go ahead and process it */
1888d0cef73dSGregory Neil Shapiro 		expand(*mvp, buf, sizeof(buf), e);
1889*d39bd2c1SGregory Neil Shapiro 		p = buf;
1890*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
1891*d39bd2c1SGregory Neil Shapiro 		/* apply to all args? */
1892*d39bd2c1SGregory Neil Shapiro 		if (strcmp(m->m_mailer, "[IPC]") == 0
1893*d39bd2c1SGregory Neil Shapiro 		    && ((*mvp)[0] & 0377) == MACROEXPAND
1894*d39bd2c1SGregory Neil Shapiro /* for now only apply [i] -> [x] conversion to $h by default */
1895*d39bd2c1SGregory Neil Shapiro # ifndef _FFR_H2X_ONLY
1896*d39bd2c1SGregory Neil Shapiro #  define _FFR_H2X_ONLY 1
1897*d39bd2c1SGregory Neil Shapiro # endif
1898*d39bd2c1SGregory Neil Shapiro # if _FFR_H2X_ONLY
1899*d39bd2c1SGregory Neil Shapiro 		    && 'h' == (*mvp)[1] && '\0' == (*mvp)[2]
1900*d39bd2c1SGregory Neil Shapiro # endif
1901*d39bd2c1SGregory Neil Shapiro 		   )
1902*d39bd2c1SGregory Neil Shapiro 		{
1903*d39bd2c1SGregory Neil Shapiro 			(void) dequote_internal_chars(buf, xbuf, sizeof(xbuf));
1904*d39bd2c1SGregory Neil Shapiro 			p = xbuf;
1905*d39bd2c1SGregory Neil Shapiro 			if (tTd(10, 33))
1906*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("expand(%s), dequoted=%s\n", *mvp, p);
1907*d39bd2c1SGregory Neil Shapiro 		}
1908*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_8BITENVADDR */
1909*d39bd2c1SGregory Neil Shapiro 		*pvp++ = sm_rpool_strdup_x(e->e_rpool, p);
1910c2aa98e2SPeter Wemm 		if (pvp >= &pv[MAXPV - 3])
1911c2aa98e2SPeter Wemm 		{
191206f25ae9SGregory Neil Shapiro 			syserr("554 5.3.5 Too many parameters to %s before $u",
191306f25ae9SGregory Neil Shapiro 			       pv[0]);
191440266059SGregory Neil Shapiro 			rcode = -1;
191540266059SGregory Neil Shapiro 			goto cleanup;
1916c2aa98e2SPeter Wemm 		}
1917c2aa98e2SPeter Wemm 	}
1918c2aa98e2SPeter Wemm 
1919c2aa98e2SPeter Wemm 	/*
1920c2aa98e2SPeter Wemm 	**  If we have no substitution for the user name in the argument
1921c2aa98e2SPeter Wemm 	**  list, we know that we must supply the names otherwise -- and
1922c2aa98e2SPeter Wemm 	**  SMTP is the answer!!
1923c2aa98e2SPeter Wemm 	*/
1924c2aa98e2SPeter Wemm 
1925c2aa98e2SPeter Wemm 	if (*mvp == NULL)
1926c2aa98e2SPeter Wemm 	{
1927602a2b1bSGregory Neil Shapiro 		/* running LMTP or SMTP */
192840266059SGregory Neil Shapiro 		clever = true;
1929c2aa98e2SPeter Wemm 		*pvp = NULL;
1930da7d7b9cSGregory Neil Shapiro 		setbitn(M_xSMTP, m->m_flags);
1931c2aa98e2SPeter Wemm 	}
1932602a2b1bSGregory Neil Shapiro 	else if (bitnset(M_LMTP, m->m_flags))
1933602a2b1bSGregory Neil Shapiro 	{
1934602a2b1bSGregory Neil Shapiro 		/* not running LMTP */
1935602a2b1bSGregory Neil Shapiro 		sm_syslog(LOG_ERR, NULL,
1936602a2b1bSGregory Neil Shapiro 			  "Warning: mailer %s: LMTP flag (F=z) turned off",
1937602a2b1bSGregory Neil Shapiro 			  m->m_name);
1938602a2b1bSGregory Neil Shapiro 		clrbitn(M_LMTP, m->m_flags);
1939602a2b1bSGregory Neil Shapiro 	}
1940c2aa98e2SPeter Wemm 
1941c2aa98e2SPeter Wemm 	/*
1942c2aa98e2SPeter Wemm 	**  At this point *mvp points to the argument with $u.  We
1943c2aa98e2SPeter Wemm 	**  run through our address list and append all the addresses
1944c2aa98e2SPeter Wemm 	**  we can.  If we run out of space, do not fret!  We can
1945c2aa98e2SPeter Wemm 	**  always send another copy later.
1946c2aa98e2SPeter Wemm 	*/
1947c2aa98e2SPeter Wemm 
194806f25ae9SGregory Neil Shapiro 	e->e_to = NULL;
194906f25ae9SGregory Neil Shapiro 	strsize = 2;
195006f25ae9SGregory Neil Shapiro 	rcptcount = 0;
1951c2aa98e2SPeter Wemm 	ctladdr = NULL;
195240266059SGregory Neil Shapiro 	if (firstto->q_signature == NULL)
195340266059SGregory Neil Shapiro 		firstto->q_signature = hostsignature(firstto->q_mailer,
19545b0945b5SGregory Neil Shapiro 						     firstto->q_host,
1955*d39bd2c1SGregory Neil Shapiro 						     QISSECURE(firstto),
1956*d39bd2c1SGregory Neil Shapiro 						     &firstto->q_flags);
195740266059SGregory Neil Shapiro 	firstsig = firstto->q_signature;
1958*d39bd2c1SGregory Neil Shapiro #if DANE
1959*d39bd2c1SGregory Neil Shapiro # define NODANEREQYET	(-1)
1960*d39bd2c1SGregory Neil Shapiro 	dane_req = NODANEREQYET;
1961*d39bd2c1SGregory Neil Shapiro #endif
196240266059SGregory Neil Shapiro 
1963c2aa98e2SPeter Wemm 	for (; to != NULL; to = to->q_next)
1964c2aa98e2SPeter Wemm 	{
1965c2aa98e2SPeter Wemm 		/* avoid sending multiple recipients to dumb mailers */
196606f25ae9SGregory Neil Shapiro 		if (tochain != NULL && !bitnset(M_MUSER, m->m_flags))
196706f25ae9SGregory Neil Shapiro 			break;
1968c2aa98e2SPeter Wemm 
1969c2aa98e2SPeter Wemm 		/* if already sent or not for this host, don't send */
197040266059SGregory Neil Shapiro 		if (!QS_IS_OK(to->q_state)) /* already sent; look at next */
1971c2aa98e2SPeter Wemm 			continue;
1972c2aa98e2SPeter Wemm 
197340266059SGregory Neil Shapiro 		/*
197440266059SGregory Neil Shapiro 		**  Must be same mailer to keep grouping rcpts.
197540266059SGregory Neil Shapiro 		**  If mailers don't match: continue; sendqueue is not
197640266059SGregory Neil Shapiro 		**  sorted by mailers, so don't break;
197740266059SGregory Neil Shapiro 		*/
197840266059SGregory Neil Shapiro 
197940266059SGregory Neil Shapiro 		if (to->q_mailer != firstto->q_mailer)
198040266059SGregory Neil Shapiro 			continue;
198140266059SGregory Neil Shapiro 
198240266059SGregory Neil Shapiro 		if (to->q_signature == NULL) /* for safety */
198340266059SGregory Neil Shapiro 			to->q_signature = hostsignature(to->q_mailer,
19845b0945b5SGregory Neil Shapiro 							to->q_host,
1985*d39bd2c1SGregory Neil Shapiro 							QISSECURE(to),
1986*d39bd2c1SGregory Neil Shapiro 							&to->q_flags);
198740266059SGregory Neil Shapiro 
198840266059SGregory Neil Shapiro 		/*
198940266059SGregory Neil Shapiro 		**  This is for coincidental and tailcoat piggybacking messages
199040266059SGregory Neil Shapiro 		**  to the same mail host. While the signatures are identical
199140266059SGregory Neil Shapiro 		**  (that's the MX-RR's are identical) we can do coincidental
199240266059SGregory Neil Shapiro 		**  piggybacking. We try hard for coattail piggybacking
199340266059SGregory Neil Shapiro 		**  with the same mail host when the next recipient has the
199440266059SGregory Neil Shapiro 		**  same host at lowest preference. It may be that this
199540266059SGregory Neil Shapiro 		**  won't work out, so 'skip_back' is maintained if a backup
199640266059SGregory Neil Shapiro 		**  to coincidental piggybacking or full signature must happen.
199740266059SGregory Neil Shapiro 		*/
199840266059SGregory Neil Shapiro 
199940266059SGregory Neil Shapiro 		ret = firstto == to ? HS_MATCH_FULL :
200040266059SGregory Neil Shapiro 				      coloncmp(to->q_signature, firstsig);
200140266059SGregory Neil Shapiro 		if (ret == HS_MATCH_FULL)
200240266059SGregory Neil Shapiro 			skip_back = to;
200340266059SGregory Neil Shapiro 		else if (ret == HS_MATCH_NO)
200406f25ae9SGregory Neil Shapiro 			break;
2005*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2006*d39bd2c1SGregory Neil Shapiro 		else if (ret == HS_MATCH_SKIP)
2007*d39bd2c1SGregory Neil Shapiro 			continue;
2008*d39bd2c1SGregory Neil Shapiro # endif
200906f25ae9SGregory Neil Shapiro 
201040266059SGregory Neil Shapiro 		if (!clever)
201140266059SGregory Neil Shapiro 		{
201240266059SGregory Neil Shapiro 			/* avoid overflowing tobuf */
201340266059SGregory Neil Shapiro 			strsize += strlen(to->q_paddr) + 1;
201440266059SGregory Neil Shapiro 			if (strsize > TOBUFSIZE)
201540266059SGregory Neil Shapiro 				break;
201640266059SGregory Neil Shapiro 		}
201740266059SGregory Neil Shapiro 
201806f25ae9SGregory Neil Shapiro 		if (++rcptcount > to->q_mailer->m_maxrcpt)
201906f25ae9SGregory Neil Shapiro 			break;
2020c2aa98e2SPeter Wemm 
2021*d39bd2c1SGregory Neil Shapiro #if DANE
2022*d39bd2c1SGregory Neil Shapiro 		if (TTD(10, 30))
2023*d39bd2c1SGregory Neil Shapiro 		{
2024*d39bd2c1SGregory Neil Shapiro 			char sep = ':';
2025*d39bd2c1SGregory Neil Shapiro 
2026*d39bd2c1SGregory Neil Shapiro 			parse_hostsignature(to->q_signature, mxhosts, m, mxads);
2027*d39bd2c1SGregory Neil Shapiro 			FIX_MXHOSTS(mxhosts[0], p, sep);
2028*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2029*d39bd2c1SGregory Neil Shapiro 			if (MXADS_ISSET(mxads, 0))
2030*d39bd2c1SGregory Neil Shapiro 				to->q_flags |= QMXSECURE;
2031*d39bd2c1SGregory Neil Shapiro 			else
2032*d39bd2c1SGregory Neil Shapiro 				to->q_flags &= ~QMXSECURE;
2033*d39bd2c1SGregory Neil Shapiro # endif
2034*d39bd2c1SGregory Neil Shapiro 
2035*d39bd2c1SGregory Neil Shapiro 			gettlsa(mxhosts[0], NULL, &ste, RCPT_MXSECURE(to) ? TLSAFLADMX : 0, 0, m->m_port);
2036*d39bd2c1SGregory Neil Shapiro 			sm_dprintf("tochain: to=%s, rcptcount=%d, QSECURE=%d, QMXSECURE=%d, MXADS[0]=%d, ste=%p\n",
2037*d39bd2c1SGregory Neil Shapiro 				to->q_user, rcptcount, QISSECURE(to),
2038*d39bd2c1SGregory Neil Shapiro 				RCPT_MXSECURE(to), MXADS_ISSET(mxads, 0), ste);
2039*d39bd2c1SGregory Neil Shapiro 			sm_dprintf("tochain: hostsig=%s, mx=%s, tlsa_n=%d, tlsa_flags=%#lx, chk_dane=%d, dane_req=%d\n"
2040*d39bd2c1SGregory Neil Shapiro 				, to->q_signature, mxhosts[0]
2041*d39bd2c1SGregory Neil Shapiro 				, STE_HAS_TLSA(ste) ? ste->s_tlsa->dane_tlsa_n : -1
2042*d39bd2c1SGregory Neil Shapiro 				, STE_HAS_TLSA(ste) ? ste->s_tlsa->dane_tlsa_flags : -1
2043*d39bd2c1SGregory Neil Shapiro 				, CHK_DANE_RCPT(Dane, to)
2044*d39bd2c1SGregory Neil Shapiro 				, dane_req
2045*d39bd2c1SGregory Neil Shapiro 				);
2046*d39bd2c1SGregory Neil Shapiro 			if (p != NULL)
2047*d39bd2c1SGregory Neil Shapiro 				*p = sep;
2048*d39bd2c1SGregory Neil Shapiro 		}
2049*d39bd2c1SGregory Neil Shapiro 		if (NODANEREQYET == dane_req)
2050*d39bd2c1SGregory Neil Shapiro 			dane_req = CHK_DANE_RCPT(Dane, to);
2051*d39bd2c1SGregory Neil Shapiro 		else if (dane_req != CHK_DANE_RCPT(Dane, to))
2052*d39bd2c1SGregory Neil Shapiro 		{
2053*d39bd2c1SGregory Neil Shapiro 			if (tTd(10, 30))
2054*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("tochain: to=%s, rcptcount=%d, status=skip\n",
2055*d39bd2c1SGregory Neil Shapiro 					to->q_user, rcptcount);
2056*d39bd2c1SGregory Neil Shapiro 			continue;
2057*d39bd2c1SGregory Neil Shapiro 		}
2058*d39bd2c1SGregory Neil Shapiro #endif /* DANE */
2059*d39bd2c1SGregory Neil Shapiro 
20602fb4f839SGregory Neil Shapiro 		/*
20612fb4f839SGregory Neil Shapiro 		**  prepare envelope for new session to avoid leakage
20622fb4f839SGregory Neil Shapiro 		**  between delivery attempts.
20632fb4f839SGregory Neil Shapiro 		*/
20642fb4f839SGregory Neil Shapiro 
20652fb4f839SGregory Neil Shapiro 		smtpclrse(e);
20662fb4f839SGregory Neil Shapiro 
2067c2aa98e2SPeter Wemm 		if (tTd(10, 1))
2068c2aa98e2SPeter Wemm 		{
206940266059SGregory Neil Shapiro 			sm_dprintf("\nsend to ");
2070e92d3f3fSGregory Neil Shapiro 			printaddr(sm_debug_file(), to, false);
2071c2aa98e2SPeter Wemm 		}
2072c2aa98e2SPeter Wemm 
2073c2aa98e2SPeter Wemm 		/* compute effective uid/gid when sending */
2074c2aa98e2SPeter Wemm 		if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
207540266059SGregory Neil Shapiro #if HASSETUSERCONTEXT
2076c2aa98e2SPeter Wemm 			contextaddr = ctladdr = getctladdr(to);
20775b0945b5SGregory Neil Shapiro #else
207840266059SGregory Neil Shapiro 			ctladdr = getctladdr(to);
20795b0945b5SGregory Neil Shapiro #endif
2080c2aa98e2SPeter Wemm 
2081c2aa98e2SPeter Wemm 		if (tTd(10, 2))
2082c2aa98e2SPeter Wemm 		{
208340266059SGregory Neil Shapiro 			sm_dprintf("ctladdr=");
2084e92d3f3fSGregory Neil Shapiro 			printaddr(sm_debug_file(), ctladdr, false);
2085c2aa98e2SPeter Wemm 		}
2086c2aa98e2SPeter Wemm 
2087c2aa98e2SPeter Wemm 		user = to->q_user;
2088c2aa98e2SPeter Wemm 		e->e_to = to->q_paddr;
2089c2aa98e2SPeter Wemm 
2090c2aa98e2SPeter Wemm 		/*
2091c2aa98e2SPeter Wemm 		**  Check to see that these people are allowed to
2092c2aa98e2SPeter Wemm 		**  talk to each other.
209342e5d165SGregory Neil Shapiro 		**  Check also for overflow of e_msgsize.
2094c2aa98e2SPeter Wemm 		*/
2095c2aa98e2SPeter Wemm 
209642e5d165SGregory Neil Shapiro 		if (m->m_maxsize != 0 &&
209742e5d165SGregory Neil Shapiro 		    (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0))
2098c2aa98e2SPeter Wemm 		{
2099c2aa98e2SPeter Wemm 			e->e_flags |= EF_NO_BODY_RETN;
2100c2aa98e2SPeter Wemm 			if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags))
2101c2aa98e2SPeter Wemm 				to->q_status = "5.2.3";
2102c2aa98e2SPeter Wemm 			else
2103c2aa98e2SPeter Wemm 				to->q_status = "5.3.4";
210440266059SGregory Neil Shapiro 
210506f25ae9SGregory Neil Shapiro 			/* set to->q_rstatus = NULL; or to the following? */
210606f25ae9SGregory Neil Shapiro 			usrerrenh(to->q_status,
210706f25ae9SGregory Neil Shapiro 				  "552 Message is too large; %ld bytes max",
210806f25ae9SGregory Neil Shapiro 				  m->m_maxsize);
210940266059SGregory Neil Shapiro 			markfailure(e, to, NULL, EX_UNAVAILABLE, false);
211006f25ae9SGregory Neil Shapiro 			giveresponse(EX_UNAVAILABLE, to->q_status, m,
211140266059SGregory Neil Shapiro 				     NULL, ctladdr, xstart, e, to);
2112c2aa98e2SPeter Wemm 			continue;
2113c2aa98e2SPeter Wemm 		}
2114602a2b1bSGregory Neil Shapiro 		SM_SET_H_ERRNO(0);
211540266059SGregory Neil Shapiro 		ovr = true;
2116c2aa98e2SPeter Wemm 
2117c2aa98e2SPeter Wemm 		/* do config file checking of compatibility */
211840266059SGregory Neil Shapiro 		quarantine = (e->e_quarmsg != NULL);
211906f25ae9SGregory Neil Shapiro 		rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr,
2120959366dcSGregory Neil Shapiro 				e, RSF_RMCOMM|RSF_COUNT, 3, NULL,
2121da7d7b9cSGregory Neil Shapiro 				e->e_id, NULL, NULL);
2122c2aa98e2SPeter Wemm 		if (rcode == EX_OK)
2123c2aa98e2SPeter Wemm 		{
2124065a643dSPeter Wemm 			/* do in-code checking if not discarding */
2125065a643dSPeter Wemm 			if (!bitset(EF_DISCARD, e->e_flags))
212606f25ae9SGregory Neil Shapiro 			{
2127c2aa98e2SPeter Wemm 				rcode = checkcompat(to, e);
212840266059SGregory Neil Shapiro 				ovr = false;
212906f25ae9SGregory Neil Shapiro 			}
2130c2aa98e2SPeter Wemm 		}
2131c2aa98e2SPeter Wemm 		if (rcode != EX_OK)
2132c2aa98e2SPeter Wemm 		{
213306f25ae9SGregory Neil Shapiro 			markfailure(e, to, NULL, rcode, ovr);
213406f25ae9SGregory Neil Shapiro 			giveresponse(rcode, to->q_status, m,
213540266059SGregory Neil Shapiro 				     NULL, ctladdr, xstart, e, to);
2136c2aa98e2SPeter Wemm 			continue;
2137c2aa98e2SPeter Wemm 		}
213840266059SGregory Neil Shapiro 		if (!quarantine && e->e_quarmsg != NULL)
213940266059SGregory Neil Shapiro 		{
214040266059SGregory Neil Shapiro 			/*
214140266059SGregory Neil Shapiro 			**  check_compat or checkcompat() has tried
214240266059SGregory Neil Shapiro 			**  to quarantine but that isn't supported.
214340266059SGregory Neil Shapiro 			**  Revert the attempt.
214440266059SGregory Neil Shapiro 			*/
214540266059SGregory Neil Shapiro 
214640266059SGregory Neil Shapiro 			e->e_quarmsg = NULL;
214740266059SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM,
214840266059SGregory Neil Shapiro 				  macid("{quarantine}"), "");
214940266059SGregory Neil Shapiro 		}
2150065a643dSPeter Wemm 		if (bitset(EF_DISCARD, e->e_flags))
2151065a643dSPeter Wemm 		{
2152065a643dSPeter Wemm 			if (tTd(10, 5))
2153065a643dSPeter Wemm 			{
215440266059SGregory Neil Shapiro 				sm_dprintf("deliver: discarding recipient ");
2155e92d3f3fSGregory Neil Shapiro 				printaddr(sm_debug_file(), to, false);
2156065a643dSPeter Wemm 			}
2157065a643dSPeter Wemm 
215806f25ae9SGregory Neil Shapiro 			/* pretend the message was sent */
215906f25ae9SGregory Neil Shapiro 			/* XXX should we log something here? */
216006f25ae9SGregory Neil Shapiro 			to->q_state = QS_DISCARDED;
216106f25ae9SGregory Neil Shapiro 
2162065a643dSPeter Wemm 			/*
2163065a643dSPeter Wemm 			**  Remove discard bit to prevent discard of
216406f25ae9SGregory Neil Shapiro 			**  future recipients.  This is safe because the
216506f25ae9SGregory Neil Shapiro 			**  true "global discard" has been handled before
216606f25ae9SGregory Neil Shapiro 			**  we get here.
2167065a643dSPeter Wemm 			*/
2168065a643dSPeter Wemm 
216906f25ae9SGregory Neil Shapiro 			e->e_flags &= ~EF_DISCARD;
2170065a643dSPeter Wemm 			continue;
2171065a643dSPeter Wemm 		}
2172c2aa98e2SPeter Wemm 
2173c2aa98e2SPeter Wemm 		/*
2174c2aa98e2SPeter Wemm 		**  Strip quote bits from names if the mailer is dumb
2175c2aa98e2SPeter Wemm 		**	about them.
2176c2aa98e2SPeter Wemm 		*/
2177c2aa98e2SPeter Wemm 
2178c2aa98e2SPeter Wemm 		if (bitnset(M_STRIPQ, m->m_flags))
2179c2aa98e2SPeter Wemm 		{
2180c2aa98e2SPeter Wemm 			stripquotes(user);
2181c2aa98e2SPeter Wemm 			stripquotes(host);
2182c2aa98e2SPeter Wemm 		}
2183e92d3f3fSGregory Neil Shapiro 
218413bd1963SGregory Neil Shapiro 		/*
2185b6bacd31SGregory Neil Shapiro 		**  Strip all leading backslashes if requested and the
218613bd1963SGregory Neil Shapiro 		**  next character is alphanumerical (the latter can
218713bd1963SGregory Neil Shapiro 		**  probably relaxed a bit, see RFC2821).
218813bd1963SGregory Neil Shapiro 		*/
218913bd1963SGregory Neil Shapiro 
219013bd1963SGregory Neil Shapiro 		if (bitnset(M_STRIPBACKSL, m->m_flags) && user[0] == '\\')
219113bd1963SGregory Neil Shapiro 			stripbackslash(user);
2192c2aa98e2SPeter Wemm 
2193c2aa98e2SPeter Wemm 		/* hack attack -- delivermail compatibility */
2194c2aa98e2SPeter Wemm 		if (m == ProgMailer && *user == '|')
2195c2aa98e2SPeter Wemm 			user++;
2196c2aa98e2SPeter Wemm 
2197c2aa98e2SPeter Wemm 		/*
2198c2aa98e2SPeter Wemm 		**  If an error message has already been given, don't
2199c2aa98e2SPeter Wemm 		**	bother to send to this address.
2200c2aa98e2SPeter Wemm 		**
2201c2aa98e2SPeter Wemm 		**	>>>>>>>>>> This clause assumes that the local mailer
2202c2aa98e2SPeter Wemm 		**	>> NOTE >> cannot do any further aliasing; that
2203c2aa98e2SPeter Wemm 		**	>>>>>>>>>> function is subsumed by sendmail.
2204c2aa98e2SPeter Wemm 		*/
2205c2aa98e2SPeter Wemm 
220606f25ae9SGregory Neil Shapiro 		if (!QS_IS_OK(to->q_state))
2207c2aa98e2SPeter Wemm 			continue;
2208c2aa98e2SPeter Wemm 
2209c2aa98e2SPeter Wemm 		/*
2210c2aa98e2SPeter Wemm 		**  See if this user name is "special".
2211c2aa98e2SPeter Wemm 		**	If the user name has a slash in it, assume that this
2212c2aa98e2SPeter Wemm 		**	is a file -- send it off without further ado.  Note
2213c2aa98e2SPeter Wemm 		**	that this type of addresses is not processed along
2214c2aa98e2SPeter Wemm 		**	with the others, so we fudge on the To person.
2215c2aa98e2SPeter Wemm 		*/
2216c2aa98e2SPeter Wemm 
2217c2aa98e2SPeter Wemm 		if (strcmp(m->m_mailer, "[FILE]") == 0)
2218c2aa98e2SPeter Wemm 		{
221940266059SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, 'u', user);
2220c2aa98e2SPeter Wemm 			p = to->q_home;
2221c2aa98e2SPeter Wemm 			if (p == NULL && ctladdr != NULL)
2222c2aa98e2SPeter Wemm 				p = ctladdr->q_home;
222340266059SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, 'z', p);
2224d0cef73dSGregory Neil Shapiro 			expand(m->m_argv[1], buf, sizeof(buf), e);
2225c2aa98e2SPeter Wemm 			if (strlen(buf) > 0)
2226c2aa98e2SPeter Wemm 				rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e);
2227c2aa98e2SPeter Wemm 			else
2228c2aa98e2SPeter Wemm 			{
2229c2aa98e2SPeter Wemm 				syserr("empty filename specification for mailer %s",
2230c2aa98e2SPeter Wemm 				       m->m_name);
2231c2aa98e2SPeter Wemm 				rcode = EX_CONFIG;
2232c2aa98e2SPeter Wemm 			}
223306f25ae9SGregory Neil Shapiro 			giveresponse(rcode, to->q_status, m, NULL,
223440266059SGregory Neil Shapiro 				     ctladdr, xstart, e, to);
223540266059SGregory Neil Shapiro 			markfailure(e, to, NULL, rcode, true);
2236c2aa98e2SPeter Wemm 			e->e_nsent++;
2237c2aa98e2SPeter Wemm 			if (rcode == EX_OK)
2238c2aa98e2SPeter Wemm 			{
223906f25ae9SGregory Neil Shapiro 				to->q_state = QS_SENT;
2240c2aa98e2SPeter Wemm 				if (bitnset(M_LOCALMAILER, m->m_flags) &&
2241c2aa98e2SPeter Wemm 				    bitset(QPINGONSUCCESS, to->q_flags))
2242c2aa98e2SPeter Wemm 				{
2243c2aa98e2SPeter Wemm 					to->q_flags |= QDELIVERED;
2244c2aa98e2SPeter Wemm 					to->q_status = "2.1.5";
224540266059SGregory Neil Shapiro 					(void) sm_io_fprintf(e->e_xfp,
224640266059SGregory Neil Shapiro 							     SM_TIME_DEFAULT,
224740266059SGregory Neil Shapiro 							     "%s... Successfully delivered\n",
2248c2aa98e2SPeter Wemm 							     to->q_paddr);
2249c2aa98e2SPeter Wemm 				}
2250c2aa98e2SPeter Wemm 			}
2251c2aa98e2SPeter Wemm 			to->q_statdate = curtime();
225240266059SGregory Neil Shapiro 			markstats(e, to, STATS_NORMAL);
2253c2aa98e2SPeter Wemm 			continue;
2254c2aa98e2SPeter Wemm 		}
2255c2aa98e2SPeter Wemm 
2256c2aa98e2SPeter Wemm 		/*
2257c2aa98e2SPeter Wemm 		**  Address is verified -- add this user to mailer
2258c2aa98e2SPeter Wemm 		**  argv, and add it to the print list of recipients.
2259c2aa98e2SPeter Wemm 		*/
2260c2aa98e2SPeter Wemm 
2261c2aa98e2SPeter Wemm 		/* link together the chain of recipients */
2262c2aa98e2SPeter Wemm 		to->q_tchain = tochain;
2263c2aa98e2SPeter Wemm 		tochain = to;
226406f25ae9SGregory Neil Shapiro 		e->e_to = "[CHAIN]";
226506f25ae9SGregory Neil Shapiro 
226640266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'u', user);  /* to user */
2267c2aa98e2SPeter Wemm 		p = to->q_home;
2268c2aa98e2SPeter Wemm 		if (p == NULL && ctladdr != NULL)
2269c2aa98e2SPeter Wemm 			p = ctladdr->q_home;
227040266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'z', p);  /* user's home */
2271c2aa98e2SPeter Wemm 
227206f25ae9SGregory Neil Shapiro 		/* set the ${dsn_notify} macro if applicable */
227306f25ae9SGregory Neil Shapiro 		if (bitset(QHASNOTIFY, to->q_flags))
227406f25ae9SGregory Neil Shapiro 		{
227506f25ae9SGregory Neil Shapiro 			char notify[MAXLINE];
227606f25ae9SGregory Neil Shapiro 
227706f25ae9SGregory Neil Shapiro 			notify[0] = '\0';
227806f25ae9SGregory Neil Shapiro 			if (bitset(QPINGONSUCCESS, to->q_flags))
227940266059SGregory Neil Shapiro 				(void) sm_strlcat(notify, "SUCCESS,",
2280d0cef73dSGregory Neil Shapiro 						  sizeof(notify));
228106f25ae9SGregory Neil Shapiro 			if (bitset(QPINGONFAILURE, to->q_flags))
228240266059SGregory Neil Shapiro 				(void) sm_strlcat(notify, "FAILURE,",
2283d0cef73dSGregory Neil Shapiro 						  sizeof(notify));
228406f25ae9SGregory Neil Shapiro 			if (bitset(QPINGONDELAY, to->q_flags))
228540266059SGregory Neil Shapiro 				(void) sm_strlcat(notify, "DELAY,",
2286d0cef73dSGregory Neil Shapiro 						  sizeof(notify));
228706f25ae9SGregory Neil Shapiro 
228806f25ae9SGregory Neil Shapiro 			/* Set to NEVER or drop trailing comma */
228906f25ae9SGregory Neil Shapiro 			if (notify[0] == '\0')
229040266059SGregory Neil Shapiro 				(void) sm_strlcat(notify, "NEVER",
2291d0cef73dSGregory Neil Shapiro 						  sizeof(notify));
229206f25ae9SGregory Neil Shapiro 			else
229306f25ae9SGregory Neil Shapiro 				notify[strlen(notify) - 1] = '\0';
229406f25ae9SGregory Neil Shapiro 
229540266059SGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
229640266059SGregory Neil Shapiro 				macid("{dsn_notify}"), notify);
229706f25ae9SGregory Neil Shapiro 		}
229806f25ae9SGregory Neil Shapiro 		else
229940266059SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM,
230040266059SGregory Neil Shapiro 				macid("{dsn_notify}"), NULL);
230106f25ae9SGregory Neil Shapiro 
2302c2aa98e2SPeter Wemm 		/*
2303c2aa98e2SPeter Wemm 		**  Expand out this user into argument list.
2304c2aa98e2SPeter Wemm 		*/
2305c2aa98e2SPeter Wemm 
2306c2aa98e2SPeter Wemm 		if (!clever)
2307c2aa98e2SPeter Wemm 		{
2308d0cef73dSGregory Neil Shapiro 			expand(*mvp, buf, sizeof(buf), e);
2309*d39bd2c1SGregory Neil Shapiro 			p = buf;
2310*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
2311*d39bd2c1SGregory Neil Shapiro 			if (((*mvp)[0] & 0377) == MACROEXPAND)
2312*d39bd2c1SGregory Neil Shapiro 			{
2313*d39bd2c1SGregory Neil Shapiro 				(void) dequote_internal_chars(buf, xbuf, sizeof(xbuf));
2314*d39bd2c1SGregory Neil Shapiro 				p = xbuf;
2315*d39bd2c1SGregory Neil Shapiro 				if (tTd(10, 33))
2316*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("expand(%s), dequoted=%s\n", *mvp, p);
2317*d39bd2c1SGregory Neil Shapiro 			}
2318*d39bd2c1SGregory Neil Shapiro #endif
2319*d39bd2c1SGregory Neil Shapiro 			*pvp++ = sm_rpool_strdup_x(e->e_rpool, p);
2320c2aa98e2SPeter Wemm 			if (pvp >= &pv[MAXPV - 2])
2321c2aa98e2SPeter Wemm 			{
2322c2aa98e2SPeter Wemm 				/* allow some space for trailing parms */
2323c2aa98e2SPeter Wemm 				break;
2324c2aa98e2SPeter Wemm 			}
2325c2aa98e2SPeter Wemm 		}
2326c2aa98e2SPeter Wemm 	}
2327c2aa98e2SPeter Wemm 
2328c2aa98e2SPeter Wemm 	/* see if any addresses still exist */
232906f25ae9SGregory Neil Shapiro 	if (tochain == NULL)
2330c2aa98e2SPeter Wemm 	{
233140266059SGregory Neil Shapiro 		rcode = 0;
233240266059SGregory Neil Shapiro 		goto cleanup;
2333c2aa98e2SPeter Wemm 	}
2334c2aa98e2SPeter Wemm 
2335c2aa98e2SPeter Wemm 	/* print out messages as full list */
233640266059SGregory Neil Shapiro 	strsize = 1;
233706f25ae9SGregory Neil Shapiro 	for (to = tochain; to != NULL; to = to->q_tchain)
233840266059SGregory Neil Shapiro 		strsize += strlen(to->q_paddr) + 1;
233940266059SGregory Neil Shapiro 	if (strsize < TOBUFSIZE)
234040266059SGregory Neil Shapiro 		strsize = TOBUFSIZE;
234140266059SGregory Neil Shapiro 	if (strsize > tobufsize)
234206f25ae9SGregory Neil Shapiro 	{
23435b0945b5SGregory Neil Shapiro 		SM_FREE(tobuf);
234440266059SGregory Neil Shapiro 		tobuf = sm_pmalloc_x(strsize);
234540266059SGregory Neil Shapiro 		tobufsize = strsize;
234606f25ae9SGregory Neil Shapiro 	}
234740266059SGregory Neil Shapiro 	p = tobuf;
234840266059SGregory Neil Shapiro 	*p = '\0';
234906f25ae9SGregory Neil Shapiro 	for (to = tochain; to != NULL; to = to->q_tchain)
235006f25ae9SGregory Neil Shapiro 	{
235140266059SGregory Neil Shapiro 		(void) sm_strlcpyn(p, tobufsize - (p - tobuf), 2,
235240266059SGregory Neil Shapiro 				   ",", to->q_paddr);
235340266059SGregory Neil Shapiro 		p += strlen(p);
235406f25ae9SGregory Neil Shapiro 	}
2355c2aa98e2SPeter Wemm 	e->e_to = tobuf + 1;
2356c2aa98e2SPeter Wemm 
2357c2aa98e2SPeter Wemm 	/*
2358c2aa98e2SPeter Wemm 	**  Fill out any parameters after the $u parameter.
2359c2aa98e2SPeter Wemm 	*/
2360c2aa98e2SPeter Wemm 
236140266059SGregory Neil Shapiro 	if (!clever)
236240266059SGregory Neil Shapiro 	{
236340266059SGregory Neil Shapiro 		while (*++mvp != NULL)
2364c2aa98e2SPeter Wemm 		{
2365d0cef73dSGregory Neil Shapiro 			expand(*mvp, buf, sizeof(buf), e);
2366*d39bd2c1SGregory Neil Shapiro 			p = buf;
2367*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR && 0
2368*d39bd2c1SGregory Neil Shapiro 			/* disabled for now - is there a use case for this? */
2369*d39bd2c1SGregory Neil Shapiro 			if (((*mvp)[0] & 0377) == MACROEXPAND)
2370*d39bd2c1SGregory Neil Shapiro 			{
2371*d39bd2c1SGregory Neil Shapiro 				(void) dequote_internal_chars(buf, xbuf, sizeof(xbuf));
2372*d39bd2c1SGregory Neil Shapiro 				p = xbuf;
2373*d39bd2c1SGregory Neil Shapiro 				if (tTd(10, 33))
2374*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("expand(%s), dequoted=%s\n", *mvp, p);
2375*d39bd2c1SGregory Neil Shapiro 			}
2376*d39bd2c1SGregory Neil Shapiro #endif
2377*d39bd2c1SGregory Neil Shapiro 			*pvp++ = sm_rpool_strdup_x(e->e_rpool, p);
2378c2aa98e2SPeter Wemm 			if (pvp >= &pv[MAXPV])
237906f25ae9SGregory Neil Shapiro 				syserr("554 5.3.0 deliver: pv overflow after $u for %s",
238006f25ae9SGregory Neil Shapiro 				       pv[0]);
2381c2aa98e2SPeter Wemm 		}
238240266059SGregory Neil Shapiro 	}
2383c2aa98e2SPeter Wemm 	*pvp++ = NULL;
2384c2aa98e2SPeter Wemm 
2385c2aa98e2SPeter Wemm 	/*
2386c2aa98e2SPeter Wemm 	**  Call the mailer.
2387c2aa98e2SPeter Wemm 	**	The argument vector gets built, pipes
2388c2aa98e2SPeter Wemm 	**	are created as necessary, and we fork & exec as
2389c2aa98e2SPeter Wemm 	**	appropriate.
2390c2aa98e2SPeter Wemm 	**	If we are running SMTP, we just need to clean up.
2391c2aa98e2SPeter Wemm 	*/
2392c2aa98e2SPeter Wemm 
23936f9c8e5bSGregory Neil Shapiro 	/* XXX this seems a bit weird */
2394c2aa98e2SPeter Wemm 	if (ctladdr == NULL && m != ProgMailer && m != FileMailer &&
2395c2aa98e2SPeter Wemm 	    bitset(QGOODUID, e->e_from.q_flags))
2396c2aa98e2SPeter Wemm 		ctladdr = &e->e_from;
2397c2aa98e2SPeter Wemm 
2398c2aa98e2SPeter Wemm #if NAMED_BIND
2399c2aa98e2SPeter Wemm 	if (ConfigLevel < 2)
2400c2aa98e2SPeter Wemm 		_res.options &= ~(RES_DEFNAMES | RES_DNSRCH);	/* XXX */
24015b0945b5SGregory Neil Shapiro #endif
2402c2aa98e2SPeter Wemm 
2403c2aa98e2SPeter Wemm 	if (tTd(11, 1))
2404c2aa98e2SPeter Wemm 	{
240540266059SGregory Neil Shapiro 		sm_dprintf("openmailer:");
2406e92d3f3fSGregory Neil Shapiro 		printav(sm_debug_file(), pv);
2407c2aa98e2SPeter Wemm 	}
2408c2aa98e2SPeter Wemm 	errno = 0;
2409602a2b1bSGregory Neil Shapiro 	SM_SET_H_ERRNO(0);
2410c2aa98e2SPeter Wemm 	CurHostName = NULL;
2411c2aa98e2SPeter Wemm 
2412c2aa98e2SPeter Wemm 	/*
2413c2aa98e2SPeter Wemm 	**  Deal with the special case of mail handled through an IPC
2414c2aa98e2SPeter Wemm 	**  connection.
2415c2aa98e2SPeter Wemm 	**	In this case we don't actually fork.  We must be
2416c2aa98e2SPeter Wemm 	**	running SMTP for this to work.  We will return a
2417c2aa98e2SPeter Wemm 	**	zero pid to indicate that we are running IPC.
2418c2aa98e2SPeter Wemm 	**  We also handle a debug version that just talks to stdin/out.
2419c2aa98e2SPeter Wemm 	*/
2420c2aa98e2SPeter Wemm 
2421c2aa98e2SPeter Wemm 	curhost = NULL;
2422c2aa98e2SPeter Wemm 	SmtpPhase = NULL;
2423c2aa98e2SPeter Wemm 	mci = NULL;
2424c2aa98e2SPeter Wemm 
2425c2aa98e2SPeter Wemm #if XDEBUG
2426c2aa98e2SPeter Wemm 	{
2427c2aa98e2SPeter Wemm 		char wbuf[MAXLINE];
2428c2aa98e2SPeter Wemm 
2429c2aa98e2SPeter Wemm 		/* make absolutely certain 0, 1, and 2 are in use */
2430d0cef73dSGregory Neil Shapiro 		(void) sm_snprintf(wbuf, sizeof(wbuf), "%s... openmailer(%s)",
243140266059SGregory Neil Shapiro 				   shortenstring(e->e_to, MAXSHORTSTR),
243240266059SGregory Neil Shapiro 				   m->m_name);
2433c2aa98e2SPeter Wemm 		checkfd012(wbuf);
2434c2aa98e2SPeter Wemm 	}
243506f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
2436c2aa98e2SPeter Wemm 
2437c2aa98e2SPeter Wemm 	/* check for 8-bit available */
2438c2aa98e2SPeter Wemm 	if (bitset(EF_HAS8BIT, e->e_flags) &&
2439c2aa98e2SPeter Wemm 	    bitnset(M_7BITS, m->m_flags) &&
2440c2aa98e2SPeter Wemm 	    (bitset(EF_DONT_MIME, e->e_flags) ||
2441c2aa98e2SPeter Wemm 	     !(bitset(MM_MIME8BIT, MimeMode) ||
2442c2aa98e2SPeter Wemm 	       (bitset(EF_IS_MIME, e->e_flags) &&
2443c2aa98e2SPeter Wemm 		bitset(MM_CVTMIME, MimeMode)))))
2444c2aa98e2SPeter Wemm 	{
2445c2aa98e2SPeter Wemm 		e->e_status = "5.6.3";
244606f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status,
244706f25ae9SGregory Neil Shapiro 			  "554 Cannot send 8-bit data to 7-bit destination");
244806f25ae9SGregory Neil Shapiro 		rcode = EX_DATAERR;
2449c2aa98e2SPeter Wemm 		goto give_up;
2450c2aa98e2SPeter Wemm 	}
2451c2aa98e2SPeter Wemm 
2452c2aa98e2SPeter Wemm 	if (tTd(62, 8))
2453c2aa98e2SPeter Wemm 		checkfds("before delivery");
2454c2aa98e2SPeter Wemm 
2455c2aa98e2SPeter Wemm 	/* check for Local Person Communication -- not for mortals!!! */
2456c2aa98e2SPeter Wemm 	if (strcmp(m->m_mailer, "[LPC]") == 0)
2457c2aa98e2SPeter Wemm 	{
245840266059SGregory Neil Shapiro 		if (clever)
245940266059SGregory Neil Shapiro 		{
246040266059SGregory Neil Shapiro 			/* flush any expired connections */
246140266059SGregory Neil Shapiro 			(void) mci_scan(NULL);
246240266059SGregory Neil Shapiro 
246340266059SGregory Neil Shapiro 			/* try to get a cached connection or just a slot */
246440266059SGregory Neil Shapiro 			mci = mci_get(m->m_name, m);
246540266059SGregory Neil Shapiro 			if (mci->mci_host == NULL)
246640266059SGregory Neil Shapiro 				mci->mci_host = m->m_name;
246740266059SGregory Neil Shapiro 			CurHostName = mci->mci_host;
246840266059SGregory Neil Shapiro 			if (mci->mci_state != MCIS_CLOSED)
246940266059SGregory Neil Shapiro 			{
247040266059SGregory Neil Shapiro 				message("Using cached SMTP/LPC connection for %s...",
247140266059SGregory Neil Shapiro 					m->m_name);
247240266059SGregory Neil Shapiro 				mci->mci_deliveries++;
247340266059SGregory Neil Shapiro 				goto do_transfer;
247440266059SGregory Neil Shapiro 			}
247540266059SGregory Neil Shapiro 		}
247640266059SGregory Neil Shapiro 		else
247740266059SGregory Neil Shapiro 		{
247840266059SGregory Neil Shapiro 			mci = mci_new(e->e_rpool);
247940266059SGregory Neil Shapiro 		}
248040266059SGregory Neil Shapiro 		mci->mci_in = smioin;
248140266059SGregory Neil Shapiro 		mci->mci_out = smioout;
248240266059SGregory Neil Shapiro 		mci->mci_mailer = m;
248340266059SGregory Neil Shapiro 		mci->mci_host = m->m_name;
248440266059SGregory Neil Shapiro 		if (clever)
248540266059SGregory Neil Shapiro 		{
248640266059SGregory Neil Shapiro 			mci->mci_state = MCIS_OPENING;
248740266059SGregory Neil Shapiro 			mci_cache(mci);
248840266059SGregory Neil Shapiro 		}
248940266059SGregory Neil Shapiro 		else
249040266059SGregory Neil Shapiro 			mci->mci_state = MCIS_OPEN;
2491c2aa98e2SPeter Wemm 	}
249240266059SGregory Neil Shapiro 	else if (strcmp(m->m_mailer, "[IPC]") == 0)
2493c2aa98e2SPeter Wemm 	{
2494c2aa98e2SPeter Wemm 		register int i;
2495c2aa98e2SPeter Wemm 
2496c2aa98e2SPeter Wemm 		if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
2497c2aa98e2SPeter Wemm 		{
249806f25ae9SGregory Neil Shapiro 			syserr("null destination for %s mailer", m->m_mailer);
2499c2aa98e2SPeter Wemm 			rcode = EX_CONFIG;
2500c2aa98e2SPeter Wemm 			goto give_up;
2501c2aa98e2SPeter Wemm 		}
2502c2aa98e2SPeter Wemm 
250306f25ae9SGregory Neil Shapiro #if NETUNIX
250406f25ae9SGregory Neil Shapiro 		if (strcmp(pv[0], "FILE") == 0)
250506f25ae9SGregory Neil Shapiro 		{
250606f25ae9SGregory Neil Shapiro 			curhost = CurHostName = "localhost";
250706f25ae9SGregory Neil Shapiro 			mux_path = pv[1];
250806f25ae9SGregory Neil Shapiro 		}
250906f25ae9SGregory Neil Shapiro 		else
251006f25ae9SGregory Neil Shapiro #endif /* NETUNIX */
25112fb4f839SGregory Neil Shapiro 		/* "else" in #if code above */
251206f25ae9SGregory Neil Shapiro 		{
2513c2aa98e2SPeter Wemm 			CurHostName = pv[1];
25145b0945b5SGregory Neil Shapiro 							/* XXX ??? */
2515*d39bd2c1SGregory Neil Shapiro 			curhost = hostsignature(m, pv[1],
2516*d39bd2c1SGregory Neil Shapiro 					QISSECURE(firstto),
2517*d39bd2c1SGregory Neil Shapiro 					&firstto->q_flags);
251806f25ae9SGregory Neil Shapiro 		}
2519c2aa98e2SPeter Wemm 
2520c2aa98e2SPeter Wemm 		if (curhost == NULL || curhost[0] == '\0')
2521c2aa98e2SPeter Wemm 		{
2522c2aa98e2SPeter Wemm 			syserr("null host signature for %s", pv[1]);
2523c2aa98e2SPeter Wemm 			rcode = EX_CONFIG;
2524c2aa98e2SPeter Wemm 			goto give_up;
2525c2aa98e2SPeter Wemm 		}
2526c2aa98e2SPeter Wemm 
2527c2aa98e2SPeter Wemm 		if (!clever)
2528c2aa98e2SPeter Wemm 		{
252906f25ae9SGregory Neil Shapiro 			syserr("554 5.3.5 non-clever IPC");
2530c2aa98e2SPeter Wemm 			rcode = EX_CONFIG;
2531c2aa98e2SPeter Wemm 			goto give_up;
2532c2aa98e2SPeter Wemm 		}
253306f25ae9SGregory Neil Shapiro 		if (pv[2] != NULL
253406f25ae9SGregory Neil Shapiro #if NETUNIX
253506f25ae9SGregory Neil Shapiro 		    && mux_path == NULL
25365b0945b5SGregory Neil Shapiro #endif
253706f25ae9SGregory Neil Shapiro 		    )
2538c2aa98e2SPeter Wemm 		{
253940266059SGregory Neil Shapiro 			port = htons((unsigned short) atoi(pv[2]));
2540c2aa98e2SPeter Wemm 			if (port == 0)
2541c2aa98e2SPeter Wemm 			{
254206f25ae9SGregory Neil Shapiro #ifdef NO_GETSERVBYNAME
254306f25ae9SGregory Neil Shapiro 				syserr("Invalid port number: %s", pv[2]);
254406f25ae9SGregory Neil Shapiro #else /* NO_GETSERVBYNAME */
2545c2aa98e2SPeter Wemm 				struct servent *sp = getservbyname(pv[2], "tcp");
2546c2aa98e2SPeter Wemm 
2547c2aa98e2SPeter Wemm 				if (sp == NULL)
2548c2aa98e2SPeter Wemm 					syserr("Service %s unknown", pv[2]);
2549c2aa98e2SPeter Wemm 				else
2550c2aa98e2SPeter Wemm 					port = sp->s_port;
255106f25ae9SGregory Neil Shapiro #endif /* NO_GETSERVBYNAME */
2552c2aa98e2SPeter Wemm 			}
2553c2aa98e2SPeter Wemm 		}
2554c2aa98e2SPeter Wemm 
2555*d39bd2c1SGregory Neil Shapiro 		nummxhosts = parse_hostsignature(curhost, mxhosts, m
2556*d39bd2c1SGregory Neil Shapiro #if DANE
2557*d39bd2c1SGregory Neil Shapiro 				, mxads
2558*d39bd2c1SGregory Neil Shapiro #endif
2559*d39bd2c1SGregory Neil Shapiro 				);
256040266059SGregory Neil Shapiro 		if (TimeOuts.to_aconnect > 0)
256140266059SGregory Neil Shapiro 			enough = curtime() + TimeOuts.to_aconnect;
256206f25ae9SGregory Neil Shapiro tryhost:
256306f25ae9SGregory Neil Shapiro 		while (hostnum < nummxhosts)
256406f25ae9SGregory Neil Shapiro 		{
256506f25ae9SGregory Neil Shapiro 			char sep = ':';
256606f25ae9SGregory Neil Shapiro 			char *endp;
25672fb4f839SGregory Neil Shapiro 			static char hostbuf[MAXNAME_I + 1];
2568e92d3f3fSGregory Neil Shapiro 			bool tried_fallbacksmarthost = false;
25695b0945b5SGregory Neil Shapiro #if DANE
25705b0945b5SGregory Neil Shapiro 			unsigned long tlsa_flags;
2571*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2572*d39bd2c1SGregory Neil Shapiro 			bool mxsecure;
2573*d39bd2c1SGregory Neil Shapiro # endif
257406f25ae9SGregory Neil Shapiro 
25755b0945b5SGregory Neil Shapiro 			ste = NULL;
25765b0945b5SGregory Neil Shapiro 			tlsa_flags = 0;
2577*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2578*d39bd2c1SGregory Neil Shapiro 			mxsecure = MXADS_ISSET(mxads, hostnum);
25795b0945b5SGregory Neil Shapiro # endif
2580*d39bd2c1SGregory Neil Shapiro #endif /* DANE */
2581*d39bd2c1SGregory Neil Shapiro 			FIX_MXHOSTS(mxhosts[hostnum], endp, sep);
258206f25ae9SGregory Neil Shapiro 
258340266059SGregory Neil Shapiro 			if (hostnum == 1 && skip_back != NULL)
258440266059SGregory Neil Shapiro 			{
258540266059SGregory Neil Shapiro 				/*
258640266059SGregory Neil Shapiro 				**  Coattail piggybacking is no longer an
258740266059SGregory Neil Shapiro 				**  option with the mail host next to be tried
258840266059SGregory Neil Shapiro 				**  no longer the lowest MX preference
258940266059SGregory Neil Shapiro 				**  (hostnum == 1 meaning we're on the second
259040266059SGregory Neil Shapiro 				**  preference). We do not try to coattail
259140266059SGregory Neil Shapiro 				**  piggyback more than the first MX preference.
259240266059SGregory Neil Shapiro 				**  Revert 'tochain' to last location for
259340266059SGregory Neil Shapiro 				**  coincidental piggybacking. This works this
259440266059SGregory Neil Shapiro 				**  easily because the q_tchain kept getting
259540266059SGregory Neil Shapiro 				**  added to the top of the linked list.
259640266059SGregory Neil Shapiro 				*/
259740266059SGregory Neil Shapiro 
259840266059SGregory Neil Shapiro 				tochain = skip_back;
259940266059SGregory Neil Shapiro 			}
260040266059SGregory Neil Shapiro 
260106f25ae9SGregory Neil Shapiro 			if (*mxhosts[hostnum] == '\0')
2602c2aa98e2SPeter Wemm 			{
2603c2aa98e2SPeter Wemm 				syserr("deliver: null host name in signature");
260406f25ae9SGregory Neil Shapiro 				hostnum++;
260506f25ae9SGregory Neil Shapiro 				if (endp != NULL)
260606f25ae9SGregory Neil Shapiro 					*endp = sep;
2607c2aa98e2SPeter Wemm 				continue;
2608c2aa98e2SPeter Wemm 			}
260940266059SGregory Neil Shapiro 			(void) sm_strlcpy(hostbuf, mxhosts[hostnum],
2610d0cef73dSGregory Neil Shapiro 					  sizeof(hostbuf));
261106f25ae9SGregory Neil Shapiro 			hostnum++;
261206f25ae9SGregory Neil Shapiro 			if (endp != NULL)
261306f25ae9SGregory Neil Shapiro 				*endp = sep;
26145b0945b5SGregory Neil Shapiro #if STARTTLS
26155b0945b5SGregory Neil Shapiro 			tlsstate = 0;
26165b0945b5SGregory Neil Shapiro #endif
2617c2aa98e2SPeter Wemm 
2618e92d3f3fSGregory Neil Shapiro   one_last_try:
2619c2aa98e2SPeter Wemm 			/* see if we already know that this host is fried */
2620c2aa98e2SPeter Wemm 			CurHostName = hostbuf;
2621c2aa98e2SPeter Wemm 			mci = mci_get(hostbuf, m);
2622*d39bd2c1SGregory Neil Shapiro 
2623*d39bd2c1SGregory Neil Shapiro #if DANE
2624*d39bd2c1SGregory Neil Shapiro 			tlsa_flags = 0;
2625*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2626*d39bd2c1SGregory Neil Shapiro 			if (mxsecure)
2627*d39bd2c1SGregory Neil Shapiro 				firstto->q_flags |= QMXSECURE;
2628*d39bd2c1SGregory Neil Shapiro 			else
2629*d39bd2c1SGregory Neil Shapiro 				firstto->q_flags &= ~QMXSECURE;
2630*d39bd2c1SGregory Neil Shapiro # endif
2631*d39bd2c1SGregory Neil Shapiro 			if (TTD(90, 30))
2632*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("deliver: mci_get: 1: mci=%p, host=%s, mx=%s, ste=%p, dane=%#x, mci_state=%d, QMXSECURE=%d, reqdane=%d, chk_dane_rcpt=%d, firstto=%s, to=%s\n",
2633*d39bd2c1SGregory Neil Shapiro 					mci, host, hostbuf, ste, Dane,
2634*d39bd2c1SGregory Neil Shapiro 					mci->mci_state, RCPT_MXSECURE(firstto),
2635*d39bd2c1SGregory Neil Shapiro 					RCPT_REQ_DANE(firstto),
2636*d39bd2c1SGregory Neil Shapiro 					CHK_DANE_RCPT(Dane, firstto),
2637*d39bd2c1SGregory Neil Shapiro 					firstto->q_user, e->e_to);
2638*d39bd2c1SGregory Neil Shapiro 
2639*d39bd2c1SGregory Neil Shapiro 			if (CHK_DANE_RCPT(Dane, firstto))
2640*d39bd2c1SGregory Neil Shapiro 			{
2641*d39bd2c1SGregory Neil Shapiro 				(void) gettlsa(hostbuf, NULL, &ste,
2642*d39bd2c1SGregory Neil Shapiro 					RCPT_MXSECURE(firstto) ? TLSAFLADMX : 0,
2643*d39bd2c1SGregory Neil Shapiro 					0, m->m_port);
2644*d39bd2c1SGregory Neil Shapiro 			}
2645*d39bd2c1SGregory Neil Shapiro 			if (TTD(90, 30))
2646*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("deliver: host=%s, mx=%s, ste=%p, chk_dane=%d\n",
2647*d39bd2c1SGregory Neil Shapiro 					host, hostbuf, ste,
2648*d39bd2c1SGregory Neil Shapiro 					CHK_DANE_RCPT(Dane, firstto));
2649*d39bd2c1SGregory Neil Shapiro 
2650*d39bd2c1SGregory Neil Shapiro 			/* XXX: check expiration! */
2651*d39bd2c1SGregory Neil Shapiro 			if (ste != NULL && TLSA_RR_TEMPFAIL(ste->s_tlsa))
2652*d39bd2c1SGregory Neil Shapiro 			{
2653*d39bd2c1SGregory Neil Shapiro 				if (tTd(11, 1))
2654*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("skip: host=%s, TLSA_RR_lookup=%d\n"
2655*d39bd2c1SGregory Neil Shapiro 						, hostbuf
2656*d39bd2c1SGregory Neil Shapiro 						, ste->s_tlsa->dane_tlsa_dnsrc);
2657*d39bd2c1SGregory Neil Shapiro 
2658*d39bd2c1SGregory Neil Shapiro 				tlsa_flags |= TLSAFLTEMP;
2659*d39bd2c1SGregory Neil Shapiro 			}
2660*d39bd2c1SGregory Neil Shapiro 			else if (ste != NULL && TTD(90, 30))
2661*d39bd2c1SGregory Neil Shapiro 			{
2662*d39bd2c1SGregory Neil Shapiro 				if (ste->s_tlsa != NULL)
2663*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("deliver: host=%s, mx=%s, tlsa_n=%d, tlsa_flags=%#lx, ssl=%p, chk=%#x, res=%d\n"
2664*d39bd2c1SGregory Neil Shapiro 					, host, hostbuf
2665*d39bd2c1SGregory Neil Shapiro 					, ste->s_tlsa->dane_tlsa_n
2666*d39bd2c1SGregory Neil Shapiro 					, ste->s_tlsa->dane_tlsa_flags
2667*d39bd2c1SGregory Neil Shapiro 					, mci->mci_ssl
2668*d39bd2c1SGregory Neil Shapiro 					, mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk
2669*d39bd2c1SGregory Neil Shapiro 					, mci->mci_tlsi.tlsi_dvc.dane_vrfy_res
2670*d39bd2c1SGregory Neil Shapiro 					);
2671*d39bd2c1SGregory Neil Shapiro 				else
2672*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("deliver: host=%s, mx=%s, notlsa\n", host, hostbuf);
2673*d39bd2c1SGregory Neil Shapiro 			}
2674*d39bd2c1SGregory Neil Shapiro 
2675*d39bd2c1SGregory Neil Shapiro 			if (mci->mci_state != MCIS_CLOSED)
2676*d39bd2c1SGregory Neil Shapiro 			{
2677*d39bd2c1SGregory Neil Shapiro 				bool dane_old, dane_new, new_session;
2678*d39bd2c1SGregory Neil Shapiro 
2679*d39bd2c1SGregory Neil Shapiro 				/* CHK_DANE(Dane): implicit via ste != NULL */
2680*d39bd2c1SGregory Neil Shapiro 				dane_new = !iscltflgset(e, D_NODANE) &&
2681*d39bd2c1SGregory Neil Shapiro 					ste != NULL && ste->s_tlsa != NULL &&
2682*d39bd2c1SGregory Neil Shapiro 					TLSA_IS_FL(ste->s_tlsa, TLSAFLSUP);
2683*d39bd2c1SGregory Neil Shapiro 				dane_old = CHK_DANE(mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk);
2684*d39bd2c1SGregory Neil Shapiro 				new_session = (dane_old != dane_new);
2685*d39bd2c1SGregory Neil Shapiro 				vrfy = "";
2686*d39bd2c1SGregory Neil Shapiro 				if (dane_old && new_session)
2687*d39bd2c1SGregory Neil Shapiro 				{
2688*d39bd2c1SGregory Neil Shapiro 					vrfy = macget(&mci->mci_macro, macid("{verify}"));
2689*d39bd2c1SGregory Neil Shapiro 					new_session = NULL == vrfy || strcmp("TRUSTED", vrfy) != 0;
2690*d39bd2c1SGregory Neil Shapiro 				}
2691*d39bd2c1SGregory Neil Shapiro 				if (TTD(11, 32))
2692*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("deliver: host=%s, mx=%s, dane_old=%d, dane_new=%d, new_session=%d, vrfy=%s\n",
2693*d39bd2c1SGregory Neil Shapiro 						host, hostbuf, dane_old,
2694*d39bd2c1SGregory Neil Shapiro 						dane_new, new_session, vrfy);
2695*d39bd2c1SGregory Neil Shapiro 				if (new_session)
2696*d39bd2c1SGregory Neil Shapiro 				{
2697*d39bd2c1SGregory Neil Shapiro 					if (TTD(11, 34))
2698*d39bd2c1SGregory Neil Shapiro 						sm_dprintf("deliver: host=%s, mx=%s, old_mci=%p, state=%d\n",
2699*d39bd2c1SGregory Neil Shapiro 							host, hostbuf,
2700*d39bd2c1SGregory Neil Shapiro 							mci, mci->mci_state);
2701*d39bd2c1SGregory Neil Shapiro 					smtpquit(mci->mci_mailer, mci, e);
2702*d39bd2c1SGregory Neil Shapiro 					if (TTD(11, 34))
2703*d39bd2c1SGregory Neil Shapiro 						sm_dprintf("deliver: host=%s, mx=%s, new_mci=%p, state=%d\n",
2704*d39bd2c1SGregory Neil Shapiro 							host, hostbuf,
2705*d39bd2c1SGregory Neil Shapiro 							mci, mci->mci_state);
2706*d39bd2c1SGregory Neil Shapiro 				}
2707*d39bd2c1SGregory Neil Shapiro 				else
2708*d39bd2c1SGregory Neil Shapiro 				{
2709*d39bd2c1SGregory Neil Shapiro 					/* are tlsa_flags the same as dane_vrfy_chk? */
2710*d39bd2c1SGregory Neil Shapiro 					tlsa_flags = mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk;
2711*d39bd2c1SGregory Neil Shapiro 					memcpy(&dane_vrfy_ctx,
2712*d39bd2c1SGregory Neil Shapiro 						&mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk,
2713*d39bd2c1SGregory Neil Shapiro 						sizeof(dane_vrfy_ctx));
2714*d39bd2c1SGregory Neil Shapiro 					dane_vrfy_ctx.dane_vrfy_host = NULL;
2715*d39bd2c1SGregory Neil Shapiro 					dane_vrfy_ctx.dane_vrfy_sni = NULL;
2716*d39bd2c1SGregory Neil Shapiro 					if (TTD(90, 40))
2717*d39bd2c1SGregory Neil Shapiro 						sm_dprintf("deliver: host=%s, mx=%s, state=reuse, chk=%#x\n",
2718*d39bd2c1SGregory Neil Shapiro 							host, hostbuf, mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk);
2719*d39bd2c1SGregory Neil Shapiro 				}
2720*d39bd2c1SGregory Neil Shapiro 			}
2721*d39bd2c1SGregory Neil Shapiro #endif /* DANE */
2722c2aa98e2SPeter Wemm 			if (mci->mci_state != MCIS_CLOSED)
2723c2aa98e2SPeter Wemm 			{
272440266059SGregory Neil Shapiro 				char *type;
272540266059SGregory Neil Shapiro 
2726c2aa98e2SPeter Wemm 				if (tTd(11, 1))
2727c2aa98e2SPeter Wemm 				{
272840266059SGregory Neil Shapiro 					sm_dprintf("openmailer: ");
2729e92d3f3fSGregory Neil Shapiro 					mci_dump(sm_debug_file(), mci, false);
2730c2aa98e2SPeter Wemm 				}
2731c2aa98e2SPeter Wemm 				CurHostName = mci->mci_host;
273240266059SGregory Neil Shapiro 				if (bitnset(M_LMTP, m->m_flags))
273340266059SGregory Neil Shapiro 					type = "L";
273440266059SGregory Neil Shapiro 				else if (bitset(MCIF_ESMTP, mci->mci_flags))
273540266059SGregory Neil Shapiro 					type = "ES";
273640266059SGregory Neil Shapiro 				else
273740266059SGregory Neil Shapiro 					type = "S";
273840266059SGregory Neil Shapiro 				message("Using cached %sMTP connection to %s via %s...",
273940266059SGregory Neil Shapiro 					type, hostbuf, m->m_name);
274006f25ae9SGregory Neil Shapiro 				mci->mci_deliveries++;
2741c2aa98e2SPeter Wemm 				break;
2742c2aa98e2SPeter Wemm 			}
2743c2aa98e2SPeter Wemm 			mci->mci_mailer = m;
27445b0945b5SGregory Neil Shapiro 
2745c2aa98e2SPeter Wemm 			if (mci->mci_exitstat != EX_OK)
2746c2aa98e2SPeter Wemm 			{
2747c2aa98e2SPeter Wemm 				if (mci->mci_exitstat == EX_TEMPFAIL)
274840266059SGregory Neil Shapiro 					goodmxfound = true;
2749e92d3f3fSGregory Neil Shapiro 
2750e92d3f3fSGregory Neil Shapiro 				/* Try FallbackSmartHost? */
2751e92d3f3fSGregory Neil Shapiro 				if (should_try_fbsh(e, &tried_fallbacksmarthost,
2752d0cef73dSGregory Neil Shapiro 						    hostbuf, sizeof(hostbuf),
2753e92d3f3fSGregory Neil Shapiro 						    mci->mci_exitstat))
2754e92d3f3fSGregory Neil Shapiro 					goto one_last_try;
2755e92d3f3fSGregory Neil Shapiro 
2756c2aa98e2SPeter Wemm 				continue;
2757c2aa98e2SPeter Wemm 			}
2758c2aa98e2SPeter Wemm 
2759c2aa98e2SPeter Wemm 			if (mci_lock_host(mci) != EX_OK)
2760c2aa98e2SPeter Wemm 			{
2761c2aa98e2SPeter Wemm 				mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
276240266059SGregory Neil Shapiro 				goodmxfound = true;
2763c2aa98e2SPeter Wemm 				continue;
2764c2aa98e2SPeter Wemm 			}
2765c2aa98e2SPeter Wemm 
2766c2aa98e2SPeter Wemm 			/* try the connection */
276740266059SGregory Neil Shapiro 			sm_setproctitle(true, e, "%s %s: %s",
276806f25ae9SGregory Neil Shapiro 					qid_printname(e),
276906f25ae9SGregory Neil Shapiro 					hostbuf, "user open");
27702fb4f839SGregory Neil Shapiro 
2771*d39bd2c1SGregory Neil Shapiro 			i = EX_OK;
27722fb4f839SGregory Neil Shapiro 			e->e_mci = mci;
2773*d39bd2c1SGregory Neil Shapiro #if STARTTLS || SASL
27742fb4f839SGregory Neil Shapiro 			if ((i = cltfeatures(e, hostbuf)) != EX_OK)
27752fb4f839SGregory Neil Shapiro 			{
27762fb4f839SGregory Neil Shapiro 				if (LogLevel > 8)
27772fb4f839SGregory Neil Shapiro 					sm_syslog(LOG_WARNING, e->e_id,
27782fb4f839SGregory Neil Shapiro 					  "clt_features=TEMPFAIL, host=%s, status=skipped"
27792fb4f839SGregory Neil Shapiro 					  , hostbuf);
27802fb4f839SGregory Neil Shapiro 				/* XXX handle error! */
27812fb4f839SGregory Neil Shapiro 				(void) sm_strlcpy(SmtpError,
27822fb4f839SGregory Neil Shapiro 					"clt_features=TEMPFAIL",
27832fb4f839SGregory Neil Shapiro 					sizeof(SmtpError));
27845b0945b5SGregory Neil Shapiro # if DANE
27852fb4f839SGregory Neil Shapiro 				tlsa_flags &= ~TLSAFLTEMP;
27862fb4f839SGregory Neil Shapiro # endif
27872fb4f839SGregory Neil Shapiro 			}
27882fb4f839SGregory Neil Shapiro # if DANE
27892fb4f839SGregory Neil Shapiro 			/* hack: disable DANE if requested */
27902fb4f839SGregory Neil Shapiro 			if (iscltflgset(e, D_NODANE))
27912fb4f839SGregory Neil Shapiro 				ste = NULL;
27922fb4f839SGregory Neil Shapiro 			tlsa_flags |= ste != NULL ? Dane : DANE_NEVER;
27935b0945b5SGregory Neil Shapiro 			dane_vrfy_ctx.dane_vrfy_chk = tlsa_flags;
27945b0945b5SGregory Neil Shapiro 			dane_vrfy_ctx.dane_vrfy_port = m->m_port;
2795*d39bd2c1SGregory Neil Shapiro 			if (TTD(11, 11))
2796*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("deliver: makeconnection=before, chk=%#x, tlsa_flags=%#lx, {client_flags}=%s, stat=%d, dane_enabled=%d\n",
2797*d39bd2c1SGregory Neil Shapiro 					dane_vrfy_ctx.dane_vrfy_chk,
2798*d39bd2c1SGregory Neil Shapiro 					tlsa_flags,
2799*d39bd2c1SGregory Neil Shapiro 					macvalue(macid("{client_flags}"), e),
2800*d39bd2c1SGregory Neil Shapiro 					i, dane_vrfy_ctx.dane_vrfy_dane_enabled);
2801*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
2802*d39bd2c1SGregory Neil Shapiro #endif /* STARTTLS || SASL */
2803*d39bd2c1SGregory Neil Shapiro #if NETUNIX
2804*d39bd2c1SGregory Neil Shapiro 			if (mux_path != NULL)
2805*d39bd2c1SGregory Neil Shapiro 			{
2806*d39bd2c1SGregory Neil Shapiro 				message("Connecting to %s via %s...",
2807*d39bd2c1SGregory Neil Shapiro 					mux_path, m->m_name);
2808*d39bd2c1SGregory Neil Shapiro 				if (EX_OK == i)
2809*d39bd2c1SGregory Neil Shapiro 				{
2810*d39bd2c1SGregory Neil Shapiro 					i = makeconnection_ds((char *) mux_path, mci);
2811*d39bd2c1SGregory Neil Shapiro #if DANE
2812*d39bd2c1SGregory Neil Shapiro 					/* fake it: "IP is secure" */
2813*d39bd2c1SGregory Neil Shapiro 					tlsa_flags |= TLSAFLADIP;
28145b0945b5SGregory Neil Shapiro #endif
2815*d39bd2c1SGregory Neil Shapiro 				}
2816*d39bd2c1SGregory Neil Shapiro 			}
2817*d39bd2c1SGregory Neil Shapiro 			else
2818*d39bd2c1SGregory Neil Shapiro #endif /* NETUNIX */
2819*d39bd2c1SGregory Neil Shapiro 			/* "else" in #if code above */
2820*d39bd2c1SGregory Neil Shapiro 			{
2821*d39bd2c1SGregory Neil Shapiro 				if (port == 0)
2822*d39bd2c1SGregory Neil Shapiro 					message("Connecting to %s via %s...",
2823*d39bd2c1SGregory Neil Shapiro 						hostbuf, m->m_name);
2824*d39bd2c1SGregory Neil Shapiro 				else
2825*d39bd2c1SGregory Neil Shapiro 					message("Connecting to %s port %d via %s...",
2826*d39bd2c1SGregory Neil Shapiro 						hostbuf, ntohs(port),
2827*d39bd2c1SGregory Neil Shapiro 						m->m_name);
2828*d39bd2c1SGregory Neil Shapiro 
2829*d39bd2c1SGregory Neil Shapiro 				/*
2830*d39bd2c1SGregory Neil Shapiro 				**  set the current connection information,
2831*d39bd2c1SGregory Neil Shapiro 				**  required to set {client_flags} in e->e_mci
2832*d39bd2c1SGregory Neil Shapiro 				*/
2833*d39bd2c1SGregory Neil Shapiro 
28342fb4f839SGregory Neil Shapiro 				if (EX_OK == i)
28352fb4f839SGregory Neil Shapiro 					i = makeconnection(hostbuf, port, mci,
28362fb4f839SGregory Neil Shapiro 						e, enough
28375b0945b5SGregory Neil Shapiro #if DANE
28385b0945b5SGregory Neil Shapiro 						, &tlsa_flags
28395b0945b5SGregory Neil Shapiro #endif
28405b0945b5SGregory Neil Shapiro 						);
2841*d39bd2c1SGregory Neil Shapiro 			}
28425b0945b5SGregory Neil Shapiro #if DANE
2843*d39bd2c1SGregory Neil Shapiro 			if (TTD(11, 11))
2844*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("deliver: makeconnection=after, chk=%#x, tlsa_flags=%#lx, stat=%d\n",
2845*d39bd2c1SGregory Neil Shapiro 					dane_vrfy_ctx.dane_vrfy_chk,
2846*d39bd2c1SGregory Neil Shapiro 					tlsa_flags, i);
2847*d39bd2c1SGregory Neil Shapiro #if OLD_WAY_TLSA_FLAGS
28485b0945b5SGregory Neil Shapiro 			if (dane_vrfy_ctx.dane_vrfy_chk != DANE_ALWAYS)
28495b0945b5SGregory Neil Shapiro 				dane_vrfy_ctx.dane_vrfy_chk = DANEMODE(tlsa_flags);
2850*d39bd2c1SGregory Neil Shapiro #else
2851*d39bd2c1SGregory Neil Shapiro 			dane_vrfy_ctx.dane_vrfy_chk = tlsa_flags;
2852*d39bd2c1SGregory Neil Shapiro #endif
28535b0945b5SGregory Neil Shapiro 			if (EX_TEMPFAIL == i &&
28545b0945b5SGregory Neil Shapiro 			    ((tlsa_flags & (TLSAFLTEMP|DANE_SECURE)) ==
28555b0945b5SGregory Neil Shapiro 			     (TLSAFLTEMP|DANE_SECURE)))
28565b0945b5SGregory Neil Shapiro 			{
28575b0945b5SGregory Neil Shapiro 				(void) sm_strlcpy(SmtpError,
28585b0945b5SGregory Neil Shapiro 					" for TLSA RR",
28595b0945b5SGregory Neil Shapiro 					sizeof(SmtpError));
28605b0945b5SGregory Neil Shapiro # if NAMED_BIND
28615b0945b5SGregory Neil Shapiro 				SM_SET_H_ERRNO(TRY_AGAIN);
28625b0945b5SGregory Neil Shapiro # endif
28635b0945b5SGregory Neil Shapiro 			}
2864*d39bd2c1SGregory Neil Shapiro #endif /* DANE */
28658774250cSGregory Neil Shapiro 			mci->mci_errno = errno;
2866c2aa98e2SPeter Wemm 			mci->mci_lastuse = curtime();
286706f25ae9SGregory Neil Shapiro 			mci->mci_deliveries = 0;
2868c2aa98e2SPeter Wemm 			mci->mci_exitstat = i;
28696f9c8e5bSGregory Neil Shapiro 			mci_clr_extensions(mci);
2870c2aa98e2SPeter Wemm #if NAMED_BIND
2871c2aa98e2SPeter Wemm 			mci->mci_herrno = h_errno;
28725b0945b5SGregory Neil Shapiro #endif
287340266059SGregory Neil Shapiro 
287440266059SGregory Neil Shapiro 			/*
287540266059SGregory Neil Shapiro 			**  Have we tried long enough to get a connection?
287640266059SGregory Neil Shapiro 			**	If yes, skip to the fallback MX hosts
287740266059SGregory Neil Shapiro 			**	(if existent).
287840266059SGregory Neil Shapiro 			*/
287940266059SGregory Neil Shapiro 
288040266059SGregory Neil Shapiro 			if (enough > 0 && mci->mci_lastuse >= enough)
288140266059SGregory Neil Shapiro 			{
288240266059SGregory Neil Shapiro 				int h;
288340266059SGregory Neil Shapiro #if NAMED_BIND
2884e92d3f3fSGregory Neil Shapiro 				extern int NumFallbackMXHosts;
28855b0945b5SGregory Neil Shapiro #else
2886e92d3f3fSGregory Neil Shapiro 				const int NumFallbackMXHosts = 0;
28875b0945b5SGregory Neil Shapiro #endif
288840266059SGregory Neil Shapiro 
288940266059SGregory Neil Shapiro 				if (hostnum < nummxhosts && LogLevel > 9)
289040266059SGregory Neil Shapiro 					sm_syslog(LOG_INFO, e->e_id,
289140266059SGregory Neil Shapiro 						  "Timeout.to_aconnect occurred before exhausting all addresses");
289240266059SGregory Neil Shapiro 
289340266059SGregory Neil Shapiro 				/* turn off timeout if fallback available */
2894e92d3f3fSGregory Neil Shapiro 				if (NumFallbackMXHosts > 0)
289540266059SGregory Neil Shapiro 					enough = 0;
289640266059SGregory Neil Shapiro 
289740266059SGregory Neil Shapiro 				/* skip to a fallback MX host */
2898e92d3f3fSGregory Neil Shapiro 				h = nummxhosts - NumFallbackMXHosts;
289940266059SGregory Neil Shapiro 				if (hostnum < h)
290040266059SGregory Neil Shapiro 					hostnum = h;
290140266059SGregory Neil Shapiro 			}
2902c2aa98e2SPeter Wemm 			if (i == EX_OK)
2903c2aa98e2SPeter Wemm 			{
290440266059SGregory Neil Shapiro 				goodmxfound = true;
2905605302a5SGregory Neil Shapiro 				markstats(e, firstto, STATS_CONNECT);
2906c2aa98e2SPeter Wemm 				mci->mci_state = MCIS_OPENING;
2907c2aa98e2SPeter Wemm 				mci_cache(mci);
2908c2aa98e2SPeter Wemm 				if (TrafficLogFile != NULL)
290940266059SGregory Neil Shapiro 					(void) sm_io_fprintf(TrafficLogFile,
291040266059SGregory Neil Shapiro 							     SM_TIME_DEFAULT,
291140266059SGregory Neil Shapiro 							     "%05d === CONNECT %s\n",
291240266059SGregory Neil Shapiro 							     (int) CurrentPid,
291340266059SGregory Neil Shapiro 							     hostbuf);
2914c2aa98e2SPeter Wemm 				break;
2915c2aa98e2SPeter Wemm 			}
2916c2aa98e2SPeter Wemm 			else
2917c2aa98e2SPeter Wemm 			{
2918e92d3f3fSGregory Neil Shapiro 				/* Try FallbackSmartHost? */
2919e92d3f3fSGregory Neil Shapiro 				if (should_try_fbsh(e, &tried_fallbacksmarthost,
2920d0cef73dSGregory Neil Shapiro 						    hostbuf, sizeof(hostbuf), i))
2921e92d3f3fSGregory Neil Shapiro 					goto one_last_try;
2922e92d3f3fSGregory Neil Shapiro 
2923c2aa98e2SPeter Wemm 				if (tTd(11, 1))
2924*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("openmailer: makeconnection(%s) => stat=%d, errno=%d\n",
2925*d39bd2c1SGregory Neil Shapiro 						   hostbuf, i, errno);
2926c2aa98e2SPeter Wemm 				if (i == EX_TEMPFAIL)
292740266059SGregory Neil Shapiro 					goodmxfound = true;
2928c2aa98e2SPeter Wemm 				mci_unlock_host(mci);
2929c2aa98e2SPeter Wemm 			}
2930c2aa98e2SPeter Wemm 
2931c2aa98e2SPeter Wemm 			/* enter status of this host */
2932c2aa98e2SPeter Wemm 			setstat(i);
2933c2aa98e2SPeter Wemm 
2934c2aa98e2SPeter Wemm 			/* should print some message here for -v mode */
2935c2aa98e2SPeter Wemm 		}
2936c2aa98e2SPeter Wemm 		if (mci == NULL)
2937c2aa98e2SPeter Wemm 		{
2938c2aa98e2SPeter Wemm 			syserr("deliver: no host name");
2939c2aa98e2SPeter Wemm 			rcode = EX_SOFTWARE;
2940c2aa98e2SPeter Wemm 			goto give_up;
2941c2aa98e2SPeter Wemm 		}
2942c2aa98e2SPeter Wemm 		mci->mci_pid = 0;
2943c2aa98e2SPeter Wemm 	}
2944c2aa98e2SPeter Wemm 	else
2945c2aa98e2SPeter Wemm 	{
2946c2aa98e2SPeter Wemm 		/* flush any expired connections */
2947c2aa98e2SPeter Wemm 		(void) mci_scan(NULL);
2948c2aa98e2SPeter Wemm 		mci = NULL;
2949c2aa98e2SPeter Wemm 
2950c2aa98e2SPeter Wemm 		if (bitnset(M_LMTP, m->m_flags))
2951c2aa98e2SPeter Wemm 		{
2952c2aa98e2SPeter Wemm 			/* try to get a cached connection */
2953c2aa98e2SPeter Wemm 			mci = mci_get(m->m_name, m);
2954c2aa98e2SPeter Wemm 			if (mci->mci_host == NULL)
2955c2aa98e2SPeter Wemm 				mci->mci_host = m->m_name;
2956c2aa98e2SPeter Wemm 			CurHostName = mci->mci_host;
2957c2aa98e2SPeter Wemm 			if (mci->mci_state != MCIS_CLOSED)
2958c2aa98e2SPeter Wemm 			{
2959c2aa98e2SPeter Wemm 				message("Using cached LMTP connection for %s...",
2960c2aa98e2SPeter Wemm 					m->m_name);
296106f25ae9SGregory Neil Shapiro 				mci->mci_deliveries++;
2962c2aa98e2SPeter Wemm 				goto do_transfer;
2963c2aa98e2SPeter Wemm 			}
2964c2aa98e2SPeter Wemm 		}
2965c2aa98e2SPeter Wemm 
2966c2aa98e2SPeter Wemm 		/* announce the connection to verbose listeners */
2967c2aa98e2SPeter Wemm 		if (host == NULL || host[0] == '\0')
2968c2aa98e2SPeter Wemm 			message("Connecting to %s...", m->m_name);
2969c2aa98e2SPeter Wemm 		else
2970c2aa98e2SPeter Wemm 			message("Connecting to %s via %s...", host, m->m_name);
2971c2aa98e2SPeter Wemm 		if (TrafficLogFile != NULL)
2972c2aa98e2SPeter Wemm 		{
2973c2aa98e2SPeter Wemm 			char **av;
2974c2aa98e2SPeter Wemm 
297540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
297640266059SGregory Neil Shapiro 					     "%05d === EXEC", (int) CurrentPid);
2977c2aa98e2SPeter Wemm 			for (av = pv; *av != NULL; av++)
297840266059SGregory Neil Shapiro 				(void) sm_io_fprintf(TrafficLogFile,
297940266059SGregory Neil Shapiro 						     SM_TIME_DEFAULT, " %s",
298040266059SGregory Neil Shapiro 						     *av);
298140266059SGregory Neil Shapiro 			(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
298240266059SGregory Neil Shapiro 					     "\n");
2983c2aa98e2SPeter Wemm 		}
2984c2aa98e2SPeter Wemm 
2985c2aa98e2SPeter Wemm 		checkfd012("before creating mail pipe");
2986c2aa98e2SPeter Wemm 
2987c2aa98e2SPeter Wemm 		/* create a pipe to shove the mail through */
2988c2aa98e2SPeter Wemm 		if (pipe(mpvect) < 0)
2989c2aa98e2SPeter Wemm 		{
2990c2aa98e2SPeter Wemm 			syserr("%s... openmailer(%s): pipe (to mailer)",
2991c2aa98e2SPeter Wemm 			       shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
2992c2aa98e2SPeter Wemm 			if (tTd(11, 1))
299340266059SGregory Neil Shapiro 				sm_dprintf("openmailer: NULL\n");
2994c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
2995c2aa98e2SPeter Wemm 			goto give_up;
2996c2aa98e2SPeter Wemm 		}
2997c2aa98e2SPeter Wemm 
2998c2aa98e2SPeter Wemm #if XDEBUG
2999c2aa98e2SPeter Wemm 		/* make sure we didn't get one of the standard I/O files */
3000c2aa98e2SPeter Wemm 		if (mpvect[0] < 3 || mpvect[1] < 3)
3001c2aa98e2SPeter Wemm 		{
3002c2aa98e2SPeter Wemm 			syserr("%s... openmailer(%s): bogus mpvect %d %d",
3003c2aa98e2SPeter Wemm 			       shortenstring(e->e_to, MAXSHORTSTR), m->m_name,
3004c2aa98e2SPeter Wemm 			       mpvect[0], mpvect[1]);
300540266059SGregory Neil Shapiro 			printopenfds(true);
3006c2aa98e2SPeter Wemm 			if (tTd(11, 1))
300740266059SGregory Neil Shapiro 				sm_dprintf("openmailer: NULL\n");
3008c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
3009c2aa98e2SPeter Wemm 			goto give_up;
3010c2aa98e2SPeter Wemm 		}
3011c2aa98e2SPeter Wemm 
3012c2aa98e2SPeter Wemm 		/* make sure system call isn't dead meat */
3013c2aa98e2SPeter Wemm 		checkfdopen(mpvect[0], "mpvect[0]");
3014c2aa98e2SPeter Wemm 		checkfdopen(mpvect[1], "mpvect[1]");
3015c2aa98e2SPeter Wemm 		if (mpvect[0] == mpvect[1] ||
3016c2aa98e2SPeter Wemm 		    (e->e_lockfp != NULL &&
301740266059SGregory Neil Shapiro 		     (mpvect[0] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
301840266059SGregory Neil Shapiro 						 NULL) ||
301940266059SGregory Neil Shapiro 		      mpvect[1] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
302040266059SGregory Neil Shapiro 						 NULL))))
3021c2aa98e2SPeter Wemm 		{
3022c2aa98e2SPeter Wemm 			if (e->e_lockfp == NULL)
3023c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): overlapping mpvect %d %d",
3024c2aa98e2SPeter Wemm 				       shortenstring(e->e_to, MAXSHORTSTR),
3025c2aa98e2SPeter Wemm 				       m->m_name, mpvect[0], mpvect[1]);
3026c2aa98e2SPeter Wemm 			else
3027c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d",
3028c2aa98e2SPeter Wemm 				       shortenstring(e->e_to, MAXSHORTSTR),
3029c2aa98e2SPeter Wemm 				       m->m_name, mpvect[0], mpvect[1],
303040266059SGregory Neil Shapiro 				       sm_io_getinfo(e->e_lockfp,
303140266059SGregory Neil Shapiro 						     SM_IO_WHAT_FD, NULL));
3032c2aa98e2SPeter Wemm 		}
303306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
3034c2aa98e2SPeter Wemm 
303506f25ae9SGregory Neil Shapiro 		/* create a return pipe */
3036c2aa98e2SPeter Wemm 		if (pipe(rpvect) < 0)
3037c2aa98e2SPeter Wemm 		{
3038c2aa98e2SPeter Wemm 			syserr("%s... openmailer(%s): pipe (from mailer)",
3039c2aa98e2SPeter Wemm 			       shortenstring(e->e_to, MAXSHORTSTR),
3040c2aa98e2SPeter Wemm 			       m->m_name);
3041c2aa98e2SPeter Wemm 			(void) close(mpvect[0]);
3042c2aa98e2SPeter Wemm 			(void) close(mpvect[1]);
3043c2aa98e2SPeter Wemm 			if (tTd(11, 1))
304440266059SGregory Neil Shapiro 				sm_dprintf("openmailer: NULL\n");
3045c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
3046c2aa98e2SPeter Wemm 			goto give_up;
3047c2aa98e2SPeter Wemm 		}
3048c2aa98e2SPeter Wemm 		checkfdopen(rpvect[0], "rpvect[0]");
3049c2aa98e2SPeter Wemm 		checkfdopen(rpvect[1], "rpvect[1]");
3050c2aa98e2SPeter Wemm 
3051c2aa98e2SPeter Wemm 		/*
3052c2aa98e2SPeter Wemm 		**  Actually fork the mailer process.
3053c2aa98e2SPeter Wemm 		**	DOFORK is clever about retrying.
3054c2aa98e2SPeter Wemm 		**
3055c2aa98e2SPeter Wemm 		**	Dispose of SIGCHLD signal catchers that may be laying
305606f25ae9SGregory Neil Shapiro 		**	around so that endmailer will get it.
3057c2aa98e2SPeter Wemm 		*/
3058c2aa98e2SPeter Wemm 
305940266059SGregory Neil Shapiro 		if (e->e_xfp != NULL)	/* for debugging */
306040266059SGregory Neil Shapiro 			(void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
306140266059SGregory Neil Shapiro 		(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
306240266059SGregory Neil Shapiro 		(void) sm_signal(SIGCHLD, SIG_DFL);
306306f25ae9SGregory Neil Shapiro 
306406f25ae9SGregory Neil Shapiro 
3065c2aa98e2SPeter Wemm 		DOFORK(FORK);
3066c2aa98e2SPeter Wemm 		/* pid is set by DOFORK */
306706f25ae9SGregory Neil Shapiro 
3068c2aa98e2SPeter Wemm 		if (pid < 0)
3069c2aa98e2SPeter Wemm 		{
3070c2aa98e2SPeter Wemm 			/* failure */
3071c2aa98e2SPeter Wemm 			syserr("%s... openmailer(%s): cannot fork",
3072c2aa98e2SPeter Wemm 			       shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
3073c2aa98e2SPeter Wemm 			(void) close(mpvect[0]);
3074c2aa98e2SPeter Wemm 			(void) close(mpvect[1]);
3075c2aa98e2SPeter Wemm 			(void) close(rpvect[0]);
3076c2aa98e2SPeter Wemm 			(void) close(rpvect[1]);
3077c2aa98e2SPeter Wemm 			if (tTd(11, 1))
307840266059SGregory Neil Shapiro 				sm_dprintf("openmailer: NULL\n");
3079c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
3080c2aa98e2SPeter Wemm 			goto give_up;
3081c2aa98e2SPeter Wemm 		}
3082c2aa98e2SPeter Wemm 		else if (pid == 0)
3083c2aa98e2SPeter Wemm 		{
308406f25ae9SGregory Neil Shapiro 			int save_errno;
308540266059SGregory Neil Shapiro 			int sff;
3086c2aa98e2SPeter Wemm 			int new_euid = NO_UID;
3087c2aa98e2SPeter Wemm 			int new_ruid = NO_UID;
3088c2aa98e2SPeter Wemm 			int new_gid = NO_GID;
308940266059SGregory Neil Shapiro 			char *user = NULL;
3090c2aa98e2SPeter Wemm 			struct stat stb;
3091c2aa98e2SPeter Wemm 			extern int DtableSize;
3092c2aa98e2SPeter Wemm 
309340266059SGregory Neil Shapiro 			CurrentPid = getpid();
309440266059SGregory Neil Shapiro 
309513058a91SGregory Neil Shapiro 			/* clear the events to turn off SIGALRMs */
309640266059SGregory Neil Shapiro 			sm_clear_events();
309713058a91SGregory Neil Shapiro 
30988774250cSGregory Neil Shapiro 			/* Reset global flags */
30998774250cSGregory Neil Shapiro 			RestartRequest = NULL;
310040266059SGregory Neil Shapiro 			RestartWorkGroup = false;
31018774250cSGregory Neil Shapiro 			ShutdownRequest = NULL;
31028774250cSGregory Neil Shapiro 			PendingSignal = 0;
31038774250cSGregory Neil Shapiro 
3104c2aa98e2SPeter Wemm 			if (e->e_lockfp != NULL)
310540266059SGregory Neil Shapiro 				(void) close(sm_io_getinfo(e->e_lockfp,
310640266059SGregory Neil Shapiro 							   SM_IO_WHAT_FD,
310740266059SGregory Neil Shapiro 							   NULL));
3108c2aa98e2SPeter Wemm 
3109c2aa98e2SPeter Wemm 			/* child -- set up input & exec mailer */
311040266059SGregory Neil Shapiro 			(void) sm_signal(SIGALRM, sm_signal_noop);
311140266059SGregory Neil Shapiro 			(void) sm_signal(SIGCHLD, SIG_DFL);
311240266059SGregory Neil Shapiro 			(void) sm_signal(SIGHUP, SIG_IGN);
311340266059SGregory Neil Shapiro 			(void) sm_signal(SIGINT, SIG_IGN);
311440266059SGregory Neil Shapiro 			(void) sm_signal(SIGTERM, SIG_DFL);
311513058a91SGregory Neil Shapiro #ifdef SIGUSR1
311640266059SGregory Neil Shapiro 			(void) sm_signal(SIGUSR1, sm_signal_noop);
31175b0945b5SGregory Neil Shapiro #endif
3118c2aa98e2SPeter Wemm 
3119c2aa98e2SPeter Wemm 			if (m != FileMailer || stat(tochain->q_user, &stb) < 0)
3120c2aa98e2SPeter Wemm 				stb.st_mode = 0;
3121c2aa98e2SPeter Wemm 
3122c2aa98e2SPeter Wemm #if HASSETUSERCONTEXT
3123c2aa98e2SPeter Wemm 			/*
3124c2aa98e2SPeter Wemm 			**  Set user resources.
3125c2aa98e2SPeter Wemm 			*/
3126c2aa98e2SPeter Wemm 
3127c2aa98e2SPeter Wemm 			if (contextaddr != NULL)
3128c2aa98e2SPeter Wemm 			{
312913bd1963SGregory Neil Shapiro 				int sucflags;
3130c2aa98e2SPeter Wemm 				struct passwd *pwd;
3131c2aa98e2SPeter Wemm 
3132c2aa98e2SPeter Wemm 				if (contextaddr->q_ruser != NULL)
3133c2aa98e2SPeter Wemm 					pwd = sm_getpwnam(contextaddr->q_ruser);
3134c2aa98e2SPeter Wemm 				else
3135c2aa98e2SPeter Wemm 					pwd = sm_getpwnam(contextaddr->q_user);
313613bd1963SGregory Neil Shapiro 				sucflags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
3137906a940eSEdward Tomasz Napierala # ifdef LOGIN_SETCPUMASK
3138906a940eSEdward Tomasz Napierala 				sucflags |= LOGIN_SETCPUMASK;
31395b0945b5SGregory Neil Shapiro # endif
3140906a940eSEdward Tomasz Napierala # ifdef LOGIN_SETLOGINCLASS
3141906a940eSEdward Tomasz Napierala 				sucflags |= LOGIN_SETLOGINCLASS;
31425b0945b5SGregory Neil Shapiro # endif
314313bd1963SGregory Neil Shapiro # ifdef LOGIN_SETMAC
314413bd1963SGregory Neil Shapiro 				sucflags |= LOGIN_SETMAC;
31455b0945b5SGregory Neil Shapiro # endif
3146959366dcSGregory Neil Shapiro 				if (pwd != NULL &&
3147959366dcSGregory Neil Shapiro 				    setusercontext(NULL, pwd, pwd->pw_uid,
314813bd1963SGregory Neil Shapiro 						   sucflags) == -1 &&
3149959366dcSGregory Neil Shapiro 				    suidwarn)
3150959366dcSGregory Neil Shapiro 				{
3151959366dcSGregory Neil Shapiro 					syserr("openmailer: setusercontext() failed");
3152959366dcSGregory Neil Shapiro 					exit(EX_TEMPFAIL);
3153959366dcSGregory Neil Shapiro 				}
3154c2aa98e2SPeter Wemm 			}
315506f25ae9SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */
3156c2aa98e2SPeter Wemm 
315740266059SGregory Neil Shapiro #if HASNICE
3158c2aa98e2SPeter Wemm 			/* tweak niceness */
3159c2aa98e2SPeter Wemm 			if (m->m_nice != 0)
316006f25ae9SGregory Neil Shapiro 				(void) nice(m->m_nice);
31612fb4f839SGregory Neil Shapiro #endif
3162c2aa98e2SPeter Wemm 
3163c2aa98e2SPeter Wemm 			/* reset group id */
3164c2aa98e2SPeter Wemm 			if (bitnset(M_SPECIFIC_UID, m->m_flags))
3165e92d3f3fSGregory Neil Shapiro 			{
3166e92d3f3fSGregory Neil Shapiro 				if (m->m_gid == NO_GID)
3167e92d3f3fSGregory Neil Shapiro 					new_gid = RunAsGid;
3168e92d3f3fSGregory Neil Shapiro 				else
3169c2aa98e2SPeter Wemm 					new_gid = m->m_gid;
3170e92d3f3fSGregory Neil Shapiro 			}
3171c2aa98e2SPeter Wemm 			else if (bitset(S_ISGID, stb.st_mode))
3172c2aa98e2SPeter Wemm 				new_gid = stb.st_gid;
3173c2aa98e2SPeter Wemm 			else if (ctladdr != NULL && ctladdr->q_gid != 0)
3174c2aa98e2SPeter Wemm 			{
3175c2aa98e2SPeter Wemm 				if (!DontInitGroups)
3176c2aa98e2SPeter Wemm 				{
317740266059SGregory Neil Shapiro 					user = ctladdr->q_ruser;
317840266059SGregory Neil Shapiro 					if (user == NULL)
317940266059SGregory Neil Shapiro 						user = ctladdr->q_user;
3180c2aa98e2SPeter Wemm 
318140266059SGregory Neil Shapiro 					if (initgroups(user,
318240266059SGregory Neil Shapiro 						       ctladdr->q_gid) == -1
318340266059SGregory Neil Shapiro 					    && suidwarn)
318406f25ae9SGregory Neil Shapiro 					{
3185da7d7b9cSGregory Neil Shapiro 						syserr("openmailer: initgroups(%s, %ld) failed",
3186da7d7b9cSGregory Neil Shapiro 							user, (long) ctladdr->q_gid);
318706f25ae9SGregory Neil Shapiro 						exit(EX_TEMPFAIL);
318806f25ae9SGregory Neil Shapiro 					}
3189c2aa98e2SPeter Wemm 				}
3190c2aa98e2SPeter Wemm 				else
3191c2aa98e2SPeter Wemm 				{
3192c2aa98e2SPeter Wemm 					GIDSET_T gidset[1];
3193c2aa98e2SPeter Wemm 
3194c2aa98e2SPeter Wemm 					gidset[0] = ctladdr->q_gid;
319540266059SGregory Neil Shapiro 					if (setgroups(1, gidset) == -1
319640266059SGregory Neil Shapiro 					    && suidwarn)
319706f25ae9SGregory Neil Shapiro 					{
3198c2aa98e2SPeter Wemm 						syserr("openmailer: setgroups() failed");
319906f25ae9SGregory Neil Shapiro 						exit(EX_TEMPFAIL);
320006f25ae9SGregory Neil Shapiro 					}
3201c2aa98e2SPeter Wemm 				}
3202c2aa98e2SPeter Wemm 				new_gid = ctladdr->q_gid;
3203c2aa98e2SPeter Wemm 			}
3204c2aa98e2SPeter Wemm 			else
3205c2aa98e2SPeter Wemm 			{
3206c2aa98e2SPeter Wemm 				if (!DontInitGroups)
3207c2aa98e2SPeter Wemm 				{
320840266059SGregory Neil Shapiro 					user = DefUser;
320940266059SGregory Neil Shapiro 					if (initgroups(DefUser, DefGid) == -1 &&
321040266059SGregory Neil Shapiro 					    suidwarn)
321106f25ae9SGregory Neil Shapiro 					{
3212da7d7b9cSGregory Neil Shapiro 						syserr("openmailer: initgroups(%s, %ld) failed",
3213da7d7b9cSGregory Neil Shapiro 						       DefUser, (long) DefGid);
321406f25ae9SGregory Neil Shapiro 						exit(EX_TEMPFAIL);
321506f25ae9SGregory Neil Shapiro 					}
3216c2aa98e2SPeter Wemm 				}
3217c2aa98e2SPeter Wemm 				else
3218c2aa98e2SPeter Wemm 				{
3219c2aa98e2SPeter Wemm 					GIDSET_T gidset[1];
3220c2aa98e2SPeter Wemm 
3221c2aa98e2SPeter Wemm 					gidset[0] = DefGid;
322240266059SGregory Neil Shapiro 					if (setgroups(1, gidset) == -1
322340266059SGregory Neil Shapiro 					    && suidwarn)
322406f25ae9SGregory Neil Shapiro 					{
3225c2aa98e2SPeter Wemm 						syserr("openmailer: setgroups() failed");
322606f25ae9SGregory Neil Shapiro 						exit(EX_TEMPFAIL);
322706f25ae9SGregory Neil Shapiro 					}
3228c2aa98e2SPeter Wemm 				}
3229e92d3f3fSGregory Neil Shapiro 				if (m->m_gid == NO_GID)
3230c2aa98e2SPeter Wemm 					new_gid = DefGid;
3231c2aa98e2SPeter Wemm 				else
3232c2aa98e2SPeter Wemm 					new_gid = m->m_gid;
3233c2aa98e2SPeter Wemm 			}
323406f25ae9SGregory Neil Shapiro 			if (new_gid != NO_GID)
323506f25ae9SGregory Neil Shapiro 			{
323606f25ae9SGregory Neil Shapiro 				if (RunAsUid != 0 &&
323706f25ae9SGregory Neil Shapiro 				    bitnset(M_SPECIFIC_UID, m->m_flags) &&
323806f25ae9SGregory Neil Shapiro 				    new_gid != getgid() &&
323906f25ae9SGregory Neil Shapiro 				    new_gid != getegid())
324006f25ae9SGregory Neil Shapiro 				{
324106f25ae9SGregory Neil Shapiro 					/* Only root can change the gid */
3242da7d7b9cSGregory Neil Shapiro 					syserr("openmailer: insufficient privileges to change gid, RunAsUid=%ld, new_gid=%ld, gid=%ld, egid=%ld",
3243da7d7b9cSGregory Neil Shapiro 					       (long) RunAsUid, (long) new_gid,
3244da7d7b9cSGregory Neil Shapiro 					       (long) getgid(), (long) getegid());
324506f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
324606f25ae9SGregory Neil Shapiro 				}
324706f25ae9SGregory Neil Shapiro 
324806f25ae9SGregory Neil Shapiro 				if (setgid(new_gid) < 0 && suidwarn)
324906f25ae9SGregory Neil Shapiro 				{
3250c2aa98e2SPeter Wemm 					syserr("openmailer: setgid(%ld) failed",
3251c2aa98e2SPeter Wemm 					       (long) new_gid);
325206f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
325306f25ae9SGregory Neil Shapiro 				}
325406f25ae9SGregory Neil Shapiro 			}
325506f25ae9SGregory Neil Shapiro 
325606f25ae9SGregory Neil Shapiro 			/* change root to some "safe" directory */
325706f25ae9SGregory Neil Shapiro 			if (m->m_rootdir != NULL)
325806f25ae9SGregory Neil Shapiro 			{
3259d0cef73dSGregory Neil Shapiro 				expand(m->m_rootdir, cbuf, sizeof(cbuf), e);
326006f25ae9SGregory Neil Shapiro 				if (tTd(11, 20))
326140266059SGregory Neil Shapiro 					sm_dprintf("openmailer: chroot %s\n",
326294c01205SGregory Neil Shapiro 						   cbuf);
326394c01205SGregory Neil Shapiro 				if (chroot(cbuf) < 0)
326406f25ae9SGregory Neil Shapiro 				{
326506f25ae9SGregory Neil Shapiro 					syserr("openmailer: Cannot chroot(%s)",
326694c01205SGregory Neil Shapiro 					       cbuf);
326706f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
326806f25ae9SGregory Neil Shapiro 				}
326906f25ae9SGregory Neil Shapiro 				if (chdir("/") < 0)
327006f25ae9SGregory Neil Shapiro 				{
327106f25ae9SGregory Neil Shapiro 					syserr("openmailer: cannot chdir(/)");
327206f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
327306f25ae9SGregory Neil Shapiro 				}
327406f25ae9SGregory Neil Shapiro 			}
3275c2aa98e2SPeter Wemm 
3276c2aa98e2SPeter Wemm 			/* reset user id */
3277c2aa98e2SPeter Wemm 			endpwent();
327840266059SGregory Neil Shapiro 			sm_mbdb_terminate();
3279c2aa98e2SPeter Wemm 			if (bitnset(M_SPECIFIC_UID, m->m_flags))
328013058a91SGregory Neil Shapiro 			{
3281e92d3f3fSGregory Neil Shapiro 				if (m->m_uid == NO_UID)
3282e92d3f3fSGregory Neil Shapiro 					new_euid = RunAsUid;
3283e92d3f3fSGregory Neil Shapiro 				else
3284c2aa98e2SPeter Wemm 					new_euid = m->m_uid;
328513058a91SGregory Neil Shapiro 
328613058a91SGregory Neil Shapiro 				/*
328713058a91SGregory Neil Shapiro 				**  Undo the effects of the uid change in main
328813058a91SGregory Neil Shapiro 				**  for signal handling.  The real uid may
328913058a91SGregory Neil Shapiro 				**  be used by mailer in adding a "From "
329013058a91SGregory Neil Shapiro 				**  line.
329113058a91SGregory Neil Shapiro 				*/
329213058a91SGregory Neil Shapiro 
329313058a91SGregory Neil Shapiro 				if (RealUid != 0 && RealUid != getuid())
329440266059SGregory Neil Shapiro 				{
329540266059SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETEUID
329640266059SGregory Neil Shapiro # if HASSETREUID
329740266059SGregory Neil Shapiro 					if (setreuid(RealUid, geteuid()) < 0)
329840266059SGregory Neil Shapiro 					{
329940266059SGregory Neil Shapiro 						syserr("openmailer: setreuid(%d, %d) failed",
330040266059SGregory Neil Shapiro 						       (int) RealUid, (int) geteuid());
330140266059SGregory Neil Shapiro 						exit(EX_OSERR);
330240266059SGregory Neil Shapiro 					}
330340266059SGregory Neil Shapiro # endif /* HASSETREUID */
330440266059SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETEUID */
330540266059SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETREUID
330613058a91SGregory Neil Shapiro 					new_ruid = RealUid;
33075b0945b5SGregory Neil Shapiro #endif
330840266059SGregory Neil Shapiro 				}
330913058a91SGregory Neil Shapiro 			}
3310c2aa98e2SPeter Wemm 			else if (bitset(S_ISUID, stb.st_mode))
3311c2aa98e2SPeter Wemm 				new_ruid = stb.st_uid;
3312c2aa98e2SPeter Wemm 			else if (ctladdr != NULL && ctladdr->q_uid != 0)
3313c2aa98e2SPeter Wemm 				new_ruid = ctladdr->q_uid;
3314e92d3f3fSGregory Neil Shapiro 			else if (m->m_uid != NO_UID)
3315c2aa98e2SPeter Wemm 				new_ruid = m->m_uid;
3316c2aa98e2SPeter Wemm 			else
3317c2aa98e2SPeter Wemm 				new_ruid = DefUid;
3318605302a5SGregory Neil Shapiro 
3319605302a5SGregory Neil Shapiro #if _FFR_USE_SETLOGIN
3320605302a5SGregory Neil Shapiro 			/* run disconnected from terminal and set login name */
3321605302a5SGregory Neil Shapiro 			if (setsid() >= 0 &&
3322605302a5SGregory Neil Shapiro 			    ctladdr != NULL && ctladdr->q_uid != 0 &&
3323605302a5SGregory Neil Shapiro 			    new_euid == ctladdr->q_uid)
3324605302a5SGregory Neil Shapiro 			{
3325605302a5SGregory Neil Shapiro 				struct passwd *pwd;
3326605302a5SGregory Neil Shapiro 
3327605302a5SGregory Neil Shapiro 				pwd = sm_getpwuid(ctladdr->q_uid);
3328605302a5SGregory Neil Shapiro 				if (pwd != NULL && suidwarn)
3329605302a5SGregory Neil Shapiro 					(void) setlogin(pwd->pw_name);
3330605302a5SGregory Neil Shapiro 				endpwent();
3331605302a5SGregory Neil Shapiro 			}
3332605302a5SGregory Neil Shapiro #endif /* _FFR_USE_SETLOGIN */
3333605302a5SGregory Neil Shapiro 
3334c2aa98e2SPeter Wemm 			if (new_euid != NO_UID)
3335c2aa98e2SPeter Wemm 			{
333606f25ae9SGregory Neil Shapiro 				if (RunAsUid != 0 && new_euid != RunAsUid)
333706f25ae9SGregory Neil Shapiro 				{
333806f25ae9SGregory Neil Shapiro 					/* Only root can change the uid */
3339da7d7b9cSGregory Neil Shapiro 					syserr("openmailer: insufficient privileges to change uid, new_euid=%ld, RunAsUid=%ld",
3340da7d7b9cSGregory Neil Shapiro 					       (long) new_euid, (long) RunAsUid);
334106f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
334206f25ae9SGregory Neil Shapiro 				}
334306f25ae9SGregory Neil Shapiro 
3344c2aa98e2SPeter Wemm 				vendor_set_uid(new_euid);
334506f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETEUID
3346c2aa98e2SPeter Wemm 				if (seteuid(new_euid) < 0 && suidwarn)
334706f25ae9SGregory Neil Shapiro 				{
3348c2aa98e2SPeter Wemm 					syserr("openmailer: seteuid(%ld) failed",
3349c2aa98e2SPeter Wemm 					       (long) new_euid);
335006f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
335106f25ae9SGregory Neil Shapiro 				}
335206f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETEUID */
335306f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETREUID
3354c2aa98e2SPeter Wemm 				if (setreuid(new_ruid, new_euid) < 0 && suidwarn)
335506f25ae9SGregory Neil Shapiro 				{
3356c2aa98e2SPeter Wemm 					syserr("openmailer: setreuid(%ld, %ld) failed",
3357c2aa98e2SPeter Wemm 					       (long) new_ruid, (long) new_euid);
335806f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
335906f25ae9SGregory Neil Shapiro 				}
336006f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETREUID */
336106f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETUID
3362c2aa98e2SPeter Wemm 				if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn)
336306f25ae9SGregory Neil Shapiro 				{
3364c2aa98e2SPeter Wemm 					syserr("openmailer: setuid(%ld) failed",
3365c2aa98e2SPeter Wemm 					       (long) new_euid);
336606f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
336706f25ae9SGregory Neil Shapiro 				}
336806f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETUID */
3369c2aa98e2SPeter Wemm 			}
3370c2aa98e2SPeter Wemm 			else if (new_ruid != NO_UID)
3371c2aa98e2SPeter Wemm 			{
3372c2aa98e2SPeter Wemm 				vendor_set_uid(new_ruid);
3373c2aa98e2SPeter Wemm 				if (setuid(new_ruid) < 0 && suidwarn)
337406f25ae9SGregory Neil Shapiro 				{
3375c2aa98e2SPeter Wemm 					syserr("openmailer: setuid(%ld) failed",
3376c2aa98e2SPeter Wemm 					       (long) new_ruid);
337706f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
337806f25ae9SGregory Neil Shapiro 				}
3379c2aa98e2SPeter Wemm 			}
3380c2aa98e2SPeter Wemm 
3381c2aa98e2SPeter Wemm 			if (tTd(11, 2))
3382da7d7b9cSGregory Neil Shapiro 				sm_dprintf("openmailer: running as r/euid=%ld/%ld, r/egid=%ld/%ld\n",
3383da7d7b9cSGregory Neil Shapiro 					   (long) getuid(), (long) geteuid(),
3384da7d7b9cSGregory Neil Shapiro 					   (long) getgid(), (long) getegid());
3385c2aa98e2SPeter Wemm 
3386c2aa98e2SPeter Wemm 			/* move into some "safe" directory */
3387c2aa98e2SPeter Wemm 			if (m->m_execdir != NULL)
3388c2aa98e2SPeter Wemm 			{
3389c2aa98e2SPeter Wemm 				char *q;
3390c2aa98e2SPeter Wemm 
3391c2aa98e2SPeter Wemm 				for (p = m->m_execdir; p != NULL; p = q)
3392c2aa98e2SPeter Wemm 				{
3393c2aa98e2SPeter Wemm 					q = strchr(p, ':');
3394c2aa98e2SPeter Wemm 					if (q != NULL)
3395c2aa98e2SPeter Wemm 						*q = '\0';
3396d0cef73dSGregory Neil Shapiro 					expand(p, cbuf, sizeof(cbuf), e);
3397c2aa98e2SPeter Wemm 					if (q != NULL)
3398c2aa98e2SPeter Wemm 						*q++ = ':';
3399c2aa98e2SPeter Wemm 					if (tTd(11, 20))
340040266059SGregory Neil Shapiro 						sm_dprintf("openmailer: trydir %s\n",
340194c01205SGregory Neil Shapiro 							   cbuf);
340294c01205SGregory Neil Shapiro 					if (cbuf[0] != '\0' &&
340394c01205SGregory Neil Shapiro 					    chdir(cbuf) >= 0)
3404c2aa98e2SPeter Wemm 						break;
3405c2aa98e2SPeter Wemm 				}
3406c2aa98e2SPeter Wemm 			}
3407c2aa98e2SPeter Wemm 
340840266059SGregory Neil Shapiro 			/* Check safety of program to be run */
340940266059SGregory Neil Shapiro 			sff = SFF_ROOTOK|SFF_EXECOK;
341040266059SGregory Neil Shapiro 			if (!bitnset(DBS_RUNWRITABLEPROGRAM,
341140266059SGregory Neil Shapiro 				     DontBlameSendmail))
341240266059SGregory Neil Shapiro 				sff |= SFF_NOGWFILES|SFF_NOWWFILES;
341340266059SGregory Neil Shapiro 			if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH,
341440266059SGregory Neil Shapiro 				    DontBlameSendmail))
341540266059SGregory Neil Shapiro 				sff |= SFF_NOPATHCHECK;
341640266059SGregory Neil Shapiro 			else
341740266059SGregory Neil Shapiro 				sff |= SFF_SAFEDIRPATH;
341840266059SGregory Neil Shapiro 			ret = safefile(m->m_mailer, getuid(), getgid(),
341940266059SGregory Neil Shapiro 				       user, sff, 0, NULL);
342040266059SGregory Neil Shapiro 			if (ret != 0)
342140266059SGregory Neil Shapiro 				sm_syslog(LOG_INFO, e->e_id,
342240266059SGregory Neil Shapiro 					  "Warning: program %s unsafe: %s",
342340266059SGregory Neil Shapiro 					  m->m_mailer, sm_errstring(ret));
342440266059SGregory Neil Shapiro 
3425c2aa98e2SPeter Wemm 			/* arrange to filter std & diag output of command */
3426c2aa98e2SPeter Wemm 			(void) close(rpvect[0]);
3427c2aa98e2SPeter Wemm 			if (dup2(rpvect[1], STDOUT_FILENO) < 0)
3428c2aa98e2SPeter Wemm 			{
3429c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): cannot dup pipe %d for stdout",
3430c2aa98e2SPeter Wemm 				       shortenstring(e->e_to, MAXSHORTSTR),
3431c2aa98e2SPeter Wemm 				       m->m_name, rpvect[1]);
3432c2aa98e2SPeter Wemm 				_exit(EX_OSERR);
3433c2aa98e2SPeter Wemm 			}
3434c2aa98e2SPeter Wemm 			(void) close(rpvect[1]);
343506f25ae9SGregory Neil Shapiro 
3436c2aa98e2SPeter Wemm 			if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
3437c2aa98e2SPeter Wemm 			{
3438c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): cannot dup stdout for stderr",
3439c2aa98e2SPeter Wemm 				       shortenstring(e->e_to, MAXSHORTSTR),
3440c2aa98e2SPeter Wemm 				       m->m_name);
3441c2aa98e2SPeter Wemm 				_exit(EX_OSERR);
3442c2aa98e2SPeter Wemm 			}
3443c2aa98e2SPeter Wemm 
3444c2aa98e2SPeter Wemm 			/* arrange to get standard input */
3445c2aa98e2SPeter Wemm 			(void) close(mpvect[1]);
3446c2aa98e2SPeter Wemm 			if (dup2(mpvect[0], STDIN_FILENO) < 0)
3447c2aa98e2SPeter Wemm 			{
3448c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): cannot dup pipe %d for stdin",
3449c2aa98e2SPeter Wemm 				       shortenstring(e->e_to, MAXSHORTSTR),
3450c2aa98e2SPeter Wemm 				       m->m_name, mpvect[0]);
3451c2aa98e2SPeter Wemm 				_exit(EX_OSERR);
3452c2aa98e2SPeter Wemm 			}
3453c2aa98e2SPeter Wemm 			(void) close(mpvect[0]);
3454c2aa98e2SPeter Wemm 
3455c2aa98e2SPeter Wemm 			/* arrange for all the files to be closed */
3456e92d3f3fSGregory Neil Shapiro 			sm_close_on_exec(STDERR_FILENO + 1, DtableSize);
3457c2aa98e2SPeter Wemm 
3458605302a5SGregory Neil Shapiro #if !_FFR_USE_SETLOGIN
3459c2aa98e2SPeter Wemm 			/* run disconnected from terminal */
3460c2aa98e2SPeter Wemm 			(void) setsid();
34615b0945b5SGregory Neil Shapiro #endif
3462c2aa98e2SPeter Wemm 
3463c2aa98e2SPeter Wemm 			/* try to execute the mailer */
346406f25ae9SGregory Neil Shapiro 			(void) execve(m->m_mailer, (ARGV_T) pv,
346506f25ae9SGregory Neil Shapiro 				      (ARGV_T) UserEnviron);
346606f25ae9SGregory Neil Shapiro 			save_errno = errno;
3467c2aa98e2SPeter Wemm 			syserr("Cannot exec %s", m->m_mailer);
3468c2aa98e2SPeter Wemm 			if (bitnset(M_LOCALMAILER, m->m_flags) ||
346906f25ae9SGregory Neil Shapiro 			    transienterror(save_errno))
3470c2aa98e2SPeter Wemm 				_exit(EX_OSERR);
3471c2aa98e2SPeter Wemm 			_exit(EX_UNAVAILABLE);
3472c2aa98e2SPeter Wemm 		}
3473c2aa98e2SPeter Wemm 
3474c2aa98e2SPeter Wemm 		/*
3475c2aa98e2SPeter Wemm 		**  Set up return value.
3476c2aa98e2SPeter Wemm 		*/
3477c2aa98e2SPeter Wemm 
3478c2aa98e2SPeter Wemm 		if (mci == NULL)
3479c2aa98e2SPeter Wemm 		{
348040266059SGregory Neil Shapiro 			if (clever)
348140266059SGregory Neil Shapiro 			{
348240266059SGregory Neil Shapiro 				/*
348340266059SGregory Neil Shapiro 				**  Allocate from general heap, not
348440266059SGregory Neil Shapiro 				**  envelope rpool, because this mci
348540266059SGregory Neil Shapiro 				**  is going to be cached.
348640266059SGregory Neil Shapiro 				*/
348740266059SGregory Neil Shapiro 
348840266059SGregory Neil Shapiro 				mci = mci_new(NULL);
348940266059SGregory Neil Shapiro 			}
349040266059SGregory Neil Shapiro 			else
349140266059SGregory Neil Shapiro 			{
349240266059SGregory Neil Shapiro 				/*
349340266059SGregory Neil Shapiro 				**  Prevent a storage leak by allocating
349440266059SGregory Neil Shapiro 				**  this from the envelope rpool.
349540266059SGregory Neil Shapiro 				*/
349640266059SGregory Neil Shapiro 
349740266059SGregory Neil Shapiro 				mci = mci_new(e->e_rpool);
349840266059SGregory Neil Shapiro 			}
3499c2aa98e2SPeter Wemm 		}
3500c2aa98e2SPeter Wemm 		mci->mci_mailer = m;
3501c2aa98e2SPeter Wemm 		if (clever)
3502c2aa98e2SPeter Wemm 		{
3503c2aa98e2SPeter Wemm 			mci->mci_state = MCIS_OPENING;
3504c2aa98e2SPeter Wemm 			mci_cache(mci);
3505c2aa98e2SPeter Wemm 		}
3506c2aa98e2SPeter Wemm 		else
3507c2aa98e2SPeter Wemm 		{
3508c2aa98e2SPeter Wemm 			mci->mci_state = MCIS_OPEN;
3509c2aa98e2SPeter Wemm 		}
3510c2aa98e2SPeter Wemm 		mci->mci_pid = pid;
3511c2aa98e2SPeter Wemm 		(void) close(mpvect[0]);
351240266059SGregory Neil Shapiro 		mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
3513e92d3f3fSGregory Neil Shapiro 					  (void *) &(mpvect[1]), SM_IO_WRONLY_B,
351440266059SGregory Neil Shapiro 					  NULL);
3515c2aa98e2SPeter Wemm 		if (mci->mci_out == NULL)
3516c2aa98e2SPeter Wemm 		{
3517c2aa98e2SPeter Wemm 			syserr("deliver: cannot create mailer output channel, fd=%d",
3518c2aa98e2SPeter Wemm 			       mpvect[1]);
3519c2aa98e2SPeter Wemm 			(void) close(mpvect[1]);
3520c2aa98e2SPeter Wemm 			(void) close(rpvect[0]);
3521c2aa98e2SPeter Wemm 			(void) close(rpvect[1]);
3522c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
3523c2aa98e2SPeter Wemm 			goto give_up;
3524c2aa98e2SPeter Wemm 		}
352506f25ae9SGregory Neil Shapiro 
3526c2aa98e2SPeter Wemm 		(void) close(rpvect[1]);
352740266059SGregory Neil Shapiro 		mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
3528e92d3f3fSGregory Neil Shapiro 					 (void *) &(rpvect[0]), SM_IO_RDONLY_B,
352940266059SGregory Neil Shapiro 					 NULL);
3530c2aa98e2SPeter Wemm 		if (mci->mci_in == NULL)
3531c2aa98e2SPeter Wemm 		{
3532c2aa98e2SPeter Wemm 			syserr("deliver: cannot create mailer input channel, fd=%d",
3533c2aa98e2SPeter Wemm 			       mpvect[1]);
3534c2aa98e2SPeter Wemm 			(void) close(rpvect[0]);
35352fb4f839SGregory Neil Shapiro 			SM_CLOSE_FP(mci->mci_out);
3536c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
3537c2aa98e2SPeter Wemm 			goto give_up;
3538c2aa98e2SPeter Wemm 		}
3539c2aa98e2SPeter Wemm 	}
3540c2aa98e2SPeter Wemm 
3541c2aa98e2SPeter Wemm 	/*
3542c2aa98e2SPeter Wemm 	**  If we are in SMTP opening state, send initial protocol.
3543c2aa98e2SPeter Wemm 	*/
3544c2aa98e2SPeter Wemm 
3545c2aa98e2SPeter Wemm 	if (bitnset(M_7BITS, m->m_flags) &&
3546c2aa98e2SPeter Wemm 	    (!clever || mci->mci_state == MCIS_OPENING))
3547c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_7BIT;
3548c2aa98e2SPeter Wemm 	if (clever && mci->mci_state != MCIS_CLOSED)
3549c2aa98e2SPeter Wemm 	{
355040266059SGregory Neil Shapiro #if STARTTLS || SASL
355140266059SGregory Neil Shapiro 		char *srvname;
3552*d39bd2c1SGregory Neil Shapiro 		int dotpos;
355340266059SGregory Neil Shapiro # if SASL
3554193538b7SGregory Neil Shapiro #  define DONE_AUTH(f)		bitset(MCIF_AUTHACT, f)
35555b0945b5SGregory Neil Shapiro # endif
355606f25ae9SGregory Neil Shapiro # if STARTTLS
3557193538b7SGregory Neil Shapiro #  define DONE_STARTTLS(f)	bitset(MCIF_TLSACT, f)
35585b0945b5SGregory Neil Shapiro # endif
3559c2aa98e2SPeter Wemm 
3560*d39bd2c1SGregory Neil Shapiro 		srvname = setservermacros(mci, &dotpos);
35615b0945b5SGregory Neil Shapiro # if DANE
35625b0945b5SGregory Neil Shapiro 		SM_FREE(dane_vrfy_ctx.dane_vrfy_host);
35635b0945b5SGregory Neil Shapiro 		SM_FREE(dane_vrfy_ctx.dane_vrfy_sni);
35645b0945b5SGregory Neil Shapiro 		dane_vrfy_ctx.dane_vrfy_fp[0] = '\0';
3565*d39bd2c1SGregory Neil Shapiro 		if (STE_HAS_TLSA(ste) && ste->s_tlsa->dane_tlsa_sni != NULL)
35665b0945b5SGregory Neil Shapiro 			dane_vrfy_ctx.dane_vrfy_sni = sm_strdup(ste->s_tlsa->dane_tlsa_sni);
35675b0945b5SGregory Neil Shapiro 		dane_vrfy_ctx.dane_vrfy_host = sm_strdup(srvname);
3568*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
3569*d39bd2c1SGregory Neil Shapiro 		/* undo change of srvname (== mci->mci_host) */
35705b0945b5SGregory Neil Shapiro 		FIX_TRAIL_DOT(srvname);
357140266059SGregory Neil Shapiro 
357240266059SGregory Neil Shapiro reconnect:	/* after switching to an encrypted connection */
35735b0945b5SGregory Neil Shapiro # if DANE
35745b0945b5SGregory Neil Shapiro 		if (DONE_STARTTLS(mci->mci_flags))
35755b0945b5SGregory Neil Shapiro 		{
35765b0945b5SGregory Neil Shapiro 			/* use a "reset" function? */
3577*d39bd2c1SGregory Neil Shapiro 			/* when is it required to "reset" this data? */
35785b0945b5SGregory Neil Shapiro 			SM_FREE(dane_vrfy_ctx.dane_vrfy_host);
35795b0945b5SGregory Neil Shapiro 			SM_FREE(dane_vrfy_ctx.dane_vrfy_sni);
35805b0945b5SGregory Neil Shapiro 			dane_vrfy_ctx.dane_vrfy_fp[0] = '\0';
3581*d39bd2c1SGregory Neil Shapiro 			dane_vrfy_ctx.dane_vrfy_res = DANE_VRFY_NONE;
3582*d39bd2c1SGregory Neil Shapiro 			dane_vrfy_ctx.dane_vrfy_dane_enabled = false;
3583*d39bd2c1SGregory Neil Shapiro 			if (TTD(90, 40))
3584*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("deliver: reset: chk=%#x, dane_enabled=%d\n",
3585*d39bd2c1SGregory Neil Shapiro 					dane_vrfy_ctx.dane_vrfy_chk,
3586*d39bd2c1SGregory Neil Shapiro 					dane_vrfy_ctx.dane_vrfy_dane_enabled);
35875b0945b5SGregory Neil Shapiro 		}
35882fb4f839SGregory Neil Shapiro # endif /* DANE */
35895b0945b5SGregory Neil Shapiro 
359040266059SGregory Neil Shapiro #endif /* STARTTLS || SASL */
359140266059SGregory Neil Shapiro 
359240266059SGregory Neil Shapiro 		/* set the current connection information */
359340266059SGregory Neil Shapiro 		e->e_mci = mci;
359440266059SGregory Neil Shapiro #if SASL
359540266059SGregory Neil Shapiro 		mci->mci_saslcap = NULL;
35965b0945b5SGregory Neil Shapiro #endif
35972fb4f839SGregory Neil Shapiro #if _FFR_MTA_STS
35982fb4f839SGregory Neil Shapiro # define USEMTASTS (MTASTS && !SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NOSTS) && !iscltflgset(e, D_NOSTS))
35992fb4f839SGregory Neil Shapiro # if DANE
36002fb4f839SGregory Neil Shapiro #  define CHKMTASTS (USEMTASTS && (ste == NULL || ste->s_tlsa == NULL || SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE)))
36012fb4f839SGregory Neil Shapiro # else
36022fb4f839SGregory Neil Shapiro #  define CHKMTASTS USEMTASTS
36032fb4f839SGregory Neil Shapiro # endif
36042fb4f839SGregory Neil Shapiro #endif /* _FFR_MTA_STS */
36052fb4f839SGregory Neil Shapiro #if _FFR_MTA_STS
36062fb4f839SGregory Neil Shapiro 		if (!DONE_STARTTLS(mci->mci_flags))
36072fb4f839SGregory Neil Shapiro 		{
36082fb4f839SGregory Neil Shapiro 		/*
36092fb4f839SGregory Neil Shapiro 		**  HACK: use the domain of the first valid RCPT for STS.
36102fb4f839SGregory Neil Shapiro 		**  It seems whoever wrote the specs did not consider
36112fb4f839SGregory Neil Shapiro 		**  SMTP sessions versus transactions.
36122fb4f839SGregory Neil Shapiro 		**  (but what would you expect from people who try
36132fb4f839SGregory Neil Shapiro 		**  to use https for "security" after relying on DNS?)
36142fb4f839SGregory Neil Shapiro 		*/
36152fb4f839SGregory Neil Shapiro 
36162fb4f839SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, macid("{rcpt_addr}"), "");
36172fb4f839SGregory Neil Shapiro # if DANE
3618*d39bd2c1SGregory Neil Shapiro 		if (MTASTS && STE_HAS_TLSA(ste))
36192fb4f839SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, macid("{sts_sni}"), "DANE");
36202fb4f839SGregory Neil Shapiro 		else
36212fb4f839SGregory Neil Shapiro # endif
36222fb4f839SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, macid("{sts_sni}"), "");
36232fb4f839SGregory Neil Shapiro 		if (USEMTASTS && firstto->q_user != NULL)
36242fb4f839SGregory Neil Shapiro 		{
36252fb4f839SGregory Neil Shapiro 			if (tTd(10, 64))
36262fb4f839SGregory Neil Shapiro 			{
36272fb4f839SGregory Neil Shapiro 				sm_dprintf("firstto ");
36282fb4f839SGregory Neil Shapiro 				printaddr(sm_debug_file(), firstto, false);
36292fb4f839SGregory Neil Shapiro 			}
36302fb4f839SGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
36312fb4f839SGregory Neil Shapiro 				  macid("{rcpt_addr}"), firstto->q_user);
36322fb4f839SGregory Neil Shapiro 		}
36332fb4f839SGregory Neil Shapiro 		else if (USEMTASTS)
36342fb4f839SGregory Neil Shapiro 		{
36352fb4f839SGregory Neil Shapiro 			if (tTd(10, 64))
36362fb4f839SGregory Neil Shapiro 			{
36372fb4f839SGregory Neil Shapiro 				sm_dprintf("tochain ");
36382fb4f839SGregory Neil Shapiro 				printaddr(sm_debug_file(), tochain, false);
36392fb4f839SGregory Neil Shapiro 			}
36402fb4f839SGregory Neil Shapiro 			for (to = tochain; to != NULL; to = to->q_tchain)
36412fb4f839SGregory Neil Shapiro 			{
36422fb4f839SGregory Neil Shapiro 				if (!QS_IS_UNMARKED(to->q_state))
36432fb4f839SGregory Neil Shapiro 					continue;
36442fb4f839SGregory Neil Shapiro 				if (to->q_user == NULL)
36452fb4f839SGregory Neil Shapiro 					continue;
36462fb4f839SGregory Neil Shapiro 				macdefine(&e->e_macro, A_TEMP,
36472fb4f839SGregory Neil Shapiro 					  macid("{rcpt_addr}"), to->q_user);
36482fb4f839SGregory Neil Shapiro 				break;
36492fb4f839SGregory Neil Shapiro 			}
36502fb4f839SGregory Neil Shapiro 		}
36512fb4f839SGregory Neil Shapiro 		}
36522fb4f839SGregory Neil Shapiro #endif /* _FFR_MTA_STS */
36532fb4f839SGregory Neil Shapiro #if USE_EAI
36542fb4f839SGregory Neil Shapiro 		if (!addr_is_ascii(e->e_from.q_paddr) && !e->e_smtputf8)
36552fb4f839SGregory Neil Shapiro 			e->e_smtputf8 = true;
36562fb4f839SGregory Neil Shapiro 		for (to = tochain; to != NULL && !e->e_smtputf8; to = to->q_tchain)
36572fb4f839SGregory Neil Shapiro 		{
36582fb4f839SGregory Neil Shapiro 			if (!QS_IS_UNMARKED(to->q_state))
36592fb4f839SGregory Neil Shapiro 				continue;
36602fb4f839SGregory Neil Shapiro 			if (!addr_is_ascii(to->q_user))
36612fb4f839SGregory Neil Shapiro 				e->e_smtputf8 = true;
36622fb4f839SGregory Neil Shapiro 		}
36632fb4f839SGregory Neil Shapiro 		/* XXX reset e_smtputf8 to original state at the end? */
36642fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
36652fb4f839SGregory Neil Shapiro 
3666*d39bd2c1SGregory Neil Shapiro #define ONLY_HELO(f)		bitset(MCIF_ONLY_EHLO, f)
3667*d39bd2c1SGregory Neil Shapiro #define SET_HELO(f)		f |= MCIF_ONLY_EHLO
3668*d39bd2c1SGregory Neil Shapiro #define CLR_HELO(f)		f &= ~MCIF_ONLY_EHLO
3669*d39bd2c1SGregory Neil Shapiro 
3670*d39bd2c1SGregory Neil Shapiro #if _FFR_SMTPS_CLIENT && STARTTLS
3671*d39bd2c1SGregory Neil Shapiro 		/*
3672*d39bd2c1SGregory Neil Shapiro 		**  For M_SMTPS_CLIENT, we do the STARTTLS code first,
3673*d39bd2c1SGregory Neil Shapiro 		**  then jump back and start the SMTP conversation.
3674*d39bd2c1SGregory Neil Shapiro 		*/
3675*d39bd2c1SGregory Neil Shapiro 
3676*d39bd2c1SGregory Neil Shapiro 		implicittls = bitnset(M_SMTPS_CLIENT, mci->mci_mailer->m_flags);
3677*d39bd2c1SGregory Neil Shapiro 		if (implicittls)
3678*d39bd2c1SGregory Neil Shapiro 			goto dotls;
3679*d39bd2c1SGregory Neil Shapiro backtosmtp:
3680*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_SMTPS_CLIENT && STARTTLS */
3681*d39bd2c1SGregory Neil Shapiro 
368240266059SGregory Neil Shapiro 		smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags));
368340266059SGregory Neil Shapiro 		CLR_HELO(mci->mci_flags);
368440266059SGregory Neil Shapiro 
368540266059SGregory Neil Shapiro 		if (IS_DLVR_RETURN(e))
368640266059SGregory Neil Shapiro 		{
368740266059SGregory Neil Shapiro 			/*
368840266059SGregory Neil Shapiro 			**  Check whether other side can deliver e-mail
368940266059SGregory Neil Shapiro 			**  fast enough
369040266059SGregory Neil Shapiro 			*/
369140266059SGregory Neil Shapiro 
369240266059SGregory Neil Shapiro 			if (!bitset(MCIF_DLVR_BY, mci->mci_flags))
369340266059SGregory Neil Shapiro 			{
369440266059SGregory Neil Shapiro 				e->e_status = "5.4.7";
369540266059SGregory Neil Shapiro 				usrerrenh(e->e_status,
369640266059SGregory Neil Shapiro 					  "554 Server does not support Deliver By");
369740266059SGregory Neil Shapiro 				rcode = EX_UNAVAILABLE;
369840266059SGregory Neil Shapiro 				goto give_up;
369940266059SGregory Neil Shapiro 			}
370040266059SGregory Neil Shapiro 			if (e->e_deliver_by > 0 &&
370140266059SGregory Neil Shapiro 			    e->e_deliver_by - (curtime() - e->e_ctime) <
370240266059SGregory Neil Shapiro 			    mci->mci_min_by)
370340266059SGregory Neil Shapiro 			{
370440266059SGregory Neil Shapiro 				e->e_status = "5.4.7";
370540266059SGregory Neil Shapiro 				usrerrenh(e->e_status,
370640266059SGregory Neil Shapiro 					  "554 Message can't be delivered in time; %ld < %ld",
37075b0945b5SGregory Neil Shapiro 					  e->e_deliver_by - (long) (curtime() -
37085b0945b5SGregory Neil Shapiro 								e->e_ctime),
370940266059SGregory Neil Shapiro 					  mci->mci_min_by);
371040266059SGregory Neil Shapiro 				rcode = EX_UNAVAILABLE;
371140266059SGregory Neil Shapiro 				goto give_up;
371240266059SGregory Neil Shapiro 			}
371340266059SGregory Neil Shapiro 		}
371440266059SGregory Neil Shapiro 
371540266059SGregory Neil Shapiro #if STARTTLS
3716*d39bd2c1SGregory Neil Shapiro # if _FFR_SMTPS_CLIENT
3717*d39bd2c1SGregory Neil Shapiro dotls:
3718*d39bd2c1SGregory Neil Shapiro # endif
371940266059SGregory Neil Shapiro 		/* first TLS then AUTH to provide a security layer */
372040266059SGregory Neil Shapiro 		if (mci->mci_state != MCIS_CLOSED &&
372140266059SGregory Neil Shapiro 		    !DONE_STARTTLS(mci->mci_flags))
372240266059SGregory Neil Shapiro 		{
372340266059SGregory Neil Shapiro 			int olderrors;
372440266059SGregory Neil Shapiro 			bool usetls;
372540266059SGregory Neil Shapiro 			bool saveQuickAbort = QuickAbort;
372640266059SGregory Neil Shapiro 			bool saveSuprErrs = SuprErrs;
3727*d39bd2c1SGregory Neil Shapiro 			char *srvname = NULL;
372840266059SGregory Neil Shapiro 
372940266059SGregory Neil Shapiro 			rcode = EX_OK;
3730*d39bd2c1SGregory Neil Shapiro 			usetls = bitset(MCIF_TLS, mci->mci_flags) || implicittls;
373140266059SGregory Neil Shapiro 			if (usetls)
373240266059SGregory Neil Shapiro 				usetls = !iscltflgset(e, D_NOTLS);
37335b0945b5SGregory Neil Shapiro 			if (usetls)
37345b0945b5SGregory Neil Shapiro 				usetls = tlsstate == 0;
373540266059SGregory Neil Shapiro 
3736*d39bd2c1SGregory Neil Shapiro 			srvname = macvalue(macid("{server_name}"), e);
373740266059SGregory Neil Shapiro 			if (usetls)
373840266059SGregory Neil Shapiro 			{
373940266059SGregory Neil Shapiro 				olderrors = Errors;
374040266059SGregory Neil Shapiro 				QuickAbort = false;
374140266059SGregory Neil Shapiro 				SuprErrs = true;
3742*d39bd2c1SGregory Neil Shapiro 				if (rscheck("try_tls", srvname, NULL, e,
3743*d39bd2c1SGregory Neil Shapiro 					    RSF_RMCOMM|RSF_STATUS, 7, srvname,
3744*d39bd2c1SGregory Neil Shapiro 					    NOQID, NULL, NULL) != EX_OK
374540266059SGregory Neil Shapiro 				    || Errors > olderrors)
3746d0cef73dSGregory Neil Shapiro 				{
374740266059SGregory Neil Shapiro 					usetls = false;
3748d0cef73dSGregory Neil Shapiro 				}
374940266059SGregory Neil Shapiro 				SuprErrs = saveSuprErrs;
375040266059SGregory Neil Shapiro 				QuickAbort = saveQuickAbort;
375140266059SGregory Neil Shapiro 			}
375240266059SGregory Neil Shapiro 
375306f25ae9SGregory Neil Shapiro 			if (usetls)
375406f25ae9SGregory Neil Shapiro 			{
3755*d39bd2c1SGregory Neil Shapiro 				if ((rcode = starttls(m, mci, e, implicittls
37565b0945b5SGregory Neil Shapiro # if DANE
37575b0945b5SGregory Neil Shapiro 							, &dane_vrfy_ctx
37585b0945b5SGregory Neil Shapiro # endif
37595b0945b5SGregory Neil Shapiro 					)) == EX_OK)
376006f25ae9SGregory Neil Shapiro 				{
376106f25ae9SGregory Neil Shapiro 					/* start again without STARTTLS */
376206f25ae9SGregory Neil Shapiro 					mci->mci_flags |= MCIF_TLSACT;
37632fb4f839SGregory Neil Shapiro # if DANE && _FFR_MTA_STS
37642fb4f839SGregory Neil Shapiro /* if DANE is used (and STS should be used): disable STS */
37652fb4f839SGregory Neil Shapiro /* also check MTASTS and NOSTS flag? */
3766*d39bd2c1SGregory Neil Shapiro 					if (STE_HAS_TLSA(ste) &&
37672fb4f839SGregory Neil Shapiro 					    !SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE))
37682fb4f839SGregory Neil Shapiro 						macdefine(&e->e_macro, A_PERM, macid("{rcpt_addr}"), "");
37692fb4f839SGregory Neil Shapiro # endif
377006f25ae9SGregory Neil Shapiro 				}
377106f25ae9SGregory Neil Shapiro 				else
377206f25ae9SGregory Neil Shapiro 				{
377306f25ae9SGregory Neil Shapiro 					char *s;
377406f25ae9SGregory Neil Shapiro 
377506f25ae9SGregory Neil Shapiro 					/*
37769bd497b8SGregory Neil Shapiro 					**  TLS negotiation failed, what to do?
377706f25ae9SGregory Neil Shapiro 					**  fall back to unencrypted connection
377806f25ae9SGregory Neil Shapiro 					**  or abort? How to decide?
377906f25ae9SGregory Neil Shapiro 					**  set a macro and call a ruleset.
378006f25ae9SGregory Neil Shapiro 					*/
378140266059SGregory Neil Shapiro 
378206f25ae9SGregory Neil Shapiro 					mci->mci_flags &= ~MCIF_TLS;
378306f25ae9SGregory Neil Shapiro 					switch (rcode)
378406f25ae9SGregory Neil Shapiro 					{
378506f25ae9SGregory Neil Shapiro 					  case EX_TEMPFAIL:
378606f25ae9SGregory Neil Shapiro 						s = "TEMP";
378706f25ae9SGregory Neil Shapiro 						break;
3788*d39bd2c1SGregory Neil Shapiro #if 0
3789*d39bd2c1SGregory Neil Shapiro 					/* see starttls() */
379006f25ae9SGregory Neil Shapiro 					  case EX_USAGE:
379106f25ae9SGregory Neil Shapiro 						s = "USAGE";
379206f25ae9SGregory Neil Shapiro 						break;
3793*d39bd2c1SGregory Neil Shapiro #endif
379406f25ae9SGregory Neil Shapiro 					  case EX_PROTOCOL:
379506f25ae9SGregory Neil Shapiro 						s = "PROTOCOL";
379606f25ae9SGregory Neil Shapiro 						break;
379706f25ae9SGregory Neil Shapiro 					  case EX_SOFTWARE:
379806f25ae9SGregory Neil Shapiro 						s = "SOFTWARE";
379906f25ae9SGregory Neil Shapiro 						break;
38004e4196cbSGregory Neil Shapiro 					  case EX_UNAVAILABLE:
38014e4196cbSGregory Neil Shapiro 						s = "NONE";
38024e4196cbSGregory Neil Shapiro 						break;
3803*d39bd2c1SGregory Neil Shapiro 
3804*d39bd2c1SGregory Neil Shapiro 					/*
3805*d39bd2c1SGregory Neil Shapiro 					**  Possible return from ruleset
3806*d39bd2c1SGregory Neil Shapiro 					**  tls_clt_features via
3807*d39bd2c1SGregory Neil Shapiro 					**  get_tls_se_features().
3808*d39bd2c1SGregory Neil Shapiro 					*/
3809*d39bd2c1SGregory Neil Shapiro 
38102fb4f839SGregory Neil Shapiro 					  case EX_CONFIG:
38112fb4f839SGregory Neil Shapiro 						s = "CONFIG";
38122fb4f839SGregory Neil Shapiro 						break;
381306f25ae9SGregory Neil Shapiro 
381406f25ae9SGregory Neil Shapiro 					  /* everything else is a failure */
381506f25ae9SGregory Neil Shapiro 					  default:
381606f25ae9SGregory Neil Shapiro 						s = "FAILURE";
381706f25ae9SGregory Neil Shapiro 						rcode = EX_TEMPFAIL;
381806f25ae9SGregory Neil Shapiro 					}
3819*d39bd2c1SGregory Neil Shapiro # if DANE
3820*d39bd2c1SGregory Neil Shapiro 					/*
3821*d39bd2c1SGregory Neil Shapiro 					**  TLSA found but STARTTLS "failed"?
3822*d39bd2c1SGregory Neil Shapiro 					**  What is the best way to "fail"?
3823*d39bd2c1SGregory Neil Shapiro 					**  XXX: check expiration!
3824*d39bd2c1SGregory Neil Shapiro 					*/
3825*d39bd2c1SGregory Neil Shapiro 
3826*d39bd2c1SGregory Neil Shapiro 					if (!iscltflgset(e, D_NODANE) &&
3827*d39bd2c1SGregory Neil Shapiro 					    STE_HAS_TLSA(ste) &&
3828*d39bd2c1SGregory Neil Shapiro 					    TLSA_HAS_RRs(ste->s_tlsa))
3829*d39bd2c1SGregory Neil Shapiro 					{
3830*d39bd2c1SGregory Neil Shapiro 						if (LogLevel > 8)
3831*d39bd2c1SGregory Neil Shapiro 							sm_syslog(LOG_NOTICE, NOQID,
3832*d39bd2c1SGregory Neil Shapiro 								"STARTTLS=client, relay=%.100s, warning=DANE configured in DNS but STARTTLS failed",
3833*d39bd2c1SGregory Neil Shapiro 								srvname);
3834*d39bd2c1SGregory Neil Shapiro 						/* XXX include TLSA RR from DNS? */
3835*d39bd2c1SGregory Neil Shapiro 
3836*d39bd2c1SGregory Neil Shapiro 						/*
3837*d39bd2c1SGregory Neil Shapiro 						**  Only override codes which
3838*d39bd2c1SGregory Neil Shapiro 						**  do not cause a failure
3839*d39bd2c1SGregory Neil Shapiro 						**  in the default rules.
3840*d39bd2c1SGregory Neil Shapiro 						*/
3841*d39bd2c1SGregory Neil Shapiro 
3842*d39bd2c1SGregory Neil Shapiro 						if (EX_PROTOCOL != rcode &&
3843*d39bd2c1SGregory Neil Shapiro 						    EX_SOFTWARE != rcode &&
3844*d39bd2c1SGregory Neil Shapiro 						    EX_CONFIG != rcode)
3845*d39bd2c1SGregory Neil Shapiro 						{
3846*d39bd2c1SGregory Neil Shapiro 							/* s = "DANE_TEMP"; */
3847*d39bd2c1SGregory Neil Shapiro 							dane_vrfy_ctx.dane_vrfy_chk |= TLSAFLNOTLS;
3848*d39bd2c1SGregory Neil Shapiro 						}
3849*d39bd2c1SGregory Neil Shapiro 					}
3850*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
385140266059SGregory Neil Shapiro 					macdefine(&e->e_macro, A_PERM,
385240266059SGregory Neil Shapiro 						  macid("{verify}"), s);
385306f25ae9SGregory Neil Shapiro 				}
385406f25ae9SGregory Neil Shapiro 			}
385506f25ae9SGregory Neil Shapiro 			else
38565b0945b5SGregory Neil Shapiro 			{
38575b0945b5SGregory Neil Shapiro 				p = tlsstate == 0 ? "NONE": "CLEAR";
38585b0945b5SGregory Neil Shapiro # if DANE
38595b0945b5SGregory Neil Shapiro 				/*
38605b0945b5SGregory Neil Shapiro 				**  TLSA found but STARTTLS not offered?
38615b0945b5SGregory Neil Shapiro 				**  What is the best way to "fail"?
38625b0945b5SGregory Neil Shapiro 				**  XXX: check expiration!
38635b0945b5SGregory Neil Shapiro 				*/
38645b0945b5SGregory Neil Shapiro 
38655b0945b5SGregory Neil Shapiro 				if (!bitset(MCIF_TLS, mci->mci_flags) &&
38662fb4f839SGregory Neil Shapiro 				    !iscltflgset(e, D_NODANE) &&
3867*d39bd2c1SGregory Neil Shapiro 				    STE_HAS_TLSA(ste) &&
3868*d39bd2c1SGregory Neil Shapiro 				    TLSA_HAS_RRs(ste->s_tlsa))
38695b0945b5SGregory Neil Shapiro 				{
38705b0945b5SGregory Neil Shapiro 					if (LogLevel > 8)
38715b0945b5SGregory Neil Shapiro 						sm_syslog(LOG_NOTICE, NOQID,
3872*d39bd2c1SGregory Neil Shapiro 							"STARTTLS=client, relay=%.100s, warning=DANE configured in DNS but STARTTLS not offered",
3873*d39bd2c1SGregory Neil Shapiro 							srvname);
38745b0945b5SGregory Neil Shapiro 					/* XXX include TLSA RR from DNS? */
38755b0945b5SGregory Neil Shapiro 				}
38765b0945b5SGregory Neil Shapiro # endif /* DANE */
387740266059SGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
38785b0945b5SGregory Neil Shapiro 					  macid("{verify}"), p);
38795b0945b5SGregory Neil Shapiro 			}
388006f25ae9SGregory Neil Shapiro 			olderrors = Errors;
388140266059SGregory Neil Shapiro 			QuickAbort = false;
388240266059SGregory Neil Shapiro 			SuprErrs = true;
388306f25ae9SGregory Neil Shapiro 
388406f25ae9SGregory Neil Shapiro 			/*
388506f25ae9SGregory Neil Shapiro 			**  rcode == EX_SOFTWARE is special:
38869bd497b8SGregory Neil Shapiro 			**  the TLS negotiation failed
38872fb4f839SGregory Neil Shapiro 			**  we have to drop the connection no matter what.
388806f25ae9SGregory Neil Shapiro 			**  However, we call tls_server to give it the chance
388906f25ae9SGregory Neil Shapiro 			**  to log the problem and return an appropriate
389006f25ae9SGregory Neil Shapiro 			**  error code.
389106f25ae9SGregory Neil Shapiro 			*/
389240266059SGregory Neil Shapiro 
389306f25ae9SGregory Neil Shapiro 			if (rscheck("tls_server",
389440266059SGregory Neil Shapiro 				    macvalue(macid("{verify}"), e),
3895959366dcSGregory Neil Shapiro 				    NULL, e, RSF_RMCOMM|RSF_COUNT, 5,
3896*d39bd2c1SGregory Neil Shapiro 				    srvname, NOQID, NULL, NULL) != EX_OK ||
389706f25ae9SGregory Neil Shapiro 			    Errors > olderrors ||
389806f25ae9SGregory Neil Shapiro 			    rcode == EX_SOFTWARE)
389906f25ae9SGregory Neil Shapiro 			{
390006f25ae9SGregory Neil Shapiro 				char enhsc[ENHSCLEN];
390106f25ae9SGregory Neil Shapiro 				extern char MsgBuf[];
390206f25ae9SGregory Neil Shapiro 
390306f25ae9SGregory Neil Shapiro 				if (ISSMTPCODE(MsgBuf) &&
390406f25ae9SGregory Neil Shapiro 				    extenhsc(MsgBuf + 4, ' ', enhsc) > 0)
390506f25ae9SGregory Neil Shapiro 				{
390640266059SGregory Neil Shapiro 					p = sm_rpool_strdup_x(e->e_rpool,
390740266059SGregory Neil Shapiro 							      MsgBuf);
390806f25ae9SGregory Neil Shapiro 				}
390906f25ae9SGregory Neil Shapiro 				else
391006f25ae9SGregory Neil Shapiro 				{
391106f25ae9SGregory Neil Shapiro 					p = "403 4.7.0 server not authenticated.";
391240266059SGregory Neil Shapiro 					(void) sm_strlcpy(enhsc, "4.7.0",
3913d0cef73dSGregory Neil Shapiro 							  sizeof(enhsc));
391406f25ae9SGregory Neil Shapiro 				}
391506f25ae9SGregory Neil Shapiro 				SuprErrs = saveSuprErrs;
391606f25ae9SGregory Neil Shapiro 				QuickAbort = saveQuickAbort;
391706f25ae9SGregory Neil Shapiro 
391806f25ae9SGregory Neil Shapiro 				if (rcode == EX_SOFTWARE)
391906f25ae9SGregory Neil Shapiro 				{
392006f25ae9SGregory Neil Shapiro 					/* drop the connection */
3921*d39bd2c1SGregory Neil Shapiro 					mci->mci_state = MCIS_ERROR;
39222fb4f839SGregory Neil Shapiro 					SM_CLOSE_FP(mci->mci_out);
392306f25ae9SGregory Neil Shapiro 					mci->mci_flags &= ~MCIF_TLSACT;
392406f25ae9SGregory Neil Shapiro 					(void) endmailer(mci, e, pv);
39255b0945b5SGregory Neil Shapiro 
39265b0945b5SGregory Neil Shapiro 					if ((TLSFallbacktoClear ||
39275b0945b5SGregory Neil Shapiro 					     SM_TLSI_IS(&(mci->mci_tlsi),
39285b0945b5SGregory Neil Shapiro 							TLSI_FL_FB2CLR)) &&
39295b0945b5SGregory Neil Shapiro 					    !SM_TLSI_IS(&(mci->mci_tlsi),
39305b0945b5SGregory Neil Shapiro 							TLSI_FL_NOFB2CLR)
39315b0945b5SGregory Neil Shapiro # if DANE
39325b0945b5SGregory Neil Shapiro 					     && dane_vrfy_ctx.dane_vrfy_chk !=
39335b0945b5SGregory Neil Shapiro 						DANE_SECURE
39345b0945b5SGregory Neil Shapiro # endif
39352fb4f839SGregory Neil Shapiro # if _FFR_MTA_STS
39362fb4f839SGregory Neil Shapiro 					     && !SM_TLSI_IS(&(mci->mci_tlsi),
39372fb4f839SGregory Neil Shapiro 							TLSI_FL_STS_NOFB2CLR)
39382fb4f839SGregory Neil Shapiro # endif
39395b0945b5SGregory Neil Shapiro 					    )
39405b0945b5SGregory Neil Shapiro 					{
39415b0945b5SGregory Neil Shapiro 						++tlsstate;
39425b0945b5SGregory Neil Shapiro 					}
394306f25ae9SGregory Neil Shapiro 				}
394406f25ae9SGregory Neil Shapiro 				else
394506f25ae9SGregory Neil Shapiro 				{
394606f25ae9SGregory Neil Shapiro 					/* abort transfer */
394706f25ae9SGregory Neil Shapiro 					smtpquit(m, mci, e);
394806f25ae9SGregory Neil Shapiro 				}
394906f25ae9SGregory Neil Shapiro 
3950193538b7SGregory Neil Shapiro 				/* avoid bogus error msg */
3951193538b7SGregory Neil Shapiro 				mci->mci_errno = 0;
3952193538b7SGregory Neil Shapiro 
395306f25ae9SGregory Neil Shapiro 				/* temp or permanent failure? */
395406f25ae9SGregory Neil Shapiro 				rcode = (*p == '4') ? EX_TEMPFAIL
395506f25ae9SGregory Neil Shapiro 						    : EX_UNAVAILABLE;
395640266059SGregory Neil Shapiro 				mci_setstat(mci, rcode, enhsc, p);
395706f25ae9SGregory Neil Shapiro 
395806f25ae9SGregory Neil Shapiro 				/*
395906f25ae9SGregory Neil Shapiro 				**  hack to get the error message into
396006f25ae9SGregory Neil Shapiro 				**  the envelope (done in giveresponse())
396106f25ae9SGregory Neil Shapiro 				*/
396240266059SGregory Neil Shapiro 
396340266059SGregory Neil Shapiro 				(void) sm_strlcpy(SmtpError, p,
3964d0cef73dSGregory Neil Shapiro 						  sizeof(SmtpError));
396506f25ae9SGregory Neil Shapiro 			}
3966d0cef73dSGregory Neil Shapiro 			else if (mci->mci_state == MCIS_CLOSED)
3967d0cef73dSGregory Neil Shapiro 			{
3968d0cef73dSGregory Neil Shapiro 				/* connection close caused by 421 */
3969d0cef73dSGregory Neil Shapiro 				mci->mci_errno = 0;
3970d0cef73dSGregory Neil Shapiro 				rcode = EX_TEMPFAIL;
3971d0cef73dSGregory Neil Shapiro 				mci_setstat(mci, rcode, NULL, "421");
3972d0cef73dSGregory Neil Shapiro 			}
3973d0cef73dSGregory Neil Shapiro 			else
3974d0cef73dSGregory Neil Shapiro 				rcode = 0;
3975d0cef73dSGregory Neil Shapiro 
397606f25ae9SGregory Neil Shapiro 			QuickAbort = saveQuickAbort;
397706f25ae9SGregory Neil Shapiro 			SuprErrs = saveSuprErrs;
3978193538b7SGregory Neil Shapiro 			if (DONE_STARTTLS(mci->mci_flags) &&
3979*d39bd2c1SGregory Neil Shapiro 			    mci->mci_state != MCIS_CLOSED
3980*d39bd2c1SGregory Neil Shapiro # if _FFR_SMTPS_CLIENT
3981*d39bd2c1SGregory Neil Shapiro 			    && !implicittls && !smtptls
3982*d39bd2c1SGregory Neil Shapiro # endif
3983*d39bd2c1SGregory Neil Shapiro 			   )
398406f25ae9SGregory Neil Shapiro 			{
3985193538b7SGregory Neil Shapiro 				SET_HELO(mci->mci_flags);
39866f9c8e5bSGregory Neil Shapiro 				mci_clr_extensions(mci);
398706f25ae9SGregory Neil Shapiro 				goto reconnect;
398806f25ae9SGregory Neil Shapiro 			}
39895b0945b5SGregory Neil Shapiro 			if (tlsstate == 1)
39905b0945b5SGregory Neil Shapiro 			{
39915b0945b5SGregory Neil Shapiro 				if (tTd(11, 1))
39925b0945b5SGregory Neil Shapiro 				{
39935b0945b5SGregory Neil Shapiro 					sm_syslog(LOG_DEBUG, NOQID,
39945b0945b5SGregory Neil Shapiro 						"STARTTLS=client, relay=%.100s, tlsstate=%d, status=trying_again",
39955b0945b5SGregory Neil Shapiro 						mci->mci_host, tlsstate);
39965b0945b5SGregory Neil Shapiro 					mci_dump(NULL, mci, true);
39975b0945b5SGregory Neil Shapiro 				}
39985b0945b5SGregory Neil Shapiro 				++tlsstate;
39995b0945b5SGregory Neil Shapiro 
40005b0945b5SGregory Neil Shapiro 				/*
40015b0945b5SGregory Neil Shapiro 				**  Fake the status so a new connection is
40025b0945b5SGregory Neil Shapiro 				**  tried, otherwise the TLS error will
40035b0945b5SGregory Neil Shapiro 				**  "persist" during this delivery attempt.
40045b0945b5SGregory Neil Shapiro 				*/
40055b0945b5SGregory Neil Shapiro 
40065b0945b5SGregory Neil Shapiro 				mci->mci_errno = 0;
40075b0945b5SGregory Neil Shapiro 				rcode = EX_OK;
40085b0945b5SGregory Neil Shapiro 				mci_setstat(mci, rcode, NULL, NULL);
40095b0945b5SGregory Neil Shapiro 				goto one_last_try;
40105b0945b5SGregory Neil Shapiro }
401106f25ae9SGregory Neil Shapiro 		}
4012*d39bd2c1SGregory Neil Shapiro 
4013*d39bd2c1SGregory Neil Shapiro # if _FFR_SMTPS_CLIENT
4014*d39bd2c1SGregory Neil Shapiro 		/*
4015*d39bd2c1SGregory Neil Shapiro 		**  For M_SMTPS_CLIENT, we do the STARTTLS code first,
4016*d39bd2c1SGregory Neil Shapiro 		**  then jump back and start the SMTP conversation.
4017*d39bd2c1SGregory Neil Shapiro 		*/
4018*d39bd2c1SGregory Neil Shapiro 
4019*d39bd2c1SGregory Neil Shapiro 		if (implicittls && !smtptls)
4020*d39bd2c1SGregory Neil Shapiro 		{
4021*d39bd2c1SGregory Neil Shapiro 			smtptls = true;
4022*d39bd2c1SGregory Neil Shapiro 			if (!DONE_STARTTLS(mci->mci_flags))
4023*d39bd2c1SGregory Neil Shapiro 			{
4024*d39bd2c1SGregory Neil Shapiro 				if (rcode == EX_TEMPFAIL)
4025*d39bd2c1SGregory Neil Shapiro 				{
4026*d39bd2c1SGregory Neil Shapiro 					e->e_status = "4.3.3";
4027*d39bd2c1SGregory Neil Shapiro 					usrerrenh(e->e_status, "454 TLS session initiation failed");
4028*d39bd2c1SGregory Neil Shapiro 				}
4029*d39bd2c1SGregory Neil Shapiro 				else
4030*d39bd2c1SGregory Neil Shapiro 				{
4031*d39bd2c1SGregory Neil Shapiro 					e->e_status = "5.3.3";
4032*d39bd2c1SGregory Neil Shapiro 					usrerrenh(e->e_status, "554 TLS session initiation failed");
4033*d39bd2c1SGregory Neil Shapiro 				}
4034*d39bd2c1SGregory Neil Shapiro 				goto give_up;
4035*d39bd2c1SGregory Neil Shapiro 			}
4036*d39bd2c1SGregory Neil Shapiro 			goto backtosmtp;
4037*d39bd2c1SGregory Neil Shapiro 		}
4038*d39bd2c1SGregory Neil Shapiro # endif /* _FFR_SMTPS_CLIENT */
403906f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
404006f25ae9SGregory Neil Shapiro #if SASL
404106f25ae9SGregory Neil Shapiro 		/* if other server supports authentication let's authenticate */
404206f25ae9SGregory Neil Shapiro 		if (mci->mci_state != MCIS_CLOSED &&
404306f25ae9SGregory Neil Shapiro 		    mci->mci_saslcap != NULL &&
404440266059SGregory Neil Shapiro 		    !DONE_AUTH(mci->mci_flags) && !iscltflgset(e, D_NOAUTH))
404506f25ae9SGregory Neil Shapiro 		{
404640266059SGregory Neil Shapiro 			/* Should we require some minimum authentication? */
404740266059SGregory Neil Shapiro 			if ((ret = smtpauth(m, mci, e)) == EX_OK)
404806f25ae9SGregory Neil Shapiro 			{
404906f25ae9SGregory Neil Shapiro 				int result;
405040266059SGregory Neil Shapiro 				sasl_ssf_t *ssf = NULL;
405106f25ae9SGregory Neil Shapiro 
405240266059SGregory Neil Shapiro 				/* Get security strength (features) */
405306f25ae9SGregory Neil Shapiro 				result = sasl_getprop(mci->mci_conn, SASL_SSF,
405494c01205SGregory Neil Shapiro # if SASL >= 20000
405594c01205SGregory Neil Shapiro 						      (const void **) &ssf);
40565b0945b5SGregory Neil Shapiro # else
405706f25ae9SGregory Neil Shapiro 						      (void **) &ssf);
40585b0945b5SGregory Neil Shapiro # endif
405940266059SGregory Neil Shapiro 
406040266059SGregory Neil Shapiro 				/* XXX authid? */
406106f25ae9SGregory Neil Shapiro 				if (LogLevel > 9)
406206f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_INFO, NOQID,
406340266059SGregory Neil Shapiro 						  "AUTH=client, relay=%.100s, mech=%.16s, bits=%d",
406406f25ae9SGregory Neil Shapiro 						  mci->mci_host,
406540266059SGregory Neil Shapiro 						  macvalue(macid("{auth_type}"), e),
406640266059SGregory Neil Shapiro 						  result == SASL_OK ? *ssf : 0);
40678774250cSGregory Neil Shapiro 
406806f25ae9SGregory Neil Shapiro 				/*
406940266059SGregory Neil Shapiro 				**  Only switch to encrypted connection
407006f25ae9SGregory Neil Shapiro 				**  if a security layer has been negotiated
407106f25ae9SGregory Neil Shapiro 				*/
407240266059SGregory Neil Shapiro 
407306f25ae9SGregory Neil Shapiro 				if (result == SASL_OK && *ssf > 0)
407406f25ae9SGregory Neil Shapiro 				{
4075af9557fdSGregory Neil Shapiro 					int tmo;
4076af9557fdSGregory Neil Shapiro 
407706f25ae9SGregory Neil Shapiro 					/*
407840266059SGregory Neil Shapiro 					**  Convert I/O layer to use SASL.
407940266059SGregory Neil Shapiro 					**  If the call fails, the connection
408040266059SGregory Neil Shapiro 					**  is aborted.
408106f25ae9SGregory Neil Shapiro 					*/
408240266059SGregory Neil Shapiro 
4083af9557fdSGregory Neil Shapiro 					tmo = DATA_PROGRESS_TIMEOUT * 1000;
408440266059SGregory Neil Shapiro 					if (sfdcsasl(&mci->mci_in,
408540266059SGregory Neil Shapiro 						     &mci->mci_out,
4086af9557fdSGregory Neil Shapiro 						     mci->mci_conn, tmo) == 0)
408706f25ae9SGregory Neil Shapiro 					{
40886f9c8e5bSGregory Neil Shapiro 						mci_clr_extensions(mci);
408940266059SGregory Neil Shapiro 						mci->mci_flags |= MCIF_AUTHACT|
409040266059SGregory Neil Shapiro 								  MCIF_ONLY_EHLO;
409106f25ae9SGregory Neil Shapiro 						goto reconnect;
409206f25ae9SGregory Neil Shapiro 					}
409340266059SGregory Neil Shapiro 					syserr("AUTH TLS switch failed in client");
409406f25ae9SGregory Neil Shapiro 				}
409506f25ae9SGregory Neil Shapiro 				/* else? XXX */
409606f25ae9SGregory Neil Shapiro 				mci->mci_flags |= MCIF_AUTHACT;
409706f25ae9SGregory Neil Shapiro 
409806f25ae9SGregory Neil Shapiro 			}
409940266059SGregory Neil Shapiro 			else if (ret == EX_TEMPFAIL)
410040266059SGregory Neil Shapiro 			{
410140266059SGregory Neil Shapiro 				if (LogLevel > 8)
410240266059SGregory Neil Shapiro 					sm_syslog(LOG_ERR, NOQID,
410340266059SGregory Neil Shapiro 						  "AUTH=client, relay=%.100s, temporary failure, connection abort",
410440266059SGregory Neil Shapiro 						  mci->mci_host);
410540266059SGregory Neil Shapiro 				smtpquit(m, mci, e);
410640266059SGregory Neil Shapiro 
410740266059SGregory Neil Shapiro 				/* avoid bogus error msg */
410840266059SGregory Neil Shapiro 				mci->mci_errno = 0;
410940266059SGregory Neil Shapiro 				rcode = EX_TEMPFAIL;
4110e92d3f3fSGregory Neil Shapiro 				mci_setstat(mci, rcode, "4.3.0", p);
411140266059SGregory Neil Shapiro 
411240266059SGregory Neil Shapiro 				/*
411340266059SGregory Neil Shapiro 				**  hack to get the error message into
411440266059SGregory Neil Shapiro 				**  the envelope (done in giveresponse())
411540266059SGregory Neil Shapiro 				*/
411640266059SGregory Neil Shapiro 
411740266059SGregory Neil Shapiro 				(void) sm_strlcpy(SmtpError,
411840266059SGregory Neil Shapiro 						  "Temporary AUTH failure",
4119d0cef73dSGregory Neil Shapiro 						  sizeof(SmtpError));
412040266059SGregory Neil Shapiro 			}
412106f25ae9SGregory Neil Shapiro 		}
412206f25ae9SGregory Neil Shapiro #endif /* SASL */
412306f25ae9SGregory Neil Shapiro 	}
412406f25ae9SGregory Neil Shapiro 
4125c2aa98e2SPeter Wemm do_transfer:
4126c2aa98e2SPeter Wemm 	/* clear out per-message flags from connection structure */
4127c2aa98e2SPeter Wemm 	mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);
4128c2aa98e2SPeter Wemm 
4129c2aa98e2SPeter Wemm 	if (bitset(EF_HAS8BIT, e->e_flags) &&
4130c2aa98e2SPeter Wemm 	    !bitset(EF_DONT_MIME, e->e_flags) &&
4131c2aa98e2SPeter Wemm 	    bitnset(M_7BITS, m->m_flags))
4132c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_CVT8TO7;
4133c2aa98e2SPeter Wemm 
4134c2aa98e2SPeter Wemm #if MIME7TO8
4135c2aa98e2SPeter Wemm 	if (bitnset(M_MAKE8BIT, m->m_flags) &&
4136c2aa98e2SPeter Wemm 	    !bitset(MCIF_7BIT, mci->mci_flags) &&
4137c2aa98e2SPeter Wemm 	    (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
41382fb4f839SGregory Neil Shapiro 	     (SM_STRCASEEQ(p, "quoted-printable") ||
41392fb4f839SGregory Neil Shapiro 	      SM_STRCASEEQ(p, "base64")) &&
4140c2aa98e2SPeter Wemm 	    (p = hvalue("Content-Type", e->e_header)) != NULL)
4141c2aa98e2SPeter Wemm 	{
4142c2aa98e2SPeter Wemm 		/* may want to convert 7 -> 8 */
4143c2aa98e2SPeter Wemm 		/* XXX should really parse it here -- and use a class XXX */
414440266059SGregory Neil Shapiro 		if (sm_strncasecmp(p, "text/plain", 10) == 0 &&
4145c2aa98e2SPeter Wemm 		    (p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
4146c2aa98e2SPeter Wemm 			mci->mci_flags |= MCIF_CVT7TO8;
4147c2aa98e2SPeter Wemm 	}
414806f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */
4149c2aa98e2SPeter Wemm 
4150c2aa98e2SPeter Wemm 	if (tTd(11, 1))
4151c2aa98e2SPeter Wemm 	{
415240266059SGregory Neil Shapiro 		sm_dprintf("openmailer: ");
4153e92d3f3fSGregory Neil Shapiro 		mci_dump(sm_debug_file(), mci, false);
4154c2aa98e2SPeter Wemm 	}
4155c2aa98e2SPeter Wemm 
415640266059SGregory Neil Shapiro #if _FFR_CLIENT_SIZE
415740266059SGregory Neil Shapiro 	/*
415840266059SGregory Neil Shapiro 	**  See if we know the maximum size and
415940266059SGregory Neil Shapiro 	**  abort if the message is too big.
416040266059SGregory Neil Shapiro 	**
416140266059SGregory Neil Shapiro 	**  NOTE: _FFR_CLIENT_SIZE is untested.
416240266059SGregory Neil Shapiro 	*/
416340266059SGregory Neil Shapiro 
416440266059SGregory Neil Shapiro 	if (bitset(MCIF_SIZE, mci->mci_flags) &&
416540266059SGregory Neil Shapiro 	    mci->mci_maxsize > 0 &&
416640266059SGregory Neil Shapiro 	    e->e_msgsize > mci->mci_maxsize)
416740266059SGregory Neil Shapiro 	{
416840266059SGregory Neil Shapiro 		e->e_flags |= EF_NO_BODY_RETN;
416940266059SGregory Neil Shapiro 		if (bitnset(M_LOCALMAILER, m->m_flags))
417040266059SGregory Neil Shapiro 			e->e_status = "5.2.3";
417140266059SGregory Neil Shapiro 		else
417240266059SGregory Neil Shapiro 			e->e_status = "5.3.4";
417340266059SGregory Neil Shapiro 
417440266059SGregory Neil Shapiro 		usrerrenh(e->e_status,
417540266059SGregory Neil Shapiro 			  "552 Message is too large; %ld bytes max",
417640266059SGregory Neil Shapiro 			  mci->mci_maxsize);
417740266059SGregory Neil Shapiro 		rcode = EX_DATAERR;
417840266059SGregory Neil Shapiro 
417940266059SGregory Neil Shapiro 		/* Need an e_message for error */
4180d0cef73dSGregory Neil Shapiro 		(void) sm_snprintf(SmtpError, sizeof(SmtpError),
418140266059SGregory Neil Shapiro 				   "Message is too large; %ld bytes max",
418240266059SGregory Neil Shapiro 				   mci->mci_maxsize);
418340266059SGregory Neil Shapiro 		goto give_up;
418440266059SGregory Neil Shapiro 	}
418540266059SGregory Neil Shapiro #endif /* _FFR_CLIENT_SIZE */
418640266059SGregory Neil Shapiro 
4187c2aa98e2SPeter Wemm 	if (mci->mci_state != MCIS_OPEN)
4188c2aa98e2SPeter Wemm 	{
4189c2aa98e2SPeter Wemm 		/* couldn't open the mailer */
4190c2aa98e2SPeter Wemm 		rcode = mci->mci_exitstat;
4191c2aa98e2SPeter Wemm 		errno = mci->mci_errno;
4192602a2b1bSGregory Neil Shapiro 		SM_SET_H_ERRNO(mci->mci_herrno);
4193c2aa98e2SPeter Wemm 		if (rcode == EX_OK)
4194c2aa98e2SPeter Wemm 		{
4195c2aa98e2SPeter Wemm 			/* shouldn't happen */
419606f25ae9SGregory Neil Shapiro 			syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s",
419740266059SGregory Neil Shapiro 			       (unsigned long) mci, rcode, errno,
419840266059SGregory Neil Shapiro 			       mci->mci_state, firstsig);
4199e92d3f3fSGregory Neil Shapiro 			mci_dump_all(smioout, true);
4200c2aa98e2SPeter Wemm 			rcode = EX_SOFTWARE;
4201c2aa98e2SPeter Wemm 		}
420206f25ae9SGregory Neil Shapiro 		else if (nummxhosts > hostnum)
4203c2aa98e2SPeter Wemm 		{
4204*d39bd2c1SGregory Neil Shapiro 			logfailover(e, m, mci, rcode, NULL);
4205c2aa98e2SPeter Wemm 			/* try next MX site */
4206c2aa98e2SPeter Wemm 			goto tryhost;
4207c2aa98e2SPeter Wemm 		}
4208c2aa98e2SPeter Wemm 	}
4209c2aa98e2SPeter Wemm 	else if (!clever)
4210c2aa98e2SPeter Wemm 	{
42114e4196cbSGregory Neil Shapiro 		bool ok;
42124e4196cbSGregory Neil Shapiro 
4213c2aa98e2SPeter Wemm 		/*
4214c2aa98e2SPeter Wemm 		**  Format and send message.
4215c2aa98e2SPeter Wemm 		*/
4216c2aa98e2SPeter Wemm 
42174e4196cbSGregory Neil Shapiro 		rcode = EX_OK;
42184e4196cbSGregory Neil Shapiro 		errno = 0;
42194e4196cbSGregory Neil Shapiro 		ok = putfromline(mci, e);
42204e4196cbSGregory Neil Shapiro 		if (ok)
42214e4196cbSGregory Neil Shapiro 			ok = (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
42224e4196cbSGregory Neil Shapiro 		if (ok)
42234e4196cbSGregory Neil Shapiro 			ok = (*e->e_putbody)(mci, e, NULL);
4224ffb83623SGregory Neil Shapiro 		if (ok && bitset(MCIF_INLONGLINE, mci->mci_flags))
4225ffb83623SGregory Neil Shapiro 			ok = putline("", mci);
4226c2aa98e2SPeter Wemm 
42274e4196cbSGregory Neil Shapiro 		/*
42284e4196cbSGregory Neil Shapiro 		**  Ignore an I/O error that was caused by EPIPE.
42294e4196cbSGregory Neil Shapiro 		**  Some broken mailers don't read the entire body
42304e4196cbSGregory Neil Shapiro 		**  but just exit() thus causing an I/O error.
42314e4196cbSGregory Neil Shapiro 		*/
42324e4196cbSGregory Neil Shapiro 
42334e4196cbSGregory Neil Shapiro 		if (!ok && (sm_io_error(mci->mci_out) && errno == EPIPE))
42344e4196cbSGregory Neil Shapiro 			ok = true;
42354e4196cbSGregory Neil Shapiro 
42364e4196cbSGregory Neil Shapiro 		/* (always) get the exit status */
4237c2aa98e2SPeter Wemm 		rcode = endmailer(mci, e, pv);
42384e4196cbSGregory Neil Shapiro 		if (!ok)
42394e4196cbSGregory Neil Shapiro 			rcode = EX_TEMPFAIL;
424040266059SGregory Neil Shapiro 		if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0')
4241602a2b1bSGregory Neil Shapiro 		{
4242602a2b1bSGregory Neil Shapiro 			/*
4243602a2b1bSGregory Neil Shapiro 			**  Need an e_message for mailq display.
4244602a2b1bSGregory Neil Shapiro 			**  We set SmtpError as
4245602a2b1bSGregory Neil Shapiro 			*/
4246602a2b1bSGregory Neil Shapiro 
4247d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(SmtpError, sizeof(SmtpError),
4248602a2b1bSGregory Neil Shapiro 					   "%s mailer (%s) exited with EX_TEMPFAIL",
4249602a2b1bSGregory Neil Shapiro 					   m->m_name, m->m_mailer);
4250602a2b1bSGregory Neil Shapiro 		}
4251c2aa98e2SPeter Wemm 	}
4252c2aa98e2SPeter Wemm 	else
4253c2aa98e2SPeter Wemm 	{
4254c2aa98e2SPeter Wemm 		/*
4255c2aa98e2SPeter Wemm 		**  Send the MAIL FROM: protocol
4256c2aa98e2SPeter Wemm 		*/
4257c2aa98e2SPeter Wemm 
425840266059SGregory Neil Shapiro 		/* XXX this isn't pipelined... */
4259c2aa98e2SPeter Wemm 		rcode = smtpmailfrom(m, mci, e);
42602fb4f839SGregory Neil Shapiro 		mci->mci_okrcpts = 0;
42612fb4f839SGregory Neil Shapiro 		mci->mci_retryrcpt = rcode == EX_TEMPFAIL;
4262c2aa98e2SPeter Wemm 		if (rcode == EX_OK)
4263c2aa98e2SPeter Wemm 		{
42642fb4f839SGregory Neil Shapiro 			register int rc;
426540266059SGregory Neil Shapiro #if PIPELINING
426640266059SGregory Neil Shapiro 			ADDRESS *volatile pchain;
42675b0945b5SGregory Neil Shapiro #endif
4268*d39bd2c1SGregory Neil Shapiro #if STARTTLS
4269*d39bd2c1SGregory Neil Shapiro 			ADDRESS addr;
4270*d39bd2c1SGregory Neil Shapiro #endif
4271c2aa98e2SPeter Wemm 
4272c2aa98e2SPeter Wemm 			/* send the recipient list */
42732fb4f839SGregory Neil Shapiro 			rc = EX_OK;
4274c2aa98e2SPeter Wemm 			tobuf[0] = '\0';
427540266059SGregory Neil Shapiro 			mci->mci_retryrcpt = false;
427640266059SGregory Neil Shapiro 			mci->mci_tolist = tobuf;
427740266059SGregory Neil Shapiro #if PIPELINING
427840266059SGregory Neil Shapiro 			pchain = NULL;
427940266059SGregory Neil Shapiro 			mci->mci_nextaddr = NULL;
42805b0945b5SGregory Neil Shapiro #endif
428106f25ae9SGregory Neil Shapiro 
4282c2aa98e2SPeter Wemm 			for (to = tochain; to != NULL; to = to->q_tchain)
4283c2aa98e2SPeter Wemm 			{
428440266059SGregory Neil Shapiro 				if (!QS_IS_UNMARKED(to->q_state))
4285c2aa98e2SPeter Wemm 					continue;
428606f25ae9SGregory Neil Shapiro 
428740266059SGregory Neil Shapiro 				/* mark recipient state as "ok so far" */
428840266059SGregory Neil Shapiro 				to->q_state = QS_OK;
428940266059SGregory Neil Shapiro 				e->e_to = to->q_paddr;
42902fb4f839SGregory Neil Shapiro #if _FFR_MTA_STS
42912fb4f839SGregory Neil Shapiro 				if (CHKMTASTS && to->q_user != NULL)
42922fb4f839SGregory Neil Shapiro 					macdefine(&e->e_macro, A_TEMP,
42932fb4f839SGregory Neil Shapiro 						macid("{rcpt_addr}"), to->q_user);
42942fb4f839SGregory Neil Shapiro 				else
42952fb4f839SGregory Neil Shapiro 					macdefine(&e->e_macro, A_PERM,
42962fb4f839SGregory Neil Shapiro 						macid("{rcpt_addr}"), "");
42972fb4f839SGregory Neil Shapiro #endif /* _FFR_MTA_STS */
429806f25ae9SGregory Neil Shapiro #if STARTTLS
4299*d39bd2c1SGregory Neil Shapiro # if DANE
4300*d39bd2c1SGregory Neil Shapiro 				vrfy = macvalue(macid("{verify}"), e);
4301*d39bd2c1SGregory Neil Shapiro 				if (NULL == vrfy)
4302*d39bd2c1SGregory Neil Shapiro 					vrfy = "NONE";
4303*d39bd2c1SGregory Neil Shapiro 				vrfy = sm_strdup(vrfy);
4304*d39bd2c1SGregory Neil Shapiro 				if (TTD(10, 32))
4305*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("deliver: 0: vrfy=%s, to=%s, mx=%s, QMXSECURE=%d, secure=%d, ste=%p, dane=%#x\n",
4306*d39bd2c1SGregory Neil Shapiro 						vrfy, to->q_user, CurHostName, RCPT_MXSECURE(to),
4307*d39bd2c1SGregory Neil Shapiro 						RCPT_REQ_DANE(to), ste, Dane);
4308*d39bd2c1SGregory Neil Shapiro 				if (NULL == ste && CHK_DANE_RCPT(Dane, to))
4309*d39bd2c1SGregory Neil Shapiro 				{
4310*d39bd2c1SGregory Neil Shapiro 					(void) gettlsa(CurHostName, NULL, &ste,
4311*d39bd2c1SGregory Neil Shapiro 						RCPT_MXSECURE(to) ? TLSAFLADMX : 0,
4312*d39bd2c1SGregory Neil Shapiro 						0, m->m_port);
4313*d39bd2c1SGregory Neil Shapiro 				}
4314*d39bd2c1SGregory Neil Shapiro 				if (TTD(10, 32))
4315*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("deliver: 2: vrfy=%s, to=%s, QMXSECURE=%d, secure=%d, ste=%p, dane=%#x, SUP=%#x, !TEMP=%d, ADIP=%d, chk_dane=%d, vrfy_chk=%#x, mcif=%#lx\n",
4316*d39bd2c1SGregory Neil Shapiro 						vrfy, to->q_user,
4317*d39bd2c1SGregory Neil Shapiro 						RCPT_MXSECURE(to), RCPT_REQ_DANE(to), ste, Dane,
4318*d39bd2c1SGregory Neil Shapiro 						STE_HAS_TLSA(ste) ? TLSA_IS_FL(ste->s_tlsa, TLSAFLSUP) : -1,
4319*d39bd2c1SGregory Neil Shapiro 						(0 == (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLTEMPVRFY)),
4320*d39bd2c1SGregory Neil Shapiro 						(0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLADIP)),
4321*d39bd2c1SGregory Neil Shapiro 						CHK_DANE(dane_vrfy_ctx.dane_vrfy_chk),
4322*d39bd2c1SGregory Neil Shapiro 						dane_vrfy_ctx.dane_vrfy_chk,
4323*d39bd2c1SGregory Neil Shapiro 						mci->mci_flags
4324*d39bd2c1SGregory Neil Shapiro 						);
4325*d39bd2c1SGregory Neil Shapiro 
4326*d39bd2c1SGregory Neil Shapiro 				if (strcmp("DANE_FAIL", vrfy) == 0)
4327*d39bd2c1SGregory Neil Shapiro 				{
4328*d39bd2c1SGregory Neil Shapiro 					if (!RCPT_REQ_DANE(to))
4329*d39bd2c1SGregory Neil Shapiro 						macdefine(&mci->mci_macro, A_PERM, macid("{verify}"), "FAIL");
4330*d39bd2c1SGregory Neil Shapiro 					else
4331*d39bd2c1SGregory Neil Shapiro 						SM_FREE(vrfy);
4332*d39bd2c1SGregory Neil Shapiro 				}
4333*d39bd2c1SGregory Neil Shapiro 
4334*d39bd2c1SGregory Neil Shapiro 				/*
4335*d39bd2c1SGregory Neil Shapiro 				**  Note: MCIF_TLS should be reset when
4336*d39bd2c1SGregory Neil Shapiro 				**  when starttls was successful because
4337*d39bd2c1SGregory Neil Shapiro 				**  the server should not offer it anymore.
4338*d39bd2c1SGregory Neil Shapiro 				*/
4339*d39bd2c1SGregory Neil Shapiro 
4340*d39bd2c1SGregory Neil Shapiro 				else if (strcmp("TRUSTED", vrfy) != 0 &&
4341*d39bd2c1SGregory Neil Shapiro 					 RCPT_REQ_DANE(to))
4342*d39bd2c1SGregory Neil Shapiro 				{
4343*d39bd2c1SGregory Neil Shapiro 					macdefine(&mci->mci_macro, A_PERM, macid("{verify}"),
4344*d39bd2c1SGregory Neil Shapiro 						(0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLNOTLS)) ?
4345*d39bd2c1SGregory Neil Shapiro 						"DANE_TEMP" :
4346*d39bd2c1SGregory Neil Shapiro 						(bitset(MCIF_TLS|MCIF_TLSACT, mci->mci_flags) ?
4347*d39bd2c1SGregory Neil Shapiro 						 "DANE_FAIL" : "DANE_NOTLS"));
4348*d39bd2c1SGregory Neil Shapiro 				}
4349*d39bd2c1SGregory Neil Shapiro 				/* DANE: unsupported types: require TLS but not available? */
4350*d39bd2c1SGregory Neil Shapiro 				else if (strcmp("TRUSTED", vrfy) != 0 &&
4351*d39bd2c1SGregory Neil Shapiro 					RCPT_REQ_TLS(to)
4352*d39bd2c1SGregory Neil Shapiro 					&& (!bitset(MCIF_TLS|MCIF_TLSACT, mci->mci_flags)
4353*d39bd2c1SGregory Neil Shapiro 					     || (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLNOTLS))))
4354*d39bd2c1SGregory Neil Shapiro 				{
4355*d39bd2c1SGregory Neil Shapiro 					macdefine(&mci->mci_macro, A_PERM, macid("{verify}"),
4356*d39bd2c1SGregory Neil Shapiro 						(0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLNOTLS)) ?
4357*d39bd2c1SGregory Neil Shapiro 						"DANE_TEMP" : "DANE_NOTLS");
4358*d39bd2c1SGregory Neil Shapiro 				}
4359*d39bd2c1SGregory Neil Shapiro 				else
4360*d39bd2c1SGregory Neil Shapiro 					SM_FREE(vrfy);
4361*d39bd2c1SGregory Neil Shapiro 				if (TTD(10, 32))
4362*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("deliver: 7: verify=%s, secure=%d\n",
4363*d39bd2c1SGregory Neil Shapiro 						macvalue(macid("{verify}"), e),
4364*d39bd2c1SGregory Neil Shapiro 						RCPT_REQ_DANE(to));
4365*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
4366*d39bd2c1SGregory Neil Shapiro 
43672fb4f839SGregory Neil Shapiro 				rc = rscheck("tls_rcpt", to->q_user, NULL, e,
4368959366dcSGregory Neil Shapiro 					    RSF_RMCOMM|RSF_COUNT, 3,
4369*d39bd2c1SGregory Neil Shapiro 					    mci->mci_host, e->e_id, &addr, NULL);
4370*d39bd2c1SGregory Neil Shapiro 
4371*d39bd2c1SGregory Neil Shapiro # if DANE
4372*d39bd2c1SGregory Neil Shapiro 				if (vrfy != NULL)
4373*d39bd2c1SGregory Neil Shapiro 				{
4374*d39bd2c1SGregory Neil Shapiro 					macdefine(&mci->mci_macro, A_PERM, macid("{verify}"), vrfy);
4375*d39bd2c1SGregory Neil Shapiro 					SM_FREE(vrfy);
4376*d39bd2c1SGregory Neil Shapiro 				}
4377*d39bd2c1SGregory Neil Shapiro # endif
4378*d39bd2c1SGregory Neil Shapiro 
4379*d39bd2c1SGregory Neil Shapiro 				if (TTD(10, 32))
4380*d39bd2c1SGregory Neil Shapiro 					sm_dprintf("deliver: 9: verify=%s, to=%s, tls_rcpt=%d\n",
4381*d39bd2c1SGregory Neil Shapiro 						macvalue(macid("{verify}"), e),
4382*d39bd2c1SGregory Neil Shapiro 						to->q_user, rc);
4383*d39bd2c1SGregory Neil Shapiro 
43842fb4f839SGregory Neil Shapiro 				if (rc != EX_OK)
4385c2aa98e2SPeter Wemm 				{
4386*d39bd2c1SGregory Neil Shapiro 					char *dsn;
4387*d39bd2c1SGregory Neil Shapiro 
43882fb4f839SGregory Neil Shapiro 					to->q_flags |= QINTREPLY;
43892fb4f839SGregory Neil Shapiro 					markfailure(e, to, mci, rc, false);
4390*d39bd2c1SGregory Neil Shapiro 					if (addr.q_host != NULL &&
4391*d39bd2c1SGregory Neil Shapiro 					    isenhsc(addr.q_host, ' ') > 0)
4392*d39bd2c1SGregory Neil Shapiro 						dsn = addr.q_host;
4393*d39bd2c1SGregory Neil Shapiro 					else
4394*d39bd2c1SGregory Neil Shapiro 						dsn = NULL;
4395*d39bd2c1SGregory Neil Shapiro 					giveresponse(rc, dsn, m, mci,
439640266059SGregory Neil Shapiro 						     ctladdr, xstart, e, to);
43972fb4f839SGregory Neil Shapiro 					if (rc == EX_TEMPFAIL)
439840266059SGregory Neil Shapiro 					{
439940266059SGregory Neil Shapiro 						mci->mci_retryrcpt = true;
440040266059SGregory Neil Shapiro 						to->q_state = QS_RETRY;
440140266059SGregory Neil Shapiro 					}
440206f25ae9SGregory Neil Shapiro 					continue;
440306f25ae9SGregory Neil Shapiro 				}
440406f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
440506f25ae9SGregory Neil Shapiro 
44062fb4f839SGregory Neil Shapiro 				rc = smtprcpt(to, m, mci, e, ctladdr, xstart);
440740266059SGregory Neil Shapiro #if PIPELINING
44082fb4f839SGregory Neil Shapiro 				if (rc == EX_OK &&
440940266059SGregory Neil Shapiro 				    bitset(MCIF_PIPELINED, mci->mci_flags))
441006f25ae9SGregory Neil Shapiro 				{
441140266059SGregory Neil Shapiro 					/*
441240266059SGregory Neil Shapiro 					**  Add new element to list of
441340266059SGregory Neil Shapiro 					**  recipients for pipelining.
441440266059SGregory Neil Shapiro 					*/
441540266059SGregory Neil Shapiro 
441640266059SGregory Neil Shapiro 					to->q_pchain = NULL;
441740266059SGregory Neil Shapiro 					if (mci->mci_nextaddr == NULL)
441840266059SGregory Neil Shapiro 						mci->mci_nextaddr = to;
441940266059SGregory Neil Shapiro 					if (pchain == NULL)
442040266059SGregory Neil Shapiro 						pchain = to;
4421c2aa98e2SPeter Wemm 					else
4422c2aa98e2SPeter Wemm 					{
442340266059SGregory Neil Shapiro 						pchain->q_pchain = to;
442440266059SGregory Neil Shapiro 						pchain = pchain->q_pchain;
442540266059SGregory Neil Shapiro 					}
442640266059SGregory Neil Shapiro 				}
442740266059SGregory Neil Shapiro #endif /* PIPELINING */
44282fb4f839SGregory Neil Shapiro 				if (rc != EX_OK)
442940266059SGregory Neil Shapiro 				{
44302fb4f839SGregory Neil Shapiro 					markfailure(e, to, mci, rc, false);
44312fb4f839SGregory Neil Shapiro 					giveresponse(rc, to->q_status, m, mci,
443240266059SGregory Neil Shapiro 						     ctladdr, xstart, e, to);
44332fb4f839SGregory Neil Shapiro 					if (rc == EX_TEMPFAIL)
443440266059SGregory Neil Shapiro 						to->q_state = QS_RETRY;
4435c2aa98e2SPeter Wemm 				}
4436c2aa98e2SPeter Wemm 			}
4437c2aa98e2SPeter Wemm 
443840266059SGregory Neil Shapiro 			/* No recipients in list and no missing responses? */
443940266059SGregory Neil Shapiro 			if (tobuf[0] == '\0'
444040266059SGregory Neil Shapiro #if PIPELINING
44412fb4f839SGregory Neil Shapiro 			    /* && bitset(MCIF_PIPELINED, mci->mci_flags) */
444240266059SGregory Neil Shapiro 			    && mci->mci_nextaddr == NULL
44435b0945b5SGregory Neil Shapiro #endif
444440266059SGregory Neil Shapiro 			   )
4445c2aa98e2SPeter Wemm 			{
44462fb4f839SGregory Neil Shapiro 				rcode = rc;
4447c2aa98e2SPeter Wemm 				e->e_to = NULL;
4448c2aa98e2SPeter Wemm 				if (bitset(MCIF_CACHED, mci->mci_flags))
4449c2aa98e2SPeter Wemm 					smtprset(m, mci, e);
4450c2aa98e2SPeter Wemm 			}
4451c2aa98e2SPeter Wemm 			else
4452c2aa98e2SPeter Wemm 			{
4453c2aa98e2SPeter Wemm 				e->e_to = tobuf + 1;
445440266059SGregory Neil Shapiro 				rcode = smtpdata(m, mci, e, ctladdr, xstart);
4455c2aa98e2SPeter Wemm 			}
4456c2aa98e2SPeter Wemm 		}
44572fb4f839SGregory Neil Shapiro 
44582fb4f839SGregory Neil Shapiro 		if (rcode == EX_TEMPFAIL && nummxhosts > hostnum
44592fb4f839SGregory Neil Shapiro 		    && (mci->mci_retryrcpt || mci->mci_okrcpts > 0)
44602fb4f839SGregory Neil Shapiro 		   )
4461c2aa98e2SPeter Wemm 		{
4462*d39bd2c1SGregory Neil Shapiro 			logfailover(e, m, mci, rcode, to);
4463c2aa98e2SPeter Wemm 			/* try next MX site */
4464c2aa98e2SPeter Wemm 			goto tryhost;
4465c2aa98e2SPeter Wemm 		}
4466c2aa98e2SPeter Wemm 	}
4467c2aa98e2SPeter Wemm #if NAMED_BIND
4468c2aa98e2SPeter Wemm 	if (ConfigLevel < 2)
4469c2aa98e2SPeter Wemm 		_res.options |= RES_DEFNAMES | RES_DNSRCH;	/* XXX */
44705b0945b5SGregory Neil Shapiro #endif
4471c2aa98e2SPeter Wemm 
4472c2aa98e2SPeter Wemm 	if (tTd(62, 1))
4473c2aa98e2SPeter Wemm 		checkfds("after delivery");
4474c2aa98e2SPeter Wemm 
4475c2aa98e2SPeter Wemm 	/*
4476c2aa98e2SPeter Wemm 	**  Do final status disposal.
4477c2aa98e2SPeter Wemm 	**	We check for something in tobuf for the SMTP case.
4478c2aa98e2SPeter Wemm 	**	If we got a temporary failure, arrange to queue the
4479c2aa98e2SPeter Wemm 	**		addressees.
4480c2aa98e2SPeter Wemm 	*/
4481c2aa98e2SPeter Wemm 
4482c2aa98e2SPeter Wemm   give_up:
4483c2aa98e2SPeter Wemm 	if (bitnset(M_LMTP, m->m_flags))
4484c2aa98e2SPeter Wemm 	{
4485c2aa98e2SPeter Wemm 		lmtp_rcode = rcode;
4486c2aa98e2SPeter Wemm 		tobuf[0] = '\0';
448740266059SGregory Neil Shapiro 		anyok = false;
448840266059SGregory Neil Shapiro 		strsize = 0;
4489c2aa98e2SPeter Wemm 	}
4490c2aa98e2SPeter Wemm 	else
4491c2aa98e2SPeter Wemm 		anyok = rcode == EX_OK;
4492c2aa98e2SPeter Wemm 
4493c2aa98e2SPeter Wemm 	for (to = tochain; to != NULL; to = to->q_tchain)
4494c2aa98e2SPeter Wemm 	{
4495c2aa98e2SPeter Wemm 		/* see if address already marked */
449606f25ae9SGregory Neil Shapiro 		if (!QS_IS_OK(to->q_state))
4497c2aa98e2SPeter Wemm 			continue;
4498c2aa98e2SPeter Wemm 
4499c2aa98e2SPeter Wemm 		/* if running LMTP, get the status for each address */
4500c2aa98e2SPeter Wemm 		if (bitnset(M_LMTP, m->m_flags))
4501c2aa98e2SPeter Wemm 		{
4502c2aa98e2SPeter Wemm 			if (lmtp_rcode == EX_OK)
4503c2aa98e2SPeter Wemm 				rcode = smtpgetstat(m, mci, e);
4504c2aa98e2SPeter Wemm 			if (rcode == EX_OK)
4505c2aa98e2SPeter Wemm 			{
450640266059SGregory Neil Shapiro 				strsize += sm_strlcat2(tobuf + strsize, ",",
450740266059SGregory Neil Shapiro 						to->q_paddr,
450840266059SGregory Neil Shapiro 						tobufsize - strsize);
450940266059SGregory Neil Shapiro 				SM_ASSERT(strsize < tobufsize);
451040266059SGregory Neil Shapiro 				anyok = true;
4511c2aa98e2SPeter Wemm 			}
4512c2aa98e2SPeter Wemm 			else
4513c2aa98e2SPeter Wemm 			{
4514c2aa98e2SPeter Wemm 				e->e_to = to->q_paddr;
451540266059SGregory Neil Shapiro 				markfailure(e, to, mci, rcode, true);
451606f25ae9SGregory Neil Shapiro 				giveresponse(rcode, to->q_status, m, mci,
451740266059SGregory Neil Shapiro 					     ctladdr, xstart, e, to);
4518c2aa98e2SPeter Wemm 				e->e_to = tobuf + 1;
4519c2aa98e2SPeter Wemm 				continue;
4520c2aa98e2SPeter Wemm 			}
4521c2aa98e2SPeter Wemm 		}
4522c2aa98e2SPeter Wemm 		else
4523c2aa98e2SPeter Wemm 		{
4524c2aa98e2SPeter Wemm 			/* mark bad addresses */
4525c2aa98e2SPeter Wemm 			if (rcode != EX_OK)
4526c2aa98e2SPeter Wemm 			{
4527c2aa98e2SPeter Wemm 				if (goodmxfound && rcode == EX_NOHOST)
4528c2aa98e2SPeter Wemm 					rcode = EX_TEMPFAIL;
452940266059SGregory Neil Shapiro 				markfailure(e, to, mci, rcode, true);
4530c2aa98e2SPeter Wemm 				continue;
4531c2aa98e2SPeter Wemm 			}
4532c2aa98e2SPeter Wemm 		}
4533c2aa98e2SPeter Wemm 
4534c2aa98e2SPeter Wemm 		/* successful delivery */
453506f25ae9SGregory Neil Shapiro 		to->q_state = QS_SENT;
4536c2aa98e2SPeter Wemm 		to->q_statdate = curtime();
4537c2aa98e2SPeter Wemm 		e->e_nsent++;
453806f25ae9SGregory Neil Shapiro 
453906f25ae9SGregory Neil Shapiro 		/*
454006f25ae9SGregory Neil Shapiro 		**  Checkpoint the send list every few addresses
454106f25ae9SGregory Neil Shapiro 		*/
454206f25ae9SGregory Neil Shapiro 
454342e5d165SGregory Neil Shapiro 		if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval)
454406f25ae9SGregory Neil Shapiro 		{
45452fb4f839SGregory Neil Shapiro 			queueup(e, QUP_FL_NONE);
454606f25ae9SGregory Neil Shapiro 			e->e_nsent = 0;
454706f25ae9SGregory Neil Shapiro 		}
454806f25ae9SGregory Neil Shapiro 
4549c2aa98e2SPeter Wemm 		if (bitnset(M_LOCALMAILER, m->m_flags) &&
4550c2aa98e2SPeter Wemm 		    bitset(QPINGONSUCCESS, to->q_flags))
4551c2aa98e2SPeter Wemm 		{
4552c2aa98e2SPeter Wemm 			to->q_flags |= QDELIVERED;
4553c2aa98e2SPeter Wemm 			to->q_status = "2.1.5";
455440266059SGregory Neil Shapiro 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
455540266059SGregory Neil Shapiro 					     "%s... Successfully delivered\n",
4556c2aa98e2SPeter Wemm 					     to->q_paddr);
4557c2aa98e2SPeter Wemm 		}
4558c2aa98e2SPeter Wemm 		else if (bitset(QPINGONSUCCESS, to->q_flags) &&
4559c2aa98e2SPeter Wemm 			 bitset(QPRIMARY, to->q_flags) &&
4560c2aa98e2SPeter Wemm 			 !bitset(MCIF_DSN, mci->mci_flags))
4561c2aa98e2SPeter Wemm 		{
4562c2aa98e2SPeter Wemm 			to->q_flags |= QRELAYED;
456340266059SGregory Neil Shapiro 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
456440266059SGregory Neil Shapiro 					     "%s... relayed; expect no further notifications\n",
456540266059SGregory Neil Shapiro 					     to->q_paddr);
456640266059SGregory Neil Shapiro 		}
456740266059SGregory Neil Shapiro 		else if (IS_DLVR_NOTIFY(e) &&
456840266059SGregory Neil Shapiro 			 !bitset(MCIF_DLVR_BY, mci->mci_flags) &&
456940266059SGregory Neil Shapiro 			 bitset(QPRIMARY, to->q_flags) &&
457040266059SGregory Neil Shapiro 			 (!bitset(QHASNOTIFY, to->q_flags) ||
457140266059SGregory Neil Shapiro 			  bitset(QPINGONSUCCESS, to->q_flags) ||
457240266059SGregory Neil Shapiro 			  bitset(QPINGONFAILURE, to->q_flags) ||
457340266059SGregory Neil Shapiro 			  bitset(QPINGONDELAY, to->q_flags)))
457440266059SGregory Neil Shapiro 		{
457540266059SGregory Neil Shapiro 			/* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */
457640266059SGregory Neil Shapiro 			to->q_flags |= QBYNRELAY;
457740266059SGregory Neil Shapiro 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
457840266059SGregory Neil Shapiro 					     "%s... Deliver-by notify: relayed\n",
457940266059SGregory Neil Shapiro 					     to->q_paddr);
458040266059SGregory Neil Shapiro 		}
458140266059SGregory Neil Shapiro 		else if (IS_DLVR_TRACE(e) &&
458240266059SGregory Neil Shapiro 			 (!bitset(QHASNOTIFY, to->q_flags) ||
458340266059SGregory Neil Shapiro 			  bitset(QPINGONSUCCESS, to->q_flags) ||
458440266059SGregory Neil Shapiro 			  bitset(QPINGONFAILURE, to->q_flags) ||
458540266059SGregory Neil Shapiro 			  bitset(QPINGONDELAY, to->q_flags)) &&
458640266059SGregory Neil Shapiro 			 bitset(QPRIMARY, to->q_flags))
458740266059SGregory Neil Shapiro 		{
458840266059SGregory Neil Shapiro 			/* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */
458940266059SGregory Neil Shapiro 			to->q_flags |= QBYTRACE;
459040266059SGregory Neil Shapiro 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
459140266059SGregory Neil Shapiro 					     "%s... Deliver-By trace: relayed\n",
4592c2aa98e2SPeter Wemm 					     to->q_paddr);
4593c2aa98e2SPeter Wemm 		}
4594c2aa98e2SPeter Wemm 	}
4595c2aa98e2SPeter Wemm 
4596c2aa98e2SPeter Wemm 	if (bitnset(M_LMTP, m->m_flags))
4597c2aa98e2SPeter Wemm 	{
4598c2aa98e2SPeter Wemm 		/*
4599c2aa98e2SPeter Wemm 		**  Global information applies to the last recipient only;
4600c2aa98e2SPeter Wemm 		**  clear it out to avoid bogus errors.
4601c2aa98e2SPeter Wemm 		*/
4602c2aa98e2SPeter Wemm 
4603c2aa98e2SPeter Wemm 		rcode = EX_OK;
4604c2aa98e2SPeter Wemm 		e->e_statmsg = NULL;
4605c2aa98e2SPeter Wemm 
4606c2aa98e2SPeter Wemm 		/* reset the mci state for the next transaction */
460740266059SGregory Neil Shapiro 		if (mci != NULL &&
460840266059SGregory Neil Shapiro 		    (mci->mci_state == MCIS_MAIL ||
460940266059SGregory Neil Shapiro 		     mci->mci_state == MCIS_RCPT ||
461040266059SGregory Neil Shapiro 		     mci->mci_state == MCIS_DATA))
4611323f6dcbSGregory Neil Shapiro 		{
4612c2aa98e2SPeter Wemm 			mci->mci_state = MCIS_OPEN;
4613323f6dcbSGregory Neil Shapiro 			SmtpPhase = mci->mci_phase = "idle";
4614323f6dcbSGregory Neil Shapiro 			sm_setproctitle(true, e, "%s: %s", CurHostName,
4615323f6dcbSGregory Neil Shapiro 					mci->mci_phase);
4616323f6dcbSGregory Neil Shapiro 		}
4617c2aa98e2SPeter Wemm 	}
4618c2aa98e2SPeter Wemm 
4619c2aa98e2SPeter Wemm 	if (tobuf[0] != '\0')
462040266059SGregory Neil Shapiro 	{
46212fb4f839SGregory Neil Shapiro 		giveresponse(rcode,
46222fb4f839SGregory Neil Shapiro #if _FFR_NULLMX_STATUS
46232fb4f839SGregory Neil Shapiro 			(NULL == mci || SM_IS_EMPTY(mci->mci_status))
46242fb4f839SGregory Neil Shapiro 				? NULL :
46252fb4f839SGregory Neil Shapiro #endif
46262fb4f839SGregory Neil Shapiro 				mci->mci_status,
46272fb4f839SGregory Neil Shapiro 			m, mci, ctladdr, xstart, e, NULL);
462840266059SGregory Neil Shapiro #if 0
462940266059SGregory Neil Shapiro 		/*
463040266059SGregory Neil Shapiro 		**  This code is disabled for now because I am not
463140266059SGregory Neil Shapiro 		**  sure that copying status from the first recipient
463240266059SGregory Neil Shapiro 		**  to all non-status'ed recipients is a good idea.
463340266059SGregory Neil Shapiro 		*/
463440266059SGregory Neil Shapiro 
463540266059SGregory Neil Shapiro 		if (tochain->q_message != NULL &&
463640266059SGregory Neil Shapiro 		    !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK)
463740266059SGregory Neil Shapiro 		{
463840266059SGregory Neil Shapiro 			for (to = tochain->q_tchain; to != NULL;
463940266059SGregory Neil Shapiro 			     to = to->q_tchain)
464040266059SGregory Neil Shapiro 			{
464140266059SGregory Neil Shapiro 				/* see if address already marked */
464240266059SGregory Neil Shapiro 				if (QS_IS_QUEUEUP(to->q_state) &&
464340266059SGregory Neil Shapiro 				    to->q_message == NULL)
464440266059SGregory Neil Shapiro 					to->q_message = sm_rpool_strdup_x(e->e_rpool,
464540266059SGregory Neil Shapiro 							tochain->q_message);
464640266059SGregory Neil Shapiro 			}
464740266059SGregory Neil Shapiro 		}
464840266059SGregory Neil Shapiro #endif /* 0 */
464940266059SGregory Neil Shapiro 	}
4650c2aa98e2SPeter Wemm 	if (anyok)
465140266059SGregory Neil Shapiro 		markstats(e, tochain, STATS_NORMAL);
4652c2aa98e2SPeter Wemm 	mci_store_persistent(mci);
4653c2aa98e2SPeter Wemm 
46545b0945b5SGregory Neil Shapiro #if _FFR_OCC
46555b0945b5SGregory Neil Shapiro 	/*
46565b0945b5SGregory Neil Shapiro 	**  HACK: this is NOT the right place to "close" a connection!
46575b0945b5SGregory Neil Shapiro 	**  use smtpquit?
46585b0945b5SGregory Neil Shapiro 	**  add a flag to mci to indicate that rate/conc. was increased?
46595b0945b5SGregory Neil Shapiro 	*/
46605b0945b5SGregory Neil Shapiro 
46615b0945b5SGregory Neil Shapiro 	if (clever)
46625b0945b5SGregory Neil Shapiro 	{
46635b0945b5SGregory Neil Shapiro 		extern SOCKADDR CurHostAddr;
46645b0945b5SGregory Neil Shapiro 
46655b0945b5SGregory Neil Shapiro 		/* check family... {} */
46665b0945b5SGregory Neil Shapiro 		/* r = anynet_pton(AF_INET, p, dst); */
46675b0945b5SGregory Neil Shapiro 		occ_close(e, mci, host, &CurHostAddr);
46685b0945b5SGregory Neil Shapiro 	}
46695b0945b5SGregory Neil Shapiro #endif /* _FFR_OCC */
46705b0945b5SGregory Neil Shapiro 
467140266059SGregory Neil Shapiro 	/* Some recipients were tempfailed, try them on the next host */
467240266059SGregory Neil Shapiro 	if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum)
467340266059SGregory Neil Shapiro 	{
4674*d39bd2c1SGregory Neil Shapiro 		logfailover(e, m, mci, rcode, to);
467540266059SGregory Neil Shapiro 		/* try next MX site */
467640266059SGregory Neil Shapiro 		goto tryhost;
467740266059SGregory Neil Shapiro 	}
467840266059SGregory Neil Shapiro 
4679c2aa98e2SPeter Wemm 	/* now close the connection */
4680c2aa98e2SPeter Wemm 	if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED &&
4681c2aa98e2SPeter Wemm 	    !bitset(MCIF_CACHED, mci->mci_flags))
4682c2aa98e2SPeter Wemm 		smtpquit(m, mci, e);
4683c2aa98e2SPeter Wemm 
468440266059SGregory Neil Shapiro cleanup: ;
468540266059SGregory Neil Shapiro 	}
468640266059SGregory Neil Shapiro 	SM_FINALLY
468740266059SGregory Neil Shapiro 	{
4688c2aa98e2SPeter Wemm 		/*
4689c2aa98e2SPeter Wemm 		**  Restore state and return.
4690c2aa98e2SPeter Wemm 		*/
4691c2aa98e2SPeter Wemm #if XDEBUG
4692c2aa98e2SPeter Wemm 		char wbuf[MAXLINE];
4693c2aa98e2SPeter Wemm 
4694c2aa98e2SPeter Wemm 		/* make absolutely certain 0, 1, and 2 are in use */
4695d0cef73dSGregory Neil Shapiro 		(void) sm_snprintf(wbuf, sizeof(wbuf),
469640266059SGregory Neil Shapiro 				   "%s... end of deliver(%s)",
4697c2aa98e2SPeter Wemm 				   e->e_to == NULL ? "NO-TO-LIST"
469840266059SGregory Neil Shapiro 						   : shortenstring(e->e_to,
469940266059SGregory Neil Shapiro 								   MAXSHORTSTR),
4700c2aa98e2SPeter Wemm 				  m->m_name);
4701c2aa98e2SPeter Wemm 		checkfd012(wbuf);
470206f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
4703c2aa98e2SPeter Wemm 
4704c2aa98e2SPeter Wemm 		errno = 0;
470540266059SGregory Neil Shapiro 
470640266059SGregory Neil Shapiro 		/*
470740266059SGregory Neil Shapiro 		**  It was originally necessary to set macro 'g' to NULL
470840266059SGregory Neil Shapiro 		**  because it previously pointed to an auto buffer.
470940266059SGregory Neil Shapiro 		**  We don't do this any more, so this may be unnecessary.
471040266059SGregory Neil Shapiro 		*/
471140266059SGregory Neil Shapiro 
471240266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL);
471306f25ae9SGregory Neil Shapiro 		e->e_to = NULL;
471440266059SGregory Neil Shapiro 	}
471540266059SGregory Neil Shapiro 	SM_END_TRY
471606f25ae9SGregory Neil Shapiro 	return rcode;
4717c2aa98e2SPeter Wemm }
471806f25ae9SGregory Neil Shapiro 
471940266059SGregory Neil Shapiro /*
4720*d39bd2c1SGregory Neil Shapiro **  EX2ENHSC -- return proper enhanced status code for an EX_ code
4721*d39bd2c1SGregory Neil Shapiro **
4722*d39bd2c1SGregory Neil Shapiro **	Parameters:
4723*d39bd2c1SGregory Neil Shapiro **		xcode -- EX_* code
4724*d39bd2c1SGregory Neil Shapiro **
4725*d39bd2c1SGregory Neil Shapiro **	Returns:
4726*d39bd2c1SGregory Neil Shapiro **		enhanced status code if appropriate
4727*d39bd2c1SGregory Neil Shapiro **		NULL otherwise
4728*d39bd2c1SGregory Neil Shapiro */
4729*d39bd2c1SGregory Neil Shapiro 
4730*d39bd2c1SGregory Neil Shapiro static char *ex2enhsc __P((int));
4731*d39bd2c1SGregory Neil Shapiro 
4732*d39bd2c1SGregory Neil Shapiro static char *
ex2enhsc(xcode)4733*d39bd2c1SGregory Neil Shapiro ex2enhsc(xcode)
4734*d39bd2c1SGregory Neil Shapiro 	int xcode;
4735*d39bd2c1SGregory Neil Shapiro {
4736*d39bd2c1SGregory Neil Shapiro 	switch (xcode)
4737*d39bd2c1SGregory Neil Shapiro 	{
4738*d39bd2c1SGregory Neil Shapiro 	  case EX_USAGE:
4739*d39bd2c1SGregory Neil Shapiro 		return "5.5.4";
4740*d39bd2c1SGregory Neil Shapiro 		break;
4741*d39bd2c1SGregory Neil Shapiro 
4742*d39bd2c1SGregory Neil Shapiro 	  case EX_DATAERR:
4743*d39bd2c1SGregory Neil Shapiro 		return "5.5.2";
4744*d39bd2c1SGregory Neil Shapiro 		break;
4745*d39bd2c1SGregory Neil Shapiro 
4746*d39bd2c1SGregory Neil Shapiro 	  case EX_NOUSER:
4747*d39bd2c1SGregory Neil Shapiro 		return "5.1.1";
4748*d39bd2c1SGregory Neil Shapiro 		break;
4749*d39bd2c1SGregory Neil Shapiro 
4750*d39bd2c1SGregory Neil Shapiro 	  case EX_NOHOST:
4751*d39bd2c1SGregory Neil Shapiro 		return "5.1.2";
4752*d39bd2c1SGregory Neil Shapiro 		break;
4753*d39bd2c1SGregory Neil Shapiro 
4754*d39bd2c1SGregory Neil Shapiro 	  case EX_NOINPUT:
4755*d39bd2c1SGregory Neil Shapiro 	  case EX_CANTCREAT:
4756*d39bd2c1SGregory Neil Shapiro 	  case EX_NOPERM:
4757*d39bd2c1SGregory Neil Shapiro 		return "5.3.0";
4758*d39bd2c1SGregory Neil Shapiro 		break;
4759*d39bd2c1SGregory Neil Shapiro 
4760*d39bd2c1SGregory Neil Shapiro 	  case EX_UNAVAILABLE:
4761*d39bd2c1SGregory Neil Shapiro 	  case EX_SOFTWARE:
4762*d39bd2c1SGregory Neil Shapiro 	  case EX_OSFILE:
4763*d39bd2c1SGregory Neil Shapiro 	  case EX_PROTOCOL:
4764*d39bd2c1SGregory Neil Shapiro 	  case EX_CONFIG:
4765*d39bd2c1SGregory Neil Shapiro 		return "5.5.0";
4766*d39bd2c1SGregory Neil Shapiro 		break;
4767*d39bd2c1SGregory Neil Shapiro 
4768*d39bd2c1SGregory Neil Shapiro 	  case EX_OSERR:
4769*d39bd2c1SGregory Neil Shapiro 	  case EX_IOERR:
4770*d39bd2c1SGregory Neil Shapiro 		return "4.5.0";
4771*d39bd2c1SGregory Neil Shapiro 		break;
4772*d39bd2c1SGregory Neil Shapiro 
4773*d39bd2c1SGregory Neil Shapiro 	  case EX_TEMPFAIL:
4774*d39bd2c1SGregory Neil Shapiro 		return "4.2.0";
4775*d39bd2c1SGregory Neil Shapiro 		break;
4776*d39bd2c1SGregory Neil Shapiro 	}
4777*d39bd2c1SGregory Neil Shapiro 	return NULL;
4778*d39bd2c1SGregory Neil Shapiro }
4779*d39bd2c1SGregory Neil Shapiro 
4780*d39bd2c1SGregory Neil Shapiro /*
4781c2aa98e2SPeter Wemm **  MARKFAILURE -- mark a failure on a specific address.
4782c2aa98e2SPeter Wemm **
4783c2aa98e2SPeter Wemm **	Parameters:
4784c2aa98e2SPeter Wemm **		e -- the envelope we are sending.
4785c2aa98e2SPeter Wemm **		q -- the address to mark.
4786c2aa98e2SPeter Wemm **		mci -- mailer connection information.
4787c2aa98e2SPeter Wemm **		rcode -- the code signifying the particular failure.
478806f25ae9SGregory Neil Shapiro **		ovr -- override an existing code?
4789c2aa98e2SPeter Wemm **
4790c2aa98e2SPeter Wemm **	Returns:
4791c2aa98e2SPeter Wemm **		none.
4792c2aa98e2SPeter Wemm **
4793c2aa98e2SPeter Wemm **	Side Effects:
4794c2aa98e2SPeter Wemm **		marks the address (and possibly the envelope) with the
4795c2aa98e2SPeter Wemm **			failure so that an error will be returned or
4796c2aa98e2SPeter Wemm **			the message will be queued, as appropriate.
4797c2aa98e2SPeter Wemm */
4798c2aa98e2SPeter Wemm 
479940266059SGregory Neil Shapiro void
markfailure(e,q,mci,rcode,ovr)480006f25ae9SGregory Neil Shapiro markfailure(e, q, mci, rcode, ovr)
4801c2aa98e2SPeter Wemm 	register ENVELOPE *e;
4802c2aa98e2SPeter Wemm 	register ADDRESS *q;
4803c2aa98e2SPeter Wemm 	register MCI *mci;
4804c2aa98e2SPeter Wemm 	int rcode;
480506f25ae9SGregory Neil Shapiro 	bool ovr;
4806c2aa98e2SPeter Wemm {
480740266059SGregory Neil Shapiro 	int save_errno = errno;
480806f25ae9SGregory Neil Shapiro 	char *status = NULL;
480906f25ae9SGregory Neil Shapiro 	char *rstatus = NULL;
4810c2aa98e2SPeter Wemm 
4811c2aa98e2SPeter Wemm 	switch (rcode)
4812c2aa98e2SPeter Wemm 	{
4813c2aa98e2SPeter Wemm 	  case EX_OK:
4814c2aa98e2SPeter Wemm 		break;
4815c2aa98e2SPeter Wemm 
4816c2aa98e2SPeter Wemm 	  case EX_TEMPFAIL:
4817c2aa98e2SPeter Wemm 	  case EX_IOERR:
4818c2aa98e2SPeter Wemm 	  case EX_OSERR:
481906f25ae9SGregory Neil Shapiro 		q->q_state = QS_QUEUEUP;
4820c2aa98e2SPeter Wemm 		break;
4821c2aa98e2SPeter Wemm 
4822c2aa98e2SPeter Wemm 	  default:
482306f25ae9SGregory Neil Shapiro 		q->q_state = QS_BADADDR;
4824c2aa98e2SPeter Wemm 		break;
4825c2aa98e2SPeter Wemm 	}
4826c2aa98e2SPeter Wemm 
4827c2aa98e2SPeter Wemm 	/* find most specific error code possible */
4828c2aa98e2SPeter Wemm 	if (mci != NULL && mci->mci_status != NULL)
4829c2aa98e2SPeter Wemm 	{
483040266059SGregory Neil Shapiro 		status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status);
4831c2aa98e2SPeter Wemm 		if (mci->mci_rstatus != NULL)
483240266059SGregory Neil Shapiro 			rstatus = sm_rpool_strdup_x(e->e_rpool,
483340266059SGregory Neil Shapiro 						    mci->mci_rstatus);
4834c2aa98e2SPeter Wemm 	}
4835c2aa98e2SPeter Wemm 	else if (e->e_status != NULL)
483606f25ae9SGregory Neil Shapiro 		status = e->e_status;
4837c2aa98e2SPeter Wemm 	else
4838*d39bd2c1SGregory Neil Shapiro 		status = ex2enhsc(rcode);
4839c2aa98e2SPeter Wemm 
484006f25ae9SGregory Neil Shapiro 	/* new status? */
484106f25ae9SGregory Neil Shapiro 	if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL ||
484206f25ae9SGregory Neil Shapiro 	    *q->q_status == '\0' || *q->q_status < *status))
484306f25ae9SGregory Neil Shapiro 	{
484406f25ae9SGregory Neil Shapiro 		q->q_status = status;
484506f25ae9SGregory Neil Shapiro 		q->q_rstatus = rstatus;
484606f25ae9SGregory Neil Shapiro 	}
4847c2aa98e2SPeter Wemm 	if (rcode != EX_OK && q->q_rstatus == NULL &&
4848c2aa98e2SPeter Wemm 	    q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL &&
48492fb4f839SGregory Neil Shapiro 	    SM_STRCASEEQ(q->q_mailer->m_diagtype, "X-UNIX"))
4850c2aa98e2SPeter Wemm 	{
485106f25ae9SGregory Neil Shapiro 		char buf[16];
4852c2aa98e2SPeter Wemm 
4853d0cef73dSGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "%d", rcode);
485440266059SGregory Neil Shapiro 		q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf);
4855c2aa98e2SPeter Wemm 	}
485606f25ae9SGregory Neil Shapiro 
485706f25ae9SGregory Neil Shapiro 	q->q_statdate = curtime();
485806f25ae9SGregory Neil Shapiro 	if (CurHostName != NULL && CurHostName[0] != '\0' &&
485906f25ae9SGregory Neil Shapiro 	    mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags))
486040266059SGregory Neil Shapiro 		q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName);
486140266059SGregory Neil Shapiro 
486240266059SGregory Neil Shapiro 	/* restore errno */
486340266059SGregory Neil Shapiro 	errno = save_errno;
4864c2aa98e2SPeter Wemm }
486540266059SGregory Neil Shapiro /*
4866c2aa98e2SPeter Wemm **  ENDMAILER -- Wait for mailer to terminate.
4867c2aa98e2SPeter Wemm **
4868c2aa98e2SPeter Wemm **	We should never get fatal errors (e.g., segmentation
4869c2aa98e2SPeter Wemm **	violation), so we report those specially.  For other
4870c2aa98e2SPeter Wemm **	errors, we choose a status message (into statmsg),
4871c2aa98e2SPeter Wemm **	and if it represents an error, we print it.
4872c2aa98e2SPeter Wemm **
4873c2aa98e2SPeter Wemm **	Parameters:
487413058a91SGregory Neil Shapiro **		mci -- the mailer connection info.
4875c2aa98e2SPeter Wemm **		e -- the current envelope.
4876c2aa98e2SPeter Wemm **		pv -- the parameter vector that invoked the mailer
4877c2aa98e2SPeter Wemm **			(for error messages).
4878c2aa98e2SPeter Wemm **
4879c2aa98e2SPeter Wemm **	Returns:
4880c2aa98e2SPeter Wemm **		exit code of mailer.
4881c2aa98e2SPeter Wemm **
4882c2aa98e2SPeter Wemm **	Side Effects:
4883c2aa98e2SPeter Wemm **		none.
4884c2aa98e2SPeter Wemm */
4885c2aa98e2SPeter Wemm 
488606f25ae9SGregory Neil Shapiro static jmp_buf	EndWaitTimeout;
488706f25ae9SGregory Neil Shapiro 
488806f25ae9SGregory Neil Shapiro static void
endwaittimeout(ignore)4889b6bacd31SGregory Neil Shapiro endwaittimeout(ignore)
4890b6bacd31SGregory Neil Shapiro 	int ignore;
489106f25ae9SGregory Neil Shapiro {
48928774250cSGregory Neil Shapiro 	/*
48938774250cSGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
48948774250cSGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
48958774250cSGregory Neil Shapiro 	**	DOING.
48968774250cSGregory Neil Shapiro 	*/
48978774250cSGregory Neil Shapiro 
489806f25ae9SGregory Neil Shapiro 	errno = ETIMEDOUT;
489906f25ae9SGregory Neil Shapiro 	longjmp(EndWaitTimeout, 1);
490006f25ae9SGregory Neil Shapiro }
490106f25ae9SGregory Neil Shapiro 
4902c2aa98e2SPeter Wemm int
endmailer(mci,e,pv)4903c2aa98e2SPeter Wemm endmailer(mci, e, pv)
4904c2aa98e2SPeter Wemm 	register MCI *mci;
4905c2aa98e2SPeter Wemm 	register ENVELOPE *e;
4906c2aa98e2SPeter Wemm 	char **pv;
4907c2aa98e2SPeter Wemm {
4908c2aa98e2SPeter Wemm 	int st;
490906f25ae9SGregory Neil Shapiro 	int save_errno = errno;
491006f25ae9SGregory Neil Shapiro 	char buf[MAXLINE];
491140266059SGregory Neil Shapiro 	SM_EVENT *ev = NULL;
491206f25ae9SGregory Neil Shapiro 
4913c2aa98e2SPeter Wemm 
4914c2aa98e2SPeter Wemm 	mci_unlock_host(mci);
4915c2aa98e2SPeter Wemm 
49168774250cSGregory Neil Shapiro 	/* close output to mailer */
49172fb4f839SGregory Neil Shapiro 	SM_CLOSE_FP(mci->mci_out);
49188774250cSGregory Neil Shapiro 
49198774250cSGregory Neil Shapiro 	/* copy any remaining input to transcript */
49208774250cSGregory Neil Shapiro 	if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR &&
49218774250cSGregory Neil Shapiro 	    e->e_xfp != NULL)
49228774250cSGregory Neil Shapiro 	{
4923d0cef73dSGregory Neil Shapiro 		while (sfgets(buf, sizeof(buf), mci->mci_in,
49248774250cSGregory Neil Shapiro 			      TimeOuts.to_quit, "Draining Input") != NULL)
492540266059SGregory Neil Shapiro 			(void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf);
49268774250cSGregory Neil Shapiro 	}
49278774250cSGregory Neil Shapiro 
492806f25ae9SGregory Neil Shapiro #if SASL
492940266059SGregory Neil Shapiro 	/* close SASL connection */
493006f25ae9SGregory Neil Shapiro 	if (bitset(MCIF_AUTHACT, mci->mci_flags))
493106f25ae9SGregory Neil Shapiro 	{
493206f25ae9SGregory Neil Shapiro 		sasl_dispose(&mci->mci_conn);
493306f25ae9SGregory Neil Shapiro 		mci->mci_flags &= ~MCIF_AUTHACT;
493406f25ae9SGregory Neil Shapiro 	}
493506f25ae9SGregory Neil Shapiro #endif /* SASL */
493606f25ae9SGregory Neil Shapiro 
493706f25ae9SGregory Neil Shapiro #if STARTTLS
493806f25ae9SGregory Neil Shapiro 	/* shutdown TLS */
493906f25ae9SGregory Neil Shapiro 	(void) endtlsclt(mci);
49405b0945b5SGregory Neil Shapiro #endif
494106f25ae9SGregory Neil Shapiro 
494206f25ae9SGregory Neil Shapiro 	/* now close the input */
49432fb4f839SGregory Neil Shapiro 	SM_CLOSE_FP(mci->mci_in);
4944c2aa98e2SPeter Wemm 	mci->mci_state = MCIS_CLOSED;
4945c2aa98e2SPeter Wemm 
494606f25ae9SGregory Neil Shapiro 	errno = save_errno;
494706f25ae9SGregory Neil Shapiro 
4948c2aa98e2SPeter Wemm 	/* in the IPC case there is nothing to wait for */
4949c2aa98e2SPeter Wemm 	if (mci->mci_pid == 0)
495006f25ae9SGregory Neil Shapiro 		return EX_OK;
4951c2aa98e2SPeter Wemm 
495206f25ae9SGregory Neil Shapiro 	/* put a timeout around the wait */
495306f25ae9SGregory Neil Shapiro 	if (mci->mci_mailer->m_wait > 0)
495406f25ae9SGregory Neil Shapiro 	{
495506f25ae9SGregory Neil Shapiro 		if (setjmp(EndWaitTimeout) == 0)
495640266059SGregory Neil Shapiro 			ev = sm_setevent(mci->mci_mailer->m_wait,
495706f25ae9SGregory Neil Shapiro 					 endwaittimeout, 0);
495806f25ae9SGregory Neil Shapiro 		else
495906f25ae9SGregory Neil Shapiro 		{
496042e5d165SGregory Neil Shapiro 			syserr("endmailer %s: wait timeout (%ld)",
496106f25ae9SGregory Neil Shapiro 			       mci->mci_mailer->m_name,
496242e5d165SGregory Neil Shapiro 			       (long) mci->mci_mailer->m_wait);
496306f25ae9SGregory Neil Shapiro 			return EX_TEMPFAIL;
496406f25ae9SGregory Neil Shapiro 		}
496506f25ae9SGregory Neil Shapiro 	}
4966c2aa98e2SPeter Wemm 
496706f25ae9SGregory Neil Shapiro 	/* wait for the mailer process, collect status */
4968c2aa98e2SPeter Wemm 	st = waitfor(mci->mci_pid);
496906f25ae9SGregory Neil Shapiro 	save_errno = errno;
497006f25ae9SGregory Neil Shapiro 	if (ev != NULL)
497140266059SGregory Neil Shapiro 		sm_clrevent(ev);
497206f25ae9SGregory Neil Shapiro 	errno = save_errno;
497306f25ae9SGregory Neil Shapiro 
4974c2aa98e2SPeter Wemm 	if (st == -1)
4975c2aa98e2SPeter Wemm 	{
4976c2aa98e2SPeter Wemm 		syserr("endmailer %s: wait", mci->mci_mailer->m_name);
497706f25ae9SGregory Neil Shapiro 		return EX_SOFTWARE;
4978c2aa98e2SPeter Wemm 	}
4979c2aa98e2SPeter Wemm 
4980c2aa98e2SPeter Wemm 	if (WIFEXITED(st))
4981c2aa98e2SPeter Wemm 	{
4982c2aa98e2SPeter Wemm 		/* normal death -- return status */
4983c2aa98e2SPeter Wemm 		return (WEXITSTATUS(st));
4984c2aa98e2SPeter Wemm 	}
4985c2aa98e2SPeter Wemm 
4986c2aa98e2SPeter Wemm 	/* it died a horrid death */
498706f25ae9SGregory Neil Shapiro 	syserr("451 4.3.0 mailer %s died with signal %d%s",
498806f25ae9SGregory Neil Shapiro 		mci->mci_mailer->m_name, WTERMSIG(st),
498906f25ae9SGregory Neil Shapiro 		WCOREDUMP(st) ? " (core dumped)" :
499006f25ae9SGregory Neil Shapiro 		(WIFSTOPPED(st) ? " (stopped)" : ""));
4991c2aa98e2SPeter Wemm 
4992c2aa98e2SPeter Wemm 	/* log the arguments */
4993c2aa98e2SPeter Wemm 	if (pv != NULL && e->e_xfp != NULL)
4994c2aa98e2SPeter Wemm 	{
4995c2aa98e2SPeter Wemm 		register char **av;
4996c2aa98e2SPeter Wemm 
499740266059SGregory Neil Shapiro 		(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:");
4998c2aa98e2SPeter Wemm 		for (av = pv; *av != NULL; av++)
499940266059SGregory Neil Shapiro 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s",
500040266059SGregory Neil Shapiro 					     *av);
500140266059SGregory Neil Shapiro 		(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n");
5002c2aa98e2SPeter Wemm 	}
5003c2aa98e2SPeter Wemm 
5004c2aa98e2SPeter Wemm 	ExitStat = EX_TEMPFAIL;
500506f25ae9SGregory Neil Shapiro 	return EX_TEMPFAIL;
5006c2aa98e2SPeter Wemm }
500740266059SGregory Neil Shapiro /*
5008c2aa98e2SPeter Wemm **  GIVERESPONSE -- Interpret an error response from a mailer
5009c2aa98e2SPeter Wemm **
5010c2aa98e2SPeter Wemm **	Parameters:
501106f25ae9SGregory Neil Shapiro **		status -- the status code from the mailer (high byte
5012c2aa98e2SPeter Wemm **			only; core dumps must have been taken care of
5013c2aa98e2SPeter Wemm **			already).
501406f25ae9SGregory Neil Shapiro **		dsn -- the DSN associated with the address, if any.
5015c2aa98e2SPeter Wemm **		m -- the mailer info for this mailer.
5016c2aa98e2SPeter Wemm **		mci -- the mailer connection info -- can be NULL if the
5017c2aa98e2SPeter Wemm **			response is given before the connection is made.
5018c2aa98e2SPeter Wemm **		ctladdr -- the controlling address for the recipient
5019c2aa98e2SPeter Wemm **			address(es).
5020c2aa98e2SPeter Wemm **		xstart -- the transaction start time, for computing
5021c2aa98e2SPeter Wemm **			transaction delays.
5022c2aa98e2SPeter Wemm **		e -- the current envelope.
502340266059SGregory Neil Shapiro **		to -- the current recipient (NULL if none).
5024c2aa98e2SPeter Wemm **
5025c2aa98e2SPeter Wemm **	Returns:
5026c2aa98e2SPeter Wemm **		none.
5027c2aa98e2SPeter Wemm **
5028c2aa98e2SPeter Wemm **	Side Effects:
5029c2aa98e2SPeter Wemm **		Errors may be incremented.
5030c2aa98e2SPeter Wemm **		ExitStat may be set.
5031c2aa98e2SPeter Wemm */
5032c2aa98e2SPeter Wemm 
5033c2aa98e2SPeter Wemm void
giveresponse(status,dsn,m,mci,ctladdr,xstart,e,to)503440266059SGregory Neil Shapiro giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
503506f25ae9SGregory Neil Shapiro 	int status;
503606f25ae9SGregory Neil Shapiro 	char *dsn;
5037c2aa98e2SPeter Wemm 	register MAILER *m;
5038c2aa98e2SPeter Wemm 	register MCI *mci;
5039c2aa98e2SPeter Wemm 	ADDRESS *ctladdr;
5040c2aa98e2SPeter Wemm 	time_t xstart;
5041c2aa98e2SPeter Wemm 	ENVELOPE *e;
504240266059SGregory Neil Shapiro 	ADDRESS *to;
5043c2aa98e2SPeter Wemm {
5044c2aa98e2SPeter Wemm 	register const char *statmsg;
504506f25ae9SGregory Neil Shapiro 	int errnum = errno;
504606f25ae9SGregory Neil Shapiro 	int off = 4;
504740266059SGregory Neil Shapiro 	bool usestat = false;
504806f25ae9SGregory Neil Shapiro 	char dsnbuf[ENHSCLEN];
5049c2aa98e2SPeter Wemm 	char buf[MAXLINE];
505040266059SGregory Neil Shapiro 	char *exmsg;
5051c2aa98e2SPeter Wemm 
5052c2aa98e2SPeter Wemm 	if (e == NULL)
5053af9557fdSGregory Neil Shapiro 	{
5054c2aa98e2SPeter Wemm 		syserr("giveresponse: null envelope");
5055af9557fdSGregory Neil Shapiro 		/* NOTREACHED */
5056af9557fdSGregory Neil Shapiro 		SM_ASSERT(0);
5057af9557fdSGregory Neil Shapiro 	}
5058c2aa98e2SPeter Wemm 
50592fb4f839SGregory Neil Shapiro 	if (tTd(11, 4))
5060*d39bd2c1SGregory Neil Shapiro 		sm_dprintf("giveresponse: status=%d, e->e_message=%s, dsn=%s, SmtpError=%s\n",
5061*d39bd2c1SGregory Neil Shapiro 			status, e->e_message, dsn, SmtpError);
50622fb4f839SGregory Neil Shapiro 
5063c2aa98e2SPeter Wemm 	/*
5064c2aa98e2SPeter Wemm 	**  Compute status message from code.
5065c2aa98e2SPeter Wemm 	*/
5066c2aa98e2SPeter Wemm 
506740266059SGregory Neil Shapiro 	exmsg = sm_sysexmsg(status);
506806f25ae9SGregory Neil Shapiro 	if (status == 0)
5069c2aa98e2SPeter Wemm 	{
507006f25ae9SGregory Neil Shapiro 		statmsg = "250 2.0.0 Sent";
5071c2aa98e2SPeter Wemm 		if (e->e_statmsg != NULL)
5072c2aa98e2SPeter Wemm 		{
5073d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof(buf), "%s (%s)",
507406f25ae9SGregory Neil Shapiro 					   statmsg,
507506f25ae9SGregory Neil Shapiro 					   shortenstring(e->e_statmsg, 403));
5076c2aa98e2SPeter Wemm 			statmsg = buf;
5077c2aa98e2SPeter Wemm 		}
5078c2aa98e2SPeter Wemm 	}
507940266059SGregory Neil Shapiro 	else if (exmsg == NULL)
5080c2aa98e2SPeter Wemm 	{
5081d0cef73dSGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf),
508206f25ae9SGregory Neil Shapiro 				   "554 5.3.0 unknown mailer error %d",
508306f25ae9SGregory Neil Shapiro 				   status);
508406f25ae9SGregory Neil Shapiro 		status = EX_UNAVAILABLE;
5085c2aa98e2SPeter Wemm 		statmsg = buf;
508640266059SGregory Neil Shapiro 		usestat = true;
5087c2aa98e2SPeter Wemm 	}
508806f25ae9SGregory Neil Shapiro 	else if (status == EX_TEMPFAIL)
5089c2aa98e2SPeter Wemm 	{
5090c2aa98e2SPeter Wemm 		char *bp = buf;
5091c2aa98e2SPeter Wemm 
509240266059SGregory Neil Shapiro 		(void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp));
5093c2aa98e2SPeter Wemm 		bp += strlen(bp);
5094c2aa98e2SPeter Wemm #if NAMED_BIND
5095c2aa98e2SPeter Wemm 		if (h_errno == TRY_AGAIN)
509640266059SGregory Neil Shapiro 			statmsg = sm_errstring(h_errno + E_DNSBASE);
5097c2aa98e2SPeter Wemm 		else
50982fb4f839SGregory Neil Shapiro #endif
5099c2aa98e2SPeter Wemm 		{
510006f25ae9SGregory Neil Shapiro 			if (errnum != 0)
510140266059SGregory Neil Shapiro 				statmsg = sm_errstring(errnum);
5102c2aa98e2SPeter Wemm 			else
5103c2aa98e2SPeter Wemm 				statmsg = SmtpError;
5104c2aa98e2SPeter Wemm 		}
5105c2aa98e2SPeter Wemm 		if (statmsg != NULL && statmsg[0] != '\0')
510606f25ae9SGregory Neil Shapiro 		{
510706f25ae9SGregory Neil Shapiro 			switch (errnum)
510806f25ae9SGregory Neil Shapiro 			{
510906f25ae9SGregory Neil Shapiro #ifdef ENETDOWN
511006f25ae9SGregory Neil Shapiro 			  case ENETDOWN:	/* Network is down */
51115b0945b5SGregory Neil Shapiro #endif
511206f25ae9SGregory Neil Shapiro #ifdef ENETUNREACH
511306f25ae9SGregory Neil Shapiro 			  case ENETUNREACH:	/* Network is unreachable */
51145b0945b5SGregory Neil Shapiro #endif
511506f25ae9SGregory Neil Shapiro #ifdef ENETRESET
511606f25ae9SGregory Neil Shapiro 			  case ENETRESET:	/* Network dropped connection on reset */
51175b0945b5SGregory Neil Shapiro #endif
511806f25ae9SGregory Neil Shapiro #ifdef ECONNABORTED
511906f25ae9SGregory Neil Shapiro 			  case ECONNABORTED:	/* Software caused connection abort */
51205b0945b5SGregory Neil Shapiro #endif
512106f25ae9SGregory Neil Shapiro #ifdef EHOSTDOWN
512206f25ae9SGregory Neil Shapiro 			  case EHOSTDOWN:	/* Host is down */
51235b0945b5SGregory Neil Shapiro #endif
512406f25ae9SGregory Neil Shapiro #ifdef EHOSTUNREACH
512506f25ae9SGregory Neil Shapiro 			  case EHOSTUNREACH:	/* No route to host */
51265b0945b5SGregory Neil Shapiro #endif
5127b6bacd31SGregory Neil Shapiro 				if (mci != NULL && mci->mci_host != NULL)
512806f25ae9SGregory Neil Shapiro 				{
512940266059SGregory Neil Shapiro 					(void) sm_strlcpyn(bp,
513040266059SGregory Neil Shapiro 							   SPACELEFT(buf, bp),
513140266059SGregory Neil Shapiro 							   2, ": ",
513240266059SGregory Neil Shapiro 							   mci->mci_host);
513306f25ae9SGregory Neil Shapiro 					bp += strlen(bp);
513406f25ae9SGregory Neil Shapiro 				}
513506f25ae9SGregory Neil Shapiro 				break;
513606f25ae9SGregory Neil Shapiro 			}
513740266059SGregory Neil Shapiro 			(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ",
513840266059SGregory Neil Shapiro 					   statmsg);
51395b0945b5SGregory Neil Shapiro #if DANE
51405b0945b5SGregory Neil Shapiro 			if (errnum == 0 && SmtpError[0] != '\0' &&
51415b0945b5SGregory Neil Shapiro 			    h_errno == TRY_AGAIN &&
51425b0945b5SGregory Neil Shapiro 			    mci->mci_exitstat == EX_TEMPFAIL)
51435b0945b5SGregory Neil Shapiro 			{
51445b0945b5SGregory Neil Shapiro 				(void) sm_strlcat(bp, SmtpError,
51455b0945b5SGregory Neil Shapiro 					SPACELEFT(buf, bp));
51465b0945b5SGregory Neil Shapiro 				bp += strlen(bp);
51475b0945b5SGregory Neil Shapiro 			}
51485b0945b5SGregory Neil Shapiro #endif /* DANE */
514940266059SGregory Neil Shapiro 			usestat = true;
515006f25ae9SGregory Neil Shapiro 		}
5151c2aa98e2SPeter Wemm 		statmsg = buf;
5152c2aa98e2SPeter Wemm 	}
5153c2aa98e2SPeter Wemm #if NAMED_BIND
515406f25ae9SGregory Neil Shapiro 	else if (status == EX_NOHOST && h_errno != 0)
5155c2aa98e2SPeter Wemm 	{
515640266059SGregory Neil Shapiro 		statmsg = sm_errstring(h_errno + E_DNSBASE);
5157d0cef73dSGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "%s (%s)", exmsg + 1,
515840266059SGregory Neil Shapiro 				   statmsg);
5159c2aa98e2SPeter Wemm 		statmsg = buf;
516040266059SGregory Neil Shapiro 		usestat = true;
5161c2aa98e2SPeter Wemm 	}
516206f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
51632fb4f839SGregory Neil Shapiro #if USE_EAI
51642fb4f839SGregory Neil Shapiro 	else if (errnum == 0 && status == EX_DATAERR
51652fb4f839SGregory Neil Shapiro 		&& e->e_message != NULL && e->e_message[0] != '\0')
51662fb4f839SGregory Neil Shapiro 	{
51672fb4f839SGregory Neil Shapiro 		int m;
51682fb4f839SGregory Neil Shapiro 
51692fb4f839SGregory Neil Shapiro 		/* XREF: 2nd arg must be coordinated with smtpmailfrom() */
51702fb4f839SGregory Neil Shapiro 		m = skipaddrhost(e->e_message, false);
51712fb4f839SGregory Neil Shapiro 
51722fb4f839SGregory Neil Shapiro 		/*
51732fb4f839SGregory Neil Shapiro 		**  XXX Why is the SMTP reply code needed here?
51742fb4f839SGregory Neil Shapiro 		**  How to avoid a hard-coded value?
51752fb4f839SGregory Neil Shapiro 		*/
51762fb4f839SGregory Neil Shapiro 
51772fb4f839SGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "550 %s", e->e_message + m);
51782fb4f839SGregory Neil Shapiro 		statmsg = buf;
51792fb4f839SGregory Neil Shapiro 		usestat = true;
51802fb4f839SGregory Neil Shapiro 	}
51812fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
5182c2aa98e2SPeter Wemm 	else
5183c2aa98e2SPeter Wemm 	{
518440266059SGregory Neil Shapiro 		statmsg = exmsg;
518506f25ae9SGregory Neil Shapiro 		if (*statmsg++ == ':' && errnum != 0)
5186c2aa98e2SPeter Wemm 		{
5187d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof(buf), "%s: %s", statmsg,
518840266059SGregory Neil Shapiro 					   sm_errstring(errnum));
5189c2aa98e2SPeter Wemm 			statmsg = buf;
519040266059SGregory Neil Shapiro 			usestat = true;
5191c2aa98e2SPeter Wemm 		}
5192605302a5SGregory Neil Shapiro 		else if (bitnset(M_LMTP, m->m_flags) && e->e_statmsg != NULL)
5193605302a5SGregory Neil Shapiro 		{
5194d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof(buf), "%s (%s)", statmsg,
5195605302a5SGregory Neil Shapiro 					   shortenstring(e->e_statmsg, 403));
5196605302a5SGregory Neil Shapiro 			statmsg = buf;
5197605302a5SGregory Neil Shapiro 			usestat = true;
5198605302a5SGregory Neil Shapiro 		}
5199c2aa98e2SPeter Wemm 	}
5200c2aa98e2SPeter Wemm 
5201c2aa98e2SPeter Wemm 	/*
5202c2aa98e2SPeter Wemm 	**  Print the message as appropriate
5203c2aa98e2SPeter Wemm 	*/
5204c2aa98e2SPeter Wemm 
520506f25ae9SGregory Neil Shapiro 	if (status == EX_OK || status == EX_TEMPFAIL)
5206c2aa98e2SPeter Wemm 	{
5207c2aa98e2SPeter Wemm 		extern char MsgBuf[];
5208c2aa98e2SPeter Wemm 
520906f25ae9SGregory Neil Shapiro 		if ((off = isenhsc(statmsg + 4, ' ')) > 0)
521006f25ae9SGregory Neil Shapiro 		{
521106f25ae9SGregory Neil Shapiro 			if (dsn == NULL)
521206f25ae9SGregory Neil Shapiro 			{
5213d0cef73dSGregory Neil Shapiro 				(void) sm_snprintf(dsnbuf, sizeof(dsnbuf),
521406f25ae9SGregory Neil Shapiro 						   "%.*s", off, statmsg + 4);
521506f25ae9SGregory Neil Shapiro 				dsn = dsnbuf;
521606f25ae9SGregory Neil Shapiro 			}
521706f25ae9SGregory Neil Shapiro 			off += 5;
521806f25ae9SGregory Neil Shapiro 		}
521906f25ae9SGregory Neil Shapiro 		else
522006f25ae9SGregory Neil Shapiro 		{
522106f25ae9SGregory Neil Shapiro 			off = 4;
522206f25ae9SGregory Neil Shapiro 		}
522306f25ae9SGregory Neil Shapiro 		message("%s", statmsg + off);
522406f25ae9SGregory Neil Shapiro 		if (status == EX_TEMPFAIL && e->e_xfp != NULL)
522540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n",
522640266059SGregory Neil Shapiro 					     &MsgBuf[4]);
5227c2aa98e2SPeter Wemm 	}
5228c2aa98e2SPeter Wemm 	else
5229c2aa98e2SPeter Wemm 	{
523006f25ae9SGregory Neil Shapiro 		char mbuf[ENHSCLEN + 4];
5231c2aa98e2SPeter Wemm 
5232c2aa98e2SPeter Wemm 		Errors++;
523306f25ae9SGregory Neil Shapiro 		if ((off = isenhsc(statmsg + 4, ' ')) > 0 &&
5234d0cef73dSGregory Neil Shapiro 		    off < sizeof(mbuf) - 4)
523506f25ae9SGregory Neil Shapiro 		{
523606f25ae9SGregory Neil Shapiro 			if (dsn == NULL)
523706f25ae9SGregory Neil Shapiro 			{
5238d0cef73dSGregory Neil Shapiro 				(void) sm_snprintf(dsnbuf, sizeof(dsnbuf),
523906f25ae9SGregory Neil Shapiro 						   "%.*s", off, statmsg + 4);
524006f25ae9SGregory Neil Shapiro 				dsn = dsnbuf;
524106f25ae9SGregory Neil Shapiro 			}
524206f25ae9SGregory Neil Shapiro 			off += 5;
524340266059SGregory Neil Shapiro 
524440266059SGregory Neil Shapiro 			/* copy only part of statmsg to mbuf */
524540266059SGregory Neil Shapiro 			(void) sm_strlcpy(mbuf, statmsg, off);
5246d0cef73dSGregory Neil Shapiro 			(void) sm_strlcat(mbuf, " %s", sizeof(mbuf));
524706f25ae9SGregory Neil Shapiro 		}
524806f25ae9SGregory Neil Shapiro 		else
524906f25ae9SGregory Neil Shapiro 		{
525006f25ae9SGregory Neil Shapiro 			dsnbuf[0] = '\0';
5251d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(mbuf, sizeof(mbuf), "%.3s %%s",
525240266059SGregory Neil Shapiro 					   statmsg);
525306f25ae9SGregory Neil Shapiro 			off = 4;
525406f25ae9SGregory Neil Shapiro 		}
525506f25ae9SGregory Neil Shapiro 		usrerr(mbuf, &statmsg[off]);
5256c2aa98e2SPeter Wemm 	}
5257c2aa98e2SPeter Wemm 
5258c2aa98e2SPeter Wemm 	/*
5259c2aa98e2SPeter Wemm 	**  Final cleanup.
5260da7d7b9cSGregory Neil Shapiro 	**	Log a record of the transaction.  Compute the new ExitStat
5261da7d7b9cSGregory Neil Shapiro 	**	-- if we already had an error, stick with that.
5262c2aa98e2SPeter Wemm 	*/
5263c2aa98e2SPeter Wemm 
5264c2aa98e2SPeter Wemm 	if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) &&
526506f25ae9SGregory Neil Shapiro 	    LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6))
5266da7d7b9cSGregory Neil Shapiro 		logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e, to, status);
5267c2aa98e2SPeter Wemm 
5268c2aa98e2SPeter Wemm 	if (tTd(11, 2))
52692fb4f839SGregory Neil Shapiro 		sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d, statmsg=%s\n",
527006f25ae9SGregory Neil Shapiro 			   status,
527106f25ae9SGregory Neil Shapiro 			   dsn == NULL ? "<NULL>" : dsn,
527240266059SGregory Neil Shapiro 			   e->e_message == NULL ? "<NULL>" : e->e_message,
52732fb4f839SGregory Neil Shapiro 			   errnum, statmsg);
5274c2aa98e2SPeter Wemm 
527506f25ae9SGregory Neil Shapiro 	if (status != EX_TEMPFAIL)
527606f25ae9SGregory Neil Shapiro 		setstat(status);
527706f25ae9SGregory Neil Shapiro 	if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL))
527840266059SGregory Neil Shapiro 		e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off);
527940266059SGregory Neil Shapiro 	if (status != EX_OK && to != NULL && to->q_message == NULL)
5280c2aa98e2SPeter Wemm 	{
528140266059SGregory Neil Shapiro 		if (!usestat && e->e_message != NULL)
528240266059SGregory Neil Shapiro 			to->q_message = sm_rpool_strdup_x(e->e_rpool,
528340266059SGregory Neil Shapiro 							  e->e_message);
528440266059SGregory Neil Shapiro 		else
528540266059SGregory Neil Shapiro 			to->q_message = sm_rpool_strdup_x(e->e_rpool,
528640266059SGregory Neil Shapiro 							  statmsg + off);
5287c2aa98e2SPeter Wemm 	}
5288c2aa98e2SPeter Wemm 	errno = 0;
5289602a2b1bSGregory Neil Shapiro 	SM_SET_H_ERRNO(0);
5290c2aa98e2SPeter Wemm }
5291*d39bd2c1SGregory Neil Shapiro 
5292*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
5293*d39bd2c1SGregory Neil Shapiro # define GET_HOST_VALUE	\
5294*d39bd2c1SGregory Neil Shapiro 	(void) dequote_internal_chars(p, xbuf, sizeof(xbuf));	\
5295*d39bd2c1SGregory Neil Shapiro 	p = xbuf;
5296*d39bd2c1SGregory Neil Shapiro #else
5297*d39bd2c1SGregory Neil Shapiro # define GET_HOST_VALUE
5298*d39bd2c1SGregory Neil Shapiro #endif
5299*d39bd2c1SGregory Neil Shapiro 
530040266059SGregory Neil Shapiro /*
5301c2aa98e2SPeter Wemm **  LOGDELIVERY -- log the delivery in the system log
5302c2aa98e2SPeter Wemm **
5303c2aa98e2SPeter Wemm **	Care is taken to avoid logging lines that are too long, because
5304c2aa98e2SPeter Wemm **	some versions of syslog have an unfortunate proclivity for core
5305c2aa98e2SPeter Wemm **	dumping.  This is a hack, to be sure, that is at best empirical.
5306c2aa98e2SPeter Wemm **
5307c2aa98e2SPeter Wemm **	Parameters:
5308c2aa98e2SPeter Wemm **		m -- the mailer info.  Can be NULL for initial queue.
5309c2aa98e2SPeter Wemm **		mci -- the mailer connection info -- can be NULL if the
531006f25ae9SGregory Neil Shapiro **			log is occurring when no connection is active.
531106f25ae9SGregory Neil Shapiro **		dsn -- the DSN attached to the status.
531206f25ae9SGregory Neil Shapiro **		status -- the message to print for the status.
5313c2aa98e2SPeter Wemm **		ctladdr -- the controlling address for the to list.
5314c2aa98e2SPeter Wemm **		xstart -- the transaction start time, used for
5315c2aa98e2SPeter Wemm **			computing transaction delay.
5316c2aa98e2SPeter Wemm **		e -- the current envelope.
5317da7d7b9cSGregory Neil Shapiro **		to -- the current recipient (NULL if none).
5318*d39bd2c1SGregory Neil Shapiro **		rcode -- status code.
5319c2aa98e2SPeter Wemm **
5320c2aa98e2SPeter Wemm **	Returns:
5321c2aa98e2SPeter Wemm **		none
5322c2aa98e2SPeter Wemm **
5323c2aa98e2SPeter Wemm **	Side Effects:
5324c2aa98e2SPeter Wemm **		none
5325c2aa98e2SPeter Wemm */
5326c2aa98e2SPeter Wemm 
5327c2aa98e2SPeter Wemm void
logdelivery(m,mci,dsn,status,ctladdr,xstart,e,to,rcode)5328da7d7b9cSGregory Neil Shapiro logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
5329c2aa98e2SPeter Wemm 	MAILER *m;
5330c2aa98e2SPeter Wemm 	register MCI *mci;
533106f25ae9SGregory Neil Shapiro 	char *dsn;
533206f25ae9SGregory Neil Shapiro 	const char *status;
5333c2aa98e2SPeter Wemm 	ADDRESS *ctladdr;
5334c2aa98e2SPeter Wemm 	time_t xstart;
5335c2aa98e2SPeter Wemm 	register ENVELOPE *e;
5336da7d7b9cSGregory Neil Shapiro 	ADDRESS *to;
5337da7d7b9cSGregory Neil Shapiro 	int rcode;
5338c2aa98e2SPeter Wemm {
5339c2aa98e2SPeter Wemm 	register char *bp;
5340c2aa98e2SPeter Wemm 	register char *p;
5341c2aa98e2SPeter Wemm 	int l;
534240266059SGregory Neil Shapiro 	time_t now = curtime();
5343c2aa98e2SPeter Wemm 	char buf[1024];
53442fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
53452fb4f839SGregory Neil Shapiro 	char xbuf[SM_MAX(SYSLOG_BUFSIZE, MAXNAME)];	/* EAI:ok */
53462fb4f839SGregory Neil Shapiro #endif
53472fb4f839SGregory Neil Shapiro 	char *xstr;
5348c2aa98e2SPeter Wemm 
5349c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
5350*d39bd2c1SGregory Neil Shapiro 	int xtype, rtype;
5351*d39bd2c1SGregory Neil Shapiro 
5352c2aa98e2SPeter Wemm 	/* ctladdr: max 106 bytes */
5353c2aa98e2SPeter Wemm 	bp = buf;
5354c2aa98e2SPeter Wemm 	if (ctladdr != NULL)
5355c2aa98e2SPeter Wemm 	{
535640266059SGregory Neil Shapiro 		(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=",
5357c2aa98e2SPeter Wemm 				   shortenstring(ctladdr->q_paddr, 83));
5358c2aa98e2SPeter Wemm 		bp += strlen(bp);
5359c2aa98e2SPeter Wemm 		if (bitset(QGOODUID, ctladdr->q_flags))
5360c2aa98e2SPeter Wemm 		{
536140266059SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
536206f25ae9SGregory Neil Shapiro 					   (int) ctladdr->q_uid,
536306f25ae9SGregory Neil Shapiro 					   (int) ctladdr->q_gid);
5364c2aa98e2SPeter Wemm 			bp += strlen(bp);
5365c2aa98e2SPeter Wemm 		}
5366c2aa98e2SPeter Wemm 	}
5367c2aa98e2SPeter Wemm 
5368c2aa98e2SPeter Wemm 	/* delay & xdelay: max 41 bytes */
536940266059SGregory Neil Shapiro 	(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=",
537040266059SGregory Neil Shapiro 			   pintvl(now - e->e_ctime, true));
5371c2aa98e2SPeter Wemm 	bp += strlen(bp);
5372c2aa98e2SPeter Wemm 
5373c2aa98e2SPeter Wemm 	if (xstart != (time_t) 0)
5374c2aa98e2SPeter Wemm 	{
537540266059SGregory Neil Shapiro 		(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=",
537640266059SGregory Neil Shapiro 				   pintvl(now - xstart, true));
5377c2aa98e2SPeter Wemm 		bp += strlen(bp);
5378c2aa98e2SPeter Wemm 	}
5379c2aa98e2SPeter Wemm 
5380c2aa98e2SPeter Wemm 	/* mailer: assume about 19 bytes (max 10 byte mailer name) */
5381c2aa98e2SPeter Wemm 	if (m != NULL)
5382c2aa98e2SPeter Wemm 	{
538340266059SGregory Neil Shapiro 		(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=",
538440266059SGregory Neil Shapiro 				   m->m_name);
5385c2aa98e2SPeter Wemm 		bp += strlen(bp);
5386c2aa98e2SPeter Wemm 	}
5387c2aa98e2SPeter Wemm 
5388da7d7b9cSGregory Neil Shapiro # if _FFR_LOG_MORE2
53895b0945b5SGregory Neil Shapiro 	LOG_MORE(buf, bp);
53905b0945b5SGregory Neil Shapiro # endif
5391da7d7b9cSGregory Neil Shapiro 
539206f25ae9SGregory Neil Shapiro 	/* pri: changes with each delivery attempt */
539340266059SGregory Neil Shapiro 	(void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld",
5394ba00ec3dSGregory Neil Shapiro 		PRT_NONNEGL(e->e_msgpriority));
539506f25ae9SGregory Neil Shapiro 	bp += strlen(bp);
539606f25ae9SGregory Neil Shapiro 
5397c2aa98e2SPeter Wemm 	/* relay: max 66 bytes for IPv4 addresses */
5398c2aa98e2SPeter Wemm 	if (mci != NULL && mci->mci_host != NULL)
5399c2aa98e2SPeter Wemm 	{
5400c2aa98e2SPeter Wemm 		extern SOCKADDR CurHostAddr;
5401c2aa98e2SPeter Wemm 
540240266059SGregory Neil Shapiro 		(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=",
5403c2aa98e2SPeter Wemm 				   shortenstring(mci->mci_host, 40));
5404c2aa98e2SPeter Wemm 		bp += strlen(bp);
5405c2aa98e2SPeter Wemm 
5406c2aa98e2SPeter Wemm 		if (CurHostAddr.sa.sa_family != 0)
5407c2aa98e2SPeter Wemm 		{
540840266059SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]",
5409c2aa98e2SPeter Wemm 					   anynet_ntoa(&CurHostAddr));
5410c2aa98e2SPeter Wemm 		}
5411c2aa98e2SPeter Wemm 	}
541240266059SGregory Neil Shapiro 	else if (strcmp(status, "quarantined") == 0)
541340266059SGregory Neil Shapiro 	{
541440266059SGregory Neil Shapiro 		if (e->e_quarmsg != NULL)
541540266059SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
541640266059SGregory Neil Shapiro 					   ", quarantine=%s",
541740266059SGregory Neil Shapiro 					   shortenstring(e->e_quarmsg, 40));
541840266059SGregory Neil Shapiro 	}
541906f25ae9SGregory Neil Shapiro 	else if (strcmp(status, "queued") != 0)
5420c2aa98e2SPeter Wemm 	{
5421c2aa98e2SPeter Wemm 		p = macvalue('h', e);
5422c2aa98e2SPeter Wemm 		if (p != NULL && p[0] != '\0')
5423c2aa98e2SPeter Wemm 		{
5424*d39bd2c1SGregory Neil Shapiro 			GET_HOST_VALUE;
542540266059SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
542640266059SGregory Neil Shapiro 					   ", relay=%s", shortenstring(p, 40));
5427c2aa98e2SPeter Wemm 		}
5428c2aa98e2SPeter Wemm 	}
5429c2aa98e2SPeter Wemm 	bp += strlen(bp);
5430c2aa98e2SPeter Wemm 
5431*d39bd2c1SGregory Neil Shapiro 	p = ex2enhsc(rcode);
5432*d39bd2c1SGregory Neil Shapiro 	if (p != NULL)
5433*d39bd2c1SGregory Neil Shapiro 		xtype = p[0] - '0';
5434*d39bd2c1SGregory Neil Shapiro 	else
5435*d39bd2c1SGregory Neil Shapiro 		xtype = 0;
5436*d39bd2c1SGregory Neil Shapiro 
5437*d39bd2c1SGregory Neil Shapiro #ifndef WHERE2REPORT
5438*d39bd2c1SGregory Neil Shapiro # define WHERE2REPORT "please see <https://sendmail.org/Report>, "
5439*d39bd2c1SGregory Neil Shapiro #endif
5440*d39bd2c1SGregory Neil Shapiro 
544106f25ae9SGregory Neil Shapiro 	/* dsn */
544206f25ae9SGregory Neil Shapiro 	if (dsn != NULL && *dsn != '\0')
544306f25ae9SGregory Neil Shapiro 	{
544440266059SGregory Neil Shapiro 		(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=",
544506f25ae9SGregory Neil Shapiro 				   shortenstring(dsn, ENHSCLEN));
544606f25ae9SGregory Neil Shapiro 		bp += strlen(bp);
5447*d39bd2c1SGregory Neil Shapiro 		if (xtype > 0 && ISSMTPCODE(dsn) &&
5448*d39bd2c1SGregory Neil Shapiro 		    (rtype = dsn[0] - '0') > 0 && rtype != xtype)
5449*d39bd2c1SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
5450*d39bd2c1SGregory Neil Shapiro 				"ERROR: inconsistent dsn, %srcode=%d, dsn=%s",
5451*d39bd2c1SGregory Neil Shapiro 				WHERE2REPORT, rcode, dsn);
545206f25ae9SGregory Neil Shapiro 	}
545306f25ae9SGregory Neil Shapiro 
545413d88268SGregory Neil Shapiro # if _FFR_LOG_NTRIES
545513d88268SGregory Neil Shapiro 	/* ntries */
545613d88268SGregory Neil Shapiro 	if (e->e_ntries >= 0)
545713d88268SGregory Neil Shapiro 	{
545813d88268SGregory Neil Shapiro 		(void) sm_snprintf(bp, SPACELEFT(buf, bp),
545913d88268SGregory Neil Shapiro 				   ", ntries=%d", e->e_ntries + 1);
546013d88268SGregory Neil Shapiro 		bp += strlen(bp);
546113d88268SGregory Neil Shapiro 	}
546213d88268SGregory Neil Shapiro # endif /* _FFR_LOG_NTRIES */
546313d88268SGregory Neil Shapiro 
5464c2aa98e2SPeter Wemm # define STATLEN		(((SYSLOG_BUFSIZE) - 100) / 4)
5465c2aa98e2SPeter Wemm # if (STATLEN) < 63
5466c2aa98e2SPeter Wemm #  undef STATLEN
5467c2aa98e2SPeter Wemm #  define STATLEN	63
54682fb4f839SGregory Neil Shapiro # endif
5469c2aa98e2SPeter Wemm # if (STATLEN) > 203
5470c2aa98e2SPeter Wemm #  undef STATLEN
5471c2aa98e2SPeter Wemm #  define STATLEN	203
54722fb4f839SGregory Neil Shapiro # endif
5473c2aa98e2SPeter Wemm 
5474*d39bd2c1SGregory Neil Shapiro # if _FFR_LOG_STAGE
5475*d39bd2c1SGregory Neil Shapiro 	/* only do this when reply= is logged? */
5476*d39bd2c1SGregory Neil Shapiro 	if (rcode != EX_OK && e->e_estate >= 0)
5477*d39bd2c1SGregory Neil Shapiro 	{
5478*d39bd2c1SGregory Neil Shapiro 		if (e->e_estate >= 0 && e->e_estate < SM_ARRAY_SIZE(xs_states))
5479*d39bd2c1SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
5480*d39bd2c1SGregory Neil Shapiro 				", stage=%s", xs_states[e->e_estate]);
5481*d39bd2c1SGregory Neil Shapiro 		else
5482*d39bd2c1SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
5483*d39bd2c1SGregory Neil Shapiro 				", stage=%d", e->e_estate);
5484*d39bd2c1SGregory Neil Shapiro 		bp += strlen(bp);
5485*d39bd2c1SGregory Neil Shapiro 	}
5486*d39bd2c1SGregory Neil Shapiro # endif /* _FFR_LOG_STAGE */
5487*d39bd2c1SGregory Neil Shapiro 
5488da7d7b9cSGregory Neil Shapiro 	/*
5489da7d7b9cSGregory Neil Shapiro 	**  Notes:
5490da7d7b9cSGregory Neil Shapiro 	**  per-rcpt status: to->q_rstatus
5491da7d7b9cSGregory Neil Shapiro 	**  global status: e->e_text
5492da7d7b9cSGregory Neil Shapiro 	**
5493da7d7b9cSGregory Neil Shapiro 	**  We (re)use STATLEN here, is that a good choice?
5494da7d7b9cSGregory Neil Shapiro 	**
5495da7d7b9cSGregory Neil Shapiro 	**  stat=Deferred: ...
5496da7d7b9cSGregory Neil Shapiro 	**  has sometimes the same text?
5497da7d7b9cSGregory Neil Shapiro 	**
54985b0945b5SGregory Neil Shapiro 	**  Note: in some case the normal logging might show the same server
54995b0945b5SGregory Neil Shapiro 	**  reply - how to avoid that?
5500da7d7b9cSGregory Neil Shapiro 	*/
5501da7d7b9cSGregory Neil Shapiro 
55022fb4f839SGregory Neil Shapiro 	/* only show errors from server */
5503*d39bd2c1SGregory Neil Shapiro 	if (rcode != EX_OK && (NULL == to || !bitset(QINTREPLY, to->q_flags)))
5504*d39bd2c1SGregory Neil Shapiro 	{
5505*d39bd2c1SGregory Neil Shapiro 		if (to != NULL && !SM_IS_EMPTY(to->q_rstatus))
5506da7d7b9cSGregory Neil Shapiro 		{
5507da7d7b9cSGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
5508da7d7b9cSGregory Neil Shapiro 				", reply=%s",
5509da7d7b9cSGregory Neil Shapiro 				shortenstring(to->q_rstatus, STATLEN));
5510da7d7b9cSGregory Neil Shapiro 			bp += strlen(bp);
5511*d39bd2c1SGregory Neil Shapiro 			if (ISSMTPCODE(to->q_rstatus) &&
5512*d39bd2c1SGregory Neil Shapiro 			    (rtype = to->q_rstatus[0] - '0') > 0 &&
5513*d39bd2c1SGregory Neil Shapiro 			    ((xtype > 0 && rtype != xtype) || rtype < 4))
5514*d39bd2c1SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
5515*d39bd2c1SGregory Neil Shapiro 					"ERROR: inconsistent reply, %srcode=%d, q_rstatus=%s",
5516*d39bd2c1SGregory Neil Shapiro 					WHERE2REPORT, rcode, to->q_rstatus);
5517da7d7b9cSGregory Neil Shapiro 		}
5518*d39bd2c1SGregory Neil Shapiro 		else if (e->e_text != NULL)
5519da7d7b9cSGregory Neil Shapiro 		{
5520da7d7b9cSGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
5521da7d7b9cSGregory Neil Shapiro 				", reply=%d %s%s%s",
5522da7d7b9cSGregory Neil Shapiro 				e->e_rcode,
5523da7d7b9cSGregory Neil Shapiro 				e->e_renhsc,
5524da7d7b9cSGregory Neil Shapiro 				(e->e_renhsc[0] != '\0') ? " " : "",
5525da7d7b9cSGregory Neil Shapiro 				shortenstring(e->e_text, STATLEN));
5526da7d7b9cSGregory Neil Shapiro 			bp += strlen(bp);
5527*d39bd2c1SGregory Neil Shapiro 			rtype = REPLYTYPE(e->e_rcode);
5528*d39bd2c1SGregory Neil Shapiro 			if (rtype > 0 &&
5529*d39bd2c1SGregory Neil Shapiro 			    ((xtype > 0 && rtype != xtype) || rtype < 4))
5530*d39bd2c1SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
5531*d39bd2c1SGregory Neil Shapiro 					"ERROR: inconsistent reply, %srcode=%d, e_rcode=%d, e_text=%s",
5532*d39bd2c1SGregory Neil Shapiro 					WHERE2REPORT, rcode, e->e_rcode, e->e_text);
5533da7d7b9cSGregory Neil Shapiro 		}
55342fb4f839SGregory Neil Shapiro #if _FFR_NULLMX_STATUS
55352fb4f839SGregory Neil Shapiro 		/* Hack for MX 0 . : how to make this general? */
5536*d39bd2c1SGregory Neil Shapiro 		else if (NULL == to && dsn != NULL &&
55372fb4f839SGregory Neil Shapiro 			 strcmp(dsn, ESCNULLMXRCPT) == 0)
55382fb4f839SGregory Neil Shapiro 		{
55392fb4f839SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
55402fb4f839SGregory Neil Shapiro 				", status=%s", ERRNULLMX);
55412fb4f839SGregory Neil Shapiro 			bp += strlen(bp);
55422fb4f839SGregory Neil Shapiro 		}
55432fb4f839SGregory Neil Shapiro #endif
5544*d39bd2c1SGregory Neil Shapiro 	}
5545da7d7b9cSGregory Neil Shapiro 
5546c2aa98e2SPeter Wemm 	/* stat: max 210 bytes */
5547d0cef73dSGregory Neil Shapiro 	if ((bp - buf) > (sizeof(buf) - ((STATLEN) + 20)))
5548c2aa98e2SPeter Wemm 	{
5549c2aa98e2SPeter Wemm 		/* desperation move -- truncate data */
5550d0cef73dSGregory Neil Shapiro 		bp = buf + sizeof(buf) - ((STATLEN) + 17);
555140266059SGregory Neil Shapiro 		(void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp));
5552c2aa98e2SPeter Wemm 		bp += 3;
5553c2aa98e2SPeter Wemm 	}
5554c2aa98e2SPeter Wemm 
555540266059SGregory Neil Shapiro 	(void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp));
5556c2aa98e2SPeter Wemm 	bp += strlen(bp);
5557c2aa98e2SPeter Wemm 
555840266059SGregory Neil Shapiro 	(void) sm_strlcpy(bp, shortenstring(status, STATLEN),
555940266059SGregory Neil Shapiro 			  SPACELEFT(buf, bp));
5560c2aa98e2SPeter Wemm 
5561c2aa98e2SPeter Wemm 	/* id, to: max 13 + TOBUFSIZE bytes */
5562c2aa98e2SPeter Wemm 	l = SYSLOG_BUFSIZE - 100 - strlen(buf);
556340266059SGregory Neil Shapiro 	if (l < 0)
556440266059SGregory Neil Shapiro 		l = 0;
556506f25ae9SGregory Neil Shapiro 	p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
556640266059SGregory Neil Shapiro 	while (strlen(p) >= l)
5567c2aa98e2SPeter Wemm 	{
556806f25ae9SGregory Neil Shapiro 		register char *q;
5569c2aa98e2SPeter Wemm 
557006f25ae9SGregory Neil Shapiro 		for (q = p + l; q > p; q--)
557106f25ae9SGregory Neil Shapiro 		{
5572da7d7b9cSGregory Neil Shapiro 			/* XXX a comma in an address will break this! */
557306f25ae9SGregory Neil Shapiro 			if (*q == ',')
557406f25ae9SGregory Neil Shapiro 				break;
557506f25ae9SGregory Neil Shapiro 		}
557606f25ae9SGregory Neil Shapiro 		if (p == q)
557706f25ae9SGregory Neil Shapiro 			break;
55782fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
55792fb4f839SGregory Neil Shapiro 		/* XXX is this correct? dequote all of p? */
55802fb4f839SGregory Neil Shapiro 		(void) dequote_internal_chars(p, xbuf, sizeof(xbuf));
55812fb4f839SGregory Neil Shapiro 		xstr = xbuf;
55822fb4f839SGregory Neil Shapiro # else
55832fb4f839SGregory Neil Shapiro 		xstr = p;
55842fb4f839SGregory Neil Shapiro # endif
558540266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s",
55862fb4f839SGregory Neil Shapiro 			  (int) (++q - p), xstr, buf);
5587c2aa98e2SPeter Wemm 		p = q;
5588c2aa98e2SPeter Wemm 	}
55892fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
55902fb4f839SGregory Neil Shapiro 	(void) dequote_internal_chars(p, xbuf, sizeof(xbuf));
55912fb4f839SGregory Neil Shapiro 	xstr = xbuf;
55922fb4f839SGregory Neil Shapiro # else
55932fb4f839SGregory Neil Shapiro 	xstr = p;
55942fb4f839SGregory Neil Shapiro # endif
55952fb4f839SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, xstr, buf);
5596c2aa98e2SPeter Wemm 
559706f25ae9SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
5598c2aa98e2SPeter Wemm 
5599c2aa98e2SPeter Wemm 	l = SYSLOG_BUFSIZE - 85;
560040266059SGregory Neil Shapiro 	if (l < 0)
560140266059SGregory Neil Shapiro 		l = 0;
560206f25ae9SGregory Neil Shapiro 	p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
560340266059SGregory Neil Shapiro 	while (strlen(p) >= l)
5604c2aa98e2SPeter Wemm 	{
560506f25ae9SGregory Neil Shapiro 		register char *q;
5606c2aa98e2SPeter Wemm 
560706f25ae9SGregory Neil Shapiro 		for (q = p + l; q > p; q--)
560806f25ae9SGregory Neil Shapiro 		{
560906f25ae9SGregory Neil Shapiro 			if (*q == ',')
561006f25ae9SGregory Neil Shapiro 				break;
561106f25ae9SGregory Neil Shapiro 		}
561206f25ae9SGregory Neil Shapiro 		if (p == q)
561306f25ae9SGregory Neil Shapiro 			break;
561406f25ae9SGregory Neil Shapiro 
561540266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]",
561642e5d165SGregory Neil Shapiro 			  (int) (++q - p), p);
5617c2aa98e2SPeter Wemm 		p = q;
5618c2aa98e2SPeter Wemm 	}
561906f25ae9SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p);
5620c2aa98e2SPeter Wemm 
5621c2aa98e2SPeter Wemm 	if (ctladdr != NULL)
5622c2aa98e2SPeter Wemm 	{
5623c2aa98e2SPeter Wemm 		bp = buf;
562440266059SGregory Neil Shapiro 		(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=",
5625c2aa98e2SPeter Wemm 				   shortenstring(ctladdr->q_paddr, 83));
5626c2aa98e2SPeter Wemm 		bp += strlen(bp);
5627c2aa98e2SPeter Wemm 		if (bitset(QGOODUID, ctladdr->q_flags))
5628c2aa98e2SPeter Wemm 		{
562940266059SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
5630c2aa98e2SPeter Wemm 					   ctladdr->q_uid, ctladdr->q_gid);
5631c2aa98e2SPeter Wemm 			bp += strlen(bp);
5632c2aa98e2SPeter Wemm 		}
5633c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id, "%s", buf);
5634c2aa98e2SPeter Wemm 	}
5635c2aa98e2SPeter Wemm 	bp = buf;
563640266059SGregory Neil Shapiro 	(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=",
563740266059SGregory Neil Shapiro 			   pintvl(now - e->e_ctime, true));
5638c2aa98e2SPeter Wemm 	bp += strlen(bp);
5639c2aa98e2SPeter Wemm 	if (xstart != (time_t) 0)
5640c2aa98e2SPeter Wemm 	{
564140266059SGregory Neil Shapiro 		(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=",
564240266059SGregory Neil Shapiro 				   pintvl(now - xstart, true));
5643c2aa98e2SPeter Wemm 		bp += strlen(bp);
5644c2aa98e2SPeter Wemm 	}
5645c2aa98e2SPeter Wemm 
5646c2aa98e2SPeter Wemm 	if (m != NULL)
5647c2aa98e2SPeter Wemm 	{
564840266059SGregory Neil Shapiro 		(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=",
564940266059SGregory Neil Shapiro 				   m->m_name);
5650c2aa98e2SPeter Wemm 		bp += strlen(bp);
5651c2aa98e2SPeter Wemm 	}
5652c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
5653c2aa98e2SPeter Wemm 
5654c2aa98e2SPeter Wemm 	buf[0] = '\0';
5655c2aa98e2SPeter Wemm 	bp = buf;
5656c2aa98e2SPeter Wemm 	if (mci != NULL && mci->mci_host != NULL)
5657c2aa98e2SPeter Wemm 	{
5658c2aa98e2SPeter Wemm 		extern SOCKADDR CurHostAddr;
5659c2aa98e2SPeter Wemm 
566040266059SGregory Neil Shapiro 		(void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s",
566140266059SGregory Neil Shapiro 				   mci->mci_host);
5662c2aa98e2SPeter Wemm 		bp += strlen(bp);
5663c2aa98e2SPeter Wemm 
5664c2aa98e2SPeter Wemm 		if (CurHostAddr.sa.sa_family != 0)
566540266059SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
566640266059SGregory Neil Shapiro 					   " [%.100s]",
5667c2aa98e2SPeter Wemm 					   anynet_ntoa(&CurHostAddr));
5668c2aa98e2SPeter Wemm 	}
566940266059SGregory Neil Shapiro 	else if (strcmp(status, "quarantined") == 0)
567040266059SGregory Neil Shapiro 	{
567140266059SGregory Neil Shapiro 		if (e->e_quarmsg != NULL)
567240266059SGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
567340266059SGregory Neil Shapiro 					   ", quarantine=%.100s",
567440266059SGregory Neil Shapiro 					   e->e_quarmsg);
567540266059SGregory Neil Shapiro 	}
567606f25ae9SGregory Neil Shapiro 	else if (strcmp(status, "queued") != 0)
5677c2aa98e2SPeter Wemm 	{
5678c2aa98e2SPeter Wemm 		p = macvalue('h', e);
5679c2aa98e2SPeter Wemm 		if (p != NULL && p[0] != '\0')
5680*d39bd2c1SGregory Neil Shapiro 		{
5681*d39bd2c1SGregory Neil Shapiro 			GET_HOST_VALUE;
5682d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof(buf), "relay=%.100s", p);
5683c2aa98e2SPeter Wemm 		}
5684*d39bd2c1SGregory Neil Shapiro 	}
5685c2aa98e2SPeter Wemm 	if (buf[0] != '\0')
5686c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
5687c2aa98e2SPeter Wemm 
568806f25ae9SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63));
568906f25ae9SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
5690c2aa98e2SPeter Wemm }
569140266059SGregory Neil Shapiro /*
5692c2aa98e2SPeter Wemm **  PUTFROMLINE -- output a UNIX-style from line (or whatever)
5693c2aa98e2SPeter Wemm **
5694c2aa98e2SPeter Wemm **	This can be made an arbitrary message separator by changing $l
5695c2aa98e2SPeter Wemm **
5696c2aa98e2SPeter Wemm **	One of the ugliest hacks seen by human eyes is contained herein:
5697c2aa98e2SPeter Wemm **	UUCP wants those stupid "remote from <host>" lines.  Why oh why
5698c2aa98e2SPeter Wemm **	does a well-meaning programmer such as myself have to deal with
5699c2aa98e2SPeter Wemm **	this kind of antique garbage????
5700c2aa98e2SPeter Wemm **
5701c2aa98e2SPeter Wemm **	Parameters:
5702c2aa98e2SPeter Wemm **		mci -- the connection information.
5703c2aa98e2SPeter Wemm **		e -- the envelope.
5704c2aa98e2SPeter Wemm **
5705c2aa98e2SPeter Wemm **	Returns:
57064e4196cbSGregory Neil Shapiro **		true iff line was written successfully
5707c2aa98e2SPeter Wemm **
5708c2aa98e2SPeter Wemm **	Side Effects:
5709c2aa98e2SPeter Wemm **		outputs some text to fp.
5710c2aa98e2SPeter Wemm */
5711c2aa98e2SPeter Wemm 
57124e4196cbSGregory Neil Shapiro bool
putfromline(mci,e)5713c2aa98e2SPeter Wemm putfromline(mci, e)
5714c2aa98e2SPeter Wemm 	register MCI *mci;
5715c2aa98e2SPeter Wemm 	ENVELOPE *e;
5716c2aa98e2SPeter Wemm {
5717c2aa98e2SPeter Wemm 	char *template = UnixFromLine;
5718c2aa98e2SPeter Wemm 	char buf[MAXLINE];
5719c2aa98e2SPeter Wemm 	char xbuf[MAXLINE];
5720c2aa98e2SPeter Wemm 
5721c2aa98e2SPeter Wemm 	if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
57224e4196cbSGregory Neil Shapiro 		return true;
5723c2aa98e2SPeter Wemm 
5724c2aa98e2SPeter Wemm 	mci->mci_flags |= MCIF_INHEADER;
5725c2aa98e2SPeter Wemm 
5726c2aa98e2SPeter Wemm 	if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags))
5727c2aa98e2SPeter Wemm 	{
5728c2aa98e2SPeter Wemm 		char *bang;
5729c2aa98e2SPeter Wemm 
5730d0cef73dSGregory Neil Shapiro 		expand("\201g", buf, sizeof(buf), e);
5731c2aa98e2SPeter Wemm 		bang = strchr(buf, '!');
5732c2aa98e2SPeter Wemm 		if (bang == NULL)
5733c2aa98e2SPeter Wemm 		{
5734c2aa98e2SPeter Wemm 			char *at;
57352fb4f839SGregory Neil Shapiro 			char hname[MAXNAME];	/* EAI:ok */
5736c2aa98e2SPeter Wemm 
5737c2aa98e2SPeter Wemm 			/*
5738c2aa98e2SPeter Wemm 			**  If we can construct a UUCP path, do so
5739c2aa98e2SPeter Wemm 			*/
5740c2aa98e2SPeter Wemm 
5741c2aa98e2SPeter Wemm 			at = strrchr(buf, '@');
5742c2aa98e2SPeter Wemm 			if (at == NULL)
5743c2aa98e2SPeter Wemm 			{
5744d0cef73dSGregory Neil Shapiro 				expand("\201k", hname, sizeof(hname), e);
5745c2aa98e2SPeter Wemm 				at = hname;
5746c2aa98e2SPeter Wemm 			}
5747c2aa98e2SPeter Wemm 			else
5748c2aa98e2SPeter Wemm 				*at++ = '\0';
5749d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(xbuf, sizeof(xbuf),
5750c2aa98e2SPeter Wemm 					   "From %.800s  \201d remote from %.100s\n",
5751c2aa98e2SPeter Wemm 					   buf, at);
5752c2aa98e2SPeter Wemm 		}
5753c2aa98e2SPeter Wemm 		else
5754c2aa98e2SPeter Wemm 		{
5755c2aa98e2SPeter Wemm 			*bang++ = '\0';
5756d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(xbuf, sizeof(xbuf),
5757c2aa98e2SPeter Wemm 					   "From %.800s  \201d remote from %.100s\n",
5758c2aa98e2SPeter Wemm 					   bang, buf);
5759c2aa98e2SPeter Wemm 			template = xbuf;
5760c2aa98e2SPeter Wemm 		}
5761c2aa98e2SPeter Wemm 	}
5762d0cef73dSGregory Neil Shapiro 	expand(template, buf, sizeof(buf), e);
57634e4196cbSGregory Neil Shapiro 	return putxline(buf, strlen(buf), mci, PXLF_HEADER);
5764c2aa98e2SPeter Wemm }
57654e4196cbSGregory Neil Shapiro 
576640266059SGregory Neil Shapiro /*
5767c2aa98e2SPeter Wemm **  PUTBODY -- put the body of a message.
5768c2aa98e2SPeter Wemm **
5769c2aa98e2SPeter Wemm **	Parameters:
5770c2aa98e2SPeter Wemm **		mci -- the connection information.
5771c2aa98e2SPeter Wemm **		e -- the envelope to put out.
5772c2aa98e2SPeter Wemm **		separator -- if non-NULL, a message separator that must
5773c2aa98e2SPeter Wemm **			not be permitted in the resulting message.
5774c2aa98e2SPeter Wemm **
5775c2aa98e2SPeter Wemm **	Returns:
57764e4196cbSGregory Neil Shapiro **		true iff message was written successfully
5777c2aa98e2SPeter Wemm **
5778c2aa98e2SPeter Wemm **	Side Effects:
5779c2aa98e2SPeter Wemm **		The message is written onto fp.
5780c2aa98e2SPeter Wemm */
5781c2aa98e2SPeter Wemm 
5782c2aa98e2SPeter Wemm /* values for output state variable */
57834e4196cbSGregory Neil Shapiro #define OSTATE_HEAD	0	/* at beginning of line */
57844e4196cbSGregory Neil Shapiro #define OSTATE_CR	1	/* read a carriage return */
57854e4196cbSGregory Neil Shapiro #define OSTATE_INLINE	2	/* putting rest of line */
5786c2aa98e2SPeter Wemm 
57874e4196cbSGregory Neil Shapiro bool
putbody(mci,e,separator)5788c2aa98e2SPeter Wemm putbody(mci, e, separator)
5789c2aa98e2SPeter Wemm 	register MCI *mci;
5790c2aa98e2SPeter Wemm 	register ENVELOPE *e;
5791c2aa98e2SPeter Wemm 	char *separator;
5792c2aa98e2SPeter Wemm {
579340266059SGregory Neil Shapiro 	bool dead = false;
57944e4196cbSGregory Neil Shapiro 	bool ioerr = false;
57954e4196cbSGregory Neil Shapiro 	int save_errno;
5796c2aa98e2SPeter Wemm 	char buf[MAXLINE];
579740266059SGregory Neil Shapiro #if MIME8TO7
5798065a643dSPeter Wemm 	char *boundaries[MAXMIMENESTING + 1];
57995b0945b5SGregory Neil Shapiro #endif
5800c2aa98e2SPeter Wemm 
5801c2aa98e2SPeter Wemm 	/*
5802c2aa98e2SPeter Wemm 	**  Output the body of the message
5803c2aa98e2SPeter Wemm 	*/
5804c2aa98e2SPeter Wemm 
5805c2aa98e2SPeter Wemm 	if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
5806c2aa98e2SPeter Wemm 	{
580740266059SGregory Neil Shapiro 		char *df = queuename(e, DATAFL_LETTER);
5808c2aa98e2SPeter Wemm 
580940266059SGregory Neil Shapiro 		e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df,
5810a7ec597cSGregory Neil Shapiro 				      SM_IO_RDONLY_B, NULL);
5811c2aa98e2SPeter Wemm 		if (e->e_dfp == NULL)
581206f25ae9SGregory Neil Shapiro 		{
581306f25ae9SGregory Neil Shapiro 			char *msg = "!putbody: Cannot open %s for %s from %s";
581406f25ae9SGregory Neil Shapiro 
581506f25ae9SGregory Neil Shapiro 			if (errno == ENOENT)
581606f25ae9SGregory Neil Shapiro 				msg++;
581706f25ae9SGregory Neil Shapiro 			syserr(msg, df, e->e_to, e->e_from.q_paddr);
581806f25ae9SGregory Neil Shapiro 		}
581940266059SGregory Neil Shapiro 
5820c2aa98e2SPeter Wemm 	}
5821c2aa98e2SPeter Wemm 	if (e->e_dfp == NULL)
5822c2aa98e2SPeter Wemm 	{
5823c2aa98e2SPeter Wemm 		if (bitset(MCIF_INHEADER, mci->mci_flags))
5824c2aa98e2SPeter Wemm 		{
58254e4196cbSGregory Neil Shapiro 			if (!putline("", mci))
58264e4196cbSGregory Neil Shapiro 				goto writeerr;
5827c2aa98e2SPeter Wemm 			mci->mci_flags &= ~MCIF_INHEADER;
5828c2aa98e2SPeter Wemm 		}
58294e4196cbSGregory Neil Shapiro 		if (!putline("<<< No Message Collected >>>", mci))
58304e4196cbSGregory Neil Shapiro 			goto writeerr;
5831c2aa98e2SPeter Wemm 		goto endofmessage;
5832c2aa98e2SPeter Wemm 	}
583306f25ae9SGregory Neil Shapiro 
5834c2aa98e2SPeter Wemm 	if (e->e_dfino == (ino_t) 0)
5835c2aa98e2SPeter Wemm 	{
5836c2aa98e2SPeter Wemm 		struct stat stbuf;
5837c2aa98e2SPeter Wemm 
583840266059SGregory Neil Shapiro 		if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf)
583940266059SGregory Neil Shapiro 		    < 0)
5840c2aa98e2SPeter Wemm 			e->e_dfino = -1;
5841c2aa98e2SPeter Wemm 		else
5842c2aa98e2SPeter Wemm 		{
5843c2aa98e2SPeter Wemm 			e->e_dfdev = stbuf.st_dev;
5844c2aa98e2SPeter Wemm 			e->e_dfino = stbuf.st_ino;
5845c2aa98e2SPeter Wemm 		}
5846c2aa98e2SPeter Wemm 	}
584706f25ae9SGregory Neil Shapiro 
584840266059SGregory Neil Shapiro 	/* paranoia: the data file should always be in a rewound state */
584906f25ae9SGregory Neil Shapiro 	(void) bfrewind(e->e_dfp);
5850c2aa98e2SPeter Wemm 
58514e4196cbSGregory Neil Shapiro 	/* simulate an I/O timeout when used as source */
58524e4196cbSGregory Neil Shapiro 	if (tTd(84, 101))
58534e4196cbSGregory Neil Shapiro 		sleep(319);
58544e4196cbSGregory Neil Shapiro 
5855c2aa98e2SPeter Wemm #if MIME8TO7
5856c2aa98e2SPeter Wemm 	if (bitset(MCIF_CVT8TO7, mci->mci_flags))
5857c2aa98e2SPeter Wemm 	{
5858c2aa98e2SPeter Wemm 		/*
5859c2aa98e2SPeter Wemm 		**  Do 8 to 7 bit MIME conversion.
5860c2aa98e2SPeter Wemm 		*/
5861c2aa98e2SPeter Wemm 
5862c2aa98e2SPeter Wemm 		/* make sure it looks like a MIME message */
58634e4196cbSGregory Neil Shapiro 		if (hvalue("MIME-Version", e->e_header) == NULL &&
58644e4196cbSGregory Neil Shapiro 		    !putline("MIME-Version: 1.0", mci))
58654e4196cbSGregory Neil Shapiro 			goto writeerr;
5866c2aa98e2SPeter Wemm 
5867c2aa98e2SPeter Wemm 		if (hvalue("Content-Type", e->e_header) == NULL)
5868c2aa98e2SPeter Wemm 		{
5869d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof(buf),
5870c2aa98e2SPeter Wemm 					   "Content-Type: text/plain; charset=%s",
5871c2aa98e2SPeter Wemm 					   defcharset(e));
58724e4196cbSGregory Neil Shapiro 			if (!putline(buf, mci))
58734e4196cbSGregory Neil Shapiro 				goto writeerr;
5874c2aa98e2SPeter Wemm 		}
5875c2aa98e2SPeter Wemm 
5876c2aa98e2SPeter Wemm 		/* now do the hard work */
5877c2aa98e2SPeter Wemm 		boundaries[0] = NULL;
5878c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
5879af9557fdSGregory Neil Shapiro 		if (mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER, 0) ==
58804e4196cbSGregory Neil Shapiro 								SM_IO_EOF)
58814e4196cbSGregory Neil Shapiro 			goto writeerr;
5882c2aa98e2SPeter Wemm 	}
5883c2aa98e2SPeter Wemm # if MIME7TO8
5884c2aa98e2SPeter Wemm 	else if (bitset(MCIF_CVT7TO8, mci->mci_flags))
5885c2aa98e2SPeter Wemm 	{
58864e4196cbSGregory Neil Shapiro 		if (!mime7to8(mci, e->e_header, e))
58874e4196cbSGregory Neil Shapiro 			goto writeerr;
5888c2aa98e2SPeter Wemm 	}
588906f25ae9SGregory Neil Shapiro # endif /* MIME7TO8 */
5890065a643dSPeter Wemm 	else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0)
5891065a643dSPeter Wemm 	{
589206f25ae9SGregory Neil Shapiro 		bool oldsuprerrs = SuprErrs;
589306f25ae9SGregory Neil Shapiro 
5894065a643dSPeter Wemm 		/* Use mime8to7 to check multipart for MIME header overflows */
5895065a643dSPeter Wemm 		boundaries[0] = NULL;
5896065a643dSPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
589706f25ae9SGregory Neil Shapiro 
589806f25ae9SGregory Neil Shapiro 		/*
589906f25ae9SGregory Neil Shapiro 		**  If EF_DONT_MIME is set, we have a broken MIME message
590006f25ae9SGregory Neil Shapiro 		**  and don't want to generate a new bounce message whose
590106f25ae9SGregory Neil Shapiro 		**  body propagates the broken MIME.  We can't just not call
590206f25ae9SGregory Neil Shapiro 		**  mime8to7() as is done above since we need the security
590306f25ae9SGregory Neil Shapiro 		**  checks.  The best we can do is suppress the errors.
590406f25ae9SGregory Neil Shapiro 		*/
590506f25ae9SGregory Neil Shapiro 
590606f25ae9SGregory Neil Shapiro 		if (bitset(EF_DONT_MIME, e->e_flags))
590740266059SGregory Neil Shapiro 			SuprErrs = true;
590806f25ae9SGregory Neil Shapiro 
59094e4196cbSGregory Neil Shapiro 		if (mime8to7(mci, e->e_header, e, boundaries,
5910af9557fdSGregory Neil Shapiro 				M87F_OUTER|M87F_NO8TO7, 0) == SM_IO_EOF)
59114e4196cbSGregory Neil Shapiro 			goto writeerr;
591206f25ae9SGregory Neil Shapiro 
591306f25ae9SGregory Neil Shapiro 		/* restore SuprErrs */
591406f25ae9SGregory Neil Shapiro 		SuprErrs = oldsuprerrs;
5915065a643dSPeter Wemm 	}
5916c2aa98e2SPeter Wemm 	else
591706f25ae9SGregory Neil Shapiro #endif /* MIME8TO7 */
5918c2aa98e2SPeter Wemm 	{
5919c2aa98e2SPeter Wemm 		int ostate;
5920c2aa98e2SPeter Wemm 		register char *bp;
5921c2aa98e2SPeter Wemm 		register char *pbp;
5922c2aa98e2SPeter Wemm 		register int c;
5923c2aa98e2SPeter Wemm 		register char *xp;
5924c2aa98e2SPeter Wemm 		int padc;
5925c2aa98e2SPeter Wemm 		char *buflim;
5926c2aa98e2SPeter Wemm 		int pos = 0;
592706f25ae9SGregory Neil Shapiro 		char peekbuf[12];
5928c2aa98e2SPeter Wemm 
5929c2aa98e2SPeter Wemm 		if (bitset(MCIF_INHEADER, mci->mci_flags))
5930c2aa98e2SPeter Wemm 		{
59314e4196cbSGregory Neil Shapiro 			if (!putline("", mci))
59324e4196cbSGregory Neil Shapiro 				goto writeerr;
5933c2aa98e2SPeter Wemm 			mci->mci_flags &= ~MCIF_INHEADER;
5934c2aa98e2SPeter Wemm 		}
5935c2aa98e2SPeter Wemm 
5936c2aa98e2SPeter Wemm 		/* determine end of buffer; allow for short mailer lines */
5937d0cef73dSGregory Neil Shapiro 		buflim = &buf[sizeof(buf) - 1];
5938c2aa98e2SPeter Wemm 		if (mci->mci_mailer->m_linelimit > 0 &&
5939d0cef73dSGregory Neil Shapiro 		    mci->mci_mailer->m_linelimit < sizeof(buf) - 1)
5940c2aa98e2SPeter Wemm 			buflim = &buf[mci->mci_mailer->m_linelimit - 1];
5941c2aa98e2SPeter Wemm 
5942c2aa98e2SPeter Wemm 		/* copy temp file to output with mapping */
59434e4196cbSGregory Neil Shapiro 		ostate = OSTATE_HEAD;
5944c2aa98e2SPeter Wemm 		bp = buf;
5945c2aa98e2SPeter Wemm 		pbp = peekbuf;
594640266059SGregory Neil Shapiro 		while (!sm_io_error(mci->mci_out) && !dead)
5947c2aa98e2SPeter Wemm 		{
5948c2aa98e2SPeter Wemm 			if (pbp > peekbuf)
5949c2aa98e2SPeter Wemm 				c = *--pbp;
595040266059SGregory Neil Shapiro 			else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT))
595140266059SGregory Neil Shapiro 				 == SM_IO_EOF)
5952c2aa98e2SPeter Wemm 				break;
5953c2aa98e2SPeter Wemm 			if (bitset(MCIF_7BIT, mci->mci_flags))
5954c2aa98e2SPeter Wemm 				c &= 0x7f;
5955c2aa98e2SPeter Wemm 			switch (ostate)
5956c2aa98e2SPeter Wemm 			{
59574e4196cbSGregory Neil Shapiro 			  case OSTATE_HEAD:
5958c2aa98e2SPeter Wemm 				if (c == '\0' &&
595940266059SGregory Neil Shapiro 				    bitnset(M_NONULLS,
596040266059SGregory Neil Shapiro 					    mci->mci_mailer->m_flags))
5961c2aa98e2SPeter Wemm 					break;
5962c2aa98e2SPeter Wemm 				if (c != '\r' && c != '\n' && bp < buflim)
5963c2aa98e2SPeter Wemm 				{
5964c2aa98e2SPeter Wemm 					*bp++ = c;
5965c2aa98e2SPeter Wemm 					break;
5966c2aa98e2SPeter Wemm 				}
5967c2aa98e2SPeter Wemm 
5968c2aa98e2SPeter Wemm 				/* check beginning of line for special cases */
5969c2aa98e2SPeter Wemm 				*bp = '\0';
5970c2aa98e2SPeter Wemm 				pos = 0;
597140266059SGregory Neil Shapiro 				padc = SM_IO_EOF;
5972c2aa98e2SPeter Wemm 				if (buf[0] == 'F' &&
597340266059SGregory Neil Shapiro 				    bitnset(M_ESCFROM, mci->mci_mailer->m_flags)
597440266059SGregory Neil Shapiro 				    && strncmp(buf, "From ", 5) == 0)
5975c2aa98e2SPeter Wemm 				{
5976c2aa98e2SPeter Wemm 					padc = '>';
5977c2aa98e2SPeter Wemm 				}
5978c2aa98e2SPeter Wemm 				if (buf[0] == '-' && buf[1] == '-' &&
5979c2aa98e2SPeter Wemm 				    separator != NULL)
5980c2aa98e2SPeter Wemm 				{
5981c2aa98e2SPeter Wemm 					/* possible separator */
5982c2aa98e2SPeter Wemm 					int sl = strlen(separator);
5983c2aa98e2SPeter Wemm 
598440266059SGregory Neil Shapiro 					if (strncmp(&buf[2], separator, sl)
598540266059SGregory Neil Shapiro 					    == 0)
5986c2aa98e2SPeter Wemm 						padc = ' ';
5987c2aa98e2SPeter Wemm 				}
5988c2aa98e2SPeter Wemm 				if (buf[0] == '.' &&
5989c2aa98e2SPeter Wemm 				    bitnset(M_XDOT, mci->mci_mailer->m_flags))
5990c2aa98e2SPeter Wemm 				{
5991c2aa98e2SPeter Wemm 					padc = '.';
5992c2aa98e2SPeter Wemm 				}
5993c2aa98e2SPeter Wemm 
5994c2aa98e2SPeter Wemm 				/* now copy out saved line */
5995c2aa98e2SPeter Wemm 				if (TrafficLogFile != NULL)
5996c2aa98e2SPeter Wemm 				{
599740266059SGregory Neil Shapiro 					(void) sm_io_fprintf(TrafficLogFile,
599840266059SGregory Neil Shapiro 							     SM_TIME_DEFAULT,
599940266059SGregory Neil Shapiro 							     "%05d >>> ",
600040266059SGregory Neil Shapiro 							     (int) CurrentPid);
600140266059SGregory Neil Shapiro 					if (padc != SM_IO_EOF)
600240266059SGregory Neil Shapiro 						(void) sm_io_putc(TrafficLogFile,
600340266059SGregory Neil Shapiro 								  SM_TIME_DEFAULT,
600440266059SGregory Neil Shapiro 								  padc);
6005c2aa98e2SPeter Wemm 					for (xp = buf; xp < bp; xp++)
600640266059SGregory Neil Shapiro 						(void) sm_io_putc(TrafficLogFile,
600740266059SGregory Neil Shapiro 								  SM_TIME_DEFAULT,
600840266059SGregory Neil Shapiro 								  (unsigned char) *xp);
6009c2aa98e2SPeter Wemm 					if (c == '\n')
601040266059SGregory Neil Shapiro 						(void) sm_io_fputs(TrafficLogFile,
601140266059SGregory Neil Shapiro 								   SM_TIME_DEFAULT,
601240266059SGregory Neil Shapiro 								   mci->mci_mailer->m_eol);
6013c2aa98e2SPeter Wemm 				}
601440266059SGregory Neil Shapiro 				if (padc != SM_IO_EOF)
6015c2aa98e2SPeter Wemm 				{
601640266059SGregory Neil Shapiro 					if (sm_io_putc(mci->mci_out,
601740266059SGregory Neil Shapiro 						       SM_TIME_DEFAULT, padc)
601840266059SGregory Neil Shapiro 					    == SM_IO_EOF)
601906f25ae9SGregory Neil Shapiro 					{
602040266059SGregory Neil Shapiro 						dead = true;
602106f25ae9SGregory Neil Shapiro 						continue;
602206f25ae9SGregory Neil Shapiro 					}
6023c2aa98e2SPeter Wemm 					pos++;
6024c2aa98e2SPeter Wemm 				}
6025c2aa98e2SPeter Wemm 				for (xp = buf; xp < bp; xp++)
6026c2aa98e2SPeter Wemm 				{
602740266059SGregory Neil Shapiro 					if (sm_io_putc(mci->mci_out,
602840266059SGregory Neil Shapiro 						       SM_TIME_DEFAULT,
602940266059SGregory Neil Shapiro 						       (unsigned char) *xp)
603040266059SGregory Neil Shapiro 					    == SM_IO_EOF)
603106f25ae9SGregory Neil Shapiro 					{
603240266059SGregory Neil Shapiro 						dead = true;
603306f25ae9SGregory Neil Shapiro 						break;
6034c2aa98e2SPeter Wemm 					}
6035193538b7SGregory Neil Shapiro 				}
603606f25ae9SGregory Neil Shapiro 				if (dead)
603706f25ae9SGregory Neil Shapiro 					continue;
6038c2aa98e2SPeter Wemm 				if (c == '\n')
6039c2aa98e2SPeter Wemm 				{
604040266059SGregory Neil Shapiro 					if (sm_io_fputs(mci->mci_out,
604140266059SGregory Neil Shapiro 							SM_TIME_DEFAULT,
604240266059SGregory Neil Shapiro 							mci->mci_mailer->m_eol)
604340266059SGregory Neil Shapiro 							== SM_IO_EOF)
604406f25ae9SGregory Neil Shapiro 						break;
6045c2aa98e2SPeter Wemm 					pos = 0;
6046c2aa98e2SPeter Wemm 				}
6047c2aa98e2SPeter Wemm 				else
6048c2aa98e2SPeter Wemm 				{
6049c2aa98e2SPeter Wemm 					pos += bp - buf;
6050c2aa98e2SPeter Wemm 					if (c != '\r')
60515ef517c0SGregory Neil Shapiro 					{
60525ef517c0SGregory Neil Shapiro 						SM_ASSERT(pbp < peekbuf +
60535ef517c0SGregory Neil Shapiro 								sizeof(peekbuf));
6054c2aa98e2SPeter Wemm 						*pbp++ = c;
6055c2aa98e2SPeter Wemm 					}
60565ef517c0SGregory Neil Shapiro 				}
605706f25ae9SGregory Neil Shapiro 
6058c2aa98e2SPeter Wemm 				bp = buf;
6059c2aa98e2SPeter Wemm 
6060c2aa98e2SPeter Wemm 				/* determine next state */
6061c2aa98e2SPeter Wemm 				if (c == '\n')
60624e4196cbSGregory Neil Shapiro 					ostate = OSTATE_HEAD;
6063c2aa98e2SPeter Wemm 				else if (c == '\r')
60644e4196cbSGregory Neil Shapiro 					ostate = OSTATE_CR;
6065c2aa98e2SPeter Wemm 				else
60664e4196cbSGregory Neil Shapiro 					ostate = OSTATE_INLINE;
6067c2aa98e2SPeter Wemm 				continue;
6068c2aa98e2SPeter Wemm 
60694e4196cbSGregory Neil Shapiro 			  case OSTATE_CR:
6070c2aa98e2SPeter Wemm 				if (c == '\n')
6071c2aa98e2SPeter Wemm 				{
6072c2aa98e2SPeter Wemm 					/* got CRLF */
607340266059SGregory Neil Shapiro 					if (sm_io_fputs(mci->mci_out,
607440266059SGregory Neil Shapiro 							SM_TIME_DEFAULT,
607540266059SGregory Neil Shapiro 							mci->mci_mailer->m_eol)
607640266059SGregory Neil Shapiro 							== SM_IO_EOF)
607706f25ae9SGregory Neil Shapiro 						continue;
607806f25ae9SGregory Neil Shapiro 
6079c2aa98e2SPeter Wemm 					if (TrafficLogFile != NULL)
6080c2aa98e2SPeter Wemm 					{
608140266059SGregory Neil Shapiro 						(void) sm_io_fputs(TrafficLogFile,
608240266059SGregory Neil Shapiro 								   SM_TIME_DEFAULT,
608340266059SGregory Neil Shapiro 								   mci->mci_mailer->m_eol);
6084c2aa98e2SPeter Wemm 					}
6085d0cef73dSGregory Neil Shapiro 					pos = 0;
60864e4196cbSGregory Neil Shapiro 					ostate = OSTATE_HEAD;
6087c2aa98e2SPeter Wemm 					continue;
6088c2aa98e2SPeter Wemm 				}
6089c2aa98e2SPeter Wemm 
6090c2aa98e2SPeter Wemm 				/* had a naked carriage return */
60915ef517c0SGregory Neil Shapiro 				SM_ASSERT(pbp < peekbuf + sizeof(peekbuf));
6092c2aa98e2SPeter Wemm 				*pbp++ = c;
6093c2aa98e2SPeter Wemm 				c = '\r';
60944e4196cbSGregory Neil Shapiro 				ostate = OSTATE_INLINE;
6095c2aa98e2SPeter Wemm 				goto putch;
6096c2aa98e2SPeter Wemm 
60974e4196cbSGregory Neil Shapiro 			  case OSTATE_INLINE:
6098c2aa98e2SPeter Wemm 				if (c == '\r')
6099c2aa98e2SPeter Wemm 				{
61004e4196cbSGregory Neil Shapiro 					ostate = OSTATE_CR;
6101c2aa98e2SPeter Wemm 					continue;
6102c2aa98e2SPeter Wemm 				}
6103c2aa98e2SPeter Wemm 				if (c == '\0' &&
610440266059SGregory Neil Shapiro 				    bitnset(M_NONULLS,
610540266059SGregory Neil Shapiro 					    mci->mci_mailer->m_flags))
6106c2aa98e2SPeter Wemm 					break;
6107c2aa98e2SPeter Wemm putch:
6108c2aa98e2SPeter Wemm 				if (mci->mci_mailer->m_linelimit > 0 &&
610906f25ae9SGregory Neil Shapiro 				    pos >= mci->mci_mailer->m_linelimit - 1 &&
6110c2aa98e2SPeter Wemm 				    c != '\n')
6111c2aa98e2SPeter Wemm 				{
611206f25ae9SGregory Neil Shapiro 					int d;
611306f25ae9SGregory Neil Shapiro 
611406f25ae9SGregory Neil Shapiro 					/* check next character for EOL */
611506f25ae9SGregory Neil Shapiro 					if (pbp > peekbuf)
611606f25ae9SGregory Neil Shapiro 						d = *(pbp - 1);
611740266059SGregory Neil Shapiro 					else if ((d = sm_io_getc(e->e_dfp,
611840266059SGregory Neil Shapiro 								 SM_TIME_DEFAULT))
611940266059SGregory Neil Shapiro 						 != SM_IO_EOF)
61205ef517c0SGregory Neil Shapiro 					{
61215ef517c0SGregory Neil Shapiro 						SM_ASSERT(pbp < peekbuf +
61225ef517c0SGregory Neil Shapiro 								sizeof(peekbuf));
612306f25ae9SGregory Neil Shapiro 						*pbp++ = d;
61245ef517c0SGregory Neil Shapiro 					}
612506f25ae9SGregory Neil Shapiro 
612640266059SGregory Neil Shapiro 					if (d == '\n' || d == SM_IO_EOF)
612706f25ae9SGregory Neil Shapiro 					{
612806f25ae9SGregory Neil Shapiro 						if (TrafficLogFile != NULL)
612940266059SGregory Neil Shapiro 							(void) sm_io_putc(TrafficLogFile,
613040266059SGregory Neil Shapiro 									  SM_TIME_DEFAULT,
613140266059SGregory Neil Shapiro 									  (unsigned char) c);
613240266059SGregory Neil Shapiro 						if (sm_io_putc(mci->mci_out,
613340266059SGregory Neil Shapiro 							       SM_TIME_DEFAULT,
613440266059SGregory Neil Shapiro 							       (unsigned char) c)
613540266059SGregory Neil Shapiro 							       == SM_IO_EOF)
613606f25ae9SGregory Neil Shapiro 						{
613740266059SGregory Neil Shapiro 							dead = true;
613806f25ae9SGregory Neil Shapiro 							continue;
613906f25ae9SGregory Neil Shapiro 						}
614006f25ae9SGregory Neil Shapiro 						pos++;
614106f25ae9SGregory Neil Shapiro 						continue;
614206f25ae9SGregory Neil Shapiro 					}
614306f25ae9SGregory Neil Shapiro 
614440266059SGregory Neil Shapiro 					if (sm_io_putc(mci->mci_out,
614540266059SGregory Neil Shapiro 						       SM_TIME_DEFAULT, '!')
614640266059SGregory Neil Shapiro 					    == SM_IO_EOF ||
614740266059SGregory Neil Shapiro 					    sm_io_fputs(mci->mci_out,
614840266059SGregory Neil Shapiro 							SM_TIME_DEFAULT,
614940266059SGregory Neil Shapiro 							mci->mci_mailer->m_eol)
615040266059SGregory Neil Shapiro 					    == SM_IO_EOF)
615106f25ae9SGregory Neil Shapiro 					{
615240266059SGregory Neil Shapiro 						dead = true;
615306f25ae9SGregory Neil Shapiro 						continue;
615406f25ae9SGregory Neil Shapiro 					}
615506f25ae9SGregory Neil Shapiro 
6156c2aa98e2SPeter Wemm 					if (TrafficLogFile != NULL)
6157c2aa98e2SPeter Wemm 					{
615840266059SGregory Neil Shapiro 						(void) sm_io_fprintf(TrafficLogFile,
615940266059SGregory Neil Shapiro 								     SM_TIME_DEFAULT,
616040266059SGregory Neil Shapiro 								     "!%s",
6161c2aa98e2SPeter Wemm 								     mci->mci_mailer->m_eol);
6162c2aa98e2SPeter Wemm 					}
61634e4196cbSGregory Neil Shapiro 					ostate = OSTATE_HEAD;
61645ef517c0SGregory Neil Shapiro 					SM_ASSERT(pbp < peekbuf +
61655ef517c0SGregory Neil Shapiro 							sizeof(peekbuf));
6166c2aa98e2SPeter Wemm 					*pbp++ = c;
6167c2aa98e2SPeter Wemm 					continue;
6168c2aa98e2SPeter Wemm 				}
6169c2aa98e2SPeter Wemm 				if (c == '\n')
6170c2aa98e2SPeter Wemm 				{
6171c2aa98e2SPeter Wemm 					if (TrafficLogFile != NULL)
617240266059SGregory Neil Shapiro 						(void) sm_io_fputs(TrafficLogFile,
617340266059SGregory Neil Shapiro 								   SM_TIME_DEFAULT,
617440266059SGregory Neil Shapiro 								   mci->mci_mailer->m_eol);
617540266059SGregory Neil Shapiro 					if (sm_io_fputs(mci->mci_out,
617640266059SGregory Neil Shapiro 							SM_TIME_DEFAULT,
617740266059SGregory Neil Shapiro 							mci->mci_mailer->m_eol)
617840266059SGregory Neil Shapiro 							== SM_IO_EOF)
617906f25ae9SGregory Neil Shapiro 						continue;
6180c2aa98e2SPeter Wemm 					pos = 0;
61814e4196cbSGregory Neil Shapiro 					ostate = OSTATE_HEAD;
6182c2aa98e2SPeter Wemm 				}
6183c2aa98e2SPeter Wemm 				else
6184c2aa98e2SPeter Wemm 				{
6185c2aa98e2SPeter Wemm 					if (TrafficLogFile != NULL)
618640266059SGregory Neil Shapiro 						(void) sm_io_putc(TrafficLogFile,
618740266059SGregory Neil Shapiro 								  SM_TIME_DEFAULT,
618840266059SGregory Neil Shapiro 								  (unsigned char) c);
618940266059SGregory Neil Shapiro 					if (sm_io_putc(mci->mci_out,
619040266059SGregory Neil Shapiro 						       SM_TIME_DEFAULT,
619140266059SGregory Neil Shapiro 						       (unsigned char) c)
619240266059SGregory Neil Shapiro 					    == SM_IO_EOF)
619306f25ae9SGregory Neil Shapiro 					{
619440266059SGregory Neil Shapiro 						dead = true;
619506f25ae9SGregory Neil Shapiro 						continue;
619606f25ae9SGregory Neil Shapiro 					}
6197c2aa98e2SPeter Wemm 					pos++;
61984e4196cbSGregory Neil Shapiro 					ostate = OSTATE_INLINE;
6199c2aa98e2SPeter Wemm 				}
6200c2aa98e2SPeter Wemm 				break;
6201c2aa98e2SPeter Wemm 			}
6202c2aa98e2SPeter Wemm 		}
6203c2aa98e2SPeter Wemm 
6204c2aa98e2SPeter Wemm 		/* make sure we are at the beginning of a line */
6205c2aa98e2SPeter Wemm 		if (bp > buf)
6206c2aa98e2SPeter Wemm 		{
6207c2aa98e2SPeter Wemm 			if (TrafficLogFile != NULL)
6208c2aa98e2SPeter Wemm 			{
6209c2aa98e2SPeter Wemm 				for (xp = buf; xp < bp; xp++)
621040266059SGregory Neil Shapiro 					(void) sm_io_putc(TrafficLogFile,
621140266059SGregory Neil Shapiro 							  SM_TIME_DEFAULT,
621240266059SGregory Neil Shapiro 							  (unsigned char) *xp);
6213c2aa98e2SPeter Wemm 			}
6214c2aa98e2SPeter Wemm 			for (xp = buf; xp < bp; xp++)
6215c2aa98e2SPeter Wemm 			{
621640266059SGregory Neil Shapiro 				if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
621740266059SGregory Neil Shapiro 					       (unsigned char) *xp)
621840266059SGregory Neil Shapiro 				    == SM_IO_EOF)
621906f25ae9SGregory Neil Shapiro 				{
622040266059SGregory Neil Shapiro 					dead = true;
622106f25ae9SGregory Neil Shapiro 					break;
622206f25ae9SGregory Neil Shapiro 				}
6223193538b7SGregory Neil Shapiro 			}
6224c2aa98e2SPeter Wemm 			pos += bp - buf;
6225c2aa98e2SPeter Wemm 		}
622606f25ae9SGregory Neil Shapiro 		if (!dead && pos > 0)
6227c2aa98e2SPeter Wemm 		{
6228c2aa98e2SPeter Wemm 			if (TrafficLogFile != NULL)
622940266059SGregory Neil Shapiro 				(void) sm_io_fputs(TrafficLogFile,
623040266059SGregory Neil Shapiro 						   SM_TIME_DEFAULT,
623140266059SGregory Neil Shapiro 						   mci->mci_mailer->m_eol);
62324e4196cbSGregory Neil Shapiro 			if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
62334e4196cbSGregory Neil Shapiro 					   mci->mci_mailer->m_eol) == SM_IO_EOF)
62344e4196cbSGregory Neil Shapiro 				goto writeerr;
6235c2aa98e2SPeter Wemm 		}
6236c2aa98e2SPeter Wemm 	}
6237c2aa98e2SPeter Wemm 
623840266059SGregory Neil Shapiro 	if (sm_io_error(e->e_dfp))
6239c2aa98e2SPeter Wemm 	{
624040266059SGregory Neil Shapiro 		syserr("putbody: %s/%cf%s: read error",
624140266059SGregory Neil Shapiro 		       qid_printqueue(e->e_dfqgrp, e->e_dfqdir),
624240266059SGregory Neil Shapiro 		       DATAFL_LETTER, e->e_id);
6243c2aa98e2SPeter Wemm 		ExitStat = EX_IOERR;
62444e4196cbSGregory Neil Shapiro 		ioerr = true;
6245c2aa98e2SPeter Wemm 	}
6246c2aa98e2SPeter Wemm 
6247c2aa98e2SPeter Wemm endofmessage:
624806f25ae9SGregory Neil Shapiro 	/*
624906f25ae9SGregory Neil Shapiro 	**  Since mailfile() uses e_dfp in a child process,
625006f25ae9SGregory Neil Shapiro 	**  the file offset in the stdio library for the
625106f25ae9SGregory Neil Shapiro 	**  parent process will not agree with the in-kernel
625206f25ae9SGregory Neil Shapiro 	**  file offset since the file descriptor is shared
625306f25ae9SGregory Neil Shapiro 	**  between the processes.  Therefore, it is vital
625406f25ae9SGregory Neil Shapiro 	**  that the file always be rewound.  This forces the
625506f25ae9SGregory Neil Shapiro 	**  kernel offset (lseek) and stdio library (ftell)
625606f25ae9SGregory Neil Shapiro 	**  offset to match.
625706f25ae9SGregory Neil Shapiro 	*/
625806f25ae9SGregory Neil Shapiro 
62594e4196cbSGregory Neil Shapiro 	save_errno = errno;
626006f25ae9SGregory Neil Shapiro 	if (e->e_dfp != NULL)
626106f25ae9SGregory Neil Shapiro 		(void) bfrewind(e->e_dfp);
626206f25ae9SGregory Neil Shapiro 
6263c2aa98e2SPeter Wemm 	/* some mailers want extra blank line at end of message */
626406f25ae9SGregory Neil Shapiro 	if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
6265c2aa98e2SPeter Wemm 	    buf[0] != '\0' && buf[0] != '\n')
6266c2aa98e2SPeter Wemm 	{
62674e4196cbSGregory Neil Shapiro 		if (!putline("", mci))
62684e4196cbSGregory Neil Shapiro 			goto writeerr;
62694e4196cbSGregory Neil Shapiro 	}
62704e4196cbSGregory Neil Shapiro 
62714e4196cbSGregory Neil Shapiro 	if (!dead &&
62724e4196cbSGregory Neil Shapiro 	    (sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF ||
62734e4196cbSGregory Neil Shapiro 	     (sm_io_error(mci->mci_out) && errno != EPIPE)))
62744e4196cbSGregory Neil Shapiro 	{
62754e4196cbSGregory Neil Shapiro 		save_errno = errno;
6276c2aa98e2SPeter Wemm 		syserr("putbody: write error");
6277c2aa98e2SPeter Wemm 		ExitStat = EX_IOERR;
62784e4196cbSGregory Neil Shapiro 		ioerr = true;
6279c2aa98e2SPeter Wemm 	}
628006f25ae9SGregory Neil Shapiro 
62814e4196cbSGregory Neil Shapiro 	errno = save_errno;
62824e4196cbSGregory Neil Shapiro 	return !dead && !ioerr;
62834e4196cbSGregory Neil Shapiro 
62844e4196cbSGregory Neil Shapiro   writeerr:
62854e4196cbSGregory Neil Shapiro 	return false;
6286c2aa98e2SPeter Wemm }
62874e4196cbSGregory Neil Shapiro 
628840266059SGregory Neil Shapiro /*
6289c2aa98e2SPeter Wemm **  MAILFILE -- Send a message to a file.
6290c2aa98e2SPeter Wemm **
629140266059SGregory Neil Shapiro **	If the file has the set-user-ID/set-group-ID bits set, but NO
629240266059SGregory Neil Shapiro **	execute bits, sendmail will try to become the owner of that file
6293c2aa98e2SPeter Wemm **	rather than the real user.  Obviously, this only works if
6294c2aa98e2SPeter Wemm **	sendmail runs as root.
6295c2aa98e2SPeter Wemm **
6296c2aa98e2SPeter Wemm **	This could be done as a subordinate mailer, except that it
6297c2aa98e2SPeter Wemm **	is used implicitly to save messages in ~/dead.letter.  We
6298c2aa98e2SPeter Wemm **	view this as being sufficiently important as to include it
6299c2aa98e2SPeter Wemm **	here.  For example, if the system is dying, we shouldn't have
6300c2aa98e2SPeter Wemm **	to create another process plus some pipes to save the message.
6301c2aa98e2SPeter Wemm **
6302c2aa98e2SPeter Wemm **	Parameters:
6303c2aa98e2SPeter Wemm **		filename -- the name of the file to send to.
6304c2aa98e2SPeter Wemm **		mailer -- mailer definition for recipient -- if NULL,
6305c2aa98e2SPeter Wemm **			use FileMailer.
6306c2aa98e2SPeter Wemm **		ctladdr -- the controlling address header -- includes
6307c2aa98e2SPeter Wemm **			the userid/groupid to be when sending.
6308c2aa98e2SPeter Wemm **		sfflags -- flags for opening.
6309c2aa98e2SPeter Wemm **		e -- the current envelope.
6310c2aa98e2SPeter Wemm **
6311c2aa98e2SPeter Wemm **	Returns:
6312c2aa98e2SPeter Wemm **		The exit code associated with the operation.
6313c2aa98e2SPeter Wemm **
6314c2aa98e2SPeter Wemm **	Side Effects:
6315c2aa98e2SPeter Wemm **		none.
6316c2aa98e2SPeter Wemm */
6317c2aa98e2SPeter Wemm 
631840266059SGregory Neil Shapiro # define RETURN(st)			exit(st);
631940266059SGregory Neil Shapiro 
6320c2aa98e2SPeter Wemm static jmp_buf	CtxMailfileTimeout;
6321c2aa98e2SPeter Wemm 
6322c2aa98e2SPeter Wemm int
mailfile(filename,mailer,ctladdr,sfflags,e)6323c2aa98e2SPeter Wemm mailfile(filename, mailer, ctladdr, sfflags, e)
6324c2aa98e2SPeter Wemm 	char *volatile filename;
6325c2aa98e2SPeter Wemm 	MAILER *volatile mailer;
6326c2aa98e2SPeter Wemm 	ADDRESS *ctladdr;
632706f25ae9SGregory Neil Shapiro 	volatile long sfflags;
6328c2aa98e2SPeter Wemm 	register ENVELOPE *e;
6329c2aa98e2SPeter Wemm {
633040266059SGregory Neil Shapiro 	register SM_FILE_T *f;
6331c2aa98e2SPeter Wemm 	register pid_t pid = -1;
633206f25ae9SGregory Neil Shapiro 	volatile int mode;
633306f25ae9SGregory Neil Shapiro 	int len;
633406f25ae9SGregory Neil Shapiro 	off_t curoff;
6335c2aa98e2SPeter Wemm 	bool suidwarn = geteuid() == 0;
6336c2aa98e2SPeter Wemm 	char *p;
633706f25ae9SGregory Neil Shapiro 	char *volatile realfile;
633840266059SGregory Neil Shapiro 	SM_EVENT *ev;
633994c01205SGregory Neil Shapiro 	char buf[MAXPATHLEN];
634094c01205SGregory Neil Shapiro 	char targetfile[MAXPATHLEN];
6341c2aa98e2SPeter Wemm 
6342c2aa98e2SPeter Wemm 	if (tTd(11, 1))
6343c2aa98e2SPeter Wemm 	{
634440266059SGregory Neil Shapiro 		sm_dprintf("mailfile %s\n  ctladdr=", filename);
6345e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), ctladdr, false);
6346c2aa98e2SPeter Wemm 	}
6347c2aa98e2SPeter Wemm 
6348c2aa98e2SPeter Wemm 	if (mailer == NULL)
6349c2aa98e2SPeter Wemm 		mailer = FileMailer;
6350c2aa98e2SPeter Wemm 
6351c2aa98e2SPeter Wemm 	if (e->e_xfp != NULL)
635240266059SGregory Neil Shapiro 		(void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
6353c2aa98e2SPeter Wemm 
6354c2aa98e2SPeter Wemm 	/*
6355c2aa98e2SPeter Wemm 	**  Special case /dev/null.  This allows us to restrict file
6356c2aa98e2SPeter Wemm 	**  delivery to regular files only.
6357c2aa98e2SPeter Wemm 	*/
6358c2aa98e2SPeter Wemm 
635940266059SGregory Neil Shapiro 	if (sm_path_isdevnull(filename))
6360c2aa98e2SPeter Wemm 		return EX_OK;
6361c2aa98e2SPeter Wemm 
6362c2aa98e2SPeter Wemm 	/* check for 8-bit available */
6363c2aa98e2SPeter Wemm 	if (bitset(EF_HAS8BIT, e->e_flags) &&
6364c2aa98e2SPeter Wemm 	    bitnset(M_7BITS, mailer->m_flags) &&
6365c2aa98e2SPeter Wemm 	    (bitset(EF_DONT_MIME, e->e_flags) ||
6366c2aa98e2SPeter Wemm 	     !(bitset(MM_MIME8BIT, MimeMode) ||
6367c2aa98e2SPeter Wemm 	       (bitset(EF_IS_MIME, e->e_flags) &&
6368c2aa98e2SPeter Wemm 		bitset(MM_CVTMIME, MimeMode)))))
6369c2aa98e2SPeter Wemm 	{
6370c2aa98e2SPeter Wemm 		e->e_status = "5.6.3";
637106f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status,
637206f25ae9SGregory Neil Shapiro 			  "554 Cannot send 8-bit data to 7-bit destination");
637340266059SGregory Neil Shapiro 		errno = 0;
637406f25ae9SGregory Neil Shapiro 		return EX_DATAERR;
637506f25ae9SGregory Neil Shapiro 	}
637606f25ae9SGregory Neil Shapiro 
637706f25ae9SGregory Neil Shapiro 	/* Find the actual file */
637806f25ae9SGregory Neil Shapiro 	if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0')
637906f25ae9SGregory Neil Shapiro 	{
638006f25ae9SGregory Neil Shapiro 		len = strlen(SafeFileEnv);
638106f25ae9SGregory Neil Shapiro 
638206f25ae9SGregory Neil Shapiro 		if (strncmp(SafeFileEnv, filename, len) == 0)
638306f25ae9SGregory Neil Shapiro 			filename += len;
638406f25ae9SGregory Neil Shapiro 
6385d0cef73dSGregory Neil Shapiro 		if (len + strlen(filename) + 1 >= sizeof(targetfile))
638606f25ae9SGregory Neil Shapiro 		{
638706f25ae9SGregory Neil Shapiro 			syserr("mailfile: filename too long (%s/%s)",
638806f25ae9SGregory Neil Shapiro 			       SafeFileEnv, filename);
638906f25ae9SGregory Neil Shapiro 			return EX_CANTCREAT;
639006f25ae9SGregory Neil Shapiro 		}
6391d0cef73dSGregory Neil Shapiro 		(void) sm_strlcpy(targetfile, SafeFileEnv, sizeof(targetfile));
639206f25ae9SGregory Neil Shapiro 		realfile = targetfile + len;
639306f25ae9SGregory Neil Shapiro 		if (*filename == '/')
639406f25ae9SGregory Neil Shapiro 			filename++;
6395605302a5SGregory Neil Shapiro 		if (*filename != '\0')
6396605302a5SGregory Neil Shapiro 		{
6397605302a5SGregory Neil Shapiro 			/* paranoia: trailing / should be removed in readcf */
6398605302a5SGregory Neil Shapiro 			if (targetfile[len - 1] != '/')
6399605302a5SGregory Neil Shapiro 				(void) sm_strlcat(targetfile,
6400d0cef73dSGregory Neil Shapiro 						  "/", sizeof(targetfile));
6401605302a5SGregory Neil Shapiro 			(void) sm_strlcat(targetfile, filename,
6402d0cef73dSGregory Neil Shapiro 					  sizeof(targetfile));
6403605302a5SGregory Neil Shapiro 		}
640406f25ae9SGregory Neil Shapiro 	}
640506f25ae9SGregory Neil Shapiro 	else if (mailer->m_rootdir != NULL)
640606f25ae9SGregory Neil Shapiro 	{
6407d0cef73dSGregory Neil Shapiro 		expand(mailer->m_rootdir, targetfile, sizeof(targetfile), e);
640806f25ae9SGregory Neil Shapiro 		len = strlen(targetfile);
640906f25ae9SGregory Neil Shapiro 
641006f25ae9SGregory Neil Shapiro 		if (strncmp(targetfile, filename, len) == 0)
641106f25ae9SGregory Neil Shapiro 			filename += len;
641206f25ae9SGregory Neil Shapiro 
6413d0cef73dSGregory Neil Shapiro 		if (len + strlen(filename) + 1 >= sizeof(targetfile))
641406f25ae9SGregory Neil Shapiro 		{
641506f25ae9SGregory Neil Shapiro 			syserr("mailfile: filename too long (%s/%s)",
641606f25ae9SGregory Neil Shapiro 			       targetfile, filename);
641706f25ae9SGregory Neil Shapiro 			return EX_CANTCREAT;
641806f25ae9SGregory Neil Shapiro 		}
641906f25ae9SGregory Neil Shapiro 		realfile = targetfile + len;
642006f25ae9SGregory Neil Shapiro 		if (targetfile[len - 1] != '/')
6421d0cef73dSGregory Neil Shapiro 			(void) sm_strlcat(targetfile, "/", sizeof(targetfile));
642206f25ae9SGregory Neil Shapiro 		if (*filename == '/')
642340266059SGregory Neil Shapiro 			(void) sm_strlcat(targetfile, filename + 1,
6424d0cef73dSGregory Neil Shapiro 					  sizeof(targetfile));
642506f25ae9SGregory Neil Shapiro 		else
642640266059SGregory Neil Shapiro 			(void) sm_strlcat(targetfile, filename,
6427d0cef73dSGregory Neil Shapiro 					  sizeof(targetfile));
642806f25ae9SGregory Neil Shapiro 	}
642906f25ae9SGregory Neil Shapiro 	else
643006f25ae9SGregory Neil Shapiro 	{
6431d0cef73dSGregory Neil Shapiro 		if (sm_strlcpy(targetfile, filename, sizeof(targetfile)) >=
6432d0cef73dSGregory Neil Shapiro 		    sizeof(targetfile))
643306f25ae9SGregory Neil Shapiro 		{
643406f25ae9SGregory Neil Shapiro 			syserr("mailfile: filename too long (%s)", filename);
643506f25ae9SGregory Neil Shapiro 			return EX_CANTCREAT;
643606f25ae9SGregory Neil Shapiro 		}
643706f25ae9SGregory Neil Shapiro 		realfile = targetfile;
6438c2aa98e2SPeter Wemm 	}
6439c2aa98e2SPeter Wemm 
6440c2aa98e2SPeter Wemm 	/*
6441c2aa98e2SPeter Wemm 	**  Fork so we can change permissions here.
6442c2aa98e2SPeter Wemm 	**	Note that we MUST use fork, not vfork, because of
6443c2aa98e2SPeter Wemm 	**	the complications of calling subroutines, etc.
6444c2aa98e2SPeter Wemm 	*/
6445c2aa98e2SPeter Wemm 
6446605302a5SGregory Neil Shapiro 
6447605302a5SGregory Neil Shapiro 	/*
6448605302a5SGregory Neil Shapiro 	**  Dispose of SIGCHLD signal catchers that may be laying
6449605302a5SGregory Neil Shapiro 	**  around so that the waitfor() below will get it.
6450605302a5SGregory Neil Shapiro 	*/
6451605302a5SGregory Neil Shapiro 
6452605302a5SGregory Neil Shapiro 	(void) sm_signal(SIGCHLD, SIG_DFL);
6453605302a5SGregory Neil Shapiro 
6454c2aa98e2SPeter Wemm 	DOFORK(fork);
6455c2aa98e2SPeter Wemm 
6456c2aa98e2SPeter Wemm 	if (pid < 0)
645706f25ae9SGregory Neil Shapiro 		return EX_OSERR;
6458c2aa98e2SPeter Wemm 	else if (pid == 0)
6459c2aa98e2SPeter Wemm 	{
6460c2aa98e2SPeter Wemm 		/* child -- actually write to file */
6461c2aa98e2SPeter Wemm 		struct stat stb;
6462c2aa98e2SPeter Wemm 		MCI mcibuf;
6463065a643dSPeter Wemm 		int err;
6464c2aa98e2SPeter Wemm 		volatile int oflags = O_WRONLY|O_APPEND;
6465c2aa98e2SPeter Wemm 
64668774250cSGregory Neil Shapiro 		/* Reset global flags */
64678774250cSGregory Neil Shapiro 		RestartRequest = NULL;
646840266059SGregory Neil Shapiro 		RestartWorkGroup = false;
64698774250cSGregory Neil Shapiro 		ShutdownRequest = NULL;
64708774250cSGregory Neil Shapiro 		PendingSignal = 0;
647140266059SGregory Neil Shapiro 		CurrentPid = getpid();
64728774250cSGregory Neil Shapiro 
6473c2aa98e2SPeter Wemm 		if (e->e_lockfp != NULL)
6474af9557fdSGregory Neil Shapiro 		{
6475af9557fdSGregory Neil Shapiro 			int fd;
6476af9557fdSGregory Neil Shapiro 
6477af9557fdSGregory Neil Shapiro 			fd = sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL);
6478af9557fdSGregory Neil Shapiro 			/* SM_ASSERT(fd >= 0); */
6479af9557fdSGregory Neil Shapiro 			if (fd >= 0)
6480af9557fdSGregory Neil Shapiro 				(void) close(fd);
6481af9557fdSGregory Neil Shapiro 		}
6482c2aa98e2SPeter Wemm 
648340266059SGregory Neil Shapiro 		(void) sm_signal(SIGINT, SIG_DFL);
648440266059SGregory Neil Shapiro 		(void) sm_signal(SIGHUP, SIG_DFL);
648540266059SGregory Neil Shapiro 		(void) sm_signal(SIGTERM, SIG_DFL);
6486c2aa98e2SPeter Wemm 		(void) umask(OldUmask);
6487c2aa98e2SPeter Wemm 		e->e_to = filename;
6488c2aa98e2SPeter Wemm 		ExitStat = EX_OK;
6489c2aa98e2SPeter Wemm 
6490c2aa98e2SPeter Wemm 		if (setjmp(CtxMailfileTimeout) != 0)
6491c2aa98e2SPeter Wemm 		{
649240266059SGregory Neil Shapiro 			RETURN(EX_TEMPFAIL);
6493c2aa98e2SPeter Wemm 		}
6494c2aa98e2SPeter Wemm 
6495c2aa98e2SPeter Wemm 		if (TimeOuts.to_fileopen > 0)
649640266059SGregory Neil Shapiro 			ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout,
649740266059SGregory Neil Shapiro 					 0);
6498c2aa98e2SPeter Wemm 		else
6499c2aa98e2SPeter Wemm 			ev = NULL;
6500c2aa98e2SPeter Wemm 
650140266059SGregory Neil Shapiro 		/* check file mode to see if set-user-ID */
650206f25ae9SGregory Neil Shapiro 		if (stat(targetfile, &stb) < 0)
6503c2aa98e2SPeter Wemm 			mode = FileMode;
650406f25ae9SGregory Neil Shapiro 		else
6505c2aa98e2SPeter Wemm 			mode = stb.st_mode;
6506c2aa98e2SPeter Wemm 
6507c2aa98e2SPeter Wemm 		/* limit the errors to those actually caused in the child */
6508c2aa98e2SPeter Wemm 		errno = 0;
6509c2aa98e2SPeter Wemm 		ExitStat = EX_OK;
6510c2aa98e2SPeter Wemm 
651106f25ae9SGregory Neil Shapiro 		/* Allow alias expansions to use the S_IS{U,G}ID bits */
651206f25ae9SGregory Neil Shapiro 		if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) ||
651306f25ae9SGregory Neil Shapiro 		    bitset(SFF_RUNASREALUID, sfflags))
6514c2aa98e2SPeter Wemm 		{
651540266059SGregory Neil Shapiro 			/* ignore set-user-ID and set-group-ID bits */
6516c2aa98e2SPeter Wemm 			mode &= ~(S_ISGID|S_ISUID);
651706f25ae9SGregory Neil Shapiro 			if (tTd(11, 20))
651840266059SGregory Neil Shapiro 				sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n");
6519c2aa98e2SPeter Wemm 		}
6520c2aa98e2SPeter Wemm 
652140266059SGregory Neil Shapiro 		/* we have to open the data file BEFORE setuid() */
6522c2aa98e2SPeter Wemm 		if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
6523c2aa98e2SPeter Wemm 		{
652440266059SGregory Neil Shapiro 			char *df = queuename(e, DATAFL_LETTER);
6525c2aa98e2SPeter Wemm 
652640266059SGregory Neil Shapiro 			e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df,
6527a7ec597cSGregory Neil Shapiro 					      SM_IO_RDONLY_B, NULL);
6528c2aa98e2SPeter Wemm 			if (e->e_dfp == NULL)
6529c2aa98e2SPeter Wemm 			{
6530c2aa98e2SPeter Wemm 				syserr("mailfile: Cannot open %s for %s from %s",
6531c2aa98e2SPeter Wemm 					df, e->e_to, e->e_from.q_paddr);
6532c2aa98e2SPeter Wemm 			}
6533c2aa98e2SPeter Wemm 		}
6534c2aa98e2SPeter Wemm 
6535c2aa98e2SPeter Wemm 		/* select a new user to run as */
6536c2aa98e2SPeter Wemm 		if (!bitset(SFF_RUNASREALUID, sfflags))
6537c2aa98e2SPeter Wemm 		{
6538c2aa98e2SPeter Wemm 			if (bitnset(M_SPECIFIC_UID, mailer->m_flags))
6539c2aa98e2SPeter Wemm 			{
6540c2aa98e2SPeter Wemm 				RealUserName = NULL;
6541e92d3f3fSGregory Neil Shapiro 				if (mailer->m_uid == NO_UID)
6542e92d3f3fSGregory Neil Shapiro 					RealUid = RunAsUid;
6543e92d3f3fSGregory Neil Shapiro 				else
6544c2aa98e2SPeter Wemm 					RealUid = mailer->m_uid;
654506f25ae9SGregory Neil Shapiro 				if (RunAsUid != 0 && RealUid != RunAsUid)
654606f25ae9SGregory Neil Shapiro 				{
654706f25ae9SGregory Neil Shapiro 					/* Only root can change the uid */
6548da7d7b9cSGregory Neil Shapiro 					syserr("mailfile: insufficient privileges to change uid, RunAsUid=%ld, RealUid=%ld",
6549da7d7b9cSGregory Neil Shapiro 						(long) RunAsUid, (long) RealUid);
655040266059SGregory Neil Shapiro 					RETURN(EX_TEMPFAIL);
655106f25ae9SGregory Neil Shapiro 				}
6552c2aa98e2SPeter Wemm 			}
6553c2aa98e2SPeter Wemm 			else if (bitset(S_ISUID, mode))
6554c2aa98e2SPeter Wemm 			{
6555c2aa98e2SPeter Wemm 				RealUserName = NULL;
6556c2aa98e2SPeter Wemm 				RealUid = stb.st_uid;
6557c2aa98e2SPeter Wemm 			}
6558c2aa98e2SPeter Wemm 			else if (ctladdr != NULL && ctladdr->q_uid != 0)
6559c2aa98e2SPeter Wemm 			{
6560c2aa98e2SPeter Wemm 				if (ctladdr->q_ruser != NULL)
6561c2aa98e2SPeter Wemm 					RealUserName = ctladdr->q_ruser;
6562c2aa98e2SPeter Wemm 				else
6563c2aa98e2SPeter Wemm 					RealUserName = ctladdr->q_user;
6564c2aa98e2SPeter Wemm 				RealUid = ctladdr->q_uid;
6565c2aa98e2SPeter Wemm 			}
6566e92d3f3fSGregory Neil Shapiro 			else if (mailer != NULL && mailer->m_uid != NO_UID)
6567c2aa98e2SPeter Wemm 			{
6568c2aa98e2SPeter Wemm 				RealUserName = DefUser;
6569c2aa98e2SPeter Wemm 				RealUid = mailer->m_uid;
6570c2aa98e2SPeter Wemm 			}
6571c2aa98e2SPeter Wemm 			else
6572c2aa98e2SPeter Wemm 			{
6573c2aa98e2SPeter Wemm 				RealUserName = DefUser;
6574c2aa98e2SPeter Wemm 				RealUid = DefUid;
6575c2aa98e2SPeter Wemm 			}
6576c2aa98e2SPeter Wemm 
6577c2aa98e2SPeter Wemm 			/* select a new group to run as */
6578c2aa98e2SPeter Wemm 			if (bitnset(M_SPECIFIC_UID, mailer->m_flags))
657906f25ae9SGregory Neil Shapiro 			{
6580e92d3f3fSGregory Neil Shapiro 				if (mailer->m_gid == NO_GID)
6581e92d3f3fSGregory Neil Shapiro 					RealGid = RunAsGid;
6582e92d3f3fSGregory Neil Shapiro 				else
6583c2aa98e2SPeter Wemm 					RealGid = mailer->m_gid;
658406f25ae9SGregory Neil Shapiro 				if (RunAsUid != 0 &&
658506f25ae9SGregory Neil Shapiro 				    (RealGid != getgid() ||
658606f25ae9SGregory Neil Shapiro 				     RealGid != getegid()))
658706f25ae9SGregory Neil Shapiro 				{
658806f25ae9SGregory Neil Shapiro 					/* Only root can change the gid */
6589da7d7b9cSGregory Neil Shapiro 					syserr("mailfile: insufficient privileges to change gid, RealGid=%ld, RunAsUid=%ld, gid=%ld, egid=%ld",
6590da7d7b9cSGregory Neil Shapiro 					       (long) RealGid, (long) RunAsUid,
6591da7d7b9cSGregory Neil Shapiro 					       (long) getgid(), (long) getegid());
659240266059SGregory Neil Shapiro 					RETURN(EX_TEMPFAIL);
659306f25ae9SGregory Neil Shapiro 				}
659406f25ae9SGregory Neil Shapiro 			}
6595c2aa98e2SPeter Wemm 			else if (bitset(S_ISGID, mode))
6596c2aa98e2SPeter Wemm 				RealGid = stb.st_gid;
659706f25ae9SGregory Neil Shapiro 			else if (ctladdr != NULL &&
659806f25ae9SGregory Neil Shapiro 				 ctladdr->q_uid == DefUid &&
659906f25ae9SGregory Neil Shapiro 				 ctladdr->q_gid == 0)
6600193538b7SGregory Neil Shapiro 			{
6601193538b7SGregory Neil Shapiro 				/*
6602193538b7SGregory Neil Shapiro 				**  Special case:  This means it is an
6603193538b7SGregory Neil Shapiro 				**  alias and we should act as DefaultUser.
6604193538b7SGregory Neil Shapiro 				**  See alias()'s comments.
6605193538b7SGregory Neil Shapiro 				*/
6606193538b7SGregory Neil Shapiro 
660706f25ae9SGregory Neil Shapiro 				RealGid = DefGid;
6608193538b7SGregory Neil Shapiro 				RealUserName = DefUser;
6609193538b7SGregory Neil Shapiro 			}
6610193538b7SGregory Neil Shapiro 			else if (ctladdr != NULL && ctladdr->q_uid != 0)
6611193538b7SGregory Neil Shapiro 				RealGid = ctladdr->q_gid;
6612e92d3f3fSGregory Neil Shapiro 			else if (mailer != NULL && mailer->m_gid != NO_GID)
6613c2aa98e2SPeter Wemm 				RealGid = mailer->m_gid;
6614c2aa98e2SPeter Wemm 			else
6615c2aa98e2SPeter Wemm 				RealGid = DefGid;
6616c2aa98e2SPeter Wemm 		}
6617c2aa98e2SPeter Wemm 
6618c2aa98e2SPeter Wemm 		/* last ditch */
6619c2aa98e2SPeter Wemm 		if (!bitset(SFF_ROOTOK, sfflags))
6620c2aa98e2SPeter Wemm 		{
6621c2aa98e2SPeter Wemm 			if (RealUid == 0)
6622c2aa98e2SPeter Wemm 				RealUid = DefUid;
6623c2aa98e2SPeter Wemm 			if (RealGid == 0)
6624c2aa98e2SPeter Wemm 				RealGid = DefGid;
6625c2aa98e2SPeter Wemm 		}
6626c2aa98e2SPeter Wemm 
6627c2aa98e2SPeter Wemm 		/* set group id list (needs /etc/group access) */
6628c2aa98e2SPeter Wemm 		if (RealUserName != NULL && !DontInitGroups)
6629c2aa98e2SPeter Wemm 		{
6630c2aa98e2SPeter Wemm 			if (initgroups(RealUserName, RealGid) == -1 && suidwarn)
663106f25ae9SGregory Neil Shapiro 			{
6632da7d7b9cSGregory Neil Shapiro 				syserr("mailfile: initgroups(%s, %ld) failed",
6633da7d7b9cSGregory Neil Shapiro 					RealUserName, (long) RealGid);
663440266059SGregory Neil Shapiro 				RETURN(EX_TEMPFAIL);
663506f25ae9SGregory Neil Shapiro 			}
6636c2aa98e2SPeter Wemm 		}
6637c2aa98e2SPeter Wemm 		else
6638c2aa98e2SPeter Wemm 		{
6639c2aa98e2SPeter Wemm 			GIDSET_T gidset[1];
6640c2aa98e2SPeter Wemm 
6641c2aa98e2SPeter Wemm 			gidset[0] = RealGid;
6642c2aa98e2SPeter Wemm 			if (setgroups(1, gidset) == -1 && suidwarn)
664306f25ae9SGregory Neil Shapiro 			{
6644c2aa98e2SPeter Wemm 				syserr("mailfile: setgroups() failed");
664540266059SGregory Neil Shapiro 				RETURN(EX_TEMPFAIL);
664606f25ae9SGregory Neil Shapiro 			}
6647c2aa98e2SPeter Wemm 		}
6648c2aa98e2SPeter Wemm 
664906f25ae9SGregory Neil Shapiro 		/*
665006f25ae9SGregory Neil Shapiro 		**  If you have a safe environment, go into it.
665106f25ae9SGregory Neil Shapiro 		*/
6652c2aa98e2SPeter Wemm 
665306f25ae9SGregory Neil Shapiro 		if (realfile != targetfile)
665406f25ae9SGregory Neil Shapiro 		{
6655605302a5SGregory Neil Shapiro 			char save;
6656605302a5SGregory Neil Shapiro 
6657605302a5SGregory Neil Shapiro 			save = *realfile;
665806f25ae9SGregory Neil Shapiro 			*realfile = '\0';
665906f25ae9SGregory Neil Shapiro 			if (tTd(11, 20))
666040266059SGregory Neil Shapiro 				sm_dprintf("mailfile: chroot %s\n", targetfile);
666106f25ae9SGregory Neil Shapiro 			if (chroot(targetfile) < 0)
6662c2aa98e2SPeter Wemm 			{
6663c2aa98e2SPeter Wemm 				syserr("mailfile: Cannot chroot(%s)",
666406f25ae9SGregory Neil Shapiro 				       targetfile);
666540266059SGregory Neil Shapiro 				RETURN(EX_CANTCREAT);
6666c2aa98e2SPeter Wemm 			}
6667605302a5SGregory Neil Shapiro 			*realfile = save;
6668c2aa98e2SPeter Wemm 		}
666906f25ae9SGregory Neil Shapiro 
667006f25ae9SGregory Neil Shapiro 		if (tTd(11, 40))
667140266059SGregory Neil Shapiro 			sm_dprintf("mailfile: deliver to %s\n", realfile);
667206f25ae9SGregory Neil Shapiro 
6673c2aa98e2SPeter Wemm 		if (chdir("/") < 0)
667406f25ae9SGregory Neil Shapiro 		{
6675c2aa98e2SPeter Wemm 			syserr("mailfile: cannot chdir(/)");
667640266059SGregory Neil Shapiro 			RETURN(EX_CANTCREAT);
667706f25ae9SGregory Neil Shapiro 		}
6678c2aa98e2SPeter Wemm 
6679c2aa98e2SPeter Wemm 		/* now reset the group and user ids */
6680c2aa98e2SPeter Wemm 		endpwent();
668140266059SGregory Neil Shapiro 		sm_mbdb_terminate();
6682c2aa98e2SPeter Wemm 		if (setgid(RealGid) < 0 && suidwarn)
668306f25ae9SGregory Neil Shapiro 		{
6684c2aa98e2SPeter Wemm 			syserr("mailfile: setgid(%ld) failed", (long) RealGid);
668540266059SGregory Neil Shapiro 			RETURN(EX_TEMPFAIL);
668606f25ae9SGregory Neil Shapiro 		}
6687c2aa98e2SPeter Wemm 		vendor_set_uid(RealUid);
6688c2aa98e2SPeter Wemm 		if (setuid(RealUid) < 0 && suidwarn)
668906f25ae9SGregory Neil Shapiro 		{
6690c2aa98e2SPeter Wemm 			syserr("mailfile: setuid(%ld) failed", (long) RealUid);
669140266059SGregory Neil Shapiro 			RETURN(EX_TEMPFAIL);
669206f25ae9SGregory Neil Shapiro 		}
669306f25ae9SGregory Neil Shapiro 
669406f25ae9SGregory Neil Shapiro 		if (tTd(11, 2))
6695da7d7b9cSGregory Neil Shapiro 			sm_dprintf("mailfile: running as r/euid=%ld/%ld, r/egid=%ld/%ld\n",
6696da7d7b9cSGregory Neil Shapiro 				(long) getuid(), (long) geteuid(),
6697da7d7b9cSGregory Neil Shapiro 				(long) getgid(), (long) getegid());
669806f25ae9SGregory Neil Shapiro 
6699c2aa98e2SPeter Wemm 
6700c2aa98e2SPeter Wemm 		/* move into some "safe" directory */
6701c2aa98e2SPeter Wemm 		if (mailer->m_execdir != NULL)
6702c2aa98e2SPeter Wemm 		{
6703c2aa98e2SPeter Wemm 			char *q;
6704c2aa98e2SPeter Wemm 
6705c2aa98e2SPeter Wemm 			for (p = mailer->m_execdir; p != NULL; p = q)
6706c2aa98e2SPeter Wemm 			{
6707c2aa98e2SPeter Wemm 				q = strchr(p, ':');
6708c2aa98e2SPeter Wemm 				if (q != NULL)
6709c2aa98e2SPeter Wemm 					*q = '\0';
6710d0cef73dSGregory Neil Shapiro 				expand(p, buf, sizeof(buf), e);
6711c2aa98e2SPeter Wemm 				if (q != NULL)
6712c2aa98e2SPeter Wemm 					*q++ = ':';
6713c2aa98e2SPeter Wemm 				if (tTd(11, 20))
671440266059SGregory Neil Shapiro 					sm_dprintf("mailfile: trydir %s\n",
671540266059SGregory Neil Shapiro 						   buf);
6716c2aa98e2SPeter Wemm 				if (buf[0] != '\0' && chdir(buf) >= 0)
6717c2aa98e2SPeter Wemm 					break;
6718c2aa98e2SPeter Wemm 			}
6719c2aa98e2SPeter Wemm 		}
6720c2aa98e2SPeter Wemm 
672106f25ae9SGregory Neil Shapiro 		/*
672206f25ae9SGregory Neil Shapiro 		**  Recheck the file after we have assumed the ID of the
672306f25ae9SGregory Neil Shapiro 		**  delivery user to make sure we can deliver to it as
672406f25ae9SGregory Neil Shapiro 		**  that user.  This is necessary if sendmail is running
672506f25ae9SGregory Neil Shapiro 		**  as root and the file is on an NFS mount which treats
672606f25ae9SGregory Neil Shapiro 		**  root as nobody.
672706f25ae9SGregory Neil Shapiro 		*/
672806f25ae9SGregory Neil Shapiro 
672906f25ae9SGregory Neil Shapiro #if HASLSTAT
673006f25ae9SGregory Neil Shapiro 		if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
673106f25ae9SGregory Neil Shapiro 			err = stat(realfile, &stb);
673206f25ae9SGregory Neil Shapiro 		else
673306f25ae9SGregory Neil Shapiro 			err = lstat(realfile, &stb);
673406f25ae9SGregory Neil Shapiro #else /* HASLSTAT */
673506f25ae9SGregory Neil Shapiro 		err = stat(realfile, &stb);
673606f25ae9SGregory Neil Shapiro #endif /* HASLSTAT */
673706f25ae9SGregory Neil Shapiro 
673806f25ae9SGregory Neil Shapiro 		if (err < 0)
673906f25ae9SGregory Neil Shapiro 		{
674006f25ae9SGregory Neil Shapiro 			stb.st_mode = ST_MODE_NOFILE;
674106f25ae9SGregory Neil Shapiro 			mode = FileMode;
674206f25ae9SGregory Neil Shapiro 			oflags |= O_CREAT|O_EXCL;
674306f25ae9SGregory Neil Shapiro 		}
674406f25ae9SGregory Neil Shapiro 		else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) ||
674506f25ae9SGregory Neil Shapiro 			 (!bitnset(DBS_FILEDELIVERYTOHARDLINK,
674606f25ae9SGregory Neil Shapiro 				   DontBlameSendmail) &&
674706f25ae9SGregory Neil Shapiro 			  stb.st_nlink != 1) ||
674806f25ae9SGregory Neil Shapiro 			 (realfile != targetfile && !S_ISREG(mode)))
674906f25ae9SGregory Neil Shapiro 			exit(EX_CANTCREAT);
675006f25ae9SGregory Neil Shapiro 		else
675106f25ae9SGregory Neil Shapiro 			mode = stb.st_mode;
675206f25ae9SGregory Neil Shapiro 
675306f25ae9SGregory Neil Shapiro 		if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
6754c2aa98e2SPeter Wemm 			sfflags |= SFF_NOSLINK;
675506f25ae9SGregory Neil Shapiro 		if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail))
6756c2aa98e2SPeter Wemm 			sfflags |= SFF_NOHLINK;
6757c2aa98e2SPeter Wemm 		sfflags &= ~SFF_OPENASROOT;
675806f25ae9SGregory Neil Shapiro 		f = safefopen(realfile, oflags, mode, sfflags);
6759c2aa98e2SPeter Wemm 		if (f == NULL)
6760c2aa98e2SPeter Wemm 		{
676106f25ae9SGregory Neil Shapiro 			if (transienterror(errno))
676206f25ae9SGregory Neil Shapiro 			{
676306f25ae9SGregory Neil Shapiro 				usrerr("454 4.3.0 cannot open %s: %s",
676406f25ae9SGregory Neil Shapiro 				       shortenstring(realfile, MAXSHORTSTR),
676540266059SGregory Neil Shapiro 				       sm_errstring(errno));
676640266059SGregory Neil Shapiro 				RETURN(EX_TEMPFAIL);
676706f25ae9SGregory Neil Shapiro 			}
676806f25ae9SGregory Neil Shapiro 			else
676906f25ae9SGregory Neil Shapiro 			{
677006f25ae9SGregory Neil Shapiro 				usrerr("554 5.3.0 cannot open %s: %s",
677106f25ae9SGregory Neil Shapiro 				       shortenstring(realfile, MAXSHORTSTR),
677240266059SGregory Neil Shapiro 				       sm_errstring(errno));
677340266059SGregory Neil Shapiro 				RETURN(EX_CANTCREAT);
6774c2aa98e2SPeter Wemm 			}
677506f25ae9SGregory Neil Shapiro 		}
677640266059SGregory Neil Shapiro 		if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
677740266059SGregory Neil Shapiro 		    &stb))
6778c2aa98e2SPeter Wemm 		{
677906f25ae9SGregory Neil Shapiro 			syserr("554 5.3.0 file changed after open");
678040266059SGregory Neil Shapiro 			RETURN(EX_CANTCREAT);
6781c2aa98e2SPeter Wemm 		}
678240266059SGregory Neil Shapiro 		if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0)
6783c2aa98e2SPeter Wemm 		{
678440266059SGregory Neil Shapiro 			syserr("554 5.3.0 cannot fstat %s",
678540266059SGregory Neil Shapiro 				sm_errstring(errno));
678640266059SGregory Neil Shapiro 			RETURN(EX_CANTCREAT);
6787c2aa98e2SPeter Wemm 		}
6788c2aa98e2SPeter Wemm 
678906f25ae9SGregory Neil Shapiro 		curoff = stb.st_size;
679006f25ae9SGregory Neil Shapiro 
6791c2aa98e2SPeter Wemm 		if (ev != NULL)
679240266059SGregory Neil Shapiro 			sm_clrevent(ev);
6793c2aa98e2SPeter Wemm 
6794d0cef73dSGregory Neil Shapiro 		memset(&mcibuf, '\0', sizeof(mcibuf));
6795c2aa98e2SPeter Wemm 		mcibuf.mci_mailer = mailer;
6796c2aa98e2SPeter Wemm 		mcibuf.mci_out = f;
6797c2aa98e2SPeter Wemm 		if (bitnset(M_7BITS, mailer->m_flags))
6798c2aa98e2SPeter Wemm 			mcibuf.mci_flags |= MCIF_7BIT;
6799c2aa98e2SPeter Wemm 
6800c2aa98e2SPeter Wemm 		/* clear out per-message flags from connection structure */
6801c2aa98e2SPeter Wemm 		mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);
6802c2aa98e2SPeter Wemm 
6803c2aa98e2SPeter Wemm 		if (bitset(EF_HAS8BIT, e->e_flags) &&
6804c2aa98e2SPeter Wemm 		    !bitset(EF_DONT_MIME, e->e_flags) &&
6805c2aa98e2SPeter Wemm 		    bitnset(M_7BITS, mailer->m_flags))
6806c2aa98e2SPeter Wemm 			mcibuf.mci_flags |= MCIF_CVT8TO7;
6807c2aa98e2SPeter Wemm 
6808c2aa98e2SPeter Wemm #if MIME7TO8
6809c2aa98e2SPeter Wemm 		if (bitnset(M_MAKE8BIT, mailer->m_flags) &&
6810c2aa98e2SPeter Wemm 		    !bitset(MCIF_7BIT, mcibuf.mci_flags) &&
6811c2aa98e2SPeter Wemm 		    (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
68122fb4f839SGregory Neil Shapiro 		    (SM_STRCASEEQ(p, "quoted-printable") ||
68132fb4f839SGregory Neil Shapiro 		     SM_STRCASEEQ(p, "base64")) &&
6814c2aa98e2SPeter Wemm 		    (p = hvalue("Content-Type", e->e_header)) != NULL)
6815c2aa98e2SPeter Wemm 		{
6816c2aa98e2SPeter Wemm 			/* may want to convert 7 -> 8 */
6817c2aa98e2SPeter Wemm 			/* XXX should really parse it here -- and use a class XXX */
681840266059SGregory Neil Shapiro 			if (sm_strncasecmp(p, "text/plain", 10) == 0 &&
6819c2aa98e2SPeter Wemm 			    (p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
6820c2aa98e2SPeter Wemm 				mcibuf.mci_flags |= MCIF_CVT7TO8;
6821c2aa98e2SPeter Wemm 		}
682206f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */
6823c2aa98e2SPeter Wemm 
68244e4196cbSGregory Neil Shapiro 		if (!putfromline(&mcibuf, e) ||
68254e4196cbSGregory Neil Shapiro 		    !(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER) ||
68264e4196cbSGregory Neil Shapiro 		    !(*e->e_putbody)(&mcibuf, e, NULL) ||
68274e4196cbSGregory Neil Shapiro 		    !putline("\n", &mcibuf) ||
68284e4196cbSGregory Neil Shapiro 		    (sm_io_flush(f, SM_TIME_DEFAULT) != 0 ||
682940266059SGregory Neil Shapiro 		    (SuperSafe != SAFE_NO &&
683040266059SGregory Neil Shapiro 		     fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) ||
68314e4196cbSGregory Neil Shapiro 		    sm_io_error(f)))
6832c2aa98e2SPeter Wemm 		{
6833c2aa98e2SPeter Wemm 			setstat(EX_IOERR);
683406f25ae9SGregory Neil Shapiro #if !NOFTRUNCATE
683540266059SGregory Neil Shapiro 			(void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
683640266059SGregory Neil Shapiro 					 curoff);
68375b0945b5SGregory Neil Shapiro #endif
6838c2aa98e2SPeter Wemm 		}
6839c2aa98e2SPeter Wemm 
6840c2aa98e2SPeter Wemm 		/* reset ISUID & ISGID bits for paranoid systems */
6841c2aa98e2SPeter Wemm #if HASFCHMOD
684240266059SGregory Neil Shapiro 		(void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
684340266059SGregory Neil Shapiro 			      (MODE_T) mode);
68442fb4f839SGregory Neil Shapiro #else
684506f25ae9SGregory Neil Shapiro 		(void) chmod(filename, (MODE_T) mode);
68462fb4f839SGregory Neil Shapiro #endif
684740266059SGregory Neil Shapiro 		if (sm_io_close(f, SM_TIME_DEFAULT) < 0)
684806f25ae9SGregory Neil Shapiro 			setstat(EX_IOERR);
684940266059SGregory Neil Shapiro 		(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
685006f25ae9SGregory Neil Shapiro 		(void) setuid(RealUid);
6851c2aa98e2SPeter Wemm 		exit(ExitStat);
6852c2aa98e2SPeter Wemm 		/* NOTREACHED */
6853c2aa98e2SPeter Wemm 	}
6854c2aa98e2SPeter Wemm 	else
6855c2aa98e2SPeter Wemm 	{
6856c2aa98e2SPeter Wemm 		/* parent -- wait for exit status */
6857c2aa98e2SPeter Wemm 		int st;
6858c2aa98e2SPeter Wemm 
6859c2aa98e2SPeter Wemm 		st = waitfor(pid);
6860c2aa98e2SPeter Wemm 		if (st == -1)
6861c2aa98e2SPeter Wemm 		{
6862c2aa98e2SPeter Wemm 			syserr("mailfile: %s: wait", mailer->m_name);
686306f25ae9SGregory Neil Shapiro 			return EX_SOFTWARE;
6864c2aa98e2SPeter Wemm 		}
6865c2aa98e2SPeter Wemm 		if (WIFEXITED(st))
686640266059SGregory Neil Shapiro 		{
686740266059SGregory Neil Shapiro 			errno = 0;
6868c2aa98e2SPeter Wemm 			return (WEXITSTATUS(st));
686940266059SGregory Neil Shapiro 		}
6870c2aa98e2SPeter Wemm 		else
6871c2aa98e2SPeter Wemm 		{
6872c2aa98e2SPeter Wemm 			syserr("mailfile: %s: child died on signal %d",
6873c2aa98e2SPeter Wemm 			       mailer->m_name, st);
687406f25ae9SGregory Neil Shapiro 			return EX_UNAVAILABLE;
6875c2aa98e2SPeter Wemm 		}
6876c2aa98e2SPeter Wemm 		/* NOTREACHED */
6877c2aa98e2SPeter Wemm 	}
6878c2aa98e2SPeter Wemm 	return EX_UNAVAILABLE;	/* avoid compiler warning on IRIX */
6879c2aa98e2SPeter Wemm }
6880c2aa98e2SPeter Wemm 
6881c2aa98e2SPeter Wemm static void
mailfiletimeout(ignore)6882b6bacd31SGregory Neil Shapiro mailfiletimeout(ignore)
6883b6bacd31SGregory Neil Shapiro 	int ignore;
6884c2aa98e2SPeter Wemm {
68858774250cSGregory Neil Shapiro 	/*
68868774250cSGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
68878774250cSGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
68888774250cSGregory Neil Shapiro 	**	DOING.
68898774250cSGregory Neil Shapiro 	*/
68908774250cSGregory Neil Shapiro 
68918774250cSGregory Neil Shapiro 	errno = ETIMEDOUT;
6892c2aa98e2SPeter Wemm 	longjmp(CtxMailfileTimeout, 1);
6893c2aa98e2SPeter Wemm }
68945b0945b5SGregory Neil Shapiro 
68955b0945b5SGregory Neil Shapiro #if DANE
68965b0945b5SGregory Neil Shapiro 
68975b0945b5SGregory Neil Shapiro /*
68985b0945b5SGregory Neil Shapiro **  GETMPORT -- return the port of a mailer
68995b0945b5SGregory Neil Shapiro **
69005b0945b5SGregory Neil Shapiro **	Parameters:
69015b0945b5SGregory Neil Shapiro **		m -- the mailer describing this host.
69025b0945b5SGregory Neil Shapiro **
69035b0945b5SGregory Neil Shapiro **	Returns:
69045b0945b5SGregory Neil Shapiro **		the port of the mailer if defined.
69055b0945b5SGregory Neil Shapiro **		0 otherwise
69065b0945b5SGregory Neil Shapiro **		<0 error
69075b0945b5SGregory Neil Shapiro */
69085b0945b5SGregory Neil Shapiro 
69095b0945b5SGregory Neil Shapiro static int getmport __P((MAILER *));
69105b0945b5SGregory Neil Shapiro 
69115b0945b5SGregory Neil Shapiro static int
getmport(m)69125b0945b5SGregory Neil Shapiro getmport(m)
69135b0945b5SGregory Neil Shapiro 	MAILER *m;
69145b0945b5SGregory Neil Shapiro {
69155b0945b5SGregory Neil Shapiro 	unsigned long ulval;
69165b0945b5SGregory Neil Shapiro 	char *buf, *ep;
69175b0945b5SGregory Neil Shapiro 
69185b0945b5SGregory Neil Shapiro 	if (m->m_port > 0)
69195b0945b5SGregory Neil Shapiro 		return m->m_port;
69205b0945b5SGregory Neil Shapiro 
69215b0945b5SGregory Neil Shapiro 	if (NULL == m->m_argv[0] ||NULL == m->m_argv[1])
69225b0945b5SGregory Neil Shapiro 		return -1;
69235b0945b5SGregory Neil Shapiro 	buf = m->m_argv[2];
69245b0945b5SGregory Neil Shapiro 	if (NULL == buf)
69255b0945b5SGregory Neil Shapiro 		return 0;
69265b0945b5SGregory Neil Shapiro 
69275b0945b5SGregory Neil Shapiro 	errno = 0;
69285b0945b5SGregory Neil Shapiro 	ulval = strtoul(buf, &ep, 0);
69295b0945b5SGregory Neil Shapiro 	if (buf[0] == '\0' || *ep != '\0')
69305b0945b5SGregory Neil Shapiro 		return -1;
69315b0945b5SGregory Neil Shapiro 	if (errno == ERANGE && ulval == ULONG_MAX)
69325b0945b5SGregory Neil Shapiro 		return -1;
69335b0945b5SGregory Neil Shapiro 	if (ulval > USHRT_MAX)
69345b0945b5SGregory Neil Shapiro 		return -1;
69355b0945b5SGregory Neil Shapiro 	m->m_port = (unsigned short) ulval;
69365b0945b5SGregory Neil Shapiro 	if (tTd(17, 30))
69375b0945b5SGregory Neil Shapiro 		sm_dprintf("getmport: mailer=%s, port=%d\n", m->m_name,
69385b0945b5SGregory Neil Shapiro 			m->m_port);
69395b0945b5SGregory Neil Shapiro 	return m->m_port;
69405b0945b5SGregory Neil Shapiro }
69415b0945b5SGregory Neil Shapiro # define GETMPORT(m) getmport(m)
69425b0945b5SGregory Neil Shapiro #else /* DANE */
69435b0945b5SGregory Neil Shapiro # define GETMPORT(m)	25
69445b0945b5SGregory Neil Shapiro #endif /* DANE */
69455b0945b5SGregory Neil Shapiro 
694640266059SGregory Neil Shapiro /*
6947*d39bd2c1SGregory Neil Shapiro **  HOSTSIGNATURE -- return the "signature" for a host (list).
6948c2aa98e2SPeter Wemm **
6949c2aa98e2SPeter Wemm **	The signature describes how we are going to send this -- it
6950c2aa98e2SPeter Wemm **	can be just the hostname (for non-Internet hosts) or can be
6951c2aa98e2SPeter Wemm **	an ordered list of MX hosts.
6952c2aa98e2SPeter Wemm **
6953c2aa98e2SPeter Wemm **	Parameters:
6954c2aa98e2SPeter Wemm **		m -- the mailer describing this host.
6955*d39bd2c1SGregory Neil Shapiro **		host -- the host name (can be a list).
6956*d39bd2c1SGregory Neil Shapiro **		ad -- DNSSEC: ad flag for lookup of host.
6957*d39bd2c1SGregory Neil Shapiro **		pqflags -- (pointer to) q_flags (can be NULL)
6958c2aa98e2SPeter Wemm **
6959c2aa98e2SPeter Wemm **	Returns:
6960c2aa98e2SPeter Wemm **		The signature for this host.
6961c2aa98e2SPeter Wemm **
6962c2aa98e2SPeter Wemm **	Side Effects:
6963c2aa98e2SPeter Wemm **		Can tweak the symbol table.
6964c2aa98e2SPeter Wemm */
696540266059SGregory Neil Shapiro 
696606f25ae9SGregory Neil Shapiro #define MAXHOSTSIGNATURE	8192	/* max len of hostsignature */
6967c2aa98e2SPeter Wemm 
696840266059SGregory Neil Shapiro char *
hostsignature(m,host,ad,pqflags)6969*d39bd2c1SGregory Neil Shapiro hostsignature(m, host, ad, pqflags)
6970c2aa98e2SPeter Wemm 	register MAILER *m;
6971c2aa98e2SPeter Wemm 	char *host;
69725b0945b5SGregory Neil Shapiro 	bool ad;
6973*d39bd2c1SGregory Neil Shapiro 	unsigned long *pqflags;
6974c2aa98e2SPeter Wemm {
6975c2aa98e2SPeter Wemm 	register char *p;
6976c2aa98e2SPeter Wemm 	register STAB *s;
697740266059SGregory Neil Shapiro 	time_t now;
697806f25ae9SGregory Neil Shapiro #if NAMED_BIND
697906f25ae9SGregory Neil Shapiro 	char sep = ':';
698006f25ae9SGregory Neil Shapiro 	char prevsep = ':';
6981c2aa98e2SPeter Wemm 	int i;
6982c2aa98e2SPeter Wemm 	int len;
6983c2aa98e2SPeter Wemm 	int nmx;
698406f25ae9SGregory Neil Shapiro 	int hl;
6985c2aa98e2SPeter Wemm 	char *hp;
6986c2aa98e2SPeter Wemm 	char *endp;
69872fb4f839SGregory Neil Shapiro 	char *lstr;
6988c2aa98e2SPeter Wemm 	int oldoptions = _res.options;
6989c2aa98e2SPeter Wemm 	char *mxhosts[MAXMXHOSTS + 1];
699040266059SGregory Neil Shapiro 	unsigned short mxprefs[MAXMXHOSTS + 1];
699106f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
6992*d39bd2c1SGregory Neil Shapiro 	int admx;
699306f25ae9SGregory Neil Shapiro 
699406f25ae9SGregory Neil Shapiro 	if (tTd(17, 3))
6995*d39bd2c1SGregory Neil Shapiro 		sm_dprintf("hostsignature: host=%s, ad=%d\n", host, ad);
6996*d39bd2c1SGregory Neil Shapiro 	if (pqflags != NULL && !ad)
6997*d39bd2c1SGregory Neil Shapiro 		*pqflags &= ~QMXSECURE;
699806f25ae9SGregory Neil Shapiro 
699906f25ae9SGregory Neil Shapiro 	/*
70008774250cSGregory Neil Shapiro 	**  If local delivery (and not remote), just return a constant.
700106f25ae9SGregory Neil Shapiro 	*/
700206f25ae9SGregory Neil Shapiro 
70038774250cSGregory Neil Shapiro 	if (bitnset(M_LOCALMAILER, m->m_flags) &&
700440266059SGregory Neil Shapiro 	    strcmp(m->m_mailer, "[IPC]") != 0 &&
700540266059SGregory Neil Shapiro 	    !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0))
700606f25ae9SGregory Neil Shapiro 		return "localhost";
7007c2aa98e2SPeter Wemm 
700813d88268SGregory Neil Shapiro 	/* an empty host does not have MX records */
700913d88268SGregory Neil Shapiro 	if (*host == '\0')
701013d88268SGregory Neil Shapiro 		return "_empty_";
701113d88268SGregory Neil Shapiro 
7012c2aa98e2SPeter Wemm 	/*
7013c2aa98e2SPeter Wemm 	**  Check to see if this uses IPC -- if not, it can't have MX records.
7014c2aa98e2SPeter Wemm 	*/
7015c2aa98e2SPeter Wemm 
701640266059SGregory Neil Shapiro 	if (strcmp(m->m_mailer, "[IPC]") != 0 ||
701740266059SGregory Neil Shapiro 	    CurEnv->e_sendmode == SM_DEFER)
7018c2aa98e2SPeter Wemm 	{
701940266059SGregory Neil Shapiro 		/* just an ordinary mailer or deferred mode */
7020c2aa98e2SPeter Wemm 		return host;
7021c2aa98e2SPeter Wemm 	}
702206f25ae9SGregory Neil Shapiro #if NETUNIX
702306f25ae9SGregory Neil Shapiro 	else if (m->m_argv[0] != NULL &&
702406f25ae9SGregory Neil Shapiro 		 strcmp(m->m_argv[0], "FILE") == 0)
702506f25ae9SGregory Neil Shapiro 	{
702606f25ae9SGregory Neil Shapiro 		/* rendezvous in the file system, no MX records */
702706f25ae9SGregory Neil Shapiro 		return host;
702806f25ae9SGregory Neil Shapiro 	}
702906f25ae9SGregory Neil Shapiro #endif /* NETUNIX */
7030c2aa98e2SPeter Wemm 
7031c2aa98e2SPeter Wemm 	/*
7032c2aa98e2SPeter Wemm 	**  Look it up in the symbol table.
7033c2aa98e2SPeter Wemm 	*/
7034c2aa98e2SPeter Wemm 
703540266059SGregory Neil Shapiro 	now = curtime();
7036c2aa98e2SPeter Wemm 	s = stab(host, ST_HOSTSIG, ST_ENTER);
703740266059SGregory Neil Shapiro 	if (s->s_hostsig.hs_sig != NULL)
703840266059SGregory Neil Shapiro 	{
703940266059SGregory Neil Shapiro 		if (s->s_hostsig.hs_exp >= now)
704006f25ae9SGregory Neil Shapiro 		{
704106f25ae9SGregory Neil Shapiro 			if (tTd(17, 3))
7042*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("hostsignature: stab(%s) found %s\n", host,
704340266059SGregory Neil Shapiro 					   s->s_hostsig.hs_sig);
704440266059SGregory Neil Shapiro 			return s->s_hostsig.hs_sig;
704506f25ae9SGregory Neil Shapiro 		}
7046c2aa98e2SPeter Wemm 
704740266059SGregory Neil Shapiro 		/* signature is expired: clear it */
704840266059SGregory Neil Shapiro 		sm_free(s->s_hostsig.hs_sig);
704940266059SGregory Neil Shapiro 		s->s_hostsig.hs_sig = NULL;
705040266059SGregory Neil Shapiro 	}
705140266059SGregory Neil Shapiro 
705240266059SGregory Neil Shapiro 	/* set default TTL */
705340266059SGregory Neil Shapiro 	s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL;
705440266059SGregory Neil Shapiro 
7055c2aa98e2SPeter Wemm 	/*
705640266059SGregory Neil Shapiro 	**  Not already there or expired -- create a signature.
7057c2aa98e2SPeter Wemm 	*/
7058c2aa98e2SPeter Wemm 
7059c2aa98e2SPeter Wemm #if NAMED_BIND
7060c2aa98e2SPeter Wemm 	if (ConfigLevel < 2)
7061c2aa98e2SPeter Wemm 		_res.options &= ~(RES_DEFNAMES | RES_DNSRCH);	/* XXX */
7062c2aa98e2SPeter Wemm 
7063c2aa98e2SPeter Wemm 	for (hp = host; hp != NULL; hp = endp)
7064c2aa98e2SPeter Wemm 	{
706506f25ae9SGregory Neil Shapiro # if NETINET6
706606f25ae9SGregory Neil Shapiro 		if (*hp == '[')
706706f25ae9SGregory Neil Shapiro 		{
706806f25ae9SGregory Neil Shapiro 			endp = strchr(hp + 1, ']');
7069c2aa98e2SPeter Wemm 			if (endp != NULL)
707006f25ae9SGregory Neil Shapiro 				endp = strpbrk(endp + 1, ":,");
707106f25ae9SGregory Neil Shapiro 		}
707206f25ae9SGregory Neil Shapiro 		else
707306f25ae9SGregory Neil Shapiro 			endp = strpbrk(hp, ":,");
707406f25ae9SGregory Neil Shapiro # else /* NETINET6 */
707506f25ae9SGregory Neil Shapiro 		endp = strpbrk(hp, ":,");
707606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
707706f25ae9SGregory Neil Shapiro 		if (endp != NULL)
707806f25ae9SGregory Neil Shapiro 		{
707906f25ae9SGregory Neil Shapiro 			sep = *endp;
7080c2aa98e2SPeter Wemm 			*endp = '\0';
708106f25ae9SGregory Neil Shapiro 		}
7082c2aa98e2SPeter Wemm 
7083c2aa98e2SPeter Wemm 		if (bitnset(M_NOMX, m->m_flags))
7084c2aa98e2SPeter Wemm 		{
7085c2aa98e2SPeter Wemm 			/* skip MX lookups */
7086c2aa98e2SPeter Wemm 			nmx = 1;
7087c2aa98e2SPeter Wemm 			mxhosts[0] = hp;
7088c2aa98e2SPeter Wemm 		}
7089c2aa98e2SPeter Wemm 		else
7090c2aa98e2SPeter Wemm 		{
7091c2aa98e2SPeter Wemm 			auto int rcode;
709240266059SGregory Neil Shapiro 			int ttl;
7093c2aa98e2SPeter Wemm 
7094*d39bd2c1SGregory Neil Shapiro 			admx = 0;
70955b0945b5SGregory Neil Shapiro 			nmx = getmxrr(hp, mxhosts, mxprefs,
7096*d39bd2c1SGregory Neil Shapiro 				      DROPLOCALHOST|(ad ? ISAD :0)|
7097*d39bd2c1SGregory Neil Shapiro 				      ((NULL == endp) ? TRYFALLBACK : 0),
7098*d39bd2c1SGregory Neil Shapiro 				      &rcode, &ttl, GETMPORT(m), &admx);
7099c2aa98e2SPeter Wemm 			if (nmx <= 0)
7100c2aa98e2SPeter Wemm 			{
710113058a91SGregory Neil Shapiro 				int save_errno;
7102c2aa98e2SPeter Wemm 				register MCI *mci;
7103c2aa98e2SPeter Wemm 
7104c2aa98e2SPeter Wemm 				/* update the connection info for this host */
710513058a91SGregory Neil Shapiro 				save_errno = errno;
7106c2aa98e2SPeter Wemm 				mci = mci_get(hp, m);
710713058a91SGregory Neil Shapiro 				mci->mci_errno = save_errno;
7108c2aa98e2SPeter Wemm 				mci->mci_herrno = h_errno;
7109193538b7SGregory Neil Shapiro 				mci->mci_lastuse = now;
71105b0945b5SGregory Neil Shapiro 				if (nmx == NULLMX)
71112fb4f839SGregory Neil Shapiro 					mci_setstat(mci, rcode, ESCNULLMXRCPT,
71122fb4f839SGregory Neil Shapiro 						    ERRNULLMX);
71135b0945b5SGregory Neil Shapiro 				else if (rcode == EX_NOHOST)
711406f25ae9SGregory Neil Shapiro 					mci_setstat(mci, rcode, "5.1.2",
711506f25ae9SGregory Neil Shapiro 						    "550 Host unknown");
711606f25ae9SGregory Neil Shapiro 				else
7117c2aa98e2SPeter Wemm 					mci_setstat(mci, rcode, NULL, NULL);
7118c2aa98e2SPeter Wemm 
7119c2aa98e2SPeter Wemm 				/* use the original host name as signature */
7120c2aa98e2SPeter Wemm 				nmx = 1;
7121c2aa98e2SPeter Wemm 				mxhosts[0] = hp;
7122c2aa98e2SPeter Wemm 			}
7123*d39bd2c1SGregory Neil Shapiro 
7124*d39bd2c1SGregory Neil Shapiro 			/*
7125*d39bd2c1SGregory Neil Shapiro 			**  NOTE: this sets QMXSECURE if the ad flags is set
7126*d39bd2c1SGregory Neil Shapiro 			**  for at least one host in the host list. XXX
7127*d39bd2c1SGregory Neil Shapiro 			*/
7128*d39bd2c1SGregory Neil Shapiro 
7129*d39bd2c1SGregory Neil Shapiro 			if (pqflags != NULL && admx)
7130*d39bd2c1SGregory Neil Shapiro 				*pqflags |= QMXSECURE;
713106f25ae9SGregory Neil Shapiro 			if (tTd(17, 3))
7132*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("hostsignature: host=%s, getmxrr=%d, mxhosts[0]=%s, admx=%d\n",
7133*d39bd2c1SGregory Neil Shapiro 					   hp, nmx, mxhosts[0], admx);
713440266059SGregory Neil Shapiro 
713540266059SGregory Neil Shapiro 			/*
713640266059SGregory Neil Shapiro 			**  Set new TTL: we use only one!
713740266059SGregory Neil Shapiro 			**	We could try to use the minimum instead.
713840266059SGregory Neil Shapiro 			*/
713940266059SGregory Neil Shapiro 
714040266059SGregory Neil Shapiro 			s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL);
7141c2aa98e2SPeter Wemm 		}
7142c2aa98e2SPeter Wemm 
7143c2aa98e2SPeter Wemm 		len = 0;
7144c2aa98e2SPeter Wemm 		for (i = 0; i < nmx; i++)
7145c2aa98e2SPeter Wemm 			len += strlen(mxhosts[i]) + 1;
714640266059SGregory Neil Shapiro 		if (s->s_hostsig.hs_sig != NULL)
714740266059SGregory Neil Shapiro 			len += strlen(s->s_hostsig.hs_sig) + 1;
7148*d39bd2c1SGregory Neil Shapiro # if DANE && HSMARKS
7149*d39bd2c1SGregory Neil Shapiro 		if (admx && DANE_SEC(Dane))
7150*d39bd2c1SGregory Neil Shapiro 			len += nmx;
7151*d39bd2c1SGregory Neil Shapiro # endif
715240266059SGregory Neil Shapiro 		if (len < 0 || len >= MAXHOSTSIGNATURE)
715306f25ae9SGregory Neil Shapiro 		{
715406f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d",
715506f25ae9SGregory Neil Shapiro 				  host, MAXHOSTSIGNATURE, len);
715606f25ae9SGregory Neil Shapiro 			len = MAXHOSTSIGNATURE;
715706f25ae9SGregory Neil Shapiro 		}
715840266059SGregory Neil Shapiro 		p = sm_pmalloc_x(len);
715940266059SGregory Neil Shapiro 		if (s->s_hostsig.hs_sig != NULL)
7160c2aa98e2SPeter Wemm 		{
716140266059SGregory Neil Shapiro 			(void) sm_strlcpy(p, s->s_hostsig.hs_sig, len);
716240266059SGregory Neil Shapiro 			sm_free(s->s_hostsig.hs_sig); /* XXX */
716340266059SGregory Neil Shapiro 			s->s_hostsig.hs_sig = p;
716406f25ae9SGregory Neil Shapiro 			hl = strlen(p);
716506f25ae9SGregory Neil Shapiro 			p += hl;
716606f25ae9SGregory Neil Shapiro 			*p++ = prevsep;
716706f25ae9SGregory Neil Shapiro 			len -= hl + 1;
7168c2aa98e2SPeter Wemm 		}
7169c2aa98e2SPeter Wemm 		else
717040266059SGregory Neil Shapiro 			s->s_hostsig.hs_sig = p;
7171c2aa98e2SPeter Wemm 		for (i = 0; i < nmx; i++)
7172c2aa98e2SPeter Wemm 		{
717306f25ae9SGregory Neil Shapiro 			hl = strlen(mxhosts[i]);
7174*d39bd2c1SGregory Neil Shapiro 			if (len <= 1 ||
7175*d39bd2c1SGregory Neil Shapiro # if DANE && HSMARKS
7176*d39bd2c1SGregory Neil Shapiro 			    len - 1 < (hl + ((admx && DANE_SEC(Dane)) ? 1 : 0))
7177*d39bd2c1SGregory Neil Shapiro # else
7178*d39bd2c1SGregory Neil Shapiro 			    len - 1 < hl
7179*d39bd2c1SGregory Neil Shapiro # endif
7180*d39bd2c1SGregory Neil Shapiro 				)
718106f25ae9SGregory Neil Shapiro 			{
718206f25ae9SGregory Neil Shapiro 				/* force to drop out of outer loop */
718306f25ae9SGregory Neil Shapiro 				len = -1;
718406f25ae9SGregory Neil Shapiro 				break;
7185c2aa98e2SPeter Wemm 			}
718606f25ae9SGregory Neil Shapiro 			if (i != 0)
718706f25ae9SGregory Neil Shapiro 			{
718806f25ae9SGregory Neil Shapiro 				if (mxprefs[i] == mxprefs[i - 1])
718906f25ae9SGregory Neil Shapiro 					*p++ = ',';
719006f25ae9SGregory Neil Shapiro 				else
719106f25ae9SGregory Neil Shapiro 					*p++ = ':';
719206f25ae9SGregory Neil Shapiro 				len--;
719306f25ae9SGregory Neil Shapiro 			}
7194*d39bd2c1SGregory Neil Shapiro # if DANE && HSMARKS
7195*d39bd2c1SGregory Neil Shapiro 			if (admx && DANE_SEC(Dane))
7196*d39bd2c1SGregory Neil Shapiro 			{
7197*d39bd2c1SGregory Neil Shapiro 				*p++ = HSM_AD;
7198*d39bd2c1SGregory Neil Shapiro 				len--;
7199*d39bd2c1SGregory Neil Shapiro 			}
7200*d39bd2c1SGregory Neil Shapiro # endif
720140266059SGregory Neil Shapiro 			(void) sm_strlcpy(p, mxhosts[i], len);
720206f25ae9SGregory Neil Shapiro 			p += hl;
720306f25ae9SGregory Neil Shapiro 			len -= hl;
720406f25ae9SGregory Neil Shapiro 		}
720506f25ae9SGregory Neil Shapiro 
720606f25ae9SGregory Neil Shapiro 		/*
720706f25ae9SGregory Neil Shapiro 		**  break out of loop if len exceeded MAXHOSTSIGNATURE
720806f25ae9SGregory Neil Shapiro 		**  because we won't have more space for further hosts
720906f25ae9SGregory Neil Shapiro 		**  anyway (separated by : in the .cf file).
721006f25ae9SGregory Neil Shapiro 		*/
721106f25ae9SGregory Neil Shapiro 
721206f25ae9SGregory Neil Shapiro 		if (len < 0)
721306f25ae9SGregory Neil Shapiro 			break;
7214c2aa98e2SPeter Wemm 		if (endp != NULL)
721506f25ae9SGregory Neil Shapiro 			*endp++ = sep;
721606f25ae9SGregory Neil Shapiro 		prevsep = sep;
7217c2aa98e2SPeter Wemm 	}
72182fb4f839SGregory Neil Shapiro 	lstr = makelower_a(&s->s_hostsig.hs_sig, NULL);
72192fb4f839SGregory Neil Shapiro 	ASSIGN_IFDIFF(s->s_hostsig.hs_sig, lstr);
7220c2aa98e2SPeter Wemm 	if (ConfigLevel < 2)
7221c2aa98e2SPeter Wemm 		_res.options = oldoptions;
722206f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */
7223c2aa98e2SPeter Wemm 	/* not using BIND -- the signature is just the host name */
722440266059SGregory Neil Shapiro 	/*
722540266059SGregory Neil Shapiro 	**  'host' points to storage that will be freed after we are
722640266059SGregory Neil Shapiro 	**  done processing the current envelope, so we copy it.
722740266059SGregory Neil Shapiro 	*/
722840266059SGregory Neil Shapiro 	s->s_hostsig.hs_sig = sm_pstrdup_x(host);
722906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
7230c2aa98e2SPeter Wemm 	if (tTd(17, 1))
7231*d39bd2c1SGregory Neil Shapiro 		sm_dprintf("hostsignature: host=%s, result=%s\n", host, s->s_hostsig.hs_sig);
723240266059SGregory Neil Shapiro 	return s->s_hostsig.hs_sig;
7233c2aa98e2SPeter Wemm }
7234*d39bd2c1SGregory Neil Shapiro 
723540266059SGregory Neil Shapiro /*
723606f25ae9SGregory Neil Shapiro **  PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array.
723706f25ae9SGregory Neil Shapiro **
723806f25ae9SGregory Neil Shapiro **	The signature describes how we are going to send this -- it
723906f25ae9SGregory Neil Shapiro **	can be just the hostname (for non-Internet hosts) or can be
724006f25ae9SGregory Neil Shapiro **	an ordered list of MX hosts which must be randomized for equal
724106f25ae9SGregory Neil Shapiro **	MX preference values.
724206f25ae9SGregory Neil Shapiro **
724306f25ae9SGregory Neil Shapiro **	Parameters:
724406f25ae9SGregory Neil Shapiro **		sig -- the host signature.
724506f25ae9SGregory Neil Shapiro **		mxhosts -- array to populate.
724640266059SGregory Neil Shapiro **		mailer -- mailer.
724706f25ae9SGregory Neil Shapiro **
724806f25ae9SGregory Neil Shapiro **	Returns:
724906f25ae9SGregory Neil Shapiro **		The number of hosts inserted into mxhosts array.
725006f25ae9SGregory Neil Shapiro **
7251*d39bd2c1SGregory Neil Shapiro **	NOTES:
7252*d39bd2c1SGregory Neil Shapiro **		mxhosts must have at least MAXMXHOSTS entries
7253*d39bd2c1SGregory Neil Shapiro **		mxhosts[] will point to elements in sig --
7254*d39bd2c1SGregory Neil Shapiro **		hence any changes to mxhosts[] will modify sig!
7255*d39bd2c1SGregory Neil Shapiro **
725606f25ae9SGregory Neil Shapiro **	Side Effects:
725706f25ae9SGregory Neil Shapiro **		Randomizes equal MX preference hosts in mxhosts.
725806f25ae9SGregory Neil Shapiro */
725906f25ae9SGregory Neil Shapiro 
726006f25ae9SGregory Neil Shapiro static int
parse_hostsignature(sig,mxhosts,mailer,mxads)7261*d39bd2c1SGregory Neil Shapiro parse_hostsignature(sig, mxhosts, mailer
7262*d39bd2c1SGregory Neil Shapiro #if DANE
7263*d39bd2c1SGregory Neil Shapiro 	, mxads
7264*d39bd2c1SGregory Neil Shapiro #endif
7265*d39bd2c1SGregory Neil Shapiro 	)
726606f25ae9SGregory Neil Shapiro 	char *sig;
726706f25ae9SGregory Neil Shapiro 	char **mxhosts;
726806f25ae9SGregory Neil Shapiro 	MAILER *mailer;
7269*d39bd2c1SGregory Neil Shapiro #if DANE
7270*d39bd2c1SGregory Neil Shapiro 	BITMAP256 mxads;
7271*d39bd2c1SGregory Neil Shapiro #endif
727206f25ae9SGregory Neil Shapiro {
727340266059SGregory Neil Shapiro 	unsigned short curpref = 0;
727440266059SGregory Neil Shapiro 	int nmx = 0, i, j;	/* NOTE: i, j, and nmx must have same type */
727506f25ae9SGregory Neil Shapiro 	char *hp, *endp;
727640266059SGregory Neil Shapiro 	unsigned short prefer[MAXMXHOSTS];
727706f25ae9SGregory Neil Shapiro 	long rndm[MAXMXHOSTS];
727806f25ae9SGregory Neil Shapiro 
7279*d39bd2c1SGregory Neil Shapiro #if DANE
7280*d39bd2c1SGregory Neil Shapiro 	clrbitmap(mxads);
7281*d39bd2c1SGregory Neil Shapiro #endif
728206f25ae9SGregory Neil Shapiro 	for (hp = sig; hp != NULL; hp = endp)
728306f25ae9SGregory Neil Shapiro 	{
728406f25ae9SGregory Neil Shapiro 		char sep = ':';
728506f25ae9SGregory Neil Shapiro 
7286*d39bd2c1SGregory Neil Shapiro 		FIX_MXHOSTS(hp, endp, sep);
7287*d39bd2c1SGregory Neil Shapiro #if HSMARKS
7288*d39bd2c1SGregory Neil Shapiro 		if (HSM_AD == *hp)
728906f25ae9SGregory Neil Shapiro 		{
7290*d39bd2c1SGregory Neil Shapiro 			MXADS_SET(mxads, nmx);
7291*d39bd2c1SGregory Neil Shapiro 			mxhosts[nmx] = hp + 1;
729206f25ae9SGregory Neil Shapiro 		}
729306f25ae9SGregory Neil Shapiro 		else
7294*d39bd2c1SGregory Neil Shapiro #endif
729506f25ae9SGregory Neil Shapiro 		mxhosts[nmx] = hp;
729606f25ae9SGregory Neil Shapiro 		prefer[nmx] = curpref;
729706f25ae9SGregory Neil Shapiro 		if (mci_match(hp, mailer))
729806f25ae9SGregory Neil Shapiro 			rndm[nmx] = 0;
729906f25ae9SGregory Neil Shapiro 		else
730006f25ae9SGregory Neil Shapiro 			rndm[nmx] = get_random();
730106f25ae9SGregory Neil Shapiro 
730206f25ae9SGregory Neil Shapiro 		if (endp != NULL)
730306f25ae9SGregory Neil Shapiro 		{
730406f25ae9SGregory Neil Shapiro 			/*
730506f25ae9SGregory Neil Shapiro 			**  Since we don't have the original MX prefs,
730606f25ae9SGregory Neil Shapiro 			**  make our own.  If the separator is a ':', that
730706f25ae9SGregory Neil Shapiro 			**  means the preference for the next host will be
730806f25ae9SGregory Neil Shapiro 			**  higher than this one, so simply increment curpref.
730906f25ae9SGregory Neil Shapiro 			*/
731006f25ae9SGregory Neil Shapiro 
731106f25ae9SGregory Neil Shapiro 			if (sep == ':')
731206f25ae9SGregory Neil Shapiro 				curpref++;
731306f25ae9SGregory Neil Shapiro 
731406f25ae9SGregory Neil Shapiro 			*endp++ = sep;
731506f25ae9SGregory Neil Shapiro 		}
731606f25ae9SGregory Neil Shapiro 		if (++nmx >= MAXMXHOSTS)
731706f25ae9SGregory Neil Shapiro 			break;
731806f25ae9SGregory Neil Shapiro 	}
731906f25ae9SGregory Neil Shapiro 
732006f25ae9SGregory Neil Shapiro 	/* sort the records using the random factor for equal preferences */
732106f25ae9SGregory Neil Shapiro 	for (i = 0; i < nmx; i++)
732206f25ae9SGregory Neil Shapiro 	{
732306f25ae9SGregory Neil Shapiro 		for (j = i + 1; j < nmx; j++)
732406f25ae9SGregory Neil Shapiro 		{
732506f25ae9SGregory Neil Shapiro 			/*
732606f25ae9SGregory Neil Shapiro 			**  List is already sorted by MX preference, only
732706f25ae9SGregory Neil Shapiro 			**  need to look for equal preference MX records
732806f25ae9SGregory Neil Shapiro 			*/
732906f25ae9SGregory Neil Shapiro 
733006f25ae9SGregory Neil Shapiro 			if (prefer[i] < prefer[j])
733106f25ae9SGregory Neil Shapiro 				break;
733206f25ae9SGregory Neil Shapiro 
733306f25ae9SGregory Neil Shapiro 			if (prefer[i] > prefer[j] ||
733406f25ae9SGregory Neil Shapiro 			    (prefer[i] == prefer[j] && rndm[i] > rndm[j]))
733506f25ae9SGregory Neil Shapiro 			{
733640266059SGregory Neil Shapiro 				register unsigned short tempp;
733706f25ae9SGregory Neil Shapiro 				register long tempr;
733806f25ae9SGregory Neil Shapiro 				register char *temp1;
733906f25ae9SGregory Neil Shapiro 
734006f25ae9SGregory Neil Shapiro 				tempp = prefer[i];
734106f25ae9SGregory Neil Shapiro 				prefer[i] = prefer[j];
734206f25ae9SGregory Neil Shapiro 				prefer[j] = tempp;
734306f25ae9SGregory Neil Shapiro 				temp1 = mxhosts[i];
734406f25ae9SGregory Neil Shapiro 				mxhosts[i] = mxhosts[j];
734506f25ae9SGregory Neil Shapiro 				mxhosts[j] = temp1;
734606f25ae9SGregory Neil Shapiro 				tempr = rndm[i];
734706f25ae9SGregory Neil Shapiro 				rndm[i] = rndm[j];
734806f25ae9SGregory Neil Shapiro 				rndm[j] = tempr;
734906f25ae9SGregory Neil Shapiro 			}
735006f25ae9SGregory Neil Shapiro 		}
735106f25ae9SGregory Neil Shapiro 	}
735206f25ae9SGregory Neil Shapiro 	return nmx;
735306f25ae9SGregory Neil Shapiro }
735406f25ae9SGregory Neil Shapiro 
735506f25ae9SGregory Neil Shapiro #if STARTTLS
735606f25ae9SGregory Neil Shapiro static SSL_CTX	*clt_ctx = NULL;
735740266059SGregory Neil Shapiro static bool	tls_ok_clt = true;
7358*d39bd2c1SGregory Neil Shapiro # if DANE
7359*d39bd2c1SGregory Neil Shapiro static bool	ctx_dane_enabled = false;
7360*d39bd2c1SGregory Neil Shapiro # endif
736106f25ae9SGregory Neil Shapiro 
736240266059SGregory Neil Shapiro /*
736340266059SGregory Neil Shapiro **  SETCLTTLS -- client side TLS: allow/disallow.
736440266059SGregory Neil Shapiro **
736540266059SGregory Neil Shapiro **	Parameters:
736640266059SGregory Neil Shapiro **		tls_ok -- should tls be done?
736740266059SGregory Neil Shapiro **
736840266059SGregory Neil Shapiro **	Returns:
736940266059SGregory Neil Shapiro **		none.
737040266059SGregory Neil Shapiro **
737140266059SGregory Neil Shapiro **	Side Effects:
737240266059SGregory Neil Shapiro **		sets tls_ok_clt (static variable in this module)
737340266059SGregory Neil Shapiro */
737440266059SGregory Neil Shapiro 
737540266059SGregory Neil Shapiro void
setclttls(tls_ok)737640266059SGregory Neil Shapiro setclttls(tls_ok)
737740266059SGregory Neil Shapiro 	bool tls_ok;
737840266059SGregory Neil Shapiro {
737940266059SGregory Neil Shapiro 	tls_ok_clt = tls_ok;
738040266059SGregory Neil Shapiro 	return;
738140266059SGregory Neil Shapiro }
7382*d39bd2c1SGregory Neil Shapiro 
738340266059SGregory Neil Shapiro /*
738406f25ae9SGregory Neil Shapiro **  INITCLTTLS -- initialize client side TLS
738506f25ae9SGregory Neil Shapiro **
738606f25ae9SGregory Neil Shapiro **	Parameters:
7387*d39bd2c1SGregory Neil Shapiro **		tls_ok -- should TLS initialization be done?
738806f25ae9SGregory Neil Shapiro **
738906f25ae9SGregory Neil Shapiro **	Returns:
739006f25ae9SGregory Neil Shapiro **		succeeded?
739140266059SGregory Neil Shapiro **
739240266059SGregory Neil Shapiro **	Side Effects:
7393*d39bd2c1SGregory Neil Shapiro **		sets tls_ok_clt, ctx_dane_enabled (static variables
7394*d39bd2c1SGregory Neil Shapiro **		in this module)
739506f25ae9SGregory Neil Shapiro */
739606f25ae9SGregory Neil Shapiro 
739706f25ae9SGregory Neil Shapiro bool
initclttls(tls_ok)739840266059SGregory Neil Shapiro initclttls(tls_ok)
739940266059SGregory Neil Shapiro 	bool tls_ok;
740006f25ae9SGregory Neil Shapiro {
740140266059SGregory Neil Shapiro 	if (!tls_ok_clt)
740240266059SGregory Neil Shapiro 		return false;
740340266059SGregory Neil Shapiro 	tls_ok_clt = tls_ok;
740440266059SGregory Neil Shapiro 	if (!tls_ok_clt)
740540266059SGregory Neil Shapiro 		return false;
740606f25ae9SGregory Neil Shapiro 	if (clt_ctx != NULL)
740740266059SGregory Neil Shapiro 		return true;	/* already done */
74089bd497b8SGregory Neil Shapiro 	tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, Clt_SSL_Options, false,
74099bd497b8SGregory Neil Shapiro 			CltCertFile, CltKeyFile,
74105b0945b5SGregory Neil Shapiro # if _FFR_CLIENTCA
74115b0945b5SGregory Neil Shapiro 			(CltCACertPath != NULL) ? CltCACertPath :
74125b0945b5SGregory Neil Shapiro # endif
74135b0945b5SGregory Neil Shapiro 				CACertPath,
74145b0945b5SGregory Neil Shapiro # if _FFR_CLIENTCA
74155b0945b5SGregory Neil Shapiro 			(CltCACertFile != NULL) ? CltCACertFile :
74165b0945b5SGregory Neil Shapiro # endif
74175b0945b5SGregory Neil Shapiro 				CACertFile,
74185b0945b5SGregory Neil Shapiro 			DHParams);
7419*d39bd2c1SGregory Neil Shapiro # if _FFR_TESTS
7420*d39bd2c1SGregory Neil Shapiro 	if (tls_ok_clt && tTd(90, 104))
7421*d39bd2c1SGregory Neil Shapiro 	{
7422*d39bd2c1SGregory Neil Shapiro 		sm_dprintf("test=simulate initclttls error\n");
7423*d39bd2c1SGregory Neil Shapiro 		tls_ok_clt = false;
7424*d39bd2c1SGregory Neil Shapiro 	}
7425*d39bd2c1SGregory Neil Shapiro # endif /* _FFR_TESTS */
7426*d39bd2c1SGregory Neil Shapiro # if DANE
7427*d39bd2c1SGregory Neil Shapiro 	if (tls_ok_clt && CHK_DANE(Dane))
7428*d39bd2c1SGregory Neil Shapiro 	{
7429*d39bd2c1SGregory Neil Shapiro #  if HAVE_SSL_CTX_dane_enable
7430*d39bd2c1SGregory Neil Shapiro 		int r;
7431*d39bd2c1SGregory Neil Shapiro 
7432*d39bd2c1SGregory Neil Shapiro 		r = SSL_CTX_dane_enable(clt_ctx);
7433*d39bd2c1SGregory Neil Shapiro #   if _FFR_TESTS
7434*d39bd2c1SGregory Neil Shapiro 		if (tTd(90, 103))
7435*d39bd2c1SGregory Neil Shapiro 		{
7436*d39bd2c1SGregory Neil Shapiro 			sm_dprintf("test=simulate SSL_CTX_dane_enable error\n");
7437*d39bd2c1SGregory Neil Shapiro #    if defined(SSL_F_DANE_CTX_ENABLE)
7438*d39bd2c1SGregory Neil Shapiro 			SSLerr(SSL_F_DANE_CTX_ENABLE, ERR_R_MALLOC_FAILURE);
7439*d39bd2c1SGregory Neil Shapiro #    endif
7440*d39bd2c1SGregory Neil Shapiro 			r = -1;
7441*d39bd2c1SGregory Neil Shapiro 		}
7442*d39bd2c1SGregory Neil Shapiro #   endif /* _FFR_TESTS */
7443*d39bd2c1SGregory Neil Shapiro 		ctx_dane_enabled = (r > 0);
7444*d39bd2c1SGregory Neil Shapiro 		if (r <= 0)
7445*d39bd2c1SGregory Neil Shapiro 		{
7446*d39bd2c1SGregory Neil Shapiro 			if (LogLevel > 1)
7447*d39bd2c1SGregory Neil Shapiro 				sm_syslog(LOG_ERR, NOQID,
7448*d39bd2c1SGregory Neil Shapiro 					"SSL_CTX_dane_enable=%d", r);
7449*d39bd2c1SGregory Neil Shapiro 			tlslogerr(LOG_ERR, 7, "init_client");
7450*d39bd2c1SGregory Neil Shapiro 		}
7451*d39bd2c1SGregory Neil Shapiro 		else if (LogLevel > 13)
7452*d39bd2c1SGregory Neil Shapiro 			sm_syslog(LOG_DEBUG, NOQID,
7453*d39bd2c1SGregory Neil Shapiro 				"SSL_CTX_dane_enable=%d", r);
7454*d39bd2c1SGregory Neil Shapiro #  else
7455*d39bd2c1SGregory Neil Shapiro 		ctx_dane_enabled = false;
7456*d39bd2c1SGregory Neil Shapiro #  endif /* HAVE_SSL_CTX_dane_enable */
7457*d39bd2c1SGregory Neil Shapiro 	}
7458*d39bd2c1SGregory Neil Shapiro 	if (tTd(90, 90))
7459*d39bd2c1SGregory Neil Shapiro 		sm_dprintf("func=initclttls, ctx_dane_enabled=%d\n", ctx_dane_enabled);
7460*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
7461*d39bd2c1SGregory Neil Shapiro 
746240266059SGregory Neil Shapiro 	return tls_ok_clt;
746306f25ae9SGregory Neil Shapiro }
746406f25ae9SGregory Neil Shapiro 
746540266059SGregory Neil Shapiro /*
746606f25ae9SGregory Neil Shapiro **  STARTTLS -- try to start secure connection (client side)
746706f25ae9SGregory Neil Shapiro **
746806f25ae9SGregory Neil Shapiro **	Parameters:
746906f25ae9SGregory Neil Shapiro **		m -- the mailer.
747006f25ae9SGregory Neil Shapiro **		mci -- the mailer connection info.
747106f25ae9SGregory Neil Shapiro **		e -- the envelope.
7472*d39bd2c1SGregory Neil Shapiro **		implicit -- implicit TLS (SMTP over TLS, no STARTTLS command)
747306f25ae9SGregory Neil Shapiro **
747406f25ae9SGregory Neil Shapiro **	Returns:
747506f25ae9SGregory Neil Shapiro **		success?
747606f25ae9SGregory Neil Shapiro **		(maybe this should be some other code than EX_
747706f25ae9SGregory Neil Shapiro **		that denotes which stage failed.)
747806f25ae9SGregory Neil Shapiro */
747906f25ae9SGregory Neil Shapiro 
748006f25ae9SGregory Neil Shapiro static int
starttls(m,mci,e,implicit,dane_vrfy_ctx)7481*d39bd2c1SGregory Neil Shapiro starttls(m, mci, e, implicit
74825b0945b5SGregory Neil Shapiro # if DANE
74835b0945b5SGregory Neil Shapiro 	, dane_vrfy_ctx
74845b0945b5SGregory Neil Shapiro # endif
74855b0945b5SGregory Neil Shapiro 	)
748606f25ae9SGregory Neil Shapiro 	MAILER *m;
748706f25ae9SGregory Neil Shapiro 	MCI *mci;
748806f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
7489*d39bd2c1SGregory Neil Shapiro 	bool implicit;
74905b0945b5SGregory Neil Shapiro # if DANE
74915b0945b5SGregory Neil Shapiro 	dane_vrfy_ctx_P	dane_vrfy_ctx;
74925b0945b5SGregory Neil Shapiro # endif
749306f25ae9SGregory Neil Shapiro {
749406f25ae9SGregory Neil Shapiro 	int smtpresult;
749542e5d165SGregory Neil Shapiro 	int result = 0;
74962fb4f839SGregory Neil Shapiro 	int ret = EX_OK;
749742e5d165SGregory Neil Shapiro 	int rfd, wfd;
749806f25ae9SGregory Neil Shapiro 	SSL *clt_ssl = NULL;
749940266059SGregory Neil Shapiro 	time_t tlsstart;
75005b0945b5SGregory Neil Shapiro 	extern int TLSsslidx;
750106f25ae9SGregory Neil Shapiro 
7502*d39bd2c1SGregory Neil Shapiro # if DANE
7503*d39bd2c1SGregory Neil Shapiro 	if (TTD(90, 60))
7504*d39bd2c1SGregory Neil Shapiro 		sm_dprintf("starttls=client: Dane=%d, dane_vrfy_chk=%#x\n",
7505*d39bd2c1SGregory Neil Shapiro 			Dane,dane_vrfy_ctx->dane_vrfy_chk);
7506*d39bd2c1SGregory Neil Shapiro # endif
750740266059SGregory Neil Shapiro 	if (clt_ctx == NULL && !initclttls(true))
750842e5d165SGregory Neil Shapiro 		return EX_TEMPFAIL;
75099bd497b8SGregory Neil Shapiro 
75105b0945b5SGregory Neil Shapiro 	if (!TLS_set_engine(SSLEngine, false))
75119bd497b8SGregory Neil Shapiro 	{
75129bd497b8SGregory Neil Shapiro 		sm_syslog(LOG_ERR, NOQID,
75135b0945b5SGregory Neil Shapiro 			  "STARTTLS=client, engine=%s, TLS_set_engine=failed",
75145b0945b5SGregory Neil Shapiro 			  SSLEngine);
75159bd497b8SGregory Neil Shapiro 		return EX_TEMPFAIL;
75169bd497b8SGregory Neil Shapiro 	}
75179bd497b8SGregory Neil Shapiro 
75182fb4f839SGregory Neil Shapiro 	/* clt_ssl needed for get_tls_se_features() hence create here */
751906f25ae9SGregory Neil Shapiro 	if ((clt_ssl = SSL_new(clt_ctx)) == NULL)
752006f25ae9SGregory Neil Shapiro 	{
752106f25ae9SGregory Neil Shapiro 		if (LogLevel > 5)
752206f25ae9SGregory Neil Shapiro 		{
752340266059SGregory Neil Shapiro 			sm_syslog(LOG_ERR, NOQID,
752440266059SGregory Neil Shapiro 				  "STARTTLS=client, error: SSL_new failed");
75255b0945b5SGregory Neil Shapiro 			tlslogerr(LOG_WARNING, 9, "client");
752606f25ae9SGregory Neil Shapiro 		}
7527*d39bd2c1SGregory Neil Shapiro 		return EX_TEMPFAIL;
752806f25ae9SGregory Neil Shapiro 	}
7529da7d7b9cSGregory Neil Shapiro 
75302fb4f839SGregory Neil Shapiro 	ret = get_tls_se_features(e, clt_ssl, &mci->mci_tlsi, false);
75312fb4f839SGregory Neil Shapiro 	if (EX_OK != ret)
7532da7d7b9cSGregory Neil Shapiro 	{
7533da7d7b9cSGregory Neil Shapiro 		sm_syslog(LOG_ERR, NOQID,
75342fb4f839SGregory Neil Shapiro 			  "STARTTLS=client, get_tls_se_features=failed, ret=%d",
75352fb4f839SGregory Neil Shapiro 			  ret);
75362fb4f839SGregory Neil Shapiro 		goto fail;
7537da7d7b9cSGregory Neil Shapiro 	}
75382fb4f839SGregory Neil Shapiro 
7539*d39bd2c1SGregory Neil Shapiro 	if (!implicit)
7540*d39bd2c1SGregory Neil Shapiro 	{
75412fb4f839SGregory Neil Shapiro 		smtpmessage("STARTTLS", m, mci);
75422fb4f839SGregory Neil Shapiro 
75432fb4f839SGregory Neil Shapiro 		/* get the reply */
75442fb4f839SGregory Neil Shapiro 		smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL,
7545*d39bd2c1SGregory Neil Shapiro 				XS_STARTTLS, NULL);
75462fb4f839SGregory Neil Shapiro 
75472fb4f839SGregory Neil Shapiro 		/* check return code from server */
75482fb4f839SGregory Neil Shapiro 		if (REPLYTYPE(smtpresult) == 4)
75492fb4f839SGregory Neil Shapiro 		{
75502fb4f839SGregory Neil Shapiro 			ret = EX_TEMPFAIL;
75512fb4f839SGregory Neil Shapiro 			goto fail;
75522fb4f839SGregory Neil Shapiro 		}
7553*d39bd2c1SGregory Neil Shapiro #if 0
7554*d39bd2c1SGregory Neil Shapiro 		/*
7555*d39bd2c1SGregory Neil Shapiro 		**  RFC 3207 says
7556*d39bd2c1SGregory Neil Shapiro 		**  501       Syntax error (no parameters allowed)
7557*d39bd2c1SGregory Neil Shapiro 		**  since sendmail does not use arguments, that's basically
7558*d39bd2c1SGregory Neil Shapiro 		**  a "cannot happen", hence treat it as any other 5xy,
7559*d39bd2c1SGregory Neil Shapiro 		**  which means it is also properly handled by the rules.
7560*d39bd2c1SGregory Neil Shapiro 		*/
7561*d39bd2c1SGregory Neil Shapiro 
75622fb4f839SGregory Neil Shapiro 		if (smtpresult == 501)
75632fb4f839SGregory Neil Shapiro 		{
75642fb4f839SGregory Neil Shapiro 			ret = EX_USAGE;
75652fb4f839SGregory Neil Shapiro 			goto fail;
75662fb4f839SGregory Neil Shapiro 		}
7567*d39bd2c1SGregory Neil Shapiro #endif /* 0 */
75682fb4f839SGregory Neil Shapiro 		if (smtpresult == -1)
75692fb4f839SGregory Neil Shapiro 		{
75702fb4f839SGregory Neil Shapiro 			ret = smtpresult;
75712fb4f839SGregory Neil Shapiro 			goto fail;
75722fb4f839SGregory Neil Shapiro 		}
75732fb4f839SGregory Neil Shapiro 
75742fb4f839SGregory Neil Shapiro 		/* not an expected reply but we have to deal with it */
75752fb4f839SGregory Neil Shapiro 		if (REPLYTYPE(smtpresult) == 5)
75762fb4f839SGregory Neil Shapiro 		{
75772fb4f839SGregory Neil Shapiro 			ret = EX_UNAVAILABLE;
75782fb4f839SGregory Neil Shapiro 			goto fail;
75792fb4f839SGregory Neil Shapiro 		}
75802fb4f839SGregory Neil Shapiro 		if (smtpresult != 220)
75812fb4f839SGregory Neil Shapiro 		{
75822fb4f839SGregory Neil Shapiro 			ret = EX_PROTOCOL;
75832fb4f839SGregory Neil Shapiro 			goto fail;
75842fb4f839SGregory Neil Shapiro 		}
7585*d39bd2c1SGregory Neil Shapiro 	}
75862fb4f839SGregory Neil Shapiro 
75872fb4f839SGregory Neil Shapiro 	if (LogLevel > 13)
75882fb4f839SGregory Neil Shapiro 		sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok");
75892fb4f839SGregory Neil Shapiro 
75902fb4f839SGregory Neil Shapiro 	/* SSL_clear(clt_ssl); ? */
75915b0945b5SGregory Neil Shapiro 	result = SSL_set_ex_data(clt_ssl, TLSsslidx, &mci->mci_tlsi);
75925b0945b5SGregory Neil Shapiro 	if (0 == result)
75935b0945b5SGregory Neil Shapiro 	{
75945b0945b5SGregory Neil Shapiro 		if (LogLevel > 5)
75955b0945b5SGregory Neil Shapiro 		{
75965b0945b5SGregory Neil Shapiro 			sm_syslog(LOG_ERR, NOQID,
75975b0945b5SGregory Neil Shapiro 				  "STARTTLS=client, error: SSL_set_ex_data failed=%d, idx=%d",
75985b0945b5SGregory Neil Shapiro 				  result, TLSsslidx);
75995b0945b5SGregory Neil Shapiro 			tlslogerr(LOG_WARNING, 9, "client");
76005b0945b5SGregory Neil Shapiro 		}
76012fb4f839SGregory Neil Shapiro 		goto fail;
76025b0945b5SGregory Neil Shapiro 	}
76035b0945b5SGregory Neil Shapiro # if DANE
76045b0945b5SGregory Neil Shapiro 	if (SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE))
76055b0945b5SGregory Neil Shapiro 		dane_vrfy_ctx->dane_vrfy_chk = DANE_NEVER;
7606*d39bd2c1SGregory Neil Shapiro 	if (TTD(90, 60))
7607*d39bd2c1SGregory Neil Shapiro 		sm_dprintf("starttls=client: 2: dane_vrfy_chk=%#x CHK_DANE=%d\n",
7608*d39bd2c1SGregory Neil Shapiro 			dane_vrfy_ctx->dane_vrfy_chk,
7609*d39bd2c1SGregory Neil Shapiro 			CHK_DANE(dane_vrfy_ctx->dane_vrfy_chk));
7610*d39bd2c1SGregory Neil Shapiro 	if (CHK_DANE(dane_vrfy_ctx->dane_vrfy_chk))
76115b0945b5SGregory Neil Shapiro 	{
76125b0945b5SGregory Neil Shapiro 		int r;
76135b0945b5SGregory Neil Shapiro 
76145b0945b5SGregory Neil Shapiro 		/* set SNI only if there is a TLSA RR */
7615*d39bd2c1SGregory Neil Shapiro 		if (tTd(90, 40))
7616*d39bd2c1SGregory Neil Shapiro 			sm_dprintf("dane_get_tlsa=%p, dane_vrfy_host=%s, dane_vrfy_sni=%s, ctx_dane_enabled=%d, dane_enabled=%d\n",
7617*d39bd2c1SGregory Neil Shapiro 				dane_get_tlsa(dane_vrfy_ctx),
7618*d39bd2c1SGregory Neil Shapiro 				dane_vrfy_ctx->dane_vrfy_host,
7619*d39bd2c1SGregory Neil Shapiro 				dane_vrfy_ctx->dane_vrfy_sni,
7620*d39bd2c1SGregory Neil Shapiro 				ctx_dane_enabled,
7621*d39bd2c1SGregory Neil Shapiro 				dane_vrfy_ctx->dane_vrfy_dane_enabled);
76225b0945b5SGregory Neil Shapiro 		if (dane_get_tlsa(dane_vrfy_ctx) != NULL &&
76235b0945b5SGregory Neil Shapiro 		    !(SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_host) &&
76242fb4f839SGregory Neil Shapiro 		      SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)))
76252fb4f839SGregory Neil Shapiro 		{
76262fb4f839SGregory Neil Shapiro #  if _FFR_MTA_STS
76272fb4f839SGregory Neil Shapiro 			SM_FREE(STS_SNI);
76282fb4f839SGregory Neil Shapiro #  endif
7629*d39bd2c1SGregory Neil Shapiro 			dane_vrfy_ctx->dane_vrfy_dane_enabled = ctx_dane_enabled;
7630*d39bd2c1SGregory Neil Shapiro 			if ((r = ssl_dane_enable(dane_vrfy_ctx, clt_ssl)) < 0)
7631*d39bd2c1SGregory Neil Shapiro 			{
7632*d39bd2c1SGregory Neil Shapiro 				dane_vrfy_ctx->dane_vrfy_dane_enabled = false;
7633*d39bd2c1SGregory Neil Shapiro 				if (LogLevel > 5)
7634*d39bd2c1SGregory Neil Shapiro 				{
7635*d39bd2c1SGregory Neil Shapiro 					sm_syslog(LOG_ERR, NOQID,
7636*d39bd2c1SGregory Neil Shapiro 						  "STARTTLS=client, host=%s, ssl_dane_enable=%d",
7637*d39bd2c1SGregory Neil Shapiro 						  dane_vrfy_ctx->dane_vrfy_host, r);
7638*d39bd2c1SGregory Neil Shapiro 				}
7639*d39bd2c1SGregory Neil Shapiro 			}
7640*d39bd2c1SGregory Neil Shapiro 			if (SM_NOTDONE == r)
7641*d39bd2c1SGregory Neil Shapiro 				dane_vrfy_ctx->dane_vrfy_dane_enabled = false;
7642*d39bd2c1SGregory Neil Shapiro 			if (tTd(90, 40))
7643*d39bd2c1SGregory Neil Shapiro 				sm_dprintf("ssl_dane_enable=%d, chk=%#x, dane_enabled=%d\n",
7644*d39bd2c1SGregory Neil Shapiro 					r, dane_vrfy_ctx->dane_vrfy_chk,
7645*d39bd2c1SGregory Neil Shapiro 					dane_vrfy_ctx->dane_vrfy_dane_enabled);
76462fb4f839SGregory Neil Shapiro 			if ((r = SSL_set_tlsext_host_name(clt_ssl,
76475b0945b5SGregory Neil Shapiro 				(!SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)
76485b0945b5SGregory Neil Shapiro 				? dane_vrfy_ctx->dane_vrfy_sni
76495b0945b5SGregory Neil Shapiro 				: dane_vrfy_ctx->dane_vrfy_host))) <= 0)
76505b0945b5SGregory Neil Shapiro 			{
76515b0945b5SGregory Neil Shapiro 				if (LogLevel > 5)
76525b0945b5SGregory Neil Shapiro 				{
76535b0945b5SGregory Neil Shapiro 					sm_syslog(LOG_ERR, NOQID,
76545b0945b5SGregory Neil Shapiro 						  "STARTTLS=client, host=%s, SSL_set_tlsext_host_name=%d",
76555b0945b5SGregory Neil Shapiro 						  dane_vrfy_ctx->dane_vrfy_host, r);
76565b0945b5SGregory Neil Shapiro 				}
76575b0945b5SGregory Neil Shapiro 				tlslogerr(LOG_ERR, 5, "client");
76585b0945b5SGregory Neil Shapiro 				/* return EX_SOFTWARE; */
76595b0945b5SGregory Neil Shapiro 			}
76605b0945b5SGregory Neil Shapiro 		}
76612fb4f839SGregory Neil Shapiro 	}
76625b0945b5SGregory Neil Shapiro 	memcpy(&mci->mci_tlsi.tlsi_dvc, dane_vrfy_ctx, sizeof(*dane_vrfy_ctx));
76635b0945b5SGregory Neil Shapiro # endif /* DANE */
76642fb4f839SGregory Neil Shapiro # if _FFR_MTA_STS
76652fb4f839SGregory Neil Shapiro 	if (STS_SNI != NULL)
76662fb4f839SGregory Neil Shapiro 	{
76672fb4f839SGregory Neil Shapiro 		int r;
76682fb4f839SGregory Neil Shapiro 
76692fb4f839SGregory Neil Shapiro 		if ((r = SSL_set_tlsext_host_name(clt_ssl, STS_SNI)) <= 0)
76702fb4f839SGregory Neil Shapiro 		{
76712fb4f839SGregory Neil Shapiro 			if (LogLevel > 5)
76722fb4f839SGregory Neil Shapiro 			{
76732fb4f839SGregory Neil Shapiro 				sm_syslog(LOG_ERR, NOQID,
76742fb4f839SGregory Neil Shapiro 					  "STARTTLS=client, host=%s, SSL_set_tlsext_host_name=%d",
76752fb4f839SGregory Neil Shapiro 					  STS_SNI, r);
76762fb4f839SGregory Neil Shapiro 			}
76772fb4f839SGregory Neil Shapiro 			tlslogerr(LOG_ERR, 5, "client");
76782fb4f839SGregory Neil Shapiro 			/* return EX_SOFTWARE; */
76792fb4f839SGregory Neil Shapiro 		}
76802fb4f839SGregory Neil Shapiro 	}
76812fb4f839SGregory Neil Shapiro # endif /* _FFR_MTA_STS */
768206f25ae9SGregory Neil Shapiro 
768340266059SGregory Neil Shapiro 	rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL);
768440266059SGregory Neil Shapiro 	wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL);
768542e5d165SGregory Neil Shapiro 
768642e5d165SGregory Neil Shapiro 	if (rfd < 0 || wfd < 0 ||
768740266059SGregory Neil Shapiro 	    (result = SSL_set_rfd(clt_ssl, rfd)) != 1 ||
768840266059SGregory Neil Shapiro 	    (result = SSL_set_wfd(clt_ssl, wfd)) != 1)
768906f25ae9SGregory Neil Shapiro 	{
769006f25ae9SGregory Neil Shapiro 		if (LogLevel > 5)
769106f25ae9SGregory Neil Shapiro 		{
769240266059SGregory Neil Shapiro 			sm_syslog(LOG_ERR, NOQID,
769340266059SGregory Neil Shapiro 				  "STARTTLS=client, error: SSL_set_xfd failed=%d",
769440266059SGregory Neil Shapiro 				  result);
76955b0945b5SGregory Neil Shapiro 			tlslogerr(LOG_WARNING, 9, "client");
769606f25ae9SGregory Neil Shapiro 		}
76972fb4f839SGregory Neil Shapiro 		goto fail;
769806f25ae9SGregory Neil Shapiro 	}
769906f25ae9SGregory Neil Shapiro 	SSL_set_connect_state(clt_ssl);
770040266059SGregory Neil Shapiro 	tlsstart = curtime();
770140266059SGregory Neil Shapiro 
770240266059SGregory Neil Shapiro ssl_retry:
770306f25ae9SGregory Neil Shapiro 	if ((result = SSL_connect(clt_ssl)) <= 0)
770406f25ae9SGregory Neil Shapiro 	{
77054e4196cbSGregory Neil Shapiro 		int i, ssl_err;
7706da7d7b9cSGregory Neil Shapiro 		int save_errno = errno;
770706f25ae9SGregory Neil Shapiro 
77084e4196cbSGregory Neil Shapiro 		ssl_err = SSL_get_error(clt_ssl, result);
77094e4196cbSGregory Neil Shapiro 		i = tls_retry(clt_ssl, rfd, wfd, tlsstart,
77104e4196cbSGregory Neil Shapiro 			TimeOuts.to_starttls, ssl_err, "client");
77114e4196cbSGregory Neil Shapiro 		if (i > 0)
77124e4196cbSGregory Neil Shapiro 			goto ssl_retry;
771340266059SGregory Neil Shapiro 
771413bd1963SGregory Neil Shapiro 		if (LogLevel > 5)
771513bd1963SGregory Neil Shapiro 		{
7716ba00ec3dSGregory Neil Shapiro 			unsigned long l;
7717ba00ec3dSGregory Neil Shapiro 			const char *sr;
7718ba00ec3dSGregory Neil Shapiro 
7719ba00ec3dSGregory Neil Shapiro 			l = ERR_peek_error();
7720ba00ec3dSGregory Neil Shapiro 			sr = ERR_reason_error_string(l);
77214e4196cbSGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
7722ba00ec3dSGregory Neil Shapiro 				  "STARTTLS=client, error: connect failed=%d, reason=%s, SSL_error=%d, errno=%d, retry=%d",
7723ba00ec3dSGregory Neil Shapiro 				  result, sr == NULL ? "unknown" : sr, ssl_err,
7724da7d7b9cSGregory Neil Shapiro 				  save_errno, i);
77255b0945b5SGregory Neil Shapiro 			tlslogerr(LOG_WARNING, 9, "client");
772613bd1963SGregory Neil Shapiro 		}
772740266059SGregory Neil Shapiro 
77282fb4f839SGregory Neil Shapiro 		goto fail;
772906f25ae9SGregory Neil Shapiro 	}
773006f25ae9SGregory Neil Shapiro 	mci->mci_ssl = clt_ssl;
773140266059SGregory Neil Shapiro 	result = tls_get_info(mci->mci_ssl, false, mci->mci_host,
773240266059SGregory Neil Shapiro 			      &mci->mci_macro, true);
773306f25ae9SGregory Neil Shapiro 
773440266059SGregory Neil Shapiro 	/* switch to use TLS... */
773506f25ae9SGregory Neil Shapiro 	if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0)
773606f25ae9SGregory Neil Shapiro 		return EX_OK;
773706f25ae9SGregory Neil Shapiro 
77382fb4f839SGregory Neil Shapiro   fail:
773906f25ae9SGregory Neil Shapiro 	/* failure */
77405b0945b5SGregory Neil Shapiro 	SM_SSL_FREE(clt_ssl);
77412fb4f839SGregory Neil Shapiro 	return (EX_OK == ret) ? EX_SOFTWARE : ret;
774206f25ae9SGregory Neil Shapiro }
77432fb4f839SGregory Neil Shapiro 
774440266059SGregory Neil Shapiro /*
774506f25ae9SGregory Neil Shapiro **  ENDTLSCLT -- shutdown secure connection (client side)
774606f25ae9SGregory Neil Shapiro **
774706f25ae9SGregory Neil Shapiro **	Parameters:
774806f25ae9SGregory Neil Shapiro **		mci -- the mailer connection info.
774906f25ae9SGregory Neil Shapiro **
775006f25ae9SGregory Neil Shapiro **	Returns:
775106f25ae9SGregory Neil Shapiro **		success?
775206f25ae9SGregory Neil Shapiro */
775340266059SGregory Neil Shapiro 
775440266059SGregory Neil Shapiro static int
endtlsclt(mci)775506f25ae9SGregory Neil Shapiro endtlsclt(mci)
775606f25ae9SGregory Neil Shapiro 	MCI *mci;
775706f25ae9SGregory Neil Shapiro {
775806f25ae9SGregory Neil Shapiro 	int r;
775906f25ae9SGregory Neil Shapiro 
776006f25ae9SGregory Neil Shapiro 	if (!bitset(MCIF_TLSACT, mci->mci_flags))
776106f25ae9SGregory Neil Shapiro 		return EX_OK;
77625b0945b5SGregory Neil Shapiro 	r = endtls(&mci->mci_ssl, "client");
776306f25ae9SGregory Neil Shapiro 	mci->mci_flags &= ~MCIF_TLSACT;
776406f25ae9SGregory Neil Shapiro 	return r;
776506f25ae9SGregory Neil Shapiro }
776640266059SGregory Neil Shapiro #endif /* STARTTLS */
776740266059SGregory Neil Shapiro #if STARTTLS || SASL
776840266059SGregory Neil Shapiro /*
776940266059SGregory Neil Shapiro **  ISCLTFLGSET -- check whether client flag is set.
777006f25ae9SGregory Neil Shapiro **
777106f25ae9SGregory Neil Shapiro **	Parameters:
777240266059SGregory Neil Shapiro **		e -- envelope.
777340266059SGregory Neil Shapiro **		flag -- flag to check in {client_flags}
777406f25ae9SGregory Neil Shapiro **
777506f25ae9SGregory Neil Shapiro **	Returns:
777640266059SGregory Neil Shapiro **		true iff flag is set.
777706f25ae9SGregory Neil Shapiro */
777806f25ae9SGregory Neil Shapiro 
777940266059SGregory Neil Shapiro static bool
iscltflgset(e,flag)778040266059SGregory Neil Shapiro iscltflgset(e, flag)
778140266059SGregory Neil Shapiro 	ENVELOPE *e;
778240266059SGregory Neil Shapiro 	int flag;
778306f25ae9SGregory Neil Shapiro {
778440266059SGregory Neil Shapiro 	char *p;
7785602a2b1bSGregory Neil Shapiro 
778640266059SGregory Neil Shapiro 	p = macvalue(macid("{client_flags}"), e);
778740266059SGregory Neil Shapiro 	if (p == NULL)
778840266059SGregory Neil Shapiro 		return false;
778940266059SGregory Neil Shapiro 	for (; *p != '\0'; p++)
779006f25ae9SGregory Neil Shapiro 	{
779140266059SGregory Neil Shapiro 		/* look for just this one flag */
779240266059SGregory Neil Shapiro 		if (*p == (char) flag)
779340266059SGregory Neil Shapiro 			return true;
779406f25ae9SGregory Neil Shapiro 	}
779540266059SGregory Neil Shapiro 	return false;
779606f25ae9SGregory Neil Shapiro }
779740266059SGregory Neil Shapiro #endif /* STARTTLS || SASL */
7798*d39bd2c1SGregory Neil Shapiro 
7799*d39bd2c1SGregory Neil Shapiro #if _FFR_TESTS
7800*d39bd2c1SGregory Neil Shapiro void
t_parsehostsig(hs,mailer)7801*d39bd2c1SGregory Neil Shapiro t_parsehostsig(hs, mailer)
7802*d39bd2c1SGregory Neil Shapiro 	char *hs;
7803*d39bd2c1SGregory Neil Shapiro 	MAILER *mailer;
7804*d39bd2c1SGregory Neil Shapiro {
7805*d39bd2c1SGregory Neil Shapiro 	int nummxhosts, i;
7806*d39bd2c1SGregory Neil Shapiro 	char *mxhosts[MAXMXHOSTS + 1];
7807*d39bd2c1SGregory Neil Shapiro #if DANE
7808*d39bd2c1SGregory Neil Shapiro 	BITMAP256 mxads;
7809*d39bd2c1SGregory Neil Shapiro #endif
7810*d39bd2c1SGregory Neil Shapiro 
7811*d39bd2c1SGregory Neil Shapiro 	if (NULL == mailer)
7812*d39bd2c1SGregory Neil Shapiro 		mailer = LocalMailer;
7813*d39bd2c1SGregory Neil Shapiro 	nummxhosts = parse_hostsignature(hs, mxhosts, mailer
7814*d39bd2c1SGregory Neil Shapiro #if DANE
7815*d39bd2c1SGregory Neil Shapiro 			, mxads
7816*d39bd2c1SGregory Neil Shapiro #endif
7817*d39bd2c1SGregory Neil Shapiro 			);
7818*d39bd2c1SGregory Neil Shapiro 	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7819*d39bd2c1SGregory Neil Shapiro 		     "nummxhosts=%d\n", nummxhosts);
7820*d39bd2c1SGregory Neil Shapiro 	for (i = 0; i < nummxhosts; i++)
7821*d39bd2c1SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7822*d39bd2c1SGregory Neil Shapiro 		     "mx[%d]=%s, ad=%d\n", i, mxhosts[i], MXADS_ISSET(mxads, 0));
7823*d39bd2c1SGregory Neil Shapiro }
7824*d39bd2c1SGregory Neil Shapiro 
7825*d39bd2c1SGregory Neil Shapiro void
t_hostsig(a,hs,mailer)7826*d39bd2c1SGregory Neil Shapiro t_hostsig(a, hs, mailer)
7827*d39bd2c1SGregory Neil Shapiro 	ADDRESS *a;
7828*d39bd2c1SGregory Neil Shapiro 	char *hs;
7829*d39bd2c1SGregory Neil Shapiro 	MAILER *mailer;
7830*d39bd2c1SGregory Neil Shapiro {
7831*d39bd2c1SGregory Neil Shapiro 	char *q;
7832*d39bd2c1SGregory Neil Shapiro 
7833*d39bd2c1SGregory Neil Shapiro 	if (NULL != a)
7834*d39bd2c1SGregory Neil Shapiro 		q = hostsignature(a->q_mailer, a->q_host, true, &a->q_flags);
7835*d39bd2c1SGregory Neil Shapiro 	else if (NULL != hs)
7836*d39bd2c1SGregory Neil Shapiro 	{
7837*d39bd2c1SGregory Neil Shapiro 		SM_REQUIRE(NULL != mailer);
7838*d39bd2c1SGregory Neil Shapiro 		q = hostsignature(mailer, hs, true, NULL);
7839*d39bd2c1SGregory Neil Shapiro 	}
7840*d39bd2c1SGregory Neil Shapiro 	else
7841*d39bd2c1SGregory Neil Shapiro 		SM_REQUIRE(NULL != hs);
7842*d39bd2c1SGregory Neil Shapiro 	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "hostsig %s\n", q);
7843*d39bd2c1SGregory Neil Shapiro 	t_parsehostsig(q, (NULL != a) ? a->q_mailer : mailer);
7844*d39bd2c1SGregory Neil Shapiro }
7845*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_TESTS */
7846