diff --git a/usr.sbin/ypserv/yp_dblookup.c b/usr.sbin/ypserv/yp_dblookup.c index ee3a4c2e9d98..c0aefb048cb9 100644 --- a/usr.sbin/ypserv/yp_dblookup.c +++ b/usr.sbin/ypserv/yp_dblookup.c @@ -1,733 +1,727 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1995 * Bill Paul . 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``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 Bill Paul OR CONTRIBUTORS 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "yp_extern.h" int ypdb_debug = 0; enum ypstat yp_errno = YP_TRUE; #define PERM_SECURE (S_IRUSR|S_IWUSR) HASHINFO openinfo = { 4096, /* bsize */ 32, /* ffactor */ 256, /* nelem */ 2048 * 512, /* cachesize */ NULL, /* hash */ 0, /* lorder */ }; #ifdef DB_CACHE #include #ifndef MAXDBS #define MAXDBS 20 #endif static int numdbs = 0; struct dbent { DB *dbp; char *name; char *key; int size; int flags; }; static TAILQ_HEAD(circlehead, circleq_entry) qhead; struct circleq_entry { struct dbent *dbptr; TAILQ_ENTRY(circleq_entry) links; }; /* * Initialize the circular queue. */ void yp_init_dbs(void) { TAILQ_INIT(&qhead); - return; } /* * Dynamically allocate an entry for the circular queue. * Return a NULL pointer on failure. */ static struct circleq_entry * yp_malloc_qent(void) { register struct circleq_entry *q; q = malloc(sizeof(struct circleq_entry)); if (q == NULL) { yp_error("failed to malloc() circleq entry"); return(NULL); } bzero((char *)q, sizeof(struct circleq_entry)); q->dbptr = malloc(sizeof(struct dbent)); if (q->dbptr == NULL) { yp_error("failed to malloc() circleq entry"); free(q); return(NULL); } bzero((char *)q->dbptr, sizeof(struct dbent)); return(q); } /* * Free a previously allocated circular queue * entry. */ static void yp_free_qent(struct circleq_entry *q) { /* * First, close the database. In theory, this is also * supposed to free the resources allocated by the DB * package, including the memory pointed to by q->dbptr->key. * This means we don't have to free q->dbptr->key here. */ if (q->dbptr->dbp) { (void)(q->dbptr->dbp->close)(q->dbptr->dbp); q->dbptr->dbp = NULL; } /* * Then free the database name, which was strdup()'ed. */ free(q->dbptr->name); /* * Free the rest of the dbent struct. */ free(q->dbptr); q->dbptr = NULL; /* * Free the circleq struct. */ free(q); q = NULL; - - return; } /* * Zorch a single entry in the dbent queue and release * all its resources. (This always removes the last entry * in the queue.) */ static void yp_flush(void) { register struct circleq_entry *qptr; qptr = TAILQ_LAST(&qhead, circlehead); TAILQ_REMOVE(&qhead, qptr, links); yp_free_qent(qptr); numdbs--; - - return; } /* * Close all databases, erase all database names and empty the queue. */ void yp_flush_all(void) { register struct circleq_entry *qptr; while (!TAILQ_EMPTY(&qhead)) { qptr = TAILQ_FIRST(&qhead); /* save this */ TAILQ_REMOVE(&qhead, qptr, links); yp_free_qent(qptr); } numdbs = 0; - return; } static char *inter_string = "YP_INTERDOMAIN"; static char *secure_string = "YP_SECURE"; static int inter_sz = sizeof("YP_INTERDOMAIN") - 1; static int secure_sz = sizeof("YP_SECURE") - 1; static int yp_setflags(DB *dbp) { DBT key = { NULL, 0 }, data = { NULL, 0 }; int flags = 0; key.data = inter_string; key.size = inter_sz; if (!(dbp->get)(dbp, &key, &data, 0)) flags |= YP_INTERDOMAIN; key.data = secure_string; key.size = secure_sz; if (!(dbp->get)(dbp, &key, &data, 0)) flags |= YP_SECURE; return(flags); } int yp_testflag(char *map, char *domain, int flag) { char buf[MAXPATHLEN + 2]; register struct circleq_entry *qptr; if (map == NULL || domain == NULL) return(0); strcpy(buf, domain); strcat(buf, "/"); strcat(buf, map); TAILQ_FOREACH(qptr, &qhead, links) { if (!strcmp(qptr->dbptr->name, buf)) { if (qptr->dbptr->flags & flag) return(1); else return(0); } } if (yp_open_db_cache(domain, map, NULL, 0) == NULL) return(0); if (TAILQ_FIRST(&qhead)->dbptr->flags & flag) return(1); return(0); } /* * Add a DB handle and database name to the cache. We only maintain * fixed number of entries in the cache, so if we're asked to store * a new entry when all our slots are already filled, we have to kick * out the entry in the last slot to make room. */ static int yp_cache_db(DB *dbp, char *name, int size) { register struct circleq_entry *qptr; if (numdbs == MAXDBS) { if (ypdb_debug) yp_error("queue overflow -- releasing last slot"); yp_flush(); } /* * Allocate a new queue entry. */ if ((qptr = yp_malloc_qent()) == NULL) { yp_error("failed to allocate a new cache entry"); return(1); } qptr->dbptr->dbp = dbp; qptr->dbptr->name = strdup(name); qptr->dbptr->size = size; qptr->dbptr->key = NULL; qptr->dbptr->flags = yp_setflags(dbp); TAILQ_INSERT_HEAD(&qhead, qptr, links); numdbs++; return(0); } /* * Search the list for a database matching 'name.' If we find it, * move it to the head of the list and return its DB handle. If * not, just fail: yp_open_db_cache() will subsequently try to open * the database itself and call yp_cache_db() to add it to the * list. * * The search works like this: * * - The caller specifies the name of a database to locate. We try to * find an entry in our queue with a matching name. * * - If the caller doesn't specify a key or size, we assume that the * first entry that we encounter with a matching name is returned. * This will result in matches regardless of the key/size values * stored in the queue entry. * * - If the caller also specifies a key and length, we check to see * if the key and length saved in the queue entry also matches. * This lets us return a DB handle that's already positioned at the * correct location within a database. * * - Once we have a match, it gets migrated to the top of the queue * so that it will be easier to find if another request for * the same database comes in later. */ static DB * yp_find_db(const char *name, const char *key, int size) { register struct circleq_entry *qptr; TAILQ_FOREACH(qptr, &qhead, links) { if (!strcmp(qptr->dbptr->name, name)) { if (size) { if (size != qptr->dbptr->size || strncmp(qptr->dbptr->key, key, size)) continue; } else { if (qptr->dbptr->size) continue; } if (qptr != TAILQ_FIRST(&qhead)) { TAILQ_REMOVE(&qhead, qptr, links); TAILQ_INSERT_HEAD(&qhead, qptr, links); } return(qptr->dbptr->dbp); } } return(NULL); } /* * Open a DB database and cache the handle for later use. We first * check the cache to see if the required database is already open. * If so, we fetch the handle from the cache. If not, we try to open * the database and save the handle in the cache for later use. */ DB * yp_open_db_cache(const char *domain, const char *map, const char *key, const int size) { DB *dbp = NULL; char buf[MAXPATHLEN + 2]; /* snprintf(buf, sizeof(buf), "%s/%s", domain, map); */ yp_errno = YP_TRUE; strcpy(buf, domain); strcat(buf, "/"); strcat(buf, map); if ((dbp = yp_find_db(buf, key, size)) != NULL) { return(dbp); } else { if ((dbp = yp_open_db(domain, map)) != NULL) { if (yp_cache_db(dbp, buf, size)) { (void)(dbp->close)(dbp); yp_errno = YP_YPERR; return(NULL); } } } return (dbp); } #endif /* * Open a DB database. */ DB * yp_open_db(const char *domain, const char *map) { DB *dbp = NULL; char buf[MAXPATHLEN + 2]; yp_errno = YP_TRUE; if (map[0] == '.' || strchr(map, '/')) { yp_errno = YP_BADARGS; return (NULL); } #ifdef DB_CACHE if (yp_validdomain(domain)) { yp_errno = YP_NODOM; return(NULL); } #endif snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, domain, map); #ifdef DB_CACHE again: #endif dbp = dbopen(buf, O_RDONLY, PERM_SECURE, DB_HASH, NULL); if (dbp == NULL) { switch (errno) { #ifdef DB_CACHE case ENFILE: /* * We ran out of file descriptors. Nuke an * open one and try again. */ yp_error("ran out of file descriptors"); yp_flush(); goto again; break; #endif case ENOENT: yp_errno = YP_NOMAP; break; case EFTYPE: yp_errno = YP_BADDB; break; default: yp_errno = YP_YPERR; break; } } return (dbp); } /* * Database access routines. * * - yp_get_record(): retrieve an arbitrary key/data pair given one key * to match against. * * - yp_first_record(): retrieve first key/data base in a database. * * - yp_next_record(): retrieve key/data pair that sequentially follows * the supplied key value in the database. */ #ifdef DB_CACHE int yp_get_record(DB *dbp, const DBT *key, DBT *data, int allow) #else int yp_get_record(const char *domain, const char *map, const DBT *key, DBT *data, int allow) #endif { #ifndef DB_CACHE DB *dbp; #endif int rval = 0; #ifndef DB_CACHE static unsigned char buf[YPMAXRECORD]; #endif if (ypdb_debug) yp_error("looking up key [%.*s]", (int)key->size, (char *)key->data); /* * Avoid passing back magic "YP_*" entries unless * the caller specifically requested them by setting * the 'allow' flag. */ if (!allow && !strncmp(key->data, "YP_", 3)) return(YP_NOKEY); #ifndef DB_CACHE if ((dbp = yp_open_db(domain, map)) == NULL) { return(yp_errno); } #endif if ((rval = (dbp->get)(dbp, key, data, 0)) != 0) { #ifdef DB_CACHE TAILQ_FIRST(&qhead)->dbptr->size = 0; #else (void)(dbp->close)(dbp); #endif if (rval == 1) return(YP_NOKEY); else return(YP_BADDB); } if (ypdb_debug) yp_error("result of lookup: key: [%.*s] data: [%.*s]", (int)key->size, (char *)key->data, (int)data->size, (char *)data->data); #ifdef DB_CACHE if (TAILQ_FIRST(&qhead)->dbptr->size) { TAILQ_FIRST(&qhead)->dbptr->key = ""; TAILQ_FIRST(&qhead)->dbptr->size = 0; } #else bcopy(data->data, &buf, data->size); data->data = &buf; (void)(dbp->close)(dbp); #endif return(YP_TRUE); } int yp_first_record(const DB *dbp, DBT *key, DBT *data, int allow) { int rval; #ifndef DB_CACHE static unsigned char buf[YPMAXRECORD]; #endif if (ypdb_debug) yp_error("retrieving first key in map"); if ((rval = (dbp->seq)(dbp,key,data,R_FIRST)) != 0) { #ifdef DB_CACHE TAILQ_FIRST(&qhead)->dbptr->size = 0; #endif if (rval == 1) return(YP_NOKEY); else return(YP_BADDB); } /* Avoid passing back magic "YP_*" records. */ while (!strncmp(key->data, "YP_", 3) && !allow) { if ((rval = (dbp->seq)(dbp,key,data,R_NEXT)) != 0) { #ifdef DB_CACHE TAILQ_FIRST(&qhead)->dbptr->size = 0; #endif if (rval == 1) return(YP_NOKEY); else return(YP_BADDB); } } if (ypdb_debug) yp_error("result of lookup: key: [%.*s] data: [%.*s]", (int)key->size, (char *)key->data, (int)data->size, (char *)data->data); #ifdef DB_CACHE if (TAILQ_FIRST(&qhead)->dbptr->size) { TAILQ_FIRST(&qhead)->dbptr->key = key->data; TAILQ_FIRST(&qhead)->dbptr->size = key->size; } #else bcopy(data->data, &buf, data->size); data->data = &buf; #endif return(YP_TRUE); } int yp_next_record(const DB *dbp, DBT *key, DBT *data, int all, int allow) { static DBT lkey = { NULL, 0 }; static DBT ldata = { NULL, 0 }; int rval; #ifndef DB_CACHE static unsigned char keybuf[YPMAXRECORD]; static unsigned char datbuf[YPMAXRECORD]; #endif if (key == NULL || !key->size || key->data == NULL) { rval = yp_first_record(dbp,key,data,allow); if (rval == YP_NOKEY) return(YP_NOMORE); else { #ifdef DB_CACHE TAILQ_FIRST(&qhead)->dbptr->key = key->data; TAILQ_FIRST(&qhead)->dbptr->size = key->size; #endif return(rval); } } if (ypdb_debug) yp_error("retrieving next key, previous was: [%.*s]", (int)key->size, (char *)key->data); if (!all) { #ifdef DB_CACHE if (TAILQ_FIRST(&qhead)->dbptr->key == NULL) { #endif (dbp->seq)(dbp,&lkey,&ldata,R_FIRST); while (key->size != lkey.size || strncmp(key->data, lkey.data, (int)key->size)) if ((dbp->seq)(dbp,&lkey,&ldata,R_NEXT)) { #ifdef DB_CACHE TAILQ_FIRST(&qhead)->dbptr->size = 0; #endif return(YP_NOKEY); } #ifdef DB_CACHE } #endif } if ((dbp->seq)(dbp,key,data,R_NEXT)) { #ifdef DB_CACHE TAILQ_FIRST(&qhead)->dbptr->size = 0; #endif return(YP_NOMORE); } /* Avoid passing back magic "YP_*" records. */ while (!strncmp(key->data, "YP_", 3) && !allow) if ((dbp->seq)(dbp,key,data,R_NEXT)) { #ifdef DB_CACHE TAILQ_FIRST(&qhead)->dbptr->size = 0; #endif return(YP_NOMORE); } if (ypdb_debug) yp_error("result of lookup: key: [%.*s] data: [%.*s]", (int)key->size, (char *)key->data, (int)data->size, (char *)data->data); #ifdef DB_CACHE if (TAILQ_FIRST(&qhead)->dbptr->size) { TAILQ_FIRST(&qhead)->dbptr->key = key->data; TAILQ_FIRST(&qhead)->dbptr->size = key->size; } #else bcopy(key->data, &keybuf, key->size); lkey.data = &keybuf; lkey.size = key->size; bcopy(data->data, &datbuf, data->size); data->data = &datbuf; #endif return(YP_TRUE); } #ifdef DB_CACHE /* * Database glue functions. */ static DB *yp_currmap_db = NULL; static int yp_allow_db = 0; ypstat yp_select_map(char *map, char *domain, keydat *key, int allow) { if (key == NULL) yp_currmap_db = yp_open_db_cache(domain, map, NULL, 0); else yp_currmap_db = yp_open_db_cache(domain, map, key->keydat_val, key->keydat_len); yp_allow_db = allow; return(yp_errno); } ypstat yp_getbykey(keydat *key, valdat *val) { DBT db_key = { NULL, 0 }, db_val = { NULL, 0 }; ypstat rval; db_key.data = key->keydat_val; db_key.size = key->keydat_len; rval = yp_get_record(yp_currmap_db, &db_key, &db_val, yp_allow_db); if (rval == YP_TRUE) { val->valdat_val = db_val.data; val->valdat_len = db_val.size; } return(rval); } ypstat yp_firstbykey(keydat *key, valdat *val) { DBT db_key = { NULL, 0 }, db_val = { NULL, 0 }; ypstat rval; rval = yp_first_record(yp_currmap_db, &db_key, &db_val, yp_allow_db); if (rval == YP_TRUE) { key->keydat_val = db_key.data; key->keydat_len = db_key.size; val->valdat_val = db_val.data; val->valdat_len = db_val.size; } return(rval); } ypstat yp_nextbykey(keydat *key, valdat *val) { DBT db_key = { NULL, 0 }, db_val = { NULL, 0 }; ypstat rval; db_key.data = key->keydat_val; db_key.size = key->keydat_len; rval = yp_next_record(yp_currmap_db, &db_key, &db_val, 0, yp_allow_db); if (rval == YP_TRUE) { key->keydat_val = db_key.data; key->keydat_len = db_key.size; val->valdat_val = db_val.data; val->valdat_len = db_val.size; } return(rval); } #endif diff --git a/usr.sbin/ypserv/yp_dnslookup.c b/usr.sbin/ypserv/yp_dnslookup.c index b1dc712c35ff..699c4d7e8018 100644 --- a/usr.sbin/ypserv/yp_dnslookup.c +++ b/usr.sbin/ypserv/yp_dnslookup.c @@ -1,551 +1,545 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1995, 1996 * Bill Paul . 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``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 Bill Paul OR CONTRIBUTORS 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 /* * Do standard and reverse DNS lookups using the resolver library. * Take care of all the dirty work here so the main program only has to * pass us a pointer to an array of characters. * * We have to use direct resolver calls here otherwise the YP server * could end up looping by calling itself over and over again until * it disappeared up its own belly button. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "yp_extern.h" static char * parse(struct hostent *hp) { static char result[MAXHOSTNAMELEN * 2]; int i; size_t len; char addr[46]; if (hp == NULL) return(NULL); if (inet_ntop(hp->h_addrtype, hp->h_addr, addr, sizeof(addr)) == NULL) return(NULL); len = strlen(addr) + 1 + strlen(hp->h_name); for (i = 0; hp->h_aliases[i]; i++) len += strlen(hp->h_aliases[i]) + 1; len++; if (len > sizeof(result)) return(NULL); bzero(result, sizeof(result)); snprintf(result, sizeof(result), "%s %s", addr, hp->h_name); for (i = 0; hp->h_aliases[i]; i++) { strcat(result, " "); strcat(result, hp->h_aliases[i]); } return ((char *)&result); } #define MAXPACKET (64*1024) #define DEF_TTL 50 #define BY_DNS_ID 1 #define BY_RPC_XID 2 extern struct hostent *__dns_getanswer(char *, int, char *, int); static TAILQ_HEAD(dns_qhead, circleq_dnsentry) qhead; struct circleq_dnsentry { SVCXPRT *xprt; unsigned long xid; struct sockaddr_in client_addr; unsigned long ypvers; unsigned long id; unsigned long ttl; unsigned long type; unsigned short prot_type; char **domain; char *name; int addrtype; int addrlen; uint32_t addr[4]; /* IPv4 or IPv6 */ TAILQ_ENTRY(circleq_dnsentry) links; }; static int pending = 0; int yp_init_resolver(void) { TAILQ_INIT(&qhead); if (!(_res.options & RES_INIT) && res_init() == -1) { yp_error("res_init failed"); return(1); } if ((resfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { yp_error("couldn't create socket"); return(1); } if (fcntl(resfd, F_SETFL, O_NONBLOCK) == -1) { yp_error("couldn't make resolver socket non-blocking"); return(1); } return(0); } static struct circleq_dnsentry *yp_malloc_dnsent(void) { register struct circleq_dnsentry *q; q = malloc(sizeof(struct circleq_dnsentry)); if (q == NULL) { yp_error("failed to malloc() circleq dns entry"); return(NULL); } return(q); } /* * Transmit a query. */ static unsigned long yp_send_dns_query(char *name, int type) { char buf[MAXPACKET]; int n; HEADER *hptr; int ns; int rval; unsigned long id; bzero(buf, sizeof(buf)); n = res_mkquery(QUERY,name,C_IN,type,NULL,0,NULL,buf,sizeof(buf)); if (n <= 0) { yp_error("res_mkquery failed for %s type %d", name, type); return(0); } hptr = (HEADER *)&buf; id = ntohs(hptr->id); for (ns = 0; ns < _res.nscount; ns++) { rval = sendto(resfd, buf, n, 0, (struct sockaddr *)&_res.nsaddr_list[ns], sizeof(struct sockaddr)); if (rval == -1) { yp_error("sendto failed"); return(0); } } return(id); } static struct circleq_dnsentry * yp_find_dnsqent(unsigned long id, int type) { register struct circleq_dnsentry *q; TAILQ_FOREACH(q, &qhead, links) { switch (type) { case BY_RPC_XID: if (id == q->xid) return(q); break; case BY_DNS_ID: default: if (id == q->id) return(q); break; } } return (NULL); } static void yp_send_dns_reply(struct circleq_dnsentry *q, char *buf) { ypresponse result_v1; ypresp_val result_v2; unsigned long xid; struct sockaddr_in client_addr; xdrproc_t xdrfunc; char *result; /* * Set up correct reply struct and * XDR filter depending on ypvers. */ switch (q->ypvers) { case YPVERS: bzero((char *)&result_v2, sizeof(result_v2)); if (buf == NULL) result_v2.stat = YP_NOKEY; else { result_v2.val.valdat_len = strlen(buf); result_v2.val.valdat_val = buf; result_v2.stat = YP_TRUE; } result = (char *)&result_v2; xdrfunc = (xdrproc_t)xdr_ypresp_val; break; case YPOLDVERS: /* * The odds are we will _never_ execute this * particular code, but we include it anyway * for the sake of completeness. */ bzero((char *)&result_v1, sizeof(result_v1)); result_v1.yp_resptype = YPRESP_VAL; #define YPVAL ypresponse_u.yp_resp_valtype if (buf == NULL) result_v1.YPVAL.stat = YP_NOKEY; else { result_v1.YPVAL.val.valdat_len = strlen(buf); result_v1.YPVAL.val.valdat_val = buf; result_v1.YPVAL.stat = YP_TRUE; } result = (char *)&result_v1; xdrfunc = (xdrproc_t)xdr_ypresponse; break; default: yp_error("bad YP program version (%lu)!", q->ypvers); return; break; } if (debug) yp_error("sending dns reply to %s (%lu)", inet_ntoa(q->client_addr.sin_addr), q->id); /* * XXX This is disgusting. There's basically one transport * handle for UDP, but we're holding off on replying to a * client until we're ready, by which time we may have received * several other queries from other clients with different * transaction IDs. So to make the delayed response thing work, * we have to save the transaction ID and client address of * each request, then jam them into the transport handle when * we're ready to send a reply. Then after we've send the reply, * we put the old transaction ID and remote address back the * way we found 'em. This is _INCREDIBLY_ non-portable; it's * not even supported by the RPC library. */ /* * XXX Don't frob the transaction ID for TCP handles. */ if (q->prot_type == SOCK_DGRAM) xid = svcudp_set_xid(q->xprt, q->xid); client_addr = q->xprt->xp_raddr; q->xprt->xp_raddr = q->client_addr; if (!svc_sendreply(q->xprt, xdrfunc, result)) yp_error("svc_sendreply failed"); /* * Now that we sent the reply, * put the handle back the way it was. */ if (q->prot_type == SOCK_DGRAM) svcudp_set_xid(q->xprt, xid); q->xprt->xp_raddr = client_addr; - - return; } /* * Decrement TTL on all queue entries, possibly nuking * any that have been around too long without being serviced. */ void yp_prune_dnsq(void) { register struct circleq_dnsentry *q, *n; q = TAILQ_FIRST(&qhead); while (q != NULL) { q->ttl--; n = TAILQ_NEXT(q, links); if (!q->ttl) { TAILQ_REMOVE(&qhead, q, links); free(q->name); free(q); pending--; } q = n; } if (pending < 0) pending = 0; - - return; } /* * Data is pending on the DNS socket; check for valid replies * to our queries and dispatch them to waiting clients. */ void yp_run_dnsq(void) { register struct circleq_dnsentry *q; char buf[sizeof(HEADER) + MAXPACKET]; struct sockaddr_in sin; socklen_t len; int rval; HEADER *hptr; struct hostent *hent; if (debug) yp_error("running dns queue"); bzero(buf, sizeof(buf)); len = sizeof(struct sockaddr_in); rval = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &len); if (rval == -1) { yp_error("recvfrom failed: %s", strerror(errno)); return; } /* * We may have data left in the socket that represents * replies to earlier queries that we don't care about * anymore. If there are no lookups pending or the packet * ID doesn't match any of the queue IDs, just drop it * on the floor. */ hptr = (HEADER *)&buf; if (!pending || (q = yp_find_dnsqent(ntohs(hptr->id), BY_DNS_ID)) == NULL) { /* ignore */ return; } if (debug) yp_error("got dns reply from %s", inet_ntoa(sin.sin_addr)); hent = __dns_getanswer(buf, rval, q->name, q->type); if (hent != NULL) { if (q->type == T_PTR) { hent->h_addr = (char *)q->addr; hent->h_addrtype = q->addrtype; hent->h_length = q->addrlen; } } /* Got an answer ready for a client -- send it off. */ yp_send_dns_reply(q, parse(hent)); pending--; TAILQ_REMOVE(&qhead, q, links); free(q->name); free(q); /* Decrement TTLs on other entries while we're here. */ yp_prune_dnsq(); - - return; } /* * Queue and transmit an asynchronous DNS hostname lookup. */ ypstat yp_async_lookup_name(struct svc_req *rqstp, char *name, int af) { register struct circleq_dnsentry *q; socklen_t len; int type; /* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */ type = -1; len = sizeof(type); if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET, SO_TYPE, &type, &len) == -1) { yp_error("getsockopt failed: %s", strerror(errno)); return(YP_YPERR); } /* Avoid transmitting dupe requests. */ if (type == SOCK_DGRAM && yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL) return(YP_TRUE); if ((q = yp_malloc_dnsent()) == NULL) return(YP_YPERR); q->type = (af == AF_INET) ? T_A : T_AAAA; q->ttl = DEF_TTL; q->xprt = rqstp->rq_xprt; q->ypvers = rqstp->rq_vers; q->prot_type = type; if (q->prot_type == SOCK_DGRAM) q->xid = svcudp_get_xid(q->xprt); q->client_addr = q->xprt->xp_raddr; q->domain = _res.dnsrch; q->id = yp_send_dns_query(name, q->type); if (q->id == 0) { yp_error("DNS query failed"); free(q); return(YP_YPERR); } q->name = strdup(name); TAILQ_INSERT_HEAD(&qhead, q, links); pending++; if (debug) yp_error("queueing async DNS name lookup (%lu)", q->id); yp_prune_dnsq(); return(YP_TRUE); } /* * Queue and transmit an asynchronous DNS IP address lookup. */ ypstat yp_async_lookup_addr(struct svc_req *rqstp, char *addr, int af) { register struct circleq_dnsentry *q; char buf[MAXHOSTNAMELEN], *qp; uint32_t abuf[4]; /* IPv4 or IPv6 */ u_char *uaddr = (u_char *)abuf; socklen_t len; int type, n; /* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */ type = -1; len = sizeof(type); if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET, SO_TYPE, &type, &len) == -1) { yp_error("getsockopt failed: %s", strerror(errno)); return(YP_YPERR); } /* Avoid transmitting dupe requests. */ if (type == SOCK_DGRAM && yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL) return(YP_TRUE); switch (af) { case AF_INET: if (inet_aton(addr, (struct in_addr *)uaddr) != 1) return(YP_NOKEY); snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff), (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff)); len = INADDRSZ; break; case AF_INET6: if (inet_pton(af, addr, uaddr) != 1) return(YP_NOKEY); qp = buf; for (n = IN6ADDRSZ - 1; n >= 0; n--) { qp += (size_t)sprintf(qp, "%x.%x.", uaddr[n] & 0xf, (uaddr[n] >> 4) & 0xf); } strlcat(buf, "ip6.arpa", sizeof(buf)); len = IN6ADDRSZ; break; default: return(YP_YPERR); } if ((q = yp_malloc_dnsent()) == NULL) return(YP_YPERR); if (debug) yp_error("DNS address is: %s", buf); q->type = T_PTR; q->ttl = DEF_TTL; q->xprt = rqstp->rq_xprt; q->ypvers = rqstp->rq_vers; q->domain = NULL; q->prot_type = type; if (q->prot_type == SOCK_DGRAM) q->xid = svcudp_get_xid(q->xprt); q->client_addr = q->xprt->xp_raddr; q->id = yp_send_dns_query(buf, q->type); if (q->id == 0) { yp_error("DNS query failed"); free(q); return(YP_YPERR); } memcpy(q->addr, uaddr, len); q->addrlen = len; q->addrtype = af; q->name = strdup(buf); TAILQ_INSERT_HEAD(&qhead, q, links); pending++; if (debug) yp_error("queueing async DNS address lookup (%lu)", q->id); yp_prune_dnsq(); return(YP_TRUE); } diff --git a/usr.sbin/ypserv/yp_main.c b/usr.sbin/ypserv/yp_main.c index dac006d4bc28..d326603a9229 100644 --- a/usr.sbin/ypserv/yp_main.c +++ b/usr.sbin/ypserv/yp_main.c @@ -1,579 +1,578 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1995 * Bill Paul . 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``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 Bill Paul OR CONTRIBUTORS 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 /* * ypserv startup function. * We need out own main() since we have to do some additional work * that rpcgen won't do for us. Most of this file was generated using * rpcgen.new, and later modified. */ #include #include #include #include #include #include "yp.h" #include #include #include #include #include #include #include /* getenv, exit */ #include /* strcmp */ #include #include #ifdef __cplusplus #include /* getdtablesize, open */ #endif /* __cplusplus */ #include #include #include "yp_extern.h" #include #include #include #ifndef SIG_PF #define SIG_PF void(*)(int) #endif #define _RPCSVC_CLOSEDOWN 120 int _rpcpmstart; /* Started by a port monitor ? */ static int _rpcfdtype; /* Whether Stream or Datagram? */ static int _rpcaf; static int _rpcfd; /* States a server can be in wrt request */ #define _IDLE 0 #define _SERVED 1 #define _SERVING 2 extern void ypprog_1(struct svc_req *, SVCXPRT *); extern void ypprog_2(struct svc_req *, SVCXPRT *); extern int _rpc_dtablesize(void); extern int _rpcsvcstate; /* Set when a request is serviced */ char *progname = "ypserv"; char *yp_dir = _PATH_YP; int debug; int do_dns = 0; int resfd; struct socklistent { int sle_sock; struct sockaddr_storage sle_ss; SLIST_ENTRY(socklistent) sle_next; }; static SLIST_HEAD(, socklistent) sle_head = SLIST_HEAD_INITIALIZER(sle_head); struct bindaddrlistent { const char *ble_hostname; SLIST_ENTRY(bindaddrlistent) ble_next; }; static SLIST_HEAD(, bindaddrlistent) ble_head = SLIST_HEAD_INITIALIZER(ble_head); static char *servname = "0"; static void _msgout(char* msg, ...) { va_list ap; va_start(ap, msg); if (debug) { if (_rpcpmstart) vsyslog(LOG_ERR, msg, ap); else vwarnx(msg, ap); } else vsyslog(LOG_ERR, msg, ap); va_end(ap); } pid_t yp_pid; static void yp_svc_run(void) { #ifdef FD_SETSIZE fd_set readfds; #else int readfds; #endif /* def FD_SETSIZE */ int fd_setsize = _rpc_dtablesize(); struct timeval timeout; /* Establish the identity of the parent ypserv process. */ yp_pid = getpid(); for (;;) { #ifdef FD_SETSIZE readfds = svc_fdset; #else readfds = svc_fds; #endif /* def FD_SETSIZE */ FD_SET(resfd, &readfds); timeout.tv_sec = RESOLVER_TIMEOUT; timeout.tv_usec = 0; switch (select(fd_setsize, &readfds, NULL, NULL, &timeout)) { case -1: if (errno == EINTR) { continue; } warn("svc_run: - select failed"); return; case 0: if (getpid() == yp_pid) yp_prune_dnsq(); break; default: if (getpid() == yp_pid) { if (FD_ISSET(resfd, &readfds)) { yp_run_dnsq(); FD_CLR(resfd, &readfds); } svc_getreqset(&readfds); } } if (yp_pid != getpid()) _exit(0); } } static void unregister(void) { (void)svc_unreg(YPPROG, YPVERS); (void)svc_unreg(YPPROG, YPOLDVERS); } static void reaper(int sig) { int status; int saved_errno; saved_errno = errno; if (sig == SIGHUP) { load_securenets(); #ifdef DB_CACHE yp_flush_all(); #endif errno = saved_errno; return; } if (sig == SIGCHLD) { while (wait3(&status, WNOHANG, NULL) > 0) children--; } else { unregister(); exit(0); } errno = saved_errno; - return; } static void usage(void) { fprintf(stderr, "usage: ypserv [-h addr] [-d] [-n] [-p path] [-P port]\n"); exit(1); } static void closedown(int sig) { if (_rpcsvcstate == _IDLE) { extern fd_set svc_fdset; static int size; int i, openfd; if (_rpcfdtype == SOCK_DGRAM) { unregister(); exit(0); } if (size == 0) { size = getdtablesize(); } for (i = 0, openfd = 0; i < size && openfd < 2; i++) if (FD_ISSET(i, &svc_fdset)) openfd++; if (openfd <= 1) { unregister(); exit(0); } } if (_rpcsvcstate == _SERVED) _rpcsvcstate = _IDLE; (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } static int create_service(const int sock, const struct netconfig *nconf, const struct __rpc_sockinfo *si) { int error; SVCXPRT *transp; struct addrinfo hints, *res, *res0; struct socklistent *slep; struct bindaddrlistent *blep; struct netbuf svcaddr; SLIST_INIT(&sle_head); memset(&hints, 0, sizeof(hints)); memset(&svcaddr, 0, sizeof(svcaddr)); hints.ai_family = si->si_af; hints.ai_socktype = si->si_socktype; hints.ai_protocol = si->si_proto; /* * Build socketlist from bindaddrlist. */ if (sock == RPC_ANYFD) { SLIST_FOREACH(blep, &ble_head, ble_next) { if (blep->ble_hostname == NULL) hints.ai_flags = AI_PASSIVE; else hints.ai_flags = 0; error = getaddrinfo(blep->ble_hostname, servname, &hints, &res0); if (error) { _msgout("getaddrinfo(): %s", gai_strerror(error)); return -1; } for (res = res0; res; res = res->ai_next) { int s; s = __rpc_nconf2fd(nconf); if (s < 0) { if (errno == EAFNOSUPPORT) _msgout("unsupported" " transport: %s", nconf->nc_netid); else _msgout("cannot create" " %s socket: %s", nconf->nc_netid, strerror(errno)); freeaddrinfo(res0); return -1; } if (bindresvport_sa(s, res->ai_addr) == -1) { if ((errno != EPERM) || (bind(s, res->ai_addr, res->ai_addrlen) == -1)) { _msgout("cannot bind " "%s socket: %s", nconf->nc_netid, strerror(errno)); freeaddrinfo(res0); close(sock); return -1; } } if (nconf->nc_semantics != NC_TPI_CLTS) listen(s, SOMAXCONN); slep = malloc(sizeof(*slep)); if (slep == NULL) { _msgout("malloc failed: %s", strerror(errno)); freeaddrinfo(res0); close(s); return -1; } memset(slep, 0, sizeof(*slep)); memcpy(&slep->sle_ss, res->ai_addr, res->ai_addrlen); slep->sle_sock = s; SLIST_INSERT_HEAD(&sle_head, slep, sle_next); /* * If servname == "0", redefine it by using * the bound socket. */ if (strncmp("0", servname, 1) == 0) { struct sockaddr *sap; socklen_t slen; char *sname; sname = malloc(NI_MAXSERV); if (sname == NULL) { _msgout("malloc(): %s", strerror(errno)); freeaddrinfo(res0); close(s); return -1; } memset(sname, 0, NI_MAXSERV); sap = (struct sockaddr *)&slep->sle_ss; slen = sizeof(*sap); error = getsockname(s, sap, &slen); if (error) { _msgout("getsockname(): %s", strerror(errno)); freeaddrinfo(res0); close(s); free(sname); return -1; } error = getnameinfo(sap, slen, NULL, 0, sname, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); if (error) { _msgout("getnameinfo(): %s", strerror(errno)); freeaddrinfo(res0); close(s); free(sname); return -1; } servname = sname; } } freeaddrinfo(res0); } } else { slep = malloc(sizeof(*slep)); if (slep == NULL) { _msgout("malloc failed: %s", strerror(errno)); return -1; } memset(slep, 0, sizeof(*slep)); slep->sle_sock = sock; SLIST_INSERT_HEAD(&sle_head, slep, sle_next); } /* * Traverse socketlist and create rpc service handles for each socket. */ SLIST_FOREACH(slep, &sle_head, sle_next) { if (nconf->nc_semantics == NC_TPI_CLTS) transp = svc_dg_create(slep->sle_sock, 0, 0); else transp = svc_vc_create(slep->sle_sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); if (transp == NULL) { _msgout("unable to create service: %s", nconf->nc_netid); continue; } if (!svc_reg(transp, YPPROG, YPOLDVERS, ypprog_1, NULL)) { svc_destroy(transp); close(slep->sle_sock); _msgout("unable to register (YPPROG, YPOLDVERS, %s):" " %s", nconf->nc_netid, strerror(errno)); continue; } if (!svc_reg(transp, YPPROG, YPVERS, ypprog_2, NULL)) { svc_destroy(transp); close(slep->sle_sock); _msgout("unable to register (YPPROG, YPVERS, %s): %s", nconf->nc_netid, strerror(errno)); continue; } } while(!(SLIST_EMPTY(&sle_head))) SLIST_REMOVE_HEAD(&sle_head, sle_next); /* * Register RPC service to rpcbind by using AI_PASSIVE address. */ hints.ai_flags = AI_PASSIVE; error = getaddrinfo(NULL, servname, &hints, &res0); if (error) { _msgout("getaddrinfo(): %s", gai_strerror(error)); return -1; } svcaddr.buf = res0->ai_addr; svcaddr.len = res0->ai_addrlen; if (si->si_af == AF_INET) { /* XXX: ignore error intentionally */ rpcb_set(YPPROG, YPOLDVERS, nconf, &svcaddr); } /* XXX: ignore error intentionally */ rpcb_set(YPPROG, YPVERS, nconf, &svcaddr); freeaddrinfo(res0); return 0; } int main(int argc, char *argv[]) { int ch; int error; int ntrans; void *nc_handle; struct netconfig *nconf; struct __rpc_sockinfo si; struct bindaddrlistent *blep; memset(&si, 0, sizeof(si)); SLIST_INIT(&ble_head); while ((ch = getopt(argc, argv, "dh:np:P:")) != -1) { switch (ch) { case 'd': debug = ypdb_debug = 1; break; case 'h': blep = malloc(sizeof(*blep)); if (blep == NULL) err(1, "malloc() failed: -h %s", optarg); blep->ble_hostname = optarg; SLIST_INSERT_HEAD(&ble_head, blep, ble_next); break; case 'n': do_dns = 1; break; case 'p': yp_dir = optarg; break; case 'P': servname = optarg; break; default: usage(); } } /* * Add "anyaddr" entry if no -h is specified. */ if (SLIST_EMPTY(&ble_head)) { blep = malloc(sizeof(*blep)); if (blep == NULL) err(1, "malloc() failed"); memset(blep, 0, sizeof(*blep)); SLIST_INSERT_HEAD(&ble_head, blep, ble_next); } load_securenets(); yp_init_resolver(); #ifdef DB_CACHE yp_init_dbs(); #endif nc_handle = setnetconfig(); if (nc_handle == NULL) err(1, "cannot read %s", NETCONFIG); if (__rpc_fd2sockinfo(0, &si) != 0) { /* invoked from inetd */ _rpcpmstart = 1; _rpcfdtype = si.si_socktype; _rpcaf = si.si_af; _rpcfd = 0; openlog("ypserv", LOG_PID, LOG_DAEMON); } else { /* standalone mode */ if (!debug) { if (daemon(0,0)) { err(1,"cannot fork"); } openlog("ypserv", LOG_PID, LOG_DAEMON); } _rpcpmstart = 0; _rpcaf = AF_INET; _rpcfd = RPC_ANYFD; unregister(); } if (madvise(NULL, 0, MADV_PROTECT) != 0) _msgout("madvise(): %s", strerror(errno)); /* * Create RPC service for each transport. */ ntrans = 0; while((nconf = getnetconfig(nc_handle))) { if ((nconf->nc_flag & NC_VISIBLE)) { if (__rpc_nconf2sockinfo(nconf, &si) == 0) { _msgout("cannot get information for %s. " "Ignored.", nconf->nc_netid); continue; } if (_rpcpmstart) { if (si.si_socktype != _rpcfdtype || si.si_af != _rpcaf) continue; } else if (si.si_af != _rpcaf) continue; error = create_service(_rpcfd, nconf, &si); if (error) { endnetconfig(nc_handle); exit(1); } ntrans++; } } endnetconfig(nc_handle); while(!(SLIST_EMPTY(&ble_head))) SLIST_REMOVE_HEAD(&ble_head, ble_next); if (ntrans == 0) { _msgout("no transport is available. Aborted."); exit(1); } if (_rpcpmstart) { (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } /* * Make sure SIGPIPE doesn't blow us away while servicing TCP * connections. */ (void) signal(SIGPIPE, SIG_IGN); (void) signal(SIGCHLD, (SIG_PF) reaper); (void) signal(SIGTERM, (SIG_PF) reaper); (void) signal(SIGINT, (SIG_PF) reaper); (void) signal(SIGHUP, (SIG_PF) reaper); yp_svc_run(); _msgout("svc_run returned"); exit(1); /* NOTREACHED */ } diff --git a/usr.sbin/ypserv/yp_server.c b/usr.sbin/ypserv/yp_server.c index 8bfff7355a16..62e45e35cbe1 100644 --- a/usr.sbin/ypserv/yp_server.c +++ b/usr.sbin/ypserv/yp_server.c @@ -1,987 +1,985 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1995 * Bill Paul . 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``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 Bill Paul OR CONTRIBUTORS 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 #include "yp.h" #include "yp_extern.h" #include #include #include #include #include #include #include #include #include #include int children = 0; #define MASTER_STRING "YP_MASTER_NAME" #define MASTER_SZ sizeof(MASTER_STRING) - 1 #define ORDER_STRING "YP_LAST_MODIFIED" #define ORDER_SZ sizeof(ORDER_STRING) - 1 static pid_t yp_fork(void) { if (yp_pid != getpid()) { yp_error("child %d trying to fork!", getpid()); errno = EEXIST; return(-1); } return(fork()); } /* * NIS v2 support. This is where most of the action happens. */ void * ypproc_null_2_svc(void *argp, struct svc_req *rqstp) { static char * result; static char rval = 0; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) #else if (yp_access(NULL, (struct svc_req *)rqstp)) #endif return(NULL); result = &rval; return((void *) &result); } bool_t * ypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp) { static bool_t result; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) { #else if (yp_access(NULL, (struct svc_req *)rqstp)) { #endif result = FALSE; return (&result); } if (argp == NULL || yp_validdomain(*argp)) result = FALSE; else result = TRUE; return (&result); } bool_t * ypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp) { static bool_t result; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) #else if (yp_access(NULL, (struct svc_req *)rqstp)) #endif return (NULL); if (argp == NULL || yp_validdomain(*argp)) return (NULL); else result = TRUE; return (&result); } ypresp_val * ypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp) { static ypresp_val result; result.val.valdat_val = ""; result.val.valdat_len = 0; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return (&result); } if (argp->domain == NULL || argp->map == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_select_map(argp->map, argp->domain, NULL, 1) != YP_TRUE) { result.stat = yp_errno; return(&result); } result.stat = yp_getbykey(&argp->key, &result.val); /* * Do DNS lookups for hosts maps if database lookup failed. */ #ifdef DB_CACHE if (do_dns && result.stat != YP_TRUE && (yp_testflag(argp->map, argp->domain, YP_INTERDOMAIN) || (strstr(argp->map, "hosts") || strstr(argp->map, "ipnodes")))) { #else if (do_dns && result.stat != YP_TRUE && (strstr(argp->map, "hosts") || strstr(argp->map, "ipnodes"))) { #endif char *nbuf; nbuf = alloca(argp->key.keydat_len + 1); /* NUL terminate! NUL terminate!! NUL TERMINATE!!! */ bcopy(argp->key.keydat_val, nbuf, argp->key.keydat_len); nbuf[argp->key.keydat_len] = '\0'; if (debug) yp_error("doing DNS lookup of %s", nbuf); if (!strcmp(argp->map, "hosts.byname")) result.stat = yp_async_lookup_name(rqstp, nbuf, AF_INET); else if (!strcmp(argp->map, "hosts.byaddr")) result.stat = yp_async_lookup_addr(rqstp, nbuf, AF_INET); else if (!strcmp(argp->map, "ipnodes.byname")) result.stat = yp_async_lookup_name(rqstp, nbuf, AF_INET6); else if (!strcmp(argp->map, "ipnodes.byaddr")) result.stat = yp_async_lookup_addr(rqstp, nbuf, AF_INET6); if (result.stat == YP_TRUE) return(NULL); } return (&result); } ypresp_key_val * ypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_key_val result; result.val.valdat_val = result.key.keydat_val = ""; result.val.valdat_len = result.key.keydat_len = 0; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return (&result); } if (argp->domain == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_select_map(argp->map, argp->domain, NULL, 0) != YP_TRUE) { result.stat = yp_errno; return(&result); } result.stat = yp_firstbykey(&result.key, &result.val); return (&result); } ypresp_key_val * ypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp) { static ypresp_key_val result; result.val.valdat_val = result.key.keydat_val = ""; result.val.valdat_len = result.key.keydat_len = 0; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return (&result); } if (argp->domain == NULL || argp->map == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_select_map(argp->map, argp->domain, &argp->key, 0) != YP_TRUE) { result.stat = yp_errno; return(&result); } result.key.keydat_len = argp->key.keydat_len; result.key.keydat_val = argp->key.keydat_val; result.stat = yp_nextbykey(&result.key, &result.val); return (&result); } static void ypxfr_callback(ypxfrstat rval, struct sockaddr_in *addr, unsigned int transid, unsigned int prognum, unsigned long port) { CLIENT *clnt; int sock = RPC_ANYSOCK; struct timeval timeout; yppushresp_xfr ypxfr_resp; struct rpc_err err; timeout.tv_sec = 5; timeout.tv_usec = 0; addr->sin_port = htons(port); if ((clnt = clntudp_create(addr,prognum,1,timeout,&sock)) == NULL) { yp_error("%s: %s", inet_ntoa(addr->sin_addr), clnt_spcreateerror("failed to establish callback handle")); return; } ypxfr_resp.status = rval; ypxfr_resp.transid = transid; /* Turn the timeout off -- we don't want to block. */ timeout.tv_sec = 0; if (clnt_control(clnt, CLSET_TIMEOUT, &timeout) == FALSE) yp_error("failed to set timeout on ypproc_xfr callback"); if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) { clnt_geterr(clnt, &err); if (err.re_status != RPC_SUCCESS && err.re_status != RPC_TIMEDOUT) yp_error("%s", clnt_sperror(clnt, "ypxfr callback failed")); } clnt_destroy(clnt); - return; } #define YPXFR_RETURN(CODE) \ /* Order is important: send regular RPC reply, then callback */ \ result.xfrstat = CODE; \ svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_ypresp_xfr, &result); \ ypxfr_callback(CODE,rqhost,argp->transid, \ argp->prog,argp->port); \ return(NULL); ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp) { static ypresp_xfr result; struct sockaddr_in *rqhost; ypresp_master *mres; ypreq_nokey mreq; result.transid = argp->transid; rqhost = svc_getcaller(rqstp->rq_xprt); #ifdef DB_CACHE if (yp_access(argp->map_parms.map, argp->map_parms.domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) { #endif YPXFR_RETURN(YPXFR_REFUSED) } if (argp->map_parms.domain == NULL) { YPXFR_RETURN(YPXFR_BADARGS) } if (yp_validdomain(argp->map_parms.domain)) { YPXFR_RETURN(YPXFR_NODOM) } /* * Determine the master host ourselves. The caller may * be up to no good. This has the side effect of verifying * that the requested map and domain actually exist. */ mreq.domain = argp->map_parms.domain; mreq.map = argp->map_parms.map; mres = ypproc_master_2_svc(&mreq, rqstp); if (mres->stat != YP_TRUE) { yp_error("couldn't find master for map %s@%s", argp->map_parms.map, argp->map_parms.domain); yp_error("host at %s (%s) may be pulling my leg", argp->map_parms.peer, inet_ntoa(rqhost->sin_addr)); YPXFR_RETURN(YPXFR_REFUSED) } switch (yp_fork()) { case 0: { char g[11], t[11], p[11]; char ypxfr_command[MAXPATHLEN + 2]; snprintf (ypxfr_command, sizeof(ypxfr_command), "%sypxfr", _PATH_LIBEXEC); snprintf (t, sizeof(t), "%u", argp->transid); snprintf (g, sizeof(g), "%u", argp->prog); snprintf (p, sizeof(p), "%u", argp->port); if (debug) { close(0); close(1); close(2); } if (strcmp(yp_dir, _PATH_YP)) { execl(ypxfr_command, "ypxfr", "-d", argp->map_parms.domain, "-h", mres->peer, "-p", yp_dir, "-C", t, g, inet_ntoa(rqhost->sin_addr), p, argp->map_parms.map, NULL); } else { execl(ypxfr_command, "ypxfr", "-d", argp->map_parms.domain, "-h", mres->peer, "-C", t, g, inet_ntoa(rqhost->sin_addr), p, argp->map_parms.map, NULL); } yp_error("ypxfr execl(%s): %s", ypxfr_command, strerror(errno)); YPXFR_RETURN(YPXFR_XFRERR) /* * Just to safe, prevent PR #10970 from biting us in * the unlikely case that execing ypxfr fails. We don't * want to have any child processes spawned from this * child process. */ _exit(0); break; } case -1: yp_error("ypxfr fork(): %s", strerror(errno)); YPXFR_RETURN(YPXFR_XFRERR) break; default: result.xfrstat = YPXFR_SUCC; children++; break; } return (&result); } #undef YPXFR_RETURN void * ypproc_clear_2_svc(void *argp, struct svc_req *rqstp) { static char * result; static char rval = 0; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) #else if (yp_access(NULL, (struct svc_req *)rqstp)) #endif return (NULL); #ifdef DB_CACHE /* clear out the database cache */ yp_flush_all(); #endif /* Re-read the securenets database for the hell of it. */ load_securenets(); result = &rval; return((void *) &result); } /* * For ypproc_all, we have to send a stream of ypresp_all structures * via TCP, but the XDR filter generated from the yp.x protocol * definition file only serializes one such structure. This means that * to send the whole stream, you need a wrapper which feeds all the * records into the underlying XDR routine until it hits an 'EOF.' * But to use the wrapper, you have to violate the boundaries between * RPC layers by calling svc_sendreply() directly from the ypproc_all * service routine instead of letting the RPC dispatcher do it. * * Bleah. */ /* * Custom XDR routine for serialzing results of ypproc_all: keep * reading from the database and spew until we run out of records * or encounter an error. */ static bool_t xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp) { while (1) { /* Get a record. */ if ((objp->ypresp_all_u.val.stat = yp_nextbykey(&objp->ypresp_all_u.val.key, &objp->ypresp_all_u.val.val)) == YP_TRUE) { objp->more = TRUE; } else { objp->more = FALSE; } /* Serialize. */ if (!xdr_ypresp_all(xdrs, objp)) return(FALSE); if (objp->more == FALSE) return(TRUE); } } ypresp_all * ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_all result; /* * Set this here so that the client will be forced to make * at least one attempt to read from us even if all we're * doing is returning an error. */ result.more = TRUE; result.ypresp_all_u.val.key.keydat_len = 0; result.ypresp_all_u.val.key.keydat_val = ""; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.ypresp_all_u.val.stat = YP_YPERR; return (&result); } if (argp->domain == NULL || argp->map == NULL) { result.ypresp_all_u.val.stat = YP_BADARGS; return (&result); } /* * XXX If we hit the child limit, fail the request. * If we don't, and the map is large, we could block for * a long time in the parent. */ if (children >= MAX_CHILDREN) { result.ypresp_all_u.val.stat = YP_YPERR; return(&result); } /* * The ypproc_all procedure can take a while to complete. * Best to handle it in a subprocess so the parent doesn't * block. (Is there a better way to do this? Maybe with * async socket I/O?) */ if (!debug) { switch (yp_fork()) { case 0: break; case -1: yp_error("ypall fork(): %s", strerror(errno)); result.ypresp_all_u.val.stat = YP_YPERR; return(&result); break; default: children++; return (NULL); break; } } /* * Fix for PR #10971: don't let the child ypserv share * DB handles with the parent process. */ #ifdef DB_CACHE yp_flush_all(); #endif if (yp_select_map(argp->map, argp->domain, &result.ypresp_all_u.val.key, 0) != YP_TRUE) { result.ypresp_all_u.val.stat = yp_errno; return(&result); } /* Kick off the actual data transfer. */ svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_my_ypresp_all, &result); /* * Proper fix for PR #10970: exit here so that we don't risk * having a child spawned from this sub-process. */ if (!debug) _exit(0); return &result; } ypresp_master * ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_master result; static char ypvalbuf[YPMAXRECORD]; keydat key = { MASTER_SZ, MASTER_STRING }; valdat val; result.peer = ""; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return(&result); } if (argp->domain == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) { result.stat = yp_errno; return(&result); } /* * Note that we copy the data retrieved from the database to * a private buffer and NUL terminate the buffer rather than * terminating the data in place. We do this because by stuffing * a '\0' into data.data, we will actually be corrupting memory * allocated by the DB package. This is a bad thing now that we * cache DB handles rather than closing the database immediately. */ result.stat = yp_getbykey(&key, &val); if (result.stat == YP_TRUE) { bcopy(val.valdat_val, &ypvalbuf, val.valdat_len); ypvalbuf[val.valdat_len] = '\0'; result.peer = ypvalbuf; } else result.peer = ""; return (&result); } ypresp_order * ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_order result; keydat key = { ORDER_SZ, ORDER_STRING }; valdat val; result.ordernum = 0; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return(&result); } if (argp->domain == NULL) { result.stat = YP_BADARGS; return (&result); } /* * We could just check the timestamp on the map file, * but that's a hack: we'll only know the last time the file * was touched, not the last time the database contents were * updated. */ if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) { result.stat = yp_errno; return(&result); } result.stat = yp_getbykey(&key, &val); if (result.stat == YP_TRUE) result.ordernum = atoi(val.valdat_val); else result.ordernum = 0; return (&result); } static void yp_maplist_free(struct ypmaplist *yp_maplist) { register struct ypmaplist *next; while (yp_maplist) { next = yp_maplist->next; free(yp_maplist->map); free(yp_maplist); yp_maplist = next; } - return; } static struct ypmaplist * yp_maplist_create(const char *domain) { char yp_mapdir[MAXPATHLEN + 2]; char yp_mapname[MAXPATHLEN + 2]; struct ypmaplist *cur = NULL; struct ypmaplist *yp_maplist = NULL; DIR *dird; struct dirent *dirp; struct stat statbuf; snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain); if ((dird = opendir(yp_mapdir)) == NULL) { yp_error("opendir(%s) failed: %s", yp_mapdir, strerror(errno)); return(NULL); } while ((dirp = readdir(dird)) != NULL) { if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) { snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s", yp_mapdir,dirp->d_name); if (stat(yp_mapname, &statbuf) < 0 || !S_ISREG(statbuf.st_mode)) continue; if ((cur = (struct ypmaplist *) malloc(sizeof(struct ypmaplist))) == NULL) { yp_error("malloc() failed"); closedir(dird); yp_maplist_free(yp_maplist); return(NULL); } if ((cur->map = strdup(dirp->d_name)) == NULL) { yp_error("strdup() failed: %s",strerror(errno)); closedir(dird); yp_maplist_free(yp_maplist); free(cur); return(NULL); } cur->next = yp_maplist; yp_maplist = cur; if (debug) yp_error("map: %s", yp_maplist->map); } } closedir(dird); return(yp_maplist); } ypresp_maplist * ypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp) { static ypresp_maplist result = { 0, NULL }; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) { #else if (yp_access(NULL, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return(&result); } if (argp == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_validdomain(*argp)) { result.stat = YP_NODOM; return (&result); } /* * We have to construct a linked list for the ypproc_maplist * procedure using dynamically allocated memory. Since the XDR * layer won't free this list for us, we have to deal with it * ourselves. We call yp_maplist_free() first to free any * previously allocated data we may have accumulated to insure * that we have only one linked list in memory at any given * time. */ yp_maplist_free(result.maps); if ((result.maps = yp_maplist_create(*argp)) == NULL) { yp_error("yp_maplist_create failed"); result.stat = YP_YPERR; return(&result); } else result.stat = YP_TRUE; return (&result); } /* * NIS v1 support. The nullproc, domain and domain_nonack * functions from v1 are identical to those in v2, so all * we have to do is hand off to them. * * The other functions are mostly just wrappers around their v2 * counterparts. For example, for the v1 'match' procedure, we * crack open the argument structure, make a request to the v2 * 'match' function, repackage the data into a v1 response and * then send it on its way. * * Note that we don't support the pull, push and get procedures. * There's little documentation available to show what they * do, and I suspect they're meant largely for map transfers * between master and slave servers. */ void * ypoldproc_null_1_svc(void *argp, struct svc_req *rqstp) { return(ypproc_null_2_svc(argp, rqstp)); } bool_t * ypoldproc_domain_1_svc(domainname *argp, struct svc_req *rqstp) { return(ypproc_domain_2_svc(argp, rqstp)); } bool_t * ypoldproc_domain_nonack_1_svc(domainname *argp, struct svc_req *rqstp) { return (ypproc_domain_nonack_2_svc(argp, rqstp)); } /* * the 'match' procedure sends a response of type YPRESP_VAL */ ypresponse * ypoldproc_match_1_svc(yprequest *argp, struct svc_req *rqstp) { static ypresponse result; ypresp_val *v2_result; result.yp_resptype = YPRESP_VAL; result.ypresponse_u.yp_resp_valtype.val.valdat_val = ""; result.ypresponse_u.yp_resp_valtype.val.valdat_len = 0; if (argp->yp_reqtype != YPREQ_KEY) { result.ypresponse_u.yp_resp_valtype.stat = YP_BADARGS; return(&result); } v2_result = ypproc_match_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp); if (v2_result == NULL) return(NULL); bcopy(v2_result, &result.ypresponse_u.yp_resp_valtype, sizeof(ypresp_val)); return (&result); } /* * the 'first' procedure sends a response of type YPRESP_KEY_VAL */ ypresponse * ypoldproc_first_1_svc(yprequest *argp, struct svc_req *rqstp) { static ypresponse result; ypresp_key_val *v2_result; result.yp_resptype = YPRESP_KEY_VAL; result.ypresponse_u.yp_resp_key_valtype.val.valdat_val = result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = ""; result.ypresponse_u.yp_resp_key_valtype.val.valdat_len = result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0; if (argp->yp_reqtype != YPREQ_NOKEY) { result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS; return(&result); } v2_result = ypproc_first_2_svc(&argp->yprequest_u.yp_req_nokeytype, rqstp); if (v2_result == NULL) return(NULL); bcopy(v2_result, &result.ypresponse_u.yp_resp_key_valtype, sizeof(ypresp_key_val)); return (&result); } /* * the 'next' procedure sends a response of type YPRESP_KEY_VAL */ ypresponse * ypoldproc_next_1_svc(yprequest *argp, struct svc_req *rqstp) { static ypresponse result; ypresp_key_val *v2_result; result.yp_resptype = YPRESP_KEY_VAL; result.ypresponse_u.yp_resp_key_valtype.val.valdat_val = result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = ""; result.ypresponse_u.yp_resp_key_valtype.val.valdat_len = result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0; if (argp->yp_reqtype != YPREQ_KEY) { result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS; return(&result); } v2_result = ypproc_next_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp); if (v2_result == NULL) return(NULL); bcopy(v2_result, &result.ypresponse_u.yp_resp_key_valtype, sizeof(ypresp_key_val)); return (&result); } /* * the 'poll' procedure sends a response of type YPRESP_MAP_PARMS */ ypresponse * ypoldproc_poll_1_svc(yprequest *argp, struct svc_req *rqstp) { static ypresponse result; ypresp_master *v2_result1; ypresp_order *v2_result2; result.yp_resptype = YPRESP_MAP_PARMS; result.ypresponse_u.yp_resp_map_parmstype.domain = argp->yprequest_u.yp_req_nokeytype.domain; result.ypresponse_u.yp_resp_map_parmstype.map = argp->yprequest_u.yp_req_nokeytype.map; /* * Hmm... there is no 'status' value in the * yp_resp_map_parmstype structure, so I have to * guess at what to do to indicate a failure. * I hope this is right. */ result.ypresponse_u.yp_resp_map_parmstype.ordernum = 0; result.ypresponse_u.yp_resp_map_parmstype.peer = ""; if (argp->yp_reqtype != YPREQ_MAP_PARMS) { return(&result); } v2_result1 = ypproc_master_2_svc(&argp->yprequest_u.yp_req_nokeytype, rqstp); if (v2_result1 == NULL) return(NULL); if (v2_result1->stat != YP_TRUE) { return(&result); } v2_result2 = ypproc_order_2_svc(&argp->yprequest_u.yp_req_nokeytype, rqstp); if (v2_result2 == NULL) return(NULL); if (v2_result2->stat != YP_TRUE) { return(&result); } result.ypresponse_u.yp_resp_map_parmstype.peer = v2_result1->peer; result.ypresponse_u.yp_resp_map_parmstype.ordernum = v2_result2->ordernum; return (&result); } ypresponse * ypoldproc_push_1_svc(yprequest *argp, struct svc_req *rqstp) { static ypresponse result; /* * Not implemented. */ return (&result); } ypresponse * ypoldproc_pull_1_svc(yprequest *argp, struct svc_req *rqstp) { static ypresponse result; /* * Not implemented. */ return (&result); } ypresponse * ypoldproc_get_1_svc(yprequest *argp, struct svc_req *rqstp) { static ypresponse result; /* * Not implemented. */ return (&result); }