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*69638Seric static char sccsid[] = "@(#)recipient.c	8.89 (Berkeley) 05/23/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))
11969561Seric 			{
12069561Seric 				if (tTd(27, 5))
12169561Seric 				{
12269561Seric 					printf("sendtolist: QSELFREF ");
12369561Seric 					printaddr(ctladdr, FALSE);
12469561Seric 				}
12568481Seric 				ctladdr->q_flags |= QSELFREF;
12669561Seric 			}
12768481Seric 
12869544Seric 			/* check for address loops */
12969544Seric 			b = self_reference(a, e);
13069544Seric 			if (b != NULL)
13169544Seric 			{
13269544Seric 				b->q_flags |= QSELFREF;
13369561Seric 				if (tTd(27, 5))
13469561Seric 				{
13569561Seric 					printf("sendtolist: QSELFREF ");
13669561Seric 					printaddr(b, FALSE);
13769561Seric 				}
13869544Seric 				if (a != b)
13969544Seric 				{
14069561Seric 					if (tTd(27, 5))
14169561Seric 					{
14269561Seric 						printf("sendtolist: QDONTSEND ");
14369561Seric 						printaddr(a, FALSE);
14469561Seric 					}
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 			}
51769619Seric 			if (bitset(EF_VRFYONLY, e->e_flags))
51869619Seric 			{
51969619Seric 				/* don't do any more now */
52069619Seric 				a->q_flags |= QVERIFIED;
52169619Seric 			}
52269619Seric 			else if (!quoted)
52368481Seric 				forward(a, sendq, aliaslevel, e);
5244174Seric 		}
5254174Seric 	}
52657642Seric 	if (!bitset(QDONTSEND, a->q_flags))
52757642Seric 		e->e_nrcpts++;
52863847Seric 
52963847Seric   testselfdestruct:
53068603Seric 	a->q_flags |= QTHISPASS;
53163978Seric 	if (tTd(26, 8))
53263847Seric 	{
53363978Seric 		printf("testselfdestruct: ");
53468603Seric 		printaddr(a, FALSE);
53568603Seric 		if (tTd(26, 10))
53668603Seric 		{
53768603Seric 			printf("SENDQ:\n");
53868603Seric 			printaddr(*sendq, TRUE);
53968603Seric 			printf("----\n");
54068603Seric 		}
54163978Seric 	}
54263978Seric 	if (a->q_alias == NULL && a != &e->e_from &&
54363978Seric 	    bitset(QDONTSEND, a->q_flags))
54463978Seric 	{
54568603Seric 		for (q = *sendq; q != NULL; q = q->q_next)
54668603Seric 		{
54768603Seric 			if (!bitset(QDONTSEND|QBADADDR, q->q_flags) &&
54868603Seric 			    bitset(QTHISPASS, q->q_flags))
54968603Seric 				break;
55068603Seric 		}
55163978Seric 		if (q == NULL)
55263847Seric 		{
55363847Seric 			a->q_flags |= QBADADDR;
55468858Seric 			a->q_status = "5.4.6";
55563847Seric 			usrerr("554 aliasing/forwarding loop broken");
55663847Seric 		}
55763847Seric 	}
55868481Seric 
55968481Seric   done:
56068603Seric 	a->q_flags |= QTHISPASS;
56168481Seric 	if (buf != buf0)
56268481Seric 		free(buf);
56368603Seric 
56468603Seric 	/*
56568603Seric 	**  If we are at the top level, check to see if this has
56668603Seric 	**  expanded to exactly one address.  If so, it can inherit
56768603Seric 	**  the primaryness of the address.
56868603Seric 	**
56968603Seric 	**  While we're at it, clear the QTHISPASS bits.
57068603Seric 	*/
57168603Seric 
57268603Seric 	if (aliaslevel == 0)
57368603Seric 	{
57468603Seric 		int nrcpts = 0;
57568603Seric 		ADDRESS *only;
57668603Seric 
57768603Seric 		for (q = *sendq; q != NULL; q = q->q_next)
57868603Seric 		{
57968603Seric 			if (bitset(QTHISPASS, q->q_flags) &&
58068603Seric 			    !bitset(QDONTSEND|QBADADDR, q->q_flags))
58168603Seric 			{
58268603Seric 				nrcpts++;
58368603Seric 				only = q;
58468603Seric 			}
58568603Seric 			q->q_flags &= ~QTHISPASS;
58668603Seric 		}
58768603Seric 		if (nrcpts == 1)
58868603Seric 		{
58968867Seric 			/* check to see if this actually got a new owner */
59068867Seric 			q = only;
59168867Seric 			while ((q = q->q_alias) != NULL)
59268867Seric 			{
59368867Seric 				if (q->q_owner != NULL)
59468867Seric 					break;
59568867Seric 			}
59668867Seric 			if (q == NULL)
59768867Seric 				only->q_flags |= QPRIMARY;
59868867Seric 		}
59968867Seric 		else if (!initialdontsend && nrcpts > 0)
60068867Seric 		{
60168603Seric 			/* arrange for return receipt */
60268603Seric 			e->e_flags |= EF_SENDRECEIPT;
60368867Seric 			a->q_flags |= QEXPANDED;
60468603Seric 			if (e->e_xfp != NULL)
60568603Seric 				fprintf(e->e_xfp,
60668603Seric 					"%s... expanded to multiple addresses\n",
60768603Seric 					a->q_paddr);
60868603Seric 		}
60968603Seric 	}
61068603Seric 
61112613Seric 	return (a);
6124174Seric }
6134174Seric /*
6144373Seric **  FINDUSER -- find the password entry for a user.
6154373Seric **
6164373Seric **	This looks a lot like getpwnam, except that it may want to
6174373Seric **	do some fancier pattern matching in /etc/passwd.
6184373Seric **
6199379Seric **	This routine contains most of the time of many sendmail runs.
6209379Seric **	It deserves to be optimized.
6219379Seric **
6224373Seric **	Parameters:
6234373Seric **		name -- the name to match against.
62455354Seric **		fuzzyp -- an outarg that is set to TRUE if this entry
62555354Seric **			was found using the fuzzy matching algorithm;
62655354Seric **			set to FALSE otherwise.
6274373Seric **
6284373Seric **	Returns:
6294373Seric **		A pointer to a pw struct.
6304373Seric **		NULL if name is unknown or ambiguous.
6314373Seric **
6324373Seric **	Side Effects:
6334407Seric **		may modify name.
6344373Seric */
6354373Seric 
6364373Seric struct passwd *
63755354Seric finduser(name, fuzzyp)
6384373Seric 	char *name;
63955354Seric 	bool *fuzzyp;
6404373Seric {
6414376Seric 	register struct passwd *pw;
6424407Seric 	register char *p;
6434373Seric 
64455354Seric 	if (tTd(29, 4))
64555354Seric 		printf("finduser(%s): ", name);
64655354Seric 
64755354Seric 	*fuzzyp = FALSE;
6484407Seric 
64968481Seric #ifdef HESIOD
65064673Seric 	/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
65164673Seric 	for (p = name; *p != '\0'; p++)
65264673Seric 		if (!isascii(*p) || !isdigit(*p))
65364673Seric 			break;
65464673Seric 	if (*p == '\0')
65564673Seric 	{
65664673Seric 		if (tTd(29, 4))
65764673Seric 			printf("failed (numeric input)\n");
65864673Seric 		return NULL;
65964673Seric 	}
66068481Seric #endif
66164673Seric 
66225777Seric 	/* look up this login name using fast path */
66368693Seric 	if ((pw = sm_getpwnam(name)) != NULL)
66455354Seric 	{
66555354Seric 		if (tTd(29, 4))
66655354Seric 			printf("found (non-fuzzy)\n");
66712634Seric 		return (pw);
66855354Seric 	}
66912634Seric 
67053735Seric #ifdef MATCHGECOS
67153735Seric 	/* see if fuzzy matching allowed */
67253735Seric 	if (!MatchGecos)
67355354Seric 	{
67455354Seric 		if (tTd(29, 4))
67555354Seric 			printf("not found (fuzzy disabled)\n");
67653735Seric 		return NULL;
67755354Seric 	}
67853735Seric 
67912634Seric 	/* search for a matching full name instead */
68025777Seric 	for (p = name; *p != '\0'; p++)
68125777Seric 	{
68225777Seric 		if (*p == (SpaceSub & 0177) || *p == '_')
68325777Seric 			*p = ' ';
68425777Seric 	}
68523107Seric 	(void) setpwent();
6864376Seric 	while ((pw = getpwent()) != NULL)
6874376Seric 	{
68868528Seric 		char buf[MAXNAME + 1];
6894376Seric 
6904998Seric 		buildfname(pw->pw_gecos, pw->pw_name, buf);
69156795Seric 		if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name))
6924381Seric 		{
69355354Seric 			if (tTd(29, 4))
69455354Seric 				printf("fuzzy matches %s\n", pw->pw_name);
69558151Seric 			message("sending to login name %s", pw->pw_name);
69655354Seric 			*fuzzyp = TRUE;
6974376Seric 			return (pw);
6984377Seric 		}
6994376Seric 	}
70055354Seric 	if (tTd(29, 4))
70155354Seric 		printf("no fuzzy match found\n");
70259015Seric #else
70359015Seric 	if (tTd(29, 4))
70459015Seric 		printf("not found (fuzzy disabled)\n");
70559015Seric #endif
7064376Seric 	return (NULL);
7074373Seric }
7084373Seric /*
7094329Seric **  WRITABLE -- predicate returning if the file is writable.
7104329Seric **
7114329Seric **	This routine must duplicate the algorithm in sys/fio.c.
7124329Seric **	Unfortunately, we cannot use the access call since we
7134329Seric **	won't necessarily be the real uid when we try to
7144329Seric **	actually open the file.
7154329Seric **
7164329Seric **	Notice that ANY file with ANY execute bit is automatically
7174329Seric **	not writable.  This is also enforced by mailfile.
7184329Seric **
7194329Seric **	Parameters:
72065064Seric **		filename -- the file name to check.
72165112Seric **		ctladdr -- the controlling address for this file.
72265064Seric **		flags -- SFF_* flags to control the function.
7234329Seric **
7244329Seric **	Returns:
7254329Seric **		TRUE -- if we will be able to write this file.
7264329Seric **		FALSE -- if we cannot write this file.
7274329Seric **
7284329Seric **	Side Effects:
7294329Seric **		none.
7304329Seric */
7314329Seric 
7324329Seric bool
73365112Seric writable(filename, ctladdr, flags)
73464819Seric 	char *filename;
73565112Seric 	ADDRESS *ctladdr;
73665064Seric 	int flags;
7374329Seric {
73855372Seric 	uid_t euid;
73955372Seric 	gid_t egid;
7404329Seric 	int bits;
74164944Seric 	register char *p;
74264944Seric 	char *uname;
7434329Seric 
74464819Seric 	if (tTd(29, 5))
74568802Seric 		printf("writable(%s, 0x%x)\n", filename, flags);
74664944Seric 
74765225Seric #ifdef SUID_ROOT_FILES_OK
74865225Seric 	/* really ought to be passed down -- and not a good idea */
74965225Seric 	flags |= SFF_ROOTOK;
75065225Seric #endif
75165225Seric 
75264944Seric 	/*
75364944Seric 	**  File does exist -- check that it is writable.
75464944Seric 	*/
75564944Seric 
75665112Seric 	if (ctladdr != NULL && geteuid() == 0)
75764944Seric 	{
75865112Seric 		euid = ctladdr->q_uid;
75965112Seric 		egid = ctladdr->q_gid;
76065112Seric 		uname = ctladdr->q_user;
76164944Seric 	}
76268802Seric 	else if (bitset(SFF_RUNASREALUID, flags))
76365112Seric 	{
76468494Seric 		extern char RealUserName[];
76568494Seric 
76665112Seric 		euid = RealUid;
76765112Seric 		egid = RealGid;
76865112Seric 		uname = RealUserName;
76965112Seric 	}
77068481Seric 	else if (FileMailer != NULL)
77168481Seric 	{
77268481Seric 		euid = FileMailer->m_uid;
77368481Seric 		egid = FileMailer->m_gid;
77468481Seric 	}
77568481Seric 	else
77668481Seric 	{
77768481Seric 		euid = egid = 0;
77868481Seric 	}
77965138Seric 	if (euid == 0)
78065138Seric 	{
78165138Seric 		euid = DefUid;
78265138Seric 		uname = DefUser;
78365138Seric 	}
78465138Seric 	if (egid == 0)
78565138Seric 		egid = DefGid;
7864329Seric 	if (geteuid() == 0)
78768494Seric 		flags |= SFF_SETUIDOK;
7884329Seric 
78968494Seric 	errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL);
79065067Seric 	return errno == 0;
7914329Seric }
7924329Seric /*
7934174Seric **  INCLUDE -- handle :include: specification.
7944174Seric **
7954174Seric **	Parameters:
7964174Seric **		fname -- filename to include.
79753037Seric **		forwarding -- if TRUE, we are reading a .forward file.
79853037Seric **			if FALSE, it's a :include: file.
7994399Seric **		ctladdr -- address template to use to fill in these
8004399Seric **			addresses -- effective user/group id are
8014399Seric **			the important things.
8025006Seric **		sendq -- a pointer to the head of the send queue
8035006Seric **			to put these addresses in.
80468481Seric **		aliaslevel -- the alias nesting depth.
80568481Seric **		e -- the current envelope.
8064174Seric **
8074174Seric **	Returns:
80857136Seric **		open error status
8094174Seric **
8104174Seric **	Side Effects:
8114174Seric **		reads the :include: file and sends to everyone
8124174Seric **		listed in that file.
81365909Seric **
81465909Seric **	Security Note:
81565909Seric **		If you have restricted chown (that is, you can't
81665909Seric **		give a file away), it is reasonable to allow programs
81765909Seric **		and files called from this :include: file to be to be
81865909Seric **		run as the owner of the :include: file.  This is bogus
81965909Seric **		if there is any chance of someone giving away a file.
82065909Seric **		We assume that pre-POSIX systems can give away files.
82165909Seric **
82265909Seric **		There is an additional restriction that if you
82365909Seric **		forward to a :include: file, it will not take on
82465909Seric **		the ownership of the :include: file.  This may not
82565909Seric **		be necessary, but shouldn't hurt.
8264174Seric */
8274174Seric 
82853037Seric static jmp_buf	CtxIncludeTimeout;
82968481Seric static void	includetimeout();
83053037Seric 
83157136Seric int
83268481Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
8334174Seric 	char *fname;
83453037Seric 	bool forwarding;
8354399Seric 	ADDRESS *ctladdr;
8365006Seric 	ADDRESS **sendq;
83768481Seric 	int aliaslevel;
83855012Seric 	ENVELOPE *e;
8394174Seric {
84068481Seric 	FILE *fp = NULL;
84155012Seric 	char *oldto = e->e_to;
8429379Seric 	char *oldfilename = FileName;
8439379Seric 	int oldlinenumber = LineNumber;
84453037Seric 	register EVENT *ev = NULL;
84558082Seric 	int nincludes;
84664325Seric 	register ADDRESS *ca;
84764325Seric 	uid_t saveduid, uid;
84864325Seric 	gid_t savedgid, gid;
84964083Seric 	char *uname;
85064325Seric 	int rval = 0;
85168513Seric 	int sfflags = SFF_REGONLY;
85265496Seric 	struct stat st;
85365948Seric 	char buf[MAXLINE];
85465909Seric #ifdef _POSIX_CHOWN_RESTRICTED
85565948Seric # if _POSIX_CHOWN_RESTRICTED == -1
85665948Seric #  define safechown	FALSE
85765948Seric # else
85865948Seric #  define safechown	TRUE
85965948Seric # endif
86065948Seric #else
86165948Seric # ifdef _PC_CHOWN_RESTRICTED
86265909Seric 	bool safechown;
86365948Seric # else
86465948Seric #  ifdef BSD
86565948Seric #   define safechown	TRUE
86665948Seric #  else
86765948Seric #   define safechown	FALSE
86865948Seric #  endif
86965948Seric # endif
87065909Seric #endif
87165948Seric 	extern bool chownsafe();
8724174Seric 
87357186Seric 	if (tTd(27, 2))
87457186Seric 		printf("include(%s)\n", fname);
87563902Seric 	if (tTd(27, 4))
87663902Seric 		printf("   ruid=%d euid=%d\n", getuid(), geteuid());
87763581Seric 	if (tTd(27, 14))
87863581Seric 	{
87963581Seric 		printf("ctladdr ");
88063581Seric 		printaddr(ctladdr, FALSE);
88163581Seric 	}
88257186Seric 
88364325Seric 	if (tTd(27, 9))
88464325Seric 		printf("include: old uid = %d/%d\n", getuid(), geteuid());
88553037Seric 
88668513Seric 	if (forwarding)
88769306Seric 		sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOSLINK;
88868513Seric 
88963581Seric 	ca = getctladdr(ctladdr);
89063581Seric 	if (ca == NULL)
89164083Seric 	{
89264846Seric 		uid = DefUid;
89364846Seric 		gid = DefGid;
89464846Seric 		uname = DefUser;
89564083Seric 	}
89663581Seric 	else
89764083Seric 	{
89863581Seric 		uid = ca->q_uid;
89964083Seric 		gid = ca->q_gid;
90064083Seric 		uname = ca->q_user;
90168481Seric 	}
902*69638Seric #if HASSETREUID || USESETEUID
90368481Seric 	saveduid = geteuid();
90468481Seric 	savedgid = getegid();
90568481Seric 	if (saveduid == 0)
90668481Seric 	{
90768481Seric 		initgroups(uname, gid);
90868481Seric 		if (uid != 0)
90964325Seric 		{
910*69638Seric # if USESETEUID
911*69638Seric 			if (seteuid(uid) < 0)
912*69638Seric 				syserr("seteuid(%d) failure (real=%d, eff=%d)",
913*69638Seric 					uid, getuid(), geteuid());
914*69638Seric # else
91568481Seric 			if (setreuid(0, uid) < 0)
91668481Seric 				syserr("setreuid(0, %d) failure (real=%d, eff=%d)",
91768481Seric 					uid, getuid(), geteuid());
918*69638Seric # endif
91968481Seric 			else
92068481Seric 				sfflags |= SFF_NOPATHCHECK;
92164325Seric 		}
92268481Seric 	}
92369544Seric #endif
92463581Seric 
92564325Seric 	if (tTd(27, 9))
92664325Seric 		printf("include: new uid = %d/%d\n", getuid(), geteuid());
92764325Seric 
92864325Seric 	/*
92964325Seric 	**  If home directory is remote mounted but server is down,
93064325Seric 	**  this can hang or give errors; use a timeout to avoid this
93164325Seric 	*/
93264325Seric 
93353037Seric 	if (setjmp(CtxIncludeTimeout) != 0)
93453037Seric 	{
93563853Seric 		ctladdr->q_flags |= QQUEUEUP;
93653037Seric 		errno = 0;
93763993Seric 
93863993Seric 		/* return pseudo-error code */
93964325Seric 		rval = EOPENTIMEOUT;
94064325Seric 		goto resetuid;
94153037Seric 	}
94268481Seric 	if (TimeOuts.to_fileopen > 0)
94368481Seric 		ev = setevent(TimeOuts.to_fileopen, includetimeout, 0);
94468481Seric 	else
94568481Seric 		ev = NULL;
94653037Seric 
94763581Seric 	/* the input file must be marked safe */
94868494Seric 	rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL);
94964329Seric 	if (rval != 0)
95053037Seric 	{
95164325Seric 		/* don't use this :include: file */
95257186Seric 		if (tTd(27, 4))
95358247Seric 			printf("include: not safe (uid=%d): %s\n",
95464329Seric 				uid, errstring(rval));
95553037Seric 	}
95665496Seric 	else
9574174Seric 	{
95865496Seric 		fp = fopen(fname, "r");
95965496Seric 		if (fp == NULL)
96058061Seric 		{
96164329Seric 			rval = errno;
96265496Seric 			if (tTd(27, 4))
96365496Seric 				printf("include: open: %s\n", errstring(rval));
96458061Seric 		}
9654406Seric 	}
96668481Seric 	if (ev != NULL)
96768481Seric 		clrevent(ev);
96853037Seric 
96964570Seric resetuid:
97064570Seric 
971*69638Seric #if HASSETREUID || USESETEUID
97264570Seric 	if (saveduid == 0)
97364570Seric 	{
97464570Seric 		if (uid != 0)
97568481Seric 		{
976*69638Seric # if USESETEUID
977*69638Seric 			if (seteuid(0) < 0)
978*69638Seric 				syserr("seteuid(0) failure (real=%d, eff=%d)",
979*69638Seric 					getuid(), geteuid());
980*69638Seric # else
98168481Seric 			if (setreuid(-1, 0) < 0)
98268481Seric 				syserr("setreuid(-1, 0) failure (real=%d, eff=%d)",
98368481Seric 					getuid(), geteuid());
98468481Seric 			if (setreuid(RealUid, 0) < 0)
98564570Seric 				syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
98664570Seric 					RealUid, getuid(), geteuid());
987*69638Seric # endif
98868481Seric 		}
98964570Seric 		setgid(savedgid);
99064570Seric 	}
99164570Seric #endif
99264570Seric 
99364570Seric 	if (tTd(27, 9))
99464570Seric 		printf("include: reset uid = %d/%d\n", getuid(), geteuid());
99564570Seric 
99665593Seric 	if (rval == EOPENTIMEOUT)
99765593Seric 		usrerr("451 open timeout on %s", fname);
99865593Seric 
99964570Seric 	if (fp == NULL)
100064570Seric 		return rval;
100164570Seric 
100265496Seric 	if (fstat(fileno(fp), &st) < 0)
100365496Seric 	{
100465496Seric 		rval = errno;
100565496Seric 		syserr("Cannot fstat %s!", fname);
100665496Seric 		return rval;
100765496Seric 	}
100865496Seric 
100965948Seric #ifndef safechown
101065948Seric 	safechown = chownsafe(fileno(fp));
101165948Seric #endif
101265909Seric 	if (ca == NULL && safechown)
101365496Seric 	{
101465496Seric 		ctladdr->q_uid = st.st_uid;
101565496Seric 		ctladdr->q_gid = st.st_gid;
101665496Seric 		ctladdr->q_flags |= QGOODUID;
101765496Seric 	}
101865496Seric 	if (ca != NULL && ca->q_uid == st.st_uid)
101965496Seric 	{
102065496Seric 		/* optimization -- avoid getpwuid if we already have info */
102165496Seric 		ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
102265496Seric 		ctladdr->q_ruser = ca->q_ruser;
102365496Seric 	}
102465496Seric 	else
102565496Seric 	{
102665496Seric 		register struct passwd *pw;
102765496Seric 
102868693Seric 		pw = sm_getpwuid(st.st_uid);
102968481Seric 		if (pw == NULL)
103068481Seric 			ctladdr->q_flags |= QBOGUSSHELL;
103168481Seric 		else
103268478Seric 		{
103368481Seric 			char *sh;
103468481Seric 
103568478Seric 			ctladdr->q_ruser = newstr(pw->pw_name);
103668478Seric 			if (safechown)
103768478Seric 				sh = pw->pw_shell;
103865909Seric 			else
103968481Seric 				sh = "/SENDMAIL/ANY/SHELL/";
104068481Seric 			if (!usershellok(sh))
104168481Seric 			{
104268481Seric 				if (safechown)
104368481Seric 					ctladdr->q_flags |= QBOGUSSHELL;
104468481Seric 				else
104568481Seric 					ctladdr->q_flags |= QUNSAFEADDR;
104668481Seric 			}
104765496Seric 		}
104865496Seric 	}
104965496Seric 
105058092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
105158092Seric 	{
105258092Seric 		/* don't do any more now */
105358868Seric 		ctladdr->q_flags |= QVERIFIED;
105458884Seric 		e->e_nrcpts++;
105558680Seric 		xfclose(fp, "include", fname);
105664570Seric 		return rval;
105758092Seric 	}
105858092Seric 
105965496Seric 	/*
106065496Seric 	** Check to see if some bad guy can write this file
106165496Seric 	**
106265496Seric 	**	This should really do something clever with group
106365496Seric 	**	permissions; currently we just view world writable
106465496Seric 	**	as unsafe.  Also, we don't check for writable
106565496Seric 	**	directories in the path.  We've got to leave
106665496Seric 	**	something for the local sysad to do.
106765496Seric 	*/
106865496Seric 
106965496Seric 	if (bitset(S_IWOTH, st.st_mode))
107065496Seric 		ctladdr->q_flags |= QUNSAFEADDR;
107165496Seric 
10724174Seric 	/* read the file -- each line is a comma-separated list. */
10739379Seric 	FileName = fname;
10749379Seric 	LineNumber = 0;
107558082Seric 	ctladdr->q_flags &= ~QSELFREF;
107658082Seric 	nincludes = 0;
10774174Seric 	while (fgets(buf, sizeof buf, fp) != NULL)
10784174Seric 	{
107956795Seric 		register char *p = strchr(buf, '\n');
10804174Seric 
108140963Sbostic 		LineNumber++;
10824174Seric 		if (p != NULL)
10834174Seric 			*p = '\0';
108457186Seric 		if (buf[0] == '#' || buf[0] == '\0')
108557139Seric 			continue;
108668787Seric 
108768787Seric 		/* <sp>#@# introduces a comment anywhere */
108868787Seric 		/* for Japanese character sets */
108968787Seric 		for (p = buf; (p = strchr(++p, '#')) != NULL; )
109068787Seric 		{
109168787Seric 			if (p[1] == '@' && p[2] == '#' &&
109268787Seric 			    isascii(p[-1]) && isspace(p[-1]) &&
109368787Seric 			    isascii(p[3]) && isspace(p[3]))
109468787Seric 			{
109568787Seric 				p[-1] = '\0';
109668787Seric 				break;
109768787Seric 			}
109868787Seric 		}
109968787Seric 		if (buf[0] == '\0')
110068787Seric 			continue;
110168787Seric 
110258008Seric 		e->e_to = NULL;
110358151Seric 		message("%s to %s",
110453037Seric 			forwarding ? "forwarding" : "sending", buf);
110557977Seric #ifdef LOG
110658020Seric 		if (forwarding && LogLevel > 9)
110757977Seric 			syslog(LOG_INFO, "%s: forward %s => %s",
110866284Seric 				e->e_id == NULL ? "NOQUEUE" : e->e_id,
110966284Seric 				oldto, buf);
111057977Seric #endif
111157977Seric 
111268481Seric 		nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e);
11134174Seric 	}
111463902Seric 
111563902Seric 	if (ferror(fp) && tTd(27, 3))
111663902Seric 		printf("include: read error: %s\n", errstring(errno));
111758082Seric 	if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
111858065Seric 	{
111958065Seric 		if (tTd(27, 5))
112058065Seric 		{
112158065Seric 			printf("include: QDONTSEND ");
112258065Seric 			printaddr(ctladdr, FALSE);
112358065Seric 		}
112458065Seric 		ctladdr->q_flags |= QDONTSEND;
112558065Seric 	}
11264174Seric 
112758680Seric 	(void) xfclose(fp, "include", fname);
11289379Seric 	FileName = oldfilename;
11299379Seric 	LineNumber = oldlinenumber;
113063847Seric 	e->e_to = oldto;
113164325Seric 	return rval;
11324174Seric }
113353037Seric 
113468481Seric static void
113553037Seric includetimeout()
113653037Seric {
113753037Seric 	longjmp(CtxIncludeTimeout, 1);
113853037Seric }
11394324Seric /*
11404324Seric **  SENDTOARGV -- send to an argument vector.
11414324Seric **
11424324Seric **	Parameters:
11434324Seric **		argv -- argument vector to send to.
114458247Seric **		e -- the current envelope.
11454324Seric **
11464324Seric **	Returns:
11474324Seric **		none.
11484324Seric **
11494324Seric **	Side Effects:
11504324Seric **		puts all addresses on the argument vector onto the
11514324Seric **			send queue.
11524324Seric */
11534324Seric 
115455012Seric sendtoargv(argv, e)
11554324Seric 	register char **argv;
115655012Seric 	register ENVELOPE *e;
11574324Seric {
11584324Seric 	register char *p;
11594324Seric 
11604324Seric 	while ((p = *argv++) != NULL)
11614324Seric 	{
116268481Seric 		(void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
11634324Seric 	}
11644324Seric }
11654399Seric /*
11664399Seric **  GETCTLADDR -- get controlling address from an address header.
11674399Seric **
11684399Seric **	If none, get one corresponding to the effective userid.
11694399Seric **
11704399Seric **	Parameters:
11714399Seric **		a -- the address to find the controller of.
11724399Seric **
11734399Seric **	Returns:
11744399Seric **		the controlling address.
11754399Seric **
11764399Seric **	Side Effects:
11774399Seric **		none.
11784399Seric */
11794399Seric 
11804399Seric ADDRESS *
11814399Seric getctladdr(a)
11824399Seric 	register ADDRESS *a;
11834399Seric {
11844404Seric 	while (a != NULL && !bitset(QGOODUID, a->q_flags))
11854399Seric 		a = a->q_alias;
11864399Seric 	return (a);
11874399Seric }
118869544Seric /*
118969544Seric **  SELF_REFERENCE -- check to see if an address references itself
119069544Seric **
119169544Seric **	The check is done through a chain of aliases.  If it is part of
119269544Seric **	a loop, break the loop at the "best" address, that is, the one
119369544Seric **	that exists as a real user.
119469544Seric **
119569544Seric **	This is to handle the case of:
119669569Seric **		awc:		Andrew.Chang
119769569Seric **		Andrew.Chang:	awc@mail.server
119869544Seric **	which is a problem only on mail.server.
119969544Seric **
120069544Seric **	Parameters:
120169544Seric **		a -- the address to check.
120269544Seric **		e -- the current envelope.
120369544Seric **
120469544Seric **	Returns:
120569544Seric **		The address that should be retained.
120669544Seric */
120769544Seric 
120869544Seric ADDRESS *
120969544Seric self_reference(a, e)
121069544Seric 	ADDRESS *a;
121169544Seric 	ENVELOPE *e;
121269544Seric {
121369544Seric 	ADDRESS *b;		/* top entry in self ref loop */
121469544Seric 	ADDRESS *c;		/* entry that point to a real mail box */
121569544Seric 
121669544Seric 	if (tTd(27, 1))
121769544Seric 		printf("self_reference(%s)\n", a->q_paddr);
121869544Seric 
121969544Seric 	for (b = a->q_alias; b != NULL; b = b->q_alias)
122069544Seric 	{
122169544Seric 		if (sameaddr(a, b))
122269544Seric 			break;
122369544Seric 	}
122469544Seric 
122569544Seric 	if (b == NULL)
122669544Seric 	{
122769544Seric 		if (tTd(27, 1))
122869544Seric 			printf("\t... no self ref\n");
122969544Seric 		return NULL;
123069544Seric 	}
123169544Seric 
123269544Seric 	/*
123369544Seric 	**  Pick the first address that resolved to a real mail box
123469544Seric 	**  i.e has a pw entry.  The returned value will be marked
123569544Seric 	**  QSELFREF in recipient(), which in turn will disable alias()
123669544Seric 	**  from marking it QDONTSEND, which mean it will be used
123769544Seric 	**  as a deliverable address.
123869544Seric 	**
123969544Seric 	**  The 2 key thing to note here are:
124069544Seric 	**	1) we are in a recursive call sequence:
124169544Seric 	**		alias->sentolist->recipient->alias
124269544Seric 	**	2) normally, when we return back to alias(), the address
124369544Seric 	**	   will be marked QDONTSEND, since alias() assumes the
124469544Seric 	**	   expanded form will be used instead of the current address.
124569544Seric 	**	   This behaviour is turned off if the address is marked
124669544Seric 	**	   QSELFREF We set QSELFREF when we return to recipient().
124769544Seric 	*/
124869544Seric 
124969544Seric 	c = a;
125069544Seric 	while (c != NULL)
125169544Seric 	{
125269544Seric 		if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
125369544Seric 		{
125469544Seric 			if (tTd(27, 2))
125569544Seric 				printf("\t... getpwnam(%s)... ", c->q_user);
125669544Seric 			if (sm_getpwnam(c->q_user) != NULL)
125769544Seric 			{
125869544Seric 				if (tTd(27, 2))
125969544Seric 					printf("found\n");
126069544Seric 
126169544Seric 				/* ought to cache results here */
126269621Seric 				if (sameaddr(b, c))
126369621Seric 					return b;
126469621Seric 				else
126569621Seric 					return c;
126669544Seric 			}
126769544Seric 			if (tTd(27, 2))
126869544Seric 				printf("failed\n");
126969544Seric 		}
127069544Seric 		c = c->q_alias;
127169544Seric 	}
127269544Seric 
127369544Seric 	if (tTd(27, 1))
127469544Seric 		printf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
127569544Seric 
127669544Seric 	return NULL;
127769544Seric }
1278