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