xref: /original-bsd/usr.sbin/sendmail/src/map.c (revision ab6c2785)
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.19 (Berkeley) 05/24/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 	char keybuf[MAXNAME + 1];
508 
509 	if (tTd(27, 20))
510 		printf("db_map_lookup(%s)\n", name);
511 
512 	key.size = strlen(name);
513 	if (key.size > sizeof keybuf - 1)
514 		key.size = sizeof keybuf - 1;
515 	key.data = keybuf;
516 	bcopy(name, keybuf, key.size + 1);
517 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
518 		makelower(keybuf);
519 	if (bitset(MF_INCLNULL, map->map_mflags))
520 		key.size++;
521 	if (((DB *) map->map_db2)->get((DB *) map->map_db2, &key, &val, 0) != 0)
522 		return NULL;
523 	if (bitset(MF_MATCHONLY, map->map_mflags))
524 		av = NULL;
525 	return map_rewrite(map, val.data, val.size, av);
526 }
527 
528 
529 /*
530 **  DB_MAP_STORE -- store a datum in the NEWDB database
531 */
532 
533 void
534 db_map_store(map, lhs, rhs)
535 	register MAP *map;
536 	char *lhs;
537 	char *rhs;
538 {
539 	int stat;
540 	DBT key;
541 	DBT data;
542 	register DB *db = map->map_db2;
543 
544 	if (tTd(27, 20))
545 		printf("db_map_store(%s, %s)\n", lhs, rhs);
546 
547 	key.size = strlen(lhs);
548 	key.data = lhs;
549 
550 	data.size = strlen(rhs);
551 	data.data = rhs;
552 
553 	if (bitset(MF_INCLNULL, map->map_mflags))
554 	{
555 		key.size++;
556 		data.size++;
557 	}
558 
559 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
560 	if (stat > 0)
561 	{
562 		usrerr("050 Warning: duplicate alias name %s", lhs);
563 		stat = db->put(db, &key, &data, 0);
564 	}
565 	if (stat != 0)
566 		syserr("readaliases: db put (%s)", lhs);
567 }
568 
569 
570 /*
571 **  DB_MAP_CLOSE -- add distinguished entries and close the database
572 */
573 
574 void
575 db_map_close(map)
576 	MAP *map;
577 {
578 	register DB *db = map->map_db2;
579 
580 	if (tTd(27, 9))
581 		printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
582 
583 	if (bitset(MF_WRITABLE, map->map_mflags))
584 	{
585 		/* write out the distinguished alias */
586 		db_map_store(map, "@", "@");
587 	}
588 
589 	if (db->close(db) != 0)
590 		syserr("readaliases: db close failure");
591 }
592 
593 #endif
594 /*
595 **  NIS Modules
596 */
597 
598 # ifdef NIS
599 
600 /*
601 **  NIS_MAP_OPEN -- open DBM map
602 */
603 
604 bool
605 nis_map_open(map, mode)
606 	MAP *map;
607 	int mode;
608 {
609 	int yperr;
610 	register char *p;
611 	auto char *vp;
612 	auto int vsize;
613 	char *master;
614 
615 	if (tTd(27, 2))
616 		printf("nis_map_open(%s)\n", map->map_file);
617 
618 	if (mode != O_RDONLY)
619 	{
620 		errno = ENODEV;
621 		return FALSE;
622 	}
623 
624 	p = strchr(map->map_file, '@');
625 	if (p != NULL)
626 	{
627 		*p++ = '\0';
628 		if (*p != '\0')
629 			map->map_domain = p;
630 	}
631 
632 	if (map->map_domain == NULL)
633 		yp_get_default_domain(&map->map_domain);
634 
635 	if (*map->map_file == '\0')
636 		map->map_file = "mail.aliases";
637 
638 	/* check to see if this map actually exists */
639 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
640 			&vp, &vsize);
641 	if (tTd(27, 10))
642 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
643 			map->map_domain, map->map_file, yperr_string(yperr));
644 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
645 		return TRUE;
646 
647 	if (!bitset(MF_OPTIONAL, map->map_mflags))
648 		syserr("Cannot bind to domain %s: %s", map->map_domain,
649 			yperr_string(yperr));
650 
651 	return FALSE;
652 }
653 
654 
655 /*
656 **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
657 */
658 
659 char *
660 nis_map_lookup(map, name, av, statp)
661 	MAP *map;
662 	char *name;
663 	char **av;
664 	int *statp;
665 {
666 	char *vp;
667 	auto int vsize;
668 	int buflen;
669 	int yperr;
670 	char keybuf[MAXNAME + 1];
671 
672 	if (tTd(27, 20))
673 		printf("nis_map_lookup(%s)\n", name);
674 
675 	buflen = strlen(name);
676 	if (buflen > sizeof keybuf - 1)
677 		buflen = sizeof keybuf - 1;
678 	bcopy(name, keybuf, buflen + 1);
679 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
680 		makelower(keybuf);
681 	if (bitset(MF_INCLNULL, map->map_mflags))
682 		buflen++;
683 	yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
684 		     &vp, &vsize);
685 	if (yperr != 0)
686 	{
687 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
688 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
689 		return NULL;
690 	}
691 	if (bitset(MF_MATCHONLY, map->map_mflags))
692 		av = NULL;
693 	return map_rewrite(map, vp, vsize, av);
694 }
695 
696 
697 /*
698 **  NIS_MAP_STORE
699 */
700 
701 void
702 nis_map_store(map, lhs, rhs)
703 	MAP *map;
704 	char *lhs;
705 	char *rhs;
706 {
707 	/* nothing */
708 }
709 
710 
711 /*
712 **  NIS_MAP_CLOSE
713 */
714 
715 void
716 nis_map_close(map)
717 	MAP *map;
718 {
719 	/* nothing */
720 }
721 
722 #endif /* NIS */
723 /*
724 **  STAB (Symbol Table) Modules
725 */
726 
727 
728 /*
729 **  STAB_MAP_LOOKUP -- look up alias in symbol table
730 */
731 
732 char *
733 stab_map_lookup(map, name)
734 	register MAP *map;
735 	char *name;
736 {
737 	register STAB *s;
738 
739 	if (tTd(27, 20))
740 		printf("stab_lookup(%s)\n", name);
741 
742 	s = stab(name, ST_ALIAS, ST_FIND);
743 	if (s != NULL)
744 		return (s->s_alias);
745 	return (NULL);
746 }
747 
748 
749 /*
750 **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
751 */
752 
753 void
754 stab_map_store(map, lhs, rhs)
755 	register MAP *map;
756 	char *lhs;
757 	char *rhs;
758 {
759 	register STAB *s;
760 
761 	s = stab(lhs, ST_ALIAS, ST_ENTER);
762 	s->s_alias = newstr(rhs);
763 }
764 
765 
766 /*
767 **  STAB_MAP_OPEN -- initialize (reads data file)
768 **
769 **	This is a wierd case -- it is only intended as a fallback for
770 **	aliases.  For this reason, opens for write (only during a
771 **	"newaliases") always fails, and opens for read open the
772 **	actual underlying text file instead of the database.
773 */
774 
775 bool
776 stab_map_open(map, mode)
777 	register MAP *map;
778 	int mode;
779 {
780 	FILE *af;
781 
782 	if (tTd(27, 2))
783 		printf("stab_map_open(%s)\n", map->map_file);
784 
785 	if (mode != O_RDONLY)
786 	{
787 		errno = ENODEV;
788 		return FALSE;
789 	}
790 
791 	return TRUE;
792 }
793 
794 
795 /*
796 **  STAB_MAP_CLOSE -- close symbol table (???)
797 */
798 
799 void
800 stab_map_close(map)
801 	MAP *map;
802 {
803 	/* ignore it */
804 }
805 /*
806 **  Implicit Modules
807 **
808 **	Tries several types.  For back compatibility of aliases.
809 */
810 
811 
812 /*
813 **  IMPL_MAP_LOOKUP -- lookup in best open database
814 */
815 
816 char *
817 impl_map_lookup(map, name, av, pstat)
818 	MAP *map;
819 	char *name;
820 	char **av;
821 	int *pstat;
822 {
823 	if (tTd(27, 20))
824 		printf("impl_map_lookup(%s)\n", name);
825 
826 #ifdef NEWDB
827 	if (bitset(MF_IMPL_HASH, map->map_mflags))
828 		return db_map_lookup(map, name, av, pstat);
829 #endif
830 #ifdef NDBM
831 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
832 		return ndbm_map_lookup(map, name, av, pstat);
833 #endif
834 	return stab_map_lookup(map, name, av, pstat);
835 }
836 
837 /*
838 **  IMPL_MAP_STORE -- store in open databases
839 */
840 
841 void
842 impl_map_store(map, lhs, rhs)
843 	MAP *map;
844 	char *lhs;
845 	char *rhs;
846 {
847 #ifdef NEWDB
848 	if (bitset(MF_IMPL_HASH, map->map_mflags))
849 		db_map_store(map, lhs, rhs);
850 #endif
851 #ifdef NDBM
852 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
853 		ndbm_map_store(map, lhs, rhs);
854 #endif
855 	stab_map_store(map, lhs, rhs);
856 }
857 
858 /*
859 **  IMPL_MAP_OPEN -- implicit database open
860 */
861 
862 bool
863 impl_map_open(map, mode)
864 	MAP *map;
865 	int mode;
866 {
867 	struct stat stb;
868 
869 	if (tTd(27, 2))
870 		printf("impl_map_open(%s)\n", map->map_file);
871 
872 	if (stat(map->map_file, &stb) < 0)
873 	{
874 		/* no alias file at all */
875 		return FALSE;
876 	}
877 
878 #ifdef NEWDB
879 	map->map_mflags |= MF_IMPL_HASH;
880 	if (hash_map_open(map, mode))
881 	{
882 #if defined(NDBM) && defined(YPCOMPAT)
883 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) == 0)
884 #endif
885 			return TRUE;
886 	}
887 	else
888 		map->map_mflags &= ~MF_IMPL_HASH;
889 #endif
890 #ifdef NDBM
891 	map->map_mflags |= MF_IMPL_NDBM;
892 	if (ndbm_map_open(map, mode))
893 	{
894 		return TRUE;
895 	}
896 	else
897 		map->map_mflags &= ~MF_IMPL_NDBM;
898 #endif
899 
900 #if !defined(NEWDB) && !defined(NDBM)
901 	if (Verbose)
902 		message("WARNING: cannot open alias database %s", map->map_file);
903 #endif
904 
905 	return stab_map_open(map, mode);
906 }
907 
908 
909 /*
910 **  IMPL_MAP_CLOSE -- close any open database(s)
911 */
912 
913 void
914 impl_map_close(map)
915 	MAP *map;
916 {
917 #ifdef NEWDB
918 	if (bitset(MF_IMPL_HASH, map->map_mflags))
919 	{
920 		db_map_close(map);
921 		map->map_mflags &= ~MF_IMPL_HASH;
922 	}
923 #endif
924 
925 #ifdef NDBM
926 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
927 	{
928 		ndbm_map_close(map);
929 		map->map_mflags &= ~MF_IMPL_NDBM;
930 	}
931 #endif
932 }
933 /*
934 **  NULL stubs
935 */
936 
937 bool
938 null_map_open(map, mode)
939 	MAP *map;
940 	int mode;
941 {
942 	return TRUE;
943 }
944 
945 void
946 null_map_close(map)
947 	MAP *map;
948 {
949 	return;
950 }
951 
952 void
953 null_map_store(map, key, val)
954 	MAP *map;
955 	char *key;
956 	char *val;
957 {
958 	return;
959 }
960