xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 58154)
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*58154Seric static char sccsid[] = "@(#)alias.c	6.17 (Berkeley) 02/23/93 (with NEWDB and NDBM)";
3351756Seric #else
34*58154Seric static char sccsid[] = "@(#)alias.c	6.17 (Berkeley) 02/23/93 (with NEWDB)";
3557736Seric #endif
3657736Seric #else
3756845Seric #ifdef NDBM
38*58154Seric static char sccsid[] = "@(#)alias.c	6.17 (Berkeley) 02/23/93 (with NDBM)";
3933728Sbostic #else
40*58154Seric static char sccsid[] = "@(#)alias.c	6.17 (Berkeley) 02/23/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;
1175701Seric 	extern char *aliaslookup();
118292Seric 
1197671Seric 	if (tTd(27, 1))
1204098Seric 		printf("alias(%s)\n", a->q_paddr);
121292Seric 
1224098Seric 	/* don't realias already aliased names */
123*58154Seric 	if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
1244098Seric 		return;
1254098Seric 
12655012Seric 	e->e_to = a->q_paddr;
1274098Seric 
1284314Seric 	/*
1294314Seric 	**  Look up this name
1304314Seric 	*/
1314314Seric 
13224944Seric 	if (NoAlias)
13324944Seric 		p = NULL;
13424944Seric 	else
13524944Seric 		p = aliaslookup(a->q_user);
1364098Seric 	if (p == NULL)
1374098Seric 		return;
138292Seric 
139292Seric 	/*
1404098Seric 	**  Match on Alias.
1414098Seric 	**	Deliver to the target list.
1421515Seric 	*/
1431515Seric 
1447671Seric 	if (tTd(27, 1))
1454098Seric 		printf("%s (%s, %s) aliased to %s\n",
1464098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
14758092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
148*58154Seric 	{
149*58154Seric 		a->q_flags |= QVERIFIED;
15058092Seric 		return;
151*58154Seric 	}
152*58154Seric 	message("aliased to %s", p);
15357977Seric #ifdef LOG
15458020Seric 	if (LogLevel > 9)
15557977Seric 		syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
15657977Seric #endif
15758082Seric 	a->q_flags &= ~QSELFREF;
1584098Seric 	AliasLevel++;
15958082Seric 	naliases = sendtolist(p, a, sendq, e);
1604098Seric 	AliasLevel--;
16158082Seric 	if (naliases > 0 && !bitset(QSELFREF, a->q_flags))
16258065Seric 	{
16358065Seric 		if (tTd(27, 5))
16458065Seric 		{
16558065Seric 			printf("alias: QDONTSEND ");
16658065Seric 			printaddr(a, FALSE);
16758065Seric 		}
16858065Seric 		a->q_flags |= QDONTSEND;
16958065Seric 	}
1704098Seric }
1714098Seric /*
1725701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1735701Seric **
1745701Seric **	Parameters:
1755701Seric **		name -- the name to look up.
1765701Seric **
1775701Seric **	Returns:
1785701Seric **		the value of name.
1795701Seric **		NULL if unknown.
1805701Seric **
1815701Seric **	Side Effects:
1825701Seric **		none.
1835701Seric **
1845701Seric **	Warnings:
1855701Seric **		The return value will be trashed across calls.
1865701Seric */
1875701Seric 
1885701Seric char *
1895701Seric aliaslookup(name)
1905701Seric 	char *name;
1915701Seric {
19257381Seric 	int i;
19357381Seric 	char keybuf[MAXNAME + 1];
19456845Seric # if defined(NEWDB) || defined(NDBM)
19556845Seric 	DBdatum rhs, lhs;
19650575Seric 	int s;
19757381Seric # else /* neither NEWDB nor NDBM */
19857381Seric 	register STAB *s;
19957381Seric # endif
2005701Seric 
2015701Seric 	/* create a key for fetch */
20257381Seric 	i = strlen(name) + 1;
20357381Seric 	if (i > sizeof keybuf)
20457381Seric 		i = sizeof keybuf;
20557381Seric 	bcopy(name, keybuf, i);
20657381Seric 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
20757381Seric 		makelower(keybuf);
20857381Seric 
20957381Seric # if defined(NEWDB) || defined(NDBM)
21057381Seric 	lhs.xx.size = i;
21157381Seric 	lhs.xx.data = keybuf;
21250575Seric # ifdef NEWDB
21351756Seric 	if (AliasDBptr != NULL)
21451756Seric 	{
21557381Seric 		i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
21657381Seric 		if (i == 0)
21756845Seric 			return (rhs.dbt.data);
21851756Seric 	}
21956845Seric # ifdef NDBM
22057249Seric 	else if (AliasDBMptr != NULL)
22151756Seric 	{
22256845Seric 		rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
22356845Seric 		return (rhs.dbm.dptr);
22451756Seric 	}
22556845Seric # endif /* NDBM */
22657530Seric 	return (NULL);
22756845Seric # else /* not NEWDB */
22856845Seric 	rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
22956845Seric 	return (rhs.dbm.dptr);
23056845Seric # endif /* NEWDB */
23156845Seric # else /* neither NEWDB nor NDBM */
23257381Seric 	s = stab(keybuf, ST_ALIAS, ST_FIND);
23351756Seric 	if (s != NULL)
23451756Seric 		return (s->s_alias);
23557530Seric 	return (NULL);
23651756Seric # endif
2375701Seric }
2385701Seric /*
2394098Seric **  INITALIASES -- initialize for aliasing
2404098Seric **
24156845Seric **	Very different depending on whether we are running NDBM or not.
2424098Seric **
2434098Seric **	Parameters:
2444098Seric **		aliasfile -- location of aliases.
24556845Seric **		init -- if set and if NDBM, initialize the NDBM files.
2464098Seric **
2474098Seric **	Returns:
2484098Seric **		none.
2494098Seric **
2504098Seric **	Side Effects:
2514098Seric **		initializes aliases:
25256845Seric **		if NDBM:  opens the database.
25356845Seric **		if ~NDBM: reads the aliases into the symbol table.
2544098Seric */
2554098Seric 
25640559Sbostic # define DBMMODE	0644
2574157Seric 
25855012Seric initaliases(aliasfile, init, e)
2594098Seric 	char *aliasfile;
2604157Seric 	bool init;
26155012Seric 	register ENVELOPE *e;
2624098Seric {
26356845Seric #if defined(NDBM) || defined(NEWDB)
2648437Seric 	int atcnt;
26525522Seric 	time_t modtime;
26625522Seric 	bool automatic = FALSE;
2674322Seric 	char buf[MAXNAME];
26850575Seric #endif
2699368Seric 	struct stat stb;
27027176Seric 	static bool initialized = FALSE;
27146928Sbostic 	static int readaliases();
2724322Seric 
27327176Seric 	if (initialized)
27427176Seric 		return;
27527176Seric 	initialized = TRUE;
27627176Seric 
27717984Seric 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
2788437Seric 	{
27925522Seric 		if (aliasfile != NULL && init)
28058151Seric 			syserr("554 Cannot open %s", aliasfile);
2818437Seric 		NoAlias = TRUE;
28211937Seric 		errno = 0;
2838437Seric 		return;
2848437Seric 	}
2858437Seric 
28656845Seric # if defined(NDBM) || defined(NEWDB)
2874322Seric 	/*
2888437Seric 	**  Check to see that the alias file is complete.
2898437Seric 	**	If not, we will assume that someone died, and it is up
2908437Seric 	**	to us to rebuild it.
2918437Seric 	*/
2928437Seric 
29325689Seric 	if (!init)
29450575Seric 	{
29550575Seric # ifdef NEWDB
29650575Seric 		(void) strcpy(buf, aliasfile);
29750575Seric 		(void) strcat(buf, ".db");
29851171Sbostic 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
29950576Seric 		if (AliasDBptr == NULL)
30050576Seric 		{
30156845Seric # ifdef NDBM
30256845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
30357249Seric 			if (AliasDBMptr == NULL)
30457249Seric 			{
30557249Seric 				syserr("initaliases: cannot open %s", buf);
30657249Seric 				NoAlias = TRUE;
30757249Seric 				return;
30857249Seric 			}
30951756Seric # else
31050576Seric 			syserr("initaliases: cannot open %s", buf);
31150576Seric 			NoAlias = TRUE;
31250576Seric 			return;
31351756Seric # endif
31450576Seric 		}
31550575Seric # else
31656845Seric 		AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
31757249Seric 		if (AliasDBMptr == NULL)
31857249Seric 		{
31957977Seric 			syserr("initaliases: cannot open DBM database %s.{pag,dir}",
32057977Seric 				aliasfile);
32157249Seric 			NoAlias = TRUE;
32257249Seric 			return;
32357249Seric 		}
32450575Seric # endif
32550575Seric 	}
32617471Seric 	atcnt = SafeAlias * 2;
32717471Seric 	if (atcnt > 0)
32817471Seric 	{
32917471Seric 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
33025689Seric 		{
33125689Seric 			/*
33225689Seric 			**  Reinitialize alias file in case the new
33325689Seric 			**  one is mv'ed in instead of cp'ed in.
33425689Seric 			**
33525689Seric 			**	Only works with new DBM -- old one will
33625689Seric 			**	just consume file descriptors forever.
33725689Seric 			**	If you have a dbmclose() it can be
33825689Seric 			**	added before the sleep(30).
33925689Seric 			*/
34025689Seric 
34150575Seric # ifdef NEWDB
34251756Seric 			if (AliasDBptr != NULL)
34351756Seric 				AliasDBptr->close(AliasDBptr);
34450575Seric # endif
34556845Seric # ifdef NDBM
34656845Seric 			if (AliasDBMptr != NULL)
34756845Seric 				dbm_close(AliasDBMptr);
34856845Seric # endif
34950575Seric 
35017471Seric 			sleep(30);
35150575Seric # ifdef NEWDB
35250575Seric 			(void) strcpy(buf, aliasfile);
35350575Seric 			(void) strcat(buf, ".db");
35451171Sbostic 			AliasDBptr =
35551171Sbostic 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
35650576Seric 			if (AliasDBptr == NULL)
35750576Seric 			{
35851756Seric # ifdef NDBM
35956845Seric 				AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
36051756Seric # else
36150576Seric 				syserr("initaliases: cannot open %s", buf);
36250576Seric 				NoAlias = TRUE;
36350576Seric 				return;
36451756Seric # endif
36550576Seric 			}
36650575Seric # else
36725689Seric # ifdef NDBM
36856845Seric 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
36957249Seric 			if (AliasDBMptr == NULL)
37057249Seric 			{
37158008Seric 				syserr("initaliases: cannot open DBM database %s.{pag,dir}",
37258008Seric 					aliasfile);
37357249Seric 				NoAlias = TRUE;
37457249Seric 				return;
37557249Seric 			}
37650575Seric # endif
37750575Seric # endif
37825689Seric 		}
37917471Seric 	}
38017471Seric 	else
38117471Seric 		atcnt = 1;
3828437Seric 
3838437Seric 	/*
38456845Seric 	**  See if the NDBM version of the file is out of date with
3854322Seric 	**  the text version.  If so, go into 'init' mode automatically.
38640559Sbostic 	**	This only happens if our effective userid owns the DBM.
38740559Sbostic 	**	Note the unpalatable hack to see if the stat succeeded.
3884322Seric 	*/
3894322Seric 
3904322Seric 	modtime = stb.st_mtime;
3914322Seric 	(void) strcpy(buf, aliasfile);
39250575Seric # ifdef NEWDB
39350575Seric 	(void) strcat(buf, ".db");
39450575Seric # else
3954322Seric 	(void) strcat(buf, ".pag");
39650575Seric # endif
3974322Seric 	stb.st_ino = 0;
39819039Seric 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
3994322Seric 	{
40011937Seric 		errno = 0;
40140559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
4024322Seric 		{
4034322Seric 			init = TRUE;
40425522Seric 			automatic = TRUE;
40558151Seric 			message("rebuilding alias database");
40624944Seric #ifdef LOG
40758020Seric 			if (LogLevel > 14)
40824944Seric 				syslog(LOG_INFO, "rebuilding alias database");
40956795Seric #endif /* LOG */
4104322Seric 		}
4114322Seric 		else
4124322Seric 		{
41319039Seric #ifdef LOG
41458020Seric 			if (LogLevel > 3)
41524944Seric 				syslog(LOG_INFO, "alias database out of date");
41656795Seric #endif /* LOG */
41758151Seric 			message("Warning: alias database out of date");
4184322Seric 		}
4194322Seric 	}
4204322Seric 
4214322Seric 
4224322Seric 	/*
42356845Seric 	**  If necessary, load the NDBM file.
42456845Seric 	**	If running without NDBM, load the symbol table.
4254322Seric 	*/
4264322Seric 
4274157Seric 	if (init)
4288437Seric 	{
42925522Seric #ifdef LOG
43058020Seric 		if (LogLevel > 7)
43125522Seric 		{
43225522Seric 			extern char *username();
43325522Seric 
43425522Seric 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
43525522Seric 				automatic ? "auto" : "", username());
43625522Seric 		}
43756795Seric #endif /* LOG */
43855012Seric 		readaliases(aliasfile, TRUE, e);
4398437Seric 	}
44056845Seric # else /* NDBM */
44155012Seric 	readaliases(aliasfile, init, e);
44256845Seric # endif /* NDBM */
4434157Seric }
4444157Seric /*
4454157Seric **  READALIASES -- read and process the alias file.
4464157Seric **
4474157Seric **	This routine implements the part of initaliases that occurs
4484157Seric **	when we are not going to use the DBM stuff.
4494157Seric **
4504157Seric **	Parameters:
4514157Seric **		aliasfile -- the pathname of the alias file master.
45256845Seric **		init -- if set, initialize the NDBM stuff.
4534157Seric **
4544157Seric **	Returns:
4554157Seric **		none.
4564157Seric **
4574157Seric **	Side Effects:
4584157Seric **		Reads aliasfile into the symbol table.
4594157Seric **		Optionally, builds the .dir & .pag files.
4604157Seric */
4614157Seric 
4624157Seric static
46355012Seric readaliases(aliasfile, init, e)
4644157Seric 	char *aliasfile;
4654157Seric 	bool init;
46655012Seric 	register ENVELOPE *e;
4674157Seric {
4684098Seric 	register char *p;
4694098Seric 	char *rhs;
4704098Seric 	bool skipping;
4719368Seric 	int naliases, bytes, longest;
4729368Seric 	FILE *af;
47353742Seric 	bool makedbmfiles;
47440970Sbostic 	void (*oldsigint)();
4754098Seric 	ADDRESS al, bl;
4764106Seric 	register STAB *s;
47750575Seric # ifdef NEWDB
47850575Seric 	DB *dbp;
47950575Seric # endif
48056845Seric # ifdef NDBM
48156845Seric 	DBM *dbmp;
48256845Seric # endif
48351937Seric # ifdef LOCKF
48451937Seric 	struct flock fld;
48551937Seric # endif
4869368Seric 	char line[BUFSIZ];
4874098Seric 
48851937Seric 	if ((af = fopen(aliasfile, "r+")) == NULL)
4891515Seric 	{
49057249Seric 		if (init)
49158151Seric 			syserr("554 Can't open %s", aliasfile);
49257249Seric 		else if (tTd(27, 1))
4934106Seric 			printf("Can't open %s\n", aliasfile);
4944098Seric 		errno = 0;
4954098Seric 		NoAlias++;
4964098Seric 		return;
4974098Seric 	}
4984314Seric 
49956845Seric # if defined(NDBM) || defined(NEWDB)
50019784Seric 	/* see if someone else is rebuilding the alias file already */
50151835Seric # ifdef LOCKF
50251937Seric 	fld.l_type = F_WRLCK;
50351937Seric 	fld.l_whence = fld.l_start = fld.l_len = 0;
50451937Seric 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
50551835Seric # else
50619784Seric 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
50751835Seric # endif
50819784Seric 	{
50919784Seric 		/* yes, they are -- wait until done and then return */
51058151Seric 		message("Alias file is already being rebuilt");
51119784Seric 		if (OpMode != MD_INITALIAS)
51219784Seric 		{
51319784Seric 			/* wait for other rebuild to complete */
51451835Seric # ifdef LOCKF
51551937Seric 			(void) fcntl(fileno(af), F_SETLKW, &fld);
51651835Seric # else
51719784Seric 			(void) flock(fileno(af), LOCK_EX);
51851835Seric # endif
51919784Seric 		}
52023108Seric 		(void) fclose(af);
52119784Seric 		errno = 0;
52219784Seric 		return;
52319784Seric 	}
52456845Seric # endif /* NDBM */
52519784Seric 
5264314Seric 	/*
52719784Seric 	**  If initializing, create the new DBM files.
52819784Seric 	*/
52919784Seric 
53019784Seric 	if (init)
53119784Seric 	{
53219784Seric 		oldsigint = signal(SIGINT, SIG_IGN);
53351756Seric # ifdef NEWDB
53451756Seric 		(void) strcpy(line, aliasfile);
53551756Seric 		(void) strcat(line, ".db");
53651756Seric 		dbp = dbopen(line,
53751756Seric 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
53851756Seric 		if (dbp == NULL)
53951756Seric 		{
54051756Seric 			syserr("readaliases: cannot create %s", line);
54151756Seric 			(void) signal(SIGINT, oldsigint);
54251756Seric 			return;
54351756Seric 		}
54453742Seric # endif
54553742Seric # ifdef IF_MAKEDBMFILES
54653742Seric # ifdef NEWDB
54753742Seric 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
54853742Seric # endif
54953742Seric 		IF_MAKEDBMFILES
55019784Seric 		{
55156845Seric 			dbmp = dbm_open(aliasfile,
55256845Seric 					       O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
55356845Seric 			if (dbmp == NULL)
55453742Seric 			{
55556845Seric 				syserr("readaliases: cannot create %s.{dir,pag}",
55656845Seric 					aliasfile);
55753742Seric 				(void) signal(SIGINT, oldsigint);
55853742Seric 				return;
55953742Seric 			}
56019784Seric 		}
56150575Seric # endif
56219784Seric 	}
56319784Seric 
56419784Seric 	/*
5654314Seric 	**  Read and interpret lines
5664314Seric 	*/
5674314Seric 
5689368Seric 	FileName = aliasfile;
5699368Seric 	LineNumber = 0;
5704322Seric 	naliases = bytes = longest = 0;
5714098Seric 	skipping = FALSE;
5724098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5734098Seric 	{
5744322Seric 		int lhssize, rhssize;
5754322Seric 
5769368Seric 		LineNumber++;
57756795Seric 		p = strchr(line, '\n');
57825278Seric 		if (p != NULL)
57925278Seric 			*p = '\0';
5804098Seric 		switch (line[0])
5814098Seric 		{
5824098Seric 		  case '#':
5834098Seric 		  case '\0':
5844098Seric 			skipping = FALSE;
5854098Seric 			continue;
5864065Seric 
5874098Seric 		  case ' ':
5884098Seric 		  case '\t':
5894098Seric 			if (!skipping)
59058151Seric 				syserr("554 Non-continuation line starts with space");
5914098Seric 			skipping = TRUE;
5924097Seric 			continue;
5934098Seric 		}
5944098Seric 		skipping = FALSE;
5951874Seric 
5964314Seric 		/*
5974314Seric 		**  Process the LHS
59857736Seric 		**	Find the colon separator, and parse the address.
59916898Seric 		**	It should resolve to a local name -- this will
60016898Seric 		**	be checked later (we want to optionally do
60116898Seric 		**	parsing of the RHS first to maximize error
60216898Seric 		**	detection).
6034314Seric 		*/
6044314Seric 
6054098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
6064097Seric 			continue;
60716898Seric 		if (*p++ != ':')
6084098Seric 		{
60958151Seric 			syserr("554 missing colon");
6104097Seric 			continue;
6114098Seric 		}
61255012Seric 		if (parseaddr(line, &al, 1, ':', e) == NULL)
6134098Seric 		{
61458151Seric 			syserr("554 illegal alias name");
61516898Seric 			continue;
6164098Seric 		}
61716898Seric 		loweraddr(&al);
6184314Seric 
6194314Seric 		/*
6204314Seric 		**  Process the RHS.
6214314Seric 		**	'al' is the internal form of the LHS address.
6224314Seric 		**	'p' points to the text of the RHS.
6234314Seric 		*/
6244314Seric 
6254098Seric 		rhs = p;
6264098Seric 		for (;;)
6274098Seric 		{
6284098Seric 			register char c;
6291515Seric 
63025821Seric 			if (init && CheckAliases)
6314098Seric 			{
6324157Seric 				/* do parsing & compression of addresses */
63325278Seric 				while (*p != '\0')
6344098Seric 				{
63525278Seric 					extern char *DelimChar;
63625278Seric 
63758050Seric 					while ((isascii(*p) && isspace(*p)) ||
63858050Seric 								*p == ',')
6394157Seric 						p++;
64025278Seric 					if (*p == '\0')
64125278Seric 						break;
64255012Seric 					if (parseaddr(p, &bl, -1, ',', e) == NULL)
64358151Seric 						usrerr("553 %s... bad address", p);
64425278Seric 					p = DelimChar;
6454098Seric 				}
6464098Seric 			}
6474157Seric 			else
64815769Seric 			{
64916898Seric 				p = &p[strlen(p)];
65016898Seric 				if (p[-1] == '\n')
65116898Seric 					*--p = '\0';
65215769Seric 			}
6531515Seric 
6544098Seric 			/* see if there should be a continuation line */
6554106Seric 			c = fgetc(af);
6564106Seric 			if (!feof(af))
6574314Seric 				(void) ungetc(c, af);
6584106Seric 			if (c != ' ' && c != '\t')
6594098Seric 				break;
6604098Seric 
6614098Seric 			/* read continuation line */
6624098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6634098Seric 				break;
6649368Seric 			LineNumber++;
66557135Seric 
66657135Seric 			/* check for line overflow */
66757135Seric 			if (strchr(p, '\n') == NULL)
66857135Seric 			{
66958151Seric 				usrerr("554 alias too long");
67057135Seric 				break;
67157135Seric 			}
6724098Seric 		}
67316898Seric 		if (al.q_mailer != LocalMailer)
67416898Seric 		{
67558151Seric 			syserr("554 cannot alias non-local names");
67616898Seric 			continue;
67716898Seric 		}
6784314Seric 
6794314Seric 		/*
6804314Seric 		**  Insert alias into symbol table or DBM file
6814314Seric 		*/
6824314Seric 
68316898Seric 		lhssize = strlen(al.q_user) + 1;
68457381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
68557381Seric 			makelower(al.q_user);
6864322Seric 		rhssize = strlen(rhs) + 1;
6874322Seric 
68856845Seric # if defined(NDBM) || defined(NEWDB)
6894157Seric 		if (init)
6904157Seric 		{
69156845Seric 			DBdatum key, content;
69257381Seric 			int putstat;
6934157Seric 
69456845Seric 			key.xx.size = lhssize;
69556845Seric 			key.xx.data = al.q_user;
69656845Seric 			content.xx.size = rhssize;
69756845Seric 			content.xx.data = rhs;
69851756Seric # ifdef NEWDB
69957381Seric 			putstat = dbp->put(dbp, &key.dbt, &content.dbt,
70057381Seric 					   R_NOOVERWRITE);
70157381Seric 			if (putstat > 0)
70257381Seric 			{
70357977Seric 				usrerr("050 Warning: duplicate alias name %s",
70457381Seric 					al.q_user);
70557381Seric 				putstat = dbp->put(dbp, &key.dbt,
70657381Seric 						   &content.dbt, 0);
70757381Seric 			}
70857381Seric 			if (putstat != 0)
70950576Seric 				syserr("readaliases: db put (%s)", al.q_user);
71050575Seric # endif
71153742Seric # ifdef IF_MAKEDBMFILES
71253742Seric 			IF_MAKEDBMFILES
71357381Seric 			{
71457381Seric 				putstat = dbm_store(dbmp, key.dbm, content.dbm,
71557381Seric 						    DBM_INSERT);
71657381Seric 				if (putstat > 0)
71757381Seric 				{
71857977Seric 					usrerr("050 Warning: duplicate alias name %s",
71957381Seric 						al.q_user);
72057381Seric 					putstat = dbm_store(dbmp, key.dbm,
72157381Seric 							content.dbm, DBM_REPLACE);
72257381Seric 				}
72357381Seric 				if (putstat != 0)
72456845Seric 					syserr("readaliases: dbm store (%s)",
72556845Seric 						al.q_user);
72657381Seric 			}
72753742Seric # endif
72857381Seric 			if (al.q_paddr != NULL)
72957381Seric 				free(al.q_paddr);
73057381Seric 			if (al.q_host != NULL)
73157381Seric 				free(al.q_host);
73257381Seric 			if (al.q_user != NULL)
73357381Seric 				free(al.q_user);
7344157Seric 		}
7354157Seric 		else
73656845Seric # endif /* NDBM */
7374157Seric 		{
7384157Seric 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
7394157Seric 			s->s_alias = newstr(rhs);
7404157Seric 		}
7414322Seric 
7424322Seric 		/* statistics */
7434322Seric 		naliases++;
7444322Seric 		bytes += lhssize + rhssize;
7454322Seric 		if (rhssize > longest)
7464322Seric 			longest = rhssize;
7471515Seric 	}
74819784Seric 
74956845Seric # if defined(NDBM) || defined(NEWDB)
75019784Seric 	if (init)
75119784Seric 	{
75219784Seric 		/* add the distinquished alias "@" */
75356845Seric 		DBdatum key;
75419784Seric 
75556845Seric 		key.xx.size = 2;
75656845Seric 		key.xx.data = "@";
75750575Seric # ifdef NEWDB
75850576Seric 		if (dbp->sync(dbp) != 0 ||
75956845Seric 		    dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
76050576Seric 		    dbp->close(dbp) != 0)
76150576Seric 			syserr("readaliases: db close failure");
76253742Seric # endif
76356789Seric # ifdef IF_MAKEDBMFILES
76456793Seric 		IF_MAKEDBMFILES
76556845Seric 		{
76658059Seric #ifdef YPCOMPAT
76758059Seric 			nis_magic(dbmp);
76858059Seric #endif
76956845Seric 			if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
77056845Seric 			    dbm_error(dbmp))
77156845Seric 				syserr("readaliases: dbm close failure");
77256845Seric 			dbm_close(dbmp);
77356845Seric 		}
77450575Seric # endif
77519784Seric 
77619784Seric 		/* restore the old signal */
77719784Seric 		(void) signal(SIGINT, oldsigint);
77819784Seric 	}
77956845Seric # endif /* NDBM */
78019784Seric 
78119784Seric 	/* closing the alias file drops the lock */
7824098Seric 	(void) fclose(af);
78355012Seric 	e->e_to = NULL;
7849368Seric 	FileName = NULL;
78558151Seric 	message("%d aliases, longest %d bytes, %d bytes total",
7864322Seric 			naliases, longest, bytes);
78724944Seric # ifdef LOG
78858020Seric 	if (LogLevel > 7)
78924944Seric 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
79024944Seric 			naliases, longest, bytes);
79156795Seric # endif /* LOG */
792292Seric }
793292Seric /*
79458059Seric **  NIS_MAGIC -- Add NIS magic dbm data
79558059Seric **
79658059Seric **	This adds the magic entries needed by SunOS to make this a valid
79758059Seric **	NIS map.
79858059Seric **
79958059Seric **	Parameters:
80058059Seric **		dbmp -- a pointer to the DBM structure.
80158059Seric **
80258059Seric **	Returns:
80358059Seric **		none.
80458059Seric */
80558059Seric 
80658059Seric # ifdef YPCOMPAT
80758059Seric 
80858059Seric static void
80958059Seric nis_magic(dbmp)
81058059Seric 	DBM *dbmp;
81158059Seric {
81258059Seric 	int i;
81358059Seric 	static datum key[2] =
81458059Seric 	{
81558059Seric 		{ "YP_LAST_MODIFIED",	sizeof "YP_LAST_MODIFIED" - 1 },
81658059Seric 		{ "YP_MASTER_NAME",	sizeof "YP_MASTER_NAME" - 1 },
81758059Seric 	};
81858059Seric 	datum contents[2];
81958059Seric 	char tbuf[12];
82058059Seric 	char hbuf[MAXHOSTNAMELEN];
82158059Seric 
82258059Seric 	(void) sprintf(tbuf, "%010ld", curtime());
82358059Seric 	contents[0].dptr = tbuf;
82458059Seric 	contents[0].dsize = strlen(tbuf);
82558059Seric 
82658059Seric 	(void) myhostname(hbuf, sizeof hbuf);
82758059Seric 	contents[1].dptr = hbuf;
82858059Seric 	contents[1].dptr = strlen(hbuf);
82958059Seric 
83058059Seric 	for (i = 0; i < sizeof key / sizeof *key; i++)
83158059Seric 	{
83258059Seric 		if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 ||
83358059Seric 		    dbm_error(dbmp))
83458059Seric 			syserr("nis_magic: dbm_store failure");
83558059Seric 	}
83658059Seric }
83758059Seric 
83858059Seric # endif
83958059Seric /*
840292Seric **  FORWARD -- Try to forward mail
841292Seric **
842292Seric **	This is similar but not identical to aliasing.
843292Seric **
844292Seric **	Parameters:
8454314Seric **		user -- the name of the user who's mail we would like
8464314Seric **			to forward to.  It must have been verified --
8474314Seric **			i.e., the q_home field must have been filled
8484314Seric **			in.
8494999Seric **		sendq -- a pointer to the head of the send queue to
8504999Seric **			put this user's aliases in.
851292Seric **
852292Seric **	Returns:
8534098Seric **		none.
854292Seric **
855292Seric **	Side Effects:
8563185Seric **		New names are added to send queues.
857292Seric */
858292Seric 
85955012Seric forward(user, sendq, e)
8602966Seric 	ADDRESS *user;
8614999Seric 	ADDRESS **sendq;
86255012Seric 	register ENVELOPE *e;
863292Seric {
86457136Seric 	char *pp;
86557136Seric 	char *ep;
8664536Seric 	extern bool safefile();
8674069Seric 
8687671Seric 	if (tTd(27, 1))
8694098Seric 		printf("forward(%s)\n", user->q_paddr);
8704098Seric 
8714594Seric 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
8724098Seric 		return;
8734314Seric 	if (user->q_home == NULL)
87458059Seric 	{
87558151Seric 		syserr("554 forward: no home");
87658059Seric 		user->q_home = "/nosuchdirectory";
87758059Seric 	}
8784069Seric 
8794069Seric 	/* good address -- look for .forward file in home */
88055012Seric 	define('z', user->q_home, e);
88157136Seric 	define('u', user->q_user, e);
88257136Seric 	define('h', user->q_host, e);
88357136Seric 	if (ForwardPath == NULL)
88458050Seric 		ForwardPath = newstr("\201z/.forward");
88557136Seric 
88657136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
88757136Seric 	{
88857232Seric 		char buf[MAXPATHLEN+1];
88957136Seric 
89057136Seric 		ep = strchr(pp, ':');
89157136Seric 		if (ep != NULL)
89257136Seric 			*ep = '\0';
89357136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
89457136Seric 		if (ep != NULL)
89557136Seric 			*ep++ = ':';
89657136Seric 		if (tTd(27, 3))
89757136Seric 			printf("forward: trying %s\n", buf);
89857136Seric 		if (include(buf, TRUE, user, sendq, e) == 0)
89957136Seric 			break;
90057136Seric 	}
901292Seric }
902