xref: /original-bsd/usr.sbin/sendmail/src/map.c (revision 3705696b)
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.5 (Berkeley) 07/26/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 	DBM *dbm;
376 
377 	if (tTd(38, 2))
378 		printf("ndbm_map_open(%s, %d)\n", map->map_file, mode);
379 
380 	if (mode == O_RDWR)
381 		mode |= O_CREAT|O_TRUNC;
382 
383 	/* open the database */
384 	dbm = dbm_open(map->map_file, mode, DBMMODE);
385 	if (dbm == NULL)
386 	{
387 		if (!bitset(MF_OPTIONAL, map->map_mflags))
388 			syserr("Cannot open DBM database %s", map->map_file);
389 		return FALSE;
390 	}
391 	map->map_db1 = (void *) dbm;
392 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
393 		aliaswait(map, ".pag");
394 	return TRUE;
395 }
396 
397 
398 /*
399 **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
400 */
401 
402 char *
403 ndbm_map_lookup(map, name, av, statp)
404 	MAP *map;
405 	char *name;
406 	char **av;
407 	int *statp;
408 {
409 	datum key, val;
410 	char keybuf[MAXNAME + 1];
411 
412 	if (tTd(38, 20))
413 		printf("ndbm_map_lookup(%s)\n", name);
414 
415 	key.dptr = name;
416 	key.dsize = strlen(name);
417 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
418 	{
419 		if (key.dsize > sizeof keybuf - 1)
420 			key.dsize = sizeof keybuf - 1;
421 		bcopy(key.dptr, keybuf, key.dsize + 1);
422 		makelower(keybuf);
423 		key.dptr = keybuf;
424 	}
425 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_SH);
426 	val.dptr = NULL;
427 	if (bitset(MF_TRY0NULL, map->map_mflags))
428 	{
429 		val = dbm_fetch((DBM *) map->map_db1, key);
430 		if (val.dptr != NULL)
431 			map->map_mflags &= ~MF_TRY1NULL;
432 	}
433 	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
434 	{
435 		key.dsize++;
436 		val = dbm_fetch((DBM *) map->map_db1, key);
437 		if (val.dptr != NULL)
438 			map->map_mflags &= ~MF_TRY0NULL;
439 	}
440 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_UN);
441 	if (val.dptr == NULL)
442 		return NULL;
443 	if (bitset(MF_MATCHONLY, map->map_mflags))
444 		return map_rewrite(map, name, strlen(name), NULL);
445 	else
446 		return map_rewrite(map, val.dptr, val.dsize, av);
447 }
448 
449 
450 /*
451 **  DBM_MAP_STORE -- store a datum in the database
452 */
453 
454 void
455 ndbm_map_store(map, lhs, rhs)
456 	register MAP *map;
457 	char *lhs;
458 	char *rhs;
459 {
460 	datum key;
461 	datum data;
462 	int stat;
463 
464 	if (tTd(38, 12))
465 		printf("ndbm_map_store(%s, %s)\n", lhs, rhs);
466 
467 	key.dsize = strlen(lhs);
468 	key.dptr = lhs;
469 
470 	data.dsize = strlen(rhs);
471 	data.dptr = rhs;
472 
473 	if (bitset(MF_INCLNULL, map->map_mflags))
474 	{
475 		key.dsize++;
476 		data.dsize++;
477 	}
478 
479 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
480 	if (stat > 0)
481 	{
482 		usrerr("050 Warning: duplicate alias name %s", lhs);
483 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
484 	}
485 	if (stat != 0)
486 		syserr("readaliases: dbm put (%s)", lhs);
487 }
488 
489 
490 /*
491 **  NDBM_MAP_CLOSE -- close the database
492 */
493 
494 void
495 ndbm_map_close(map)
496 	register MAP  *map;
497 {
498 	if (bitset(MF_WRITABLE, map->map_mflags))
499 	{
500 #ifdef YPCOMPAT
501 		char buf[200];
502 
503 		(void) sprintf(buf, "%010ld", curtime());
504 		ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
505 
506 		(void) myhostname(buf, sizeof buf);
507 		ndbm_map_store(map, "YP_MASTER_NAME", buf);
508 #endif
509 
510 		/* write out the distinguished alias */
511 		ndbm_map_store(map, "@", "@");
512 	}
513 	dbm_close((DBM *) map->map_db1);
514 }
515 
516 #endif
517 /*
518 **  NEWDB (Hash and BTree) Modules
519 */
520 
521 #ifdef NEWDB
522 
523 /*
524 **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
525 **
526 **	These do rather bizarre locking.  If you can lock on open,
527 **	do that to avoid the condition of opening a database that
528 **	is being rebuilt.  If you don't, we'll try to fake it, but
529 **	there will be a race condition.  If opening for read-only,
530 **	we immediately release the lock to avoid freezing things up.
531 **	We really ought to hold the lock, but guarantee that we won't
532 **	be pokey about it.  That's hard to do.
533 */
534 
535 bool
536 bt_map_open(map, mode)
537 	MAP *map;
538 	int mode;
539 {
540 	DB *db;
541 	int i;
542 	int omode;
543 	char buf[MAXNAME];
544 
545 	if (tTd(38, 2))
546 		printf("bt_map_open(%s, %d)\n", map->map_file, mode);
547 
548 	omode = mode;
549 	if (omode == O_RDWR)
550 	{
551 		omode |= O_CREAT|O_TRUNC;
552 #if defined(O_EXLOCK) && defined(HASFLOCK)
553 		omode |= O_EXLOCK;
554 # if !defined(OLD_NEWDB)
555 	}
556 	else
557 	{
558 		omode |= O_SHLOCK;
559 # endif
560 #endif
561 	}
562 
563 	(void) strcpy(buf, map->map_file);
564 	i = strlen(buf);
565 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
566 		(void) strcat(buf, ".db");
567 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
568 	if (db == NULL)
569 	{
570 		if (!bitset(MF_OPTIONAL, map->map_mflags))
571 			syserr("Cannot open BTREE database %s", map->map_file);
572 		return FALSE;
573 	}
574 #if !defined(OLD_NEWDB) && defined(HASFLOCK)
575 # if !defined(O_EXLOCK)
576 	if (mode == O_RDWR)
577 		(void) lockfile(db->fd(db), map->map_file, LOCK_EX);
578 # else
579 	if (mode == O_RDONLY)
580 		(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
581 # endif
582 #endif
583 
584 	/* try to make sure that at least the database header is on disk */
585 	if (mode == O_RDWR)
586 		(void) db->sync(db, 0);
587 
588 	map->map_db2 = (void *) db;
589 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
590 		aliaswait(map, ".db");
591 	return TRUE;
592 }
593 
594 
595 /*
596 **  HASH_MAP_INIT -- HASH-style map initialization
597 */
598 
599 bool
600 hash_map_open(map, mode)
601 	MAP *map;
602 	int mode;
603 {
604 	DB *db;
605 	int i;
606 	int omode;
607 	char buf[MAXNAME];
608 
609 	if (tTd(38, 2))
610 		printf("hash_map_open(%s, %d)\n", map->map_file, mode);
611 
612 	omode = mode;
613 	if (omode == O_RDWR)
614 	{
615 		omode |= O_CREAT|O_TRUNC;
616 #if defined(O_EXLOCK) && defined(HASFLOCK)
617 		omode |= O_EXLOCK;
618 # if !defined(OLD_NEWDB)
619 	}
620 	else
621 	{
622 		omode |= O_SHLOCK;
623 # endif
624 #endif
625 	}
626 
627 	(void) strcpy(buf, map->map_file);
628 	i = strlen(buf);
629 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
630 		(void) strcat(buf, ".db");
631 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
632 	if (db == NULL)
633 	{
634 		if (!bitset(MF_OPTIONAL, map->map_mflags))
635 			syserr("Cannot open HASH database %s", map->map_file);
636 		return FALSE;
637 	}
638 #if !defined(OLD_NEWDB) && defined(HASFLOCK)
639 # if !defined(O_EXLOCK)
640 	if (mode == O_RDWR)
641 		(void) lockfile(db->fd(db), map->map_file, LOCK_EX);
642 # else
643 	if (mode == O_RDONLY)
644 		(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
645 # endif
646 #endif
647 
648 	/* try to make sure that at least the database header is on disk */
649 	if (mode == O_RDWR)
650 		(void) db->sync(db, 0);
651 
652 	map->map_db2 = (void *) db;
653 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
654 		aliaswait(map, ".db");
655 	return TRUE;
656 }
657 
658 
659 /*
660 **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
661 */
662 
663 char *
664 db_map_lookup(map, name, av, statp)
665 	MAP *map;
666 	char *name;
667 	char **av;
668 	int *statp;
669 {
670 	DBT key, val;
671 	register DB *db = (DB *) map->map_db2;
672 	int st;
673 	int saveerrno;
674 	char keybuf[MAXNAME + 1];
675 
676 	if (tTd(38, 20))
677 		printf("db_map_lookup(%s)\n", name);
678 
679 	key.size = strlen(name);
680 	if (key.size > sizeof keybuf - 1)
681 		key.size = sizeof keybuf - 1;
682 	key.data = keybuf;
683 	bcopy(name, keybuf, key.size + 1);
684 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
685 		makelower(keybuf);
686 #ifndef OLD_NEWDB
687 	(void) lockfile(db->fd(db), map->map_file, LOCK_SH);
688 #endif
689 	st = 1;
690 	if (bitset(MF_TRY0NULL, map->map_mflags))
691 	{
692 		st = db->get(db, &key, &val, 0);
693 		if (st == 0)
694 			map->map_mflags &= ~MF_TRY1NULL;
695 	}
696 	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
697 	{
698 		key.size++;
699 		st = db->get(db, &key, &val, 0);
700 		if (st == 0)
701 			map->map_mflags &= ~MF_TRY0NULL;
702 	}
703 	saveerrno = errno;
704 #ifndef OLD_NEWDB
705 	(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
706 #endif
707 	if (st != 0)
708 	{
709 		errno = saveerrno;
710 		if (st < 0)
711 			syserr("db_map_lookup: get (%s)", name);
712 		return NULL;
713 	}
714 	if (bitset(MF_MATCHONLY, map->map_mflags))
715 		return map_rewrite(map, name, strlen(name), NULL);
716 	else
717 		return map_rewrite(map, val.data, val.size, av);
718 }
719 
720 
721 /*
722 **  DB_MAP_STORE -- store a datum in the NEWDB database
723 */
724 
725 void
726 db_map_store(map, lhs, rhs)
727 	register MAP *map;
728 	char *lhs;
729 	char *rhs;
730 {
731 	int stat;
732 	DBT key;
733 	DBT data;
734 	register DB *db = map->map_db2;
735 
736 	if (tTd(38, 20))
737 		printf("db_map_store(%s, %s)\n", lhs, rhs);
738 
739 	key.size = strlen(lhs);
740 	key.data = lhs;
741 
742 	data.size = strlen(rhs);
743 	data.data = rhs;
744 
745 	if (bitset(MF_INCLNULL, map->map_mflags))
746 	{
747 		key.size++;
748 		data.size++;
749 	}
750 
751 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
752 	if (stat > 0)
753 	{
754 		usrerr("050 Warning: duplicate alias name %s", lhs);
755 		stat = db->put(db, &key, &data, 0);
756 	}
757 	if (stat != 0)
758 		syserr("readaliases: db put (%s)", lhs);
759 }
760 
761 
762 /*
763 **  DB_MAP_CLOSE -- add distinguished entries and close the database
764 */
765 
766 void
767 db_map_close(map)
768 	MAP *map;
769 {
770 	register DB *db = map->map_db2;
771 
772 	if (tTd(38, 9))
773 		printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
774 
775 	if (bitset(MF_WRITABLE, map->map_mflags))
776 	{
777 		/* write out the distinguished alias */
778 		db_map_store(map, "@", "@");
779 	}
780 
781 	if (db->close(db) != 0)
782 		syserr("readaliases: db close failure");
783 }
784 
785 #endif
786 /*
787 **  NIS Modules
788 */
789 
790 # ifdef NIS
791 
792 /*
793 **  NIS_MAP_OPEN -- open DBM map
794 */
795 
796 bool
797 nis_map_open(map, mode)
798 	MAP *map;
799 	int mode;
800 {
801 	int yperr;
802 	register char *p;
803 	auto char *vp;
804 	auto int vsize;
805 	char *master;
806 
807 	if (tTd(38, 2))
808 		printf("nis_map_open(%s)\n", map->map_file);
809 
810 	if (mode != O_RDONLY)
811 	{
812 		errno = ENODEV;
813 		return FALSE;
814 	}
815 
816 	p = strchr(map->map_file, '@');
817 	if (p != NULL)
818 	{
819 		*p++ = '\0';
820 		if (*p != '\0')
821 			map->map_domain = p;
822 	}
823 
824 	if (map->map_domain == NULL)
825 		yp_get_default_domain(&map->map_domain);
826 
827 	if (*map->map_file == '\0')
828 		map->map_file = "mail.aliases";
829 
830 	/* check to see if this map actually exists */
831 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
832 			&vp, &vsize);
833 	if (tTd(38, 10))
834 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
835 			map->map_domain, map->map_file, yperr_string(yperr));
836 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
837 		return TRUE;
838 
839 	if (!bitset(MF_OPTIONAL, map->map_mflags))
840 		syserr("Cannot bind to domain %s: %s", map->map_domain,
841 			yperr_string(yperr));
842 
843 	return FALSE;
844 }
845 
846 
847 /*
848 **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
849 */
850 
851 char *
852 nis_map_lookup(map, name, av, statp)
853 	MAP *map;
854 	char *name;
855 	char **av;
856 	int *statp;
857 {
858 	char *vp;
859 	auto int vsize;
860 	int buflen;
861 	int yperr;
862 	char keybuf[MAXNAME + 1];
863 
864 	if (tTd(38, 20))
865 		printf("nis_map_lookup(%s)\n", name);
866 
867 	buflen = strlen(name);
868 	if (buflen > sizeof keybuf - 1)
869 		buflen = sizeof keybuf - 1;
870 	bcopy(name, keybuf, buflen + 1);
871 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
872 		makelower(keybuf);
873 	yperr = YPERR_KEY;
874 	if (bitset(MF_TRY0NULL, map->map_mflags))
875 	{
876 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
877 			     &vp, &vsize);
878 		if (yperr == 0)
879 			map->map_mflags &= ~MF_TRY1NULL;
880 	}
881 	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
882 	{
883 		buflen++;
884 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
885 			     &vp, &vsize);
886 		if (yperr == 0)
887 			map->map_mflags &= ~MF_TRY0NULL;
888 	}
889 	if (yperr != 0)
890 	{
891 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
892 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
893 		return NULL;
894 	}
895 	if (bitset(MF_MATCHONLY, map->map_mflags))
896 		return map_rewrite(map, name, strlen(name), NULL);
897 	else
898 		return map_rewrite(map, vp, vsize, av);
899 }
900 
901 
902 /*
903 **  NIS_MAP_STORE
904 */
905 
906 void
907 nis_map_store(map, lhs, rhs)
908 	MAP *map;
909 	char *lhs;
910 	char *rhs;
911 {
912 	/* nothing */
913 }
914 
915 
916 /*
917 **  NIS_MAP_CLOSE
918 */
919 
920 void
921 nis_map_close(map)
922 	MAP *map;
923 {
924 	/* nothing */
925 }
926 
927 #endif /* NIS */
928 /*
929 **  STAB (Symbol Table) Modules
930 */
931 
932 
933 /*
934 **  STAB_MAP_LOOKUP -- look up alias in symbol table
935 */
936 
937 char *
938 stab_map_lookup(map, name, av, pstat)
939 	register MAP *map;
940 	char *name;
941 	char **av;
942 	int *pstat;
943 {
944 	register STAB *s;
945 
946 	if (tTd(38, 20))
947 		printf("stab_lookup(%s)\n", name);
948 
949 	s = stab(name, ST_ALIAS, ST_FIND);
950 	if (s != NULL)
951 		return (s->s_alias);
952 	return (NULL);
953 }
954 
955 
956 /*
957 **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
958 */
959 
960 void
961 stab_map_store(map, lhs, rhs)
962 	register MAP *map;
963 	char *lhs;
964 	char *rhs;
965 {
966 	register STAB *s;
967 
968 	s = stab(lhs, ST_ALIAS, ST_ENTER);
969 	s->s_alias = newstr(rhs);
970 }
971 
972 
973 /*
974 **  STAB_MAP_OPEN -- initialize (reads data file)
975 **
976 **	This is a wierd case -- it is only intended as a fallback for
977 **	aliases.  For this reason, opens for write (only during a
978 **	"newaliases") always fails, and opens for read open the
979 **	actual underlying text file instead of the database.
980 */
981 
982 bool
983 stab_map_open(map, mode)
984 	register MAP *map;
985 	int mode;
986 {
987 	FILE *af;
988 
989 	if (tTd(38, 2))
990 		printf("stab_map_open(%s)\n", map->map_file);
991 
992 	if (mode != O_RDONLY)
993 	{
994 		errno = ENODEV;
995 		return FALSE;
996 	}
997 
998 	af = fopen(map->map_file, "r");
999 	if (af == NULL)
1000 		return FALSE;
1001 	readaliases(map, af, TRUE);
1002 	fclose(af);
1003 
1004 	return TRUE;
1005 }
1006 
1007 
1008 /*
1009 **  STAB_MAP_CLOSE -- close symbol table (???)
1010 */
1011 
1012 void
1013 stab_map_close(map)
1014 	MAP *map;
1015 {
1016 	/* ignore it */
1017 }
1018 /*
1019 **  Implicit Modules
1020 **
1021 **	Tries several types.  For back compatibility of aliases.
1022 */
1023 
1024 
1025 /*
1026 **  IMPL_MAP_LOOKUP -- lookup in best open database
1027 */
1028 
1029 char *
1030 impl_map_lookup(map, name, av, pstat)
1031 	MAP *map;
1032 	char *name;
1033 	char **av;
1034 	int *pstat;
1035 {
1036 	if (tTd(38, 20))
1037 		printf("impl_map_lookup(%s)\n", name);
1038 
1039 #ifdef NEWDB
1040 	if (bitset(MF_IMPL_HASH, map->map_mflags))
1041 		return db_map_lookup(map, name, av, pstat);
1042 #endif
1043 #ifdef NDBM
1044 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
1045 		return ndbm_map_lookup(map, name, av, pstat);
1046 #endif
1047 	return stab_map_lookup(map, name, av, pstat);
1048 }
1049 
1050 /*
1051 **  IMPL_MAP_STORE -- store in open databases
1052 */
1053 
1054 void
1055 impl_map_store(map, lhs, rhs)
1056 	MAP *map;
1057 	char *lhs;
1058 	char *rhs;
1059 {
1060 #ifdef NEWDB
1061 	if (bitset(MF_IMPL_HASH, map->map_mflags))
1062 		db_map_store(map, lhs, rhs);
1063 #endif
1064 #ifdef NDBM
1065 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
1066 		ndbm_map_store(map, lhs, rhs);
1067 #endif
1068 	stab_map_store(map, lhs, rhs);
1069 }
1070 
1071 /*
1072 **  IMPL_MAP_OPEN -- implicit database open
1073 */
1074 
1075 bool
1076 impl_map_open(map, mode)
1077 	MAP *map;
1078 	int mode;
1079 {
1080 	struct stat stb;
1081 
1082 	if (tTd(38, 2))
1083 		printf("impl_map_open(%s)\n", map->map_file);
1084 
1085 	if (stat(map->map_file, &stb) < 0)
1086 	{
1087 		/* no alias file at all */
1088 		return FALSE;
1089 	}
1090 
1091 #ifdef NEWDB
1092 	map->map_mflags |= MF_IMPL_HASH;
1093 	if (hash_map_open(map, mode))
1094 	{
1095 #if defined(NDBM) && defined(YPCOMPAT)
1096 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
1097 #endif
1098 			return TRUE;
1099 	}
1100 	else
1101 		map->map_mflags &= ~MF_IMPL_HASH;
1102 #endif
1103 #ifdef NDBM
1104 	map->map_mflags |= MF_IMPL_NDBM;
1105 	if (ndbm_map_open(map, mode))
1106 	{
1107 		return TRUE;
1108 	}
1109 	else
1110 		map->map_mflags &= ~MF_IMPL_NDBM;
1111 #endif
1112 
1113 #if !defined(NEWDB) && !defined(NDBM)
1114 	if (Verbose)
1115 		message("WARNING: cannot open alias database %s", map->map_file);
1116 #endif
1117 
1118 	return stab_map_open(map, mode);
1119 }
1120 
1121 
1122 /*
1123 **  IMPL_MAP_CLOSE -- close any open database(s)
1124 */
1125 
1126 void
1127 impl_map_close(map)
1128 	MAP *map;
1129 {
1130 #ifdef NEWDB
1131 	if (bitset(MF_IMPL_HASH, map->map_mflags))
1132 	{
1133 		db_map_close(map);
1134 		map->map_mflags &= ~MF_IMPL_HASH;
1135 	}
1136 #endif
1137 
1138 #ifdef NDBM
1139 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
1140 	{
1141 		ndbm_map_close(map);
1142 		map->map_mflags &= ~MF_IMPL_NDBM;
1143 	}
1144 #endif
1145 }
1146 /*
1147 **  NULL stubs
1148 */
1149 
1150 bool
1151 null_map_open(map, mode)
1152 	MAP *map;
1153 	int mode;
1154 {
1155 	return TRUE;
1156 }
1157 
1158 void
1159 null_map_close(map)
1160 	MAP *map;
1161 {
1162 	return;
1163 }
1164 
1165 void
1166 null_map_store(map, key, val)
1167 	MAP *map;
1168 	char *key;
1169 	char *val;
1170 {
1171 	return;
1172 }
1173