xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 59758)
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
2159724Seric # ifdef NIS_ALIASES
2259673Seric # include <rpcsvc/ypclnt.h>
2359673Seric # endif
2456766Seric 
2533728Sbostic #ifndef lint
2651756Seric #ifdef NEWDB
2757736Seric #ifdef NDBM
28*59758Seric static char sccsid[] = "@(#)alias.c	6.45 (Berkeley) 05/06/93 (with NEWDB and NDBM)";
2951756Seric #else
30*59758Seric static char sccsid[] = "@(#)alias.c	6.45 (Berkeley) 05/06/93 (with NEWDB)";
3157736Seric #endif
3257736Seric #else
3356845Seric #ifdef NDBM
34*59758Seric static char sccsid[] = "@(#)alias.c	6.45 (Berkeley) 05/06/93 (with NDBM)";
3533728Sbostic #else
36*59758Seric static char sccsid[] = "@(#)alias.c	6.45 (Berkeley) 05/06/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 */
7459733Seric 	void	(*ac_rebuild)__P((ALIASDB *, FILE *, int, 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 
25159697Seric 	if (tTd(27, 8))
25259697Seric 		printf("setalias(%s)\n", spec);
25359697Seric 
254*59758Seric 	for (p = spec; p != NULL; )
25551756Seric 	{
256*59758Seric 		while (isspace(*p))
257*59758Seric 			p++;
258*59758Seric 		if (*p == NULL)
25959673Seric 			break;
26059673Seric 		spec = p;
26159673Seric 
262*59758Seric 		if (NAliasDBs >= MAXALIASDB)
263*59758Seric 		{
264*59758Seric 			syserr("Too many alias databases defined, %d max", MAXALIASDB);
265*59758Seric 			return;
266*59758Seric 		}
267*59758Seric 		ad = &AliasDB[NAliasDBs];
268*59758Seric 
269*59758Seric 		p = strpbrk(p, " ,/:");
270*59758Seric 		if (p != NULL && *p == ':')
271*59758Seric 		{
272*59758Seric 			/* explicit class listed */
273*59758Seric 			*p++ = '\0';
274*59758Seric 			class = spec;
275*59758Seric 			spec = p;
276*59758Seric 		}
277*59758Seric 		else
278*59758Seric 		{
279*59758Seric 			/* implicit class */
280*59758Seric 			class = "implicit";
281*59758Seric 		}
282*59758Seric 
283*59758Seric 		/* find end of spec */
284*59758Seric 		if (p != NULL)
285*59758Seric 			p = strchr(p, ',');
286*59758Seric 		if (p != NULL)
287*59758Seric 			*p++ = '\0';
288*59758Seric 
289*59758Seric 		/* look up class */
290*59758Seric 		s = stab(class, ST_ALIASCLASS, ST_FIND);
291*59758Seric 		if (s == NULL)
292*59758Seric 		{
293*59758Seric 			if (tTd(27, 1))
294*59758Seric 				printf("Unknown alias class %s\n", class);
295*59758Seric 		}
296*59758Seric 		else
297*59758Seric 		{
298*59758Seric 			ad->ad_class = s->s_aliasclass;
299*59758Seric 			ad->ad_name = newstr(spec);
300*59758Seric 			NAliasDBs++;
301*59758Seric 		}
30259756Seric 	}
3035701Seric }
3045701Seric /*
3054098Seric **  INITALIASES -- initialize for aliasing
3064098Seric **
30756845Seric **	Very different depending on whether we are running NDBM or not.
3084098Seric **
3094098Seric **	Parameters:
31059673Seric **		rebuild -- if TRUE, this rebuilds the cached versions.
31159673Seric **		e -- current envelope.
3124098Seric **
3134098Seric **	Returns:
3144098Seric **		none.
3154098Seric **
3164098Seric **	Side Effects:
3174098Seric **		initializes aliases:
31856845Seric **		if NDBM:  opens the database.
31956845Seric **		if ~NDBM: reads the aliases into the symbol table.
3204098Seric */
3214098Seric 
32240559Sbostic # define DBMMODE	0644
3234157Seric 
32459673Seric initaliases(rebuild, e)
32559673Seric 	bool rebuild;
32655012Seric 	register ENVELOPE *e;
3274098Seric {
32859673Seric 	int dbno;
32959673Seric 	register ALIASDB *ad;
3304322Seric 
33159673Seric 	for (dbno = 0; dbno < NAliasDBs; dbno++)
3328437Seric 	{
33359673Seric 		ad = &AliasDB[dbno];
33459697Seric 
33559697Seric 		if (tTd(27, 2))
33659697Seric 			printf("initaliases(%s:%s)\n",
33759697Seric 				ad->ad_class->ac_name, ad->ad_name);
33859697Seric 
33959673Seric 		if (rebuild)
34050576Seric 		{
34159673Seric 			rebuildaliases(ad, FALSE, e);
34250576Seric 		}
34359673Seric 		else
34457249Seric 		{
34559697Seric 			if (ad->ad_class->ac_init(ad, e))
34659756Seric 			{
34759756Seric 				if (tTd(27, 4))
34859756Seric 					printf("%s:%s: valid\n",
34959756Seric 						ad->ad_class->ac_name,
35059756Seric 						ad->ad_name);
35159697Seric 				ad->ad_flags |= ADF_VALID;
35259756Seric 			}
35359756Seric 			else if (tTd(27, 4))
35459756Seric 				printf("%s:%s: invalid: %s\n",
35559756Seric 					ad->ad_class->ac_name, ad->ad_name,
35659756Seric 					errstring(errno));
35757249Seric 		}
35850575Seric 	}
35959673Seric }
36059673Seric /*
36159673Seric **  ALIASWAIT -- wait for distinguished @:@ token to appear.
36259673Seric **
36359673Seric **	This can decide to reopen or rebuild the alias file
36459673Seric */
36559673Seric 
36659673Seric aliaswait(ad, ext, e)
36759673Seric 	ALIASDB *ad;
36859673Seric 	char *ext;
36959673Seric 	ENVELOPE *e;
37059673Seric {
37159673Seric 	int atcnt;
37259673Seric 	time_t mtime;
37359673Seric 	struct stat stb;
37459673Seric 	char buf[MAXNAME];
37559673Seric 
37659697Seric 	if (tTd(27, 3))
37759697Seric 		printf("aliaswait\n");
37859697Seric 
37917471Seric 	atcnt = SafeAlias * 2;
38017471Seric 	if (atcnt > 0)
38117471Seric 	{
38259673Seric 		while (atcnt-- >= 0 &&
38359673Seric 		       ad->ad_class->ac_lookup(ad, "@", e) == NULL)
38425689Seric 		{
38525689Seric 			/*
38659673Seric 			**  Close and re-open the alias database in case
38759673Seric 			**  the one is mv'ed instead of cp'ed in.
38825689Seric 			*/
38925689Seric 
39059697Seric 			if (tTd(27, 2))
39159697Seric 				printf("aliaswait: sleeping\n");
39259697Seric 
39359673Seric 			ad->ad_class->ac_close(ad, e);
39417471Seric 			sleep(30);
39559673Seric 			ad->ad_class->ac_init(ad, e);
39625689Seric 		}
39717471Seric 	}
3988437Seric 
39959673Seric 	/* see if we need to go into auto-rebuild mode */
40059673Seric 	if (stat(ad->ad_name, &stb) < 0)
40159673Seric 		return;
40259673Seric 	mtime = stb.st_mtime;
40359673Seric 	(void) strcpy(buf, ad->ad_name);
40459673Seric 	(void) strcat(buf, ext);
40559673Seric 	if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0)
4064322Seric 	{
40759673Seric 		/* database is out of date */
40840559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
4094322Seric 		{
41059673Seric 			message("auto-rebuilding alias database %s",
41159673Seric 				ad->ad_name);
41259673Seric 			rebuildaliases(ad, TRUE, e);
4134322Seric 		}
4144322Seric 		else
4154322Seric 		{
41619039Seric #ifdef LOG
41758020Seric 			if (LogLevel > 3)
41859673Seric 				syslog(LOG_INFO, "alias database %s out of date",
41959673Seric 					ad->ad_name);
42056795Seric #endif /* LOG */
42159673Seric 			message("Warning: alias database %s out of date",
42259673Seric 				ad->ad_name);
4234322Seric 		}
4244322Seric 	}
42559673Seric }
42659673Seric /*
42759673Seric **  REBUILDALIASES -- rebuild the alias database.
42859673Seric **
42959673Seric **	Parameters:
43059673Seric **		ad -- the database to rebuild.
43159673Seric **		automatic -- set if this was automatically generated.
43259673Seric **		e -- current envelope.
43359673Seric **
43459673Seric **	Returns:
43559673Seric **		none.
43659673Seric **
43759673Seric **	Side Effects:
43859673Seric **		Reads the text version of the database, builds the
43959673Seric **		DBM or DB version.
44059673Seric */
4414322Seric 
44259673Seric rebuildaliases(ad, automatic, e)
44359673Seric 	register ALIASDB *ad;
44459673Seric 	bool automatic;
44559673Seric 	register ENVELOPE *e;
44659673Seric {
44759673Seric 	FILE *af;
44859673Seric 	void (*oldsigint)();
4494322Seric 
45059673Seric 	if (!bitset(ACF_BUILDABLE, ad->ad_class->ac_flags))
45159673Seric 		return;
4524322Seric 
45359673Seric #ifdef LOG
45459673Seric 	if (LogLevel > 7)
4558437Seric 	{
45659673Seric 		extern char *username();
45725522Seric 
45859673Seric 		syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
45959673Seric 			ad->ad_name, automatic ? "auto" : "", username());
46059673Seric 	}
46156795Seric #endif /* LOG */
46259673Seric 
46359673Seric 	/* try to lock the source file */
46459673Seric 	if ((af = fopen(ad->ad_name, "r+")) == NULL)
46559673Seric 	{
46659756Seric 		if (tTd(27, 1))
46759756Seric 			printf("Can't open %s: %s\n",
46859756Seric 				ad->ad_name, errstring(errno));
46959756Seric 		ad->ad_flags &= ~ADF_VALID;
47059673Seric 		errno = 0;
47159673Seric 		return;
4728437Seric 	}
47359673Seric 
47459673Seric 	/* see if someone else is rebuilding the alias file */
47559673Seric 	if (!lockfile(fileno(af), ad->ad_name, LOCK_EX|LOCK_NB))
47659673Seric 	{
47759673Seric 		/* yes, they are -- wait until done */
47859673Seric 		message("Alias file %s is already being rebuilt",
47959673Seric 			ad->ad_name);
48059673Seric 		if (OpMode != MD_INITALIAS)
48159673Seric 		{
48259673Seric 			/* wait for other rebuild to complete */
48359673Seric 			(void) lockfile(fileno(af), ad->ad_name,
48459673Seric 					LOCK_EX);
48559673Seric 		}
48659673Seric 		(void) fclose(af);
48759673Seric 		errno = 0;
48859673Seric 		return;
48959673Seric 	}
49059673Seric 
49159673Seric 	oldsigint = signal(SIGINT, SIG_IGN);
49259673Seric 
49359733Seric 	ad->ad_class->ac_rebuild(ad, af, automatic, e);
49459673Seric 
49559673Seric 	/* close the file, thus releasing locks */
49659673Seric 	fclose(af);
49759673Seric 
49859673Seric 	/* add distinguished entries and close the database */
49959701Seric 	if (bitset(ADF_VALID, ad->ad_flags))
50059701Seric 		ad->ad_class->ac_close(ad, e);
50159673Seric 
50259673Seric 	/* restore the old signal */
50359673Seric 	(void) signal(SIGINT, oldsigint);
5044157Seric }
5054157Seric /*
5064157Seric **  READALIASES -- read and process the alias file.
5074157Seric **
5084157Seric **	This routine implements the part of initaliases that occurs
5094157Seric **	when we are not going to use the DBM stuff.
5104157Seric **
5114157Seric **	Parameters:
51259673Seric **		ad -- the alias database descriptor.
51359673Seric **		af -- file to read the aliases from.
51459733Seric **		automatic -- set if this was an automatic rebuild.
51559673Seric **		e -- the current alias file.
5164157Seric **
5174157Seric **	Returns:
5184157Seric **		none.
5194157Seric **
5204157Seric **	Side Effects:
5214157Seric **		Reads aliasfile into the symbol table.
5224157Seric **		Optionally, builds the .dir & .pag files.
5234157Seric */
5244157Seric 
5254157Seric static
52659733Seric readaliases(ad, af, automatic, e)
52759673Seric 	register ALIASDB *ad;
52859673Seric 	FILE *af;
52959733Seric 	int automatic;
53055012Seric 	register ENVELOPE *e;
5314157Seric {
5324098Seric 	register char *p;
5334098Seric 	char *rhs;
5344098Seric 	bool skipping;
53559673Seric 	long naliases, bytes, longest;
5364098Seric 	ADDRESS al, bl;
5374106Seric 	register STAB *s;
5389368Seric 	char line[BUFSIZ];
5394098Seric 
5404314Seric 	/*
5414314Seric 	**  Read and interpret lines
5424314Seric 	*/
5434314Seric 
54459673Seric 	FileName = ad->ad_name;
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)
56658151Seric 				syserr("554 Non-continuation line starts with space");
5674098Seric 			skipping = TRUE;
5684097Seric 			continue;
5694098Seric 		}
5704098Seric 		skipping = FALSE;
5711874Seric 
5724314Seric 		/*
5734314Seric 		**  Process the LHS
57457736Seric 		**	Find the colon separator, 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 		{
58558151Seric 			syserr("554 missing colon");
5864097Seric 			continue;
5874098Seric 		}
58858333Seric 		if (parseaddr(line, &al, 1, ':', NULL, e) == NULL)
5894098Seric 		{
59058151Seric 			syserr("554 illegal alias name");
59116898Seric 			continue;
5924098Seric 		}
5934314Seric 
5944314Seric 		/*
5954314Seric 		**  Process the RHS.
5964314Seric 		**	'al' is the internal form of the LHS address.
5974314Seric 		**	'p' points to the text of the RHS.
5984314Seric 		*/
5994314Seric 
60058914Seric 		while (isascii(*p) && isspace(*p))
60158914Seric 			p++;
6024098Seric 		rhs = p;
6034098Seric 		for (;;)
6044098Seric 		{
6054098Seric 			register char c;
60658662Seric 			register char *nlp;
6071515Seric 
60858662Seric 			nlp = &p[strlen(p)];
60958662Seric 			if (nlp[-1] == '\n')
61058662Seric 				*--nlp = '\0';
61158662Seric 
61259673Seric 			if (CheckAliases)
6134098Seric 			{
6144157Seric 				/* do parsing & compression of addresses */
61525278Seric 				while (*p != '\0')
6164098Seric 				{
61758333Seric 					auto char *delimptr;
61825278Seric 
61958050Seric 					while ((isascii(*p) && isspace(*p)) ||
62058050Seric 								*p == ',')
6214157Seric 						p++;
62225278Seric 					if (*p == '\0')
62325278Seric 						break;
62458333Seric 					if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL)
62558151Seric 						usrerr("553 %s... bad address", p);
62658333Seric 					p = delimptr;
6274098Seric 				}
6284098Seric 			}
6294157Seric 			else
63015769Seric 			{
63158662Seric 				p = nlp;
63215769Seric 			}
6331515Seric 
6344098Seric 			/* see if there should be a continuation line */
6354106Seric 			c = fgetc(af);
6364106Seric 			if (!feof(af))
6374314Seric 				(void) ungetc(c, af);
6384106Seric 			if (c != ' ' && c != '\t')
6394098Seric 				break;
6404098Seric 
6414098Seric 			/* read continuation line */
6424098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6434098Seric 				break;
6449368Seric 			LineNumber++;
64557135Seric 
64657135Seric 			/* check for line overflow */
64757135Seric 			if (strchr(p, '\n') == NULL)
64857135Seric 			{
64958151Seric 				usrerr("554 alias too long");
65057135Seric 				break;
65157135Seric 			}
6524098Seric 		}
65316898Seric 		if (al.q_mailer != LocalMailer)
65416898Seric 		{
65558151Seric 			syserr("554 cannot alias non-local names");
65616898Seric 			continue;
65716898Seric 		}
6584314Seric 
6594314Seric 		/*
6604314Seric 		**  Insert alias into symbol table or DBM file
6614314Seric 		*/
6624314Seric 
66357381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
66457381Seric 			makelower(al.q_user);
6654322Seric 
66659673Seric 		lhssize = strlen(al.q_user);
66759673Seric 		rhssize = strlen(rhs);
66859673Seric 		ad->ad_class->ac_store(ad, al.q_user, rhs, e);
6694157Seric 
67059673Seric 		if (al.q_paddr != NULL)
67159673Seric 			free(al.q_paddr);
67259673Seric 		if (al.q_host != NULL)
67359673Seric 			free(al.q_host);
67459673Seric 		if (al.q_user != NULL)
67559673Seric 			free(al.q_user);
6764322Seric 
6774322Seric 		/* statistics */
6784322Seric 		naliases++;
6794322Seric 		bytes += lhssize + rhssize;
6804322Seric 		if (rhssize > longest)
6814322Seric 			longest = rhssize;
6821515Seric 	}
68319784Seric 
68459673Seric 	e->e_to = NULL;
68559673Seric 	FileName = NULL;
68659733Seric 	if (Verbose || !automatic)
68759733Seric 		message("%s: %d aliases, longest %d bytes, %d bytes total",
68859673Seric 			ad->ad_name, naliases, longest, bytes);
68959673Seric # ifdef LOG
69059673Seric 	if (LogLevel > 7)
69159673Seric 		syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
69259673Seric 			ad->ad_name, naliases, longest, bytes);
69359673Seric # endif /* LOG */
69459673Seric }
69559673Seric /*
69659673Seric **  NDBM modules
69759673Seric */
69859673Seric 
69959673Seric #ifdef NDBM
70059673Seric 
70159673Seric /*
70259673Seric **  NDBM_ALOOKUP -- look up alias in ndbm file
70359673Seric */
70459673Seric 
70559673Seric char *
70659673Seric ndbm_alookup(ad, name, e)
70759673Seric 	register ALIASDB *ad;
70859673Seric 	char *name;
70959673Seric 	ENVELOPE *e;
71059673Seric {
71159673Seric 	int i;
71259673Seric 	datum rhs, lhs;
71359673Seric 	char keybuf[MAXNAME + 1];
71459673Seric 
71559697Seric 	if (tTd(27, 20))
71659697Seric 		printf("ndbm_lookup(%s)\n", name);
71759697Seric 
71859673Seric 	/* create a key for fetch */
71959673Seric 	i = strlen(name) + 1;
72059673Seric 	if (i > sizeof keybuf)
72159673Seric 		i = sizeof keybuf;
72259673Seric 	bcopy(name, keybuf, i);
72359673Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
72459673Seric 		makelower(keybuf);
72559673Seric 
72659673Seric 	lhs.dsize = i;
72759673Seric 	lhs.dptr = keybuf;
72859673Seric 	rhs = dbm_fetch((DBM *) ad->ad_dbp, lhs);
72959673Seric 	return (rhs.dptr);
73059673Seric }
73159673Seric 
73259673Seric 
73359673Seric /*
73459673Seric **  NDBM_ASTORE -- store a datum in the database
73559673Seric */
73659673Seric 
73759673Seric void
73859673Seric ndbm_astore(ad, lhs, rhs, e)
73959673Seric 	register ALIASDB *ad;
74059673Seric 	char *lhs;
74159673Seric 	char *rhs;
74259673Seric 	ENVELOPE *e;
74359673Seric {
74459673Seric 	datum key;
74559673Seric 	datum data;
74659673Seric 	int stat;
74759673Seric 
74859697Seric 	key.dsize = strlen(lhs) + 1;
74959673Seric 	key.dptr = lhs;
75059673Seric 
75159697Seric 	data.dsize = strlen(rhs) + 1;
75259673Seric 	data.dptr = rhs;
75359673Seric 
75459673Seric 	stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_INSERT);
75559673Seric 	if (stat > 0)
75619784Seric 	{
75759673Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
75859673Seric 		stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_REPLACE);
75959673Seric 	}
76059673Seric 	if (stat != 0)
76159673Seric 		syserr("readaliases: dbm put (%s)", lhs);
76259673Seric }
76319784Seric 
76459673Seric 
76559673Seric /*
76659673Seric **  NDBM_AINIT -- initialize DBM database
76759673Seric */
76859673Seric 
76959673Seric bool
77059673Seric ndbm_ainit(ad, e)
77159673Seric 	register ALIASDB *ad;
77259673Seric 	ENVELOPE *e;
77359673Seric {
77459673Seric 	char buf[MAXNAME];
77559673Seric 
77659697Seric 	if (tTd(27, 2))
77759697Seric 		printf("ndbm_ainit(%s)\n", ad->ad_name);
77859697Seric 
77959673Seric 	/* open the database */
78059673Seric 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDONLY, DBMMODE);
78159673Seric 	if (ad->ad_dbp == NULL)
78259673Seric 		return FALSE;
78359673Seric 
78459673Seric 	/* wait for @:@ to appear */
78559673Seric 	aliaswait(ad, ".pag", e);
78659673Seric 
78759673Seric 	return TRUE;
78859673Seric }
78959673Seric 
79059673Seric 
79159673Seric /*
79259673Seric **  NDBM_AREBUILD -- rebuild hash database
79359673Seric */
79459673Seric 
79559673Seric void
79659733Seric ndbm_arebuild(ad, fp, automatic, e)
79759673Seric 	register ALIASDB *ad;
79859673Seric 	FILE *fp;
79959733Seric 	int automatic;
80059673Seric 	ENVELOPE *e;
80159673Seric {
80259673Seric 	register DBM *db;
80359673Seric 	int i;
80459673Seric 	char buf[MAXNAME];
80559673Seric 
80659697Seric 	if (tTd(27, 2))
80759697Seric 		printf("ndbm_arebuild(%s)\n", ad->ad_name);
80859697Seric 
80959673Seric 	db = dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
81059673Seric 	if (db == NULL)
81159673Seric 	{
81259701Seric 		syserr("ndbm_arebuild: cannot create %s", buf);
81359673Seric 		return;
81459673Seric 	}
81559673Seric 	ad->ad_dbp = (void *) db;
81659701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
81759673Seric 
81859673Seric 	/* read and store the aliases */
81959733Seric 	readaliases(ad, fp, automatic, e);
82059673Seric }
82159673Seric 
82259673Seric /*
82359673Seric **  NDBM_ACLOSE -- close the database
82459673Seric */
82559673Seric 
82659673Seric void
82759673Seric ndbm_aclose(ad, e)
82859673Seric 	register ALIASDB  *ad;
82959673Seric 	ENVELOPE *e;
83059673Seric {
83159673Seric 	if (bitset(ADF_WRITABLE, ad->ad_flags))
83259673Seric 	{
83358059Seric #ifdef YPCOMPAT
83459673Seric 		char buf[200];
83558846Seric 
83659673Seric 		(void) sprintf(buf, "%010ld", curtime());
83759673Seric 		ndbm_astore(ad, "YP_LAST_MODIFIED", buf, e);
83859673Seric 
83959673Seric 		(void) myhostname(buf, sizeof buf);
84059673Seric 		ndbm_astore(ad, "YP_MASTER_NAME", buf, e);
84158059Seric #endif
84219784Seric 
84359673Seric 		/* write out the distinguished alias */
84459673Seric 		ndbm_astore(ad, "@", "@", e);
84519784Seric 	}
84659673Seric 	dbm_close((DBM *) ad->ad_dbp);
84759673Seric }
84819784Seric 
84959673Seric #endif
85059673Seric /*
85159673Seric **  HASH (NEWDB) Modules
85259673Seric */
85359673Seric 
85459673Seric #ifdef NEWDB
85559673Seric 
85659673Seric /*
85759673Seric **  HASH_ALOOKUP -- look up alias in hash file
85859673Seric */
85959673Seric 
86059673Seric char *
86159673Seric hash_alookup(ad, name, e)
86259673Seric 	register ALIASDB *ad;
86359673Seric 	char *name;
86459673Seric 	ENVELOPE *e;
86559673Seric {
86659673Seric 	int i;
86759673Seric 	DBT rhs, lhs;
86859673Seric 	int s;
86959673Seric 	char keybuf[MAXNAME + 1];
87059673Seric 
87159697Seric 	if (tTd(27, 20))
87259697Seric 		printf("hash_alookup(%s)\n", name);
87359697Seric 
87459673Seric 	/* create a key for fetch */
87559673Seric 	i = strlen(name) + 1;
87659673Seric 	if (i > sizeof keybuf)
87759673Seric 		i = sizeof keybuf;
87859673Seric 	bcopy(name, keybuf, i);
87959673Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
88059673Seric 		makelower(keybuf);
88159673Seric 
88259673Seric 	lhs.size = i;
88359673Seric 	lhs.data = keybuf;
88459673Seric 	i = ad->ad_ndbp->get(ad->ad_ndbp, &lhs, &rhs, 0);
88559673Seric 	if (i == 0)
88659673Seric 		return (rhs.data);
88759673Seric 	return (NULL);
888292Seric }
88959673Seric 
89059673Seric 
89159673Seric /*
89259673Seric **  HASH_ASTORE -- store a datum in the database
89359673Seric */
89459673Seric 
89559673Seric void
89659673Seric hash_astore(ad, lhs, rhs, e)
89759673Seric 	register ALIASDB *ad;
89859673Seric 	char *lhs;
89959673Seric 	char *rhs;
90059673Seric 	ENVELOPE *e;
90159673Seric {
90259673Seric 	int stat;
90359673Seric 	DBT key;
90459673Seric 	DBT data;
90559673Seric 
90659697Seric 	if (tTd(27, 20))
90759697Seric 		printf("hash_astore(%s, %s)\n", lhs, rhs);
90859697Seric 
90959697Seric 	key.size = strlen(lhs) + 1;
91059673Seric 	key.data = lhs;
91159673Seric 
91259697Seric 	data.size = strlen(rhs) + 1;
91359673Seric 	data.data = rhs;
91459673Seric 
91559673Seric 	stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, R_NOOVERWRITE);
91659673Seric 	if (stat > 0)
91759673Seric 	{
91859673Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
91959673Seric 		stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, 0);
92059673Seric 	}
92159673Seric 	if (stat != 0)
92259673Seric 		syserr("readaliases: db put (%s)", lhs);
92359673Seric }
92459673Seric 
92559673Seric 
92659673Seric /*
92759673Seric **  HASH_AINIT -- initialize hash database
92859673Seric */
92959673Seric 
93059673Seric bool
93159673Seric hash_ainit(ad, e)
93259673Seric 	register ALIASDB *ad;
93359673Seric 	ENVELOPE *e;
93459673Seric {
93559673Seric 	char buf[MAXNAME];
93659673Seric 
93759697Seric 	if (tTd(27, 2))
93859697Seric 		printf("hash_ainit(%s)\n", ad->ad_name);
93959697Seric 
94059673Seric 	/* open the database */
94159673Seric 	(void) strcpy(buf, ad->ad_name);
94259673Seric 	(void) strcat(buf, ".db");
94359673Seric 	ad->ad_ndbp = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
94459673Seric 	if (ad->ad_ndbp == NULL)
94559673Seric 		return FALSE;
94659673Seric 
94759673Seric 	/* wait for @:@ to appear */
94859673Seric 	aliaswait(ad, ".db", e);
94959673Seric 	return TRUE;
95059673Seric }
95159673Seric 
95259673Seric 
95359673Seric /*
95459673Seric **  HASH_AREBUILD -- rebuild hash database
95559673Seric */
95659673Seric 
95759673Seric void
95859733Seric hash_arebuild(ad, fp, automatic, e)
95959673Seric 	register ALIASDB *ad;
96059673Seric 	FILE *fp;
96159733Seric 	int automatic;
96259673Seric 	ENVELOPE *e;
96359673Seric {
96459673Seric 	register DB *db;
96559673Seric 	char buf[MAXNAME];
96659673Seric 
96759697Seric 	if (tTd(27, 2))
96859697Seric 		printf("hash_arebuild(%s)\n", ad->ad_name);
96959697Seric 
97059701Seric 	(void) strcpy(buf, ad->ad_name);
97159701Seric 	(void) strcat(buf, ".db");
97259673Seric 	db = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
97359673Seric 	if (db == NULL)
97459673Seric 	{
97559701Seric 		syserr("hash_arebuild: cannot create %s", buf);
97659673Seric 		return;
97759673Seric 	}
97859673Seric 	ad->ad_ndbp = db;
97959701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
98059673Seric 
98159673Seric 	/* read and store the aliases */
98259733Seric 	readaliases(ad, fp, automatic, e);
98359673Seric }
98459673Seric 
98559673Seric 
98659673Seric /*
98759673Seric **  HASH_ACLOSE -- add distinguished entries and close the database
98859673Seric */
98959673Seric 
99059673Seric void
99159673Seric hash_aclose(ad, e)
99259673Seric 	ALIASDB *ad;
99359673Seric 	ENVELOPE *e;
99459673Seric {
99559697Seric 	if (tTd(27, 9))
99659697Seric 		printf("hash_aclose(%x)\n", ad->ad_flags);
99759697Seric 
99859673Seric 	if (bitset(ADF_WRITABLE, ad->ad_flags))
99959673Seric 	{
100059673Seric 		/* write out the distinguished alias */
100159673Seric 		hash_astore(ad, "@", "@", e);
100259673Seric 	}
100359673Seric 
100459673Seric 	if (ad->ad_ndbp->close(ad->ad_ndbp) != 0)
100559673Seric 		syserr("readaliases: db close failure");
100659673Seric }
100759673Seric 
100859673Seric #endif
1009292Seric /*
101059673Seric **  STAB (Symbol Table) Modules
101159673Seric */
101259673Seric 
101359673Seric 
101459673Seric /*
101559673Seric **  STAB_ALOOKUP -- look up alias in symbol table
101659673Seric */
101759673Seric 
101859673Seric char *
101959673Seric stab_alookup(ad, name, e)
102059673Seric 	register ALIASDB *ad;
102159673Seric 	char *name;
102259673Seric 	ENVELOPE *e;
102359673Seric {
102459673Seric 	register STAB *s;
102559673Seric 
102659697Seric 	if (tTd(27, 20))
102759697Seric 		printf("stab_lookup(%s)\n", name);
102859697Seric 
102959673Seric 	s = stab(name, ST_ALIAS, ST_FIND);
103059673Seric 	if (s != NULL)
103159673Seric 		return (s->s_alias);
103259673Seric 	return (NULL);
103359673Seric }
103459673Seric 
103559673Seric 
103659673Seric /*
103759673Seric **  STAB_ASTORE -- store in symtab (actually using during init, not rebuild)
103859673Seric */
103959673Seric 
104059673Seric void
104159673Seric stab_astore(ad, lhs, rhs, e)
104259673Seric 	register ALIASDB *ad;
104359673Seric 	char *lhs;
104459673Seric 	char *rhs;
104559673Seric 	ENVELOPE *e;
104659673Seric {
104759673Seric 	register STAB *s;
104859673Seric 
104959673Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
105059673Seric 	s->s_alias = newstr(rhs);
105159673Seric }
105259673Seric 
105359673Seric 
105459673Seric /*
105559673Seric **  STAB_AINIT -- initialize (reads data file)
105659673Seric */
105759673Seric 
105859673Seric bool
105959673Seric stab_ainit(ad, e)
106059673Seric 	register ALIASDB *ad;
106159673Seric 	ENVELOPE *e;
106259673Seric {
106359673Seric 	FILE *af;
106459673Seric 
106559697Seric 	if (tTd(27, 2))
106659697Seric 		printf("stab_ainit(%s)\n", ad->ad_name);
106759697Seric 
106859673Seric 	af = fopen(ad->ad_name, "r");
106959673Seric 	if (af == NULL)
107059673Seric 		return FALSE;
107159673Seric 
107259733Seric 	readaliases(ad, af, TRUE, e);
107359673Seric }
107459673Seric 
107559673Seric 
107659673Seric /*
107759673Seric **  STAB_AREBUILD -- rebuild alias file
107859673Seric */
107959673Seric 
108059673Seric void
108159733Seric stab_arebuild(ad, fp, automatic, e)
108259673Seric 	ALIASDB *ad;
108359673Seric 	FILE *fp;
108459733Seric 	int automatic;
108559673Seric 	ENVELOPE *e;
108659673Seric {
108759697Seric 	if (tTd(27, 2))
108859697Seric 		printf("stab_arebuild(%s)\n", ad->ad_name);
108959697Seric 
109059701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
109159673Seric }
109259673Seric 
109359673Seric 
109459673Seric /*
109559673Seric **  STAB_ACLOSE -- close symbol table (???)
109659673Seric */
109759673Seric 
109859673Seric void
109959673Seric stab_aclose(ad, e)
110059673Seric 	ALIASDB *ad;
110159673Seric 	ENVELOPE *e;
110259673Seric {
110359673Seric 	/* ignore it */
110459673Seric }
110559673Seric /*
110659673Seric **  NIS Modules
110759673Seric */
110859673Seric 
110959724Seric #ifdef NIS_ALIASES
111059673Seric 
111159673Seric /*
111259673Seric **  NIS_ALOOKUP
111359673Seric */
111459673Seric 
111559673Seric char *
111659673Seric nis_alookup(ad, name, e)
111759673Seric 	ALIASDB *ad;
111859673Seric 	char *name;
111959673Seric 	ENVELOPE *e;
112059673Seric {
112159673Seric 	auto char *vp;
112259673Seric 	auto int vsize;
112359756Seric 	int yperr;
112459756Seric 	int keylen;
112559673Seric 
112659697Seric 	if (tTd(27, 20))
112759697Seric 		printf("nis_lookup(%s)\n", name);
112859697Seric 
112959756Seric 	keylen = strlen(name);
113059756Seric 	yperr = yp_match(ad->ad_domain, ad->ad_name, name, keylen,
113159756Seric 			&vp, &vsize);
113259756Seric 	if (yperr == YPERR_KEY)
113359756Seric 		yperr = yp_match(ad->ad_domain, ad->ad_name, name, ++keylen,
113459756Seric 				&vp, &vsize);
113559756Seric 	if (yperr == 0)
113659756Seric 		return vp;
113759756Seric 
113859756Seric 	if (tTd(27, 10))
113959756Seric 		printf("nis_alookup: yp_match(%s, %s, %s) => %s\n",
114059756Seric 			ad->ad_domain, ad->ad_name, name, yperr_string(yperr));
114159756Seric 	if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
114259756Seric 		ad->ad_flags &= ~ADF_VALID;
114359756Seric 	return NULL;
114459673Seric }
114559673Seric 
114659673Seric /*
114759673Seric **  NIS_ASTORE
114859673Seric */
114959673Seric 
115059673Seric void
115159673Seric nis_astore(ad, lhs, rhs, e)
115259673Seric 	ALIASDB *ad;
115359673Seric 	char *lhs;
115459673Seric 	char *rhs;
115559673Seric 	ENVELOPE *e;
115659673Seric {
115759673Seric 	/* nothing */
115859673Seric }
115959673Seric 
116059673Seric /*
116159673Seric **  NIS_AINIT
116259673Seric */
116359673Seric 
116459673Seric bool
116559673Seric nis_ainit(ad, e)
116659673Seric 	ALIASDB *ad;
116759673Seric 	ENVELOPE *e;
116859673Seric {
116959673Seric 	register char *p;
117059756Seric 	int yperr;
117159756Seric 	auto char *vp;
117259756Seric 	auto int vsize;
117359673Seric 
117459697Seric 	if (tTd(27, 2))
117559697Seric 		printf("nis_ainit(%s)\n", ad->ad_name);
117659697Seric 
117759673Seric 	p = strchr(ad->ad_name, '@');
117859673Seric 	if (p != NULL)
117959673Seric 	{
118059673Seric 		*p++ = '\0';
118159673Seric 		if (*p != '\0')
118259673Seric 			ad->ad_domain = p;
118359673Seric 	}
118459673Seric 	if (ad->ad_domain == NULL)
118559673Seric 		yp_get_default_domain(&ad->ad_domain);
118659673Seric 
118759673Seric 	if (*ad->ad_name == '\0')
118859673Seric 		ad->ad_name = "mail.aliases";
118959673Seric 
119059756Seric 	yperr = yp_match(ad->ad_domain, ad->ad_name, "@", 1,
119159756Seric 			&vp, &vsize);
119259756Seric 	if (tTd(27, 10))
119359756Seric 		printf("nis_ainit: yp_match(%s, %s) => %s\n",
119459756Seric 			ad->ad_domain, ad->ad_name, yperr_string(yperr));
119559756Seric 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
119659756Seric 		return TRUE;
119759756Seric 	return FALSE;
119859673Seric }
119959673Seric 
120059673Seric /*
120159673Seric **  NIS_AREBUILD
120259673Seric */
120359673Seric 
120459673Seric void
120559733Seric nis_arebuild(ad, fp, automatic, e)
120659673Seric 	ALIASDB *ad;
120759673Seric 	FILE *fp;
120859733Seric 	int automatic;
120959673Seric 	ENVELOPE *e;
121059673Seric {
121159697Seric 	if (tTd(27, 2))
121259697Seric 		printf("nis_arebuild(%s)\n", ad->ad_name);
121359673Seric }
121459673Seric 
121559673Seric 
121659673Seric /*
121759673Seric **  NIS_ACLOSE
121859673Seric */
121959673Seric 
122059673Seric void
122159673Seric nis_aclose(ad, e)
122259673Seric 	ALIASDB *ad;
122359673Seric 	ENVELOPE *e;
122459673Seric {
122559673Seric 	/* nothing */
122659673Seric }
122759673Seric 
122859724Seric #endif /* NIS_ALIASES */
122959673Seric /*
123059673Seric **  Implicit Modules
123158059Seric **
123259673Seric **	Tries several types.  For back compatibility.
123358059Seric */
123458059Seric 
123559673Seric /*
123659673Seric **  IMPL_ALOOKUP -- lookup in best open database
123759673Seric */
123858059Seric 
123959673Seric char *
124059673Seric impl_alookup(ad, name, e)
124159673Seric 	ALIASDB *ad;
124259673Seric 	char *name;
124359673Seric 	ENVELOPE *e;
124458059Seric {
124559697Seric 	if (tTd(27, 20))
124659697Seric 		printf("impl_lookup(%s)\n", name);
124759697Seric 
124859673Seric #ifdef NEWDB
124959673Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
125059673Seric 		return hash_alookup(ad, name, e);
125159673Seric #endif
125259673Seric #ifdef NDBM
125359673Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
125459673Seric 		return ndbm_alookup(ad, name, e);
125559673Seric #endif
125659673Seric 	return stab_alookup(ad, name, e);
125759673Seric }
125859673Seric 
125959673Seric /*
126059673Seric **  IMPL_ASTORE -- store in open databases
126159673Seric */
126259673Seric 
126359673Seric void
126459673Seric impl_astore(ad, lhs, rhs, e)
126559673Seric 	ALIASDB *ad;
126659673Seric 	char *lhs;
126759673Seric 	char *rhs;
126859673Seric 	ENVELOPE *e;
126959673Seric {
127059673Seric #ifdef NEWDB
127159673Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
127259673Seric 		hash_astore(ad, lhs, rhs, e);
127359673Seric #endif
127459673Seric #ifdef NDBM
127559673Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
127659673Seric 		ndbm_astore(ad, lhs, rhs, e);
127759673Seric #endif
127859673Seric 	stab_astore(ad, lhs, rhs, e);
127959673Seric }
128059673Seric 
128159673Seric /*
128259673Seric **  IMPL_AINIT -- implicit database lookup
128359673Seric */
128459673Seric 
128559673Seric bool
128659673Seric impl_ainit(ad, e)
128759673Seric 	ALIASDB *ad;
128859673Seric 	ENVELOPE *e;
128959673Seric {
129059733Seric 	struct stat stb;
129159733Seric 
129259697Seric 	if (tTd(27, 2))
129359697Seric 		printf("impl_ainit(%s)\n", ad->ad_name);
129459697Seric 
129559733Seric 	if (stat(ad->ad_name, &stb) < 0)
129659733Seric 	{
129759733Seric 		/* no alias file at all */
129859733Seric 		return FALSE;
129959733Seric 	}
130059733Seric 
130159673Seric #ifdef NEWDB
130259697Seric 	ad->ad_flags |= ADF_IMPLHASH;
130359673Seric 	if (hash_ainit(ad, e))
130458059Seric 	{
130559697Seric 		return TRUE;
130659673Seric 	}
130759697Seric 	ad->ad_flags &= ~ADF_IMPLHASH;
130859673Seric #endif
130959673Seric #ifdef NDBM
131059697Seric 	ad->ad_flags |= ADF_IMPLNDBM;
131159673Seric 	if (ndbm_ainit(ad, e))
131259673Seric 	{
131359697Seric 		return TRUE;
131459673Seric 	}
131559697Seric 	ad->ad_flags &= ~ADF_IMPLNDBM;
131659673Seric #endif
131758059Seric 
131859733Seric 	if (Verbose)
131959733Seric 		message("WARNING: cannot open alias database %s", ad->ad_name);
132059733Seric 
132159673Seric 	if (stab_ainit(ad, e))
132259673Seric 	{
132359697Seric 		return TRUE;
132459673Seric 	}
132559697Seric 
132659697Seric 	return FALSE;
132759673Seric }
132858059Seric 
132959673Seric /*
133059673Seric **  IMPL_AREBUILD -- rebuild alias database
133159673Seric */
133258059Seric 
133359673Seric void
133459733Seric impl_arebuild(ad, fp, automatic, e)
133559673Seric 	ALIASDB *ad;
133659673Seric 	FILE *fp;
133759733Seric 	int automatic;
133859673Seric 	ENVELOPE *e;
133959673Seric {
134059673Seric #ifdef NEWDB
134159673Seric 	DB *ndb;
134259673Seric 	char buf[MAXNAME];
134359697Seric #endif
134459673Seric 
134559697Seric 	if (tTd(27, 2))
134659697Seric 		printf("impl_arebuild(%s)\n", ad->ad_name);
134759697Seric 
134859697Seric #ifdef NEWDB
134959673Seric 	(void) strcpy(buf, ad->ad_name);
135059673Seric 	(void) strcat(buf, ".db");
135159673Seric 	ndb = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
135259673Seric 	if (ndb == NULL)
135358059Seric 	{
135459673Seric 		syserr("rebuildaliases: cannot create %s", buf);
135558059Seric 	}
135659673Seric 	else
135759673Seric 	{
135859673Seric 		ad->ad_ndbp = ndb;
135959673Seric 		ad->ad_flags |= ADF_IMPLHASH;
136059673Seric #if defined(NDBM) && defined(YPCOMPAT)
136159673Seric 		if (access("/var/yp/Makefile", R_OK) != 0)
136259673Seric #endif
136359697Seric 			goto readem;
136459673Seric 	}
136559673Seric #endif
136659673Seric 
136759673Seric #ifdef NDBM
136859673Seric 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
136959673Seric 	if (ad->ad_dbp == NULL)
137059673Seric 	{
137159673Seric 		syserr("rebuildaliases: cannot create %s.{pag,dir}",
137259673Seric 			ad->ad_name);
137359673Seric 	}
137459673Seric 	else
137559673Seric 	{
137659673Seric 		ad->ad_flags |= ADF_IMPLNDBM;
137759673Seric 	}
137859673Seric #endif
137959673Seric 
138059673Seric 	if (!bitset(ADF_IMPLHASH|ADF_IMPLNDBM, ad->ad_flags))
138159673Seric 		return;
138259673Seric 
138359697Seric   readem:
138459701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
138559673Seric 
138659673Seric 	/* read and store aliases */
138759733Seric 	readaliases(ad, fp, automatic, e);
138858059Seric }
138958059Seric 
139059673Seric 
139159673Seric /*
139259673Seric **  IMPL_ACLOSE -- close any open database(s)
139359673Seric */
139459673Seric 
139559673Seric void
139659673Seric impl_aclose(ad, e)
139759673Seric 	ALIASDB *ad;
139859673Seric 	ENVELOPE *e;
139959673Seric {
140059673Seric #ifdef NEWDB
140159697Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
140259697Seric 		hash_aclose(ad, e);
140359673Seric #endif
140459673Seric 
140559673Seric #ifdef NDBM
140659697Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
140759697Seric 		ndbm_aclose(ad, e);
140859673Seric #endif
140959673Seric }
141058059Seric /*
141159673Seric **  SETUPALIASES -- set up aliases classes
141259673Seric */
141359673Seric 
141459673Seric #ifdef NEWDB
141559673Seric ALIASCLASS	HashAClass =
141659673Seric {
141759673Seric 	"hash",		hash_alookup,	hash_astore,
141859673Seric 	hash_ainit,	hash_arebuild,	hash_aclose,
141959673Seric 	ACF_BUILDABLE
142059673Seric };
142159673Seric #endif
142259673Seric 
142359673Seric #ifdef NDBM
142459673Seric ALIASCLASS	DbmAClass =
142559673Seric {
142659673Seric 	"dbm",		ndbm_alookup,	ndbm_astore,
142759673Seric 	ndbm_ainit,	ndbm_arebuild,	ndbm_aclose,
142859673Seric 	ACF_BUILDABLE
142959673Seric };
143059673Seric #endif
143159673Seric 
143259724Seric #ifdef NIS_ALIASES
143359673Seric ALIASCLASS	NisAClass =
143459673Seric {
143559673Seric 	"nis",		nis_alookup,	nis_astore,
143659673Seric 	nis_ainit,	nis_arebuild,	nis_aclose,
143759673Seric 	0
143859673Seric };
143959673Seric #endif
144059673Seric 
144159673Seric ALIASCLASS	StabAClass =
144259673Seric {
144359673Seric 	"stab",		stab_alookup,	stab_astore,
144459673Seric 	stab_ainit,	stab_arebuild,	stab_aclose,
144559673Seric 	0
144659673Seric };
144759673Seric 
144859673Seric ALIASCLASS	ImplAClass =
144959673Seric {
145059673Seric 	"implicit",	impl_alookup,	impl_astore,
145159673Seric 	impl_ainit,	impl_arebuild,	impl_aclose,
145259673Seric 	ACF_BUILDABLE
145359673Seric };
145459673Seric 
145559673Seric setupaliases()
145659673Seric {
145759673Seric 	register STAB *s;
145859673Seric 
145959673Seric #ifdef NEWDB
146059673Seric 	s = stab("hash", ST_ALIASCLASS, ST_ENTER);
146159673Seric 	s->s_aliasclass = &HashAClass;
146259673Seric #endif
146359673Seric 
146459673Seric #ifdef NDBM
146559673Seric 	s = stab("dbm", ST_ALIASCLASS, ST_ENTER);
146659673Seric 	s->s_aliasclass = &DbmAClass;
146759673Seric #endif
146859673Seric 
146959724Seric #ifdef NIS_ALIASES
147059673Seric 	s = stab("nis", ST_ALIASCLASS, ST_ENTER);
147159673Seric 	s->s_aliasclass = &NisAClass;
147259673Seric #endif
147359673Seric 
147459673Seric #if !defined(NEWDB) && !defined(NDBM)
147559673Seric 	s = stab("stab", ST_ALIASCLASS, ST_ENTER);
147659673Seric 	s->s_aliasclass = &StabAClass;
147759673Seric #endif
147859673Seric 
147959673Seric 	s = stab("implicit", ST_ALIASCLASS, ST_ENTER);
148059673Seric 	s->s_aliasclass = &ImplAClass;
148159673Seric }
148259673Seric /*
1483292Seric **  FORWARD -- Try to forward mail
1484292Seric **
1485292Seric **	This is similar but not identical to aliasing.
1486292Seric **
1487292Seric **	Parameters:
14884314Seric **		user -- the name of the user who's mail we would like
14894314Seric **			to forward to.  It must have been verified --
14904314Seric **			i.e., the q_home field must have been filled
14914314Seric **			in.
14924999Seric **		sendq -- a pointer to the head of the send queue to
14934999Seric **			put this user's aliases in.
1494292Seric **
1495292Seric **	Returns:
14964098Seric **		none.
1497292Seric **
1498292Seric **	Side Effects:
14993185Seric **		New names are added to send queues.
1500292Seric */
1501292Seric 
150255012Seric forward(user, sendq, e)
15032966Seric 	ADDRESS *user;
15044999Seric 	ADDRESS **sendq;
150555012Seric 	register ENVELOPE *e;
1506292Seric {
150757136Seric 	char *pp;
150857136Seric 	char *ep;
15094069Seric 
15107671Seric 	if (tTd(27, 1))
15114098Seric 		printf("forward(%s)\n", user->q_paddr);
15124098Seric 
15134594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
15144098Seric 		return;
15154314Seric 	if (user->q_home == NULL)
151658059Seric 	{
151758151Seric 		syserr("554 forward: no home");
151858059Seric 		user->q_home = "/nosuchdirectory";
151958059Seric 	}
15204069Seric 
15214069Seric 	/* good address -- look for .forward file in home */
152255012Seric 	define('z', user->q_home, e);
152357136Seric 	define('u', user->q_user, e);
152457136Seric 	define('h', user->q_host, e);
152557136Seric 	if (ForwardPath == NULL)
152658050Seric 		ForwardPath = newstr("\201z/.forward");
152757136Seric 
152857136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
152957136Seric 	{
153058247Seric 		int err;
153157232Seric 		char buf[MAXPATHLEN+1];
153257136Seric 
153357136Seric 		ep = strchr(pp, ':');
153457136Seric 		if (ep != NULL)
153557136Seric 			*ep = '\0';
153657136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
153757136Seric 		if (ep != NULL)
153857136Seric 			*ep++ = ':';
153957136Seric 		if (tTd(27, 3))
154057136Seric 			printf("forward: trying %s\n", buf);
154158247Seric 		err = include(buf, TRUE, user, sendq, e);
154258247Seric 		if (err == 0)
154357136Seric 			break;
154458247Seric 		if (transienterror(err))
154558247Seric 		{
154658247Seric 			/* we have to suspend this message */
154759563Seric 			if (tTd(27, 2))
154859563Seric 				printf("forward: transient error on %s\n", buf);
154959563Seric #ifdef LOG
155059563Seric 			if (LogLevel > 2)
155159624Seric 				syslog(LOG_ERR, "%s: forward %s: transient error: %s",
155259624Seric 					e->e_id, buf, errstring(err));
155359563Seric #endif
155459611Seric 			message("%s: %s: message queued", buf, errstring(err));
155558247Seric 			user->q_flags |= QQUEUEUP|QDONTSEND;
155658247Seric 			return;
155758247Seric 		}
155857136Seric 	}
1559292Seric }
1560