root/usr.sbin/ypserv/ypserv/ypserv_db.c
/*      $NetBSD: ypserv_db.c,v 1.23 2020/10/13 13:56:34 kamil Exp $     */

/*
 * Copyright (c) 1994 Mats O Jansson <moj@stacken.kth.se>
 * Copyright (c) 1996 Charles D. Cranor
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: ypserv_db.c,v 1.23 2020/10/13 13:56:34 kamil Exp $");
#endif

/*
 * major revision/cleanup of Mats' version done by
 * Chuck Cranor <chuck@netbsd> Jan 1996.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <sys/param.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <resolv.h>
#include <syslog.h>

#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>

#include "ypdb.h"
#include "ypdef.h"
#include "ypserv.h"

LIST_HEAD(domainlist, opt_domain);      /* LIST of domains */
LIST_HEAD(maplist, opt_map);            /* LIST of maps (in a domain) */
TAILQ_HEAD(mapq, opt_map);              /* TAILQ of maps (LRU) */

struct opt_map {
        char    *map;                   /* map name (malloc'd) */
        DBM     *db;                    /* database */
        struct opt_domain *dom;         /* back ptr to our domain */
        int     host_lookup;            /* host lookup */
        int     secure;                 /* is this map secure? */
        dev_t   dbdev;                  /* device db is on */
        ino_t   dbino;                  /* inode of db */
        time_t  dbmtime;                /* time of last db modification */
        TAILQ_ENTRY(opt_map) mapsq;     /* map queue pointers */
        LIST_ENTRY(opt_map) mapsl;      /* map list pointers */
};

struct opt_domain {
        char    *domain;                /* domain name (malloc'd) */
        struct maplist dmaps;           /* the domain's active maps */
        LIST_ENTRY(opt_domain) domsl;   /* global linked list of domains */
};

struct domainlist doms;                 /* global list of domains */
struct mapq     maps;                   /* global queue of maps (LRU) */

extern int      usedns;

int     yp_private(datum, int);
void    ypdb_close_db(DBM *);
void    ypdb_close_last(void);
void    ypdb_close_map(struct opt_map *);
DBM    *ypdb_open_db(const char *, const char *, u_int *, struct opt_map **);
u_int   lookup_host(int, int, DBM *, char *, struct ypresp_val *);

/*
 * ypdb_init: init the queues and lists
 */
void
ypdb_init(void)
{

        LIST_INIT(&doms);
        TAILQ_INIT(&maps);
}

/*
 * yp_private:
 * Check if key is a YP private key.  Return TRUE if it is and
 * ypprivate is FALSE.
 */
int
yp_private(datum key, int ypprivate)
{

        if (ypprivate)
                return (FALSE);

        if (key.dsize == 0 || key.dptr == NULL)
                return (FALSE);

        if (key.dsize == YP_LAST_LEN &&
            strncmp(key.dptr, YP_LAST_KEY, YP_LAST_LEN) == 0)
                return (TRUE);

        if (key.dsize == YP_INPUT_LEN &&
            strncmp(key.dptr, YP_INPUT_KEY, YP_INPUT_LEN) == 0)
                return (TRUE);

        if (key.dsize == YP_OUTPUT_LEN &&
            strncmp(key.dptr, YP_OUTPUT_KEY, YP_OUTPUT_LEN) == 0)
                return (TRUE);

        if (key.dsize == YP_MASTER_LEN &&
            strncmp(key.dptr, YP_MASTER_KEY, YP_MASTER_LEN) == 0)
                return (TRUE);

        if (key.dsize == YP_DOMAIN_LEN &&
            strncmp(key.dptr, YP_DOMAIN_KEY, YP_DOMAIN_LEN) == 0)
                return (TRUE);

        if (key.dsize == YP_INTERDOMAIN_LEN &&
            strncmp(key.dptr, YP_INTERDOMAIN_KEY, YP_INTERDOMAIN_LEN) == 0)
                return (TRUE);

        if (key.dsize == YP_SECURE_LEN &&
            strncmp(key.dptr, YP_SECURE_KEY, YP_SECURE_LEN) == 0)
                return (TRUE);

        return (FALSE);
}

