1*0a6a1f1dSLionel Sambuc /* $NetBSD: rpcb_clnt.c,v 1.31 2015/03/26 11:31:57 justin Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*
484d9c625SLionel Sambuc * Copyright (c) 2010, Oracle America, Inc.
52fe8fb19SBen Gras *
684d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without
784d9c625SLionel Sambuc * modification, are permitted provided that the following conditions are
884d9c625SLionel Sambuc * met:
92fe8fb19SBen Gras *
1084d9c625SLionel Sambuc * * Redistributions of source code must retain the above copyright
1184d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1284d9c625SLionel Sambuc * * Redistributions in binary form must reproduce the above
1384d9c625SLionel Sambuc * copyright notice, this list of conditions and the following
1484d9c625SLionel Sambuc * disclaimer in the documentation and/or other materials
1584d9c625SLionel Sambuc * provided with the distribution.
1684d9c625SLionel Sambuc * * Neither the name of the "Oracle America, Inc." nor the names of its
1784d9c625SLionel Sambuc * contributors may be used to endorse or promote products derived
1884d9c625SLionel Sambuc * from this software without specific prior written permission.
192fe8fb19SBen Gras *
2084d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2184d9c625SLionel Sambuc * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2284d9c625SLionel Sambuc * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2384d9c625SLionel Sambuc * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2484d9c625SLionel Sambuc * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2584d9c625SLionel Sambuc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2684d9c625SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2784d9c625SLionel Sambuc * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2884d9c625SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2984d9c625SLionel Sambuc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3084d9c625SLionel Sambuc * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3184d9c625SLionel Sambuc * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322fe8fb19SBen Gras */
332fe8fb19SBen Gras /*
342fe8fb19SBen Gras * Copyright (c) 1986-1991 by Sun Microsystems Inc.
352fe8fb19SBen Gras */
362fe8fb19SBen Gras
372fe8fb19SBen Gras /* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */
382fe8fb19SBen Gras
392fe8fb19SBen Gras #include <sys/cdefs.h>
402fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
412fe8fb19SBen Gras #if 0
422fe8fb19SBen Gras static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro";
432fe8fb19SBen Gras #else
44*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: rpcb_clnt.c,v 1.31 2015/03/26 11:31:57 justin Exp $");
452fe8fb19SBen Gras #endif
462fe8fb19SBen Gras #endif
472fe8fb19SBen Gras
482fe8fb19SBen Gras /*
492fe8fb19SBen Gras * rpcb_clnt.c
502fe8fb19SBen Gras * interface to rpcbind rpc service.
512fe8fb19SBen Gras *
522fe8fb19SBen Gras * Copyright (C) 1988, Sun Microsystems, Inc.
532fe8fb19SBen Gras */
542fe8fb19SBen Gras
552fe8fb19SBen Gras #include "namespace.h"
562fe8fb19SBen Gras #include "reentrant.h"
572fe8fb19SBen Gras #include <sys/types.h>
582fe8fb19SBen Gras #include <sys/socket.h>
592fe8fb19SBen Gras #include <sys/un.h>
602fe8fb19SBen Gras #include <sys/utsname.h>
612fe8fb19SBen Gras #include <rpc/rpc.h>
622fe8fb19SBen Gras #include <rpc/rpcb_prot.h>
632fe8fb19SBen Gras #include <rpc/nettype.h>
642fe8fb19SBen Gras #include <netconfig.h>
652fe8fb19SBen Gras #ifdef PORTMAP
662fe8fb19SBen Gras #include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
672fe8fb19SBen Gras #include <rpc/pmap_prot.h>
682fe8fb19SBen Gras #endif
692fe8fb19SBen Gras #include <assert.h>
702fe8fb19SBen Gras #include <errno.h>
712fe8fb19SBen Gras #include <netdb.h>
722fe8fb19SBen Gras #include <stdio.h>
732fe8fb19SBen Gras #include <stdlib.h>
742fe8fb19SBen Gras #include <string.h>
752fe8fb19SBen Gras #include <syslog.h>
762fe8fb19SBen Gras #include <unistd.h>
772fe8fb19SBen Gras
7884d9c625SLionel Sambuc #include "svc_fdset.h"
792fe8fb19SBen Gras #include "rpc_internal.h"
802fe8fb19SBen Gras
812fe8fb19SBen Gras #ifdef __weak_alias
822fe8fb19SBen Gras __weak_alias(rpcb_set,_rpcb_set)
832fe8fb19SBen Gras __weak_alias(rpcb_unset,_rpcb_unset)
842fe8fb19SBen Gras __weak_alias(rpcb_getmaps,_rpcb_getmaps)
852fe8fb19SBen Gras __weak_alias(rpcb_taddr2uaddr,_rpcb_taddr2uaddr)
862fe8fb19SBen Gras __weak_alias(rpcb_uaddr2taddr,_rpcb_uaddr2taddr)
872fe8fb19SBen Gras #endif
882fe8fb19SBen Gras
892fe8fb19SBen Gras static struct timeval tottimeout = { 60, 0 };
902fe8fb19SBen Gras static const struct timeval rmttimeout = { 3, 0 };
912fe8fb19SBen Gras
922fe8fb19SBen Gras static const char nullstring[] = "\000";
932fe8fb19SBen Gras
942fe8fb19SBen Gras #define CACHESIZE 6
952fe8fb19SBen Gras
962fe8fb19SBen Gras struct address_cache {
972fe8fb19SBen Gras char *ac_host;
982fe8fb19SBen Gras char *ac_netid;
992fe8fb19SBen Gras char *ac_uaddr;
1002fe8fb19SBen Gras struct netbuf *ac_taddr;
1012fe8fb19SBen Gras struct address_cache *ac_next;
1022fe8fb19SBen Gras };
1032fe8fb19SBen Gras
1042fe8fb19SBen Gras static struct address_cache *front;
1052fe8fb19SBen Gras static int cachesize;
1062fe8fb19SBen Gras
1072fe8fb19SBen Gras #define CLCR_GET_RPCB_TIMEOUT 1
1082fe8fb19SBen Gras #define CLCR_SET_RPCB_TIMEOUT 2
1092fe8fb19SBen Gras
1102fe8fb19SBen Gras
1112fe8fb19SBen Gras extern int __rpc_lowvers;
1122fe8fb19SBen Gras
113f14fb602SLionel Sambuc static struct address_cache *check_cache(const char *, const char *);
114f14fb602SLionel Sambuc static void delete_cache(struct netbuf *);
115f14fb602SLionel Sambuc static void add_cache(const char *, const char *, struct netbuf *, char *);
116f14fb602SLionel Sambuc static CLIENT *getclnthandle(const char *, const struct netconfig *, char **);
117f14fb602SLionel Sambuc static CLIENT *local_rpcb(void);
118f14fb602SLionel Sambuc static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *);
1192fe8fb19SBen Gras
1202fe8fb19SBen Gras /*
1212fe8fb19SBen Gras * This routine adjusts the timeout used for calls to the remote rpcbind.
1222fe8fb19SBen Gras * Also, this routine can be used to set the use of portmapper version 2
1232fe8fb19SBen Gras * only when doing rpc_broadcasts
1242fe8fb19SBen Gras * These are private routines that may not be provided in future releases.
1252fe8fb19SBen Gras */
1262fe8fb19SBen Gras bool_t
__rpc_control(int request,void * info)127f14fb602SLionel Sambuc __rpc_control(int request, void *info)
1282fe8fb19SBen Gras {
1292fe8fb19SBen Gras
1302fe8fb19SBen Gras _DIAGASSERT(info != NULL);
1312fe8fb19SBen Gras
1322fe8fb19SBen Gras switch (request) {
1332fe8fb19SBen Gras case CLCR_GET_RPCB_TIMEOUT:
1342fe8fb19SBen Gras *(struct timeval *)info = tottimeout;
1352fe8fb19SBen Gras break;
1362fe8fb19SBen Gras case CLCR_SET_RPCB_TIMEOUT:
1372fe8fb19SBen Gras tottimeout = *(struct timeval *)info;
1382fe8fb19SBen Gras break;
1392fe8fb19SBen Gras case CLCR_SET_LOWVERS:
1402fe8fb19SBen Gras __rpc_lowvers = *(int *)info;
1412fe8fb19SBen Gras break;
1422fe8fb19SBen Gras case CLCR_GET_LOWVERS:
1432fe8fb19SBen Gras *(int *)info = __rpc_lowvers;
1442fe8fb19SBen Gras break;
1452fe8fb19SBen Gras default:
1462fe8fb19SBen Gras return (FALSE);
1472fe8fb19SBen Gras }
1482fe8fb19SBen Gras return (TRUE);
1492fe8fb19SBen Gras }
1502fe8fb19SBen Gras
1512fe8fb19SBen Gras /*
1522fe8fb19SBen Gras * It might seem that a reader/writer lock would be more reasonable here.
1532fe8fb19SBen Gras * However because getclnthandle(), the only user of the cache functions,
1542fe8fb19SBen Gras * may do a delete_cache() operation if a check_cache() fails to return an
1552fe8fb19SBen Gras * address useful to clnt_tli_create(), we may as well use a mutex.
1562fe8fb19SBen Gras */
1572fe8fb19SBen Gras /*
1582fe8fb19SBen Gras * As it turns out, if the cache lock is *not* a reader/writer lock, we will
1592fe8fb19SBen Gras * block all clnt_create's if we are trying to connect to a host that's down,
1602fe8fb19SBen Gras * since the lock will be held all during that time.
1612fe8fb19SBen Gras */
1622fe8fb19SBen Gras #ifdef _REENTRANT
1632fe8fb19SBen Gras extern rwlock_t rpcbaddr_cache_lock;
1642fe8fb19SBen Gras #endif
1652fe8fb19SBen Gras
1662fe8fb19SBen Gras /*
1672fe8fb19SBen Gras * The routines check_cache(), add_cache(), delete_cache() manage the
1682fe8fb19SBen Gras * cache of rpcbind addresses for (host, netid).
1692fe8fb19SBen Gras */
1702fe8fb19SBen Gras
1712fe8fb19SBen Gras static struct address_cache *
check_cache(const char * host,const char * netid)172f14fb602SLionel Sambuc check_cache(const char *host, const char *netid)
1732fe8fb19SBen Gras {
1742fe8fb19SBen Gras struct address_cache *cptr;
1752fe8fb19SBen Gras
1762fe8fb19SBen Gras _DIAGASSERT(host != NULL);
1772fe8fb19SBen Gras _DIAGASSERT(netid != NULL);
1782fe8fb19SBen Gras
1792fe8fb19SBen Gras /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
1802fe8fb19SBen Gras
1812fe8fb19SBen Gras for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
1822fe8fb19SBen Gras if (!strcmp(cptr->ac_host, host) &&
1832fe8fb19SBen Gras !strcmp(cptr->ac_netid, netid)) {
1842fe8fb19SBen Gras #ifdef ND_DEBUG
1852fe8fb19SBen Gras fprintf(stderr, "Found cache entry for %s: %s\n",
1862fe8fb19SBen Gras host, netid);
1872fe8fb19SBen Gras #endif
1882fe8fb19SBen Gras return (cptr);
1892fe8fb19SBen Gras }
1902fe8fb19SBen Gras }
1912fe8fb19SBen Gras return NULL;
1922fe8fb19SBen Gras }
1932fe8fb19SBen Gras
1942fe8fb19SBen Gras static void
delete_cache(struct netbuf * addr)195f14fb602SLionel Sambuc delete_cache(struct netbuf *addr)
1962fe8fb19SBen Gras {
1972fe8fb19SBen Gras struct address_cache *cptr, *prevptr = NULL;
1982fe8fb19SBen Gras
1992fe8fb19SBen Gras _DIAGASSERT(addr != NULL);
2002fe8fb19SBen Gras
2012fe8fb19SBen Gras /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
2022fe8fb19SBen Gras for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
2032fe8fb19SBen Gras if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
2042fe8fb19SBen Gras free(cptr->ac_host);
2052fe8fb19SBen Gras free(cptr->ac_netid);
2062fe8fb19SBen Gras free(cptr->ac_taddr->buf);
2072fe8fb19SBen Gras free(cptr->ac_taddr);
2082fe8fb19SBen Gras if (cptr->ac_uaddr)
2092fe8fb19SBen Gras free(cptr->ac_uaddr);
2102fe8fb19SBen Gras if (prevptr)
2112fe8fb19SBen Gras prevptr->ac_next = cptr->ac_next;
2122fe8fb19SBen Gras else
2132fe8fb19SBen Gras front = cptr->ac_next;
2142fe8fb19SBen Gras free(cptr);
2152fe8fb19SBen Gras cachesize--;
2162fe8fb19SBen Gras break;
2172fe8fb19SBen Gras }
2182fe8fb19SBen Gras prevptr = cptr;
2192fe8fb19SBen Gras }
2202fe8fb19SBen Gras }
2212fe8fb19SBen Gras
2222fe8fb19SBen Gras static void
add_cache(const char * host,const char * netid,struct netbuf * taddr,char * uaddr)223f14fb602SLionel Sambuc add_cache(const char *host, const char *netid, struct netbuf *taddr,
224f14fb602SLionel Sambuc char *uaddr)
2252fe8fb19SBen Gras {
2262fe8fb19SBen Gras struct address_cache *ad_cache, *cptr, *prevptr;
2272fe8fb19SBen Gras
2282fe8fb19SBen Gras _DIAGASSERT(host != NULL);
2292fe8fb19SBen Gras _DIAGASSERT(netid != NULL);
2302fe8fb19SBen Gras /* uaddr may be NULL */
2312fe8fb19SBen Gras /* taddr may be NULL ??? */
2322fe8fb19SBen Gras
2332fe8fb19SBen Gras ad_cache = malloc(sizeof(*ad_cache));
2342fe8fb19SBen Gras if (!ad_cache) {
2352fe8fb19SBen Gras return;
2362fe8fb19SBen Gras }
2372fe8fb19SBen Gras ad_cache->ac_host = strdup(host);
2382fe8fb19SBen Gras ad_cache->ac_netid = strdup(netid);
2392fe8fb19SBen Gras ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
2402fe8fb19SBen Gras ad_cache->ac_taddr = malloc(sizeof(*ad_cache->ac_taddr));
2412fe8fb19SBen Gras if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
2422fe8fb19SBen Gras (uaddr && !ad_cache->ac_uaddr)) {
2432fe8fb19SBen Gras goto out;
2442fe8fb19SBen Gras }
2452fe8fb19SBen Gras ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
2462fe8fb19SBen Gras ad_cache->ac_taddr->buf = malloc(taddr->len);
2472fe8fb19SBen Gras if (ad_cache->ac_taddr->buf == NULL) {
2482fe8fb19SBen Gras out:
2492fe8fb19SBen Gras if (ad_cache->ac_host)
2502fe8fb19SBen Gras free(ad_cache->ac_host);
2512fe8fb19SBen Gras if (ad_cache->ac_netid)
2522fe8fb19SBen Gras free(ad_cache->ac_netid);
2532fe8fb19SBen Gras if (ad_cache->ac_uaddr)
2542fe8fb19SBen Gras free(ad_cache->ac_uaddr);
2552fe8fb19SBen Gras if (ad_cache->ac_taddr)
2562fe8fb19SBen Gras free(ad_cache->ac_taddr);
2572fe8fb19SBen Gras free(ad_cache);
2582fe8fb19SBen Gras return;
2592fe8fb19SBen Gras }
2602fe8fb19SBen Gras memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
2612fe8fb19SBen Gras #ifdef ND_DEBUG
2622fe8fb19SBen Gras fprintf(stderr, "Added to cache: %s : %s\n", host, netid);
2632fe8fb19SBen Gras #endif
2642fe8fb19SBen Gras
2652fe8fb19SBen Gras /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
2662fe8fb19SBen Gras
2672fe8fb19SBen Gras rwlock_wrlock(&rpcbaddr_cache_lock);
2682fe8fb19SBen Gras if (cachesize < CACHESIZE) {
2692fe8fb19SBen Gras ad_cache->ac_next = front;
2702fe8fb19SBen Gras front = ad_cache;
2712fe8fb19SBen Gras cachesize++;
2722fe8fb19SBen Gras } else {
2732fe8fb19SBen Gras /* Free the last entry */
2742fe8fb19SBen Gras cptr = front;
2752fe8fb19SBen Gras prevptr = NULL;
2762fe8fb19SBen Gras while (cptr->ac_next) {
2772fe8fb19SBen Gras prevptr = cptr;
2782fe8fb19SBen Gras cptr = cptr->ac_next;
2792fe8fb19SBen Gras }
2802fe8fb19SBen Gras
2812fe8fb19SBen Gras #ifdef ND_DEBUG
2822fe8fb19SBen Gras fprintf(stderr, "Deleted from cache: %s : %s\n",
2832fe8fb19SBen Gras cptr->ac_host, cptr->ac_netid);
2842fe8fb19SBen Gras #endif
2852fe8fb19SBen Gras free(cptr->ac_host);
2862fe8fb19SBen Gras free(cptr->ac_netid);
2872fe8fb19SBen Gras free(cptr->ac_taddr->buf);
2882fe8fb19SBen Gras free(cptr->ac_taddr);
2892fe8fb19SBen Gras if (cptr->ac_uaddr)
2902fe8fb19SBen Gras free(cptr->ac_uaddr);
2912fe8fb19SBen Gras
2922fe8fb19SBen Gras if (prevptr) {
2932fe8fb19SBen Gras prevptr->ac_next = NULL;
2942fe8fb19SBen Gras ad_cache->ac_next = front;
2952fe8fb19SBen Gras front = ad_cache;
2962fe8fb19SBen Gras } else {
2972fe8fb19SBen Gras front = ad_cache;
2982fe8fb19SBen Gras ad_cache->ac_next = NULL;
2992fe8fb19SBen Gras }
3002fe8fb19SBen Gras free(cptr);
3012fe8fb19SBen Gras }
3022fe8fb19SBen Gras rwlock_unlock(&rpcbaddr_cache_lock);
3032fe8fb19SBen Gras }
3042fe8fb19SBen Gras
3052fe8fb19SBen Gras /*
3062fe8fb19SBen Gras * This routine will return a client handle that is connected to the
3072fe8fb19SBen Gras * rpcbind. Returns NULL on error and free's everything.
3082fe8fb19SBen Gras */
3092fe8fb19SBen Gras static CLIENT *
getclnthandle(const char * host,const struct netconfig * nconf,char ** targaddr)310f14fb602SLionel Sambuc getclnthandle(const char *host, const struct netconfig *nconf, char **targaddr)
3112fe8fb19SBen Gras {
3122fe8fb19SBen Gras CLIENT *client;
3132fe8fb19SBen Gras struct netbuf *addr, taddr;
3142fe8fb19SBen Gras struct netbuf addr_to_delete;
3152fe8fb19SBen Gras struct __rpc_sockinfo si;
3162fe8fb19SBen Gras struct addrinfo hints, *res, *tres;
3172fe8fb19SBen Gras struct address_cache *ad_cache;
3182fe8fb19SBen Gras char *tmpaddr;
3192fe8fb19SBen Gras
3202fe8fb19SBen Gras _DIAGASSERT(host != NULL);
3212fe8fb19SBen Gras _DIAGASSERT(nconf != NULL);
3222fe8fb19SBen Gras /* targaddr may be NULL */
3232fe8fb19SBen Gras
3242fe8fb19SBen Gras /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */
3252fe8fb19SBen Gras
3262fe8fb19SBen Gras /* Get the address of the rpcbind. Check cache first */
3272fe8fb19SBen Gras client = NULL;
3282fe8fb19SBen Gras addr_to_delete.len = 0;
3292fe8fb19SBen Gras addr_to_delete.buf = NULL;
3302fe8fb19SBen Gras rwlock_rdlock(&rpcbaddr_cache_lock);
3312fe8fb19SBen Gras ad_cache = check_cache(host, nconf->nc_netid);
3322fe8fb19SBen Gras if (ad_cache != NULL) {
3332fe8fb19SBen Gras addr = ad_cache->ac_taddr;
3342fe8fb19SBen Gras client = clnt_tli_create(RPC_ANYFD, nconf, addr,
3352fe8fb19SBen Gras (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
3362fe8fb19SBen Gras if (client != NULL) {
3372fe8fb19SBen Gras if (targaddr)
3382fe8fb19SBen Gras *targaddr = ad_cache->ac_uaddr;
3392fe8fb19SBen Gras rwlock_unlock(&rpcbaddr_cache_lock);
3402fe8fb19SBen Gras return (client);
3412fe8fb19SBen Gras }
3422fe8fb19SBen Gras addr_to_delete.len = addr->len;
3432fe8fb19SBen Gras addr_to_delete.buf = malloc(addr->len);
3442fe8fb19SBen Gras if (addr_to_delete.buf == NULL) {
3452fe8fb19SBen Gras addr_to_delete.len = 0;
3462fe8fb19SBen Gras } else {
3472fe8fb19SBen Gras memcpy(addr_to_delete.buf, addr->buf, addr->len);
3482fe8fb19SBen Gras }
3492fe8fb19SBen Gras }
3502fe8fb19SBen Gras rwlock_unlock(&rpcbaddr_cache_lock);
3512fe8fb19SBen Gras if (addr_to_delete.len != 0) {
3522fe8fb19SBen Gras /*
3532fe8fb19SBen Gras * Assume this may be due to cache data being
3542fe8fb19SBen Gras * outdated
3552fe8fb19SBen Gras */
3562fe8fb19SBen Gras rwlock_wrlock(&rpcbaddr_cache_lock);
3572fe8fb19SBen Gras delete_cache(&addr_to_delete);
3582fe8fb19SBen Gras rwlock_unlock(&rpcbaddr_cache_lock);
3592fe8fb19SBen Gras free(addr_to_delete.buf);
3602fe8fb19SBen Gras }
3612fe8fb19SBen Gras if (!__rpc_nconf2sockinfo(nconf, &si)) {
3622fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
3632fe8fb19SBen Gras return NULL;
3642fe8fb19SBen Gras }
3652fe8fb19SBen Gras
3662fe8fb19SBen Gras memset(&hints, 0, sizeof hints);
3672fe8fb19SBen Gras hints.ai_family = si.si_af;
3682fe8fb19SBen Gras hints.ai_socktype = si.si_socktype;
3692fe8fb19SBen Gras hints.ai_protocol = si.si_proto;
3702fe8fb19SBen Gras
3712fe8fb19SBen Gras #ifdef CLNT_DEBUG
3722fe8fb19SBen Gras printf("trying netid %s family %d proto %d socktype %d\n",
3732fe8fb19SBen Gras nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype);
3742fe8fb19SBen Gras #endif
3752fe8fb19SBen Gras
3762fe8fb19SBen Gras if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) {
3772fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
3782fe8fb19SBen Gras return NULL;
3792fe8fb19SBen Gras }
3802fe8fb19SBen Gras
3812fe8fb19SBen Gras for (tres = res; tres != NULL; tres = tres->ai_next) {
3822fe8fb19SBen Gras taddr.buf = tres->ai_addr;
3832fe8fb19SBen Gras taddr.len = taddr.maxlen = tres->ai_addrlen;
3842fe8fb19SBen Gras
3852fe8fb19SBen Gras #ifdef ND_DEBUG
3862fe8fb19SBen Gras {
3872fe8fb19SBen Gras char *ua;
3882fe8fb19SBen Gras
3892fe8fb19SBen Gras ua = taddr2uaddr(nconf, &taddr);
3902fe8fb19SBen Gras fprintf(stderr, "Got it [%s]\n", ua);
3912fe8fb19SBen Gras free(ua);
3922fe8fb19SBen Gras }
3932fe8fb19SBen Gras #endif
3942fe8fb19SBen Gras
3952fe8fb19SBen Gras #ifdef ND_DEBUG
3962fe8fb19SBen Gras {
3972fe8fb19SBen Gras int i;
3982fe8fb19SBen Gras
3992fe8fb19SBen Gras fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n",
4002fe8fb19SBen Gras taddr.len, taddr.maxlen);
4012fe8fb19SBen Gras fprintf(stderr, "\tAddress is ");
4022fe8fb19SBen Gras for (i = 0; i < taddr.len; i++)
4032fe8fb19SBen Gras fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]);
4042fe8fb19SBen Gras fprintf(stderr, "\n");
4052fe8fb19SBen Gras }
4062fe8fb19SBen Gras #endif
4072fe8fb19SBen Gras client = clnt_tli_create(RPC_ANYFD, nconf, &taddr,
4082fe8fb19SBen Gras (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
4092fe8fb19SBen Gras #ifdef ND_DEBUG
4102fe8fb19SBen Gras if (! client) {
4112fe8fb19SBen Gras clnt_pcreateerror("rpcbind clnt interface");
4122fe8fb19SBen Gras }
4132fe8fb19SBen Gras #endif
4142fe8fb19SBen Gras
4152fe8fb19SBen Gras if (client) {
4162fe8fb19SBen Gras tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL;
4172fe8fb19SBen Gras add_cache(host, nconf->nc_netid, &taddr, tmpaddr);
4182fe8fb19SBen Gras if (targaddr)
4192fe8fb19SBen Gras *targaddr = tmpaddr;
4202fe8fb19SBen Gras break;
4212fe8fb19SBen Gras }
4222fe8fb19SBen Gras }
4232fe8fb19SBen Gras freeaddrinfo(res);
4242fe8fb19SBen Gras return (client);
4252fe8fb19SBen Gras }
4262fe8fb19SBen Gras
4272fe8fb19SBen Gras /* XXX */
4282fe8fb19SBen Gras #define IN4_LOCALHOST_STRING "127.0.0.1"
4292fe8fb19SBen Gras #define IN6_LOCALHOST_STRING "::1"
4302fe8fb19SBen Gras
4312fe8fb19SBen Gras /*
4322fe8fb19SBen Gras * This routine will return a client handle that is connected to the local
4332fe8fb19SBen Gras * rpcbind. Returns NULL on error and free's everything.
4342fe8fb19SBen Gras */
4352fe8fb19SBen Gras static CLIENT *
local_rpcb(void)436f14fb602SLionel Sambuc local_rpcb(void)
4372fe8fb19SBen Gras {
4382fe8fb19SBen Gras CLIENT *client;
4392fe8fb19SBen Gras static struct netconfig *loopnconf;
4402fe8fb19SBen Gras static const char *hostname;
4412fe8fb19SBen Gras #ifdef _REENTRANT
4422fe8fb19SBen Gras extern mutex_t loopnconf_lock;
4432fe8fb19SBen Gras #endif
4442fe8fb19SBen Gras int sock;
4452fe8fb19SBen Gras size_t tsize;
4462fe8fb19SBen Gras struct netbuf nbuf;
4472fe8fb19SBen Gras struct sockaddr_un sun;
4482fe8fb19SBen Gras
4492fe8fb19SBen Gras /*
4502fe8fb19SBen Gras * Try connecting to the local rpcbind through a local socket
4512fe8fb19SBen Gras * first. If this doesn't work, try all transports defined in
4522fe8fb19SBen Gras * the netconfig file.
4532fe8fb19SBen Gras */
4542fe8fb19SBen Gras memset(&sun, 0, sizeof sun);
4552fe8fb19SBen Gras sock = socket(AF_LOCAL, SOCK_STREAM, 0);
4562fe8fb19SBen Gras if (sock < 0)
4572fe8fb19SBen Gras goto try_nconf;
4582fe8fb19SBen Gras sun.sun_family = AF_LOCAL;
4592fe8fb19SBen Gras strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
460f14fb602SLionel Sambuc tsize = SUN_LEN(&sun);
461f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(uint8_t, tsize));
462f14fb602SLionel Sambuc nbuf.len = sun.sun_len = (uint8_t)tsize;
4632fe8fb19SBen Gras nbuf.maxlen = sizeof (struct sockaddr_un);
4642fe8fb19SBen Gras nbuf.buf = &sun;
4652fe8fb19SBen Gras
4662fe8fb19SBen Gras tsize = __rpc_get_t_size(AF_LOCAL, 0, 0);
467f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(u_int, tsize));
4682fe8fb19SBen Gras client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG,
469f14fb602SLionel Sambuc (rpcvers_t)RPCBVERS, (u_int)tsize, (u_int)tsize);
4702fe8fb19SBen Gras
4712fe8fb19SBen Gras if (client != NULL) {
4722fe8fb19SBen Gras /* XXX - mark the socket to be closed in destructor */
4732fe8fb19SBen Gras (void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL);
4742fe8fb19SBen Gras return client;
4752fe8fb19SBen Gras }
4762fe8fb19SBen Gras
4772fe8fb19SBen Gras /* XXX - nobody needs this socket anymore, free the descriptor */
4782fe8fb19SBen Gras close(sock);
4792fe8fb19SBen Gras
4802fe8fb19SBen Gras try_nconf:
4812fe8fb19SBen Gras
4822fe8fb19SBen Gras /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
4832fe8fb19SBen Gras mutex_lock(&loopnconf_lock);
4842fe8fb19SBen Gras if (loopnconf == NULL) {
4852fe8fb19SBen Gras struct netconfig *nconf, *tmpnconf = NULL;
4862fe8fb19SBen Gras void *nc_handle;
4872fe8fb19SBen Gras int fd;
4882fe8fb19SBen Gras
4892fe8fb19SBen Gras nc_handle = setnetconfig();
4902fe8fb19SBen Gras if (nc_handle == NULL) {
4912fe8fb19SBen Gras /* fails to open netconfig file */
4922fe8fb19SBen Gras syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
4932fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
4942fe8fb19SBen Gras mutex_unlock(&loopnconf_lock);
4952fe8fb19SBen Gras return (NULL);
4962fe8fb19SBen Gras }
4972fe8fb19SBen Gras while ((nconf = getnetconfig(nc_handle)) != NULL) {
4982fe8fb19SBen Gras #ifdef INET6
4992fe8fb19SBen Gras if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 ||
5002fe8fb19SBen Gras #else
5012fe8fb19SBen Gras if ((
5022fe8fb19SBen Gras #endif
5032fe8fb19SBen Gras strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
5042fe8fb19SBen Gras (nconf->nc_semantics == NC_TPI_COTS ||
5052fe8fb19SBen Gras nconf->nc_semantics == NC_TPI_COTS_ORD)) {
5062fe8fb19SBen Gras fd = __rpc_nconf2fd(nconf);
5072fe8fb19SBen Gras /*
5082fe8fb19SBen Gras * Can't create a socket, assume that
5092fe8fb19SBen Gras * this family isn't configured in the kernel.
5102fe8fb19SBen Gras */
5112fe8fb19SBen Gras if (fd < 0)
5122fe8fb19SBen Gras continue;
5132fe8fb19SBen Gras close(fd);
5142fe8fb19SBen Gras tmpnconf = nconf;
5152fe8fb19SBen Gras if (!strcmp(nconf->nc_protofmly, NC_INET))
5162fe8fb19SBen Gras hostname = IN4_LOCALHOST_STRING;
5172fe8fb19SBen Gras else
5182fe8fb19SBen Gras hostname = IN6_LOCALHOST_STRING;
5192fe8fb19SBen Gras }
5202fe8fb19SBen Gras }
5212fe8fb19SBen Gras if (tmpnconf == NULL) {
5222fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
5232fe8fb19SBen Gras mutex_unlock(&loopnconf_lock);
5242fe8fb19SBen Gras return (NULL);
5252fe8fb19SBen Gras }
5262fe8fb19SBen Gras loopnconf = getnetconfigent(tmpnconf->nc_netid);
5272fe8fb19SBen Gras /* loopnconf is never freed */
5282fe8fb19SBen Gras endnetconfig(nc_handle);
5292fe8fb19SBen Gras }
5302fe8fb19SBen Gras mutex_unlock(&loopnconf_lock);
5312fe8fb19SBen Gras client = getclnthandle(hostname, loopnconf, NULL);
5322fe8fb19SBen Gras return (client);
5332fe8fb19SBen Gras }
5342fe8fb19SBen Gras
5352fe8fb19SBen Gras /*
5362fe8fb19SBen Gras * Set a mapping between program, version and address.
5372fe8fb19SBen Gras * Calls the rpcbind service to do the mapping.
5382fe8fb19SBen Gras */
5392fe8fb19SBen Gras bool_t
rpcb_set(rpcprog_t program,rpcvers_t version,const struct netconfig * nconf,const struct netbuf * address)540f14fb602SLionel Sambuc rpcb_set(rpcprog_t program, rpcvers_t version,
541f14fb602SLionel Sambuc const struct netconfig *nconf, /* Network structure of transport */
542f14fb602SLionel Sambuc const struct netbuf *address) /* Services netconfig address */
5432fe8fb19SBen Gras {
5442fe8fb19SBen Gras CLIENT *client;
5452fe8fb19SBen Gras bool_t rslt = FALSE;
5462fe8fb19SBen Gras RPCB parms;
5472fe8fb19SBen Gras char uidbuf[32];
5482fe8fb19SBen Gras
5492fe8fb19SBen Gras /* parameter checking */
5502fe8fb19SBen Gras if (nconf == NULL) {
5512fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
5522fe8fb19SBen Gras return (FALSE);
5532fe8fb19SBen Gras }
5542fe8fb19SBen Gras if (address == NULL) {
5552fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
5562fe8fb19SBen Gras return (FALSE);
5572fe8fb19SBen Gras }
5582fe8fb19SBen Gras client = local_rpcb();
5592fe8fb19SBen Gras if (! client) {
5602fe8fb19SBen Gras return (FALSE);
5612fe8fb19SBen Gras }
5622fe8fb19SBen Gras
5632fe8fb19SBen Gras /* convert to universal */
5642fe8fb19SBen Gras parms.r_addr = taddr2uaddr(__UNCONST(nconf), __UNCONST(address));
5652fe8fb19SBen Gras if (!parms.r_addr) {
5662fe8fb19SBen Gras CLNT_DESTROY(client);
5672fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
5682fe8fb19SBen Gras return (FALSE); /* no universal address */
5692fe8fb19SBen Gras }
5702fe8fb19SBen Gras parms.r_prog = program;
5712fe8fb19SBen Gras parms.r_vers = version;
5722fe8fb19SBen Gras parms.r_netid = nconf->nc_netid;
5732fe8fb19SBen Gras /*
5742fe8fb19SBen Gras * Though uid is not being used directly, we still send it for
5752fe8fb19SBen Gras * completeness. For non-unix platforms, perhaps some other
5762fe8fb19SBen Gras * string or an empty string can be sent.
5772fe8fb19SBen Gras */
5782fe8fb19SBen Gras (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
5792fe8fb19SBen Gras parms.r_owner = uidbuf;
5802fe8fb19SBen Gras
581*0a6a1f1dSLionel Sambuc if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb,
5822fe8fb19SBen Gras (char *)(void *)&parms, (xdrproc_t) xdr_bool,
583*0a6a1f1dSLionel Sambuc (char *)(void *)&rslt, tottimeout) != RPC_SUCCESS) {
584*0a6a1f1dSLionel Sambuc rpc_createerr.cf_stat = RPC_PMAPFAILURE;
585*0a6a1f1dSLionel Sambuc clnt_geterr(client, &rpc_createerr.cf_error);
586*0a6a1f1dSLionel Sambuc }
5872fe8fb19SBen Gras
5882fe8fb19SBen Gras CLNT_DESTROY(client);
5892fe8fb19SBen Gras free(parms.r_addr);
5902fe8fb19SBen Gras return (rslt);
5912fe8fb19SBen Gras }
5922fe8fb19SBen Gras
5932fe8fb19SBen Gras /*
5942fe8fb19SBen Gras * Remove the mapping between program, version and netbuf address.
5952fe8fb19SBen Gras * Calls the rpcbind service to do the un-mapping.
5962fe8fb19SBen Gras * If netbuf is NULL, unset for all the transports, otherwise unset
5972fe8fb19SBen Gras * only for the given transport.
5982fe8fb19SBen Gras */
5992fe8fb19SBen Gras bool_t
rpcb_unset(rpcprog_t program,rpcvers_t version,const struct netconfig * nconf)600f14fb602SLionel Sambuc rpcb_unset(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf)
6012fe8fb19SBen Gras {
6022fe8fb19SBen Gras CLIENT *client;
6032fe8fb19SBen Gras bool_t rslt = FALSE;
6042fe8fb19SBen Gras RPCB parms;
6052fe8fb19SBen Gras char uidbuf[32];
6062fe8fb19SBen Gras
6072fe8fb19SBen Gras client = local_rpcb();
6082fe8fb19SBen Gras if (! client) {
6092fe8fb19SBen Gras return (FALSE);
6102fe8fb19SBen Gras }
6112fe8fb19SBen Gras
6122fe8fb19SBen Gras parms.r_prog = program;
6132fe8fb19SBen Gras parms.r_vers = version;
6142fe8fb19SBen Gras if (nconf)
6152fe8fb19SBen Gras parms.r_netid = nconf->nc_netid;
6162fe8fb19SBen Gras else {
6172fe8fb19SBen Gras parms.r_netid = __UNCONST(&nullstring[0]); /* unsets all */
6182fe8fb19SBen Gras }
6192fe8fb19SBen Gras parms.r_addr = __UNCONST(&nullstring[0]);
6202fe8fb19SBen Gras (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
6212fe8fb19SBen Gras parms.r_owner = uidbuf;
6222fe8fb19SBen Gras
623*0a6a1f1dSLionel Sambuc if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb,
6242fe8fb19SBen Gras (char *)(void *)&parms, (xdrproc_t) xdr_bool,
625*0a6a1f1dSLionel Sambuc (char *)(void *)&rslt, tottimeout) != RPC_SUCCESS) {
626*0a6a1f1dSLionel Sambuc rpc_createerr.cf_stat = RPC_PMAPFAILURE;
627*0a6a1f1dSLionel Sambuc clnt_geterr(client, &rpc_createerr.cf_error);
628*0a6a1f1dSLionel Sambuc }
6292fe8fb19SBen Gras
6302fe8fb19SBen Gras CLNT_DESTROY(client);
6312fe8fb19SBen Gras return (rslt);
6322fe8fb19SBen Gras }
6332fe8fb19SBen Gras
6342fe8fb19SBen Gras /*
6352fe8fb19SBen Gras * From the merged list, find the appropriate entry
6362fe8fb19SBen Gras */
6372fe8fb19SBen Gras static struct netbuf *
got_entry(rpcb_entry_list_ptr relp,const struct netconfig * nconf)638f14fb602SLionel Sambuc got_entry(rpcb_entry_list_ptr relp, const struct netconfig *nconf)
6392fe8fb19SBen Gras {
6402fe8fb19SBen Gras struct netbuf *na = NULL;
6412fe8fb19SBen Gras rpcb_entry_list_ptr sp;
6422fe8fb19SBen Gras rpcb_entry *rmap;
6432fe8fb19SBen Gras
6442fe8fb19SBen Gras _DIAGASSERT(nconf != NULL);
6452fe8fb19SBen Gras
6462fe8fb19SBen Gras for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
6472fe8fb19SBen Gras rmap = &sp->rpcb_entry_map;
6482fe8fb19SBen Gras if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
6492fe8fb19SBen Gras (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
6502fe8fb19SBen Gras (nconf->nc_semantics == rmap->r_nc_semantics) &&
6512fe8fb19SBen Gras (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) {
6522fe8fb19SBen Gras na = uaddr2taddr(nconf, rmap->r_maddr);
6532fe8fb19SBen Gras #ifdef ND_DEBUG
6542fe8fb19SBen Gras fprintf(stderr, "\tRemote address is [%s].\n",
6552fe8fb19SBen Gras rmap->r_maddr);
6562fe8fb19SBen Gras if (!na)
6572fe8fb19SBen Gras fprintf(stderr,
6582fe8fb19SBen Gras "\tCouldn't resolve remote address!\n");
6592fe8fb19SBen Gras #endif
6602fe8fb19SBen Gras break;
6612fe8fb19SBen Gras }
6622fe8fb19SBen Gras }
6632fe8fb19SBen Gras return (na);
6642fe8fb19SBen Gras }
6652fe8fb19SBen Gras
6662fe8fb19SBen Gras /*
6672fe8fb19SBen Gras * An internal function which optimizes rpcb_getaddr function. It also
6682fe8fb19SBen Gras * returns the client handle that it uses to contact the remote rpcbind.
6692fe8fb19SBen Gras *
6702fe8fb19SBen Gras * The algorithm used: If the transports is TCP or UDP, it first tries
6712fe8fb19SBen Gras * version 2 (portmap), 4 and then 3 (svr4). This order should be
6722fe8fb19SBen Gras * changed in the next OS release to 4, 2 and 3. We are assuming that by
6732fe8fb19SBen Gras * that time, version 4 would be available on many machines on the network.
6742fe8fb19SBen Gras * With this algorithm, we get performance as well as a plan for
6752fe8fb19SBen Gras * obsoleting version 2.
6762fe8fb19SBen Gras *
6772fe8fb19SBen Gras * For all other transports, the algorithm remains as 4 and then 3.
6782fe8fb19SBen Gras *
6792fe8fb19SBen Gras * XXX: Due to some problems with t_connect(), we do not reuse the same client
6802fe8fb19SBen Gras * handle for COTS cases and hence in these cases we do not return the
6812fe8fb19SBen Gras * client handle. This code will change if t_connect() ever
6822fe8fb19SBen Gras * starts working properly. Also look under clnt_vc.c.
6832fe8fb19SBen Gras */
6842fe8fb19SBen Gras struct netbuf *
__rpcb_findaddr(rpcprog_t program,rpcvers_t version,const struct netconfig * nconf,const char * host,CLIENT ** clpp)685f14fb602SLionel Sambuc __rpcb_findaddr(rpcprog_t program, rpcvers_t version,
686f14fb602SLionel Sambuc const struct netconfig *nconf, const char *host, CLIENT **clpp)
6872fe8fb19SBen Gras {
6882fe8fb19SBen Gras CLIENT *client = NULL;
6892fe8fb19SBen Gras RPCB parms;
6902fe8fb19SBen Gras enum clnt_stat clnt_st;
6912fe8fb19SBen Gras char *ua = NULL;
6922fe8fb19SBen Gras rpcvers_t vers;
6932fe8fb19SBen Gras struct netbuf *address = NULL;
6942fe8fb19SBen Gras rpcvers_t start_vers = RPCBVERS4;
6952fe8fb19SBen Gras struct netbuf servaddr;
6962fe8fb19SBen Gras
6972fe8fb19SBen Gras /* nconf is handled below */
6982fe8fb19SBen Gras _DIAGASSERT(host != NULL);
6992fe8fb19SBen Gras /* clpp may be NULL */
7002fe8fb19SBen Gras
7012fe8fb19SBen Gras /* parameter checking */
7022fe8fb19SBen Gras if (nconf == NULL) {
7032fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
7042fe8fb19SBen Gras return (NULL);
7052fe8fb19SBen Gras }
7062fe8fb19SBen Gras
7072fe8fb19SBen Gras parms.r_addr = NULL;
7082fe8fb19SBen Gras
7092fe8fb19SBen Gras #ifdef PORTMAP
7102fe8fb19SBen Gras /* Try version 2 for TCP or UDP */
7112fe8fb19SBen Gras if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
7122fe8fb19SBen Gras u_short port = 0;
7132fe8fb19SBen Gras struct netbuf remote;
7142fe8fb19SBen Gras rpcvers_t pmapvers = 2;
7152fe8fb19SBen Gras struct pmap pmapparms;
7162fe8fb19SBen Gras
7172fe8fb19SBen Gras /*
7182fe8fb19SBen Gras * Try UDP only - there are some portmappers out
7192fe8fb19SBen Gras * there that use UDP only.
7202fe8fb19SBen Gras */
7212fe8fb19SBen Gras if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
7222fe8fb19SBen Gras struct netconfig *newnconf;
7232fe8fb19SBen Gras
7242fe8fb19SBen Gras if ((newnconf = getnetconfigent("udp")) == NULL) {
7252fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
7262fe8fb19SBen Gras return (NULL);
7272fe8fb19SBen Gras }
7282fe8fb19SBen Gras client = getclnthandle(host, newnconf, &parms.r_addr);
7292fe8fb19SBen Gras freenetconfigent(newnconf);
7302fe8fb19SBen Gras } else {
7312fe8fb19SBen Gras client = getclnthandle(host, nconf, &parms.r_addr);
7322fe8fb19SBen Gras }
7332fe8fb19SBen Gras if (client == NULL) {
7342fe8fb19SBen Gras return (NULL);
7352fe8fb19SBen Gras }
7362fe8fb19SBen Gras
7372fe8fb19SBen Gras /* Set the version */
7382fe8fb19SBen Gras CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&pmapvers);
7392fe8fb19SBen Gras pmapparms.pm_prog = program;
7402fe8fb19SBen Gras pmapparms.pm_vers = version;
7412fe8fb19SBen Gras pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
7422fe8fb19SBen Gras IPPROTO_UDP : IPPROTO_TCP;
7432fe8fb19SBen Gras pmapparms.pm_port = 0; /* not needed */
7442fe8fb19SBen Gras clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
7452fe8fb19SBen Gras (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms,
7462fe8fb19SBen Gras (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port,
7472fe8fb19SBen Gras tottimeout);
7482fe8fb19SBen Gras if (clnt_st != RPC_SUCCESS) {
7492fe8fb19SBen Gras if ((clnt_st == RPC_PROGVERSMISMATCH) ||
7502fe8fb19SBen Gras (clnt_st == RPC_PROGUNAVAIL))
7512fe8fb19SBen Gras goto try_rpcbind; /* Try different versions */
7522fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_PMAPFAILURE;
7532fe8fb19SBen Gras clnt_geterr(client, &rpc_createerr.cf_error);
7542fe8fb19SBen Gras goto error;
7552fe8fb19SBen Gras } else if (port == 0) {
7562fe8fb19SBen Gras address = NULL;
7572fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
7582fe8fb19SBen Gras goto error;
7592fe8fb19SBen Gras }
7602fe8fb19SBen Gras port = htons(port);
7612fe8fb19SBen Gras CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)(void *)&remote);
7622fe8fb19SBen Gras if (((address = malloc(sizeof(struct netbuf))) == NULL) ||
7632fe8fb19SBen Gras ((address->buf = malloc(remote.len)) == NULL)) {
7642fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_SYSTEMERROR;
7652fe8fb19SBen Gras clnt_geterr(client, &rpc_createerr.cf_error);
7662fe8fb19SBen Gras if (address) {
7672fe8fb19SBen Gras free(address);
7682fe8fb19SBen Gras address = NULL;
7692fe8fb19SBen Gras }
7702fe8fb19SBen Gras goto error;
7712fe8fb19SBen Gras }
7722fe8fb19SBen Gras memcpy(address->buf, remote.buf, remote.len);
7732fe8fb19SBen Gras memcpy(&((char *)address->buf)[sizeof (short)],
7742fe8fb19SBen Gras (char *)(void *)&port, sizeof (short));
7752fe8fb19SBen Gras address->len = address->maxlen = remote.len;
7762fe8fb19SBen Gras goto done;
7772fe8fb19SBen Gras }
7782fe8fb19SBen Gras #endif
7792fe8fb19SBen Gras
7802fe8fb19SBen Gras try_rpcbind:
7812fe8fb19SBen Gras /*
7822fe8fb19SBen Gras * Now we try version 4 and then 3.
7832fe8fb19SBen Gras * We also send the remote system the address we used to
7842fe8fb19SBen Gras * contact it in case it can help to connect back with us
7852fe8fb19SBen Gras */
7862fe8fb19SBen Gras parms.r_prog = program;
7872fe8fb19SBen Gras parms.r_vers = version;
7882fe8fb19SBen Gras parms.r_owner = __UNCONST(&nullstring[0]); /* not needed; */
7892fe8fb19SBen Gras /* just for xdring */
7902fe8fb19SBen Gras parms.r_netid = nconf->nc_netid; /* not really needed */
7912fe8fb19SBen Gras
7922fe8fb19SBen Gras /*
7932fe8fb19SBen Gras * If a COTS transport is being used, try getting address via CLTS
7942fe8fb19SBen Gras * transport. This works only with version 4.
7952fe8fb19SBen Gras * NOTE: This is being done for all transports EXCEPT LOOPBACK
7962fe8fb19SBen Gras * because with loopback the cost to go to a COTS is same as
7972fe8fb19SBen Gras * the cost to go through CLTS, plus you get the advantage of
7982fe8fb19SBen Gras * finding out immediately if the local rpcbind process is dead.
7992fe8fb19SBen Gras */
8002fe8fb19SBen Gras #if 1
8012fe8fb19SBen Gras if ((nconf->nc_semantics == NC_TPI_COTS_ORD ||
8022fe8fb19SBen Gras nconf->nc_semantics == NC_TPI_COTS) &&
8032fe8fb19SBen Gras (strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0))
8042fe8fb19SBen Gras #else
8052fe8fb19SBen Gras if (client != NULL) {
8062fe8fb19SBen Gras CLNT_DESTROY(client);
8072fe8fb19SBen Gras client = NULL;
8082fe8fb19SBen Gras }
8092fe8fb19SBen Gras if (nconf->nc_semantics == NC_TPI_CLTS)
8102fe8fb19SBen Gras #endif
8112fe8fb19SBen Gras {
8122fe8fb19SBen Gras void *handle;
8132fe8fb19SBen Gras struct netconfig *nconf_clts;
8142fe8fb19SBen Gras rpcb_entry_list_ptr relp = NULL;
8152fe8fb19SBen Gras
8162fe8fb19SBen Gras if (client == NULL) {
8172fe8fb19SBen Gras /* This did not go through the above PORTMAP/TCP code */
8182fe8fb19SBen Gras #if 1
8192fe8fb19SBen Gras if ((handle = __rpc_setconf("datagram_v")) != NULL)
8202fe8fb19SBen Gras #else
8212fe8fb19SBen Gras if ((handle = __rpc_setconf("circuit_v")) != NULL)
8222fe8fb19SBen Gras #endif
8232fe8fb19SBen Gras {
8242fe8fb19SBen Gras while ((nconf_clts = __rpc_getconf(handle))
8252fe8fb19SBen Gras != NULL) {
8262fe8fb19SBen Gras if (strcmp(nconf_clts->nc_protofmly,
8272fe8fb19SBen Gras nconf->nc_protofmly) != 0) {
8282fe8fb19SBen Gras continue;
8292fe8fb19SBen Gras }
8302fe8fb19SBen Gras client = getclnthandle(host, nconf_clts,
8312fe8fb19SBen Gras &parms.r_addr);
8322fe8fb19SBen Gras break;
8332fe8fb19SBen Gras }
8342fe8fb19SBen Gras __rpc_endconf(handle);
8352fe8fb19SBen Gras }
8362fe8fb19SBen Gras if (client == NULL)
8372fe8fb19SBen Gras goto regular_rpcbind; /* Go the regular way */
8382fe8fb19SBen Gras } else {
8392fe8fb19SBen Gras /* This is a UDP PORTMAP handle. Change to version 4 */
8402fe8fb19SBen Gras vers = RPCBVERS4;
8412fe8fb19SBen Gras CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
8422fe8fb19SBen Gras }
8432fe8fb19SBen Gras /*
8442fe8fb19SBen Gras * We also send the remote system the address we used to
8452fe8fb19SBen Gras * contact it in case it can help it connect back with us
8462fe8fb19SBen Gras */
8472fe8fb19SBen Gras if (parms.r_addr == NULL) {
8482fe8fb19SBen Gras /* for XDRing */
8492fe8fb19SBen Gras parms.r_addr = __UNCONST(&nullstring[0]);
8502fe8fb19SBen Gras }
8512fe8fb19SBen Gras clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST,
8522fe8fb19SBen Gras (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
8532fe8fb19SBen Gras (xdrproc_t) xdr_rpcb_entry_list_ptr,
8542fe8fb19SBen Gras (char *)(void *)&relp, tottimeout);
8552fe8fb19SBen Gras if (clnt_st == RPC_SUCCESS) {
8562fe8fb19SBen Gras if ((address = got_entry(relp, nconf)) != NULL) {
8572fe8fb19SBen Gras xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
8582fe8fb19SBen Gras (char *)(void *)&relp);
8592fe8fb19SBen Gras CLNT_CONTROL(client, CLGET_SVC_ADDR,
8602fe8fb19SBen Gras (char *)(void *)&servaddr);
8612fe8fb19SBen Gras __rpc_fixup_addr(address, &servaddr);
8622fe8fb19SBen Gras goto done;
8632fe8fb19SBen Gras }
8642fe8fb19SBen Gras /* Entry not found for this transport */
8652fe8fb19SBen Gras xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
8662fe8fb19SBen Gras (char *)(void *)&relp);
8672fe8fb19SBen Gras /*
8682fe8fb19SBen Gras * XXX: should have perhaps returned with error but
8692fe8fb19SBen Gras * since the remote machine might not always be able
8702fe8fb19SBen Gras * to send the address on all transports, we try the
8712fe8fb19SBen Gras * regular way with regular_rpcbind
8722fe8fb19SBen Gras */
8732fe8fb19SBen Gras goto regular_rpcbind;
8742fe8fb19SBen Gras } else if ((clnt_st == RPC_PROGVERSMISMATCH) ||
8752fe8fb19SBen Gras (clnt_st == RPC_PROGUNAVAIL)) {
8762fe8fb19SBen Gras start_vers = RPCBVERS; /* Try version 3 now */
8772fe8fb19SBen Gras goto regular_rpcbind; /* Try different versions */
8782fe8fb19SBen Gras } else {
8792fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_PMAPFAILURE;
8802fe8fb19SBen Gras clnt_geterr(client, &rpc_createerr.cf_error);
8812fe8fb19SBen Gras goto error;
8822fe8fb19SBen Gras }
8832fe8fb19SBen Gras }
8842fe8fb19SBen Gras
8852fe8fb19SBen Gras regular_rpcbind:
8862fe8fb19SBen Gras
8872fe8fb19SBen Gras /* Now the same transport is to be used to get the address */
8882fe8fb19SBen Gras #if 1
8892fe8fb19SBen Gras if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
8902fe8fb19SBen Gras (nconf->nc_semantics == NC_TPI_COTS)))
8912fe8fb19SBen Gras #else
8922fe8fb19SBen Gras if (client && nconf->nc_semantics == NC_TPI_CLTS)
8932fe8fb19SBen Gras #endif
8942fe8fb19SBen Gras {
8952fe8fb19SBen Gras /* A CLTS type of client - destroy it */
8962fe8fb19SBen Gras CLNT_DESTROY(client);
8972fe8fb19SBen Gras client = NULL;
8982fe8fb19SBen Gras }
8992fe8fb19SBen Gras
9002fe8fb19SBen Gras if (client == NULL) {
9012fe8fb19SBen Gras client = getclnthandle(host, nconf, &parms.r_addr);
9022fe8fb19SBen Gras if (client == NULL) {
9032fe8fb19SBen Gras goto error;
9042fe8fb19SBen Gras }
9052fe8fb19SBen Gras }
9062fe8fb19SBen Gras if (parms.r_addr == NULL)
9072fe8fb19SBen Gras parms.r_addr = __UNCONST(&nullstring[0]);
9082fe8fb19SBen Gras
9092fe8fb19SBen Gras /* First try from start_vers and then version 3 (RPCBVERS) */
9102fe8fb19SBen Gras for (vers = start_vers; vers >= RPCBVERS; vers--) {
9112fe8fb19SBen Gras /* Set the version */
9122fe8fb19SBen Gras CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
9132fe8fb19SBen Gras clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
9142fe8fb19SBen Gras (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
9152fe8fb19SBen Gras (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua,
9162fe8fb19SBen Gras tottimeout);
9172fe8fb19SBen Gras if (clnt_st == RPC_SUCCESS) {
9182fe8fb19SBen Gras if ((ua == NULL) || (ua[0] == 0)) {
9192fe8fb19SBen Gras /* address unknown */
9202fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
9212fe8fb19SBen Gras goto error;
9222fe8fb19SBen Gras }
9232fe8fb19SBen Gras address = uaddr2taddr(nconf, ua);
9242fe8fb19SBen Gras #ifdef ND_DEBUG
9252fe8fb19SBen Gras fprintf(stderr, "\tRemote address is [%s]\n", ua);
9262fe8fb19SBen Gras if (!address)
9272fe8fb19SBen Gras fprintf(stderr,
9282fe8fb19SBen Gras "\tCouldn't resolve remote address!\n");
9292fe8fb19SBen Gras #endif
9302fe8fb19SBen Gras xdr_free((xdrproc_t)xdr_wrapstring,
9312fe8fb19SBen Gras (char *)(void *)&ua);
9322fe8fb19SBen Gras
9332fe8fb19SBen Gras if (! address) {
9342fe8fb19SBen Gras /* We don't know about your universal address */
9352fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
9362fe8fb19SBen Gras goto error;
9372fe8fb19SBen Gras }
9382fe8fb19SBen Gras CLNT_CONTROL(client, CLGET_SVC_ADDR,
9392fe8fb19SBen Gras (char *)(void *)&servaddr);
9402fe8fb19SBen Gras __rpc_fixup_addr(address, &servaddr);
9412fe8fb19SBen Gras goto done;
9422fe8fb19SBen Gras } else if (clnt_st == RPC_PROGVERSMISMATCH) {
9432fe8fb19SBen Gras struct rpc_err rpcerr;
9442fe8fb19SBen Gras
9452fe8fb19SBen Gras clnt_geterr(client, &rpcerr);
9462fe8fb19SBen Gras if (rpcerr.re_vers.low > RPCBVERS4)
9472fe8fb19SBen Gras goto error; /* a new version, can't handle */
9482fe8fb19SBen Gras } else if (clnt_st != RPC_PROGUNAVAIL) {
9492fe8fb19SBen Gras /* Cant handle this error */
9502fe8fb19SBen Gras rpc_createerr.cf_stat = clnt_st;
9512fe8fb19SBen Gras clnt_geterr(client, &rpc_createerr.cf_error);
9522fe8fb19SBen Gras goto error;
9532fe8fb19SBen Gras }
9542fe8fb19SBen Gras }
9552fe8fb19SBen Gras
9562fe8fb19SBen Gras error:
9572fe8fb19SBen Gras if (client) {
9582fe8fb19SBen Gras CLNT_DESTROY(client);
9592fe8fb19SBen Gras client = NULL;
9602fe8fb19SBen Gras }
9612fe8fb19SBen Gras done:
9622fe8fb19SBen Gras if (nconf->nc_semantics != NC_TPI_CLTS) {
9632fe8fb19SBen Gras /* This client is the connectionless one */
9642fe8fb19SBen Gras if (client) {
9652fe8fb19SBen Gras CLNT_DESTROY(client);
9662fe8fb19SBen Gras client = NULL;
9672fe8fb19SBen Gras }
9682fe8fb19SBen Gras }
9692fe8fb19SBen Gras if (clpp) {
9702fe8fb19SBen Gras *clpp = client;
9712fe8fb19SBen Gras } else if (client) {
9722fe8fb19SBen Gras CLNT_DESTROY(client);
9732fe8fb19SBen Gras }
9742fe8fb19SBen Gras return (address);
9752fe8fb19SBen Gras }
9762fe8fb19SBen Gras
9772fe8fb19SBen Gras
9782fe8fb19SBen Gras /*
9792fe8fb19SBen Gras * Find the mapped address for program, version.
9802fe8fb19SBen Gras * Calls the rpcbind service remotely to do the lookup.
9812fe8fb19SBen Gras * Uses the transport specified in nconf.
9822fe8fb19SBen Gras * Returns FALSE (0) if no map exists, else returns 1.
9832fe8fb19SBen Gras *
9842fe8fb19SBen Gras * Assuming that the address is all properly allocated
9852fe8fb19SBen Gras */
986*0a6a1f1dSLionel Sambuc bool_t
rpcb_getaddr(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf,struct netbuf * address,const char * host)987*0a6a1f1dSLionel Sambuc rpcb_getaddr(const rpcprog_t program, const rpcvers_t version,
988f14fb602SLionel Sambuc const struct netconfig *nconf, struct netbuf *address,
989f14fb602SLionel Sambuc const char *host)
9902fe8fb19SBen Gras {
9912fe8fb19SBen Gras struct netbuf *na;
9922fe8fb19SBen Gras
9932fe8fb19SBen Gras _DIAGASSERT(address != NULL);
9942fe8fb19SBen Gras
9952fe8fb19SBen Gras if ((na = __rpcb_findaddr(program, version, nconf,
9962fe8fb19SBen Gras host, NULL)) == NULL)
9972fe8fb19SBen Gras return (FALSE);
9982fe8fb19SBen Gras
9992fe8fb19SBen Gras if (na->len > address->maxlen) {
10002fe8fb19SBen Gras /* Too long address */
10012fe8fb19SBen Gras free(na->buf);
10022fe8fb19SBen Gras free(na);
10032fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_FAILED;
10042fe8fb19SBen Gras return (FALSE);
10052fe8fb19SBen Gras }
10062fe8fb19SBen Gras memcpy(address->buf, na->buf, (size_t)na->len);
10072fe8fb19SBen Gras address->len = na->len;
10082fe8fb19SBen Gras free(na->buf);
10092fe8fb19SBen Gras free(na);
10102fe8fb19SBen Gras return (TRUE);
10112fe8fb19SBen Gras }
10122fe8fb19SBen Gras
10132fe8fb19SBen Gras /*
10142fe8fb19SBen Gras * Get a copy of the current maps.
10152fe8fb19SBen Gras * Calls the rpcbind service remotely to get the maps.
10162fe8fb19SBen Gras *
10172fe8fb19SBen Gras * It returns only a list of the services
10182fe8fb19SBen Gras * It returns NULL on failure.
10192fe8fb19SBen Gras */
10202fe8fb19SBen Gras rpcblist *
rpcb_getmaps(const struct netconfig * nconf,const char * host)1021f14fb602SLionel Sambuc rpcb_getmaps(const struct netconfig *nconf, const char *host)
10222fe8fb19SBen Gras {
10232fe8fb19SBen Gras rpcblist_ptr head = NULL;
10242fe8fb19SBen Gras CLIENT *client;
10252fe8fb19SBen Gras enum clnt_stat clnt_st;
10262fe8fb19SBen Gras rpcvers_t vers = 0;
10272fe8fb19SBen Gras
10282fe8fb19SBen Gras client = getclnthandle(host, nconf, NULL);
10292fe8fb19SBen Gras if (client == NULL) {
10302fe8fb19SBen Gras return (head);
10312fe8fb19SBen Gras }
10322fe8fb19SBen Gras clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
10332fe8fb19SBen Gras (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
10342fe8fb19SBen Gras (char *)(void *)&head, tottimeout);
10352fe8fb19SBen Gras if (clnt_st == RPC_SUCCESS)
10362fe8fb19SBen Gras goto done;
10372fe8fb19SBen Gras
10382fe8fb19SBen Gras if ((clnt_st != RPC_PROGVERSMISMATCH) &&
10392fe8fb19SBen Gras (clnt_st != RPC_PROGUNAVAIL)) {
10402fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_RPCBFAILURE;
10412fe8fb19SBen Gras clnt_geterr(client, &rpc_createerr.cf_error);
10422fe8fb19SBen Gras goto done;
10432fe8fb19SBen Gras }
10442fe8fb19SBen Gras
10452fe8fb19SBen Gras /* fall back to earlier version */
10462fe8fb19SBen Gras CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
10472fe8fb19SBen Gras if (vers == RPCBVERS4) {
10482fe8fb19SBen Gras vers = RPCBVERS;
10492fe8fb19SBen Gras CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
10502fe8fb19SBen Gras if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
10512fe8fb19SBen Gras (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
10522fe8fb19SBen Gras (char *)(void *)&head, tottimeout) == RPC_SUCCESS)
10532fe8fb19SBen Gras goto done;
10542fe8fb19SBen Gras }
10552fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_RPCBFAILURE;
10562fe8fb19SBen Gras clnt_geterr(client, &rpc_createerr.cf_error);
10572fe8fb19SBen Gras
10582fe8fb19SBen Gras done:
10592fe8fb19SBen Gras CLNT_DESTROY(client);
10602fe8fb19SBen Gras return (head);
10612fe8fb19SBen Gras }
10622fe8fb19SBen Gras
10632fe8fb19SBen Gras /*
10642fe8fb19SBen Gras * rpcbinder remote-call-service interface.
10652fe8fb19SBen Gras * This routine is used to call the rpcbind remote call service
10662fe8fb19SBen Gras * which will look up a service program in the address maps, and then
10672fe8fb19SBen Gras * remotely call that routine with the given parameters. This allows
10682fe8fb19SBen Gras * programs to do a lookup and call in one step.
10692fe8fb19SBen Gras */
10702fe8fb19SBen Gras enum clnt_stat
rpcb_rmtcall(const struct netconfig * nconf,const char * host,rpcprog_t prog,rpcvers_t vers,rpcproc_t proc,xdrproc_t xdrargs,const char * argsp,xdrproc_t xdrres,caddr_t resp,struct timeval tout,const struct netbuf * addr_ptr)1071f14fb602SLionel Sambuc rpcb_rmtcall(
1072f14fb602SLionel Sambuc const struct netconfig *nconf, /* Netconfig structure */
1073f14fb602SLionel Sambuc const char *host, /* Remote host name */
1074f14fb602SLionel Sambuc rpcprog_t prog,
1075f14fb602SLionel Sambuc rpcvers_t vers,
1076f14fb602SLionel Sambuc rpcproc_t proc, /* Remote proc identifiers */
1077f14fb602SLionel Sambuc xdrproc_t xdrargs,
1078f14fb602SLionel Sambuc const char *argsp, /* Argument */
1079f14fb602SLionel Sambuc xdrproc_t xdrres, /* XDR routines */
1080f14fb602SLionel Sambuc caddr_t resp, /* Result */
1081f14fb602SLionel Sambuc struct timeval tout, /* Timeout value for this call */
1082f14fb602SLionel Sambuc const struct netbuf *addr_ptr) /* Preallocated netbuf address */
10832fe8fb19SBen Gras {
10842fe8fb19SBen Gras CLIENT *client;
10852fe8fb19SBen Gras enum clnt_stat stat;
10862fe8fb19SBen Gras struct r_rpcb_rmtcallargs a;
10872fe8fb19SBen Gras struct r_rpcb_rmtcallres r;
10882fe8fb19SBen Gras rpcvers_t rpcb_vers;
10892fe8fb19SBen Gras
10902fe8fb19SBen Gras stat = RPC_FAILED; /* XXXGCC -Wuninitialized [dreamcast] */
10912fe8fb19SBen Gras
10922fe8fb19SBen Gras client = getclnthandle(host, nconf, NULL);
10932fe8fb19SBen Gras if (client == NULL) {
10942fe8fb19SBen Gras return (RPC_FAILED);
10952fe8fb19SBen Gras }
10962fe8fb19SBen Gras CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, __UNCONST(&rmttimeout));
10972fe8fb19SBen Gras a.prog = prog;
10982fe8fb19SBen Gras a.vers = vers;
10992fe8fb19SBen Gras a.proc = proc;
11002fe8fb19SBen Gras a.args.args_val = argsp;
11012fe8fb19SBen Gras a.xdr_args = xdrargs;
11022fe8fb19SBen Gras r.addr = NULL;
11032fe8fb19SBen Gras r.results.results_val = resp;
11042fe8fb19SBen Gras r.xdr_res = xdrres;
11052fe8fb19SBen Gras
11062fe8fb19SBen Gras for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
11072fe8fb19SBen Gras CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers);
11082fe8fb19SBen Gras stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT,
11092fe8fb19SBen Gras (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a,
11102fe8fb19SBen Gras (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout);
11112fe8fb19SBen Gras if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
11122fe8fb19SBen Gras struct netbuf *na;
11132fe8fb19SBen Gras na = uaddr2taddr(__UNCONST(nconf), r.addr);
11142fe8fb19SBen Gras if (!na) {
11152fe8fb19SBen Gras stat = RPC_N2AXLATEFAILURE;
11162fe8fb19SBen Gras ((struct netbuf *)__UNCONST(addr_ptr))->len = 0;
11172fe8fb19SBen Gras goto error;
11182fe8fb19SBen Gras }
11192fe8fb19SBen Gras if (na->len > addr_ptr->maxlen) {
11202fe8fb19SBen Gras /* Too long address */
11212fe8fb19SBen Gras stat = RPC_FAILED; /* XXX A better error no */
11222fe8fb19SBen Gras free(na->buf);
11232fe8fb19SBen Gras free(na);
11242fe8fb19SBen Gras ((struct netbuf *)__UNCONST(addr_ptr))->len = 0;
11252fe8fb19SBen Gras goto error;
11262fe8fb19SBen Gras }
11272fe8fb19SBen Gras memcpy(addr_ptr->buf, na->buf, (size_t)na->len);
11282fe8fb19SBen Gras ((struct netbuf *)__UNCONST(addr_ptr))->len = na->len;
11292fe8fb19SBen Gras free(na->buf);
11302fe8fb19SBen Gras free(na);
11312fe8fb19SBen Gras break;
11322fe8fb19SBen Gras } else if ((stat != RPC_PROGVERSMISMATCH) &&
11332fe8fb19SBen Gras (stat != RPC_PROGUNAVAIL)) {
11342fe8fb19SBen Gras goto error;
11352fe8fb19SBen Gras }
11362fe8fb19SBen Gras }
11372fe8fb19SBen Gras error:
11382fe8fb19SBen Gras CLNT_DESTROY(client);
11392fe8fb19SBen Gras if (r.addr)
11402fe8fb19SBen Gras xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr);
11412fe8fb19SBen Gras return (stat);
11422fe8fb19SBen Gras }
11432fe8fb19SBen Gras
11442fe8fb19SBen Gras /*
11452fe8fb19SBen Gras * Gets the time on the remote host.
11462fe8fb19SBen Gras * Returns 1 if succeeds else 0.
11472fe8fb19SBen Gras */
11482fe8fb19SBen Gras bool_t
rpcb_gettime(const char * host,time_t * timep)1149f14fb602SLionel Sambuc rpcb_gettime(const char *host, time_t *timep)
11502fe8fb19SBen Gras {
11512fe8fb19SBen Gras CLIENT *client = NULL;
11522fe8fb19SBen Gras void *handle;
11532fe8fb19SBen Gras struct netconfig *nconf;
11542fe8fb19SBen Gras rpcvers_t vers;
11552fe8fb19SBen Gras enum clnt_stat st;
11562fe8fb19SBen Gras
11572fe8fb19SBen Gras
11582fe8fb19SBen Gras if ((host == NULL) || (host[0] == 0)) {
11592fe8fb19SBen Gras time(timep);
11602fe8fb19SBen Gras return (TRUE);
11612fe8fb19SBen Gras }
11622fe8fb19SBen Gras
11632fe8fb19SBen Gras if ((handle = __rpc_setconf("netpath")) == NULL) {
11642fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
11652fe8fb19SBen Gras return (FALSE);
11662fe8fb19SBen Gras }
11672fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_SUCCESS;
11682fe8fb19SBen Gras while (client == NULL) {
11692fe8fb19SBen Gras if ((nconf = __rpc_getconf(handle)) == NULL) {
11702fe8fb19SBen Gras if (rpc_createerr.cf_stat == RPC_SUCCESS)
11712fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
11722fe8fb19SBen Gras break;
11732fe8fb19SBen Gras }
11742fe8fb19SBen Gras client = getclnthandle(host, nconf, NULL);
11752fe8fb19SBen Gras if (client)
11762fe8fb19SBen Gras break;
11772fe8fb19SBen Gras }
11782fe8fb19SBen Gras __rpc_endconf(handle);
11792fe8fb19SBen Gras if (client == NULL) {
11802fe8fb19SBen Gras return (FALSE);
11812fe8fb19SBen Gras }
11822fe8fb19SBen Gras
11832fe8fb19SBen Gras st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
11842fe8fb19SBen Gras (xdrproc_t) xdr_void, NULL,
11852fe8fb19SBen Gras (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout);
11862fe8fb19SBen Gras
11872fe8fb19SBen Gras if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
11882fe8fb19SBen Gras CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
11892fe8fb19SBen Gras if (vers == RPCBVERS4) {
11902fe8fb19SBen Gras /* fall back to earlier version */
11912fe8fb19SBen Gras vers = RPCBVERS;
11922fe8fb19SBen Gras CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
11932fe8fb19SBen Gras st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
11942fe8fb19SBen Gras (xdrproc_t) xdr_void, NULL,
11952fe8fb19SBen Gras (xdrproc_t) xdr_int, (char *)(void *)timep,
11962fe8fb19SBen Gras tottimeout);
11972fe8fb19SBen Gras }
11982fe8fb19SBen Gras }
11992fe8fb19SBen Gras CLNT_DESTROY(client);
12002fe8fb19SBen Gras return (st == RPC_SUCCESS? TRUE: FALSE);
12012fe8fb19SBen Gras }
12022fe8fb19SBen Gras
12032fe8fb19SBen Gras /*
12042fe8fb19SBen Gras * Converts taddr to universal address. This routine should never
12052fe8fb19SBen Gras * really be called because local n2a libraries are always provided.
12062fe8fb19SBen Gras */
12072fe8fb19SBen Gras char *
rpcb_taddr2uaddr(struct netconfig * nconf,struct netbuf * taddr)1208f14fb602SLionel Sambuc rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
12092fe8fb19SBen Gras {
12102fe8fb19SBen Gras CLIENT *client;
12112fe8fb19SBen Gras char *uaddr = NULL;
12122fe8fb19SBen Gras
12132fe8fb19SBen Gras /* parameter checking */
12142fe8fb19SBen Gras if (nconf == NULL) {
12152fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
12162fe8fb19SBen Gras return (NULL);
12172fe8fb19SBen Gras }
12182fe8fb19SBen Gras if (taddr == NULL) {
12192fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
12202fe8fb19SBen Gras return (NULL);
12212fe8fb19SBen Gras }
12222fe8fb19SBen Gras client = local_rpcb();
12232fe8fb19SBen Gras if (! client) {
12242fe8fb19SBen Gras return (NULL);
12252fe8fb19SBen Gras }
12262fe8fb19SBen Gras
1227*0a6a1f1dSLionel Sambuc if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR,
12282fe8fb19SBen Gras (xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
1229*0a6a1f1dSLionel Sambuc (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout)
1230*0a6a1f1dSLionel Sambuc != RPC_SUCCESS) {
1231*0a6a1f1dSLionel Sambuc rpc_createerr.cf_stat = RPC_PMAPFAILURE;
1232*0a6a1f1dSLionel Sambuc clnt_geterr(client, &rpc_createerr.cf_error);
1233*0a6a1f1dSLionel Sambuc }
12342fe8fb19SBen Gras CLNT_DESTROY(client);
12352fe8fb19SBen Gras return (uaddr);
12362fe8fb19SBen Gras }
12372fe8fb19SBen Gras
12382fe8fb19SBen Gras /*
12392fe8fb19SBen Gras * Converts universal address to netbuf. This routine should never
12402fe8fb19SBen Gras * really be called because local n2a libraries are always provided.
12412fe8fb19SBen Gras */
12422fe8fb19SBen Gras struct netbuf *
rpcb_uaddr2taddr(struct netconfig * nconf,char * uaddr)1243f14fb602SLionel Sambuc rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
12442fe8fb19SBen Gras {
12452fe8fb19SBen Gras CLIENT *client;
12462fe8fb19SBen Gras struct netbuf *taddr;
12472fe8fb19SBen Gras
12482fe8fb19SBen Gras
12492fe8fb19SBen Gras /* parameter checking */
12502fe8fb19SBen Gras if (nconf == NULL) {
12512fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
12522fe8fb19SBen Gras return (NULL);
12532fe8fb19SBen Gras }
12542fe8fb19SBen Gras if (uaddr == NULL) {
12552fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
12562fe8fb19SBen Gras return (NULL);
12572fe8fb19SBen Gras }
12582fe8fb19SBen Gras client = local_rpcb();
12592fe8fb19SBen Gras if (! client) {
12602fe8fb19SBen Gras return (NULL);
12612fe8fb19SBen Gras }
12622fe8fb19SBen Gras
12632fe8fb19SBen Gras taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf));
12642fe8fb19SBen Gras if (taddr == NULL) {
12652fe8fb19SBen Gras CLNT_DESTROY(client);
12662fe8fb19SBen Gras return (NULL);
12672fe8fb19SBen Gras }
12682fe8fb19SBen Gras if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR,
12692fe8fb19SBen Gras (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr,
12702fe8fb19SBen Gras (xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
12712fe8fb19SBen Gras tottimeout) != RPC_SUCCESS) {
1272*0a6a1f1dSLionel Sambuc rpc_createerr.cf_stat = RPC_PMAPFAILURE;
1273*0a6a1f1dSLionel Sambuc clnt_geterr(client, &rpc_createerr.cf_error);
12742fe8fb19SBen Gras free(taddr);
12752fe8fb19SBen Gras taddr = NULL;
12762fe8fb19SBen Gras }
12772fe8fb19SBen Gras CLNT_DESTROY(client);
12782fe8fb19SBen Gras return (taddr);
12792fe8fb19SBen Gras }
1280