1292Seric # include <pwd.h>
24212Seric # include <sys/types.h>
34212Seric # include <sys/stat.h>
43309Seric # include "sendmail.h"
5292Seric 
64106Seric # ifdef DBM
7*4314Seric static char SccsId[] = "@(#)alias.c	3.19	09/06/81	(with DBM)";
84106Seric # else DBM
9*4314Seric static char SccsId[] = "@(#)alias.c	3.19	09/06/81	(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.
21292Seric **
22292Seric **	Returns:
23292Seric **		none
24292Seric **
25292Seric **	Side Effects:
263185Seric **		Aliases found are expanded.
27292Seric **
28292Seric **	Files:
294098Seric **		/usr/lib/aliases -- the mail aliases.  The format is
30569Seric **			a series of lines of the form:
31569Seric **				alias:name1,name2,name3,...
32569Seric **			where 'alias' expands to all of
33569Seric **			'name[i]'.  Continuations begin with
34569Seric **			space or tab.
354098Seric **		/usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version
361503Smark **			of alias file.  Keys are aliases, datums
371503Smark **			(data?) are name1,name2, ...
38292Seric **
39292Seric **	Notes:
40292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
41292Seric **			done.
42292Seric **
43292Seric **	Deficiencies:
44292Seric **		It should complain about names that are aliased to
45292Seric **			nothing.
46292Seric **		It is unsophisticated about line overflows.
47292Seric */
48292Seric 
49292Seric 
501503Smark #ifdef DBM
512966Seric typedef struct
522966Seric {
532966Seric 	char	*dptr;
544157Seric 	int	dsize;
554157Seric } DATUM;
564157Seric DATUM lhs, rhs;
574157Seric extern DATUM fetch();
581503Smark #endif DBM
59292Seric 
604097Seric alias(a)
614097Seric 	register ADDRESS *a;
62292Seric {
634081Seric 	register char *p;
644081Seric # ifndef DBM
654098Seric 	register STAB *s;
664081Seric # endif DBM
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 
794098Seric 	To = a->q_paddr;
804098Seric 
81*4314Seric 	/*
82*4314Seric 	**  Look up this name
83*4314Seric 	*/
84*4314Seric 
854097Seric # ifdef DBM
864098Seric 	/* create a key for fetch */
874098Seric 	lhs.dptr = a->q_user;
884098Seric 	lhs.dsize = strlen(a->q_user) + 1;
894098Seric 	rhs = fetch(lhs);
904098Seric 
914098Seric 	/* find this alias? */
924098Seric 	p = rhs.dptr;
934098Seric 	if (p == NULL)
944098Seric 		return;
954098Seric # else DBM
964098Seric 	s = stab(a->q_user, ST_ALIAS, ST_FIND);
974098Seric 	if (s == NULL)
984098Seric 		return;
994098Seric 	p = s->s_alias;
1004097Seric # endif DBM
101292Seric 
102292Seric 	/*
1034098Seric 	**  Match on Alias.
1044098Seric 	**	Deliver to the target list.
1051515Seric 	*/
1061515Seric 
1074098Seric # ifdef DEBUG
1084098Seric 	if (Debug)
1094098Seric 		printf("%s (%s, %s) aliased to %s\n",
1104098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
1114098Seric # endif
1124098Seric 	if (Verbose)
1134165Seric 		message(Arpa_Info, "aliased to %s", p);
1144098Seric 	a->q_flags |= QDONTSEND;
1154098Seric 	AliasLevel++;
1164098Seric 	sendto(p, 1);
1174098Seric 	AliasLevel--;
1184098Seric }
1194098Seric /*
1204098Seric **  INITALIASES -- initialize for aliasing
1214098Seric **
1224098Seric **	Very different depending on whether we are running DBM or not.
1234098Seric **
1244098Seric **	Parameters:
1254098Seric **		aliasfile -- location of aliases.
1264157Seric **		init -- if set and if DBM, initialize the DBM files.
1274098Seric **
1284098Seric **	Returns:
1294098Seric **		none.
1304098Seric **
1314098Seric **	Side Effects:
1324098Seric **		initializes aliases:
1334098Seric **		if DBM:  opens the database.
1344098Seric **		if ~DBM: reads the aliases into the symbol table.
1354098Seric */
1364098Seric 
1374157Seric # define DBMMODE	0666
1384157Seric 
1394157Seric initaliases(aliasfile, init)
1404098Seric 	char *aliasfile;
1414157Seric 	bool init;
1424098Seric {
1434098Seric # ifdef DBM
1444157Seric 	if (init)
1454157Seric 	{
1464157Seric 		char buf[MAXNAME];
1474157Seric 
1484157Seric 		(void) strcpy(buf, aliasfile);
1494157Seric 		(void) strcat(buf, ".dir");
1504157Seric 		if (close(creat(buf, DBMMODE)) < 0)
1514157Seric 		{
1524157Seric 			syserr("cannot make %s", buf);
1534157Seric 			return;
1544157Seric 		}
1554157Seric 		(void) strcpy(buf, aliasfile);
1564157Seric 		(void) strcat(buf, ".pag");
1574157Seric 		if (close(creat(buf, DBMMODE)) < 0)
1584157Seric 		{
1594157Seric 			syserr("cannot make %s", buf);
1604157Seric 			return;
1614157Seric 		}
1624157Seric 	}
1634098Seric 	dbminit(aliasfile);
1644157Seric 	if (init)
1654157Seric 		readaliases(aliasfile, TRUE);
1664098Seric # else DBM
1674157Seric 	readaliases(aliasfile, init);
1684157Seric # endif DBM
1694157Seric }
1704157Seric /*
1714157Seric **  READALIASES -- read and process the alias file.
1724157Seric **
1734157Seric **	This routine implements the part of initaliases that occurs
1744157Seric **	when we are not going to use the DBM stuff.
1754157Seric **
1764157Seric **	Parameters:
1774157Seric **		aliasfile -- the pathname of the alias file master.
1784157Seric **		init -- if set, initialize the DBM stuff.
1794157Seric **
1804157Seric **	Returns:
1814157Seric **		none.
1824157Seric **
1834157Seric **	Side Effects:
1844157Seric **		Reads aliasfile into the symbol table.
1854157Seric **		Optionally, builds the .dir & .pag files.
1864157Seric */
1874157Seric 
1884157Seric static
1894157Seric readaliases(aliasfile, init)
1904157Seric 	char *aliasfile;
1914157Seric 	bool init;
1924157Seric {
1934098Seric 	char line[BUFSIZ];
1944098Seric 	register char *p;
1954098Seric 	char *p2;
1964098Seric 	char *rhs;
1974098Seric 	bool skipping;
1984098Seric 	ADDRESS al, bl;
1994106Seric 	FILE *af;
2004106Seric 	int lineno;
2014106Seric 	register STAB *s;
2024098Seric 
2034098Seric 	if ((af = fopen(aliasfile, "r")) == NULL)
2041515Seric 	{
2054098Seric # ifdef DEBUG
2064098Seric 		if (Debug)
2074106Seric 			printf("Can't open %s\n", aliasfile);
2084098Seric # endif
2094098Seric 		errno = 0;
2104098Seric 		NoAlias++;
2114098Seric 		return;
2124098Seric 	}
213*4314Seric 
214*4314Seric 	/*
215*4314Seric 	**  Read and interpret lines
216*4314Seric 	*/
217*4314Seric 
2184098Seric 	lineno = 0;
2194098Seric 	skipping = FALSE;
2204098Seric 	while (fgets(line, sizeof (line), af) != NULL)
2214098Seric 	{
2224098Seric 		lineno++;
2234098Seric 		switch (line[0])
2244098Seric 		{
2254098Seric 		  case '#':
2264098Seric 		  case '\n':
2274098Seric 		  case '\0':
2284098Seric 			skipping = FALSE;
2294098Seric 			continue;
2304065Seric 
2314098Seric 		  case ' ':
2324098Seric 		  case '\t':
2334098Seric 			if (!skipping)
2344098Seric 				syserr("aliases: %d: Non-continuation line starts with space", lineno);
2354098Seric 			skipping = TRUE;
2364097Seric 			continue;
2374098Seric 		}
2384098Seric 		skipping = FALSE;
2391874Seric 
240*4314Seric 		/*
241*4314Seric 		**  Process the LHS
242*4314Seric 		**	Find the final colon, and parse the address.
243*4314Seric 		**	It should resolve to a local name -- this will
244*4314Seric 		**	be checked later (we want to optionally do
245*4314Seric 		**	parsing of the RHS first to maximize error
246*4314Seric 		**	detection).
247*4314Seric 		*/
248*4314Seric 
2494098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
2504097Seric 			continue;
2514098Seric 		if (*p == '\0' || *p == '\n')
2524098Seric 		{
2534098Seric 		 syntaxerr:
2544098Seric 			syserr("aliases: %d: missing colon", lineno);
2554097Seric 			continue;
2564098Seric 		}
2574098Seric 		*p++ = '\0';
2584098Seric 		if (parse(line, &al, 1) == NULL)
2594098Seric 		{
2604098Seric 			*--p = ':';
2614098Seric 			goto syntaxerr;
2624098Seric 		}
263*4314Seric 
264*4314Seric 		/*
265*4314Seric 		**  Process the RHS.
266*4314Seric 		**	'al' is the internal form of the LHS address.
267*4314Seric 		**	'p' points to the text of the RHS.
268*4314Seric 		*/
269*4314Seric 
2704098Seric 		rhs = p;
2714098Seric 		for (;;)
2724098Seric 		{
2734098Seric 			register char c;
2741515Seric 
2754157Seric 			if (init)
2764098Seric 			{
2774157Seric 				/* do parsing & compression of addresses */
2784098Seric 				c = *p;
2794157Seric 				while (c != '\0')
2804098Seric 				{
2814157Seric 					p2 = p;
2824157Seric 					while (*p != '\n' && *p != ',' && *p != '\0')
2834157Seric 						p++;
2844157Seric 					c = *p;
2854157Seric 					*p++ = '\0';
2864157Seric 					if (*p2 == '\0')
2874157Seric 					{
2884157Seric 						p[-1] = c;
2894157Seric 						continue;
2904157Seric 					}
291*4314Seric 					(void) parse(p2, &bl, -1);
2924098Seric 					p[-1] = c;
2934157Seric 					while (isspace(*p))
2944157Seric 						p++;
2954098Seric 				}
2964098Seric 			}
2974157Seric 			else
2984157Seric 				p = &p[strlen(p)];
2991515Seric 
3004098Seric 			/* see if there should be a continuation line */
3014106Seric 			c = fgetc(af);
3024106Seric 			if (!feof(af))
303*4314Seric 				(void) ungetc(c, af);
3044106Seric 			if (c != ' ' && c != '\t')
3054098Seric 				break;
3064098Seric 
3074098Seric 			/* read continuation line */
3084098Seric 			p--;
3094098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
3104098Seric 				break;
3114098Seric 			lineno++;
3124098Seric 		}
3134193Seric 		if (al.q_mailer != MN_LOCAL)
3144098Seric 		{
3154098Seric 			syserr("aliases: %d: cannot alias non-local names", lineno);
3164098Seric 			continue;
3174098Seric 		}
318*4314Seric 
319*4314Seric 		/*
320*4314Seric 		**  Insert alias into symbol table or DBM file
321*4314Seric 		*/
322*4314Seric 
3234157Seric # ifdef DBM
3244157Seric 		if (init)
3254157Seric 		{
3264157Seric 			DATUM key, content;
3274157Seric 
3284157Seric 			key.dsize = strlen(al.q_user) + 1;
3294157Seric 			key.dptr = al.q_user;
3304157Seric 			content.dsize = strlen(rhs) + 1;
3314157Seric 			content.dptr = rhs;
3324157Seric 			store(key, content);
3334157Seric 		}
3344157Seric 		else
3354157Seric # endif DBM
3364157Seric 		{
3374157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
3384157Seric 			s->s_alias = newstr(rhs);
3394157Seric 		}
3401515Seric 	}
3414098Seric 	(void) fclose(af);
342292Seric }
343292Seric /*
344292Seric **  FORWARD -- Try to forward mail
345292Seric **
346292Seric **	This is similar but not identical to aliasing.
347292Seric **
348292Seric **	Parameters:
349*4314Seric **		user -- the name of the user who's mail we would like
350*4314Seric **			to forward to.  It must have been verified --
351*4314Seric **			i.e., the q_home field must have been filled
352*4314Seric **			in.
353292Seric **
354292Seric **	Returns:
3554098Seric **		none.
356292Seric **
357292Seric **	Side Effects:
3583185Seric **		New names are added to send queues.
3594098Seric **		Sets the QDONTSEND bit in addresses that are forwarded.
360292Seric */
361292Seric 
362292Seric forward(user)
3632966Seric 	ADDRESS *user;
364292Seric {
3654078Seric 	char buf[60];
3664212Seric 	struct stat stbuf;
3674069Seric 
3684098Seric # ifdef DEBUG
3694098Seric 	if (Debug)
3704098Seric 		printf("forward(%s)\n", user->q_paddr);
3714098Seric # endif DEBUG
3724098Seric 
3734193Seric 	if (user->q_mailer != MN_LOCAL || bitset(QBADADDR, user->q_flags))
3744098Seric 		return;
375*4314Seric # ifdef DEBUG
376*4314Seric 	if (user->q_home == NULL)
377*4314Seric 		syserr("forward: no home");
378*4314Seric # endif DEBUG
3794069Seric 
3804069Seric 	/* good address -- look for .forward file in home */
3814104Seric 	define('z', user->q_home);
3824081Seric 	(void) expand("$z/.forward", buf, &buf[sizeof buf - 1]);
3834212Seric 	if (stat(buf, &stbuf) < 0 || stbuf.st_uid != user->q_uid ||
3844212Seric 	    !bitset(S_IREAD, stbuf.st_mode))
3854098Seric 		return;
3864069Seric 
3874069Seric 	/* we do have an address to forward to -- do it */
3884098Seric 	user->q_flags |= QDONTSEND;
3894177Seric 	include(buf, "forwarding");
390292Seric }
391