/*
 * Close specified map.
 */
void
ypdb_close_map(struct opt_map *map)
{
        TAILQ_REMOVE(&maps, map, mapsq);        /* remove from LRU tailq */
        LIST_REMOVE(map, mapsl);                /* remove from domain list */

#ifdef DEBUG
        syslog(LOG_DEBUG,
            "ypdb_close_map: closing map %s in domain %s [db=%p]",
            map->map, map->dom->domain, map->db);
#endif

        ypdb_close(map->db);                    /* close DB */
        free(map->map);                         /* free map name */
        free(map);                              /* free map */
}

/*
 * Close least recently used map. This routine is called when we have
 * no more file descriptors free, or we want to close all maps.
 */
void
ypdb_close_last(void)
{
        struct opt_map *last;

        if (TAILQ_EMPTY(&maps)) {
                syslog(LOG_ERR,
                    "ypdb_close_last: LRU list is empty!");
                return;
        }
        last = TAILQ_LAST(&maps, mapq);
        ypdb_close_map(last);
}

/*
 * Close all open maps.
 */
void
ypdb_close_all(void)
{

#ifdef DEBUG
        syslog(LOG_DEBUG, "ypdb_close_all(): start");
#endif

        while (!TAILQ_EMPTY(&maps))
                ypdb_close_last();

#ifdef DEBUG
        syslog(LOG_DEBUG, "ypdb_close_all(): done");
#endif
}

/*
 * Close Database if Open/Close Optimization isn't turned on.
 */
void
/*ARGSUSED*/
ypdb_close_db(DBM *db)
{

#ifdef DEBUG
        syslog(LOG_DEBUG, "ypdb_close_db(%p)", db);
#endif

#ifndef OPTIMIZE_DB
        ypdb_close_all();
#endif /* not OPTIMIZE_DB */
}

/*
 * ypdb_open_db
 */
DBM *
ypdb_open_db(const char *domain, const char *map, u_int *status,
             struct opt_map **map_info)
{
        static const char *domain_key = YP_INTERDOMAIN_KEY;
        static const char *secure_key = YP_SECURE_KEY;
        char map_path[MAXPATHLEN];
        struct stat finfo;
        struct opt_domain *d = NULL;
        struct opt_map *m = NULL;
        DBM *db;
        datum k, v;

        *status = YP_TRUE;      /* defaults to true */

        /*
         * check for illegal domain and map names
         */
        if (_yp_invalid_domain(domain)) {
                *status = YP_NODOM;
                return (NULL);
        }
        if (_yp_invalid_map(map)) {
                *status = YP_NOMAP;
                return (NULL);
        }

        /*
         * check for domain, file.
         */
        (void)snprintf(map_path, sizeof(map_path), "%s/%s", YP_DB_PATH, domain);
        if (stat(map_path, &finfo) < 0 || !S_ISDIR(finfo.st_mode)) {
#ifdef DEBUG
                syslog(LOG_DEBUG,
                    "ypdb_open_db: no domain %s (map=%s)", domain, map);
#endif
                *status = YP_NODOM;
        } else {
                (void)snprintf(map_path, sizeof(map_path), "%s/%s/%s%s",
                    YP_DB_PATH, domain, map, YPDB_SUFFIX);
                if (stat(map_path, &finfo) < 0) {
#ifdef DEBUG
                        syslog(LOG_DEBUG,
                            "ypdb_open_db: no map %s (domain=%s)", map,
                            domain);
#endif
                        *status = YP_NOMAP;
                }
        }

        /*
         * check for preloaded domain, map
         */
        for (d = doms.lh_first; d != NULL; d = d->domsl.le_next)
                if (strcmp(domain, d->domain) == 0)
                        break;

        if (d)
                for (m = d->dmaps.lh_first; m != NULL; m = m->mapsl.le_next)
                        if (strcmp(map, m->map) == 0)
                                break;

