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