122710Sdist /*
234921Sbostic  * Copyright (c) 1983 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*68284Seric static char sccsid[] = "@(#)recipient.c	8.62 (Berkeley) 02/11/95";
1133731Sbostic #endif /* not lint */
1222710Sdist 
1358332Seric # include "sendmail.h"
144174Seric # include <pwd.h>
154174Seric 
164174Seric /*
179622Seric **  SENDTOLIST -- Designate a send list.
184174Seric **
194174Seric **	The parameter is a comma-separated list of people to send to.
204174Seric **	This routine arranges to send to all of them.
214174Seric **
224174Seric **	Parameters:
234174Seric **		list -- the send list.
244399Seric **		ctladdr -- the address template for the person to
254399Seric **			send to -- effective uid/gid are important.
265006Seric **			This is typically the alias that caused this
275006Seric **			expansion.
285006Seric **		sendq -- a pointer to the head of a queue to put
295006Seric **			these people into.
30*68284Seric **		aliaslevel -- the current alias nesting depth -- to
31*68284Seric **			diagnose loops.
3258247Seric **		e -- the envelope in which to add these recipients.
334174Seric **
344174Seric **	Returns:
3558082Seric **		The number of addresses actually on the list.
364174Seric **
374174Seric **	Side Effects:
384174Seric **		none.
394174Seric */
404174Seric 
41*68284Seric #define MAXRCRSN	10	/* maximum levels of alias recursion */
424174Seric 
43*68284Seric /* q_flags bits inherited from ctladdr */
44*68284Seric #define QINHERITEDBITS	(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHAS_RET_PARAM|QRET_HDRS)
45*68284Seric 
46*68284Seric int
47*68284Seric sendtolist(list, ctladdr, sendq, aliaslevel, e)
484174Seric 	char *list;
494399Seric 	ADDRESS *ctladdr;
505198Seric 	ADDRESS **sendq;
51*68284Seric 	int aliaslevel;
5255012Seric 	register ENVELOPE *e;
534174Seric {
544174Seric 	register char *p;
558223Seric 	register ADDRESS *al;	/* list of addresses to send to */
564423Seric 	bool firstone;		/* set on first address sent */
5711446Seric 	char delimiter;		/* the address delimiter */
5858082Seric 	int naddrs;
5963847Seric 	char *oldto = e->e_to;
6068271Seric 	static char *bufp = NULL;
6168271Seric 	static int buflen;
6268271Seric 	char buf[MAXNAME + 1];
634174Seric 
6464131Seric 	if (list == NULL)
6564131Seric 	{
6664131Seric 		syserr("sendtolist: null list");
6764131Seric 		return 0;
6864131Seric 	}
6964131Seric 
707676Seric 	if (tTd(25, 1))
714444Seric 	{
724444Seric 		printf("sendto: %s\n   ctladdr=", list);
734444Seric 		printaddr(ctladdr, FALSE);
744444Seric 	}
754324Seric 
768223Seric 	/* heuristic to determine old versus new style addresses */
778230Seric 	if (ctladdr == NULL &&
7856795Seric 	    (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
7956795Seric 	     strchr(list, '<') != NULL || strchr(list, '(') != NULL))
8055012Seric 		e->e_flags &= ~EF_OLDSTYLE;
8111446Seric 	delimiter = ' ';
8255012Seric 	if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL)
8311446Seric 		delimiter = ',';
848223Seric 
854423Seric 	firstone = TRUE;
864324Seric 	al = NULL;
8758082Seric 	naddrs = 0;
888223Seric 
8968271Seric 	if (buf == NULL)
904174Seric 	{
9168271Seric 		bufp = buf;
9268271Seric 		buflen = sizeof buf - 1;
9368271Seric 	}
9468271Seric 	if (strlen(list) > buflen)
9568271Seric 	{
9668271Seric 		/* allocate additional space */
9768271Seric 		if (bufp != buf)
9868271Seric 			free(bufp);
9968271Seric 		buflen = strlen(list);
10068271Seric 		bufp = malloc(buflen + 1);
10168271Seric 	}
10268271Seric 	strcpy(bufp, list);
10368271Seric 
10468271Seric 	for (p = bufp; *p != '\0'; )
10568271Seric 	{
10658333Seric 		auto char *delimptr;
1078081Seric 		register ADDRESS *a;
1084319Seric 
1098081Seric 		/* parse the address */
11058050Seric 		while ((isascii(*p) && isspace(*p)) || *p == ',')
1114174Seric 			p++;
11264284Seric 		a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e);
11358333Seric 		p = delimptr;
1149297Seric 		if (a == NULL)
1154174Seric 			continue;
1164324Seric 		a->q_next = al;
1174399Seric 		a->q_alias = ctladdr;
1184444Seric 
1194444Seric 		/* see if this should be marked as a primary address */
1204423Seric 		if (ctladdr == NULL ||
1218081Seric 		    (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags)))
1224423Seric 			a->q_flags |= QPRIMARY;
1234444Seric 
124*68284Seric 		/* arrange to inherit attributes from parent */
125*68284Seric 		if (ctladdr != NULL)
126*68284Seric 		{
127*68284Seric 			/* self reference test */
128*68284Seric 			if (sameaddr(ctladdr, a))
129*68284Seric 				ctladdr->q_flags |= QSELFREF;
130*68284Seric 
131*68284Seric 			/* full name */
132*68284Seric 			if (a->q_fullname == NULL)
133*68284Seric 				a->q_fullname = ctladdr->q_fullname;
134*68284Seric 
135*68284Seric 			/* various flag bits */
136*68284Seric 			a->q_flags &= ~QINHERITEDBITS;
137*68284Seric 			a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
138*68284Seric 
139*68284Seric 			/* original recipient information */
140*68284Seric 			a->q_orcpt = ctladdr->q_orcpt;
141*68284Seric 		}
142*68284Seric 
14357731Seric 		al = a;
1444423Seric 		firstone = FALSE;
1454324Seric 	}
1464324Seric 
1474324Seric 	/* arrange to send to everyone on the local send list */
1484324Seric 	while (al != NULL)
1494324Seric 	{
1504324Seric 		register ADDRESS *a = al;
1514324Seric 
1524324Seric 		al = a->q_next;
153*68284Seric 		a = recipient(a, sendq, aliaslevel, e);
15458082Seric 		naddrs++;
1554174Seric 	}
1564324Seric 
15763847Seric 	e->e_to = oldto;
15858082Seric 	return (naddrs);
1594174Seric }
1604174Seric /*
1614174Seric **  RECIPIENT -- Designate a message recipient
1624174Seric **
1634174Seric **	Saves the named person for future mailing.
1644174Seric **
1654174Seric **	Parameters:
1664174Seric **		a -- the (preparsed) address header for the recipient.
1675006Seric **		sendq -- a pointer to the head of a queue to put the
1685006Seric **			recipient in.  Duplicate supression is done
1695006Seric **			in this queue.
170*68284Seric **		aliaslevel -- the current alias nesting depth.
17157731Seric **		e -- the current envelope.
1724174Seric **
1734174Seric **	Returns:
17412613Seric **		The actual address in the queue.  This will be "a" if
17512613Seric **		the address is not a duplicate, else the original address.
1764174Seric **
1774174Seric **	Side Effects:
1784174Seric **		none.
1794174Seric */
1804174Seric 
18112613Seric ADDRESS *
182*68284Seric recipient(a, sendq, aliaslevel, e)
1834174Seric 	register ADDRESS *a;
1845006Seric 	register ADDRESS **sendq;
185*68284Seric 	int aliaslevel;
18655012Seric 	register ENVELOPE *e;
1874174Seric {
1884174Seric 	register ADDRESS *q;
1894319Seric 	ADDRESS **pq;
1904174Seric 	register struct mailer *m;
1919210Seric 	register char *p;
1929210Seric 	bool quoted = FALSE;		/* set if the addr has a quote bit */
19353735Seric 	int findusercount = 0;
194*68284Seric 	int i;
195*68284Seric 	char *buf;
196*68284Seric 	char buf0[MAXNAME];		/* unquoted image of the user name */
19758247Seric 	extern int safefile();
1984174Seric 
19955012Seric 	e->e_to = a->q_paddr;
2004600Seric 	m = a->q_mailer;
2014174Seric 	errno = 0;
2027676Seric 	if (tTd(26, 1))
2034444Seric 	{
2044444Seric 		printf("\nrecipient: ");
2054444Seric 		printaddr(a, FALSE);
2064444Seric 	}
2074174Seric 
20864146Seric 	/* if this is primary, add it to the original recipient list */
20964146Seric 	if (a->q_alias == NULL)
21064146Seric 	{
21164146Seric 		if (e->e_origrcpt == NULL)
21264146Seric 			e->e_origrcpt = a->q_paddr;
21364146Seric 		else if (e->e_origrcpt != a->q_paddr)
21464146Seric 			e->e_origrcpt = "";
21564146Seric 	}
21664146Seric 
2174174Seric 	/* break aliasing loops */
218*68284Seric 	if (aliaslevel > MAXRCRSN)
2194174Seric 	{
220*68284Seric 		usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max",
221*68284Seric 			aliaslevel, MAXRCRSN);
22212613Seric 		return (a);
2234174Seric 	}
2244174Seric 
2254174Seric 	/*
2264627Seric 	**  Finish setting up address structure.
2274174Seric 	*/
2284174Seric 
22916160Seric 	/* get unquoted user for file, program or user.name check */
230*68284Seric 	i = strlen(a->q_user);
231*68284Seric 	if (i >= sizeof buf)
232*68284Seric 		buf = xalloc(i + 1);
233*68284Seric 	else
234*68284Seric 		buf = buf0;
2359210Seric 	(void) strcpy(buf, a->q_user);
2369210Seric 	for (p = buf; *p != '\0' && !quoted; p++)
2379210Seric 	{
23854993Seric 		if (*p == '\\')
2399210Seric 			quoted = TRUE;
2409210Seric 	}
24154983Seric 	stripquotes(buf);
2429210Seric 
24357402Seric 	/* check for direct mailing to restricted mailers */
24465496Seric 	if (m == ProgMailer)
2454174Seric 	{
24665496Seric 		if (a->q_alias == NULL)
24765496Seric 		{
24865496Seric 			a->q_flags |= QBADADDR;
24965496Seric 			usrerr("550 Cannot mail directly to programs");
25065496Seric 		}
25165496Seric 		else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
25265496Seric 		{
25365496Seric 			a->q_flags |= QBADADDR;
25465496Seric 			usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs",
25565496Seric 				a->q_alias->q_ruser, MyHostName);
25665496Seric 		}
25765496Seric 		else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
25865496Seric 		{
25965496Seric 			a->q_flags |= QBADADDR;
26065496Seric 			usrerr("550 Address %s is unsafe for mailing to programs",
26165496Seric 				a->q_alias->q_paddr);
26265496Seric 		}
2634174Seric 	}
2644174Seric 
2654174Seric 	/*
2664419Seric 	**  Look up this person in the recipient list.
2674419Seric 	**	If they are there already, return, otherwise continue.
2684419Seric 	**	If the list is empty, just add it.  Notice the cute
2694419Seric 	**	hack to make from addresses suppress things correctly:
2704419Seric 	**	the QDONTSEND bit will be set in the send list.
2714419Seric 	**	[Please note: the emphasis is on "hack."]
2724174Seric 	*/
2734174Seric 
2745006Seric 	for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
2754174Seric 	{
27658294Seric 		if (sameaddr(q, a))
2774174Seric 		{
2787676Seric 			if (tTd(26, 1))
2794444Seric 			{
2804444Seric 				printf("%s in sendq: ", a->q_paddr);
2814444Seric 				printaddr(q, FALSE);
2824444Seric 			}
28365593Seric 			if (!bitset(QPRIMARY, q->q_flags))
28458065Seric 			{
28565593Seric 				if (!bitset(QDONTSEND, a->q_flags))
28658151Seric 					message("duplicate suppressed");
28765593Seric 				q->q_flags |= a->q_flags;
28865593Seric 			}
28965593Seric 			else if (bitset(QSELFREF, q->q_flags))
29065579Seric 				q->q_flags |= a->q_flags & ~QDONTSEND;
29163847Seric 			a = q;
292*68284Seric 			goto done;
2934174Seric 		}
2944319Seric 	}
2954174Seric 
2964319Seric 	/* add address on list */
29758884Seric 	*pq = a;
29858884Seric 	a->q_next = NULL;
2994174Seric 
3004174Seric 	/*
30157402Seric 	**  Alias the name and handle special mailer types.
3024174Seric 	*/
3034174Seric 
30453735Seric   trylocaluser:
30555354Seric 	if (tTd(29, 7))
30655354Seric 		printf("at trylocaluser %s\n", a->q_user);
30755354Seric 
30858680Seric 	if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
30963847Seric 		goto testselfdestruct;
31057402Seric 
31157402Seric 	if (m == InclMailer)
3124174Seric 	{
31357402Seric 		a->q_flags |= QDONTSEND;
31464761Seric 		if (a->q_alias == NULL)
3154174Seric 		{
31658680Seric 			a->q_flags |= QBADADDR;
31758151Seric 			usrerr("550 Cannot mail directly to :include:s");
3184174Seric 		}
3194174Seric 		else
32050556Seric 		{
32159563Seric 			int ret;
32258247Seric 
32358151Seric 			message("including file %s", a->q_user);
324*68284Seric 			ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e);
32559563Seric 			if (transienterror(ret))
32659563Seric 			{
32759563Seric #ifdef LOG
32859563Seric 				if (LogLevel > 2)
32966239Seric 					syslog(LOG_ERR, "%s: include %s: transient error: %s",
33066284Seric 						e->e_id == NULL ? "NOQUEUE" : e->e_id,
33166284Seric 						a->q_user, errstring(ret));
33259563Seric #endif
33363853Seric 				a->q_flags |= QQUEUEUP;
33465215Seric 				a->q_flags &= ~QDONTSEND;
33559563Seric 				usrerr("451 Cannot open %s: %s",
33659563Seric 					a->q_user, errstring(ret));
33759563Seric 			}
33859563Seric 			else if (ret != 0)
33959563Seric 			{
34063938Seric 				a->q_flags |= QBADADDR;
34159563Seric 				usrerr("550 Cannot open %s: %s",
34259563Seric 					a->q_user, errstring(ret));
34359563Seric 			}
34450556Seric 		}
3454174Seric 	}
34657642Seric 	else if (m == FileMailer)
3474174Seric 	{
3484329Seric 		extern bool writable();
3494174Seric 
35051317Seric 		/* check if writable or creatable */
35164761Seric 		if (a->q_alias == NULL)
3524174Seric 		{
35358680Seric 			a->q_flags |= QBADADDR;
35458151Seric 			usrerr("550 Cannot mail directly to files");
3554174Seric 		}
35665496Seric 		else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
35765496Seric 		{
35865496Seric 			a->q_flags |= QBADADDR;
35965496Seric 			usrerr("550 User %s@%s doesn't have a valid shell for mailing to files",
36065496Seric 				a->q_alias->q_ruser, MyHostName);
36165496Seric 		}
36265496Seric 		else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
36365496Seric 		{
36465496Seric 			a->q_flags |= QBADADDR;
36565496Seric 			usrerr("550 Address %s is unsafe for mailing to files",
36665496Seric 				a->q_alias->q_paddr);
36765496Seric 		}
36865112Seric 		else if (!writable(buf, getctladdr(a), SFF_ANYFILE))
36951317Seric 		{
37058680Seric 			a->q_flags |= QBADADDR;
371*68284Seric 			giveresponse(EX_CANTCREAT, m, NULL, a->q_alias,
372*68284Seric 				     (time_t) 0, e);
37351317Seric 		}
37451317Seric 	}
37551317Seric 
37657402Seric 	/* try aliasing */
377*68284Seric 	if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags))
378*68284Seric 		alias(a, sendq, aliaslevel, e);
37957402Seric 
38057402Seric # ifdef USERDB
38157402Seric 	/* if not aliased, look it up in the user database */
382*68284Seric 	if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) &&
383*68284Seric 	    bitnset(M_CHECKUDB, m->m_flags))
38457402Seric 	{
38557402Seric 		extern int udbexpand();
38657402Seric 
387*68284Seric 		if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL)
38857402Seric 		{
38963853Seric 			a->q_flags |= QQUEUEUP;
39057402Seric 			if (e->e_message == NULL)
39157402Seric 				e->e_message = newstr("Deferred: user database error");
39257402Seric # ifdef LOG
39358020Seric 			if (LogLevel > 8)
39459623Seric 				syslog(LOG_INFO, "%s: deferred: udbexpand: %s",
39566284Seric 					e->e_id == NULL ? "NOQUEUE" : e->e_id,
39666284Seric 					errstring(errno));
39757402Seric # endif
39859615Seric 			message("queued (user database error): %s",
39959615Seric 				errstring(errno));
40057642Seric 			e->e_nrcpts++;
40163847Seric 			goto testselfdestruct;
40257402Seric 		}
40357402Seric 	}
40457402Seric # endif
40557402Seric 
40651317Seric 	/*
40751317Seric 	**  If we have a level two config file, then pass the name through
40851317Seric 	**  Ruleset 5 before sending it off.  Ruleset 5 has the right
40951317Seric 	**  to send rewrite it to another mailer.  This gives us a hook
41051317Seric 	**  after local aliasing has been done.
41151317Seric 	*/
41251317Seric 
41351317Seric 	if (tTd(29, 5))
41451317Seric 	{
41551317Seric 		printf("recipient: testing local?  cl=%d, rr5=%x\n\t",
41651317Seric 			ConfigLevel, RewriteRules[5]);
41751317Seric 		printaddr(a, FALSE);
41851317Seric 	}
419*68284Seric 	if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
420*68284Seric 	    ConfigLevel >= 2 && RewriteRules[5] != NULL &&
421*68284Seric 	    bitnset(M_TRYRULESET5, m->m_flags))
42251317Seric 	{
423*68284Seric 		maplocaluser(a, sendq, aliaslevel, e);
42451317Seric 	}
42551317Seric 
42651317Seric 	/*
42751317Seric 	**  If it didn't get rewritten to another mailer, go ahead
42851317Seric 	**  and deliver it.
42951317Seric 	*/
43051317Seric 
431*68284Seric 	if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
432*68284Seric 	    bitnset(M_HASPWENT, m->m_flags))
43351317Seric 	{
43455354Seric 		auto bool fuzzy;
43551317Seric 		register struct passwd *pw;
43651317Seric 		extern struct passwd *finduser();
43751317Seric 
43851317Seric 		/* warning -- finduser may trash buf */
43955354Seric 		pw = finduser(buf, &fuzzy);
44051317Seric 		if (pw == NULL)
44151317Seric 		{
44258680Seric 			a->q_flags |= QBADADDR;
443*68284Seric 			giveresponse(EX_NOUSER, m, NULL, a->q_alias,
444*68284Seric 				     (time_t) 0, e);
44551317Seric 		}
4464174Seric 		else
4474174Seric 		{
44851317Seric 			char nbuf[MAXNAME];
4494373Seric 
45055354Seric 			if (fuzzy)
4514174Seric 			{
45253735Seric 				/* name was a fuzzy match */
45351317Seric 				a->q_user = newstr(pw->pw_name);
45453735Seric 				if (findusercount++ > 3)
45553735Seric 				{
45658680Seric 					a->q_flags |= QBADADDR;
45758151Seric 					usrerr("554 aliasing/forwarding loop for %s broken",
45853735Seric 						pw->pw_name);
459*68284Seric 					goto done;
46053735Seric 				}
46153735Seric 
46253735Seric 				/* see if it aliases */
46351317Seric 				(void) strcpy(buf, pw->pw_name);
46453735Seric 				goto trylocaluser;
4654174Seric 			}
46665822Seric 			if (strcmp(pw->pw_dir, "/") == 0)
46765822Seric 				a->q_home = "";
46865822Seric 			else
46965822Seric 				a->q_home = newstr(pw->pw_dir);
47051317Seric 			a->q_uid = pw->pw_uid;
47151317Seric 			a->q_gid = pw->pw_gid;
47259083Seric 			a->q_ruser = newstr(pw->pw_name);
47351317Seric 			a->q_flags |= QGOODUID;
47451317Seric 			buildfname(pw->pw_gecos, pw->pw_name, nbuf);
47551317Seric 			if (nbuf[0] != '\0')
47651317Seric 				a->q_fullname = newstr(nbuf);
47765211Seric 			if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' &&
47865211Seric 			    !usershellok(pw->pw_shell))
47965206Seric 			{
48065211Seric 				a->q_flags |= QBOGUSSHELL;
48165206Seric 			}
48251317Seric 			if (!quoted)
483*68284Seric 				forward(a, sendq, aliaslevel, e);
4844174Seric 		}
4854174Seric 	}
48657642Seric 	if (!bitset(QDONTSEND, a->q_flags))
48757642Seric 		e->e_nrcpts++;
48863847Seric 
48963847Seric   testselfdestruct:
49063978Seric 	if (tTd(26, 8))
49163847Seric 	{
49263978Seric 		printf("testselfdestruct: ");
49363978Seric 		printaddr(a, TRUE);
49463978Seric 	}
49563978Seric 	if (a->q_alias == NULL && a != &e->e_from &&
49663978Seric 	    bitset(QDONTSEND, a->q_flags))
49763978Seric 	{
49863978Seric 		q = *sendq;
49963965Seric 		while (q != NULL && bitset(QDONTSEND, q->q_flags))
50063847Seric 			q = q->q_next;
50163978Seric 		if (q == NULL)
50263847Seric 		{
50363847Seric 			a->q_flags |= QBADADDR;
50463847Seric 			usrerr("554 aliasing/forwarding loop broken");
50563847Seric 		}
50663847Seric 	}
507*68284Seric 
508*68284Seric   done:
509*68284Seric 	if (buf != buf0)
510*68284Seric 		free(buf);
51112613Seric 	return (a);
5124174Seric }
5134174Seric /*
5144373Seric **  FINDUSER -- find the password entry for a user.
5154373Seric **
5164373Seric **	This looks a lot like getpwnam, except that it may want to
5174373Seric **	do some fancier pattern matching in /etc/passwd.
5184373Seric **
5199379Seric **	This routine contains most of the time of many sendmail runs.
5209379Seric **	It deserves to be optimized.
5219379Seric **
5224373Seric **	Parameters:
5234373Seric **		name -- the name to match against.
52455354Seric **		fuzzyp -- an outarg that is set to TRUE if this entry
52555354Seric **			was found using the fuzzy matching algorithm;
52655354Seric **			set to FALSE otherwise.
5274373Seric **
5284373Seric **	Returns:
5294373Seric **		A pointer to a pw struct.
5304373Seric **		NULL if name is unknown or ambiguous.
5314373Seric **
5324373Seric **	Side Effects:
5334407Seric **		may modify name.
5344373Seric */
5354373Seric 
5364373Seric struct passwd *
53755354Seric finduser(name, fuzzyp)
5384373Seric 	char *name;
53955354Seric 	bool *fuzzyp;
5404373Seric {
5414376Seric 	register struct passwd *pw;
5424407Seric 	register char *p;
54315325Seric 	extern struct passwd *getpwent();
54415325Seric 	extern struct passwd *getpwnam();
5454373Seric 
54655354Seric 	if (tTd(29, 4))
54755354Seric 		printf("finduser(%s): ", name);
54855354Seric 
54955354Seric 	*fuzzyp = FALSE;
5504407Seric 
551*68284Seric #ifdef HESIOD
55264673Seric 	/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
55364673Seric 	for (p = name; *p != '\0'; p++)
55464673Seric 		if (!isascii(*p) || !isdigit(*p))
55564673Seric 			break;
55664673Seric 	if (*p == '\0')
55764673Seric 	{
55864673Seric 		if (tTd(29, 4))
55964673Seric 			printf("failed (numeric input)\n");
56064673Seric 		return NULL;
56164673Seric 	}
562*68284Seric #endif
56364673Seric 
56425777Seric 	/* look up this login name using fast path */
56512634Seric 	if ((pw = getpwnam(name)) != NULL)
56655354Seric 	{
56755354Seric 		if (tTd(29, 4))
56855354Seric 			printf("found (non-fuzzy)\n");
56912634Seric 		return (pw);
57055354Seric 	}
57112634Seric 
57253735Seric #ifdef MATCHGECOS
57353735Seric 	/* see if fuzzy matching allowed */
57453735Seric 	if (!MatchGecos)
57555354Seric 	{
57655354Seric 		if (tTd(29, 4))
57755354Seric 			printf("not found (fuzzy disabled)\n");
57853735Seric 		return NULL;
57955354Seric 	}
58053735Seric 
58112634Seric 	/* search for a matching full name instead */
58225777Seric 	for (p = name; *p != '\0'; p++)
58325777Seric 	{
58425777Seric 		if (*p == (SpaceSub & 0177) || *p == '_')
58525777Seric 			*p = ' ';
58625777Seric 	}
58723107Seric 	(void) setpwent();
5884376Seric 	while ((pw = getpwent()) != NULL)
5894376Seric 	{
5904998Seric 		char buf[MAXNAME];
5914376Seric 
5924998Seric 		buildfname(pw->pw_gecos, pw->pw_name, buf);
59356795Seric 		if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name))
5944381Seric 		{
59555354Seric 			if (tTd(29, 4))
59655354Seric 				printf("fuzzy matches %s\n", pw->pw_name);
59758151Seric 			message("sending to login name %s", pw->pw_name);
59855354Seric 			*fuzzyp = TRUE;
5994376Seric 			return (pw);
6004377Seric 		}
6014376Seric 	}
60255354Seric 	if (tTd(29, 4))
60355354Seric 		printf("no fuzzy match found\n");
60459015Seric #else
60559015Seric 	if (tTd(29, 4))
60659015Seric 		printf("not found (fuzzy disabled)\n");
60759015Seric #endif
6084376Seric 	return (NULL);
6094373Seric }
6104373Seric /*
6114329Seric **  WRITABLE -- predicate returning if the file is writable.
6124329Seric **
6134329Seric **	This routine must duplicate the algorithm in sys/fio.c.
6144329Seric **	Unfortunately, we cannot use the access call since we
6154329Seric **	won't necessarily be the real uid when we try to
6164329Seric **	actually open the file.
6174329Seric **
6184329Seric **	Notice that ANY file with ANY execute bit is automatically
6194329Seric **	not writable.  This is also enforced by mailfile.
6204329Seric **
6214329Seric **	Parameters:
62265064Seric **		filename -- the file name to check.
62365112Seric **		ctladdr -- the controlling address for this file.
62465064Seric **		flags -- SFF_* flags to control the function.
6254329Seric **
6264329Seric **	Returns:
6274329Seric **		TRUE -- if we will be able to write this file.
6284329Seric **		FALSE -- if we cannot write this file.
6294329Seric **
6304329Seric **	Side Effects:
6314329Seric **		none.
6324329Seric */
6334329Seric 
6344329Seric bool
63565112Seric writable(filename, ctladdr, flags)
63664819Seric 	char *filename;
63765112Seric 	ADDRESS *ctladdr;
63865064Seric 	int flags;
6394329Seric {
64055372Seric 	uid_t euid;
64155372Seric 	gid_t egid;
6424329Seric 	int bits;
64364944Seric 	register char *p;
64464944Seric 	char *uname;
64564944Seric 	struct stat stb;
64664944Seric 	extern char RealUserName[];
6474329Seric 
64864819Seric 	if (tTd(29, 5))
64965064Seric 		printf("writable(%s, %x)\n", filename, flags);
65064944Seric 
65164944Seric #ifdef HASLSTAT
65265064Seric 	if ((bitset(SFF_NOSLINK, flags) ? lstat(filename, &stb)
65365064Seric 					: stat(filename, &stb)) < 0)
65464944Seric #else
65564944Seric 	if (stat(filename, &stb) < 0)
65664944Seric #endif
65764944Seric 	{
65864944Seric 		/* file does not exist -- see if directory is safe */
65964944Seric 		p = strrchr(filename, '/');
66064944Seric 		if (p == NULL)
66164944Seric 		{
66265067Seric 			errno = ENOTDIR;
66364944Seric 			return FALSE;
66464944Seric 		}
66565067Seric 		*p = '\0';
66665067Seric 		errno = safefile(filename, RealUid, RealGid, RealUserName,
66765067Seric 				 SFF_MUSTOWN, S_IWRITE|S_IEXEC);
66864944Seric 		*p = '/';
66965067Seric 		return errno == 0;
67064944Seric 	}
67164944Seric 
67265225Seric #ifdef SUID_ROOT_FILES_OK
67365225Seric 	/* really ought to be passed down -- and not a good idea */
67465225Seric 	flags |= SFF_ROOTOK;
67565225Seric #endif
67665225Seric 
67764944Seric 	/*
67864944Seric 	**  File does exist -- check that it is writable.
67964944Seric 	*/
68064944Seric 
68164944Seric 	if (bitset(0111, stb.st_mode))
68265022Seric 	{
68365022Seric 		if (tTd(29, 5))
68465022Seric 			printf("failed (mode %o: x bits)\n", stb.st_mode);
68565067Seric 		errno = EPERM;
6864329Seric 		return (FALSE);
68765022Seric 	}
68864944Seric 
68965112Seric 	if (ctladdr != NULL && geteuid() == 0)
69064944Seric 	{
69165112Seric 		euid = ctladdr->q_uid;
69265112Seric 		egid = ctladdr->q_gid;
69365112Seric 		uname = ctladdr->q_user;
69464944Seric 	}
695*68284Seric #ifdef RUN_AS_REAL_UID
69665112Seric 	else
69765112Seric 	{
69865112Seric 		euid = RealUid;
69965112Seric 		egid = RealGid;
70065112Seric 		uname = RealUserName;
70165112Seric 	}
702*68284Seric #else
703*68284Seric 	else if (FileMailer != NULL)
704*68284Seric 	{
705*68284Seric 		euid = FileMailer->m_uid;
706*68284Seric 		egid = FileMailer->m_gid;
707*68284Seric 	}
708*68284Seric 	else
709*68284Seric 	{
710*68284Seric 		euid = egid = 0;
711*68284Seric 	}
712*68284Seric #endif
71365138Seric 	if (euid == 0)
71465138Seric 	{
71565138Seric 		euid = DefUid;
71665138Seric 		uname = DefUser;
71765138Seric 	}
71865138Seric 	if (egid == 0)
71965138Seric 		egid = DefGid;
7204329Seric 	if (geteuid() == 0)
7214329Seric 	{
72265225Seric 		if (bitset(S_ISUID, stb.st_mode) &&
72365225Seric 		    (stb.st_uid != 0 || bitset(SFF_ROOTOK, flags)))
72464944Seric 		{
72564944Seric 			euid = stb.st_uid;
72664944Seric 			uname = NULL;
72764944Seric 		}
72865225Seric 		if (bitset(S_ISGID, stb.st_mode) &&
72965225Seric 		    (stb.st_gid != 0 || bitset(SFF_ROOTOK, flags)))
73064944Seric 			egid = stb.st_gid;
7314329Seric 	}
7324329Seric 
73364819Seric 	if (tTd(29, 5))
73464819Seric 		printf("\teu/gid=%d/%d, st_u/gid=%d/%d\n",
73564944Seric 			euid, egid, stb.st_uid, stb.st_gid);
73664819Seric 
73765067Seric 	errno = safefile(filename, euid, egid, uname, flags, S_IWRITE);
73865067Seric 	return errno == 0;
7394329Seric }
7404329Seric /*
7414174Seric **  INCLUDE -- handle :include: specification.
7424174Seric **
7434174Seric **	Parameters:
7444174Seric **		fname -- filename to include.
74553037Seric **		forwarding -- if TRUE, we are reading a .forward file.
74653037Seric **			if FALSE, it's a :include: file.
7474399Seric **		ctladdr -- address template to use to fill in these
7484399Seric **			addresses -- effective user/group id are
7494399Seric **			the important things.
7505006Seric **		sendq -- a pointer to the head of the send queue
7515006Seric **			to put these addresses in.
752*68284Seric **		aliaslevel -- the alias nesting depth.
753*68284Seric **		e -- the current envelope.
7544174Seric **
7554174Seric **	Returns:
75657136Seric **		open error status
7574174Seric **
7584174Seric **	Side Effects:
7594174Seric **		reads the :include: file and sends to everyone
7604174Seric **		listed in that file.
76165909Seric **
76265909Seric **	Security Note:
76365909Seric **		If you have restricted chown (that is, you can't
76465909Seric **		give a file away), it is reasonable to allow programs
76565909Seric **		and files called from this :include: file to be to be
76665909Seric **		run as the owner of the :include: file.  This is bogus
76765909Seric **		if there is any chance of someone giving away a file.
76865909Seric **		We assume that pre-POSIX systems can give away files.
76965909Seric **
77065909Seric **		There is an additional restriction that if you
77165909Seric **		forward to a :include: file, it will not take on
77265909Seric **		the ownership of the :include: file.  This may not
77365909Seric **		be necessary, but shouldn't hurt.
7744174Seric */
7754174Seric 
77653037Seric static jmp_buf	CtxIncludeTimeout;
77763937Seric static int	includetimeout();
77853037Seric 
77965496Seric #ifndef S_IWOTH
78065496Seric # define S_IWOTH	(S_IWRITE >> 6)
78165496Seric #endif
78265496Seric 
78357136Seric int
784*68284Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
7854174Seric 	char *fname;
78653037Seric 	bool forwarding;
7874399Seric 	ADDRESS *ctladdr;
7885006Seric 	ADDRESS **sendq;
789*68284Seric 	int aliaslevel;
79055012Seric 	ENVELOPE *e;
7914174Seric {
79264570Seric 	register FILE *fp = NULL;
79355012Seric 	char *oldto = e->e_to;
7949379Seric 	char *oldfilename = FileName;
7959379Seric 	int oldlinenumber = LineNumber;
79653037Seric 	register EVENT *ev = NULL;
79758082Seric 	int nincludes;
79864325Seric 	register ADDRESS *ca;
79964325Seric 	uid_t saveduid, uid;
80064325Seric 	gid_t savedgid, gid;
80164083Seric 	char *uname;
80264325Seric 	int rval = 0;
80365064Seric 	int sfflags = forwarding ? SFF_MUSTOWN : SFF_ANYFILE;
80465496Seric 	struct stat st;
80565948Seric 	char buf[MAXLINE];
80665909Seric #ifdef _POSIX_CHOWN_RESTRICTED
80765948Seric # if _POSIX_CHOWN_RESTRICTED == -1
80865948Seric #  define safechown	FALSE
80965948Seric # else
81065948Seric #  define safechown	TRUE
81165948Seric # endif
81265948Seric #else
81365948Seric # ifdef _PC_CHOWN_RESTRICTED
81465909Seric 	bool safechown;
81565948Seric # else
81665948Seric #  ifdef BSD
81765948Seric #   define safechown	TRUE
81865948Seric #  else
81965948Seric #   define safechown	FALSE
82065948Seric #  endif
82165948Seric # endif
82265909Seric #endif
82365948Seric 	extern bool chownsafe();
8244174Seric 
82557186Seric 	if (tTd(27, 2))
82657186Seric 		printf("include(%s)\n", fname);
82763902Seric 	if (tTd(27, 4))
82863902Seric 		printf("   ruid=%d euid=%d\n", getuid(), geteuid());
82963581Seric 	if (tTd(27, 14))
83063581Seric 	{
83163581Seric 		printf("ctladdr ");
83263581Seric 		printaddr(ctladdr, FALSE);
83363581Seric 	}
83457186Seric 
83564325Seric 	if (tTd(27, 9))
83664325Seric 		printf("include: old uid = %d/%d\n", getuid(), geteuid());
83753037Seric 
83863581Seric 	ca = getctladdr(ctladdr);
83963581Seric 	if (ca == NULL)
84064083Seric 	{
84164846Seric 		uid = DefUid;
84264846Seric 		gid = DefGid;
84364846Seric 		uname = DefUser;
84464325Seric 		saveduid = -1;
84564083Seric 	}
84663581Seric 	else
84764083Seric 	{
84863581Seric 		uid = ca->q_uid;
84964083Seric 		gid = ca->q_gid;
85064083Seric 		uname = ca->q_user;
85164325Seric #ifdef HASSETREUID
85264325Seric 		saveduid = geteuid();
85364325Seric 		savedgid = getegid();
85464325Seric 		if (saveduid == 0)
85564325Seric 		{
85664325Seric 			initgroups(uname, gid);
85764325Seric 			if (uid != 0)
858*68284Seric 			{
859*68284Seric 				if (setreuid(0, uid) < 0)
860*68284Seric 					syserr("setreuid(0, %d) failure (real=%d, eff=%d)",
861*68284Seric 						uid, getuid(), geteuid());
862*68284Seric 				else
863*68284Seric 					sfflags |= SFF_NOPATHCHECK;
864*68284Seric 			}
86564325Seric 		}
86664325Seric #endif
86764083Seric 	}
86863581Seric 
86964325Seric 	if (tTd(27, 9))
87064325Seric 		printf("include: new uid = %d/%d\n", getuid(), geteuid());
87164325Seric 
87264325Seric 	/*
87364325Seric 	**  If home directory is remote mounted but server is down,
87464325Seric 	**  this can hang or give errors; use a timeout to avoid this
87564325Seric 	*/
87664325Seric 
87753037Seric 	if (setjmp(CtxIncludeTimeout) != 0)
87853037Seric 	{
87963853Seric 		ctladdr->q_flags |= QQUEUEUP;
88053037Seric 		errno = 0;
88163993Seric 
88263993Seric 		/* return pseudo-error code */
88364325Seric 		rval = EOPENTIMEOUT;
88464325Seric 		goto resetuid;
88553037Seric 	}
886*68284Seric 	if (TimeOuts.to_fileopen > 0)
887*68284Seric 		ev = setevent(TimeOuts.to_fileopen, includetimeout, 0);
888*68284Seric 	else
889*68284Seric 		ev = NULL;
89053037Seric 
89163581Seric 	/* the input file must be marked safe */
89264944Seric 	rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD);
89364329Seric 	if (rval != 0)
89453037Seric 	{
89564325Seric 		/* don't use this :include: file */
89657186Seric 		if (tTd(27, 4))
89758247Seric 			printf("include: not safe (uid=%d): %s\n",
89864329Seric 				uid, errstring(rval));
89953037Seric 	}
90065496Seric 	else
9014174Seric 	{
90265496Seric 		fp = fopen(fname, "r");
90365496Seric 		if (fp == NULL)
90458061Seric 		{
90564329Seric 			rval = errno;
90665496Seric 			if (tTd(27, 4))
90765496Seric 				printf("include: open: %s\n", errstring(rval));
90858061Seric 		}
9094406Seric 	}
910*68284Seric 	if (ev != NULL)
911*68284Seric 		clrevent(ev);
91253037Seric 
91364570Seric resetuid:
91464570Seric 
91564570Seric #ifdef HASSETREUID
91664570Seric 	if (saveduid == 0)
91764570Seric 	{
91864570Seric 		if (uid != 0)
919*68284Seric 		{
920*68284Seric 			if (setreuid(-1, 0) < 0)
921*68284Seric 				syserr("setreuid(-1, 0) failure (real=%d, eff=%d)",
922*68284Seric 					getuid(), geteuid());
923*68284Seric 			if (setreuid(RealUid, 0) < 0)
92464570Seric 				syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
92564570Seric 					RealUid, getuid(), geteuid());
926*68284Seric 		}
92764570Seric 		setgid(savedgid);
92864570Seric 	}
92964570Seric #endif
93064570Seric 
93164570Seric 	if (tTd(27, 9))
93264570Seric 		printf("include: reset uid = %d/%d\n", getuid(), geteuid());
93364570Seric 
93465593Seric 	if (rval == EOPENTIMEOUT)
93565593Seric 		usrerr("451 open timeout on %s", fname);
93665593Seric 
93764570Seric 	if (fp == NULL)
93864570Seric 		return rval;
93964570Seric 
94065496Seric 	if (fstat(fileno(fp), &st) < 0)
94165496Seric 	{
94265496Seric 		rval = errno;
94365496Seric 		syserr("Cannot fstat %s!", fname);
94465496Seric 		return rval;
94565496Seric 	}
94665496Seric 
94765948Seric #ifndef safechown
94865948Seric 	safechown = chownsafe(fileno(fp));
94965948Seric #endif
95065909Seric 	if (ca == NULL && safechown)
95165496Seric 	{
95265496Seric 		ctladdr->q_uid = st.st_uid;
95365496Seric 		ctladdr->q_gid = st.st_gid;
95465496Seric 		ctladdr->q_flags |= QGOODUID;
95565496Seric 	}
95665496Seric 	if (ca != NULL && ca->q_uid == st.st_uid)
95765496Seric 	{
95865496Seric 		/* optimization -- avoid getpwuid if we already have info */
95965496Seric 		ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
96065496Seric 		ctladdr->q_ruser = ca->q_ruser;
96165496Seric 	}
96265496Seric 	else
96365496Seric 	{
96465496Seric 		register struct passwd *pw;
96565496Seric 
96665496Seric 		pw = getpwuid(st.st_uid);
967*68284Seric 		if (pw == NULL)
968*68284Seric 			ctladdr->q_flags |= QBOGUSSHELL;
969*68284Seric 		else
97068268Seric 		{
971*68284Seric 			char *sh;
972*68284Seric 
97368268Seric 			ctladdr->q_ruser = newstr(pw->pw_name);
97468268Seric 			if (safechown)
97568268Seric 				sh = pw->pw_shell;
97665909Seric 			else
977*68284Seric 				sh = "/SENDMAIL/ANY/SHELL/";
978*68284Seric 			if (!usershellok(sh))
979*68284Seric 			{
980*68284Seric 				if (safechown)
981*68284Seric 					ctladdr->q_flags |= QBOGUSSHELL;
982*68284Seric 				else
983*68284Seric 					ctladdr->q_flags |= QUNSAFEADDR;
984*68284Seric 			}
98565496Seric 		}
98665496Seric 	}
98765496Seric 
98858092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
98958092Seric 	{
99058092Seric 		/* don't do any more now */
99158868Seric 		ctladdr->q_flags |= QVERIFIED;
99258884Seric 		e->e_nrcpts++;
99358680Seric 		xfclose(fp, "include", fname);
99464570Seric 		return rval;
99558092Seric 	}
99658092Seric 
99765496Seric 	/*
99865496Seric 	** Check to see if some bad guy can write this file
99965496Seric 	**
100065496Seric 	**	This should really do something clever with group
100165496Seric 	**	permissions; currently we just view world writable
100265496Seric 	**	as unsafe.  Also, we don't check for writable
100365496Seric 	**	directories in the path.  We've got to leave
100465496Seric 	**	something for the local sysad to do.
100565496Seric 	*/
100665496Seric 
100765496Seric 	if (bitset(S_IWOTH, st.st_mode))
100865496Seric 		ctladdr->q_flags |= QUNSAFEADDR;
100965496Seric 
10104174Seric 	/* read the file -- each line is a comma-separated list. */
10119379Seric 	FileName = fname;
10129379Seric 	LineNumber = 0;
101358082Seric 	ctladdr->q_flags &= ~QSELFREF;
101458082Seric 	nincludes = 0;
10154174Seric 	while (fgets(buf, sizeof buf, fp) != NULL)
10164174Seric 	{
101756795Seric 		register char *p = strchr(buf, '\n');
10184174Seric 
101940963Sbostic 		LineNumber++;
10204174Seric 		if (p != NULL)
10214174Seric 			*p = '\0';
102257186Seric 		if (buf[0] == '#' || buf[0] == '\0')
102357139Seric 			continue;
102458008Seric 		e->e_to = NULL;
102558151Seric 		message("%s to %s",
102653037Seric 			forwarding ? "forwarding" : "sending", buf);
102757977Seric #ifdef LOG
102858020Seric 		if (forwarding && LogLevel > 9)
102957977Seric 			syslog(LOG_INFO, "%s: forward %s => %s",
103066284Seric 				e->e_id == NULL ? "NOQUEUE" : e->e_id,
103166284Seric 				oldto, buf);
103257977Seric #endif
103357977Seric 
1034*68284Seric 		nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e);
10354174Seric 	}
103663902Seric 
103763902Seric 	if (ferror(fp) && tTd(27, 3))
103863902Seric 		printf("include: read error: %s\n", errstring(errno));
103958082Seric 	if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
104058065Seric 	{
104158065Seric 		if (tTd(27, 5))
104258065Seric 		{
104358065Seric 			printf("include: QDONTSEND ");
104458065Seric 			printaddr(ctladdr, FALSE);
104558065Seric 		}
104658065Seric 		ctladdr->q_flags |= QDONTSEND;
104758065Seric 	}
10484174Seric 
104958680Seric 	(void) xfclose(fp, "include", fname);
10509379Seric 	FileName = oldfilename;
10519379Seric 	LineNumber = oldlinenumber;
105263847Seric 	e->e_to = oldto;
105364325Seric 	return rval;
10544174Seric }
105553037Seric 
105653037Seric static
105753037Seric includetimeout()
105853037Seric {
105953037Seric 	longjmp(CtxIncludeTimeout, 1);
106053037Seric }
10614324Seric /*
10624324Seric **  SENDTOARGV -- send to an argument vector.
10634324Seric **
10644324Seric **	Parameters:
10654324Seric **		argv -- argument vector to send to.
106658247Seric **		e -- the current envelope.
10674324Seric **
10684324Seric **	Returns:
10694324Seric **		none.
10704324Seric **
10714324Seric **	Side Effects:
10724324Seric **		puts all addresses on the argument vector onto the
10734324Seric **			send queue.
10744324Seric */
10754324Seric 
107655012Seric sendtoargv(argv, e)
10774324Seric 	register char **argv;
107855012Seric 	register ENVELOPE *e;
10794324Seric {
10804324Seric 	register char *p;
10814324Seric 
10824324Seric 	while ((p = *argv++) != NULL)
10834324Seric 	{
1084*68284Seric 		(void) sendtolist(denlstring(p), NULLADDR,
1085*68284Seric 				  &e->e_sendqueue, 0, e);
10864324Seric 	}
10874324Seric }
10884399Seric /*
10894399Seric **  GETCTLADDR -- get controlling address from an address header.
10904399Seric **
10914399Seric **	If none, get one corresponding to the effective userid.
10924399Seric **
10934399Seric **	Parameters:
10944399Seric **		a -- the address to find the controller of.
10954399Seric **
10964399Seric **	Returns:
10974399Seric **		the controlling address.
10984399Seric **
10994399Seric **	Side Effects:
11004399Seric **		none.
11014399Seric */
11024399Seric 
11034399Seric ADDRESS *
11044399Seric getctladdr(a)
11054399Seric 	register ADDRESS *a;
11064399Seric {
11074404Seric 	while (a != NULL && !bitset(QGOODUID, a->q_flags))
11084399Seric 		a = a->q_alias;
11094399Seric 	return (a);
11104399Seric }
1111