        /*
         * map found open?
         */
        if (m) {
#ifdef DEBUG
                syslog(LOG_DEBUG,
                    "ypdb_open_db: cached open: domain=%s, map=%s, db=%p,",
                    domain, map, m->db);
                syslog(LOG_DEBUG,
                    "\tdbdev %d new %d; dbino %d new %d; dbmtime %ld new %ld",
                    m->dbdev, finfo.st_dev, m->dbino, finfo.st_ino,
                    (long) m->dbmtime, (long) finfo.st_mtime);
#endif
                /*
                 * if status != YP_TRUE, then this cached database is now
                 * non-existent
                 */
                if (*status != YP_TRUE) {
#ifdef DEBUG
                        syslog(LOG_DEBUG,
                            "ypdb_open_db: cached db is now unavailable - "
                            "closing: status %s",
                            yperr_string(ypprot_err(*status)));
#endif
                        ypdb_close_map(m);
                        return (NULL);
                }

                /*
                 * is this the same db?
                 */
                if (finfo.st_dev == m->dbdev && finfo.st_ino == m->dbino &&
                    finfo.st_mtime == m->dbmtime) {
                        TAILQ_REMOVE(&maps, m, mapsq); /* adjust LRU queue */
                        TAILQ_INSERT_HEAD(&maps, m, mapsq);
                        if (map_info)
                                *map_info = m;
                        return (m->db);
                } else {
#ifdef DEBUG
                        syslog(LOG_DEBUG,
                            "ypdb_open_db: db changed; closing");
#endif
                        ypdb_close_map(m);
                        m = NULL;
                }
        }

        /*
         * not cached and non-existent, return
         */
        if (*status != YP_TRUE) 
                return (NULL);

        /*
         * open map
         */
        (void)snprintf(map_path, sizeof(map_path), "%s/%s/%s",
            YP_DB_PATH, domain, map);
#ifdef OPTIMIZE_DB
retryopen:
#endif /* OPTIMIZE_DB */
        db = ypdb_open(map_path);
#ifdef OPTIMIZE_DB
        if (db == NULL) {
#ifdef DEBUG
                syslog(LOG_DEBUG,
                    "ypdb_open_db: errno %d (%s)", errno, strerror(errno));
#endif /* DEBUG */
                if ((errno == ENFILE) || (errno == EMFILE)) {
                        ypdb_close_last();
                        goto retryopen;
                }
        }
#endif /* OPTIMIZE_DB */

        *status = YP_NOMAP;     /* see note below */

        if (db == NULL) {
#ifdef DEBUG
                syslog(LOG_DEBUG,
                    "ypdb_open_db: ypdb_open FAILED: map %s (domain=%s)",
                    map, domain);
#endif
                return (NULL);
        }

        /*
         * note: status now YP_NOMAP
         */
        if (d == NULL) {        /* allocate new domain? */
                d = (struct opt_domain *) malloc(sizeof(*d));
                if (d)
                        d->domain = strdup(domain);
                if (d == NULL || d->domain == NULL) {
                        syslog(LOG_ERR,
                            "ypdb_open_db: MALLOC failed");
                        ypdb_close(db);
                        if (d)
                                free(d);
                        return (NULL);
                }
                LIST_INIT(&d->dmaps);
                LIST_INSERT_HEAD(&doms, d, domsl);
#ifdef DEBUG
                syslog(LOG_DEBUG,
                    "ypdb_open_db: NEW DOMAIN %s", domain);
#endif
        }

        /*
         * m must be NULL since we couldn't find a map.  allocate new one
         */
        m = (struct opt_map *) malloc(sizeof(*m));
        if (m)
                m->map = strdup(map);

        if (m == NULL || m->map == NULL) {
                if (m)
                        free(m);
                syslog(LOG_ERR, "ypdb_open_db: MALLOC failed");
                ypdb_close(db);
                return (NULL);
        }
        m->db = db;
        m->dom = d;
        m->host_lookup = FALSE;
        m->dbdev = finfo.st_dev;
        m->dbino = finfo.st_ino;
        m->dbmtime = finfo.st_mtime;
        TAILQ_INSERT_HEAD(&maps, m, mapsq);
        LIST_INSERT_HEAD(&d->dmaps, m, mapsl);
        if (strcmp(map, YP_HOSTNAME) == 0 || strcmp(map, YP_HOSTADDR) == 0) {
                if (!usedns) {
                        k.dptr = domain_key;
                        k.dsize = YP_INTERDOMAIN_LEN;
                        v = ypdb_fetch(db, k);
                        if (v.dptr)
                                m->host_lookup = TRUE;
                } else
                        m->host_lookup = TRUE;
        }

