xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 64335)
1 /*
2  * Copyright (c) 1992 Eric P. Allman.
3  * Copyright (c) 1992, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)map.c	8.9 (Berkeley) 08/23/93";
11 #endif /* not lint */
12 
13 #include "sendmail.h"
14 
15 #ifdef NDBM
16 #include <ndbm.h>
17 #endif
18 #ifdef NEWDB
19 #include <db.h>
20 #endif
21 #ifdef NIS
22 #include <rpcsvc/ypclnt.h>
23 #endif
24 
25 /*
26 **  MAP.C -- implementations for various map classes.
27 **
28 **	Each map class implements a series of functions:
29 **
30 **	bool map_parse(MAP *map, char *args)
31 **		Parse the arguments from the config file.  Return TRUE
32 **		if they were ok, FALSE otherwise.  Fill in map with the
33 **		values.
34 **
35 **	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
36 **		Look up the key in the given map.  If found, do any
37 **		rewriting the map wants (including "args" if desired)
38 **		and return the value.  Set *pstat to the appropriate status
39 **		on error and return NULL.  Args will be NULL if called
40 **		from the alias routines, although this should probably
41 **		not be relied upon.  It is suggested you call map_rewrite
42 **		to return the results -- it takes care of null termination
43 **		and uses a dynamically expanded buffer as needed.
44 **
45 **	void map_store(MAP *map, char *key, char *value)
46 **		Store the key:value pair in the map.
47 **
48 **	bool map_open(MAP *map, int mode)
49 **		Open the map for the indicated mode.  Mode should
50 **		be either O_RDONLY or O_RDWR.  Return TRUE if it
51 **		was opened successfully, FALSE otherwise.  If the open
52 **		failed an the MF_OPTIONAL flag is not set, it should
53 **		also print an error.  If the MF_ALIAS bit is set
54 **		and this map class understands the @:@ convention, it
55 **		should call aliaswait() before returning.
56 **
57 **	void map_close(MAP *map)
58 **		Close the map.
59 */
60 
61 #define DBMMODE		0644
62 /*
63 **  MAP_PARSEARGS -- parse config line arguments for database lookup
64 **
65 **	This is a generic version of the map_parse method.
66 **
67 **	Parameters:
68 **		map -- the map being initialized.
69 **		ap -- a pointer to the args on the config line.
70 **
71 **	Returns:
72 **		TRUE -- if everything parsed OK.
73 **		FALSE -- otherwise.
74 **
75 **	Side Effects:
76 **		null terminates the filename; stores it in map
77 */
78 
79 bool
80 map_parseargs(map, ap)
81 	MAP *map;
82 	char *ap;
83 {
84 	register char *p = ap;
85 
86 	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
87 	for (;;)
88 	{
89 		while (isascii(*p) && isspace(*p))
90 			p++;
91 		if (*p != '-')
92 			break;
93 		switch (*++p)
94 		{
95 		  case 'N':
96 			map->map_mflags |= MF_INCLNULL;
97 			map->map_mflags &= ~MF_TRY0NULL;
98 			break;
99 
100 		  case 'O':
101 			map->map_mflags &= ~MF_TRY1NULL;
102 			break;
103 
104 		  case 'o':
105 			map->map_mflags |= MF_OPTIONAL;
106 			break;
107 
108 		  case 'f':
109 			map->map_mflags |= MF_NOFOLDCASE;
110 			break;
111 
112 		  case 'm':
113 			map->map_mflags |= MF_MATCHONLY;
114 			break;
115 
116 		  case 'a':
117 			map->map_app = ++p;
118 			break;
119 		}
120 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
121 			p++;
122 		if (*p != '\0')
123 			*p++ = '\0';
124 	}
125 	if (map->map_app != NULL)
126 		map->map_app = newstr(map->map_app);
127 
128 	if (*p != '\0')
129 	{
130 		map->map_file = p;
131 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
132 			p++;
133 		if (*p != '\0')
134 			*p++ = '\0';
135 		map->map_file = newstr(map->map_file);
136 	}
137 
138 	while (*p != '\0' && isascii(*p) && isspace(*p))
139 		p++;
140 	if (*p != '\0')
141 		map->map_rebuild = newstr(p);
142 
143 	if (map->map_file == NULL)
144 	{
145 		syserr("No file name for %s map %s",
146 			map->map_class->map_cname, map->map_mname);
147 		return FALSE;
148 	}
149 	return TRUE;
150 }
151 /*
152 **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
153 **
154 **	It also adds the map_app string.  It can be used as a utility
155 **	in the map_lookup method.
156 **
157 **	Parameters:
158 **		map -- the map that causes this.
159 **		s -- the string to rewrite, NOT necessarily null terminated.
160 **		slen -- the length of s.
161 **		av -- arguments to interpolate into buf.
162 **
163 **	Returns:
164 **		Pointer to rewritten result.
165 **
166 **	Side Effects:
167 **		none.
168 */
169 
170 struct rwbuf
171 {
172 	int	rwb_len;	/* size of buffer */
173 	char	*rwb_buf;	/* ptr to buffer */
174 };
175 
176 struct rwbuf	RwBufs[2];	/* buffers for rewriting output */
177 
178 char *
179 map_rewrite(map, s, slen, av)
180 	register MAP *map;
181 	register char *s;
182 	int slen;
183 	char **av;
184 {
185 	register char *bp;
186 	register char c;
187 	char **avp;
188 	register char *ap;
189 	register struct rwbuf *rwb;
190 	int i;
191 	int len;
192 
193 	if (tTd(39, 1))
194 	{
195 		printf("map_rewrite(%.*s), av =", slen, s);
196 		if (av == NULL)
197 			printf(" (nullv)");
198 		else
199 		{
200 			for (avp = av; *avp != NULL; avp++)
201 				printf("\n\t%s", *avp);
202 		}
203 		printf("\n");
204 	}
205 
206 	rwb = RwBufs;
207 	if (av == NULL)
208 		rwb++;
209 
210 	/* count expected size of output (can safely overestimate) */
211 	i = len = slen;
212 	if (av != NULL)
213 	{
214 		bp = s;
215 		for (i = slen; --i >= 0 && (c = *bp++) != 0; )
216 		{
217 			if (c != '%')
218 				continue;
219 			if (--i < 0)
220 				break;
221 			c = *bp++;
222 			if (!(isascii(c) && isdigit(c)))
223 				continue;
224 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
225 				continue;
226 			if (*avp == NULL)
227 				continue;
228 			len += strlen(*avp);
229 		}
230 	}
231 	if (map->map_app != NULL)
232 		len += strlen(map->map_app);
233 	if (rwb->rwb_len < ++len)
234 	{
235 		/* need to malloc additional space */
236 		rwb->rwb_len = len;
237 		if (rwb->rwb_buf != NULL)
238 			free(rwb->rwb_buf);
239 		rwb->rwb_buf = xalloc(rwb->rwb_len);
240 	}
241 
242 	bp = rwb->rwb_buf;
243 	if (av == NULL)
244 	{
245 		bcopy(s, bp, slen);
246 		bp += slen;
247 	}
248 	else
249 	{
250 		while (--slen >= 0 && (c = *s++) != '\0')
251 		{
252 			if (c != '%')
253 			{
254   pushc:
255 				*bp++ = c;
256 				continue;
257 			}
258 			if (--slen < 0 || (c = *s++) == '\0')
259 				c = '%';
260 			if (c == '%')
261 				goto pushc;
262 			if (!(isascii(c) && isdigit(c)))
263 			{
264 				*bp++ = '%';
265 				goto pushc;
266 			}
267 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
268 				continue;
269 			if (*avp == NULL)
270 				continue;
271 
272 			/* transliterate argument into output string */
273 			for (ap = *avp; (c = *ap++) != '\0'; )
274 				*bp++ = c;
275 		}
276 	}
277 	if (map->map_app != NULL)
278 		strcpy(bp, map->map_app);
279 	else
280 		*bp = '\0';
281 	if (tTd(39, 1))
282 		printf("map_rewrite => %s\n", rwb->rwb_buf);
283 	return rwb->rwb_buf;
284 }
285 /*
286 **  INITMAPS -- initialize for aliasing
287 **
288 **	Parameters:
289 **		rebuild -- if TRUE, this rebuilds the cached versions.
290 **		e -- current envelope.
291 **
292 **	Returns:
293 **		none.
294 **
295 **	Side Effects:
296 **		initializes aliases:
297 **		if NDBM:  opens the database.
298 **		if ~NDBM: reads the aliases into the symbol table.
299 */
300 
301 initmaps(rebuild, e)
302 	bool rebuild;
303 	register ENVELOPE *e;
304 {
305 	extern void map_init();
306 
307 	CurEnv = e;
308 	stabapply(map_init, rebuild);
309 }
310 
311 void
312 map_init(s, rebuild)
313 	register STAB *s;
314 	int rebuild;
315 {
316 	register MAP *map;
317 
318 	/* has to be a map */
319 	if (s->s_type != ST_MAP)
320 		return;
321 
322 	map = &s->s_map;
323 	if (!bitset(MF_VALID, map->map_mflags))
324 		return;
325 
326 	if (tTd(38, 2))
327 		printf("map_init(%s:%s)\n",
328 			map->map_class->map_cname, map->map_file);
329 
330 	/* if already open, close it (for nested open) */
331 	if (bitset(MF_OPEN, map->map_mflags))
332 	{
333 		map->map_class->map_close(map);
334 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
335 	}
336 
337 	if (rebuild)
338 	{
339 		if (bitset(MF_ALIAS, map->map_mflags) &&
340 		    bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
341 			rebuildaliases(map, FALSE);
342 	}
343 	else
344 	{
345 		if (map->map_class->map_open(map, O_RDONLY))
346 		{
347 			if (tTd(38, 4))
348 				printf("%s:%s: valid\n",
349 					map->map_class->map_cname,
350 					map->map_file);
351 			map->map_mflags |= MF_OPEN;
352 		}
353 		else if (tTd(38, 4))
354 			printf("%s:%s: invalid: %s\n",
355 				map->map_class->map_cname,
356 				map->map_file,
357 				errstring(errno));
358 	}
359 }
360 /*
361 **  NDBM modules
362 */
363 
364 #ifdef NDBM
365 
366 /*
367 **  DBM_MAP_OPEN -- DBM-style map open
368 */
369 
370 bool
371 ndbm_map_open(map, mode)
372 	MAP *map;
373 	int mode;
374 {
375 	register DBM *dbm;
376 	struct stat st;
377 
378 	if (tTd(38, 2))
379 		printf("ndbm_map_open(%s, %d)\n", map->map_file, mode);
380 
381 	if (mode == O_RDWR)
382 		mode |= O_CREAT|O_TRUNC;
383 
384 	/* open the database */
385 	dbm = dbm_open(map->map_file, mode, DBMMODE);
386 	if (dbm == NULL)
387 	{
388 		if (!bitset(MF_OPTIONAL, map->map_mflags))
389 			syserr("Cannot open DBM database %s", map->map_file);
390 		return FALSE;
391 	}
392 	map->map_db1 = (void *) dbm;
393 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
394 		aliaswait(map, ".pag");
395 	if (fstat(dbm_dirfno(dbm), &st) >= 0)
396 		map->map_mtime = st.st_mtime;
397 	return TRUE;
398 }
399 
400 
401 /*
402 **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
403 */
404 
405 char *
406 ndbm_map_lookup(map, name, av, statp)
407 	MAP *map;
408 	char *name;
409 	char **av;
410 	int *statp;
411 {
412 	datum key, val;
413 	char keybuf[MAXNAME + 1];
414 
415 	if (tTd(38, 20))
416 		printf("ndbm_map_lookup(%s)\n", name);
417 
418 	key.dptr = name;
419 	key.dsize = strlen(name);
420 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
421 	{
422 		if (key.dsize > sizeof keybuf - 1)
423 			key.dsize = sizeof keybuf - 1;
424 		bcopy(key.dptr, keybuf, key.dsize + 1);
425 		makelower(keybuf);
426 		key.dptr = keybuf;
427 	}
428 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file,
429 			".dir", LOCK_SH);
430 	val.dptr = NULL;
431 	if (bitset(MF_TRY0NULL, map->map_mflags))
432 	{
433 		val = dbm_fetch((DBM *) map->map_db1, key);
434 		if (val.dptr != NULL)
435 			map->map_mflags &= ~MF_TRY1NULL;
436 	}
437 	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
438 	{
439 		key.dsize++;
440 		val = dbm_fetch((DBM *) map->map_db1, key);
441 		if (val.dptr != NULL)
442 			map->map_mflags &= ~MF_TRY0NULL;
443 	}
444 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file,
445 			".dir", LOCK_UN);
446 	if (val.dptr == NULL)
447 		return NULL;
448 	if (bitset(MF_MATCHONLY, map->map_mflags))
449 		return map_rewrite(map, name, strlen(name), NULL);
450 	else
451 		return map_rewrite(map, val.dptr, val.dsize, av);
452 }
453 
454 
455 /*
456 **  DBM_MAP_STORE -- store a datum in the database
457 */
458 
459 void
460 ndbm_map_store(map, lhs, rhs)
461 	register MAP *map;
462 	char *lhs;
463 	char *rhs;
464 {
465 	datum key;
466 	datum data;
467 	int stat;
468 
469 	if (tTd(38, 12))
470 		printf("ndbm_map_store(%s, %s)\n", lhs, rhs);
471 
472 	key.dsize = strlen(lhs);
473 	key.dptr = lhs;
474 
475 	data.dsize = strlen(rhs);
476 	data.dptr = rhs;
477 
478 	if (bitset(MF_INCLNULL, map->map_mflags))
479 	{
480 		key.dsize++;
481 		data.dsize++;
482 	}
483 
484 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
485 	if (stat > 0)
486 	{
487 		usrerr("050 Warning: duplicate alias name %s", lhs);
488 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
489 	}
490 	if (stat != 0)
491 		syserr("readaliases: dbm put (%s)", lhs);
492 }
493 
494 
495 /*
496 **  NDBM_MAP_CLOSE -- close the database
497 */
498 
499 void
500 ndbm_map_close(map)
501 	register MAP  *map;
502 {
503 	if (bitset(MF_WRITABLE, map->map_mflags))
504 	{
505 #ifdef NIS
506 		bool inclnull;
507 		char buf[200];
508 
509 		inclnull = bitset(MF_INCLNULL, map->map_mflags);
510 		map->map_mflags &= ~MF_INCLNULL;
511 
512 		(void) sprintf(buf, "%010ld", curtime());
513 		ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
514 
515 		(void) myhostname(buf, sizeof buf);
516 		ndbm_map_store(map, "YP_MASTER_NAME", buf);
517 
518 		if (inclnull)
519 			map->map_mflags |= MF_INCLNULL;
520 #endif
521 
522 		/* write out the distinguished alias */
523 		ndbm_map_store(map, "@", "@");
524 	}
525 	dbm_close((DBM *) map->map_db1);
526 }
527 
528 #endif
529 /*
530 **  NEWDB (Hash and BTree) Modules
531 */
532 
533 #ifdef NEWDB
534 
535 /*
536 **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
537 **
538 **	These do rather bizarre locking.  If you can lock on open,
539 **	do that to avoid the condition of opening a database that
540 **	is being rebuilt.  If you don't, we'll try to fake it, but
541 **	there will be a race condition.  If opening for read-only,
542 **	we immediately release the lock to avoid freezing things up.
543 **	We really ought to hold the lock, but guarantee that we won't
544 **	be pokey about it.  That's hard to do.
545 */
546 
547 bool
548 bt_map_open(map, mode)
549 	MAP *map;
550 	int mode;
551 {
552 	DB *db;
553 	int i;
554 	int omode;
555 	struct stat st;
556 	char buf[MAXNAME];
557 
558 	if (tTd(38, 2))
559 		printf("bt_map_open(%s, %d)\n", map->map_file, mode);
560 
561 	omode = mode;
562 	if (omode == O_RDWR)
563 	{
564 		omode |= O_CREAT|O_TRUNC;
565 #if defined(O_EXLOCK) && defined(HASFLOCK)
566 		omode |= O_EXLOCK;
567 # if !defined(OLD_NEWDB)
568 	}
569 	else
570 	{
571 		omode |= O_SHLOCK;
572 # endif
573 #endif
574 	}
575 
576 	(void) strcpy(buf, map->map_file);
577 	i = strlen(buf);
578 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
579 		(void) strcat(buf, ".db");
580 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
581 	if (db == NULL)
582 	{
583 		if (!bitset(MF_OPTIONAL, map->map_mflags))
584 			syserr("Cannot open BTREE database %s", map->map_file);
585 		return FALSE;
586 	}
587 #if !defined(OLD_NEWDB) && defined(HASFLOCK)
588 # if !defined(O_EXLOCK)
589 	if (mode == O_RDWR)
590 		(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_EX);
591 # else
592 	if (mode == O_RDONLY)
593 		(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_UN);
594 # endif
595 #endif
596 
597 	/* try to make sure that at least the database header is on disk */
598 	if (mode == O_RDWR)
599 		(void) db->sync(db, 0);
600 
601 #ifndef OLD_NEWDB
602 	if (fstat(db->fd(db), &st) >= 0)
603 		map->map_mtime = st.st_mtime;
604 #endif
605 
606 	map->map_db2 = (void *) db;
607 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
608 		aliaswait(map, ".db");
609 	return TRUE;
610 }
611 
612 
613 /*
614 **  HASH_MAP_INIT -- HASH-style map initialization
615 */
616 
617 bool
618 hash_map_open(map, mode)
619 	MAP *map;
620 	int mode;
621 {
622 	DB *db;
623 	int i;
624 	int omode;
625 	struct stat st;
626 	char buf[MAXNAME];
627 
628 	if (tTd(38, 2))
629 		printf("hash_map_open(%s, %d)\n", map->map_file, mode);
630 
631 	omode = mode;
632 	if (omode == O_RDWR)
633 	{
634 		omode |= O_CREAT|O_TRUNC;
635 #if defined(O_EXLOCK) && defined(HASFLOCK)
636 		omode |= O_EXLOCK;
637 # if !defined(OLD_NEWDB)
638 	}
639 	else
640 	{
641 		omode |= O_SHLOCK;
642 # endif
643 #endif
644 	}
645 
646 	(void) strcpy(buf, map->map_file);
647 	i = strlen(buf);
648 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
649 		(void) strcat(buf, ".db");
650 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
651 	if (db == NULL)
652 	{
653 		if (!bitset(MF_OPTIONAL, map->map_mflags))
654 			syserr("Cannot open HASH database %s", map->map_file);
655 		return FALSE;
656 	}
657 #if !defined(OLD_NEWDB) && defined(HASFLOCK)
658 # if !defined(O_EXLOCK)
659 	if (mode == O_RDWR)
660 		(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_EX);
661 # else
662 	if (mode == O_RDONLY)
663 		(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_UN);
664 # endif
665 #endif
666 
667 	/* try to make sure that at least the database header is on disk */
668 	if (mode == O_RDWR)
669 		(void) db->sync(db, 0);
670 
671 #ifndef OLD_NEWDB
672 	if (fstat(db->fd(db), &st) >= 0)
673 		map->map_mtime = st.st_mtime;
674 #endif
675 
676 	map->map_db2 = (void *) db;
677 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
678 		aliaswait(map, ".db");
679 	return TRUE;
680 }
681 
682 
683 /*
684 **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
685 */
686 
687 char *
688 db_map_lookup(map, name, av, statp)
689 	MAP *map;
690 	char *name;
691 	char **av;
692 	int *statp;
693 {
694 	DBT key, val;
695 	register DB *db = (DB *) map->map_db2;
696 	int st;
697 	int saveerrno;
698 	char keybuf[MAXNAME + 1];
699 
700 	if (tTd(38, 20))
701 		printf("db_map_lookup(%s)\n", name);
702 
703 	key.size = strlen(name);
704 	if (key.size > sizeof keybuf - 1)
705 		key.size = sizeof keybuf - 1;
706 	key.data = keybuf;
707 	bcopy(name, keybuf, key.size + 1);
708 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
709 		makelower(keybuf);
710 #ifndef OLD_NEWDB
711 	(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH);
712 #endif
713 	st = 1;
714 	if (bitset(MF_TRY0NULL, map->map_mflags))
715 	{
716 		st = db->get(db, &key, &val, 0);
717 		if (st == 0)
718 			map->map_mflags &= ~MF_TRY1NULL;
719 	}
720 	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
721 	{
722 		key.size++;
723 		st = db->get(db, &key, &val, 0);
724 		if (st == 0)
725 			map->map_mflags &= ~MF_TRY0NULL;
726 	}
727 	saveerrno = errno;
728 #ifndef OLD_NEWDB
729 	(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_UN);
730 #endif
731 	if (st != 0)
732 	{
733 		errno = saveerrno;
734 		if (st < 0)
735 			syserr("db_map_lookup: get (%s)", name);
736 		return NULL;
737 	}
738 	if (bitset(MF_MATCHONLY, map->map_mflags))
739 		return map_rewrite(map, name, strlen(name), NULL);
740 	else
741 		return map_rewrite(map, val.data, val.size, av);
742 }
743 
744 
745 /*
746 **  DB_MAP_STORE -- store a datum in the NEWDB database
747 */
748 
749 void
750 db_map_store(map, lhs, rhs)
751 	register MAP *map;
752 	char *lhs;
753 	char *rhs;
754 {
755 	int stat;
756 	DBT key;
757 	DBT data;
758 	register DB *db = map->map_db2;
759 
760 	if (tTd(38, 20))
761 		printf("db_map_store(%s, %s)\n", lhs, rhs);
762 
763 	key.size = strlen(lhs);
764 	key.data = lhs;
765 
766 	data.size = strlen(rhs);
767 	data.data = rhs;
768 
769 	if (bitset(MF_INCLNULL, map->map_mflags))
770 	{
771 		key.size++;
772 		data.size++;
773 	}
774 
775 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
776 	if (stat > 0)
777 	{
778 		usrerr("050 Warning: duplicate alias name %s", lhs);
779 		stat = db->put(db, &key, &data, 0);
780 	}
781 	if (stat != 0)
782 		syserr("readaliases: db put (%s)", lhs);
783 }
784 
785 
786 /*
787 **  DB_MAP_CLOSE -- add distinguished entries and close the database
788 */
789 
790 void
791 db_map_close(map)
792 	MAP *map;
793 {
794 	register DB *db = map->map_db2;
795 
796 	if (tTd(38, 9))
797 		printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
798 
799 	if (bitset(MF_WRITABLE, map->map_mflags))
800 	{
801 		/* write out the distinguished alias */
802 		db_map_store(map, "@", "@");
803 	}
804 
805 	if (db->close(db) != 0)
806 		syserr("readaliases: db close failure");
807 }
808 
809 #endif
810 /*
811 **  NIS Modules
812 */
813 
814 # ifdef NIS
815 
816 /*
817 **  NIS_MAP_OPEN -- open DBM map
818 */
819 
820 bool
821 nis_map_open(map, mode)
822 	MAP *map;
823 	int mode;
824 {
825 	int yperr;
826 	register char *p;
827 	auto char *vp;
828 	auto int vsize;
829 	char *master;
830 
831 	if (tTd(38, 2))
832 		printf("nis_map_open(%s)\n", map->map_file);
833 
834 	if (mode != O_RDONLY)
835 	{
836 		errno = ENODEV;
837 		return FALSE;
838 	}
839 
840 	p = strchr(map->map_file, '@');
841 	if (p != NULL)
842 	{
843 		*p++ = '\0';
844 		if (*p != '\0')
845 			map->map_domain = p;
846 	}
847 
848 	if (map->map_domain == NULL)
849 		yp_get_default_domain(&map->map_domain);
850 
851 	if (*map->map_file == '\0')
852 		map->map_file = "mail.aliases";
853 
854 	/* check to see if this map actually exists */
855 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
856 			&vp, &vsize);
857 	if (tTd(38, 10))
858 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
859 			map->map_domain, map->map_file, yperr_string(yperr));
860 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
861 		return TRUE;
862 
863 	if (!bitset(MF_OPTIONAL, map->map_mflags))
864 		syserr("Cannot bind to domain %s: %s", map->map_domain,
865 			yperr_string(yperr));
866 
867 	return FALSE;
868 }
869 
870 
871 /*
872 **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
873 */
874 
875 char *
876 nis_map_lookup(map, name, av, statp)
877 	MAP *map;
878 	char *name;
879 	char **av;
880 	int *statp;
881 {
882 	char *vp;
883 	auto int vsize;
884 	int buflen;
885 	int yperr;
886 	char keybuf[MAXNAME + 1];
887 
888 	if (tTd(38, 20))
889 		printf("nis_map_lookup(%s)\n", name);
890 
891 	buflen = strlen(name);
892 	if (buflen > sizeof keybuf - 1)
893 		buflen = sizeof keybuf - 1;
894 	bcopy(name, keybuf, buflen + 1);
895 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
896 		makelower(keybuf);
897 	yperr = YPERR_KEY;
898 	if (bitset(MF_TRY0NULL, map->map_mflags))
899 	{
900 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
901 			     &vp, &vsize);
902 		if (yperr == 0)
903 			map->map_mflags &= ~MF_TRY1NULL;
904 	}
905 	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
906 	{
907 		buflen++;
908 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
909 			     &vp, &vsize);
910 		if (yperr == 0)
911 			map->map_mflags &= ~MF_TRY0NULL;
912 	}
913 	if (yperr != 0)
914 	{
915 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
916 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
917 		return NULL;
918 	}
919 	if (bitset(MF_MATCHONLY, map->map_mflags))
920 		return map_rewrite(map, name, strlen(name), NULL);
921 	else
922 		return map_rewrite(map, vp, vsize, av);
923 }
924 
925 
926 /*
927 **  NIS_MAP_STORE
928 */
929 
930 void
931 nis_map_store(map, lhs, rhs)
932 	MAP *map;
933 	char *lhs;
934 	char *rhs;
935 {
936 	/* nothing */
937 }
938 
939 
940 /*
941 **  NIS_MAP_CLOSE
942 */
943 
944 void
945 nis_map_close(map)
946 	MAP *map;
947 {
948 	/* nothing */
949 }
950 
951 #endif /* NIS */
952 /*
953 **  STAB (Symbol Table) Modules
954 */
955 
956 
957 /*
958 **  STAB_MAP_LOOKUP -- look up alias in symbol table
959 */
960 
961 char *
962 stab_map_lookup(map, name, av, pstat)
963 	register MAP *map;
964 	char *name;
965 	char **av;
966 	int *pstat;
967 {
968 	register STAB *s;
969 
970 	if (tTd(38, 20))
971 		printf("stab_lookup(%s)\n", name);
972 
973 	s = stab(name, ST_ALIAS, ST_FIND);
974 	if (s != NULL)
975 		return (s->s_alias);
976 	return (NULL);
977 }
978 
979 
980 /*
981 **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
982 */
983 
984 void
985 stab_map_store(map, lhs, rhs)
986 	register MAP *map;
987 	char *lhs;
988 	char *rhs;
989 {
990 	register STAB *s;
991 
992 	s = stab(lhs, ST_ALIAS, ST_ENTER);
993 	s->s_alias = newstr(rhs);
994 }
995 
996 
997 /*
998 **  STAB_MAP_OPEN -- initialize (reads data file)
999 **
1000 **	This is a wierd case -- it is only intended as a fallback for
1001 **	aliases.  For this reason, opens for write (only during a
1002 **	"newaliases") always fails, and opens for read open the
1003 **	actual underlying text file instead of the database.
1004 */
1005 
1006 bool
1007 stab_map_open(map, mode)
1008 	register MAP *map;
1009 	int mode;
1010 {
1011 	FILE *af;
1012 	struct stat st;
1013 
1014 	if (tTd(38, 2))
1015 		printf("stab_map_open(%s)\n", map->map_file);
1016 
1017 	if (mode != O_RDONLY)
1018 	{
1019 		errno = ENODEV;
1020 		return FALSE;
1021 	}
1022 
1023 	af = fopen(map->map_file, "r");
1024 	if (af == NULL)
1025 		return FALSE;
1026 	readaliases(map, af, TRUE);
1027 
1028 	if (fstat(fileno(af), &st) >= 0)
1029 		map->map_mtime = st.st_mtime;
1030 	fclose(af);
1031 
1032 	return TRUE;
1033 }
1034 
1035 
1036 /*
1037 **  STAB_MAP_CLOSE -- close symbol table (???)
1038 */
1039 
1040 void
1041 stab_map_close(map)
1042 	MAP *map;
1043 {
1044 	/* ignore it */
1045 }
1046 /*
1047 **  Implicit Modules
1048 **
1049 **	Tries several types.  For back compatibility of aliases.
1050 */
1051 
1052 
1053 /*
1054 **  IMPL_MAP_LOOKUP -- lookup in best open database
1055 */
1056 
1057 char *
1058 impl_map_lookup(map, name, av, pstat)
1059 	MAP *map;
1060 	char *name;
1061 	char **av;
1062 	int *pstat;
1063 {
1064 	if (tTd(38, 20))
1065 		printf("impl_map_lookup(%s)\n", name);
1066 
1067 #ifdef NEWDB
1068 	if (bitset(MF_IMPL_HASH, map->map_mflags))
1069 		return db_map_lookup(map, name, av, pstat);
1070 #endif
1071 #ifdef NDBM
1072 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
1073 		return ndbm_map_lookup(map, name, av, pstat);
1074 #endif
1075 	return stab_map_lookup(map, name, av, pstat);
1076 }
1077 
1078 /*
1079 **  IMPL_MAP_STORE -- store in open databases
1080 */
1081 
1082 void
1083 impl_map_store(map, lhs, rhs)
1084 	MAP *map;
1085 	char *lhs;
1086 	char *rhs;
1087 {
1088 #ifdef NEWDB
1089 	if (bitset(MF_IMPL_HASH, map->map_mflags))
1090 		db_map_store(map, lhs, rhs);
1091 #endif
1092 #ifdef NDBM
1093 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
1094 		ndbm_map_store(map, lhs, rhs);
1095 #endif
1096 	stab_map_store(map, lhs, rhs);
1097 }
1098 
1099 /*
1100 **  IMPL_MAP_OPEN -- implicit database open
1101 */
1102 
1103 bool
1104 impl_map_open(map, mode)
1105 	MAP *map;
1106 	int mode;
1107 {
1108 	struct stat stb;
1109 
1110 	if (tTd(38, 2))
1111 		printf("impl_map_open(%s)\n", map->map_file);
1112 
1113 	if (stat(map->map_file, &stb) < 0)
1114 	{
1115 		/* no alias file at all */
1116 		return FALSE;
1117 	}
1118 
1119 #ifdef NEWDB
1120 	map->map_mflags |= MF_IMPL_HASH;
1121 	if (hash_map_open(map, mode))
1122 	{
1123 #if defined(NDBM) && defined(NIS)
1124 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
1125 #endif
1126 			return TRUE;
1127 	}
1128 	else
1129 		map->map_mflags &= ~MF_IMPL_HASH;
1130 #endif
1131 #ifdef NDBM
1132 	map->map_mflags |= MF_IMPL_NDBM;
1133 	if (ndbm_map_open(map, mode))
1134 	{
1135 		return TRUE;
1136 	}
1137 	else
1138 		map->map_mflags &= ~MF_IMPL_NDBM;
1139 #endif
1140 
1141 #if !defined(NEWDB) && !defined(NDBM)
1142 	if (Verbose)
1143 		message("WARNING: cannot open alias database %s", map->map_file);
1144 #endif
1145 
1146 	return stab_map_open(map, mode);
1147 }
1148 
1149 
1150 /*
1151 **  IMPL_MAP_CLOSE -- close any open database(s)
1152 */
1153 
1154 void
1155 impl_map_close(map)
1156 	MAP *map;
1157 {
1158 #ifdef NEWDB
1159 	if (bitset(MF_IMPL_HASH, map->map_mflags))
1160 	{
1161 		db_map_close(map);
1162 		map->map_mflags &= ~MF_IMPL_HASH;
1163 	}
1164 #endif
1165 
1166 #ifdef NDBM
1167 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
1168 	{
1169 		ndbm_map_close(map);
1170 		map->map_mflags &= ~MF_IMPL_NDBM;
1171 	}
1172 #endif
1173 }
1174 /*
1175 **  NULL stubs
1176 */
1177 
1178 bool
1179 null_map_open(map, mode)
1180 	MAP *map;
1181 	int mode;
1182 {
1183 	return TRUE;
1184 }
1185 
1186 void
1187 null_map_close(map)
1188 	MAP *map;
1189 {
1190 	return;
1191 }
1192 
1193 void
1194 null_map_store(map, key, val)
1195 	MAP *map;
1196 	char *key;
1197 	char *val;
1198 {
1199 	return;
1200 }
1201