xref: /original-bsd/usr.sbin/sendmail/src/map.c (revision f673f637)
1 /*
2  * Copyright (c) 1992 Eric P. Allman.
3  * Copyright (c) 1992 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)map.c	6.20 (Berkeley) 05/25/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 	for (;;)
87 	{
88 		while (isascii(*p) && isspace(*p))
89 			p++;
90 		if (*p != '-')
91 			break;
92 		switch (*++p)
93 		{
94 		  case 'N':
95 			map->map_mflags |= MF_INCLNULL;
96 			break;
97 
98 		  case 'o':
99 			map->map_mflags |= MF_OPTIONAL;
100 			break;
101 
102 		  case 'f':
103 			map->map_mflags |= MF_NOFOLDCASE;
104 			break;
105 
106 		  case 'm':
107 			map->map_mflags |= MF_MATCHONLY;
108 			break;
109 
110 		  case 'a':
111 			map->map_app = ++p;
112 			break;
113 		}
114 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
115 			p++;
116 		if (*p != '\0')
117 			*p++ = '\0';
118 	}
119 	if (map->map_app != NULL)
120 		map->map_app = newstr(map->map_app);
121 
122 	if (*p != '\0')
123 	{
124 		map->map_file = p;
125 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
126 			p++;
127 		if (*p != '\0')
128 			*p++ = '\0';
129 		map->map_file = newstr(map->map_file);
130 	}
131 
132 	while (*p != '\0' && isascii(*p) && isspace(*p))
133 		p++;
134 	if (*p != '\0')
135 		map->map_rebuild = newstr(p);
136 
137 	if (map->map_file == NULL)
138 	{
139 		syserr("No file name for %s map %s",
140 			map->map_class->map_cname, map->map_mname);
141 		return FALSE;
142 	}
143 	return TRUE;
144 }
145 /*
146 **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
147 **
148 **	It also adds the map_app string.  It can be used as a utility
149 **	in the map_lookup method.
150 **
151 **	Parameters:
152 **		map -- the map that causes this.
153 **		s -- the string to rewrite, NOT necessarily null terminated.
154 **		slen -- the length of s.
155 **		av -- arguments to interpolate into buf.
156 **
157 **	Returns:
158 **		Pointer to rewritten result.
159 **
160 **	Side Effects:
161 **		none.
162 */
163 
164 char *
165 map_rewrite(map, s, slen, av)
166 	register MAP *map;
167 	register char *s;
168 	int slen;
169 	char **av;
170 {
171 	register char *bp;
172 	register char c;
173 	char **avp;
174 	register char *ap;
175 	int i;
176 	int len;
177 	static int buflen = -1;
178 	static char *buf = NULL;
179 
180 	if (tTd(23, 1))
181 	{
182 		printf("map_rewrite(%.*s), av =", slen, s);
183 		if (av == NULL)
184 			printf(" (nullv)");
185 		else
186 		{
187 			for (avp = av; *avp != NULL; avp++)
188 				printf("\n\t%s", *avp);
189 		}
190 		printf("\n");
191 	}
192 
193 	/* count expected size of output (can safely overestimate) */
194 	i = len = slen;
195 	if (av != NULL)
196 	{
197 		bp = s;
198 		for (i = slen; --i >= 0 && (c = *bp++) != 0; )
199 		{
200 			if (c != '%')
201 				continue;
202 			if (--i < 0)
203 				break;
204 			c = *bp++;
205 			if (!(isascii(c) && isdigit(c)))
206 				continue;
207 			c -= 0;
208 			for (avp = av; --c >= 0 && *avp != NULL; avp++)
209 				continue;
210 			if (*avp == NULL)
211 				continue;
212 			len += strlen(*avp);
213 		}
214 	}
215 	if (map->map_app != NULL)
216 		len += strlen(map->map_app);
217 	if (buflen < ++len)
218 	{
219 		/* need to malloc additional space */
220 		buflen = len;
221 		if (buf != NULL)
222 			free(buf);
223 		buf = xalloc(buflen);
224 	}
225 
226 	bp = buf;
227 	if (av == NULL)
228 	{
229 		bcopy(s, bp, slen);
230 		bp += slen;
231 	}
232 	else
233 	{
234 		while (--slen >= 0 && (c = *s++) != '\0')
235 		{
236 			if (c != '%')
237 			{
238   pushc:
239 				*bp++ = c;
240 				continue;
241 			}
242 			if (--slen < 0 || (c = *s++) == '\0')
243 				c = '%';
244 			if (c == '%')
245 				goto pushc;
246 			if (!(isascii(c) && isdigit(c)))
247 			{
248 				*bp++ = '%';
249 				goto pushc;
250 			}
251 			c -= '0';
252 			for (avp = av; --c >= 0 && *avp != NULL; avp++)
253 				continue;
254 			if (*avp == NULL)
255 				continue;
256 
257 			/* transliterate argument into output string */
258 			for (ap = *avp; (c = *ap++) != '\0'; )
259 				*bp++ = c;
260 		}
261 	}
262 	if (map->map_app != NULL)
263 		strcpy(bp, map->map_app);
264 	else
265 		*bp = '\0';
266 	if (tTd(23, 1))
267 		printf("map_rewrite => %s\n", buf);
268 	return buf;
269 }
270 /*
271 **  NDBM modules
272 */
273 
274 #ifdef NDBM
275 
276 /*
277 **  DBM_MAP_OPEN -- DBM-style map open
278 */
279 
280 bool
281 ndbm_map_open(map, mode)
282 	MAP *map;
283 	int mode;
284 {
285 	DBM *dbm;
286 
287 	if (tTd(27, 2))
288 		printf("ndbm_map_open(%s, %d)\n", map->map_file, mode);
289 
290 	if (mode == O_RDWR)
291 		mode |= O_CREAT|O_TRUNC;
292 
293 	/* open the database */
294 	dbm = dbm_open(map->map_file, mode, DBMMODE);
295 	if (dbm == NULL)
296 	{
297 		if (!bitset(MF_OPTIONAL, map->map_mflags))
298 			syserr("Cannot open DBM database %s", map->map_file);
299 		return FALSE;
300 	}
301 	map->map_db1 = (void *) dbm;
302 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
303 		aliaswait(map, ".dir");
304 	return TRUE;
305 }
306 
307 
308 /*
309 **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
310 */
311 
312 char *
313 ndbm_map_lookup(map, name, av, statp)
314 	MAP *map;
315 	char *name;
316 	char **av;
317 	int *statp;
318 {
319 	datum key, val;
320 	char keybuf[MAXNAME + 1];
321 
322 	if (tTd(27, 20))
323 		printf("ndbm_map_lookup(%s)\n", name);
324 
325 	key.dptr = name;
326 	key.dsize = strlen(name);
327 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
328 	{
329 		if (key.dsize > sizeof keybuf - 1)
330 			key.dsize = sizeof keybuf - 1;
331 		bcopy(key.dptr, keybuf, key.dsize + 1);
332 		makelower(keybuf);
333 		key.dptr = keybuf;
334 	}
335 	if (bitset(MF_INCLNULL, map->map_mflags))
336 		key.dsize++;
337 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_SH);
338 	val = dbm_fetch((DBM *) map->map_db1, key);
339 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_UN);
340 	if (val.dptr == NULL)
341 		return NULL;
342 	if (bitset(MF_MATCHONLY, map->map_mflags))
343 		av = NULL;
344 	return map_rewrite(map, val.dptr, val.dsize, av);
345 }
346 
347 
348 /*
349 **  DBM_MAP_STORE -- store a datum in the database
350 */
351 
352 void
353 ndbm_map_store(map, lhs, rhs)
354 	register MAP *map;
355 	char *lhs;
356 	char *rhs;
357 {
358 	datum key;
359 	datum data;
360 	int stat;
361 
362 	if (tTd(27, 12))
363 		printf("ndbm_map_store(%s, %s)\n", lhs, rhs);
364 
365 	key.dsize = strlen(lhs);
366 	key.dptr = lhs;
367 
368 	data.dsize = strlen(rhs);
369 	data.dptr = rhs;
370 
371 	if (bitset(MF_INCLNULL, map->map_mflags))
372 	{
373 		key.dsize++;
374 		data.dsize++;
375 	}
376 
377 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
378 	if (stat > 0)
379 	{
380 		usrerr("050 Warning: duplicate alias name %s", lhs);
381 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
382 	}
383 	if (stat != 0)
384 		syserr("readaliases: dbm put (%s)", lhs);
385 }
386 
387 
388 /*
389 **  NDBM_MAP_CLOSE -- close the database
390 */
391 
392 void
393 ndbm_map_close(map)
394 	register MAP  *map;
395 {
396 	if (bitset(MF_WRITABLE, map->map_mflags))
397 	{
398 #ifdef YPCOMPAT
399 		char buf[200];
400 
401 		(void) sprintf(buf, "%010ld", curtime());
402 		ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
403 
404 		(void) myhostname(buf, sizeof buf);
405 		ndbm_map_store(map, "YP_MASTER_NAME", buf);
406 #endif
407 
408 		/* write out the distinguished alias */
409 		ndbm_map_store(map, "@", "@");
410 	}
411 	dbm_close((DBM *) map->map_db1);
412 }
413 
414 #endif
415 /*
416 **  HASH (NEWDB) Modules
417 */
418 
419 #ifdef NEWDB
420 
421 /*
422 **  BTREE_MAP_PARSE -- BTREE-style map initialization
423 */
424 
425 bool
426 bt_map_open(map, mode)
427 	MAP *map;
428 	int mode;
429 {
430 	DB *db;
431 	int i;
432 	char buf[MAXNAME];
433 
434 	if (tTd(27, 2))
435 		printf("bt_map_open(%s, %d)\n", map->map_file, mode);
436 
437 	if (mode == O_RDWR)
438 		mode |= O_CREAT|O_TRUNC;
439 
440 	(void) strcpy(buf, map->map_file);
441 	i = strlen(buf);
442 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
443 		(void) strcat(buf, ".db");
444 	db = dbopen(buf, mode, DBMMODE, DB_BTREE, NULL);
445 	if (db == NULL)
446 	{
447 		if (!bitset(MF_OPTIONAL, map->map_mflags))
448 			syserr("Cannot open BTREE database %s", map->map_file);
449 		return FALSE;
450 	}
451 	map->map_db2 = (void *) db;
452 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
453 		aliaswait(map, ".db");
454 	return TRUE;
455 }
456 
457 
458 /*
459 **  HASH_MAP_INIT -- HASH-style map initialization
460 */
461 
462 bool
463 hash_map_open(map, mode)
464 	MAP *map;
465 	int mode;
466 {
467 	DB *db;
468 	int i;
469 	char buf[MAXNAME];
470 
471 	if (tTd(27, 2))
472 		printf("hash_map_open(%s, %d)\n", map->map_file, mode);
473 
474 	if (mode == O_RDWR)
475 		mode |= O_CREAT|O_TRUNC;
476 
477 	(void) strcpy(buf, map->map_file);
478 	i = strlen(buf);
479 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
480 		(void) strcat(buf, ".db");
481 	db = dbopen(buf, mode, DBMMODE, DB_HASH, NULL);
482 	if (db == NULL)
483 	{
484 		if (!bitset(MF_OPTIONAL, map->map_mflags))
485 			syserr("Cannot open HASH database %s", map->map_file);
486 		return FALSE;
487 	}
488 	map->map_db2 = (void *) db;
489 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
490 		aliaswait(map, ".db");
491 	return TRUE;
492 }
493 
494 
495 /*
496 **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
497 */
498 
499 char *
500 db_map_lookup(map, name, av, statp)
501 	MAP *map;
502 	char *name;
503 	char **av;
504 	int *statp;
505 {
506 	DBT key, val;
507 	register DB *db = (DB *) map->map_db2;
508 	int st;
509 	int saveerrno;
510 	char keybuf[MAXNAME + 1];
511 
512 	if (tTd(27, 20))
513 		printf("db_map_lookup(%s)\n", name);
514 
515 	key.size = strlen(name);
516 	if (key.size > sizeof keybuf - 1)
517 		key.size = sizeof keybuf - 1;
518 	key.data = keybuf;
519 	bcopy(name, keybuf, key.size + 1);
520 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
521 		makelower(keybuf);
522 	if (bitset(MF_INCLNULL, map->map_mflags))
523 		key.size++;
524 #ifndef OLD_NEWDB
525 	(void) lockfile(db->fd(db), map->map_file, LOCK_SH);
526 #endif
527 	st = db->get(db, &key, &val, 0);
528 	saveerrno = errno;
529 #ifndef OLD_NEWDB
530 	(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
531 #endif
532 	if (st != 0)
533 	{
534 		errno = saveerrno;
535 		if (st < 0)
536 			syserr("db_map_lookup: get (%s)", name);
537 		return NULL;
538 	}
539 	if (bitset(MF_MATCHONLY, map->map_mflags))
540 		av = NULL;
541 	return map_rewrite(map, val.data, val.size, av);
542 }
543 
544 
545 /*
546 **  DB_MAP_STORE -- store a datum in the NEWDB database
547 */
548 
549 void
550 db_map_store(map, lhs, rhs)
551 	register MAP *map;
552 	char *lhs;
553 	char *rhs;
554 {
555 	int stat;
556 	DBT key;
557 	DBT data;
558 	register DB *db = map->map_db2;
559 
560 	if (tTd(27, 20))
561 		printf("db_map_store(%s, %s)\n", lhs, rhs);
562 
563 	key.size = strlen(lhs);
564 	key.data = lhs;
565 
566 	data.size = strlen(rhs);
567 	data.data = rhs;
568 
569 	if (bitset(MF_INCLNULL, map->map_mflags))
570 	{
571 		key.size++;
572 		data.size++;
573 	}
574 
575 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
576 	if (stat > 0)
577 	{
578 		usrerr("050 Warning: duplicate alias name %s", lhs);
579 		stat = db->put(db, &key, &data, 0);
580 	}
581 	if (stat != 0)
582 		syserr("readaliases: db put (%s)", lhs);
583 }
584 
585 
586 /*
587 **  DB_MAP_CLOSE -- add distinguished entries and close the database
588 */
589 
590 void
591 db_map_close(map)
592 	MAP *map;
593 {
594 	register DB *db = map->map_db2;
595 
596 	if (tTd(27, 9))
597 		printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
598 
599 	if (bitset(MF_WRITABLE, map->map_mflags))
600 	{
601 		/* write out the distinguished alias */
602 		db_map_store(map, "@", "@");
603 	}
604 
605 	if (db->close(db) != 0)
606 		syserr("readaliases: db close failure");
607 }
608 
609 #endif
610 /*
611 **  NIS Modules
612 */
613 
614 # ifdef NIS
615 
616 /*
617 **  NIS_MAP_OPEN -- open DBM map
618 */
619 
620 bool
621 nis_map_open(map, mode)
622 	MAP *map;
623 	int mode;
624 {
625 	int yperr;
626 	register char *p;
627 	auto char *vp;
628 	auto int vsize;
629 	char *master;
630 
631 	if (tTd(27, 2))
632 		printf("nis_map_open(%s)\n", map->map_file);
633 
634 	if (mode != O_RDONLY)
635 	{
636 		errno = ENODEV;
637 		return FALSE;
638 	}
639 
640 	p = strchr(map->map_file, '@');
641 	if (p != NULL)
642 	{
643 		*p++ = '\0';
644 		if (*p != '\0')
645 			map->map_domain = p;
646 	}
647 
648 	if (map->map_domain == NULL)
649 		yp_get_default_domain(&map->map_domain);
650 
651 	if (*map->map_file == '\0')
652 		map->map_file = "mail.aliases";
653 
654 	/* check to see if this map actually exists */
655 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
656 			&vp, &vsize);
657 	if (tTd(27, 10))
658 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
659 			map->map_domain, map->map_file, yperr_string(yperr));
660 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
661 		return TRUE;
662 
663 	if (!bitset(MF_OPTIONAL, map->map_mflags))
664 		syserr("Cannot bind to domain %s: %s", map->map_domain,
665 			yperr_string(yperr));
666 
667 	return FALSE;
668 }
669 
670 
671 /*
672 **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
673 */
674 
675 char *
676 nis_map_lookup(map, name, av, statp)
677 	MAP *map;
678 	char *name;
679 	char **av;
680 	int *statp;
681 {
682 	char *vp;
683 	auto int vsize;
684 	int buflen;
685 	int yperr;
686 	char keybuf[MAXNAME + 1];
687 
688 	if (tTd(27, 20))
689 		printf("nis_map_lookup(%s)\n", name);
690 
691 	buflen = strlen(name);
692 	if (buflen > sizeof keybuf - 1)
693 		buflen = sizeof keybuf - 1;
694 	bcopy(name, keybuf, buflen + 1);
695 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
696 		makelower(keybuf);
697 	if (bitset(MF_INCLNULL, map->map_mflags))
698 		buflen++;
699 	yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
700 		     &vp, &vsize);
701 	if (yperr != 0)
702 	{
703 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
704 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
705 		return NULL;
706 	}
707 	if (bitset(MF_MATCHONLY, map->map_mflags))
708 		av = NULL;
709 	return map_rewrite(map, vp, vsize, av);
710 }
711 
712 
713 /*
714 **  NIS_MAP_STORE
715 */
716 
717 void
718 nis_map_store(map, lhs, rhs)
719 	MAP *map;
720 	char *lhs;
721 	char *rhs;
722 {
723 	/* nothing */
724 }
725 
726 
727 /*
728 **  NIS_MAP_CLOSE
729 */
730 
731 void
732 nis_map_close(map)
733 	MAP *map;
734 {
735 	/* nothing */
736 }
737 
738 #endif /* NIS */
739 /*
740 **  STAB (Symbol Table) Modules
741 */
742 
743 
744 /*
745 **  STAB_MAP_LOOKUP -- look up alias in symbol table
746 */
747 
748 char *
749 stab_map_lookup(map, name)
750 	register MAP *map;
751 	char *name;
752 {
753 	register STAB *s;
754 
755 	if (tTd(27, 20))
756 		printf("stab_lookup(%s)\n", name);
757 
758 	s = stab(name, ST_ALIAS, ST_FIND);
759 	if (s != NULL)
760 		return (s->s_alias);
761 	return (NULL);
762 }
763 
764 
765 /*
766 **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
767 */
768 
769 void
770 stab_map_store(map, lhs, rhs)
771 	register MAP *map;
772 	char *lhs;
773 	char *rhs;
774 {
775 	register STAB *s;
776 
777 	s = stab(lhs, ST_ALIAS, ST_ENTER);
778 	s->s_alias = newstr(rhs);
779 }
780 
781 
782 /*
783 **  STAB_MAP_OPEN -- initialize (reads data file)
784 **
785 **	This is a wierd case -- it is only intended as a fallback for
786 **	aliases.  For this reason, opens for write (only during a
787 **	"newaliases") always fails, and opens for read open the
788 **	actual underlying text file instead of the database.
789 */
790 
791 bool
792 stab_map_open(map, mode)
793 	register MAP *map;
794 	int mode;
795 {
796 	FILE *af;
797 
798 	if (tTd(27, 2))
799 		printf("stab_map_open(%s)\n", map->map_file);
800 
801 	if (mode != O_RDONLY)
802 	{
803 		errno = ENODEV;
804 		return FALSE;
805 	}
806 
807 	return TRUE;
808 }
809 
810 
811 /*
812 **  STAB_MAP_CLOSE -- close symbol table (???)
813 */
814 
815 void
816 stab_map_close(map)
817 	MAP *map;
818 {
819 	/* ignore it */
820 }
821 /*
822 **  Implicit Modules
823 **
824 **	Tries several types.  For back compatibility of aliases.
825 */
826 
827 
828 /*
829 **  IMPL_MAP_LOOKUP -- lookup in best open database
830 */
831 
832 char *
833 impl_map_lookup(map, name, av, pstat)
834 	MAP *map;
835 	char *name;
836 	char **av;
837 	int *pstat;
838 {
839 	if (tTd(27, 20))
840 		printf("impl_map_lookup(%s)\n", name);
841 
842 #ifdef NEWDB
843 	if (bitset(MF_IMPL_HASH, map->map_mflags))
844 		return db_map_lookup(map, name, av, pstat);
845 #endif
846 #ifdef NDBM
847 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
848 		return ndbm_map_lookup(map, name, av, pstat);
849 #endif
850 	return stab_map_lookup(map, name, av, pstat);
851 }
852 
853 /*
854 **  IMPL_MAP_STORE -- store in open databases
855 */
856 
857 void
858 impl_map_store(map, lhs, rhs)
859 	MAP *map;
860 	char *lhs;
861 	char *rhs;
862 {
863 #ifdef NEWDB
864 	if (bitset(MF_IMPL_HASH, map->map_mflags))
865 		db_map_store(map, lhs, rhs);
866 #endif
867 #ifdef NDBM
868 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
869 		ndbm_map_store(map, lhs, rhs);
870 #endif
871 	stab_map_store(map, lhs, rhs);
872 }
873 
874 /*
875 **  IMPL_MAP_OPEN -- implicit database open
876 */
877 
878 bool
879 impl_map_open(map, mode)
880 	MAP *map;
881 	int mode;
882 {
883 	struct stat stb;
884 
885 	if (tTd(27, 2))
886 		printf("impl_map_open(%s)\n", map->map_file);
887 
888 	if (stat(map->map_file, &stb) < 0)
889 	{
890 		/* no alias file at all */
891 		return FALSE;
892 	}
893 
894 #ifdef NEWDB
895 	map->map_mflags |= MF_IMPL_HASH;
896 	if (hash_map_open(map, mode))
897 	{
898 #if defined(NDBM) && defined(YPCOMPAT)
899 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) == 0)
900 #endif
901 			return TRUE;
902 	}
903 	else
904 		map->map_mflags &= ~MF_IMPL_HASH;
905 #endif
906 #ifdef NDBM
907 	map->map_mflags |= MF_IMPL_NDBM;
908 	if (ndbm_map_open(map, mode))
909 	{
910 		return TRUE;
911 	}
912 	else
913 		map->map_mflags &= ~MF_IMPL_NDBM;
914 #endif
915 
916 #if !defined(NEWDB) && !defined(NDBM)
917 	if (Verbose)
918 		message("WARNING: cannot open alias database %s", map->map_file);
919 #endif
920 
921 	return stab_map_open(map, mode);
922 }
923 
924 
925 /*
926 **  IMPL_MAP_CLOSE -- close any open database(s)
927 */
928 
929 void
930 impl_map_close(map)
931 	MAP *map;
932 {
933 #ifdef NEWDB
934 	if (bitset(MF_IMPL_HASH, map->map_mflags))
935 	{
936 		db_map_close(map);
937 		map->map_mflags &= ~MF_IMPL_HASH;
938 	}
939 #endif
940 
941 #ifdef NDBM
942 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
943 	{
944 		ndbm_map_close(map);
945 		map->map_mflags &= ~MF_IMPL_NDBM;
946 	}
947 #endif
948 }
949 /*
950 **  NULL stubs
951 */
952 
953 bool
954 null_map_open(map, mode)
955 	MAP *map;
956 	int mode;
957 {
958 	return TRUE;
959 }
960 
961 void
962 null_map_close(map)
963 	MAP *map;
964 {
965 	return;
966 }
967 
968 void
969 null_map_store(map, key, val)
970 	MAP *map;
971 	char *key;
972 	char *val;
973 {
974 	return;
975 }
976