        m->secure = FALSE;
        k.dptr = secure_key;
        k.dsize = YP_SECURE_LEN;
        v = ypdb_fetch(db, k);
        if (v.dptr != NULL)
                m->secure = TRUE;

        *status = YP_TRUE;

        if (map_info)
                *map_info = m;

#ifdef DEBUG
        syslog(LOG_DEBUG,
            "ypdb_open_db: NEW MAP domain=%s, map=%s, hl=%d, s=%d, db=%p",
            domain, map, m->host_lookup, m->secure, m->db);
#endif

        return (m->db);
}

/*
 * lookup host
 */
u_int
/*ARGSUSED*/
lookup_host(int nametable, int host_lookup, DBM *db, char *keystr,
            struct ypresp_val *result)
{
        struct hostent *host;
        struct in_addr *addr_name;
        struct in_addr addr_addr;
        static char val[BUFSIZ + 1];    /* match libc */
        static char hostname[MAXHOSTNAMELEN];
        char tmpbuf[MAXHOSTNAMELEN + 20];
        char *v, *ptr;
        int l;

        if (!host_lookup)
                return (YP_NOKEY);

        if ((_res.options & RES_INIT) == 0)
                (void)res_init();

        if (nametable) {
                host = gethostbyname(keystr);
                if (host == NULL || host->h_addrtype != AF_INET)
                        return (YP_NOKEY);

                addr_name = (struct in_addr *)(void *)host->h_addr_list[0];

                v = val;

                for (; host->h_addr_list[0] != NULL; host->h_addr_list++) {
                        addr_name = (struct in_addr *)(void *)host->h_addr_list[0];
                        (void)snprintf(tmpbuf, sizeof(tmpbuf), "%s %s\n",
                            inet_ntoa(*addr_name), host->h_name);
                        if (v - val + strlen(tmpbuf) + 1 > sizeof(val))
                                break;
                        (void)strlcpy(v, tmpbuf, sizeof(val) - (v - val));
                        v = v + strlen(tmpbuf);
                }
                result->valdat.dptr = val;
                result->valdat.dsize = v - val;
                return (YP_TRUE);
        }
        if (inet_aton(keystr, &addr_addr) == -1)
                return (YP_NOKEY);

        host = gethostbyaddr((void *)&addr_addr, sizeof(addr_addr), AF_INET);
        if (host == NULL)
                return (YP_NOKEY);

        (void)strlcpy(hostname, host->h_name, sizeof(hostname));
        host = gethostbyname(hostname);
        if (host == NULL)
                return (YP_NOKEY);

        l = 0;
        for (; host->h_addr_list[0] != NULL; host->h_addr_list++)
                if (!memcmp(host->h_addr_list[0], &addr_addr,
                    sizeof(addr_addr)))
                        l++;

        if (l == 0) {
                syslog(LOG_NOTICE,
                    "address %s not listed for host %s\n",
                    inet_ntoa(addr_addr), hostname);
                return (YP_NOKEY);
        }

        (void)snprintf(val, sizeof(val), "%s %s", keystr, host->h_name);
        l = strlen(val);
        v = val + l;
        while ((ptr = *(host->h_aliases)) != NULL) {
                l = strlen(ptr);
                if ((v - val) + l + 1 > BUFSIZ)
                        break;
                (void)strlcpy(v, " ", sizeof(val) - (v - val));
                v += 1;
                (void)strlcpy(v, ptr, sizeof(val) - (v - val));
                v += l;
                host->h_aliases++;
        }
        result->valdat.dptr = val;
        result->valdat.dsize = v - val;

        return (YP_TRUE);
}

