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