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