xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 68798)
122694Sdist /*
235073Sbostic  * Copyright (c) 1983 Eric P. Allman
362522Sbostic  * Copyright (c) 1988, 1993
462522Sbostic  *	The Regents of the University of California.  All rights reserved.
533728Sbostic  *
642824Sbostic  * %sccs.include.redist.c%
733728Sbostic  */
822694Sdist 
958332Seric # include "sendmail.h"
1056766Seric 
1133728Sbostic #ifndef lint
12*68798Seric static char sccsid[] = "@(#)alias.c	8.43 (Berkeley) 04/13/95";
1333728Sbostic #endif /* not lint */
1459673Seric 
1559673Seric 
1660537Seric MAP	*AliasDB[MAXALIASDB + 1];	/* actual database list */
1759673Seric int	NAliasDBs;			/* number of alias databases */
1859673Seric /*
19292Seric **  ALIAS -- Compute aliases.
20292Seric **
219368Seric **	Scans the alias file for an alias for the given address.
229368Seric **	If found, it arranges to deliver to the alias list instead.
239368Seric **	Uses libdbm database if -DDBM.
24292Seric **
25292Seric **	Parameters:
264097Seric **		a -- address to alias.
274999Seric **		sendq -- a pointer to the head of the send queue
284999Seric **			to put the aliases in.
2967982Seric **		aliaslevel -- the current alias nesting depth.
3058092Seric **		e -- the current envelope.
31292Seric **
32292Seric **	Returns:
33292Seric **		none
34292Seric **
35292Seric **	Side Effects:
363185Seric **		Aliases found are expanded.
37292Seric **
38292Seric **	Deficiencies:
39292Seric **		It should complain about names that are aliased to
40292Seric **			nothing.
41292Seric */
42292Seric 
4368433Seric void
4467982Seric alias(a, sendq, aliaslevel, e)
454097Seric 	register ADDRESS *a;
464999Seric 	ADDRESS **sendq;
4767982Seric 	int aliaslevel;
4855012Seric 	register ENVELOPE *e;
49292Seric {
504081Seric 	register char *p;
5158082Seric 	int naliases;
5258170Seric 	char *owner;
5368706Seric 	auto int stat = EX_OK;
5458170Seric 	char obuf[MAXNAME + 6];
555701Seric 	extern char *aliaslookup();
56292Seric 
577671Seric 	if (tTd(27, 1))
5867426Seric 		printf("alias(%s)\n", a->q_user);
59292Seric 
604098Seric 	/* don't realias already aliased names */
6158680Seric 	if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
624098Seric 		return;
634098Seric 
6459673Seric 	if (NoAlias)
6559673Seric 		return;
6659673Seric 
6755012Seric 	e->e_to = a->q_paddr;
684098Seric 
694314Seric 	/*
7068706Seric 	**  Look up this name.
7168706Seric 	**
7268706Seric 	**	If the map was unavailable, we will queue this message
7368706Seric 	**	until the map becomes available; otherwise, we could
7468706Seric 	**	bounce messages inappropriately.
754314Seric 	*/
764314Seric 
7768706Seric 	p = aliaslookup(a->q_user, &stat, e);
7868706Seric 	if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE)
7968706Seric 	{
8068706Seric 		a->q_flags |= QQUEUEUP;
8168706Seric 		if (e->e_message == NULL)
8268706Seric 			e->e_message = "alias database unavailable";
8368706Seric 		return;
8468706Seric 	}
854098Seric 	if (p == NULL)
864098Seric 		return;
87292Seric 
88292Seric 	/*
894098Seric 	**  Match on Alias.
904098Seric 	**	Deliver to the target list.
911515Seric 	*/
921515Seric 
937671Seric 	if (tTd(27, 1))
944098Seric 		printf("%s (%s, %s) aliased to %s\n",
954098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
9658092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
9758154Seric 	{
9858154Seric 		a->q_flags |= QVERIFIED;
9958884Seric 		e->e_nrcpts++;
10058092Seric 		return;
10158154Seric 	}
10258154Seric 	message("aliased to %s", p);
10357977Seric #ifdef LOG
10458020Seric 	if (LogLevel > 9)
10566280Seric 		syslog(LOG_INFO, "%s: alias %s => %s",
10666280Seric 			e->e_id == NULL ? "NOQUEUE" : e->e_id,
10766280Seric 			a->q_paddr, p);
10857977Seric #endif
10958082Seric 	a->q_flags &= ~QSELFREF;
11067982Seric 	if (tTd(27, 5))
11158065Seric 	{
11267982Seric 		printf("alias: QDONTSEND ");
11367982Seric 		printaddr(a, FALSE);
11458065Seric 	}
11567982Seric 	a->q_flags |= QDONTSEND;
11667982Seric 	naliases = sendtolist(p, a, sendq, aliaslevel + 1, e);
11767982Seric 	if (bitset(QSELFREF, a->q_flags))
11867982Seric 		a->q_flags &= ~QDONTSEND;
11958170Seric 
12058170Seric 	/*
12158170Seric 	**  Look for owner of alias
12258170Seric 	*/
12358170Seric 
12458170Seric 	(void) strcpy(obuf, "owner-");
12558170Seric 	if (strncmp(a->q_user, "owner-", 6) == 0)
12658170Seric 		(void) strcat(obuf, "owner");
12758170Seric 	else
12858170Seric 		(void) strcat(obuf, a->q_user);
12958170Seric 	if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
13058170Seric 		makelower(obuf);
13168706Seric 	owner = aliaslookup(obuf, &stat, e);
13266784Seric 	if (owner == NULL)
13366784Seric 		return;
13466784Seric 
13566784Seric 	/* reflect owner into envelope sender */
13666784Seric 	if (strpbrk(owner, ",:/|\"") != NULL)
13766784Seric 		owner = obuf;
13866784Seric 	a->q_owner = newstr(owner);
13966784Seric 
14066784Seric 	/* announce delivery to this alias; NORECEIPT bit set later */
14166784Seric 	if (e->e_xfp != NULL)
14266784Seric 		fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
14366784Seric 			a->q_paddr);
14468001Seric 	e->e_flags |= EF_SENDRECEIPT;
14568603Seric 	a->q_flags |= QREPORT|QEXPLODED;
1464098Seric }
1474098Seric /*
1485701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1495701Seric **
1505701Seric **	Parameters:
1515701Seric **		name -- the name to look up.
15268706Seric **		pstat -- a pointer to a place to put the status.
15368706Seric **		e -- the current envelope.
1545701Seric **
1555701Seric **	Returns:
1565701Seric **		the value of name.
1575701Seric **		NULL if unknown.
1585701Seric **
1595701Seric **	Side Effects:
1605701Seric **		none.
1615701Seric **
1625701Seric **	Warnings:
1635701Seric **		The return value will be trashed across calls.
1645701Seric */
1655701Seric 
1665701Seric char *
16768706Seric aliaslookup(name, pstat, e)
1685701Seric 	char *name;
16968706Seric 	int *pstat;
17059673Seric 	ENVELOPE *e;
1715701Seric {
17259673Seric 	register int dbno;
17360089Seric 	register MAP *map;
17459673Seric 	register char *p;
1755701Seric 
17659673Seric 	for (dbno = 0; dbno < NAliasDBs; dbno++)
17759673Seric 	{
17860089Seric 		auto int stat;
17960089Seric 
18060537Seric 		map = AliasDB[dbno];
18160207Seric 		if (!bitset(MF_OPEN, map->map_mflags))
18259673Seric 			continue;
18368706Seric 		p = (*map->map_class->map_lookup)(map, name, NULL, pstat);
18459673Seric 		if (p != NULL)
18559673Seric 			return p;
18659673Seric 	}
18759673Seric 	return NULL;
18859673Seric }
18959673Seric /*
19059673Seric **  SETALIAS -- set up an alias map
19159673Seric **
19259673Seric **	Called when reading configuration file.
19359673Seric **
19459673Seric **	Parameters:
19559673Seric **		spec -- the alias specification
19659673Seric **
19759673Seric **	Returns:
19859673Seric **		none.
19959673Seric */
20057381Seric 
20168433Seric void
20259673Seric setalias(spec)
20359673Seric 	char *spec;
20459673Seric {
20559673Seric 	register char *p;
20660089Seric 	register MAP *map;
20759673Seric 	char *class;
20859673Seric 	STAB *s;
20968096Seric 	static bool first_unqual = TRUE;
21059673Seric 
21159697Seric 	if (tTd(27, 8))
21259697Seric 		printf("setalias(%s)\n", spec);
21359697Seric 
21459758Seric 	for (p = spec; p != NULL; )
21551756Seric 	{
21659758Seric 		while (isspace(*p))
21759758Seric 			p++;
21860502Seric 		if (*p == '\0')
21959673Seric 			break;
22059673Seric 		spec = p;
22159673Seric 
22267848Seric 		/*
22367848Seric 		**  Treat simple filename specially -- this is the file name
22467848Seric 		**  for the files implementation, not necessarily in order.
22567848Seric 		*/
22667848Seric 
22768096Seric 		if (spec[0] == '/' && first_unqual)
22859758Seric 		{
22967848Seric 			s = stab("aliases.files", ST_MAP, ST_ENTER);
23067848Seric 			map = &s->s_map;
23168096Seric 			first_unqual = FALSE;
23259758Seric 		}
23367848Seric 		else
23467848Seric 		{
23567848Seric 			char aname[50];
23667848Seric 
23767848Seric 			if (NAliasDBs >= MAXALIASDB)
23867848Seric 			{
23967848Seric 				syserr("Too many alias databases defined, %d max",
24067848Seric 					MAXALIASDB);
24167848Seric 				return;
24267848Seric 			}
24367848Seric 			(void) sprintf(aname, "Alias%d", NAliasDBs);
24467848Seric 			s = stab(aname, ST_MAP, ST_ENTER);
24567848Seric 			map = &s->s_map;
24667848Seric 			AliasDB[NAliasDBs] = map;
24767848Seric 		}
24860089Seric 		bzero(map, sizeof *map);
24967973Seric 		map->map_mname = s->s_name;
25059758Seric 
25159758Seric 		p = strpbrk(p, " ,/:");
25259758Seric 		if (p != NULL && *p == ':')
25359758Seric 		{
25460089Seric 			/* map name */
25559758Seric 			*p++ = '\0';
25659758Seric 			class = spec;
25759758Seric 			spec = p;
25859758Seric 		}
25959758Seric 		else
26059758Seric 		{
26159758Seric 			class = "implicit";
26260228Seric 			map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
26359758Seric 		}
26459758Seric 
26559758Seric 		/* find end of spec */
26659758Seric 		if (p != NULL)
26759758Seric 			p = strchr(p, ',');
26859758Seric 		if (p != NULL)
26959758Seric 			*p++ = '\0';
27059758Seric 
27167848Seric 		if (tTd(27, 20))
27267848Seric 			printf("  map %s:%s %s\n", class, s->s_name, spec);
27367848Seric 
27459758Seric 		/* look up class */
27560089Seric 		s = stab(class, ST_MAPCLASS, ST_FIND);
27659758Seric 		if (s == NULL)
27759758Seric 		{
27859758Seric 			if (tTd(27, 1))
27959758Seric 				printf("Unknown alias class %s\n", class);
28059758Seric 		}
28160207Seric 		else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
28260207Seric 		{
28360207Seric 			syserr("setalias: map class %s can't handle aliases",
28460207Seric 				class);
28560207Seric 		}
28659758Seric 		else
28759758Seric 		{
28860207Seric 			map->map_class = &s->s_mapclass;
28960089Seric 			if (map->map_class->map_parse(map, spec))
29060089Seric 			{
29160207Seric 				map->map_mflags |= MF_VALID|MF_ALIAS;
29267848Seric 				if (AliasDB[NAliasDBs] == map)
29367848Seric 					NAliasDBs++;
29460089Seric 			}
29559758Seric 		}
29659756Seric 	}
2975701Seric }
2985701Seric /*
29959673Seric **  ALIASWAIT -- wait for distinguished @:@ token to appear.
30059673Seric **
30159673Seric **	This can decide to reopen or rebuild the alias file
30264718Seric **
30364718Seric **	Parameters:
30464718Seric **		map -- a pointer to the map descriptor for this alias file.
30564718Seric **		ext -- the filename extension (e.g., ".db") for the
30664718Seric **			database file.
30764718Seric **		isopen -- if set, the database is already open, and we
30864718Seric **			should check for validity; otherwise, we are
30964718Seric **			just checking to see if it should be created.
31064718Seric **
31164718Seric **	Returns:
31264718Seric **		TRUE -- if the database is open when we return.
31364718Seric **		FALSE -- if the database is closed when we return.
31459673Seric */
31559673Seric 
31664718Seric bool
31764718Seric aliaswait(map, ext, isopen)
31860089Seric 	MAP *map;
31960207Seric 	char *ext;
32064718Seric 	int isopen;
32159673Seric {
32264795Seric 	bool attimeout = FALSE;
32359673Seric 	time_t mtime;
32459673Seric 	struct stat stb;
32568528Seric 	char buf[MAXNAME + 1];
32659673Seric 
32759697Seric 	if (tTd(27, 3))
32860207Seric 		printf("aliaswait(%s:%s)\n",
32960207Seric 			map->map_class->map_cname, map->map_file);
33064648Seric 	if (bitset(MF_ALIASWAIT, map->map_mflags))
33164795Seric 		return isopen;
33264648Seric 	map->map_mflags |= MF_ALIASWAIT;
33359697Seric 
33464795Seric 	if (SafeAlias > 0)
33517471Seric 	{
33660089Seric 		auto int st;
33764795Seric 		time_t toolong = curtime() + SafeAlias;
33864795Seric 		unsigned int sleeptime = 2;
33960089Seric 
34064795Seric 		while (isopen &&
34160089Seric 		       map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
34225689Seric 		{
34364795Seric 			if (curtime() > toolong)
34464795Seric 			{
34564795Seric 				/* we timed out */
34664795Seric 				attimeout = TRUE;
34764795Seric 				break;
34864795Seric 			}
34964795Seric 
35025689Seric 			/*
35159673Seric 			**  Close and re-open the alias database in case
35259673Seric 			**  the one is mv'ed instead of cp'ed in.
35325689Seric 			*/
35425689Seric 
35559697Seric 			if (tTd(27, 2))
35664795Seric 				printf("aliaswait: sleeping for %d seconds\n",
35764795Seric 					sleeptime);
35859697Seric 
35960089Seric 			map->map_class->map_close(map);
360*68798Seric 			map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
36164795Seric 			sleep(sleeptime);
36264795Seric 			sleeptime *= 2;
36364795Seric 			if (sleeptime > 60)
36464795Seric 				sleeptime = 60;
36564718Seric 			isopen = map->map_class->map_open(map, O_RDONLY);
36625689Seric 		}
36717471Seric 	}
3688437Seric 
36959673Seric 	/* see if we need to go into auto-rebuild mode */
37060207Seric 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
37160207Seric 	{
37260207Seric 		if (tTd(27, 3))
37360207Seric 			printf("aliaswait: not rebuildable\n");
37464648Seric 		map->map_mflags &= ~MF_ALIASWAIT;
37564718Seric 		return isopen;
37660207Seric 	}
37760207Seric 	if (stat(map->map_file, &stb) < 0)
37860207Seric 	{
37960207Seric 		if (tTd(27, 3))
38060207Seric 			printf("aliaswait: no source file\n");
38164648Seric 		map->map_mflags &= ~MF_ALIASWAIT;
38264718Seric 		return isopen;
38360207Seric 	}
38459673Seric 	mtime = stb.st_mtime;
38560089Seric 	(void) strcpy(buf, map->map_file);
38660207Seric 	if (ext != NULL)
38760207Seric 		(void) strcat(buf, ext);
38864795Seric 	if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
3894322Seric 	{
39059673Seric 		/* database is out of date */
39140559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3924322Seric 		{
39368101Seric 			bool oldSuprErrs;
39468101Seric 
39560089Seric 			message("auto-rebuilding alias database %s", buf);
39668101Seric 			oldSuprErrs = SuprErrs;
39768101Seric 			SuprErrs = TRUE;
39864718Seric 			if (isopen)
399*68798Seric 			{
40064718Seric 				map->map_class->map_close(map);
401*68798Seric 				map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
402*68798Seric 			}
40360207Seric 			rebuildaliases(map, TRUE);
40464718Seric 			isopen = map->map_class->map_open(map, O_RDONLY);
40568101Seric 			SuprErrs = oldSuprErrs;
4064322Seric 		}
4074322Seric 		else
4084322Seric 		{
40919039Seric #ifdef LOG
41058020Seric 			if (LogLevel > 3)
41159673Seric 				syslog(LOG_INFO, "alias database %s out of date",
41260089Seric 					buf);
41356795Seric #endif /* LOG */
41460089Seric 			message("Warning: alias database %s out of date", buf);
4154322Seric 		}
4164322Seric 	}
41764648Seric 	map->map_mflags &= ~MF_ALIASWAIT;
41864718Seric 	return isopen;
41959673Seric }
42059673Seric /*
42159673Seric **  REBUILDALIASES -- rebuild the alias database.
42259673Seric **
42359673Seric **	Parameters:
42460089Seric **		map -- the database to rebuild.
42559673Seric **		automatic -- set if this was automatically generated.
42659673Seric **
42759673Seric **	Returns:
42859673Seric **		none.
42959673Seric **
43059673Seric **	Side Effects:
43159673Seric **		Reads the text version of the database, builds the
43259673Seric **		DBM or DB version.
43359673Seric */
4344322Seric 
43568433Seric void
43660207Seric rebuildaliases(map, automatic)
43760089Seric 	register MAP *map;
43859673Seric 	bool automatic;
43959673Seric {
44059673Seric 	FILE *af;
44164388Seric 	bool nolock = FALSE;
44267430Seric 	sigfunc_t oldsigint, oldsigquit;
44367430Seric #ifdef SIGTSTP
44467430Seric 	sigfunc_t oldsigtstp;
44567430Seric #endif
4464322Seric 
44760207Seric 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
44859673Seric 		return;
4494322Seric 
45059673Seric 	/* try to lock the source file */
45160089Seric 	if ((af = fopen(map->map_file, "r+")) == NULL)
45259673Seric 	{
45365953Seric 		if ((errno != EACCES && errno != EROFS) || automatic ||
45464388Seric 		    (af = fopen(map->map_file, "r")) == NULL)
45564388Seric 		{
45664388Seric 			int saveerr = errno;
45764382Seric 
45864388Seric 			if (tTd(27, 1))
45964388Seric 				printf("Can't open %s: %s\n",
46064388Seric 					map->map_file, errstring(saveerr));
46168435Seric 			if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
46264388Seric 				message("newaliases: cannot open %s: %s",
46364388Seric 					map->map_file, errstring(saveerr));
46464388Seric 			errno = 0;
46564388Seric 			return;
46664388Seric 		}
46764388Seric 		nolock = TRUE;
46864388Seric 		message("warning: cannot lock %s: %s",
46964388Seric 			map->map_file, errstring(errno));
4708437Seric 	}
47159673Seric 
47259673Seric 	/* see if someone else is rebuilding the alias file */
47364388Seric 	if (!nolock &&
47464388Seric 	    !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
47559673Seric 	{
47659673Seric 		/* yes, they are -- wait until done */
47759673Seric 		message("Alias file %s is already being rebuilt",
47860089Seric 			map->map_file);
47959673Seric 		if (OpMode != MD_INITALIAS)
48059673Seric 		{
48159673Seric 			/* wait for other rebuild to complete */
48264335Seric 			(void) lockfile(fileno(af), map->map_file, NULL,
48359673Seric 					LOCK_EX);
48459673Seric 		}
48564772Seric 		(void) xfclose(af, "rebuildaliases1", map->map_file);
48659673Seric 		errno = 0;
48759673Seric 		return;
48859673Seric 	}
48959673Seric 
49067430Seric 	/* avoid denial-of-service attacks */
49167430Seric 	resetlimits();
49264035Seric 	oldsigint = setsignal(SIGINT, SIG_IGN);
49367430Seric 	oldsigquit = setsignal(SIGQUIT, SIG_IGN);
49467430Seric #ifdef SIGTSTP
49567430Seric 	oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
49667430Seric #endif
49759673Seric 
49860207Seric 	if (map->map_class->map_open(map, O_RDWR))
49960089Seric 	{
50064382Seric #ifdef LOG
50164382Seric 		if (LogLevel > 7)
50264382Seric 		{
50364382Seric 			syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
50464382Seric 				map->map_file, automatic ? "auto" : "",
50564382Seric 				username());
50664382Seric 		}
50764382Seric #endif /* LOG */
50860207Seric 		map->map_mflags |= MF_OPEN|MF_WRITABLE;
50967263Seric 		readaliases(map, af, !automatic, TRUE);
51060089Seric 	}
51160207Seric 	else
51260207Seric 	{
51360207Seric 		if (tTd(27, 1))
51460207Seric 			printf("Can't create database for %s: %s\n",
51560207Seric 				map->map_file, errstring(errno));
51660207Seric 		if (!automatic)
51760207Seric 			syserr("Cannot create database for alias file %s",
51860207Seric 				map->map_file);
51960207Seric 	}
52059673Seric 
52159673Seric 	/* close the file, thus releasing locks */
52264772Seric 	xfclose(af, "rebuildaliases2", map->map_file);
52359673Seric 
52459673Seric 	/* add distinguished entries and close the database */
52560207Seric 	if (bitset(MF_OPEN, map->map_mflags))
526*68798Seric 	{
52760089Seric 		map->map_class->map_close(map);
528*68798Seric 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
529*68798Seric 	}
53059673Seric 
53167430Seric 	/* restore the old signals */
53264035Seric 	(void) setsignal(SIGINT, oldsigint);
53367430Seric 	(void) setsignal(SIGQUIT, oldsigquit);
53467430Seric #ifdef SIGTSTP
53567430Seric 	(void) setsignal(SIGTSTP, oldsigtstp);
53667430Seric #endif
5374157Seric }
5384157Seric /*
5394157Seric **  READALIASES -- read and process the alias file.
5404157Seric **
5414157Seric **	This routine implements the part of initaliases that occurs
5424157Seric **	when we are not going to use the DBM stuff.
5434157Seric **
5444157Seric **	Parameters:
54560089Seric **		map -- the alias database descriptor.
54659673Seric **		af -- file to read the aliases from.
54767263Seric **		announcestats -- anounce statistics regarding number of
54867263Seric **			aliases, longest alias, etc.
54967263Seric **		logstats -- lot the same info.
5504157Seric **
5514157Seric **	Returns:
5524157Seric **		none.
5534157Seric **
5544157Seric **	Side Effects:
5554157Seric **		Reads aliasfile into the symbol table.
5564157Seric **		Optionally, builds the .dir & .pag files.
5574157Seric */
5584157Seric 
55968433Seric void
56067263Seric readaliases(map, af, announcestats, logstats)
56160089Seric 	register MAP *map;
56259673Seric 	FILE *af;
56367263Seric 	bool announcestats;
56467263Seric 	bool logstats;
5654157Seric {
5664098Seric 	register char *p;
5674098Seric 	char *rhs;
5684098Seric 	bool skipping;
56959673Seric 	long naliases, bytes, longest;
5704098Seric 	ADDRESS al, bl;
5719368Seric 	char line[BUFSIZ];
5724098Seric 
5734314Seric 	/*
5744314Seric 	**  Read and interpret lines
5754314Seric 	*/
5764314Seric 
57760089Seric 	FileName = map->map_file;
5789368Seric 	LineNumber = 0;
5794322Seric 	naliases = bytes = longest = 0;
5804098Seric 	skipping = FALSE;
5814098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5824098Seric 	{
5834322Seric 		int lhssize, rhssize;
5844322Seric 
5859368Seric 		LineNumber++;
58656795Seric 		p = strchr(line, '\n');
58725278Seric 		if (p != NULL)
58825278Seric 			*p = '\0';
5894098Seric 		switch (line[0])
5904098Seric 		{
5914098Seric 		  case '#':
5924098Seric 		  case '\0':
5934098Seric 			skipping = FALSE;
5944098Seric 			continue;
5954065Seric 
5964098Seric 		  case ' ':
5974098Seric 		  case '\t':
5984098Seric 			if (!skipping)
59958151Seric 				syserr("554 Non-continuation line starts with space");
6004098Seric 			skipping = TRUE;
6014097Seric 			continue;
6024098Seric 		}
6034098Seric 		skipping = FALSE;
6041874Seric 
6054314Seric 		/*
6064314Seric 		**  Process the LHS
60757736Seric 		**	Find the colon separator, and parse the address.
60816898Seric 		**	It should resolve to a local name -- this will
60916898Seric 		**	be checked later (we want to optionally do
61016898Seric 		**	parsing of the RHS first to maximize error
61116898Seric 		**	detection).
6124314Seric 		*/
6134314Seric 
6144098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
6154097Seric 			continue;
61616898Seric 		if (*p++ != ':')
6174098Seric 		{
61858151Seric 			syserr("554 missing colon");
6194097Seric 			continue;
6204098Seric 		}
62164284Seric 		if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
6224098Seric 		{
62364838Seric 			syserr("554 %.40s... illegal alias name", line);
62416898Seric 			continue;
6254098Seric 		}
6264314Seric 
6274314Seric 		/*
6284314Seric 		**  Process the RHS.
6294314Seric 		**	'al' is the internal form of the LHS address.
6304314Seric 		**	'p' points to the text of the RHS.
6314314Seric 		*/
6324314Seric 
63358914Seric 		while (isascii(*p) && isspace(*p))
63458914Seric 			p++;
6354098Seric 		rhs = p;
6364098Seric 		for (;;)
6374098Seric 		{
6384098Seric 			register char c;
63958662Seric 			register char *nlp;
6401515Seric 
64158662Seric 			nlp = &p[strlen(p)];
64258662Seric 			if (nlp[-1] == '\n')
64358662Seric 				*--nlp = '\0';
64458662Seric 
64559673Seric 			if (CheckAliases)
6464098Seric 			{
6474157Seric 				/* do parsing & compression of addresses */
64825278Seric 				while (*p != '\0')
6494098Seric 				{
65058333Seric 					auto char *delimptr;
65125278Seric 
65258050Seric 					while ((isascii(*p) && isspace(*p)) ||
65358050Seric 								*p == ',')
6544157Seric 						p++;
65525278Seric 					if (*p == '\0')
65625278Seric 						break;
65764284Seric 					if (parseaddr(p, &bl, RF_COPYNONE, ',',
65864284Seric 						      &delimptr, CurEnv) == NULL)
65958151Seric 						usrerr("553 %s... bad address", p);
66058333Seric 					p = delimptr;
6614098Seric 				}
6624098Seric 			}
6634157Seric 			else
66415769Seric 			{
66558662Seric 				p = nlp;
66615769Seric 			}
6671515Seric 
6684098Seric 			/* see if there should be a continuation line */
6694106Seric 			c = fgetc(af);
6704106Seric 			if (!feof(af))
6714314Seric 				(void) ungetc(c, af);
6724106Seric 			if (c != ' ' && c != '\t')
6734098Seric 				break;
6744098Seric 
6754098Seric 			/* read continuation line */
6764098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6774098Seric 				break;
6789368Seric 			LineNumber++;
67957135Seric 
68057135Seric 			/* check for line overflow */
68157135Seric 			if (strchr(p, '\n') == NULL)
68257135Seric 			{
68358151Seric 				usrerr("554 alias too long");
68457135Seric 				break;
68557135Seric 			}
6864098Seric 		}
68767473Seric 		if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
68816898Seric 		{
68964278Seric 			syserr("554 %s... cannot alias non-local names",
69064278Seric 				al.q_paddr);
69116898Seric 			continue;
69216898Seric 		}
6934314Seric 
6944314Seric 		/*
6954314Seric 		**  Insert alias into symbol table or DBM file
6964314Seric 		*/
6974314Seric 
69857381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
69957381Seric 			makelower(al.q_user);
7004322Seric 
70159673Seric 		lhssize = strlen(al.q_user);
70259673Seric 		rhssize = strlen(rhs);
70360089Seric 		map->map_class->map_store(map, al.q_user, rhs);
7044157Seric 
70559673Seric 		if (al.q_paddr != NULL)
70659673Seric 			free(al.q_paddr);
70759673Seric 		if (al.q_host != NULL)
70859673Seric 			free(al.q_host);
70959673Seric 		if (al.q_user != NULL)
71059673Seric 			free(al.q_user);
7114322Seric 
7124322Seric 		/* statistics */
7134322Seric 		naliases++;
7144322Seric 		bytes += lhssize + rhssize;
7154322Seric 		if (rhssize > longest)
7164322Seric 			longest = rhssize;
7171515Seric 	}
71819784Seric 
71960207Seric 	CurEnv->e_to = NULL;
72059673Seric 	FileName = NULL;
72167263Seric 	if (Verbose || announcestats)
72259733Seric 		message("%s: %d aliases, longest %d bytes, %d bytes total",
72360089Seric 			map->map_file, naliases, longest, bytes);
72459673Seric # ifdef LOG
72567263Seric 	if (LogLevel > 7 && logstats)
72659673Seric 		syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
72760089Seric 			map->map_file, naliases, longest, bytes);
72859673Seric # endif /* LOG */
72959673Seric }
73059673Seric /*
731292Seric **  FORWARD -- Try to forward mail
732292Seric **
733292Seric **	This is similar but not identical to aliasing.
734292Seric **
735292Seric **	Parameters:
7364314Seric **		user -- the name of the user who's mail we would like
7374314Seric **			to forward to.  It must have been verified --
7384314Seric **			i.e., the q_home field must have been filled
7394314Seric **			in.
7404999Seric **		sendq -- a pointer to the head of the send queue to
7414999Seric **			put this user's aliases in.
74267982Seric **		aliaslevel -- the current alias nesting depth.
74367982Seric **		e -- the current envelope.
744292Seric **
745292Seric **	Returns:
7464098Seric **		none.
747292Seric **
748292Seric **	Side Effects:
7493185Seric **		New names are added to send queues.
750292Seric */
751292Seric 
75268433Seric void
75367982Seric forward(user, sendq, aliaslevel, e)
7542966Seric 	ADDRESS *user;
7554999Seric 	ADDRESS **sendq;
75667982Seric 	int aliaslevel;
75755012Seric 	register ENVELOPE *e;
758292Seric {
75957136Seric 	char *pp;
76057136Seric 	char *ep;
7614069Seric 
7627671Seric 	if (tTd(27, 1))
7634098Seric 		printf("forward(%s)\n", user->q_paddr);
7644098Seric 
76567473Seric 	if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
76667473Seric 	    bitset(QBADADDR, user->q_flags))
7674098Seric 		return;
7684314Seric 	if (user->q_home == NULL)
76958059Seric 	{
77058151Seric 		syserr("554 forward: no home");
77158059Seric 		user->q_home = "/nosuchdirectory";
77258059Seric 	}
7734069Seric 
7744069Seric 	/* good address -- look for .forward file in home */
77555012Seric 	define('z', user->q_home, e);
77657136Seric 	define('u', user->q_user, e);
77757136Seric 	define('h', user->q_host, e);
77857136Seric 	if (ForwardPath == NULL)
77958050Seric 		ForwardPath = newstr("\201z/.forward");
78057136Seric 
78157136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
78257136Seric 	{
78358247Seric 		int err;
78457232Seric 		char buf[MAXPATHLEN+1];
78568433Seric 		extern int include();
78657136Seric 
78757136Seric 		ep = strchr(pp, ':');
78857136Seric 		if (ep != NULL)
78957136Seric 			*ep = '\0';
79068529Seric 		expand(pp, buf, sizeof buf, e);
79157136Seric 		if (ep != NULL)
79257136Seric 			*ep++ = ':';
79357136Seric 		if (tTd(27, 3))
79457136Seric 			printf("forward: trying %s\n", buf);
79563753Seric 
79667982Seric 		err = include(buf, TRUE, user, sendq, aliaslevel, e);
79758247Seric 		if (err == 0)
79857136Seric 			break;
79964325Seric 		else if (transienterror(err))
80058247Seric 		{
80158247Seric 			/* we have to suspend this message */
80259563Seric 			if (tTd(27, 2))
80359563Seric 				printf("forward: transient error on %s\n", buf);
80459563Seric #ifdef LOG
80559563Seric 			if (LogLevel > 2)
80659624Seric 				syslog(LOG_ERR, "%s: forward %s: transient error: %s",
80766284Seric 					e->e_id == NULL ? "NOQUEUE" : e->e_id,
80866284Seric 					buf, errstring(err));
80959563Seric #endif
81059611Seric 			message("%s: %s: message queued", buf, errstring(err));
81163853Seric 			user->q_flags |= QQUEUEUP;
81258247Seric 			return;
81358247Seric 		}
81457136Seric 	}
815292Seric }
816