xref: /freebsd/contrib/sendmail/src/recipient.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
1c2aa98e2SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2003, 2006 Proofpoint, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
1506f25ae9SGregory Neil Shapiro 
164313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: recipient.c,v 8.351 2013-11-22 20:51:56 ca Exp $")
1706f25ae9SGregory Neil Shapiro 
182fb4f839SGregory Neil Shapiro #include <sm/sendmail.h>
192fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
202fb4f839SGregory Neil Shapiro # include <sm/ixlen.h>
212fb4f839SGregory Neil Shapiro #endif
222fb4f839SGregory Neil Shapiro 
23b6bacd31SGregory Neil Shapiro static void	includetimeout __P((int));
2406f25ae9SGregory Neil Shapiro static ADDRESS	*self_reference __P((ADDRESS *));
2540266059SGregory Neil Shapiro static int	sortexpensive __P((ADDRESS *, ADDRESS *));
2640266059SGregory Neil Shapiro static int	sortbysignature __P((ADDRESS *, ADDRESS *));
2740266059SGregory Neil Shapiro static int	sorthost __P((ADDRESS *, ADDRESS *));
2840266059SGregory Neil Shapiro 
2940266059SGregory Neil Shapiro typedef int	sortfn_t __P((ADDRESS *, ADDRESS *));
3040266059SGregory Neil Shapiro 
3140266059SGregory Neil Shapiro /*
3240266059SGregory Neil Shapiro **  SORTHOST -- strcmp()-like func for host portion of an ADDRESS
3340266059SGregory Neil Shapiro **
3440266059SGregory Neil Shapiro **	Parameters:
3540266059SGregory Neil Shapiro **		xx -- first ADDRESS
3640266059SGregory Neil Shapiro **		yy -- second ADDRESS
3740266059SGregory Neil Shapiro **
3840266059SGregory Neil Shapiro **	Returns:
3940266059SGregory Neil Shapiro **		<0 when xx->q_host is less than yy->q_host
4040266059SGregory Neil Shapiro **		>0 when xx->q_host is greater than yy->q_host
4140266059SGregory Neil Shapiro **		0 when equal
4240266059SGregory Neil Shapiro */
4340266059SGregory Neil Shapiro 
4440266059SGregory Neil Shapiro static int
sorthost(xx,yy)4540266059SGregory Neil Shapiro sorthost(xx, yy)
4640266059SGregory Neil Shapiro 	register ADDRESS *xx;
4740266059SGregory Neil Shapiro 	register ADDRESS *yy;
4840266059SGregory Neil Shapiro {
4940266059SGregory Neil Shapiro #if _FFR_HOST_SORT_REVERSE
5040266059SGregory Neil Shapiro 	/* XXX maybe compare hostnames from the end? */
5140266059SGregory Neil Shapiro 	return sm_strrevcasecmp(xx->q_host, yy->q_host);
525b0945b5SGregory Neil Shapiro #else
5340266059SGregory Neil Shapiro 	return sm_strcasecmp(xx->q_host, yy->q_host);
545b0945b5SGregory Neil Shapiro #endif
5540266059SGregory Neil Shapiro }
5640266059SGregory Neil Shapiro 
5740266059SGregory Neil Shapiro /*
5840266059SGregory Neil Shapiro **  SORTEXPENSIVE -- strcmp()-like func for expensive mailers
5940266059SGregory Neil Shapiro **
6040266059SGregory Neil Shapiro **  The mailer has been noted already as "expensive" for 'xx'. This
6140266059SGregory Neil Shapiro **  will give a result relative to 'yy'. Expensive mailers get rated
6240266059SGregory Neil Shapiro **  "greater than" non-expensive mailers because during the delivery phase
6340266059SGregory Neil Shapiro **  it will get queued -- no use it getting in the way of less expensive
6440266059SGregory Neil Shapiro **  recipients. We avoid an MX RR lookup when both 'xx' and 'yy' are
6540266059SGregory Neil Shapiro **  expensive since an MX RR lookup happens when extracted from the queue
6640266059SGregory Neil Shapiro **  later.
6740266059SGregory Neil Shapiro **
6840266059SGregory Neil Shapiro **	Parameters:
6940266059SGregory Neil Shapiro **		xx -- first ADDRESS
7040266059SGregory Neil Shapiro **		yy -- second ADDRESS
7140266059SGregory Neil Shapiro **
7240266059SGregory Neil Shapiro **	Returns:
7340266059SGregory Neil Shapiro **		<0 when xx->q_host is less than yy->q_host and both are
7440266059SGregory Neil Shapiro **			expensive
7540266059SGregory Neil Shapiro **		>0 when xx->q_host is greater than yy->q_host, or when
7640266059SGregory Neil Shapiro **			'yy' is non-expensive
7740266059SGregory Neil Shapiro **		0 when equal (by expense and q_host)
7840266059SGregory Neil Shapiro */
7940266059SGregory Neil Shapiro 
8040266059SGregory Neil Shapiro static int
sortexpensive(xx,yy)8140266059SGregory Neil Shapiro sortexpensive(xx, yy)
8240266059SGregory Neil Shapiro 	ADDRESS *xx;
8340266059SGregory Neil Shapiro 	ADDRESS *yy;
8440266059SGregory Neil Shapiro {
8540266059SGregory Neil Shapiro 	if (!bitnset(M_EXPENSIVE, yy->q_mailer->m_flags))
8640266059SGregory Neil Shapiro 		return 1; /* xx should go later */
8740266059SGregory Neil Shapiro #if _FFR_HOST_SORT_REVERSE
8840266059SGregory Neil Shapiro 	/* XXX maybe compare hostnames from the end? */
8940266059SGregory Neil Shapiro 	return sm_strrevcasecmp(xx->q_host, yy->q_host);
905b0945b5SGregory Neil Shapiro #else
9140266059SGregory Neil Shapiro 	return sm_strcasecmp(xx->q_host, yy->q_host);
925b0945b5SGregory Neil Shapiro #endif
9340266059SGregory Neil Shapiro }
9440266059SGregory Neil Shapiro 
9540266059SGregory Neil Shapiro /*
9640266059SGregory Neil Shapiro **  SORTBYSIGNATURE -- a strcmp()-like func for q_mailer and q_host in ADDRESS
9740266059SGregory Neil Shapiro **
9840266059SGregory Neil Shapiro **	Parameters:
9940266059SGregory Neil Shapiro **		xx -- first ADDRESS
10040266059SGregory Neil Shapiro **		yy -- second ADDRESS
10140266059SGregory Neil Shapiro **
10240266059SGregory Neil Shapiro **	Returns:
10340266059SGregory Neil Shapiro **		0 when the "signature"'s are same
10440266059SGregory Neil Shapiro **		<0 when xx->q_signature is less than yy->q_signature
10540266059SGregory Neil Shapiro **		>0 when xx->q_signature is greater than yy->q_signature
10640266059SGregory Neil Shapiro **
10740266059SGregory Neil Shapiro **	Side Effect:
10840266059SGregory Neil Shapiro **		May set ADDRESS pointer for q_signature if not already set.
10940266059SGregory Neil Shapiro */
11040266059SGregory Neil Shapiro 
11140266059SGregory Neil Shapiro static int
sortbysignature(xx,yy)11240266059SGregory Neil Shapiro sortbysignature(xx, yy)
11340266059SGregory Neil Shapiro 	ADDRESS *xx;
11440266059SGregory Neil Shapiro 	ADDRESS *yy;
11540266059SGregory Neil Shapiro {
11640266059SGregory Neil Shapiro 	register int ret;
11740266059SGregory Neil Shapiro 
11840266059SGregory Neil Shapiro 	/* Let's avoid redoing the signature over and over again */
11940266059SGregory Neil Shapiro 	if (xx->q_signature == NULL)
120*d39bd2c1SGregory Neil Shapiro 		xx->q_signature = hostsignature(xx->q_mailer, xx->q_host,
121*d39bd2c1SGregory Neil Shapiro 					QISSECURE(xx), NULL);
12240266059SGregory Neil Shapiro 	if (yy->q_signature == NULL)
123*d39bd2c1SGregory Neil Shapiro 		yy->q_signature = hostsignature(yy->q_mailer, yy->q_host,
124*d39bd2c1SGregory Neil Shapiro 					QISSECURE(yy), NULL);
12540266059SGregory Neil Shapiro 	ret = strcmp(xx->q_signature, yy->q_signature);
12640266059SGregory Neil Shapiro 
12740266059SGregory Neil Shapiro 	/*
12840266059SGregory Neil Shapiro 	**  If the two signatures are the same then we will return a sort
12940266059SGregory Neil Shapiro 	**  value based on 'q_user'. But note that we have reversed xx and yy
13040266059SGregory Neil Shapiro 	**  on purpose. This additional compare helps reduce the number of
13140266059SGregory Neil Shapiro 	**  sameaddr() calls and loops in recipient() for the case when
13240266059SGregory Neil Shapiro 	**  the rcpt list has been provided already in-order.
13340266059SGregory Neil Shapiro 	*/
13440266059SGregory Neil Shapiro 
13540266059SGregory Neil Shapiro 	if (ret == 0)
13640266059SGregory Neil Shapiro 		return strcmp(yy->q_user, xx->q_user);
13740266059SGregory Neil Shapiro 	else
13840266059SGregory Neil Shapiro 		return ret;
13940266059SGregory Neil Shapiro }
140c2aa98e2SPeter Wemm 
141c2aa98e2SPeter Wemm /*
142c2aa98e2SPeter Wemm **  SENDTOLIST -- Designate a send list.
143c2aa98e2SPeter Wemm **
144c2aa98e2SPeter Wemm **	The parameter is a comma-separated list of people to send to.
145c2aa98e2SPeter Wemm **	This routine arranges to send to all of them.
146c2aa98e2SPeter Wemm **
147c2aa98e2SPeter Wemm **	Parameters:
148c2aa98e2SPeter Wemm **		list -- the send list.
149c2aa98e2SPeter Wemm **		ctladdr -- the address template for the person to
150c2aa98e2SPeter Wemm **			send to -- effective uid/gid are important.
151c2aa98e2SPeter Wemm **			This is typically the alias that caused this
152c2aa98e2SPeter Wemm **			expansion.
153c2aa98e2SPeter Wemm **		sendq -- a pointer to the head of a queue to put
154c2aa98e2SPeter Wemm **			these people into.
155c2aa98e2SPeter Wemm **		aliaslevel -- the current alias nesting depth -- to
156c2aa98e2SPeter Wemm **			diagnose loops.
157c2aa98e2SPeter Wemm **		e -- the envelope in which to add these recipients.
158c2aa98e2SPeter Wemm **
159c2aa98e2SPeter Wemm **	Returns:
160c2aa98e2SPeter Wemm **		The number of addresses actually on the list.
161c2aa98e2SPeter Wemm */
162c2aa98e2SPeter Wemm 
163c2aa98e2SPeter Wemm /* q_flags bits inherited from ctladdr */
164c2aa98e2SPeter Wemm #define QINHERITEDBITS	(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY)
165c2aa98e2SPeter Wemm 
166c2aa98e2SPeter Wemm int
sendtolist(list,ctladdr,sendq,aliaslevel,e)167c2aa98e2SPeter Wemm sendtolist(list, ctladdr, sendq, aliaslevel, e)
168c2aa98e2SPeter Wemm 	char *list;
169c2aa98e2SPeter Wemm 	ADDRESS *ctladdr;
170c2aa98e2SPeter Wemm 	ADDRESS **sendq;
171c2aa98e2SPeter Wemm 	int aliaslevel;
172c2aa98e2SPeter Wemm 	register ENVELOPE *e;
173c2aa98e2SPeter Wemm {
174c2aa98e2SPeter Wemm 	register char *p;
17540266059SGregory Neil Shapiro 	register ADDRESS *SM_NONVOLATILE al; /* list of addresses to send to */
17640266059SGregory Neil Shapiro 	SM_NONVOLATILE char delimiter;		/* the address delimiter */
17740266059SGregory Neil Shapiro 	SM_NONVOLATILE int naddrs;
17840266059SGregory Neil Shapiro 	SM_NONVOLATILE int i;
179a7ec597cSGregory Neil Shapiro 	char *endp;
180c2aa98e2SPeter Wemm 	char *oldto = e->e_to;
18140266059SGregory Neil Shapiro 	char *SM_NONVOLATILE bufp;
1822fb4f839SGregory Neil Shapiro 	char buf[MAXNAME + 1];	/* EAI: ok, uses bufp dynamically expanded */
183c2aa98e2SPeter Wemm 
184c2aa98e2SPeter Wemm 	if (list == NULL)
185c2aa98e2SPeter Wemm 	{
186c2aa98e2SPeter Wemm 		syserr("sendtolist: null list");
187c2aa98e2SPeter Wemm 		return 0;
188c2aa98e2SPeter Wemm 	}
189c2aa98e2SPeter Wemm 
190c2aa98e2SPeter Wemm 	if (tTd(25, 1))
191c2aa98e2SPeter Wemm 	{
19240266059SGregory Neil Shapiro 		sm_dprintf("sendto: %s\n   ctladdr=", list);
193e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), ctladdr, false);
194c2aa98e2SPeter Wemm 	}
195c2aa98e2SPeter Wemm 
196c2aa98e2SPeter Wemm 	/* heuristic to determine old versus new style addresses */
197c2aa98e2SPeter Wemm 	if (ctladdr == NULL &&
198c2aa98e2SPeter Wemm 	    (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
199c2aa98e2SPeter Wemm 	     strchr(list, '<') != NULL || strchr(list, '(') != NULL))
200c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_OLDSTYLE;
201c2aa98e2SPeter Wemm 	delimiter = ' ';
202c2aa98e2SPeter Wemm 	if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL)
203c2aa98e2SPeter Wemm 		delimiter = ',';
204c2aa98e2SPeter Wemm 
205c2aa98e2SPeter Wemm 	al = NULL;
206c2aa98e2SPeter Wemm 	naddrs = 0;
207c2aa98e2SPeter Wemm 
208c2aa98e2SPeter Wemm 	/* make sure we have enough space to copy the string */
209c2aa98e2SPeter Wemm 	i = strlen(list) + 1;
210d0cef73dSGregory Neil Shapiro 	if (i <= sizeof(buf))
21106f25ae9SGregory Neil Shapiro 	{
212c2aa98e2SPeter Wemm 		bufp = buf;
213d0cef73dSGregory Neil Shapiro 		i = sizeof(buf);
21406f25ae9SGregory Neil Shapiro 	}
215c2aa98e2SPeter Wemm 	else
21640266059SGregory Neil Shapiro 		bufp = sm_malloc_x(i);
217a7ec597cSGregory Neil Shapiro 	endp = bufp + i;
218c2aa98e2SPeter Wemm 
21940266059SGregory Neil Shapiro 	SM_TRY
22040266059SGregory Neil Shapiro 	{
22140266059SGregory Neil Shapiro 		(void) sm_strlcpy(bufp, denlstring(list, false, true), i);
22240266059SGregory Neil Shapiro 
22340266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
224c2aa98e2SPeter Wemm 		for (p = bufp; *p != '\0'; )
225c2aa98e2SPeter Wemm 		{
226c2aa98e2SPeter Wemm 			auto char *delimptr;
227c2aa98e2SPeter Wemm 			register ADDRESS *a;
228c2aa98e2SPeter Wemm 
229a7ec597cSGregory Neil Shapiro 			SM_ASSERT(p < endp);
230a7ec597cSGregory Neil Shapiro 
231c2aa98e2SPeter Wemm 			/* parse the address */
2325b0945b5SGregory Neil Shapiro 			while ((SM_ISSPACE(*p)) || *p == ',')
233c2aa98e2SPeter Wemm 				p++;
234a7ec597cSGregory Neil Shapiro 			SM_ASSERT(p < endp);
2352fb4f839SGregory Neil Shapiro /* XXX p must be [i] */
23640266059SGregory Neil Shapiro 			a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter,
23740266059SGregory Neil Shapiro 				      &delimptr, e, true);
238c2aa98e2SPeter Wemm 			p = delimptr;
239a7ec597cSGregory Neil Shapiro 			SM_ASSERT(p < endp);
240c2aa98e2SPeter Wemm 			if (a == NULL)
241c2aa98e2SPeter Wemm 				continue;
242c2aa98e2SPeter Wemm 			a->q_next = al;
243c2aa98e2SPeter Wemm 			a->q_alias = ctladdr;
244c2aa98e2SPeter Wemm 
245c2aa98e2SPeter Wemm 			/* arrange to inherit attributes from parent */
246c2aa98e2SPeter Wemm 			if (ctladdr != NULL)
247c2aa98e2SPeter Wemm 			{
248c2aa98e2SPeter Wemm 				ADDRESS *b;
249c2aa98e2SPeter Wemm 
250c2aa98e2SPeter Wemm 				/* self reference test */
251c2aa98e2SPeter Wemm 				if (sameaddr(ctladdr, a))
252c2aa98e2SPeter Wemm 				{
253c2aa98e2SPeter Wemm 					if (tTd(27, 5))
254c2aa98e2SPeter Wemm 					{
25540266059SGregory Neil Shapiro 						sm_dprintf("sendtolist: QSELFREF ");
256e92d3f3fSGregory Neil Shapiro 						printaddr(sm_debug_file(), ctladdr, false);
257c2aa98e2SPeter Wemm 					}
258c2aa98e2SPeter Wemm 					ctladdr->q_flags |= QSELFREF;
259c2aa98e2SPeter Wemm 				}
260c2aa98e2SPeter Wemm 
261c2aa98e2SPeter Wemm 				/* check for address loops */
26206f25ae9SGregory Neil Shapiro 				b = self_reference(a);
263c2aa98e2SPeter Wemm 				if (b != NULL)
264c2aa98e2SPeter Wemm 				{
265c2aa98e2SPeter Wemm 					b->q_flags |= QSELFREF;
266c2aa98e2SPeter Wemm 					if (tTd(27, 5))
267c2aa98e2SPeter Wemm 					{
26840266059SGregory Neil Shapiro 						sm_dprintf("sendtolist: QSELFREF ");
269e92d3f3fSGregory Neil Shapiro 						printaddr(sm_debug_file(), b, false);
270c2aa98e2SPeter Wemm 					}
271c2aa98e2SPeter Wemm 					if (a != b)
272c2aa98e2SPeter Wemm 					{
273c2aa98e2SPeter Wemm 						if (tTd(27, 5))
274c2aa98e2SPeter Wemm 						{
27540266059SGregory Neil Shapiro 							sm_dprintf("sendtolist: QS_DONTSEND ");
276e92d3f3fSGregory Neil Shapiro 							printaddr(sm_debug_file(), a, false);
277c2aa98e2SPeter Wemm 						}
27806f25ae9SGregory Neil Shapiro 						a->q_state = QS_DONTSEND;
279c2aa98e2SPeter Wemm 						b->q_flags |= a->q_flags & QNOTREMOTE;
280c2aa98e2SPeter Wemm 						continue;
281c2aa98e2SPeter Wemm 					}
282c2aa98e2SPeter Wemm 				}
283c2aa98e2SPeter Wemm 
284c2aa98e2SPeter Wemm 				/* full name */
285c2aa98e2SPeter Wemm 				if (a->q_fullname == NULL)
286c2aa98e2SPeter Wemm 					a->q_fullname = ctladdr->q_fullname;
287c2aa98e2SPeter Wemm 
288c2aa98e2SPeter Wemm 				/* various flag bits */
289c2aa98e2SPeter Wemm 				a->q_flags &= ~QINHERITEDBITS;
290c2aa98e2SPeter Wemm 				a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
291c2aa98e2SPeter Wemm 
29240266059SGregory Neil Shapiro 				/* DSN recipient information */
29340266059SGregory Neil Shapiro 				a->q_finalrcpt = ctladdr->q_finalrcpt;
294c2aa98e2SPeter Wemm 				a->q_orcpt = ctladdr->q_orcpt;
295c2aa98e2SPeter Wemm 			}
296c2aa98e2SPeter Wemm 
297c2aa98e2SPeter Wemm 			al = a;
298c2aa98e2SPeter Wemm 		}
299c2aa98e2SPeter Wemm 
300c2aa98e2SPeter Wemm 		/* arrange to send to everyone on the local send list */
301c2aa98e2SPeter Wemm 		while (al != NULL)
302c2aa98e2SPeter Wemm 		{
303c2aa98e2SPeter Wemm 			register ADDRESS *a = al;
304c2aa98e2SPeter Wemm 
305c2aa98e2SPeter Wemm 			al = a->q_next;
306c2aa98e2SPeter Wemm 			a = recipient(a, sendq, aliaslevel, e);
307c2aa98e2SPeter Wemm 			naddrs++;
308c2aa98e2SPeter Wemm 		}
30940266059SGregory Neil Shapiro 	}
31040266059SGregory Neil Shapiro 	SM_FINALLY
31140266059SGregory Neil Shapiro 	{
312c2aa98e2SPeter Wemm 		e->e_to = oldto;
313c2aa98e2SPeter Wemm 		if (bufp != buf)
3148774250cSGregory Neil Shapiro 			sm_free(bufp);
31540266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
31640266059SGregory Neil Shapiro 	}
31740266059SGregory Neil Shapiro 	SM_END_TRY
31806f25ae9SGregory Neil Shapiro 	return naddrs;
31906f25ae9SGregory Neil Shapiro }
320d0cef73dSGregory Neil Shapiro 
32140266059SGregory Neil Shapiro #if MILTER
32240266059SGregory Neil Shapiro /*
32306f25ae9SGregory Neil Shapiro **  REMOVEFROMLIST -- Remove addresses from a send list.
32406f25ae9SGregory Neil Shapiro **
32506f25ae9SGregory Neil Shapiro **	The parameter is a comma-separated list of recipients to remove.
32606f25ae9SGregory Neil Shapiro **	Note that it only deletes matching addresses.  If those addresses
32740266059SGregory Neil Shapiro **	have been expanded already in the sendq, it won't mark the
32806f25ae9SGregory Neil Shapiro **	expanded recipients as QS_REMOVED.
32906f25ae9SGregory Neil Shapiro **
33006f25ae9SGregory Neil Shapiro **	Parameters:
33106f25ae9SGregory Neil Shapiro **		list -- the list to remove.
33206f25ae9SGregory Neil Shapiro **		sendq -- a pointer to the head of a queue to remove
33306f25ae9SGregory Neil Shapiro **			these addresses from.
33406f25ae9SGregory Neil Shapiro **		e -- the envelope in which to remove these recipients.
33506f25ae9SGregory Neil Shapiro **
33606f25ae9SGregory Neil Shapiro **	Returns:
33706f25ae9SGregory Neil Shapiro **		The number of addresses removed from the list.
33806f25ae9SGregory Neil Shapiro **
33906f25ae9SGregory Neil Shapiro */
34006f25ae9SGregory Neil Shapiro 
34106f25ae9SGregory Neil Shapiro int
removefromlist(list,sendq,e)34206f25ae9SGregory Neil Shapiro removefromlist(list, sendq, e)
34306f25ae9SGregory Neil Shapiro 	char *list;
34406f25ae9SGregory Neil Shapiro 	ADDRESS **sendq;
34506f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
34606f25ae9SGregory Neil Shapiro {
34740266059SGregory Neil Shapiro 	SM_NONVOLATILE char delimiter;		/* the address delimiter */
34840266059SGregory Neil Shapiro 	SM_NONVOLATILE int naddrs;
34940266059SGregory Neil Shapiro 	SM_NONVOLATILE int i;
35006f25ae9SGregory Neil Shapiro 	char *p;
35106f25ae9SGregory Neil Shapiro 	char *oldto = e->e_to;
35240266059SGregory Neil Shapiro 	char *SM_NONVOLATILE bufp;
3532fb4f839SGregory Neil Shapiro 	char buf[MAXNAME + 1];	/* EAI: ok, uses bufp dynamically expanded */
35406f25ae9SGregory Neil Shapiro 
35506f25ae9SGregory Neil Shapiro 	if (list == NULL)
35606f25ae9SGregory Neil Shapiro 	{
35706f25ae9SGregory Neil Shapiro 		syserr("removefromlist: null list");
35806f25ae9SGregory Neil Shapiro 		return 0;
35906f25ae9SGregory Neil Shapiro 	}
36006f25ae9SGregory Neil Shapiro 
36106f25ae9SGregory Neil Shapiro 	if (tTd(25, 1))
36240266059SGregory Neil Shapiro 		sm_dprintf("removefromlist: %s\n", list);
36306f25ae9SGregory Neil Shapiro 
36406f25ae9SGregory Neil Shapiro 	/* heuristic to determine old versus new style addresses */
36506f25ae9SGregory Neil Shapiro 	if (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
36606f25ae9SGregory Neil Shapiro 	    strchr(list, '<') != NULL || strchr(list, '(') != NULL)
36706f25ae9SGregory Neil Shapiro 		e->e_flags &= ~EF_OLDSTYLE;
36806f25ae9SGregory Neil Shapiro 	delimiter = ' ';
36906f25ae9SGregory Neil Shapiro 	if (!bitset(EF_OLDSTYLE, e->e_flags))
37006f25ae9SGregory Neil Shapiro 		delimiter = ',';
37106f25ae9SGregory Neil Shapiro 
37206f25ae9SGregory Neil Shapiro 	naddrs = 0;
37306f25ae9SGregory Neil Shapiro 
37406f25ae9SGregory Neil Shapiro 	/* make sure we have enough space to copy the string */
37506f25ae9SGregory Neil Shapiro 	i = strlen(list) + 1;
376d0cef73dSGregory Neil Shapiro 	if (i <= sizeof(buf))
37706f25ae9SGregory Neil Shapiro 	{
37806f25ae9SGregory Neil Shapiro 		bufp = buf;
379d0cef73dSGregory Neil Shapiro 		i = sizeof(buf);
38006f25ae9SGregory Neil Shapiro 	}
38106f25ae9SGregory Neil Shapiro 	else
38240266059SGregory Neil Shapiro 		bufp = sm_malloc_x(i);
38306f25ae9SGregory Neil Shapiro 
38440266059SGregory Neil Shapiro 	SM_TRY
38540266059SGregory Neil Shapiro 	{
38640266059SGregory Neil Shapiro 		(void) sm_strlcpy(bufp, denlstring(list, false, true), i);
38740266059SGregory Neil Shapiro 
388ffb83623SGregory Neil Shapiro # if _FFR_ADDR_TYPE_MODES
389ffb83623SGregory Neil Shapiro 		if (AddrTypeModes)
390ffb83623SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
391ffb83623SGregory Neil Shapiro 				  "e r d");
392ffb83623SGregory Neil Shapiro 		else
393ffb83623SGregory Neil Shapiro # endif /* _FFR_ADDR_TYPE_MODES */
3942fb4f839SGregory Neil Shapiro 		/* "else" in #if code above */
3952fb4f839SGregory Neil Shapiro 		{
3962fb4f839SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
3972fb4f839SGregory Neil Shapiro 				  "e r");
3982fb4f839SGregory Neil Shapiro 		}
39906f25ae9SGregory Neil Shapiro 		for (p = bufp; *p != '\0'; )
40006f25ae9SGregory Neil Shapiro 		{
40106f25ae9SGregory Neil Shapiro 			ADDRESS a;	/* parsed address to be removed */
40206f25ae9SGregory Neil Shapiro 			ADDRESS *q;
40306f25ae9SGregory Neil Shapiro 			ADDRESS **pq;
40406f25ae9SGregory Neil Shapiro 			char *delimptr;
40506f25ae9SGregory Neil Shapiro 
40606f25ae9SGregory Neil Shapiro 			/* parse the address */
4075b0945b5SGregory Neil Shapiro 			while ((SM_ISSPACE(*p)) || *p == ',')
40806f25ae9SGregory Neil Shapiro 				p++;
4092fb4f839SGregory Neil Shapiro 			/* XXX p must be [i] */
410d0cef73dSGregory Neil Shapiro 			if (parseaddr(p, &a, RF_COPYALL|RF_RM_ADDR,
41140266059SGregory Neil Shapiro 				      delimiter, &delimptr, e, true) == NULL)
41206f25ae9SGregory Neil Shapiro 			{
41306f25ae9SGregory Neil Shapiro 				p = delimptr;
41406f25ae9SGregory Neil Shapiro 				continue;
41506f25ae9SGregory Neil Shapiro 			}
41606f25ae9SGregory Neil Shapiro 			p = delimptr;
41706f25ae9SGregory Neil Shapiro 			for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
41806f25ae9SGregory Neil Shapiro 			{
41906f25ae9SGregory Neil Shapiro 				if (!QS_IS_DEAD(q->q_state) &&
420323f6dcbSGregory Neil Shapiro 				    (sameaddr(q, &a) ||
421323f6dcbSGregory Neil Shapiro 				     strcmp(q->q_paddr, a.q_paddr) == 0))
42206f25ae9SGregory Neil Shapiro 				{
42306f25ae9SGregory Neil Shapiro 					if (tTd(25, 5))
42406f25ae9SGregory Neil Shapiro 					{
42540266059SGregory Neil Shapiro 						sm_dprintf("removefromlist: QS_REMOVED ");
426e92d3f3fSGregory Neil Shapiro 						printaddr(sm_debug_file(), &a, false);
42706f25ae9SGregory Neil Shapiro 					}
42806f25ae9SGregory Neil Shapiro 					q->q_state = QS_REMOVED;
42906f25ae9SGregory Neil Shapiro 					naddrs++;
43006f25ae9SGregory Neil Shapiro 					break;
43106f25ae9SGregory Neil Shapiro 				}
43206f25ae9SGregory Neil Shapiro 			}
43306f25ae9SGregory Neil Shapiro 		}
43440266059SGregory Neil Shapiro 	}
43540266059SGregory Neil Shapiro 	SM_FINALLY
43640266059SGregory Neil Shapiro 	{
43706f25ae9SGregory Neil Shapiro 		e->e_to = oldto;
43806f25ae9SGregory Neil Shapiro 		if (bufp != buf)
4398774250cSGregory Neil Shapiro 			sm_free(bufp);
44040266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
44140266059SGregory Neil Shapiro 	}
44240266059SGregory Neil Shapiro 	SM_END_TRY
44306f25ae9SGregory Neil Shapiro 	return naddrs;
444c2aa98e2SPeter Wemm }
44540266059SGregory Neil Shapiro #endif /* MILTER */
446d0cef73dSGregory Neil Shapiro 
44740266059SGregory Neil Shapiro /*
448c2aa98e2SPeter Wemm **  RECIPIENT -- Designate a message recipient
449d0cef73dSGregory Neil Shapiro **	Saves the named person for future mailing (after some checks).
450c2aa98e2SPeter Wemm **
451c2aa98e2SPeter Wemm **	Parameters:
45240266059SGregory Neil Shapiro **		new -- the (preparsed) address header for the recipient.
453c2aa98e2SPeter Wemm **		sendq -- a pointer to the head of a queue to put the
45406f25ae9SGregory Neil Shapiro **			recipient in.  Duplicate suppression is done
455c2aa98e2SPeter Wemm **			in this queue.
456c2aa98e2SPeter Wemm **		aliaslevel -- the current alias nesting depth.
457c2aa98e2SPeter Wemm **		e -- the current envelope.
458c2aa98e2SPeter Wemm **
459c2aa98e2SPeter Wemm **	Returns:
460c2aa98e2SPeter Wemm **		The actual address in the queue.  This will be "a" if
461c2aa98e2SPeter Wemm **		the address is not a duplicate, else the original address.
462c2aa98e2SPeter Wemm **
463c2aa98e2SPeter Wemm */
464c2aa98e2SPeter Wemm 
465c2aa98e2SPeter Wemm ADDRESS *
recipient(new,sendq,aliaslevel,e)46640266059SGregory Neil Shapiro recipient(new, sendq, aliaslevel, e)
46740266059SGregory Neil Shapiro 	register ADDRESS *new;
468c2aa98e2SPeter Wemm 	register ADDRESS **sendq;
469c2aa98e2SPeter Wemm 	int aliaslevel;
470c2aa98e2SPeter Wemm 	register ENVELOPE *e;
471c2aa98e2SPeter Wemm {
472c2aa98e2SPeter Wemm 	register ADDRESS *q;
473c2aa98e2SPeter Wemm 	ADDRESS **pq;
47440266059SGregory Neil Shapiro 	ADDRESS **prev;
475c2aa98e2SPeter Wemm 	register struct mailer *m;
47640266059SGregory Neil Shapiro 	register char *p;
47706f25ae9SGregory Neil Shapiro 	int i, buflen;
47840266059SGregory Neil Shapiro 	bool quoted;		/* set if the addr has a quote bit */
47940266059SGregory Neil Shapiro 	bool insert;
48040266059SGregory Neil Shapiro 	int findusercount;
48140266059SGregory Neil Shapiro 	bool initialdontsend;
482c2aa98e2SPeter Wemm 	char *buf;
4832fb4f839SGregory Neil Shapiro 	char buf0[MAXNAME + 1]; /* EAI: ok, uses bufp dynamically expanded */
4842fb4f839SGregory Neil Shapiro 		/* unquoted image of the user name */
48540266059SGregory Neil Shapiro 	sortfn_t *sortfn;
486c2aa98e2SPeter Wemm 
48740266059SGregory Neil Shapiro 	p = NULL;
48840266059SGregory Neil Shapiro 	quoted = false;
48940266059SGregory Neil Shapiro 	insert = false;
49040266059SGregory Neil Shapiro 	findusercount = 0;
49140266059SGregory Neil Shapiro 	initialdontsend = QS_IS_DEAD(new->q_state);
49240266059SGregory Neil Shapiro 	e->e_to = new->q_paddr;
49340266059SGregory Neil Shapiro 	m = new->q_mailer;
494c2aa98e2SPeter Wemm 	errno = 0;
495c2aa98e2SPeter Wemm 	if (aliaslevel == 0)
49640266059SGregory Neil Shapiro 		new->q_flags |= QPRIMARY;
497c2aa98e2SPeter Wemm 	if (tTd(26, 1))
498c2aa98e2SPeter Wemm 	{
49940266059SGregory Neil Shapiro 		sm_dprintf("\nrecipient (%d): ", aliaslevel);
500e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), new, false);
501c2aa98e2SPeter Wemm 	}
502c2aa98e2SPeter Wemm 
50340266059SGregory Neil Shapiro 	/* if this is primary, use it as original recipient */
50440266059SGregory Neil Shapiro 	if (new->q_alias == NULL)
505c2aa98e2SPeter Wemm 	{
506c2aa98e2SPeter Wemm 		if (e->e_origrcpt == NULL)
50740266059SGregory Neil Shapiro 			e->e_origrcpt = new->q_paddr;
50840266059SGregory Neil Shapiro 		else if (e->e_origrcpt != new->q_paddr)
509c2aa98e2SPeter Wemm 			e->e_origrcpt = "";
510c2aa98e2SPeter Wemm 	}
511c2aa98e2SPeter Wemm 
51240266059SGregory Neil Shapiro 	/* find parent recipient for finalrcpt and orcpt */
51340266059SGregory Neil Shapiro 	for (q = new; q->q_alias != NULL; q = q->q_alias)
51440266059SGregory Neil Shapiro 		continue;
51540266059SGregory Neil Shapiro 
51640266059SGregory Neil Shapiro 	/* find final recipient DSN address */
51740266059SGregory Neil Shapiro 	if (new->q_finalrcpt == NULL &&
51840266059SGregory Neil Shapiro 	    e->e_from.q_mailer != NULL)
51940266059SGregory Neil Shapiro 	{
52040266059SGregory Neil Shapiro 		char frbuf[MAXLINE];
52140266059SGregory Neil Shapiro 
52240266059SGregory Neil Shapiro 		p = e->e_from.q_mailer->m_addrtype;
52340266059SGregory Neil Shapiro 		if (p == NULL)
52440266059SGregory Neil Shapiro 			p = "rfc822";
5252fb4f839SGregory Neil Shapiro #if USE_EAI
5262fb4f839SGregory Neil Shapiro 		if (SM_STRCASEEQ(p, "rfc822") &&
5275b0945b5SGregory Neil Shapiro 		    !addr_is_ascii(q->q_user))
5285b0945b5SGregory Neil Shapiro 			p = "utf-8";
5295b0945b5SGregory Neil Shapiro #endif
53040266059SGregory Neil Shapiro 		if (sm_strcasecmp(p, "rfc822") != 0)
53140266059SGregory Neil Shapiro 		{
532d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s",
53340266059SGregory Neil Shapiro 					   q->q_mailer->m_addrtype,
53440266059SGregory Neil Shapiro 					   q->q_user);
53540266059SGregory Neil Shapiro 		}
53640266059SGregory Neil Shapiro 		else if (strchr(q->q_user, '@') != NULL)
53740266059SGregory Neil Shapiro 		{
538d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s",
53940266059SGregory Neil Shapiro 					   p, q->q_user);
54040266059SGregory Neil Shapiro 		}
54140266059SGregory Neil Shapiro 		else if (strchr(q->q_paddr, '@') != NULL)
54240266059SGregory Neil Shapiro 		{
54340266059SGregory Neil Shapiro 			char *qp;
54440266059SGregory Neil Shapiro 			bool b;
54540266059SGregory Neil Shapiro 
54640266059SGregory Neil Shapiro 			qp = q->q_paddr;
54740266059SGregory Neil Shapiro 
54840266059SGregory Neil Shapiro 			/* strip brackets from address */
54940266059SGregory Neil Shapiro 			b = false;
55040266059SGregory Neil Shapiro 			if (*qp == '<')
55140266059SGregory Neil Shapiro 			{
55240266059SGregory Neil Shapiro 				b = qp[strlen(qp) - 1] == '>';
55340266059SGregory Neil Shapiro 				if (b)
55440266059SGregory Neil Shapiro 					qp[strlen(qp) - 1] = '\0';
55540266059SGregory Neil Shapiro 				qp++;
55640266059SGregory Neil Shapiro 			}
557d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s",
55840266059SGregory Neil Shapiro 					   p, qp);
55940266059SGregory Neil Shapiro 
56040266059SGregory Neil Shapiro 			/* undo damage */
56140266059SGregory Neil Shapiro 			if (b)
56240266059SGregory Neil Shapiro 				qp[strlen(qp)] = '>';
56340266059SGregory Neil Shapiro 		}
56440266059SGregory Neil Shapiro 		else
56540266059SGregory Neil Shapiro 		{
566d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(frbuf, sizeof(frbuf),
56740266059SGregory Neil Shapiro 					   "%s; %.700s@%.100s",
56840266059SGregory Neil Shapiro 					   p, q->q_user, MyHostName);
56940266059SGregory Neil Shapiro 		}
57040266059SGregory Neil Shapiro 		new->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool, frbuf);
57140266059SGregory Neil Shapiro 	}
57240266059SGregory Neil Shapiro 
57306f25ae9SGregory Neil Shapiro #if _FFR_GEN_ORCPT
57406f25ae9SGregory Neil Shapiro 	/* set ORCPT DSN arg if not already set */
57540266059SGregory Neil Shapiro 	if (new->q_orcpt == NULL)
57606f25ae9SGregory Neil Shapiro 	{
57706f25ae9SGregory Neil Shapiro 		/* check for an existing ORCPT */
57806f25ae9SGregory Neil Shapiro 		if (q->q_orcpt != NULL)
57940266059SGregory Neil Shapiro 			new->q_orcpt = q->q_orcpt;
58006f25ae9SGregory Neil Shapiro 		else
58106f25ae9SGregory Neil Shapiro 		{
58206f25ae9SGregory Neil Shapiro 			/* make our own */
58340266059SGregory Neil Shapiro 			bool b = false;
58406f25ae9SGregory Neil Shapiro 			char *qp;
58506f25ae9SGregory Neil Shapiro 			char obuf[MAXLINE];
58606f25ae9SGregory Neil Shapiro 
58706f25ae9SGregory Neil Shapiro 			if (e->e_from.q_mailer != NULL)
58806f25ae9SGregory Neil Shapiro 				p = e->e_from.q_mailer->m_addrtype;
58906f25ae9SGregory Neil Shapiro 			if (p == NULL)
59006f25ae9SGregory Neil Shapiro 				p = "rfc822";
591d0cef73dSGregory Neil Shapiro 			(void) sm_strlcpyn(obuf, sizeof(obuf), 2, p, ";");
59206f25ae9SGregory Neil Shapiro 
59306f25ae9SGregory Neil Shapiro 			qp = q->q_paddr;
59406f25ae9SGregory Neil Shapiro 
59506f25ae9SGregory Neil Shapiro 			/* FFR: Needs to strip comments from stdin addrs */
59606f25ae9SGregory Neil Shapiro 
59706f25ae9SGregory Neil Shapiro 			/* strip brackets from address */
59806f25ae9SGregory Neil Shapiro 			if (*qp == '<')
59906f25ae9SGregory Neil Shapiro 			{
60006f25ae9SGregory Neil Shapiro 				b = qp[strlen(qp) - 1] == '>';
60106f25ae9SGregory Neil Shapiro 				if (b)
60206f25ae9SGregory Neil Shapiro 					qp[strlen(qp) - 1] = '\0';
60306f25ae9SGregory Neil Shapiro 				qp++;
60406f25ae9SGregory Neil Shapiro 			}
60506f25ae9SGregory Neil Shapiro 
606d0cef73dSGregory Neil Shapiro 			p = xtextify(denlstring(qp, true, false), "=");
60706f25ae9SGregory Neil Shapiro 
608d0cef73dSGregory Neil Shapiro 			if (sm_strlcat(obuf, p, sizeof(obuf)) >= sizeof(obuf))
60906f25ae9SGregory Neil Shapiro 			{
61006f25ae9SGregory Neil Shapiro 				/* if too big, don't use it */
61106f25ae9SGregory Neil Shapiro 				obuf[0] = '\0';
61206f25ae9SGregory Neil Shapiro 			}
61306f25ae9SGregory Neil Shapiro 
61406f25ae9SGregory Neil Shapiro 			/* undo damage */
61506f25ae9SGregory Neil Shapiro 			if (b)
61606f25ae9SGregory Neil Shapiro 				qp[strlen(qp)] = '>';
61706f25ae9SGregory Neil Shapiro 
61806f25ae9SGregory Neil Shapiro 			if (obuf[0] != '\0')
61940266059SGregory Neil Shapiro 				new->q_orcpt =
62040266059SGregory Neil Shapiro 					sm_rpool_strdup_x(e->e_rpool, obuf);
62106f25ae9SGregory Neil Shapiro 		}
62206f25ae9SGregory Neil Shapiro 	}
62306f25ae9SGregory Neil Shapiro #endif /* _FFR_GEN_ORCPT */
62406f25ae9SGregory Neil Shapiro 
625c2aa98e2SPeter Wemm 	/* break aliasing loops */
626c2aa98e2SPeter Wemm 	if (aliaslevel > MaxAliasRecursion)
627c2aa98e2SPeter Wemm 	{
62840266059SGregory Neil Shapiro 		new->q_state = QS_BADADDR;
62940266059SGregory Neil Shapiro 		new->q_status = "5.4.6";
630d0cef73dSGregory Neil Shapiro 		if (new->q_alias != NULL)
631d0cef73dSGregory Neil Shapiro 		{
632d0cef73dSGregory Neil Shapiro 			new->q_alias->q_state = QS_BADADDR;
633d0cef73dSGregory Neil Shapiro 			new->q_alias->q_status = "5.4.6";
634d0cef73dSGregory Neil Shapiro 		}
635d0cef73dSGregory Neil Shapiro 		if ((SuprErrs || !LogUsrErrs) && LogLevel > 0)
636d0cef73dSGregory Neil Shapiro 		{
637d0cef73dSGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
638d0cef73dSGregory Neil Shapiro 				"aliasing/forwarding loop broken: %s (%d aliases deep; %d max)",
639d0cef73dSGregory Neil Shapiro 				FileName != NULL ? FileName : "", aliaslevel,
640d0cef73dSGregory Neil Shapiro 				MaxAliasRecursion);
641d0cef73dSGregory Neil Shapiro 		}
64240266059SGregory Neil Shapiro 		usrerrenh(new->q_status,
64306f25ae9SGregory Neil Shapiro 			  "554 aliasing/forwarding loop broken (%d aliases deep; %d max)",
644c2aa98e2SPeter Wemm 			  aliaslevel, MaxAliasRecursion);
64540266059SGregory Neil Shapiro 		return new;
646c2aa98e2SPeter Wemm 	}
647c2aa98e2SPeter Wemm 
648c2aa98e2SPeter Wemm 	/*
649c2aa98e2SPeter Wemm 	**  Finish setting up address structure.
650c2aa98e2SPeter Wemm 	*/
651c2aa98e2SPeter Wemm 
652c2aa98e2SPeter Wemm 	/* get unquoted user for file, program or user.name check */
65340266059SGregory Neil Shapiro 	i = strlen(new->q_user);
654d0cef73dSGregory Neil Shapiro 	if (i >= sizeof(buf0))
65506f25ae9SGregory Neil Shapiro 	{
65606f25ae9SGregory Neil Shapiro 		buflen = i + 1;
65706f25ae9SGregory Neil Shapiro 		buf = xalloc(buflen);
65806f25ae9SGregory Neil Shapiro 	}
659c2aa98e2SPeter Wemm 	else
66006f25ae9SGregory Neil Shapiro 	{
661c2aa98e2SPeter Wemm 		buf = buf0;
662d0cef73dSGregory Neil Shapiro 		buflen = sizeof(buf0);
66306f25ae9SGregory Neil Shapiro 	}
66440266059SGregory Neil Shapiro 	(void) sm_strlcpy(buf, new->q_user, buflen);
665c2aa98e2SPeter Wemm 	for (p = buf; *p != '\0' && !quoted; p++)
666c2aa98e2SPeter Wemm 	{
667c2aa98e2SPeter Wemm 		if (*p == '\\')
66840266059SGregory Neil Shapiro 			quoted = true;
669c2aa98e2SPeter Wemm 	}
670c2aa98e2SPeter Wemm 	stripquotes(buf);
671c2aa98e2SPeter Wemm 
672c2aa98e2SPeter Wemm 	/* check for direct mailing to restricted mailers */
673c2aa98e2SPeter Wemm 	if (m == ProgMailer)
674c2aa98e2SPeter Wemm 	{
67540266059SGregory Neil Shapiro 		if (new->q_alias == NULL || UseMSP ||
67640266059SGregory Neil Shapiro 		    bitset(EF_UNSAFE, e->e_flags))
677c2aa98e2SPeter Wemm 		{
67840266059SGregory Neil Shapiro 			new->q_state = QS_BADADDR;
67940266059SGregory Neil Shapiro 			new->q_status = "5.7.1";
68040266059SGregory Neil Shapiro 			usrerrenh(new->q_status,
68106f25ae9SGregory Neil Shapiro 				  "550 Cannot mail directly to programs");
682c2aa98e2SPeter Wemm 		}
68340266059SGregory Neil Shapiro 		else if (bitset(QBOGUSSHELL, new->q_alias->q_flags))
684c2aa98e2SPeter Wemm 		{
68540266059SGregory Neil Shapiro 			new->q_state = QS_BADADDR;
68640266059SGregory Neil Shapiro 			new->q_status = "5.7.1";
68740266059SGregory Neil Shapiro 			if (new->q_alias->q_ruser == NULL)
68840266059SGregory Neil Shapiro 				usrerrenh(new->q_status,
689da7d7b9cSGregory Neil Shapiro 					  "550 UID %ld is an unknown user: cannot mail to programs",
690da7d7b9cSGregory Neil Shapiro 					  (long) new->q_alias->q_uid);
691c2aa98e2SPeter Wemm 			else
69240266059SGregory Neil Shapiro 				usrerrenh(new->q_status,
69306f25ae9SGregory Neil Shapiro 					  "550 User %s@%s doesn't have a valid shell for mailing to programs",
69440266059SGregory Neil Shapiro 					  new->q_alias->q_ruser, MyHostName);
695c2aa98e2SPeter Wemm 		}
69640266059SGregory Neil Shapiro 		else if (bitset(QUNSAFEADDR, new->q_alias->q_flags))
697c2aa98e2SPeter Wemm 		{
69840266059SGregory Neil Shapiro 			new->q_state = QS_BADADDR;
69940266059SGregory Neil Shapiro 			new->q_status = "5.7.1";
70040266059SGregory Neil Shapiro 			new->q_rstatus = "550 Unsafe for mailing to programs";
70140266059SGregory Neil Shapiro 			usrerrenh(new->q_status,
70206f25ae9SGregory Neil Shapiro 				  "550 Address %s is unsafe for mailing to programs",
70340266059SGregory Neil Shapiro 				  new->q_alias->q_paddr);
704c2aa98e2SPeter Wemm 		}
705c2aa98e2SPeter Wemm 	}
706c2aa98e2SPeter Wemm 
707c2aa98e2SPeter Wemm 	/*
708c2aa98e2SPeter Wemm 	**  Look up this person in the recipient list.
709c2aa98e2SPeter Wemm 	**	If they are there already, return, otherwise continue.
710c2aa98e2SPeter Wemm 	**	If the list is empty, just add it.  Notice the cute
711c2aa98e2SPeter Wemm 	**	hack to make from addresses suppress things correctly:
71206f25ae9SGregory Neil Shapiro 	**	the QS_DUPLICATE state will be set in the send list.
713c2aa98e2SPeter Wemm 	**	[Please note: the emphasis is on "hack."]
714c2aa98e2SPeter Wemm 	*/
715c2aa98e2SPeter Wemm 
71640266059SGregory Neil Shapiro 	prev = NULL;
71740266059SGregory Neil Shapiro 
71840266059SGregory Neil Shapiro 	/*
71940266059SGregory Neil Shapiro 	**  If this message is going to the queue or FastSplit is set
72040266059SGregory Neil Shapiro 	**  and it is the first try and the envelope hasn't split, then we
72140266059SGregory Neil Shapiro 	**  avoid doing an MX RR lookup now because one will be done when the
72240266059SGregory Neil Shapiro 	**  message is extracted from the queue later. It can go to the queue
72340266059SGregory Neil Shapiro 	**  because all messages are going to the queue or this mailer of
72440266059SGregory Neil Shapiro 	**  the current recipient is marked expensive.
72540266059SGregory Neil Shapiro 	*/
72640266059SGregory Neil Shapiro 
72713bd1963SGregory Neil Shapiro 	if (UseMSP || WILL_BE_QUEUED(e->e_sendmode) ||
72840266059SGregory Neil Shapiro 	    (!bitset(EF_SPLIT, e->e_flags) && e->e_ntries == 0 &&
72940266059SGregory Neil Shapiro 	     FastSplit > 0))
73040266059SGregory Neil Shapiro 		sortfn = sorthost;
73140266059SGregory Neil Shapiro 	else if (NoConnect && bitnset(M_EXPENSIVE, new->q_mailer->m_flags))
73240266059SGregory Neil Shapiro 		sortfn = sortexpensive;
73340266059SGregory Neil Shapiro 	else
73440266059SGregory Neil Shapiro 		sortfn = sortbysignature;
73540266059SGregory Neil Shapiro 
736c2aa98e2SPeter Wemm 	for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
737c2aa98e2SPeter Wemm 	{
73840266059SGregory Neil Shapiro 		/*
73940266059SGregory Neil Shapiro 		**  If address is "less than" it should be inserted now.
74040266059SGregory Neil Shapiro 		**  If address is "greater than" current comparison it'll
74140266059SGregory Neil Shapiro 		**  insert later in the list; so loop again (if possible).
74240266059SGregory Neil Shapiro 		**  If address is "equal" (different equal than sameaddr()
74340266059SGregory Neil Shapiro 		**  call) then check if sameaddr() will be true.
74440266059SGregory Neil Shapiro 		**  Because this list is now sorted, it'll mean fewer
74540266059SGregory Neil Shapiro 		**  comparisons and fewer loops which is important for more
74640266059SGregory Neil Shapiro 		**  recipients.
74740266059SGregory Neil Shapiro 		*/
74840266059SGregory Neil Shapiro 
74940266059SGregory Neil Shapiro 		i = (*sortfn)(new, q);
75040266059SGregory Neil Shapiro 		if (i == 0) /* equal */
75140266059SGregory Neil Shapiro 		{
75240266059SGregory Neil Shapiro 			/*
753*d39bd2c1SGregory Neil Shapiro 			**  sortbysignature() has said that the two have
75440266059SGregory Neil Shapiro 			**  equal MX RR's and the same user. Calling sameaddr()
75540266059SGregory Neil Shapiro 			**  now checks if the two hosts are as identical as the
75640266059SGregory Neil Shapiro 			**  MX RR's are (which might not be the case)
75740266059SGregory Neil Shapiro 			**  before saying these are the identical addresses.
75840266059SGregory Neil Shapiro 			*/
75940266059SGregory Neil Shapiro 
76040266059SGregory Neil Shapiro 			if (sameaddr(q, new) &&
761c2aa98e2SPeter Wemm 			    (bitset(QRCPTOK, q->q_flags) ||
762c2aa98e2SPeter Wemm 			     !bitset(QPRIMARY, q->q_flags)))
763c2aa98e2SPeter Wemm 			{
764c2aa98e2SPeter Wemm 				if (tTd(26, 1))
765c2aa98e2SPeter Wemm 				{
76640266059SGregory Neil Shapiro 					sm_dprintf("%s in sendq: ",
76740266059SGregory Neil Shapiro 						   new->q_paddr);
768e92d3f3fSGregory Neil Shapiro 					printaddr(sm_debug_file(), q, false);
769c2aa98e2SPeter Wemm 				}
770c2aa98e2SPeter Wemm 				if (!bitset(QPRIMARY, q->q_flags))
771c2aa98e2SPeter Wemm 				{
77240266059SGregory Neil Shapiro 					if (!QS_IS_DEAD(new->q_state))
773c2aa98e2SPeter Wemm 						message("duplicate suppressed");
77406f25ae9SGregory Neil Shapiro 					else
77506f25ae9SGregory Neil Shapiro 						q->q_state = QS_DUPLICATE;
77640266059SGregory Neil Shapiro 					q->q_flags |= new->q_flags;
777c2aa98e2SPeter Wemm 				}
77806f25ae9SGregory Neil Shapiro 				else if (bitset(QSELFREF, q->q_flags)
77940266059SGregory Neil Shapiro 					 || q->q_state == QS_REMOVED)
78006f25ae9SGregory Neil Shapiro 				{
78106f25ae9SGregory Neil Shapiro 					/*
78240266059SGregory Neil Shapiro 					**  If an earlier milter removed the
78340266059SGregory Neil Shapiro 					**  address, a later one can still add
78440266059SGregory Neil Shapiro 					**  it back.
78506f25ae9SGregory Neil Shapiro 					*/
78640266059SGregory Neil Shapiro 
78740266059SGregory Neil Shapiro 					q->q_state = new->q_state;
78840266059SGregory Neil Shapiro 					q->q_flags |= new->q_flags;
78906f25ae9SGregory Neil Shapiro 				}
79040266059SGregory Neil Shapiro 				new = q;
791c2aa98e2SPeter Wemm 				goto done;
792c2aa98e2SPeter Wemm 			}
793c2aa98e2SPeter Wemm 		}
79440266059SGregory Neil Shapiro 		else if (i < 0) /* less than */
79540266059SGregory Neil Shapiro 		{
79640266059SGregory Neil Shapiro 			insert = true;
79740266059SGregory Neil Shapiro 			break;
79840266059SGregory Neil Shapiro 		}
79940266059SGregory Neil Shapiro 		prev = pq;
80040266059SGregory Neil Shapiro 	}
80140266059SGregory Neil Shapiro 
80240266059SGregory Neil Shapiro 	/* pq should point to an address, never NULL */
80340266059SGregory Neil Shapiro 	SM_ASSERT(pq != NULL);
804c2aa98e2SPeter Wemm 
805c2aa98e2SPeter Wemm 	/* add address on list */
80640266059SGregory Neil Shapiro 	if (insert)
807065a643dSPeter Wemm 	{
80840266059SGregory Neil Shapiro 		/*
80940266059SGregory Neil Shapiro 		**  insert before 'pq'. Only possible when at least 1
81040266059SGregory Neil Shapiro 		**  ADDRESS is in the list already.
81140266059SGregory Neil Shapiro 		*/
81240266059SGregory Neil Shapiro 
81340266059SGregory Neil Shapiro 		new->q_next = *pq;
81440266059SGregory Neil Shapiro 		if (prev == NULL)
81540266059SGregory Neil Shapiro 			*sendq = new; /* To be the first ADDRESS */
81640266059SGregory Neil Shapiro 		else
81740266059SGregory Neil Shapiro 			(*prev)->q_next = new;
818065a643dSPeter Wemm 	}
81940266059SGregory Neil Shapiro 	else
82040266059SGregory Neil Shapiro 	{
82140266059SGregory Neil Shapiro 		/*
82240266059SGregory Neil Shapiro 		**  Place in list at current 'pq' position. Possible
82340266059SGregory Neil Shapiro 		**  when there are 0 or more ADDRESS's in the list.
82440266059SGregory Neil Shapiro 		*/
82540266059SGregory Neil Shapiro 
82640266059SGregory Neil Shapiro 		new->q_next = NULL;
82740266059SGregory Neil Shapiro 		*pq = new;
82840266059SGregory Neil Shapiro 	}
82940266059SGregory Neil Shapiro 
83040266059SGregory Neil Shapiro 	/* added a new address: clear split flag */
83140266059SGregory Neil Shapiro 	e->e_flags &= ~EF_SPLIT;
832c2aa98e2SPeter Wemm 
833c2aa98e2SPeter Wemm 	/*
834c2aa98e2SPeter Wemm 	**  Alias the name and handle special mailer types.
835c2aa98e2SPeter Wemm 	*/
836c2aa98e2SPeter Wemm 
837c2aa98e2SPeter Wemm   trylocaluser:
838c2aa98e2SPeter Wemm 	if (tTd(29, 7))
839065a643dSPeter Wemm 	{
84040266059SGregory Neil Shapiro 		sm_dprintf("at trylocaluser: ");
841e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), new, false);
842065a643dSPeter Wemm 	}
843c2aa98e2SPeter Wemm 
84440266059SGregory Neil Shapiro 	if (!QS_IS_OK(new->q_state))
84540266059SGregory Neil Shapiro 	{
84640266059SGregory Neil Shapiro 		if (QS_IS_UNDELIVERED(new->q_state))
84740266059SGregory Neil Shapiro 			e->e_nrcpts++;
848c2aa98e2SPeter Wemm 		goto testselfdestruct;
84940266059SGregory Neil Shapiro 	}
850c2aa98e2SPeter Wemm 
851c2aa98e2SPeter Wemm 	if (m == InclMailer)
852c2aa98e2SPeter Wemm 	{
85340266059SGregory Neil Shapiro 		new->q_state = QS_INCLUDED;
85440266059SGregory Neil Shapiro 		if (new->q_alias == NULL || UseMSP ||
85540266059SGregory Neil Shapiro 		    bitset(EF_UNSAFE, e->e_flags))
856c2aa98e2SPeter Wemm 		{
85740266059SGregory Neil Shapiro 			new->q_state = QS_BADADDR;
85840266059SGregory Neil Shapiro 			new->q_status = "5.7.1";
85940266059SGregory Neil Shapiro 			usrerrenh(new->q_status,
86006f25ae9SGregory Neil Shapiro 				  "550 Cannot mail directly to :include:s");
861c2aa98e2SPeter Wemm 		}
862c2aa98e2SPeter Wemm 		else
863c2aa98e2SPeter Wemm 		{
864c2aa98e2SPeter Wemm 			int ret;
865c2aa98e2SPeter Wemm 
86640266059SGregory Neil Shapiro 			message("including file %s", new->q_user);
86740266059SGregory Neil Shapiro 			ret = include(new->q_user, false, new,
86840266059SGregory Neil Shapiro 				      sendq, aliaslevel, e);
869c2aa98e2SPeter Wemm 			if (transienterror(ret))
870c2aa98e2SPeter Wemm 			{
871c2aa98e2SPeter Wemm 				if (LogLevel > 2)
872c2aa98e2SPeter Wemm 					sm_syslog(LOG_ERR, e->e_id,
873c2aa98e2SPeter Wemm 						  "include %s: transient error: %s",
87440266059SGregory Neil Shapiro 						  shortenstring(new->q_user,
87540266059SGregory Neil Shapiro 								MAXSHORTSTR),
87640266059SGregory Neil Shapiro 								sm_errstring(ret));
87740266059SGregory Neil Shapiro 				new->q_state = QS_QUEUEUP;
87806f25ae9SGregory Neil Shapiro 				usrerr("451 4.2.4 Cannot open %s: %s",
87940266059SGregory Neil Shapiro 					shortenstring(new->q_user,
88040266059SGregory Neil Shapiro 						      MAXSHORTSTR),
88140266059SGregory Neil Shapiro 					sm_errstring(ret));
882c2aa98e2SPeter Wemm 			}
883c2aa98e2SPeter Wemm 			else if (ret != 0)
884c2aa98e2SPeter Wemm 			{
88540266059SGregory Neil Shapiro 				new->q_state = QS_BADADDR;
88640266059SGregory Neil Shapiro 				new->q_status = "5.2.4";
88740266059SGregory Neil Shapiro 				usrerrenh(new->q_status,
88806f25ae9SGregory Neil Shapiro 					  "550 Cannot open %s: %s",
88940266059SGregory Neil Shapiro 					  shortenstring(new->q_user,
89040266059SGregory Neil Shapiro 							MAXSHORTSTR),
89140266059SGregory Neil Shapiro 					  sm_errstring(ret));
892c2aa98e2SPeter Wemm 			}
893c2aa98e2SPeter Wemm 		}
894c2aa98e2SPeter Wemm 	}
895c2aa98e2SPeter Wemm 	else if (m == FileMailer)
896c2aa98e2SPeter Wemm 	{
89740266059SGregory Neil Shapiro 		/* check if allowed */
89840266059SGregory Neil Shapiro 		if (new->q_alias == NULL || UseMSP ||
89940266059SGregory Neil Shapiro 		    bitset(EF_UNSAFE, e->e_flags))
900c2aa98e2SPeter Wemm 		{
90140266059SGregory Neil Shapiro 			new->q_state = QS_BADADDR;
90240266059SGregory Neil Shapiro 			new->q_status = "5.7.1";
90340266059SGregory Neil Shapiro 			usrerrenh(new->q_status,
90406f25ae9SGregory Neil Shapiro 				  "550 Cannot mail directly to files");
905c2aa98e2SPeter Wemm 		}
90640266059SGregory Neil Shapiro 		else if (bitset(QBOGUSSHELL, new->q_alias->q_flags))
907c2aa98e2SPeter Wemm 		{
90840266059SGregory Neil Shapiro 			new->q_state = QS_BADADDR;
90940266059SGregory Neil Shapiro 			new->q_status = "5.7.1";
91040266059SGregory Neil Shapiro 			if (new->q_alias->q_ruser == NULL)
91140266059SGregory Neil Shapiro 				usrerrenh(new->q_status,
912da7d7b9cSGregory Neil Shapiro 					  "550 UID %ld is an unknown user: cannot mail to files",
913da7d7b9cSGregory Neil Shapiro 					  (long) new->q_alias->q_uid);
914c2aa98e2SPeter Wemm 			else
91540266059SGregory Neil Shapiro 				usrerrenh(new->q_status,
91606f25ae9SGregory Neil Shapiro 					  "550 User %s@%s doesn't have a valid shell for mailing to files",
91740266059SGregory Neil Shapiro 					  new->q_alias->q_ruser, MyHostName);
918c2aa98e2SPeter Wemm 		}
91940266059SGregory Neil Shapiro 		else if (bitset(QUNSAFEADDR, new->q_alias->q_flags))
920c2aa98e2SPeter Wemm 		{
92140266059SGregory Neil Shapiro 			new->q_state = QS_BADADDR;
92240266059SGregory Neil Shapiro 			new->q_status = "5.7.1";
92340266059SGregory Neil Shapiro 			new->q_rstatus = "550 Unsafe for mailing to files";
92440266059SGregory Neil Shapiro 			usrerrenh(new->q_status,
92506f25ae9SGregory Neil Shapiro 				  "550 Address %s is unsafe for mailing to files",
92640266059SGregory Neil Shapiro 				  new->q_alias->q_paddr);
927c2aa98e2SPeter Wemm 		}
928c2aa98e2SPeter Wemm 	}
929c2aa98e2SPeter Wemm 
930c2aa98e2SPeter Wemm 	/* try aliasing */
93140266059SGregory Neil Shapiro 	if (!quoted && QS_IS_OK(new->q_state) &&
932c2aa98e2SPeter Wemm 	    bitnset(M_ALIASABLE, m->m_flags))
93340266059SGregory Neil Shapiro 		alias(new, sendq, aliaslevel, e);
934c2aa98e2SPeter Wemm 
935c2aa98e2SPeter Wemm #if USERDB
936c2aa98e2SPeter Wemm 	/* if not aliased, look it up in the user database */
93740266059SGregory Neil Shapiro 	if (!bitset(QNOTREMOTE, new->q_flags) &&
93840266059SGregory Neil Shapiro 	    QS_IS_SENDABLE(new->q_state) &&
939c2aa98e2SPeter Wemm 	    bitnset(M_CHECKUDB, m->m_flags))
940c2aa98e2SPeter Wemm 	{
94140266059SGregory Neil Shapiro 		if (udbexpand(new, sendq, aliaslevel, e) == EX_TEMPFAIL)
942c2aa98e2SPeter Wemm 		{
94340266059SGregory Neil Shapiro 			new->q_state = QS_QUEUEUP;
944c2aa98e2SPeter Wemm 			if (e->e_message == NULL)
945d0cef73dSGregory Neil Shapiro 				e->e_message = sm_rpool_strdup_x(e->e_rpool,
946d0cef73dSGregory Neil Shapiro 						"Deferred: user database error");
94740266059SGregory Neil Shapiro 			if (new->q_message == NULL)
94840266059SGregory Neil Shapiro 				new->q_message = "Deferred: user database error";
949c2aa98e2SPeter Wemm 			if (LogLevel > 8)
950c2aa98e2SPeter Wemm 				sm_syslog(LOG_INFO, e->e_id,
951c2aa98e2SPeter Wemm 					  "deferred: udbexpand: %s",
95240266059SGregory Neil Shapiro 					  sm_errstring(errno));
953c2aa98e2SPeter Wemm 			message("queued (user database error): %s",
95440266059SGregory Neil Shapiro 				sm_errstring(errno));
955c2aa98e2SPeter Wemm 			e->e_nrcpts++;
956c2aa98e2SPeter Wemm 			goto testselfdestruct;
957c2aa98e2SPeter Wemm 		}
958c2aa98e2SPeter Wemm 	}
95906f25ae9SGregory Neil Shapiro #endif /* USERDB */
960c2aa98e2SPeter Wemm 
961c2aa98e2SPeter Wemm 	/*
962c2aa98e2SPeter Wemm 	**  If we have a level two config file, then pass the name through
963c2aa98e2SPeter Wemm 	**  Ruleset 5 before sending it off.  Ruleset 5 has the right
96440266059SGregory Neil Shapiro 	**  to rewrite it to another mailer.  This gives us a hook
965c2aa98e2SPeter Wemm 	**  after local aliasing has been done.
966c2aa98e2SPeter Wemm 	*/
967c2aa98e2SPeter Wemm 
968c2aa98e2SPeter Wemm 	if (tTd(29, 5))
969c2aa98e2SPeter Wemm 	{
97040266059SGregory Neil Shapiro 		sm_dprintf("recipient: testing local?  cl=%d, rr5=%p\n\t",
9715b0945b5SGregory Neil Shapiro 			   ConfigLevel, (void *)RewriteRules[5]);
972e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), new, false);
973c2aa98e2SPeter Wemm 	}
97406f25ae9SGregory Neil Shapiro 	if (ConfigLevel >= 2 && RewriteRules[5] != NULL &&
97506f25ae9SGregory Neil Shapiro 	    bitnset(M_TRYRULESET5, m->m_flags) &&
97640266059SGregory Neil Shapiro 	    !bitset(QNOTREMOTE, new->q_flags) &&
97740266059SGregory Neil Shapiro 	    QS_IS_OK(new->q_state))
978c2aa98e2SPeter Wemm 	{
97940266059SGregory Neil Shapiro 		maplocaluser(new, sendq, aliaslevel + 1, e);
980c2aa98e2SPeter Wemm 	}
981c2aa98e2SPeter Wemm 
982c2aa98e2SPeter Wemm 	/*
983c2aa98e2SPeter Wemm 	**  If it didn't get rewritten to another mailer, go ahead
984c2aa98e2SPeter Wemm 	**  and deliver it.
985c2aa98e2SPeter Wemm 	*/
986c2aa98e2SPeter Wemm 
98740266059SGregory Neil Shapiro 	if (QS_IS_OK(new->q_state) &&
988c2aa98e2SPeter Wemm 	    bitnset(M_HASPWENT, m->m_flags))
989c2aa98e2SPeter Wemm 	{
990c2aa98e2SPeter Wemm 		auto bool fuzzy;
99140266059SGregory Neil Shapiro 		SM_MBDB_T user;
99240266059SGregory Neil Shapiro 		int status;
993c2aa98e2SPeter Wemm 
994c2aa98e2SPeter Wemm 		/* warning -- finduser may trash buf */
99540266059SGregory Neil Shapiro 		status = finduser(buf, &fuzzy, &user);
99640266059SGregory Neil Shapiro 		switch (status)
997c2aa98e2SPeter Wemm 		{
99840266059SGregory Neil Shapiro 		  case EX_TEMPFAIL:
99940266059SGregory Neil Shapiro 			new->q_state = QS_QUEUEUP;
100040266059SGregory Neil Shapiro 			new->q_status = "4.5.2";
100140266059SGregory Neil Shapiro 			giveresponse(EX_TEMPFAIL, new->q_status, m, NULL,
100240266059SGregory Neil Shapiro 				     new->q_alias, (time_t) 0, e, new);
100340266059SGregory Neil Shapiro 			break;
100440266059SGregory Neil Shapiro 		  default:
100540266059SGregory Neil Shapiro 			new->q_state = QS_BADADDR;
100640266059SGregory Neil Shapiro 			new->q_status = "5.1.1";
100740266059SGregory Neil Shapiro 			new->q_rstatus = "550 5.1.1 User unknown";
100840266059SGregory Neil Shapiro 			giveresponse(EX_NOUSER, new->q_status, m, NULL,
100940266059SGregory Neil Shapiro 				     new->q_alias, (time_t) 0, e, new);
101040266059SGregory Neil Shapiro 			break;
101140266059SGregory Neil Shapiro 		  case EX_OK:
1012c2aa98e2SPeter Wemm 			if (fuzzy)
1013c2aa98e2SPeter Wemm 			{
1014c2aa98e2SPeter Wemm 				/* name was a fuzzy match */
101540266059SGregory Neil Shapiro 				new->q_user = sm_rpool_strdup_x(e->e_rpool,
101640266059SGregory Neil Shapiro 								user.mbdb_name);
1017c2aa98e2SPeter Wemm 				if (findusercount++ > 3)
1018c2aa98e2SPeter Wemm 				{
101940266059SGregory Neil Shapiro 					new->q_state = QS_BADADDR;
102040266059SGregory Neil Shapiro 					new->q_status = "5.4.6";
102140266059SGregory Neil Shapiro 					usrerrenh(new->q_status,
102206f25ae9SGregory Neil Shapiro 						  "554 aliasing/forwarding loop for %s broken",
102340266059SGregory Neil Shapiro 						  user.mbdb_name);
1024c2aa98e2SPeter Wemm 					goto done;
1025c2aa98e2SPeter Wemm 				}
1026c2aa98e2SPeter Wemm 
1027c2aa98e2SPeter Wemm 				/* see if it aliases */
102840266059SGregory Neil Shapiro 				(void) sm_strlcpy(buf, user.mbdb_name, buflen);
1029c2aa98e2SPeter Wemm 				goto trylocaluser;
1030c2aa98e2SPeter Wemm 			}
103140266059SGregory Neil Shapiro 			if (*user.mbdb_homedir == '\0')
103240266059SGregory Neil Shapiro 				new->q_home = NULL;
103340266059SGregory Neil Shapiro 			else if (strcmp(user.mbdb_homedir, "/") == 0)
103440266059SGregory Neil Shapiro 				new->q_home = "";
1035c2aa98e2SPeter Wemm 			else
103640266059SGregory Neil Shapiro 				new->q_home = sm_rpool_strdup_x(e->e_rpool,
103740266059SGregory Neil Shapiro 							user.mbdb_homedir);
103840266059SGregory Neil Shapiro 			if (user.mbdb_uid != SM_NO_UID)
1039c2aa98e2SPeter Wemm 			{
104040266059SGregory Neil Shapiro 				new->q_uid = user.mbdb_uid;
104140266059SGregory Neil Shapiro 				new->q_gid = user.mbdb_gid;
104240266059SGregory Neil Shapiro 				new->q_flags |= QGOODUID;
104340266059SGregory Neil Shapiro 			}
104440266059SGregory Neil Shapiro 			new->q_ruser = sm_rpool_strdup_x(e->e_rpool,
104540266059SGregory Neil Shapiro 							 user.mbdb_name);
104640266059SGregory Neil Shapiro 			if (user.mbdb_fullname[0] != '\0')
104740266059SGregory Neil Shapiro 				new->q_fullname = sm_rpool_strdup_x(e->e_rpool,
104840266059SGregory Neil Shapiro 							user.mbdb_fullname);
104940266059SGregory Neil Shapiro 			if (!usershellok(user.mbdb_name, user.mbdb_shell))
105040266059SGregory Neil Shapiro 			{
105140266059SGregory Neil Shapiro 				new->q_flags |= QBOGUSSHELL;
1052c2aa98e2SPeter Wemm 			}
1053c2aa98e2SPeter Wemm 			if (bitset(EF_VRFYONLY, e->e_flags))
1054c2aa98e2SPeter Wemm 			{
1055c2aa98e2SPeter Wemm 				/* don't do any more now */
105640266059SGregory Neil Shapiro 				new->q_state = QS_VERIFIED;
1057c2aa98e2SPeter Wemm 			}
1058c2aa98e2SPeter Wemm 			else if (!quoted)
105940266059SGregory Neil Shapiro 				forward(new, sendq, aliaslevel, e);
1060c2aa98e2SPeter Wemm 		}
1061c2aa98e2SPeter Wemm 	}
106240266059SGregory Neil Shapiro 	if (!QS_IS_DEAD(new->q_state))
1063c2aa98e2SPeter Wemm 		e->e_nrcpts++;
1064c2aa98e2SPeter Wemm 
1065c2aa98e2SPeter Wemm   testselfdestruct:
106640266059SGregory Neil Shapiro 	new->q_flags |= QTHISPASS;
1067c2aa98e2SPeter Wemm 	if (tTd(26, 8))
1068c2aa98e2SPeter Wemm 	{
106940266059SGregory Neil Shapiro 		sm_dprintf("testselfdestruct: ");
1070e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), new, false);
1071c2aa98e2SPeter Wemm 		if (tTd(26, 10))
1072c2aa98e2SPeter Wemm 		{
107340266059SGregory Neil Shapiro 			sm_dprintf("SENDQ:\n");
1074e92d3f3fSGregory Neil Shapiro 			printaddr(sm_debug_file(), *sendq, true);
107540266059SGregory Neil Shapiro 			sm_dprintf("----\n");
1076c2aa98e2SPeter Wemm 		}
1077c2aa98e2SPeter Wemm 	}
107840266059SGregory Neil Shapiro 	if (new->q_alias == NULL && new != &e->e_from &&
107940266059SGregory Neil Shapiro 	    QS_IS_DEAD(new->q_state))
1080c2aa98e2SPeter Wemm 	{
1081c2aa98e2SPeter Wemm 		for (q = *sendq; q != NULL; q = q->q_next)
1082c2aa98e2SPeter Wemm 		{
108306f25ae9SGregory Neil Shapiro 			if (!QS_IS_DEAD(q->q_state))
1084c2aa98e2SPeter Wemm 				break;
1085c2aa98e2SPeter Wemm 		}
1086c2aa98e2SPeter Wemm 		if (q == NULL)
1087c2aa98e2SPeter Wemm 		{
108840266059SGregory Neil Shapiro 			new->q_state = QS_BADADDR;
108940266059SGregory Neil Shapiro 			new->q_status = "5.4.6";
109040266059SGregory Neil Shapiro 			usrerrenh(new->q_status,
109106f25ae9SGregory Neil Shapiro 				  "554 aliasing/forwarding loop broken");
1092c2aa98e2SPeter Wemm 		}
1093c2aa98e2SPeter Wemm 	}
1094c2aa98e2SPeter Wemm 
1095c2aa98e2SPeter Wemm   done:
109640266059SGregory Neil Shapiro 	new->q_flags |= QTHISPASS;
1097c2aa98e2SPeter Wemm 	if (buf != buf0)
109840266059SGregory Neil Shapiro 		sm_free(buf); /* XXX leak if above code raises exception */
1099c2aa98e2SPeter Wemm 
1100c2aa98e2SPeter Wemm 	/*
1101c2aa98e2SPeter Wemm 	**  If we are at the top level, check to see if this has
1102c2aa98e2SPeter Wemm 	**  expanded to exactly one address.  If so, it can inherit
1103c2aa98e2SPeter Wemm 	**  the primaryness of the address.
1104c2aa98e2SPeter Wemm 	**
1105c2aa98e2SPeter Wemm 	**  While we're at it, clear the QTHISPASS bits.
1106c2aa98e2SPeter Wemm 	*/
1107c2aa98e2SPeter Wemm 
1108c2aa98e2SPeter Wemm 	if (aliaslevel == 0)
1109c2aa98e2SPeter Wemm 	{
1110c2aa98e2SPeter Wemm 		int nrcpts = 0;
1111c2aa98e2SPeter Wemm 		ADDRESS *only = NULL;
1112c2aa98e2SPeter Wemm 
1113c2aa98e2SPeter Wemm 		for (q = *sendq; q != NULL; q = q->q_next)
1114c2aa98e2SPeter Wemm 		{
1115c2aa98e2SPeter Wemm 			if (bitset(QTHISPASS, q->q_flags) &&
111606f25ae9SGregory Neil Shapiro 			    QS_IS_SENDABLE(q->q_state))
1117c2aa98e2SPeter Wemm 			{
1118c2aa98e2SPeter Wemm 				nrcpts++;
1119c2aa98e2SPeter Wemm 				only = q;
1120c2aa98e2SPeter Wemm 			}
1121c2aa98e2SPeter Wemm 			q->q_flags &= ~QTHISPASS;
1122c2aa98e2SPeter Wemm 		}
1123c2aa98e2SPeter Wemm 		if (nrcpts == 1)
1124c2aa98e2SPeter Wemm 		{
1125c2aa98e2SPeter Wemm 			/* check to see if this actually got a new owner */
1126c2aa98e2SPeter Wemm 			q = only;
1127c2aa98e2SPeter Wemm 			while ((q = q->q_alias) != NULL)
1128c2aa98e2SPeter Wemm 			{
1129c2aa98e2SPeter Wemm 				if (q->q_owner != NULL)
1130c2aa98e2SPeter Wemm 					break;
1131c2aa98e2SPeter Wemm 			}
1132c2aa98e2SPeter Wemm 			if (q == NULL)
1133c2aa98e2SPeter Wemm 				only->q_flags |= QPRIMARY;
1134c2aa98e2SPeter Wemm 		}
1135c2aa98e2SPeter Wemm 		else if (!initialdontsend && nrcpts > 0)
1136c2aa98e2SPeter Wemm 		{
1137c2aa98e2SPeter Wemm 			/* arrange for return receipt */
1138c2aa98e2SPeter Wemm 			e->e_flags |= EF_SENDRECEIPT;
113940266059SGregory Neil Shapiro 			new->q_flags |= QEXPANDED;
114006f25ae9SGregory Neil Shapiro 			if (e->e_xfp != NULL &&
114140266059SGregory Neil Shapiro 			    bitset(QPINGONSUCCESS, new->q_flags))
114240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
1143c2aa98e2SPeter Wemm 						     "%s... expanded to multiple addresses\n",
114440266059SGregory Neil Shapiro 						     new->q_paddr);
1145c2aa98e2SPeter Wemm 		}
1146c2aa98e2SPeter Wemm 	}
114740266059SGregory Neil Shapiro 	new->q_flags |= QRCPTOK;
1148d0cef73dSGregory Neil Shapiro 	(void) sm_snprintf(buf0, sizeof(buf0), "%d", e->e_nrcpts);
114940266059SGregory Neil Shapiro 	macdefine(&e->e_macro, A_TEMP, macid("{nrcpts}"), buf0);
115040266059SGregory Neil Shapiro 	return new;
1151c2aa98e2SPeter Wemm }
1152d0cef73dSGregory Neil Shapiro 
115340266059SGregory Neil Shapiro /*
1154c2aa98e2SPeter Wemm **  FINDUSER -- find the password entry for a user.
1155c2aa98e2SPeter Wemm **
1156c2aa98e2SPeter Wemm **	This looks a lot like getpwnam, except that it may want to
1157c2aa98e2SPeter Wemm **	do some fancier pattern matching in /etc/passwd.
1158c2aa98e2SPeter Wemm **
1159c2aa98e2SPeter Wemm **	This routine contains most of the time of many sendmail runs.
1160c2aa98e2SPeter Wemm **	It deserves to be optimized.
1161c2aa98e2SPeter Wemm **
1162c2aa98e2SPeter Wemm **	Parameters:
1163c2aa98e2SPeter Wemm **		name -- the name to match against.
116440266059SGregory Neil Shapiro **		fuzzyp -- an outarg that is set to true if this entry
1165c2aa98e2SPeter Wemm **			was found using the fuzzy matching algorithm;
116640266059SGregory Neil Shapiro **			set to false otherwise.
116740266059SGregory Neil Shapiro **		user -- structure to fill in if user is found
1168c2aa98e2SPeter Wemm **
1169c2aa98e2SPeter Wemm **	Returns:
117040266059SGregory Neil Shapiro **		On success, fill in *user, set *fuzzyp and return EX_OK.
117140266059SGregory Neil Shapiro **		If the user was not found, return EX_NOUSER.
117240266059SGregory Neil Shapiro **		On error, return EX_TEMPFAIL or EX_OSERR.
1173c2aa98e2SPeter Wemm **
1174c2aa98e2SPeter Wemm **	Side Effects:
1175c2aa98e2SPeter Wemm **		may modify name.
1176c2aa98e2SPeter Wemm */
1177c2aa98e2SPeter Wemm 
117840266059SGregory Neil Shapiro int
finduser(name,fuzzyp,user)117940266059SGregory Neil Shapiro finduser(name, fuzzyp, user)
1180c2aa98e2SPeter Wemm 	char *name;
1181c2aa98e2SPeter Wemm 	bool *fuzzyp;
118240266059SGregory Neil Shapiro 	SM_MBDB_T *user;
1183c2aa98e2SPeter Wemm {
118440266059SGregory Neil Shapiro #if MATCHGECOS
1185c2aa98e2SPeter Wemm 	register struct passwd *pw;
11865b0945b5SGregory Neil Shapiro #endif
1187c2aa98e2SPeter Wemm 	register char *p;
1188c2aa98e2SPeter Wemm 	bool tryagain;
118940266059SGregory Neil Shapiro 	int status;
1190c2aa98e2SPeter Wemm 
1191c2aa98e2SPeter Wemm 	if (tTd(29, 4))
119240266059SGregory Neil Shapiro 		sm_dprintf("finduser(%s): ", name);
1193c2aa98e2SPeter Wemm 
119440266059SGregory Neil Shapiro 	*fuzzyp = false;
1195c2aa98e2SPeter Wemm 
1196da7d7b9cSGregory Neil Shapiro #if HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN
1197c2aa98e2SPeter Wemm 	/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
1198c2aa98e2SPeter Wemm 	for (p = name; *p != '\0'; p++)
1199c2aa98e2SPeter Wemm 		if (!isascii(*p) || !isdigit(*p))
1200c2aa98e2SPeter Wemm 			break;
1201c2aa98e2SPeter Wemm 	if (*p == '\0')
1202c2aa98e2SPeter Wemm 	{
1203c2aa98e2SPeter Wemm 		if (tTd(29, 4))
120440266059SGregory Neil Shapiro 			sm_dprintf("failed (numeric input)\n");
120540266059SGregory Neil Shapiro 		return EX_NOUSER;
1206c2aa98e2SPeter Wemm 	}
1207da7d7b9cSGregory Neil Shapiro #endif /* HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN */
1208c2aa98e2SPeter Wemm 
1209c2aa98e2SPeter Wemm 	/* look up this login name using fast path */
121040266059SGregory Neil Shapiro 	status = sm_mbdb_lookup(name, user);
121140266059SGregory Neil Shapiro 	if (status != EX_NOUSER)
1212c2aa98e2SPeter Wemm 	{
1213c2aa98e2SPeter Wemm 		if (tTd(29, 4))
121440266059SGregory Neil Shapiro 			sm_dprintf("%s (non-fuzzy)\n", sm_strexit(status));
121540266059SGregory Neil Shapiro 		return status;
1216c2aa98e2SPeter Wemm 	}
1217c2aa98e2SPeter Wemm 
1218c2aa98e2SPeter Wemm 	/* try mapping it to lower case */
121940266059SGregory Neil Shapiro 	tryagain = false;
1220c2aa98e2SPeter Wemm 	for (p = name; *p != '\0'; p++)
1221c2aa98e2SPeter Wemm 	{
1222c2aa98e2SPeter Wemm 		if (isascii(*p) && isupper(*p))
1223c2aa98e2SPeter Wemm 		{
1224c2aa98e2SPeter Wemm 			*p = tolower(*p);
122540266059SGregory Neil Shapiro 			tryagain = true;
1226c2aa98e2SPeter Wemm 		}
1227c2aa98e2SPeter Wemm 	}
122840266059SGregory Neil Shapiro 	if (tryagain && (status = sm_mbdb_lookup(name, user)) != EX_NOUSER)
1229c2aa98e2SPeter Wemm 	{
1230c2aa98e2SPeter Wemm 		if (tTd(29, 4))
123140266059SGregory Neil Shapiro 			sm_dprintf("%s (lower case)\n", sm_strexit(status));
123240266059SGregory Neil Shapiro 		*fuzzyp = true;
123340266059SGregory Neil Shapiro 		return status;
1234c2aa98e2SPeter Wemm 	}
1235c2aa98e2SPeter Wemm 
1236c2aa98e2SPeter Wemm #if MATCHGECOS
1237c2aa98e2SPeter Wemm 	/* see if fuzzy matching allowed */
1238c2aa98e2SPeter Wemm 	if (!MatchGecos)
1239c2aa98e2SPeter Wemm 	{
1240c2aa98e2SPeter Wemm 		if (tTd(29, 4))
124140266059SGregory Neil Shapiro 			sm_dprintf("not found (fuzzy disabled)\n");
124240266059SGregory Neil Shapiro 		return EX_NOUSER;
1243c2aa98e2SPeter Wemm 	}
1244c2aa98e2SPeter Wemm 
1245c2aa98e2SPeter Wemm 	/* search for a matching full name instead */
1246c2aa98e2SPeter Wemm 	for (p = name; *p != '\0'; p++)
1247c2aa98e2SPeter Wemm 	{
1248c2aa98e2SPeter Wemm 		if (*p == (SpaceSub & 0177) || *p == '_')
1249c2aa98e2SPeter Wemm 			*p = ' ';
1250c2aa98e2SPeter Wemm 	}
1251c2aa98e2SPeter Wemm 	(void) setpwent();
1252c2aa98e2SPeter Wemm 	while ((pw = getpwent()) != NULL)
1253c2aa98e2SPeter Wemm 	{
12542fb4f839SGregory Neil Shapiro 		char buf[MAXNAME + 1];	/* EAI: ok: for pw_gecos */
1255c2aa98e2SPeter Wemm 
1256c2aa98e2SPeter Wemm # if 0
12572fb4f839SGregory Neil Shapiro 		if (SM_STRCASEEQ(pw->pw_name, name))
1258c2aa98e2SPeter Wemm 		{
1259c2aa98e2SPeter Wemm 			if (tTd(29, 4))
126040266059SGregory Neil Shapiro 				sm_dprintf("found (case wrapped)\n");
1261c2aa98e2SPeter Wemm 			break;
1262c2aa98e2SPeter Wemm 		}
126306f25ae9SGregory Neil Shapiro # endif /* 0 */
1264c2aa98e2SPeter Wemm 
1265d0cef73dSGregory Neil Shapiro 		sm_pwfullname(pw->pw_gecos, pw->pw_name, buf, sizeof(buf));
12662fb4f839SGregory Neil Shapiro 		if (strchr(buf, ' ') != NULL && SM_STRCASEEQ(buf, name))
1267c2aa98e2SPeter Wemm 		{
1268c2aa98e2SPeter Wemm 			if (tTd(29, 4))
126940266059SGregory Neil Shapiro 				sm_dprintf("fuzzy matches %s\n", pw->pw_name);
1270c2aa98e2SPeter Wemm 			message("sending to login name %s", pw->pw_name);
1271c2aa98e2SPeter Wemm 			break;
1272c2aa98e2SPeter Wemm 		}
1273c2aa98e2SPeter Wemm 	}
1274c2aa98e2SPeter Wemm 	if (pw != NULL)
127540266059SGregory Neil Shapiro 		*fuzzyp = true;
1276c2aa98e2SPeter Wemm 	else if (tTd(29, 4))
127740266059SGregory Neil Shapiro 		sm_dprintf("no fuzzy match found\n");
1278c2aa98e2SPeter Wemm # if DEC_OSF_BROKEN_GETPWENT	/* DEC OSF/1 3.2 or earlier */
1279c2aa98e2SPeter Wemm 	endpwent();
12805b0945b5SGregory Neil Shapiro # endif
128140266059SGregory Neil Shapiro 	if (pw == NULL)
128240266059SGregory Neil Shapiro 		return EX_NOUSER;
128340266059SGregory Neil Shapiro 	sm_mbdb_frompw(user, pw);
128440266059SGregory Neil Shapiro 	return EX_OK;
128506f25ae9SGregory Neil Shapiro #else /* MATCHGECOS */
1286c2aa98e2SPeter Wemm 	if (tTd(29, 4))
128740266059SGregory Neil Shapiro 		sm_dprintf("not found (fuzzy disabled)\n");
128840266059SGregory Neil Shapiro 	return EX_NOUSER;
128906f25ae9SGregory Neil Shapiro #endif /* MATCHGECOS */
1290c2aa98e2SPeter Wemm }
1291d0cef73dSGregory Neil Shapiro 
129240266059SGregory Neil Shapiro /*
1293c2aa98e2SPeter Wemm **  WRITABLE -- predicate returning if the file is writable.
1294c2aa98e2SPeter Wemm **
1295c2aa98e2SPeter Wemm **	This routine must duplicate the algorithm in sys/fio.c.
1296c2aa98e2SPeter Wemm **	Unfortunately, we cannot use the access call since we
1297c2aa98e2SPeter Wemm **	won't necessarily be the real uid when we try to
1298c2aa98e2SPeter Wemm **	actually open the file.
1299c2aa98e2SPeter Wemm **
1300c2aa98e2SPeter Wemm **	Notice that ANY file with ANY execute bit is automatically
1301c2aa98e2SPeter Wemm **	not writable.  This is also enforced by mailfile.
1302c2aa98e2SPeter Wemm **
1303c2aa98e2SPeter Wemm **	Parameters:
1304c2aa98e2SPeter Wemm **		filename -- the file name to check.
1305c2aa98e2SPeter Wemm **		ctladdr -- the controlling address for this file.
1306c2aa98e2SPeter Wemm **		flags -- SFF_* flags to control the function.
1307c2aa98e2SPeter Wemm **
1308c2aa98e2SPeter Wemm **	Returns:
130940266059SGregory Neil Shapiro **		true -- if we will be able to write this file.
131040266059SGregory Neil Shapiro **		false -- if we cannot write this file.
1311c2aa98e2SPeter Wemm **
1312c2aa98e2SPeter Wemm **	Side Effects:
1313c2aa98e2SPeter Wemm **		none.
1314c2aa98e2SPeter Wemm */
1315c2aa98e2SPeter Wemm 
1316c2aa98e2SPeter Wemm bool
writable(filename,ctladdr,flags)1317c2aa98e2SPeter Wemm writable(filename, ctladdr, flags)
1318c2aa98e2SPeter Wemm 	char *filename;
1319c2aa98e2SPeter Wemm 	ADDRESS *ctladdr;
132006f25ae9SGregory Neil Shapiro 	long flags;
1321c2aa98e2SPeter Wemm {
132206f25ae9SGregory Neil Shapiro 	uid_t euid = 0;
132306f25ae9SGregory Neil Shapiro 	gid_t egid = 0;
132406f25ae9SGregory Neil Shapiro 	char *user = NULL;
1325c2aa98e2SPeter Wemm 
1326c2aa98e2SPeter Wemm 	if (tTd(44, 5))
132740266059SGregory Neil Shapiro 		sm_dprintf("writable(%s, 0x%lx)\n", filename, flags);
1328c2aa98e2SPeter Wemm 
1329c2aa98e2SPeter Wemm 	/*
1330c2aa98e2SPeter Wemm 	**  File does exist -- check that it is writable.
1331c2aa98e2SPeter Wemm 	*/
1332c2aa98e2SPeter Wemm 
1333c2aa98e2SPeter Wemm 	if (geteuid() != 0)
1334c2aa98e2SPeter Wemm 	{
1335c2aa98e2SPeter Wemm 		euid = geteuid();
1336c2aa98e2SPeter Wemm 		egid = getegid();
133706f25ae9SGregory Neil Shapiro 		user = NULL;
1338c2aa98e2SPeter Wemm 	}
1339c2aa98e2SPeter Wemm 	else if (ctladdr != NULL)
1340c2aa98e2SPeter Wemm 	{
1341c2aa98e2SPeter Wemm 		euid = ctladdr->q_uid;
1342c2aa98e2SPeter Wemm 		egid = ctladdr->q_gid;
134306f25ae9SGregory Neil Shapiro 		user = ctladdr->q_user;
1344c2aa98e2SPeter Wemm 	}
1345c2aa98e2SPeter Wemm 	else if (bitset(SFF_RUNASREALUID, flags))
1346c2aa98e2SPeter Wemm 	{
1347c2aa98e2SPeter Wemm 		euid = RealUid;
1348c2aa98e2SPeter Wemm 		egid = RealGid;
134906f25ae9SGregory Neil Shapiro 		user = RealUserName;
1350c2aa98e2SPeter Wemm 	}
1351c2aa98e2SPeter Wemm 	else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags))
1352c2aa98e2SPeter Wemm 	{
1353e92d3f3fSGregory Neil Shapiro 		if (FileMailer->m_uid == NO_UID)
1354e92d3f3fSGregory Neil Shapiro 		{
1355e92d3f3fSGregory Neil Shapiro 			euid = DefUid;
1356e92d3f3fSGregory Neil Shapiro 			user = DefUser;
1357e92d3f3fSGregory Neil Shapiro 		}
1358e92d3f3fSGregory Neil Shapiro 		else
1359e92d3f3fSGregory Neil Shapiro 		{
1360c2aa98e2SPeter Wemm 			euid = FileMailer->m_uid;
136106f25ae9SGregory Neil Shapiro 			user = NULL;
1362c2aa98e2SPeter Wemm 		}
1363e92d3f3fSGregory Neil Shapiro 		if (FileMailer->m_gid == NO_GID)
1364e92d3f3fSGregory Neil Shapiro 			egid = DefGid;
1365e92d3f3fSGregory Neil Shapiro 		else
1366e92d3f3fSGregory Neil Shapiro 			egid = FileMailer->m_gid;
1367e92d3f3fSGregory Neil Shapiro 	}
1368c2aa98e2SPeter Wemm 	else
1369c2aa98e2SPeter Wemm 	{
1370c2aa98e2SPeter Wemm 		euid = egid = 0;
137106f25ae9SGregory Neil Shapiro 		user = NULL;
1372c2aa98e2SPeter Wemm 	}
1373c2aa98e2SPeter Wemm 	if (!bitset(SFF_ROOTOK, flags))
1374c2aa98e2SPeter Wemm 	{
1375c2aa98e2SPeter Wemm 		if (euid == 0)
1376c2aa98e2SPeter Wemm 		{
1377c2aa98e2SPeter Wemm 			euid = DefUid;
137806f25ae9SGregory Neil Shapiro 			user = DefUser;
1379c2aa98e2SPeter Wemm 		}
1380c2aa98e2SPeter Wemm 		if (egid == 0)
1381c2aa98e2SPeter Wemm 			egid = DefGid;
1382c2aa98e2SPeter Wemm 	}
1383c2aa98e2SPeter Wemm 	if (geteuid() == 0 &&
1384c2aa98e2SPeter Wemm 	    (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags)))
1385c2aa98e2SPeter Wemm 		flags |= SFF_SETUIDOK;
1386c2aa98e2SPeter Wemm 
138706f25ae9SGregory Neil Shapiro 	if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
1388c2aa98e2SPeter Wemm 		flags |= SFF_NOSLINK;
138906f25ae9SGregory Neil Shapiro 	if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail))
1390c2aa98e2SPeter Wemm 		flags |= SFF_NOHLINK;
1391c2aa98e2SPeter Wemm 
139206f25ae9SGregory Neil Shapiro 	errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL);
1393c2aa98e2SPeter Wemm 	return errno == 0;
1394c2aa98e2SPeter Wemm }
1395d0cef73dSGregory Neil Shapiro 
139640266059SGregory Neil Shapiro /*
1397c2aa98e2SPeter Wemm **  INCLUDE -- handle :include: specification.
1398c2aa98e2SPeter Wemm **
1399c2aa98e2SPeter Wemm **	Parameters:
1400c2aa98e2SPeter Wemm **		fname -- filename to include.
140140266059SGregory Neil Shapiro **		forwarding -- if true, we are reading a .forward file.
140240266059SGregory Neil Shapiro **			if false, it's a :include: file.
1403c2aa98e2SPeter Wemm **		ctladdr -- address template to use to fill in these
1404c2aa98e2SPeter Wemm **			addresses -- effective user/group id are
1405c2aa98e2SPeter Wemm **			the important things.
1406c2aa98e2SPeter Wemm **		sendq -- a pointer to the head of the send queue
1407c2aa98e2SPeter Wemm **			to put these addresses in.
1408c2aa98e2SPeter Wemm **		aliaslevel -- the alias nesting depth.
1409c2aa98e2SPeter Wemm **		e -- the current envelope.
1410c2aa98e2SPeter Wemm **
1411c2aa98e2SPeter Wemm **	Returns:
1412c2aa98e2SPeter Wemm **		open error status
1413c2aa98e2SPeter Wemm **
1414c2aa98e2SPeter Wemm **	Side Effects:
1415c2aa98e2SPeter Wemm **		reads the :include: file and sends to everyone
1416c2aa98e2SPeter Wemm **		listed in that file.
1417c2aa98e2SPeter Wemm **
1418c2aa98e2SPeter Wemm **	Security Note:
1419c2aa98e2SPeter Wemm **		If you have restricted chown (that is, you can't
1420c2aa98e2SPeter Wemm **		give a file away), it is reasonable to allow programs
1421c2aa98e2SPeter Wemm **		and files called from this :include: file to be to be
1422c2aa98e2SPeter Wemm **		run as the owner of the :include: file.  This is bogus
1423c2aa98e2SPeter Wemm **		if there is any chance of someone giving away a file.
1424c2aa98e2SPeter Wemm **		We assume that pre-POSIX systems can give away files.
1425c2aa98e2SPeter Wemm **
1426c2aa98e2SPeter Wemm **		There is an additional restriction that if you
1427c2aa98e2SPeter Wemm **		forward to a :include: file, it will not take on
1428c2aa98e2SPeter Wemm **		the ownership of the :include: file.  This may not
1429c2aa98e2SPeter Wemm **		be necessary, but shouldn't hurt.
1430c2aa98e2SPeter Wemm */
1431c2aa98e2SPeter Wemm 
1432c2aa98e2SPeter Wemm static jmp_buf	CtxIncludeTimeout;
1433c2aa98e2SPeter Wemm 
1434c2aa98e2SPeter Wemm int
include(fname,forwarding,ctladdr,sendq,aliaslevel,e)1435c2aa98e2SPeter Wemm include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
1436c2aa98e2SPeter Wemm 	char *fname;
1437c2aa98e2SPeter Wemm 	bool forwarding;
1438c2aa98e2SPeter Wemm 	ADDRESS *ctladdr;
1439c2aa98e2SPeter Wemm 	ADDRESS **sendq;
1440c2aa98e2SPeter Wemm 	int aliaslevel;
1441c2aa98e2SPeter Wemm 	ENVELOPE *e;
1442c2aa98e2SPeter Wemm {
144340266059SGregory Neil Shapiro 	SM_FILE_T *volatile fp = NULL;
1444c2aa98e2SPeter Wemm 	char *oldto = e->e_to;
1445c2aa98e2SPeter Wemm 	char *oldfilename = FileName;
1446c2aa98e2SPeter Wemm 	int oldlinenumber = LineNumber;
144740266059SGregory Neil Shapiro 	register SM_EVENT *ev = NULL;
1448c2aa98e2SPeter Wemm 	int nincludes;
1449c2aa98e2SPeter Wemm 	int mode;
145040266059SGregory Neil Shapiro 	volatile bool maxreached = false;
1451c2aa98e2SPeter Wemm 	register ADDRESS *ca;
145206f25ae9SGregory Neil Shapiro 	volatile uid_t saveduid;
145306f25ae9SGregory Neil Shapiro 	volatile gid_t savedgid;
145406f25ae9SGregory Neil Shapiro 	volatile uid_t uid;
145506f25ae9SGregory Neil Shapiro 	volatile gid_t gid;
145606f25ae9SGregory Neil Shapiro 	char *volatile user;
1457c2aa98e2SPeter Wemm 	int rval = 0;
145806f25ae9SGregory Neil Shapiro 	volatile long sfflags = SFF_REGONLY;
1459c2aa98e2SPeter Wemm 	register char *p;
146040266059SGregory Neil Shapiro 	bool safechown = false;
146140266059SGregory Neil Shapiro 	volatile bool safedir = false;
1462c2aa98e2SPeter Wemm 	struct stat st;
1463c2aa98e2SPeter Wemm 	char buf[MAXLINE];
1464c2aa98e2SPeter Wemm 
1465c2aa98e2SPeter Wemm 	if (tTd(27, 2))
146640266059SGregory Neil Shapiro 		sm_dprintf("include(%s)\n", fname);
1467c2aa98e2SPeter Wemm 	if (tTd(27, 4))
1468da7d7b9cSGregory Neil Shapiro 		sm_dprintf("   ruid=%ld euid=%ld\n",
1469da7d7b9cSGregory Neil Shapiro 			(long) getuid(), (long) geteuid());
1470c2aa98e2SPeter Wemm 	if (tTd(27, 14))
1471c2aa98e2SPeter Wemm 	{
147240266059SGregory Neil Shapiro 		sm_dprintf("ctladdr ");
1473e92d3f3fSGregory Neil Shapiro 		printaddr(sm_debug_file(), ctladdr, false);
1474c2aa98e2SPeter Wemm 	}
1475c2aa98e2SPeter Wemm 
1476c2aa98e2SPeter Wemm 	if (tTd(27, 9))
1477da7d7b9cSGregory Neil Shapiro 		sm_dprintf("include: old uid = %ld/%ld\n",
1478da7d7b9cSGregory Neil Shapiro 			   (long) getuid(), (long) geteuid());
1479c2aa98e2SPeter Wemm 
148042e5d165SGregory Neil Shapiro 	if (forwarding)
148142e5d165SGregory Neil Shapiro 	{
148294c01205SGregory Neil Shapiro 		sfflags |= SFF_MUSTOWN|SFF_ROOTOK;
148342e5d165SGregory Neil Shapiro 		if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail))
148442e5d165SGregory Neil Shapiro 			sfflags |= SFF_NOGWFILES;
148542e5d165SGregory Neil Shapiro 		if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail))
148642e5d165SGregory Neil Shapiro 			sfflags |= SFF_NOWWFILES;
148742e5d165SGregory Neil Shapiro 	}
148842e5d165SGregory Neil Shapiro 	else
148942e5d165SGregory Neil Shapiro 	{
149042e5d165SGregory Neil Shapiro 		if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail))
149142e5d165SGregory Neil Shapiro 			sfflags |= SFF_NOGWFILES;
149242e5d165SGregory Neil Shapiro 		if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail))
149342e5d165SGregory Neil Shapiro 			sfflags |= SFF_NOWWFILES;
149442e5d165SGregory Neil Shapiro 	}
1495c2aa98e2SPeter Wemm 
149606f25ae9SGregory Neil Shapiro 	/*
149706f25ae9SGregory Neil Shapiro 	**  If RunAsUser set, won't be able to run programs as user
149806f25ae9SGregory Neil Shapiro 	**  so mark them as unsafe unless the administrator knows better.
149906f25ae9SGregory Neil Shapiro 	*/
150006f25ae9SGregory Neil Shapiro 
150106f25ae9SGregory Neil Shapiro 	if ((geteuid() != 0 || RunAsUid != 0) &&
150206f25ae9SGregory Neil Shapiro 	    !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail))
150306f25ae9SGregory Neil Shapiro 	{
150406f25ae9SGregory Neil Shapiro 		if (tTd(27, 4))
1505da7d7b9cSGregory Neil Shapiro 			sm_dprintf("include: not safe (euid=%ld, RunAsUid=%ld)\n",
1506da7d7b9cSGregory Neil Shapiro 				   (long) geteuid(), (long) RunAsUid);
150706f25ae9SGregory Neil Shapiro 		ctladdr->q_flags |= QUNSAFEADDR;
150806f25ae9SGregory Neil Shapiro 	}
150906f25ae9SGregory Neil Shapiro 
1510c2aa98e2SPeter Wemm 	ca = getctladdr(ctladdr);
151106f25ae9SGregory Neil Shapiro 	if (ca == NULL ||
151206f25ae9SGregory Neil Shapiro 	    (ca->q_uid == DefUid && ca->q_gid == 0))
1513c2aa98e2SPeter Wemm 	{
1514c2aa98e2SPeter Wemm 		uid = DefUid;
1515c2aa98e2SPeter Wemm 		gid = DefGid;
151606f25ae9SGregory Neil Shapiro 		user = DefUser;
1517c2aa98e2SPeter Wemm 	}
1518c2aa98e2SPeter Wemm 	else
1519c2aa98e2SPeter Wemm 	{
1520c2aa98e2SPeter Wemm 		uid = ca->q_uid;
1521c2aa98e2SPeter Wemm 		gid = ca->q_gid;
152206f25ae9SGregory Neil Shapiro 		user = ca->q_user;
1523c2aa98e2SPeter Wemm 	}
152406f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD != USE_SETUID
1525c2aa98e2SPeter Wemm 	saveduid = geteuid();
1526c2aa98e2SPeter Wemm 	savedgid = getegid();
1527c2aa98e2SPeter Wemm 	if (saveduid == 0)
1528c2aa98e2SPeter Wemm 	{
1529c2aa98e2SPeter Wemm 		if (!DontInitGroups)
1530c2aa98e2SPeter Wemm 		{
153106f25ae9SGregory Neil Shapiro 			if (initgroups(user, gid) == -1)
153206f25ae9SGregory Neil Shapiro 			{
153306f25ae9SGregory Neil Shapiro 				rval = EAGAIN;
1534da7d7b9cSGregory Neil Shapiro 				syserr("include: initgroups(%s, %ld) failed",
1535da7d7b9cSGregory Neil Shapiro 					user, (long) gid);
153606f25ae9SGregory Neil Shapiro 				goto resetuid;
153706f25ae9SGregory Neil Shapiro 			}
1538c2aa98e2SPeter Wemm 		}
1539c2aa98e2SPeter Wemm 		else
1540c2aa98e2SPeter Wemm 		{
1541c2aa98e2SPeter Wemm 			GIDSET_T gidset[1];
1542c2aa98e2SPeter Wemm 
1543c2aa98e2SPeter Wemm 			gidset[0] = gid;
1544c2aa98e2SPeter Wemm 			if (setgroups(1, gidset) == -1)
154506f25ae9SGregory Neil Shapiro 			{
154606f25ae9SGregory Neil Shapiro 				rval = EAGAIN;
1547c2aa98e2SPeter Wemm 				syserr("include: setgroups() failed");
154806f25ae9SGregory Neil Shapiro 				goto resetuid;
154906f25ae9SGregory Neil Shapiro 			}
1550c2aa98e2SPeter Wemm 		}
1551c2aa98e2SPeter Wemm 
1552c2aa98e2SPeter Wemm 		if (gid != 0 && setgid(gid) < -1)
155306f25ae9SGregory Neil Shapiro 		{
155406f25ae9SGregory Neil Shapiro 			rval = EAGAIN;
1555da7d7b9cSGregory Neil Shapiro 			syserr("setgid(%ld) failure", (long) gid);
155606f25ae9SGregory Neil Shapiro 			goto resetuid;
155706f25ae9SGregory Neil Shapiro 		}
1558c2aa98e2SPeter Wemm 		if (uid != 0)
1559c2aa98e2SPeter Wemm 		{
156006f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID
1561c2aa98e2SPeter Wemm 			if (seteuid(uid) < 0)
156206f25ae9SGregory Neil Shapiro 			{
156306f25ae9SGregory Neil Shapiro 				rval = EAGAIN;
1564da7d7b9cSGregory Neil Shapiro 				syserr("seteuid(%ld) failure (real=%ld, eff=%ld)",
1565da7d7b9cSGregory Neil Shapiro 					(long) uid, (long) getuid(), (long) geteuid());
156606f25ae9SGregory Neil Shapiro 				goto resetuid;
156706f25ae9SGregory Neil Shapiro 			}
156806f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */
156906f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID
1570c2aa98e2SPeter Wemm 			if (setreuid(0, uid) < 0)
157106f25ae9SGregory Neil Shapiro 			{
157206f25ae9SGregory Neil Shapiro 				rval = EAGAIN;
1573da7d7b9cSGregory Neil Shapiro 				syserr("setreuid(0, %ld) failure (real=%ld, eff=%ld)",
1574da7d7b9cSGregory Neil Shapiro 					(long) uid, (long) getuid(), (long) geteuid());
157506f25ae9SGregory Neil Shapiro 				goto resetuid;
157606f25ae9SGregory Neil Shapiro 			}
157706f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */
1578c2aa98e2SPeter Wemm 		}
1579c2aa98e2SPeter Wemm 	}
158006f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD != USE_SETUID */
1581c2aa98e2SPeter Wemm 
1582c2aa98e2SPeter Wemm 	if (tTd(27, 9))
1583da7d7b9cSGregory Neil Shapiro 		sm_dprintf("include: new uid = %ld/%ld\n",
1584da7d7b9cSGregory Neil Shapiro 			   (long) getuid(), (long) geteuid());
1585c2aa98e2SPeter Wemm 
1586c2aa98e2SPeter Wemm 	/*
1587c2aa98e2SPeter Wemm 	**  If home directory is remote mounted but server is down,
1588c2aa98e2SPeter Wemm 	**  this can hang or give errors; use a timeout to avoid this
1589c2aa98e2SPeter Wemm 	*/
1590c2aa98e2SPeter Wemm 
1591c2aa98e2SPeter Wemm 	if (setjmp(CtxIncludeTimeout) != 0)
1592c2aa98e2SPeter Wemm 	{
159306f25ae9SGregory Neil Shapiro 		ctladdr->q_state = QS_QUEUEUP;
1594c2aa98e2SPeter Wemm 		errno = 0;
1595c2aa98e2SPeter Wemm 
1596c2aa98e2SPeter Wemm 		/* return pseudo-error code */
1597c2aa98e2SPeter Wemm 		rval = E_SM_OPENTIMEOUT;
1598c2aa98e2SPeter Wemm 		goto resetuid;
1599c2aa98e2SPeter Wemm 	}
1600c2aa98e2SPeter Wemm 	if (TimeOuts.to_fileopen > 0)
160140266059SGregory Neil Shapiro 		ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0);
1602c2aa98e2SPeter Wemm 	else
1603c2aa98e2SPeter Wemm 		ev = NULL;
1604c2aa98e2SPeter Wemm 
1605c2aa98e2SPeter Wemm 	/* check for writable parent directory */
1606c2aa98e2SPeter Wemm 	p = strrchr(fname, '/');
1607c2aa98e2SPeter Wemm 	if (p != NULL)
1608c2aa98e2SPeter Wemm 	{
1609c2aa98e2SPeter Wemm 		int ret;
1610c2aa98e2SPeter Wemm 
1611c2aa98e2SPeter Wemm 		*p = '\0';
161206f25ae9SGregory Neil Shapiro 		ret = safedirpath(fname, uid, gid, user,
161306f25ae9SGregory Neil Shapiro 				  sfflags|SFF_SAFEDIRPATH, 0, 0);
1614c2aa98e2SPeter Wemm 		if (ret == 0)
1615c2aa98e2SPeter Wemm 		{
1616c2aa98e2SPeter Wemm 			/* in safe directory: relax chown & link rules */
161740266059SGregory Neil Shapiro 			safedir = true;
1618c2aa98e2SPeter Wemm 			sfflags |= SFF_NOPATHCHECK;
1619c2aa98e2SPeter Wemm 		}
1620c2aa98e2SPeter Wemm 		else
1621c2aa98e2SPeter Wemm 		{
162206f25ae9SGregory Neil Shapiro 			if (bitnset((forwarding ?
1623c2aa98e2SPeter Wemm 				     DBS_FORWARDFILEINUNSAFEDIRPATH :
1624c2aa98e2SPeter Wemm 				     DBS_INCLUDEFILEINUNSAFEDIRPATH),
1625c2aa98e2SPeter Wemm 				    DontBlameSendmail))
1626c2aa98e2SPeter Wemm 				sfflags |= SFF_NOPATHCHECK;
162706f25ae9SGregory Neil Shapiro 			else if (bitnset((forwarding ?
1628c2aa98e2SPeter Wemm 					  DBS_FORWARDFILEINGROUPWRITABLEDIRPATH :
1629c2aa98e2SPeter Wemm 					  DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH),
1630c2aa98e2SPeter Wemm 					 DontBlameSendmail) &&
1631c2aa98e2SPeter Wemm 				 ret == E_SM_GWDIR)
1632c2aa98e2SPeter Wemm 			{
163306f25ae9SGregory Neil Shapiro 				setbitn(DBS_GROUPWRITABLEDIRPATHSAFE,
163406f25ae9SGregory Neil Shapiro 					DontBlameSendmail);
163506f25ae9SGregory Neil Shapiro 				ret = safedirpath(fname, uid, gid, user,
163606f25ae9SGregory Neil Shapiro 						  sfflags|SFF_SAFEDIRPATH,
163706f25ae9SGregory Neil Shapiro 						  0, 0);
163806f25ae9SGregory Neil Shapiro 				clrbitn(DBS_GROUPWRITABLEDIRPATHSAFE,
163906f25ae9SGregory Neil Shapiro 					DontBlameSendmail);
1640c2aa98e2SPeter Wemm 				if (ret == 0)
1641c2aa98e2SPeter Wemm 					sfflags |= SFF_NOPATHCHECK;
1642c2aa98e2SPeter Wemm 				else
1643c2aa98e2SPeter Wemm 					sfflags |= SFF_SAFEDIRPATH;
1644c2aa98e2SPeter Wemm 			}
1645c2aa98e2SPeter Wemm 			else
1646c2aa98e2SPeter Wemm 				sfflags |= SFF_SAFEDIRPATH;
1647c2aa98e2SPeter Wemm 			if (ret > E_PSEUDOBASE &&
164806f25ae9SGregory Neil Shapiro 			    !bitnset((forwarding ?
1649c2aa98e2SPeter Wemm 				      DBS_FORWARDFILEINUNSAFEDIRPATHSAFE :
1650c2aa98e2SPeter Wemm 				      DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE),
1651c2aa98e2SPeter Wemm 				     DontBlameSendmail))
1652c2aa98e2SPeter Wemm 			{
165340266059SGregory Neil Shapiro 				if (LogLevel > 11)
1654c2aa98e2SPeter Wemm 					sm_syslog(LOG_INFO, e->e_id,
1655c2aa98e2SPeter Wemm 						  "%s: unsafe directory path, marked unsafe",
1656c2aa98e2SPeter Wemm 						  shortenstring(fname, MAXSHORTSTR));
1657c2aa98e2SPeter Wemm 				ctladdr->q_flags |= QUNSAFEADDR;
1658c2aa98e2SPeter Wemm 			}
1659c2aa98e2SPeter Wemm 		}
1660c2aa98e2SPeter Wemm 		*p = '/';
1661c2aa98e2SPeter Wemm 	}
1662c2aa98e2SPeter Wemm 
1663c2aa98e2SPeter Wemm 	/* allow links only in unwritable directories */
1664c2aa98e2SPeter Wemm 	if (!safedir &&
166506f25ae9SGregory Neil Shapiro 	    !bitnset((forwarding ?
1666c2aa98e2SPeter Wemm 		      DBS_LINKEDFORWARDFILEINWRITABLEDIR :
1667c2aa98e2SPeter Wemm 		      DBS_LINKEDINCLUDEFILEINWRITABLEDIR),
1668c2aa98e2SPeter Wemm 		     DontBlameSendmail))
1669c2aa98e2SPeter Wemm 		sfflags |= SFF_NOLINK;
1670c2aa98e2SPeter Wemm 
167106f25ae9SGregory Neil Shapiro 	rval = safefile(fname, uid, gid, user, sfflags, S_IREAD, &st);
1672c2aa98e2SPeter Wemm 	if (rval != 0)
1673c2aa98e2SPeter Wemm 	{
1674c2aa98e2SPeter Wemm 		/* don't use this :include: file */
1675c2aa98e2SPeter Wemm 		if (tTd(27, 4))
1676da7d7b9cSGregory Neil Shapiro 			sm_dprintf("include: not safe (uid=%ld): %s\n",
1677da7d7b9cSGregory Neil Shapiro 				   (long) uid, sm_errstring(rval));
1678c2aa98e2SPeter Wemm 	}
167940266059SGregory Neil Shapiro 	else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname,
168040266059SGregory Neil Shapiro 				  SM_IO_RDONLY, NULL)) == NULL)
1681c2aa98e2SPeter Wemm 	{
1682c2aa98e2SPeter Wemm 		rval = errno;
1683c2aa98e2SPeter Wemm 		if (tTd(27, 4))
168440266059SGregory Neil Shapiro 			sm_dprintf("include: open: %s\n", sm_errstring(rval));
1685c2aa98e2SPeter Wemm 	}
168640266059SGregory Neil Shapiro 	else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st))
1687c2aa98e2SPeter Wemm 	{
1688c2aa98e2SPeter Wemm 		rval = E_SM_FILECHANGE;
1689c2aa98e2SPeter Wemm 		if (tTd(27, 4))
169040266059SGregory Neil Shapiro 			sm_dprintf("include: file changed after open\n");
1691c2aa98e2SPeter Wemm 	}
1692c2aa98e2SPeter Wemm 	if (ev != NULL)
169340266059SGregory Neil Shapiro 		sm_clrevent(ev);
1694c2aa98e2SPeter Wemm 
1695c2aa98e2SPeter Wemm resetuid:
1696c2aa98e2SPeter Wemm 
1697c2aa98e2SPeter Wemm #if HASSETREUID || USESETEUID
1698c2aa98e2SPeter Wemm 	if (saveduid == 0)
1699c2aa98e2SPeter Wemm 	{
1700c2aa98e2SPeter Wemm 		if (uid != 0)
1701c2aa98e2SPeter Wemm 		{
1702c2aa98e2SPeter Wemm # if USESETEUID
1703c2aa98e2SPeter Wemm 			if (seteuid(0) < 0)
1704da7d7b9cSGregory Neil Shapiro 				syserr("!seteuid(0) failure (real=%ld, eff=%ld)",
1705da7d7b9cSGregory Neil Shapiro 				       (long) getuid(), (long) geteuid());
170606f25ae9SGregory Neil Shapiro # else /* USESETEUID */
1707c2aa98e2SPeter Wemm 			if (setreuid(-1, 0) < 0)
1708da7d7b9cSGregory Neil Shapiro 				syserr("!setreuid(-1, 0) failure (real=%ld, eff=%ld)",
1709da7d7b9cSGregory Neil Shapiro 				       (long) getuid(), (long) geteuid());
1710c2aa98e2SPeter Wemm 			if (setreuid(RealUid, 0) < 0)
1711da7d7b9cSGregory Neil Shapiro 				syserr("!setreuid(%ld, 0) failure (real=%ld, eff=%ld)",
1712da7d7b9cSGregory Neil Shapiro 				       (long) RealUid, (long) getuid(),
1713da7d7b9cSGregory Neil Shapiro 				       (long) geteuid());
171406f25ae9SGregory Neil Shapiro # endif /* USESETEUID */
1715c2aa98e2SPeter Wemm 		}
171606f25ae9SGregory Neil Shapiro 		if (setgid(savedgid) < 0)
1717da7d7b9cSGregory Neil Shapiro 			syserr("!setgid(%ld) failure (real=%ld eff=%ld)",
1718da7d7b9cSGregory Neil Shapiro 			       (long) savedgid, (long) getgid(),
1719da7d7b9cSGregory Neil Shapiro 			       (long) getegid());
1720c2aa98e2SPeter Wemm 	}
172106f25ae9SGregory Neil Shapiro #endif /* HASSETREUID || USESETEUID */
1722c2aa98e2SPeter Wemm 
1723c2aa98e2SPeter Wemm 	if (tTd(27, 9))
1724da7d7b9cSGregory Neil Shapiro 		sm_dprintf("include: reset uid = %ld/%ld\n",
1725da7d7b9cSGregory Neil Shapiro 			   (long) getuid(), (long) geteuid());
1726c2aa98e2SPeter Wemm 
1727c2aa98e2SPeter Wemm 	if (rval == E_SM_OPENTIMEOUT)
172806f25ae9SGregory Neil Shapiro 		usrerr("451 4.4.1 open timeout on %s", fname);
1729c2aa98e2SPeter Wemm 
1730c2aa98e2SPeter Wemm 	if (fp == NULL)
1731c2aa98e2SPeter Wemm 		return rval;
1732c2aa98e2SPeter Wemm 
173340266059SGregory Neil Shapiro 	if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0)
1734c2aa98e2SPeter Wemm 	{
1735c2aa98e2SPeter Wemm 		rval = errno;
1736c2aa98e2SPeter Wemm 		syserr("Cannot fstat %s!", fname);
173740266059SGregory Neil Shapiro 		(void) sm_io_close(fp, SM_TIME_DEFAULT);
1738c2aa98e2SPeter Wemm 		return rval;
1739c2aa98e2SPeter Wemm 	}
1740c2aa98e2SPeter Wemm 
1741c2aa98e2SPeter Wemm 	/* if path was writable, check to avoid file giveaway tricks */
174240266059SGregory Neil Shapiro 	safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir);
1743c2aa98e2SPeter Wemm 	if (tTd(27, 6))
174440266059SGregory Neil Shapiro 		sm_dprintf("include: parent of %s is %s, chown is %ssafe\n",
174540266059SGregory Neil Shapiro 			   fname, safedir ? "safe" : "dangerous",
1746c2aa98e2SPeter Wemm 			   safechown ? "" : "un");
1747c2aa98e2SPeter Wemm 
174806f25ae9SGregory Neil Shapiro 	/* if no controlling user or coming from an alias delivery */
174906f25ae9SGregory Neil Shapiro 	if (safechown &&
175006f25ae9SGregory Neil Shapiro 	    (ca == NULL ||
175106f25ae9SGregory Neil Shapiro 	     (ca->q_uid == DefUid && ca->q_gid == 0)))
1752c2aa98e2SPeter Wemm 	{
1753c2aa98e2SPeter Wemm 		ctladdr->q_uid = st.st_uid;
1754c2aa98e2SPeter Wemm 		ctladdr->q_gid = st.st_gid;
1755c2aa98e2SPeter Wemm 		ctladdr->q_flags |= QGOODUID;
1756c2aa98e2SPeter Wemm 	}
1757c2aa98e2SPeter Wemm 	if (ca != NULL && ca->q_uid == st.st_uid)
1758c2aa98e2SPeter Wemm 	{
1759c2aa98e2SPeter Wemm 		/* optimization -- avoid getpwuid if we already have info */
1760c2aa98e2SPeter Wemm 		ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
1761c2aa98e2SPeter Wemm 		ctladdr->q_ruser = ca->q_ruser;
1762c2aa98e2SPeter Wemm 	}
1763c2aa98e2SPeter Wemm 	else if (!forwarding)
1764c2aa98e2SPeter Wemm 	{
1765c2aa98e2SPeter Wemm 		register struct passwd *pw;
1766c2aa98e2SPeter Wemm 
1767c2aa98e2SPeter Wemm 		pw = sm_getpwuid(st.st_uid);
1768c2aa98e2SPeter Wemm 		if (pw == NULL)
176906f25ae9SGregory Neil Shapiro 		{
177006f25ae9SGregory Neil Shapiro 			ctladdr->q_uid = st.st_uid;
1771c2aa98e2SPeter Wemm 			ctladdr->q_flags |= QBOGUSSHELL;
177206f25ae9SGregory Neil Shapiro 		}
1773c2aa98e2SPeter Wemm 		else
1774c2aa98e2SPeter Wemm 		{
1775c2aa98e2SPeter Wemm 			char *sh;
1776c2aa98e2SPeter Wemm 
177740266059SGregory Neil Shapiro 			ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool,
177840266059SGregory Neil Shapiro 							     pw->pw_name);
1779c2aa98e2SPeter Wemm 			if (safechown)
1780c2aa98e2SPeter Wemm 				sh = pw->pw_shell;
1781c2aa98e2SPeter Wemm 			else
1782c2aa98e2SPeter Wemm 				sh = "/SENDMAIL/ANY/SHELL/";
1783c2aa98e2SPeter Wemm 			if (!usershellok(pw->pw_name, sh))
1784c2aa98e2SPeter Wemm 			{
178540266059SGregory Neil Shapiro 				if (LogLevel > 11)
1786c2aa98e2SPeter Wemm 					sm_syslog(LOG_INFO, e->e_id,
1787c2aa98e2SPeter Wemm 						  "%s: user %s has bad shell %s, marked %s",
178840266059SGregory Neil Shapiro 						  shortenstring(fname,
178940266059SGregory Neil Shapiro 								MAXSHORTSTR),
1790c2aa98e2SPeter Wemm 						  pw->pw_name, sh,
1791c2aa98e2SPeter Wemm 						  safechown ? "bogus" : "unsafe");
1792c2aa98e2SPeter Wemm 				if (safechown)
1793c2aa98e2SPeter Wemm 					ctladdr->q_flags |= QBOGUSSHELL;
1794c2aa98e2SPeter Wemm 				else
1795c2aa98e2SPeter Wemm 					ctladdr->q_flags |= QUNSAFEADDR;
1796c2aa98e2SPeter Wemm 			}
1797c2aa98e2SPeter Wemm 		}
1798c2aa98e2SPeter Wemm 	}
1799c2aa98e2SPeter Wemm 
1800c2aa98e2SPeter Wemm 	if (bitset(EF_VRFYONLY, e->e_flags))
1801c2aa98e2SPeter Wemm 	{
1802c2aa98e2SPeter Wemm 		/* don't do any more now */
180306f25ae9SGregory Neil Shapiro 		ctladdr->q_state = QS_VERIFIED;
1804c2aa98e2SPeter Wemm 		e->e_nrcpts++;
180540266059SGregory Neil Shapiro 		(void) sm_io_close(fp, SM_TIME_DEFAULT);
1806c2aa98e2SPeter Wemm 		return rval;
1807c2aa98e2SPeter Wemm 	}
1808c2aa98e2SPeter Wemm 
1809c2aa98e2SPeter Wemm 	/*
1810c2aa98e2SPeter Wemm 	**  Check to see if some bad guy can write this file
1811c2aa98e2SPeter Wemm 	**
1812c2aa98e2SPeter Wemm 	**	Group write checking could be more clever, e.g.,
1813c2aa98e2SPeter Wemm 	**	guessing as to which groups are actually safe ("sys"
1814c2aa98e2SPeter Wemm 	**	may be; "user" probably is not).
1815c2aa98e2SPeter Wemm 	*/
1816c2aa98e2SPeter Wemm 
1817c2aa98e2SPeter Wemm 	mode = S_IWOTH;
181806f25ae9SGregory Neil Shapiro 	if (!bitnset((forwarding ?
1819c2aa98e2SPeter Wemm 		      DBS_GROUPWRITABLEFORWARDFILESAFE :
1820c2aa98e2SPeter Wemm 		      DBS_GROUPWRITABLEINCLUDEFILESAFE),
1821c2aa98e2SPeter Wemm 		     DontBlameSendmail))
1822c2aa98e2SPeter Wemm 		mode |= S_IWGRP;
1823c2aa98e2SPeter Wemm 
1824c2aa98e2SPeter Wemm 	if (bitset(mode, st.st_mode))
1825c2aa98e2SPeter Wemm 	{
1826c2aa98e2SPeter Wemm 		if (tTd(27, 6))
182740266059SGregory Neil Shapiro 			sm_dprintf("include: %s is %s writable, marked unsafe\n",
1828c2aa98e2SPeter Wemm 				   shortenstring(fname, MAXSHORTSTR),
182940266059SGregory Neil Shapiro 				   bitset(S_IWOTH, st.st_mode) ? "world"
183040266059SGregory Neil Shapiro 							       : "group");
183140266059SGregory Neil Shapiro 		if (LogLevel > 11)
1832c2aa98e2SPeter Wemm 			sm_syslog(LOG_INFO, e->e_id,
1833c2aa98e2SPeter Wemm 				  "%s: %s writable %s file, marked unsafe",
1834c2aa98e2SPeter Wemm 				  shortenstring(fname, MAXSHORTSTR),
1835c2aa98e2SPeter Wemm 				  bitset(S_IWOTH, st.st_mode) ? "world" : "group",
1836c2aa98e2SPeter Wemm 				  forwarding ? "forward" : ":include:");
1837c2aa98e2SPeter Wemm 		ctladdr->q_flags |= QUNSAFEADDR;
1838c2aa98e2SPeter Wemm 	}
1839c2aa98e2SPeter Wemm 
1840c2aa98e2SPeter Wemm 	/* read the file -- each line is a comma-separated list. */
1841c2aa98e2SPeter Wemm 	FileName = fname;
1842c2aa98e2SPeter Wemm 	LineNumber = 0;
1843c2aa98e2SPeter Wemm 	ctladdr->q_flags &= ~QSELFREF;
1844c2aa98e2SPeter Wemm 	nincludes = 0;
1845552d4955SGregory Neil Shapiro 	while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0 &&
184640266059SGregory Neil Shapiro 	       !maxreached)
1847c2aa98e2SPeter Wemm 	{
184840266059SGregory Neil Shapiro 		fixcrlf(buf, true);
1849c2aa98e2SPeter Wemm 		LineNumber++;
1850c2aa98e2SPeter Wemm 		if (buf[0] == '#' || buf[0] == '\0')
1851c2aa98e2SPeter Wemm 			continue;
1852c2aa98e2SPeter Wemm 
1853c2aa98e2SPeter Wemm 		/* <sp>#@# introduces a comment anywhere */
1854c2aa98e2SPeter Wemm 		/* for Japanese character sets */
1855c2aa98e2SPeter Wemm 		for (p = buf; (p = strchr(++p, '#')) != NULL; )
1856c2aa98e2SPeter Wemm 		{
1857c2aa98e2SPeter Wemm 			if (p[1] == '@' && p[2] == '#' &&
1858c2aa98e2SPeter Wemm 			    isascii(p[-1]) && isspace(p[-1]) &&
18595b0945b5SGregory Neil Shapiro 			    (p[3] == '\0' || (SM_ISSPACE(p[3]))))
1860c2aa98e2SPeter Wemm 			{
186142e5d165SGregory Neil Shapiro 				--p;
186242e5d165SGregory Neil Shapiro 				while (p > buf && isascii(p[-1]) &&
186342e5d165SGregory Neil Shapiro 				       isspace(p[-1]))
186442e5d165SGregory Neil Shapiro 					--p;
186542e5d165SGregory Neil Shapiro 				p[0] = '\0';
1866c2aa98e2SPeter Wemm 				break;
1867c2aa98e2SPeter Wemm 			}
1868c2aa98e2SPeter Wemm 		}
1869c2aa98e2SPeter Wemm 		if (buf[0] == '\0')
1870c2aa98e2SPeter Wemm 			continue;
1871c2aa98e2SPeter Wemm 
1872c2aa98e2SPeter Wemm 		e->e_to = NULL;
1873c2aa98e2SPeter Wemm 		message("%s to %s",
1874c2aa98e2SPeter Wemm 			forwarding ? "forwarding" : "sending", buf);
187506f25ae9SGregory Neil Shapiro 		if (forwarding && LogLevel > 10)
1876c2aa98e2SPeter Wemm 			sm_syslog(LOG_INFO, e->e_id,
1877c2aa98e2SPeter Wemm 				  "forward %.200s => %s",
1878c2aa98e2SPeter Wemm 				  oldto, shortenstring(buf, MAXSHORTSTR));
1879c2aa98e2SPeter Wemm 
1880c2aa98e2SPeter Wemm 		nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e);
188106f25ae9SGregory Neil Shapiro 
188206f25ae9SGregory Neil Shapiro 		if (forwarding &&
188306f25ae9SGregory Neil Shapiro 		    MaxForwardEntries > 0 &&
188406f25ae9SGregory Neil Shapiro 		    nincludes >= MaxForwardEntries)
188506f25ae9SGregory Neil Shapiro 		{
188606f25ae9SGregory Neil Shapiro 			/* just stop reading and processing further entries */
188740266059SGregory Neil Shapiro #if 0
188840266059SGregory Neil Shapiro 			/* additional: (?) */
188906f25ae9SGregory Neil Shapiro 			ctladdr->q_state = QS_DONTSEND;
189040266059SGregory Neil Shapiro #endif /* 0 */
189140266059SGregory Neil Shapiro 
189240266059SGregory Neil Shapiro 			syserr("Attempt to forward to more than %d addresses (in %s)!",
189306f25ae9SGregory Neil Shapiro 				MaxForwardEntries, fname);
189440266059SGregory Neil Shapiro 			maxreached = true;
189506f25ae9SGregory Neil Shapiro 		}
1896c2aa98e2SPeter Wemm 	}
1897c2aa98e2SPeter Wemm 
189840266059SGregory Neil Shapiro 	if (sm_io_error(fp) && tTd(27, 3))
189940266059SGregory Neil Shapiro 		sm_dprintf("include: read error: %s\n", sm_errstring(errno));
1900c2aa98e2SPeter Wemm 	if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
1901c2aa98e2SPeter Wemm 	{
1902d0cef73dSGregory Neil Shapiro 		if (aliaslevel <= MaxAliasRecursion ||
1903d0cef73dSGregory Neil Shapiro 		    ctladdr->q_state != QS_BADADDR)
1904d0cef73dSGregory Neil Shapiro 		{
1905d0cef73dSGregory Neil Shapiro 			ctladdr->q_state = QS_DONTSEND;
1906c2aa98e2SPeter Wemm 			if (tTd(27, 5))
1907c2aa98e2SPeter Wemm 			{
190840266059SGregory Neil Shapiro 				sm_dprintf("include: QS_DONTSEND ");
1909e92d3f3fSGregory Neil Shapiro 				printaddr(sm_debug_file(), ctladdr, false);
1910c2aa98e2SPeter Wemm 			}
1911d0cef73dSGregory Neil Shapiro 		}
1912c2aa98e2SPeter Wemm 	}
1913c2aa98e2SPeter Wemm 
191440266059SGregory Neil Shapiro 	(void) sm_io_close(fp, SM_TIME_DEFAULT);
1915c2aa98e2SPeter Wemm 	FileName = oldfilename;
1916c2aa98e2SPeter Wemm 	LineNumber = oldlinenumber;
1917c2aa98e2SPeter Wemm 	e->e_to = oldto;
1918c2aa98e2SPeter Wemm 	return rval;
1919c2aa98e2SPeter Wemm }
1920c2aa98e2SPeter Wemm 
1921c2aa98e2SPeter Wemm static void
includetimeout(ignore)1922b6bacd31SGregory Neil Shapiro includetimeout(ignore)
1923b6bacd31SGregory Neil Shapiro 	int ignore;
1924c2aa98e2SPeter Wemm {
19258774250cSGregory Neil Shapiro 	/*
19268774250cSGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
19278774250cSGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
19288774250cSGregory Neil Shapiro 	**	DOING.
19298774250cSGregory Neil Shapiro 	*/
19308774250cSGregory Neil Shapiro 
19318774250cSGregory Neil Shapiro 	errno = ETIMEDOUT;
1932c2aa98e2SPeter Wemm 	longjmp(CtxIncludeTimeout, 1);
1933c2aa98e2SPeter Wemm }
1934d0cef73dSGregory Neil Shapiro 
193540266059SGregory Neil Shapiro /*
1936c2aa98e2SPeter Wemm **  SENDTOARGV -- send to an argument vector.
1937c2aa98e2SPeter Wemm **
1938c2aa98e2SPeter Wemm **	Parameters:
1939c2aa98e2SPeter Wemm **		argv -- argument vector to send to.
1940c2aa98e2SPeter Wemm **		e -- the current envelope.
1941c2aa98e2SPeter Wemm **
1942c2aa98e2SPeter Wemm **	Returns:
1943c2aa98e2SPeter Wemm **		none.
1944c2aa98e2SPeter Wemm **
1945c2aa98e2SPeter Wemm **	Side Effects:
1946c2aa98e2SPeter Wemm **		puts all addresses on the argument vector onto the
1947c2aa98e2SPeter Wemm **			send queue.
1948c2aa98e2SPeter Wemm */
1949c2aa98e2SPeter Wemm 
1950c2aa98e2SPeter Wemm void
sendtoargv(argv,e)1951c2aa98e2SPeter Wemm sendtoargv(argv, e)
1952c2aa98e2SPeter Wemm 	register char **argv;
1953c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1954c2aa98e2SPeter Wemm {
1955c2aa98e2SPeter Wemm 	register char *p;
1956c2aa98e2SPeter Wemm 
19572fb4f839SGregory Neil Shapiro #if USE_EAI
19582fb4f839SGregory Neil Shapiro 	if (!e->e_smtputf8)
19592fb4f839SGregory Neil Shapiro 	{
19602fb4f839SGregory Neil Shapiro 		char **av;
19612fb4f839SGregory Neil Shapiro 
19622fb4f839SGregory Neil Shapiro 		av = argv;
19632fb4f839SGregory Neil Shapiro 		while ((p = *av++) != NULL)
19642fb4f839SGregory Neil Shapiro 		{
19652fb4f839SGregory Neil Shapiro 			if (!addr_is_ascii(p))
19662fb4f839SGregory Neil Shapiro 			{
19672fb4f839SGregory Neil Shapiro 				e->e_smtputf8 = true;
19682fb4f839SGregory Neil Shapiro 				break;
19692fb4f839SGregory Neil Shapiro 			}
19702fb4f839SGregory Neil Shapiro 		}
19712fb4f839SGregory Neil Shapiro 	}
19722fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
19732fb4f839SGregory Neil Shapiro 
1974c2aa98e2SPeter Wemm 	while ((p = *argv++) != NULL)
19752fb4f839SGregory Neil Shapiro 	{
19762fb4f839SGregory Neil Shapiro #if USE_EAI
19772fb4f839SGregory Neil Shapiro 		if (e->e_smtputf8)
19782fb4f839SGregory Neil Shapiro 		{
19792fb4f839SGregory Neil Shapiro 			int len = 0;
19802fb4f839SGregory Neil Shapiro 
1981*d39bd2c1SGregory Neil Shapiro 			if (!SMTP_UTF8 && !asciistr(p))
19822fb4f839SGregory Neil Shapiro 			{
19832fb4f839SGregory Neil Shapiro 				usrerr("non-ASCII recipient address %s requires SMTPUTF8",
19842fb4f839SGregory Neil Shapiro 					p);
19852fb4f839SGregory Neil Shapiro 				finis(false, true, EX_USAGE);
19862fb4f839SGregory Neil Shapiro 			}
19872fb4f839SGregory Neil Shapiro 			p = quote_internal_chars(p, NULL, &len, NULL);
19882fb4f839SGregory Neil Shapiro 		}
19892fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
1990c2aa98e2SPeter Wemm 		(void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
1991c2aa98e2SPeter Wemm 	}
19922fb4f839SGregory Neil Shapiro }
1993d0cef73dSGregory Neil Shapiro 
199440266059SGregory Neil Shapiro /*
1995c2aa98e2SPeter Wemm **  GETCTLADDR -- get controlling address from an address header.
1996c2aa98e2SPeter Wemm **
1997c2aa98e2SPeter Wemm **	If none, get one corresponding to the effective userid.
1998c2aa98e2SPeter Wemm **
1999c2aa98e2SPeter Wemm **	Parameters:
2000c2aa98e2SPeter Wemm **		a -- the address to find the controller of.
2001c2aa98e2SPeter Wemm **
2002c2aa98e2SPeter Wemm **	Returns:
2003c2aa98e2SPeter Wemm **		the controlling address.
2004c2aa98e2SPeter Wemm */
2005c2aa98e2SPeter Wemm 
2006c2aa98e2SPeter Wemm ADDRESS *
getctladdr(a)2007c2aa98e2SPeter Wemm getctladdr(a)
2008c2aa98e2SPeter Wemm 	register ADDRESS *a;
2009c2aa98e2SPeter Wemm {
2010c2aa98e2SPeter Wemm 	while (a != NULL && !bitset(QGOODUID, a->q_flags))
2011c2aa98e2SPeter Wemm 		a = a->q_alias;
201206f25ae9SGregory Neil Shapiro 	return a;
2013c2aa98e2SPeter Wemm }
2014d0cef73dSGregory Neil Shapiro 
201540266059SGregory Neil Shapiro /*
2016c2aa98e2SPeter Wemm **  SELF_REFERENCE -- check to see if an address references itself
2017c2aa98e2SPeter Wemm **
2018c2aa98e2SPeter Wemm **	The check is done through a chain of aliases.  If it is part of
2019c2aa98e2SPeter Wemm **	a loop, break the loop at the "best" address, that is, the one
2020c2aa98e2SPeter Wemm **	that exists as a real user.
2021c2aa98e2SPeter Wemm **
2022c2aa98e2SPeter Wemm **	This is to handle the case of:
2023c2aa98e2SPeter Wemm **		awc:		Andrew.Chang
2024c2aa98e2SPeter Wemm **		Andrew.Chang:	awc@mail.server
2025c2aa98e2SPeter Wemm **	which is a problem only on mail.server.
2026c2aa98e2SPeter Wemm **
2027c2aa98e2SPeter Wemm **	Parameters:
2028c2aa98e2SPeter Wemm **		a -- the address to check.
2029c2aa98e2SPeter Wemm **
2030c2aa98e2SPeter Wemm **	Returns:
2031c2aa98e2SPeter Wemm **		The address that should be retained.
2032c2aa98e2SPeter Wemm */
2033c2aa98e2SPeter Wemm 
203406f25ae9SGregory Neil Shapiro static ADDRESS *
self_reference(a)203506f25ae9SGregory Neil Shapiro self_reference(a)
2036c2aa98e2SPeter Wemm 	ADDRESS *a;
2037c2aa98e2SPeter Wemm {
2038c2aa98e2SPeter Wemm 	ADDRESS *b;		/* top entry in self ref loop */
2039c2aa98e2SPeter Wemm 	ADDRESS *c;		/* entry that point to a real mail box */
2040c2aa98e2SPeter Wemm 
2041c2aa98e2SPeter Wemm 	if (tTd(27, 1))
204240266059SGregory Neil Shapiro 		sm_dprintf("self_reference(%s)\n", a->q_paddr);
2043c2aa98e2SPeter Wemm 
2044c2aa98e2SPeter Wemm 	for (b = a->q_alias; b != NULL; b = b->q_alias)
2045c2aa98e2SPeter Wemm 	{
2046c2aa98e2SPeter Wemm 		if (sameaddr(a, b))
2047c2aa98e2SPeter Wemm 			break;
2048c2aa98e2SPeter Wemm 	}
2049c2aa98e2SPeter Wemm 
2050c2aa98e2SPeter Wemm 	if (b == NULL)
2051c2aa98e2SPeter Wemm 	{
2052c2aa98e2SPeter Wemm 		if (tTd(27, 1))
205340266059SGregory Neil Shapiro 			sm_dprintf("\t... no self ref\n");
2054c2aa98e2SPeter Wemm 		return NULL;
2055c2aa98e2SPeter Wemm 	}
2056c2aa98e2SPeter Wemm 
2057c2aa98e2SPeter Wemm 	/*
2058c2aa98e2SPeter Wemm 	**  Pick the first address that resolved to a real mail box
205940266059SGregory Neil Shapiro 	**  i.e has a mbdb entry.  The returned value will be marked
2060c2aa98e2SPeter Wemm 	**  QSELFREF in recipient(), which in turn will disable alias()
206106f25ae9SGregory Neil Shapiro 	**  from marking it as QS_IS_DEAD(), which mean it will be used
2062c2aa98e2SPeter Wemm 	**  as a deliverable address.
2063c2aa98e2SPeter Wemm 	**
2064c2aa98e2SPeter Wemm 	**  The 2 key thing to note here are:
2065c2aa98e2SPeter Wemm 	**	1) we are in a recursive call sequence:
206640266059SGregory Neil Shapiro 	**		alias->sendtolist->recipient->alias
2067c2aa98e2SPeter Wemm 	**	2) normally, when we return back to alias(), the address
206806f25ae9SGregory Neil Shapiro 	**	   will be marked QS_EXPANDED, since alias() assumes the
2069c2aa98e2SPeter Wemm 	**	   expanded form will be used instead of the current address.
2070c2aa98e2SPeter Wemm 	**	   This behaviour is turned off if the address is marked
207140266059SGregory Neil Shapiro 	**	   QSELFREF.  We set QSELFREF when we return to recipient().
2072c2aa98e2SPeter Wemm 	*/
2073c2aa98e2SPeter Wemm 
2074c2aa98e2SPeter Wemm 	c = a;
2075c2aa98e2SPeter Wemm 	while (c != NULL)
2076c2aa98e2SPeter Wemm 	{
20772e43090eSPeter Wemm 		if (tTd(27, 10))
207840266059SGregory Neil Shapiro 			sm_dprintf("  %s", c->q_user);
2079c2aa98e2SPeter Wemm 		if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
2080c2aa98e2SPeter Wemm 		{
208140266059SGregory Neil Shapiro 			SM_MBDB_T user;
208240266059SGregory Neil Shapiro 
2083c2aa98e2SPeter Wemm 			if (tTd(27, 2))
208440266059SGregory Neil Shapiro 				sm_dprintf("\t... getpwnam(%s)... ", c->q_user);
208540266059SGregory Neil Shapiro 			if (sm_mbdb_lookup(c->q_user, &user) == EX_OK)
2086c2aa98e2SPeter Wemm 			{
2087c2aa98e2SPeter Wemm 				if (tTd(27, 2))
208840266059SGregory Neil Shapiro 					sm_dprintf("found\n");
2089c2aa98e2SPeter Wemm 
2090c2aa98e2SPeter Wemm 				/* ought to cache results here */
2091c2aa98e2SPeter Wemm 				if (sameaddr(b, c))
2092c2aa98e2SPeter Wemm 					return b;
2093c2aa98e2SPeter Wemm 				else
2094c2aa98e2SPeter Wemm 					return c;
2095c2aa98e2SPeter Wemm 			}
2096c2aa98e2SPeter Wemm 			if (tTd(27, 2))
209740266059SGregory Neil Shapiro 				sm_dprintf("failed\n");
2098c2aa98e2SPeter Wemm 		}
20992e43090eSPeter Wemm 		else
21002e43090eSPeter Wemm 		{
21012e43090eSPeter Wemm 			/* if local delivery, compare usernames */
21022e43090eSPeter Wemm 			if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) &&
21032e43090eSPeter Wemm 			    b->q_mailer == c->q_mailer)
21042e43090eSPeter Wemm 			{
21052e43090eSPeter Wemm 				if (tTd(27, 2))
210640266059SGregory Neil Shapiro 					sm_dprintf("\t... local match (%s)\n",
210706f25ae9SGregory Neil Shapiro 						c->q_user);
21082e43090eSPeter Wemm 				if (sameaddr(b, c))
21092e43090eSPeter Wemm 					return b;
21102e43090eSPeter Wemm 				else
21112e43090eSPeter Wemm 					return c;
21122e43090eSPeter Wemm 			}
21132e43090eSPeter Wemm 		}
21142e43090eSPeter Wemm 		if (tTd(27, 10))
211540266059SGregory Neil Shapiro 			sm_dprintf("\n");
2116c2aa98e2SPeter Wemm 		c = c->q_alias;
2117c2aa98e2SPeter Wemm 	}
2118c2aa98e2SPeter Wemm 
2119c2aa98e2SPeter Wemm 	if (tTd(27, 1))
212040266059SGregory Neil Shapiro 		sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
2121c2aa98e2SPeter Wemm 
2122c2aa98e2SPeter Wemm 	return NULL;
2123c2aa98e2SPeter Wemm }
2124