xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 58082)
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 
950577Seric # include <sys/types.h>
1050577Seric # include <sys/stat.h>
1157948Seric # include <sys/file.h>
1250577Seric # include <signal.h>
1350577Seric # include "sendmail.h"
1457737Seric # include <fcntl.h>
1550577Seric # include <pwd.h>
1650577Seric 
1756845Seric # ifdef DBM
1856848Seric ERROR: DBM is no longer supported -- use NDBM instead.
1956845Seric # endif
2056845Seric 
2150577Seric # ifdef NEWDB
2250577Seric # include <db.h>
2350577Seric # endif
2450577Seric 
2556766Seric # ifdef NDBM
2656845Seric # include <ndbm.h>
2756766Seric # endif
2856766Seric 
2933728Sbostic #ifndef lint
3051756Seric #ifdef NEWDB
3157736Seric #ifdef NDBM
32*58082Seric static char sccsid[] = "@(#)alias.c	6.14 (Berkeley) 02/20/93 (with NEWDB and NDBM)";
3351756Seric #else
34*58082Seric static char sccsid[] = "@(#)alias.c	6.14 (Berkeley) 02/20/93 (with NEWDB)";
3557736Seric #endif
3657736Seric #else
3756845Seric #ifdef NDBM
38*58082Seric static char sccsid[] = "@(#)alias.c	6.14 (Berkeley) 02/20/93 (with NDBM)";
3933728Sbostic #else
40*58082Seric static char sccsid[] = "@(#)alias.c	6.14 (Berkeley) 02/20/93 (without NEWDB or NDBM)";
4133728Sbostic #endif
4250575Seric #endif
4333728Sbostic #endif /* not lint */
4451756Seric /*
45292Seric **  ALIAS -- Compute aliases.
46292Seric **
479368Seric **	Scans the alias file for an alias for the given address.
489368Seric **	If found, it arranges to deliver to the alias list instead.
499368Seric **	Uses libdbm database if -DDBM.
50292Seric **
51292Seric **	Parameters:
524097Seric **		a -- address to alias.
534999Seric **		sendq -- a pointer to the head of the send queue
544999Seric **			to put the aliases in.
55292Seric **
56292Seric **	Returns:
57292Seric **		none
58292Seric **
59292Seric **	Side Effects:
603185Seric **		Aliases found are expanded.
61292Seric **
62292Seric **	Notes:
63292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
64292Seric **			done.
65292Seric **
66292Seric **	Deficiencies:
67292Seric **		It should complain about names that are aliased to
68292Seric **			nothing.
69292Seric */
70292Seric 
71292Seric 
7253742Seric /*
7353742Seric **  Sun YP servers read the dbm files directly, so we have to build them
7453742Seric **  even if NEWDB
7553742Seric */
7653742Seric 
7756845Seric #ifdef NDBM
7853742Seric # ifndef NEWDB
7953742Seric #  define IF_MAKEDBMFILES
8053742Seric # else
8153742Seric #  ifdef YPCOMPAT
8253742Seric #   define IF_MAKEDBMFILES		if (makedbmfiles)
8353742Seric #  endif
8453742Seric # endif
8553742Seric #endif
8653742Seric 
8756845Seric typedef union
882966Seric {
8956845Seric #ifdef NDBM
9056845Seric 	datum	dbm;
9151756Seric #endif
9256845Seric #ifdef NEWDB
9356845Seric 	DBT	dbt;
9456845Seric #endif
9556845Seric 	struct
9656845Seric 	{
9756845Seric 		char	*data;
9856845Seric 		int	size;
9956845Seric 	} xx;
10056845Seric } DBdatum;
101292Seric 
10250575Seric #ifdef NEWDB
10350575Seric static DB	*AliasDBptr;
10450575Seric #endif
10556845Seric #ifdef NDBM
10656845Seric static DBM	*AliasDBMptr;
10756845Seric #endif
10850575Seric 
10955012Seric alias(a, sendq, e)
1104097Seric 	register ADDRESS *a;
1114999Seric 	ADDRESS **sendq;
11255012Seric 	register ENVELOPE *e;
113292Seric {
1144081Seric 	register char *p;
115*58082Seric 	int naliases;
1165701Seric 	extern char *aliaslookup();
117292Seric 
1187671Seric 	if (tTd(27, 1))
1194098Seric 		printf("alias(%s)\n", a->q_paddr);
120292Seric 
1214098Seric 	/* don't realias already aliased names */
1224098Seric 	if (bitset(QDONTSEND, a->q_flags))
1234098Seric 		return;
1244098Seric 
12555012Seric 	e->e_to = a->q_paddr;
1264098Seric 
1274314Seric 	/*
1284314Seric 	**  Look up this name
1294314Seric 	*/
1304314Seric 
13124944Seric 	if (NoAlias)
13224944Seric 		p = NULL;
13324944Seric 	else
13424944Seric 		p = aliaslookup(a->q_user);
1354098Seric 	if (p == NULL)
1364098Seric 		return;
137292Seric 
138292Seric 	/*
1394098Seric 	**  Match on Alias.
1404098Seric 	**	Deliver to the target list.
1411515Seric 	*/
1421515Seric 
1437671Seric 	if (tTd(27, 1))
1444098Seric 		printf("%s (%s, %s) aliased to %s\n",
1454098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
1467051Seric 	message(Arpa_Info, "aliased to %s", p);
14757977Seric #ifdef LOG
14858020Seric 	if (LogLevel > 9)
14957977Seric 		syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
15057977Seric #endif
151*58082Seric 	a->q_flags &= ~QSELFREF;
1524098Seric 	AliasLevel++;
153*58082Seric 	naliases = sendtolist(p, a, sendq, e);
1544098Seric 	AliasLevel--;
155*58082Seric 	if (naliases > 0 && !bitset(QSELFREF, a->q_flags))
15658065Seric 	{
15758065Seric 		if (tTd(27, 5))
15858065Seric 		{
15958065Seric 			printf("alias: QDONTSEND ");
16058065Seric 			printaddr(a, FALSE);
16158065Seric 		}
16258065Seric 		a->q_flags |= QDONTSEND;
16358065Seric 	}
1644098Seric }
1654098Seric /*
1665701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1675701Seric **
1685701Seric **	Parameters:
1695701Seric **		name -- the name to look up.
1705701Seric **
1715701Seric **	Returns:
1725701Seric **		the value of name.
1735701Seric **		NULL if unknown.
1745701Seric **
1755701Seric **	Side Effects:
1765701Seric **		none.
1775701Seric **
1785701Seric **	Warnings:
1795701Seric **		The return value will be trashed across calls.
1805701Seric */
1815701Seric 
1825701Seric char *
1835701Seric aliaslookup(name)
1845701Seric 	char *name;
1855701Seric {
18657381Seric 	int i;
18757381Seric 	char keybuf[MAXNAME + 1];
18856845Seric # if defined(NEWDB) || defined(NDBM)
18956845Seric 	DBdatum rhs, lhs;
19050575Seric 	int s;
19157381Seric # else /* neither NEWDB nor NDBM */
19257381Seric 	register STAB *s;
19357381Seric # endif
1945701Seric 
1955701Seric 	/* create a key for fetch */
19657381Seric 	i = strlen(name) + 1;
19757381Seric 	if (i > sizeof keybuf)
19857381Seric 		i = sizeof keybuf;
19957381Seric 	bcopy(name, keybuf, i);
20057381Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
20157381Seric 		makelower(keybuf);
20257381Seric 
20357381Seric # if defined(NEWDB) || defined(NDBM)
20457381Seric 	lhs.xx.size = i;
20557381Seric 	lhs.xx.data = keybuf;
20650575Seric # ifdef NEWDB
20751756Seric 	if (AliasDBptr != NULL)
20851756Seric 	{
20957381Seric 		i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
21057381Seric 		if (i == 0)
21156845Seric 			return (rhs.dbt.data);
21251756Seric 	}
21356845Seric # ifdef NDBM
21457249Seric 	else if (AliasDBMptr != NULL)
21551756Seric 	{
21656845Seric 		rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
21756845Seric 		return (rhs.dbm.dptr);
21851756Seric 	}
21956845Seric # endif /* NDBM */
22057530Seric 	return (NULL);
22156845Seric # else /* not NEWDB */
22256845Seric 	rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
22356845Seric 	return (rhs.dbm.dptr);
22456845Seric # endif /* NEWDB */
22556845Seric # else /* neither NEWDB nor NDBM */
22657381Seric 	s = stab(keybuf, ST_ALIAS, ST_FIND);
22751756Seric 	if (s != NULL)
22851756Seric 		return (s->s_alias);
22957530Seric 	return (NULL);
23051756Seric # endif
2315701Seric }
2325701Seric /*
2334098Seric **  INITALIASES -- initialize for aliasing
2344098Seric **
23556845Seric **	Very different depending on whether we are running NDBM or not.
2364098Seric **
2374098Seric **	Parameters:
2384098Seric **		aliasfile -- location of aliases.
23956845Seric **		init -- if set and if NDBM, initialize the NDBM files.
2404098Seric **
2414098Seric **	Returns:
2424098Seric **		none.
2434098Seric **
2444098Seric **	Side Effects:
2454098Seric **		initializes aliases:
24656845Seric **		if NDBM:  opens the database.
24756845Seric **		if ~NDBM: reads the aliases into the symbol table.
2484098Seric */
2494098Seric 
25040559Sbostic # define DBMMODE	0644
2514157Seric 
25255012Seric initaliases(aliasfile, init, e)
2534098Seric 	char *aliasfile;
2544157Seric 	bool init;
25555012Seric 	register ENVELOPE *e;
2564098Seric {
25756845Seric #if defined(NDBM) || defined(NEWDB)
2588437Seric 	int atcnt;
25925522Seric 	time_t modtime;
26025522Seric 	bool automatic = FALSE;
2614322Seric 	char buf[MAXNAME];
26250575Seric #endif
2639368Seric 	struct stat stb;
26427176Seric 	static bool initialized = FALSE;
26546928Sbostic 	static int readaliases();
2664322Seric 
26727176Seric 	if (initialized)
26827176Seric 		return;
26927176Seric 	initialized = TRUE;
27027176Seric 
27117984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2728437Seric 	{
27325522Seric 		if (aliasfile != NULL && init)
27425522Seric 			syserr("Cannot open %s", aliasfile);
2758437Seric 		NoAlias = TRUE;
27611937Seric 		errno = 0;
2778437Seric 		return;
2788437Seric 	}
2798437Seric 
28056845Seric # if defined(NDBM) || defined(NEWDB)
2814322Seric 	/*
2828437Seric 	**  Check to see that the alias file is complete.
2838437Seric 	**	If not, we will assume that someone died, and it is up
2848437Seric 	**	to us to rebuild it.
2858437Seric 	*/
2868437Seric 
28725689Seric 	if (!init)
28850575Seric 	{
28950575Seric # ifdef NEWDB
29050575Seric 		(void) strcpy(buf, aliasfile);
29150575Seric 		(void) strcat(buf, ".db");
29251171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
29350576Seric 		if (AliasDBptr == NULL)
29450576Seric 		{
29556845Seric # ifdef NDBM
29656845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
29757249Seric 			if (AliasDBMptr == NULL)
29857249Seric 			{
29957249Seric 				syserr("initaliases: cannot open %s", buf);
30057249Seric 				NoAlias = TRUE;
30157249Seric 				return;
30257249Seric 			}
30351756Seric # else
30450576Seric 			syserr("initaliases: cannot open %s", buf);
30550576Seric 			NoAlias = TRUE;
30650576Seric 			return;
30751756Seric # endif
30850576Seric 		}
30950575Seric # else
31056845Seric 		AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
31157249Seric 		if (AliasDBMptr == NULL)
31257249Seric 		{
31357977Seric 			syserr("initaliases: cannot open DBM database %s.{pag,dir}",
31457977Seric 				aliasfile);
31557249Seric 			NoAlias = TRUE;
31657249Seric 			return;
31757249Seric 		}
31850575Seric # endif
31950575Seric 	}
32017471Seric 	atcnt = SafeAlias * 2;
32117471Seric 	if (atcnt > 0)
32217471Seric 	{
32317471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
32425689Seric 		{
32525689Seric 			/*
32625689Seric 			**  Reinitialize alias file in case the new
32725689Seric 			**  one is mv'ed in instead of cp'ed in.
32825689Seric 			**
32925689Seric 			**	Only works with new DBM -- old one will
33025689Seric 			**	just consume file descriptors forever.
33125689Seric 			**	If you have a dbmclose() it can be
33225689Seric 			**	added before the sleep(30).
33325689Seric 			*/
33425689Seric 
33550575Seric # ifdef NEWDB
33651756Seric 			if (AliasDBptr != NULL)
33751756Seric 				AliasDBptr->close(AliasDBptr);
33850575Seric # endif
33956845Seric # ifdef NDBM
34056845Seric 			if (AliasDBMptr != NULL)
34156845Seric 				dbm_close(AliasDBMptr);
34256845Seric # endif
34350575Seric 
34417471Seric 			sleep(30);
34550575Seric # ifdef NEWDB
34650575Seric 			(void) strcpy(buf, aliasfile);
34750575Seric 			(void) strcat(buf, ".db");
34851171Sbostic 			AliasDBptr =
34951171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
35050576Seric 			if (AliasDBptr == NULL)
35150576Seric 			{
35251756Seric # ifdef NDBM
35356845Seric 				AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
35451756Seric # else
35550576Seric 				syserr("initaliases: cannot open %s", buf);
35650576Seric 				NoAlias = TRUE;
35750576Seric 				return;
35851756Seric # endif
35950576Seric 			}
36050575Seric # else
36125689Seric # ifdef NDBM
36256845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
36357249Seric 			if (AliasDBMptr == NULL)
36457249Seric 			{
36558008Seric 				syserr("initaliases: cannot open DBM database %s.{pag,dir}",
36658008Seric 					aliasfile);
36757249Seric 				NoAlias = TRUE;
36857249Seric 				return;
36957249Seric 			}
37050575Seric # endif
37150575Seric # endif
37225689Seric 		}
37317471Seric 	}
37417471Seric 	else
37517471Seric 		atcnt = 1;
3768437Seric 
3778437Seric 	/*
37856845Seric 	**  See if the NDBM version of the file is out of date with
3794322Seric 	**  the text version.  If so, go into 'init' mode automatically.
38040559Sbostic 	**	This only happens if our effective userid owns the DBM.
38140559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
3824322Seric 	*/
3834322Seric 
3844322Seric 	modtime = stb.st_mtime;
3854322Seric 	(void) strcpy(buf, aliasfile);
38650575Seric # ifdef NEWDB
38750575Seric 	(void) strcat(buf, ".db");
38850575Seric # else
3894322Seric 	(void) strcat(buf, ".pag");
39050575Seric # endif
3914322Seric 	stb.st_ino = 0;
39219039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
3934322Seric 	{
39411937Seric 		errno = 0;
39540559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3964322Seric 		{
3974322Seric 			init = TRUE;
39825522Seric 			automatic = TRUE;
3997051Seric 			message(Arpa_Info, "rebuilding alias database");
40024944Seric #ifdef LOG
40158020Seric 			if (LogLevel > 14)
40224944Seric 				syslog(LOG_INFO, "rebuilding alias database");
40356795Seric #endif /* LOG */
4044322Seric 		}
4054322Seric 		else
4064322Seric 		{
40719039Seric #ifdef LOG
40858020Seric 			if (LogLevel > 3)
40924944Seric 				syslog(LOG_INFO, "alias database out of date");
41056795Seric #endif /* LOG */
4114322Seric 			message(Arpa_Info, "Warning: alias database out of date");
4124322Seric 		}
4134322Seric 	}
4144322Seric 
4154322Seric 
4164322Seric 	/*
41756845Seric 	**  If necessary, load the NDBM file.
41856845Seric 	**	If running without NDBM, load the symbol table.
4194322Seric 	*/
4204322Seric 
4214157Seric 	if (init)
4228437Seric 	{
42325522Seric #ifdef LOG
42458020Seric 		if (LogLevel > 7)
42525522Seric 		{
42625522Seric 			extern char *username();
42725522Seric 
42825522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
42925522Seric 				automatic ? "auto" : "", username());
43025522Seric 		}
43156795Seric #endif /* LOG */
43255012Seric 		readaliases(aliasfile, TRUE, e);
4338437Seric 	}
43456845Seric # else /* NDBM */
43555012Seric 	readaliases(aliasfile, init, e);
43656845Seric # endif /* NDBM */
4374157Seric }
4384157Seric /*
4394157Seric **  READALIASES -- read and process the alias file.
4404157Seric **
4414157Seric **	This routine implements the part of initaliases that occurs
4424157Seric **	when we are not going to use the DBM stuff.
4434157Seric **
4444157Seric **	Parameters:
4454157Seric **		aliasfile -- the pathname of the alias file master.
44656845Seric **		init -- if set, initialize the NDBM stuff.
4474157Seric **
4484157Seric **	Returns:
4494157Seric **		none.
4504157Seric **
4514157Seric **	Side Effects:
4524157Seric **		Reads aliasfile into the symbol table.
4534157Seric **		Optionally, builds the .dir & .pag files.
4544157Seric */
4554157Seric 
4564157Seric static
45755012Seric readaliases(aliasfile, init, e)
4584157Seric 	char *aliasfile;
4594157Seric 	bool init;
46055012Seric 	register ENVELOPE *e;
4614157Seric {
4624098Seric 	register char *p;
4634098Seric 	char *rhs;
4644098Seric 	bool skipping;
4659368Seric 	int naliases, bytes, longest;
4669368Seric 	FILE *af;
46753742Seric 	bool makedbmfiles;
46840970Sbostic 	void (*oldsigint)();
4694098Seric 	ADDRESS al, bl;
4704106Seric 	register STAB *s;
47150575Seric # ifdef NEWDB
47250575Seric 	DB *dbp;
47350575Seric # endif
47456845Seric # ifdef NDBM
47556845Seric 	DBM *dbmp;
47656845Seric # endif
47751937Seric # ifdef LOCKF
47851937Seric 	struct flock fld;
47951937Seric # endif
4809368Seric 	char line[BUFSIZ];
4814098Seric 
48251937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
4831515Seric 	{
48457249Seric 		if (init)
48557249Seric 			syserr("Can't open %s", aliasfile);
48657249Seric 		else if (tTd(27, 1))
4874106Seric 			printf("Can't open %s\n", aliasfile);
4884098Seric 		errno = 0;
4894098Seric 		NoAlias++;
4904098Seric 		return;
4914098Seric 	}
4924314Seric 
49356845Seric # if defined(NDBM) || defined(NEWDB)
49419784Seric 	/* see if someone else is rebuilding the alias file already */
49551835Seric # ifdef LOCKF
49651937Seric 	fld.l_type = F_WRLCK;
49751937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
49851937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
49951835Seric # else
50019784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
50151835Seric # endif
50219784Seric 	{
50319784Seric 		/* yes, they are -- wait until done and then return */
50419784Seric 		message(Arpa_Info, "Alias file is already being rebuilt");
50519784Seric 		if (OpMode != MD_INITALIAS)
50619784Seric 		{
50719784Seric 			/* wait for other rebuild to complete */
50851835Seric # ifdef LOCKF
50951937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
51051835Seric # else
51119784Seric 			(void) flock(fileno(af), LOCK_EX);
51251835Seric # endif
51319784Seric 		}
51423108Seric 		(void) fclose(af);
51519784Seric 		errno = 0;
51619784Seric 		return;
51719784Seric 	}
51856845Seric # endif /* NDBM */
51919784Seric 
5204314Seric 	/*
52119784Seric 	**  If initializing, create the new DBM files.
52219784Seric 	*/
52319784Seric 
52419784Seric 	if (init)
52519784Seric 	{
52619784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
52751756Seric # ifdef NEWDB
52851756Seric 		(void) strcpy(line, aliasfile);
52951756Seric 		(void) strcat(line, ".db");
53051756Seric 		dbp = dbopen(line,
53151756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
53251756Seric 		if (dbp == NULL)
53351756Seric 		{
53451756Seric 			syserr("readaliases: cannot create %s", line);
53551756Seric 			(void) signal(SIGINT, oldsigint);
53651756Seric 			return;
53751756Seric 		}
53853742Seric # endif
53953742Seric # ifdef IF_MAKEDBMFILES
54053742Seric # ifdef NEWDB
54153742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
54253742Seric # endif
54353742Seric 		IF_MAKEDBMFILES
54419784Seric 		{
54556845Seric 			dbmp = dbm_open(aliasfile,
54656845Seric 					       O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
54756845Seric 			if (dbmp == NULL)
54853742Seric 			{
54956845Seric 				syserr("readaliases: cannot create %s.{dir,pag}",
55056845Seric 					aliasfile);
55153742Seric 				(void) signal(SIGINT, oldsigint);
55253742Seric 				return;
55353742Seric 			}
55419784Seric 		}
55550575Seric # endif
55619784Seric 	}
55719784Seric 
55819784Seric 	/*
5594314Seric 	**  Read and interpret lines
5604314Seric 	*/
5614314Seric 
5629368Seric 	FileName = aliasfile;
5639368Seric 	LineNumber = 0;
5644322Seric 	naliases = bytes = longest = 0;
5654098Seric 	skipping = FALSE;
5664098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5674098Seric 	{
5684322Seric 		int lhssize, rhssize;
5694322Seric 
5709368Seric 		LineNumber++;
57156795Seric 		p = strchr(line, '\n');
57225278Seric 		if (p != NULL)
57325278Seric 			*p = '\0';
5744098Seric 		switch (line[0])
5754098Seric 		{
5764098Seric 		  case '#':
5774098Seric 		  case '\0':
5784098Seric 			skipping = FALSE;
5794098Seric 			continue;
5804065Seric 
5814098Seric 		  case ' ':
5824098Seric 		  case '\t':
5834098Seric 			if (!skipping)
5849368Seric 				syserr("Non-continuation line starts with space");
5854098Seric 			skipping = TRUE;
5864097Seric 			continue;
5874098Seric 		}
5884098Seric 		skipping = FALSE;
5891874Seric 
5904314Seric 		/*
5914314Seric 		**  Process the LHS
59257736Seric 		**	Find the colon separator, and parse the address.
59316898Seric 		**	It should resolve to a local name -- this will
59416898Seric 		**	be checked later (we want to optionally do
59516898Seric 		**	parsing of the RHS first to maximize error
59616898Seric 		**	detection).
5974314Seric 		*/
5984314Seric 
5994098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
6004097Seric 			continue;
60116898Seric 		if (*p++ != ':')
6024098Seric 		{
6039368Seric 			syserr("missing colon");
6044097Seric 			continue;
6054098Seric 		}
60655012Seric 		if (parseaddr(line, &al, 1, ':', e) == NULL)
6074098Seric 		{
60816898Seric 			syserr("illegal alias name");
60916898Seric 			continue;
6104098Seric 		}
61116898Seric 		loweraddr(&al);
6124314Seric 
6134314Seric 		/*
6144314Seric 		**  Process the RHS.
6154314Seric 		**	'al' is the internal form of the LHS address.
6164314Seric 		**	'p' points to the text of the RHS.
6174314Seric 		*/
6184314Seric 
6194098Seric 		rhs = p;
6204098Seric 		for (;;)
6214098Seric 		{
6224098Seric 			register char c;
6231515Seric 
62425821Seric 			if (init && CheckAliases)
6254098Seric 			{
6264157Seric 				/* do parsing & compression of addresses */
62725278Seric 				while (*p != '\0')
6284098Seric 				{
62925278Seric 					extern char *DelimChar;
63025278Seric 
63158050Seric 					while ((isascii(*p) && isspace(*p)) ||
63258050Seric 								*p == ',')
6334157Seric 						p++;
63425278Seric 					if (*p == '\0')
63525278Seric 						break;
63655012Seric 					if (parseaddr(p, &bl, -1, ',', e) == NULL)
63725278Seric 						usrerr("%s... bad address", p);
63825278Seric 					p = DelimChar;
6394098Seric 				}
6404098Seric 			}
6414157Seric 			else
64215769Seric 			{
64316898Seric 				p = &p[strlen(p)];
64416898Seric 				if (p[-1] == '\n')
64516898Seric 					*--p = '\0';
64615769Seric 			}
6471515Seric 
6484098Seric 			/* see if there should be a continuation line */
6494106Seric 			c = fgetc(af);
6504106Seric 			if (!feof(af))
6514314Seric 				(void) ungetc(c, af);
6524106Seric 			if (c != ' ' && c != '\t')
6534098Seric 				break;
6544098Seric 
6554098Seric 			/* read continuation line */
6564098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6574098Seric 				break;
6589368Seric 			LineNumber++;
65957135Seric 
66057135Seric 			/* check for line overflow */
66157135Seric 			if (strchr(p, '\n') == NULL)
66257135Seric 			{
66357135Seric 				usrerr("alias too long");
66457135Seric 				break;
66557135Seric 			}
6664098Seric 		}
66716898Seric 		if (al.q_mailer != LocalMailer)
66816898Seric 		{
66916898Seric 			syserr("cannot alias non-local names");
67016898Seric 			continue;
67116898Seric 		}
6724314Seric 
6734314Seric 		/*
6744314Seric 		**  Insert alias into symbol table or DBM file
6754314Seric 		*/
6764314Seric 
67716898Seric 		lhssize = strlen(al.q_user) + 1;
67857381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
67957381Seric 			makelower(al.q_user);
6804322Seric 		rhssize = strlen(rhs) + 1;
6814322Seric 
68256845Seric # if defined(NDBM) || defined(NEWDB)
6834157Seric 		if (init)
6844157Seric 		{
68556845Seric 			DBdatum key, content;
68657381Seric 			int putstat;
6874157Seric 
68856845Seric 			key.xx.size = lhssize;
68956845Seric 			key.xx.data = al.q_user;
69056845Seric 			content.xx.size = rhssize;
69156845Seric 			content.xx.data = rhs;
69251756Seric # ifdef NEWDB
69357381Seric 			putstat = dbp->put(dbp, &key.dbt, &content.dbt,
69457381Seric 					   R_NOOVERWRITE);
69557381Seric 			if (putstat > 0)
69657381Seric 			{
69757977Seric 				usrerr("050 Warning: duplicate alias name %s",
69857381Seric 					al.q_user);
69957381Seric 				putstat = dbp->put(dbp, &key.dbt,
70057381Seric 						   &content.dbt, 0);
70157381Seric 			}
70257381Seric 			if (putstat != 0)
70350576Seric 				syserr("readaliases: db put (%s)", al.q_user);
70450575Seric # endif
70553742Seric # ifdef IF_MAKEDBMFILES
70653742Seric 			IF_MAKEDBMFILES
70757381Seric 			{
70857381Seric 				putstat = dbm_store(dbmp, key.dbm, content.dbm,
70957381Seric 						    DBM_INSERT);
71057381Seric 				if (putstat > 0)
71157381Seric 				{
71257977Seric 					usrerr("050 Warning: duplicate alias name %s",
71357381Seric 						al.q_user);
71457381Seric 					putstat = dbm_store(dbmp, key.dbm,
71557381Seric 							content.dbm, DBM_REPLACE);
71657381Seric 				}
71757381Seric 				if (putstat != 0)
71856845Seric 					syserr("readaliases: dbm store (%s)",
71956845Seric 						al.q_user);
72057381Seric 			}
72153742Seric # endif
72257381Seric 			if (al.q_paddr != NULL)
72357381Seric 				free(al.q_paddr);
72457381Seric 			if (al.q_host != NULL)
72557381Seric 				free(al.q_host);
72657381Seric 			if (al.q_user != NULL)
72757381Seric 				free(al.q_user);
7284157Seric 		}
7294157Seric 		else
73056845Seric # endif /* NDBM */
7314157Seric 		{
7324157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
7334157Seric 			s->s_alias = newstr(rhs);
7344157Seric 		}
7354322Seric 
7364322Seric 		/* statistics */
7374322Seric 		naliases++;
7384322Seric 		bytes += lhssize + rhssize;
7394322Seric 		if (rhssize > longest)
7404322Seric 			longest = rhssize;
7411515Seric 	}
74219784Seric 
74356845Seric # if defined(NDBM) || defined(NEWDB)
74419784Seric 	if (init)
74519784Seric 	{
74619784Seric 		/* add the distinquished alias "@" */
74756845Seric 		DBdatum key;
74819784Seric 
74956845Seric 		key.xx.size = 2;
75056845Seric 		key.xx.data = "@";
75150575Seric # ifdef NEWDB
75250576Seric 		if (dbp->sync(dbp) != 0 ||
75356845Seric 		    dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
75450576Seric 		    dbp->close(dbp) != 0)
75550576Seric 			syserr("readaliases: db close failure");
75653742Seric # endif
75756789Seric # ifdef IF_MAKEDBMFILES
75856793Seric 		IF_MAKEDBMFILES
75956845Seric 		{
76058059Seric #ifdef YPCOMPAT
76158059Seric 			nis_magic(dbmp);
76258059Seric #endif
76356845Seric 			if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
76456845Seric 			    dbm_error(dbmp))
76556845Seric 				syserr("readaliases: dbm close failure");
76656845Seric 			dbm_close(dbmp);
76756845Seric 		}
76850575Seric # endif
76919784Seric 
77019784Seric 		/* restore the old signal */
77119784Seric 		(void) signal(SIGINT, oldsigint);
77219784Seric 	}
77356845Seric # endif /* NDBM */
77419784Seric 
77519784Seric 	/* closing the alias file drops the lock */
7764098Seric 	(void) fclose(af);
77755012Seric 	e->e_to = NULL;
7789368Seric 	FileName = NULL;
7797051Seric 	message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
7804322Seric 			naliases, longest, bytes);
78124944Seric # ifdef LOG
78258020Seric 	if (LogLevel > 7)
78324944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
78424944Seric 			naliases, longest, bytes);
78556795Seric # endif /* LOG */
786292Seric }
787292Seric /*
78858059Seric **  NIS_MAGIC -- Add NIS magic dbm data
78958059Seric **
79058059Seric **	This adds the magic entries needed by SunOS to make this a valid
79158059Seric **	NIS map.
79258059Seric **
79358059Seric **	Parameters:
79458059Seric **		dbmp -- a pointer to the DBM structure.
79558059Seric **
79658059Seric **	Returns:
79758059Seric **		none.
79858059Seric */
79958059Seric 
80058059Seric # ifdef YPCOMPAT
80158059Seric 
80258059Seric static void
80358059Seric nis_magic(dbmp)
80458059Seric 	DBM *dbmp;
80558059Seric {
80658059Seric 	int i;
80758059Seric 	static datum key[2] =
80858059Seric 	{
80958059Seric 		{ "YP_LAST_MODIFIED",	sizeof "YP_LAST_MODIFIED" - 1 },
81058059Seric 		{ "YP_MASTER_NAME",	sizeof "YP_MASTER_NAME" - 1 },
81158059Seric 	};
81258059Seric 	datum contents[2];
81358059Seric 	char tbuf[12];
81458059Seric 	char hbuf[MAXHOSTNAMELEN];
81558059Seric 
81658059Seric 	(void) sprintf(tbuf, "%010ld", curtime());
81758059Seric 	contents[0].dptr = tbuf;
81858059Seric 	contents[0].dsize = strlen(tbuf);
81958059Seric 
82058059Seric 	(void) myhostname(hbuf, sizeof hbuf);
82158059Seric 	contents[1].dptr = hbuf;
82258059Seric 	contents[1].dptr = strlen(hbuf);
82358059Seric 
82458059Seric 	for (i = 0; i < sizeof key / sizeof *key; i++)
82558059Seric 	{
82658059Seric 		if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 ||
82758059Seric 		    dbm_error(dbmp))
82858059Seric 			syserr("nis_magic: dbm_store failure");
82958059Seric 	}
83058059Seric }
83158059Seric 
83258059Seric # endif
83358059Seric /*
834292Seric **  FORWARD -- Try to forward mail
835292Seric **
836292Seric **	This is similar but not identical to aliasing.
837292Seric **
838292Seric **	Parameters:
8394314Seric **		user -- the name of the user who's mail we would like
8404314Seric **			to forward to.  It must have been verified --
8414314Seric **			i.e., the q_home field must have been filled
8424314Seric **			in.
8434999Seric **		sendq -- a pointer to the head of the send queue to
8444999Seric **			put this user's aliases in.
845292Seric **
846292Seric **	Returns:
8474098Seric **		none.
848292Seric **
849292Seric **	Side Effects:
8503185Seric **		New names are added to send queues.
851292Seric */
852292Seric 
85355012Seric forward(user, sendq, e)
8542966Seric 	ADDRESS *user;
8554999Seric 	ADDRESS **sendq;
85655012Seric 	register ENVELOPE *e;
857292Seric {
85857136Seric 	char *pp;
85957136Seric 	char *ep;
8604536Seric 	extern bool safefile();
8614069Seric 
8627671Seric 	if (tTd(27, 1))
8634098Seric 		printf("forward(%s)\n", user->q_paddr);
8644098Seric 
8654594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
8664098Seric 		return;
8674314Seric 	if (user->q_home == NULL)
86858059Seric 	{
8694314Seric 		syserr("forward: no home");
87058059Seric 		user->q_home = "/nosuchdirectory";
87158059Seric 	}
8724069Seric 
8734069Seric 	/* good address -- look for .forward file in home */
87455012Seric 	define('z', user->q_home, e);
87557136Seric 	define('u', user->q_user, e);
87657136Seric 	define('h', user->q_host, e);
87757136Seric 	if (ForwardPath == NULL)
87858050Seric 		ForwardPath = newstr("\201z/.forward");
87957136Seric 
88057136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
88157136Seric 	{
88257232Seric 		char buf[MAXPATHLEN+1];
88357136Seric 
88457136Seric 		ep = strchr(pp, ':');
88557136Seric 		if (ep != NULL)
88657136Seric 			*ep = '\0';
88757136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
88857136Seric 		if (ep != NULL)
88957136Seric 			*ep++ = ':';
89057136Seric 		if (tTd(27, 3))
89157136Seric 			printf("forward: trying %s\n", buf);
89257136Seric 		if (include(buf, TRUE, user, sendq, e) == 0)
89357136Seric 			break;
89457136Seric 	}
895292Seric }
896