xref: /original-bsd/usr.sbin/sendmail/src/map.c (revision 4f00418d)
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.1 (Berkeley) 06/07/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 struct rwbuf
165 {
166 	int	rwb_len;	/* size of buffer */
167 	char	*rwb_buf;	/* ptr to buffer */
168 };
169 
170 struct rwbuf	RwBufs[2];	/* buffers for rewriting output */
171 
172 char *
173 map_rewrite(map, s, slen, av)
174 	register MAP *map;
175 	register char *s;
176 	int slen;
177 	char **av;
178 {
179 	register char *bp;
180 	register char c;
181 	char **avp;
182 	register char *ap;
183 	register struct rwbuf *rwb;
184 	int i;
185 	int len;
186 
187 	if (tTd(39, 1))
188 	{
189 		printf("map_rewrite(%.*s), av =", slen, s);
190 		if (av == NULL)
191 			printf(" (nullv)");
192 		else
193 		{
194 			for (avp = av; *avp != NULL; avp++)
195 				printf("\n\t%s", *avp);
196 		}
197 		printf("\n");
198 	}
199 
200 	rwb = RwBufs;
201 	if (av == NULL)
202 		rwb++;
203 
204 	/* count expected size of output (can safely overestimate) */
205 	i = len = slen;
206 	if (av != NULL)
207 	{
208 		bp = s;
209 		for (i = slen; --i >= 0 && (c = *bp++) != 0; )
210 		{
211 			if (c != '%')
212 				continue;
213 			if (--i < 0)
214 				break;
215 			c = *bp++;
216 			if (!(isascii(c) && isdigit(c)))
217 				continue;
218 			c -= 0;
219 			for (avp = av; --c >= 0 && *avp != NULL; avp++)
220 				continue;
221 			if (*avp == NULL)
222 				continue;
223 			len += strlen(*avp);
224 		}
225 	}
226 	if (map->map_app != NULL)
227 		len += strlen(map->map_app);
228 	if (rwb->rwb_len < ++len)
229 	{
230 		/* need to malloc additional space */
231 		rwb->rwb_len = len;
232 		if (rwb->rwb_buf != NULL)
233 			free(rwb->rwb_buf);
234 		rwb->rwb_buf = xalloc(rwb->rwb_len);
235 	}
236 
237 	bp = rwb->rwb_buf;
238 	if (av == NULL)
239 	{
240 		bcopy(s, bp, slen);
241 		bp += slen;
242 	}
243 	else
244 	{
245 		while (--slen >= 0 && (c = *s++) != '\0')
246 		{
247 			if (c != '%')
248 			{
249   pushc:
250 				*bp++ = c;
251 				continue;
252 			}
253 			if (--slen < 0 || (c = *s++) == '\0')
254 				c = '%';
255 			if (c == '%')
256 				goto pushc;
257 			if (!(isascii(c) && isdigit(c)))
258 			{
259 				*bp++ = '%';
260 				goto pushc;
261 			}
262 			c -= '0';
263 			for (avp = av; --c >= 0 && *avp != NULL; avp++)
264 				continue;
265 			if (*avp == NULL)
266 				continue;
267 
268 			/* transliterate argument into output string */
269 			for (ap = *avp; (c = *ap++) != '\0'; )
270 				*bp++ = c;
271 		}
272 	}
273 	if (map->map_app != NULL)
274 		strcpy(bp, map->map_app);
275 	else
276 		*bp = '\0';
277 	if (tTd(39, 1))
278 		printf("map_rewrite => %s\n", rwb->rwb_buf);
279 	return rwb->rwb_buf;
280 }
281 /*
282 **  INITMAPS -- initialize for aliasing
283 **
284 **	Parameters:
285 **		rebuild -- if TRUE, this rebuilds the cached versions.
286 **		e -- current envelope.
287 **
288 **	Returns:
289 **		none.
290 **
291 **	Side Effects:
292 **		initializes aliases:
293 **		if NDBM:  opens the database.
294 **		if ~NDBM: reads the aliases into the symbol table.
295 */
296 
297 initmaps(rebuild, e)
298 	bool rebuild;
299 	register ENVELOPE *e;
300 {
301 	extern void map_init();
302 
303 	CurEnv = e;
304 	stabapply(map_init, rebuild);
305 }
306 
307 void
308 map_init(s, rebuild)
309 	register STAB *s;
310 	int rebuild;
311 {
312 	register MAP *map;
313 
314 	/* has to be a map */
315 	if (s->s_type != ST_MAP)
316 		return;
317 
318 	map = &s->s_map;
319 	if (!bitset(MF_VALID, map->map_mflags))
320 		return;
321 
322 	if (tTd(38, 2))
323 		printf("map_init(%s:%s)\n",
324 			map->map_class->map_cname, map->map_file);
325 
326 	/* if already open, close it (for nested open) */
327 	if (bitset(MF_OPEN, map->map_mflags))
328 	{
329 		map->map_class->map_close(map);
330 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
331 	}
332 
333 	if (rebuild)
334 	{
335 		if (bitset(MF_ALIAS, map->map_mflags) &&
336 		    bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
337 			rebuildaliases(map, FALSE);
338 	}
339 	else
340 	{
341 		if (map->map_class->map_open(map, O_RDONLY))
342 		{
343 			if (tTd(38, 4))
344 				printf("%s:%s: valid\n",
345 					map->map_class->map_cname,
346 					map->map_file);
347 			map->map_mflags |= MF_OPEN;
348 		}
349 		else if (tTd(38, 4))
350 			printf("%s:%s: invalid: %s\n",
351 				map->map_class->map_cname,
352 				map->map_file,
353 				errstring(errno));
354 	}
355 }
356 /*
357 **  NDBM modules
358 */
359 
360 #ifdef NDBM
361 
362 /*
363 **  DBM_MAP_OPEN -- DBM-style map open
364 */
365 
366 bool
367 ndbm_map_open(map, mode)
368 	MAP *map;
369 	int mode;
370 {
371 	DBM *dbm;
372 
373 	if (tTd(38, 2))
374 		printf("ndbm_map_open(%s, %d)\n", map->map_file, mode);
375 
376 	if (mode == O_RDWR)
377 		mode |= O_CREAT|O_TRUNC;
378 
379 	/* open the database */
380 	dbm = dbm_open(map->map_file, mode, DBMMODE);
381 	if (dbm == NULL)
382 	{
383 		if (!bitset(MF_OPTIONAL, map->map_mflags))
384 			syserr("Cannot open DBM database %s", map->map_file);
385 		return FALSE;
386 	}
387 	map->map_db1 = (void *) dbm;
388 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
389 		aliaswait(map, ".pag");
390 	return TRUE;
391 }
392 
393 
394 /*
395 **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
396 */
397 
398 char *
399 ndbm_map_lookup(map, name, av, statp)
400 	MAP *map;
401 	char *name;
402 	char **av;
403 	int *statp;
404 {
405 	datum key, val;
406 	char keybuf[MAXNAME + 1];
407 
408 	if (tTd(38, 20))
409 		printf("ndbm_map_lookup(%s)\n", name);
410 
411 	key.dptr = name;
412 	key.dsize = strlen(name);
413 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
414 	{
415 		if (key.dsize > sizeof keybuf - 1)
416 			key.dsize = sizeof keybuf - 1;
417 		bcopy(key.dptr, keybuf, key.dsize + 1);
418 		makelower(keybuf);
419 		key.dptr = keybuf;
420 	}
421 	if (bitset(MF_INCLNULL, map->map_mflags))
422 		key.dsize++;
423 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_SH);
424 	val = dbm_fetch((DBM *) map->map_db1, key);
425 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_UN);
426 	if (val.dptr == NULL)
427 		return NULL;
428 	if (bitset(MF_MATCHONLY, map->map_mflags))
429 		av = NULL;
430 	return map_rewrite(map, val.dptr, val.dsize, av);
431 }
432 
433 
434 /*
435 **  DBM_MAP_STORE -- store a datum in the database
436 */
437 
438 void
439 ndbm_map_store(map, lhs, rhs)
440 	register MAP *map;
441 	char *lhs;
442 	char *rhs;
443 {
444 	datum key;
445 	datum data;
446 	int stat;
447 
448 	if (tTd(38, 12))
449 		printf("ndbm_map_store(%s, %s)\n", lhs, rhs);
450 
451 	key.dsize = strlen(lhs);
452 	key.dptr = lhs;
453 
454 	data.dsize = strlen(rhs);
455 	data.dptr = rhs;
456 
457 	if (bitset(MF_INCLNULL, map->map_mflags))
458 	{
459 		key.dsize++;
460 		data.dsize++;
461 	}
462 
463 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
464 	if (stat > 0)
465 	{
466 		usrerr("050 Warning: duplicate alias name %s", lhs);
467 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
468 	}
469 	if (stat != 0)
470 		syserr("readaliases: dbm put (%s)", lhs);
471 }
472 
473 
474 /*
475 **  NDBM_MAP_CLOSE -- close the database
476 */
477 
478 void
479 ndbm_map_close(map)
480 	register MAP  *map;
481 {
482 	if (bitset(MF_WRITABLE, map->map_mflags))
483 	{
484 #ifdef YPCOMPAT
485 		char buf[200];
486 
487 		(void) sprintf(buf, "%010ld", curtime());
488 		ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
489 
490 		(void) myhostname(buf, sizeof buf);
491 		ndbm_map_store(map, "YP_MASTER_NAME", buf);
492 #endif
493 
494 		/* write out the distinguished alias */
495 		ndbm_map_store(map, "@", "@");
496 	}
497 	dbm_close((DBM *) map->map_db1);
498 }
499 
500 #endif
501 /*
502 **  NEWDB (Hash and BTree) Modules
503 */
504 
505 #ifdef NEWDB
506 
507 /*
508 **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
509 **
510 **	These do rather bizarre locking.  If you can lock on open,
511 **	do that to avoid the condition of opening a database that
512 **	is being rebuilt.  If you don't, we'll try to fake it, but
513 **	there will be a race condition.  If opening for read-only,
514 **	we immediately release the lock to avoid freezing things up.
515 **	We really ought to hold the lock, but guarantee that we won't
516 **	be pokey about it.  That's hard to do.
517 */
518 
519 bool
520 bt_map_open(map, mode)
521 	MAP *map;
522 	int mode;
523 {
524 	DB *db;
525 	int i;
526 	int omode;
527 	char buf[MAXNAME];
528 
529 	if (tTd(38, 2))
530 		printf("bt_map_open(%s, %d)\n", map->map_file, mode);
531 
532 	omode = mode;
533 	if (omode == O_RDWR)
534 	{
535 		omode |= O_CREAT|O_TRUNC;
536 #if defined(O_EXLOCK) && !defined(LOCKF)
537 		omode |= O_EXLOCK;
538 # if !defined(OLD_NEWDB)
539 	}
540 	else
541 	{
542 		omode |= O_SHLOCK;
543 # endif
544 #endif
545 	}
546 
547 	(void) strcpy(buf, map->map_file);
548 	i = strlen(buf);
549 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
550 		(void) strcat(buf, ".db");
551 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
552 	if (db == NULL)
553 	{
554 		if (!bitset(MF_OPTIONAL, map->map_mflags))
555 			syserr("Cannot open BTREE database %s", map->map_file);
556 		return FALSE;
557 	}
558 #if !defined(OLD_NEWDB) && !defined(LOCKF)
559 # if !defined(O_EXLOCK)
560 	if (mode == O_RDWR)
561 		(void) lockfile(db->fd(db), map->map_file, LOCK_EX);
562 # else
563 	if (mode == O_RDONLY)
564 		(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
565 # endif
566 #endif
567 
568 	/* try to make sure that at least the database header is on disk */
569 	if (mode == O_RDWR)
570 		(void) db->sync(db, 0);
571 
572 	map->map_db2 = (void *) db;
573 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
574 		aliaswait(map, ".db");
575 	return TRUE;
576 }
577 
578 
579 /*
580 **  HASH_MAP_INIT -- HASH-style map initialization
581 */
582 
583 bool
584 hash_map_open(map, mode)
585 	MAP *map;
586 	int mode;
587 {
588 	DB *db;
589 	int i;
590 	int omode;
591 	char buf[MAXNAME];
592 
593 	if (tTd(38, 2))
594 		printf("hash_map_open(%s, %d)\n", map->map_file, mode);
595 
596 	omode = mode;
597 	if (omode == O_RDWR)
598 	{
599 		omode |= O_CREAT|O_TRUNC;
600 #if defined(O_EXLOCK) && !defined(LOCKF)
601 		omode |= O_EXLOCK;
602 # if !defined(OLD_NEWDB)
603 	}
604 	else
605 	{
606 		omode |= O_SHLOCK;
607 # endif
608 #endif
609 	}
610 
611 	(void) strcpy(buf, map->map_file);
612 	i = strlen(buf);
613 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
614 		(void) strcat(buf, ".db");
615 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
616 	if (db == NULL)
617 	{
618 		if (!bitset(MF_OPTIONAL, map->map_mflags))
619 			syserr("Cannot open HASH database %s", map->map_file);
620 		return FALSE;
621 	}
622 #if !defined(OLD_NEWDB) && !defined(LOCKF)
623 # if !defined(O_EXLOCK)
624 	if (mode == O_RDWR)
625 		(void) lockfile(db->fd(db), map->map_file, LOCK_EX);
626 # else
627 	if (mode == O_RDONLY)
628 		(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
629 # endif
630 #endif
631 
632 	/* try to make sure that at least the database header is on disk */
633 	if (mode == O_RDWR)
634 		(void) db->sync(db, 0);
635 
636 	map->map_db2 = (void *) db;
637 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
638 		aliaswait(map, ".db");
639 	return TRUE;
640 }
641 
642 
643 /*
644 **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
645 */
646 
647 char *
648 db_map_lookup(map, name, av, statp)
649 	MAP *map;
650 	char *name;
651 	char **av;
652 	int *statp;
653 {
654 	DBT key, val;
655 	register DB *db = (DB *) map->map_db2;
656 	int st;
657 	int saveerrno;
658 	char keybuf[MAXNAME + 1];
659 
660 	if (tTd(38, 20))
661 		printf("db_map_lookup(%s)\n", name);
662 
663 	key.size = strlen(name);
664 	if (key.size > sizeof keybuf - 1)
665 		key.size = sizeof keybuf - 1;
666 	key.data = keybuf;
667 	bcopy(name, keybuf, key.size + 1);
668 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
669 		makelower(keybuf);
670 	if (bitset(MF_INCLNULL, map->map_mflags))
671 		key.size++;
672 #ifndef OLD_NEWDB
673 	(void) lockfile(db->fd(db), map->map_file, LOCK_SH);
674 #endif
675 	st = db->get(db, &key, &val, 0);
676 	saveerrno = errno;
677 #ifndef OLD_NEWDB
678 	(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
679 #endif
680 	if (st != 0)
681 	{
682 		errno = saveerrno;
683 		if (st < 0)
684 			syserr("db_map_lookup: get (%s)", name);
685 		return NULL;
686 	}
687 	if (bitset(MF_MATCHONLY, map->map_mflags))
688 		av = NULL;
689 	return map_rewrite(map, val.data, val.size, av);
690 }
691 
692 
693 /*
694 **  DB_MAP_STORE -- store a datum in the NEWDB database
695 */
696 
697 void
698 db_map_store(map, lhs, rhs)
699 	register MAP *map;
700 	char *lhs;
701 	char *rhs;
702 {
703 	int stat;
704 	DBT key;
705 	DBT data;
706 	register DB *db = map->map_db2;
707 
708 	if (tTd(38, 20))
709 		printf("db_map_store(%s, %s)\n", lhs, rhs);
710 
711 	key.size = strlen(lhs);
712 	key.data = lhs;
713 
714 	data.size = strlen(rhs);
715 	data.data = rhs;
716 
717 	if (bitset(MF_INCLNULL, map->map_mflags))
718 	{
719 		key.size++;
720 		data.size++;
721 	}
722 
723 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
724 	if (stat > 0)
725 	{
726 		usrerr("050 Warning: duplicate alias name %s", lhs);
727 		stat = db->put(db, &key, &data, 0);
728 	}
729 	if (stat != 0)
730 		syserr("readaliases: db put (%s)", lhs);
731 }
732 
733 
734 /*
735 **  DB_MAP_CLOSE -- add distinguished entries and close the database
736 */
737 
738 void
739 db_map_close(map)
740 	MAP *map;
741 {
742 	register DB *db = map->map_db2;
743 
744 	if (tTd(38, 9))
745 		printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
746 
747 	if (bitset(MF_WRITABLE, map->map_mflags))
748 	{
749 		/* write out the distinguished alias */
750 		db_map_store(map, "@", "@");
751 	}
752 
753 	if (db->close(db) != 0)
754 		syserr("readaliases: db close failure");
755 }
756 
757 #endif
758 /*
759 **  NIS Modules
760 */
761 
762 # ifdef NIS
763 
764 /*
765 **  NIS_MAP_OPEN -- open DBM map
766 */
767 
768 bool
769 nis_map_open(map, mode)
770 	MAP *map;
771 	int mode;
772 {
773 	int yperr;
774 	register char *p;
775 	auto char *vp;
776 	auto int vsize;
777 	char *master;
778 
779 	if (tTd(38, 2))
780 		printf("nis_map_open(%s)\n", map->map_file);
781 
782 	if (mode != O_RDONLY)
783 	{
784 		errno = ENODEV;
785 		return FALSE;
786 	}
787 
788 	p = strchr(map->map_file, '@');
789 	if (p != NULL)
790 	{
791 		*p++ = '\0';
792 		if (*p != '\0')
793 			map->map_domain = p;
794 	}
795 
796 	if (map->map_domain == NULL)
797 		yp_get_default_domain(&map->map_domain);
798 
799 	if (*map->map_file == '\0')
800 		map->map_file = "mail.aliases";
801 
802 	/* check to see if this map actually exists */
803 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
804 			&vp, &vsize);
805 	if (tTd(38, 10))
806 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
807 			map->map_domain, map->map_file, yperr_string(yperr));
808 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
809 		return TRUE;
810 
811 	if (!bitset(MF_OPTIONAL, map->map_mflags))
812 		syserr("Cannot bind to domain %s: %s", map->map_domain,
813 			yperr_string(yperr));
814 
815 	return FALSE;
816 }
817 
818 
819 /*
820 **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
821 */
822 
823 char *
824 nis_map_lookup(map, name, av, statp)
825 	MAP *map;
826 	char *name;
827 	char **av;
828 	int *statp;
829 {
830 	char *vp;
831 	auto int vsize;
832 	int buflen;
833 	int yperr;
834 	char keybuf[MAXNAME + 1];
835 
836 	if (tTd(38, 20))
837 		printf("nis_map_lookup(%s)\n", name);
838 
839 	buflen = strlen(name);
840 	if (buflen > sizeof keybuf - 1)
841 		buflen = sizeof keybuf - 1;
842 	bcopy(name, keybuf, buflen + 1);
843 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
844 		makelower(keybuf);
845 	if (bitset(MF_INCLNULL, map->map_mflags))
846 		buflen++;
847 	yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
848 		     &vp, &vsize);
849 	if (yperr != 0)
850 	{
851 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
852 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
853 		return NULL;
854 	}
855 	if (bitset(MF_MATCHONLY, map->map_mflags))
856 		av = NULL;
857 	return map_rewrite(map, vp, vsize, av);
858 }
859 
860 
861 /*
862 **  NIS_MAP_STORE
863 */
864 
865 void
866 nis_map_store(map, lhs, rhs)
867 	MAP *map;
868 	char *lhs;
869 	char *rhs;
870 {
871 	/* nothing */
872 }
873 
874 
875 /*
876 **  NIS_MAP_CLOSE
877 */
878 
879 void
880 nis_map_close(map)
881 	MAP *map;
882 {
883 	/* nothing */
884 }
885 
886 #endif /* NIS */
887 /*
888 **  STAB (Symbol Table) Modules
889 */
890 
891 
892 /*
893 **  STAB_MAP_LOOKUP -- look up alias in symbol table
894 */
895 
896 char *
897 stab_map_lookup(map, name, av, pstat)
898 	register MAP *map;
899 	char *name;
900 	char **av;
901 	int *pstat;
902 {
903 	register STAB *s;
904 
905 	if (tTd(38, 20))
906 		printf("stab_lookup(%s)\n", name);
907 
908 	s = stab(name, ST_ALIAS, ST_FIND);
909 	if (s != NULL)
910 		return (s->s_alias);
911 	return (NULL);
912 }
913 
914 
915 /*
916 **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
917 */
918 
919 void
920 stab_map_store(map, lhs, rhs)
921 	register MAP *map;
922 	char *lhs;
923 	char *rhs;
924 {
925 	register STAB *s;
926 
927 	s = stab(lhs, ST_ALIAS, ST_ENTER);
928 	s->s_alias = newstr(rhs);
929 }
930 
931 
932 /*
933 **  STAB_MAP_OPEN -- initialize (reads data file)
934 **
935 **	This is a wierd case -- it is only intended as a fallback for
936 **	aliases.  For this reason, opens for write (only during a
937 **	"newaliases") always fails, and opens for read open the
938 **	actual underlying text file instead of the database.
939 */
940 
941 bool
942 stab_map_open(map, mode)
943 	register MAP *map;
944 	int mode;
945 {
946 	if (tTd(38, 2))
947 		printf("stab_map_open(%s)\n", map->map_file);
948 
949 	if (mode != O_RDONLY)
950 	{
951 		errno = ENODEV;
952 		return FALSE;
953 	}
954 
955 	return TRUE;
956 }
957 
958 
959 /*
960 **  STAB_MAP_CLOSE -- close symbol table (???)
961 */
962 
963 void
964 stab_map_close(map)
965 	MAP *map;
966 {
967 	/* ignore it */
968 }
969 /*
970 **  Implicit Modules
971 **
972 **	Tries several types.  For back compatibility of aliases.
973 */
974 
975 
976 /*
977 **  IMPL_MAP_LOOKUP -- lookup in best open database
978 */
979 
980 char *
981 impl_map_lookup(map, name, av, pstat)
982 	MAP *map;
983 	char *name;
984 	char **av;
985 	int *pstat;
986 {
987 	if (tTd(38, 20))
988 		printf("impl_map_lookup(%s)\n", name);
989 
990 #ifdef NEWDB
991 	if (bitset(MF_IMPL_HASH, map->map_mflags))
992 		return db_map_lookup(map, name, av, pstat);
993 #endif
994 #ifdef NDBM
995 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
996 		return ndbm_map_lookup(map, name, av, pstat);
997 #endif
998 	return stab_map_lookup(map, name, av, pstat);
999 }
1000 
1001 /*
1002 **  IMPL_MAP_STORE -- store in open databases
1003 */
1004 
1005 void
1006 impl_map_store(map, lhs, rhs)
1007 	MAP *map;
1008 	char *lhs;
1009 	char *rhs;
1010 {
1011 #ifdef NEWDB
1012 	if (bitset(MF_IMPL_HASH, map->map_mflags))
1013 		db_map_store(map, lhs, rhs);
1014 #endif
1015 #ifdef NDBM
1016 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
1017 		ndbm_map_store(map, lhs, rhs);
1018 #endif
1019 	stab_map_store(map, lhs, rhs);
1020 }
1021 
1022 /*
1023 **  IMPL_MAP_OPEN -- implicit database open
1024 */
1025 
1026 bool
1027 impl_map_open(map, mode)
1028 	MAP *map;
1029 	int mode;
1030 {
1031 	struct stat stb;
1032 
1033 	if (tTd(38, 2))
1034 		printf("impl_map_open(%s)\n", map->map_file);
1035 
1036 	if (stat(map->map_file, &stb) < 0)
1037 	{
1038 		/* no alias file at all */
1039 		return FALSE;
1040 	}
1041 
1042 #ifdef NEWDB
1043 	map->map_mflags |= MF_IMPL_HASH;
1044 	if (hash_map_open(map, mode))
1045 	{
1046 #if defined(NDBM) && defined(YPCOMPAT)
1047 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
1048 #endif
1049 			return TRUE;
1050 	}
1051 	else
1052 		map->map_mflags &= ~MF_IMPL_HASH;
1053 #endif
1054 #ifdef NDBM
1055 	map->map_mflags |= MF_IMPL_NDBM;
1056 	if (ndbm_map_open(map, mode))
1057 	{
1058 		return TRUE;
1059 	}
1060 	else
1061 		map->map_mflags &= ~MF_IMPL_NDBM;
1062 #endif
1063 
1064 #if !defined(NEWDB) && !defined(NDBM)
1065 	if (Verbose)
1066 		message("WARNING: cannot open alias database %s", map->map_file);
1067 #endif
1068 
1069 	return stab_map_open(map, mode);
1070 }
1071 
1072 
1073 /*
1074 **  IMPL_MAP_CLOSE -- close any open database(s)
1075 */
1076 
1077 void
1078 impl_map_close(map)
1079 	MAP *map;
1080 {
1081 #ifdef NEWDB
1082 	if (bitset(MF_IMPL_HASH, map->map_mflags))
1083 	{
1084 		db_map_close(map);
1085 		map->map_mflags &= ~MF_IMPL_HASH;
1086 	}
1087 #endif
1088 
1089 #ifdef NDBM
1090 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
1091 	{
1092 		ndbm_map_close(map);
1093 		map->map_mflags &= ~MF_IMPL_NDBM;
1094 	}
1095 #endif
1096 }
1097 /*
1098 **  NULL stubs
1099 */
1100 
1101 bool
1102 null_map_open(map, mode)
1103 	MAP *map;
1104 	int mode;
1105 {
1106 	return TRUE;
1107 }
1108 
1109 void
1110 null_map_close(map)
1111 	MAP *map;
1112 {
1113 	return;
1114 }
1115 
1116 void
1117 null_map_store(map, key, val)
1118 	MAP *map;
1119 	char *key;
1120 	char *val;
1121 {
1122 	return;
1123 }
1124