xref: /original-bsd/usr.sbin/sendmail/src/alias.c (revision 2bdcd748)
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 "sendmail.h"
10 # include <signal.h>
11 # include <pwd.h>
12 # ifdef DBM
13 ERROR: DBM is no longer supported -- use NDBM instead.
14 # endif
15 # ifdef NEWDB
16 # include <db.h>
17 # endif
18 # ifdef NDBM
19 # include <ndbm.h>
20 # endif
21 # ifdef NIS_ALIASES
22 # include <rpcsvc/ypclnt.h>
23 # endif
24 
25 #ifndef lint
26 #ifdef NEWDB
27 #ifdef NDBM
28 static char sccsid[] = "@(#)alias.c	6.45 (Berkeley) 05/06/93 (with NEWDB and NDBM)";
29 #else
30 static char sccsid[] = "@(#)alias.c	6.45 (Berkeley) 05/06/93 (with NEWDB)";
31 #endif
32 #else
33 #ifdef NDBM
34 static char sccsid[] = "@(#)alias.c	6.45 (Berkeley) 05/06/93 (with NDBM)";
35 #else
36 static char sccsid[] = "@(#)alias.c	6.45 (Berkeley) 05/06/93 (without NEWDB or NDBM)";
37 #endif
38 #endif
39 #endif /* not lint */
40 /*
41 **  Alias data structures
42 */
43 #define ALIASDB		struct _aliasdb
44 
45 
46 ALIASDB
47 {
48 	ALIASCLASS	*ad_class;	/* class of this database */
49 	char		*ad_name;	/* name of alias file */
50 	char		*ad_domain;	/* name of (NIS) domain */
51 	void		*ad_dbp;	/* ndbm/nis database pointer */
52 #ifdef NEWDB
53 	DB		*ad_ndbp;	/* newdb database pointer */
54 #endif
55 	short		ad_flags;	/* flag bits */
56 };
57 
58 /* bits for ad_flags */
59 #define ADF_VALID	0x0001		/* database initialized */
60 #define ADF_WRITABLE	0x0002		/* open for write */
61 #define ADF_IMPLHASH	0x0004		/* IMPL: underlying hash database */
62 #define ADF_IMPLNDBM	0x0008		/* IMPL: underlying NDBM database */
63 
64 
65 ALIASCLASS
66 {
67 	char	*ac_name;		/* name of alias class */
68 	char	*(*ac_lookup)__P((ALIASDB *, char *, ENVELOPE *));
69 					/* lookup func */
70 	void	(*ac_store)__P((ALIASDB *, char *, char *, ENVELOPE *));
71 					/* database store func */
72 	bool	(*ac_init)__P((ALIASDB *, ENVELOPE *));
73 					/* initialization func */
74 	void	(*ac_rebuild)__P((ALIASDB *, FILE *, int, ENVELOPE *));
75 					/* initialization func */
76 	void	(*ac_close)__P((ALIASDB *, ENVELOPE *));
77 					/* close function */
78 	short	ac_flags;		/* flag bits */
79 };
80 
81 /* bits for ac_flags */
82 #define ACF_BUILDABLE	0x0001		/* can build a cached version */
83 
84 
85 ALIASDB	AliasDB[MAXALIASDB + 1];	/* actual database list */
86 int	NAliasDBs;			/* number of alias databases */
87 /*
88 **  ALIAS -- Compute aliases.
89 **
90 **	Scans the alias file for an alias for the given address.
91 **	If found, it arranges to deliver to the alias list instead.
92 **	Uses libdbm database if -DDBM.
93 **
94 **	Parameters:
95 **		a -- address to alias.
96 **		sendq -- a pointer to the head of the send queue
97 **			to put the aliases in.
98 **		e -- the current envelope.
99 **
100 **	Returns:
101 **		none
102 **
103 **	Side Effects:
104 **		Aliases found are expanded.
105 **
106 **	Deficiencies:
107 **		It should complain about names that are aliased to
108 **			nothing.
109 */
110 
111 alias(a, sendq, e)
112 	register ADDRESS *a;
113 	ADDRESS **sendq;
114 	register ENVELOPE *e;
115 {
116 	register char *p;
117 	int naliases;
118 	char *owner;
119 	char obuf[MAXNAME + 6];
120 	extern char *aliaslookup();
121 
122 	if (tTd(27, 1))
123 		printf("alias(%s)\n", a->q_paddr);
124 
125 	/* don't realias already aliased names */
126 	if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
127 		return;
128 
129 	if (NoAlias)
130 		return;
131 
132 	e->e_to = a->q_paddr;
133 
134 	/*
135 	**  Look up this name
136 	*/
137 
138 	p = aliaslookup(a->q_user, e);
139 	if (p == NULL)
140 		return;
141 
142 	/*
143 	**  Match on Alias.
144 	**	Deliver to the target list.
145 	*/
146 
147 	if (tTd(27, 1))
148 		printf("%s (%s, %s) aliased to %s\n",
149 		    a->q_paddr, a->q_host, a->q_user, p);
150 	if (bitset(EF_VRFYONLY, e->e_flags))
151 	{
152 		a->q_flags |= QVERIFIED;
153 		e->e_nrcpts++;
154 		return;
155 	}
156 	message("aliased to %s", p);
157 #ifdef LOG
158 	if (LogLevel > 9)
159 		syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
160 #endif
161 	a->q_flags &= ~QSELFREF;
162 	AliasLevel++;
163 	naliases = sendtolist(p, a, sendq, e);
164 	AliasLevel--;
165 	if (naliases > 0 && !bitset(QSELFREF, a->q_flags))
166 	{
167 		if (tTd(27, 5))
168 		{
169 			printf("alias: QDONTSEND ");
170 			printaddr(a, FALSE);
171 		}
172 		a->q_flags |= QDONTSEND;
173 	}
174 
175 	/*
176 	**  Look for owner of alias
177 	*/
178 
179 	(void) strcpy(obuf, "owner-");
180 	if (strncmp(a->q_user, "owner-", 6) == 0)
181 		(void) strcat(obuf, "owner");
182 	else
183 		(void) strcat(obuf, a->q_user);
184 	if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
185 		makelower(obuf);
186 	owner = aliaslookup(obuf, e);
187 	if (owner != NULL)
188 	{
189 		if (strchr(owner, ',') != NULL)
190 			owner = obuf;
191 		a->q_owner = newstr(owner);
192 	}
193 }
194 /*
195 **  ALIASLOOKUP -- look up a name in the alias file.
196 **
197 **	Parameters:
198 **		name -- the name to look up.
199 **
200 **	Returns:
201 **		the value of name.
202 **		NULL if unknown.
203 **
204 **	Side Effects:
205 **		none.
206 **
207 **	Warnings:
208 **		The return value will be trashed across calls.
209 */
210 
211 char *
212 aliaslookup(name, e)
213 	char *name;
214 	ENVELOPE *e;
215 {
216 	register int dbno;
217 	register ALIASDB *ad;
218 	register char *p;
219 
220 	for (dbno = 0; dbno < NAliasDBs; dbno++)
221 	{
222 		ad = &AliasDB[dbno];
223 		if (!bitset(ADF_VALID, ad->ad_flags))
224 			continue;
225 		p = (*ad->ad_class->ac_lookup)(ad, name, e);
226 		if (p != NULL)
227 			return p;
228 	}
229 	return NULL;
230 }
231 /*
232 **  SETALIAS -- set up an alias map
233 **
234 **	Called when reading configuration file.
235 **
236 **	Parameters:
237 **		spec -- the alias specification
238 **
239 **	Returns:
240 **		none.
241 */
242 
243 setalias(spec)
244 	char *spec;
245 {
246 	register char *p;
247 	register ALIASDB *ad;
248 	char *class;
249 	STAB *s;
250 
251 	if (tTd(27, 8))
252 		printf("setalias(%s)\n", spec);
253 
254 	for (p = spec; p != NULL; )
255 	{
256 		while (isspace(*p))
257 			p++;
258 		if (*p == NULL)
259 			break;
260 		spec = p;
261 
262 		if (NAliasDBs >= MAXALIASDB)
263 		{
264 			syserr("Too many alias databases defined, %d max", MAXALIASDB);
265 			return;
266 		}
267 		ad = &AliasDB[NAliasDBs];
268 
269 		p = strpbrk(p, " ,/:");
270 		if (p != NULL && *p == ':')
271 		{
272 			/* explicit class listed */
273 			*p++ = '\0';
274 			class = spec;
275 			spec = p;
276 		}
277 		else
278 		{
279 			/* implicit class */
280 			class = "implicit";
281 		}
282 
283 		/* find end of spec */
284 		if (p != NULL)
285 			p = strchr(p, ',');
286 		if (p != NULL)
287 			*p++ = '\0';
288 
289 		/* look up class */
290 		s = stab(class, ST_ALIASCLASS, ST_FIND);
291 		if (s == NULL)
292 		{
293 			if (tTd(27, 1))
294 				printf("Unknown alias class %s\n", class);
295 		}
296 		else
297 		{
298 			ad->ad_class = s->s_aliasclass;
299 			ad->ad_name = newstr(spec);
300 			NAliasDBs++;
301 		}
302 	}
303 }
304 /*
305 **  INITALIASES -- initialize for aliasing
306 **
307 **	Very different depending on whether we are running NDBM or not.
308 **
309 **	Parameters:
310 **		rebuild -- if TRUE, this rebuilds the cached versions.
311 **		e -- current envelope.
312 **
313 **	Returns:
314 **		none.
315 **
316 **	Side Effects:
317 **		initializes aliases:
318 **		if NDBM:  opens the database.
319 **		if ~NDBM: reads the aliases into the symbol table.
320 */
321 
322 # define DBMMODE	0644
323 
324 initaliases(rebuild, e)
325 	bool rebuild;
326 	register ENVELOPE *e;
327 {
328 	int dbno;
329 	register ALIASDB *ad;
330 
331 	for (dbno = 0; dbno < NAliasDBs; dbno++)
332 	{
333 		ad = &AliasDB[dbno];
334 
335 		if (tTd(27, 2))
336 			printf("initaliases(%s:%s)\n",
337 				ad->ad_class->ac_name, ad->ad_name);
338 
339 		if (rebuild)
340 		{
341 			rebuildaliases(ad, FALSE, e);
342 		}
343 		else
344 		{
345 			if (ad->ad_class->ac_init(ad, e))
346 			{
347 				if (tTd(27, 4))
348 					printf("%s:%s: valid\n",
349 						ad->ad_class->ac_name,
350 						ad->ad_name);
351 				ad->ad_flags |= ADF_VALID;
352 			}
353 			else if (tTd(27, 4))
354 				printf("%s:%s: invalid: %s\n",
355 					ad->ad_class->ac_name, ad->ad_name,
356 					errstring(errno));
357 		}
358 	}
359 }
360 /*
361 **  ALIASWAIT -- wait for distinguished @:@ token to appear.
362 **
363 **	This can decide to reopen or rebuild the alias file
364 */
365 
366 aliaswait(ad, ext, e)
367 	ALIASDB *ad;
368 	char *ext;
369 	ENVELOPE *e;
370 {
371 	int atcnt;
372 	time_t mtime;
373 	struct stat stb;
374 	char buf[MAXNAME];
375 
376 	if (tTd(27, 3))
377 		printf("aliaswait\n");
378 
379 	atcnt = SafeAlias * 2;
380 	if (atcnt > 0)
381 	{
382 		while (atcnt-- >= 0 &&
383 		       ad->ad_class->ac_lookup(ad, "@", e) == NULL)
384 		{
385 			/*
386 			**  Close and re-open the alias database in case
387 			**  the one is mv'ed instead of cp'ed in.
388 			*/
389 
390 			if (tTd(27, 2))
391 				printf("aliaswait: sleeping\n");
392 
393 			ad->ad_class->ac_close(ad, e);
394 			sleep(30);
395 			ad->ad_class->ac_init(ad, e);
396 		}
397 	}
398 
399 	/* see if we need to go into auto-rebuild mode */
400 	if (stat(ad->ad_name, &stb) < 0)
401 		return;
402 	mtime = stb.st_mtime;
403 	(void) strcpy(buf, ad->ad_name);
404 	(void) strcat(buf, ext);
405 	if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0)
406 	{
407 		/* database is out of date */
408 		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
409 		{
410 			message("auto-rebuilding alias database %s",
411 				ad->ad_name);
412 			rebuildaliases(ad, TRUE, e);
413 		}
414 		else
415 		{
416 #ifdef LOG
417 			if (LogLevel > 3)
418 				syslog(LOG_INFO, "alias database %s out of date",
419 					ad->ad_name);
420 #endif /* LOG */
421 			message("Warning: alias database %s out of date",
422 				ad->ad_name);
423 		}
424 	}
425 }
426 /*
427 **  REBUILDALIASES -- rebuild the alias database.
428 **
429 **	Parameters:
430 **		ad -- the database to rebuild.
431 **		automatic -- set if this was automatically generated.
432 **		e -- current envelope.
433 **
434 **	Returns:
435 **		none.
436 **
437 **	Side Effects:
438 **		Reads the text version of the database, builds the
439 **		DBM or DB version.
440 */
441 
442 rebuildaliases(ad, automatic, e)
443 	register ALIASDB *ad;
444 	bool automatic;
445 	register ENVELOPE *e;
446 {
447 	FILE *af;
448 	void (*oldsigint)();
449 
450 	if (!bitset(ACF_BUILDABLE, ad->ad_class->ac_flags))
451 		return;
452 
453 #ifdef LOG
454 	if (LogLevel > 7)
455 	{
456 		extern char *username();
457 
458 		syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
459 			ad->ad_name, automatic ? "auto" : "", username());
460 	}
461 #endif /* LOG */
462 
463 	/* try to lock the source file */
464 	if ((af = fopen(ad->ad_name, "r+")) == NULL)
465 	{
466 		if (tTd(27, 1))
467 			printf("Can't open %s: %s\n",
468 				ad->ad_name, errstring(errno));
469 		ad->ad_flags &= ~ADF_VALID;
470 		errno = 0;
471 		return;
472 	}
473 
474 	/* see if someone else is rebuilding the alias file */
475 	if (!lockfile(fileno(af), ad->ad_name, LOCK_EX|LOCK_NB))
476 	{
477 		/* yes, they are -- wait until done */
478 		message("Alias file %s is already being rebuilt",
479 			ad->ad_name);
480 		if (OpMode != MD_INITALIAS)
481 		{
482 			/* wait for other rebuild to complete */
483 			(void) lockfile(fileno(af), ad->ad_name,
484 					LOCK_EX);
485 		}
486 		(void) fclose(af);
487 		errno = 0;
488 		return;
489 	}
490 
491 	oldsigint = signal(SIGINT, SIG_IGN);
492 
493 	ad->ad_class->ac_rebuild(ad, af, automatic, e);
494 
495 	/* close the file, thus releasing locks */
496 	fclose(af);
497 
498 	/* add distinguished entries and close the database */
499 	if (bitset(ADF_VALID, ad->ad_flags))
500 		ad->ad_class->ac_close(ad, e);
501 
502 	/* restore the old signal */
503 	(void) signal(SIGINT, oldsigint);
504 }
505 /*
506 **  READALIASES -- read and process the alias file.
507 **
508 **	This routine implements the part of initaliases that occurs
509 **	when we are not going to use the DBM stuff.
510 **
511 **	Parameters:
512 **		ad -- the alias database descriptor.
513 **		af -- file to read the aliases from.
514 **		automatic -- set if this was an automatic rebuild.
515 **		e -- the current alias file.
516 **
517 **	Returns:
518 **		none.
519 **
520 **	Side Effects:
521 **		Reads aliasfile into the symbol table.
522 **		Optionally, builds the .dir & .pag files.
523 */
524 
525 static
526 readaliases(ad, af, automatic, e)
527 	register ALIASDB *ad;
528 	FILE *af;
529 	int automatic;
530 	register ENVELOPE *e;
531 {
532 	register char *p;
533 	char *rhs;
534 	bool skipping;
535 	long naliases, bytes, longest;
536 	ADDRESS al, bl;
537 	register STAB *s;
538 	char line[BUFSIZ];
539 
540 	/*
541 	**  Read and interpret lines
542 	*/
543 
544 	FileName = ad->ad_name;
545 	LineNumber = 0;
546 	naliases = bytes = longest = 0;
547 	skipping = FALSE;
548 	while (fgets(line, sizeof (line), af) != NULL)
549 	{
550 		int lhssize, rhssize;
551 
552 		LineNumber++;
553 		p = strchr(line, '\n');
554 		if (p != NULL)
555 			*p = '\0';
556 		switch (line[0])
557 		{
558 		  case '#':
559 		  case '\0':
560 			skipping = FALSE;
561 			continue;
562 
563 		  case ' ':
564 		  case '\t':
565 			if (!skipping)
566 				syserr("554 Non-continuation line starts with space");
567 			skipping = TRUE;
568 			continue;
569 		}
570 		skipping = FALSE;
571 
572 		/*
573 		**  Process the LHS
574 		**	Find the colon separator, and parse the address.
575 		**	It should resolve to a local name -- this will
576 		**	be checked later (we want to optionally do
577 		**	parsing of the RHS first to maximize error
578 		**	detection).
579 		*/
580 
581 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
582 			continue;
583 		if (*p++ != ':')
584 		{
585 			syserr("554 missing colon");
586 			continue;
587 		}
588 		if (parseaddr(line, &al, 1, ':', NULL, e) == NULL)
589 		{
590 			syserr("554 illegal alias name");
591 			continue;
592 		}
593 
594 		/*
595 		**  Process the RHS.
596 		**	'al' is the internal form of the LHS address.
597 		**	'p' points to the text of the RHS.
598 		*/
599 
600 		while (isascii(*p) && isspace(*p))
601 			p++;
602 		rhs = p;
603 		for (;;)
604 		{
605 			register char c;
606 			register char *nlp;
607 
608 			nlp = &p[strlen(p)];
609 			if (nlp[-1] == '\n')
610 				*--nlp = '\0';
611 
612 			if (CheckAliases)
613 			{
614 				/* do parsing & compression of addresses */
615 				while (*p != '\0')
616 				{
617 					auto char *delimptr;
618 
619 					while ((isascii(*p) && isspace(*p)) ||
620 								*p == ',')
621 						p++;
622 					if (*p == '\0')
623 						break;
624 					if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL)
625 						usrerr("553 %s... bad address", p);
626 					p = delimptr;
627 				}
628 			}
629 			else
630 			{
631 				p = nlp;
632 			}
633 
634 			/* see if there should be a continuation line */
635 			c = fgetc(af);
636 			if (!feof(af))
637 				(void) ungetc(c, af);
638 			if (c != ' ' && c != '\t')
639 				break;
640 
641 			/* read continuation line */
642 			if (fgets(p, sizeof line - (p - line), af) == NULL)
643 				break;
644 			LineNumber++;
645 
646 			/* check for line overflow */
647 			if (strchr(p, '\n') == NULL)
648 			{
649 				usrerr("554 alias too long");
650 				break;
651 			}
652 		}
653 		if (al.q_mailer != LocalMailer)
654 		{
655 			syserr("554 cannot alias non-local names");
656 			continue;
657 		}
658 
659 		/*
660 		**  Insert alias into symbol table or DBM file
661 		*/
662 
663 		if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
664 			makelower(al.q_user);
665 
666 		lhssize = strlen(al.q_user);
667 		rhssize = strlen(rhs);
668 		ad->ad_class->ac_store(ad, al.q_user, rhs, e);
669 
670 		if (al.q_paddr != NULL)
671 			free(al.q_paddr);
672 		if (al.q_host != NULL)
673 			free(al.q_host);
674 		if (al.q_user != NULL)
675 			free(al.q_user);
676 
677 		/* statistics */
678 		naliases++;
679 		bytes += lhssize + rhssize;
680 		if (rhssize > longest)
681 			longest = rhssize;
682 	}
683 
684 	e->e_to = NULL;
685 	FileName = NULL;
686 	if (Verbose || !automatic)
687 		message("%s: %d aliases, longest %d bytes, %d bytes total",
688 			ad->ad_name, naliases, longest, bytes);
689 # ifdef LOG
690 	if (LogLevel > 7)
691 		syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
692 			ad->ad_name, naliases, longest, bytes);
693 # endif /* LOG */
694 }
695 /*
696 **  NDBM modules
697 */
698 
699 #ifdef NDBM
700 
701 /*
702 **  NDBM_ALOOKUP -- look up alias in ndbm file
703 */
704 
705 char *
706 ndbm_alookup(ad, name, e)
707 	register ALIASDB *ad;
708 	char *name;
709 	ENVELOPE *e;
710 {
711 	int i;
712 	datum rhs, lhs;
713 	char keybuf[MAXNAME + 1];
714 
715 	if (tTd(27, 20))
716 		printf("ndbm_lookup(%s)\n", name);
717 
718 	/* create a key for fetch */
719 	i = strlen(name) + 1;
720 	if (i > sizeof keybuf)
721 		i = sizeof keybuf;
722 	bcopy(name, keybuf, i);
723 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
724 		makelower(keybuf);
725 
726 	lhs.dsize = i;
727 	lhs.dptr = keybuf;
728 	rhs = dbm_fetch((DBM *) ad->ad_dbp, lhs);
729 	return (rhs.dptr);
730 }
731 
732 
733 /*
734 **  NDBM_ASTORE -- store a datum in the database
735 */
736 
737 void
738 ndbm_astore(ad, lhs, rhs, e)
739 	register ALIASDB *ad;
740 	char *lhs;
741 	char *rhs;
742 	ENVELOPE *e;
743 {
744 	datum key;
745 	datum data;
746 	int stat;
747 
748 	key.dsize = strlen(lhs) + 1;
749 	key.dptr = lhs;
750 
751 	data.dsize = strlen(rhs) + 1;
752 	data.dptr = rhs;
753 
754 	stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_INSERT);
755 	if (stat > 0)
756 	{
757 		usrerr("050 Warning: duplicate alias name %s", lhs);
758 		stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_REPLACE);
759 	}
760 	if (stat != 0)
761 		syserr("readaliases: dbm put (%s)", lhs);
762 }
763 
764 
765 /*
766 **  NDBM_AINIT -- initialize DBM database
767 */
768 
769 bool
770 ndbm_ainit(ad, e)
771 	register ALIASDB *ad;
772 	ENVELOPE *e;
773 {
774 	char buf[MAXNAME];
775 
776 	if (tTd(27, 2))
777 		printf("ndbm_ainit(%s)\n", ad->ad_name);
778 
779 	/* open the database */
780 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDONLY, DBMMODE);
781 	if (ad->ad_dbp == NULL)
782 		return FALSE;
783 
784 	/* wait for @:@ to appear */
785 	aliaswait(ad, ".pag", e);
786 
787 	return TRUE;
788 }
789 
790 
791 /*
792 **  NDBM_AREBUILD -- rebuild hash database
793 */
794 
795 void
796 ndbm_arebuild(ad, fp, automatic, e)
797 	register ALIASDB *ad;
798 	FILE *fp;
799 	int automatic;
800 	ENVELOPE *e;
801 {
802 	register DBM *db;
803 	int i;
804 	char buf[MAXNAME];
805 
806 	if (tTd(27, 2))
807 		printf("ndbm_arebuild(%s)\n", ad->ad_name);
808 
809 	db = dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
810 	if (db == NULL)
811 	{
812 		syserr("ndbm_arebuild: cannot create %s", buf);
813 		return;
814 	}
815 	ad->ad_dbp = (void *) db;
816 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
817 
818 	/* read and store the aliases */
819 	readaliases(ad, fp, automatic, e);
820 }
821 
822 /*
823 **  NDBM_ACLOSE -- close the database
824 */
825 
826 void
827 ndbm_aclose(ad, e)
828 	register ALIASDB  *ad;
829 	ENVELOPE *e;
830 {
831 	if (bitset(ADF_WRITABLE, ad->ad_flags))
832 	{
833 #ifdef YPCOMPAT
834 		char buf[200];
835 
836 		(void) sprintf(buf, "%010ld", curtime());
837 		ndbm_astore(ad, "YP_LAST_MODIFIED", buf, e);
838 
839 		(void) myhostname(buf, sizeof buf);
840 		ndbm_astore(ad, "YP_MASTER_NAME", buf, e);
841 #endif
842 
843 		/* write out the distinguished alias */
844 		ndbm_astore(ad, "@", "@", e);
845 	}
846 	dbm_close((DBM *) ad->ad_dbp);
847 }
848 
849 #endif
850 /*
851 **  HASH (NEWDB) Modules
852 */
853 
854 #ifdef NEWDB
855 
856 /*
857 **  HASH_ALOOKUP -- look up alias in hash file
858 */
859 
860 char *
861 hash_alookup(ad, name, e)
862 	register ALIASDB *ad;
863 	char *name;
864 	ENVELOPE *e;
865 {
866 	int i;
867 	DBT rhs, lhs;
868 	int s;
869 	char keybuf[MAXNAME + 1];
870 
871 	if (tTd(27, 20))
872 		printf("hash_alookup(%s)\n", name);
873 
874 	/* create a key for fetch */
875 	i = strlen(name) + 1;
876 	if (i > sizeof keybuf)
877 		i = sizeof keybuf;
878 	bcopy(name, keybuf, i);
879 	if (!bitnset(M_USR_UPPER, LocalMailer->m_flags))
880 		makelower(keybuf);
881 
882 	lhs.size = i;
883 	lhs.data = keybuf;
884 	i = ad->ad_ndbp->get(ad->ad_ndbp, &lhs, &rhs, 0);
885 	if (i == 0)
886 		return (rhs.data);
887 	return (NULL);
888 }
889 
890 
891 /*
892 **  HASH_ASTORE -- store a datum in the database
893 */
894 
895 void
896 hash_astore(ad, lhs, rhs, e)
897 	register ALIASDB *ad;
898 	char *lhs;
899 	char *rhs;
900 	ENVELOPE *e;
901 {
902 	int stat;
903 	DBT key;
904 	DBT data;
905 
906 	if (tTd(27, 20))
907 		printf("hash_astore(%s, %s)\n", lhs, rhs);
908 
909 	key.size = strlen(lhs) + 1;
910 	key.data = lhs;
911 
912 	data.size = strlen(rhs) + 1;
913 	data.data = rhs;
914 
915 	stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, R_NOOVERWRITE);
916 	if (stat > 0)
917 	{
918 		usrerr("050 Warning: duplicate alias name %s", lhs);
919 		stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, 0);
920 	}
921 	if (stat != 0)
922 		syserr("readaliases: db put (%s)", lhs);
923 }
924 
925 
926 /*
927 **  HASH_AINIT -- initialize hash database
928 */
929 
930 bool
931 hash_ainit(ad, e)
932 	register ALIASDB *ad;
933 	ENVELOPE *e;
934 {
935 	char buf[MAXNAME];
936 
937 	if (tTd(27, 2))
938 		printf("hash_ainit(%s)\n", ad->ad_name);
939 
940 	/* open the database */
941 	(void) strcpy(buf, ad->ad_name);
942 	(void) strcat(buf, ".db");
943 	ad->ad_ndbp = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL);
944 	if (ad->ad_ndbp == NULL)
945 		return FALSE;
946 
947 	/* wait for @:@ to appear */
948 	aliaswait(ad, ".db", e);
949 	return TRUE;
950 }
951 
952 
953 /*
954 **  HASH_AREBUILD -- rebuild hash database
955 */
956 
957 void
958 hash_arebuild(ad, fp, automatic, e)
959 	register ALIASDB *ad;
960 	FILE *fp;
961 	int automatic;
962 	ENVELOPE *e;
963 {
964 	register DB *db;
965 	char buf[MAXNAME];
966 
967 	if (tTd(27, 2))
968 		printf("hash_arebuild(%s)\n", ad->ad_name);
969 
970 	(void) strcpy(buf, ad->ad_name);
971 	(void) strcat(buf, ".db");
972 	db = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
973 	if (db == NULL)
974 	{
975 		syserr("hash_arebuild: cannot create %s", buf);
976 		return;
977 	}
978 	ad->ad_ndbp = db;
979 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
980 
981 	/* read and store the aliases */
982 	readaliases(ad, fp, automatic, e);
983 }
984 
985 
986 /*
987 **  HASH_ACLOSE -- add distinguished entries and close the database
988 */
989 
990 void
991 hash_aclose(ad, e)
992 	ALIASDB *ad;
993 	ENVELOPE *e;
994 {
995 	if (tTd(27, 9))
996 		printf("hash_aclose(%x)\n", ad->ad_flags);
997 
998 	if (bitset(ADF_WRITABLE, ad->ad_flags))
999 	{
1000 		/* write out the distinguished alias */
1001 		hash_astore(ad, "@", "@", e);
1002 	}
1003 
1004 	if (ad->ad_ndbp->close(ad->ad_ndbp) != 0)
1005 		syserr("readaliases: db close failure");
1006 }
1007 
1008 #endif
1009 /*
1010 **  STAB (Symbol Table) Modules
1011 */
1012 
1013 
1014 /*
1015 **  STAB_ALOOKUP -- look up alias in symbol table
1016 */
1017 
1018 char *
1019 stab_alookup(ad, name, e)
1020 	register ALIASDB *ad;
1021 	char *name;
1022 	ENVELOPE *e;
1023 {
1024 	register STAB *s;
1025 
1026 	if (tTd(27, 20))
1027 		printf("stab_lookup(%s)\n", name);
1028 
1029 	s = stab(name, ST_ALIAS, ST_FIND);
1030 	if (s != NULL)
1031 		return (s->s_alias);
1032 	return (NULL);
1033 }
1034 
1035 
1036 /*
1037 **  STAB_ASTORE -- store in symtab (actually using during init, not rebuild)
1038 */
1039 
1040 void
1041 stab_astore(ad, lhs, rhs, e)
1042 	register ALIASDB *ad;
1043 	char *lhs;
1044 	char *rhs;
1045 	ENVELOPE *e;
1046 {
1047 	register STAB *s;
1048 
1049 	s = stab(lhs, ST_ALIAS, ST_ENTER);
1050 	s->s_alias = newstr(rhs);
1051 }
1052 
1053 
1054 /*
1055 **  STAB_AINIT -- initialize (reads data file)
1056 */
1057 
1058 bool
1059 stab_ainit(ad, e)
1060 	register ALIASDB *ad;
1061 	ENVELOPE *e;
1062 {
1063 	FILE *af;
1064 
1065 	if (tTd(27, 2))
1066 		printf("stab_ainit(%s)\n", ad->ad_name);
1067 
1068 	af = fopen(ad->ad_name, "r");
1069 	if (af == NULL)
1070 		return FALSE;
1071 
1072 	readaliases(ad, af, TRUE, e);
1073 }
1074 
1075 
1076 /*
1077 **  STAB_AREBUILD -- rebuild alias file
1078 */
1079 
1080 void
1081 stab_arebuild(ad, fp, automatic, e)
1082 	ALIASDB *ad;
1083 	FILE *fp;
1084 	int automatic;
1085 	ENVELOPE *e;
1086 {
1087 	if (tTd(27, 2))
1088 		printf("stab_arebuild(%s)\n", ad->ad_name);
1089 
1090 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
1091 }
1092 
1093 
1094 /*
1095 **  STAB_ACLOSE -- close symbol table (???)
1096 */
1097 
1098 void
1099 stab_aclose(ad, e)
1100 	ALIASDB *ad;
1101 	ENVELOPE *e;
1102 {
1103 	/* ignore it */
1104 }
1105 /*
1106 **  NIS Modules
1107 */
1108 
1109 #ifdef NIS_ALIASES
1110 
1111 /*
1112 **  NIS_ALOOKUP
1113 */
1114 
1115 char *
1116 nis_alookup(ad, name, e)
1117 	ALIASDB *ad;
1118 	char *name;
1119 	ENVELOPE *e;
1120 {
1121 	auto char *vp;
1122 	auto int vsize;
1123 	int yperr;
1124 	int keylen;
1125 
1126 	if (tTd(27, 20))
1127 		printf("nis_lookup(%s)\n", name);
1128 
1129 	keylen = strlen(name);
1130 	yperr = yp_match(ad->ad_domain, ad->ad_name, name, keylen,
1131 			&vp, &vsize);
1132 	if (yperr == YPERR_KEY)
1133 		yperr = yp_match(ad->ad_domain, ad->ad_name, name, ++keylen,
1134 				&vp, &vsize);
1135 	if (yperr == 0)
1136 		return vp;
1137 
1138 	if (tTd(27, 10))
1139 		printf("nis_alookup: yp_match(%s, %s, %s) => %s\n",
1140 			ad->ad_domain, ad->ad_name, name, yperr_string(yperr));
1141 	if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
1142 		ad->ad_flags &= ~ADF_VALID;
1143 	return NULL;
1144 }
1145 
1146 /*
1147 **  NIS_ASTORE
1148 */
1149 
1150 void
1151 nis_astore(ad, lhs, rhs, e)
1152 	ALIASDB *ad;
1153 	char *lhs;
1154 	char *rhs;
1155 	ENVELOPE *e;
1156 {
1157 	/* nothing */
1158 }
1159 
1160 /*
1161 **  NIS_AINIT
1162 */
1163 
1164 bool
1165 nis_ainit(ad, e)
1166 	ALIASDB *ad;
1167 	ENVELOPE *e;
1168 {
1169 	register char *p;
1170 	int yperr;
1171 	auto char *vp;
1172 	auto int vsize;
1173 
1174 	if (tTd(27, 2))
1175 		printf("nis_ainit(%s)\n", ad->ad_name);
1176 
1177 	p = strchr(ad->ad_name, '@');
1178 	if (p != NULL)
1179 	{
1180 		*p++ = '\0';
1181 		if (*p != '\0')
1182 			ad->ad_domain = p;
1183 	}
1184 	if (ad->ad_domain == NULL)
1185 		yp_get_default_domain(&ad->ad_domain);
1186 
1187 	if (*ad->ad_name == '\0')
1188 		ad->ad_name = "mail.aliases";
1189 
1190 	yperr = yp_match(ad->ad_domain, ad->ad_name, "@", 1,
1191 			&vp, &vsize);
1192 	if (tTd(27, 10))
1193 		printf("nis_ainit: yp_match(%s, %s) => %s\n",
1194 			ad->ad_domain, ad->ad_name, yperr_string(yperr));
1195 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
1196 		return TRUE;
1197 	return FALSE;
1198 }
1199 
1200 /*
1201 **  NIS_AREBUILD
1202 */
1203 
1204 void
1205 nis_arebuild(ad, fp, automatic, e)
1206 	ALIASDB *ad;
1207 	FILE *fp;
1208 	int automatic;
1209 	ENVELOPE *e;
1210 {
1211 	if (tTd(27, 2))
1212 		printf("nis_arebuild(%s)\n", ad->ad_name);
1213 }
1214 
1215 
1216 /*
1217 **  NIS_ACLOSE
1218 */
1219 
1220 void
1221 nis_aclose(ad, e)
1222 	ALIASDB *ad;
1223 	ENVELOPE *e;
1224 {
1225 	/* nothing */
1226 }
1227 
1228 #endif /* NIS_ALIASES */
1229 /*
1230 **  Implicit Modules
1231 **
1232 **	Tries several types.  For back compatibility.
1233 */
1234 
1235 /*
1236 **  IMPL_ALOOKUP -- lookup in best open database
1237 */
1238 
1239 char *
1240 impl_alookup(ad, name, e)
1241 	ALIASDB *ad;
1242 	char *name;
1243 	ENVELOPE *e;
1244 {
1245 	if (tTd(27, 20))
1246 		printf("impl_lookup(%s)\n", name);
1247 
1248 #ifdef NEWDB
1249 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
1250 		return hash_alookup(ad, name, e);
1251 #endif
1252 #ifdef NDBM
1253 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
1254 		return ndbm_alookup(ad, name, e);
1255 #endif
1256 	return stab_alookup(ad, name, e);
1257 }
1258 
1259 /*
1260 **  IMPL_ASTORE -- store in open databases
1261 */
1262 
1263 void
1264 impl_astore(ad, lhs, rhs, e)
1265 	ALIASDB *ad;
1266 	char *lhs;
1267 	char *rhs;
1268 	ENVELOPE *e;
1269 {
1270 #ifdef NEWDB
1271 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
1272 		hash_astore(ad, lhs, rhs, e);
1273 #endif
1274 #ifdef NDBM
1275 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
1276 		ndbm_astore(ad, lhs, rhs, e);
1277 #endif
1278 	stab_astore(ad, lhs, rhs, e);
1279 }
1280 
1281 /*
1282 **  IMPL_AINIT -- implicit database lookup
1283 */
1284 
1285 bool
1286 impl_ainit(ad, e)
1287 	ALIASDB *ad;
1288 	ENVELOPE *e;
1289 {
1290 	struct stat stb;
1291 
1292 	if (tTd(27, 2))
1293 		printf("impl_ainit(%s)\n", ad->ad_name);
1294 
1295 	if (stat(ad->ad_name, &stb) < 0)
1296 	{
1297 		/* no alias file at all */
1298 		return FALSE;
1299 	}
1300 
1301 #ifdef NEWDB
1302 	ad->ad_flags |= ADF_IMPLHASH;
1303 	if (hash_ainit(ad, e))
1304 	{
1305 		return TRUE;
1306 	}
1307 	ad->ad_flags &= ~ADF_IMPLHASH;
1308 #endif
1309 #ifdef NDBM
1310 	ad->ad_flags |= ADF_IMPLNDBM;
1311 	if (ndbm_ainit(ad, e))
1312 	{
1313 		return TRUE;
1314 	}
1315 	ad->ad_flags &= ~ADF_IMPLNDBM;
1316 #endif
1317 
1318 	if (Verbose)
1319 		message("WARNING: cannot open alias database %s", ad->ad_name);
1320 
1321 	if (stab_ainit(ad, e))
1322 	{
1323 		return TRUE;
1324 	}
1325 
1326 	return FALSE;
1327 }
1328 
1329 /*
1330 **  IMPL_AREBUILD -- rebuild alias database
1331 */
1332 
1333 void
1334 impl_arebuild(ad, fp, automatic, e)
1335 	ALIASDB *ad;
1336 	FILE *fp;
1337 	int automatic;
1338 	ENVELOPE *e;
1339 {
1340 #ifdef NEWDB
1341 	DB *ndb;
1342 	char buf[MAXNAME];
1343 #endif
1344 
1345 	if (tTd(27, 2))
1346 		printf("impl_arebuild(%s)\n", ad->ad_name);
1347 
1348 #ifdef NEWDB
1349 	(void) strcpy(buf, ad->ad_name);
1350 	(void) strcat(buf, ".db");
1351 	ndb = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL);
1352 	if (ndb == NULL)
1353 	{
1354 		syserr("rebuildaliases: cannot create %s", buf);
1355 	}
1356 	else
1357 	{
1358 		ad->ad_ndbp = ndb;
1359 		ad->ad_flags |= ADF_IMPLHASH;
1360 #if defined(NDBM) && defined(YPCOMPAT)
1361 		if (access("/var/yp/Makefile", R_OK) != 0)
1362 #endif
1363 			goto readem;
1364 	}
1365 #endif
1366 
1367 #ifdef NDBM
1368 	ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE);
1369 	if (ad->ad_dbp == NULL)
1370 	{
1371 		syserr("rebuildaliases: cannot create %s.{pag,dir}",
1372 			ad->ad_name);
1373 	}
1374 	else
1375 	{
1376 		ad->ad_flags |= ADF_IMPLNDBM;
1377 	}
1378 #endif
1379 
1380 	if (!bitset(ADF_IMPLHASH|ADF_IMPLNDBM, ad->ad_flags))
1381 		return;
1382 
1383   readem:
1384 	ad->ad_flags |= ADF_WRITABLE|ADF_VALID;
1385 
1386 	/* read and store aliases */
1387 	readaliases(ad, fp, automatic, e);
1388 }
1389 
1390 
1391 /*
1392 **  IMPL_ACLOSE -- close any open database(s)
1393 */
1394 
1395 void
1396 impl_aclose(ad, e)
1397 	ALIASDB *ad;
1398 	ENVELOPE *e;
1399 {
1400 #ifdef NEWDB
1401 	if (bitset(ADF_IMPLHASH, ad->ad_flags))
1402 		hash_aclose(ad, e);
1403 #endif
1404 
1405 #ifdef NDBM
1406 	if (bitset(ADF_IMPLNDBM, ad->ad_flags))
1407 		ndbm_aclose(ad, e);
1408 #endif
1409 }
1410 /*
1411 **  SETUPALIASES -- set up aliases classes
1412 */
1413 
1414 #ifdef NEWDB
1415 ALIASCLASS	HashAClass =
1416 {
1417 	"hash",		hash_alookup,	hash_astore,
1418 	hash_ainit,	hash_arebuild,	hash_aclose,
1419 	ACF_BUILDABLE
1420 };
1421 #endif
1422 
1423 #ifdef NDBM
1424 ALIASCLASS	DbmAClass =
1425 {
1426 	"dbm",		ndbm_alookup,	ndbm_astore,
1427 	ndbm_ainit,	ndbm_arebuild,	ndbm_aclose,
1428 	ACF_BUILDABLE
1429 };
1430 #endif
1431 
1432 #ifdef NIS_ALIASES
1433 ALIASCLASS	NisAClass =
1434 {
1435 	"nis",		nis_alookup,	nis_astore,
1436 	nis_ainit,	nis_arebuild,	nis_aclose,
1437 	0
1438 };
1439 #endif
1440 
1441 ALIASCLASS	StabAClass =
1442 {
1443 	"stab",		stab_alookup,	stab_astore,
1444 	stab_ainit,	stab_arebuild,	stab_aclose,
1445 	0
1446 };
1447 
1448 ALIASCLASS	ImplAClass =
1449 {
1450 	"implicit",	impl_alookup,	impl_astore,
1451 	impl_ainit,	impl_arebuild,	impl_aclose,
1452 	ACF_BUILDABLE
1453 };
1454 
1455 setupaliases()
1456 {
1457 	register STAB *s;
1458 
1459 #ifdef NEWDB
1460 	s = stab("hash", ST_ALIASCLASS, ST_ENTER);
1461 	s->s_aliasclass = &HashAClass;
1462 #endif
1463 
1464 #ifdef NDBM
1465 	s = stab("dbm", ST_ALIASCLASS, ST_ENTER);
1466 	s->s_aliasclass = &DbmAClass;
1467 #endif
1468 
1469 #ifdef NIS_ALIASES
1470 	s = stab("nis", ST_ALIASCLASS, ST_ENTER);
1471 	s->s_aliasclass = &NisAClass;
1472 #endif
1473 
1474 #if !defined(NEWDB) && !defined(NDBM)
1475 	s = stab("stab", ST_ALIASCLASS, ST_ENTER);
1476 	s->s_aliasclass = &StabAClass;
1477 #endif
1478 
1479 	s = stab("implicit", ST_ALIASCLASS, ST_ENTER);
1480 	s->s_aliasclass = &ImplAClass;
1481 }
1482 /*
1483 **  FORWARD -- Try to forward mail
1484 **
1485 **	This is similar but not identical to aliasing.
1486 **
1487 **	Parameters:
1488 **		user -- the name of the user who's mail we would like
1489 **			to forward to.  It must have been verified --
1490 **			i.e., the q_home field must have been filled
1491 **			in.
1492 **		sendq -- a pointer to the head of the send queue to
1493 **			put this user's aliases in.
1494 **
1495 **	Returns:
1496 **		none.
1497 **
1498 **	Side Effects:
1499 **		New names are added to send queues.
1500 */
1501 
1502 forward(user, sendq, e)
1503 	ADDRESS *user;
1504 	ADDRESS **sendq;
1505 	register ENVELOPE *e;
1506 {
1507 	char *pp;
1508 	char *ep;
1509 
1510 	if (tTd(27, 1))
1511 		printf("forward(%s)\n", user->q_paddr);
1512 
1513 	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
1514 		return;
1515 	if (user->q_home == NULL)
1516 	{
1517 		syserr("554 forward: no home");
1518 		user->q_home = "/nosuchdirectory";
1519 	}
1520 
1521 	/* good address -- look for .forward file in home */
1522 	define('z', user->q_home, e);
1523 	define('u', user->q_user, e);
1524 	define('h', user->q_host, e);
1525 	if (ForwardPath == NULL)
1526 		ForwardPath = newstr("\201z/.forward");
1527 
1528 	for (pp = ForwardPath; pp != NULL; pp = ep)
1529 	{
1530 		int err;
1531 		char buf[MAXPATHLEN+1];
1532 
1533 		ep = strchr(pp, ':');
1534 		if (ep != NULL)
1535 			*ep = '\0';
1536 		expand(pp, buf, &buf[sizeof buf - 1], e);
1537 		if (ep != NULL)
1538 			*ep++ = ':';
1539 		if (tTd(27, 3))
1540 			printf("forward: trying %s\n", buf);
1541 		err = include(buf, TRUE, user, sendq, e);
1542 		if (err == 0)
1543 			break;
1544 		if (transienterror(err))
1545 		{
1546 			/* we have to suspend this message */
1547 			if (tTd(27, 2))
1548 				printf("forward: transient error on %s\n", buf);
1549 #ifdef LOG
1550 			if (LogLevel > 2)
1551 				syslog(LOG_ERR, "%s: forward %s: transient error: %s",
1552 					e->e_id, buf, errstring(err));
1553 #endif
1554 			message("%s: %s: message queued", buf, errstring(err));
1555 			user->q_flags |= QQUEUEUP|QDONTSEND;
1556 			return;
1557 		}
1558 	}
1559 }
1560