xref: /freebsd/usr.sbin/ypserv/yp_dblookup.c (revision df57947f083046d50552e99b91074927d2458708)
1*df57947fSPedro F. Giffuni /*-
2*df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3*df57947fSPedro F. Giffuni  *
4778c7b1cSBill Paul  * Copyright (c) 1995
5778c7b1cSBill Paul  *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
6778c7b1cSBill Paul  *
7778c7b1cSBill Paul  * Redistribution and use in source and binary forms, with or without
8778c7b1cSBill Paul  * modification, are permitted provided that the following conditions
9778c7b1cSBill Paul  * are met:
10778c7b1cSBill Paul  * 1. Redistributions of source code must retain the above copyright
11778c7b1cSBill Paul  *    notice, this list of conditions and the following disclaimer.
12778c7b1cSBill Paul  * 2. Redistributions in binary form must reproduce the above copyright
13778c7b1cSBill Paul  *    notice, this list of conditions and the following disclaimer in the
14778c7b1cSBill Paul  *    documentation and/or other materials provided with the distribution.
15778c7b1cSBill Paul  * 3. All advertising materials mentioning features or use of this software
16778c7b1cSBill Paul  *    must display the following acknowledgement:
17778c7b1cSBill Paul  *	This product includes software developed by Bill Paul.
18778c7b1cSBill Paul  * 4. Neither the name of the author nor the names of any co-contributors
19778c7b1cSBill Paul  *    may be used to endorse or promote products derived from this software
20778c7b1cSBill Paul  *    without specific prior written permission.
21778c7b1cSBill Paul  *
22778c7b1cSBill Paul  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23778c7b1cSBill Paul  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24778c7b1cSBill Paul  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25778c7b1cSBill Paul  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
26778c7b1cSBill Paul  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27778c7b1cSBill Paul  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28778c7b1cSBill Paul  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29778c7b1cSBill Paul  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30778c7b1cSBill Paul  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31778c7b1cSBill Paul  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32778c7b1cSBill Paul  * SUCH DAMAGE.
33778c7b1cSBill Paul  */
34778c7b1cSBill Paul 
35b728350eSDavid E. O'Brien #include <sys/cdefs.h>
36b728350eSDavid E. O'Brien __FBSDID("$FreeBSD$");
3798834523SPhilippe Charnier 
3898834523SPhilippe Charnier #include <db.h>
3998834523SPhilippe Charnier #include <errno.h>
4098834523SPhilippe Charnier #include <fcntl.h>
4198834523SPhilippe Charnier #include <limits.h>
4298834523SPhilippe Charnier #include <paths.h>
4398834523SPhilippe Charnier #include <stdio.h>
4498834523SPhilippe Charnier #include <stdlib.h>
4598834523SPhilippe Charnier #include <string.h>
4698834523SPhilippe Charnier #include <unistd.h>
4798834523SPhilippe Charnier #include <sys/stat.h>
4898834523SPhilippe Charnier #include <sys/param.h>
4998834523SPhilippe Charnier #include <rpcsvc/yp.h>
5098834523SPhilippe Charnier #include "yp_extern.h"
511fbdac93SBill Paul 
5277732bc5SBill Paul int ypdb_debug = 0;
53180807d2SBill Paul enum ypstat yp_errno = YP_TRUE;
54778c7b1cSBill Paul 
55778c7b1cSBill Paul #define PERM_SECURE (S_IRUSR|S_IWUSR)
56778c7b1cSBill Paul HASHINFO openinfo = {
57778c7b1cSBill Paul 	4096,		/* bsize */
58778c7b1cSBill Paul 	32,		/* ffactor */
59b3e93234SBill Paul 	256,		/* nelem */
60b2264be8SBill Paul 	2048 * 512, 	/* cachesize */
61778c7b1cSBill Paul 	NULL,		/* hash */
62778c7b1cSBill Paul 	0,		/* lorder */
63778c7b1cSBill Paul };
64778c7b1cSBill Paul 
65b2264be8SBill Paul #ifdef DB_CACHE
6679acf67fSBill Paul #include <sys/queue.h>
6779acf67fSBill Paul 
6879acf67fSBill Paul #ifndef MAXDBS
69b2264be8SBill Paul #define MAXDBS 20
7079acf67fSBill Paul #endif
7179acf67fSBill Paul 
7279acf67fSBill Paul static int numdbs = 0;
73b2264be8SBill Paul 
74b2264be8SBill Paul struct dbent {
75b2264be8SBill Paul 	DB *dbp;
76b2264be8SBill Paul 	char *name;
77b2264be8SBill Paul 	char *key;
78b2264be8SBill Paul 	int size;
7944519760SBill Paul 	int flags;
80b2264be8SBill Paul };
81b2264be8SBill Paul 
82c5e5cd90SPoul-Henning Kamp static TAILQ_HEAD(circlehead, circleq_entry) qhead;
8379acf67fSBill Paul 
8479acf67fSBill Paul struct circleq_entry {
8579acf67fSBill Paul 	struct dbent *dbptr;
86c5e5cd90SPoul-Henning Kamp 	TAILQ_ENTRY(circleq_entry) links;
8779acf67fSBill Paul };
88b2264be8SBill Paul 
89778c7b1cSBill Paul /*
9079acf67fSBill Paul  * Initialize the circular queue.
91b2264be8SBill Paul  */
92dc584ddbSDag-Erling Smørgrav void
93dc584ddbSDag-Erling Smørgrav yp_init_dbs(void)
94b2264be8SBill Paul {
95c5e5cd90SPoul-Henning Kamp 	TAILQ_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  */
103dc584ddbSDag-Erling Smørgrav static struct circleq_entry *
104dc584ddbSDag-Erling Smørgrav yp_malloc_qent(void)
105b2264be8SBill Paul {
10679acf67fSBill Paul 	register struct circleq_entry *q;
10779acf67fSBill Paul 
108650dae44SMarcelo Araujo 	q = malloc(sizeof(struct circleq_entry));
10979acf67fSBill Paul 	if (q == NULL) {
11098834523SPhilippe Charnier 		yp_error("failed to malloc() circleq entry");
11179acf67fSBill Paul 		return(NULL);
11279acf67fSBill Paul 	}
11379acf67fSBill Paul 	bzero((char *)q, sizeof(struct circleq_entry));
114650dae44SMarcelo Araujo 	q->dbptr = malloc(sizeof(struct dbent));
11579acf67fSBill Paul 	if (q->dbptr == NULL) {
11698834523SPhilippe Charnier 		yp_error("failed to malloc() circleq entry");
11779acf67fSBill Paul 		free(q);
11879acf67fSBill Paul 		return(NULL);
11979acf67fSBill Paul 	}
12079acf67fSBill Paul 	bzero((char *)q->dbptr, sizeof(struct dbent));
12179acf67fSBill Paul 
12279acf67fSBill Paul 	return(q);
123b2264be8SBill Paul }
124b2264be8SBill Paul 
125b2264be8SBill Paul /*
12679acf67fSBill Paul  * Free a previously allocated circular queue
12779acf67fSBill Paul  * entry.
12879acf67fSBill Paul  */
129dc584ddbSDag-Erling Smørgrav static void
130dc584ddbSDag-Erling Smørgrav yp_free_qent(struct circleq_entry *q)
13179acf67fSBill Paul {
13279acf67fSBill Paul 	/*
13379acf67fSBill Paul 	 * First, close the database. In theory, this is also
13479acf67fSBill Paul 	 * supposed to free the resources allocated by the DB
13579acf67fSBill Paul 	 * package, including the memory pointed to by q->dbptr->key.
13679acf67fSBill Paul 	 * This means we don't have to free q->dbptr->key here.
13779acf67fSBill Paul 	 */
13879acf67fSBill Paul 	if (q->dbptr->dbp) {
13979acf67fSBill Paul 		(void)(q->dbptr->dbp->close)(q->dbptr->dbp);
14079acf67fSBill Paul 		q->dbptr->dbp = NULL;
14179acf67fSBill Paul 	}
14279acf67fSBill Paul 	/*
14379acf67fSBill Paul 	 * Then free the database name, which was strdup()'ed.
14479acf67fSBill Paul 	 */
14579acf67fSBill Paul 	free(q->dbptr->name);
14679acf67fSBill Paul 
14779acf67fSBill Paul 	/*
14879acf67fSBill Paul 	 * Free the rest of the dbent struct.
14979acf67fSBill Paul 	 */
15079acf67fSBill Paul 	free(q->dbptr);
15179acf67fSBill Paul 	q->dbptr = NULL;
15279acf67fSBill Paul 
15379acf67fSBill Paul 	/*
15479acf67fSBill Paul 	 * Free the circleq struct.
15579acf67fSBill Paul 	 */
15679acf67fSBill Paul 	free(q);
15779acf67fSBill Paul 	q = NULL;
15879acf67fSBill Paul 
15979acf67fSBill Paul 	return;
16079acf67fSBill Paul }
16179acf67fSBill Paul 
16279acf67fSBill Paul /*
16379acf67fSBill Paul  * Zorch a single entry in the dbent queue and release
16479acf67fSBill Paul  * all its resources. (This always removes the last entry
16579acf67fSBill Paul  * in the queue.)
16679acf67fSBill Paul  */
167dc584ddbSDag-Erling Smørgrav static void
168dc584ddbSDag-Erling Smørgrav yp_flush(void)
16979acf67fSBill Paul {
17079acf67fSBill Paul 	register struct circleq_entry *qptr;
17179acf67fSBill Paul 
172c5e5cd90SPoul-Henning Kamp 	qptr = TAILQ_LAST(&qhead, circlehead);
173c5e5cd90SPoul-Henning Kamp 	TAILQ_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  */
183dc584ddbSDag-Erling Smørgrav void
184dc584ddbSDag-Erling Smørgrav yp_flush_all(void)
185b2264be8SBill Paul {
18679acf67fSBill Paul 	register struct circleq_entry *qptr;
187b2264be8SBill Paul 
188c5e5cd90SPoul-Henning Kamp 	while (!TAILQ_EMPTY(&qhead)) {
189c5e5cd90SPoul-Henning Kamp 		qptr = TAILQ_FIRST(&qhead); /* save this */
190c5e5cd90SPoul-Henning Kamp 		TAILQ_REMOVE(&qhead, qptr, links);
19179acf67fSBill Paul 		yp_free_qent(qptr);
192b2264be8SBill Paul 	}
19379acf67fSBill Paul 	numdbs = 0;
19479acf67fSBill Paul 
19579acf67fSBill Paul 	return;
196b2264be8SBill Paul }
197b2264be8SBill Paul 
19844519760SBill Paul static char *inter_string = "YP_INTERDOMAIN";
19944519760SBill Paul static char *secure_string = "YP_SECURE";
20044519760SBill Paul static int inter_sz = sizeof("YP_INTERDOMAIN") - 1;
20144519760SBill Paul static int secure_sz = sizeof("YP_SECURE") - 1;
20244519760SBill Paul 
203dc584ddbSDag-Erling Smørgrav static int
204dc584ddbSDag-Erling Smørgrav yp_setflags(DB *dbp)
20544519760SBill Paul {
20644519760SBill Paul 	DBT key = { NULL, 0 }, data = { NULL, 0 };
20744519760SBill Paul 	int flags = 0;
20844519760SBill Paul 
20944519760SBill Paul 	key.data = inter_string;
21044519760SBill Paul 	key.size = inter_sz;
21144519760SBill Paul 
21244519760SBill Paul 	if (!(dbp->get)(dbp, &key, &data, 0))
21344519760SBill Paul 		flags |= YP_INTERDOMAIN;
21444519760SBill Paul 
21544519760SBill Paul 	key.data = secure_string;
21644519760SBill Paul 	key.size = secure_sz;
21744519760SBill Paul 
21844519760SBill Paul 	if (!(dbp->get)(dbp, &key, &data, 0))
21944519760SBill Paul 		flags |= YP_SECURE;
22044519760SBill Paul 
22144519760SBill Paul 	return(flags);
22244519760SBill Paul }
22344519760SBill Paul 
224dc584ddbSDag-Erling Smørgrav int
225dc584ddbSDag-Erling Smørgrav yp_testflag(char *map, char *domain, int flag)
22644519760SBill Paul {
22744519760SBill Paul 	char buf[MAXPATHLEN + 2];
22844519760SBill Paul 	register struct circleq_entry *qptr;
22944519760SBill Paul 
23044519760SBill Paul 	if (map == NULL || domain == NULL)
23144519760SBill Paul 		return(0);
23244519760SBill Paul 
23344519760SBill Paul 	strcpy(buf, domain);
23444519760SBill Paul 	strcat(buf, "/");
23544519760SBill Paul 	strcat(buf, map);
23644519760SBill Paul 
237c5e5cd90SPoul-Henning Kamp 	TAILQ_FOREACH(qptr, &qhead, links) {
23844519760SBill Paul 		if (!strcmp(qptr->dbptr->name, buf)) {
23944519760SBill Paul 			if (qptr->dbptr->flags & flag)
24044519760SBill Paul 				return(1);
24144519760SBill Paul 			else
24244519760SBill Paul 				return(0);
24344519760SBill Paul 		}
24444519760SBill Paul 	}
24544519760SBill Paul 
24644519760SBill Paul 	if (yp_open_db_cache(domain, map, NULL, 0) == NULL)
24744519760SBill Paul 		return(0);
24844519760SBill Paul 
249c5e5cd90SPoul-Henning Kamp 	if (TAILQ_FIRST(&qhead)->dbptr->flags & flag)
25044519760SBill Paul 		return(1);
25144519760SBill Paul 
25244519760SBill Paul 	return(0);
25344519760SBill Paul }
254b2264be8SBill Paul 
255b2264be8SBill Paul /*
256b2264be8SBill Paul  * Add a DB handle and database name to the cache. We only maintain
257b2264be8SBill Paul  * fixed number of entries in the cache, so if we're asked to store
258b2264be8SBill Paul  * a new entry when all our slots are already filled, we have to kick
259b2264be8SBill Paul  * out the entry in the last slot to make room.
260b2264be8SBill Paul  */
261dc584ddbSDag-Erling Smørgrav static int
262dc584ddbSDag-Erling Smørgrav yp_cache_db(DB *dbp, char *name, int size)
263b2264be8SBill Paul {
26479acf67fSBill Paul 	register struct circleq_entry *qptr;
265b2264be8SBill Paul 
26679acf67fSBill Paul 	if (numdbs == MAXDBS) {
267b2264be8SBill Paul 		if (ypdb_debug)
26879acf67fSBill Paul 			yp_error("queue overflow -- releasing last slot");
26979acf67fSBill Paul 		yp_flush();
270b2264be8SBill Paul 	}
271b2264be8SBill Paul 
272b2264be8SBill Paul 	/*
27379acf67fSBill Paul 	 * Allocate a new queue entry.
274b2264be8SBill Paul 	 */
27579acf67fSBill Paul 
27679acf67fSBill Paul 	if ((qptr = yp_malloc_qent()) == NULL) {
27779acf67fSBill Paul 		yp_error("failed to allocate a new cache entry");
27879acf67fSBill Paul 		return(1);
279b2264be8SBill Paul 	}
280b2264be8SBill Paul 
28179acf67fSBill Paul 	qptr->dbptr->dbp = dbp;
28279acf67fSBill Paul 	qptr->dbptr->name = strdup(name);
28379acf67fSBill Paul 	qptr->dbptr->size = size;
28479acf67fSBill Paul 	qptr->dbptr->key = NULL;
28579acf67fSBill Paul 
28644519760SBill Paul 	qptr->dbptr->flags = yp_setflags(dbp);
28744519760SBill Paul 
288c5e5cd90SPoul-Henning Kamp 	TAILQ_INSERT_HEAD(&qhead, qptr, links);
289b2264be8SBill Paul 	numdbs++;
29079acf67fSBill Paul 
29179acf67fSBill Paul 	return(0);
292b2264be8SBill Paul }
293b2264be8SBill Paul 
294b2264be8SBill Paul /*
295b2264be8SBill Paul  * Search the list for a database matching 'name.' If we find it,
296b2264be8SBill Paul  * move it to the head of the list and return its DB handle. If
297b2264be8SBill Paul  * not, just fail: yp_open_db_cache() will subsequently try to open
29879acf67fSBill Paul  * the database itself and call yp_cache_db() to add it to the
299b2264be8SBill Paul  * list.
300b2264be8SBill Paul  *
301b2264be8SBill Paul  * The search works like this:
302b2264be8SBill Paul  *
303b2264be8SBill Paul  * - The caller specifies the name of a database to locate. We try to
30479acf67fSBill Paul  *   find an entry in our queue with a matching name.
305b2264be8SBill Paul  *
306b2264be8SBill Paul  * - If the caller doesn't specify a key or size, we assume that the
307b2264be8SBill Paul  *   first entry that we encounter with a matching name is returned.
30879acf67fSBill Paul  *   This will result in matches regardless of the key/size values
30979acf67fSBill Paul  *   stored in the queue entry.
310b2264be8SBill Paul  *
31179acf67fSBill Paul  * - If the caller also specifies a key and length, we check to see
31279acf67fSBill Paul  *   if the key and length saved in the queue entry also matches.
313b2264be8SBill Paul  *   This lets us return a DB handle that's already positioned at the
314b2264be8SBill Paul  *   correct location within a database.
315b2264be8SBill Paul  *
31679acf67fSBill Paul  * - Once we have a match, it gets migrated to the top of the queue
31779acf67fSBill Paul  *   so that it will be easier to find if another request for
318b2264be8SBill Paul  *   the same database comes in later.
319b2264be8SBill Paul  */
320dc584ddbSDag-Erling Smørgrav static DB *
321f249dbccSDag-Erling Smørgrav yp_find_db(const char *name, const char *key, int size)
322b2264be8SBill Paul {
32379acf67fSBill Paul 	register struct circleq_entry *qptr;
324b2264be8SBill Paul 
325c5e5cd90SPoul-Henning Kamp 	TAILQ_FOREACH(qptr, &qhead, links) {
32679acf67fSBill Paul 		if (!strcmp(qptr->dbptr->name, name)) {
327b2264be8SBill Paul 			if (size) {
32879acf67fSBill Paul 				if (size != qptr->dbptr->size ||
32979acf67fSBill Paul 				   strncmp(qptr->dbptr->key, key, size))
330b2264be8SBill Paul 					continue;
331b2264be8SBill Paul 			} else {
33279acf67fSBill Paul 				if (qptr->dbptr->size)
333b2264be8SBill Paul 					continue;
334b2264be8SBill Paul 			}
335c5e5cd90SPoul-Henning Kamp 			if (qptr != TAILQ_FIRST(&qhead)) {
336c5e5cd90SPoul-Henning Kamp 				TAILQ_REMOVE(&qhead, qptr, links);
337c5e5cd90SPoul-Henning Kamp 				TAILQ_INSERT_HEAD(&qhead, qptr, links);
338b2264be8SBill Paul 			}
33979acf67fSBill Paul 			return(qptr->dbptr->dbp);
340b2264be8SBill Paul 		}
341b2264be8SBill Paul 	}
342b3e93234SBill Paul 
343b2264be8SBill Paul 	return(NULL);
344b2264be8SBill Paul }
345b2264be8SBill Paul 
346b2264be8SBill Paul /*
347b2264be8SBill Paul  * Open a DB database and cache the handle for later use. We first
348b2264be8SBill Paul  * check the cache to see if the required database is already open.
349b2264be8SBill Paul  * If so, we fetch the handle from the cache. If not, we try to open
350b2264be8SBill Paul  * the database and save the handle in the cache for later use.
351b2264be8SBill Paul  */
352dc584ddbSDag-Erling Smørgrav DB *
353dc584ddbSDag-Erling Smørgrav yp_open_db_cache(const char *domain, const char *map, const char *key,
354dc584ddbSDag-Erling Smørgrav     const int size)
355b2264be8SBill Paul {
356b2264be8SBill Paul 	DB *dbp = NULL;
357b2264be8SBill Paul 	char buf[MAXPATHLEN + 2];
358b3e93234SBill Paul /*
359b3e93234SBill Paul 	snprintf(buf, sizeof(buf), "%s/%s", domain, map);
360b3e93234SBill Paul */
36179acf67fSBill Paul 	yp_errno = YP_TRUE;
362b2264be8SBill Paul 
3631fbdac93SBill Paul 	strcpy(buf, domain);
3641fbdac93SBill Paul 	strcat(buf, "/");
3651fbdac93SBill Paul 	strcat(buf, map);
366b2264be8SBill Paul 
367f249dbccSDag-Erling Smørgrav 	if ((dbp = yp_find_db(buf, key, size)) != NULL) {
368b2264be8SBill Paul 		return(dbp);
369b2264be8SBill Paul 	} else {
37079acf67fSBill Paul 		if ((dbp = yp_open_db(domain, map)) != NULL) {
371f249dbccSDag-Erling Smørgrav 			if (yp_cache_db(dbp, buf, size)) {
37279acf67fSBill Paul 				(void)(dbp->close)(dbp);
37379acf67fSBill Paul 				yp_errno = YP_YPERR;
37479acf67fSBill Paul 				return(NULL);
37579acf67fSBill Paul 			}
37679acf67fSBill Paul 		}
377b2264be8SBill Paul 	}
378b2264be8SBill Paul 
379b2264be8SBill Paul 	return (dbp);
380b2264be8SBill Paul }
381b2264be8SBill Paul #endif
382b2264be8SBill Paul 
383b2264be8SBill Paul /*
384b2264be8SBill Paul  * Open a DB database.
385778c7b1cSBill Paul  */
386dc584ddbSDag-Erling Smørgrav DB *
387dc584ddbSDag-Erling Smørgrav yp_open_db(const char *domain, const char *map)
388778c7b1cSBill Paul {
389b2264be8SBill Paul 	DB *dbp = NULL;
390b2264be8SBill Paul 	char buf[MAXPATHLEN + 2];
391778c7b1cSBill Paul 
392778c7b1cSBill Paul 	yp_errno = YP_TRUE;
393778c7b1cSBill Paul 
394778c7b1cSBill Paul 	if (map[0] == '.' || strchr(map, '/')) {
395778c7b1cSBill Paul 		yp_errno = YP_BADARGS;
396778c7b1cSBill Paul 		return (NULL);
397778c7b1cSBill Paul 	}
398778c7b1cSBill Paul 
399b2264be8SBill Paul #ifdef DB_CACHE
400b2264be8SBill Paul 	if (yp_validdomain(domain)) {
401b2264be8SBill Paul 		yp_errno = YP_NODOM;
402b2264be8SBill Paul 		return(NULL);
403b2264be8SBill Paul 	}
404b2264be8SBill Paul #endif
405778c7b1cSBill Paul 	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, domain, map);
406778c7b1cSBill Paul 
407b2264be8SBill Paul #ifdef DB_CACHE
408b2264be8SBill Paul again:
409b2264be8SBill Paul #endif
410b2264be8SBill Paul 	dbp = dbopen(buf, O_RDONLY, PERM_SECURE, DB_HASH, NULL);
411778c7b1cSBill Paul 
412778c7b1cSBill Paul 	if (dbp == NULL) {
413778c7b1cSBill Paul 		switch (errno) {
414b2264be8SBill Paul #ifdef DB_CACHE
415b2264be8SBill Paul 		case ENFILE:
416b2264be8SBill Paul 			/*
417b2264be8SBill Paul 			 * We ran out of file descriptors. Nuke an
418b2264be8SBill Paul 			 * open one and try again.
419b2264be8SBill Paul 			 */
420b2264be8SBill Paul 			yp_error("ran out of file descriptors");
42179acf67fSBill Paul 			yp_flush();
422b2264be8SBill Paul 			goto again;
423b2264be8SBill Paul 			break;
424b2264be8SBill Paul #endif
425778c7b1cSBill Paul 		case ENOENT:
426778c7b1cSBill Paul 			yp_errno = YP_NOMAP;
427778c7b1cSBill Paul 			break;
428778c7b1cSBill Paul 		case EFTYPE:
429778c7b1cSBill Paul 			yp_errno = YP_BADDB;
430778c7b1cSBill Paul 			break;
431778c7b1cSBill Paul 		default:
432778c7b1cSBill Paul 			yp_errno = YP_YPERR;
433778c7b1cSBill Paul 			break;
434778c7b1cSBill Paul 		}
435778c7b1cSBill Paul 	}
436778c7b1cSBill Paul 
437778c7b1cSBill Paul 	return (dbp);
438778c7b1cSBill Paul }
439778c7b1cSBill Paul 
440778c7b1cSBill Paul /*
441778c7b1cSBill Paul  * Database access routines.
442778c7b1cSBill Paul  *
443778c7b1cSBill Paul  * - yp_get_record(): retrieve an arbitrary key/data pair given one key
444778c7b1cSBill Paul  *                 to match against.
445778c7b1cSBill Paul  *
446778c7b1cSBill Paul  * - yp_first_record(): retrieve first key/data base in a database.
447778c7b1cSBill Paul  *
448778c7b1cSBill Paul  * - yp_next_record(): retrieve key/data pair that sequentially follows
449778c7b1cSBill Paul  *                   the supplied key value in the database.
450778c7b1cSBill Paul  */
451778c7b1cSBill Paul 
452180807d2SBill Paul #ifdef DB_CACHE
453dc584ddbSDag-Erling Smørgrav int
454dc584ddbSDag-Erling Smørgrav yp_get_record(DB *dbp, const DBT *key, DBT *data, int allow)
455180807d2SBill Paul #else
456dc584ddbSDag-Erling Smørgrav int
457dc584ddbSDag-Erling Smørgrav yp_get_record(const char *domain, const char *map,
458dc584ddbSDag-Erling Smørgrav     const DBT *key, DBT *data, int allow)
459180807d2SBill Paul #endif
460778c7b1cSBill Paul {
461180807d2SBill Paul #ifndef DB_CACHE
462778c7b1cSBill Paul 	DB *dbp;
463180807d2SBill Paul #endif
464b2264be8SBill Paul 	int rval = 0;
46579acf67fSBill Paul #ifndef DB_CACHE
46679acf67fSBill Paul 	static unsigned char buf[YPMAXRECORD];
46779acf67fSBill Paul #endif
468778c7b1cSBill Paul 
46977732bc5SBill Paul 	if (ypdb_debug)
47098834523SPhilippe Charnier 		yp_error("looking up key [%.*s]",
471e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data);
472778c7b1cSBill Paul 
473778c7b1cSBill Paul 	/*
474778c7b1cSBill Paul 	 * Avoid passing back magic "YP_*" entries unless
475778c7b1cSBill Paul 	 * the caller specifically requested them by setting
476778c7b1cSBill Paul 	 * the 'allow' flag.
477778c7b1cSBill Paul 	 */
478778c7b1cSBill Paul 	if (!allow && !strncmp(key->data, "YP_", 3))
479778c7b1cSBill Paul 		return(YP_NOKEY);
480778c7b1cSBill Paul 
481180807d2SBill Paul #ifndef DB_CACHE
482778c7b1cSBill Paul 	if ((dbp = yp_open_db(domain, map)) == NULL) {
483778c7b1cSBill Paul 		return(yp_errno);
484778c7b1cSBill Paul 	}
485180807d2SBill Paul #endif
486778c7b1cSBill Paul 
487920491cfSBill Paul 	if ((rval = (dbp->get)(dbp, key, data, 0)) != 0) {
488b2264be8SBill Paul #ifdef DB_CACHE
489c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
490b2264be8SBill Paul #else
491778c7b1cSBill Paul 		(void)(dbp->close)(dbp);
492b2264be8SBill Paul #endif
493920491cfSBill Paul 		if (rval == 1)
494778c7b1cSBill Paul 			return(YP_NOKEY);
495920491cfSBill Paul 		else
496920491cfSBill Paul 			return(YP_BADDB);
497778c7b1cSBill Paul 	}
498778c7b1cSBill Paul 
49977732bc5SBill Paul 	if (ypdb_debug)
50098834523SPhilippe Charnier 		yp_error("result of lookup: key: [%.*s] data: [%.*s]",
501e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data,
502e009976aSDag-Erling Smørgrav 		    (int)data->size, (char *)data->data);
503778c7b1cSBill Paul 
504b2264be8SBill Paul #ifdef DB_CACHE
505c5e5cd90SPoul-Henning Kamp 	if (TAILQ_FIRST(&qhead)->dbptr->size) {
506c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->key = "";
507c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
508b2264be8SBill Paul 	}
509b2264be8SBill Paul #else
510f249dbccSDag-Erling Smørgrav 	bcopy(data->data, &buf, data->size);
511f249dbccSDag-Erling Smørgrav 	data->data = &buf;
512b2264be8SBill Paul 	(void)(dbp->close)(dbp);
513b2264be8SBill Paul #endif
514b2264be8SBill Paul 
515778c7b1cSBill Paul 	return(YP_TRUE);
516778c7b1cSBill Paul }
517778c7b1cSBill Paul 
518dc584ddbSDag-Erling Smørgrav int
519dc584ddbSDag-Erling Smørgrav yp_first_record(const DB *dbp, DBT *key, DBT *data, int allow)
520778c7b1cSBill Paul {
521920491cfSBill Paul 	int rval;
52279acf67fSBill Paul #ifndef DB_CACHE
52379acf67fSBill Paul 	static unsigned char buf[YPMAXRECORD];
52479acf67fSBill Paul #endif
525778c7b1cSBill Paul 
52677732bc5SBill Paul 	if (ypdb_debug)
52798834523SPhilippe Charnier 		yp_error("retrieving first key in map");
528778c7b1cSBill Paul 
529920491cfSBill Paul 	if ((rval = (dbp->seq)(dbp,key,data,R_FIRST)) != 0) {
530b2264be8SBill Paul #ifdef DB_CACHE
531c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
532b2264be8SBill Paul #endif
533920491cfSBill Paul 		if (rval == 1)
534920491cfSBill Paul 			return(YP_NOKEY);
535920491cfSBill Paul 		else
536778c7b1cSBill Paul 			return(YP_BADDB);
537920491cfSBill Paul 	}
538778c7b1cSBill Paul 
539778c7b1cSBill Paul 	/* Avoid passing back magic "YP_*" records. */
540b2264be8SBill Paul 	while (!strncmp(key->data, "YP_", 3) && !allow) {
541920491cfSBill Paul 		if ((rval = (dbp->seq)(dbp,key,data,R_NEXT)) != 0) {
542b2264be8SBill Paul #ifdef DB_CACHE
543c5e5cd90SPoul-Henning Kamp 			TAILQ_FIRST(&qhead)->dbptr->size = 0;
544b2264be8SBill Paul #endif
545920491cfSBill Paul 			if (rval == 1)
546920491cfSBill Paul 				return(YP_NOKEY);
547920491cfSBill Paul 			else
548778c7b1cSBill Paul 				return(YP_BADDB);
549778c7b1cSBill Paul 		}
550920491cfSBill Paul 	}
551778c7b1cSBill Paul 
55277732bc5SBill Paul 	if (ypdb_debug)
55398834523SPhilippe Charnier 		yp_error("result of lookup: key: [%.*s] data: [%.*s]",
554e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data,
555e009976aSDag-Erling Smørgrav 		    (int)data->size, (char *)data->data);
556778c7b1cSBill Paul 
557b2264be8SBill Paul #ifdef DB_CACHE
558c5e5cd90SPoul-Henning Kamp 	if (TAILQ_FIRST(&qhead)->dbptr->size) {
559c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->key = key->data;
560c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = key->size;
561b2264be8SBill Paul 	}
56279acf67fSBill Paul #else
563f249dbccSDag-Erling Smørgrav 	bcopy(data->data, &buf, data->size);
564f249dbccSDag-Erling Smørgrav 	data->data = &buf;
565b2264be8SBill Paul #endif
566b2264be8SBill Paul 
567778c7b1cSBill Paul 	return(YP_TRUE);
568778c7b1cSBill Paul }
569778c7b1cSBill Paul 
570dc584ddbSDag-Erling Smørgrav int
571dc584ddbSDag-Erling Smørgrav yp_next_record(const DB *dbp, DBT *key, DBT *data, int all, int allow)
572778c7b1cSBill Paul {
573b2264be8SBill Paul 	static DBT lkey = { NULL, 0 };
574b2264be8SBill Paul 	static DBT ldata = { NULL, 0 };
575920491cfSBill Paul 	int rval;
57679acf67fSBill Paul #ifndef DB_CACHE
57779acf67fSBill Paul 	static unsigned char keybuf[YPMAXRECORD];
57879acf67fSBill Paul 	static unsigned char datbuf[YPMAXRECORD];
57979acf67fSBill Paul #endif
580778c7b1cSBill Paul 
581180807d2SBill Paul 	if (key == NULL || !key->size || key->data == NULL) {
582b2264be8SBill Paul 		rval = yp_first_record(dbp,key,data,allow);
583920491cfSBill Paul 		if (rval == YP_NOKEY)
584920491cfSBill Paul 			return(YP_NOMORE);
585559605f1SBill Paul 		else {
586559605f1SBill Paul #ifdef DB_CACHE
587c5e5cd90SPoul-Henning Kamp 			TAILQ_FIRST(&qhead)->dbptr->key = key->data;
588c5e5cd90SPoul-Henning Kamp 			TAILQ_FIRST(&qhead)->dbptr->size = key->size;
589559605f1SBill Paul #endif
590920491cfSBill Paul 			return(rval);
591920491cfSBill Paul 		}
592559605f1SBill Paul 	}
593778c7b1cSBill Paul 
59477732bc5SBill Paul 	if (ypdb_debug)
59598834523SPhilippe Charnier 		yp_error("retrieving next key, previous was: [%.*s]",
596e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data);
597778c7b1cSBill Paul 
598778c7b1cSBill Paul 	if (!all) {
599b3e93234SBill Paul #ifdef DB_CACHE
600c5e5cd90SPoul-Henning Kamp 		if (TAILQ_FIRST(&qhead)->dbptr->key == NULL) {
601b2264be8SBill Paul #endif
602778c7b1cSBill Paul 			(dbp->seq)(dbp,&lkey,&ldata,R_FIRST);
60368cd9748SBill Paul 			while (key->size != lkey.size ||
604f249dbccSDag-Erling Smørgrav 			    strncmp(key->data, lkey.data,
60568cd9748SBill Paul 			    (int)key->size))
606b3e93234SBill Paul 				if ((dbp->seq)(dbp,&lkey,&ldata,R_NEXT)) {
607b3e93234SBill Paul #ifdef DB_CACHE
608c5e5cd90SPoul-Henning Kamp 					TAILQ_FIRST(&qhead)->dbptr->size = 0;
609b3e93234SBill Paul #endif
610b3e93234SBill Paul 					return(YP_NOKEY);
611778c7b1cSBill Paul 				}
612b3e93234SBill Paul 
613b3e93234SBill Paul #ifdef DB_CACHE
614b3e93234SBill Paul 		}
615b3e93234SBill Paul #endif
616b2264be8SBill Paul 	}
617778c7b1cSBill Paul 
618b2264be8SBill Paul 	if ((dbp->seq)(dbp,key,data,R_NEXT)) {
619b2264be8SBill Paul #ifdef DB_CACHE
620c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
621b2264be8SBill Paul #endif
622778c7b1cSBill Paul 		return(YP_NOMORE);
623b2264be8SBill Paul 	}
624778c7b1cSBill Paul 
625778c7b1cSBill Paul 	/* Avoid passing back magic "YP_*" records. */
626b2264be8SBill Paul 	while (!strncmp(key->data, "YP_", 3) && !allow)
627b2264be8SBill Paul 		if ((dbp->seq)(dbp,key,data,R_NEXT)) {
628b2264be8SBill Paul #ifdef DB_CACHE
629c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = 0;
630b2264be8SBill Paul #endif
631778c7b1cSBill Paul 			return(YP_NOMORE);
632b2264be8SBill Paul 		}
633778c7b1cSBill Paul 
63477732bc5SBill Paul 	if (ypdb_debug)
63598834523SPhilippe Charnier 		yp_error("result of lookup: key: [%.*s] data: [%.*s]",
636e009976aSDag-Erling Smørgrav 		    (int)key->size, (char *)key->data,
637e009976aSDag-Erling Smørgrav 		    (int)data->size, (char *)data->data);
638778c7b1cSBill Paul 
639b2264be8SBill Paul #ifdef DB_CACHE
640c5e5cd90SPoul-Henning Kamp 	if (TAILQ_FIRST(&qhead)->dbptr->size) {
641c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->key = key->data;
642c5e5cd90SPoul-Henning Kamp 		TAILQ_FIRST(&qhead)->dbptr->size = key->size;
643b2264be8SBill Paul 	}
644b2264be8SBill Paul #else
645f249dbccSDag-Erling Smørgrav 	bcopy(key->data, &keybuf, key->size);
646f249dbccSDag-Erling Smørgrav 	lkey.data = &keybuf;
647b2264be8SBill Paul 	lkey.size = key->size;
648f249dbccSDag-Erling Smørgrav 	bcopy(data->data, &datbuf, data->size);
649f249dbccSDag-Erling Smørgrav 	data->data = &datbuf;
650b2264be8SBill Paul #endif
651b2264be8SBill Paul 
652778c7b1cSBill Paul 	return(YP_TRUE);
653778c7b1cSBill Paul }
654180807d2SBill Paul 
655180807d2SBill Paul #ifdef DB_CACHE
656180807d2SBill Paul /*
657180807d2SBill Paul  * Database glue functions.
658180807d2SBill Paul  */
659180807d2SBill Paul 
660180807d2SBill Paul static DB *yp_currmap_db = NULL;
661180807d2SBill Paul static int yp_allow_db = 0;
662180807d2SBill Paul 
663dc584ddbSDag-Erling Smørgrav ypstat
664dc584ddbSDag-Erling Smørgrav yp_select_map(char *map, char *domain, keydat *key, int allow)
665180807d2SBill Paul {
6660d15a950SBill Paul 	if (key == NULL)
6670d15a950SBill Paul 		yp_currmap_db = yp_open_db_cache(domain, map, NULL, 0);
6680d15a950SBill Paul 	else
6690d15a950SBill Paul 		yp_currmap_db = yp_open_db_cache(domain, map,
6700d15a950SBill Paul 						 key->keydat_val,
671180807d2SBill Paul 						 key->keydat_len);
672180807d2SBill Paul 
673180807d2SBill Paul 	yp_allow_db = allow;
674180807d2SBill Paul 	return(yp_errno);
675180807d2SBill Paul }
676180807d2SBill Paul 
677dc584ddbSDag-Erling Smørgrav ypstat
678dc584ddbSDag-Erling Smørgrav yp_getbykey(keydat *key, valdat *val)
679180807d2SBill Paul {
680180807d2SBill Paul 	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
681180807d2SBill Paul 	ypstat rval;
682180807d2SBill Paul 
683180807d2SBill Paul 	db_key.data = key->keydat_val;
684180807d2SBill Paul 	db_key.size = key->keydat_len;
685180807d2SBill Paul 
686180807d2SBill Paul 	rval = yp_get_record(yp_currmap_db,
687180807d2SBill Paul 				&db_key, &db_val, yp_allow_db);
688180807d2SBill Paul 
689180807d2SBill Paul 	if (rval == YP_TRUE) {
690180807d2SBill Paul 		val->valdat_val = db_val.data;
691180807d2SBill Paul 		val->valdat_len = db_val.size;
692180807d2SBill Paul 	}
693180807d2SBill Paul 
694180807d2SBill Paul 	return(rval);
695180807d2SBill Paul }
696180807d2SBill Paul 
697dc584ddbSDag-Erling Smørgrav ypstat
698dc584ddbSDag-Erling Smørgrav yp_firstbykey(keydat *key, valdat *val)
699180807d2SBill Paul {
700180807d2SBill Paul 	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
701180807d2SBill Paul 	ypstat rval;
702180807d2SBill Paul 
703180807d2SBill Paul 	rval = yp_first_record(yp_currmap_db, &db_key, &db_val, yp_allow_db);
704180807d2SBill Paul 
705180807d2SBill Paul 	if (rval == YP_TRUE) {
706180807d2SBill Paul 		key->keydat_val = db_key.data;
707180807d2SBill Paul 		key->keydat_len = db_key.size;
708180807d2SBill Paul 		val->valdat_val = db_val.data;
709180807d2SBill Paul 		val->valdat_len = db_val.size;
710180807d2SBill Paul 	}
711180807d2SBill Paul 
712180807d2SBill Paul 	return(rval);
713180807d2SBill Paul }
714180807d2SBill Paul 
715dc584ddbSDag-Erling Smørgrav ypstat
716dc584ddbSDag-Erling Smørgrav yp_nextbykey(keydat *key, valdat *val)
717180807d2SBill Paul {
718180807d2SBill Paul 	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
719180807d2SBill Paul 	ypstat rval;
720180807d2SBill Paul 
721180807d2SBill Paul 	db_key.data = key->keydat_val;
722180807d2SBill Paul 	db_key.size = key->keydat_len;
723180807d2SBill Paul 
724180807d2SBill Paul 	rval = yp_next_record(yp_currmap_db, &db_key, &db_val, 0, yp_allow_db);
725180807d2SBill Paul 
726180807d2SBill Paul 	if (rval == YP_TRUE) {
727180807d2SBill Paul 		key->keydat_val = db_key.data;
728180807d2SBill Paul 		key->keydat_len = db_key.size;
729180807d2SBill Paul 		val->valdat_val = db_val.data;
730180807d2SBill Paul 		val->valdat_len = db_val.size;
731180807d2SBill Paul 	}
732180807d2SBill Paul 
733180807d2SBill Paul 	return(rval);
734180807d2SBill Paul }
735180807d2SBill Paul #endif
736