xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 68433)
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"
1050577Seric # include <pwd.h>
1156766Seric 
1233728Sbostic #ifndef lint
13*68433Seric static char sccsid[] = "@(#)alias.c	8.36 (Berkeley) 02/23/95";
1433728Sbostic #endif /* not lint */
1559673Seric 
1659673Seric 
1760537Seric MAP	*AliasDB[MAXALIASDB + 1];	/* actual database list */
1859673Seric int	NAliasDBs;			/* number of alias databases */
1959673Seric /*
20292Seric **  ALIAS -- Compute aliases.
21292Seric **
229368Seric **	Scans the alias file for an alias for the given address.
239368Seric **	If found, it arranges to deliver to the alias list instead.
249368Seric **	Uses libdbm database if -DDBM.
25292Seric **
26292Seric **	Parameters:
274097Seric **		a -- address to alias.
284999Seric **		sendq -- a pointer to the head of the send queue
294999Seric **			to put the aliases in.
3067982Seric **		aliaslevel -- the current alias nesting depth.
3158092Seric **		e -- the current envelope.
32292Seric **
33292Seric **	Returns:
34292Seric **		none
35292Seric **
36292Seric **	Side Effects:
373185Seric **		Aliases found are expanded.
38292Seric **
39292Seric **	Deficiencies:
40292Seric **		It should complain about names that are aliased to
41292Seric **			nothing.
42292Seric */
43292Seric 
44*68433Seric void
4567982Seric alias(a, sendq, aliaslevel, e)
464097Seric 	register ADDRESS *a;
474999Seric 	ADDRESS **sendq;
4867982Seric 	int aliaslevel;
4955012Seric 	register ENVELOPE *e;
50292Seric {
514081Seric 	register char *p;
5258082Seric 	int naliases;
5358170Seric 	char *owner;
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 	/*
704314Seric 	**  Look up this name
714314Seric 	*/
724314Seric 
7359673Seric 	p = aliaslookup(a->q_user, e);
744098Seric 	if (p == NULL)
754098Seric 		return;
76292Seric 
77292Seric 	/*
784098Seric 	**  Match on Alias.
794098Seric 	**	Deliver to the target list.
801515Seric 	*/
811515Seric 
827671Seric 	if (tTd(27, 1))
834098Seric 		printf("%s (%s, %s) aliased to %s\n",
844098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
8558092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
8658154Seric 	{
8758154Seric 		a->q_flags |= QVERIFIED;
8858884Seric 		e->e_nrcpts++;
8958092Seric 		return;
9058154Seric 	}
9158154Seric 	message("aliased to %s", p);
9257977Seric #ifdef LOG
9358020Seric 	if (LogLevel > 9)
9466280Seric 		syslog(LOG_INFO, "%s: alias %s => %s",
9566280Seric 			e->e_id == NULL ? "NOQUEUE" : e->e_id,
9666280Seric 			a->q_paddr, p);
9757977Seric #endif
9858082Seric 	a->q_flags &= ~QSELFREF;
9967982Seric 	if (tTd(27, 5))
10058065Seric 	{
10167982Seric 		printf("alias: QDONTSEND ");
10267982Seric 		printaddr(a, FALSE);
10358065Seric 	}
10467982Seric 	a->q_flags |= QDONTSEND;
10567982Seric 	naliases = sendtolist(p, a, sendq, aliaslevel + 1, e);
10667982Seric 	if (bitset(QSELFREF, a->q_flags))
10767982Seric 		a->q_flags &= ~QDONTSEND;
10858170Seric 
10958170Seric 	/*
11058170Seric 	**  Look for owner of alias
11158170Seric 	*/
11258170Seric 
11358170Seric 	(void) strcpy(obuf, "owner-");
11458170Seric 	if (strncmp(a->q_user, "owner-", 6) == 0)
11558170Seric 		(void) strcat(obuf, "owner");
11658170Seric 	else
11758170Seric 		(void) strcat(obuf, a->q_user);
11858170Seric 	if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
11958170Seric 		makelower(obuf);
12059673Seric 	owner = aliaslookup(obuf, e);
12166784Seric 	if (owner == NULL)
12266784Seric 		return;
12366784Seric 
12466784Seric 	/* reflect owner into envelope sender */
12566784Seric 	if (strpbrk(owner, ",:/|\"") != NULL)
12666784Seric 		owner = obuf;
12766784Seric 	a->q_owner = newstr(owner);
12866784Seric 
12966784Seric 	/* announce delivery to this alias; NORECEIPT bit set later */
13066784Seric 	if (e->e_xfp != NULL)
13166784Seric 		fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
13266784Seric 			a->q_paddr);
13368001Seric 	e->e_flags |= EF_SENDRECEIPT;
13468001Seric 	a->q_flags |= QREPORT;
1354098Seric }
1364098Seric /*
1375701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1385701Seric **
1395701Seric **	Parameters:
1405701Seric **		name -- the name to look up.
1415701Seric **
1425701Seric **	Returns:
1435701Seric **		the value of name.
1445701Seric **		NULL if unknown.
1455701Seric **
1465701Seric **	Side Effects:
1475701Seric **		none.
1485701Seric **
1495701Seric **	Warnings:
1505701Seric **		The return value will be trashed across calls.
1515701Seric */
1525701Seric 
1535701Seric char *
15459673Seric aliaslookup(name, e)
1555701Seric 	char *name;
15659673Seric 	ENVELOPE *e;
1575701Seric {
15859673Seric 	register int dbno;
15960089Seric 	register MAP *map;
16059673Seric 	register char *p;
1615701Seric 
16259673Seric 	for (dbno = 0; dbno < NAliasDBs; dbno++)
16359673Seric 	{
16460089Seric 		auto int stat;
16560089Seric 
16660537Seric 		map = AliasDB[dbno];
16760207Seric 		if (!bitset(MF_OPEN, map->map_mflags))
16859673Seric 			continue;
16960207Seric 		p = (*map->map_class->map_lookup)(map, name, NULL, &stat);
17059673Seric 		if (p != NULL)
17159673Seric 			return p;
17259673Seric 	}
17359673Seric 	return NULL;
17459673Seric }
17559673Seric /*
17659673Seric **  SETALIAS -- set up an alias map
17759673Seric **
17859673Seric **	Called when reading configuration file.
17959673Seric **
18059673Seric **	Parameters:
18159673Seric **		spec -- the alias specification
18259673Seric **
18359673Seric **	Returns:
18459673Seric **		none.
18559673Seric */
18657381Seric 
187*68433Seric void
18859673Seric setalias(spec)
18959673Seric 	char *spec;
19059673Seric {
19159673Seric 	register char *p;
19260089Seric 	register MAP *map;
19359673Seric 	char *class;
19459673Seric 	STAB *s;
19568096Seric 	static bool first_unqual = TRUE;
19659673Seric 
19759697Seric 	if (tTd(27, 8))
19859697Seric 		printf("setalias(%s)\n", spec);
19959697Seric 
20059758Seric 	for (p = spec; p != NULL; )
20151756Seric 	{
20259758Seric 		while (isspace(*p))
20359758Seric 			p++;
20460502Seric 		if (*p == '\0')
20559673Seric 			break;
20659673Seric 		spec = p;
20759673Seric 
20867848Seric 		/*
20967848Seric 		**  Treat simple filename specially -- this is the file name
21067848Seric 		**  for the files implementation, not necessarily in order.
21167848Seric 		*/
21267848Seric 
21368096Seric 		if (spec[0] == '/' && first_unqual)
21459758Seric 		{
21567848Seric 			s = stab("aliases.files", ST_MAP, ST_ENTER);
21667848Seric 			map = &s->s_map;
21768096Seric 			first_unqual = FALSE;
21859758Seric 		}
21967848Seric 		else
22067848Seric 		{
22167848Seric 			char aname[50];
22267848Seric 
22367848Seric 			if (NAliasDBs >= MAXALIASDB)
22467848Seric 			{
22567848Seric 				syserr("Too many alias databases defined, %d max",
22667848Seric 					MAXALIASDB);
22767848Seric 				return;
22867848Seric 			}
22967848Seric 			(void) sprintf(aname, "Alias%d", NAliasDBs);
23067848Seric 			s = stab(aname, ST_MAP, ST_ENTER);
23167848Seric 			map = &s->s_map;
23267848Seric 			AliasDB[NAliasDBs] = map;
23367848Seric 		}
23460089Seric 		bzero(map, sizeof *map);
23567973Seric 		map->map_mname = s->s_name;
23659758Seric 
23759758Seric 		p = strpbrk(p, " ,/:");
23859758Seric 		if (p != NULL && *p == ':')
23959758Seric 		{
24060089Seric 			/* map name */
24159758Seric 			*p++ = '\0';
24259758Seric 			class = spec;
24359758Seric 			spec = p;
24459758Seric 		}
24559758Seric 		else
24659758Seric 		{
24759758Seric 			class = "implicit";
24860228Seric 			map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
24959758Seric 		}
25059758Seric 
25159758Seric 		/* find end of spec */
25259758Seric 		if (p != NULL)
25359758Seric 			p = strchr(p, ',');
25459758Seric 		if (p != NULL)
25559758Seric 			*p++ = '\0';
25659758Seric 
25767848Seric 		if (tTd(27, 20))
25867848Seric 			printf("  map %s:%s %s\n", class, s->s_name, spec);
25967848Seric 
26059758Seric 		/* look up class */
26160089Seric 		s = stab(class, ST_MAPCLASS, ST_FIND);
26259758Seric 		if (s == NULL)
26359758Seric 		{
26459758Seric 			if (tTd(27, 1))
26559758Seric 				printf("Unknown alias class %s\n", class);
26659758Seric 		}
26760207Seric 		else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
26860207Seric 		{
26960207Seric 			syserr("setalias: map class %s can't handle aliases",
27060207Seric 				class);
27160207Seric 		}
27259758Seric 		else
27359758Seric 		{
27460207Seric 			map->map_class = &s->s_mapclass;
27560089Seric 			if (map->map_class->map_parse(map, spec))
27660089Seric 			{
27760207Seric 				map->map_mflags |= MF_VALID|MF_ALIAS;
27867848Seric 				if (AliasDB[NAliasDBs] == map)
27967848Seric 					NAliasDBs++;
28060089Seric 			}
28159758Seric 		}
28259756Seric 	}
2835701Seric }
2845701Seric /*
28559673Seric **  ALIASWAIT -- wait for distinguished @:@ token to appear.
28659673Seric **
28759673Seric **	This can decide to reopen or rebuild the alias file
28864718Seric **
28964718Seric **	Parameters:
29064718Seric **		map -- a pointer to the map descriptor for this alias file.
29164718Seric **		ext -- the filename extension (e.g., ".db") for the
29264718Seric **			database file.
29364718Seric **		isopen -- if set, the database is already open, and we
29464718Seric **			should check for validity; otherwise, we are
29564718Seric **			just checking to see if it should be created.
29664718Seric **
29764718Seric **	Returns:
29864718Seric **		TRUE -- if the database is open when we return.
29964718Seric **		FALSE -- if the database is closed when we return.
30059673Seric */
30159673Seric 
30264718Seric bool
30364718Seric aliaswait(map, ext, isopen)
30460089Seric 	MAP *map;
30560207Seric 	char *ext;
30664718Seric 	int isopen;
30759673Seric {
30864795Seric 	bool attimeout = FALSE;
30959673Seric 	time_t mtime;
31059673Seric 	struct stat stb;
31159673Seric 	char buf[MAXNAME];
31259673Seric 
31359697Seric 	if (tTd(27, 3))
31460207Seric 		printf("aliaswait(%s:%s)\n",
31560207Seric 			map->map_class->map_cname, map->map_file);
31664648Seric 	if (bitset(MF_ALIASWAIT, map->map_mflags))
31764795Seric 		return isopen;
31864648Seric 	map->map_mflags |= MF_ALIASWAIT;
31959697Seric 
32064795Seric 	if (SafeAlias > 0)
32117471Seric 	{
32260089Seric 		auto int st;
32364795Seric 		time_t toolong = curtime() + SafeAlias;
32464795Seric 		unsigned int sleeptime = 2;
32560089Seric 
32664795Seric 		while (isopen &&
32760089Seric 		       map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
32825689Seric 		{
32964795Seric 			if (curtime() > toolong)
33064795Seric 			{
33164795Seric 				/* we timed out */
33264795Seric 				attimeout = TRUE;
33364795Seric 				break;
33464795Seric 			}
33564795Seric 
33625689Seric 			/*
33759673Seric 			**  Close and re-open the alias database in case
33859673Seric 			**  the one is mv'ed instead of cp'ed in.
33925689Seric 			*/
34025689Seric 
34159697Seric 			if (tTd(27, 2))
34264795Seric 				printf("aliaswait: sleeping for %d seconds\n",
34364795Seric 					sleeptime);
34459697Seric 
34560089Seric 			map->map_class->map_close(map);
34664795Seric 			sleep(sleeptime);
34764795Seric 			sleeptime *= 2;
34864795Seric 			if (sleeptime > 60)
34964795Seric 				sleeptime = 60;
35064718Seric 			isopen = map->map_class->map_open(map, O_RDONLY);
35125689Seric 		}
35217471Seric 	}
3538437Seric 
35459673Seric 	/* see if we need to go into auto-rebuild mode */
35560207Seric 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
35660207Seric 	{
35760207Seric 		if (tTd(27, 3))
35860207Seric 			printf("aliaswait: not rebuildable\n");
35964648Seric 		map->map_mflags &= ~MF_ALIASWAIT;
36064718Seric 		return isopen;
36160207Seric 	}
36260207Seric 	if (stat(map->map_file, &stb) < 0)
36360207Seric 	{
36460207Seric 		if (tTd(27, 3))
36560207Seric 			printf("aliaswait: no source file\n");
36664648Seric 		map->map_mflags &= ~MF_ALIASWAIT;
36764718Seric 		return isopen;
36860207Seric 	}
36959673Seric 	mtime = stb.st_mtime;
37060089Seric 	(void) strcpy(buf, map->map_file);
37160207Seric 	if (ext != NULL)
37260207Seric 		(void) strcat(buf, ext);
37364795Seric 	if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
3744322Seric 	{
37559673Seric 		/* database is out of date */
37640559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3774322Seric 		{
37868101Seric 			bool oldSuprErrs;
37968101Seric 
38060089Seric 			message("auto-rebuilding alias database %s", buf);
38168101Seric 			oldSuprErrs = SuprErrs;
38268101Seric 			SuprErrs = TRUE;
38364718Seric 			if (isopen)
38464718Seric 				map->map_class->map_close(map);
38560207Seric 			rebuildaliases(map, TRUE);
38664718Seric 			isopen = map->map_class->map_open(map, O_RDONLY);
38768101Seric 			SuprErrs = oldSuprErrs;
3884322Seric 		}
3894322Seric 		else
3904322Seric 		{
39119039Seric #ifdef LOG
39258020Seric 			if (LogLevel > 3)
39359673Seric 				syslog(LOG_INFO, "alias database %s out of date",
39460089Seric 					buf);
39556795Seric #endif /* LOG */
39660089Seric 			message("Warning: alias database %s out of date", buf);
3974322Seric 		}
3984322Seric 	}
39964648Seric 	map->map_mflags &= ~MF_ALIASWAIT;
40064718Seric 	return isopen;
40159673Seric }
40259673Seric /*
40359673Seric **  REBUILDALIASES -- rebuild the alias database.
40459673Seric **
40559673Seric **	Parameters:
40660089Seric **		map -- the database to rebuild.
40759673Seric **		automatic -- set if this was automatically generated.
40859673Seric **
40959673Seric **	Returns:
41059673Seric **		none.
41159673Seric **
41259673Seric **	Side Effects:
41359673Seric **		Reads the text version of the database, builds the
41459673Seric **		DBM or DB version.
41559673Seric */
4164322Seric 
417*68433Seric void
41860207Seric rebuildaliases(map, automatic)
41960089Seric 	register MAP *map;
42059673Seric 	bool automatic;
42159673Seric {
42259673Seric 	FILE *af;
42364388Seric 	bool nolock = FALSE;
42467430Seric 	sigfunc_t oldsigint, oldsigquit;
42567430Seric #ifdef SIGTSTP
42667430Seric 	sigfunc_t oldsigtstp;
42767430Seric #endif
4284322Seric 
42960207Seric 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
43059673Seric 		return;
4314322Seric 
43259673Seric 	/* try to lock the source file */
43360089Seric 	if ((af = fopen(map->map_file, "r+")) == NULL)
43459673Seric 	{
43565953Seric 		if ((errno != EACCES && errno != EROFS) || automatic ||
43664388Seric 		    (af = fopen(map->map_file, "r")) == NULL)
43764388Seric 		{
43864388Seric 			int saveerr = errno;
43964382Seric 
44064388Seric 			if (tTd(27, 1))
44164388Seric 				printf("Can't open %s: %s\n",
44264388Seric 					map->map_file, errstring(saveerr));
44364388Seric 			if (!automatic)
44464388Seric 				message("newaliases: cannot open %s: %s",
44564388Seric 					map->map_file, errstring(saveerr));
44664388Seric 			errno = 0;
44764388Seric 			return;
44864388Seric 		}
44964388Seric 		nolock = TRUE;
45064388Seric 		message("warning: cannot lock %s: %s",
45164388Seric 			map->map_file, errstring(errno));
4528437Seric 	}
45359673Seric 
45459673Seric 	/* see if someone else is rebuilding the alias file */
45564388Seric 	if (!nolock &&
45664388Seric 	    !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
45759673Seric 	{
45859673Seric 		/* yes, they are -- wait until done */
45959673Seric 		message("Alias file %s is already being rebuilt",
46060089Seric 			map->map_file);
46159673Seric 		if (OpMode != MD_INITALIAS)
46259673Seric 		{
46359673Seric 			/* wait for other rebuild to complete */
46464335Seric 			(void) lockfile(fileno(af), map->map_file, NULL,
46559673Seric 					LOCK_EX);
46659673Seric 		}
46764772Seric 		(void) xfclose(af, "rebuildaliases1", map->map_file);
46859673Seric 		errno = 0;
46959673Seric 		return;
47059673Seric 	}
47159673Seric 
47267430Seric 	/* avoid denial-of-service attacks */
47367430Seric 	resetlimits();
47464035Seric 	oldsigint = setsignal(SIGINT, SIG_IGN);
47567430Seric 	oldsigquit = setsignal(SIGQUIT, SIG_IGN);
47667430Seric #ifdef SIGTSTP
47767430Seric 	oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
47867430Seric #endif
47959673Seric 
48060207Seric 	if (map->map_class->map_open(map, O_RDWR))
48160089Seric 	{
48264382Seric #ifdef LOG
48364382Seric 		if (LogLevel > 7)
48464382Seric 		{
48564382Seric 			syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
48664382Seric 				map->map_file, automatic ? "auto" : "",
48764382Seric 				username());
48864382Seric 		}
48964382Seric #endif /* LOG */
49060207Seric 		map->map_mflags |= MF_OPEN|MF_WRITABLE;
49167263Seric 		readaliases(map, af, !automatic, TRUE);
49260089Seric 	}
49360207Seric 	else
49460207Seric 	{
49560207Seric 		if (tTd(27, 1))
49660207Seric 			printf("Can't create database for %s: %s\n",
49760207Seric 				map->map_file, errstring(errno));
49860207Seric 		if (!automatic)
49960207Seric 			syserr("Cannot create database for alias file %s",
50060207Seric 				map->map_file);
50160207Seric 	}
50259673Seric 
50359673Seric 	/* close the file, thus releasing locks */
50464772Seric 	xfclose(af, "rebuildaliases2", map->map_file);
50559673Seric 
50659673Seric 	/* add distinguished entries and close the database */
50760207Seric 	if (bitset(MF_OPEN, map->map_mflags))
50860089Seric 		map->map_class->map_close(map);
50959673Seric 
51067430Seric 	/* restore the old signals */
51164035Seric 	(void) setsignal(SIGINT, oldsigint);
51267430Seric 	(void) setsignal(SIGQUIT, oldsigquit);
51367430Seric #ifdef SIGTSTP
51467430Seric 	(void) setsignal(SIGTSTP, oldsigtstp);
51567430Seric #endif
5164157Seric }
5174157Seric /*
5184157Seric **  READALIASES -- read and process the alias file.
5194157Seric **
5204157Seric **	This routine implements the part of initaliases that occurs
5214157Seric **	when we are not going to use the DBM stuff.
5224157Seric **
5234157Seric **	Parameters:
52460089Seric **		map -- the alias database descriptor.
52559673Seric **		af -- file to read the aliases from.
52667263Seric **		announcestats -- anounce statistics regarding number of
52767263Seric **			aliases, longest alias, etc.
52867263Seric **		logstats -- lot the same info.
5294157Seric **
5304157Seric **	Returns:
5314157Seric **		none.
5324157Seric **
5334157Seric **	Side Effects:
5344157Seric **		Reads aliasfile into the symbol table.
5354157Seric **		Optionally, builds the .dir & .pag files.
5364157Seric */
5374157Seric 
538*68433Seric void
53967263Seric readaliases(map, af, announcestats, logstats)
54060089Seric 	register MAP *map;
54159673Seric 	FILE *af;
54267263Seric 	bool announcestats;
54367263Seric 	bool logstats;
5444157Seric {
5454098Seric 	register char *p;
5464098Seric 	char *rhs;
5474098Seric 	bool skipping;
54859673Seric 	long naliases, bytes, longest;
5494098Seric 	ADDRESS al, bl;
5509368Seric 	char line[BUFSIZ];
5514098Seric 
5524314Seric 	/*
5534314Seric 	**  Read and interpret lines
5544314Seric 	*/
5554314Seric 
55660089Seric 	FileName = map->map_file;
5579368Seric 	LineNumber = 0;
5584322Seric 	naliases = bytes = longest = 0;
5594098Seric 	skipping = FALSE;
5604098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5614098Seric 	{
5624322Seric 		int lhssize, rhssize;
5634322Seric 
5649368Seric 		LineNumber++;
56556795Seric 		p = strchr(line, '\n');
56625278Seric 		if (p != NULL)
56725278Seric 			*p = '\0';
5684098Seric 		switch (line[0])
5694098Seric 		{
5704098Seric 		  case '#':
5714098Seric 		  case '\0':
5724098Seric 			skipping = FALSE;
5734098Seric 			continue;
5744065Seric 
5754098Seric 		  case ' ':
5764098Seric 		  case '\t':
5774098Seric 			if (!skipping)
57858151Seric 				syserr("554 Non-continuation line starts with space");
5794098Seric 			skipping = TRUE;
5804097Seric 			continue;
5814098Seric 		}
5824098Seric 		skipping = FALSE;
5831874Seric 
5844314Seric 		/*
5854314Seric 		**  Process the LHS
58657736Seric 		**	Find the colon separator, and parse the address.
58716898Seric 		**	It should resolve to a local name -- this will
58816898Seric 		**	be checked later (we want to optionally do
58916898Seric 		**	parsing of the RHS first to maximize error
59016898Seric 		**	detection).
5914314Seric 		*/
5924314Seric 
5934098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5944097Seric 			continue;
59516898Seric 		if (*p++ != ':')
5964098Seric 		{
59758151Seric 			syserr("554 missing colon");
5984097Seric 			continue;
5994098Seric 		}
60064284Seric 		if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
6014098Seric 		{
60264838Seric 			syserr("554 %.40s... illegal alias name", line);
60316898Seric 			continue;
6044098Seric 		}
6054314Seric 
6064314Seric 		/*
6074314Seric 		**  Process the RHS.
6084314Seric 		**	'al' is the internal form of the LHS address.
6094314Seric 		**	'p' points to the text of the RHS.
6104314Seric 		*/
6114314Seric 
61258914Seric 		while (isascii(*p) && isspace(*p))
61358914Seric 			p++;
6144098Seric 		rhs = p;
6154098Seric 		for (;;)
6164098Seric 		{
6174098Seric 			register char c;
61858662Seric 			register char *nlp;
6191515Seric 
62058662Seric 			nlp = &p[strlen(p)];
62158662Seric 			if (nlp[-1] == '\n')
62258662Seric 				*--nlp = '\0';
62358662Seric 
62459673Seric 			if (CheckAliases)
6254098Seric 			{
6264157Seric 				/* do parsing & compression of addresses */
62725278Seric 				while (*p != '\0')
6284098Seric 				{
62958333Seric 					auto char *delimptr;
63025278Seric 
63158050Seric 					while ((isascii(*p) && isspace(*p)) ||
63258050Seric 								*p == ',')
6334157Seric 						p++;
63425278Seric 					if (*p == '\0')
63525278Seric 						break;
63664284Seric 					if (parseaddr(p, &bl, RF_COPYNONE, ',',
63764284Seric 						      &delimptr, CurEnv) == NULL)
63858151Seric 						usrerr("553 %s... bad address", p);
63958333Seric 					p = delimptr;
6404098Seric 				}
6414098Seric 			}
6424157Seric 			else
64315769Seric 			{
64458662Seric 				p = nlp;
64515769Seric 			}
6461515Seric 
6474098Seric 			/* see if there should be a continuation line */
6484106Seric 			c = fgetc(af);
6494106Seric 			if (!feof(af))
6504314Seric 				(void) ungetc(c, af);
6514106Seric 			if (c != ' ' && c != '\t')
6524098Seric 				break;
6534098Seric 
6544098Seric 			/* read continuation line */
6554098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6564098Seric 				break;
6579368Seric 			LineNumber++;
65857135Seric 
65957135Seric 			/* check for line overflow */
66057135Seric 			if (strchr(p, '\n') == NULL)
66157135Seric 			{
66258151Seric 				usrerr("554 alias too long");
66357135Seric 				break;
66457135Seric 			}
6654098Seric 		}
66667473Seric 		if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
66716898Seric 		{
66864278Seric 			syserr("554 %s... cannot alias non-local names",
66964278Seric 				al.q_paddr);
67016898Seric 			continue;
67116898Seric 		}
6724314Seric 
6734314Seric 		/*
6744314Seric 		**  Insert alias into symbol table or DBM file
6754314Seric 		*/
6764314Seric 
67757381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
67857381Seric 			makelower(al.q_user);
6794322Seric 
68059673Seric 		lhssize = strlen(al.q_user);
68159673Seric 		rhssize = strlen(rhs);
68260089Seric 		map->map_class->map_store(map, al.q_user, rhs);
6834157Seric 
68459673Seric 		if (al.q_paddr != NULL)
68559673Seric 			free(al.q_paddr);
68659673Seric 		if (al.q_host != NULL)
68759673Seric 			free(al.q_host);
68859673Seric 		if (al.q_user != NULL)
68959673Seric 			free(al.q_user);
6904322Seric 
6914322Seric 		/* statistics */
6924322Seric 		naliases++;
6934322Seric 		bytes += lhssize + rhssize;
6944322Seric 		if (rhssize > longest)
6954322Seric 			longest = rhssize;
6961515Seric 	}
69719784Seric 
69860207Seric 	CurEnv->e_to = NULL;
69959673Seric 	FileName = NULL;
70067263Seric 	if (Verbose || announcestats)
70159733Seric 		message("%s: %d aliases, longest %d bytes, %d bytes total",
70260089Seric 			map->map_file, naliases, longest, bytes);
70359673Seric # ifdef LOG
70467263Seric 	if (LogLevel > 7 && logstats)
70559673Seric 		syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
70660089Seric 			map->map_file, naliases, longest, bytes);
70759673Seric # endif /* LOG */
70859673Seric }
70959673Seric /*
710292Seric **  FORWARD -- Try to forward mail
711292Seric **
712292Seric **	This is similar but not identical to aliasing.
713292Seric **
714292Seric **	Parameters:
7154314Seric **		user -- the name of the user who's mail we would like
7164314Seric **			to forward to.  It must have been verified --
7174314Seric **			i.e., the q_home field must have been filled
7184314Seric **			in.
7194999Seric **		sendq -- a pointer to the head of the send queue to
7204999Seric **			put this user's aliases in.
72167982Seric **		aliaslevel -- the current alias nesting depth.
72267982Seric **		e -- the current envelope.
723292Seric **
724292Seric **	Returns:
7254098Seric **		none.
726292Seric **
727292Seric **	Side Effects:
7283185Seric **		New names are added to send queues.
729292Seric */
730292Seric 
731*68433Seric void
73267982Seric forward(user, sendq, aliaslevel, e)
7332966Seric 	ADDRESS *user;
7344999Seric 	ADDRESS **sendq;
73567982Seric 	int aliaslevel;
73655012Seric 	register ENVELOPE *e;
737292Seric {
73857136Seric 	char *pp;
73957136Seric 	char *ep;
7404069Seric 
7417671Seric 	if (tTd(27, 1))
7424098Seric 		printf("forward(%s)\n", user->q_paddr);
7434098Seric 
74467473Seric 	if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
74567473Seric 	    bitset(QBADADDR, user->q_flags))
7464098Seric 		return;
7474314Seric 	if (user->q_home == NULL)
74858059Seric 	{
74958151Seric 		syserr("554 forward: no home");
75058059Seric 		user->q_home = "/nosuchdirectory";
75158059Seric 	}
7524069Seric 
7534069Seric 	/* good address -- look for .forward file in home */
75455012Seric 	define('z', user->q_home, e);
75557136Seric 	define('u', user->q_user, e);
75657136Seric 	define('h', user->q_host, e);
75757136Seric 	if (ForwardPath == NULL)
75858050Seric 		ForwardPath = newstr("\201z/.forward");
75957136Seric 
76057136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
76157136Seric 	{
76258247Seric 		int err;
76357232Seric 		char buf[MAXPATHLEN+1];
764*68433Seric 		extern int include();
76557136Seric 
76657136Seric 		ep = strchr(pp, ':');
76757136Seric 		if (ep != NULL)
76857136Seric 			*ep = '\0';
76957136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
77057136Seric 		if (ep != NULL)
77157136Seric 			*ep++ = ':';
77257136Seric 		if (tTd(27, 3))
77357136Seric 			printf("forward: trying %s\n", buf);
77463753Seric 
77567982Seric 		err = include(buf, TRUE, user, sendq, aliaslevel, e);
77658247Seric 		if (err == 0)
77757136Seric 			break;
77864325Seric 		else if (transienterror(err))
77958247Seric 		{
78058247Seric 			/* we have to suspend this message */
78159563Seric 			if (tTd(27, 2))
78259563Seric 				printf("forward: transient error on %s\n", buf);
78359563Seric #ifdef LOG
78459563Seric 			if (LogLevel > 2)
78559624Seric 				syslog(LOG_ERR, "%s: forward %s: transient error: %s",
78666284Seric 					e->e_id == NULL ? "NOQUEUE" : e->e_id,
78766284Seric 					buf, errstring(err));
78859563Seric #endif
78959611Seric 			message("%s: %s: message queued", buf, errstring(err));
79063853Seric 			user->q_flags |= QQUEUEUP;
79158247Seric 			return;
79258247Seric 		}
79357136Seric 	}
794292Seric }
795