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