xref: /illumos-gate/usr/src/lib/libnsl/rpc/rpcb_clnt.c (revision 5422785d352a2bb398daceab3d1898a8aa64d006)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2014 Gary Mills
25  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31 /*
32  * Portions of this source code were derived from Berkeley
33  * 4.3 BSD under license from the Regents of the University of
34  * California.
35  */
36 
37 /*
38  * interface to rpcbind rpc service.
39  */
40 
41 #include "mt.h"
42 #include "rpc_mt.h"
43 #include <assert.h>
44 #include <rpc/rpc.h>
45 #include <rpc/rpcb_prot.h>
46 #include <netconfig.h>
47 #include <netdir.h>
48 #include <netdb.h>
49 #include <rpc/nettype.h>
50 #include <syslog.h>
51 #ifdef PORTMAP
52 #include <netinet/in.h>		/* FOR IPPROTO_TCP/UDP definitions */
53 #include <rpc/pmap_prot.h>
54 #endif
55 #include <sys/utsname.h>
56 #include <errno.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60 
61 static struct timeval tottimeout = { 60, 0 };
62 static const struct timeval rmttimeout = { 3, 0 };
63 static struct timeval rpcbrmttime = { 15, 0 };
64 
65 extern bool_t xdr_wrapstring(XDR *, char **);
66 
67 static const char nullstring[] = "\000";
68 
69 extern CLIENT *_clnt_tli_create_timed(int, const struct netconfig *,
70 			struct netbuf *, rpcprog_t, rpcvers_t, uint_t, uint_t,
71 			const struct timeval *);
72 
73 static CLIENT *_getclnthandle_timed(char *, struct netconfig *, char **,
74 			struct timeval *);
75 
76 
77 /*
78  * The life time of a cached entry should not exceed 5 minutes
79  * since automountd attempts an unmount every 5 minutes.
80  * It is arbitrarily set a little lower (3 min = 180 sec)
81  * to reduce the time during which an entry is stale.
82  */
83 #define	CACHE_TTL 180
84 #define	CACHESIZE 6
85 
86 struct address_cache {
87 	char *ac_host;
88 	char *ac_netid;
89 	char *ac_uaddr;
90 	struct netbuf *ac_taddr;
91 	struct address_cache *ac_next;
92 	time_t ac_maxtime;
93 };
94 
95 static struct address_cache *front;
96 static int cachesize;
97 
98 extern int lowvers;
99 extern int authdes_cachesz;
100 /*
101  * This routine adjusts the timeout used for calls to the remote rpcbind.
102  * Also, this routine can be used to set the use of portmapper version 2
103  * only when doing rpc_broadcasts
104  * These are private routines that may not be provided in future releases.
105  */
106 bool_t
107 __rpc_control(int request, void *info)
108 {
109 	switch (request) {
110 	case CLCR_GET_RPCB_TIMEOUT:
111 		*(struct timeval *)info = tottimeout;
112 		break;
113 	case CLCR_SET_RPCB_TIMEOUT:
114 		tottimeout = *(struct timeval *)info;
115 		break;
116 	case CLCR_GET_LOWVERS:
117 		*(int *)info = lowvers;
118 		break;
119 	case CLCR_SET_LOWVERS:
120 		lowvers = *(int *)info;
121 		break;
122 	case CLCR_GET_RPCB_RMTTIME:
123 		*(struct timeval *)info = rpcbrmttime;
124 		break;
125 	case CLCR_SET_RPCB_RMTTIME:
126 		rpcbrmttime = *(struct timeval *)info;
127 		break;
128 	case CLCR_GET_CRED_CACHE_SZ:
129 		*(int *)info = authdes_cachesz;
130 		break;
131 	case CLCR_SET_CRED_CACHE_SZ:
132 		authdes_cachesz = *(int *)info;
133 		break;
134 	default:
135 		return (FALSE);
136 	}
137 	return (TRUE);
138 }
139 
140 /*
141  *	It might seem that a reader/writer lock would be more reasonable here.
142  *	However because getclnthandle(), the only user of the cache functions,
143  *	may do a delete_cache() operation if a check_cache() fails to return an
144  *	address useful to clnt_tli_create(), we may as well use a mutex.
145  */
146 /*
147  * As it turns out, if the cache lock is *not* a reader/writer lock, we will
148  * block all clnt_create's if we are trying to connect to a host that's down,
149  * since the lock will be held all during that time.
150  */
151 extern rwlock_t	rpcbaddr_cache_lock;
152 
153 /*
154  * The routines check_cache(), add_cache(), delete_cache() manage the
155  * cache of rpcbind addresses for (host, netid).
156  */
157 
158 static struct address_cache *
159 check_cache(char *host, char *netid)
160 {
161 	struct address_cache *cptr;
162 
163 	/* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
164 
165 	assert(RW_READ_HELD(&rpcbaddr_cache_lock));
166 	for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
167 		if ((strcmp(cptr->ac_host, host) == 0) &&
168 		    (strcmp(cptr->ac_netid, netid) == 0) &&
169 		    (time(NULL) <= cptr->ac_maxtime)) {
170 			return (cptr);
171 		}
172 	}
173 	return (NULL);
174 }
175 
176 static void
177 delete_cache(struct netbuf *addr)
178 {
179 	struct address_cache *cptr, *prevptr = NULL;
180 
181 	/* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
182 	assert(RW_WRITE_HELD(&rpcbaddr_cache_lock));
183 	for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
184 		if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
185 			free(cptr->ac_host);
186 			free(cptr->ac_netid);
187 			free(cptr->ac_taddr->buf);
188 			free(cptr->ac_taddr);
189 			if (cptr->ac_uaddr)
190 				free(cptr->ac_uaddr);
191 			if (prevptr)
192 				prevptr->ac_next = cptr->ac_next;
193 			else
194 				front = cptr->ac_next;
195 			free(cptr);
196 			cachesize--;
197 			break;
198 		}
199 		prevptr = cptr;
200 	}
201 }
202 
203 static void
204 add_cache(char *host, char *netid, struct netbuf *taddr, char *uaddr)
205 {
206 	struct address_cache  *ad_cache, *cptr, *prevptr;
207 
208 	ad_cache = malloc(sizeof (struct address_cache));
209 	if (!ad_cache) {
210 		goto memerr;
211 	}
212 	ad_cache->ac_maxtime = time(NULL) + CACHE_TTL;
213 	ad_cache->ac_host = strdup(host);
214 	ad_cache->ac_netid = strdup(netid);
215 	ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
216 	ad_cache->ac_taddr = malloc(sizeof (struct netbuf));
217 	if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
218 	    (uaddr && !ad_cache->ac_uaddr)) {
219 		goto memerr1;
220 	}
221 
222 	ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
223 	ad_cache->ac_taddr->buf = malloc(taddr->len);
224 	if (ad_cache->ac_taddr->buf == NULL) {
225 		goto memerr1;
226 	}
227 
228 	(void) memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
229 
230 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock:  cptr */
231 
232 	(void) rw_wrlock(&rpcbaddr_cache_lock);
233 	if (cachesize < CACHESIZE) {
234 		ad_cache->ac_next = front;
235 		front = ad_cache;
236 		cachesize++;
237 	} else {
238 		/* Free the last entry */
239 		cptr = front;
240 		prevptr = NULL;
241 		while (cptr->ac_next) {
242 			prevptr = cptr;
243 			cptr = cptr->ac_next;
244 		}
245 
246 		free(cptr->ac_host);
247 		free(cptr->ac_netid);
248 		free(cptr->ac_taddr->buf);
249 		free(cptr->ac_taddr);
250 		if (cptr->ac_uaddr)
251 			free(cptr->ac_uaddr);
252 
253 		if (prevptr) {
254 			prevptr->ac_next = NULL;
255 			ad_cache->ac_next = front;
256 			front = ad_cache;
257 		} else {
258 			front = ad_cache;
259 			ad_cache->ac_next = NULL;
260 		}
261 		free(cptr);
262 	}
263 	(void) rw_unlock(&rpcbaddr_cache_lock);
264 	return;
265 memerr1:
266 	if (ad_cache->ac_host)
267 		free(ad_cache->ac_host);
268 	if (ad_cache->ac_netid)
269 		free(ad_cache->ac_netid);
270 	if (ad_cache->ac_uaddr)
271 		free(ad_cache->ac_uaddr);
272 	if (ad_cache->ac_taddr)
273 		free(ad_cache->ac_taddr);
274 	free(ad_cache);
275 memerr:
276 	syslog(LOG_ERR, "add_cache : out of memory.");
277 }
278 
279 /*
280  * This routine will return a client handle that is connected to the
281  * rpcbind. Returns NULL on error and free's everything.
282  */
283 static CLIENT *
284 getclnthandle(char *host, struct netconfig *nconf, char **targaddr)
285 {
286 	return (_getclnthandle_timed(host, nconf, targaddr, NULL));
287 }
288 
289 /*
290  * Same as getclnthandle() except it takes an extra timeout argument.
291  * This is for bug 4049792: clnt_create_timed does not timeout.
292  *
293  * If tp is NULL, use default timeout to get a client handle.
294  */
295 static CLIENT *
296 _getclnthandle_timed(char *host, struct netconfig *nconf, char **targaddr,
297 							struct timeval *tp)
298 {
299 	CLIENT *client = NULL;
300 	struct netbuf *addr;
301 	struct netbuf addr_to_delete;
302 	struct nd_addrlist *nas;
303 	struct nd_hostserv rpcbind_hs;
304 	struct address_cache *ad_cache;
305 	char *tmpaddr;
306 	int neterr;
307 	int j;
308 
309 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock:  ad_cache */
310 
311 	/* Get the address of the rpcbind.  Check cache first */
312 	addr_to_delete.len = 0;
313 	(void) rw_rdlock(&rpcbaddr_cache_lock);
314 	ad_cache = check_cache(host, nconf->nc_netid);
315 	if (ad_cache != NULL) {
316 		addr = ad_cache->ac_taddr;
317 		client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr,
318 		    RPCBPROG, RPCBVERS4, 0, 0, tp);
319 		if (client != NULL) {
320 			if (targaddr) {
321 				/*
322 				 * case where a client handle is created
323 				 * without a targaddr and the handle is
324 				 * requested with a targaddr
325 				 */
326 				if (ad_cache->ac_uaddr != NULL) {
327 					*targaddr = strdup(ad_cache->ac_uaddr);
328 					if (*targaddr == NULL) {
329 						syslog(LOG_ERR,
330 						"_getclnthandle_timed: strdup "
331 						"failed.");
332 						rpc_createerr.cf_stat =
333 						    RPC_SYSTEMERROR;
334 						(void) rw_unlock(
335 						    &rpcbaddr_cache_lock);
336 						return (NULL);
337 					}
338 				} else {
339 					*targaddr = NULL;
340 				}
341 			}
342 			(void) rw_unlock(&rpcbaddr_cache_lock);
343 			return (client);
344 		}
345 		if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) {
346 			(void) rw_unlock(&rpcbaddr_cache_lock);
347 			return (NULL);
348 		}
349 		addr_to_delete.len = addr->len;
350 		addr_to_delete.buf = malloc(addr->len);
351 		if (addr_to_delete.buf == NULL) {
352 			addr_to_delete.len = 0;
353 		} else {
354 			(void) memcpy(addr_to_delete.buf, addr->buf, addr->len);
355 		}
356 	}
357 	(void) rw_unlock(&rpcbaddr_cache_lock);
358 	if (addr_to_delete.len != 0) {
359 		/*
360 		 * Assume this may be due to cache data being
361 		 *  outdated
362 		 */
363 		(void) rw_wrlock(&rpcbaddr_cache_lock);
364 		delete_cache(&addr_to_delete);
365 		(void) rw_unlock(&rpcbaddr_cache_lock);
366 		free(addr_to_delete.buf);
367 	}
368 	rpcbind_hs.h_host = host;
369 	rpcbind_hs.h_serv = "rpcbind";
370 
371 	if ((neterr = netdir_getbyname(nconf, &rpcbind_hs, &nas)) != 0) {
372 		if (neterr == ND_NOHOST)
373 			rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
374 		else
375 			rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
376 		return (NULL);
377 	}
378 	/* XXX nas should perhaps be cached for better performance */
379 
380 	for (j = 0; j < nas->n_cnt; j++) {
381 		addr = &(nas->n_addrs[j]);
382 	client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr, RPCBPROG,
383 	    RPCBVERS4, 0, 0, tp);
384 	if (client)
385 		break;
386 	}
387 
388 	if (client) {
389 		tmpaddr = targaddr ? taddr2uaddr(nconf, addr) : NULL;
390 		add_cache(host, nconf->nc_netid, addr, tmpaddr);
391 		if (targaddr) {
392 			*targaddr = tmpaddr;
393 		}
394 	}
395 	netdir_free((char *)nas, ND_ADDRLIST);
396 	return (client);
397 }
398 
399 /*
400  * This routine will return a client handle that is connected to the local
401  * rpcbind. Returns NULL on error.
402  */
403 static CLIENT *
404 local_rpcb(void)
405 {
406 	static struct netconfig *loopnconf;
407 	static char hostname[MAXHOSTNAMELEN + 1];
408 	extern mutex_t loopnconf_lock;
409 
410 /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
411 	(void) mutex_lock(&loopnconf_lock);
412 	if (loopnconf == NULL) {
413 		struct netconfig *nconf, *tmpnconf = NULL;
414 		void *nc_handle;
415 
416 		if ((hostname[0] == '\0') && (gethostname(hostname,
417 		    sizeof (hostname)) < 0)) {
418 			syslog(LOG_ERR, "local_rpcb: gethostname failed.");
419 			rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
420 			(void) mutex_unlock(&loopnconf_lock);
421 			return (NULL);
422 		}
423 		nc_handle = setnetconfig();
424 		if (nc_handle == NULL) {
425 			/* fails to open netconfig file */
426 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
427 			(void) mutex_unlock(&loopnconf_lock);
428 			return (NULL);
429 		}
430 		while (nconf = getnetconfig(nc_handle)) {
431 			if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
432 				tmpnconf = nconf;
433 				if (nconf->nc_semantics == NC_TPI_CLTS)
434 					break;
435 			}
436 		}
437 		if (tmpnconf == NULL) {
438 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
439 			(void) mutex_unlock(&loopnconf_lock);
440 			return (NULL);
441 		}
442 		loopnconf = getnetconfigent(tmpnconf->nc_netid);
443 		/* loopnconf is never freed */
444 		(void) endnetconfig(nc_handle);
445 	}
446 	(void) mutex_unlock(&loopnconf_lock);
447 	return (getclnthandle(hostname, loopnconf, NULL));
448 }
449 
450 /*
451  * Set a mapping between program, version and address.
452  * Calls the rpcbind service to do the mapping.
453  */
454 bool_t
455 rpcb_set(const rpcprog_t program, const rpcvers_t version,
456 		const struct netconfig *nconf, const struct netbuf *address)
457 {
458 	CLIENT *client;
459 	bool_t rslt = FALSE;
460 	RPCB parms;
461 	char uidbuf[32];
462 
463 	/* parameter checking */
464 	if (nconf == NULL) {
465 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
466 		return (FALSE);
467 	}
468 	if (address == NULL) {
469 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
470 		return (FALSE);
471 	}
472 	client = local_rpcb();
473 	if (!client)
474 		return (FALSE);
475 
476 	parms.r_addr = taddr2uaddr((struct netconfig *)nconf,
477 	    (struct netbuf *)address); /* convert to universal */
478 	if (!parms.r_addr) {
479 		rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
480 		return (FALSE); /* no universal address */
481 	}
482 	parms.r_prog = program;
483 	parms.r_vers = version;
484 	parms.r_netid = nconf->nc_netid;
485 	/*
486 	 * Though uid is not being used directly, we still send it for
487 	 * completeness.  For non-unix platforms, perhaps some other
488 	 * string or an empty string can be sent.
489 	 */
490 	(void) sprintf(uidbuf, "%d", (int)geteuid());
491 	parms.r_owner = uidbuf;
492 
493 	CLNT_CALL(client, RPCBPROC_SET, (xdrproc_t)xdr_rpcb, (char *)&parms,
494 	    (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
495 
496 	CLNT_DESTROY(client);
497 	free(parms.r_addr);
498 	return (rslt);
499 }
500 
501 /*
502  * Remove the mapping between program, version and netbuf address.
503  * Calls the rpcbind service to do the un-mapping.
504  * If netbuf is NULL, unset for all the transports, otherwise unset
505  * only for the given transport.
506  */
507 bool_t
508 rpcb_unset(const rpcprog_t program, const rpcvers_t version,
509 						const struct netconfig *nconf)
510 {
511 	CLIENT *client;
512 	bool_t rslt = FALSE;
513 	RPCB parms;
514 	char uidbuf[32];
515 
516 	client = local_rpcb();
517 	if (!client)
518 		return (FALSE);
519 
520 	parms.r_prog = program;
521 	parms.r_vers = version;
522 	if (nconf)
523 		parms.r_netid = nconf->nc_netid;
524 	else
525 		parms.r_netid = (char *)&nullstring[0]; /* unsets  all */
526 	parms.r_addr = (char *)&nullstring[0];
527 	(void) sprintf(uidbuf, "%d", (int)geteuid());
528 	parms.r_owner = uidbuf;
529 
530 	CLNT_CALL(client, RPCBPROC_UNSET, (xdrproc_t)xdr_rpcb, (char *)&parms,
531 	    (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
532 
533 	CLNT_DESTROY(client);
534 	return (rslt);
535 }
536 
537 /*
538  * From the merged list, find the appropriate entry
539  */
540 static struct netbuf *
541 got_entry(rpcb_entry_list_ptr relp, struct netconfig *nconf)
542 {
543 	struct netbuf *na = NULL;
544 	rpcb_entry_list_ptr sp;
545 	rpcb_entry *rmap;
546 
547 	for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
548 		rmap = &sp->rpcb_entry_map;
549 		if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
550 		    (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
551 		    (nconf->nc_semantics == rmap->r_nc_semantics) &&
552 		    (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != NULL)) {
553 			na = uaddr2taddr(nconf, rmap->r_maddr);
554 			break;
555 		}
556 	}
557 	return (na);
558 }
559 
560 /*
561  * Quick check to see if rpcbind is up.  Tries to connect over
562  * local transport.
563  */
564 bool_t
565 __rpcbind_is_up(void)
566 {
567 	char hostname[MAXHOSTNAMELEN + 1];
568 	char uaddr[SYS_NMLN];
569 	struct netbuf *addr;
570 	int fd;
571 	struct t_call *sndcall;
572 	struct netconfig *netconf;
573 	bool_t res;
574 
575 	if (gethostname(hostname, sizeof (hostname)) < 0)
576 		return (TRUE);
577 
578 	if ((fd = t_open("/dev/ticotsord", O_RDWR, NULL)) == -1)
579 		return (TRUE);
580 
581 	if (t_bind(fd, NULL, NULL) == -1) {
582 		(void) t_close(fd);
583 		return (TRUE);
584 	}
585 
586 	/* LINTED pointer cast */
587 	if ((sndcall = (struct t_call *)t_alloc(fd, T_CALL, 0)) == NULL) {
588 		(void) t_close(fd);
589 		return (TRUE);
590 	}
591 
592 	uaddr[0] = '\0';
593 	(void) strlcpy(uaddr, hostname, sizeof (uaddr) - 5);
594 	(void) strcat(uaddr, ".rpc");
595 	if ((netconf = getnetconfigent("ticotsord")) == NULL) {
596 		(void) t_free((char *)sndcall, T_CALL);
597 		(void) t_close(fd);
598 		return (FALSE);
599 	}
600 	addr = uaddr2taddr(netconf, uaddr);
601 	freenetconfigent(netconf);
602 	if (addr == NULL || addr->buf == NULL) {
603 		if (addr)
604 			free(addr);
605 		(void) t_free((char *)sndcall, T_CALL);
606 		(void) t_close(fd);
607 		return (FALSE);
608 	}
609 	sndcall->addr.maxlen = addr->maxlen;
610 	sndcall->addr.len = addr->len;
611 	sndcall->addr.buf = addr->buf;
612 
613 	if (t_connect(fd, sndcall, NULL) == -1)
614 		res = FALSE;
615 	else
616 		res = TRUE;
617 
618 	sndcall->addr.maxlen = sndcall->addr.len = 0;
619 	sndcall->addr.buf = NULL;
620 	(void) t_free((char *)sndcall, T_CALL);
621 	free(addr->buf);
622 	free(addr);
623 	(void) t_close(fd);
624 
625 	return (res);
626 }
627 
628 
629 /*
630  * An internal function which optimizes rpcb_getaddr function.  It returns
631  * the universal address of the remote service or NULL.  It also optionally
632  * returns the client handle that it uses to contact the remote rpcbind.
633  * The caller will re-purpose the client handle to contact the remote service.
634  *
635  * The algorithm used: First try version 4.  Then try version 3 (svr4).
636  * Finally, if the transport is TCP or UDP, try version 2 (portmap).
637  * Version 4 is now available with all current systems on the network.
638  * With this algorithm, we get performance as well as a plan for
639  * obsoleting version 2.
640  *
641  * XXX: Due to some problems with t_connect(), we do not reuse the same client
642  * handle for COTS cases and hence in these cases we do not return the
643  * client handle.  This code will change if t_connect() ever
644  * starts working properly.  Also look under clnt_vc.c.
645  */
646 struct netbuf *
647 __rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version,
648 	struct netconfig *nconf, char *host, CLIENT **clpp, struct timeval *tp)
649 {
650 	static bool_t check_rpcbind = TRUE;
651 	CLIENT *client = NULL;
652 	RPCB parms;
653 	enum clnt_stat clnt_st;
654 	char *ua = NULL;
655 	uint_t vers;
656 	struct netbuf *address = NULL;
657 	void *handle;
658 	rpcb_entry_list_ptr relp = NULL;
659 	bool_t tmp_client = FALSE;
660 
661 	/* parameter checking */
662 	if (nconf == NULL) {
663 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
664 		/*
665 		 * Setting rpc_createerr.cf_stat is sufficient.
666 		 * No details in rpc_createerr.cf_error needed.
667 		 */
668 		return (NULL);
669 	}
670 
671 	parms.r_addr = NULL;
672 
673 	/*
674 	 * Use default total timeout if no timeout is specified.
675 	 */
676 	if (tp == NULL)
677 		tp = &tottimeout;
678 
679 	/*
680 	 * Check if rpcbind is up.  This prevents needless delays when
681 	 * accessing applications such as the keyserver while booting
682 	 * disklessly.
683 	 */
684 	if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
685 		if (!__rpcbind_is_up()) {
686 			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
687 			rpc_createerr.cf_error.re_errno = 0;
688 			rpc_createerr.cf_error.re_terrno = 0;
689 			goto error;
690 		}
691 		check_rpcbind = FALSE;
692 	}
693 
694 	/*
695 	 * First try version 4.
696 	 */
697 	parms.r_prog = program;
698 	parms.r_vers = version;
699 	parms.r_owner = (char *)&nullstring[0];	/* not needed; */
700 	/* just for xdring */
701 	parms.r_netid = nconf->nc_netid; /* not really needed */
702 
703 	/*
704 	 * If a COTS transport is being used, try getting address via CLTS
705 	 * transport.  This works only with version 4.
706 	 */
707 	if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
708 	    nconf->nc_semantics == NC_TPI_COTS) {
709 		tmp_client = TRUE;
710 		if ((handle = __rpc_setconf("datagram_v")) != NULL) {
711 			struct netconfig *nconf_clts;
712 
713 			while ((nconf_clts = __rpc_getconf(handle)) != NULL) {
714 				if (strcmp(nconf_clts->nc_protofmly,
715 				    nconf->nc_protofmly) != 0) {
716 					continue;
717 				}
718 				/*
719 				 * Sets rpc_createerr.cf_error members
720 				 * on failure
721 				 */
722 				client = _getclnthandle_timed(host, nconf_clts,
723 				    &parms.r_addr, tp);
724 				break;
725 			}
726 			__rpc_endconf(handle);
727 		}
728 	} else {
729 		/* Sets rpc_createerr.cf_error members on failure */
730 		client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
731 	}
732 
733 	if (client != NULL) {
734 
735 		/* Set rpcbind version 4 */
736 		vers = RPCBVERS4;
737 		CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
738 
739 		/*
740 		 * We also send the remote system the address we used to
741 		 * contact it in case it can help it connect back with us
742 		 */
743 		if (parms.r_addr == NULL) {
744 			parms.r_addr = strdup(""); /* for XDRing */
745 			if (parms.r_addr == NULL) {
746 				syslog(LOG_ERR, "__rpcb_findaddr_timed: "
747 				    "strdup failed.");
748 				/* Construct a system error */
749 				rpc_createerr.cf_error.re_errno = errno;
750 				rpc_createerr.cf_error.re_terrno = 0;
751 				rpc_createerr.cf_stat = RPC_SYSTEMERROR;
752 				goto error;
753 			}
754 		}
755 
756 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
757 		    (char *)&rpcbrmttime);
758 
759 		/* Sets error structure members in client handle */
760 		clnt_st = CLNT_CALL(client, RPCBPROC_GETADDRLIST,
761 		    (xdrproc_t)xdr_rpcb, (char *)&parms,
762 		    (xdrproc_t)xdr_rpcb_entry_list_ptr, (char *)&relp, *tp);
763 
764 		switch (clnt_st) {
765 		case RPC_SUCCESS: /* Call succeeded */
766 			address = got_entry(relp, nconf);
767 			xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
768 			    (char *)&relp);
769 			if (address != NULL) {
770 				/* Program number and version number matched */
771 				goto done;
772 			}
773 			/* Program and version not found for this transport */
774 			/*
775 			 * XXX: should have returned with RPC_PROGUNAVAIL
776 			 * or perhaps RPC_PROGNOTREGISTERED error but
777 			 * since the remote machine might not always be able
778 			 * to send the address on all transports, we try the
779 			 * regular way with version 3, then 2
780 			 */
781 			/* Try the next version */
782 			break;
783 		case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */
784 			clnt_geterr(client, &rpc_createerr.cf_error);
785 			if (rpc_createerr.cf_error.re_vers.low > vers) {
786 				rpc_createerr.cf_stat = clnt_st;
787 				goto error;  /* a new version, can't handle */
788 			}
789 			/* Try the next version */
790 			break;
791 		case RPC_PROCUNAVAIL: /* Procedure unavailable */
792 		case RPC_PROGUNAVAIL: /* Program not available */
793 		case RPC_TIMEDOUT: /* Call timed out */
794 			/* Try the next version */
795 			break;
796 		default:
797 			clnt_geterr(client, &rpc_createerr.cf_error);
798 			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
799 			goto error;
800 			break;
801 		}
802 
803 	} else {
804 
805 		/* No client */
806 		tmp_client = FALSE;
807 
808 	} /* End of version 4 */
809 
810 	/* Destroy a temporary client */
811 	if (client != NULL && tmp_client) {
812 		CLNT_DESTROY(client);
813 		client = NULL;
814 		free(parms.r_addr);
815 		parms.r_addr = NULL;
816 	}
817 	tmp_client = FALSE;
818 
819 	/*
820 	 * Try version 3
821 	 */
822 
823 	/* Now the same transport is to be used to get the address */
824 	if (client == NULL) {
825 		/* Sets rpc_createerr.cf_error members on failure */
826 		client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
827 	}
828 	address = NULL;
829 	if (client != NULL) {
830 		if (parms.r_addr == NULL) {
831 			parms.r_addr = strdup("");	/* for XDRing */
832 			if (parms.r_addr == NULL) {
833 				syslog(LOG_ERR, "__rpcb_findaddr_timed: "
834 				    "strdup failed.");
835 				/* Construct a system error */
836 				rpc_createerr.cf_error.re_errno = errno;
837 				rpc_createerr.cf_error.re_terrno = 0;
838 				rpc_createerr.cf_stat = RPC_SYSTEMERROR;
839 				goto error;
840 			}
841 		}
842 
843 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
844 		    (char *)&rpcbrmttime);
845 		vers = RPCBVERS; /* Set the version */
846 		CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
847 
848 		/* Sets error structure members in client handle */
849 		clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR,
850 		    (xdrproc_t)xdr_rpcb, (char *)&parms,
851 		    (xdrproc_t)xdr_wrapstring, (char *)&ua, *tp);
852 
853 		switch (clnt_st) {
854 		case RPC_SUCCESS: /* Call succeeded */
855 			if (ua != NULL) {
856 				if (ua[0] != '\0') {
857 					address = uaddr2taddr(nconf, ua);
858 				}
859 				xdr_free((xdrproc_t)xdr_wrapstring,
860 				    (char *)&ua);
861 
862 				if (address != NULL) {
863 					goto done;
864 				}
865 				/* NULL universal address */
866 				/* But client call was successful */
867 				clnt_geterr(client, &rpc_createerr.cf_error);
868 				rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
869 				goto error;
870 			}
871 #ifndef PORTMAP
872 			clnt_geterr(client, &rpc_createerr.cf_error);
873 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
874 			goto error;
875 #endif
876 			/* Try the next version */
877 			break;
878 		case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */
879 			clnt_geterr(client, &rpc_createerr.cf_error);
880 #ifdef PORTMAP
881 			if (rpc_createerr.cf_error.re_vers.low > vers) {
882 				rpc_createerr.cf_stat = clnt_st;
883 				goto error;  /* a new version, can't handle */
884 			}
885 #else
886 			rpc_createerr.cf_stat = clnt_st;
887 			goto error;
888 #endif
889 			/* Try the next version */
890 			break;
891 #ifdef PORTMAP
892 		case RPC_PROCUNAVAIL: /* Procedure unavailable */
893 		case RPC_PROGUNAVAIL: /* Program not available */
894 		case RPC_TIMEDOUT: /* Call timed out */
895 			/* Try the next version */
896 			break;
897 #endif
898 		default:
899 			clnt_geterr(client, &rpc_createerr.cf_error);
900 			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
901 			goto error;
902 			break;
903 		}
904 	} /* End of version 3 */
905 #ifndef PORTMAP
906 	/* cf_error members set by creation failure */
907 	rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
908 #endif
909 	/*
910 	 * Try version 2
911 	 */
912 
913 #ifdef PORTMAP
914 	/* Try version 2 for TCP or UDP */
915 	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
916 		ushort_t port = 0;
917 		struct netbuf remote;
918 		uint_t pmapvers = 2;
919 		struct pmap pmapparms;
920 
921 		/*
922 		 * Try UDP only - there are some portmappers out
923 		 * there that use UDP only.
924 		 */
925 		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
926 			struct netconfig *newnconf;
927 
928 			if (client != NULL) {
929 				CLNT_DESTROY(client);
930 				client = NULL;
931 				free(parms.r_addr);
932 				parms.r_addr = NULL;
933 			}
934 			if ((handle = __rpc_setconf("udp")) == NULL) {
935 				/* Construct an unknown protocol error */
936 				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
937 				goto error;
938 			}
939 
940 			/*
941 			 * The following to reinforce that you can
942 			 * only request for remote address through
943 			 * the same transport you are requesting.
944 			 * ie. requesting unversial address
945 			 * of IPv4 has to be carried through IPv4.
946 			 * Can't use IPv6 to send out the request.
947 			 * The mergeaddr in rpcbind can't handle
948 			 * this.
949 			 */
950 			for (;;) {
951 				if ((newnconf = __rpc_getconf(handle))
952 				    == NULL) {
953 					__rpc_endconf(handle);
954 					/*
955 					 * Construct an unknown protocol
956 					 * error
957 					 */
958 					rpc_createerr.cf_stat =
959 					    RPC_UNKNOWNPROTO;
960 					goto error;
961 				}
962 				/*
963 				 * here check the protocol family to
964 				 * be consistent with the request one
965 				 */
966 				if (strcmp(newnconf->nc_protofmly,
967 				    nconf->nc_protofmly) == 0)
968 					break;
969 			}
970 
971 			/* Sets rpc_createerr.cf_error members on failure */
972 			client = _getclnthandle_timed(host, newnconf,
973 			    &parms.r_addr, tp);
974 			__rpc_endconf(handle);
975 			tmp_client = TRUE;
976 		}
977 		if (client == NULL) {
978 			/*
979 			 * rpc_createerr. cf_error members were set by
980 			 * creation failure
981 			 */
982 			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
983 			tmp_client = FALSE;
984 			goto error;
985 		}
986 
987 		/*
988 		 * Set version and retry timeout.
989 		 */
990 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
991 		CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
992 
993 		pmapparms.pm_prog = program;
994 		pmapparms.pm_vers = version;
995 		pmapparms.pm_prot = (strcmp(nconf->nc_proto, NC_TCP) != 0) ?
996 		    IPPROTO_UDP : IPPROTO_TCP;
997 		pmapparms.pm_port = 0;	/* not needed */
998 
999 		/* Sets error structure members in client handle */
1000 		clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT,
1001 		    (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms,
1002 		    (xdrproc_t)xdr_u_short, (caddr_t)&port, *tp);
1003 
1004 		if (clnt_st != RPC_SUCCESS) {
1005 			clnt_geterr(client, &rpc_createerr.cf_error);
1006 			rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1007 			goto error;
1008 		} else if (port == 0) {
1009 			/* Will be NULL universal address */
1010 			/* But client call was successful */
1011 			clnt_geterr(client, &rpc_createerr.cf_error);
1012 			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
1013 			goto error;
1014 		}
1015 		port = htons(port);
1016 		CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
1017 		if (((address = malloc(sizeof (struct netbuf))) == NULL) ||
1018 		    ((address->buf = malloc(remote.len)) == NULL)) {
1019 			/* Construct a system error */
1020 			rpc_createerr.cf_error.re_errno = errno;
1021 			rpc_createerr.cf_error.re_terrno = 0;
1022 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1023 			free(address);
1024 			address = NULL;
1025 			goto error;
1026 		}
1027 		(void) memcpy(address->buf, remote.buf, remote.len);
1028 		(void) memcpy(&address->buf[sizeof (short)], &port,
1029 		    sizeof (short));
1030 		address->len = address->maxlen = remote.len;
1031 		goto done;
1032 	} else {
1033 		/*
1034 		 * This is not NC_INET.
1035 		 * Always an error for version 2.
1036 		 */
1037 		if (client != NULL && clnt_st != RPC_SUCCESS) {
1038 			/* There is a client that failed */
1039 			clnt_geterr(client, &rpc_createerr.cf_error);
1040 			rpc_createerr.cf_stat = clnt_st;
1041 		} else {
1042 			/* Something else */
1043 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1044 			/*
1045 			 * Setting rpc_createerr.cf_stat is sufficient.
1046 			 * No details in rpc_createerr.cf_error needed.
1047 			 */
1048 		}
1049 	}
1050 #endif
1051 
1052 error:
1053 	/* Return NULL address and NULL client */
1054 	address = NULL;
1055 	if (client != NULL) {
1056 		CLNT_DESTROY(client);
1057 		client = NULL;
1058 	}
1059 
1060 done:
1061 	/* Return an address and optional client */
1062 	if (client != NULL && tmp_client) {
1063 		/* This client is the temporary one */
1064 		CLNT_DESTROY(client);
1065 		client = NULL;
1066 	}
1067 	if (clpp != NULL) {
1068 		*clpp = client;
1069 	} else if (client != NULL) {
1070 		CLNT_DESTROY(client);
1071 	}
1072 	free(parms.r_addr);
1073 	return (address);
1074 }
1075 
1076 
1077 /*
1078  * Find the mapped address for program, version.
1079  * Calls the rpcbind service remotely to do the lookup.
1080  * Uses the transport specified in nconf.
1081  * Returns FALSE (0) if no map exists, else returns 1.
1082  *
1083  * Assuming that the address is all properly allocated
1084  */
1085 int
1086 rpcb_getaddr(const rpcprog_t program, const rpcvers_t version,
1087 	const struct netconfig *nconf, struct netbuf *address, const char *host)
1088 {
1089 	struct netbuf *na;
1090 
1091 	if ((na = __rpcb_findaddr_timed(program, version,
1092 	    (struct netconfig *)nconf, (char *)host, NULL, NULL)) == NULL)
1093 		return (FALSE);
1094 
1095 	if (na->len > address->maxlen) {
1096 		/* Too long address */
1097 		netdir_free((char *)na, ND_ADDR);
1098 		rpc_createerr.cf_stat = RPC_FAILED;
1099 		return (FALSE);
1100 	}
1101 	(void) memcpy(address->buf, na->buf, (int)na->len);
1102 	address->len = na->len;
1103 	netdir_free((char *)na, ND_ADDR);
1104 	return (TRUE);
1105 }
1106 
1107 /*
1108  * Get a copy of the current maps.
1109  * Calls the rpcbind service remotely to get the maps.
1110  *
1111  * It returns only a list of the services
1112  * It returns NULL on failure.
1113  */
1114 rpcblist *
1115 rpcb_getmaps(const struct netconfig *nconf, const char *host)
1116 {
1117 	rpcblist_ptr head = NULL;
1118 	CLIENT *client;
1119 	enum clnt_stat clnt_st;
1120 	int vers = 0;
1121 
1122 	client = getclnthandle((char *)host,
1123 	    (struct netconfig *)nconf, NULL);
1124 	if (client == NULL)
1125 		return (NULL);
1126 
1127 	clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
1128 	    (xdrproc_t)xdr_void, NULL,
1129 	    (xdrproc_t)xdr_rpcblist_ptr,
1130 	    (char *)&head, tottimeout);
1131 	if (clnt_st == RPC_SUCCESS)
1132 		goto done;
1133 
1134 	if ((clnt_st != RPC_PROGVERSMISMATCH) &&
1135 	    (clnt_st != RPC_PROGUNAVAIL)) {
1136 		rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1137 		clnt_geterr(client, &rpc_createerr.cf_error);
1138 		goto done;
1139 	}
1140 
1141 	/* fall back to earlier version */
1142 	CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
1143 	if (vers == RPCBVERS4) {
1144 		vers = RPCBVERS;
1145 		CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
1146 		if (CLNT_CALL(client, RPCBPROC_DUMP,
1147 		    (xdrproc_t)xdr_void,
1148 		    NULL, (xdrproc_t)xdr_rpcblist_ptr,
1149 		    (char *)&head, tottimeout) == RPC_SUCCESS)
1150 				goto done;
1151 	}
1152 	rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1153 	clnt_geterr(client, &rpc_createerr.cf_error);
1154 
1155 done:
1156 	CLNT_DESTROY(client);
1157 	return (head);
1158 }
1159 
1160 /*
1161  * rpcbinder remote-call-service interface.
1162  * This routine is used to call the rpcbind remote call service
1163  * which will look up a service program in the address maps, and then
1164  * remotely call that routine with the given parameters. This allows
1165  * programs to do a lookup and call in one step.
1166  */
1167 enum clnt_stat
1168 rpcb_rmtcall(const struct netconfig *nconf, const char *host,
1169 	const rpcprog_t prog, const rpcvers_t vers, const rpcproc_t proc,
1170 	const xdrproc_t xdrargs, const caddr_t argsp, const xdrproc_t xdrres,
1171 	const caddr_t resp, const struct timeval tout, struct netbuf *addr_ptr)
1172 {
1173 	CLIENT *client;
1174 	enum clnt_stat stat;
1175 	struct r_rpcb_rmtcallargs a;
1176 	struct r_rpcb_rmtcallres r;
1177 	int rpcb_vers;
1178 
1179 	client = getclnthandle((char *)host, (struct netconfig *)nconf, NULL);
1180 	if (client == NULL)
1181 		return (RPC_FAILED);
1182 	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rmttimeout);
1183 	a.prog = prog;
1184 	a.vers = vers;
1185 	a.proc = proc;
1186 	a.args.args_val = argsp;
1187 	a.xdr_args = xdrargs;
1188 	r.addr = NULL;
1189 	r.results.results_val = resp;
1190 	r.xdr_res = xdrres;
1191 
1192 	for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
1193 		CLNT_CONTROL(client, CLSET_VERS, (char *)&rpcb_vers);
1194 		stat = CLNT_CALL(client, RPCBPROC_CALLIT,
1195 		    (xdrproc_t)xdr_rpcb_rmtcallargs, (char *)&a,
1196 		    (xdrproc_t)xdr_rpcb_rmtcallres, (char *)&r, tout);
1197 		if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
1198 			struct netbuf *na;
1199 
1200 			na = uaddr2taddr((struct netconfig *)nconf, r.addr);
1201 			if (!na) {
1202 				stat = RPC_N2AXLATEFAILURE;
1203 				((struct netbuf *)addr_ptr)->len = 0;
1204 				goto error;
1205 			}
1206 			if (na->len > addr_ptr->maxlen) {
1207 				/* Too long address */
1208 				stat = RPC_FAILED; /* XXX A better error no */
1209 				netdir_free((char *)na, ND_ADDR);
1210 				((struct netbuf *)addr_ptr)->len = 0;
1211 				goto error;
1212 			}
1213 			(void) memcpy(addr_ptr->buf, na->buf, (int)na->len);
1214 			((struct netbuf *)addr_ptr)->len = na->len;
1215 			netdir_free((char *)na, ND_ADDR);
1216 			break;
1217 		}
1218 		if ((stat != RPC_PROGVERSMISMATCH) &&
1219 		    (stat != RPC_PROGUNAVAIL))
1220 			goto error;
1221 	}
1222 error:
1223 	CLNT_DESTROY(client);
1224 	if (r.addr)
1225 		xdr_free((xdrproc_t)xdr_wrapstring, (char *)&r.addr);
1226 	return (stat);
1227 }
1228 
1229 /*
1230  * Gets the time on the remote host.
1231  * Returns 1 if succeeds else 0.
1232  */
1233 bool_t
1234 rpcb_gettime(const char *host, time_t *timep)
1235 {
1236 	CLIENT *client = NULL;
1237 	void *handle;
1238 	struct netconfig *nconf;
1239 	int vers;
1240 	enum clnt_stat st;
1241 
1242 	if ((host == NULL) || (host[0] == NULL)) {
1243 		(void) time(timep);
1244 		return (TRUE);
1245 	}
1246 
1247 	if ((handle = __rpc_setconf("netpath")) == NULL) {
1248 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1249 		return (FALSE);
1250 	}
1251 	rpc_createerr.cf_stat = RPC_SUCCESS;
1252 	while (client == NULL) {
1253 		if ((nconf = __rpc_getconf(handle)) == NULL) {
1254 			if (rpc_createerr.cf_stat == RPC_SUCCESS)
1255 				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1256 			break;
1257 		}
1258 		client = getclnthandle((char *)host, nconf, NULL);
1259 		if (client)
1260 			break;
1261 	}
1262 	__rpc_endconf(handle);
1263 	if (client == NULL)
1264 		return (FALSE);
1265 
1266 	st = CLNT_CALL(client, RPCBPROC_GETTIME,
1267 	    (xdrproc_t)xdr_void, NULL,
1268 	    (xdrproc_t)xdr_time_t, (char *)timep, tottimeout);
1269 
1270 	if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
1271 		CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
1272 		if (vers == RPCBVERS4) {
1273 			/* fall back to earlier version */
1274 			vers = RPCBVERS;
1275 			CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
1276 			st = CLNT_CALL(client, RPCBPROC_GETTIME,
1277 			    (xdrproc_t)xdr_void, NULL,
1278 			    (xdrproc_t)xdr_time_t, (char *)timep,
1279 			    tottimeout);
1280 		}
1281 	}
1282 	CLNT_DESTROY(client);
1283 	return (st == RPC_SUCCESS? TRUE : FALSE);
1284 }
1285 
1286 /*
1287  * Converts taddr to universal address.  This routine should never
1288  * really be called because local n2a libraries are always provided.
1289  */
1290 char *
1291 rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
1292 {
1293 	CLIENT *client;
1294 	char *uaddr = NULL;
1295 
1296 	/* parameter checking */
1297 	if (nconf == NULL) {
1298 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1299 		return (NULL);
1300 	}
1301 	if (taddr == NULL) {
1302 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1303 		return (NULL);
1304 	}
1305 	client = local_rpcb();
1306 	if (!client)
1307 		return (NULL);
1308 
1309 	CLNT_CALL(client, RPCBPROC_TADDR2UADDR, (xdrproc_t)xdr_netbuf,
1310 	    (char *)taddr, (xdrproc_t)xdr_wrapstring, (char *)&uaddr,
1311 	    tottimeout);
1312 	CLNT_DESTROY(client);
1313 	return (uaddr);
1314 }
1315 
1316 /*
1317  * Converts universal address to netbuf.  This routine should never
1318  * really be called because local n2a libraries are always provided.
1319  */
1320 struct netbuf *
1321 rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
1322 {
1323 	CLIENT *client;
1324 	struct netbuf *taddr;
1325 
1326 	/* parameter checking */
1327 	if (nconf == NULL) {
1328 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1329 		return (NULL);
1330 	}
1331 	if (uaddr == NULL) {
1332 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1333 		return (NULL);
1334 	}
1335 	client = local_rpcb();
1336 	if (!client)
1337 		return (NULL);
1338 
1339 	taddr = calloc(1, sizeof (struct netbuf));
1340 	if (taddr == NULL) {
1341 		CLNT_DESTROY(client);
1342 		return (NULL);
1343 	}
1344 
1345 	if (CLNT_CALL(client, RPCBPROC_UADDR2TADDR, (xdrproc_t)xdr_wrapstring,
1346 	    (char *)&uaddr, (xdrproc_t)xdr_netbuf, (char *)taddr,
1347 	    tottimeout) != RPC_SUCCESS) {
1348 		free(taddr);
1349 		taddr = NULL;
1350 	}
1351 	CLNT_DESTROY(client);
1352 	return (taddr);
1353 }
1354