xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 58065)
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*58065Seric static char sccsid[] = "@(#)alias.c	6.13 (Berkeley) 02/19/93 (with NEWDB and NDBM)";
3351756Seric #else
34*58065Seric static char sccsid[] = "@(#)alias.c	6.13 (Berkeley) 02/19/93 (with NEWDB)";
3557736Seric #endif
3657736Seric #else
3756845Seric #ifdef NDBM
38*58065Seric static char sccsid[] = "@(#)alias.c	6.13 (Berkeley) 02/19/93 (with NDBM)";
3933728Sbostic #else
40*58065Seric static char sccsid[] = "@(#)alias.c	6.13 (Berkeley) 02/19/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;
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 */
1214098Seric 	if (bitset(QDONTSEND, 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);
1457051Seric 	message(Arpa_Info, "aliased to %s", p);
14657977Seric #ifdef LOG
14758020Seric 	if (LogLevel > 9)
14857977Seric 		syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
14957977Seric #endif
1504098Seric 	AliasLevel++;
15155012Seric 	sendtolist(p, a, sendq, e);
1524098Seric 	AliasLevel--;
153*58065Seric 	if (!bitset(QSELFREF, a->q_flags))
154*58065Seric 	{
155*58065Seric 		if (tTd(27, 5))
156*58065Seric 		{
157*58065Seric 			printf("alias: QDONTSEND ");
158*58065Seric 			printaddr(a, FALSE);
159*58065Seric 		}
160*58065Seric 		a->q_flags |= QDONTSEND;
161*58065Seric 	}
1624098Seric }
1634098Seric /*
1645701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1655701Seric **
1665701Seric **	Parameters:
1675701Seric **		name -- the name to look up.
1685701Seric **
1695701Seric **	Returns:
1705701Seric **		the value of name.
1715701Seric **		NULL if unknown.
1725701Seric **
1735701Seric **	Side Effects:
1745701Seric **		none.
1755701Seric **
1765701Seric **	Warnings:
1775701Seric **		The return value will be trashed across calls.
1785701Seric */
1795701Seric 
1805701Seric char *
1815701Seric aliaslookup(name)
1825701Seric 	char *name;
1835701Seric {
18457381Seric 	int i;
18557381Seric 	char keybuf[MAXNAME + 1];
18656845Seric # if defined(NEWDB) || defined(NDBM)
18756845Seric 	DBdatum rhs, lhs;
18850575Seric 	int s;
18957381Seric # else /* neither NEWDB nor NDBM */
19057381Seric 	register STAB *s;
19157381Seric # endif
1925701Seric 
1935701Seric 	/* create a key for fetch */
19457381Seric 	i = strlen(name) + 1;
19557381Seric 	if (i > sizeof keybuf)
19657381Seric 		i = sizeof keybuf;
19757381Seric 	bcopy(name, keybuf, i);
19857381Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
19957381Seric 		makelower(keybuf);
20057381Seric 
20157381Seric # if defined(NEWDB) || defined(NDBM)
20257381Seric 	lhs.xx.size = i;
20357381Seric 	lhs.xx.data = keybuf;
20450575Seric # ifdef NEWDB
20551756Seric 	if (AliasDBptr != NULL)
20651756Seric 	{
20757381Seric 		i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
20857381Seric 		if (i == 0)
20956845Seric 			return (rhs.dbt.data);
21051756Seric 	}
21156845Seric # ifdef NDBM
21257249Seric 	else if (AliasDBMptr != NULL)
21351756Seric 	{
21456845Seric 		rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
21556845Seric 		return (rhs.dbm.dptr);
21651756Seric 	}
21756845Seric # endif /* NDBM */
21857530Seric 	return (NULL);
21956845Seric # else /* not NEWDB */
22056845Seric 	rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
22156845Seric 	return (rhs.dbm.dptr);
22256845Seric # endif /* NEWDB */
22356845Seric # else /* neither NEWDB nor NDBM */
22457381Seric 	s = stab(keybuf, ST_ALIAS, ST_FIND);
22551756Seric 	if (s != NULL)
22651756Seric 		return (s->s_alias);
22757530Seric 	return (NULL);
22851756Seric # endif
2295701Seric }
2305701Seric /*
2314098Seric **  INITALIASES -- initialize for aliasing
2324098Seric **
23356845Seric **	Very different depending on whether we are running NDBM or not.
2344098Seric **
2354098Seric **	Parameters:
2364098Seric **		aliasfile -- location of aliases.
23756845Seric **		init -- if set and if NDBM, initialize the NDBM files.
2384098Seric **
2394098Seric **	Returns:
2404098Seric **		none.
2414098Seric **
2424098Seric **	Side Effects:
2434098Seric **		initializes aliases:
24456845Seric **		if NDBM:  opens the database.
24556845Seric **		if ~NDBM: reads the aliases into the symbol table.
2464098Seric */
2474098Seric 
24840559Sbostic # define DBMMODE	0644
2494157Seric 
25055012Seric initaliases(aliasfile, init, e)
2514098Seric 	char *aliasfile;
2524157Seric 	bool init;
25355012Seric 	register ENVELOPE *e;
2544098Seric {
25556845Seric #if defined(NDBM) || defined(NEWDB)
2568437Seric 	int atcnt;
25725522Seric 	time_t modtime;
25825522Seric 	bool automatic = FALSE;
2594322Seric 	char buf[MAXNAME];
26050575Seric #endif
2619368Seric 	struct stat stb;
26227176Seric 	static bool initialized = FALSE;
26346928Sbostic 	static int readaliases();
2644322Seric 
26527176Seric 	if (initialized)
26627176Seric 		return;
26727176Seric 	initialized = TRUE;
26827176Seric 
26917984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2708437Seric 	{
27125522Seric 		if (aliasfile != NULL && init)
27225522Seric 			syserr("Cannot open %s", aliasfile);
2738437Seric 		NoAlias = TRUE;
27411937Seric 		errno = 0;
2758437Seric 		return;
2768437Seric 	}
2778437Seric 
27856845Seric # if defined(NDBM) || defined(NEWDB)
2794322Seric 	/*
2808437Seric 	**  Check to see that the alias file is complete.
2818437Seric 	**	If not, we will assume that someone died, and it is up
2828437Seric 	**	to us to rebuild it.
2838437Seric 	*/
2848437Seric 
28525689Seric 	if (!init)
28650575Seric 	{
28750575Seric # ifdef NEWDB
28850575Seric 		(void) strcpy(buf, aliasfile);
28950575Seric 		(void) strcat(buf, ".db");
29051171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
29150576Seric 		if (AliasDBptr == NULL)
29250576Seric 		{
29356845Seric # ifdef NDBM
29456845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
29557249Seric 			if (AliasDBMptr == NULL)
29657249Seric 			{
29757249Seric 				syserr("initaliases: cannot open %s", buf);
29857249Seric 				NoAlias = TRUE;
29957249Seric 				return;
30057249Seric 			}
30151756Seric # else
30250576Seric 			syserr("initaliases: cannot open %s", buf);
30350576Seric 			NoAlias = TRUE;
30450576Seric 			return;
30551756Seric # endif
30650576Seric 		}
30750575Seric # else
30856845Seric 		AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
30957249Seric 		if (AliasDBMptr == NULL)
31057249Seric 		{
31157977Seric 			syserr("initaliases: cannot open DBM database %s.{pag,dir}",
31257977Seric 				aliasfile);
31357249Seric 			NoAlias = TRUE;
31457249Seric 			return;
31557249Seric 		}
31650575Seric # endif
31750575Seric 	}
31817471Seric 	atcnt = SafeAlias * 2;
31917471Seric 	if (atcnt > 0)
32017471Seric 	{
32117471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
32225689Seric 		{
32325689Seric 			/*
32425689Seric 			**  Reinitialize alias file in case the new
32525689Seric 			**  one is mv'ed in instead of cp'ed in.
32625689Seric 			**
32725689Seric 			**	Only works with new DBM -- old one will
32825689Seric 			**	just consume file descriptors forever.
32925689Seric 			**	If you have a dbmclose() it can be
33025689Seric 			**	added before the sleep(30).
33125689Seric 			*/
33225689Seric 
33350575Seric # ifdef NEWDB
33451756Seric 			if (AliasDBptr != NULL)
33551756Seric 				AliasDBptr->close(AliasDBptr);
33650575Seric # endif
33756845Seric # ifdef NDBM
33856845Seric 			if (AliasDBMptr != NULL)
33956845Seric 				dbm_close(AliasDBMptr);
34056845Seric # endif
34150575Seric 
34217471Seric 			sleep(30);
34350575Seric # ifdef NEWDB
34450575Seric 			(void) strcpy(buf, aliasfile);
34550575Seric 			(void) strcat(buf, ".db");
34651171Sbostic 			AliasDBptr =
34751171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
34850576Seric 			if (AliasDBptr == NULL)
34950576Seric 			{
35051756Seric # ifdef NDBM
35156845Seric 				AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
35251756Seric # else
35350576Seric 				syserr("initaliases: cannot open %s", buf);
35450576Seric 				NoAlias = TRUE;
35550576Seric 				return;
35651756Seric # endif
35750576Seric 			}
35850575Seric # else
35925689Seric # ifdef NDBM
36056845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
36157249Seric 			if (AliasDBMptr == NULL)
36257249Seric 			{
36358008Seric 				syserr("initaliases: cannot open DBM database %s.{pag,dir}",
36458008Seric 					aliasfile);
36557249Seric 				NoAlias = TRUE;
36657249Seric 				return;
36757249Seric 			}
36850575Seric # endif
36950575Seric # endif
37025689Seric 		}
37117471Seric 	}
37217471Seric 	else
37317471Seric 		atcnt = 1;
3748437Seric 
3758437Seric 	/*
37656845Seric 	**  See if the NDBM version of the file is out of date with
3774322Seric 	**  the text version.  If so, go into 'init' mode automatically.
37840559Sbostic 	**	This only happens if our effective userid owns the DBM.
37940559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
3804322Seric 	*/
3814322Seric 
3824322Seric 	modtime = stb.st_mtime;
3834322Seric 	(void) strcpy(buf, aliasfile);
38450575Seric # ifdef NEWDB
38550575Seric 	(void) strcat(buf, ".db");
38650575Seric # else
3874322Seric 	(void) strcat(buf, ".pag");
38850575Seric # endif
3894322Seric 	stb.st_ino = 0;
39019039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
3914322Seric 	{
39211937Seric 		errno = 0;
39340559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3944322Seric 		{
3954322Seric 			init = TRUE;
39625522Seric 			automatic = TRUE;
3977051Seric 			message(Arpa_Info, "rebuilding alias database");
39824944Seric #ifdef LOG
39958020Seric 			if (LogLevel > 14)
40024944Seric 				syslog(LOG_INFO, "rebuilding alias database");
40156795Seric #endif /* LOG */
4024322Seric 		}
4034322Seric 		else
4044322Seric 		{
40519039Seric #ifdef LOG
40658020Seric 			if (LogLevel > 3)
40724944Seric 				syslog(LOG_INFO, "alias database out of date");
40856795Seric #endif /* LOG */
4094322Seric 			message(Arpa_Info, "Warning: alias database out of date");
4104322Seric 		}
4114322Seric 	}
4124322Seric 
4134322Seric 
4144322Seric 	/*
41556845Seric 	**  If necessary, load the NDBM file.
41656845Seric 	**	If running without NDBM, load the symbol table.
4174322Seric 	*/
4184322Seric 
4194157Seric 	if (init)
4208437Seric 	{
42125522Seric #ifdef LOG
42258020Seric 		if (LogLevel > 7)
42325522Seric 		{
42425522Seric 			extern char *username();
42525522Seric 
42625522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
42725522Seric 				automatic ? "auto" : "", username());
42825522Seric 		}
42956795Seric #endif /* LOG */
43055012Seric 		readaliases(aliasfile, TRUE, e);
4318437Seric 	}
43256845Seric # else /* NDBM */
43355012Seric 	readaliases(aliasfile, init, e);
43456845Seric # endif /* NDBM */
4354157Seric }
4364157Seric /*
4374157Seric **  READALIASES -- read and process the alias file.
4384157Seric **
4394157Seric **	This routine implements the part of initaliases that occurs
4404157Seric **	when we are not going to use the DBM stuff.
4414157Seric **
4424157Seric **	Parameters:
4434157Seric **		aliasfile -- the pathname of the alias file master.
44456845Seric **		init -- if set, initialize the NDBM stuff.
4454157Seric **
4464157Seric **	Returns:
4474157Seric **		none.
4484157Seric **
4494157Seric **	Side Effects:
4504157Seric **		Reads aliasfile into the symbol table.
4514157Seric **		Optionally, builds the .dir & .pag files.
4524157Seric */
4534157Seric 
4544157Seric static
45555012Seric readaliases(aliasfile, init, e)
4564157Seric 	char *aliasfile;
4574157Seric 	bool init;
45855012Seric 	register ENVELOPE *e;
4594157Seric {
4604098Seric 	register char *p;
4614098Seric 	char *rhs;
4624098Seric 	bool skipping;
4639368Seric 	int naliases, bytes, longest;
4649368Seric 	FILE *af;
46553742Seric 	bool makedbmfiles;
46640970Sbostic 	void (*oldsigint)();
4674098Seric 	ADDRESS al, bl;
4684106Seric 	register STAB *s;
46950575Seric # ifdef NEWDB
47050575Seric 	DB *dbp;
47150575Seric # endif
47256845Seric # ifdef NDBM
47356845Seric 	DBM *dbmp;
47456845Seric # endif
47551937Seric # ifdef LOCKF
47651937Seric 	struct flock fld;
47751937Seric # endif
4789368Seric 	char line[BUFSIZ];
4794098Seric 
48051937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
4811515Seric 	{
48257249Seric 		if (init)
48357249Seric 			syserr("Can't open %s", aliasfile);
48457249Seric 		else if (tTd(27, 1))
4854106Seric 			printf("Can't open %s\n", aliasfile);
4864098Seric 		errno = 0;
4874098Seric 		NoAlias++;
4884098Seric 		return;
4894098Seric 	}
4904314Seric 
49156845Seric # if defined(NDBM) || defined(NEWDB)
49219784Seric 	/* see if someone else is rebuilding the alias file already */
49351835Seric # ifdef LOCKF
49451937Seric 	fld.l_type = F_WRLCK;
49551937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
49651937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
49751835Seric # else
49819784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
49951835Seric # endif
50019784Seric 	{
50119784Seric 		/* yes, they are -- wait until done and then return */
50219784Seric 		message(Arpa_Info, "Alias file is already being rebuilt");
50319784Seric 		if (OpMode != MD_INITALIAS)
50419784Seric 		{
50519784Seric 			/* wait for other rebuild to complete */
50651835Seric # ifdef LOCKF
50751937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
50851835Seric # else
50919784Seric 			(void) flock(fileno(af), LOCK_EX);
51051835Seric # endif
51119784Seric 		}
51223108Seric 		(void) fclose(af);
51319784Seric 		errno = 0;
51419784Seric 		return;
51519784Seric 	}
51656845Seric # endif /* NDBM */
51719784Seric 
5184314Seric 	/*
51919784Seric 	**  If initializing, create the new DBM files.
52019784Seric 	*/
52119784Seric 
52219784Seric 	if (init)
52319784Seric 	{
52419784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
52551756Seric # ifdef NEWDB
52651756Seric 		(void) strcpy(line, aliasfile);
52751756Seric 		(void) strcat(line, ".db");
52851756Seric 		dbp = dbopen(line,
52951756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
53051756Seric 		if (dbp == NULL)
53151756Seric 		{
53251756Seric 			syserr("readaliases: cannot create %s", line);
53351756Seric 			(void) signal(SIGINT, oldsigint);
53451756Seric 			return;
53551756Seric 		}
53653742Seric # endif
53753742Seric # ifdef IF_MAKEDBMFILES
53853742Seric # ifdef NEWDB
53953742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
54053742Seric # endif
54153742Seric 		IF_MAKEDBMFILES
54219784Seric 		{
54356845Seric 			dbmp = dbm_open(aliasfile,
54456845Seric 					       O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
54556845Seric 			if (dbmp == NULL)
54653742Seric 			{
54756845Seric 				syserr("readaliases: cannot create %s.{dir,pag}",
54856845Seric 					aliasfile);
54953742Seric 				(void) signal(SIGINT, oldsigint);
55053742Seric 				return;
55153742Seric 			}
55219784Seric 		}
55350575Seric # endif
55419784Seric 	}
55519784Seric 
55619784Seric 	/*
5574314Seric 	**  Read and interpret lines
5584314Seric 	*/
5594314Seric 
5609368Seric 	FileName = aliasfile;
5619368Seric 	LineNumber = 0;
5624322Seric 	naliases = bytes = longest = 0;
5634098Seric 	skipping = FALSE;
5644098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5654098Seric 	{
5664322Seric 		int lhssize, rhssize;
5674322Seric 
5689368Seric 		LineNumber++;
56956795Seric 		p = strchr(line, '\n');
57025278Seric 		if (p != NULL)
57125278Seric 			*p = '\0';
5724098Seric 		switch (line[0])
5734098Seric 		{
5744098Seric 		  case '#':
5754098Seric 		  case '\0':
5764098Seric 			skipping = FALSE;
5774098Seric 			continue;
5784065Seric 
5794098Seric 		  case ' ':
5804098Seric 		  case '\t':
5814098Seric 			if (!skipping)
5829368Seric 				syserr("Non-continuation line starts with space");
5834098Seric 			skipping = TRUE;
5844097Seric 			continue;
5854098Seric 		}
5864098Seric 		skipping = FALSE;
5871874Seric 
5884314Seric 		/*
5894314Seric 		**  Process the LHS
59057736Seric 		**	Find the colon separator, and parse the address.
59116898Seric 		**	It should resolve to a local name -- this will
59216898Seric 		**	be checked later (we want to optionally do
59316898Seric 		**	parsing of the RHS first to maximize error
59416898Seric 		**	detection).
5954314Seric 		*/
5964314Seric 
5974098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5984097Seric 			continue;
59916898Seric 		if (*p++ != ':')
6004098Seric 		{
6019368Seric 			syserr("missing colon");
6024097Seric 			continue;
6034098Seric 		}
60455012Seric 		if (parseaddr(line, &al, 1, ':', e) == NULL)
6054098Seric 		{
60616898Seric 			syserr("illegal alias name");
60716898Seric 			continue;
6084098Seric 		}
60916898Seric 		loweraddr(&al);
6104314Seric 
6114314Seric 		/*
6124314Seric 		**  Process the RHS.
6134314Seric 		**	'al' is the internal form of the LHS address.
6144314Seric 		**	'p' points to the text of the RHS.
6154314Seric 		*/
6164314Seric 
6174098Seric 		rhs = p;
6184098Seric 		for (;;)
6194098Seric 		{
6204098Seric 			register char c;
6211515Seric 
62225821Seric 			if (init && CheckAliases)
6234098Seric 			{
6244157Seric 				/* do parsing & compression of addresses */
62525278Seric 				while (*p != '\0')
6264098Seric 				{
62725278Seric 					extern char *DelimChar;
62825278Seric 
62958050Seric 					while ((isascii(*p) && isspace(*p)) ||
63058050Seric 								*p == ',')
6314157Seric 						p++;
63225278Seric 					if (*p == '\0')
63325278Seric 						break;
63455012Seric 					if (parseaddr(p, &bl, -1, ',', e) == NULL)
63525278Seric 						usrerr("%s... bad address", p);
63625278Seric 					p = DelimChar;
6374098Seric 				}
6384098Seric 			}
6394157Seric 			else
64015769Seric 			{
64116898Seric 				p = &p[strlen(p)];
64216898Seric 				if (p[-1] == '\n')
64316898Seric 					*--p = '\0';
64415769Seric 			}
6451515Seric 
6464098Seric 			/* see if there should be a continuation line */
6474106Seric 			c = fgetc(af);
6484106Seric 			if (!feof(af))
6494314Seric 				(void) ungetc(c, af);
6504106Seric 			if (c != ' ' && c != '\t')
6514098Seric 				break;
6524098Seric 
6534098Seric 			/* read continuation line */
6544098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6554098Seric 				break;
6569368Seric 			LineNumber++;
65757135Seric 
65857135Seric 			/* check for line overflow */
65957135Seric 			if (strchr(p, '\n') == NULL)
66057135Seric 			{
66157135Seric 				usrerr("alias too long");
66257135Seric 				break;
66357135Seric 			}
6644098Seric 		}
66516898Seric 		if (al.q_mailer != LocalMailer)
66616898Seric 		{
66716898Seric 			syserr("cannot alias non-local names");
66816898Seric 			continue;
66916898Seric 		}
6704314Seric 
6714314Seric 		/*
6724314Seric 		**  Insert alias into symbol table or DBM file
6734314Seric 		*/
6744314Seric 
67516898Seric 		lhssize = strlen(al.q_user) + 1;
67657381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
67757381Seric 			makelower(al.q_user);
6784322Seric 		rhssize = strlen(rhs) + 1;
6794322Seric 
68056845Seric # if defined(NDBM) || defined(NEWDB)
6814157Seric 		if (init)
6824157Seric 		{
68356845Seric 			DBdatum key, content;
68457381Seric 			int putstat;
6854157Seric 
68656845Seric 			key.xx.size = lhssize;
68756845Seric 			key.xx.data = al.q_user;
68856845Seric 			content.xx.size = rhssize;
68956845Seric 			content.xx.data = rhs;
69051756Seric # ifdef NEWDB
69157381Seric 			putstat = dbp->put(dbp, &key.dbt, &content.dbt,
69257381Seric 					   R_NOOVERWRITE);
69357381Seric 			if (putstat > 0)
69457381Seric 			{
69557977Seric 				usrerr("050 Warning: duplicate alias name %s",
69657381Seric 					al.q_user);
69757381Seric 				putstat = dbp->put(dbp, &key.dbt,
69857381Seric 						   &content.dbt, 0);
69957381Seric 			}
70057381Seric 			if (putstat != 0)
70150576Seric 				syserr("readaliases: db put (%s)", al.q_user);
70250575Seric # endif
70353742Seric # ifdef IF_MAKEDBMFILES
70453742Seric 			IF_MAKEDBMFILES
70557381Seric 			{
70657381Seric 				putstat = dbm_store(dbmp, key.dbm, content.dbm,
70757381Seric 						    DBM_INSERT);
70857381Seric 				if (putstat > 0)
70957381Seric 				{
71057977Seric 					usrerr("050 Warning: duplicate alias name %s",
71157381Seric 						al.q_user);
71257381Seric 					putstat = dbm_store(dbmp, key.dbm,
71357381Seric 							content.dbm, DBM_REPLACE);
71457381Seric 				}
71557381Seric 				if (putstat != 0)
71656845Seric 					syserr("readaliases: dbm store (%s)",
71756845Seric 						al.q_user);
71857381Seric 			}
71953742Seric # endif
72057381Seric 			if (al.q_paddr != NULL)
72157381Seric 				free(al.q_paddr);
72257381Seric 			if (al.q_host != NULL)
72357381Seric 				free(al.q_host);
72457381Seric 			if (al.q_user != NULL)
72557381Seric 				free(al.q_user);
7264157Seric 		}
7274157Seric 		else
72856845Seric # endif /* NDBM */
7294157Seric 		{
7304157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
7314157Seric 			s->s_alias = newstr(rhs);
7324157Seric 		}
7334322Seric 
7344322Seric 		/* statistics */
7354322Seric 		naliases++;
7364322Seric 		bytes += lhssize + rhssize;
7374322Seric 		if (rhssize > longest)
7384322Seric 			longest = rhssize;
7391515Seric 	}
74019784Seric 
74156845Seric # if defined(NDBM) || defined(NEWDB)
74219784Seric 	if (init)
74319784Seric 	{
74419784Seric 		/* add the distinquished alias "@" */
74556845Seric 		DBdatum key;
74619784Seric 
74756845Seric 		key.xx.size = 2;
74856845Seric 		key.xx.data = "@";
74950575Seric # ifdef NEWDB
75050576Seric 		if (dbp->sync(dbp) != 0 ||
75156845Seric 		    dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
75250576Seric 		    dbp->close(dbp) != 0)
75350576Seric 			syserr("readaliases: db close failure");
75453742Seric # endif
75556789Seric # ifdef IF_MAKEDBMFILES
75656793Seric 		IF_MAKEDBMFILES
75756845Seric 		{
75858059Seric #ifdef YPCOMPAT
75958059Seric 			nis_magic(dbmp);
76058059Seric #endif
76156845Seric 			if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
76256845Seric 			    dbm_error(dbmp))
76356845Seric 				syserr("readaliases: dbm close failure");
76456845Seric 			dbm_close(dbmp);
76556845Seric 		}
76650575Seric # endif
76719784Seric 
76819784Seric 		/* restore the old signal */
76919784Seric 		(void) signal(SIGINT, oldsigint);
77019784Seric 	}
77156845Seric # endif /* NDBM */
77219784Seric 
77319784Seric 	/* closing the alias file drops the lock */
7744098Seric 	(void) fclose(af);
77555012Seric 	e->e_to = NULL;
7769368Seric 	FileName = NULL;
7777051Seric 	message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
7784322Seric 			naliases, longest, bytes);
77924944Seric # ifdef LOG
78058020Seric 	if (LogLevel > 7)
78124944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
78224944Seric 			naliases, longest, bytes);
78356795Seric # endif /* LOG */
784292Seric }
785292Seric /*
78658059Seric **  NIS_MAGIC -- Add NIS magic dbm data
78758059Seric **
78858059Seric **	This adds the magic entries needed by SunOS to make this a valid
78958059Seric **	NIS map.
79058059Seric **
79158059Seric **	Parameters:
79258059Seric **		dbmp -- a pointer to the DBM structure.
79358059Seric **
79458059Seric **	Returns:
79558059Seric **		none.
79658059Seric */
79758059Seric 
79858059Seric # ifdef YPCOMPAT
79958059Seric 
80058059Seric static void
80158059Seric nis_magic(dbmp)
80258059Seric 	DBM *dbmp;
80358059Seric {
80458059Seric 	int i;
80558059Seric 	static datum key[2] =
80658059Seric 	{
80758059Seric 		{ "YP_LAST_MODIFIED",	sizeof "YP_LAST_MODIFIED" - 1 },
80858059Seric 		{ "YP_MASTER_NAME",	sizeof "YP_MASTER_NAME" - 1 },
80958059Seric 	};
81058059Seric 	datum contents[2];
81158059Seric 	char tbuf[12];
81258059Seric 	char hbuf[MAXHOSTNAMELEN];
81358059Seric 
81458059Seric 	(void) sprintf(tbuf, "%010ld", curtime());
81558059Seric 	contents[0].dptr = tbuf;
81658059Seric 	contents[0].dsize = strlen(tbuf);
81758059Seric 
81858059Seric 	(void) myhostname(hbuf, sizeof hbuf);
81958059Seric 	contents[1].dptr = hbuf;
82058059Seric 	contents[1].dptr = strlen(hbuf);
82158059Seric 
82258059Seric 	for (i = 0; i < sizeof key / sizeof *key; i++)
82358059Seric 	{
82458059Seric 		if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 ||
82558059Seric 		    dbm_error(dbmp))
82658059Seric 			syserr("nis_magic: dbm_store failure");
82758059Seric 	}
82858059Seric }
82958059Seric 
83058059Seric # endif
83158059Seric /*
832292Seric **  FORWARD -- Try to forward mail
833292Seric **
834292Seric **	This is similar but not identical to aliasing.
835292Seric **
836292Seric **	Parameters:
8374314Seric **		user -- the name of the user who's mail we would like
8384314Seric **			to forward to.  It must have been verified --
8394314Seric **			i.e., the q_home field must have been filled
8404314Seric **			in.
8414999Seric **		sendq -- a pointer to the head of the send queue to
8424999Seric **			put this user's aliases in.
843292Seric **
844292Seric **	Returns:
8454098Seric **		none.
846292Seric **
847292Seric **	Side Effects:
8483185Seric **		New names are added to send queues.
849292Seric */
850292Seric 
85155012Seric forward(user, sendq, e)
8522966Seric 	ADDRESS *user;
8534999Seric 	ADDRESS **sendq;
85455012Seric 	register ENVELOPE *e;
855292Seric {
85657136Seric 	char *pp;
85757136Seric 	char *ep;
8584536Seric 	extern bool safefile();
8594069Seric 
8607671Seric 	if (tTd(27, 1))
8614098Seric 		printf("forward(%s)\n", user->q_paddr);
8624098Seric 
8634594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
8644098Seric 		return;
8654314Seric 	if (user->q_home == NULL)
86658059Seric 	{
8674314Seric 		syserr("forward: no home");
86858059Seric 		user->q_home = "/nosuchdirectory";
86958059Seric 	}
8704069Seric 
8714069Seric 	/* good address -- look for .forward file in home */
87255012Seric 	define('z', user->q_home, e);
87357136Seric 	define('u', user->q_user, e);
87457136Seric 	define('h', user->q_host, e);
87557136Seric 	if (ForwardPath == NULL)
87658050Seric 		ForwardPath = newstr("\201z/.forward");
87757136Seric 
87857136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
87957136Seric 	{
88057232Seric 		char buf[MAXPATHLEN+1];
88157136Seric 
88257136Seric 		ep = strchr(pp, ':');
88357136Seric 		if (ep != NULL)
88457136Seric 			*ep = '\0';
88557136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
88657136Seric 		if (ep != NULL)
88757136Seric 			*ep++ = ':';
88857136Seric 		if (tTd(27, 3))
88957136Seric 			printf("forward: trying %s\n", buf);
89057136Seric 		if (include(buf, TRUE, user, sendq, e) == 0)
89157136Seric 			break;
89257136Seric 	}
893292Seric }
894