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
237c478bd9Sstevel@tonic-gate /*
24*6935f61bSMarcel Telka * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25*6935f61bSMarcel Telka */
26*6935f61bSMarcel Telka
27*6935f61bSMarcel Telka /*
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) &&
1727c478bd9Sstevel@tonic-gate (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 ||
2217c478bd9Sstevel@tonic-gate (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,
3217c478bd9Sstevel@tonic-gate 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 =
3367c478bd9Sstevel@tonic-gate RPC_SYSTEMERROR;
33761961e0fSrobinson (void) rw_unlock(
33861961e0fSrobinson &rpcbaddr_cache_lock);
33961961e0fSrobinson return (NULL);
3407c478bd9Sstevel@tonic-gate }
34161961e0fSrobinson } else {
3427c478bd9Sstevel@tonic-gate *targaddr = NULL;
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate }
34561961e0fSrobinson (void) rw_unlock(&rpcbaddr_cache_lock);
34661961e0fSrobinson 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,
3867c478bd9Sstevel@tonic-gate 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);
442*6935f61bSMarcel 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,
47261961e0fSrobinson (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,
4897c478bd9Sstevel@tonic-gate (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,
5267c478bd9Sstevel@tonic-gate (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) &&
5477c478bd9Sstevel@tonic-gate (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != NULL)) {
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 }
587*6935f61bSMarcel 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;
6977c478bd9Sstevel@tonic-gate if ((handle = __rpc_setconf("datagram_v")) != NULL) {
698a9e987e0SGary Mills struct netconfig *nconf_clts;
699a9e987e0SGary Mills
700a9e987e0SGary Mills while ((nconf_clts = __rpc_getconf(handle)) != NULL) {
7017c478bd9Sstevel@tonic-gate if (strcmp(nconf_clts->nc_protofmly,
7027c478bd9Sstevel@tonic-gate nconf->nc_protofmly) != 0) {
7037c478bd9Sstevel@tonic-gate 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);
7117c478bd9Sstevel@tonic-gate break;
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate __rpc_endconf(handle);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate } 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 */
7237c478bd9Sstevel@tonic-gate vers = RPCBVERS4;
7247c478bd9Sstevel@tonic-gate 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: "
7347c478bd9Sstevel@tonic-gate "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,
7487c478bd9Sstevel@tonic-gate (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);
7547c478bd9Sstevel@tonic-gate xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
7557c478bd9Sstevel@tonic-gate (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 */
7717c478bd9Sstevel@tonic-gate 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:
784a9e987e0SGary Mills 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;
8057c478bd9Sstevel@tonic-gate
806a9e987e0SGary Mills /*
807a9e987e0SGary Mills * Try version 3
808a9e987e0SGary Mills */
809a9e987e0SGary Mills
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);
814a9e987e0SGary Mills }
8157c478bd9Sstevel@tonic-gate address = NULL;
816a9e987e0SGary Mills if (client != NULL) {
8177c478bd9Sstevel@tonic-gate if (parms.r_addr == NULL) {
8187c478bd9Sstevel@tonic-gate parms.r_addr = strdup(""); /* for XDRing */
8197c478bd9Sstevel@tonic-gate if (parms.r_addr == NULL) {
8207c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "__rpcb_findaddr_timed: "
8217c478bd9Sstevel@tonic-gate "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;
8257c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR;
8267c478bd9Sstevel@tonic-gate goto error;
8277c478bd9Sstevel@tonic-gate }
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,
8377c478bd9Sstevel@tonic-gate (xdrproc_t)xdr_rpcb, (char *)&parms,
838a9e987e0SGary Mills (xdrproc_t)xdr_wrapstring, (char *)&ua, *tp);
839d9638e54Smws
840a9e987e0SGary Mills switch (clnt_st) {
841a9e987e0SGary Mills case RPC_SUCCESS: /* Call succeeded */
842a9e987e0SGary Mills if (ua != NULL) {
843a9e987e0SGary Mills if (ua[0] != '\0') {
8447c478bd9Sstevel@tonic-gate address = uaddr2taddr(nconf, ua);
8457c478bd9Sstevel@tonic-gate }
846a9e987e0SGary Mills xdr_free((xdrproc_t)xdr_wrapstring,
847a9e987e0SGary Mills (char *)&ua);
848a9e987e0SGary Mills
849a9e987e0SGary Mills if (address != NULL) {
8507c478bd9Sstevel@tonic-gate goto done;
85161961e0fSrobinson }
852a9e987e0SGary Mills /* NULL universal address */
853a9e987e0SGary Mills /* But client call was successful */
854a9e987e0SGary Mills clnt_geterr(client, &rpc_createerr.cf_error);
855a9e987e0SGary Mills 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;
875a9e987e0SGary Mills #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;
914a9e987e0SGary Mills
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;
924a9e987e0SGary Mills 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;
9487c478bd9Sstevel@tonic-gate }
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;
971a9e987e0SGary Mills goto error;
972a9e987e0SGary Mills }
973a9e987e0SGary Mills
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 }
1036a9e987e0SGary Mills }
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 */
10517c478bd9Sstevel@tonic-gate CLNT_DESTROY(client);
10527c478bd9Sstevel@tonic-gate 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 }
10597c478bd9Sstevel@tonic-gate 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,
111061961e0fSrobinson (struct netconfig *)nconf, NULL);
111161961e0fSrobinson if (client == NULL)
111261961e0fSrobinson return (NULL);
11137c478bd9Sstevel@tonic-gate
11147c478bd9Sstevel@tonic-gate clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
11157c478bd9Sstevel@tonic-gate (xdrproc_t)xdr_void, NULL,
11167c478bd9Sstevel@tonic-gate (xdrproc_t)xdr_rpcblist_ptr,
11177c478bd9Sstevel@tonic-gate (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) &&
11227c478bd9Sstevel@tonic-gate (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,
11347c478bd9Sstevel@tonic-gate (xdrproc_t)xdr_void,
113561961e0fSrobinson NULL, (xdrproc_t)xdr_rpcblist_ptr,
11367c478bd9Sstevel@tonic-gate (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,
11827c478bd9Sstevel@tonic-gate (xdrproc_t)xdr_rpcb_rmtcallargs, (char *)&a,
11837c478bd9Sstevel@tonic-gate (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);
11887c478bd9Sstevel@tonic-gate 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) &&
120661961e0fSrobinson (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
12297c478bd9Sstevel@tonic-gate if ((host == NULL) || (host[0] == NULL)) {
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,
125461961e0fSrobinson (xdrproc_t)xdr_void, NULL,
12557c478bd9Sstevel@tonic-gate (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,
126461961e0fSrobinson (xdrproc_t)xdr_void, NULL,
12657c478bd9Sstevel@tonic-gate (xdrproc_t)xdr_time_t, (char *)timep,
12667c478bd9Sstevel@tonic-gate tottimeout);
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate }
12697c478bd9Sstevel@tonic-gate CLNT_DESTROY(client);
12707c478bd9Sstevel@tonic-gate 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,
12977c478bd9Sstevel@tonic-gate (char *)taddr, (xdrproc_t)xdr_wrapstring, (char *)&uaddr,
12987c478bd9Sstevel@tonic-gate 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,
13337c478bd9Sstevel@tonic-gate (char *)&uaddr, (xdrproc_t)xdr_netbuf, (char *)taddr,
13347c478bd9Sstevel@tonic-gate 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