1292Seric # include <pwd.h>
24212Seric # include <sys/types.h>
34212Seric # include <sys/stat.h>
43309Seric # include "sendmail.h"
5292Seric 
64106Seric # ifdef DBM
7*6973Seric SCCSID(@(#)alias.c	3.31.1.1		05/29/82	(with DBM));
84106Seric # else DBM
9*6973Seric SCCSID(@(#)alias.c	3.31.1.1		05/29/82	(without DBM));
104106Seric # endif DBM
11402Seric 
12292Seric /*
13292Seric **  ALIAS -- Compute aliases.
14292Seric **
154098Seric **	Scans the file /usr/lib/aliases for a set of aliases.
163185Seric **	If found, it arranges to deliver to them.  Uses libdbm
173185Seric **	database if -DDBM.
18292Seric **
19292Seric **	Parameters:
204097Seric **		a -- address to alias.
214999Seric **		sendq -- a pointer to the head of the send queue
224999Seric **			to put the aliases in.
23292Seric **
24292Seric **	Returns:
25292Seric **		none
26292Seric **
27292Seric **	Side Effects:
283185Seric **		Aliases found are expanded.
29292Seric **
30292Seric **	Files:
314098Seric **		/usr/lib/aliases -- the mail aliases.  The format is
32569Seric **			a series of lines of the form:
33569Seric **				alias:name1,name2,name3,...
34569Seric **			where 'alias' expands to all of
35569Seric **			'name[i]'.  Continuations begin with
36569Seric **			space or tab.
374098Seric **		/usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version
381503Smark **			of alias file.  Keys are aliases, datums
391503Smark **			(data?) are name1,name2, ...
40292Seric **
41292Seric **	Notes:
42292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
43292Seric **			done.
44292Seric **
45292Seric **	Deficiencies:
46292Seric **		It should complain about names that are aliased to
47292Seric **			nothing.
48292Seric **		It is unsophisticated about line overflows.
49292Seric */
50292Seric 
51292Seric 
521503Smark #ifdef DBM
532966Seric typedef struct
542966Seric {
552966Seric 	char	*dptr;
564157Seric 	int	dsize;
574157Seric } DATUM;
584157Seric extern DATUM fetch();
591503Smark #endif DBM
60292Seric 
614999Seric alias(a, sendq)
624097Seric 	register ADDRESS *a;
634999Seric 	ADDRESS **sendq;
64292Seric {
654081Seric 	register char *p;
665701Seric 	extern char *aliaslookup();
67292Seric 
68292Seric 	if (NoAlias)
69292Seric 		return;
70292Seric # ifdef DEBUG
71292Seric 	if (Debug)
724098Seric 		printf("alias(%s)\n", a->q_paddr);
73292Seric # endif
74292Seric 
754098Seric 	/* don't realias already aliased names */
764098Seric 	if (bitset(QDONTSEND, a->q_flags))
774098Seric 		return;
784098Seric 
796898Seric 	CurEnv->e_to = a->q_paddr;
804098Seric 
814314Seric 	/*
824314Seric 	**  Look up this name
834314Seric 	*/
844314Seric 
855701Seric 	p = aliaslookup(a->q_user);
864098Seric 	if (p == NULL)
874098Seric 		return;
88292Seric 
89292Seric 	/*
904098Seric 	**  Match on Alias.
914098Seric 	**	Deliver to the target list.
921515Seric 	*/
931515Seric 
944098Seric # ifdef DEBUG
954098Seric 	if (Debug)
964098Seric 		printf("%s (%s, %s) aliased to %s\n",
974098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
984098Seric # endif
994098Seric 	if (Verbose)
1004165Seric 		message(Arpa_Info, "aliased to %s", p);
1014098Seric 	AliasLevel++;
1024999Seric 	sendto(p, 1, a, sendq);
1034098Seric 	AliasLevel--;
1044098Seric }
1054098Seric /*
1065701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1075701Seric **
1085701Seric **	Parameters:
1095701Seric **		name -- the name to look up.
1105701Seric **
1115701Seric **	Returns:
1125701Seric **		the value of name.
1135701Seric **		NULL if unknown.
1145701Seric **
1155701Seric **	Side Effects:
1165701Seric **		none.
1175701Seric **
1185701Seric **	Warnings:
1195701Seric **		The return value will be trashed across calls.
1205701Seric */
1215701Seric 
1225701Seric char *
1235701Seric aliaslookup(name)
1245701Seric 	char *name;
1255701Seric {
1265701Seric # ifdef DBM
1275701Seric 	DATUM rhs, lhs;
1285701Seric 
1295701Seric 	/* create a key for fetch */
1305701Seric 	lhs.dptr = name;
1315701Seric 	lhs.dsize = strlen(name) + 1;
1325701Seric 	rhs = fetch(lhs);
1335701Seric 	return (rhs.dptr);
1345701Seric # else DBM
1355701Seric 	register STAB *s;
1365701Seric 
1375701Seric 	s = stab(name, ST_ALIAS, ST_FIND);
1385701Seric 	if (s == NULL)
1395701Seric 		return (NULL);
1405701Seric 	return (s->s_alias);
1415701Seric # endif DBM
1425701Seric }
1435701Seric /*
1444098Seric **  INITALIASES -- initialize for aliasing
1454098Seric **
1464098Seric **	Very different depending on whether we are running DBM or not.
1474098Seric **
1484098Seric **	Parameters:
1494098Seric **		aliasfile -- location of aliases.
1504157Seric **		init -- if set and if DBM, initialize the DBM files.
1514098Seric **
1524098Seric **	Returns:
1534098Seric **		none.
1544098Seric **
1554098Seric **	Side Effects:
1564098Seric **		initializes aliases:
1574098Seric **		if DBM:  opens the database.
1584098Seric **		if ~DBM: reads the aliases into the symbol table.
1594098Seric */
1604098Seric 
1614157Seric # define DBMMODE	0666
1624157Seric 
1634157Seric initaliases(aliasfile, init)
1644098Seric 	char *aliasfile;
1654157Seric 	bool init;
1664098Seric {
1674322Seric 	char buf[MAXNAME];
1684322Seric 	struct stat stb;
1694322Seric 	time_t modtime;
1704322Seric 
1714322Seric 	/*
1724322Seric 	**  See if the DBM version of the file is out of date with
1734322Seric 	**  the text version.  If so, go into 'init' mode automatically.
1744322Seric 	**	This only happens if our effective userid owns the DBM
1754325Seric 	**	version or if the mode of the database is 666 -- this
1764322Seric 	**	is an attempt to avoid protection problems.  Note the
1774322Seric 	**	unpalatable hack to see if the stat succeeded.
1784322Seric 	*/
1794322Seric 
1804322Seric 	if (stat(aliasfile, &stb) < 0)
1814322Seric 		return;
1824098Seric # ifdef DBM
1834322Seric 	modtime = stb.st_mtime;
1844322Seric 	(void) strcpy(buf, aliasfile);
1854322Seric 	(void) strcat(buf, ".pag");
1864322Seric 	stb.st_ino = 0;
1874322Seric 	if ((stat(buf, &stb) < 0 || stb.st_mtime < modtime) && !init)
1884322Seric 	{
1894322Seric 		if (stb.st_ino != 0 &&
1904325Seric 		    ((stb.st_mode & 0666) == 0666 || stb.st_uid == geteuid()))
1914322Seric 		{
1924322Seric 			init = TRUE;
1934322Seric 			if (Verbose)
1944322Seric 				message(Arpa_Info, "rebuilding alias database");
1954322Seric 		}
1964322Seric 		else
1974322Seric 		{
1984322Seric 			message(Arpa_Info, "Warning: alias database out of date");
1994322Seric 		}
2004322Seric 	}
2014322Seric # endif DBM
2024322Seric 
2034322Seric 	/*
2044322Seric 	**  If initializing, create the new files.
2054322Seric 	**	We should lock the alias file here to prevent other
2064322Seric 	**	instantiations of sendmail from reading an incomplete
2074322Seric 	**	file -- or worse yet, doing a concurrent initialize.
2084322Seric 	*/
2094322Seric 
2104322Seric # ifdef DBM
2114157Seric 	if (init)
2124157Seric 	{
2134157Seric 		(void) strcpy(buf, aliasfile);
2144157Seric 		(void) strcat(buf, ".dir");
2154157Seric 		if (close(creat(buf, DBMMODE)) < 0)
2164157Seric 		{
2174157Seric 			syserr("cannot make %s", buf);
2184157Seric 			return;
2194157Seric 		}
2204157Seric 		(void) strcpy(buf, aliasfile);
2214157Seric 		(void) strcat(buf, ".pag");
2224157Seric 		if (close(creat(buf, DBMMODE)) < 0)
2234157Seric 		{
2244157Seric 			syserr("cannot make %s", buf);
2254157Seric 			return;
2264157Seric 		}
2274157Seric 	}
2284322Seric 
2294322Seric 	/*
2304322Seric 	**  Open and, if necessary, load the DBM file.
2314322Seric 	**	If running without DBM, load the symbol table.
2324322Seric 	*/
2334322Seric 
2344098Seric 	dbminit(aliasfile);
2354157Seric 	if (init)
2364157Seric 		readaliases(aliasfile, TRUE);
2374098Seric # else DBM
2384157Seric 	readaliases(aliasfile, init);
2394157Seric # endif DBM
2404157Seric }
2414157Seric /*
2424157Seric **  READALIASES -- read and process the alias file.
2434157Seric **
2444157Seric **	This routine implements the part of initaliases that occurs
2454157Seric **	when we are not going to use the DBM stuff.
2464157Seric **
2474157Seric **	Parameters:
2484157Seric **		aliasfile -- the pathname of the alias file master.
2494157Seric **		init -- if set, initialize the DBM stuff.
2504157Seric **
2514157Seric **	Returns:
2524157Seric **		none.
2534157Seric **
2544157Seric **	Side Effects:
2554157Seric **		Reads aliasfile into the symbol table.
2564157Seric **		Optionally, builds the .dir & .pag files.
2574157Seric */
2584157Seric 
2594157Seric static
2604157Seric readaliases(aliasfile, init)
2614157Seric 	char *aliasfile;
2624157Seric 	bool init;
2634157Seric {
2644098Seric 	char line[BUFSIZ];
2654098Seric 	register char *p;
2664098Seric 	char *p2;
2674098Seric 	char *rhs;
2684098Seric 	bool skipping;
2694098Seric 	ADDRESS al, bl;
2704106Seric 	FILE *af;
2714106Seric 	int lineno;
2724106Seric 	register STAB *s;
2734322Seric 	int naliases, bytes, longest;
2744098Seric 
2754098Seric 	if ((af = fopen(aliasfile, "r")) == NULL)
2761515Seric 	{
2774098Seric # ifdef DEBUG
2784098Seric 		if (Debug)
2794106Seric 			printf("Can't open %s\n", aliasfile);
2804098Seric # endif
2814098Seric 		errno = 0;
2824098Seric 		NoAlias++;
2834098Seric 		return;
2844098Seric 	}
2854314Seric 
2864314Seric 	/*
2874314Seric 	**  Read and interpret lines
2884314Seric 	*/
2894314Seric 
2904098Seric 	lineno = 0;
2914322Seric 	naliases = bytes = longest = 0;
2924098Seric 	skipping = FALSE;
2934098Seric 	while (fgets(line, sizeof (line), af) != NULL)
2944098Seric 	{
2954322Seric 		int lhssize, rhssize;
2964322Seric 
2974098Seric 		lineno++;
2984098Seric 		switch (line[0])
2994098Seric 		{
3004098Seric 		  case '#':
3014098Seric 		  case '\n':
3024098Seric 		  case '\0':
3034098Seric 			skipping = FALSE;
3044098Seric 			continue;
3054065Seric 
3064098Seric 		  case ' ':
3074098Seric 		  case '\t':
3084098Seric 			if (!skipping)
3094098Seric 				syserr("aliases: %d: Non-continuation line starts with space", lineno);
3104098Seric 			skipping = TRUE;
3114097Seric 			continue;
3124098Seric 		}
3134098Seric 		skipping = FALSE;
3141874Seric 
3154314Seric 		/*
3164314Seric 		**  Process the LHS
3174314Seric 		**	Find the final colon, and parse the address.
3184314Seric 		**	It should resolve to a local name -- this will
3194314Seric 		**	be checked later (we want to optionally do
3204314Seric 		**	parsing of the RHS first to maximize error
3214314Seric 		**	detection).
3224314Seric 		*/
3234314Seric 
3244098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
3254097Seric 			continue;
3264098Seric 		if (*p == '\0' || *p == '\n')
3274098Seric 		{
3284098Seric 		 syntaxerr:
3294098Seric 			syserr("aliases: %d: missing colon", lineno);
3304097Seric 			continue;
3314098Seric 		}
3324098Seric 		*p++ = '\0';
3334098Seric 		if (parse(line, &al, 1) == NULL)
3344098Seric 		{
3354098Seric 			*--p = ':';
3364098Seric 			goto syntaxerr;
3374098Seric 		}
3384314Seric 
3394314Seric 		/*
3404314Seric 		**  Process the RHS.
3414314Seric 		**	'al' is the internal form of the LHS address.
3424314Seric 		**	'p' points to the text of the RHS.
3434314Seric 		*/
3444314Seric 
3454098Seric 		rhs = p;
3464098Seric 		for (;;)
3474098Seric 		{
3484098Seric 			register char c;
3491515Seric 
3504157Seric 			if (init)
3514098Seric 			{
3524157Seric 				/* do parsing & compression of addresses */
3534098Seric 				c = *p;
3544157Seric 				while (c != '\0')
3554098Seric 				{
3564157Seric 					p2 = p;
3574157Seric 					while (*p != '\n' && *p != ',' && *p != '\0')
3584157Seric 						p++;
3594157Seric 					c = *p;
3604157Seric 					*p++ = '\0';
3614322Seric 					if (c == '\n')
3624322Seric 						c = '\0';
3634157Seric 					if (*p2 == '\0')
3644157Seric 					{
3654157Seric 						p[-1] = c;
3664157Seric 						continue;
3674157Seric 					}
3684314Seric 					(void) parse(p2, &bl, -1);
3694098Seric 					p[-1] = c;
3704157Seric 					while (isspace(*p))
3714157Seric 						p++;
3724098Seric 				}
3734098Seric 			}
3744157Seric 			else
3754157Seric 				p = &p[strlen(p)];
3761515Seric 
3774098Seric 			/* see if there should be a continuation line */
3784106Seric 			c = fgetc(af);
3794106Seric 			if (!feof(af))
3804314Seric 				(void) ungetc(c, af);
3814106Seric 			if (c != ' ' && c != '\t')
3824098Seric 				break;
3834098Seric 
3844098Seric 			/* read continuation line */
3854098Seric 			p--;
3864098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
3874098Seric 				break;
3884098Seric 			lineno++;
3894098Seric 		}
3904594Seric 		if (al.q_mailer != LocalMailer)
3914098Seric 		{
3924098Seric 			syserr("aliases: %d: cannot alias non-local names", lineno);
3934098Seric 			continue;
3944098Seric 		}
3954314Seric 
3964314Seric 		/*
3974314Seric 		**  Insert alias into symbol table or DBM file
3984314Seric 		*/
3994314Seric 
4004322Seric 		lhssize = strlen(al.q_user) + 1;
4014322Seric 		rhssize = strlen(rhs) + 1;
4024322Seric 
4034157Seric # ifdef DBM
4044157Seric 		if (init)
4054157Seric 		{
4064157Seric 			DATUM key, content;
4074157Seric 
4084322Seric 			key.dsize = lhssize;
4094157Seric 			key.dptr = al.q_user;
4104322Seric 			content.dsize = rhssize;
4114157Seric 			content.dptr = rhs;
4124157Seric 			store(key, content);
4134157Seric 		}
4144157Seric 		else
4154157Seric # endif DBM
4164157Seric 		{
4174157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
4184157Seric 			s->s_alias = newstr(rhs);
4194157Seric 		}
4204322Seric 
4214322Seric 		/* statistics */
4224322Seric 		naliases++;
4234322Seric 		bytes += lhssize + rhssize;
4244322Seric 		if (rhssize > longest)
4254322Seric 			longest = rhssize;
4261515Seric 	}
4274098Seric 	(void) fclose(af);
4286898Seric 	CurEnv->e_to = NULL;
4294322Seric 	if (Verbose)
4304322Seric 		message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
4314322Seric 			naliases, longest, bytes);
432292Seric }
433292Seric /*
434292Seric **  FORWARD -- Try to forward mail
435292Seric **
436292Seric **	This is similar but not identical to aliasing.
437292Seric **
438292Seric **	Parameters:
4394314Seric **		user -- the name of the user who's mail we would like
4404314Seric **			to forward to.  It must have been verified --
4414314Seric **			i.e., the q_home field must have been filled
4424314Seric **			in.
4434999Seric **		sendq -- a pointer to the head of the send queue to
4444999Seric **			put this user's aliases in.
445292Seric **
446292Seric **	Returns:
4474098Seric **		none.
448292Seric **
449292Seric **	Side Effects:
4503185Seric **		New names are added to send queues.
451292Seric */
452292Seric 
4534999Seric forward(user, sendq)
4542966Seric 	ADDRESS *user;
4554999Seric 	ADDRESS **sendq;
456292Seric {
4574078Seric 	char buf[60];
4584536Seric 	extern bool safefile();
4594069Seric 
4604098Seric # ifdef DEBUG
4614098Seric 	if (Debug)
4624098Seric 		printf("forward(%s)\n", user->q_paddr);
4634098Seric # endif DEBUG
4644098Seric 
4654594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
4664098Seric 		return;
4674314Seric # ifdef DEBUG
4684314Seric 	if (user->q_home == NULL)
4694314Seric 		syserr("forward: no home");
4704314Seric # endif DEBUG
4714069Seric 
4724069Seric 	/* good address -- look for .forward file in home */
4734104Seric 	define('z', user->q_home);
474*6973Seric 	expand("$z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
4754536Seric 	if (!safefile(buf, user->q_uid, S_IREAD))
4764098Seric 		return;
4774069Seric 
4784069Seric 	/* we do have an address to forward to -- do it */
4794999Seric 	include(buf, "forwarding", user, sendq);
480292Seric }
4815701Seric /*
4825701Seric **  HOSTALIAS -- alias a host name
4835701Seric **
4845701Seric **	Given a host name, look it up in the host alias table
4855701Seric **	and return it's value.  If nothing, return NULL.
4865701Seric **
4875701Seric **	Parameters:
4885701Seric **		a -- address to alias.
4895701Seric **
4905701Seric **	Returns:
4915701Seric **		text result of aliasing.
4925701Seric **		NULL if none.
4935701Seric **
4945701Seric **	Side Effects:
4955701Seric **		none.
4965701Seric */
4975701Seric 
4985701Seric char *
4995701Seric hostalias(a)
5005701Seric 	register ADDRESS *a;
5015701Seric {
5025701Seric 	char buf[MAXNAME+2];
5035701Seric 	register char *p;
5045701Seric 
5055701Seric 	strcpy(buf, "/");
5065701Seric 	strcat(buf, a->q_host);
5075701Seric 	makelower(buf);
5085701Seric 
5095701Seric 	p = aliaslookup(buf);
5105701Seric 	if (p == NULL)
5115701Seric 		return (NULL);
5125844Seric 	(void) sprintf(buf, p, a->q_user);
5135701Seric 	return (newstr(buf));
5145701Seric }
515