xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 67473)
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*67473Seric static char sccsid[] = "@(#)alias.c	8.29 (Berkeley) 07/03/94";
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.
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 
4355012Seric alias(a, sendq, e)
444097Seric 	register ADDRESS *a;
454999Seric 	ADDRESS **sendq;
4655012Seric 	register ENVELOPE *e;
47292Seric {
484081Seric 	register char *p;
4958082Seric 	int naliases;
5058170Seric 	char *owner;
5158170Seric 	char obuf[MAXNAME + 6];
525701Seric 	extern char *aliaslookup();
53292Seric 
547671Seric 	if (tTd(27, 1))
5567426Seric 		printf("alias(%s)\n", a->q_user);
56292Seric 
574098Seric 	/* don't realias already aliased names */
5858680Seric 	if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
594098Seric 		return;
604098Seric 
6159673Seric 	if (NoAlias)
6259673Seric 		return;
6359673Seric 
6455012Seric 	e->e_to = a->q_paddr;
654098Seric 
664314Seric 	/*
674314Seric 	**  Look up this name
684314Seric 	*/
694314Seric 
7059673Seric 	p = aliaslookup(a->q_user, e);
714098Seric 	if (p == NULL)
724098Seric 		return;
73292Seric 
74292Seric 	/*
754098Seric 	**  Match on Alias.
764098Seric 	**	Deliver to the target list.
771515Seric 	*/
781515Seric 
797671Seric 	if (tTd(27, 1))
804098Seric 		printf("%s (%s, %s) aliased to %s\n",
814098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
8258092Seric 	if (bitset(EF_VRFYONLY, e->e_flags))
8358154Seric 	{
8458154Seric 		a->q_flags |= QVERIFIED;
8558884Seric 		e->e_nrcpts++;
8658092Seric 		return;
8758154Seric 	}
8858154Seric 	message("aliased to %s", p);
8957977Seric #ifdef LOG
9058020Seric 	if (LogLevel > 9)
9166280Seric 		syslog(LOG_INFO, "%s: alias %s => %s",
9266280Seric 			e->e_id == NULL ? "NOQUEUE" : e->e_id,
9366280Seric 			a->q_paddr, p);
9457977Seric #endif
9558082Seric 	a->q_flags &= ~QSELFREF;
964098Seric 	AliasLevel++;
9758082Seric 	naliases = sendtolist(p, a, sendq, e);
984098Seric 	AliasLevel--;
9964301Seric 	if (!bitset(QSELFREF, a->q_flags))
10058065Seric 	{
10158065Seric 		if (tTd(27, 5))
10258065Seric 		{
10358065Seric 			printf("alias: QDONTSEND ");
10458065Seric 			printaddr(a, FALSE);
10558065Seric 		}
10658065Seric 		a->q_flags |= QDONTSEND;
10758065Seric 	}
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)
13158170Seric 	{
13266784Seric 		fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
13366784Seric 			a->q_paddr);
13466784Seric 		e->e_flags |= EF_SENDRECEIPT;
13558170Seric 	}
1364098Seric }
1374098Seric /*
1385701Seric **  ALIASLOOKUP -- look up a name in the alias file.
1395701Seric **
1405701Seric **	Parameters:
1415701Seric **		name -- the name to look up.
1425701Seric **
1435701Seric **	Returns:
1445701Seric **		the value of name.
1455701Seric **		NULL if unknown.
1465701Seric **
1475701Seric **	Side Effects:
1485701Seric **		none.
1495701Seric **
1505701Seric **	Warnings:
1515701Seric **		The return value will be trashed across calls.
1525701Seric */
1535701Seric 
1545701Seric char *
15559673Seric aliaslookup(name, e)
1565701Seric 	char *name;
15759673Seric 	ENVELOPE *e;
1585701Seric {
15959673Seric 	register int dbno;
16060089Seric 	register MAP *map;
16159673Seric 	register char *p;
1625701Seric 
16359673Seric 	for (dbno = 0; dbno < NAliasDBs; dbno++)
16459673Seric 	{
16560089Seric 		auto int stat;
16660089Seric 
16760537Seric 		map = AliasDB[dbno];
16860207Seric 		if (!bitset(MF_OPEN, map->map_mflags))
16959673Seric 			continue;
17060207Seric 		p = (*map->map_class->map_lookup)(map, name, NULL, &stat);
17159673Seric 		if (p != NULL)
17259673Seric 			return p;
17359673Seric 	}
17459673Seric 	return NULL;
17559673Seric }
17659673Seric /*
17759673Seric **  SETALIAS -- set up an alias map
17859673Seric **
17959673Seric **	Called when reading configuration file.
18059673Seric **
18159673Seric **	Parameters:
18259673Seric **		spec -- the alias specification
18359673Seric **
18459673Seric **	Returns:
18559673Seric **		none.
18659673Seric */
18757381Seric 
18859673Seric setalias(spec)
18959673Seric 	char *spec;
19059673Seric {
19159673Seric 	register char *p;
19260089Seric 	register MAP *map;
19359673Seric 	char *class;
19459673Seric 	STAB *s;
19559673Seric 
19659697Seric 	if (tTd(27, 8))
19759697Seric 		printf("setalias(%s)\n", spec);
19859697Seric 
19959758Seric 	for (p = spec; p != NULL; )
20051756Seric 	{
20160537Seric 		char aname[50];
20260537Seric 
20359758Seric 		while (isspace(*p))
20459758Seric 			p++;
20560502Seric 		if (*p == '\0')
20659673Seric 			break;
20759673Seric 		spec = p;
20859673Seric 
20959758Seric 		if (NAliasDBs >= MAXALIASDB)
21059758Seric 		{
21159758Seric 			syserr("Too many alias databases defined, %d max", MAXALIASDB);
21259758Seric 			return;
21359758Seric 		}
21460537Seric 		(void) sprintf(aname, "Alias%d", NAliasDBs);
21560537Seric 		s = stab(aname, ST_MAP, ST_ENTER);
21660537Seric 		map = &s->s_map;
21760537Seric 		AliasDB[NAliasDBs] = map;
21860089Seric 		bzero(map, sizeof *map);
21959758Seric 
22059758Seric 		p = strpbrk(p, " ,/:");
22159758Seric 		if (p != NULL && *p == ':')
22259758Seric 		{
22360089Seric 			/* map name */
22459758Seric 			*p++ = '\0';
22559758Seric 			class = spec;
22659758Seric 			spec = p;
22759758Seric 		}
22859758Seric 		else
22959758Seric 		{
23059758Seric 			class = "implicit";
23160228Seric 			map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
23259758Seric 		}
23359758Seric 
23459758Seric 		/* find end of spec */
23559758Seric 		if (p != NULL)
23659758Seric 			p = strchr(p, ',');
23759758Seric 		if (p != NULL)
23859758Seric 			*p++ = '\0';
23959758Seric 
24059758Seric 		/* look up class */
24160089Seric 		s = stab(class, ST_MAPCLASS, ST_FIND);
24259758Seric 		if (s == NULL)
24359758Seric 		{
24459758Seric 			if (tTd(27, 1))
24559758Seric 				printf("Unknown alias class %s\n", class);
24659758Seric 		}
24760207Seric 		else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
24860207Seric 		{
24960207Seric 			syserr("setalias: map class %s can't handle aliases",
25060207Seric 				class);
25160207Seric 		}
25259758Seric 		else
25359758Seric 		{
25460207Seric 			map->map_class = &s->s_mapclass;
25560089Seric 			if (map->map_class->map_parse(map, spec))
25660089Seric 			{
25760207Seric 				map->map_mflags |= MF_VALID|MF_ALIAS;
25860089Seric 				NAliasDBs++;
25960089Seric 			}
26059758Seric 		}
26159756Seric 	}
2625701Seric }
2635701Seric /*
26459673Seric **  ALIASWAIT -- wait for distinguished @:@ token to appear.
26559673Seric **
26659673Seric **	This can decide to reopen or rebuild the alias file
26764718Seric **
26864718Seric **	Parameters:
26964718Seric **		map -- a pointer to the map descriptor for this alias file.
27064718Seric **		ext -- the filename extension (e.g., ".db") for the
27164718Seric **			database file.
27264718Seric **		isopen -- if set, the database is already open, and we
27364718Seric **			should check for validity; otherwise, we are
27464718Seric **			just checking to see if it should be created.
27564718Seric **
27664718Seric **	Returns:
27764718Seric **		TRUE -- if the database is open when we return.
27864718Seric **		FALSE -- if the database is closed when we return.
27959673Seric */
28059673Seric 
28164718Seric bool
28264718Seric aliaswait(map, ext, isopen)
28360089Seric 	MAP *map;
28460207Seric 	char *ext;
28564718Seric 	int isopen;
28659673Seric {
28764795Seric 	bool attimeout = FALSE;
28859673Seric 	time_t mtime;
28959673Seric 	struct stat stb;
29059673Seric 	char buf[MAXNAME];
29159673Seric 
29259697Seric 	if (tTd(27, 3))
29360207Seric 		printf("aliaswait(%s:%s)\n",
29460207Seric 			map->map_class->map_cname, map->map_file);
29564648Seric 	if (bitset(MF_ALIASWAIT, map->map_mflags))
29664795Seric 		return isopen;
29764648Seric 	map->map_mflags |= MF_ALIASWAIT;
29859697Seric 
29964795Seric 	if (SafeAlias > 0)
30017471Seric 	{
30160089Seric 		auto int st;
30264795Seric 		time_t toolong = curtime() + SafeAlias;
30364795Seric 		unsigned int sleeptime = 2;
30460089Seric 
30564795Seric 		while (isopen &&
30660089Seric 		       map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
30725689Seric 		{
30864795Seric 			if (curtime() > toolong)
30964795Seric 			{
31064795Seric 				/* we timed out */
31164795Seric 				attimeout = TRUE;
31264795Seric 				break;
31364795Seric 			}
31464795Seric 
31525689Seric 			/*
31659673Seric 			**  Close and re-open the alias database in case
31759673Seric 			**  the one is mv'ed instead of cp'ed in.
31825689Seric 			*/
31925689Seric 
32059697Seric 			if (tTd(27, 2))
32164795Seric 				printf("aliaswait: sleeping for %d seconds\n",
32264795Seric 					sleeptime);
32359697Seric 
32460089Seric 			map->map_class->map_close(map);
32564795Seric 			sleep(sleeptime);
32664795Seric 			sleeptime *= 2;
32764795Seric 			if (sleeptime > 60)
32864795Seric 				sleeptime = 60;
32964718Seric 			isopen = map->map_class->map_open(map, O_RDONLY);
33025689Seric 		}
33117471Seric 	}
3328437Seric 
33359673Seric 	/* see if we need to go into auto-rebuild mode */
33460207Seric 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
33560207Seric 	{
33660207Seric 		if (tTd(27, 3))
33760207Seric 			printf("aliaswait: not rebuildable\n");
33864648Seric 		map->map_mflags &= ~MF_ALIASWAIT;
33964718Seric 		return isopen;
34060207Seric 	}
34160207Seric 	if (stat(map->map_file, &stb) < 0)
34260207Seric 	{
34360207Seric 		if (tTd(27, 3))
34460207Seric 			printf("aliaswait: no source file\n");
34564648Seric 		map->map_mflags &= ~MF_ALIASWAIT;
34664718Seric 		return isopen;
34760207Seric 	}
34859673Seric 	mtime = stb.st_mtime;
34960089Seric 	(void) strcpy(buf, map->map_file);
35060207Seric 	if (ext != NULL)
35160207Seric 		(void) strcat(buf, ext);
35264795Seric 	if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
3534322Seric 	{
35459673Seric 		/* database is out of date */
35540559Sbostic 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3564322Seric 		{
35760089Seric 			message("auto-rebuilding alias database %s", buf);
35864718Seric 			if (isopen)
35964718Seric 				map->map_class->map_close(map);
36060207Seric 			rebuildaliases(map, TRUE);
36164718Seric 			isopen = map->map_class->map_open(map, O_RDONLY);
3624322Seric 		}
3634322Seric 		else
3644322Seric 		{
36519039Seric #ifdef LOG
36658020Seric 			if (LogLevel > 3)
36759673Seric 				syslog(LOG_INFO, "alias database %s out of date",
36860089Seric 					buf);
36956795Seric #endif /* LOG */
37060089Seric 			message("Warning: alias database %s out of date", buf);
3714322Seric 		}
3724322Seric 	}
37364648Seric 	map->map_mflags &= ~MF_ALIASWAIT;
37464718Seric 	return isopen;
37559673Seric }
37659673Seric /*
37759673Seric **  REBUILDALIASES -- rebuild the alias database.
37859673Seric **
37959673Seric **	Parameters:
38060089Seric **		map -- the database to rebuild.
38159673Seric **		automatic -- set if this was automatically generated.
38259673Seric **
38359673Seric **	Returns:
38459673Seric **		none.
38559673Seric **
38659673Seric **	Side Effects:
38759673Seric **		Reads the text version of the database, builds the
38859673Seric **		DBM or DB version.
38959673Seric */
3904322Seric 
39160207Seric rebuildaliases(map, automatic)
39260089Seric 	register MAP *map;
39359673Seric 	bool automatic;
39459673Seric {
39559673Seric 	FILE *af;
39664388Seric 	bool nolock = FALSE;
39767430Seric 	sigfunc_t oldsigint, oldsigquit;
39867430Seric #ifdef SIGTSTP
39967430Seric 	sigfunc_t oldsigtstp;
40067430Seric #endif
4014322Seric 
40260207Seric 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
40359673Seric 		return;
4044322Seric 
40559673Seric 	/* try to lock the source file */
40660089Seric 	if ((af = fopen(map->map_file, "r+")) == NULL)
40759673Seric 	{
40865953Seric 		if ((errno != EACCES && errno != EROFS) || automatic ||
40964388Seric 		    (af = fopen(map->map_file, "r")) == NULL)
41064388Seric 		{
41164388Seric 			int saveerr = errno;
41264382Seric 
41364388Seric 			if (tTd(27, 1))
41464388Seric 				printf("Can't open %s: %s\n",
41564388Seric 					map->map_file, errstring(saveerr));
41664388Seric 			if (!automatic)
41764388Seric 				message("newaliases: cannot open %s: %s",
41864388Seric 					map->map_file, errstring(saveerr));
41964388Seric 			errno = 0;
42064388Seric 			return;
42164388Seric 		}
42264388Seric 		nolock = TRUE;
42364388Seric 		message("warning: cannot lock %s: %s",
42464388Seric 			map->map_file, errstring(errno));
4258437Seric 	}
42659673Seric 
42759673Seric 	/* see if someone else is rebuilding the alias file */
42864388Seric 	if (!nolock &&
42964388Seric 	    !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
43059673Seric 	{
43159673Seric 		/* yes, they are -- wait until done */
43259673Seric 		message("Alias file %s is already being rebuilt",
43360089Seric 			map->map_file);
43459673Seric 		if (OpMode != MD_INITALIAS)
43559673Seric 		{
43659673Seric 			/* wait for other rebuild to complete */
43764335Seric 			(void) lockfile(fileno(af), map->map_file, NULL,
43859673Seric 					LOCK_EX);
43959673Seric 		}
44064772Seric 		(void) xfclose(af, "rebuildaliases1", map->map_file);
44159673Seric 		errno = 0;
44259673Seric 		return;
44359673Seric 	}
44459673Seric 
44567430Seric 	/* avoid denial-of-service attacks */
44667430Seric 	resetlimits();
44764035Seric 	oldsigint = setsignal(SIGINT, SIG_IGN);
44867430Seric 	oldsigquit = setsignal(SIGQUIT, SIG_IGN);
44967430Seric #ifdef SIGTSTP
45067430Seric 	oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
45167430Seric #endif
45259673Seric 
45360207Seric 	if (map->map_class->map_open(map, O_RDWR))
45460089Seric 	{
45564382Seric #ifdef LOG
45664382Seric 		if (LogLevel > 7)
45764382Seric 		{
45864382Seric 			syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
45964382Seric 				map->map_file, automatic ? "auto" : "",
46064382Seric 				username());
46164382Seric 		}
46264382Seric #endif /* LOG */
46360207Seric 		map->map_mflags |= MF_OPEN|MF_WRITABLE;
46467263Seric 		readaliases(map, af, !automatic, TRUE);
46560089Seric 	}
46660207Seric 	else
46760207Seric 	{
46860207Seric 		if (tTd(27, 1))
46960207Seric 			printf("Can't create database for %s: %s\n",
47060207Seric 				map->map_file, errstring(errno));
47160207Seric 		if (!automatic)
47260207Seric 			syserr("Cannot create database for alias file %s",
47360207Seric 				map->map_file);
47460207Seric 	}
47559673Seric 
47659673Seric 	/* close the file, thus releasing locks */
47764772Seric 	xfclose(af, "rebuildaliases2", map->map_file);
47859673Seric 
47959673Seric 	/* add distinguished entries and close the database */
48060207Seric 	if (bitset(MF_OPEN, map->map_mflags))
48160089Seric 		map->map_class->map_close(map);
48259673Seric 
48367430Seric 	/* restore the old signals */
48464035Seric 	(void) setsignal(SIGINT, oldsigint);
48567430Seric 	(void) setsignal(SIGQUIT, oldsigquit);
48667430Seric #ifdef SIGTSTP
48767430Seric 	(void) setsignal(SIGTSTP, oldsigtstp);
48867430Seric #endif
4894157Seric }
4904157Seric /*
4914157Seric **  READALIASES -- read and process the alias file.
4924157Seric **
4934157Seric **	This routine implements the part of initaliases that occurs
4944157Seric **	when we are not going to use the DBM stuff.
4954157Seric **
4964157Seric **	Parameters:
49760089Seric **		map -- the alias database descriptor.
49859673Seric **		af -- file to read the aliases from.
49967263Seric **		announcestats -- anounce statistics regarding number of
50067263Seric **			aliases, longest alias, etc.
50167263Seric **		logstats -- lot the same info.
5024157Seric **
5034157Seric **	Returns:
5044157Seric **		none.
5054157Seric **
5064157Seric **	Side Effects:
5074157Seric **		Reads aliasfile into the symbol table.
5084157Seric **		Optionally, builds the .dir & .pag files.
5094157Seric */
5104157Seric 
51167263Seric readaliases(map, af, announcestats, logstats)
51260089Seric 	register MAP *map;
51359673Seric 	FILE *af;
51467263Seric 	bool announcestats;
51567263Seric 	bool logstats;
5164157Seric {
5174098Seric 	register char *p;
5184098Seric 	char *rhs;
5194098Seric 	bool skipping;
52059673Seric 	long naliases, bytes, longest;
5214098Seric 	ADDRESS al, bl;
5229368Seric 	char line[BUFSIZ];
5234098Seric 
5244314Seric 	/*
5254314Seric 	**  Read and interpret lines
5264314Seric 	*/
5274314Seric 
52860089Seric 	FileName = map->map_file;
5299368Seric 	LineNumber = 0;
5304322Seric 	naliases = bytes = longest = 0;
5314098Seric 	skipping = FALSE;
5324098Seric 	while (fgets(line, sizeof (line), af) != NULL)
5334098Seric 	{
5344322Seric 		int lhssize, rhssize;
5354322Seric 
5369368Seric 		LineNumber++;
53756795Seric 		p = strchr(line, '\n');
53825278Seric 		if (p != NULL)
53925278Seric 			*p = '\0';
5404098Seric 		switch (line[0])
5414098Seric 		{
5424098Seric 		  case '#':
5434098Seric 		  case '\0':
5444098Seric 			skipping = FALSE;
5454098Seric 			continue;
5464065Seric 
5474098Seric 		  case ' ':
5484098Seric 		  case '\t':
5494098Seric 			if (!skipping)
55058151Seric 				syserr("554 Non-continuation line starts with space");
5514098Seric 			skipping = TRUE;
5524097Seric 			continue;
5534098Seric 		}
5544098Seric 		skipping = FALSE;
5551874Seric 
5564314Seric 		/*
5574314Seric 		**  Process the LHS
55857736Seric 		**	Find the colon separator, and parse the address.
55916898Seric 		**	It should resolve to a local name -- this will
56016898Seric 		**	be checked later (we want to optionally do
56116898Seric 		**	parsing of the RHS first to maximize error
56216898Seric 		**	detection).
5634314Seric 		*/
5644314Seric 
5654098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
5664097Seric 			continue;
56716898Seric 		if (*p++ != ':')
5684098Seric 		{
56958151Seric 			syserr("554 missing colon");
5704097Seric 			continue;
5714098Seric 		}
57264284Seric 		if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
5734098Seric 		{
57464838Seric 			syserr("554 %.40s... illegal alias name", line);
57516898Seric 			continue;
5764098Seric 		}
5774314Seric 
5784314Seric 		/*
5794314Seric 		**  Process the RHS.
5804314Seric 		**	'al' is the internal form of the LHS address.
5814314Seric 		**	'p' points to the text of the RHS.
5824314Seric 		*/
5834314Seric 
58458914Seric 		while (isascii(*p) && isspace(*p))
58558914Seric 			p++;
5864098Seric 		rhs = p;
5874098Seric 		for (;;)
5884098Seric 		{
5894098Seric 			register char c;
59058662Seric 			register char *nlp;
5911515Seric 
59258662Seric 			nlp = &p[strlen(p)];
59358662Seric 			if (nlp[-1] == '\n')
59458662Seric 				*--nlp = '\0';
59558662Seric 
59659673Seric 			if (CheckAliases)
5974098Seric 			{
5984157Seric 				/* do parsing & compression of addresses */
59925278Seric 				while (*p != '\0')
6004098Seric 				{
60158333Seric 					auto char *delimptr;
60225278Seric 
60358050Seric 					while ((isascii(*p) && isspace(*p)) ||
60458050Seric 								*p == ',')
6054157Seric 						p++;
60625278Seric 					if (*p == '\0')
60725278Seric 						break;
60864284Seric 					if (parseaddr(p, &bl, RF_COPYNONE, ',',
60964284Seric 						      &delimptr, CurEnv) == NULL)
61058151Seric 						usrerr("553 %s... bad address", p);
61158333Seric 					p = delimptr;
6124098Seric 				}
6134098Seric 			}
6144157Seric 			else
61515769Seric 			{
61658662Seric 				p = nlp;
61715769Seric 			}
6181515Seric 
6194098Seric 			/* see if there should be a continuation line */
6204106Seric 			c = fgetc(af);
6214106Seric 			if (!feof(af))
6224314Seric 				(void) ungetc(c, af);
6234106Seric 			if (c != ' ' && c != '\t')
6244098Seric 				break;
6254098Seric 
6264098Seric 			/* read continuation line */
6274098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
6284098Seric 				break;
6299368Seric 			LineNumber++;
63057135Seric 
63157135Seric 			/* check for line overflow */
63257135Seric 			if (strchr(p, '\n') == NULL)
63357135Seric 			{
63458151Seric 				usrerr("554 alias too long");
63557135Seric 				break;
63657135Seric 			}
6374098Seric 		}
638*67473Seric 		if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
63916898Seric 		{
64064278Seric 			syserr("554 %s... cannot alias non-local names",
64164278Seric 				al.q_paddr);
64216898Seric 			continue;
64316898Seric 		}
6444314Seric 
6454314Seric 		/*
6464314Seric 		**  Insert alias into symbol table or DBM file
6474314Seric 		*/
6484314Seric 
64957381Seric 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
65057381Seric 			makelower(al.q_user);
6514322Seric 
65259673Seric 		lhssize = strlen(al.q_user);
65359673Seric 		rhssize = strlen(rhs);
65460089Seric 		map->map_class->map_store(map, al.q_user, rhs);
6554157Seric 
65659673Seric 		if (al.q_paddr != NULL)
65759673Seric 			free(al.q_paddr);
65859673Seric 		if (al.q_host != NULL)
65959673Seric 			free(al.q_host);
66059673Seric 		if (al.q_user != NULL)
66159673Seric 			free(al.q_user);
6624322Seric 
6634322Seric 		/* statistics */
6644322Seric 		naliases++;
6654322Seric 		bytes += lhssize + rhssize;
6664322Seric 		if (rhssize > longest)
6674322Seric 			longest = rhssize;
6681515Seric 	}
66919784Seric 
67060207Seric 	CurEnv->e_to = NULL;
67159673Seric 	FileName = NULL;
67267263Seric 	if (Verbose || announcestats)
67359733Seric 		message("%s: %d aliases, longest %d bytes, %d bytes total",
67460089Seric 			map->map_file, naliases, longest, bytes);
67559673Seric # ifdef LOG
67667263Seric 	if (LogLevel > 7 && logstats)
67759673Seric 		syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
67860089Seric 			map->map_file, naliases, longest, bytes);
67959673Seric # endif /* LOG */
68059673Seric }
68159673Seric /*
682292Seric **  FORWARD -- Try to forward mail
683292Seric **
684292Seric **	This is similar but not identical to aliasing.
685292Seric **
686292Seric **	Parameters:
6874314Seric **		user -- the name of the user who's mail we would like
6884314Seric **			to forward to.  It must have been verified --
6894314Seric **			i.e., the q_home field must have been filled
6904314Seric **			in.
6914999Seric **		sendq -- a pointer to the head of the send queue to
6924999Seric **			put this user's aliases in.
693292Seric **
694292Seric **	Returns:
6954098Seric **		none.
696292Seric **
697292Seric **	Side Effects:
6983185Seric **		New names are added to send queues.
699292Seric */
700292Seric 
70155012Seric forward(user, sendq, e)
7022966Seric 	ADDRESS *user;
7034999Seric 	ADDRESS **sendq;
70455012Seric 	register ENVELOPE *e;
705292Seric {
70657136Seric 	char *pp;
70757136Seric 	char *ep;
7084069Seric 
7097671Seric 	if (tTd(27, 1))
7104098Seric 		printf("forward(%s)\n", user->q_paddr);
7114098Seric 
712*67473Seric 	if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
713*67473Seric 	    bitset(QBADADDR, user->q_flags))
7144098Seric 		return;
7154314Seric 	if (user->q_home == NULL)
71658059Seric 	{
71758151Seric 		syserr("554 forward: no home");
71858059Seric 		user->q_home = "/nosuchdirectory";
71958059Seric 	}
7204069Seric 
7214069Seric 	/* good address -- look for .forward file in home */
72255012Seric 	define('z', user->q_home, e);
72357136Seric 	define('u', user->q_user, e);
72457136Seric 	define('h', user->q_host, e);
72557136Seric 	if (ForwardPath == NULL)
72658050Seric 		ForwardPath = newstr("\201z/.forward");
72757136Seric 
72857136Seric 	for (pp = ForwardPath; pp != NULL; pp = ep)
72957136Seric 	{
73058247Seric 		int err;
73157232Seric 		char buf[MAXPATHLEN+1];
73257136Seric 
73357136Seric 		ep = strchr(pp, ':');
73457136Seric 		if (ep != NULL)
73557136Seric 			*ep = '\0';
73657136Seric 		expand(pp, buf, &buf[sizeof buf - 1], e);
73757136Seric 		if (ep != NULL)
73857136Seric 			*ep++ = ':';
73957136Seric 		if (tTd(27, 3))
74057136Seric 			printf("forward: trying %s\n", buf);
74163753Seric 
74258247Seric 		err = include(buf, TRUE, user, sendq, e);
74358247Seric 		if (err == 0)
74457136Seric 			break;
74564325Seric 		else if (transienterror(err))
74658247Seric 		{
74758247Seric 			/* we have to suspend this message */
74859563Seric 			if (tTd(27, 2))
74959563Seric 				printf("forward: transient error on %s\n", buf);
75059563Seric #ifdef LOG
75159563Seric 			if (LogLevel > 2)
75259624Seric 				syslog(LOG_ERR, "%s: forward %s: transient error: %s",
75366284Seric 					e->e_id == NULL ? "NOQUEUE" : e->e_id,
75466284Seric 					buf, errstring(err));
75559563Seric #endif
75659611Seric 			message("%s: %s: message queued", buf, errstring(err));
75763853Seric 			user->q_flags |= QQUEUEUP;
75858247Seric 			return;
75958247Seric 		}
76057136Seric 	}
761292Seric }
762