Home | History | Annotate | Line # | Download | only in yp
yplib.c revision 1.4
      1 /*
      2  * Copyright (c) 1992/3 Theo de Raadt <deraadt (at) fsa.ca>
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. The name of the author may not be used to endorse or promote
     14  *    products derived from this software without specific prior written
     15  *    permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 
     30 #ifndef LINT
     31 static char rcsid[] = "$Id: yplib.c,v 1.4 1993/06/12 19:46:33 deraadt Exp $";
     32 #endif
     33 
     34 #include <sys/param.h>
     35 #include <sys/types.h>
     36 #include <sys/socket.h>
     37 #include <sys/file.h>
     38 #include <errno.h>
     39 #include <stdio.h>
     40 #include <string.h>
     41 #include <rpc/rpc.h>
     42 #include <rpc/xdr.h>
     43 #include <rpcsvc/yp_prot.h>
     44 #include <rpcsvc/ypclnt.h>
     45 
     46 #ifndef BINDINGDIR
     47 #define BINDINGDIR "/var/yp/binding"
     48 #endif
     49 #define YPMATCHCACHE
     50 
     51 extern bool_t xdr_domainname(), xdr_ypbind_resp();
     52 extern bool_t xdr_ypreq_key(), xdr_ypresp_val();
     53 extern bool_t xdr_ypreq_nokey(), xdr_ypresp_key_val();
     54 extern bool_t xdr_ypresp_all(), xdr_ypresp_all_seq();
     55 extern bool_t xdr_ypresp_master();
     56 
     57 int (*ypresp_allfn)();
     58 void *ypresp_data;
     59 
     60 struct dom_binding *_ypbindlist;
     61 static char _yp_domain[MAXHOSTNAMELEN];
     62 int _yplib_timeout = 10;
     63 
     64 #ifdef YPMATCHCACHE
     65 int _yplib_cache = 5;
     66 
     67 static struct ypmatch_ent {
     68 	struct ypmatch_ent *next;
     69 	char *map, *key, *val;
     70 	int keylen, vallen;
     71 	time_t expire_t;
     72 } *ypmc;
     73 
     74 static void
     75 ypmatch_add(map, key, keylen, val, vallen)
     76 char *map, *key, *val;
     77 {
     78 	struct ypmatch_ent *ep;
     79 	time_t t;
     80 
     81 	time(&t);
     82 
     83 	for(ep=ypmc; ep; ep=ep->next)
     84 		if(ep->expire_t < t)
     85 			break;
     86 	if(ep==NULL) {
     87 		ep = (struct ypmatch_ent *)malloc(sizeof *ep);
     88 		bzero((char *)ep, sizeof *ep);
     89 		if(ypmc)
     90 			ep->next = ypmc;
     91 		ypmc = ep;
     92 	}
     93 
     94 	if(ep->key)
     95 		free(ep->key);
     96 	if(ep->val)
     97 		free(ep->val);
     98 
     99 	ep->key = NULL;
    100 	ep->val = NULL;
    101 
    102 	ep->key = (char *)malloc(keylen);
    103 	if(ep->key==NULL)
    104 		return;
    105 
    106 	ep->val = (char *)malloc(vallen);
    107 	if(ep->key==NULL) {
    108 		free(ep->key);
    109 		ep->key = NULL;
    110 		return;
    111 	}
    112 	ep->keylen = keylen;
    113 	ep->vallen = vallen;
    114 
    115 	bcopy(key, ep->key, ep->keylen);
    116 	bcopy(val, ep->val, ep->vallen);
    117 
    118 	if(ep->map) {
    119 		if( strcmp(ep->map, map) ) {
    120 			free(ep->map);
    121 			ep->map = strdup(map);
    122 		}
    123 	} else {
    124 		ep->map = strdup(map);
    125 	}
    126 
    127 	ep->expire_t = t + _yplib_cache;
    128 }
    129 
    130 static bool_t
    131 ypmatch_find(map, key, keylen, val, vallen)
    132 char *map, *key;
    133 int keylen;
    134 char **val;
    135 int *vallen;
    136 {
    137 	struct ypmatch_ent *ep;
    138 	time_t t;
    139 
    140 	if(ypmc==NULL)
    141 		return 0;
    142 
    143 	time(&t);
    144 
    145 	for(ep=ypmc; ep; ep=ep->next) {
    146 		if(ep->keylen != keylen)
    147 			continue;
    148 		if(strcmp(ep->map, map))
    149 			continue;
    150 		if(bcmp(ep->key, key, keylen))
    151 			continue;
    152 		if(t > ep->expire_t)
    153 			continue;
    154 
    155 		*val = ep->val;
    156 		*vallen = ep->vallen;
    157 		return 1;
    158 	}
    159 	return 0;
    160 }
    161 #endif
    162 
    163 int
    164 _yp_dobind(dom, ypdb)
    165 char *dom;
    166 struct dom_binding **ypdb;
    167 {
    168 	static int pid = -1;
    169 	char path[MAXPATHLEN];
    170 	struct dom_binding *ysd, *ysd2;
    171 	struct ypbind_resp ypbr;
    172 	struct timeval tv;
    173 	struct sockaddr_in clnt_sin;
    174 	int clnt_sock, fd, gpid;
    175 	CLIENT *client;
    176 	int new=0, r;
    177 
    178 	gpid = getpid();
    179 	if( !(pid==-1 || pid==gpid) ) {
    180 		ysd = _ypbindlist;
    181 		while(ysd) {
    182 			if(ysd->dom_client)
    183 				clnt_destroy(ysd->dom_client);
    184 			ysd2 = ysd->dom_pnext;
    185 			free(ysd);
    186 			ysd = ysd2;
    187 		}
    188 		_ypbindlist = NULL;
    189 	}
    190 	pid = gpid;
    191 
    192 	if(ypdb!=NULL)
    193 		*ypdb = NULL;
    194 
    195 	if(dom==NULL || strlen(dom)==0)
    196 		return YPERR_BADARGS;
    197 
    198 	for(ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
    199 		if( strcmp(dom, ysd->dom_domain) == 0)
    200 			break;
    201 	if(ysd==NULL) {
    202 		ysd = (struct dom_binding *)malloc(sizeof *ysd);
    203 		bzero((char *)ysd, sizeof *ysd);
    204 		ysd->dom_socket = -1;
    205 		ysd->dom_vers = 0;
    206 		new = 1;
    207 	}
    208 again:
    209 #ifdef BINDINGDIR
    210 	if(ysd->dom_vers==0) {
    211 		sprintf(path, "%s/%s.%d", BINDINGDIR, dom, 2);
    212 		if( (fd=open(path, O_RDONLY)) == -1) {
    213 			/* no binding file, YP is dead. */
    214 			if(new)
    215 				free(ysd);
    216 			return YPERR_YPBIND;
    217 		}
    218 		if( flock(fd, LOCK_EX|LOCK_NB) == -1 && errno==EWOULDBLOCK) {
    219 			r = read(fd, &ysd->dom_server_addr, sizeof ysd->dom_server_addr);
    220 			if(r != sizeof ysd->dom_server_addr) {
    221 				close(fd);
    222 				ysd->dom_vers = -1;
    223 				goto again;
    224 			}
    225 			ysd->dom_server_port = ysd->dom_server_addr.sin_port;
    226 			close(fd);
    227 			goto gotit;
    228 		} else {
    229 			/* no lock on binding file, YP is dead. */
    230 			close(fd);
    231 			if(new)
    232 				free(ysd);
    233 			return YPERR_YPBIND;
    234 		}
    235 	}
    236 #endif
    237 	if(ysd->dom_vers==-1 || ysd->dom_vers==0) {
    238 		bzero((char *)&clnt_sin, sizeof clnt_sin);
    239 		clnt_sin.sin_family = AF_INET;
    240 		clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    241 
    242 		clnt_sock = RPC_ANYSOCK;
    243 		client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock,
    244 			0, 0);
    245 		if(client==NULL) {
    246 			clnt_pcreateerror("clnttcp_create");
    247 			if(new)
    248 				free(ysd);
    249 			return YPERR_YPBIND;
    250 		}
    251 
    252 		tv.tv_sec = _yplib_timeout;
    253 		tv.tv_usec = 0;
    254 		r = clnt_call(client, YPBINDPROC_DOMAIN,
    255 			xdr_domainname, dom, xdr_ypbind_resp, &ypbr, tv);
    256 		if(r != RPC_SUCCESS) {
    257 			fprintf(stderr,
    258 			"YP: server for domain %s not responding, still trying\n", dom);
    259 			clnt_destroy(client);
    260 			ysd->dom_vers = -1;
    261 			goto again;
    262 		}
    263 		clnt_destroy(client);
    264 
    265 		bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
    266 		ysd->dom_server_addr.sin_family = AF_INET;
    267 		ysd->dom_server_addr.sin_port =
    268 			ypbr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port;
    269 		ysd->dom_server_addr.sin_addr.s_addr =
    270 			ypbr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr;
    271 		ysd->dom_server_port =
    272 			ypbr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port;
    273 gotit:
    274 		ysd->dom_vers = YPVERS;
    275 		strcpy(ysd->dom_domain, dom);
    276 	}
    277 
    278 	tv.tv_sec = _yplib_timeout/2;
    279 	tv.tv_usec = 0;
    280 	if(ysd->dom_client)
    281 		clnt_destroy(ysd->dom_client);
    282 	ysd->dom_socket = RPC_ANYSOCK;
    283 	ysd->dom_client = clntudp_create(&ysd->dom_server_addr,
    284 		YPPROG, YPVERS, tv, &ysd->dom_socket);
    285 	if(ysd->dom_client==NULL) {
    286 		clnt_pcreateerror("clntudp_create");
    287 		ysd->dom_vers = -1;
    288 		goto again;
    289 	}
    290 	if( fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
    291 		perror("fcntl: F_SETFD");
    292 
    293 	if(new) {
    294 		ysd->dom_pnext = _ypbindlist;
    295 		_ypbindlist = ysd;
    296 	}
    297 
    298 	if(ypdb!=NULL)
    299 		*ypdb = ysd;
    300 	return 0;
    301 }
    302 
    303 static void
    304 _yp_unbind(ypb)
    305 struct dom_binding *ypb;
    306 {
    307 	clnt_destroy(ypb->dom_client);
    308 	ypb->dom_client = NULL;
    309 	ypb->dom_socket = -1;
    310 }
    311 
    312 int
    313 yp_bind(dom)
    314 char *dom;
    315 {
    316 	return _yp_dobind(dom, NULL);
    317 }
    318 
    319 void
    320 yp_unbind(dom)
    321 char *dom;
    322 {
    323 	struct dom_binding *ypb, *ypbp;
    324 
    325 	ypbp = NULL;
    326 	for(ypb=_ypbindlist; ypb; ypb=ypb->dom_pnext) {
    327 		if( strcmp(dom, ypb->dom_domain) == 0) {
    328 			clnt_destroy(ypb->dom_client);
    329 			if(ypbp)
    330 				ypbp->dom_pnext = ypb->dom_pnext;
    331 			else
    332 				_ypbindlist = ypb->dom_pnext;
    333 			free(ypb);
    334 			return;
    335 		}
    336 		ypbp = ypb;
    337 	}
    338 	return;
    339 }
    340 
    341 int
    342 yp_match(indomain, inmap, inkey, inkeylen, outval, outvallen)
    343 char *indomain;
    344 char *inmap;
    345 char *inkey;
    346 int inkeylen;
    347 char **outval;
    348 int *outvallen;
    349 {
    350 	struct dom_binding *ysd;
    351 	struct ypresp_val yprv;
    352 	struct timeval tv;
    353 	struct ypreq_key yprk;
    354 	int r;
    355 
    356 	*outval = NULL;
    357 	*outvallen = 0;
    358 
    359 again:
    360 	if( _yp_dobind(indomain, &ysd) != 0)
    361 		return YPERR_DOMAIN;
    362 
    363 #ifdef YPMATCHCACHE
    364 	if( !strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
    365 	    inkeylen, &yprv.valdat.dptr, &yprv.valdat.dsize)) {
    366 		*outvallen = yprv.valdat.dsize;
    367 		*outval = (char *)malloc(*outvallen+1);
    368 		bcopy(yprv.valdat.dptr, *outval, *outvallen);
    369 		(*outval)[*outvallen] = '\0';
    370 		return 0;
    371 	}
    372 #endif
    373 
    374 	tv.tv_sec = _yplib_timeout;
    375 	tv.tv_usec = 0;
    376 
    377 	yprk.domain = indomain;
    378 	yprk.map = inmap;
    379 	yprk.keydat.dptr = inkey;
    380 	yprk.keydat.dsize = inkeylen;
    381 
    382 	bzero((char *)&yprv, sizeof yprv);
    383 
    384 	r = clnt_call(ysd->dom_client, YPPROC_MATCH,
    385 		xdr_ypreq_key, &yprk, xdr_ypresp_val, &yprv, tv);
    386 	if(r != RPC_SUCCESS) {
    387 		clnt_perror(ysd->dom_client, "yp_match: clnt_call");
    388 		ysd->dom_vers = -1;
    389 		goto again;
    390 	}
    391 	if( !(r=ypprot_err(yprv.status)) ) {
    392 		*outvallen = yprv.valdat.dsize;
    393 		*outval = (char *)malloc(*outvallen+1);
    394 		bcopy(yprv.valdat.dptr, *outval, *outvallen);
    395 		(*outval)[*outvallen] = '\0';
    396 #ifdef YPMATCHCACHE
    397 		if( strcmp(_yp_domain, indomain)==0 )
    398 			 ypmatch_add(inmap, inkey, inkeylen, *outval, *outvallen);
    399 #endif
    400 	}
    401 	xdr_free(xdr_ypresp_val, (char *)&yprv);
    402 	_yp_unbind(ysd);
    403 	return r;
    404 }
    405 
    406 int
    407 yp_get_default_domain(domp)
    408 char **domp;
    409 {
    410 	*domp = NULL;
    411 	if(_yp_domain[0] == '\0')
    412 		if( getdomainname(_yp_domain, sizeof _yp_domain))
    413 			return YPERR_NODOM;
    414 	*domp = _yp_domain;
    415 	return 0;
    416 }
    417 
    418 int
    419 yp_first(indomain, inmap, outkey, outkeylen, outval, outvallen)
    420 char *indomain;
    421 char *inmap;
    422 char **outkey;
    423 int *outkeylen;
    424 char **outval;
    425 int *outvallen;
    426 {
    427 	struct ypresp_key_val yprkv;
    428 	struct ypreq_nokey yprnk;
    429 	struct dom_binding *ysd;
    430 	struct timeval tv;
    431 	int r;
    432 
    433 	*outkey = *outval = NULL;
    434 	*outkeylen = *outvallen = 0;
    435 
    436 again:
    437 	if( _yp_dobind(indomain, &ysd) != 0)
    438 		return YPERR_DOMAIN;
    439 
    440 	tv.tv_sec = _yplib_timeout;
    441 	tv.tv_usec = 0;
    442 
    443 	yprnk.domain = indomain;
    444 	yprnk.map = inmap;
    445 	bzero((char *)&yprkv, sizeof yprkv);
    446 
    447 	r = clnt_call(ysd->dom_client, YPPROC_FIRST,
    448 		xdr_ypreq_nokey, &yprnk, xdr_ypresp_key_val, &yprkv, tv);
    449 	if(r != RPC_SUCCESS) {
    450 		clnt_perror(ysd->dom_client, "yp_first: clnt_call");
    451 		ysd->dom_vers = -1;
    452 		goto again;
    453 	}
    454 	if( !(r=ypprot_err(yprkv.status)) ) {
    455 		*outkeylen = yprkv.keydat.dsize;
    456 		*outkey = (char *)malloc(*outkeylen+1);
    457 		bcopy(yprkv.keydat.dptr, *outkey, *outkeylen);
    458 		(*outkey)[*outkeylen] = '\0';
    459 		*outvallen = yprkv.valdat.dsize;
    460 		*outval = (char *)malloc(*outvallen+1);
    461 		bcopy(yprkv.valdat.dptr, *outval, *outvallen);
    462 		(*outval)[*outvallen] = '\0';
    463 	}
    464 	xdr_free(xdr_ypresp_key_val, (char *)&yprkv);
    465 	_yp_unbind(ysd);
    466 	return r;
    467 }
    468 
    469 int
    470 yp_next(indomain, inmap, inkey, inkeylen, outkey, outkeylen, outval, outvallen)
    471 char *indomain;
    472 char *inmap;
    473 char *inkey;
    474 int inkeylen;
    475 char **outkey;
    476 int *outkeylen;
    477 char **outval;
    478 int *outvallen;
    479 {
    480 	struct ypresp_key_val yprkv;
    481 	struct ypreq_key yprk;
    482 	struct dom_binding *ysd;
    483 	struct timeval tv;
    484 	int r;
    485 
    486 	*outkey = *outval = NULL;
    487 	*outkeylen = *outvallen = 0;
    488 
    489 again:
    490 	if( _yp_dobind(indomain, &ysd) != 0)
    491 		return YPERR_DOMAIN;
    492 
    493 	tv.tv_sec = _yplib_timeout;
    494 	tv.tv_usec = 0;
    495 
    496 	yprk.domain = indomain;
    497 	yprk.map = inmap;
    498 	yprk.keydat.dptr = inkey;
    499 	yprk.keydat.dsize = inkeylen;
    500 	bzero((char *)&yprkv, sizeof yprkv);
    501 
    502 	r = clnt_call(ysd->dom_client, YPPROC_NEXT,
    503 		xdr_ypreq_key, &yprk, xdr_ypresp_key_val, &yprkv, tv);
    504 	if(r != RPC_SUCCESS) {
    505 		clnt_perror(ysd->dom_client, "yp_next: clnt_call");
    506 		ysd->dom_vers = -1;
    507 		goto again;
    508 	}
    509 	if( !(r=ypprot_err(yprkv.status)) ) {
    510 		*outkeylen = yprkv.keydat.dsize;
    511 		*outkey = (char *)malloc(*outkeylen+1);
    512 		bcopy(yprkv.keydat.dptr, *outkey, *outkeylen);
    513 		(*outkey)[*outkeylen] = '\0';
    514 		*outvallen = yprkv.valdat.dsize;
    515 		*outval = (char *)malloc(*outvallen+1);
    516 		bcopy(yprkv.valdat.dptr, *outval, *outvallen);
    517 		(*outval)[*outvallen] = '\0';
    518 	}
    519 	xdr_free(xdr_ypresp_key_val, (char *)&yprkv);
    520 	_yp_unbind(ysd);
    521 	return r;
    522 }
    523 
    524 int
    525 yp_all(indomain, inmap, incallback)
    526 char *indomain;
    527 char *inmap;
    528 struct ypall_callback *incallback;
    529 {
    530 	struct ypreq_nokey yprnk;
    531 	struct dom_binding *ysd;
    532 	struct timeval tv;
    533 	struct sockaddr_in clnt_sin;
    534 	CLIENT *clnt;
    535 	u_long status;
    536 	int clnt_sock;
    537 
    538 	if( _yp_dobind(indomain, &ysd) != 0)
    539 		return YPERR_DOMAIN;
    540 
    541 	tv.tv_sec = _yplib_timeout;
    542 	tv.tv_usec = 0;
    543 	clnt_sock = RPC_ANYSOCK;
    544 	clnt_sin = ysd->dom_server_addr;
    545 	clnt_sin.sin_port = 0;
    546 	clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
    547 	if(clnt==NULL) {
    548 		printf("clnttcp_create failed\n");
    549 		return YPERR_PMAP;
    550 	}
    551 
    552 	yprnk.domain = indomain;
    553 	yprnk.map = inmap;
    554 	ypresp_allfn = incallback->foreach;
    555 	ypresp_data = (void *)incallback->data;
    556 
    557 	(void) clnt_call(clnt, YPPROC_ALL,
    558 		xdr_ypreq_nokey, &yprnk, xdr_ypresp_all_seq, &status, tv);
    559 	clnt_destroy(clnt);
    560 	xdr_free(xdr_ypresp_all_seq, (char *)&status);	/* not really needed... */
    561 	_yp_unbind(ysd);
    562 
    563 	if(status != YP_FALSE)
    564 		return ypprot_err(status);
    565 	return 0;
    566 }
    567 
    568 int
    569 yp_order(indomain, inmap, outorder)
    570 char *indomain;
    571 char *inmap;
    572 int *outorder;
    573 {
    574  	struct dom_binding *ysd;
    575 	struct ypresp_order ypro;
    576 	struct ypreq_nokey yprnk;
    577 	struct timeval tv;
    578 	int r;
    579 
    580 again:
    581 	if( _yp_dobind(indomain, &ysd) != 0)
    582 		return YPERR_DOMAIN;
    583 
    584 	tv.tv_sec = _yplib_timeout;
    585 	tv.tv_usec = 0;
    586 
    587 	yprnk.domain = indomain;
    588 	yprnk.map = inmap;
    589 
    590 	bzero((char *)(char *)&ypro, sizeof ypro);
    591 
    592 	r = clnt_call(ysd->dom_client, YPPROC_ORDER,
    593 		xdr_ypreq_nokey, &yprnk, xdr_ypresp_order, &ypro, tv);
    594 	if(r != RPC_SUCCESS) {
    595 		clnt_perror(ysd->dom_client, "yp_order: clnt_call");
    596 		ysd->dom_vers = -1;
    597 		goto again;
    598 	}
    599 
    600 	*outorder = ypro.ordernum;
    601 	xdr_free(xdr_ypresp_order, (char *)&ypro);
    602 	_yp_unbind(ysd);
    603 	return ypprot_err(ypro.status);
    604 }
    605 
    606 yp_master(indomain, inmap, outname)
    607 char *indomain;
    608 char *inmap;
    609 char **outname;
    610 {
    611 	struct dom_binding *ysd;
    612 	struct ypresp_master yprm;
    613 	struct ypreq_nokey yprnk;
    614 	struct timeval tv;
    615 	int r;
    616 
    617 again:
    618 	if( _yp_dobind(indomain, &ysd) != 0)
    619 		return YPERR_DOMAIN;
    620 
    621 	tv.tv_sec = _yplib_timeout;
    622 	tv.tv_usec = 0;
    623 
    624 	yprnk.domain = indomain;
    625 	yprnk.map = inmap;
    626 
    627 	bzero((char *)&yprm, sizeof yprm);
    628 
    629 	r = clnt_call(ysd->dom_client, YPPROC_MASTER,
    630 		xdr_ypreq_nokey, &yprnk, xdr_ypresp_master, &yprm, tv);
    631 	if(r != RPC_SUCCESS) {
    632 		clnt_perror(ysd->dom_client, "yp_master: clnt_call");
    633 		ysd->dom_vers = -1;
    634 		goto again;
    635 	}
    636 	if( !(r=ypprot_err(yprm.status)) ) {
    637 		*outname = (char *)strdup(yprm.master);
    638 	}
    639 	xdr_free(xdr_ypresp_master, (char *)&yprm);
    640 	_yp_unbind(ysd);
    641 	return r;
    642 }
    643 
    644 yp_maplist(indomain, outmaplist)
    645 char *indomain;
    646 struct ypmaplist **outmaplist;
    647 {
    648 	struct dom_binding *ysd;
    649 	struct ypresp_maplist ypml;
    650 	struct timeval tv;
    651 	int r;
    652 
    653 again:
    654 	if( _yp_dobind(indomain, &ysd) != 0)
    655 		return YPERR_DOMAIN;
    656 
    657 	tv.tv_sec = _yplib_timeout;
    658 	tv.tv_usec = 0;
    659 
    660 	bzero((char *)&ypml, sizeof ypml);
    661 
    662 	r = clnt_call(ysd->dom_client, YPPROC_MAPLIST,
    663 		xdr_domainname, indomain, xdr_ypresp_maplist, &ypml, tv);
    664 	if (r != RPC_SUCCESS) {
    665 		clnt_perror(ysd->dom_client, "yp_maplist: clnt_call");
    666 		ysd->dom_vers = -1;
    667 		goto again;
    668 	}
    669 	*outmaplist = ypml.list;
    670 	/* NO: xdr_free(xdr_ypresp_maplist, &ypml);*/
    671 	_yp_unbind(ysd);
    672 	return ypprot_err(ypml.status);
    673 }
    674 
    675 char *
    676 yperr_string(incode)
    677 int incode;
    678 {
    679 	static char err[80];
    680 
    681 	switch(incode) {
    682 	case 0:
    683 		return "Success";
    684 	case YPERR_BADARGS:
    685 		return "Request arguments bad";
    686 	case YPERR_RPC:
    687 		return "RPC failure";
    688 	case YPERR_DOMAIN:
    689 		return "Can't bind to server which serves this domain";
    690 	case YPERR_MAP:
    691 		return "No such map in server's domain";
    692 	case YPERR_KEY:
    693 		return "No such key in map";
    694 	case YPERR_YPERR:
    695 		return "YP server error";
    696 	case YPERR_RESRC:
    697 		return "Local resource allocation failure";
    698 	case YPERR_NOMORE:
    699 		return "No more records in map database";
    700 	case YPERR_PMAP:
    701 		return "Can't communicate with portmapper";
    702 	case YPERR_YPBIND:
    703 		return "Can't communicate with ypbind";
    704 	case YPERR_YPSERV:
    705 		return "Can't communicate with ypserv";
    706 	case YPERR_NODOM:
    707 		return "Local domain name not set";
    708 	case YPERR_BADDB:
    709 		return "Server data base is bad";
    710 	case YPERR_VERS:
    711 		return "YP server version mismatch - server can't supply service.";
    712 	case YPERR_ACCESS:
    713 		return "Access violation";
    714 	case YPERR_BUSY:
    715 		return "Database is busy";
    716 	}
    717 	sprintf(err, "YP unknown error %d\n", incode);
    718 	return err;
    719 }
    720 
    721 int
    722 ypprot_err(incode)
    723 unsigned int incode;
    724 {
    725 	switch(incode) {
    726 	case YP_TRUE:
    727 		return 0;
    728 	case YP_FALSE:
    729 		return YPERR_YPBIND;
    730 	case YP_NOMORE:
    731 		return YPERR_NOMORE;
    732 	case YP_NOMAP:
    733 		return YPERR_MAP;
    734 	case YP_NODOM:
    735 		return YPERR_NODOM;
    736 	case YP_NOKEY:
    737 		return YPERR_KEY;
    738 	case YP_BADOP:
    739 		return YPERR_YPERR;
    740 	case YP_BADDB:
    741 		return YPERR_BADDB;
    742 	case YP_YPERR:
    743 		return YPERR_YPERR;
    744 	case YP_BADARGS:
    745 		return YPERR_BADARGS;
    746 	case YP_VERS:
    747 		return YPERR_VERS;
    748 	}
    749 	return YPERR_YPERR;
    750 }
    751 
    752 int
    753 _yp_check(dom)
    754 char **dom;
    755 {
    756 	int use_yp = 0;
    757 	char *unused;
    758 
    759 	if( _yp_domain[0]=='\0' )
    760 		if( yp_get_default_domain(&unused) )
    761 			return 0;
    762 
    763 	if(dom)
    764 		*dom = _yp_domain;
    765 
    766 	if( yp_bind(_yp_domain)==0 )
    767 		return 1;
    768 	return 0;
    769 }
    770