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