xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 53742)
122694Sdist /*
235073Sbostic  * Copyright (c) 1983 Eric P. Allman
333728Sbostic  * Copyright (c) 1988 Regents of the University of California.
433728Sbostic  * All rights reserved.
533728Sbostic  *
642824Sbostic  * %sccs.include.redist.c%
733728Sbostic  */
822694Sdist 
950577Seric # include <sys/types.h>
1050577Seric # include <sys/stat.h>
1150577Seric # include <signal.h>
1250577Seric # include <errno.h>
1350577Seric # include "sendmail.h"
1450577Seric # include <sys/file.h>
1550577Seric # include <pwd.h>
1651937Seric # ifdef LOCKF
1751937Seric # include <fcntl.h>
1851937Seric # endif
1950577Seric 
2050577Seric # ifdef NEWDB
2150577Seric # include <db.h>
2250577Seric # endif
2350577Seric 
2433728Sbostic #ifndef lint
2551756Seric #ifdef NEWDB
26*53742Seric static char sccsid[] = "@(#)alias.c	5.33 (Berkeley) 05/29/92 (with NEWDB)";
2751756Seric #else
2833728Sbostic #ifdef DBM
29*53742Seric static char sccsid[] = "@(#)alias.c	5.33 (Berkeley) 05/29/92 (with DBM)";
3033728Sbostic #else
31*53742Seric static char sccsid[] = "@(#)alias.c	5.33 (Berkeley) 05/29/92 (without DBM)";
3233728Sbostic #endif
3350575Seric #endif
3433728Sbostic #endif /* not lint */
3551756Seric /*
36292Seric **  ALIAS -- Compute aliases.
37292Seric **
389368Seric **	Scans the alias file for an alias for the given address.
399368Seric **	If found, it arranges to deliver to the alias list instead.
409368Seric **	Uses libdbm database if -DDBM.
41292Seric **
42292Seric **	Parameters:
434097Seric **		a -- address to alias.
444999Seric **		sendq -- a pointer to the head of the send queue
454999Seric **			to put the aliases in.
46292Seric **
47292Seric **	Returns:
48292Seric **		none
49292Seric **
50292Seric **	Side Effects:
513185Seric **		Aliases found are expanded.
52292Seric **
53292Seric **	Notes:
54292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
55292Seric **			done.
56292Seric **
57292Seric **	Deficiencies:
58292Seric **		It should complain about names that are aliased to
59292Seric **			nothing.
60292Seric */
61292Seric 
62292Seric 
63*53742Seric /*
64*53742Seric **  Sun YP servers read the dbm files directly, so we have to build them
65*53742Seric **  even if NEWDB
66*53742Seric */
67*53742Seric 
681503Smark #ifdef DBM
69*53742Seric # ifndef NEWDB
70*53742Seric #  define IF_MAKEDBMFILES
71*53742Seric # else
72*53742Seric #  ifdef YPCOMPAT
73*53742Seric #   define IF_MAKEDBMFILES		if (makedbmfiles)
74*53742Seric #  endif
75*53742Seric # endif
76*53742Seric #endif
77*53742Seric 
78*53742Seric #ifdef DBM
7951756Seric #ifndef NEWDB
802966Seric typedef struct
812966Seric {
8250575Seric 	char	*data;
8350575Seric 	int	size;
8450575Seric } DBT;
8551756Seric #endif
8650575Seric extern DBT fetch();
8750575Seric #endif /* DBM */
88292Seric 
8950575Seric #ifdef NEWDB
9050575Seric static DB	*AliasDBptr;
9150575Seric #endif
9250575Seric 
934999Seric alias(a, sendq)
944097Seric 	register ADDRESS *a;
954999Seric 	ADDRESS **sendq;
96292Seric {
974081Seric 	register char *p;
985701Seric 	extern char *aliaslookup();
99292Seric 
1007671Seric 	if (tTd(27, 1))
1014098Seric 		printf("alias(%s)\n", a->q_paddr);
102292Seric 
1034098Seric 	/* don't realias already aliased names */
1044098Seric 	if (bitset(QDONTSEND, a->q_flags))
1054098Seric 		return;
1064098Seric 
1076898Seric 	CurEnv->e_to = a->q_paddr;
1084098Seric 
1094314Seric 	/*
1104314Seric 	**  Look up this name
1114314Seric 	*/
1124314Seric 
11324944Seric 	if (NoAlias)
11424944Seric 		p = NULL;
11524944Seric 	else
11624944Seric 		p = aliaslookup(a->q_user);
1174098Seric 	if (p == NULL)
1184098Seric 		return;
119292Seric 
120292Seric 	/*
1214098Seric 	**  Match on Alias.
1224098Seric 	**	Deliver to the target list.
1231515Seric 	*/
1241515Seric 
1257671Seric 	if (tTd(27, 1))
1264098Seric 		printf("%s (%s, %s) aliased to %s\n",
1274098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
1287051Seric 	message(Arpa_Info, "aliased to %s", p);
1294098Seric 	AliasLevel++;
1309614Seric 	sendtolist(p, a, sendq);
1314098Seric 	AliasLevel--;
1324098Seric }
1334098Seric /*
1345701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1355701Seric **
1365701Seric **	Parameters:
1375701Seric **		name -- the name to look up.
1385701Seric **
1395701Seric **	Returns:
1405701Seric **		the value of name.
1415701Seric **		NULL if unknown.
1425701Seric **
1435701Seric **	Side Effects:
1445701Seric **		none.
1455701Seric **
1465701Seric **	Warnings:
1475701Seric **		The return value will be trashed across calls.
1485701Seric */
1495701Seric 
1505701Seric char *
1515701Seric aliaslookup(name)
1525701Seric 	char *name;
1535701Seric {
15450575Seric # if defined(NEWDB) || defined(DBM)
15550575Seric 	DBT rhs, lhs;
15650575Seric 	int s;
1575701Seric 
1585701Seric 	/* create a key for fetch */
15950575Seric 	lhs.data = name;
16050575Seric 	lhs.size = strlen(name) + 1;
16150575Seric # ifdef NEWDB
16251756Seric 	if (AliasDBptr != NULL)
16351756Seric 	{
16451756Seric 		s = AliasDBptr->get(AliasDBptr, &lhs, &rhs, 0);
16551756Seric 		if (s == 0)
16651756Seric 			return (rhs.data);
16751756Seric 	}
16851756Seric # ifdef DBM
16951756Seric 	else
17051756Seric 	{
17151756Seric 		rhs = fetch(lhs);
17251756Seric 		return (rhs.data);
17351756Seric 	}
17451756Seric # endif
17550575Seric # else
1765701Seric 	rhs = fetch(lhs);
17751756Seric 	return (rhs.data);
17850575Seric # endif
17951756Seric # else /* neither NEWDB nor DBM */
1805701Seric 	register STAB *s;
1815701Seric 
1825701Seric 	s = stab(name, ST_ALIAS, ST_FIND);
18351756Seric 	if (s != NULL)
18451756Seric 		return (s->s_alias);
18551756Seric # endif
18651756Seric 	return (NULL);
1875701Seric }
1885701Seric /*
1894098Seric **  INITALIASES -- initialize for aliasing
1904098Seric **
1914098Seric **	Very different depending on whether we are running DBM or not.
1924098Seric **
1934098Seric **	Parameters:
1944098Seric **		aliasfile -- location of aliases.
1954157Seric **		init -- if set and if DBM, initialize the DBM files.
1964098Seric **
1974098Seric **	Returns:
1984098Seric **		none.
1994098Seric **
2004098Seric **	Side Effects:
2014098Seric **		initializes aliases:
2024098Seric **		if DBM:  opens the database.
2034098Seric **		if ~DBM: reads the aliases into the symbol table.
2044098Seric */
2054098Seric 
20640559Sbostic # define DBMMODE	0644
2074157Seric 
2084157Seric initaliases(aliasfile, init)
2094098Seric 	char *aliasfile;
2104157Seric 	bool init;
2114098Seric {
21250575Seric #if defined(DBM) || defined(NEWDB)
2138437Seric 	int atcnt;
21425522Seric 	time_t modtime;
21525522Seric 	bool automatic = FALSE;
2164322Seric 	char buf[MAXNAME];
21750575Seric #endif
2189368Seric 	struct stat stb;
21927176Seric 	static bool initialized = FALSE;
22046928Sbostic 	static int readaliases();
2214322Seric 
22227176Seric 	if (initialized)
22327176Seric 		return;
22427176Seric 	initialized = TRUE;
22527176Seric 
22617984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2278437Seric 	{
22825522Seric 		if (aliasfile != NULL && init)
22925522Seric 			syserr("Cannot open %s", aliasfile);
2308437Seric 		NoAlias = TRUE;
23111937Seric 		errno = 0;
2328437Seric 		return;
2338437Seric 	}
2348437Seric 
23550575Seric # if defined(DBM) || defined(NEWDB)
2364322Seric 	/*
2378437Seric 	**  Check to see that the alias file is complete.
2388437Seric 	**	If not, we will assume that someone died, and it is up
2398437Seric 	**	to us to rebuild it.
2408437Seric 	*/
2418437Seric 
24225689Seric 	if (!init)
24350575Seric 	{
24450575Seric # ifdef NEWDB
24550575Seric 		(void) strcpy(buf, aliasfile);
24650575Seric 		(void) strcat(buf, ".db");
24751171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
24850576Seric 		if (AliasDBptr == NULL)
24950576Seric 		{
25051756Seric # ifdef DBM
25151756Seric 			dbminit(aliasfile);
25251756Seric # else
25350576Seric 			syserr("initaliases: cannot open %s", buf);
25450576Seric 			NoAlias = TRUE;
25550576Seric 			return;
25651756Seric # endif
25750576Seric 		}
25850575Seric # else
25925689Seric 		dbminit(aliasfile);
26050575Seric # endif
26150575Seric 	}
26217471Seric 	atcnt = SafeAlias * 2;
26317471Seric 	if (atcnt > 0)
26417471Seric 	{
26517471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
26625689Seric 		{
26725689Seric 			/*
26825689Seric 			**  Reinitialize alias file in case the new
26925689Seric 			**  one is mv'ed in instead of cp'ed in.
27025689Seric 			**
27125689Seric 			**	Only works with new DBM -- old one will
27225689Seric 			**	just consume file descriptors forever.
27325689Seric 			**	If you have a dbmclose() it can be
27425689Seric 			**	added before the sleep(30).
27525689Seric 			*/
27625689Seric 
27750575Seric # ifdef NEWDB
27851756Seric 			if (AliasDBptr != NULL)
27951756Seric 				AliasDBptr->close(AliasDBptr);
28050575Seric # endif
28150575Seric 
28217471Seric 			sleep(30);
28350575Seric # ifdef NEWDB
28450575Seric 			(void) strcpy(buf, aliasfile);
28550575Seric 			(void) strcat(buf, ".db");
28651171Sbostic 			AliasDBptr =
28751171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
28850576Seric 			if (AliasDBptr == NULL)
28950576Seric 			{
29051756Seric # ifdef NDBM
29151756Seric 				dbminit(aliasfile);
29251756Seric # else
29350576Seric 				syserr("initaliases: cannot open %s", buf);
29450576Seric 				NoAlias = TRUE;
29550576Seric 				return;
29651756Seric # endif
29750576Seric 			}
29850575Seric # else
29925689Seric # ifdef NDBM
30025689Seric 			dbminit(aliasfile);
30150575Seric # endif
30250575Seric # endif
30325689Seric 		}
30417471Seric 	}
30517471Seric 	else
30617471Seric 		atcnt = 1;
3078437Seric 
3088437Seric 	/*
3094322Seric 	**  See if the DBM version of the file is out of date with
3104322Seric 	**  the text version.  If so, go into 'init' mode automatically.
31140559Sbostic 	**	This only happens if our effective userid owns the DBM.
31240559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
3134322Seric 	*/
3144322Seric 
3154322Seric 	modtime = stb.st_mtime;
3164322Seric 	(void) strcpy(buf, aliasfile);
31750575Seric # ifdef NEWDB
31850575Seric 	(void) strcat(buf, ".db");
31950575Seric # else
3204322Seric 	(void) strcat(buf, ".pag");
32150575Seric # endif
3224322Seric 	stb.st_ino = 0;
32319039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
3244322Seric 	{
32511937Seric 		errno = 0;
32640559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3274322Seric 		{
3284322Seric 			init = TRUE;
32925522Seric 			automatic = TRUE;
3307051Seric 			message(Arpa_Info, "rebuilding alias database");
33124944Seric #ifdef LOG
33224944Seric 			if (LogLevel >= 7)
33324944Seric 				syslog(LOG_INFO, "rebuilding alias database");
33424944Seric #endif LOG
3354322Seric 		}
3364322Seric 		else
3374322Seric 		{
33819039Seric #ifdef LOG
33924944Seric 			if (LogLevel >= 7)
34024944Seric 				syslog(LOG_INFO, "alias database out of date");
34119039Seric #endif LOG
3424322Seric 			message(Arpa_Info, "Warning: alias database out of date");
3434322Seric 		}
3444322Seric 	}
3454322Seric 
3464322Seric 
3474322Seric 	/*
3488437Seric 	**  If necessary, load the DBM file.
3494322Seric 	**	If running without DBM, load the symbol table.
3504322Seric 	*/
3514322Seric 
3524157Seric 	if (init)
3538437Seric 	{
35425522Seric #ifdef LOG
35525522Seric 		if (LogLevel >= 6)
35625522Seric 		{
35725522Seric 			extern char *username();
35825522Seric 
35925522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
36025522Seric 				automatic ? "auto" : "", username());
36125522Seric 		}
36225522Seric #endif LOG
3634157Seric 		readaliases(aliasfile, TRUE);
3648437Seric 	}
3654098Seric # else DBM
3664157Seric 	readaliases(aliasfile, init);
3674157Seric # endif DBM
3684157Seric }
3694157Seric /*
3704157Seric **  READALIASES -- read and process the alias file.
3714157Seric **
3724157Seric **	This routine implements the part of initaliases that occurs
3734157Seric **	when we are not going to use the DBM stuff.
3744157Seric **
3754157Seric **	Parameters:
3764157Seric **		aliasfile -- the pathname of the alias file master.
3774157Seric **		init -- if set, initialize the DBM stuff.
3784157Seric **
3794157Seric **	Returns:
3804157Seric **		none.
3814157Seric **
3824157Seric **	Side Effects:
3834157Seric **		Reads aliasfile into the symbol table.
3844157Seric **		Optionally, builds the .dir & .pag files.
3854157Seric */
3864157Seric 
3874157Seric static
3884157Seric readaliases(aliasfile, init)
3894157Seric 	char *aliasfile;
3904157Seric 	bool init;
3914157Seric {
3924098Seric 	register char *p;
3934098Seric 	char *rhs;
3944098Seric 	bool skipping;
3959368Seric 	int naliases, bytes, longest;
3969368Seric 	FILE *af;
397*53742Seric 	bool makedbmfiles;
39840970Sbostic 	void (*oldsigint)();
3994098Seric 	ADDRESS al, bl;
4004106Seric 	register STAB *s;
40150575Seric # ifdef NEWDB
40250575Seric 	DB *dbp;
40350575Seric # endif
40451937Seric # ifdef LOCKF
40551937Seric 	struct flock fld;
40651937Seric # endif
4079368Seric 	char line[BUFSIZ];
4084098Seric 
40951937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
4101515Seric 	{
4117671Seric 		if (tTd(27, 1))
4124106Seric 			printf("Can't open %s\n", aliasfile);
4134098Seric 		errno = 0;
4144098Seric 		NoAlias++;
4154098Seric 		return;
4164098Seric 	}
4174314Seric 
41850575Seric # if defined(DBM) || defined(NEWDB)
41919784Seric 	/* see if someone else is rebuilding the alias file already */
42051835Seric # ifdef LOCKF
42151937Seric 	fld.l_type = F_WRLCK;
42251937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
42351937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
42451835Seric # else
42519784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
42651835Seric # endif
42719784Seric 	{
42819784Seric 		/* yes, they are -- wait until done and then return */
42919784Seric 		message(Arpa_Info, "Alias file is already being rebuilt");
43019784Seric 		if (OpMode != MD_INITALIAS)
43119784Seric 		{
43219784Seric 			/* wait for other rebuild to complete */
43351835Seric # ifdef LOCKF
43451937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
43551835Seric # else
43619784Seric 			(void) flock(fileno(af), LOCK_EX);
43751835Seric # endif
43819784Seric 		}
43923108Seric 		(void) fclose(af);
44019784Seric 		errno = 0;
44119784Seric 		return;
44219784Seric 	}
44319784Seric # endif DBM
44419784Seric 
4454314Seric 	/*
44619784Seric 	**  If initializing, create the new DBM files.
44719784Seric 	*/
44819784Seric 
44919784Seric 	if (init)
45019784Seric 	{
45119784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
45251756Seric # ifdef NEWDB
45351756Seric 		(void) strcpy(line, aliasfile);
45451756Seric 		(void) strcat(line, ".db");
45551756Seric 		dbp = dbopen(line,
45651756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
45751756Seric 		if (dbp == NULL)
45851756Seric 		{
45951756Seric 			syserr("readaliases: cannot create %s", line);
46051756Seric 			(void) signal(SIGINT, oldsigint);
46151756Seric 			return;
46251756Seric 		}
463*53742Seric # endif
464*53742Seric # ifdef IF_MAKEDBMFILES
465*53742Seric # ifdef NEWDB
466*53742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
467*53742Seric # endif
468*53742Seric 		IF_MAKEDBMFILES
46919784Seric 		{
470*53742Seric 			(void) strcpy(line, aliasfile);
471*53742Seric 			(void) strcat(line, ".dir");
472*53742Seric 			if (close(creat(line, DBMMODE)) < 0)
473*53742Seric 			{
474*53742Seric 				syserr("cannot make %s", line);
475*53742Seric 				(void) signal(SIGINT, oldsigint);
476*53742Seric 				return;
477*53742Seric 			}
478*53742Seric 			(void) strcpy(line, aliasfile);
479*53742Seric 			(void) strcat(line, ".pag");
480*53742Seric 			if (close(creat(line, DBMMODE)) < 0)
481*53742Seric 			{
482*53742Seric 				syserr("cannot make %s", line);
483*53742Seric 				(void) signal(SIGINT, oldsigint);
484*53742Seric 				return;
485*53742Seric 			}
486*53742Seric 			dbminit(aliasfile);
48719784Seric 		}
48850575Seric # endif
48919784Seric 	}
49019784Seric 
49119784Seric 	/*
4924314Seric 	**  Read and interpret lines
4934314Seric 	*/
4944314Seric 
4959368Seric 	FileName = aliasfile;
4969368Seric 	LineNumber = 0;
4974322Seric 	naliases = bytes = longest = 0;
4984098Seric 	skipping = FALSE;
4994098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5004098Seric 	{
5014322Seric 		int lhssize, rhssize;
5024322Seric 
5039368Seric 		LineNumber++;
50425278Seric 		p = index(line, '\n');
50525278Seric 		if (p != NULL)
50625278Seric 			*p = '\0';
5074098Seric 		switch (line[0])
5084098Seric 		{
5094098Seric 		  case '#':
5104098Seric 		  case '\0':
5114098Seric 			skipping = FALSE;
5124098Seric 			continue;
5134065Seric 
5144098Seric 		  case ' ':
5154098Seric 		  case '\t':
5164098Seric 			if (!skipping)
5179368Seric 				syserr("Non-continuation line starts with space");
5184098Seric 			skipping = TRUE;
5194097Seric 			continue;
5204098Seric 		}
5214098Seric 		skipping = FALSE;
5221874Seric 
5234314Seric 		/*
5244314Seric 		**  Process the LHS
5254314Seric 		**	Find the final colon, and parse the address.
52616898Seric 		**	It should resolve to a local name -- this will
52716898Seric 		**	be checked later (we want to optionally do
52816898Seric 		**	parsing of the RHS first to maximize error
52916898Seric 		**	detection).
5304314Seric 		*/
5314314Seric 
5324098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5334097Seric 			continue;
53416898Seric 		if (*p++ != ':')
5354098Seric 		{
5369368Seric 			syserr("missing colon");
5374097Seric 			continue;
5384098Seric 		}
53916898Seric 		if (parseaddr(line, &al, 1, ':') == NULL)
5404098Seric 		{
54116898Seric 			syserr("illegal alias name");
54216898Seric 			continue;
5434098Seric 		}
54416898Seric 		loweraddr(&al);
5454314Seric 
5464314Seric 		/*
5474314Seric 		**  Process the RHS.
5484314Seric 		**	'al' is the internal form of the LHS address.
5494314Seric 		**	'p' points to the text of the RHS.
5504314Seric 		*/
5514314Seric 
5524098Seric 		rhs = p;
5534098Seric 		for (;;)
5544098Seric 		{
5554098Seric 			register char c;
5561515Seric 
55725821Seric 			if (init && CheckAliases)
5584098Seric 			{
5594157Seric 				/* do parsing & compression of addresses */
56025278Seric 				while (*p != '\0')
5614098Seric 				{
56225278Seric 					extern char *DelimChar;
56325278Seric 
56425278Seric 					while (isspace(*p) || *p == ',')
5654157Seric 						p++;
56625278Seric 					if (*p == '\0')
56725278Seric 						break;
56825278Seric 					if (parseaddr(p, &bl, -1, ',') == NULL)
56925278Seric 						usrerr("%s... bad address", p);
57025278Seric 					p = DelimChar;
5714098Seric 				}
5724098Seric 			}
5734157Seric 			else
57415769Seric 			{
57516898Seric 				p = &p[strlen(p)];
57616898Seric 				if (p[-1] == '\n')
57716898Seric 					*--p = '\0';
57815769Seric 			}
5791515Seric 
5804098Seric 			/* see if there should be a continuation line */
5814106Seric 			c = fgetc(af);
5824106Seric 			if (!feof(af))
5834314Seric 				(void) ungetc(c, af);
5844106Seric 			if (c != ' ' && c != '\t')
5854098Seric 				break;
5864098Seric 
5874098Seric 			/* read continuation line */
5884098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
5894098Seric 				break;
5909368Seric 			LineNumber++;
5914098Seric 		}
59216898Seric 		if (al.q_mailer != LocalMailer)
59316898Seric 		{
59416898Seric 			syserr("cannot alias non-local names");
59516898Seric 			continue;
59616898Seric 		}
5974314Seric 
5984314Seric 		/*
5994314Seric 		**  Insert alias into symbol table or DBM file
6004314Seric 		*/
6014314Seric 
60216898Seric 		lhssize = strlen(al.q_user) + 1;
6034322Seric 		rhssize = strlen(rhs) + 1;
6044322Seric 
60550575Seric # if defined(DBM) || defined(NEWDB)
6064157Seric 		if (init)
6074157Seric 		{
60850575Seric 			DBT key, content;
6094157Seric 
61050575Seric 			key.size = lhssize;
61150575Seric 			key.data = al.q_user;
61250575Seric 			content.size = rhssize;
61350575Seric 			content.data = rhs;
61451756Seric # ifdef NEWDB
61551171Sbostic 			if (dbp->put(dbp, &key, &content, 0) != 0)
61650576Seric 				syserr("readaliases: db put (%s)", al.q_user);
61750575Seric # endif
618*53742Seric # ifdef IF_MAKEDBMFILES
619*53742Seric 			IF_MAKEDBMFILES
620*53742Seric 				store(key, content);
621*53742Seric # endif
6224157Seric 		}
6234157Seric 		else
6244157Seric # endif DBM
6254157Seric 		{
6264157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
6274157Seric 			s->s_alias = newstr(rhs);
6284157Seric 		}
6294322Seric 
6304322Seric 		/* statistics */
6314322Seric 		naliases++;
6324322Seric 		bytes += lhssize + rhssize;
6334322Seric 		if (rhssize > longest)
6344322Seric 			longest = rhssize;
6351515Seric 	}
63619784Seric 
63750575Seric # if defined(DBM) || defined(NEWDB)
63819784Seric 	if (init)
63919784Seric 	{
64019784Seric 		/* add the distinquished alias "@" */
64150575Seric 		DBT key;
64219784Seric 
64350575Seric 		key.size = 2;
64450575Seric 		key.data = "@";
64550575Seric # ifdef NEWDB
64650576Seric 		if (dbp->sync(dbp) != 0 ||
64751171Sbostic 		    dbp->put(dbp, &key, &key, 0) != 0 ||
64850576Seric 		    dbp->close(dbp) != 0)
64950576Seric 			syserr("readaliases: db close failure");
650*53742Seric # endif
651*53742Seric # ifdef MAKEDBMFILES
65219784Seric 		store(key, key);
65350575Seric # endif
65419784Seric 
65519784Seric 		/* restore the old signal */
65619784Seric 		(void) signal(SIGINT, oldsigint);
65719784Seric 	}
65819784Seric # endif DBM
65919784Seric 
66019784Seric 	/* closing the alias file drops the lock */
6614098Seric 	(void) fclose(af);
6626898Seric 	CurEnv->e_to = NULL;
6639368Seric 	FileName = NULL;
6647051Seric 	message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
6654322Seric 			naliases, longest, bytes);
66624944Seric # ifdef LOG
66724944Seric 	if (LogLevel >= 8)
66824944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
66924944Seric 			naliases, longest, bytes);
67024944Seric # endif LOG
671292Seric }
672292Seric /*
673292Seric **  FORWARD -- Try to forward mail
674292Seric **
675292Seric **	This is similar but not identical to aliasing.
676292Seric **
677292Seric **	Parameters:
6784314Seric **		user -- the name of the user who's mail we would like
6794314Seric **			to forward to.  It must have been verified --
6804314Seric **			i.e., the q_home field must have been filled
6814314Seric **			in.
6824999Seric **		sendq -- a pointer to the head of the send queue to
6834999Seric **			put this user's aliases in.
684292Seric **
685292Seric **	Returns:
6864098Seric **		none.
687292Seric **
688292Seric **	Side Effects:
6893185Seric **		New names are added to send queues.
690292Seric */
691292Seric 
6924999Seric forward(user, sendq)
6932966Seric 	ADDRESS *user;
6944999Seric 	ADDRESS **sendq;
695292Seric {
6964078Seric 	char buf[60];
6974536Seric 	extern bool safefile();
6984069Seric 
6997671Seric 	if (tTd(27, 1))
7004098Seric 		printf("forward(%s)\n", user->q_paddr);
7014098Seric 
7024594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
7034098Seric 		return;
7044314Seric 	if (user->q_home == NULL)
7054314Seric 		syserr("forward: no home");
7064069Seric 
7074069Seric 	/* good address -- look for .forward file in home */
7089368Seric 	define('z', user->q_home, CurEnv);
70916154Seric 	expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
71053037Seric 	include(buf, TRUE, user, sendq);
711292Seric }
712