1292Seric # include <stdio.h>
2292Seric # include <ctype.h>
3292Seric # include <pwd.h>
43309Seric # include "sendmail.h"
5292Seric 
64106Seric # ifdef DBM
7*4165Seric static char SccsId[] = "@(#)alias.c	3.14	08/18/81	(with DBM)";
84106Seric # else DBM
9*4165Seric static char SccsId[] = "@(#)alias.c	3.14	08/18/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 
814097Seric # ifdef DBM
824098Seric 	/* create a key for fetch */
834098Seric 	lhs.dptr = a->q_user;
844098Seric 	lhs.dsize = strlen(a->q_user) + 1;
854098Seric 	rhs = fetch(lhs);
864098Seric 
874098Seric 	/* find this alias? */
884098Seric 	p = rhs.dptr;
894098Seric 	if (p == NULL)
904098Seric 		return;
914098Seric # else DBM
924098Seric 	s = stab(a->q_user, ST_ALIAS, ST_FIND);
934098Seric 	if (s == NULL)
944098Seric 		return;
954098Seric 	p = s->s_alias;
964097Seric # endif DBM
97292Seric 
98292Seric 	/*
994098Seric 	**  Match on Alias.
1004098Seric 	**	Deliver to the target list.
1011515Seric 	*/
1021515Seric 
1034098Seric # ifdef DEBUG
1044098Seric 	if (Debug)
1054098Seric 		printf("%s (%s, %s) aliased to %s\n",
1064098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
1074098Seric # endif
1084098Seric 	if (Verbose)
109*4165Seric 		message(Arpa_Info, "aliased to %s", p);
1104098Seric 	a->q_flags |= QDONTSEND;
1114098Seric 	AliasLevel++;
1124098Seric 	sendto(p, 1);
1134098Seric 	AliasLevel--;
1144098Seric }
1154098Seric /*
1164098Seric **  INITALIASES -- initialize for aliasing
1174098Seric **
1184098Seric **	Very different depending on whether we are running DBM or not.
1194098Seric **
1204098Seric **	Parameters:
1214098Seric **		aliasfile -- location of aliases.
1224157Seric **		init -- if set and if DBM, initialize the DBM files.
1234098Seric **
1244098Seric **	Returns:
1254098Seric **		none.
1264098Seric **
1274098Seric **	Side Effects:
1284098Seric **		initializes aliases:
1294098Seric **		if DBM:  opens the database.
1304098Seric **		if ~DBM: reads the aliases into the symbol table.
1314098Seric */
1324098Seric 
1334157Seric # define DBMMODE	0666
1344157Seric 
1354157Seric initaliases(aliasfile, init)
1364098Seric 	char *aliasfile;
1374157Seric 	bool init;
1384098Seric {
1394098Seric # ifdef DBM
1404157Seric 	if (init)
1414157Seric 	{
1424157Seric 		char buf[MAXNAME];
1434157Seric 
1444157Seric 		(void) strcpy(buf, aliasfile);
1454157Seric 		(void) strcat(buf, ".dir");
1464157Seric 		if (close(creat(buf, DBMMODE)) < 0)
1474157Seric 		{
1484157Seric 			syserr("cannot make %s", buf);
1494157Seric 			return;
1504157Seric 		}
1514157Seric 		(void) strcpy(buf, aliasfile);
1524157Seric 		(void) strcat(buf, ".pag");
1534157Seric 		if (close(creat(buf, DBMMODE)) < 0)
1544157Seric 		{
1554157Seric 			syserr("cannot make %s", buf);
1564157Seric 			return;
1574157Seric 		}
1584157Seric 	}
1594098Seric 	dbminit(aliasfile);
1604157Seric 	if (init)
1614157Seric 		readaliases(aliasfile, TRUE);
1624098Seric # else DBM
1634157Seric 	readaliases(aliasfile, init);
1644157Seric # endif DBM
1654157Seric }
1664157Seric /*
1674157Seric **  READALIASES -- read and process the alias file.
1684157Seric **
1694157Seric **	This routine implements the part of initaliases that occurs
1704157Seric **	when we are not going to use the DBM stuff.
1714157Seric **
1724157Seric **	Parameters:
1734157Seric **		aliasfile -- the pathname of the alias file master.
1744157Seric **		init -- if set, initialize the DBM stuff.
1754157Seric **
1764157Seric **	Returns:
1774157Seric **		none.
1784157Seric **
1794157Seric **	Side Effects:
1804157Seric **		Reads aliasfile into the symbol table.
1814157Seric **		Optionally, builds the .dir & .pag files.
1824157Seric */
1834157Seric 
1844157Seric static
1854157Seric readaliases(aliasfile, init)
1864157Seric 	char *aliasfile;
1874157Seric 	bool init;
1884157Seric {
1894098Seric 	char line[BUFSIZ];
1904098Seric 	register char *p;
1914098Seric 	char *p2;
1924098Seric 	char *rhs;
1934098Seric 	bool skipping;
1944098Seric 	ADDRESS al, bl;
1954106Seric 	FILE *af;
1964106Seric 	int lineno;
1974106Seric 	register STAB *s;
1984098Seric 
1994098Seric 	if ((af = fopen(aliasfile, "r")) == NULL)
2001515Seric 	{
2014098Seric # ifdef DEBUG
2024098Seric 		if (Debug)
2034106Seric 			printf("Can't open %s\n", aliasfile);
2044098Seric # endif
2054098Seric 		errno = 0;
2064098Seric 		NoAlias++;
2074098Seric 		return;
2084098Seric 	}
2094098Seric 	/* read and interpret lines */
2104098Seric 	lineno = 0;
2114098Seric 	skipping = FALSE;
2124098Seric 	while (fgets(line, sizeof (line), af) != NULL)
2134098Seric 	{
2144098Seric 		lineno++;
2154098Seric 		switch (line[0])
2164098Seric 		{
2174098Seric 		  case '#':
2184098Seric 		  case '\n':
2194098Seric 		  case '\0':
2204098Seric 			skipping = FALSE;
2214098Seric 			continue;
2224065Seric 
2234098Seric 		  case ' ':
2244098Seric 		  case '\t':
2254098Seric 			if (!skipping)
2264098Seric 				syserr("aliases: %d: Non-continuation line starts with space", lineno);
2274098Seric 			skipping = TRUE;
2284097Seric 			continue;
2294098Seric 		}
2304098Seric 		skipping = FALSE;
2311874Seric 
2324098Seric 		/* process the LHS */
2334098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
2344097Seric 			continue;
2354098Seric 		if (*p == '\0' || *p == '\n')
2364098Seric 		{
2374098Seric 		 syntaxerr:
2384098Seric 			syserr("aliases: %d: missing colon", lineno);
2394097Seric 			continue;
2404098Seric 		}
2414098Seric 		*p++ = '\0';
2424098Seric 		if (parse(line, &al, 1) == NULL)
2434098Seric 		{
2444098Seric 			*--p = ':';
2454098Seric 			goto syntaxerr;
2464098Seric 		}
2474098Seric 		rhs = p;
2484098Seric 		for (;;)
2494098Seric 		{
2504098Seric 			register char c;
2511515Seric 
2524157Seric 			if (init)
2534098Seric 			{
2544157Seric 				/* do parsing & compression of addresses */
2554098Seric 				c = *p;
2564157Seric 				while (c != '\0')
2574098Seric 				{
2584157Seric 					p2 = p;
2594157Seric 					while (*p != '\n' && *p != ',' && *p != '\0')
2604157Seric 						p++;
2614157Seric 					c = *p;
2624157Seric 					*p++ = '\0';
2634157Seric 					if (*p2 == '\0')
2644157Seric 					{
2654157Seric 						p[-1] = c;
2664157Seric 						continue;
2674157Seric 					}
2684157Seric 					parse(p2, &bl, -1);
2694098Seric 					p[-1] = c;
2704157Seric 					while (isspace(*p))
2714157Seric 						p++;
2724098Seric 				}
2734098Seric 			}
2744157Seric 			else
2754157Seric 				p = &p[strlen(p)];
2761515Seric 
2774098Seric 			/* see if there should be a continuation line */
2784106Seric 			c = fgetc(af);
2794106Seric 			if (!feof(af))
2804106Seric 				ungetc(c, af);
2814106Seric 			if (c != ' ' && c != '\t')
2824098Seric 				break;
2834098Seric 
2844098Seric 			/* read continuation line */
2854098Seric 			p--;
2864098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
2874098Seric 				break;
2884098Seric 			lineno++;
2894098Seric 		}
2904098Seric 		if (al.q_mailer != M_LOCAL)
2914098Seric 		{
2924098Seric 			syserr("aliases: %d: cannot alias non-local names", lineno);
2934098Seric 			continue;
2944098Seric 		}
2954157Seric # ifdef DBM
2964157Seric 		if (init)
2974157Seric 		{
2984157Seric 			DATUM key, content;
2994157Seric 
3004157Seric 			key.dsize = strlen(al.q_user) + 1;
3014157Seric 			key.dptr = al.q_user;
3024157Seric 			content.dsize = strlen(rhs) + 1;
3034157Seric 			content.dptr = rhs;
3044157Seric 			store(key, content);
3054157Seric 		}
3064157Seric 		else
3074157Seric # endif DBM
3084157Seric 		{
3094157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
3104157Seric 			s->s_alias = newstr(rhs);
3114157Seric 		}
3121515Seric 	}
3134098Seric 	(void) fclose(af);
314292Seric }
315292Seric /*
316292Seric **  FORWARD -- Try to forward mail
317292Seric **
318292Seric **	This is similar but not identical to aliasing.
319292Seric **
320292Seric **	Parameters:
321292Seric **		user -- the name of the user who's mail we
322292Seric **			would like to forward to.
323292Seric **
324292Seric **	Returns:
3254098Seric **		none.
326292Seric **
327292Seric **	Side Effects:
3283185Seric **		New names are added to send queues.
3294098Seric **		Sets the QDONTSEND bit in addresses that are forwarded.
330292Seric */
331292Seric 
332292Seric forward(user)
3332966Seric 	ADDRESS *user;
334292Seric {
3354078Seric 	char buf[60];
3364069Seric 	register FILE *fp;
3374069Seric 	register char *p;
3384069Seric 
3394098Seric # ifdef DEBUG
3404098Seric 	if (Debug)
3414098Seric 		printf("forward(%s)\n", user->q_paddr);
3424098Seric # endif DEBUG
3434098Seric 
3444078Seric 	if (user->q_mailer != M_LOCAL || bitset(QBADADDR, user->q_flags))
3454098Seric 		return;
3464069Seric 
3474069Seric 	/* good address -- look for .forward file in home */
3484104Seric 	define('z', user->q_home);
3494081Seric 	(void) expand("$z/.forward", buf, &buf[sizeof buf - 1]);
3504069Seric 	fp = fopen(buf, "r");
3514069Seric 	if (fp == NULL)
3524098Seric 		return;
3534069Seric 
3544069Seric 	/* we do have an address to forward to -- do it */
3554098Seric 	user->q_flags |= QDONTSEND;
3564081Seric 	(void) fgets(buf, sizeof buf, fp);
3574069Seric 	if ((p = index(buf, '\n')) != NULL)
3584069Seric 		*p = '\0';
3594081Seric 	(void) fclose(fp);
3604069Seric 	if (buf[0] == '\0')
3614098Seric 		return;
3624069Seric 	if (Verbose)
363*4165Seric 		message(Arpa_Info, "forwarded to %s", buf);
3644098Seric 	AliasLevel++;
3654069Seric 	sendto(buf, 1);
3664098Seric 	AliasLevel--;
3674098Seric 	return;
368292Seric }
369