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