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