envelope.c revision 64562
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
1564562Sgshapirostatic char id[] = "@(#)$Id: envelope.c,v 8.180.14.3 2000/06/29 05:30:23 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;
9438032Speter	char buf[MAXLINE];
9538032Speter
9638032Speter	if (tTd(50, 1))
9738032Speter	{
9864562Sgshapiro		dprintf("dropenvelope %lx: id=", (u_long) e);
9938032Speter		xputs(e->e_id);
10064562Sgshapiro		dprintf(", flags=");
10138032Speter		printenvflags(e);
10238032Speter		if (tTd(50, 10))
10338032Speter		{
10464562Sgshapiro			dprintf("sendq=");
10538032Speter			printaddr(e->e_sendqueue, TRUE);
10638032Speter		}
10738032Speter	}
10838032Speter
10938032Speter	if (LogLevel > 84)
11038032Speter		sm_syslog(LOG_DEBUG, id,
11164562Sgshapiro			  "dropenvelope, e_flags=0x%lx, OpMode=%c, pid=%d",
11264562Sgshapiro			  e->e_flags, OpMode, getpid());
11338032Speter
11438032Speter	/* we must have an id to remove disk files */
11538032Speter	if (id == NULL)
11638032Speter		return;
11738032Speter
11838032Speter	/* if verify-only mode, we can skip most of this */
11938032Speter	if (OpMode == MD_VERIFY)
12038032Speter		goto simpledrop;
12138032Speter
12238032Speter	if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
12338032Speter		logsender(e, NULL);
12438032Speter	e->e_flags &= ~EF_LOGSENDER;
12538032Speter
12638032Speter	/* post statistics */
12738032Speter	poststats(StatFile);
12838032Speter
12938032Speter	/*
13038032Speter	**  Extract state information from dregs of send list.
13138032Speter	*/
13238032Speter
13338032Speter	if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
13438032Speter		message_timeout = TRUE;
13538032Speter
13664562Sgshapiro	if (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
13764562Sgshapiro	    !bitset(EF_RESPONSE, e->e_flags))
13864562Sgshapiro	{
13964562Sgshapiro		message_timeout = TRUE;
14064562Sgshapiro		e->e_flags |= EF_FATALERRS|EF_CLRQUEUE;
14164562Sgshapiro	}
14264562Sgshapiro
14338032Speter	e->e_flags &= ~EF_QUEUERUN;
14438032Speter	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
14538032Speter	{
14664562Sgshapiro		if (QS_IS_UNDELIVERED(q->q_state))
14738032Speter			queueit = TRUE;
14838032Speter
14938032Speter		/* see if a notification is needed */
15038032Speter		if (bitset(QPINGONFAILURE, q->q_flags) &&
15164562Sgshapiro		    ((message_timeout && QS_IS_QUEUEUP(q->q_state)) ||
15264562Sgshapiro		     QS_IS_BADADDR(q->q_state) ||
15364562Sgshapiro		     (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
15464562Sgshapiro		      !bitset(EF_RESPONSE, e->e_flags))))
15564562Sgshapiro
15638032Speter		{
15738032Speter			failure_return = TRUE;
15864562Sgshapiro			if (!done && q->q_owner == NULL &&
15964562Sgshapiro			    !emptyaddr(&e->e_from))
16064562Sgshapiro			{
16138032Speter				(void) sendtolist(e->e_from.q_paddr, NULLADDR,
16238032Speter						  &e->e_errorqueue, 0, e);
16364562Sgshapiro				done = TRUE;
16464562Sgshapiro			}
16538032Speter		}
16638032Speter		else if (bitset(QPINGONSUCCESS, q->q_flags) &&
16764562Sgshapiro			 ((QS_IS_SENT(q->q_state) &&
16838032Speter			   bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) ||
16938032Speter			  bitset(QRELAYED|QEXPANDED|QDELIVERED, q->q_flags)))
17038032Speter		{
17138032Speter			success_return = TRUE;
17238032Speter		}
17338032Speter	}
17438032Speter
17538032Speter	if (e->e_class < 0)
17638032Speter		e->e_flags |= EF_NO_BODY_RETN;
17738032Speter
17838032Speter	/*
17938032Speter	**  See if the message timed out.
18038032Speter	*/
18138032Speter
18238032Speter	if (!queueit)
18364562Sgshapiro		/* EMPTY */
18438032Speter		/* nothing to do */ ;
18538032Speter	else if (message_timeout)
18638032Speter	{
18738032Speter		if (failure_return)
18838032Speter		{
18938032Speter			(void) snprintf(buf, sizeof buf,
19064562Sgshapiro					"Cannot send message for %s",
19164562Sgshapiro					pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
19238032Speter			if (e->e_message != NULL)
19338032Speter				free(e->e_message);
19438032Speter			e->e_message = newstr(buf);
19538032Speter			message(buf);
19638032Speter			e->e_flags |= EF_CLRQUEUE;
19738032Speter		}
19838032Speter		fprintf(e->e_xfp, "Message could not be delivered for %s\n",
19938032Speter			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
20038032Speter		fprintf(e->e_xfp, "Message will be deleted from queue\n");
20138032Speter		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
20238032Speter		{
20364562Sgshapiro			if (QS_IS_UNDELIVERED(q->q_state))
20438032Speter			{
20564562Sgshapiro				q->q_state = QS_BADADDR;
20638032Speter				q->q_status = "4.4.7";
20738032Speter			}
20838032Speter		}
20938032Speter	}
21038032Speter	else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
21138032Speter	    curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass])
21238032Speter	{
21338032Speter		if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
21438032Speter		    e->e_class >= 0 &&
21538032Speter		    e->e_from.q_paddr != NULL &&
21638032Speter		    strcmp(e->e_from.q_paddr, "<>") != 0 &&
21738032Speter		    strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
21838032Speter		    (strlen(e->e_from.q_paddr) <= (SIZE_T) 8 ||
21938032Speter		     strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0))
22038032Speter		{
22138032Speter			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
22238032Speter			{
22364562Sgshapiro				if (QS_IS_QUEUEUP(q->q_state) &&
22464562Sgshapiro#if _FFR_NODELAYDSN_ON_HOLD
22564562Sgshapiro				    !bitnset(M_HOLD, q->q_mailer->m_flags) &&
22664562Sgshapiro#endif /* _FFR_NODELAYDSN_ON_HOLD */
22738032Speter				    bitset(QPINGONDELAY, q->q_flags))
22838032Speter				{
22938032Speter					q->q_flags |= QDELAYED;
23038032Speter					delay_return = TRUE;
23138032Speter				}
23238032Speter			}
23338032Speter		}
23438032Speter		if (delay_return)
23538032Speter		{
23638032Speter			(void) snprintf(buf, sizeof buf,
23738032Speter				"Warning: could not send message for past %s",
23838032Speter				pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
23938032Speter			if (e->e_message != NULL)
24038032Speter				free(e->e_message);
24138032Speter			e->e_message = newstr(buf);
24238032Speter			message(buf);
24338032Speter			e->e_flags |= EF_WARNING;
24438032Speter		}
24538032Speter		fprintf(e->e_xfp,
24638032Speter			"Warning: message still undelivered after %s\n",
24738032Speter			pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
24838032Speter		fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
24938032Speter			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
25038032Speter	}
25138032Speter
25238032Speter	if (tTd(50, 2))
25364562Sgshapiro		dprintf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n",
25438032Speter			failure_return, delay_return, success_return, queueit);
25538032Speter
25638032Speter	/*
25738032Speter	**  If we had some fatal error, but no addresses are marked as
25838032Speter	**  bad, mark them _all_ as bad.
25938032Speter	*/
26038032Speter
26138032Speter	if (bitset(EF_FATALERRS, e->e_flags) && !failure_return)
26238032Speter	{
26338032Speter		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
26438032Speter		{
26564562Sgshapiro			if ((QS_IS_OK(q->q_state) ||
26664562Sgshapiro			     QS_IS_VERIFIED(q->q_state)) &&
26738032Speter			    bitset(QPINGONFAILURE, q->q_flags))
26838032Speter			{
26938032Speter				failure_return = TRUE;
27064562Sgshapiro				q->q_state = QS_BADADDR;
27138032Speter			}
27238032Speter		}
27338032Speter	}
27438032Speter
27538032Speter	/*
27638032Speter	**  Send back return receipts as requested.
27738032Speter	*/
27838032Speter
27938032Speter	if (success_return && !failure_return && !delay_return && fulldrop &&
28038032Speter	    !bitset(PRIV_NORECEIPTS, PrivacyFlags) &&
28138032Speter	    strcmp(e->e_from.q_paddr, "<>") != 0)
28238032Speter	{
28338032Speter		auto ADDRESS *rlist = NULL;
28438032Speter
28538032Speter		if (tTd(50, 8))
28664562Sgshapiro			dprintf("dropenvelope(%s): sending return receipt\n",
28764562Sgshapiro				id);
28838032Speter		e->e_flags |= EF_SENDRECEIPT;
28938032Speter		(void) sendtolist(e->e_from.q_paddr, NULLADDR, &rlist, 0, e);
29038032Speter		(void) returntosender("Return receipt", rlist, RTSF_NO_BODY, e);
29138032Speter	}
29238032Speter	e->e_flags &= ~EF_SENDRECEIPT;
29338032Speter
29438032Speter	/*
29538032Speter	**  Arrange to send error messages if there are fatal errors.
29638032Speter	*/
29738032Speter
29838032Speter	if ((failure_return || delay_return) && e->e_errormode != EM_QUIET)
29938032Speter	{
30038032Speter		if (tTd(50, 8))
30164562Sgshapiro			dprintf("dropenvelope(%s): saving mail\n", id);
30238032Speter		savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags));
30338032Speter	}
30438032Speter
30538032Speter	/*
30638032Speter	**  Arrange to send warning messages to postmaster as requested.
30738032Speter	*/
30838032Speter
30964562Sgshapiro	if ((failure_return || pmnotify) &&
31038032Speter	    PostMasterCopy != NULL &&
31164562Sgshapiro	    !bitset(EF_RESPONSE, e->e_flags) &&
31264562Sgshapiro	    e->e_class >= 0)
31338032Speter	{
31438032Speter		auto ADDRESS *rlist = NULL;
31564562Sgshapiro		char pcopy[MAXNAME];
31638032Speter
31764562Sgshapiro		if (failure_return)
31864562Sgshapiro		{
31964562Sgshapiro			expand(PostMasterCopy, pcopy, sizeof pcopy, e);
32064562Sgshapiro
32164562Sgshapiro			if (tTd(50, 8))
32264562Sgshapiro				dprintf("dropenvelope(%s): sending postmaster copy to %s\n",
32364562Sgshapiro					id, pcopy);
32464562Sgshapiro			(void) sendtolist(pcopy, NULLADDR, &rlist, 0, e);
32564562Sgshapiro		}
32664562Sgshapiro		if (pmnotify)
32764562Sgshapiro			(void) sendtolist("postmaster", NULLADDR,
32864562Sgshapiro					  &rlist, 0, e);
32964562Sgshapiro		(void) returntosender(e->e_message, rlist,
33064562Sgshapiro				      RTSF_PM_BOUNCE|RTSF_NO_BODY, e);
33138032Speter	}
33238032Speter
33338032Speter	/*
33438032Speter	**  Instantiate or deinstantiate the queue.
33538032Speter	*/
33638032Speter
33738032Spetersimpledrop:
33838032Speter	if (tTd(50, 8))
33964562Sgshapiro		dprintf("dropenvelope(%s): at simpledrop, queueit=%d\n",
34038032Speter			id, queueit);
34138032Speter	if (!queueit || bitset(EF_CLRQUEUE, e->e_flags))
34238032Speter	{
34338032Speter		if (tTd(50, 1))
34438032Speter		{
34564562Sgshapiro			dprintf("\n===== Dropping [dq]f%s... queueit=%d, e_flags=",
34638032Speter				e->e_id, queueit);
34738032Speter			printenvflags(e);
34838032Speter		}
34938032Speter		xunlink(queuename(e, 'd'));
35038032Speter		xunlink(queuename(e, 'q'));
35138032Speter
35264562Sgshapiro		if (e->e_ntries > 0 && LogLevel > 9)
35364562Sgshapiro			sm_syslog(LOG_INFO, id, "done; delay=%s, ntries=%d",
35464562Sgshapiro				  pintvl(curtime() - e->e_ctime, TRUE),
35564562Sgshapiro				  e->e_ntries);
35638032Speter	}
35738032Speter	else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
35838032Speter	{
35938032Speter#if QUEUE
36038032Speter		queueup(e, FALSE);
36138032Speter#else /* QUEUE */
36264562Sgshapiro		syserr("554 5.3.0 dropenvelope: queueup");
36338032Speter#endif /* QUEUE */
36438032Speter	}
36538032Speter
36638032Speter	/* now unlock the job */
36738032Speter	if (tTd(50, 8))
36864562Sgshapiro		dprintf("dropenvelope(%s): unlocking job\n", id);
36938032Speter	closexscript(e);
37038032Speter	unlockqueue(e);
37138032Speter
37238032Speter	/* make sure that this envelope is marked unused */
37338032Speter	if (e->e_dfp != NULL)
37464562Sgshapiro		(void) bfclose(e->e_dfp);
37538032Speter	e->e_dfp = NULL;
37638032Speter	e->e_id = NULL;
37738032Speter	e->e_flags &= ~EF_HAS_DF;
37838032Speter}
37938032Speter/*
38038032Speter**  CLEARENVELOPE -- clear an envelope without unlocking
38138032Speter**
38238032Speter**	This is normally used by a child process to get a clean
38338032Speter**	envelope without disturbing the parent.
38438032Speter**
38538032Speter**	Parameters:
38638032Speter**		e -- the envelope to clear.
38738032Speter**		fullclear - if set, the current envelope is total
38838032Speter**			garbage and should be ignored; otherwise,
38938032Speter**			release any resources it may indicate.
39038032Speter**
39138032Speter**	Returns:
39238032Speter**		none.
39338032Speter**
39438032Speter**	Side Effects:
39538032Speter**		Closes files associated with the envelope.
39638032Speter**		Marks the envelope as unallocated.
39738032Speter*/
39838032Speter
39938032Spetervoid
40038032Speterclearenvelope(e, fullclear)
40138032Speter	register ENVELOPE *e;
40238032Speter	bool fullclear;
40338032Speter{
40438032Speter	register HDR *bh;
40538032Speter	register HDR **nhp;
40638032Speter	extern ENVELOPE BlankEnvelope;
40738032Speter
40838032Speter	if (!fullclear)
40938032Speter	{
41038032Speter		/* clear out any file information */
41138032Speter		if (e->e_xfp != NULL)
41264562Sgshapiro			(void) bfclose(e->e_xfp);
41338032Speter		if (e->e_dfp != NULL)
41464562Sgshapiro			(void) bfclose(e->e_dfp);
41538032Speter		e->e_xfp = e->e_dfp = NULL;
41638032Speter	}
41738032Speter
41838032Speter	/* now clear out the data */
41938032Speter	STRUCTCOPY(BlankEnvelope, *e);
42038032Speter	e->e_message = NULL;
42138032Speter	if (Verbose)
42264562Sgshapiro		set_delivery_mode(SM_DELIVER, e);
42338032Speter	bh = BlankEnvelope.e_header;
42438032Speter	nhp = &e->e_header;
42538032Speter	while (bh != NULL)
42638032Speter	{
42738032Speter		*nhp = (HDR *) xalloc(sizeof *bh);
42864562Sgshapiro		memmove((char *) *nhp, (char *) bh, sizeof *bh);
42938032Speter		bh = bh->h_link;
43038032Speter		nhp = &(*nhp)->h_link;
43138032Speter	}
43238032Speter}
43338032Speter/*
43438032Speter**  INITSYS -- initialize instantiation of system
43538032Speter**
43638032Speter**	In Daemon mode, this is done in the child.
43738032Speter**
43838032Speter**	Parameters:
43964562Sgshapiro**		e -- the envelope to use.
44038032Speter**
44138032Speter**	Returns:
44238032Speter**		none.
44338032Speter**
44438032Speter**	Side Effects:
44538032Speter**		Initializes the system macros, some global variables,
44638032Speter**		etc.  In particular, the current time in various
44738032Speter**		forms is set.
44838032Speter*/
44938032Speter
45038032Spetervoid
45138032Speterinitsys(e)
45238032Speter	register ENVELOPE *e;
45338032Speter{
45438032Speter	char cbuf[5];				/* holds hop count */
45538032Speter	char pbuf[10];				/* holds pid */
45638032Speter#ifdef TTYNAME
45738032Speter	static char ybuf[60];			/* holds tty id */
45838032Speter	register char *p;
45938032Speter	extern char *ttyname();
46038032Speter#endif /* TTYNAME */
46138032Speter
46238032Speter	/*
46338032Speter	**  Give this envelope a reality.
46438032Speter	**	I.e., an id, a transcript, and a creation time.
46538032Speter	*/
46638032Speter
46764562Sgshapiro	setnewqueue(e);
46838032Speter	openxscript(e);
46938032Speter	e->e_ctime = curtime();
47064562Sgshapiro#if _FFR_QUEUEDELAY
47164562Sgshapiro	e->e_queuealg = QueueAlg;
47264562Sgshapiro	e->e_queuedelay = QueueInitDelay;
47364562Sgshapiro#endif /* _FFR_QUEUEDELAY */
47438032Speter
47538032Speter	/*
47638032Speter	**  Set OutChannel to something useful if stdout isn't it.
47738032Speter	**	This arranges that any extra stuff the mailer produces
47838032Speter	**	gets sent back to the user on error (because it is
47938032Speter	**	tucked away in the transcript).
48038032Speter	*/
48138032Speter
48238032Speter	if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
48338032Speter	    e->e_xfp != NULL)
48438032Speter		OutChannel = e->e_xfp;
48538032Speter
48638032Speter	/*
48738032Speter	**  Set up some basic system macros.
48838032Speter	*/
48938032Speter
49038032Speter	/* process id */
49164562Sgshapiro	(void) snprintf(pbuf, sizeof pbuf, "%d", (int) getpid());
49238032Speter	define('p', newstr(pbuf), e);
49338032Speter
49438032Speter	/* hop count */
49538032Speter	(void) snprintf(cbuf, sizeof cbuf, "%d", e->e_hopcount);
49638032Speter	define('c', newstr(cbuf), e);
49738032Speter
49838032Speter	/* time as integer, unix time, arpa time */
49938032Speter	settime(e);
50038032Speter
50164562Sgshapiro	/* Load average */
50264562Sgshapiro	(void)sm_getla(e);
50364562Sgshapiro
50438032Speter#ifdef TTYNAME
50538032Speter	/* tty name */
50638032Speter	if (macvalue('y', e) == NULL)
50738032Speter	{
50838032Speter		p = ttyname(2);
50938032Speter		if (p != NULL)
51038032Speter		{
51138032Speter			if (strrchr(p, '/') != NULL)
51238032Speter				p = strrchr(p, '/') + 1;
51338032Speter			snprintf(ybuf, sizeof ybuf, "%s", p);
51438032Speter			define('y', ybuf, e);
51538032Speter		}
51638032Speter	}
51738032Speter#endif /* TTYNAME */
51838032Speter}
51938032Speter/*
52038032Speter**  SETTIME -- set the current time.
52138032Speter**
52238032Speter**	Parameters:
52364562Sgshapiro**		e -- the envelope in which the macros should be set.
52438032Speter**
52538032Speter**	Returns:
52638032Speter**		none.
52738032Speter**
52838032Speter**	Side Effects:
52938032Speter**		Sets the various time macros -- $a, $b, $d, $t.
53038032Speter*/
53138032Speter
53238032Spetervoid
53338032Spetersettime(e)
53438032Speter	register ENVELOPE *e;
53538032Speter{
53638032Speter	register char *p;
53738032Speter	auto time_t now;
53838032Speter	char tbuf[20];				/* holds "current" time */
53938032Speter	char dbuf[30];				/* holds ctime(tbuf) */
54038032Speter	register struct tm *tm;
54138032Speter
54238032Speter	now = curtime();
54338032Speter	tm = gmtime(&now);
54438032Speter	(void) snprintf(tbuf, sizeof tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
54564562Sgshapiro			tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
54638032Speter	define('t', newstr(tbuf), e);
54764562Sgshapiro	(void) strlcpy(dbuf, ctime(&now), sizeof dbuf);
54838032Speter	p = strchr(dbuf, '\n');
54938032Speter	if (p != NULL)
55038032Speter		*p = '\0';
55138032Speter	define('d', newstr(dbuf), e);
55238032Speter	p = arpadate(dbuf);
55338032Speter	p = newstr(p);
55438032Speter	if (macvalue('a', e) == NULL)
55538032Speter		define('a', p, e);
55638032Speter	define('b', p, e);
55738032Speter}
55838032Speter/*
55938032Speter**  OPENXSCRIPT -- Open transcript file
56038032Speter**
56138032Speter**	Creates a transcript file for possible eventual mailing or
56238032Speter**	sending back.
56338032Speter**
56438032Speter**	Parameters:
56538032Speter**		e -- the envelope to create the transcript in/for.
56638032Speter**
56738032Speter**	Returns:
56838032Speter**		none
56938032Speter**
57038032Speter**	Side Effects:
57138032Speter**		Creates the transcript file.
57238032Speter*/
57338032Speter
57438032Speter#ifndef O_APPEND
57564562Sgshapiro# define O_APPEND	0
57664562Sgshapiro#endif /* ! O_APPEND */
57738032Speter
57838032Spetervoid
57938032Speteropenxscript(e)
58038032Speter	register ENVELOPE *e;
58138032Speter{
58238032Speter	register char *p;
58338032Speter
58438032Speter	if (e->e_xfp != NULL)
58538032Speter		return;
58664562Sgshapiro
58764562Sgshapiro#if 0
58864562Sgshapiro	if (e->e_lockfp == NULL && bitset(EF_INQUEUE, e->e_flags))
58964562Sgshapiro		syserr("openxscript: job not locked");
59064562Sgshapiro#endif /* 0 */
59164562Sgshapiro
59238032Speter	p = queuename(e, 'x');
59364562Sgshapiro	e->e_xfp = bfopen(p, FileMode, XscriptFileBufferSize,
59464562Sgshapiro			  SFF_NOTEXCL|SFF_OPENASROOT);
59564562Sgshapiro
59664562Sgshapiro	if (e->e_xfp == NULL)
59738032Speter	{
59838032Speter		syserr("Can't create transcript file %s", p);
59964562Sgshapiro		e->e_xfp = fopen("/dev/null", "r+");
60064562Sgshapiro		if (e->e_xfp == NULL)
60138032Speter			syserr("!Can't open /dev/null");
60238032Speter	}
60364562Sgshapiro#if HASSETVBUF
60464562Sgshapiro	(void) setvbuf(e->e_xfp, NULL, _IOLBF, 0);
60564562Sgshapiro#else /* HASSETVBUF */
60664562Sgshapiro	(void) setlinebuf(e->e_xfp);
60764562Sgshapiro#endif /* HASSETVBUF */
60838032Speter	if (tTd(46, 9))
60938032Speter	{
61064562Sgshapiro		dprintf("openxscript(%s):\n  ", p);
61138032Speter		dumpfd(fileno(e->e_xfp), TRUE, FALSE);
61238032Speter	}
61338032Speter}
61438032Speter/*
61538032Speter**  CLOSEXSCRIPT -- close the transcript file.
61638032Speter**
61738032Speter**	Parameters:
61838032Speter**		e -- the envelope containing the transcript to close.
61938032Speter**
62038032Speter**	Returns:
62138032Speter**		none.
62238032Speter**
62338032Speter**	Side Effects:
62438032Speter**		none.
62538032Speter*/
62638032Speter
62738032Spetervoid
62838032Speterclosexscript(e)
62938032Speter	register ENVELOPE *e;
63038032Speter{
63138032Speter	if (e->e_xfp == NULL)
63238032Speter		return;
63364562Sgshapiro#if 0
63464562Sgshapiro	if (e->e_lockfp == NULL)
63564562Sgshapiro		syserr("closexscript: job not locked");
63664562Sgshapiro#endif /* 0 */
63764562Sgshapiro	(void) bfclose(e->e_xfp);
63838032Speter	e->e_xfp = NULL;
63938032Speter}
64038032Speter/*
64138032Speter**  SETSENDER -- set the person who this message is from
64238032Speter**
64338032Speter**	Under certain circumstances allow the user to say who
64438032Speter**	s/he is (using -f or -r).  These are:
64538032Speter**	1.  The user's uid is zero (root).
64638032Speter**	2.  The user's login name is in an approved list (typically
64738032Speter**	    from a network server).
64838032Speter**	3.  The address the user is trying to claim has a
64938032Speter**	    "!" character in it (since #2 doesn't do it for
65038032Speter**	    us if we are dialing out for UUCP).
65138032Speter**	A better check to replace #3 would be if the
65238032Speter**	effective uid is "UUCP" -- this would require me
65338032Speter**	to rewrite getpwent to "grab" uucp as it went by,
65438032Speter**	make getname more nasty, do another passwd file
65538032Speter**	scan, or compile the UID of "UUCP" into the code,
65638032Speter**	all of which are reprehensible.
65738032Speter**
65838032Speter**	Assuming all of these fail, we figure out something
65938032Speter**	ourselves.
66038032Speter**
66138032Speter**	Parameters:
66238032Speter**		from -- the person we would like to believe this message
66338032Speter**			is from, as specified on the command line.
66438032Speter**		e -- the envelope in which we would like the sender set.
66538032Speter**		delimptr -- if non-NULL, set to the location of the
66638032Speter**			trailing delimiter.
66738032Speter**		delimchar -- the character that will delimit the sender
66838032Speter**			address.
66938032Speter**		internal -- set if this address is coming from an internal
67038032Speter**			source such as an owner alias.
67138032Speter**
67238032Speter**	Returns:
67338032Speter**		none.
67438032Speter**
67538032Speter**	Side Effects:
67638032Speter**		sets sendmail's notion of who the from person is.
67738032Speter*/
67838032Speter
67938032Spetervoid
68038032Spetersetsender(from, e, delimptr, delimchar, internal)
68138032Speter	char *from;
68238032Speter	register ENVELOPE *e;
68338032Speter	char **delimptr;
68438032Speter	int delimchar;
68538032Speter	bool internal;
68638032Speter{
68738032Speter	register char **pvp;
68838032Speter	char *realname = NULL;
68938032Speter	register struct passwd *pw;
69038032Speter	char *bp;
69138032Speter	char buf[MAXNAME + 2];
69238032Speter	char pvpbuf[PSBUFSIZE];
69338032Speter	extern char *FullName;
69438032Speter
69538032Speter	if (tTd(45, 1))
69664562Sgshapiro		dprintf("setsender(%s)\n", from == NULL ? "" : from);
69738032Speter
69838032Speter	/*
69938032Speter	**  Figure out the real user executing us.
70038032Speter	**	Username can return errno != 0 on non-errors.
70138032Speter	*/
70238032Speter
70338032Speter	if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP ||
70438032Speter	    OpMode == MD_ARPAFTP || OpMode == MD_DAEMON)
70538032Speter		realname = from;
70638032Speter	if (realname == NULL || realname[0] == '\0')
70738032Speter		realname = username();
70838032Speter
70938032Speter	if (ConfigLevel < 2)
71038032Speter		SuprErrs = TRUE;
71138032Speter
71264562Sgshapiro#if _FFR_ADDR_TYPE
71364562Sgshapiro	define(macid("{addr_type}", NULL), "e s", e);
71464562Sgshapiro#endif /* _FFR_ADDR_TYPE */
71564562Sgshapiro	/* preset state for then clause in case from == NULL */
71664562Sgshapiro	e->e_from.q_state = QS_BADADDR;
71764562Sgshapiro	e->e_from.q_flags = 0;
71838032Speter	if (from == NULL ||
71938032Speter	    parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
72038032Speter		      delimchar, delimptr, e) == NULL ||
72164562Sgshapiro	    QS_IS_BADADDR(e->e_from.q_state) ||
72238032Speter	    e->e_from.q_mailer == ProgMailer ||
72338032Speter	    e->e_from.q_mailer == FileMailer ||
72438032Speter	    e->e_from.q_mailer == InclMailer)
72538032Speter	{
72638032Speter		/* log garbage addresses for traceback */
72738032Speter		if (from != NULL && LogLevel > 2)
72838032Speter		{
72938032Speter			char *p;
73038032Speter			char ebuf[MAXNAME * 2 + 2];
73138032Speter
73238032Speter			p = macvalue('_', e);
73338032Speter			if (p == NULL)
73438032Speter			{
73538032Speter				char *host = RealHostName;
73638032Speter
73738032Speter				if (host == NULL)
73838032Speter					host = MyHostName;
73938032Speter				(void) snprintf(ebuf, sizeof ebuf, "%.*s@%.*s",
74038032Speter					MAXNAME, realname,
74138032Speter					MAXNAME, host);
74238032Speter				p = ebuf;
74338032Speter			}
74438032Speter			sm_syslog(LOG_NOTICE, e->e_id,
74564562Sgshapiro				  "setsender: %s: invalid or unparsable, received from %s",
74664562Sgshapiro				  shortenstring(from, 83), p);
74738032Speter		}
74838032Speter		if (from != NULL)
74938032Speter		{
75064562Sgshapiro			if (!QS_IS_BADADDR(e->e_from.q_state))
75138032Speter			{
75238032Speter				/* it was a bogus mailer in the from addr */
75338032Speter				e->e_status = "5.1.7";
75464562Sgshapiro				usrerrenh(e->e_status,
75564562Sgshapiro					  "553 Invalid sender address");
75638032Speter			}
75738032Speter			SuprErrs = TRUE;
75838032Speter		}
75938032Speter		if (from == realname ||
76038032Speter		    parseaddr(from = newstr(realname), &e->e_from,
76138032Speter			      RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL)
76238032Speter		{
76338032Speter			char nbuf[100];
76438032Speter
76538032Speter			SuprErrs = TRUE;
76638032Speter			expand("\201n", nbuf, sizeof nbuf, e);
76738032Speter			if (parseaddr(from = newstr(nbuf), &e->e_from,
76838032Speter				      RF_COPYALL, ' ', NULL, e) == NULL &&
76938032Speter			    parseaddr(from = "postmaster", &e->e_from,
77064562Sgshapiro				      RF_COPYALL, ' ', NULL, e) == NULL)
77164562Sgshapiro				syserr("553 5.3.0 setsender: can't even parse postmaster!");
77238032Speter		}
77338032Speter	}
77438032Speter	else
77538032Speter		FromFlag = TRUE;
77664562Sgshapiro	e->e_from.q_state = QS_SENDER;
77738032Speter	if (tTd(45, 5))
77838032Speter	{
77964562Sgshapiro		dprintf("setsender: QS_SENDER ");
78038032Speter		printaddr(&e->e_from, FALSE);
78138032Speter	}
78238032Speter	SuprErrs = FALSE;
78338032Speter
78464562Sgshapiro#if USERDB
78538032Speter	if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags))
78638032Speter	{
78738032Speter		register char *p;
78838032Speter
78938032Speter		p = udbsender(e->e_from.q_user);
79038032Speter		if (p != NULL)
79138032Speter			from = p;
79238032Speter	}
79364562Sgshapiro#endif /* USERDB */
79438032Speter
79538032Speter	if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
79638032Speter	{
79738032Speter		if (!internal)
79838032Speter		{
79938032Speter			/* if the user already given fullname don't redefine */
80038032Speter			if (FullName == NULL)
80138032Speter				FullName = macvalue('x', e);
80238032Speter			if (FullName != NULL && FullName[0] == '\0')
80338032Speter				FullName = NULL;
80438032Speter		}
80538032Speter
80638032Speter		if (e->e_from.q_user[0] != '\0' &&
80738032Speter		    (pw = sm_getpwnam(e->e_from.q_user)) != NULL)
80838032Speter		{
80938032Speter			/*
81038032Speter			**  Process passwd file entry.
81138032Speter			*/
81238032Speter
81338032Speter			/* extract home directory */
81438032Speter			if (strcmp(pw->pw_dir, "/") == 0)
81538032Speter				e->e_from.q_home = newstr("");
81638032Speter			else
81738032Speter				e->e_from.q_home = newstr(pw->pw_dir);
81838032Speter			define('z', e->e_from.q_home, e);
81938032Speter
82038032Speter			/* extract user and group id */
82138032Speter			e->e_from.q_uid = pw->pw_uid;
82238032Speter			e->e_from.q_gid = pw->pw_gid;
82338032Speter			e->e_from.q_flags |= QGOODUID;
82438032Speter
82538032Speter			/* extract full name from passwd file */
82638032Speter			if (FullName == NULL && pw->pw_gecos != NULL &&
82738032Speter			    strcmp(pw->pw_name, e->e_from.q_user) == 0 &&
82838032Speter			    !internal)
82938032Speter			{
83038032Speter				buildfname(pw->pw_gecos, e->e_from.q_user, buf, sizeof buf);
83138032Speter				if (buf[0] != '\0')
83238032Speter					FullName = newstr(buf);
83338032Speter			}
83438032Speter		}
83538032Speter		else
83638032Speter		{
83764562Sgshapiro			e->e_from.q_home = NULL;
83838032Speter		}
83938032Speter		if (FullName != NULL && !internal)
84038032Speter			define('x', FullName, e);
84138032Speter	}
84243730Speter	else if (!internal && OpMode != MD_DAEMON && OpMode != MD_SMTP)
84338032Speter	{
84438032Speter		if (e->e_from.q_home == NULL)
84538032Speter		{
84638032Speter			e->e_from.q_home = getenv("HOME");
84738032Speter			if (e->e_from.q_home != NULL &&
84838032Speter			    strcmp(e->e_from.q_home, "/") == 0)
84938032Speter				e->e_from.q_home++;
85038032Speter		}
85138032Speter		e->e_from.q_uid = RealUid;
85238032Speter		e->e_from.q_gid = RealGid;
85338032Speter		e->e_from.q_flags |= QGOODUID;
85438032Speter	}
85538032Speter
85638032Speter	/*
85738032Speter	**  Rewrite the from person to dispose of possible implicit
85838032Speter	**	links in the net.
85938032Speter	*/
86038032Speter
86138032Speter	pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL, NULL);
86238032Speter	if (pvp == NULL)
86338032Speter	{
86438032Speter		/* don't need to give error -- prescan did that already */
86538032Speter		if (LogLevel > 2)
86638032Speter			sm_syslog(LOG_NOTICE, e->e_id,
86764562Sgshapiro				  "cannot prescan from (%s)",
86864562Sgshapiro				  shortenstring(from, MAXSHORTSTR));
86942575Speter		finis(TRUE, ExitStat);
87038032Speter	}
87138032Speter	(void) rewrite(pvp, 3, 0, e);
87238032Speter	(void) rewrite(pvp, 1, 0, e);
87338032Speter	(void) rewrite(pvp, 4, 0, e);
87464562Sgshapiro#if _FFR_ADDR_TYPE
87564562Sgshapiro	define(macid("{addr_type}", NULL), NULL, e);
87664562Sgshapiro#endif /* _FFR_ADDR_TYPE */
87738032Speter	bp = buf + 1;
87838032Speter	cataddr(pvp, NULL, bp, sizeof buf - 2, '\0');
87938032Speter	if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags))
88038032Speter	{
88138032Speter		/* heuristic: route-addr: add angle brackets */
88264562Sgshapiro		(void) strlcat(bp, ">", sizeof buf - 1);
88338032Speter		*--bp = '<';
88438032Speter	}
88538032Speter	e->e_sender = newstr(bp);
88638032Speter	define('f', e->e_sender, e);
88738032Speter
88838032Speter	/* save the domain spec if this mailer wants it */
88938032Speter	if (e->e_from.q_mailer != NULL &&
89038032Speter	    bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags))
89138032Speter	{
89238032Speter		char **lastat;
89338032Speter
89438032Speter		/* get rid of any pesky angle brackets */
89564562Sgshapiro#if _FFR_ADDR_TYPE
89664562Sgshapiro		define(macid("{addr_type}", NULL), "e s", e);
89764562Sgshapiro#endif /* _FFR_ADDR_TYPE */
89838032Speter		(void) rewrite(pvp, 3, 0, e);
89938032Speter		(void) rewrite(pvp, 1, 0, e);
90038032Speter		(void) rewrite(pvp, 4, 0, e);
90164562Sgshapiro#if _FFR_ADDR_TYPE
90264562Sgshapiro		define(macid("{addr_type}", NULL), NULL, e);
90364562Sgshapiro#endif /* _FFR_ADDR_TYPE */
90438032Speter
90538032Speter		/* strip off to the last "@" sign */
90638032Speter		for (lastat = NULL; *pvp != NULL; pvp++)
90738032Speter			if (strcmp(*pvp, "@") == 0)
90838032Speter				lastat = pvp;
90938032Speter		if (lastat != NULL)
91038032Speter		{
91138032Speter			e->e_fromdomain = copyplist(lastat, TRUE);
91238032Speter			if (tTd(45, 3))
91338032Speter			{
91464562Sgshapiro				dprintf("Saving from domain: ");
91538032Speter				printav(e->e_fromdomain);
91638032Speter			}
91738032Speter		}
91838032Speter	}
91938032Speter}
92038032Speter/*
92138032Speter**  PRINTENVFLAGS -- print envelope flags for debugging
92238032Speter**
92338032Speter**	Parameters:
92438032Speter**		e -- the envelope with the flags to be printed.
92538032Speter**
92638032Speter**	Returns:
92738032Speter**		none.
92838032Speter*/
92938032Speter
93038032Speterstruct eflags
93138032Speter{
93238032Speter	char	*ef_name;
93338032Speter	u_long	ef_bit;
93438032Speter};
93538032Speter
93664562Sgshapirostatic struct eflags	EnvelopeFlags[] =
93738032Speter{
93838032Speter	{ "OLDSTYLE",		EF_OLDSTYLE	},
93938032Speter	{ "INQUEUE",		EF_INQUEUE	},
94038032Speter	{ "NO_BODY_RETN",	EF_NO_BODY_RETN	},
94138032Speter	{ "CLRQUEUE",		EF_CLRQUEUE	},
94238032Speter	{ "SENDRECEIPT",	EF_SENDRECEIPT	},
94338032Speter	{ "FATALERRS",		EF_FATALERRS	},
94438032Speter	{ "DELETE_BCC",		EF_DELETE_BCC	},
94538032Speter	{ "RESPONSE",		EF_RESPONSE	},
94638032Speter	{ "RESENT",		EF_RESENT	},
94738032Speter	{ "VRFYONLY",		EF_VRFYONLY	},
94838032Speter	{ "WARNING",		EF_WARNING	},
94938032Speter	{ "QUEUERUN",		EF_QUEUERUN	},
95038032Speter	{ "GLOBALERRS",		EF_GLOBALERRS	},
95138032Speter	{ "PM_NOTIFY",		EF_PM_NOTIFY	},
95238032Speter	{ "METOO",		EF_METOO	},
95338032Speter	{ "LOGSENDER",		EF_LOGSENDER	},
95438032Speter	{ "NORECEIPT",		EF_NORECEIPT	},
95538032Speter	{ "HAS8BIT",		EF_HAS8BIT	},
95638032Speter	{ "NL_NOT_EOL",		EF_NL_NOT_EOL	},
95738032Speter	{ "CRLF_NOT_EOL",	EF_CRLF_NOT_EOL	},
95838032Speter	{ "RET_PARAM",		EF_RET_PARAM	},
95938032Speter	{ "HAS_DF",		EF_HAS_DF	},
96038032Speter	{ "IS_MIME",		EF_IS_MIME	},
96138032Speter	{ "DONT_MIME",		EF_DONT_MIME	},
96238032Speter	{ NULL }
96338032Speter};
96438032Speter
96538032Spetervoid
96638032Speterprintenvflags(e)
96738032Speter	register ENVELOPE *e;
96838032Speter{
96938032Speter	register struct eflags *ef;
97038032Speter	bool first = TRUE;
97138032Speter
97238032Speter	printf("%lx", e->e_flags);
97338032Speter	for (ef = EnvelopeFlags; ef->ef_name != NULL; ef++)
97438032Speter	{
97538032Speter		if (!bitset(ef->ef_bit, e->e_flags))
97638032Speter			continue;
97738032Speter		if (first)
97838032Speter			printf("<%s", ef->ef_name);
97938032Speter		else
98038032Speter			printf(",%s", ef->ef_name);
98138032Speter		first = FALSE;
98238032Speter	}
98338032Speter	if (!first)
98438032Speter		printf(">\n");
98538032Speter}
986