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