xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 58333)
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 <sys/stat.h>
1157948Seric # include <sys/file.h>
1250577Seric # include <signal.h>
1357737Seric # include <fcntl.h>
1450577Seric # include <pwd.h>
1550577Seric 
1656845Seric # ifdef DBM
1756848Seric ERROR: DBM is no longer supported -- use NDBM instead.
1856845Seric # endif
1956845Seric 
2050577Seric # ifdef NEWDB
2150577Seric # include <db.h>
2250577Seric # endif
2350577Seric 
2456766Seric # ifdef NDBM
2556845Seric # include <ndbm.h>
2656766Seric # endif
2756766Seric 
2833728Sbostic #ifndef lint
2951756Seric #ifdef NEWDB
3057736Seric #ifdef NDBM
31*58333Seric static char sccsid[] = "@(#)alias.c	6.21 (Berkeley) 03/01/93 (with NEWDB and NDBM)";
3251756Seric #else
33*58333Seric static char sccsid[] = "@(#)alias.c	6.21 (Berkeley) 03/01/93 (with NEWDB)";
3457736Seric #endif
3557736Seric #else
3656845Seric #ifdef NDBM
37*58333Seric static char sccsid[] = "@(#)alias.c	6.21 (Berkeley) 03/01/93 (with NDBM)";
3833728Sbostic #else
39*58333Seric static char sccsid[] = "@(#)alias.c	6.21 (Berkeley) 03/01/93 (without NEWDB or NDBM)";
4033728Sbostic #endif
4150575Seric #endif
4233728Sbostic #endif /* not lint */
4351756Seric /*
44292Seric **  ALIAS -- Compute aliases.
45292Seric **
469368Seric **	Scans the alias file for an alias for the given address.
479368Seric **	If found, it arranges to deliver to the alias list instead.
489368Seric **	Uses libdbm database if -DDBM.
49292Seric **
50292Seric **	Parameters:
514097Seric **		a -- address to alias.
524999Seric **		sendq -- a pointer to the head of the send queue
534999Seric **			to put the aliases in.
5458092Seric **		e -- the current envelope.
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;
11558082Seric 	int naliases;
11658170Seric 	char *owner;
11758170Seric 	char obuf[MAXNAME + 6];
1185701Seric 	extern char *aliaslookup();
119292Seric 
1207671Seric 	if (tTd(27, 1))
1214098Seric 		printf("alias(%s)\n", a->q_paddr);
122292Seric 
1234098Seric 	/* don't realias already aliased names */
12458154Seric 	if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
1254098Seric 		return;
1264098Seric 
12755012Seric 	e->e_to = a->q_paddr;
1284098Seric 
1294314Seric 	/*
1304314Seric 	**  Look up this name
1314314Seric 	*/
1324314Seric 
13324944Seric 	if (NoAlias)
13424944Seric 		p = NULL;
13524944Seric 	else
13624944Seric 		p = aliaslookup(a->q_user);
1374098Seric 	if (p == NULL)
1384098Seric 		return;
139292Seric 
140292Seric 	/*
1414098Seric 	**  Match on Alias.
1424098Seric 	**	Deliver to the target list.
1431515Seric 	*/
1441515Seric 
1457671Seric 	if (tTd(27, 1))
1464098Seric 		printf("%s (%s, %s) aliased to %s\n",
1474098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
14858092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
14958154Seric 	{
15058154Seric 		a->q_flags |= QVERIFIED;
15158092Seric 		return;
15258154Seric 	}
15358154Seric 	message("aliased to %s", p);
15457977Seric #ifdef LOG
15558020Seric 	if (LogLevel > 9)
15657977Seric 		syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
15757977Seric #endif
15858082Seric 	a->q_flags &= ~QSELFREF;
1594098Seric 	AliasLevel++;
16058082Seric 	naliases = sendtolist(p, a, sendq, e);
1614098Seric 	AliasLevel--;
16258082Seric 	if (naliases > 0 && !bitset(QSELFREF, a->q_flags))
16358065Seric 	{
16458065Seric 		if (tTd(27, 5))
16558065Seric 		{
16658065Seric 			printf("alias: QDONTSEND ");
16758065Seric 			printaddr(a, FALSE);
16858065Seric 		}
16958065Seric 		a->q_flags |= QDONTSEND;
17058065Seric 	}
17158170Seric 
17258170Seric 	/*
17358170Seric 	**  Look for owner of alias
17458170Seric 	*/
17558170Seric 
17658170Seric 	(void) strcpy(obuf, "owner-");
17758170Seric 	if (strncmp(a->q_user, "owner-", 6) == 0)
17858170Seric 		(void) strcat(obuf, "owner");
17958170Seric 	else
18058170Seric 		(void) strcat(obuf, a->q_user);
18158170Seric 	if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
18258170Seric 		makelower(obuf);
18358170Seric 	owner = aliaslookup(obuf);
18458170Seric 	if (owner != NULL)
18558170Seric 	{
18658170Seric 		if (strchr(owner, ',') != NULL)
18758170Seric 			owner = obuf;
18858170Seric 		a->q_owner = newstr(owner);
18958170Seric 	}
1904098Seric }
1914098Seric /*
1925701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1935701Seric **
1945701Seric **	Parameters:
1955701Seric **		name -- the name to look up.
1965701Seric **
1975701Seric **	Returns:
1985701Seric **		the value of name.
1995701Seric **		NULL if unknown.
2005701Seric **
2015701Seric **	Side Effects:
2025701Seric **		none.
2035701Seric **
2045701Seric **	Warnings:
2055701Seric **		The return value will be trashed across calls.
2065701Seric */
2075701Seric 
2085701Seric char *
2095701Seric aliaslookup(name)
2105701Seric 	char *name;
2115701Seric {
21257381Seric 	int i;
21357381Seric 	char keybuf[MAXNAME + 1];
21456845Seric # if defined(NEWDB) || defined(NDBM)
21556845Seric 	DBdatum rhs, lhs;
21650575Seric 	int s;
21757381Seric # else /* neither NEWDB nor NDBM */
21857381Seric 	register STAB *s;
21957381Seric # endif
2205701Seric 
2215701Seric 	/* create a key for fetch */
22257381Seric 	i = strlen(name) + 1;
22357381Seric 	if (i > sizeof keybuf)
22457381Seric 		i = sizeof keybuf;
22557381Seric 	bcopy(name, keybuf, i);
22657381Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
22757381Seric 		makelower(keybuf);
22857381Seric 
22957381Seric # if defined(NEWDB) || defined(NDBM)
23057381Seric 	lhs.xx.size = i;
23157381Seric 	lhs.xx.data = keybuf;
23250575Seric # ifdef NEWDB
23351756Seric 	if (AliasDBptr != NULL)
23451756Seric 	{
23557381Seric 		i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
23657381Seric 		if (i == 0)
23756845Seric 			return (rhs.dbt.data);
23851756Seric 	}
23956845Seric # ifdef NDBM
24057249Seric 	else if (AliasDBMptr != NULL)
24151756Seric 	{
24256845Seric 		rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
24356845Seric 		return (rhs.dbm.dptr);
24451756Seric 	}
24556845Seric # endif /* NDBM */
24657530Seric 	return (NULL);
24756845Seric # else /* not NEWDB */
24856845Seric 	rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
24956845Seric 	return (rhs.dbm.dptr);
25056845Seric # endif /* NEWDB */
25156845Seric # else /* neither NEWDB nor NDBM */
25257381Seric 	s = stab(keybuf, ST_ALIAS, ST_FIND);
25351756Seric 	if (s != NULL)
25451756Seric 		return (s->s_alias);
25557530Seric 	return (NULL);
25651756Seric # endif
2575701Seric }
2585701Seric /*
2594098Seric **  INITALIASES -- initialize for aliasing
2604098Seric **
26156845Seric **	Very different depending on whether we are running NDBM or not.
2624098Seric **
2634098Seric **	Parameters:
2644098Seric **		aliasfile -- location of aliases.
26556845Seric **		init -- if set and if NDBM, initialize the NDBM files.
2664098Seric **
2674098Seric **	Returns:
2684098Seric **		none.
2694098Seric **
2704098Seric **	Side Effects:
2714098Seric **		initializes aliases:
27256845Seric **		if NDBM:  opens the database.
27356845Seric **		if ~NDBM: reads the aliases into the symbol table.
2744098Seric */
2754098Seric 
27640559Sbostic # define DBMMODE	0644
2774157Seric 
27855012Seric initaliases(aliasfile, init, e)
2794098Seric 	char *aliasfile;
2804157Seric 	bool init;
28155012Seric 	register ENVELOPE *e;
2824098Seric {
28356845Seric #if defined(NDBM) || defined(NEWDB)
2848437Seric 	int atcnt;
28525522Seric 	time_t modtime;
28625522Seric 	bool automatic = FALSE;
2874322Seric 	char buf[MAXNAME];
28850575Seric #endif
2899368Seric 	struct stat stb;
29027176Seric 	static bool initialized = FALSE;
29146928Sbostic 	static int readaliases();
2924322Seric 
29327176Seric 	if (initialized)
29427176Seric 		return;
29527176Seric 	initialized = TRUE;
29627176Seric 
29717984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2988437Seric 	{
29925522Seric 		if (aliasfile != NULL && init)
30058151Seric 			syserr("554 Cannot open %s", aliasfile);
3018437Seric 		NoAlias = TRUE;
30211937Seric 		errno = 0;
3038437Seric 		return;
3048437Seric 	}
3058437Seric 
30656845Seric # if defined(NDBM) || defined(NEWDB)
3074322Seric 	/*
3088437Seric 	**  Check to see that the alias file is complete.
3098437Seric 	**	If not, we will assume that someone died, and it is up
3108437Seric 	**	to us to rebuild it.
3118437Seric 	*/
3128437Seric 
31325689Seric 	if (!init)
31450575Seric 	{
31550575Seric # ifdef NEWDB
31650575Seric 		(void) strcpy(buf, aliasfile);
31750575Seric 		(void) strcat(buf, ".db");
31851171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
31950576Seric 		if (AliasDBptr == NULL)
32050576Seric 		{
32156845Seric # ifdef NDBM
32256845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
32357249Seric 			if (AliasDBMptr == NULL)
32457249Seric 			{
32557249Seric 				syserr("initaliases: cannot open %s", buf);
32657249Seric 				NoAlias = TRUE;
32757249Seric 				return;
32857249Seric 			}
32951756Seric # else
33050576Seric 			syserr("initaliases: cannot open %s", buf);
33150576Seric 			NoAlias = TRUE;
33250576Seric 			return;
33351756Seric # endif
33450576Seric 		}
33550575Seric # else
33656845Seric 		AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
33757249Seric 		if (AliasDBMptr == NULL)
33857249Seric 		{
33957977Seric 			syserr("initaliases: cannot open DBM database %s.{pag,dir}",
34057977Seric 				aliasfile);
34157249Seric 			NoAlias = TRUE;
34257249Seric 			return;
34357249Seric 		}
34450575Seric # endif
34550575Seric 	}
34617471Seric 	atcnt = SafeAlias * 2;
34717471Seric 	if (atcnt > 0)
34817471Seric 	{
34917471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
35025689Seric 		{
35125689Seric 			/*
35225689Seric 			**  Reinitialize alias file in case the new
35325689Seric 			**  one is mv'ed in instead of cp'ed in.
35425689Seric 			**
35525689Seric 			**	Only works with new DBM -- old one will
35625689Seric 			**	just consume file descriptors forever.
35725689Seric 			**	If you have a dbmclose() it can be
35825689Seric 			**	added before the sleep(30).
35925689Seric 			*/
36025689Seric 
36150575Seric # ifdef NEWDB
36251756Seric 			if (AliasDBptr != NULL)
36351756Seric 				AliasDBptr->close(AliasDBptr);
36450575Seric # endif
36556845Seric # ifdef NDBM
36656845Seric 			if (AliasDBMptr != NULL)
36756845Seric 				dbm_close(AliasDBMptr);
36856845Seric # endif
36950575Seric 
37017471Seric 			sleep(30);
37150575Seric # ifdef NEWDB
37250575Seric 			(void) strcpy(buf, aliasfile);
37350575Seric 			(void) strcat(buf, ".db");
37451171Sbostic 			AliasDBptr =
37551171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
37650576Seric 			if (AliasDBptr == NULL)
37750576Seric 			{
37851756Seric # ifdef NDBM
37956845Seric 				AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
38051756Seric # else
38150576Seric 				syserr("initaliases: cannot open %s", buf);
38250576Seric 				NoAlias = TRUE;
38350576Seric 				return;
38451756Seric # endif
38550576Seric 			}
38650575Seric # else
38725689Seric # ifdef NDBM
38856845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
38957249Seric 			if (AliasDBMptr == NULL)
39057249Seric 			{
39158008Seric 				syserr("initaliases: cannot open DBM database %s.{pag,dir}",
39258008Seric 					aliasfile);
39357249Seric 				NoAlias = TRUE;
39457249Seric 				return;
39557249Seric 			}
39650575Seric # endif
39750575Seric # endif
39825689Seric 		}
39917471Seric 	}
40017471Seric 	else
40117471Seric 		atcnt = 1;
4028437Seric 
4038437Seric 	/*
40456845Seric 	**  See if the NDBM version of the file is out of date with
4054322Seric 	**  the text version.  If so, go into 'init' mode automatically.
40640559Sbostic 	**	This only happens if our effective userid owns the DBM.
40740559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
4084322Seric 	*/
4094322Seric 
4104322Seric 	modtime = stb.st_mtime;
4114322Seric 	(void) strcpy(buf, aliasfile);
41250575Seric # ifdef NEWDB
41350575Seric 	(void) strcat(buf, ".db");
41450575Seric # else
4154322Seric 	(void) strcat(buf, ".pag");
41650575Seric # endif
4174322Seric 	stb.st_ino = 0;
41819039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
4194322Seric 	{
42011937Seric 		errno = 0;
42140559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
4224322Seric 		{
4234322Seric 			init = TRUE;
42425522Seric 			automatic = TRUE;
42558151Seric 			message("rebuilding alias database");
42624944Seric #ifdef LOG
42758020Seric 			if (LogLevel > 14)
42824944Seric 				syslog(LOG_INFO, "rebuilding alias database");
42956795Seric #endif /* LOG */
4304322Seric 		}
4314322Seric 		else
4324322Seric 		{
43319039Seric #ifdef LOG
43458020Seric 			if (LogLevel > 3)
43524944Seric 				syslog(LOG_INFO, "alias database out of date");
43656795Seric #endif /* LOG */
43758151Seric 			message("Warning: alias database out of date");
4384322Seric 		}
4394322Seric 	}
4404322Seric 
4414322Seric 
4424322Seric 	/*
44356845Seric 	**  If necessary, load the NDBM file.
44456845Seric 	**	If running without NDBM, load the symbol table.
4454322Seric 	*/
4464322Seric 
4474157Seric 	if (init)
4488437Seric 	{
44925522Seric #ifdef LOG
45058020Seric 		if (LogLevel > 7)
45125522Seric 		{
45225522Seric 			extern char *username();
45325522Seric 
45425522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
45525522Seric 				automatic ? "auto" : "", username());
45625522Seric 		}
45756795Seric #endif /* LOG */
45855012Seric 		readaliases(aliasfile, TRUE, e);
4598437Seric 	}
46056845Seric # else /* NDBM */
46155012Seric 	readaliases(aliasfile, init, e);
46256845Seric # endif /* NDBM */
4634157Seric }
4644157Seric /*
4654157Seric **  READALIASES -- read and process the alias file.
4664157Seric **
4674157Seric **	This routine implements the part of initaliases that occurs
4684157Seric **	when we are not going to use the DBM stuff.
4694157Seric **
4704157Seric **	Parameters:
4714157Seric **		aliasfile -- the pathname of the alias file master.
47256845Seric **		init -- if set, initialize the NDBM stuff.
4734157Seric **
4744157Seric **	Returns:
4754157Seric **		none.
4764157Seric **
4774157Seric **	Side Effects:
4784157Seric **		Reads aliasfile into the symbol table.
4794157Seric **		Optionally, builds the .dir & .pag files.
4804157Seric */
4814157Seric 
4824157Seric static
48355012Seric readaliases(aliasfile, init, e)
4844157Seric 	char *aliasfile;
4854157Seric 	bool init;
48655012Seric 	register ENVELOPE *e;
4874157Seric {
4884098Seric 	register char *p;
4894098Seric 	char *rhs;
4904098Seric 	bool skipping;
4919368Seric 	int naliases, bytes, longest;
4929368Seric 	FILE *af;
49353742Seric 	bool makedbmfiles;
49440970Sbostic 	void (*oldsigint)();
4954098Seric 	ADDRESS al, bl;
4964106Seric 	register STAB *s;
49750575Seric # ifdef NEWDB
49850575Seric 	DB *dbp;
49950575Seric # endif
50056845Seric # ifdef NDBM
50156845Seric 	DBM *dbmp;
50256845Seric # endif
50351937Seric # ifdef LOCKF
50451937Seric 	struct flock fld;
50551937Seric # endif
5069368Seric 	char line[BUFSIZ];
5074098Seric 
50851937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
5091515Seric 	{
51057249Seric 		if (init)
51158151Seric 			syserr("554 Can't open %s", aliasfile);
51257249Seric 		else if (tTd(27, 1))
5134106Seric 			printf("Can't open %s\n", aliasfile);
5144098Seric 		errno = 0;
5154098Seric 		NoAlias++;
5164098Seric 		return;
5174098Seric 	}
5184314Seric 
51956845Seric # if defined(NDBM) || defined(NEWDB)
52019784Seric 	/* see if someone else is rebuilding the alias file already */
52151835Seric # ifdef LOCKF
52251937Seric 	fld.l_type = F_WRLCK;
52351937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
52451937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
52551835Seric # else
52619784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
52751835Seric # endif
52819784Seric 	{
52919784Seric 		/* yes, they are -- wait until done and then return */
53058151Seric 		message("Alias file is already being rebuilt");
53119784Seric 		if (OpMode != MD_INITALIAS)
53219784Seric 		{
53319784Seric 			/* wait for other rebuild to complete */
53451835Seric # ifdef LOCKF
53551937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
53651835Seric # else
53719784Seric 			(void) flock(fileno(af), LOCK_EX);
53851835Seric # endif
53919784Seric 		}
54023108Seric 		(void) fclose(af);
54119784Seric 		errno = 0;
54219784Seric 		return;
54319784Seric 	}
54456845Seric # endif /* NDBM */
54519784Seric 
5464314Seric 	/*
54719784Seric 	**  If initializing, create the new DBM files.
54819784Seric 	*/
54919784Seric 
55019784Seric 	if (init)
55119784Seric 	{
55219784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
55351756Seric # ifdef NEWDB
55451756Seric 		(void) strcpy(line, aliasfile);
55551756Seric 		(void) strcat(line, ".db");
55651756Seric 		dbp = dbopen(line,
55751756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
55851756Seric 		if (dbp == NULL)
55951756Seric 		{
56051756Seric 			syserr("readaliases: cannot create %s", line);
56151756Seric 			(void) signal(SIGINT, oldsigint);
56251756Seric 			return;
56351756Seric 		}
56453742Seric # endif
56553742Seric # ifdef IF_MAKEDBMFILES
56653742Seric # ifdef NEWDB
56753742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
56853742Seric # endif
56953742Seric 		IF_MAKEDBMFILES
57019784Seric 		{
57156845Seric 			dbmp = dbm_open(aliasfile,
57256845Seric 					       O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
57356845Seric 			if (dbmp == NULL)
57453742Seric 			{
57556845Seric 				syserr("readaliases: cannot create %s.{dir,pag}",
57656845Seric 					aliasfile);
57753742Seric 				(void) signal(SIGINT, oldsigint);
57853742Seric 				return;
57953742Seric 			}
58019784Seric 		}
58150575Seric # endif
58219784Seric 	}
58319784Seric 
58419784Seric 	/*
5854314Seric 	**  Read and interpret lines
5864314Seric 	*/
5874314Seric 
5889368Seric 	FileName = aliasfile;
5899368Seric 	LineNumber = 0;
5904322Seric 	naliases = bytes = longest = 0;
5914098Seric 	skipping = FALSE;
5924098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5934098Seric 	{
5944322Seric 		int lhssize, rhssize;
5954322Seric 
5969368Seric 		LineNumber++;
59756795Seric 		p = strchr(line, '\n');
59825278Seric 		if (p != NULL)
59925278Seric 			*p = '\0';
6004098Seric 		switch (line[0])
6014098Seric 		{
6024098Seric 		  case '#':
6034098Seric 		  case '\0':
6044098Seric 			skipping = FALSE;
6054098Seric 			continue;
6064065Seric 
6074098Seric 		  case ' ':
6084098Seric 		  case '\t':
6094098Seric 			if (!skipping)
61058151Seric 				syserr("554 Non-continuation line starts with space");
6114098Seric 			skipping = TRUE;
6124097Seric 			continue;
6134098Seric 		}
6144098Seric 		skipping = FALSE;
6151874Seric 
6164314Seric 		/*
6174314Seric 		**  Process the LHS
61857736Seric 		**	Find the colon separator, and parse the address.
61916898Seric 		**	It should resolve to a local name -- this will
62016898Seric 		**	be checked later (we want to optionally do
62116898Seric 		**	parsing of the RHS first to maximize error
62216898Seric 		**	detection).
6234314Seric 		*/
6244314Seric 
6254098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
6264097Seric 			continue;
62716898Seric 		if (*p++ != ':')
6284098Seric 		{
62958151Seric 			syserr("554 missing colon");
6304097Seric 			continue;
6314098Seric 		}
632*58333Seric 		if (parseaddr(line, &al, 1, ':', NULL, e) == NULL)
6334098Seric 		{
63458151Seric 			syserr("554 illegal alias name");
63516898Seric 			continue;
6364098Seric 		}
63716898Seric 		loweraddr(&al);
6384314Seric 
6394314Seric 		/*
6404314Seric 		**  Process the RHS.
6414314Seric 		**	'al' is the internal form of the LHS address.
6424314Seric 		**	'p' points to the text of the RHS.
6434314Seric 		*/
6444314Seric 
6454098Seric 		rhs = p;
6464098Seric 		for (;;)
6474098Seric 		{
6484098Seric 			register char c;
6491515Seric 
65025821Seric 			if (init && CheckAliases)
6514098Seric 			{
6524157Seric 				/* do parsing & compression of addresses */
65325278Seric 				while (*p != '\0')
6544098Seric 				{
655*58333Seric 					auto char *delimptr;
65625278Seric 
65758050Seric 					while ((isascii(*p) && isspace(*p)) ||
65858050Seric 								*p == ',')
6594157Seric 						p++;
66025278Seric 					if (*p == '\0')
66125278Seric 						break;
662*58333Seric 					if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL)
66358151Seric 						usrerr("553 %s... bad address", p);
664*58333Seric 					p = delimptr;
6654098Seric 				}
6664098Seric 			}
6674157Seric 			else
66815769Seric 			{
66916898Seric 				p = &p[strlen(p)];
67016898Seric 				if (p[-1] == '\n')
67116898Seric 					*--p = '\0';
67215769Seric 			}
6731515Seric 
6744098Seric 			/* see if there should be a continuation line */
6754106Seric 			c = fgetc(af);
6764106Seric 			if (!feof(af))
6774314Seric 				(void) ungetc(c, af);
6784106Seric 			if (c != ' ' && c != '\t')
6794098Seric 				break;
6804098Seric 
6814098Seric 			/* read continuation line */
6824098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6834098Seric 				break;
6849368Seric 			LineNumber++;
68557135Seric 
68657135Seric 			/* check for line overflow */
68757135Seric 			if (strchr(p, '\n') == NULL)
68857135Seric 			{
68958151Seric 				usrerr("554 alias too long");
69057135Seric 				break;
69157135Seric 			}
6924098Seric 		}
69316898Seric 		if (al.q_mailer != LocalMailer)
69416898Seric 		{
69558151Seric 			syserr("554 cannot alias non-local names");
69616898Seric 			continue;
69716898Seric 		}
6984314Seric 
6994314Seric 		/*
7004314Seric 		**  Insert alias into symbol table or DBM file
7014314Seric 		*/
7024314Seric 
70316898Seric 		lhssize = strlen(al.q_user) + 1;
70457381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
70557381Seric 			makelower(al.q_user);
7064322Seric 		rhssize = strlen(rhs) + 1;
7074322Seric 
70856845Seric # if defined(NDBM) || defined(NEWDB)
7094157Seric 		if (init)
7104157Seric 		{
71156845Seric 			DBdatum key, content;
71257381Seric 			int putstat;
7134157Seric 
71456845Seric 			key.xx.size = lhssize;
71556845Seric 			key.xx.data = al.q_user;
71656845Seric 			content.xx.size = rhssize;
71756845Seric 			content.xx.data = rhs;
71851756Seric # ifdef NEWDB
71957381Seric 			putstat = dbp->put(dbp, &key.dbt, &content.dbt,
72057381Seric 					   R_NOOVERWRITE);
72157381Seric 			if (putstat > 0)
72257381Seric 			{
72357977Seric 				usrerr("050 Warning: duplicate alias name %s",
72457381Seric 					al.q_user);
72557381Seric 				putstat = dbp->put(dbp, &key.dbt,
72657381Seric 						   &content.dbt, 0);
72757381Seric 			}
72857381Seric 			if (putstat != 0)
72950576Seric 				syserr("readaliases: db put (%s)", al.q_user);
73050575Seric # endif
73153742Seric # ifdef IF_MAKEDBMFILES
73253742Seric 			IF_MAKEDBMFILES
73357381Seric 			{
73457381Seric 				putstat = dbm_store(dbmp, key.dbm, content.dbm,
73557381Seric 						    DBM_INSERT);
73657381Seric 				if (putstat > 0)
73757381Seric 				{
73857977Seric 					usrerr("050 Warning: duplicate alias name %s",
73957381Seric 						al.q_user);
74057381Seric 					putstat = dbm_store(dbmp, key.dbm,
74157381Seric 							content.dbm, DBM_REPLACE);
74257381Seric 				}
74357381Seric 				if (putstat != 0)
74456845Seric 					syserr("readaliases: dbm store (%s)",
74556845Seric 						al.q_user);
74657381Seric 			}
74753742Seric # endif
74857381Seric 			if (al.q_paddr != NULL)
74957381Seric 				free(al.q_paddr);
75057381Seric 			if (al.q_host != NULL)
75157381Seric 				free(al.q_host);
75257381Seric 			if (al.q_user != NULL)
75357381Seric 				free(al.q_user);
7544157Seric 		}
7554157Seric 		else
75656845Seric # endif /* NDBM */
7574157Seric 		{
7584157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
7594157Seric 			s->s_alias = newstr(rhs);
7604157Seric 		}
7614322Seric 
7624322Seric 		/* statistics */
7634322Seric 		naliases++;
7644322Seric 		bytes += lhssize + rhssize;
7654322Seric 		if (rhssize > longest)
7664322Seric 			longest = rhssize;
7671515Seric 	}
76819784Seric 
76956845Seric # if defined(NDBM) || defined(NEWDB)
77019784Seric 	if (init)
77119784Seric 	{
77219784Seric 		/* add the distinquished alias "@" */
77356845Seric 		DBdatum key;
77419784Seric 
77556845Seric 		key.xx.size = 2;
77656845Seric 		key.xx.data = "@";
77750575Seric # ifdef NEWDB
77850576Seric 		if (dbp->sync(dbp) != 0 ||
77956845Seric 		    dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
78050576Seric 		    dbp->close(dbp) != 0)
78150576Seric 			syserr("readaliases: db close failure");
78253742Seric # endif
78356789Seric # ifdef IF_MAKEDBMFILES
78456793Seric 		IF_MAKEDBMFILES
78556845Seric 		{
78658059Seric #ifdef YPCOMPAT
78758059Seric 			nis_magic(dbmp);
78858059Seric #endif
78956845Seric 			if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
79056845Seric 			    dbm_error(dbmp))
79156845Seric 				syserr("readaliases: dbm close failure");
79256845Seric 			dbm_close(dbmp);
79356845Seric 		}
79450575Seric # endif
79519784Seric 
79619784Seric 		/* restore the old signal */
79719784Seric 		(void) signal(SIGINT, oldsigint);
79819784Seric 	}
79956845Seric # endif /* NDBM */
80019784Seric 
80119784Seric 	/* closing the alias file drops the lock */
8024098Seric 	(void) fclose(af);
80355012Seric 	e->e_to = NULL;
8049368Seric 	FileName = NULL;
80558151Seric 	message("%d aliases, longest %d bytes, %d bytes total",
8064322Seric 			naliases, longest, bytes);
80724944Seric # ifdef LOG
80858020Seric 	if (LogLevel > 7)
80924944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
81024944Seric 			naliases, longest, bytes);
81156795Seric # endif /* LOG */
812292Seric }
813292Seric /*
81458059Seric **  NIS_MAGIC -- Add NIS magic dbm data
81558059Seric **
81658059Seric **	This adds the magic entries needed by SunOS to make this a valid
81758059Seric **	NIS map.
81858059Seric **
81958059Seric **	Parameters:
82058059Seric **		dbmp -- a pointer to the DBM structure.
82158059Seric **
82258059Seric **	Returns:
82358059Seric **		none.
82458059Seric */
82558059Seric 
82658059Seric # ifdef YPCOMPAT
82758059Seric 
82858059Seric static void
82958059Seric nis_magic(dbmp)
83058059Seric 	DBM *dbmp;
83158059Seric {
83258059Seric 	int i;
83358059Seric 	static datum key[2] =
83458059Seric 	{
83558059Seric 		{ "YP_LAST_MODIFIED",	sizeof "YP_LAST_MODIFIED" - 1 },
83658059Seric 		{ "YP_MASTER_NAME",	sizeof "YP_MASTER_NAME" - 1 },
83758059Seric 	};
83858059Seric 	datum contents[2];
83958059Seric 	char tbuf[12];
84058059Seric 	char hbuf[MAXHOSTNAMELEN];
84158059Seric 
84258059Seric 	(void) sprintf(tbuf, "%010ld", curtime());
84358059Seric 	contents[0].dptr = tbuf;
84458059Seric 	contents[0].dsize = strlen(tbuf);
84558059Seric 
84658059Seric 	(void) myhostname(hbuf, sizeof hbuf);
84758059Seric 	contents[1].dptr = hbuf;
84858059Seric 	contents[1].dptr = strlen(hbuf);
84958059Seric 
85058059Seric 	for (i = 0; i < sizeof key / sizeof *key; i++)
85158059Seric 	{
85258059Seric 		if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 ||
85358059Seric 		    dbm_error(dbmp))
85458059Seric 			syserr("nis_magic: dbm_store failure");
85558059Seric 	}
85658059Seric }
85758059Seric 
85858059Seric # endif
85958059Seric /*
860292Seric **  FORWARD -- Try to forward mail
861292Seric **
862292Seric **	This is similar but not identical to aliasing.
863292Seric **
864292Seric **	Parameters:
8654314Seric **		user -- the name of the user who's mail we would like
8664314Seric **			to forward to.  It must have been verified --
8674314Seric **			i.e., the q_home field must have been filled
8684314Seric **			in.
8694999Seric **		sendq -- a pointer to the head of the send queue to
8704999Seric **			put this user's aliases in.
871292Seric **
872292Seric **	Returns:
8734098Seric **		none.
874292Seric **
875292Seric **	Side Effects:
8763185Seric **		New names are added to send queues.
877292Seric */
878292Seric 
87955012Seric forward(user, sendq, e)
8802966Seric 	ADDRESS *user;
8814999Seric 	ADDRESS **sendq;
88255012Seric 	register ENVELOPE *e;
883292Seric {
88457136Seric 	char *pp;
88557136Seric 	char *ep;
8864069Seric 
8877671Seric 	if (tTd(27, 1))
8884098Seric 		printf("forward(%s)\n", user->q_paddr);
8894098Seric 
8904594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
8914098Seric 		return;
8924314Seric 	if (user->q_home == NULL)
89358059Seric 	{
89458151Seric 		syserr("554 forward: no home");
89558059Seric 		user->q_home = "/nosuchdirectory";
89658059Seric 	}
8974069Seric 
8984069Seric 	/* good address -- look for .forward file in home */
89955012Seric 	define('z', user->q_home, e);
90057136Seric 	define('u', user->q_user, e);
90157136Seric 	define('h', user->q_host, e);
90257136Seric 	if (ForwardPath == NULL)
90358050Seric 		ForwardPath = newstr("\201z/.forward");
90457136Seric 
90557136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
90657136Seric 	{
90758247Seric 		int err;
90857232Seric 		char buf[MAXPATHLEN+1];
90958247Seric 		extern bool transienterror();
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);
91958247Seric 		err = include(buf, TRUE, user, sendq, e);
92058247Seric 		if (err == 0)
92157136Seric 			break;
92258247Seric 		if (transienterror(err))
92358247Seric 		{
92458247Seric 			/* we have to suspend this message */
92558247Seric 			user->q_flags |= QQUEUEUP|QDONTSEND;
92658247Seric 			return;
92758247Seric 		}
92857136Seric 	}
929292Seric }
930