diff options
author | wpaul <wpaul@FreeBSD.org> | 1996-12-22 22:30:58 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1996-12-22 22:30:58 +0000 |
commit | c1aa3ecaa1541240fd02352141c42ab719ee6e88 (patch) | |
tree | 8fe710785aad94fb6f6a3c1a55e03c034c4b1748 /usr.sbin/ypserv | |
parent | d389236bb21608788d7843fe717422b5eeb5af45 (diff) | |
download | FreeBSD-src-c1aa3ecaa1541240fd02352141c42ab719ee6e88.zip FreeBSD-src-c1aa3ecaa1541240fd02352141c42ab719ee6e88.tar.gz |
Big round o changes:
- yp_dblookup.c: Create non-DB specific database access functions.
Using these allows access to the underlying database functions without
needing explicit knowledge of Berkeley DB. (These are used only
when DB_CACHE is #defined. Other programs that use the non-caching
functions (yp_mkdb, ypxfr, yppush, rpc.yppasswdd) shouldn't notice
the difference.)
- yp_dnslookup: Implement async DNS lookups. We send our own DNS
requests using UDP and put the request in a queue. When the response
arrives, we use the ID in the header to find the corresponsing queue
entry and then send the response to the client. We can go about our
business and handle other YP requests in the meantime. This way, we
can deal with time consuming DNS requests without blocking and without
forking.
- yp_server.c: Convert to using new non-DB-specific database access
functions. This simplifies the code a bit and removes the need for
this module to know anything about Berkeley DB. Also convert the
ypproc_match_2_svc() function to use the async DNS lookup routines.
- yp_main.c: tweak yp_svc_run() to add the resolver socket to the
set of descriptors monitored in the select() loop. Also add a
timeout to select(); we may get stale DNS requests stuck in the
queue which we want to invalidate after a while. If the timeout
hits, we decrement the ttl on all pending DNS requests and nuke
those requests that aren't handled before ttl hits zero.
- yp_extern.h: Add prototypes for new stuff.
- yp_svc_udp.c (new file): The async resolver code needs to be able
to rummage around inside the RPC UDP transport handle in order to
work correcty. There's basically one transport handle, and each time
a request comes in, the transaction ID in the handle is changed.
This means that if we queue a DNS request, then we handle some other
unrelated requests, we will be unable to send the DNS response because
the transaction ID and remote address of the client that made the DNS
request will have been lost. What we need to do is save the client
address and transaction ID in the queue entry for the DNS request,
then put the transaction ID and address back in the transport handle
when we're ready to reply. (And then we have to undo the change so
as not to confuse any other part of the server.) The trouble is that
the transaction ID is hidden in an opaque part of the transport handle,
and only the code in the svc_udp module in the RPC library knows how
to handle it. This file contains a couple of functions that let us
read and set the transaction ID in spite of this. This is really a
dirty trick and I should be taken out and shot for even thinking about
it, but there's no other way to get this stuff to work.
- Makefile: add yp_svc_udp.c to SRCS.
Diffstat (limited to 'usr.sbin/ypserv')
-rw-r--r-- | usr.sbin/ypserv/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_dblookup.c | 109 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_dnslookup.c | 367 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_extern.h | 32 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_main.c | 20 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_server.c | 162 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_svc_udp.c | 90 |
7 files changed, 625 insertions, 159 deletions
diff --git a/usr.sbin/ypserv/Makefile b/usr.sbin/ypserv/Makefile index 2911c37..8889e1a 100644 --- a/usr.sbin/ypserv/Makefile +++ b/usr.sbin/ypserv/Makefile @@ -1,8 +1,8 @@ -# $Id: Makefile,v 1.6 1996/09/15 00:39:19 wpaul Exp $ +# $Id: Makefile,v 1.8 1996/12/03 02:37:35 wpaul Exp $ PROG= ypserv SRCS= yp_svc.c yp_server.c yp_dblookup.c yp_dnslookup.c \ - ypxfr_clnt.c yp_main.c yp_error.c yp_access.c + ypxfr_clnt.c yp_main.c yp_error.c yp_access.c yp_svc_udp.c MAN8= ypserv.8 diff --git a/usr.sbin/ypserv/yp_dblookup.c b/usr.sbin/ypserv/yp_dblookup.c index a55acb8..2edb673 100644 --- a/usr.sbin/ypserv/yp_dblookup.c +++ b/usr.sbin/ypserv/yp_dblookup.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: yp_dblookup.c,v 1.4 1996/07/07 19:04:33 wpaul Exp wpaul $ + * $Id: yp_dblookup.c,v 1.2 1996/12/22 15:54:15 wpaul Exp $ * */ #include <stdio.h> @@ -47,11 +47,11 @@ #include "yp_extern.h" #ifndef lint -static const char rcsid[] = "$Id: yp_dblookup.c,v 1.4 1996/07/07 19:04:33 wpaul Exp wpaul $"; +static const char rcsid[] = "$Id: yp_dblookup.c,v 1.2 1996/12/22 15:54:15 wpaul Exp $"; #endif int ypdb_debug = 0; -int yp_errno = YP_TRUE; +enum ypstat yp_errno = YP_TRUE; #define PERM_SECURE (S_IRUSR|S_IWUSR) HASHINFO openinfo = { @@ -459,22 +459,29 @@ again: * the supplied key value in the database. */ +#ifdef DB_CACHE +int yp_get_record(dbp,key,data,allow) + DB *dbp; +#else int yp_get_record(domain,map,key,data,allow) const char *domain; const char *map; +#endif const DBT *key; DBT *data; int allow; { +#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] in map [%s]", - key->size, key->data, map); + yp_error("Looking up key [%.*s]", + key->size, key->data); /* * Avoid passing back magic "YP_*" entries unless @@ -484,13 +491,11 @@ int yp_get_record(domain,map,key,data,allow) if (!allow && !strncmp(key->data, "YP_", 3)) return(YP_NOKEY); -#ifdef DB_CACHE - if ((dbp = yp_open_db_cache(domain, map, NULL, 0)) == NULL) { -#else +#ifndef DB_CACHE if ((dbp = yp_open_db(domain, map)) == NULL) { -#endif return(yp_errno); } +#endif if ((rval = (dbp->get)(dbp, key, data, 0)) != 0) { #ifdef DB_CACHE @@ -591,7 +596,7 @@ int yp_next_record(dbp,key,data,all,allow) static unsigned char datbuf[YPMAXRECORD]; #endif - if (key == NULL || key->data == NULL) { + if (key == NULL || !key->size || key->data == NULL) { rval = yp_first_record(dbp,key,data,allow); if (rval == YP_NOKEY) return(YP_NOMORE); @@ -657,3 +662,87 @@ int yp_next_record(dbp,key,data,all,allow) 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(map, domain, key, allow) + char *map; + char *domain; + keydat *key; + int allow; +{ + 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(key, val) + 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(key, val) + 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(key, val) + 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 9f77980..7b0acbb 100644 --- a/usr.sbin/ypserv/yp_dnslookup.c +++ b/usr.sbin/ypserv/yp_dnslookup.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: yp_dnslookup.c,v 1.2 1996/05/31 16:01:49 wpaul Exp $ + * $Id: yp_dnslookup.c,v 1.5 1996/12/22 15:45:33 wpaul Exp $ */ /* @@ -42,19 +42,30 @@ * it disappeared up its own belly button. */ -#include <sys/types.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include <sys/param.h> -#include <netdb.h> -#include <netinet/in.h> #include <sys/socket.h> +#include <sys/time.h> +#include <sys/fcntl.h> +#include <sys/queue.h> +#include <netinet/in.h> #include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <stdio.h> +#include <ctype.h> +#include <resolv.h> +#include <netdb.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <err.h> + +#include <rpcsvc/yp.h> #include "yp_extern.h" #ifndef lint -static const char rcsid[] = "$Id: yp_dnslookup.c,v 1.2 1996/05/31 16:01:49 wpaul Exp $"; +static const char rcsid[] = "$Id: yp_dnslookup.c,v 1.5 1996/12/22 15:45:33 wpaul Exp $"; #endif static char *parse(hp) @@ -64,6 +75,9 @@ static char *parse(hp) int len,i; struct in_addr addr; + if (hp == NULL) + return(NULL); + len = 16 + strlen(hp->h_name); for (i = 0; hp->h_aliases[i]; i++) len += strlen(hp->h_aliases[i]) + 1; @@ -81,32 +95,329 @@ static char *parse(hp) return ((char *)&result); } -char *yp_dnsname(address) - char *address; +#define MAXPACKET 1024 +#define DEF_TTL 50 + +extern struct hostent *__dns_getanswer __P((char *, int, char *, int)); + +static CIRCLEQ_HEAD(dns_qhead, circleq_dnsentry) qhead; + +struct circleq_dnsentry { + SVCXPRT *xprt; + unsigned long xid; + struct sockaddr_in client_addr; + unsigned long id; + unsigned long ttl; + unsigned long sent; + unsigned long type; + char **domain; + char *name; + struct in_addr addr; + CIRCLEQ_ENTRY(circleq_dnsentry) links; +}; + +static int pending = 0; + +int yp_init_resolver() { - struct hostent *hp; + CIRCLEQ_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); +} + +int yp_dnsq_pending() +{ + return(pending); +} + +static struct circleq_dnsentry *yp_malloc_dnsent() +{ + register struct circleq_dnsentry *q; - if (strchr(address, '@')) - return (NULL); - if ((hp = (struct hostent *)_gethostbydnsname(address, AF_INET)) == NULL) - return (NULL); + q = (struct circleq_dnsentry *)malloc(sizeof(struct circleq_dnsentry)); - return(parse(hp)); + if (q == NULL) { + yp_error("failed to malloc() circleq dns entry: %s", + strerror(errno)); + return(NULL); + } + + return(q); } -char *yp_dnsaddr(address) - const char *address; +/* + * Transmit a query. + */ +static unsigned long yp_send_dns_query(name, type) + char *name; + int type; { - struct hostent *hp; - struct in_addr addr; + 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"); + 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(id) + unsigned long id; +{ + register struct circleq_dnsentry *q; + + for (q = qhead.cqh_first; q != (void *)&qhead; q = q->links.cqe_next) { + if (q->id == id) + return(q); + } + return (NULL); +} + +static void yp_send_dns_reply(q, buf) + struct circleq_dnsentry *q; + char *buf; +{ + ypresp_val result; + unsigned long xid; + struct sockaddr_in client_addr; + + bzero((char *)&result, sizeof(result)); + + if (buf == NULL) + result.stat = YP_NOKEY; + else { + result.val.valdat_len = strlen(buf); + result.val.valdat_val = buf; + result.stat = YP_TRUE; + } + + 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. + */ + 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, xdr_ypresp_val, (char *)&result)) + yp_error("svc_sendreply failed"); + svcudp_set_xid(q->xprt, xid); + q->xprt->xp_raddr = client_addr; + return; +} + +void yp_prune_dnsq() +{ + register struct circleq_dnsentry *q; + + for (q = qhead.cqh_first; q != (void *)&qhead; q = q->links.cqe_next) { + q->ttl--; + if (!q->ttl) { + CIRCLEQ_REMOVE(&qhead, q, links); + free(q->name); + free(q); + pending--; + } + } + + if (pending < 0) + pending = 0; + + return; +} + +void yp_run_dnsq() +{ + register struct circleq_dnsentry *q; + char buf[sizeof(HEADER) + MAXPACKET]; + struct sockaddr_in sin; + int rval; + int len; + 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; + } + + hptr = (HEADER *)&buf; + if ((q = yp_find_dnsqent(ntohs(hptr->id))) == NULL) { + /* bogus id -- 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) { + char retrybuf[MAXHOSTNAMELEN]; + + if (q->domain && *q->domain) { + snprintf(retrybuf, sizeof(retrybuf), "%s.%s", + q->name, *q->domain); + if (debug) + yp_error("Retrying with: %s", retrybuf); + q->id = yp_send_dns_query(retrybuf, q->type); + q->ttl = DEF_TTL; + q->domain++; + return; + } + } + + if (q->type == T_PTR) { + hent->h_addr = (char *)&q->addr.s_addr; + hent->h_length = sizeof(struct in_addr); + } + yp_send_dns_reply(q, parse(hent)); + + pending--; + CIRCLEQ_REMOVE(&qhead, q, links); + free(q->name); + free(q); + + yp_prune_dnsq(); + + return; +} + +ypstat yp_async_lookup_name(xprt, name) + SVCXPRT *xprt; + char *name; +{ + register struct circleq_dnsentry *q; + + if ((q = yp_malloc_dnsent()) == NULL) + return(YP_YPERR); + + q->type = T_A; + q->ttl = DEF_TTL; + q->sent = 1; + q->xprt = xprt; + q->xid = svcudp_get_xid(xprt); + q->client_addr = xprt->xp_raddr; + if (!strchr(name, '.')) + q->domain = _res.dnsrch; + else + q->domain = NULL; + 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); + CIRCLEQ_INSERT_HEAD(&qhead, q, links); + pending++; + + if (debug) + yp_error("Queueing async DNS name lookup (%d)", q->id); + + return(YP_TRUE); +} + +ypstat yp_async_lookup_addr(xprt, addr) + SVCXPRT *xprt; + char *addr; +{ + register struct circleq_dnsentry *q; + char buf[MAXHOSTNAMELEN]; + int a, b, c, d; + + if ((q = yp_malloc_dnsent()) == NULL) + return(YP_YPERR); + + if (sscanf(addr, "%d.%d.%d.%d", &a, &b, &c, &d) != 4) + return(YP_NOKEY); + + snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", + d, c, b, a, addr); + + if (debug) + yp_error("DNS address is: %s", buf); + + q->type = T_PTR; + q->ttl = DEF_TTL; + q->sent = 1; + q->xprt = xprt; + q->domain = NULL; + q->xid = svcudp_get_xid(xprt); + q->client_addr = 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); + } + + inet_aton(addr, &q->addr); + q->name = strdup(buf); + CIRCLEQ_INSERT_HEAD(&qhead, q, links); + pending++; - if (strchr(address, '@')) - return (NULL); - if (!inet_aton(address, &addr)) - return (NULL); - if ((hp = (struct hostent *)_gethostbydnsaddr((const char *)&addr, - sizeof(unsigned long), AF_INET)) == NULL) - return (NULL); + if (debug) + yp_error("Queueing async DNS address lookup (%d)", q->id); - return(parse(hp)); + return(YP_TRUE); } diff --git a/usr.sbin/ypserv/yp_extern.h b/usr.sbin/ypserv/yp_extern.h index bdb99f9..fc3e6dd 100644 --- a/usr.sbin/ypserv/yp_extern.h +++ b/usr.sbin/ypserv/yp_extern.h @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: yp_extern.h,v 1.5 1996/10/24 18:58:24 wpaul Exp $ + * $Id: yp_extern.h,v 1.3 1996/12/22 15:53:55 wpaul Exp $ */ #include <stdio.h> #include <string.h> @@ -39,7 +39,7 @@ #include <limits.h> #include <db.h> #include <rpc/rpc.h> - +#include <rpcsvc/yp.h> #ifndef _PATH_YP #define _PATH_YP "/var/yp/" @@ -64,11 +64,16 @@ extern int debug; extern int ypdb_debug; extern int do_dns; extern int children; +extern int resfd; extern char *progname; extern char *yp_dir; -extern int yp_errno; +extern enum ypstat yp_errno; extern void yp_error __P((const char *, ...)); +#ifdef DB_CACHE +extern int yp_get_record __P(( DB *, const DBT *, DBT *, int)); +#else extern int yp_get_record __P(( const char *, const char *, const DBT *, DBT *, int)); +#endif extern int yp_first_record __P((const DB *, DBT *, DBT *, int)); extern int yp_next_record __P((const DB *, DBT *, DBT *, int, int)); extern char *yp_dnsname __P(( char * )); @@ -85,3 +90,24 @@ extern void yp_flush_all __P(( void )); extern void yp_init_dbs __P(( void )); extern int yp_testflag __P(( char *, char *, int )); extern void load_securenets __P(( void )); + +#ifdef DB_CACHE +extern ypstat yp_select_map __P(( char *, char *, keydat *, int )); +extern ypstat yp_getbykey __P(( keydat *, valdat * )); +extern ypstat yp_firstbykey __P(( keydat *, valdat * )); +extern ypstat yp_nextbykey __P(( keydat *, valdat * )); +#endif + +extern unsigned long svcudp_set_xid __P(( SVCXPRT *, unsigned long )); +extern unsigned long svcudp_get_xid __P(( SVCXPRT * )); + +#ifndef RESOLVER_TIMEOUT +#define RESOLVER_TIMEOUT 3600 +#endif + +extern int yp_init_resolver __P(( void )); +extern int yp_dnsq_pending __P(( void )); +extern void yp_run_dnsq __P(( void )); +extern void yp_prune_dnsq __P(( void )); +extern ypstat yp_async_lookup_name __P(( SVCXPRT *, char * )); +extern ypstat yp_async_lookup_addr __P(( SVCXPRT *, char * )); diff --git a/usr.sbin/ypserv/yp_main.c b/usr.sbin/ypserv/yp_main.c index 5c22d89..db40ac6 100644 --- a/usr.sbin/ypserv/yp_main.c +++ b/usr.sbin/ypserv/yp_main.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: yp_main.c,v 1.6 1996/05/31 16:01:50 wpaul Exp $ + * $Id: yp_main.c,v 1.4 1996/12/22 15:54:03 wpaul Exp $ */ /* @@ -66,7 +66,7 @@ #define _RPCSVC_CLOSEDOWN 120 #ifndef lint -static const char rcsid[] = "$Id: yp_main.c,v 1.6 1996/05/31 16:01:50 wpaul Exp $"; +static const char rcsid[] = "$Id: yp_main.c,v 1.4 1996/12/22 15:54:03 wpaul Exp $"; #endif /* not lint */ int _rpcpmstart; /* Started by a port monitor ? */ static int _rpcfdtype; @@ -85,6 +85,7 @@ char *progname = "ypserv"; char *yp_dir = _PATH_YP; int debug = 0; int do_dns = 0; +int resfd; static void _msgout(char* msg) @@ -109,6 +110,7 @@ yp_svc_run() extern int forked; int pid; int fd_setsize = _rpc_dtablesize(); + struct timeval timeout = { RESOLVER_TIMEOUT, 0 }; /* Establish the identity of the parent ypserv process. */ pid = getpid(); @@ -119,8 +121,12 @@ yp_svc_run() #else readfds = svc_fds; #endif /* def FD_SETSIZE */ + + if (yp_dnsq_pending()) + FD_SET(resfd, &readfds); + switch (select(fd_setsize, &readfds, NULL, NULL, - (struct timeval *)0)) { + &timeout)) { case -1: if (errno == EINTR) { continue; @@ -128,8 +134,13 @@ yp_svc_run() perror("svc_run: - select failed"); return; case 0: - continue; + yp_prune_dnsq(); + break; default: + if (FD_ISSET(resfd, &readfds)) { + yp_run_dnsq(); + FD_CLR(resfd, &readfds); + } svc_getreqset(&readfds); if (forked && pid != getpid()) exit(0); @@ -230,6 +241,7 @@ main(argc, argv) } load_securenets(); + yp_init_resolver(); #ifdef DB_CACHE yp_init_dbs(); #endif diff --git a/usr.sbin/ypserv/yp_server.c b/usr.sbin/ypserv/yp_server.c index 77cc6f7..32a8a2c 100644 --- a/usr.sbin/ypserv/yp_server.c +++ b/usr.sbin/ypserv/yp_server.c @@ -31,8 +31,8 @@ * */ -#include "yp_extern.h" #include "yp.h" +#include "yp_extern.h" #include <stdlib.h> #include <dirent.h> #include <sys/stat.h> @@ -45,12 +45,11 @@ #include <rpc/rpc.h> #ifndef lint -static const char rcsid[] = "$Id: yp_server.c,v 1.12 1996/10/24 18:58:26 wpaul Exp $"; +static const char rcsid[] = "$Id: yp_server.c,v 1.2 1996/12/22 06:57:55 wpaul Exp $"; #endif /* not lint */ int forked = 0; int children = 0; -static DB *spec_dbp = NULL; /* Special global DB handle for ypproc_all. */ static char *master_string = "YP_MASTER_NAME"; static char *order_string = "YP_LAST_MODIFIED"; static int master_sz = sizeof("YP_MASTER_NAME") - 1; @@ -124,7 +123,6 @@ ypresp_val * ypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp) { static ypresp_val result; - DBT key, data; result.val.valdat_val = ""; result.val.valdat_len = 0; @@ -143,15 +141,13 @@ ypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp) return (&result); } - key.size = argp->key.keydat_len; - key.data = argp->key.keydat_val; - - if ((result.stat = yp_get_record(argp->domain, argp->map, - &key, &data, 1)) == YP_TRUE) { - result.val.valdat_len = data.size; - result.val.valdat_val = data.data; + if (yp_select_map(argp->map, argp->domain, &argp->key, 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. */ @@ -163,50 +159,24 @@ ypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp) #else if (do_dns && result.stat != YP_TRUE && strstr(argp->map, "hosts")) { #endif - char *rval = NULL; - - /* DNS lookups can take time -- do them in a subprocess */ - - if (!debug && children < MAX_CHILDREN && fork()) { - children++; - forked = 0; - /* - * Returning NULL here prevents svc_sendreply() - * from being called by the parent. This is vital - * since having both the parent and the child process - * call it would confuse the client. - */ - return (NULL); - } else { - forked++; - } + + /* NUL terminate! NUL terminate!! NUL TERMINATE!!! */ + argp->key.keydat_val[argp->key.keydat_len] = '\0'; if (debug) yp_error("Doing DNS lookup of %.*s", argp->key.keydat_len, argp->key.keydat_val); - /* NUL terminate! NUL terminate!! NUL TERMINATE!!! */ - argp->key.keydat_val[argp->key.keydat_len] = '\0'; - if (!strcmp(argp->map, "hosts.byname")) - rval = yp_dnsname((char *)argp->key.keydat_val); + result.stat = yp_async_lookup_name(rqstp->rq_xprt, + (char *)argp->key.keydat_val); else if (!strcmp(argp->map, "hosts.byaddr")) - rval = yp_dnsaddr((const char *)argp->key.keydat_val); - + result.stat = yp_async_lookup_addr(rqstp->rq_xprt, + (char *)argp->key.keydat_val); - if (rval) { - if (debug) - yp_error("DNS lookup successful. Result: %s", - rval); - result.val.valdat_len = strlen(rval); - result.val.valdat_val = rval; - result.stat = YP_TRUE; - } else { - if (debug) - yp_error("DNS lookup failed."); - result.stat = YP_NOKEY; - } + if (result.stat == YP_TRUE) + return(NULL); } return (&result); @@ -216,8 +186,6 @@ ypresp_key_val * ypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_key_val result; - DBT key, data; - DB *dbp; result.val.valdat_val = result.key.keydat_val = ""; result.val.valdat_len = result.key.keydat_len = 0; @@ -236,27 +204,13 @@ ypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) return (&result); } -#ifdef DB_CACHE - if ((dbp = yp_open_db_cache(argp->domain, argp->map, NULL, 0)) == NULL) { -#else - if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) { -#endif + if (yp_select_map(argp->map, argp->domain, &result.key, 0) != YP_TRUE) { result.stat = yp_errno; return(&result); } - key.data = NULL; - key.size = 0; + result.stat = yp_firstbykey(&result.key, &result.val); - if ((result.stat = yp_first_record(dbp, &key, &data, 0)) == YP_TRUE) { - result.key.keydat_len = key.size; - result.key.keydat_val = key.data; - result.val.valdat_len = data.size; - result.val.valdat_val = data.data; - } -#ifndef DB_CACHE - (void)(dbp->close)(dbp); -#endif return (&result); } @@ -264,8 +218,6 @@ ypresp_key_val * ypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp) { static ypresp_key_val result; - DBT key, data; - DB *dbp; result.val.valdat_val = result.key.keydat_val = ""; result.val.valdat_len = result.key.keydat_len = 0; @@ -284,29 +236,16 @@ ypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp) return (&result); } -#ifdef DB_CACHE - if ((dbp = yp_open_db_cache(argp->domain, argp->map, - argp->key.keydat_val, - argp->key.keydat_len)) == NULL) { -#else - if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) { -#endif + if (yp_select_map(argp->map, argp->domain, &argp->key, 0) != YP_TRUE) { result.stat = yp_errno; return(&result); } - key.size = argp->key.keydat_len; - key.data = argp->key.keydat_val; + result.key.keydat_len = argp->key.keydat_len; + result.key.keydat_val = argp->key.keydat_val; + + result.stat = yp_nextbykey(&result.key, &result.val); - if ((result.stat = yp_next_record(dbp, &key, &data,0,0)) == YP_TRUE) { - result.key.keydat_len = key.size; - result.key.keydat_val = key.data; - result.val.valdat_len = data.size; - result.val.valdat_val = data.data; - } -#ifndef DB_CACHE - (void)(dbp->close)(dbp); -#endif return (&result); } @@ -480,16 +419,11 @@ ypproc_clear_2_svc(void *argp, struct svc_req *rqstp) static bool_t xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp) { - DBT key = { NULL, 0 } , data = { NULL, 0 }; - while (1) { /* Get a record. */ if ((objp->ypresp_all_u.val.stat = - yp_next_record(spec_dbp,&key,&data,1,0)) == YP_TRUE) { - objp->ypresp_all_u.val.val.valdat_len = data.size; - objp->ypresp_all_u.val.val.valdat_val = data.data; - objp->ypresp_all_u.val.key.keydat_len = key.size; - objp->ypresp_all_u.val.key.keydat_val = key.data; + yp_nextbykey(&objp->ypresp_all_u.val.key, + &objp->ypresp_all_u.val.val)) == YP_TRUE) { objp->more = TRUE; } else { objp->more = FALSE; @@ -545,24 +479,15 @@ ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) forked++; } -#ifndef DB_CACHE - if ((spec_dbp = yp_open_db(argp->domain, argp->map)) == NULL) { - result.ypresp_all_u.val.stat = yp_errno; - return(&result); - } -#else - if ((spec_dbp = yp_open_db_cache(argp->domain, argp->map, NULL, 0)) == NULL) { + 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); } -#endif /* Kick off the actual data transfer. */ svc_sendreply(rqstp->rq_xprt, xdr_my_ypresp_all, (char *)&result); -#ifndef DB_CACHE - (void)(spec_dbp->close)(spec_dbp); -#endif /* * Returning NULL prevents the dispatcher from calling * svc_sendreply() since we already did it. @@ -575,7 +500,8 @@ ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_master result; static char ypvalbuf[YPMAXRECORD]; - DBT key = { master_string, master_sz }, data; + keydat key = { master_sz, master_string }; + valdat val; result.peer = ""; @@ -593,6 +519,11 @@ ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) 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 @@ -601,10 +532,11 @@ ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) * allocated by the DB package. This is a bad thing now that we * cache DB handles rather than closing the database immediately. */ - if ((result.stat = yp_get_record(argp->domain, argp->map, - &key, &data, 1)) == YP_TRUE) { - bcopy((char *)data.data, (char *)&ypvalbuf, data.size); - ypvalbuf[data.size] = '\0'; + result.stat = yp_getbykey(&key, &val); + if (result.stat == YP_TRUE) { + bcopy((char *)val.valdat_val, (char *)&ypvalbuf, + val.valdat_len); + ypvalbuf[val.valdat_len] = '\0'; result.peer = (char *)&ypvalbuf; } else result.peer = ""; @@ -616,7 +548,8 @@ ypresp_order * ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_order result; - DBT key = { order_string, order_sz }, data; + keydat key = { order_sz, order_string }; + valdat val; result.ordernum = 0; @@ -641,13 +574,18 @@ ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) * updated. */ - if ((result.stat = yp_get_record(argp->domain, argp->map, - &key, &data, 1)) == YP_TRUE) - result.ordernum = atoi((char *)data.data); + 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((char *)val.valdat_val); else result.ordernum = 0; - return (&result); } diff --git a/usr.sbin/ypserv/yp_svc_udp.c b/usr.sbin/ypserv/yp_svc_udp.c new file mode 100644 index 0000000..0652a2e --- /dev/null +++ b/usr.sbin/ypserv/yp_svc_udp.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1996 + * Bill Paul <wpaul@ctr.columbia.edu>. 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. + * + * $Id: yp_svc_udp.c,v 1.1 1996/12/22 15:44:09 wpaul Exp $ + */ + +#include <rpc/rpc.h> +#include "yp_extern.h" + +#ifndef lint +static const char rcsid[] = "$Id: yp_svc_udp.c,v 1.1 1996/12/22 15:44:09 wpaul Exp $"; +#endif + +/* + * XXX Must not diverge from what's in src/lib/libc/rpc/svc_udp.c + */ + +/* + * kept in xprt->xp_p2 + */ +struct svcudp_data { + u_int su_iosz; /* byte size of send.recv buffer */ + u_long su_xid; /* transaction id */ + XDR su_xdrs; /* XDR handle */ + char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ + char * su_cache; /* cached data, NULL if no cache */ +}; +#define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2)) + +/* + * We need to be able to manually set the transaction ID in the + * UDP transport handle, but the standard library offers us no way + * to do that. Hence we need this garbage. + */ + +unsigned long +svcudp_get_xid(xprt) + SVCXPRT *xprt; +{ + struct svcudp_data *su; + + if (xprt == NULL) + return(0); + su = su_data(xprt); + return(su->su_xid); +} + +unsigned long +svcudp_set_xid(xprt, xid) + SVCXPRT *xprt; + unsigned long xid; +{ + struct svcudp_data *su; + unsigned long old_xid; + + if (xprt == NULL) + return(0); + su = su_data(xprt); + old_xid = su->su_xid; + su->su_xid = xid; + return(old_xid); +} |