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*69952Seric static char sccsid[] = "@(#)recipient.c	8.97 (Berkeley) 06/20/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
sendtolist(list,ctladdr,sendq,aliaslevel,e)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 *
recipient(a,sendq,aliaslevel,e)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 */
41069904Seric 	if (!quoted && !bitset(QDONTSEND, a->q_flags) &&
41169904Seric 	    bitnset(M_ALIASABLE, m->m_flags))
41268481Seric 		alias(a, sendq, aliaslevel, e);
41357402Seric 
41469714Seric # if USERDB
41557402Seric 	/* if not aliased, look it up in the user database */
41668481Seric 	if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) &&
41768481Seric 	    bitnset(M_CHECKUDB, m->m_flags))
41857402Seric 	{
41957402Seric 		extern int udbexpand();
42057402Seric 
42168481Seric 		if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL)
42257402Seric 		{
42363853Seric 			a->q_flags |= QQUEUEUP;
42457402Seric 			if (e->e_message == NULL)
42557402Seric 				e->e_message = newstr("Deferred: user database error");
42657402Seric # ifdef LOG
42758020Seric 			if (LogLevel > 8)
42859623Seric 				syslog(LOG_INFO, "%s: deferred: udbexpand: %s",
42966284Seric 					e->e_id == NULL ? "NOQUEUE" : e->e_id,
43066284Seric 					errstring(errno));
43157402Seric # endif
43259615Seric 			message("queued (user database error): %s",
43359615Seric 				errstring(errno));
43457642Seric 			e->e_nrcpts++;
43563847Seric 			goto testselfdestruct;
43657402Seric 		}
43757402Seric 	}
43857402Seric # endif
43957402Seric 
44051317Seric 	/*
44151317Seric 	**  If we have a level two config file, then pass the name through
44251317Seric 	**  Ruleset 5 before sending it off.  Ruleset 5 has the right
44351317Seric 	**  to send rewrite it to another mailer.  This gives us a hook
44451317Seric 	**  after local aliasing has been done.
44551317Seric 	*/
44651317Seric 
44751317Seric 	if (tTd(29, 5))
44851317Seric 	{
44951317Seric 		printf("recipient: testing local?  cl=%d, rr5=%x\n\t",
45051317Seric 			ConfigLevel, RewriteRules[5]);
45151317Seric 		printaddr(a, FALSE);
45251317Seric 	}
45368481Seric 	if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
45468481Seric 	    ConfigLevel >= 2 && RewriteRules[5] != NULL &&
45568481Seric 	    bitnset(M_TRYRULESET5, m->m_flags))
45651317Seric 	{
45768603Seric 		maplocaluser(a, sendq, aliaslevel + 1, e);
45851317Seric 	}
45951317Seric 
46051317Seric 	/*
46151317Seric 	**  If it didn't get rewritten to another mailer, go ahead
46251317Seric 	**  and deliver it.
46351317Seric 	*/
46451317Seric 
46568481Seric 	if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
46668481Seric 	    bitnset(M_HASPWENT, m->m_flags))
46751317Seric 	{
46855354Seric 		auto bool fuzzy;
46951317Seric 		register struct passwd *pw;
47051317Seric 		extern struct passwd *finduser();
47151317Seric 
47251317Seric 		/* warning -- finduser may trash buf */
47355354Seric 		pw = finduser(buf, &fuzzy);
47451317Seric 		if (pw == NULL)
47551317Seric 		{
47658680Seric 			a->q_flags |= QBADADDR;
47768857Seric 			a->q_status = "5.1.1";
47868481Seric 			giveresponse(EX_NOUSER, m, NULL, a->q_alias,
47968481Seric 				     (time_t) 0, e);
48051317Seric 		}
4814174Seric 		else
4824174Seric 		{
48368528Seric 			char nbuf[MAXNAME + 1];
4844373Seric 
48555354Seric 			if (fuzzy)
4864174Seric 			{
48753735Seric 				/* name was a fuzzy match */
48851317Seric 				a->q_user = newstr(pw->pw_name);
48953735Seric 				if (findusercount++ > 3)
49053735Seric 				{
49158680Seric 					a->q_flags |= QBADADDR;
49268857Seric 					a->q_status = "5.4.6";
49358151Seric 					usrerr("554 aliasing/forwarding loop for %s broken",
49453735Seric 						pw->pw_name);
49568481Seric 					goto done;
49653735Seric 				}
49753735Seric 
49853735Seric 				/* see if it aliases */
49951317Seric 				(void) strcpy(buf, pw->pw_name);
50053735Seric 				goto trylocaluser;
5014174Seric 			}
50265822Seric 			if (strcmp(pw->pw_dir, "/") == 0)
50365822Seric 				a->q_home = "";
50465822Seric 			else
50565822Seric 				a->q_home = newstr(pw->pw_dir);
50651317Seric 			a->q_uid = pw->pw_uid;
50751317Seric 			a->q_gid = pw->pw_gid;
50859083Seric 			a->q_ruser = newstr(pw->pw_name);
50951317Seric 			a->q_flags |= QGOODUID;
51051317Seric 			buildfname(pw->pw_gecos, pw->pw_name, nbuf);
51151317Seric 			if (nbuf[0] != '\0')
51251317Seric 				a->q_fullname = newstr(nbuf);
51369894Seric 			if (!usershellok(pw->pw_name, 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 		{
54769898Seric 			if (!bitset(QDONTSEND, 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 *
finduser(name,fuzzyp)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 
67069881Seric #if 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
writable(filename,ctladdr,flags)73365112Seric writable(filename, ctladdr, flags)
73464819Seric 	char *filename;
73565112Seric 	ADDRESS *ctladdr;
73665064Seric 	int flags;
7374329Seric {
73855372Seric 	uid_t euid;
73955372Seric 	gid_t egid;
74064944Seric 	char *uname;
7414329Seric 
74264819Seric 	if (tTd(29, 5))
74368802Seric 		printf("writable(%s, 0x%x)\n", filename, flags);
74464944Seric 
74564944Seric 	/*
74664944Seric 	**  File does exist -- check that it is writable.
74764944Seric 	*/
74864944Seric 
74965112Seric 	if (ctladdr != NULL && geteuid() == 0)
75064944Seric 	{
75165112Seric 		euid = ctladdr->q_uid;
75265112Seric 		egid = ctladdr->q_gid;
75365112Seric 		uname = ctladdr->q_user;
75464944Seric 	}
75568802Seric 	else if (bitset(SFF_RUNASREALUID, flags))
75665112Seric 	{
75765112Seric 		euid = RealUid;
75865112Seric 		egid = RealGid;
75965112Seric 		uname = RealUserName;
76065112Seric 	}
761*69952Seric 	else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags))
76268481Seric 	{
76368481Seric 		euid = FileMailer->m_uid;
76468481Seric 		egid = FileMailer->m_gid;
76569748Seric 		uname = NULL;
76668481Seric 	}
76768481Seric 	else
76868481Seric 	{
76968481Seric 		euid = egid = 0;
77069748Seric 		uname = NULL;
77168481Seric 	}
772*69952Seric 	if (!bitset(SFF_ROOTOK, flags))
77365138Seric 	{
774*69952Seric 		if (euid == 0)
775*69952Seric 		{
776*69952Seric 			euid = DefUid;
777*69952Seric 			uname = DefUser;
778*69952Seric 		}
779*69952Seric 		if (egid == 0)
780*69952Seric 			egid = DefGid;
78165138Seric 	}
7824329Seric 	if (geteuid() == 0)
78368494Seric 		flags |= SFF_SETUIDOK;
7844329Seric 
78568494Seric 	errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL);
78665067Seric 	return errno == 0;
7874329Seric }
7884329Seric /*
7894174Seric **  INCLUDE -- handle :include: specification.
7904174Seric **
7914174Seric **	Parameters:
7924174Seric **		fname -- filename to include.
79353037Seric **		forwarding -- if TRUE, we are reading a .forward file.
79453037Seric **			if FALSE, it's a :include: file.
7954399Seric **		ctladdr -- address template to use to fill in these
7964399Seric **			addresses -- effective user/group id are
7974399Seric **			the important things.
7985006Seric **		sendq -- a pointer to the head of the send queue
7995006Seric **			to put these addresses in.
80068481Seric **		aliaslevel -- the alias nesting depth.
80168481Seric **		e -- the current envelope.
8024174Seric **
8034174Seric **	Returns:
80457136Seric **		open error status
8054174Seric **
8064174Seric **	Side Effects:
8074174Seric **		reads the :include: file and sends to everyone
8084174Seric **		listed in that file.
80965909Seric **
81065909Seric **	Security Note:
81165909Seric **		If you have restricted chown (that is, you can't
81265909Seric **		give a file away), it is reasonable to allow programs
81365909Seric **		and files called from this :include: file to be to be
81465909Seric **		run as the owner of the :include: file.  This is bogus
81565909Seric **		if there is any chance of someone giving away a file.
81665909Seric **		We assume that pre-POSIX systems can give away files.
81765909Seric **
81865909Seric **		There is an additional restriction that if you
81965909Seric **		forward to a :include: file, it will not take on
82065909Seric **		the ownership of the :include: file.  This may not
82165909Seric **		be necessary, but shouldn't hurt.
8224174Seric */
8234174Seric 
82453037Seric static jmp_buf	CtxIncludeTimeout;
82568481Seric static void	includetimeout();
82653037Seric 
82757136Seric int
include(fname,forwarding,ctladdr,sendq,aliaslevel,e)82868481Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
8294174Seric 	char *fname;
83053037Seric 	bool forwarding;
8314399Seric 	ADDRESS *ctladdr;
8325006Seric 	ADDRESS **sendq;
83368481Seric 	int aliaslevel;
83455012Seric 	ENVELOPE *e;
8354174Seric {
83668481Seric 	FILE *fp = NULL;
83755012Seric 	char *oldto = e->e_to;
8389379Seric 	char *oldfilename = FileName;
8399379Seric 	int oldlinenumber = LineNumber;
84053037Seric 	register EVENT *ev = NULL;
84158082Seric 	int nincludes;
84264325Seric 	register ADDRESS *ca;
84364325Seric 	uid_t saveduid, uid;
84464325Seric 	gid_t savedgid, gid;
84564083Seric 	char *uname;
84664325Seric 	int rval = 0;
84768513Seric 	int sfflags = SFF_REGONLY;
84865496Seric 	struct stat st;
84965948Seric 	char buf[MAXLINE];
85065909Seric #ifdef _POSIX_CHOWN_RESTRICTED
85165948Seric # if _POSIX_CHOWN_RESTRICTED == -1
85265948Seric #  define safechown	FALSE
85365948Seric # else
85465948Seric #  define safechown	TRUE
85565948Seric # endif
85665948Seric #else
85765948Seric # ifdef _PC_CHOWN_RESTRICTED
85865909Seric 	bool safechown;
85965948Seric # else
86065948Seric #  ifdef BSD
86165948Seric #   define safechown	TRUE
86265948Seric #  else
86365948Seric #   define safechown	FALSE
86465948Seric #  endif
86565948Seric # endif
86665909Seric #endif
86765948Seric 	extern bool chownsafe();
8684174Seric 
86957186Seric 	if (tTd(27, 2))
87057186Seric 		printf("include(%s)\n", fname);
87163902Seric 	if (tTd(27, 4))
87263902Seric 		printf("   ruid=%d euid=%d\n", getuid(), geteuid());
87363581Seric 	if (tTd(27, 14))
87463581Seric 	{
87563581Seric 		printf("ctladdr ");
87663581Seric 		printaddr(ctladdr, FALSE);
87763581Seric 	}
87857186Seric 
87964325Seric 	if (tTd(27, 9))
88064325Seric 		printf("include: old uid = %d/%d\n", getuid(), geteuid());
88153037Seric 
88268513Seric 	if (forwarding)
88369306Seric 		sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOSLINK;
88468513Seric 
88563581Seric 	ca = getctladdr(ctladdr);
88663581Seric 	if (ca == NULL)
88764083Seric 	{
88864846Seric 		uid = DefUid;
88964846Seric 		gid = DefGid;
89064846Seric 		uname = DefUser;
89164083Seric 	}
89263581Seric 	else
89364083Seric 	{
89463581Seric 		uid = ca->q_uid;
89564083Seric 		gid = ca->q_gid;
89664083Seric 		uname = ca->q_user;
89768481Seric 	}
89869638Seric #if HASSETREUID || USESETEUID
89968481Seric 	saveduid = geteuid();
90068481Seric 	savedgid = getegid();
90168481Seric 	if (saveduid == 0)
90268481Seric 	{
90368481Seric 		initgroups(uname, gid);
90468481Seric 		if (uid != 0)
90564325Seric 		{
90669638Seric # if USESETEUID
90769638Seric 			if (seteuid(uid) < 0)
90869638Seric 				syserr("seteuid(%d) failure (real=%d, eff=%d)",
90969638Seric 					uid, getuid(), geteuid());
91069638Seric # else
91168481Seric 			if (setreuid(0, uid) < 0)
91268481Seric 				syserr("setreuid(0, %d) failure (real=%d, eff=%d)",
91368481Seric 					uid, getuid(), geteuid());
91469638Seric # endif
91568481Seric 			else
91668481Seric 				sfflags |= SFF_NOPATHCHECK;
91764325Seric 		}
91868481Seric 	}
91969544Seric #endif
92063581Seric 
92164325Seric 	if (tTd(27, 9))
92264325Seric 		printf("include: new uid = %d/%d\n", getuid(), geteuid());
92364325Seric 
92464325Seric 	/*
92564325Seric 	**  If home directory is remote mounted but server is down,
92664325Seric 	**  this can hang or give errors; use a timeout to avoid this
92764325Seric 	*/
92864325Seric 
92953037Seric 	if (setjmp(CtxIncludeTimeout) != 0)
93053037Seric 	{
93163853Seric 		ctladdr->q_flags |= QQUEUEUP;
93253037Seric 		errno = 0;
93363993Seric 
93463993Seric 		/* return pseudo-error code */
93564325Seric 		rval = EOPENTIMEOUT;
93664325Seric 		goto resetuid;
93753037Seric 	}
93868481Seric 	if (TimeOuts.to_fileopen > 0)
93968481Seric 		ev = setevent(TimeOuts.to_fileopen, includetimeout, 0);
94068481Seric 	else
94168481Seric 		ev = NULL;
94253037Seric 
94363581Seric 	/* the input file must be marked safe */
94468494Seric 	rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL);
94564329Seric 	if (rval != 0)
94653037Seric 	{
94764325Seric 		/* don't use this :include: file */
94857186Seric 		if (tTd(27, 4))
94958247Seric 			printf("include: not safe (uid=%d): %s\n",
95064329Seric 				uid, errstring(rval));
95153037Seric 	}
95265496Seric 	else
9534174Seric 	{
95465496Seric 		fp = fopen(fname, "r");
95565496Seric 		if (fp == NULL)
95658061Seric 		{
95764329Seric 			rval = errno;
95865496Seric 			if (tTd(27, 4))
95965496Seric 				printf("include: open: %s\n", errstring(rval));
96058061Seric 		}
9614406Seric 	}
96268481Seric 	if (ev != NULL)
96368481Seric 		clrevent(ev);
96453037Seric 
96564570Seric resetuid:
96664570Seric 
96769638Seric #if HASSETREUID || USESETEUID
96864570Seric 	if (saveduid == 0)
96964570Seric 	{
97064570Seric 		if (uid != 0)
97168481Seric 		{
97269638Seric # if USESETEUID
97369638Seric 			if (seteuid(0) < 0)
97469638Seric 				syserr("seteuid(0) failure (real=%d, eff=%d)",
97569638Seric 					getuid(), geteuid());
97669638Seric # else
97768481Seric 			if (setreuid(-1, 0) < 0)
97868481Seric 				syserr("setreuid(-1, 0) failure (real=%d, eff=%d)",
97968481Seric 					getuid(), geteuid());
98068481Seric 			if (setreuid(RealUid, 0) < 0)
98164570Seric 				syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
98264570Seric 					RealUid, getuid(), geteuid());
98369638Seric # endif
98468481Seric 		}
98564570Seric 		setgid(savedgid);
98664570Seric 	}
98764570Seric #endif
98864570Seric 
98964570Seric 	if (tTd(27, 9))
99064570Seric 		printf("include: reset uid = %d/%d\n", getuid(), geteuid());
99164570Seric 
99265593Seric 	if (rval == EOPENTIMEOUT)
99365593Seric 		usrerr("451 open timeout on %s", fname);
99465593Seric 
99564570Seric 	if (fp == NULL)
99664570Seric 		return rval;
99764570Seric 
99865496Seric 	if (fstat(fileno(fp), &st) < 0)
99965496Seric 	{
100065496Seric 		rval = errno;
100165496Seric 		syserr("Cannot fstat %s!", fname);
100265496Seric 		return rval;
100365496Seric 	}
100465496Seric 
100565948Seric #ifndef safechown
100665948Seric 	safechown = chownsafe(fileno(fp));
100765948Seric #endif
100865909Seric 	if (ca == NULL && safechown)
100965496Seric 	{
101065496Seric 		ctladdr->q_uid = st.st_uid;
101165496Seric 		ctladdr->q_gid = st.st_gid;
101265496Seric 		ctladdr->q_flags |= QGOODUID;
101365496Seric 	}
101465496Seric 	if (ca != NULL && ca->q_uid == st.st_uid)
101565496Seric 	{
101665496Seric 		/* optimization -- avoid getpwuid if we already have info */
101765496Seric 		ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
101865496Seric 		ctladdr->q_ruser = ca->q_ruser;
101965496Seric 	}
102065496Seric 	else
102165496Seric 	{
102265496Seric 		register struct passwd *pw;
102365496Seric 
102468693Seric 		pw = sm_getpwuid(st.st_uid);
102568481Seric 		if (pw == NULL)
102668481Seric 			ctladdr->q_flags |= QBOGUSSHELL;
102768481Seric 		else
102868478Seric 		{
102968481Seric 			char *sh;
103068481Seric 
103168478Seric 			ctladdr->q_ruser = newstr(pw->pw_name);
103268478Seric 			if (safechown)
103368478Seric 				sh = pw->pw_shell;
103465909Seric 			else
103568481Seric 				sh = "/SENDMAIL/ANY/SHELL/";
103669894Seric 			if (!usershellok(pw->pw_name, sh))
103768481Seric 			{
103868481Seric 				if (safechown)
103968481Seric 					ctladdr->q_flags |= QBOGUSSHELL;
104068481Seric 				else
104168481Seric 					ctladdr->q_flags |= QUNSAFEADDR;
104268481Seric 			}
104365496Seric 		}
104465496Seric 	}
104565496Seric 
104658092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
104758092Seric 	{
104858092Seric 		/* don't do any more now */
104958868Seric 		ctladdr->q_flags |= QVERIFIED;
105058884Seric 		e->e_nrcpts++;
105158680Seric 		xfclose(fp, "include", fname);
105264570Seric 		return rval;
105358092Seric 	}
105458092Seric 
105565496Seric 	/*
105665496Seric 	** Check to see if some bad guy can write this file
105765496Seric 	**
105865496Seric 	**	This should really do something clever with group
105965496Seric 	**	permissions; currently we just view world writable
106065496Seric 	**	as unsafe.  Also, we don't check for writable
106165496Seric 	**	directories in the path.  We've got to leave
106265496Seric 	**	something for the local sysad to do.
106365496Seric 	*/
106465496Seric 
106565496Seric 	if (bitset(S_IWOTH, st.st_mode))
106665496Seric 		ctladdr->q_flags |= QUNSAFEADDR;
106765496Seric 
10684174Seric 	/* read the file -- each line is a comma-separated list. */
10699379Seric 	FileName = fname;
10709379Seric 	LineNumber = 0;
107158082Seric 	ctladdr->q_flags &= ~QSELFREF;
107258082Seric 	nincludes = 0;
10734174Seric 	while (fgets(buf, sizeof buf, fp) != NULL)
10744174Seric 	{
107556795Seric 		register char *p = strchr(buf, '\n');
10764174Seric 
107740963Sbostic 		LineNumber++;
10784174Seric 		if (p != NULL)
10794174Seric 			*p = '\0';
108057186Seric 		if (buf[0] == '#' || buf[0] == '\0')
108157139Seric 			continue;
108268787Seric 
108368787Seric 		/* <sp>#@# introduces a comment anywhere */
108468787Seric 		/* for Japanese character sets */
108568787Seric 		for (p = buf; (p = strchr(++p, '#')) != NULL; )
108668787Seric 		{
108768787Seric 			if (p[1] == '@' && p[2] == '#' &&
108868787Seric 			    isascii(p[-1]) && isspace(p[-1]) &&
108969714Seric 			    (p[3] == '\0' || (isascii(p[3]) && isspace(p[3]))))
109068787Seric 			{
109168787Seric 				p[-1] = '\0';
109268787Seric 				break;
109368787Seric 			}
109468787Seric 		}
109568787Seric 		if (buf[0] == '\0')
109668787Seric 			continue;
109768787Seric 
109858008Seric 		e->e_to = NULL;
109958151Seric 		message("%s to %s",
110053037Seric 			forwarding ? "forwarding" : "sending", buf);
110157977Seric #ifdef LOG
110258020Seric 		if (forwarding && LogLevel > 9)
110357977Seric 			syslog(LOG_INFO, "%s: forward %s => %s",
110466284Seric 				e->e_id == NULL ? "NOQUEUE" : e->e_id,
110566284Seric 				oldto, buf);
110657977Seric #endif
110757977Seric 
110868481Seric 		nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e);
11094174Seric 	}
111063902Seric 
111163902Seric 	if (ferror(fp) && tTd(27, 3))
111263902Seric 		printf("include: read error: %s\n", errstring(errno));
111358082Seric 	if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
111458065Seric 	{
111558065Seric 		if (tTd(27, 5))
111658065Seric 		{
111758065Seric 			printf("include: QDONTSEND ");
111858065Seric 			printaddr(ctladdr, FALSE);
111958065Seric 		}
112058065Seric 		ctladdr->q_flags |= QDONTSEND;
112158065Seric 	}
11224174Seric 
112358680Seric 	(void) xfclose(fp, "include", fname);
11249379Seric 	FileName = oldfilename;
11259379Seric 	LineNumber = oldlinenumber;
112663847Seric 	e->e_to = oldto;
112764325Seric 	return rval;
11284174Seric }
112953037Seric 
113068481Seric static void
includetimeout()113153037Seric includetimeout()
113253037Seric {
113353037Seric 	longjmp(CtxIncludeTimeout, 1);
113453037Seric }
11354324Seric /*
11364324Seric **  SENDTOARGV -- send to an argument vector.
11374324Seric **
11384324Seric **	Parameters:
11394324Seric **		argv -- argument vector to send to.
114058247Seric **		e -- the current envelope.
11414324Seric **
11424324Seric **	Returns:
11434324Seric **		none.
11444324Seric **
11454324Seric **	Side Effects:
11464324Seric **		puts all addresses on the argument vector onto the
11474324Seric **			send queue.
11484324Seric */
11494324Seric 
115069748Seric void
sendtoargv(argv,e)115155012Seric sendtoargv(argv, e)
11524324Seric 	register char **argv;
115355012Seric 	register ENVELOPE *e;
11544324Seric {
11554324Seric 	register char *p;
11564324Seric 
11574324Seric 	while ((p = *argv++) != NULL)
11584324Seric 	{
115968481Seric 		(void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
11604324Seric 	}
11614324Seric }
11624399Seric /*
11634399Seric **  GETCTLADDR -- get controlling address from an address header.
11644399Seric **
11654399Seric **	If none, get one corresponding to the effective userid.
11664399Seric **
11674399Seric **	Parameters:
11684399Seric **		a -- the address to find the controller of.
11694399Seric **
11704399Seric **	Returns:
11714399Seric **		the controlling address.
11724399Seric **
11734399Seric **	Side Effects:
11744399Seric **		none.
11754399Seric */
11764399Seric 
11774399Seric ADDRESS *
getctladdr(a)11784399Seric getctladdr(a)
11794399Seric 	register ADDRESS *a;
11804399Seric {
11814404Seric 	while (a != NULL && !bitset(QGOODUID, a->q_flags))
11824399Seric 		a = a->q_alias;
11834399Seric 	return (a);
11844399Seric }
118569544Seric /*
118669544Seric **  SELF_REFERENCE -- check to see if an address references itself
118769544Seric **
118869544Seric **	The check is done through a chain of aliases.  If it is part of
118969544Seric **	a loop, break the loop at the "best" address, that is, the one
119069544Seric **	that exists as a real user.
119169544Seric **
119269544Seric **	This is to handle the case of:
119369569Seric **		awc:		Andrew.Chang
119469569Seric **		Andrew.Chang:	awc@mail.server
119569544Seric **	which is a problem only on mail.server.
119669544Seric **
119769544Seric **	Parameters:
119869544Seric **		a -- the address to check.
119969544Seric **		e -- the current envelope.
120069544Seric **
120169544Seric **	Returns:
120269544Seric **		The address that should be retained.
120369544Seric */
120469544Seric 
120569544Seric ADDRESS *
self_reference(a,e)120669544Seric self_reference(a, e)
120769544Seric 	ADDRESS *a;
120869544Seric 	ENVELOPE *e;
120969544Seric {
121069544Seric 	ADDRESS *b;		/* top entry in self ref loop */
121169544Seric 	ADDRESS *c;		/* entry that point to a real mail box */
121269544Seric 
121369544Seric 	if (tTd(27, 1))
121469544Seric 		printf("self_reference(%s)\n", a->q_paddr);
121569544Seric 
121669544Seric 	for (b = a->q_alias; b != NULL; b = b->q_alias)
121769544Seric 	{
121869544Seric 		if (sameaddr(a, b))
121969544Seric 			break;
122069544Seric 	}
122169544Seric 
122269544Seric 	if (b == NULL)
122369544Seric 	{
122469544Seric 		if (tTd(27, 1))
122569544Seric 			printf("\t... no self ref\n");
122669544Seric 		return NULL;
122769544Seric 	}
122869544Seric 
122969544Seric 	/*
123069544Seric 	**  Pick the first address that resolved to a real mail box
123169544Seric 	**  i.e has a pw entry.  The returned value will be marked
123269544Seric 	**  QSELFREF in recipient(), which in turn will disable alias()
123369544Seric 	**  from marking it QDONTSEND, which mean it will be used
123469544Seric 	**  as a deliverable address.
123569544Seric 	**
123669544Seric 	**  The 2 key thing to note here are:
123769544Seric 	**	1) we are in a recursive call sequence:
123869544Seric 	**		alias->sentolist->recipient->alias
123969544Seric 	**	2) normally, when we return back to alias(), the address
124069544Seric 	**	   will be marked QDONTSEND, since alias() assumes the
124169544Seric 	**	   expanded form will be used instead of the current address.
124269544Seric 	**	   This behaviour is turned off if the address is marked
124369544Seric 	**	   QSELFREF We set QSELFREF when we return to recipient().
124469544Seric 	*/
124569544Seric 
124669544Seric 	c = a;
124769544Seric 	while (c != NULL)
124869544Seric 	{
124969544Seric 		if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
125069544Seric 		{
125169544Seric 			if (tTd(27, 2))
125269544Seric 				printf("\t... getpwnam(%s)... ", c->q_user);
125369544Seric 			if (sm_getpwnam(c->q_user) != NULL)
125469544Seric 			{
125569544Seric 				if (tTd(27, 2))
125669544Seric 					printf("found\n");
125769544Seric 
125869544Seric 				/* ought to cache results here */
125969621Seric 				if (sameaddr(b, c))
126069621Seric 					return b;
126169621Seric 				else
126269621Seric 					return c;
126369544Seric 			}
126469544Seric 			if (tTd(27, 2))
126569544Seric 				printf("failed\n");
126669544Seric 		}
126769544Seric 		c = c->q_alias;
126869544Seric 	}
126969544Seric 
127069544Seric 	if (tTd(27, 1))
127169544Seric 		printf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
127269544Seric 
127369544Seric 	return NULL;
127469544Seric }
1275