envelope.c revision 71345
138032Speter/*
264562Sgshapiro * Copyright (c) 1998-2000 Sendmail, 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
1438032Speter#ifndef lint
1571345Sgshapirostatic char id[] = "@(#)$Id: envelope.c,v 8.180.14.6 2000/11/30 00:39:46 gshapiro Exp $";
1664562Sgshapiro#endif /* ! lint */
1738032Speter
1864562Sgshapiro#include <sendmail.h>
1938032Speter
2064562Sgshapiro
2138032Speter/*
2238032Speter**  NEWENVELOPE -- allocate a new envelope
2338032Speter**
2438032Speter**	Supports inheritance.
2538032Speter**
2638032Speter**	Parameters:
2738032Speter**		e -- the new envelope to fill in.
2838032Speter**		parent -- the envelope to be the parent of e.
2938032Speter**
3038032Speter**	Returns:
3138032Speter**		e.
3238032Speter**
3338032Speter**	Side Effects:
3438032Speter**		none.
3538032Speter*/
3638032Speter
3738032SpeterENVELOPE *
3838032Speternewenvelope(e, parent)
3938032Speter	register ENVELOPE *e;
4038032Speter	register ENVELOPE *parent;
4138032Speter{
4238032Speter	if (e == parent && e->e_parent != NULL)
4338032Speter		parent = e->e_parent;
4438032Speter	clearenvelope(e, TRUE);
4538032Speter	if (e == CurEnv)
4664562Sgshapiro		memmove((char *) &e->e_from,
4764562Sgshapiro			(char *) &NullAddress,
4864562Sgshapiro			sizeof e->e_from);
4938032Speter	else
5064562Sgshapiro		memmove((char *) &e->e_from,
5164562Sgshapiro			(char *) &CurEnv->e_from,
5264562Sgshapiro			sizeof e->e_from);
5338032Speter	e->e_parent = parent;
5464562Sgshapiro	assign_queueid(e);
5538032Speter	e->e_ctime = curtime();
5638032Speter	if (parent != NULL)
5738032Speter		e->e_msgpriority = parent->e_msgsize;
5838032Speter	e->e_puthdr = putheader;
5938032Speter	e->e_putbody = putbody;
6038032Speter	if (CurEnv->e_xfp != NULL)
6138032Speter		(void) fflush(CurEnv->e_xfp);
6238032Speter
6364562Sgshapiro	return e;
6438032Speter}
6538032Speter/*
6638032Speter**  DROPENVELOPE -- deallocate an envelope.
6738032Speter**
6838032Speter**	Parameters:
6938032Speter**		e -- the envelope to deallocate.
7038032Speter**		fulldrop -- if set, do return receipts.
7138032Speter**
7238032Speter**	Returns:
7338032Speter**		none.
7438032Speter**
7538032Speter**	Side Effects:
7638032Speter**		housekeeping necessary to dispose of an envelope.
7738032Speter**		Unlocks this queue file.
7838032Speter*/
7938032Speter
8038032Spetervoid
8138032Speterdropenvelope(e, fulldrop)
8238032Speter	register ENVELOPE *e;
8338032Speter	bool fulldrop;
8438032Speter{
8538032Speter	bool queueit = FALSE;
8638032Speter	bool message_timeout = FALSE;
8738032Speter	bool failure_return = FALSE;
8838032Speter	bool delay_return = FALSE;
8938032Speter	bool success_return = FALSE;
9064562Sgshapiro	bool pmnotify = bitset(EF_PM_NOTIFY, e->e_flags);
9164562Sgshapiro	bool done = FALSE;
9238032Speter	register ADDRESS *q;
9338032Speter	char *id = e->e_id;
9471345Sgshapiro	time_t now;
9538032Speter	char buf[MAXLINE];
9638032Speter
9738032Speter	if (tTd(50, 1))
9838032Speter	{
9964562Sgshapiro		dprintf("dropenvelope %lx: id=", (u_long) e);
10038032Speter		xputs(e->e_id);
10164562Sgshapiro		dprintf(", flags=");
10238032Speter		printenvflags(e);
10338032Speter		if (tTd(50, 10))
10438032Speter		{
10564562Sgshapiro			dprintf("sendq=");
10638032Speter			printaddr(e->e_sendqueue, TRUE);
10738032Speter		}
10838032Speter	}
10938032Speter
11038032Speter	if (LogLevel > 84)
11138032Speter		sm_syslog(LOG_DEBUG, id,
11264562Sgshapiro			  "dropenvelope, e_flags=0x%lx, OpMode=%c, pid=%d",
11364562Sgshapiro			  e->e_flags, OpMode, getpid());
11438032Speter
11538032Speter	/* we must have an id to remove disk files */
11638032Speter	if (id == NULL)
11738032Speter		return;
11838032Speter
11938032Speter	/* if verify-only mode, we can skip most of this */
12038032Speter	if (OpMode == MD_VERIFY)
12138032Speter		goto simpledrop;
12238032Speter
12338032Speter	if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
12438032Speter		logsender(e, NULL);
12538032Speter	e->e_flags &= ~EF_LOGSENDER;
12638032Speter
12738032Speter	/* post statistics */
12838032Speter	poststats(StatFile);
12938032Speter
13038032Speter	/*
13138032Speter	**  Extract state information from dregs of send list.
13238032Speter	*/
13338032Speter
13471345Sgshapiro	now = curtime();
13571345Sgshapiro	if (now > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
13638032Speter		message_timeout = TRUE;
13738032Speter
13864562Sgshapiro	if (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
13964562Sgshapiro	    !bitset(EF_RESPONSE, e->e_flags))
14064562Sgshapiro	{
14164562Sgshapiro		message_timeout = TRUE;
14264562Sgshapiro		e->e_flags |= EF_FATALERRS|EF_CLRQUEUE;
14364562Sgshapiro	}
14464562Sgshapiro
14538032Speter	e->e_flags &= ~EF_QUEUERUN;
14638032Speter	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
14738032Speter	{
14864562Sgshapiro		if (QS_IS_UNDELIVERED(q->q_state))
14938032Speter			queueit = TRUE;
15038032Speter
15138032Speter		/* see if a notification is needed */
15238032Speter		if (bitset(QPINGONFAILURE, q->q_flags) &&
15364562Sgshapiro		    ((message_timeout && QS_IS_QUEUEUP(q->q_state)) ||
15464562Sgshapiro		     QS_IS_BADADDR(q->q_state) ||
15564562Sgshapiro		     (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
15664562Sgshapiro		      !bitset(EF_RESPONSE, e->e_flags))))
15764562Sgshapiro
15838032Speter		{
15938032Speter			failure_return = TRUE;
16064562Sgshapiro			if (!done && q->q_owner == NULL &&
16164562Sgshapiro			    !emptyaddr(&e->e_from))
16264562Sgshapiro			{
16338032Speter				(void) sendtolist(e->e_from.q_paddr, NULLADDR,
16438032Speter						  &e->e_errorqueue, 0, e);
16564562Sgshapiro				done = TRUE;
16664562Sgshapiro			}
16738032Speter		}
16838032Speter		else if (bitset(QPINGONSUCCESS, q->q_flags) &&
16964562Sgshapiro			 ((QS_IS_SENT(q->q_state) &&
17038032Speter			   bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) ||
17138032Speter			  bitset(QRELAYED|QEXPANDED|QDELIVERED, q->q_flags)))
17238032Speter		{
17338032Speter			success_return = TRUE;
17438032Speter		}
17538032Speter	}
17638032Speter
17738032Speter	if (e->e_class < 0)
17838032Speter		e->e_flags |= EF_NO_BODY_RETN;
17938032Speter
18038032Speter	/*
18138032Speter	**  See if the message timed out.
18238032Speter	*/
18338032Speter
18438032Speter	if (!queueit)
18564562Sgshapiro		/* EMPTY */
18638032Speter		/* nothing to do */ ;
18738032Speter	else if (message_timeout)
18838032Speter	{
18938032Speter		if (failure_return)
19038032Speter		{
19138032Speter			(void) snprintf(buf, sizeof buf,
19264562Sgshapiro					"Cannot send message for %s",
19364562Sgshapiro					pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
19438032Speter			if (e->e_message != NULL)
19538032Speter				free(e->e_message);
19638032Speter			e->e_message = newstr(buf);
19738032Speter			message(buf);
19838032Speter			e->e_flags |= EF_CLRQUEUE;
19938032Speter		}
20038032Speter		fprintf(e->e_xfp, "Message could not be delivered for %s\n",
20138032Speter			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
20238032Speter		fprintf(e->e_xfp, "Message will be deleted from queue\n");
20338032Speter		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
20438032Speter		{
20564562Sgshapiro			if (QS_IS_UNDELIVERED(q->q_state))
20638032Speter			{
20764562Sgshapiro				q->q_state = QS_BADADDR;
20838032Speter				q->q_status = "4.4.7";
20938032Speter			}
21038032Speter		}
21138032Speter	}
21238032Speter	else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
21371345Sgshapiro		 now > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass])
21438032Speter	{
21538032Speter		if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
21638032Speter		    e->e_class >= 0 &&
21738032Speter		    e->e_from.q_paddr != NULL &&
21838032Speter		    strcmp(e->e_from.q_paddr, "<>") != 0 &&
21938032Speter		    strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
22038032Speter		    (strlen(e->e_from.q_paddr) <= (SIZE_T) 8 ||
22138032Speter		     strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0))
22238032Speter		{
22338032Speter			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
22438032Speter			{
22564562Sgshapiro				if (QS_IS_QUEUEUP(q->q_state) &&
22664562Sgshapiro#if _FFR_NODELAYDSN_ON_HOLD
22764562Sgshapiro				    !bitnset(M_HOLD, q->q_mailer->m_flags) &&
22864562Sgshapiro#endif /* _FFR_NODELAYDSN_ON_HOLD */
22938032Speter				    bitset(QPINGONDELAY, q->q_flags))
23038032Speter				{
23138032Speter					q->q_flags |= QDELAYED;
23238032Speter					delay_return = TRUE;
23338032Speter				}
23438032Speter			}
23538032Speter		}
23638032Speter		if (delay_return)
23738032Speter		{
23838032Speter			(void) snprintf(buf, sizeof buf,
23938032Speter				"Warning: could not send message for past %s",
24038032Speter				pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
24138032Speter			if (e->e_message != NULL)
24238032Speter				free(e->e_message);
24338032Speter			e->e_message = newstr(buf);
24438032Speter			message(buf);
24538032Speter			e->e_flags |= EF_WARNING;
24638032Speter		}
24738032Speter		fprintf(e->e_xfp,
24838032Speter			"Warning: message still undelivered after %s\n",
24938032Speter			pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
25038032Speter		fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
25138032Speter			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
25238032Speter	}
25338032Speter
25438032Speter	if (tTd(50, 2))
25564562Sgshapiro		dprintf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n",
25638032Speter			failure_return, delay_return, success_return, queueit);
25738032Speter
25838032Speter	/*
25938032Speter	**  If we had some fatal error, but no addresses are marked as
26038032Speter	**  bad, mark them _all_ as bad.
26138032Speter	*/
26238032Speter
26338032Speter	if (bitset(EF_FATALERRS, e->e_flags) && !failure_return)
26438032Speter	{
26538032Speter		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
26638032Speter		{
26764562Sgshapiro			if ((QS_IS_OK(q->q_state) ||
26864562Sgshapiro			     QS_IS_VERIFIED(q->q_state)) &&
26938032Speter			    bitset(QPINGONFAILURE, q->q_flags))
27038032Speter			{
27138032Speter				failure_return = TRUE;
27264562Sgshapiro				q->q_state = QS_BADADDR;
27338032Speter			}
27438032Speter		}
27538032Speter	}
27638032Speter
27738032Speter	/*
27838032Speter	**  Send back return receipts as requested.
27938032Speter	*/
28038032Speter
28138032Speter	if (success_return && !failure_return && !delay_return && fulldrop &&
28238032Speter	    !bitset(PRIV_NORECEIPTS, PrivacyFlags) &&
28338032Speter	    strcmp(e->e_from.q_paddr, "<>") != 0)
28438032Speter	{
28538032Speter		auto ADDRESS *rlist = NULL;
28638032Speter
28738032Speter		if (tTd(50, 8))
28864562Sgshapiro			dprintf("dropenvelope(%s): sending return receipt\n",
28964562Sgshapiro				id);
29038032Speter		e->e_flags |= EF_SENDRECEIPT;
29138032Speter		(void) sendtolist(e->e_from.q_paddr, NULLADDR, &rlist, 0, e);
29238032Speter		(void) returntosender("Return receipt", rlist, RTSF_NO_BODY, e);
29338032Speter	}
29438032Speter	e->e_flags &= ~EF_SENDRECEIPT;
29538032Speter
29638032Speter	/*
29738032Speter	**  Arrange to send error messages if there are fatal errors.
29838032Speter	*/
29938032Speter
30038032Speter	if ((failure_return || delay_return) && e->e_errormode != EM_QUIET)
30138032Speter	{
30238032Speter		if (tTd(50, 8))
30364562Sgshapiro			dprintf("dropenvelope(%s): saving mail\n", id);
30438032Speter		savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags));
30538032Speter	}
30638032Speter
30738032Speter	/*
30838032Speter	**  Arrange to send warning messages to postmaster as requested.
30938032Speter	*/
31038032Speter
31164562Sgshapiro	if ((failure_return || pmnotify) &&
31238032Speter	    PostMasterCopy != NULL &&
31364562Sgshapiro	    !bitset(EF_RESPONSE, e->e_flags) &&
31464562Sgshapiro	    e->e_class >= 0)
31538032Speter	{
31638032Speter		auto ADDRESS *rlist = NULL;
31764562Sgshapiro		char pcopy[MAXNAME];
31838032Speter
31964562Sgshapiro		if (failure_return)
32064562Sgshapiro		{
32164562Sgshapiro			expand(PostMasterCopy, pcopy, sizeof pcopy, e);
32264562Sgshapiro
32364562Sgshapiro			if (tTd(50, 8))
32464562Sgshapiro				dprintf("dropenvelope(%s): sending postmaster copy to %s\n",
32564562Sgshapiro					id, pcopy);
32664562Sgshapiro			(void) sendtolist(pcopy, NULLADDR, &rlist, 0, e);
32764562Sgshapiro		}
32864562Sgshapiro		if (pmnotify)
32964562Sgshapiro			(void) sendtolist("postmaster", NULLADDR,
33064562Sgshapiro					  &rlist, 0, e);
33164562Sgshapiro		(void) returntosender(e->e_message, rlist,
33264562Sgshapiro				      RTSF_PM_BOUNCE|RTSF_NO_BODY, e);
33338032Speter	}
33438032Speter
33538032Speter	/*
33638032Speter	**  Instantiate or deinstantiate the queue.
33738032Speter	*/
33838032Speter
33938032Spetersimpledrop:
34038032Speter	if (tTd(50, 8))
34164562Sgshapiro		dprintf("dropenvelope(%s): at simpledrop, queueit=%d\n",
34238032Speter			id, queueit);
34338032Speter	if (!queueit || bitset(EF_CLRQUEUE, e->e_flags))
34438032Speter	{
34538032Speter		if (tTd(50, 1))
34638032Speter		{
34764562Sgshapiro			dprintf("\n===== Dropping [dq]f%s... queueit=%d, e_flags=",
34838032Speter				e->e_id, queueit);
34938032Speter			printenvflags(e);
35038032Speter		}
35138032Speter		xunlink(queuename(e, 'd'));
35238032Speter		xunlink(queuename(e, 'q'));
35338032Speter
35464562Sgshapiro		if (e->e_ntries > 0 && LogLevel > 9)
35564562Sgshapiro			sm_syslog(LOG_INFO, id, "done; delay=%s, ntries=%d",
35664562Sgshapiro				  pintvl(curtime() - e->e_ctime, TRUE),
35764562Sgshapiro				  e->e_ntries);
35838032Speter	}
35938032Speter	else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
36038032Speter	{
36138032Speter#if QUEUE
36238032Speter		queueup(e, FALSE);
36338032Speter#else /* QUEUE */
36464562Sgshapiro		syserr("554 5.3.0 dropenvelope: queueup");
36538032Speter#endif /* QUEUE */
36638032Speter	}
36738032Speter
36838032Speter	/* now unlock the job */
36938032Speter	if (tTd(50, 8))
37064562Sgshapiro		dprintf("dropenvelope(%s): unlocking job\n", id);
37138032Speter	closexscript(e);
37238032Speter	unlockqueue(e);
37338032Speter
37438032Speter	/* make sure that this envelope is marked unused */
37538032Speter	if (e->e_dfp != NULL)
37664562Sgshapiro		(void) bfclose(e->e_dfp);
37738032Speter	e->e_dfp = NULL;
37838032Speter	e->e_id = NULL;
37938032Speter	e->e_flags &= ~EF_HAS_DF;
38038032Speter}
38138032Speter/*
38238032Speter**  CLEARENVELOPE -- clear an envelope without unlocking
38338032Speter**
38438032Speter**	This is normally used by a child process to get a clean
38538032Speter**	envelope without disturbing the parent.
38638032Speter**
38738032Speter**	Parameters:
38838032Speter**		e -- the envelope to clear.
38938032Speter**		fullclear - if set, the current envelope is total
39038032Speter**			garbage and should be ignored; otherwise,
39138032Speter**			release any resources it may indicate.
39238032Speter**
39338032Speter**	Returns:
39438032Speter**		none.
39538032Speter**
39638032Speter**	Side Effects:
39738032Speter**		Closes files associated with the envelope.
39838032Speter**		Marks the envelope as unallocated.
39938032Speter*/
40038032Speter
40138032Spetervoid
40238032Speterclearenvelope(e, fullclear)
40338032Speter	register ENVELOPE *e;
40438032Speter	bool fullclear;
40538032Speter{
40638032Speter	register HDR *bh;
40738032Speter	register HDR **nhp;
40838032Speter	extern ENVELOPE BlankEnvelope;
40938032Speter
41038032Speter	if (!fullclear)
41138032Speter	{
41238032Speter		/* clear out any file information */
41338032Speter		if (e->e_xfp != NULL)
41464562Sgshapiro			(void) bfclose(e->e_xfp);
41538032Speter		if (e->e_dfp != NULL)
41664562Sgshapiro			(void) bfclose(e->e_dfp);
41738032Speter		e->e_xfp = e->e_dfp = NULL;
41838032Speter	}
41938032Speter
42038032Speter	/* now clear out the data */
42138032Speter	STRUCTCOPY(BlankEnvelope, *e);
42238032Speter	e->e_message = NULL;
42338032Speter	if (Verbose)
42464562Sgshapiro		set_delivery_mode(SM_DELIVER, e);
42538032Speter	bh = BlankEnvelope.e_header;
42638032Speter	nhp = &e->e_header;
42738032Speter	while (bh != NULL)
42838032Speter	{
42938032Speter		*nhp = (HDR *) xalloc(sizeof *bh);
43064562Sgshapiro		memmove((char *) *nhp, (char *) bh, sizeof *bh);
43138032Speter		bh = bh->h_link;
43238032Speter		nhp = &(*nhp)->h_link;
43338032Speter	}
43438032Speter}
43538032Speter/*
43638032Speter**  INITSYS -- initialize instantiation of system
43738032Speter**
43838032Speter**	In Daemon mode, this is done in the child.
43938032Speter**
44038032Speter**	Parameters:
44164562Sgshapiro**		e -- the envelope to use.
44238032Speter**
44338032Speter**	Returns:
44438032Speter**		none.
44538032Speter**
44638032Speter**	Side Effects:
44738032Speter**		Initializes the system macros, some global variables,
44838032Speter**		etc.  In particular, the current time in various
44938032Speter**		forms is set.
45038032Speter*/
45138032Speter
45238032Spetervoid
45338032Speterinitsys(e)
45438032Speter	register ENVELOPE *e;
45538032Speter{
45638032Speter	char cbuf[5];				/* holds hop count */
45738032Speter	char pbuf[10];				/* holds pid */
45838032Speter#ifdef TTYNAME
45938032Speter	static char ybuf[60];			/* holds tty id */
46038032Speter	register char *p;
46138032Speter	extern char *ttyname();
46238032Speter#endif /* TTYNAME */
46338032Speter
46438032Speter	/*
46538032Speter	**  Give this envelope a reality.
46638032Speter	**	I.e., an id, a transcript, and a creation time.
46738032Speter	*/
46838032Speter
46964562Sgshapiro	setnewqueue(e);
47038032Speter	openxscript(e);
47138032Speter	e->e_ctime = curtime();
47264562Sgshapiro#if _FFR_QUEUEDELAY
47364562Sgshapiro	e->e_queuealg = QueueAlg;
47464562Sgshapiro	e->e_queuedelay = QueueInitDelay;
47564562Sgshapiro#endif /* _FFR_QUEUEDELAY */
47638032Speter
47738032Speter	/*
47838032Speter	**  Set OutChannel to something useful if stdout isn't it.
47938032Speter	**	This arranges that any extra stuff the mailer produces
48038032Speter	**	gets sent back to the user on error (because it is
48138032Speter	**	tucked away in the transcript).
48238032Speter	*/
48338032Speter
48438032Speter	if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
48538032Speter	    e->e_xfp != NULL)
48638032Speter		OutChannel = e->e_xfp;
48738032Speter
48838032Speter	/*
48938032Speter	**  Set up some basic system macros.
49038032Speter	*/
49138032Speter
49238032Speter	/* process id */
49364562Sgshapiro	(void) snprintf(pbuf, sizeof pbuf, "%d", (int) getpid());
49438032Speter	define('p', newstr(pbuf), e);
49538032Speter
49638032Speter	/* hop count */
49738032Speter	(void) snprintf(cbuf, sizeof cbuf, "%d", e->e_hopcount);
49838032Speter	define('c', newstr(cbuf), e);
49938032Speter
50038032Speter	/* time as integer, unix time, arpa time */
50138032Speter	settime(e);
50238032Speter
50364562Sgshapiro	/* Load average */
50464562Sgshapiro	(void)sm_getla(e);
50564562Sgshapiro
50638032Speter#ifdef TTYNAME
50738032Speter	/* tty name */
50838032Speter	if (macvalue('y', e) == NULL)
50938032Speter	{
51038032Speter		p = ttyname(2);
51138032Speter		if (p != NULL)
51238032Speter		{
51338032Speter			if (strrchr(p, '/') != NULL)
51438032Speter				p = strrchr(p, '/') + 1;
51538032Speter			snprintf(ybuf, sizeof ybuf, "%s", p);
51638032Speter			define('y', ybuf, e);
51738032Speter		}
51838032Speter	}
51938032Speter#endif /* TTYNAME */
52038032Speter}
52138032Speter/*
52238032Speter**  SETTIME -- set the current time.
52338032Speter**
52438032Speter**	Parameters:
52564562Sgshapiro**		e -- the envelope in which the macros should be set.
52638032Speter**
52738032Speter**	Returns:
52838032Speter**		none.
52938032Speter**
53038032Speter**	Side Effects:
53138032Speter**		Sets the various time macros -- $a, $b, $d, $t.
53238032Speter*/
53338032Speter
53438032Spetervoid
53538032Spetersettime(e)
53638032Speter	register ENVELOPE *e;
53738032Speter{
53838032Speter	register char *p;
53938032Speter	auto time_t now;
54038032Speter	char tbuf[20];				/* holds "current" time */
54138032Speter	char dbuf[30];				/* holds ctime(tbuf) */
54238032Speter	register struct tm *tm;
54338032Speter
54438032Speter	now = curtime();
54538032Speter	tm = gmtime(&now);
54638032Speter	(void) snprintf(tbuf, sizeof tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
54764562Sgshapiro			tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
54838032Speter	define('t', newstr(tbuf), e);
54964562Sgshapiro	(void) strlcpy(dbuf, ctime(&now), sizeof dbuf);
55038032Speter	p = strchr(dbuf, '\n');
55138032Speter	if (p != NULL)
55238032Speter		*p = '\0';
55338032Speter	define('d', newstr(dbuf), e);
55438032Speter	p = arpadate(dbuf);
55538032Speter	p = newstr(p);
55638032Speter	if (macvalue('a', e) == NULL)
55738032Speter		define('a', p, e);
55838032Speter	define('b', p, e);
55938032Speter}
56038032Speter/*
56138032Speter**  OPENXSCRIPT -- Open transcript file
56238032Speter**
56338032Speter**	Creates a transcript file for possible eventual mailing or
56438032Speter**	sending back.
56538032Speter**
56638032Speter**	Parameters:
56738032Speter**		e -- the envelope to create the transcript in/for.
56838032Speter**
56938032Speter**	Returns:
57038032Speter**		none
57138032Speter**
57238032Speter**	Side Effects:
57338032Speter**		Creates the transcript file.
57438032Speter*/
57538032Speter
57638032Speter#ifndef O_APPEND
57764562Sgshapiro# define O_APPEND	0
57864562Sgshapiro#endif /* ! O_APPEND */
57938032Speter
58038032Spetervoid
58138032Speteropenxscript(e)
58238032Speter	register ENVELOPE *e;
58338032Speter{
58438032Speter	register char *p;
58538032Speter
58638032Speter	if (e->e_xfp != NULL)
58738032Speter		return;
58864562Sgshapiro
58964562Sgshapiro#if 0
59064562Sgshapiro	if (e->e_lockfp == NULL && bitset(EF_INQUEUE, e->e_flags))
59164562Sgshapiro		syserr("openxscript: job not locked");
59264562Sgshapiro#endif /* 0 */
59364562Sgshapiro
59438032Speter	p = queuename(e, 'x');
59564562Sgshapiro	e->e_xfp = bfopen(p, FileMode, XscriptFileBufferSize,
59664562Sgshapiro			  SFF_NOTEXCL|SFF_OPENASROOT);
59764562Sgshapiro
59864562Sgshapiro	if (e->e_xfp == NULL)
59938032Speter	{
60038032Speter		syserr("Can't create transcript file %s", p);
60164562Sgshapiro		e->e_xfp = fopen("/dev/null", "r+");
60264562Sgshapiro		if (e->e_xfp == NULL)
60338032Speter			syserr("!Can't open /dev/null");
60438032Speter	}
60564562Sgshapiro#if HASSETVBUF
60664562Sgshapiro	(void) setvbuf(e->e_xfp, NULL, _IOLBF, 0);
60764562Sgshapiro#else /* HASSETVBUF */
60864562Sgshapiro	(void) setlinebuf(e->e_xfp);
60964562Sgshapiro#endif /* HASSETVBUF */
61038032Speter	if (tTd(46, 9))
61138032Speter	{
61264562Sgshapiro		dprintf("openxscript(%s):\n  ", p);
61338032Speter		dumpfd(fileno(e->e_xfp), TRUE, FALSE);
61438032Speter	}
61538032Speter}
61638032Speter/*
61738032Speter**  CLOSEXSCRIPT -- close the transcript file.
61838032Speter**
61938032Speter**	Parameters:
62038032Speter**		e -- the envelope containing the transcript to close.
62138032Speter**
62238032Speter**	Returns:
62338032Speter**		none.
62438032Speter**
62538032Speter**	Side Effects:
62638032Speter**		none.
62738032Speter*/
62838032Speter
62938032Spetervoid
63038032Speterclosexscript(e)
63138032Speter	register ENVELOPE *e;
63238032Speter{
63338032Speter	if (e->e_xfp == NULL)
63438032Speter		return;
63564562Sgshapiro#if 0
63664562Sgshapiro	if (e->e_lockfp == NULL)
63764562Sgshapiro		syserr("closexscript: job not locked");
63864562Sgshapiro#endif /* 0 */
63964562Sgshapiro	(void) bfclose(e->e_xfp);
64038032Speter	e->e_xfp = NULL;
64138032Speter}
64238032Speter/*
64338032Speter**  SETSENDER -- set the person who this message is from
64438032Speter**
64538032Speter**	Under certain circumstances allow the user to say who
64638032Speter**	s/he is (using -f or -r).  These are:
64738032Speter**	1.  The user's uid is zero (root).
64838032Speter**	2.  The user's login name is in an approved list (typically
64938032Speter**	    from a network server).
65038032Speter**	3.  The address the user is trying to claim has a
65138032Speter**	    "!" character in it (since #2 doesn't do it for
65238032Speter**	    us if we are dialing out for UUCP).
65338032Speter**	A better check to replace #3 would be if the
65438032Speter**	effective uid is "UUCP" -- this would require me
65538032Speter**	to rewrite getpwent to "grab" uucp as it went by,
65638032Speter**	make getname more nasty, do another passwd file
65738032Speter**	scan, or compile the UID of "UUCP" into the code,
65838032Speter**	all of which are reprehensible.
65938032Speter**
66038032Speter**	Assuming all of these fail, we figure out something
66138032Speter**	ourselves.
66238032Speter**
66338032Speter**	Parameters:
66438032Speter**		from -- the person we would like to believe this message
66538032Speter**			is from, as specified on the command line.
66638032Speter**		e -- the envelope in which we would like the sender set.
66738032Speter**		delimptr -- if non-NULL, set to the location of the
66838032Speter**			trailing delimiter.
66938032Speter**		delimchar -- the character that will delimit the sender
67038032Speter**			address.
67138032Speter**		internal -- set if this address is coming from an internal
67238032Speter**			source such as an owner alias.
67338032Speter**
67438032Speter**	Returns:
67538032Speter**		none.
67638032Speter**
67738032Speter**	Side Effects:
67838032Speter**		sets sendmail's notion of who the from person is.
67938032Speter*/
68038032Speter
68138032Spetervoid
68238032Spetersetsender(from, e, delimptr, delimchar, internal)
68338032Speter	char *from;
68438032Speter	register ENVELOPE *e;
68538032Speter	char **delimptr;
68638032Speter	int delimchar;
68738032Speter	bool internal;
68838032Speter{
68938032Speter	register char **pvp;
69038032Speter	char *realname = NULL;
69138032Speter	register struct passwd *pw;
69238032Speter	char *bp;
69338032Speter	char buf[MAXNAME + 2];
69438032Speter	char pvpbuf[PSBUFSIZE];
69538032Speter	extern char *FullName;
69638032Speter
69738032Speter	if (tTd(45, 1))
69864562Sgshapiro		dprintf("setsender(%s)\n", from == NULL ? "" : from);
69938032Speter
70038032Speter	/*
70138032Speter	**  Figure out the real user executing us.
70238032Speter	**	Username can return errno != 0 on non-errors.
70338032Speter	*/
70438032Speter
70538032Speter	if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP ||
70638032Speter	    OpMode == MD_ARPAFTP || OpMode == MD_DAEMON)
70738032Speter		realname = from;
70838032Speter	if (realname == NULL || realname[0] == '\0')
70938032Speter		realname = username();
71038032Speter
71138032Speter	if (ConfigLevel < 2)
71238032Speter		SuprErrs = TRUE;
71338032Speter
71464562Sgshapiro#if _FFR_ADDR_TYPE
71564562Sgshapiro	define(macid("{addr_type}", NULL), "e s", e);
71664562Sgshapiro#endif /* _FFR_ADDR_TYPE */
71764562Sgshapiro	/* preset state for then clause in case from == NULL */
71864562Sgshapiro	e->e_from.q_state = QS_BADADDR;
71964562Sgshapiro	e->e_from.q_flags = 0;
72038032Speter	if (from == NULL ||
72138032Speter	    parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
72238032Speter		      delimchar, delimptr, e) == NULL ||
72364562Sgshapiro	    QS_IS_BADADDR(e->e_from.q_state) ||
72438032Speter	    e->e_from.q_mailer == ProgMailer ||
72538032Speter	    e->e_from.q_mailer == FileMailer ||
72638032Speter	    e->e_from.q_mailer == InclMailer)
72738032Speter	{
72838032Speter		/* log garbage addresses for traceback */
72938032Speter		if (from != NULL && LogLevel > 2)
73038032Speter		{
73138032Speter			char *p;
73238032Speter			char ebuf[MAXNAME * 2 + 2];
73338032Speter
73438032Speter			p = macvalue('_', e);
73538032Speter			if (p == NULL)
73638032Speter			{
73738032Speter				char *host = RealHostName;
73838032Speter
73938032Speter				if (host == NULL)
74038032Speter					host = MyHostName;
74138032Speter				(void) snprintf(ebuf, sizeof ebuf, "%.*s@%.*s",
74238032Speter					MAXNAME, realname,
74338032Speter					MAXNAME, host);
74438032Speter				p = ebuf;
74538032Speter			}
74638032Speter			sm_syslog(LOG_NOTICE, e->e_id,
74764562Sgshapiro				  "setsender: %s: invalid or unparsable, received from %s",
74864562Sgshapiro				  shortenstring(from, 83), p);
74938032Speter		}
75038032Speter		if (from != NULL)
75138032Speter		{
75264562Sgshapiro			if (!QS_IS_BADADDR(e->e_from.q_state))
75338032Speter			{
75438032Speter				/* it was a bogus mailer in the from addr */
75538032Speter				e->e_status = "5.1.7";
75664562Sgshapiro				usrerrenh(e->e_status,
75764562Sgshapiro					  "553 Invalid sender address");
75838032Speter			}
75938032Speter			SuprErrs = TRUE;
76038032Speter		}
76138032Speter		if (from == realname ||
76238032Speter		    parseaddr(from = newstr(realname), &e->e_from,
76338032Speter			      RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL)
76438032Speter		{
76538032Speter			char nbuf[100];
76638032Speter
76738032Speter			SuprErrs = TRUE;
76838032Speter			expand("\201n", nbuf, sizeof nbuf, e);
76938032Speter			if (parseaddr(from = newstr(nbuf), &e->e_from,
77038032Speter				      RF_COPYALL, ' ', NULL, e) == NULL &&
77138032Speter			    parseaddr(from = "postmaster", &e->e_from,
77264562Sgshapiro				      RF_COPYALL, ' ', NULL, e) == NULL)
77364562Sgshapiro				syserr("553 5.3.0 setsender: can't even parse postmaster!");
77438032Speter		}
77538032Speter	}
77638032Speter	else
77738032Speter		FromFlag = TRUE;
77864562Sgshapiro	e->e_from.q_state = QS_SENDER;
77938032Speter	if (tTd(45, 5))
78038032Speter	{
78164562Sgshapiro		dprintf("setsender: QS_SENDER ");
78238032Speter		printaddr(&e->e_from, FALSE);
78338032Speter	}
78438032Speter	SuprErrs = FALSE;
78538032Speter
78664562Sgshapiro#if USERDB
78738032Speter	if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags))
78838032Speter	{
78938032Speter		register char *p;
79038032Speter
79138032Speter		p = udbsender(e->e_from.q_user);
79238032Speter		if (p != NULL)
79338032Speter			from = p;
79438032Speter	}
79564562Sgshapiro#endif /* USERDB */
79638032Speter
79738032Speter	if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
79838032Speter	{
79938032Speter		if (!internal)
80038032Speter		{
80138032Speter			/* if the user already given fullname don't redefine */
80238032Speter			if (FullName == NULL)
80338032Speter				FullName = macvalue('x', e);
80438032Speter			if (FullName != NULL && FullName[0] == '\0')
80538032Speter				FullName = NULL;
80638032Speter		}
80738032Speter
80838032Speter		if (e->e_from.q_user[0] != '\0' &&
80938032Speter		    (pw = sm_getpwnam(e->e_from.q_user)) != NULL)
81038032Speter		{
81138032Speter			/*
81238032Speter			**  Process passwd file entry.
81338032Speter			*/
81438032Speter
81538032Speter			/* extract home directory */
81666494Sgshapiro			if (*pw->pw_dir == '\0')
81766494Sgshapiro				e->e_from.q_home = NULL;
81866494Sgshapiro			else if (strcmp(pw->pw_dir, "/") == 0)
81938032Speter				e->e_from.q_home = newstr("");
82038032Speter			else
82138032Speter				e->e_from.q_home = newstr(pw->pw_dir);
82238032Speter			define('z', e->e_from.q_home, e);
82338032Speter
82438032Speter			/* extract user and group id */
82538032Speter			e->e_from.q_uid = pw->pw_uid;
82638032Speter			e->e_from.q_gid = pw->pw_gid;
82738032Speter			e->e_from.q_flags |= QGOODUID;
82838032Speter
82938032Speter			/* extract full name from passwd file */
83038032Speter			if (FullName == NULL && pw->pw_gecos != NULL &&
83138032Speter			    strcmp(pw->pw_name, e->e_from.q_user) == 0 &&
83238032Speter			    !internal)
83338032Speter			{
83438032Speter				buildfname(pw->pw_gecos, e->e_from.q_user, buf, sizeof buf);
83538032Speter				if (buf[0] != '\0')
83638032Speter					FullName = newstr(buf);
83738032Speter			}
83838032Speter		}
83938032Speter		else
84038032Speter		{
84164562Sgshapiro			e->e_from.q_home = NULL;
84238032Speter		}
84338032Speter		if (FullName != NULL && !internal)
84438032Speter			define('x', FullName, e);
84538032Speter	}
84643730Speter	else if (!internal && OpMode != MD_DAEMON && OpMode != MD_SMTP)
84738032Speter	{
84838032Speter		if (e->e_from.q_home == NULL)
84938032Speter		{
85038032Speter			e->e_from.q_home = getenv("HOME");
85166494Sgshapiro			if (e->e_from.q_home != NULL)
85266494Sgshapiro			{
85366494Sgshapiro				if (*e->e_from.q_home == '\0')
85466494Sgshapiro					e->e_from.q_home = NULL;
85566494Sgshapiro				else if (strcmp(e->e_from.q_home, "/") == 0)
85666494Sgshapiro					e->e_from.q_home++;
85766494Sgshapiro			}
85838032Speter		}
85938032Speter		e->e_from.q_uid = RealUid;
86038032Speter		e->e_from.q_gid = RealGid;
86138032Speter		e->e_from.q_flags |= QGOODUID;
86238032Speter	}
86338032Speter
86438032Speter	/*
86538032Speter	**  Rewrite the from person to dispose of possible implicit
86638032Speter	**	links in the net.
86738032Speter	*/
86838032Speter
86938032Speter	pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL, NULL);
87038032Speter	if (pvp == NULL)
87138032Speter	{
87238032Speter		/* don't need to give error -- prescan did that already */
87338032Speter		if (LogLevel > 2)
87438032Speter			sm_syslog(LOG_NOTICE, e->e_id,
87564562Sgshapiro				  "cannot prescan from (%s)",
87664562Sgshapiro				  shortenstring(from, MAXSHORTSTR));
87742575Speter		finis(TRUE, ExitStat);
87838032Speter	}
87938032Speter	(void) rewrite(pvp, 3, 0, e);
88038032Speter	(void) rewrite(pvp, 1, 0, e);
88138032Speter	(void) rewrite(pvp, 4, 0, e);
88264562Sgshapiro#if _FFR_ADDR_TYPE
88364562Sgshapiro	define(macid("{addr_type}", NULL), NULL, e);
88464562Sgshapiro#endif /* _FFR_ADDR_TYPE */
88538032Speter	bp = buf + 1;
88638032Speter	cataddr(pvp, NULL, bp, sizeof buf - 2, '\0');
88738032Speter	if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags))
88838032Speter	{
88938032Speter		/* heuristic: route-addr: add angle brackets */
89064562Sgshapiro		(void) strlcat(bp, ">", sizeof buf - 1);
89138032Speter		*--bp = '<';
89238032Speter	}
89338032Speter	e->e_sender = newstr(bp);
89438032Speter	define('f', e->e_sender, e);
89538032Speter
89638032Speter	/* save the domain spec if this mailer wants it */
89738032Speter	if (e->e_from.q_mailer != NULL &&
89838032Speter	    bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags))
89938032Speter	{
90038032Speter		char **lastat;
90138032Speter
90238032Speter		/* get rid of any pesky angle brackets */
90364562Sgshapiro#if _FFR_ADDR_TYPE
90464562Sgshapiro		define(macid("{addr_type}", NULL), "e s", e);
90564562Sgshapiro#endif /* _FFR_ADDR_TYPE */
90638032Speter		(void) rewrite(pvp, 3, 0, e);
90738032Speter		(void) rewrite(pvp, 1, 0, e);
90838032Speter		(void) rewrite(pvp, 4, 0, e);
90964562Sgshapiro#if _FFR_ADDR_TYPE
91064562Sgshapiro		define(macid("{addr_type}", NULL), NULL, e);
91164562Sgshapiro#endif /* _FFR_ADDR_TYPE */
91238032Speter
91338032Speter		/* strip off to the last "@" sign */
91438032Speter		for (lastat = NULL; *pvp != NULL; pvp++)
91538032Speter			if (strcmp(*pvp, "@") == 0)
91638032Speter				lastat = pvp;
91738032Speter		if (lastat != NULL)
91838032Speter		{
91938032Speter			e->e_fromdomain = copyplist(lastat, TRUE);
92038032Speter			if (tTd(45, 3))
92138032Speter			{
92264562Sgshapiro				dprintf("Saving from domain: ");
92338032Speter				printav(e->e_fromdomain);
92438032Speter			}
92538032Speter		}
92638032Speter	}
92738032Speter}
92838032Speter/*
92938032Speter**  PRINTENVFLAGS -- print envelope flags for debugging
93038032Speter**
93138032Speter**	Parameters:
93238032Speter**		e -- the envelope with the flags to be printed.
93338032Speter**
93438032Speter**	Returns:
93538032Speter**		none.
93638032Speter*/
93738032Speter
93838032Speterstruct eflags
93938032Speter{
94038032Speter	char	*ef_name;
94138032Speter	u_long	ef_bit;
94238032Speter};
94338032Speter
94464562Sgshapirostatic struct eflags	EnvelopeFlags[] =
94538032Speter{
94638032Speter	{ "OLDSTYLE",		EF_OLDSTYLE	},
94738032Speter	{ "INQUEUE",		EF_INQUEUE	},
94838032Speter	{ "NO_BODY_RETN",	EF_NO_BODY_RETN	},
94938032Speter	{ "CLRQUEUE",		EF_CLRQUEUE	},
95038032Speter	{ "SENDRECEIPT",	EF_SENDRECEIPT	},
95138032Speter	{ "FATALERRS",		EF_FATALERRS	},
95238032Speter	{ "DELETE_BCC",		EF_DELETE_BCC	},
95338032Speter	{ "RESPONSE",		EF_RESPONSE	},
95438032Speter	{ "RESENT",		EF_RESENT	},
95538032Speter	{ "VRFYONLY",		EF_VRFYONLY	},
95638032Speter	{ "WARNING",		EF_WARNING	},
95738032Speter	{ "QUEUERUN",		EF_QUEUERUN	},
95838032Speter	{ "GLOBALERRS",		EF_GLOBALERRS	},
95938032Speter	{ "PM_NOTIFY",		EF_PM_NOTIFY	},
96038032Speter	{ "METOO",		EF_METOO	},
96138032Speter	{ "LOGSENDER",		EF_LOGSENDER	},
96238032Speter	{ "NORECEIPT",		EF_NORECEIPT	},
96338032Speter	{ "HAS8BIT",		EF_HAS8BIT	},
96438032Speter	{ "NL_NOT_EOL",		EF_NL_NOT_EOL	},
96538032Speter	{ "CRLF_NOT_EOL",	EF_CRLF_NOT_EOL	},
96638032Speter	{ "RET_PARAM",		EF_RET_PARAM	},
96738032Speter	{ "HAS_DF",		EF_HAS_DF	},
96838032Speter	{ "IS_MIME",		EF_IS_MIME	},
96938032Speter	{ "DONT_MIME",		EF_DONT_MIME	},
97071345Sgshapiro	{ NULL,			0		}
97138032Speter};
97238032Speter
97338032Spetervoid
97438032Speterprintenvflags(e)
97538032Speter	register ENVELOPE *e;
97638032Speter{
97738032Speter	register struct eflags *ef;
97838032Speter	bool first = TRUE;
97938032Speter
98038032Speter	printf("%lx", e->e_flags);
98138032Speter	for (ef = EnvelopeFlags; ef->ef_name != NULL; ef++)
98238032Speter	{
98338032Speter		if (!bitset(ef->ef_bit, e->e_flags))
98438032Speter			continue;
98538032Speter		if (first)
98638032Speter			printf("<%s", ef->ef_name);
98738032Speter		else
98838032Speter			printf(",%s", ef->ef_name);
98938032Speter		first = FALSE;
99038032Speter	}
99138032Speter	if (!first)
99238032Speter		printf(">\n");
99338032Speter}
994