xref: /freebsd/usr.sbin/ypserv/yp_dblookup.c (revision 559605f1ec4e088e7c0ab38d58620477dec566e3)
1778c7b1cSBill Paul /*
2778c7b1cSBill Paul  * Copyright (c) 1995
3778c7b1cSBill Paul  *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4778c7b1cSBill Paul  *
5778c7b1cSBill Paul  * Redistribution and use in source and binary forms, with or without
6778c7b1cSBill Paul  * modification, are permitted provided that the following conditions
7778c7b1cSBill Paul  * are met:
8778c7b1cSBill Paul  * 1. Redistributions of source code must retain the above copyright
9778c7b1cSBill Paul  *    notice, this list of conditions and the following disclaimer.
10778c7b1cSBill Paul  * 2. Redistributions in binary form must reproduce the above copyright
11778c7b1cSBill Paul  *    notice, this list of conditions and the following disclaimer in the
12778c7b1cSBill Paul  *    documentation and/or other materials provided with the distribution.
13778c7b1cSBill Paul  * 3. All advertising materials mentioning features or use of this software
14778c7b1cSBill Paul  *    must display the following acknowledgement:
15778c7b1cSBill Paul  *	This product includes software developed by Bill Paul.
16778c7b1cSBill Paul  * 4. Neither the name of the author nor the names of any co-contributors
17778c7b1cSBill Paul  *    may be used to endorse or promote products derived from this software
18778c7b1cSBill Paul  *    without specific prior written permission.
19778c7b1cSBill Paul  *
20778c7b1cSBill Paul  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21778c7b1cSBill Paul  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22778c7b1cSBill Paul  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23778c7b1cSBill Paul  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24778c7b1cSBill Paul  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25778c7b1cSBill Paul  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26778c7b1cSBill Paul  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27778c7b1cSBill Paul  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28778c7b1cSBill Paul  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29778c7b1cSBill Paul  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30778c7b1cSBill Paul  * SUCH DAMAGE.
31778c7b1cSBill Paul  *
321130b656SJordan K. Hubbard  *	$FreeBSD$
33778c7b1cSBill Paul  *
34778c7b1cSBill Paul  */
35778c7b1cSBill Paul #include <stdio.h>
36778c7b1cSBill Paul #include <stdlib.h>
37778c7b1cSBill Paul #include <fcntl.h>
38778c7b1cSBill Paul #include <string.h>
39778c7b1cSBill Paul #include <limits.h>
40778c7b1cSBill Paul #include <unistd.h>
41778c7b1cSBill Paul #include <db.h>
42778c7b1cSBill Paul #include <sys/stat.h>
43b2264be8SBill Paul #include <sys/param.h>
44778c7b1cSBill Paul #include <errno.h>
45778c7b1cSBill Paul #include <paths.h>
46b2264be8SBill Paul #include <rpcsvc/yp.h>
47778c7b1cSBill Paul #include "yp_extern.h"
48778c7b1cSBill Paul 
491fbdac93SBill Paul #ifndef lint
501130b656SJordan K. Hubbard static const char rcsid[] = "$FreeBSD$";
511fbdac93SBill Paul #endif
521fbdac93SBill Paul 
5377732bc5SBill Paul int ypdb_debug = 0;
54180807d2SBill Paul enum ypstat yp_errno = YP_TRUE;
55778c7b1cSBill Paul 
56778c7b1cSBill Paul #define PERM_SECURE (S_IRUSR|S_IWUSR)
57778c7b1cSBill Paul HASHINFO openinfo = {
58778c7b1cSBill Paul 	4096,		/* bsize */
59778c7b1cSBill Paul 	32,		/* ffactor */
60b3e93234SBill Paul 	256,		/* nelem */
61b2264be8SBill Paul 	2048 * 512, 	/* cachesize */
62778c7b1cSBill Paul 	NULL,		/* hash */
63778c7b1cSBill Paul 	0,		/* lorder */
64778c7b1cSBill Paul };
65778c7b1cSBill Paul 
66b2264be8SBill Paul #ifdef DB_CACHE
6779acf67fSBill Paul #include <sys/queue.h>
6879acf67fSBill Paul 
6979acf67fSBill Paul #ifndef MAXDBS
70b2264be8SBill Paul #define MAXDBS 20
7179acf67fSBill Paul #endif
7279acf67fSBill Paul 
7379acf67fSBill Paul static int numdbs = 0;
74b2264be8SBill Paul 
75b2264be8SBill Paul struct dbent {
76b2264be8SBill Paul 	DB *dbp;
77b2264be8SBill Paul 	char *name;
78b2264be8SBill Paul 	char *key;
79b2264be8SBill Paul 	int size;
8044519760SBill Paul 	int flags;
81b2264be8SBill Paul };
82b2264be8SBill Paul 
8379acf67fSBill Paul static CIRCLEQ_HEAD(circlehead, circleq_entry) qhead;
8479acf67fSBill Paul 
8579acf67fSBill Paul struct circleq_entry {
8679acf67fSBill Paul 	struct dbent *dbptr;
8779acf67fSBill Paul 	CIRCLEQ_ENTRY(circleq_entry) links;
8879acf67fSBill Paul };
89b2264be8SBill Paul 
90778c7b1cSBill Paul /*
9179acf67fSBill Paul  * Initialize the circular queue.
92b2264be8SBill Paul  */
93b2264be8SBill Paul void yp_init_dbs()
94b2264be8SBill Paul {
9579acf67fSBill Paul 	CIRCLEQ_INIT(&qhead);
96b2264be8SBill Paul 	return;
97b2264be8SBill Paul }
98b2264be8SBill Paul 
991fbdac93SBill Paul /*
10079acf67fSBill Paul  * Dynamically allocate an entry for the circular queue.
10179acf67fSBill Paul  * Return a NULL pointer on failure.
1021fbdac93SBill Paul  */
10379acf67fSBill Paul static struct circleq_entry *yp_malloc_qent()
104b2264be8SBill Paul {
10579acf67fSBill Paul 	register struct circleq_entry *q;
10679acf67fSBill Paul 
10779acf67fSBill Paul 	q = (struct circleq_entry *)malloc(sizeof(struct circleq_entry));
10879acf67fSBill Paul 	if (q == NULL) {
10979acf67fSBill Paul 		yp_error("failed to malloc() circleq entry: %s",
11079acf67fSBill Paul 							strerror(errno));
11179acf67fSBill Paul 		return(NULL);
11279acf67fSBill Paul 	}
11379acf67fSBill Paul 	bzero((char *)q, sizeof(struct circleq_entry));
11479acf67fSBill Paul 	q->dbptr = (struct dbent *)malloc(sizeof(struct dbent));
11579acf67fSBill Paul 	if (q->dbptr == NULL) {
11679acf67fSBill Paul 		yp_error("failed to malloc() circleq entry: %s",
11779acf67fSBill Paul 							strerror(errno));
11879acf67fSBill Paul 		free(q);
11979acf67fSBill Paul 		return(NULL);
12079acf67fSBill Paul 	}
12179acf67fSBill Paul 	bzero((char *)q->dbptr, sizeof(struct dbent));
12279acf67fSBill Paul 
12379acf67fSBill Paul 	return(q);
124b2264be8SBill Paul }
125b2264be8SBill Paul 
126b2264be8SBill Paul /*
12779acf67fSBill Paul  * Free a previously allocated circular queue
12879acf67fSBill Paul  * entry.
12979acf67fSBill Paul  */
13079acf67fSBill Paul static void yp_free_qent(q)
13179acf67fSBill Paul 	struct circleq_entry *q;
13279acf67fSBill Paul {
13379acf67fSBill Paul 	/*
13479acf67fSBill Paul 	 * First, close the database. In theory, this is also
13579acf67fSBill Paul 	 * supposed to free the resources allocated by the DB
13679acf67fSBill Paul 	 * package, including the memory pointed to by q->dbptr->key.
13779acf67fSBill Paul 	 * This means we don't have to free q->dbptr->key here.
13879acf67fSBill Paul 	 */
13979acf67fSBill Paul 	if (q->dbptr->dbp) {
14079acf67fSBill Paul 		(void)(q->dbptr->dbp->close)(q->dbptr->dbp);
14179acf67fSBill Paul 		q->dbptr->dbp = NULL;
14279acf67fSBill Paul 	}
14379acf67fSBill Paul 	/*
14479acf67fSBill Paul 	 * Then free the database name, which was strdup()'ed.
14579acf67fSBill Paul 	 */
14679acf67fSBill Paul 	free(q->dbptr->name);
14779acf67fSBill Paul 
14879acf67fSBill Paul 	/*
14979acf67fSBill Paul 	 * Free the rest of the dbent struct.
15079acf67fSBill Paul 	 */
15179acf67fSBill Paul 	free(q->dbptr);
15279acf67fSBill Paul 	q->dbptr = NULL;
15379acf67fSBill Paul 
15479acf67fSBill Paul 	/*
15579acf67fSBill Paul 	 * Free the circleq struct.
15679acf67fSBill Paul 	 */
15779acf67fSBill Paul 	free(q);
15879acf67fSBill Paul 	q = NULL;
15979acf67fSBill Paul 
16079acf67fSBill Paul 	return;
16179acf67fSBill Paul }
16279acf67fSBill Paul 
16379acf67fSBill Paul /*
16479acf67fSBill Paul  * Zorch a single entry in the dbent queue and release
16579acf67fSBill Paul  * all its resources. (This always removes the last entry
16679acf67fSBill Paul  * in the queue.)
16779acf67fSBill Paul  */
16879acf67fSBill Paul static void yp_flush()
16979acf67fSBill Paul {
17079acf67fSBill Paul 	register struct circleq_entry *qptr;
17179acf67fSBill Paul 
17279acf67fSBill Paul 	qptr = qhead.cqh_last;
17379acf67fSBill Paul 	CIRCLEQ_REMOVE(&qhead, qptr, links);
17479acf67fSBill Paul 	yp_free_qent(qptr);
17579acf67fSBill Paul 	numdbs--;
17679acf67fSBill Paul 
17779acf67fSBill Paul 	return;
17879acf67fSBill Paul }
17979acf67fSBill Paul 
18079acf67fSBill Paul /*
18179acf67fSBill Paul  * Close all databases, erase all database names and empty the queue.
182b2264be8SBill Paul  */
183b2264be8SBill Paul void yp_flush_all()
184b2264be8SBill Paul {
18579acf67fSBill Paul 	register struct circleq_entry *qptr;
186b2264be8SBill Paul 
18779acf67fSBill Paul 	while(qhead.cqh_first != (void *)&qhead) {
18879acf67fSBill Paul 		qptr = qhead.cqh_first; /* save this */
18979acf67fSBill Paul 		CIRCLEQ_REMOVE(&qhead, qhead.cqh_first, links);
19079acf67fSBill Paul 		yp_free_qent(qptr);
191b2264be8SBill Paul 	}
19279acf67fSBill Paul 	numdbs = 0;
19379acf67fSBill Paul 
19479acf67fSBill Paul 	return;
195b2264be8SBill Paul }
196b2264be8SBill Paul 
19744519760SBill Paul static char *inter_string = "YP_INTERDOMAIN";
19844519760SBill Paul static char *secure_string = "YP_SECURE";
19944519760SBill Paul static int inter_sz = sizeof("YP_INTERDOMAIN") - 1;
20044519760SBill Paul static int secure_sz = sizeof("YP_SECURE") - 1;
20144519760SBill Paul 
20244519760SBill Paul static int yp_setflags(dbp)
20344519760SBill Paul 	DB *dbp;
20444519760SBill Paul {
20544519760SBill Paul 	DBT key = { NULL, 0 }, data = { NULL, 0 };
20644519760SBill Paul 	int flags = 0;
20744519760SBill Paul 
20844519760SBill Paul 	key.data = inter_string;
20944519760SBill Paul 	key.size = inter_sz;
21044519760SBill Paul 
21144519760SBill Paul 	if (!(dbp->get)(dbp, &key, &data, 0))
21244519760SBill Paul 		flags |= YP_INTERDOMAIN;
21344519760SBill Paul 
21444519760SBill Paul 	key.data = secure_string;
21544519760SBill Paul 	key.size = secure_sz;
21644519760SBill Paul 
21744519760SBill Paul 	if (!(dbp->get)(dbp, &key, &data, 0))
21844519760SBill Paul 		flags |= YP_SECURE;
21944519760SBill Paul 
22044519760SBill Paul 	return(flags);
22144519760SBill Paul }
22244519760SBill Paul 
22344519760SBill Paul int yp_testflag(map, domain, flag)
22444519760SBill Paul 	char *map;
22544519760SBill Paul 	char *domain;
22644519760SBill Paul 	int flag;
22744519760SBill Paul {
22844519760SBill Paul 	char buf[MAXPATHLEN + 2];
22944519760SBill Paul 	register struct circleq_entry *qptr;
23044519760SBill Paul 
23144519760SBill Paul 	if (map == NULL || domain == NULL)
23244519760SBill Paul 		return(0);
23344519760SBill Paul 
23444519760SBill Paul 	strcpy(buf, domain);
23544519760SBill Paul 	strcat(buf, "/");
23644519760SBill Paul 	strcat(buf, map);
23744519760SBill Paul 
23844519760SBill Paul 	for (qptr = qhead.cqh_first; qptr != (void *)&qhead;
23944519760SBill Paul 						qptr = qptr->links.cqe_next) {
24044519760SBill Paul 		if (!strcmp(qptr->dbptr->name, buf)) {
24144519760SBill Paul 			if (qptr->dbptr->flags & flag)
24244519760SBill Paul 				return(1);
24344519760SBill Paul 			else
24444519760SBill Paul 				return(0);
24544519760SBill Paul 		}
24644519760SBill Paul 	}
24744519760SBill Paul 
24844519760SBill Paul 	if (yp_open_db_cache(domain, map, NULL, 0) == NULL)
24944519760SBill Paul 		return(0);
25044519760SBill Paul 
25144519760SBill Paul 	if (qhead.cqh_first->dbptr->flags & flag)
25244519760SBill Paul 		return(1);
25344519760SBill Paul 
25444519760SBill Paul 	return(0);
25544519760SBill Paul }
256b2264be8SBill Paul 
257b2264be8SBill Paul /*
258b2264be8SBill Paul  * Add a DB handle and database name to the cache. We only maintain
259b2264be8SBill Paul  * fixed number of entries in the cache, so if we're asked to store
260b2264be8SBill Paul  * a new entry when all our slots are already filled, we have to kick
261b2264be8SBill Paul  * out the entry in the last slot to make room.
262b2264be8SBill Paul  */
26379acf67fSBill Paul static int yp_cache_db(dbp, name, size)
264b2264be8SBill Paul 	DB *dbp;
265b2264be8SBill Paul 	char *name;
266b2264be8SBill Paul 	int size;
267b2264be8SBill Paul {
26879acf67fSBill Paul 	register struct circleq_entry *qptr;
269b2264be8SBill Paul 
27079acf67fSBill Paul 	if (numdbs == MAXDBS) {
271b2264be8SBill Paul 		if (ypdb_debug)
27279acf67fSBill Paul 			yp_error("queue overflow -- releasing last slot");
27379acf67fSBill Paul 		yp_flush();
274b2264be8SBill Paul 	}
275b2264be8SBill Paul 
276b2264be8SBill Paul 	/*
27779acf67fSBill Paul 	 * Allocate a new queue entry.
278b2264be8SBill Paul 	 */
27979acf67fSBill Paul 
28079acf67fSBill Paul 	if ((qptr = yp_malloc_qent()) == NULL) {
28179acf67fSBill Paul 		yp_error("failed to allocate a new cache entry");
28279acf67fSBill Paul 		return(1);
283b2264be8SBill Paul 	}
284b2264be8SBill Paul 
28579acf67fSBill Paul 	qptr->dbptr->dbp = dbp;
28679acf67fSBill Paul 	qptr->dbptr->name = strdup(name);
28779acf67fSBill Paul 	qptr->dbptr->size = size;
28879acf67fSBill Paul 	qptr->dbptr->key = NULL;
28979acf67fSBill Paul 
29044519760SBill Paul 	qptr->dbptr->flags = yp_setflags(dbp);
29144519760SBill Paul 
29279acf67fSBill Paul 	CIRCLEQ_INSERT_HEAD(&qhead, qptr, links);
293b2264be8SBill Paul 	numdbs++;
29479acf67fSBill Paul 
29579acf67fSBill Paul 	return(0);
296b2264be8SBill Paul }
297b2264be8SBill Paul 
298b2264be8SBill Paul /*
299b2264be8SBill Paul  * Search the list for a database matching 'name.' If we find it,
300b2264be8SBill Paul  * move it to the head of the list and return its DB handle. If
301b2264be8SBill Paul  * not, just fail: yp_open_db_cache() will subsequently try to open
30279acf67fSBill Paul  * the database itself and call yp_cache_db() to add it to the
303b2264be8SBill Paul  * list.
304b2264be8SBill Paul  *
305b2264be8SBill Paul  * The search works like this:
306b2264be8SBill Paul  *
307b2264be8SBill Paul  * - The caller specifies the name of a database to locate. We try to
30879acf67fSBill Paul  *   find an entry in our queue with a matching name.
309b2264be8SBill Paul  *
310b2264be8SBill Paul  * - If the caller doesn't specify a key or size, we assume that the
311b2264be8SBill Paul  *   first entry that we encounter with a matching name is returned.
31279acf67fSBill Paul  *   This will result in matches regardless of the key/size values
31379acf67fSBill Paul  *   stored in the queue entry.
314b2264be8SBill Paul  *
31579acf67fSBill Paul  * - If the caller also specifies a key and length, we check to see
31679acf67fSBill Paul  *   if the key and length saved in the queue entry also matches.
317b2264be8SBill Paul  *   This lets us return a DB handle that's already positioned at the
318b2264be8SBill Paul  *   correct location within a database.
319b2264be8SBill Paul  *
32079acf67fSBill Paul  * - Once we have a match, it gets migrated to the top of the queue
32179acf67fSBill Paul  *   so that it will be easier to find if another request for
322b2264be8SBill Paul  *   the same database comes in later.
323b2264be8SBill Paul  */
324b3e93234SBill Paul static DB *yp_find_db(name, key, size)
325b2264be8SBill Paul 	char *name;
326b2264be8SBill Paul 	char *key;
3271fbdac93SBill Paul 	int size;
328b2264be8SBill Paul {
32979acf67fSBill Paul 	register struct circleq_entry *qptr;
330b2264be8SBill Paul 
33179acf67fSBill Paul 	for (qptr = qhead.cqh_first; qptr != (void *)&qhead;
33279acf67fSBill Paul 						qptr = qptr->links.cqe_next) {
33379acf67fSBill Paul 		if (!strcmp(qptr->dbptr->name, name)) {
334b2264be8SBill Paul 			if (size) {
33579acf67fSBill Paul 				if (size != qptr->dbptr->size ||
33679acf67fSBill Paul 				   strncmp(qptr->dbptr->key, key, size))
337b2264be8SBill Paul 					continue;
338b2264be8SBill Paul 			} else {
33979acf67fSBill Paul 				if (qptr->dbptr->size)
340b2264be8SBill Paul 					continue;
341b2264be8SBill Paul 			}
34279acf67fSBill Paul 			if (qptr != qhead.cqh_first) {
34379acf67fSBill Paul 				CIRCLEQ_REMOVE(&qhead, qptr, links);
34479acf67fSBill Paul 				CIRCLEQ_INSERT_HEAD(&qhead, qptr, links);
345b2264be8SBill Paul 			}
34679acf67fSBill Paul 			return(qptr->dbptr->dbp);
347b2264be8SBill Paul 		}
348b2264be8SBill Paul 	}
349b3e93234SBill Paul 
350b2264be8SBill Paul 	return(NULL);
351b2264be8SBill Paul }
352b2264be8SBill Paul 
353b2264be8SBill Paul /*
354b2264be8SBill Paul  * Open a DB database and cache the handle for later use. We first
355b2264be8SBill Paul  * check the cache to see if the required database is already open.
356b2264be8SBill Paul  * If so, we fetch the handle from the cache. If not, we try to open
357b2264be8SBill Paul  * the database and save the handle in the cache for later use.
358b2264be8SBill Paul  */
359b2264be8SBill Paul DB *yp_open_db_cache(domain, map, key, size)
360b2264be8SBill Paul 	const char *domain;
361b2264be8SBill Paul 	const char *map;
362b2264be8SBill Paul 	const char *key;
363b2264be8SBill Paul 	const int size;
364b2264be8SBill Paul {
365b2264be8SBill Paul 	DB *dbp = NULL;
366b2264be8SBill Paul 	char buf[MAXPATHLEN + 2];
367b3e93234SBill Paul /*
368b3e93234SBill Paul 	snprintf(buf, sizeof(buf), "%s/%s", domain, map);
369b3e93234SBill Paul */
37079acf67fSBill Paul 	yp_errno = YP_TRUE;
371b2264be8SBill Paul 
3721fbdac93SBill Paul 	strcpy(buf, domain);
3731fbdac93SBill Paul 	strcat(buf, "/");
3741fbdac93SBill Paul 	strcat(buf, map);
375b2264be8SBill Paul 
376b2264be8SBill Paul 	if ((dbp = yp_find_db((char *)&buf, key, size)) != NULL) {
377b2264be8SBill Paul 		return(dbp);
378b2264be8SBill Paul 	} else {
37979acf67fSBill Paul 		if ((dbp = yp_open_db(domain, map)) != NULL) {
38079acf67fSBill Paul 			if (yp_cache_db(dbp, (char *)&buf, size)) {
38179acf67fSBill Paul 				(void)(dbp->close)(dbp);
38279acf67fSBill Paul 				yp_errno = YP_YPERR;
38379acf67fSBill Paul 				return(NULL);
38479acf67fSBill Paul 			}
38579acf67fSBill Paul 		}
386b2264be8SBill Paul 	}
387b2264be8SBill Paul 
388b2264be8SBill Paul 	return (dbp);
389b2264be8SBill Paul }
390b2264be8SBill Paul #endif
391b2264be8SBill Paul 
392b2264be8SBill Paul /*
393b2264be8SBill Paul  * Open a DB database.
394778c7b1cSBill Paul  */
395778c7b1cSBill Paul DB *yp_open_db(domain, map)
396778c7b1cSBill Paul 	const char *domain;
397778c7b1cSBill Paul 	const char *map;
398778c7b1cSBill Paul {
399b2264be8SBill Paul 	DB *dbp = NULL;
400b2264be8SBill Paul 	char buf[MAXPATHLEN + 2];
401778c7b1cSBill Paul 
402778c7b1cSBill Paul 	yp_errno = YP_TRUE;
403778c7b1cSBill Paul 
404778c7b1cSBill Paul 	if (map[0] == '.' || strchr(map, '/')) {
405778c7b1cSBill Paul 		yp_errno = YP_BADARGS;
406778c7b1cSBill Paul 		return (NULL);
407778c7b1cSBill Paul 	}
408778c7b1cSBill Paul 
409b2264be8SBill Paul #ifdef DB_CACHE
410b2264be8SBill Paul 	if (yp_validdomain(domain)) {
411b2264be8SBill Paul 		yp_errno = YP_NODOM;
412b2264be8SBill Paul 		return(NULL);
413b2264be8SBill Paul 	}
414b2264be8SBill Paul #endif
415778c7b1cSBill Paul 	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, domain, map);
416778c7b1cSBill Paul 
417b2264be8SBill Paul #ifdef DB_CACHE
418b2264be8SBill Paul again:
419b2264be8SBill Paul #endif
420b2264be8SBill Paul 	dbp = dbopen(buf,O_RDONLY, PERM_SECURE, DB_HASH, NULL);
421778c7b1cSBill Paul 
422778c7b1cSBill Paul 	if (dbp == NULL) {
423778c7b1cSBill Paul 		switch(errno) {
424b2264be8SBill Paul #ifdef DB_CACHE
425b2264be8SBill Paul 		case ENFILE:
426b2264be8SBill Paul 			/*
427b2264be8SBill Paul 			 * We ran out of file descriptors. Nuke an
428b2264be8SBill Paul 			 * open one and try again.
429b2264be8SBill Paul 			 */
430b2264be8SBill Paul 			yp_error("ran out of file descriptors");
43179acf67fSBill Paul 			yp_flush();
432b2264be8SBill Paul 			goto again;
433b2264be8SBill Paul 			break;
434b2264be8SBill Paul #endif
435778c7b1cSBill Paul 		case ENOENT:
436778c7b1cSBill Paul 			yp_errno = YP_NOMAP;
437778c7b1cSBill Paul 			break;
438778c7b1cSBill Paul 		case EFTYPE:
439778c7b1cSBill Paul 			yp_errno = YP_BADDB;
440778c7b1cSBill Paul 			break;
441778c7b1cSBill Paul 		default:
442778c7b1cSBill Paul 			yp_errno = YP_YPERR;
443778c7b1cSBill Paul 			break;
444778c7b1cSBill Paul 		}
445778c7b1cSBill Paul 	}
446778c7b1cSBill Paul 
447778c7b1cSBill Paul 	return (dbp);
448778c7b1cSBill Paul }
449778c7b1cSBill Paul 
450778c7b1cSBill Paul /*
451778c7b1cSBill Paul  * Database access routines.
452778c7b1cSBill Paul  *
453778c7b1cSBill Paul  * - yp_get_record(): retrieve an arbitrary key/data pair given one key
454778c7b1cSBill Paul  *                 to match against.
455778c7b1cSBill Paul  *
456778c7b1cSBill Paul  * - yp_first_record(): retrieve first key/data base in a database.
457778c7b1cSBill Paul  *
458778c7b1cSBill Paul  * - yp_next_record(): retrieve key/data pair that sequentially follows
459778c7b1cSBill Paul  *                   the supplied key value in the database.
460778c7b1cSBill Paul  */
461778c7b1cSBill Paul 
462180807d2SBill Paul #ifdef DB_CACHE
463180807d2SBill Paul int yp_get_record(dbp,key,data,allow)
464180807d2SBill Paul 	DB *dbp;
465180807d2SBill Paul #else
466778c7b1cSBill Paul int yp_get_record(domain,map,key,data,allow)
467778c7b1cSBill Paul 	const char *domain;
468778c7b1cSBill Paul 	const char *map;
469180807d2SBill Paul #endif
470778c7b1cSBill Paul 	const DBT *key;
471778c7b1cSBill Paul 	DBT *data;
472778c7b1cSBill Paul 	int allow;
473778c7b1cSBill Paul {
474180807d2SBill Paul #ifndef DB_CACHE
475778c7b1cSBill Paul 	DB *dbp;
476180807d2SBill Paul #endif
477b2264be8SBill Paul 	int rval = 0;
47879acf67fSBill Paul #ifndef DB_CACHE
47979acf67fSBill Paul 	static unsigned char buf[YPMAXRECORD];
48079acf67fSBill Paul #endif
481778c7b1cSBill Paul 
48277732bc5SBill Paul 	if (ypdb_debug)
483180807d2SBill Paul 		yp_error("Looking up key [%.*s]",
484180807d2SBill Paul 			  key->size, key->data);
485778c7b1cSBill Paul 
486778c7b1cSBill Paul 	/*
487778c7b1cSBill Paul 	 * Avoid passing back magic "YP_*" entries unless
488778c7b1cSBill Paul 	 * the caller specifically requested them by setting
489778c7b1cSBill Paul 	 * the 'allow' flag.
490778c7b1cSBill Paul 	 */
491778c7b1cSBill Paul 	if (!allow && !strncmp(key->data, "YP_", 3))
492778c7b1cSBill Paul 		return(YP_NOKEY);
493778c7b1cSBill Paul 
494180807d2SBill Paul #ifndef DB_CACHE
495778c7b1cSBill Paul 	if ((dbp = yp_open_db(domain, map)) == NULL) {
496778c7b1cSBill Paul 		return(yp_errno);
497778c7b1cSBill Paul 	}
498180807d2SBill Paul #endif
499778c7b1cSBill Paul 
500920491cfSBill Paul 	if ((rval = (dbp->get)(dbp, key, data, 0)) != 0) {
501b2264be8SBill Paul #ifdef DB_CACHE
50279acf67fSBill Paul 		qhead.cqh_first->dbptr->size = 0;
503b2264be8SBill Paul #else
504778c7b1cSBill Paul 		(void)(dbp->close)(dbp);
505b2264be8SBill Paul #endif
506920491cfSBill Paul 		if (rval == 1)
507778c7b1cSBill Paul 			return(YP_NOKEY);
508920491cfSBill Paul 		else
509920491cfSBill Paul 			return(YP_BADDB);
510778c7b1cSBill Paul 	}
511778c7b1cSBill Paul 
51277732bc5SBill Paul 	if (ypdb_debug)
513778c7b1cSBill Paul 		yp_error("Result of lookup: key: [%.*s] data: [%.*s]",
514778c7b1cSBill Paul 			 key->size, key->data, data->size, data->data);
515778c7b1cSBill Paul 
516b2264be8SBill Paul #ifdef DB_CACHE
51779acf67fSBill Paul 	if (qhead.cqh_first->dbptr->size) {
51879acf67fSBill Paul 		qhead.cqh_first->dbptr->key = key->data;
51979acf67fSBill Paul 		qhead.cqh_first->dbptr->size = key->size;
520b2264be8SBill Paul 	}
521b2264be8SBill Paul #else
52279acf67fSBill Paul 	bcopy((char *)data->data, (char *)&buf, data->size);
52379acf67fSBill Paul 	data->data = (void *)&buf;
524b2264be8SBill Paul 	(void)(dbp->close)(dbp);
525b2264be8SBill Paul #endif
526b2264be8SBill Paul 
527778c7b1cSBill Paul 	return(YP_TRUE);
528778c7b1cSBill Paul }
529778c7b1cSBill Paul 
530b2264be8SBill Paul int yp_first_record(dbp,key,data,allow)
531778c7b1cSBill Paul 	const DB *dbp;
532778c7b1cSBill Paul 	DBT *key;
533778c7b1cSBill Paul 	DBT *data;
534b2264be8SBill Paul 	int allow;
535778c7b1cSBill Paul {
536920491cfSBill Paul 	int rval;
53779acf67fSBill Paul #ifndef DB_CACHE
53879acf67fSBill Paul 	static unsigned char buf[YPMAXRECORD];
53979acf67fSBill Paul #endif
540778c7b1cSBill Paul 
54177732bc5SBill Paul 	if (ypdb_debug)
542778c7b1cSBill Paul 		yp_error("Retrieving first key in map.");
543778c7b1cSBill Paul 
544920491cfSBill Paul 	if ((rval = (dbp->seq)(dbp,key,data,R_FIRST)) != 0) {
545b2264be8SBill Paul #ifdef DB_CACHE
54679acf67fSBill Paul 		qhead.cqh_first->dbptr->size = 0;
547b2264be8SBill Paul #endif
548920491cfSBill Paul 		if (rval == 1)
549920491cfSBill Paul 			return(YP_NOKEY);
550920491cfSBill Paul 		else
551778c7b1cSBill Paul 			return(YP_BADDB);
552920491cfSBill Paul 	}
553778c7b1cSBill Paul 
554778c7b1cSBill Paul 	/* Avoid passing back magic "YP_*" records. */
555b2264be8SBill Paul 	while (!strncmp(key->data, "YP_", 3) && !allow) {
556920491cfSBill Paul 		if ((rval = (dbp->seq)(dbp,key,data,R_NEXT)) != 0) {
557b2264be8SBill Paul #ifdef DB_CACHE
55879acf67fSBill Paul 			qhead.cqh_first->dbptr->size = 0;
559b2264be8SBill Paul #endif
560920491cfSBill Paul 			if (rval == 1)
561920491cfSBill Paul 				return(YP_NOKEY);
562920491cfSBill Paul 			else
563778c7b1cSBill Paul 				return(YP_BADDB);
564778c7b1cSBill Paul 		}
565920491cfSBill Paul 	}
566778c7b1cSBill Paul 
56777732bc5SBill Paul 	if (ypdb_debug)
568778c7b1cSBill Paul 		yp_error("Result of lookup: key: [%.*s] data: [%.*s]",
569778c7b1cSBill Paul 			 key->size, key->data, data->size, data->data);
570778c7b1cSBill Paul 
571b2264be8SBill Paul #ifdef DB_CACHE
57279acf67fSBill Paul 	if (qhead.cqh_first->dbptr->size) {
57379acf67fSBill Paul 		qhead.cqh_first->dbptr->key = key->data;
57479acf67fSBill Paul 		qhead.cqh_first->dbptr->size = key->size;
575b2264be8SBill Paul 	}
57679acf67fSBill Paul #else
57779acf67fSBill Paul 	bcopy((char *)data->data, (char *)&buf, data->size);
57879acf67fSBill Paul 	data->data = (void *)&buf;
579b2264be8SBill Paul #endif
580b2264be8SBill Paul 
581778c7b1cSBill Paul 	return(YP_TRUE);
582778c7b1cSBill Paul }
583778c7b1cSBill Paul 
584b2264be8SBill Paul int yp_next_record(dbp,key,data,all,allow)
585778c7b1cSBill Paul 	const DB *dbp;
586778c7b1cSBill Paul 	DBT *key;
587778c7b1cSBill Paul 	DBT *data;
588778c7b1cSBill Paul 	int all;
589b2264be8SBill Paul 	int allow;
590778c7b1cSBill Paul {
591b2264be8SBill Paul 	static DBT lkey = { NULL, 0 };
592b2264be8SBill Paul 	static DBT ldata = { NULL, 0 };
593920491cfSBill Paul 	int rval;
59479acf67fSBill Paul #ifndef DB_CACHE
59579acf67fSBill Paul 	static unsigned char keybuf[YPMAXRECORD];
59679acf67fSBill Paul 	static unsigned char datbuf[YPMAXRECORD];
59779acf67fSBill Paul #endif
598778c7b1cSBill Paul 
599180807d2SBill Paul 	if (key == NULL || !key->size || key->data == NULL) {
600b2264be8SBill Paul 		rval = yp_first_record(dbp,key,data,allow);
601920491cfSBill Paul 		if (rval == YP_NOKEY)
602920491cfSBill Paul 			return(YP_NOMORE);
603559605f1SBill Paul 		else {
604559605f1SBill Paul #ifdef DB_CACHE
605559605f1SBill Paul 			qhead.cqh_first->dbptr->key = key->data;
606559605f1SBill Paul 			qhead.cqh_first->dbptr->size = key->size;
607559605f1SBill Paul #endif
608920491cfSBill Paul 			return(rval);
609920491cfSBill Paul 		}
610559605f1SBill Paul 	}
611778c7b1cSBill Paul 
61277732bc5SBill Paul 	if (ypdb_debug)
613778c7b1cSBill Paul 		yp_error("Retreiving next key, previous was: [%.*s]",
614778c7b1cSBill Paul 			  key->size, key->data);
615778c7b1cSBill Paul 
616778c7b1cSBill Paul 	if (!all) {
617b3e93234SBill Paul #ifdef DB_CACHE
61879acf67fSBill Paul 		if (qhead.cqh_first->dbptr->key == NULL) {
619b2264be8SBill Paul #endif
620778c7b1cSBill Paul 			(dbp->seq)(dbp,&lkey,&ldata,R_FIRST);
621b2264be8SBill Paul 			while(strncmp((char *)key->data,lkey.data,
622b2264be8SBill Paul 				(int)key->size) || key->size != lkey.size)
623b3e93234SBill Paul 				if ((dbp->seq)(dbp,&lkey,&ldata,R_NEXT)) {
624b3e93234SBill Paul #ifdef DB_CACHE
62579acf67fSBill Paul 					qhead.cqh_first->dbptr->size = 0;
626b3e93234SBill Paul #endif
627b3e93234SBill Paul 					return(YP_NOKEY);
628778c7b1cSBill Paul 				}
629b3e93234SBill Paul 
630b3e93234SBill Paul #ifdef DB_CACHE
631b3e93234SBill Paul 		}
632b3e93234SBill Paul #endif
633b2264be8SBill Paul 	}
634778c7b1cSBill Paul 
635b2264be8SBill Paul 	if ((dbp->seq)(dbp,key,data,R_NEXT)) {
636b2264be8SBill Paul #ifdef DB_CACHE
63779acf67fSBill Paul 		qhead.cqh_first->dbptr->size = 0;
638b2264be8SBill Paul #endif
639778c7b1cSBill Paul 		return(YP_NOMORE);
640b2264be8SBill Paul 	}
641778c7b1cSBill Paul 
642778c7b1cSBill Paul 	/* Avoid passing back magic "YP_*" records. */
643b2264be8SBill Paul 	while (!strncmp(key->data, "YP_", 3) && !allow)
644b2264be8SBill Paul 		if ((dbp->seq)(dbp,key,data,R_NEXT)) {
645b2264be8SBill Paul #ifdef DB_CACHE
64679acf67fSBill Paul 		qhead.cqh_first->dbptr->size = 0;
647b2264be8SBill Paul #endif
648778c7b1cSBill Paul 			return(YP_NOMORE);
649b2264be8SBill Paul 		}
650778c7b1cSBill Paul 
65177732bc5SBill Paul 	if (ypdb_debug)
652778c7b1cSBill Paul 		yp_error("Result of lookup: key: [%.*s] data: [%.*s]",
653778c7b1cSBill Paul 			 key->size, key->data, data->size, data->data);
654778c7b1cSBill Paul 
655b2264be8SBill Paul #ifdef DB_CACHE
65679acf67fSBill Paul 	if (qhead.cqh_first->dbptr->size) {
65779acf67fSBill Paul 		qhead.cqh_first->dbptr->key = key->data;
65879acf67fSBill Paul 		qhead.cqh_first->dbptr->size = key->size;
659b2264be8SBill Paul 	}
660b2264be8SBill Paul #else
66179acf67fSBill Paul 	bcopy((char *)key->data, (char *)&keybuf, key->size);
66279acf67fSBill Paul 	lkey.data = (void *)&keybuf;
663b2264be8SBill Paul 	lkey.size = key->size;
66479acf67fSBill Paul 	bcopy((char *)data->data, (char *)&datbuf, data->size);
66579acf67fSBill Paul 	data->data = (void *)&datbuf;
666b2264be8SBill Paul #endif
667b2264be8SBill Paul 
668778c7b1cSBill Paul 	return(YP_TRUE);
669778c7b1cSBill Paul }
670180807d2SBill Paul 
671180807d2SBill Paul #ifdef DB_CACHE
672180807d2SBill Paul /*
673180807d2SBill Paul  * Database glue functions.
674180807d2SBill Paul  */
675180807d2SBill Paul 
676180807d2SBill Paul static DB *yp_currmap_db = NULL;
677180807d2SBill Paul static int yp_allow_db = 0;
678180807d2SBill Paul 
679180807d2SBill Paul ypstat yp_select_map(map, domain, key, allow)
680180807d2SBill Paul 	char *map;
681180807d2SBill Paul 	char *domain;
682180807d2SBill Paul 	keydat *key;
683180807d2SBill Paul 	int allow;
684180807d2SBill Paul {
685180807d2SBill Paul 	yp_currmap_db = yp_open_db_cache(domain, map, key->keydat_val,
686180807d2SBill Paul 							key->keydat_len);
687180807d2SBill Paul 
688180807d2SBill Paul 	yp_allow_db = allow;
689180807d2SBill Paul 	return(yp_errno);
690180807d2SBill Paul }
691180807d2SBill Paul 
692180807d2SBill Paul ypstat yp_getbykey(key, val)
693180807d2SBill Paul 	keydat *key;
694180807d2SBill Paul 	valdat *val;
695180807d2SBill Paul {
696180807d2SBill Paul 	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
697180807d2SBill Paul 	ypstat rval;
698180807d2SBill Paul 
699180807d2SBill Paul 	db_key.data = key->keydat_val;
700180807d2SBill Paul 	db_key.size = key->keydat_len;
701180807d2SBill Paul 
702180807d2SBill Paul 	rval = yp_get_record(yp_currmap_db,
703180807d2SBill Paul 				&db_key, &db_val, yp_allow_db);
704180807d2SBill Paul 
705180807d2SBill Paul 	if (rval == YP_TRUE) {
706180807d2SBill Paul 		val->valdat_val = db_val.data;
707180807d2SBill Paul 		val->valdat_len = db_val.size;
708180807d2SBill Paul 	}
709180807d2SBill Paul 
710180807d2SBill Paul 	return(rval);
711180807d2SBill Paul }
712180807d2SBill Paul 
713180807d2SBill Paul ypstat yp_firstbykey(key, val)
714180807d2SBill Paul 	keydat *key;
715180807d2SBill Paul 	valdat *val;
716180807d2SBill Paul {
717180807d2SBill Paul 	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
718180807d2SBill Paul 	ypstat rval;
719180807d2SBill Paul 
720180807d2SBill Paul 	rval = yp_first_record(yp_currmap_db, &db_key, &db_val, yp_allow_db);
721180807d2SBill Paul 
722180807d2SBill Paul 	if (rval == YP_TRUE) {
723180807d2SBill Paul 		key->keydat_val = db_key.data;
724180807d2SBill Paul 		key->keydat_len = db_key.size;
725180807d2SBill Paul 		val->valdat_val = db_val.data;
726180807d2SBill Paul 		val->valdat_len = db_val.size;
727180807d2SBill Paul 	}
728180807d2SBill Paul 
729180807d2SBill Paul 	return(rval);
730180807d2SBill Paul }
731180807d2SBill Paul 
732180807d2SBill Paul ypstat yp_nextbykey(key, val)
733180807d2SBill Paul 	keydat *key;
734180807d2SBill Paul 	valdat *val;
735180807d2SBill Paul {
736180807d2SBill Paul 	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
737180807d2SBill Paul 	ypstat rval;
738180807d2SBill Paul 
739180807d2SBill Paul 	db_key.data = key->keydat_val;
740180807d2SBill Paul 	db_key.size = key->keydat_len;
741180807d2SBill Paul 
742180807d2SBill Paul 	rval = yp_next_record(yp_currmap_db, &db_key, &db_val, 0, yp_allow_db);
743180807d2SBill Paul 
744180807d2SBill Paul 	if (rval == YP_TRUE) {
745180807d2SBill Paul 		key->keydat_val = db_key.data;
746180807d2SBill Paul 		key->keydat_len = db_key.size;
747180807d2SBill Paul 		val->valdat_val = db_val.data;
748180807d2SBill Paul 		val->valdat_len = db_val.size;
749180807d2SBill Paul 	}
750180807d2SBill Paul 
751180807d2SBill Paul 	return(rval);
752180807d2SBill Paul }
753180807d2SBill Paul #endif
754