xref: /freebsd/contrib/sendmail/src/deliver.c (revision 602a2b1b1d5877cb573baf0407540810a490b0cf)
1c2aa98e2SPeter Wemm /*
2602a2b1bSGregory Neil Shapiro  * Copyright (c) 1998-2001 Sendmail, 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 
14c2aa98e2SPeter Wemm #ifndef lint
15602a2b1bSGregory Neil Shapiro static char id[] = "@(#)$Id: deliver.c,v 8.600.2.1.2.66 2001/02/25 23:30:35 gshapiro Exp $";
1606f25ae9SGregory Neil Shapiro #endif /* ! lint */
17c2aa98e2SPeter Wemm 
1806f25ae9SGregory Neil Shapiro #include <sendmail.h>
1906f25ae9SGregory Neil Shapiro 
20c2aa98e2SPeter Wemm 
21c2aa98e2SPeter Wemm #if HASSETUSERCONTEXT
22c2aa98e2SPeter Wemm # include <login_cap.h>
2306f25ae9SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */
2406f25ae9SGregory Neil Shapiro 
2506f25ae9SGregory Neil Shapiro #if STARTTLS || (SASL && SFIO)
2606f25ae9SGregory Neil Shapiro # include "sfsasl.h"
2706f25ae9SGregory Neil Shapiro #endif /* STARTTLS || (SASL && SFIO) */
2806f25ae9SGregory Neil Shapiro 
2906f25ae9SGregory Neil Shapiro static int	deliver __P((ENVELOPE *, ADDRESS *));
3006f25ae9SGregory Neil Shapiro static void	dup_queue_file __P((ENVELOPE *, ENVELOPE *, int));
3106f25ae9SGregory Neil Shapiro static void	mailfiletimeout __P((void));
3206f25ae9SGregory Neil Shapiro static void	markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool));
3306f25ae9SGregory Neil Shapiro static int	parse_hostsignature __P((char *, char **, MAILER *));
3406f25ae9SGregory Neil Shapiro static void	sendenvelope __P((ENVELOPE *, int));
3506f25ae9SGregory Neil Shapiro static char	*hostsignature __P((MAILER *, char *));
36c2aa98e2SPeter Wemm 
37c2aa98e2SPeter Wemm #if SMTP
3806f25ae9SGregory Neil Shapiro # if STARTTLS
3906f25ae9SGregory Neil Shapiro static int	starttls __P((MAILER *, MCI *, ENVELOPE *));
4006f25ae9SGregory Neil Shapiro # endif /* STARTTLS */
4106f25ae9SGregory Neil Shapiro #endif /* SMTP */
42c2aa98e2SPeter Wemm 
43c2aa98e2SPeter Wemm /*
44c2aa98e2SPeter Wemm **  SENDALL -- actually send all the messages.
45c2aa98e2SPeter Wemm **
46c2aa98e2SPeter Wemm **	Parameters:
47c2aa98e2SPeter Wemm **		e -- the envelope to send.
48c2aa98e2SPeter Wemm **		mode -- the delivery mode to use.  If SM_DEFAULT, use
49c2aa98e2SPeter Wemm **			the current e->e_sendmode.
50c2aa98e2SPeter Wemm **
51c2aa98e2SPeter Wemm **	Returns:
52c2aa98e2SPeter Wemm **		none.
53c2aa98e2SPeter Wemm **
54c2aa98e2SPeter Wemm **	Side Effects:
55c2aa98e2SPeter Wemm **		Scans the send lists and sends everything it finds.
56c2aa98e2SPeter Wemm **		Delivers any appropriate error messages.
57c2aa98e2SPeter Wemm **		If we are running in a non-interactive mode, takes the
58c2aa98e2SPeter Wemm **			appropriate action.
59c2aa98e2SPeter Wemm */
60c2aa98e2SPeter Wemm 
61c2aa98e2SPeter Wemm void
62c2aa98e2SPeter Wemm sendall(e, mode)
63c2aa98e2SPeter Wemm 	ENVELOPE *e;
64c2aa98e2SPeter Wemm 	int mode;
65c2aa98e2SPeter Wemm {
66c2aa98e2SPeter Wemm 	register ADDRESS *q;
67c2aa98e2SPeter Wemm 	char *owner;
68c2aa98e2SPeter Wemm 	int otherowners;
6906f25ae9SGregory Neil Shapiro 	int save_errno;
70c2aa98e2SPeter Wemm 	register ENVELOPE *ee;
71c2aa98e2SPeter Wemm 	ENVELOPE *splitenv = NULL;
72c2aa98e2SPeter Wemm 	int oldverbose = Verbose;
73c2aa98e2SPeter Wemm 	bool somedeliveries = FALSE, expensive = FALSE;
74c2aa98e2SPeter Wemm 	pid_t pid;
75c2aa98e2SPeter Wemm 
76c2aa98e2SPeter Wemm 	/*
77c2aa98e2SPeter Wemm 	**  If this message is to be discarded, don't bother sending
78c2aa98e2SPeter Wemm 	**  the message at all.
79c2aa98e2SPeter Wemm 	*/
80c2aa98e2SPeter Wemm 
81c2aa98e2SPeter Wemm 	if (bitset(EF_DISCARD, e->e_flags))
82c2aa98e2SPeter Wemm 	{
83c2aa98e2SPeter Wemm 		if (tTd(13, 1))
8406f25ae9SGregory Neil Shapiro 			dprintf("sendall: discarding id %s\n", e->e_id);
85c2aa98e2SPeter Wemm 		e->e_flags |= EF_CLRQUEUE;
86c2aa98e2SPeter Wemm 		if (LogLevel > 4)
87c2aa98e2SPeter Wemm 			sm_syslog(LOG_INFO, e->e_id, "discarded");
88c2aa98e2SPeter Wemm 		markstats(e, NULL, TRUE);
89c2aa98e2SPeter Wemm 		return;
90c2aa98e2SPeter Wemm 	}
91c2aa98e2SPeter Wemm 
92c2aa98e2SPeter Wemm 	/*
93c2aa98e2SPeter Wemm 	**  If we have had global, fatal errors, don't bother sending
94c2aa98e2SPeter Wemm 	**  the message at all if we are in SMTP mode.  Local errors
95c2aa98e2SPeter Wemm 	**  (e.g., a single address failing) will still cause the other
96c2aa98e2SPeter Wemm 	**  addresses to be sent.
97c2aa98e2SPeter Wemm 	*/
98c2aa98e2SPeter Wemm 
99c2aa98e2SPeter Wemm 	if (bitset(EF_FATALERRS, e->e_flags) &&
100c2aa98e2SPeter Wemm 	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
101c2aa98e2SPeter Wemm 	{
102c2aa98e2SPeter Wemm 		e->e_flags |= EF_CLRQUEUE;
103c2aa98e2SPeter Wemm 		return;
104c2aa98e2SPeter Wemm 	}
105c2aa98e2SPeter Wemm 
106c2aa98e2SPeter Wemm 	/* determine actual delivery mode */
107c2aa98e2SPeter Wemm 	if (mode == SM_DEFAULT)
108c2aa98e2SPeter Wemm 	{
109c2aa98e2SPeter Wemm 		mode = e->e_sendmode;
110c2aa98e2SPeter Wemm 		if (mode != SM_VERIFY && mode != SM_DEFER &&
111c2aa98e2SPeter Wemm 		    shouldqueue(e->e_msgpriority, e->e_ctime))
112c2aa98e2SPeter Wemm 			mode = SM_QUEUE;
113c2aa98e2SPeter Wemm 	}
114c2aa98e2SPeter Wemm 
115c2aa98e2SPeter Wemm 	if (tTd(13, 1))
116c2aa98e2SPeter Wemm 	{
11706f25ae9SGregory Neil Shapiro 		dprintf("\n===== SENDALL: mode %c, id %s, e_from ",
118c2aa98e2SPeter Wemm 			mode, e->e_id);
119c2aa98e2SPeter Wemm 		printaddr(&e->e_from, FALSE);
12006f25ae9SGregory Neil Shapiro 		dprintf("\te_flags = ");
121c2aa98e2SPeter Wemm 		printenvflags(e);
12206f25ae9SGregory Neil Shapiro 		dprintf("sendqueue:\n");
123c2aa98e2SPeter Wemm 		printaddr(e->e_sendqueue, TRUE);
124c2aa98e2SPeter Wemm 	}
125c2aa98e2SPeter Wemm 
126c2aa98e2SPeter Wemm 	/*
127c2aa98e2SPeter Wemm 	**  Do any preprocessing necessary for the mode we are running.
128c2aa98e2SPeter Wemm 	**	Check to make sure the hop count is reasonable.
129c2aa98e2SPeter Wemm 	**	Delete sends to the sender in mailing lists.
130c2aa98e2SPeter Wemm 	*/
131c2aa98e2SPeter Wemm 
132c2aa98e2SPeter Wemm 	CurEnv = e;
133c2aa98e2SPeter Wemm 	if (tTd(62, 1))
134c2aa98e2SPeter Wemm 		checkfds(NULL);
135c2aa98e2SPeter Wemm 
136c2aa98e2SPeter Wemm 	if (e->e_hopcount > MaxHopCount)
137c2aa98e2SPeter Wemm 	{
138c2aa98e2SPeter Wemm 		errno = 0;
139c2aa98e2SPeter Wemm #if QUEUE
140c2aa98e2SPeter Wemm 		queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
14106f25ae9SGregory Neil Shapiro #endif /* QUEUE */
142c2aa98e2SPeter Wemm 		e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
14306f25ae9SGregory Neil Shapiro 		ExitStat = EX_UNAVAILABLE;
14406f25ae9SGregory Neil Shapiro 		syserr("554 5.0.0 Too many hops %d (%d max): from %s via %s, to %s",
145c2aa98e2SPeter Wemm 			e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
146c2aa98e2SPeter Wemm 			RealHostName == NULL ? "localhost" : RealHostName,
147c2aa98e2SPeter Wemm 			e->e_sendqueue->q_paddr);
14806f25ae9SGregory Neil Shapiro 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
14906f25ae9SGregory Neil Shapiro 		{
15006f25ae9SGregory Neil Shapiro 			if (QS_IS_DEAD(q->q_state))
15106f25ae9SGregory Neil Shapiro 				continue;
15206f25ae9SGregory Neil Shapiro 			q->q_state = QS_BADADDR;
15306f25ae9SGregory Neil Shapiro 			q->q_status = "5.4.6";
15406f25ae9SGregory Neil Shapiro 		}
155c2aa98e2SPeter Wemm 		return;
156c2aa98e2SPeter Wemm 	}
157c2aa98e2SPeter Wemm 
158c2aa98e2SPeter Wemm 	/*
159c2aa98e2SPeter Wemm 	**  Do sender deletion.
160c2aa98e2SPeter Wemm 	**
16106f25ae9SGregory Neil Shapiro 	**	If the sender should be queued up, skip this.
162c2aa98e2SPeter Wemm 	**	This can happen if the name server is hosed when you
163c2aa98e2SPeter Wemm 	**	are trying to send mail.  The result is that the sender
164c2aa98e2SPeter Wemm 	**	is instantiated in the queue as a recipient.
165c2aa98e2SPeter Wemm 	*/
166c2aa98e2SPeter Wemm 
167c2aa98e2SPeter Wemm 	if (!bitset(EF_METOO, e->e_flags) &&
16806f25ae9SGregory Neil Shapiro 	    !QS_IS_QUEUEUP(e->e_from.q_state))
169c2aa98e2SPeter Wemm 	{
170c2aa98e2SPeter Wemm 		if (tTd(13, 5))
171c2aa98e2SPeter Wemm 		{
17206f25ae9SGregory Neil Shapiro 			dprintf("sendall: QS_SENDER ");
173c2aa98e2SPeter Wemm 			printaddr(&e->e_from, FALSE);
174c2aa98e2SPeter Wemm 		}
17506f25ae9SGregory Neil Shapiro 		e->e_from.q_state = QS_SENDER;
176c2aa98e2SPeter Wemm 		(void) recipient(&e->e_from, &e->e_sendqueue, 0, e);
177c2aa98e2SPeter Wemm 	}
178c2aa98e2SPeter Wemm 
179c2aa98e2SPeter Wemm 	/*
180c2aa98e2SPeter Wemm 	**  Handle alias owners.
181c2aa98e2SPeter Wemm 	**
182c2aa98e2SPeter Wemm 	**	We scan up the q_alias chain looking for owners.
183c2aa98e2SPeter Wemm 	**	We discard owners that are the same as the return path.
184c2aa98e2SPeter Wemm 	*/
185c2aa98e2SPeter Wemm 
186c2aa98e2SPeter Wemm 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
187c2aa98e2SPeter Wemm 	{
188c2aa98e2SPeter Wemm 		register struct address *a;
189c2aa98e2SPeter Wemm 
190c2aa98e2SPeter Wemm 		for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias)
191c2aa98e2SPeter Wemm 			continue;
192c2aa98e2SPeter Wemm 		if (a != NULL)
193c2aa98e2SPeter Wemm 			q->q_owner = a->q_owner;
194c2aa98e2SPeter Wemm 
195c2aa98e2SPeter Wemm 		if (q->q_owner != NULL &&
19606f25ae9SGregory Neil Shapiro 		    !QS_IS_DEAD(q->q_state) &&
197c2aa98e2SPeter Wemm 		    strcmp(q->q_owner, e->e_from.q_paddr) == 0)
198c2aa98e2SPeter Wemm 			q->q_owner = NULL;
199c2aa98e2SPeter Wemm 	}
200c2aa98e2SPeter Wemm 
201c2aa98e2SPeter Wemm 	if (tTd(13, 25))
202c2aa98e2SPeter Wemm 	{
20306f25ae9SGregory Neil Shapiro 		dprintf("\nAfter first owner pass, sendq =\n");
204c2aa98e2SPeter Wemm 		printaddr(e->e_sendqueue, TRUE);
205c2aa98e2SPeter Wemm 	}
206c2aa98e2SPeter Wemm 
207c2aa98e2SPeter Wemm 	owner = "";
208c2aa98e2SPeter Wemm 	otherowners = 1;
209c2aa98e2SPeter Wemm 	while (owner != NULL && otherowners > 0)
210c2aa98e2SPeter Wemm 	{
211c2aa98e2SPeter Wemm 		if (tTd(13, 28))
21206f25ae9SGregory Neil Shapiro 			dprintf("owner = \"%s\", otherowners = %d\n",
213c2aa98e2SPeter Wemm 				owner, otherowners);
214c2aa98e2SPeter Wemm 		owner = NULL;
215c2aa98e2SPeter Wemm 		otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0;
216c2aa98e2SPeter Wemm 
217c2aa98e2SPeter Wemm 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
218c2aa98e2SPeter Wemm 		{
219c2aa98e2SPeter Wemm 			if (tTd(13, 30))
220c2aa98e2SPeter Wemm 			{
22106f25ae9SGregory Neil Shapiro 				dprintf("Checking ");
222c2aa98e2SPeter Wemm 				printaddr(q, FALSE);
223c2aa98e2SPeter Wemm 			}
22406f25ae9SGregory Neil Shapiro 			if (QS_IS_DEAD(q->q_state))
225c2aa98e2SPeter Wemm 			{
226c2aa98e2SPeter Wemm 				if (tTd(13, 30))
22706f25ae9SGregory Neil Shapiro 					dprintf("    ... QS_IS_DEAD\n");
228c2aa98e2SPeter Wemm 				continue;
229c2aa98e2SPeter Wemm 			}
230c2aa98e2SPeter Wemm 			if (tTd(13, 29) && !tTd(13, 30))
231c2aa98e2SPeter Wemm 			{
23206f25ae9SGregory Neil Shapiro 				dprintf("Checking ");
233c2aa98e2SPeter Wemm 				printaddr(q, FALSE);
234c2aa98e2SPeter Wemm 			}
235c2aa98e2SPeter Wemm 
236c2aa98e2SPeter Wemm 			if (q->q_owner != NULL)
237c2aa98e2SPeter Wemm 			{
238c2aa98e2SPeter Wemm 				if (owner == NULL)
239c2aa98e2SPeter Wemm 				{
240c2aa98e2SPeter Wemm 					if (tTd(13, 40))
24106f25ae9SGregory Neil Shapiro 						dprintf("    ... First owner = \"%s\"\n",
242c2aa98e2SPeter Wemm 							q->q_owner);
243c2aa98e2SPeter Wemm 					owner = q->q_owner;
244c2aa98e2SPeter Wemm 				}
245c2aa98e2SPeter Wemm 				else if (owner != q->q_owner)
246c2aa98e2SPeter Wemm 				{
247c2aa98e2SPeter Wemm 					if (strcmp(owner, q->q_owner) == 0)
248c2aa98e2SPeter Wemm 					{
249c2aa98e2SPeter Wemm 						if (tTd(13, 40))
25006f25ae9SGregory Neil Shapiro 							dprintf("    ... Same owner = \"%s\"\n",
251c2aa98e2SPeter Wemm 								owner);
252c2aa98e2SPeter Wemm 
253c2aa98e2SPeter Wemm 						/* make future comparisons cheap */
254c2aa98e2SPeter Wemm 						q->q_owner = owner;
255c2aa98e2SPeter Wemm 					}
256c2aa98e2SPeter Wemm 					else
257c2aa98e2SPeter Wemm 					{
258c2aa98e2SPeter Wemm 						if (tTd(13, 40))
25906f25ae9SGregory Neil Shapiro 							dprintf("    ... Another owner \"%s\"\n",
260c2aa98e2SPeter Wemm 								q->q_owner);
261c2aa98e2SPeter Wemm 						otherowners++;
262c2aa98e2SPeter Wemm 					}
263c2aa98e2SPeter Wemm 					owner = q->q_owner;
264c2aa98e2SPeter Wemm 				}
265c2aa98e2SPeter Wemm 				else if (tTd(13, 40))
26606f25ae9SGregory Neil Shapiro 					dprintf("    ... Same owner = \"%s\"\n",
267c2aa98e2SPeter Wemm 						owner);
268c2aa98e2SPeter Wemm 			}
269c2aa98e2SPeter Wemm 			else
270c2aa98e2SPeter Wemm 			{
271c2aa98e2SPeter Wemm 				if (tTd(13, 40))
27206f25ae9SGregory Neil Shapiro 					dprintf("    ... Null owner\n");
273c2aa98e2SPeter Wemm 				otherowners++;
274c2aa98e2SPeter Wemm 			}
275c2aa98e2SPeter Wemm 
27606f25ae9SGregory Neil Shapiro 			if (QS_IS_BADADDR(q->q_state))
27706f25ae9SGregory Neil Shapiro 			{
27806f25ae9SGregory Neil Shapiro 				if (tTd(13, 30))
27906f25ae9SGregory Neil Shapiro 					dprintf("    ... QS_IS_BADADDR\n");
28006f25ae9SGregory Neil Shapiro 				continue;
28106f25ae9SGregory Neil Shapiro 			}
28206f25ae9SGregory Neil Shapiro 
28306f25ae9SGregory Neil Shapiro 			if (QS_IS_QUEUEUP(q->q_state))
28406f25ae9SGregory Neil Shapiro 			{
28506f25ae9SGregory Neil Shapiro 				MAILER *m = q->q_mailer;
28606f25ae9SGregory Neil Shapiro 
28706f25ae9SGregory Neil Shapiro 				/*
28806f25ae9SGregory Neil Shapiro 				**  If we have temporary address failures
28906f25ae9SGregory Neil Shapiro 				**  (e.g., dns failure) and a fallback MX is
29006f25ae9SGregory Neil Shapiro 				**  set, send directly to the fallback MX host.
29106f25ae9SGregory Neil Shapiro 				*/
29206f25ae9SGregory Neil Shapiro 
29306f25ae9SGregory Neil Shapiro 				if (FallBackMX != NULL &&
29406f25ae9SGregory Neil Shapiro 				    !wordinclass(FallBackMX, 'w') &&
29506f25ae9SGregory Neil Shapiro 				    mode != SM_VERIFY &&
29606f25ae9SGregory Neil Shapiro 				    (strcmp(m->m_mailer, "[IPC]") == 0 ||
29706f25ae9SGregory Neil Shapiro 				     strcmp(m->m_mailer, "[TCP]") == 0) &&
29806f25ae9SGregory Neil Shapiro 				    m->m_argv[0] != NULL &&
29906f25ae9SGregory Neil Shapiro 				    (strcmp(m->m_argv[0], "TCP") == 0 ||
30006f25ae9SGregory Neil Shapiro 				     strcmp(m->m_argv[0], "IPC") == 0))
30106f25ae9SGregory Neil Shapiro 				{
30206f25ae9SGregory Neil Shapiro 					int len;
30306f25ae9SGregory Neil Shapiro 					char *p;
30406f25ae9SGregory Neil Shapiro 
30506f25ae9SGregory Neil Shapiro 					if (tTd(13, 30))
30606f25ae9SGregory Neil Shapiro 						dprintf("    ... FallBackMX\n");
30706f25ae9SGregory Neil Shapiro 
30806f25ae9SGregory Neil Shapiro 					len = strlen(FallBackMX) + 3;
30906f25ae9SGregory Neil Shapiro 					p = xalloc(len);
31006f25ae9SGregory Neil Shapiro 					snprintf(p, len, "[%s]", FallBackMX);
31106f25ae9SGregory Neil Shapiro 					q->q_state = QS_OK;
31206f25ae9SGregory Neil Shapiro 					q->q_host = p;
31306f25ae9SGregory Neil Shapiro 				}
31406f25ae9SGregory Neil Shapiro 				else
31506f25ae9SGregory Neil Shapiro 				{
31606f25ae9SGregory Neil Shapiro 					if (tTd(13, 30))
31706f25ae9SGregory Neil Shapiro 						dprintf("    ... QS_IS_QUEUEUP\n");
31806f25ae9SGregory Neil Shapiro 					continue;
31906f25ae9SGregory Neil Shapiro 				}
32006f25ae9SGregory Neil Shapiro 			}
32106f25ae9SGregory Neil Shapiro 
322c2aa98e2SPeter Wemm 			/*
323c2aa98e2SPeter Wemm 			**  If this mailer is expensive, and if we don't
324c2aa98e2SPeter Wemm 			**  want to make connections now, just mark these
325c2aa98e2SPeter Wemm 			**  addresses and return.  This is useful if we
326c2aa98e2SPeter Wemm 			**  want to batch connections to reduce load.  This
327c2aa98e2SPeter Wemm 			**  will cause the messages to be queued up, and a
328c2aa98e2SPeter Wemm 			**  daemon will come along to send the messages later.
329c2aa98e2SPeter Wemm 			*/
330c2aa98e2SPeter Wemm 
331c2aa98e2SPeter Wemm 			if (NoConnect && !Verbose &&
332c2aa98e2SPeter Wemm 			    bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
333c2aa98e2SPeter Wemm 			{
334c2aa98e2SPeter Wemm 				if (tTd(13, 30))
33506f25ae9SGregory Neil Shapiro 					dprintf("    ... expensive\n");
33606f25ae9SGregory Neil Shapiro 				q->q_state = QS_QUEUEUP;
33706f25ae9SGregory Neil Shapiro 				expensive = TRUE;
33806f25ae9SGregory Neil Shapiro 			}
33906f25ae9SGregory Neil Shapiro 			else if (bitnset(M_HOLD, q->q_mailer->m_flags) &&
34006f25ae9SGregory Neil Shapiro 				 QueueLimitId == NULL &&
34106f25ae9SGregory Neil Shapiro 				 QueueLimitSender == NULL &&
34206f25ae9SGregory Neil Shapiro 				 QueueLimitRecipient == NULL)
34306f25ae9SGregory Neil Shapiro 			{
34406f25ae9SGregory Neil Shapiro 				if (tTd(13, 30))
34506f25ae9SGregory Neil Shapiro 					dprintf("    ... hold\n");
34606f25ae9SGregory Neil Shapiro 				q->q_state = QS_QUEUEUP;
347c2aa98e2SPeter Wemm 				expensive = TRUE;
348c2aa98e2SPeter Wemm 			}
349c2aa98e2SPeter Wemm 			else
350c2aa98e2SPeter Wemm 			{
351c2aa98e2SPeter Wemm 				if (tTd(13, 30))
35206f25ae9SGregory Neil Shapiro 					dprintf("    ... deliverable\n");
353c2aa98e2SPeter Wemm 				somedeliveries = TRUE;
354c2aa98e2SPeter Wemm 			}
355c2aa98e2SPeter Wemm 		}
356c2aa98e2SPeter Wemm 
357c2aa98e2SPeter Wemm 		if (owner != NULL && otherowners > 0)
358c2aa98e2SPeter Wemm 		{
359c2aa98e2SPeter Wemm 			/*
360c2aa98e2SPeter Wemm 			**  Split this envelope into two.
361c2aa98e2SPeter Wemm 			*/
362c2aa98e2SPeter Wemm 
36306f25ae9SGregory Neil Shapiro 			ee = (ENVELOPE *) xalloc(sizeof *ee);
364c2aa98e2SPeter Wemm 			*ee = *e;
36506f25ae9SGregory Neil Shapiro 			ee->e_message = NULL;
366c2aa98e2SPeter Wemm 			ee->e_id = NULL;
36706f25ae9SGregory Neil Shapiro 			assign_queueid(ee);
368c2aa98e2SPeter Wemm 
369c2aa98e2SPeter Wemm 			if (tTd(13, 1))
37006f25ae9SGregory Neil Shapiro 				dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n",
371c2aa98e2SPeter Wemm 					e->e_id, ee->e_id, owner, otherowners);
372c2aa98e2SPeter Wemm 
373c2aa98e2SPeter Wemm 			ee->e_header = copyheader(e->e_header);
374c2aa98e2SPeter Wemm 			ee->e_sendqueue = copyqueue(e->e_sendqueue);
375c2aa98e2SPeter Wemm 			ee->e_errorqueue = copyqueue(e->e_errorqueue);
376c2aa98e2SPeter Wemm 			ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM);
377c2aa98e2SPeter Wemm 			ee->e_flags |= EF_NORECEIPT;
378c2aa98e2SPeter Wemm 			setsender(owner, ee, NULL, '\0', TRUE);
379c2aa98e2SPeter Wemm 			if (tTd(13, 5))
380c2aa98e2SPeter Wemm 			{
38106f25ae9SGregory Neil Shapiro 				dprintf("sendall(split): QS_SENDER ");
382c2aa98e2SPeter Wemm 				printaddr(&ee->e_from, FALSE);
383c2aa98e2SPeter Wemm 			}
38406f25ae9SGregory Neil Shapiro 			ee->e_from.q_state = QS_SENDER;
385c2aa98e2SPeter Wemm 			ee->e_dfp = NULL;
38606f25ae9SGregory Neil Shapiro 			ee->e_lockfp = NULL;
387c2aa98e2SPeter Wemm 			ee->e_xfp = NULL;
38806f25ae9SGregory Neil Shapiro 			ee->e_queuedir = e->e_queuedir;
389c2aa98e2SPeter Wemm 			ee->e_errormode = EM_MAIL;
390c2aa98e2SPeter Wemm 			ee->e_sibling = splitenv;
39106f25ae9SGregory Neil Shapiro 			ee->e_statmsg = NULL;
392c2aa98e2SPeter Wemm 			splitenv = ee;
393c2aa98e2SPeter Wemm 
394c2aa98e2SPeter Wemm 			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
395c2aa98e2SPeter Wemm 			{
396c2aa98e2SPeter Wemm 				if (q->q_owner == owner)
397c2aa98e2SPeter Wemm 				{
39806f25ae9SGregory Neil Shapiro 					q->q_state = QS_CLONED;
399c2aa98e2SPeter Wemm 					if (tTd(13, 6))
40006f25ae9SGregory Neil Shapiro 						dprintf("\t... stripping %s from original envelope\n",
401c2aa98e2SPeter Wemm 							q->q_paddr);
402c2aa98e2SPeter Wemm 				}
403c2aa98e2SPeter Wemm 			}
404c2aa98e2SPeter Wemm 			for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
405c2aa98e2SPeter Wemm 			{
406c2aa98e2SPeter Wemm 				if (q->q_owner != owner)
407c2aa98e2SPeter Wemm 				{
40806f25ae9SGregory Neil Shapiro 					q->q_state = QS_CLONED;
409c2aa98e2SPeter Wemm 					if (tTd(13, 6))
41006f25ae9SGregory Neil Shapiro 						dprintf("\t... dropping %s from cloned envelope\n",
411c2aa98e2SPeter Wemm 							q->q_paddr);
412c2aa98e2SPeter Wemm 				}
413c2aa98e2SPeter Wemm 				else
414c2aa98e2SPeter Wemm 				{
415c2aa98e2SPeter Wemm 					/* clear DSN parameters */
416c2aa98e2SPeter Wemm 					q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
417c2aa98e2SPeter Wemm 					q->q_flags |= DefaultNotify & ~QPINGONSUCCESS;
418c2aa98e2SPeter Wemm 					if (tTd(13, 6))
41906f25ae9SGregory Neil Shapiro 						dprintf("\t... moving %s to cloned envelope\n",
420c2aa98e2SPeter Wemm 							q->q_paddr);
421c2aa98e2SPeter Wemm 				}
422c2aa98e2SPeter Wemm 			}
423c2aa98e2SPeter Wemm 
424c2aa98e2SPeter Wemm 			if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags))
425c2aa98e2SPeter Wemm 				dup_queue_file(e, ee, 'd');
42606f25ae9SGregory Neil Shapiro 
42706f25ae9SGregory Neil Shapiro 			/*
42806f25ae9SGregory Neil Shapiro 			**  Give the split envelope access to the parent
42906f25ae9SGregory Neil Shapiro 			**  transcript file for errors obtained while
43006f25ae9SGregory Neil Shapiro 			**  processing the recipients (done before the
43106f25ae9SGregory Neil Shapiro 			**  envelope splitting).
43206f25ae9SGregory Neil Shapiro 			*/
43306f25ae9SGregory Neil Shapiro 
43406f25ae9SGregory Neil Shapiro 			if (e->e_xfp != NULL)
43506f25ae9SGregory Neil Shapiro 				ee->e_xfp = bfdup(e->e_xfp);
43606f25ae9SGregory Neil Shapiro 
43706f25ae9SGregory Neil Shapiro 			/* failed to dup e->e_xfp, start a new transcript */
43806f25ae9SGregory Neil Shapiro 			if (ee->e_xfp == NULL)
439c2aa98e2SPeter Wemm 				openxscript(ee);
44006f25ae9SGregory Neil Shapiro 
441065a643dSPeter Wemm 			if (mode != SM_VERIFY && LogLevel > 4)
442c2aa98e2SPeter Wemm 				sm_syslog(LOG_INFO, ee->e_id,
443c2aa98e2SPeter Wemm 					  "clone %s, owner=%s",
444c2aa98e2SPeter Wemm 					  e->e_id, owner);
445c2aa98e2SPeter Wemm 		}
446c2aa98e2SPeter Wemm 	}
447c2aa98e2SPeter Wemm 
448c2aa98e2SPeter Wemm 	if (owner != NULL)
449c2aa98e2SPeter Wemm 	{
450c2aa98e2SPeter Wemm 		setsender(owner, e, NULL, '\0', TRUE);
451c2aa98e2SPeter Wemm 		if (tTd(13, 5))
452c2aa98e2SPeter Wemm 		{
45306f25ae9SGregory Neil Shapiro 			dprintf("sendall(owner): QS_SENDER ");
454c2aa98e2SPeter Wemm 			printaddr(&e->e_from, FALSE);
455c2aa98e2SPeter Wemm 		}
45606f25ae9SGregory Neil Shapiro 		e->e_from.q_state = QS_SENDER;
457c2aa98e2SPeter Wemm 		e->e_errormode = EM_MAIL;
458c2aa98e2SPeter Wemm 		e->e_flags |= EF_NORECEIPT;
459c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_FATALERRS;
460c2aa98e2SPeter Wemm 	}
461c2aa98e2SPeter Wemm 
462c2aa98e2SPeter Wemm 	/* if nothing to be delivered, just queue up everything */
463c2aa98e2SPeter Wemm 	if (!somedeliveries && mode != SM_QUEUE && mode != SM_DEFER &&
464c2aa98e2SPeter Wemm 	    mode != SM_VERIFY)
465c2aa98e2SPeter Wemm 	{
466193538b7SGregory Neil Shapiro 		time_t now = curtime();
467193538b7SGregory Neil Shapiro 
468c2aa98e2SPeter Wemm 		if (tTd(13, 29))
46906f25ae9SGregory Neil Shapiro 			dprintf("No deliveries: auto-queuing\n");
470c2aa98e2SPeter Wemm 		mode = SM_QUEUE;
471c2aa98e2SPeter Wemm 
472c2aa98e2SPeter Wemm 		/* treat this as a delivery in terms of counting tries */
473193538b7SGregory Neil Shapiro 		e->e_dtime = now;
474c2aa98e2SPeter Wemm 		if (!expensive)
475c2aa98e2SPeter Wemm 			e->e_ntries++;
476c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
477c2aa98e2SPeter Wemm 		{
478193538b7SGregory Neil Shapiro 			ee->e_dtime = now;
479c2aa98e2SPeter Wemm 			if (!expensive)
480c2aa98e2SPeter Wemm 				ee->e_ntries++;
481c2aa98e2SPeter Wemm 		}
482c2aa98e2SPeter Wemm 	}
483c2aa98e2SPeter Wemm 
484c2aa98e2SPeter Wemm #if QUEUE
485c2aa98e2SPeter Wemm 	if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK ||
486c2aa98e2SPeter Wemm 	     (mode != SM_VERIFY && SuperSafe)) &&
487c2aa98e2SPeter Wemm 	    (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL))
488c2aa98e2SPeter Wemm 	{
48942e5d165SGregory Neil Shapiro 		/*
49042e5d165SGregory Neil Shapiro 		**  Be sure everything is instantiated in the queue.
49142e5d165SGregory Neil Shapiro 		**  Split envelopes first in case the machine crashes.
49242e5d165SGregory Neil Shapiro 		**  If the original were done first, we may lose
49342e5d165SGregory Neil Shapiro 		**  recipients.
49442e5d165SGregory Neil Shapiro 		*/
49542e5d165SGregory Neil Shapiro 
496c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
497c2aa98e2SPeter Wemm 			queueup(ee, mode == SM_QUEUE || mode == SM_DEFER);
49842e5d165SGregory Neil Shapiro 		queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
499c2aa98e2SPeter Wemm 	}
500c2aa98e2SPeter Wemm #endif /* QUEUE */
501c2aa98e2SPeter Wemm 
502c2aa98e2SPeter Wemm 	if (tTd(62, 10))
503c2aa98e2SPeter Wemm 		checkfds("after envelope splitting");
504c2aa98e2SPeter Wemm 
505c2aa98e2SPeter Wemm 	/*
506c2aa98e2SPeter Wemm 	**  If we belong in background, fork now.
507c2aa98e2SPeter Wemm 	*/
508c2aa98e2SPeter Wemm 
509c2aa98e2SPeter Wemm 	if (tTd(13, 20))
510c2aa98e2SPeter Wemm 	{
51106f25ae9SGregory Neil Shapiro 		dprintf("sendall: final mode = %c\n", mode);
512c2aa98e2SPeter Wemm 		if (tTd(13, 21))
513c2aa98e2SPeter Wemm 		{
51406f25ae9SGregory Neil Shapiro 			dprintf("\n================ Final Send Queue(s) =====================\n");
51506f25ae9SGregory Neil Shapiro 			dprintf("\n  *** Envelope %s, e_from=%s ***\n",
516c2aa98e2SPeter Wemm 				e->e_id, e->e_from.q_paddr);
517c2aa98e2SPeter Wemm 			printaddr(e->e_sendqueue, TRUE);
518c2aa98e2SPeter Wemm 			for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
519c2aa98e2SPeter Wemm 			{
52006f25ae9SGregory Neil Shapiro 				dprintf("\n  *** Envelope %s, e_from=%s ***\n",
521c2aa98e2SPeter Wemm 					ee->e_id, ee->e_from.q_paddr);
522c2aa98e2SPeter Wemm 				printaddr(ee->e_sendqueue, TRUE);
523c2aa98e2SPeter Wemm 			}
52406f25ae9SGregory Neil Shapiro 			dprintf("==========================================================\n\n");
525c2aa98e2SPeter Wemm 		}
526c2aa98e2SPeter Wemm 	}
527c2aa98e2SPeter Wemm 	switch (mode)
528c2aa98e2SPeter Wemm 	{
529c2aa98e2SPeter Wemm 	  case SM_VERIFY:
530c2aa98e2SPeter Wemm 		Verbose = 2;
531c2aa98e2SPeter Wemm 		break;
532c2aa98e2SPeter Wemm 
533c2aa98e2SPeter Wemm 	  case SM_QUEUE:
534c2aa98e2SPeter Wemm 	  case SM_DEFER:
535c2aa98e2SPeter Wemm #if HASFLOCK
536c2aa98e2SPeter Wemm   queueonly:
53706f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */
538c2aa98e2SPeter Wemm 		if (e->e_nrcpts > 0)
539c2aa98e2SPeter Wemm 			e->e_flags |= EF_INQUEUE;
540c2aa98e2SPeter Wemm 		dropenvelope(e, splitenv != NULL);
541c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
542c2aa98e2SPeter Wemm 		{
543c2aa98e2SPeter Wemm 			if (ee->e_nrcpts > 0)
544c2aa98e2SPeter Wemm 				ee->e_flags |= EF_INQUEUE;
545c2aa98e2SPeter Wemm 			dropenvelope(ee, FALSE);
546c2aa98e2SPeter Wemm 		}
547c2aa98e2SPeter Wemm 		return;
548c2aa98e2SPeter Wemm 
549c2aa98e2SPeter Wemm 	  case SM_FORK:
550c2aa98e2SPeter Wemm 		if (e->e_xfp != NULL)
551c2aa98e2SPeter Wemm 			(void) fflush(e->e_xfp);
552c2aa98e2SPeter Wemm 
553c2aa98e2SPeter Wemm #if !HASFLOCK
554c2aa98e2SPeter Wemm 		/*
555c2aa98e2SPeter Wemm 		**  Since fcntl locking has the interesting semantic that
556c2aa98e2SPeter Wemm 		**  the lock is owned by a process, not by an open file
557c2aa98e2SPeter Wemm 		**  descriptor, we have to flush this to the queue, and
558c2aa98e2SPeter Wemm 		**  then restart from scratch in the child.
559c2aa98e2SPeter Wemm 		*/
560c2aa98e2SPeter Wemm 
561c2aa98e2SPeter Wemm 		{
562c2aa98e2SPeter Wemm 			/* save id for future use */
563c2aa98e2SPeter Wemm 			char *qid = e->e_id;
564c2aa98e2SPeter Wemm 
565c2aa98e2SPeter Wemm 			/* now drop the envelope in the parent */
566c2aa98e2SPeter Wemm 			e->e_flags |= EF_INQUEUE;
567c2aa98e2SPeter Wemm 			dropenvelope(e, splitenv != NULL);
568c2aa98e2SPeter Wemm 
569c2aa98e2SPeter Wemm 			/* arrange to reacquire lock after fork */
570c2aa98e2SPeter Wemm 			e->e_id = qid;
571c2aa98e2SPeter Wemm 		}
572c2aa98e2SPeter Wemm 
573c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
574c2aa98e2SPeter Wemm 		{
575c2aa98e2SPeter Wemm 			/* save id for future use */
576c2aa98e2SPeter Wemm 			char *qid = ee->e_id;
577c2aa98e2SPeter Wemm 
578c2aa98e2SPeter Wemm 			/* drop envelope in parent */
579c2aa98e2SPeter Wemm 			ee->e_flags |= EF_INQUEUE;
580c2aa98e2SPeter Wemm 			dropenvelope(ee, FALSE);
581c2aa98e2SPeter Wemm 
582c2aa98e2SPeter Wemm 			/* and save qid for reacquisition */
583c2aa98e2SPeter Wemm 			ee->e_id = qid;
584c2aa98e2SPeter Wemm 		}
585c2aa98e2SPeter Wemm 
586c2aa98e2SPeter Wemm #endif /* !HASFLOCK */
587c2aa98e2SPeter Wemm 
58806f25ae9SGregory Neil Shapiro 		/*
58906f25ae9SGregory Neil Shapiro 		**  Since the delivery may happen in a child and the parent
59006f25ae9SGregory Neil Shapiro 		**  does not wait, the parent may close the maps thereby
59106f25ae9SGregory Neil Shapiro 		**  removing any shared memory used by the map.  Therefore,
59206f25ae9SGregory Neil Shapiro 		**  close the maps now so the child will dynamically open
59306f25ae9SGregory Neil Shapiro 		**  them if necessary.
59406f25ae9SGregory Neil Shapiro 		*/
59506f25ae9SGregory Neil Shapiro 
59606f25ae9SGregory Neil Shapiro 		closemaps();
59706f25ae9SGregory Neil Shapiro 
598c2aa98e2SPeter Wemm 		pid = fork();
599c2aa98e2SPeter Wemm 		if (pid < 0)
600c2aa98e2SPeter Wemm 		{
60106f25ae9SGregory Neil Shapiro 			syserr("deliver: fork 1");
602c2aa98e2SPeter Wemm #if HASFLOCK
603c2aa98e2SPeter Wemm 			goto queueonly;
60406f25ae9SGregory Neil Shapiro #else /* HASFLOCK */
605c2aa98e2SPeter Wemm 			e->e_id = NULL;
606c2aa98e2SPeter Wemm 			for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
607c2aa98e2SPeter Wemm 				ee->e_id = NULL;
608c2aa98e2SPeter Wemm 			return;
609c2aa98e2SPeter Wemm #endif /* HASFLOCK */
610c2aa98e2SPeter Wemm 		}
611c2aa98e2SPeter Wemm 		else if (pid > 0)
612c2aa98e2SPeter Wemm 		{
613c2aa98e2SPeter Wemm #if HASFLOCK
614c2aa98e2SPeter Wemm 			/* be sure we leave the temp files to our child */
615c2aa98e2SPeter Wemm 			/* close any random open files in the envelope */
616c2aa98e2SPeter Wemm 			closexscript(e);
617c2aa98e2SPeter Wemm 			if (e->e_dfp != NULL)
61806f25ae9SGregory Neil Shapiro 				(void) bfclose(e->e_dfp);
619c2aa98e2SPeter Wemm 			e->e_dfp = NULL;
620c2aa98e2SPeter Wemm 			e->e_flags &= ~EF_HAS_DF;
621c2aa98e2SPeter Wemm 
622c2aa98e2SPeter Wemm 			/* can't call unlockqueue to avoid unlink of xfp */
623c2aa98e2SPeter Wemm 			if (e->e_lockfp != NULL)
62406f25ae9SGregory Neil Shapiro 				(void) fclose(e->e_lockfp);
62506f25ae9SGregory Neil Shapiro 			else
62606f25ae9SGregory Neil Shapiro 				syserr("%s: sendall: null lockfp", e->e_id);
627c2aa98e2SPeter Wemm 			e->e_lockfp = NULL;
62806f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */
629c2aa98e2SPeter Wemm 
630c2aa98e2SPeter Wemm 			/* make sure the parent doesn't own the envelope */
631c2aa98e2SPeter Wemm 			e->e_id = NULL;
632c2aa98e2SPeter Wemm 
633c2aa98e2SPeter Wemm 			/* catch intermediate zombie */
634c2aa98e2SPeter Wemm 			(void) waitfor(pid);
635c2aa98e2SPeter Wemm 			return;
636c2aa98e2SPeter Wemm 		}
637c2aa98e2SPeter Wemm 
63842e5d165SGregory Neil Shapiro 		/*
63942e5d165SGregory Neil Shapiro 		**  Since we have accepted responsbility for the message,
64042e5d165SGregory Neil Shapiro 		**  change the SIGTERM handler.  intsig() (the old handler)
64142e5d165SGregory Neil Shapiro 		**  would remove the envelope if this was a command line
64242e5d165SGregory Neil Shapiro 		**  message submission.
64342e5d165SGregory Neil Shapiro 		*/
64442e5d165SGregory Neil Shapiro 
64542e5d165SGregory Neil Shapiro 		(void) setsignal(SIGTERM, SIG_DFL);
64642e5d165SGregory Neil Shapiro 
647c2aa98e2SPeter Wemm 		/* double fork to avoid zombies */
648c2aa98e2SPeter Wemm 		pid = fork();
649c2aa98e2SPeter Wemm 		if (pid > 0)
650c2aa98e2SPeter Wemm 			exit(EX_OK);
65106f25ae9SGregory Neil Shapiro 		save_errno = errno;
652c2aa98e2SPeter Wemm 
653c2aa98e2SPeter Wemm 		/* be sure we are immune from the terminal */
654c2aa98e2SPeter Wemm 		disconnect(2, e);
65506f25ae9SGregory Neil Shapiro 		clearstats();
656c2aa98e2SPeter Wemm 
657c2aa98e2SPeter Wemm 		/* prevent parent from waiting if there was an error */
658c2aa98e2SPeter Wemm 		if (pid < 0)
659c2aa98e2SPeter Wemm 		{
66006f25ae9SGregory Neil Shapiro 			errno = save_errno;
66106f25ae9SGregory Neil Shapiro 			syserr("deliver: fork 2");
662c2aa98e2SPeter Wemm #if HASFLOCK
663c2aa98e2SPeter Wemm 			e->e_flags |= EF_INQUEUE;
66406f25ae9SGregory Neil Shapiro #else /* HASFLOCK */
665c2aa98e2SPeter Wemm 			e->e_id = NULL;
666c2aa98e2SPeter Wemm #endif /* HASFLOCK */
667065a643dSPeter Wemm 			finis(TRUE, ExitStat);
668c2aa98e2SPeter Wemm 		}
669c2aa98e2SPeter Wemm 
670c2aa98e2SPeter Wemm 		/* be sure to give error messages in child */
671c2aa98e2SPeter Wemm 		QuickAbort = FALSE;
672c2aa98e2SPeter Wemm 
673c2aa98e2SPeter Wemm 		/*
674c2aa98e2SPeter Wemm 		**  Close any cached connections.
675c2aa98e2SPeter Wemm 		**
676c2aa98e2SPeter Wemm 		**	We don't send the QUIT protocol because the parent
677c2aa98e2SPeter Wemm 		**	still knows about the connection.
678c2aa98e2SPeter Wemm 		**
679c2aa98e2SPeter Wemm 		**	This should only happen when delivering an error
680c2aa98e2SPeter Wemm 		**	message.
681c2aa98e2SPeter Wemm 		*/
682c2aa98e2SPeter Wemm 
683c2aa98e2SPeter Wemm 		mci_flush(FALSE, NULL);
684c2aa98e2SPeter Wemm 
685c2aa98e2SPeter Wemm #if HASFLOCK
686c2aa98e2SPeter Wemm 		break;
68706f25ae9SGregory Neil Shapiro #else /* HASFLOCK */
688c2aa98e2SPeter Wemm 
689c2aa98e2SPeter Wemm 		/*
690c2aa98e2SPeter Wemm 		**  Now reacquire and run the various queue files.
691c2aa98e2SPeter Wemm 		*/
692c2aa98e2SPeter Wemm 
693c2aa98e2SPeter Wemm 		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
694c2aa98e2SPeter Wemm 		{
695c2aa98e2SPeter Wemm 			ENVELOPE *sibling = ee->e_sibling;
696c2aa98e2SPeter Wemm 
69706f25ae9SGregory Neil Shapiro 			(void) dowork(ee->e_queuedir, ee->e_id,
69806f25ae9SGregory Neil Shapiro 				      FALSE, FALSE, ee);
699c2aa98e2SPeter Wemm 			ee->e_sibling = sibling;
700c2aa98e2SPeter Wemm 		}
70106f25ae9SGregory Neil Shapiro 		(void) dowork(e->e_queuedir, e->e_id,
70206f25ae9SGregory Neil Shapiro 			      FALSE, FALSE, e);
703065a643dSPeter Wemm 		finis(TRUE, ExitStat);
70406f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */
705c2aa98e2SPeter Wemm 	}
706c2aa98e2SPeter Wemm 
707c2aa98e2SPeter Wemm 	sendenvelope(e, mode);
708c2aa98e2SPeter Wemm 	dropenvelope(e, TRUE);
709c2aa98e2SPeter Wemm 	for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
710c2aa98e2SPeter Wemm 	{
711c2aa98e2SPeter Wemm 		CurEnv = ee;
712c2aa98e2SPeter Wemm 		if (mode != SM_VERIFY)
713c2aa98e2SPeter Wemm 			openxscript(ee);
714c2aa98e2SPeter Wemm 		sendenvelope(ee, mode);
715c2aa98e2SPeter Wemm 		dropenvelope(ee, TRUE);
716c2aa98e2SPeter Wemm 	}
717c2aa98e2SPeter Wemm 	CurEnv = e;
718c2aa98e2SPeter Wemm 
719c2aa98e2SPeter Wemm 	Verbose = oldverbose;
720c2aa98e2SPeter Wemm 	if (mode == SM_FORK)
721065a643dSPeter Wemm 		finis(TRUE, ExitStat);
722c2aa98e2SPeter Wemm }
723c2aa98e2SPeter Wemm 
72406f25ae9SGregory Neil Shapiro static void
725c2aa98e2SPeter Wemm sendenvelope(e, mode)
726c2aa98e2SPeter Wemm 	register ENVELOPE *e;
727c2aa98e2SPeter Wemm 	int mode;
728c2aa98e2SPeter Wemm {
729c2aa98e2SPeter Wemm 	register ADDRESS *q;
730c2aa98e2SPeter Wemm 	bool didany;
731c2aa98e2SPeter Wemm 
732c2aa98e2SPeter Wemm 	if (tTd(13, 10))
73306f25ae9SGregory Neil Shapiro 		dprintf("sendenvelope(%s) e_flags=0x%lx\n",
734c2aa98e2SPeter Wemm 			e->e_id == NULL ? "[NOQUEUE]" : e->e_id,
735c2aa98e2SPeter Wemm 			e->e_flags);
736c2aa98e2SPeter Wemm 	if (LogLevel > 80)
737c2aa98e2SPeter Wemm 		sm_syslog(LOG_DEBUG, e->e_id,
73806f25ae9SGregory Neil Shapiro 			  "sendenvelope, flags=0x%lx",
739c2aa98e2SPeter Wemm 			  e->e_flags);
740c2aa98e2SPeter Wemm 
741c2aa98e2SPeter Wemm 	/*
742c2aa98e2SPeter Wemm 	**  If we have had global, fatal errors, don't bother sending
743c2aa98e2SPeter Wemm 	**  the message at all if we are in SMTP mode.  Local errors
744c2aa98e2SPeter Wemm 	**  (e.g., a single address failing) will still cause the other
745c2aa98e2SPeter Wemm 	**  addresses to be sent.
746c2aa98e2SPeter Wemm 	*/
747c2aa98e2SPeter Wemm 
748c2aa98e2SPeter Wemm 	if (bitset(EF_FATALERRS, e->e_flags) &&
749c2aa98e2SPeter Wemm 	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
750c2aa98e2SPeter Wemm 	{
751c2aa98e2SPeter Wemm 		e->e_flags |= EF_CLRQUEUE;
752c2aa98e2SPeter Wemm 		return;
753c2aa98e2SPeter Wemm 	}
754c2aa98e2SPeter Wemm 
75506f25ae9SGregory Neil Shapiro 	/* Don't attempt deliveries if we want to bounce now */
75606f25ae9SGregory Neil Shapiro 	if (!bitset(EF_RESPONSE, e->e_flags) &&
75706f25ae9SGregory Neil Shapiro 	    TimeOuts.to_q_return[e->e_timeoutclass] == NOW)
75806f25ae9SGregory Neil Shapiro 		return;
75906f25ae9SGregory Neil Shapiro 
760c2aa98e2SPeter Wemm 	/*
761c2aa98e2SPeter Wemm 	**  Run through the list and send everything.
762c2aa98e2SPeter Wemm 	**
763c2aa98e2SPeter Wemm 	**	Set EF_GLOBALERRS so that error messages during delivery
764c2aa98e2SPeter Wemm 	**	result in returned mail.
765c2aa98e2SPeter Wemm 	*/
766c2aa98e2SPeter Wemm 
767c2aa98e2SPeter Wemm 	e->e_nsent = 0;
768c2aa98e2SPeter Wemm 	e->e_flags |= EF_GLOBALERRS;
76906f25ae9SGregory Neil Shapiro 
770c2aa98e2SPeter Wemm 	define(macid("{envid}", NULL), e->e_envid, e);
771c2aa98e2SPeter Wemm 	define(macid("{bodytype}", NULL), e->e_bodytype, e);
772c2aa98e2SPeter Wemm 	didany = FALSE;
773c2aa98e2SPeter Wemm 
774c2aa98e2SPeter Wemm 	/* now run through the queue */
775c2aa98e2SPeter Wemm 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
776c2aa98e2SPeter Wemm 	{
777c2aa98e2SPeter Wemm #if XDEBUG
778c2aa98e2SPeter Wemm 		char wbuf[MAXNAME + 20];
779c2aa98e2SPeter Wemm 
780c2aa98e2SPeter Wemm 		(void) snprintf(wbuf, sizeof wbuf, "sendall(%.*s)",
781c2aa98e2SPeter Wemm 			MAXNAME, q->q_paddr);
782c2aa98e2SPeter Wemm 		checkfd012(wbuf);
78306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
784c2aa98e2SPeter Wemm 		if (mode == SM_VERIFY)
785c2aa98e2SPeter Wemm 		{
786c2aa98e2SPeter Wemm 			e->e_to = q->q_paddr;
78706f25ae9SGregory Neil Shapiro 			if (QS_IS_SENDABLE(q->q_state))
788c2aa98e2SPeter Wemm 			{
789c2aa98e2SPeter Wemm 				if (q->q_host != NULL && q->q_host[0] != '\0')
790c2aa98e2SPeter Wemm 					message("deliverable: mailer %s, host %s, user %s",
791c2aa98e2SPeter Wemm 						q->q_mailer->m_name,
792c2aa98e2SPeter Wemm 						q->q_host,
793c2aa98e2SPeter Wemm 						q->q_user);
794c2aa98e2SPeter Wemm 				else
795c2aa98e2SPeter Wemm 					message("deliverable: mailer %s, user %s",
796c2aa98e2SPeter Wemm 						q->q_mailer->m_name,
797c2aa98e2SPeter Wemm 						q->q_user);
798c2aa98e2SPeter Wemm 			}
799c2aa98e2SPeter Wemm 		}
80006f25ae9SGregory Neil Shapiro 		else if (QS_IS_OK(q->q_state))
801c2aa98e2SPeter Wemm 		{
802c2aa98e2SPeter Wemm #if QUEUE
803c2aa98e2SPeter Wemm 			/*
804c2aa98e2SPeter Wemm 			**  Checkpoint the send list every few addresses
805c2aa98e2SPeter Wemm 			*/
806c2aa98e2SPeter Wemm 
80742e5d165SGregory Neil Shapiro 			if (CheckpointInterval > 0 &&
80842e5d165SGregory Neil Shapiro 			    e->e_nsent >= CheckpointInterval)
809c2aa98e2SPeter Wemm 			{
810c2aa98e2SPeter Wemm 				queueup(e, FALSE);
811c2aa98e2SPeter Wemm 				e->e_nsent = 0;
812c2aa98e2SPeter Wemm 			}
813c2aa98e2SPeter Wemm #endif /* QUEUE */
814c2aa98e2SPeter Wemm 			(void) deliver(e, q);
815c2aa98e2SPeter Wemm 			didany = TRUE;
816c2aa98e2SPeter Wemm 		}
817c2aa98e2SPeter Wemm 	}
818c2aa98e2SPeter Wemm 	if (didany)
819c2aa98e2SPeter Wemm 	{
820c2aa98e2SPeter Wemm 		e->e_dtime = curtime();
821c2aa98e2SPeter Wemm 		e->e_ntries++;
822c2aa98e2SPeter Wemm 	}
823c2aa98e2SPeter Wemm 
824c2aa98e2SPeter Wemm #if XDEBUG
825c2aa98e2SPeter Wemm 	checkfd012("end of sendenvelope");
82606f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
827c2aa98e2SPeter Wemm }
828c2aa98e2SPeter Wemm /*
829c2aa98e2SPeter Wemm **  DUP_QUEUE_FILE -- duplicate a queue file into a split queue
830c2aa98e2SPeter Wemm **
831c2aa98e2SPeter Wemm **	Parameters:
832c2aa98e2SPeter Wemm **		e -- the existing envelope
833c2aa98e2SPeter Wemm **		ee -- the new envelope
834c2aa98e2SPeter Wemm **		type -- the queue file type (e.g., 'd')
835c2aa98e2SPeter Wemm **
836c2aa98e2SPeter Wemm **	Returns:
837c2aa98e2SPeter Wemm **		none
838c2aa98e2SPeter Wemm */
839c2aa98e2SPeter Wemm 
84006f25ae9SGregory Neil Shapiro static void
841c2aa98e2SPeter Wemm dup_queue_file(e, ee, type)
842c2aa98e2SPeter Wemm 	struct envelope *e, *ee;
843c2aa98e2SPeter Wemm 	int type;
844c2aa98e2SPeter Wemm {
84506f25ae9SGregory Neil Shapiro 	char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN];
846c2aa98e2SPeter Wemm 
847c2aa98e2SPeter Wemm 	ee->e_dfp = NULL;
848c2aa98e2SPeter Wemm 	ee->e_xfp = NULL;
84906f25ae9SGregory Neil Shapiro 
85006f25ae9SGregory Neil Shapiro 	/*
85106f25ae9SGregory Neil Shapiro 	**  Make sure both are in the same directory.
85206f25ae9SGregory Neil Shapiro 	*/
85306f25ae9SGregory Neil Shapiro 
854c2aa98e2SPeter Wemm 	snprintf(f1buf, sizeof f1buf, "%s", queuename(e, type));
855c2aa98e2SPeter Wemm 	snprintf(f2buf, sizeof f2buf, "%s", queuename(ee, type));
856c2aa98e2SPeter Wemm 	if (link(f1buf, f2buf) < 0)
857c2aa98e2SPeter Wemm 	{
85806f25ae9SGregory Neil Shapiro 		int save_errno = errno;
859c2aa98e2SPeter Wemm 
860c2aa98e2SPeter Wemm 		syserr("sendall: link(%s, %s)", f1buf, f2buf);
86106f25ae9SGregory Neil Shapiro 		if (save_errno == EEXIST)
862c2aa98e2SPeter Wemm 		{
863c2aa98e2SPeter Wemm 			if (unlink(f2buf) < 0)
864c2aa98e2SPeter Wemm 			{
865c2aa98e2SPeter Wemm 				syserr("!sendall: unlink(%s): permanent",
866c2aa98e2SPeter Wemm 					f2buf);
867c2aa98e2SPeter Wemm 				/* NOTREACHED */
868c2aa98e2SPeter Wemm 			}
869c2aa98e2SPeter Wemm 			if (link(f1buf, f2buf) < 0)
870c2aa98e2SPeter Wemm 			{
871c2aa98e2SPeter Wemm 				syserr("!sendall: link(%s, %s): permanent",
872c2aa98e2SPeter Wemm 					f1buf, f2buf);
873c2aa98e2SPeter Wemm 				/* NOTREACHED */
874c2aa98e2SPeter Wemm 			}
875c2aa98e2SPeter Wemm 		}
876c2aa98e2SPeter Wemm 	}
877c2aa98e2SPeter Wemm }
878c2aa98e2SPeter Wemm /*
879c2aa98e2SPeter Wemm **  DOFORK -- do a fork, retrying a couple of times on failure.
880c2aa98e2SPeter Wemm **
881c2aa98e2SPeter Wemm **	This MUST be a macro, since after a vfork we are running
882c2aa98e2SPeter Wemm **	two processes on the same stack!!!
883c2aa98e2SPeter Wemm **
884c2aa98e2SPeter Wemm **	Parameters:
885c2aa98e2SPeter Wemm **		none.
886c2aa98e2SPeter Wemm **
887c2aa98e2SPeter Wemm **	Returns:
888c2aa98e2SPeter Wemm **		From a macro???  You've got to be kidding!
889c2aa98e2SPeter Wemm **
890c2aa98e2SPeter Wemm **	Side Effects:
891c2aa98e2SPeter Wemm **		Modifies the ==> LOCAL <== variable 'pid', leaving:
892c2aa98e2SPeter Wemm **			pid of child in parent, zero in child.
893c2aa98e2SPeter Wemm **			-1 on unrecoverable error.
894c2aa98e2SPeter Wemm **
895c2aa98e2SPeter Wemm **	Notes:
896c2aa98e2SPeter Wemm **		I'm awfully sorry this looks so awful.  That's
897c2aa98e2SPeter Wemm **		vfork for you.....
898c2aa98e2SPeter Wemm */
899c2aa98e2SPeter Wemm 
900c2aa98e2SPeter Wemm #define NFORKTRIES	5
901c2aa98e2SPeter Wemm 
902c2aa98e2SPeter Wemm #ifndef FORK
903c2aa98e2SPeter Wemm # define FORK	fork
90406f25ae9SGregory Neil Shapiro #endif /* ! FORK */
905c2aa98e2SPeter Wemm 
906c2aa98e2SPeter Wemm #define DOFORK(fORKfN) \
907c2aa98e2SPeter Wemm {\
908c2aa98e2SPeter Wemm 	register int i;\
909c2aa98e2SPeter Wemm \
910c2aa98e2SPeter Wemm 	for (i = NFORKTRIES; --i >= 0; )\
911c2aa98e2SPeter Wemm 	{\
912c2aa98e2SPeter Wemm 		pid = fORKfN();\
913c2aa98e2SPeter Wemm 		if (pid >= 0)\
914c2aa98e2SPeter Wemm 			break;\
915c2aa98e2SPeter Wemm 		if (i > 0)\
91606f25ae9SGregory Neil Shapiro 			(void) sleep((unsigned) NFORKTRIES - i);\
917c2aa98e2SPeter Wemm 	}\
918c2aa98e2SPeter Wemm }
919c2aa98e2SPeter Wemm /*
920c2aa98e2SPeter Wemm **  DOFORK -- simple fork interface to DOFORK.
921c2aa98e2SPeter Wemm **
922c2aa98e2SPeter Wemm **	Parameters:
923c2aa98e2SPeter Wemm **		none.
924c2aa98e2SPeter Wemm **
925c2aa98e2SPeter Wemm **	Returns:
926c2aa98e2SPeter Wemm **		pid of child in parent.
927c2aa98e2SPeter Wemm **		zero in child.
928c2aa98e2SPeter Wemm **		-1 on error.
929c2aa98e2SPeter Wemm **
930c2aa98e2SPeter Wemm **	Side Effects:
931c2aa98e2SPeter Wemm **		returns twice, once in parent and once in child.
932c2aa98e2SPeter Wemm */
933c2aa98e2SPeter Wemm 
934c2aa98e2SPeter Wemm int
935c2aa98e2SPeter Wemm dofork()
936c2aa98e2SPeter Wemm {
937c2aa98e2SPeter Wemm 	register pid_t pid = -1;
938c2aa98e2SPeter Wemm 
939c2aa98e2SPeter Wemm 	DOFORK(fork);
94006f25ae9SGregory Neil Shapiro 	return pid;
941c2aa98e2SPeter Wemm }
942c2aa98e2SPeter Wemm /*
943c2aa98e2SPeter Wemm **  DELIVER -- Deliver a message to a list of addresses.
944c2aa98e2SPeter Wemm **
945c2aa98e2SPeter Wemm **	This routine delivers to everyone on the same host as the
946c2aa98e2SPeter Wemm **	user on the head of the list.  It is clever about mailers
947c2aa98e2SPeter Wemm **	that don't handle multiple users.  It is NOT guaranteed
948c2aa98e2SPeter Wemm **	that it will deliver to all these addresses however -- so
949c2aa98e2SPeter Wemm **	deliver should be called once for each address on the
950c2aa98e2SPeter Wemm **	list.
951c2aa98e2SPeter Wemm **
952c2aa98e2SPeter Wemm **	Parameters:
953c2aa98e2SPeter Wemm **		e -- the envelope to deliver.
954c2aa98e2SPeter Wemm **		firstto -- head of the address list to deliver to.
955c2aa98e2SPeter Wemm **
956c2aa98e2SPeter Wemm **	Returns:
957c2aa98e2SPeter Wemm **		zero -- successfully delivered.
958c2aa98e2SPeter Wemm **		else -- some failure, see ExitStat for more info.
959c2aa98e2SPeter Wemm **
960c2aa98e2SPeter Wemm **	Side Effects:
961c2aa98e2SPeter Wemm **		The standard input is passed off to someone.
962c2aa98e2SPeter Wemm */
963c2aa98e2SPeter Wemm 
964c2aa98e2SPeter Wemm #ifndef NO_UID
965c2aa98e2SPeter Wemm # define NO_UID		-1
96606f25ae9SGregory Neil Shapiro #endif /* ! NO_UID */
967c2aa98e2SPeter Wemm #ifndef NO_GID
968c2aa98e2SPeter Wemm # define NO_GID		-1
96906f25ae9SGregory Neil Shapiro #endif /* ! NO_GID */
970c2aa98e2SPeter Wemm 
97106f25ae9SGregory Neil Shapiro static int
972c2aa98e2SPeter Wemm deliver(e, firstto)
973c2aa98e2SPeter Wemm 	register ENVELOPE *e;
974c2aa98e2SPeter Wemm 	ADDRESS *firstto;
975c2aa98e2SPeter Wemm {
976c2aa98e2SPeter Wemm 	char *host;			/* host being sent to */
977c2aa98e2SPeter Wemm 	char *user;			/* user being sent to */
978c2aa98e2SPeter Wemm 	char **pvp;
979c2aa98e2SPeter Wemm 	register char **mvp;
980c2aa98e2SPeter Wemm 	register char *p;
981c2aa98e2SPeter Wemm 	register MAILER *m;		/* mailer for this recipient */
982c2aa98e2SPeter Wemm 	ADDRESS *volatile ctladdr;
983c2aa98e2SPeter Wemm 	ADDRESS *volatile contextaddr = NULL;
984c2aa98e2SPeter Wemm 	register MCI *volatile mci;
985c2aa98e2SPeter Wemm 	register ADDRESS *to = firstto;
986c2aa98e2SPeter Wemm 	volatile bool clever = FALSE;	/* running user smtp to this mailer */
987c2aa98e2SPeter Wemm 	ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */
988c2aa98e2SPeter Wemm 	int rcode;			/* response code */
989c2aa98e2SPeter Wemm 	int lmtp_rcode = EX_OK;
99006f25ae9SGregory Neil Shapiro 	int nummxhosts = 0;		/* number of MX hosts available */
99106f25ae9SGregory Neil Shapiro 	int hostnum = 0;		/* current MX host index */
992c2aa98e2SPeter Wemm 	char *firstsig;			/* signature of firstto */
993c2aa98e2SPeter Wemm 	pid_t pid = -1;
994c2aa98e2SPeter Wemm 	char *volatile curhost;
995c2aa98e2SPeter Wemm 	register u_short port = 0;
99606f25ae9SGregory Neil Shapiro #if NETUNIX
99706f25ae9SGregory Neil Shapiro 	char *mux_path = NULL;		/* path to UNIX domain socket */
99806f25ae9SGregory Neil Shapiro #endif /* NETUNIX */
999c2aa98e2SPeter Wemm 	time_t xstart;
1000c2aa98e2SPeter Wemm 	bool suidwarn;
1001c2aa98e2SPeter Wemm 	bool anyok;			/* at least one address was OK */
1002c2aa98e2SPeter Wemm 	bool goodmxfound = FALSE;	/* at least one MX was OK */
100306f25ae9SGregory Neil Shapiro 	bool ovr;
100406f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
100506f25ae9SGregory Neil Shapiro 	int strsize;
100606f25ae9SGregory Neil Shapiro 	int rcptcount;
100706f25ae9SGregory Neil Shapiro 	static int tobufsize = 0;
100806f25ae9SGregory Neil Shapiro 	static char *tobuf = NULL;
100906f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
101006f25ae9SGregory Neil Shapiro 	char tobuf[TOBUFSIZE];		/* text line of to people */
101106f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
1012c2aa98e2SPeter Wemm 	int mpvect[2];
1013c2aa98e2SPeter Wemm 	int rpvect[2];
101406f25ae9SGregory Neil Shapiro 	char *mxhosts[MAXMXHOSTS + 1];
1015c2aa98e2SPeter Wemm 	char *pv[MAXPV + 1];
1016c2aa98e2SPeter Wemm 	char buf[MAXNAME + 1];
1017c2aa98e2SPeter Wemm 	char rpathbuf[MAXNAME + 1];	/* translated return path */
1018c2aa98e2SPeter Wemm 
1019c2aa98e2SPeter Wemm 	errno = 0;
102006f25ae9SGregory Neil Shapiro 	if (!QS_IS_OK(to->q_state))
102106f25ae9SGregory Neil Shapiro 		return 0;
1022c2aa98e2SPeter Wemm 
1023c2aa98e2SPeter Wemm 	suidwarn = geteuid() == 0;
1024c2aa98e2SPeter Wemm 
1025c2aa98e2SPeter Wemm 	m = to->q_mailer;
1026c2aa98e2SPeter Wemm 	host = to->q_host;
1027c2aa98e2SPeter Wemm 	CurEnv = e;			/* just in case */
1028c2aa98e2SPeter Wemm 	e->e_statmsg = NULL;
1029c2aa98e2SPeter Wemm #if SMTP
1030c2aa98e2SPeter Wemm 	SmtpError[0] = '\0';
103106f25ae9SGregory Neil Shapiro #endif /* SMTP */
1032c2aa98e2SPeter Wemm 	xstart = curtime();
1033c2aa98e2SPeter Wemm 
1034c2aa98e2SPeter Wemm 	if (tTd(10, 1))
103506f25ae9SGregory Neil Shapiro 		dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
1036c2aa98e2SPeter Wemm 			e->e_id, m->m_name, host, to->q_user);
1037c2aa98e2SPeter Wemm 	if (tTd(10, 100))
1038c2aa98e2SPeter Wemm 		printopenfds(FALSE);
1039c2aa98e2SPeter Wemm 
1040c2aa98e2SPeter Wemm 	/*
1041c2aa98e2SPeter Wemm 	**  Clear $&{client_*} macros if this is a bounce message to
1042c2aa98e2SPeter Wemm 	**  prevent rejection by check_compat ruleset.
1043c2aa98e2SPeter Wemm 	*/
1044c2aa98e2SPeter Wemm 
1045c2aa98e2SPeter Wemm 	if (bitset(EF_RESPONSE, e->e_flags))
1046c2aa98e2SPeter Wemm 	{
1047c2aa98e2SPeter Wemm 		define(macid("{client_name}", NULL), "", e);
1048c2aa98e2SPeter Wemm 		define(macid("{client_addr}", NULL), "", e);
1049c2aa98e2SPeter Wemm 		define(macid("{client_port}", NULL), "", e);
1050c2aa98e2SPeter Wemm 	}
1051c2aa98e2SPeter Wemm 
1052c2aa98e2SPeter Wemm 	/*
1053c2aa98e2SPeter Wemm 	**  Do initial argv setup.
1054c2aa98e2SPeter Wemm 	**	Insert the mailer name.  Notice that $x expansion is
1055c2aa98e2SPeter Wemm 	**	NOT done on the mailer name.  Then, if the mailer has
1056c2aa98e2SPeter Wemm 	**	a picky -f flag, we insert it as appropriate.  This
1057c2aa98e2SPeter Wemm 	**	code does not check for 'pv' overflow; this places a
1058c2aa98e2SPeter Wemm 	**	manifest lower limit of 4 for MAXPV.
1059c2aa98e2SPeter Wemm 	**		The from address rewrite is expected to make
1060c2aa98e2SPeter Wemm 	**		the address relative to the other end.
1061c2aa98e2SPeter Wemm 	*/
1062c2aa98e2SPeter Wemm 
1063c2aa98e2SPeter Wemm 	/* rewrite from address, using rewriting rules */
1064c2aa98e2SPeter Wemm 	rcode = EX_OK;
1065c2aa98e2SPeter Wemm 	if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
1066c2aa98e2SPeter Wemm 		p = e->e_sender;
1067c2aa98e2SPeter Wemm 	else
1068c2aa98e2SPeter Wemm 		p = e->e_from.q_paddr;
1069c2aa98e2SPeter Wemm 	p = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e);
1070c2aa98e2SPeter Wemm 	if (strlen(p) >= (SIZE_T) sizeof rpathbuf)
1071c2aa98e2SPeter Wemm 	{
1072c2aa98e2SPeter Wemm 		p = shortenstring(p, MAXSHORTSTR);
1073c2aa98e2SPeter Wemm 		syserr("remotename: huge return %s", p);
1074c2aa98e2SPeter Wemm 	}
1075c2aa98e2SPeter Wemm 	snprintf(rpathbuf, sizeof rpathbuf, "%s", p);
1076c2aa98e2SPeter Wemm 	define('g', rpathbuf, e);		/* translated return path */
1077c2aa98e2SPeter Wemm 	define('h', host, e);			/* to host */
1078c2aa98e2SPeter Wemm 	Errors = 0;
1079c2aa98e2SPeter Wemm 	pvp = pv;
1080c2aa98e2SPeter Wemm 	*pvp++ = m->m_argv[0];
1081c2aa98e2SPeter Wemm 
1082c2aa98e2SPeter Wemm 	/* insert -f or -r flag as appropriate */
108306f25ae9SGregory Neil Shapiro 	if (FromFlag &&
108406f25ae9SGregory Neil Shapiro 	    (bitnset(M_FOPT, m->m_flags) ||
108506f25ae9SGregory Neil Shapiro 	     bitnset(M_ROPT, m->m_flags)))
1086c2aa98e2SPeter Wemm 	{
1087c2aa98e2SPeter Wemm 		if (bitnset(M_FOPT, m->m_flags))
1088c2aa98e2SPeter Wemm 			*pvp++ = "-f";
1089c2aa98e2SPeter Wemm 		else
1090c2aa98e2SPeter Wemm 			*pvp++ = "-r";
1091c2aa98e2SPeter Wemm 		*pvp++ = newstr(rpathbuf);
1092c2aa98e2SPeter Wemm 	}
1093c2aa98e2SPeter Wemm 
1094c2aa98e2SPeter Wemm 	/*
1095c2aa98e2SPeter Wemm 	**  Append the other fixed parts of the argv.  These run
1096c2aa98e2SPeter Wemm 	**  up to the first entry containing "$u".  There can only
1097c2aa98e2SPeter Wemm 	**  be one of these, and there are only a few more slots
1098c2aa98e2SPeter Wemm 	**  in the pv after it.
1099c2aa98e2SPeter Wemm 	*/
1100c2aa98e2SPeter Wemm 
1101c2aa98e2SPeter Wemm 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
1102c2aa98e2SPeter Wemm 	{
1103c2aa98e2SPeter Wemm 		/* can't use strchr here because of sign extension problems */
1104c2aa98e2SPeter Wemm 		while (*p != '\0')
1105c2aa98e2SPeter Wemm 		{
1106c2aa98e2SPeter Wemm 			if ((*p++ & 0377) == MACROEXPAND)
1107c2aa98e2SPeter Wemm 			{
1108c2aa98e2SPeter Wemm 				if (*p == 'u')
1109c2aa98e2SPeter Wemm 					break;
1110c2aa98e2SPeter Wemm 			}
1111c2aa98e2SPeter Wemm 		}
1112c2aa98e2SPeter Wemm 
1113c2aa98e2SPeter Wemm 		if (*p != '\0')
1114c2aa98e2SPeter Wemm 			break;
1115c2aa98e2SPeter Wemm 
1116c2aa98e2SPeter Wemm 		/* this entry is safe -- go ahead and process it */
1117c2aa98e2SPeter Wemm 		expand(*mvp, buf, sizeof buf, e);
1118c2aa98e2SPeter Wemm 		*pvp++ = newstr(buf);
1119c2aa98e2SPeter Wemm 		if (pvp >= &pv[MAXPV - 3])
1120c2aa98e2SPeter Wemm 		{
112106f25ae9SGregory Neil Shapiro 			syserr("554 5.3.5 Too many parameters to %s before $u",
112206f25ae9SGregory Neil Shapiro 			       pv[0]);
112306f25ae9SGregory Neil Shapiro 			return -1;
1124c2aa98e2SPeter Wemm 		}
1125c2aa98e2SPeter Wemm 	}
1126c2aa98e2SPeter Wemm 
1127c2aa98e2SPeter Wemm 	/*
1128c2aa98e2SPeter Wemm 	**  If we have no substitution for the user name in the argument
1129c2aa98e2SPeter Wemm 	**  list, we know that we must supply the names otherwise -- and
1130c2aa98e2SPeter Wemm 	**  SMTP is the answer!!
1131c2aa98e2SPeter Wemm 	*/
1132c2aa98e2SPeter Wemm 
1133c2aa98e2SPeter Wemm 	if (*mvp == NULL)
1134c2aa98e2SPeter Wemm 	{
1135602a2b1bSGregory Neil Shapiro 		/* running LMTP or SMTP */
1136c2aa98e2SPeter Wemm #if SMTP
1137c2aa98e2SPeter Wemm 		clever = TRUE;
1138c2aa98e2SPeter Wemm 		*pvp = NULL;
1139c2aa98e2SPeter Wemm #else /* SMTP */
1140c2aa98e2SPeter Wemm 		/* oops!  we don't implement SMTP */
114106f25ae9SGregory Neil Shapiro 		syserr("554 5.3.5 SMTP style mailer not implemented");
114206f25ae9SGregory Neil Shapiro 		return EX_SOFTWARE;
1143c2aa98e2SPeter Wemm #endif /* SMTP */
1144c2aa98e2SPeter Wemm 	}
1145602a2b1bSGregory Neil Shapiro 	else if (bitnset(M_LMTP, m->m_flags))
1146602a2b1bSGregory Neil Shapiro 	{
1147602a2b1bSGregory Neil Shapiro 		/* not running LMTP */
1148602a2b1bSGregory Neil Shapiro 		sm_syslog(LOG_ERR, NULL,
1149602a2b1bSGregory Neil Shapiro 			  "Warning: mailer %s: LMTP flag (F=z) turned off",
1150602a2b1bSGregory Neil Shapiro 			  m->m_name);
1151602a2b1bSGregory Neil Shapiro 		clrbitn(M_LMTP, m->m_flags);
1152602a2b1bSGregory Neil Shapiro 	}
1153c2aa98e2SPeter Wemm 
1154c2aa98e2SPeter Wemm 	/*
1155c2aa98e2SPeter Wemm 	**  At this point *mvp points to the argument with $u.  We
1156c2aa98e2SPeter Wemm 	**  run through our address list and append all the addresses
1157c2aa98e2SPeter Wemm 	**  we can.  If we run out of space, do not fret!  We can
1158c2aa98e2SPeter Wemm 	**  always send another copy later.
1159c2aa98e2SPeter Wemm 	*/
1160c2aa98e2SPeter Wemm 
116106f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
116206f25ae9SGregory Neil Shapiro 	e->e_to = NULL;
116306f25ae9SGregory Neil Shapiro 	strsize = 2;
116406f25ae9SGregory Neil Shapiro 	rcptcount = 0;
116506f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
1166c2aa98e2SPeter Wemm 	tobuf[0] = '\0';
1167c2aa98e2SPeter Wemm 	e->e_to = tobuf;
116806f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
116906f25ae9SGregory Neil Shapiro 
1170c2aa98e2SPeter Wemm 	ctladdr = NULL;
117106f25ae9SGregory Neil Shapiro 	firstsig = hostsignature(firstto->q_mailer, firstto->q_host);
1172c2aa98e2SPeter Wemm 	for (; to != NULL; to = to->q_next)
1173c2aa98e2SPeter Wemm 	{
1174c2aa98e2SPeter Wemm 		/* avoid sending multiple recipients to dumb mailers */
117506f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
117606f25ae9SGregory Neil Shapiro 		if (tochain != NULL && !bitnset(M_MUSER, m->m_flags))
117706f25ae9SGregory Neil Shapiro 			break;
117806f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
1179c2aa98e2SPeter Wemm 		if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))
1180c2aa98e2SPeter Wemm 			break;
118106f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
1182c2aa98e2SPeter Wemm 
1183c2aa98e2SPeter Wemm 		/* if already sent or not for this host, don't send */
118406f25ae9SGregory Neil Shapiro 		if (!QS_IS_OK(to->q_state) ||
1185c2aa98e2SPeter Wemm 		    to->q_mailer != firstto->q_mailer ||
118606f25ae9SGregory Neil Shapiro 		    strcmp(hostsignature(to->q_mailer, to->q_host),
118706f25ae9SGregory Neil Shapiro 			   firstsig) != 0)
1188c2aa98e2SPeter Wemm 			continue;
1189c2aa98e2SPeter Wemm 
1190c2aa98e2SPeter Wemm 		/* avoid overflowing tobuf */
119106f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
119206f25ae9SGregory Neil Shapiro 		strsize += strlen(to->q_paddr) + 1;
119306f25ae9SGregory Neil Shapiro 		if (!clever && strsize > TOBUFSIZE)
119406f25ae9SGregory Neil Shapiro 			break;
119506f25ae9SGregory Neil Shapiro 
119606f25ae9SGregory Neil Shapiro 		if (++rcptcount > to->q_mailer->m_maxrcpt)
119706f25ae9SGregory Neil Shapiro 			break;
119806f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
1199c2aa98e2SPeter Wemm 		if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))
1200c2aa98e2SPeter Wemm 			break;
120106f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
1202c2aa98e2SPeter Wemm 
1203c2aa98e2SPeter Wemm 		if (tTd(10, 1))
1204c2aa98e2SPeter Wemm 		{
120506f25ae9SGregory Neil Shapiro 			dprintf("\nsend to ");
1206c2aa98e2SPeter Wemm 			printaddr(to, FALSE);
1207c2aa98e2SPeter Wemm 		}
1208c2aa98e2SPeter Wemm 
1209c2aa98e2SPeter Wemm 		/* compute effective uid/gid when sending */
1210c2aa98e2SPeter Wemm 		if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
1211c2aa98e2SPeter Wemm 			contextaddr = ctladdr = getctladdr(to);
1212c2aa98e2SPeter Wemm 
1213c2aa98e2SPeter Wemm 		if (tTd(10, 2))
1214c2aa98e2SPeter Wemm 		{
121506f25ae9SGregory Neil Shapiro 			dprintf("ctladdr=");
1216c2aa98e2SPeter Wemm 			printaddr(ctladdr, FALSE);
1217c2aa98e2SPeter Wemm 		}
1218c2aa98e2SPeter Wemm 
1219c2aa98e2SPeter Wemm 		user = to->q_user;
1220c2aa98e2SPeter Wemm 		e->e_to = to->q_paddr;
1221c2aa98e2SPeter Wemm 
1222c2aa98e2SPeter Wemm 		/*
1223c2aa98e2SPeter Wemm 		**  Check to see that these people are allowed to
1224c2aa98e2SPeter Wemm 		**  talk to each other.
122542e5d165SGregory Neil Shapiro 		**  Check also for overflow of e_msgsize.
1226c2aa98e2SPeter Wemm 		*/
1227c2aa98e2SPeter Wemm 
122842e5d165SGregory Neil Shapiro 		if (m->m_maxsize != 0 &&
122942e5d165SGregory Neil Shapiro 		    (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0))
1230c2aa98e2SPeter Wemm 		{
1231c2aa98e2SPeter Wemm 			e->e_flags |= EF_NO_BODY_RETN;
1232c2aa98e2SPeter Wemm 			if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags))
1233c2aa98e2SPeter Wemm 				to->q_status = "5.2.3";
1234c2aa98e2SPeter Wemm 			else
1235c2aa98e2SPeter Wemm 				to->q_status = "5.3.4";
123606f25ae9SGregory Neil Shapiro 			/* set to->q_rstatus = NULL; or to the following? */
123706f25ae9SGregory Neil Shapiro 			usrerrenh(to->q_status,
123806f25ae9SGregory Neil Shapiro 				  "552 Message is too large; %ld bytes max",
123906f25ae9SGregory Neil Shapiro 				  m->m_maxsize);
124006f25ae9SGregory Neil Shapiro 			markfailure(e, to, NULL, EX_UNAVAILABLE, FALSE);
124106f25ae9SGregory Neil Shapiro 			giveresponse(EX_UNAVAILABLE, to->q_status, m,
124206f25ae9SGregory Neil Shapiro 				     NULL, ctladdr, xstart, e);
1243c2aa98e2SPeter Wemm 			continue;
1244c2aa98e2SPeter Wemm 		}
1245c2aa98e2SPeter Wemm #if NAMED_BIND
1246602a2b1bSGregory Neil Shapiro 		SM_SET_H_ERRNO(0);
124706f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
1248c2aa98e2SPeter Wemm 
124906f25ae9SGregory Neil Shapiro 		ovr = TRUE;
1250c2aa98e2SPeter Wemm 		/* do config file checking of compatibility */
125106f25ae9SGregory Neil Shapiro 		rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr,
1252193538b7SGregory Neil Shapiro 				e, TRUE, TRUE, 4, NULL);
1253c2aa98e2SPeter Wemm 		if (rcode == EX_OK)
1254c2aa98e2SPeter Wemm 		{
1255065a643dSPeter Wemm 			/* do in-code checking if not discarding */
1256065a643dSPeter Wemm 			if (!bitset(EF_DISCARD, e->e_flags))
125706f25ae9SGregory Neil Shapiro 			{
1258c2aa98e2SPeter Wemm 				rcode = checkcompat(to, e);
125906f25ae9SGregory Neil Shapiro 				ovr = FALSE;
126006f25ae9SGregory Neil Shapiro 			}
1261c2aa98e2SPeter Wemm 		}
1262c2aa98e2SPeter Wemm 		if (rcode != EX_OK)
1263c2aa98e2SPeter Wemm 		{
126406f25ae9SGregory Neil Shapiro 			markfailure(e, to, NULL, rcode, ovr);
126506f25ae9SGregory Neil Shapiro 			giveresponse(rcode, to->q_status, m,
126606f25ae9SGregory Neil Shapiro 				     NULL, ctladdr, xstart, e);
1267c2aa98e2SPeter Wemm 			continue;
1268c2aa98e2SPeter Wemm 		}
1269065a643dSPeter Wemm 		if (bitset(EF_DISCARD, e->e_flags))
1270065a643dSPeter Wemm 		{
1271065a643dSPeter Wemm 			if (tTd(10, 5))
1272065a643dSPeter Wemm 			{
127306f25ae9SGregory Neil Shapiro 				dprintf("deliver: discarding recipient ");
1274065a643dSPeter Wemm 				printaddr(to, FALSE);
1275065a643dSPeter Wemm 			}
1276065a643dSPeter Wemm 
127706f25ae9SGregory Neil Shapiro 			/* pretend the message was sent */
127806f25ae9SGregory Neil Shapiro 			/* XXX should we log something here? */
127906f25ae9SGregory Neil Shapiro 			to->q_state = QS_DISCARDED;
128006f25ae9SGregory Neil Shapiro 
1281065a643dSPeter Wemm 			/*
1282065a643dSPeter Wemm 			**  Remove discard bit to prevent discard of
128306f25ae9SGregory Neil Shapiro 			**  future recipients.  This is safe because the
128406f25ae9SGregory Neil Shapiro 			**  true "global discard" has been handled before
128506f25ae9SGregory Neil Shapiro 			**  we get here.
1286065a643dSPeter Wemm 			*/
1287065a643dSPeter Wemm 
128806f25ae9SGregory Neil Shapiro 			e->e_flags &= ~EF_DISCARD;
1289065a643dSPeter Wemm 			continue;
1290065a643dSPeter Wemm 		}
1291c2aa98e2SPeter Wemm 
1292c2aa98e2SPeter Wemm 		/*
1293c2aa98e2SPeter Wemm 		**  Strip quote bits from names if the mailer is dumb
1294c2aa98e2SPeter Wemm 		**	about them.
1295c2aa98e2SPeter Wemm 		*/
1296c2aa98e2SPeter Wemm 
1297c2aa98e2SPeter Wemm 		if (bitnset(M_STRIPQ, m->m_flags))
1298c2aa98e2SPeter Wemm 		{
1299c2aa98e2SPeter Wemm 			stripquotes(user);
1300c2aa98e2SPeter Wemm 			stripquotes(host);
1301c2aa98e2SPeter Wemm 		}
1302c2aa98e2SPeter Wemm 
1303c2aa98e2SPeter Wemm 		/* hack attack -- delivermail compatibility */
1304c2aa98e2SPeter Wemm 		if (m == ProgMailer && *user == '|')
1305c2aa98e2SPeter Wemm 			user++;
1306c2aa98e2SPeter Wemm 
1307c2aa98e2SPeter Wemm 		/*
1308c2aa98e2SPeter Wemm 		**  If an error message has already been given, don't
1309c2aa98e2SPeter Wemm 		**	bother to send to this address.
1310c2aa98e2SPeter Wemm 		**
1311c2aa98e2SPeter Wemm 		**	>>>>>>>>>> This clause assumes that the local mailer
1312c2aa98e2SPeter Wemm 		**	>> NOTE >> cannot do any further aliasing; that
1313c2aa98e2SPeter Wemm 		**	>>>>>>>>>> function is subsumed by sendmail.
1314c2aa98e2SPeter Wemm 		*/
1315c2aa98e2SPeter Wemm 
131606f25ae9SGregory Neil Shapiro 		if (!QS_IS_OK(to->q_state))
1317c2aa98e2SPeter Wemm 			continue;
1318c2aa98e2SPeter Wemm 
1319c2aa98e2SPeter Wemm 		/*
1320c2aa98e2SPeter Wemm 		**  See if this user name is "special".
1321c2aa98e2SPeter Wemm 		**	If the user name has a slash in it, assume that this
1322c2aa98e2SPeter Wemm 		**	is a file -- send it off without further ado.  Note
1323c2aa98e2SPeter Wemm 		**	that this type of addresses is not processed along
1324c2aa98e2SPeter Wemm 		**	with the others, so we fudge on the To person.
1325c2aa98e2SPeter Wemm 		*/
1326c2aa98e2SPeter Wemm 
1327c2aa98e2SPeter Wemm 		if (strcmp(m->m_mailer, "[FILE]") == 0)
1328c2aa98e2SPeter Wemm 		{
1329c2aa98e2SPeter Wemm 			define('u', user, e);	/* to user */
1330c2aa98e2SPeter Wemm 			p = to->q_home;
1331c2aa98e2SPeter Wemm 			if (p == NULL && ctladdr != NULL)
1332c2aa98e2SPeter Wemm 				p = ctladdr->q_home;
1333c2aa98e2SPeter Wemm 			define('z', p, e);	/* user's home */
1334c2aa98e2SPeter Wemm 			expand(m->m_argv[1], buf, sizeof buf, e);
1335c2aa98e2SPeter Wemm 			if (strlen(buf) > 0)
1336c2aa98e2SPeter Wemm 				rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e);
1337c2aa98e2SPeter Wemm 			else
1338c2aa98e2SPeter Wemm 			{
1339c2aa98e2SPeter Wemm 				syserr("empty filename specification for mailer %s",
1340c2aa98e2SPeter Wemm 				       m->m_name);
1341c2aa98e2SPeter Wemm 				rcode = EX_CONFIG;
1342c2aa98e2SPeter Wemm 			}
134306f25ae9SGregory Neil Shapiro 			giveresponse(rcode, to->q_status, m, NULL,
134406f25ae9SGregory Neil Shapiro 				     ctladdr, xstart, e);
134506f25ae9SGregory Neil Shapiro 			markfailure(e, to, NULL, rcode, TRUE);
1346c2aa98e2SPeter Wemm 			e->e_nsent++;
1347c2aa98e2SPeter Wemm 			if (rcode == EX_OK)
1348c2aa98e2SPeter Wemm 			{
134906f25ae9SGregory Neil Shapiro 				to->q_state = QS_SENT;
1350c2aa98e2SPeter Wemm 				if (bitnset(M_LOCALMAILER, m->m_flags) &&
1351c2aa98e2SPeter Wemm 				    bitset(QPINGONSUCCESS, to->q_flags))
1352c2aa98e2SPeter Wemm 				{
1353c2aa98e2SPeter Wemm 					to->q_flags |= QDELIVERED;
1354c2aa98e2SPeter Wemm 					to->q_status = "2.1.5";
1355c2aa98e2SPeter Wemm 					fprintf(e->e_xfp, "%s... Successfully delivered\n",
1356c2aa98e2SPeter Wemm 						to->q_paddr);
1357c2aa98e2SPeter Wemm 				}
1358c2aa98e2SPeter Wemm 			}
1359c2aa98e2SPeter Wemm 			to->q_statdate = curtime();
1360c2aa98e2SPeter Wemm 			markstats(e, to, FALSE);
1361c2aa98e2SPeter Wemm 			continue;
1362c2aa98e2SPeter Wemm 		}
1363c2aa98e2SPeter Wemm 
1364c2aa98e2SPeter Wemm 		/*
1365c2aa98e2SPeter Wemm 		**  Address is verified -- add this user to mailer
1366c2aa98e2SPeter Wemm 		**  argv, and add it to the print list of recipients.
1367c2aa98e2SPeter Wemm 		*/
1368c2aa98e2SPeter Wemm 
1369c2aa98e2SPeter Wemm 		/* link together the chain of recipients */
1370c2aa98e2SPeter Wemm 		to->q_tchain = tochain;
1371c2aa98e2SPeter Wemm 		tochain = to;
1372c2aa98e2SPeter Wemm 
137306f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
137406f25ae9SGregory Neil Shapiro 		e->e_to = "[CHAIN]";
137506f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
1376c2aa98e2SPeter Wemm 		/* create list of users for error messages */
137706f25ae9SGregory Neil Shapiro 		(void) strlcat(tobuf, ",", sizeof tobuf);
137806f25ae9SGregory Neil Shapiro 		(void) strlcat(tobuf, to->q_paddr, sizeof tobuf);
137906f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
138006f25ae9SGregory Neil Shapiro 
1381c2aa98e2SPeter Wemm 		define('u', user, e);		/* to user */
1382c2aa98e2SPeter Wemm 		p = to->q_home;
1383c2aa98e2SPeter Wemm 		if (p == NULL && ctladdr != NULL)
1384c2aa98e2SPeter Wemm 			p = ctladdr->q_home;
1385c2aa98e2SPeter Wemm 		define('z', p, e);	/* user's home */
1386c2aa98e2SPeter Wemm 
138706f25ae9SGregory Neil Shapiro 		/* set the ${dsn_notify} macro if applicable */
138806f25ae9SGregory Neil Shapiro 		if (bitset(QHASNOTIFY, to->q_flags))
138906f25ae9SGregory Neil Shapiro 		{
139006f25ae9SGregory Neil Shapiro 			char notify[MAXLINE];
139106f25ae9SGregory Neil Shapiro 
139206f25ae9SGregory Neil Shapiro 			notify[0] = '\0';
139306f25ae9SGregory Neil Shapiro 			if (bitset(QPINGONSUCCESS, to->q_flags))
139406f25ae9SGregory Neil Shapiro 				(void) strlcat(notify, "SUCCESS,",
139506f25ae9SGregory Neil Shapiro 					       sizeof notify);
139606f25ae9SGregory Neil Shapiro 			if (bitset(QPINGONFAILURE, to->q_flags))
139706f25ae9SGregory Neil Shapiro 				(void) strlcat(notify, "FAILURE,",
139806f25ae9SGregory Neil Shapiro 					       sizeof notify);
139906f25ae9SGregory Neil Shapiro 			if (bitset(QPINGONDELAY, to->q_flags))
140006f25ae9SGregory Neil Shapiro 				(void) strlcat(notify, "DELAY,", sizeof notify);
140106f25ae9SGregory Neil Shapiro 
140206f25ae9SGregory Neil Shapiro 			/* Set to NEVER or drop trailing comma */
140306f25ae9SGregory Neil Shapiro 			if (notify[0] == '\0')
140406f25ae9SGregory Neil Shapiro 				(void) strlcat(notify, "NEVER", sizeof notify);
140506f25ae9SGregory Neil Shapiro 			else
140606f25ae9SGregory Neil Shapiro 				notify[strlen(notify) - 1] = '\0';
140706f25ae9SGregory Neil Shapiro 
140806f25ae9SGregory Neil Shapiro 			define(macid("{dsn_notify}", NULL), newstr(notify), e);
140906f25ae9SGregory Neil Shapiro 		}
141006f25ae9SGregory Neil Shapiro 		else
141106f25ae9SGregory Neil Shapiro 			define(macid("{dsn_notify}", NULL), NULL, e);
141206f25ae9SGregory Neil Shapiro 
1413c2aa98e2SPeter Wemm 		/*
1414c2aa98e2SPeter Wemm 		**  Expand out this user into argument list.
1415c2aa98e2SPeter Wemm 		*/
1416c2aa98e2SPeter Wemm 
1417c2aa98e2SPeter Wemm 		if (!clever)
1418c2aa98e2SPeter Wemm 		{
1419c2aa98e2SPeter Wemm 			expand(*mvp, buf, sizeof buf, e);
1420c2aa98e2SPeter Wemm 			*pvp++ = newstr(buf);
1421c2aa98e2SPeter Wemm 			if (pvp >= &pv[MAXPV - 2])
1422c2aa98e2SPeter Wemm 			{
1423c2aa98e2SPeter Wemm 				/* allow some space for trailing parms */
1424c2aa98e2SPeter Wemm 				break;
1425c2aa98e2SPeter Wemm 			}
1426c2aa98e2SPeter Wemm 		}
1427c2aa98e2SPeter Wemm 	}
1428c2aa98e2SPeter Wemm 
1429c2aa98e2SPeter Wemm 	/* see if any addresses still exist */
143006f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
143106f25ae9SGregory Neil Shapiro 	if (tochain == NULL)
143206f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
1433c2aa98e2SPeter Wemm 	if (tobuf[0] == '\0')
143406f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
1435c2aa98e2SPeter Wemm 	{
1436c2aa98e2SPeter Wemm 		define('g', (char *) NULL, e);
143706f25ae9SGregory Neil Shapiro 		e->e_to = NULL;
143806f25ae9SGregory Neil Shapiro 		return 0;
1439c2aa98e2SPeter Wemm 	}
1440c2aa98e2SPeter Wemm 
1441c2aa98e2SPeter Wemm 	/* print out messages as full list */
144206f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
144306f25ae9SGregory Neil Shapiro 	{
144406f25ae9SGregory Neil Shapiro 		int l = 1;
144506f25ae9SGregory Neil Shapiro 		char *tobufptr;
144606f25ae9SGregory Neil Shapiro 
144706f25ae9SGregory Neil Shapiro 		for (to = tochain; to != NULL; to = to->q_tchain)
144806f25ae9SGregory Neil Shapiro 			l += strlen(to->q_paddr) + 1;
144906f25ae9SGregory Neil Shapiro 		if (l < TOBUFSIZE)
145006f25ae9SGregory Neil Shapiro 			l = TOBUFSIZE;
145106f25ae9SGregory Neil Shapiro 		if (l > tobufsize)
145206f25ae9SGregory Neil Shapiro 		{
145306f25ae9SGregory Neil Shapiro 			if (tobuf != NULL)
145406f25ae9SGregory Neil Shapiro 				free(tobuf);
145506f25ae9SGregory Neil Shapiro 			tobufsize = l;
145606f25ae9SGregory Neil Shapiro 			tobuf = xalloc(tobufsize);
145706f25ae9SGregory Neil Shapiro 		}
145806f25ae9SGregory Neil Shapiro 		tobufptr = tobuf;
145906f25ae9SGregory Neil Shapiro 		*tobufptr = '\0';
146006f25ae9SGregory Neil Shapiro 		for (to = tochain; to != NULL; to = to->q_tchain)
146106f25ae9SGregory Neil Shapiro 		{
146206f25ae9SGregory Neil Shapiro 			snprintf(tobufptr, tobufsize - (tobufptr - tobuf),
146306f25ae9SGregory Neil Shapiro 				 ",%s", to->q_paddr);
146406f25ae9SGregory Neil Shapiro 			tobufptr += strlen(tobufptr);
146506f25ae9SGregory Neil Shapiro 		}
146606f25ae9SGregory Neil Shapiro 	}
146706f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
1468c2aa98e2SPeter Wemm 	e->e_to = tobuf + 1;
1469c2aa98e2SPeter Wemm 
1470c2aa98e2SPeter Wemm 	/*
1471c2aa98e2SPeter Wemm 	**  Fill out any parameters after the $u parameter.
1472c2aa98e2SPeter Wemm 	*/
1473c2aa98e2SPeter Wemm 
1474c2aa98e2SPeter Wemm 	while (!clever && *++mvp != NULL)
1475c2aa98e2SPeter Wemm 	{
1476c2aa98e2SPeter Wemm 		expand(*mvp, buf, sizeof buf, e);
1477c2aa98e2SPeter Wemm 		*pvp++ = newstr(buf);
1478c2aa98e2SPeter Wemm 		if (pvp >= &pv[MAXPV])
147906f25ae9SGregory Neil Shapiro 			syserr("554 5.3.0 deliver: pv overflow after $u for %s",
148006f25ae9SGregory Neil Shapiro 			       pv[0]);
1481c2aa98e2SPeter Wemm 	}
1482c2aa98e2SPeter Wemm 	*pvp++ = NULL;
1483c2aa98e2SPeter Wemm 
1484c2aa98e2SPeter Wemm 	/*
1485c2aa98e2SPeter Wemm 	**  Call the mailer.
1486c2aa98e2SPeter Wemm 	**	The argument vector gets built, pipes
1487c2aa98e2SPeter Wemm 	**	are created as necessary, and we fork & exec as
1488c2aa98e2SPeter Wemm 	**	appropriate.
1489c2aa98e2SPeter Wemm 	**	If we are running SMTP, we just need to clean up.
1490c2aa98e2SPeter Wemm 	*/
1491c2aa98e2SPeter Wemm 
1492c2aa98e2SPeter Wemm 	/* XXX this seems a bit wierd */
1493c2aa98e2SPeter Wemm 	if (ctladdr == NULL && m != ProgMailer && m != FileMailer &&
1494c2aa98e2SPeter Wemm 	    bitset(QGOODUID, e->e_from.q_flags))
1495c2aa98e2SPeter Wemm 		ctladdr = &e->e_from;
1496c2aa98e2SPeter Wemm 
1497c2aa98e2SPeter Wemm #if NAMED_BIND
1498c2aa98e2SPeter Wemm 	if (ConfigLevel < 2)
1499c2aa98e2SPeter Wemm 		_res.options &= ~(RES_DEFNAMES | RES_DNSRCH);	/* XXX */
150006f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
1501c2aa98e2SPeter Wemm 
1502c2aa98e2SPeter Wemm 	if (tTd(11, 1))
1503c2aa98e2SPeter Wemm 	{
150406f25ae9SGregory Neil Shapiro 		dprintf("openmailer:");
1505c2aa98e2SPeter Wemm 		printav(pv);
1506c2aa98e2SPeter Wemm 	}
1507c2aa98e2SPeter Wemm 	errno = 0;
1508c2aa98e2SPeter Wemm #if NAMED_BIND
1509602a2b1bSGregory Neil Shapiro 	SM_SET_H_ERRNO(0);
151006f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
1511c2aa98e2SPeter Wemm 
1512c2aa98e2SPeter Wemm 	CurHostName = NULL;
1513c2aa98e2SPeter Wemm 
1514c2aa98e2SPeter Wemm 	/*
1515c2aa98e2SPeter Wemm 	**  Deal with the special case of mail handled through an IPC
1516c2aa98e2SPeter Wemm 	**  connection.
1517c2aa98e2SPeter Wemm 	**	In this case we don't actually fork.  We must be
1518c2aa98e2SPeter Wemm 	**	running SMTP for this to work.  We will return a
1519c2aa98e2SPeter Wemm 	**	zero pid to indicate that we are running IPC.
1520c2aa98e2SPeter Wemm 	**  We also handle a debug version that just talks to stdin/out.
1521c2aa98e2SPeter Wemm 	*/
1522c2aa98e2SPeter Wemm 
1523c2aa98e2SPeter Wemm 	curhost = NULL;
1524c2aa98e2SPeter Wemm 	SmtpPhase = NULL;
1525c2aa98e2SPeter Wemm 	mci = NULL;
1526c2aa98e2SPeter Wemm 
1527c2aa98e2SPeter Wemm #if XDEBUG
1528c2aa98e2SPeter Wemm 	{
1529c2aa98e2SPeter Wemm 		char wbuf[MAXLINE];
1530c2aa98e2SPeter Wemm 
1531c2aa98e2SPeter Wemm 		/* make absolutely certain 0, 1, and 2 are in use */
1532c2aa98e2SPeter Wemm 		snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)",
1533c2aa98e2SPeter Wemm 			shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
1534c2aa98e2SPeter Wemm 		checkfd012(wbuf);
1535c2aa98e2SPeter Wemm 	}
153606f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
1537c2aa98e2SPeter Wemm 
1538c2aa98e2SPeter Wemm 	/* check for 8-bit available */
1539c2aa98e2SPeter Wemm 	if (bitset(EF_HAS8BIT, e->e_flags) &&
1540c2aa98e2SPeter Wemm 	    bitnset(M_7BITS, m->m_flags) &&
1541c2aa98e2SPeter Wemm 	    (bitset(EF_DONT_MIME, e->e_flags) ||
1542c2aa98e2SPeter Wemm 	     !(bitset(MM_MIME8BIT, MimeMode) ||
1543c2aa98e2SPeter Wemm 	       (bitset(EF_IS_MIME, e->e_flags) &&
1544c2aa98e2SPeter Wemm 		bitset(MM_CVTMIME, MimeMode)))))
1545c2aa98e2SPeter Wemm 	{
1546c2aa98e2SPeter Wemm 		e->e_status = "5.6.3";
154706f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status,
154806f25ae9SGregory Neil Shapiro 		       "554 Cannot send 8-bit data to 7-bit destination");
154906f25ae9SGregory Neil Shapiro 		rcode = EX_DATAERR;
1550c2aa98e2SPeter Wemm 		goto give_up;
1551c2aa98e2SPeter Wemm 	}
1552c2aa98e2SPeter Wemm 
1553c2aa98e2SPeter Wemm 	if (tTd(62, 8))
1554c2aa98e2SPeter Wemm 		checkfds("before delivery");
1555c2aa98e2SPeter Wemm 
1556c2aa98e2SPeter Wemm 	/* check for Local Person Communication -- not for mortals!!! */
1557c2aa98e2SPeter Wemm 	if (strcmp(m->m_mailer, "[LPC]") == 0)
1558c2aa98e2SPeter Wemm 	{
1559c2aa98e2SPeter Wemm 		mci = (MCI *) xalloc(sizeof *mci);
156006f25ae9SGregory Neil Shapiro 		memset((char *) mci, '\0', sizeof *mci);
1561c2aa98e2SPeter Wemm 		mci->mci_in = stdin;
1562c2aa98e2SPeter Wemm 		mci->mci_out = stdout;
1563c2aa98e2SPeter Wemm 		mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
1564c2aa98e2SPeter Wemm 		mci->mci_mailer = m;
1565c2aa98e2SPeter Wemm 	}
1566c2aa98e2SPeter Wemm 	else if (strcmp(m->m_mailer, "[IPC]") == 0 ||
1567c2aa98e2SPeter Wemm 		 strcmp(m->m_mailer, "[TCP]") == 0)
1568c2aa98e2SPeter Wemm 	{
1569c2aa98e2SPeter Wemm #if DAEMON
1570c2aa98e2SPeter Wemm 		register int i;
1571c2aa98e2SPeter Wemm 
1572c2aa98e2SPeter Wemm 		if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
1573c2aa98e2SPeter Wemm 		{
157406f25ae9SGregory Neil Shapiro 			syserr("null destination for %s mailer", m->m_mailer);
1575c2aa98e2SPeter Wemm 			rcode = EX_CONFIG;
1576c2aa98e2SPeter Wemm 			goto give_up;
1577c2aa98e2SPeter Wemm 		}
1578c2aa98e2SPeter Wemm 
157906f25ae9SGregory Neil Shapiro # if NETUNIX
158006f25ae9SGregory Neil Shapiro 		if (strcmp(pv[0], "FILE") == 0)
158106f25ae9SGregory Neil Shapiro 		{
158206f25ae9SGregory Neil Shapiro 			curhost = CurHostName = "localhost";
158306f25ae9SGregory Neil Shapiro 			mux_path = pv[1];
158406f25ae9SGregory Neil Shapiro 		}
158506f25ae9SGregory Neil Shapiro 		else
158606f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
158706f25ae9SGregory Neil Shapiro 		{
1588c2aa98e2SPeter Wemm 			CurHostName = pv[1];
158906f25ae9SGregory Neil Shapiro 			curhost = hostsignature(m, pv[1]);
159006f25ae9SGregory Neil Shapiro 		}
1591c2aa98e2SPeter Wemm 
1592c2aa98e2SPeter Wemm 		if (curhost == NULL || curhost[0] == '\0')
1593c2aa98e2SPeter Wemm 		{
1594c2aa98e2SPeter Wemm 			syserr("null host signature for %s", pv[1]);
1595c2aa98e2SPeter Wemm 			rcode = EX_CONFIG;
1596c2aa98e2SPeter Wemm 			goto give_up;
1597c2aa98e2SPeter Wemm 		}
1598c2aa98e2SPeter Wemm 
1599c2aa98e2SPeter Wemm 		if (!clever)
1600c2aa98e2SPeter Wemm 		{
160106f25ae9SGregory Neil Shapiro 			syserr("554 5.3.5 non-clever IPC");
1602c2aa98e2SPeter Wemm 			rcode = EX_CONFIG;
1603c2aa98e2SPeter Wemm 			goto give_up;
1604c2aa98e2SPeter Wemm 		}
160506f25ae9SGregory Neil Shapiro 		if (pv[2] != NULL
160606f25ae9SGregory Neil Shapiro # if NETUNIX
160706f25ae9SGregory Neil Shapiro 		    && mux_path == NULL
160806f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
160906f25ae9SGregory Neil Shapiro 		    )
1610c2aa98e2SPeter Wemm 		{
161106f25ae9SGregory Neil Shapiro 			port = htons((u_short)atoi(pv[2]));
1612c2aa98e2SPeter Wemm 			if (port == 0)
1613c2aa98e2SPeter Wemm 			{
161406f25ae9SGregory Neil Shapiro # ifdef NO_GETSERVBYNAME
161506f25ae9SGregory Neil Shapiro 				syserr("Invalid port number: %s", pv[2]);
161606f25ae9SGregory Neil Shapiro # else /* NO_GETSERVBYNAME */
1617c2aa98e2SPeter Wemm 				struct servent *sp = getservbyname(pv[2], "tcp");
1618c2aa98e2SPeter Wemm 
1619c2aa98e2SPeter Wemm 				if (sp == NULL)
1620c2aa98e2SPeter Wemm 					syserr("Service %s unknown", pv[2]);
1621c2aa98e2SPeter Wemm 				else
1622c2aa98e2SPeter Wemm 					port = sp->s_port;
162306f25ae9SGregory Neil Shapiro # endif /* NO_GETSERVBYNAME */
1624c2aa98e2SPeter Wemm 			}
1625c2aa98e2SPeter Wemm 		}
1626c2aa98e2SPeter Wemm 
162706f25ae9SGregory Neil Shapiro 		nummxhosts = parse_hostsignature(curhost, mxhosts, m);
162806f25ae9SGregory Neil Shapiro tryhost:
162906f25ae9SGregory Neil Shapiro 		while (hostnum < nummxhosts)
163006f25ae9SGregory Neil Shapiro 		{
163106f25ae9SGregory Neil Shapiro 			char sep = ':';
163206f25ae9SGregory Neil Shapiro 			char *endp;
163306f25ae9SGregory Neil Shapiro 			static char hostbuf[MAXNAME + 1];
163406f25ae9SGregory Neil Shapiro 
163506f25ae9SGregory Neil Shapiro # if NETINET6
163606f25ae9SGregory Neil Shapiro 			if (*mxhosts[hostnum] == '[')
163706f25ae9SGregory Neil Shapiro 			{
163806f25ae9SGregory Neil Shapiro 				endp = strchr(mxhosts[hostnum] + 1, ']');
163906f25ae9SGregory Neil Shapiro 				if (endp != NULL)
164006f25ae9SGregory Neil Shapiro 					endp = strpbrk(endp + 1, ":,");
164106f25ae9SGregory Neil Shapiro 			}
164206f25ae9SGregory Neil Shapiro 			else
164306f25ae9SGregory Neil Shapiro 				endp = strpbrk(mxhosts[hostnum], ":,");
164406f25ae9SGregory Neil Shapiro # else /* NETINET6 */
164506f25ae9SGregory Neil Shapiro 			endp = strpbrk(mxhosts[hostnum], ":,");
164606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
164706f25ae9SGregory Neil Shapiro 			if (endp != NULL)
164806f25ae9SGregory Neil Shapiro 			{
164906f25ae9SGregory Neil Shapiro 				sep = *endp;
165006f25ae9SGregory Neil Shapiro 				*endp = '\0';
165106f25ae9SGregory Neil Shapiro 			}
165206f25ae9SGregory Neil Shapiro 
165306f25ae9SGregory Neil Shapiro 			if (*mxhosts[hostnum] == '\0')
1654c2aa98e2SPeter Wemm 			{
1655c2aa98e2SPeter Wemm 				syserr("deliver: null host name in signature");
165606f25ae9SGregory Neil Shapiro 				hostnum++;
165706f25ae9SGregory Neil Shapiro 				if (endp != NULL)
165806f25ae9SGregory Neil Shapiro 					*endp = sep;
1659c2aa98e2SPeter Wemm 				continue;
1660c2aa98e2SPeter Wemm 			}
166106f25ae9SGregory Neil Shapiro 			(void) strlcpy(hostbuf, mxhosts[hostnum],
166206f25ae9SGregory Neil Shapiro 				       sizeof hostbuf);
166306f25ae9SGregory Neil Shapiro 			hostnum++;
166406f25ae9SGregory Neil Shapiro 			if (endp != NULL)
166506f25ae9SGregory Neil Shapiro 				*endp = sep;
1666c2aa98e2SPeter Wemm 
1667c2aa98e2SPeter Wemm 			/* see if we already know that this host is fried */
1668c2aa98e2SPeter Wemm 			CurHostName = hostbuf;
1669c2aa98e2SPeter Wemm 			mci = mci_get(hostbuf, m);
1670c2aa98e2SPeter Wemm 			if (mci->mci_state != MCIS_CLOSED)
1671c2aa98e2SPeter Wemm 			{
1672c2aa98e2SPeter Wemm 				if (tTd(11, 1))
1673c2aa98e2SPeter Wemm 				{
167406f25ae9SGregory Neil Shapiro 					dprintf("openmailer: ");
1675c2aa98e2SPeter Wemm 					mci_dump(mci, FALSE);
1676c2aa98e2SPeter Wemm 				}
1677c2aa98e2SPeter Wemm 				CurHostName = mci->mci_host;
1678c2aa98e2SPeter Wemm 				message("Using cached %sSMTP connection to %s via %s...",
1679c2aa98e2SPeter Wemm 					bitset(MCIF_ESMTP, mci->mci_flags) ? "E" : "",
1680c2aa98e2SPeter Wemm 					hostbuf, m->m_name);
168106f25ae9SGregory Neil Shapiro 				mci->mci_deliveries++;
1682c2aa98e2SPeter Wemm 				break;
1683c2aa98e2SPeter Wemm 			}
1684c2aa98e2SPeter Wemm 			mci->mci_mailer = m;
1685c2aa98e2SPeter Wemm 			if (mci->mci_exitstat != EX_OK)
1686c2aa98e2SPeter Wemm 			{
1687c2aa98e2SPeter Wemm 				if (mci->mci_exitstat == EX_TEMPFAIL)
1688c2aa98e2SPeter Wemm 					goodmxfound = TRUE;
1689c2aa98e2SPeter Wemm 				continue;
1690c2aa98e2SPeter Wemm 			}
1691c2aa98e2SPeter Wemm 
1692c2aa98e2SPeter Wemm 			if (mci_lock_host(mci) != EX_OK)
1693c2aa98e2SPeter Wemm 			{
1694c2aa98e2SPeter Wemm 				mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
1695c2aa98e2SPeter Wemm 				goodmxfound = TRUE;
1696c2aa98e2SPeter Wemm 				continue;
1697c2aa98e2SPeter Wemm 			}
1698c2aa98e2SPeter Wemm 
1699c2aa98e2SPeter Wemm 			/* try the connection */
170006f25ae9SGregory Neil Shapiro 			sm_setproctitle(TRUE, e, "%s %s: %s",
170106f25ae9SGregory Neil Shapiro 					qid_printname(e),
170206f25ae9SGregory Neil Shapiro 					hostbuf, "user open");
170306f25ae9SGregory Neil Shapiro # if NETUNIX
170406f25ae9SGregory Neil Shapiro 			if (mux_path != NULL)
170506f25ae9SGregory Neil Shapiro 			{
170606f25ae9SGregory Neil Shapiro 				message("Connecting to %s via %s...",
170706f25ae9SGregory Neil Shapiro 					mux_path, m->m_name);
170806f25ae9SGregory Neil Shapiro 				i = makeconnection_ds(mux_path, mci);
170906f25ae9SGregory Neil Shapiro 			}
171006f25ae9SGregory Neil Shapiro 			else
171106f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
171206f25ae9SGregory Neil Shapiro 			{
1713c2aa98e2SPeter Wemm 				if (port == 0)
1714c2aa98e2SPeter Wemm 					message("Connecting to %s via %s...",
1715c2aa98e2SPeter Wemm 						hostbuf, m->m_name);
1716c2aa98e2SPeter Wemm 				else
1717c2aa98e2SPeter Wemm 					message("Connecting to %s port %d via %s...",
171806f25ae9SGregory Neil Shapiro 						hostbuf, ntohs(port),
171906f25ae9SGregory Neil Shapiro 						m->m_name);
1720c2aa98e2SPeter Wemm 				i = makeconnection(hostbuf, port, mci, e);
172106f25ae9SGregory Neil Shapiro 			}
1722c2aa98e2SPeter Wemm 			mci->mci_lastuse = curtime();
172306f25ae9SGregory Neil Shapiro 			mci->mci_deliveries = 0;
1724c2aa98e2SPeter Wemm 			mci->mci_exitstat = i;
1725c2aa98e2SPeter Wemm 			mci->mci_errno = errno;
1726c2aa98e2SPeter Wemm # if NAMED_BIND
1727c2aa98e2SPeter Wemm 			mci->mci_herrno = h_errno;
172806f25ae9SGregory Neil Shapiro # endif /* NAMED_BIND */
1729c2aa98e2SPeter Wemm 			if (i == EX_OK)
1730c2aa98e2SPeter Wemm 			{
1731c2aa98e2SPeter Wemm 				goodmxfound = TRUE;
1732c2aa98e2SPeter Wemm 				mci->mci_state = MCIS_OPENING;
1733c2aa98e2SPeter Wemm 				mci_cache(mci);
1734c2aa98e2SPeter Wemm 				if (TrafficLogFile != NULL)
1735c2aa98e2SPeter Wemm 					fprintf(TrafficLogFile, "%05d === CONNECT %s\n",
1736c2aa98e2SPeter Wemm 						(int) getpid(), hostbuf);
1737c2aa98e2SPeter Wemm 				break;
1738c2aa98e2SPeter Wemm 			}
1739c2aa98e2SPeter Wemm 			else
1740c2aa98e2SPeter Wemm 			{
1741c2aa98e2SPeter Wemm 				if (tTd(11, 1))
174206f25ae9SGregory Neil Shapiro 					dprintf("openmailer: makeconnection => stat=%d, errno=%d\n",
1743c2aa98e2SPeter Wemm 						i, errno);
1744c2aa98e2SPeter Wemm 				if (i == EX_TEMPFAIL)
1745c2aa98e2SPeter Wemm 					goodmxfound = TRUE;
1746c2aa98e2SPeter Wemm 				mci_unlock_host(mci);
1747c2aa98e2SPeter Wemm 			}
1748c2aa98e2SPeter Wemm 
1749c2aa98e2SPeter Wemm 			/* enter status of this host */
1750c2aa98e2SPeter Wemm 			setstat(i);
1751c2aa98e2SPeter Wemm 
1752c2aa98e2SPeter Wemm 			/* should print some message here for -v mode */
1753c2aa98e2SPeter Wemm 		}
1754c2aa98e2SPeter Wemm 		if (mci == NULL)
1755c2aa98e2SPeter Wemm 		{
1756c2aa98e2SPeter Wemm 			syserr("deliver: no host name");
1757c2aa98e2SPeter Wemm 			rcode = EX_SOFTWARE;
1758c2aa98e2SPeter Wemm 			goto give_up;
1759c2aa98e2SPeter Wemm 		}
1760c2aa98e2SPeter Wemm 		mci->mci_pid = 0;
176106f25ae9SGregory Neil Shapiro #else /* DAEMON */
176206f25ae9SGregory Neil Shapiro 		syserr("554 5.3.5 openmailer: no IPC");
1763c2aa98e2SPeter Wemm 		if (tTd(11, 1))
176406f25ae9SGregory Neil Shapiro 			dprintf("openmailer: NULL\n");
1765c2aa98e2SPeter Wemm 		rcode = EX_UNAVAILABLE;
1766c2aa98e2SPeter Wemm 		goto give_up;
1767c2aa98e2SPeter Wemm #endif /* DAEMON */
1768c2aa98e2SPeter Wemm 	}
1769c2aa98e2SPeter Wemm 	else
1770c2aa98e2SPeter Wemm 	{
1771c2aa98e2SPeter Wemm 		/* flush any expired connections */
1772c2aa98e2SPeter Wemm 		(void) mci_scan(NULL);
1773c2aa98e2SPeter Wemm 		mci = NULL;
1774c2aa98e2SPeter Wemm 
1775c2aa98e2SPeter Wemm #if SMTP
1776c2aa98e2SPeter Wemm 		if (bitnset(M_LMTP, m->m_flags))
1777c2aa98e2SPeter Wemm 		{
1778c2aa98e2SPeter Wemm 			/* try to get a cached connection */
1779c2aa98e2SPeter Wemm 			mci = mci_get(m->m_name, m);
1780c2aa98e2SPeter Wemm 			if (mci->mci_host == NULL)
1781c2aa98e2SPeter Wemm 				mci->mci_host = m->m_name;
1782c2aa98e2SPeter Wemm 			CurHostName = mci->mci_host;
1783c2aa98e2SPeter Wemm 			if (mci->mci_state != MCIS_CLOSED)
1784c2aa98e2SPeter Wemm 			{
1785c2aa98e2SPeter Wemm 				message("Using cached LMTP connection for %s...",
1786c2aa98e2SPeter Wemm 					m->m_name);
178706f25ae9SGregory Neil Shapiro 				mci->mci_deliveries++;
1788c2aa98e2SPeter Wemm 				goto do_transfer;
1789c2aa98e2SPeter Wemm 			}
1790c2aa98e2SPeter Wemm 		}
179106f25ae9SGregory Neil Shapiro #endif /* SMTP */
1792c2aa98e2SPeter Wemm 
1793c2aa98e2SPeter Wemm 		/* announce the connection to verbose listeners */
1794c2aa98e2SPeter Wemm 		if (host == NULL || host[0] == '\0')
1795c2aa98e2SPeter Wemm 			message("Connecting to %s...", m->m_name);
1796c2aa98e2SPeter Wemm 		else
1797c2aa98e2SPeter Wemm 			message("Connecting to %s via %s...", host, m->m_name);
1798c2aa98e2SPeter Wemm 		if (TrafficLogFile != NULL)
1799c2aa98e2SPeter Wemm 		{
1800c2aa98e2SPeter Wemm 			char **av;
1801c2aa98e2SPeter Wemm 
1802c2aa98e2SPeter Wemm 			fprintf(TrafficLogFile, "%05d === EXEC", (int) getpid());
1803c2aa98e2SPeter Wemm 			for (av = pv; *av != NULL; av++)
1804c2aa98e2SPeter Wemm 				fprintf(TrafficLogFile, " %s", *av);
1805c2aa98e2SPeter Wemm 			fprintf(TrafficLogFile, "\n");
1806c2aa98e2SPeter Wemm 		}
1807c2aa98e2SPeter Wemm 
1808c2aa98e2SPeter Wemm #if XDEBUG
1809c2aa98e2SPeter Wemm 		checkfd012("before creating mail pipe");
181006f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
1811c2aa98e2SPeter Wemm 
1812c2aa98e2SPeter Wemm 		/* create a pipe to shove the mail through */
1813c2aa98e2SPeter Wemm 		if (pipe(mpvect) < 0)
1814c2aa98e2SPeter Wemm 		{
1815c2aa98e2SPeter Wemm 			syserr("%s... openmailer(%s): pipe (to mailer)",
1816c2aa98e2SPeter Wemm 				shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
1817c2aa98e2SPeter Wemm 			if (tTd(11, 1))
181806f25ae9SGregory Neil Shapiro 				dprintf("openmailer: NULL\n");
1819c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
1820c2aa98e2SPeter Wemm 			goto give_up;
1821c2aa98e2SPeter Wemm 		}
1822c2aa98e2SPeter Wemm 
1823c2aa98e2SPeter Wemm #if XDEBUG
1824c2aa98e2SPeter Wemm 		/* make sure we didn't get one of the standard I/O files */
1825c2aa98e2SPeter Wemm 		if (mpvect[0] < 3 || mpvect[1] < 3)
1826c2aa98e2SPeter Wemm 		{
1827c2aa98e2SPeter Wemm 			syserr("%s... openmailer(%s): bogus mpvect %d %d",
1828c2aa98e2SPeter Wemm 				shortenstring(e->e_to, MAXSHORTSTR), m->m_name,
1829c2aa98e2SPeter Wemm 				mpvect[0], mpvect[1]);
1830c2aa98e2SPeter Wemm 			printopenfds(TRUE);
1831c2aa98e2SPeter Wemm 			if (tTd(11, 1))
183206f25ae9SGregory Neil Shapiro 				dprintf("openmailer: NULL\n");
1833c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
1834c2aa98e2SPeter Wemm 			goto give_up;
1835c2aa98e2SPeter Wemm 		}
1836c2aa98e2SPeter Wemm 
1837c2aa98e2SPeter Wemm 		/* make sure system call isn't dead meat */
1838c2aa98e2SPeter Wemm 		checkfdopen(mpvect[0], "mpvect[0]");
1839c2aa98e2SPeter Wemm 		checkfdopen(mpvect[1], "mpvect[1]");
1840c2aa98e2SPeter Wemm 		if (mpvect[0] == mpvect[1] ||
1841c2aa98e2SPeter Wemm 		    (e->e_lockfp != NULL &&
1842c2aa98e2SPeter Wemm 		     (mpvect[0] == fileno(e->e_lockfp) ||
1843c2aa98e2SPeter Wemm 		      mpvect[1] == fileno(e->e_lockfp))))
1844c2aa98e2SPeter Wemm 		{
1845c2aa98e2SPeter Wemm 			if (e->e_lockfp == NULL)
1846c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): overlapping mpvect %d %d",
1847c2aa98e2SPeter Wemm 					shortenstring(e->e_to, MAXSHORTSTR),
1848c2aa98e2SPeter Wemm 					m->m_name, mpvect[0], mpvect[1]);
1849c2aa98e2SPeter Wemm 			else
1850c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d",
1851c2aa98e2SPeter Wemm 					shortenstring(e->e_to, MAXSHORTSTR),
1852c2aa98e2SPeter Wemm 					m->m_name, mpvect[0], mpvect[1],
1853c2aa98e2SPeter Wemm 					fileno(e->e_lockfp));
1854c2aa98e2SPeter Wemm 		}
185506f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
1856c2aa98e2SPeter Wemm 
185706f25ae9SGregory Neil Shapiro 		/* create a return pipe */
1858c2aa98e2SPeter Wemm 		if (pipe(rpvect) < 0)
1859c2aa98e2SPeter Wemm 		{
1860c2aa98e2SPeter Wemm 			syserr("%s... openmailer(%s): pipe (from mailer)",
1861c2aa98e2SPeter Wemm 				shortenstring(e->e_to, MAXSHORTSTR),
1862c2aa98e2SPeter Wemm 				m->m_name);
1863c2aa98e2SPeter Wemm 			(void) close(mpvect[0]);
1864c2aa98e2SPeter Wemm 			(void) close(mpvect[1]);
1865c2aa98e2SPeter Wemm 			if (tTd(11, 1))
186606f25ae9SGregory Neil Shapiro 				dprintf("openmailer: NULL\n");
1867c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
1868c2aa98e2SPeter Wemm 			goto give_up;
1869c2aa98e2SPeter Wemm 		}
1870c2aa98e2SPeter Wemm #if XDEBUG
1871c2aa98e2SPeter Wemm 		checkfdopen(rpvect[0], "rpvect[0]");
1872c2aa98e2SPeter Wemm 		checkfdopen(rpvect[1], "rpvect[1]");
187306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
1874c2aa98e2SPeter Wemm 
1875c2aa98e2SPeter Wemm 		/*
1876c2aa98e2SPeter Wemm 		**  Actually fork the mailer process.
1877c2aa98e2SPeter Wemm 		**	DOFORK is clever about retrying.
1878c2aa98e2SPeter Wemm 		**
1879c2aa98e2SPeter Wemm 		**	Dispose of SIGCHLD signal catchers that may be laying
188006f25ae9SGregory Neil Shapiro 		**	around so that endmailer will get it.
1881c2aa98e2SPeter Wemm 		*/
1882c2aa98e2SPeter Wemm 
1883c2aa98e2SPeter Wemm 		if (e->e_xfp != NULL)
1884c2aa98e2SPeter Wemm 			(void) fflush(e->e_xfp);	/* for debugging */
1885c2aa98e2SPeter Wemm 		(void) fflush(stdout);
1886c2aa98e2SPeter Wemm 		(void) setsignal(SIGCHLD, SIG_DFL);
188706f25ae9SGregory Neil Shapiro 
188806f25ae9SGregory Neil Shapiro 
1889c2aa98e2SPeter Wemm 		DOFORK(FORK);
1890c2aa98e2SPeter Wemm 		/* pid is set by DOFORK */
189106f25ae9SGregory Neil Shapiro 
1892c2aa98e2SPeter Wemm 		if (pid < 0)
1893c2aa98e2SPeter Wemm 		{
1894c2aa98e2SPeter Wemm 			/* failure */
1895c2aa98e2SPeter Wemm 			syserr("%s... openmailer(%s): cannot fork",
1896c2aa98e2SPeter Wemm 				shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
1897c2aa98e2SPeter Wemm 			(void) close(mpvect[0]);
1898c2aa98e2SPeter Wemm 			(void) close(mpvect[1]);
1899c2aa98e2SPeter Wemm 			(void) close(rpvect[0]);
1900c2aa98e2SPeter Wemm 			(void) close(rpvect[1]);
1901c2aa98e2SPeter Wemm 			if (tTd(11, 1))
190206f25ae9SGregory Neil Shapiro 				dprintf("openmailer: NULL\n");
1903c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
1904c2aa98e2SPeter Wemm 			goto give_up;
1905c2aa98e2SPeter Wemm 		}
1906c2aa98e2SPeter Wemm 		else if (pid == 0)
1907c2aa98e2SPeter Wemm 		{
1908c2aa98e2SPeter Wemm 			int i;
190906f25ae9SGregory Neil Shapiro 			int save_errno;
1910c2aa98e2SPeter Wemm 			int new_euid = NO_UID;
1911c2aa98e2SPeter Wemm 			int new_ruid = NO_UID;
1912c2aa98e2SPeter Wemm 			int new_gid = NO_GID;
1913c2aa98e2SPeter Wemm 			struct stat stb;
1914c2aa98e2SPeter Wemm 			extern int DtableSize;
1915c2aa98e2SPeter Wemm 
1916c2aa98e2SPeter Wemm 			if (e->e_lockfp != NULL)
1917c2aa98e2SPeter Wemm 				(void) close(fileno(e->e_lockfp));
1918c2aa98e2SPeter Wemm 
1919c2aa98e2SPeter Wemm 			/* child -- set up input & exec mailer */
1920c2aa98e2SPeter Wemm 			(void) setsignal(SIGINT, SIG_IGN);
1921c2aa98e2SPeter Wemm 			(void) setsignal(SIGHUP, SIG_IGN);
1922c2aa98e2SPeter Wemm 			(void) setsignal(SIGTERM, SIG_DFL);
1923c2aa98e2SPeter Wemm 
1924c2aa98e2SPeter Wemm 			if (m != FileMailer || stat(tochain->q_user, &stb) < 0)
1925c2aa98e2SPeter Wemm 				stb.st_mode = 0;
1926c2aa98e2SPeter Wemm 
1927c2aa98e2SPeter Wemm # if HASSETUSERCONTEXT
1928c2aa98e2SPeter Wemm 			/*
1929c2aa98e2SPeter Wemm 			**  Set user resources.
1930c2aa98e2SPeter Wemm 			*/
1931c2aa98e2SPeter Wemm 
1932c2aa98e2SPeter Wemm 			if (contextaddr != NULL)
1933c2aa98e2SPeter Wemm 			{
1934c2aa98e2SPeter Wemm 				struct passwd *pwd;
1935c2aa98e2SPeter Wemm 
1936c2aa98e2SPeter Wemm 				if (contextaddr->q_ruser != NULL)
1937c2aa98e2SPeter Wemm 					pwd = sm_getpwnam(contextaddr->q_ruser);
1938c2aa98e2SPeter Wemm 				else
1939c2aa98e2SPeter Wemm 					pwd = sm_getpwnam(contextaddr->q_user);
1940c2aa98e2SPeter Wemm 				if (pwd != NULL)
1941c2aa98e2SPeter Wemm 					(void) setusercontext(NULL,
1942c2aa98e2SPeter Wemm 						pwd, pwd->pw_uid,
1943c2aa98e2SPeter Wemm 						LOGIN_SETRESOURCES|LOGIN_SETPRIORITY);
1944c2aa98e2SPeter Wemm 			}
194506f25ae9SGregory Neil Shapiro # endif /* HASSETUSERCONTEXT */
1946c2aa98e2SPeter Wemm 
1947c2aa98e2SPeter Wemm 			/* tweak niceness */
1948c2aa98e2SPeter Wemm 			if (m->m_nice != 0)
194906f25ae9SGregory Neil Shapiro 				(void) nice(m->m_nice);
1950c2aa98e2SPeter Wemm 
1951c2aa98e2SPeter Wemm 			/* reset group id */
1952c2aa98e2SPeter Wemm 			if (bitnset(M_SPECIFIC_UID, m->m_flags))
1953c2aa98e2SPeter Wemm 				new_gid = m->m_gid;
1954c2aa98e2SPeter Wemm 			else if (bitset(S_ISGID, stb.st_mode))
1955c2aa98e2SPeter Wemm 				new_gid = stb.st_gid;
1956c2aa98e2SPeter Wemm 			else if (ctladdr != NULL && ctladdr->q_gid != 0)
1957c2aa98e2SPeter Wemm 			{
1958c2aa98e2SPeter Wemm 				if (!DontInitGroups)
1959c2aa98e2SPeter Wemm 				{
1960c2aa98e2SPeter Wemm 					char *u = ctladdr->q_ruser;
1961c2aa98e2SPeter Wemm 
1962c2aa98e2SPeter Wemm 					if (u == NULL)
1963c2aa98e2SPeter Wemm 						u = ctladdr->q_user;
1964c2aa98e2SPeter Wemm 
1965c2aa98e2SPeter Wemm 					if (initgroups(u, ctladdr->q_gid) == -1 && suidwarn)
196606f25ae9SGregory Neil Shapiro 					{
1967c2aa98e2SPeter Wemm 						syserr("openmailer: initgroups(%s, %d) failed",
1968c2aa98e2SPeter Wemm 							u, ctladdr->q_gid);
196906f25ae9SGregory Neil Shapiro 						exit(EX_TEMPFAIL);
197006f25ae9SGregory Neil Shapiro 					}
1971c2aa98e2SPeter Wemm 				}
1972c2aa98e2SPeter Wemm 				else
1973c2aa98e2SPeter Wemm 				{
1974c2aa98e2SPeter Wemm 					GIDSET_T gidset[1];
1975c2aa98e2SPeter Wemm 
1976c2aa98e2SPeter Wemm 					gidset[0] = ctladdr->q_gid;
1977c2aa98e2SPeter Wemm 					if (setgroups(1, gidset) == -1 && suidwarn)
197806f25ae9SGregory Neil Shapiro 					{
1979c2aa98e2SPeter Wemm 						syserr("openmailer: setgroups() failed");
198006f25ae9SGregory Neil Shapiro 						exit(EX_TEMPFAIL);
198106f25ae9SGregory Neil Shapiro 					}
1982c2aa98e2SPeter Wemm 				}
1983c2aa98e2SPeter Wemm 				new_gid = ctladdr->q_gid;
1984c2aa98e2SPeter Wemm 			}
1985c2aa98e2SPeter Wemm 			else
1986c2aa98e2SPeter Wemm 			{
1987c2aa98e2SPeter Wemm 				if (!DontInitGroups)
1988c2aa98e2SPeter Wemm 				{
1989c2aa98e2SPeter Wemm 					if (initgroups(DefUser, DefGid) == -1 && suidwarn)
199006f25ae9SGregory Neil Shapiro 					{
1991c2aa98e2SPeter Wemm 						syserr("openmailer: initgroups(%s, %d) failed",
1992c2aa98e2SPeter Wemm 							DefUser, DefGid);
199306f25ae9SGregory Neil Shapiro 						exit(EX_TEMPFAIL);
199406f25ae9SGregory Neil Shapiro 					}
1995c2aa98e2SPeter Wemm 				}
1996c2aa98e2SPeter Wemm 				else
1997c2aa98e2SPeter Wemm 				{
1998c2aa98e2SPeter Wemm 					GIDSET_T gidset[1];
1999c2aa98e2SPeter Wemm 
2000c2aa98e2SPeter Wemm 					gidset[0] = DefGid;
2001c2aa98e2SPeter Wemm 					if (setgroups(1, gidset) == -1 && suidwarn)
200206f25ae9SGregory Neil Shapiro 					{
2003c2aa98e2SPeter Wemm 						syserr("openmailer: setgroups() failed");
200406f25ae9SGregory Neil Shapiro 						exit(EX_TEMPFAIL);
200506f25ae9SGregory Neil Shapiro 					}
2006c2aa98e2SPeter Wemm 				}
2007c2aa98e2SPeter Wemm 				if (m->m_gid == 0)
2008c2aa98e2SPeter Wemm 					new_gid = DefGid;
2009c2aa98e2SPeter Wemm 				else
2010c2aa98e2SPeter Wemm 					new_gid = m->m_gid;
2011c2aa98e2SPeter Wemm 			}
201206f25ae9SGregory Neil Shapiro 			if (new_gid != NO_GID)
201306f25ae9SGregory Neil Shapiro 			{
201406f25ae9SGregory Neil Shapiro 				if (RunAsUid != 0 &&
201506f25ae9SGregory Neil Shapiro 				    bitnset(M_SPECIFIC_UID, m->m_flags) &&
201606f25ae9SGregory Neil Shapiro 				    new_gid != getgid() &&
201706f25ae9SGregory Neil Shapiro 				    new_gid != getegid())
201806f25ae9SGregory Neil Shapiro 				{
201906f25ae9SGregory Neil Shapiro 					/* Only root can change the gid */
202006f25ae9SGregory Neil Shapiro 					syserr("openmailer: insufficient privileges to change gid");
202106f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
202206f25ae9SGregory Neil Shapiro 				}
202306f25ae9SGregory Neil Shapiro 
202406f25ae9SGregory Neil Shapiro 				if (setgid(new_gid) < 0 && suidwarn)
202506f25ae9SGregory Neil Shapiro 				{
2026c2aa98e2SPeter Wemm 					syserr("openmailer: setgid(%ld) failed",
2027c2aa98e2SPeter Wemm 					       (long) new_gid);
202806f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
202906f25ae9SGregory Neil Shapiro 				}
203006f25ae9SGregory Neil Shapiro 			}
203106f25ae9SGregory Neil Shapiro 
203206f25ae9SGregory Neil Shapiro 			/* change root to some "safe" directory */
203306f25ae9SGregory Neil Shapiro 			if (m->m_rootdir != NULL)
203406f25ae9SGregory Neil Shapiro 			{
203506f25ae9SGregory Neil Shapiro 				expand(m->m_rootdir, buf, sizeof buf, e);
203606f25ae9SGregory Neil Shapiro 				if (tTd(11, 20))
203706f25ae9SGregory Neil Shapiro 					dprintf("openmailer: chroot %s\n",
203806f25ae9SGregory Neil Shapiro 						buf);
203906f25ae9SGregory Neil Shapiro 				if (chroot(buf) < 0)
204006f25ae9SGregory Neil Shapiro 				{
204106f25ae9SGregory Neil Shapiro 					syserr("openmailer: Cannot chroot(%s)",
204206f25ae9SGregory Neil Shapiro 					       buf);
204306f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
204406f25ae9SGregory Neil Shapiro 				}
204506f25ae9SGregory Neil Shapiro 				if (chdir("/") < 0)
204606f25ae9SGregory Neil Shapiro 				{
204706f25ae9SGregory Neil Shapiro 					syserr("openmailer: cannot chdir(/)");
204806f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
204906f25ae9SGregory Neil Shapiro 				}
205006f25ae9SGregory Neil Shapiro 			}
2051c2aa98e2SPeter Wemm 
2052c2aa98e2SPeter Wemm 			/* reset user id */
2053c2aa98e2SPeter Wemm 			endpwent();
2054c2aa98e2SPeter Wemm 			if (bitnset(M_SPECIFIC_UID, m->m_flags))
2055c2aa98e2SPeter Wemm 				new_euid = m->m_uid;
2056c2aa98e2SPeter Wemm 			else if (bitset(S_ISUID, stb.st_mode))
2057c2aa98e2SPeter Wemm 				new_ruid = stb.st_uid;
2058c2aa98e2SPeter Wemm 			else if (ctladdr != NULL && ctladdr->q_uid != 0)
2059c2aa98e2SPeter Wemm 				new_ruid = ctladdr->q_uid;
2060c2aa98e2SPeter Wemm 			else if (m->m_uid != 0)
2061c2aa98e2SPeter Wemm 				new_ruid = m->m_uid;
2062c2aa98e2SPeter Wemm 			else
2063c2aa98e2SPeter Wemm 				new_ruid = DefUid;
2064c2aa98e2SPeter Wemm 			if (new_euid != NO_UID)
2065c2aa98e2SPeter Wemm 			{
206606f25ae9SGregory Neil Shapiro 				if (RunAsUid != 0 && new_euid != RunAsUid)
206706f25ae9SGregory Neil Shapiro 				{
206806f25ae9SGregory Neil Shapiro 					/* Only root can change the uid */
206906f25ae9SGregory Neil Shapiro 					syserr("openmailer: insufficient privileges to change uid");
207006f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
207106f25ae9SGregory Neil Shapiro 				}
207206f25ae9SGregory Neil Shapiro 
2073c2aa98e2SPeter Wemm 				vendor_set_uid(new_euid);
207406f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID
2075c2aa98e2SPeter Wemm 				if (seteuid(new_euid) < 0 && suidwarn)
207606f25ae9SGregory Neil Shapiro 				{
2077c2aa98e2SPeter Wemm 					syserr("openmailer: seteuid(%ld) failed",
2078c2aa98e2SPeter Wemm 						(long) new_euid);
207906f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
208006f25ae9SGregory Neil Shapiro 				}
208106f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */
208206f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID
2083c2aa98e2SPeter Wemm 				if (setreuid(new_ruid, new_euid) < 0 && suidwarn)
208406f25ae9SGregory Neil Shapiro 				{
2085c2aa98e2SPeter Wemm 					syserr("openmailer: setreuid(%ld, %ld) failed",
2086c2aa98e2SPeter Wemm 						(long) new_ruid, (long) new_euid);
208706f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
208806f25ae9SGregory Neil Shapiro 				}
208906f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */
209006f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETUID
2091c2aa98e2SPeter Wemm 				if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn)
209206f25ae9SGregory Neil Shapiro 				{
2093c2aa98e2SPeter Wemm 					syserr("openmailer: setuid(%ld) failed",
2094c2aa98e2SPeter Wemm 						(long) new_euid);
209506f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
209606f25ae9SGregory Neil Shapiro 				}
209706f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETUID */
2098c2aa98e2SPeter Wemm 			}
2099c2aa98e2SPeter Wemm 			else if (new_ruid != NO_UID)
2100c2aa98e2SPeter Wemm 			{
2101c2aa98e2SPeter Wemm 				vendor_set_uid(new_ruid);
2102c2aa98e2SPeter Wemm 				if (setuid(new_ruid) < 0 && suidwarn)
210306f25ae9SGregory Neil Shapiro 				{
2104c2aa98e2SPeter Wemm 					syserr("openmailer: setuid(%ld) failed",
2105c2aa98e2SPeter Wemm 						(long) new_ruid);
210606f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
210706f25ae9SGregory Neil Shapiro 				}
2108c2aa98e2SPeter Wemm 			}
2109c2aa98e2SPeter Wemm 
2110c2aa98e2SPeter Wemm 			if (tTd(11, 2))
211106f25ae9SGregory Neil Shapiro 				dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n",
211206f25ae9SGregory Neil Shapiro 					(int) getuid(), (int) geteuid(),
211306f25ae9SGregory Neil Shapiro 					(int) getgid(), (int) getegid());
2114c2aa98e2SPeter Wemm 
2115c2aa98e2SPeter Wemm 			/* move into some "safe" directory */
2116c2aa98e2SPeter Wemm 			if (m->m_execdir != NULL)
2117c2aa98e2SPeter Wemm 			{
2118c2aa98e2SPeter Wemm 				char *q;
2119c2aa98e2SPeter Wemm 
2120c2aa98e2SPeter Wemm 				for (p = m->m_execdir; p != NULL; p = q)
2121c2aa98e2SPeter Wemm 				{
2122c2aa98e2SPeter Wemm 					q = strchr(p, ':');
2123c2aa98e2SPeter Wemm 					if (q != NULL)
2124c2aa98e2SPeter Wemm 						*q = '\0';
2125c2aa98e2SPeter Wemm 					expand(p, buf, sizeof buf, e);
2126c2aa98e2SPeter Wemm 					if (q != NULL)
2127c2aa98e2SPeter Wemm 						*q++ = ':';
2128c2aa98e2SPeter Wemm 					if (tTd(11, 20))
212906f25ae9SGregory Neil Shapiro 						dprintf("openmailer: trydir %s\n",
2130c2aa98e2SPeter Wemm 							buf);
2131c2aa98e2SPeter Wemm 					if (buf[0] != '\0' && chdir(buf) >= 0)
2132c2aa98e2SPeter Wemm 						break;
2133c2aa98e2SPeter Wemm 				}
2134c2aa98e2SPeter Wemm 			}
2135c2aa98e2SPeter Wemm 
2136c2aa98e2SPeter Wemm 			/* arrange to filter std & diag output of command */
2137c2aa98e2SPeter Wemm 			(void) close(rpvect[0]);
2138c2aa98e2SPeter Wemm 			if (dup2(rpvect[1], STDOUT_FILENO) < 0)
2139c2aa98e2SPeter Wemm 			{
2140c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): cannot dup pipe %d for stdout",
2141c2aa98e2SPeter Wemm 				       shortenstring(e->e_to, MAXSHORTSTR),
2142c2aa98e2SPeter Wemm 				       m->m_name, rpvect[1]);
2143c2aa98e2SPeter Wemm 				_exit(EX_OSERR);
2144c2aa98e2SPeter Wemm 			}
2145c2aa98e2SPeter Wemm 			(void) close(rpvect[1]);
214606f25ae9SGregory Neil Shapiro 
2147c2aa98e2SPeter Wemm 			if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
2148c2aa98e2SPeter Wemm 			{
2149c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): cannot dup stdout for stderr",
2150c2aa98e2SPeter Wemm 					shortenstring(e->e_to, MAXSHORTSTR),
2151c2aa98e2SPeter Wemm 					m->m_name);
2152c2aa98e2SPeter Wemm 				_exit(EX_OSERR);
2153c2aa98e2SPeter Wemm 			}
2154c2aa98e2SPeter Wemm 
2155c2aa98e2SPeter Wemm 			/* arrange to get standard input */
2156c2aa98e2SPeter Wemm 			(void) close(mpvect[1]);
2157c2aa98e2SPeter Wemm 			if (dup2(mpvect[0], STDIN_FILENO) < 0)
2158c2aa98e2SPeter Wemm 			{
2159c2aa98e2SPeter Wemm 				syserr("%s... openmailer(%s): cannot dup pipe %d for stdin",
2160c2aa98e2SPeter Wemm 					shortenstring(e->e_to, MAXSHORTSTR),
2161c2aa98e2SPeter Wemm 					m->m_name, mpvect[0]);
2162c2aa98e2SPeter Wemm 				_exit(EX_OSERR);
2163c2aa98e2SPeter Wemm 			}
2164c2aa98e2SPeter Wemm 			(void) close(mpvect[0]);
2165c2aa98e2SPeter Wemm 
2166c2aa98e2SPeter Wemm 			/* arrange for all the files to be closed */
2167c2aa98e2SPeter Wemm 			for (i = 3; i < DtableSize; i++)
2168c2aa98e2SPeter Wemm 			{
2169c2aa98e2SPeter Wemm 				register int j;
2170c2aa98e2SPeter Wemm 
2171c2aa98e2SPeter Wemm 				if ((j = fcntl(i, F_GETFD, 0)) != -1)
217206f25ae9SGregory Neil Shapiro 					(void) fcntl(i, F_SETFD,
217306f25ae9SGregory Neil Shapiro 						     j | FD_CLOEXEC);
2174c2aa98e2SPeter Wemm 			}
2175c2aa98e2SPeter Wemm 
2176c2aa98e2SPeter Wemm 			/* run disconnected from terminal */
2177c2aa98e2SPeter Wemm 			(void) setsid();
2178c2aa98e2SPeter Wemm 
2179c2aa98e2SPeter Wemm 			/* try to execute the mailer */
218006f25ae9SGregory Neil Shapiro 			(void) execve(m->m_mailer, (ARGV_T) pv,
218106f25ae9SGregory Neil Shapiro 				      (ARGV_T) UserEnviron);
218206f25ae9SGregory Neil Shapiro 			save_errno = errno;
2183c2aa98e2SPeter Wemm 			syserr("Cannot exec %s", m->m_mailer);
2184c2aa98e2SPeter Wemm 			if (bitnset(M_LOCALMAILER, m->m_flags) ||
218506f25ae9SGregory Neil Shapiro 			    transienterror(save_errno))
2186c2aa98e2SPeter Wemm 				_exit(EX_OSERR);
2187c2aa98e2SPeter Wemm 			_exit(EX_UNAVAILABLE);
2188c2aa98e2SPeter Wemm 		}
2189c2aa98e2SPeter Wemm 
2190c2aa98e2SPeter Wemm 		/*
2191c2aa98e2SPeter Wemm 		**  Set up return value.
2192c2aa98e2SPeter Wemm 		*/
2193c2aa98e2SPeter Wemm 
2194c2aa98e2SPeter Wemm 		if (mci == NULL)
2195c2aa98e2SPeter Wemm 		{
2196c2aa98e2SPeter Wemm 			mci = (MCI *) xalloc(sizeof *mci);
219706f25ae9SGregory Neil Shapiro 			memset((char *) mci, '\0', sizeof *mci);
2198c2aa98e2SPeter Wemm 		}
2199c2aa98e2SPeter Wemm 		mci->mci_mailer = m;
2200c2aa98e2SPeter Wemm 		if (clever)
2201c2aa98e2SPeter Wemm 		{
2202c2aa98e2SPeter Wemm 			mci->mci_state = MCIS_OPENING;
2203c2aa98e2SPeter Wemm 			mci_cache(mci);
2204c2aa98e2SPeter Wemm 		}
2205c2aa98e2SPeter Wemm 		else
2206c2aa98e2SPeter Wemm 		{
2207c2aa98e2SPeter Wemm 			mci->mci_state = MCIS_OPEN;
2208c2aa98e2SPeter Wemm 		}
2209c2aa98e2SPeter Wemm 		mci->mci_pid = pid;
2210c2aa98e2SPeter Wemm 		(void) close(mpvect[0]);
2211c2aa98e2SPeter Wemm 		mci->mci_out = fdopen(mpvect[1], "w");
2212c2aa98e2SPeter Wemm 		if (mci->mci_out == NULL)
2213c2aa98e2SPeter Wemm 		{
2214c2aa98e2SPeter Wemm 			syserr("deliver: cannot create mailer output channel, fd=%d",
2215c2aa98e2SPeter Wemm 				mpvect[1]);
2216c2aa98e2SPeter Wemm 			(void) close(mpvect[1]);
2217c2aa98e2SPeter Wemm 			(void) close(rpvect[0]);
2218c2aa98e2SPeter Wemm 			(void) close(rpvect[1]);
2219c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
2220c2aa98e2SPeter Wemm 			goto give_up;
2221c2aa98e2SPeter Wemm 		}
222206f25ae9SGregory Neil Shapiro 
2223c2aa98e2SPeter Wemm 		(void) close(rpvect[1]);
2224c2aa98e2SPeter Wemm 		mci->mci_in = fdopen(rpvect[0], "r");
2225c2aa98e2SPeter Wemm 		if (mci->mci_in == NULL)
2226c2aa98e2SPeter Wemm 		{
2227c2aa98e2SPeter Wemm 			syserr("deliver: cannot create mailer input channel, fd=%d",
2228c2aa98e2SPeter Wemm 			       mpvect[1]);
2229c2aa98e2SPeter Wemm 			(void) close(rpvect[0]);
223006f25ae9SGregory Neil Shapiro 			(void) fclose(mci->mci_out);
2231c2aa98e2SPeter Wemm 			mci->mci_out = NULL;
2232c2aa98e2SPeter Wemm 			rcode = EX_OSERR;
2233c2aa98e2SPeter Wemm 			goto give_up;
2234c2aa98e2SPeter Wemm 		}
223506f25ae9SGregory Neil Shapiro 
223606f25ae9SGregory Neil Shapiro 		/* Don't cache non-clever connections */
223706f25ae9SGregory Neil Shapiro 		if (!clever)
2238c2aa98e2SPeter Wemm 			mci->mci_flags |= MCIF_TEMP;
2239c2aa98e2SPeter Wemm 	}
2240c2aa98e2SPeter Wemm 
2241c2aa98e2SPeter Wemm 	/*
2242c2aa98e2SPeter Wemm 	**  If we are in SMTP opening state, send initial protocol.
2243c2aa98e2SPeter Wemm 	*/
2244c2aa98e2SPeter Wemm 
2245c2aa98e2SPeter Wemm 	if (bitnset(M_7BITS, m->m_flags) &&
2246c2aa98e2SPeter Wemm 	    (!clever || mci->mci_state == MCIS_OPENING))
2247c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_7BIT;
2248c2aa98e2SPeter Wemm #if SMTP
2249c2aa98e2SPeter Wemm 	if (clever && mci->mci_state != MCIS_CLOSED)
2250c2aa98e2SPeter Wemm 	{
225106f25ae9SGregory Neil Shapiro # if SASL && SFIO
2252193538b7SGregory Neil Shapiro #  define DONE_AUTH(f)		bitset(MCIF_AUTHACT, f)
225306f25ae9SGregory Neil Shapiro # endif /* SASL && SFIO */
225406f25ae9SGregory Neil Shapiro # if STARTTLS
2255193538b7SGregory Neil Shapiro #  define DONE_STARTTLS(f)	bitset(MCIF_TLSACT, f)
225606f25ae9SGregory Neil Shapiro # endif /* STARTTLS */
2257193538b7SGregory Neil Shapiro # define ONLY_HELO(f)		bitset(MCIF_ONLY_EHLO, f)
2258193538b7SGregory Neil Shapiro # define SET_HELO(f)		f |= MCIF_ONLY_EHLO
2259193538b7SGregory Neil Shapiro # define CLR_HELO(f)		f &= ~MCIF_ONLY_EHLO
2260c2aa98e2SPeter Wemm 
2261193538b7SGregory Neil Shapiro 
226206f25ae9SGregory Neil Shapiro # if STARTTLS || (SASL && SFIO)
226306f25ae9SGregory Neil Shapiro reconnect:	/* after switching to an authenticated connection */
226406f25ae9SGregory Neil Shapiro # endif /* STARTTLS || (SASL && SFIO) */
226506f25ae9SGregory Neil Shapiro 
226606f25ae9SGregory Neil Shapiro # if SASL
226706f25ae9SGregory Neil Shapiro 		mci->mci_saslcap = NULL;
226806f25ae9SGregory Neil Shapiro # endif /* SASL */
2269193538b7SGregory Neil Shapiro 		smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags));
2270193538b7SGregory Neil Shapiro 		CLR_HELO(mci->mci_flags);
227106f25ae9SGregory Neil Shapiro 
227206f25ae9SGregory Neil Shapiro # if STARTTLS
227306f25ae9SGregory Neil Shapiro 		/* first TLS then AUTH to provide a security layer */
2274193538b7SGregory Neil Shapiro 		if (mci->mci_state != MCIS_CLOSED &&
2275193538b7SGregory Neil Shapiro 		    !DONE_STARTTLS(mci->mci_flags))
227606f25ae9SGregory Neil Shapiro 		{
227706f25ae9SGregory Neil Shapiro 			int olderrors;
2278602a2b1bSGregory Neil Shapiro 			int dotpos;
227906f25ae9SGregory Neil Shapiro 			bool usetls;
228006f25ae9SGregory Neil Shapiro 			bool saveQuickAbort = QuickAbort;
228106f25ae9SGregory Neil Shapiro 			bool saveSuprErrs = SuprErrs;
2282193538b7SGregory Neil Shapiro 			char *host = NULL;
228342e5d165SGregory Neil Shapiro #  if _FFR_TLS_CLT1
228442e5d165SGregory Neil Shapiro 			char *p;
228542e5d165SGregory Neil Shapiro #  endif /* _FFR_TLS_CLT1 */
2286602a2b1bSGregory Neil Shapiro 			char *srvname;
228706f25ae9SGregory Neil Shapiro 			extern SOCKADDR CurHostAddr;
228806f25ae9SGregory Neil Shapiro 
228906f25ae9SGregory Neil Shapiro 			rcode = EX_OK;
229006f25ae9SGregory Neil Shapiro 			usetls = bitset(MCIF_TLS, mci->mci_flags);
229142e5d165SGregory Neil Shapiro #  if _FFR_TLS_CLT1
229242e5d165SGregory Neil Shapiro 			if (usetls &&
229342e5d165SGregory Neil Shapiro 			    (p = macvalue(macid("{client_flags}", NULL), e))
229442e5d165SGregory Neil Shapiro 			    != NULL)
229542e5d165SGregory Neil Shapiro 			{
229642e5d165SGregory Neil Shapiro 				for (; *p != '\0'; p++)
229742e5d165SGregory Neil Shapiro 				{
229842e5d165SGregory Neil Shapiro 					/* look for just this one flag */
229942e5d165SGregory Neil Shapiro 					if (*p == D_CLTNOTLS)
230042e5d165SGregory Neil Shapiro 					{
230142e5d165SGregory Neil Shapiro 						usetls = FALSE;
230242e5d165SGregory Neil Shapiro 						break;
230342e5d165SGregory Neil Shapiro 					}
230442e5d165SGregory Neil Shapiro 				}
230542e5d165SGregory Neil Shapiro 			}
230642e5d165SGregory Neil Shapiro #  endif /* _FFR_TLS_CLT1 */
230742e5d165SGregory Neil Shapiro 
2308602a2b1bSGregory Neil Shapiro 			if (mci->mci_host != NULL)
2309602a2b1bSGregory Neil Shapiro 			{
2310602a2b1bSGregory Neil Shapiro 				srvname = mci->mci_host;
2311602a2b1bSGregory Neil Shapiro 				dotpos = strlen(srvname) - 1;
2312602a2b1bSGregory Neil Shapiro 				if (dotpos >= 0)
2313602a2b1bSGregory Neil Shapiro 				{
2314602a2b1bSGregory Neil Shapiro 					if (srvname[dotpos] == '.')
2315602a2b1bSGregory Neil Shapiro 						srvname[dotpos] = '\0';
2316602a2b1bSGregory Neil Shapiro 					else
2317602a2b1bSGregory Neil Shapiro 						dotpos = -1;
2318602a2b1bSGregory Neil Shapiro 				}
2319602a2b1bSGregory Neil Shapiro 			}
2320602a2b1bSGregory Neil Shapiro 			else
2321602a2b1bSGregory Neil Shapiro 			{
2322602a2b1bSGregory Neil Shapiro 				srvname = "";
2323602a2b1bSGregory Neil Shapiro 				dotpos = -1;
2324602a2b1bSGregory Neil Shapiro 			}
232506f25ae9SGregory Neil Shapiro 			define(macid("{server_name}", NULL),
2326602a2b1bSGregory Neil Shapiro 			       newstr(srvname), e);
232706f25ae9SGregory Neil Shapiro 			if (CurHostAddr.sa.sa_family != 0)
232806f25ae9SGregory Neil Shapiro 				define(macid("{server_addr}", NULL),
232906f25ae9SGregory Neil Shapiro 				       newstr(anynet_ntoa(&CurHostAddr)), e);
233006f25ae9SGregory Neil Shapiro 			else
233106f25ae9SGregory Neil Shapiro 				define(macid("{server_addr}", NULL), NULL, e);
233206f25ae9SGregory Neil Shapiro 			if (usetls)
233306f25ae9SGregory Neil Shapiro 			{
2334193538b7SGregory Neil Shapiro 				host = macvalue(macid("{server_name}", NULL),
2335193538b7SGregory Neil Shapiro 						e);
2336193538b7SGregory Neil Shapiro #  if _FFR_TLS_O_T
233706f25ae9SGregory Neil Shapiro 				olderrors = Errors;
233806f25ae9SGregory Neil Shapiro 				QuickAbort = FALSE;
233906f25ae9SGregory Neil Shapiro 				SuprErrs = TRUE;
2340602a2b1bSGregory Neil Shapiro 				if (rscheck("try_tls", srvname, NULL,
2341193538b7SGregory Neil Shapiro 					    e, TRUE, FALSE, 8, host) != EX_OK
234206f25ae9SGregory Neil Shapiro 				    || Errors > olderrors)
234306f25ae9SGregory Neil Shapiro 					usetls = FALSE;
234406f25ae9SGregory Neil Shapiro 				SuprErrs = saveSuprErrs;
234506f25ae9SGregory Neil Shapiro 				QuickAbort = saveQuickAbort;
234606f25ae9SGregory Neil Shapiro #  endif /* _FFR_TLS_O_T */
2347193538b7SGregory Neil Shapiro 			}
234806f25ae9SGregory Neil Shapiro 
2349602a2b1bSGregory Neil Shapiro 			/* undo change of srvname */
2350602a2b1bSGregory Neil Shapiro 			if (dotpos >= 0)
2351602a2b1bSGregory Neil Shapiro 				srvname[dotpos] = '.';
235206f25ae9SGregory Neil Shapiro 			if (usetls)
235306f25ae9SGregory Neil Shapiro 			{
235406f25ae9SGregory Neil Shapiro 				if ((rcode = starttls(m, mci, e)) == EX_OK)
235506f25ae9SGregory Neil Shapiro 				{
235606f25ae9SGregory Neil Shapiro 					/* start again without STARTTLS */
235706f25ae9SGregory Neil Shapiro 					mci->mci_flags |= MCIF_TLSACT;
235806f25ae9SGregory Neil Shapiro 				}
235906f25ae9SGregory Neil Shapiro 				else
236006f25ae9SGregory Neil Shapiro 				{
236106f25ae9SGregory Neil Shapiro 					char *s;
236206f25ae9SGregory Neil Shapiro 
236306f25ae9SGregory Neil Shapiro 					/*
236406f25ae9SGregory Neil Shapiro 					**  TLS negotation failed, what to do?
236506f25ae9SGregory Neil Shapiro 					**  fall back to unencrypted connection
236606f25ae9SGregory Neil Shapiro 					**  or abort? How to decide?
236706f25ae9SGregory Neil Shapiro 					**  set a macro and call a ruleset.
236806f25ae9SGregory Neil Shapiro 					*/
236906f25ae9SGregory Neil Shapiro 					mci->mci_flags &= ~MCIF_TLS;
237006f25ae9SGregory Neil Shapiro 					switch (rcode)
237106f25ae9SGregory Neil Shapiro 					{
237206f25ae9SGregory Neil Shapiro 					  case EX_TEMPFAIL:
237306f25ae9SGregory Neil Shapiro 						s = "TEMP";
237406f25ae9SGregory Neil Shapiro 						break;
237506f25ae9SGregory Neil Shapiro 					  case EX_USAGE:
237606f25ae9SGregory Neil Shapiro 						s = "USAGE";
237706f25ae9SGregory Neil Shapiro 						break;
237806f25ae9SGregory Neil Shapiro 					  case EX_PROTOCOL:
237906f25ae9SGregory Neil Shapiro 						s = "PROTOCOL";
238006f25ae9SGregory Neil Shapiro 						break;
238106f25ae9SGregory Neil Shapiro 					  case EX_SOFTWARE:
238206f25ae9SGregory Neil Shapiro 						s = "SOFTWARE";
238306f25ae9SGregory Neil Shapiro 						break;
238406f25ae9SGregory Neil Shapiro 
238506f25ae9SGregory Neil Shapiro 					  /* everything else is a failure */
238606f25ae9SGregory Neil Shapiro 					  default:
238706f25ae9SGregory Neil Shapiro 						s = "FAILURE";
238806f25ae9SGregory Neil Shapiro 						rcode = EX_TEMPFAIL;
238906f25ae9SGregory Neil Shapiro 					}
239006f25ae9SGregory Neil Shapiro 					define(macid("{verify}", NULL),
239106f25ae9SGregory Neil Shapiro 					       newstr(s), e);
239206f25ae9SGregory Neil Shapiro 				}
239306f25ae9SGregory Neil Shapiro 			}
2394193538b7SGregory Neil Shapiro 			else if (mci->mci_ssl != NULL)
2395193538b7SGregory Neil Shapiro 			{
2396193538b7SGregory Neil Shapiro 				/* active TLS connection, use that data */
2397193538b7SGregory Neil Shapiro 				(void) tls_get_info(mci->mci_ssl, e, FALSE,
2398193538b7SGregory Neil Shapiro 						    mci->mci_host, FALSE);
2399193538b7SGregory Neil Shapiro 			}
240006f25ae9SGregory Neil Shapiro 			else
240106f25ae9SGregory Neil Shapiro 				define(macid("{verify}", NULL), "NONE", e);
240206f25ae9SGregory Neil Shapiro 			olderrors = Errors;
240306f25ae9SGregory Neil Shapiro 			QuickAbort = FALSE;
240406f25ae9SGregory Neil Shapiro 			SuprErrs = TRUE;
240506f25ae9SGregory Neil Shapiro 
240606f25ae9SGregory Neil Shapiro 			/*
240706f25ae9SGregory Neil Shapiro 			**  rcode == EX_SOFTWARE is special:
240806f25ae9SGregory Neil Shapiro 			**  the TLS negotation failed
240906f25ae9SGregory Neil Shapiro 			**  we have to drop the connection no matter what
241006f25ae9SGregory Neil Shapiro 			**  However, we call tls_server to give it the chance
241106f25ae9SGregory Neil Shapiro 			**  to log the problem and return an appropriate
241206f25ae9SGregory Neil Shapiro 			**  error code.
241306f25ae9SGregory Neil Shapiro 			*/
241406f25ae9SGregory Neil Shapiro 			if (rscheck("tls_server",
241506f25ae9SGregory Neil Shapiro 				     macvalue(macid("{verify}", NULL), e),
2416193538b7SGregory Neil Shapiro 				     NULL, e, TRUE, TRUE, 6, host) != EX_OK ||
241706f25ae9SGregory Neil Shapiro 			    Errors > olderrors ||
241806f25ae9SGregory Neil Shapiro 			    rcode == EX_SOFTWARE)
241906f25ae9SGregory Neil Shapiro 			{
242006f25ae9SGregory Neil Shapiro 				char enhsc[ENHSCLEN];
242106f25ae9SGregory Neil Shapiro 				extern char MsgBuf[];
242206f25ae9SGregory Neil Shapiro 
242306f25ae9SGregory Neil Shapiro 				if (ISSMTPCODE(MsgBuf) &&
242406f25ae9SGregory Neil Shapiro 				    extenhsc(MsgBuf + 4, ' ', enhsc) > 0)
242506f25ae9SGregory Neil Shapiro 				{
242606f25ae9SGregory Neil Shapiro 					p = newstr(MsgBuf);
242706f25ae9SGregory Neil Shapiro 				}
242806f25ae9SGregory Neil Shapiro 				else
242906f25ae9SGregory Neil Shapiro 				{
243006f25ae9SGregory Neil Shapiro 					p = "403 4.7.0 server not authenticated.";
243106f25ae9SGregory Neil Shapiro 					(void) strlcpy(enhsc, "4.7.0",
243206f25ae9SGregory Neil Shapiro 						       sizeof enhsc);
243306f25ae9SGregory Neil Shapiro 				}
243406f25ae9SGregory Neil Shapiro 				SuprErrs = saveSuprErrs;
243506f25ae9SGregory Neil Shapiro 				QuickAbort = saveQuickAbort;
243606f25ae9SGregory Neil Shapiro 
243706f25ae9SGregory Neil Shapiro 				if (rcode == EX_SOFTWARE)
243806f25ae9SGregory Neil Shapiro 				{
243906f25ae9SGregory Neil Shapiro 					/* drop the connection */
244006f25ae9SGregory Neil Shapiro 					mci->mci_state = MCIS_QUITING;
244106f25ae9SGregory Neil Shapiro 					if (mci->mci_in != NULL)
244206f25ae9SGregory Neil Shapiro 					{
244306f25ae9SGregory Neil Shapiro 						(void) fclose(mci->mci_in);
244406f25ae9SGregory Neil Shapiro 						mci->mci_in = NULL;
244506f25ae9SGregory Neil Shapiro 					}
244606f25ae9SGregory Neil Shapiro 					mci->mci_flags &= ~MCIF_TLSACT;
244706f25ae9SGregory Neil Shapiro 					(void) endmailer(mci, e, pv);
244806f25ae9SGregory Neil Shapiro 				}
244906f25ae9SGregory Neil Shapiro 				else
245006f25ae9SGregory Neil Shapiro 				{
245106f25ae9SGregory Neil Shapiro 					/* abort transfer */
245206f25ae9SGregory Neil Shapiro 					smtpquit(m, mci, e);
245306f25ae9SGregory Neil Shapiro 				}
245406f25ae9SGregory Neil Shapiro 
2455193538b7SGregory Neil Shapiro 				/* avoid bogus error msg */
2456193538b7SGregory Neil Shapiro 				mci->mci_errno = 0;
2457193538b7SGregory Neil Shapiro 
245806f25ae9SGregory Neil Shapiro 				/* temp or permanent failure? */
245906f25ae9SGregory Neil Shapiro 				rcode = (*p == '4') ? EX_TEMPFAIL
246006f25ae9SGregory Neil Shapiro 						    : EX_UNAVAILABLE;
246106f25ae9SGregory Neil Shapiro 				mci_setstat(mci, rcode, newstr(enhsc), p);
246206f25ae9SGregory Neil Shapiro 
246306f25ae9SGregory Neil Shapiro 				/*
246406f25ae9SGregory Neil Shapiro 				**  hack to get the error message into
246506f25ae9SGregory Neil Shapiro 				**  the envelope (done in giveresponse())
246606f25ae9SGregory Neil Shapiro 				*/
246706f25ae9SGregory Neil Shapiro 				(void) strlcpy(SmtpError, p, sizeof SmtpError);
246806f25ae9SGregory Neil Shapiro 			}
246906f25ae9SGregory Neil Shapiro 			QuickAbort = saveQuickAbort;
247006f25ae9SGregory Neil Shapiro 			SuprErrs = saveSuprErrs;
2471193538b7SGregory Neil Shapiro 			if (DONE_STARTTLS(mci->mci_flags) &&
2472193538b7SGregory Neil Shapiro 			    mci->mci_state != MCIS_CLOSED)
247306f25ae9SGregory Neil Shapiro 			{
2474193538b7SGregory Neil Shapiro 				SET_HELO(mci->mci_flags);
247506f25ae9SGregory Neil Shapiro 				mci->mci_flags &= ~MCIF_EXTENS;
247606f25ae9SGregory Neil Shapiro 				goto reconnect;
247706f25ae9SGregory Neil Shapiro 			}
247806f25ae9SGregory Neil Shapiro 		}
2479193538b7SGregory Neil Shapiro 		else if (mci->mci_ssl != NULL)
2480193538b7SGregory Neil Shapiro 		{
2481193538b7SGregory Neil Shapiro 			/* active TLS connection, use that data */
2482193538b7SGregory Neil Shapiro 			(void) tls_get_info(mci->mci_ssl, e, FALSE,
2483193538b7SGregory Neil Shapiro 					    mci->mci_host, FALSE);
2484193538b7SGregory Neil Shapiro 		}
248506f25ae9SGregory Neil Shapiro # endif /* STARTTLS */
248606f25ae9SGregory Neil Shapiro # if SASL
248706f25ae9SGregory Neil Shapiro 		/* if other server supports authentication let's authenticate */
248806f25ae9SGregory Neil Shapiro 		if (mci->mci_state != MCIS_CLOSED &&
248906f25ae9SGregory Neil Shapiro 		    mci->mci_saslcap != NULL &&
249006f25ae9SGregory Neil Shapiro #  if SFIO
2491193538b7SGregory Neil Shapiro 		    !DONE_AUTH(mci->mci_flags) &&
249206f25ae9SGregory Neil Shapiro #  endif /* SFIO */
249306f25ae9SGregory Neil Shapiro 		    SASLInfo != NULL)
249406f25ae9SGregory Neil Shapiro 		{
249506f25ae9SGregory Neil Shapiro 			/*
249606f25ae9SGregory Neil Shapiro 			**  should we require some minimum authentication?
249706f25ae9SGregory Neil Shapiro 			**  XXX ignore result?
249806f25ae9SGregory Neil Shapiro 			*/
249906f25ae9SGregory Neil Shapiro 			if (smtpauth(m, mci, e) == EX_OK)
250006f25ae9SGregory Neil Shapiro 			{
250106f25ae9SGregory Neil Shapiro #  if SFIO
250206f25ae9SGregory Neil Shapiro 				int result;
250306f25ae9SGregory Neil Shapiro 				sasl_ssf_t *ssf;
250406f25ae9SGregory Neil Shapiro 
250506f25ae9SGregory Neil Shapiro 				/* get security strength (features) */
250606f25ae9SGregory Neil Shapiro 				result = sasl_getprop(mci->mci_conn, SASL_SSF,
250706f25ae9SGregory Neil Shapiro 						      (void **) &ssf);
250806f25ae9SGregory Neil Shapiro 				if (LogLevel > 9)
250906f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_INFO, NOQID,
251006f25ae9SGregory Neil Shapiro 						  "SASL: outgoing connection to %.64s: mech=%.16s, bits=%d",
251106f25ae9SGregory Neil Shapiro 						  mci->mci_host,
251206f25ae9SGregory Neil Shapiro 						  macvalue(macid("{auth_type}",
251306f25ae9SGregory Neil Shapiro 								 NULL), e),
251406f25ae9SGregory Neil Shapiro 						  *ssf);
251506f25ae9SGregory Neil Shapiro 				/*
251606f25ae9SGregory Neil Shapiro 				**  only switch to encrypted connection
251706f25ae9SGregory Neil Shapiro 				**  if a security layer has been negotiated
251806f25ae9SGregory Neil Shapiro 				*/
251906f25ae9SGregory Neil Shapiro 				if (result == SASL_OK && *ssf > 0)
252006f25ae9SGregory Neil Shapiro 				{
252106f25ae9SGregory Neil Shapiro 					/*
252206f25ae9SGregory Neil Shapiro 					**  convert sfio stuff to use SASL
252306f25ae9SGregory Neil Shapiro 					**  check return values
252406f25ae9SGregory Neil Shapiro 					**  if the call fails,
252506f25ae9SGregory Neil Shapiro 					**  fall back to unencrypted version
252606f25ae9SGregory Neil Shapiro 					**  unless some cf option requires
252706f25ae9SGregory Neil Shapiro 					**  encryption then the connection must
252806f25ae9SGregory Neil Shapiro 					**  be aborted
252906f25ae9SGregory Neil Shapiro 					*/
253006f25ae9SGregory Neil Shapiro 					if (sfdcsasl(mci->mci_in, mci->mci_out,
253106f25ae9SGregory Neil Shapiro 						     mci->mci_conn) == 0)
253206f25ae9SGregory Neil Shapiro 					{
2533193538b7SGregory Neil Shapiro 						SET_HELO(mci->mci_flags);
253406f25ae9SGregory Neil Shapiro 						mci->mci_flags &= ~MCIF_EXTENS;
253506f25ae9SGregory Neil Shapiro 						mci->mci_flags |= MCIF_AUTHACT;
253606f25ae9SGregory Neil Shapiro 						goto reconnect;
253706f25ae9SGregory Neil Shapiro 					}
253806f25ae9SGregory Neil Shapiro 					syserr("SASL TLS switch failed in client");
253906f25ae9SGregory Neil Shapiro 				}
254006f25ae9SGregory Neil Shapiro 				/* else? XXX */
254106f25ae9SGregory Neil Shapiro #  endif /* SFIO */
254206f25ae9SGregory Neil Shapiro 				mci->mci_flags |= MCIF_AUTHACT;
254306f25ae9SGregory Neil Shapiro 
254406f25ae9SGregory Neil Shapiro 			}
254506f25ae9SGregory Neil Shapiro 		}
254606f25ae9SGregory Neil Shapiro # endif /* SASL */
254706f25ae9SGregory Neil Shapiro 	}
254806f25ae9SGregory Neil Shapiro 
254906f25ae9SGregory Neil Shapiro #endif /* SMTP */
2550c2aa98e2SPeter Wemm 
2551c2aa98e2SPeter Wemm do_transfer:
2552c2aa98e2SPeter Wemm 	/* clear out per-message flags from connection structure */
2553c2aa98e2SPeter Wemm 	mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);
2554c2aa98e2SPeter Wemm 
2555c2aa98e2SPeter Wemm 	if (bitset(EF_HAS8BIT, e->e_flags) &&
2556c2aa98e2SPeter Wemm 	    !bitset(EF_DONT_MIME, e->e_flags) &&
2557c2aa98e2SPeter Wemm 	    bitnset(M_7BITS, m->m_flags))
2558c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_CVT8TO7;
2559c2aa98e2SPeter Wemm 
2560c2aa98e2SPeter Wemm #if MIME7TO8
2561c2aa98e2SPeter Wemm 	if (bitnset(M_MAKE8BIT, m->m_flags) &&
2562c2aa98e2SPeter Wemm 	    !bitset(MCIF_7BIT, mci->mci_flags) &&
2563c2aa98e2SPeter Wemm 	    (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
2564c2aa98e2SPeter Wemm 	     (strcasecmp(p, "quoted-printable") == 0 ||
2565c2aa98e2SPeter Wemm 	      strcasecmp(p, "base64") == 0) &&
2566c2aa98e2SPeter Wemm 	    (p = hvalue("Content-Type", e->e_header)) != NULL)
2567c2aa98e2SPeter Wemm 	{
2568c2aa98e2SPeter Wemm 		/* may want to convert 7 -> 8 */
2569c2aa98e2SPeter Wemm 		/* XXX should really parse it here -- and use a class XXX */
2570c2aa98e2SPeter Wemm 		if (strncasecmp(p, "text/plain", 10) == 0 &&
2571c2aa98e2SPeter Wemm 		    (p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
2572c2aa98e2SPeter Wemm 			mci->mci_flags |= MCIF_CVT7TO8;
2573c2aa98e2SPeter Wemm 	}
257406f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */
2575c2aa98e2SPeter Wemm 
2576c2aa98e2SPeter Wemm 	if (tTd(11, 1))
2577c2aa98e2SPeter Wemm 	{
257806f25ae9SGregory Neil Shapiro 		dprintf("openmailer: ");
2579c2aa98e2SPeter Wemm 		mci_dump(mci, FALSE);
2580c2aa98e2SPeter Wemm 	}
2581c2aa98e2SPeter Wemm 
2582c2aa98e2SPeter Wemm 	if (mci->mci_state != MCIS_OPEN)
2583c2aa98e2SPeter Wemm 	{
2584c2aa98e2SPeter Wemm 		/* couldn't open the mailer */
2585c2aa98e2SPeter Wemm 		rcode = mci->mci_exitstat;
2586c2aa98e2SPeter Wemm 		errno = mci->mci_errno;
2587c2aa98e2SPeter Wemm #if NAMED_BIND
2588602a2b1bSGregory Neil Shapiro 		SM_SET_H_ERRNO(mci->mci_herrno);
258906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
2590c2aa98e2SPeter Wemm 		if (rcode == EX_OK)
2591c2aa98e2SPeter Wemm 		{
2592c2aa98e2SPeter Wemm 			/* shouldn't happen */
259306f25ae9SGregory Neil Shapiro 			syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s",
259406f25ae9SGregory Neil Shapiro 				(u_long) mci, rcode, errno, mci->mci_state,
2595c2aa98e2SPeter Wemm 				firstsig);
2596c2aa98e2SPeter Wemm 			mci_dump_all(TRUE);
2597c2aa98e2SPeter Wemm 			rcode = EX_SOFTWARE;
2598c2aa98e2SPeter Wemm 		}
2599c2aa98e2SPeter Wemm #if DAEMON
260006f25ae9SGregory Neil Shapiro 		else if (nummxhosts > hostnum)
2601c2aa98e2SPeter Wemm 		{
2602c2aa98e2SPeter Wemm 			/* try next MX site */
2603c2aa98e2SPeter Wemm 			goto tryhost;
2604c2aa98e2SPeter Wemm 		}
260506f25ae9SGregory Neil Shapiro #endif /* DAEMON */
2606c2aa98e2SPeter Wemm 	}
2607c2aa98e2SPeter Wemm 	else if (!clever)
2608c2aa98e2SPeter Wemm 	{
2609c2aa98e2SPeter Wemm 		/*
2610c2aa98e2SPeter Wemm 		**  Format and send message.
2611c2aa98e2SPeter Wemm 		*/
2612c2aa98e2SPeter Wemm 
2613c2aa98e2SPeter Wemm 		putfromline(mci, e);
26142e43090eSPeter Wemm 		(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
2615c2aa98e2SPeter Wemm 		(*e->e_putbody)(mci, e, NULL);
2616c2aa98e2SPeter Wemm 
2617c2aa98e2SPeter Wemm 		/* get the exit status */
2618c2aa98e2SPeter Wemm 		rcode = endmailer(mci, e, pv);
2619602a2b1bSGregory Neil Shapiro 		if (rcode == EX_TEMPFAIL &&
2620602a2b1bSGregory Neil Shapiro 		    SmtpError[0] == '\0')
2621602a2b1bSGregory Neil Shapiro 		{
2622602a2b1bSGregory Neil Shapiro 			/*
2623602a2b1bSGregory Neil Shapiro 			**  Need an e_message for mailq display.
2624602a2b1bSGregory Neil Shapiro 			**  We set SmtpError as
2625602a2b1bSGregory Neil Shapiro 			*/
2626602a2b1bSGregory Neil Shapiro 
2627602a2b1bSGregory Neil Shapiro 			snprintf(SmtpError, sizeof SmtpError,
2628602a2b1bSGregory Neil Shapiro 				 "%s mailer (%s) exited with EX_TEMPFAIL",
2629602a2b1bSGregory Neil Shapiro 				 m->m_name, m->m_mailer);
2630602a2b1bSGregory Neil Shapiro 		}
2631c2aa98e2SPeter Wemm 	}
2632c2aa98e2SPeter Wemm 	else
2633c2aa98e2SPeter Wemm #if SMTP
2634c2aa98e2SPeter Wemm 	{
2635c2aa98e2SPeter Wemm 		/*
2636c2aa98e2SPeter Wemm 		**  Send the MAIL FROM: protocol
2637c2aa98e2SPeter Wemm 		*/
2638c2aa98e2SPeter Wemm 
2639c2aa98e2SPeter Wemm 		rcode = smtpmailfrom(m, mci, e);
2640c2aa98e2SPeter Wemm 		if (rcode == EX_OK)
2641c2aa98e2SPeter Wemm 		{
2642c2aa98e2SPeter Wemm 			register char *t = tobuf;
2643c2aa98e2SPeter Wemm 			register int i;
2644c2aa98e2SPeter Wemm 
2645c2aa98e2SPeter Wemm 			/* send the recipient list */
2646c2aa98e2SPeter Wemm 			tobuf[0] = '\0';
264706f25ae9SGregory Neil Shapiro 
2648c2aa98e2SPeter Wemm 			for (to = tochain; to != NULL; to = to->q_tchain)
2649c2aa98e2SPeter Wemm 			{
2650c2aa98e2SPeter Wemm 				e->e_to = to->q_paddr;
265106f25ae9SGregory Neil Shapiro #if !_FFR_DYNAMIC_TOBUF
265206f25ae9SGregory Neil Shapiro 				if (strlen(to->q_paddr) +
265306f25ae9SGregory Neil Shapiro 				    (t - tobuf) + 2 > sizeof tobuf)
2654c2aa98e2SPeter Wemm 				{
2655c2aa98e2SPeter Wemm 					/* not enough room */
2656c2aa98e2SPeter Wemm 					continue;
2657c2aa98e2SPeter Wemm 				}
265806f25ae9SGregory Neil Shapiro #endif /* !_FFR_DYNAMIC_TOBUF */
265906f25ae9SGregory Neil Shapiro 
266006f25ae9SGregory Neil Shapiro # if STARTTLS
266106f25ae9SGregory Neil Shapiro #  if _FFR_TLS_RCPT
266206f25ae9SGregory Neil Shapiro 				i = rscheck("tls_rcpt", to->q_user, NULL, e,
2663193538b7SGregory Neil Shapiro 					    TRUE, TRUE, 4, mci->mci_host);
266406f25ae9SGregory Neil Shapiro 				if (i != EX_OK)
2665c2aa98e2SPeter Wemm 				{
2666193538b7SGregory Neil Shapiro 					/* avoid bogus error msg */
2667193538b7SGregory Neil Shapiro 					errno = 0;
266806f25ae9SGregory Neil Shapiro 					markfailure(e, to, mci, i, FALSE);
266906f25ae9SGregory Neil Shapiro 					giveresponse(i, to->q_status,  m,
267006f25ae9SGregory Neil Shapiro 						     mci, ctladdr, xstart, e);
267106f25ae9SGregory Neil Shapiro 					continue;
267206f25ae9SGregory Neil Shapiro 				}
267306f25ae9SGregory Neil Shapiro #  endif /* _FFR_TLS_RCPT */
267406f25ae9SGregory Neil Shapiro # endif /* STARTTLS */
267506f25ae9SGregory Neil Shapiro 
267606f25ae9SGregory Neil Shapiro 				if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
267706f25ae9SGregory Neil Shapiro 				{
267806f25ae9SGregory Neil Shapiro 					markfailure(e, to, mci, i, FALSE);
267906f25ae9SGregory Neil Shapiro 					giveresponse(i, to->q_status,  m,
268006f25ae9SGregory Neil Shapiro 						     mci, ctladdr, xstart, e);
2681c2aa98e2SPeter Wemm 				}
2682c2aa98e2SPeter Wemm 				else
2683c2aa98e2SPeter Wemm 				{
2684c2aa98e2SPeter Wemm 					*t++ = ',';
2685c2aa98e2SPeter Wemm 					for (p = to->q_paddr; *p; *t++ = *p++)
2686c2aa98e2SPeter Wemm 						continue;
2687c2aa98e2SPeter Wemm 					*t = '\0';
2688c2aa98e2SPeter Wemm 				}
2689c2aa98e2SPeter Wemm 			}
2690c2aa98e2SPeter Wemm 
2691c2aa98e2SPeter Wemm 			/* now send the data */
2692c2aa98e2SPeter Wemm 			if (tobuf[0] == '\0')
2693c2aa98e2SPeter Wemm 			{
2694c2aa98e2SPeter Wemm 				rcode = EX_OK;
2695c2aa98e2SPeter Wemm 				e->e_to = NULL;
2696c2aa98e2SPeter Wemm 				if (bitset(MCIF_CACHED, mci->mci_flags))
2697c2aa98e2SPeter Wemm 					smtprset(m, mci, e);
2698c2aa98e2SPeter Wemm 			}
2699c2aa98e2SPeter Wemm 			else
2700c2aa98e2SPeter Wemm 			{
2701c2aa98e2SPeter Wemm 				e->e_to = tobuf + 1;
2702c2aa98e2SPeter Wemm 				rcode = smtpdata(m, mci, e);
2703c2aa98e2SPeter Wemm 			}
2704c2aa98e2SPeter Wemm 		}
2705c2aa98e2SPeter Wemm # if DAEMON
270606f25ae9SGregory Neil Shapiro 		if (rcode == EX_TEMPFAIL && nummxhosts > hostnum)
2707c2aa98e2SPeter Wemm 		{
2708c2aa98e2SPeter Wemm 			/* try next MX site */
2709c2aa98e2SPeter Wemm 			goto tryhost;
2710c2aa98e2SPeter Wemm 		}
271106f25ae9SGregory Neil Shapiro # endif /* DAEMON */
2712c2aa98e2SPeter Wemm 	}
271306f25ae9SGregory Neil Shapiro #else /* SMTP */
2714c2aa98e2SPeter Wemm 	{
271506f25ae9SGregory Neil Shapiro 		syserr("554 5.3.5 deliver: need SMTP compiled to use clever mailer");
2716c2aa98e2SPeter Wemm 		rcode = EX_CONFIG;
2717c2aa98e2SPeter Wemm 		goto give_up;
2718c2aa98e2SPeter Wemm 	}
2719c2aa98e2SPeter Wemm #endif /* SMTP */
2720c2aa98e2SPeter Wemm #if NAMED_BIND
2721c2aa98e2SPeter Wemm 	if (ConfigLevel < 2)
2722c2aa98e2SPeter Wemm 		_res.options |= RES_DEFNAMES | RES_DNSRCH;	/* XXX */
272306f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
2724c2aa98e2SPeter Wemm 
2725c2aa98e2SPeter Wemm 	if (tTd(62, 1))
2726c2aa98e2SPeter Wemm 		checkfds("after delivery");
2727c2aa98e2SPeter Wemm 
2728c2aa98e2SPeter Wemm 	/*
2729c2aa98e2SPeter Wemm 	**  Do final status disposal.
2730c2aa98e2SPeter Wemm 	**	We check for something in tobuf for the SMTP case.
2731c2aa98e2SPeter Wemm 	**	If we got a temporary failure, arrange to queue the
2732c2aa98e2SPeter Wemm 	**		addressees.
2733c2aa98e2SPeter Wemm 	*/
2734c2aa98e2SPeter Wemm 
2735c2aa98e2SPeter Wemm   give_up:
2736c2aa98e2SPeter Wemm #if SMTP
2737c2aa98e2SPeter Wemm 	if (bitnset(M_LMTP, m->m_flags))
2738c2aa98e2SPeter Wemm 	{
2739c2aa98e2SPeter Wemm 		lmtp_rcode = rcode;
2740c2aa98e2SPeter Wemm 		tobuf[0] = '\0';
2741c2aa98e2SPeter Wemm 		anyok = FALSE;
2742c2aa98e2SPeter Wemm 	}
2743c2aa98e2SPeter Wemm 	else
274406f25ae9SGregory Neil Shapiro #endif /* SMTP */
2745c2aa98e2SPeter Wemm 		anyok = rcode == EX_OK;
2746c2aa98e2SPeter Wemm 
2747c2aa98e2SPeter Wemm 	for (to = tochain; to != NULL; to = to->q_tchain)
2748c2aa98e2SPeter Wemm 	{
2749c2aa98e2SPeter Wemm 		/* see if address already marked */
275006f25ae9SGregory Neil Shapiro 		if (!QS_IS_OK(to->q_state))
2751c2aa98e2SPeter Wemm 			continue;
2752c2aa98e2SPeter Wemm 
2753c2aa98e2SPeter Wemm #if SMTP
2754c2aa98e2SPeter Wemm 		/* if running LMTP, get the status for each address */
2755c2aa98e2SPeter Wemm 		if (bitnset(M_LMTP, m->m_flags))
2756c2aa98e2SPeter Wemm 		{
2757c2aa98e2SPeter Wemm 			if (lmtp_rcode == EX_OK)
2758c2aa98e2SPeter Wemm 				rcode = smtpgetstat(m, mci, e);
2759c2aa98e2SPeter Wemm 			if (rcode == EX_OK)
2760c2aa98e2SPeter Wemm 			{
276142e5d165SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
276242e5d165SGregory Neil Shapiro 				(void) strlcat(tobuf, ",", tobufsize);
276342e5d165SGregory Neil Shapiro 				(void) strlcat(tobuf, to->q_paddr, tobufsize);
276442e5d165SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
276506f25ae9SGregory Neil Shapiro 				if (strlen(to->q_paddr) +
276606f25ae9SGregory Neil Shapiro 				    strlen(tobuf) + 2 > sizeof tobuf)
2767c2aa98e2SPeter Wemm 				{
2768c2aa98e2SPeter Wemm 					syserr("LMTP tobuf overflow");
2769c2aa98e2SPeter Wemm 				}
2770c2aa98e2SPeter Wemm 				else
2771c2aa98e2SPeter Wemm 				{
277206f25ae9SGregory Neil Shapiro 					(void) strlcat(tobuf, ",",
277306f25ae9SGregory Neil Shapiro 						       sizeof tobuf);
277406f25ae9SGregory Neil Shapiro 					(void) strlcat(tobuf, to->q_paddr,
277506f25ae9SGregory Neil Shapiro 						       sizeof tobuf);
2776c2aa98e2SPeter Wemm 				}
277742e5d165SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
2778c2aa98e2SPeter Wemm 				anyok = TRUE;
2779c2aa98e2SPeter Wemm 			}
2780c2aa98e2SPeter Wemm 			else
2781c2aa98e2SPeter Wemm 			{
2782c2aa98e2SPeter Wemm 				e->e_to = to->q_paddr;
278306f25ae9SGregory Neil Shapiro 				markfailure(e, to, mci, rcode, TRUE);
278406f25ae9SGregory Neil Shapiro 				giveresponse(rcode, to->q_status, m, mci,
278506f25ae9SGregory Neil Shapiro 					     ctladdr, xstart, e);
2786c2aa98e2SPeter Wemm 				e->e_to = tobuf + 1;
2787c2aa98e2SPeter Wemm 				continue;
2788c2aa98e2SPeter Wemm 			}
2789c2aa98e2SPeter Wemm 		}
2790c2aa98e2SPeter Wemm 		else
279106f25ae9SGregory Neil Shapiro #endif /* SMTP */
2792c2aa98e2SPeter Wemm 		{
2793c2aa98e2SPeter Wemm 			/* mark bad addresses */
2794c2aa98e2SPeter Wemm 			if (rcode != EX_OK)
2795c2aa98e2SPeter Wemm 			{
2796c2aa98e2SPeter Wemm 				if (goodmxfound && rcode == EX_NOHOST)
2797c2aa98e2SPeter Wemm 					rcode = EX_TEMPFAIL;
279806f25ae9SGregory Neil Shapiro 				markfailure(e, to, mci, rcode, TRUE);
2799c2aa98e2SPeter Wemm 				continue;
2800c2aa98e2SPeter Wemm 			}
2801c2aa98e2SPeter Wemm 		}
2802c2aa98e2SPeter Wemm 
2803c2aa98e2SPeter Wemm 		/* successful delivery */
280406f25ae9SGregory Neil Shapiro 		to->q_state = QS_SENT;
2805c2aa98e2SPeter Wemm 		to->q_statdate = curtime();
2806c2aa98e2SPeter Wemm 		e->e_nsent++;
280706f25ae9SGregory Neil Shapiro 
280806f25ae9SGregory Neil Shapiro #if QUEUE
280906f25ae9SGregory Neil Shapiro 		/*
281006f25ae9SGregory Neil Shapiro 		**  Checkpoint the send list every few addresses
281106f25ae9SGregory Neil Shapiro 		*/
281206f25ae9SGregory Neil Shapiro 
281342e5d165SGregory Neil Shapiro 		if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval)
281406f25ae9SGregory Neil Shapiro 		{
281506f25ae9SGregory Neil Shapiro 			queueup(e, FALSE);
281606f25ae9SGregory Neil Shapiro 			e->e_nsent = 0;
281706f25ae9SGregory Neil Shapiro 		}
281806f25ae9SGregory Neil Shapiro #endif /* QUEUE */
281906f25ae9SGregory Neil Shapiro 
2820c2aa98e2SPeter Wemm 		if (bitnset(M_LOCALMAILER, m->m_flags) &&
2821c2aa98e2SPeter Wemm 		    bitset(QPINGONSUCCESS, to->q_flags))
2822c2aa98e2SPeter Wemm 		{
2823c2aa98e2SPeter Wemm 			to->q_flags |= QDELIVERED;
2824c2aa98e2SPeter Wemm 			to->q_status = "2.1.5";
2825c2aa98e2SPeter Wemm 			fprintf(e->e_xfp, "%s... Successfully delivered\n",
2826c2aa98e2SPeter Wemm 				to->q_paddr);
2827c2aa98e2SPeter Wemm 		}
2828c2aa98e2SPeter Wemm 		else if (bitset(QPINGONSUCCESS, to->q_flags) &&
2829c2aa98e2SPeter Wemm 			 bitset(QPRIMARY, to->q_flags) &&
2830c2aa98e2SPeter Wemm 			 !bitset(MCIF_DSN, mci->mci_flags))
2831c2aa98e2SPeter Wemm 		{
2832c2aa98e2SPeter Wemm 			to->q_flags |= QRELAYED;
2833c2aa98e2SPeter Wemm 			fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n",
2834c2aa98e2SPeter Wemm 				to->q_paddr);
2835c2aa98e2SPeter Wemm 		}
2836c2aa98e2SPeter Wemm 	}
2837c2aa98e2SPeter Wemm 
2838c2aa98e2SPeter Wemm #if SMTP
2839c2aa98e2SPeter Wemm 	if (bitnset(M_LMTP, m->m_flags))
2840c2aa98e2SPeter Wemm 	{
2841c2aa98e2SPeter Wemm 		/*
2842c2aa98e2SPeter Wemm 		**  Global information applies to the last recipient only;
2843c2aa98e2SPeter Wemm 		**  clear it out to avoid bogus errors.
2844c2aa98e2SPeter Wemm 		*/
2845c2aa98e2SPeter Wemm 
2846c2aa98e2SPeter Wemm 		rcode = EX_OK;
2847c2aa98e2SPeter Wemm 		e->e_statmsg = NULL;
2848c2aa98e2SPeter Wemm 
2849c2aa98e2SPeter Wemm 		/* reset the mci state for the next transaction */
2850c2aa98e2SPeter Wemm 		if (mci != NULL && mci->mci_state == MCIS_ACTIVE)
2851c2aa98e2SPeter Wemm 			mci->mci_state = MCIS_OPEN;
2852c2aa98e2SPeter Wemm 	}
285306f25ae9SGregory Neil Shapiro #endif /* SMTP */
2854c2aa98e2SPeter Wemm 
2855c2aa98e2SPeter Wemm 	if (tobuf[0] != '\0')
285606f25ae9SGregory Neil Shapiro 		giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e);
2857c2aa98e2SPeter Wemm 	if (anyok)
2858c2aa98e2SPeter Wemm 		markstats(e, tochain, FALSE);
2859c2aa98e2SPeter Wemm 	mci_store_persistent(mci);
2860c2aa98e2SPeter Wemm 
2861c2aa98e2SPeter Wemm #if SMTP
2862c2aa98e2SPeter Wemm 	/* now close the connection */
2863c2aa98e2SPeter Wemm 	if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED &&
2864c2aa98e2SPeter Wemm 	    !bitset(MCIF_CACHED, mci->mci_flags))
2865c2aa98e2SPeter Wemm 		smtpquit(m, mci, e);
286606f25ae9SGregory Neil Shapiro #endif /* SMTP */
2867c2aa98e2SPeter Wemm 
2868c2aa98e2SPeter Wemm 	/*
2869c2aa98e2SPeter Wemm 	**  Restore state and return.
2870c2aa98e2SPeter Wemm 	*/
2871c2aa98e2SPeter Wemm 
2872c2aa98e2SPeter Wemm #if XDEBUG
2873c2aa98e2SPeter Wemm 	{
2874c2aa98e2SPeter Wemm 		char wbuf[MAXLINE];
2875c2aa98e2SPeter Wemm 
2876c2aa98e2SPeter Wemm 		/* make absolutely certain 0, 1, and 2 are in use */
2877c2aa98e2SPeter Wemm 		snprintf(wbuf, sizeof wbuf, "%s... end of deliver(%s)",
2878c2aa98e2SPeter Wemm 			e->e_to == NULL ? "NO-TO-LIST"
2879c2aa98e2SPeter Wemm 					: shortenstring(e->e_to, MAXSHORTSTR),
2880c2aa98e2SPeter Wemm 			m->m_name);
2881c2aa98e2SPeter Wemm 		checkfd012(wbuf);
2882c2aa98e2SPeter Wemm 	}
288306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
2884c2aa98e2SPeter Wemm 
2885c2aa98e2SPeter Wemm 	errno = 0;
2886c2aa98e2SPeter Wemm 	define('g', (char *) NULL, e);
288706f25ae9SGregory Neil Shapiro 	e->e_to = NULL;
288806f25ae9SGregory Neil Shapiro 	return rcode;
2889c2aa98e2SPeter Wemm }
289006f25ae9SGregory Neil Shapiro 
2891c2aa98e2SPeter Wemm /*
2892c2aa98e2SPeter Wemm **  MARKFAILURE -- mark a failure on a specific address.
2893c2aa98e2SPeter Wemm **
2894c2aa98e2SPeter Wemm **	Parameters:
2895c2aa98e2SPeter Wemm **		e -- the envelope we are sending.
2896c2aa98e2SPeter Wemm **		q -- the address to mark.
2897c2aa98e2SPeter Wemm **		mci -- mailer connection information.
2898c2aa98e2SPeter Wemm **		rcode -- the code signifying the particular failure.
289906f25ae9SGregory Neil Shapiro **		ovr -- override an existing code?
2900c2aa98e2SPeter Wemm **
2901c2aa98e2SPeter Wemm **	Returns:
2902c2aa98e2SPeter Wemm **		none.
2903c2aa98e2SPeter Wemm **
2904c2aa98e2SPeter Wemm **	Side Effects:
2905c2aa98e2SPeter Wemm **		marks the address (and possibly the envelope) with the
2906c2aa98e2SPeter Wemm **			failure so that an error will be returned or
2907c2aa98e2SPeter Wemm **			the message will be queued, as appropriate.
2908c2aa98e2SPeter Wemm */
2909c2aa98e2SPeter Wemm 
291006f25ae9SGregory Neil Shapiro static void
291106f25ae9SGregory Neil Shapiro markfailure(e, q, mci, rcode, ovr)
2912c2aa98e2SPeter Wemm 	register ENVELOPE *e;
2913c2aa98e2SPeter Wemm 	register ADDRESS *q;
2914c2aa98e2SPeter Wemm 	register MCI *mci;
2915c2aa98e2SPeter Wemm 	int rcode;
291606f25ae9SGregory Neil Shapiro 	bool ovr;
2917c2aa98e2SPeter Wemm {
291806f25ae9SGregory Neil Shapiro 	char *status = NULL;
291906f25ae9SGregory Neil Shapiro 	char *rstatus = NULL;
2920c2aa98e2SPeter Wemm 
2921c2aa98e2SPeter Wemm 	switch (rcode)
2922c2aa98e2SPeter Wemm 	{
2923c2aa98e2SPeter Wemm 	  case EX_OK:
2924c2aa98e2SPeter Wemm 		break;
2925c2aa98e2SPeter Wemm 
2926c2aa98e2SPeter Wemm 	  case EX_TEMPFAIL:
2927c2aa98e2SPeter Wemm 	  case EX_IOERR:
2928c2aa98e2SPeter Wemm 	  case EX_OSERR:
292906f25ae9SGregory Neil Shapiro 		q->q_state = QS_QUEUEUP;
2930c2aa98e2SPeter Wemm 		break;
2931c2aa98e2SPeter Wemm 
2932c2aa98e2SPeter Wemm 	  default:
293306f25ae9SGregory Neil Shapiro 		q->q_state = QS_BADADDR;
2934c2aa98e2SPeter Wemm 		break;
2935c2aa98e2SPeter Wemm 	}
2936c2aa98e2SPeter Wemm 
2937c2aa98e2SPeter Wemm 	/* find most specific error code possible */
2938c2aa98e2SPeter Wemm 	if (mci != NULL && mci->mci_status != NULL)
2939c2aa98e2SPeter Wemm 	{
294006f25ae9SGregory Neil Shapiro 		status = mci->mci_status;
2941c2aa98e2SPeter Wemm 		if (mci->mci_rstatus != NULL)
294206f25ae9SGregory Neil Shapiro 			rstatus = newstr(mci->mci_rstatus);
2943c2aa98e2SPeter Wemm 		else
294406f25ae9SGregory Neil Shapiro 			rstatus = NULL;
2945c2aa98e2SPeter Wemm 	}
2946c2aa98e2SPeter Wemm 	else if (e->e_status != NULL)
2947c2aa98e2SPeter Wemm 	{
294806f25ae9SGregory Neil Shapiro 		status = e->e_status;
294906f25ae9SGregory Neil Shapiro 		rstatus = NULL;
2950c2aa98e2SPeter Wemm 	}
2951c2aa98e2SPeter Wemm 	else
2952c2aa98e2SPeter Wemm 	{
2953c2aa98e2SPeter Wemm 		switch (rcode)
2954c2aa98e2SPeter Wemm 		{
2955c2aa98e2SPeter Wemm 		  case EX_USAGE:
295606f25ae9SGregory Neil Shapiro 			status = "5.5.4";
2957c2aa98e2SPeter Wemm 			break;
2958c2aa98e2SPeter Wemm 
2959c2aa98e2SPeter Wemm 		  case EX_DATAERR:
296006f25ae9SGregory Neil Shapiro 			status = "5.5.2";
2961c2aa98e2SPeter Wemm 			break;
2962c2aa98e2SPeter Wemm 
2963c2aa98e2SPeter Wemm 		  case EX_NOUSER:
296406f25ae9SGregory Neil Shapiro 			status = "5.1.1";
2965c2aa98e2SPeter Wemm 			break;
2966c2aa98e2SPeter Wemm 
2967c2aa98e2SPeter Wemm 		  case EX_NOHOST:
296806f25ae9SGregory Neil Shapiro 			status = "5.1.2";
2969c2aa98e2SPeter Wemm 			break;
2970c2aa98e2SPeter Wemm 
2971c2aa98e2SPeter Wemm 		  case EX_NOINPUT:
2972c2aa98e2SPeter Wemm 		  case EX_CANTCREAT:
2973c2aa98e2SPeter Wemm 		  case EX_NOPERM:
297406f25ae9SGregory Neil Shapiro 			status = "5.3.0";
2975c2aa98e2SPeter Wemm 			break;
2976c2aa98e2SPeter Wemm 
2977c2aa98e2SPeter Wemm 		  case EX_UNAVAILABLE:
2978c2aa98e2SPeter Wemm 		  case EX_SOFTWARE:
2979c2aa98e2SPeter Wemm 		  case EX_OSFILE:
2980c2aa98e2SPeter Wemm 		  case EX_PROTOCOL:
2981c2aa98e2SPeter Wemm 		  case EX_CONFIG:
298206f25ae9SGregory Neil Shapiro 			status = "5.5.0";
2983c2aa98e2SPeter Wemm 			break;
2984c2aa98e2SPeter Wemm 
2985c2aa98e2SPeter Wemm 		  case EX_OSERR:
2986c2aa98e2SPeter Wemm 		  case EX_IOERR:
298706f25ae9SGregory Neil Shapiro 			status = "4.5.0";
2988c2aa98e2SPeter Wemm 			break;
2989c2aa98e2SPeter Wemm 
2990c2aa98e2SPeter Wemm 		  case EX_TEMPFAIL:
299106f25ae9SGregory Neil Shapiro 			status = "4.2.0";
2992c2aa98e2SPeter Wemm 			break;
2993c2aa98e2SPeter Wemm 		}
2994c2aa98e2SPeter Wemm 	}
2995c2aa98e2SPeter Wemm 
299606f25ae9SGregory Neil Shapiro 	/* new status? */
299706f25ae9SGregory Neil Shapiro 	if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL ||
299806f25ae9SGregory Neil Shapiro 	    *q->q_status == '\0' || *q->q_status < *status))
299906f25ae9SGregory Neil Shapiro 	{
300006f25ae9SGregory Neil Shapiro 		q->q_status = status;
300106f25ae9SGregory Neil Shapiro 		q->q_rstatus = rstatus;
300206f25ae9SGregory Neil Shapiro 	}
3003c2aa98e2SPeter Wemm 	if (rcode != EX_OK && q->q_rstatus == NULL &&
3004c2aa98e2SPeter Wemm 	    q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL &&
300506f25ae9SGregory Neil Shapiro 	    strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0)
3006c2aa98e2SPeter Wemm 	{
300706f25ae9SGregory Neil Shapiro 		char buf[16];
3008c2aa98e2SPeter Wemm 
3009c2aa98e2SPeter Wemm 		(void) snprintf(buf, sizeof buf, "%d", rcode);
3010c2aa98e2SPeter Wemm 		q->q_rstatus = newstr(buf);
3011c2aa98e2SPeter Wemm 	}
301206f25ae9SGregory Neil Shapiro 
301306f25ae9SGregory Neil Shapiro 	q->q_statdate = curtime();
301406f25ae9SGregory Neil Shapiro 	if (CurHostName != NULL && CurHostName[0] != '\0' &&
301506f25ae9SGregory Neil Shapiro 	    mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags))
301606f25ae9SGregory Neil Shapiro 		q->q_statmta = newstr(CurHostName);
3017c2aa98e2SPeter Wemm }
3018c2aa98e2SPeter Wemm /*
3019c2aa98e2SPeter Wemm **  ENDMAILER -- Wait for mailer to terminate.
3020c2aa98e2SPeter Wemm **
3021c2aa98e2SPeter Wemm **	We should never get fatal errors (e.g., segmentation
3022c2aa98e2SPeter Wemm **	violation), so we report those specially.  For other
3023c2aa98e2SPeter Wemm **	errors, we choose a status message (into statmsg),
3024c2aa98e2SPeter Wemm **	and if it represents an error, we print it.
3025c2aa98e2SPeter Wemm **
3026c2aa98e2SPeter Wemm **	Parameters:
3027c2aa98e2SPeter Wemm **		pid -- pid of mailer.
3028c2aa98e2SPeter Wemm **		e -- the current envelope.
3029c2aa98e2SPeter Wemm **		pv -- the parameter vector that invoked the mailer
3030c2aa98e2SPeter Wemm **			(for error messages).
3031c2aa98e2SPeter Wemm **
3032c2aa98e2SPeter Wemm **	Returns:
3033c2aa98e2SPeter Wemm **		exit code of mailer.
3034c2aa98e2SPeter Wemm **
3035c2aa98e2SPeter Wemm **	Side Effects:
3036c2aa98e2SPeter Wemm **		none.
3037c2aa98e2SPeter Wemm */
3038c2aa98e2SPeter Wemm 
303906f25ae9SGregory Neil Shapiro static jmp_buf	EndWaitTimeout;
304006f25ae9SGregory Neil Shapiro 
304106f25ae9SGregory Neil Shapiro static void
304206f25ae9SGregory Neil Shapiro endwaittimeout()
304306f25ae9SGregory Neil Shapiro {
304406f25ae9SGregory Neil Shapiro 	errno = ETIMEDOUT;
304506f25ae9SGregory Neil Shapiro 	longjmp(EndWaitTimeout, 1);
304606f25ae9SGregory Neil Shapiro }
304706f25ae9SGregory Neil Shapiro 
3048c2aa98e2SPeter Wemm int
3049c2aa98e2SPeter Wemm endmailer(mci, e, pv)
3050c2aa98e2SPeter Wemm 	register MCI *mci;
3051c2aa98e2SPeter Wemm 	register ENVELOPE *e;
3052c2aa98e2SPeter Wemm 	char **pv;
3053c2aa98e2SPeter Wemm {
3054c2aa98e2SPeter Wemm 	int st;
305506f25ae9SGregory Neil Shapiro 	int save_errno = errno;
305606f25ae9SGregory Neil Shapiro 	char buf[MAXLINE];
305706f25ae9SGregory Neil Shapiro 	EVENT *ev = NULL;
305806f25ae9SGregory Neil Shapiro 
3059c2aa98e2SPeter Wemm 
3060c2aa98e2SPeter Wemm 	mci_unlock_host(mci);
3061c2aa98e2SPeter Wemm 
306206f25ae9SGregory Neil Shapiro #if SASL
306306f25ae9SGregory Neil Shapiro 	/* shutdown SASL */
306406f25ae9SGregory Neil Shapiro 	if (bitset(MCIF_AUTHACT, mci->mci_flags))
306506f25ae9SGregory Neil Shapiro 	{
306606f25ae9SGregory Neil Shapiro 		sasl_dispose(&mci->mci_conn);
306706f25ae9SGregory Neil Shapiro 		mci->mci_flags &= ~MCIF_AUTHACT;
306806f25ae9SGregory Neil Shapiro 	}
306906f25ae9SGregory Neil Shapiro #endif /* SASL */
307006f25ae9SGregory Neil Shapiro 
307106f25ae9SGregory Neil Shapiro #if STARTTLS
307206f25ae9SGregory Neil Shapiro 	/* shutdown TLS */
307306f25ae9SGregory Neil Shapiro 	(void) endtlsclt(mci);
307406f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
307506f25ae9SGregory Neil Shapiro 
307606f25ae9SGregory Neil Shapiro 	/* close output to mailer */
3077c2aa98e2SPeter Wemm 	if (mci->mci_out != NULL)
307806f25ae9SGregory Neil Shapiro 		(void) fclose(mci->mci_out);
307906f25ae9SGregory Neil Shapiro 
308006f25ae9SGregory Neil Shapiro 	/* copy any remaining input to transcript */
308106f25ae9SGregory Neil Shapiro 	if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR &&
308206f25ae9SGregory Neil Shapiro 	    e->e_xfp != NULL)
308306f25ae9SGregory Neil Shapiro 	{
308406f25ae9SGregory Neil Shapiro 		while (sfgets(buf, sizeof buf, mci->mci_in,
308506f25ae9SGregory Neil Shapiro 		       TimeOuts.to_quit, "Draining Input") != NULL)
308606f25ae9SGregory Neil Shapiro 			(void) fputs(buf, e->e_xfp);
308706f25ae9SGregory Neil Shapiro 	}
308806f25ae9SGregory Neil Shapiro 
308906f25ae9SGregory Neil Shapiro 	/* now close the input */
309006f25ae9SGregory Neil Shapiro 	if (mci->mci_in != NULL)
309106f25ae9SGregory Neil Shapiro 		(void) fclose(mci->mci_in);
3092c2aa98e2SPeter Wemm 	mci->mci_in = mci->mci_out = NULL;
3093c2aa98e2SPeter Wemm 	mci->mci_state = MCIS_CLOSED;
3094c2aa98e2SPeter Wemm 
309506f25ae9SGregory Neil Shapiro 	errno = save_errno;
309606f25ae9SGregory Neil Shapiro 
3097c2aa98e2SPeter Wemm 	/* in the IPC case there is nothing to wait for */
3098c2aa98e2SPeter Wemm 	if (mci->mci_pid == 0)
309906f25ae9SGregory Neil Shapiro 		return EX_OK;
3100c2aa98e2SPeter Wemm 
310106f25ae9SGregory Neil Shapiro 	/* put a timeout around the wait */
310206f25ae9SGregory Neil Shapiro 	if (mci->mci_mailer->m_wait > 0)
310306f25ae9SGregory Neil Shapiro 	{
310406f25ae9SGregory Neil Shapiro 		if (setjmp(EndWaitTimeout) == 0)
310506f25ae9SGregory Neil Shapiro 			ev = setevent(mci->mci_mailer->m_wait,
310606f25ae9SGregory Neil Shapiro 				      endwaittimeout, 0);
310706f25ae9SGregory Neil Shapiro 		else
310806f25ae9SGregory Neil Shapiro 		{
310942e5d165SGregory Neil Shapiro 			syserr("endmailer %s: wait timeout (%ld)",
311006f25ae9SGregory Neil Shapiro 			       mci->mci_mailer->m_name,
311142e5d165SGregory Neil Shapiro 			       (long) mci->mci_mailer->m_wait);
311206f25ae9SGregory Neil Shapiro 			return EX_TEMPFAIL;
311306f25ae9SGregory Neil Shapiro 		}
311406f25ae9SGregory Neil Shapiro 	}
3115c2aa98e2SPeter Wemm 
311606f25ae9SGregory Neil Shapiro 	/* wait for the mailer process, collect status */
3117c2aa98e2SPeter Wemm 	st = waitfor(mci->mci_pid);
311806f25ae9SGregory Neil Shapiro 	save_errno = errno;
311906f25ae9SGregory Neil Shapiro 	if (ev != NULL)
312006f25ae9SGregory Neil Shapiro 		clrevent(ev);
312106f25ae9SGregory Neil Shapiro 	errno = save_errno;
312206f25ae9SGregory Neil Shapiro 
3123c2aa98e2SPeter Wemm 	if (st == -1)
3124c2aa98e2SPeter Wemm 	{
3125c2aa98e2SPeter Wemm 		syserr("endmailer %s: wait", mci->mci_mailer->m_name);
312606f25ae9SGregory Neil Shapiro 		return EX_SOFTWARE;
3127c2aa98e2SPeter Wemm 	}
3128c2aa98e2SPeter Wemm 
3129c2aa98e2SPeter Wemm 	if (WIFEXITED(st))
3130c2aa98e2SPeter Wemm 	{
3131c2aa98e2SPeter Wemm 		/* normal death -- return status */
3132c2aa98e2SPeter Wemm 		return (WEXITSTATUS(st));
3133c2aa98e2SPeter Wemm 	}
3134c2aa98e2SPeter Wemm 
3135c2aa98e2SPeter Wemm 	/* it died a horrid death */
313606f25ae9SGregory Neil Shapiro 	syserr("451 4.3.0 mailer %s died with signal %d%s",
313706f25ae9SGregory Neil Shapiro 		mci->mci_mailer->m_name, WTERMSIG(st),
313806f25ae9SGregory Neil Shapiro 		WCOREDUMP(st) ? " (core dumped)" :
313906f25ae9SGregory Neil Shapiro 		(WIFSTOPPED(st) ? " (stopped)" : ""));
3140c2aa98e2SPeter Wemm 
3141c2aa98e2SPeter Wemm 	/* log the arguments */
3142c2aa98e2SPeter Wemm 	if (pv != NULL && e->e_xfp != NULL)
3143c2aa98e2SPeter Wemm 	{
3144c2aa98e2SPeter Wemm 		register char **av;
3145c2aa98e2SPeter Wemm 
3146c2aa98e2SPeter Wemm 		fprintf(e->e_xfp, "Arguments:");
3147c2aa98e2SPeter Wemm 		for (av = pv; *av != NULL; av++)
3148c2aa98e2SPeter Wemm 			fprintf(e->e_xfp, " %s", *av);
3149c2aa98e2SPeter Wemm 		fprintf(e->e_xfp, "\n");
3150c2aa98e2SPeter Wemm 	}
3151c2aa98e2SPeter Wemm 
3152c2aa98e2SPeter Wemm 	ExitStat = EX_TEMPFAIL;
315306f25ae9SGregory Neil Shapiro 	return EX_TEMPFAIL;
3154c2aa98e2SPeter Wemm }
3155c2aa98e2SPeter Wemm /*
3156c2aa98e2SPeter Wemm **  GIVERESPONSE -- Interpret an error response from a mailer
3157c2aa98e2SPeter Wemm **
3158c2aa98e2SPeter Wemm **	Parameters:
315906f25ae9SGregory Neil Shapiro **		status -- the status code from the mailer (high byte
3160c2aa98e2SPeter Wemm **			only; core dumps must have been taken care of
3161c2aa98e2SPeter Wemm **			already).
316206f25ae9SGregory Neil Shapiro **		dsn -- the DSN associated with the address, if any.
3163c2aa98e2SPeter Wemm **		m -- the mailer info for this mailer.
3164c2aa98e2SPeter Wemm **		mci -- the mailer connection info -- can be NULL if the
3165c2aa98e2SPeter Wemm **			response is given before the connection is made.
3166c2aa98e2SPeter Wemm **		ctladdr -- the controlling address for the recipient
3167c2aa98e2SPeter Wemm **			address(es).
3168c2aa98e2SPeter Wemm **		xstart -- the transaction start time, for computing
3169c2aa98e2SPeter Wemm **			transaction delays.
3170c2aa98e2SPeter Wemm **		e -- the current envelope.
3171c2aa98e2SPeter Wemm **
3172c2aa98e2SPeter Wemm **	Returns:
3173c2aa98e2SPeter Wemm **		none.
3174c2aa98e2SPeter Wemm **
3175c2aa98e2SPeter Wemm **	Side Effects:
3176c2aa98e2SPeter Wemm **		Errors may be incremented.
3177c2aa98e2SPeter Wemm **		ExitStat may be set.
3178c2aa98e2SPeter Wemm */
3179c2aa98e2SPeter Wemm 
3180c2aa98e2SPeter Wemm void
318106f25ae9SGregory Neil Shapiro giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
318206f25ae9SGregory Neil Shapiro 	int status;
318306f25ae9SGregory Neil Shapiro 	char *dsn;
3184c2aa98e2SPeter Wemm 	register MAILER *m;
3185c2aa98e2SPeter Wemm 	register MCI *mci;
3186c2aa98e2SPeter Wemm 	ADDRESS *ctladdr;
3187c2aa98e2SPeter Wemm 	time_t xstart;
3188c2aa98e2SPeter Wemm 	ENVELOPE *e;
3189c2aa98e2SPeter Wemm {
3190c2aa98e2SPeter Wemm 	register const char *statmsg;
3191c2aa98e2SPeter Wemm 	extern char *SysExMsg[];
3192c2aa98e2SPeter Wemm 	register int i;
319306f25ae9SGregory Neil Shapiro 	int errnum = errno;
319406f25ae9SGregory Neil Shapiro 	int off = 4;
3195c2aa98e2SPeter Wemm 	extern int N_SysEx;
319606f25ae9SGregory Neil Shapiro 	char dsnbuf[ENHSCLEN];
3197c2aa98e2SPeter Wemm 	char buf[MAXLINE];
3198c2aa98e2SPeter Wemm 
3199c2aa98e2SPeter Wemm 	if (e == NULL)
3200c2aa98e2SPeter Wemm 		syserr("giveresponse: null envelope");
3201c2aa98e2SPeter Wemm 
3202c2aa98e2SPeter Wemm 	/*
3203c2aa98e2SPeter Wemm 	**  Compute status message from code.
3204c2aa98e2SPeter Wemm 	*/
3205c2aa98e2SPeter Wemm 
320606f25ae9SGregory Neil Shapiro 	i = status - EX__BASE;
320706f25ae9SGregory Neil Shapiro 	if (status == 0)
3208c2aa98e2SPeter Wemm 	{
320906f25ae9SGregory Neil Shapiro 		statmsg = "250 2.0.0 Sent";
3210c2aa98e2SPeter Wemm 		if (e->e_statmsg != NULL)
3211c2aa98e2SPeter Wemm 		{
3212c2aa98e2SPeter Wemm 			(void) snprintf(buf, sizeof buf, "%s (%s)",
321306f25ae9SGregory Neil Shapiro 					statmsg,
321406f25ae9SGregory Neil Shapiro 					shortenstring(e->e_statmsg, 403));
3215c2aa98e2SPeter Wemm 			statmsg = buf;
3216c2aa98e2SPeter Wemm 		}
3217c2aa98e2SPeter Wemm 	}
3218c2aa98e2SPeter Wemm 	else if (i < 0 || i >= N_SysEx)
3219c2aa98e2SPeter Wemm 	{
322006f25ae9SGregory Neil Shapiro 		(void) snprintf(buf, sizeof buf,
322106f25ae9SGregory Neil Shapiro 				"554 5.3.0 unknown mailer error %d",
322206f25ae9SGregory Neil Shapiro 				status);
322306f25ae9SGregory Neil Shapiro 		status = EX_UNAVAILABLE;
3224c2aa98e2SPeter Wemm 		statmsg = buf;
3225c2aa98e2SPeter Wemm 	}
322606f25ae9SGregory Neil Shapiro 	else if (status == EX_TEMPFAIL)
3227c2aa98e2SPeter Wemm 	{
3228c2aa98e2SPeter Wemm 		char *bp = buf;
3229c2aa98e2SPeter Wemm 
3230c2aa98e2SPeter Wemm 		snprintf(bp, SPACELEFT(buf, bp), "%s", SysExMsg[i] + 1);
3231c2aa98e2SPeter Wemm 		bp += strlen(bp);
3232c2aa98e2SPeter Wemm #if NAMED_BIND
3233c2aa98e2SPeter Wemm 		if (h_errno == TRY_AGAIN)
3234c2aa98e2SPeter Wemm 			statmsg = errstring(h_errno+E_DNSBASE);
3235c2aa98e2SPeter Wemm 		else
323606f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
3237c2aa98e2SPeter Wemm 		{
323806f25ae9SGregory Neil Shapiro 			if (errnum != 0)
323906f25ae9SGregory Neil Shapiro 				statmsg = errstring(errnum);
3240c2aa98e2SPeter Wemm 			else
3241c2aa98e2SPeter Wemm 			{
3242c2aa98e2SPeter Wemm #if SMTP
3243c2aa98e2SPeter Wemm 				statmsg = SmtpError;
3244c2aa98e2SPeter Wemm #else /* SMTP */
3245c2aa98e2SPeter Wemm 				statmsg = NULL;
3246c2aa98e2SPeter Wemm #endif /* SMTP */
3247c2aa98e2SPeter Wemm 			}
3248c2aa98e2SPeter Wemm 		}
3249c2aa98e2SPeter Wemm 		if (statmsg != NULL && statmsg[0] != '\0')
325006f25ae9SGregory Neil Shapiro 		{
325106f25ae9SGregory Neil Shapiro 			switch (errnum)
325206f25ae9SGregory Neil Shapiro 			{
325306f25ae9SGregory Neil Shapiro #ifdef ENETDOWN
325406f25ae9SGregory Neil Shapiro 			  case ENETDOWN:	/* Network is down */
325506f25ae9SGregory Neil Shapiro #endif /* ENETDOWN */
325606f25ae9SGregory Neil Shapiro #ifdef ENETUNREACH
325706f25ae9SGregory Neil Shapiro 			  case ENETUNREACH:	/* Network is unreachable */
325806f25ae9SGregory Neil Shapiro #endif /* ENETUNREACH */
325906f25ae9SGregory Neil Shapiro #ifdef ENETRESET
326006f25ae9SGregory Neil Shapiro 			  case ENETRESET:	/* Network dropped connection on reset */
326106f25ae9SGregory Neil Shapiro #endif /* ENETRESET */
326206f25ae9SGregory Neil Shapiro #ifdef ECONNABORTED
326306f25ae9SGregory Neil Shapiro 			  case ECONNABORTED:	/* Software caused connection abort */
326406f25ae9SGregory Neil Shapiro #endif /* ECONNABORTED */
326506f25ae9SGregory Neil Shapiro #ifdef EHOSTDOWN
326606f25ae9SGregory Neil Shapiro 			  case EHOSTDOWN:	/* Host is down */
326706f25ae9SGregory Neil Shapiro #endif /* EHOSTDOWN */
326806f25ae9SGregory Neil Shapiro #ifdef EHOSTUNREACH
326906f25ae9SGregory Neil Shapiro 			  case EHOSTUNREACH:	/* No route to host */
327006f25ae9SGregory Neil Shapiro #endif /* EHOSTUNREACH */
327106f25ae9SGregory Neil Shapiro 				if (mci->mci_host != NULL)
327206f25ae9SGregory Neil Shapiro 				{
327306f25ae9SGregory Neil Shapiro 					snprintf(bp, SPACELEFT(buf, bp),
327406f25ae9SGregory Neil Shapiro 						 ": %s", mci->mci_host);
327506f25ae9SGregory Neil Shapiro 					bp += strlen(bp);
327606f25ae9SGregory Neil Shapiro 				}
327706f25ae9SGregory Neil Shapiro 				break;
327806f25ae9SGregory Neil Shapiro 			}
3279c2aa98e2SPeter Wemm 			snprintf(bp, SPACELEFT(buf, bp), ": %s", statmsg);
328006f25ae9SGregory Neil Shapiro 		}
3281c2aa98e2SPeter Wemm 		statmsg = buf;
3282c2aa98e2SPeter Wemm 	}
3283c2aa98e2SPeter Wemm #if NAMED_BIND
328406f25ae9SGregory Neil Shapiro 	else if (status == EX_NOHOST && h_errno != 0)
3285c2aa98e2SPeter Wemm 	{
3286c2aa98e2SPeter Wemm 		statmsg = errstring(h_errno + E_DNSBASE);
3287c2aa98e2SPeter Wemm 		(void) snprintf(buf, sizeof buf, "%s (%s)",
3288c2aa98e2SPeter Wemm 			SysExMsg[i] + 1, statmsg);
3289c2aa98e2SPeter Wemm 		statmsg = buf;
3290c2aa98e2SPeter Wemm 	}
329106f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
3292c2aa98e2SPeter Wemm 	else
3293c2aa98e2SPeter Wemm 	{
3294c2aa98e2SPeter Wemm 		statmsg = SysExMsg[i];
329506f25ae9SGregory Neil Shapiro 		if (*statmsg++ == ':' && errnum != 0)
3296c2aa98e2SPeter Wemm 		{
3297c2aa98e2SPeter Wemm 			(void) snprintf(buf, sizeof buf, "%s: %s",
329806f25ae9SGregory Neil Shapiro 				statmsg, errstring(errnum));
3299c2aa98e2SPeter Wemm 			statmsg = buf;
3300c2aa98e2SPeter Wemm 		}
3301c2aa98e2SPeter Wemm 	}
3302c2aa98e2SPeter Wemm 
3303c2aa98e2SPeter Wemm 	/*
3304c2aa98e2SPeter Wemm 	**  Print the message as appropriate
3305c2aa98e2SPeter Wemm 	*/
3306c2aa98e2SPeter Wemm 
330706f25ae9SGregory Neil Shapiro 	if (status == EX_OK || status == EX_TEMPFAIL)
3308c2aa98e2SPeter Wemm 	{
3309c2aa98e2SPeter Wemm 		extern char MsgBuf[];
3310c2aa98e2SPeter Wemm 
331106f25ae9SGregory Neil Shapiro 		if ((off = isenhsc(statmsg + 4, ' ')) > 0)
331206f25ae9SGregory Neil Shapiro 		{
331306f25ae9SGregory Neil Shapiro 			if (dsn == NULL)
331406f25ae9SGregory Neil Shapiro 			{
331506f25ae9SGregory Neil Shapiro 				snprintf(dsnbuf, sizeof dsnbuf,
331606f25ae9SGregory Neil Shapiro 					 "%.*s", off, statmsg + 4);
331706f25ae9SGregory Neil Shapiro 				dsn = dsnbuf;
331806f25ae9SGregory Neil Shapiro 			}
331906f25ae9SGregory Neil Shapiro 			off += 5;
332006f25ae9SGregory Neil Shapiro 		}
332106f25ae9SGregory Neil Shapiro 		else
332206f25ae9SGregory Neil Shapiro 		{
332306f25ae9SGregory Neil Shapiro 			off = 4;
332406f25ae9SGregory Neil Shapiro 		}
332506f25ae9SGregory Neil Shapiro 		message("%s", statmsg + off);
332606f25ae9SGregory Neil Shapiro 		if (status == EX_TEMPFAIL && e->e_xfp != NULL)
3327c2aa98e2SPeter Wemm 			fprintf(e->e_xfp, "%s\n", &MsgBuf[4]);
3328c2aa98e2SPeter Wemm 	}
3329c2aa98e2SPeter Wemm 	else
3330c2aa98e2SPeter Wemm 	{
333106f25ae9SGregory Neil Shapiro 		char mbuf[ENHSCLEN + 4];
3332c2aa98e2SPeter Wemm 
3333c2aa98e2SPeter Wemm 		Errors++;
333406f25ae9SGregory Neil Shapiro 		if ((off = isenhsc(statmsg + 4, ' ')) > 0 &&
333506f25ae9SGregory Neil Shapiro 		    off < sizeof mbuf - 4)
333606f25ae9SGregory Neil Shapiro 		{
333706f25ae9SGregory Neil Shapiro 			if (dsn == NULL)
333806f25ae9SGregory Neil Shapiro 			{
333906f25ae9SGregory Neil Shapiro 				snprintf(dsnbuf, sizeof dsnbuf,
334006f25ae9SGregory Neil Shapiro 					 "%.*s", off, statmsg + 4);
334106f25ae9SGregory Neil Shapiro 				dsn = dsnbuf;
334206f25ae9SGregory Neil Shapiro 			}
334306f25ae9SGregory Neil Shapiro 			off += 5;
334406f25ae9SGregory Neil Shapiro 			(void) strlcpy(mbuf, statmsg, off);
334506f25ae9SGregory Neil Shapiro 			(void) strlcat(mbuf, " %s", sizeof mbuf);
334606f25ae9SGregory Neil Shapiro 		}
334706f25ae9SGregory Neil Shapiro 		else
334806f25ae9SGregory Neil Shapiro 		{
334906f25ae9SGregory Neil Shapiro 			dsnbuf[0] = '\0';
335006f25ae9SGregory Neil Shapiro 			(void) snprintf(mbuf, sizeof mbuf, "%.3s %%s", statmsg);
335106f25ae9SGregory Neil Shapiro 			off = 4;
335206f25ae9SGregory Neil Shapiro 		}
335306f25ae9SGregory Neil Shapiro 		usrerr(mbuf, &statmsg[off]);
3354c2aa98e2SPeter Wemm 	}
3355c2aa98e2SPeter Wemm 
3356c2aa98e2SPeter Wemm 	/*
3357c2aa98e2SPeter Wemm 	**  Final cleanup.
3358c2aa98e2SPeter Wemm 	**	Log a record of the transaction.  Compute the new
3359c2aa98e2SPeter Wemm 	**	ExitStat -- if we already had an error, stick with
3360c2aa98e2SPeter Wemm 	**	that.
3361c2aa98e2SPeter Wemm 	*/
3362c2aa98e2SPeter Wemm 
3363c2aa98e2SPeter Wemm 	if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) &&
336406f25ae9SGregory Neil Shapiro 	    LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6))
336506f25ae9SGregory Neil Shapiro 		logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e);
3366c2aa98e2SPeter Wemm 
3367c2aa98e2SPeter Wemm 	if (tTd(11, 2))
336806f25ae9SGregory Neil Shapiro 		dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s\n",
336906f25ae9SGregory Neil Shapiro 			status,
337006f25ae9SGregory Neil Shapiro 			dsn == NULL ? "<NULL>" : dsn,
337106f25ae9SGregory Neil Shapiro 			e->e_message == NULL ? "<NULL>" : e->e_message);
3372c2aa98e2SPeter Wemm 
337306f25ae9SGregory Neil Shapiro 	if (status != EX_TEMPFAIL)
337406f25ae9SGregory Neil Shapiro 		setstat(status);
337506f25ae9SGregory Neil Shapiro 	if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL))
3376c2aa98e2SPeter Wemm 	{
3377c2aa98e2SPeter Wemm 		if (e->e_message != NULL)
3378c2aa98e2SPeter Wemm 			free(e->e_message);
337906f25ae9SGregory Neil Shapiro 		e->e_message = newstr(statmsg + off);
3380c2aa98e2SPeter Wemm 	}
3381c2aa98e2SPeter Wemm 	errno = 0;
3382c2aa98e2SPeter Wemm #if NAMED_BIND
3383602a2b1bSGregory Neil Shapiro 	SM_SET_H_ERRNO(0);
338406f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
3385c2aa98e2SPeter Wemm }
3386c2aa98e2SPeter Wemm /*
3387c2aa98e2SPeter Wemm **  LOGDELIVERY -- log the delivery in the system log
3388c2aa98e2SPeter Wemm **
3389c2aa98e2SPeter Wemm **	Care is taken to avoid logging lines that are too long, because
3390c2aa98e2SPeter Wemm **	some versions of syslog have an unfortunate proclivity for core
3391c2aa98e2SPeter Wemm **	dumping.  This is a hack, to be sure, that is at best empirical.
3392c2aa98e2SPeter Wemm **
3393c2aa98e2SPeter Wemm **	Parameters:
3394c2aa98e2SPeter Wemm **		m -- the mailer info.  Can be NULL for initial queue.
3395c2aa98e2SPeter Wemm **		mci -- the mailer connection info -- can be NULL if the
339606f25ae9SGregory Neil Shapiro **			log is occurring when no connection is active.
339706f25ae9SGregory Neil Shapiro **		dsn -- the DSN attached to the status.
339806f25ae9SGregory Neil Shapiro **		status -- the message to print for the status.
3399c2aa98e2SPeter Wemm **		ctladdr -- the controlling address for the to list.
3400c2aa98e2SPeter Wemm **		xstart -- the transaction start time, used for
3401c2aa98e2SPeter Wemm **			computing transaction delay.
3402c2aa98e2SPeter Wemm **		e -- the current envelope.
3403c2aa98e2SPeter Wemm **
3404c2aa98e2SPeter Wemm **	Returns:
3405c2aa98e2SPeter Wemm **		none
3406c2aa98e2SPeter Wemm **
3407c2aa98e2SPeter Wemm **	Side Effects:
3408c2aa98e2SPeter Wemm **		none
3409c2aa98e2SPeter Wemm */
3410c2aa98e2SPeter Wemm 
3411c2aa98e2SPeter Wemm void
341206f25ae9SGregory Neil Shapiro logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
3413c2aa98e2SPeter Wemm 	MAILER *m;
3414c2aa98e2SPeter Wemm 	register MCI *mci;
341506f25ae9SGregory Neil Shapiro 	char *dsn;
341606f25ae9SGregory Neil Shapiro 	const char *status;
3417c2aa98e2SPeter Wemm 	ADDRESS *ctladdr;
3418c2aa98e2SPeter Wemm 	time_t xstart;
3419c2aa98e2SPeter Wemm 	register ENVELOPE *e;
3420c2aa98e2SPeter Wemm {
3421c2aa98e2SPeter Wemm 	register char *bp;
3422c2aa98e2SPeter Wemm 	register char *p;
3423c2aa98e2SPeter Wemm 	int l;
3424193538b7SGregory Neil Shapiro 	time_t now;
3425c2aa98e2SPeter Wemm 	char buf[1024];
3426c2aa98e2SPeter Wemm 
3427c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
3428c2aa98e2SPeter Wemm 	/* ctladdr: max 106 bytes */
3429c2aa98e2SPeter Wemm 	bp = buf;
3430c2aa98e2SPeter Wemm 	if (ctladdr != NULL)
3431c2aa98e2SPeter Wemm 	{
3432c2aa98e2SPeter Wemm 		snprintf(bp, SPACELEFT(buf, bp), ", ctladdr=%s",
3433c2aa98e2SPeter Wemm 			 shortenstring(ctladdr->q_paddr, 83));
3434c2aa98e2SPeter Wemm 		bp += strlen(bp);
3435c2aa98e2SPeter Wemm 		if (bitset(QGOODUID, ctladdr->q_flags))
3436c2aa98e2SPeter Wemm 		{
3437c2aa98e2SPeter Wemm 			(void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
343806f25ae9SGregory Neil Shapiro 					(int) ctladdr->q_uid,
343906f25ae9SGregory Neil Shapiro 					(int) ctladdr->q_gid);
3440c2aa98e2SPeter Wemm 			bp += strlen(bp);
3441c2aa98e2SPeter Wemm 		}
3442c2aa98e2SPeter Wemm 	}
3443c2aa98e2SPeter Wemm 
3444c2aa98e2SPeter Wemm 	/* delay & xdelay: max 41 bytes */
3445193538b7SGregory Neil Shapiro 	now = curtime();
3446c2aa98e2SPeter Wemm 	snprintf(bp, SPACELEFT(buf, bp), ", delay=%s",
3447193538b7SGregory Neil Shapiro 		 pintvl(now - e->e_ctime, TRUE));
3448c2aa98e2SPeter Wemm 	bp += strlen(bp);
3449c2aa98e2SPeter Wemm 
3450c2aa98e2SPeter Wemm 	if (xstart != (time_t) 0)
3451c2aa98e2SPeter Wemm 	{
3452c2aa98e2SPeter Wemm 		snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s",
3453193538b7SGregory Neil Shapiro 			 pintvl(now - xstart, TRUE));
3454c2aa98e2SPeter Wemm 		bp += strlen(bp);
3455c2aa98e2SPeter Wemm 	}
3456c2aa98e2SPeter Wemm 
3457c2aa98e2SPeter Wemm 	/* mailer: assume about 19 bytes (max 10 byte mailer name) */
3458c2aa98e2SPeter Wemm 	if (m != NULL)
3459c2aa98e2SPeter Wemm 	{
3460c2aa98e2SPeter Wemm 		snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name);
3461c2aa98e2SPeter Wemm 		bp += strlen(bp);
3462c2aa98e2SPeter Wemm 	}
3463c2aa98e2SPeter Wemm 
346406f25ae9SGregory Neil Shapiro 	/* pri: changes with each delivery attempt */
346506f25ae9SGregory Neil Shapiro 	snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", e->e_msgpriority);
346606f25ae9SGregory Neil Shapiro 	bp += strlen(bp);
346706f25ae9SGregory Neil Shapiro 
3468c2aa98e2SPeter Wemm 	/* relay: max 66 bytes for IPv4 addresses */
3469c2aa98e2SPeter Wemm 	if (mci != NULL && mci->mci_host != NULL)
3470c2aa98e2SPeter Wemm 	{
3471c2aa98e2SPeter Wemm # if DAEMON
3472c2aa98e2SPeter Wemm 		extern SOCKADDR CurHostAddr;
347306f25ae9SGregory Neil Shapiro # endif /* DAEMON */
3474c2aa98e2SPeter Wemm 
3475c2aa98e2SPeter Wemm 		snprintf(bp, SPACELEFT(buf, bp), ", relay=%s",
3476c2aa98e2SPeter Wemm 			 shortenstring(mci->mci_host, 40));
3477c2aa98e2SPeter Wemm 		bp += strlen(bp);
3478c2aa98e2SPeter Wemm 
3479c2aa98e2SPeter Wemm # if DAEMON
3480c2aa98e2SPeter Wemm 		if (CurHostAddr.sa.sa_family != 0)
3481c2aa98e2SPeter Wemm 		{
3482c2aa98e2SPeter Wemm 			snprintf(bp, SPACELEFT(buf, bp), " [%s]",
3483c2aa98e2SPeter Wemm 				 anynet_ntoa(&CurHostAddr));
3484c2aa98e2SPeter Wemm 		}
348506f25ae9SGregory Neil Shapiro # endif /* DAEMON */
3486c2aa98e2SPeter Wemm 	}
348706f25ae9SGregory Neil Shapiro 	else if (strcmp(status, "queued") != 0)
3488c2aa98e2SPeter Wemm 	{
3489c2aa98e2SPeter Wemm 		p = macvalue('h', e);
3490c2aa98e2SPeter Wemm 		if (p != NULL && p[0] != '\0')
3491c2aa98e2SPeter Wemm 		{
3492c2aa98e2SPeter Wemm 			snprintf(bp, SPACELEFT(buf, bp), ", relay=%s",
3493c2aa98e2SPeter Wemm 				 shortenstring(p, 40));
3494c2aa98e2SPeter Wemm 		}
3495c2aa98e2SPeter Wemm 	}
3496c2aa98e2SPeter Wemm 	bp += strlen(bp);
3497c2aa98e2SPeter Wemm 
349806f25ae9SGregory Neil Shapiro 	/* dsn */
349906f25ae9SGregory Neil Shapiro 	if (dsn != NULL && *dsn != '\0')
350006f25ae9SGregory Neil Shapiro 	{
350106f25ae9SGregory Neil Shapiro 		snprintf(bp, SPACELEFT(buf, bp), ", dsn=%s",
350206f25ae9SGregory Neil Shapiro 			 shortenstring(dsn, ENHSCLEN));
350306f25ae9SGregory Neil Shapiro 		bp += strlen(bp);
350406f25ae9SGregory Neil Shapiro 	}
350506f25ae9SGregory Neil Shapiro 
3506c2aa98e2SPeter Wemm # define STATLEN		(((SYSLOG_BUFSIZE) - 100) / 4)
3507c2aa98e2SPeter Wemm # if (STATLEN) < 63
3508c2aa98e2SPeter Wemm #  undef STATLEN
3509c2aa98e2SPeter Wemm #  define STATLEN	63
351006f25ae9SGregory Neil Shapiro # endif /* (STATLEN) < 63 */
3511c2aa98e2SPeter Wemm # if (STATLEN) > 203
3512c2aa98e2SPeter Wemm #  undef STATLEN
3513c2aa98e2SPeter Wemm #  define STATLEN	203
351406f25ae9SGregory Neil Shapiro # endif /* (STATLEN) > 203 */
3515c2aa98e2SPeter Wemm 
3516c2aa98e2SPeter Wemm 	/* stat: max 210 bytes */
3517c2aa98e2SPeter Wemm 	if ((bp - buf) > (sizeof buf - ((STATLEN) + 20)))
3518c2aa98e2SPeter Wemm 	{
3519c2aa98e2SPeter Wemm 		/* desperation move -- truncate data */
3520c2aa98e2SPeter Wemm 		bp = buf + sizeof buf - ((STATLEN) + 17);
352106f25ae9SGregory Neil Shapiro 		(void) strlcpy(bp, "...", SPACELEFT(buf, bp));
3522c2aa98e2SPeter Wemm 		bp += 3;
3523c2aa98e2SPeter Wemm 	}
3524c2aa98e2SPeter Wemm 
352506f25ae9SGregory Neil Shapiro 	(void) strlcpy(bp, ", stat=", SPACELEFT(buf, bp));
3526c2aa98e2SPeter Wemm 	bp += strlen(bp);
3527c2aa98e2SPeter Wemm 
352806f25ae9SGregory Neil Shapiro 	(void) strlcpy(bp, shortenstring(status, STATLEN), SPACELEFT(buf, bp));
3529c2aa98e2SPeter Wemm 
3530c2aa98e2SPeter Wemm 	/* id, to: max 13 + TOBUFSIZE bytes */
3531c2aa98e2SPeter Wemm 	l = SYSLOG_BUFSIZE - 100 - strlen(buf);
353206f25ae9SGregory Neil Shapiro 	p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
3533c2aa98e2SPeter Wemm 	while (strlen(p) >= (SIZE_T) l)
3534c2aa98e2SPeter Wemm 	{
353506f25ae9SGregory Neil Shapiro 		register char *q;
3536c2aa98e2SPeter Wemm 
353706f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
353806f25ae9SGregory Neil Shapiro 		for (q = p + l; q > p; q--)
353906f25ae9SGregory Neil Shapiro 		{
354006f25ae9SGregory Neil Shapiro 			if (*q == ',')
354106f25ae9SGregory Neil Shapiro 				break;
354206f25ae9SGregory Neil Shapiro 		}
354306f25ae9SGregory Neil Shapiro 		if (p == q)
354406f25ae9SGregory Neil Shapiro 			break;
354506f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
354606f25ae9SGregory Neil Shapiro 		q = strchr(p + l, ',');
3547c2aa98e2SPeter Wemm 		if (q == NULL)
3548c2aa98e2SPeter Wemm 			break;
354906f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
355006f25ae9SGregory Neil Shapiro 
3551c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
3552c2aa98e2SPeter Wemm 			  "to=%.*s [more]%s",
355342e5d165SGregory Neil Shapiro 			  (int) (++q - p), p, buf);
3554c2aa98e2SPeter Wemm 		p = q;
3555c2aa98e2SPeter Wemm 	}
355606f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
355706f25ae9SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf);
355806f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
3559c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id, "to=%s%s", p, buf);
356006f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
3561c2aa98e2SPeter Wemm 
356206f25ae9SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
3563c2aa98e2SPeter Wemm 
3564c2aa98e2SPeter Wemm 	l = SYSLOG_BUFSIZE - 85;
356506f25ae9SGregory Neil Shapiro 	p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
3566c2aa98e2SPeter Wemm 	while (strlen(p) >= (SIZE_T) l)
3567c2aa98e2SPeter Wemm 	{
356806f25ae9SGregory Neil Shapiro 		register char *q;
3569c2aa98e2SPeter Wemm 
357006f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
357106f25ae9SGregory Neil Shapiro 		for (q = p + l; q > p; q--)
357206f25ae9SGregory Neil Shapiro 		{
357306f25ae9SGregory Neil Shapiro 			if (*q == ',')
357406f25ae9SGregory Neil Shapiro 				break;
357506f25ae9SGregory Neil Shapiro 		}
357606f25ae9SGregory Neil Shapiro 		if (p == q)
357706f25ae9SGregory Neil Shapiro 			break;
357806f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
357906f25ae9SGregory Neil Shapiro 		q = strchr(p + l, ',');
3580c2aa98e2SPeter Wemm 		if (q == NULL)
3581c2aa98e2SPeter Wemm 			break;
358206f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
358306f25ae9SGregory Neil Shapiro 
3584c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
3585c2aa98e2SPeter Wemm 			  "to=%.*s [more]",
358642e5d165SGregory Neil Shapiro 			  (int) (++q - p), p);
3587c2aa98e2SPeter Wemm 		p = q;
3588c2aa98e2SPeter Wemm 	}
358906f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF
359006f25ae9SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p);
359106f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */
3592c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id, "to=%s", p);
359306f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */
3594c2aa98e2SPeter Wemm 
3595c2aa98e2SPeter Wemm 	if (ctladdr != NULL)
3596c2aa98e2SPeter Wemm 	{
3597c2aa98e2SPeter Wemm 		bp = buf;
3598c2aa98e2SPeter Wemm 		snprintf(bp, SPACELEFT(buf, bp), "ctladdr=%s",
3599c2aa98e2SPeter Wemm 			 shortenstring(ctladdr->q_paddr, 83));
3600c2aa98e2SPeter Wemm 		bp += strlen(bp);
3601c2aa98e2SPeter Wemm 		if (bitset(QGOODUID, ctladdr->q_flags))
3602c2aa98e2SPeter Wemm 		{
3603c2aa98e2SPeter Wemm 			(void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
3604c2aa98e2SPeter Wemm 					ctladdr->q_uid, ctladdr->q_gid);
3605c2aa98e2SPeter Wemm 			bp += strlen(bp);
3606c2aa98e2SPeter Wemm 		}
3607c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id, "%s", buf);
3608c2aa98e2SPeter Wemm 	}
3609c2aa98e2SPeter Wemm 	bp = buf;
3610c2aa98e2SPeter Wemm 	snprintf(bp, SPACELEFT(buf, bp), "delay=%s",
3611193538b7SGregory Neil Shapiro 		 pintvl(now - e->e_ctime, TRUE));
3612c2aa98e2SPeter Wemm 	bp += strlen(bp);
3613c2aa98e2SPeter Wemm 	if (xstart != (time_t) 0)
3614c2aa98e2SPeter Wemm 	{
3615c2aa98e2SPeter Wemm 		snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s",
3616193538b7SGregory Neil Shapiro 			 pintvl(now - xstart, TRUE));
3617c2aa98e2SPeter Wemm 		bp += strlen(bp);
3618c2aa98e2SPeter Wemm 	}
3619c2aa98e2SPeter Wemm 
3620c2aa98e2SPeter Wemm 	if (m != NULL)
3621c2aa98e2SPeter Wemm 	{
3622c2aa98e2SPeter Wemm 		snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name);
3623c2aa98e2SPeter Wemm 		bp += strlen(bp);
3624c2aa98e2SPeter Wemm 	}
3625c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
3626c2aa98e2SPeter Wemm 
3627c2aa98e2SPeter Wemm 	buf[0] = '\0';
3628c2aa98e2SPeter Wemm 	bp = buf;
3629c2aa98e2SPeter Wemm 	if (mci != NULL && mci->mci_host != NULL)
3630c2aa98e2SPeter Wemm 	{
3631c2aa98e2SPeter Wemm # if DAEMON
3632c2aa98e2SPeter Wemm 		extern SOCKADDR CurHostAddr;
363306f25ae9SGregory Neil Shapiro # endif /* DAEMON */
3634c2aa98e2SPeter Wemm 
3635c2aa98e2SPeter Wemm 		snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", mci->mci_host);
3636c2aa98e2SPeter Wemm 		bp += strlen(bp);
3637c2aa98e2SPeter Wemm 
3638c2aa98e2SPeter Wemm # if DAEMON
3639c2aa98e2SPeter Wemm 		if (CurHostAddr.sa.sa_family != 0)
3640c2aa98e2SPeter Wemm 			snprintf(bp, SPACELEFT(buf, bp), " [%.100s]",
3641c2aa98e2SPeter Wemm 				anynet_ntoa(&CurHostAddr));
364206f25ae9SGregory Neil Shapiro # endif /* DAEMON */
3643c2aa98e2SPeter Wemm 	}
364406f25ae9SGregory Neil Shapiro 	else if (strcmp(status, "queued") != 0)
3645c2aa98e2SPeter Wemm 	{
3646c2aa98e2SPeter Wemm 		p = macvalue('h', e);
3647c2aa98e2SPeter Wemm 		if (p != NULL && p[0] != '\0')
3648c2aa98e2SPeter Wemm 			snprintf(buf, sizeof buf, "relay=%.100s", p);
3649c2aa98e2SPeter Wemm 	}
3650c2aa98e2SPeter Wemm 	if (buf[0] != '\0')
3651c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
3652c2aa98e2SPeter Wemm 
365306f25ae9SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63));
365406f25ae9SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
3655c2aa98e2SPeter Wemm }
3656c2aa98e2SPeter Wemm /*
3657c2aa98e2SPeter Wemm **  PUTFROMLINE -- output a UNIX-style from line (or whatever)
3658c2aa98e2SPeter Wemm **
3659c2aa98e2SPeter Wemm **	This can be made an arbitrary message separator by changing $l
3660c2aa98e2SPeter Wemm **
3661c2aa98e2SPeter Wemm **	One of the ugliest hacks seen by human eyes is contained herein:
3662c2aa98e2SPeter Wemm **	UUCP wants those stupid "remote from <host>" lines.  Why oh why
3663c2aa98e2SPeter Wemm **	does a well-meaning programmer such as myself have to deal with
3664c2aa98e2SPeter Wemm **	this kind of antique garbage????
3665c2aa98e2SPeter Wemm **
3666c2aa98e2SPeter Wemm **	Parameters:
3667c2aa98e2SPeter Wemm **		mci -- the connection information.
3668c2aa98e2SPeter Wemm **		e -- the envelope.
3669c2aa98e2SPeter Wemm **
3670c2aa98e2SPeter Wemm **	Returns:
3671c2aa98e2SPeter Wemm **		none
3672c2aa98e2SPeter Wemm **
3673c2aa98e2SPeter Wemm **	Side Effects:
3674c2aa98e2SPeter Wemm **		outputs some text to fp.
3675c2aa98e2SPeter Wemm */
3676c2aa98e2SPeter Wemm 
3677c2aa98e2SPeter Wemm void
3678c2aa98e2SPeter Wemm putfromline(mci, e)
3679c2aa98e2SPeter Wemm 	register MCI *mci;
3680c2aa98e2SPeter Wemm 	ENVELOPE *e;
3681c2aa98e2SPeter Wemm {
3682c2aa98e2SPeter Wemm 	char *template = UnixFromLine;
3683c2aa98e2SPeter Wemm 	char buf[MAXLINE];
3684c2aa98e2SPeter Wemm 	char xbuf[MAXLINE];
3685c2aa98e2SPeter Wemm 
3686c2aa98e2SPeter Wemm 	if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
3687c2aa98e2SPeter Wemm 		return;
3688c2aa98e2SPeter Wemm 
3689c2aa98e2SPeter Wemm 	mci->mci_flags |= MCIF_INHEADER;
3690c2aa98e2SPeter Wemm 
3691c2aa98e2SPeter Wemm 	if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags))
3692c2aa98e2SPeter Wemm 	{
3693c2aa98e2SPeter Wemm 		char *bang;
3694c2aa98e2SPeter Wemm 
3695c2aa98e2SPeter Wemm 		expand("\201g", buf, sizeof buf, e);
3696c2aa98e2SPeter Wemm 		bang = strchr(buf, '!');
3697c2aa98e2SPeter Wemm 		if (bang == NULL)
3698c2aa98e2SPeter Wemm 		{
3699c2aa98e2SPeter Wemm 			char *at;
3700c2aa98e2SPeter Wemm 			char hname[MAXNAME];
3701c2aa98e2SPeter Wemm 
3702c2aa98e2SPeter Wemm 			/*
3703c2aa98e2SPeter Wemm 			**  If we can construct a UUCP path, do so
3704c2aa98e2SPeter Wemm 			*/
3705c2aa98e2SPeter Wemm 
3706c2aa98e2SPeter Wemm 			at = strrchr(buf, '@');
3707c2aa98e2SPeter Wemm 			if (at == NULL)
3708c2aa98e2SPeter Wemm 			{
3709c2aa98e2SPeter Wemm 				expand("\201k", hname, sizeof hname, e);
3710c2aa98e2SPeter Wemm 				at = hname;
3711c2aa98e2SPeter Wemm 			}
3712c2aa98e2SPeter Wemm 			else
3713c2aa98e2SPeter Wemm 				*at++ = '\0';
3714c2aa98e2SPeter Wemm 			(void) snprintf(xbuf, sizeof xbuf,
3715c2aa98e2SPeter Wemm 				"From %.800s  \201d remote from %.100s\n",
3716c2aa98e2SPeter Wemm 				buf, at);
3717c2aa98e2SPeter Wemm 		}
3718c2aa98e2SPeter Wemm 		else
3719c2aa98e2SPeter Wemm 		{
3720c2aa98e2SPeter Wemm 			*bang++ = '\0';
3721c2aa98e2SPeter Wemm 			(void) snprintf(xbuf, sizeof xbuf,
3722c2aa98e2SPeter Wemm 				"From %.800s  \201d remote from %.100s\n",
3723c2aa98e2SPeter Wemm 				bang, buf);
3724c2aa98e2SPeter Wemm 			template = xbuf;
3725c2aa98e2SPeter Wemm 		}
3726c2aa98e2SPeter Wemm 	}
3727c2aa98e2SPeter Wemm 	expand(template, buf, sizeof buf, e);
3728c2aa98e2SPeter Wemm 	putxline(buf, strlen(buf), mci, PXLF_HEADER);
3729c2aa98e2SPeter Wemm }
3730c2aa98e2SPeter Wemm /*
3731c2aa98e2SPeter Wemm **  PUTBODY -- put the body of a message.
3732c2aa98e2SPeter Wemm **
3733c2aa98e2SPeter Wemm **	Parameters:
3734c2aa98e2SPeter Wemm **		mci -- the connection information.
3735c2aa98e2SPeter Wemm **		e -- the envelope to put out.
3736c2aa98e2SPeter Wemm **		separator -- if non-NULL, a message separator that must
3737c2aa98e2SPeter Wemm **			not be permitted in the resulting message.
3738c2aa98e2SPeter Wemm **
3739c2aa98e2SPeter Wemm **	Returns:
3740c2aa98e2SPeter Wemm **		none.
3741c2aa98e2SPeter Wemm **
3742c2aa98e2SPeter Wemm **	Side Effects:
3743c2aa98e2SPeter Wemm **		The message is written onto fp.
3744c2aa98e2SPeter Wemm */
3745c2aa98e2SPeter Wemm 
3746c2aa98e2SPeter Wemm /* values for output state variable */
3747c2aa98e2SPeter Wemm #define OS_HEAD		0	/* at beginning of line */
3748c2aa98e2SPeter Wemm #define OS_CR		1	/* read a carriage return */
3749c2aa98e2SPeter Wemm #define OS_INLINE	2	/* putting rest of line */
3750c2aa98e2SPeter Wemm 
3751c2aa98e2SPeter Wemm void
3752c2aa98e2SPeter Wemm putbody(mci, e, separator)
3753c2aa98e2SPeter Wemm 	register MCI *mci;
3754c2aa98e2SPeter Wemm 	register ENVELOPE *e;
3755c2aa98e2SPeter Wemm 	char *separator;
3756c2aa98e2SPeter Wemm {
375706f25ae9SGregory Neil Shapiro 	bool dead = FALSE;
3758c2aa98e2SPeter Wemm 	char buf[MAXLINE];
3759065a643dSPeter Wemm 	char *boundaries[MAXMIMENESTING + 1];
3760c2aa98e2SPeter Wemm 
3761c2aa98e2SPeter Wemm 	/*
3762c2aa98e2SPeter Wemm 	**  Output the body of the message
3763c2aa98e2SPeter Wemm 	*/
3764c2aa98e2SPeter Wemm 
3765c2aa98e2SPeter Wemm 	if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
3766c2aa98e2SPeter Wemm 	{
3767c2aa98e2SPeter Wemm 		char *df = queuename(e, 'd');
3768c2aa98e2SPeter Wemm 
3769c2aa98e2SPeter Wemm 		e->e_dfp = fopen(df, "r");
3770c2aa98e2SPeter Wemm 		if (e->e_dfp == NULL)
377106f25ae9SGregory Neil Shapiro 		{
377206f25ae9SGregory Neil Shapiro 			char *msg = "!putbody: Cannot open %s for %s from %s";
377306f25ae9SGregory Neil Shapiro 
377406f25ae9SGregory Neil Shapiro 			if (errno == ENOENT)
377506f25ae9SGregory Neil Shapiro 				msg++;
377606f25ae9SGregory Neil Shapiro 			syserr(msg, df, e->e_to, e->e_from.q_paddr);
377706f25ae9SGregory Neil Shapiro 		}
3778c2aa98e2SPeter Wemm 	}
3779c2aa98e2SPeter Wemm 	if (e->e_dfp == NULL)
3780c2aa98e2SPeter Wemm 	{
3781c2aa98e2SPeter Wemm 		if (bitset(MCIF_INHEADER, mci->mci_flags))
3782c2aa98e2SPeter Wemm 		{
3783c2aa98e2SPeter Wemm 			putline("", mci);
3784c2aa98e2SPeter Wemm 			mci->mci_flags &= ~MCIF_INHEADER;
3785c2aa98e2SPeter Wemm 		}
3786c2aa98e2SPeter Wemm 		putline("<<< No Message Collected >>>", mci);
3787c2aa98e2SPeter Wemm 		goto endofmessage;
3788c2aa98e2SPeter Wemm 	}
378906f25ae9SGregory Neil Shapiro 
3790c2aa98e2SPeter Wemm 	if (e->e_dfino == (ino_t) 0)
3791c2aa98e2SPeter Wemm 	{
3792c2aa98e2SPeter Wemm 		struct stat stbuf;
3793c2aa98e2SPeter Wemm 
3794c2aa98e2SPeter Wemm 		if (fstat(fileno(e->e_dfp), &stbuf) < 0)
3795c2aa98e2SPeter Wemm 			e->e_dfino = -1;
3796c2aa98e2SPeter Wemm 		else
3797c2aa98e2SPeter Wemm 		{
3798c2aa98e2SPeter Wemm 			e->e_dfdev = stbuf.st_dev;
3799c2aa98e2SPeter Wemm 			e->e_dfino = stbuf.st_ino;
3800c2aa98e2SPeter Wemm 		}
3801c2aa98e2SPeter Wemm 	}
380206f25ae9SGregory Neil Shapiro 
380306f25ae9SGregory Neil Shapiro 	/* paranoia: the df file should always be in a rewound state */
380406f25ae9SGregory Neil Shapiro 	(void) bfrewind(e->e_dfp);
3805c2aa98e2SPeter Wemm 
3806c2aa98e2SPeter Wemm #if MIME8TO7
3807c2aa98e2SPeter Wemm 	if (bitset(MCIF_CVT8TO7, mci->mci_flags))
3808c2aa98e2SPeter Wemm 	{
3809c2aa98e2SPeter Wemm 		/*
3810c2aa98e2SPeter Wemm 		**  Do 8 to 7 bit MIME conversion.
3811c2aa98e2SPeter Wemm 		*/
3812c2aa98e2SPeter Wemm 
3813c2aa98e2SPeter Wemm 		/* make sure it looks like a MIME message */
3814c2aa98e2SPeter Wemm 		if (hvalue("MIME-Version", e->e_header) == NULL)
3815c2aa98e2SPeter Wemm 			putline("MIME-Version: 1.0", mci);
3816c2aa98e2SPeter Wemm 
3817c2aa98e2SPeter Wemm 		if (hvalue("Content-Type", e->e_header) == NULL)
3818c2aa98e2SPeter Wemm 		{
3819c2aa98e2SPeter Wemm 			snprintf(buf, sizeof buf,
3820c2aa98e2SPeter Wemm 				"Content-Type: text/plain; charset=%s",
3821c2aa98e2SPeter Wemm 				defcharset(e));
3822c2aa98e2SPeter Wemm 			putline(buf, mci);
3823c2aa98e2SPeter Wemm 		}
3824c2aa98e2SPeter Wemm 
3825c2aa98e2SPeter Wemm 		/* now do the hard work */
3826c2aa98e2SPeter Wemm 		boundaries[0] = NULL;
3827c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
382806f25ae9SGregory Neil Shapiro 		(void) mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER);
3829c2aa98e2SPeter Wemm 	}
3830c2aa98e2SPeter Wemm # if MIME7TO8
3831c2aa98e2SPeter Wemm 	else if (bitset(MCIF_CVT7TO8, mci->mci_flags))
3832c2aa98e2SPeter Wemm 	{
383306f25ae9SGregory Neil Shapiro 		(void) mime7to8(mci, e->e_header, e);
3834c2aa98e2SPeter Wemm 	}
383506f25ae9SGregory Neil Shapiro # endif /* MIME7TO8 */
3836065a643dSPeter Wemm 	else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0)
3837065a643dSPeter Wemm 	{
383806f25ae9SGregory Neil Shapiro 		bool oldsuprerrs = SuprErrs;
383906f25ae9SGregory Neil Shapiro 
3840065a643dSPeter Wemm 		/* Use mime8to7 to check multipart for MIME header overflows */
3841065a643dSPeter Wemm 		boundaries[0] = NULL;
3842065a643dSPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
384306f25ae9SGregory Neil Shapiro 
384406f25ae9SGregory Neil Shapiro 		/*
384506f25ae9SGregory Neil Shapiro 		**  If EF_DONT_MIME is set, we have a broken MIME message
384606f25ae9SGregory Neil Shapiro 		**  and don't want to generate a new bounce message whose
384706f25ae9SGregory Neil Shapiro 		**  body propagates the broken MIME.  We can't just not call
384806f25ae9SGregory Neil Shapiro 		**  mime8to7() as is done above since we need the security
384906f25ae9SGregory Neil Shapiro 		**  checks.  The best we can do is suppress the errors.
385006f25ae9SGregory Neil Shapiro 		*/
385106f25ae9SGregory Neil Shapiro 
385206f25ae9SGregory Neil Shapiro 		if (bitset(EF_DONT_MIME, e->e_flags))
385306f25ae9SGregory Neil Shapiro 			SuprErrs = TRUE;
385406f25ae9SGregory Neil Shapiro 
385506f25ae9SGregory Neil Shapiro 		(void) mime8to7(mci, e->e_header, e, boundaries,
385606f25ae9SGregory Neil Shapiro 				M87F_OUTER|M87F_NO8TO7);
385706f25ae9SGregory Neil Shapiro 
385806f25ae9SGregory Neil Shapiro 		/* restore SuprErrs */
385906f25ae9SGregory Neil Shapiro 		SuprErrs = oldsuprerrs;
3860065a643dSPeter Wemm 	}
3861c2aa98e2SPeter Wemm 	else
386206f25ae9SGregory Neil Shapiro #endif /* MIME8TO7 */
3863c2aa98e2SPeter Wemm 	{
3864c2aa98e2SPeter Wemm 		int ostate;
3865c2aa98e2SPeter Wemm 		register char *bp;
3866c2aa98e2SPeter Wemm 		register char *pbp;
3867c2aa98e2SPeter Wemm 		register int c;
3868c2aa98e2SPeter Wemm 		register char *xp;
3869c2aa98e2SPeter Wemm 		int padc;
3870c2aa98e2SPeter Wemm 		char *buflim;
3871c2aa98e2SPeter Wemm 		int pos = 0;
387206f25ae9SGregory Neil Shapiro 		char peekbuf[12];
3873c2aa98e2SPeter Wemm 
3874c2aa98e2SPeter Wemm 		if (bitset(MCIF_INHEADER, mci->mci_flags))
3875c2aa98e2SPeter Wemm 		{
3876c2aa98e2SPeter Wemm 			putline("", mci);
3877c2aa98e2SPeter Wemm 			mci->mci_flags &= ~MCIF_INHEADER;
3878c2aa98e2SPeter Wemm 		}
3879c2aa98e2SPeter Wemm 
3880c2aa98e2SPeter Wemm 		/* determine end of buffer; allow for short mailer lines */
3881c2aa98e2SPeter Wemm 		buflim = &buf[sizeof buf - 1];
3882c2aa98e2SPeter Wemm 		if (mci->mci_mailer->m_linelimit > 0 &&
3883c2aa98e2SPeter Wemm 		    mci->mci_mailer->m_linelimit < sizeof buf - 1)
3884c2aa98e2SPeter Wemm 			buflim = &buf[mci->mci_mailer->m_linelimit - 1];
3885c2aa98e2SPeter Wemm 
3886c2aa98e2SPeter Wemm 		/* copy temp file to output with mapping */
3887c2aa98e2SPeter Wemm 		ostate = OS_HEAD;
3888c2aa98e2SPeter Wemm 		bp = buf;
3889c2aa98e2SPeter Wemm 		pbp = peekbuf;
389006f25ae9SGregory Neil Shapiro 		while (!ferror(mci->mci_out) && !dead)
3891c2aa98e2SPeter Wemm 		{
3892c2aa98e2SPeter Wemm 			if (pbp > peekbuf)
3893c2aa98e2SPeter Wemm 				c = *--pbp;
3894c2aa98e2SPeter Wemm 			else if ((c = getc(e->e_dfp)) == EOF)
3895c2aa98e2SPeter Wemm 				break;
3896c2aa98e2SPeter Wemm 			if (bitset(MCIF_7BIT, mci->mci_flags))
3897c2aa98e2SPeter Wemm 				c &= 0x7f;
3898c2aa98e2SPeter Wemm 			switch (ostate)
3899c2aa98e2SPeter Wemm 			{
3900c2aa98e2SPeter Wemm 			  case OS_HEAD:
3901c2aa98e2SPeter Wemm #if _FFR_NONULLS
3902c2aa98e2SPeter Wemm 				if (c == '\0' &&
3903c2aa98e2SPeter Wemm 				    bitnset(M_NONULLS, mci->mci_mailer->m_flags))
3904c2aa98e2SPeter Wemm 					break;
390506f25ae9SGregory Neil Shapiro #endif /* _FFR_NONULLS */
3906c2aa98e2SPeter Wemm 				if (c != '\r' && c != '\n' && bp < buflim)
3907c2aa98e2SPeter Wemm 				{
3908c2aa98e2SPeter Wemm 					*bp++ = c;
3909c2aa98e2SPeter Wemm 					break;
3910c2aa98e2SPeter Wemm 				}
3911c2aa98e2SPeter Wemm 
3912c2aa98e2SPeter Wemm 				/* check beginning of line for special cases */
3913c2aa98e2SPeter Wemm 				*bp = '\0';
3914c2aa98e2SPeter Wemm 				pos = 0;
3915c2aa98e2SPeter Wemm 				padc = EOF;
3916c2aa98e2SPeter Wemm 				if (buf[0] == 'F' &&
3917c2aa98e2SPeter Wemm 				    bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
3918c2aa98e2SPeter Wemm 				    strncmp(buf, "From ", 5) == 0)
3919c2aa98e2SPeter Wemm 				{
3920c2aa98e2SPeter Wemm 					padc = '>';
3921c2aa98e2SPeter Wemm 				}
3922c2aa98e2SPeter Wemm 				if (buf[0] == '-' && buf[1] == '-' &&
3923c2aa98e2SPeter Wemm 				    separator != NULL)
3924c2aa98e2SPeter Wemm 				{
3925c2aa98e2SPeter Wemm 					/* possible separator */
3926c2aa98e2SPeter Wemm 					int sl = strlen(separator);
3927c2aa98e2SPeter Wemm 
3928c2aa98e2SPeter Wemm 					if (strncmp(&buf[2], separator, sl) == 0)
3929c2aa98e2SPeter Wemm 						padc = ' ';
3930c2aa98e2SPeter Wemm 				}
3931c2aa98e2SPeter Wemm 				if (buf[0] == '.' &&
3932c2aa98e2SPeter Wemm 				    bitnset(M_XDOT, mci->mci_mailer->m_flags))
3933c2aa98e2SPeter Wemm 				{
3934c2aa98e2SPeter Wemm 					padc = '.';
3935c2aa98e2SPeter Wemm 				}
3936c2aa98e2SPeter Wemm 
3937c2aa98e2SPeter Wemm 				/* now copy out saved line */
3938c2aa98e2SPeter Wemm 				if (TrafficLogFile != NULL)
3939c2aa98e2SPeter Wemm 				{
3940c2aa98e2SPeter Wemm 					fprintf(TrafficLogFile, "%05d >>> ",
3941c2aa98e2SPeter Wemm 						(int) getpid());
3942c2aa98e2SPeter Wemm 					if (padc != EOF)
394306f25ae9SGregory Neil Shapiro 						(void) putc(padc,
394406f25ae9SGregory Neil Shapiro 							    TrafficLogFile);
3945c2aa98e2SPeter Wemm 					for (xp = buf; xp < bp; xp++)
394606f25ae9SGregory Neil Shapiro 						(void) putc((unsigned char) *xp,
394706f25ae9SGregory Neil Shapiro 							    TrafficLogFile);
3948c2aa98e2SPeter Wemm 					if (c == '\n')
394906f25ae9SGregory Neil Shapiro 						(void) fputs(mci->mci_mailer->m_eol,
3950c2aa98e2SPeter Wemm 						      TrafficLogFile);
3951c2aa98e2SPeter Wemm 				}
3952c2aa98e2SPeter Wemm 				if (padc != EOF)
3953c2aa98e2SPeter Wemm 				{
395406f25ae9SGregory Neil Shapiro 					if (putc(padc, mci->mci_out) == EOF)
395506f25ae9SGregory Neil Shapiro 					{
395606f25ae9SGregory Neil Shapiro 						dead = TRUE;
395706f25ae9SGregory Neil Shapiro 						continue;
395806f25ae9SGregory Neil Shapiro 					}
3959193538b7SGregory Neil Shapiro 					else
3960193538b7SGregory Neil Shapiro 					{
3961193538b7SGregory Neil Shapiro 						/* record progress for DATA timeout */
3962193538b7SGregory Neil Shapiro 						DataProgress = TRUE;
3963193538b7SGregory Neil Shapiro 					}
3964c2aa98e2SPeter Wemm 					pos++;
3965c2aa98e2SPeter Wemm 				}
3966c2aa98e2SPeter Wemm 				for (xp = buf; xp < bp; xp++)
3967c2aa98e2SPeter Wemm 				{
396806f25ae9SGregory Neil Shapiro 					if (putc((unsigned char) *xp,
396906f25ae9SGregory Neil Shapiro 						 mci->mci_out) == EOF)
397006f25ae9SGregory Neil Shapiro 					{
397106f25ae9SGregory Neil Shapiro 						dead = TRUE;
397206f25ae9SGregory Neil Shapiro 						break;
3973c2aa98e2SPeter Wemm 					}
3974193538b7SGregory Neil Shapiro 					else
3975193538b7SGregory Neil Shapiro 					{
397606f25ae9SGregory Neil Shapiro 						/* record progress for DATA timeout */
397706f25ae9SGregory Neil Shapiro 						DataProgress = TRUE;
397806f25ae9SGregory Neil Shapiro 					}
3979193538b7SGregory Neil Shapiro 				}
398006f25ae9SGregory Neil Shapiro 				if (dead)
398106f25ae9SGregory Neil Shapiro 					continue;
3982c2aa98e2SPeter Wemm 				if (c == '\n')
3983c2aa98e2SPeter Wemm 				{
398406f25ae9SGregory Neil Shapiro 					if (fputs(mci->mci_mailer->m_eol,
398506f25ae9SGregory Neil Shapiro 						  mci->mci_out) == EOF)
398606f25ae9SGregory Neil Shapiro 						break;
3987193538b7SGregory Neil Shapiro 					else
3988193538b7SGregory Neil Shapiro 					{
3989193538b7SGregory Neil Shapiro 						/* record progress for DATA timeout */
3990193538b7SGregory Neil Shapiro 						DataProgress = TRUE;
3991193538b7SGregory Neil Shapiro 					}
3992c2aa98e2SPeter Wemm 					pos = 0;
3993c2aa98e2SPeter Wemm 				}
3994c2aa98e2SPeter Wemm 				else
3995c2aa98e2SPeter Wemm 				{
3996c2aa98e2SPeter Wemm 					pos += bp - buf;
3997c2aa98e2SPeter Wemm 					if (c != '\r')
3998c2aa98e2SPeter Wemm 						*pbp++ = c;
3999c2aa98e2SPeter Wemm 				}
400006f25ae9SGregory Neil Shapiro 
4001c2aa98e2SPeter Wemm 				bp = buf;
4002c2aa98e2SPeter Wemm 
4003c2aa98e2SPeter Wemm 				/* determine next state */
4004c2aa98e2SPeter Wemm 				if (c == '\n')
4005c2aa98e2SPeter Wemm 					ostate = OS_HEAD;
4006c2aa98e2SPeter Wemm 				else if (c == '\r')
4007c2aa98e2SPeter Wemm 					ostate = OS_CR;
4008c2aa98e2SPeter Wemm 				else
4009c2aa98e2SPeter Wemm 					ostate = OS_INLINE;
4010c2aa98e2SPeter Wemm 				continue;
4011c2aa98e2SPeter Wemm 
4012c2aa98e2SPeter Wemm 			  case OS_CR:
4013c2aa98e2SPeter Wemm 				if (c == '\n')
4014c2aa98e2SPeter Wemm 				{
4015c2aa98e2SPeter Wemm 					/* got CRLF */
401606f25ae9SGregory Neil Shapiro 					if (fputs(mci->mci_mailer->m_eol,
401706f25ae9SGregory Neil Shapiro 						  mci->mci_out) == EOF)
401806f25ae9SGregory Neil Shapiro 						continue;
4019193538b7SGregory Neil Shapiro 					else
4020193538b7SGregory Neil Shapiro 					{
402106f25ae9SGregory Neil Shapiro 						/* record progress for DATA timeout */
402206f25ae9SGregory Neil Shapiro 						DataProgress = TRUE;
4023193538b7SGregory Neil Shapiro 					}
402406f25ae9SGregory Neil Shapiro 
4025c2aa98e2SPeter Wemm 					if (TrafficLogFile != NULL)
4026c2aa98e2SPeter Wemm 					{
402706f25ae9SGregory Neil Shapiro 						(void) fputs(mci->mci_mailer->m_eol,
4028c2aa98e2SPeter Wemm 							     TrafficLogFile);
4029c2aa98e2SPeter Wemm 					}
4030c2aa98e2SPeter Wemm 					ostate = OS_HEAD;
4031c2aa98e2SPeter Wemm 					continue;
4032c2aa98e2SPeter Wemm 				}
4033c2aa98e2SPeter Wemm 
4034c2aa98e2SPeter Wemm 				/* had a naked carriage return */
4035c2aa98e2SPeter Wemm 				*pbp++ = c;
4036c2aa98e2SPeter Wemm 				c = '\r';
4037c2aa98e2SPeter Wemm 				ostate = OS_INLINE;
4038c2aa98e2SPeter Wemm 				goto putch;
4039c2aa98e2SPeter Wemm 
4040c2aa98e2SPeter Wemm 			  case OS_INLINE:
4041c2aa98e2SPeter Wemm 				if (c == '\r')
4042c2aa98e2SPeter Wemm 				{
4043c2aa98e2SPeter Wemm 					ostate = OS_CR;
4044c2aa98e2SPeter Wemm 					continue;
4045c2aa98e2SPeter Wemm 				}
4046c2aa98e2SPeter Wemm #if _FFR_NONULLS
4047c2aa98e2SPeter Wemm 				if (c == '\0' &&
4048c2aa98e2SPeter Wemm 				    bitnset(M_NONULLS, mci->mci_mailer->m_flags))
4049c2aa98e2SPeter Wemm 					break;
405006f25ae9SGregory Neil Shapiro #endif /* _FFR_NONULLS */
4051c2aa98e2SPeter Wemm putch:
4052c2aa98e2SPeter Wemm 				if (mci->mci_mailer->m_linelimit > 0 &&
405306f25ae9SGregory Neil Shapiro 				    pos >= mci->mci_mailer->m_linelimit - 1 &&
4054c2aa98e2SPeter Wemm 				    c != '\n')
4055c2aa98e2SPeter Wemm 				{
405606f25ae9SGregory Neil Shapiro 					int d;
405706f25ae9SGregory Neil Shapiro 
405806f25ae9SGregory Neil Shapiro 					/* check next character for EOL */
405906f25ae9SGregory Neil Shapiro 					if (pbp > peekbuf)
406006f25ae9SGregory Neil Shapiro 						d = *(pbp - 1);
406106f25ae9SGregory Neil Shapiro 					else if ((d = getc(e->e_dfp)) != EOF)
406206f25ae9SGregory Neil Shapiro 						*pbp++ = d;
406306f25ae9SGregory Neil Shapiro 
406406f25ae9SGregory Neil Shapiro 					if (d == '\n' || d == EOF)
406506f25ae9SGregory Neil Shapiro 					{
406606f25ae9SGregory Neil Shapiro 						if (TrafficLogFile != NULL)
406706f25ae9SGregory Neil Shapiro 							(void) putc((unsigned char) c,
406806f25ae9SGregory Neil Shapiro 							    TrafficLogFile);
406906f25ae9SGregory Neil Shapiro 						if (putc((unsigned char) c,
407006f25ae9SGregory Neil Shapiro 							 mci->mci_out) == EOF)
407106f25ae9SGregory Neil Shapiro 						{
407206f25ae9SGregory Neil Shapiro 							dead = TRUE;
407306f25ae9SGregory Neil Shapiro 							continue;
407406f25ae9SGregory Neil Shapiro 						}
4075193538b7SGregory Neil Shapiro 						else
4076193538b7SGregory Neil Shapiro 						{
4077193538b7SGregory Neil Shapiro 							/* record progress for DATA timeout */
4078193538b7SGregory Neil Shapiro 							DataProgress = TRUE;
4079193538b7SGregory Neil Shapiro 						}
408006f25ae9SGregory Neil Shapiro 						pos++;
408106f25ae9SGregory Neil Shapiro 						continue;
408206f25ae9SGregory Neil Shapiro 					}
408306f25ae9SGregory Neil Shapiro 
408406f25ae9SGregory Neil Shapiro 					if (putc('!', mci->mci_out) == EOF ||
408506f25ae9SGregory Neil Shapiro 					    fputs(mci->mci_mailer->m_eol,
408606f25ae9SGregory Neil Shapiro 						  mci->mci_out) == EOF)
408706f25ae9SGregory Neil Shapiro 					{
408806f25ae9SGregory Neil Shapiro 						dead = TRUE;
408906f25ae9SGregory Neil Shapiro 						continue;
409006f25ae9SGregory Neil Shapiro 					}
4091193538b7SGregory Neil Shapiro 					else
4092193538b7SGregory Neil Shapiro 					{
409306f25ae9SGregory Neil Shapiro 						/* record progress for DATA timeout */
409406f25ae9SGregory Neil Shapiro 						DataProgress = TRUE;
4095193538b7SGregory Neil Shapiro 					}
409606f25ae9SGregory Neil Shapiro 
4097c2aa98e2SPeter Wemm 					if (TrafficLogFile != NULL)
4098c2aa98e2SPeter Wemm 					{
4099c2aa98e2SPeter Wemm 						fprintf(TrafficLogFile, "!%s",
4100c2aa98e2SPeter Wemm 							mci->mci_mailer->m_eol);
4101c2aa98e2SPeter Wemm 					}
4102c2aa98e2SPeter Wemm 					ostate = OS_HEAD;
4103c2aa98e2SPeter Wemm 					*pbp++ = c;
4104c2aa98e2SPeter Wemm 					continue;
4105c2aa98e2SPeter Wemm 				}
4106c2aa98e2SPeter Wemm 				if (c == '\n')
4107c2aa98e2SPeter Wemm 				{
4108c2aa98e2SPeter Wemm 					if (TrafficLogFile != NULL)
410906f25ae9SGregory Neil Shapiro 						(void) fputs(mci->mci_mailer->m_eol,
4110c2aa98e2SPeter Wemm 						      TrafficLogFile);
411106f25ae9SGregory Neil Shapiro 					if (fputs(mci->mci_mailer->m_eol,
411206f25ae9SGregory Neil Shapiro 						  mci->mci_out) == EOF)
411306f25ae9SGregory Neil Shapiro 						continue;
4114193538b7SGregory Neil Shapiro 					else
4115193538b7SGregory Neil Shapiro 					{
4116193538b7SGregory Neil Shapiro 						/* record progress for DATA timeout */
4117193538b7SGregory Neil Shapiro 						DataProgress = TRUE;
4118193538b7SGregory Neil Shapiro 					}
4119c2aa98e2SPeter Wemm 					pos = 0;
4120c2aa98e2SPeter Wemm 					ostate = OS_HEAD;
4121c2aa98e2SPeter Wemm 				}
4122c2aa98e2SPeter Wemm 				else
4123c2aa98e2SPeter Wemm 				{
4124c2aa98e2SPeter Wemm 					if (TrafficLogFile != NULL)
412506f25ae9SGregory Neil Shapiro 						(void) putc((unsigned char) c,
412606f25ae9SGregory Neil Shapiro 							    TrafficLogFile);
412706f25ae9SGregory Neil Shapiro 					if (putc((unsigned char) c,
412806f25ae9SGregory Neil Shapiro 						 mci->mci_out) == EOF)
412906f25ae9SGregory Neil Shapiro 					{
413006f25ae9SGregory Neil Shapiro 						dead = TRUE;
413106f25ae9SGregory Neil Shapiro 						continue;
413206f25ae9SGregory Neil Shapiro 					}
4133193538b7SGregory Neil Shapiro 					else
4134193538b7SGregory Neil Shapiro 					{
4135193538b7SGregory Neil Shapiro 						/* record progress for DATA timeout */
4136193538b7SGregory Neil Shapiro 						DataProgress = TRUE;
4137193538b7SGregory Neil Shapiro 					}
4138c2aa98e2SPeter Wemm 					pos++;
4139c2aa98e2SPeter Wemm 					ostate = OS_INLINE;
4140c2aa98e2SPeter Wemm 				}
4141c2aa98e2SPeter Wemm 				break;
4142c2aa98e2SPeter Wemm 			}
4143c2aa98e2SPeter Wemm 		}
4144c2aa98e2SPeter Wemm 
4145c2aa98e2SPeter Wemm 		/* make sure we are at the beginning of a line */
4146c2aa98e2SPeter Wemm 		if (bp > buf)
4147c2aa98e2SPeter Wemm 		{
4148c2aa98e2SPeter Wemm 			if (TrafficLogFile != NULL)
4149c2aa98e2SPeter Wemm 			{
4150c2aa98e2SPeter Wemm 				for (xp = buf; xp < bp; xp++)
415106f25ae9SGregory Neil Shapiro 					(void) putc((unsigned char) *xp,
415206f25ae9SGregory Neil Shapiro 						    TrafficLogFile);
4153c2aa98e2SPeter Wemm 			}
4154c2aa98e2SPeter Wemm 			for (xp = buf; xp < bp; xp++)
4155c2aa98e2SPeter Wemm 			{
415606f25ae9SGregory Neil Shapiro 				if (putc((unsigned char) *xp, mci->mci_out) ==
415706f25ae9SGregory Neil Shapiro 				    EOF)
415806f25ae9SGregory Neil Shapiro 				{
415906f25ae9SGregory Neil Shapiro 					dead = TRUE;
416006f25ae9SGregory Neil Shapiro 					break;
416106f25ae9SGregory Neil Shapiro 				}
4162193538b7SGregory Neil Shapiro 				else
4163193538b7SGregory Neil Shapiro 				{
416406f25ae9SGregory Neil Shapiro 					/* record progress for DATA timeout */
416506f25ae9SGregory Neil Shapiro 					DataProgress = TRUE;
4166c2aa98e2SPeter Wemm 				}
4167193538b7SGregory Neil Shapiro 			}
4168c2aa98e2SPeter Wemm 			pos += bp - buf;
4169c2aa98e2SPeter Wemm 		}
417006f25ae9SGregory Neil Shapiro 		if (!dead && pos > 0)
4171c2aa98e2SPeter Wemm 		{
4172c2aa98e2SPeter Wemm 			if (TrafficLogFile != NULL)
417306f25ae9SGregory Neil Shapiro 				(void) fputs(mci->mci_mailer->m_eol,
417406f25ae9SGregory Neil Shapiro 					     TrafficLogFile);
417506f25ae9SGregory Neil Shapiro 			(void) fputs(mci->mci_mailer->m_eol, mci->mci_out);
417606f25ae9SGregory Neil Shapiro 
417706f25ae9SGregory Neil Shapiro 			/* record progress for DATA timeout */
417806f25ae9SGregory Neil Shapiro 			DataProgress = TRUE;
4179c2aa98e2SPeter Wemm 		}
4180c2aa98e2SPeter Wemm 	}
4181c2aa98e2SPeter Wemm 
4182c2aa98e2SPeter Wemm 	if (ferror(e->e_dfp))
4183c2aa98e2SPeter Wemm 	{
418406f25ae9SGregory Neil Shapiro 		syserr("putbody: %s/df%s: read error",
418506f25ae9SGregory Neil Shapiro 		       qid_printqueue(e->e_queuedir), e->e_id);
4186c2aa98e2SPeter Wemm 		ExitStat = EX_IOERR;
4187c2aa98e2SPeter Wemm 	}
4188c2aa98e2SPeter Wemm 
4189c2aa98e2SPeter Wemm endofmessage:
419006f25ae9SGregory Neil Shapiro 	/*
419106f25ae9SGregory Neil Shapiro 	**  Since mailfile() uses e_dfp in a child process,
419206f25ae9SGregory Neil Shapiro 	**  the file offset in the stdio library for the
419306f25ae9SGregory Neil Shapiro 	**  parent process will not agree with the in-kernel
419406f25ae9SGregory Neil Shapiro 	**  file offset since the file descriptor is shared
419506f25ae9SGregory Neil Shapiro 	**  between the processes.  Therefore, it is vital
419606f25ae9SGregory Neil Shapiro 	**  that the file always be rewound.  This forces the
419706f25ae9SGregory Neil Shapiro 	**  kernel offset (lseek) and stdio library (ftell)
419806f25ae9SGregory Neil Shapiro 	**  offset to match.
419906f25ae9SGregory Neil Shapiro 	*/
420006f25ae9SGregory Neil Shapiro 
420106f25ae9SGregory Neil Shapiro 	if (e->e_dfp != NULL)
420206f25ae9SGregory Neil Shapiro 		(void) bfrewind(e->e_dfp);
420306f25ae9SGregory Neil Shapiro 
4204c2aa98e2SPeter Wemm 	/* some mailers want extra blank line at end of message */
420506f25ae9SGregory Neil Shapiro 	if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
4206c2aa98e2SPeter Wemm 	    buf[0] != '\0' && buf[0] != '\n')
4207c2aa98e2SPeter Wemm 		putline("", mci);
4208c2aa98e2SPeter Wemm 
4209c2aa98e2SPeter Wemm 	(void) fflush(mci->mci_out);
4210c2aa98e2SPeter Wemm 	if (ferror(mci->mci_out) && errno != EPIPE)
4211c2aa98e2SPeter Wemm 	{
4212c2aa98e2SPeter Wemm 		syserr("putbody: write error");
4213c2aa98e2SPeter Wemm 		ExitStat = EX_IOERR;
4214c2aa98e2SPeter Wemm 	}
421506f25ae9SGregory Neil Shapiro 
4216c2aa98e2SPeter Wemm 	errno = 0;
4217c2aa98e2SPeter Wemm }
4218c2aa98e2SPeter Wemm /*
4219c2aa98e2SPeter Wemm **  MAILFILE -- Send a message to a file.
4220c2aa98e2SPeter Wemm **
4221c2aa98e2SPeter Wemm **	If the file has the setuid/setgid bits set, but NO execute
4222c2aa98e2SPeter Wemm **	bits, sendmail will try to become the owner of that file
4223c2aa98e2SPeter Wemm **	rather than the real user.  Obviously, this only works if
4224c2aa98e2SPeter Wemm **	sendmail runs as root.
4225c2aa98e2SPeter Wemm **
4226c2aa98e2SPeter Wemm **	This could be done as a subordinate mailer, except that it
4227c2aa98e2SPeter Wemm **	is used implicitly to save messages in ~/dead.letter.  We
4228c2aa98e2SPeter Wemm **	view this as being sufficiently important as to include it
4229c2aa98e2SPeter Wemm **	here.  For example, if the system is dying, we shouldn't have
4230c2aa98e2SPeter Wemm **	to create another process plus some pipes to save the message.
4231c2aa98e2SPeter Wemm **
4232c2aa98e2SPeter Wemm **	Parameters:
4233c2aa98e2SPeter Wemm **		filename -- the name of the file to send to.
4234c2aa98e2SPeter Wemm **		mailer -- mailer definition for recipient -- if NULL,
4235c2aa98e2SPeter Wemm **			use FileMailer.
4236c2aa98e2SPeter Wemm **		ctladdr -- the controlling address header -- includes
4237c2aa98e2SPeter Wemm **			the userid/groupid to be when sending.
4238c2aa98e2SPeter Wemm **		sfflags -- flags for opening.
4239c2aa98e2SPeter Wemm **		e -- the current envelope.
4240c2aa98e2SPeter Wemm **
4241c2aa98e2SPeter Wemm **	Returns:
4242c2aa98e2SPeter Wemm **		The exit code associated with the operation.
4243c2aa98e2SPeter Wemm **
4244c2aa98e2SPeter Wemm **	Side Effects:
4245c2aa98e2SPeter Wemm **		none.
4246c2aa98e2SPeter Wemm */
4247c2aa98e2SPeter Wemm 
4248c2aa98e2SPeter Wemm static jmp_buf	CtxMailfileTimeout;
4249c2aa98e2SPeter Wemm 
4250c2aa98e2SPeter Wemm int
4251c2aa98e2SPeter Wemm mailfile(filename, mailer, ctladdr, sfflags, e)
4252c2aa98e2SPeter Wemm 	char *volatile filename;
4253c2aa98e2SPeter Wemm 	MAILER *volatile mailer;
4254c2aa98e2SPeter Wemm 	ADDRESS *ctladdr;
425506f25ae9SGregory Neil Shapiro 	volatile long sfflags;
4256c2aa98e2SPeter Wemm 	register ENVELOPE *e;
4257c2aa98e2SPeter Wemm {
4258c2aa98e2SPeter Wemm 	register FILE *f;
4259c2aa98e2SPeter Wemm 	register pid_t pid = -1;
426006f25ae9SGregory Neil Shapiro 	volatile int mode;
426106f25ae9SGregory Neil Shapiro 	int len;
426206f25ae9SGregory Neil Shapiro 	off_t curoff;
4263c2aa98e2SPeter Wemm 	bool suidwarn = geteuid() == 0;
4264c2aa98e2SPeter Wemm 	char *p;
426506f25ae9SGregory Neil Shapiro 	char *volatile realfile;
4266c2aa98e2SPeter Wemm 	EVENT *ev;
426706f25ae9SGregory Neil Shapiro 	char buf[MAXLINE + 1];
426806f25ae9SGregory Neil Shapiro 	char targetfile[MAXPATHLEN + 1];
4269c2aa98e2SPeter Wemm 
4270c2aa98e2SPeter Wemm 	if (tTd(11, 1))
4271c2aa98e2SPeter Wemm 	{
427206f25ae9SGregory Neil Shapiro 		dprintf("mailfile %s\n  ctladdr=", filename);
4273c2aa98e2SPeter Wemm 		printaddr(ctladdr, FALSE);
4274c2aa98e2SPeter Wemm 	}
4275c2aa98e2SPeter Wemm 
4276c2aa98e2SPeter Wemm 	if (mailer == NULL)
4277c2aa98e2SPeter Wemm 		mailer = FileMailer;
4278c2aa98e2SPeter Wemm 
4279c2aa98e2SPeter Wemm 	if (e->e_xfp != NULL)
428006f25ae9SGregory Neil Shapiro 		(void) fflush(e->e_xfp);
4281c2aa98e2SPeter Wemm 
4282c2aa98e2SPeter Wemm 	/*
4283c2aa98e2SPeter Wemm 	**  Special case /dev/null.  This allows us to restrict file
4284c2aa98e2SPeter Wemm 	**  delivery to regular files only.
4285c2aa98e2SPeter Wemm 	*/
4286c2aa98e2SPeter Wemm 
4287c2aa98e2SPeter Wemm 	if (strcmp(filename, "/dev/null") == 0)
4288c2aa98e2SPeter Wemm 		return EX_OK;
4289c2aa98e2SPeter Wemm 
4290c2aa98e2SPeter Wemm 	/* check for 8-bit available */
4291c2aa98e2SPeter Wemm 	if (bitset(EF_HAS8BIT, e->e_flags) &&
4292c2aa98e2SPeter Wemm 	    bitnset(M_7BITS, mailer->m_flags) &&
4293c2aa98e2SPeter Wemm 	    (bitset(EF_DONT_MIME, e->e_flags) ||
4294c2aa98e2SPeter Wemm 	     !(bitset(MM_MIME8BIT, MimeMode) ||
4295c2aa98e2SPeter Wemm 	       (bitset(EF_IS_MIME, e->e_flags) &&
4296c2aa98e2SPeter Wemm 		bitset(MM_CVTMIME, MimeMode)))))
4297c2aa98e2SPeter Wemm 	{
4298c2aa98e2SPeter Wemm 		e->e_status = "5.6.3";
429906f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status,
430006f25ae9SGregory Neil Shapiro 		       "554 Cannot send 8-bit data to 7-bit destination");
430106f25ae9SGregory Neil Shapiro 		return EX_DATAERR;
430206f25ae9SGregory Neil Shapiro 	}
430306f25ae9SGregory Neil Shapiro 
430406f25ae9SGregory Neil Shapiro 	/* Find the actual file */
430506f25ae9SGregory Neil Shapiro 	if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0')
430606f25ae9SGregory Neil Shapiro 	{
430706f25ae9SGregory Neil Shapiro 		len = strlen(SafeFileEnv);
430806f25ae9SGregory Neil Shapiro 
430906f25ae9SGregory Neil Shapiro 		if (strncmp(SafeFileEnv, filename, len) == 0)
431006f25ae9SGregory Neil Shapiro 			filename += len;
431106f25ae9SGregory Neil Shapiro 
431206f25ae9SGregory Neil Shapiro 		if (len + strlen(filename) + 1 > MAXPATHLEN)
431306f25ae9SGregory Neil Shapiro 		{
431406f25ae9SGregory Neil Shapiro 			syserr("mailfile: filename too long (%s/%s)",
431506f25ae9SGregory Neil Shapiro 			       SafeFileEnv, filename);
431606f25ae9SGregory Neil Shapiro 			return EX_CANTCREAT;
431706f25ae9SGregory Neil Shapiro 		}
431806f25ae9SGregory Neil Shapiro 		(void) strlcpy(targetfile, SafeFileEnv, sizeof targetfile);
431906f25ae9SGregory Neil Shapiro 		realfile = targetfile + len;
432006f25ae9SGregory Neil Shapiro 		if (targetfile[len - 1] != '/')
432106f25ae9SGregory Neil Shapiro 			(void) strlcat(targetfile, "/", sizeof targetfile);
432206f25ae9SGregory Neil Shapiro 		if (*filename == '/')
432306f25ae9SGregory Neil Shapiro 			filename++;
432406f25ae9SGregory Neil Shapiro 		(void) strlcat(targetfile, filename, sizeof targetfile);
432506f25ae9SGregory Neil Shapiro 	}
432606f25ae9SGregory Neil Shapiro 	else if (mailer->m_rootdir != NULL)
432706f25ae9SGregory Neil Shapiro 	{
432806f25ae9SGregory Neil Shapiro 		expand(mailer->m_rootdir, targetfile, sizeof targetfile, e);
432906f25ae9SGregory Neil Shapiro 		len = strlen(targetfile);
433006f25ae9SGregory Neil Shapiro 
433106f25ae9SGregory Neil Shapiro 		if (strncmp(targetfile, filename, len) == 0)
433206f25ae9SGregory Neil Shapiro 			filename += len;
433306f25ae9SGregory Neil Shapiro 
433406f25ae9SGregory Neil Shapiro 		if (len + strlen(filename) + 1 > MAXPATHLEN)
433506f25ae9SGregory Neil Shapiro 		{
433606f25ae9SGregory Neil Shapiro 			syserr("mailfile: filename too long (%s/%s)",
433706f25ae9SGregory Neil Shapiro 			       targetfile, filename);
433806f25ae9SGregory Neil Shapiro 			return EX_CANTCREAT;
433906f25ae9SGregory Neil Shapiro 		}
434006f25ae9SGregory Neil Shapiro 		realfile = targetfile + len;
434106f25ae9SGregory Neil Shapiro 		if (targetfile[len - 1] != '/')
434206f25ae9SGregory Neil Shapiro 			(void) strlcat(targetfile, "/", sizeof targetfile);
434306f25ae9SGregory Neil Shapiro 		if (*filename == '/')
434406f25ae9SGregory Neil Shapiro 			(void) strlcat(targetfile, filename + 1,
434506f25ae9SGregory Neil Shapiro 				       sizeof targetfile);
434606f25ae9SGregory Neil Shapiro 		else
434706f25ae9SGregory Neil Shapiro 			(void) strlcat(targetfile, filename, sizeof targetfile);
434806f25ae9SGregory Neil Shapiro 	}
434906f25ae9SGregory Neil Shapiro 	else
435006f25ae9SGregory Neil Shapiro 	{
435106f25ae9SGregory Neil Shapiro 		if (strlen(filename) > MAXPATHLEN)
435206f25ae9SGregory Neil Shapiro 		{
435306f25ae9SGregory Neil Shapiro 			syserr("mailfile: filename too long (%s)", filename);
435406f25ae9SGregory Neil Shapiro 			return EX_CANTCREAT;
435506f25ae9SGregory Neil Shapiro 		}
435606f25ae9SGregory Neil Shapiro 		(void) strlcpy(targetfile, filename, sizeof targetfile);
435706f25ae9SGregory Neil Shapiro 		realfile = targetfile;
4358c2aa98e2SPeter Wemm 	}
4359c2aa98e2SPeter Wemm 
4360c2aa98e2SPeter Wemm 	/*
4361c2aa98e2SPeter Wemm 	**  Fork so we can change permissions here.
4362c2aa98e2SPeter Wemm 	**	Note that we MUST use fork, not vfork, because of
4363c2aa98e2SPeter Wemm 	**	the complications of calling subroutines, etc.
4364c2aa98e2SPeter Wemm 	*/
4365c2aa98e2SPeter Wemm 
4366c2aa98e2SPeter Wemm 	DOFORK(fork);
4367c2aa98e2SPeter Wemm 
4368c2aa98e2SPeter Wemm 	if (pid < 0)
436906f25ae9SGregory Neil Shapiro 		return EX_OSERR;
4370c2aa98e2SPeter Wemm 	else if (pid == 0)
4371c2aa98e2SPeter Wemm 	{
4372c2aa98e2SPeter Wemm 		/* child -- actually write to file */
4373c2aa98e2SPeter Wemm 		struct stat stb;
4374c2aa98e2SPeter Wemm 		MCI mcibuf;
4375065a643dSPeter Wemm 		int err;
4376c2aa98e2SPeter Wemm 		volatile int oflags = O_WRONLY|O_APPEND;
4377c2aa98e2SPeter Wemm 
4378c2aa98e2SPeter Wemm 		if (e->e_lockfp != NULL)
4379c2aa98e2SPeter Wemm 			(void) close(fileno(e->e_lockfp));
4380c2aa98e2SPeter Wemm 
4381c2aa98e2SPeter Wemm 		(void) setsignal(SIGINT, SIG_DFL);
4382c2aa98e2SPeter Wemm 		(void) setsignal(SIGHUP, SIG_DFL);
4383c2aa98e2SPeter Wemm 		(void) setsignal(SIGTERM, SIG_DFL);
4384c2aa98e2SPeter Wemm 		(void) umask(OldUmask);
4385c2aa98e2SPeter Wemm 		e->e_to = filename;
4386c2aa98e2SPeter Wemm 		ExitStat = EX_OK;
4387c2aa98e2SPeter Wemm 
4388c2aa98e2SPeter Wemm 		if (setjmp(CtxMailfileTimeout) != 0)
4389c2aa98e2SPeter Wemm 		{
4390c2aa98e2SPeter Wemm 			exit(EX_TEMPFAIL);
4391c2aa98e2SPeter Wemm 		}
4392c2aa98e2SPeter Wemm 
4393c2aa98e2SPeter Wemm 		if (TimeOuts.to_fileopen > 0)
4394c2aa98e2SPeter Wemm 			ev = setevent(TimeOuts.to_fileopen, mailfiletimeout, 0);
4395c2aa98e2SPeter Wemm 		else
4396c2aa98e2SPeter Wemm 			ev = NULL;
4397c2aa98e2SPeter Wemm 
439806f25ae9SGregory Neil Shapiro 		/* check file mode to see if setuid */
439906f25ae9SGregory Neil Shapiro 		if (stat(targetfile, &stb) < 0)
4400c2aa98e2SPeter Wemm 			mode = FileMode;
440106f25ae9SGregory Neil Shapiro 		else
4402c2aa98e2SPeter Wemm 			mode = stb.st_mode;
4403c2aa98e2SPeter Wemm 
4404c2aa98e2SPeter Wemm 		/* limit the errors to those actually caused in the child */
4405c2aa98e2SPeter Wemm 		errno = 0;
4406c2aa98e2SPeter Wemm 		ExitStat = EX_OK;
4407c2aa98e2SPeter Wemm 
440806f25ae9SGregory Neil Shapiro 		/* Allow alias expansions to use the S_IS{U,G}ID bits */
440906f25ae9SGregory Neil Shapiro 		if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) ||
441006f25ae9SGregory Neil Shapiro 		    bitset(SFF_RUNASREALUID, sfflags))
4411c2aa98e2SPeter Wemm 		{
4412c2aa98e2SPeter Wemm 			/* ignore setuid and setgid bits */
4413c2aa98e2SPeter Wemm 			mode &= ~(S_ISGID|S_ISUID);
441406f25ae9SGregory Neil Shapiro 			if (tTd(11, 20))
441506f25ae9SGregory Neil Shapiro 				dprintf("mailfile: ignoring setuid/setgid bits\n");
4416c2aa98e2SPeter Wemm 		}
4417c2aa98e2SPeter Wemm 
4418c2aa98e2SPeter Wemm 		/* we have to open the dfile BEFORE setuid */
4419c2aa98e2SPeter Wemm 		if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
4420c2aa98e2SPeter Wemm 		{
4421c2aa98e2SPeter Wemm 			char *df = queuename(e, 'd');
4422c2aa98e2SPeter Wemm 
4423c2aa98e2SPeter Wemm 			e->e_dfp = fopen(df, "r");
4424c2aa98e2SPeter Wemm 			if (e->e_dfp == NULL)
4425c2aa98e2SPeter Wemm 			{
4426c2aa98e2SPeter Wemm 				syserr("mailfile: Cannot open %s for %s from %s",
4427c2aa98e2SPeter Wemm 					df, e->e_to, e->e_from.q_paddr);
4428c2aa98e2SPeter Wemm 			}
4429c2aa98e2SPeter Wemm 		}
4430c2aa98e2SPeter Wemm 
4431c2aa98e2SPeter Wemm 		/* select a new user to run as */
4432c2aa98e2SPeter Wemm 		if (!bitset(SFF_RUNASREALUID, sfflags))
4433c2aa98e2SPeter Wemm 		{
4434c2aa98e2SPeter Wemm 			if (bitnset(M_SPECIFIC_UID, mailer->m_flags))
4435c2aa98e2SPeter Wemm 			{
4436c2aa98e2SPeter Wemm 				RealUserName = NULL;
4437c2aa98e2SPeter Wemm 				RealUid = mailer->m_uid;
443806f25ae9SGregory Neil Shapiro 				if (RunAsUid != 0 && RealUid != RunAsUid)
443906f25ae9SGregory Neil Shapiro 				{
444006f25ae9SGregory Neil Shapiro 					/* Only root can change the uid */
444106f25ae9SGregory Neil Shapiro 					syserr("mailfile: insufficient privileges to change uid");
444206f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
444306f25ae9SGregory Neil Shapiro 				}
4444c2aa98e2SPeter Wemm 			}
4445c2aa98e2SPeter Wemm 			else if (bitset(S_ISUID, mode))
4446c2aa98e2SPeter Wemm 			{
4447c2aa98e2SPeter Wemm 				RealUserName = NULL;
4448c2aa98e2SPeter Wemm 				RealUid = stb.st_uid;
4449c2aa98e2SPeter Wemm 			}
4450c2aa98e2SPeter Wemm 			else if (ctladdr != NULL && ctladdr->q_uid != 0)
4451c2aa98e2SPeter Wemm 			{
4452c2aa98e2SPeter Wemm 				if (ctladdr->q_ruser != NULL)
4453c2aa98e2SPeter Wemm 					RealUserName = ctladdr->q_ruser;
4454c2aa98e2SPeter Wemm 				else
4455c2aa98e2SPeter Wemm 					RealUserName = ctladdr->q_user;
4456c2aa98e2SPeter Wemm 				RealUid = ctladdr->q_uid;
4457c2aa98e2SPeter Wemm 			}
4458c2aa98e2SPeter Wemm 			else if (mailer != NULL && mailer->m_uid != 0)
4459c2aa98e2SPeter Wemm 			{
4460c2aa98e2SPeter Wemm 				RealUserName = DefUser;
4461c2aa98e2SPeter Wemm 				RealUid = mailer->m_uid;
4462c2aa98e2SPeter Wemm 			}
4463c2aa98e2SPeter Wemm 			else
4464c2aa98e2SPeter Wemm 			{
4465c2aa98e2SPeter Wemm 				RealUserName = DefUser;
4466c2aa98e2SPeter Wemm 				RealUid = DefUid;
4467c2aa98e2SPeter Wemm 			}
4468c2aa98e2SPeter Wemm 
4469c2aa98e2SPeter Wemm 			/* select a new group to run as */
4470c2aa98e2SPeter Wemm 			if (bitnset(M_SPECIFIC_UID, mailer->m_flags))
447106f25ae9SGregory Neil Shapiro 			{
4472c2aa98e2SPeter Wemm 				RealGid = mailer->m_gid;
447306f25ae9SGregory Neil Shapiro 				if (RunAsUid != 0 &&
447406f25ae9SGregory Neil Shapiro 				    (RealGid != getgid() ||
447506f25ae9SGregory Neil Shapiro 				     RealGid != getegid()))
447606f25ae9SGregory Neil Shapiro 				{
447706f25ae9SGregory Neil Shapiro 					/* Only root can change the gid */
447806f25ae9SGregory Neil Shapiro 					syserr("mailfile: insufficient privileges to change gid");
447906f25ae9SGregory Neil Shapiro 					exit(EX_TEMPFAIL);
448006f25ae9SGregory Neil Shapiro 				}
448106f25ae9SGregory Neil Shapiro 			}
4482c2aa98e2SPeter Wemm 			else if (bitset(S_ISGID, mode))
4483c2aa98e2SPeter Wemm 				RealGid = stb.st_gid;
448406f25ae9SGregory Neil Shapiro 			else if (ctladdr != NULL &&
448506f25ae9SGregory Neil Shapiro 				 ctladdr->q_uid == DefUid &&
448606f25ae9SGregory Neil Shapiro 				 ctladdr->q_gid == 0)
4487193538b7SGregory Neil Shapiro 			{
4488193538b7SGregory Neil Shapiro 				/*
4489193538b7SGregory Neil Shapiro 				**  Special case:  This means it is an
4490193538b7SGregory Neil Shapiro 				**  alias and we should act as DefaultUser.
4491193538b7SGregory Neil Shapiro 				**  See alias()'s comments.
4492193538b7SGregory Neil Shapiro 				*/
4493193538b7SGregory Neil Shapiro 
449406f25ae9SGregory Neil Shapiro 				RealGid = DefGid;
4495193538b7SGregory Neil Shapiro 				RealUserName = DefUser;
4496193538b7SGregory Neil Shapiro 			}
4497193538b7SGregory Neil Shapiro 			else if (ctladdr != NULL && ctladdr->q_uid != 0)
4498193538b7SGregory Neil Shapiro 				RealGid = ctladdr->q_gid;
4499c2aa98e2SPeter Wemm 			else if (mailer != NULL && mailer->m_gid != 0)
4500c2aa98e2SPeter Wemm 				RealGid = mailer->m_gid;
4501c2aa98e2SPeter Wemm 			else
4502c2aa98e2SPeter Wemm 				RealGid = DefGid;
4503c2aa98e2SPeter Wemm 		}
4504c2aa98e2SPeter Wemm 
4505c2aa98e2SPeter Wemm 		/* last ditch */
4506c2aa98e2SPeter Wemm 		if (!bitset(SFF_ROOTOK, sfflags))
4507c2aa98e2SPeter Wemm 		{
4508c2aa98e2SPeter Wemm 			if (RealUid == 0)
4509c2aa98e2SPeter Wemm 				RealUid = DefUid;
4510c2aa98e2SPeter Wemm 			if (RealGid == 0)
4511c2aa98e2SPeter Wemm 				RealGid = DefGid;
4512c2aa98e2SPeter Wemm 		}
4513c2aa98e2SPeter Wemm 
4514c2aa98e2SPeter Wemm 		/* set group id list (needs /etc/group access) */
4515c2aa98e2SPeter Wemm 		if (RealUserName != NULL && !DontInitGroups)
4516c2aa98e2SPeter Wemm 		{
4517c2aa98e2SPeter Wemm 			if (initgroups(RealUserName, RealGid) == -1 && suidwarn)
451806f25ae9SGregory Neil Shapiro 			{
4519c2aa98e2SPeter Wemm 				syserr("mailfile: initgroups(%s, %d) failed",
4520c2aa98e2SPeter Wemm 					RealUserName, RealGid);
452106f25ae9SGregory Neil Shapiro 				exit(EX_TEMPFAIL);
452206f25ae9SGregory Neil Shapiro 			}
4523c2aa98e2SPeter Wemm 		}
4524c2aa98e2SPeter Wemm 		else
4525c2aa98e2SPeter Wemm 		{
4526c2aa98e2SPeter Wemm 			GIDSET_T gidset[1];
4527c2aa98e2SPeter Wemm 
4528c2aa98e2SPeter Wemm 			gidset[0] = RealGid;
4529c2aa98e2SPeter Wemm 			if (setgroups(1, gidset) == -1 && suidwarn)
453006f25ae9SGregory Neil Shapiro 			{
4531c2aa98e2SPeter Wemm 				syserr("mailfile: setgroups() failed");
453206f25ae9SGregory Neil Shapiro 				exit(EX_TEMPFAIL);
453306f25ae9SGregory Neil Shapiro 			}
4534c2aa98e2SPeter Wemm 		}
4535c2aa98e2SPeter Wemm 
453606f25ae9SGregory Neil Shapiro 		/*
453706f25ae9SGregory Neil Shapiro 		**  If you have a safe environment, go into it.
453806f25ae9SGregory Neil Shapiro 		*/
4539c2aa98e2SPeter Wemm 
454006f25ae9SGregory Neil Shapiro 		if (realfile != targetfile)
454106f25ae9SGregory Neil Shapiro 		{
454206f25ae9SGregory Neil Shapiro 			*realfile = '\0';
454306f25ae9SGregory Neil Shapiro 			if (tTd(11, 20))
454406f25ae9SGregory Neil Shapiro 				dprintf("mailfile: chroot %s\n", targetfile);
454506f25ae9SGregory Neil Shapiro 			if (chroot(targetfile) < 0)
4546c2aa98e2SPeter Wemm 			{
4547c2aa98e2SPeter Wemm 				syserr("mailfile: Cannot chroot(%s)",
454806f25ae9SGregory Neil Shapiro 				       targetfile);
4549c2aa98e2SPeter Wemm 				exit(EX_CANTCREAT);
4550c2aa98e2SPeter Wemm 			}
455106f25ae9SGregory Neil Shapiro 			*realfile = '/';
4552c2aa98e2SPeter Wemm 		}
455306f25ae9SGregory Neil Shapiro 
455406f25ae9SGregory Neil Shapiro 		if (tTd(11, 40))
455506f25ae9SGregory Neil Shapiro 			dprintf("mailfile: deliver to %s\n", realfile);
455606f25ae9SGregory Neil Shapiro 
4557c2aa98e2SPeter Wemm 		if (chdir("/") < 0)
455806f25ae9SGregory Neil Shapiro 		{
4559c2aa98e2SPeter Wemm 			syserr("mailfile: cannot chdir(/)");
456006f25ae9SGregory Neil Shapiro 			exit(EX_CANTCREAT);
456106f25ae9SGregory Neil Shapiro 		}
4562c2aa98e2SPeter Wemm 
4563c2aa98e2SPeter Wemm 		/* now reset the group and user ids */
4564c2aa98e2SPeter Wemm 		endpwent();
4565c2aa98e2SPeter Wemm 		if (setgid(RealGid) < 0 && suidwarn)
456606f25ae9SGregory Neil Shapiro 		{
4567c2aa98e2SPeter Wemm 			syserr("mailfile: setgid(%ld) failed", (long) RealGid);
456806f25ae9SGregory Neil Shapiro 			exit(EX_TEMPFAIL);
456906f25ae9SGregory Neil Shapiro 		}
4570c2aa98e2SPeter Wemm 		vendor_set_uid(RealUid);
4571c2aa98e2SPeter Wemm 		if (setuid(RealUid) < 0 && suidwarn)
457206f25ae9SGregory Neil Shapiro 		{
4573c2aa98e2SPeter Wemm 			syserr("mailfile: setuid(%ld) failed", (long) RealUid);
457406f25ae9SGregory Neil Shapiro 			exit(EX_TEMPFAIL);
457506f25ae9SGregory Neil Shapiro 		}
457606f25ae9SGregory Neil Shapiro 
457706f25ae9SGregory Neil Shapiro 		if (tTd(11, 2))
457806f25ae9SGregory Neil Shapiro 			dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n",
457906f25ae9SGregory Neil Shapiro 				(int) getuid(), (int) geteuid(),
458006f25ae9SGregory Neil Shapiro 				(int) getgid(), (int) getegid());
458106f25ae9SGregory Neil Shapiro 
4582c2aa98e2SPeter Wemm 
4583c2aa98e2SPeter Wemm 		/* move into some "safe" directory */
4584c2aa98e2SPeter Wemm 		if (mailer->m_execdir != NULL)
4585c2aa98e2SPeter Wemm 		{
4586c2aa98e2SPeter Wemm 			char *q;
4587c2aa98e2SPeter Wemm 
4588c2aa98e2SPeter Wemm 			for (p = mailer->m_execdir; p != NULL; p = q)
4589c2aa98e2SPeter Wemm 			{
4590c2aa98e2SPeter Wemm 				q = strchr(p, ':');
4591c2aa98e2SPeter Wemm 				if (q != NULL)
4592c2aa98e2SPeter Wemm 					*q = '\0';
4593c2aa98e2SPeter Wemm 				expand(p, buf, sizeof buf, e);
4594c2aa98e2SPeter Wemm 				if (q != NULL)
4595c2aa98e2SPeter Wemm 					*q++ = ':';
4596c2aa98e2SPeter Wemm 				if (tTd(11, 20))
459706f25ae9SGregory Neil Shapiro 					dprintf("mailfile: trydir %s\n", buf);
4598c2aa98e2SPeter Wemm 				if (buf[0] != '\0' && chdir(buf) >= 0)
4599c2aa98e2SPeter Wemm 					break;
4600c2aa98e2SPeter Wemm 			}
4601c2aa98e2SPeter Wemm 		}
4602c2aa98e2SPeter Wemm 
460306f25ae9SGregory Neil Shapiro 		/*
460406f25ae9SGregory Neil Shapiro 		**  Recheck the file after we have assumed the ID of the
460506f25ae9SGregory Neil Shapiro 		**  delivery user to make sure we can deliver to it as
460606f25ae9SGregory Neil Shapiro 		**  that user.  This is necessary if sendmail is running
460706f25ae9SGregory Neil Shapiro 		**  as root and the file is on an NFS mount which treats
460806f25ae9SGregory Neil Shapiro 		**  root as nobody.
460906f25ae9SGregory Neil Shapiro 		*/
461006f25ae9SGregory Neil Shapiro 
461106f25ae9SGregory Neil Shapiro #if HASLSTAT
461206f25ae9SGregory Neil Shapiro 		if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
461306f25ae9SGregory Neil Shapiro 			err = stat(realfile, &stb);
461406f25ae9SGregory Neil Shapiro 		else
461506f25ae9SGregory Neil Shapiro 			err = lstat(realfile, &stb);
461606f25ae9SGregory Neil Shapiro #else /* HASLSTAT */
461706f25ae9SGregory Neil Shapiro 		err = stat(realfile, &stb);
461806f25ae9SGregory Neil Shapiro #endif /* HASLSTAT */
461906f25ae9SGregory Neil Shapiro 
462006f25ae9SGregory Neil Shapiro 		if (err < 0)
462106f25ae9SGregory Neil Shapiro 		{
462206f25ae9SGregory Neil Shapiro 			stb.st_mode = ST_MODE_NOFILE;
462306f25ae9SGregory Neil Shapiro 			mode = FileMode;
462406f25ae9SGregory Neil Shapiro 			oflags |= O_CREAT|O_EXCL;
462506f25ae9SGregory Neil Shapiro 		}
462606f25ae9SGregory Neil Shapiro 		else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) ||
462706f25ae9SGregory Neil Shapiro 			 (!bitnset(DBS_FILEDELIVERYTOHARDLINK,
462806f25ae9SGregory Neil Shapiro 				   DontBlameSendmail) &&
462906f25ae9SGregory Neil Shapiro 			  stb.st_nlink != 1) ||
463006f25ae9SGregory Neil Shapiro 			 (realfile != targetfile && !S_ISREG(mode)))
463106f25ae9SGregory Neil Shapiro 			exit(EX_CANTCREAT);
463206f25ae9SGregory Neil Shapiro 		else
463306f25ae9SGregory Neil Shapiro 			mode = stb.st_mode;
463406f25ae9SGregory Neil Shapiro 
463506f25ae9SGregory Neil Shapiro 		if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
4636c2aa98e2SPeter Wemm 			sfflags |= SFF_NOSLINK;
463706f25ae9SGregory Neil Shapiro 		if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail))
4638c2aa98e2SPeter Wemm 			sfflags |= SFF_NOHLINK;
4639c2aa98e2SPeter Wemm 		sfflags &= ~SFF_OPENASROOT;
464006f25ae9SGregory Neil Shapiro 		f = safefopen(realfile, oflags, mode, sfflags);
4641c2aa98e2SPeter Wemm 		if (f == NULL)
4642c2aa98e2SPeter Wemm 		{
464306f25ae9SGregory Neil Shapiro 			if (transienterror(errno))
464406f25ae9SGregory Neil Shapiro 			{
464506f25ae9SGregory Neil Shapiro 				usrerr("454 4.3.0 cannot open %s: %s",
464606f25ae9SGregory Neil Shapiro 				       shortenstring(realfile, MAXSHORTSTR),
464706f25ae9SGregory Neil Shapiro 				       errstring(errno));
464806f25ae9SGregory Neil Shapiro 				exit(EX_TEMPFAIL);
464906f25ae9SGregory Neil Shapiro 			}
465006f25ae9SGregory Neil Shapiro 			else
465106f25ae9SGregory Neil Shapiro 			{
465206f25ae9SGregory Neil Shapiro 				usrerr("554 5.3.0 cannot open %s: %s",
465306f25ae9SGregory Neil Shapiro 				       shortenstring(realfile, MAXSHORTSTR),
4654c2aa98e2SPeter Wemm 				       errstring(errno));
4655c2aa98e2SPeter Wemm 				exit(EX_CANTCREAT);
4656c2aa98e2SPeter Wemm 			}
465706f25ae9SGregory Neil Shapiro 		}
465806f25ae9SGregory Neil Shapiro 		if (filechanged(realfile, fileno(f), &stb))
4659c2aa98e2SPeter Wemm 		{
466006f25ae9SGregory Neil Shapiro 			syserr("554 5.3.0 file changed after open");
4661c2aa98e2SPeter Wemm 			exit(EX_CANTCREAT);
4662c2aa98e2SPeter Wemm 		}
4663c2aa98e2SPeter Wemm 		if (fstat(fileno(f), &stb) < 0)
4664c2aa98e2SPeter Wemm 		{
466506f25ae9SGregory Neil Shapiro 			syserr("554 5.3.0 cannot fstat %s", errstring(errno));
4666c2aa98e2SPeter Wemm 			exit(EX_CANTCREAT);
4667c2aa98e2SPeter Wemm 		}
4668c2aa98e2SPeter Wemm 
466906f25ae9SGregory Neil Shapiro 		curoff = stb.st_size;
467006f25ae9SGregory Neil Shapiro 
4671c2aa98e2SPeter Wemm 		if (ev != NULL)
4672c2aa98e2SPeter Wemm 			clrevent(ev);
4673c2aa98e2SPeter Wemm 
467406f25ae9SGregory Neil Shapiro 		memset(&mcibuf, '\0', sizeof mcibuf);
4675c2aa98e2SPeter Wemm 		mcibuf.mci_mailer = mailer;
4676c2aa98e2SPeter Wemm 		mcibuf.mci_out = f;
4677c2aa98e2SPeter Wemm 		if (bitnset(M_7BITS, mailer->m_flags))
4678c2aa98e2SPeter Wemm 			mcibuf.mci_flags |= MCIF_7BIT;
4679c2aa98e2SPeter Wemm 
4680c2aa98e2SPeter Wemm 		/* clear out per-message flags from connection structure */
4681c2aa98e2SPeter Wemm 		mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);
4682c2aa98e2SPeter Wemm 
4683c2aa98e2SPeter Wemm 		if (bitset(EF_HAS8BIT, e->e_flags) &&
4684c2aa98e2SPeter Wemm 		    !bitset(EF_DONT_MIME, e->e_flags) &&
4685c2aa98e2SPeter Wemm 		    bitnset(M_7BITS, mailer->m_flags))
4686c2aa98e2SPeter Wemm 			mcibuf.mci_flags |= MCIF_CVT8TO7;
4687c2aa98e2SPeter Wemm 
4688c2aa98e2SPeter Wemm #if MIME7TO8
4689c2aa98e2SPeter Wemm 		if (bitnset(M_MAKE8BIT, mailer->m_flags) &&
4690c2aa98e2SPeter Wemm 		    !bitset(MCIF_7BIT, mcibuf.mci_flags) &&
4691c2aa98e2SPeter Wemm 		    (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
4692c2aa98e2SPeter Wemm 		    (strcasecmp(p, "quoted-printable") == 0 ||
4693c2aa98e2SPeter Wemm 		     strcasecmp(p, "base64") == 0) &&
4694c2aa98e2SPeter Wemm 		    (p = hvalue("Content-Type", e->e_header)) != NULL)
4695c2aa98e2SPeter Wemm 		{
4696c2aa98e2SPeter Wemm 			/* may want to convert 7 -> 8 */
4697c2aa98e2SPeter Wemm 			/* XXX should really parse it here -- and use a class XXX */
4698c2aa98e2SPeter Wemm 			if (strncasecmp(p, "text/plain", 10) == 0 &&
4699c2aa98e2SPeter Wemm 			    (p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
4700c2aa98e2SPeter Wemm 				mcibuf.mci_flags |= MCIF_CVT7TO8;
4701c2aa98e2SPeter Wemm 		}
470206f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */
4703c2aa98e2SPeter Wemm 
4704c2aa98e2SPeter Wemm 		putfromline(&mcibuf, e);
47052e43090eSPeter Wemm 		(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
4706c2aa98e2SPeter Wemm 		(*e->e_putbody)(&mcibuf, e, NULL);
4707c2aa98e2SPeter Wemm 		putline("\n", &mcibuf);
470806f25ae9SGregory Neil Shapiro 		if (fflush(f) < 0 ||
470906f25ae9SGregory Neil Shapiro 		    (SuperSafe && fsync(fileno(f)) < 0) ||
471006f25ae9SGregory Neil Shapiro 		    ferror(f))
4711c2aa98e2SPeter Wemm 		{
4712c2aa98e2SPeter Wemm 			setstat(EX_IOERR);
471306f25ae9SGregory Neil Shapiro #if !NOFTRUNCATE
471406f25ae9SGregory Neil Shapiro 			(void) ftruncate(fileno(f), curoff);
471506f25ae9SGregory Neil Shapiro #endif /* !NOFTRUNCATE */
4716c2aa98e2SPeter Wemm 		}
4717c2aa98e2SPeter Wemm 
4718c2aa98e2SPeter Wemm 		/* reset ISUID & ISGID bits for paranoid systems */
4719c2aa98e2SPeter Wemm #if HASFCHMOD
472006f25ae9SGregory Neil Shapiro 		(void) fchmod(fileno(f), (MODE_T) mode);
472106f25ae9SGregory Neil Shapiro #else /* HASFCHMOD */
472206f25ae9SGregory Neil Shapiro 		(void) chmod(filename, (MODE_T) mode);
472306f25ae9SGregory Neil Shapiro #endif /* HASFCHMOD */
472406f25ae9SGregory Neil Shapiro 		if (fclose(f) < 0)
472506f25ae9SGregory Neil Shapiro 			setstat(EX_IOERR);
4726c2aa98e2SPeter Wemm 		(void) fflush(stdout);
472706f25ae9SGregory Neil Shapiro 		(void) setuid(RealUid);
4728c2aa98e2SPeter Wemm 		exit(ExitStat);
4729c2aa98e2SPeter Wemm 		/* NOTREACHED */
4730c2aa98e2SPeter Wemm 	}
4731c2aa98e2SPeter Wemm 	else
4732c2aa98e2SPeter Wemm 	{
4733c2aa98e2SPeter Wemm 		/* parent -- wait for exit status */
4734c2aa98e2SPeter Wemm 		int st;
4735c2aa98e2SPeter Wemm 
4736c2aa98e2SPeter Wemm 		st = waitfor(pid);
4737c2aa98e2SPeter Wemm 		if (st == -1)
4738c2aa98e2SPeter Wemm 		{
4739c2aa98e2SPeter Wemm 			syserr("mailfile: %s: wait", mailer->m_name);
474006f25ae9SGregory Neil Shapiro 			return EX_SOFTWARE;
4741c2aa98e2SPeter Wemm 		}
4742c2aa98e2SPeter Wemm 		if (WIFEXITED(st))
4743c2aa98e2SPeter Wemm 			return (WEXITSTATUS(st));
4744c2aa98e2SPeter Wemm 		else
4745c2aa98e2SPeter Wemm 		{
4746c2aa98e2SPeter Wemm 			syserr("mailfile: %s: child died on signal %d",
4747c2aa98e2SPeter Wemm 			       mailer->m_name, st);
474806f25ae9SGregory Neil Shapiro 			return EX_UNAVAILABLE;
4749c2aa98e2SPeter Wemm 		}
4750c2aa98e2SPeter Wemm 		/* NOTREACHED */
4751c2aa98e2SPeter Wemm 	}
4752c2aa98e2SPeter Wemm 	return EX_UNAVAILABLE;	/* avoid compiler warning on IRIX */
4753c2aa98e2SPeter Wemm }
4754c2aa98e2SPeter Wemm 
4755c2aa98e2SPeter Wemm static void
4756c2aa98e2SPeter Wemm mailfiletimeout()
4757c2aa98e2SPeter Wemm {
4758c2aa98e2SPeter Wemm 	longjmp(CtxMailfileTimeout, 1);
4759c2aa98e2SPeter Wemm }
4760c2aa98e2SPeter Wemm /*
4761c2aa98e2SPeter Wemm **  HOSTSIGNATURE -- return the "signature" for a host.
4762c2aa98e2SPeter Wemm **
4763c2aa98e2SPeter Wemm **	The signature describes how we are going to send this -- it
4764c2aa98e2SPeter Wemm **	can be just the hostname (for non-Internet hosts) or can be
4765c2aa98e2SPeter Wemm **	an ordered list of MX hosts.
4766c2aa98e2SPeter Wemm **
4767c2aa98e2SPeter Wemm **	Parameters:
4768c2aa98e2SPeter Wemm **		m -- the mailer describing this host.
4769c2aa98e2SPeter Wemm **		host -- the host name.
4770c2aa98e2SPeter Wemm **
4771c2aa98e2SPeter Wemm **	Returns:
4772c2aa98e2SPeter Wemm **		The signature for this host.
4773c2aa98e2SPeter Wemm **
4774c2aa98e2SPeter Wemm **	Side Effects:
4775c2aa98e2SPeter Wemm **		Can tweak the symbol table.
4776c2aa98e2SPeter Wemm */
477706f25ae9SGregory Neil Shapiro #define MAXHOSTSIGNATURE	8192	/* max len of hostsignature */
4778c2aa98e2SPeter Wemm 
477906f25ae9SGregory Neil Shapiro static char *
478006f25ae9SGregory Neil Shapiro hostsignature(m, host)
4781c2aa98e2SPeter Wemm 	register MAILER *m;
4782c2aa98e2SPeter Wemm 	char *host;
4783c2aa98e2SPeter Wemm {
4784c2aa98e2SPeter Wemm 	register char *p;
4785c2aa98e2SPeter Wemm 	register STAB *s;
478606f25ae9SGregory Neil Shapiro #if NAMED_BIND
478706f25ae9SGregory Neil Shapiro 	char sep = ':';
478806f25ae9SGregory Neil Shapiro 	char prevsep = ':';
4789c2aa98e2SPeter Wemm 	int i;
4790c2aa98e2SPeter Wemm 	int len;
4791c2aa98e2SPeter Wemm 	int nmx;
479206f25ae9SGregory Neil Shapiro 	int hl;
4793193538b7SGregory Neil Shapiro 	time_t now;
4794c2aa98e2SPeter Wemm 	char *hp;
4795c2aa98e2SPeter Wemm 	char *endp;
4796c2aa98e2SPeter Wemm 	int oldoptions = _res.options;
4797c2aa98e2SPeter Wemm 	char *mxhosts[MAXMXHOSTS + 1];
479806f25ae9SGregory Neil Shapiro 	u_short mxprefs[MAXMXHOSTS + 1];
479906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
480006f25ae9SGregory Neil Shapiro 
480106f25ae9SGregory Neil Shapiro 	if (tTd(17, 3))
480206f25ae9SGregory Neil Shapiro 		dprintf("hostsignature(%s)\n", host);
480306f25ae9SGregory Neil Shapiro 
480406f25ae9SGregory Neil Shapiro 	/*
480506f25ae9SGregory Neil Shapiro 	**  If local delivery, just return a constant.
480606f25ae9SGregory Neil Shapiro 	*/
480706f25ae9SGregory Neil Shapiro 
480806f25ae9SGregory Neil Shapiro 	if (bitnset(M_LOCALMAILER, m->m_flags))
480906f25ae9SGregory Neil Shapiro 		return "localhost";
4810c2aa98e2SPeter Wemm 
4811c2aa98e2SPeter Wemm 	/*
4812c2aa98e2SPeter Wemm 	**  Check to see if this uses IPC -- if not, it can't have MX records.
4813c2aa98e2SPeter Wemm 	*/
4814c2aa98e2SPeter Wemm 
4815c2aa98e2SPeter Wemm 	p = m->m_mailer;
481606f25ae9SGregory Neil Shapiro 	if (strcmp(p, "[IPC]") != 0 &&
481706f25ae9SGregory Neil Shapiro 	    strcmp(p, "[TCP]") != 0)
4818c2aa98e2SPeter Wemm 	{
4819c2aa98e2SPeter Wemm 		/* just an ordinary mailer */
4820c2aa98e2SPeter Wemm 		return host;
4821c2aa98e2SPeter Wemm 	}
482206f25ae9SGregory Neil Shapiro #if NETUNIX
482306f25ae9SGregory Neil Shapiro 	else if (m->m_argv[0] != NULL &&
482406f25ae9SGregory Neil Shapiro 		 strcmp(m->m_argv[0], "FILE") == 0)
482506f25ae9SGregory Neil Shapiro 	{
482606f25ae9SGregory Neil Shapiro 		/* rendezvous in the file system, no MX records */
482706f25ae9SGregory Neil Shapiro 		return host;
482806f25ae9SGregory Neil Shapiro 	}
482906f25ae9SGregory Neil Shapiro #endif /* NETUNIX */
4830c2aa98e2SPeter Wemm 
4831c2aa98e2SPeter Wemm 	/*
4832c2aa98e2SPeter Wemm 	**  Look it up in the symbol table.
4833c2aa98e2SPeter Wemm 	*/
4834c2aa98e2SPeter Wemm 
4835c2aa98e2SPeter Wemm 	s = stab(host, ST_HOSTSIG, ST_ENTER);
4836c2aa98e2SPeter Wemm 	if (s->s_hostsig != NULL)
483706f25ae9SGregory Neil Shapiro 	{
483806f25ae9SGregory Neil Shapiro 		if (tTd(17, 3))
483906f25ae9SGregory Neil Shapiro 			dprintf("hostsignature(): stab(%s) found %s\n", host,
484006f25ae9SGregory Neil Shapiro 				s->s_hostsig);
4841c2aa98e2SPeter Wemm 		return s->s_hostsig;
484206f25ae9SGregory Neil Shapiro 	}
4843c2aa98e2SPeter Wemm 
4844c2aa98e2SPeter Wemm 	/*
4845c2aa98e2SPeter Wemm 	**  Not already there -- create a signature.
4846c2aa98e2SPeter Wemm 	*/
4847c2aa98e2SPeter Wemm 
4848c2aa98e2SPeter Wemm #if NAMED_BIND
4849c2aa98e2SPeter Wemm 	if (ConfigLevel < 2)
4850c2aa98e2SPeter Wemm 		_res.options &= ~(RES_DEFNAMES | RES_DNSRCH);	/* XXX */
4851c2aa98e2SPeter Wemm 
4852193538b7SGregory Neil Shapiro 	now = curtime();
4853c2aa98e2SPeter Wemm 	for (hp = host; hp != NULL; hp = endp)
4854c2aa98e2SPeter Wemm 	{
485506f25ae9SGregory Neil Shapiro #if NETINET6
485606f25ae9SGregory Neil Shapiro 		if (*hp == '[')
485706f25ae9SGregory Neil Shapiro 		{
485806f25ae9SGregory Neil Shapiro 			endp = strchr(hp + 1, ']');
4859c2aa98e2SPeter Wemm 			if (endp != NULL)
486006f25ae9SGregory Neil Shapiro 				endp = strpbrk(endp + 1, ":,");
486106f25ae9SGregory Neil Shapiro 		}
486206f25ae9SGregory Neil Shapiro 		else
486306f25ae9SGregory Neil Shapiro 			endp = strpbrk(hp, ":,");
486406f25ae9SGregory Neil Shapiro #else /* NETINET6 */
486506f25ae9SGregory Neil Shapiro 		endp = strpbrk(hp, ":,");
486606f25ae9SGregory Neil Shapiro #endif /* NETINET6 */
486706f25ae9SGregory Neil Shapiro 		if (endp != NULL)
486806f25ae9SGregory Neil Shapiro 		{
486906f25ae9SGregory Neil Shapiro 			sep = *endp;
4870c2aa98e2SPeter Wemm 			*endp = '\0';
487106f25ae9SGregory Neil Shapiro 		}
4872c2aa98e2SPeter Wemm 
4873c2aa98e2SPeter Wemm 		if (bitnset(M_NOMX, m->m_flags))
4874c2aa98e2SPeter Wemm 		{
4875c2aa98e2SPeter Wemm 			/* skip MX lookups */
4876c2aa98e2SPeter Wemm 			nmx = 1;
4877c2aa98e2SPeter Wemm 			mxhosts[0] = hp;
4878c2aa98e2SPeter Wemm 		}
4879c2aa98e2SPeter Wemm 		else
4880c2aa98e2SPeter Wemm 		{
4881c2aa98e2SPeter Wemm 			auto int rcode;
4882c2aa98e2SPeter Wemm 
488306f25ae9SGregory Neil Shapiro 			nmx = getmxrr(hp, mxhosts, mxprefs, TRUE, &rcode);
4884c2aa98e2SPeter Wemm 			if (nmx <= 0)
4885c2aa98e2SPeter Wemm 			{
4886c2aa98e2SPeter Wemm 				register MCI *mci;
4887c2aa98e2SPeter Wemm 
4888c2aa98e2SPeter Wemm 				/* update the connection info for this host */
4889c2aa98e2SPeter Wemm 				mci = mci_get(hp, m);
4890c2aa98e2SPeter Wemm 				mci->mci_errno = errno;
4891c2aa98e2SPeter Wemm 				mci->mci_herrno = h_errno;
4892193538b7SGregory Neil Shapiro 				mci->mci_lastuse = now;
489306f25ae9SGregory Neil Shapiro 				if (rcode == EX_NOHOST)
489406f25ae9SGregory Neil Shapiro 					mci_setstat(mci, rcode, "5.1.2",
489506f25ae9SGregory Neil Shapiro 						"550 Host unknown");
489606f25ae9SGregory Neil Shapiro 				else
4897c2aa98e2SPeter Wemm 					mci_setstat(mci, rcode, NULL, NULL);
4898c2aa98e2SPeter Wemm 
4899c2aa98e2SPeter Wemm 				/* use the original host name as signature */
4900c2aa98e2SPeter Wemm 				nmx = 1;
4901c2aa98e2SPeter Wemm 				mxhosts[0] = hp;
4902c2aa98e2SPeter Wemm 			}
490306f25ae9SGregory Neil Shapiro 			if (tTd(17, 3))
490406f25ae9SGregory Neil Shapiro 				dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n",
490506f25ae9SGregory Neil Shapiro 					nmx, mxhosts[0]);
4906c2aa98e2SPeter Wemm 		}
4907c2aa98e2SPeter Wemm 
4908c2aa98e2SPeter Wemm 		len = 0;
4909c2aa98e2SPeter Wemm 		for (i = 0; i < nmx; i++)
4910c2aa98e2SPeter Wemm 			len += strlen(mxhosts[i]) + 1;
4911c2aa98e2SPeter Wemm 		if (s->s_hostsig != NULL)
4912c2aa98e2SPeter Wemm 			len += strlen(s->s_hostsig) + 1;
491306f25ae9SGregory Neil Shapiro 		if (len >= MAXHOSTSIGNATURE)
491406f25ae9SGregory Neil Shapiro 		{
491506f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d",
491606f25ae9SGregory Neil Shapiro 				  host, MAXHOSTSIGNATURE, len);
491706f25ae9SGregory Neil Shapiro 			len = MAXHOSTSIGNATURE;
491806f25ae9SGregory Neil Shapiro 		}
4919c2aa98e2SPeter Wemm 		p = xalloc(len);
4920c2aa98e2SPeter Wemm 		if (s->s_hostsig != NULL)
4921c2aa98e2SPeter Wemm 		{
492206f25ae9SGregory Neil Shapiro 			(void) strlcpy(p, s->s_hostsig, len);
4923c2aa98e2SPeter Wemm 			free(s->s_hostsig);
4924c2aa98e2SPeter Wemm 			s->s_hostsig = p;
492506f25ae9SGregory Neil Shapiro 			hl = strlen(p);
492606f25ae9SGregory Neil Shapiro 			p += hl;
492706f25ae9SGregory Neil Shapiro 			*p++ = prevsep;
492806f25ae9SGregory Neil Shapiro 			len -= hl + 1;
4929c2aa98e2SPeter Wemm 		}
4930c2aa98e2SPeter Wemm 		else
4931c2aa98e2SPeter Wemm 			s->s_hostsig = p;
4932c2aa98e2SPeter Wemm 		for (i = 0; i < nmx; i++)
4933c2aa98e2SPeter Wemm 		{
493406f25ae9SGregory Neil Shapiro 			hl = strlen(mxhosts[i]);
493506f25ae9SGregory Neil Shapiro 			if (len - 1 < hl || len <= 1)
493606f25ae9SGregory Neil Shapiro 			{
493706f25ae9SGregory Neil Shapiro 				/* force to drop out of outer loop */
493806f25ae9SGregory Neil Shapiro 				len = -1;
493906f25ae9SGregory Neil Shapiro 				break;
4940c2aa98e2SPeter Wemm 			}
494106f25ae9SGregory Neil Shapiro 			if (i != 0)
494206f25ae9SGregory Neil Shapiro 			{
494306f25ae9SGregory Neil Shapiro 				if (mxprefs[i] == mxprefs[i - 1])
494406f25ae9SGregory Neil Shapiro 					*p++ = ',';
494506f25ae9SGregory Neil Shapiro 				else
494606f25ae9SGregory Neil Shapiro 					*p++ = ':';
494706f25ae9SGregory Neil Shapiro 				len--;
494806f25ae9SGregory Neil Shapiro 			}
494906f25ae9SGregory Neil Shapiro 			(void) strlcpy(p, mxhosts[i], len);
495006f25ae9SGregory Neil Shapiro 			p += hl;
495106f25ae9SGregory Neil Shapiro 			len -= hl;
495206f25ae9SGregory Neil Shapiro 		}
495306f25ae9SGregory Neil Shapiro 
495406f25ae9SGregory Neil Shapiro 		/*
495506f25ae9SGregory Neil Shapiro 		**  break out of loop if len exceeded MAXHOSTSIGNATURE
495606f25ae9SGregory Neil Shapiro 		**  because we won't have more space for further hosts
495706f25ae9SGregory Neil Shapiro 		**  anyway (separated by : in the .cf file).
495806f25ae9SGregory Neil Shapiro 		*/
495906f25ae9SGregory Neil Shapiro 
496006f25ae9SGregory Neil Shapiro 		if (len < 0)
496106f25ae9SGregory Neil Shapiro 			break;
4962c2aa98e2SPeter Wemm 		if (endp != NULL)
496306f25ae9SGregory Neil Shapiro 			*endp++ = sep;
496406f25ae9SGregory Neil Shapiro 		prevsep = sep;
4965c2aa98e2SPeter Wemm 	}
4966c2aa98e2SPeter Wemm 	makelower(s->s_hostsig);
4967c2aa98e2SPeter Wemm 	if (ConfigLevel < 2)
4968c2aa98e2SPeter Wemm 		_res.options = oldoptions;
496906f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */
4970c2aa98e2SPeter Wemm 	/* not using BIND -- the signature is just the host name */
4971c2aa98e2SPeter Wemm 	s->s_hostsig = host;
497206f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
4973c2aa98e2SPeter Wemm 	if (tTd(17, 1))
497406f25ae9SGregory Neil Shapiro 		dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig);
4975c2aa98e2SPeter Wemm 	return s->s_hostsig;
4976c2aa98e2SPeter Wemm }
497706f25ae9SGregory Neil Shapiro /*
497806f25ae9SGregory Neil Shapiro **  PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array.
497906f25ae9SGregory Neil Shapiro **
498006f25ae9SGregory Neil Shapiro **	The signature describes how we are going to send this -- it
498106f25ae9SGregory Neil Shapiro **	can be just the hostname (for non-Internet hosts) or can be
498206f25ae9SGregory Neil Shapiro **	an ordered list of MX hosts which must be randomized for equal
498306f25ae9SGregory Neil Shapiro **	MX preference values.
498406f25ae9SGregory Neil Shapiro **
498506f25ae9SGregory Neil Shapiro **	Parameters:
498606f25ae9SGregory Neil Shapiro **		sig -- the host signature.
498706f25ae9SGregory Neil Shapiro **		mxhosts -- array to populate.
498806f25ae9SGregory Neil Shapiro **
498906f25ae9SGregory Neil Shapiro **	Returns:
499006f25ae9SGregory Neil Shapiro **		The number of hosts inserted into mxhosts array.
499106f25ae9SGregory Neil Shapiro **
499206f25ae9SGregory Neil Shapiro **	Side Effects:
499306f25ae9SGregory Neil Shapiro **		Randomizes equal MX preference hosts in mxhosts.
499406f25ae9SGregory Neil Shapiro */
499506f25ae9SGregory Neil Shapiro 
499606f25ae9SGregory Neil Shapiro static int
499706f25ae9SGregory Neil Shapiro parse_hostsignature(sig, mxhosts, mailer)
499806f25ae9SGregory Neil Shapiro 	char *sig;
499906f25ae9SGregory Neil Shapiro 	char **mxhosts;
500006f25ae9SGregory Neil Shapiro 	MAILER *mailer;
500106f25ae9SGregory Neil Shapiro {
500206f25ae9SGregory Neil Shapiro 	int nmx = 0;
500306f25ae9SGregory Neil Shapiro 	int curpref = 0;
500406f25ae9SGregory Neil Shapiro 	int i, j;
500506f25ae9SGregory Neil Shapiro 	char *hp, *endp;
500606f25ae9SGregory Neil Shapiro 	u_short prefer[MAXMXHOSTS];
500706f25ae9SGregory Neil Shapiro 	long rndm[MAXMXHOSTS];
500806f25ae9SGregory Neil Shapiro 
500906f25ae9SGregory Neil Shapiro 	for (hp = sig; hp != NULL; hp = endp)
501006f25ae9SGregory Neil Shapiro 	{
501106f25ae9SGregory Neil Shapiro 		char sep = ':';
501206f25ae9SGregory Neil Shapiro 
501306f25ae9SGregory Neil Shapiro #if NETINET6
501406f25ae9SGregory Neil Shapiro 		if (*hp == '[')
501506f25ae9SGregory Neil Shapiro 		{
501606f25ae9SGregory Neil Shapiro 			endp = strchr(hp + 1, ']');
501706f25ae9SGregory Neil Shapiro 			if (endp != NULL)
501806f25ae9SGregory Neil Shapiro 				endp = strpbrk(endp + 1, ":,");
501906f25ae9SGregory Neil Shapiro 		}
502006f25ae9SGregory Neil Shapiro 		else
502106f25ae9SGregory Neil Shapiro 			endp = strpbrk(hp, ":,");
502206f25ae9SGregory Neil Shapiro #else /* NETINET6 */
502306f25ae9SGregory Neil Shapiro 		endp = strpbrk(hp, ":,");
502406f25ae9SGregory Neil Shapiro #endif /* NETINET6 */
502506f25ae9SGregory Neil Shapiro 		if (endp != NULL)
502606f25ae9SGregory Neil Shapiro 		{
502706f25ae9SGregory Neil Shapiro 			sep = *endp;
502806f25ae9SGregory Neil Shapiro 			*endp = '\0';
502906f25ae9SGregory Neil Shapiro 		}
503006f25ae9SGregory Neil Shapiro 
503106f25ae9SGregory Neil Shapiro 		mxhosts[nmx] = hp;
503206f25ae9SGregory Neil Shapiro 		prefer[nmx] = curpref;
503306f25ae9SGregory Neil Shapiro 		if (mci_match(hp, mailer))
503406f25ae9SGregory Neil Shapiro 			rndm[nmx] = 0;
503506f25ae9SGregory Neil Shapiro 		else
503606f25ae9SGregory Neil Shapiro 			rndm[nmx] = get_random();
503706f25ae9SGregory Neil Shapiro 
503806f25ae9SGregory Neil Shapiro 		if (endp != NULL)
503906f25ae9SGregory Neil Shapiro 		{
504006f25ae9SGregory Neil Shapiro 			/*
504106f25ae9SGregory Neil Shapiro 			**  Since we don't have the original MX prefs,
504206f25ae9SGregory Neil Shapiro 			**  make our own.  If the separator is a ':', that
504306f25ae9SGregory Neil Shapiro 			**  means the preference for the next host will be
504406f25ae9SGregory Neil Shapiro 			**  higher than this one, so simply increment curpref.
504506f25ae9SGregory Neil Shapiro 			*/
504606f25ae9SGregory Neil Shapiro 
504706f25ae9SGregory Neil Shapiro 			if (sep == ':')
504806f25ae9SGregory Neil Shapiro 				curpref++;
504906f25ae9SGregory Neil Shapiro 
505006f25ae9SGregory Neil Shapiro 			*endp++ = sep;
505106f25ae9SGregory Neil Shapiro 		}
505206f25ae9SGregory Neil Shapiro 		if (++nmx >= MAXMXHOSTS)
505306f25ae9SGregory Neil Shapiro 			break;
505406f25ae9SGregory Neil Shapiro 	}
505506f25ae9SGregory Neil Shapiro 
505606f25ae9SGregory Neil Shapiro 	/* sort the records using the random factor for equal preferences */
505706f25ae9SGregory Neil Shapiro 	for (i = 0; i < nmx; i++)
505806f25ae9SGregory Neil Shapiro 	{
505906f25ae9SGregory Neil Shapiro 		for (j = i + 1; j < nmx; j++)
506006f25ae9SGregory Neil Shapiro 		{
506106f25ae9SGregory Neil Shapiro 			/*
506206f25ae9SGregory Neil Shapiro 			**  List is already sorted by MX preference, only
506306f25ae9SGregory Neil Shapiro 			**  need to look for equal preference MX records
506406f25ae9SGregory Neil Shapiro 			*/
506506f25ae9SGregory Neil Shapiro 
506606f25ae9SGregory Neil Shapiro 			if (prefer[i] < prefer[j])
506706f25ae9SGregory Neil Shapiro 				break;
506806f25ae9SGregory Neil Shapiro 
506906f25ae9SGregory Neil Shapiro 			if (prefer[i] > prefer[j] ||
507006f25ae9SGregory Neil Shapiro 			    (prefer[i] == prefer[j] && rndm[i] > rndm[j]))
507106f25ae9SGregory Neil Shapiro 			{
507206f25ae9SGregory Neil Shapiro 				register u_short tempp;
507306f25ae9SGregory Neil Shapiro 				register long tempr;
507406f25ae9SGregory Neil Shapiro 				register char *temp1;
507506f25ae9SGregory Neil Shapiro 
507606f25ae9SGregory Neil Shapiro 				tempp = prefer[i];
507706f25ae9SGregory Neil Shapiro 				prefer[i] = prefer[j];
507806f25ae9SGregory Neil Shapiro 				prefer[j] = tempp;
507906f25ae9SGregory Neil Shapiro 				temp1 = mxhosts[i];
508006f25ae9SGregory Neil Shapiro 				mxhosts[i] = mxhosts[j];
508106f25ae9SGregory Neil Shapiro 				mxhosts[j] = temp1;
508206f25ae9SGregory Neil Shapiro 				tempr = rndm[i];
508306f25ae9SGregory Neil Shapiro 				rndm[i] = rndm[j];
508406f25ae9SGregory Neil Shapiro 				rndm[j] = tempr;
508506f25ae9SGregory Neil Shapiro 			}
508606f25ae9SGregory Neil Shapiro 		}
508706f25ae9SGregory Neil Shapiro 	}
508806f25ae9SGregory Neil Shapiro 	return nmx;
508906f25ae9SGregory Neil Shapiro }
509006f25ae9SGregory Neil Shapiro 
509106f25ae9SGregory Neil Shapiro #if SMTP
509206f25ae9SGregory Neil Shapiro # if STARTTLS
509306f25ae9SGregory Neil Shapiro static SSL_CTX	*clt_ctx = NULL;
509406f25ae9SGregory Neil Shapiro 
509506f25ae9SGregory Neil Shapiro /*
509606f25ae9SGregory Neil Shapiro **  INITCLTTLS -- initialize client side TLS
509706f25ae9SGregory Neil Shapiro **
509806f25ae9SGregory Neil Shapiro **	Parameters:
509906f25ae9SGregory Neil Shapiro **		none.
510006f25ae9SGregory Neil Shapiro **
510106f25ae9SGregory Neil Shapiro **	Returns:
510206f25ae9SGregory Neil Shapiro **		succeeded?
510306f25ae9SGregory Neil Shapiro */
510406f25ae9SGregory Neil Shapiro 
510506f25ae9SGregory Neil Shapiro bool
510606f25ae9SGregory Neil Shapiro initclttls()
510706f25ae9SGregory Neil Shapiro {
510806f25ae9SGregory Neil Shapiro 	if (clt_ctx != NULL)
510906f25ae9SGregory Neil Shapiro 		return TRUE;	/* already done */
511006f25ae9SGregory Neil Shapiro 	return inittls(&clt_ctx, TLS_I_CLT, FALSE, CltCERTfile, Cltkeyfile,
511106f25ae9SGregory Neil Shapiro 		       CACERTpath, CACERTfile, DHParams);
511206f25ae9SGregory Neil Shapiro }
511306f25ae9SGregory Neil Shapiro 
511406f25ae9SGregory Neil Shapiro /*
511506f25ae9SGregory Neil Shapiro **  STARTTLS -- try to start secure connection (client side)
511606f25ae9SGregory Neil Shapiro **
511706f25ae9SGregory Neil Shapiro **	Parameters:
511806f25ae9SGregory Neil Shapiro **		m -- the mailer.
511906f25ae9SGregory Neil Shapiro **		mci -- the mailer connection info.
512006f25ae9SGregory Neil Shapiro **		e -- the envelope.
512106f25ae9SGregory Neil Shapiro **
512206f25ae9SGregory Neil Shapiro **	Returns:
512306f25ae9SGregory Neil Shapiro **		success?
512406f25ae9SGregory Neil Shapiro **		(maybe this should be some other code than EX_
512506f25ae9SGregory Neil Shapiro **		that denotes which stage failed.)
512606f25ae9SGregory Neil Shapiro */
512706f25ae9SGregory Neil Shapiro 
512806f25ae9SGregory Neil Shapiro static int
512906f25ae9SGregory Neil Shapiro starttls(m, mci, e)
513006f25ae9SGregory Neil Shapiro 	MAILER *m;
513106f25ae9SGregory Neil Shapiro 	MCI *mci;
513206f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
513306f25ae9SGregory Neil Shapiro {
513406f25ae9SGregory Neil Shapiro 	int smtpresult;
513542e5d165SGregory Neil Shapiro 	int result = 0;
513642e5d165SGregory Neil Shapiro 	int rfd, wfd;
513706f25ae9SGregory Neil Shapiro 	SSL *clt_ssl = NULL;
513806f25ae9SGregory Neil Shapiro 
513942e5d165SGregory Neil Shapiro 	if (clt_ctx == NULL && !initclttls())
514042e5d165SGregory Neil Shapiro 		return EX_TEMPFAIL;
514106f25ae9SGregory Neil Shapiro 	smtpmessage("STARTTLS", m, mci);
514206f25ae9SGregory Neil Shapiro 
514306f25ae9SGregory Neil Shapiro 	/* get the reply */
514406f25ae9SGregory Neil Shapiro 	smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, NULL, NULL);
514506f25ae9SGregory Neil Shapiro 	/* which timeout? XXX */
514606f25ae9SGregory Neil Shapiro 
514706f25ae9SGregory Neil Shapiro 	/* check return code from server */
514806f25ae9SGregory Neil Shapiro 	if (smtpresult == 454)
514906f25ae9SGregory Neil Shapiro 		return EX_TEMPFAIL;
515006f25ae9SGregory Neil Shapiro 	if (smtpresult == 501)
515106f25ae9SGregory Neil Shapiro 		return EX_USAGE;
515206f25ae9SGregory Neil Shapiro 	if (smtpresult == -1)
515306f25ae9SGregory Neil Shapiro 		return smtpresult;
515406f25ae9SGregory Neil Shapiro 	if (smtpresult != 220)
515506f25ae9SGregory Neil Shapiro 		return EX_PROTOCOL;
515606f25ae9SGregory Neil Shapiro 
515706f25ae9SGregory Neil Shapiro 	if (LogLevel > 13)
515806f25ae9SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "TLS: start client");
515906f25ae9SGregory Neil Shapiro 
516006f25ae9SGregory Neil Shapiro 	/* start connection */
516106f25ae9SGregory Neil Shapiro 	if ((clt_ssl = SSL_new(clt_ctx)) == NULL)
516206f25ae9SGregory Neil Shapiro 	{
516306f25ae9SGregory Neil Shapiro 		if (LogLevel > 5)
516406f25ae9SGregory Neil Shapiro 		{
516506f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
516606f25ae9SGregory Neil Shapiro 				  "TLS: error: client: SSL_new failed");
516706f25ae9SGregory Neil Shapiro 			if (LogLevel > 9)
516806f25ae9SGregory Neil Shapiro 				tlslogerr();
516906f25ae9SGregory Neil Shapiro 		}
517006f25ae9SGregory Neil Shapiro 		return EX_SOFTWARE;
517106f25ae9SGregory Neil Shapiro 	}
517206f25ae9SGregory Neil Shapiro 
517342e5d165SGregory Neil Shapiro 	rfd = fileno(mci->mci_in);
517442e5d165SGregory Neil Shapiro 	wfd = fileno(mci->mci_out);
517542e5d165SGregory Neil Shapiro 
517606f25ae9SGregory Neil Shapiro 	/* SSL_clear(clt_ssl); ? */
517742e5d165SGregory Neil Shapiro 	if (rfd < 0 || wfd < 0 ||
517842e5d165SGregory Neil Shapiro 	    (result = SSL_set_rfd(clt_ssl, rfd)) <= 0 ||
517942e5d165SGregory Neil Shapiro 	    (result = SSL_set_wfd(clt_ssl, wfd)) <= 0)
518006f25ae9SGregory Neil Shapiro 	{
518106f25ae9SGregory Neil Shapiro 		if (LogLevel > 5)
518206f25ae9SGregory Neil Shapiro 		{
518306f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
518406f25ae9SGregory Neil Shapiro 				  "TLS: error: SSL_set_xfd failed=%d", result);
518506f25ae9SGregory Neil Shapiro 			if (LogLevel > 9)
518606f25ae9SGregory Neil Shapiro 				tlslogerr();
518706f25ae9SGregory Neil Shapiro 		}
518806f25ae9SGregory Neil Shapiro 		return EX_SOFTWARE;
518906f25ae9SGregory Neil Shapiro 	}
519006f25ae9SGregory Neil Shapiro 	SSL_set_connect_state(clt_ssl);
519106f25ae9SGregory Neil Shapiro 	if ((result = SSL_connect(clt_ssl)) <= 0)
519206f25ae9SGregory Neil Shapiro 	{
519306f25ae9SGregory Neil Shapiro 		int i;
519406f25ae9SGregory Neil Shapiro 
519506f25ae9SGregory Neil Shapiro 		/* what to do in this case? */
519606f25ae9SGregory Neil Shapiro 		i = SSL_get_error(clt_ssl, result);
519706f25ae9SGregory Neil Shapiro 		if (LogLevel > 5)
519806f25ae9SGregory Neil Shapiro 		{
519906f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
520006f25ae9SGregory Neil Shapiro 				  "TLS: error: SSL_connect failed=%d (%d)",
520106f25ae9SGregory Neil Shapiro 				  result, i);
520206f25ae9SGregory Neil Shapiro 			if (LogLevel > 9)
520306f25ae9SGregory Neil Shapiro 				tlslogerr();
520406f25ae9SGregory Neil Shapiro 		}
520506f25ae9SGregory Neil Shapiro 		SSL_free(clt_ssl);
520606f25ae9SGregory Neil Shapiro 		clt_ssl = NULL;
520706f25ae9SGregory Neil Shapiro 		return EX_SOFTWARE;
520806f25ae9SGregory Neil Shapiro 	}
520906f25ae9SGregory Neil Shapiro 	mci->mci_ssl = clt_ssl;
5210193538b7SGregory Neil Shapiro 	result = tls_get_info(clt_ssl, e, FALSE, mci->mci_host, TRUE);
521106f25ae9SGregory Neil Shapiro 
521206f25ae9SGregory Neil Shapiro 	/* switch to use SSL... */
521306f25ae9SGregory Neil Shapiro #if SFIO
521406f25ae9SGregory Neil Shapiro 	if (sfdctls(mci->mci_in, mci->mci_out, mci->mci_ssl) == 0)
521506f25ae9SGregory Neil Shapiro 		return EX_OK;
521606f25ae9SGregory Neil Shapiro #else /* SFIO */
521706f25ae9SGregory Neil Shapiro # if _FFR_TLS_TOREK
521806f25ae9SGregory Neil Shapiro 	if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0)
521906f25ae9SGregory Neil Shapiro 		return EX_OK;
522006f25ae9SGregory Neil Shapiro # endif /* _FFR_TLS_TOREK */
522106f25ae9SGregory Neil Shapiro #endif /* SFIO */
522206f25ae9SGregory Neil Shapiro 
522306f25ae9SGregory Neil Shapiro 	/* failure */
522406f25ae9SGregory Neil Shapiro 	SSL_free(clt_ssl);
522506f25ae9SGregory Neil Shapiro 	clt_ssl = NULL;
522606f25ae9SGregory Neil Shapiro 	return EX_SOFTWARE;
522706f25ae9SGregory Neil Shapiro }
522806f25ae9SGregory Neil Shapiro 
522906f25ae9SGregory Neil Shapiro /*
523006f25ae9SGregory Neil Shapiro **  ENDTLSCLT -- shutdown secure connection (client side)
523106f25ae9SGregory Neil Shapiro **
523206f25ae9SGregory Neil Shapiro **	Parameters:
523306f25ae9SGregory Neil Shapiro **		mci -- the mailer connection info.
523406f25ae9SGregory Neil Shapiro **
523506f25ae9SGregory Neil Shapiro **	Returns:
523606f25ae9SGregory Neil Shapiro **		success?
523706f25ae9SGregory Neil Shapiro */
523806f25ae9SGregory Neil Shapiro int
523906f25ae9SGregory Neil Shapiro endtlsclt(mci)
524006f25ae9SGregory Neil Shapiro 	MCI *mci;
524106f25ae9SGregory Neil Shapiro {
524206f25ae9SGregory Neil Shapiro 	int r;
524306f25ae9SGregory Neil Shapiro 
524406f25ae9SGregory Neil Shapiro 	if (!bitset(MCIF_TLSACT, mci->mci_flags))
524506f25ae9SGregory Neil Shapiro 		return EX_OK;
524606f25ae9SGregory Neil Shapiro 	r = endtls(mci->mci_ssl, "client");
524706f25ae9SGregory Neil Shapiro 	mci->mci_flags &= ~MCIF_TLSACT;
524806f25ae9SGregory Neil Shapiro 	return r;
524906f25ae9SGregory Neil Shapiro }
525006f25ae9SGregory Neil Shapiro /*
525106f25ae9SGregory Neil Shapiro **  ENDTLS -- shutdown secure connection
525206f25ae9SGregory Neil Shapiro **
525306f25ae9SGregory Neil Shapiro **	Parameters:
525406f25ae9SGregory Neil Shapiro **		ssl -- SSL connection information.
525506f25ae9SGregory Neil Shapiro **		side -- srv/clt (for logging).
525606f25ae9SGregory Neil Shapiro **
525706f25ae9SGregory Neil Shapiro **	Returns:
525806f25ae9SGregory Neil Shapiro **		success?
525906f25ae9SGregory Neil Shapiro */
526006f25ae9SGregory Neil Shapiro 
526106f25ae9SGregory Neil Shapiro int
526206f25ae9SGregory Neil Shapiro endtls(ssl, side)
526306f25ae9SGregory Neil Shapiro 	SSL *ssl;
526406f25ae9SGregory Neil Shapiro 	char *side;
526506f25ae9SGregory Neil Shapiro {
5266602a2b1bSGregory Neil Shapiro 	int ret = EX_OK;
5267602a2b1bSGregory Neil Shapiro 
526806f25ae9SGregory Neil Shapiro 	if (ssl != NULL)
526906f25ae9SGregory Neil Shapiro 	{
527006f25ae9SGregory Neil Shapiro 		int r;
527106f25ae9SGregory Neil Shapiro 
527206f25ae9SGregory Neil Shapiro 		if ((r = SSL_shutdown(ssl)) < 0)
527306f25ae9SGregory Neil Shapiro 		{
527406f25ae9SGregory Neil Shapiro 			if (LogLevel > 11)
527506f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_WARNING, NOQID,
527606f25ae9SGregory Neil Shapiro 					  "SSL_shutdown %s failed: %d",
527706f25ae9SGregory Neil Shapiro 					  side, r);
5278602a2b1bSGregory Neil Shapiro 			ret = EX_SOFTWARE;
527906f25ae9SGregory Neil Shapiro 		}
528006f25ae9SGregory Neil Shapiro 		else if (r == 0)
528106f25ae9SGregory Neil Shapiro 		{
528206f25ae9SGregory Neil Shapiro 			if (LogLevel > 13)
528306f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_WARNING, NOQID,
528406f25ae9SGregory Neil Shapiro 					  "SSL_shutdown %s not done",
528506f25ae9SGregory Neil Shapiro 					  side);
5286602a2b1bSGregory Neil Shapiro 			ret = EX_SOFTWARE;
528706f25ae9SGregory Neil Shapiro 		}
528806f25ae9SGregory Neil Shapiro 		SSL_free(ssl);
528906f25ae9SGregory Neil Shapiro 		ssl = NULL;
529006f25ae9SGregory Neil Shapiro 	}
5291602a2b1bSGregory Neil Shapiro 	return ret;
529206f25ae9SGregory Neil Shapiro }
529306f25ae9SGregory Neil Shapiro # endif /* STARTTLS */
529406f25ae9SGregory Neil Shapiro #endif /* SMTP */
5295