1292Seric # include <pwd.h>
23309Seric # include "sendmail.h"
3292Seric 
44106Seric # ifdef DBM
5*4193Seric static char SccsId[] = "@(#)alias.c	3.17	08/21/81	(with DBM)";
64106Seric # else DBM
7*4193Seric static char SccsId[] = "@(#)alias.c	3.17	08/21/81	(without DBM)";
84106Seric # endif DBM
9402Seric 
10292Seric /*
11292Seric **  ALIAS -- Compute aliases.
12292Seric **
134098Seric **	Scans the file /usr/lib/aliases for a set of aliases.
143185Seric **	If found, it arranges to deliver to them.  Uses libdbm
153185Seric **	database if -DDBM.
16292Seric **
17292Seric **	Parameters:
184097Seric **		a -- address to alias.
19292Seric **
20292Seric **	Returns:
21292Seric **		none
22292Seric **
23292Seric **	Side Effects:
243185Seric **		Aliases found are expanded.
25292Seric **
26292Seric **	Files:
274098Seric **		/usr/lib/aliases -- the mail aliases.  The format is
28569Seric **			a series of lines of the form:
29569Seric **				alias:name1,name2,name3,...
30569Seric **			where 'alias' expands to all of
31569Seric **			'name[i]'.  Continuations begin with
32569Seric **			space or tab.
334098Seric **		/usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version
341503Smark **			of alias file.  Keys are aliases, datums
351503Smark **			(data?) are name1,name2, ...
36292Seric **
37292Seric **	Notes:
38292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
39292Seric **			done.
40292Seric **
41292Seric **	Deficiencies:
42292Seric **		It should complain about names that are aliased to
43292Seric **			nothing.
44292Seric **		It is unsophisticated about line overflows.
45292Seric */
46292Seric 
47292Seric 
481503Smark #ifdef DBM
492966Seric typedef struct
502966Seric {
512966Seric 	char	*dptr;
524157Seric 	int	dsize;
534157Seric } DATUM;
544157Seric DATUM lhs, rhs;
554157Seric extern DATUM fetch();
561503Smark #endif DBM
57292Seric 
584097Seric alias(a)
594097Seric 	register ADDRESS *a;
60292Seric {
614081Seric 	register char *p;
624081Seric # ifndef DBM
634098Seric 	register STAB *s;
644081Seric # endif DBM
65292Seric 
66292Seric 	if (NoAlias)
67292Seric 		return;
68292Seric # ifdef DEBUG
69292Seric 	if (Debug)
704098Seric 		printf("alias(%s)\n", a->q_paddr);
71292Seric # endif
72292Seric 
734098Seric 	/* don't realias already aliased names */
744098Seric 	if (bitset(QDONTSEND, a->q_flags))
754098Seric 		return;
764098Seric 
774098Seric 	To = a->q_paddr;
784098Seric 
794097Seric # ifdef DBM
804098Seric 	/* create a key for fetch */
814098Seric 	lhs.dptr = a->q_user;
824098Seric 	lhs.dsize = strlen(a->q_user) + 1;
834098Seric 	rhs = fetch(lhs);
844098Seric 
854098Seric 	/* find this alias? */
864098Seric 	p = rhs.dptr;
874098Seric 	if (p == NULL)
884098Seric 		return;
894098Seric # else DBM
904098Seric 	s = stab(a->q_user, ST_ALIAS, ST_FIND);
914098Seric 	if (s == NULL)
924098Seric 		return;
934098Seric 	p = s->s_alias;
944097Seric # endif DBM
95292Seric 
96292Seric 	/*
974098Seric 	**  Match on Alias.
984098Seric 	**	Deliver to the target list.
991515Seric 	*/
1001515Seric 
1014098Seric # ifdef DEBUG
1024098Seric 	if (Debug)
1034098Seric 		printf("%s (%s, %s) aliased to %s\n",
1044098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
1054098Seric # endif
1064098Seric 	if (Verbose)
1074165Seric 		message(Arpa_Info, "aliased to %s", p);
1084098Seric 	a->q_flags |= QDONTSEND;
1094098Seric 	AliasLevel++;
1104098Seric 	sendto(p, 1);
1114098Seric 	AliasLevel--;
1124098Seric }
1134098Seric /*
1144098Seric **  INITALIASES -- initialize for aliasing
1154098Seric **
1164098Seric **	Very different depending on whether we are running DBM or not.
1174098Seric **
1184098Seric **	Parameters:
1194098Seric **		aliasfile -- location of aliases.
1204157Seric **		init -- if set and if DBM, initialize the DBM files.
1214098Seric **
1224098Seric **	Returns:
1234098Seric **		none.
1244098Seric **
1254098Seric **	Side Effects:
1264098Seric **		initializes aliases:
1274098Seric **		if DBM:  opens the database.
1284098Seric **		if ~DBM: reads the aliases into the symbol table.
1294098Seric */
1304098Seric 
1314157Seric # define DBMMODE	0666
1324157Seric 
1334157Seric initaliases(aliasfile, init)
1344098Seric 	char *aliasfile;
1354157Seric 	bool init;
1364098Seric {
1374098Seric # ifdef DBM
1384157Seric 	if (init)
1394157Seric 	{
1404157Seric 		char buf[MAXNAME];
1414157Seric 
1424157Seric 		(void) strcpy(buf, aliasfile);
1434157Seric 		(void) strcat(buf, ".dir");
1444157Seric 		if (close(creat(buf, DBMMODE)) < 0)
1454157Seric 		{
1464157Seric 			syserr("cannot make %s", buf);
1474157Seric 			return;
1484157Seric 		}
1494157Seric 		(void) strcpy(buf, aliasfile);
1504157Seric 		(void) strcat(buf, ".pag");
1514157Seric 		if (close(creat(buf, DBMMODE)) < 0)
1524157Seric 		{
1534157Seric 			syserr("cannot make %s", buf);
1544157Seric 			return;
1554157Seric 		}
1564157Seric 	}
1574098Seric 	dbminit(aliasfile);
1584157Seric 	if (init)
1594157Seric 		readaliases(aliasfile, TRUE);
1604098Seric # else DBM
1614157Seric 	readaliases(aliasfile, init);
1624157Seric # endif DBM
1634157Seric }
1644157Seric /*
1654157Seric **  READALIASES -- read and process the alias file.
1664157Seric **
1674157Seric **	This routine implements the part of initaliases that occurs
1684157Seric **	when we are not going to use the DBM stuff.
1694157Seric **
1704157Seric **	Parameters:
1714157Seric **		aliasfile -- the pathname of the alias file master.
1724157Seric **		init -- if set, initialize the DBM stuff.
1734157Seric **
1744157Seric **	Returns:
1754157Seric **		none.
1764157Seric **
1774157Seric **	Side Effects:
1784157Seric **		Reads aliasfile into the symbol table.
1794157Seric **		Optionally, builds the .dir & .pag files.
1804157Seric */
1814157Seric 
1824157Seric static
1834157Seric readaliases(aliasfile, init)
1844157Seric 	char *aliasfile;
1854157Seric 	bool init;
1864157Seric {
1874098Seric 	char line[BUFSIZ];
1884098Seric 	register char *p;
1894098Seric 	char *p2;
1904098Seric 	char *rhs;
1914098Seric 	bool skipping;
1924098Seric 	ADDRESS al, bl;
1934106Seric 	FILE *af;
1944106Seric 	int lineno;
1954106Seric 	register STAB *s;
1964098Seric 
1974098Seric 	if ((af = fopen(aliasfile, "r")) == NULL)
1981515Seric 	{
1994098Seric # ifdef DEBUG
2004098Seric 		if (Debug)
2014106Seric 			printf("Can't open %s\n", aliasfile);
2024098Seric # endif
2034098Seric 		errno = 0;
2044098Seric 		NoAlias++;
2054098Seric 		return;
2064098Seric 	}
2074098Seric 	/* read and interpret lines */
2084098Seric 	lineno = 0;
2094098Seric 	skipping = FALSE;
2104098Seric 	while (fgets(line, sizeof (line), af) != NULL)
2114098Seric 	{
2124098Seric 		lineno++;
2134098Seric 		switch (line[0])
2144098Seric 		{
2154098Seric 		  case '#':
2164098Seric 		  case '\n':
2174098Seric 		  case '\0':
2184098Seric 			skipping = FALSE;
2194098Seric 			continue;
2204065Seric 
2214098Seric 		  case ' ':
2224098Seric 		  case '\t':
2234098Seric 			if (!skipping)
2244098Seric 				syserr("aliases: %d: Non-continuation line starts with space", lineno);
2254098Seric 			skipping = TRUE;
2264097Seric 			continue;
2274098Seric 		}
2284098Seric 		skipping = FALSE;
2291874Seric 
2304098Seric 		/* process the LHS */
2314098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
2324097Seric 			continue;
2334098Seric 		if (*p == '\0' || *p == '\n')
2344098Seric 		{
2354098Seric 		 syntaxerr:
2364098Seric 			syserr("aliases: %d: missing colon", lineno);
2374097Seric 			continue;
2384098Seric 		}
2394098Seric 		*p++ = '\0';
2404098Seric 		if (parse(line, &al, 1) == NULL)
2414098Seric 		{
2424098Seric 			*--p = ':';
2434098Seric 			goto syntaxerr;
2444098Seric 		}
2454098Seric 		rhs = p;
2464098Seric 		for (;;)
2474098Seric 		{
2484098Seric 			register char c;
2491515Seric 
2504157Seric 			if (init)
2514098Seric 			{
2524157Seric 				/* do parsing & compression of addresses */
2534098Seric 				c = *p;
2544157Seric 				while (c != '\0')
2554098Seric 				{
2564157Seric 					p2 = p;
2574157Seric 					while (*p != '\n' && *p != ',' && *p != '\0')
2584157Seric 						p++;
2594157Seric 					c = *p;
2604157Seric 					*p++ = '\0';
2614157Seric 					if (*p2 == '\0')
2624157Seric 					{
2634157Seric 						p[-1] = c;
2644157Seric 						continue;
2654157Seric 					}
2664157Seric 					parse(p2, &bl, -1);
2674098Seric 					p[-1] = c;
2684157Seric 					while (isspace(*p))
2694157Seric 						p++;
2704098Seric 				}
2714098Seric 			}
2724157Seric 			else
2734157Seric 				p = &p[strlen(p)];
2741515Seric 
2754098Seric 			/* see if there should be a continuation line */
2764106Seric 			c = fgetc(af);
2774106Seric 			if (!feof(af))
2784106Seric 				ungetc(c, af);
2794106Seric 			if (c != ' ' && c != '\t')
2804098Seric 				break;
2814098Seric 
2824098Seric 			/* read continuation line */
2834098Seric 			p--;
2844098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
2854098Seric 				break;
2864098Seric 			lineno++;
2874098Seric 		}
288*4193Seric 		if (al.q_mailer != MN_LOCAL)
2894098Seric 		{
2904098Seric 			syserr("aliases: %d: cannot alias non-local names", lineno);
2914098Seric 			continue;
2924098Seric 		}
2934157Seric # ifdef DBM
2944157Seric 		if (init)
2954157Seric 		{
2964157Seric 			DATUM key, content;
2974157Seric 
2984157Seric 			key.dsize = strlen(al.q_user) + 1;
2994157Seric 			key.dptr = al.q_user;
3004157Seric 			content.dsize = strlen(rhs) + 1;
3014157Seric 			content.dptr = rhs;
3024157Seric 			store(key, content);
3034157Seric 		}
3044157Seric 		else
3054157Seric # endif DBM
3064157Seric 		{
3074157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
3084157Seric 			s->s_alias = newstr(rhs);
3094157Seric 		}
3101515Seric 	}
3114098Seric 	(void) fclose(af);
312292Seric }
313292Seric /*
314292Seric **  FORWARD -- Try to forward mail
315292Seric **
316292Seric **	This is similar but not identical to aliasing.
317292Seric **
318292Seric **	Parameters:
319292Seric **		user -- the name of the user who's mail we
320292Seric **			would like to forward to.
321292Seric **
322292Seric **	Returns:
3234098Seric **		none.
324292Seric **
325292Seric **	Side Effects:
3263185Seric **		New names are added to send queues.
3274098Seric **		Sets the QDONTSEND bit in addresses that are forwarded.
328292Seric */
329292Seric 
330292Seric forward(user)
3312966Seric 	ADDRESS *user;
332292Seric {
3334078Seric 	char buf[60];
3344069Seric 	register FILE *fp;
3354069Seric 	register char *p;
3364069Seric 
3374098Seric # ifdef DEBUG
3384098Seric 	if (Debug)
3394098Seric 		printf("forward(%s)\n", user->q_paddr);
3404098Seric # endif DEBUG
3414098Seric 
342*4193Seric 	if (user->q_mailer != MN_LOCAL || bitset(QBADADDR, user->q_flags))
3434098Seric 		return;
3444069Seric 
3454069Seric 	/* good address -- look for .forward file in home */
3464104Seric 	define('z', user->q_home);
3474081Seric 	(void) expand("$z/.forward", buf, &buf[sizeof buf - 1]);
3484177Seric 	if (access(buf, 4) < 0)
3494098Seric 		return;
3504069Seric 
3514069Seric 	/* we do have an address to forward to -- do it */
3524098Seric 	user->q_flags |= QDONTSEND;
3534177Seric 	include(buf, "forwarding");
354292Seric }
355