xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 59697)
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 
958332Seric # include "sendmail.h"
1050577Seric # include <signal.h>
1150577Seric # include <pwd.h>
1256845Seric # ifdef DBM
1356848Seric ERROR: DBM is no longer supported -- use NDBM instead.
1456845Seric # endif
1550577Seric # ifdef NEWDB
1650577Seric # include <db.h>
1750577Seric # endif
1856766Seric # ifdef NDBM
1956845Seric # include <ndbm.h>
2056766Seric # endif
2159673Seric # ifdef NIS
2259673Seric # include <rpcsvc/ypclnt.h>
2359673Seric # endif
2456766Seric 
2533728Sbostic #ifndef lint
2651756Seric #ifdef NEWDB
2757736Seric #ifdef NDBM
28*59697Seric static char sccsid[] = "@(#)alias.c	6.40 (Berkeley) 05/03/93 (with NEWDB and NDBM)";
2951756Seric #else
30*59697Seric static char sccsid[] = "@(#)alias.c	6.40 (Berkeley) 05/03/93 (with NEWDB)";
3157736Seric #endif
3257736Seric #else
3356845Seric #ifdef NDBM
34*59697Seric static char sccsid[] = "@(#)alias.c	6.40 (Berkeley) 05/03/93 (with NDBM)";
3533728Sbostic #else
36*59697Seric static char sccsid[] = "@(#)alias.c	6.40 (Berkeley) 05/03/93 (without NEWDB or NDBM)";
3733728Sbostic #endif
3850575Seric #endif
3933728Sbostic #endif /* not lint */
4051756Seric /*
4159673Seric **  Alias data structures
4259673Seric */
4359673Seric #define ALIASDB		struct _aliasdb
4459673Seric 
4559673Seric 
4659673Seric ALIASDB
4759673Seric {
4859673Seric 	ALIASCLASS	*ad_class;	/* class of this database */
4959673Seric 	char		*ad_name;	/* name of alias file */
5059673Seric 	char		*ad_domain;	/* name of (NIS) domain */
5159673Seric 	void		*ad_dbp;	/* ndbm/nis database pointer */
5259673Seric #ifdef NEWDB
5359673Seric 	DB		*ad_ndbp;	/* newdb database pointer */
5459673Seric #endif
5559673Seric 	short		ad_flags;	/* flag bits */
5659673Seric };
5759673Seric 
5859673Seric /* bits for ad_flags */
5959673Seric #define ADF_VALID	0x0001		/* database initialized */
6059673Seric #define ADF_WRITABLE	0x0002		/* open for write */
6159673Seric #define ADF_IMPLHASH	0x0004		/* IMPL: underlying hash database */
6259673Seric #define ADF_IMPLNDBM	0x0008		/* IMPL: underlying NDBM database */
6359673Seric 
6459673Seric 
6559673Seric ALIASCLASS
6659673Seric {
6759673Seric 	char	*ac_name;		/* name of alias class */
6859673Seric 	char	*(*ac_lookup)__P((ALIASDB *, char *, ENVELOPE *));
6959673Seric 					/* lookup func */
7059673Seric 	void	(*ac_store)__P((ALIASDB *, char *, char *, ENVELOPE *));
7159673Seric 					/* database store func */
7259673Seric 	bool	(*ac_init)__P((ALIASDB *, ENVELOPE *));
7359673Seric 					/* initialization func */
7459673Seric 	void	(*ac_rebuild)__P((ALIASDB *, FILE *, ENVELOPE *));
7559673Seric 					/* initialization func */
7659673Seric 	void	(*ac_close)__P((ALIASDB *, ENVELOPE *));
7759673Seric 					/* close function */
7859673Seric 	short	ac_flags;		/* flag bits */
7959673Seric };
8059673Seric 
8159673Seric /* bits for ac_flags */
8259673Seric #define ACF_BUILDABLE	0x0001		/* can build a cached version */
8359673Seric 
8459673Seric 
8559673Seric ALIASDB	AliasDB[MAXALIASDB + 1];	/* actual database list */
8659673Seric int	NAliasDBs;			/* number of alias databases */
8759673Seric /*
88292Seric **  ALIAS -- Compute aliases.
89292Seric **
909368Seric **	Scans the alias file for an alias for the given address.
919368Seric **	If found, it arranges to deliver to the alias list instead.
929368Seric **	Uses libdbm database if -DDBM.
93292Seric **
94292Seric **	Parameters:
954097Seric **		a -- address to alias.
964999Seric **		sendq -- a pointer to the head of the send queue
974999Seric **			to put the aliases in.
9858092Seric **		e -- the current envelope.
99292Seric **
100292Seric **	Returns:
101292Seric **		none
102292Seric **
103292Seric **	Side Effects:
1043185Seric **		Aliases found are expanded.
105292Seric **
106292Seric **	Deficiencies:
107292Seric **		It should complain about names that are aliased to
108292Seric **			nothing.
109292Seric */
110292Seric 
11155012Seric alias(a, sendq, e)
1124097Seric 	register ADDRESS *a;
1134999Seric 	ADDRESS **sendq;
11455012Seric 	register ENVELOPE *e;
115292Seric {
1164081Seric 	register char *p;
11758082Seric 	int naliases;
11858170Seric 	char *owner;
11958170Seric 	char obuf[MAXNAME + 6];
1205701Seric 	extern char *aliaslookup();
121292Seric 
1227671Seric 	if (tTd(27, 1))
1234098Seric 		printf("alias(%s)\n", a->q_paddr);
124292Seric 
1254098Seric 	/* don't realias already aliased names */
12658680Seric 	if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
1274098Seric 		return;
1284098Seric 
12959673Seric 	if (NoAlias)
13059673Seric 		return;
13159673Seric 
13255012Seric 	e->e_to = a->q_paddr;
1334098Seric 
1344314Seric 	/*
1354314Seric 	**  Look up this name
1364314Seric 	*/
1374314Seric 
13859673Seric 	p = aliaslookup(a->q_user, e);
1394098Seric 	if (p == NULL)
1404098Seric 		return;
141292Seric 
142292Seric 	/*
1434098Seric 	**  Match on Alias.
1444098Seric 	**	Deliver to the target list.
1451515Seric 	*/
1461515Seric 
1477671Seric 	if (tTd(27, 1))
1484098Seric 		printf("%s (%s, %s) aliased to %s\n",
1494098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
15058092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
15158154Seric 	{
15258154Seric 		a->q_flags |= QVERIFIED;
15358884Seric 		e->e_nrcpts++;
15458092Seric 		return;
15558154Seric 	}
15658154Seric 	message("aliased to %s", p);
15757977Seric #ifdef LOG
15858020Seric 	if (LogLevel > 9)
15957977Seric 		syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
16057977Seric #endif
16158082Seric 	a->q_flags &= ~QSELFREF;
1624098Seric 	AliasLevel++;
16358082Seric 	naliases = sendtolist(p, a, sendq, e);
1644098Seric 	AliasLevel--;
16558082Seric 	if (naliases > 0 && !bitset(QSELFREF, a->q_flags))
16658065Seric 	{
16758065Seric 		if (tTd(27, 5))
16858065Seric 		{
16958065Seric 			printf("alias: QDONTSEND ");
17058065Seric 			printaddr(a, FALSE);
17158065Seric 		}
17258065Seric 		a->q_flags |= QDONTSEND;
17358065Seric 	}
17458170Seric 
17558170Seric 	/*
17658170Seric 	**  Look for owner of alias
17758170Seric 	*/
17858170Seric 
17958170Seric 	(void) strcpy(obuf, "owner-");
18058170Seric 	if (strncmp(a->q_user, "owner-", 6) == 0)
18158170Seric 		(void) strcat(obuf, "owner");
18258170Seric 	else
18358170Seric 		(void) strcat(obuf, a->q_user);
18458170Seric 	if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
18558170Seric 		makelower(obuf);
18659673Seric 	owner = aliaslookup(obuf, e);
18758170Seric 	if (owner != NULL)
18858170Seric 	{
18958170Seric 		if (strchr(owner, ',') != NULL)
19058170Seric 			owner = obuf;
19158170Seric 		a->q_owner = newstr(owner);
19258170Seric 	}
1934098Seric }
1944098Seric /*
1955701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1965701Seric **
1975701Seric **	Parameters:
1985701Seric **		name -- the name to look up.
1995701Seric **
2005701Seric **	Returns:
2015701Seric **		the value of name.
2025701Seric **		NULL if unknown.
2035701Seric **
2045701Seric **	Side Effects:
2055701Seric **		none.
2065701Seric **
2075701Seric **	Warnings:
2085701Seric **		The return value will be trashed across calls.
2095701Seric */
2105701Seric 
2115701Seric char *
21259673Seric aliaslookup(name, e)
2135701Seric 	char *name;
21459673Seric 	ENVELOPE *e;
2155701Seric {
21659673Seric 	register int dbno;
21759673Seric 	register ALIASDB *ad;
21859673Seric 	register char *p;
2195701Seric 
22059673Seric 	for (dbno = 0; dbno < NAliasDBs; dbno++)
22159673Seric 	{
22259673Seric 		ad = &AliasDB[dbno];
22359673Seric 		if (!bitset(ADF_VALID, ad->ad_flags))
22459673Seric 			continue;
22559673Seric 		p = (*ad->ad_class->ac_lookup)(ad, name, e);
22659673Seric 		if (p != NULL)
22759673Seric 			return p;
22859673Seric 	}
22959673Seric 	return NULL;
23059673Seric }
23159673Seric /*
23259673Seric **  SETALIAS -- set up an alias map
23359673Seric **
23459673Seric **	Called when reading configuration file.
23559673Seric **
23659673Seric **	Parameters:
23759673Seric **		spec -- the alias specification
23859673Seric **
23959673Seric **	Returns:
24059673Seric **		none.
24159673Seric */
24257381Seric 
24359673Seric setalias(spec)
24459673Seric 	char *spec;
24559673Seric {
24659673Seric 	register char *p;
24759673Seric 	register ALIASDB *ad;
24859673Seric 	char *class;
24959673Seric 	STAB *s;
25059673Seric 
251*59697Seric 	if (tTd(27, 8))
252*59697Seric 		printf("setalias(%s)\n", spec);
253*59697Seric 
25459673Seric 	if (NAliasDBs >= MAXALIASDB)
25551756Seric 	{
25659673Seric 		syserr("Too many alias databases defined, %d max", MAXALIASDB);
25759673Seric 		return;
25851756Seric 	}
25959673Seric 	ad = &AliasDB[NAliasDBs];
26059673Seric 
26159673Seric 	for (p = spec; *p != '\0'; p++)
26251756Seric 	{
26359673Seric 		if (strchr(" /:", *p) != NULL)
26459673Seric 			break;
26551756Seric 	}
26659673Seric 
26759673Seric 	if (*p == ':')
26859673Seric 	{
26959673Seric 		/* explicit class listed */
27059673Seric 		*p++ = '\0';
27159673Seric 		class = spec;
27259673Seric 		spec = p;
27359673Seric 	}
27459673Seric 	else
27559673Seric 	{
27659673Seric 		/* implicit class */
27759673Seric 		class = "implicit";
27859673Seric 	}
27959673Seric 
28059673Seric 	/* look up class */
28159673Seric 	s = stab(class, ST_ALIASCLASS, ST_FIND);
28259673Seric 	if (s == NULL)
28359673Seric 		syserr("Unknown alias class %s", class);
28459673Seric 	else
28559673Seric 	{
28659673Seric 		ad->ad_class = s->s_aliasclass;
28759673Seric 		ad->ad_name = newstr(spec);
28859673Seric 		NAliasDBs++;
28959673Seric 	}
2905701Seric }
2915701Seric /*
2924098Seric **  INITALIASES -- initialize for aliasing
2934098Seric **
29456845Seric **	Very different depending on whether we are running NDBM or not.
2954098Seric **
2964098Seric **	Parameters:
29759673Seric **		rebuild -- if TRUE, this rebuilds the cached versions.
29859673Seric **		e -- current envelope.
2994098Seric **
3004098Seric **	Returns:
3014098Seric **		none.
3024098Seric **
3034098Seric **	Side Effects:
3044098Seric **		initializes aliases:
30556845Seric **		if NDBM:  opens the database.
30656845Seric **		if ~NDBM: reads the aliases into the symbol table.
3074098Seric */
3084098Seric 
30940559Sbostic # define DBMMODE	0644
3104157Seric 
31159673Seric initaliases(rebuild, e)
31259673Seric 	bool rebuild;
31355012Seric 	register ENVELOPE *e;
3144098Seric {
31559673Seric 	int dbno;
31659673Seric 	register ALIASDB *ad;
3174322Seric 
31859673Seric 	for (dbno = 0; dbno < NAliasDBs; dbno++)
3198437Seric 	{
32059673Seric 		ad = &AliasDB[dbno];
321*59697Seric 
322*59697Seric 		if (tTd(27, 2))
323*59697Seric 			printf("initaliases(%s:%s)\n",
324*59697Seric 				ad->ad_class->ac_name, ad->ad_name);
325*59697Seric 
32659673Seric 		if (rebuild)
32750576Seric 		{
32859673Seric 			rebuildaliases(ad, FALSE, e);
32950576Seric 		}
33059673Seric 		else
33157249Seric 		{
332*59697Seric 			if (ad->ad_class->ac_init(ad, e))
333*59697Seric 				ad->ad_flags |= ADF_VALID;
33457249Seric 		}
33550575Seric 	}
33659673Seric }
33759673Seric /*
33859673Seric **  ALIASWAIT -- wait for distinguished @:@ token to appear.
33959673Seric **
34059673Seric **	This can decide to reopen or rebuild the alias file
34159673Seric */
34259673Seric 
34359673Seric aliaswait(ad, ext, e)
34459673Seric 	ALIASDB *ad;
34559673Seric 	char *ext;
34659673Seric 	ENVELOPE *e;
34759673Seric {
34859673Seric 	int atcnt;
34959673Seric 	time_t mtime;
35059673Seric 	struct stat stb;
35159673Seric 	char buf[MAXNAME];
35259673Seric 
353*59697Seric 	if (tTd(27, 3))
354*59697Seric 		printf("aliaswait\n");
355*59697Seric 
35617471Seric 	atcnt = SafeAlias * 2;
35717471Seric 	if (atcnt > 0)
35817471Seric 	{
35959673Seric 		while (atcnt-- >= 0 &&
36059673Seric 		       ad->ad_class->ac_lookup(ad, "@", e) == NULL)
36125689Seric 		{
36225689Seric 			/*
36359673Seric 			**  Close and re-open the alias database in case
36459673Seric 			**  the one is mv'ed instead of cp'ed in.
36525689Seric 			*/
36625689Seric 
367*59697Seric 			if (tTd(27, 2))
368*59697Seric 				printf("aliaswait: sleeping\n");
369*59697Seric 
37059673Seric 			ad->ad_class->ac_close(ad, e);
37117471Seric 			sleep(30);
37259673Seric 			ad->ad_class->ac_init(ad, e);
37325689Seric 		}
37417471Seric 	}
3758437Seric 
37659673Seric 	/* see if we need to go into auto-rebuild mode */
37759673Seric 	if (stat(ad->ad_name, &stb) < 0)
37859673Seric 		return;
37959673Seric 	mtime = stb.st_mtime;
38059673Seric 	(void) strcpy(buf, ad->ad_name);
38159673Seric 	(void) strcat(buf, ext);
38259673Seric 	if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0)
3834322Seric 	{
38459673Seric 		/* database is out of date */
38540559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3864322Seric 		{
38759673Seric 			message("auto-rebuilding alias database %s",
38859673Seric 				ad->ad_name);
38959673Seric 			rebuildaliases(ad, TRUE, e);
3904322Seric 		}
3914322Seric 		else
3924322Seric 		{
39319039Seric #ifdef LOG
39458020Seric 			if (LogLevel > 3)
39559673Seric 				syslog(LOG_INFO, "alias database %s out of date",
39659673Seric 					ad->ad_name);
39756795Seric #endif /* LOG */
39859673Seric 			message("Warning: alias database %s out of date",
39959673Seric 				ad->ad_name);
4004322Seric 		}
4014322Seric 	}
40259673Seric }
40359673Seric /*
40459673Seric **  REBUILDALIASES -- rebuild the alias database.
40559673Seric **
40659673Seric **	Parameters:
40759673Seric **		ad -- the database to rebuild.
40859673Seric **		automatic -- set if this was automatically generated.
40959673Seric **		e -- current envelope.
41059673Seric **
41159673Seric **	Returns:
41259673Seric **		none.
41359673Seric **
41459673Seric **	Side Effects:
41559673Seric **		Reads the text version of the database, builds the
41659673Seric **		DBM or DB version.
41759673Seric */
4184322Seric 
41959673Seric rebuildaliases(ad, automatic, e)
42059673Seric 	register ALIASDB *ad;
42159673Seric 	bool automatic;
42259673Seric 	register ENVELOPE *e;
42359673Seric {
42459673Seric 	FILE *af;
42559673Seric 	void (*oldsigint)();
4264322Seric 
42759673Seric 	if (!bitset(ACF_BUILDABLE, ad->ad_class->ac_flags))
42859673Seric 		return;
4294322Seric 
43059673Seric #ifdef LOG
43159673Seric 	if (LogLevel > 7)
4328437Seric 	{
43359673Seric 		extern char *username();
43425522Seric 
43559673Seric 		syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
43659673Seric 			ad->ad_name, automatic ? "auto" : "", username());
43759673Seric 	}
43856795Seric #endif /* LOG */
43959673Seric 
44059673Seric 	/* try to lock the source file */
44159673Seric 	if ((af = fopen(ad->ad_name, "r+")) == NULL)
44259673Seric 	{
44359673Seric 		syserr("554 Can't open %s", ad->ad_name);
44459673Seric 		printf("Can't open %s\n", ad->ad_name);
44559673Seric 		errno = 0;
44659673Seric 		return;
4478437Seric 	}
44859673Seric 
44959673Seric 	/* see if someone else is rebuilding the alias file */
45059673Seric 	if (!lockfile(fileno(af), ad->ad_name, LOCK_EX|LOCK_NB))
45159673Seric 	{
45259673Seric 		/* yes, they are -- wait until done */
45359673Seric 		message("Alias file %s is already being rebuilt",
45459673Seric 			ad->ad_name);
45559673Seric 		if (OpMode != MD_INITALIAS)
45659673Seric 		{
45759673Seric 			/* wait for other rebuild to complete */
45859673Seric 			(void) lockfile(fileno(af), ad->ad_name,
45959673Seric 					LOCK_EX);
46059673Seric 		}
46159673Seric 		(void) fclose(af);
46259673Seric 		errno = 0;
46359673Seric 		return;
46459673Seric 	}
46559673Seric 
46659673Seric 	oldsigint = signal(SIGINT, SIG_IGN);
46759673Seric 
46859673Seric 	ad->ad_class->ac_rebuild(ad, af, e);
46959673Seric 
47059673Seric 	/* close the file, thus releasing locks */
47159673Seric 	fclose(af);
47259673Seric 
47359673Seric 	/* add distinguished entries and close the database */
47459673Seric 	ad->ad_class->ac_close(ad, e);
47559673Seric 
47659673Seric 	/* restore the old signal */
47759673Seric 	(void) signal(SIGINT, oldsigint);
4784157Seric }
4794157Seric /*
4804157Seric **  READALIASES -- read and process the alias file.
4814157Seric **
4824157Seric **	This routine implements the part of initaliases that occurs
4834157Seric **	when we are not going to use the DBM stuff.
4844157Seric **
4854157Seric **	Parameters:
48659673Seric **		ad -- the alias database descriptor.
48759673Seric **		af -- file to read the aliases from.
48859673Seric **		e -- the current alias file.
4894157Seric **
4904157Seric **	Returns:
4914157Seric **		none.
4924157Seric **
4934157Seric **	Side Effects:
4944157Seric **		Reads aliasfile into the symbol table.
4954157Seric **		Optionally, builds the .dir & .pag files.
4964157Seric */
4974157Seric 
4984157Seric static
49959673Seric readaliases(ad, af, e)
50059673Seric 	register ALIASDB *ad;
50159673Seric 	FILE *af;
50255012Seric 	register ENVELOPE *e;
5034157Seric {
5044098Seric 	register char *p;
5054098Seric 	char *rhs;
5064098Seric 	bool skipping;
50759673Seric 	long naliases, bytes, longest;
5084098Seric 	ADDRESS al, bl;
5094106Seric 	register STAB *s;
5109368Seric 	char line[BUFSIZ];
5114098Seric 
5124314Seric 	/*
5134314Seric 	**  Read and interpret lines
5144314Seric 	*/
5154314Seric 
51659673Seric 	FileName = ad->ad_name;
5179368Seric 	LineNumber = 0;
5184322Seric 	naliases = bytes = longest = 0;
5194098Seric 	skipping = FALSE;
5204098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5214098Seric 	{
5224322Seric 		int lhssize, rhssize;
5234322Seric 
5249368Seric 		LineNumber++;
52556795Seric 		p = strchr(line, '\n');
52625278Seric 		if (p != NULL)
52725278Seric 			*p = '\0';
5284098Seric 		switch (line[0])
5294098Seric 		{
5304098Seric 		  case '#':
5314098Seric 		  case '\0':
5324098Seric 			skipping = FALSE;
5334098Seric 			continue;
5344065Seric 
5354098Seric 		  case ' ':
5364098Seric 		  case '\t':
5374098Seric 			if (!skipping)
53858151Seric 				syserr("554 Non-continuation line starts with space");
5394098Seric 			skipping = TRUE;
5404097Seric 			continue;
5414098Seric 		}
5424098Seric 		skipping = FALSE;
5431874Seric 
5444314Seric 		/*
5454314Seric 		**  Process the LHS
54657736Seric 		**	Find the colon separator, and parse the address.
54716898Seric 		**	It should resolve to a local name -- this will
54816898Seric 		**	be checked later (we want to optionally do
54916898Seric 		**	parsing of the RHS first to maximize error
55016898Seric 		**	detection).
5514314Seric 		*/
5524314Seric 
5534098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5544097Seric 			continue;
55516898Seric 		if (*p++ != ':')
5564098Seric 		{
55758151Seric 			syserr("554 missing colon");
5584097Seric 			continue;
5594098Seric 		}
56058333Seric 		if (parseaddr(line, &al, 1, ':', NULL, e) == NULL)
5614098Seric 		{
56258151Seric 			syserr("554 illegal alias name");
56316898Seric 			continue;
5644098Seric 		}
5654314Seric 
5664314Seric 		/*
5674314Seric 		**  Process the RHS.
5684314Seric 		**	'al' is the internal form of the LHS address.
5694314Seric 		**	'p' points to the text of the RHS.
5704314Seric 		*/
5714314Seric 
57258914Seric 		while (isascii(*p) && isspace(*p))
57358914Seric 			p++;
5744098Seric 		rhs = p;
5754098Seric 		for (;;)
5764098Seric 		{
5774098Seric 			register char c;
57858662Seric 			register char *nlp;
5791515Seric 
58058662Seric 			nlp = &p[strlen(p)];
58158662Seric 			if (nlp[-1] == '\n')
58258662Seric 				*--nlp = '\0';
58358662Seric 
58459673Seric 			if (CheckAliases)
5854098Seric 			{
5864157Seric 				/* do parsing & compression of addresses */
58725278Seric 				while (*p != '\0')
5884098Seric 				{
58958333Seric 					auto char *delimptr;
59025278Seric 
59158050Seric 					while ((isascii(*p) && isspace(*p)) ||
59258050Seric 								*p == ',')
5934157Seric 						p++;
59425278Seric 					if (*p == '\0')
59525278Seric 						break;
59658333Seric 					if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL)
59758151Seric 						usrerr("553 %s... bad address", p);
59858333Seric 					p = delimptr;
5994098Seric 				}
6004098Seric 			}
6014157Seric 			else
60215769Seric 			{
60358662Seric 				p = nlp;
60415769Seric 			}
6051515Seric 
6064098Seric 			/* see if there should be a continuation line */
6074106Seric 			c = fgetc(af);
6084106Seric 			if (!feof(af))
6094314Seric 				(void) ungetc(c, af);
6104106Seric 			if (c != ' ' && c != '\t')
6114098Seric 				break;
6124098Seric 
6134098Seric 			/* read continuation line */
6144098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6154098Seric 				break;
6169368Seric 			LineNumber++;
61757135Seric 
61857135Seric 			/* check for line overflow */
61957135Seric 			if (strchr(p, '\n') == NULL)
62057135Seric 			{
62158151Seric 				usrerr("554 alias too long");
62257135Seric 				break;
62357135Seric 			}
6244098Seric 		}
62516898Seric 		if (al.q_mailer != LocalMailer)
62616898Seric 		{
62758151Seric 			syserr("554 cannot alias non-local names");
62816898Seric 			continue;
62916898Seric 		}
6304314Seric 
6314314Seric 		/*
6324314Seric 		**  Insert alias into symbol table or DBM file
6334314Seric 		*/
6344314Seric 
63557381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
63657381Seric 			makelower(al.q_user);
6374322Seric 
63859673Seric 		lhssize = strlen(al.q_user);
63959673Seric 		rhssize = strlen(rhs);
64059673Seric 		ad->ad_class->ac_store(ad, al.q_user, rhs, e);
6414157Seric 
64259673Seric 		if (al.q_paddr != NULL)
64359673Seric 			free(al.q_paddr);
64459673Seric 		if (al.q_host != NULL)
64559673Seric 			free(al.q_host);
64659673Seric 		if (al.q_user != NULL)
64759673Seric 			free(al.q_user);
6484322Seric 
6494322Seric 		/* statistics */
6504322Seric 		naliases++;
6514322Seric 		bytes += lhssize + rhssize;
6524322Seric 		if (rhssize > longest)
6534322Seric 			longest = rhssize;
6541515Seric 	}
65519784Seric 
65659673Seric 	e->e_to = NULL;
65759673Seric 	FileName = NULL;
65859673Seric 	message("%s: %d aliases, longest %d bytes, %d bytes total",
65959673Seric 			ad->ad_name, naliases, longest, bytes);
66059673Seric # ifdef LOG
66159673Seric 	if (LogLevel > 7)
66259673Seric 		syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
66359673Seric 			ad->ad_name, naliases, longest, bytes);
66459673Seric # endif /* LOG */
66559673Seric }
66659673Seric /*
66759673Seric **  NDBM modules
66859673Seric */
66959673Seric 
67059673Seric #ifdef NDBM
67159673Seric 
67259673Seric /*
67359673Seric **  NDBM_ALOOKUP -- look up alias in ndbm file
67459673Seric */
67559673Seric 
67659673Seric char *
67759673Seric ndbm_alookup(ad, name, e)
67859673Seric 	register ALIASDB *ad;
67959673Seric 	char *name;
68059673Seric 	ENVELOPE *e;
68159673Seric {
68259673Seric 	int i;
68359673Seric 	datum rhs, lhs;
68459673Seric 	char keybuf[MAXNAME + 1];
68559673Seric 
686*59697Seric 	if (tTd(27, 20))
687*59697Seric 		printf("ndbm_lookup(%s)\n", name);
688*59697Seric 
68959673Seric 	/* create a key for fetch */
69059673Seric 	i = strlen(name) + 1;
69159673Seric 	if (i > sizeof keybuf)
69259673Seric 		i = sizeof keybuf;
69359673Seric 	bcopy(name, keybuf, i);
69459673Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
69559673Seric 		makelower(keybuf);
69659673Seric 
69759673Seric 	lhs.dsize = i;
69859673Seric 	lhs.dptr = keybuf;
69959673Seric 	rhs = dbm_fetch((DBM *) ad->ad_dbp, lhs);
70059673Seric 	return (rhs.dptr);
70159673Seric }
70259673Seric 
70359673Seric 
70459673Seric /*
70559673Seric **  NDBM_ASTORE -- store a datum in the database
70659673Seric */
70759673Seric 
70859673Seric void
70959673Seric ndbm_astore(ad, lhs, rhs, e)
71059673Seric 	register ALIASDB *ad;
71159673Seric 	char *lhs;
71259673Seric 	char *rhs;
71359673Seric 	ENVELOPE *e;
71459673Seric {
71559673Seric 	datum key;
71659673Seric 	datum data;
71759673Seric 	int stat;
71859673Seric 
719*59697Seric 	key.dsize = strlen(lhs) + 1;
72059673Seric 	key.dptr = lhs;
72159673Seric 
722*59697Seric 	data.dsize = strlen(rhs) + 1;
72359673Seric 	data.dptr = rhs;
72459673Seric 
72559673Seric 	stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_INSERT);
72659673Seric 	if (stat > 0)
72719784Seric 	{
72859673Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
72959673Seric 		stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_REPLACE);
73059673Seric 	}
73159673Seric 	if (stat != 0)
73259673Seric 		syserr("readaliases: dbm put (%s)", lhs);
73359673Seric }
73419784Seric 
73559673Seric 
73659673Seric /*
73759673Seric **  NDBM_AINIT -- initialize DBM database
73859673Seric */
73959673Seric 
74059673Seric bool
74159673Seric ndbm_ainit(ad, e)
74259673Seric 	register ALIASDB *ad;
74359673Seric 	ENVELOPE *e;
74459673Seric {
74559673Seric 	char buf[MAXNAME];
74659673Seric 
747*59697Seric 	if (tTd(27, 2))
748*59697Seric 		printf("ndbm_ainit(%s)\n", ad->ad_name);
749*59697Seric 
75059673Seric 	/* open the database */
75159673Seric 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDONLY, DBMMODE);
75259673Seric 	if (ad->ad_dbp == NULL)
75359673Seric 		return FALSE;
75459673Seric 
75559673Seric 	/* wait for @:@ to appear */
75659673Seric 	aliaswait(ad, ".pag", e);
75759673Seric 
75859673Seric 	return TRUE;
75959673Seric }
76059673Seric 
76159673Seric 
76259673Seric /*
76359673Seric **  NDBM_AREBUILD -- rebuild hash database
76459673Seric */
76559673Seric 
76659673Seric void
76759673Seric ndbm_arebuild(ad, fp, e)
76859673Seric 	register ALIASDB *ad;
76959673Seric 	FILE *fp;
77059673Seric 	ENVELOPE *e;
77159673Seric {
77259673Seric 	register DBM *db;
77359673Seric 	int i;
77459673Seric 	char buf[MAXNAME];
77559673Seric 
776*59697Seric 	if (tTd(27, 2))
777*59697Seric 		printf("ndbm_arebuild(%s)\n", ad->ad_name);
778*59697Seric 
77959673Seric 	db = dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
78059673Seric 	if (db == NULL)
78159673Seric 	{
78259673Seric 		syserr("readaliases: cannot create %s", buf);
78359673Seric 		return;
78459673Seric 	}
78559673Seric 	ad->ad_dbp = (void *) db;
786*59697Seric 	ad->ad_flags |= ADF_WRITABLE;
78759673Seric 
78859673Seric 	/* read and store the aliases */
78959673Seric 	readaliases(ad, fp, e);
79059673Seric }
79159673Seric 
79259673Seric /*
79359673Seric **  NDBM_ACLOSE -- close the database
79459673Seric */
79559673Seric 
79659673Seric void
79759673Seric ndbm_aclose(ad, e)
79859673Seric 	register ALIASDB  *ad;
79959673Seric 	ENVELOPE *e;
80059673Seric {
80159673Seric 	if (bitset(ADF_WRITABLE, ad->ad_flags))
80259673Seric 	{
80358059Seric #ifdef YPCOMPAT
80459673Seric 		char buf[200];
80558846Seric 
80659673Seric 		(void) sprintf(buf, "%010ld", curtime());
80759673Seric 		ndbm_astore(ad, "YP_LAST_MODIFIED", buf, e);
80859673Seric 
80959673Seric 		(void) myhostname(buf, sizeof buf);
81059673Seric 		ndbm_astore(ad, "YP_MASTER_NAME", buf, e);
81158059Seric #endif
81219784Seric 
81359673Seric 		/* write out the distinguished alias */
81459673Seric 		ndbm_astore(ad, "@", "@", e);
81519784Seric 	}
81659673Seric 	dbm_close((DBM *) ad->ad_dbp);
81759673Seric }
81819784Seric 
81959673Seric #endif
82059673Seric /*
82159673Seric **  HASH (NEWDB) Modules
82259673Seric */
82359673Seric 
82459673Seric #ifdef NEWDB
82559673Seric 
82659673Seric /*
82759673Seric **  HASH_ALOOKUP -- look up alias in hash file
82859673Seric */
82959673Seric 
83059673Seric char *
83159673Seric hash_alookup(ad, name, e)
83259673Seric 	register ALIASDB *ad;
83359673Seric 	char *name;
83459673Seric 	ENVELOPE *e;
83559673Seric {
83659673Seric 	int i;
83759673Seric 	DBT rhs, lhs;
83859673Seric 	int s;
83959673Seric 	char keybuf[MAXNAME + 1];
84059673Seric 
841*59697Seric 	if (tTd(27, 20))
842*59697Seric 		printf("hash_alookup(%s)\n", name);
843*59697Seric 
84459673Seric 	/* create a key for fetch */
84559673Seric 	i = strlen(name) + 1;
84659673Seric 	if (i > sizeof keybuf)
84759673Seric 		i = sizeof keybuf;
84859673Seric 	bcopy(name, keybuf, i);
84959673Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
85059673Seric 		makelower(keybuf);
85159673Seric 
85259673Seric 	lhs.size = i;
85359673Seric 	lhs.data = keybuf;
85459673Seric 	i = ad->ad_ndbp->get(ad->ad_ndbp, &lhs, &rhs, 0);
85559673Seric 	if (i == 0)
85659673Seric 		return (rhs.data);
85759673Seric 	return (NULL);
858292Seric }
85959673Seric 
86059673Seric 
86159673Seric /*
86259673Seric **  HASH_ASTORE -- store a datum in the database
86359673Seric */
86459673Seric 
86559673Seric void
86659673Seric hash_astore(ad, lhs, rhs, e)
86759673Seric 	register ALIASDB *ad;
86859673Seric 	char *lhs;
86959673Seric 	char *rhs;
87059673Seric 	ENVELOPE *e;
87159673Seric {
87259673Seric 	int stat;
87359673Seric 	DBT key;
87459673Seric 	DBT data;
87559673Seric 
876*59697Seric 	if (tTd(27, 20))
877*59697Seric 		printf("hash_astore(%s, %s)\n", lhs, rhs);
878*59697Seric 
879*59697Seric 	key.size = strlen(lhs) + 1;
88059673Seric 	key.data = lhs;
88159673Seric 
882*59697Seric 	data.size = strlen(rhs) + 1;
88359673Seric 	data.data = rhs;
88459673Seric 
88559673Seric 	stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, R_NOOVERWRITE);
88659673Seric 	if (stat > 0)
88759673Seric 	{
88859673Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
88959673Seric 		stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, 0);
89059673Seric 	}
89159673Seric 	if (stat != 0)
89259673Seric 		syserr("readaliases: db put (%s)", lhs);
89359673Seric }
89459673Seric 
89559673Seric 
89659673Seric /*
89759673Seric **  HASH_AINIT -- initialize hash database
89859673Seric */
89959673Seric 
90059673Seric bool
90159673Seric hash_ainit(ad, e)
90259673Seric 	register ALIASDB *ad;
90359673Seric 	ENVELOPE *e;
90459673Seric {
90559673Seric 	char buf[MAXNAME];
90659673Seric 
907*59697Seric 	if (tTd(27, 2))
908*59697Seric 		printf("hash_ainit(%s)\n", ad->ad_name);
909*59697Seric 
91059673Seric 	/* open the database */
91159673Seric 	(void) strcpy(buf, ad->ad_name);
91259673Seric 	(void) strcat(buf, ".db");
91359673Seric 	ad->ad_ndbp = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
91459673Seric 	if (ad->ad_ndbp == NULL)
91559673Seric 		return FALSE;
91659673Seric 
91759673Seric 	/* wait for @:@ to appear */
91859673Seric 	aliaswait(ad, ".db", e);
91959673Seric 	return TRUE;
92059673Seric }
92159673Seric 
92259673Seric 
92359673Seric /*
92459673Seric **  HASH_AREBUILD -- rebuild hash database
92559673Seric */
92659673Seric 
92759673Seric void
92859673Seric hash_arebuild(ad, fp, e)
92959673Seric 	register ALIASDB *ad;
93059673Seric 	FILE *fp;
93159673Seric 	ENVELOPE *e;
93259673Seric {
93359673Seric 	register DB *db;
93459673Seric 	char buf[MAXNAME];
93559673Seric 
936*59697Seric 	if (tTd(27, 2))
937*59697Seric 		printf("hash_arebuild(%s)\n", ad->ad_name);
938*59697Seric 
93959673Seric 	db = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
94059673Seric 	if (db == NULL)
94159673Seric 	{
94259673Seric 		syserr("readaliases: cannot create %s", buf);
94359673Seric 		return;
94459673Seric 	}
94559673Seric 	ad->ad_ndbp = db;
946*59697Seric 	ad->ad_flags |= ADF_WRITABLE;
94759673Seric 
94859673Seric 	/* read and store the aliases */
94959673Seric 	readaliases(ad, fp, e);
95059673Seric }
95159673Seric 
95259673Seric 
95359673Seric /*
95459673Seric **  HASH_ACLOSE -- add distinguished entries and close the database
95559673Seric */
95659673Seric 
95759673Seric void
95859673Seric hash_aclose(ad, e)
95959673Seric 	ALIASDB *ad;
96059673Seric 	ENVELOPE *e;
96159673Seric {
962*59697Seric 	if (tTd(27, 9))
963*59697Seric 		printf("hash_aclose(%x)\n", ad->ad_flags);
964*59697Seric 
96559673Seric 	if (bitset(ADF_WRITABLE, ad->ad_flags))
96659673Seric 	{
96759673Seric 		/* write out the distinguished alias */
96859673Seric 		hash_astore(ad, "@", "@", e);
96959673Seric 	}
97059673Seric 
97159673Seric 	if (ad->ad_ndbp->close(ad->ad_ndbp) != 0)
97259673Seric 		syserr("readaliases: db close failure");
97359673Seric }
97459673Seric 
97559673Seric #endif
976292Seric /*
97759673Seric **  STAB (Symbol Table) Modules
97859673Seric */
97959673Seric 
98059673Seric 
98159673Seric /*
98259673Seric **  STAB_ALOOKUP -- look up alias in symbol table
98359673Seric */
98459673Seric 
98559673Seric char *
98659673Seric stab_alookup(ad, name, e)
98759673Seric 	register ALIASDB *ad;
98859673Seric 	char *name;
98959673Seric 	ENVELOPE *e;
99059673Seric {
99159673Seric 	register STAB *s;
99259673Seric 
993*59697Seric 	if (tTd(27, 20))
994*59697Seric 		printf("stab_lookup(%s)\n", name);
995*59697Seric 
99659673Seric 	s = stab(name, ST_ALIAS, ST_FIND);
99759673Seric 	if (s != NULL)
99859673Seric 		return (s->s_alias);
99959673Seric 	return (NULL);
100059673Seric }
100159673Seric 
100259673Seric 
100359673Seric /*
100459673Seric **  STAB_ASTORE -- store in symtab (actually using during init, not rebuild)
100559673Seric */
100659673Seric 
100759673Seric void
100859673Seric stab_astore(ad, lhs, rhs, e)
100959673Seric 	register ALIASDB *ad;
101059673Seric 	char *lhs;
101159673Seric 	char *rhs;
101259673Seric 	ENVELOPE *e;
101359673Seric {
101459673Seric 	register STAB *s;
101559673Seric 
101659673Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
101759673Seric 	s->s_alias = newstr(rhs);
101859673Seric }
101959673Seric 
102059673Seric 
102159673Seric /*
102259673Seric **  STAB_AINIT -- initialize (reads data file)
102359673Seric */
102459673Seric 
102559673Seric bool
102659673Seric stab_ainit(ad, e)
102759673Seric 	register ALIASDB *ad;
102859673Seric 	ENVELOPE *e;
102959673Seric {
103059673Seric 	FILE *af;
103159673Seric 
1032*59697Seric 	if (tTd(27, 2))
1033*59697Seric 		printf("stab_ainit(%s)\n", ad->ad_name);
1034*59697Seric 
103559673Seric 	af = fopen(ad->ad_name, "r");
103659673Seric 	if (af == NULL)
103759673Seric 	{
103859673Seric 		syserr("554 Can't open %s", ad->ad_name);
103959673Seric 		errno = 0;
104059673Seric 		return FALSE;
104159673Seric 	}
104259673Seric 
104359673Seric 	readaliases(ad, af, e);
104459673Seric }
104559673Seric 
104659673Seric 
104759673Seric /*
104859673Seric **  STAB_AREBUILD -- rebuild alias file
104959673Seric */
105059673Seric 
105159673Seric void
105259673Seric stab_arebuild(ad, fp, e)
105359673Seric 	ALIASDB *ad;
105459673Seric 	FILE *fp;
105559673Seric 	ENVELOPE *e;
105659673Seric {
1057*59697Seric 	if (tTd(27, 2))
1058*59697Seric 		printf("stab_arebuild(%s)\n", ad->ad_name);
1059*59697Seric 
1060*59697Seric 	ad->ad_flags |= ADF_WRITABLE;
106159673Seric }
106259673Seric 
106359673Seric 
106459673Seric /*
106559673Seric **  STAB_ACLOSE -- close symbol table (???)
106659673Seric */
106759673Seric 
106859673Seric void
106959673Seric stab_aclose(ad, e)
107059673Seric 	ALIASDB *ad;
107159673Seric 	ENVELOPE *e;
107259673Seric {
107359673Seric 	/* ignore it */
107459673Seric }
107559673Seric /*
107659673Seric **  NIS Modules
107759673Seric */
107859673Seric 
107959673Seric #ifdef NIS
108059673Seric 
108159673Seric /*
108259673Seric **  NIS_ALOOKUP
108359673Seric */
108459673Seric 
108559673Seric char *
108659673Seric nis_alookup(ad, name, e)
108759673Seric 	ALIASDB *ad;
108859673Seric 	char *name;
108959673Seric 	ENVELOPE *e;
109059673Seric {
109159673Seric 	auto char *vp;
109259673Seric 	auto int vsize;
109359673Seric 
1094*59697Seric 	if (tTd(27, 20))
1095*59697Seric 		printf("nis_lookup(%s)\n", name);
1096*59697Seric 
109759673Seric 	if (ypmatch(ad->ad_domain, ad->ad_name, name, strlen(name),
109859673Seric 			&vp, &vsize) != 0)
109959673Seric 		return NULL;
110059673Seric 	return vp;
110159673Seric }
110259673Seric 
110359673Seric /*
110459673Seric **  NIS_ASTORE
110559673Seric */
110659673Seric 
110759673Seric void
110859673Seric nis_astore(ad, lhs, rhs, e)
110959673Seric 	ALIASDB *ad;
111059673Seric 	char *lhs;
111159673Seric 	char *rhs;
111259673Seric 	ENVELOPE *e;
111359673Seric {
111459673Seric 	/* nothing */
111559673Seric }
111659673Seric 
111759673Seric /*
111859673Seric **  NIS_AINIT
111959673Seric */
112059673Seric 
112159673Seric bool
112259673Seric nis_ainit(ad, e)
112359673Seric 	ALIASDB *ad;
112459673Seric 	ENVELOPE *e;
112559673Seric {
112659673Seric 	register char *p;
112759673Seric 	auto char *ypmaster;
112859673Seric 
1129*59697Seric 	if (tTd(27, 2))
1130*59697Seric 		printf("nis_ainit(%s)\n", ad->ad_name);
1131*59697Seric 
113259673Seric 	p = strchr(ad->ad_name, '@');
113359673Seric 	if (p != NULL)
113459673Seric 	{
113559673Seric 		*p++ = '\0';
113659673Seric 		if (*p != '\0')
113759673Seric 			ad->ad_domain = p;
113859673Seric 	}
113959673Seric 	if (ad->ad_domain == NULL)
114059673Seric 		yp_get_default_domain(&ad->ad_domain);
114159673Seric 
114259673Seric 	if (*ad->ad_name == '\0')
114359673Seric 		ad->ad_name = "mail.aliases";
114459673Seric 
114559673Seric 	yperr = yp_master(ad->ad_domain, ad->ad_name, &ypmaster);
114659673Seric 	return (yperr == 0);
114759673Seric }
114859673Seric 
114959673Seric /*
115059673Seric **  NIS_AREBUILD
115159673Seric */
115259673Seric 
115359673Seric void
115459673Seric nis_arebuild(ad, fp, e)
115559673Seric 	ALIASDB *ad;
115659673Seric 	FILE *fp;
115759673Seric 	ENVELOPE *e;
115859673Seric {
1159*59697Seric 	if (tTd(27, 2))
1160*59697Seric 		printf("nis_arebuild(%s)\n", ad->ad_name);
1161*59697Seric 
116259673Seric 	/* nothing */
116359673Seric }
116459673Seric 
116559673Seric 
116659673Seric /*
116759673Seric **  NIS_ACLOSE
116859673Seric */
116959673Seric 
117059673Seric void
117159673Seric nis_aclose(ad, e)
117259673Seric 	ALIASDB *ad;
117359673Seric 	ENVELOPE *e;
117459673Seric {
117559673Seric 	/* nothing */
117659673Seric }
117759673Seric 
117859673Seric #endif /* NIS */
117959673Seric /*
118059673Seric **  Implicit Modules
118158059Seric **
118259673Seric **	Tries several types.  For back compatibility.
118358059Seric */
118458059Seric 
118559673Seric /*
118659673Seric **  IMPL_ALOOKUP -- lookup in best open database
118759673Seric */
118858059Seric 
118959673Seric char *
119059673Seric impl_alookup(ad, name, e)
119159673Seric 	ALIASDB *ad;
119259673Seric 	char *name;
119359673Seric 	ENVELOPE *e;
119458059Seric {
1195*59697Seric 	if (tTd(27, 20))
1196*59697Seric 		printf("impl_lookup(%s)\n", name);
1197*59697Seric 
119859673Seric #ifdef NEWDB
119959673Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
120059673Seric 		return hash_alookup(ad, name, e);
120159673Seric #endif
120259673Seric #ifdef NDBM
120359673Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
120459673Seric 		return ndbm_alookup(ad, name, e);
120559673Seric #endif
120659673Seric 	return stab_alookup(ad, name, e);
120759673Seric }
120859673Seric 
120959673Seric /*
121059673Seric **  IMPL_ASTORE -- store in open databases
121159673Seric */
121259673Seric 
121359673Seric void
121459673Seric impl_astore(ad, lhs, rhs, e)
121559673Seric 	ALIASDB *ad;
121659673Seric 	char *lhs;
121759673Seric 	char *rhs;
121859673Seric 	ENVELOPE *e;
121959673Seric {
122059673Seric #ifdef NEWDB
122159673Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
122259673Seric 		hash_astore(ad, lhs, rhs, e);
122359673Seric #endif
122459673Seric #ifdef NDBM
122559673Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
122659673Seric 		ndbm_astore(ad, lhs, rhs, e);
122759673Seric #endif
122859673Seric 	stab_astore(ad, lhs, rhs, e);
122959673Seric }
123059673Seric 
123159673Seric /*
123259673Seric **  IMPL_AINIT -- implicit database lookup
123359673Seric */
123459673Seric 
123559673Seric bool
123659673Seric impl_ainit(ad, e)
123759673Seric 	ALIASDB *ad;
123859673Seric 	ENVELOPE *e;
123959673Seric {
1240*59697Seric 	if (tTd(27, 2))
1241*59697Seric 		printf("impl_ainit(%s)\n", ad->ad_name);
1242*59697Seric 
124359673Seric 	/* implicit class */
124459673Seric #ifdef NEWDB
1245*59697Seric 	ad->ad_flags |= ADF_IMPLHASH;
124659673Seric 	if (hash_ainit(ad, e))
124758059Seric 	{
1248*59697Seric 		return TRUE;
124959673Seric 	}
1250*59697Seric 	ad->ad_flags &= ~ADF_IMPLHASH;
125159673Seric #endif
125259673Seric #ifdef NDBM
1253*59697Seric 	ad->ad_flags |= ADF_IMPLNDBM;
125459673Seric 	if (ndbm_ainit(ad, e))
125559673Seric 	{
1256*59697Seric 		return TRUE;
125759673Seric 	}
1258*59697Seric 	ad->ad_flags &= ~ADF_IMPLNDBM;
125959673Seric #endif
126059673Seric 	syserr("WARNING: cannot open alias database %s", ad->ad_name);
126158059Seric 
126259673Seric 	if (stab_ainit(ad, e))
126359673Seric 	{
1264*59697Seric 		return TRUE;
126559673Seric 	}
1266*59697Seric 
1267*59697Seric 	return FALSE;
126859673Seric }
126958059Seric 
127059673Seric /*
127159673Seric **  IMPL_AREBUILD -- rebuild alias database
127259673Seric */
127358059Seric 
127459673Seric void
127559673Seric impl_arebuild(ad, fp, e)
127659673Seric 	ALIASDB *ad;
127759673Seric 	FILE *fp;
127859673Seric 	ENVELOPE *e;
127959673Seric {
128059673Seric #ifdef NEWDB
128159673Seric 	DB *ndb;
128259673Seric 	char buf[MAXNAME];
1283*59697Seric #endif
128459673Seric 
1285*59697Seric 	if (tTd(27, 2))
1286*59697Seric 		printf("impl_arebuild(%s)\n", ad->ad_name);
1287*59697Seric 
1288*59697Seric #ifdef NEWDB
128959673Seric 	(void) strcpy(buf, ad->ad_name);
129059673Seric 	(void) strcat(buf, ".db");
129159673Seric 	ndb = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
129259673Seric 	if (ndb == NULL)
129358059Seric 	{
129459673Seric 		syserr("rebuildaliases: cannot create %s", buf);
129558059Seric 	}
129659673Seric 	else
129759673Seric 	{
129859673Seric 		ad->ad_ndbp = ndb;
129959673Seric 		ad->ad_flags |= ADF_IMPLHASH;
130059673Seric #if defined(NDBM) && defined(YPCOMPAT)
130159673Seric 		if (access("/var/yp/Makefile", R_OK) != 0)
130259673Seric #endif
1303*59697Seric 			goto readem;
130459673Seric 	}
130559673Seric #endif
130659673Seric 
130759673Seric #ifdef NDBM
130859673Seric 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
130959673Seric 	if (ad->ad_dbp == NULL)
131059673Seric 	{
131159673Seric 		syserr("rebuildaliases: cannot create %s.{pag,dir}",
131259673Seric 			ad->ad_name);
131359673Seric 	}
131459673Seric 	else
131559673Seric 	{
131659673Seric 		ad->ad_flags |= ADF_IMPLNDBM;
131759673Seric 	}
131859673Seric #endif
131959673Seric 
132059673Seric 	if (!bitset(ADF_IMPLHASH|ADF_IMPLNDBM, ad->ad_flags))
132159673Seric 		return;
132259673Seric 
1323*59697Seric   readem:
1324*59697Seric 	ad->ad_flags |= ADF_WRITABLE;
132559673Seric 
132659673Seric 	/* read and store aliases */
132759673Seric 	readaliases(ad, fp, e);
132858059Seric }
132958059Seric 
133059673Seric 
133159673Seric /*
133259673Seric **  IMPL_ACLOSE -- close any open database(s)
133359673Seric */
133459673Seric 
133559673Seric void
133659673Seric impl_aclose(ad, e)
133759673Seric 	ALIASDB *ad;
133859673Seric 	ENVELOPE *e;
133959673Seric {
134059673Seric #ifdef NEWDB
1341*59697Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
1342*59697Seric 		hash_aclose(ad, e);
134359673Seric #endif
134459673Seric 
134559673Seric #ifdef NDBM
1346*59697Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
1347*59697Seric 		ndbm_aclose(ad, e);
134859673Seric #endif
134959673Seric }
135058059Seric /*
135159673Seric **  SETUPALIASES -- set up aliases classes
135259673Seric */
135359673Seric 
135459673Seric #ifdef NEWDB
135559673Seric ALIASCLASS	HashAClass =
135659673Seric {
135759673Seric 	"hash",		hash_alookup,	hash_astore,
135859673Seric 	hash_ainit,	hash_arebuild,	hash_aclose,
135959673Seric 	ACF_BUILDABLE
136059673Seric };
136159673Seric #endif
136259673Seric 
136359673Seric #ifdef NDBM
136459673Seric ALIASCLASS	DbmAClass =
136559673Seric {
136659673Seric 	"dbm",		ndbm_alookup,	ndbm_astore,
136759673Seric 	ndbm_ainit,	ndbm_arebuild,	ndbm_aclose,
136859673Seric 	ACF_BUILDABLE
136959673Seric };
137059673Seric #endif
137159673Seric 
137259673Seric #ifdef NIS
137359673Seric ALIASCLASS	NisAClass =
137459673Seric {
137559673Seric 	"nis",		nis_alookup,	nis_astore,
137659673Seric 	nis_ainit,	nis_arebuild,	nis_aclose,
137759673Seric 	0
137859673Seric };
137959673Seric #endif
138059673Seric 
138159673Seric ALIASCLASS	StabAClass =
138259673Seric {
138359673Seric 	"stab",		stab_alookup,	stab_astore,
138459673Seric 	stab_ainit,	stab_arebuild,	stab_aclose,
138559673Seric 	0
138659673Seric };
138759673Seric 
138859673Seric ALIASCLASS	ImplAClass =
138959673Seric {
139059673Seric 	"implicit",	impl_alookup,	impl_astore,
139159673Seric 	impl_ainit,	impl_arebuild,	impl_aclose,
139259673Seric 	ACF_BUILDABLE
139359673Seric };
139459673Seric 
139559673Seric setupaliases()
139659673Seric {
139759673Seric 	register STAB *s;
139859673Seric 
139959673Seric #ifdef NEWDB
140059673Seric 	s = stab("hash", ST_ALIASCLASS, ST_ENTER);
140159673Seric 	s->s_aliasclass = &HashAClass;
140259673Seric #endif
140359673Seric 
140459673Seric #ifdef NDBM
140559673Seric 	s = stab("dbm", ST_ALIASCLASS, ST_ENTER);
140659673Seric 	s->s_aliasclass = &DbmAClass;
140759673Seric #endif
140859673Seric 
140959673Seric #ifdef NIS
141059673Seric 	s = stab("nis", ST_ALIASCLASS, ST_ENTER);
141159673Seric 	s->s_aliasclass = &NisAClass;
141259673Seric #endif
141359673Seric 
141459673Seric #if !defined(NEWDB) && !defined(NDBM)
141559673Seric 	s = stab("stab", ST_ALIASCLASS, ST_ENTER);
141659673Seric 	s->s_aliasclass = &StabAClass;
141759673Seric #endif
141859673Seric 
141959673Seric 	s = stab("implicit", ST_ALIASCLASS, ST_ENTER);
142059673Seric 	s->s_aliasclass = &ImplAClass;
142159673Seric }
142259673Seric /*
1423292Seric **  FORWARD -- Try to forward mail
1424292Seric **
1425292Seric **	This is similar but not identical to aliasing.
1426292Seric **
1427292Seric **	Parameters:
14284314Seric **		user -- the name of the user who's mail we would like
14294314Seric **			to forward to.  It must have been verified --
14304314Seric **			i.e., the q_home field must have been filled
14314314Seric **			in.
14324999Seric **		sendq -- a pointer to the head of the send queue to
14334999Seric **			put this user's aliases in.
1434292Seric **
1435292Seric **	Returns:
14364098Seric **		none.
1437292Seric **
1438292Seric **	Side Effects:
14393185Seric **		New names are added to send queues.
1440292Seric */
1441292Seric 
144255012Seric forward(user, sendq, e)
14432966Seric 	ADDRESS *user;
14444999Seric 	ADDRESS **sendq;
144555012Seric 	register ENVELOPE *e;
1446292Seric {
144757136Seric 	char *pp;
144857136Seric 	char *ep;
14494069Seric 
14507671Seric 	if (tTd(27, 1))
14514098Seric 		printf("forward(%s)\n", user->q_paddr);
14524098Seric 
14534594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
14544098Seric 		return;
14554314Seric 	if (user->q_home == NULL)
145658059Seric 	{
145758151Seric 		syserr("554 forward: no home");
145858059Seric 		user->q_home = "/nosuchdirectory";
145958059Seric 	}
14604069Seric 
14614069Seric 	/* good address -- look for .forward file in home */
146255012Seric 	define('z', user->q_home, e);
146357136Seric 	define('u', user->q_user, e);
146457136Seric 	define('h', user->q_host, e);
146557136Seric 	if (ForwardPath == NULL)
146658050Seric 		ForwardPath = newstr("\201z/.forward");
146757136Seric 
146857136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
146957136Seric 	{
147058247Seric 		int err;
147157232Seric 		char buf[MAXPATHLEN+1];
147257136Seric 
147357136Seric 		ep = strchr(pp, ':');
147457136Seric 		if (ep != NULL)
147557136Seric 			*ep = '\0';
147657136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
147757136Seric 		if (ep != NULL)
147857136Seric 			*ep++ = ':';
147957136Seric 		if (tTd(27, 3))
148057136Seric 			printf("forward: trying %s\n", buf);
148158247Seric 		err = include(buf, TRUE, user, sendq, e);
148258247Seric 		if (err == 0)
148357136Seric 			break;
148458247Seric 		if (transienterror(err))
148558247Seric 		{
148658247Seric 			/* we have to suspend this message */
148759563Seric 			if (tTd(27, 2))
148859563Seric 				printf("forward: transient error on %s\n", buf);
148959563Seric #ifdef LOG
149059563Seric 			if (LogLevel > 2)
149159624Seric 				syslog(LOG_ERR, "%s: forward %s: transient error: %s",
149259624Seric 					e->e_id, buf, errstring(err));
149359563Seric #endif
149459611Seric 			message("%s: %s: message queued", buf, errstring(err));
149558247Seric 			user->q_flags |= QQUEUEUP|QDONTSEND;
149658247Seric 			return;
149758247Seric 		}
149857136Seric 	}
1499292Seric }
1500