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