xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 55012)
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*55012Seric static char sccsid[] = "@(#)alias.c	5.34 (Berkeley) 07/12/92 (with NEWDB)";
2751756Seric #else
2833728Sbostic #ifdef DBM
29*55012Seric static char sccsid[] = "@(#)alias.c	5.34 (Berkeley) 07/12/92 (with DBM)";
3033728Sbostic #else
31*55012Seric static char sccsid[] = "@(#)alias.c	5.34 (Berkeley) 07/12/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 
6353742Seric /*
6453742Seric **  Sun YP servers read the dbm files directly, so we have to build them
6553742Seric **  even if NEWDB
6653742Seric */
6753742Seric 
681503Smark #ifdef DBM
6953742Seric # ifndef NEWDB
7053742Seric #  define IF_MAKEDBMFILES
7153742Seric # else
7253742Seric #  ifdef YPCOMPAT
7353742Seric #   define IF_MAKEDBMFILES		if (makedbmfiles)
7453742Seric #  endif
7553742Seric # endif
7653742Seric #endif
7753742Seric 
7853742Seric #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 
93*55012Seric alias(a, sendq, e)
944097Seric 	register ADDRESS *a;
954999Seric 	ADDRESS **sendq;
96*55012Seric 	register ENVELOPE *e;
97292Seric {
984081Seric 	register char *p;
995701Seric 	extern char *aliaslookup();
100292Seric 
1017671Seric 	if (tTd(27, 1))
1024098Seric 		printf("alias(%s)\n", a->q_paddr);
103292Seric 
1044098Seric 	/* don't realias already aliased names */
1054098Seric 	if (bitset(QDONTSEND, a->q_flags))
1064098Seric 		return;
1074098Seric 
108*55012Seric 	e->e_to = a->q_paddr;
1094098Seric 
1104314Seric 	/*
1114314Seric 	**  Look up this name
1124314Seric 	*/
1134314Seric 
11424944Seric 	if (NoAlias)
11524944Seric 		p = NULL;
11624944Seric 	else
11724944Seric 		p = aliaslookup(a->q_user);
1184098Seric 	if (p == NULL)
1194098Seric 		return;
120292Seric 
121292Seric 	/*
1224098Seric 	**  Match on Alias.
1234098Seric 	**	Deliver to the target list.
1241515Seric 	*/
1251515Seric 
1267671Seric 	if (tTd(27, 1))
1274098Seric 		printf("%s (%s, %s) aliased to %s\n",
1284098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
1297051Seric 	message(Arpa_Info, "aliased to %s", p);
1304098Seric 	AliasLevel++;
131*55012Seric 	sendtolist(p, a, sendq, e);
1324098Seric 	AliasLevel--;
1334098Seric }
1344098Seric /*
1355701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1365701Seric **
1375701Seric **	Parameters:
1385701Seric **		name -- the name to look up.
1395701Seric **
1405701Seric **	Returns:
1415701Seric **		the value of name.
1425701Seric **		NULL if unknown.
1435701Seric **
1445701Seric **	Side Effects:
1455701Seric **		none.
1465701Seric **
1475701Seric **	Warnings:
1485701Seric **		The return value will be trashed across calls.
1495701Seric */
1505701Seric 
1515701Seric char *
1525701Seric aliaslookup(name)
1535701Seric 	char *name;
1545701Seric {
15550575Seric # if defined(NEWDB) || defined(DBM)
15650575Seric 	DBT rhs, lhs;
15750575Seric 	int s;
1585701Seric 
1595701Seric 	/* create a key for fetch */
16050575Seric 	lhs.data = name;
16150575Seric 	lhs.size = strlen(name) + 1;
16250575Seric # ifdef NEWDB
16351756Seric 	if (AliasDBptr != NULL)
16451756Seric 	{
16551756Seric 		s = AliasDBptr->get(AliasDBptr, &lhs, &rhs, 0);
16651756Seric 		if (s == 0)
16751756Seric 			return (rhs.data);
16851756Seric 	}
16951756Seric # ifdef DBM
17051756Seric 	else
17151756Seric 	{
17251756Seric 		rhs = fetch(lhs);
17351756Seric 		return (rhs.data);
17451756Seric 	}
17551756Seric # endif
17650575Seric # else
1775701Seric 	rhs = fetch(lhs);
17851756Seric 	return (rhs.data);
17950575Seric # endif
18051756Seric # else /* neither NEWDB nor DBM */
1815701Seric 	register STAB *s;
1825701Seric 
1835701Seric 	s = stab(name, ST_ALIAS, ST_FIND);
18451756Seric 	if (s != NULL)
18551756Seric 		return (s->s_alias);
18651756Seric # endif
18751756Seric 	return (NULL);
1885701Seric }
1895701Seric /*
1904098Seric **  INITALIASES -- initialize for aliasing
1914098Seric **
1924098Seric **	Very different depending on whether we are running DBM or not.
1934098Seric **
1944098Seric **	Parameters:
1954098Seric **		aliasfile -- location of aliases.
1964157Seric **		init -- if set and if DBM, initialize the DBM files.
1974098Seric **
1984098Seric **	Returns:
1994098Seric **		none.
2004098Seric **
2014098Seric **	Side Effects:
2024098Seric **		initializes aliases:
2034098Seric **		if DBM:  opens the database.
2044098Seric **		if ~DBM: reads the aliases into the symbol table.
2054098Seric */
2064098Seric 
20740559Sbostic # define DBMMODE	0644
2084157Seric 
209*55012Seric initaliases(aliasfile, init, e)
2104098Seric 	char *aliasfile;
2114157Seric 	bool init;
212*55012Seric 	register ENVELOPE *e;
2134098Seric {
21450575Seric #if defined(DBM) || defined(NEWDB)
2158437Seric 	int atcnt;
21625522Seric 	time_t modtime;
21725522Seric 	bool automatic = FALSE;
2184322Seric 	char buf[MAXNAME];
21950575Seric #endif
2209368Seric 	struct stat stb;
22127176Seric 	static bool initialized = FALSE;
22246928Sbostic 	static int readaliases();
2234322Seric 
22427176Seric 	if (initialized)
22527176Seric 		return;
22627176Seric 	initialized = TRUE;
22727176Seric 
22817984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2298437Seric 	{
23025522Seric 		if (aliasfile != NULL && init)
23125522Seric 			syserr("Cannot open %s", aliasfile);
2328437Seric 		NoAlias = TRUE;
23311937Seric 		errno = 0;
2348437Seric 		return;
2358437Seric 	}
2368437Seric 
23750575Seric # if defined(DBM) || defined(NEWDB)
2384322Seric 	/*
2398437Seric 	**  Check to see that the alias file is complete.
2408437Seric 	**	If not, we will assume that someone died, and it is up
2418437Seric 	**	to us to rebuild it.
2428437Seric 	*/
2438437Seric 
24425689Seric 	if (!init)
24550575Seric 	{
24650575Seric # ifdef NEWDB
24750575Seric 		(void) strcpy(buf, aliasfile);
24850575Seric 		(void) strcat(buf, ".db");
24951171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
25050576Seric 		if (AliasDBptr == NULL)
25150576Seric 		{
25251756Seric # ifdef DBM
25351756Seric 			dbminit(aliasfile);
25451756Seric # else
25550576Seric 			syserr("initaliases: cannot open %s", buf);
25650576Seric 			NoAlias = TRUE;
25750576Seric 			return;
25851756Seric # endif
25950576Seric 		}
26050575Seric # else
26125689Seric 		dbminit(aliasfile);
26250575Seric # endif
26350575Seric 	}
26417471Seric 	atcnt = SafeAlias * 2;
26517471Seric 	if (atcnt > 0)
26617471Seric 	{
26717471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
26825689Seric 		{
26925689Seric 			/*
27025689Seric 			**  Reinitialize alias file in case the new
27125689Seric 			**  one is mv'ed in instead of cp'ed in.
27225689Seric 			**
27325689Seric 			**	Only works with new DBM -- old one will
27425689Seric 			**	just consume file descriptors forever.
27525689Seric 			**	If you have a dbmclose() it can be
27625689Seric 			**	added before the sleep(30).
27725689Seric 			*/
27825689Seric 
27950575Seric # ifdef NEWDB
28051756Seric 			if (AliasDBptr != NULL)
28151756Seric 				AliasDBptr->close(AliasDBptr);
28250575Seric # endif
28350575Seric 
28417471Seric 			sleep(30);
28550575Seric # ifdef NEWDB
28650575Seric 			(void) strcpy(buf, aliasfile);
28750575Seric 			(void) strcat(buf, ".db");
28851171Sbostic 			AliasDBptr =
28951171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
29050576Seric 			if (AliasDBptr == NULL)
29150576Seric 			{
29251756Seric # ifdef NDBM
29351756Seric 				dbminit(aliasfile);
29451756Seric # else
29550576Seric 				syserr("initaliases: cannot open %s", buf);
29650576Seric 				NoAlias = TRUE;
29750576Seric 				return;
29851756Seric # endif
29950576Seric 			}
30050575Seric # else
30125689Seric # ifdef NDBM
30225689Seric 			dbminit(aliasfile);
30350575Seric # endif
30450575Seric # endif
30525689Seric 		}
30617471Seric 	}
30717471Seric 	else
30817471Seric 		atcnt = 1;
3098437Seric 
3108437Seric 	/*
3114322Seric 	**  See if the DBM version of the file is out of date with
3124322Seric 	**  the text version.  If so, go into 'init' mode automatically.
31340559Sbostic 	**	This only happens if our effective userid owns the DBM.
31440559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
3154322Seric 	*/
3164322Seric 
3174322Seric 	modtime = stb.st_mtime;
3184322Seric 	(void) strcpy(buf, aliasfile);
31950575Seric # ifdef NEWDB
32050575Seric 	(void) strcat(buf, ".db");
32150575Seric # else
3224322Seric 	(void) strcat(buf, ".pag");
32350575Seric # endif
3244322Seric 	stb.st_ino = 0;
32519039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
3264322Seric 	{
32711937Seric 		errno = 0;
32840559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3294322Seric 		{
3304322Seric 			init = TRUE;
33125522Seric 			automatic = TRUE;
3327051Seric 			message(Arpa_Info, "rebuilding alias database");
33324944Seric #ifdef LOG
33424944Seric 			if (LogLevel >= 7)
33524944Seric 				syslog(LOG_INFO, "rebuilding alias database");
33624944Seric #endif LOG
3374322Seric 		}
3384322Seric 		else
3394322Seric 		{
34019039Seric #ifdef LOG
34124944Seric 			if (LogLevel >= 7)
34224944Seric 				syslog(LOG_INFO, "alias database out of date");
34319039Seric #endif LOG
3444322Seric 			message(Arpa_Info, "Warning: alias database out of date");
3454322Seric 		}
3464322Seric 	}
3474322Seric 
3484322Seric 
3494322Seric 	/*
3508437Seric 	**  If necessary, load the DBM file.
3514322Seric 	**	If running without DBM, load the symbol table.
3524322Seric 	*/
3534322Seric 
3544157Seric 	if (init)
3558437Seric 	{
35625522Seric #ifdef LOG
35725522Seric 		if (LogLevel >= 6)
35825522Seric 		{
35925522Seric 			extern char *username();
36025522Seric 
36125522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
36225522Seric 				automatic ? "auto" : "", username());
36325522Seric 		}
36425522Seric #endif LOG
365*55012Seric 		readaliases(aliasfile, TRUE, e);
3668437Seric 	}
3674098Seric # else DBM
368*55012Seric 	readaliases(aliasfile, init, e);
3694157Seric # endif DBM
3704157Seric }
3714157Seric /*
3724157Seric **  READALIASES -- read and process the alias file.
3734157Seric **
3744157Seric **	This routine implements the part of initaliases that occurs
3754157Seric **	when we are not going to use the DBM stuff.
3764157Seric **
3774157Seric **	Parameters:
3784157Seric **		aliasfile -- the pathname of the alias file master.
3794157Seric **		init -- if set, initialize the DBM stuff.
3804157Seric **
3814157Seric **	Returns:
3824157Seric **		none.
3834157Seric **
3844157Seric **	Side Effects:
3854157Seric **		Reads aliasfile into the symbol table.
3864157Seric **		Optionally, builds the .dir & .pag files.
3874157Seric */
3884157Seric 
3894157Seric static
390*55012Seric readaliases(aliasfile, init, e)
3914157Seric 	char *aliasfile;
3924157Seric 	bool init;
393*55012Seric 	register ENVELOPE *e;
3944157Seric {
3954098Seric 	register char *p;
3964098Seric 	char *rhs;
3974098Seric 	bool skipping;
3989368Seric 	int naliases, bytes, longest;
3999368Seric 	FILE *af;
40053742Seric 	bool makedbmfiles;
40140970Sbostic 	void (*oldsigint)();
4024098Seric 	ADDRESS al, bl;
4034106Seric 	register STAB *s;
40450575Seric # ifdef NEWDB
40550575Seric 	DB *dbp;
40650575Seric # endif
40751937Seric # ifdef LOCKF
40851937Seric 	struct flock fld;
40951937Seric # endif
4109368Seric 	char line[BUFSIZ];
4114098Seric 
41251937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
4131515Seric 	{
4147671Seric 		if (tTd(27, 1))
4154106Seric 			printf("Can't open %s\n", aliasfile);
4164098Seric 		errno = 0;
4174098Seric 		NoAlias++;
4184098Seric 		return;
4194098Seric 	}
4204314Seric 
42150575Seric # if defined(DBM) || defined(NEWDB)
42219784Seric 	/* see if someone else is rebuilding the alias file already */
42351835Seric # ifdef LOCKF
42451937Seric 	fld.l_type = F_WRLCK;
42551937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
42651937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
42751835Seric # else
42819784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
42951835Seric # endif
43019784Seric 	{
43119784Seric 		/* yes, they are -- wait until done and then return */
43219784Seric 		message(Arpa_Info, "Alias file is already being rebuilt");
43319784Seric 		if (OpMode != MD_INITALIAS)
43419784Seric 		{
43519784Seric 			/* wait for other rebuild to complete */
43651835Seric # ifdef LOCKF
43751937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
43851835Seric # else
43919784Seric 			(void) flock(fileno(af), LOCK_EX);
44051835Seric # endif
44119784Seric 		}
44223108Seric 		(void) fclose(af);
44319784Seric 		errno = 0;
44419784Seric 		return;
44519784Seric 	}
44619784Seric # endif DBM
44719784Seric 
4484314Seric 	/*
44919784Seric 	**  If initializing, create the new DBM files.
45019784Seric 	*/
45119784Seric 
45219784Seric 	if (init)
45319784Seric 	{
45419784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
45551756Seric # ifdef NEWDB
45651756Seric 		(void) strcpy(line, aliasfile);
45751756Seric 		(void) strcat(line, ".db");
45851756Seric 		dbp = dbopen(line,
45951756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
46051756Seric 		if (dbp == NULL)
46151756Seric 		{
46251756Seric 			syserr("readaliases: cannot create %s", line);
46351756Seric 			(void) signal(SIGINT, oldsigint);
46451756Seric 			return;
46551756Seric 		}
46653742Seric # endif
46753742Seric # ifdef IF_MAKEDBMFILES
46853742Seric # ifdef NEWDB
46953742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
47053742Seric # endif
47153742Seric 		IF_MAKEDBMFILES
47219784Seric 		{
47353742Seric 			(void) strcpy(line, aliasfile);
47453742Seric 			(void) strcat(line, ".dir");
47553742Seric 			if (close(creat(line, DBMMODE)) < 0)
47653742Seric 			{
47753742Seric 				syserr("cannot make %s", line);
47853742Seric 				(void) signal(SIGINT, oldsigint);
47953742Seric 				return;
48053742Seric 			}
48153742Seric 			(void) strcpy(line, aliasfile);
48253742Seric 			(void) strcat(line, ".pag");
48353742Seric 			if (close(creat(line, DBMMODE)) < 0)
48453742Seric 			{
48553742Seric 				syserr("cannot make %s", line);
48653742Seric 				(void) signal(SIGINT, oldsigint);
48753742Seric 				return;
48853742Seric 			}
48953742Seric 			dbminit(aliasfile);
49019784Seric 		}
49150575Seric # endif
49219784Seric 	}
49319784Seric 
49419784Seric 	/*
4954314Seric 	**  Read and interpret lines
4964314Seric 	*/
4974314Seric 
4989368Seric 	FileName = aliasfile;
4999368Seric 	LineNumber = 0;
5004322Seric 	naliases = bytes = longest = 0;
5014098Seric 	skipping = FALSE;
5024098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5034098Seric 	{
5044322Seric 		int lhssize, rhssize;
5054322Seric 
5069368Seric 		LineNumber++;
50725278Seric 		p = index(line, '\n');
50825278Seric 		if (p != NULL)
50925278Seric 			*p = '\0';
5104098Seric 		switch (line[0])
5114098Seric 		{
5124098Seric 		  case '#':
5134098Seric 		  case '\0':
5144098Seric 			skipping = FALSE;
5154098Seric 			continue;
5164065Seric 
5174098Seric 		  case ' ':
5184098Seric 		  case '\t':
5194098Seric 			if (!skipping)
5209368Seric 				syserr("Non-continuation line starts with space");
5214098Seric 			skipping = TRUE;
5224097Seric 			continue;
5234098Seric 		}
5244098Seric 		skipping = FALSE;
5251874Seric 
5264314Seric 		/*
5274314Seric 		**  Process the LHS
5284314Seric 		**	Find the final colon, and parse the address.
52916898Seric 		**	It should resolve to a local name -- this will
53016898Seric 		**	be checked later (we want to optionally do
53116898Seric 		**	parsing of the RHS first to maximize error
53216898Seric 		**	detection).
5334314Seric 		*/
5344314Seric 
5354098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5364097Seric 			continue;
53716898Seric 		if (*p++ != ':')
5384098Seric 		{
5399368Seric 			syserr("missing colon");
5404097Seric 			continue;
5414098Seric 		}
542*55012Seric 		if (parseaddr(line, &al, 1, ':', e) == NULL)
5434098Seric 		{
54416898Seric 			syserr("illegal alias name");
54516898Seric 			continue;
5464098Seric 		}
54716898Seric 		loweraddr(&al);
5484314Seric 
5494314Seric 		/*
5504314Seric 		**  Process the RHS.
5514314Seric 		**	'al' is the internal form of the LHS address.
5524314Seric 		**	'p' points to the text of the RHS.
5534314Seric 		*/
5544314Seric 
5554098Seric 		rhs = p;
5564098Seric 		for (;;)
5574098Seric 		{
5584098Seric 			register char c;
5591515Seric 
56025821Seric 			if (init && CheckAliases)
5614098Seric 			{
5624157Seric 				/* do parsing & compression of addresses */
56325278Seric 				while (*p != '\0')
5644098Seric 				{
56525278Seric 					extern char *DelimChar;
56625278Seric 
56725278Seric 					while (isspace(*p) || *p == ',')
5684157Seric 						p++;
56925278Seric 					if (*p == '\0')
57025278Seric 						break;
571*55012Seric 					if (parseaddr(p, &bl, -1, ',', e) == NULL)
57225278Seric 						usrerr("%s... bad address", p);
57325278Seric 					p = DelimChar;
5744098Seric 				}
5754098Seric 			}
5764157Seric 			else
57715769Seric 			{
57816898Seric 				p = &p[strlen(p)];
57916898Seric 				if (p[-1] == '\n')
58016898Seric 					*--p = '\0';
58115769Seric 			}
5821515Seric 
5834098Seric 			/* see if there should be a continuation line */
5844106Seric 			c = fgetc(af);
5854106Seric 			if (!feof(af))
5864314Seric 				(void) ungetc(c, af);
5874106Seric 			if (c != ' ' && c != '\t')
5884098Seric 				break;
5894098Seric 
5904098Seric 			/* read continuation line */
5914098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
5924098Seric 				break;
5939368Seric 			LineNumber++;
5944098Seric 		}
59516898Seric 		if (al.q_mailer != LocalMailer)
59616898Seric 		{
59716898Seric 			syserr("cannot alias non-local names");
59816898Seric 			continue;
59916898Seric 		}
6004314Seric 
6014314Seric 		/*
6024314Seric 		**  Insert alias into symbol table or DBM file
6034314Seric 		*/
6044314Seric 
60516898Seric 		lhssize = strlen(al.q_user) + 1;
6064322Seric 		rhssize = strlen(rhs) + 1;
6074322Seric 
60850575Seric # if defined(DBM) || defined(NEWDB)
6094157Seric 		if (init)
6104157Seric 		{
61150575Seric 			DBT key, content;
6124157Seric 
61350575Seric 			key.size = lhssize;
61450575Seric 			key.data = al.q_user;
61550575Seric 			content.size = rhssize;
61650575Seric 			content.data = rhs;
61751756Seric # ifdef NEWDB
61851171Sbostic 			if (dbp->put(dbp, &key, &content, 0) != 0)
61950576Seric 				syserr("readaliases: db put (%s)", al.q_user);
62050575Seric # endif
62153742Seric # ifdef IF_MAKEDBMFILES
62253742Seric 			IF_MAKEDBMFILES
62353742Seric 				store(key, content);
62453742Seric # endif
6254157Seric 		}
6264157Seric 		else
6274157Seric # endif DBM
6284157Seric 		{
6294157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
6304157Seric 			s->s_alias = newstr(rhs);
6314157Seric 		}
6324322Seric 
6334322Seric 		/* statistics */
6344322Seric 		naliases++;
6354322Seric 		bytes += lhssize + rhssize;
6364322Seric 		if (rhssize > longest)
6374322Seric 			longest = rhssize;
6381515Seric 	}
63919784Seric 
64050575Seric # if defined(DBM) || defined(NEWDB)
64119784Seric 	if (init)
64219784Seric 	{
64319784Seric 		/* add the distinquished alias "@" */
64450575Seric 		DBT key;
64519784Seric 
64650575Seric 		key.size = 2;
64750575Seric 		key.data = "@";
64850575Seric # ifdef NEWDB
64950576Seric 		if (dbp->sync(dbp) != 0 ||
65051171Sbostic 		    dbp->put(dbp, &key, &key, 0) != 0 ||
65150576Seric 		    dbp->close(dbp) != 0)
65250576Seric 			syserr("readaliases: db close failure");
65353742Seric # endif
65453742Seric # ifdef MAKEDBMFILES
65519784Seric 		store(key, key);
65650575Seric # endif
65719784Seric 
65819784Seric 		/* restore the old signal */
65919784Seric 		(void) signal(SIGINT, oldsigint);
66019784Seric 	}
66119784Seric # endif DBM
66219784Seric 
66319784Seric 	/* closing the alias file drops the lock */
6644098Seric 	(void) fclose(af);
665*55012Seric 	e->e_to = NULL;
6669368Seric 	FileName = NULL;
6677051Seric 	message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
6684322Seric 			naliases, longest, bytes);
66924944Seric # ifdef LOG
67024944Seric 	if (LogLevel >= 8)
67124944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
67224944Seric 			naliases, longest, bytes);
67324944Seric # endif LOG
674292Seric }
675292Seric /*
676292Seric **  FORWARD -- Try to forward mail
677292Seric **
678292Seric **	This is similar but not identical to aliasing.
679292Seric **
680292Seric **	Parameters:
6814314Seric **		user -- the name of the user who's mail we would like
6824314Seric **			to forward to.  It must have been verified --
6834314Seric **			i.e., the q_home field must have been filled
6844314Seric **			in.
6854999Seric **		sendq -- a pointer to the head of the send queue to
6864999Seric **			put this user's aliases in.
687292Seric **
688292Seric **	Returns:
6894098Seric **		none.
690292Seric **
691292Seric **	Side Effects:
6923185Seric **		New names are added to send queues.
693292Seric */
694292Seric 
695*55012Seric forward(user, sendq, e)
6962966Seric 	ADDRESS *user;
6974999Seric 	ADDRESS **sendq;
698*55012Seric 	register ENVELOPE *e;
699292Seric {
7004078Seric 	char buf[60];
7014536Seric 	extern bool safefile();
7024069Seric 
7037671Seric 	if (tTd(27, 1))
7044098Seric 		printf("forward(%s)\n", user->q_paddr);
7054098Seric 
7064594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
7074098Seric 		return;
7084314Seric 	if (user->q_home == NULL)
7094314Seric 		syserr("forward: no home");
7104069Seric 
7114069Seric 	/* good address -- look for .forward file in home */
712*55012Seric 	define('z', user->q_home, e);
713*55012Seric 	expand("\001z/.forward", buf, &buf[sizeof buf - 1], e);
714*55012Seric 	include(buf, TRUE, user, sendq, e);
715292Seric }
716