xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 51835)
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>
1650577Seric 
1750577Seric # ifdef NEWDB
1850577Seric # include <db.h>
1950577Seric # endif
2050577Seric 
21*51835Seric # ifdef LOCKF
22*51835Seric # include <unistd.h>
23*51835Seric # endif
24*51835Seric 
2533728Sbostic #ifndef lint
2651756Seric #ifdef NEWDB
27*51835Seric static char sccsid[] = "@(#)alias.c	5.28 (Berkeley) 12/05/91 (with NEWDB)";
2851756Seric #else
2933728Sbostic #ifdef DBM
30*51835Seric static char sccsid[] = "@(#)alias.c	5.28 (Berkeley) 12/05/91 (with DBM)";
3133728Sbostic #else
32*51835Seric static char sccsid[] = "@(#)alias.c	5.28 (Berkeley) 12/05/91 (without DBM)";
3333728Sbostic #endif
3450575Seric #endif
3533728Sbostic #endif /* not lint */
3651756Seric /*
37292Seric **  ALIAS -- Compute aliases.
38292Seric **
399368Seric **	Scans the alias file for an alias for the given address.
409368Seric **	If found, it arranges to deliver to the alias list instead.
419368Seric **	Uses libdbm database if -DDBM.
42292Seric **
43292Seric **	Parameters:
444097Seric **		a -- address to alias.
454999Seric **		sendq -- a pointer to the head of the send queue
464999Seric **			to put the aliases in.
47292Seric **
48292Seric **	Returns:
49292Seric **		none
50292Seric **
51292Seric **	Side Effects:
523185Seric **		Aliases found are expanded.
53292Seric **
54292Seric **	Notes:
55292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
56292Seric **			done.
57292Seric **
58292Seric **	Deficiencies:
59292Seric **		It should complain about names that are aliased to
60292Seric **			nothing.
61292Seric */
62292Seric 
63292Seric 
641503Smark #ifdef DBM
6551756Seric #ifndef NEWDB
662966Seric typedef struct
672966Seric {
6850575Seric 	char	*data;
6950575Seric 	int	size;
7050575Seric } DBT;
7151756Seric #endif
7250575Seric extern DBT fetch();
7350575Seric #endif /* DBM */
74292Seric 
7550575Seric #ifdef NEWDB
7650575Seric static DB	*AliasDBptr;
7750575Seric #endif
7850575Seric 
794999Seric alias(a, sendq)
804097Seric 	register ADDRESS *a;
814999Seric 	ADDRESS **sendq;
82292Seric {
834081Seric 	register char *p;
845701Seric 	extern char *aliaslookup();
85292Seric 
867671Seric 	if (tTd(27, 1))
874098Seric 		printf("alias(%s)\n", a->q_paddr);
88292Seric 
894098Seric 	/* don't realias already aliased names */
904098Seric 	if (bitset(QDONTSEND, a->q_flags))
914098Seric 		return;
924098Seric 
936898Seric 	CurEnv->e_to = a->q_paddr;
944098Seric 
954314Seric 	/*
964314Seric 	**  Look up this name
974314Seric 	*/
984314Seric 
9924944Seric 	if (NoAlias)
10024944Seric 		p = NULL;
10124944Seric 	else
10224944Seric 		p = aliaslookup(a->q_user);
1034098Seric 	if (p == NULL)
1044098Seric 		return;
105292Seric 
106292Seric 	/*
1074098Seric 	**  Match on Alias.
1084098Seric 	**	Deliver to the target list.
1091515Seric 	*/
1101515Seric 
1117671Seric 	if (tTd(27, 1))
1124098Seric 		printf("%s (%s, %s) aliased to %s\n",
1134098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
1147051Seric 	message(Arpa_Info, "aliased to %s", p);
1154098Seric 	AliasLevel++;
1169614Seric 	sendtolist(p, a, sendq);
1174098Seric 	AliasLevel--;
1184098Seric }
1194098Seric /*
1205701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1215701Seric **
1225701Seric **	Parameters:
1235701Seric **		name -- the name to look up.
1245701Seric **
1255701Seric **	Returns:
1265701Seric **		the value of name.
1275701Seric **		NULL if unknown.
1285701Seric **
1295701Seric **	Side Effects:
1305701Seric **		none.
1315701Seric **
1325701Seric **	Warnings:
1335701Seric **		The return value will be trashed across calls.
1345701Seric */
1355701Seric 
1365701Seric char *
1375701Seric aliaslookup(name)
1385701Seric 	char *name;
1395701Seric {
14050575Seric # if defined(NEWDB) || defined(DBM)
14150575Seric 	DBT rhs, lhs;
14250575Seric 	int s;
1435701Seric 
1445701Seric 	/* create a key for fetch */
14550575Seric 	lhs.data = name;
14650575Seric 	lhs.size = strlen(name) + 1;
14750575Seric # ifdef NEWDB
14851756Seric 	if (AliasDBptr != NULL)
14951756Seric 	{
15051756Seric 		s = AliasDBptr->get(AliasDBptr, &lhs, &rhs, 0);
15151756Seric 		if (s == 0)
15251756Seric 			return (rhs.data);
15351756Seric 	}
15451756Seric # ifdef DBM
15551756Seric 	else
15651756Seric 	{
15751756Seric 		rhs = fetch(lhs);
15851756Seric 		return (rhs.data);
15951756Seric 	}
16051756Seric # endif
16150575Seric # else
1625701Seric 	rhs = fetch(lhs);
16351756Seric 	return (rhs.data);
16450575Seric # endif
16551756Seric # else /* neither NEWDB nor DBM */
1665701Seric 	register STAB *s;
1675701Seric 
1685701Seric 	s = stab(name, ST_ALIAS, ST_FIND);
16951756Seric 	if (s != NULL)
17051756Seric 		return (s->s_alias);
17151756Seric # endif
17251756Seric 	return (NULL);
1735701Seric }
1745701Seric /*
1754098Seric **  INITALIASES -- initialize for aliasing
1764098Seric **
1774098Seric **	Very different depending on whether we are running DBM or not.
1784098Seric **
1794098Seric **	Parameters:
1804098Seric **		aliasfile -- location of aliases.
1814157Seric **		init -- if set and if DBM, initialize the DBM files.
1824098Seric **
1834098Seric **	Returns:
1844098Seric **		none.
1854098Seric **
1864098Seric **	Side Effects:
1874098Seric **		initializes aliases:
1884098Seric **		if DBM:  opens the database.
1894098Seric **		if ~DBM: reads the aliases into the symbol table.
1904098Seric */
1914098Seric 
19240559Sbostic # define DBMMODE	0644
1934157Seric 
1944157Seric initaliases(aliasfile, init)
1954098Seric 	char *aliasfile;
1964157Seric 	bool init;
1974098Seric {
19850575Seric #if defined(DBM) || defined(NEWDB)
1998437Seric 	int atcnt;
20025522Seric 	time_t modtime;
20125522Seric 	bool automatic = FALSE;
2024322Seric 	char buf[MAXNAME];
20350575Seric #endif
2049368Seric 	struct stat stb;
20527176Seric 	static bool initialized = FALSE;
20646928Sbostic 	static int readaliases();
2074322Seric 
20827176Seric 	if (initialized)
20927176Seric 		return;
21027176Seric 	initialized = TRUE;
21127176Seric 
21217984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2138437Seric 	{
21425522Seric 		if (aliasfile != NULL && init)
21525522Seric 			syserr("Cannot open %s", aliasfile);
2168437Seric 		NoAlias = TRUE;
21711937Seric 		errno = 0;
2188437Seric 		return;
2198437Seric 	}
2208437Seric 
22150575Seric # if defined(DBM) || defined(NEWDB)
2224322Seric 	/*
2238437Seric 	**  Check to see that the alias file is complete.
2248437Seric 	**	If not, we will assume that someone died, and it is up
2258437Seric 	**	to us to rebuild it.
2268437Seric 	*/
2278437Seric 
22825689Seric 	if (!init)
22950575Seric 	{
23050575Seric # ifdef NEWDB
23150575Seric 		(void) strcpy(buf, aliasfile);
23250575Seric 		(void) strcat(buf, ".db");
23351171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
23450576Seric 		if (AliasDBptr == NULL)
23550576Seric 		{
23651756Seric # ifdef DBM
23751756Seric 			dbminit(aliasfile);
23851756Seric # else
23950576Seric 			syserr("initaliases: cannot open %s", buf);
24050576Seric 			NoAlias = TRUE;
24150576Seric 			return;
24251756Seric # endif
24350576Seric 		}
24450575Seric # else
24525689Seric 		dbminit(aliasfile);
24650575Seric # endif
24750575Seric 	}
24817471Seric 	atcnt = SafeAlias * 2;
24917471Seric 	if (atcnt > 0)
25017471Seric 	{
25117471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
25225689Seric 		{
25325689Seric 			/*
25425689Seric 			**  Reinitialize alias file in case the new
25525689Seric 			**  one is mv'ed in instead of cp'ed in.
25625689Seric 			**
25725689Seric 			**	Only works with new DBM -- old one will
25825689Seric 			**	just consume file descriptors forever.
25925689Seric 			**	If you have a dbmclose() it can be
26025689Seric 			**	added before the sleep(30).
26125689Seric 			*/
26225689Seric 
26350575Seric # ifdef NEWDB
26451756Seric 			if (AliasDBptr != NULL)
26551756Seric 				AliasDBptr->close(AliasDBptr);
26650575Seric # endif
26750575Seric 
26817471Seric 			sleep(30);
26950575Seric # ifdef NEWDB
27050575Seric 			(void) strcpy(buf, aliasfile);
27150575Seric 			(void) strcat(buf, ".db");
27251171Sbostic 			AliasDBptr =
27351171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
27450576Seric 			if (AliasDBptr == NULL)
27550576Seric 			{
27651756Seric # ifdef NDBM
27751756Seric 				dbminit(aliasfile);
27851756Seric # else
27950576Seric 				syserr("initaliases: cannot open %s", buf);
28050576Seric 				NoAlias = TRUE;
28150576Seric 				return;
28251756Seric # endif
28350576Seric 			}
28450575Seric # else
28525689Seric # ifdef NDBM
28625689Seric 			dbminit(aliasfile);
28750575Seric # endif
28850575Seric # endif
28925689Seric 		}
29017471Seric 	}
29117471Seric 	else
29217471Seric 		atcnt = 1;
2938437Seric 
2948437Seric 	/*
2954322Seric 	**  See if the DBM version of the file is out of date with
2964322Seric 	**  the text version.  If so, go into 'init' mode automatically.
29740559Sbostic 	**	This only happens if our effective userid owns the DBM.
29840559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
2994322Seric 	*/
3004322Seric 
3014322Seric 	modtime = stb.st_mtime;
3024322Seric 	(void) strcpy(buf, aliasfile);
30350575Seric # ifdef NEWDB
30450575Seric 	(void) strcat(buf, ".db");
30550575Seric # else
3064322Seric 	(void) strcat(buf, ".pag");
30750575Seric # endif
3084322Seric 	stb.st_ino = 0;
30919039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
3104322Seric 	{
31111937Seric 		errno = 0;
31240559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3134322Seric 		{
3144322Seric 			init = TRUE;
31525522Seric 			automatic = TRUE;
3167051Seric 			message(Arpa_Info, "rebuilding alias database");
31724944Seric #ifdef LOG
31824944Seric 			if (LogLevel >= 7)
31924944Seric 				syslog(LOG_INFO, "rebuilding alias database");
32024944Seric #endif LOG
3214322Seric 		}
3224322Seric 		else
3234322Seric 		{
32419039Seric #ifdef LOG
32524944Seric 			if (LogLevel >= 7)
32624944Seric 				syslog(LOG_INFO, "alias database out of date");
32719039Seric #endif LOG
3284322Seric 			message(Arpa_Info, "Warning: alias database out of date");
3294322Seric 		}
3304322Seric 	}
3314322Seric 
3324322Seric 
3334322Seric 	/*
3348437Seric 	**  If necessary, load the DBM file.
3354322Seric 	**	If running without DBM, load the symbol table.
3364322Seric 	*/
3374322Seric 
3384157Seric 	if (init)
3398437Seric 	{
34025522Seric #ifdef LOG
34125522Seric 		if (LogLevel >= 6)
34225522Seric 		{
34325522Seric 			extern char *username();
34425522Seric 
34525522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
34625522Seric 				automatic ? "auto" : "", username());
34725522Seric 		}
34825522Seric #endif LOG
3494157Seric 		readaliases(aliasfile, TRUE);
3508437Seric 	}
3514098Seric # else DBM
3524157Seric 	readaliases(aliasfile, init);
3534157Seric # endif DBM
3544157Seric }
3554157Seric /*
3564157Seric **  READALIASES -- read and process the alias file.
3574157Seric **
3584157Seric **	This routine implements the part of initaliases that occurs
3594157Seric **	when we are not going to use the DBM stuff.
3604157Seric **
3614157Seric **	Parameters:
3624157Seric **		aliasfile -- the pathname of the alias file master.
3634157Seric **		init -- if set, initialize the DBM stuff.
3644157Seric **
3654157Seric **	Returns:
3664157Seric **		none.
3674157Seric **
3684157Seric **	Side Effects:
3694157Seric **		Reads aliasfile into the symbol table.
3704157Seric **		Optionally, builds the .dir & .pag files.
3714157Seric */
3724157Seric 
3734157Seric static
3744157Seric readaliases(aliasfile, init)
3754157Seric 	char *aliasfile;
3764157Seric 	bool init;
3774157Seric {
3784098Seric 	register char *p;
3794098Seric 	char *rhs;
3804098Seric 	bool skipping;
3819368Seric 	int naliases, bytes, longest;
3829368Seric 	FILE *af;
38340970Sbostic 	void (*oldsigint)();
3844098Seric 	ADDRESS al, bl;
3854106Seric 	register STAB *s;
38650575Seric # ifdef NEWDB
38750575Seric 	DB *dbp;
38850575Seric # endif
3899368Seric 	char line[BUFSIZ];
3904098Seric 
3914098Seric 	if ((af = fopen(aliasfile, "r")) == NULL)
3921515Seric 	{
3937671Seric 		if (tTd(27, 1))
3944106Seric 			printf("Can't open %s\n", aliasfile);
3954098Seric 		errno = 0;
3964098Seric 		NoAlias++;
3974098Seric 		return;
3984098Seric 	}
3994314Seric 
40050575Seric # if defined(DBM) || defined(NEWDB)
40119784Seric 	/* see if someone else is rebuilding the alias file already */
402*51835Seric # ifdef LOCKF
403*51835Seric 	if (lockf(fileno(af), F_TEST, 0) < 0 && errno == EACCES)
404*51835Seric # else
40519784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
406*51835Seric # endif
40719784Seric 	{
40819784Seric 		/* yes, they are -- wait until done and then return */
40919784Seric 		message(Arpa_Info, "Alias file is already being rebuilt");
41019784Seric 		if (OpMode != MD_INITALIAS)
41119784Seric 		{
41219784Seric 			/* wait for other rebuild to complete */
413*51835Seric # ifdef LOCKF
414*51835Seric 			(void) lockf(fileno(af), F_LOCK, 0);
415*51835Seric # else
41619784Seric 			(void) flock(fileno(af), LOCK_EX);
417*51835Seric # endif
41819784Seric 		}
41923108Seric 		(void) fclose(af);
42019784Seric 		errno = 0;
42119784Seric 		return;
42219784Seric 	}
42319784Seric # endif DBM
42419784Seric 
4254314Seric 	/*
42619784Seric 	**  If initializing, create the new DBM files.
42719784Seric 	*/
42819784Seric 
42919784Seric 	if (init)
43019784Seric 	{
43119784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
43251756Seric # ifdef NEWDB
43351756Seric 		(void) strcpy(line, aliasfile);
43451756Seric 		(void) strcat(line, ".db");
43551756Seric 		dbp = dbopen(line,
43651756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
43751756Seric 		if (dbp == NULL)
43851756Seric 		{
43951756Seric 			syserr("readaliases: cannot create %s", line);
44051756Seric 			(void) signal(SIGINT, oldsigint);
44151756Seric 			return;
44251756Seric 		}
44351756Seric # else
44450575Seric # ifdef DBM
44519784Seric 		(void) strcpy(line, aliasfile);
44619784Seric 		(void) strcat(line, ".dir");
44719784Seric 		if (close(creat(line, DBMMODE)) < 0)
44819784Seric 		{
44919784Seric 			syserr("cannot make %s", line);
45019784Seric 			(void) signal(SIGINT, oldsigint);
45119784Seric 			return;
45219784Seric 		}
45319784Seric 		(void) strcpy(line, aliasfile);
45419784Seric 		(void) strcat(line, ".pag");
45519784Seric 		if (close(creat(line, DBMMODE)) < 0)
45619784Seric 		{
45719784Seric 			syserr("cannot make %s", line);
45819784Seric 			(void) signal(SIGINT, oldsigint);
45919784Seric 			return;
46019784Seric 		}
46126501Seric 		dbminit(aliasfile);
46250575Seric # endif
46350575Seric # endif
46419784Seric 	}
46519784Seric 
46619784Seric 	/*
4674314Seric 	**  Read and interpret lines
4684314Seric 	*/
4694314Seric 
4709368Seric 	FileName = aliasfile;
4719368Seric 	LineNumber = 0;
4724322Seric 	naliases = bytes = longest = 0;
4734098Seric 	skipping = FALSE;
4744098Seric 	while (fgets(line, sizeof (line), af) != NULL)
4754098Seric 	{
4764322Seric 		int lhssize, rhssize;
4774322Seric 
4789368Seric 		LineNumber++;
47925278Seric 		p = index(line, '\n');
48025278Seric 		if (p != NULL)
48125278Seric 			*p = '\0';
4824098Seric 		switch (line[0])
4834098Seric 		{
4844098Seric 		  case '#':
4854098Seric 		  case '\0':
4864098Seric 			skipping = FALSE;
4874098Seric 			continue;
4884065Seric 
4894098Seric 		  case ' ':
4904098Seric 		  case '\t':
4914098Seric 			if (!skipping)
4929368Seric 				syserr("Non-continuation line starts with space");
4934098Seric 			skipping = TRUE;
4944097Seric 			continue;
4954098Seric 		}
4964098Seric 		skipping = FALSE;
4971874Seric 
4984314Seric 		/*
4994314Seric 		**  Process the LHS
5004314Seric 		**	Find the final colon, and parse the address.
50116898Seric 		**	It should resolve to a local name -- this will
50216898Seric 		**	be checked later (we want to optionally do
50316898Seric 		**	parsing of the RHS first to maximize error
50416898Seric 		**	detection).
5054314Seric 		*/
5064314Seric 
5074098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5084097Seric 			continue;
50916898Seric 		if (*p++ != ':')
5104098Seric 		{
5119368Seric 			syserr("missing colon");
5124097Seric 			continue;
5134098Seric 		}
51416898Seric 		if (parseaddr(line, &al, 1, ':') == NULL)
5154098Seric 		{
51616898Seric 			syserr("illegal alias name");
51716898Seric 			continue;
5184098Seric 		}
51916898Seric 		loweraddr(&al);
5204314Seric 
5214314Seric 		/*
5224314Seric 		**  Process the RHS.
5234314Seric 		**	'al' is the internal form of the LHS address.
5244314Seric 		**	'p' points to the text of the RHS.
5254314Seric 		*/
5264314Seric 
5274098Seric 		rhs = p;
5284098Seric 		for (;;)
5294098Seric 		{
5304098Seric 			register char c;
5311515Seric 
53225821Seric 			if (init && CheckAliases)
5334098Seric 			{
5344157Seric 				/* do parsing & compression of addresses */
53525278Seric 				while (*p != '\0')
5364098Seric 				{
53725278Seric 					extern char *DelimChar;
53825278Seric 
53925278Seric 					while (isspace(*p) || *p == ',')
5404157Seric 						p++;
54125278Seric 					if (*p == '\0')
54225278Seric 						break;
54325278Seric 					if (parseaddr(p, &bl, -1, ',') == NULL)
54425278Seric 						usrerr("%s... bad address", p);
54525278Seric 					p = DelimChar;
5464098Seric 				}
5474098Seric 			}
5484157Seric 			else
54915769Seric 			{
55016898Seric 				p = &p[strlen(p)];
55116898Seric 				if (p[-1] == '\n')
55216898Seric 					*--p = '\0';
55315769Seric 			}
5541515Seric 
5554098Seric 			/* see if there should be a continuation line */
5564106Seric 			c = fgetc(af);
5574106Seric 			if (!feof(af))
5584314Seric 				(void) ungetc(c, af);
5594106Seric 			if (c != ' ' && c != '\t')
5604098Seric 				break;
5614098Seric 
5624098Seric 			/* read continuation line */
5634098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
5644098Seric 				break;
5659368Seric 			LineNumber++;
5664098Seric 		}
56716898Seric 		if (al.q_mailer != LocalMailer)
56816898Seric 		{
56916898Seric 			syserr("cannot alias non-local names");
57016898Seric 			continue;
57116898Seric 		}
5724314Seric 
5734314Seric 		/*
5744314Seric 		**  Insert alias into symbol table or DBM file
5754314Seric 		*/
5764314Seric 
57716898Seric 		lhssize = strlen(al.q_user) + 1;
5784322Seric 		rhssize = strlen(rhs) + 1;
5794322Seric 
58050575Seric # if defined(DBM) || defined(NEWDB)
5814157Seric 		if (init)
5824157Seric 		{
58350575Seric 			DBT key, content;
5844157Seric 
58550575Seric 			key.size = lhssize;
58650575Seric 			key.data = al.q_user;
58750575Seric 			content.size = rhssize;
58850575Seric 			content.data = rhs;
58951756Seric # ifdef NEWDB
59051171Sbostic 			if (dbp->put(dbp, &key, &content, 0) != 0)
59150576Seric 				syserr("readaliases: db put (%s)", al.q_user);
59251756Seric # else
59351756Seric 			store(key, content);
59450575Seric # endif
5954157Seric 		}
5964157Seric 		else
5974157Seric # endif DBM
5984157Seric 		{
5994157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
6004157Seric 			s->s_alias = newstr(rhs);
6014157Seric 		}
6024322Seric 
6034322Seric 		/* statistics */
6044322Seric 		naliases++;
6054322Seric 		bytes += lhssize + rhssize;
6064322Seric 		if (rhssize > longest)
6074322Seric 			longest = rhssize;
6081515Seric 	}
60919784Seric 
61050575Seric # if defined(DBM) || defined(NEWDB)
61119784Seric 	if (init)
61219784Seric 	{
61319784Seric 		/* add the distinquished alias "@" */
61450575Seric 		DBT key;
61519784Seric 
61650575Seric 		key.size = 2;
61750575Seric 		key.data = "@";
61850575Seric # ifdef NEWDB
61950576Seric 		if (dbp->sync(dbp) != 0 ||
62051171Sbostic 		    dbp->put(dbp, &key, &key, 0) != 0 ||
62150576Seric 		    dbp->close(dbp) != 0)
62250576Seric 			syserr("readaliases: db close failure");
62350575Seric # else
62419784Seric 		store(key, key);
62550575Seric # endif
62619784Seric 
62719784Seric 		/* restore the old signal */
62819784Seric 		(void) signal(SIGINT, oldsigint);
62919784Seric 	}
63019784Seric # endif DBM
63119784Seric 
63219784Seric 	/* closing the alias file drops the lock */
6334098Seric 	(void) fclose(af);
6346898Seric 	CurEnv->e_to = NULL;
6359368Seric 	FileName = NULL;
6367051Seric 	message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
6374322Seric 			naliases, longest, bytes);
63824944Seric # ifdef LOG
63924944Seric 	if (LogLevel >= 8)
64024944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
64124944Seric 			naliases, longest, bytes);
64224944Seric # endif LOG
643292Seric }
644292Seric /*
645292Seric **  FORWARD -- Try to forward mail
646292Seric **
647292Seric **	This is similar but not identical to aliasing.
648292Seric **
649292Seric **	Parameters:
6504314Seric **		user -- the name of the user who's mail we would like
6514314Seric **			to forward to.  It must have been verified --
6524314Seric **			i.e., the q_home field must have been filled
6534314Seric **			in.
6544999Seric **		sendq -- a pointer to the head of the send queue to
6554999Seric **			put this user's aliases in.
656292Seric **
657292Seric **	Returns:
6584098Seric **		none.
659292Seric **
660292Seric **	Side Effects:
6613185Seric **		New names are added to send queues.
662292Seric */
663292Seric 
6644999Seric forward(user, sendq)
6652966Seric 	ADDRESS *user;
6664999Seric 	ADDRESS **sendq;
667292Seric {
6684078Seric 	char buf[60];
6694536Seric 	extern bool safefile();
6704069Seric 
6717671Seric 	if (tTd(27, 1))
6724098Seric 		printf("forward(%s)\n", user->q_paddr);
6734098Seric 
6744594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
6754098Seric 		return;
6764314Seric 	if (user->q_home == NULL)
6774314Seric 		syserr("forward: no home");
6784069Seric 
6794069Seric 	/* good address -- look for .forward file in home */
6809368Seric 	define('z', user->q_home, CurEnv);
68116154Seric 	expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
6824536Seric 	if (!safefile(buf, user->q_uid, S_IREAD))
6834098Seric 		return;
6844069Seric 
6854069Seric 	/* we do have an address to forward to -- do it */
6864999Seric 	include(buf, "forwarding", user, sendq);
687292Seric }
688