xref: /illumos-gate/usr/src/lib/libnsl/rpc/rpcb_clnt.c (revision 344db6f4)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
2261961e0fSrobinson 
236935f61bSMarcel Telka /*
246935f61bSMarcel Telka  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
256935f61bSMarcel Telka  */
266935f61bSMarcel Telka 
277c478bd9Sstevel@tonic-gate /*
28a9e987e0SGary Mills  * Copyright 2014 Gary Mills
29e8031f0aSraf  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
307c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
317c478bd9Sstevel@tonic-gate  */
32e8031f0aSraf 
337c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
347c478bd9Sstevel@tonic-gate /* All Rights Reserved */
357c478bd9Sstevel@tonic-gate /*
367c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley
377c478bd9Sstevel@tonic-gate  * 4.3 BSD under license from the Regents of the University of
387c478bd9Sstevel@tonic-gate  * California.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * interface to rpcbind rpc service.
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include "mt.h"
467c478bd9Sstevel@tonic-gate #include "rpc_mt.h"
477c478bd9Sstevel@tonic-gate #include <assert.h>
487c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
497c478bd9Sstevel@tonic-gate #include <rpc/rpcb_prot.h>
507c478bd9Sstevel@tonic-gate #include <netconfig.h>
517c478bd9Sstevel@tonic-gate #include <netdir.h>
52a9e987e0SGary Mills #include <netdb.h>
537c478bd9Sstevel@tonic-gate #include <rpc/nettype.h>
547c478bd9Sstevel@tonic-gate #include <syslog.h>
557c478bd9Sstevel@tonic-gate #ifdef PORTMAP
567c478bd9Sstevel@tonic-gate #include <netinet/in.h>		/* FOR IPPROTO_TCP/UDP definitions */
577c478bd9Sstevel@tonic-gate #include <rpc/pmap_prot.h>
587c478bd9Sstevel@tonic-gate #endif
597c478bd9Sstevel@tonic-gate #include <errno.h>
607c478bd9Sstevel@tonic-gate #include <stdlib.h>
617c478bd9Sstevel@tonic-gate #include <string.h>
627c478bd9Sstevel@tonic-gate #include <unistd.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static struct timeval tottimeout = { 60, 0 };
657c478bd9Sstevel@tonic-gate static const struct timeval rmttimeout = { 3, 0 };
667c478bd9Sstevel@tonic-gate static struct timeval rpcbrmttime = { 15, 0 };
677c478bd9Sstevel@tonic-gate 
6861961e0fSrobinson extern bool_t xdr_wrapstring(XDR *, char **);
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static const char nullstring[] = "\000";
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate extern CLIENT *_clnt_tli_create_timed(int, const struct netconfig *,
737c478bd9Sstevel@tonic-gate 			struct netbuf *, rpcprog_t, rpcvers_t, uint_t, uint_t,
747c478bd9Sstevel@tonic-gate 			const struct timeval *);
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static CLIENT *_getclnthandle_timed(char *, struct netconfig *, char **,
777c478bd9Sstevel@tonic-gate 			struct timeval *);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * The life time of a cached entry should not exceed 5 minutes
827c478bd9Sstevel@tonic-gate  * since automountd attempts an unmount every 5 minutes.
837c478bd9Sstevel@tonic-gate  * It is arbitrarily set a little lower (3 min = 180 sec)
847c478bd9Sstevel@tonic-gate  * to reduce the time during which an entry is stale.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate #define	CACHE_TTL 180
877c478bd9Sstevel@tonic-gate #define	CACHESIZE 6
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate struct address_cache {
907c478bd9Sstevel@tonic-gate 	char *ac_host;
917c478bd9Sstevel@tonic-gate 	char *ac_netid;
927c478bd9Sstevel@tonic-gate 	char *ac_uaddr;
937c478bd9Sstevel@tonic-gate 	struct netbuf *ac_taddr;
947c478bd9Sstevel@tonic-gate 	struct address_cache *ac_next;
957c478bd9Sstevel@tonic-gate 	time_t ac_maxtime;
967c478bd9Sstevel@tonic-gate };
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static struct address_cache *front;
997c478bd9Sstevel@tonic-gate static int cachesize;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate extern int lowvers;
1027c478bd9Sstevel@tonic-gate extern int authdes_cachesz;
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * This routine adjusts the timeout used for calls to the remote rpcbind.
1057c478bd9Sstevel@tonic-gate  * Also, this routine can be used to set the use of portmapper version 2
1067c478bd9Sstevel@tonic-gate  * only when doing rpc_broadcasts
1077c478bd9Sstevel@tonic-gate  * These are private routines that may not be provided in future releases.
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate bool_t
__rpc_control(int request,void * info)11061961e0fSrobinson __rpc_control(int request, void *info)
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate 	switch (request) {
1137c478bd9Sstevel@tonic-gate 	case CLCR_GET_RPCB_TIMEOUT:
1147c478bd9Sstevel@tonic-gate 		*(struct timeval *)info = tottimeout;
1157c478bd9Sstevel@tonic-gate 		break;
1167c478bd9Sstevel@tonic-gate 	case CLCR_SET_RPCB_TIMEOUT:
1177c478bd9Sstevel@tonic-gate 		tottimeout = *(struct timeval *)info;
1187c478bd9Sstevel@tonic-gate 		break;
1197c478bd9Sstevel@tonic-gate 	case CLCR_GET_LOWVERS:
1207c478bd9Sstevel@tonic-gate 		*(int *)info = lowvers;
1217c478bd9Sstevel@tonic-gate 		break;
1227c478bd9Sstevel@tonic-gate 	case CLCR_SET_LOWVERS:
1237c478bd9Sstevel@tonic-gate 		lowvers = *(int *)info;
1247c478bd9Sstevel@tonic-gate 		break;
1257c478bd9Sstevel@tonic-gate 	case CLCR_GET_RPCB_RMTTIME:
1267c478bd9Sstevel@tonic-gate 		*(struct timeval *)info = rpcbrmttime;
1277c478bd9Sstevel@tonic-gate 		break;
1287c478bd9Sstevel@tonic-gate 	case CLCR_SET_RPCB_RMTTIME:
1297c478bd9Sstevel@tonic-gate 		rpcbrmttime = *(struct timeval *)info;
1307c478bd9Sstevel@tonic-gate 		break;
1317c478bd9Sstevel@tonic-gate 	case CLCR_GET_CRED_CACHE_SZ:
1327c478bd9Sstevel@tonic-gate 		*(int *)info = authdes_cachesz;
1337c478bd9Sstevel@tonic-gate 		break;
1347c478bd9Sstevel@tonic-gate 	case CLCR_SET_CRED_CACHE_SZ:
1357c478bd9Sstevel@tonic-gate 		authdes_cachesz = *(int *)info;
1367c478bd9Sstevel@tonic-gate 		break;
1377c478bd9Sstevel@tonic-gate 	default:
1387c478bd9Sstevel@tonic-gate 		return (FALSE);
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 	return (TRUE);
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate  *	It might seem that a reader/writer lock would be more reasonable here.
1457c478bd9Sstevel@tonic-gate  *	However because getclnthandle(), the only user of the cache functions,
1467c478bd9Sstevel@tonic-gate  *	may do a delete_cache() operation if a check_cache() fails to return an
1477c478bd9Sstevel@tonic-gate  *	address useful to clnt_tli_create(), we may as well use a mutex.
1487c478bd9Sstevel@tonic-gate  */
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * As it turns out, if the cache lock is *not* a reader/writer lock, we will
1517c478bd9Sstevel@tonic-gate  * block all clnt_create's if we are trying to connect to a host that's down,
1527c478bd9Sstevel@tonic-gate  * since the lock will be held all during that time.
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate extern rwlock_t	rpcbaddr_cache_lock;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate  * The routines check_cache(), add_cache(), delete_cache() manage the
1587c478bd9Sstevel@tonic-gate  * cache of rpcbind addresses for (host, netid).
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static struct address_cache *
check_cache(char * host,char * netid)16261961e0fSrobinson check_cache(char *host, char *netid)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 	struct address_cache *cptr;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	assert(RW_READ_HELD(&rpcbaddr_cache_lock));
1697c478bd9Sstevel@tonic-gate 	for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
1707c478bd9Sstevel@tonic-gate 		if ((strcmp(cptr->ac_host, host) == 0) &&
1717c478bd9Sstevel@tonic-gate 		    (strcmp(cptr->ac_netid, netid) == 0) &&
172a9e987e0SGary Mills 		    (time(NULL) <= cptr->ac_maxtime)) {
1737c478bd9Sstevel@tonic-gate 			return (cptr);
1747c478bd9Sstevel@tonic-gate 		}
1757c478bd9Sstevel@tonic-gate 	}
17661961e0fSrobinson 	return (NULL);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate static void
delete_cache(struct netbuf * addr)18061961e0fSrobinson delete_cache(struct netbuf *addr)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate 	struct address_cache *cptr, *prevptr = NULL;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	/* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
1857c478bd9Sstevel@tonic-gate 	assert(RW_WRITE_HELD(&rpcbaddr_cache_lock));
1867c478bd9Sstevel@tonic-gate 	for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
1877c478bd9Sstevel@tonic-gate 		if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
1887c478bd9Sstevel@tonic-gate 			free(cptr->ac_host);
1897c478bd9Sstevel@tonic-gate 			free(cptr->ac_netid);
1907c478bd9Sstevel@tonic-gate 			free(cptr->ac_taddr->buf);
1917c478bd9Sstevel@tonic-gate 			free(cptr->ac_taddr);
1927c478bd9Sstevel@tonic-gate 			if (cptr->ac_uaddr)
1937c478bd9Sstevel@tonic-gate 				free(cptr->ac_uaddr);
1947c478bd9Sstevel@tonic-gate 			if (prevptr)
1957c478bd9Sstevel@tonic-gate 				prevptr->ac_next = cptr->ac_next;
1967c478bd9Sstevel@tonic-gate 			else
1977c478bd9Sstevel@tonic-gate 				front = cptr->ac_next;
1987c478bd9Sstevel@tonic-gate 			free(cptr);
1997c478bd9Sstevel@tonic-gate 			cachesize--;
2007c478bd9Sstevel@tonic-gate 			break;
2017c478bd9Sstevel@tonic-gate 		}
2027c478bd9Sstevel@tonic-gate 		prevptr = cptr;
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate static void
add_cache(char * host,char * netid,struct netbuf * taddr,char * uaddr)20761961e0fSrobinson add_cache(char *host, char *netid, struct netbuf *taddr, char *uaddr)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	struct address_cache  *ad_cache, *cptr, *prevptr;
2107c478bd9Sstevel@tonic-gate 
21161961e0fSrobinson 	ad_cache = malloc(sizeof (struct address_cache));
2127c478bd9Sstevel@tonic-gate 	if (!ad_cache) {
2137c478bd9Sstevel@tonic-gate 		goto memerr;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 	ad_cache->ac_maxtime = time(NULL) + CACHE_TTL;
2167c478bd9Sstevel@tonic-gate 	ad_cache->ac_host = strdup(host);
2177c478bd9Sstevel@tonic-gate 	ad_cache->ac_netid = strdup(netid);
2187c478bd9Sstevel@tonic-gate 	ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
21961961e0fSrobinson 	ad_cache->ac_taddr = malloc(sizeof (struct netbuf));
2207c478bd9Sstevel@tonic-gate 	if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
221a9e987e0SGary Mills 	    (uaddr && !ad_cache->ac_uaddr)) {
2227c478bd9Sstevel@tonic-gate 		goto memerr1;
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
22661961e0fSrobinson 	ad_cache->ac_taddr->buf = malloc(taddr->len);
2277c478bd9Sstevel@tonic-gate 	if (ad_cache->ac_taddr->buf == NULL) {
2287c478bd9Sstevel@tonic-gate 		goto memerr1;
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 
23161961e0fSrobinson 	(void) memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY rpcbaddr_cache_lock:  cptr */
2347c478bd9Sstevel@tonic-gate 
23561961e0fSrobinson 	(void) rw_wrlock(&rpcbaddr_cache_lock);
2367c478bd9Sstevel@tonic-gate 	if (cachesize < CACHESIZE) {
2377c478bd9Sstevel@tonic-gate 		ad_cache->ac_next = front;
2387c478bd9Sstevel@tonic-gate 		front = ad_cache;
2397c478bd9Sstevel@tonic-gate 		cachesize++;
2407c478bd9Sstevel@tonic-gate 	} else {
2417c478bd9Sstevel@tonic-gate 		/* Free the last entry */
2427c478bd9Sstevel@tonic-gate 		cptr = front;
2437c478bd9Sstevel@tonic-gate 		prevptr = NULL;
2447c478bd9Sstevel@tonic-gate 		while (cptr->ac_next) {
2457c478bd9Sstevel@tonic-gate 			prevptr = cptr;
2467c478bd9Sstevel@tonic-gate 			cptr = cptr->ac_next;
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		free(cptr->ac_host);
2507c478bd9Sstevel@tonic-gate 		free(cptr->ac_netid);
2517c478bd9Sstevel@tonic-gate 		free(cptr->ac_taddr->buf);
2527c478bd9Sstevel@tonic-gate 		free(cptr->ac_taddr);
2537c478bd9Sstevel@tonic-gate 		if (cptr->ac_uaddr)
2547c478bd9Sstevel@tonic-gate 			free(cptr->ac_uaddr);
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		if (prevptr) {
2577c478bd9Sstevel@tonic-gate 			prevptr->ac_next = NULL;
2587c478bd9Sstevel@tonic-gate 			ad_cache->ac_next = front;
2597c478bd9Sstevel@tonic-gate 			front = ad_cache;
2607c478bd9Sstevel@tonic-gate 		} else {
2617c478bd9Sstevel@tonic-gate 			front = ad_cache;
2627c478bd9Sstevel@tonic-gate 			ad_cache->ac_next = NULL;
2637c478bd9Sstevel@tonic-gate 		}
2647c478bd9Sstevel@tonic-gate 		free(cptr);
2657c478bd9Sstevel@tonic-gate 	}
26661961e0fSrobinson 	(void) rw_unlock(&rpcbaddr_cache_lock);
2677c478bd9Sstevel@tonic-gate 	return;
2687c478bd9Sstevel@tonic-gate memerr1:
2697c478bd9Sstevel@tonic-gate 	if (ad_cache->ac_host)
2707c478bd9Sstevel@tonic-gate 		free(ad_cache->ac_host);
2717c478bd9Sstevel@tonic-gate 	if (ad_cache->ac_netid)
2727c478bd9Sstevel@tonic-gate 		free(ad_cache->ac_netid);
2737c478bd9Sstevel@tonic-gate 	if (ad_cache->ac_uaddr)
2747c478bd9Sstevel@tonic-gate 		free(ad_cache->ac_uaddr);
2757c478bd9Sstevel@tonic-gate 	if (ad_cache->ac_taddr)
2767c478bd9Sstevel@tonic-gate 		free(ad_cache->ac_taddr);
2777c478bd9Sstevel@tonic-gate 	free(ad_cache);
2787c478bd9Sstevel@tonic-gate memerr:
2797c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "add_cache : out of memory.");
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate  * This routine will return a client handle that is connected to the
2847c478bd9Sstevel@tonic-gate  * rpcbind. Returns NULL on error and free's everything.
2857c478bd9Sstevel@tonic-gate  */
2867c478bd9Sstevel@tonic-gate static CLIENT *
getclnthandle(char * host,struct netconfig * nconf,char ** targaddr)28761961e0fSrobinson getclnthandle(char *host, struct netconfig *nconf, char **targaddr)
2887c478bd9Sstevel@tonic-gate {
2897c478bd9Sstevel@tonic-gate 	return (_getclnthandle_timed(host, nconf, targaddr, NULL));
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate  * Same as getclnthandle() except it takes an extra timeout argument.
2947c478bd9Sstevel@tonic-gate  * This is for bug 4049792: clnt_create_timed does not timeout.
2957c478bd9Sstevel@tonic-gate  *
2967c478bd9Sstevel@tonic-gate  * If tp is NULL, use default timeout to get a client handle.
2977c478bd9Sstevel@tonic-gate  */
2987c478bd9Sstevel@tonic-gate static CLIENT *
_getclnthandle_timed(char * host,struct netconfig * nconf,char ** targaddr,struct timeval * tp)29961961e0fSrobinson _getclnthandle_timed(char *host, struct netconfig *nconf, char **targaddr,
30061961e0fSrobinson 							struct timeval *tp)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	CLIENT *client = NULL;
3037c478bd9Sstevel@tonic-gate 	struct netbuf *addr;
3047c478bd9Sstevel@tonic-gate 	struct netbuf addr_to_delete;
3057c478bd9Sstevel@tonic-gate 	struct nd_addrlist *nas;
3067c478bd9Sstevel@tonic-gate 	struct nd_hostserv rpcbind_hs;
3077c478bd9Sstevel@tonic-gate 	struct address_cache *ad_cache;
3087c478bd9Sstevel@tonic-gate 	char *tmpaddr;
3097c478bd9Sstevel@tonic-gate 	int neterr;
3107c478bd9Sstevel@tonic-gate 	int j;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY rpcbaddr_cache_lock:  ad_cache */
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/* Get the address of the rpcbind.  Check cache first */
3157c478bd9Sstevel@tonic-gate 	addr_to_delete.len = 0;
31661961e0fSrobinson 	(void) rw_rdlock(&rpcbaddr_cache_lock);
3177c478bd9Sstevel@tonic-gate 	ad_cache = check_cache(host, nconf->nc_netid);
3187c478bd9Sstevel@tonic-gate 	if (ad_cache != NULL) {
3197c478bd9Sstevel@tonic-gate 		addr = ad_cache->ac_taddr;
3207c478bd9Sstevel@tonic-gate 		client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr,
321a9e987e0SGary Mills 		    RPCBPROG, RPCBVERS4, 0, 0, tp);
3227c478bd9Sstevel@tonic-gate 		if (client != NULL) {
3237c478bd9Sstevel@tonic-gate 			if (targaddr) {
3247c478bd9Sstevel@tonic-gate 				/*
3257c478bd9Sstevel@tonic-gate 				 * case where a client handle is created
3267c478bd9Sstevel@tonic-gate 				 * without a targaddr and the handle is
3277c478bd9Sstevel@tonic-gate 				 * requested with a targaddr
3287c478bd9Sstevel@tonic-gate 				 */
3297c478bd9Sstevel@tonic-gate 				if (ad_cache->ac_uaddr != NULL) {
3307c478bd9Sstevel@tonic-gate 					*targaddr = strdup(ad_cache->ac_uaddr);
3317c478bd9Sstevel@tonic-gate 					if (*targaddr == NULL) {
3327c478bd9Sstevel@tonic-gate 						syslog(LOG_ERR,
3337c478bd9Sstevel@tonic-gate 						"_getclnthandle_timed: strdup "
3347c478bd9Sstevel@tonic-gate 						"failed.");
3357c478bd9Sstevel@tonic-gate 						rpc_createerr.cf_stat =
336a9e987e0SGary Mills 						    RPC_SYSTEMERROR;
33761961e0fSrobinson 						(void) rw_unlock(
338a9e987e0SGary Mills 						    &rpcbaddr_cache_lock);
33961961e0fSrobinson 						return (NULL);
3407c478bd9Sstevel@tonic-gate 					}
34161961e0fSrobinson 				} else {
3427c478bd9Sstevel@tonic-gate 					*targaddr = NULL;
34361961e0fSrobinson 				}
3447c478bd9Sstevel@tonic-gate 			}
34561961e0fSrobinson 			(void) rw_unlock(&rpcbaddr_cache_lock);
3467c478bd9Sstevel@tonic-gate 			return (client);
34761961e0fSrobinson 		}
34861961e0fSrobinson 		if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) {
34961961e0fSrobinson 			(void) rw_unlock(&rpcbaddr_cache_lock);
35061961e0fSrobinson 			return (NULL);
3517c478bd9Sstevel@tonic-gate 		}
3527c478bd9Sstevel@tonic-gate 		addr_to_delete.len = addr->len;
35361961e0fSrobinson 		addr_to_delete.buf = malloc(addr->len);
3547c478bd9Sstevel@tonic-gate 		if (addr_to_delete.buf == NULL) {
3557c478bd9Sstevel@tonic-gate 			addr_to_delete.len = 0;
3567c478bd9Sstevel@tonic-gate 		} else {
35761961e0fSrobinson 			(void) memcpy(addr_to_delete.buf, addr->buf, addr->len);
3587c478bd9Sstevel@tonic-gate 		}
3597c478bd9Sstevel@tonic-gate 	}
36061961e0fSrobinson 	(void) rw_unlock(&rpcbaddr_cache_lock);
3617c478bd9Sstevel@tonic-gate 	if (addr_to_delete.len != 0) {
3627c478bd9Sstevel@tonic-gate 		/*
3637c478bd9Sstevel@tonic-gate 		 * Assume this may be due to cache data being
3647c478bd9Sstevel@tonic-gate 		 *  outdated
3657c478bd9Sstevel@tonic-gate 		 */
36661961e0fSrobinson 		(void) rw_wrlock(&rpcbaddr_cache_lock);
3677c478bd9Sstevel@tonic-gate 		delete_cache(&addr_to_delete);
36861961e0fSrobinson 		(void) rw_unlock(&rpcbaddr_cache_lock);
3697c478bd9Sstevel@tonic-gate 		free(addr_to_delete.buf);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 	rpcbind_hs.h_host = host;
3727c478bd9Sstevel@tonic-gate 	rpcbind_hs.h_serv = "rpcbind";
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	if ((neterr = netdir_getbyname(nconf, &rpcbind_hs, &nas)) != 0) {
3757c478bd9Sstevel@tonic-gate 		if (neterr == ND_NOHOST)
3767c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
3777c478bd9Sstevel@tonic-gate 		else
3787c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
37961961e0fSrobinson 		return (NULL);
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 	/* XXX nas should perhaps be cached for better performance */
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	for (j = 0; j < nas->n_cnt; j++) {
3847c478bd9Sstevel@tonic-gate 		addr = &(nas->n_addrs[j]);
3857c478bd9Sstevel@tonic-gate 	client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr, RPCBPROG,
386a9e987e0SGary Mills 	    RPCBVERS4, 0, 0, tp);
3877c478bd9Sstevel@tonic-gate 	if (client)
3887c478bd9Sstevel@tonic-gate 		break;
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	if (client) {
3927c478bd9Sstevel@tonic-gate 		tmpaddr = targaddr ? taddr2uaddr(nconf, addr) : NULL;
3937c478bd9Sstevel@tonic-gate 		add_cache(host, nconf->nc_netid, addr, tmpaddr);
3947c478bd9Sstevel@tonic-gate 		if (targaddr) {
3957c478bd9Sstevel@tonic-gate 			*targaddr = tmpaddr;
3967c478bd9Sstevel@tonic-gate 		}
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 	netdir_free((char *)nas, ND_ADDRLIST);
3997c478bd9Sstevel@tonic-gate 	return (client);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate  * This routine will return a client handle that is connected to the local
404a9e987e0SGary Mills  * rpcbind. Returns NULL on error.
4057c478bd9Sstevel@tonic-gate  */
4067c478bd9Sstevel@tonic-gate static CLIENT *
local_rpcb(void)40761961e0fSrobinson local_rpcb(void)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 	static struct netconfig *loopnconf;
4107c478bd9Sstevel@tonic-gate 	extern mutex_t loopnconf_lock;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
41361961e0fSrobinson 	(void) mutex_lock(&loopnconf_lock);
4147c478bd9Sstevel@tonic-gate 	if (loopnconf == NULL) {
4157c478bd9Sstevel@tonic-gate 		struct netconfig *nconf, *tmpnconf = NULL;
4167c478bd9Sstevel@tonic-gate 		void *nc_handle;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 		nc_handle = setnetconfig();
4197c478bd9Sstevel@tonic-gate 		if (nc_handle == NULL) {
4207c478bd9Sstevel@tonic-gate 			/* fails to open netconfig file */
4217c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
42261961e0fSrobinson 			(void) mutex_unlock(&loopnconf_lock);
4237c478bd9Sstevel@tonic-gate 			return (NULL);
4247c478bd9Sstevel@tonic-gate 		}
4257c478bd9Sstevel@tonic-gate 		while (nconf = getnetconfig(nc_handle)) {
4267c478bd9Sstevel@tonic-gate 			if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
4277c478bd9Sstevel@tonic-gate 				tmpnconf = nconf;
4287c478bd9Sstevel@tonic-gate 				if (nconf->nc_semantics == NC_TPI_CLTS)
4297c478bd9Sstevel@tonic-gate 					break;
4307c478bd9Sstevel@tonic-gate 			}
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 		if (tmpnconf == NULL) {
4337c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
43461961e0fSrobinson 			(void) mutex_unlock(&loopnconf_lock);
4357c478bd9Sstevel@tonic-gate 			return (NULL);
4367c478bd9Sstevel@tonic-gate 		}
4377c478bd9Sstevel@tonic-gate 		loopnconf = getnetconfigent(tmpnconf->nc_netid);
4387c478bd9Sstevel@tonic-gate 		/* loopnconf is never freed */
43961961e0fSrobinson 		(void) endnetconfig(nc_handle);
4407c478bd9Sstevel@tonic-gate 	}
44161961e0fSrobinson 	(void) mutex_unlock(&loopnconf_lock);
4426935f61bSMarcel Telka 	return (getclnthandle(HOST_SELF_CONNECT, loopnconf, NULL));
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate /*
4467c478bd9Sstevel@tonic-gate  * Set a mapping between program, version and address.
4477c478bd9Sstevel@tonic-gate  * Calls the rpcbind service to do the mapping.
4487c478bd9Sstevel@tonic-gate  */
4497c478bd9Sstevel@tonic-gate bool_t
rpcb_set(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf,const struct netbuf * address)45061961e0fSrobinson rpcb_set(const rpcprog_t program, const rpcvers_t version,
45161961e0fSrobinson 		const struct netconfig *nconf, const struct netbuf *address)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	CLIENT *client;
4547c478bd9Sstevel@tonic-gate 	bool_t rslt = FALSE;
4557c478bd9Sstevel@tonic-gate 	RPCB parms;
4567c478bd9Sstevel@tonic-gate 	char uidbuf[32];
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	/* parameter checking */
45961961e0fSrobinson 	if (nconf == NULL) {
4607c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
4617c478bd9Sstevel@tonic-gate 		return (FALSE);
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 	if (address == NULL) {
4647c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
4657c478bd9Sstevel@tonic-gate 		return (FALSE);
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 	client = local_rpcb();
46861961e0fSrobinson 	if (!client)
4697c478bd9Sstevel@tonic-gate 		return (FALSE);
4707c478bd9Sstevel@tonic-gate 
47161961e0fSrobinson 	parms.r_addr = taddr2uaddr((struct netconfig *)nconf,
472a9e987e0SGary Mills 	    (struct netbuf *)address); /* convert to universal */
4737c478bd9Sstevel@tonic-gate 	if (!parms.r_addr) {
4747c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
4757c478bd9Sstevel@tonic-gate 		return (FALSE); /* no universal address */
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 	parms.r_prog = program;
4787c478bd9Sstevel@tonic-gate 	parms.r_vers = version;
4797c478bd9Sstevel@tonic-gate 	parms.r_netid = nconf->nc_netid;
4807c478bd9Sstevel@tonic-gate 	/*
4817c478bd9Sstevel@tonic-gate 	 * Though uid is not being used directly, we still send it for
4827c478bd9Sstevel@tonic-gate 	 * completeness.  For non-unix platforms, perhaps some other
4837c478bd9Sstevel@tonic-gate 	 * string or an empty string can be sent.
4847c478bd9Sstevel@tonic-gate 	 */
48561961e0fSrobinson 	(void) sprintf(uidbuf, "%d", (int)geteuid());
4867c478bd9Sstevel@tonic-gate 	parms.r_owner = uidbuf;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	CLNT_CALL(client, RPCBPROC_SET, (xdrproc_t)xdr_rpcb, (char *)&parms,
489a9e987e0SGary Mills 	    (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	CLNT_DESTROY(client);
4927c478bd9Sstevel@tonic-gate 	free(parms.r_addr);
4937c478bd9Sstevel@tonic-gate 	return (rslt);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate  * Remove the mapping between program, version and netbuf address.
4987c478bd9Sstevel@tonic-gate  * Calls the rpcbind service to do the un-mapping.
4997c478bd9Sstevel@tonic-gate  * If netbuf is NULL, unset for all the transports, otherwise unset
5007c478bd9Sstevel@tonic-gate  * only for the given transport.
5017c478bd9Sstevel@tonic-gate  */
5027c478bd9Sstevel@tonic-gate bool_t
rpcb_unset(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf)50361961e0fSrobinson rpcb_unset(const rpcprog_t program, const rpcvers_t version,
50461961e0fSrobinson 						const struct netconfig *nconf)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	CLIENT *client;
5077c478bd9Sstevel@tonic-gate 	bool_t rslt = FALSE;
5087c478bd9Sstevel@tonic-gate 	RPCB parms;
5097c478bd9Sstevel@tonic-gate 	char uidbuf[32];
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	client = local_rpcb();
51261961e0fSrobinson 	if (!client)
5137c478bd9Sstevel@tonic-gate 		return (FALSE);
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	parms.r_prog = program;
5167c478bd9Sstevel@tonic-gate 	parms.r_vers = version;
5177c478bd9Sstevel@tonic-gate 	if (nconf)
5187c478bd9Sstevel@tonic-gate 		parms.r_netid = nconf->nc_netid;
5197c478bd9Sstevel@tonic-gate 	else
5207c478bd9Sstevel@tonic-gate 		parms.r_netid = (char *)&nullstring[0]; /* unsets  all */
5217c478bd9Sstevel@tonic-gate 	parms.r_addr = (char *)&nullstring[0];
52261961e0fSrobinson 	(void) sprintf(uidbuf, "%d", (int)geteuid());
5237c478bd9Sstevel@tonic-gate 	parms.r_owner = uidbuf;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	CLNT_CALL(client, RPCBPROC_UNSET, (xdrproc_t)xdr_rpcb, (char *)&parms,
526a9e987e0SGary Mills 	    (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	CLNT_DESTROY(client);
5297c478bd9Sstevel@tonic-gate 	return (rslt);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate /*
5337c478bd9Sstevel@tonic-gate  * From the merged list, find the appropriate entry
5347c478bd9Sstevel@tonic-gate  */
5357c478bd9Sstevel@tonic-gate static struct netbuf *
got_entry(rpcb_entry_list_ptr relp,struct netconfig * nconf)53661961e0fSrobinson got_entry(rpcb_entry_list_ptr relp, struct netconfig *nconf)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	struct netbuf *na = NULL;
5397c478bd9Sstevel@tonic-gate 	rpcb_entry_list_ptr sp;
5407c478bd9Sstevel@tonic-gate 	rpcb_entry *rmap;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
5437c478bd9Sstevel@tonic-gate 		rmap = &sp->rpcb_entry_map;
5447c478bd9Sstevel@tonic-gate 		if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
5457c478bd9Sstevel@tonic-gate 		    (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
5467c478bd9Sstevel@tonic-gate 		    (nconf->nc_semantics == rmap->r_nc_semantics) &&
547*344db6f4SToomas Soome 		    (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) {
5487c478bd9Sstevel@tonic-gate 			na = uaddr2taddr(nconf, rmap->r_maddr);
5497c478bd9Sstevel@tonic-gate 			break;
5507c478bd9Sstevel@tonic-gate 		}
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 	return (na);
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate /*
5567c478bd9Sstevel@tonic-gate  * Quick check to see if rpcbind is up.  Tries to connect over
5577c478bd9Sstevel@tonic-gate  * local transport.
5587c478bd9Sstevel@tonic-gate  */
5597c478bd9Sstevel@tonic-gate bool_t
__rpcbind_is_up(void)56061961e0fSrobinson __rpcbind_is_up(void)
5617c478bd9Sstevel@tonic-gate {
5627c478bd9Sstevel@tonic-gate 	struct netbuf *addr;
5637c478bd9Sstevel@tonic-gate 	int fd;
5647c478bd9Sstevel@tonic-gate 	struct t_call *sndcall;
5657c478bd9Sstevel@tonic-gate 	struct netconfig *netconf;
5667c478bd9Sstevel@tonic-gate 	bool_t res;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	if ((fd = t_open("/dev/ticotsord", O_RDWR, NULL)) == -1)
5697c478bd9Sstevel@tonic-gate 		return (TRUE);
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if (t_bind(fd, NULL, NULL) == -1) {
57261961e0fSrobinson 		(void) t_close(fd);
5737c478bd9Sstevel@tonic-gate 		return (TRUE);
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 
57661961e0fSrobinson 	/* LINTED pointer cast */
5777c478bd9Sstevel@tonic-gate 	if ((sndcall = (struct t_call *)t_alloc(fd, T_CALL, 0)) == NULL) {
57861961e0fSrobinson 		(void) t_close(fd);
5797c478bd9Sstevel@tonic-gate 		return (TRUE);
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	if ((netconf = getnetconfigent("ticotsord")) == NULL) {
58361961e0fSrobinson 		(void) t_free((char *)sndcall, T_CALL);
58461961e0fSrobinson 		(void) t_close(fd);
5857c478bd9Sstevel@tonic-gate 		return (FALSE);
5867c478bd9Sstevel@tonic-gate 	}
5876935f61bSMarcel Telka 	addr = uaddr2taddr(netconf, "localhost.rpc");
5887c478bd9Sstevel@tonic-gate 	freenetconfigent(netconf);
5897c478bd9Sstevel@tonic-gate 	if (addr == NULL || addr->buf == NULL) {
5907c478bd9Sstevel@tonic-gate 		if (addr)
59161961e0fSrobinson 			free(addr);
59261961e0fSrobinson 		(void) t_free((char *)sndcall, T_CALL);
59361961e0fSrobinson 		(void) t_close(fd);
5947c478bd9Sstevel@tonic-gate 		return (FALSE);
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 	sndcall->addr.maxlen = addr->maxlen;
5977c478bd9Sstevel@tonic-gate 	sndcall->addr.len = addr->len;
5987c478bd9Sstevel@tonic-gate 	sndcall->addr.buf = addr->buf;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	if (t_connect(fd, sndcall, NULL) == -1)
6017c478bd9Sstevel@tonic-gate 		res = FALSE;
6027c478bd9Sstevel@tonic-gate 	else
6037c478bd9Sstevel@tonic-gate 		res = TRUE;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	sndcall->addr.maxlen = sndcall->addr.len = 0;
6067c478bd9Sstevel@tonic-gate 	sndcall->addr.buf = NULL;
60761961e0fSrobinson 	(void) t_free((char *)sndcall, T_CALL);
60861961e0fSrobinson 	free(addr->buf);
60961961e0fSrobinson 	free(addr);
61061961e0fSrobinson 	(void) t_close(fd);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	return (res);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate /*
617a9e987e0SGary Mills  * An internal function which optimizes rpcb_getaddr function.  It returns
618a9e987e0SGary Mills  * the universal address of the remote service or NULL.  It also optionally
6197c478bd9Sstevel@tonic-gate  * returns the client handle that it uses to contact the remote rpcbind.
620a9e987e0SGary Mills  * The caller will re-purpose the client handle to contact the remote service.
6217c478bd9Sstevel@tonic-gate  *
622a9e987e0SGary Mills  * The algorithm used: First try version 4.  Then try version 3 (svr4).
623a9e987e0SGary Mills  * Finally, if the transport is TCP or UDP, try version 2 (portmap).
624a9e987e0SGary Mills  * Version 4 is now available with all current systems on the network.
6257c478bd9Sstevel@tonic-gate  * With this algorithm, we get performance as well as a plan for
6267c478bd9Sstevel@tonic-gate  * obsoleting version 2.
6277c478bd9Sstevel@tonic-gate  *
6287c478bd9Sstevel@tonic-gate  * XXX: Due to some problems with t_connect(), we do not reuse the same client
6297c478bd9Sstevel@tonic-gate  * handle for COTS cases and hence in these cases we do not return the
6307c478bd9Sstevel@tonic-gate  * client handle.  This code will change if t_connect() ever
6317c478bd9Sstevel@tonic-gate  * starts working properly.  Also look under clnt_vc.c.
6327c478bd9Sstevel@tonic-gate  */
6337c478bd9Sstevel@tonic-gate struct netbuf *
__rpcb_findaddr_timed(rpcprog_t program,rpcvers_t version,struct netconfig * nconf,char * host,CLIENT ** clpp,struct timeval * tp)63461961e0fSrobinson __rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version,
63561961e0fSrobinson 	struct netconfig *nconf, char *host, CLIENT **clpp, struct timeval *tp)
6367c478bd9Sstevel@tonic-gate {
6377c478bd9Sstevel@tonic-gate 	static bool_t check_rpcbind = TRUE;
6387c478bd9Sstevel@tonic-gate 	CLIENT *client = NULL;
6397c478bd9Sstevel@tonic-gate 	RPCB parms;
6407c478bd9Sstevel@tonic-gate 	enum clnt_stat clnt_st;
6417c478bd9Sstevel@tonic-gate 	char *ua = NULL;
6427c478bd9Sstevel@tonic-gate 	uint_t vers;
6437c478bd9Sstevel@tonic-gate 	struct netbuf *address = NULL;
644a9e987e0SGary Mills 	void *handle;
645a9e987e0SGary Mills 	rpcb_entry_list_ptr relp = NULL;
646a9e987e0SGary Mills 	bool_t tmp_client = FALSE;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	/* parameter checking */
64961961e0fSrobinson 	if (nconf == NULL) {
6507c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
651a9e987e0SGary Mills 		/*
652a9e987e0SGary Mills 		 * Setting rpc_createerr.cf_stat is sufficient.
653a9e987e0SGary Mills 		 * No details in rpc_createerr.cf_error needed.
654a9e987e0SGary Mills 		 */
6557c478bd9Sstevel@tonic-gate 		return (NULL);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	parms.r_addr = NULL;
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	/*
6617c478bd9Sstevel@tonic-gate 	 * Use default total timeout if no timeout is specified.
6627c478bd9Sstevel@tonic-gate 	 */
6637c478bd9Sstevel@tonic-gate 	if (tp == NULL)
6647c478bd9Sstevel@tonic-gate 		tp = &tottimeout;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	/*
6677c478bd9Sstevel@tonic-gate 	 * Check if rpcbind is up.  This prevents needless delays when
6687c478bd9Sstevel@tonic-gate 	 * accessing applications such as the keyserver while booting
6697c478bd9Sstevel@tonic-gate 	 * disklessly.
6707c478bd9Sstevel@tonic-gate 	 */
6717c478bd9Sstevel@tonic-gate 	if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
6727c478bd9Sstevel@tonic-gate 		if (!__rpcbind_is_up()) {
6737c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
6747c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_error.re_errno = 0;
6757c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_error.re_terrno = 0;
6767c478bd9Sstevel@tonic-gate 			goto error;
6777c478bd9Sstevel@tonic-gate 		}
6787c478bd9Sstevel@tonic-gate 		check_rpcbind = FALSE;
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	/*
682a9e987e0SGary Mills 	 * First try version 4.
6837c478bd9Sstevel@tonic-gate 	 */
6847c478bd9Sstevel@tonic-gate 	parms.r_prog = program;
6857c478bd9Sstevel@tonic-gate 	parms.r_vers = version;
6867c478bd9Sstevel@tonic-gate 	parms.r_owner = (char *)&nullstring[0];	/* not needed; */
6877c478bd9Sstevel@tonic-gate 	/* just for xdring */
6887c478bd9Sstevel@tonic-gate 	parms.r_netid = nconf->nc_netid; /* not really needed */
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	/*
6917c478bd9Sstevel@tonic-gate 	 * If a COTS transport is being used, try getting address via CLTS
6927c478bd9Sstevel@tonic-gate 	 * transport.  This works only with version 4.
6937c478bd9Sstevel@tonic-gate 	 */
6947c478bd9Sstevel@tonic-gate 	if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
6957c478bd9Sstevel@tonic-gate 	    nconf->nc_semantics == NC_TPI_COTS) {
696a9e987e0SGary Mills 		tmp_client = TRUE;
697a9e987e0SGary Mills 		if ((handle = __rpc_setconf("datagram_v")) != NULL) {
698a9e987e0SGary Mills 			struct netconfig *nconf_clts;
699a9e987e0SGary Mills 
700a9e987e0SGary Mills 			while ((nconf_clts = __rpc_getconf(handle)) != NULL) {
701a9e987e0SGary Mills 				if (strcmp(nconf_clts->nc_protofmly,
702a9e987e0SGary Mills 				    nconf->nc_protofmly) != 0) {
703a9e987e0SGary Mills 					continue;
7047c478bd9Sstevel@tonic-gate 				}
705a9e987e0SGary Mills 				/*
706a9e987e0SGary Mills 				 * Sets rpc_createerr.cf_error members
707a9e987e0SGary Mills 				 * on failure
708a9e987e0SGary Mills 				 */
709a9e987e0SGary Mills 				client = _getclnthandle_timed(host, nconf_clts,
710a9e987e0SGary Mills 				    &parms.r_addr, tp);
711a9e987e0SGary Mills 				break;
7127c478bd9Sstevel@tonic-gate 			}
713a9e987e0SGary Mills 			__rpc_endconf(handle);
7147c478bd9Sstevel@tonic-gate 		}
715a9e987e0SGary Mills 	} else {
716a9e987e0SGary Mills 		/* Sets rpc_createerr.cf_error members on failure */
717a9e987e0SGary Mills 		client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
718a9e987e0SGary Mills 	}
719a9e987e0SGary Mills 
720a9e987e0SGary Mills 	if (client != NULL) {
721a9e987e0SGary Mills 
722a9e987e0SGary Mills 		/* Set rpcbind version 4 */
723a9e987e0SGary Mills 		vers = RPCBVERS4;
724a9e987e0SGary Mills 		CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
725a9e987e0SGary Mills 
7267c478bd9Sstevel@tonic-gate 		/*
7277c478bd9Sstevel@tonic-gate 		 * We also send the remote system the address we used to
7287c478bd9Sstevel@tonic-gate 		 * contact it in case it can help it connect back with us
7297c478bd9Sstevel@tonic-gate 		 */
7307c478bd9Sstevel@tonic-gate 		if (parms.r_addr == NULL) {
7317c478bd9Sstevel@tonic-gate 			parms.r_addr = strdup(""); /* for XDRing */
7327c478bd9Sstevel@tonic-gate 			if (parms.r_addr == NULL) {
7337c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "__rpcb_findaddr_timed: "
734a9e987e0SGary Mills 				    "strdup failed.");
735a9e987e0SGary Mills 				/* Construct a system error */
736a9e987e0SGary Mills 				rpc_createerr.cf_error.re_errno = errno;
737a9e987e0SGary Mills 				rpc_createerr.cf_error.re_terrno = 0;
7387c478bd9Sstevel@tonic-gate 				rpc_createerr.cf_stat = RPC_SYSTEMERROR;
7397c478bd9Sstevel@tonic-gate 				goto error;
7407c478bd9Sstevel@tonic-gate 			}
7417c478bd9Sstevel@tonic-gate 		}
7427c478bd9Sstevel@tonic-gate 
743a9e987e0SGary Mills 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
744a9e987e0SGary Mills 		    (char *)&rpcbrmttime);
7457c478bd9Sstevel@tonic-gate 
746a9e987e0SGary Mills 		/* Sets error structure members in client handle */
7477c478bd9Sstevel@tonic-gate 		clnt_st = CLNT_CALL(client, RPCBPROC_GETADDRLIST,
748a9e987e0SGary Mills 		    (xdrproc_t)xdr_rpcb, (char *)&parms,
749a9e987e0SGary Mills 		    (xdrproc_t)xdr_rpcb_entry_list_ptr, (char *)&relp, *tp);
750a9e987e0SGary Mills 
751a9e987e0SGary Mills 		switch (clnt_st) {
752a9e987e0SGary Mills 		case RPC_SUCCESS: /* Call succeeded */
753a9e987e0SGary Mills 			address = got_entry(relp, nconf);
754a9e987e0SGary Mills 			xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
755a9e987e0SGary Mills 			    (char *)&relp);
756a9e987e0SGary Mills 			if (address != NULL) {
757a9e987e0SGary Mills 				/* Program number and version number matched */
7587c478bd9Sstevel@tonic-gate 				goto done;
7597c478bd9Sstevel@tonic-gate 			}
760a9e987e0SGary Mills 			/* Program and version not found for this transport */
7617c478bd9Sstevel@tonic-gate 			/*
762a9e987e0SGary Mills 			 * XXX: should have returned with RPC_PROGUNAVAIL
763a9e987e0SGary Mills 			 * or perhaps RPC_PROGNOTREGISTERED error but
7647c478bd9Sstevel@tonic-gate 			 * since the remote machine might not always be able
7657c478bd9Sstevel@tonic-gate 			 * to send the address on all transports, we try the
766a9e987e0SGary Mills 			 * regular way with version 3, then 2
7677c478bd9Sstevel@tonic-gate 			 */
768a9e987e0SGary Mills 			/* Try the next version */
769a9e987e0SGary Mills 			break;
770a9e987e0SGary Mills 		case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */
771a9e987e0SGary Mills 			clnt_geterr(client, &rpc_createerr.cf_error);
772a9e987e0SGary Mills 			if (rpc_createerr.cf_error.re_vers.low > vers) {
773a9e987e0SGary Mills 				rpc_createerr.cf_stat = clnt_st;
774a9e987e0SGary Mills 				goto error;  /* a new version, can't handle */
775a9e987e0SGary Mills 			}
776a9e987e0SGary Mills 			/* Try the next version */
777a9e987e0SGary Mills 			break;
778a9e987e0SGary Mills 		case RPC_PROCUNAVAIL: /* Procedure unavailable */
779a9e987e0SGary Mills 		case RPC_PROGUNAVAIL: /* Program not available */
780a9e987e0SGary Mills 		case RPC_TIMEDOUT: /* Call timed out */
781a9e987e0SGary Mills 			/* Try the next version */
782a9e987e0SGary Mills 			break;
783a9e987e0SGary Mills 		default:
7847c478bd9Sstevel@tonic-gate 			clnt_geterr(client, &rpc_createerr.cf_error);
785a9e987e0SGary Mills 			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
7867c478bd9Sstevel@tonic-gate 			goto error;
787a9e987e0SGary Mills 			break;
7887c478bd9Sstevel@tonic-gate 		}
7897c478bd9Sstevel@tonic-gate 
790a9e987e0SGary Mills 	} else {
7917c478bd9Sstevel@tonic-gate 
792a9e987e0SGary Mills 		/* No client */
793a9e987e0SGary Mills 		tmp_client = FALSE;
794a9e987e0SGary Mills 
795a9e987e0SGary Mills 	} /* End of version 4 */
796a9e987e0SGary Mills 
797a9e987e0SGary Mills 	/* Destroy a temporary client */
798a9e987e0SGary Mills 	if (client != NULL && tmp_client) {
7997c478bd9Sstevel@tonic-gate 		CLNT_DESTROY(client);
8007c478bd9Sstevel@tonic-gate 		client = NULL;
801d9638e54Smws 		free(parms.r_addr);
802d9638e54Smws 		parms.r_addr = NULL;
8037c478bd9Sstevel@tonic-gate 	}
804a9e987e0SGary Mills 	tmp_client = FALSE;
805a9e987e0SGary Mills 
806a9e987e0SGary Mills 	/*
807a9e987e0SGary Mills 	 * Try version 3
808a9e987e0SGary Mills 	 */
8097c478bd9Sstevel@tonic-gate 
810a9e987e0SGary Mills 	/* Now the same transport is to be used to get the address */
8117c478bd9Sstevel@tonic-gate 	if (client == NULL) {
812a9e987e0SGary Mills 		/* Sets rpc_createerr.cf_error members on failure */
8137c478bd9Sstevel@tonic-gate 		client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
8147c478bd9Sstevel@tonic-gate 	}
815a9e987e0SGary Mills 	address = NULL;
816a9e987e0SGary Mills 	if (client != NULL) {
8177c478bd9Sstevel@tonic-gate 		if (parms.r_addr == NULL) {
818a9e987e0SGary Mills 			parms.r_addr = strdup("");	/* for XDRing */
819a9e987e0SGary Mills 			if (parms.r_addr == NULL) {
820a9e987e0SGary Mills 				syslog(LOG_ERR, "__rpcb_findaddr_timed: "
821a9e987e0SGary Mills 				    "strdup failed.");
822a9e987e0SGary Mills 				/* Construct a system error */
823a9e987e0SGary Mills 				rpc_createerr.cf_error.re_errno = errno;
824a9e987e0SGary Mills 				rpc_createerr.cf_error.re_terrno = 0;
825a9e987e0SGary Mills 				rpc_createerr.cf_stat = RPC_SYSTEMERROR;
826a9e987e0SGary Mills 				goto error;
827a9e987e0SGary Mills 			}
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 
830a9e987e0SGary Mills 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
831a9e987e0SGary Mills 		    (char *)&rpcbrmttime);
832a9e987e0SGary Mills 		vers = RPCBVERS; /* Set the version */
8337c478bd9Sstevel@tonic-gate 		CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
834a9e987e0SGary Mills 
835a9e987e0SGary Mills 		/* Sets error structure members in client handle */
8367c478bd9Sstevel@tonic-gate 		clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR,
837a9e987e0SGary Mills 		    (xdrproc_t)xdr_rpcb, (char *)&parms,
838a9e987e0SGary Mills 		    (xdrproc_t)xdr_wrapstring, (char *)&ua, *tp);
839a9e987e0SGary Mills 
840a9e987e0SGary Mills 		switch (clnt_st) {
841a9e987e0SGary Mills 		case RPC_SUCCESS: /* Call succeeded */
842a9e987e0SGary Mills 			if (ua != NULL) {
843a9e987e0SGary Mills 				if (ua[0] != '\0') {
844a9e987e0SGary Mills 					address = uaddr2taddr(nconf, ua);
845a9e987e0SGary Mills 				}
846a9e987e0SGary Mills 				xdr_free((xdrproc_t)xdr_wrapstring,
847a9e987e0SGary Mills 				    (char *)&ua);
848a9e987e0SGary Mills 
849a9e987e0SGary Mills 				if (address != NULL) {
850a9e987e0SGary Mills 					goto done;
851a9e987e0SGary Mills 				}
852a9e987e0SGary Mills 				/* NULL universal address */
853a9e987e0SGary Mills 				/* But client call was successful */
854a9e987e0SGary Mills 				clnt_geterr(client, &rpc_createerr.cf_error);
8557c478bd9Sstevel@tonic-gate 				rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
8567c478bd9Sstevel@tonic-gate 				goto error;
8577c478bd9Sstevel@tonic-gate 			}
858a9e987e0SGary Mills #ifndef PORTMAP
859a9e987e0SGary Mills 			clnt_geterr(client, &rpc_createerr.cf_error);
860a9e987e0SGary Mills 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
861a9e987e0SGary Mills 			goto error;
862a9e987e0SGary Mills #endif
863a9e987e0SGary Mills 			/* Try the next version */
864a9e987e0SGary Mills 			break;
865a9e987e0SGary Mills 		case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */
866a9e987e0SGary Mills 			clnt_geterr(client, &rpc_createerr.cf_error);
867a9e987e0SGary Mills #ifdef PORTMAP
868a9e987e0SGary Mills 			if (rpc_createerr.cf_error.re_vers.low > vers) {
869a9e987e0SGary Mills 				rpc_createerr.cf_stat = clnt_st;
870a9e987e0SGary Mills 				goto error;  /* a new version, can't handle */
871a9e987e0SGary Mills 			}
872a9e987e0SGary Mills #else
873a9e987e0SGary Mills 			rpc_createerr.cf_stat = clnt_st;
874a9e987e0SGary Mills 			goto error;
8757c478bd9Sstevel@tonic-gate #endif
876a9e987e0SGary Mills 			/* Try the next version */
877a9e987e0SGary Mills 			break;
878a9e987e0SGary Mills #ifdef PORTMAP
879a9e987e0SGary Mills 		case RPC_PROCUNAVAIL: /* Procedure unavailable */
880a9e987e0SGary Mills 		case RPC_PROGUNAVAIL: /* Program not available */
881a9e987e0SGary Mills 		case RPC_TIMEDOUT: /* Call timed out */
882a9e987e0SGary Mills 			/* Try the next version */
883a9e987e0SGary Mills 			break;
884a9e987e0SGary Mills #endif
885a9e987e0SGary Mills 		default:
886a9e987e0SGary Mills 			clnt_geterr(client, &rpc_createerr.cf_error);
887a9e987e0SGary Mills 			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
888a9e987e0SGary Mills 			goto error;
889a9e987e0SGary Mills 			break;
890a9e987e0SGary Mills 		}
891a9e987e0SGary Mills 	} /* End of version 3 */
892a9e987e0SGary Mills #ifndef PORTMAP
893a9e987e0SGary Mills 	/* cf_error members set by creation failure */
894a9e987e0SGary Mills 	rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
895a9e987e0SGary Mills #endif
896a9e987e0SGary Mills 	/*
897a9e987e0SGary Mills 	 * Try version 2
898a9e987e0SGary Mills 	 */
899a9e987e0SGary Mills 
900a9e987e0SGary Mills #ifdef PORTMAP
901a9e987e0SGary Mills 	/* Try version 2 for TCP or UDP */
902a9e987e0SGary Mills 	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
903a9e987e0SGary Mills 		ushort_t port = 0;
904a9e987e0SGary Mills 		struct netbuf remote;
905a9e987e0SGary Mills 		uint_t pmapvers = 2;
906a9e987e0SGary Mills 		struct pmap pmapparms;
907a9e987e0SGary Mills 
908a9e987e0SGary Mills 		/*
909a9e987e0SGary Mills 		 * Try UDP only - there are some portmappers out
910a9e987e0SGary Mills 		 * there that use UDP only.
911a9e987e0SGary Mills 		 */
912a9e987e0SGary Mills 		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
913a9e987e0SGary Mills 			struct netconfig *newnconf;
9147c478bd9Sstevel@tonic-gate 
915a9e987e0SGary Mills 			if (client != NULL) {
916a9e987e0SGary Mills 				CLNT_DESTROY(client);
917a9e987e0SGary Mills 				client = NULL;
918a9e987e0SGary Mills 				free(parms.r_addr);
919a9e987e0SGary Mills 				parms.r_addr = NULL;
920a9e987e0SGary Mills 			}
921a9e987e0SGary Mills 			if ((handle = __rpc_setconf("udp")) == NULL) {
922a9e987e0SGary Mills 				/* Construct an unknown protocol error */
923a9e987e0SGary Mills 				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
9247c478bd9Sstevel@tonic-gate 				goto error;
9257c478bd9Sstevel@tonic-gate 			}
9267c478bd9Sstevel@tonic-gate 
927a9e987e0SGary Mills 			/*
928a9e987e0SGary Mills 			 * The following to reinforce that you can
929a9e987e0SGary Mills 			 * only request for remote address through
930a9e987e0SGary Mills 			 * the same transport you are requesting.
931a9e987e0SGary Mills 			 * ie. requesting unversial address
932a9e987e0SGary Mills 			 * of IPv4 has to be carried through IPv4.
933a9e987e0SGary Mills 			 * Can't use IPv6 to send out the request.
934a9e987e0SGary Mills 			 * The mergeaddr in rpcbind can't handle
935a9e987e0SGary Mills 			 * this.
936a9e987e0SGary Mills 			 */
937a9e987e0SGary Mills 			for (;;) {
938a9e987e0SGary Mills 				if ((newnconf = __rpc_getconf(handle))
939a9e987e0SGary Mills 				    == NULL) {
940a9e987e0SGary Mills 					__rpc_endconf(handle);
941a9e987e0SGary Mills 					/*
942a9e987e0SGary Mills 					 * Construct an unknown protocol
943a9e987e0SGary Mills 					 * error
944a9e987e0SGary Mills 					 */
945a9e987e0SGary Mills 					rpc_createerr.cf_stat =
946a9e987e0SGary Mills 					    RPC_UNKNOWNPROTO;
947a9e987e0SGary Mills 					goto error;
948a9e987e0SGary Mills 				}
949a9e987e0SGary Mills 				/*
950a9e987e0SGary Mills 				 * here check the protocol family to
951a9e987e0SGary Mills 				 * be consistent with the request one
952a9e987e0SGary Mills 				 */
953a9e987e0SGary Mills 				if (strcmp(newnconf->nc_protofmly,
954a9e987e0SGary Mills 				    nconf->nc_protofmly) == 0)
955a9e987e0SGary Mills 					break;
956a9e987e0SGary Mills 			}
957a9e987e0SGary Mills 
958a9e987e0SGary Mills 			/* Sets rpc_createerr.cf_error members on failure */
959a9e987e0SGary Mills 			client = _getclnthandle_timed(host, newnconf,
960a9e987e0SGary Mills 			    &parms.r_addr, tp);
961a9e987e0SGary Mills 			__rpc_endconf(handle);
962a9e987e0SGary Mills 			tmp_client = TRUE;
963a9e987e0SGary Mills 		}
964a9e987e0SGary Mills 		if (client == NULL) {
965a9e987e0SGary Mills 			/*
966a9e987e0SGary Mills 			 * rpc_createerr. cf_error members were set by
967a9e987e0SGary Mills 			 * creation failure
968a9e987e0SGary Mills 			 */
969a9e987e0SGary Mills 			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
970a9e987e0SGary Mills 			tmp_client = FALSE;
9717c478bd9Sstevel@tonic-gate 			goto error;
9727c478bd9Sstevel@tonic-gate 		}
9737c478bd9Sstevel@tonic-gate 
974a9e987e0SGary Mills 		/*
975a9e987e0SGary Mills 		 * Set version and retry timeout.
976a9e987e0SGary Mills 		 */
977a9e987e0SGary Mills 		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
978a9e987e0SGary Mills 		CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
979a9e987e0SGary Mills 
980a9e987e0SGary Mills 		pmapparms.pm_prog = program;
981a9e987e0SGary Mills 		pmapparms.pm_vers = version;
982a9e987e0SGary Mills 		pmapparms.pm_prot = (strcmp(nconf->nc_proto, NC_TCP) != 0) ?
983a9e987e0SGary Mills 		    IPPROTO_UDP : IPPROTO_TCP;
984a9e987e0SGary Mills 		pmapparms.pm_port = 0;	/* not needed */
985a9e987e0SGary Mills 
986a9e987e0SGary Mills 		/* Sets error structure members in client handle */
987a9e987e0SGary Mills 		clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT,
988a9e987e0SGary Mills 		    (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms,
989a9e987e0SGary Mills 		    (xdrproc_t)xdr_u_short, (caddr_t)&port, *tp);
990a9e987e0SGary Mills 
991a9e987e0SGary Mills 		if (clnt_st != RPC_SUCCESS) {
992a9e987e0SGary Mills 			clnt_geterr(client, &rpc_createerr.cf_error);
993a9e987e0SGary Mills 			rpc_createerr.cf_stat = RPC_RPCBFAILURE;
994a9e987e0SGary Mills 			goto error;
995a9e987e0SGary Mills 		} else if (port == 0) {
996a9e987e0SGary Mills 			/* Will be NULL universal address */
997a9e987e0SGary Mills 			/* But client call was successful */
998a9e987e0SGary Mills 			clnt_geterr(client, &rpc_createerr.cf_error);
999a9e987e0SGary Mills 			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
1000a9e987e0SGary Mills 			goto error;
1001a9e987e0SGary Mills 		}
1002a9e987e0SGary Mills 		port = htons(port);
1003a9e987e0SGary Mills 		CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
1004a9e987e0SGary Mills 		if (((address = malloc(sizeof (struct netbuf))) == NULL) ||
1005a9e987e0SGary Mills 		    ((address->buf = malloc(remote.len)) == NULL)) {
1006a9e987e0SGary Mills 			/* Construct a system error */
1007a9e987e0SGary Mills 			rpc_createerr.cf_error.re_errno = errno;
1008a9e987e0SGary Mills 			rpc_createerr.cf_error.re_terrno = 0;
1009a9e987e0SGary Mills 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1010a9e987e0SGary Mills 			free(address);
1011a9e987e0SGary Mills 			address = NULL;
1012a9e987e0SGary Mills 			goto error;
1013a9e987e0SGary Mills 		}
1014a9e987e0SGary Mills 		(void) memcpy(address->buf, remote.buf, remote.len);
1015a9e987e0SGary Mills 		(void) memcpy(&address->buf[sizeof (short)], &port,
1016a9e987e0SGary Mills 		    sizeof (short));
1017a9e987e0SGary Mills 		address->len = address->maxlen = remote.len;
1018a9e987e0SGary Mills 		goto done;
1019a9e987e0SGary Mills 	} else {
1020a9e987e0SGary Mills 		/*
1021a9e987e0SGary Mills 		 * This is not NC_INET.
1022a9e987e0SGary Mills 		 * Always an error for version 2.
1023a9e987e0SGary Mills 		 */
1024a9e987e0SGary Mills 		if (client != NULL && clnt_st != RPC_SUCCESS) {
1025a9e987e0SGary Mills 			/* There is a client that failed */
1026a9e987e0SGary Mills 			clnt_geterr(client, &rpc_createerr.cf_error);
1027a9e987e0SGary Mills 			rpc_createerr.cf_stat = clnt_st;
1028a9e987e0SGary Mills 		} else {
1029a9e987e0SGary Mills 			/* Something else */
1030a9e987e0SGary Mills 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1031a9e987e0SGary Mills 			/*
1032a9e987e0SGary Mills 			 * Setting rpc_createerr.cf_stat is sufficient.
1033a9e987e0SGary Mills 			 * No details in rpc_createerr.cf_error needed.
1034a9e987e0SGary Mills 			 */
1035a9e987e0SGary Mills 		}
10367c478bd9Sstevel@tonic-gate 	}
1037a9e987e0SGary Mills #endif
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate error:
1040a9e987e0SGary Mills 	/* Return NULL address and NULL client */
1041a9e987e0SGary Mills 	address = NULL;
1042a9e987e0SGary Mills 	if (client != NULL) {
10437c478bd9Sstevel@tonic-gate 		CLNT_DESTROY(client);
10447c478bd9Sstevel@tonic-gate 		client = NULL;
10457c478bd9Sstevel@tonic-gate 	}
1046a9e987e0SGary Mills 
10477c478bd9Sstevel@tonic-gate done:
1048a9e987e0SGary Mills 	/* Return an address and optional client */
1049a9e987e0SGary Mills 	if (client != NULL && tmp_client) {
1050a9e987e0SGary Mills 		/* This client is the temporary one */
1051a9e987e0SGary Mills 		CLNT_DESTROY(client);
1052a9e987e0SGary Mills 		client = NULL;
10537c478bd9Sstevel@tonic-gate 	}
1054a9e987e0SGary Mills 	if (clpp != NULL) {
10557c478bd9Sstevel@tonic-gate 		*clpp = client;
1056a9e987e0SGary Mills 	} else if (client != NULL) {
10577c478bd9Sstevel@tonic-gate 		CLNT_DESTROY(client);
10587c478bd9Sstevel@tonic-gate 	}
1059a9e987e0SGary Mills 	free(parms.r_addr);
10607c478bd9Sstevel@tonic-gate 	return (address);
10617c478bd9Sstevel@tonic-gate }
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate /*
10657c478bd9Sstevel@tonic-gate  * Find the mapped address for program, version.
10667c478bd9Sstevel@tonic-gate  * Calls the rpcbind service remotely to do the lookup.
10677c478bd9Sstevel@tonic-gate  * Uses the transport specified in nconf.
10687c478bd9Sstevel@tonic-gate  * Returns FALSE (0) if no map exists, else returns 1.
10697c478bd9Sstevel@tonic-gate  *
10707c478bd9Sstevel@tonic-gate  * Assuming that the address is all properly allocated
10717c478bd9Sstevel@tonic-gate  */
10727c478bd9Sstevel@tonic-gate int
rpcb_getaddr(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf,struct netbuf * address,const char * host)107361961e0fSrobinson rpcb_getaddr(const rpcprog_t program, const rpcvers_t version,
107461961e0fSrobinson 	const struct netconfig *nconf, struct netbuf *address, const char *host)
10757c478bd9Sstevel@tonic-gate {
10767c478bd9Sstevel@tonic-gate 	struct netbuf *na;
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	if ((na = __rpcb_findaddr_timed(program, version,
107961961e0fSrobinson 	    (struct netconfig *)nconf, (char *)host, NULL, NULL)) == NULL)
10807c478bd9Sstevel@tonic-gate 		return (FALSE);
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	if (na->len > address->maxlen) {
10837c478bd9Sstevel@tonic-gate 		/* Too long address */
10847c478bd9Sstevel@tonic-gate 		netdir_free((char *)na, ND_ADDR);
10857c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_FAILED;
10867c478bd9Sstevel@tonic-gate 		return (FALSE);
10877c478bd9Sstevel@tonic-gate 	}
108861961e0fSrobinson 	(void) memcpy(address->buf, na->buf, (int)na->len);
10897c478bd9Sstevel@tonic-gate 	address->len = na->len;
10907c478bd9Sstevel@tonic-gate 	netdir_free((char *)na, ND_ADDR);
10917c478bd9Sstevel@tonic-gate 	return (TRUE);
10927c478bd9Sstevel@tonic-gate }
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate /*
10957c478bd9Sstevel@tonic-gate  * Get a copy of the current maps.
10967c478bd9Sstevel@tonic-gate  * Calls the rpcbind service remotely to get the maps.
10977c478bd9Sstevel@tonic-gate  *
10987c478bd9Sstevel@tonic-gate  * It returns only a list of the services
10997c478bd9Sstevel@tonic-gate  * It returns NULL on failure.
11007c478bd9Sstevel@tonic-gate  */
11017c478bd9Sstevel@tonic-gate rpcblist *
rpcb_getmaps(const struct netconfig * nconf,const char * host)110261961e0fSrobinson rpcb_getmaps(const struct netconfig *nconf, const char *host)
11037c478bd9Sstevel@tonic-gate {
110461961e0fSrobinson 	rpcblist_ptr head = NULL;
11057c478bd9Sstevel@tonic-gate 	CLIENT *client;
11067c478bd9Sstevel@tonic-gate 	enum clnt_stat clnt_st;
11077c478bd9Sstevel@tonic-gate 	int vers = 0;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	client = getclnthandle((char *)host,
1110a9e987e0SGary Mills 	    (struct netconfig *)nconf, NULL);
111161961e0fSrobinson 	if (client == NULL)
111261961e0fSrobinson 		return (NULL);
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
1115a9e987e0SGary Mills 	    (xdrproc_t)xdr_void, NULL,
1116a9e987e0SGary Mills 	    (xdrproc_t)xdr_rpcblist_ptr,
1117a9e987e0SGary Mills 	    (char *)&head, tottimeout);
11187c478bd9Sstevel@tonic-gate 	if (clnt_st == RPC_SUCCESS)
11197c478bd9Sstevel@tonic-gate 		goto done;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	if ((clnt_st != RPC_PROGVERSMISMATCH) &&
1122a9e987e0SGary Mills 	    (clnt_st != RPC_PROGUNAVAIL)) {
11237c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_RPCBFAILURE;
11247c478bd9Sstevel@tonic-gate 		clnt_geterr(client, &rpc_createerr.cf_error);
11257c478bd9Sstevel@tonic-gate 		goto done;
11267c478bd9Sstevel@tonic-gate 	}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	/* fall back to earlier version */
11297c478bd9Sstevel@tonic-gate 	CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
11307c478bd9Sstevel@tonic-gate 	if (vers == RPCBVERS4) {
11317c478bd9Sstevel@tonic-gate 		vers = RPCBVERS;
11327c478bd9Sstevel@tonic-gate 		CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
11337c478bd9Sstevel@tonic-gate 		if (CLNT_CALL(client, RPCBPROC_DUMP,
1134a9e987e0SGary Mills 		    (xdrproc_t)xdr_void,
1135a9e987e0SGary Mills 		    NULL, (xdrproc_t)xdr_rpcblist_ptr,
1136a9e987e0SGary Mills 		    (char *)&head, tottimeout) == RPC_SUCCESS)
11377c478bd9Sstevel@tonic-gate 				goto done;
11387c478bd9Sstevel@tonic-gate 	}
11397c478bd9Sstevel@tonic-gate 	rpc_createerr.cf_stat = RPC_RPCBFAILURE;
11407c478bd9Sstevel@tonic-gate 	clnt_geterr(client, &rpc_createerr.cf_error);
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate done:
11437c478bd9Sstevel@tonic-gate 	CLNT_DESTROY(client);
11447c478bd9Sstevel@tonic-gate 	return (head);
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate /*
11487c478bd9Sstevel@tonic-gate  * rpcbinder remote-call-service interface.
11497c478bd9Sstevel@tonic-gate  * This routine is used to call the rpcbind remote call service
11507c478bd9Sstevel@tonic-gate  * which will look up a service program in the address maps, and then
11517c478bd9Sstevel@tonic-gate  * remotely call that routine with the given parameters. This allows
11527c478bd9Sstevel@tonic-gate  * programs to do a lookup and call in one step.
11537c478bd9Sstevel@tonic-gate  */
11547c478bd9Sstevel@tonic-gate enum clnt_stat
rpcb_rmtcall(const struct netconfig * nconf,const char * host,const rpcprog_t prog,const rpcvers_t vers,const rpcproc_t proc,const xdrproc_t xdrargs,const caddr_t argsp,const xdrproc_t xdrres,const caddr_t resp,const struct timeval tout,struct netbuf * addr_ptr)115561961e0fSrobinson rpcb_rmtcall(const struct netconfig *nconf, const char *host,
115661961e0fSrobinson 	const rpcprog_t prog, const rpcvers_t vers, const rpcproc_t proc,
115761961e0fSrobinson 	const xdrproc_t xdrargs, const caddr_t argsp, const xdrproc_t xdrres,
115861961e0fSrobinson 	const caddr_t resp, const struct timeval tout, struct netbuf *addr_ptr)
11597c478bd9Sstevel@tonic-gate {
11607c478bd9Sstevel@tonic-gate 	CLIENT *client;
11617c478bd9Sstevel@tonic-gate 	enum clnt_stat stat;
11627c478bd9Sstevel@tonic-gate 	struct r_rpcb_rmtcallargs a;
11637c478bd9Sstevel@tonic-gate 	struct r_rpcb_rmtcallres r;
11647c478bd9Sstevel@tonic-gate 	int rpcb_vers;
11657c478bd9Sstevel@tonic-gate 
116661961e0fSrobinson 	client = getclnthandle((char *)host, (struct netconfig *)nconf, NULL);
116761961e0fSrobinson 	if (client == NULL)
11687c478bd9Sstevel@tonic-gate 		return (RPC_FAILED);
11697c478bd9Sstevel@tonic-gate 	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rmttimeout);
11707c478bd9Sstevel@tonic-gate 	a.prog = prog;
11717c478bd9Sstevel@tonic-gate 	a.vers = vers;
11727c478bd9Sstevel@tonic-gate 	a.proc = proc;
11737c478bd9Sstevel@tonic-gate 	a.args.args_val = argsp;
11747c478bd9Sstevel@tonic-gate 	a.xdr_args = xdrargs;
11757c478bd9Sstevel@tonic-gate 	r.addr = NULL;
11767c478bd9Sstevel@tonic-gate 	r.results.results_val = resp;
11777c478bd9Sstevel@tonic-gate 	r.xdr_res = xdrres;
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
11807c478bd9Sstevel@tonic-gate 		CLNT_CONTROL(client, CLSET_VERS, (char *)&rpcb_vers);
11817c478bd9Sstevel@tonic-gate 		stat = CLNT_CALL(client, RPCBPROC_CALLIT,
1182a9e987e0SGary Mills 		    (xdrproc_t)xdr_rpcb_rmtcallargs, (char *)&a,
1183a9e987e0SGary Mills 		    (xdrproc_t)xdr_rpcb_rmtcallres, (char *)&r, tout);
11847c478bd9Sstevel@tonic-gate 		if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
11857c478bd9Sstevel@tonic-gate 			struct netbuf *na;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 			na = uaddr2taddr((struct netconfig *)nconf, r.addr);
118861961e0fSrobinson 			if (!na) {
11897c478bd9Sstevel@tonic-gate 				stat = RPC_N2AXLATEFAILURE;
11907c478bd9Sstevel@tonic-gate 				((struct netbuf *)addr_ptr)->len = 0;
11917c478bd9Sstevel@tonic-gate 				goto error;
11927c478bd9Sstevel@tonic-gate 			}
11937c478bd9Sstevel@tonic-gate 			if (na->len > addr_ptr->maxlen) {
11947c478bd9Sstevel@tonic-gate 				/* Too long address */
11957c478bd9Sstevel@tonic-gate 				stat = RPC_FAILED; /* XXX A better error no */
11967c478bd9Sstevel@tonic-gate 				netdir_free((char *)na, ND_ADDR);
11977c478bd9Sstevel@tonic-gate 				((struct netbuf *)addr_ptr)->len = 0;
11987c478bd9Sstevel@tonic-gate 				goto error;
11997c478bd9Sstevel@tonic-gate 			}
120061961e0fSrobinson 			(void) memcpy(addr_ptr->buf, na->buf, (int)na->len);
12017c478bd9Sstevel@tonic-gate 			((struct netbuf *)addr_ptr)->len = na->len;
12027c478bd9Sstevel@tonic-gate 			netdir_free((char *)na, ND_ADDR);
12037c478bd9Sstevel@tonic-gate 			break;
12047c478bd9Sstevel@tonic-gate 		}
120561961e0fSrobinson 		if ((stat != RPC_PROGVERSMISMATCH) &&
1206a9e987e0SGary Mills 		    (stat != RPC_PROGUNAVAIL))
120761961e0fSrobinson 			goto error;
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate error:
12107c478bd9Sstevel@tonic-gate 	CLNT_DESTROY(client);
12117c478bd9Sstevel@tonic-gate 	if (r.addr)
12127c478bd9Sstevel@tonic-gate 		xdr_free((xdrproc_t)xdr_wrapstring, (char *)&r.addr);
12137c478bd9Sstevel@tonic-gate 	return (stat);
12147c478bd9Sstevel@tonic-gate }
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate /*
12177c478bd9Sstevel@tonic-gate  * Gets the time on the remote host.
12187c478bd9Sstevel@tonic-gate  * Returns 1 if succeeds else 0.
12197c478bd9Sstevel@tonic-gate  */
12207c478bd9Sstevel@tonic-gate bool_t
rpcb_gettime(const char * host,time_t * timep)122161961e0fSrobinson rpcb_gettime(const char *host, time_t *timep)
12227c478bd9Sstevel@tonic-gate {
12237c478bd9Sstevel@tonic-gate 	CLIENT *client = NULL;
12247c478bd9Sstevel@tonic-gate 	void *handle;
12257c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
12267c478bd9Sstevel@tonic-gate 	int vers;
12277c478bd9Sstevel@tonic-gate 	enum clnt_stat st;
12287c478bd9Sstevel@tonic-gate 
1229*344db6f4SToomas Soome 	if ((host == NULL) || (host[0] == '\0')) {
123061961e0fSrobinson 		(void) time(timep);
12317c478bd9Sstevel@tonic-gate 		return (TRUE);
12327c478bd9Sstevel@tonic-gate 	}
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	if ((handle = __rpc_setconf("netpath")) == NULL) {
12357c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
12367c478bd9Sstevel@tonic-gate 		return (FALSE);
12377c478bd9Sstevel@tonic-gate 	}
12387c478bd9Sstevel@tonic-gate 	rpc_createerr.cf_stat = RPC_SUCCESS;
123961961e0fSrobinson 	while (client == NULL) {
12407c478bd9Sstevel@tonic-gate 		if ((nconf = __rpc_getconf(handle)) == NULL) {
12417c478bd9Sstevel@tonic-gate 			if (rpc_createerr.cf_stat == RPC_SUCCESS)
12427c478bd9Sstevel@tonic-gate 				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
12437c478bd9Sstevel@tonic-gate 			break;
12447c478bd9Sstevel@tonic-gate 		}
124561961e0fSrobinson 		client = getclnthandle((char *)host, nconf, NULL);
12467c478bd9Sstevel@tonic-gate 		if (client)
12477c478bd9Sstevel@tonic-gate 			break;
12487c478bd9Sstevel@tonic-gate 	}
12497c478bd9Sstevel@tonic-gate 	__rpc_endconf(handle);
125061961e0fSrobinson 	if (client == NULL)
12517c478bd9Sstevel@tonic-gate 		return (FALSE);
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	st = CLNT_CALL(client, RPCBPROC_GETTIME,
1254a9e987e0SGary Mills 	    (xdrproc_t)xdr_void, NULL,
1255a9e987e0SGary Mills 	    (xdrproc_t)xdr_time_t, (char *)timep, tottimeout);
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
12587c478bd9Sstevel@tonic-gate 		CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
12597c478bd9Sstevel@tonic-gate 		if (vers == RPCBVERS4) {
12607c478bd9Sstevel@tonic-gate 			/* fall back to earlier version */
12617c478bd9Sstevel@tonic-gate 			vers = RPCBVERS;
12627c478bd9Sstevel@tonic-gate 			CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
12637c478bd9Sstevel@tonic-gate 			st = CLNT_CALL(client, RPCBPROC_GETTIME,
1264a9e987e0SGary Mills 			    (xdrproc_t)xdr_void, NULL,
1265a9e987e0SGary Mills 			    (xdrproc_t)xdr_time_t, (char *)timep,
1266a9e987e0SGary Mills 			    tottimeout);
12677c478bd9Sstevel@tonic-gate 		}
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 	CLNT_DESTROY(client);
127061961e0fSrobinson 	return (st == RPC_SUCCESS? TRUE : FALSE);
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate /*
12747c478bd9Sstevel@tonic-gate  * Converts taddr to universal address.  This routine should never
12757c478bd9Sstevel@tonic-gate  * really be called because local n2a libraries are always provided.
12767c478bd9Sstevel@tonic-gate  */
12777c478bd9Sstevel@tonic-gate char *
rpcb_taddr2uaddr(struct netconfig * nconf,struct netbuf * taddr)127861961e0fSrobinson rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
12797c478bd9Sstevel@tonic-gate {
12807c478bd9Sstevel@tonic-gate 	CLIENT *client;
12817c478bd9Sstevel@tonic-gate 	char *uaddr = NULL;
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	/* parameter checking */
128461961e0fSrobinson 	if (nconf == NULL) {
12857c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
12867c478bd9Sstevel@tonic-gate 		return (NULL);
12877c478bd9Sstevel@tonic-gate 	}
12887c478bd9Sstevel@tonic-gate 	if (taddr == NULL) {
12897c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
12907c478bd9Sstevel@tonic-gate 		return (NULL);
12917c478bd9Sstevel@tonic-gate 	}
12927c478bd9Sstevel@tonic-gate 	client = local_rpcb();
129361961e0fSrobinson 	if (!client)
12947c478bd9Sstevel@tonic-gate 		return (NULL);
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	CLNT_CALL(client, RPCBPROC_TADDR2UADDR, (xdrproc_t)xdr_netbuf,
1297a9e987e0SGary Mills 	    (char *)taddr, (xdrproc_t)xdr_wrapstring, (char *)&uaddr,
1298a9e987e0SGary Mills 	    tottimeout);
12997c478bd9Sstevel@tonic-gate 	CLNT_DESTROY(client);
13007c478bd9Sstevel@tonic-gate 	return (uaddr);
13017c478bd9Sstevel@tonic-gate }
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate /*
13047c478bd9Sstevel@tonic-gate  * Converts universal address to netbuf.  This routine should never
13057c478bd9Sstevel@tonic-gate  * really be called because local n2a libraries are always provided.
13067c478bd9Sstevel@tonic-gate  */
13077c478bd9Sstevel@tonic-gate struct netbuf *
rpcb_uaddr2taddr(struct netconfig * nconf,char * uaddr)130861961e0fSrobinson rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
13097c478bd9Sstevel@tonic-gate {
13107c478bd9Sstevel@tonic-gate 	CLIENT *client;
13117c478bd9Sstevel@tonic-gate 	struct netbuf *taddr;
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	/* parameter checking */
131461961e0fSrobinson 	if (nconf == NULL) {
13157c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
13167c478bd9Sstevel@tonic-gate 		return (NULL);
13177c478bd9Sstevel@tonic-gate 	}
13187c478bd9Sstevel@tonic-gate 	if (uaddr == NULL) {
13197c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
13207c478bd9Sstevel@tonic-gate 		return (NULL);
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 	client = local_rpcb();
132361961e0fSrobinson 	if (!client)
13247c478bd9Sstevel@tonic-gate 		return (NULL);
13257c478bd9Sstevel@tonic-gate 
132661961e0fSrobinson 	taddr = calloc(1, sizeof (struct netbuf));
13277c478bd9Sstevel@tonic-gate 	if (taddr == NULL) {
13287c478bd9Sstevel@tonic-gate 		CLNT_DESTROY(client);
13297c478bd9Sstevel@tonic-gate 		return (NULL);
13307c478bd9Sstevel@tonic-gate 	}
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	if (CLNT_CALL(client, RPCBPROC_UADDR2TADDR, (xdrproc_t)xdr_wrapstring,
1333a9e987e0SGary Mills 	    (char *)&uaddr, (xdrproc_t)xdr_netbuf, (char *)taddr,
1334a9e987e0SGary Mills 	    tottimeout) != RPC_SUCCESS) {
13357c478bd9Sstevel@tonic-gate 		free(taddr);
13367c478bd9Sstevel@tonic-gate 		taddr = NULL;
13377c478bd9Sstevel@tonic-gate 	}
13387c478bd9Sstevel@tonic-gate 	CLNT_DESTROY(client);
13397c478bd9Sstevel@tonic-gate 	return (taddr);
13407c478bd9Sstevel@tonic-gate }
1341