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