112891Swpaul/*
212891Swpaul * Copyright (c) 1995
312891Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
412891Swpaul *
512891Swpaul * Redistribution and use in source and binary forms, with or without
612891Swpaul * modification, are permitted provided that the following conditions
712891Swpaul * are met:
812891Swpaul * 1. Redistributions of source code must retain the above copyright
912891Swpaul *    notice, this list of conditions and the following disclaimer.
1012891Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1112891Swpaul *    notice, this list of conditions and the following disclaimer in the
1212891Swpaul *    documentation and/or other materials provided with the distribution.
1312891Swpaul * 3. All advertising materials mentioning features or use of this software
1412891Swpaul *    must display the following acknowledgement:
1512891Swpaul *	This product includes software developed by Bill Paul.
1612891Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1712891Swpaul *    may be used to endorse or promote products derived from this software
1812891Swpaul *    without specific prior written permission.
1912891Swpaul *
2012891Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2112891Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2212891Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2312891Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2412891Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2512891Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2612891Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2712891Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2812891Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2912891Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3012891Swpaul * SUCH DAMAGE.
3112891Swpaul */
3230827Scharnier
33114601Sobrien#include <sys/cdefs.h>
34114601Sobrien__FBSDID("$FreeBSD$");
3530827Scharnier
3630827Scharnier#include <db.h>
3730827Scharnier#include <errno.h>
3830827Scharnier#include <fcntl.h>
3930827Scharnier#include <limits.h>
4030827Scharnier#include <paths.h>
4112891Swpaul#include <stdio.h>
4212891Swpaul#include <stdlib.h>
4312891Swpaul#include <string.h>
4412891Swpaul#include <unistd.h>
4512891Swpaul#include <sys/stat.h>
4615426Swpaul#include <sys/param.h>
4715426Swpaul#include <rpcsvc/yp.h>
4812891Swpaul#include "yp_extern.h"
4912891Swpaul
5012997Swpaulint ypdb_debug = 0;
5120818Swpaulenum ypstat yp_errno = YP_TRUE;
5212891Swpaul
5312891Swpaul#define PERM_SECURE (S_IRUSR|S_IWUSR)
5412891SwpaulHASHINFO openinfo = {
5512891Swpaul	4096,		/* bsize */
5612891Swpaul	32,		/* ffactor */
5716118Swpaul	256,		/* nelem */
5815426Swpaul	2048 * 512, 	/* cachesize */
5912891Swpaul	NULL,		/* hash */
6012891Swpaul	0,		/* lorder */
6112891Swpaul};
6212891Swpaul
6315426Swpaul#ifdef DB_CACHE
6416999Swpaul#include <sys/queue.h>
6516999Swpaul
6616999Swpaul#ifndef MAXDBS
6715426Swpaul#define MAXDBS 20
6816999Swpaul#endif
6915426Swpaul
7016999Swpaulstatic int numdbs = 0;
7116999Swpaul
7215426Swpaulstruct dbent {
7315426Swpaul	DB *dbp;
7415426Swpaul	char *name;
7515426Swpaul	char *key;
7615426Swpaul	int size;
7719161Swpaul	int flags;
7815426Swpaul};
7915426Swpaul
8070493Sphkstatic TAILQ_HEAD(circlehead, circleq_entry) qhead;
8115426Swpaul
8216999Swpaulstruct circleq_entry {
8316999Swpaul	struct dbent *dbptr;
8470493Sphk	TAILQ_ENTRY(circleq_entry) links;
8516999Swpaul};
8616999Swpaul
8712891Swpaul/*
8816999Swpaul * Initialize the circular queue.
8912891Swpaul */
9090298Sdesvoid
9190298Sdesyp_init_dbs(void)
9215426Swpaul{
9370493Sphk	TAILQ_INIT(&qhead);
9416999Swpaul	return;
9516999Swpaul}
9615426Swpaul
9716999Swpaul/*
9816999Swpaul * Dynamically allocate an entry for the circular queue.
9916999Swpaul * Return a NULL pointer on failure.
10016999Swpaul */
10190298Sdesstatic struct circleq_entry *
10290298Sdesyp_malloc_qent(void)
10316999Swpaul{
10416999Swpaul	register struct circleq_entry *q;
10516999Swpaul
10616999Swpaul	q = (struct circleq_entry *)malloc(sizeof(struct circleq_entry));
10716999Swpaul	if (q == NULL) {
10830827Scharnier		yp_error("failed to malloc() circleq entry");
10916999Swpaul		return(NULL);
11016999Swpaul	}
11116999Swpaul	bzero((char *)q, sizeof(struct circleq_entry));
11216999Swpaul	q->dbptr = (struct dbent *)malloc(sizeof(struct dbent));
11316999Swpaul	if (q->dbptr == NULL) {
11430827Scharnier		yp_error("failed to malloc() circleq entry");
11516999Swpaul		free(q);
11616999Swpaul		return(NULL);
11716999Swpaul	}
11816999Swpaul	bzero((char *)q->dbptr, sizeof(struct dbent));
11916999Swpaul
12016999Swpaul	return(q);
12116999Swpaul}
12216999Swpaul
12316999Swpaul/*
12416999Swpaul * Free a previously allocated circular queue
12516999Swpaul * entry.
12616999Swpaul */
12790298Sdesstatic void
12890298Sdesyp_free_qent(struct circleq_entry *q)
12916999Swpaul{
13016999Swpaul	/*
13116999Swpaul	 * First, close the database. In theory, this is also
13216999Swpaul	 * supposed to free the resources allocated by the DB
13316999Swpaul	 * package, including the memory pointed to by q->dbptr->key.
13416999Swpaul	 * This means we don't have to free q->dbptr->key here.
13516999Swpaul	 */
13616999Swpaul	if (q->dbptr->dbp) {
13716999Swpaul		(void)(q->dbptr->dbp->close)(q->dbptr->dbp);
13816999Swpaul		q->dbptr->dbp = NULL;
13916999Swpaul	}
14016999Swpaul	/*
14116999Swpaul	 * Then free the database name, which was strdup()'ed.
14216999Swpaul	 */
14316999Swpaul	free(q->dbptr->name);
14416999Swpaul
14516999Swpaul	/*
14616999Swpaul	 * Free the rest of the dbent struct.
14716999Swpaul	 */
14816999Swpaul	free(q->dbptr);
14916999Swpaul	q->dbptr = NULL;
15016999Swpaul
15116999Swpaul	/*
15216999Swpaul	 * Free the circleq struct.
15316999Swpaul	 */
15416999Swpaul	free(q);
15516999Swpaul	q = NULL;
15616999Swpaul
15715426Swpaul	return;
15815426Swpaul}
15915426Swpaul
16016044Swpaul/*
16116999Swpaul * Zorch a single entry in the dbent queue and release
16216999Swpaul * all its resources. (This always removes the last entry
16316999Swpaul * in the queue.)
16416044Swpaul */
16590298Sdesstatic void
16690298Sdesyp_flush(void)
16715426Swpaul{
16816999Swpaul	register struct circleq_entry *qptr;
16916999Swpaul
17070493Sphk	qptr = TAILQ_LAST(&qhead, circlehead);
17170493Sphk	TAILQ_REMOVE(&qhead, qptr, links);
17216999Swpaul	yp_free_qent(qptr);
17315426Swpaul	numdbs--;
17416999Swpaul
17516999Swpaul	return;
17615426Swpaul}
17715426Swpaul
17815426Swpaul/*
17916999Swpaul * Close all databases, erase all database names and empty the queue.
18015426Swpaul */
18190298Sdesvoid
18290298Sdesyp_flush_all(void)
18315426Swpaul{
18416999Swpaul	register struct circleq_entry *qptr;
18515426Swpaul
18690297Sdes	while (!TAILQ_EMPTY(&qhead)) {
18770493Sphk		qptr = TAILQ_FIRST(&qhead); /* save this */
18870493Sphk		TAILQ_REMOVE(&qhead, qptr, links);
18990297Sdes		yp_free_qent(qptr);
19015426Swpaul	}
19116999Swpaul	numdbs = 0;
19216999Swpaul
19316999Swpaul	return;
19415426Swpaul}
19515426Swpaul
19619161Swpaulstatic char *inter_string = "YP_INTERDOMAIN";
19719161Swpaulstatic char *secure_string = "YP_SECURE";
19819161Swpaulstatic int inter_sz = sizeof("YP_INTERDOMAIN") - 1;
19919161Swpaulstatic int secure_sz = sizeof("YP_SECURE") - 1;
20015426Swpaul
20190298Sdesstatic int
20290298Sdesyp_setflags(DB *dbp)
20319161Swpaul{
20419161Swpaul	DBT key = { NULL, 0 }, data = { NULL, 0 };
20519161Swpaul	int flags = 0;
20619161Swpaul
20719161Swpaul	key.data = inter_string;
20819161Swpaul	key.size = inter_sz;
20919161Swpaul
21019161Swpaul	if (!(dbp->get)(dbp, &key, &data, 0))
21119161Swpaul		flags |= YP_INTERDOMAIN;
21219161Swpaul
21319161Swpaul	key.data = secure_string;
21419161Swpaul	key.size = secure_sz;
21519161Swpaul
21619161Swpaul	if (!(dbp->get)(dbp, &key, &data, 0))
21719161Swpaul		flags |= YP_SECURE;
21819161Swpaul
21919161Swpaul	return(flags);
22019161Swpaul}
22119161Swpaul
22290298Sdesint
22390298Sdesyp_testflag(char *map, char *domain, int flag)
22419161Swpaul{
22519161Swpaul	char buf[MAXPATHLEN + 2];
22619161Swpaul	register struct circleq_entry *qptr;
22719161Swpaul
22819161Swpaul	if (map == NULL || domain == NULL)
22919161Swpaul		return(0);
23019161Swpaul
23119161Swpaul	strcpy(buf, domain);
23219161Swpaul	strcat(buf, "/");
23319161Swpaul	strcat(buf, map);
23419161Swpaul
23570493Sphk	TAILQ_FOREACH(qptr, &qhead, links) {
23619161Swpaul		if (!strcmp(qptr->dbptr->name, buf)) {
23719161Swpaul			if (qptr->dbptr->flags & flag)
23819161Swpaul				return(1);
23919161Swpaul			else
24019161Swpaul				return(0);
24119161Swpaul		}
24219161Swpaul	}
24319161Swpaul
24419161Swpaul	if (yp_open_db_cache(domain, map, NULL, 0) == NULL)
24519161Swpaul		return(0);
24619161Swpaul
24770493Sphk	if (TAILQ_FIRST(&qhead)->dbptr->flags & flag)
24819161Swpaul		return(1);
24919161Swpaul
25019161Swpaul	return(0);
25119161Swpaul}
25219161Swpaul
25315426Swpaul/*
25415426Swpaul * Add a DB handle and database name to the cache. We only maintain
25515426Swpaul * fixed number of entries in the cache, so if we're asked to store
25615426Swpaul * a new entry when all our slots are already filled, we have to kick
25715426Swpaul * out the entry in the last slot to make room.
25815426Swpaul */
25990298Sdesstatic int
26090298Sdesyp_cache_db(DB *dbp, char *name, int size)
26115426Swpaul{
26216999Swpaul	register struct circleq_entry *qptr;
26315426Swpaul
26416999Swpaul	if (numdbs == MAXDBS) {
26515426Swpaul		if (ypdb_debug)
26616999Swpaul			yp_error("queue overflow -- releasing last slot");
26716999Swpaul		yp_flush();
26815426Swpaul	}
26915426Swpaul
27015426Swpaul	/*
27116999Swpaul	 * Allocate a new queue entry.
27215426Swpaul	 */
27316999Swpaul
27416999Swpaul	if ((qptr = yp_malloc_qent()) == NULL) {
27516999Swpaul		yp_error("failed to allocate a new cache entry");
27616999Swpaul		return(1);
27715426Swpaul	}
27815426Swpaul
27916999Swpaul	qptr->dbptr->dbp = dbp;
28016999Swpaul	qptr->dbptr->name = strdup(name);
28116999Swpaul	qptr->dbptr->size = size;
28216999Swpaul	qptr->dbptr->key = NULL;
28316999Swpaul
28419161Swpaul	qptr->dbptr->flags = yp_setflags(dbp);
28519161Swpaul
28670493Sphk	TAILQ_INSERT_HEAD(&qhead, qptr, links);
28715426Swpaul	numdbs++;
28816999Swpaul
28916999Swpaul	return(0);
29015426Swpaul}
29115426Swpaul
29215426Swpaul/*
29315426Swpaul * Search the list for a database matching 'name.' If we find it,
29415426Swpaul * move it to the head of the list and return its DB handle. If
29515426Swpaul * not, just fail: yp_open_db_cache() will subsequently try to open
29616999Swpaul * the database itself and call yp_cache_db() to add it to the
29715426Swpaul * list.
29815426Swpaul *
29915426Swpaul * The search works like this:
30015426Swpaul *
30115426Swpaul * - The caller specifies the name of a database to locate. We try to
30216999Swpaul *   find an entry in our queue with a matching name.
30315426Swpaul *
30415426Swpaul * - If the caller doesn't specify a key or size, we assume that the
30515426Swpaul *   first entry that we encounter with a matching name is returned.
30616999Swpaul *   This will result in matches regardless of the key/size values
30716999Swpaul *   stored in the queue entry.
30815426Swpaul *
30916999Swpaul * - If the caller also specifies a key and length, we check to see
31016999Swpaul *   if the key and length saved in the queue entry also matches.
31115426Swpaul *   This lets us return a DB handle that's already positioned at the
31215426Swpaul *   correct location within a database.
31315426Swpaul *
31416999Swpaul * - Once we have a match, it gets migrated to the top of the queue
31516999Swpaul *   so that it will be easier to find if another request for
31615426Swpaul *   the same database comes in later.
31715426Swpaul */
31890298Sdesstatic DB *
31995658Sdesyp_find_db(const char *name, const char *key, int size)
32015426Swpaul{
32116999Swpaul	register struct circleq_entry *qptr;
32215426Swpaul
32370493Sphk	TAILQ_FOREACH(qptr, &qhead, links) {
32416999Swpaul		if (!strcmp(qptr->dbptr->name, name)) {
32515426Swpaul			if (size) {
32616999Swpaul				if (size != qptr->dbptr->size ||
32716999Swpaul				   strncmp(qptr->dbptr->key, key, size))
32815426Swpaul					continue;
32915426Swpaul			} else {
33016999Swpaul				if (qptr->dbptr->size)
33115426Swpaul					continue;
33215426Swpaul			}
33370493Sphk			if (qptr != TAILQ_FIRST(&qhead)) {
33470493Sphk				TAILQ_REMOVE(&qhead, qptr, links);
33570493Sphk				TAILQ_INSERT_HEAD(&qhead, qptr, links);
33615426Swpaul			}
33716999Swpaul			return(qptr->dbptr->dbp);
33815426Swpaul		}
33915426Swpaul	}
34016118Swpaul
34115426Swpaul	return(NULL);
34215426Swpaul}
34315426Swpaul
34415426Swpaul/*
34515426Swpaul * Open a DB database and cache the handle for later use. We first
34615426Swpaul * check the cache to see if the required database is already open.
34715426Swpaul * If so, we fetch the handle from the cache. If not, we try to open
34815426Swpaul * the database and save the handle in the cache for later use.
34915426Swpaul */
35090298SdesDB *
35190298Sdesyp_open_db_cache(const char *domain, const char *map, const char *key,
35290298Sdes    const int size)
35315426Swpaul{
35415426Swpaul	DB *dbp = NULL;
35515426Swpaul	char buf[MAXPATHLEN + 2];
35616118Swpaul/*
35716118Swpaul	snprintf(buf, sizeof(buf), "%s/%s", domain, map);
35816118Swpaul*/
35916999Swpaul	yp_errno = YP_TRUE;
36015426Swpaul
36116044Swpaul	strcpy(buf, domain);
36216044Swpaul	strcat(buf, "/");
36316044Swpaul	strcat(buf, map);
36415426Swpaul
36595658Sdes	if ((dbp = yp_find_db(buf, key, size)) != NULL) {
36615426Swpaul		return(dbp);
36715426Swpaul	} else {
36816999Swpaul		if ((dbp = yp_open_db(domain, map)) != NULL) {
36995658Sdes			if (yp_cache_db(dbp, buf, size)) {
37016999Swpaul				(void)(dbp->close)(dbp);
37116999Swpaul				yp_errno = YP_YPERR;
37216999Swpaul				return(NULL);
37316999Swpaul			}
37416999Swpaul		}
37515426Swpaul	}
37615426Swpaul
37715426Swpaul	return (dbp);
37815426Swpaul}
37915426Swpaul#endif
38015426Swpaul
38115426Swpaul/*
38215426Swpaul * Open a DB database.
38315426Swpaul */
38490298SdesDB *
38590298Sdesyp_open_db(const char *domain, const char *map)
38612891Swpaul{
38715426Swpaul	DB *dbp = NULL;
38815426Swpaul	char buf[MAXPATHLEN + 2];
38912891Swpaul
39012891Swpaul	yp_errno = YP_TRUE;
39112891Swpaul
39212891Swpaul	if (map[0] == '.' || strchr(map, '/')) {
39312891Swpaul		yp_errno = YP_BADARGS;
39412891Swpaul		return (NULL);
39512891Swpaul	}
39612891Swpaul
39715426Swpaul#ifdef DB_CACHE
39815426Swpaul	if (yp_validdomain(domain)) {
39915426Swpaul		yp_errno = YP_NODOM;
40015426Swpaul		return(NULL);
40115426Swpaul	}
40215426Swpaul#endif
40312891Swpaul	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, domain, map);
40412891Swpaul
40515426Swpaul#ifdef DB_CACHE
40615426Swpaulagain:
40715426Swpaul#endif
40815426Swpaul	dbp = dbopen(buf,O_RDONLY, PERM_SECURE, DB_HASH, NULL);
40912891Swpaul
41012891Swpaul	if (dbp == NULL) {
41190297Sdes		switch (errno) {
41215426Swpaul#ifdef DB_CACHE
41315426Swpaul		case ENFILE:
41415426Swpaul			/*
41515426Swpaul			 * We ran out of file descriptors. Nuke an
41615426Swpaul			 * open one and try again.
41715426Swpaul			 */
41815426Swpaul			yp_error("ran out of file descriptors");
41916999Swpaul			yp_flush();
42015426Swpaul			goto again;
42115426Swpaul			break;
42215426Swpaul#endif
42312891Swpaul		case ENOENT:
42412891Swpaul			yp_errno = YP_NOMAP;
42512891Swpaul			break;
42612891Swpaul		case EFTYPE:
42712891Swpaul			yp_errno = YP_BADDB;
42812891Swpaul			break;
42912891Swpaul		default:
43012891Swpaul			yp_errno = YP_YPERR;
43112891Swpaul			break;
43212891Swpaul		}
43312891Swpaul	}
43412891Swpaul
43512891Swpaul	return (dbp);
43612891Swpaul}
43712891Swpaul
43812891Swpaul/*
43912891Swpaul * Database access routines.
44012891Swpaul *
44112891Swpaul * - yp_get_record(): retrieve an arbitrary key/data pair given one key
44212891Swpaul *                 to match against.
44312891Swpaul *
44412891Swpaul * - yp_first_record(): retrieve first key/data base in a database.
44590297Sdes *
44612891Swpaul * - yp_next_record(): retrieve key/data pair that sequentially follows
44712891Swpaul *                   the supplied key value in the database.
44812891Swpaul */
44912891Swpaul
45020818Swpaul#ifdef DB_CACHE
45190298Sdesint
45290298Sdesyp_get_record(DB *dbp, const DBT *key, DBT *data, int allow)
45320818Swpaul#else
45490298Sdesint
45590298Sdesyp_get_record(const char *domain, const char *map,
45690298Sdes    const DBT *key, DBT *data, int allow)
45720818Swpaul#endif
45812891Swpaul{
45920818Swpaul#ifndef DB_CACHE
46012891Swpaul	DB *dbp;
46120818Swpaul#endif
46215426Swpaul	int rval = 0;
46316999Swpaul#ifndef DB_CACHE
46416999Swpaul	static unsigned char buf[YPMAXRECORD];
46516999Swpaul#endif
46612891Swpaul
46712997Swpaul	if (ypdb_debug)
46830827Scharnier		yp_error("looking up key [%.*s]",
46996221Sdes		    (int)key->size, (char *)key->data);
47012891Swpaul
47112891Swpaul	/*
47212891Swpaul	 * Avoid passing back magic "YP_*" entries unless
47312891Swpaul	 * the caller specifically requested them by setting
47412891Swpaul	 * the 'allow' flag.
47512891Swpaul	 */
47612891Swpaul	if (!allow && !strncmp(key->data, "YP_", 3))
47712891Swpaul		return(YP_NOKEY);
47812891Swpaul
47920818Swpaul#ifndef DB_CACHE
48012891Swpaul	if ((dbp = yp_open_db(domain, map)) == NULL) {
48112891Swpaul		return(yp_errno);
48212891Swpaul	}
48320818Swpaul#endif
48412891Swpaul
48515426Swpaul	if ((rval = (dbp->get)(dbp, key, data, 0)) != 0) {
48615426Swpaul#ifdef DB_CACHE
48770493Sphk		TAILQ_FIRST(&qhead)->dbptr->size = 0;
48815426Swpaul#else
48912891Swpaul		(void)(dbp->close)(dbp);
49015426Swpaul#endif
49113896Swpaul		if (rval == 1)
49213896Swpaul			return(YP_NOKEY);
49313896Swpaul		else
49413896Swpaul			return(YP_BADDB);
49512891Swpaul	}
49612891Swpaul
49712997Swpaul	if (ypdb_debug)
49830827Scharnier		yp_error("result of lookup: key: [%.*s] data: [%.*s]",
49996221Sdes		    (int)key->size, (char *)key->data,
50096221Sdes		    (int)data->size, (char *)data->data);
50112891Swpaul
50215426Swpaul#ifdef DB_CACHE
50370493Sphk	if (TAILQ_FIRST(&qhead)->dbptr->size) {
50470493Sphk		TAILQ_FIRST(&qhead)->dbptr->key = "";
50570493Sphk		TAILQ_FIRST(&qhead)->dbptr->size = 0;
50615426Swpaul	}
50715426Swpaul#else
50895658Sdes	bcopy(data->data, &buf, data->size);
50995658Sdes	data->data = &buf;
51015426Swpaul	(void)(dbp->close)(dbp);
51115426Swpaul#endif
51215426Swpaul
51312891Swpaul	return(YP_TRUE);
51412891Swpaul}
51512891Swpaul
51690298Sdesint
51790298Sdesyp_first_record(const DB *dbp, DBT *key, DBT *data, int allow)
51812891Swpaul{
51913896Swpaul	int rval;
52016999Swpaul#ifndef DB_CACHE
52116999Swpaul	static unsigned char buf[YPMAXRECORD];
52216999Swpaul#endif
52312891Swpaul
52412997Swpaul	if (ypdb_debug)
52530827Scharnier		yp_error("retrieving first key in map");
52612891Swpaul
52713896Swpaul	if ((rval = (dbp->seq)(dbp,key,data,R_FIRST)) != 0) {
52815426Swpaul#ifdef DB_CACHE
52970493Sphk		TAILQ_FIRST(&qhead)->dbptr->size = 0;
53015426Swpaul#endif
53113896Swpaul		if (rval == 1)
53213896Swpaul			return(YP_NOKEY);
53390297Sdes		else
53413896Swpaul			return(YP_BADDB);
53513896Swpaul	}
53612891Swpaul
53712891Swpaul	/* Avoid passing back magic "YP_*" records. */
53815426Swpaul	while (!strncmp(key->data, "YP_", 3) && !allow) {
53913896Swpaul		if ((rval = (dbp->seq)(dbp,key,data,R_NEXT)) != 0) {
54015426Swpaul#ifdef DB_CACHE
54170493Sphk			TAILQ_FIRST(&qhead)->dbptr->size = 0;
54215426Swpaul#endif
54313896Swpaul			if (rval == 1)
54413896Swpaul				return(YP_NOKEY);
54513896Swpaul			else
54613896Swpaul				return(YP_BADDB);
54713896Swpaul		}
54812891Swpaul	}
54912891Swpaul
55012997Swpaul	if (ypdb_debug)
55130827Scharnier		yp_error("result of lookup: key: [%.*s] data: [%.*s]",
55296221Sdes		    (int)key->size, (char *)key->data,
55396221Sdes		    (int)data->size, (char *)data->data);
55412891Swpaul
55515426Swpaul#ifdef DB_CACHE
55670493Sphk	if (TAILQ_FIRST(&qhead)->dbptr->size) {
55770493Sphk		TAILQ_FIRST(&qhead)->dbptr->key = key->data;
55870493Sphk		TAILQ_FIRST(&qhead)->dbptr->size = key->size;
55915426Swpaul	}
56016999Swpaul#else
56195658Sdes	bcopy(data->data, &buf, data->size);
56295658Sdes	data->data = &buf;
56315426Swpaul#endif
56415426Swpaul
56512891Swpaul	return(YP_TRUE);
56612891Swpaul}
56712891Swpaul
56890298Sdesint
56990298Sdesyp_next_record(const DB *dbp, DBT *key, DBT *data, int all, int allow)
57012891Swpaul{
57115426Swpaul	static DBT lkey = { NULL, 0 };
57215426Swpaul	static DBT ldata = { NULL, 0 };
57313896Swpaul	int rval;
57416999Swpaul#ifndef DB_CACHE
57516999Swpaul	static unsigned char keybuf[YPMAXRECORD];
57616999Swpaul	static unsigned char datbuf[YPMAXRECORD];
57716999Swpaul#endif
57812891Swpaul
57920818Swpaul	if (key == NULL || !key->size || key->data == NULL) {
58015426Swpaul		rval = yp_first_record(dbp,key,data,allow);
58113896Swpaul		if (rval == YP_NOKEY)
58213896Swpaul			return(YP_NOMORE);
58321882Swpaul		else {
58421882Swpaul#ifdef DB_CACHE
58570493Sphk			TAILQ_FIRST(&qhead)->dbptr->key = key->data;
58670493Sphk			TAILQ_FIRST(&qhead)->dbptr->size = key->size;
58721882Swpaul#endif
58813896Swpaul			return(rval);
58921882Swpaul		}
59013896Swpaul	}
59112891Swpaul
59212997Swpaul	if (ypdb_debug)
59330827Scharnier		yp_error("retrieving next key, previous was: [%.*s]",
59496221Sdes		    (int)key->size, (char *)key->data);
59512891Swpaul
59612891Swpaul	if (!all) {
59716118Swpaul#ifdef DB_CACHE
59870493Sphk		if (TAILQ_FIRST(&qhead)->dbptr->key == NULL) {
59915426Swpaul#endif
60015426Swpaul			(dbp->seq)(dbp,&lkey,&ldata,R_FIRST);
60145671Swpaul			while (key->size != lkey.size ||
60295658Sdes			    strncmp(key->data, lkey.data,
60345671Swpaul			    (int)key->size))
60416118Swpaul				if ((dbp->seq)(dbp,&lkey,&ldata,R_NEXT)) {
60516118Swpaul#ifdef DB_CACHE
60670493Sphk					TAILQ_FIRST(&qhead)->dbptr->size = 0;
60716118Swpaul#endif
60816118Swpaul					return(YP_NOKEY);
60916118Swpaul				}
61016118Swpaul
61190297Sdes#ifdef DB_CACHE
61215426Swpaul		}
61316118Swpaul#endif
61412891Swpaul	}
61512891Swpaul
61615426Swpaul	if ((dbp->seq)(dbp,key,data,R_NEXT)) {
61715426Swpaul#ifdef DB_CACHE
61870493Sphk		TAILQ_FIRST(&qhead)->dbptr->size = 0;
61915426Swpaul#endif
62012891Swpaul		return(YP_NOMORE);
62115426Swpaul	}
62212891Swpaul
62312891Swpaul	/* Avoid passing back magic "YP_*" records. */
62415426Swpaul	while (!strncmp(key->data, "YP_", 3) && !allow)
62515426Swpaul		if ((dbp->seq)(dbp,key,data,R_NEXT)) {
62615426Swpaul#ifdef DB_CACHE
62770493Sphk		TAILQ_FIRST(&qhead)->dbptr->size = 0;
62815426Swpaul#endif
62912891Swpaul			return(YP_NOMORE);
63015426Swpaul		}
63112891Swpaul
63212997Swpaul	if (ypdb_debug)
63330827Scharnier		yp_error("result of lookup: key: [%.*s] data: [%.*s]",
63496221Sdes		    (int)key->size, (char *)key->data,
63596221Sdes		    (int)data->size, (char *)data->data);
63612891Swpaul
63715426Swpaul#ifdef DB_CACHE
63870493Sphk	if (TAILQ_FIRST(&qhead)->dbptr->size) {
63970493Sphk		TAILQ_FIRST(&qhead)->dbptr->key = key->data;
64070493Sphk		TAILQ_FIRST(&qhead)->dbptr->size = key->size;
64115426Swpaul	}
64215426Swpaul#else
64395658Sdes	bcopy(key->data, &keybuf, key->size);
64495658Sdes	lkey.data = &keybuf;
64515426Swpaul	lkey.size = key->size;
64695658Sdes	bcopy(data->data, &datbuf, data->size);
64795658Sdes	data->data = &datbuf;
64815426Swpaul#endif
64915426Swpaul
65012891Swpaul	return(YP_TRUE);
65112891Swpaul}
65220818Swpaul
65320818Swpaul#ifdef DB_CACHE
65420818Swpaul/*
65520818Swpaul * Database glue functions.
65620818Swpaul */
65720818Swpaul
65820818Swpaulstatic DB *yp_currmap_db = NULL;
65920818Swpaulstatic int yp_allow_db = 0;
66020818Swpaul
66190298Sdesypstat
66290298Sdesyp_select_map(char *map, char *domain, keydat *key, int allow)
66320818Swpaul{
66433250Swpaul	if (key == NULL)
66533250Swpaul		yp_currmap_db = yp_open_db_cache(domain, map, NULL, 0);
66633250Swpaul	else
66733250Swpaul		yp_currmap_db = yp_open_db_cache(domain, map,
66833250Swpaul						 key->keydat_val,
66933250Swpaul						 key->keydat_len);
67020818Swpaul
67120818Swpaul	yp_allow_db = allow;
67220818Swpaul	return(yp_errno);
67320818Swpaul}
67420818Swpaul
67590298Sdesypstat
67690298Sdesyp_getbykey(keydat *key, valdat *val)
67720818Swpaul{
67820818Swpaul	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
67920818Swpaul	ypstat rval;
68020818Swpaul
68120818Swpaul	db_key.data = key->keydat_val;
68220818Swpaul	db_key.size = key->keydat_len;
68320818Swpaul
68420818Swpaul	rval = yp_get_record(yp_currmap_db,
68520818Swpaul				&db_key, &db_val, yp_allow_db);
68620818Swpaul
68720818Swpaul	if (rval == YP_TRUE) {
68820818Swpaul		val->valdat_val = db_val.data;
68920818Swpaul		val->valdat_len = db_val.size;
69020818Swpaul	}
69120818Swpaul
69220818Swpaul	return(rval);
69320818Swpaul}
69420818Swpaul
69590298Sdesypstat
69690298Sdesyp_firstbykey(keydat *key, valdat *val)
69720818Swpaul{
69820818Swpaul	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
69920818Swpaul	ypstat rval;
70020818Swpaul
70120818Swpaul	rval = yp_first_record(yp_currmap_db, &db_key, &db_val, yp_allow_db);
70220818Swpaul
70320818Swpaul	if (rval == YP_TRUE) {
70420818Swpaul		key->keydat_val = db_key.data;
70520818Swpaul		key->keydat_len = db_key.size;
70620818Swpaul		val->valdat_val = db_val.data;
70720818Swpaul		val->valdat_len = db_val.size;
70820818Swpaul	}
70920818Swpaul
71020818Swpaul	return(rval);
71120818Swpaul}
71220818Swpaul
71390298Sdesypstat
71490298Sdesyp_nextbykey(keydat *key, valdat *val)
71520818Swpaul{
71620818Swpaul	DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
71720818Swpaul	ypstat rval;
71820818Swpaul
71920818Swpaul	db_key.data = key->keydat_val;
72020818Swpaul	db_key.size = key->keydat_len;
72120818Swpaul
72220818Swpaul	rval = yp_next_record(yp_currmap_db, &db_key, &db_val, 0, yp_allow_db);
72320818Swpaul
72420818Swpaul	if (rval == YP_TRUE) {
72520818Swpaul		key->keydat_val = db_key.data;
72620818Swpaul		key->keydat_len = db_key.size;
72720818Swpaul		val->valdat_val = db_val.data;
72820818Swpaul		val->valdat_len = db_val.size;
72920818Swpaul	}
73020818Swpaul
73120818Swpaul	return(rval);
73220818Swpaul}
73320818Swpaul#endif
734