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