xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 56848)
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 "sendmail.h"
1350577Seric # include <sys/file.h>
1450577Seric # include <pwd.h>
1551937Seric # ifdef LOCKF
1651937Seric # include <fcntl.h>
1751937Seric # endif
1850577Seric 
1956845Seric # ifdef DBM
20*56848Seric ERROR: DBM is no longer supported -- use NDBM instead.
2156845Seric # endif
2256845Seric 
2350577Seric # ifdef NEWDB
2450577Seric # include <db.h>
2550577Seric # endif
2650577Seric 
2756766Seric # ifdef NDBM
2856845Seric # include <ndbm.h>
2956766Seric # endif
3056766Seric 
3133728Sbostic #ifndef lint
3251756Seric #ifdef NEWDB
33*56848Seric static char sccsid[] = "@(#)alias.c	5.40 (Berkeley) 11/16/92 (with NEWDB)";
3451756Seric #else
3556845Seric #ifdef NDBM
36*56848Seric static char sccsid[] = "@(#)alias.c	5.40 (Berkeley) 11/16/92 (with NDBM)";
3733728Sbostic #else
38*56848Seric static char sccsid[] = "@(#)alias.c	5.40 (Berkeley) 11/16/92 (without NDBM)";
3933728Sbostic #endif
4050575Seric #endif
4133728Sbostic #endif /* not lint */
4251756Seric /*
43292Seric **  ALIAS -- Compute aliases.
44292Seric **
459368Seric **	Scans the alias file for an alias for the given address.
469368Seric **	If found, it arranges to deliver to the alias list instead.
479368Seric **	Uses libdbm database if -DDBM.
48292Seric **
49292Seric **	Parameters:
504097Seric **		a -- address to alias.
514999Seric **		sendq -- a pointer to the head of the send queue
524999Seric **			to put the aliases in.
53292Seric **
54292Seric **	Returns:
55292Seric **		none
56292Seric **
57292Seric **	Side Effects:
583185Seric **		Aliases found are expanded.
59292Seric **
60292Seric **	Notes:
61292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
62292Seric **			done.
63292Seric **
64292Seric **	Deficiencies:
65292Seric **		It should complain about names that are aliased to
66292Seric **			nothing.
67292Seric */
68292Seric 
69292Seric 
7053742Seric /*
7153742Seric **  Sun YP servers read the dbm files directly, so we have to build them
7253742Seric **  even if NEWDB
7353742Seric */
7453742Seric 
7556845Seric #ifdef NDBM
7653742Seric # ifndef NEWDB
7753742Seric #  define IF_MAKEDBMFILES
7853742Seric # else
7953742Seric #  ifdef YPCOMPAT
8053742Seric #   define IF_MAKEDBMFILES		if (makedbmfiles)
8153742Seric #  endif
8253742Seric # endif
8353742Seric #endif
8453742Seric 
8556845Seric typedef union
862966Seric {
8756845Seric #ifdef NDBM
8856845Seric 	datum	dbm;
8951756Seric #endif
9056845Seric #ifdef NEWDB
9156845Seric 	DBT	dbt;
9256845Seric #endif
9356845Seric 	struct
9456845Seric 	{
9556845Seric 		char	*data;
9656845Seric 		int	size;
9756845Seric 	} xx;
9856845Seric } DBdatum;
99292Seric 
10050575Seric #ifdef NEWDB
10150575Seric static DB	*AliasDBptr;
10250575Seric #endif
10356845Seric #ifdef NDBM
10456845Seric static DBM	*AliasDBMptr;
10556845Seric #endif
10650575Seric 
10755012Seric alias(a, sendq, e)
1084097Seric 	register ADDRESS *a;
1094999Seric 	ADDRESS **sendq;
11055012Seric 	register ENVELOPE *e;
111292Seric {
1124081Seric 	register char *p;
1135701Seric 	extern char *aliaslookup();
114292Seric 
1157671Seric 	if (tTd(27, 1))
1164098Seric 		printf("alias(%s)\n", a->q_paddr);
117292Seric 
1184098Seric 	/* don't realias already aliased names */
1194098Seric 	if (bitset(QDONTSEND, a->q_flags))
1204098Seric 		return;
1214098Seric 
12255012Seric 	e->e_to = a->q_paddr;
1234098Seric 
1244314Seric 	/*
1254314Seric 	**  Look up this name
1264314Seric 	*/
1274314Seric 
12824944Seric 	if (NoAlias)
12924944Seric 		p = NULL;
13024944Seric 	else
13124944Seric 		p = aliaslookup(a->q_user);
1324098Seric 	if (p == NULL)
1334098Seric 		return;
134292Seric 
135292Seric 	/*
1364098Seric 	**  Match on Alias.
1374098Seric 	**	Deliver to the target list.
1381515Seric 	*/
1391515Seric 
1407671Seric 	if (tTd(27, 1))
1414098Seric 		printf("%s (%s, %s) aliased to %s\n",
1424098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
1437051Seric 	message(Arpa_Info, "aliased to %s", p);
1444098Seric 	AliasLevel++;
14555012Seric 	sendtolist(p, a, sendq, e);
1464098Seric 	AliasLevel--;
1474098Seric }
1484098Seric /*
1495701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1505701Seric **
1515701Seric **	Parameters:
1525701Seric **		name -- the name to look up.
1535701Seric **
1545701Seric **	Returns:
1555701Seric **		the value of name.
1565701Seric **		NULL if unknown.
1575701Seric **
1585701Seric **	Side Effects:
1595701Seric **		none.
1605701Seric **
1615701Seric **	Warnings:
1625701Seric **		The return value will be trashed across calls.
1635701Seric */
1645701Seric 
1655701Seric char *
1665701Seric aliaslookup(name)
1675701Seric 	char *name;
1685701Seric {
16956845Seric # if defined(NEWDB) || defined(NDBM)
17056845Seric 	DBdatum rhs, lhs;
17150575Seric 	int s;
1725701Seric 
1735701Seric 	/* create a key for fetch */
17456845Seric 	lhs.xx.data = name;
17556845Seric 	lhs.xx.size = strlen(name) + 1;
17650575Seric # ifdef NEWDB
17751756Seric 	if (AliasDBptr != NULL)
17851756Seric 	{
17956845Seric 		s = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
18051756Seric 		if (s == 0)
18156845Seric 			return (rhs.dbt.data);
18251756Seric 	}
18356845Seric # ifdef NDBM
18451756Seric 	else
18551756Seric 	{
18656845Seric 		rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
18756845Seric 		return (rhs.dbm.dptr);
18851756Seric 	}
18956845Seric # endif /* NDBM */
19056845Seric # else /* not NEWDB */
19156845Seric 	rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
19256845Seric 	return (rhs.dbm.dptr);
19356845Seric # endif /* NEWDB */
19456845Seric # else /* neither NEWDB nor NDBM */
1955701Seric 	register STAB *s;
1965701Seric 
1975701Seric 	s = stab(name, ST_ALIAS, ST_FIND);
19851756Seric 	if (s != NULL)
19951756Seric 		return (s->s_alias);
20051756Seric # endif
20151756Seric 	return (NULL);
2025701Seric }
2035701Seric /*
2044098Seric **  INITALIASES -- initialize for aliasing
2054098Seric **
20656845Seric **	Very different depending on whether we are running NDBM or not.
2074098Seric **
2084098Seric **	Parameters:
2094098Seric **		aliasfile -- location of aliases.
21056845Seric **		init -- if set and if NDBM, initialize the NDBM files.
2114098Seric **
2124098Seric **	Returns:
2134098Seric **		none.
2144098Seric **
2154098Seric **	Side Effects:
2164098Seric **		initializes aliases:
21756845Seric **		if NDBM:  opens the database.
21856845Seric **		if ~NDBM: reads the aliases into the symbol table.
2194098Seric */
2204098Seric 
22140559Sbostic # define DBMMODE	0644
2224157Seric 
22355012Seric initaliases(aliasfile, init, e)
2244098Seric 	char *aliasfile;
2254157Seric 	bool init;
22655012Seric 	register ENVELOPE *e;
2274098Seric {
22856845Seric #if defined(NDBM) || defined(NEWDB)
2298437Seric 	int atcnt;
23025522Seric 	time_t modtime;
23125522Seric 	bool automatic = FALSE;
2324322Seric 	char buf[MAXNAME];
23350575Seric #endif
2349368Seric 	struct stat stb;
23527176Seric 	static bool initialized = FALSE;
23646928Sbostic 	static int readaliases();
2374322Seric 
23827176Seric 	if (initialized)
23927176Seric 		return;
24027176Seric 	initialized = TRUE;
24127176Seric 
24217984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2438437Seric 	{
24425522Seric 		if (aliasfile != NULL && init)
24525522Seric 			syserr("Cannot open %s", aliasfile);
2468437Seric 		NoAlias = TRUE;
24711937Seric 		errno = 0;
2488437Seric 		return;
2498437Seric 	}
2508437Seric 
25156845Seric # if defined(NDBM) || defined(NEWDB)
2524322Seric 	/*
2538437Seric 	**  Check to see that the alias file is complete.
2548437Seric 	**	If not, we will assume that someone died, and it is up
2558437Seric 	**	to us to rebuild it.
2568437Seric 	*/
2578437Seric 
25825689Seric 	if (!init)
25950575Seric 	{
26050575Seric # ifdef NEWDB
26150575Seric 		(void) strcpy(buf, aliasfile);
26250575Seric 		(void) strcat(buf, ".db");
26351171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
26450576Seric 		if (AliasDBptr == NULL)
26550576Seric 		{
26656845Seric # ifdef NDBM
26756845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
26851756Seric # else
26950576Seric 			syserr("initaliases: cannot open %s", buf);
27050576Seric 			NoAlias = TRUE;
27150576Seric 			return;
27251756Seric # endif
27350576Seric 		}
27450575Seric # else
27556845Seric 		AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
27650575Seric # endif
27750575Seric 	}
27817471Seric 	atcnt = SafeAlias * 2;
27917471Seric 	if (atcnt > 0)
28017471Seric 	{
28117471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
28225689Seric 		{
28325689Seric 			/*
28425689Seric 			**  Reinitialize alias file in case the new
28525689Seric 			**  one is mv'ed in instead of cp'ed in.
28625689Seric 			**
28725689Seric 			**	Only works with new DBM -- old one will
28825689Seric 			**	just consume file descriptors forever.
28925689Seric 			**	If you have a dbmclose() it can be
29025689Seric 			**	added before the sleep(30).
29125689Seric 			*/
29225689Seric 
29350575Seric # ifdef NEWDB
29451756Seric 			if (AliasDBptr != NULL)
29551756Seric 				AliasDBptr->close(AliasDBptr);
29650575Seric # endif
29756845Seric # ifdef NDBM
29856845Seric 			if (AliasDBMptr != NULL)
29956845Seric 				dbm_close(AliasDBMptr);
30056845Seric # endif
30150575Seric 
30217471Seric 			sleep(30);
30350575Seric # ifdef NEWDB
30450575Seric 			(void) strcpy(buf, aliasfile);
30550575Seric 			(void) strcat(buf, ".db");
30651171Sbostic 			AliasDBptr =
30751171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
30850576Seric 			if (AliasDBptr == NULL)
30950576Seric 			{
31051756Seric # ifdef NDBM
31156845Seric 				AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
31251756Seric # else
31350576Seric 				syserr("initaliases: cannot open %s", buf);
31450576Seric 				NoAlias = TRUE;
31550576Seric 				return;
31651756Seric # endif
31750576Seric 			}
31850575Seric # else
31925689Seric # ifdef NDBM
32056845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
32150575Seric # endif
32250575Seric # endif
32325689Seric 		}
32417471Seric 	}
32517471Seric 	else
32617471Seric 		atcnt = 1;
3278437Seric 
3288437Seric 	/*
32956845Seric 	**  See if the NDBM version of the file is out of date with
3304322Seric 	**  the text version.  If so, go into 'init' mode automatically.
33140559Sbostic 	**	This only happens if our effective userid owns the DBM.
33240559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
3334322Seric 	*/
3344322Seric 
3354322Seric 	modtime = stb.st_mtime;
3364322Seric 	(void) strcpy(buf, aliasfile);
33750575Seric # ifdef NEWDB
33850575Seric 	(void) strcat(buf, ".db");
33950575Seric # else
3404322Seric 	(void) strcat(buf, ".pag");
34150575Seric # endif
3424322Seric 	stb.st_ino = 0;
34319039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
3444322Seric 	{
34511937Seric 		errno = 0;
34640559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3474322Seric 		{
3484322Seric 			init = TRUE;
34925522Seric 			automatic = TRUE;
3507051Seric 			message(Arpa_Info, "rebuilding alias database");
35124944Seric #ifdef LOG
35224944Seric 			if (LogLevel >= 7)
35324944Seric 				syslog(LOG_INFO, "rebuilding alias database");
35456795Seric #endif /* LOG */
3554322Seric 		}
3564322Seric 		else
3574322Seric 		{
35819039Seric #ifdef LOG
35924944Seric 			if (LogLevel >= 7)
36024944Seric 				syslog(LOG_INFO, "alias database out of date");
36156795Seric #endif /* LOG */
3624322Seric 			message(Arpa_Info, "Warning: alias database out of date");
3634322Seric 		}
3644322Seric 	}
3654322Seric 
3664322Seric 
3674322Seric 	/*
36856845Seric 	**  If necessary, load the NDBM file.
36956845Seric 	**	If running without NDBM, load the symbol table.
3704322Seric 	*/
3714322Seric 
3724157Seric 	if (init)
3738437Seric 	{
37425522Seric #ifdef LOG
37525522Seric 		if (LogLevel >= 6)
37625522Seric 		{
37725522Seric 			extern char *username();
37825522Seric 
37925522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
38025522Seric 				automatic ? "auto" : "", username());
38125522Seric 		}
38256795Seric #endif /* LOG */
38355012Seric 		readaliases(aliasfile, TRUE, e);
3848437Seric 	}
38556845Seric # else /* NDBM */
38655012Seric 	readaliases(aliasfile, init, e);
38756845Seric # endif /* NDBM */
3884157Seric }
3894157Seric /*
3904157Seric **  READALIASES -- read and process the alias file.
3914157Seric **
3924157Seric **	This routine implements the part of initaliases that occurs
3934157Seric **	when we are not going to use the DBM stuff.
3944157Seric **
3954157Seric **	Parameters:
3964157Seric **		aliasfile -- the pathname of the alias file master.
39756845Seric **		init -- if set, initialize the NDBM stuff.
3984157Seric **
3994157Seric **	Returns:
4004157Seric **		none.
4014157Seric **
4024157Seric **	Side Effects:
4034157Seric **		Reads aliasfile into the symbol table.
4044157Seric **		Optionally, builds the .dir & .pag files.
4054157Seric */
4064157Seric 
4074157Seric static
40855012Seric readaliases(aliasfile, init, e)
4094157Seric 	char *aliasfile;
4104157Seric 	bool init;
41155012Seric 	register ENVELOPE *e;
4124157Seric {
4134098Seric 	register char *p;
4144098Seric 	char *rhs;
4154098Seric 	bool skipping;
4169368Seric 	int naliases, bytes, longest;
4179368Seric 	FILE *af;
41853742Seric 	bool makedbmfiles;
41940970Sbostic 	void (*oldsigint)();
4204098Seric 	ADDRESS al, bl;
4214106Seric 	register STAB *s;
42250575Seric # ifdef NEWDB
42350575Seric 	DB *dbp;
42450575Seric # endif
42556845Seric # ifdef NDBM
42656845Seric 	DBM *dbmp;
42756845Seric # endif
42851937Seric # ifdef LOCKF
42951937Seric 	struct flock fld;
43051937Seric # endif
4319368Seric 	char line[BUFSIZ];
4324098Seric 
43351937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
4341515Seric 	{
4357671Seric 		if (tTd(27, 1))
4364106Seric 			printf("Can't open %s\n", aliasfile);
4374098Seric 		errno = 0;
4384098Seric 		NoAlias++;
4394098Seric 		return;
4404098Seric 	}
4414314Seric 
44256845Seric # if defined(NDBM) || defined(NEWDB)
44319784Seric 	/* see if someone else is rebuilding the alias file already */
44451835Seric # ifdef LOCKF
44551937Seric 	fld.l_type = F_WRLCK;
44651937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
44751937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
44851835Seric # else
44919784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
45051835Seric # endif
45119784Seric 	{
45219784Seric 		/* yes, they are -- wait until done and then return */
45319784Seric 		message(Arpa_Info, "Alias file is already being rebuilt");
45419784Seric 		if (OpMode != MD_INITALIAS)
45519784Seric 		{
45619784Seric 			/* wait for other rebuild to complete */
45751835Seric # ifdef LOCKF
45851937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
45951835Seric # else
46019784Seric 			(void) flock(fileno(af), LOCK_EX);
46151835Seric # endif
46219784Seric 		}
46323108Seric 		(void) fclose(af);
46419784Seric 		errno = 0;
46519784Seric 		return;
46619784Seric 	}
46756845Seric # endif /* NDBM */
46819784Seric 
4694314Seric 	/*
47019784Seric 	**  If initializing, create the new DBM files.
47119784Seric 	*/
47219784Seric 
47319784Seric 	if (init)
47419784Seric 	{
47519784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
47651756Seric # ifdef NEWDB
47751756Seric 		(void) strcpy(line, aliasfile);
47851756Seric 		(void) strcat(line, ".db");
47951756Seric 		dbp = dbopen(line,
48051756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
48151756Seric 		if (dbp == NULL)
48251756Seric 		{
48351756Seric 			syserr("readaliases: cannot create %s", line);
48451756Seric 			(void) signal(SIGINT, oldsigint);
48551756Seric 			return;
48651756Seric 		}
48753742Seric # endif
48853742Seric # ifdef IF_MAKEDBMFILES
48953742Seric # ifdef NEWDB
49053742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
49153742Seric # endif
49253742Seric 		IF_MAKEDBMFILES
49319784Seric 		{
49456845Seric 			dbmp = dbm_open(aliasfile,
49556845Seric 					       O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
49656845Seric 			if (dbmp == NULL)
49753742Seric 			{
49856845Seric 				syserr("readaliases: cannot create %s.{dir,pag}",
49956845Seric 					aliasfile);
50053742Seric 				(void) signal(SIGINT, oldsigint);
50153742Seric 				return;
50253742Seric 			}
50319784Seric 		}
50450575Seric # endif
50519784Seric 	}
50619784Seric 
50719784Seric 	/*
5084314Seric 	**  Read and interpret lines
5094314Seric 	*/
5104314Seric 
5119368Seric 	FileName = aliasfile;
5129368Seric 	LineNumber = 0;
5134322Seric 	naliases = bytes = longest = 0;
5144098Seric 	skipping = FALSE;
5154098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5164098Seric 	{
5174322Seric 		int lhssize, rhssize;
5184322Seric 
5199368Seric 		LineNumber++;
52056795Seric 		p = strchr(line, '\n');
52125278Seric 		if (p != NULL)
52225278Seric 			*p = '\0';
5234098Seric 		switch (line[0])
5244098Seric 		{
5254098Seric 		  case '#':
5264098Seric 		  case '\0':
5274098Seric 			skipping = FALSE;
5284098Seric 			continue;
5294065Seric 
5304098Seric 		  case ' ':
5314098Seric 		  case '\t':
5324098Seric 			if (!skipping)
5339368Seric 				syserr("Non-continuation line starts with space");
5344098Seric 			skipping = TRUE;
5354097Seric 			continue;
5364098Seric 		}
5374098Seric 		skipping = FALSE;
5381874Seric 
5394314Seric 		/*
5404314Seric 		**  Process the LHS
5414314Seric 		**	Find the final colon, and parse the address.
54216898Seric 		**	It should resolve to a local name -- this will
54316898Seric 		**	be checked later (we want to optionally do
54416898Seric 		**	parsing of the RHS first to maximize error
54516898Seric 		**	detection).
5464314Seric 		*/
5474314Seric 
5484098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5494097Seric 			continue;
55016898Seric 		if (*p++ != ':')
5514098Seric 		{
5529368Seric 			syserr("missing colon");
5534097Seric 			continue;
5544098Seric 		}
55555012Seric 		if (parseaddr(line, &al, 1, ':', e) == NULL)
5564098Seric 		{
55716898Seric 			syserr("illegal alias name");
55816898Seric 			continue;
5594098Seric 		}
56016898Seric 		loweraddr(&al);
5614314Seric 
5624314Seric 		/*
5634314Seric 		**  Process the RHS.
5644314Seric 		**	'al' is the internal form of the LHS address.
5654314Seric 		**	'p' points to the text of the RHS.
5664314Seric 		*/
5674314Seric 
5684098Seric 		rhs = p;
5694098Seric 		for (;;)
5704098Seric 		{
5714098Seric 			register char c;
5721515Seric 
57325821Seric 			if (init && CheckAliases)
5744098Seric 			{
5754157Seric 				/* do parsing & compression of addresses */
57625278Seric 				while (*p != '\0')
5774098Seric 				{
57825278Seric 					extern char *DelimChar;
57925278Seric 
58025278Seric 					while (isspace(*p) || *p == ',')
5814157Seric 						p++;
58225278Seric 					if (*p == '\0')
58325278Seric 						break;
58455012Seric 					if (parseaddr(p, &bl, -1, ',', e) == NULL)
58525278Seric 						usrerr("%s... bad address", p);
58625278Seric 					p = DelimChar;
5874098Seric 				}
5884098Seric 			}
5894157Seric 			else
59015769Seric 			{
59116898Seric 				p = &p[strlen(p)];
59216898Seric 				if (p[-1] == '\n')
59316898Seric 					*--p = '\0';
59415769Seric 			}
5951515Seric 
5964098Seric 			/* see if there should be a continuation line */
5974106Seric 			c = fgetc(af);
5984106Seric 			if (!feof(af))
5994314Seric 				(void) ungetc(c, af);
6004106Seric 			if (c != ' ' && c != '\t')
6014098Seric 				break;
6024098Seric 
6034098Seric 			/* read continuation line */
6044098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6054098Seric 				break;
6069368Seric 			LineNumber++;
6074098Seric 		}
60816898Seric 		if (al.q_mailer != LocalMailer)
60916898Seric 		{
61016898Seric 			syserr("cannot alias non-local names");
61116898Seric 			continue;
61216898Seric 		}
6134314Seric 
6144314Seric 		/*
6154314Seric 		**  Insert alias into symbol table or DBM file
6164314Seric 		*/
6174314Seric 
61816898Seric 		lhssize = strlen(al.q_user) + 1;
6194322Seric 		rhssize = strlen(rhs) + 1;
6204322Seric 
62156845Seric # if defined(NDBM) || defined(NEWDB)
6224157Seric 		if (init)
6234157Seric 		{
62456845Seric 			DBdatum key, content;
6254157Seric 
62656845Seric 			key.xx.size = lhssize;
62756845Seric 			key.xx.data = al.q_user;
62856845Seric 			content.xx.size = rhssize;
62956845Seric 			content.xx.data = rhs;
63051756Seric # ifdef NEWDB
63156845Seric 			if (dbp->put(dbp, &key.dbt, &content.dbt, 0) != 0)
63250576Seric 				syserr("readaliases: db put (%s)", al.q_user);
63350575Seric # endif
63453742Seric # ifdef IF_MAKEDBMFILES
63553742Seric 			IF_MAKEDBMFILES
63656845Seric 				if (dbm_store(dbmp, key.dbm, content.dbm, DBM_REPLACE) != 0)
63756845Seric 					syserr("readaliases: dbm store (%s)",
63856845Seric 						al.q_user);
63953742Seric # endif
6404157Seric 		}
6414157Seric 		else
64256845Seric # endif /* NDBM */
6434157Seric 		{
6444157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
6454157Seric 			s->s_alias = newstr(rhs);
6464157Seric 		}
6474322Seric 
6484322Seric 		/* statistics */
6494322Seric 		naliases++;
6504322Seric 		bytes += lhssize + rhssize;
6514322Seric 		if (rhssize > longest)
6524322Seric 			longest = rhssize;
6531515Seric 	}
65419784Seric 
65556845Seric # if defined(NDBM) || defined(NEWDB)
65619784Seric 	if (init)
65719784Seric 	{
65819784Seric 		/* add the distinquished alias "@" */
65956845Seric 		DBdatum key;
66019784Seric 
66156845Seric 		key.xx.size = 2;
66256845Seric 		key.xx.data = "@";
66350575Seric # ifdef NEWDB
66450576Seric 		if (dbp->sync(dbp) != 0 ||
66556845Seric 		    dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
66650576Seric 		    dbp->close(dbp) != 0)
66750576Seric 			syserr("readaliases: db close failure");
66853742Seric # endif
66956789Seric # ifdef IF_MAKEDBMFILES
67056793Seric 		IF_MAKEDBMFILES
67156845Seric 		{
67256845Seric 			if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
67356845Seric 			    dbm_error(dbmp))
67456845Seric 				syserr("readaliases: dbm close failure");
67556845Seric 			dbm_close(dbmp);
67656845Seric 		}
67750575Seric # endif
67819784Seric 
67919784Seric 		/* restore the old signal */
68019784Seric 		(void) signal(SIGINT, oldsigint);
68119784Seric 	}
68256845Seric # endif /* NDBM */
68319784Seric 
68419784Seric 	/* closing the alias file drops the lock */
6854098Seric 	(void) fclose(af);
68655012Seric 	e->e_to = NULL;
6879368Seric 	FileName = NULL;
6887051Seric 	message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
6894322Seric 			naliases, longest, bytes);
69024944Seric # ifdef LOG
69124944Seric 	if (LogLevel >= 8)
69224944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
69324944Seric 			naliases, longest, bytes);
69456795Seric # endif /* LOG */
695292Seric }
696292Seric /*
697292Seric **  FORWARD -- Try to forward mail
698292Seric **
699292Seric **	This is similar but not identical to aliasing.
700292Seric **
701292Seric **	Parameters:
7024314Seric **		user -- the name of the user who's mail we would like
7034314Seric **			to forward to.  It must have been verified --
7044314Seric **			i.e., the q_home field must have been filled
7054314Seric **			in.
7064999Seric **		sendq -- a pointer to the head of the send queue to
7074999Seric **			put this user's aliases in.
708292Seric **
709292Seric **	Returns:
7104098Seric **		none.
711292Seric **
712292Seric **	Side Effects:
7133185Seric **		New names are added to send queues.
714292Seric */
715292Seric 
71655012Seric forward(user, sendq, e)
7172966Seric 	ADDRESS *user;
7184999Seric 	ADDRESS **sendq;
71955012Seric 	register ENVELOPE *e;
720292Seric {
7214078Seric 	char buf[60];
7224536Seric 	extern bool safefile();
7234069Seric 
7247671Seric 	if (tTd(27, 1))
7254098Seric 		printf("forward(%s)\n", user->q_paddr);
7264098Seric 
7274594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
7284098Seric 		return;
7294314Seric 	if (user->q_home == NULL)
7304314Seric 		syserr("forward: no home");
7314069Seric 
7324069Seric 	/* good address -- look for .forward file in home */
73355012Seric 	define('z', user->q_home, e);
73455012Seric 	expand("\001z/.forward", buf, &buf[sizeof buf - 1], e);
73555012Seric 	include(buf, TRUE, user, sendq, e);
736292Seric }
737