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