10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
22132Srobinson
230Sstevel@tonic-gate /*
24*1219Sraf * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
250Sstevel@tonic-gate * Use is subject to license terms.
260Sstevel@tonic-gate */
27*1219Sraf
280Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
290Sstevel@tonic-gate /* All Rights Reserved */
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate * Portions of this source code were derived from Berkeley
320Sstevel@tonic-gate * 4.3 BSD under license from the Regents of the University of
330Sstevel@tonic-gate * California.
340Sstevel@tonic-gate */
350Sstevel@tonic-gate
360Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
370Sstevel@tonic-gate
380Sstevel@tonic-gate /*
390Sstevel@tonic-gate * interface to rpcbind rpc service.
400Sstevel@tonic-gate */
410Sstevel@tonic-gate
420Sstevel@tonic-gate #include "mt.h"
430Sstevel@tonic-gate #include "rpc_mt.h"
440Sstevel@tonic-gate #include <assert.h>
450Sstevel@tonic-gate #include <rpc/rpc.h>
460Sstevel@tonic-gate #include <rpc/rpcb_prot.h>
470Sstevel@tonic-gate #include <netconfig.h>
480Sstevel@tonic-gate #include <netdir.h>
490Sstevel@tonic-gate #include <rpc/nettype.h>
500Sstevel@tonic-gate #include <syslog.h>
510Sstevel@tonic-gate #ifdef PORTMAP
520Sstevel@tonic-gate #include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
530Sstevel@tonic-gate #include <rpc/pmap_prot.h>
540Sstevel@tonic-gate #endif
550Sstevel@tonic-gate #ifdef ND_DEBUG
560Sstevel@tonic-gate #include <stdio.h>
570Sstevel@tonic-gate #endif
580Sstevel@tonic-gate #include <sys/utsname.h>
590Sstevel@tonic-gate #include <errno.h>
600Sstevel@tonic-gate #include <stdlib.h>
610Sstevel@tonic-gate #include <string.h>
620Sstevel@tonic-gate #include <unistd.h>
630Sstevel@tonic-gate
640Sstevel@tonic-gate static struct timeval tottimeout = { 60, 0 };
650Sstevel@tonic-gate static const struct timeval rmttimeout = { 3, 0 };
660Sstevel@tonic-gate static struct timeval rpcbrmttime = { 15, 0 };
670Sstevel@tonic-gate
68132Srobinson extern bool_t xdr_wrapstring(XDR *, char **);
690Sstevel@tonic-gate
700Sstevel@tonic-gate static const char nullstring[] = "\000";
710Sstevel@tonic-gate
720Sstevel@tonic-gate extern CLIENT *_clnt_tli_create_timed(int, const struct netconfig *,
730Sstevel@tonic-gate struct netbuf *, rpcprog_t, rpcvers_t, uint_t, uint_t,
740Sstevel@tonic-gate const struct timeval *);
750Sstevel@tonic-gate
760Sstevel@tonic-gate static CLIENT *_getclnthandle_timed(char *, struct netconfig *, char **,
770Sstevel@tonic-gate struct timeval *);
780Sstevel@tonic-gate
790Sstevel@tonic-gate
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate * The life time of a cached entry should not exceed 5 minutes
820Sstevel@tonic-gate * since automountd attempts an unmount every 5 minutes.
830Sstevel@tonic-gate * It is arbitrarily set a little lower (3 min = 180 sec)
840Sstevel@tonic-gate * to reduce the time during which an entry is stale.
850Sstevel@tonic-gate */
860Sstevel@tonic-gate #define CACHE_TTL 180
870Sstevel@tonic-gate #define CACHESIZE 6
880Sstevel@tonic-gate
890Sstevel@tonic-gate struct address_cache {
900Sstevel@tonic-gate char *ac_host;
910Sstevel@tonic-gate char *ac_netid;
920Sstevel@tonic-gate char *ac_uaddr;
930Sstevel@tonic-gate struct netbuf *ac_taddr;
940Sstevel@tonic-gate struct address_cache *ac_next;
950Sstevel@tonic-gate time_t ac_maxtime;
960Sstevel@tonic-gate };
970Sstevel@tonic-gate
980Sstevel@tonic-gate static struct address_cache *front;
990Sstevel@tonic-gate static int cachesize;
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate extern int lowvers;
1020Sstevel@tonic-gate extern int authdes_cachesz;
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate * This routine adjusts the timeout used for calls to the remote rpcbind.
1050Sstevel@tonic-gate * Also, this routine can be used to set the use of portmapper version 2
1060Sstevel@tonic-gate * only when doing rpc_broadcasts
1070Sstevel@tonic-gate * These are private routines that may not be provided in future releases.
1080Sstevel@tonic-gate */
1090Sstevel@tonic-gate bool_t
__rpc_control(int request,void * info)110132Srobinson __rpc_control(int request, void *info)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate switch (request) {
1130Sstevel@tonic-gate case CLCR_GET_RPCB_TIMEOUT:
1140Sstevel@tonic-gate *(struct timeval *)info = tottimeout;
1150Sstevel@tonic-gate break;
1160Sstevel@tonic-gate case CLCR_SET_RPCB_TIMEOUT:
1170Sstevel@tonic-gate tottimeout = *(struct timeval *)info;
1180Sstevel@tonic-gate break;
1190Sstevel@tonic-gate case CLCR_GET_LOWVERS:
1200Sstevel@tonic-gate *(int *)info = lowvers;
1210Sstevel@tonic-gate break;
1220Sstevel@tonic-gate case CLCR_SET_LOWVERS:
1230Sstevel@tonic-gate lowvers = *(int *)info;
1240Sstevel@tonic-gate break;
1250Sstevel@tonic-gate case CLCR_GET_RPCB_RMTTIME:
1260Sstevel@tonic-gate *(struct timeval *)info = rpcbrmttime;
1270Sstevel@tonic-gate break;
1280Sstevel@tonic-gate case CLCR_SET_RPCB_RMTTIME:
1290Sstevel@tonic-gate rpcbrmttime = *(struct timeval *)info;
1300Sstevel@tonic-gate break;
1310Sstevel@tonic-gate case CLCR_GET_CRED_CACHE_SZ:
1320Sstevel@tonic-gate *(int *)info = authdes_cachesz;
1330Sstevel@tonic-gate break;
1340Sstevel@tonic-gate case CLCR_SET_CRED_CACHE_SZ:
1350Sstevel@tonic-gate authdes_cachesz = *(int *)info;
1360Sstevel@tonic-gate break;
1370Sstevel@tonic-gate default:
1380Sstevel@tonic-gate return (FALSE);
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate return (TRUE);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate * It might seem that a reader/writer lock would be more reasonable here.
1450Sstevel@tonic-gate * However because getclnthandle(), the only user of the cache functions,
1460Sstevel@tonic-gate * may do a delete_cache() operation if a check_cache() fails to return an
1470Sstevel@tonic-gate * address useful to clnt_tli_create(), we may as well use a mutex.
1480Sstevel@tonic-gate */
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate * As it turns out, if the cache lock is *not* a reader/writer lock, we will
1510Sstevel@tonic-gate * block all clnt_create's if we are trying to connect to a host that's down,
1520Sstevel@tonic-gate * since the lock will be held all during that time.
1530Sstevel@tonic-gate */
1540Sstevel@tonic-gate extern rwlock_t rpcbaddr_cache_lock;
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate * The routines check_cache(), add_cache(), delete_cache() manage the
1580Sstevel@tonic-gate * cache of rpcbind addresses for (host, netid).
1590Sstevel@tonic-gate */
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate static struct address_cache *
check_cache(char * host,char * netid)162132Srobinson check_cache(char *host, char *netid)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate struct address_cache *cptr;
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate assert(RW_READ_HELD(&rpcbaddr_cache_lock));
1690Sstevel@tonic-gate for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
1700Sstevel@tonic-gate if ((strcmp(cptr->ac_host, host) == 0) &&
1710Sstevel@tonic-gate (strcmp(cptr->ac_netid, netid) == 0) &&
1720Sstevel@tonic-gate (time(NULL) <= cptr->ac_maxtime)) {
1730Sstevel@tonic-gate #ifdef ND_DEBUG
1740Sstevel@tonic-gate fprintf(stderr, "Found cache entry for %s: %s\n",
1750Sstevel@tonic-gate host, netid);
1760Sstevel@tonic-gate #endif
1770Sstevel@tonic-gate return (cptr);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate }
180132Srobinson return (NULL);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate static void
delete_cache(struct netbuf * addr)184132Srobinson delete_cache(struct netbuf *addr)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate struct address_cache *cptr, *prevptr = NULL;
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
1890Sstevel@tonic-gate assert(RW_WRITE_HELD(&rpcbaddr_cache_lock));
1900Sstevel@tonic-gate for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
1910Sstevel@tonic-gate if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
1920Sstevel@tonic-gate free(cptr->ac_host);
1930Sstevel@tonic-gate free(cptr->ac_netid);
1940Sstevel@tonic-gate free(cptr->ac_taddr->buf);
1950Sstevel@tonic-gate free(cptr->ac_taddr);
1960Sstevel@tonic-gate if (cptr->ac_uaddr)
1970Sstevel@tonic-gate free(cptr->ac_uaddr);
1980Sstevel@tonic-gate if (prevptr)
1990Sstevel@tonic-gate prevptr->ac_next = cptr->ac_next;
2000Sstevel@tonic-gate else
2010Sstevel@tonic-gate front = cptr->ac_next;
2020Sstevel@tonic-gate free(cptr);
2030Sstevel@tonic-gate cachesize--;
2040Sstevel@tonic-gate break;
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate prevptr = cptr;
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate static void
add_cache(char * host,char * netid,struct netbuf * taddr,char * uaddr)211132Srobinson add_cache(char *host, char *netid, struct netbuf *taddr, char *uaddr)
2120Sstevel@tonic-gate {
2130Sstevel@tonic-gate struct address_cache *ad_cache, *cptr, *prevptr;
2140Sstevel@tonic-gate
215132Srobinson ad_cache = malloc(sizeof (struct address_cache));
2160Sstevel@tonic-gate if (!ad_cache) {
2170Sstevel@tonic-gate goto memerr;
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate ad_cache->ac_maxtime = time(NULL) + CACHE_TTL;
2200Sstevel@tonic-gate ad_cache->ac_host = strdup(host);
2210Sstevel@tonic-gate ad_cache->ac_netid = strdup(netid);
2220Sstevel@tonic-gate ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
223132Srobinson ad_cache->ac_taddr = malloc(sizeof (struct netbuf));
2240Sstevel@tonic-gate if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
2250Sstevel@tonic-gate (uaddr && !ad_cache->ac_uaddr)) {
2260Sstevel@tonic-gate goto memerr1;
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
230132Srobinson ad_cache->ac_taddr->buf = malloc(taddr->len);
2310Sstevel@tonic-gate if (ad_cache->ac_taddr->buf == NULL) {
2320Sstevel@tonic-gate goto memerr1;
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate
235132Srobinson (void) memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
2360Sstevel@tonic-gate #ifdef ND_DEBUG
237132Srobinson (void) fprintf(stderr, "Added to cache: %s : %s\n", host, netid);
2380Sstevel@tonic-gate #endif
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
2410Sstevel@tonic-gate
242132Srobinson (void) rw_wrlock(&rpcbaddr_cache_lock);
2430Sstevel@tonic-gate if (cachesize < CACHESIZE) {
2440Sstevel@tonic-gate ad_cache->ac_next = front;
2450Sstevel@tonic-gate front = ad_cache;
2460Sstevel@tonic-gate cachesize++;
2470Sstevel@tonic-gate } else {
2480Sstevel@tonic-gate /* Free the last entry */
2490Sstevel@tonic-gate cptr = front;
2500Sstevel@tonic-gate prevptr = NULL;
2510Sstevel@tonic-gate while (cptr->ac_next) {
2520Sstevel@tonic-gate prevptr = cptr;
2530Sstevel@tonic-gate cptr = cptr->ac_next;
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate #ifdef ND_DEBUG
2570Sstevel@tonic-gate fprintf(stderr, "Deleted from cache: %s : %s\n",
2580Sstevel@tonic-gate cptr->ac_host, cptr->ac_netid);
2590Sstevel@tonic-gate #endif
2600Sstevel@tonic-gate free(cptr->ac_host);
2610Sstevel@tonic-gate free(cptr->ac_netid);
2620Sstevel@tonic-gate free(cptr->ac_taddr->buf);
2630Sstevel@tonic-gate free(cptr->ac_taddr);
2640Sstevel@tonic-gate if (cptr->ac_uaddr)
2650Sstevel@tonic-gate free(cptr->ac_uaddr);
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate if (prevptr) {
2680Sstevel@tonic-gate prevptr->ac_next = NULL;
2690Sstevel@tonic-gate ad_cache->ac_next = front;
2700Sstevel@tonic-gate front = ad_cache;
2710Sstevel@tonic-gate } else {
2720Sstevel@tonic-gate front = ad_cache;
2730Sstevel@tonic-gate ad_cache->ac_next = NULL;
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate free(cptr);
2760Sstevel@tonic-gate }
277132Srobinson (void) rw_unlock(&rpcbaddr_cache_lock);
2780Sstevel@tonic-gate return;
2790Sstevel@tonic-gate memerr1:
2800Sstevel@tonic-gate if (ad_cache->ac_host)
2810Sstevel@tonic-gate free(ad_cache->ac_host);
2820Sstevel@tonic-gate if (ad_cache->ac_netid)
2830Sstevel@tonic-gate free(ad_cache->ac_netid);
2840Sstevel@tonic-gate if (ad_cache->ac_uaddr)
2850Sstevel@tonic-gate free(ad_cache->ac_uaddr);
2860Sstevel@tonic-gate if (ad_cache->ac_taddr)
2870Sstevel@tonic-gate free(ad_cache->ac_taddr);
2880Sstevel@tonic-gate free(ad_cache);
2890Sstevel@tonic-gate memerr:
2900Sstevel@tonic-gate syslog(LOG_ERR, "add_cache : out of memory.");
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate /*
2940Sstevel@tonic-gate * This routine will return a client handle that is connected to the
2950Sstevel@tonic-gate * rpcbind. Returns NULL on error and free's everything.
2960Sstevel@tonic-gate */
2970Sstevel@tonic-gate static CLIENT *
getclnthandle(char * host,struct netconfig * nconf,char ** targaddr)298132Srobinson getclnthandle(char *host, struct netconfig *nconf, char **targaddr)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate return (_getclnthandle_timed(host, nconf, targaddr, NULL));
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate /*
3040Sstevel@tonic-gate * Same as getclnthandle() except it takes an extra timeout argument.
3050Sstevel@tonic-gate * This is for bug 4049792: clnt_create_timed does not timeout.
3060Sstevel@tonic-gate *
3070Sstevel@tonic-gate * If tp is NULL, use default timeout to get a client handle.
3080Sstevel@tonic-gate */
3090Sstevel@tonic-gate static CLIENT *
_getclnthandle_timed(char * host,struct netconfig * nconf,char ** targaddr,struct timeval * tp)310132Srobinson _getclnthandle_timed(char *host, struct netconfig *nconf, char **targaddr,
311132Srobinson struct timeval *tp)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate CLIENT *client = NULL;
3140Sstevel@tonic-gate struct netbuf *addr;
3150Sstevel@tonic-gate struct netbuf addr_to_delete;
3160Sstevel@tonic-gate struct nd_addrlist *nas;
3170Sstevel@tonic-gate struct nd_hostserv rpcbind_hs;
3180Sstevel@tonic-gate struct address_cache *ad_cache;
3190Sstevel@tonic-gate char *tmpaddr;
3200Sstevel@tonic-gate int neterr;
3210Sstevel@tonic-gate int j;
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate /* Get the address of the rpcbind. Check cache first */
3260Sstevel@tonic-gate addr_to_delete.len = 0;
327132Srobinson (void) rw_rdlock(&rpcbaddr_cache_lock);
3280Sstevel@tonic-gate ad_cache = check_cache(host, nconf->nc_netid);
3290Sstevel@tonic-gate if (ad_cache != NULL) {
3300Sstevel@tonic-gate addr = ad_cache->ac_taddr;
3310Sstevel@tonic-gate client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr,
3320Sstevel@tonic-gate RPCBPROG, RPCBVERS4, 0, 0, tp);
3330Sstevel@tonic-gate if (client != NULL) {
3340Sstevel@tonic-gate if (targaddr) {
3350Sstevel@tonic-gate /*
3360Sstevel@tonic-gate * case where a client handle is created
3370Sstevel@tonic-gate * without a targaddr and the handle is
3380Sstevel@tonic-gate * requested with a targaddr
3390Sstevel@tonic-gate */
3400Sstevel@tonic-gate if (ad_cache->ac_uaddr != NULL) {
3410Sstevel@tonic-gate *targaddr = strdup(ad_cache->ac_uaddr);
3420Sstevel@tonic-gate if (*targaddr == NULL) {
3430Sstevel@tonic-gate syslog(LOG_ERR,
3440Sstevel@tonic-gate "_getclnthandle_timed: strdup "
3450Sstevel@tonic-gate "failed.");
3460Sstevel@tonic-gate rpc_createerr.cf_stat =
3470Sstevel@tonic-gate RPC_SYSTEMERROR;
348132Srobinson (void) rw_unlock(
349132Srobinson &rpcbaddr_cache_lock);
350132Srobinson return (NULL);
3510Sstevel@tonic-gate }
352132Srobinson } else {
353132Srobinson *targaddr = NULL;
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate }
356132Srobinson (void) rw_unlock(&rpcbaddr_cache_lock);
3570Sstevel@tonic-gate return (client);
358132Srobinson }
359132Srobinson if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) {
360132Srobinson (void) rw_unlock(&rpcbaddr_cache_lock);
361132Srobinson return (NULL);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate addr_to_delete.len = addr->len;
364132Srobinson addr_to_delete.buf = malloc(addr->len);
3650Sstevel@tonic-gate if (addr_to_delete.buf == NULL) {
3660Sstevel@tonic-gate addr_to_delete.len = 0;
3670Sstevel@tonic-gate } else {
368132Srobinson (void) memcpy(addr_to_delete.buf, addr->buf, addr->len);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate }
371132Srobinson (void) rw_unlock(&rpcbaddr_cache_lock);
3720Sstevel@tonic-gate if (addr_to_delete.len != 0) {
3730Sstevel@tonic-gate /*
3740Sstevel@tonic-gate * Assume this may be due to cache data being
3750Sstevel@tonic-gate * outdated
3760Sstevel@tonic-gate */
377132Srobinson (void) rw_wrlock(&rpcbaddr_cache_lock);
3780Sstevel@tonic-gate delete_cache(&addr_to_delete);
379132Srobinson (void) rw_unlock(&rpcbaddr_cache_lock);
3800Sstevel@tonic-gate free(addr_to_delete.buf);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate rpcbind_hs.h_host = host;
3830Sstevel@tonic-gate rpcbind_hs.h_serv = "rpcbind";
3840Sstevel@tonic-gate #ifdef ND_DEBUG
3850Sstevel@tonic-gate fprintf(stderr, "rpcbind client routines: diagnostics :\n");
3860Sstevel@tonic-gate fprintf(stderr, "\tGetting address for (%s, %s, %s) ... \n",
3870Sstevel@tonic-gate rpcbind_hs.h_host, rpcbind_hs.h_serv, nconf->nc_netid);
3880Sstevel@tonic-gate #endif
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate if ((neterr = netdir_getbyname(nconf, &rpcbind_hs, &nas)) != 0) {
3910Sstevel@tonic-gate if (neterr == ND_NOHOST)
3920Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
3930Sstevel@tonic-gate else
3940Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
395132Srobinson return (NULL);
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate /* XXX nas should perhaps be cached for better performance */
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate for (j = 0; j < nas->n_cnt; j++) {
4000Sstevel@tonic-gate addr = &(nas->n_addrs[j]);
4010Sstevel@tonic-gate #ifdef ND_DEBUG
4020Sstevel@tonic-gate {
4030Sstevel@tonic-gate int i;
4040Sstevel@tonic-gate char *ua;
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate ua = taddr2uaddr(nconf, &(nas->n_addrs[j]));
4070Sstevel@tonic-gate fprintf(stderr, "Got it [%s]\n", ua);
4080Sstevel@tonic-gate free(ua);
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n",
4110Sstevel@tonic-gate addr->len, addr->maxlen);
4120Sstevel@tonic-gate fprintf(stderr, "\tAddress is ");
4130Sstevel@tonic-gate for (i = 0; i < addr->len; i++)
4140Sstevel@tonic-gate fprintf(stderr, "%u.", addr->buf[i]);
4150Sstevel@tonic-gate fprintf(stderr, "\n");
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate #endif
4180Sstevel@tonic-gate client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr, RPCBPROG,
4190Sstevel@tonic-gate RPCBVERS4, 0, 0, tp);
4200Sstevel@tonic-gate if (client)
4210Sstevel@tonic-gate break;
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate #ifdef ND_DEBUG
424132Srobinson if (!client) {
4250Sstevel@tonic-gate clnt_pcreateerror("rpcbind clnt interface");
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate #endif
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate if (client) {
4300Sstevel@tonic-gate tmpaddr = targaddr ? taddr2uaddr(nconf, addr) : NULL;
4310Sstevel@tonic-gate add_cache(host, nconf->nc_netid, addr, tmpaddr);
4320Sstevel@tonic-gate if (targaddr) {
4330Sstevel@tonic-gate *targaddr = tmpaddr;
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate netdir_free((char *)nas, ND_ADDRLIST);
4370Sstevel@tonic-gate return (client);
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate /*
4410Sstevel@tonic-gate * This routine will return a client handle that is connected to the local
4420Sstevel@tonic-gate * rpcbind. Returns NULL on error and free's everything.
4430Sstevel@tonic-gate */
4440Sstevel@tonic-gate static CLIENT *
local_rpcb(void)445132Srobinson local_rpcb(void)
4460Sstevel@tonic-gate {
4470Sstevel@tonic-gate static struct netconfig *loopnconf;
4480Sstevel@tonic-gate static char *hostname;
4490Sstevel@tonic-gate extern mutex_t loopnconf_lock;
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
452132Srobinson (void) mutex_lock(&loopnconf_lock);
4530Sstevel@tonic-gate if (loopnconf == NULL) {
4540Sstevel@tonic-gate struct utsname utsname;
4550Sstevel@tonic-gate struct netconfig *nconf, *tmpnconf = NULL;
4560Sstevel@tonic-gate void *nc_handle;
4570Sstevel@tonic-gate
458132Srobinson if (hostname == NULL) {
4590Sstevel@tonic-gate #if defined(__i386) && !defined(__amd64)
4600Sstevel@tonic-gate if ((_nuname(&utsname) == -1) ||
4610Sstevel@tonic-gate #else
462*1219Sraf if ((uname(&utsname) == -1) ||
4630Sstevel@tonic-gate #endif
4640Sstevel@tonic-gate ((hostname = strdup(utsname.nodename)) == NULL)) {
4650Sstevel@tonic-gate syslog(LOG_ERR, "local_rpcb : strdup failed.");
4660Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
467132Srobinson (void) mutex_unlock(&loopnconf_lock);
468132Srobinson return (NULL);
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate nc_handle = setnetconfig();
4720Sstevel@tonic-gate if (nc_handle == NULL) {
4730Sstevel@tonic-gate /* fails to open netconfig file */
4740Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
475132Srobinson (void) mutex_unlock(&loopnconf_lock);
4760Sstevel@tonic-gate return (NULL);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate while (nconf = getnetconfig(nc_handle)) {
4790Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
4800Sstevel@tonic-gate tmpnconf = nconf;
4810Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_CLTS)
4820Sstevel@tonic-gate break;
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate if (tmpnconf == NULL) {
4860Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
487132Srobinson (void) mutex_unlock(&loopnconf_lock);
4880Sstevel@tonic-gate return (NULL);
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate loopnconf = getnetconfigent(tmpnconf->nc_netid);
4910Sstevel@tonic-gate /* loopnconf is never freed */
492132Srobinson (void) endnetconfig(nc_handle);
4930Sstevel@tonic-gate }
494132Srobinson (void) mutex_unlock(&loopnconf_lock);
495132Srobinson return (getclnthandle(hostname, loopnconf, NULL));
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate * Set a mapping between program, version and address.
5000Sstevel@tonic-gate * Calls the rpcbind service to do the mapping.
5010Sstevel@tonic-gate */
5020Sstevel@tonic-gate bool_t
rpcb_set(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf,const struct netbuf * address)503132Srobinson rpcb_set(const rpcprog_t program, const rpcvers_t version,
504132Srobinson const struct netconfig *nconf, const struct netbuf *address)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate CLIENT *client;
5070Sstevel@tonic-gate bool_t rslt = FALSE;
5080Sstevel@tonic-gate RPCB parms;
5090Sstevel@tonic-gate char uidbuf[32];
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /* parameter checking */
512132Srobinson if (nconf == NULL) {
5130Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
5140Sstevel@tonic-gate return (FALSE);
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate if (address == NULL) {
5170Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
5180Sstevel@tonic-gate return (FALSE);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate client = local_rpcb();
521132Srobinson if (!client)
5220Sstevel@tonic-gate return (FALSE);
5230Sstevel@tonic-gate
524132Srobinson parms.r_addr = taddr2uaddr((struct netconfig *)nconf,
525132Srobinson (struct netbuf *)address); /* convert to universal */
5260Sstevel@tonic-gate if (!parms.r_addr) {
5270Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
5280Sstevel@tonic-gate return (FALSE); /* no universal address */
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate parms.r_prog = program;
5310Sstevel@tonic-gate parms.r_vers = version;
5320Sstevel@tonic-gate parms.r_netid = nconf->nc_netid;
5330Sstevel@tonic-gate /*
5340Sstevel@tonic-gate * Though uid is not being used directly, we still send it for
5350Sstevel@tonic-gate * completeness. For non-unix platforms, perhaps some other
5360Sstevel@tonic-gate * string or an empty string can be sent.
5370Sstevel@tonic-gate */
538132Srobinson (void) sprintf(uidbuf, "%d", (int)geteuid());
5390Sstevel@tonic-gate parms.r_owner = uidbuf;
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate CLNT_CALL(client, RPCBPROC_SET, (xdrproc_t)xdr_rpcb, (char *)&parms,
5420Sstevel@tonic-gate (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate CLNT_DESTROY(client);
5450Sstevel@tonic-gate free(parms.r_addr);
5460Sstevel@tonic-gate return (rslt);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate /*
5500Sstevel@tonic-gate * Remove the mapping between program, version and netbuf address.
5510Sstevel@tonic-gate * Calls the rpcbind service to do the un-mapping.
5520Sstevel@tonic-gate * If netbuf is NULL, unset for all the transports, otherwise unset
5530Sstevel@tonic-gate * only for the given transport.
5540Sstevel@tonic-gate */
5550Sstevel@tonic-gate bool_t
rpcb_unset(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf)556132Srobinson rpcb_unset(const rpcprog_t program, const rpcvers_t version,
557132Srobinson const struct netconfig *nconf)
5580Sstevel@tonic-gate {
5590Sstevel@tonic-gate CLIENT *client;
5600Sstevel@tonic-gate bool_t rslt = FALSE;
5610Sstevel@tonic-gate RPCB parms;
5620Sstevel@tonic-gate char uidbuf[32];
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate client = local_rpcb();
565132Srobinson if (!client)
5660Sstevel@tonic-gate return (FALSE);
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate parms.r_prog = program;
5690Sstevel@tonic-gate parms.r_vers = version;
5700Sstevel@tonic-gate if (nconf)
5710Sstevel@tonic-gate parms.r_netid = nconf->nc_netid;
5720Sstevel@tonic-gate else
5730Sstevel@tonic-gate parms.r_netid = (char *)&nullstring[0]; /* unsets all */
5740Sstevel@tonic-gate parms.r_addr = (char *)&nullstring[0];
575132Srobinson (void) sprintf(uidbuf, "%d", (int)geteuid());
5760Sstevel@tonic-gate parms.r_owner = uidbuf;
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate CLNT_CALL(client, RPCBPROC_UNSET, (xdrproc_t)xdr_rpcb, (char *)&parms,
5790Sstevel@tonic-gate (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate CLNT_DESTROY(client);
5820Sstevel@tonic-gate return (rslt);
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate /*
5860Sstevel@tonic-gate * From the merged list, find the appropriate entry
5870Sstevel@tonic-gate */
5880Sstevel@tonic-gate static struct netbuf *
got_entry(rpcb_entry_list_ptr relp,struct netconfig * nconf)589132Srobinson got_entry(rpcb_entry_list_ptr relp, struct netconfig *nconf)
5900Sstevel@tonic-gate {
5910Sstevel@tonic-gate struct netbuf *na = NULL;
5920Sstevel@tonic-gate rpcb_entry_list_ptr sp;
5930Sstevel@tonic-gate rpcb_entry *rmap;
5940Sstevel@tonic-gate
5950Sstevel@tonic-gate for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
5960Sstevel@tonic-gate rmap = &sp->rpcb_entry_map;
5970Sstevel@tonic-gate if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
5980Sstevel@tonic-gate (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
5990Sstevel@tonic-gate (nconf->nc_semantics == rmap->r_nc_semantics) &&
6000Sstevel@tonic-gate (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != NULL)) {
6010Sstevel@tonic-gate na = uaddr2taddr(nconf, rmap->r_maddr);
6020Sstevel@tonic-gate #ifdef ND_DEBUG
6030Sstevel@tonic-gate fprintf(stderr, "\tRemote address is [%s].\n",
6040Sstevel@tonic-gate rmap->r_maddr);
6050Sstevel@tonic-gate if (!na)
6060Sstevel@tonic-gate fprintf(stderr,
6070Sstevel@tonic-gate "\tCouldn't resolve remote address!\n");
6080Sstevel@tonic-gate #endif
6090Sstevel@tonic-gate break;
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate return (na);
6130Sstevel@tonic-gate }
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate /*
6160Sstevel@tonic-gate * Quick check to see if rpcbind is up. Tries to connect over
6170Sstevel@tonic-gate * local transport.
6180Sstevel@tonic-gate */
6190Sstevel@tonic-gate bool_t
__rpcbind_is_up(void)620132Srobinson __rpcbind_is_up(void)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate struct utsname name;
6230Sstevel@tonic-gate char uaddr[SYS_NMLN];
6240Sstevel@tonic-gate struct netbuf *addr;
6250Sstevel@tonic-gate int fd;
6260Sstevel@tonic-gate struct t_call *sndcall;
6270Sstevel@tonic-gate struct netconfig *netconf;
6280Sstevel@tonic-gate bool_t res;
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate #if defined(__i386) && !defined(__amd64)
6310Sstevel@tonic-gate if (_nuname(&name) == -1)
6320Sstevel@tonic-gate #else
633*1219Sraf if (uname(&name) == -1)
6340Sstevel@tonic-gate #endif
6350Sstevel@tonic-gate return (TRUE);
6360Sstevel@tonic-gate
6370Sstevel@tonic-gate if ((fd = t_open("/dev/ticotsord", O_RDWR, NULL)) == -1)
6380Sstevel@tonic-gate return (TRUE);
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate if (t_bind(fd, NULL, NULL) == -1) {
641132Srobinson (void) t_close(fd);
6420Sstevel@tonic-gate return (TRUE);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate
645132Srobinson /* LINTED pointer cast */
6460Sstevel@tonic-gate if ((sndcall = (struct t_call *)t_alloc(fd, T_CALL, 0)) == NULL) {
647132Srobinson (void) t_close(fd);
6480Sstevel@tonic-gate return (TRUE);
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate uaddr[0] = '\0';
652132Srobinson (void) strcpy(uaddr, name.nodename);
653132Srobinson (void) strcat(uaddr, ".rpc");
6540Sstevel@tonic-gate if ((netconf = getnetconfigent("ticotsord")) == NULL) {
655132Srobinson (void) t_free((char *)sndcall, T_CALL);
656132Srobinson (void) t_close(fd);
6570Sstevel@tonic-gate return (FALSE);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate addr = uaddr2taddr(netconf, uaddr);
6600Sstevel@tonic-gate freenetconfigent(netconf);
6610Sstevel@tonic-gate if (addr == NULL || addr->buf == NULL) {
6620Sstevel@tonic-gate if (addr)
663132Srobinson free(addr);
664132Srobinson (void) t_free((char *)sndcall, T_CALL);
665132Srobinson (void) t_close(fd);
6660Sstevel@tonic-gate return (FALSE);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate sndcall->addr.maxlen = addr->maxlen;
6690Sstevel@tonic-gate sndcall->addr.len = addr->len;
6700Sstevel@tonic-gate sndcall->addr.buf = addr->buf;
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate if (t_connect(fd, sndcall, NULL) == -1)
6730Sstevel@tonic-gate res = FALSE;
6740Sstevel@tonic-gate else
6750Sstevel@tonic-gate res = TRUE;
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate sndcall->addr.maxlen = sndcall->addr.len = 0;
6780Sstevel@tonic-gate sndcall->addr.buf = NULL;
679132Srobinson (void) t_free((char *)sndcall, T_CALL);
680132Srobinson free(addr->buf);
681132Srobinson free(addr);
682132Srobinson (void) t_close(fd);
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate return (res);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate /*
6890Sstevel@tonic-gate * An internal function which optimizes rpcb_getaddr function. It also
6900Sstevel@tonic-gate * returns the client handle that it uses to contact the remote rpcbind.
6910Sstevel@tonic-gate *
6920Sstevel@tonic-gate * The algorithm used: If the transports is TCP or UDP, it first tries
6930Sstevel@tonic-gate * version 2 (portmap), 4 and then 3 (svr4). This order should be
6940Sstevel@tonic-gate * changed in the next OS release to 4, 2 and 3. We are assuming that by
6950Sstevel@tonic-gate * that time, version 4 would be available on many machines on the network.
6960Sstevel@tonic-gate * With this algorithm, we get performance as well as a plan for
6970Sstevel@tonic-gate * obsoleting version 2.
6980Sstevel@tonic-gate *
6990Sstevel@tonic-gate * For all other transports, the algorithm remains as 4 and then 3.
7000Sstevel@tonic-gate *
7010Sstevel@tonic-gate * XXX: Due to some problems with t_connect(), we do not reuse the same client
7020Sstevel@tonic-gate * handle for COTS cases and hence in these cases we do not return the
7030Sstevel@tonic-gate * client handle. This code will change if t_connect() ever
7040Sstevel@tonic-gate * starts working properly. Also look under clnt_vc.c.
7050Sstevel@tonic-gate */
7060Sstevel@tonic-gate struct netbuf *
__rpcb_findaddr_timed(rpcprog_t program,rpcvers_t version,struct netconfig * nconf,char * host,CLIENT ** clpp,struct timeval * tp)707132Srobinson __rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version,
708132Srobinson struct netconfig *nconf, char *host, CLIENT **clpp, struct timeval *tp)
7090Sstevel@tonic-gate {
7100Sstevel@tonic-gate static bool_t check_rpcbind = TRUE;
7110Sstevel@tonic-gate CLIENT *client = NULL;
7120Sstevel@tonic-gate RPCB parms;
7130Sstevel@tonic-gate enum clnt_stat clnt_st;
7140Sstevel@tonic-gate char *ua = NULL;
7150Sstevel@tonic-gate uint_t vers;
7160Sstevel@tonic-gate struct netbuf *address = NULL;
7170Sstevel@tonic-gate uint_t start_vers = RPCBVERS4;
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate /* parameter checking */
720132Srobinson if (nconf == NULL) {
7210Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
7220Sstevel@tonic-gate return (NULL);
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate
7250Sstevel@tonic-gate parms.r_addr = NULL;
7260Sstevel@tonic-gate
7270Sstevel@tonic-gate /*
7280Sstevel@tonic-gate * Use default total timeout if no timeout is specified.
7290Sstevel@tonic-gate */
7300Sstevel@tonic-gate if (tp == NULL)
7310Sstevel@tonic-gate tp = &tottimeout;
7320Sstevel@tonic-gate
7330Sstevel@tonic-gate #ifdef PORTMAP
7340Sstevel@tonic-gate /* Try version 2 for TCP or UDP */
7350Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
7360Sstevel@tonic-gate ushort_t port = 0;
7370Sstevel@tonic-gate struct netbuf remote;
7380Sstevel@tonic-gate uint_t pmapvers = 2;
7390Sstevel@tonic-gate struct pmap pmapparms;
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate /*
7420Sstevel@tonic-gate * Try UDP only - there are some portmappers out
7430Sstevel@tonic-gate * there that use UDP only.
7440Sstevel@tonic-gate */
7450Sstevel@tonic-gate if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
7460Sstevel@tonic-gate struct netconfig *newnconf;
7470Sstevel@tonic-gate void *handle;
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate if ((handle = __rpc_setconf("udp")) == NULL) {
7500Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
7510Sstevel@tonic-gate return (NULL);
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate /*
7550Sstevel@tonic-gate * The following to reinforce that you can
7560Sstevel@tonic-gate * only request for remote address through
7570Sstevel@tonic-gate * the same transport you are requesting.
7580Sstevel@tonic-gate * ie. requesting unversial address
7590Sstevel@tonic-gate * of IPv4 has to be carried through IPv4.
7600Sstevel@tonic-gate * Can't use IPv6 to send out the request.
7610Sstevel@tonic-gate * The mergeaddr in rpcbind can't handle
7620Sstevel@tonic-gate * this.
7630Sstevel@tonic-gate */
764132Srobinson for (;;) {
7650Sstevel@tonic-gate if ((newnconf = __rpc_getconf(handle))
766132Srobinson == NULL) {
7670Sstevel@tonic-gate __rpc_endconf(handle);
768132Srobinson rpc_createerr.cf_stat =
7690Sstevel@tonic-gate RPC_UNKNOWNPROTO;
7700Sstevel@tonic-gate return (NULL);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate /*
7730Sstevel@tonic-gate * here check the protocol family to
7740Sstevel@tonic-gate * be consistent with the request one
7750Sstevel@tonic-gate */
7760Sstevel@tonic-gate if (strcmp(newnconf->nc_protofmly,
7770Sstevel@tonic-gate nconf->nc_protofmly) == NULL)
7780Sstevel@tonic-gate break;
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate client = _getclnthandle_timed(host, newnconf,
7820Sstevel@tonic-gate &parms.r_addr, tp);
7830Sstevel@tonic-gate __rpc_endconf(handle);
7840Sstevel@tonic-gate } else {
7850Sstevel@tonic-gate client = _getclnthandle_timed(host, nconf,
7860Sstevel@tonic-gate &parms.r_addr, tp);
7870Sstevel@tonic-gate }
788132Srobinson if (client == NULL)
7890Sstevel@tonic-gate return (NULL);
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate /*
7920Sstevel@tonic-gate * Set version and retry timeout.
7930Sstevel@tonic-gate */
7940Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
7950Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
7960Sstevel@tonic-gate
7970Sstevel@tonic-gate pmapparms.pm_prog = program;
7980Sstevel@tonic-gate pmapparms.pm_vers = version;
7990Sstevel@tonic-gate pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
8000Sstevel@tonic-gate IPPROTO_UDP : IPPROTO_TCP;
8010Sstevel@tonic-gate pmapparms.pm_port = 0; /* not needed */
8020Sstevel@tonic-gate clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT,
8030Sstevel@tonic-gate (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms,
8040Sstevel@tonic-gate (xdrproc_t)xdr_u_short, (caddr_t)&port,
8050Sstevel@tonic-gate *tp);
8060Sstevel@tonic-gate if (clnt_st != RPC_SUCCESS) {
8070Sstevel@tonic-gate if ((clnt_st == RPC_PROGVERSMISMATCH) ||
8080Sstevel@tonic-gate (clnt_st == RPC_PROGUNAVAIL))
8090Sstevel@tonic-gate goto try_rpcbind; /* Try different versions */
8100Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_PMAPFAILURE;
8110Sstevel@tonic-gate clnt_geterr(client, &rpc_createerr.cf_error);
8120Sstevel@tonic-gate goto error;
8130Sstevel@tonic-gate } else if (port == 0) {
8140Sstevel@tonic-gate address = NULL;
8150Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
8160Sstevel@tonic-gate goto error;
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate port = htons(port);
8190Sstevel@tonic-gate CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
820132Srobinson if (((address = malloc(sizeof (struct netbuf))) == NULL) ||
821132Srobinson ((address->buf = malloc(remote.len)) == NULL)) {
8220Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR;
8230Sstevel@tonic-gate clnt_geterr(client, &rpc_createerr.cf_error);
8240Sstevel@tonic-gate if (address) {
8250Sstevel@tonic-gate free(address);
8260Sstevel@tonic-gate address = NULL;
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate goto error;
8290Sstevel@tonic-gate }
830132Srobinson (void) memcpy(address->buf, remote.buf, remote.len);
831132Srobinson (void) memcpy(&address->buf[sizeof (short)], &port,
832132Srobinson sizeof (short));
8330Sstevel@tonic-gate address->len = address->maxlen = remote.len;
8340Sstevel@tonic-gate goto done;
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate #endif
8370Sstevel@tonic-gate
8380Sstevel@tonic-gate try_rpcbind:
8390Sstevel@tonic-gate /*
8400Sstevel@tonic-gate * Check if rpcbind is up. This prevents needless delays when
8410Sstevel@tonic-gate * accessing applications such as the keyserver while booting
8420Sstevel@tonic-gate * disklessly.
8430Sstevel@tonic-gate */
8440Sstevel@tonic-gate if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
8450Sstevel@tonic-gate if (!__rpcbind_is_up()) {
8460Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_PMAPFAILURE;
8470Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = 0;
8480Sstevel@tonic-gate rpc_createerr.cf_error.re_terrno = 0;
8490Sstevel@tonic-gate goto error;
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate check_rpcbind = FALSE;
8520Sstevel@tonic-gate }
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate /*
8550Sstevel@tonic-gate * Now we try version 4 and then 3.
8560Sstevel@tonic-gate * We also send the remote system the address we used to
8570Sstevel@tonic-gate * contact it in case it can help to connect back with us
8580Sstevel@tonic-gate */
8590Sstevel@tonic-gate parms.r_prog = program;
8600Sstevel@tonic-gate parms.r_vers = version;
8610Sstevel@tonic-gate parms.r_owner = (char *)&nullstring[0]; /* not needed; */
8620Sstevel@tonic-gate /* just for xdring */
8630Sstevel@tonic-gate parms.r_netid = nconf->nc_netid; /* not really needed */
8640Sstevel@tonic-gate
8650Sstevel@tonic-gate /*
8660Sstevel@tonic-gate * If a COTS transport is being used, try getting address via CLTS
8670Sstevel@tonic-gate * transport. This works only with version 4.
8680Sstevel@tonic-gate */
8690Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
8700Sstevel@tonic-gate nconf->nc_semantics == NC_TPI_COTS) {
8710Sstevel@tonic-gate void *handle;
8720Sstevel@tonic-gate struct netconfig *nconf_clts;
8730Sstevel@tonic-gate rpcb_entry_list_ptr relp = NULL;
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate if (client == NULL) {
8760Sstevel@tonic-gate /* This did not go through the above PORTMAP/TCP code */
8770Sstevel@tonic-gate if ((handle = __rpc_setconf("datagram_v")) != NULL) {
8780Sstevel@tonic-gate while ((nconf_clts = __rpc_getconf(handle))
8790Sstevel@tonic-gate != NULL) {
8800Sstevel@tonic-gate if (strcmp(nconf_clts->nc_protofmly,
8810Sstevel@tonic-gate nconf->nc_protofmly) != 0) {
8820Sstevel@tonic-gate continue;
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate client = _getclnthandle_timed(host,
8850Sstevel@tonic-gate nconf_clts, &parms.r_addr,
8860Sstevel@tonic-gate tp);
8870Sstevel@tonic-gate break;
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate __rpc_endconf(handle);
8900Sstevel@tonic-gate }
891132Srobinson if (client == NULL)
8920Sstevel@tonic-gate goto regular_rpcbind; /* Go the regular way */
8930Sstevel@tonic-gate } else {
8940Sstevel@tonic-gate /* This is a UDP PORTMAP handle. Change to version 4 */
8950Sstevel@tonic-gate vers = RPCBVERS4;
8960Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate /*
8990Sstevel@tonic-gate * We also send the remote system the address we used to
9000Sstevel@tonic-gate * contact it in case it can help it connect back with us
9010Sstevel@tonic-gate */
9020Sstevel@tonic-gate if (parms.r_addr == NULL) {
9030Sstevel@tonic-gate parms.r_addr = strdup(""); /* for XDRing */
9040Sstevel@tonic-gate if (parms.r_addr == NULL) {
9050Sstevel@tonic-gate syslog(LOG_ERR, "__rpcb_findaddr_timed: "
9060Sstevel@tonic-gate "strdup failed.");
9070Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR;
9080Sstevel@tonic-gate address = NULL;
9090Sstevel@tonic-gate goto error;
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate clnt_st = CLNT_CALL(client, RPCBPROC_GETADDRLIST,
9160Sstevel@tonic-gate (xdrproc_t)xdr_rpcb, (char *)&parms,
9170Sstevel@tonic-gate (xdrproc_t)xdr_rpcb_entry_list_ptr,
9180Sstevel@tonic-gate (char *)&relp, *tp);
9190Sstevel@tonic-gate if (clnt_st == RPC_SUCCESS) {
9200Sstevel@tonic-gate if (address = got_entry(relp, nconf)) {
9210Sstevel@tonic-gate xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
9220Sstevel@tonic-gate (char *)&relp);
9230Sstevel@tonic-gate goto done;
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate /* Entry not found for this transport */
9260Sstevel@tonic-gate xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
9270Sstevel@tonic-gate (char *)&relp);
9280Sstevel@tonic-gate /*
9290Sstevel@tonic-gate * XXX: should have perhaps returned with error but
9300Sstevel@tonic-gate * since the remote machine might not always be able
9310Sstevel@tonic-gate * to send the address on all transports, we try the
9320Sstevel@tonic-gate * regular way with regular_rpcbind
9330Sstevel@tonic-gate */
9340Sstevel@tonic-gate goto regular_rpcbind;
9350Sstevel@tonic-gate } else if ((clnt_st == RPC_PROGVERSMISMATCH) ||
9360Sstevel@tonic-gate (clnt_st == RPC_PROGUNAVAIL)) {
9370Sstevel@tonic-gate start_vers = RPCBVERS; /* Try version 3 now */
9380Sstevel@tonic-gate goto regular_rpcbind; /* Try different versions */
9390Sstevel@tonic-gate } else {
9400Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_PMAPFAILURE;
9410Sstevel@tonic-gate clnt_geterr(client, &rpc_createerr.cf_error);
9420Sstevel@tonic-gate goto error;
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate }
9450Sstevel@tonic-gate
9460Sstevel@tonic-gate regular_rpcbind:
9470Sstevel@tonic-gate
9480Sstevel@tonic-gate /* Now the same transport is to be used to get the address */
9490Sstevel@tonic-gate if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
9500Sstevel@tonic-gate (nconf->nc_semantics == NC_TPI_COTS))) {
9510Sstevel@tonic-gate /* A CLTS type of client - destroy it */
9520Sstevel@tonic-gate CLNT_DESTROY(client);
9530Sstevel@tonic-gate client = NULL;
9541193Smws free(parms.r_addr);
9551193Smws parms.r_addr = NULL;
9560Sstevel@tonic-gate }
9570Sstevel@tonic-gate
9580Sstevel@tonic-gate if (client == NULL) {
9590Sstevel@tonic-gate client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
9600Sstevel@tonic-gate if (client == NULL) {
9610Sstevel@tonic-gate address = NULL;
9620Sstevel@tonic-gate goto error;
9630Sstevel@tonic-gate }
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate if (parms.r_addr == NULL) {
9660Sstevel@tonic-gate parms.r_addr = strdup(""); /* for XDRing */
9670Sstevel@tonic-gate if (parms.r_addr == NULL) {
9680Sstevel@tonic-gate syslog(LOG_ERR, "__rpcb_findaddr_timed: "
9690Sstevel@tonic-gate "strdup failed.");
9700Sstevel@tonic-gate address = NULL;
9710Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR;
9720Sstevel@tonic-gate goto error;
9730Sstevel@tonic-gate }
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate
9760Sstevel@tonic-gate /* First try from start_vers and then version 3 (RPCBVERS) */
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
9790Sstevel@tonic-gate for (vers = start_vers; vers >= RPCBVERS; vers--) {
9800Sstevel@tonic-gate /* Set the version */
9810Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
9820Sstevel@tonic-gate clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR,
9830Sstevel@tonic-gate (xdrproc_t)xdr_rpcb, (char *)&parms,
9840Sstevel@tonic-gate (xdrproc_t)xdr_wrapstring,
9850Sstevel@tonic-gate (char *)&ua, *tp);
9860Sstevel@tonic-gate if (clnt_st == RPC_SUCCESS) {
9870Sstevel@tonic-gate if ((ua == NULL) || (ua[0] == NULL)) {
9881193Smws if (ua != NULL)
9891193Smws xdr_free(xdr_wrapstring, (char *)&ua);
9901193Smws
9910Sstevel@tonic-gate /* address unknown */
9920Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
9930Sstevel@tonic-gate goto error;
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate address = uaddr2taddr(nconf, ua);
9960Sstevel@tonic-gate #ifdef ND_DEBUG
9970Sstevel@tonic-gate fprintf(stderr, "\tRemote address is [%s]\n", ua);
9980Sstevel@tonic-gate if (!address)
9990Sstevel@tonic-gate fprintf(stderr,
10000Sstevel@tonic-gate "\tCouldn't resolve remote address!\n");
10010Sstevel@tonic-gate #endif
10020Sstevel@tonic-gate xdr_free((xdrproc_t)xdr_wrapstring, (char *)&ua);
10030Sstevel@tonic-gate
1004132Srobinson if (!address) {
10050Sstevel@tonic-gate /* We don't know about your universal address */
10060Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
10070Sstevel@tonic-gate goto error;
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate goto done;
1010132Srobinson }
1011132Srobinson if (clnt_st == RPC_PROGVERSMISMATCH) {
10120Sstevel@tonic-gate struct rpc_err rpcerr;
10130Sstevel@tonic-gate
10140Sstevel@tonic-gate clnt_geterr(client, &rpcerr);
10150Sstevel@tonic-gate if (rpcerr.re_vers.low > RPCBVERS4)
10160Sstevel@tonic-gate goto error; /* a new version, can't handle */
10170Sstevel@tonic-gate } else if (clnt_st != RPC_PROGUNAVAIL) {
10180Sstevel@tonic-gate /* Cant handle this error */
10190Sstevel@tonic-gate goto error;
10200Sstevel@tonic-gate }
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate
10230Sstevel@tonic-gate if ((address == NULL) || (address->len == 0)) {
10240Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
10250Sstevel@tonic-gate clnt_geterr(client, &rpc_createerr.cf_error);
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate error:
10290Sstevel@tonic-gate if (client) {
10300Sstevel@tonic-gate CLNT_DESTROY(client);
10310Sstevel@tonic-gate client = NULL;
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate done:
10340Sstevel@tonic-gate if (nconf->nc_semantics != NC_TPI_CLTS) {
10350Sstevel@tonic-gate /* This client is the connectionless one */
10360Sstevel@tonic-gate if (client) {
10370Sstevel@tonic-gate CLNT_DESTROY(client);
10380Sstevel@tonic-gate client = NULL;
10390Sstevel@tonic-gate }
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate if (clpp) {
10420Sstevel@tonic-gate *clpp = client;
10430Sstevel@tonic-gate } else if (client) {
10440Sstevel@tonic-gate CLNT_DESTROY(client);
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate if (parms.r_addr)
10470Sstevel@tonic-gate free(parms.r_addr);
10480Sstevel@tonic-gate return (address);
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate
10520Sstevel@tonic-gate /*
10530Sstevel@tonic-gate * Find the mapped address for program, version.
10540Sstevel@tonic-gate * Calls the rpcbind service remotely to do the lookup.
10550Sstevel@tonic-gate * Uses the transport specified in nconf.
10560Sstevel@tonic-gate * Returns FALSE (0) if no map exists, else returns 1.
10570Sstevel@tonic-gate *
10580Sstevel@tonic-gate * Assuming that the address is all properly allocated
10590Sstevel@tonic-gate */
10600Sstevel@tonic-gate int
rpcb_getaddr(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf,struct netbuf * address,const char * host)1061132Srobinson rpcb_getaddr(const rpcprog_t program, const rpcvers_t version,
1062132Srobinson const struct netconfig *nconf, struct netbuf *address, const char *host)
10630Sstevel@tonic-gate {
10640Sstevel@tonic-gate struct netbuf *na;
10650Sstevel@tonic-gate
10660Sstevel@tonic-gate if ((na = __rpcb_findaddr_timed(program, version,
1067132Srobinson (struct netconfig *)nconf, (char *)host, NULL, NULL)) == NULL)
10680Sstevel@tonic-gate return (FALSE);
10690Sstevel@tonic-gate
10700Sstevel@tonic-gate if (na->len > address->maxlen) {
10710Sstevel@tonic-gate /* Too long address */
10720Sstevel@tonic-gate netdir_free((char *)na, ND_ADDR);
10730Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_FAILED;
10740Sstevel@tonic-gate return (FALSE);
10750Sstevel@tonic-gate }
1076132Srobinson (void) memcpy(address->buf, na->buf, (int)na->len);
10770Sstevel@tonic-gate address->len = na->len;
10780Sstevel@tonic-gate netdir_free((char *)na, ND_ADDR);
10790Sstevel@tonic-gate return (TRUE);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate
10820Sstevel@tonic-gate /*
10830Sstevel@tonic-gate * Get a copy of the current maps.
10840Sstevel@tonic-gate * Calls the rpcbind service remotely to get the maps.
10850Sstevel@tonic-gate *
10860Sstevel@tonic-gate * It returns only a list of the services
10870Sstevel@tonic-gate * It returns NULL on failure.
10880Sstevel@tonic-gate */
10890Sstevel@tonic-gate rpcblist *
rpcb_getmaps(const struct netconfig * nconf,const char * host)1090132Srobinson rpcb_getmaps(const struct netconfig *nconf, const char *host)
10910Sstevel@tonic-gate {
1092132Srobinson rpcblist_ptr head = NULL;
10930Sstevel@tonic-gate CLIENT *client;
10940Sstevel@tonic-gate enum clnt_stat clnt_st;
10950Sstevel@tonic-gate int vers = 0;
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate client = getclnthandle((char *)host,
1098132Srobinson (struct netconfig *)nconf, NULL);
1099132Srobinson if (client == NULL)
1100132Srobinson return (NULL);
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
11030Sstevel@tonic-gate (xdrproc_t)xdr_void, NULL,
11040Sstevel@tonic-gate (xdrproc_t)xdr_rpcblist_ptr,
11050Sstevel@tonic-gate (char *)&head, tottimeout);
11060Sstevel@tonic-gate if (clnt_st == RPC_SUCCESS)
11070Sstevel@tonic-gate goto done;
11080Sstevel@tonic-gate
11090Sstevel@tonic-gate if ((clnt_st != RPC_PROGVERSMISMATCH) &&
11100Sstevel@tonic-gate (clnt_st != RPC_PROGUNAVAIL)) {
11110Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_RPCBFAILURE;
11120Sstevel@tonic-gate clnt_geterr(client, &rpc_createerr.cf_error);
11130Sstevel@tonic-gate goto done;
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate
11160Sstevel@tonic-gate /* fall back to earlier version */
11170Sstevel@tonic-gate CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
11180Sstevel@tonic-gate if (vers == RPCBVERS4) {
11190Sstevel@tonic-gate vers = RPCBVERS;
11200Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
11210Sstevel@tonic-gate if (CLNT_CALL(client, RPCBPROC_DUMP,
11220Sstevel@tonic-gate (xdrproc_t)xdr_void,
1123132Srobinson NULL, (xdrproc_t)xdr_rpcblist_ptr,
11240Sstevel@tonic-gate (char *)&head, tottimeout) == RPC_SUCCESS)
11250Sstevel@tonic-gate goto done;
11260Sstevel@tonic-gate }
11270Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_RPCBFAILURE;
11280Sstevel@tonic-gate clnt_geterr(client, &rpc_createerr.cf_error);
11290Sstevel@tonic-gate
11300Sstevel@tonic-gate done:
11310Sstevel@tonic-gate CLNT_DESTROY(client);
11320Sstevel@tonic-gate return (head);
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate
11350Sstevel@tonic-gate /*
11360Sstevel@tonic-gate * rpcbinder remote-call-service interface.
11370Sstevel@tonic-gate * This routine is used to call the rpcbind remote call service
11380Sstevel@tonic-gate * which will look up a service program in the address maps, and then
11390Sstevel@tonic-gate * remotely call that routine with the given parameters. This allows
11400Sstevel@tonic-gate * programs to do a lookup and call in one step.
11410Sstevel@tonic-gate */
11420Sstevel@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)1143132Srobinson rpcb_rmtcall(const struct netconfig *nconf, const char *host,
1144132Srobinson const rpcprog_t prog, const rpcvers_t vers, const rpcproc_t proc,
1145132Srobinson const xdrproc_t xdrargs, const caddr_t argsp, const xdrproc_t xdrres,
1146132Srobinson const caddr_t resp, const struct timeval tout, struct netbuf *addr_ptr)
11470Sstevel@tonic-gate {
11480Sstevel@tonic-gate CLIENT *client;
11490Sstevel@tonic-gate enum clnt_stat stat;
11500Sstevel@tonic-gate struct r_rpcb_rmtcallargs a;
11510Sstevel@tonic-gate struct r_rpcb_rmtcallres r;
11520Sstevel@tonic-gate int rpcb_vers;
11530Sstevel@tonic-gate
1154132Srobinson client = getclnthandle((char *)host, (struct netconfig *)nconf, NULL);
1155132Srobinson if (client == NULL)
11560Sstevel@tonic-gate return (RPC_FAILED);
11570Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rmttimeout);
11580Sstevel@tonic-gate a.prog = prog;
11590Sstevel@tonic-gate a.vers = vers;
11600Sstevel@tonic-gate a.proc = proc;
11610Sstevel@tonic-gate a.args.args_val = argsp;
11620Sstevel@tonic-gate a.xdr_args = xdrargs;
11630Sstevel@tonic-gate r.addr = NULL;
11640Sstevel@tonic-gate r.results.results_val = resp;
11650Sstevel@tonic-gate r.xdr_res = xdrres;
11660Sstevel@tonic-gate
11670Sstevel@tonic-gate for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
11680Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_VERS, (char *)&rpcb_vers);
11690Sstevel@tonic-gate stat = CLNT_CALL(client, RPCBPROC_CALLIT,
11700Sstevel@tonic-gate (xdrproc_t)xdr_rpcb_rmtcallargs, (char *)&a,
11710Sstevel@tonic-gate (xdrproc_t)xdr_rpcb_rmtcallres, (char *)&r, tout);
11720Sstevel@tonic-gate if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
11730Sstevel@tonic-gate struct netbuf *na;
11740Sstevel@tonic-gate
11750Sstevel@tonic-gate na = uaddr2taddr((struct netconfig *)nconf, r.addr);
1176132Srobinson if (!na) {
11770Sstevel@tonic-gate stat = RPC_N2AXLATEFAILURE;
11780Sstevel@tonic-gate ((struct netbuf *)addr_ptr)->len = 0;
11790Sstevel@tonic-gate goto error;
11800Sstevel@tonic-gate }
11810Sstevel@tonic-gate if (na->len > addr_ptr->maxlen) {
11820Sstevel@tonic-gate /* Too long address */
11830Sstevel@tonic-gate stat = RPC_FAILED; /* XXX A better error no */
11840Sstevel@tonic-gate netdir_free((char *)na, ND_ADDR);
11850Sstevel@tonic-gate ((struct netbuf *)addr_ptr)->len = 0;
11860Sstevel@tonic-gate goto error;
11870Sstevel@tonic-gate }
1188132Srobinson (void) memcpy(addr_ptr->buf, na->buf, (int)na->len);
11890Sstevel@tonic-gate ((struct netbuf *)addr_ptr)->len = na->len;
11900Sstevel@tonic-gate netdir_free((char *)na, ND_ADDR);
11910Sstevel@tonic-gate break;
1192132Srobinson }
1193132Srobinson if ((stat != RPC_PROGVERSMISMATCH) &&
1194132Srobinson (stat != RPC_PROGUNAVAIL))
11950Sstevel@tonic-gate goto error;
11960Sstevel@tonic-gate }
11970Sstevel@tonic-gate error:
11980Sstevel@tonic-gate CLNT_DESTROY(client);
11990Sstevel@tonic-gate if (r.addr)
12000Sstevel@tonic-gate xdr_free((xdrproc_t)xdr_wrapstring, (char *)&r.addr);
12010Sstevel@tonic-gate return (stat);
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate /*
12050Sstevel@tonic-gate * Gets the time on the remote host.
12060Sstevel@tonic-gate * Returns 1 if succeeds else 0.
12070Sstevel@tonic-gate */
12080Sstevel@tonic-gate bool_t
rpcb_gettime(const char * host,time_t * timep)1209132Srobinson rpcb_gettime(const char *host, time_t *timep)
12100Sstevel@tonic-gate {
12110Sstevel@tonic-gate CLIENT *client = NULL;
12120Sstevel@tonic-gate void *handle;
12130Sstevel@tonic-gate struct netconfig *nconf;
12140Sstevel@tonic-gate int vers;
12150Sstevel@tonic-gate enum clnt_stat st;
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate if ((host == NULL) || (host[0] == NULL)) {
1218132Srobinson (void) time(timep);
12190Sstevel@tonic-gate return (TRUE);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate if ((handle = __rpc_setconf("netpath")) == NULL) {
12230Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
12240Sstevel@tonic-gate return (FALSE);
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SUCCESS;
1227132Srobinson while (client == NULL) {
12280Sstevel@tonic-gate if ((nconf = __rpc_getconf(handle)) == NULL) {
12290Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_SUCCESS)
12300Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
12310Sstevel@tonic-gate break;
12320Sstevel@tonic-gate }
1233132Srobinson client = getclnthandle((char *)host, nconf, NULL);
12340Sstevel@tonic-gate if (client)
12350Sstevel@tonic-gate break;
12360Sstevel@tonic-gate }
12370Sstevel@tonic-gate __rpc_endconf(handle);
1238132Srobinson if (client == NULL)
12390Sstevel@tonic-gate return (FALSE);
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate st = CLNT_CALL(client, RPCBPROC_GETTIME,
1242132Srobinson (xdrproc_t)xdr_void, NULL,
12430Sstevel@tonic-gate (xdrproc_t)xdr_time_t, (char *)timep, tottimeout);
12440Sstevel@tonic-gate
12450Sstevel@tonic-gate if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
12460Sstevel@tonic-gate CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
12470Sstevel@tonic-gate if (vers == RPCBVERS4) {
12480Sstevel@tonic-gate /* fall back to earlier version */
12490Sstevel@tonic-gate vers = RPCBVERS;
12500Sstevel@tonic-gate CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
12510Sstevel@tonic-gate st = CLNT_CALL(client, RPCBPROC_GETTIME,
1252132Srobinson (xdrproc_t)xdr_void, NULL,
12530Sstevel@tonic-gate (xdrproc_t)xdr_time_t, (char *)timep,
12540Sstevel@tonic-gate tottimeout);
12550Sstevel@tonic-gate }
12560Sstevel@tonic-gate }
12570Sstevel@tonic-gate CLNT_DESTROY(client);
1258132Srobinson return (st == RPC_SUCCESS? TRUE : FALSE);
12590Sstevel@tonic-gate }
12600Sstevel@tonic-gate
12610Sstevel@tonic-gate /*
12620Sstevel@tonic-gate * Converts taddr to universal address. This routine should never
12630Sstevel@tonic-gate * really be called because local n2a libraries are always provided.
12640Sstevel@tonic-gate */
12650Sstevel@tonic-gate char *
rpcb_taddr2uaddr(struct netconfig * nconf,struct netbuf * taddr)1266132Srobinson rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
12670Sstevel@tonic-gate {
12680Sstevel@tonic-gate CLIENT *client;
12690Sstevel@tonic-gate char *uaddr = NULL;
12700Sstevel@tonic-gate
12710Sstevel@tonic-gate /* parameter checking */
1272132Srobinson if (nconf == NULL) {
12730Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
12740Sstevel@tonic-gate return (NULL);
12750Sstevel@tonic-gate }
12760Sstevel@tonic-gate if (taddr == NULL) {
12770Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
12780Sstevel@tonic-gate return (NULL);
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate client = local_rpcb();
1281132Srobinson if (!client)
12820Sstevel@tonic-gate return (NULL);
12830Sstevel@tonic-gate
12840Sstevel@tonic-gate CLNT_CALL(client, RPCBPROC_TADDR2UADDR, (xdrproc_t)xdr_netbuf,
12850Sstevel@tonic-gate (char *)taddr, (xdrproc_t)xdr_wrapstring, (char *)&uaddr,
12860Sstevel@tonic-gate tottimeout);
12870Sstevel@tonic-gate CLNT_DESTROY(client);
12880Sstevel@tonic-gate return (uaddr);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate /*
12920Sstevel@tonic-gate * Converts universal address to netbuf. This routine should never
12930Sstevel@tonic-gate * really be called because local n2a libraries are always provided.
12940Sstevel@tonic-gate */
12950Sstevel@tonic-gate struct netbuf *
rpcb_uaddr2taddr(struct netconfig * nconf,char * uaddr)1296132Srobinson rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
12970Sstevel@tonic-gate {
12980Sstevel@tonic-gate CLIENT *client;
12990Sstevel@tonic-gate struct netbuf *taddr;
13000Sstevel@tonic-gate
13010Sstevel@tonic-gate /* parameter checking */
1302132Srobinson if (nconf == NULL) {
13030Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
13040Sstevel@tonic-gate return (NULL);
13050Sstevel@tonic-gate }
13060Sstevel@tonic-gate if (uaddr == NULL) {
13070Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
13080Sstevel@tonic-gate return (NULL);
13090Sstevel@tonic-gate }
13100Sstevel@tonic-gate client = local_rpcb();
1311132Srobinson if (!client)
13120Sstevel@tonic-gate return (NULL);
13130Sstevel@tonic-gate
1314132Srobinson taddr = calloc(1, sizeof (struct netbuf));
13150Sstevel@tonic-gate if (taddr == NULL) {
13160Sstevel@tonic-gate CLNT_DESTROY(client);
13170Sstevel@tonic-gate return (NULL);
13180Sstevel@tonic-gate }
13190Sstevel@tonic-gate
13200Sstevel@tonic-gate if (CLNT_CALL(client, RPCBPROC_UADDR2TADDR, (xdrproc_t)xdr_wrapstring,
13210Sstevel@tonic-gate (char *)&uaddr, (xdrproc_t)xdr_netbuf, (char *)taddr,
13220Sstevel@tonic-gate tottimeout) != RPC_SUCCESS) {
13230Sstevel@tonic-gate free(taddr);
13240Sstevel@tonic-gate taddr = NULL;
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate CLNT_DESTROY(client);
13270Sstevel@tonic-gate return (taddr);
13280Sstevel@tonic-gate }
1329