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