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 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 * 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 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 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 * 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 * 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 * 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 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 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 * 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 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 * 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 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 * 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 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 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 * 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 * 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