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