xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 57381)
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
2056848Seric 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*57381Seric static char sccsid[] = "@(#)alias.c	6.2 (Berkeley) 01/01/93 (with NEWDB)";
3451756Seric #else
3556845Seric #ifdef NDBM
36*57381Seric static char sccsid[] = "@(#)alias.c	6.2 (Berkeley) 01/01/93 (with NDBM)";
3733728Sbostic #else
38*57381Seric static char sccsid[] = "@(#)alias.c	6.2 (Berkeley) 01/01/93 (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 {
169*57381Seric 	int i;
170*57381Seric 	char keybuf[MAXNAME + 1];
17156845Seric # if defined(NEWDB) || defined(NDBM)
17256845Seric 	DBdatum rhs, lhs;
17350575Seric 	int s;
174*57381Seric # else /* neither NEWDB nor NDBM */
175*57381Seric 	register STAB *s;
176*57381Seric # endif
1775701Seric 
1785701Seric 	/* create a key for fetch */
179*57381Seric 	i = strlen(name) + 1;
180*57381Seric 	if (i > sizeof keybuf)
181*57381Seric 		i = sizeof keybuf;
182*57381Seric 	bcopy(name, keybuf, i);
183*57381Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
184*57381Seric 		makelower(keybuf);
185*57381Seric 
186*57381Seric # if defined(NEWDB) || defined(NDBM)
187*57381Seric 	lhs.xx.size = i;
188*57381Seric 	lhs.xx.data = keybuf;
18950575Seric # ifdef NEWDB
19051756Seric 	if (AliasDBptr != NULL)
19151756Seric 	{
192*57381Seric 		i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
193*57381Seric 		if (i == 0)
19456845Seric 			return (rhs.dbt.data);
19551756Seric 	}
19656845Seric # ifdef NDBM
19757249Seric 	else if (AliasDBMptr != NULL)
19851756Seric 	{
19956845Seric 		rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
20056845Seric 		return (rhs.dbm.dptr);
20151756Seric 	}
20256845Seric # endif /* NDBM */
20356845Seric # else /* not NEWDB */
20456845Seric 	rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
20556845Seric 	return (rhs.dbm.dptr);
20656845Seric # endif /* NEWDB */
20756845Seric # else /* neither NEWDB nor NDBM */
2085701Seric 	register STAB *s;
2095701Seric 
210*57381Seric 	s = stab(keybuf, ST_ALIAS, ST_FIND);
21151756Seric 	if (s != NULL)
21251756Seric 		return (s->s_alias);
21351756Seric # endif
21451756Seric 	return (NULL);
2155701Seric }
2165701Seric /*
2174098Seric **  INITALIASES -- initialize for aliasing
2184098Seric **
21956845Seric **	Very different depending on whether we are running NDBM or not.
2204098Seric **
2214098Seric **	Parameters:
2224098Seric **		aliasfile -- location of aliases.
22356845Seric **		init -- if set and if NDBM, initialize the NDBM files.
2244098Seric **
2254098Seric **	Returns:
2264098Seric **		none.
2274098Seric **
2284098Seric **	Side Effects:
2294098Seric **		initializes aliases:
23056845Seric **		if NDBM:  opens the database.
23156845Seric **		if ~NDBM: reads the aliases into the symbol table.
2324098Seric */
2334098Seric 
23440559Sbostic # define DBMMODE	0644
2354157Seric 
23655012Seric initaliases(aliasfile, init, e)
2374098Seric 	char *aliasfile;
2384157Seric 	bool init;
23955012Seric 	register ENVELOPE *e;
2404098Seric {
24156845Seric #if defined(NDBM) || defined(NEWDB)
2428437Seric 	int atcnt;
24325522Seric 	time_t modtime;
24425522Seric 	bool automatic = FALSE;
2454322Seric 	char buf[MAXNAME];
24650575Seric #endif
2479368Seric 	struct stat stb;
24827176Seric 	static bool initialized = FALSE;
24946928Sbostic 	static int readaliases();
2504322Seric 
25127176Seric 	if (initialized)
25227176Seric 		return;
25327176Seric 	initialized = TRUE;
25427176Seric 
25517984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2568437Seric 	{
25725522Seric 		if (aliasfile != NULL && init)
25825522Seric 			syserr("Cannot open %s", aliasfile);
2598437Seric 		NoAlias = TRUE;
26011937Seric 		errno = 0;
2618437Seric 		return;
2628437Seric 	}
2638437Seric 
26456845Seric # if defined(NDBM) || defined(NEWDB)
2654322Seric 	/*
2668437Seric 	**  Check to see that the alias file is complete.
2678437Seric 	**	If not, we will assume that someone died, and it is up
2688437Seric 	**	to us to rebuild it.
2698437Seric 	*/
2708437Seric 
27125689Seric 	if (!init)
27250575Seric 	{
27350575Seric # ifdef NEWDB
27450575Seric 		(void) strcpy(buf, aliasfile);
27550575Seric 		(void) strcat(buf, ".db");
27651171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
27750576Seric 		if (AliasDBptr == NULL)
27850576Seric 		{
27956845Seric # ifdef NDBM
28056845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
28157249Seric 			if (AliasDBMptr == NULL)
28257249Seric 			{
28357249Seric 				syserr("initaliases: cannot open %s", buf);
28457249Seric 				NoAlias = TRUE;
28557249Seric 				return;
28657249Seric 			}
28751756Seric # else
28850576Seric 			syserr("initaliases: cannot open %s", buf);
28950576Seric 			NoAlias = TRUE;
29050576Seric 			return;
29151756Seric # endif
29250576Seric 		}
29350575Seric # else
29456845Seric 		AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
29557249Seric 		if (AliasDBMptr == NULL)
29657249Seric 		{
29757249Seric 			syserr("initaliases: cannot open %s", buf);
29857249Seric 			NoAlias = TRUE;
29957249Seric 			return;
30057249Seric 		}
30150575Seric # endif
30250575Seric 	}
30317471Seric 	atcnt = SafeAlias * 2;
30417471Seric 	if (atcnt > 0)
30517471Seric 	{
30617471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
30725689Seric 		{
30825689Seric 			/*
30925689Seric 			**  Reinitialize alias file in case the new
31025689Seric 			**  one is mv'ed in instead of cp'ed in.
31125689Seric 			**
31225689Seric 			**	Only works with new DBM -- old one will
31325689Seric 			**	just consume file descriptors forever.
31425689Seric 			**	If you have a dbmclose() it can be
31525689Seric 			**	added before the sleep(30).
31625689Seric 			*/
31725689Seric 
31850575Seric # ifdef NEWDB
31951756Seric 			if (AliasDBptr != NULL)
32051756Seric 				AliasDBptr->close(AliasDBptr);
32150575Seric # endif
32256845Seric # ifdef NDBM
32356845Seric 			if (AliasDBMptr != NULL)
32456845Seric 				dbm_close(AliasDBMptr);
32556845Seric # endif
32650575Seric 
32717471Seric 			sleep(30);
32850575Seric # ifdef NEWDB
32950575Seric 			(void) strcpy(buf, aliasfile);
33050575Seric 			(void) strcat(buf, ".db");
33151171Sbostic 			AliasDBptr =
33251171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
33350576Seric 			if (AliasDBptr == NULL)
33450576Seric 			{
33551756Seric # ifdef NDBM
33656845Seric 				AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
33751756Seric # else
33850576Seric 				syserr("initaliases: cannot open %s", buf);
33950576Seric 				NoAlias = TRUE;
34050576Seric 				return;
34151756Seric # endif
34250576Seric 			}
34350575Seric # else
34425689Seric # ifdef NDBM
34556845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
34657249Seric 			if (AliasDBMptr == NULL)
34757249Seric 			{
34857249Seric 				syserr("initaliases: cannot open %s", buf);
34957249Seric 				NoAlias = TRUE;
35057249Seric 				return;
35157249Seric 			}
35250575Seric # endif
35350575Seric # endif
35425689Seric 		}
35517471Seric 	}
35617471Seric 	else
35717471Seric 		atcnt = 1;
3588437Seric 
3598437Seric 	/*
36056845Seric 	**  See if the NDBM version of the file is out of date with
3614322Seric 	**  the text version.  If so, go into 'init' mode automatically.
36240559Sbostic 	**	This only happens if our effective userid owns the DBM.
36340559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
3644322Seric 	*/
3654322Seric 
3664322Seric 	modtime = stb.st_mtime;
3674322Seric 	(void) strcpy(buf, aliasfile);
36850575Seric # ifdef NEWDB
36950575Seric 	(void) strcat(buf, ".db");
37050575Seric # else
3714322Seric 	(void) strcat(buf, ".pag");
37250575Seric # endif
3734322Seric 	stb.st_ino = 0;
37419039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
3754322Seric 	{
37611937Seric 		errno = 0;
37740559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3784322Seric 		{
3794322Seric 			init = TRUE;
38025522Seric 			automatic = TRUE;
3817051Seric 			message(Arpa_Info, "rebuilding alias database");
38224944Seric #ifdef LOG
38324944Seric 			if (LogLevel >= 7)
38424944Seric 				syslog(LOG_INFO, "rebuilding alias database");
38556795Seric #endif /* LOG */
3864322Seric 		}
3874322Seric 		else
3884322Seric 		{
38919039Seric #ifdef LOG
39024944Seric 			if (LogLevel >= 7)
39124944Seric 				syslog(LOG_INFO, "alias database out of date");
39256795Seric #endif /* LOG */
3934322Seric 			message(Arpa_Info, "Warning: alias database out of date");
3944322Seric 		}
3954322Seric 	}
3964322Seric 
3974322Seric 
3984322Seric 	/*
39956845Seric 	**  If necessary, load the NDBM file.
40056845Seric 	**	If running without NDBM, load the symbol table.
4014322Seric 	*/
4024322Seric 
4034157Seric 	if (init)
4048437Seric 	{
40525522Seric #ifdef LOG
40625522Seric 		if (LogLevel >= 6)
40725522Seric 		{
40825522Seric 			extern char *username();
40925522Seric 
41025522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
41125522Seric 				automatic ? "auto" : "", username());
41225522Seric 		}
41356795Seric #endif /* LOG */
41455012Seric 		readaliases(aliasfile, TRUE, e);
4158437Seric 	}
41656845Seric # else /* NDBM */
41755012Seric 	readaliases(aliasfile, init, e);
41856845Seric # endif /* NDBM */
4194157Seric }
4204157Seric /*
4214157Seric **  READALIASES -- read and process the alias file.
4224157Seric **
4234157Seric **	This routine implements the part of initaliases that occurs
4244157Seric **	when we are not going to use the DBM stuff.
4254157Seric **
4264157Seric **	Parameters:
4274157Seric **		aliasfile -- the pathname of the alias file master.
42856845Seric **		init -- if set, initialize the NDBM stuff.
4294157Seric **
4304157Seric **	Returns:
4314157Seric **		none.
4324157Seric **
4334157Seric **	Side Effects:
4344157Seric **		Reads aliasfile into the symbol table.
4354157Seric **		Optionally, builds the .dir & .pag files.
4364157Seric */
4374157Seric 
4384157Seric static
43955012Seric readaliases(aliasfile, init, e)
4404157Seric 	char *aliasfile;
4414157Seric 	bool init;
44255012Seric 	register ENVELOPE *e;
4434157Seric {
4444098Seric 	register char *p;
4454098Seric 	char *rhs;
4464098Seric 	bool skipping;
4479368Seric 	int naliases, bytes, longest;
4489368Seric 	FILE *af;
44953742Seric 	bool makedbmfiles;
45040970Sbostic 	void (*oldsigint)();
4514098Seric 	ADDRESS al, bl;
4524106Seric 	register STAB *s;
45350575Seric # ifdef NEWDB
45450575Seric 	DB *dbp;
45550575Seric # endif
45656845Seric # ifdef NDBM
45756845Seric 	DBM *dbmp;
45856845Seric # endif
45951937Seric # ifdef LOCKF
46051937Seric 	struct flock fld;
46151937Seric # endif
4629368Seric 	char line[BUFSIZ];
4634098Seric 
46451937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
4651515Seric 	{
46657249Seric 		if (init)
46757249Seric 			syserr("Can't open %s", aliasfile);
46857249Seric 		else if (tTd(27, 1))
4694106Seric 			printf("Can't open %s\n", aliasfile);
4704098Seric 		errno = 0;
4714098Seric 		NoAlias++;
4724098Seric 		return;
4734098Seric 	}
4744314Seric 
47556845Seric # if defined(NDBM) || defined(NEWDB)
47619784Seric 	/* see if someone else is rebuilding the alias file already */
47751835Seric # ifdef LOCKF
47851937Seric 	fld.l_type = F_WRLCK;
47951937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
48051937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
48151835Seric # else
48219784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
48351835Seric # endif
48419784Seric 	{
48519784Seric 		/* yes, they are -- wait until done and then return */
48619784Seric 		message(Arpa_Info, "Alias file is already being rebuilt");
48719784Seric 		if (OpMode != MD_INITALIAS)
48819784Seric 		{
48919784Seric 			/* wait for other rebuild to complete */
49051835Seric # ifdef LOCKF
49151937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
49251835Seric # else
49319784Seric 			(void) flock(fileno(af), LOCK_EX);
49451835Seric # endif
49519784Seric 		}
49623108Seric 		(void) fclose(af);
49719784Seric 		errno = 0;
49819784Seric 		return;
49919784Seric 	}
50056845Seric # endif /* NDBM */
50119784Seric 
5024314Seric 	/*
50319784Seric 	**  If initializing, create the new DBM files.
50419784Seric 	*/
50519784Seric 
50619784Seric 	if (init)
50719784Seric 	{
50819784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
50951756Seric # ifdef NEWDB
51051756Seric 		(void) strcpy(line, aliasfile);
51151756Seric 		(void) strcat(line, ".db");
51251756Seric 		dbp = dbopen(line,
51351756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
51451756Seric 		if (dbp == NULL)
51551756Seric 		{
51651756Seric 			syserr("readaliases: cannot create %s", line);
51751756Seric 			(void) signal(SIGINT, oldsigint);
51851756Seric 			return;
51951756Seric 		}
52053742Seric # endif
52153742Seric # ifdef IF_MAKEDBMFILES
52253742Seric # ifdef NEWDB
52353742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
52453742Seric # endif
52553742Seric 		IF_MAKEDBMFILES
52619784Seric 		{
52756845Seric 			dbmp = dbm_open(aliasfile,
52856845Seric 					       O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
52956845Seric 			if (dbmp == NULL)
53053742Seric 			{
53156845Seric 				syserr("readaliases: cannot create %s.{dir,pag}",
53256845Seric 					aliasfile);
53353742Seric 				(void) signal(SIGINT, oldsigint);
53453742Seric 				return;
53553742Seric 			}
53619784Seric 		}
53750575Seric # endif
53819784Seric 	}
53919784Seric 
54019784Seric 	/*
5414314Seric 	**  Read and interpret lines
5424314Seric 	*/
5434314Seric 
5449368Seric 	FileName = aliasfile;
5459368Seric 	LineNumber = 0;
5464322Seric 	naliases = bytes = longest = 0;
5474098Seric 	skipping = FALSE;
5484098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5494098Seric 	{
5504322Seric 		int lhssize, rhssize;
5514322Seric 
5529368Seric 		LineNumber++;
55356795Seric 		p = strchr(line, '\n');
55425278Seric 		if (p != NULL)
55525278Seric 			*p = '\0';
5564098Seric 		switch (line[0])
5574098Seric 		{
5584098Seric 		  case '#':
5594098Seric 		  case '\0':
5604098Seric 			skipping = FALSE;
5614098Seric 			continue;
5624065Seric 
5634098Seric 		  case ' ':
5644098Seric 		  case '\t':
5654098Seric 			if (!skipping)
5669368Seric 				syserr("Non-continuation line starts with space");
5674098Seric 			skipping = TRUE;
5684097Seric 			continue;
5694098Seric 		}
5704098Seric 		skipping = FALSE;
5711874Seric 
5724314Seric 		/*
5734314Seric 		**  Process the LHS
5744314Seric 		**	Find the final colon, and parse the address.
57516898Seric 		**	It should resolve to a local name -- this will
57616898Seric 		**	be checked later (we want to optionally do
57716898Seric 		**	parsing of the RHS first to maximize error
57816898Seric 		**	detection).
5794314Seric 		*/
5804314Seric 
5814098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5824097Seric 			continue;
58316898Seric 		if (*p++ != ':')
5844098Seric 		{
5859368Seric 			syserr("missing colon");
5864097Seric 			continue;
5874098Seric 		}
58855012Seric 		if (parseaddr(line, &al, 1, ':', e) == NULL)
5894098Seric 		{
59016898Seric 			syserr("illegal alias name");
59116898Seric 			continue;
5924098Seric 		}
59316898Seric 		loweraddr(&al);
5944314Seric 
5954314Seric 		/*
5964314Seric 		**  Process the RHS.
5974314Seric 		**	'al' is the internal form of the LHS address.
5984314Seric 		**	'p' points to the text of the RHS.
5994314Seric 		*/
6004314Seric 
6014098Seric 		rhs = p;
6024098Seric 		for (;;)
6034098Seric 		{
6044098Seric 			register char c;
6051515Seric 
60625821Seric 			if (init && CheckAliases)
6074098Seric 			{
6084157Seric 				/* do parsing & compression of addresses */
60925278Seric 				while (*p != '\0')
6104098Seric 				{
61125278Seric 					extern char *DelimChar;
61225278Seric 
61325278Seric 					while (isspace(*p) || *p == ',')
6144157Seric 						p++;
61525278Seric 					if (*p == '\0')
61625278Seric 						break;
61755012Seric 					if (parseaddr(p, &bl, -1, ',', e) == NULL)
61825278Seric 						usrerr("%s... bad address", p);
61925278Seric 					p = DelimChar;
6204098Seric 				}
6214098Seric 			}
6224157Seric 			else
62315769Seric 			{
62416898Seric 				p = &p[strlen(p)];
62516898Seric 				if (p[-1] == '\n')
62616898Seric 					*--p = '\0';
62715769Seric 			}
6281515Seric 
6294098Seric 			/* see if there should be a continuation line */
6304106Seric 			c = fgetc(af);
6314106Seric 			if (!feof(af))
6324314Seric 				(void) ungetc(c, af);
6334106Seric 			if (c != ' ' && c != '\t')
6344098Seric 				break;
6354098Seric 
6364098Seric 			/* read continuation line */
6374098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6384098Seric 				break;
6399368Seric 			LineNumber++;
64057135Seric 
64157135Seric 			/* check for line overflow */
64257135Seric 			if (strchr(p, '\n') == NULL)
64357135Seric 			{
64457135Seric 				usrerr("alias too long");
64557135Seric 				break;
64657135Seric 			}
6474098Seric 		}
64816898Seric 		if (al.q_mailer != LocalMailer)
64916898Seric 		{
65016898Seric 			syserr("cannot alias non-local names");
65116898Seric 			continue;
65216898Seric 		}
6534314Seric 
6544314Seric 		/*
6554314Seric 		**  Insert alias into symbol table or DBM file
6564314Seric 		*/
6574314Seric 
65816898Seric 		lhssize = strlen(al.q_user) + 1;
659*57381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
660*57381Seric 			makelower(al.q_user);
6614322Seric 		rhssize = strlen(rhs) + 1;
6624322Seric 
66356845Seric # if defined(NDBM) || defined(NEWDB)
6644157Seric 		if (init)
6654157Seric 		{
66656845Seric 			DBdatum key, content;
667*57381Seric 			int putstat;
6684157Seric 
66956845Seric 			key.xx.size = lhssize;
67056845Seric 			key.xx.data = al.q_user;
67156845Seric 			content.xx.size = rhssize;
67256845Seric 			content.xx.data = rhs;
67351756Seric # ifdef NEWDB
674*57381Seric 			putstat = dbp->put(dbp, &key.dbt, &content.dbt,
675*57381Seric 					   R_NOOVERWRITE);
676*57381Seric 			if (putstat > 0)
677*57381Seric 			{
678*57381Seric 				usrerr("Warning: duplicate alias name %s",
679*57381Seric 					al.q_user);
680*57381Seric 				putstat = dbp->put(dbp, &key.dbt,
681*57381Seric 						   &content.dbt, 0);
682*57381Seric 			}
683*57381Seric 			if (putstat != 0)
68450576Seric 				syserr("readaliases: db put (%s)", al.q_user);
68550575Seric # endif
68653742Seric # ifdef IF_MAKEDBMFILES
68753742Seric 			IF_MAKEDBMFILES
688*57381Seric 			{
689*57381Seric 				putstat = dbm_store(dbmp, key.dbm, content.dbm,
690*57381Seric 						    DBM_INSERT);
691*57381Seric 				if (putstat > 0)
692*57381Seric 				{
693*57381Seric 					usrerr("Warning: duplicate alias name %s",
694*57381Seric 						al.q_user);
695*57381Seric 					putstat = dbm_store(dbmp, key.dbm,
696*57381Seric 							content.dbm, DBM_REPLACE);
697*57381Seric 				}
698*57381Seric 				if (putstat != 0)
69956845Seric 					syserr("readaliases: dbm store (%s)",
70056845Seric 						al.q_user);
701*57381Seric 			}
70253742Seric # endif
703*57381Seric 			if (al.q_paddr != NULL)
704*57381Seric 				free(al.q_paddr);
705*57381Seric 			if (al.q_host != NULL)
706*57381Seric 				free(al.q_host);
707*57381Seric 			if (al.q_user != NULL)
708*57381Seric 				free(al.q_user);
7094157Seric 		}
7104157Seric 		else
71156845Seric # endif /* NDBM */
7124157Seric 		{
7134157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
7144157Seric 			s->s_alias = newstr(rhs);
7154157Seric 		}
7164322Seric 
7174322Seric 		/* statistics */
7184322Seric 		naliases++;
7194322Seric 		bytes += lhssize + rhssize;
7204322Seric 		if (rhssize > longest)
7214322Seric 			longest = rhssize;
7221515Seric 	}
72319784Seric 
72456845Seric # if defined(NDBM) || defined(NEWDB)
72519784Seric 	if (init)
72619784Seric 	{
72719784Seric 		/* add the distinquished alias "@" */
72856845Seric 		DBdatum key;
72919784Seric 
73056845Seric 		key.xx.size = 2;
73156845Seric 		key.xx.data = "@";
73250575Seric # ifdef NEWDB
73350576Seric 		if (dbp->sync(dbp) != 0 ||
73456845Seric 		    dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
73550576Seric 		    dbp->close(dbp) != 0)
73650576Seric 			syserr("readaliases: db close failure");
73753742Seric # endif
73856789Seric # ifdef IF_MAKEDBMFILES
73956793Seric 		IF_MAKEDBMFILES
74056845Seric 		{
74156845Seric 			if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
74256845Seric 			    dbm_error(dbmp))
74356845Seric 				syserr("readaliases: dbm close failure");
74456845Seric 			dbm_close(dbmp);
74556845Seric 		}
74650575Seric # endif
74719784Seric 
74819784Seric 		/* restore the old signal */
74919784Seric 		(void) signal(SIGINT, oldsigint);
75019784Seric 	}
75156845Seric # endif /* NDBM */
75219784Seric 
75319784Seric 	/* closing the alias file drops the lock */
7544098Seric 	(void) fclose(af);
75555012Seric 	e->e_to = NULL;
7569368Seric 	FileName = NULL;
7577051Seric 	message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
7584322Seric 			naliases, longest, bytes);
75924944Seric # ifdef LOG
76024944Seric 	if (LogLevel >= 8)
76124944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
76224944Seric 			naliases, longest, bytes);
76356795Seric # endif /* LOG */
764292Seric }
765292Seric /*
766292Seric **  FORWARD -- Try to forward mail
767292Seric **
768292Seric **	This is similar but not identical to aliasing.
769292Seric **
770292Seric **	Parameters:
7714314Seric **		user -- the name of the user who's mail we would like
7724314Seric **			to forward to.  It must have been verified --
7734314Seric **			i.e., the q_home field must have been filled
7744314Seric **			in.
7754999Seric **		sendq -- a pointer to the head of the send queue to
7764999Seric **			put this user's aliases in.
777292Seric **
778292Seric **	Returns:
7794098Seric **		none.
780292Seric **
781292Seric **	Side Effects:
7823185Seric **		New names are added to send queues.
783292Seric */
784292Seric 
78555012Seric forward(user, sendq, e)
7862966Seric 	ADDRESS *user;
7874999Seric 	ADDRESS **sendq;
78855012Seric 	register ENVELOPE *e;
789292Seric {
79057136Seric 	char *pp;
79157136Seric 	char *ep;
7924536Seric 	extern bool safefile();
7934069Seric 
7947671Seric 	if (tTd(27, 1))
7954098Seric 		printf("forward(%s)\n", user->q_paddr);
7964098Seric 
7974594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
7984098Seric 		return;
7994314Seric 	if (user->q_home == NULL)
8004314Seric 		syserr("forward: no home");
8014069Seric 
8024069Seric 	/* good address -- look for .forward file in home */
80355012Seric 	define('z', user->q_home, e);
80457136Seric 	define('u', user->q_user, e);
80557136Seric 	define('h', user->q_host, e);
80657136Seric 	if (ForwardPath == NULL)
80757136Seric 		ForwardPath = newstr("\001z/.forward");
80857136Seric 
80957136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
81057136Seric 	{
81157232Seric 		char buf[MAXPATHLEN+1];
81257136Seric 
81357136Seric 		ep = strchr(pp, ':');
81457136Seric 		if (ep != NULL)
81557136Seric 			*ep = '\0';
81657136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
81757136Seric 		if (ep != NULL)
81857136Seric 			*ep++ = ':';
81957136Seric 		if (tTd(27, 3))
82057136Seric 			printf("forward: trying %s\n", buf);
82157136Seric 		if (include(buf, TRUE, user, sendq, e) == 0)
82257136Seric 			break;
82357136Seric 	}
824292Seric }
825