xref: /freebsd/lib/libc/yp/yplib.c (revision 0ea3482342b4d7d6e71f3007ce4dafe445c639fd)
1 /*
2  * Copyright (c) 1992/3 Theo de Raadt <deraadt@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.12 1995/09/02 04:16:21 wpaul 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 <sys/uio.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <rpc/rpc.h>
45 #include <rpc/xdr.h>
46 #include <rpcsvc/yp_prot.h>
47 #include <rpcsvc/ypclnt.h>
48 
49 #ifndef YPBINDLOCK
50 #define YPBINDLOCK "/var/run/ypbind.lock"
51 #endif
52 
53 #ifndef BINDINGDIR
54 #define BINDINGDIR "/var/yp/binding"
55 #endif
56 #define YPMATCHCACHE
57 #define MAX_RETRIES 20
58 
59 extern bool_t xdr_domainname(), xdr_ypbind_resp();
60 extern bool_t xdr_ypreq_key(), xdr_ypresp_val();
61 extern bool_t xdr_ypreq_nokey(), xdr_ypresp_key_val();
62 extern bool_t xdr_ypresp_all(), xdr_ypresp_all_seq();
63 extern bool_t xdr_ypresp_master();
64 
65 int (*ypresp_allfn)();
66 void *ypresp_data;
67 
68 struct dom_binding *_ypbindlist;
69 static char _yp_domain[MAXHOSTNAMELEN];
70 int _yplib_timeout = 10;
71 
72 #ifdef YPMATCHCACHE
73 int _yplib_cache = 5;
74 
75 static struct ypmatch_ent {
76 	struct ypmatch_ent *next;
77 	char *map, *key, *val;
78 	int keylen, vallen;
79 	time_t expire_t;
80 } *ypmc;
81 
82 static void
83 ypmatch_add(map, key, keylen, val, vallen)
84 char *map;
85 char *key;
86 int keylen;
87 char *val;
88 int vallen;
89 {
90 	struct ypmatch_ent *ep;
91 	time_t t;
92 
93 	time(&t);
94 
95 	for(ep=ypmc; ep; ep=ep->next)
96 		if(ep->expire_t < t)
97 			break;
98 	if(ep==NULL) {
99 		ep = (struct ypmatch_ent *)malloc(sizeof *ep);
100 		bzero((char *)ep, sizeof *ep);
101 		if(ypmc)
102 			ep->next = ypmc;
103 		ypmc = ep;
104 	}
105 
106 	if(ep->key)
107 		free(ep->key);
108 	if(ep->val)
109 		free(ep->val);
110 
111 	ep->key = NULL;
112 	ep->val = NULL;
113 
114 	ep->key = (char *)malloc(keylen);
115 	if(ep->key==NULL)
116 		return;
117 
118 	ep->val = (char *)malloc(vallen);
119 	if(ep->key==NULL) {
120 		free(ep->key);
121 		ep->key = NULL;
122 		return;
123 	}
124 	ep->keylen = keylen;
125 	ep->vallen = vallen;
126 
127 	bcopy(key, ep->key, ep->keylen);
128 	bcopy(val, ep->val, ep->vallen);
129 
130 	if(ep->map) {
131 		if( strcmp(ep->map, map) ) {
132 			free(ep->map);
133 			ep->map = strdup(map);
134 		}
135 	} else {
136 		ep->map = strdup(map);
137 	}
138 
139 	ep->expire_t = t + _yplib_cache;
140 }
141 
142 static bool_t
143 ypmatch_find(map, key, keylen, val, vallen)
144 char *map;
145 char *key;
146 int keylen;
147 char **val;
148 int *vallen;
149 {
150 	struct ypmatch_ent *ep;
151 	time_t t;
152 
153 	if(ypmc==NULL)
154 		return 0;
155 
156 	time(&t);
157 
158 	for(ep=ypmc; ep; ep=ep->next) {
159 		if(ep->keylen != keylen)
160 			continue;
161 		if(strcmp(ep->map, map))
162 			continue;
163 		if(bcmp(ep->key, key, keylen))
164 			continue;
165 		if(t > ep->expire_t)
166 			continue;
167 
168 		*val = ep->val;
169 		*vallen = ep->vallen;
170 		return 1;
171 	}
172 	return 0;
173 }
174 #endif
175 
176 char *
177 ypbinderr_string(incode)
178 int incode;
179 {
180 	static char err[80];
181 	switch(incode) {
182 	case 0:
183 		return "Success";
184 	case YPBIND_ERR_ERR:
185 		return "Internal ypbind error";
186 	case YPBIND_ERR_NOSERV:
187 		return "Domain not bound";
188 	case YPBIND_ERR_RESC:
189 		return "System resource allocation failure";
190 	}
191 	sprintf(err, "Unknown ypbind error: #%d\n", incode);
192 	return err;
193 }
194 
195 int
196 _yp_dobind(dom, ypdb)
197 char *dom;
198 struct dom_binding **ypdb;
199 {
200 	static int pid = -1;
201 	char path[MAXPATHLEN];
202 	struct dom_binding *ysd, *ysd2;
203 	struct ypbind_resp ypbr;
204 	struct timeval tv;
205 	struct sockaddr_in clnt_sin;
206 	int clnt_sock, lfd, fd, gpid;
207 	CLIENT *client;
208 	int new = 0, r;
209 	int retries = 0;
210 
211 	gpid = getpid();
212 	if( !(pid==-1 || pid==gpid) ) {
213 		ysd = _ypbindlist;
214 		while(ysd) {
215 			if(ysd->dom_client)
216 				clnt_destroy(ysd->dom_client);
217 			ysd2 = ysd->dom_pnext;
218 			free(ysd);
219 			ysd = ysd2;
220 		}
221 		_ypbindlist = NULL;
222 	}
223 	pid = gpid;
224 
225 	if(ypdb!=NULL)
226 		*ypdb = NULL;
227 
228 	if(dom==NULL || strlen(dom)==0)
229 		return YPERR_BADARGS;
230 
231 	for(ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
232 		if( strcmp(dom, ysd->dom_domain) == 0)
233 			break;
234 	if(ysd==NULL) {
235 		ysd = (struct dom_binding *)malloc(sizeof *ysd);
236 		bzero((char *)ysd, sizeof *ysd);
237 		ysd->dom_socket = -1;
238 		ysd->dom_vers = 0;
239 		new = 1;
240 	}
241 
242 	if ((lfd = open(YPBINDLOCK, O_RDONLY)) == -1)
243 		return(YPERR_YPBIND);
244 	errno = 0;
245 	switch (flock(lfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) {
246 	case 0:
247 		close(lfd);
248 		return (YPERR_YPBIND);
249 		break;
250 	case 1:
251 	default:
252 		close(lfd);
253 		break;
254 	}
255 
256 again:
257 	retries++;
258 	if (retries > MAX_RETRIES) {
259 		if (new)
260 			free(ysd);
261 		return(YPERR_YPBIND);
262 	}
263 #ifdef BINDINGDIR
264 	if(ysd->dom_vers==0) {
265 		sprintf(path, "%s/%s.%d", BINDINGDIR, dom, 2);
266 		if( (fd=open(path, O_RDONLY)) == -1) {
267 			/* no binding file, YP is dead. */
268 			/* Try to bring it back to life. */
269 			close(fd);
270 			goto skipit;
271 		}
272 		if( flock(fd, LOCK_EX|LOCK_NB) == -1 && errno==EWOULDBLOCK) {
273 			struct iovec iov[2];
274 			struct ypbind_resp ybr;
275 			u_short	ypb_port;
276 
277 			iov[0].iov_base = (caddr_t)&ypb_port;
278 			iov[0].iov_len = sizeof ypb_port;
279 			iov[1].iov_base = (caddr_t)&ybr;
280 			iov[1].iov_len = sizeof ybr;
281 
282 			r = readv(fd, iov, 2);
283 			if(r != iov[0].iov_len + iov[1].iov_len) {
284 				close(fd);
285 				ysd->dom_vers = -1;
286 				goto again;
287 			}
288 
289 			bzero(&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
290 			ysd->dom_server_addr.sin_family = AF_INET;
291 			ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
292 			ysd->dom_server_addr.sin_addr =
293 			    ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr;
294 			ysd->dom_server_addr.sin_port =
295 			    ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port;
296 
297 			ysd->dom_server_port = ysd->dom_server_addr.sin_port;
298 			close(fd);
299 			goto gotit;
300 		} else {
301 			/* no lock on binding file, YP is dead. */
302 			/* Try to bring it back to life. */
303 			close(fd);
304 			goto skipit;
305 		}
306 	}
307 skipit:
308 #endif
309 	if(ysd->dom_vers==-1 || ysd->dom_vers==0) {
310 		bzero((char *)&clnt_sin, sizeof clnt_sin);
311 		clnt_sin.sin_family = AF_INET;
312 		clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
313 
314 		clnt_sock = RPC_ANYSOCK;
315 		client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock,
316 			0, 0);
317 		if(client==NULL) {
318 			clnt_pcreateerror("clnttcp_create");
319 			if(new)
320 				free(ysd);
321 			return (YPERR_YPBIND);
322 		}
323 
324 		tv.tv_sec = _yplib_timeout/2;
325 		tv.tv_usec = 0;
326 		r = clnt_call(client, YPBINDPROC_DOMAIN,
327 			xdr_domainname, dom, xdr_ypbind_resp, &ypbr, tv);
328 		if(r != RPC_SUCCESS) {
329 			fprintf(stderr,
330 			"YP: server for domain %s not responding, retrying\n", dom);
331 			clnt_destroy(client);
332 			ysd->dom_vers = -1;
333 			goto again;
334 		} else {
335 			if (ypbr.ypbind_status != YPBIND_SUCC_VAL) {
336 				clnt_destroy(client);
337 				ysd->dom_vers = -1;
338 				sleep(_yplib_timeout/2);
339 				goto again;
340 			}
341 		}
342 		clnt_destroy(client);
343 
344 		bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
345 		ysd->dom_server_addr.sin_family = AF_INET;
346 		ysd->dom_server_addr.sin_port =
347 			ypbr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port;
348 		ysd->dom_server_addr.sin_addr.s_addr =
349 			ypbr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr;
350 		ysd->dom_server_port =
351 			ypbr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port;
352 gotit:
353 		ysd->dom_vers = YPVERS;
354 		strcpy(ysd->dom_domain, dom);
355 	}
356 
357 	tv.tv_sec = _yplib_timeout/2;
358 	tv.tv_usec = 0;
359 	if(ysd->dom_client)
360 		clnt_destroy(ysd->dom_client);
361 	ysd->dom_socket = RPC_ANYSOCK;
362 	ysd->dom_client = clntudp_create(&ysd->dom_server_addr,
363 		YPPROG, YPVERS, tv, &ysd->dom_socket);
364 	if(ysd->dom_client==NULL) {
365 		clnt_pcreateerror("clntudp_create");
366 		ysd->dom_vers = -1;
367 		goto again;
368 	}
369 	if( fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
370 		perror("fcntl: F_SETFD");
371 
372 	if(new) {
373 		ysd->dom_pnext = _ypbindlist;
374 		_ypbindlist = ysd;
375 	}
376 
377 	if(ypdb!=NULL)
378 		*ypdb = ysd;
379 	return 0;
380 }
381 
382 static void
383 _yp_unbind(ypb)
384 struct dom_binding *ypb;
385 {
386 	clnt_destroy(ypb->dom_client);
387 	ypb->dom_client = NULL;
388 	ypb->dom_socket = -1;
389 }
390 
391 int
392 yp_bind(dom)
393 char *dom;
394 {
395 	return _yp_dobind(dom, NULL);
396 }
397 
398 void
399 yp_unbind(dom)
400 char *dom;
401 {
402 	struct dom_binding *ypb, *ypbp;
403 
404 	ypbp = NULL;
405 	for(ypb=_ypbindlist; ypb; ypb=ypb->dom_pnext) {
406 		if( strcmp(dom, ypb->dom_domain) == 0) {
407 			clnt_destroy(ypb->dom_client);
408 			if(ypbp)
409 				ypbp->dom_pnext = ypb->dom_pnext;
410 			else
411 				_ypbindlist = ypb->dom_pnext;
412 			free(ypb);
413 			return;
414 		}
415 		ypbp = ypb;
416 	}
417 	return;
418 }
419 
420 int
421 yp_match(indomain, inmap, inkey, inkeylen, outval, outvallen)
422 char *indomain;
423 char *inmap;
424 const char *inkey;
425 int inkeylen;
426 char **outval;
427 int *outvallen;
428 {
429 	struct dom_binding *ysd;
430 	struct ypresp_val yprv;
431 	struct timeval tv;
432 	struct ypreq_key yprk;
433 	int r;
434 
435 	*outval = NULL;
436 	*outvallen = 0;
437 
438 	/* Sanity check */
439 
440 	if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
441 	    inmap == NULL || !strlen(inmap) ||
442 	    indomain == NULL || !strlen(indomain))
443 		return YPERR_BADARGS;
444 
445 #ifdef YPMATCHCACHE
446 	if( !strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
447 	    inkeylen, &yprv.valdat.dptr, &yprv.valdat.dsize)) {
448 		*outvallen = yprv.valdat.dsize;
449 		*outval = (char *)malloc(*outvallen+1);
450 		bcopy(yprv.valdat.dptr, *outval, *outvallen);
451 		(*outval)[*outvallen] = '\0';
452 		return 0;
453 	}
454 #endif
455 
456 again:
457 	if( _yp_dobind(indomain, &ysd) != 0)
458 		return YPERR_DOMAIN;
459 
460 	tv.tv_sec = _yplib_timeout;
461 	tv.tv_usec = 0;
462 
463 	yprk.domain = indomain;
464 	yprk.map = inmap;
465 	yprk.keydat.dptr = (char *)inkey;
466 	yprk.keydat.dsize = inkeylen;
467 
468 	bzero((char *)&yprv, sizeof yprv);
469 
470 	r = clnt_call(ysd->dom_client, YPPROC_MATCH,
471 		xdr_ypreq_key, &yprk, xdr_ypresp_val, &yprv, tv);
472 	if(r != RPC_SUCCESS) {
473 		clnt_perror(ysd->dom_client, "yp_match: clnt_call");
474 		ysd->dom_vers = -1;
475 		goto again;
476 	}
477 	if( !(r=ypprot_err(yprv.status)) ) {
478 		*outvallen = yprv.valdat.dsize;
479 		*outval = (char *)malloc(*outvallen+1);
480 		bcopy(yprv.valdat.dptr, *outval, *outvallen);
481 		(*outval)[*outvallen] = '\0';
482 #ifdef YPMATCHCACHE
483 		if( strcmp(_yp_domain, indomain)==0 )
484 			 ypmatch_add(inmap, inkey, inkeylen, *outval, *outvallen);
485 #endif
486 	}
487 	xdr_free(xdr_ypresp_val, (char *)&yprv);
488 	_yp_unbind(ysd);
489 	return r;
490 }
491 
492 int
493 yp_get_default_domain(domp)
494 char **domp;
495 {
496 	*domp = NULL;
497 	if(_yp_domain[0] == '\0')
498 		if( getdomainname(_yp_domain, sizeof _yp_domain))
499 			return YPERR_NODOM;
500 	*domp = _yp_domain;
501 	return 0;
502 }
503 
504 int
505 yp_first(indomain, inmap, outkey, outkeylen, outval, outvallen)
506 char *indomain;
507 char *inmap;
508 char **outkey;
509 int *outkeylen;
510 char **outval;
511 int *outvallen;
512 {
513 	struct ypresp_key_val yprkv;
514 	struct ypreq_nokey yprnk;
515 	struct dom_binding *ysd;
516 	struct timeval tv;
517 	int r;
518 
519 	/* Sanity check */
520 
521 	if (indomain == NULL || !strlen(indomain) ||
522 	    inmap == NULL || !strlen(inmap))
523 		return YPERR_BADARGS;
524 
525 	*outkey = *outval = NULL;
526 	*outkeylen = *outvallen = 0;
527 
528 again:
529 	if( _yp_dobind(indomain, &ysd) != 0)
530 		return YPERR_DOMAIN;
531 
532 	tv.tv_sec = _yplib_timeout;
533 	tv.tv_usec = 0;
534 
535 	yprnk.domain = indomain;
536 	yprnk.map = inmap;
537 	bzero((char *)&yprkv, sizeof yprkv);
538 
539 	r = clnt_call(ysd->dom_client, YPPROC_FIRST,
540 		xdr_ypreq_nokey, &yprnk, xdr_ypresp_key_val, &yprkv, tv);
541 	if(r != RPC_SUCCESS) {
542 		clnt_perror(ysd->dom_client, "yp_first: clnt_call");
543 		ysd->dom_vers = 0;
544 		goto again;
545 	}
546 	if( !(r=ypprot_err(yprkv.status)) ) {
547 		*outkeylen = yprkv.keydat.dsize;
548 		*outkey = (char *)malloc(*outkeylen+1);
549 		bcopy(yprkv.keydat.dptr, *outkey, *outkeylen);
550 		(*outkey)[*outkeylen] = '\0';
551 		*outvallen = yprkv.valdat.dsize;
552 		*outval = (char *)malloc(*outvallen+1);
553 		bcopy(yprkv.valdat.dptr, *outval, *outvallen);
554 		(*outval)[*outvallen] = '\0';
555 	}
556 	xdr_free(xdr_ypresp_key_val, (char *)&yprkv);
557 	_yp_unbind(ysd);
558 	return r;
559 }
560 
561 int
562 yp_next(indomain, inmap, inkey, inkeylen, outkey, outkeylen, outval, outvallen)
563 char *indomain;
564 char *inmap;
565 char *inkey;
566 int inkeylen;
567 char **outkey;
568 int *outkeylen;
569 char **outval;
570 int *outvallen;
571 {
572 	struct ypresp_key_val yprkv;
573 	struct ypreq_key yprk;
574 	struct dom_binding *ysd;
575 	struct timeval tv;
576 	int r;
577 
578 	/* Sanity check */
579 
580 	if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
581 	    inmap == NULL || !strlen(inmap) ||
582 	    indomain == NULL || !strlen(indomain))
583 		return YPERR_BADARGS;
584 
585 	*outkey = *outval = NULL;
586 	*outkeylen = *outvallen = 0;
587 
588 again:
589 	if( _yp_dobind(indomain, &ysd) != 0)
590 		return YPERR_DOMAIN;
591 
592 	tv.tv_sec = _yplib_timeout;
593 	tv.tv_usec = 0;
594 
595 	yprk.domain = indomain;
596 	yprk.map = inmap;
597 	yprk.keydat.dptr = inkey;
598 	yprk.keydat.dsize = inkeylen;
599 	bzero((char *)&yprkv, sizeof yprkv);
600 
601 	r = clnt_call(ysd->dom_client, YPPROC_NEXT,
602 		xdr_ypreq_key, &yprk, xdr_ypresp_key_val, &yprkv, tv);
603 	if(r != RPC_SUCCESS) {
604 		clnt_perror(ysd->dom_client, "yp_next: clnt_call");
605 		ysd->dom_vers = -1;
606 		goto again;
607 	}
608 	if( !(r=ypprot_err(yprkv.status)) ) {
609 		*outkeylen = yprkv.keydat.dsize;
610 		*outkey = (char *)malloc(*outkeylen+1);
611 		bcopy(yprkv.keydat.dptr, *outkey, *outkeylen);
612 		(*outkey)[*outkeylen] = '\0';
613 		*outvallen = yprkv.valdat.dsize;
614 		*outval = (char *)malloc(*outvallen+1);
615 		bcopy(yprkv.valdat.dptr, *outval, *outvallen);
616 		(*outval)[*outvallen] = '\0';
617 	}
618 	xdr_free(xdr_ypresp_key_val, (char *)&yprkv);
619 	_yp_unbind(ysd);
620 	return r;
621 }
622 
623 int
624 yp_all(indomain, inmap, incallback)
625 char *indomain;
626 char *inmap;
627 struct ypall_callback *incallback;
628 {
629 	struct ypreq_nokey yprnk;
630 	struct dom_binding *ysd;
631 	struct timeval tv;
632 	struct sockaddr_in clnt_sin;
633 	CLIENT *clnt;
634 	u_long status;
635 	int clnt_sock;
636 
637 	/* Sanity check */
638 
639 	if (indomain == NULL || !strlen(indomain) ||
640 	    inmap == NULL || !strlen(inmap))
641 		return YPERR_BADARGS;
642 
643 	if( _yp_dobind(indomain, &ysd) != 0)
644 		return YPERR_DOMAIN;
645 
646 	tv.tv_sec = _yplib_timeout;
647 	tv.tv_usec = 0;
648 	clnt_sock = RPC_ANYSOCK;
649 	clnt_sin = ysd->dom_server_addr;
650 	clnt_sin.sin_port = 0;
651 	clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
652 	if(clnt==NULL) {
653 		printf("clnttcp_create failed\n");
654 		return YPERR_PMAP;
655 	}
656 
657 	yprnk.domain = indomain;
658 	yprnk.map = inmap;
659 	ypresp_allfn = incallback->foreach;
660 	ypresp_data = (void *)incallback->data;
661 
662 	(void) clnt_call(clnt, YPPROC_ALL,
663 		xdr_ypreq_nokey, &yprnk, xdr_ypresp_all_seq, &status, tv);
664 	clnt_destroy(clnt);
665 	xdr_free(xdr_ypresp_all_seq, (char *)&status);	/* not really needed... */
666 	_yp_unbind(ysd);
667 
668 	if(status != YP_FALSE)
669 		return ypprot_err(status);
670 	return 0;
671 }
672 
673 int
674 yp_order(indomain, inmap, outorder)
675 char *indomain;
676 char *inmap;
677 int *outorder;
678 {
679  	struct dom_binding *ysd;
680 	struct ypresp_order ypro;
681 	struct ypreq_nokey yprnk;
682 	struct timeval tv;
683 	int r;
684 
685 	/* Sanity check */
686 
687 	if (indomain == NULL || !strlen(indomain) ||
688 	    inmap == NULL || !strlen(inmap))
689 		return YPERR_BADARGS;
690 
691 again:
692 	if( _yp_dobind(indomain, &ysd) != 0)
693 		return YPERR_DOMAIN;
694 
695 	tv.tv_sec = _yplib_timeout;
696 	tv.tv_usec = 0;
697 
698 	yprnk.domain = indomain;
699 	yprnk.map = inmap;
700 
701 	bzero((char *)(char *)&ypro, sizeof ypro);
702 
703 	r = clnt_call(ysd->dom_client, YPPROC_ORDER,
704 		xdr_ypreq_nokey, &yprnk, xdr_ypresp_order, &ypro, tv);
705 	if(r != RPC_SUCCESS) {
706 		clnt_perror(ysd->dom_client, "yp_order: clnt_call");
707 		ysd->dom_vers = -1;
708 		goto again;
709 	}
710 
711 	*outorder = ypro.ordernum;
712 	xdr_free(xdr_ypresp_order, (char *)&ypro);
713 	_yp_unbind(ysd);
714 	return ypprot_err(ypro.status);
715 }
716 
717 int
718 yp_master(indomain, inmap, outname)
719 char *indomain;
720 char *inmap;
721 char **outname;
722 {
723 	struct dom_binding *ysd;
724 	struct ypresp_master yprm;
725 	struct ypreq_nokey yprnk;
726 	struct timeval tv;
727 	int r;
728 
729 	/* Sanity check */
730 
731 	if (indomain == NULL || !strlen(indomain) ||
732 	    inmap == NULL || !strlen(inmap))
733 		return YPERR_BADARGS;
734 again:
735 	if( _yp_dobind(indomain, &ysd) != 0)
736 		return YPERR_DOMAIN;
737 
738 	tv.tv_sec = _yplib_timeout;
739 	tv.tv_usec = 0;
740 
741 	yprnk.domain = indomain;
742 	yprnk.map = inmap;
743 
744 	bzero((char *)&yprm, sizeof yprm);
745 
746 	r = clnt_call(ysd->dom_client, YPPROC_MASTER,
747 		xdr_ypreq_nokey, &yprnk, xdr_ypresp_master, &yprm, tv);
748 	if(r != RPC_SUCCESS) {
749 		clnt_perror(ysd->dom_client, "yp_master: clnt_call");
750 		ysd->dom_vers = -1;
751 		goto again;
752 	}
753 	if( !(r=ypprot_err(yprm.status)) ) {
754 		*outname = (char *)strdup(yprm.master);
755 	}
756 	xdr_free(xdr_ypresp_master, (char *)&yprm);
757 	_yp_unbind(ysd);
758 	return r;
759 }
760 int
761 yp_maplist(indomain, outmaplist)
762 char *indomain;
763 struct ypmaplist **outmaplist;
764 {
765 	struct dom_binding *ysd;
766 	struct ypresp_maplist ypml;
767 	struct timeval tv;
768 	int r;
769 
770 	/* Sanity check */
771 
772 	if (indomain == NULL || !strlen(indomain))
773 		return YPERR_BADARGS;
774 
775 again:
776 	if( _yp_dobind(indomain, &ysd) != 0)
777 		return YPERR_DOMAIN;
778 
779 	tv.tv_sec = _yplib_timeout;
780 	tv.tv_usec = 0;
781 
782 	bzero((char *)&ypml, sizeof ypml);
783 
784 	r = clnt_call(ysd->dom_client, YPPROC_MAPLIST,
785 		xdr_domainname, indomain, xdr_ypresp_maplist, &ypml, tv);
786 	if (r != RPC_SUCCESS) {
787 		clnt_perror(ysd->dom_client, "yp_maplist: clnt_call");
788 		ysd->dom_vers = -1;
789 		goto again;
790 	}
791 	*outmaplist = ypml.list;
792 	/* NO: xdr_free(xdr_ypresp_maplist, &ypml);*/
793 	_yp_unbind(ysd);
794 	return ypprot_err(ypml.status);
795 }
796 
797 char *
798 yperr_string(incode)
799 int incode;
800 {
801 	static char err[80];
802 
803 	switch(incode) {
804 	case 0:
805 		return "Success";
806 	case YPERR_BADARGS:
807 		return "Request arguments bad";
808 	case YPERR_RPC:
809 		return "RPC failure";
810 	case YPERR_DOMAIN:
811 		return "Can't bind to server which serves this domain";
812 	case YPERR_MAP:
813 		return "No such map in server's domain";
814 	case YPERR_KEY:
815 		return "No such key in map";
816 	case YPERR_YPERR:
817 		return "YP server error";
818 	case YPERR_RESRC:
819 		return "Local resource allocation failure";
820 	case YPERR_NOMORE:
821 		return "No more records in map database";
822 	case YPERR_PMAP:
823 		return "Can't communicate with portmapper";
824 	case YPERR_YPBIND:
825 		return "Can't communicate with ypbind";
826 	case YPERR_YPSERV:
827 		return "Can't communicate with ypserv";
828 	case YPERR_NODOM:
829 		return "Local domain name not set";
830 	case YPERR_BADDB:
831 		return "Server data base is bad";
832 	case YPERR_VERS:
833 		return "YP server version mismatch - server can't supply service.";
834 	case YPERR_ACCESS:
835 		return "Access violation";
836 	case YPERR_BUSY:
837 		return "Database is busy";
838 	}
839 	sprintf(err, "YP unknown error %d\n", incode);
840 	return err;
841 }
842 
843 int
844 ypprot_err(incode)
845 unsigned int incode;
846 {
847 	switch(incode) {
848 	case YP_TRUE:
849 		return 0;
850 	case YP_FALSE:
851 		return YPERR_YPBIND;
852 	case YP_NOMORE:
853 		return YPERR_NOMORE;
854 	case YP_NOMAP:
855 		return YPERR_MAP;
856 	case YP_NODOM:
857 		return YPERR_DOMAIN;
858 	case YP_NOKEY:
859 		return YPERR_KEY;
860 	case YP_BADOP:
861 		return YPERR_YPERR;
862 	case YP_BADDB:
863 		return YPERR_BADDB;
864 	case YP_YPERR:
865 		return YPERR_YPERR;
866 	case YP_BADARGS:
867 		return YPERR_BADARGS;
868 	case YP_VERS:
869 		return YPERR_VERS;
870 	}
871 	return YPERR_YPERR;
872 }
873 
874 int
875 _yp_check(dom)
876 char **dom;
877 {
878 	char *unused;
879 
880 	if( _yp_domain[0]=='\0' )
881 		if( yp_get_default_domain(&unused) )
882 			return 0;
883 
884 	if(dom)
885 		*dom = _yp_domain;
886 
887 	if( yp_bind(_yp_domain)==0 ) {
888 		yp_unbind(_yp_domain);
889 		return 1;
890 	}
891 	return 0;
892 }
893