rpcb_clnt.c revision 241007
167468Snon/* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */ 279697Snon 367468Snon/* 467468Snon * The contents of this file are subject to the Sun Standards 567468Snon * License Version 1.0 the (the "License";) You may not use 679697Snon * this file except in compliance with the License. You may 779697Snon * obtain a copy of the License at lib/libc/rpc/LICENSE 879697Snon * 979697Snon * Software distributed under the License is distributed on 1079697Snon * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 1179697Snon * express or implied. See the License for the specific 1279697Snon * language governing rights and limitations under the License. 1379697Snon * 1467468Snon * The Original Code is Copyright 1998 by Sun Microsystems, Inc 1567468Snon * 1679697Snon * The Initial Developer of the Original Code is: Sun 1767468Snon * Microsystems, Inc. 1879697Snon * 1979697Snon * All Rights Reserved. 2079697Snon * 2179697Snon * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 2267468Snon * unrestricted use provided that this legend is included on all tape 2367468Snon * media and as a part of the software program in whole or part. Users 2479697Snon * may copy or modify Sun RPC without charge, but are not authorized 2567468Snon * to license or distribute it to anyone else except as part of a product or 2679697Snon * program developed by the user. 2767468Snon * 2879697Snon * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 2979697Snon * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 3079697Snon * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 3179697Snon * 3279697Snon * Sun RPC is provided with no support and without any obligation on the 3367468Snon * part of Sun Microsystems, Inc. to assist in its use, correction, 3467468Snon * modification or enhancement. 3567468Snon * 3667468Snon * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 3767468Snon * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 3867468Snon * OR ANY PART THEREOF. 3967468Snon * 4067468Snon * In no event will Sun Microsystems, Inc. be liable for any lost revenue 4167468Snon * or profits or other special, indirect and consequential damages, even if 4267468Snon * Sun has been advised of the possibility of such damages. 4367468Snon * 4467468Snon * Sun Microsystems, Inc. 4567468Snon * 2550 Garcia Avenue 4667468Snon * Mountain View, California 94043 4767468Snon */ 4867468Snon/* 4967468Snon * Copyright (c) 1986-1991 by Sun Microsystems Inc. 5067468Snon */ 5167468Snon 5267468Snon/* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */ 5367468Snon 5467468Snon 5567468Snon#if defined(LIBC_SCCS) && !defined(lint) 5667468Snonstatic char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro"; 5767468Snon#endif 5867468Snon#include <sys/cdefs.h> 5967468Snon__FBSDID("$FreeBSD: head/sys/rpc/rpcb_clnt.c 241007 2012-09-27 19:10:25Z pfg $"); 6067468Snon 6167468Snon/* 6279697Snon * rpcb_clnt.c 6379697Snon * interface to rpcbind rpc service. 6479697Snon * 6567468Snon * Copyright (C) 1988, Sun Microsystems, Inc. 6667468Snon */ 6767468Snon 6867468Snon#include "opt_inet6.h" 6967468Snon 7067468Snon#include <sys/param.h> 7179697Snon#include <sys/systm.h> 7273025Snon#include <sys/kernel.h> 7373025Snon#include <sys/malloc.h> 7467468Snon#include <sys/proc.h> 7579697Snon#include <sys/socket.h> 7679697Snon#include <sys/socketvar.h> 7773025Snon 7869979Snon#include <rpc/rpc.h> 7979697Snon#include <rpc/rpcb_clnt.h> 8079697Snon#include <rpc/rpcb_prot.h> 8167468Snon 8267468Snon#include <rpc/rpc_com.h> 8367468Snon 8467468Snonstatic struct timeval tottimeout = { 60, 0 }; 8567468Snonstatic const struct timeval rmttimeout = { 3, 0 }; 8679697Snonstatic const char nullstring[] = "\000"; 8779697Snon 8867468Snonstatic CLIENT *local_rpcb(void); 8967468Snon 9067468Snon#if 0 9167468Snon 9267468Snonstatic struct timeval rpcbrmttime = { 15, 0 }; 9367468Snon 9467468Snon#define CACHESIZE 6 9567468Snon 9667468Snonstruct address_cache { 9767468Snon char *ac_host; 9867468Snon char *ac_netid; 9967468Snon char *ac_uaddr; 10067468Snon struct netbuf *ac_taddr; 10179697Snon struct address_cache *ac_next; 10267468Snon}; 10367468Snon 10479697Snonstatic struct address_cache *front; 10579697Snonstatic int cachesize; 10667468Snon 10767468Snon#define CLCR_GET_RPCB_TIMEOUT 1 10867468Snon#define CLCR_SET_RPCB_TIMEOUT 2 10967468Snon 11067468Snon 11167468Snonextern int __rpc_lowvers; 11267468Snon 11367468Snonstatic struct address_cache *check_cache(const char *, const char *); 11473025Snonstatic void delete_cache(struct netbuf *); 11567468Snonstatic void add_cache(const char *, const char *, struct netbuf *, char *); 11667468Snonstatic CLIENT *getclnthandle(const char *, const struct netconfig *, char **); 11767468Snonstatic CLIENT *local_rpcb(void); 11867468Snonstatic struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *); 11979697Snon 12067468Snon/* 12179697Snon * This routine adjusts the timeout used for calls to the remote rpcbind. 12279697Snon * Also, this routine can be used to set the use of portmapper version 2 12379697Snon * only when doing rpc_broadcasts 12479697Snon * These are private routines that may not be provided in future releases. 12567468Snon */ 12679697Snonbool_t 12779697Snon__rpc_control(request, info) 12879697Snon int request; 12979697Snon void *info; 13067468Snon{ 13167468Snon switch (request) { 13267468Snon case CLCR_GET_RPCB_TIMEOUT: 13379697Snon *(struct timeval *)info = tottimeout; 13479697Snon break; 13579697Snon case CLCR_SET_RPCB_TIMEOUT: 13679697Snon tottimeout = *(struct timeval *)info; 13779697Snon break; 13879697Snon case CLCR_SET_LOWVERS: 13979697Snon __rpc_lowvers = *(int *)info; 14079697Snon break; 14179697Snon case CLCR_GET_LOWVERS: 14279697Snon *(int *)info = __rpc_lowvers; 14379697Snon break; 14479697Snon default: 14579697Snon return (FALSE); 14679697Snon } 14779697Snon return (TRUE); 14879697Snon} 14967468Snon 15067468Snon/* 15167468Snon * It might seem that a reader/writer lock would be more reasonable here. 15279697Snon * However because getclnthandle(), the only user of the cache functions, 15379697Snon * may do a delete_cache() operation if a check_cache() fails to return an 15467468Snon * address useful to clnt_tli_create(), we may as well use a mutex. 15567468Snon */ 15679697Snon/* 15779697Snon * As it turns out, if the cache lock is *not* a reader/writer lock, we will 15879697Snon * block all clnt_create's if we are trying to connect to a host that's down, 15979697Snon * since the lock will be held all during that time. 16067468Snon */ 16179697Snon 16279697Snon/* 16367468Snon * The routines check_cache(), add_cache(), delete_cache() manage the 16467468Snon * cache of rpcbind addresses for (host, netid). 16567468Snon */ 16667468Snon 16779697Snonstatic struct address_cache * 16879697Snoncheck_cache(host, netid) 16979697Snon const char *host, *netid; 17079697Snon{ 17179697Snon struct address_cache *cptr; 17279697Snon 17379697Snon /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ 17479697Snon 17579697Snon for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { 17679697Snon if (!strcmp(cptr->ac_host, host) && 17779697Snon !strcmp(cptr->ac_netid, netid)) { 17879697Snon#ifdef ND_DEBUG 17979697Snon fprintf(stderr, "Found cache entry for %s: %s\n", 18079697Snon host, netid); 18179697Snon#endif 18279697Snon return (cptr); 18379697Snon } 18479697Snon } 18579697Snon return ((struct address_cache *) NULL); 18679697Snon} 18779697Snon 18879697Snonstatic void 18979697Snondelete_cache(addr) 19079697Snon struct netbuf *addr; 19179697Snon{ 19279697Snon struct address_cache *cptr, *prevptr = NULL; 19379697Snon 19467468Snon /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ 19589113Smsmith for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { 19667468Snon if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { 19767468Snon free(cptr->ac_host); 19867468Snon free(cptr->ac_netid); 19967468Snon free(cptr->ac_taddr->buf); 20067468Snon free(cptr->ac_taddr); 20167468Snon if (cptr->ac_uaddr) 20267468Snon free(cptr->ac_uaddr); 20379697Snon if (prevptr) 20479697Snon prevptr->ac_next = cptr->ac_next; 20579697Snon else 20679697Snon front = cptr->ac_next; 20779697Snon free(cptr); 20879697Snon cachesize--; 20979697Snon break; 21079697Snon } 21179697Snon prevptr = cptr; 21279697Snon } 21379697Snon} 21479697Snon 21579697Snonstatic void 21679697Snonadd_cache(host, netid, taddr, uaddr) 21779697Snon const char *host, *netid; 21879697Snon char *uaddr; 21979697Snon struct netbuf *taddr; 22079697Snon{ 22179697Snon struct address_cache *ad_cache, *cptr, *prevptr; 22279697Snon 22379697Snon ad_cache = (struct address_cache *) 22479697Snon malloc(sizeof (struct address_cache)); 22579697Snon if (!ad_cache) { 22679697Snon return; 22779697Snon } 22879697Snon ad_cache->ac_host = strdup(host); 22967468Snon ad_cache->ac_netid = strdup(netid); 23079697Snon ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL; 23179697Snon ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf)); 23279697Snon if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr || 23379697Snon (uaddr && !ad_cache->ac_uaddr)) { 23479697Snon goto out; 23579697Snon } 23679697Snon ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len; 23779697Snon ad_cache->ac_taddr->buf = (char *) malloc(taddr->len); 23879697Snon if (ad_cache->ac_taddr->buf == NULL) { 23979697Snonout: 24079697Snon if (ad_cache->ac_host) 24179697Snon free(ad_cache->ac_host); 24279697Snon if (ad_cache->ac_netid) 24379697Snon free(ad_cache->ac_netid); 24479697Snon if (ad_cache->ac_uaddr) 24579697Snon free(ad_cache->ac_uaddr); 24679697Snon if (ad_cache->ac_taddr) 24779697Snon free(ad_cache->ac_taddr); 24879697Snon free(ad_cache); 24979697Snon return; 25079697Snon } 25179697Snon memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len); 25279697Snon#ifdef ND_DEBUG 25379697Snon fprintf(stderr, "Added to cache: %s : %s\n", host, netid); 25479697Snon#endif 25579697Snon 25679697Snon/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ 25779697Snon 25879697Snon rwlock_wrlock(&rpcbaddr_cache_lock); 25979697Snon if (cachesize < CACHESIZE) { 26079697Snon ad_cache->ac_next = front; 26179697Snon front = ad_cache; 26279697Snon cachesize++; 26379697Snon } else { 26479697Snon /* Free the last entry */ 26579697Snon cptr = front; 26679697Snon prevptr = NULL; 26779697Snon while (cptr->ac_next) { 26879697Snon prevptr = cptr; 26979697Snon cptr = cptr->ac_next; 27079697Snon } 27179697Snon 27279697Snon#ifdef ND_DEBUG 27379697Snon fprintf(stderr, "Deleted from cache: %s : %s\n", 27479697Snon cptr->ac_host, cptr->ac_netid); 27579697Snon#endif 27679697Snon free(cptr->ac_host); 27779697Snon free(cptr->ac_netid); 27879697Snon free(cptr->ac_taddr->buf); 27979697Snon free(cptr->ac_taddr); 28079697Snon if (cptr->ac_uaddr) 28179697Snon free(cptr->ac_uaddr); 28279697Snon 28379697Snon if (prevptr) { 28479697Snon prevptr->ac_next = NULL; 28579697Snon ad_cache->ac_next = front; 28679697Snon front = ad_cache; 28779697Snon } else { 28879697Snon front = ad_cache; 28979697Snon ad_cache->ac_next = NULL; 29079697Snon } 29179697Snon free(cptr); 29279697Snon } 29379697Snon rwlock_unlock(&rpcbaddr_cache_lock); 29479697Snon} 29579697Snon 29679697Snon/* 29779697Snon * This routine will return a client handle that is connected to the 29879697Snon * rpcbind. If targaddr is non-NULL, the "universal address" of the 29979697Snon * host will be stored in *targaddr; the caller is responsible for 30079697Snon * freeing this string. 30179697Snon * On error, returns NULL and free's everything. 30279697Snon */ 30379697Snonstatic CLIENT * 30479697Snongetclnthandle(host, nconf, targaddr) 30579697Snon const char *host; 30679697Snon const struct netconfig *nconf; 30779697Snon char **targaddr; 30879697Snon{ 30979697Snon CLIENT *client; 31079697Snon struct netbuf *addr, taddr; 31179697Snon struct netbuf addr_to_delete; 31279697Snon struct __rpc_sockinfo si; 31379697Snon struct addrinfo hints, *res, *tres; 31479697Snon struct address_cache *ad_cache; 31579697Snon char *tmpaddr; 31679697Snon 31779697Snon/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ 31879697Snon 31979697Snon /* Get the address of the rpcbind. Check cache first */ 32079697Snon client = NULL; 32179697Snon addr_to_delete.len = 0; 32279697Snon rwlock_rdlock(&rpcbaddr_cache_lock); 32379697Snon ad_cache = NULL; 32479697Snon if (host != NULL) 32579697Snon ad_cache = check_cache(host, nconf->nc_netid); 32679697Snon if (ad_cache != NULL) { 32779697Snon addr = ad_cache->ac_taddr; 32879697Snon client = clnt_tli_create(RPC_ANYFD, nconf, addr, 32979697Snon (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); 33079697Snon if (client != NULL) { 33179697Snon if (targaddr) 33279697Snon *targaddr = strdup(ad_cache->ac_uaddr); 33379697Snon rwlock_unlock(&rpcbaddr_cache_lock); 33479697Snon return (client); 33579697Snon } 33679697Snon addr_to_delete.len = addr->len; 33779697Snon addr_to_delete.buf = (char *)malloc(addr->len); 33879697Snon if (addr_to_delete.buf == NULL) { 33979697Snon addr_to_delete.len = 0; 34079697Snon } else { 34179697Snon memcpy(addr_to_delete.buf, addr->buf, addr->len); 34279697Snon } 34379697Snon } 34479697Snon rwlock_unlock(&rpcbaddr_cache_lock); 34579697Snon if (addr_to_delete.len != 0) { 34679697Snon /* 34779697Snon * Assume this may be due to cache data being 34879697Snon * outdated 34979697Snon */ 35079697Snon rwlock_wrlock(&rpcbaddr_cache_lock); 35179697Snon delete_cache(&addr_to_delete); 35279697Snon rwlock_unlock(&rpcbaddr_cache_lock); 35379697Snon free(addr_to_delete.buf); 35479697Snon } 35579697Snon if (!__rpc_nconf2sockinfo(nconf, &si)) { 35679697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 35779697Snon return NULL; 35879697Snon } 35979697Snon 36079697Snon memset(&hints, 0, sizeof hints); 36179697Snon hints.ai_family = si.si_af; 36279697Snon hints.ai_socktype = si.si_socktype; 36379697Snon hints.ai_protocol = si.si_proto; 36479697Snon 36579697Snon#ifdef CLNT_DEBUG 36679697Snon printf("trying netid %s family %d proto %d socktype %d\n", 36779697Snon nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype); 36879697Snon#endif 36979697Snon 37079697Snon if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 37179697Snon client = local_rpcb(); 37279697Snon if (! client) { 37379697Snon#ifdef ND_DEBUG 37479697Snon clnt_pcreateerror("rpcbind clnt interface"); 37579697Snon#endif 37679697Snon return (NULL); 37779697Snon } else { 37879697Snon struct sockaddr_un sun; 37979697Snon if (targaddr) { 38079697Snon *targaddr = malloc(sizeof(sun.sun_path)); 38179697Snon if (*targaddr == NULL) { 38279697Snon CLNT_DESTROY(client); 38379697Snon return (NULL); 38479697Snon } 38579697Snon strncpy(*targaddr, _PATH_RPCBINDSOCK, 38679697Snon sizeof(sun.sun_path)); 38779697Snon } 38879697Snon return (client); 38979697Snon } 39079697Snon } else { 39179697Snon if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) { 39279697Snon rpc_createerr.cf_stat = RPC_UNKNOWNHOST; 39379697Snon return NULL; 39479697Snon } 39579697Snon } 39679697Snon 39779697Snon for (tres = res; tres != NULL; tres = tres->ai_next) { 39879697Snon taddr.buf = tres->ai_addr; 39979697Snon taddr.len = taddr.maxlen = tres->ai_addrlen; 40079697Snon 40179697Snon#ifdef ND_DEBUG 40279697Snon { 40379697Snon char *ua; 40479697Snon 40579697Snon ua = taddr2uaddr(nconf, &taddr); 40679697Snon fprintf(stderr, "Got it [%s]\n", ua); 40779697Snon free(ua); 40879697Snon } 40979697Snon#endif 41079697Snon 41179697Snon#ifdef ND_DEBUG 41279697Snon { 41379697Snon int i; 41479697Snon 41579697Snon fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n", 41679697Snon taddr.len, taddr.maxlen); 41779697Snon fprintf(stderr, "\tAddress is "); 41879697Snon for (i = 0; i < taddr.len; i++) 41979697Snon fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]); 42079697Snon fprintf(stderr, "\n"); 42179697Snon } 42279697Snon#endif 42379697Snon client = clnt_tli_create(RPC_ANYFD, nconf, &taddr, 42479697Snon (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); 42579697Snon#ifdef ND_DEBUG 42679697Snon if (! client) { 42779697Snon clnt_pcreateerror("rpcbind clnt interface"); 42879697Snon } 42979697Snon#endif 43079697Snon 43179697Snon if (client) { 43279697Snon tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL; 43379697Snon add_cache(host, nconf->nc_netid, &taddr, tmpaddr); 43479697Snon if (targaddr) 43579697Snon *targaddr = tmpaddr; 43679697Snon break; 43779697Snon } 43879697Snon } 43979697Snon if (res) 44079697Snon freeaddrinfo(res); 44179697Snon return (client); 44279697Snon} 44379697Snon 44479697Snon#endif 44579697Snon 44679697Snon/* XXX */ 44779697Snon#define IN4_LOCALHOST_STRING "127.0.0.1" 44879697Snon#define IN6_LOCALHOST_STRING "::1" 44979697Snon 45079697Snon/* 45179697Snon * This routine will return a client handle that is connected to the local 45279697Snon * rpcbind. Returns NULL on error and free's everything. 45379697Snon */ 45479697Snonstatic CLIENT * 45579697Snonlocal_rpcb() 45679697Snon{ 45779697Snon CLIENT *client; 45879697Snon struct socket *so; 45979697Snon size_t tsize; 46079697Snon struct sockaddr_un sun; 46179697Snon int error; 46279697Snon 46379697Snon /* 46479697Snon * Try connecting to the local rpcbind through a local socket 46579697Snon * first. If this doesn't work, try all transports defined in 46679697Snon * the netconfig file. 46779697Snon */ 46879697Snon memset(&sun, 0, sizeof sun); 46979697Snon so = NULL; 47079697Snon error = socreate(AF_LOCAL, &so, SOCK_STREAM, 0, curthread->td_ucred, 47179697Snon curthread); 47279697Snon if (error) 47379697Snon goto try_nconf; 47479697Snon sun.sun_family = AF_LOCAL; 47579697Snon strcpy(sun.sun_path, _PATH_RPCBINDSOCK); 47679697Snon sun.sun_len = SUN_LEN(&sun); 47779697Snon 47879697Snon tsize = __rpc_get_t_size(AF_LOCAL, 0, 0); 47979697Snon client = clnt_vc_create(so, (struct sockaddr *)&sun, (rpcprog_t)RPCBPROG, 48079697Snon (rpcvers_t)RPCBVERS, tsize, tsize, 1); 48179697Snon 48279697Snon if (client != NULL) { 48379697Snon /* Mark the socket to be closed in destructor */ 48479697Snon (void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); 48579697Snon return client; 48679697Snon } 48779697Snon 48879697Snon /* Nobody needs this socket anymore; free the descriptor. */ 48979697Snon soclose(so); 49079697Snon 49179697Snontry_nconf: 49279697Snon 49379697Snon#if 0 49479697Snon static struct netconfig *loopnconf; 49579697Snon static char *localhostname; 49679697Snon 49779697Snon/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */ 49879697Snon mutex_lock(&loopnconf_lock); 49979697Snon if (loopnconf == NULL) { 50079697Snon struct netconfig *nconf, *tmpnconf = NULL; 50179697Snon void *nc_handle; 50279697Snon int fd; 50379697Snon 50479697Snon nc_handle = setnetconfig(); 50579697Snon if (nc_handle == NULL) { 50679697Snon /* fails to open netconfig file */ 50779697Snon syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 50879697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 50979697Snon mutex_unlock(&loopnconf_lock); 51079697Snon return (NULL); 51179697Snon } 51279697Snon while ((nconf = getnetconfig(nc_handle)) != NULL) { 51379697Snon if (( 51479697Snon#ifdef INET6 51579697Snon strcmp(nconf->nc_protofmly, NC_INET6) == 0 || 51679697Snon#endif 51779697Snon strcmp(nconf->nc_protofmly, NC_INET) == 0) && 51879697Snon (nconf->nc_semantics == NC_TPI_COTS || 51979697Snon nconf->nc_semantics == NC_TPI_COTS_ORD)) { 52079697Snon fd = __rpc_nconf2fd(nconf); 52179697Snon /* 52279697Snon * Can't create a socket, assume that 52379697Snon * this family isn't configured in the kernel. 52479697Snon */ 52579697Snon if (fd < 0) 52679697Snon continue; 52779697Snon _close(fd); 52879697Snon tmpnconf = nconf; 52979697Snon if (!strcmp(nconf->nc_protofmly, NC_INET)) 53079697Snon localhostname = IN4_LOCALHOST_STRING; 53179697Snon else 53279697Snon localhostname = IN6_LOCALHOST_STRING; 53379697Snon } 53479697Snon } 53579697Snon if (tmpnconf == NULL) { 53679697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 53779697Snon mutex_unlock(&loopnconf_lock); 53879697Snon return (NULL); 53979697Snon } 54079697Snon loopnconf = getnetconfigent(tmpnconf->nc_netid); 54179697Snon /* loopnconf is never freed */ 54279697Snon endnetconfig(nc_handle); 54379697Snon } 54479697Snon mutex_unlock(&loopnconf_lock); 54579697Snon client = getclnthandle(localhostname, loopnconf, NULL); 54679697Snon return (client); 54779697Snon#else 54879697Snon return (NULL); 54979697Snon#endif 55079697Snon} 55179697Snon 55279697Snon/* 55379697Snon * Set a mapping between program, version and address. 55479697Snon * Calls the rpcbind service to do the mapping. 55579697Snon */ 55679697Snonbool_t 55779697Snonrpcb_set(rpcprog_t program, rpcvers_t version, 55879697Snon const struct netconfig *nconf, /* Network structure of transport */ 55979697Snon const struct netbuf *address) /* Services netconfig address */ 56079697Snon{ 56179697Snon CLIENT *client; 56279697Snon bool_t rslt = FALSE; 56379697Snon RPCB parms; 56479697Snon#if 0 56579697Snon char uidbuf[32]; 56679697Snon#endif 56779697Snon struct netconfig nconfcopy; 56879697Snon struct netbuf addresscopy; 56979697Snon 57079697Snon /* parameter checking */ 57179697Snon if (nconf == NULL) { 57279697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 57379697Snon return (FALSE); 57479697Snon } 57579697Snon if (address == NULL) { 57679697Snon rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 57779697Snon return (FALSE); 57879697Snon } 57979697Snon client = local_rpcb(); 58079697Snon if (! client) { 58179697Snon return (FALSE); 58279697Snon } 58379697Snon 58479697Snon /* convert to universal */ 58579697Snon /*LINTED const castaway*/ 58679697Snon nconfcopy = *nconf; 58779697Snon addresscopy = *address; 58879697Snon parms.r_addr = taddr2uaddr(&nconfcopy, &addresscopy); 58979697Snon if (!parms.r_addr) { 59079697Snon CLNT_DESTROY(client); 59179697Snon rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 59279697Snon return (FALSE); /* no universal address */ 59379697Snon } 59479697Snon parms.r_prog = program; 59579697Snon parms.r_vers = version; 59679697Snon parms.r_netid = nconf->nc_netid; 59779697Snon#if 0 59879697Snon /* 59979697Snon * Though uid is not being used directly, we still send it for 60079697Snon * completeness. For non-unix platforms, perhaps some other 60179697Snon * string or an empty string can be sent. 60279697Snon */ 60379697Snon (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); 60479697Snon parms.r_owner = uidbuf; 60579697Snon#else 60679697Snon parms.r_owner = ""; 60779697Snon#endif 60879697Snon 60979697Snon CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb, 61079697Snon (char *)(void *)&parms, (xdrproc_t) xdr_bool, 61179697Snon (char *)(void *)&rslt, tottimeout); 61279697Snon 61379697Snon CLNT_DESTROY(client); 61479697Snon free(parms.r_addr, M_RPC); 61579697Snon return (rslt); 61679697Snon} 61779697Snon 61879697Snon/* 61979697Snon * Remove the mapping between program, version and netbuf address. 62079697Snon * Calls the rpcbind service to do the un-mapping. 62179697Snon * If netbuf is NULL, unset for all the transports, otherwise unset 62279697Snon * only for the given transport. 62379697Snon */ 62479697Snonbool_t 62579697Snonrpcb_unset(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf) 62679697Snon{ 62779697Snon CLIENT *client; 62879697Snon bool_t rslt = FALSE; 62979697Snon RPCB parms; 63079697Snon#if 0 63179697Snon char uidbuf[32]; 63279697Snon#endif 63379697Snon 63479697Snon client = local_rpcb(); 63579697Snon if (! client) { 63679697Snon return (FALSE); 63779697Snon } 63879697Snon 63979697Snon parms.r_prog = program; 64079697Snon parms.r_vers = version; 64179697Snon if (nconf) 64279697Snon parms.r_netid = nconf->nc_netid; 64379697Snon else { 64479697Snon /*LINTED const castaway*/ 64579697Snon parms.r_netid = (char *)(uintptr_t) &nullstring[0]; /* unsets all */ 64679697Snon } 64779697Snon /*LINTED const castaway*/ 64879697Snon parms.r_addr = (char *)(uintptr_t) &nullstring[0]; 64979697Snon#if 0 65079697Snon (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); 65179697Snon parms.r_owner = uidbuf; 65279697Snon#else 65379697Snon parms.r_owner = ""; 65479697Snon#endif 65579697Snon 65679697Snon CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb, 65779697Snon (char *)(void *)&parms, (xdrproc_t) xdr_bool, 65879697Snon (char *)(void *)&rslt, tottimeout); 65979697Snon 66079697Snon CLNT_DESTROY(client); 66179697Snon return (rslt); 66279697Snon} 66379697Snon 66479697Snon#if 0 66579697Snon 66679697Snon/* 66779697Snon * From the merged list, find the appropriate entry 66879697Snon */ 66979697Snonstatic struct netbuf * 67079697Snongot_entry(relp, nconf) 67179697Snon rpcb_entry_list_ptr relp; 67279697Snon const struct netconfig *nconf; 67379697Snon{ 67479697Snon struct netbuf *na = NULL; 67579697Snon rpcb_entry_list_ptr sp; 67679697Snon rpcb_entry *rmap; 67779697Snon 67879697Snon for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) { 67979697Snon rmap = &sp->rpcb_entry_map; 68079697Snon if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) && 68179697Snon (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) && 68279697Snon (nconf->nc_semantics == rmap->r_nc_semantics) && 68379697Snon (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) { 68479697Snon na = uaddr2taddr(nconf, rmap->r_maddr); 68579697Snon#ifdef ND_DEBUG 68679697Snon fprintf(stderr, "\tRemote address is [%s].\n", 68779697Snon rmap->r_maddr); 68879697Snon if (!na) 68979697Snon fprintf(stderr, 69079697Snon "\tCouldn't resolve remote address!\n"); 69179697Snon#endif 69279697Snon break; 69379697Snon } 69479697Snon } 69579697Snon return (na); 69679697Snon} 69779697Snon 69879697Snon/* 69979697Snon * Quick check to see if rpcbind is up. Tries to connect over 70079697Snon * local transport. 70179697Snon */ 70279697Snonstatic bool_t 70379697Snon__rpcbind_is_up() 70479697Snon{ 70579697Snon struct netconfig *nconf; 70679697Snon struct sockaddr_un sun; 70779697Snon void *localhandle; 70879697Snon int sock; 70979697Snon 71079697Snon nconf = NULL; 71179697Snon localhandle = setnetconfig(); 71279697Snon while ((nconf = getnetconfig(localhandle)) != NULL) { 71379697Snon if (nconf->nc_protofmly != NULL && 71479697Snon strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) 71579697Snon break; 71679697Snon } 71779697Snon if (nconf == NULL) 71879697Snon return (FALSE); 71979697Snon 72079697Snon endnetconfig(localhandle); 72179697Snon 72279697Snon memset(&sun, 0, sizeof sun); 72379697Snon sock = _socket(AF_LOCAL, SOCK_STREAM, 0); 72479697Snon if (sock < 0) 72579697Snon return (FALSE); 72679697Snon sun.sun_family = AF_LOCAL; 72779697Snon strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path)); 72879697Snon sun.sun_len = SUN_LEN(&sun); 72979697Snon 73079697Snon if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) { 73179697Snon _close(sock); 73279697Snon return (FALSE); 73379697Snon } 73479697Snon 73579697Snon _close(sock); 73679697Snon return (TRUE); 73779697Snon} 73879697Snon 73979697Snon/* 74079697Snon * An internal function which optimizes rpcb_getaddr function. It also 74179697Snon * returns the client handle that it uses to contact the remote rpcbind. 74279697Snon * 74379697Snon * The algorithm used: If the transports is TCP or UDP, it first tries 74479697Snon * version 2 (portmap), 4 and then 3 (svr4). This order should be 74579697Snon * changed in the next OS release to 4, 2 and 3. We are assuming that by 74679697Snon * that time, version 4 would be available on many machines on the network. 74779697Snon * With this algorithm, we get performance as well as a plan for 74879697Snon * obsoleting version 2. 74979697Snon * 75079697Snon * For all other transports, the algorithm remains as 4 and then 3. 75179697Snon * 75279697Snon * XXX: Due to some problems with t_connect(), we do not reuse the same client 75379697Snon * handle for COTS cases and hence in these cases we do not return the 75479697Snon * client handle. This code will change if t_connect() ever 75579697Snon * starts working properly. Also look under clnt_vc.c. 75679697Snon */ 75779697Snonstruct netbuf * 75879697Snon__rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) 75979697Snon rpcprog_t program; 76079697Snon rpcvers_t version; 76179697Snon const struct netconfig *nconf; 76279697Snon const char *host; 76379697Snon CLIENT **clpp; 76479697Snon struct timeval *tp; 76579697Snon{ 76679697Snon static bool_t check_rpcbind = TRUE; 76779697Snon CLIENT *client = NULL; 76879697Snon RPCB parms; 76979697Snon enum clnt_stat clnt_st; 77079697Snon char *ua = NULL; 77179697Snon rpcvers_t vers; 77279697Snon struct netbuf *address = NULL; 77379697Snon rpcvers_t start_vers = RPCBVERS4; 77479697Snon struct netbuf servaddr; 77579697Snon 77679697Snon /* parameter checking */ 77779697Snon if (nconf == NULL) { 77879697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 77979697Snon return (NULL); 78079697Snon } 78179697Snon 78279697Snon parms.r_addr = NULL; 78379697Snon 78479697Snon /* 78579697Snon * Use default total timeout if no timeout is specified. 78679697Snon */ 78779697Snon if (tp == NULL) 78879697Snon tp = &tottimeout; 78979697Snon 79079697Snon#ifdef PORTMAP 79179697Snon /* Try version 2 for TCP or UDP */ 79279697Snon if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 79379697Snon u_short port = 0; 79479697Snon struct netbuf remote; 79579697Snon rpcvers_t pmapvers = 2; 79679697Snon struct pmap pmapparms; 79779697Snon 79879697Snon /* 79979697Snon * Try UDP only - there are some portmappers out 80079697Snon * there that use UDP only. 80179697Snon */ 80279697Snon if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 80379697Snon struct netconfig *newnconf; 80479697Snon 80579697Snon if ((newnconf = getnetconfigent("udp")) == NULL) { 80679697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 80779697Snon return (NULL); 80879697Snon } 80979697Snon client = getclnthandle(host, newnconf, &parms.r_addr); 81079697Snon freenetconfigent(newnconf); 81179697Snon } else { 81279697Snon client = getclnthandle(host, nconf, &parms.r_addr); 81379697Snon } 81479697Snon if (client == NULL) 81579697Snon return (NULL); 81679697Snon 81779697Snon /* 81879697Snon * Set version and retry timeout. 81979697Snon */ 82079697Snon CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); 82179697Snon CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); 82279697Snon 82379697Snon pmapparms.pm_prog = program; 82479697Snon pmapparms.pm_vers = version; 82579697Snon pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? 82679697Snon IPPROTO_UDP : IPPROTO_TCP; 82779697Snon pmapparms.pm_port = 0; /* not needed */ 82879697Snon clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, 82979697Snon (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, 83079697Snon (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, 83179697Snon *tp); 83279697Snon if (clnt_st != RPC_SUCCESS) { 83379697Snon if ((clnt_st == RPC_PROGVERSMISMATCH) || 83479697Snon (clnt_st == RPC_PROGUNAVAIL)) 83579697Snon goto try_rpcbind; /* Try different versions */ 83679697Snon rpc_createerr.cf_stat = RPC_PMAPFAILURE; 83779697Snon clnt_geterr(client, &rpc_createerr.cf_error); 83879697Snon goto error; 83979697Snon } else if (port == 0) { 84079697Snon address = NULL; 84179697Snon rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 84279697Snon goto error; 84379697Snon } 84479697Snon port = htons(port); 84579697Snon CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); 84679697Snon if (((address = (struct netbuf *) 84779697Snon malloc(sizeof (struct netbuf))) == NULL) || 84879697Snon ((address->buf = (char *) 84979697Snon malloc(remote.len)) == NULL)) { 85079697Snon rpc_createerr.cf_stat = RPC_SYSTEMERROR; 85179697Snon clnt_geterr(client, &rpc_createerr.cf_error); 85279697Snon if (address) { 85379697Snon free(address); 85479697Snon address = NULL; 85579697Snon } 85679697Snon goto error; 85779697Snon } 85879697Snon memcpy(address->buf, remote.buf, remote.len); 85979697Snon memcpy(&((char *)address->buf)[sizeof (short)], 86079697Snon (char *)(void *)&port, sizeof (short)); 86179697Snon address->len = address->maxlen = remote.len; 86279697Snon goto done; 86379697Snon } 86479697Snon#endif /* PORTMAP */ 86579697Snon 86679697Snontry_rpcbind: 86779697Snon /* 86879697Snon * Check if rpcbind is up. This prevents needless delays when 86979697Snon * accessing applications such as the keyserver while booting 87079697Snon * disklessly. 87179697Snon */ 87279697Snon if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 87379697Snon if (!__rpcbind_is_up()) { 87479697Snon rpc_createerr.cf_stat = RPC_PMAPFAILURE; 87579697Snon rpc_createerr.cf_error.re_errno = 0; 87679697Snon goto error; 87779697Snon } 87879697Snon check_rpcbind = FALSE; 87979697Snon } 88079697Snon 88179697Snon /* 88279697Snon * Now we try version 4 and then 3. 88379697Snon * We also send the remote system the address we used to 88479697Snon * contact it in case it can help to connect back with us 88579697Snon */ 88679697Snon parms.r_prog = program; 88779697Snon parms.r_vers = version; 88879697Snon /*LINTED const castaway*/ 88979697Snon parms.r_owner = (char *) &nullstring[0]; /* not needed; */ 89079697Snon /* just for xdring */ 89179697Snon parms.r_netid = nconf->nc_netid; /* not really needed */ 89279697Snon 89379697Snon /* 89479697Snon * If a COTS transport is being used, try getting address via CLTS 89579697Snon * transport. This works only with version 4. 89679697Snon */ 89779697Snon if (nconf->nc_semantics == NC_TPI_COTS_ORD || 89879697Snon nconf->nc_semantics == NC_TPI_COTS) { 89979697Snon 90079697Snon void *handle; 90179697Snon struct netconfig *nconf_clts; 90279697Snon rpcb_entry_list_ptr relp = NULL; 90379697Snon 90479697Snon if (client == NULL) { 90579697Snon /* This did not go through the above PORTMAP/TCP code */ 90679697Snon if ((handle = __rpc_setconf("datagram_v")) != NULL) { 90779697Snon while ((nconf_clts = __rpc_getconf(handle)) 90879697Snon != NULL) { 90979697Snon if (strcmp(nconf_clts->nc_protofmly, 91079697Snon nconf->nc_protofmly) != 0) { 91179697Snon continue; 91279697Snon } 91379697Snon client = getclnthandle(host, nconf_clts, 91479697Snon &parms.r_addr); 91579697Snon break; 91679697Snon } 91779697Snon __rpc_endconf(handle); 91879697Snon } 91979697Snon if (client == NULL) 92079697Snon goto regular_rpcbind; /* Go the regular way */ 92179697Snon } else { 92279697Snon /* This is a UDP PORTMAP handle. Change to version 4 */ 92379697Snon vers = RPCBVERS4; 92479697Snon CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 92579697Snon } 92679697Snon /* 92779697Snon * We also send the remote system the address we used to 92879697Snon * contact it in case it can help it connect back with us 92979697Snon */ 93079697Snon if (parms.r_addr == NULL) { 93179697Snon /*LINTED const castaway*/ 93279697Snon parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ 93379697Snon } 93479697Snon 93579697Snon CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); 93679697Snon 93779697Snon clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, 93879697Snon (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 93979697Snon (xdrproc_t) xdr_rpcb_entry_list_ptr, 94079697Snon (char *)(void *)&relp, *tp); 94179697Snon if (clnt_st == RPC_SUCCESS) { 94279697Snon if ((address = got_entry(relp, nconf)) != NULL) { 94379697Snon xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 94479697Snon (char *)(void *)&relp); 94579697Snon CLNT_CONTROL(client, CLGET_SVC_ADDR, 94679697Snon (char *)(void *)&servaddr); 94779697Snon __rpc_fixup_addr(address, &servaddr); 94879697Snon goto done; 94979697Snon } 95079697Snon /* Entry not found for this transport */ 95179697Snon xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 95279697Snon (char *)(void *)&relp); 95379697Snon /* 95479697Snon * XXX: should have perhaps returned with error but 95579697Snon * since the remote machine might not always be able 95679697Snon * to send the address on all transports, we try the 95779697Snon * regular way with regular_rpcbind 95879697Snon */ 95979697Snon goto regular_rpcbind; 96079697Snon } else if ((clnt_st == RPC_PROGVERSMISMATCH) || 96179697Snon (clnt_st == RPC_PROGUNAVAIL)) { 96279697Snon start_vers = RPCBVERS; /* Try version 3 now */ 96379697Snon goto regular_rpcbind; /* Try different versions */ 96479697Snon } else { 96579697Snon rpc_createerr.cf_stat = RPC_PMAPFAILURE; 96679697Snon clnt_geterr(client, &rpc_createerr.cf_error); 96779697Snon goto error; 96879697Snon } 96979697Snon } 97079697Snon 97179697Snonregular_rpcbind: 97279697Snon 97379697Snon /* Now the same transport is to be used to get the address */ 97479697Snon if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || 97579697Snon (nconf->nc_semantics == NC_TPI_COTS))) { 97679697Snon /* A CLTS type of client - destroy it */ 97779697Snon CLNT_DESTROY(client); 97879697Snon client = NULL; 97979697Snon } 98079697Snon 98179697Snon if (client == NULL) { 98279697Snon client = getclnthandle(host, nconf, &parms.r_addr); 98379697Snon if (client == NULL) { 98479697Snon goto error; 98579697Snon } 98679697Snon } 98779697Snon if (parms.r_addr == NULL) { 98879697Snon /*LINTED const castaway*/ 98979697Snon parms.r_addr = (char *) &nullstring[0]; 99079697Snon } 99179697Snon 99279697Snon /* First try from start_vers and then version 3 (RPCBVERS) */ 99379697Snon 99479697Snon CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); 99579697Snon for (vers = start_vers; vers >= RPCBVERS; vers--) { 99679697Snon /* Set the version */ 99779697Snon CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 99879697Snon clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, 99979697Snon (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 100079697Snon (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp); 100179697Snon if (clnt_st == RPC_SUCCESS) { 100279697Snon if ((ua == NULL) || (ua[0] == 0)) { 100379697Snon /* address unknown */ 100479697Snon rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 100579697Snon goto error; 100679697Snon } 100779697Snon address = uaddr2taddr(nconf, ua); 100879697Snon#ifdef ND_DEBUG 100979697Snon fprintf(stderr, "\tRemote address is [%s]\n", ua); 101079697Snon if (!address) 101179697Snon fprintf(stderr, 101279697Snon "\tCouldn't resolve remote address!\n"); 101379697Snon#endif 101479697Snon xdr_free((xdrproc_t)xdr_wrapstring, 101579697Snon (char *)(void *)&ua); 101679697Snon 101779697Snon if (! address) { 101879697Snon /* We don't know about your universal address */ 101979697Snon rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 102079697Snon goto error; 102179697Snon } 102279697Snon CLNT_CONTROL(client, CLGET_SVC_ADDR, 102379697Snon (char *)(void *)&servaddr); 102479697Snon __rpc_fixup_addr(address, &servaddr); 102579697Snon goto done; 102679697Snon } else if (clnt_st == RPC_PROGVERSMISMATCH) { 102779697Snon struct rpc_err rpcerr; 102879697Snon 102979697Snon clnt_geterr(client, &rpcerr); 103079697Snon if (rpcerr.re_vers.low > RPCBVERS4) 103179697Snon goto error; /* a new version, can't handle */ 103279697Snon } else if (clnt_st != RPC_PROGUNAVAIL) { 103379697Snon /* Cant handle this error */ 103479697Snon rpc_createerr.cf_stat = clnt_st; 103579697Snon clnt_geterr(client, &rpc_createerr.cf_error); 103679697Snon goto error; 103779697Snon } 103879697Snon } 103979697Snon 104079697Snonerror: 104179697Snon if (client) { 104279697Snon CLNT_DESTROY(client); 104379697Snon client = NULL; 104479697Snon } 104579697Snondone: 104679697Snon if (nconf->nc_semantics != NC_TPI_CLTS) { 104779697Snon /* This client is the connectionless one */ 104879697Snon if (client) { 104979697Snon CLNT_DESTROY(client); 105079697Snon client = NULL; 105179697Snon } 105279697Snon } 105379697Snon if (clpp) { 105479697Snon *clpp = client; 105579697Snon } else if (client) { 105679697Snon CLNT_DESTROY(client); 105779697Snon } 105879697Snon if (parms.r_addr != NULL && parms.r_addr != nullstring) 105979697Snon free(parms.r_addr); 106079697Snon return (address); 106179697Snon} 106279697Snon 106379697Snon 106479697Snon/* 106579697Snon * Find the mapped address for program, version. 106679697Snon * Calls the rpcbind service remotely to do the lookup. 106779697Snon * Uses the transport specified in nconf. 106879697Snon * Returns FALSE (0) if no map exists, else returns 1. 106979697Snon * 107079697Snon * Assuming that the address is all properly allocated 107179697Snon */ 107279697Snonint 107379697Snonrpcb_getaddr(program, version, nconf, address, host) 107479697Snon rpcprog_t program; 107579697Snon rpcvers_t version; 107679697Snon const struct netconfig *nconf; 107779697Snon struct netbuf *address; 107879697Snon const char *host; 107979697Snon{ 108079697Snon struct netbuf *na; 108179697Snon 108279697Snon if ((na = __rpcb_findaddr_timed(program, version, 108379697Snon (struct netconfig *) nconf, (char *) host, 108479697Snon (CLIENT **) NULL, (struct timeval *) NULL)) == NULL) 108579697Snon return (FALSE); 108679697Snon 108779697Snon if (na->len > address->maxlen) { 108879697Snon /* Too long address */ 108979697Snon free(na->buf); 109079697Snon free(na); 109179697Snon rpc_createerr.cf_stat = RPC_FAILED; 109279697Snon return (FALSE); 109379697Snon } 109479697Snon memcpy(address->buf, na->buf, (size_t)na->len); 109579697Snon address->len = na->len; 109679697Snon free(na->buf); 109779697Snon free(na); 109879697Snon return (TRUE); 109979697Snon} 110079697Snon 110179697Snon/* 110279697Snon * Get a copy of the current maps. 110379697Snon * Calls the rpcbind service remotely to get the maps. 110479697Snon * 110579697Snon * It returns only a list of the services 110679697Snon * It returns NULL on failure. 110779697Snon */ 110879697Snonrpcblist * 110979697Snonrpcb_getmaps(nconf, host) 111079697Snon const struct netconfig *nconf; 111179697Snon const char *host; 111279697Snon{ 111379697Snon rpcblist_ptr head = NULL; 111479697Snon CLIENT *client; 111579697Snon enum clnt_stat clnt_st; 111679697Snon rpcvers_t vers = 0; 111779697Snon 111879697Snon client = getclnthandle(host, nconf, NULL); 111979697Snon if (client == NULL) { 112079697Snon return (head); 112179697Snon } 112279697Snon clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 112379697Snon (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 112479697Snon (char *)(void *)&head, tottimeout); 112579697Snon if (clnt_st == RPC_SUCCESS) 112679697Snon goto done; 112779697Snon 112879697Snon if ((clnt_st != RPC_PROGVERSMISMATCH) && 112979697Snon (clnt_st != RPC_PROGUNAVAIL)) { 113079697Snon rpc_createerr.cf_stat = RPC_RPCBFAILURE; 113179697Snon clnt_geterr(client, &rpc_createerr.cf_error); 113279697Snon goto done; 113379697Snon } 113479697Snon 113579697Snon /* fall back to earlier version */ 113679697Snon CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 113779697Snon if (vers == RPCBVERS4) { 113879697Snon vers = RPCBVERS; 113979697Snon CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 114079697Snon if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 114179697Snon (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 114279697Snon (char *)(void *)&head, tottimeout) == RPC_SUCCESS) 114379697Snon goto done; 114479697Snon } 114579697Snon rpc_createerr.cf_stat = RPC_RPCBFAILURE; 114679697Snon clnt_geterr(client, &rpc_createerr.cf_error); 114779697Snon 114879697Snondone: 114979697Snon CLNT_DESTROY(client); 115079697Snon return (head); 115179697Snon} 115279697Snon 115379697Snon/* 115479697Snon * rpcbinder remote-call-service interface. 115579697Snon * This routine is used to call the rpcbind remote call service 115679697Snon * which will look up a service program in the address maps, and then 115779697Snon * remotely call that routine with the given parameters. This allows 115879697Snon * programs to do a lookup and call in one step. 115979697Snon*/ 116079697Snonenum clnt_stat 116179697Snonrpcb_rmtcall(nconf, host, prog, vers, proc, xdrargs, argsp, 116279697Snon xdrres, resp, tout, addr_ptr) 116379697Snon const struct netconfig *nconf; /* Netconfig structure */ 116479697Snon const char *host; /* Remote host name */ 116579697Snon rpcprog_t prog; 116679697Snon rpcvers_t vers; 116779697Snon rpcproc_t proc; /* Remote proc identifiers */ 116879697Snon xdrproc_t xdrargs, xdrres; /* XDR routines */ 116979697Snon caddr_t argsp, resp; /* Argument and Result */ 117079697Snon struct timeval tout; /* Timeout value for this call */ 117179697Snon const struct netbuf *addr_ptr; /* Preallocated netbuf address */ 117279697Snon{ 117379697Snon CLIENT *client; 117479697Snon enum clnt_stat stat; 117579697Snon struct r_rpcb_rmtcallargs a; 117679697Snon struct r_rpcb_rmtcallres r; 117779697Snon rpcvers_t rpcb_vers; 117879697Snon 117979697Snon stat = 0; 118079697Snon client = getclnthandle(host, nconf, NULL); 118179697Snon if (client == NULL) { 118279697Snon return (RPC_FAILED); 118379697Snon } 118479697Snon /*LINTED const castaway*/ 118579697Snon CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout); 118679697Snon a.prog = prog; 118779697Snon a.vers = vers; 118879697Snon a.proc = proc; 118979697Snon a.args.args_val = argsp; 119079697Snon a.xdr_args = xdrargs; 119179697Snon r.addr = NULL; 119279697Snon r.results.results_val = resp; 119379697Snon r.xdr_res = xdrres; 119479697Snon 119579697Snon for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { 119679697Snon CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers); 119779697Snon stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT, 119879697Snon (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a, 119979697Snon (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout); 120079697Snon if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { 120179697Snon struct netbuf *na; 120279697Snon /*LINTED const castaway*/ 120379697Snon na = uaddr2taddr((struct netconfig *) nconf, r.addr); 120479697Snon if (!na) { 120579697Snon stat = RPC_N2AXLATEFAILURE; 120679697Snon /*LINTED const castaway*/ 120779697Snon ((struct netbuf *) addr_ptr)->len = 0; 120879697Snon goto error; 120979697Snon } 121079697Snon if (na->len > addr_ptr->maxlen) { 121179697Snon /* Too long address */ 121279697Snon stat = RPC_FAILED; /* XXX A better error no */ 121379697Snon free(na->buf); 121479697Snon free(na); 121579697Snon /*LINTED const castaway*/ 121679697Snon ((struct netbuf *) addr_ptr)->len = 0; 121779697Snon goto error; 121879697Snon } 121979697Snon memcpy(addr_ptr->buf, na->buf, (size_t)na->len); 122079697Snon /*LINTED const castaway*/ 122179697Snon ((struct netbuf *)addr_ptr)->len = na->len; 122279697Snon free(na->buf); 122379697Snon free(na); 122479697Snon break; 122579697Snon } else if ((stat != RPC_PROGVERSMISMATCH) && 122679697Snon (stat != RPC_PROGUNAVAIL)) { 122779697Snon goto error; 122879697Snon } 122979697Snon } 123079697Snonerror: 123179697Snon CLNT_DESTROY(client); 123279697Snon if (r.addr) 123379697Snon xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr); 123479697Snon return (stat); 123579697Snon} 123679697Snon 123779697Snon/* 123879697Snon * Gets the time on the remote host. 123979697Snon * Returns 1 if succeeds else 0. 124079697Snon */ 124179697Snonbool_t 124279697Snonrpcb_gettime(host, timep) 124379697Snon const char *host; 124479697Snon time_t *timep; 124579697Snon{ 124679697Snon CLIENT *client = NULL; 124779697Snon void *handle; 124879697Snon struct netconfig *nconf; 124979697Snon rpcvers_t vers; 125079697Snon enum clnt_stat st; 125179697Snon 125279697Snon 125379697Snon if ((host == NULL) || (host[0] == 0)) { 125479697Snon time(timep); 125579697Snon return (TRUE); 125679697Snon } 125779697Snon 125879697Snon if ((handle = __rpc_setconf("netpath")) == NULL) { 125979697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 126079697Snon return (FALSE); 126179697Snon } 126279697Snon rpc_createerr.cf_stat = RPC_SUCCESS; 126379697Snon while (client == NULL) { 126479697Snon if ((nconf = __rpc_getconf(handle)) == NULL) { 126579697Snon if (rpc_createerr.cf_stat == RPC_SUCCESS) 126679697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 126779697Snon break; 126879697Snon } 126979697Snon client = getclnthandle(host, nconf, NULL); 127079697Snon if (client) 127179697Snon break; 127279697Snon } 127379697Snon __rpc_endconf(handle); 127479697Snon if (client == (CLIENT *) NULL) { 127579697Snon return (FALSE); 127679697Snon } 127779697Snon 127879697Snon st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 127979697Snon (xdrproc_t) xdr_void, NULL, 128079697Snon (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); 128179697Snon 128279697Snon if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { 128379697Snon CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 128479697Snon if (vers == RPCBVERS4) { 128579697Snon /* fall back to earlier version */ 128679697Snon vers = RPCBVERS; 128779697Snon CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 128879697Snon st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 128979697Snon (xdrproc_t) xdr_void, NULL, 129079697Snon (xdrproc_t) xdr_int, (char *)(void *)timep, 129179697Snon tottimeout); 129279697Snon } 129379697Snon } 129479697Snon CLNT_DESTROY(client); 129579697Snon return (st == RPC_SUCCESS? TRUE: FALSE); 129679697Snon} 129779697Snon 129879697Snonstatic bool_t 129979697Snonxdr_netbuf(XDR *xdrs, struct netbuf *objp) 130079697Snon{ 130179697Snon bool_t dummy; 130279697Snon void **pp; 130379697Snon 130479697Snon if (!xdr_uint32_t(xdrs, (uint32_t *) &objp->maxlen)) { 130579697Snon return (FALSE); 130679697Snon } 130779697Snon pp = &objp->buf; 130879697Snon dummy = xdr_bytes(xdrs, (char **) pp, 130979697Snon (u_int *)&(objp->len), objp->maxlen); 131079697Snon return (dummy); 131179697Snon} 131279697Snon 131379697Snon/* 131479697Snon * Converts taddr to universal address. This routine should never 131579697Snon * really be called because local n2a libraries are always provided. 131679697Snon */ 131779697Snonchar * 131879697Snonrpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr) 131979697Snon{ 132079697Snon CLIENT *client; 132179697Snon char *uaddr = NULL; 132279697Snon 132379697Snon 132479697Snon /* parameter checking */ 132579697Snon if (nconf == NULL) { 132679697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 132779697Snon return (NULL); 132879697Snon } 132979697Snon if (taddr == NULL) { 133079697Snon rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 133179697Snon return (NULL); 133279697Snon } 133379697Snon client = local_rpcb(); 133479697Snon if (! client) { 133579697Snon return (NULL); 133679697Snon } 133779697Snon 133879697Snon CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR, 133979697Snon (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 134079697Snon (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout); 134179697Snon CLNT_DESTROY(client); 134279697Snon return (uaddr); 134379697Snon} 134479697Snon 134579697Snon/* 134679697Snon * Converts universal address to netbuf. This routine should never 134779697Snon * really be called because local n2a libraries are always provided. 134879697Snon */ 134979697Snonstruct netbuf * 135079697Snonrpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr) 135179697Snon{ 135279697Snon CLIENT *client; 135379697Snon struct netbuf *taddr; 135479697Snon 135579697Snon 135679697Snon /* parameter checking */ 135779697Snon if (nconf == NULL) { 135879697Snon rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 135979697Snon return (NULL); 136079697Snon } 136179697Snon if (uaddr == NULL) { 136279697Snon rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 136379697Snon return (NULL); 136479697Snon } 136579697Snon client = local_rpcb(); 136679697Snon if (! client) { 136779697Snon return (NULL); 136879697Snon } 136979697Snon 137079697Snon taddr = (struct netbuf *)malloc(sizeof (struct netbuf), M_RPC, M_WAITOK|M_ZERO); 137179697Snon if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR, 137279697Snon (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, 137379697Snon (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 137479697Snon tottimeout) != RPC_SUCCESS) { 137579697Snon free(taddr); 137679697Snon taddr = NULL; 137779697Snon } 137879697Snon CLNT_DESTROY(client); 137979697Snon return (taddr); 138079697Snon} 138179697Snon 138279697Snon#endif 138379697Snon