122710Sdist /*
268839Seric  * Copyright (c) 1983, 1995 Eric P. Allman
363589Sbostic  * Copyright (c) 1988, 1993
463589Sbostic  *	The Regents of the University of California.  All rights reserved.
533731Sbostic  *
642829Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822710Sdist 
922710Sdist #ifndef lint
10*69561Seric static char sccsid[] = "@(#)recipient.c	8.85 (Berkeley) 05/19/95";
1133731Sbostic #endif /* not lint */
1222710Sdist 
1358332Seric # include "sendmail.h"
144174Seric 
154174Seric /*
169622Seric **  SENDTOLIST -- Designate a send list.
174174Seric **
184174Seric **	The parameter is a comma-separated list of people to send to.
194174Seric **	This routine arranges to send to all of them.
204174Seric **
214174Seric **	Parameters:
224174Seric **		list -- the send list.
234399Seric **		ctladdr -- the address template for the person to
244399Seric **			send to -- effective uid/gid are important.
255006Seric **			This is typically the alias that caused this
265006Seric **			expansion.
275006Seric **		sendq -- a pointer to the head of a queue to put
285006Seric **			these people into.
2968481Seric **		aliaslevel -- the current alias nesting depth -- to
3068481Seric **			diagnose loops.
3158247Seric **		e -- the envelope in which to add these recipients.
324174Seric **
334174Seric **	Returns:
3458082Seric **		The number of addresses actually on the list.
354174Seric **
364174Seric **	Side Effects:
374174Seric **		none.
384174Seric */
394174Seric 
4068481Seric #define MAXRCRSN	10	/* maximum levels of alias recursion */
414174Seric 
4268481Seric /* q_flags bits inherited from ctladdr */
4368595Seric #define QINHERITEDBITS	(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY)
4468481Seric 
4568481Seric int
4668481Seric sendtolist(list, ctladdr, sendq, aliaslevel, e)
474174Seric 	char *list;
484399Seric 	ADDRESS *ctladdr;
495198Seric 	ADDRESS **sendq;
5068481Seric 	int aliaslevel;
5155012Seric 	register ENVELOPE *e;
524174Seric {
534174Seric 	register char *p;
548223Seric 	register ADDRESS *al;	/* list of addresses to send to */
554423Seric 	bool firstone;		/* set on first address sent */
5611446Seric 	char delimiter;		/* the address delimiter */
5758082Seric 	int naddrs;
5868392Seric 	int i;
5963847Seric 	char *oldto = e->e_to;
6068392Seric 	char *bufp;
6168271Seric 	char buf[MAXNAME + 1];
624174Seric 
6364131Seric 	if (list == NULL)
6464131Seric 	{
6564131Seric 		syserr("sendtolist: null list");
6664131Seric 		return 0;
6764131Seric 	}
6864131Seric 
697676Seric 	if (tTd(25, 1))
704444Seric 	{
714444Seric 		printf("sendto: %s\n   ctladdr=", list);
724444Seric 		printaddr(ctladdr, FALSE);
734444Seric 	}
744324Seric 
758223Seric 	/* heuristic to determine old versus new style addresses */
768230Seric 	if (ctladdr == NULL &&
7756795Seric 	    (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
7856795Seric 	     strchr(list, '<') != NULL || strchr(list, '(') != NULL))
7955012Seric 		e->e_flags &= ~EF_OLDSTYLE;
8011446Seric 	delimiter = ' ';
8155012Seric 	if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL)
8211446Seric 		delimiter = ',';
838223Seric 
844423Seric 	firstone = TRUE;
854324Seric 	al = NULL;
8658082Seric 	naddrs = 0;
878223Seric 
8868392Seric 	/* make sure we have enough space to copy the string */
8968392Seric 	i = strlen(list) + 1;
9068392Seric 	if (i <= sizeof buf)
9168271Seric 		bufp = buf;
9268392Seric 	else
9368392Seric 		bufp = xalloc(i);
9468478Seric 	strcpy(bufp, denlstring(list, FALSE, TRUE));
9568271Seric 
9668271Seric 	for (p = bufp; *p != '\0'; )
9768271Seric 	{
9858333Seric 		auto char *delimptr;
998081Seric 		register ADDRESS *a;
1004319Seric 
1018081Seric 		/* parse the address */
10258050Seric 		while ((isascii(*p) && isspace(*p)) || *p == ',')
1034174Seric 			p++;
10464284Seric 		a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e);
10558333Seric 		p = delimptr;
1069297Seric 		if (a == NULL)
1074174Seric 			continue;
1084324Seric 		a->q_next = al;
1094399Seric 		a->q_alias = ctladdr;
1104444Seric 
11168481Seric 		/* arrange to inherit attributes from parent */
11268481Seric 		if (ctladdr != NULL)
11368481Seric 		{
11469544Seric 			ADDRESS *b;
11569544Seric 			extern ADDRESS *self_reference();
11669544Seric 
11768481Seric 			/* self reference test */
11868481Seric 			if (sameaddr(ctladdr, a))
119*69561Seric 			{
120*69561Seric 				if (tTd(27, 5))
121*69561Seric 				{
122*69561Seric 					printf("sendtolist: QSELFREF ");
123*69561Seric 					printaddr(ctladdr, FALSE);
124*69561Seric 				}
12568481Seric 				ctladdr->q_flags |= QSELFREF;
126*69561Seric 			}
12768481Seric 
12869544Seric 			/* check for address loops */
12969544Seric 			b = self_reference(a, e);
13069544Seric 			if (b != NULL)
13169544Seric 			{
13269544Seric 				b->q_flags |= QSELFREF;
133*69561Seric 				if (tTd(27, 5))
134*69561Seric 				{
135*69561Seric 					printf("sendtolist: QSELFREF ");
136*69561Seric 					printaddr(b, FALSE);
137*69561Seric 				}
13869544Seric 				if (a != b)
13969544Seric 				{
140*69561Seric 					if (tTd(27, 5))
141*69561Seric 					{
142*69561Seric 						printf("sendtolist: QDONTSEND ");
143*69561Seric 						printaddr(a, FALSE);
144*69561Seric 					}
14569544Seric 					a->q_flags |= QDONTSEND;
14669544Seric 					continue;
14769544Seric 				}
14869544Seric 			}
14969544Seric 
15068481Seric 			/* full name */
15168481Seric 			if (a->q_fullname == NULL)
15268481Seric 				a->q_fullname = ctladdr->q_fullname;
15368481Seric 
15468481Seric 			/* various flag bits */
15568481Seric 			a->q_flags &= ~QINHERITEDBITS;
15668481Seric 			a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
15768481Seric 
15868481Seric 			/* original recipient information */
15968481Seric 			a->q_orcpt = ctladdr->q_orcpt;
16068481Seric 		}
16168481Seric 
16257731Seric 		al = a;
1634423Seric 		firstone = FALSE;
1644324Seric 	}
1654324Seric 
1664324Seric 	/* arrange to send to everyone on the local send list */
1674324Seric 	while (al != NULL)
1684324Seric 	{
1694324Seric 		register ADDRESS *a = al;
1704324Seric 
1714324Seric 		al = a->q_next;
17268481Seric 		a = recipient(a, sendq, aliaslevel, e);
17358082Seric 		naddrs++;
1744174Seric 	}
1754324Seric 
17663847Seric 	e->e_to = oldto;
17768392Seric 	if (bufp != buf)
17868392Seric 		free(bufp);
17958082Seric 	return (naddrs);
1804174Seric }
1814174Seric /*
1824174Seric **  RECIPIENT -- Designate a message recipient
1834174Seric **
1844174Seric **	Saves the named person for future mailing.
1854174Seric **
1864174Seric **	Parameters:
1874174Seric **		a -- the (preparsed) address header for the recipient.
1885006Seric **		sendq -- a pointer to the head of a queue to put the
1895006Seric **			recipient in.  Duplicate supression is done
1905006Seric **			in this queue.
19168481Seric **		aliaslevel -- the current alias nesting depth.
19257731Seric **		e -- the current envelope.
1934174Seric **
1944174Seric **	Returns:
19512613Seric **		The actual address in the queue.  This will be "a" if
19612613Seric **		the address is not a duplicate, else the original address.
1974174Seric **
1984174Seric **	Side Effects:
1994174Seric **		none.
2004174Seric */
2014174Seric 
20212613Seric ADDRESS *
20368481Seric recipient(a, sendq, aliaslevel, e)
2044174Seric 	register ADDRESS *a;
2055006Seric 	register ADDRESS **sendq;
20668481Seric 	int aliaslevel;
20755012Seric 	register ENVELOPE *e;
2084174Seric {
2094174Seric 	register ADDRESS *q;
2104319Seric 	ADDRESS **pq;
2114174Seric 	register struct mailer *m;
2129210Seric 	register char *p;
2139210Seric 	bool quoted = FALSE;		/* set if the addr has a quote bit */
21453735Seric 	int findusercount = 0;
21568603Seric 	bool initialdontsend = bitset(QDONTSEND, a->q_flags);
21668481Seric 	int i;
21768481Seric 	char *buf;
21868528Seric 	char buf0[MAXNAME + 1];		/* unquoted image of the user name */
21958247Seric 	extern int safefile();
2204174Seric 
22155012Seric 	e->e_to = a->q_paddr;
2224600Seric 	m = a->q_mailer;
2234174Seric 	errno = 0;
22468603Seric 	if (aliaslevel == 0)
22568603Seric 		a->q_flags |= QPRIMARY;
2267676Seric 	if (tTd(26, 1))
2274444Seric 	{
22868603Seric 		printf("\nrecipient (%d): ", aliaslevel);
2294444Seric 		printaddr(a, FALSE);
2304444Seric 	}
2314174Seric 
23264146Seric 	/* if this is primary, add it to the original recipient list */
23364146Seric 	if (a->q_alias == NULL)
23464146Seric 	{
23564146Seric 		if (e->e_origrcpt == NULL)
23664146Seric 			e->e_origrcpt = a->q_paddr;
23764146Seric 		else if (e->e_origrcpt != a->q_paddr)
23864146Seric 			e->e_origrcpt = "";
23964146Seric 	}
24064146Seric 
2414174Seric 	/* break aliasing loops */
24268481Seric 	if (aliaslevel > MAXRCRSN)
2434174Seric 	{
24468857Seric 		a->q_status = "5.4.6";
24568481Seric 		usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max",
24668481Seric 			aliaslevel, MAXRCRSN);
24712613Seric 		return (a);
2484174Seric 	}
2494174Seric 
2504174Seric 	/*
2514627Seric 	**  Finish setting up address structure.
2524174Seric 	*/
2534174Seric 
25416160Seric 	/* get unquoted user for file, program or user.name check */
25568481Seric 	i = strlen(a->q_user);
25668528Seric 	if (i >= sizeof buf0)
25768481Seric 		buf = xalloc(i + 1);
25868481Seric 	else
25968481Seric 		buf = buf0;
2609210Seric 	(void) strcpy(buf, a->q_user);
2619210Seric 	for (p = buf; *p != '\0' && !quoted; p++)
2629210Seric 	{
26354993Seric 		if (*p == '\\')
2649210Seric 			quoted = TRUE;
2659210Seric 	}
26654983Seric 	stripquotes(buf);
2679210Seric 
26857402Seric 	/* check for direct mailing to restricted mailers */
26965496Seric 	if (m == ProgMailer)
2704174Seric 	{
27165496Seric 		if (a->q_alias == NULL)
27265496Seric 		{
27365496Seric 			a->q_flags |= QBADADDR;
27468857Seric 			a->q_status = "5.7.1";
27565496Seric 			usrerr("550 Cannot mail directly to programs");
27665496Seric 		}
27765496Seric 		else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
27865496Seric 		{
27965496Seric 			a->q_flags |= QBADADDR;
28068857Seric 			a->q_status = "5.7.1";
28165496Seric 			usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs",
28265496Seric 				a->q_alias->q_ruser, MyHostName);
28365496Seric 		}
28465496Seric 		else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
28565496Seric 		{
28665496Seric 			a->q_flags |= QBADADDR;
28768857Seric 			a->q_status = "5.7.1";
28865496Seric 			usrerr("550 Address %s is unsafe for mailing to programs",
28965496Seric 				a->q_alias->q_paddr);
29065496Seric 		}
2914174Seric 	}
2924174Seric 
2934174Seric 	/*
2944419Seric 	**  Look up this person in the recipient list.
2954419Seric 	**	If they are there already, return, otherwise continue.
2964419Seric 	**	If the list is empty, just add it.  Notice the cute
2974419Seric 	**	hack to make from addresses suppress things correctly:
2984419Seric 	**	the QDONTSEND bit will be set in the send list.
2994419Seric 	**	[Please note: the emphasis is on "hack."]
3004174Seric 	*/
3014174Seric 
3025006Seric 	for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
3034174Seric 	{
30458294Seric 		if (sameaddr(q, a))
3054174Seric 		{
3067676Seric 			if (tTd(26, 1))
3074444Seric 			{
3084444Seric 				printf("%s in sendq: ", a->q_paddr);
3094444Seric 				printaddr(q, FALSE);
3104444Seric 			}
31165593Seric 			if (!bitset(QPRIMARY, q->q_flags))
31258065Seric 			{
31365593Seric 				if (!bitset(QDONTSEND, a->q_flags))
31458151Seric 					message("duplicate suppressed");
31565593Seric 				q->q_flags |= a->q_flags;
31665593Seric 			}
31765593Seric 			else if (bitset(QSELFREF, q->q_flags))
31865579Seric 				q->q_flags |= a->q_flags & ~QDONTSEND;
31963847Seric 			a = q;
32068481Seric 			goto done;
3214174Seric 		}
3224319Seric 	}
3234174Seric 
3244319Seric 	/* add address on list */
32558884Seric 	*pq = a;
32658884Seric 	a->q_next = NULL;
3274174Seric 
3284174Seric 	/*
32957402Seric 	**  Alias the name and handle special mailer types.
3304174Seric 	*/
3314174Seric 
33253735Seric   trylocaluser:
33355354Seric 	if (tTd(29, 7))
33455354Seric 		printf("at trylocaluser %s\n", a->q_user);
33555354Seric 
33658680Seric 	if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
33763847Seric 		goto testselfdestruct;
33857402Seric 
33957402Seric 	if (m == InclMailer)
3404174Seric 	{
34157402Seric 		a->q_flags |= QDONTSEND;
34264761Seric 		if (a->q_alias == NULL)
3434174Seric 		{
34458680Seric 			a->q_flags |= QBADADDR;
34568857Seric 			a->q_status = "5.7.1";
34658151Seric 			usrerr("550 Cannot mail directly to :include:s");
3474174Seric 		}
3484174Seric 		else
34950556Seric 		{
35059563Seric 			int ret;
35158247Seric 
35258151Seric 			message("including file %s", a->q_user);
35368481Seric 			ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e);
35459563Seric 			if (transienterror(ret))
35559563Seric 			{
35659563Seric #ifdef LOG
35759563Seric 				if (LogLevel > 2)
35866239Seric 					syslog(LOG_ERR, "%s: include %s: transient error: %s",
35966284Seric 						e->e_id == NULL ? "NOQUEUE" : e->e_id,
36066284Seric 						a->q_user, errstring(ret));
36159563Seric #endif
36263853Seric 				a->q_flags |= QQUEUEUP;
36365215Seric 				a->q_flags &= ~QDONTSEND;
36459563Seric 				usrerr("451 Cannot open %s: %s",
36559563Seric 					a->q_user, errstring(ret));
36659563Seric 			}
36759563Seric 			else if (ret != 0)
36859563Seric 			{
36963938Seric 				a->q_flags |= QBADADDR;
37068857Seric 				a->q_status = "5.2.4";
37159563Seric 				usrerr("550 Cannot open %s: %s",
37259563Seric 					a->q_user, errstring(ret));
37359563Seric 			}
37450556Seric 		}
3754174Seric 	}
37657642Seric 	else if (m == FileMailer)
3774174Seric 	{
3784329Seric 		extern bool writable();
3794174Seric 
38051317Seric 		/* check if writable or creatable */
38164761Seric 		if (a->q_alias == NULL)
3824174Seric 		{
38358680Seric 			a->q_flags |= QBADADDR;
38468857Seric 			a->q_status = "5.7.1";
38558151Seric 			usrerr("550 Cannot mail directly to files");
3864174Seric 		}
38765496Seric 		else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
38865496Seric 		{
38965496Seric 			a->q_flags |= QBADADDR;
39068857Seric 			a->q_status = "5.7.1";
39165496Seric 			usrerr("550 User %s@%s doesn't have a valid shell for mailing to files",
39265496Seric 				a->q_alias->q_ruser, MyHostName);
39365496Seric 		}
39465496Seric 		else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
39565496Seric 		{
39665496Seric 			a->q_flags |= QBADADDR;
39768857Seric 			a->q_status = "5.7.1";
39865496Seric 			usrerr("550 Address %s is unsafe for mailing to files",
39965496Seric 				a->q_alias->q_paddr);
40065496Seric 		}
40168494Seric 		else if (!writable(buf, getctladdr(a), SFF_CREAT))
40251317Seric 		{
40358680Seric 			a->q_flags |= QBADADDR;
40468481Seric 			giveresponse(EX_CANTCREAT, m, NULL, a->q_alias,
40568481Seric 				     (time_t) 0, e);
40651317Seric 		}
40751317Seric 	}
40851317Seric 
40957402Seric 	/* try aliasing */
41068481Seric 	if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags))
41168481Seric 		alias(a, sendq, aliaslevel, e);
41257402Seric 
41357402Seric # ifdef USERDB
41457402Seric 	/* if not aliased, look it up in the user database */
41568481Seric 	if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) &&
41668481Seric 	    bitnset(M_CHECKUDB, m->m_flags))
41757402Seric 	{
41857402Seric 		extern int udbexpand();
41957402Seric 
42068481Seric 		if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL)
42157402Seric 		{
42263853Seric 			a->q_flags |= QQUEUEUP;
42357402Seric 			if (e->e_message == NULL)
42457402Seric 				e->e_message = newstr("Deferred: user database error");
42557402Seric # ifdef LOG
42658020Seric 			if (LogLevel > 8)
42759623Seric 				syslog(LOG_INFO, "%s: deferred: udbexpand: %s",
42866284Seric 					e->e_id == NULL ? "NOQUEUE" : e->e_id,
42966284Seric 					errstring(errno));
43057402Seric # endif
43159615Seric 			message("queued (user database error): %s",
43259615Seric 				errstring(errno));
43357642Seric 			e->e_nrcpts++;
43463847Seric 			goto testselfdestruct;
43557402Seric 		}
43657402Seric 	}
43757402Seric # endif
43857402Seric 
43951317Seric 	/*
44051317Seric 	**  If we have a level two config file, then pass the name through
44151317Seric 	**  Ruleset 5 before sending it off.  Ruleset 5 has the right
44251317Seric 	**  to send rewrite it to another mailer.  This gives us a hook
44351317Seric 	**  after local aliasing has been done.
44451317Seric 	*/
44551317Seric 
44651317Seric 	if (tTd(29, 5))
44751317Seric 	{
44851317Seric 		printf("recipient: testing local?  cl=%d, rr5=%x\n\t",
44951317Seric 			ConfigLevel, RewriteRules[5]);
45051317Seric 		printaddr(a, FALSE);
45151317Seric 	}
45268481Seric 	if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
45368481Seric 	    ConfigLevel >= 2 && RewriteRules[5] != NULL &&
45468481Seric 	    bitnset(M_TRYRULESET5, m->m_flags))
45551317Seric 	{
45668603Seric 		maplocaluser(a, sendq, aliaslevel + 1, e);
45751317Seric 	}
45851317Seric 
45951317Seric 	/*
46051317Seric 	**  If it didn't get rewritten to another mailer, go ahead
46151317Seric 	**  and deliver it.
46251317Seric 	*/
46351317Seric 
46468481Seric 	if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
46568481Seric 	    bitnset(M_HASPWENT, m->m_flags))
46651317Seric 	{
46755354Seric 		auto bool fuzzy;
46851317Seric 		register struct passwd *pw;
46951317Seric 		extern struct passwd *finduser();
47051317Seric 
47151317Seric 		/* warning -- finduser may trash buf */
47255354Seric 		pw = finduser(buf, &fuzzy);
47351317Seric 		if (pw == NULL)
47451317Seric 		{
47558680Seric 			a->q_flags |= QBADADDR;
47668857Seric 			a->q_status = "5.1.1";
47768481Seric 			giveresponse(EX_NOUSER, m, NULL, a->q_alias,
47868481Seric 				     (time_t) 0, e);
47951317Seric 		}
4804174Seric 		else
4814174Seric 		{
48268528Seric 			char nbuf[MAXNAME + 1];
4834373Seric 
48455354Seric 			if (fuzzy)
4854174Seric 			{
48653735Seric 				/* name was a fuzzy match */
48751317Seric 				a->q_user = newstr(pw->pw_name);
48853735Seric 				if (findusercount++ > 3)
48953735Seric 				{
49058680Seric 					a->q_flags |= QBADADDR;
49168857Seric 					a->q_status = "5.4.6";
49258151Seric 					usrerr("554 aliasing/forwarding loop for %s broken",
49353735Seric 						pw->pw_name);
49468481Seric 					goto done;
49553735Seric 				}
49653735Seric 
49753735Seric 				/* see if it aliases */
49851317Seric 				(void) strcpy(buf, pw->pw_name);
49953735Seric 				goto trylocaluser;
5004174Seric 			}
50165822Seric 			if (strcmp(pw->pw_dir, "/") == 0)
50265822Seric 				a->q_home = "";
50365822Seric 			else
50465822Seric 				a->q_home = newstr(pw->pw_dir);
50551317Seric 			a->q_uid = pw->pw_uid;
50651317Seric 			a->q_gid = pw->pw_gid;
50759083Seric 			a->q_ruser = newstr(pw->pw_name);
50851317Seric 			a->q_flags |= QGOODUID;
50951317Seric 			buildfname(pw->pw_gecos, pw->pw_name, nbuf);
51051317Seric 			if (nbuf[0] != '\0')
51151317Seric 				a->q_fullname = newstr(nbuf);
51265211Seric 			if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' &&
51365211Seric 			    !usershellok(pw->pw_shell))
51465206Seric 			{
51565211Seric 				a->q_flags |= QBOGUSSHELL;
51665206Seric 			}
51751317Seric 			if (!quoted)
51868481Seric 				forward(a, sendq, aliaslevel, e);
5194174Seric 		}
5204174Seric 	}
52157642Seric 	if (!bitset(QDONTSEND, a->q_flags))
52257642Seric 		e->e_nrcpts++;
52363847Seric 
52463847Seric   testselfdestruct:
52568603Seric 	a->q_flags |= QTHISPASS;
52663978Seric 	if (tTd(26, 8))
52763847Seric 	{
52863978Seric 		printf("testselfdestruct: ");
52968603Seric 		printaddr(a, FALSE);
53068603Seric 		if (tTd(26, 10))
53168603Seric 		{
53268603Seric 			printf("SENDQ:\n");
53368603Seric 			printaddr(*sendq, TRUE);
53468603Seric 			printf("----\n");
53568603Seric 		}
53663978Seric 	}
53763978Seric 	if (a->q_alias == NULL && a != &e->e_from &&
53863978Seric 	    bitset(QDONTSEND, a->q_flags))
53963978Seric 	{
54068603Seric 		for (q = *sendq; q != NULL; q = q->q_next)
54168603Seric 		{
54268603Seric 			if (!bitset(QDONTSEND|QBADADDR, q->q_flags) &&
54368603Seric 			    bitset(QTHISPASS, q->q_flags))
54468603Seric 				break;
54568603Seric 		}
54663978Seric 		if (q == NULL)
54763847Seric 		{
54863847Seric 			a->q_flags |= QBADADDR;
54968858Seric 			a->q_status = "5.4.6";
55063847Seric 			usrerr("554 aliasing/forwarding loop broken");
55163847Seric 		}
55263847Seric 	}
55368481Seric 
55468481Seric   done:
55568603Seric 	a->q_flags |= QTHISPASS;
55668481Seric 	if (buf != buf0)
55768481Seric 		free(buf);
55868603Seric 
55968603Seric 	/*
56068603Seric 	**  If we are at the top level, check to see if this has
56168603Seric 	**  expanded to exactly one address.  If so, it can inherit
56268603Seric 	**  the primaryness of the address.
56368603Seric 	**
56468603Seric 	**  While we're at it, clear the QTHISPASS bits.
56568603Seric 	*/
56668603Seric 
56768603Seric 	if (aliaslevel == 0)
56868603Seric 	{
56968603Seric 		int nrcpts = 0;
57068603Seric 		ADDRESS *only;
57168603Seric 
57268603Seric 		for (q = *sendq; q != NULL; q = q->q_next)
57368603Seric 		{
57468603Seric 			if (bitset(QTHISPASS, q->q_flags) &&
57568603Seric 			    !bitset(QDONTSEND|QBADADDR, q->q_flags))
57668603Seric 			{
57768603Seric 				nrcpts++;
57868603Seric 				only = q;
57968603Seric 			}
58068603Seric 			q->q_flags &= ~QTHISPASS;
58168603Seric 		}
58268603Seric 		if (nrcpts == 1)
58368603Seric 		{
58468867Seric 			/* check to see if this actually got a new owner */
58568867Seric 			q = only;
58668867Seric 			while ((q = q->q_alias) != NULL)
58768867Seric 			{
58868867Seric 				if (q->q_owner != NULL)
58968867Seric 					break;
59068867Seric 			}
59168867Seric 			if (q == NULL)
59268867Seric 				only->q_flags |= QPRIMARY;
59368867Seric 		}
59468867Seric 		else if (!initialdontsend && nrcpts > 0)
59568867Seric 		{
59668603Seric 			/* arrange for return receipt */
59768603Seric 			e->e_flags |= EF_SENDRECEIPT;
59868867Seric 			a->q_flags |= QEXPANDED;
59968603Seric 			if (e->e_xfp != NULL)
60068603Seric 				fprintf(e->e_xfp,
60168603Seric 					"%s... expanded to multiple addresses\n",
60268603Seric 					a->q_paddr);
60368603Seric 		}
60468603Seric 	}
60568603Seric 
60612613Seric 	return (a);
6074174Seric }
6084174Seric /*
6094373Seric **  FINDUSER -- find the password entry for a user.
6104373Seric **
6114373Seric **	This looks a lot like getpwnam, except that it may want to
6124373Seric **	do some fancier pattern matching in /etc/passwd.
6134373Seric **
6149379Seric **	This routine contains most of the time of many sendmail runs.
6159379Seric **	It deserves to be optimized.
6169379Seric **
6174373Seric **	Parameters:
6184373Seric **		name -- the name to match against.
61955354Seric **		fuzzyp -- an outarg that is set to TRUE if this entry
62055354Seric **			was found using the fuzzy matching algorithm;
62155354Seric **			set to FALSE otherwise.
6224373Seric **
6234373Seric **	Returns:
6244373Seric **		A pointer to a pw struct.
6254373Seric **		NULL if name is unknown or ambiguous.
6264373Seric **
6274373Seric **	Side Effects:
6284407Seric **		may modify name.
6294373Seric */
6304373Seric 
6314373Seric struct passwd *
63255354Seric finduser(name, fuzzyp)
6334373Seric 	char *name;
63455354Seric 	bool *fuzzyp;
6354373Seric {
6364376Seric 	register struct passwd *pw;
6374407Seric 	register char *p;
6384373Seric 
63955354Seric 	if (tTd(29, 4))
64055354Seric 		printf("finduser(%s): ", name);
64155354Seric 
64255354Seric 	*fuzzyp = FALSE;
6434407Seric 
64468481Seric #ifdef HESIOD
64564673Seric 	/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
64664673Seric 	for (p = name; *p != '\0'; p++)
64764673Seric 		if (!isascii(*p) || !isdigit(*p))
64864673Seric 			break;
64964673Seric 	if (*p == '\0')
65064673Seric 	{
65164673Seric 		if (tTd(29, 4))
65264673Seric 			printf("failed (numeric input)\n");
65364673Seric 		return NULL;
65464673Seric 	}
65568481Seric #endif
65664673Seric 
65725777Seric 	/* look up this login name using fast path */
65868693Seric 	if ((pw = sm_getpwnam(name)) != NULL)
65955354Seric 	{
66055354Seric 		if (tTd(29, 4))
66155354Seric 			printf("found (non-fuzzy)\n");
66212634Seric 		return (pw);
66355354Seric 	}
66412634Seric 
66553735Seric #ifdef MATCHGECOS
66653735Seric 	/* see if fuzzy matching allowed */
66753735Seric 	if (!MatchGecos)
66855354Seric 	{
66955354Seric 		if (tTd(29, 4))
67055354Seric 			printf("not found (fuzzy disabled)\n");
67153735Seric 		return NULL;
67255354Seric 	}
67353735Seric 
67412634Seric 	/* search for a matching full name instead */
67525777Seric 	for (p = name; *p != '\0'; p++)
67625777Seric 	{
67725777Seric 		if (*p == (SpaceSub & 0177) || *p == '_')
67825777Seric 			*p = ' ';
67925777Seric 	}
68023107Seric 	(void) setpwent();
6814376Seric 	while ((pw = getpwent()) != NULL)
6824376Seric 	{
68368528Seric 		char buf[MAXNAME + 1];
6844376Seric 
6854998Seric 		buildfname(pw->pw_gecos, pw->pw_name, buf);
68656795Seric 		if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name))
6874381Seric 		{
68855354Seric 			if (tTd(29, 4))
68955354Seric 				printf("fuzzy matches %s\n", pw->pw_name);
69058151Seric 			message("sending to login name %s", pw->pw_name);
69155354Seric 			*fuzzyp = TRUE;
6924376Seric 			return (pw);
6934377Seric 		}
6944376Seric 	}
69555354Seric 	if (tTd(29, 4))
69655354Seric 		printf("no fuzzy match found\n");
69759015Seric #else
69859015Seric 	if (tTd(29, 4))
69959015Seric 		printf("not found (fuzzy disabled)\n");
70059015Seric #endif
7014376Seric 	return (NULL);
7024373Seric }
7034373Seric /*
7044329Seric **  WRITABLE -- predicate returning if the file is writable.
7054329Seric **
7064329Seric **	This routine must duplicate the algorithm in sys/fio.c.
7074329Seric **	Unfortunately, we cannot use the access call since we
7084329Seric **	won't necessarily be the real uid when we try to
7094329Seric **	actually open the file.
7104329Seric **
7114329Seric **	Notice that ANY file with ANY execute bit is automatically
7124329Seric **	not writable.  This is also enforced by mailfile.
7134329Seric **
7144329Seric **	Parameters:
71565064Seric **		filename -- the file name to check.
71665112Seric **		ctladdr -- the controlling address for this file.
71765064Seric **		flags -- SFF_* flags to control the function.
7184329Seric **
7194329Seric **	Returns:
7204329Seric **		TRUE -- if we will be able to write this file.
7214329Seric **		FALSE -- if we cannot write this file.
7224329Seric **
7234329Seric **	Side Effects:
7244329Seric **		none.
7254329Seric */
7264329Seric 
7274329Seric bool
72865112Seric writable(filename, ctladdr, flags)
72964819Seric 	char *filename;
73065112Seric 	ADDRESS *ctladdr;
73165064Seric 	int flags;
7324329Seric {
73355372Seric 	uid_t euid;
73455372Seric 	gid_t egid;
7354329Seric 	int bits;
73664944Seric 	register char *p;
73764944Seric 	char *uname;
7384329Seric 
73964819Seric 	if (tTd(29, 5))
74068802Seric 		printf("writable(%s, 0x%x)\n", filename, flags);
74164944Seric 
74265225Seric #ifdef SUID_ROOT_FILES_OK
74365225Seric 	/* really ought to be passed down -- and not a good idea */
74465225Seric 	flags |= SFF_ROOTOK;
74565225Seric #endif
74665225Seric 
74764944Seric 	/*
74864944Seric 	**  File does exist -- check that it is writable.
74964944Seric 	*/
75064944Seric 
75165112Seric 	if (ctladdr != NULL && geteuid() == 0)
75264944Seric 	{
75365112Seric 		euid = ctladdr->q_uid;
75465112Seric 		egid = ctladdr->q_gid;
75565112Seric 		uname = ctladdr->q_user;
75664944Seric 	}
75768802Seric 	else if (bitset(SFF_RUNASREALUID, flags))
75865112Seric 	{
75968494Seric 		extern char RealUserName[];
76068494Seric 
76165112Seric 		euid = RealUid;
76265112Seric 		egid = RealGid;
76365112Seric 		uname = RealUserName;
76465112Seric 	}
76568481Seric 	else if (FileMailer != NULL)
76668481Seric 	{
76768481Seric 		euid = FileMailer->m_uid;
76868481Seric 		egid = FileMailer->m_gid;
76968481Seric 	}
77068481Seric 	else
77168481Seric 	{
77268481Seric 		euid = egid = 0;
77368481Seric 	}
77465138Seric 	if (euid == 0)
77565138Seric 	{
77665138Seric 		euid = DefUid;
77765138Seric 		uname = DefUser;
77865138Seric 	}
77965138Seric 	if (egid == 0)
78065138Seric 		egid = DefGid;
7814329Seric 	if (geteuid() == 0)
78268494Seric 		flags |= SFF_SETUIDOK;
7834329Seric 
78468494Seric 	errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL);
78565067Seric 	return errno == 0;
7864329Seric }
7874329Seric /*
7884174Seric **  INCLUDE -- handle :include: specification.
7894174Seric **
7904174Seric **	Parameters:
7914174Seric **		fname -- filename to include.
79253037Seric **		forwarding -- if TRUE, we are reading a .forward file.
79353037Seric **			if FALSE, it's a :include: file.
7944399Seric **		ctladdr -- address template to use to fill in these
7954399Seric **			addresses -- effective user/group id are
7964399Seric **			the important things.
7975006Seric **		sendq -- a pointer to the head of the send queue
7985006Seric **			to put these addresses in.
79968481Seric **		aliaslevel -- the alias nesting depth.
80068481Seric **		e -- the current envelope.
8014174Seric **
8024174Seric **	Returns:
80357136Seric **		open error status
8044174Seric **
8054174Seric **	Side Effects:
8064174Seric **		reads the :include: file and sends to everyone
8074174Seric **		listed in that file.
80865909Seric **
80965909Seric **	Security Note:
81065909Seric **		If you have restricted chown (that is, you can't
81165909Seric **		give a file away), it is reasonable to allow programs
81265909Seric **		and files called from this :include: file to be to be
81365909Seric **		run as the owner of the :include: file.  This is bogus
81465909Seric **		if there is any chance of someone giving away a file.
81565909Seric **		We assume that pre-POSIX systems can give away files.
81665909Seric **
81765909Seric **		There is an additional restriction that if you
81865909Seric **		forward to a :include: file, it will not take on
81965909Seric **		the ownership of the :include: file.  This may not
82065909Seric **		be necessary, but shouldn't hurt.
8214174Seric */
8224174Seric 
82353037Seric static jmp_buf	CtxIncludeTimeout;
82468481Seric static void	includetimeout();
82553037Seric 
82657136Seric int
82768481Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
8284174Seric 	char *fname;
82953037Seric 	bool forwarding;
8304399Seric 	ADDRESS *ctladdr;
8315006Seric 	ADDRESS **sendq;
83268481Seric 	int aliaslevel;
83355012Seric 	ENVELOPE *e;
8344174Seric {
83568481Seric 	FILE *fp = NULL;
83655012Seric 	char *oldto = e->e_to;
8379379Seric 	char *oldfilename = FileName;
8389379Seric 	int oldlinenumber = LineNumber;
83953037Seric 	register EVENT *ev = NULL;
84058082Seric 	int nincludes;
84164325Seric 	register ADDRESS *ca;
84264325Seric 	uid_t saveduid, uid;
84364325Seric 	gid_t savedgid, gid;
84464083Seric 	char *uname;
84564325Seric 	int rval = 0;
84668513Seric 	int sfflags = SFF_REGONLY;
84765496Seric 	struct stat st;
84865948Seric 	char buf[MAXLINE];
84965909Seric #ifdef _POSIX_CHOWN_RESTRICTED
85065948Seric # if _POSIX_CHOWN_RESTRICTED == -1
85165948Seric #  define safechown	FALSE
85265948Seric # else
85365948Seric #  define safechown	TRUE
85465948Seric # endif
85565948Seric #else
85665948Seric # ifdef _PC_CHOWN_RESTRICTED
85765909Seric 	bool safechown;
85865948Seric # else
85965948Seric #  ifdef BSD
86065948Seric #   define safechown	TRUE
86165948Seric #  else
86265948Seric #   define safechown	FALSE
86365948Seric #  endif
86465948Seric # endif
86565909Seric #endif
86665948Seric 	extern bool chownsafe();
8674174Seric 
86857186Seric 	if (tTd(27, 2))
86957186Seric 		printf("include(%s)\n", fname);
87063902Seric 	if (tTd(27, 4))
87163902Seric 		printf("   ruid=%d euid=%d\n", getuid(), geteuid());
87263581Seric 	if (tTd(27, 14))
87363581Seric 	{
87463581Seric 		printf("ctladdr ");
87563581Seric 		printaddr(ctladdr, FALSE);
87663581Seric 	}
87757186Seric 
87864325Seric 	if (tTd(27, 9))
87964325Seric 		printf("include: old uid = %d/%d\n", getuid(), geteuid());
88053037Seric 
88168513Seric 	if (forwarding)
88269306Seric 		sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOSLINK;
88368513Seric 
88463581Seric 	ca = getctladdr(ctladdr);
88563581Seric 	if (ca == NULL)
88664083Seric 	{
88764846Seric 		uid = DefUid;
88864846Seric 		gid = DefGid;
88964846Seric 		uname = DefUser;
89064083Seric 	}
89163581Seric 	else
89264083Seric 	{
89363581Seric 		uid = ca->q_uid;
89464083Seric 		gid = ca->q_gid;
89564083Seric 		uname = ca->q_user;
89668481Seric 	}
89764325Seric #ifdef HASSETREUID
89868481Seric 	saveduid = geteuid();
89968481Seric 	savedgid = getegid();
90068481Seric 	if (saveduid == 0)
90168481Seric 	{
90268481Seric 		initgroups(uname, gid);
90368481Seric 		if (uid != 0)
90464325Seric 		{
90568481Seric 			if (setreuid(0, uid) < 0)
90668481Seric 				syserr("setreuid(0, %d) failure (real=%d, eff=%d)",
90768481Seric 					uid, getuid(), geteuid());
90868481Seric 			else
90968481Seric 				sfflags |= SFF_NOPATHCHECK;
91064325Seric 		}
91168481Seric 	}
91269544Seric #endif
91363581Seric 
91464325Seric 	if (tTd(27, 9))
91564325Seric 		printf("include: new uid = %d/%d\n", getuid(), geteuid());
91664325Seric 
91764325Seric 	/*
91864325Seric 	**  If home directory is remote mounted but server is down,
91964325Seric 	**  this can hang or give errors; use a timeout to avoid this
92064325Seric 	*/
92164325Seric 
92253037Seric 	if (setjmp(CtxIncludeTimeout) != 0)
92353037Seric 	{
92463853Seric 		ctladdr->q_flags |= QQUEUEUP;
92553037Seric 		errno = 0;
92663993Seric 
92763993Seric 		/* return pseudo-error code */
92864325Seric 		rval = EOPENTIMEOUT;
92964325Seric 		goto resetuid;
93053037Seric 	}
93168481Seric 	if (TimeOuts.to_fileopen > 0)
93268481Seric 		ev = setevent(TimeOuts.to_fileopen, includetimeout, 0);
93368481Seric 	else
93468481Seric 		ev = NULL;
93553037Seric 
93663581Seric 	/* the input file must be marked safe */
93768494Seric 	rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL);
93864329Seric 	if (rval != 0)
93953037Seric 	{
94064325Seric 		/* don't use this :include: file */
94157186Seric 		if (tTd(27, 4))
94258247Seric 			printf("include: not safe (uid=%d): %s\n",
94364329Seric 				uid, errstring(rval));
94453037Seric 	}
94565496Seric 	else
9464174Seric 	{
94765496Seric 		fp = fopen(fname, "r");
94865496Seric 		if (fp == NULL)
94958061Seric 		{
95064329Seric 			rval = errno;
95165496Seric 			if (tTd(27, 4))
95265496Seric 				printf("include: open: %s\n", errstring(rval));
95358061Seric 		}
9544406Seric 	}
95568481Seric 	if (ev != NULL)
95668481Seric 		clrevent(ev);
95753037Seric 
95864570Seric resetuid:
95964570Seric 
96064570Seric #ifdef HASSETREUID
96164570Seric 	if (saveduid == 0)
96264570Seric 	{
96364570Seric 		if (uid != 0)
96468481Seric 		{
96568481Seric 			if (setreuid(-1, 0) < 0)
96668481Seric 				syserr("setreuid(-1, 0) failure (real=%d, eff=%d)",
96768481Seric 					getuid(), geteuid());
96868481Seric 			if (setreuid(RealUid, 0) < 0)
96964570Seric 				syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
97064570Seric 					RealUid, getuid(), geteuid());
97168481Seric 		}
97264570Seric 		setgid(savedgid);
97364570Seric 	}
97464570Seric #endif
97564570Seric 
97664570Seric 	if (tTd(27, 9))
97764570Seric 		printf("include: reset uid = %d/%d\n", getuid(), geteuid());
97864570Seric 
97965593Seric 	if (rval == EOPENTIMEOUT)
98065593Seric 		usrerr("451 open timeout on %s", fname);
98165593Seric 
98264570Seric 	if (fp == NULL)
98364570Seric 		return rval;
98464570Seric 
98565496Seric 	if (fstat(fileno(fp), &st) < 0)
98665496Seric 	{
98765496Seric 		rval = errno;
98865496Seric 		syserr("Cannot fstat %s!", fname);
98965496Seric 		return rval;
99065496Seric 	}
99165496Seric 
99265948Seric #ifndef safechown
99365948Seric 	safechown = chownsafe(fileno(fp));
99465948Seric #endif
99565909Seric 	if (ca == NULL && safechown)
99665496Seric 	{
99765496Seric 		ctladdr->q_uid = st.st_uid;
99865496Seric 		ctladdr->q_gid = st.st_gid;
99965496Seric 		ctladdr->q_flags |= QGOODUID;
100065496Seric 	}
100165496Seric 	if (ca != NULL && ca->q_uid == st.st_uid)
100265496Seric 	{
100365496Seric 		/* optimization -- avoid getpwuid if we already have info */
100465496Seric 		ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
100565496Seric 		ctladdr->q_ruser = ca->q_ruser;
100665496Seric 	}
100765496Seric 	else
100865496Seric 	{
100965496Seric 		register struct passwd *pw;
101065496Seric 
101168693Seric 		pw = sm_getpwuid(st.st_uid);
101268481Seric 		if (pw == NULL)
101368481Seric 			ctladdr->q_flags |= QBOGUSSHELL;
101468481Seric 		else
101568478Seric 		{
101668481Seric 			char *sh;
101768481Seric 
101868478Seric 			ctladdr->q_ruser = newstr(pw->pw_name);
101968478Seric 			if (safechown)
102068478Seric 				sh = pw->pw_shell;
102165909Seric 			else
102268481Seric 				sh = "/SENDMAIL/ANY/SHELL/";
102368481Seric 			if (!usershellok(sh))
102468481Seric 			{
102568481Seric 				if (safechown)
102668481Seric 					ctladdr->q_flags |= QBOGUSSHELL;
102768481Seric 				else
102868481Seric 					ctladdr->q_flags |= QUNSAFEADDR;
102968481Seric 			}
103065496Seric 		}
103165496Seric 	}
103265496Seric 
103358092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
103458092Seric 	{
103558092Seric 		/* don't do any more now */
103658868Seric 		ctladdr->q_flags |= QVERIFIED;
103758884Seric 		e->e_nrcpts++;
103858680Seric 		xfclose(fp, "include", fname);
103964570Seric 		return rval;
104058092Seric 	}
104158092Seric 
104265496Seric 	/*
104365496Seric 	** Check to see if some bad guy can write this file
104465496Seric 	**
104565496Seric 	**	This should really do something clever with group
104665496Seric 	**	permissions; currently we just view world writable
104765496Seric 	**	as unsafe.  Also, we don't check for writable
104865496Seric 	**	directories in the path.  We've got to leave
104965496Seric 	**	something for the local sysad to do.
105065496Seric 	*/
105165496Seric 
105265496Seric 	if (bitset(S_IWOTH, st.st_mode))
105365496Seric 		ctladdr->q_flags |= QUNSAFEADDR;
105465496Seric 
10554174Seric 	/* read the file -- each line is a comma-separated list. */
10569379Seric 	FileName = fname;
10579379Seric 	LineNumber = 0;
105858082Seric 	ctladdr->q_flags &= ~QSELFREF;
105958082Seric 	nincludes = 0;
10604174Seric 	while (fgets(buf, sizeof buf, fp) != NULL)
10614174Seric 	{
106256795Seric 		register char *p = strchr(buf, '\n');
10634174Seric 
106440963Sbostic 		LineNumber++;
10654174Seric 		if (p != NULL)
10664174Seric 			*p = '\0';
106757186Seric 		if (buf[0] == '#' || buf[0] == '\0')
106857139Seric 			continue;
106968787Seric 
107068787Seric 		/* <sp>#@# introduces a comment anywhere */
107168787Seric 		/* for Japanese character sets */
107268787Seric 		for (p = buf; (p = strchr(++p, '#')) != NULL; )
107368787Seric 		{
107468787Seric 			if (p[1] == '@' && p[2] == '#' &&
107568787Seric 			    isascii(p[-1]) && isspace(p[-1]) &&
107668787Seric 			    isascii(p[3]) && isspace(p[3]))
107768787Seric 			{
107868787Seric 				p[-1] = '\0';
107968787Seric 				break;
108068787Seric 			}
108168787Seric 		}
108268787Seric 		if (buf[0] == '\0')
108368787Seric 			continue;
108468787Seric 
108558008Seric 		e->e_to = NULL;
108658151Seric 		message("%s to %s",
108753037Seric 			forwarding ? "forwarding" : "sending", buf);
108857977Seric #ifdef LOG
108958020Seric 		if (forwarding && LogLevel > 9)
109057977Seric 			syslog(LOG_INFO, "%s: forward %s => %s",
109166284Seric 				e->e_id == NULL ? "NOQUEUE" : e->e_id,
109266284Seric 				oldto, buf);
109357977Seric #endif
109457977Seric 
109568481Seric 		nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e);
10964174Seric 	}
109763902Seric 
109863902Seric 	if (ferror(fp) && tTd(27, 3))
109963902Seric 		printf("include: read error: %s\n", errstring(errno));
110058082Seric 	if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
110158065Seric 	{
110258065Seric 		if (tTd(27, 5))
110358065Seric 		{
110458065Seric 			printf("include: QDONTSEND ");
110558065Seric 			printaddr(ctladdr, FALSE);
110658065Seric 		}
110758065Seric 		ctladdr->q_flags |= QDONTSEND;
110858065Seric 	}
11094174Seric 
111058680Seric 	(void) xfclose(fp, "include", fname);
11119379Seric 	FileName = oldfilename;
11129379Seric 	LineNumber = oldlinenumber;
111363847Seric 	e->e_to = oldto;
111464325Seric 	return rval;
11154174Seric }
111653037Seric 
111768481Seric static void
111853037Seric includetimeout()
111953037Seric {
112053037Seric 	longjmp(CtxIncludeTimeout, 1);
112153037Seric }
11224324Seric /*
11234324Seric **  SENDTOARGV -- send to an argument vector.
11244324Seric **
11254324Seric **	Parameters:
11264324Seric **		argv -- argument vector to send to.
112758247Seric **		e -- the current envelope.
11284324Seric **
11294324Seric **	Returns:
11304324Seric **		none.
11314324Seric **
11324324Seric **	Side Effects:
11334324Seric **		puts all addresses on the argument vector onto the
11344324Seric **			send queue.
11354324Seric */
11364324Seric 
113755012Seric sendtoargv(argv, e)
11384324Seric 	register char **argv;
113955012Seric 	register ENVELOPE *e;
11404324Seric {
11414324Seric 	register char *p;
11424324Seric 
11434324Seric 	while ((p = *argv++) != NULL)
11444324Seric 	{
114568481Seric 		(void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
11464324Seric 	}
11474324Seric }
11484399Seric /*
11494399Seric **  GETCTLADDR -- get controlling address from an address header.
11504399Seric **
11514399Seric **	If none, get one corresponding to the effective userid.
11524399Seric **
11534399Seric **	Parameters:
11544399Seric **		a -- the address to find the controller of.
11554399Seric **
11564399Seric **	Returns:
11574399Seric **		the controlling address.
11584399Seric **
11594399Seric **	Side Effects:
11604399Seric **		none.
11614399Seric */
11624399Seric 
11634399Seric ADDRESS *
11644399Seric getctladdr(a)
11654399Seric 	register ADDRESS *a;
11664399Seric {
11674404Seric 	while (a != NULL && !bitset(QGOODUID, a->q_flags))
11684399Seric 		a = a->q_alias;
11694399Seric 	return (a);
11704399Seric }
117169544Seric /*
117269544Seric **  SELF_REFERENCE -- check to see if an address references itself
117369544Seric **
117469544Seric **	The check is done through a chain of aliases.  If it is part of
117569544Seric **	a loop, break the loop at the "best" address, that is, the one
117669544Seric **	that exists as a real user.
117769544Seric **
117869544Seric **	This is to handle the case of:
117969544Seric **		Andrew.Chang:	awc
118069544Seric **		awc:		Andrew.Chang@mail.server.
118169544Seric **	which is a problem only on mail.server.
118269544Seric **
118369544Seric **	Parameters:
118469544Seric **		a -- the address to check.
118569544Seric **		e -- the current envelope.
118669544Seric **
118769544Seric **	Returns:
118869544Seric **		The address that should be retained.
118969544Seric */
119069544Seric 
119169544Seric ADDRESS *
119269544Seric self_reference(a, e)
119369544Seric 	ADDRESS *a;
119469544Seric 	ENVELOPE *e;
119569544Seric {
119669544Seric 	ADDRESS *b;		/* top entry in self ref loop */
119769544Seric 	ADDRESS *c;		/* entry that point to a real mail box */
119869544Seric 
119969544Seric 	if (tTd(27, 1))
120069544Seric 		printf("self_reference(%s)\n", a->q_paddr);
120169544Seric 
120269544Seric 	for (b = a->q_alias; b != NULL; b = b->q_alias)
120369544Seric 	{
120469544Seric 		if (sameaddr(a, b))
120569544Seric 			break;
120669544Seric 	}
120769544Seric 
120869544Seric 	if (b == NULL)
120969544Seric 	{
121069544Seric 		if (tTd(27, 1))
121169544Seric 			printf("\t... no self ref\n");
121269544Seric 		return NULL;
121369544Seric 	}
121469544Seric 
121569544Seric 	/*
121669544Seric 	**  Pick the first address that resolved to a real mail box
121769544Seric 	**  i.e has a pw entry.  The returned value will be marked
121869544Seric 	**  QSELFREF in recipient(), which in turn will disable alias()
121969544Seric 	**  from marking it QDONTSEND, which mean it will be used
122069544Seric 	**  as a deliverable address.
122169544Seric 	**
122269544Seric 	**  The 2 key thing to note here are:
122369544Seric 	**	1) we are in a recursive call sequence:
122469544Seric 	**		alias->sentolist->recipient->alias
122569544Seric 	**	2) normally, when we return back to alias(), the address
122669544Seric 	**	   will be marked QDONTSEND, since alias() assumes the
122769544Seric 	**	   expanded form will be used instead of the current address.
122869544Seric 	**	   This behaviour is turned off if the address is marked
122969544Seric 	**	   QSELFREF We set QSELFREF when we return to recipient().
123069544Seric 	*/
123169544Seric 
123269544Seric 	c = a;
123369544Seric 	while (c != NULL)
123469544Seric 	{
123569544Seric 		if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
123669544Seric 		{
123769544Seric 			if (tTd(27, 2))
123869544Seric 				printf("\t... getpwnam(%s)... ", c->q_user);
123969544Seric 			if (sm_getpwnam(c->q_user) != NULL)
124069544Seric 			{
124169544Seric 				if (tTd(27, 2))
124269544Seric 					printf("found\n");
124369544Seric 
124469544Seric 				/* ought to cache results here */
124569544Seric 				return c;
124669544Seric 			}
124769544Seric 			if (tTd(27, 2))
124869544Seric 				printf("failed\n");
124969544Seric 		}
125069544Seric 		c = c->q_alias;
125169544Seric 	}
125269544Seric 
125369544Seric 	if (tTd(27, 1))
125469544Seric 		printf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
125569544Seric 
125669544Seric 	return NULL;
125769544Seric }
1258