struct ypresp_val
ypdb_get_record(const char *domain, const char *map, datum key, int ypprivate)
{
        static struct ypresp_val res;
        static char keystr[YPMAXRECORD + 1];
        DBM *db;
        datum k, v;
        int host_lookup, hn;
        struct opt_map *map_info = NULL;

        host_lookup = 0;        /* XXX gcc -Wuninitialized */

        (void)memset(&res, 0, sizeof(res));

        db = ypdb_open_db(domain, map, &res.status, &map_info);
        if (db == NULL || (int)res.status < 0)
                return (res);

        if (map_info)
                host_lookup = map_info->host_lookup;

        k.dptr = key.dptr;
        k.dsize = key.dsize;

        if (yp_private(k, ypprivate)) {
                res.status = YP_NOKEY;
                goto done;
        }
        v = ypdb_fetch(db, k);

        if (v.dptr == NULL) {
                res.status = YP_NOKEY;
                if ((hn = strcmp(map, YP_HOSTNAME)) != 0 &&
                    strcmp(map, YP_HOSTADDR) != 0)
                        return (res);

                /* note: lookup_host needs null terminated string */
                (void)strlcpy(keystr, key.dptr, (size_t)key.dsize + 1);
                res.status = lookup_host((hn == 0) ? TRUE : FALSE,
                    host_lookup, db, keystr, &res);
        } else {
                res.valdat.dptr = v.dptr;
                res.valdat.dsize = v.dsize;
        }

 done:
        ypdb_close_db(db);
        return (res);
}

struct ypresp_key_val
ypdb_get_first(const char *domain, const char *map, int ypprivate)
{
        static struct ypresp_key_val res;
        DBM *db;
        datum k, v;

        (void)memset(&res, 0, sizeof(res));

        db = ypdb_open_db(domain, map, &res.status, NULL);

        if (db != NULL && (int)res.status >= 0) {
                k = ypdb_firstkey(db);

                while (yp_private(k, ypprivate))
                        k = ypdb_nextkey(db);

                if (k.dptr == NULL)
                        res.status = YP_NOKEY;
                else {
                        res.keydat.dptr = k.dptr;
                        res.keydat.dsize = k.dsize;
                        v = ypdb_fetch(db, k);
                        if (v.dptr == NULL)
                                res.status = YP_NOKEY;
                        else {
                                res.valdat.dptr = v.dptr;
                                res.valdat.dsize = v.dsize;
                        }
                }
        }

        if (db != NULL)
                ypdb_close_db(db);

        return (res);
}

struct ypresp_key_val
ypdb_get_next(const char *domain, const char *map, datum key, int ypprivate)
{
        static struct ypresp_key_val res;
        DBM *db;
        datum k, v, n;

        (void)memset(&res, 0, sizeof(res));

        db = ypdb_open_db(domain, map, &res.status, NULL);

        if (db != NULL && (int)res.status >= 0) {
                n.dptr = key.dptr;
                n.dsize = key.dsize;
                v.dptr = NULL;
                v.dsize = 0;
                k.dptr = NULL;
                k.dsize = 0;

                n = ypdb_setkey(db, n);

                if (n.dptr != NULL)
                        k = ypdb_nextkey(db);
                else
                        k.dptr = NULL;

                if (k.dptr != NULL)
                        while (yp_private(k, ypprivate))
                                k = ypdb_nextkey(db);

                if (k.dptr == NULL)
                        res.status = YP_NOMORE;
                else {
                        res.keydat.dptr = k.dptr;
                        res.keydat.dsize = k.dsize;
                        v = ypdb_fetch(db, k);
                        if (v.dptr == NULL)
                                res.status = YP_NOMORE;
                        else {
                                res.valdat.dptr = v.dptr;
                                res.valdat.dsize = v.dsize;
                        }
                }
        }

        if (db != NULL)
                ypdb_close_db(db);

        return (res);
}

