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