xref: /original-bsd/usr.sbin/sendmail/src/alias.c (revision 661ccc76)
1 /*
2  * Copyright (c) 1983, 1995 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 # include "sendmail.h"
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)alias.c	8.49 (Berkeley) 05/30/95";
13 #endif /* not lint */
14 
15 
16 MAP	*AliasFileMap = NULL;	/* the actual aliases.files map */
17 int	NAliasFileMaps;		/* the number of entries in AliasFileMap */
18 /*
19 **  ALIAS -- Compute aliases.
20 **
21 **	Scans the alias file for an alias for the given address.
22 **	If found, it arranges to deliver to the alias list instead.
23 **	Uses libdbm database if -DDBM.
24 **
25 **	Parameters:
26 **		a -- address to alias.
27 **		sendq -- a pointer to the head of the send queue
28 **			to put the aliases in.
29 **		aliaslevel -- the current alias nesting depth.
30 **		e -- the current envelope.
31 **
32 **	Returns:
33 **		none
34 **
35 **	Side Effects:
36 **		Aliases found are expanded.
37 **
38 **	Deficiencies:
39 **		It should complain about names that are aliased to
40 **			nothing.
41 */
42 
43 void
alias(a,sendq,aliaslevel,e)44 alias(a, sendq, aliaslevel, e)
45 	register ADDRESS *a;
46 	ADDRESS **sendq;
47 	int aliaslevel;
48 	register ENVELOPE *e;
49 {
50 	register char *p;
51 	int naliases;
52 	char *owner;
53 	auto int stat = EX_OK;
54 	char obuf[MAXNAME + 6];
55 	extern char *aliaslookup();
56 
57 	if (tTd(27, 1))
58 		printf("alias(%s)\n", a->q_user);
59 
60 	/* don't realias already aliased names */
61 	if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
62 		return;
63 
64 	if (NoAlias)
65 		return;
66 
67 	e->e_to = a->q_paddr;
68 
69 	/*
70 	**  Look up this name.
71 	**
72 	**	If the map was unavailable, we will queue this message
73 	**	until the map becomes available; otherwise, we could
74 	**	bounce messages inappropriately.
75 	*/
76 
77 	p = aliaslookup(a->q_user, &stat, e);
78 	if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE)
79 	{
80 		a->q_flags |= QQUEUEUP;
81 		if (e->e_message == NULL)
82 			e->e_message = "alias database unavailable";
83 		return;
84 	}
85 	if (p == NULL)
86 		return;
87 
88 	/*
89 	**  Match on Alias.
90 	**	Deliver to the target list.
91 	*/
92 
93 	if (tTd(27, 1))
94 		printf("%s (%s, %s) aliased to %s\n",
95 		    a->q_paddr, a->q_host, a->q_user, p);
96 	if (bitset(EF_VRFYONLY, e->e_flags))
97 	{
98 		a->q_flags |= QVERIFIED;
99 		e->e_nrcpts++;
100 		return;
101 	}
102 	message("aliased to %s", p);
103 #ifdef LOG
104 	if (LogLevel > 9)
105 		syslog(LOG_INFO, "%s: alias %s => %s",
106 			e->e_id == NULL ? "NOQUEUE" : e->e_id,
107 			a->q_paddr, p);
108 #endif
109 	a->q_flags &= ~QSELFREF;
110 	if (tTd(27, 5))
111 	{
112 		printf("alias: QDONTSEND ");
113 		printaddr(a, FALSE);
114 	}
115 	a->q_flags |= QDONTSEND;
116 	naliases = sendtolist(p, a, sendq, aliaslevel + 1, e);
117 	if (bitset(QSELFREF, a->q_flags))
118 		a->q_flags &= ~QDONTSEND;
119 
120 	/*
121 	**  Look for owner of alias
122 	*/
123 
124 	(void) strcpy(obuf, "owner-");
125 	if (strncmp(a->q_user, "owner-", 6) == 0)
126 		(void) strcat(obuf, "owner");
127 	else
128 		(void) strcat(obuf, a->q_user);
129 	if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
130 		makelower(obuf);
131 	owner = aliaslookup(obuf, &stat, e);
132 	if (owner == NULL)
133 		return;
134 
135 	/* reflect owner into envelope sender */
136 	if (strpbrk(owner, ",:/|\"") != NULL)
137 		owner = obuf;
138 	a->q_owner = newstr(owner);
139 
140 	/* announce delivery to this alias; NORECEIPT bit set later */
141 	if (e->e_xfp != NULL)
142 		fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
143 			a->q_paddr);
144 	e->e_flags |= EF_SENDRECEIPT;
145 	a->q_flags |= QDELIVERED|QEXPANDED;
146 }
147 /*
148 **  ALIASLOOKUP -- look up a name in the alias file.
149 **
150 **	Parameters:
151 **		name -- the name to look up.
152 **		pstat -- a pointer to a place to put the status.
153 **		e -- the current envelope.
154 **
155 **	Returns:
156 **		the value of name.
157 **		NULL if unknown.
158 **
159 **	Side Effects:
160 **		none.
161 **
162 **	Warnings:
163 **		The return value will be trashed across calls.
164 */
165 
166 char *
aliaslookup(name,pstat,e)167 aliaslookup(name, pstat, e)
168 	char *name;
169 	int *pstat;
170 	ENVELOPE *e;
171 {
172 	static MAP *map = NULL;
173 
174 	if (map == NULL)
175 	{
176 		STAB *s = stab("aliases", ST_MAP, ST_FIND);
177 
178 		if (s == NULL)
179 			return NULL;
180 		map = &s->s_map;
181 	}
182 	if (!bitset(MF_OPEN, map->map_mflags))
183 		return NULL;
184 	return (*map->map_class->map_lookup)(map, name, NULL, pstat);
185 }
186 /*
187 **  SETALIAS -- set up an alias map
188 **
189 **	Called when reading configuration file.
190 **
191 **	Parameters:
192 **		spec -- the alias specification
193 **
194 **	Returns:
195 **		none.
196 */
197 
198 void
setalias(spec)199 setalias(spec)
200 	char *spec;
201 {
202 	register char *p;
203 	register MAP *map;
204 	char *class;
205 	STAB *s;
206 
207 	if (tTd(27, 8))
208 		printf("setalias(%s)\n", spec);
209 
210 	for (p = spec; p != NULL; )
211 	{
212 		char buf[50];
213 
214 		while (isspace(*p))
215 			p++;
216 		if (*p == '\0')
217 			break;
218 		spec = p;
219 
220 		if (NAliasFileMaps >= MAXMAPSTACK)
221 		{
222 			syserr("Too many alias databases defined, %d max",
223 				MAXMAPSTACK);
224 			return;
225 		}
226 		if (AliasFileMap == NULL)
227 		{
228 			strcpy(buf, "aliases.files sequence");
229 			AliasFileMap = makemapentry(buf);
230 			if (AliasFileMap == NULL)
231 			{
232 				syserr("setalias: cannot create aliases.files map");
233 				return;
234 			}
235 		}
236 		(void) sprintf(buf, "Alias%d", NAliasFileMaps);
237 		s = stab(buf, ST_MAP, ST_ENTER);
238 		map = &s->s_map;
239 		bzero(map, sizeof *map);
240 		map->map_mname = s->s_name;
241 
242 		p = strpbrk(p, " ,/:");
243 		if (p != NULL && *p == ':')
244 		{
245 			/* map name */
246 			*p++ = '\0';
247 			class = spec;
248 			spec = p;
249 		}
250 		else
251 		{
252 			class = "implicit";
253 			map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
254 		}
255 
256 		/* find end of spec */
257 		if (p != NULL)
258 			p = strchr(p, ',');
259 		if (p != NULL)
260 			*p++ = '\0';
261 
262 		if (tTd(27, 20))
263 			printf("  map %s:%s %s\n", class, s->s_name, spec);
264 
265 		/* look up class */
266 		s = stab(class, ST_MAPCLASS, ST_FIND);
267 		if (s == NULL)
268 		{
269 			if (tTd(27, 1))
270 				printf("Unknown alias class %s\n", class);
271 		}
272 		else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
273 		{
274 			syserr("setalias: map class %s can't handle aliases",
275 				class);
276 		}
277 		else
278 		{
279 			map->map_class = &s->s_mapclass;
280 			if (map->map_class->map_parse(map, spec))
281 			{
282 				map->map_mflags |= MF_VALID|MF_ALIAS;
283 				AliasFileMap->map_stack[NAliasFileMaps++] = map;
284 			}
285 		}
286 	}
287 }
288 /*
289 **  ALIASWAIT -- wait for distinguished @:@ token to appear.
290 **
291 **	This can decide to reopen or rebuild the alias file
292 **
293 **	Parameters:
294 **		map -- a pointer to the map descriptor for this alias file.
295 **		ext -- the filename extension (e.g., ".db") for the
296 **			database file.
297 **		isopen -- if set, the database is already open, and we
298 **			should check for validity; otherwise, we are
299 **			just checking to see if it should be created.
300 **
301 **	Returns:
302 **		TRUE -- if the database is open when we return.
303 **		FALSE -- if the database is closed when we return.
304 */
305 
306 bool
aliaswait(map,ext,isopen)307 aliaswait(map, ext, isopen)
308 	MAP *map;
309 	char *ext;
310 	int isopen;
311 {
312 	bool attimeout = FALSE;
313 	time_t mtime;
314 	struct stat stb;
315 	char buf[MAXNAME + 1];
316 
317 	if (tTd(27, 3))
318 		printf("aliaswait(%s:%s)\n",
319 			map->map_class->map_cname, map->map_file);
320 	if (bitset(MF_ALIASWAIT, map->map_mflags))
321 		return isopen;
322 	map->map_mflags |= MF_ALIASWAIT;
323 
324 	if (SafeAlias > 0)
325 	{
326 		auto int st;
327 		time_t toolong = curtime() + SafeAlias;
328 		unsigned int sleeptime = 2;
329 
330 		while (isopen &&
331 		       map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
332 		{
333 			if (curtime() > toolong)
334 			{
335 				/* we timed out */
336 				attimeout = TRUE;
337 				break;
338 			}
339 
340 			/*
341 			**  Close and re-open the alias database in case
342 			**  the one is mv'ed instead of cp'ed in.
343 			*/
344 
345 			if (tTd(27, 2))
346 				printf("aliaswait: sleeping for %d seconds\n",
347 					sleeptime);
348 
349 			map->map_class->map_close(map);
350 			map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
351 			sleep(sleeptime);
352 			sleeptime *= 2;
353 			if (sleeptime > 60)
354 				sleeptime = 60;
355 			isopen = map->map_class->map_open(map, O_RDONLY);
356 		}
357 	}
358 
359 	/* see if we need to go into auto-rebuild mode */
360 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
361 	{
362 		if (tTd(27, 3))
363 			printf("aliaswait: not rebuildable\n");
364 		map->map_mflags &= ~MF_ALIASWAIT;
365 		return isopen;
366 	}
367 	if (stat(map->map_file, &stb) < 0)
368 	{
369 		if (tTd(27, 3))
370 			printf("aliaswait: no source file\n");
371 		map->map_mflags &= ~MF_ALIASWAIT;
372 		return isopen;
373 	}
374 	mtime = stb.st_mtime;
375 	(void) strcpy(buf, map->map_file);
376 	if (ext != NULL)
377 		(void) strcat(buf, ext);
378 	if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
379 	{
380 		/* database is out of date */
381 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
382 		{
383 			bool oldSuprErrs;
384 
385 			message("auto-rebuilding alias database %s", buf);
386 			oldSuprErrs = SuprErrs;
387 			SuprErrs = TRUE;
388 			if (isopen)
389 			{
390 				map->map_class->map_close(map);
391 				map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
392 			}
393 			rebuildaliases(map, TRUE);
394 			isopen = map->map_class->map_open(map, O_RDONLY);
395 			SuprErrs = oldSuprErrs;
396 		}
397 		else
398 		{
399 #ifdef LOG
400 			if (LogLevel > 3)
401 				syslog(LOG_INFO, "alias database %s out of date",
402 					buf);
403 #endif /* LOG */
404 			message("Warning: alias database %s out of date", buf);
405 		}
406 	}
407 	map->map_mflags &= ~MF_ALIASWAIT;
408 	return isopen;
409 }
410 /*
411 **  REBUILDALIASES -- rebuild the alias database.
412 **
413 **	Parameters:
414 **		map -- the database to rebuild.
415 **		automatic -- set if this was automatically generated.
416 **
417 **	Returns:
418 **		none.
419 **
420 **	Side Effects:
421 **		Reads the text version of the database, builds the
422 **		DBM or DB version.
423 */
424 
425 void
rebuildaliases(map,automatic)426 rebuildaliases(map, automatic)
427 	register MAP *map;
428 	bool automatic;
429 {
430 	FILE *af;
431 	bool nolock = FALSE;
432 	sigfunc_t oldsigint, oldsigquit;
433 #ifdef SIGTSTP
434 	sigfunc_t oldsigtstp;
435 #endif
436 
437 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
438 		return;
439 
440 	/* try to lock the source file */
441 	if ((af = fopen(map->map_file, "r+")) == NULL)
442 	{
443 		if ((errno != EACCES && errno != EROFS) || automatic ||
444 		    (af = fopen(map->map_file, "r")) == NULL)
445 		{
446 			int saveerr = errno;
447 
448 			if (tTd(27, 1))
449 				printf("Can't open %s: %s\n",
450 					map->map_file, errstring(saveerr));
451 			if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
452 				message("newaliases: cannot open %s: %s",
453 					map->map_file, errstring(saveerr));
454 			errno = 0;
455 			return;
456 		}
457 		nolock = TRUE;
458 		message("warning: cannot lock %s: %s",
459 			map->map_file, errstring(errno));
460 	}
461 
462 	/* see if someone else is rebuilding the alias file */
463 	if (!nolock &&
464 	    !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
465 	{
466 		/* yes, they are -- wait until done */
467 		message("Alias file %s is already being rebuilt",
468 			map->map_file);
469 		if (OpMode != MD_INITALIAS)
470 		{
471 			/* wait for other rebuild to complete */
472 			(void) lockfile(fileno(af), map->map_file, NULL,
473 					LOCK_EX);
474 		}
475 		(void) xfclose(af, "rebuildaliases1", map->map_file);
476 		errno = 0;
477 		return;
478 	}
479 
480 	/* avoid denial-of-service attacks */
481 	resetlimits();
482 	oldsigint = setsignal(SIGINT, SIG_IGN);
483 	oldsigquit = setsignal(SIGQUIT, SIG_IGN);
484 #ifdef SIGTSTP
485 	oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
486 #endif
487 
488 	if (map->map_class->map_open(map, O_RDWR))
489 	{
490 #ifdef LOG
491 		if (LogLevel > 7)
492 		{
493 			syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
494 				map->map_file, automatic ? "auto" : "",
495 				username());
496 		}
497 #endif /* LOG */
498 		map->map_mflags |= MF_OPEN|MF_WRITABLE;
499 		readaliases(map, af, !automatic, TRUE);
500 	}
501 	else
502 	{
503 		if (tTd(27, 1))
504 			printf("Can't create database for %s: %s\n",
505 				map->map_file, errstring(errno));
506 		if (!automatic)
507 			syserr("Cannot create database for alias file %s",
508 				map->map_file);
509 	}
510 
511 	/* close the file, thus releasing locks */
512 	xfclose(af, "rebuildaliases2", map->map_file);
513 
514 	/* add distinguished entries and close the database */
515 	if (bitset(MF_OPEN, map->map_mflags))
516 	{
517 		map->map_class->map_close(map);
518 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
519 	}
520 
521 	/* restore the old signals */
522 	(void) setsignal(SIGINT, oldsigint);
523 	(void) setsignal(SIGQUIT, oldsigquit);
524 #ifdef SIGTSTP
525 	(void) setsignal(SIGTSTP, oldsigtstp);
526 #endif
527 }
528 /*
529 **  READALIASES -- read and process the alias file.
530 **
531 **	This routine implements the part of initaliases that occurs
532 **	when we are not going to use the DBM stuff.
533 **
534 **	Parameters:
535 **		map -- the alias database descriptor.
536 **		af -- file to read the aliases from.
537 **		announcestats -- anounce statistics regarding number of
538 **			aliases, longest alias, etc.
539 **		logstats -- lot the same info.
540 **
541 **	Returns:
542 **		none.
543 **
544 **	Side Effects:
545 **		Reads aliasfile into the symbol table.
546 **		Optionally, builds the .dir & .pag files.
547 */
548 
549 void
readaliases(map,af,announcestats,logstats)550 readaliases(map, af, announcestats, logstats)
551 	register MAP *map;
552 	FILE *af;
553 	bool announcestats;
554 	bool logstats;
555 {
556 	register char *p;
557 	char *rhs;
558 	bool skipping;
559 	long naliases, bytes, longest;
560 	ADDRESS al, bl;
561 	char line[BUFSIZ];
562 
563 	/*
564 	**  Read and interpret lines
565 	*/
566 
567 	FileName = map->map_file;
568 	LineNumber = 0;
569 	naliases = bytes = longest = 0;
570 	skipping = FALSE;
571 	while (fgets(line, sizeof (line), af) != NULL)
572 	{
573 		int lhssize, rhssize;
574 
575 		LineNumber++;
576 		p = strchr(line, '\n');
577 		if (p != NULL)
578 			*p = '\0';
579 		switch (line[0])
580 		{
581 		  case '#':
582 		  case '\0':
583 			skipping = FALSE;
584 			continue;
585 
586 		  case ' ':
587 		  case '\t':
588 			if (!skipping)
589 				syserr("554 Non-continuation line starts with space");
590 			skipping = TRUE;
591 			continue;
592 		}
593 		skipping = FALSE;
594 
595 		/*
596 		**  Process the LHS
597 		**	Find the colon separator, and parse the address.
598 		**	It should resolve to a local name -- this will
599 		**	be checked later (we want to optionally do
600 		**	parsing of the RHS first to maximize error
601 		**	detection).
602 		*/
603 
604 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
605 			continue;
606 		if (*p++ != ':')
607 		{
608 			syserr("554 missing colon");
609 			continue;
610 		}
611 		if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
612 		{
613 			syserr("554 %.40s... illegal alias name", line);
614 			continue;
615 		}
616 
617 		/*
618 		**  Process the RHS.
619 		**	'al' is the internal form of the LHS address.
620 		**	'p' points to the text of the RHS.
621 		*/
622 
623 		while (isascii(*p) && isspace(*p))
624 			p++;
625 		rhs = p;
626 		for (;;)
627 		{
628 			register char c;
629 			register char *nlp;
630 
631 			nlp = &p[strlen(p)];
632 			if (nlp[-1] == '\n')
633 				*--nlp = '\0';
634 
635 			if (CheckAliases)
636 			{
637 				/* do parsing & compression of addresses */
638 				while (*p != '\0')
639 				{
640 					auto char *delimptr;
641 
642 					while ((isascii(*p) && isspace(*p)) ||
643 								*p == ',')
644 						p++;
645 					if (*p == '\0')
646 						break;
647 					if (parseaddr(p, &bl, RF_COPYNONE, ',',
648 						      &delimptr, CurEnv) == NULL)
649 						usrerr("553 %s... bad address", p);
650 					p = delimptr;
651 				}
652 			}
653 			else
654 			{
655 				p = nlp;
656 			}
657 
658 			/* see if there should be a continuation line */
659 			c = getc(af);
660 			if (!feof(af))
661 				(void) ungetc(c, af);
662 			if (c != ' ' && c != '\t')
663 				break;
664 
665 			/* read continuation line */
666 			if (fgets(p, sizeof line - (p - line), af) == NULL)
667 				break;
668 			LineNumber++;
669 
670 			/* check for line overflow */
671 			if (strchr(p, '\n') == NULL)
672 			{
673 				usrerr("554 alias too long");
674 				break;
675 			}
676 		}
677 		if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
678 		{
679 			syserr("554 %s... cannot alias non-local names",
680 				al.q_paddr);
681 			continue;
682 		}
683 
684 		/*
685 		**  Insert alias into symbol table or DBM file
686 		*/
687 
688 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
689 			makelower(al.q_user);
690 
691 		lhssize = strlen(al.q_user);
692 		rhssize = strlen(rhs);
693 		map->map_class->map_store(map, al.q_user, rhs);
694 
695 		if (al.q_paddr != NULL)
696 			free(al.q_paddr);
697 		if (al.q_host != NULL)
698 			free(al.q_host);
699 		if (al.q_user != NULL)
700 			free(al.q_user);
701 
702 		/* statistics */
703 		naliases++;
704 		bytes += lhssize + rhssize;
705 		if (rhssize > longest)
706 			longest = rhssize;
707 	}
708 
709 	CurEnv->e_to = NULL;
710 	FileName = NULL;
711 	if (Verbose || announcestats)
712 		message("%s: %d aliases, longest %d bytes, %d bytes total",
713 			map->map_file, naliases, longest, bytes);
714 # ifdef LOG
715 	if (LogLevel > 7 && logstats)
716 		syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
717 			map->map_file, naliases, longest, bytes);
718 # endif /* LOG */
719 }
720 /*
721 **  FORWARD -- Try to forward mail
722 **
723 **	This is similar but not identical to aliasing.
724 **
725 **	Parameters:
726 **		user -- the name of the user who's mail we would like
727 **			to forward to.  It must have been verified --
728 **			i.e., the q_home field must have been filled
729 **			in.
730 **		sendq -- a pointer to the head of the send queue to
731 **			put this user's aliases in.
732 **		aliaslevel -- the current alias nesting depth.
733 **		e -- the current envelope.
734 **
735 **	Returns:
736 **		none.
737 **
738 **	Side Effects:
739 **		New names are added to send queues.
740 */
741 
742 void
forward(user,sendq,aliaslevel,e)743 forward(user, sendq, aliaslevel, e)
744 	ADDRESS *user;
745 	ADDRESS **sendq;
746 	int aliaslevel;
747 	register ENVELOPE *e;
748 {
749 	char *pp;
750 	char *ep;
751 
752 	if (tTd(27, 1))
753 		printf("forward(%s)\n", user->q_paddr);
754 
755 	if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
756 	    bitset(QBADADDR, user->q_flags))
757 		return;
758 	if (user->q_home == NULL)
759 	{
760 		syserr("554 forward: no home");
761 		user->q_home = "/nosuchdirectory";
762 	}
763 
764 	/* good address -- look for .forward file in home */
765 	define('z', user->q_home, e);
766 	define('u', user->q_user, e);
767 	define('h', user->q_host, e);
768 	if (ForwardPath == NULL)
769 		ForwardPath = newstr("\201z/.forward");
770 
771 	for (pp = ForwardPath; pp != NULL; pp = ep)
772 	{
773 		int err;
774 		char buf[MAXPATHLEN+1];
775 		extern int include();
776 
777 		ep = strchr(pp, ':');
778 		if (ep != NULL)
779 			*ep = '\0';
780 		expand(pp, buf, sizeof buf, e);
781 		if (ep != NULL)
782 			*ep++ = ':';
783 		if (tTd(27, 3))
784 			printf("forward: trying %s\n", buf);
785 
786 		err = include(buf, TRUE, user, sendq, aliaslevel, e);
787 		if (err == 0)
788 			break;
789 		else if (transienterror(err))
790 		{
791 			/* we have to suspend this message */
792 			if (tTd(27, 2))
793 				printf("forward: transient error on %s\n", buf);
794 #ifdef LOG
795 			if (LogLevel > 2)
796 				syslog(LOG_ERR, "%s: forward %s: transient error: %s",
797 					e->e_id == NULL ? "NOQUEUE" : e->e_id,
798 					buf, errstring(err));
799 #endif
800 			message("%s: %s: message queued", buf, errstring(err));
801 			user->q_flags |= QQUEUEUP;
802 			return;
803 		}
804 	}
805 }
806