xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 58170)
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*58170Seric static char sccsid[] = "@(#)alias.c	6.18 (Berkeley) 02/24/93 (with NEWDB and NDBM)";
3351756Seric #else
34*58170Seric static char sccsid[] = "@(#)alias.c	6.18 (Berkeley) 02/24/93 (with NEWDB)";
3557736Seric #endif
3657736Seric #else
3756845Seric #ifdef NDBM
38*58170Seric static char sccsid[] = "@(#)alias.c	6.18 (Berkeley) 02/24/93 (with NDBM)";
3933728Sbostic #else
40*58170Seric static char sccsid[] = "@(#)alias.c	6.18 (Berkeley) 02/24/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.
5558092Seric **		e -- the current envelope.
56292Seric **
57292Seric **	Returns:
58292Seric **		none
59292Seric **
60292Seric **	Side Effects:
613185Seric **		Aliases found are expanded.
62292Seric **
63292Seric **	Notes:
64292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
65292Seric **			done.
66292Seric **
67292Seric **	Deficiencies:
68292Seric **		It should complain about names that are aliased to
69292Seric **			nothing.
70292Seric */
71292Seric 
72292Seric 
7353742Seric /*
7453742Seric **  Sun YP servers read the dbm files directly, so we have to build them
7553742Seric **  even if NEWDB
7653742Seric */
7753742Seric 
7856845Seric #ifdef NDBM
7953742Seric # ifndef NEWDB
8053742Seric #  define IF_MAKEDBMFILES
8153742Seric # else
8253742Seric #  ifdef YPCOMPAT
8353742Seric #   define IF_MAKEDBMFILES		if (makedbmfiles)
8453742Seric #  endif
8553742Seric # endif
8653742Seric #endif
8753742Seric 
8856845Seric typedef union
892966Seric {
9056845Seric #ifdef NDBM
9156845Seric 	datum	dbm;
9251756Seric #endif
9356845Seric #ifdef NEWDB
9456845Seric 	DBT	dbt;
9556845Seric #endif
9656845Seric 	struct
9756845Seric 	{
9856845Seric 		char	*data;
9956845Seric 		int	size;
10056845Seric 	} xx;
10156845Seric } DBdatum;
102292Seric 
10350575Seric #ifdef NEWDB
10450575Seric static DB	*AliasDBptr;
10550575Seric #endif
10656845Seric #ifdef NDBM
10756845Seric static DBM	*AliasDBMptr;
10856845Seric #endif
10950575Seric 
11055012Seric alias(a, sendq, e)
1114097Seric 	register ADDRESS *a;
1124999Seric 	ADDRESS **sendq;
11355012Seric 	register ENVELOPE *e;
114292Seric {
1154081Seric 	register char *p;
11658082Seric 	int naliases;
117*58170Seric 	char *owner;
118*58170Seric 	char obuf[MAXNAME + 6];
1195701Seric 	extern char *aliaslookup();
120292Seric 
1217671Seric 	if (tTd(27, 1))
1224098Seric 		printf("alias(%s)\n", a->q_paddr);
123292Seric 
1244098Seric 	/* don't realias already aliased names */
12558154Seric 	if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
1264098Seric 		return;
1274098Seric 
12855012Seric 	e->e_to = a->q_paddr;
1294098Seric 
1304314Seric 	/*
1314314Seric 	**  Look up this name
1324314Seric 	*/
1334314Seric 
13424944Seric 	if (NoAlias)
13524944Seric 		p = NULL;
13624944Seric 	else
13724944Seric 		p = aliaslookup(a->q_user);
1384098Seric 	if (p == NULL)
1394098Seric 		return;
140292Seric 
141292Seric 	/*
1424098Seric 	**  Match on Alias.
1434098Seric 	**	Deliver to the target list.
1441515Seric 	*/
1451515Seric 
1467671Seric 	if (tTd(27, 1))
1474098Seric 		printf("%s (%s, %s) aliased to %s\n",
1484098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
14958092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
15058154Seric 	{
15158154Seric 		a->q_flags |= QVERIFIED;
15258092Seric 		return;
15358154Seric 	}
15458154Seric 	message("aliased to %s", p);
15557977Seric #ifdef LOG
15658020Seric 	if (LogLevel > 9)
15757977Seric 		syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
15857977Seric #endif
15958082Seric 	a->q_flags &= ~QSELFREF;
1604098Seric 	AliasLevel++;
16158082Seric 	naliases = sendtolist(p, a, sendq, e);
1624098Seric 	AliasLevel--;
16358082Seric 	if (naliases > 0 && !bitset(QSELFREF, a->q_flags))
16458065Seric 	{
16558065Seric 		if (tTd(27, 5))
16658065Seric 		{
16758065Seric 			printf("alias: QDONTSEND ");
16858065Seric 			printaddr(a, FALSE);
16958065Seric 		}
17058065Seric 		a->q_flags |= QDONTSEND;
17158065Seric 	}
172*58170Seric 
173*58170Seric 	/*
174*58170Seric 	**  Look for owner of alias
175*58170Seric 	*/
176*58170Seric 
177*58170Seric 	(void) strcpy(obuf, "owner-");
178*58170Seric 	if (strncmp(a->q_user, "owner-", 6) == 0)
179*58170Seric 		(void) strcat(obuf, "owner");
180*58170Seric 	else
181*58170Seric 		(void) strcat(obuf, a->q_user);
182*58170Seric 	if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
183*58170Seric 		makelower(obuf);
184*58170Seric 	owner = aliaslookup(obuf);
185*58170Seric 	if (owner != NULL)
186*58170Seric 	{
187*58170Seric 		if (strchr(owner, ',') != NULL)
188*58170Seric 			owner = obuf;
189*58170Seric 		a->q_owner = newstr(owner);
190*58170Seric 	}
1914098Seric }
1924098Seric /*
1935701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1945701Seric **
1955701Seric **	Parameters:
1965701Seric **		name -- the name to look up.
1975701Seric **
1985701Seric **	Returns:
1995701Seric **		the value of name.
2005701Seric **		NULL if unknown.
2015701Seric **
2025701Seric **	Side Effects:
2035701Seric **		none.
2045701Seric **
2055701Seric **	Warnings:
2065701Seric **		The return value will be trashed across calls.
2075701Seric */
2085701Seric 
2095701Seric char *
2105701Seric aliaslookup(name)
2115701Seric 	char *name;
2125701Seric {
21357381Seric 	int i;
21457381Seric 	char keybuf[MAXNAME + 1];
21556845Seric # if defined(NEWDB) || defined(NDBM)
21656845Seric 	DBdatum rhs, lhs;
21750575Seric 	int s;
21857381Seric # else /* neither NEWDB nor NDBM */
21957381Seric 	register STAB *s;
22057381Seric # endif
2215701Seric 
2225701Seric 	/* create a key for fetch */
22357381Seric 	i = strlen(name) + 1;
22457381Seric 	if (i > sizeof keybuf)
22557381Seric 		i = sizeof keybuf;
22657381Seric 	bcopy(name, keybuf, i);
22757381Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
22857381Seric 		makelower(keybuf);
22957381Seric 
23057381Seric # if defined(NEWDB) || defined(NDBM)
23157381Seric 	lhs.xx.size = i;
23257381Seric 	lhs.xx.data = keybuf;
23350575Seric # ifdef NEWDB
23451756Seric 	if (AliasDBptr != NULL)
23551756Seric 	{
23657381Seric 		i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
23757381Seric 		if (i == 0)
23856845Seric 			return (rhs.dbt.data);
23951756Seric 	}
24056845Seric # ifdef NDBM
24157249Seric 	else if (AliasDBMptr != NULL)
24251756Seric 	{
24356845Seric 		rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
24456845Seric 		return (rhs.dbm.dptr);
24551756Seric 	}
24656845Seric # endif /* NDBM */
24757530Seric 	return (NULL);
24856845Seric # else /* not NEWDB */
24956845Seric 	rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
25056845Seric 	return (rhs.dbm.dptr);
25156845Seric # endif /* NEWDB */
25256845Seric # else /* neither NEWDB nor NDBM */
25357381Seric 	s = stab(keybuf, ST_ALIAS, ST_FIND);
25451756Seric 	if (s != NULL)
25551756Seric 		return (s->s_alias);
25657530Seric 	return (NULL);
25751756Seric # endif
2585701Seric }
2595701Seric /*
2604098Seric **  INITALIASES -- initialize for aliasing
2614098Seric **
26256845Seric **	Very different depending on whether we are running NDBM or not.
2634098Seric **
2644098Seric **	Parameters:
2654098Seric **		aliasfile -- location of aliases.
26656845Seric **		init -- if set and if NDBM, initialize the NDBM files.
2674098Seric **
2684098Seric **	Returns:
2694098Seric **		none.
2704098Seric **
2714098Seric **	Side Effects:
2724098Seric **		initializes aliases:
27356845Seric **		if NDBM:  opens the database.
27456845Seric **		if ~NDBM: reads the aliases into the symbol table.
2754098Seric */
2764098Seric 
27740559Sbostic # define DBMMODE	0644
2784157Seric 
27955012Seric initaliases(aliasfile, init, e)
2804098Seric 	char *aliasfile;
2814157Seric 	bool init;
28255012Seric 	register ENVELOPE *e;
2834098Seric {
28456845Seric #if defined(NDBM) || defined(NEWDB)
2858437Seric 	int atcnt;
28625522Seric 	time_t modtime;
28725522Seric 	bool automatic = FALSE;
2884322Seric 	char buf[MAXNAME];
28950575Seric #endif
2909368Seric 	struct stat stb;
29127176Seric 	static bool initialized = FALSE;
29246928Sbostic 	static int readaliases();
2934322Seric 
29427176Seric 	if (initialized)
29527176Seric 		return;
29627176Seric 	initialized = TRUE;
29727176Seric 
29817984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2998437Seric 	{
30025522Seric 		if (aliasfile != NULL && init)
30158151Seric 			syserr("554 Cannot open %s", aliasfile);
3028437Seric 		NoAlias = TRUE;
30311937Seric 		errno = 0;
3048437Seric 		return;
3058437Seric 	}
3068437Seric 
30756845Seric # if defined(NDBM) || defined(NEWDB)
3084322Seric 	/*
3098437Seric 	**  Check to see that the alias file is complete.
3108437Seric 	**	If not, we will assume that someone died, and it is up
3118437Seric 	**	to us to rebuild it.
3128437Seric 	*/
3138437Seric 
31425689Seric 	if (!init)
31550575Seric 	{
31650575Seric # ifdef NEWDB
31750575Seric 		(void) strcpy(buf, aliasfile);
31850575Seric 		(void) strcat(buf, ".db");
31951171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
32050576Seric 		if (AliasDBptr == NULL)
32150576Seric 		{
32256845Seric # ifdef NDBM
32356845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
32457249Seric 			if (AliasDBMptr == NULL)
32557249Seric 			{
32657249Seric 				syserr("initaliases: cannot open %s", buf);
32757249Seric 				NoAlias = TRUE;
32857249Seric 				return;
32957249Seric 			}
33051756Seric # else
33150576Seric 			syserr("initaliases: cannot open %s", buf);
33250576Seric 			NoAlias = TRUE;
33350576Seric 			return;
33451756Seric # endif
33550576Seric 		}
33650575Seric # else
33756845Seric 		AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
33857249Seric 		if (AliasDBMptr == NULL)
33957249Seric 		{
34057977Seric 			syserr("initaliases: cannot open DBM database %s.{pag,dir}",
34157977Seric 				aliasfile);
34257249Seric 			NoAlias = TRUE;
34357249Seric 			return;
34457249Seric 		}
34550575Seric # endif
34650575Seric 	}
34717471Seric 	atcnt = SafeAlias * 2;
34817471Seric 	if (atcnt > 0)
34917471Seric 	{
35017471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
35125689Seric 		{
35225689Seric 			/*
35325689Seric 			**  Reinitialize alias file in case the new
35425689Seric 			**  one is mv'ed in instead of cp'ed in.
35525689Seric 			**
35625689Seric 			**	Only works with new DBM -- old one will
35725689Seric 			**	just consume file descriptors forever.
35825689Seric 			**	If you have a dbmclose() it can be
35925689Seric 			**	added before the sleep(30).
36025689Seric 			*/
36125689Seric 
36250575Seric # ifdef NEWDB
36351756Seric 			if (AliasDBptr != NULL)
36451756Seric 				AliasDBptr->close(AliasDBptr);
36550575Seric # endif
36656845Seric # ifdef NDBM
36756845Seric 			if (AliasDBMptr != NULL)
36856845Seric 				dbm_close(AliasDBMptr);
36956845Seric # endif
37050575Seric 
37117471Seric 			sleep(30);
37250575Seric # ifdef NEWDB
37350575Seric 			(void) strcpy(buf, aliasfile);
37450575Seric 			(void) strcat(buf, ".db");
37551171Sbostic 			AliasDBptr =
37651171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
37750576Seric 			if (AliasDBptr == NULL)
37850576Seric 			{
37951756Seric # ifdef NDBM
38056845Seric 				AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
38151756Seric # else
38250576Seric 				syserr("initaliases: cannot open %s", buf);
38350576Seric 				NoAlias = TRUE;
38450576Seric 				return;
38551756Seric # endif
38650576Seric 			}
38750575Seric # else
38825689Seric # ifdef NDBM
38956845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
39057249Seric 			if (AliasDBMptr == NULL)
39157249Seric 			{
39258008Seric 				syserr("initaliases: cannot open DBM database %s.{pag,dir}",
39358008Seric 					aliasfile);
39457249Seric 				NoAlias = TRUE;
39557249Seric 				return;
39657249Seric 			}
39750575Seric # endif
39850575Seric # endif
39925689Seric 		}
40017471Seric 	}
40117471Seric 	else
40217471Seric 		atcnt = 1;
4038437Seric 
4048437Seric 	/*
40556845Seric 	**  See if the NDBM version of the file is out of date with
4064322Seric 	**  the text version.  If so, go into 'init' mode automatically.
40740559Sbostic 	**	This only happens if our effective userid owns the DBM.
40840559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
4094322Seric 	*/
4104322Seric 
4114322Seric 	modtime = stb.st_mtime;
4124322Seric 	(void) strcpy(buf, aliasfile);
41350575Seric # ifdef NEWDB
41450575Seric 	(void) strcat(buf, ".db");
41550575Seric # else
4164322Seric 	(void) strcat(buf, ".pag");
41750575Seric # endif
4184322Seric 	stb.st_ino = 0;
41919039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
4204322Seric 	{
42111937Seric 		errno = 0;
42240559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
4234322Seric 		{
4244322Seric 			init = TRUE;
42525522Seric 			automatic = TRUE;
42658151Seric 			message("rebuilding alias database");
42724944Seric #ifdef LOG
42858020Seric 			if (LogLevel > 14)
42924944Seric 				syslog(LOG_INFO, "rebuilding alias database");
43056795Seric #endif /* LOG */
4314322Seric 		}
4324322Seric 		else
4334322Seric 		{
43419039Seric #ifdef LOG
43558020Seric 			if (LogLevel > 3)
43624944Seric 				syslog(LOG_INFO, "alias database out of date");
43756795Seric #endif /* LOG */
43858151Seric 			message("Warning: alias database out of date");
4394322Seric 		}
4404322Seric 	}
4414322Seric 
4424322Seric 
4434322Seric 	/*
44456845Seric 	**  If necessary, load the NDBM file.
44556845Seric 	**	If running without NDBM, load the symbol table.
4464322Seric 	*/
4474322Seric 
4484157Seric 	if (init)
4498437Seric 	{
45025522Seric #ifdef LOG
45158020Seric 		if (LogLevel > 7)
45225522Seric 		{
45325522Seric 			extern char *username();
45425522Seric 
45525522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
45625522Seric 				automatic ? "auto" : "", username());
45725522Seric 		}
45856795Seric #endif /* LOG */
45955012Seric 		readaliases(aliasfile, TRUE, e);
4608437Seric 	}
46156845Seric # else /* NDBM */
46255012Seric 	readaliases(aliasfile, init, e);
46356845Seric # endif /* NDBM */
4644157Seric }
4654157Seric /*
4664157Seric **  READALIASES -- read and process the alias file.
4674157Seric **
4684157Seric **	This routine implements the part of initaliases that occurs
4694157Seric **	when we are not going to use the DBM stuff.
4704157Seric **
4714157Seric **	Parameters:
4724157Seric **		aliasfile -- the pathname of the alias file master.
47356845Seric **		init -- if set, initialize the NDBM stuff.
4744157Seric **
4754157Seric **	Returns:
4764157Seric **		none.
4774157Seric **
4784157Seric **	Side Effects:
4794157Seric **		Reads aliasfile into the symbol table.
4804157Seric **		Optionally, builds the .dir & .pag files.
4814157Seric */
4824157Seric 
4834157Seric static
48455012Seric readaliases(aliasfile, init, e)
4854157Seric 	char *aliasfile;
4864157Seric 	bool init;
48755012Seric 	register ENVELOPE *e;
4884157Seric {
4894098Seric 	register char *p;
4904098Seric 	char *rhs;
4914098Seric 	bool skipping;
4929368Seric 	int naliases, bytes, longest;
4939368Seric 	FILE *af;
49453742Seric 	bool makedbmfiles;
49540970Sbostic 	void (*oldsigint)();
4964098Seric 	ADDRESS al, bl;
4974106Seric 	register STAB *s;
49850575Seric # ifdef NEWDB
49950575Seric 	DB *dbp;
50050575Seric # endif
50156845Seric # ifdef NDBM
50256845Seric 	DBM *dbmp;
50356845Seric # endif
50451937Seric # ifdef LOCKF
50551937Seric 	struct flock fld;
50651937Seric # endif
5079368Seric 	char line[BUFSIZ];
5084098Seric 
50951937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
5101515Seric 	{
51157249Seric 		if (init)
51258151Seric 			syserr("554 Can't open %s", aliasfile);
51357249Seric 		else if (tTd(27, 1))
5144106Seric 			printf("Can't open %s\n", aliasfile);
5154098Seric 		errno = 0;
5164098Seric 		NoAlias++;
5174098Seric 		return;
5184098Seric 	}
5194314Seric 
52056845Seric # if defined(NDBM) || defined(NEWDB)
52119784Seric 	/* see if someone else is rebuilding the alias file already */
52251835Seric # ifdef LOCKF
52351937Seric 	fld.l_type = F_WRLCK;
52451937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
52551937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
52651835Seric # else
52719784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
52851835Seric # endif
52919784Seric 	{
53019784Seric 		/* yes, they are -- wait until done and then return */
53158151Seric 		message("Alias file is already being rebuilt");
53219784Seric 		if (OpMode != MD_INITALIAS)
53319784Seric 		{
53419784Seric 			/* wait for other rebuild to complete */
53551835Seric # ifdef LOCKF
53651937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
53751835Seric # else
53819784Seric 			(void) flock(fileno(af), LOCK_EX);
53951835Seric # endif
54019784Seric 		}
54123108Seric 		(void) fclose(af);
54219784Seric 		errno = 0;
54319784Seric 		return;
54419784Seric 	}
54556845Seric # endif /* NDBM */
54619784Seric 
5474314Seric 	/*
54819784Seric 	**  If initializing, create the new DBM files.
54919784Seric 	*/
55019784Seric 
55119784Seric 	if (init)
55219784Seric 	{
55319784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
55451756Seric # ifdef NEWDB
55551756Seric 		(void) strcpy(line, aliasfile);
55651756Seric 		(void) strcat(line, ".db");
55751756Seric 		dbp = dbopen(line,
55851756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
55951756Seric 		if (dbp == NULL)
56051756Seric 		{
56151756Seric 			syserr("readaliases: cannot create %s", line);
56251756Seric 			(void) signal(SIGINT, oldsigint);
56351756Seric 			return;
56451756Seric 		}
56553742Seric # endif
56653742Seric # ifdef IF_MAKEDBMFILES
56753742Seric # ifdef NEWDB
56853742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
56953742Seric # endif
57053742Seric 		IF_MAKEDBMFILES
57119784Seric 		{
57256845Seric 			dbmp = dbm_open(aliasfile,
57356845Seric 					       O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
57456845Seric 			if (dbmp == NULL)
57553742Seric 			{
57656845Seric 				syserr("readaliases: cannot create %s.{dir,pag}",
57756845Seric 					aliasfile);
57853742Seric 				(void) signal(SIGINT, oldsigint);
57953742Seric 				return;
58053742Seric 			}
58119784Seric 		}
58250575Seric # endif
58319784Seric 	}
58419784Seric 
58519784Seric 	/*
5864314Seric 	**  Read and interpret lines
5874314Seric 	*/
5884314Seric 
5899368Seric 	FileName = aliasfile;
5909368Seric 	LineNumber = 0;
5914322Seric 	naliases = bytes = longest = 0;
5924098Seric 	skipping = FALSE;
5934098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5944098Seric 	{
5954322Seric 		int lhssize, rhssize;
5964322Seric 
5979368Seric 		LineNumber++;
59856795Seric 		p = strchr(line, '\n');
59925278Seric 		if (p != NULL)
60025278Seric 			*p = '\0';
6014098Seric 		switch (line[0])
6024098Seric 		{
6034098Seric 		  case '#':
6044098Seric 		  case '\0':
6054098Seric 			skipping = FALSE;
6064098Seric 			continue;
6074065Seric 
6084098Seric 		  case ' ':
6094098Seric 		  case '\t':
6104098Seric 			if (!skipping)
61158151Seric 				syserr("554 Non-continuation line starts with space");
6124098Seric 			skipping = TRUE;
6134097Seric 			continue;
6144098Seric 		}
6154098Seric 		skipping = FALSE;
6161874Seric 
6174314Seric 		/*
6184314Seric 		**  Process the LHS
61957736Seric 		**	Find the colon separator, and parse the address.
62016898Seric 		**	It should resolve to a local name -- this will
62116898Seric 		**	be checked later (we want to optionally do
62216898Seric 		**	parsing of the RHS first to maximize error
62316898Seric 		**	detection).
6244314Seric 		*/
6254314Seric 
6264098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
6274097Seric 			continue;
62816898Seric 		if (*p++ != ':')
6294098Seric 		{
63058151Seric 			syserr("554 missing colon");
6314097Seric 			continue;
6324098Seric 		}
63355012Seric 		if (parseaddr(line, &al, 1, ':', e) == NULL)
6344098Seric 		{
63558151Seric 			syserr("554 illegal alias name");
63616898Seric 			continue;
6374098Seric 		}
63816898Seric 		loweraddr(&al);
6394314Seric 
6404314Seric 		/*
6414314Seric 		**  Process the RHS.
6424314Seric 		**	'al' is the internal form of the LHS address.
6434314Seric 		**	'p' points to the text of the RHS.
6444314Seric 		*/
6454314Seric 
6464098Seric 		rhs = p;
6474098Seric 		for (;;)
6484098Seric 		{
6494098Seric 			register char c;
6501515Seric 
65125821Seric 			if (init && CheckAliases)
6524098Seric 			{
6534157Seric 				/* do parsing & compression of addresses */
65425278Seric 				while (*p != '\0')
6554098Seric 				{
65625278Seric 					extern char *DelimChar;
65725278Seric 
65858050Seric 					while ((isascii(*p) && isspace(*p)) ||
65958050Seric 								*p == ',')
6604157Seric 						p++;
66125278Seric 					if (*p == '\0')
66225278Seric 						break;
66355012Seric 					if (parseaddr(p, &bl, -1, ',', e) == NULL)
66458151Seric 						usrerr("553 %s... bad address", p);
66525278Seric 					p = DelimChar;
6664098Seric 				}
6674098Seric 			}
6684157Seric 			else
66915769Seric 			{
67016898Seric 				p = &p[strlen(p)];
67116898Seric 				if (p[-1] == '\n')
67216898Seric 					*--p = '\0';
67315769Seric 			}
6741515Seric 
6754098Seric 			/* see if there should be a continuation line */
6764106Seric 			c = fgetc(af);
6774106Seric 			if (!feof(af))
6784314Seric 				(void) ungetc(c, af);
6794106Seric 			if (c != ' ' && c != '\t')
6804098Seric 				break;
6814098Seric 
6824098Seric 			/* read continuation line */
6834098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6844098Seric 				break;
6859368Seric 			LineNumber++;
68657135Seric 
68757135Seric 			/* check for line overflow */
68857135Seric 			if (strchr(p, '\n') == NULL)
68957135Seric 			{
69058151Seric 				usrerr("554 alias too long");
69157135Seric 				break;
69257135Seric 			}
6934098Seric 		}
69416898Seric 		if (al.q_mailer != LocalMailer)
69516898Seric 		{
69658151Seric 			syserr("554 cannot alias non-local names");
69716898Seric 			continue;
69816898Seric 		}
6994314Seric 
7004314Seric 		/*
7014314Seric 		**  Insert alias into symbol table or DBM file
7024314Seric 		*/
7034314Seric 
70416898Seric 		lhssize = strlen(al.q_user) + 1;
70557381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
70657381Seric 			makelower(al.q_user);
7074322Seric 		rhssize = strlen(rhs) + 1;
7084322Seric 
70956845Seric # if defined(NDBM) || defined(NEWDB)
7104157Seric 		if (init)
7114157Seric 		{
71256845Seric 			DBdatum key, content;
71357381Seric 			int putstat;
7144157Seric 
71556845Seric 			key.xx.size = lhssize;
71656845Seric 			key.xx.data = al.q_user;
71756845Seric 			content.xx.size = rhssize;
71856845Seric 			content.xx.data = rhs;
71951756Seric # ifdef NEWDB
72057381Seric 			putstat = dbp->put(dbp, &key.dbt, &content.dbt,
72157381Seric 					   R_NOOVERWRITE);
72257381Seric 			if (putstat > 0)
72357381Seric 			{
72457977Seric 				usrerr("050 Warning: duplicate alias name %s",
72557381Seric 					al.q_user);
72657381Seric 				putstat = dbp->put(dbp, &key.dbt,
72757381Seric 						   &content.dbt, 0);
72857381Seric 			}
72957381Seric 			if (putstat != 0)
73050576Seric 				syserr("readaliases: db put (%s)", al.q_user);
73150575Seric # endif
73253742Seric # ifdef IF_MAKEDBMFILES
73353742Seric 			IF_MAKEDBMFILES
73457381Seric 			{
73557381Seric 				putstat = dbm_store(dbmp, key.dbm, content.dbm,
73657381Seric 						    DBM_INSERT);
73757381Seric 				if (putstat > 0)
73857381Seric 				{
73957977Seric 					usrerr("050 Warning: duplicate alias name %s",
74057381Seric 						al.q_user);
74157381Seric 					putstat = dbm_store(dbmp, key.dbm,
74257381Seric 							content.dbm, DBM_REPLACE);
74357381Seric 				}
74457381Seric 				if (putstat != 0)
74556845Seric 					syserr("readaliases: dbm store (%s)",
74656845Seric 						al.q_user);
74757381Seric 			}
74853742Seric # endif
74957381Seric 			if (al.q_paddr != NULL)
75057381Seric 				free(al.q_paddr);
75157381Seric 			if (al.q_host != NULL)
75257381Seric 				free(al.q_host);
75357381Seric 			if (al.q_user != NULL)
75457381Seric 				free(al.q_user);
7554157Seric 		}
7564157Seric 		else
75756845Seric # endif /* NDBM */
7584157Seric 		{
7594157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
7604157Seric 			s->s_alias = newstr(rhs);
7614157Seric 		}
7624322Seric 
7634322Seric 		/* statistics */
7644322Seric 		naliases++;
7654322Seric 		bytes += lhssize + rhssize;
7664322Seric 		if (rhssize > longest)
7674322Seric 			longest = rhssize;
7681515Seric 	}
76919784Seric 
77056845Seric # if defined(NDBM) || defined(NEWDB)
77119784Seric 	if (init)
77219784Seric 	{
77319784Seric 		/* add the distinquished alias "@" */
77456845Seric 		DBdatum key;
77519784Seric 
77656845Seric 		key.xx.size = 2;
77756845Seric 		key.xx.data = "@";
77850575Seric # ifdef NEWDB
77950576Seric 		if (dbp->sync(dbp) != 0 ||
78056845Seric 		    dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
78150576Seric 		    dbp->close(dbp) != 0)
78250576Seric 			syserr("readaliases: db close failure");
78353742Seric # endif
78456789Seric # ifdef IF_MAKEDBMFILES
78556793Seric 		IF_MAKEDBMFILES
78656845Seric 		{
78758059Seric #ifdef YPCOMPAT
78858059Seric 			nis_magic(dbmp);
78958059Seric #endif
79056845Seric 			if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
79156845Seric 			    dbm_error(dbmp))
79256845Seric 				syserr("readaliases: dbm close failure");
79356845Seric 			dbm_close(dbmp);
79456845Seric 		}
79550575Seric # endif
79619784Seric 
79719784Seric 		/* restore the old signal */
79819784Seric 		(void) signal(SIGINT, oldsigint);
79919784Seric 	}
80056845Seric # endif /* NDBM */
80119784Seric 
80219784Seric 	/* closing the alias file drops the lock */
8034098Seric 	(void) fclose(af);
80455012Seric 	e->e_to = NULL;
8059368Seric 	FileName = NULL;
80658151Seric 	message("%d aliases, longest %d bytes, %d bytes total",
8074322Seric 			naliases, longest, bytes);
80824944Seric # ifdef LOG
80958020Seric 	if (LogLevel > 7)
81024944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
81124944Seric 			naliases, longest, bytes);
81256795Seric # endif /* LOG */
813292Seric }
814292Seric /*
81558059Seric **  NIS_MAGIC -- Add NIS magic dbm data
81658059Seric **
81758059Seric **	This adds the magic entries needed by SunOS to make this a valid
81858059Seric **	NIS map.
81958059Seric **
82058059Seric **	Parameters:
82158059Seric **		dbmp -- a pointer to the DBM structure.
82258059Seric **
82358059Seric **	Returns:
82458059Seric **		none.
82558059Seric */
82658059Seric 
82758059Seric # ifdef YPCOMPAT
82858059Seric 
82958059Seric static void
83058059Seric nis_magic(dbmp)
83158059Seric 	DBM *dbmp;
83258059Seric {
83358059Seric 	int i;
83458059Seric 	static datum key[2] =
83558059Seric 	{
83658059Seric 		{ "YP_LAST_MODIFIED",	sizeof "YP_LAST_MODIFIED" - 1 },
83758059Seric 		{ "YP_MASTER_NAME",	sizeof "YP_MASTER_NAME" - 1 },
83858059Seric 	};
83958059Seric 	datum contents[2];
84058059Seric 	char tbuf[12];
84158059Seric 	char hbuf[MAXHOSTNAMELEN];
84258059Seric 
84358059Seric 	(void) sprintf(tbuf, "%010ld", curtime());
84458059Seric 	contents[0].dptr = tbuf;
84558059Seric 	contents[0].dsize = strlen(tbuf);
84658059Seric 
84758059Seric 	(void) myhostname(hbuf, sizeof hbuf);
84858059Seric 	contents[1].dptr = hbuf;
84958059Seric 	contents[1].dptr = strlen(hbuf);
85058059Seric 
85158059Seric 	for (i = 0; i < sizeof key / sizeof *key; i++)
85258059Seric 	{
85358059Seric 		if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 ||
85458059Seric 		    dbm_error(dbmp))
85558059Seric 			syserr("nis_magic: dbm_store failure");
85658059Seric 	}
85758059Seric }
85858059Seric 
85958059Seric # endif
86058059Seric /*
861292Seric **  FORWARD -- Try to forward mail
862292Seric **
863292Seric **	This is similar but not identical to aliasing.
864292Seric **
865292Seric **	Parameters:
8664314Seric **		user -- the name of the user who's mail we would like
8674314Seric **			to forward to.  It must have been verified --
8684314Seric **			i.e., the q_home field must have been filled
8694314Seric **			in.
8704999Seric **		sendq -- a pointer to the head of the send queue to
8714999Seric **			put this user's aliases in.
872292Seric **
873292Seric **	Returns:
8744098Seric **		none.
875292Seric **
876292Seric **	Side Effects:
8773185Seric **		New names are added to send queues.
878292Seric */
879292Seric 
88055012Seric forward(user, sendq, e)
8812966Seric 	ADDRESS *user;
8824999Seric 	ADDRESS **sendq;
88355012Seric 	register ENVELOPE *e;
884292Seric {
88557136Seric 	char *pp;
88657136Seric 	char *ep;
8874536Seric 	extern bool safefile();
8884069Seric 
8897671Seric 	if (tTd(27, 1))
8904098Seric 		printf("forward(%s)\n", user->q_paddr);
8914098Seric 
8924594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
8934098Seric 		return;
8944314Seric 	if (user->q_home == NULL)
89558059Seric 	{
89658151Seric 		syserr("554 forward: no home");
89758059Seric 		user->q_home = "/nosuchdirectory";
89858059Seric 	}
8994069Seric 
9004069Seric 	/* good address -- look for .forward file in home */
90155012Seric 	define('z', user->q_home, e);
90257136Seric 	define('u', user->q_user, e);
90357136Seric 	define('h', user->q_host, e);
90457136Seric 	if (ForwardPath == NULL)
90558050Seric 		ForwardPath = newstr("\201z/.forward");
90657136Seric 
90757136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
90857136Seric 	{
90957232Seric 		char buf[MAXPATHLEN+1];
91057136Seric 
91157136Seric 		ep = strchr(pp, ':');
91257136Seric 		if (ep != NULL)
91357136Seric 			*ep = '\0';
91457136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
91557136Seric 		if (ep != NULL)
91657136Seric 			*ep++ = ':';
91757136Seric 		if (tTd(27, 3))
91857136Seric 			printf("forward: trying %s\n", buf);
91957136Seric 		if (include(buf, TRUE, user, sendq, e) == 0)
92057136Seric 			break;
92157136Seric 	}
922292Seric }
923