xref: /dragonfly/lib/libc/rpc/rpcb_clnt.c (revision c8860c9a)
1 /*
2  * The contents of this file are subject to the Sun Standards
3  * License Version 1.0 the (the "License";) You may not use
4  * this file except in compliance with the License.  You may
5  * obtain a copy of the License at lib/libc/rpc/LICENSE
6  *
7  * Software distributed under the License is distributed on
8  * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
9  * express or implied.  See the License for the specific
10  * language governing rights and limitations under the License.
11  *
12  * The Original Code is Copyright 1998 by Sun Microsystems, Inc
13  *
14  * The Initial Developer of the Original Code is:  Sun
15  * Microsystems, Inc.
16  *
17  * All Rights Reserved.
18  *
19  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
20  * unrestricted use provided that this legend is included on all tape
21  * media and as a part of the software program in whole or part.  Users
22  * may copy or modify Sun RPC without charge, but are not authorized
23  * to license or distribute it to anyone else except as part of a product or
24  * program developed by the user.
25  *
26  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
27  * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
29  *
30  * Sun RPC is provided with no support and without any obligation on the
31  * part of Sun Microsystems, Inc. to assist in its use, correction,
32  * modification or enhancement.
33  *
34  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
35  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
36  * OR ANY PART THEREOF.
37  *
38  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
39  * or profits or other special, indirect and consequential damages, even if
40  * Sun has been advised of the possibility of such damages.
41  *
42  * Sun Microsystems, Inc.
43  * 2550 Garcia Avenue
44  * Mountain View, California  94043
45  * @(#)rpcb_clnt.c	1.27	94/04/24 SMI; 1.30 89/06/21 Copyr 1988 Sun Micro
46  * $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $
47  * $FreeBSD: src/lib/libc/rpc/rpcb_clnt.c,v 1.17 2007/09/20 22:35:24 matteo Exp $
48  */
49 /*
50  * Copyright (c) 1986-1991 by Sun Microsystems Inc.
51  */
52 
53 /*
54  * rpcb_clnt.c
55  * interface to rpcbind rpc service.
56  *
57  * Copyright (C) 1988, Sun Microsystems, Inc.
58  */
59 
60 #include "namespace.h"
61 #include "reentrant.h"
62 #include <sys/types.h>
63 #include <sys/socket.h>
64 #include <sys/un.h>
65 #include <sys/utsname.h>
66 #include <rpc/rpc.h>
67 #include <rpc/rpcb_prot.h>
68 #include <rpc/nettype.h>
69 #include <netconfig.h>
70 #ifdef PORTMAP
71 #include <netinet/in.h>		/* FOR IPPROTO_TCP/UDP definitions */
72 #include <rpc/pmap_prot.h>
73 #endif				/* PORTMAP */
74 #include <stdio.h>
75 #include <errno.h>
76 #include <stdlib.h>
77 #include <string.h>
78 #include <unistd.h>
79 #include <netdb.h>
80 #include <syslog.h>
81 #include "un-namespace.h"
82 
83 #include "rpc_com.h"
84 #include "mt_misc.h"
85 
86 static struct timeval tottimeout = { 60, 0 };
87 static const struct timeval rmttimeout = { 3, 0 };
88 static struct timeval rpcbrmttime = { 15, 0 };
89 
90 extern bool_t xdr_wrapstring(XDR *, char **);
91 
92 static const char nullstring[] = "\000";
93 
94 #define	CACHESIZE 6
95 
96 struct address_cache {
97 	char *ac_host;
98 	char *ac_netid;
99 	char *ac_uaddr;
100 	struct netbuf *ac_taddr;
101 	struct address_cache *ac_next;
102 };
103 
104 static struct address_cache *front;
105 static int cachesize;
106 
107 #define	CLCR_GET_RPCB_TIMEOUT	1
108 #define	CLCR_SET_RPCB_TIMEOUT	2
109 
110 
111 extern int __rpc_lowvers;
112 
113 static struct address_cache *check_cache(const char *, const char *);
114 static void delete_cache(struct netbuf *);
115 static void add_cache(const char *, const char *, struct netbuf *, char *);
116 static CLIENT *getclnthandle(const char *, const struct netconfig *, char **);
117 static CLIENT *local_rpcb(void);
118 static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *);
119 
120 /*
121  * This routine adjusts the timeout used for calls to the remote rpcbind.
122  * Also, this routine can be used to set the use of portmapper version 2
123  * only when doing rpc_broadcasts
124  * These are private routines that may not be provided in future releases.
125  */
126 bool_t
127 __rpc_control(int request, void *info)
128 {
129 	switch (request) {
130 	case CLCR_GET_RPCB_TIMEOUT:
131 		*(struct timeval *)info = tottimeout;
132 		break;
133 	case CLCR_SET_RPCB_TIMEOUT:
134 		tottimeout = *(struct timeval *)info;
135 		break;
136 	case CLCR_SET_LOWVERS:
137 		__rpc_lowvers = *(int *)info;
138 		break;
139 	case CLCR_GET_LOWVERS:
140 		*(int *)info = __rpc_lowvers;
141 		break;
142 	default:
143 		return (FALSE);
144 	}
145 	return (TRUE);
146 }
147 
148 /*
149  *	It might seem that a reader/writer lock would be more reasonable here.
150  *	However because getclnthandle(), the only user of the cache functions,
151  *	may do a delete_cache() operation if a check_cache() fails to return an
152  *	address useful to clnt_tli_create(), we may as well use a mutex.
153  */
154 /*
155  * As it turns out, if the cache lock is *not* a reader/writer lock, we will
156  * block all clnt_create's if we are trying to connect to a host that's down,
157  * since the lock will be held all during that time.
158  */
159 
160 /*
161  * The routines check_cache(), add_cache(), delete_cache() manage the
162  * cache of rpcbind addresses for (host, netid).
163  */
164 
165 static struct address_cache *
166 check_cache(const char *host, const char *netid)
167 {
168 	struct address_cache *cptr;
169 
170 	/* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
171 
172 	for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
173 		if (!strcmp(cptr->ac_host, host) &&
174 		    !strcmp(cptr->ac_netid, netid)) {
175 #ifdef ND_DEBUG
176 			fprintf(stderr, "Found cache entry for %s: %s\n",
177 				host, netid);
178 #endif
179 			return (cptr);
180 		}
181 	}
182 	return (NULL);
183 }
184 
185 static void
186 delete_cache(struct netbuf *addr)
187 {
188 	struct address_cache *cptr, *prevptr = NULL;
189 
190 	/* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
191 	for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
192 		if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
193 			free(cptr->ac_host);
194 			free(cptr->ac_netid);
195 			free(cptr->ac_taddr->buf);
196 			free(cptr->ac_taddr);
197 			if (cptr->ac_uaddr)
198 				free(cptr->ac_uaddr);
199 			if (prevptr)
200 				prevptr->ac_next = cptr->ac_next;
201 			else
202 				front = cptr->ac_next;
203 			free(cptr);
204 			cachesize--;
205 			break;
206 		}
207 		prevptr = cptr;
208 	}
209 }
210 
211 static void
212 add_cache(const char *host, const char *netid, struct netbuf *taddr,
213 	  char *uaddr)
214 {
215 	struct address_cache  *ad_cache, *cptr, *prevptr;
216 
217 	ad_cache = (struct address_cache *)
218 			malloc(sizeof (struct address_cache));
219 	if (!ad_cache) {
220 		return;
221 	}
222 	ad_cache->ac_host = strdup(host);
223 	ad_cache->ac_netid = strdup(netid);
224 	ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
225 	ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf));
226 	if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
227 		(uaddr && !ad_cache->ac_uaddr)) {
228 		goto out;
229 	}
230 	ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
231 	ad_cache->ac_taddr->buf = (char *) malloc(taddr->len);
232 	if (ad_cache->ac_taddr->buf == NULL) {
233 out:
234 		if (ad_cache->ac_host)
235 			free(ad_cache->ac_host);
236 		if (ad_cache->ac_netid)
237 			free(ad_cache->ac_netid);
238 		if (ad_cache->ac_uaddr)
239 			free(ad_cache->ac_uaddr);
240 		if (ad_cache->ac_taddr)
241 			free(ad_cache->ac_taddr);
242 		free(ad_cache);
243 		return;
244 	}
245 	memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
246 #ifdef ND_DEBUG
247 	fprintf(stderr, "Added to cache: %s : %s\n", host, netid);
248 #endif
249 
250 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock:  cptr */
251 
252 	rwlock_wrlock(&rpcbaddr_cache_lock);
253 	if (cachesize < CACHESIZE) {
254 		ad_cache->ac_next = front;
255 		front = ad_cache;
256 		cachesize++;
257 	} else {
258 		/* Free the last entry */
259 		cptr = front;
260 		prevptr = NULL;
261 		while (cptr->ac_next) {
262 			prevptr = cptr;
263 			cptr = cptr->ac_next;
264 		}
265 
266 #ifdef ND_DEBUG
267 		fprintf(stderr, "Deleted from cache: %s : %s\n",
268 			cptr->ac_host, cptr->ac_netid);
269 #endif
270 		free(cptr->ac_host);
271 		free(cptr->ac_netid);
272 		free(cptr->ac_taddr->buf);
273 		free(cptr->ac_taddr);
274 		if (cptr->ac_uaddr)
275 			free(cptr->ac_uaddr);
276 
277 		if (prevptr) {
278 			prevptr->ac_next = NULL;
279 			ad_cache->ac_next = front;
280 			front = ad_cache;
281 		} else {
282 			front = ad_cache;
283 			ad_cache->ac_next = NULL;
284 		}
285 		free(cptr);
286 	}
287 	rwlock_unlock(&rpcbaddr_cache_lock);
288 }
289 
290 /*
291  * This routine will return a client handle that is connected to the
292  * rpcbind. If targaddr is non-NULL, the "universal address" of the
293  * host will be stored in *targaddr; the caller is responsible for
294  * freeing this string.
295  * On error, returns NULL and free's everything.
296  */
297 static CLIENT *
298 getclnthandle(const char *host, const struct netconfig *nconf, char **targaddr)
299 {
300 	CLIENT *client;
301 	struct netbuf *addr, taddr;
302 	struct netbuf addr_to_delete;
303 	struct __rpc_sockinfo si;
304 	struct addrinfo hints, *res, *tres;
305 	struct address_cache *ad_cache;
306 	char *tmpaddr;
307 
308 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock:  ad_cache */
309 
310 	/* Get the address of the rpcbind.  Check cache first */
311 	client = NULL;
312 	addr_to_delete.len = 0;
313 	rwlock_rdlock(&rpcbaddr_cache_lock);
314 	ad_cache = NULL;
315 	if (host != NULL)
316 		ad_cache = check_cache(host, nconf->nc_netid);
317 	if (ad_cache != NULL) {
318 		addr = ad_cache->ac_taddr;
319 		client = clnt_tli_create(RPC_ANYFD, nconf, addr,
320 		    (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
321 		if (client != NULL) {
322 			if (targaddr)
323 				*targaddr = strdup(ad_cache->ac_uaddr);
324 			rwlock_unlock(&rpcbaddr_cache_lock);
325 			return (client);
326 		}
327 		addr_to_delete.len = addr->len;
328 		addr_to_delete.buf = (char *)malloc(addr->len);
329 		if (addr_to_delete.buf == NULL) {
330 			addr_to_delete.len = 0;
331 		} else {
332 			memcpy(addr_to_delete.buf, addr->buf, addr->len);
333 		}
334 	}
335 	rwlock_unlock(&rpcbaddr_cache_lock);
336 	if (addr_to_delete.len != 0) {
337 		/*
338 		 * Assume this may be due to cache data being
339 		 *  outdated
340 		 */
341 		rwlock_wrlock(&rpcbaddr_cache_lock);
342 		delete_cache(&addr_to_delete);
343 		rwlock_unlock(&rpcbaddr_cache_lock);
344 		free(addr_to_delete.buf);
345 	}
346 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
347 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
348 		return NULL;
349 	}
350 
351 	memset(&hints, 0, sizeof hints);
352 	hints.ai_family = si.si_af;
353 	hints.ai_socktype = si.si_socktype;
354 	hints.ai_protocol = si.si_proto;
355 
356 #ifdef CLNT_DEBUG
357 	printf("trying netid %s family %d proto %d socktype %d\n",
358 	    nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype);
359 #endif
360 
361 	if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
362 		client = local_rpcb();
363 		if (! client) {
364 #ifdef ND_DEBUG
365 			clnt_pcreateerror("rpcbind clnt interface");
366 #endif
367 			return (NULL);
368 		} else {
369 			struct sockaddr_un sun;
370 			if (targaddr) {
371 			    *targaddr = malloc(sizeof(sun.sun_path));
372 			    if (*targaddr == NULL) {
373 				CLNT_DESTROY(client);
374 				return (NULL);
375 			    }
376 			    strncpy(*targaddr, _PATH_RPCBINDSOCK,
377 				sizeof(sun.sun_path));
378 			}
379 			return (client);
380 		}
381 	} else {
382 		if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) {
383 			rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
384 			return NULL;
385 		}
386 	}
387 
388 	for (tres = res; tres != NULL; tres = tres->ai_next) {
389 		taddr.buf = tres->ai_addr;
390 		taddr.len = taddr.maxlen = tres->ai_addrlen;
391 
392 #ifdef ND_DEBUG
393 		{
394 			char *ua;
395 
396 			ua = taddr2uaddr(nconf, &taddr);
397 			fprintf(stderr, "Got it [%s]\n", ua);
398 			free(ua);
399 		}
400 #endif
401 
402 #ifdef ND_DEBUG
403 		{
404 			int i;
405 
406 			fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n",
407 				taddr.len, taddr.maxlen);
408 			fprintf(stderr, "\tAddress is ");
409 			for (i = 0; i < taddr.len; i++)
410 				fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]);
411 			fprintf(stderr, "\n");
412 		}
413 #endif
414 		client = clnt_tli_create(RPC_ANYFD, nconf, &taddr,
415 		    (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
416 #ifdef ND_DEBUG
417 		if (! client) {
418 			clnt_pcreateerror("rpcbind clnt interface");
419 		}
420 #endif
421 
422 		if (client) {
423 			tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL;
424 			add_cache(host, nconf->nc_netid, &taddr, tmpaddr);
425 			if (targaddr)
426 				*targaddr = tmpaddr;
427 			break;
428 		}
429 	}
430 	if (res)
431 		freeaddrinfo(res);
432 	return (client);
433 }
434 
435 /* XXX */
436 #define IN4_LOCALHOST_STRING	"127.0.0.1"
437 #define IN6_LOCALHOST_STRING	"::1"
438 
439 /*
440  * This routine will return a client handle that is connected to the local
441  * rpcbind. Returns NULL on error and free's everything.
442  */
443 static CLIENT *
444 local_rpcb(void)
445 {
446 	CLIENT *client;
447 	static struct netconfig *loopnconf;
448 	static char *hostname;
449 	int sock;
450 	size_t tsize;
451 	struct netbuf nbuf;
452 	struct sockaddr_un sun;
453 
454 	/*
455 	 * Try connecting to the local rpcbind through a local socket
456 	 * first. If this doesn't work, try all transports defined in
457 	 * the netconfig file.
458 	 */
459 	memset(&sun, 0, sizeof sun);
460 	sock = _socket(AF_LOCAL, SOCK_STREAM, 0);
461 	if (sock < 0)
462 		goto try_nconf;
463 	sun.sun_family = AF_LOCAL;
464 	strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
465 	nbuf.len = sun.sun_len = SUN_LEN(&sun);
466 	nbuf.maxlen = sizeof (struct sockaddr_un);
467 	nbuf.buf = &sun;
468 
469 	tsize = __rpc_get_t_size(AF_LOCAL, 0, 0);
470 	client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG,
471 	    (rpcvers_t)RPCBVERS, tsize, tsize);
472 
473 	if (client != NULL) {
474 		/* Mark the socket to be closed in destructor */
475 		CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL);
476 		return client;
477 	}
478 
479 	/* Nobody needs this socket anymore; free the descriptor. */
480 	_close(sock);
481 
482 try_nconf:
483 
484 /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
485 	mutex_lock(&loopnconf_lock);
486 	if (loopnconf == NULL) {
487 		struct netconfig *nconf, *tmpnconf = NULL;
488 		void *nc_handle;
489 		int fd;
490 
491 		nc_handle = setnetconfig();
492 		if (nc_handle == NULL) {
493 			/* fails to open netconfig file */
494 			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
495 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
496 			mutex_unlock(&loopnconf_lock);
497 			return (NULL);
498 		}
499 		while ((nconf = getnetconfig(nc_handle)) != NULL) {
500 #ifdef INET6
501 			if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 ||
502 #else
503 			if ((
504 #endif
505 			     strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
506 			    (nconf->nc_semantics == NC_TPI_COTS ||
507 			     nconf->nc_semantics == NC_TPI_COTS_ORD)) {
508 				fd = __rpc_nconf2fd(nconf);
509 				/*
510 				 * Can't create a socket, assume that
511 				 * this family isn't configured in the kernel.
512 				 */
513 				if (fd < 0)
514 					continue;
515 				_close(fd);
516 				tmpnconf = nconf;
517 				if (!strcmp(nconf->nc_protofmly, NC_INET))
518 					hostname = IN4_LOCALHOST_STRING;
519 				else
520 					hostname = IN6_LOCALHOST_STRING;
521 			}
522 		}
523 		if (tmpnconf == NULL) {
524 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
525 			mutex_unlock(&loopnconf_lock);
526 			return (NULL);
527 		}
528 		loopnconf = getnetconfigent(tmpnconf->nc_netid);
529 		/* loopnconf is never freed */
530 		endnetconfig(nc_handle);
531 	}
532 	mutex_unlock(&loopnconf_lock);
533 	client = getclnthandle(hostname, loopnconf, NULL);
534 	return (client);
535 }
536 
537 /*
538  * Set a mapping between program, version and address.
539  * Calls the rpcbind service to do the mapping.
540  */
541 bool_t
542 rpcb_set(rpcprog_t program, rpcvers_t version,
543 	 const struct netconfig *nconf,	/* Network structure of transport */
544 	 const struct netbuf *address)	/* Services netconfig address */
545 {
546 	CLIENT *client;
547 	bool_t rslt = FALSE;
548 	RPCB parms;
549 	char uidbuf[32];
550 
551 	/* parameter checking */
552 	if (nconf == NULL) {
553 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
554 		return (FALSE);
555 	}
556 	if (address == NULL) {
557 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
558 		return (FALSE);
559 	}
560 	client = local_rpcb();
561 	if (! client) {
562 		return (FALSE);
563 	}
564 
565 	/* convert to universal */
566 	/*LINTED const castaway*/
567 	parms.r_addr = taddr2uaddr((struct netconfig *) nconf,
568 				   (struct netbuf *)address);
569 	if (!parms.r_addr) {
570 		CLNT_DESTROY(client);
571 		rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
572 		return (FALSE); /* no universal address */
573 	}
574 	parms.r_prog = program;
575 	parms.r_vers = version;
576 	parms.r_netid = nconf->nc_netid;
577 	/*
578 	 * Though uid is not being used directly, we still send it for
579 	 * completeness.  For non-unix platforms, perhaps some other
580 	 * string or an empty string can be sent.
581 	 */
582 	snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
583 	parms.r_owner = uidbuf;
584 
585 	CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb,
586 	    (char *)(void *)&parms, (xdrproc_t) xdr_bool,
587 	    (char *)(void *)&rslt, tottimeout);
588 
589 	CLNT_DESTROY(client);
590 	free(parms.r_addr);
591 	return (rslt);
592 }
593 
594 /*
595  * Remove the mapping between program, version and netbuf address.
596  * Calls the rpcbind service to do the un-mapping.
597  * If netbuf is NULL, unset for all the transports, otherwise unset
598  * only for the given transport.
599  */
600 bool_t
601 rpcb_unset(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf)
602 {
603 	CLIENT *client;
604 	bool_t rslt = FALSE;
605 	RPCB parms;
606 	char uidbuf[32];
607 
608 	client = local_rpcb();
609 	if (! client) {
610 		return (FALSE);
611 	}
612 
613 	parms.r_prog = program;
614 	parms.r_vers = version;
615 	if (nconf)
616 		parms.r_netid = nconf->nc_netid;
617 	else {
618 		/*LINTED const castaway*/
619 		parms.r_netid = (char *) &nullstring[0]; /* unsets  all */
620 	}
621 	/*LINTED const castaway*/
622 	parms.r_addr = (char *) &nullstring[0];
623 	snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
624 	parms.r_owner = uidbuf;
625 
626 	CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb,
627 	    (char *)(void *)&parms, (xdrproc_t) xdr_bool,
628 	    (char *)(void *)&rslt, tottimeout);
629 
630 	CLNT_DESTROY(client);
631 	return (rslt);
632 }
633 
634 /*
635  * From the merged list, find the appropriate entry
636  */
637 static struct netbuf *
638 got_entry(rpcb_entry_list_ptr relp, const struct netconfig *nconf)
639 {
640 	struct netbuf *na = NULL;
641 	rpcb_entry_list_ptr sp;
642 	rpcb_entry *rmap;
643 
644 	for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
645 		rmap = &sp->rpcb_entry_map;
646 		if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
647 		    (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
648 		    (nconf->nc_semantics == rmap->r_nc_semantics) &&
649 		    (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) {
650 			na = uaddr2taddr(nconf, rmap->r_maddr);
651 #ifdef ND_DEBUG
652 			fprintf(stderr, "\tRemote address is [%s].\n",
653 				rmap->r_maddr);
654 			if (!na)
655 				fprintf(stderr,
656 				    "\tCouldn't resolve remote address!\n");
657 #endif
658 			break;
659 		}
660 	}
661 	return (na);
662 }
663 
664 /*
665  * Quick check to see if rpcbind is up.  Tries to connect over
666  * local transport.
667  */
668 static bool_t
669 __rpcbind_is_up(void)
670 {
671 	struct netconfig *nconf;
672 	struct sockaddr_un sun;
673 	void *localhandle;
674 	int sock;
675 
676 	nconf = NULL;
677 	localhandle = setnetconfig();
678 	while ((nconf = getnetconfig(localhandle)) != NULL) {
679 		if (nconf->nc_protofmly != NULL &&
680 		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
681 			 break;
682 	}
683 	if (nconf == NULL)
684 		return (FALSE);
685 
686 	endnetconfig(localhandle);
687 
688 	memset(&sun, 0, sizeof sun);
689 	sock = _socket(AF_LOCAL, SOCK_STREAM, 0);
690 	if (sock < 0)
691 		return (FALSE);
692 	sun.sun_family = AF_LOCAL;
693 	strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path));
694 	sun.sun_len = SUN_LEN(&sun);
695 
696 	if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) {
697 		_close(sock);
698 		return (FALSE);
699 	}
700 
701 	_close(sock);
702 	return (TRUE);
703 }
704 
705 /*
706  * An internal function which optimizes rpcb_getaddr function.  It also
707  * returns the client handle that it uses to contact the remote rpcbind.
708  *
709  * The algorithm used: If the transports is TCP or UDP, it first tries
710  * version 2 (portmap), 4 and then 3 (svr4).  This order should be
711  * changed in the next OS release to 4, 2 and 3.  We are assuming that by
712  * that time, version 4 would be available on many machines on the network.
713  * With this algorithm, we get performance as well as a plan for
714  * obsoleting version 2.
715  *
716  * For all other transports, the algorithm remains as 4 and then 3.
717  *
718  * XXX: Due to some problems with t_connect(), we do not reuse the same client
719  * handle for COTS cases and hence in these cases we do not return the
720  * client handle.  This code will change if t_connect() ever
721  * starts working properly.  Also look under clnt_vc.c.
722  */
723 struct netbuf *
724 __rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version,
725 		      const struct netconfig *nconf, const char *host,
726 		      CLIENT **clpp, struct timeval *tp)
727 {
728 	static bool_t check_rpcbind = TRUE;
729 	CLIENT *client = NULL;
730 	RPCB parms;
731 	enum clnt_stat clnt_st;
732 	char *ua = NULL;
733 	rpcvers_t vers;
734 	struct netbuf *address = NULL;
735 	rpcvers_t start_vers = RPCBVERS4;
736 	struct netbuf servaddr;
737 
738 	/* parameter checking */
739 	if (nconf == NULL) {
740 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
741 		return (NULL);
742 	}
743 
744 	parms.r_addr = NULL;
745 
746 	/*
747 	 * Use default total timeout if no timeout is specified.
748 	 */
749 	if (tp == NULL)
750 		tp = &tottimeout;
751 
752 #ifdef PORTMAP
753 	/* Try version 2 for TCP or UDP */
754 	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
755 		u_short port = 0;
756 		struct netbuf remote;
757 		rpcvers_t pmapvers = 2;
758 		struct pmap pmapparms;
759 
760 		/*
761 		 * Try UDP only - there are some portmappers out
762 		 * there that use UDP only.
763 		 */
764 		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
765 			struct netconfig *newnconf;
766 
767 			if ((newnconf = getnetconfigent("udp")) == NULL) {
768 				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
769 				return (NULL);
770 			}
771 			client = getclnthandle(host, newnconf, &parms.r_addr);
772 			freenetconfigent(newnconf);
773 		} else {
774 			client = getclnthandle(host, nconf, &parms.r_addr);
775 		}
776 		if (client == NULL)
777 			return (NULL);
778 
779 		/*
780 		 * Set version and retry timeout.
781 		 */
782 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
783 		CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
784 
785 		pmapparms.pm_prog = program;
786 		pmapparms.pm_vers = version;
787 		pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
788 					IPPROTO_UDP : IPPROTO_TCP;
789 		pmapparms.pm_port = 0;	/* not needed */
790 		clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
791 		    (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms,
792 		    (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port,
793 		    *tp);
794 		if (clnt_st != RPC_SUCCESS) {
795 			if ((clnt_st == RPC_PROGVERSMISMATCH) ||
796 				(clnt_st == RPC_PROGUNAVAIL))
797 				goto try_rpcbind; /* Try different versions */
798 			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
799 			clnt_geterr(client, &rpc_createerr.cf_error);
800 			goto error;
801 		} else if (port == 0) {
802 			address = NULL;
803 			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
804 			goto error;
805 		}
806 		port = htons(port);
807 		CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
808 		if (((address = (struct netbuf *)
809 			malloc(sizeof (struct netbuf))) == NULL) ||
810 		    ((address->buf = (char *)
811 			malloc(remote.len)) == NULL)) {
812 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
813 			clnt_geterr(client, &rpc_createerr.cf_error);
814 			if (address) {
815 				free(address);
816 				address = NULL;
817 			}
818 			goto error;
819 		}
820 		memcpy(address->buf, remote.buf, remote.len);
821 		memcpy(&((char *)address->buf)[sizeof (short)],
822 				(char *)(void *)&port, sizeof (short));
823 		address->len = address->maxlen = remote.len;
824 		goto done;
825 	}
826 #endif				/* PORTMAP */
827 
828 try_rpcbind:
829 	/*
830 	 * Check if rpcbind is up.  This prevents needless delays when
831 	 * accessing applications such as the keyserver while booting
832 	 * disklessly.
833 	 */
834 	if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
835 		if (!__rpcbind_is_up()) {
836 			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
837 			rpc_createerr.cf_error.re_errno = 0;
838 			goto error;
839 		}
840 		check_rpcbind = FALSE;
841 	}
842 
843 	/*
844 	 * Now we try version 4 and then 3.
845 	 * We also send the remote system the address we used to
846 	 * contact it in case it can help to connect back with us
847 	 */
848 	parms.r_prog = program;
849 	parms.r_vers = version;
850 	/*LINTED const castaway*/
851 	parms.r_owner = (char *) &nullstring[0];	/* not needed; */
852 							/* just for xdring */
853 	parms.r_netid = nconf->nc_netid; /* not really needed */
854 
855 	/*
856 	 * If a COTS transport is being used, try getting address via CLTS
857 	 * transport.  This works only with version 4.
858 	 */
859 	if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
860 			nconf->nc_semantics == NC_TPI_COTS) {
861 
862 		void *handle;
863 		struct netconfig *nconf_clts;
864 		rpcb_entry_list_ptr relp = NULL;
865 
866 		if (client == NULL) {
867 			/* This did not go through the above PORTMAP/TCP code */
868 			if ((handle = __rpc_setconf("datagram_v")) != NULL) {
869 				while ((nconf_clts = __rpc_getconf(handle))
870 					!= NULL) {
871 					if (strcmp(nconf_clts->nc_protofmly,
872 						nconf->nc_protofmly) != 0) {
873 						continue;
874 					}
875 					client = getclnthandle(host, nconf_clts,
876 							&parms.r_addr);
877 					break;
878 				}
879 				__rpc_endconf(handle);
880 			}
881 			if (client == NULL)
882 				goto regular_rpcbind;	/* Go the regular way */
883 		} else {
884 			/* This is a UDP PORTMAP handle.  Change to version 4 */
885 			vers = RPCBVERS4;
886 			CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
887 		}
888 		/*
889 		 * We also send the remote system the address we used to
890 		 * contact it in case it can help it connect back with us
891 		 */
892 		if (parms.r_addr == NULL) {
893 			/*LINTED const castaway*/
894 			parms.r_addr = (char *) &nullstring[0]; /* for XDRing */
895 		}
896 
897 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
898 
899 		clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST,
900 		    (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
901 		    (xdrproc_t) xdr_rpcb_entry_list_ptr,
902 		    (char *)(void *)&relp, *tp);
903 		if (clnt_st == RPC_SUCCESS) {
904 			if ((address = got_entry(relp, nconf)) != NULL) {
905 				xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
906 				    (char *)(void *)&relp);
907 				CLNT_CONTROL(client, CLGET_SVC_ADDR,
908 					(char *)(void *)&servaddr);
909 				__rpc_fixup_addr(address, &servaddr);
910 				goto done;
911 			}
912 			/* Entry not found for this transport */
913 			xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
914 			    (char *)(void *)&relp);
915 			/*
916 			 * XXX: should have perhaps returned with error but
917 			 * since the remote machine might not always be able
918 			 * to send the address on all transports, we try the
919 			 * regular way with regular_rpcbind
920 			 */
921 			goto regular_rpcbind;
922 		} else if ((clnt_st == RPC_PROGVERSMISMATCH) ||
923 			(clnt_st == RPC_PROGUNAVAIL)) {
924 			start_vers = RPCBVERS;	/* Try version 3 now */
925 			goto regular_rpcbind; /* Try different versions */
926 		} else {
927 			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
928 			clnt_geterr(client, &rpc_createerr.cf_error);
929 			goto error;
930 		}
931 	}
932 
933 regular_rpcbind:
934 
935 	/* Now the same transport is to be used to get the address */
936 	if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
937 			(nconf->nc_semantics == NC_TPI_COTS))) {
938 		/* A CLTS type of client - destroy it */
939 		CLNT_DESTROY(client);
940 		client = NULL;
941 	}
942 
943 	if (client == NULL) {
944 		client = getclnthandle(host, nconf, &parms.r_addr);
945 		if (client == NULL) {
946 			goto error;
947 		}
948 	}
949 	if (parms.r_addr == NULL) {
950 		/*LINTED const castaway*/
951 		parms.r_addr = (char *) &nullstring[0];
952 	}
953 
954 	/* First try from start_vers and then version 3 (RPCBVERS) */
955 
956 	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime);
957 	for (vers = start_vers;  vers >= RPCBVERS; vers--) {
958 		/* Set the version */
959 		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
960 		clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
961 		    (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
962 		    (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp);
963 		if (clnt_st == RPC_SUCCESS) {
964 			if ((ua == NULL) || (ua[0] == 0)) {
965 				/* address unknown */
966 				rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
967 				goto error;
968 			}
969 			address = uaddr2taddr(nconf, ua);
970 #ifdef ND_DEBUG
971 			fprintf(stderr, "\tRemote address is [%s]\n", ua);
972 			if (!address)
973 				fprintf(stderr,
974 					"\tCouldn't resolve remote address!\n");
975 #endif
976 			xdr_free((xdrproc_t)xdr_wrapstring,
977 			    (char *)(void *)&ua);
978 
979 			if (! address) {
980 				/* We don't know about your universal address */
981 				rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
982 				goto error;
983 			}
984 			CLNT_CONTROL(client, CLGET_SVC_ADDR,
985 			    (char *)(void *)&servaddr);
986 			__rpc_fixup_addr(address, &servaddr);
987 			goto done;
988 		} else if (clnt_st == RPC_PROGVERSMISMATCH) {
989 			struct rpc_err rpcerr;
990 
991 			clnt_geterr(client, &rpcerr);
992 			if (rpcerr.re_vers.low > RPCBVERS4)
993 				goto error;  /* a new version, can't handle */
994 		} else if (clnt_st != RPC_PROGUNAVAIL) {
995 			/* Cant handle this error */
996 			rpc_createerr.cf_stat = clnt_st;
997 			clnt_geterr(client, &rpc_createerr.cf_error);
998 			goto error;
999 		}
1000 	}
1001 
1002 error:
1003 	if (client) {
1004 		CLNT_DESTROY(client);
1005 		client = NULL;
1006 	}
1007 done:
1008 	if (nconf->nc_semantics != NC_TPI_CLTS) {
1009 		/* This client is the connectionless one */
1010 		if (client) {
1011 			CLNT_DESTROY(client);
1012 			client = NULL;
1013 		}
1014 	}
1015 	if (clpp) {
1016 		*clpp = client;
1017 	} else if (client) {
1018 		CLNT_DESTROY(client);
1019 	}
1020 	if (parms.r_addr != NULL && parms.r_addr != nullstring)
1021 		free(parms.r_addr);
1022 	return (address);
1023 }
1024 
1025 
1026 /*
1027  * Find the mapped address for program, version.
1028  * Calls the rpcbind service remotely to do the lookup.
1029  * Uses the transport specified in nconf.
1030  * Returns FALSE (0) if no map exists, else returns 1.
1031  *
1032  * Assuming that the address is all properly allocated
1033  */
1034 int
1035 rpcb_getaddr(rpcprog_t program, rpcvers_t version,
1036 	     const struct netconfig *nconf, struct netbuf *address,
1037 	     const char *host)
1038 {
1039 	struct netbuf *na;
1040 
1041 	if ((na = __rpcb_findaddr_timed(program, version,
1042 	    (struct netconfig *) nconf, (char *) host,
1043 	    NULL, NULL)) == NULL)
1044 		return (FALSE);
1045 
1046 	if (na->len > address->maxlen) {
1047 		/* Too long address */
1048 		free(na->buf);
1049 		free(na);
1050 		rpc_createerr.cf_stat = RPC_FAILED;
1051 		return (FALSE);
1052 	}
1053 	memcpy(address->buf, na->buf, (size_t)na->len);
1054 	address->len = na->len;
1055 	free(na->buf);
1056 	free(na);
1057 	return (TRUE);
1058 }
1059 
1060 /*
1061  * Get a copy of the current maps.
1062  * Calls the rpcbind service remotely to get the maps.
1063  *
1064  * It returns only a list of the services
1065  * It returns NULL on failure.
1066  */
1067 rpcblist *
1068 rpcb_getmaps(const struct netconfig *nconf, const char *host)
1069 {
1070 	rpcblist_ptr head = NULL;
1071 	CLIENT *client;
1072 	enum clnt_stat clnt_st;
1073 	rpcvers_t vers = 0;
1074 
1075 	client = getclnthandle(host, nconf, NULL);
1076 	if (client == NULL) {
1077 		return (head);
1078 	}
1079 	clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
1080 	    (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
1081 	    (char *)(void *)&head, tottimeout);
1082 	if (clnt_st == RPC_SUCCESS)
1083 		goto done;
1084 
1085 	if ((clnt_st != RPC_PROGVERSMISMATCH) &&
1086 	    (clnt_st != RPC_PROGUNAVAIL)) {
1087 		rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1088 		clnt_geterr(client, &rpc_createerr.cf_error);
1089 		goto done;
1090 	}
1091 
1092 	/* fall back to earlier version */
1093 	CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
1094 	if (vers == RPCBVERS4) {
1095 		vers = RPCBVERS;
1096 		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
1097 		if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
1098 		    (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
1099 		    (char *)(void *)&head, tottimeout) == RPC_SUCCESS)
1100 			goto done;
1101 	}
1102 	rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1103 	clnt_geterr(client, &rpc_createerr.cf_error);
1104 
1105 done:
1106 	CLNT_DESTROY(client);
1107 	return (head);
1108 }
1109 
1110 /*
1111  * rpcbinder remote-call-service interface.
1112  * This routine is used to call the rpcbind remote call service
1113  * which will look up a service program in the address maps, and then
1114  * remotely call that routine with the given parameters. This allows
1115  * programs to do a lookup and call in one step.
1116 */
1117 enum clnt_stat
1118 rpcb_rmtcall(const struct netconfig *nconf, const char *host, rpcprog_t prog,
1119 	     rpcvers_t vers, rpcproc_t proc, xdrproc_t xdrargs, caddr_t argsp,
1120 	     xdrproc_t xdrres, caddr_t resp, struct timeval tout,
1121 	     const struct netbuf *addr_ptr)
1122 {
1123 	CLIENT *client;
1124 	enum clnt_stat stat;
1125 	struct r_rpcb_rmtcallargs a;
1126 	struct r_rpcb_rmtcallres r;
1127 	rpcvers_t rpcb_vers;
1128 
1129 	stat = 0;
1130 	client = getclnthandle(host, nconf, NULL);
1131 	if (client == NULL) {
1132 		return (RPC_FAILED);
1133 	}
1134 	/*LINTED const castaway*/
1135 	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout);
1136 	a.prog = prog;
1137 	a.vers = vers;
1138 	a.proc = proc;
1139 	a.args.args_val = argsp;
1140 	a.xdr_args = xdrargs;
1141 	r.addr = NULL;
1142 	r.results.results_val = resp;
1143 	r.xdr_res = xdrres;
1144 
1145 	for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
1146 		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers);
1147 		stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT,
1148 		    (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a,
1149 		    (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout);
1150 		if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
1151 			struct netbuf *na;
1152 			/*LINTED const castaway*/
1153 			na = uaddr2taddr((struct netconfig *) nconf, r.addr);
1154 			if (!na) {
1155 				stat = RPC_N2AXLATEFAILURE;
1156 				/*LINTED const castaway*/
1157 				((struct netbuf *) addr_ptr)->len = 0;
1158 				goto error;
1159 			}
1160 			if (na->len > addr_ptr->maxlen) {
1161 				/* Too long address */
1162 				stat = RPC_FAILED; /* XXX A better error no */
1163 				free(na->buf);
1164 				free(na);
1165 				/*LINTED const castaway*/
1166 				((struct netbuf *) addr_ptr)->len = 0;
1167 				goto error;
1168 			}
1169 			memcpy(addr_ptr->buf, na->buf, (size_t)na->len);
1170 			/*LINTED const castaway*/
1171 			((struct netbuf *)addr_ptr)->len = na->len;
1172 			free(na->buf);
1173 			free(na);
1174 			break;
1175 		} else if ((stat != RPC_PROGVERSMISMATCH) &&
1176 			    (stat != RPC_PROGUNAVAIL)) {
1177 			goto error;
1178 		}
1179 	}
1180 error:
1181 	CLNT_DESTROY(client);
1182 	if (r.addr)
1183 		xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr);
1184 	return (stat);
1185 }
1186 
1187 /*
1188  * Gets the time on the remote host.
1189  * Returns 1 if succeeds else 0.
1190  */
1191 bool_t
1192 rpcb_gettime(const char *host, time_t *timep)
1193 {
1194 	CLIENT *client = NULL;
1195 	void *handle;
1196 	struct netconfig *nconf;
1197 	rpcvers_t vers;
1198 	enum clnt_stat st;
1199 
1200 
1201 	if ((host == NULL) || (host[0] == 0)) {
1202 		time(timep);
1203 		return (TRUE);
1204 	}
1205 
1206 	if ((handle = __rpc_setconf("netpath")) == NULL) {
1207 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1208 		return (FALSE);
1209 	}
1210 	rpc_createerr.cf_stat = RPC_SUCCESS;
1211 	while (client == NULL) {
1212 		if ((nconf = __rpc_getconf(handle)) == NULL) {
1213 			if (rpc_createerr.cf_stat == RPC_SUCCESS)
1214 				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1215 			break;
1216 		}
1217 		client = getclnthandle(host, nconf, NULL);
1218 		if (client)
1219 			break;
1220 	}
1221 	__rpc_endconf(handle);
1222 	if (client == NULL) {
1223 		return (FALSE);
1224 	}
1225 
1226 	st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
1227 		(xdrproc_t) xdr_void, NULL,
1228 		(xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout);
1229 
1230 	if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
1231 		CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
1232 		if (vers == RPCBVERS4) {
1233 			/* fall back to earlier version */
1234 			vers = RPCBVERS;
1235 			CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
1236 			st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
1237 				(xdrproc_t) xdr_void, NULL,
1238 				(xdrproc_t) xdr_int, (char *)(void *)timep,
1239 				tottimeout);
1240 		}
1241 	}
1242 	CLNT_DESTROY(client);
1243 	return (st == RPC_SUCCESS);
1244 }
1245 
1246 /*
1247  * Converts taddr to universal address.  This routine should never
1248  * really be called because local n2a libraries are always provided.
1249  */
1250 char *
1251 rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
1252 {
1253 	CLIENT *client;
1254 	char *uaddr = NULL;
1255 
1256 
1257 	/* parameter checking */
1258 	if (nconf == NULL) {
1259 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1260 		return (NULL);
1261 	}
1262 	if (taddr == NULL) {
1263 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1264 		return (NULL);
1265 	}
1266 	client = local_rpcb();
1267 	if (! client) {
1268 		return (NULL);
1269 	}
1270 
1271 	CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR,
1272 	    (xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
1273 	    (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout);
1274 	CLNT_DESTROY(client);
1275 	return (uaddr);
1276 }
1277 
1278 /*
1279  * Converts universal address to netbuf.  This routine should never
1280  * really be called because local n2a libraries are always provided.
1281  */
1282 struct netbuf *
1283 rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
1284 {
1285 	CLIENT *client;
1286 	struct netbuf *taddr;
1287 
1288 
1289 	/* parameter checking */
1290 	if (nconf == NULL) {
1291 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1292 		return (NULL);
1293 	}
1294 	if (uaddr == NULL) {
1295 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1296 		return (NULL);
1297 	}
1298 	client = local_rpcb();
1299 	if (! client) {
1300 		return (NULL);
1301 	}
1302 
1303 	taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf));
1304 	if (taddr == NULL) {
1305 		CLNT_DESTROY(client);
1306 		return (NULL);
1307 	}
1308 	if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR,
1309 	    (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr,
1310 	    (xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
1311 	    tottimeout) != RPC_SUCCESS) {
1312 		free(taddr);
1313 		taddr = NULL;
1314 	}
1315 	CLNT_DESTROY(client);
1316 	return (taddr);
1317 }
1318