struct ypresp_order
ypdb_get_order(const char *domain, const char *map)
{
        static struct ypresp_order res;
        static const char *order_key = YP_LAST_KEY;
        char order[MAX_LAST_LEN + 1];
        DBM *db;
        datum k, v;

        (void)memset(&res, 0, sizeof(res));

        db = ypdb_open_db(domain, map, &res.status, NULL);

        if (db != NULL && (int)res.status >= 0) {
                k.dptr = order_key;
                k.dsize = YP_LAST_LEN;

                v = ypdb_fetch(db, k);
                if (v.dptr == NULL)
                        res.status = YP_NOKEY;
                else {
                        (void)strlcpy(order, v.dptr, (size_t)v.dsize + 1);
                        res.ordernum = (u_int) atol(order);
                }
        }

        if (db != NULL)
                ypdb_close_db(db);

        return (res);
}

struct ypresp_master
ypdb_get_master(const char *domain, const char *map)
{
        static struct ypresp_master res;
        static const char *master_key = YP_MASTER_KEY;
        static char master[MAX_MASTER_LEN + 1];
        DBM *db;
        datum k, v;

        (void)memset(&res, 0, sizeof(res));

        db = ypdb_open_db(domain, map, &res.status, NULL);

        if (db != NULL && (int)res.status >= 0) {
                k.dptr = master_key;
                k.dsize = YP_MASTER_LEN;

                v = ypdb_fetch(db, k);
                if (v.dptr == NULL)
                        res.status = YP_NOKEY;
                else {
                        (void)strlcpy(master, v.dptr, (size_t)v.dsize + 1);
                        res.master = &master[0];
                }
        }

        if (db != NULL)
                ypdb_close_db(db);

        return (res);
}

bool_t
ypdb_xdr_get_all(XDR *xdrs, struct ypreq_nokey *req)
{
        static struct ypresp_all resp;
        DBM *db;
        datum k, v;

        (void)memset(&resp, 0, sizeof(resp));

        /*
         * open db, and advance past any private keys we may see
         */
        db = ypdb_open_db(req->domain, req->map,
            &resp.ypresp_all_u.val.status, NULL);

        if (db == NULL || (int)resp.ypresp_all_u.val.status < 0)
                return (FALSE);

        k = ypdb_firstkey(db);
        while (yp_private(k, FALSE))
                k = ypdb_nextkey(db);

        for (;;) {
                if (k.dptr == NULL)
                        break;

                v = ypdb_fetch(db, k);

                if (v.dptr == NULL)
                        break;

                resp.more = TRUE;
                resp.ypresp_all_u.val.status = YP_TRUE;
                resp.ypresp_all_u.val.keydat.dptr = k.dptr;
                resp.ypresp_all_u.val.keydat.dsize = k.dsize;
                resp.ypresp_all_u.val.valdat.dptr = v.dptr;
                resp.ypresp_all_u.val.valdat.dsize = v.dsize;

                if (!xdr_ypresp_all(xdrs, &resp)) {
#ifdef DEBUG
                        syslog(LOG_DEBUG,
                            "ypdb_xdr_get_all: xdr_ypresp_all failed");
#endif
                        return (FALSE);
                }

                /* advance past private keys */
                k = ypdb_nextkey(db);
                while (yp_private(k, FALSE))
                        k = ypdb_nextkey(db);
        }

        (void)memset(&resp, 0, sizeof(resp));
        resp.ypresp_all_u.val.status = YP_NOKEY;
        resp.more = FALSE;

        if (!xdr_ypresp_all(xdrs, &resp)) {
#ifdef DEBUG
                syslog(LOG_DEBUG,
                    "ypdb_xdr_get_all: final xdr_ypresp_all failed");
#endif
                return (FALSE);
        }

        if (db != NULL)
                ypdb_close_db(db);

        return (TRUE);
}

int
ypdb_secure(const char *domain, const char *map)
{
        DBM *db;
        int secure;
        u_int status;
        struct opt_map *map_info = NULL;

        secure = FALSE;

        db = ypdb_open_db(domain, map, &status, &map_info);
        if (db == NULL || (int)status < 0)
                return (secure);
        if (map_info != NULL) 
                secure = map_info->secure;

        ypdb_close_db(db);
        return (secure);
}