xref: /freebsd/usr.sbin/ypserv/yp_dblookup.c (revision b728350ee67c01f96c3c5121774536fee81ad176)
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  */
32778c7b1cSBill Paul 
33b728350eSDavid E. O'Brien #include <sys/cdefs.h>
34b728350eSDavid E. O'Brien __FBSDID("$FreeBSD$");
3598834523SPhilippe Charnier 
3698834523SPhilippe Charnier #include <db.h>
3798834523SPhilippe Charnier #include <errno.h>
3898834523SPhilippe Charnier #include <fcntl.h>
3998834523SPhilippe Charnier #include <limits.h>
4098834523SPhilippe Charnier #include <paths.h>
4198834523SPhilippe Charnier #include <stdio.h>
4298834523SPhilippe Charnier #include <stdlib.h>
4398834523SPhilippe Charnier #include <string.h>
4498834523SPhilippe Charnier #include <unistd.h>
4598834523SPhilippe Charnier #include <sys/stat.h>
4698834523SPhilippe Charnier #include <sys/param.h>
4798834523SPhilippe Charnier #include <rpcsvc/yp.h>
4898834523SPhilippe Charnier #include "yp_extern.h"
491fbdac93SBill Paul 
5077732bc5SBill Paul int ypdb_debug = 0;
51180807d2SBill Paul enum ypstat yp_errno = YP_TRUE;
52778c7b1cSBill Paul 
53778c7b1cSBill Paul #define PERM_SECURE (S_IRUSR|S_IWUSR)
54778c7b1cSBill Paul HASHINFO openinfo = {
55778c7b1cSBill Paul 	4096,		/* bsize */
56778c7b1cSBill Paul 	32,		/* ffactor */
57b3e93234SBill Paul 	256,		/* nelem */
58b2264be8SBill Paul 	2048 * 512, 	/* cachesize */
59778c7b1cSBill Paul 	NULL,		/* hash */
60778c7b1cSBill Paul 	0,		/* lorder */
61778c7b1cSBill Paul };
62778c7b1cSBill Paul 
63b2264be8SBill Paul #ifdef DB_CACHE
6479acf67fSBill Paul #include <sys/queue.h>
6579acf67fSBill Paul 
6679acf67fSBill Paul #ifndef MAXDBS
67b2264be8SBill Paul #define MAXDBS 20
6879acf67fSBill Paul #endif
6979acf67fSBill Paul 
7079acf67fSBill Paul static int numdbs = 0;
71b2264be8SBill Paul 
72b2264be8SBill Paul struct dbent {
73b2264be8SBill Paul 	DB *dbp;
74b2264be8SBill Paul 	char *name;
75b2264be8SBill Paul 	char *key;
76b2264be8SBill Paul 	int size;
7744519760SBill Paul 	int flags;
78b2264be8SBill Paul };
79b2264be8SBill Paul 
80c5e5cd90SPoul-Henning Kamp static TAILQ_HEAD(circlehead, circleq_entry) qhead;
8179acf67fSBill Paul 
8279acf67fSBill Paul struct circleq_entry {
8379acf67fSBill Paul 	struct dbent *dbptr;
84c5e5cd90SPoul-Henning Kamp 	TAILQ_ENTRY(circleq_entry) links;
8579acf67fSBill Paul };
86b2264be8SBill Paul 
87778c7b1cSBill Paul /*
8879acf67fSBill Paul  * Initialize the circular queue.
89b2264be8SBill Paul  */
90dc584ddbSDag-Erling Smørgrav void
91dc584ddbSDag-Erling Smørgrav yp_init_dbs(void)
92b2264be8SBill Paul {
93c5e5cd90SPoul-Henning Kamp 	TAILQ_INIT(&qhead);
94b2264be8SBill Paul 	return;
95b2264be8SBill Paul }
96b2264be8SBill Paul 
971fbdac93SBill Paul /*
9879acf67fSBill Paul  * Dynamically allocate an entry for the circular queue.
9979acf67fSBill Paul  * Return a NULL pointer on failure.
1001fbdac93SBill Paul  */
101dc584ddbSDag-Erling Smørgrav static struct circleq_entry *
102dc584ddbSDag-Erling Smørgrav yp_malloc_qent(void)
103b2264be8SBill Paul {
10479acf67fSBill Paul 	register struct circleq_entry *q;
10579acf67fSBill Paul 
10679acf67fSBill Paul 	q = (struct circleq_entry *)malloc(sizeof(struct circleq_entry));
10779acf67fSBill Paul 	if (q == NULL) {
10898834523SPhilippe Charnier 		yp_error("failed to malloc() circleq entry");
10979acf67fSBill Paul 		return(NULL);
11079acf67fSBill Paul 	}
11179acf67fSBill Paul 	bzero((char *)q, sizeof(struct circleq_entry));
11279acf67fSBill Paul 	q->dbptr = (struct dbent *)malloc(sizeof(struct dbent));
11379acf67fSBill Paul 	if (q->dbptr == NULL) {
11498834523SPhilippe Charnier 		yp_error("failed to malloc() circleq entry");
11579acf67fSBill Paul 		free(q);
11679acf67fSBill Paul 		return(NULL);
11779acf67fSBill Paul 	}
11879acf67fSBill Paul 	bzero((char *)q->dbptr, sizeof(struct dbent));
11979acf67fSBill Paul 
12079acf67fSBill Paul 	return(q);
121b2264be8SBill Paul }
122b2264be8SBill Paul 
123b2264be8SBill Paul /*
12479acf67fSBill Paul  * Free a previously allocated circular queue
12579acf67fSBill Paul  * entry.
12679acf67fSBill Paul  */
127dc584ddbSDag-Erling Smørgrav static void
128dc584ddbSDag-Erling Smørgrav yp_free_qent(struct circleq_entry *q)
12979acf67fSBill Paul {
13079acf67fSBill Paul 	/*
13179acf67fSBill Paul 	 * First, close the database. In theory, this is also
13279acf67fSBill Paul 	 * supposed to free the resources allocated by the DB
13379acf67fSBill Paul 	 * package, including the memory pointed to by q->dbptr->key.
13479acf67fSBill Paul 	 * This means we don't have to free q->dbptr->key here.
13579acf67fSBill Paul 	 */
13679acf67fSBill Paul 	if (q->dbptr->dbp) {
13779acf67fSBill Paul 		(void)(q->dbptr->dbp->close)(q->dbptr->dbp);
13879acf67fSBill Paul 		q->dbptr->dbp = NULL;
13979acf67fSBill Paul 	}
14079acf67fSBill Paul 	/*
14179acf67fSBill Paul 	 * Then free the database name, which was strdup()'ed.
14279acf67fSBill Paul 	 */
14379acf67fSBill Paul 	free(q->dbptr->name);
14479acf67fSBill Paul 
14579acf67fSBill Paul 	/*
14679acf67fSBill Paul 	 * Free the rest of the dbent struct.
14779acf67fSBill Paul 	 */
14879acf67fSBill Paul 	free(q->dbptr);
14979acf67fSBill Paul 	q->dbptr = NULL;
15079acf67fSBill Paul 
15179acf67fSBill Paul 	/*
15279acf67fSBill Paul 	 * Free the circleq struct.
15379acf67fSBill Paul 	 */
15479acf67fSBill Paul 	free(q);
15579acf67fSBill Paul 	q = NULL;
15679acf67fSBill Paul 
15779acf67fSBill Paul 	return;
15879acf67fSBill Paul }
15979acf67fSBill Paul 
16079acf67fSBill Paul /*
16179acf67fSBill Paul  * Zorch a single entry in the dbent queue and release
16279acf67fSBill Paul  * all its resources. (This always removes the last entry
16379acf67fSBill Paul  * in the queue.)
16479acf67fSBill Paul  */
165dc584ddbSDag-Erling Smørgrav static void
166dc584ddbSDag-Erling Smørgrav yp_flush(void)
16779acf67fSBill Paul {
16879acf67fSBill Paul 	register struct circleq_entry *qptr;
16979acf67fSBill Paul 
170c5e5cd90SPoul-Henning Kamp 	qptr = TAILQ_LAST(&qhead, circlehead);
171c5e5cd90SPoul-Henning Kamp 	TAILQ_REMOVE(&qhead, qptr, links);
17279acf67fSBill Paul 	yp_free_qent(qptr);
17379acf67fSBill Paul 	numdbs--;
17479acf67fSBill Paul 
17579acf67fSBill Paul 	return;
17679acf67fSBill Paul }
17779acf67fSBill Paul 
17879acf67fSBill Paul /*
17979acf67fSBill Paul  * Close all databases, erase all database names and empty the queue.
180b2264be8SBill Paul  */
181dc584ddbSDag-Erling Smørgrav void
182dc584ddbSDag-Erling Smørgrav yp_flush_all(void)
183b2264be8SBill Paul {
18479acf67fSBill Paul 	register struct circleq_entry *qptr;
185b2264be8SBill Paul 
186c5e5cd90SPoul-Henning Kamp 	while (!TAILQ_EMPTY(&qhead)) {
187c5e5cd90SPoul-Henning Kamp 		qptr = TAILQ_FIRST(&qhead); /* save this */
188c5e5cd90SPoul-Henning Kamp 		TAILQ_REMOVE(&qhead, qptr, links);
18979acf67fSBill Paul 		yp_free_qent(qptr);
190b2264be8SBill Paul 	}
19179acf67fSBill Paul 	numdbs = 0;
19279acf67fSBill Paul 
19379acf67fSBill Paul 	return;
194b2264be8SBill Paul }
195b2264be8SBill Paul 
19644519760SBill Paul static char *inter_string = "YP_INTERDOMAIN";
19744519760SBill Paul static char *secure_string = "YP_SECURE";
19844519760SBill Paul static int inter_sz = sizeof("YP_INTERDOMAIN") - 1;
19944519760SBill Paul static int secure_sz = sizeof("YP_SECURE") - 1;
20044519760SBill Paul 
201dc584ddbSDag-Erling Smørgrav static int
202dc584ddbSDag-Erling Smørgrav yp_setflags(DB *dbp)
20344519760SBill Paul {
20444519760SBill Paul 	DBT key = { NULL, 0 }, data = { NULL, 0 };
20544519760SBill Paul 	int flags = 0;
20644519760SBill Paul 
20744519760SBill Paul 	key.data = inter_string;
20844519760SBill Paul 	key.size = inter_sz;
20944519760SBill Paul 
21044519760SBill Paul 	if (!(dbp->get)(dbp, &key, &data, 0))
21144519760SBill Paul 		flags |= YP_INTERDOMAIN;
21244519760SBill Paul 
21344519760SBill Paul 	key.data = secure_string;
21444519760SBill Paul 	key.size = secure_sz;
21544519760SBill Paul 
21644519760SBill Paul 	if (!(dbp->get)(dbp, &key, &data, 0))
21744519760SBill Paul 		flags |= YP_SECURE;
21844519760SBill Paul 
21944519760SBill Paul 	return(flags);
22044519760SBill Paul }
22144519760SBill Paul 
222dc584ddbSDag-Erling Smørgrav int
223dc584ddbSDag-Erling Smørgrav yp_testflag(char *map, char *domain, int flag)
22444519760SBill Paul {
22544519760SBill Paul 	char buf[MAXPATHLEN + 2];
22644519760SBill Paul 	register struct circleq_entry *qptr;
22744519760SBill Paul 
22844519760SBill Paul 	if (map == NULL || domain == NULL)
22944519760SBill Paul 		return(0);
23044519760SBill Paul 
23144519760SBill Paul 	strcpy(buf, domain);
23244519760SBill Paul 	strcat(buf, "/");
23344519760SBill Paul 	strcat(buf, map);
23444519760SBill Paul 
235c5e5cd90SPoul-Henning Kamp 	TAILQ_FOREACH(qptr, &qhead, links) {
23644519760SBill Paul 		if (!strcmp(qptr->dbptr->name, buf)) {
23744519760SBill Paul 			if (qptr->dbptr->flags & flag)
23844519760SBill Paul 				return(1);
23944519760SBill Paul 			else
24044519760SBill Paul 				return(0);
24144519760SBill Paul 		}
24244519760SBill Paul 	}
24344519760SBill Paul 
24444519760SBill Paul 	if (yp_open_db_cache(domain, map, NULL, 0) == NULL)
24544519760SBill Paul 		return(0);
24644519760SBill Paul 
247c5e5cd90SPoul-Henning Kamp 	if (TAILQ_FIRST(&qhead)->dbptr->flags & flag)
24844519760SBill Paul 		return(1);
24944519760SBill Paul 
25044519760SBill Paul 	return(0);
25144519760SBill Paul }
252b2264be8SBill Paul 
253b2264be8SBill Paul /*
254b2264be8SBill Paul  * Add a DB handle and database name to the cache. We only maintain
255b2264be8SBill Paul  * fixed number of entries in the cache, so if we're asked to store
256b2264be8SBill Paul  * a new entry when all our slots are already filled, we have to kick
257b2264be8SBill Paul  * out the entry in the last slot to make room.
258b2264be8SBill Paul  */
259dc584ddbSDag-Erling Smørgrav static int
260dc584ddbSDag-Erling Smørgrav yp_cache_db(DB *dbp, char *name, int size)
261b2264be8SBill Paul {
26279acf67fSBill Paul 	register struct circleq_entry *qptr;
263b2264be8SBill Paul 
26479acf67fSBill Paul 	if (numdbs == MAXDBS) {
265b2264be8SBill Paul 		if (ypdb_debug)
26679acf67fSBill Paul 			yp_error("queue overflow -- releasing last slot");
26779acf67fSBill Paul 		yp_flush();
268b2264be8SBill Paul 	}
269b2264be8SBill Paul 
270b2264be8SBill Paul 	/*
27179acf67fSBill Paul 	 * Allocate a new queue entry.
272b2264be8SBill Paul 	 */
27379acf67fSBill Paul 
27479acf67fSBill Paul 	if ((qptr = yp_malloc_qent()) == NULL) {
27579acf67fSBill Paul 		yp_error("failed to allocate a new cache entry");
27679acf67fSBill Paul 		return(1);
277b2264be8SBill Paul 	}
278b2264be8SBill Paul 
27979acf67fSBill Paul 	qptr->dbptr->dbp = dbp;
28079acf67fSBill Paul 	qptr->dbptr->name = strdup(name);
28179acf67fSBill Paul 	qptr->dbptr->size = size;
28279acf67fSBill Paul 	qptr->dbptr->key = NULL;
28379acf67fSBill Paul 
28444519760SBill Paul 	qptr->dbptr->flags = yp_setflags(dbp);
28544519760SBill Paul 
286c5e5cd90SPoul-Henning Kamp 	TAILQ_INSERT_HEAD(&qhead, qptr, links);
287b2264be8SBill Paul 	numdbs++;
28879acf67fSBill Paul 
28979acf67fSBill Paul 	return(0);
290b2264be8SBill Paul }
291b2264be8SBill Paul 
292b2264be8SBill Paul /*
293b2264be8SBill Paul  * Search the list for a database matching 'name.' If we find it,
294b2264be8SBill Paul  * move it to the head of the list and return its DB handle. If
295b2264be8SBill Paul  * not, just fail: yp_open_db_cache() will subsequently try to open
29679acf67fSBill Paul  * the database itself and call yp_cache_db() to add it to the
297b2264be8SBill Paul  * list.
298b2264be8SBill Paul  *
299b2264be8SBill Paul  * The search works like this:
300b2264be8SBill Paul  *
301b2264be8SBill Paul  * - The caller specifies the name of a database to locate. We try to
30279acf67fSBill Paul  *   find an entry in our queue with a matching name.
303b2264be8SBill Paul  *
304b2264be8SBill Paul  * - If the caller doesn't specify a key or size, we assume that the
305b2264be8SBill Paul  *   first entry that we encounter with a matching name is returned.
30679acf67fSBill Paul  *   This will result in matches regardless of the key/size values
30779acf67fSBill Paul  *   stored in the queue entry.
308b2264be8SBill Paul  *
30979acf67fSBill Paul  * - If the caller also specifies a key and length, we check to see
31079acf67fSBill Paul  *   if the key and length saved in the queue entry also matches.
311b2264be8SBill Paul  *   This lets us return a DB handle that's already positioned at the
312b2264be8SBill Paul  *   correct location within a database.
313b2264be8SBill Paul  *
31479acf67fSBill Paul  * - Once we have a match, it gets migrated to the top of the queue
31579acf67fSBill Paul  *   so that it will be easier to find if another request for
316b2264be8SBill Paul  *   the same database comes in later.
317b2264be8SBill Paul  */
318dc584ddbSDag-Erling Smørgrav static DB *
319f249dbccSDag-Erling Smørgrav yp_find_db(const char *name, const char *key, int size)
320b2264be8SBill Paul {
32179acf67fSBill Paul 	register struct circleq_entry *qptr;
322b2264be8SBill Paul 
323c5e5cd90SPoul-Henning Kamp 	TAILQ_FOREACH(qptr, &qhead, links) {
32479acf67fSBill Paul 		if (!strcmp(qptr->dbptr->name, name)) {
325b2264be8SBill Paul 			if (size) {
32679acf67fSBill Paul 				if (size != qptr->dbptr->size ||
32779acf67fSBill Paul 				   strncmp(qptr->dbptr->key, key, size))
328b2264be8SBill Paul 					continue;
329b2264be8SBill Paul 			} else {
33079acf67fSBill Paul 				if (qptr->dbptr->size)
331b2264be8SBill Paul 					continue;
332b2264be8SBill Paul 			}
333c5e5cd90SPoul-Henning Kamp 			if (qptr != TAILQ_FIRST(&qhead)) {
334c5e5cd90SPoul-Henning Kamp 				TAILQ_REMOVE(&qhead, qptr, links);
335c5e5cd90SPoul-Henning Kamp 				TAILQ_INSERT_HEAD(&qhead, qptr, links);
336b2264be8SBill Paul 			}
33779acf67fSBill Paul 			return(qptr->dbptr->dbp);
338b2264be8SBill Paul 		}
339b2264be8SBill Paul 	}
340b3e93234SBill Paul 
341b2264be8SBill Paul 	return(NULL);
342b2264be8SBill Paul }
343b2264be8SBill Paul 
344b2264be8SBill Paul /*
345b2264be8SBill Paul  * Open a DB database and cache the handle for later use. We first
346b2264be8SBill Paul  * check the cache to see if the required database is already open.
347b2264be8SBill Paul  * If so, we fetch the handle from the cache. If not, we try to open
348b2264be8SBill Paul  * the database and save the handle in the cache for later use.
349b2264be8SBill Paul  */
350dc584ddbSDag-Erling Smørgrav DB *
351dc584ddbSDag-Erling Smørgrav yp_open_db_cache(const char *domain, const char *map, const char *key,
352dc584ddbSDag-Erling Smørgrav     const int size)
353b2264be8SBill Paul {
354b2264be8SBill Paul 	DB *dbp = NULL;
355b2264be8SBill Paul 	char buf[MAXPATHLEN + 2];
356b3e93234SBill Paul /*
357b3e93234SBill Paul 	snprintf(buf, sizeof(buf), "%s/%s", domain, map);
358b3e93234SBill Paul */
35979acf67fSBill Paul 	yp_errno = YP_TRUE;
360b2264be8SBill Paul 
3611fbdac93SBill Paul 	strcpy(buf, domain);
3621fbdac93SBill Paul 	strcat(buf, "/");
3631fbdac93SBill Paul 	strcat(buf, map);
364b2264be8SBill Paul 
365f249dbccSDag-Erling Smørgrav 	if ((dbp = yp_find_db(buf, key, size)) != NULL) {
366b2264be8SBill Paul 		return(dbp);
367b2264be8SBill Paul 	} else {
36879acf67fSBill Paul 		if ((dbp = yp_open_db(domain, map)) != NULL) {
369f249dbccSDag-Erling Smørgrav 			if (yp_cache_db(dbp, buf, size)) {
37079acf67fSBill Paul 				(void)(dbp->close)(dbp);
37179acf67fSBill Paul 				yp_errno = YP_YPERR;
37279acf67fSBill Paul 				return(NULL);
37379acf67fSBill Paul 			}
37479acf67fSBill Paul 		}
375b2264be8SBill Paul 	}
376b2264be8SBill Paul 
377b2264be8SBill Paul 	return (dbp);
378b2264be8SBill Paul }
379b2264be8SBill Paul #endif
380b2264be8SBill Paul 
381b2264be8SBill Paul /*
382b2264be8SBill Paul  * Open a DB database.
383778c7b1cSBill Paul  */
384dc584ddbSDag-Erling Smørgrav DB *
385dc584ddbSDag-Erling Smørgrav yp_open_db(const char *domain, const char *map)
386778c7b1cSBill Paul {
387b2264be8SBill Paul 	DB *dbp = NULL;
388b2264be8SBill Paul 	char buf[MAXPATHLEN + 2];
389778c7b1cSBill Paul 
390778c7b1cSBill Paul 	yp_errno = YP_TRUE;
391778c7b1cSBill Paul 
392778c7b1cSBill Paul 	if (map[0] == '.' || strchr(map, '/')) {
393778c7b1cSBill Paul 		yp_errno = YP_BADARGS;
394778c7b1cSBill Paul 		return (NULL);
395778c7b1cSBill Paul 	}
396778c7b1cSBill Paul 
397b2264be8SBill Paul #ifdef DB_CACHE
398b2264be8SBill Paul 	if (yp_validdomain(domain)) {
399b2264be8SBill Paul 		yp_errno = YP_NODOM;
400b2264be8SBill Paul 		return(NULL);
401b2264be8SBill Paul 	}
402b2264be8SBill Paul #endif
403778c7b1cSBill Paul 	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, domain, map);
404778c7b1cSBill Paul 
405b2264be8SBill Paul #ifdef DB_CACHE
406b2264be8SBill Paul again:
407b2264be8SBill Paul #endif
408b2264be8SBill Paul 	dbp = dbopen(buf,O_RDONLY, PERM_SECURE, DB_HASH, NULL);
409778c7b1cSBill Paul 
410778c7b1cSBill Paul 	if (dbp == NULL) {
411778c7b1cSBill Paul 		switch (errno) {
412b2264be8SBill Paul #ifdef DB_CACHE
413b2264be8SBill Paul 		case ENFILE:
414b2264be8SBill Paul 			/*
415b2264be8SBill Paul 			 * We ran out of file descriptors. Nuke an
416b2264be8SBill Paul 			 * open one and try again.
417b2264be8SBill Paul 			 */
418b2264be8SBill Paul 			yp_error("ran out of file descriptors");
41979acf67fSBill Paul 			yp_flush();
420b2264be8SBill Paul 			goto again;
421b2264be8SBill Paul 			break;
422b2264be8SBill Paul #endif
423778c7b1cSBill Paul 		case ENOENT:
424778c7b1cSBill Paul 			yp_errno = YP_NOMAP;
425778c7b1cSBill Paul 			break;
426778c7b1cSBill Paul 		case EFTYPE:
427778c7b1cSBill Paul 			yp_errno = YP_BADDB;
428778c7b1cSBill Paul 			break;
429778c7b1cSBill Paul 		default:
430778c7b1cSBill Paul 			yp_errno = YP_YPERR;
431778c7b1cSBill Paul 			break;
432778c7b1cSBill Paul 		}
433778c7b1cSBill Paul 	}
434778c7b1cSBill Paul 
435778c7b1cSBill Paul 	return (dbp);
436778c7b1cSBill Paul }
437778c7b1cSBill Paul 
438778c7b1cSBill Paul /*
439778c7b1cSBill Paul  * Database access routines.
440778c7b1cSBill Paul  *
441778c7b1cSBill Paul  * - yp_get_record(): retrieve an arbitrary key/data pair given one key
442778c7b1cSBill Paul  *                 to match against.
443778c7b1cSBill Paul  *
444778c7b1cSBill Paul  * - yp_first_record(): retrieve first key/data base in a database.
445778c7b1cSBill Paul  *
446778c7b1cSBill Paul  * - yp_next_record(): retrieve key/data pair that sequentially follows
447778c7b1cSBill Paul  *                   the supplied key value in the database.
448778c7b1cSBill Paul  */
449778c7b1cSBill Paul 
450180807d2SBill Paul #ifdef DB_CACHE
451dc584ddbSDag-Erling Smørgrav int
452dc584ddbSDag-Erling Smørgrav yp_get_record(DB *dbp, const DBT *key, DBT *data, int allow)
453180807d2SBill Paul #else
454dc584ddbSDag-Erling Smørgrav int
455dc584ddbSDag-Erling Smørgrav yp_get_record(const char *domain, const char *map,
456dc584ddbSDag-Erling Smørgrav     const DBT *key, DBT *data, int allow)
457180807d2SBill Paul #endif
458778c7b1cSBill Paul {
459180807d2SBill Paul #ifndef DB_CACHE
460778c7b1cSBill Paul 	DB *dbp;
461180807d2SBill Paul #endif
462b2264be8SBill Paul 	int rval = 0;
46379acf67fSBill Paul #ifndef DB_CACHE
46479acf67fSBill Paul 	static unsigned char buf[YPMAXRECORD];
46579acf67fSBill Paul #endif
466778c7b1cSBill Paul 
46777732bc5SBill Paul 	if (ypdb_debug)
46898834523SPhilippe Charnier 		yp_error("looking up key [%.*s]",
469e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data);
470778c7b1cSBill Paul 
471778c7b1cSBill Paul 	/*
472778c7b1cSBill Paul 	 * Avoid passing back magic "YP_*" entries unless
473778c7b1cSBill Paul 	 * the caller specifically requested them by setting
474778c7b1cSBill Paul 	 * the 'allow' flag.
475778c7b1cSBill Paul 	 */
476778c7b1cSBill Paul 	if (!allow && !strncmp(key->data, "YP_", 3))
477778c7b1cSBill Paul 		return(YP_NOKEY);
478778c7b1cSBill Paul 
479180807d2SBill Paul #ifndef DB_CACHE
480778c7b1cSBill Paul 	if ((dbp = yp_open_db(domain, map)) == NULL) {
481778c7b1cSBill Paul 		return(yp_errno);
482778c7b1cSBill Paul 	}
483180807d2SBill Paul #endif
484778c7b1cSBill Paul 
485920491cfSBill Paul 	if ((rval = (dbp->get)(dbp, key, data, 0)) != 0) {
486b2264be8SBill Paul #ifdef DB_CACHE
487c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
488b2264be8SBill Paul #else
489778c7b1cSBill Paul 		(void)(dbp->close)(dbp);
490b2264be8SBill Paul #endif
491920491cfSBill Paul 		if (rval == 1)
492778c7b1cSBill Paul 			return(YP_NOKEY);
493920491cfSBill Paul 		else
494920491cfSBill Paul 			return(YP_BADDB);
495778c7b1cSBill Paul 	}
496778c7b1cSBill Paul 
49777732bc5SBill Paul 	if (ypdb_debug)
49898834523SPhilippe Charnier 		yp_error("result of lookup: key: [%.*s] data: [%.*s]",
499e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data,
500e009976aSDag-Erling Smørgrav 		    (int)data->size, (char *)data->data);
501778c7b1cSBill Paul 
502b2264be8SBill Paul #ifdef DB_CACHE
503c5e5cd90SPoul-Henning Kamp 	if (TAILQ_FIRST(&qhead)->dbptr->size) {
504c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->key = "";
505c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
506b2264be8SBill Paul 	}
507b2264be8SBill Paul #else
508f249dbccSDag-Erling Smørgrav 	bcopy(data->data, &buf, data->size);
509f249dbccSDag-Erling Smørgrav 	data->data = &buf;
510b2264be8SBill Paul 	(void)(dbp->close)(dbp);
511b2264be8SBill Paul #endif
512b2264be8SBill Paul 
513778c7b1cSBill Paul 	return(YP_TRUE);
514778c7b1cSBill Paul }
515778c7b1cSBill Paul 
516dc584ddbSDag-Erling Smørgrav int
517dc584ddbSDag-Erling Smørgrav yp_first_record(const DB *dbp, DBT *key, DBT *data, int allow)
518778c7b1cSBill Paul {
519920491cfSBill Paul 	int rval;
52079acf67fSBill Paul #ifndef DB_CACHE
52179acf67fSBill Paul 	static unsigned char buf[YPMAXRECORD];
52279acf67fSBill Paul #endif
523778c7b1cSBill Paul 
52477732bc5SBill Paul 	if (ypdb_debug)
52598834523SPhilippe Charnier 		yp_error("retrieving first key in map");
526778c7b1cSBill Paul 
527920491cfSBill Paul 	if ((rval = (dbp->seq)(dbp,key,data,R_FIRST)) != 0) {
528b2264be8SBill Paul #ifdef DB_CACHE
529c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
530b2264be8SBill Paul #endif
531920491cfSBill Paul 		if (rval == 1)
532920491cfSBill Paul 			return(YP_NOKEY);
533920491cfSBill Paul 		else
534778c7b1cSBill Paul 			return(YP_BADDB);
535920491cfSBill Paul 	}
536778c7b1cSBill Paul 
537778c7b1cSBill Paul 	/* Avoid passing back magic "YP_*" records. */
538b2264be8SBill Paul 	while (!strncmp(key->data, "YP_", 3) && !allow) {
539920491cfSBill Paul 		if ((rval = (dbp->seq)(dbp,key,data,R_NEXT)) != 0) {
540b2264be8SBill Paul #ifdef DB_CACHE
541c5e5cd90SPoul-Henning Kamp 			TAILQ_FIRST(&qhead)->dbptr->size = 0;
542b2264be8SBill Paul #endif
543920491cfSBill Paul 			if (rval == 1)
544920491cfSBill Paul 				return(YP_NOKEY);
545920491cfSBill Paul 			else
546778c7b1cSBill Paul 				return(YP_BADDB);
547778c7b1cSBill Paul 		}
548920491cfSBill Paul 	}
549778c7b1cSBill Paul 
55077732bc5SBill Paul 	if (ypdb_debug)
55198834523SPhilippe Charnier 		yp_error("result of lookup: key: [%.*s] data: [%.*s]",
552e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data,
553e009976aSDag-Erling Smørgrav 		    (int)data->size, (char *)data->data);
554778c7b1cSBill Paul 
555b2264be8SBill Paul #ifdef DB_CACHE
556c5e5cd90SPoul-Henning Kamp 	if (TAILQ_FIRST(&qhead)->dbptr->size) {
557c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->key = key->data;
558c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = key->size;
559b2264be8SBill Paul 	}
56079acf67fSBill Paul #else
561f249dbccSDag-Erling Smørgrav 	bcopy(data->data, &buf, data->size);
562f249dbccSDag-Erling Smørgrav 	data->data = &buf;
563b2264be8SBill Paul #endif
564b2264be8SBill Paul 
565778c7b1cSBill Paul 	return(YP_TRUE);
566778c7b1cSBill Paul }
567778c7b1cSBill Paul 
568dc584ddbSDag-Erling Smørgrav int
569dc584ddbSDag-Erling Smørgrav yp_next_record(const DB *dbp, DBT *key, DBT *data, int all, int allow)
570778c7b1cSBill Paul {
571b2264be8SBill Paul 	static DBT lkey = { NULL, 0 };
572b2264be8SBill Paul 	static DBT ldata = { NULL, 0 };
573920491cfSBill Paul 	int rval;
57479acf67fSBill Paul #ifndef DB_CACHE
57579acf67fSBill Paul 	static unsigned char keybuf[YPMAXRECORD];
57679acf67fSBill Paul 	static unsigned char datbuf[YPMAXRECORD];
57779acf67fSBill Paul #endif
578778c7b1cSBill Paul 
579180807d2SBill Paul 	if (key == NULL || !key->size || key->data == NULL) {
580b2264be8SBill Paul 		rval = yp_first_record(dbp,key,data,allow);
581920491cfSBill Paul 		if (rval == YP_NOKEY)
582920491cfSBill Paul 			return(YP_NOMORE);
583559605f1SBill Paul 		else {
584559605f1SBill Paul #ifdef DB_CACHE
585c5e5cd90SPoul-Henning Kamp 			TAILQ_FIRST(&qhead)->dbptr->key = key->data;
586c5e5cd90SPoul-Henning Kamp 			TAILQ_FIRST(&qhead)->dbptr->size = key->size;
587559605f1SBill Paul #endif
588920491cfSBill Paul 			return(rval);
589920491cfSBill Paul 		}
590559605f1SBill Paul 	}
591778c7b1cSBill Paul 
59277732bc5SBill Paul 	if (ypdb_debug)
59398834523SPhilippe Charnier 		yp_error("retrieving next key, previous was: [%.*s]",
594e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data);
595778c7b1cSBill Paul 
596778c7b1cSBill Paul 	if (!all) {
597b3e93234SBill Paul #ifdef DB_CACHE
598c5e5cd90SPoul-Henning Kamp 		if (TAILQ_FIRST(&qhead)->dbptr->key == NULL) {
599b2264be8SBill Paul #endif
600778c7b1cSBill Paul 			(dbp->seq)(dbp,&lkey,&ldata,R_FIRST);
60168cd9748SBill Paul 			while (key->size != lkey.size ||
602f249dbccSDag-Erling Smørgrav 			    strncmp(key->data, lkey.data,
60368cd9748SBill Paul 			    (int)key->size))
604b3e93234SBill Paul 				if ((dbp->seq)(dbp,&lkey,&ldata,R_NEXT)) {
605b3e93234SBill Paul #ifdef DB_CACHE
606c5e5cd90SPoul-Henning Kamp 					TAILQ_FIRST(&qhead)->dbptr->size = 0;
607b3e93234SBill Paul #endif
608b3e93234SBill Paul 					return(YP_NOKEY);
609778c7b1cSBill Paul 				}
610b3e93234SBill Paul 
611b3e93234SBill Paul #ifdef DB_CACHE
612b3e93234SBill Paul 		}
613b3e93234SBill Paul #endif
614b2264be8SBill Paul 	}
615778c7b1cSBill Paul 
616b2264be8SBill Paul 	if ((dbp->seq)(dbp,key,data,R_NEXT)) {
617b2264be8SBill Paul #ifdef DB_CACHE
618c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
619b2264be8SBill Paul #endif
620778c7b1cSBill Paul 		return(YP_NOMORE);
621b2264be8SBill Paul 	}
622778c7b1cSBill Paul 
623778c7b1cSBill Paul 	/* Avoid passing back magic "YP_*" records. */
624b2264be8SBill Paul 	while (!strncmp(key->data, "YP_", 3) && !allow)
625b2264be8SBill Paul 		if ((dbp->seq)(dbp,key,data,R_NEXT)) {
626b2264be8SBill Paul #ifdef DB_CACHE
627c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
628b2264be8SBill Paul #endif
629778c7b1cSBill Paul 			return(YP_NOMORE);
630b2264be8SBill Paul 		}
631778c7b1cSBill Paul 
63277732bc5SBill Paul 	if (ypdb_debug)
63398834523SPhilippe Charnier 		yp_error("result of lookup: key: [%.*s] data: [%.*s]",
634e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data,
635e009976aSDag-Erling Smørgrav 		    (int)data->size, (char *)data->data);
636778c7b1cSBill Paul 
637b2264be8SBill Paul #ifdef DB_CACHE
638c5e5cd90SPoul-Henning Kamp 	if (TAILQ_FIRST(&qhead)->dbptr->size) {
639c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->key = key->data;
640c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = key->size;
641b2264be8SBill Paul 	}
642b2264be8SBill Paul #else
643f249dbccSDag-Erling Smørgrav 	bcopy(key->data, &keybuf, key->size);
644f249dbccSDag-Erling Smørgrav 	lkey.data = &keybuf;
645b2264be8SBill Paul 	lkey.size = key->size;
646f249dbccSDag-Erling Smørgrav 	bcopy(data->data, &datbuf, data->size);
647f249dbccSDag-Erling Smørgrav 	data->data = &datbuf;
648b2264be8SBill Paul #endif
649b2264be8SBill Paul 
650778c7b1cSBill Paul 	return(YP_TRUE);
651778c7b1cSBill Paul }
652180807d2SBill Paul 
653180807d2SBill Paul #ifdef DB_CACHE
654180807d2SBill Paul /*
655180807d2SBill Paul  * Database glue functions.
656180807d2SBill Paul  */
657180807d2SBill Paul 
658180807d2SBill Paul static DB *yp_currmap_db = NULL;
659180807d2SBill Paul static int yp_allow_db = 0;
660180807d2SBill Paul 
661dc584ddbSDag-Erling Smørgrav ypstat
662dc584ddbSDag-Erling Smørgrav yp_select_map(char *map, char *domain, keydat *key, int allow)
663180807d2SBill Paul {
6640d15a950SBill Paul 	if (key == NULL)
6650d15a950SBill Paul 		yp_currmap_db = yp_open_db_cache(domain, map, NULL, 0);
6660d15a950SBill Paul 	else
6670d15a950SBill Paul 		yp_currmap_db = yp_open_db_cache(domain, map,
6680d15a950SBill Paul 						 key->keydat_val,
669180807d2SBill Paul 						 key->keydat_len);
670180807d2SBill Paul 
671180807d2SBill Paul 	yp_allow_db = allow;
672180807d2SBill Paul 	return(yp_errno);
673180807d2SBill Paul }
674180807d2SBill Paul 
675dc584ddbSDag-Erling Smørgrav ypstat
676dc584ddbSDag-Erling Smørgrav yp_getbykey(keydat *key, valdat *val)
677180807d2SBill Paul {
678180807d2SBill Paul 	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
679180807d2SBill Paul 	ypstat rval;
680180807d2SBill Paul 
681180807d2SBill Paul 	db_key.data = key->keydat_val;
682180807d2SBill Paul 	db_key.size = key->keydat_len;
683180807d2SBill Paul 
684180807d2SBill Paul 	rval = yp_get_record(yp_currmap_db,
685180807d2SBill Paul 				&db_key, &db_val, yp_allow_db);
686180807d2SBill Paul 
687180807d2SBill Paul 	if (rval == YP_TRUE) {
688180807d2SBill Paul 		val->valdat_val = db_val.data;
689180807d2SBill Paul 		val->valdat_len = db_val.size;
690180807d2SBill Paul 	}
691180807d2SBill Paul 
692180807d2SBill Paul 	return(rval);
693180807d2SBill Paul }
694180807d2SBill Paul 
695dc584ddbSDag-Erling Smørgrav ypstat
696dc584ddbSDag-Erling Smørgrav yp_firstbykey(keydat *key, valdat *val)
697180807d2SBill Paul {
698180807d2SBill Paul 	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
699180807d2SBill Paul 	ypstat rval;
700180807d2SBill Paul 
701180807d2SBill Paul 	rval = yp_first_record(yp_currmap_db, &db_key, &db_val, yp_allow_db);
702180807d2SBill Paul 
703180807d2SBill Paul 	if (rval == YP_TRUE) {
704180807d2SBill Paul 		key->keydat_val = db_key.data;
705180807d2SBill Paul 		key->keydat_len = db_key.size;
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 
713dc584ddbSDag-Erling Smørgrav ypstat
714dc584ddbSDag-Erling Smørgrav yp_nextbykey(keydat *key, valdat *val)
715180807d2SBill Paul {
716180807d2SBill Paul 	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
717180807d2SBill Paul 	ypstat rval;
718180807d2SBill Paul 
719180807d2SBill Paul 	db_key.data = key->keydat_val;
720180807d2SBill Paul 	db_key.size = key->keydat_len;
721180807d2SBill Paul 
722180807d2SBill Paul 	rval = yp_next_record(yp_currmap_db, &db_key, &db_val, 0, yp_allow_db);
723180807d2SBill Paul 
724180807d2SBill Paul 	if (rval == YP_TRUE) {
725180807d2SBill Paul 		key->keydat_val = db_key.data;
726180807d2SBill Paul 		key->keydat_len = db_key.size;
727180807d2SBill Paul 		val->valdat_val = db_val.data;
728180807d2SBill Paul 		val->valdat_len = db_val.size;
729180807d2SBill Paul 	}
730180807d2SBill Paul 
731180807d2SBill Paul 	return(rval);
732180807d2SBill Paul }
733180807d2SBill Paul #endif
734