xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 59733)
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*59733Seric static char sccsid[] = "@(#)alias.c	6.43 (Berkeley) 05/04/93 (with NEWDB and NDBM)";
2951756Seric #else
30*59733Seric static char sccsid[] = "@(#)alias.c	6.43 (Berkeley) 05/04/93 (with NEWDB)";
3157736Seric #endif
3257736Seric #else
3356845Seric #ifdef NDBM
34*59733Seric static char sccsid[] = "@(#)alias.c	6.43 (Berkeley) 05/04/93 (with NDBM)";
3533728Sbostic #else
36*59733Seric static char sccsid[] = "@(#)alias.c	6.43 (Berkeley) 05/04/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 */
74*59733Seric 	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 
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 		errno = 0;
44559673Seric 		return;
4468437Seric 	}
44759673Seric 
44859673Seric 	/* see if someone else is rebuilding the alias file */
44959673Seric 	if (!lockfile(fileno(af), ad->ad_name, LOCK_EX|LOCK_NB))
45059673Seric 	{
45159673Seric 		/* yes, they are -- wait until done */
45259673Seric 		message("Alias file %s is already being rebuilt",
45359673Seric 			ad->ad_name);
45459673Seric 		if (OpMode != MD_INITALIAS)
45559673Seric 		{
45659673Seric 			/* wait for other rebuild to complete */
45759673Seric 			(void) lockfile(fileno(af), ad->ad_name,
45859673Seric 					LOCK_EX);
45959673Seric 		}
46059673Seric 		(void) fclose(af);
46159673Seric 		errno = 0;
46259673Seric 		return;
46359673Seric 	}
46459673Seric 
46559673Seric 	oldsigint = signal(SIGINT, SIG_IGN);
46659673Seric 
467*59733Seric 	ad->ad_class->ac_rebuild(ad, af, automatic, e);
46859673Seric 
46959673Seric 	/* close the file, thus releasing locks */
47059673Seric 	fclose(af);
47159673Seric 
47259673Seric 	/* add distinguished entries and close the database */
47359701Seric 	if (bitset(ADF_VALID, ad->ad_flags))
47459701Seric 		ad->ad_class->ac_close(ad, e);
47559673Seric 
47659673Seric 	/* restore the old signal */
47759673Seric 	(void) signal(SIGINT, oldsigint);
4784157Seric }
4794157Seric /*
4804157Seric **  READALIASES -- read and process the alias file.
4814157Seric **
4824157Seric **	This routine implements the part of initaliases that occurs
4834157Seric **	when we are not going to use the DBM stuff.
4844157Seric **
4854157Seric **	Parameters:
48659673Seric **		ad -- the alias database descriptor.
48759673Seric **		af -- file to read the aliases from.
488*59733Seric **		automatic -- set if this was an automatic rebuild.
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
500*59733Seric readaliases(ad, af, automatic, e)
50159673Seric 	register ALIASDB *ad;
50259673Seric 	FILE *af;
503*59733Seric 	int automatic;
50455012Seric 	register ENVELOPE *e;
5054157Seric {
5064098Seric 	register char *p;
5074098Seric 	char *rhs;
5084098Seric 	bool skipping;
50959673Seric 	long naliases, bytes, longest;
5104098Seric 	ADDRESS al, bl;
5114106Seric 	register STAB *s;
5129368Seric 	char line[BUFSIZ];
5134098Seric 
5144314Seric 	/*
5154314Seric 	**  Read and interpret lines
5164314Seric 	*/
5174314Seric 
51859673Seric 	FileName = ad->ad_name;
5199368Seric 	LineNumber = 0;
5204322Seric 	naliases = bytes = longest = 0;
5214098Seric 	skipping = FALSE;
5224098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5234098Seric 	{
5244322Seric 		int lhssize, rhssize;
5254322Seric 
5269368Seric 		LineNumber++;
52756795Seric 		p = strchr(line, '\n');
52825278Seric 		if (p != NULL)
52925278Seric 			*p = '\0';
5304098Seric 		switch (line[0])
5314098Seric 		{
5324098Seric 		  case '#':
5334098Seric 		  case '\0':
5344098Seric 			skipping = FALSE;
5354098Seric 			continue;
5364065Seric 
5374098Seric 		  case ' ':
5384098Seric 		  case '\t':
5394098Seric 			if (!skipping)
54058151Seric 				syserr("554 Non-continuation line starts with space");
5414098Seric 			skipping = TRUE;
5424097Seric 			continue;
5434098Seric 		}
5444098Seric 		skipping = FALSE;
5451874Seric 
5464314Seric 		/*
5474314Seric 		**  Process the LHS
54857736Seric 		**	Find the colon separator, and parse the address.
54916898Seric 		**	It should resolve to a local name -- this will
55016898Seric 		**	be checked later (we want to optionally do
55116898Seric 		**	parsing of the RHS first to maximize error
55216898Seric 		**	detection).
5534314Seric 		*/
5544314Seric 
5554098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5564097Seric 			continue;
55716898Seric 		if (*p++ != ':')
5584098Seric 		{
55958151Seric 			syserr("554 missing colon");
5604097Seric 			continue;
5614098Seric 		}
56258333Seric 		if (parseaddr(line, &al, 1, ':', NULL, e) == NULL)
5634098Seric 		{
56458151Seric 			syserr("554 illegal alias name");
56516898Seric 			continue;
5664098Seric 		}
5674314Seric 
5684314Seric 		/*
5694314Seric 		**  Process the RHS.
5704314Seric 		**	'al' is the internal form of the LHS address.
5714314Seric 		**	'p' points to the text of the RHS.
5724314Seric 		*/
5734314Seric 
57458914Seric 		while (isascii(*p) && isspace(*p))
57558914Seric 			p++;
5764098Seric 		rhs = p;
5774098Seric 		for (;;)
5784098Seric 		{
5794098Seric 			register char c;
58058662Seric 			register char *nlp;
5811515Seric 
58258662Seric 			nlp = &p[strlen(p)];
58358662Seric 			if (nlp[-1] == '\n')
58458662Seric 				*--nlp = '\0';
58558662Seric 
58659673Seric 			if (CheckAliases)
5874098Seric 			{
5884157Seric 				/* do parsing & compression of addresses */
58925278Seric 				while (*p != '\0')
5904098Seric 				{
59158333Seric 					auto char *delimptr;
59225278Seric 
59358050Seric 					while ((isascii(*p) && isspace(*p)) ||
59458050Seric 								*p == ',')
5954157Seric 						p++;
59625278Seric 					if (*p == '\0')
59725278Seric 						break;
59858333Seric 					if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL)
59958151Seric 						usrerr("553 %s... bad address", p);
60058333Seric 					p = delimptr;
6014098Seric 				}
6024098Seric 			}
6034157Seric 			else
60415769Seric 			{
60558662Seric 				p = nlp;
60615769Seric 			}
6071515Seric 
6084098Seric 			/* see if there should be a continuation line */
6094106Seric 			c = fgetc(af);
6104106Seric 			if (!feof(af))
6114314Seric 				(void) ungetc(c, af);
6124106Seric 			if (c != ' ' && c != '\t')
6134098Seric 				break;
6144098Seric 
6154098Seric 			/* read continuation line */
6164098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6174098Seric 				break;
6189368Seric 			LineNumber++;
61957135Seric 
62057135Seric 			/* check for line overflow */
62157135Seric 			if (strchr(p, '\n') == NULL)
62257135Seric 			{
62358151Seric 				usrerr("554 alias too long");
62457135Seric 				break;
62557135Seric 			}
6264098Seric 		}
62716898Seric 		if (al.q_mailer != LocalMailer)
62816898Seric 		{
62958151Seric 			syserr("554 cannot alias non-local names");
63016898Seric 			continue;
63116898Seric 		}
6324314Seric 
6334314Seric 		/*
6344314Seric 		**  Insert alias into symbol table or DBM file
6354314Seric 		*/
6364314Seric 
63757381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
63857381Seric 			makelower(al.q_user);
6394322Seric 
64059673Seric 		lhssize = strlen(al.q_user);
64159673Seric 		rhssize = strlen(rhs);
64259673Seric 		ad->ad_class->ac_store(ad, al.q_user, rhs, e);
6434157Seric 
64459673Seric 		if (al.q_paddr != NULL)
64559673Seric 			free(al.q_paddr);
64659673Seric 		if (al.q_host != NULL)
64759673Seric 			free(al.q_host);
64859673Seric 		if (al.q_user != NULL)
64959673Seric 			free(al.q_user);
6504322Seric 
6514322Seric 		/* statistics */
6524322Seric 		naliases++;
6534322Seric 		bytes += lhssize + rhssize;
6544322Seric 		if (rhssize > longest)
6554322Seric 			longest = rhssize;
6561515Seric 	}
65719784Seric 
65859673Seric 	e->e_to = NULL;
65959673Seric 	FileName = NULL;
660*59733Seric 	if (Verbose || !automatic)
661*59733Seric 		message("%s: %d aliases, longest %d bytes, %d bytes total",
66259673Seric 			ad->ad_name, naliases, longest, bytes);
66359673Seric # ifdef LOG
66459673Seric 	if (LogLevel > 7)
66559673Seric 		syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
66659673Seric 			ad->ad_name, naliases, longest, bytes);
66759673Seric # endif /* LOG */
66859673Seric }
66959673Seric /*
67059673Seric **  NDBM modules
67159673Seric */
67259673Seric 
67359673Seric #ifdef NDBM
67459673Seric 
67559673Seric /*
67659673Seric **  NDBM_ALOOKUP -- look up alias in ndbm file
67759673Seric */
67859673Seric 
67959673Seric char *
68059673Seric ndbm_alookup(ad, name, e)
68159673Seric 	register ALIASDB *ad;
68259673Seric 	char *name;
68359673Seric 	ENVELOPE *e;
68459673Seric {
68559673Seric 	int i;
68659673Seric 	datum rhs, lhs;
68759673Seric 	char keybuf[MAXNAME + 1];
68859673Seric 
68959697Seric 	if (tTd(27, 20))
69059697Seric 		printf("ndbm_lookup(%s)\n", name);
69159697Seric 
69259673Seric 	/* create a key for fetch */
69359673Seric 	i = strlen(name) + 1;
69459673Seric 	if (i > sizeof keybuf)
69559673Seric 		i = sizeof keybuf;
69659673Seric 	bcopy(name, keybuf, i);
69759673Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
69859673Seric 		makelower(keybuf);
69959673Seric 
70059673Seric 	lhs.dsize = i;
70159673Seric 	lhs.dptr = keybuf;
70259673Seric 	rhs = dbm_fetch((DBM *) ad->ad_dbp, lhs);
70359673Seric 	return (rhs.dptr);
70459673Seric }
70559673Seric 
70659673Seric 
70759673Seric /*
70859673Seric **  NDBM_ASTORE -- store a datum in the database
70959673Seric */
71059673Seric 
71159673Seric void
71259673Seric ndbm_astore(ad, lhs, rhs, e)
71359673Seric 	register ALIASDB *ad;
71459673Seric 	char *lhs;
71559673Seric 	char *rhs;
71659673Seric 	ENVELOPE *e;
71759673Seric {
71859673Seric 	datum key;
71959673Seric 	datum data;
72059673Seric 	int stat;
72159673Seric 
72259697Seric 	key.dsize = strlen(lhs) + 1;
72359673Seric 	key.dptr = lhs;
72459673Seric 
72559697Seric 	data.dsize = strlen(rhs) + 1;
72659673Seric 	data.dptr = rhs;
72759673Seric 
72859673Seric 	stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_INSERT);
72959673Seric 	if (stat > 0)
73019784Seric 	{
73159673Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
73259673Seric 		stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_REPLACE);
73359673Seric 	}
73459673Seric 	if (stat != 0)
73559673Seric 		syserr("readaliases: dbm put (%s)", lhs);
73659673Seric }
73719784Seric 
73859673Seric 
73959673Seric /*
74059673Seric **  NDBM_AINIT -- initialize DBM database
74159673Seric */
74259673Seric 
74359673Seric bool
74459673Seric ndbm_ainit(ad, e)
74559673Seric 	register ALIASDB *ad;
74659673Seric 	ENVELOPE *e;
74759673Seric {
74859673Seric 	char buf[MAXNAME];
74959673Seric 
75059697Seric 	if (tTd(27, 2))
75159697Seric 		printf("ndbm_ainit(%s)\n", ad->ad_name);
75259697Seric 
75359673Seric 	/* open the database */
75459673Seric 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDONLY, DBMMODE);
75559673Seric 	if (ad->ad_dbp == NULL)
75659673Seric 		return FALSE;
75759673Seric 
75859673Seric 	/* wait for @:@ to appear */
75959673Seric 	aliaswait(ad, ".pag", e);
76059673Seric 
76159673Seric 	return TRUE;
76259673Seric }
76359673Seric 
76459673Seric 
76559673Seric /*
76659673Seric **  NDBM_AREBUILD -- rebuild hash database
76759673Seric */
76859673Seric 
76959673Seric void
770*59733Seric ndbm_arebuild(ad, fp, automatic, e)
77159673Seric 	register ALIASDB *ad;
77259673Seric 	FILE *fp;
773*59733Seric 	int automatic;
77459673Seric 	ENVELOPE *e;
77559673Seric {
77659673Seric 	register DBM *db;
77759673Seric 	int i;
77859673Seric 	char buf[MAXNAME];
77959673Seric 
78059697Seric 	if (tTd(27, 2))
78159697Seric 		printf("ndbm_arebuild(%s)\n", ad->ad_name);
78259697Seric 
78359673Seric 	db = dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
78459673Seric 	if (db == NULL)
78559673Seric 	{
78659701Seric 		syserr("ndbm_arebuild: cannot create %s", buf);
78759673Seric 		return;
78859673Seric 	}
78959673Seric 	ad->ad_dbp = (void *) db;
79059701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
79159673Seric 
79259673Seric 	/* read and store the aliases */
793*59733Seric 	readaliases(ad, fp, automatic, e);
79459673Seric }
79559673Seric 
79659673Seric /*
79759673Seric **  NDBM_ACLOSE -- close the database
79859673Seric */
79959673Seric 
80059673Seric void
80159673Seric ndbm_aclose(ad, e)
80259673Seric 	register ALIASDB  *ad;
80359673Seric 	ENVELOPE *e;
80459673Seric {
80559673Seric 	if (bitset(ADF_WRITABLE, ad->ad_flags))
80659673Seric 	{
80758059Seric #ifdef YPCOMPAT
80859673Seric 		char buf[200];
80958846Seric 
81059673Seric 		(void) sprintf(buf, "%010ld", curtime());
81159673Seric 		ndbm_astore(ad, "YP_LAST_MODIFIED", buf, e);
81259673Seric 
81359673Seric 		(void) myhostname(buf, sizeof buf);
81459673Seric 		ndbm_astore(ad, "YP_MASTER_NAME", buf, e);
81558059Seric #endif
81619784Seric 
81759673Seric 		/* write out the distinguished alias */
81859673Seric 		ndbm_astore(ad, "@", "@", e);
81919784Seric 	}
82059673Seric 	dbm_close((DBM *) ad->ad_dbp);
82159673Seric }
82219784Seric 
82359673Seric #endif
82459673Seric /*
82559673Seric **  HASH (NEWDB) Modules
82659673Seric */
82759673Seric 
82859673Seric #ifdef NEWDB
82959673Seric 
83059673Seric /*
83159673Seric **  HASH_ALOOKUP -- look up alias in hash file
83259673Seric */
83359673Seric 
83459673Seric char *
83559673Seric hash_alookup(ad, name, e)
83659673Seric 	register ALIASDB *ad;
83759673Seric 	char *name;
83859673Seric 	ENVELOPE *e;
83959673Seric {
84059673Seric 	int i;
84159673Seric 	DBT rhs, lhs;
84259673Seric 	int s;
84359673Seric 	char keybuf[MAXNAME + 1];
84459673Seric 
84559697Seric 	if (tTd(27, 20))
84659697Seric 		printf("hash_alookup(%s)\n", name);
84759697Seric 
84859673Seric 	/* create a key for fetch */
84959673Seric 	i = strlen(name) + 1;
85059673Seric 	if (i > sizeof keybuf)
85159673Seric 		i = sizeof keybuf;
85259673Seric 	bcopy(name, keybuf, i);
85359673Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
85459673Seric 		makelower(keybuf);
85559673Seric 
85659673Seric 	lhs.size = i;
85759673Seric 	lhs.data = keybuf;
85859673Seric 	i = ad->ad_ndbp->get(ad->ad_ndbp, &lhs, &rhs, 0);
85959673Seric 	if (i == 0)
86059673Seric 		return (rhs.data);
86159673Seric 	return (NULL);
862292Seric }
86359673Seric 
86459673Seric 
86559673Seric /*
86659673Seric **  HASH_ASTORE -- store a datum in the database
86759673Seric */
86859673Seric 
86959673Seric void
87059673Seric hash_astore(ad, lhs, rhs, e)
87159673Seric 	register ALIASDB *ad;
87259673Seric 	char *lhs;
87359673Seric 	char *rhs;
87459673Seric 	ENVELOPE *e;
87559673Seric {
87659673Seric 	int stat;
87759673Seric 	DBT key;
87859673Seric 	DBT data;
87959673Seric 
88059697Seric 	if (tTd(27, 20))
88159697Seric 		printf("hash_astore(%s, %s)\n", lhs, rhs);
88259697Seric 
88359697Seric 	key.size = strlen(lhs) + 1;
88459673Seric 	key.data = lhs;
88559673Seric 
88659697Seric 	data.size = strlen(rhs) + 1;
88759673Seric 	data.data = rhs;
88859673Seric 
88959673Seric 	stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, R_NOOVERWRITE);
89059673Seric 	if (stat > 0)
89159673Seric 	{
89259673Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
89359673Seric 		stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, 0);
89459673Seric 	}
89559673Seric 	if (stat != 0)
89659673Seric 		syserr("readaliases: db put (%s)", lhs);
89759673Seric }
89859673Seric 
89959673Seric 
90059673Seric /*
90159673Seric **  HASH_AINIT -- initialize hash database
90259673Seric */
90359673Seric 
90459673Seric bool
90559673Seric hash_ainit(ad, e)
90659673Seric 	register ALIASDB *ad;
90759673Seric 	ENVELOPE *e;
90859673Seric {
90959673Seric 	char buf[MAXNAME];
91059673Seric 
91159697Seric 	if (tTd(27, 2))
91259697Seric 		printf("hash_ainit(%s)\n", ad->ad_name);
91359697Seric 
91459673Seric 	/* open the database */
91559673Seric 	(void) strcpy(buf, ad->ad_name);
91659673Seric 	(void) strcat(buf, ".db");
91759673Seric 	ad->ad_ndbp = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
91859673Seric 	if (ad->ad_ndbp == NULL)
91959673Seric 		return FALSE;
92059673Seric 
92159673Seric 	/* wait for @:@ to appear */
92259673Seric 	aliaswait(ad, ".db", e);
92359673Seric 	return TRUE;
92459673Seric }
92559673Seric 
92659673Seric 
92759673Seric /*
92859673Seric **  HASH_AREBUILD -- rebuild hash database
92959673Seric */
93059673Seric 
93159673Seric void
932*59733Seric hash_arebuild(ad, fp, automatic, e)
93359673Seric 	register ALIASDB *ad;
93459673Seric 	FILE *fp;
935*59733Seric 	int automatic;
93659673Seric 	ENVELOPE *e;
93759673Seric {
93859673Seric 	register DB *db;
93959673Seric 	char buf[MAXNAME];
94059673Seric 
94159697Seric 	if (tTd(27, 2))
94259697Seric 		printf("hash_arebuild(%s)\n", ad->ad_name);
94359697Seric 
94459701Seric 	(void) strcpy(buf, ad->ad_name);
94559701Seric 	(void) strcat(buf, ".db");
94659673Seric 	db = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
94759673Seric 	if (db == NULL)
94859673Seric 	{
94959701Seric 		syserr("hash_arebuild: cannot create %s", buf);
95059673Seric 		return;
95159673Seric 	}
95259673Seric 	ad->ad_ndbp = db;
95359701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
95459673Seric 
95559673Seric 	/* read and store the aliases */
956*59733Seric 	readaliases(ad, fp, automatic, e);
95759673Seric }
95859673Seric 
95959673Seric 
96059673Seric /*
96159673Seric **  HASH_ACLOSE -- add distinguished entries and close the database
96259673Seric */
96359673Seric 
96459673Seric void
96559673Seric hash_aclose(ad, e)
96659673Seric 	ALIASDB *ad;
96759673Seric 	ENVELOPE *e;
96859673Seric {
96959697Seric 	if (tTd(27, 9))
97059697Seric 		printf("hash_aclose(%x)\n", ad->ad_flags);
97159697Seric 
97259673Seric 	if (bitset(ADF_WRITABLE, ad->ad_flags))
97359673Seric 	{
97459673Seric 		/* write out the distinguished alias */
97559673Seric 		hash_astore(ad, "@", "@", e);
97659673Seric 	}
97759673Seric 
97859673Seric 	if (ad->ad_ndbp->close(ad->ad_ndbp) != 0)
97959673Seric 		syserr("readaliases: db close failure");
98059673Seric }
98159673Seric 
98259673Seric #endif
983292Seric /*
98459673Seric **  STAB (Symbol Table) Modules
98559673Seric */
98659673Seric 
98759673Seric 
98859673Seric /*
98959673Seric **  STAB_ALOOKUP -- look up alias in symbol table
99059673Seric */
99159673Seric 
99259673Seric char *
99359673Seric stab_alookup(ad, name, e)
99459673Seric 	register ALIASDB *ad;
99559673Seric 	char *name;
99659673Seric 	ENVELOPE *e;
99759673Seric {
99859673Seric 	register STAB *s;
99959673Seric 
100059697Seric 	if (tTd(27, 20))
100159697Seric 		printf("stab_lookup(%s)\n", name);
100259697Seric 
100359673Seric 	s = stab(name, ST_ALIAS, ST_FIND);
100459673Seric 	if (s != NULL)
100559673Seric 		return (s->s_alias);
100659673Seric 	return (NULL);
100759673Seric }
100859673Seric 
100959673Seric 
101059673Seric /*
101159673Seric **  STAB_ASTORE -- store in symtab (actually using during init, not rebuild)
101259673Seric */
101359673Seric 
101459673Seric void
101559673Seric stab_astore(ad, lhs, rhs, e)
101659673Seric 	register ALIASDB *ad;
101759673Seric 	char *lhs;
101859673Seric 	char *rhs;
101959673Seric 	ENVELOPE *e;
102059673Seric {
102159673Seric 	register STAB *s;
102259673Seric 
102359673Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
102459673Seric 	s->s_alias = newstr(rhs);
102559673Seric }
102659673Seric 
102759673Seric 
102859673Seric /*
102959673Seric **  STAB_AINIT -- initialize (reads data file)
103059673Seric */
103159673Seric 
103259673Seric bool
103359673Seric stab_ainit(ad, e)
103459673Seric 	register ALIASDB *ad;
103559673Seric 	ENVELOPE *e;
103659673Seric {
103759673Seric 	FILE *af;
103859673Seric 
103959697Seric 	if (tTd(27, 2))
104059697Seric 		printf("stab_ainit(%s)\n", ad->ad_name);
104159697Seric 
104259673Seric 	af = fopen(ad->ad_name, "r");
104359673Seric 	if (af == NULL)
104459673Seric 	{
104559673Seric 		syserr("554 Can't open %s", ad->ad_name);
104659673Seric 		errno = 0;
104759673Seric 		return FALSE;
104859673Seric 	}
104959673Seric 
1050*59733Seric 	readaliases(ad, af, TRUE, e);
105159673Seric }
105259673Seric 
105359673Seric 
105459673Seric /*
105559673Seric **  STAB_AREBUILD -- rebuild alias file
105659673Seric */
105759673Seric 
105859673Seric void
1059*59733Seric stab_arebuild(ad, fp, automatic, e)
106059673Seric 	ALIASDB *ad;
106159673Seric 	FILE *fp;
1062*59733Seric 	int automatic;
106359673Seric 	ENVELOPE *e;
106459673Seric {
106559697Seric 	if (tTd(27, 2))
106659697Seric 		printf("stab_arebuild(%s)\n", ad->ad_name);
106759697Seric 
106859701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
106959673Seric }
107059673Seric 
107159673Seric 
107259673Seric /*
107359673Seric **  STAB_ACLOSE -- close symbol table (???)
107459673Seric */
107559673Seric 
107659673Seric void
107759673Seric stab_aclose(ad, e)
107859673Seric 	ALIASDB *ad;
107959673Seric 	ENVELOPE *e;
108059673Seric {
108159673Seric 	/* ignore it */
108259673Seric }
108359673Seric /*
108459673Seric **  NIS Modules
108559673Seric */
108659673Seric 
108759724Seric #ifdef NIS_ALIASES
108859673Seric 
108959673Seric /*
109059673Seric **  NIS_ALOOKUP
109159673Seric */
109259673Seric 
109359673Seric char *
109459673Seric nis_alookup(ad, name, e)
109559673Seric 	ALIASDB *ad;
109659673Seric 	char *name;
109759673Seric 	ENVELOPE *e;
109859673Seric {
109959673Seric 	auto char *vp;
110059673Seric 	auto int vsize;
110159673Seric 
110259697Seric 	if (tTd(27, 20))
110359697Seric 		printf("nis_lookup(%s)\n", name);
110459697Seric 
110559673Seric 	if (ypmatch(ad->ad_domain, ad->ad_name, name, strlen(name),
110659673Seric 			&vp, &vsize) != 0)
110759673Seric 		return NULL;
110859673Seric 	return vp;
110959673Seric }
111059673Seric 
111159673Seric /*
111259673Seric **  NIS_ASTORE
111359673Seric */
111459673Seric 
111559673Seric void
111659673Seric nis_astore(ad, lhs, rhs, e)
111759673Seric 	ALIASDB *ad;
111859673Seric 	char *lhs;
111959673Seric 	char *rhs;
112059673Seric 	ENVELOPE *e;
112159673Seric {
112259673Seric 	/* nothing */
112359673Seric }
112459673Seric 
112559673Seric /*
112659673Seric **  NIS_AINIT
112759673Seric */
112859673Seric 
112959673Seric bool
113059673Seric nis_ainit(ad, e)
113159673Seric 	ALIASDB *ad;
113259673Seric 	ENVELOPE *e;
113359673Seric {
113459673Seric 	register char *p;
113559673Seric 	auto char *ypmaster;
113659673Seric 
113759697Seric 	if (tTd(27, 2))
113859697Seric 		printf("nis_ainit(%s)\n", ad->ad_name);
113959697Seric 
114059673Seric 	p = strchr(ad->ad_name, '@');
114159673Seric 	if (p != NULL)
114259673Seric 	{
114359673Seric 		*p++ = '\0';
114459673Seric 		if (*p != '\0')
114559673Seric 			ad->ad_domain = p;
114659673Seric 	}
114759673Seric 	if (ad->ad_domain == NULL)
114859673Seric 		yp_get_default_domain(&ad->ad_domain);
114959673Seric 
115059673Seric 	if (*ad->ad_name == '\0')
115159673Seric 		ad->ad_name = "mail.aliases";
115259673Seric 
115359673Seric 	yperr = yp_master(ad->ad_domain, ad->ad_name, &ypmaster);
115459673Seric 	return (yperr == 0);
115559673Seric }
115659673Seric 
115759673Seric /*
115859673Seric **  NIS_AREBUILD
115959673Seric */
116059673Seric 
116159673Seric void
1162*59733Seric nis_arebuild(ad, fp, automatic, e)
116359673Seric 	ALIASDB *ad;
116459673Seric 	FILE *fp;
1165*59733Seric 	int automatic;
116659673Seric 	ENVELOPE *e;
116759673Seric {
116859697Seric 	if (tTd(27, 2))
116959697Seric 		printf("nis_arebuild(%s)\n", ad->ad_name);
117059673Seric }
117159673Seric 
117259673Seric 
117359673Seric /*
117459673Seric **  NIS_ACLOSE
117559673Seric */
117659673Seric 
117759673Seric void
117859673Seric nis_aclose(ad, e)
117959673Seric 	ALIASDB *ad;
118059673Seric 	ENVELOPE *e;
118159673Seric {
118259673Seric 	/* nothing */
118359673Seric }
118459673Seric 
118559724Seric #endif /* NIS_ALIASES */
118659673Seric /*
118759673Seric **  Implicit Modules
118858059Seric **
118959673Seric **	Tries several types.  For back compatibility.
119058059Seric */
119158059Seric 
119259673Seric /*
119359673Seric **  IMPL_ALOOKUP -- lookup in best open database
119459673Seric */
119558059Seric 
119659673Seric char *
119759673Seric impl_alookup(ad, name, e)
119859673Seric 	ALIASDB *ad;
119959673Seric 	char *name;
120059673Seric 	ENVELOPE *e;
120158059Seric {
120259697Seric 	if (tTd(27, 20))
120359697Seric 		printf("impl_lookup(%s)\n", name);
120459697Seric 
120559673Seric #ifdef NEWDB
120659673Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
120759673Seric 		return hash_alookup(ad, name, e);
120859673Seric #endif
120959673Seric #ifdef NDBM
121059673Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
121159673Seric 		return ndbm_alookup(ad, name, e);
121259673Seric #endif
121359673Seric 	return stab_alookup(ad, name, e);
121459673Seric }
121559673Seric 
121659673Seric /*
121759673Seric **  IMPL_ASTORE -- store in open databases
121859673Seric */
121959673Seric 
122059673Seric void
122159673Seric impl_astore(ad, lhs, rhs, e)
122259673Seric 	ALIASDB *ad;
122359673Seric 	char *lhs;
122459673Seric 	char *rhs;
122559673Seric 	ENVELOPE *e;
122659673Seric {
122759673Seric #ifdef NEWDB
122859673Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
122959673Seric 		hash_astore(ad, lhs, rhs, e);
123059673Seric #endif
123159673Seric #ifdef NDBM
123259673Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
123359673Seric 		ndbm_astore(ad, lhs, rhs, e);
123459673Seric #endif
123559673Seric 	stab_astore(ad, lhs, rhs, e);
123659673Seric }
123759673Seric 
123859673Seric /*
123959673Seric **  IMPL_AINIT -- implicit database lookup
124059673Seric */
124159673Seric 
124259673Seric bool
124359673Seric impl_ainit(ad, e)
124459673Seric 	ALIASDB *ad;
124559673Seric 	ENVELOPE *e;
124659673Seric {
1247*59733Seric 	struct stat stb;
1248*59733Seric 
124959697Seric 	if (tTd(27, 2))
125059697Seric 		printf("impl_ainit(%s)\n", ad->ad_name);
125159697Seric 
1252*59733Seric 	if (stat(ad->ad_name, &stb) < 0)
1253*59733Seric 	{
1254*59733Seric 		/* no alias file at all */
1255*59733Seric 		return FALSE;
1256*59733Seric 	}
1257*59733Seric 
125859673Seric #ifdef NEWDB
125959697Seric 	ad->ad_flags |= ADF_IMPLHASH;
126059673Seric 	if (hash_ainit(ad, e))
126158059Seric 	{
126259697Seric 		return TRUE;
126359673Seric 	}
126459697Seric 	ad->ad_flags &= ~ADF_IMPLHASH;
126559673Seric #endif
126659673Seric #ifdef NDBM
126759697Seric 	ad->ad_flags |= ADF_IMPLNDBM;
126859673Seric 	if (ndbm_ainit(ad, e))
126959673Seric 	{
127059697Seric 		return TRUE;
127159673Seric 	}
127259697Seric 	ad->ad_flags &= ~ADF_IMPLNDBM;
127359673Seric #endif
127458059Seric 
1275*59733Seric 	if (Verbose)
1276*59733Seric 		message("WARNING: cannot open alias database %s", ad->ad_name);
1277*59733Seric 
127859673Seric 	if (stab_ainit(ad, e))
127959673Seric 	{
128059697Seric 		return TRUE;
128159673Seric 	}
128259697Seric 
128359697Seric 	return FALSE;
128459673Seric }
128558059Seric 
128659673Seric /*
128759673Seric **  IMPL_AREBUILD -- rebuild alias database
128859673Seric */
128958059Seric 
129059673Seric void
1291*59733Seric impl_arebuild(ad, fp, automatic, e)
129259673Seric 	ALIASDB *ad;
129359673Seric 	FILE *fp;
1294*59733Seric 	int automatic;
129559673Seric 	ENVELOPE *e;
129659673Seric {
129759673Seric #ifdef NEWDB
129859673Seric 	DB *ndb;
129959673Seric 	char buf[MAXNAME];
130059697Seric #endif
130159673Seric 
130259697Seric 	if (tTd(27, 2))
130359697Seric 		printf("impl_arebuild(%s)\n", ad->ad_name);
130459697Seric 
130559697Seric #ifdef NEWDB
130659673Seric 	(void) strcpy(buf, ad->ad_name);
130759673Seric 	(void) strcat(buf, ".db");
130859673Seric 	ndb = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
130959673Seric 	if (ndb == NULL)
131058059Seric 	{
131159673Seric 		syserr("rebuildaliases: cannot create %s", buf);
131258059Seric 	}
131359673Seric 	else
131459673Seric 	{
131559673Seric 		ad->ad_ndbp = ndb;
131659673Seric 		ad->ad_flags |= ADF_IMPLHASH;
131759673Seric #if defined(NDBM) && defined(YPCOMPAT)
131859673Seric 		if (access("/var/yp/Makefile", R_OK) != 0)
131959673Seric #endif
132059697Seric 			goto readem;
132159673Seric 	}
132259673Seric #endif
132359673Seric 
132459673Seric #ifdef NDBM
132559673Seric 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
132659673Seric 	if (ad->ad_dbp == NULL)
132759673Seric 	{
132859673Seric 		syserr("rebuildaliases: cannot create %s.{pag,dir}",
132959673Seric 			ad->ad_name);
133059673Seric 	}
133159673Seric 	else
133259673Seric 	{
133359673Seric 		ad->ad_flags |= ADF_IMPLNDBM;
133459673Seric 	}
133559673Seric #endif
133659673Seric 
133759673Seric 	if (!bitset(ADF_IMPLHASH|ADF_IMPLNDBM, ad->ad_flags))
133859673Seric 		return;
133959673Seric 
134059697Seric   readem:
134159701Seric 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
134259673Seric 
134359673Seric 	/* read and store aliases */
1344*59733Seric 	readaliases(ad, fp, automatic, e);
134558059Seric }
134658059Seric 
134759673Seric 
134859673Seric /*
134959673Seric **  IMPL_ACLOSE -- close any open database(s)
135059673Seric */
135159673Seric 
135259673Seric void
135359673Seric impl_aclose(ad, e)
135459673Seric 	ALIASDB *ad;
135559673Seric 	ENVELOPE *e;
135659673Seric {
135759673Seric #ifdef NEWDB
135859697Seric 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
135959697Seric 		hash_aclose(ad, e);
136059673Seric #endif
136159673Seric 
136259673Seric #ifdef NDBM
136359697Seric 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
136459697Seric 		ndbm_aclose(ad, e);
136559673Seric #endif
136659673Seric }
136758059Seric /*
136859673Seric **  SETUPALIASES -- set up aliases classes
136959673Seric */
137059673Seric 
137159673Seric #ifdef NEWDB
137259673Seric ALIASCLASS	HashAClass =
137359673Seric {
137459673Seric 	"hash",		hash_alookup,	hash_astore,
137559673Seric 	hash_ainit,	hash_arebuild,	hash_aclose,
137659673Seric 	ACF_BUILDABLE
137759673Seric };
137859673Seric #endif
137959673Seric 
138059673Seric #ifdef NDBM
138159673Seric ALIASCLASS	DbmAClass =
138259673Seric {
138359673Seric 	"dbm",		ndbm_alookup,	ndbm_astore,
138459673Seric 	ndbm_ainit,	ndbm_arebuild,	ndbm_aclose,
138559673Seric 	ACF_BUILDABLE
138659673Seric };
138759673Seric #endif
138859673Seric 
138959724Seric #ifdef NIS_ALIASES
139059673Seric ALIASCLASS	NisAClass =
139159673Seric {
139259673Seric 	"nis",		nis_alookup,	nis_astore,
139359673Seric 	nis_ainit,	nis_arebuild,	nis_aclose,
139459673Seric 	0
139559673Seric };
139659673Seric #endif
139759673Seric 
139859673Seric ALIASCLASS	StabAClass =
139959673Seric {
140059673Seric 	"stab",		stab_alookup,	stab_astore,
140159673Seric 	stab_ainit,	stab_arebuild,	stab_aclose,
140259673Seric 	0
140359673Seric };
140459673Seric 
140559673Seric ALIASCLASS	ImplAClass =
140659673Seric {
140759673Seric 	"implicit",	impl_alookup,	impl_astore,
140859673Seric 	impl_ainit,	impl_arebuild,	impl_aclose,
140959673Seric 	ACF_BUILDABLE
141059673Seric };
141159673Seric 
141259673Seric setupaliases()
141359673Seric {
141459673Seric 	register STAB *s;
141559673Seric 
141659673Seric #ifdef NEWDB
141759673Seric 	s = stab("hash", ST_ALIASCLASS, ST_ENTER);
141859673Seric 	s->s_aliasclass = &HashAClass;
141959673Seric #endif
142059673Seric 
142159673Seric #ifdef NDBM
142259673Seric 	s = stab("dbm", ST_ALIASCLASS, ST_ENTER);
142359673Seric 	s->s_aliasclass = &DbmAClass;
142459673Seric #endif
142559673Seric 
142659724Seric #ifdef NIS_ALIASES
142759673Seric 	s = stab("nis", ST_ALIASCLASS, ST_ENTER);
142859673Seric 	s->s_aliasclass = &NisAClass;
142959673Seric #endif
143059673Seric 
143159673Seric #if !defined(NEWDB) && !defined(NDBM)
143259673Seric 	s = stab("stab", ST_ALIASCLASS, ST_ENTER);
143359673Seric 	s->s_aliasclass = &StabAClass;
143459673Seric #endif
143559673Seric 
143659673Seric 	s = stab("implicit", ST_ALIASCLASS, ST_ENTER);
143759673Seric 	s->s_aliasclass = &ImplAClass;
143859673Seric }
143959673Seric /*
1440292Seric **  FORWARD -- Try to forward mail
1441292Seric **
1442292Seric **	This is similar but not identical to aliasing.
1443292Seric **
1444292Seric **	Parameters:
14454314Seric **		user -- the name of the user who's mail we would like
14464314Seric **			to forward to.  It must have been verified --
14474314Seric **			i.e., the q_home field must have been filled
14484314Seric **			in.
14494999Seric **		sendq -- a pointer to the head of the send queue to
14504999Seric **			put this user's aliases in.
1451292Seric **
1452292Seric **	Returns:
14534098Seric **		none.
1454292Seric **
1455292Seric **	Side Effects:
14563185Seric **		New names are added to send queues.
1457292Seric */
1458292Seric 
145955012Seric forward(user, sendq, e)
14602966Seric 	ADDRESS *user;
14614999Seric 	ADDRESS **sendq;
146255012Seric 	register ENVELOPE *e;
1463292Seric {
146457136Seric 	char *pp;
146557136Seric 	char *ep;
14664069Seric 
14677671Seric 	if (tTd(27, 1))
14684098Seric 		printf("forward(%s)\n", user->q_paddr);
14694098Seric 
14704594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
14714098Seric 		return;
14724314Seric 	if (user->q_home == NULL)
147358059Seric 	{
147458151Seric 		syserr("554 forward: no home");
147558059Seric 		user->q_home = "/nosuchdirectory";
147658059Seric 	}
14774069Seric 
14784069Seric 	/* good address -- look for .forward file in home */
147955012Seric 	define('z', user->q_home, e);
148057136Seric 	define('u', user->q_user, e);
148157136Seric 	define('h', user->q_host, e);
148257136Seric 	if (ForwardPath == NULL)
148358050Seric 		ForwardPath = newstr("\201z/.forward");
148457136Seric 
148557136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
148657136Seric 	{
148758247Seric 		int err;
148857232Seric 		char buf[MAXPATHLEN+1];
148957136Seric 
149057136Seric 		ep = strchr(pp, ':');
149157136Seric 		if (ep != NULL)
149257136Seric 			*ep = '\0';
149357136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
149457136Seric 		if (ep != NULL)
149557136Seric 			*ep++ = ':';
149657136Seric 		if (tTd(27, 3))
149757136Seric 			printf("forward: trying %s\n", buf);
149858247Seric 		err = include(buf, TRUE, user, sendq, e);
149958247Seric 		if (err == 0)
150057136Seric 			break;
150158247Seric 		if (transienterror(err))
150258247Seric 		{
150358247Seric 			/* we have to suspend this message */
150459563Seric 			if (tTd(27, 2))
150559563Seric 				printf("forward: transient error on %s\n", buf);
150659563Seric #ifdef LOG
150759563Seric 			if (LogLevel > 2)
150859624Seric 				syslog(LOG_ERR, "%s: forward %s: transient error: %s",
150959624Seric 					e->e_id, buf, errstring(err));
151059563Seric #endif
151159611Seric 			message("%s: %s: message queued", buf, errstring(err));
151258247Seric 			user->q_flags |= QQUEUEUP|QDONTSEND;
151358247Seric 			return;
151458247Seric 		}
151557136Seric 	}
1516292Seric }
1517