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