xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 56766)
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 
24*56766Seric # ifdef NDBM
25*56766Seric # ifndef DBM
26*56766Seric # define DBM
27*56766Seric # endif
28*56766Seric # endif
29*56766Seric 
3033728Sbostic #ifndef lint
3151756Seric #ifdef NEWDB
32*56766Seric static char sccsid[] = "@(#)alias.c	5.35 (Berkeley) 11/13/92 (with NEWDB)";
3351756Seric #else
3433728Sbostic #ifdef DBM
35*56766Seric static char sccsid[] = "@(#)alias.c	5.35 (Berkeley) 11/13/92 (with DBM)";
3633728Sbostic #else
37*56766Seric static char sccsid[] = "@(#)alias.c	5.35 (Berkeley) 11/13/92 (without DBM)";
3833728Sbostic #endif
3950575Seric #endif
4033728Sbostic #endif /* not lint */
4151756Seric /*
42292Seric **  ALIAS -- Compute aliases.
43292Seric **
449368Seric **	Scans the alias file for an alias for the given address.
459368Seric **	If found, it arranges to deliver to the alias list instead.
469368Seric **	Uses libdbm database if -DDBM.
47292Seric **
48292Seric **	Parameters:
494097Seric **		a -- address to alias.
504999Seric **		sendq -- a pointer to the head of the send queue
514999Seric **			to put the aliases in.
52292Seric **
53292Seric **	Returns:
54292Seric **		none
55292Seric **
56292Seric **	Side Effects:
573185Seric **		Aliases found are expanded.
58292Seric **
59292Seric **	Notes:
60292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
61292Seric **			done.
62292Seric **
63292Seric **	Deficiencies:
64292Seric **		It should complain about names that are aliased to
65292Seric **			nothing.
66292Seric */
67292Seric 
68292Seric 
6953742Seric /*
7053742Seric **  Sun YP servers read the dbm files directly, so we have to build them
7153742Seric **  even if NEWDB
7253742Seric */
7353742Seric 
741503Smark #ifdef DBM
7553742Seric # ifndef NEWDB
7653742Seric #  define IF_MAKEDBMFILES
7753742Seric # else
7853742Seric #  ifdef YPCOMPAT
7953742Seric #   define IF_MAKEDBMFILES		if (makedbmfiles)
8053742Seric #  endif
8153742Seric # endif
8253742Seric #endif
8353742Seric 
8453742Seric #ifdef DBM
8551756Seric #ifndef NEWDB
862966Seric typedef struct
872966Seric {
8850575Seric 	char	*data;
8950575Seric 	int	size;
9050575Seric } DBT;
9151756Seric #endif
9250575Seric extern DBT fetch();
9350575Seric #endif /* DBM */
94292Seric 
9550575Seric #ifdef NEWDB
9650575Seric static DB	*AliasDBptr;
9750575Seric #endif
9850575Seric 
9955012Seric alias(a, sendq, e)
1004097Seric 	register ADDRESS *a;
1014999Seric 	ADDRESS **sendq;
10255012Seric 	register ENVELOPE *e;
103292Seric {
1044081Seric 	register char *p;
1055701Seric 	extern char *aliaslookup();
106292Seric 
1077671Seric 	if (tTd(27, 1))
1084098Seric 		printf("alias(%s)\n", a->q_paddr);
109292Seric 
1104098Seric 	/* don't realias already aliased names */
1114098Seric 	if (bitset(QDONTSEND, a->q_flags))
1124098Seric 		return;
1134098Seric 
11455012Seric 	e->e_to = a->q_paddr;
1154098Seric 
1164314Seric 	/*
1174314Seric 	**  Look up this name
1184314Seric 	*/
1194314Seric 
12024944Seric 	if (NoAlias)
12124944Seric 		p = NULL;
12224944Seric 	else
12324944Seric 		p = aliaslookup(a->q_user);
1244098Seric 	if (p == NULL)
1254098Seric 		return;
126292Seric 
127292Seric 	/*
1284098Seric 	**  Match on Alias.
1294098Seric 	**	Deliver to the target list.
1301515Seric 	*/
1311515Seric 
1327671Seric 	if (tTd(27, 1))
1334098Seric 		printf("%s (%s, %s) aliased to %s\n",
1344098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
1357051Seric 	message(Arpa_Info, "aliased to %s", p);
1364098Seric 	AliasLevel++;
13755012Seric 	sendtolist(p, a, sendq, e);
1384098Seric 	AliasLevel--;
1394098Seric }
1404098Seric /*
1415701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1425701Seric **
1435701Seric **	Parameters:
1445701Seric **		name -- the name to look up.
1455701Seric **
1465701Seric **	Returns:
1475701Seric **		the value of name.
1485701Seric **		NULL if unknown.
1495701Seric **
1505701Seric **	Side Effects:
1515701Seric **		none.
1525701Seric **
1535701Seric **	Warnings:
1545701Seric **		The return value will be trashed across calls.
1555701Seric */
1565701Seric 
1575701Seric char *
1585701Seric aliaslookup(name)
1595701Seric 	char *name;
1605701Seric {
16150575Seric # if defined(NEWDB) || defined(DBM)
16250575Seric 	DBT rhs, lhs;
16350575Seric 	int s;
1645701Seric 
1655701Seric 	/* create a key for fetch */
16650575Seric 	lhs.data = name;
16750575Seric 	lhs.size = strlen(name) + 1;
16850575Seric # ifdef NEWDB
16951756Seric 	if (AliasDBptr != NULL)
17051756Seric 	{
17151756Seric 		s = AliasDBptr->get(AliasDBptr, &lhs, &rhs, 0);
17251756Seric 		if (s == 0)
17351756Seric 			return (rhs.data);
17451756Seric 	}
17551756Seric # ifdef DBM
17651756Seric 	else
17751756Seric 	{
17851756Seric 		rhs = fetch(lhs);
17951756Seric 		return (rhs.data);
18051756Seric 	}
18151756Seric # endif
18250575Seric # else
1835701Seric 	rhs = fetch(lhs);
18451756Seric 	return (rhs.data);
18550575Seric # endif
18651756Seric # else /* neither NEWDB nor DBM */
1875701Seric 	register STAB *s;
1885701Seric 
1895701Seric 	s = stab(name, ST_ALIAS, ST_FIND);
19051756Seric 	if (s != NULL)
19151756Seric 		return (s->s_alias);
19251756Seric # endif
19351756Seric 	return (NULL);
1945701Seric }
1955701Seric /*
1964098Seric **  INITALIASES -- initialize for aliasing
1974098Seric **
1984098Seric **	Very different depending on whether we are running DBM or not.
1994098Seric **
2004098Seric **	Parameters:
2014098Seric **		aliasfile -- location of aliases.
2024157Seric **		init -- if set and if DBM, initialize the DBM files.
2034098Seric **
2044098Seric **	Returns:
2054098Seric **		none.
2064098Seric **
2074098Seric **	Side Effects:
2084098Seric **		initializes aliases:
2094098Seric **		if DBM:  opens the database.
2104098Seric **		if ~DBM: reads the aliases into the symbol table.
2114098Seric */
2124098Seric 
21340559Sbostic # define DBMMODE	0644
2144157Seric 
21555012Seric initaliases(aliasfile, init, e)
2164098Seric 	char *aliasfile;
2174157Seric 	bool init;
21855012Seric 	register ENVELOPE *e;
2194098Seric {
22050575Seric #if defined(DBM) || defined(NEWDB)
2218437Seric 	int atcnt;
22225522Seric 	time_t modtime;
22325522Seric 	bool automatic = FALSE;
2244322Seric 	char buf[MAXNAME];
22550575Seric #endif
2269368Seric 	struct stat stb;
22727176Seric 	static bool initialized = FALSE;
22846928Sbostic 	static int readaliases();
2294322Seric 
23027176Seric 	if (initialized)
23127176Seric 		return;
23227176Seric 	initialized = TRUE;
23327176Seric 
23417984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2358437Seric 	{
23625522Seric 		if (aliasfile != NULL && init)
23725522Seric 			syserr("Cannot open %s", aliasfile);
2388437Seric 		NoAlias = TRUE;
23911937Seric 		errno = 0;
2408437Seric 		return;
2418437Seric 	}
2428437Seric 
24350575Seric # if defined(DBM) || defined(NEWDB)
2444322Seric 	/*
2458437Seric 	**  Check to see that the alias file is complete.
2468437Seric 	**	If not, we will assume that someone died, and it is up
2478437Seric 	**	to us to rebuild it.
2488437Seric 	*/
2498437Seric 
25025689Seric 	if (!init)
25150575Seric 	{
25250575Seric # ifdef NEWDB
25350575Seric 		(void) strcpy(buf, aliasfile);
25450575Seric 		(void) strcat(buf, ".db");
25551171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
25650576Seric 		if (AliasDBptr == NULL)
25750576Seric 		{
25851756Seric # ifdef DBM
25951756Seric 			dbminit(aliasfile);
26051756Seric # else
26150576Seric 			syserr("initaliases: cannot open %s", buf);
26250576Seric 			NoAlias = TRUE;
26350576Seric 			return;
26451756Seric # endif
26550576Seric 		}
26650575Seric # else
26725689Seric 		dbminit(aliasfile);
26850575Seric # endif
26950575Seric 	}
27017471Seric 	atcnt = SafeAlias * 2;
27117471Seric 	if (atcnt > 0)
27217471Seric 	{
27317471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
27425689Seric 		{
27525689Seric 			/*
27625689Seric 			**  Reinitialize alias file in case the new
27725689Seric 			**  one is mv'ed in instead of cp'ed in.
27825689Seric 			**
27925689Seric 			**	Only works with new DBM -- old one will
28025689Seric 			**	just consume file descriptors forever.
28125689Seric 			**	If you have a dbmclose() it can be
28225689Seric 			**	added before the sleep(30).
28325689Seric 			*/
28425689Seric 
28550575Seric # ifdef NEWDB
28651756Seric 			if (AliasDBptr != NULL)
28751756Seric 				AliasDBptr->close(AliasDBptr);
28850575Seric # endif
28950575Seric 
29017471Seric 			sleep(30);
29150575Seric # ifdef NEWDB
29250575Seric 			(void) strcpy(buf, aliasfile);
29350575Seric 			(void) strcat(buf, ".db");
29451171Sbostic 			AliasDBptr =
29551171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
29650576Seric 			if (AliasDBptr == NULL)
29750576Seric 			{
29851756Seric # ifdef NDBM
29951756Seric 				dbminit(aliasfile);
30051756Seric # else
30150576Seric 				syserr("initaliases: cannot open %s", buf);
30250576Seric 				NoAlias = TRUE;
30350576Seric 				return;
30451756Seric # endif
30550576Seric 			}
30650575Seric # else
30725689Seric # ifdef NDBM
30825689Seric 			dbminit(aliasfile);
30950575Seric # endif
31050575Seric # endif
31125689Seric 		}
31217471Seric 	}
31317471Seric 	else
31417471Seric 		atcnt = 1;
3158437Seric 
3168437Seric 	/*
3174322Seric 	**  See if the DBM version of the file is out of date with
3184322Seric 	**  the text version.  If so, go into 'init' mode automatically.
31940559Sbostic 	**	This only happens if our effective userid owns the DBM.
32040559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
3214322Seric 	*/
3224322Seric 
3234322Seric 	modtime = stb.st_mtime;
3244322Seric 	(void) strcpy(buf, aliasfile);
32550575Seric # ifdef NEWDB
32650575Seric 	(void) strcat(buf, ".db");
32750575Seric # else
3284322Seric 	(void) strcat(buf, ".pag");
32950575Seric # endif
3304322Seric 	stb.st_ino = 0;
33119039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
3324322Seric 	{
33311937Seric 		errno = 0;
33440559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3354322Seric 		{
3364322Seric 			init = TRUE;
33725522Seric 			automatic = TRUE;
3387051Seric 			message(Arpa_Info, "rebuilding alias database");
33924944Seric #ifdef LOG
34024944Seric 			if (LogLevel >= 7)
34124944Seric 				syslog(LOG_INFO, "rebuilding alias database");
34224944Seric #endif LOG
3434322Seric 		}
3444322Seric 		else
3454322Seric 		{
34619039Seric #ifdef LOG
34724944Seric 			if (LogLevel >= 7)
34824944Seric 				syslog(LOG_INFO, "alias database out of date");
34919039Seric #endif LOG
3504322Seric 			message(Arpa_Info, "Warning: alias database out of date");
3514322Seric 		}
3524322Seric 	}
3534322Seric 
3544322Seric 
3554322Seric 	/*
3568437Seric 	**  If necessary, load the DBM file.
3574322Seric 	**	If running without DBM, load the symbol table.
3584322Seric 	*/
3594322Seric 
3604157Seric 	if (init)
3618437Seric 	{
36225522Seric #ifdef LOG
36325522Seric 		if (LogLevel >= 6)
36425522Seric 		{
36525522Seric 			extern char *username();
36625522Seric 
36725522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
36825522Seric 				automatic ? "auto" : "", username());
36925522Seric 		}
37025522Seric #endif LOG
37155012Seric 		readaliases(aliasfile, TRUE, e);
3728437Seric 	}
3734098Seric # else DBM
37455012Seric 	readaliases(aliasfile, init, e);
3754157Seric # endif DBM
3764157Seric }
3774157Seric /*
3784157Seric **  READALIASES -- read and process the alias file.
3794157Seric **
3804157Seric **	This routine implements the part of initaliases that occurs
3814157Seric **	when we are not going to use the DBM stuff.
3824157Seric **
3834157Seric **	Parameters:
3844157Seric **		aliasfile -- the pathname of the alias file master.
3854157Seric **		init -- if set, initialize the DBM stuff.
3864157Seric **
3874157Seric **	Returns:
3884157Seric **		none.
3894157Seric **
3904157Seric **	Side Effects:
3914157Seric **		Reads aliasfile into the symbol table.
3924157Seric **		Optionally, builds the .dir & .pag files.
3934157Seric */
3944157Seric 
3954157Seric static
39655012Seric readaliases(aliasfile, init, e)
3974157Seric 	char *aliasfile;
3984157Seric 	bool init;
39955012Seric 	register ENVELOPE *e;
4004157Seric {
4014098Seric 	register char *p;
4024098Seric 	char *rhs;
4034098Seric 	bool skipping;
4049368Seric 	int naliases, bytes, longest;
4059368Seric 	FILE *af;
40653742Seric 	bool makedbmfiles;
40740970Sbostic 	void (*oldsigint)();
4084098Seric 	ADDRESS al, bl;
4094106Seric 	register STAB *s;
41050575Seric # ifdef NEWDB
41150575Seric 	DB *dbp;
41250575Seric # endif
41351937Seric # ifdef LOCKF
41451937Seric 	struct flock fld;
41551937Seric # endif
4169368Seric 	char line[BUFSIZ];
4174098Seric 
41851937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
4191515Seric 	{
4207671Seric 		if (tTd(27, 1))
4214106Seric 			printf("Can't open %s\n", aliasfile);
4224098Seric 		errno = 0;
4234098Seric 		NoAlias++;
4244098Seric 		return;
4254098Seric 	}
4264314Seric 
42750575Seric # if defined(DBM) || defined(NEWDB)
42819784Seric 	/* see if someone else is rebuilding the alias file already */
42951835Seric # ifdef LOCKF
43051937Seric 	fld.l_type = F_WRLCK;
43151937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
43251937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
43351835Seric # else
43419784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
43551835Seric # endif
43619784Seric 	{
43719784Seric 		/* yes, they are -- wait until done and then return */
43819784Seric 		message(Arpa_Info, "Alias file is already being rebuilt");
43919784Seric 		if (OpMode != MD_INITALIAS)
44019784Seric 		{
44119784Seric 			/* wait for other rebuild to complete */
44251835Seric # ifdef LOCKF
44351937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
44451835Seric # else
44519784Seric 			(void) flock(fileno(af), LOCK_EX);
44651835Seric # endif
44719784Seric 		}
44823108Seric 		(void) fclose(af);
44919784Seric 		errno = 0;
45019784Seric 		return;
45119784Seric 	}
45219784Seric # endif DBM
45319784Seric 
4544314Seric 	/*
45519784Seric 	**  If initializing, create the new DBM files.
45619784Seric 	*/
45719784Seric 
45819784Seric 	if (init)
45919784Seric 	{
46019784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
46151756Seric # ifdef NEWDB
46251756Seric 		(void) strcpy(line, aliasfile);
46351756Seric 		(void) strcat(line, ".db");
46451756Seric 		dbp = dbopen(line,
46551756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
46651756Seric 		if (dbp == NULL)
46751756Seric 		{
46851756Seric 			syserr("readaliases: cannot create %s", line);
46951756Seric 			(void) signal(SIGINT, oldsigint);
47051756Seric 			return;
47151756Seric 		}
47253742Seric # endif
47353742Seric # ifdef IF_MAKEDBMFILES
47453742Seric # ifdef NEWDB
47553742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
47653742Seric # endif
47753742Seric 		IF_MAKEDBMFILES
47819784Seric 		{
47953742Seric 			(void) strcpy(line, aliasfile);
48053742Seric 			(void) strcat(line, ".dir");
48153742Seric 			if (close(creat(line, DBMMODE)) < 0)
48253742Seric 			{
48353742Seric 				syserr("cannot make %s", line);
48453742Seric 				(void) signal(SIGINT, oldsigint);
48553742Seric 				return;
48653742Seric 			}
48753742Seric 			(void) strcpy(line, aliasfile);
48853742Seric 			(void) strcat(line, ".pag");
48953742Seric 			if (close(creat(line, DBMMODE)) < 0)
49053742Seric 			{
49153742Seric 				syserr("cannot make %s", line);
49253742Seric 				(void) signal(SIGINT, oldsigint);
49353742Seric 				return;
49453742Seric 			}
49553742Seric 			dbminit(aliasfile);
49619784Seric 		}
49750575Seric # endif
49819784Seric 	}
49919784Seric 
50019784Seric 	/*
5014314Seric 	**  Read and interpret lines
5024314Seric 	*/
5034314Seric 
5049368Seric 	FileName = aliasfile;
5059368Seric 	LineNumber = 0;
5064322Seric 	naliases = bytes = longest = 0;
5074098Seric 	skipping = FALSE;
5084098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5094098Seric 	{
5104322Seric 		int lhssize, rhssize;
5114322Seric 
5129368Seric 		LineNumber++;
51325278Seric 		p = index(line, '\n');
51425278Seric 		if (p != NULL)
51525278Seric 			*p = '\0';
5164098Seric 		switch (line[0])
5174098Seric 		{
5184098Seric 		  case '#':
5194098Seric 		  case '\0':
5204098Seric 			skipping = FALSE;
5214098Seric 			continue;
5224065Seric 
5234098Seric 		  case ' ':
5244098Seric 		  case '\t':
5254098Seric 			if (!skipping)
5269368Seric 				syserr("Non-continuation line starts with space");
5274098Seric 			skipping = TRUE;
5284097Seric 			continue;
5294098Seric 		}
5304098Seric 		skipping = FALSE;
5311874Seric 
5324314Seric 		/*
5334314Seric 		**  Process the LHS
5344314Seric 		**	Find the final colon, and parse the address.
53516898Seric 		**	It should resolve to a local name -- this will
53616898Seric 		**	be checked later (we want to optionally do
53716898Seric 		**	parsing of the RHS first to maximize error
53816898Seric 		**	detection).
5394314Seric 		*/
5404314Seric 
5414098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5424097Seric 			continue;
54316898Seric 		if (*p++ != ':')
5444098Seric 		{
5459368Seric 			syserr("missing colon");
5464097Seric 			continue;
5474098Seric 		}
54855012Seric 		if (parseaddr(line, &al, 1, ':', e) == NULL)
5494098Seric 		{
55016898Seric 			syserr("illegal alias name");
55116898Seric 			continue;
5524098Seric 		}
55316898Seric 		loweraddr(&al);
5544314Seric 
5554314Seric 		/*
5564314Seric 		**  Process the RHS.
5574314Seric 		**	'al' is the internal form of the LHS address.
5584314Seric 		**	'p' points to the text of the RHS.
5594314Seric 		*/
5604314Seric 
5614098Seric 		rhs = p;
5624098Seric 		for (;;)
5634098Seric 		{
5644098Seric 			register char c;
5651515Seric 
56625821Seric 			if (init && CheckAliases)
5674098Seric 			{
5684157Seric 				/* do parsing & compression of addresses */
56925278Seric 				while (*p != '\0')
5704098Seric 				{
57125278Seric 					extern char *DelimChar;
57225278Seric 
57325278Seric 					while (isspace(*p) || *p == ',')
5744157Seric 						p++;
57525278Seric 					if (*p == '\0')
57625278Seric 						break;
57755012Seric 					if (parseaddr(p, &bl, -1, ',', e) == NULL)
57825278Seric 						usrerr("%s... bad address", p);
57925278Seric 					p = DelimChar;
5804098Seric 				}
5814098Seric 			}
5824157Seric 			else
58315769Seric 			{
58416898Seric 				p = &p[strlen(p)];
58516898Seric 				if (p[-1] == '\n')
58616898Seric 					*--p = '\0';
58715769Seric 			}
5881515Seric 
5894098Seric 			/* see if there should be a continuation line */
5904106Seric 			c = fgetc(af);
5914106Seric 			if (!feof(af))
5924314Seric 				(void) ungetc(c, af);
5934106Seric 			if (c != ' ' && c != '\t')
5944098Seric 				break;
5954098Seric 
5964098Seric 			/* read continuation line */
5974098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
5984098Seric 				break;
5999368Seric 			LineNumber++;
6004098Seric 		}
60116898Seric 		if (al.q_mailer != LocalMailer)
60216898Seric 		{
60316898Seric 			syserr("cannot alias non-local names");
60416898Seric 			continue;
60516898Seric 		}
6064314Seric 
6074314Seric 		/*
6084314Seric 		**  Insert alias into symbol table or DBM file
6094314Seric 		*/
6104314Seric 
61116898Seric 		lhssize = strlen(al.q_user) + 1;
6124322Seric 		rhssize = strlen(rhs) + 1;
6134322Seric 
61450575Seric # if defined(DBM) || defined(NEWDB)
6154157Seric 		if (init)
6164157Seric 		{
61750575Seric 			DBT key, content;
6184157Seric 
61950575Seric 			key.size = lhssize;
62050575Seric 			key.data = al.q_user;
62150575Seric 			content.size = rhssize;
62250575Seric 			content.data = rhs;
62351756Seric # ifdef NEWDB
62451171Sbostic 			if (dbp->put(dbp, &key, &content, 0) != 0)
62550576Seric 				syserr("readaliases: db put (%s)", al.q_user);
62650575Seric # endif
62753742Seric # ifdef IF_MAKEDBMFILES
62853742Seric 			IF_MAKEDBMFILES
62953742Seric 				store(key, content);
63053742Seric # endif
6314157Seric 		}
6324157Seric 		else
6334157Seric # endif DBM
6344157Seric 		{
6354157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
6364157Seric 			s->s_alias = newstr(rhs);
6374157Seric 		}
6384322Seric 
6394322Seric 		/* statistics */
6404322Seric 		naliases++;
6414322Seric 		bytes += lhssize + rhssize;
6424322Seric 		if (rhssize > longest)
6434322Seric 			longest = rhssize;
6441515Seric 	}
64519784Seric 
64650575Seric # if defined(DBM) || defined(NEWDB)
64719784Seric 	if (init)
64819784Seric 	{
64919784Seric 		/* add the distinquished alias "@" */
65050575Seric 		DBT key;
65119784Seric 
65250575Seric 		key.size = 2;
65350575Seric 		key.data = "@";
65450575Seric # ifdef NEWDB
65550576Seric 		if (dbp->sync(dbp) != 0 ||
65651171Sbostic 		    dbp->put(dbp, &key, &key, 0) != 0 ||
65750576Seric 		    dbp->close(dbp) != 0)
65850576Seric 			syserr("readaliases: db close failure");
65953742Seric # endif
66053742Seric # ifdef MAKEDBMFILES
66119784Seric 		store(key, key);
66250575Seric # endif
66319784Seric 
66419784Seric 		/* restore the old signal */
66519784Seric 		(void) signal(SIGINT, oldsigint);
66619784Seric 	}
66719784Seric # endif DBM
66819784Seric 
66919784Seric 	/* closing the alias file drops the lock */
6704098Seric 	(void) fclose(af);
67155012Seric 	e->e_to = NULL;
6729368Seric 	FileName = NULL;
6737051Seric 	message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
6744322Seric 			naliases, longest, bytes);
67524944Seric # ifdef LOG
67624944Seric 	if (LogLevel >= 8)
67724944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
67824944Seric 			naliases, longest, bytes);
67924944Seric # endif LOG
680292Seric }
681292Seric /*
682292Seric **  FORWARD -- Try to forward mail
683292Seric **
684292Seric **	This is similar but not identical to aliasing.
685292Seric **
686292Seric **	Parameters:
6874314Seric **		user -- the name of the user who's mail we would like
6884314Seric **			to forward to.  It must have been verified --
6894314Seric **			i.e., the q_home field must have been filled
6904314Seric **			in.
6914999Seric **		sendq -- a pointer to the head of the send queue to
6924999Seric **			put this user's aliases in.
693292Seric **
694292Seric **	Returns:
6954098Seric **		none.
696292Seric **
697292Seric **	Side Effects:
6983185Seric **		New names are added to send queues.
699292Seric */
700292Seric 
70155012Seric forward(user, sendq, e)
7022966Seric 	ADDRESS *user;
7034999Seric 	ADDRESS **sendq;
70455012Seric 	register ENVELOPE *e;
705292Seric {
7064078Seric 	char buf[60];
7074536Seric 	extern bool safefile();
7084069Seric 
7097671Seric 	if (tTd(27, 1))
7104098Seric 		printf("forward(%s)\n", user->q_paddr);
7114098Seric 
7124594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
7134098Seric 		return;
7144314Seric 	if (user->q_home == NULL)
7154314Seric 		syserr("forward: no home");
7164069Seric 
7174069Seric 	/* good address -- look for .forward file in home */
71855012Seric 	define('z', user->q_home, e);
71955012Seric 	expand("\001z/.forward", buf, &buf[sizeof buf - 1], e);
72055012Seric 	include(buf, TRUE, user, sendq, e);
721292Seric }
722