1177633Sdfr/* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */ 2177633Sdfr 3261057Smav/*- 4261057Smav * Copyright (c) 2010, Oracle America, Inc. 5261057Smav * All rights reserved. 6177633Sdfr * 7261057Smav * Redistribution and use in source and binary forms, with or without 8261057Smav * modification, are permitted provided that the following conditions are met: 9261057Smav * - Redistributions of source code must retain the above copyright notice, 10261057Smav * this list of conditions and the following disclaimer. 11261057Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261057Smav * this list of conditions and the following disclaimer in the documentation 13261057Smav * and/or other materials provided with the distribution. 14261057Smav * - Neither the name of the "Oracle America, Inc." nor the names of its 15261057Smav * contributors may be used to endorse or promote products derived 16261057Smav * from this software without specific prior written permission. 17177633Sdfr * 18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261057Smav * POSSIBILITY OF SUCH DAMAGE. 29177633Sdfr */ 30177633Sdfr/* 31177633Sdfr * Copyright (c) 1986-1991 by Sun Microsystems Inc. 32177633Sdfr */ 33177633Sdfr 34177633Sdfr/* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */ 35177633Sdfr 36177633Sdfr 37177633Sdfr#if defined(LIBC_SCCS) && !defined(lint) 38177633Sdfrstatic char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro"; 39177633Sdfr#endif 40177633Sdfr#include <sys/cdefs.h> 41177633Sdfr__FBSDID("$FreeBSD$"); 42177633Sdfr 43177633Sdfr/* 44177633Sdfr * rpcb_clnt.c 45177633Sdfr * interface to rpcbind rpc service. 46177633Sdfr * 47177633Sdfr * Copyright (C) 1988, Sun Microsystems, Inc. 48177633Sdfr */ 49177633Sdfr 50177633Sdfr#include "opt_inet6.h" 51177633Sdfr 52177633Sdfr#include <sys/param.h> 53177633Sdfr#include <sys/systm.h> 54177633Sdfr#include <sys/kernel.h> 55177633Sdfr#include <sys/malloc.h> 56177633Sdfr#include <sys/proc.h> 57177633Sdfr#include <sys/socket.h> 58177633Sdfr#include <sys/socketvar.h> 59177633Sdfr 60177633Sdfr#include <rpc/rpc.h> 61177633Sdfr#include <rpc/rpcb_clnt.h> 62177633Sdfr#include <rpc/rpcb_prot.h> 63177633Sdfr 64177685Sdfr#include <rpc/rpc_com.h> 65177633Sdfr 66177633Sdfrstatic struct timeval tottimeout = { 60, 0 }; 67177633Sdfrstatic const char nullstring[] = "\000"; 68177633Sdfr 69177633Sdfrstatic CLIENT *local_rpcb(void); 70177633Sdfr 71177633Sdfr#if 0 72177633Sdfr 73259984Sdimstatic const struct timeval rmttimeout = { 3, 0 }; 74177633Sdfrstatic struct timeval rpcbrmttime = { 15, 0 }; 75177633Sdfr 76177633Sdfr#define CACHESIZE 6 77177633Sdfr 78177633Sdfrstruct address_cache { 79177633Sdfr char *ac_host; 80177633Sdfr char *ac_netid; 81177633Sdfr char *ac_uaddr; 82177633Sdfr struct netbuf *ac_taddr; 83177633Sdfr struct address_cache *ac_next; 84177633Sdfr}; 85177633Sdfr 86177633Sdfrstatic struct address_cache *front; 87177633Sdfrstatic int cachesize; 88177633Sdfr 89177633Sdfr#define CLCR_GET_RPCB_TIMEOUT 1 90177633Sdfr#define CLCR_SET_RPCB_TIMEOUT 2 91177633Sdfr 92177633Sdfr 93177633Sdfrextern int __rpc_lowvers; 94177633Sdfr 95177633Sdfrstatic struct address_cache *check_cache(const char *, const char *); 96177633Sdfrstatic void delete_cache(struct netbuf *); 97177633Sdfrstatic void add_cache(const char *, const char *, struct netbuf *, char *); 98177633Sdfrstatic CLIENT *getclnthandle(const char *, const struct netconfig *, char **); 99177633Sdfrstatic CLIENT *local_rpcb(void); 100177633Sdfrstatic struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *); 101177633Sdfr 102177633Sdfr/* 103177633Sdfr * This routine adjusts the timeout used for calls to the remote rpcbind. 104177633Sdfr * Also, this routine can be used to set the use of portmapper version 2 105177633Sdfr * only when doing rpc_broadcasts 106177633Sdfr * These are private routines that may not be provided in future releases. 107177633Sdfr */ 108177633Sdfrbool_t 109177633Sdfr__rpc_control(request, info) 110177633Sdfr int request; 111177633Sdfr void *info; 112177633Sdfr{ 113177633Sdfr switch (request) { 114177633Sdfr case CLCR_GET_RPCB_TIMEOUT: 115177633Sdfr *(struct timeval *)info = tottimeout; 116177633Sdfr break; 117177633Sdfr case CLCR_SET_RPCB_TIMEOUT: 118177633Sdfr tottimeout = *(struct timeval *)info; 119177633Sdfr break; 120177633Sdfr case CLCR_SET_LOWVERS: 121177633Sdfr __rpc_lowvers = *(int *)info; 122177633Sdfr break; 123177633Sdfr case CLCR_GET_LOWVERS: 124177633Sdfr *(int *)info = __rpc_lowvers; 125177633Sdfr break; 126177633Sdfr default: 127177633Sdfr return (FALSE); 128177633Sdfr } 129177633Sdfr return (TRUE); 130177633Sdfr} 131177633Sdfr 132177633Sdfr/* 133177633Sdfr * It might seem that a reader/writer lock would be more reasonable here. 134177633Sdfr * However because getclnthandle(), the only user of the cache functions, 135177633Sdfr * may do a delete_cache() operation if a check_cache() fails to return an 136177633Sdfr * address useful to clnt_tli_create(), we may as well use a mutex. 137177633Sdfr */ 138177633Sdfr/* 139177633Sdfr * As it turns out, if the cache lock is *not* a reader/writer lock, we will 140177633Sdfr * block all clnt_create's if we are trying to connect to a host that's down, 141177633Sdfr * since the lock will be held all during that time. 142177633Sdfr */ 143177633Sdfr 144177633Sdfr/* 145177633Sdfr * The routines check_cache(), add_cache(), delete_cache() manage the 146177633Sdfr * cache of rpcbind addresses for (host, netid). 147177633Sdfr */ 148177633Sdfr 149177633Sdfrstatic struct address_cache * 150177633Sdfrcheck_cache(host, netid) 151177633Sdfr const char *host, *netid; 152177633Sdfr{ 153177633Sdfr struct address_cache *cptr; 154177633Sdfr 155177633Sdfr /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ 156177633Sdfr 157177633Sdfr for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { 158177633Sdfr if (!strcmp(cptr->ac_host, host) && 159177633Sdfr !strcmp(cptr->ac_netid, netid)) { 160177633Sdfr#ifdef ND_DEBUG 161177633Sdfr fprintf(stderr, "Found cache entry for %s: %s\n", 162177633Sdfr host, netid); 163177633Sdfr#endif 164177633Sdfr return (cptr); 165177633Sdfr } 166177633Sdfr } 167177633Sdfr return ((struct address_cache *) NULL); 168177633Sdfr} 169177633Sdfr 170177633Sdfrstatic void 171177633Sdfrdelete_cache(addr) 172177633Sdfr struct netbuf *addr; 173177633Sdfr{ 174177633Sdfr struct address_cache *cptr, *prevptr = NULL; 175177633Sdfr 176177633Sdfr /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ 177177633Sdfr for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { 178177633Sdfr if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { 179177633Sdfr free(cptr->ac_host); 180177633Sdfr free(cptr->ac_netid); 181177633Sdfr free(cptr->ac_taddr->buf); 182177633Sdfr free(cptr->ac_taddr); 183177633Sdfr if (cptr->ac_uaddr) 184177633Sdfr free(cptr->ac_uaddr); 185177633Sdfr if (prevptr) 186177633Sdfr prevptr->ac_next = cptr->ac_next; 187177633Sdfr else 188177633Sdfr front = cptr->ac_next; 189177633Sdfr free(cptr); 190177633Sdfr cachesize--; 191177633Sdfr break; 192177633Sdfr } 193177633Sdfr prevptr = cptr; 194177633Sdfr } 195177633Sdfr} 196177633Sdfr 197177633Sdfrstatic void 198177633Sdfradd_cache(host, netid, taddr, uaddr) 199177633Sdfr const char *host, *netid; 200177633Sdfr char *uaddr; 201177633Sdfr struct netbuf *taddr; 202177633Sdfr{ 203177633Sdfr struct address_cache *ad_cache, *cptr, *prevptr; 204177633Sdfr 205177633Sdfr ad_cache = (struct address_cache *) 206177633Sdfr malloc(sizeof (struct address_cache)); 207177633Sdfr if (!ad_cache) { 208177633Sdfr return; 209177633Sdfr } 210177633Sdfr ad_cache->ac_host = strdup(host); 211177633Sdfr ad_cache->ac_netid = strdup(netid); 212177633Sdfr ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL; 213177633Sdfr ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf)); 214177633Sdfr if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr || 215177633Sdfr (uaddr && !ad_cache->ac_uaddr)) { 216177633Sdfr goto out; 217177633Sdfr } 218177633Sdfr ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len; 219177633Sdfr ad_cache->ac_taddr->buf = (char *) malloc(taddr->len); 220177633Sdfr if (ad_cache->ac_taddr->buf == NULL) { 221177633Sdfrout: 222177633Sdfr if (ad_cache->ac_host) 223177633Sdfr free(ad_cache->ac_host); 224177633Sdfr if (ad_cache->ac_netid) 225177633Sdfr free(ad_cache->ac_netid); 226177633Sdfr if (ad_cache->ac_uaddr) 227177633Sdfr free(ad_cache->ac_uaddr); 228177633Sdfr if (ad_cache->ac_taddr) 229177633Sdfr free(ad_cache->ac_taddr); 230177633Sdfr free(ad_cache); 231177633Sdfr return; 232177633Sdfr } 233177633Sdfr memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len); 234177633Sdfr#ifdef ND_DEBUG 235177633Sdfr fprintf(stderr, "Added to cache: %s : %s\n", host, netid); 236177633Sdfr#endif 237177633Sdfr 238177633Sdfr/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ 239177633Sdfr 240177633Sdfr rwlock_wrlock(&rpcbaddr_cache_lock); 241177633Sdfr if (cachesize < CACHESIZE) { 242177633Sdfr ad_cache->ac_next = front; 243177633Sdfr front = ad_cache; 244177633Sdfr cachesize++; 245177633Sdfr } else { 246177633Sdfr /* Free the last entry */ 247177633Sdfr cptr = front; 248177633Sdfr prevptr = NULL; 249177633Sdfr while (cptr->ac_next) { 250177633Sdfr prevptr = cptr; 251177633Sdfr cptr = cptr->ac_next; 252177633Sdfr } 253177633Sdfr 254177633Sdfr#ifdef ND_DEBUG 255177633Sdfr fprintf(stderr, "Deleted from cache: %s : %s\n", 256177633Sdfr cptr->ac_host, cptr->ac_netid); 257177633Sdfr#endif 258177633Sdfr free(cptr->ac_host); 259177633Sdfr free(cptr->ac_netid); 260177633Sdfr free(cptr->ac_taddr->buf); 261177633Sdfr free(cptr->ac_taddr); 262177633Sdfr if (cptr->ac_uaddr) 263177633Sdfr free(cptr->ac_uaddr); 264177633Sdfr 265177633Sdfr if (prevptr) { 266177633Sdfr prevptr->ac_next = NULL; 267177633Sdfr ad_cache->ac_next = front; 268177633Sdfr front = ad_cache; 269177633Sdfr } else { 270177633Sdfr front = ad_cache; 271177633Sdfr ad_cache->ac_next = NULL; 272177633Sdfr } 273177633Sdfr free(cptr); 274177633Sdfr } 275177633Sdfr rwlock_unlock(&rpcbaddr_cache_lock); 276177633Sdfr} 277177633Sdfr 278177633Sdfr/* 279177633Sdfr * This routine will return a client handle that is connected to the 280177633Sdfr * rpcbind. If targaddr is non-NULL, the "universal address" of the 281177633Sdfr * host will be stored in *targaddr; the caller is responsible for 282177633Sdfr * freeing this string. 283177633Sdfr * On error, returns NULL and free's everything. 284177633Sdfr */ 285177633Sdfrstatic CLIENT * 286177633Sdfrgetclnthandle(host, nconf, targaddr) 287177633Sdfr const char *host; 288177633Sdfr const struct netconfig *nconf; 289177633Sdfr char **targaddr; 290177633Sdfr{ 291177633Sdfr CLIENT *client; 292177633Sdfr struct netbuf *addr, taddr; 293177633Sdfr struct netbuf addr_to_delete; 294177633Sdfr struct __rpc_sockinfo si; 295177633Sdfr struct addrinfo hints, *res, *tres; 296177633Sdfr struct address_cache *ad_cache; 297177633Sdfr char *tmpaddr; 298177633Sdfr 299177633Sdfr/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ 300177633Sdfr 301177633Sdfr /* Get the address of the rpcbind. Check cache first */ 302177633Sdfr client = NULL; 303177633Sdfr addr_to_delete.len = 0; 304177633Sdfr rwlock_rdlock(&rpcbaddr_cache_lock); 305177633Sdfr ad_cache = NULL; 306177633Sdfr if (host != NULL) 307177633Sdfr ad_cache = check_cache(host, nconf->nc_netid); 308177633Sdfr if (ad_cache != NULL) { 309177633Sdfr addr = ad_cache->ac_taddr; 310177633Sdfr client = clnt_tli_create(RPC_ANYFD, nconf, addr, 311177633Sdfr (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); 312177633Sdfr if (client != NULL) { 313177633Sdfr if (targaddr) 314177633Sdfr *targaddr = strdup(ad_cache->ac_uaddr); 315177633Sdfr rwlock_unlock(&rpcbaddr_cache_lock); 316177633Sdfr return (client); 317177633Sdfr } 318177633Sdfr addr_to_delete.len = addr->len; 319177633Sdfr addr_to_delete.buf = (char *)malloc(addr->len); 320177633Sdfr if (addr_to_delete.buf == NULL) { 321177633Sdfr addr_to_delete.len = 0; 322177633Sdfr } else { 323177633Sdfr memcpy(addr_to_delete.buf, addr->buf, addr->len); 324177633Sdfr } 325177633Sdfr } 326177633Sdfr rwlock_unlock(&rpcbaddr_cache_lock); 327177633Sdfr if (addr_to_delete.len != 0) { 328177633Sdfr /* 329177633Sdfr * Assume this may be due to cache data being 330177633Sdfr * outdated 331177633Sdfr */ 332177633Sdfr rwlock_wrlock(&rpcbaddr_cache_lock); 333177633Sdfr delete_cache(&addr_to_delete); 334177633Sdfr rwlock_unlock(&rpcbaddr_cache_lock); 335177633Sdfr free(addr_to_delete.buf); 336177633Sdfr } 337177633Sdfr if (!__rpc_nconf2sockinfo(nconf, &si)) { 338177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 339177633Sdfr return NULL; 340177633Sdfr } 341177633Sdfr 342177633Sdfr memset(&hints, 0, sizeof hints); 343177633Sdfr hints.ai_family = si.si_af; 344177633Sdfr hints.ai_socktype = si.si_socktype; 345177633Sdfr hints.ai_protocol = si.si_proto; 346177633Sdfr 347177633Sdfr#ifdef CLNT_DEBUG 348177633Sdfr printf("trying netid %s family %d proto %d socktype %d\n", 349177633Sdfr nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype); 350177633Sdfr#endif 351177633Sdfr 352177633Sdfr if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 353177633Sdfr client = local_rpcb(); 354177633Sdfr if (! client) { 355177633Sdfr#ifdef ND_DEBUG 356177633Sdfr clnt_pcreateerror("rpcbind clnt interface"); 357177633Sdfr#endif 358177633Sdfr return (NULL); 359177633Sdfr } else { 360177633Sdfr struct sockaddr_un sun; 361177633Sdfr if (targaddr) { 362177633Sdfr *targaddr = malloc(sizeof(sun.sun_path)); 363177633Sdfr if (*targaddr == NULL) { 364177633Sdfr CLNT_DESTROY(client); 365177633Sdfr return (NULL); 366177633Sdfr } 367177633Sdfr strncpy(*targaddr, _PATH_RPCBINDSOCK, 368177633Sdfr sizeof(sun.sun_path)); 369177633Sdfr } 370177633Sdfr return (client); 371177633Sdfr } 372177633Sdfr } else { 373177633Sdfr if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) { 374177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNHOST; 375177633Sdfr return NULL; 376177633Sdfr } 377177633Sdfr } 378177633Sdfr 379177633Sdfr for (tres = res; tres != NULL; tres = tres->ai_next) { 380177633Sdfr taddr.buf = tres->ai_addr; 381177633Sdfr taddr.len = taddr.maxlen = tres->ai_addrlen; 382177633Sdfr 383177633Sdfr#ifdef ND_DEBUG 384177633Sdfr { 385177633Sdfr char *ua; 386177633Sdfr 387177633Sdfr ua = taddr2uaddr(nconf, &taddr); 388177633Sdfr fprintf(stderr, "Got it [%s]\n", ua); 389177633Sdfr free(ua); 390177633Sdfr } 391177633Sdfr#endif 392177633Sdfr 393177633Sdfr#ifdef ND_DEBUG 394177633Sdfr { 395177633Sdfr int i; 396177633Sdfr 397177633Sdfr fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n", 398177633Sdfr taddr.len, taddr.maxlen); 399177633Sdfr fprintf(stderr, "\tAddress is "); 400177633Sdfr for (i = 0; i < taddr.len; i++) 401177633Sdfr fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]); 402177633Sdfr fprintf(stderr, "\n"); 403177633Sdfr } 404177633Sdfr#endif 405177633Sdfr client = clnt_tli_create(RPC_ANYFD, nconf, &taddr, 406177633Sdfr (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); 407177633Sdfr#ifdef ND_DEBUG 408177633Sdfr if (! client) { 409177633Sdfr clnt_pcreateerror("rpcbind clnt interface"); 410177633Sdfr } 411177633Sdfr#endif 412177633Sdfr 413177633Sdfr if (client) { 414177633Sdfr tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL; 415177633Sdfr add_cache(host, nconf->nc_netid, &taddr, tmpaddr); 416177633Sdfr if (targaddr) 417177633Sdfr *targaddr = tmpaddr; 418177633Sdfr break; 419177633Sdfr } 420177633Sdfr } 421177633Sdfr if (res) 422177633Sdfr freeaddrinfo(res); 423177633Sdfr return (client); 424177633Sdfr} 425177633Sdfr 426177633Sdfr#endif 427177633Sdfr 428177633Sdfr/* XXX */ 429177633Sdfr#define IN4_LOCALHOST_STRING "127.0.0.1" 430177633Sdfr#define IN6_LOCALHOST_STRING "::1" 431177633Sdfr 432177633Sdfr/* 433177633Sdfr * This routine will return a client handle that is connected to the local 434177633Sdfr * rpcbind. Returns NULL on error and free's everything. 435177633Sdfr */ 436177633Sdfrstatic CLIENT * 437177633Sdfrlocal_rpcb() 438177633Sdfr{ 439177633Sdfr CLIENT *client; 440177633Sdfr struct socket *so; 441177633Sdfr size_t tsize; 442177633Sdfr struct sockaddr_un sun; 443177633Sdfr int error; 444177633Sdfr 445177633Sdfr /* 446177633Sdfr * Try connecting to the local rpcbind through a local socket 447177633Sdfr * first. If this doesn't work, try all transports defined in 448177633Sdfr * the netconfig file. 449177633Sdfr */ 450177633Sdfr memset(&sun, 0, sizeof sun); 451177633Sdfr so = NULL; 452177633Sdfr error = socreate(AF_LOCAL, &so, SOCK_STREAM, 0, curthread->td_ucred, 453177633Sdfr curthread); 454177633Sdfr if (error) 455177633Sdfr goto try_nconf; 456177633Sdfr sun.sun_family = AF_LOCAL; 457177633Sdfr strcpy(sun.sun_path, _PATH_RPCBINDSOCK); 458177633Sdfr sun.sun_len = SUN_LEN(&sun); 459177633Sdfr 460177633Sdfr tsize = __rpc_get_t_size(AF_LOCAL, 0, 0); 461177633Sdfr client = clnt_vc_create(so, (struct sockaddr *)&sun, (rpcprog_t)RPCBPROG, 462221127Srmacklem (rpcvers_t)RPCBVERS, tsize, tsize, 1); 463177633Sdfr 464177633Sdfr if (client != NULL) { 465177633Sdfr /* Mark the socket to be closed in destructor */ 466177633Sdfr (void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); 467177633Sdfr return client; 468177633Sdfr } 469177633Sdfr 470177633Sdfr /* Nobody needs this socket anymore; free the descriptor. */ 471177633Sdfr soclose(so); 472177633Sdfr 473177633Sdfrtry_nconf: 474177633Sdfr 475177633Sdfr#if 0 476177633Sdfr static struct netconfig *loopnconf; 477180087Sjulian static char *localhostname; 478177633Sdfr 479177633Sdfr/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */ 480177633Sdfr mutex_lock(&loopnconf_lock); 481177633Sdfr if (loopnconf == NULL) { 482177633Sdfr struct netconfig *nconf, *tmpnconf = NULL; 483177633Sdfr void *nc_handle; 484177633Sdfr int fd; 485177633Sdfr 486177633Sdfr nc_handle = setnetconfig(); 487177633Sdfr if (nc_handle == NULL) { 488177633Sdfr /* fails to open netconfig file */ 489177633Sdfr syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 490177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 491177633Sdfr mutex_unlock(&loopnconf_lock); 492177633Sdfr return (NULL); 493177633Sdfr } 494177633Sdfr while ((nconf = getnetconfig(nc_handle)) != NULL) { 495177633Sdfr if (( 496177633Sdfr#ifdef INET6 497177633Sdfr strcmp(nconf->nc_protofmly, NC_INET6) == 0 || 498177633Sdfr#endif 499177633Sdfr strcmp(nconf->nc_protofmly, NC_INET) == 0) && 500177633Sdfr (nconf->nc_semantics == NC_TPI_COTS || 501177633Sdfr nconf->nc_semantics == NC_TPI_COTS_ORD)) { 502177633Sdfr fd = __rpc_nconf2fd(nconf); 503177633Sdfr /* 504177633Sdfr * Can't create a socket, assume that 505177633Sdfr * this family isn't configured in the kernel. 506177633Sdfr */ 507177633Sdfr if (fd < 0) 508177633Sdfr continue; 509177633Sdfr _close(fd); 510177633Sdfr tmpnconf = nconf; 511177633Sdfr if (!strcmp(nconf->nc_protofmly, NC_INET)) 512180087Sjulian localhostname = IN4_LOCALHOST_STRING; 513177633Sdfr else 514180087Sjulian localhostname = IN6_LOCALHOST_STRING; 515177633Sdfr } 516177633Sdfr } 517177633Sdfr if (tmpnconf == NULL) { 518177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 519177633Sdfr mutex_unlock(&loopnconf_lock); 520177633Sdfr return (NULL); 521177633Sdfr } 522177633Sdfr loopnconf = getnetconfigent(tmpnconf->nc_netid); 523177633Sdfr /* loopnconf is never freed */ 524177633Sdfr endnetconfig(nc_handle); 525177633Sdfr } 526177633Sdfr mutex_unlock(&loopnconf_lock); 527180087Sjulian client = getclnthandle(localhostname, loopnconf, NULL); 528177633Sdfr return (client); 529177633Sdfr#else 530177633Sdfr return (NULL); 531177633Sdfr#endif 532177633Sdfr} 533177633Sdfr 534177633Sdfr/* 535177633Sdfr * Set a mapping between program, version and address. 536177633Sdfr * Calls the rpcbind service to do the mapping. 537177633Sdfr */ 538177633Sdfrbool_t 539177633Sdfrrpcb_set(rpcprog_t program, rpcvers_t version, 540177633Sdfr const struct netconfig *nconf, /* Network structure of transport */ 541177633Sdfr const struct netbuf *address) /* Services netconfig address */ 542177633Sdfr{ 543177633Sdfr CLIENT *client; 544177633Sdfr bool_t rslt = FALSE; 545177633Sdfr RPCB parms; 546177633Sdfr#if 0 547177633Sdfr char uidbuf[32]; 548177633Sdfr#endif 549177633Sdfr struct netconfig nconfcopy; 550177633Sdfr struct netbuf addresscopy; 551177633Sdfr 552177633Sdfr /* parameter checking */ 553177633Sdfr if (nconf == NULL) { 554177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 555177633Sdfr return (FALSE); 556177633Sdfr } 557177633Sdfr if (address == NULL) { 558177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 559177633Sdfr return (FALSE); 560177633Sdfr } 561177633Sdfr client = local_rpcb(); 562177633Sdfr if (! client) { 563177633Sdfr return (FALSE); 564177633Sdfr } 565177633Sdfr 566177633Sdfr /* convert to universal */ 567177633Sdfr /*LINTED const castaway*/ 568177633Sdfr nconfcopy = *nconf; 569177633Sdfr addresscopy = *address; 570177633Sdfr parms.r_addr = taddr2uaddr(&nconfcopy, &addresscopy); 571177633Sdfr if (!parms.r_addr) { 572177633Sdfr CLNT_DESTROY(client); 573177633Sdfr rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 574177633Sdfr return (FALSE); /* no universal address */ 575177633Sdfr } 576177633Sdfr parms.r_prog = program; 577177633Sdfr parms.r_vers = version; 578177633Sdfr parms.r_netid = nconf->nc_netid; 579177633Sdfr#if 0 580177633Sdfr /* 581177633Sdfr * Though uid is not being used directly, we still send it for 582177633Sdfr * completeness. For non-unix platforms, perhaps some other 583177633Sdfr * string or an empty string can be sent. 584177633Sdfr */ 585177633Sdfr (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); 586177633Sdfr parms.r_owner = uidbuf; 587177633Sdfr#else 588177633Sdfr parms.r_owner = ""; 589177633Sdfr#endif 590177633Sdfr 591177633Sdfr CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb, 592177633Sdfr (char *)(void *)&parms, (xdrproc_t) xdr_bool, 593177633Sdfr (char *)(void *)&rslt, tottimeout); 594177633Sdfr 595177633Sdfr CLNT_DESTROY(client); 596177633Sdfr free(parms.r_addr, M_RPC); 597177633Sdfr return (rslt); 598177633Sdfr} 599177633Sdfr 600177633Sdfr/* 601177633Sdfr * Remove the mapping between program, version and netbuf address. 602177633Sdfr * Calls the rpcbind service to do the un-mapping. 603177633Sdfr * If netbuf is NULL, unset for all the transports, otherwise unset 604177633Sdfr * only for the given transport. 605177633Sdfr */ 606177633Sdfrbool_t 607177633Sdfrrpcb_unset(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf) 608177633Sdfr{ 609177633Sdfr CLIENT *client; 610177633Sdfr bool_t rslt = FALSE; 611177633Sdfr RPCB parms; 612177633Sdfr#if 0 613177633Sdfr char uidbuf[32]; 614177633Sdfr#endif 615177633Sdfr 616177633Sdfr client = local_rpcb(); 617177633Sdfr if (! client) { 618177633Sdfr return (FALSE); 619177633Sdfr } 620177633Sdfr 621177633Sdfr parms.r_prog = program; 622177633Sdfr parms.r_vers = version; 623177633Sdfr if (nconf) 624177633Sdfr parms.r_netid = nconf->nc_netid; 625177633Sdfr else { 626177633Sdfr /*LINTED const castaway*/ 627177633Sdfr parms.r_netid = (char *)(uintptr_t) &nullstring[0]; /* unsets all */ 628177633Sdfr } 629177633Sdfr /*LINTED const castaway*/ 630177633Sdfr parms.r_addr = (char *)(uintptr_t) &nullstring[0]; 631177633Sdfr#if 0 632177633Sdfr (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); 633177633Sdfr parms.r_owner = uidbuf; 634177633Sdfr#else 635177633Sdfr parms.r_owner = ""; 636177633Sdfr#endif 637177633Sdfr 638177633Sdfr CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb, 639177633Sdfr (char *)(void *)&parms, (xdrproc_t) xdr_bool, 640177633Sdfr (char *)(void *)&rslt, tottimeout); 641177633Sdfr 642177633Sdfr CLNT_DESTROY(client); 643177633Sdfr return (rslt); 644177633Sdfr} 645177633Sdfr 646177633Sdfr#if 0 647177633Sdfr 648177633Sdfr/* 649177633Sdfr * From the merged list, find the appropriate entry 650177633Sdfr */ 651177633Sdfrstatic struct netbuf * 652177633Sdfrgot_entry(relp, nconf) 653177633Sdfr rpcb_entry_list_ptr relp; 654177633Sdfr const struct netconfig *nconf; 655177633Sdfr{ 656177633Sdfr struct netbuf *na = NULL; 657177633Sdfr rpcb_entry_list_ptr sp; 658177633Sdfr rpcb_entry *rmap; 659177633Sdfr 660177633Sdfr for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) { 661177633Sdfr rmap = &sp->rpcb_entry_map; 662177633Sdfr if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) && 663177633Sdfr (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) && 664177633Sdfr (nconf->nc_semantics == rmap->r_nc_semantics) && 665177633Sdfr (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) { 666177633Sdfr na = uaddr2taddr(nconf, rmap->r_maddr); 667177633Sdfr#ifdef ND_DEBUG 668177633Sdfr fprintf(stderr, "\tRemote address is [%s].\n", 669177633Sdfr rmap->r_maddr); 670177633Sdfr if (!na) 671177633Sdfr fprintf(stderr, 672177633Sdfr "\tCouldn't resolve remote address!\n"); 673177633Sdfr#endif 674177633Sdfr break; 675177633Sdfr } 676177633Sdfr } 677177633Sdfr return (na); 678177633Sdfr} 679177633Sdfr 680177633Sdfr/* 681177633Sdfr * Quick check to see if rpcbind is up. Tries to connect over 682177633Sdfr * local transport. 683177633Sdfr */ 684177633Sdfrstatic bool_t 685177633Sdfr__rpcbind_is_up() 686177633Sdfr{ 687177633Sdfr struct netconfig *nconf; 688177633Sdfr struct sockaddr_un sun; 689177633Sdfr void *localhandle; 690177633Sdfr int sock; 691177633Sdfr 692177633Sdfr nconf = NULL; 693177633Sdfr localhandle = setnetconfig(); 694177633Sdfr while ((nconf = getnetconfig(localhandle)) != NULL) { 695177633Sdfr if (nconf->nc_protofmly != NULL && 696177633Sdfr strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) 697177633Sdfr break; 698177633Sdfr } 699177633Sdfr if (nconf == NULL) 700177633Sdfr return (FALSE); 701177633Sdfr 702177633Sdfr endnetconfig(localhandle); 703177633Sdfr 704177633Sdfr memset(&sun, 0, sizeof sun); 705177633Sdfr sock = _socket(AF_LOCAL, SOCK_STREAM, 0); 706177633Sdfr if (sock < 0) 707177633Sdfr return (FALSE); 708177633Sdfr sun.sun_family = AF_LOCAL; 709177633Sdfr strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path)); 710177633Sdfr sun.sun_len = SUN_LEN(&sun); 711177633Sdfr 712177633Sdfr if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) { 713177633Sdfr _close(sock); 714177633Sdfr return (FALSE); 715177633Sdfr } 716177633Sdfr 717177633Sdfr _close(sock); 718177633Sdfr return (TRUE); 719177633Sdfr} 720177633Sdfr 721177633Sdfr/* 722177633Sdfr * An internal function which optimizes rpcb_getaddr function. It also 723177633Sdfr * returns the client handle that it uses to contact the remote rpcbind. 724177633Sdfr * 725177633Sdfr * The algorithm used: If the transports is TCP or UDP, it first tries 726177633Sdfr * version 2 (portmap), 4 and then 3 (svr4). This order should be 727177633Sdfr * changed in the next OS release to 4, 2 and 3. We are assuming that by 728177633Sdfr * that time, version 4 would be available on many machines on the network. 729177633Sdfr * With this algorithm, we get performance as well as a plan for 730177633Sdfr * obsoleting version 2. 731177633Sdfr * 732177633Sdfr * For all other transports, the algorithm remains as 4 and then 3. 733177633Sdfr * 734177633Sdfr * XXX: Due to some problems with t_connect(), we do not reuse the same client 735177633Sdfr * handle for COTS cases and hence in these cases we do not return the 736177633Sdfr * client handle. This code will change if t_connect() ever 737177633Sdfr * starts working properly. Also look under clnt_vc.c. 738177633Sdfr */ 739177633Sdfrstruct netbuf * 740177633Sdfr__rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) 741177633Sdfr rpcprog_t program; 742177633Sdfr rpcvers_t version; 743177633Sdfr const struct netconfig *nconf; 744177633Sdfr const char *host; 745177633Sdfr CLIENT **clpp; 746177633Sdfr struct timeval *tp; 747177633Sdfr{ 748177633Sdfr static bool_t check_rpcbind = TRUE; 749177633Sdfr CLIENT *client = NULL; 750177633Sdfr RPCB parms; 751177633Sdfr enum clnt_stat clnt_st; 752177633Sdfr char *ua = NULL; 753177633Sdfr rpcvers_t vers; 754177633Sdfr struct netbuf *address = NULL; 755177633Sdfr rpcvers_t start_vers = RPCBVERS4; 756177633Sdfr struct netbuf servaddr; 757177633Sdfr 758177633Sdfr /* parameter checking */ 759177633Sdfr if (nconf == NULL) { 760177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 761177633Sdfr return (NULL); 762177633Sdfr } 763177633Sdfr 764177633Sdfr parms.r_addr = NULL; 765177633Sdfr 766177633Sdfr /* 767177633Sdfr * Use default total timeout if no timeout is specified. 768177633Sdfr */ 769177633Sdfr if (tp == NULL) 770177633Sdfr tp = &tottimeout; 771177633Sdfr 772177633Sdfr#ifdef PORTMAP 773177633Sdfr /* Try version 2 for TCP or UDP */ 774177633Sdfr if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 775177633Sdfr u_short port = 0; 776177633Sdfr struct netbuf remote; 777177633Sdfr rpcvers_t pmapvers = 2; 778177633Sdfr struct pmap pmapparms; 779177633Sdfr 780177633Sdfr /* 781177633Sdfr * Try UDP only - there are some portmappers out 782177633Sdfr * there that use UDP only. 783177633Sdfr */ 784177633Sdfr if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 785177633Sdfr struct netconfig *newnconf; 786177633Sdfr 787177633Sdfr if ((newnconf = getnetconfigent("udp")) == NULL) { 788177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 789177633Sdfr return (NULL); 790177633Sdfr } 791177633Sdfr client = getclnthandle(host, newnconf, &parms.r_addr); 792177633Sdfr freenetconfigent(newnconf); 793177633Sdfr } else { 794177633Sdfr client = getclnthandle(host, nconf, &parms.r_addr); 795177633Sdfr } 796177633Sdfr if (client == NULL) 797177633Sdfr return (NULL); 798177633Sdfr 799177633Sdfr /* 800177633Sdfr * Set version and retry timeout. 801177633Sdfr */ 802177633Sdfr CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); 803177633Sdfr CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); 804177633Sdfr 805177633Sdfr pmapparms.pm_prog = program; 806177633Sdfr pmapparms.pm_vers = version; 807177633Sdfr pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? 808177633Sdfr IPPROTO_UDP : IPPROTO_TCP; 809177633Sdfr pmapparms.pm_port = 0; /* not needed */ 810177633Sdfr clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, 811177633Sdfr (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, 812177633Sdfr (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, 813177633Sdfr *tp); 814177633Sdfr if (clnt_st != RPC_SUCCESS) { 815177633Sdfr if ((clnt_st == RPC_PROGVERSMISMATCH) || 816177633Sdfr (clnt_st == RPC_PROGUNAVAIL)) 817177633Sdfr goto try_rpcbind; /* Try different versions */ 818177633Sdfr rpc_createerr.cf_stat = RPC_PMAPFAILURE; 819177633Sdfr clnt_geterr(client, &rpc_createerr.cf_error); 820177633Sdfr goto error; 821177633Sdfr } else if (port == 0) { 822177633Sdfr address = NULL; 823177633Sdfr rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 824177633Sdfr goto error; 825177633Sdfr } 826177633Sdfr port = htons(port); 827177633Sdfr CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); 828177633Sdfr if (((address = (struct netbuf *) 829177633Sdfr malloc(sizeof (struct netbuf))) == NULL) || 830177633Sdfr ((address->buf = (char *) 831177633Sdfr malloc(remote.len)) == NULL)) { 832177633Sdfr rpc_createerr.cf_stat = RPC_SYSTEMERROR; 833177633Sdfr clnt_geterr(client, &rpc_createerr.cf_error); 834177633Sdfr if (address) { 835177633Sdfr free(address); 836177633Sdfr address = NULL; 837177633Sdfr } 838177633Sdfr goto error; 839177633Sdfr } 840177633Sdfr memcpy(address->buf, remote.buf, remote.len); 841177633Sdfr memcpy(&((char *)address->buf)[sizeof (short)], 842177633Sdfr (char *)(void *)&port, sizeof (short)); 843177633Sdfr address->len = address->maxlen = remote.len; 844177633Sdfr goto done; 845177633Sdfr } 846177633Sdfr#endif /* PORTMAP */ 847177633Sdfr 848177633Sdfrtry_rpcbind: 849177633Sdfr /* 850177633Sdfr * Check if rpcbind is up. This prevents needless delays when 851177633Sdfr * accessing applications such as the keyserver while booting 852177633Sdfr * disklessly. 853177633Sdfr */ 854177633Sdfr if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 855177633Sdfr if (!__rpcbind_is_up()) { 856177633Sdfr rpc_createerr.cf_stat = RPC_PMAPFAILURE; 857177633Sdfr rpc_createerr.cf_error.re_errno = 0; 858177633Sdfr goto error; 859177633Sdfr } 860177633Sdfr check_rpcbind = FALSE; 861177633Sdfr } 862177633Sdfr 863177633Sdfr /* 864177633Sdfr * Now we try version 4 and then 3. 865177633Sdfr * We also send the remote system the address we used to 866177633Sdfr * contact it in case it can help to connect back with us 867177633Sdfr */ 868177633Sdfr parms.r_prog = program; 869177633Sdfr parms.r_vers = version; 870177633Sdfr /*LINTED const castaway*/ 871177633Sdfr parms.r_owner = (char *) &nullstring[0]; /* not needed; */ 872177633Sdfr /* just for xdring */ 873177633Sdfr parms.r_netid = nconf->nc_netid; /* not really needed */ 874177633Sdfr 875177633Sdfr /* 876177633Sdfr * If a COTS transport is being used, try getting address via CLTS 877177633Sdfr * transport. This works only with version 4. 878177633Sdfr */ 879177633Sdfr if (nconf->nc_semantics == NC_TPI_COTS_ORD || 880177633Sdfr nconf->nc_semantics == NC_TPI_COTS) { 881177633Sdfr 882177633Sdfr void *handle; 883177633Sdfr struct netconfig *nconf_clts; 884177633Sdfr rpcb_entry_list_ptr relp = NULL; 885177633Sdfr 886177633Sdfr if (client == NULL) { 887177633Sdfr /* This did not go through the above PORTMAP/TCP code */ 888177633Sdfr if ((handle = __rpc_setconf("datagram_v")) != NULL) { 889177633Sdfr while ((nconf_clts = __rpc_getconf(handle)) 890177633Sdfr != NULL) { 891177633Sdfr if (strcmp(nconf_clts->nc_protofmly, 892177633Sdfr nconf->nc_protofmly) != 0) { 893177633Sdfr continue; 894177633Sdfr } 895177633Sdfr client = getclnthandle(host, nconf_clts, 896177633Sdfr &parms.r_addr); 897177633Sdfr break; 898177633Sdfr } 899177633Sdfr __rpc_endconf(handle); 900177633Sdfr } 901177633Sdfr if (client == NULL) 902177633Sdfr goto regular_rpcbind; /* Go the regular way */ 903177633Sdfr } else { 904177633Sdfr /* This is a UDP PORTMAP handle. Change to version 4 */ 905177633Sdfr vers = RPCBVERS4; 906177633Sdfr CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 907177633Sdfr } 908177633Sdfr /* 909177633Sdfr * We also send the remote system the address we used to 910177633Sdfr * contact it in case it can help it connect back with us 911177633Sdfr */ 912177633Sdfr if (parms.r_addr == NULL) { 913177633Sdfr /*LINTED const castaway*/ 914177633Sdfr parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ 915177633Sdfr } 916177633Sdfr 917177633Sdfr CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); 918177633Sdfr 919177633Sdfr clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, 920177633Sdfr (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 921177633Sdfr (xdrproc_t) xdr_rpcb_entry_list_ptr, 922177633Sdfr (char *)(void *)&relp, *tp); 923177633Sdfr if (clnt_st == RPC_SUCCESS) { 924177633Sdfr if ((address = got_entry(relp, nconf)) != NULL) { 925177633Sdfr xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 926177633Sdfr (char *)(void *)&relp); 927177633Sdfr CLNT_CONTROL(client, CLGET_SVC_ADDR, 928177633Sdfr (char *)(void *)&servaddr); 929177633Sdfr __rpc_fixup_addr(address, &servaddr); 930177633Sdfr goto done; 931177633Sdfr } 932177633Sdfr /* Entry not found for this transport */ 933177633Sdfr xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 934177633Sdfr (char *)(void *)&relp); 935177633Sdfr /* 936177633Sdfr * XXX: should have perhaps returned with error but 937177633Sdfr * since the remote machine might not always be able 938177633Sdfr * to send the address on all transports, we try the 939177633Sdfr * regular way with regular_rpcbind 940177633Sdfr */ 941177633Sdfr goto regular_rpcbind; 942177633Sdfr } else if ((clnt_st == RPC_PROGVERSMISMATCH) || 943177633Sdfr (clnt_st == RPC_PROGUNAVAIL)) { 944177633Sdfr start_vers = RPCBVERS; /* Try version 3 now */ 945177633Sdfr goto regular_rpcbind; /* Try different versions */ 946177633Sdfr } else { 947177633Sdfr rpc_createerr.cf_stat = RPC_PMAPFAILURE; 948177633Sdfr clnt_geterr(client, &rpc_createerr.cf_error); 949177633Sdfr goto error; 950177633Sdfr } 951177633Sdfr } 952177633Sdfr 953177633Sdfrregular_rpcbind: 954177633Sdfr 955177633Sdfr /* Now the same transport is to be used to get the address */ 956177633Sdfr if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || 957177633Sdfr (nconf->nc_semantics == NC_TPI_COTS))) { 958177633Sdfr /* A CLTS type of client - destroy it */ 959177633Sdfr CLNT_DESTROY(client); 960177633Sdfr client = NULL; 961177633Sdfr } 962177633Sdfr 963177633Sdfr if (client == NULL) { 964177633Sdfr client = getclnthandle(host, nconf, &parms.r_addr); 965177633Sdfr if (client == NULL) { 966177633Sdfr goto error; 967177633Sdfr } 968177633Sdfr } 969177633Sdfr if (parms.r_addr == NULL) { 970177633Sdfr /*LINTED const castaway*/ 971177633Sdfr parms.r_addr = (char *) &nullstring[0]; 972177633Sdfr } 973177633Sdfr 974177633Sdfr /* First try from start_vers and then version 3 (RPCBVERS) */ 975177633Sdfr 976177633Sdfr CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); 977177633Sdfr for (vers = start_vers; vers >= RPCBVERS; vers--) { 978177633Sdfr /* Set the version */ 979177633Sdfr CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 980177633Sdfr clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, 981177633Sdfr (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 982177633Sdfr (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp); 983177633Sdfr if (clnt_st == RPC_SUCCESS) { 984177633Sdfr if ((ua == NULL) || (ua[0] == 0)) { 985177633Sdfr /* address unknown */ 986177633Sdfr rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 987177633Sdfr goto error; 988177633Sdfr } 989177633Sdfr address = uaddr2taddr(nconf, ua); 990177633Sdfr#ifdef ND_DEBUG 991177633Sdfr fprintf(stderr, "\tRemote address is [%s]\n", ua); 992177633Sdfr if (!address) 993177633Sdfr fprintf(stderr, 994177633Sdfr "\tCouldn't resolve remote address!\n"); 995177633Sdfr#endif 996177633Sdfr xdr_free((xdrproc_t)xdr_wrapstring, 997177633Sdfr (char *)(void *)&ua); 998177633Sdfr 999177633Sdfr if (! address) { 1000177633Sdfr /* We don't know about your universal address */ 1001177633Sdfr rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 1002177633Sdfr goto error; 1003177633Sdfr } 1004177633Sdfr CLNT_CONTROL(client, CLGET_SVC_ADDR, 1005177633Sdfr (char *)(void *)&servaddr); 1006177633Sdfr __rpc_fixup_addr(address, &servaddr); 1007177633Sdfr goto done; 1008177633Sdfr } else if (clnt_st == RPC_PROGVERSMISMATCH) { 1009177633Sdfr struct rpc_err rpcerr; 1010177633Sdfr 1011177633Sdfr clnt_geterr(client, &rpcerr); 1012177633Sdfr if (rpcerr.re_vers.low > RPCBVERS4) 1013177633Sdfr goto error; /* a new version, can't handle */ 1014177633Sdfr } else if (clnt_st != RPC_PROGUNAVAIL) { 1015177633Sdfr /* Cant handle this error */ 1016177633Sdfr rpc_createerr.cf_stat = clnt_st; 1017177633Sdfr clnt_geterr(client, &rpc_createerr.cf_error); 1018177633Sdfr goto error; 1019177633Sdfr } 1020177633Sdfr } 1021177633Sdfr 1022177633Sdfrerror: 1023177633Sdfr if (client) { 1024177633Sdfr CLNT_DESTROY(client); 1025177633Sdfr client = NULL; 1026177633Sdfr } 1027177633Sdfrdone: 1028177633Sdfr if (nconf->nc_semantics != NC_TPI_CLTS) { 1029177633Sdfr /* This client is the connectionless one */ 1030177633Sdfr if (client) { 1031177633Sdfr CLNT_DESTROY(client); 1032177633Sdfr client = NULL; 1033177633Sdfr } 1034177633Sdfr } 1035177633Sdfr if (clpp) { 1036177633Sdfr *clpp = client; 1037177633Sdfr } else if (client) { 1038177633Sdfr CLNT_DESTROY(client); 1039177633Sdfr } 1040177633Sdfr if (parms.r_addr != NULL && parms.r_addr != nullstring) 1041177633Sdfr free(parms.r_addr); 1042177633Sdfr return (address); 1043177633Sdfr} 1044177633Sdfr 1045177633Sdfr 1046177633Sdfr/* 1047177633Sdfr * Find the mapped address for program, version. 1048177633Sdfr * Calls the rpcbind service remotely to do the lookup. 1049177633Sdfr * Uses the transport specified in nconf. 1050177633Sdfr * Returns FALSE (0) if no map exists, else returns 1. 1051177633Sdfr * 1052177633Sdfr * Assuming that the address is all properly allocated 1053177633Sdfr */ 1054177633Sdfrint 1055177633Sdfrrpcb_getaddr(program, version, nconf, address, host) 1056177633Sdfr rpcprog_t program; 1057177633Sdfr rpcvers_t version; 1058177633Sdfr const struct netconfig *nconf; 1059177633Sdfr struct netbuf *address; 1060177633Sdfr const char *host; 1061177633Sdfr{ 1062177633Sdfr struct netbuf *na; 1063177633Sdfr 1064177633Sdfr if ((na = __rpcb_findaddr_timed(program, version, 1065177633Sdfr (struct netconfig *) nconf, (char *) host, 1066177633Sdfr (CLIENT **) NULL, (struct timeval *) NULL)) == NULL) 1067177633Sdfr return (FALSE); 1068177633Sdfr 1069177633Sdfr if (na->len > address->maxlen) { 1070177633Sdfr /* Too long address */ 1071177633Sdfr free(na->buf); 1072177633Sdfr free(na); 1073177633Sdfr rpc_createerr.cf_stat = RPC_FAILED; 1074177633Sdfr return (FALSE); 1075177633Sdfr } 1076177633Sdfr memcpy(address->buf, na->buf, (size_t)na->len); 1077177633Sdfr address->len = na->len; 1078177633Sdfr free(na->buf); 1079177633Sdfr free(na); 1080177633Sdfr return (TRUE); 1081177633Sdfr} 1082177633Sdfr 1083177633Sdfr/* 1084177633Sdfr * Get a copy of the current maps. 1085177633Sdfr * Calls the rpcbind service remotely to get the maps. 1086177633Sdfr * 1087177633Sdfr * It returns only a list of the services 1088177633Sdfr * It returns NULL on failure. 1089177633Sdfr */ 1090177633Sdfrrpcblist * 1091177633Sdfrrpcb_getmaps(nconf, host) 1092177633Sdfr const struct netconfig *nconf; 1093177633Sdfr const char *host; 1094177633Sdfr{ 1095177633Sdfr rpcblist_ptr head = NULL; 1096177633Sdfr CLIENT *client; 1097177633Sdfr enum clnt_stat clnt_st; 1098177633Sdfr rpcvers_t vers = 0; 1099177633Sdfr 1100177633Sdfr client = getclnthandle(host, nconf, NULL); 1101177633Sdfr if (client == NULL) { 1102177633Sdfr return (head); 1103177633Sdfr } 1104177633Sdfr clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 1105177633Sdfr (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 1106177633Sdfr (char *)(void *)&head, tottimeout); 1107177633Sdfr if (clnt_st == RPC_SUCCESS) 1108177633Sdfr goto done; 1109177633Sdfr 1110177633Sdfr if ((clnt_st != RPC_PROGVERSMISMATCH) && 1111177633Sdfr (clnt_st != RPC_PROGUNAVAIL)) { 1112177633Sdfr rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1113177633Sdfr clnt_geterr(client, &rpc_createerr.cf_error); 1114177633Sdfr goto done; 1115177633Sdfr } 1116177633Sdfr 1117177633Sdfr /* fall back to earlier version */ 1118177633Sdfr CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 1119177633Sdfr if (vers == RPCBVERS4) { 1120177633Sdfr vers = RPCBVERS; 1121177633Sdfr CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 1122177633Sdfr if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 1123177633Sdfr (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 1124177633Sdfr (char *)(void *)&head, tottimeout) == RPC_SUCCESS) 1125177633Sdfr goto done; 1126177633Sdfr } 1127177633Sdfr rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1128177633Sdfr clnt_geterr(client, &rpc_createerr.cf_error); 1129177633Sdfr 1130177633Sdfrdone: 1131177633Sdfr CLNT_DESTROY(client); 1132177633Sdfr return (head); 1133177633Sdfr} 1134177633Sdfr 1135177633Sdfr/* 1136177633Sdfr * rpcbinder remote-call-service interface. 1137177633Sdfr * This routine is used to call the rpcbind remote call service 1138177633Sdfr * which will look up a service program in the address maps, and then 1139177633Sdfr * remotely call that routine with the given parameters. This allows 1140177633Sdfr * programs to do a lookup and call in one step. 1141177633Sdfr*/ 1142177633Sdfrenum clnt_stat 1143177633Sdfrrpcb_rmtcall(nconf, host, prog, vers, proc, xdrargs, argsp, 1144177633Sdfr xdrres, resp, tout, addr_ptr) 1145177633Sdfr const struct netconfig *nconf; /* Netconfig structure */ 1146177633Sdfr const char *host; /* Remote host name */ 1147177633Sdfr rpcprog_t prog; 1148177633Sdfr rpcvers_t vers; 1149177633Sdfr rpcproc_t proc; /* Remote proc identifiers */ 1150177633Sdfr xdrproc_t xdrargs, xdrres; /* XDR routines */ 1151177633Sdfr caddr_t argsp, resp; /* Argument and Result */ 1152177633Sdfr struct timeval tout; /* Timeout value for this call */ 1153177633Sdfr const struct netbuf *addr_ptr; /* Preallocated netbuf address */ 1154177633Sdfr{ 1155177633Sdfr CLIENT *client; 1156177633Sdfr enum clnt_stat stat; 1157177633Sdfr struct r_rpcb_rmtcallargs a; 1158177633Sdfr struct r_rpcb_rmtcallres r; 1159177633Sdfr rpcvers_t rpcb_vers; 1160177633Sdfr 1161177633Sdfr stat = 0; 1162177633Sdfr client = getclnthandle(host, nconf, NULL); 1163177633Sdfr if (client == NULL) { 1164177633Sdfr return (RPC_FAILED); 1165177633Sdfr } 1166177633Sdfr /*LINTED const castaway*/ 1167177633Sdfr CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout); 1168177633Sdfr a.prog = prog; 1169177633Sdfr a.vers = vers; 1170177633Sdfr a.proc = proc; 1171177633Sdfr a.args.args_val = argsp; 1172177633Sdfr a.xdr_args = xdrargs; 1173177633Sdfr r.addr = NULL; 1174177633Sdfr r.results.results_val = resp; 1175177633Sdfr r.xdr_res = xdrres; 1176177633Sdfr 1177177633Sdfr for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { 1178177633Sdfr CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers); 1179177633Sdfr stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT, 1180177633Sdfr (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a, 1181177633Sdfr (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout); 1182177633Sdfr if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { 1183177633Sdfr struct netbuf *na; 1184177633Sdfr /*LINTED const castaway*/ 1185177633Sdfr na = uaddr2taddr((struct netconfig *) nconf, r.addr); 1186177633Sdfr if (!na) { 1187177633Sdfr stat = RPC_N2AXLATEFAILURE; 1188177633Sdfr /*LINTED const castaway*/ 1189177633Sdfr ((struct netbuf *) addr_ptr)->len = 0; 1190177633Sdfr goto error; 1191177633Sdfr } 1192177633Sdfr if (na->len > addr_ptr->maxlen) { 1193177633Sdfr /* Too long address */ 1194177633Sdfr stat = RPC_FAILED; /* XXX A better error no */ 1195177633Sdfr free(na->buf); 1196177633Sdfr free(na); 1197177633Sdfr /*LINTED const castaway*/ 1198177633Sdfr ((struct netbuf *) addr_ptr)->len = 0; 1199177633Sdfr goto error; 1200177633Sdfr } 1201177633Sdfr memcpy(addr_ptr->buf, na->buf, (size_t)na->len); 1202177633Sdfr /*LINTED const castaway*/ 1203177633Sdfr ((struct netbuf *)addr_ptr)->len = na->len; 1204177633Sdfr free(na->buf); 1205177633Sdfr free(na); 1206177633Sdfr break; 1207177633Sdfr } else if ((stat != RPC_PROGVERSMISMATCH) && 1208177633Sdfr (stat != RPC_PROGUNAVAIL)) { 1209177633Sdfr goto error; 1210177633Sdfr } 1211177633Sdfr } 1212177633Sdfrerror: 1213177633Sdfr CLNT_DESTROY(client); 1214177633Sdfr if (r.addr) 1215177633Sdfr xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr); 1216177633Sdfr return (stat); 1217177633Sdfr} 1218177633Sdfr 1219177633Sdfr/* 1220177633Sdfr * Gets the time on the remote host. 1221177633Sdfr * Returns 1 if succeeds else 0. 1222177633Sdfr */ 1223177633Sdfrbool_t 1224177633Sdfrrpcb_gettime(host, timep) 1225177633Sdfr const char *host; 1226177633Sdfr time_t *timep; 1227177633Sdfr{ 1228177633Sdfr CLIENT *client = NULL; 1229177633Sdfr void *handle; 1230177633Sdfr struct netconfig *nconf; 1231177633Sdfr rpcvers_t vers; 1232177633Sdfr enum clnt_stat st; 1233177633Sdfr 1234177633Sdfr 1235177633Sdfr if ((host == NULL) || (host[0] == 0)) { 1236177633Sdfr time(timep); 1237177633Sdfr return (TRUE); 1238177633Sdfr } 1239177633Sdfr 1240177633Sdfr if ((handle = __rpc_setconf("netpath")) == NULL) { 1241177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1242177633Sdfr return (FALSE); 1243177633Sdfr } 1244177633Sdfr rpc_createerr.cf_stat = RPC_SUCCESS; 1245177633Sdfr while (client == NULL) { 1246177633Sdfr if ((nconf = __rpc_getconf(handle)) == NULL) { 1247177633Sdfr if (rpc_createerr.cf_stat == RPC_SUCCESS) 1248177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1249177633Sdfr break; 1250177633Sdfr } 1251177633Sdfr client = getclnthandle(host, nconf, NULL); 1252177633Sdfr if (client) 1253177633Sdfr break; 1254177633Sdfr } 1255177633Sdfr __rpc_endconf(handle); 1256177633Sdfr if (client == (CLIENT *) NULL) { 1257177633Sdfr return (FALSE); 1258177633Sdfr } 1259177633Sdfr 1260177633Sdfr st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 1261177633Sdfr (xdrproc_t) xdr_void, NULL, 1262177633Sdfr (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); 1263177633Sdfr 1264177633Sdfr if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { 1265177633Sdfr CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 1266177633Sdfr if (vers == RPCBVERS4) { 1267177633Sdfr /* fall back to earlier version */ 1268177633Sdfr vers = RPCBVERS; 1269177633Sdfr CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 1270177633Sdfr st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 1271177633Sdfr (xdrproc_t) xdr_void, NULL, 1272177633Sdfr (xdrproc_t) xdr_int, (char *)(void *)timep, 1273177633Sdfr tottimeout); 1274177633Sdfr } 1275177633Sdfr } 1276177633Sdfr CLNT_DESTROY(client); 1277177633Sdfr return (st == RPC_SUCCESS? TRUE: FALSE); 1278177633Sdfr} 1279177633Sdfr 1280177633Sdfrstatic bool_t 1281177633Sdfrxdr_netbuf(XDR *xdrs, struct netbuf *objp) 1282177633Sdfr{ 1283177633Sdfr bool_t dummy; 1284177633Sdfr void **pp; 1285177633Sdfr 1286177633Sdfr if (!xdr_uint32_t(xdrs, (uint32_t *) &objp->maxlen)) { 1287177633Sdfr return (FALSE); 1288177633Sdfr } 1289177633Sdfr pp = &objp->buf; 1290177633Sdfr dummy = xdr_bytes(xdrs, (char **) pp, 1291177633Sdfr (u_int *)&(objp->len), objp->maxlen); 1292177633Sdfr return (dummy); 1293177633Sdfr} 1294177633Sdfr 1295177633Sdfr/* 1296177633Sdfr * Converts taddr to universal address. This routine should never 1297177633Sdfr * really be called because local n2a libraries are always provided. 1298177633Sdfr */ 1299177633Sdfrchar * 1300177633Sdfrrpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr) 1301177633Sdfr{ 1302177633Sdfr CLIENT *client; 1303177633Sdfr char *uaddr = NULL; 1304177633Sdfr 1305177633Sdfr 1306177633Sdfr /* parameter checking */ 1307177633Sdfr if (nconf == NULL) { 1308177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1309177633Sdfr return (NULL); 1310177633Sdfr } 1311177633Sdfr if (taddr == NULL) { 1312177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1313177633Sdfr return (NULL); 1314177633Sdfr } 1315177633Sdfr client = local_rpcb(); 1316177633Sdfr if (! client) { 1317177633Sdfr return (NULL); 1318177633Sdfr } 1319177633Sdfr 1320177633Sdfr CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR, 1321177633Sdfr (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 1322177633Sdfr (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout); 1323177633Sdfr CLNT_DESTROY(client); 1324177633Sdfr return (uaddr); 1325177633Sdfr} 1326177633Sdfr 1327177633Sdfr/* 1328177633Sdfr * Converts universal address to netbuf. This routine should never 1329177633Sdfr * really be called because local n2a libraries are always provided. 1330177633Sdfr */ 1331177633Sdfrstruct netbuf * 1332177633Sdfrrpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr) 1333177633Sdfr{ 1334177633Sdfr CLIENT *client; 1335177633Sdfr struct netbuf *taddr; 1336177633Sdfr 1337177633Sdfr 1338177633Sdfr /* parameter checking */ 1339177633Sdfr if (nconf == NULL) { 1340177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1341177633Sdfr return (NULL); 1342177633Sdfr } 1343177633Sdfr if (uaddr == NULL) { 1344177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1345177633Sdfr return (NULL); 1346177633Sdfr } 1347177633Sdfr client = local_rpcb(); 1348177633Sdfr if (! client) { 1349177633Sdfr return (NULL); 1350177633Sdfr } 1351177633Sdfr 1352177633Sdfr taddr = (struct netbuf *)malloc(sizeof (struct netbuf), M_RPC, M_WAITOK|M_ZERO); 1353177633Sdfr if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR, 1354177633Sdfr (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, 1355177633Sdfr (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 1356177633Sdfr tottimeout) != RPC_SUCCESS) { 1357177633Sdfr free(taddr); 1358177633Sdfr taddr = NULL; 1359177633Sdfr } 1360177633Sdfr CLNT_DESTROY(client); 1361177633Sdfr return (taddr); 1362177633Sdfr} 1363177633Sdfr 1364177633Sdfr#endif 1365