138032Speter/*
2261194Sgshapiro * Copyright (c) 1998-2003, 2006 Proofpoint, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
1538032Speter
16266527SgshapiroSM_RCSID("@(#)$Id: envelope.c,v 8.313 2013-11-22 20:51:55 ca Exp $")
1764562Sgshapiro
1838032Speter/*
19110560Sgshapiro**  CLRSESSENVELOPE -- clear session oriented data in an envelope
20110560Sgshapiro**
21110560Sgshapiro**	Parameters:
22110560Sgshapiro**		e -- the envelope to clear.
23110560Sgshapiro**
24110560Sgshapiro**	Returns:
25110560Sgshapiro**		none.
26110560Sgshapiro*/
27110560Sgshapiro
28110560Sgshapirovoid
29110560Sgshapiroclrsessenvelope(e)
30110560Sgshapiro	ENVELOPE *e;
31110560Sgshapiro{
32110560Sgshapiro#if SASL
33110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{auth_type}"), "");
34110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{auth_authen}"), "");
35110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{auth_author}"), "");
36110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{auth_ssf}"), "");
37110560Sgshapiro#endif /* SASL */
38110560Sgshapiro#if STARTTLS
39110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{cert_issuer}"), "");
40110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{cert_subject}"), "");
41110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{cipher_bits}"), "");
42110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{cipher}"), "");
43110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{tls_version}"), "");
44110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{verify}"), "");
45110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{alg_bits}"), "");
46110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{cn_issuer}"), "");
47110560Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{cn_subject}"), "");
48110560Sgshapiro#endif /* STARTTLS */
49110560Sgshapiro}
50110560Sgshapiro
51110560Sgshapiro/*
5290792Sgshapiro**  NEWENVELOPE -- fill in a new envelope
5338032Speter**
5438032Speter**	Supports inheritance.
5538032Speter**
5638032Speter**	Parameters:
5738032Speter**		e -- the new envelope to fill in.
5838032Speter**		parent -- the envelope to be the parent of e.
5990792Sgshapiro**		rpool -- either NULL, or a pointer to a resource pool
6090792Sgshapiro**			from which envelope memory is allocated, and
6190792Sgshapiro**			to which envelope resources are attached.
6238032Speter**
6338032Speter**	Returns:
6438032Speter**		e.
6538032Speter**
6638032Speter**	Side Effects:
6738032Speter**		none.
6838032Speter*/
6938032Speter
7038032SpeterENVELOPE *
7190792Sgshapironewenvelope(e, parent, rpool)
7238032Speter	register ENVELOPE *e;
7338032Speter	register ENVELOPE *parent;
7490792Sgshapiro	SM_RPOOL_T *rpool;
7538032Speter{
76182352Sgshapiro	int sendmode;
77157001Sgshapiro
7890792Sgshapiro	/*
7990792Sgshapiro	**  This code used to read:
8090792Sgshapiro	**	if (e == parent && e->e_parent != NULL)
8190792Sgshapiro	**		parent = e->e_parent;
8290792Sgshapiro	**  So if e == parent && e->e_parent == NULL then we would
8390792Sgshapiro	**  set e->e_parent = e, which creates a loop in the e_parent chain.
8490792Sgshapiro	**  This meant macvalue() could go into an infinite loop.
8590792Sgshapiro	*/
8690792Sgshapiro
87157001Sgshapiro	if (parent != NULL)
88157001Sgshapiro		sendmode = parent->e_sendmode;
89157001Sgshapiro	else
90157001Sgshapiro		sendmode = DM_NOTSET;
91157001Sgshapiro
9290792Sgshapiro	if (e == parent)
9338032Speter		parent = e->e_parent;
9490792Sgshapiro	clearenvelope(e, true, rpool);
9538032Speter	if (e == CurEnv)
9664562Sgshapiro		memmove((char *) &e->e_from,
9764562Sgshapiro			(char *) &NullAddress,
98168515Sgshapiro			sizeof(e->e_from));
9938032Speter	else
10064562Sgshapiro		memmove((char *) &e->e_from,
10164562Sgshapiro			(char *) &CurEnv->e_from,
102168515Sgshapiro			sizeof(e->e_from));
10338032Speter	e->e_parent = parent;
10464562Sgshapiro	assign_queueid(e);
10538032Speter	e->e_ctime = curtime();
106173340Sgshapiro#if _FFR_SESSID
107173340Sgshapiro	e->e_sessid = e->e_id;
108363466Sgshapiro#endif
10938032Speter	if (parent != NULL)
11090792Sgshapiro	{
11138032Speter		e->e_msgpriority = parent->e_msgsize;
112173340Sgshapiro#if _FFR_SESSID
113173340Sgshapiro		if (parent->e_sessid != NULL)
114173340Sgshapiro			e->e_sessid = sm_rpool_strdup_x(rpool,
115173340Sgshapiro							parent->e_sessid);
116363466Sgshapiro#endif
117173340Sgshapiro
11890792Sgshapiro		if (parent->e_quarmsg == NULL)
11990792Sgshapiro		{
12090792Sgshapiro			e->e_quarmsg = NULL;
12190792Sgshapiro			macdefine(&e->e_macro, A_PERM,
12290792Sgshapiro				  macid("{quarantine}"), "");
12390792Sgshapiro		}
12490792Sgshapiro		else
12590792Sgshapiro		{
12690792Sgshapiro			e->e_quarmsg = sm_rpool_strdup_x(rpool,
12790792Sgshapiro							 parent->e_quarmsg);
12890792Sgshapiro			macdefine(&e->e_macro, A_PERM,
12990792Sgshapiro				  macid("{quarantine}"), e->e_quarmsg);
13090792Sgshapiro		}
13190792Sgshapiro	}
13238032Speter	e->e_puthdr = putheader;
13338032Speter	e->e_putbody = putbody;
13438032Speter	if (CurEnv->e_xfp != NULL)
13590792Sgshapiro		(void) sm_io_flush(CurEnv->e_xfp, SM_TIME_DEFAULT);
136157001Sgshapiro	if (sendmode != DM_NOTSET)
137182352Sgshapiro		set_delivery_mode(sendmode, e);
13838032Speter
13964562Sgshapiro	return e;
14038032Speter}
14190792Sgshapiro
14290792Sgshapiro/* values for msg_timeout, see also IS_* below for usage (bit layout) */
14390792Sgshapiro#define MSG_T_O		0x01	/* normal timeout */
14490792Sgshapiro#define MSG_T_O_NOW	0x02	/* NOW timeout */
14590792Sgshapiro#define MSG_NOT_BY	0x04	/* Deliver-By time exceeded, mode R */
14690792Sgshapiro#define MSG_WARN	0x10	/* normal queue warning */
14790792Sgshapiro#define MSG_WARN_BY	0x20	/* Deliver-By time exceeded, mode N */
14890792Sgshapiro
14990792Sgshapiro#define IS_MSG_ERR(x)	(((x) & 0x0f) != 0)	/* return an error */
15090792Sgshapiro
15190792Sgshapiro/* immediate return */
15290792Sgshapiro#define IS_IMM_RET(x)	(((x) & (MSG_T_O_NOW|MSG_NOT_BY)) != 0)
15390792Sgshapiro#define IS_MSG_WARN(x)	(((x) & 0xf0) != 0)	/* return a warning */
15490792Sgshapiro
15590792Sgshapiro/*
15638032Speter**  DROPENVELOPE -- deallocate an envelope.
15738032Speter**
15838032Speter**	Parameters:
15938032Speter**		e -- the envelope to deallocate.
16038032Speter**		fulldrop -- if set, do return receipts.
16190792Sgshapiro**		split -- if true, split by recipient if message is queued up
16238032Speter**
16338032Speter**	Returns:
164203004Sgshapiro**		EX_* status (currently: 0: success, EX_IOERR on panic)
16538032Speter**
16638032Speter**	Side Effects:
16738032Speter**		housekeeping necessary to dispose of an envelope.
16838032Speter**		Unlocks this queue file.
16938032Speter*/
17038032Speter
171203004Sgshapiroint
17290792Sgshapirodropenvelope(e, fulldrop, split)
17338032Speter	register ENVELOPE *e;
17438032Speter	bool fulldrop;
17590792Sgshapiro	bool split;
17638032Speter{
17790792Sgshapiro	bool panic = false;
17890792Sgshapiro	bool queueit = false;
17990792Sgshapiro	int msg_timeout = 0;
18090792Sgshapiro	bool failure_return = false;
18190792Sgshapiro	bool delay_return = false;
18290792Sgshapiro	bool success_return = false;
18364562Sgshapiro	bool pmnotify = bitset(EF_PM_NOTIFY, e->e_flags);
18490792Sgshapiro	bool done = false;
18538032Speter	register ADDRESS *q;
18638032Speter	char *id = e->e_id;
18771345Sgshapiro	time_t now;
18838032Speter	char buf[MAXLINE];
18938032Speter
19038032Speter	if (tTd(50, 1))
19138032Speter	{
192363466Sgshapiro		sm_dprintf("dropenvelope %p: id=", (void *)e);
193132943Sgshapiro		xputs(sm_debug_file(), e->e_id);
19490792Sgshapiro		sm_dprintf(", flags=");
19538032Speter		printenvflags(e);
19638032Speter		if (tTd(50, 10))
19738032Speter		{
19890792Sgshapiro			sm_dprintf("sendq=");
199132943Sgshapiro			printaddr(sm_debug_file(), e->e_sendqueue, true);
20038032Speter		}
20138032Speter	}
20238032Speter
20338032Speter	if (LogLevel > 84)
20438032Speter		sm_syslog(LOG_DEBUG, id,
20564562Sgshapiro			  "dropenvelope, e_flags=0x%lx, OpMode=%c, pid=%d",
20690792Sgshapiro			  e->e_flags, OpMode, (int) CurrentPid);
20738032Speter
20838032Speter	/* we must have an id to remove disk files */
20938032Speter	if (id == NULL)
210203004Sgshapiro		return EX_OK;
21138032Speter
21238032Speter	/* if verify-only mode, we can skip most of this */
21338032Speter	if (OpMode == MD_VERIFY)
21438032Speter		goto simpledrop;
21538032Speter
216203004Sgshapiro	if (tTd(92, 2))
217203004Sgshapiro		sm_dprintf("dropenvelope: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n",
218203004Sgshapiro			e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel);
21938032Speter	if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
22038032Speter		logsender(e, NULL);
22138032Speter	e->e_flags &= ~EF_LOGSENDER;
22238032Speter
22338032Speter	/* post statistics */
22438032Speter	poststats(StatFile);
22538032Speter
22638032Speter	/*
22738032Speter	**  Extract state information from dregs of send list.
22838032Speter	*/
22938032Speter
23071345Sgshapiro	now = curtime();
23177349Sgshapiro	if (now >= e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
23290792Sgshapiro		msg_timeout = MSG_T_O;
23390792Sgshapiro	if (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 &&
23490792Sgshapiro	    now >= e->e_ctime + e->e_deliver_by &&
23564562Sgshapiro	    !bitset(EF_RESPONSE, e->e_flags))
23664562Sgshapiro	{
23790792Sgshapiro		msg_timeout = MSG_NOT_BY;
23864562Sgshapiro		e->e_flags |= EF_FATALERRS|EF_CLRQUEUE;
23964562Sgshapiro	}
24090792Sgshapiro	else if (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
24190792Sgshapiro		 !bitset(EF_RESPONSE, e->e_flags))
24290792Sgshapiro	{
24390792Sgshapiro		msg_timeout = MSG_T_O_NOW;
24490792Sgshapiro		e->e_flags |= EF_FATALERRS|EF_CLRQUEUE;
24590792Sgshapiro	}
24664562Sgshapiro
247285229Sgshapiro#if _FFR_PROXY
248285229Sgshapiro	if (tTd(87, 2))
249285229Sgshapiro	{
250285229Sgshapiro		q = e->e_sendqueue;
251285229Sgshapiro		sm_dprintf("dropenvelope: mode=%c, e=%p, sibling=%p, nrcpts=%d, sendqueue=%p, next=%p, state=%d\n",
252285229Sgshapiro			e->e_sendmode, e, e->e_sibling, e->e_nrcpts, q,
253285229Sgshapiro			(q == NULL) ? (void *)0 : q->q_next,
254285229Sgshapiro			(q == NULL) ? -1 : q->q_state);
255285229Sgshapiro	}
256285229Sgshapiro#endif /* _FFR_PROXY */
257223067Sgshapiro
25838032Speter	e->e_flags &= ~EF_QUEUERUN;
25938032Speter	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
26038032Speter	{
26164562Sgshapiro		if (QS_IS_UNDELIVERED(q->q_state))
26290792Sgshapiro			queueit = true;
26338032Speter
264285229Sgshapiro#if _FFR_PROXY
265285229Sgshapiro		if (queueit && e->e_sendmode == SM_PROXY)
266285229Sgshapiro			queueit = false;
267363466Sgshapiro#endif
268223067Sgshapiro
26938032Speter		/* see if a notification is needed */
27038032Speter		if (bitset(QPINGONFAILURE, q->q_flags) &&
27190792Sgshapiro		    ((IS_MSG_ERR(msg_timeout) &&
27290792Sgshapiro		      QS_IS_UNDELIVERED(q->q_state)) ||
27364562Sgshapiro		     QS_IS_BADADDR(q->q_state) ||
27490792Sgshapiro		     IS_IMM_RET(msg_timeout)))
27538032Speter		{
27690792Sgshapiro			failure_return = true;
27764562Sgshapiro			if (!done && q->q_owner == NULL &&
27864562Sgshapiro			    !emptyaddr(&e->e_from))
27964562Sgshapiro			{
28038032Speter				(void) sendtolist(e->e_from.q_paddr, NULLADDR,
28138032Speter						  &e->e_errorqueue, 0, e);
28290792Sgshapiro				done = true;
28364562Sgshapiro			}
28438032Speter		}
28590792Sgshapiro		else if ((bitset(QPINGONSUCCESS, q->q_flags) &&
28690792Sgshapiro			  ((QS_IS_SENT(q->q_state) &&
28790792Sgshapiro			    bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) ||
28890792Sgshapiro			   bitset(QRELAYED|QEXPANDED|QDELIVERED, q->q_flags))) ||
28990792Sgshapiro			  bitset(QBYTRACE, q->q_flags) ||
29090792Sgshapiro			  bitset(QBYNRELAY, q->q_flags))
29138032Speter		{
29290792Sgshapiro			success_return = true;
29338032Speter		}
29438032Speter	}
29538032Speter
29638032Speter	if (e->e_class < 0)
29738032Speter		e->e_flags |= EF_NO_BODY_RETN;
29838032Speter
29938032Speter	/*
30038032Speter	**  See if the message timed out.
30138032Speter	*/
30238032Speter
30338032Speter	if (!queueit)
30464562Sgshapiro		/* EMPTY */
30538032Speter		/* nothing to do */ ;
30690792Sgshapiro	else if (IS_MSG_ERR(msg_timeout))
30738032Speter	{
30838032Speter		if (failure_return)
30938032Speter		{
31090792Sgshapiro			if (msg_timeout == MSG_NOT_BY)
31190792Sgshapiro			{
312168515Sgshapiro				(void) sm_snprintf(buf, sizeof(buf),
31390792Sgshapiro					"delivery time expired %lds",
31490792Sgshapiro					e->e_deliver_by);
31590792Sgshapiro			}
31690792Sgshapiro			else
31790792Sgshapiro			{
318168515Sgshapiro				(void) sm_snprintf(buf, sizeof(buf),
31964562Sgshapiro					"Cannot send message for %s",
32090792Sgshapiro					pintvl(TimeOuts.to_q_return[e->e_timeoutclass],
32190792Sgshapiro						false));
32290792Sgshapiro			}
32390792Sgshapiro
32490792Sgshapiro			/* don't free, allocated from e_rpool */
32590792Sgshapiro			e->e_message = sm_rpool_strdup_x(e->e_rpool, buf);
326363466Sgshapiro			message("%s", buf);
32738032Speter			e->e_flags |= EF_CLRQUEUE;
32838032Speter		}
32990792Sgshapiro		if (msg_timeout == MSG_NOT_BY)
33090792Sgshapiro		{
33190792Sgshapiro			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
33290792Sgshapiro				"Delivery time (%lds) expired\n",
33390792Sgshapiro				e->e_deliver_by);
33490792Sgshapiro		}
33590792Sgshapiro		else
33690792Sgshapiro			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
33790792Sgshapiro				"Message could not be delivered for %s\n",
33890792Sgshapiro				pintvl(TimeOuts.to_q_return[e->e_timeoutclass],
33990792Sgshapiro					false));
34090792Sgshapiro		(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
34190792Sgshapiro			"Message will be deleted from queue\n");
34238032Speter		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
34338032Speter		{
34464562Sgshapiro			if (QS_IS_UNDELIVERED(q->q_state))
34538032Speter			{
34664562Sgshapiro				q->q_state = QS_BADADDR;
34790792Sgshapiro				if (msg_timeout == MSG_NOT_BY)
34890792Sgshapiro					q->q_status = "5.4.7";
34990792Sgshapiro				else
35090792Sgshapiro					q->q_status = "4.4.7";
35138032Speter			}
35238032Speter		}
35338032Speter	}
35490792Sgshapiro	else
35538032Speter	{
35690792Sgshapiro		if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
35790792Sgshapiro		    now >= e->e_ctime +
35890792Sgshapiro				TimeOuts.to_q_warning[e->e_timeoutclass])
35990792Sgshapiro			msg_timeout = MSG_WARN;
36090792Sgshapiro		else if (IS_DLVR_NOTIFY(e) &&
36190792Sgshapiro			 e->e_deliver_by > 0 &&
36290792Sgshapiro			 now >= e->e_ctime + e->e_deliver_by)
36390792Sgshapiro			msg_timeout = MSG_WARN_BY;
36490792Sgshapiro
36590792Sgshapiro		if (IS_MSG_WARN(msg_timeout))
36638032Speter		{
36790792Sgshapiro			if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
36890792Sgshapiro			    e->e_class >= 0 &&
36990792Sgshapiro			    e->e_from.q_paddr != NULL &&
37090792Sgshapiro			    strcmp(e->e_from.q_paddr, "<>") != 0 &&
37190792Sgshapiro			    sm_strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
37290792Sgshapiro			    (strlen(e->e_from.q_paddr) <= 8 ||
37390792Sgshapiro			     sm_strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8],
37490792Sgshapiro					   "-request") != 0))
37538032Speter			{
37690792Sgshapiro				for (q = e->e_sendqueue; q != NULL;
37790792Sgshapiro				     q = q->q_next)
37890792Sgshapiro				{
37990792Sgshapiro					if (QS_IS_UNDELIVERED(q->q_state)
38064562Sgshapiro#if _FFR_NODELAYDSN_ON_HOLD
38190792Sgshapiro					    && !bitnset(M_HOLD,
38290792Sgshapiro							q->q_mailer->m_flags)
383363466Sgshapiro#endif
38490792Sgshapiro					   )
38590792Sgshapiro					{
38690792Sgshapiro						if (msg_timeout ==
38790792Sgshapiro						    MSG_WARN_BY &&
38890792Sgshapiro						    (bitset(QPINGONDELAY,
38990792Sgshapiro							    q->q_flags) ||
39090792Sgshapiro						    !bitset(QHASNOTIFY,
39190792Sgshapiro							    q->q_flags))
39290792Sgshapiro						   )
39390792Sgshapiro						{
39490792Sgshapiro							q->q_flags |= QBYNDELAY;
39590792Sgshapiro							delay_return = true;
39690792Sgshapiro						}
39790792Sgshapiro						if (bitset(QPINGONDELAY,
39890792Sgshapiro							   q->q_flags))
39990792Sgshapiro						{
40090792Sgshapiro							q->q_flags |= QDELAYED;
40190792Sgshapiro							delay_return = true;
40290792Sgshapiro						}
40390792Sgshapiro					}
40490792Sgshapiro				}
40590792Sgshapiro			}
40690792Sgshapiro			if (delay_return)
40790792Sgshapiro			{
40890792Sgshapiro				if (msg_timeout == MSG_WARN_BY)
40938032Speter				{
410168515Sgshapiro					(void) sm_snprintf(buf, sizeof(buf),
41190792Sgshapiro						"Warning: Delivery time (%lds) exceeded",
41290792Sgshapiro						e->e_deliver_by);
41338032Speter				}
41490792Sgshapiro				else
415168515Sgshapiro					(void) sm_snprintf(buf, sizeof(buf),
41690792Sgshapiro						"Warning: could not send message for past %s",
41790792Sgshapiro						pintvl(TimeOuts.to_q_warning[e->e_timeoutclass],
41890792Sgshapiro							false));
41990792Sgshapiro
42090792Sgshapiro				/* don't free, allocated from e_rpool */
42190792Sgshapiro				e->e_message = sm_rpool_strdup_x(e->e_rpool,
42290792Sgshapiro								 buf);
423363466Sgshapiro				message("%s", buf);
42490792Sgshapiro				e->e_flags |= EF_WARNING;
42538032Speter			}
42690792Sgshapiro			if (msg_timeout == MSG_WARN_BY)
42790792Sgshapiro			{
42890792Sgshapiro				(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
42990792Sgshapiro					"Warning: Delivery time (%lds) exceeded\n",
43090792Sgshapiro					e->e_deliver_by);
43190792Sgshapiro			}
43290792Sgshapiro			else
43390792Sgshapiro				(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
43490792Sgshapiro					"Warning: message still undelivered after %s\n",
43590792Sgshapiro					pintvl(TimeOuts.to_q_warning[e->e_timeoutclass],
43690792Sgshapiro					     false));
43790792Sgshapiro			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
43890792Sgshapiro				      "Will keep trying until message is %s old\n",
43990792Sgshapiro				      pintvl(TimeOuts.to_q_return[e->e_timeoutclass],
44090792Sgshapiro					     false));
44138032Speter		}
44238032Speter	}
44338032Speter
44438032Speter	if (tTd(50, 2))
44590792Sgshapiro		sm_dprintf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n",
44638032Speter			failure_return, delay_return, success_return, queueit);
44738032Speter
44838032Speter	/*
449363466Sgshapiro	**  If we had some fatal error, but no addresses are marked as bad,
450363466Sgshapiro	**  mark all OK/VERIFIED addresses as bad (if QPINGONFAILURE).
45138032Speter	*/
45238032Speter
45338032Speter	if (bitset(EF_FATALERRS, e->e_flags) && !failure_return)
45438032Speter	{
45538032Speter		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
45638032Speter		{
45764562Sgshapiro			if ((QS_IS_OK(q->q_state) ||
458363466Sgshapiro			     QS_IS_VERIFIED(q->q_state))
459363466Sgshapiro			    && bitset(QPINGONFAILURE, q->q_flags)
460363466Sgshapiro
461363466Sgshapiro			/*
462363466Sgshapiro			**  do not mark an address as bad if
463363466Sgshapiro			**  - the address itself is stored in the queue
464363466Sgshapiro			**  - the DeliveryMode requires queueing
465363466Sgshapiro			**  - the envelope is queued
466363466Sgshapiro			*/
467363466Sgshapiro
468363466Sgshapiro			    && !(bitset(QQUEUED, q->q_flags)
469363466Sgshapiro				 && WILL_BE_QUEUED(e->e_sendmode)
470363466Sgshapiro				 && bitset(EF_INQUEUE, e->e_flags)
471363466Sgshapiro				)
472363466Sgshapiro			   )
47338032Speter			{
47490792Sgshapiro				failure_return = true;
47564562Sgshapiro				q->q_state = QS_BADADDR;
47638032Speter			}
47738032Speter		}
47838032Speter	}
47938032Speter
48038032Speter	/*
48138032Speter	**  Send back return receipts as requested.
48238032Speter	*/
48338032Speter
48438032Speter	if (success_return && !failure_return && !delay_return && fulldrop &&
48538032Speter	    !bitset(PRIV_NORECEIPTS, PrivacyFlags) &&
48638032Speter	    strcmp(e->e_from.q_paddr, "<>") != 0)
48738032Speter	{
48838032Speter		auto ADDRESS *rlist = NULL;
48938032Speter
49038032Speter		if (tTd(50, 8))
49190792Sgshapiro			sm_dprintf("dropenvelope(%s): sending return receipt\n",
49264562Sgshapiro				id);
49338032Speter		e->e_flags |= EF_SENDRECEIPT;
49438032Speter		(void) sendtolist(e->e_from.q_paddr, NULLADDR, &rlist, 0, e);
49538032Speter		(void) returntosender("Return receipt", rlist, RTSF_NO_BODY, e);
49638032Speter	}
49738032Speter	e->e_flags &= ~EF_SENDRECEIPT;
49838032Speter
49938032Speter	/*
50038032Speter	**  Arrange to send error messages if there are fatal errors.
50138032Speter	*/
50238032Speter
50338032Speter	if ((failure_return || delay_return) && e->e_errormode != EM_QUIET)
50438032Speter	{
50538032Speter		if (tTd(50, 8))
50690792Sgshapiro			sm_dprintf("dropenvelope(%s): saving mail\n", id);
50790792Sgshapiro		panic = savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags));
50838032Speter	}
50938032Speter
51038032Speter	/*
51138032Speter	**  Arrange to send warning messages to postmaster as requested.
51238032Speter	*/
51338032Speter
51464562Sgshapiro	if ((failure_return || pmnotify) &&
51538032Speter	    PostMasterCopy != NULL &&
51664562Sgshapiro	    !bitset(EF_RESPONSE, e->e_flags) &&
51764562Sgshapiro	    e->e_class >= 0)
51838032Speter	{
51938032Speter		auto ADDRESS *rlist = NULL;
52064562Sgshapiro		char pcopy[MAXNAME];
52138032Speter
52264562Sgshapiro		if (failure_return)
52364562Sgshapiro		{
524168515Sgshapiro			expand(PostMasterCopy, pcopy, sizeof(pcopy), e);
52564562Sgshapiro
52664562Sgshapiro			if (tTd(50, 8))
52790792Sgshapiro				sm_dprintf("dropenvelope(%s): sending postmaster copy to %s\n",
52864562Sgshapiro					id, pcopy);
52964562Sgshapiro			(void) sendtolist(pcopy, NULLADDR, &rlist, 0, e);
53064562Sgshapiro		}
53164562Sgshapiro		if (pmnotify)
53264562Sgshapiro			(void) sendtolist("postmaster", NULLADDR,
53364562Sgshapiro					  &rlist, 0, e);
53464562Sgshapiro		(void) returntosender(e->e_message, rlist,
53564562Sgshapiro				      RTSF_PM_BOUNCE|RTSF_NO_BODY, e);
53638032Speter	}
53738032Speter
53838032Speter	/*
53938032Speter	**  Instantiate or deinstantiate the queue.
54038032Speter	*/
54138032Speter
54238032Spetersimpledrop:
54338032Speter	if (tTd(50, 8))
54490792Sgshapiro		sm_dprintf("dropenvelope(%s): at simpledrop, queueit=%d\n",
54538032Speter			id, queueit);
54638032Speter	if (!queueit || bitset(EF_CLRQUEUE, e->e_flags))
54738032Speter	{
54838032Speter		if (tTd(50, 1))
54938032Speter		{
55090792Sgshapiro			sm_dprintf("\n===== Dropping queue files for %s... queueit=%d, e_flags=",
55138032Speter				e->e_id, queueit);
55238032Speter			printenvflags(e);
55338032Speter		}
55490792Sgshapiro		if (!panic)
555159609Sgshapiro		{
556159609Sgshapiro			if (e->e_dfp != NULL)
557159609Sgshapiro			{
558159609Sgshapiro				(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
559159609Sgshapiro				e->e_dfp = NULL;
560159609Sgshapiro			}
56190792Sgshapiro			(void) xunlink(queuename(e, DATAFL_LETTER));
562159609Sgshapiro		}
56390792Sgshapiro		if (panic && QueueMode == QM_LOST)
56490792Sgshapiro		{
56590792Sgshapiro			/*
56690792Sgshapiro			**  leave the Qf file behind as
56790792Sgshapiro			**  the delivery attempt failed.
56890792Sgshapiro			*/
56938032Speter
57090792Sgshapiro			/* EMPTY */
57190792Sgshapiro		}
57290792Sgshapiro		else
57390792Sgshapiro		if (xunlink(queuename(e, ANYQFL_LETTER)) == 0)
57490792Sgshapiro		{
57590792Sgshapiro			/* add to available space in filesystem */
576147078Sgshapiro			updfs(e, -1, panic ? 0 : -1, "dropenvelope");
57790792Sgshapiro		}
57890792Sgshapiro
57964562Sgshapiro		if (e->e_ntries > 0 && LogLevel > 9)
58064562Sgshapiro			sm_syslog(LOG_INFO, id, "done; delay=%s, ntries=%d",
58190792Sgshapiro				  pintvl(curtime() - e->e_ctime, true),
58264562Sgshapiro				  e->e_ntries);
58338032Speter	}
58438032Speter	else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
58538032Speter	{
58690792Sgshapiro		if (!split)
58790792Sgshapiro			queueup(e, false, true);
58890792Sgshapiro		else
58990792Sgshapiro		{
59090792Sgshapiro			ENVELOPE *oldsib;
59190792Sgshapiro			ENVELOPE *ee;
59290792Sgshapiro
59390792Sgshapiro			/*
59490792Sgshapiro			**  Save old sibling and set it to NULL to avoid
59590792Sgshapiro			**  queueing up the same envelopes again.
59690792Sgshapiro			**  This requires that envelopes in that list have
59790792Sgshapiro			**  been take care of before (or at some other place).
59890792Sgshapiro			*/
59990792Sgshapiro
60090792Sgshapiro			oldsib = e->e_sibling;
60190792Sgshapiro			e->e_sibling = NULL;
60290792Sgshapiro			if (!split_by_recipient(e) &&
60390792Sgshapiro			    bitset(EF_FATALERRS, e->e_flags))
60490792Sgshapiro			{
605285229Sgshapiro				syserr("!dropenvelope(%s): cannot commit data file %s, uid=%ld",
60690792Sgshapiro					e->e_id, queuename(e, DATAFL_LETTER),
607285229Sgshapiro					(long) geteuid());
60890792Sgshapiro			}
60990792Sgshapiro			for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
61090792Sgshapiro				queueup(ee, false, true);
61190792Sgshapiro			queueup(e, false, true);
61290792Sgshapiro
61390792Sgshapiro			/* clean up */
61490792Sgshapiro			for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
61590792Sgshapiro			{
61690792Sgshapiro				/* now unlock the job */
61790792Sgshapiro				if (tTd(50, 8))
61890792Sgshapiro					sm_dprintf("dropenvelope(%s): unlocking job\n",
61990792Sgshapiro						   ee->e_id);
62090792Sgshapiro				closexscript(ee);
62190792Sgshapiro				unlockqueue(ee);
62290792Sgshapiro
62390792Sgshapiro				/* this envelope is marked unused */
62490792Sgshapiro				if (ee->e_dfp != NULL)
62590792Sgshapiro				{
62690792Sgshapiro					(void) sm_io_close(ee->e_dfp,
62790792Sgshapiro							   SM_TIME_DEFAULT);
62890792Sgshapiro					ee->e_dfp = NULL;
62990792Sgshapiro				}
63090792Sgshapiro				ee->e_id = NULL;
63190792Sgshapiro				ee->e_flags &= ~EF_HAS_DF;
63290792Sgshapiro			}
63390792Sgshapiro			e->e_sibling = oldsib;
63490792Sgshapiro		}
63538032Speter	}
63638032Speter
63738032Speter	/* now unlock the job */
63838032Speter	if (tTd(50, 8))
63990792Sgshapiro		sm_dprintf("dropenvelope(%s): unlocking job\n", id);
64038032Speter	closexscript(e);
64138032Speter	unlockqueue(e);
64238032Speter
64338032Speter	/* make sure that this envelope is marked unused */
64438032Speter	if (e->e_dfp != NULL)
64590792Sgshapiro	{
64690792Sgshapiro		(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
64790792Sgshapiro		e->e_dfp = NULL;
64890792Sgshapiro	}
64938032Speter	e->e_id = NULL;
65038032Speter	e->e_flags &= ~EF_HAS_DF;
651203004Sgshapiro	if (panic)
652203004Sgshapiro		return EX_IOERR;
653203004Sgshapiro	return EX_OK;
65438032Speter}
655203004Sgshapiro
65690792Sgshapiro/*
65738032Speter**  CLEARENVELOPE -- clear an envelope without unlocking
65838032Speter**
65938032Speter**	This is normally used by a child process to get a clean
66038032Speter**	envelope without disturbing the parent.
66138032Speter**
66238032Speter**	Parameters:
66338032Speter**		e -- the envelope to clear.
66438032Speter**		fullclear - if set, the current envelope is total
66538032Speter**			garbage and should be ignored; otherwise,
66638032Speter**			release any resources it may indicate.
66790792Sgshapiro**		rpool -- either NULL, or a pointer to a resource pool
66890792Sgshapiro**			from which envelope memory is allocated, and
66990792Sgshapiro**			to which envelope resources are attached.
67038032Speter**
67138032Speter**	Returns:
67238032Speter**		none.
67338032Speter**
67438032Speter**	Side Effects:
67538032Speter**		Closes files associated with the envelope.
67638032Speter**		Marks the envelope as unallocated.
67738032Speter*/
67838032Speter
67938032Spetervoid
68090792Sgshapiroclearenvelope(e, fullclear, rpool)
68138032Speter	register ENVELOPE *e;
68238032Speter	bool fullclear;
68390792Sgshapiro	SM_RPOOL_T *rpool;
68438032Speter{
68538032Speter	register HDR *bh;
68638032Speter	register HDR **nhp;
68738032Speter	extern ENVELOPE BlankEnvelope;
68890792Sgshapiro	char **p;
68938032Speter
69038032Speter	if (!fullclear)
69138032Speter	{
69238032Speter		/* clear out any file information */
69338032Speter		if (e->e_xfp != NULL)
69490792Sgshapiro			(void) sm_io_close(e->e_xfp, SM_TIME_DEFAULT);
69538032Speter		if (e->e_dfp != NULL)
69690792Sgshapiro			(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
69738032Speter		e->e_xfp = e->e_dfp = NULL;
69838032Speter	}
69938032Speter
70090792Sgshapiro	/*
70190792Sgshapiro	**  Copy BlankEnvelope into *e.
70290792Sgshapiro	**  It is not safe to simply copy pointers to strings;
70390792Sgshapiro	**  the strings themselves must be copied (or set to NULL).
70490792Sgshapiro	**  The problem is that when we assign a new string value to
70590792Sgshapiro	**  a member of BlankEnvelope, we free the old string.
70690792Sgshapiro	**  We did not need to do this copying in sendmail 8.11 :-(
70790792Sgshapiro	**  and it is a potential performance hit.  Reference counted
70890792Sgshapiro	**  strings are one way out.
70990792Sgshapiro	*/
71090792Sgshapiro
71190792Sgshapiro	*e = BlankEnvelope;
71238032Speter	e->e_message = NULL;
71390792Sgshapiro	e->e_qfletter = '\0';
71490792Sgshapiro	e->e_quarmsg = NULL;
71590792Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), "");
71690792Sgshapiro
71790792Sgshapiro	/*
71890792Sgshapiro	**  Copy the macro table.
71990792Sgshapiro	**  We might be able to avoid this by zeroing the macro table
72090792Sgshapiro	**  and always searching BlankEnvelope.e_macro after e->e_macro
72190792Sgshapiro	**  in macvalue().
72290792Sgshapiro	*/
72390792Sgshapiro
72490792Sgshapiro	for (p = &e->e_macro.mac_table[0];
72590792Sgshapiro	     p <= &e->e_macro.mac_table[MAXMACROID];
72690792Sgshapiro	     ++p)
72790792Sgshapiro	{
72890792Sgshapiro		if (*p != NULL)
72990792Sgshapiro			*p = sm_rpool_strdup_x(rpool, *p);
73090792Sgshapiro	}
73190792Sgshapiro
73290792Sgshapiro	/*
73390792Sgshapiro	**  XXX There are many strings in the envelope structure
73490792Sgshapiro	**  XXX that we are not attempting to copy here.
73590792Sgshapiro	**  XXX Investigate this further.
73690792Sgshapiro	*/
73790792Sgshapiro
73890792Sgshapiro	e->e_rpool = rpool;
73990792Sgshapiro	e->e_macro.mac_rpool = rpool;
74038032Speter	if (Verbose)
74164562Sgshapiro		set_delivery_mode(SM_DELIVER, e);
74238032Speter	bh = BlankEnvelope.e_header;
74338032Speter	nhp = &e->e_header;
74438032Speter	while (bh != NULL)
74538032Speter	{
746168515Sgshapiro		*nhp = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*bh));
747168515Sgshapiro		memmove((char *) *nhp, (char *) bh, sizeof(*bh));
74838032Speter		bh = bh->h_link;
74938032Speter		nhp = &(*nhp)->h_link;
75038032Speter	}
751203004Sgshapiro#if _FFR_MILTER_ENHSC
752203004Sgshapiro	e->e_enhsc[0] = '\0';
753363466Sgshapiro#endif
75438032Speter}
75590792Sgshapiro/*
75638032Speter**  INITSYS -- initialize instantiation of system
75738032Speter**
75838032Speter**	In Daemon mode, this is done in the child.
75938032Speter**
76038032Speter**	Parameters:
76164562Sgshapiro**		e -- the envelope to use.
76238032Speter**
76338032Speter**	Returns:
76438032Speter**		none.
76538032Speter**
76638032Speter**	Side Effects:
76738032Speter**		Initializes the system macros, some global variables,
76838032Speter**		etc.  In particular, the current time in various
76938032Speter**		forms is set.
77038032Speter*/
77138032Speter
77238032Spetervoid
77338032Speterinitsys(e)
77438032Speter	register ENVELOPE *e;
77538032Speter{
77690792Sgshapiro	char buf[10];
77738032Speter#ifdef TTYNAME
77838032Speter	static char ybuf[60];			/* holds tty id */
77938032Speter	register char *p;
78038032Speter	extern char *ttyname();
78138032Speter#endif /* TTYNAME */
78238032Speter
78338032Speter	/*
78438032Speter	**  Give this envelope a reality.
78538032Speter	**	I.e., an id, a transcript, and a creation time.
78690792Sgshapiro	**  We don't select the queue until all of the recipients are known.
78738032Speter	*/
78838032Speter
78938032Speter	openxscript(e);
79038032Speter	e->e_ctime = curtime();
79190792Sgshapiro	e->e_qfletter = '\0';
79238032Speter
79338032Speter	/*
79438032Speter	**  Set OutChannel to something useful if stdout isn't it.
79538032Speter	**	This arranges that any extra stuff the mailer produces
79638032Speter	**	gets sent back to the user on error (because it is
79738032Speter	**	tucked away in the transcript).
79838032Speter	*/
79938032Speter
80038032Speter	if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
80138032Speter	    e->e_xfp != NULL)
80238032Speter		OutChannel = e->e_xfp;
80338032Speter
80438032Speter	/*
80538032Speter	**  Set up some basic system macros.
80638032Speter	*/
80738032Speter
80838032Speter	/* process id */
809168515Sgshapiro	(void) sm_snprintf(buf, sizeof(buf), "%d", (int) CurrentPid);
81090792Sgshapiro	macdefine(&e->e_macro, A_TEMP, 'p', buf);
81138032Speter
81238032Speter	/* hop count */
813168515Sgshapiro	(void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount);
81490792Sgshapiro	macdefine(&e->e_macro, A_TEMP, 'c', buf);
81538032Speter
81638032Speter	/* time as integer, unix time, arpa time */
81738032Speter	settime(e);
81838032Speter
81964562Sgshapiro	/* Load average */
82090792Sgshapiro	sm_getla();
82164562Sgshapiro
82238032Speter#ifdef TTYNAME
82338032Speter	/* tty name */
82438032Speter	if (macvalue('y', e) == NULL)
82538032Speter	{
82638032Speter		p = ttyname(2);
82738032Speter		if (p != NULL)
82838032Speter		{
82938032Speter			if (strrchr(p, '/') != NULL)
83038032Speter				p = strrchr(p, '/') + 1;
831168515Sgshapiro			(void) sm_strlcpy(ybuf, sizeof(ybuf), p);
83290792Sgshapiro			macdefine(&e->e_macro, A_PERM, 'y', ybuf);
83338032Speter		}
83438032Speter	}
83538032Speter#endif /* TTYNAME */
83638032Speter}
83790792Sgshapiro/*
83838032Speter**  SETTIME -- set the current time.
83938032Speter**
84038032Speter**	Parameters:
84164562Sgshapiro**		e -- the envelope in which the macros should be set.
84238032Speter**
84338032Speter**	Returns:
84438032Speter**		none.
84538032Speter**
84638032Speter**	Side Effects:
84738032Speter**		Sets the various time macros -- $a, $b, $d, $t.
84838032Speter*/
84938032Speter
85038032Spetervoid
85138032Spetersettime(e)
85238032Speter	register ENVELOPE *e;
85338032Speter{
85438032Speter	register char *p;
85538032Speter	auto time_t now;
85690792Sgshapiro	char buf[30];
85738032Speter	register struct tm *tm;
85838032Speter
85938032Speter	now = curtime();
860168515Sgshapiro	(void) sm_snprintf(buf, sizeof(buf), "%ld", (long) now);
861132943Sgshapiro	macdefine(&e->e_macro, A_TEMP, macid("{time}"), buf);
86238032Speter	tm = gmtime(&now);
863168515Sgshapiro	(void) sm_snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d",
86490792Sgshapiro			   tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
86590792Sgshapiro			   tm->tm_hour, tm->tm_min);
86690792Sgshapiro	macdefine(&e->e_macro, A_TEMP, 't', buf);
867168515Sgshapiro	(void) sm_strlcpy(buf, ctime(&now), sizeof(buf));
86890792Sgshapiro	p = strchr(buf, '\n');
86938032Speter	if (p != NULL)
87038032Speter		*p = '\0';
87190792Sgshapiro	macdefine(&e->e_macro, A_TEMP, 'd', buf);
87290792Sgshapiro	macdefine(&e->e_macro, A_TEMP, 'b', arpadate(buf));
87338032Speter	if (macvalue('a', e) == NULL)
87490792Sgshapiro		macdefine(&e->e_macro, A_PERM, 'a', macvalue('b', e));
87538032Speter}
87690792Sgshapiro/*
87738032Speter**  OPENXSCRIPT -- Open transcript file
87838032Speter**
87938032Speter**	Creates a transcript file for possible eventual mailing or
88038032Speter**	sending back.
88138032Speter**
88238032Speter**	Parameters:
88338032Speter**		e -- the envelope to create the transcript in/for.
88438032Speter**
88538032Speter**	Returns:
88638032Speter**		none
88738032Speter**
88838032Speter**	Side Effects:
88938032Speter**		Creates the transcript file.
89038032Speter*/
89138032Speter
89238032Speter#ifndef O_APPEND
89364562Sgshapiro# define O_APPEND	0
894363466Sgshapiro#endif
89538032Speter
89638032Spetervoid
89738032Speteropenxscript(e)
89838032Speter	register ENVELOPE *e;
89938032Speter{
90038032Speter	register char *p;
90138032Speter
90238032Speter	if (e->e_xfp != NULL)
90338032Speter		return;
90464562Sgshapiro
90564562Sgshapiro#if 0
90664562Sgshapiro	if (e->e_lockfp == NULL && bitset(EF_INQUEUE, e->e_flags))
90764562Sgshapiro		syserr("openxscript: job not locked");
908363466Sgshapiro#endif
90964562Sgshapiro
91090792Sgshapiro	p = queuename(e, XSCRPT_LETTER);
91164562Sgshapiro	e->e_xfp = bfopen(p, FileMode, XscriptFileBufferSize,
91264562Sgshapiro			  SFF_NOTEXCL|SFF_OPENASROOT);
91364562Sgshapiro
91464562Sgshapiro	if (e->e_xfp == NULL)
91538032Speter	{
91638032Speter		syserr("Can't create transcript file %s", p);
91790792Sgshapiro		e->e_xfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
91890792Sgshapiro				      SM_PATH_DEVNULL, SM_IO_RDWR, NULL);
91964562Sgshapiro		if (e->e_xfp == NULL)
92090792Sgshapiro			syserr("!Can't open %s", SM_PATH_DEVNULL);
92138032Speter	}
92290792Sgshapiro	(void) sm_io_setvbuf(e->e_xfp, SM_TIME_DEFAULT, NULL, SM_IO_LBF, 0);
92338032Speter	if (tTd(46, 9))
92438032Speter	{
92590792Sgshapiro		sm_dprintf("openxscript(%s):\n  ", p);
92690792Sgshapiro		dumpfd(sm_io_getinfo(e->e_xfp, SM_IO_WHAT_FD, NULL), true,
92790792Sgshapiro		       false);
92838032Speter	}
92938032Speter}
93090792Sgshapiro/*
93138032Speter**  CLOSEXSCRIPT -- close the transcript file.
93238032Speter**
93338032Speter**	Parameters:
93438032Speter**		e -- the envelope containing the transcript to close.
93538032Speter**
93638032Speter**	Returns:
93738032Speter**		none.
93838032Speter**
93938032Speter**	Side Effects:
94038032Speter**		none.
94138032Speter*/
94238032Speter
94338032Spetervoid
94438032Speterclosexscript(e)
94538032Speter	register ENVELOPE *e;
94638032Speter{
94738032Speter	if (e->e_xfp == NULL)
94838032Speter		return;
94964562Sgshapiro#if 0
95064562Sgshapiro	if (e->e_lockfp == NULL)
95164562Sgshapiro		syserr("closexscript: job not locked");
952363466Sgshapiro#endif
95390792Sgshapiro	(void) sm_io_close(e->e_xfp, SM_TIME_DEFAULT);
95438032Speter	e->e_xfp = NULL;
95538032Speter}
95690792Sgshapiro/*
95738032Speter**  SETSENDER -- set the person who this message is from
95838032Speter**
95938032Speter**	Under certain circumstances allow the user to say who
96038032Speter**	s/he is (using -f or -r).  These are:
96138032Speter**	1.  The user's uid is zero (root).
96238032Speter**	2.  The user's login name is in an approved list (typically
96338032Speter**	    from a network server).
96438032Speter**	3.  The address the user is trying to claim has a
96538032Speter**	    "!" character in it (since #2 doesn't do it for
96638032Speter**	    us if we are dialing out for UUCP).
96738032Speter**	A better check to replace #3 would be if the
96838032Speter**	effective uid is "UUCP" -- this would require me
96938032Speter**	to rewrite getpwent to "grab" uucp as it went by,
97038032Speter**	make getname more nasty, do another passwd file
97138032Speter**	scan, or compile the UID of "UUCP" into the code,
97238032Speter**	all of which are reprehensible.
97338032Speter**
97438032Speter**	Assuming all of these fail, we figure out something
97538032Speter**	ourselves.
97638032Speter**
97738032Speter**	Parameters:
97838032Speter**		from -- the person we would like to believe this message
97938032Speter**			is from, as specified on the command line.
98038032Speter**		e -- the envelope in which we would like the sender set.
98138032Speter**		delimptr -- if non-NULL, set to the location of the
98238032Speter**			trailing delimiter.
98338032Speter**		delimchar -- the character that will delimit the sender
98438032Speter**			address.
98538032Speter**		internal -- set if this address is coming from an internal
98638032Speter**			source such as an owner alias.
98738032Speter**
98838032Speter**	Returns:
98938032Speter**		none.
99038032Speter**
99138032Speter**	Side Effects:
99238032Speter**		sets sendmail's notion of who the from person is.
99338032Speter*/
99438032Speter
99538032Spetervoid
99638032Spetersetsender(from, e, delimptr, delimchar, internal)
99738032Speter	char *from;
99838032Speter	register ENVELOPE *e;
99938032Speter	char **delimptr;
100038032Speter	int delimchar;
100138032Speter	bool internal;
100238032Speter{
100338032Speter	register char **pvp;
100438032Speter	char *realname = NULL;
100538032Speter	char *bp;
100638032Speter	char buf[MAXNAME + 2];
100738032Speter	char pvpbuf[PSBUFSIZE];
100838032Speter	extern char *FullName;
100938032Speter
101038032Speter	if (tTd(45, 1))
101190792Sgshapiro		sm_dprintf("setsender(%s)\n", from == NULL ? "" : from);
101238032Speter
1013110560Sgshapiro	/* may be set from earlier calls */
1014110560Sgshapiro	macdefine(&e->e_macro, A_PERM, 'x', "");
1015110560Sgshapiro
101638032Speter	/*
101738032Speter	**  Figure out the real user executing us.
101838032Speter	**	Username can return errno != 0 on non-errors.
101938032Speter	*/
102038032Speter
102138032Speter	if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP ||
102238032Speter	    OpMode == MD_ARPAFTP || OpMode == MD_DAEMON)
102338032Speter		realname = from;
102438032Speter	if (realname == NULL || realname[0] == '\0')
102538032Speter		realname = username();
102638032Speter
102738032Speter	if (ConfigLevel < 2)
102890792Sgshapiro		SuprErrs = true;
102938032Speter
103090792Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e s");
103190792Sgshapiro
103264562Sgshapiro	/* preset state for then clause in case from == NULL */
103364562Sgshapiro	e->e_from.q_state = QS_BADADDR;
103464562Sgshapiro	e->e_from.q_flags = 0;
103538032Speter	if (from == NULL ||
103638032Speter	    parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
103790792Sgshapiro		      delimchar, delimptr, e, false) == NULL ||
103864562Sgshapiro	    QS_IS_BADADDR(e->e_from.q_state) ||
103938032Speter	    e->e_from.q_mailer == ProgMailer ||
104038032Speter	    e->e_from.q_mailer == FileMailer ||
104138032Speter	    e->e_from.q_mailer == InclMailer)
104238032Speter	{
104338032Speter		/* log garbage addresses for traceback */
104438032Speter		if (from != NULL && LogLevel > 2)
104538032Speter		{
104638032Speter			char *p;
104738032Speter			char ebuf[MAXNAME * 2 + 2];
104838032Speter
104938032Speter			p = macvalue('_', e);
105038032Speter			if (p == NULL)
105138032Speter			{
105238032Speter				char *host = RealHostName;
105338032Speter
105438032Speter				if (host == NULL)
105538032Speter					host = MyHostName;
1056168515Sgshapiro				(void) sm_snprintf(ebuf, sizeof(ebuf),
105790792Sgshapiro						   "%.*s@%.*s", MAXNAME,
105890792Sgshapiro						   realname, MAXNAME, host);
105938032Speter				p = ebuf;
106038032Speter			}
106138032Speter			sm_syslog(LOG_NOTICE, e->e_id,
106264562Sgshapiro				  "setsender: %s: invalid or unparsable, received from %s",
106364562Sgshapiro				  shortenstring(from, 83), p);
106438032Speter		}
106538032Speter		if (from != NULL)
106638032Speter		{
106764562Sgshapiro			if (!QS_IS_BADADDR(e->e_from.q_state))
106838032Speter			{
106938032Speter				/* it was a bogus mailer in the from addr */
107038032Speter				e->e_status = "5.1.7";
107164562Sgshapiro				usrerrenh(e->e_status,
107264562Sgshapiro					  "553 Invalid sender address");
107338032Speter			}
107490792Sgshapiro			SuprErrs = true;
107538032Speter		}
107638032Speter		if (from == realname ||
107790792Sgshapiro		    parseaddr(from = realname,
107890792Sgshapiro			      &e->e_from, RF_COPYALL|RF_SENDERADDR, ' ',
107990792Sgshapiro			      NULL, e, false) == NULL)
108038032Speter		{
108138032Speter			char nbuf[100];
108238032Speter
108390792Sgshapiro			SuprErrs = true;
1084168515Sgshapiro			expand("\201n", nbuf, sizeof(nbuf), e);
108590792Sgshapiro			from = sm_rpool_strdup_x(e->e_rpool, nbuf);
108690792Sgshapiro			if (parseaddr(from, &e->e_from, RF_COPYALL, ' ',
108790792Sgshapiro				      NULL, e, false) == NULL &&
108838032Speter			    parseaddr(from = "postmaster", &e->e_from,
108990792Sgshapiro				      RF_COPYALL, ' ', NULL, e, false) == NULL)
109064562Sgshapiro				syserr("553 5.3.0 setsender: can't even parse postmaster!");
109138032Speter		}
109238032Speter	}
109338032Speter	else
109490792Sgshapiro		FromFlag = true;
109564562Sgshapiro	e->e_from.q_state = QS_SENDER;
109638032Speter	if (tTd(45, 5))
109738032Speter	{
109890792Sgshapiro		sm_dprintf("setsender: QS_SENDER ");
1099132943Sgshapiro		printaddr(sm_debug_file(), &e->e_from, false);
110038032Speter	}
110190792Sgshapiro	SuprErrs = false;
110238032Speter
110364562Sgshapiro#if USERDB
110438032Speter	if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags))
110538032Speter	{
110638032Speter		register char *p;
110738032Speter
110890792Sgshapiro		p = udbsender(e->e_from.q_user, e->e_rpool);
110938032Speter		if (p != NULL)
111038032Speter			from = p;
111138032Speter	}
111264562Sgshapiro#endif /* USERDB */
111338032Speter
111438032Speter	if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
111538032Speter	{
111690792Sgshapiro		SM_MBDB_T user;
111790792Sgshapiro
111838032Speter		if (!internal)
111938032Speter		{
112038032Speter			/* if the user already given fullname don't redefine */
112138032Speter			if (FullName == NULL)
112238032Speter				FullName = macvalue('x', e);
112394334Sgshapiro			if (FullName != NULL)
112494334Sgshapiro			{
112594334Sgshapiro				if (FullName[0] == '\0')
112694334Sgshapiro					FullName = NULL;
112794334Sgshapiro				else
112894334Sgshapiro					FullName = newstr(FullName);
112994334Sgshapiro			}
113038032Speter		}
113138032Speter
113238032Speter		if (e->e_from.q_user[0] != '\0' &&
113390792Sgshapiro		    sm_mbdb_lookup(e->e_from.q_user, &user) == EX_OK)
113438032Speter		{
113538032Speter			/*
113638032Speter			**  Process passwd file entry.
113738032Speter			*/
113838032Speter
113938032Speter			/* extract home directory */
114090792Sgshapiro			if (*user.mbdb_homedir == '\0')
114166494Sgshapiro				e->e_from.q_home = NULL;
114290792Sgshapiro			else if (strcmp(user.mbdb_homedir, "/") == 0)
114390792Sgshapiro				e->e_from.q_home = "";
114438032Speter			else
114590792Sgshapiro				e->e_from.q_home = sm_rpool_strdup_x(e->e_rpool,
114690792Sgshapiro							user.mbdb_homedir);
114790792Sgshapiro			macdefine(&e->e_macro, A_PERM, 'z', e->e_from.q_home);
114838032Speter
114938032Speter			/* extract user and group id */
115090792Sgshapiro			if (user.mbdb_uid != SM_NO_UID)
115190792Sgshapiro			{
115290792Sgshapiro				e->e_from.q_uid = user.mbdb_uid;
115390792Sgshapiro				e->e_from.q_gid = user.mbdb_gid;
115490792Sgshapiro				e->e_from.q_flags |= QGOODUID;
115590792Sgshapiro			}
115638032Speter
115738032Speter			/* extract full name from passwd file */
115890792Sgshapiro			if (FullName == NULL && !internal &&
115990792Sgshapiro			    user.mbdb_fullname[0] != '\0' &&
116090792Sgshapiro			    strcmp(user.mbdb_name, e->e_from.q_user) == 0)
116138032Speter			{
116290792Sgshapiro				FullName = newstr(user.mbdb_fullname);
116338032Speter			}
116438032Speter		}
116538032Speter		else
116638032Speter		{
116764562Sgshapiro			e->e_from.q_home = NULL;
116838032Speter		}
116938032Speter		if (FullName != NULL && !internal)
1170110560Sgshapiro			macdefine(&e->e_macro, A_TEMP, 'x', FullName);
117138032Speter	}
117243730Speter	else if (!internal && OpMode != MD_DAEMON && OpMode != MD_SMTP)
117338032Speter	{
117438032Speter		if (e->e_from.q_home == NULL)
117538032Speter		{
117638032Speter			e->e_from.q_home = getenv("HOME");
117766494Sgshapiro			if (e->e_from.q_home != NULL)
117866494Sgshapiro			{
117966494Sgshapiro				if (*e->e_from.q_home == '\0')
118066494Sgshapiro					e->e_from.q_home = NULL;
118166494Sgshapiro				else if (strcmp(e->e_from.q_home, "/") == 0)
118266494Sgshapiro					e->e_from.q_home++;
118366494Sgshapiro			}
118438032Speter		}
118538032Speter		e->e_from.q_uid = RealUid;
118638032Speter		e->e_from.q_gid = RealGid;
118738032Speter		e->e_from.q_flags |= QGOODUID;
118838032Speter	}
118938032Speter
119038032Speter	/*
119138032Speter	**  Rewrite the from person to dispose of possible implicit
119238032Speter	**	links in the net.
119338032Speter	*/
119438032Speter
1195168515Sgshapiro	pvp = prescan(from, delimchar, pvpbuf, sizeof(pvpbuf), NULL,
1196168515Sgshapiro			IntTokenTab, false);
119738032Speter	if (pvp == NULL)
119838032Speter	{
119938032Speter		/* don't need to give error -- prescan did that already */
120038032Speter		if (LogLevel > 2)
120138032Speter			sm_syslog(LOG_NOTICE, e->e_id,
120264562Sgshapiro				  "cannot prescan from (%s)",
120364562Sgshapiro				  shortenstring(from, MAXSHORTSTR));
120490792Sgshapiro		finis(true, true, ExitStat);
120538032Speter	}
120690792Sgshapiro	(void) REWRITE(pvp, 3, e);
120790792Sgshapiro	(void) REWRITE(pvp, 1, e);
120890792Sgshapiro	(void) REWRITE(pvp, 4, e);
120990792Sgshapiro	macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
121038032Speter	bp = buf + 1;
1211168515Sgshapiro	cataddr(pvp, NULL, bp, sizeof(buf) - 2, '\0', false);
121238032Speter	if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags))
121338032Speter	{
121438032Speter		/* heuristic: route-addr: add angle brackets */
1215168515Sgshapiro		(void) sm_strlcat(bp, ">", sizeof(buf) - 1);
121638032Speter		*--bp = '<';
121738032Speter	}
121890792Sgshapiro	e->e_sender = sm_rpool_strdup_x(e->e_rpool, bp);
121990792Sgshapiro	macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
122038032Speter
122138032Speter	/* save the domain spec if this mailer wants it */
122238032Speter	if (e->e_from.q_mailer != NULL &&
122338032Speter	    bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags))
122438032Speter	{
122538032Speter		char **lastat;
122638032Speter
122738032Speter		/* get rid of any pesky angle brackets */
122890792Sgshapiro		macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e s");
122990792Sgshapiro		(void) REWRITE(pvp, 3, e);
123090792Sgshapiro		(void) REWRITE(pvp, 1, e);
123190792Sgshapiro		(void) REWRITE(pvp, 4, e);
123290792Sgshapiro		macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
123338032Speter
123438032Speter		/* strip off to the last "@" sign */
123538032Speter		for (lastat = NULL; *pvp != NULL; pvp++)
1236132943Sgshapiro		{
123738032Speter			if (strcmp(*pvp, "@") == 0)
123838032Speter				lastat = pvp;
1239132943Sgshapiro		}
124038032Speter		if (lastat != NULL)
124138032Speter		{
124290792Sgshapiro			e->e_fromdomain = copyplist(lastat, true, e->e_rpool);
124338032Speter			if (tTd(45, 3))
124438032Speter			{
124590792Sgshapiro				sm_dprintf("Saving from domain: ");
1246132943Sgshapiro				printav(sm_debug_file(), e->e_fromdomain);
124738032Speter			}
124838032Speter		}
124938032Speter	}
125038032Speter}
125190792Sgshapiro/*
125238032Speter**  PRINTENVFLAGS -- print envelope flags for debugging
125338032Speter**
125438032Speter**	Parameters:
125538032Speter**		e -- the envelope with the flags to be printed.
125638032Speter**
125738032Speter**	Returns:
125838032Speter**		none.
125938032Speter*/
126038032Speter
126138032Speterstruct eflags
126238032Speter{
126390792Sgshapiro	char		*ef_name;
126490792Sgshapiro	unsigned long	ef_bit;
126538032Speter};
126638032Speter
126764562Sgshapirostatic struct eflags	EnvelopeFlags[] =
126838032Speter{
126938032Speter	{ "OLDSTYLE",		EF_OLDSTYLE	},
127038032Speter	{ "INQUEUE",		EF_INQUEUE	},
127138032Speter	{ "NO_BODY_RETN",	EF_NO_BODY_RETN	},
127238032Speter	{ "CLRQUEUE",		EF_CLRQUEUE	},
127338032Speter	{ "SENDRECEIPT",	EF_SENDRECEIPT	},
127438032Speter	{ "FATALERRS",		EF_FATALERRS	},
127538032Speter	{ "DELETE_BCC",		EF_DELETE_BCC	},
127638032Speter	{ "RESPONSE",		EF_RESPONSE	},
127738032Speter	{ "RESENT",		EF_RESENT	},
127838032Speter	{ "VRFYONLY",		EF_VRFYONLY	},
127938032Speter	{ "WARNING",		EF_WARNING	},
128038032Speter	{ "QUEUERUN",		EF_QUEUERUN	},
128138032Speter	{ "GLOBALERRS",		EF_GLOBALERRS	},
128238032Speter	{ "PM_NOTIFY",		EF_PM_NOTIFY	},
128338032Speter	{ "METOO",		EF_METOO	},
128438032Speter	{ "LOGSENDER",		EF_LOGSENDER	},
128538032Speter	{ "NORECEIPT",		EF_NORECEIPT	},
128638032Speter	{ "HAS8BIT",		EF_HAS8BIT	},
128738032Speter	{ "RET_PARAM",		EF_RET_PARAM	},
128838032Speter	{ "HAS_DF",		EF_HAS_DF	},
128938032Speter	{ "IS_MIME",		EF_IS_MIME	},
129038032Speter	{ "DONT_MIME",		EF_DONT_MIME	},
129190792Sgshapiro	{ "DISCARD",		EF_DISCARD	},
129290792Sgshapiro	{ "TOOBIG",		EF_TOOBIG	},
129390792Sgshapiro	{ "SPLIT",		EF_SPLIT	},
129490792Sgshapiro	{ "UNSAFE",		EF_UNSAFE	},
1295363466Sgshapiro	{ "TOODEEP",		EF_TOODEEP	},
1296363466Sgshapiro	{ "SECURE",		EF_SECURE	},
129771345Sgshapiro	{ NULL,			0		}
129838032Speter};
129938032Speter
130038032Spetervoid
130138032Speterprintenvflags(e)
130238032Speter	register ENVELOPE *e;
130338032Speter{
130438032Speter	register struct eflags *ef;
130590792Sgshapiro	bool first = true;
130638032Speter
1307132943Sgshapiro	sm_dprintf("%lx", e->e_flags);
130838032Speter	for (ef = EnvelopeFlags; ef->ef_name != NULL; ef++)
130938032Speter	{
131038032Speter		if (!bitset(ef->ef_bit, e->e_flags))
131138032Speter			continue;
131238032Speter		if (first)
1313132943Sgshapiro			sm_dprintf("<%s", ef->ef_name);
131438032Speter		else
1315132943Sgshapiro			sm_dprintf(",%s", ef->ef_name);
131690792Sgshapiro		first = false;
131738032Speter	}
131838032Speter	if (!first)
1319132943Sgshapiro		sm_dprintf(">\n");
132038032Speter}
1321