xref: /csrg-svn/usr.sbin/sendmail/src/alias.c (revision 58050)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 # include <sys/types.h>
10 # include <sys/stat.h>
11 # include <sys/file.h>
12 # include <signal.h>
13 # include "sendmail.h"
14 # include <fcntl.h>
15 # include <pwd.h>
16 
17 # ifdef DBM
18 ERROR: DBM is no longer supported -- use NDBM instead.
19 # endif
20 
21 # ifdef NEWDB
22 # include <db.h>
23 # endif
24 
25 # ifdef NDBM
26 # include <ndbm.h>
27 # endif
28 
29 #ifndef lint
30 #ifdef NEWDB
31 #ifdef NDBM
32 static char sccsid[] = "@(#)alias.c	6.11 (Berkeley) 02/18/93 (with NEWDB and NDBM)";
33 #else
34 static char sccsid[] = "@(#)alias.c	6.11 (Berkeley) 02/18/93 (with NEWDB)";
35 #endif
36 #else
37 #ifdef NDBM
38 static char sccsid[] = "@(#)alias.c	6.11 (Berkeley) 02/18/93 (with NDBM)";
39 #else
40 static char sccsid[] = "@(#)alias.c	6.11 (Berkeley) 02/18/93 (without NEWDB or NDBM)";
41 #endif
42 #endif
43 #endif /* not lint */
44 /*
45 **  ALIAS -- Compute aliases.
46 **
47 **	Scans the alias file for an alias for the given address.
48 **	If found, it arranges to deliver to the alias list instead.
49 **	Uses libdbm database if -DDBM.
50 **
51 **	Parameters:
52 **		a -- address to alias.
53 **		sendq -- a pointer to the head of the send queue
54 **			to put the aliases in.
55 **
56 **	Returns:
57 **		none
58 **
59 **	Side Effects:
60 **		Aliases found are expanded.
61 **
62 **	Notes:
63 **		If NoAlias (the "-n" flag) is set, no aliasing is
64 **			done.
65 **
66 **	Deficiencies:
67 **		It should complain about names that are aliased to
68 **			nothing.
69 */
70 
71 
72 /*
73 **  Sun YP servers read the dbm files directly, so we have to build them
74 **  even if NEWDB
75 */
76 
77 #ifdef NDBM
78 # ifndef NEWDB
79 #  define IF_MAKEDBMFILES
80 # else
81 #  ifdef YPCOMPAT
82 #   define IF_MAKEDBMFILES		if (makedbmfiles)
83 #  endif
84 # endif
85 #endif
86 
87 typedef union
88 {
89 #ifdef NDBM
90 	datum	dbm;
91 #endif
92 #ifdef NEWDB
93 	DBT	dbt;
94 #endif
95 	struct
96 	{
97 		char	*data;
98 		int	size;
99 	} xx;
100 } DBdatum;
101 
102 #ifdef NEWDB
103 static DB	*AliasDBptr;
104 #endif
105 #ifdef NDBM
106 static DBM	*AliasDBMptr;
107 #endif
108 
109 alias(a, sendq, e)
110 	register ADDRESS *a;
111 	ADDRESS **sendq;
112 	register ENVELOPE *e;
113 {
114 	register char *p;
115 	extern char *aliaslookup();
116 
117 	if (tTd(27, 1))
118 		printf("alias(%s)\n", a->q_paddr);
119 
120 	/* don't realias already aliased names */
121 	if (bitset(QDONTSEND, a->q_flags))
122 		return;
123 
124 	e->e_to = a->q_paddr;
125 
126 	/*
127 	**  Look up this name
128 	*/
129 
130 	if (NoAlias)
131 		p = NULL;
132 	else
133 		p = aliaslookup(a->q_user);
134 	if (p == NULL)
135 		return;
136 
137 	/*
138 	**  Match on Alias.
139 	**	Deliver to the target list.
140 	*/
141 
142 	if (tTd(27, 1))
143 		printf("%s (%s, %s) aliased to %s\n",
144 		    a->q_paddr, a->q_host, a->q_user, p);
145 	message(Arpa_Info, "aliased to %s", p);
146 #ifdef LOG
147 	if (LogLevel > 9)
148 		syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
149 #endif
150 	AliasLevel++;
151 	sendtolist(p, a, sendq, e);
152 	AliasLevel--;
153 }
154 /*
155 **  ALIASLOOKUP -- look up a name in the alias file.
156 **
157 **	Parameters:
158 **		name -- the name to look up.
159 **
160 **	Returns:
161 **		the value of name.
162 **		NULL if unknown.
163 **
164 **	Side Effects:
165 **		none.
166 **
167 **	Warnings:
168 **		The return value will be trashed across calls.
169 */
170 
171 char *
172 aliaslookup(name)
173 	char *name;
174 {
175 	int i;
176 	char keybuf[MAXNAME + 1];
177 # if defined(NEWDB) || defined(NDBM)
178 	DBdatum rhs, lhs;
179 	int s;
180 # else /* neither NEWDB nor NDBM */
181 	register STAB *s;
182 # endif
183 
184 	/* create a key for fetch */
185 	i = strlen(name) + 1;
186 	if (i > sizeof keybuf)
187 		i = sizeof keybuf;
188 	bcopy(name, keybuf, i);
189 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
190 		makelower(keybuf);
191 
192 # if defined(NEWDB) || defined(NDBM)
193 	lhs.xx.size = i;
194 	lhs.xx.data = keybuf;
195 # ifdef NEWDB
196 	if (AliasDBptr != NULL)
197 	{
198 		i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0);
199 		if (i == 0)
200 			return (rhs.dbt.data);
201 	}
202 # ifdef NDBM
203 	else if (AliasDBMptr != NULL)
204 	{
205 		rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
206 		return (rhs.dbm.dptr);
207 	}
208 # endif /* NDBM */
209 	return (NULL);
210 # else /* not NEWDB */
211 	rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm);
212 	return (rhs.dbm.dptr);
213 # endif /* NEWDB */
214 # else /* neither NEWDB nor NDBM */
215 	s = stab(keybuf, ST_ALIAS, ST_FIND);
216 	if (s != NULL)
217 		return (s->s_alias);
218 	return (NULL);
219 # endif
220 }
221 /*
222 **  INITALIASES -- initialize for aliasing
223 **
224 **	Very different depending on whether we are running NDBM or not.
225 **
226 **	Parameters:
227 **		aliasfile -- location of aliases.
228 **		init -- if set and if NDBM, initialize the NDBM files.
229 **
230 **	Returns:
231 **		none.
232 **
233 **	Side Effects:
234 **		initializes aliases:
235 **		if NDBM:  opens the database.
236 **		if ~NDBM: reads the aliases into the symbol table.
237 */
238 
239 # define DBMMODE	0644
240 
241 initaliases(aliasfile, init, e)
242 	char *aliasfile;
243 	bool init;
244 	register ENVELOPE *e;
245 {
246 #if defined(NDBM) || defined(NEWDB)
247 	int atcnt;
248 	time_t modtime;
249 	bool automatic = FALSE;
250 	char buf[MAXNAME];
251 #endif
252 	struct stat stb;
253 	static bool initialized = FALSE;
254 	static int readaliases();
255 
256 	if (initialized)
257 		return;
258 	initialized = TRUE;
259 
260 	if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
261 	{
262 		if (aliasfile != NULL && init)
263 			syserr("Cannot open %s", aliasfile);
264 		NoAlias = TRUE;
265 		errno = 0;
266 		return;
267 	}
268 
269 # if defined(NDBM) || defined(NEWDB)
270 	/*
271 	**  Check to see that the alias file is complete.
272 	**	If not, we will assume that someone died, and it is up
273 	**	to us to rebuild it.
274 	*/
275 
276 	if (!init)
277 	{
278 # ifdef NEWDB
279 		(void) strcpy(buf, aliasfile);
280 		(void) strcat(buf, ".db");
281 		AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
282 		if (AliasDBptr == NULL)
283 		{
284 # ifdef NDBM
285 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
286 			if (AliasDBMptr == NULL)
287 			{
288 				syserr("initaliases: cannot open %s", buf);
289 				NoAlias = TRUE;
290 				return;
291 			}
292 # else
293 			syserr("initaliases: cannot open %s", buf);
294 			NoAlias = TRUE;
295 			return;
296 # endif
297 		}
298 # else
299 		AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
300 		if (AliasDBMptr == NULL)
301 		{
302 			syserr("initaliases: cannot open DBM database %s.{pag,dir}",
303 				aliasfile);
304 			NoAlias = TRUE;
305 			return;
306 		}
307 # endif
308 	}
309 	atcnt = SafeAlias * 2;
310 	if (atcnt > 0)
311 	{
312 		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
313 		{
314 			/*
315 			**  Reinitialize alias file in case the new
316 			**  one is mv'ed in instead of cp'ed in.
317 			**
318 			**	Only works with new DBM -- old one will
319 			**	just consume file descriptors forever.
320 			**	If you have a dbmclose() it can be
321 			**	added before the sleep(30).
322 			*/
323 
324 # ifdef NEWDB
325 			if (AliasDBptr != NULL)
326 				AliasDBptr->close(AliasDBptr);
327 # endif
328 # ifdef NDBM
329 			if (AliasDBMptr != NULL)
330 				dbm_close(AliasDBMptr);
331 # endif
332 
333 			sleep(30);
334 # ifdef NEWDB
335 			(void) strcpy(buf, aliasfile);
336 			(void) strcat(buf, ".db");
337 			AliasDBptr =
338 			    dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
339 			if (AliasDBptr == NULL)
340 			{
341 # ifdef NDBM
342 				AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
343 # else
344 				syserr("initaliases: cannot open %s", buf);
345 				NoAlias = TRUE;
346 				return;
347 # endif
348 			}
349 # else
350 # ifdef NDBM
351 			AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE);
352 			if (AliasDBMptr == NULL)
353 			{
354 				syserr("initaliases: cannot open DBM database %s.{pag,dir}",
355 					aliasfile);
356 				NoAlias = TRUE;
357 				return;
358 			}
359 # endif
360 # endif
361 		}
362 	}
363 	else
364 		atcnt = 1;
365 
366 	/*
367 	**  See if the NDBM version of the file is out of date with
368 	**  the text version.  If so, go into 'init' mode automatically.
369 	**	This only happens if our effective userid owns the DBM.
370 	**	Note the unpalatable hack to see if the stat succeeded.
371 	*/
372 
373 	modtime = stb.st_mtime;
374 	(void) strcpy(buf, aliasfile);
375 # ifdef NEWDB
376 	(void) strcat(buf, ".db");
377 # else
378 	(void) strcat(buf, ".pag");
379 # endif
380 	stb.st_ino = 0;
381 	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
382 	{
383 		errno = 0;
384 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
385 		{
386 			init = TRUE;
387 			automatic = TRUE;
388 			message(Arpa_Info, "rebuilding alias database");
389 #ifdef LOG
390 			if (LogLevel > 14)
391 				syslog(LOG_INFO, "rebuilding alias database");
392 #endif /* LOG */
393 		}
394 		else
395 		{
396 #ifdef LOG
397 			if (LogLevel > 3)
398 				syslog(LOG_INFO, "alias database out of date");
399 #endif /* LOG */
400 			message(Arpa_Info, "Warning: alias database out of date");
401 		}
402 	}
403 
404 
405 	/*
406 	**  If necessary, load the NDBM file.
407 	**	If running without NDBM, load the symbol table.
408 	*/
409 
410 	if (init)
411 	{
412 #ifdef LOG
413 		if (LogLevel > 7)
414 		{
415 			extern char *username();
416 
417 			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
418 				automatic ? "auto" : "", username());
419 		}
420 #endif /* LOG */
421 		readaliases(aliasfile, TRUE, e);
422 	}
423 # else /* NDBM */
424 	readaliases(aliasfile, init, e);
425 # endif /* NDBM */
426 }
427 /*
428 **  READALIASES -- read and process the alias file.
429 **
430 **	This routine implements the part of initaliases that occurs
431 **	when we are not going to use the DBM stuff.
432 **
433 **	Parameters:
434 **		aliasfile -- the pathname of the alias file master.
435 **		init -- if set, initialize the NDBM stuff.
436 **
437 **	Returns:
438 **		none.
439 **
440 **	Side Effects:
441 **		Reads aliasfile into the symbol table.
442 **		Optionally, builds the .dir & .pag files.
443 */
444 
445 static
446 readaliases(aliasfile, init, e)
447 	char *aliasfile;
448 	bool init;
449 	register ENVELOPE *e;
450 {
451 	register char *p;
452 	char *rhs;
453 	bool skipping;
454 	int naliases, bytes, longest;
455 	FILE *af;
456 	bool makedbmfiles;
457 	void (*oldsigint)();
458 	ADDRESS al, bl;
459 	register STAB *s;
460 # ifdef NEWDB
461 	DB *dbp;
462 # endif
463 # ifdef NDBM
464 	DBM *dbmp;
465 # endif
466 # ifdef LOCKF
467 	struct flock fld;
468 # endif
469 	char line[BUFSIZ];
470 
471 	if ((af = fopen(aliasfile, "r+")) == NULL)
472 	{
473 		if (init)
474 			syserr("Can't open %s", aliasfile);
475 		else if (tTd(27, 1))
476 			printf("Can't open %s\n", aliasfile);
477 		errno = 0;
478 		NoAlias++;
479 		return;
480 	}
481 
482 # if defined(NDBM) || defined(NEWDB)
483 	/* see if someone else is rebuilding the alias file already */
484 # ifdef LOCKF
485 	fld.l_type = F_WRLCK;
486 	fld.l_whence = fld.l_start = fld.l_len = 0;
487 	if (fcntl(fileno(af), F_SETLK, &fld) < 0)
488 # else
489 	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
490 # endif
491 	{
492 		/* yes, they are -- wait until done and then return */
493 		message(Arpa_Info, "Alias file is already being rebuilt");
494 		if (OpMode != MD_INITALIAS)
495 		{
496 			/* wait for other rebuild to complete */
497 # ifdef LOCKF
498 			(void) fcntl(fileno(af), F_SETLKW, &fld);
499 # else
500 			(void) flock(fileno(af), LOCK_EX);
501 # endif
502 		}
503 		(void) fclose(af);
504 		errno = 0;
505 		return;
506 	}
507 # endif /* NDBM */
508 
509 	/*
510 	**  If initializing, create the new DBM files.
511 	*/
512 
513 	if (init)
514 	{
515 		oldsigint = signal(SIGINT, SIG_IGN);
516 # ifdef NEWDB
517 		(void) strcpy(line, aliasfile);
518 		(void) strcat(line, ".db");
519 		dbp = dbopen(line,
520 		    O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
521 		if (dbp == NULL)
522 		{
523 			syserr("readaliases: cannot create %s", line);
524 			(void) signal(SIGINT, oldsigint);
525 			return;
526 		}
527 # endif
528 # ifdef IF_MAKEDBMFILES
529 # ifdef NEWDB
530 		makedbmfiles = access("/var/yp/Makefile", R_OK) == 0;
531 # endif
532 		IF_MAKEDBMFILES
533 		{
534 			dbmp = dbm_open(aliasfile,
535 					       O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
536 			if (dbmp == NULL)
537 			{
538 				syserr("readaliases: cannot create %s.{dir,pag}",
539 					aliasfile);
540 				(void) signal(SIGINT, oldsigint);
541 				return;
542 			}
543 		}
544 # endif
545 	}
546 
547 	/*
548 	**  Read and interpret lines
549 	*/
550 
551 	FileName = aliasfile;
552 	LineNumber = 0;
553 	naliases = bytes = longest = 0;
554 	skipping = FALSE;
555 	while (fgets(line, sizeof (line), af) != NULL)
556 	{
557 		int lhssize, rhssize;
558 
559 		LineNumber++;
560 		p = strchr(line, '\n');
561 		if (p != NULL)
562 			*p = '\0';
563 		switch (line[0])
564 		{
565 		  case '#':
566 		  case '\0':
567 			skipping = FALSE;
568 			continue;
569 
570 		  case ' ':
571 		  case '\t':
572 			if (!skipping)
573 				syserr("Non-continuation line starts with space");
574 			skipping = TRUE;
575 			continue;
576 		}
577 		skipping = FALSE;
578 
579 		/*
580 		**  Process the LHS
581 		**	Find the colon separator, and parse the address.
582 		**	It should resolve to a local name -- this will
583 		**	be checked later (we want to optionally do
584 		**	parsing of the RHS first to maximize error
585 		**	detection).
586 		*/
587 
588 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
589 			continue;
590 		if (*p++ != ':')
591 		{
592 			syserr("missing colon");
593 			continue;
594 		}
595 		if (parseaddr(line, &al, 1, ':', e) == NULL)
596 		{
597 			syserr("illegal alias name");
598 			continue;
599 		}
600 		loweraddr(&al);
601 
602 		/*
603 		**  Process the RHS.
604 		**	'al' is the internal form of the LHS address.
605 		**	'p' points to the text of the RHS.
606 		*/
607 
608 		rhs = p;
609 		for (;;)
610 		{
611 			register char c;
612 
613 			if (init && CheckAliases)
614 			{
615 				/* do parsing & compression of addresses */
616 				while (*p != '\0')
617 				{
618 					extern char *DelimChar;
619 
620 					while ((isascii(*p) && isspace(*p)) ||
621 								*p == ',')
622 						p++;
623 					if (*p == '\0')
624 						break;
625 					if (parseaddr(p, &bl, -1, ',', e) == NULL)
626 						usrerr("%s... bad address", p);
627 					p = DelimChar;
628 				}
629 			}
630 			else
631 			{
632 				p = &p[strlen(p)];
633 				if (p[-1] == '\n')
634 					*--p = '\0';
635 			}
636 
637 			/* see if there should be a continuation line */
638 			c = fgetc(af);
639 			if (!feof(af))
640 				(void) ungetc(c, af);
641 			if (c != ' ' && c != '\t')
642 				break;
643 
644 			/* read continuation line */
645 			if (fgets(p, sizeof line - (p - line), af) == NULL)
646 				break;
647 			LineNumber++;
648 
649 			/* check for line overflow */
650 			if (strchr(p, '\n') == NULL)
651 			{
652 				usrerr("alias too long");
653 				break;
654 			}
655 		}
656 		if (al.q_mailer != LocalMailer)
657 		{
658 			syserr("cannot alias non-local names");
659 			continue;
660 		}
661 
662 		/*
663 		**  Insert alias into symbol table or DBM file
664 		*/
665 
666 		lhssize = strlen(al.q_user) + 1;
667 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
668 			makelower(al.q_user);
669 		rhssize = strlen(rhs) + 1;
670 
671 # if defined(NDBM) || defined(NEWDB)
672 		if (init)
673 		{
674 			DBdatum key, content;
675 			int putstat;
676 
677 			key.xx.size = lhssize;
678 			key.xx.data = al.q_user;
679 			content.xx.size = rhssize;
680 			content.xx.data = rhs;
681 # ifdef NEWDB
682 			putstat = dbp->put(dbp, &key.dbt, &content.dbt,
683 					   R_NOOVERWRITE);
684 			if (putstat > 0)
685 			{
686 				usrerr("050 Warning: duplicate alias name %s",
687 					al.q_user);
688 				putstat = dbp->put(dbp, &key.dbt,
689 						   &content.dbt, 0);
690 			}
691 			if (putstat != 0)
692 				syserr("readaliases: db put (%s)", al.q_user);
693 # endif
694 # ifdef IF_MAKEDBMFILES
695 			IF_MAKEDBMFILES
696 			{
697 				putstat = dbm_store(dbmp, key.dbm, content.dbm,
698 						    DBM_INSERT);
699 				if (putstat > 0)
700 				{
701 					usrerr("050 Warning: duplicate alias name %s",
702 						al.q_user);
703 					putstat = dbm_store(dbmp, key.dbm,
704 							content.dbm, DBM_REPLACE);
705 				}
706 				if (putstat != 0)
707 					syserr("readaliases: dbm store (%s)",
708 						al.q_user);
709 			}
710 # endif
711 			if (al.q_paddr != NULL)
712 				free(al.q_paddr);
713 			if (al.q_host != NULL)
714 				free(al.q_host);
715 			if (al.q_user != NULL)
716 				free(al.q_user);
717 		}
718 		else
719 # endif /* NDBM */
720 		{
721 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
722 			s->s_alias = newstr(rhs);
723 		}
724 
725 		/* statistics */
726 		naliases++;
727 		bytes += lhssize + rhssize;
728 		if (rhssize > longest)
729 			longest = rhssize;
730 	}
731 
732 # if defined(NDBM) || defined(NEWDB)
733 	if (init)
734 	{
735 		/* add the distinquished alias "@" */
736 		DBdatum key;
737 
738 		key.xx.size = 2;
739 		key.xx.data = "@";
740 # ifdef NEWDB
741 		if (dbp->sync(dbp) != 0 ||
742 		    dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 ||
743 		    dbp->close(dbp) != 0)
744 			syserr("readaliases: db close failure");
745 # endif
746 # ifdef IF_MAKEDBMFILES
747 		IF_MAKEDBMFILES
748 		{
749 			if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 ||
750 			    dbm_error(dbmp))
751 				syserr("readaliases: dbm close failure");
752 			dbm_close(dbmp);
753 		}
754 # endif
755 
756 		/* restore the old signal */
757 		(void) signal(SIGINT, oldsigint);
758 	}
759 # endif /* NDBM */
760 
761 	/* closing the alias file drops the lock */
762 	(void) fclose(af);
763 	e->e_to = NULL;
764 	FileName = NULL;
765 	message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
766 			naliases, longest, bytes);
767 # ifdef LOG
768 	if (LogLevel > 7)
769 		syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
770 			naliases, longest, bytes);
771 # endif /* LOG */
772 }
773 /*
774 **  FORWARD -- Try to forward mail
775 **
776 **	This is similar but not identical to aliasing.
777 **
778 **	Parameters:
779 **		user -- the name of the user who's mail we would like
780 **			to forward to.  It must have been verified --
781 **			i.e., the q_home field must have been filled
782 **			in.
783 **		sendq -- a pointer to the head of the send queue to
784 **			put this user's aliases in.
785 **
786 **	Returns:
787 **		none.
788 **
789 **	Side Effects:
790 **		New names are added to send queues.
791 */
792 
793 forward(user, sendq, e)
794 	ADDRESS *user;
795 	ADDRESS **sendq;
796 	register ENVELOPE *e;
797 {
798 	char *pp;
799 	char *ep;
800 	extern bool safefile();
801 
802 	if (tTd(27, 1))
803 		printf("forward(%s)\n", user->q_paddr);
804 
805 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
806 		return;
807 	if (user->q_home == NULL)
808 		syserr("forward: no home");
809 
810 	/* good address -- look for .forward file in home */
811 	define('z', user->q_home, e);
812 	define('u', user->q_user, e);
813 	define('h', user->q_host, e);
814 	if (ForwardPath == NULL)
815 		ForwardPath = newstr("\201z/.forward");
816 
817 	for (pp = ForwardPath; pp != NULL; pp = ep)
818 	{
819 		char buf[MAXPATHLEN+1];
820 
821 		ep = strchr(pp, ':');
822 		if (ep != NULL)
823 			*ep = '\0';
824 		expand(pp, buf, &buf[sizeof buf - 1], e);
825 		if (ep != NULL)
826 			*ep++ = ':';
827 		if (tTd(27, 3))
828 			printf("forward: trying %s\n", buf);
829 		if (include(buf, TRUE, user, sendq, e) == 0)
830 			break;
831 	}
832 }
833