xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 59701)
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*59701Seric static char sccsid[] = "@(#)alias.c	6.41 (Berkeley) 05/03/93 (with NEWDB and NDBM)";
2951756Seric #else
30*59701Seric static char sccsid[] = "@(#)alias.c	6.41 (Berkeley) 05/03/93 (with NEWDB)";
3157736Seric #endif
3257736Seric #else
3356845Seric #ifdef NDBM
34*59701Seric static char sccsid[] = "@(#)alias.c	6.41 (Berkeley) 05/03/93 (with NDBM)";
3533728Sbostic #else
36*59701Seric static char sccsid[] = "@(#)alias.c	6.41 (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 
25159697Seric 	if (tTd(27, 8))
25259697Seric 		printf("setalias(%s)\n", spec);
25359697Seric 
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];
32159697Seric 
32259697Seric 		if (tTd(27, 2))
32359697Seric 			printf("initaliases(%s:%s)\n",
32459697Seric 				ad->ad_class->ac_name, ad->ad_name);
32559697Seric 
32659673Seric 		if (rebuild)
32750576Seric 		{
32859673Seric 			rebuildaliases(ad, FALSE, e);
32950576Seric 		}
33059673Seric 		else
33157249Seric 		{
33259697Seric 			if (ad->ad_class->ac_init(ad, e))
33359697Seric 				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 
35359697Seric 	if (tTd(27, 3))
35459697Seric 		printf("aliaswait\n");
35559697Seric 
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 
36759697Seric 			if (tTd(27, 2))
36859697Seric 				printf("aliaswait: sleeping\n");
36959697Seric 
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 */
474*59701Seric 	if (bitset(ADF_VALID, ad->ad_flags))
475*59701Seric 		ad->ad_class->ac_close(ad, e);
47659673Seric 
47759673Seric 	/* restore the old signal */
47859673Seric 	(void) signal(SIGINT, oldsigint);
4794157Seric }
4804157Seric /*
4814157Seric **  READALIASES -- read and process the alias file.
4824157Seric **
4834157Seric **	This routine implements the part of initaliases that occurs
4844157Seric **	when we are not going to use the DBM stuff.
4854157Seric **
4864157Seric **	Parameters:
48759673Seric **		ad -- the alias database descriptor.
48859673Seric **		af -- file to read the aliases from.
48959673Seric **		e -- the current alias file.
4904157Seric **
4914157Seric **	Returns:
4924157Seric **		none.
4934157Seric **
4944157Seric **	Side Effects:
4954157Seric **		Reads aliasfile into the symbol table.
4964157Seric **		Optionally, builds the .dir & .pag files.
4974157Seric */
4984157Seric 
4994157Seric static
50059673Seric readaliases(ad, af, e)
50159673Seric 	register ALIASDB *ad;
50259673Seric 	FILE *af;
50355012Seric 	register ENVELOPE *e;
5044157Seric {
5054098Seric 	register char *p;
5064098Seric 	char *rhs;
5074098Seric 	bool skipping;
50859673Seric 	long naliases, bytes, longest;
5094098Seric 	ADDRESS al, bl;
5104106Seric 	register STAB *s;
5119368Seric 	char line[BUFSIZ];
5124098Seric 
5134314Seric 	/*
5144314Seric 	**  Read and interpret lines
5154314Seric 	*/
5164314Seric 
51759673Seric 	FileName = ad->ad_name;
5189368Seric 	LineNumber = 0;
5194322Seric 	naliases = bytes = longest = 0;
5204098Seric 	skipping = FALSE;
5214098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5224098Seric 	{
5234322Seric 		int lhssize, rhssize;
5244322Seric 
5259368Seric 		LineNumber++;
52656795Seric 		p = strchr(line, '\n');
52725278Seric 		if (p != NULL)
52825278Seric 			*p = '\0';
5294098Seric 		switch (line[0])
5304098Seric 		{
5314098Seric 		  case '#':
5324098Seric 		  case '\0':
5334098Seric 			skipping = FALSE;
5344098Seric 			continue;
5354065Seric 
5364098Seric 		  case ' ':
5374098Seric 		  case '\t':
5384098Seric 			if (!skipping)
53958151Seric 				syserr("554 Non-continuation line starts with space");
5404098Seric 			skipping = TRUE;
5414097Seric 			continue;
5424098Seric 		}
5434098Seric 		skipping = FALSE;
5441874Seric 
5454314Seric 		/*
5464314Seric 		**  Process the LHS
54757736Seric 		**	Find the colon separator, and parse the address.
54816898Seric 		**	It should resolve to a local name -- this will
54916898Seric 		**	be checked later (we want to optionally do
55016898Seric 		**	parsing of the RHS first to maximize error
55116898Seric 		**	detection).
5524314Seric 		*/
5534314Seric 
5544098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5554097Seric 			continue;
55616898Seric 		if (*p++ != ':')
5574098Seric 		{
55858151Seric 			syserr("554 missing colon");
5594097Seric 			continue;
5604098Seric 		}
56158333Seric 		if (parseaddr(line, &al, 1, ':', NULL, e) == NULL)
5624098Seric 		{
56358151Seric 			syserr("554 illegal alias name");
56416898Seric 			continue;
5654098Seric 		}
5664314Seric 
5674314Seric 		/*
5684314Seric 		**  Process the RHS.
5694314Seric 		**	'al' is the internal form of the LHS address.
5704314Seric 		**	'p' points to the text of the RHS.
5714314Seric 		*/
5724314Seric 
57358914Seric 		while (isascii(*p) && isspace(*p))
57458914Seric 			p++;
5754098Seric 		rhs = p;
5764098Seric 		for (;;)
5774098Seric 		{
5784098Seric 			register char c;
57958662Seric 			register char *nlp;
5801515Seric 
58158662Seric 			nlp = &p[strlen(p)];
58258662Seric 			if (nlp[-1] == '\n')
58358662Seric 				*--nlp = '\0';
58458662Seric 
58559673Seric 			if (CheckAliases)
5864098Seric 			{
5874157Seric 				/* do parsing & compression of addresses */
58825278Seric 				while (*p != '\0')
5894098Seric 				{
59058333Seric 					auto char *delimptr;
59125278Seric 
59258050Seric 					while ((isascii(*p) && isspace(*p)) ||
59358050Seric 								*p == ',')
5944157Seric 						p++;
59525278Seric 					if (*p == '\0')
59625278Seric 						break;
59758333Seric 					if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL)
59858151Seric 						usrerr("553 %s... bad address", p);
59958333Seric 					p = delimptr;
6004098Seric 				}
6014098Seric 			}
6024157Seric 			else
60315769Seric 			{
60458662Seric 				p = nlp;
60515769Seric 			}
6061515Seric 
6074098Seric 			/* see if there should be a continuation line */
6084106Seric 			c = fgetc(af);
6094106Seric 			if (!feof(af))
6104314Seric 				(void) ungetc(c, af);
6114106Seric 			if (c != ' ' && c != '\t')
6124098Seric 				break;
6134098Seric 
6144098Seric 			/* read continuation line */
6154098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6164098Seric 				break;
6179368Seric 			LineNumber++;
61857135Seric 
61957135Seric 			/* check for line overflow */
62057135Seric 			if (strchr(p, '\n') == NULL)
62157135Seric 			{
62258151Seric 				usrerr("554 alias too long");
62357135Seric 				break;
62457135Seric 			}
6254098Seric 		}
62616898Seric 		if (al.q_mailer != LocalMailer)
62716898Seric 		{
62858151Seric 			syserr("554 cannot alias non-local names");
62916898Seric 			continue;
63016898Seric 		}
6314314Seric 
6324314Seric 		/*
6334314Seric 		**  Insert alias into symbol table or DBM file
6344314Seric 		*/
6354314Seric 
63657381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
63757381Seric 			makelower(al.q_user);
6384322Seric 
63959673Seric 		lhssize = strlen(al.q_user);
64059673Seric 		rhssize = strlen(rhs);
64159673Seric 		ad->ad_class->ac_store(ad, al.q_user, rhs, e);
6424157Seric 
64359673Seric 		if (al.q_paddr != NULL)
64459673Seric 			free(al.q_paddr);
64559673Seric 		if (al.q_host != NULL)
64659673Seric 			free(al.q_host);
64759673Seric 		if (al.q_user != NULL)
64859673Seric 			free(al.q_user);
6494322Seric 
6504322Seric 		/* statistics */
6514322Seric 		naliases++;
6524322Seric 		bytes += lhssize + rhssize;
6534322Seric 		if (rhssize > longest)
6544322Seric 			longest = rhssize;
6551515Seric 	}
65619784Seric 
65759673Seric 	e->e_to = NULL;
65859673Seric 	FileName = NULL;
65959673Seric 	message("%s: %d aliases, longest %d bytes, %d bytes total",
66059673Seric 			ad->ad_name, naliases, longest, bytes);
66159673Seric # ifdef LOG
66259673Seric 	if (LogLevel > 7)
66359673Seric 		syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
66459673Seric 			ad->ad_name, naliases, longest, bytes);
66559673Seric # endif /* LOG */
66659673Seric }
66759673Seric /*
66859673Seric **  NDBM modules
66959673Seric */
67059673Seric 
67159673Seric #ifdef NDBM
67259673Seric 
67359673Seric /*
67459673Seric **  NDBM_ALOOKUP -- look up alias in ndbm file
67559673Seric */
67659673Seric 
67759673Seric char *
67859673Seric ndbm_alookup(ad, name, e)
67959673Seric 	register ALIASDB *ad;
68059673Seric 	char *name;
68159673Seric 	ENVELOPE *e;
68259673Seric {
68359673Seric 	int i;
68459673Seric 	datum rhs, lhs;
68559673Seric 	char keybuf[MAXNAME + 1];
68659673Seric 
68759697Seric 	if (tTd(27, 20))
68859697Seric 		printf("ndbm_lookup(%s)\n", name);
68959697Seric 
69059673Seric 	/* create a key for fetch */
69159673Seric 	i = strlen(name) + 1;
69259673Seric 	if (i > sizeof keybuf)
69359673Seric 		i = sizeof keybuf;
69459673Seric 	bcopy(name, keybuf, i);
69559673Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
69659673Seric 		makelower(keybuf);
69759673Seric 
69859673Seric 	lhs.dsize = i;
69959673Seric 	lhs.dptr = keybuf;
70059673Seric 	rhs = dbm_fetch((DBM *) ad->ad_dbp, lhs);
70159673Seric 	return (rhs.dptr);
70259673Seric }
70359673Seric 
70459673Seric 
70559673Seric /*
70659673Seric **  NDBM_ASTORE -- store a datum in the database
70759673Seric */
70859673Seric 
70959673Seric void
71059673Seric ndbm_astore(ad, lhs, rhs, e)
71159673Seric 	register ALIASDB *ad;
71259673Seric 	char *lhs;
71359673Seric 	char *rhs;
71459673Seric 	ENVELOPE *e;
71559673Seric {
71659673Seric 	datum key;
71759673Seric 	datum data;
71859673Seric 	int stat;
71959673Seric 
72059697Seric 	key.dsize = strlen(lhs) + 1;
72159673Seric 	key.dptr = lhs;
72259673Seric 
72359697Seric 	data.dsize = strlen(rhs) + 1;
72459673Seric 	data.dptr = rhs;
72559673Seric 
72659673Seric 	stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_INSERT);
72759673Seric 	if (stat > 0)
72819784Seric 	{
72959673Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
73059673Seric 		stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_REPLACE);
73159673Seric 	}
73259673Seric 	if (stat != 0)
73359673Seric 		syserr("readaliases: dbm put (%s)", lhs);
73459673Seric }
73519784Seric 
73659673Seric 
73759673Seric /*
73859673Seric **  NDBM_AINIT -- initialize DBM database
73959673Seric */
74059673Seric 
74159673Seric bool
74259673Seric ndbm_ainit(ad, e)
74359673Seric 	register ALIASDB *ad;
74459673Seric 	ENVELOPE *e;
74559673Seric {
74659673Seric 	char buf[MAXNAME];
74759673Seric 
74859697Seric 	if (tTd(27, 2))
74959697Seric 		printf("ndbm_ainit(%s)\n", ad->ad_name);
75059697Seric 
75159673Seric 	/* open the database */
75259673Seric 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDONLY, DBMMODE);
75359673Seric 	if (ad->ad_dbp == NULL)
75459673Seric 		return FALSE;
75559673Seric 
75659673Seric 	/* wait for @:@ to appear */
75759673Seric 	aliaswait(ad, ".pag", e);
75859673Seric 
75959673Seric 	return TRUE;
76059673Seric }
76159673Seric 
76259673Seric 
76359673Seric /*
76459673Seric **  NDBM_AREBUILD -- rebuild hash database
76559673Seric */
76659673Seric 
76759673Seric void
76859673Seric ndbm_arebuild(ad, fp, e)
76959673Seric 	register ALIASDB *ad;
77059673Seric 	FILE *fp;
77159673Seric 	ENVELOPE *e;
77259673Seric {
77359673Seric 	register DBM *db;
77459673Seric 	int i;
77559673Seric 	char buf[MAXNAME];
77659673Seric 
77759697Seric 	if (tTd(27, 2))
77859697Seric 		printf("ndbm_arebuild(%s)\n", ad->ad_name);
77959697Seric 
78059673Seric 	db = dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
78159673Seric 	if (db == NULL)
78259673Seric 	{
783*59701Seric 		syserr("ndbm_arebuild: cannot create %s", buf);
78459673Seric 		return;
78559673Seric 	}
78659673Seric 	ad->ad_dbp = (void *) db;
787*59701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
78859673Seric 
78959673Seric 	/* read and store the aliases */
79059673Seric 	readaliases(ad, fp, e);
79159673Seric }
79259673Seric 
79359673Seric /*
79459673Seric **  NDBM_ACLOSE -- close the database
79559673Seric */
79659673Seric 
79759673Seric void
79859673Seric ndbm_aclose(ad, e)
79959673Seric 	register ALIASDB  *ad;
80059673Seric 	ENVELOPE *e;
80159673Seric {
80259673Seric 	if (bitset(ADF_WRITABLE, ad->ad_flags))
80359673Seric 	{
80458059Seric #ifdef YPCOMPAT
80559673Seric 		char buf[200];
80658846Seric 
80759673Seric 		(void) sprintf(buf, "%010ld", curtime());
80859673Seric 		ndbm_astore(ad, "YP_LAST_MODIFIED", buf, e);
80959673Seric 
81059673Seric 		(void) myhostname(buf, sizeof buf);
81159673Seric 		ndbm_astore(ad, "YP_MASTER_NAME", buf, e);
81258059Seric #endif
81319784Seric 
81459673Seric 		/* write out the distinguished alias */
81559673Seric 		ndbm_astore(ad, "@", "@", e);
81619784Seric 	}
81759673Seric 	dbm_close((DBM *) ad->ad_dbp);
81859673Seric }
81919784Seric 
82059673Seric #endif
82159673Seric /*
82259673Seric **  HASH (NEWDB) Modules
82359673Seric */
82459673Seric 
82559673Seric #ifdef NEWDB
82659673Seric 
82759673Seric /*
82859673Seric **  HASH_ALOOKUP -- look up alias in hash file
82959673Seric */
83059673Seric 
83159673Seric char *
83259673Seric hash_alookup(ad, name, e)
83359673Seric 	register ALIASDB *ad;
83459673Seric 	char *name;
83559673Seric 	ENVELOPE *e;
83659673Seric {
83759673Seric 	int i;
83859673Seric 	DBT rhs, lhs;
83959673Seric 	int s;
84059673Seric 	char keybuf[MAXNAME + 1];
84159673Seric 
84259697Seric 	if (tTd(27, 20))
84359697Seric 		printf("hash_alookup(%s)\n", name);
84459697Seric 
84559673Seric 	/* create a key for fetch */
84659673Seric 	i = strlen(name) + 1;
84759673Seric 	if (i > sizeof keybuf)
84859673Seric 		i = sizeof keybuf;
84959673Seric 	bcopy(name, keybuf, i);
85059673Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
85159673Seric 		makelower(keybuf);
85259673Seric 
85359673Seric 	lhs.size = i;
85459673Seric 	lhs.data = keybuf;
85559673Seric 	i = ad->ad_ndbp->get(ad->ad_ndbp, &lhs, &rhs, 0);
85659673Seric 	if (i == 0)
85759673Seric 		return (rhs.data);
85859673Seric 	return (NULL);
859292Seric }
86059673Seric 
86159673Seric 
86259673Seric /*
86359673Seric **  HASH_ASTORE -- store a datum in the database
86459673Seric */
86559673Seric 
86659673Seric void
86759673Seric hash_astore(ad, lhs, rhs, e)
86859673Seric 	register ALIASDB *ad;
86959673Seric 	char *lhs;
87059673Seric 	char *rhs;
87159673Seric 	ENVELOPE *e;
87259673Seric {
87359673Seric 	int stat;
87459673Seric 	DBT key;
87559673Seric 	DBT data;
87659673Seric 
87759697Seric 	if (tTd(27, 20))
87859697Seric 		printf("hash_astore(%s, %s)\n", lhs, rhs);
87959697Seric 
88059697Seric 	key.size = strlen(lhs) + 1;
88159673Seric 	key.data = lhs;
88259673Seric 
88359697Seric 	data.size = strlen(rhs) + 1;
88459673Seric 	data.data = rhs;
88559673Seric 
88659673Seric 	stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, R_NOOVERWRITE);
88759673Seric 	if (stat > 0)
88859673Seric 	{
88959673Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
89059673Seric 		stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, 0);
89159673Seric 	}
89259673Seric 	if (stat != 0)
89359673Seric 		syserr("readaliases: db put (%s)", lhs);
89459673Seric }
89559673Seric 
89659673Seric 
89759673Seric /*
89859673Seric **  HASH_AINIT -- initialize hash database
89959673Seric */
90059673Seric 
90159673Seric bool
90259673Seric hash_ainit(ad, e)
90359673Seric 	register ALIASDB *ad;
90459673Seric 	ENVELOPE *e;
90559673Seric {
90659673Seric 	char buf[MAXNAME];
90759673Seric 
90859697Seric 	if (tTd(27, 2))
90959697Seric 		printf("hash_ainit(%s)\n", ad->ad_name);
91059697Seric 
91159673Seric 	/* open the database */
91259673Seric 	(void) strcpy(buf, ad->ad_name);
91359673Seric 	(void) strcat(buf, ".db");
91459673Seric 	ad->ad_ndbp = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
91559673Seric 	if (ad->ad_ndbp == NULL)
91659673Seric 		return FALSE;
91759673Seric 
91859673Seric 	/* wait for @:@ to appear */
91959673Seric 	aliaswait(ad, ".db", e);
92059673Seric 	return TRUE;
92159673Seric }
92259673Seric 
92359673Seric 
92459673Seric /*
92559673Seric **  HASH_AREBUILD -- rebuild hash database
92659673Seric */
92759673Seric 
92859673Seric void
92959673Seric hash_arebuild(ad, fp, e)
93059673Seric 	register ALIASDB *ad;
93159673Seric 	FILE *fp;
93259673Seric 	ENVELOPE *e;
93359673Seric {
93459673Seric 	register DB *db;
93559673Seric 	char buf[MAXNAME];
93659673Seric 
93759697Seric 	if (tTd(27, 2))
93859697Seric 		printf("hash_arebuild(%s)\n", ad->ad_name);
93959697Seric 
940*59701Seric 	(void) strcpy(buf, ad->ad_name);
941*59701Seric 	(void) strcat(buf, ".db");
94259673Seric 	db = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
94359673Seric 	if (db == NULL)
94459673Seric 	{
945*59701Seric 		syserr("hash_arebuild: cannot create %s", buf);
94659673Seric 		return;
94759673Seric 	}
94859673Seric 	ad->ad_ndbp = db;
949*59701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
95059673Seric 
95159673Seric 	/* read and store the aliases */
95259673Seric 	readaliases(ad, fp, e);
95359673Seric }
95459673Seric 
95559673Seric 
95659673Seric /*
95759673Seric **  HASH_ACLOSE -- add distinguished entries and close the database
95859673Seric */
95959673Seric 
96059673Seric void
96159673Seric hash_aclose(ad, e)
96259673Seric 	ALIASDB *ad;
96359673Seric 	ENVELOPE *e;
96459673Seric {
96559697Seric 	if (tTd(27, 9))
96659697Seric 		printf("hash_aclose(%x)\n", ad->ad_flags);
96759697Seric 
96859673Seric 	if (bitset(ADF_WRITABLE, ad->ad_flags))
96959673Seric 	{
97059673Seric 		/* write out the distinguished alias */
97159673Seric 		hash_astore(ad, "@", "@", e);
97259673Seric 	}
97359673Seric 
97459673Seric 	if (ad->ad_ndbp->close(ad->ad_ndbp) != 0)
97559673Seric 		syserr("readaliases: db close failure");
97659673Seric }
97759673Seric 
97859673Seric #endif
979292Seric /*
98059673Seric **  STAB (Symbol Table) Modules
98159673Seric */
98259673Seric 
98359673Seric 
98459673Seric /*
98559673Seric **  STAB_ALOOKUP -- look up alias in symbol table
98659673Seric */
98759673Seric 
98859673Seric char *
98959673Seric stab_alookup(ad, name, e)
99059673Seric 	register ALIASDB *ad;
99159673Seric 	char *name;
99259673Seric 	ENVELOPE *e;
99359673Seric {
99459673Seric 	register STAB *s;
99559673Seric 
99659697Seric 	if (tTd(27, 20))
99759697Seric 		printf("stab_lookup(%s)\n", name);
99859697Seric 
99959673Seric 	s = stab(name, ST_ALIAS, ST_FIND);
100059673Seric 	if (s != NULL)
100159673Seric 		return (s->s_alias);
100259673Seric 	return (NULL);
100359673Seric }
100459673Seric 
100559673Seric 
100659673Seric /*
100759673Seric **  STAB_ASTORE -- store in symtab (actually using during init, not rebuild)
100859673Seric */
100959673Seric 
101059673Seric void
101159673Seric stab_astore(ad, lhs, rhs, e)
101259673Seric 	register ALIASDB *ad;
101359673Seric 	char *lhs;
101459673Seric 	char *rhs;
101559673Seric 	ENVELOPE *e;
101659673Seric {
101759673Seric 	register STAB *s;
101859673Seric 
101959673Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
102059673Seric 	s->s_alias = newstr(rhs);
102159673Seric }
102259673Seric 
102359673Seric 
102459673Seric /*
102559673Seric **  STAB_AINIT -- initialize (reads data file)
102659673Seric */
102759673Seric 
102859673Seric bool
102959673Seric stab_ainit(ad, e)
103059673Seric 	register ALIASDB *ad;
103159673Seric 	ENVELOPE *e;
103259673Seric {
103359673Seric 	FILE *af;
103459673Seric 
103559697Seric 	if (tTd(27, 2))
103659697Seric 		printf("stab_ainit(%s)\n", ad->ad_name);
103759697Seric 
103859673Seric 	af = fopen(ad->ad_name, "r");
103959673Seric 	if (af == NULL)
104059673Seric 	{
104159673Seric 		syserr("554 Can't open %s", ad->ad_name);
104259673Seric 		errno = 0;
104359673Seric 		return FALSE;
104459673Seric 	}
104559673Seric 
104659673Seric 	readaliases(ad, af, e);
104759673Seric }
104859673Seric 
104959673Seric 
105059673Seric /*
105159673Seric **  STAB_AREBUILD -- rebuild alias file
105259673Seric */
105359673Seric 
105459673Seric void
105559673Seric stab_arebuild(ad, fp, e)
105659673Seric 	ALIASDB *ad;
105759673Seric 	FILE *fp;
105859673Seric 	ENVELOPE *e;
105959673Seric {
106059697Seric 	if (tTd(27, 2))
106159697Seric 		printf("stab_arebuild(%s)\n", ad->ad_name);
106259697Seric 
1063*59701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
106459673Seric }
106559673Seric 
106659673Seric 
106759673Seric /*
106859673Seric **  STAB_ACLOSE -- close symbol table (???)
106959673Seric */
107059673Seric 
107159673Seric void
107259673Seric stab_aclose(ad, e)
107359673Seric 	ALIASDB *ad;
107459673Seric 	ENVELOPE *e;
107559673Seric {
107659673Seric 	/* ignore it */
107759673Seric }
107859673Seric /*
107959673Seric **  NIS Modules
108059673Seric */
108159673Seric 
108259673Seric #ifdef NIS
108359673Seric 
108459673Seric /*
108559673Seric **  NIS_ALOOKUP
108659673Seric */
108759673Seric 
108859673Seric char *
108959673Seric nis_alookup(ad, name, e)
109059673Seric 	ALIASDB *ad;
109159673Seric 	char *name;
109259673Seric 	ENVELOPE *e;
109359673Seric {
109459673Seric 	auto char *vp;
109559673Seric 	auto int vsize;
109659673Seric 
109759697Seric 	if (tTd(27, 20))
109859697Seric 		printf("nis_lookup(%s)\n", name);
109959697Seric 
110059673Seric 	if (ypmatch(ad->ad_domain, ad->ad_name, name, strlen(name),
110159673Seric 			&vp, &vsize) != 0)
110259673Seric 		return NULL;
110359673Seric 	return vp;
110459673Seric }
110559673Seric 
110659673Seric /*
110759673Seric **  NIS_ASTORE
110859673Seric */
110959673Seric 
111059673Seric void
111159673Seric nis_astore(ad, lhs, rhs, e)
111259673Seric 	ALIASDB *ad;
111359673Seric 	char *lhs;
111459673Seric 	char *rhs;
111559673Seric 	ENVELOPE *e;
111659673Seric {
111759673Seric 	/* nothing */
111859673Seric }
111959673Seric 
112059673Seric /*
112159673Seric **  NIS_AINIT
112259673Seric */
112359673Seric 
112459673Seric bool
112559673Seric nis_ainit(ad, e)
112659673Seric 	ALIASDB *ad;
112759673Seric 	ENVELOPE *e;
112859673Seric {
112959673Seric 	register char *p;
113059673Seric 	auto char *ypmaster;
113159673Seric 
113259697Seric 	if (tTd(27, 2))
113359697Seric 		printf("nis_ainit(%s)\n", ad->ad_name);
113459697Seric 
113559673Seric 	p = strchr(ad->ad_name, '@');
113659673Seric 	if (p != NULL)
113759673Seric 	{
113859673Seric 		*p++ = '\0';
113959673Seric 		if (*p != '\0')
114059673Seric 			ad->ad_domain = p;
114159673Seric 	}
114259673Seric 	if (ad->ad_domain == NULL)
114359673Seric 		yp_get_default_domain(&ad->ad_domain);
114459673Seric 
114559673Seric 	if (*ad->ad_name == '\0')
114659673Seric 		ad->ad_name = "mail.aliases";
114759673Seric 
114859673Seric 	yperr = yp_master(ad->ad_domain, ad->ad_name, &ypmaster);
114959673Seric 	return (yperr == 0);
115059673Seric }
115159673Seric 
115259673Seric /*
115359673Seric **  NIS_AREBUILD
115459673Seric */
115559673Seric 
115659673Seric void
115759673Seric nis_arebuild(ad, fp, e)
115859673Seric 	ALIASDB *ad;
115959673Seric 	FILE *fp;
116059673Seric 	ENVELOPE *e;
116159673Seric {
116259697Seric 	if (tTd(27, 2))
116359697Seric 		printf("nis_arebuild(%s)\n", ad->ad_name);
116459673Seric }
116559673Seric 
116659673Seric 
116759673Seric /*
116859673Seric **  NIS_ACLOSE
116959673Seric */
117059673Seric 
117159673Seric void
117259673Seric nis_aclose(ad, e)
117359673Seric 	ALIASDB *ad;
117459673Seric 	ENVELOPE *e;
117559673Seric {
117659673Seric 	/* nothing */
117759673Seric }
117859673Seric 
117959673Seric #endif /* NIS */
118059673Seric /*
118159673Seric **  Implicit Modules
118258059Seric **
118359673Seric **	Tries several types.  For back compatibility.
118458059Seric */
118558059Seric 
118659673Seric /*
118759673Seric **  IMPL_ALOOKUP -- lookup in best open database
118859673Seric */
118958059Seric 
119059673Seric char *
119159673Seric impl_alookup(ad, name, e)
119259673Seric 	ALIASDB *ad;
119359673Seric 	char *name;
119459673Seric 	ENVELOPE *e;
119558059Seric {
119659697Seric 	if (tTd(27, 20))
119759697Seric 		printf("impl_lookup(%s)\n", name);
119859697Seric 
119959673Seric #ifdef NEWDB
120059673Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
120159673Seric 		return hash_alookup(ad, name, e);
120259673Seric #endif
120359673Seric #ifdef NDBM
120459673Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
120559673Seric 		return ndbm_alookup(ad, name, e);
120659673Seric #endif
120759673Seric 	return stab_alookup(ad, name, e);
120859673Seric }
120959673Seric 
121059673Seric /*
121159673Seric **  IMPL_ASTORE -- store in open databases
121259673Seric */
121359673Seric 
121459673Seric void
121559673Seric impl_astore(ad, lhs, rhs, e)
121659673Seric 	ALIASDB *ad;
121759673Seric 	char *lhs;
121859673Seric 	char *rhs;
121959673Seric 	ENVELOPE *e;
122059673Seric {
122159673Seric #ifdef NEWDB
122259673Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
122359673Seric 		hash_astore(ad, lhs, rhs, e);
122459673Seric #endif
122559673Seric #ifdef NDBM
122659673Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
122759673Seric 		ndbm_astore(ad, lhs, rhs, e);
122859673Seric #endif
122959673Seric 	stab_astore(ad, lhs, rhs, e);
123059673Seric }
123159673Seric 
123259673Seric /*
123359673Seric **  IMPL_AINIT -- implicit database lookup
123459673Seric */
123559673Seric 
123659673Seric bool
123759673Seric impl_ainit(ad, e)
123859673Seric 	ALIASDB *ad;
123959673Seric 	ENVELOPE *e;
124059673Seric {
124159697Seric 	if (tTd(27, 2))
124259697Seric 		printf("impl_ainit(%s)\n", ad->ad_name);
124359697Seric 
124459673Seric 	/* implicit class */
124559673Seric #ifdef NEWDB
124659697Seric 	ad->ad_flags |= ADF_IMPLHASH;
124759673Seric 	if (hash_ainit(ad, e))
124858059Seric 	{
124959697Seric 		return TRUE;
125059673Seric 	}
125159697Seric 	ad->ad_flags &= ~ADF_IMPLHASH;
125259673Seric #endif
125359673Seric #ifdef NDBM
125459697Seric 	ad->ad_flags |= ADF_IMPLNDBM;
125559673Seric 	if (ndbm_ainit(ad, e))
125659673Seric 	{
125759697Seric 		return TRUE;
125859673Seric 	}
125959697Seric 	ad->ad_flags &= ~ADF_IMPLNDBM;
126059673Seric #endif
126159673Seric 	syserr("WARNING: cannot open alias database %s", ad->ad_name);
126258059Seric 
126359673Seric 	if (stab_ainit(ad, e))
126459673Seric 	{
126559697Seric 		return TRUE;
126659673Seric 	}
126759697Seric 
126859697Seric 	return FALSE;
126959673Seric }
127058059Seric 
127159673Seric /*
127259673Seric **  IMPL_AREBUILD -- rebuild alias database
127359673Seric */
127458059Seric 
127559673Seric void
127659673Seric impl_arebuild(ad, fp, e)
127759673Seric 	ALIASDB *ad;
127859673Seric 	FILE *fp;
127959673Seric 	ENVELOPE *e;
128059673Seric {
128159673Seric #ifdef NEWDB
128259673Seric 	DB *ndb;
128359673Seric 	char buf[MAXNAME];
128459697Seric #endif
128559673Seric 
128659697Seric 	if (tTd(27, 2))
128759697Seric 		printf("impl_arebuild(%s)\n", ad->ad_name);
128859697Seric 
128959697Seric #ifdef NEWDB
129059673Seric 	(void) strcpy(buf, ad->ad_name);
129159673Seric 	(void) strcat(buf, ".db");
129259673Seric 	ndb = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
129359673Seric 	if (ndb == NULL)
129458059Seric 	{
129559673Seric 		syserr("rebuildaliases: cannot create %s", buf);
129658059Seric 	}
129759673Seric 	else
129859673Seric 	{
129959673Seric 		ad->ad_ndbp = ndb;
130059673Seric 		ad->ad_flags |= ADF_IMPLHASH;
130159673Seric #if defined(NDBM) && defined(YPCOMPAT)
130259673Seric 		if (access("/var/yp/Makefile", R_OK) != 0)
130359673Seric #endif
130459697Seric 			goto readem;
130559673Seric 	}
130659673Seric #endif
130759673Seric 
130859673Seric #ifdef NDBM
130959673Seric 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
131059673Seric 	if (ad->ad_dbp == NULL)
131159673Seric 	{
131259673Seric 		syserr("rebuildaliases: cannot create %s.{pag,dir}",
131359673Seric 			ad->ad_name);
131459673Seric 	}
131559673Seric 	else
131659673Seric 	{
131759673Seric 		ad->ad_flags |= ADF_IMPLNDBM;
131859673Seric 	}
131959673Seric #endif
132059673Seric 
132159673Seric 	if (!bitset(ADF_IMPLHASH|ADF_IMPLNDBM, ad->ad_flags))
132259673Seric 		return;
132359673Seric 
132459697Seric   readem:
1325*59701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
132659673Seric 
132759673Seric 	/* read and store aliases */
132859673Seric 	readaliases(ad, fp, e);
132958059Seric }
133058059Seric 
133159673Seric 
133259673Seric /*
133359673Seric **  IMPL_ACLOSE -- close any open database(s)
133459673Seric */
133559673Seric 
133659673Seric void
133759673Seric impl_aclose(ad, e)
133859673Seric 	ALIASDB *ad;
133959673Seric 	ENVELOPE *e;
134059673Seric {
134159673Seric #ifdef NEWDB
134259697Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
134359697Seric 		hash_aclose(ad, e);
134459673Seric #endif
134559673Seric 
134659673Seric #ifdef NDBM
134759697Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
134859697Seric 		ndbm_aclose(ad, e);
134959673Seric #endif
135059673Seric }
135158059Seric /*
135259673Seric **  SETUPALIASES -- set up aliases classes
135359673Seric */
135459673Seric 
135559673Seric #ifdef NEWDB
135659673Seric ALIASCLASS	HashAClass =
135759673Seric {
135859673Seric 	"hash",		hash_alookup,	hash_astore,
135959673Seric 	hash_ainit,	hash_arebuild,	hash_aclose,
136059673Seric 	ACF_BUILDABLE
136159673Seric };
136259673Seric #endif
136359673Seric 
136459673Seric #ifdef NDBM
136559673Seric ALIASCLASS	DbmAClass =
136659673Seric {
136759673Seric 	"dbm",		ndbm_alookup,	ndbm_astore,
136859673Seric 	ndbm_ainit,	ndbm_arebuild,	ndbm_aclose,
136959673Seric 	ACF_BUILDABLE
137059673Seric };
137159673Seric #endif
137259673Seric 
137359673Seric #ifdef NIS
137459673Seric ALIASCLASS	NisAClass =
137559673Seric {
137659673Seric 	"nis",		nis_alookup,	nis_astore,
137759673Seric 	nis_ainit,	nis_arebuild,	nis_aclose,
137859673Seric 	0
137959673Seric };
138059673Seric #endif
138159673Seric 
138259673Seric ALIASCLASS	StabAClass =
138359673Seric {
138459673Seric 	"stab",		stab_alookup,	stab_astore,
138559673Seric 	stab_ainit,	stab_arebuild,	stab_aclose,
138659673Seric 	0
138759673Seric };
138859673Seric 
138959673Seric ALIASCLASS	ImplAClass =
139059673Seric {
139159673Seric 	"implicit",	impl_alookup,	impl_astore,
139259673Seric 	impl_ainit,	impl_arebuild,	impl_aclose,
139359673Seric 	ACF_BUILDABLE
139459673Seric };
139559673Seric 
139659673Seric setupaliases()
139759673Seric {
139859673Seric 	register STAB *s;
139959673Seric 
140059673Seric #ifdef NEWDB
140159673Seric 	s = stab("hash", ST_ALIASCLASS, ST_ENTER);
140259673Seric 	s->s_aliasclass = &HashAClass;
140359673Seric #endif
140459673Seric 
140559673Seric #ifdef NDBM
140659673Seric 	s = stab("dbm", ST_ALIASCLASS, ST_ENTER);
140759673Seric 	s->s_aliasclass = &DbmAClass;
140859673Seric #endif
140959673Seric 
141059673Seric #ifdef NIS
141159673Seric 	s = stab("nis", ST_ALIASCLASS, ST_ENTER);
141259673Seric 	s->s_aliasclass = &NisAClass;
141359673Seric #endif
141459673Seric 
141559673Seric #if !defined(NEWDB) && !defined(NDBM)
141659673Seric 	s = stab("stab", ST_ALIASCLASS, ST_ENTER);
141759673Seric 	s->s_aliasclass = &StabAClass;
141859673Seric #endif
141959673Seric 
142059673Seric 	s = stab("implicit", ST_ALIASCLASS, ST_ENTER);
142159673Seric 	s->s_aliasclass = &ImplAClass;
142259673Seric }
142359673Seric /*
1424292Seric **  FORWARD -- Try to forward mail
1425292Seric **
1426292Seric **	This is similar but not identical to aliasing.
1427292Seric **
1428292Seric **	Parameters:
14294314Seric **		user -- the name of the user who's mail we would like
14304314Seric **			to forward to.  It must have been verified --
14314314Seric **			i.e., the q_home field must have been filled
14324314Seric **			in.
14334999Seric **		sendq -- a pointer to the head of the send queue to
14344999Seric **			put this user's aliases in.
1435292Seric **
1436292Seric **	Returns:
14374098Seric **		none.
1438292Seric **
1439292Seric **	Side Effects:
14403185Seric **		New names are added to send queues.
1441292Seric */
1442292Seric 
144355012Seric forward(user, sendq, e)
14442966Seric 	ADDRESS *user;
14454999Seric 	ADDRESS **sendq;
144655012Seric 	register ENVELOPE *e;
1447292Seric {
144857136Seric 	char *pp;
144957136Seric 	char *ep;
14504069Seric 
14517671Seric 	if (tTd(27, 1))
14524098Seric 		printf("forward(%s)\n", user->q_paddr);
14534098Seric 
14544594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
14554098Seric 		return;
14564314Seric 	if (user->q_home == NULL)
145758059Seric 	{
145858151Seric 		syserr("554 forward: no home");
145958059Seric 		user->q_home = "/nosuchdirectory";
146058059Seric 	}
14614069Seric 
14624069Seric 	/* good address -- look for .forward file in home */
146355012Seric 	define('z', user->q_home, e);
146457136Seric 	define('u', user->q_user, e);
146557136Seric 	define('h', user->q_host, e);
146657136Seric 	if (ForwardPath == NULL)
146758050Seric 		ForwardPath = newstr("\201z/.forward");
146857136Seric 
146957136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
147057136Seric 	{
147158247Seric 		int err;
147257232Seric 		char buf[MAXPATHLEN+1];
147357136Seric 
147457136Seric 		ep = strchr(pp, ':');
147557136Seric 		if (ep != NULL)
147657136Seric 			*ep = '\0';
147757136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
147857136Seric 		if (ep != NULL)
147957136Seric 			*ep++ = ':';
148057136Seric 		if (tTd(27, 3))
148157136Seric 			printf("forward: trying %s\n", buf);
148258247Seric 		err = include(buf, TRUE, user, sendq, e);
148358247Seric 		if (err == 0)
148457136Seric 			break;
148558247Seric 		if (transienterror(err))
148658247Seric 		{
148758247Seric 			/* we have to suspend this message */
148859563Seric 			if (tTd(27, 2))
148959563Seric 				printf("forward: transient error on %s\n", buf);
149059563Seric #ifdef LOG
149159563Seric 			if (LogLevel > 2)
149259624Seric 				syslog(LOG_ERR, "%s: forward %s: transient error: %s",
149359624Seric 					e->e_id, buf, errstring(err));
149459563Seric #endif
149559611Seric 			message("%s: %s: message queued", buf, errstring(err));
149658247Seric 			user->q_flags |= QQUEUEUP|QDONTSEND;
149758247Seric 			return;
149858247Seric 		}
149957136Seric 	}
1500292Seric }
1501