xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 59611)
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>
1250577Seric 
1356845Seric # ifdef DBM
1456848Seric ERROR: DBM is no longer supported -- use NDBM instead.
1556845Seric # endif
1656845Seric 
1750577Seric # ifdef NEWDB
1850577Seric # include <db.h>
1950577Seric # endif
2050577Seric 
2156766Seric # ifdef NDBM
2256845Seric # include <ndbm.h>
2356766Seric # endif
2456766Seric 
2533728Sbostic #ifndef lint
2651756Seric #ifdef NEWDB
2757736Seric #ifdef NDBM
28*59611Seric static char sccsid[] = "@(#)alias.c	6.35 (Berkeley) 05/01/93 (with NEWDB and NDBM)";
2951756Seric #else
30*59611Seric static char sccsid[] = "@(#)alias.c	6.35 (Berkeley) 05/01/93 (with NEWDB)";
3157736Seric #endif
3257736Seric #else
3356845Seric #ifdef NDBM
34*59611Seric static char sccsid[] = "@(#)alias.c	6.35 (Berkeley) 05/01/93 (with NDBM)";
3533728Sbostic #else
36*59611Seric static char sccsid[] = "@(#)alias.c	6.35 (Berkeley) 05/01/93 (without NEWDB or NDBM)";
3733728Sbostic #endif
3850575Seric #endif
3933728Sbostic #endif /* not lint */
4051756Seric /*
41292Seric **  ALIAS -- Compute aliases.
42292Seric **
439368Seric **	Scans the alias file for an alias for the given address.
449368Seric **	If found, it arranges to deliver to the alias list instead.
459368Seric **	Uses libdbm database if -DDBM.
46292Seric **
47292Seric **	Parameters:
484097Seric **		a -- address to alias.
494999Seric **		sendq -- a pointer to the head of the send queue
504999Seric **			to put the aliases in.
5158092Seric **		e -- the current envelope.
52292Seric **
53292Seric **	Returns:
54292Seric **		none
55292Seric **
56292Seric **	Side Effects:
573185Seric **		Aliases found are expanded.
58292Seric **
59292Seric **	Notes:
60292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
61292Seric **			done.
62292Seric **
63292Seric **	Deficiencies:
64292Seric **		It should complain about names that are aliased to
65292Seric **			nothing.
66292Seric */
67292Seric 
68292Seric 
6953742Seric /*
7053742Seric **  Sun YP servers read the dbm files directly, so we have to build them
7153742Seric **  even if NEWDB
7253742Seric */
7353742Seric 
7456845Seric #ifdef NDBM
7553742Seric # ifndef NEWDB
7653742Seric #  define IF_MAKEDBMFILES
7753742Seric # else
7853742Seric #  ifdef YPCOMPAT
7953742Seric #   define IF_MAKEDBMFILES		if (makedbmfiles)
8053742Seric #  endif
8153742Seric # endif
8253742Seric #endif
8353742Seric 
8456845Seric typedef union
852966Seric {
8656845Seric #ifdef NDBM
8756845Seric 	datum	dbm;
8851756Seric #endif
8956845Seric #ifdef NEWDB
9056845Seric 	DBT	dbt;
9156845Seric #endif
9256845Seric 	struct
9356845Seric 	{
9456845Seric 		char	*data;
9556845Seric 		int	size;
9656845Seric 	} xx;
9756845Seric } DBdatum;
98292Seric 
9950575Seric #ifdef NEWDB
10050575Seric static DB	*AliasDBptr;
10150575Seric #endif
10256845Seric #ifdef NDBM
10356845Seric static DBM	*AliasDBMptr;
10456845Seric #endif
10550575Seric 
10655012Seric alias(a, sendq, e)
1074097Seric 	register ADDRESS *a;
1084999Seric 	ADDRESS **sendq;
10955012Seric 	register ENVELOPE *e;
110292Seric {
1114081Seric 	register char *p;
11258082Seric 	int naliases;
11358170Seric 	char *owner;
11458170Seric 	char obuf[MAXNAME + 6];
1155701Seric 	extern char *aliaslookup();
116292Seric 
1177671Seric 	if (tTd(27, 1))
1184098Seric 		printf("alias(%s)\n", a->q_paddr);
119292Seric 
1204098Seric 	/* don't realias already aliased names */
12158680Seric 	if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
1224098Seric 		return;
1234098Seric 
12455012Seric 	e->e_to = a->q_paddr;
1254098Seric 
1264314Seric 	/*
1274314Seric 	**  Look up this name
1284314Seric 	*/
1294314Seric 
13024944Seric 	if (NoAlias)
13124944Seric 		p = NULL;
13224944Seric 	else
13324944Seric 		p = aliaslookup(a->q_user);
1344098Seric 	if (p == NULL)
1354098Seric 		return;
136292Seric 
137292Seric 	/*
1384098Seric 	**  Match on Alias.
1394098Seric 	**	Deliver to the target list.
1401515Seric 	*/
1411515Seric 
1427671Seric 	if (tTd(27, 1))
1434098Seric 		printf("%s (%s, %s) aliased to %s\n",
1444098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
14558092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
14658154Seric 	{
14758154Seric 		a->q_flags |= QVERIFIED;
14858884Seric 		e->e_nrcpts++;
14958092Seric 		return;
15058154Seric 	}
15158154Seric 	message("aliased to %s", p);
15257977Seric #ifdef LOG
15358020Seric 	if (LogLevel > 9)
15457977Seric 		syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
15557977Seric #endif
15658082Seric 	a->q_flags &= ~QSELFREF;
1574098Seric 	AliasLevel++;
15858082Seric 	naliases = sendtolist(p, a, sendq, e);
1594098Seric 	AliasLevel--;
16058082Seric 	if (naliases > 0 && !bitset(QSELFREF, a->q_flags))
16158065Seric 	{
16258065Seric 		if (tTd(27, 5))
16358065Seric 		{
16458065Seric 			printf("alias: QDONTSEND ");
16558065Seric 			printaddr(a, FALSE);
16658065Seric 		}
16758065Seric 		a->q_flags |= QDONTSEND;
16858065Seric 	}
16958170Seric 
17058170Seric 	/*
17158170Seric 	**  Look for owner of alias
17258170Seric 	*/
17358170Seric 
17458170Seric 	(void) strcpy(obuf, "owner-");
17558170Seric 	if (strncmp(a->q_user, "owner-", 6) == 0)
17658170Seric 		(void) strcat(obuf, "owner");
17758170Seric 	else
17858170Seric 		(void) strcat(obuf, a->q_user);
17958170Seric 	if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
18058170Seric 		makelower(obuf);
18158170Seric 	owner = aliaslookup(obuf);
18258170Seric 	if (owner != NULL)
18358170Seric 	{
18458170Seric 		if (strchr(owner, ',') != NULL)
18558170Seric 			owner = obuf;
18658170Seric 		a->q_owner = newstr(owner);
18758170Seric 	}
1884098Seric }
1894098Seric /*
1905701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1915701Seric **
1925701Seric **	Parameters:
1935701Seric **		name -- the name to look up.
1945701Seric **
1955701Seric **	Returns:
1965701Seric **		the value of name.
1975701Seric **		NULL if unknown.
1985701Seric **
1995701Seric **	Side Effects:
2005701Seric **		none.
2015701Seric **
2025701Seric **	Warnings:
2035701Seric **		The return value will be trashed across calls.
2045701Seric */
2055701Seric 
2065701Seric char *
2075701Seric aliaslookup(name)
2085701Seric 	char *name;
2095701Seric {
21057381Seric 	int i;
21157381Seric 	char keybuf[MAXNAME + 1];
21256845Seric # if defined(NEWDB) || defined(NDBM)
21356845Seric 	DBdatum rhs, lhs;
21450575Seric 	int s;
21557381Seric # else /* neither NEWDB nor NDBM */
21657381Seric 	register STAB *s;
21757381Seric # endif
2185701Seric 
2195701Seric 	/* create a key for fetch */
22057381Seric 	i = strlen(name) + 1;
22157381Seric 	if (i > sizeof keybuf)
22257381Seric 		i = sizeof keybuf;
22357381Seric 	bcopy(name, keybuf, i);
22457381Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
22557381Seric 		makelower(keybuf);
22657381Seric 
22757381Seric # if defined(NEWDB) || defined(NDBM)
22857381Seric 	lhs.xx.size = i;
22957381Seric 	lhs.xx.data = keybuf;
23050575Seric # ifdef NEWDB
23151756Seric 	if (AliasDBptr != NULL)
23251756Seric 	{
23357381Seric 		i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
23457381Seric 		if (i == 0)
23556845Seric 			return (rhs.dbt.data);
23651756Seric 	}
23756845Seric # ifdef NDBM
23857249Seric 	else if (AliasDBMptr != NULL)
23951756Seric 	{
24056845Seric 		rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
24156845Seric 		return (rhs.dbm.dptr);
24251756Seric 	}
24356845Seric # endif /* NDBM */
24457530Seric 	return (NULL);
24556845Seric # else /* not NEWDB */
24656845Seric 	rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
24756845Seric 	return (rhs.dbm.dptr);
24856845Seric # endif /* NEWDB */
24956845Seric # else /* neither NEWDB nor NDBM */
25057381Seric 	s = stab(keybuf, ST_ALIAS, ST_FIND);
25151756Seric 	if (s != NULL)
25251756Seric 		return (s->s_alias);
25357530Seric 	return (NULL);
25451756Seric # endif
2555701Seric }
2565701Seric /*
2574098Seric **  INITALIASES -- initialize for aliasing
2584098Seric **
25956845Seric **	Very different depending on whether we are running NDBM or not.
2604098Seric **
2614098Seric **	Parameters:
2624098Seric **		aliasfile -- location of aliases.
26356845Seric **		init -- if set and if NDBM, initialize the NDBM files.
2644098Seric **
2654098Seric **	Returns:
2664098Seric **		none.
2674098Seric **
2684098Seric **	Side Effects:
2694098Seric **		initializes aliases:
27056845Seric **		if NDBM:  opens the database.
27156845Seric **		if ~NDBM: reads the aliases into the symbol table.
2724098Seric */
2734098Seric 
27440559Sbostic # define DBMMODE	0644
2754157Seric 
27655012Seric initaliases(aliasfile, init, e)
2774098Seric 	char *aliasfile;
2784157Seric 	bool init;
27955012Seric 	register ENVELOPE *e;
2804098Seric {
28156845Seric #if defined(NDBM) || defined(NEWDB)
2828437Seric 	int atcnt;
28325522Seric 	time_t modtime;
28425522Seric 	bool automatic = FALSE;
2854322Seric 	char buf[MAXNAME];
28650575Seric #endif
2879368Seric 	struct stat stb;
28827176Seric 	static bool initialized = FALSE;
28946928Sbostic 	static int readaliases();
2904322Seric 
29127176Seric 	if (initialized)
29227176Seric 		return;
29327176Seric 	initialized = TRUE;
29427176Seric 
29517984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2968437Seric 	{
29725522Seric 		if (aliasfile != NULL && init)
29858151Seric 			syserr("554 Cannot open %s", aliasfile);
2998437Seric 		NoAlias = TRUE;
30011937Seric 		errno = 0;
3018437Seric 		return;
3028437Seric 	}
3038437Seric 
30456845Seric # if defined(NDBM) || defined(NEWDB)
3054322Seric 	/*
3068437Seric 	**  Check to see that the alias file is complete.
3078437Seric 	**	If not, we will assume that someone died, and it is up
3088437Seric 	**	to us to rebuild it.
3098437Seric 	*/
3108437Seric 
31125689Seric 	if (!init)
31250575Seric 	{
31350575Seric # ifdef NEWDB
31450575Seric 		(void) strcpy(buf, aliasfile);
31550575Seric 		(void) strcat(buf, ".db");
31651171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
31750576Seric 		if (AliasDBptr == NULL)
31850576Seric 		{
31956845Seric # ifdef NDBM
32056845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
32157249Seric 			if (AliasDBMptr == NULL)
32257249Seric 			{
32359025Seric 				syserr("WARNING: initaliases: cannot open %s", buf);
32457249Seric 				NoAlias = TRUE;
32557249Seric 				return;
32657249Seric 			}
32751756Seric # else
32859025Seric 			syserr("WARNING: initaliases: cannot open %s", buf);
32950576Seric 			NoAlias = TRUE;
33050576Seric 			return;
33151756Seric # endif
33250576Seric 		}
33350575Seric # else
33456845Seric 		AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
33557249Seric 		if (AliasDBMptr == NULL)
33657249Seric 		{
33759025Seric 			syserr("WARNING: initaliases: cannot open DBM database %s.{pag,dir}",
33857977Seric 				aliasfile);
33957249Seric 			NoAlias = TRUE;
34057249Seric 			return;
34157249Seric 		}
34250575Seric # endif
34350575Seric 	}
34417471Seric 	atcnt = SafeAlias * 2;
34517471Seric 	if (atcnt > 0)
34617471Seric 	{
34717471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
34825689Seric 		{
34925689Seric 			/*
35025689Seric 			**  Reinitialize alias file in case the new
35125689Seric 			**  one is mv'ed in instead of cp'ed in.
35225689Seric 			**
35325689Seric 			**	Only works with new DBM -- old one will
35425689Seric 			**	just consume file descriptors forever.
35525689Seric 			**	If you have a dbmclose() it can be
35625689Seric 			**	added before the sleep(30).
35725689Seric 			*/
35825689Seric 
35950575Seric # ifdef NEWDB
36051756Seric 			if (AliasDBptr != NULL)
36151756Seric 				AliasDBptr->close(AliasDBptr);
36250575Seric # endif
36356845Seric # ifdef NDBM
36456845Seric 			if (AliasDBMptr != NULL)
36556845Seric 				dbm_close(AliasDBMptr);
36656845Seric # endif
36750575Seric 
36817471Seric 			sleep(30);
36950575Seric # ifdef NEWDB
37050575Seric 			(void) strcpy(buf, aliasfile);
37150575Seric 			(void) strcat(buf, ".db");
37251171Sbostic 			AliasDBptr =
37351171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
37450576Seric 			if (AliasDBptr == NULL)
37550576Seric 			{
37651756Seric # ifdef NDBM
37756845Seric 				AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
37851756Seric # else
37959025Seric 				syserr("WARNING: initaliases: cannot open %s", buf);
38050576Seric 				NoAlias = TRUE;
38150576Seric 				return;
38251756Seric # endif
38350576Seric 			}
38450575Seric # else
38525689Seric # ifdef NDBM
38656845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
38757249Seric 			if (AliasDBMptr == NULL)
38857249Seric 			{
38959025Seric 				syserr("WARNING: initaliases: cannot open DBM database %s.{pag,dir}",
39058008Seric 					aliasfile);
39157249Seric 				NoAlias = TRUE;
39257249Seric 				return;
39357249Seric 			}
39450575Seric # endif
39550575Seric # endif
39625689Seric 		}
39717471Seric 	}
39817471Seric 	else
39917471Seric 		atcnt = 1;
4008437Seric 
4018437Seric 	/*
40256845Seric 	**  See if the NDBM version of the file is out of date with
4034322Seric 	**  the text version.  If so, go into 'init' mode automatically.
40440559Sbostic 	**	This only happens if our effective userid owns the DBM.
40540559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
4064322Seric 	*/
4074322Seric 
4084322Seric 	modtime = stb.st_mtime;
4094322Seric 	(void) strcpy(buf, aliasfile);
41050575Seric # ifdef NEWDB
41150575Seric 	(void) strcat(buf, ".db");
41250575Seric # else
4134322Seric 	(void) strcat(buf, ".pag");
41450575Seric # endif
4154322Seric 	stb.st_ino = 0;
41619039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
4174322Seric 	{
41811937Seric 		errno = 0;
41940559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
4204322Seric 		{
4214322Seric 			init = TRUE;
42225522Seric 			automatic = TRUE;
42358151Seric 			message("rebuilding alias database");
42424944Seric #ifdef LOG
42558020Seric 			if (LogLevel > 14)
42624944Seric 				syslog(LOG_INFO, "rebuilding alias database");
42756795Seric #endif /* LOG */
4284322Seric 		}
4294322Seric 		else
4304322Seric 		{
43119039Seric #ifdef LOG
43258020Seric 			if (LogLevel > 3)
43324944Seric 				syslog(LOG_INFO, "alias database out of date");
43456795Seric #endif /* LOG */
43558151Seric 			message("Warning: alias database out of date");
4364322Seric 		}
4374322Seric 	}
4384322Seric 
4394322Seric 
4404322Seric 	/*
44156845Seric 	**  If necessary, load the NDBM file.
44256845Seric 	**	If running without NDBM, load the symbol table.
4434322Seric 	*/
4444322Seric 
4454157Seric 	if (init)
4468437Seric 	{
44725522Seric #ifdef LOG
44858020Seric 		if (LogLevel > 7)
44925522Seric 		{
45025522Seric 			extern char *username();
45125522Seric 
45225522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
45325522Seric 				automatic ? "auto" : "", username());
45425522Seric 		}
45556795Seric #endif /* LOG */
45655012Seric 		readaliases(aliasfile, TRUE, e);
4578437Seric 	}
45856845Seric # else /* NDBM */
45955012Seric 	readaliases(aliasfile, init, e);
46056845Seric # endif /* NDBM */
4614157Seric }
4624157Seric /*
4634157Seric **  READALIASES -- read and process the alias file.
4644157Seric **
4654157Seric **	This routine implements the part of initaliases that occurs
4664157Seric **	when we are not going to use the DBM stuff.
4674157Seric **
4684157Seric **	Parameters:
4694157Seric **		aliasfile -- the pathname of the alias file master.
47056845Seric **		init -- if set, initialize the NDBM stuff.
4714157Seric **
4724157Seric **	Returns:
4734157Seric **		none.
4744157Seric **
4754157Seric **	Side Effects:
4764157Seric **		Reads aliasfile into the symbol table.
4774157Seric **		Optionally, builds the .dir & .pag files.
4784157Seric */
4794157Seric 
4804157Seric static
48155012Seric readaliases(aliasfile, init, e)
4824157Seric 	char *aliasfile;
4834157Seric 	bool init;
48455012Seric 	register ENVELOPE *e;
4854157Seric {
4864098Seric 	register char *p;
4874098Seric 	char *rhs;
4884098Seric 	bool skipping;
4899368Seric 	int naliases, bytes, longest;
4909368Seric 	FILE *af;
49153742Seric 	bool makedbmfiles;
49240970Sbostic 	void (*oldsigint)();
4934098Seric 	ADDRESS al, bl;
4944106Seric 	register STAB *s;
49550575Seric # ifdef NEWDB
49650575Seric 	DB *dbp;
49750575Seric # endif
49856845Seric # ifdef NDBM
49956845Seric 	DBM *dbmp;
50056845Seric # endif
5019368Seric 	char line[BUFSIZ];
50258689Seric 	extern bool lockfile();
5034098Seric 
50451937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
5051515Seric 	{
50657249Seric 		if (init)
50758151Seric 			syserr("554 Can't open %s", aliasfile);
50857249Seric 		else if (tTd(27, 1))
5094106Seric 			printf("Can't open %s\n", aliasfile);
5104098Seric 		errno = 0;
5114098Seric 		NoAlias++;
5124098Seric 		return;
5134098Seric 	}
5144314Seric 
51556845Seric # if defined(NDBM) || defined(NEWDB)
51619784Seric 	/* see if someone else is rebuilding the alias file already */
51758689Seric 	if (!lockfile(fileno(af), aliasfile, LOCK_EX|LOCK_NB))
51819784Seric 	{
51919784Seric 		/* yes, they are -- wait until done and then return */
52058151Seric 		message("Alias file is already being rebuilt");
52119784Seric 		if (OpMode != MD_INITALIAS)
52219784Seric 		{
52319784Seric 			/* wait for other rebuild to complete */
52458689Seric 			(void) lockfile(fileno(af), aliasfile, LOCK_EX);
52519784Seric 		}
52623108Seric 		(void) fclose(af);
52719784Seric 		errno = 0;
52819784Seric 		return;
52919784Seric 	}
53056845Seric # endif /* NDBM */
53119784Seric 
5324314Seric 	/*
53319784Seric 	**  If initializing, create the new DBM files.
53419784Seric 	*/
53519784Seric 
53619784Seric 	if (init)
53719784Seric 	{
53819784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
53951756Seric # ifdef NEWDB
54051756Seric 		(void) strcpy(line, aliasfile);
54151756Seric 		(void) strcat(line, ".db");
54251756Seric 		dbp = dbopen(line,
54351756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
54451756Seric 		if (dbp == NULL)
54551756Seric 		{
54651756Seric 			syserr("readaliases: cannot create %s", line);
54751756Seric 			(void) signal(SIGINT, oldsigint);
54851756Seric 			return;
54951756Seric 		}
55053742Seric # endif
55153742Seric # ifdef IF_MAKEDBMFILES
55253742Seric # ifdef NEWDB
55353742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
55453742Seric # endif
55553742Seric 		IF_MAKEDBMFILES
55619784Seric 		{
55756845Seric 			dbmp = dbm_open(aliasfile,
55856845Seric 					       O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
55956845Seric 			if (dbmp == NULL)
56053742Seric 			{
56156845Seric 				syserr("readaliases: cannot create %s.{dir,pag}",
56256845Seric 					aliasfile);
56353742Seric 				(void) signal(SIGINT, oldsigint);
56453742Seric 				return;
56553742Seric 			}
56619784Seric 		}
56750575Seric # endif
56819784Seric 	}
56919784Seric 
57019784Seric 	/*
5714314Seric 	**  Read and interpret lines
5724314Seric 	*/
5734314Seric 
5749368Seric 	FileName = aliasfile;
5759368Seric 	LineNumber = 0;
5764322Seric 	naliases = bytes = longest = 0;
5774098Seric 	skipping = FALSE;
5784098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5794098Seric 	{
5804322Seric 		int lhssize, rhssize;
5814322Seric 
5829368Seric 		LineNumber++;
58356795Seric 		p = strchr(line, '\n');
58425278Seric 		if (p != NULL)
58525278Seric 			*p = '\0';
5864098Seric 		switch (line[0])
5874098Seric 		{
5884098Seric 		  case '#':
5894098Seric 		  case '\0':
5904098Seric 			skipping = FALSE;
5914098Seric 			continue;
5924065Seric 
5934098Seric 		  case ' ':
5944098Seric 		  case '\t':
5954098Seric 			if (!skipping)
59658151Seric 				syserr("554 Non-continuation line starts with space");
5974098Seric 			skipping = TRUE;
5984097Seric 			continue;
5994098Seric 		}
6004098Seric 		skipping = FALSE;
6011874Seric 
6024314Seric 		/*
6034314Seric 		**  Process the LHS
60457736Seric 		**	Find the colon separator, and parse the address.
60516898Seric 		**	It should resolve to a local name -- this will
60616898Seric 		**	be checked later (we want to optionally do
60716898Seric 		**	parsing of the RHS first to maximize error
60816898Seric 		**	detection).
6094314Seric 		*/
6104314Seric 
6114098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
6124097Seric 			continue;
61316898Seric 		if (*p++ != ':')
6144098Seric 		{
61558151Seric 			syserr("554 missing colon");
6164097Seric 			continue;
6174098Seric 		}
61858333Seric 		if (parseaddr(line, &al, 1, ':', NULL, e) == NULL)
6194098Seric 		{
62058151Seric 			syserr("554 illegal alias name");
62116898Seric 			continue;
6224098Seric 		}
6234314Seric 
6244314Seric 		/*
6254314Seric 		**  Process the RHS.
6264314Seric 		**	'al' is the internal form of the LHS address.
6274314Seric 		**	'p' points to the text of the RHS.
6284314Seric 		*/
6294314Seric 
63058914Seric 		while (isascii(*p) && isspace(*p))
63158914Seric 			p++;
6324098Seric 		rhs = p;
6334098Seric 		for (;;)
6344098Seric 		{
6354098Seric 			register char c;
63658662Seric 			register char *nlp;
6371515Seric 
63858662Seric 			nlp = &p[strlen(p)];
63958662Seric 			if (nlp[-1] == '\n')
64058662Seric 				*--nlp = '\0';
64158662Seric 
64225821Seric 			if (init && CheckAliases)
6434098Seric 			{
6444157Seric 				/* do parsing & compression of addresses */
64525278Seric 				while (*p != '\0')
6464098Seric 				{
64758333Seric 					auto char *delimptr;
64825278Seric 
64958050Seric 					while ((isascii(*p) && isspace(*p)) ||
65058050Seric 								*p == ',')
6514157Seric 						p++;
65225278Seric 					if (*p == '\0')
65325278Seric 						break;
65458333Seric 					if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL)
65558151Seric 						usrerr("553 %s... bad address", p);
65658333Seric 					p = delimptr;
6574098Seric 				}
6584098Seric 			}
6594157Seric 			else
66015769Seric 			{
66158662Seric 				p = nlp;
66215769Seric 			}
6631515Seric 
6644098Seric 			/* see if there should be a continuation line */
6654106Seric 			c = fgetc(af);
6664106Seric 			if (!feof(af))
6674314Seric 				(void) ungetc(c, af);
6684106Seric 			if (c != ' ' && c != '\t')
6694098Seric 				break;
6704098Seric 
6714098Seric 			/* read continuation line */
6724098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6734098Seric 				break;
6749368Seric 			LineNumber++;
67557135Seric 
67657135Seric 			/* check for line overflow */
67757135Seric 			if (strchr(p, '\n') == NULL)
67857135Seric 			{
67958151Seric 				usrerr("554 alias too long");
68057135Seric 				break;
68157135Seric 			}
6824098Seric 		}
68316898Seric 		if (al.q_mailer != LocalMailer)
68416898Seric 		{
68558151Seric 			syserr("554 cannot alias non-local names");
68616898Seric 			continue;
68716898Seric 		}
6884314Seric 
6894314Seric 		/*
6904314Seric 		**  Insert alias into symbol table or DBM file
6914314Seric 		*/
6924314Seric 
69316898Seric 		lhssize = strlen(al.q_user) + 1;
69457381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
69557381Seric 			makelower(al.q_user);
6964322Seric 		rhssize = strlen(rhs) + 1;
6974322Seric 
69856845Seric # if defined(NDBM) || defined(NEWDB)
6994157Seric 		if (init)
7004157Seric 		{
70156845Seric 			DBdatum key, content;
70257381Seric 			int putstat;
7034157Seric 
70456845Seric 			key.xx.size = lhssize;
70556845Seric 			key.xx.data = al.q_user;
70656845Seric 			content.xx.size = rhssize;
70756845Seric 			content.xx.data = rhs;
70851756Seric # ifdef NEWDB
70957381Seric 			putstat = dbp->put(dbp, &key.dbt, &content.dbt,
71057381Seric 					   R_NOOVERWRITE);
71157381Seric 			if (putstat > 0)
71257381Seric 			{
71357977Seric 				usrerr("050 Warning: duplicate alias name %s",
71457381Seric 					al.q_user);
71557381Seric 				putstat = dbp->put(dbp, &key.dbt,
71657381Seric 						   &content.dbt, 0);
71757381Seric 			}
71857381Seric 			if (putstat != 0)
71950576Seric 				syserr("readaliases: db put (%s)", al.q_user);
72050575Seric # endif
72153742Seric # ifdef IF_MAKEDBMFILES
72253742Seric 			IF_MAKEDBMFILES
72357381Seric 			{
72457381Seric 				putstat = dbm_store(dbmp, key.dbm, content.dbm,
72557381Seric 						    DBM_INSERT);
72657381Seric 				if (putstat > 0)
72757381Seric 				{
72857977Seric 					usrerr("050 Warning: duplicate alias name %s",
72957381Seric 						al.q_user);
73057381Seric 					putstat = dbm_store(dbmp, key.dbm,
73157381Seric 							content.dbm, DBM_REPLACE);
73257381Seric 				}
73357381Seric 				if (putstat != 0)
73456845Seric 					syserr("readaliases: dbm store (%s)",
73556845Seric 						al.q_user);
73657381Seric 			}
73753742Seric # endif
73857381Seric 			if (al.q_paddr != NULL)
73957381Seric 				free(al.q_paddr);
74057381Seric 			if (al.q_host != NULL)
74157381Seric 				free(al.q_host);
74257381Seric 			if (al.q_user != NULL)
74357381Seric 				free(al.q_user);
7444157Seric 		}
7454157Seric 		else
74656845Seric # endif /* NDBM */
7474157Seric 		{
7484157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
7494157Seric 			s->s_alias = newstr(rhs);
7504157Seric 		}
7514322Seric 
7524322Seric 		/* statistics */
7534322Seric 		naliases++;
7544322Seric 		bytes += lhssize + rhssize;
7554322Seric 		if (rhssize > longest)
7564322Seric 			longest = rhssize;
7571515Seric 	}
75819784Seric 
75956845Seric # if defined(NDBM) || defined(NEWDB)
76019784Seric 	if (init)
76119784Seric 	{
76219784Seric 		/* add the distinquished alias "@" */
76356845Seric 		DBdatum key;
76419784Seric 
76556845Seric 		key.xx.size = 2;
76656845Seric 		key.xx.data = "@";
76750575Seric # ifdef NEWDB
76850576Seric 		if (dbp->sync(dbp) != 0 ||
76956845Seric 		    dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
77050576Seric 		    dbp->close(dbp) != 0)
77150576Seric 			syserr("readaliases: db close failure");
77253742Seric # endif
77356789Seric # ifdef IF_MAKEDBMFILES
77456793Seric 		IF_MAKEDBMFILES
77556845Seric 		{
77658059Seric #ifdef YPCOMPAT
77759152Seric 			static void nis_magic __P((DBM *dbmp));
77858846Seric 
77958059Seric 			nis_magic(dbmp);
78058059Seric #endif
78156845Seric 			if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
78256845Seric 			    dbm_error(dbmp))
78356845Seric 				syserr("readaliases: dbm close failure");
78456845Seric 			dbm_close(dbmp);
78556845Seric 		}
78650575Seric # endif
78719784Seric 
78819784Seric 		/* restore the old signal */
78919784Seric 		(void) signal(SIGINT, oldsigint);
79019784Seric 	}
79156845Seric # endif /* NDBM */
79219784Seric 
79319784Seric 	/* closing the alias file drops the lock */
7944098Seric 	(void) fclose(af);
79555012Seric 	e->e_to = NULL;
7969368Seric 	FileName = NULL;
79758151Seric 	message("%d aliases, longest %d bytes, %d bytes total",
7984322Seric 			naliases, longest, bytes);
79924944Seric # ifdef LOG
80058020Seric 	if (LogLevel > 7)
80124944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
80224944Seric 			naliases, longest, bytes);
80356795Seric # endif /* LOG */
804292Seric }
805292Seric /*
80658059Seric **  NIS_MAGIC -- Add NIS magic dbm data
80758059Seric **
80858059Seric **	This adds the magic entries needed by SunOS to make this a valid
80958059Seric **	NIS map.
81058059Seric **
81158059Seric **	Parameters:
81258059Seric **		dbmp -- a pointer to the DBM structure.
81358059Seric **
81458059Seric **	Returns:
81558059Seric **		none.
81658059Seric */
81758059Seric 
81858059Seric # ifdef YPCOMPAT
81958059Seric 
82058059Seric static void
82158059Seric nis_magic(dbmp)
82258059Seric 	DBM *dbmp;
82358059Seric {
82458059Seric 	int i;
82558059Seric 	static datum key[2] =
82658059Seric 	{
82758059Seric 		{ "YP_LAST_MODIFIED",	sizeof "YP_LAST_MODIFIED" - 1 },
82858059Seric 		{ "YP_MASTER_NAME",	sizeof "YP_MASTER_NAME" - 1 },
82958059Seric 	};
83058059Seric 	datum contents[2];
83158059Seric 	char tbuf[12];
83258059Seric 	char hbuf[MAXHOSTNAMELEN];
83358059Seric 
83458059Seric 	(void) sprintf(tbuf, "%010ld", curtime());
83558059Seric 	contents[0].dptr = tbuf;
83658059Seric 	contents[0].dsize = strlen(tbuf);
83758059Seric 
83858059Seric 	(void) myhostname(hbuf, sizeof hbuf);
83958059Seric 	contents[1].dptr = hbuf;
84058846Seric 	contents[1].dsize = strlen(hbuf);
84158059Seric 
84258059Seric 	for (i = 0; i < sizeof key / sizeof *key; i++)
84358059Seric 	{
84458059Seric 		if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 ||
84558059Seric 		    dbm_error(dbmp))
84658059Seric 			syserr("nis_magic: dbm_store failure");
84758059Seric 	}
84858059Seric }
84958059Seric 
85058059Seric # endif
85158059Seric /*
852292Seric **  FORWARD -- Try to forward mail
853292Seric **
854292Seric **	This is similar but not identical to aliasing.
855292Seric **
856292Seric **	Parameters:
8574314Seric **		user -- the name of the user who's mail we would like
8584314Seric **			to forward to.  It must have been verified --
8594314Seric **			i.e., the q_home field must have been filled
8604314Seric **			in.
8614999Seric **		sendq -- a pointer to the head of the send queue to
8624999Seric **			put this user's aliases in.
863292Seric **
864292Seric **	Returns:
8654098Seric **		none.
866292Seric **
867292Seric **	Side Effects:
8683185Seric **		New names are added to send queues.
869292Seric */
870292Seric 
87155012Seric forward(user, sendq, e)
8722966Seric 	ADDRESS *user;
8734999Seric 	ADDRESS **sendq;
87455012Seric 	register ENVELOPE *e;
875292Seric {
87657136Seric 	char *pp;
87757136Seric 	char *ep;
8784069Seric 
8797671Seric 	if (tTd(27, 1))
8804098Seric 		printf("forward(%s)\n", user->q_paddr);
8814098Seric 
8824594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
8834098Seric 		return;
8844314Seric 	if (user->q_home == NULL)
88558059Seric 	{
88658151Seric 		syserr("554 forward: no home");
88758059Seric 		user->q_home = "/nosuchdirectory";
88858059Seric 	}
8894069Seric 
8904069Seric 	/* good address -- look for .forward file in home */
89155012Seric 	define('z', user->q_home, e);
89257136Seric 	define('u', user->q_user, e);
89357136Seric 	define('h', user->q_host, e);
89457136Seric 	if (ForwardPath == NULL)
89558050Seric 		ForwardPath = newstr("\201z/.forward");
89657136Seric 
89757136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
89857136Seric 	{
89958247Seric 		int err;
90057232Seric 		char buf[MAXPATHLEN+1];
90157136Seric 
90257136Seric 		ep = strchr(pp, ':');
90357136Seric 		if (ep != NULL)
90457136Seric 			*ep = '\0';
90557136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
90657136Seric 		if (ep != NULL)
90757136Seric 			*ep++ = ':';
90857136Seric 		if (tTd(27, 3))
90957136Seric 			printf("forward: trying %s\n", buf);
91058247Seric 		err = include(buf, TRUE, user, sendq, e);
91158247Seric 		if (err == 0)
91257136Seric 			break;
91358247Seric 		if (transienterror(err))
91458247Seric 		{
91558247Seric 			/* we have to suspend this message */
91659563Seric 			if (tTd(27, 2))
91759563Seric 				printf("forward: transient error on %s\n", buf);
91859563Seric #ifdef LOG
91959563Seric 			if (LogLevel > 2)
92059563Seric 				syslog(LOG_NOTICE, "%s: forward %s: transient error: %e",
92159563Seric 					e->e_id, buf);
92259563Seric #endif
923*59611Seric 			message("%s: %s: message queued", buf, errstring(err));
92458247Seric 			user->q_flags |= QQUEUEUP|QDONTSEND;
92558247Seric 			return;
92658247Seric 		}
92757136Seric 	}
928292Seric }
929