1/* $NetBSD: rpcb_clnt.c,v 1.32 2024/01/23 17:24:38 christos Exp $ */ 2 3/* 4 * Copyright (c) 2010, Oracle America, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * * Neither the name of the "Oracle America, Inc." nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33/* 34 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 35 */ 36 37/* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */ 38 39#include <sys/cdefs.h> 40#if defined(LIBC_SCCS) && !defined(lint) 41#if 0 42static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro"; 43#else 44__RCSID("$NetBSD: rpcb_clnt.c,v 1.32 2024/01/23 17:24:38 christos Exp $"); 45#endif 46#endif 47 48/* 49 * rpcb_clnt.c 50 * interface to rpcbind rpc service. 51 * 52 * Copyright (C) 1988, Sun Microsystems, Inc. 53 */ 54 55#include "namespace.h" 56#include "reentrant.h" 57#include <sys/types.h> 58#include <sys/socket.h> 59#include <sys/un.h> 60#include <sys/utsname.h> 61#include <rpc/rpc.h> 62#include <rpc/rpcb_prot.h> 63#include <rpc/nettype.h> 64#include <netconfig.h> 65#ifdef PORTMAP 66#include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */ 67#include <rpc/pmap_prot.h> 68#endif 69#include <assert.h> 70#include <errno.h> 71#include <netdb.h> 72#include <stdio.h> 73#include <stdlib.h> 74#include <string.h> 75#include <syslog.h> 76#include <unistd.h> 77 78#include "svc_fdset.h" 79#include "rpc_internal.h" 80 81#ifdef __weak_alias 82__weak_alias(rpcb_set,_rpcb_set) 83__weak_alias(rpcb_unset,_rpcb_unset) 84__weak_alias(rpcb_getmaps,_rpcb_getmaps) 85__weak_alias(rpcb_taddr2uaddr,_rpcb_taddr2uaddr) 86__weak_alias(rpcb_uaddr2taddr,_rpcb_uaddr2taddr) 87#endif 88 89static struct timeval tottimeout = { 60, 0 }; 90static const struct timeval rmttimeout = { 3, 0 }; 91 92static const char nullstring[] = "\000"; 93 94#define CACHESIZE 6 95 96struct address_cache { 97 char *ac_host; 98 char *ac_netid; 99 char *ac_uaddr; 100 struct netbuf *ac_taddr; 101 struct address_cache *ac_next; 102}; 103 104static struct address_cache *front; 105static int cachesize; 106 107#define CLCR_GET_RPCB_TIMEOUT 1 108#define CLCR_SET_RPCB_TIMEOUT 2 109 110 111static struct address_cache *check_cache(const char *, const char *); 112static void delete_cache(struct netbuf *); 113static void add_cache(const char *, const char *, struct netbuf *, char *); 114static CLIENT *getclnthandle(const char *, const struct netconfig *, char **); 115static CLIENT *local_rpcb(void); 116static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *); 117 118/* 119 * This routine adjusts the timeout used for calls to the remote rpcbind. 120 * Also, this routine can be used to set the use of portmapper version 2 121 * only when doing rpc_broadcasts 122 * These are private routines that may not be provided in future releases. 123 */ 124bool_t 125__rpc_control(int request, void *info) 126{ 127 128 _DIAGASSERT(info != NULL); 129 130 switch (request) { 131 case CLCR_GET_RPCB_TIMEOUT: 132 *(struct timeval *)info = tottimeout; 133 break; 134 case CLCR_SET_RPCB_TIMEOUT: 135 tottimeout = *(struct timeval *)info; 136 break; 137 case CLCR_SET_LOWVERS: 138 __rpc_lowvers = *(int *)info; 139 break; 140 case CLCR_GET_LOWVERS: 141 *(int *)info = __rpc_lowvers; 142 break; 143 default: 144 return (FALSE); 145 } 146 return (TRUE); 147} 148 149/* 150 * It might seem that a reader/writer lock would be more reasonable here. 151 * However because getclnthandle(), the only user of the cache functions, 152 * may do a delete_cache() operation if a check_cache() fails to return an 153 * address useful to clnt_tli_create(), we may as well use a mutex. 154 */ 155/* 156 * As it turns out, if the cache lock is *not* a reader/writer lock, we will 157 * block all clnt_create's if we are trying to connect to a host that's down, 158 * since the lock will be held all during that time. 159 */ 160 161/* 162 * The routines check_cache(), add_cache(), delete_cache() manage the 163 * cache of rpcbind addresses for (host, netid). 164 */ 165 166static struct address_cache * 167check_cache(const char *host, const char *netid) 168{ 169 struct address_cache *cptr; 170 171 _DIAGASSERT(host != NULL); 172 _DIAGASSERT(netid != NULL); 173 174 /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ 175 176 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { 177 if (!strcmp(cptr->ac_host, host) && 178 !strcmp(cptr->ac_netid, netid)) { 179#ifdef ND_DEBUG 180 fprintf(stderr, "Found cache entry for %s: %s\n", 181 host, netid); 182#endif 183 return (cptr); 184 } 185 } 186 return NULL; 187} 188 189static void 190delete_cache(struct netbuf *addr) 191{ 192 struct address_cache *cptr, *prevptr = NULL; 193 194 _DIAGASSERT(addr != NULL); 195 196 /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ 197 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { 198 if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { 199 free(cptr->ac_host); 200 free(cptr->ac_netid); 201 free(cptr->ac_taddr->buf); 202 free(cptr->ac_taddr); 203 if (cptr->ac_uaddr) 204 free(cptr->ac_uaddr); 205 if (prevptr) 206 prevptr->ac_next = cptr->ac_next; 207 else 208 front = cptr->ac_next; 209 free(cptr); 210 cachesize--; 211 break; 212 } 213 prevptr = cptr; 214 } 215} 216 217static void 218add_cache(const char *host, const char *netid, struct netbuf *taddr, 219 char *uaddr) 220{ 221 struct address_cache *ad_cache, *cptr, *prevptr; 222 223 _DIAGASSERT(host != NULL); 224 _DIAGASSERT(netid != NULL); 225 /* uaddr may be NULL */ 226 /* taddr may be NULL ??? */ 227 228 ad_cache = malloc(sizeof(*ad_cache)); 229 if (!ad_cache) { 230 return; 231 } 232 ad_cache->ac_host = strdup(host); 233 ad_cache->ac_netid = strdup(netid); 234 ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL; 235 ad_cache->ac_taddr = malloc(sizeof(*ad_cache->ac_taddr)); 236 if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr || 237 (uaddr && !ad_cache->ac_uaddr)) { 238 goto out; 239 } 240 ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len; 241 ad_cache->ac_taddr->buf = malloc(taddr->len); 242 if (ad_cache->ac_taddr->buf == NULL) { 243out: 244 if (ad_cache->ac_host) 245 free(ad_cache->ac_host); 246 if (ad_cache->ac_netid) 247 free(ad_cache->ac_netid); 248 if (ad_cache->ac_uaddr) 249 free(ad_cache->ac_uaddr); 250 if (ad_cache->ac_taddr) 251 free(ad_cache->ac_taddr); 252 free(ad_cache); 253 return; 254 } 255 memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len); 256#ifdef ND_DEBUG 257 fprintf(stderr, "Added to cache: %s : %s\n", host, netid); 258#endif 259 260/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ 261 262 rwlock_wrlock(&rpcbaddr_cache_lock); 263 if (cachesize < CACHESIZE) { 264 ad_cache->ac_next = front; 265 front = ad_cache; 266 cachesize++; 267 } else { 268 /* Free the last entry */ 269 cptr = front; 270 prevptr = NULL; 271 while (cptr->ac_next) { 272 prevptr = cptr; 273 cptr = cptr->ac_next; 274 } 275 276#ifdef ND_DEBUG 277 fprintf(stderr, "Deleted from cache: %s : %s\n", 278 cptr->ac_host, cptr->ac_netid); 279#endif 280 free(cptr->ac_host); 281 free(cptr->ac_netid); 282 free(cptr->ac_taddr->buf); 283 free(cptr->ac_taddr); 284 if (cptr->ac_uaddr) 285 free(cptr->ac_uaddr); 286 287 if (prevptr) { 288 prevptr->ac_next = NULL; 289 ad_cache->ac_next = front; 290 front = ad_cache; 291 } else { 292 front = ad_cache; 293 ad_cache->ac_next = NULL; 294 } 295 free(cptr); 296 } 297 rwlock_unlock(&rpcbaddr_cache_lock); 298} 299 300/* 301 * This routine will return a client handle that is connected to the 302 * rpcbind. Returns NULL on error and free's everything. 303 */ 304static CLIENT * 305getclnthandle(const char *host, const struct netconfig *nconf, char **targaddr) 306{ 307 CLIENT *client; 308 struct netbuf *addr, taddr; 309 struct netbuf addr_to_delete; 310 struct __rpc_sockinfo si; 311 struct addrinfo hints, *res, *tres; 312 struct address_cache *ad_cache; 313 char *tmpaddr; 314 315 _DIAGASSERT(host != NULL); 316 _DIAGASSERT(nconf != NULL); 317 /* targaddr may be NULL */ 318 319/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ 320 321 /* Get the address of the rpcbind. Check cache first */ 322 client = NULL; 323 addr_to_delete.len = 0; 324 addr_to_delete.buf = NULL; 325 rwlock_rdlock(&rpcbaddr_cache_lock); 326 ad_cache = check_cache(host, nconf->nc_netid); 327 if (ad_cache != NULL) { 328 addr = ad_cache->ac_taddr; 329 client = clnt_tli_create(RPC_ANYFD, nconf, addr, 330 (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); 331 if (client != NULL) { 332 if (targaddr) 333 *targaddr = ad_cache->ac_uaddr; 334 rwlock_unlock(&rpcbaddr_cache_lock); 335 return (client); 336 } 337 addr_to_delete.len = addr->len; 338 addr_to_delete.buf = malloc(addr->len); 339 if (addr_to_delete.buf == NULL) { 340 addr_to_delete.len = 0; 341 } else { 342 memcpy(addr_to_delete.buf, addr->buf, addr->len); 343 } 344 } 345 rwlock_unlock(&rpcbaddr_cache_lock); 346 if (addr_to_delete.len != 0) { 347 /* 348 * Assume this may be due to cache data being 349 * outdated 350 */ 351 rwlock_wrlock(&rpcbaddr_cache_lock); 352 delete_cache(&addr_to_delete); 353 rwlock_unlock(&rpcbaddr_cache_lock); 354 free(addr_to_delete.buf); 355 } 356 if (!__rpc_nconf2sockinfo(nconf, &si)) { 357 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 358 return NULL; 359 } 360 361 memset(&hints, 0, sizeof hints); 362 hints.ai_family = si.si_af; 363 hints.ai_socktype = si.si_socktype; 364 hints.ai_protocol = si.si_proto; 365 366#ifdef CLNT_DEBUG 367 printf("trying netid %s family %d proto %d socktype %d\n", 368 nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype); 369#endif 370 371 if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) { 372 rpc_createerr.cf_stat = RPC_UNKNOWNHOST; 373 return NULL; 374 } 375 376 for (tres = res; tres != NULL; tres = tres->ai_next) { 377 taddr.buf = tres->ai_addr; 378 taddr.len = taddr.maxlen = tres->ai_addrlen; 379 380#ifdef ND_DEBUG 381 { 382 char *ua; 383 384 ua = taddr2uaddr(nconf, &taddr); 385 fprintf(stderr, "Got it [%s]\n", ua); 386 free(ua); 387 } 388#endif 389 390#ifdef ND_DEBUG 391 { 392 int i; 393 394 fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n", 395 taddr.len, taddr.maxlen); 396 fprintf(stderr, "\tAddress is "); 397 for (i = 0; i < taddr.len; i++) 398 fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]); 399 fprintf(stderr, "\n"); 400 } 401#endif 402 client = clnt_tli_create(RPC_ANYFD, nconf, &taddr, 403 (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); 404#ifdef ND_DEBUG 405 if (! client) { 406 clnt_pcreateerror("rpcbind clnt interface"); 407 } 408#endif 409 410 if (client) { 411 tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL; 412 add_cache(host, nconf->nc_netid, &taddr, tmpaddr); 413 if (targaddr) 414 *targaddr = tmpaddr; 415 break; 416 } 417 } 418 freeaddrinfo(res); 419 return (client); 420} 421 422/* XXX */ 423#define IN4_LOCALHOST_STRING "127.0.0.1" 424#define IN6_LOCALHOST_STRING "::1" 425 426/* 427 * This routine will return a client handle that is connected to the local 428 * rpcbind. Returns NULL on error and free's everything. 429 */ 430static CLIENT * 431local_rpcb(void) 432{ 433 CLIENT *client; 434 static struct netconfig *loopnconf; 435 static const char *hostname; 436 int sock; 437 size_t tsize; 438 struct netbuf nbuf; 439 struct sockaddr_un sun; 440 441 /* 442 * Try connecting to the local rpcbind through a local socket 443 * first. If this doesn't work, try all transports defined in 444 * the netconfig file. 445 */ 446 memset(&sun, 0, sizeof sun); 447 sock = socket(AF_LOCAL, SOCK_STREAM, 0); 448 if (sock < 0) 449 goto try_nconf; 450 sun.sun_family = AF_LOCAL; 451 strcpy(sun.sun_path, _PATH_RPCBINDSOCK); 452 tsize = SUN_LEN(&sun); 453 _DIAGASSERT(__type_fit(uint8_t, tsize)); 454 nbuf.len = sun.sun_len = (uint8_t)tsize; 455 nbuf.maxlen = sizeof (struct sockaddr_un); 456 nbuf.buf = &sun; 457 458 tsize = __rpc_get_t_size(AF_LOCAL, 0, 0); 459 _DIAGASSERT(__type_fit(u_int, tsize)); 460 client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG, 461 (rpcvers_t)RPCBVERS, (u_int)tsize, (u_int)tsize); 462 463 if (client != NULL) { 464 /* XXX - mark the socket to be closed in destructor */ 465 (void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); 466 return client; 467 } 468 469 /* XXX - nobody needs this socket anymore, free the descriptor */ 470 close(sock); 471 472try_nconf: 473 474/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */ 475 mutex_lock(&loopnconf_lock); 476 if (loopnconf == NULL) { 477 struct netconfig *nconf, *tmpnconf = NULL; 478 void *nc_handle; 479 int fd; 480 481 nc_handle = setnetconfig(); 482 if (nc_handle == NULL) { 483 /* fails to open netconfig file */ 484 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 485 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 486 mutex_unlock(&loopnconf_lock); 487 return (NULL); 488 } 489 while ((nconf = getnetconfig(nc_handle)) != NULL) { 490#ifdef INET6 491 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 || 492#else 493 if (( 494#endif 495 strcmp(nconf->nc_protofmly, NC_INET) == 0) && 496 (nconf->nc_semantics == NC_TPI_COTS || 497 nconf->nc_semantics == NC_TPI_COTS_ORD)) { 498 fd = __rpc_nconf2fd(nconf); 499 /* 500 * Can't create a socket, assume that 501 * this family isn't configured in the kernel. 502 */ 503 if (fd < 0) 504 continue; 505 close(fd); 506 tmpnconf = nconf; 507 if (!strcmp(nconf->nc_protofmly, NC_INET)) 508 hostname = IN4_LOCALHOST_STRING; 509 else 510 hostname = IN6_LOCALHOST_STRING; 511 } 512 } 513 if (tmpnconf == NULL) { 514 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 515 mutex_unlock(&loopnconf_lock); 516 return (NULL); 517 } 518 loopnconf = getnetconfigent(tmpnconf->nc_netid); 519 /* loopnconf is never freed */ 520 endnetconfig(nc_handle); 521 } 522 mutex_unlock(&loopnconf_lock); 523 client = getclnthandle(hostname, loopnconf, NULL); 524 return (client); 525} 526 527/* 528 * Set a mapping between program, version and address. 529 * Calls the rpcbind service to do the mapping. 530 */ 531bool_t 532rpcb_set(rpcprog_t program, rpcvers_t version, 533 const struct netconfig *nconf, /* Network structure of transport */ 534 const struct netbuf *address) /* Services netconfig address */ 535{ 536 CLIENT *client; 537 bool_t rslt = FALSE; 538 RPCB parms; 539 char uidbuf[32]; 540 541 /* parameter checking */ 542 if (nconf == NULL) { 543 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 544 return (FALSE); 545 } 546 if (address == NULL) { 547 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 548 return (FALSE); 549 } 550 client = local_rpcb(); 551 if (! client) { 552 return (FALSE); 553 } 554 555 /* convert to universal */ 556 parms.r_addr = taddr2uaddr(__UNCONST(nconf), __UNCONST(address)); 557 if (!parms.r_addr) { 558 CLNT_DESTROY(client); 559 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 560 return (FALSE); /* no universal address */ 561 } 562 parms.r_prog = program; 563 parms.r_vers = version; 564 parms.r_netid = nconf->nc_netid; 565 /* 566 * Though uid is not being used directly, we still send it for 567 * completeness. For non-unix platforms, perhaps some other 568 * string or an empty string can be sent. 569 */ 570 (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); 571 parms.r_owner = uidbuf; 572 573 if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb, 574 (char *)(void *)&parms, (xdrproc_t) xdr_bool, 575 (char *)(void *)&rslt, tottimeout) != RPC_SUCCESS) { 576 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 577 clnt_geterr(client, &rpc_createerr.cf_error); 578 } 579 580 CLNT_DESTROY(client); 581 free(parms.r_addr); 582 return (rslt); 583} 584 585/* 586 * Remove the mapping between program, version and netbuf address. 587 * Calls the rpcbind service to do the un-mapping. 588 * If netbuf is NULL, unset for all the transports, otherwise unset 589 * only for the given transport. 590 */ 591bool_t 592rpcb_unset(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf) 593{ 594 CLIENT *client; 595 bool_t rslt = FALSE; 596 RPCB parms; 597 char uidbuf[32]; 598 599 client = local_rpcb(); 600 if (! client) { 601 return (FALSE); 602 } 603 604 parms.r_prog = program; 605 parms.r_vers = version; 606 if (nconf) 607 parms.r_netid = nconf->nc_netid; 608 else { 609 parms.r_netid = __UNCONST(&nullstring[0]); /* unsets all */ 610 } 611 parms.r_addr = __UNCONST(&nullstring[0]); 612 (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); 613 parms.r_owner = uidbuf; 614 615 if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb, 616 (char *)(void *)&parms, (xdrproc_t) xdr_bool, 617 (char *)(void *)&rslt, tottimeout) != RPC_SUCCESS) { 618 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 619 clnt_geterr(client, &rpc_createerr.cf_error); 620 } 621 622 CLNT_DESTROY(client); 623 return (rslt); 624} 625 626/* 627 * From the merged list, find the appropriate entry 628 */ 629static struct netbuf * 630got_entry(rpcb_entry_list_ptr relp, const struct netconfig *nconf) 631{ 632 struct netbuf *na = NULL; 633 rpcb_entry_list_ptr sp; 634 rpcb_entry *rmap; 635 636 _DIAGASSERT(nconf != NULL); 637 638 for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) { 639 rmap = &sp->rpcb_entry_map; 640 if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) && 641 (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) && 642 (nconf->nc_semantics == rmap->r_nc_semantics) && 643 (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) { 644 na = uaddr2taddr(nconf, rmap->r_maddr); 645#ifdef ND_DEBUG 646 fprintf(stderr, "\tRemote address is [%s].\n", 647 rmap->r_maddr); 648 if (!na) 649 fprintf(stderr, 650 "\tCouldn't resolve remote address!\n"); 651#endif 652 break; 653 } 654 } 655 return (na); 656} 657 658/* 659 * An internal function which optimizes rpcb_getaddr function. It also 660 * returns the client handle that it uses to contact the remote rpcbind. 661 * 662 * The algorithm used: If the transports is TCP or UDP, it first tries 663 * version 2 (portmap), 4 and then 3 (svr4). This order should be 664 * changed in the next OS release to 4, 2 and 3. We are assuming that by 665 * that time, version 4 would be available on many machines on the network. 666 * With this algorithm, we get performance as well as a plan for 667 * obsoleting version 2. 668 * 669 * For all other transports, the algorithm remains as 4 and then 3. 670 * 671 * XXX: Due to some problems with t_connect(), we do not reuse the same client 672 * handle for COTS cases and hence in these cases we do not return the 673 * client handle. This code will change if t_connect() ever 674 * starts working properly. Also look under clnt_vc.c. 675 */ 676struct netbuf * 677__rpcb_findaddr(rpcprog_t program, rpcvers_t version, 678 const struct netconfig *nconf, const char *host, CLIENT **clpp) 679{ 680 CLIENT *client = NULL; 681 RPCB parms; 682 enum clnt_stat clnt_st; 683 char *ua = NULL; 684 rpcvers_t vers; 685 struct netbuf *address = NULL; 686 rpcvers_t start_vers = RPCBVERS4; 687 struct netbuf servaddr; 688 689 /* nconf is handled below */ 690 _DIAGASSERT(host != NULL); 691 /* clpp may be NULL */ 692 693 /* parameter checking */ 694 if (nconf == NULL) { 695 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 696 return (NULL); 697 } 698 699 parms.r_addr = NULL; 700 701#ifdef PORTMAP 702 /* Try version 2 for TCP or UDP */ 703 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 704 u_short port = 0; 705 struct netbuf remote; 706 rpcvers_t pmapvers = 2; 707 struct pmap pmapparms; 708 709 /* 710 * Try UDP only - there are some portmappers out 711 * there that use UDP only. 712 */ 713 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 714 struct netconfig *newnconf; 715 716 if ((newnconf = getnetconfigent("udp")) == NULL) { 717 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 718 return (NULL); 719 } 720 client = getclnthandle(host, newnconf, &parms.r_addr); 721 freenetconfigent(newnconf); 722 } else { 723 client = getclnthandle(host, nconf, &parms.r_addr); 724 } 725 if (client == NULL) { 726 return (NULL); 727 } 728 729 /* Set the version */ 730 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&pmapvers); 731 pmapparms.pm_prog = program; 732 pmapparms.pm_vers = version; 733 pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? 734 IPPROTO_UDP : IPPROTO_TCP; 735 pmapparms.pm_port = 0; /* not needed */ 736 clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, 737 (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, 738 (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, 739 tottimeout); 740 if (clnt_st != RPC_SUCCESS) { 741 if ((clnt_st == RPC_PROGVERSMISMATCH) || 742 (clnt_st == RPC_PROGUNAVAIL)) 743 goto try_rpcbind; /* Try different versions */ 744 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 745 clnt_geterr(client, &rpc_createerr.cf_error); 746 goto error; 747 } else if (port == 0) { 748 address = NULL; 749 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 750 goto error; 751 } 752 port = htons(port); 753 CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)(void *)&remote); 754 if (((address = malloc(sizeof(struct netbuf))) == NULL) || 755 ((address->buf = malloc(remote.len)) == NULL)) { 756 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 757 clnt_geterr(client, &rpc_createerr.cf_error); 758 if (address) { 759 free(address); 760 address = NULL; 761 } 762 goto error; 763 } 764 memcpy(address->buf, remote.buf, remote.len); 765 memcpy(&((char *)address->buf)[sizeof (short)], 766 (char *)(void *)&port, sizeof (short)); 767 address->len = address->maxlen = remote.len; 768 goto done; 769 } 770#endif 771 772try_rpcbind: 773 /* 774 * Now we try version 4 and then 3. 775 * We also send the remote system the address we used to 776 * contact it in case it can help to connect back with us 777 */ 778 parms.r_prog = program; 779 parms.r_vers = version; 780 parms.r_owner = __UNCONST(&nullstring[0]); /* not needed; */ 781 /* just for xdring */ 782 parms.r_netid = nconf->nc_netid; /* not really needed */ 783 784 /* 785 * If a COTS transport is being used, try getting address via CLTS 786 * transport. This works only with version 4. 787 * NOTE: This is being done for all transports EXCEPT LOOPBACK 788 * because with loopback the cost to go to a COTS is same as 789 * the cost to go through CLTS, plus you get the advantage of 790 * finding out immediately if the local rpcbind process is dead. 791 */ 792#if 1 793 if ((nconf->nc_semantics == NC_TPI_COTS_ORD || 794 nconf->nc_semantics == NC_TPI_COTS) && 795 (strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0)) 796#else 797 if (client != NULL) { 798 CLNT_DESTROY(client); 799 client = NULL; 800 } 801 if (nconf->nc_semantics == NC_TPI_CLTS) 802#endif 803 { 804 void *handle; 805 struct netconfig *nconf_clts; 806 rpcb_entry_list_ptr relp = NULL; 807 808 if (client == NULL) { 809 /* This did not go through the above PORTMAP/TCP code */ 810#if 1 811 if ((handle = __rpc_setconf("datagram_v")) != NULL) 812#else 813 if ((handle = __rpc_setconf("circuit_v")) != NULL) 814#endif 815 { 816 while ((nconf_clts = __rpc_getconf(handle)) 817 != NULL) { 818 if (strcmp(nconf_clts->nc_protofmly, 819 nconf->nc_protofmly) != 0) { 820 continue; 821 } 822 client = getclnthandle(host, nconf_clts, 823 &parms.r_addr); 824 break; 825 } 826 __rpc_endconf(handle); 827 } 828 if (client == NULL) 829 goto regular_rpcbind; /* Go the regular way */ 830 } else { 831 /* This is a UDP PORTMAP handle. Change to version 4 */ 832 vers = RPCBVERS4; 833 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 834 } 835 /* 836 * We also send the remote system the address we used to 837 * contact it in case it can help it connect back with us 838 */ 839 if (parms.r_addr == NULL) { 840 /* for XDRing */ 841 parms.r_addr = __UNCONST(&nullstring[0]); 842 } 843 clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, 844 (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 845 (xdrproc_t) xdr_rpcb_entry_list_ptr, 846 (char *)(void *)&relp, tottimeout); 847 if (clnt_st == RPC_SUCCESS) { 848 if ((address = got_entry(relp, nconf)) != NULL) { 849 xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 850 (char *)(void *)&relp); 851 CLNT_CONTROL(client, CLGET_SVC_ADDR, 852 (char *)(void *)&servaddr); 853 __rpc_fixup_addr(address, &servaddr); 854 goto done; 855 } 856 /* Entry not found for this transport */ 857 xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 858 (char *)(void *)&relp); 859 /* 860 * XXX: should have perhaps returned with error but 861 * since the remote machine might not always be able 862 * to send the address on all transports, we try the 863 * regular way with regular_rpcbind 864 */ 865 goto regular_rpcbind; 866 } else if ((clnt_st == RPC_PROGVERSMISMATCH) || 867 (clnt_st == RPC_PROGUNAVAIL)) { 868 start_vers = RPCBVERS; /* Try version 3 now */ 869 goto regular_rpcbind; /* Try different versions */ 870 } else { 871 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 872 clnt_geterr(client, &rpc_createerr.cf_error); 873 goto error; 874 } 875 } 876 877regular_rpcbind: 878 879 /* Now the same transport is to be used to get the address */ 880#if 1 881 if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || 882 (nconf->nc_semantics == NC_TPI_COTS))) 883#else 884 if (client && nconf->nc_semantics == NC_TPI_CLTS) 885#endif 886 { 887 /* A CLTS type of client - destroy it */ 888 CLNT_DESTROY(client); 889 client = NULL; 890 } 891 892 if (client == NULL) { 893 client = getclnthandle(host, nconf, &parms.r_addr); 894 if (client == NULL) { 895 goto error; 896 } 897 } 898 if (parms.r_addr == NULL) 899 parms.r_addr = __UNCONST(&nullstring[0]); 900 901 /* First try from start_vers and then version 3 (RPCBVERS) */ 902 for (vers = start_vers; vers >= RPCBVERS; vers--) { 903 /* Set the version */ 904 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 905 clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, 906 (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 907 (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, 908 tottimeout); 909 if (clnt_st == RPC_SUCCESS) { 910 if ((ua == NULL) || (ua[0] == 0)) { 911 /* address unknown */ 912 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 913 goto error; 914 } 915 address = uaddr2taddr(nconf, ua); 916#ifdef ND_DEBUG 917 fprintf(stderr, "\tRemote address is [%s]\n", ua); 918 if (!address) 919 fprintf(stderr, 920 "\tCouldn't resolve remote address!\n"); 921#endif 922 xdr_free((xdrproc_t)xdr_wrapstring, 923 (char *)(void *)&ua); 924 925 if (! address) { 926 /* We don't know about your universal address */ 927 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 928 goto error; 929 } 930 CLNT_CONTROL(client, CLGET_SVC_ADDR, 931 (char *)(void *)&servaddr); 932 __rpc_fixup_addr(address, &servaddr); 933 goto done; 934 } else if (clnt_st == RPC_PROGVERSMISMATCH) { 935 struct rpc_err rpcerr; 936 937 clnt_geterr(client, &rpcerr); 938 if (rpcerr.re_vers.low > RPCBVERS4) 939 goto error; /* a new version, can't handle */ 940 } else if (clnt_st != RPC_PROGUNAVAIL) { 941 /* Cant handle this error */ 942 rpc_createerr.cf_stat = clnt_st; 943 clnt_geterr(client, &rpc_createerr.cf_error); 944 goto error; 945 } 946 } 947 948error: 949 if (client) { 950 CLNT_DESTROY(client); 951 client = NULL; 952 } 953done: 954 if (nconf->nc_semantics != NC_TPI_CLTS) { 955 /* This client is the connectionless one */ 956 if (client) { 957 CLNT_DESTROY(client); 958 client = NULL; 959 } 960 } 961 if (clpp) { 962 *clpp = client; 963 } else if (client) { 964 CLNT_DESTROY(client); 965 } 966 return (address); 967} 968 969 970/* 971 * Find the mapped address for program, version. 972 * Calls the rpcbind service remotely to do the lookup. 973 * Uses the transport specified in nconf. 974 * Returns FALSE (0) if no map exists, else returns 1. 975 * 976 * Assuming that the address is all properly allocated 977 */ 978bool_t 979rpcb_getaddr(const rpcprog_t program, const rpcvers_t version, 980 const struct netconfig *nconf, struct netbuf *address, 981 const char *host) 982{ 983 struct netbuf *na; 984 985 _DIAGASSERT(address != NULL); 986 987 if ((na = __rpcb_findaddr(program, version, nconf, 988 host, NULL)) == NULL) 989 return (FALSE); 990 991 if (na->len > address->maxlen) { 992 /* Too long address */ 993 free(na->buf); 994 free(na); 995 rpc_createerr.cf_stat = RPC_FAILED; 996 return (FALSE); 997 } 998 memcpy(address->buf, na->buf, (size_t)na->len); 999 address->len = na->len; 1000 free(na->buf); 1001 free(na); 1002 return (TRUE); 1003} 1004 1005/* 1006 * Get a copy of the current maps. 1007 * Calls the rpcbind service remotely to get the maps. 1008 * 1009 * It returns only a list of the services 1010 * It returns NULL on failure. 1011 */ 1012rpcblist * 1013rpcb_getmaps(const struct netconfig *nconf, const char *host) 1014{ 1015 rpcblist_ptr head = NULL; 1016 CLIENT *client; 1017 enum clnt_stat clnt_st; 1018 rpcvers_t vers = 0; 1019 1020 client = getclnthandle(host, nconf, NULL); 1021 if (client == NULL) { 1022 return (head); 1023 } 1024 clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 1025 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 1026 (char *)(void *)&head, tottimeout); 1027 if (clnt_st == RPC_SUCCESS) 1028 goto done; 1029 1030 if ((clnt_st != RPC_PROGVERSMISMATCH) && 1031 (clnt_st != RPC_PROGUNAVAIL)) { 1032 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1033 clnt_geterr(client, &rpc_createerr.cf_error); 1034 goto done; 1035 } 1036 1037 /* fall back to earlier version */ 1038 CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 1039 if (vers == RPCBVERS4) { 1040 vers = RPCBVERS; 1041 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 1042 if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 1043 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 1044 (char *)(void *)&head, tottimeout) == RPC_SUCCESS) 1045 goto done; 1046 } 1047 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1048 clnt_geterr(client, &rpc_createerr.cf_error); 1049 1050done: 1051 CLNT_DESTROY(client); 1052 return (head); 1053} 1054 1055/* 1056 * rpcbinder remote-call-service interface. 1057 * This routine is used to call the rpcbind remote call service 1058 * which will look up a service program in the address maps, and then 1059 * remotely call that routine with the given parameters. This allows 1060 * programs to do a lookup and call in one step. 1061*/ 1062enum clnt_stat 1063rpcb_rmtcall( 1064 const struct netconfig *nconf, /* Netconfig structure */ 1065 const char *host, /* Remote host name */ 1066 rpcprog_t prog, 1067 rpcvers_t vers, 1068 rpcproc_t proc, /* Remote proc identifiers */ 1069 xdrproc_t xdrargs, 1070 const char *argsp, /* Argument */ 1071 xdrproc_t xdrres, /* XDR routines */ 1072 caddr_t resp, /* Result */ 1073 struct timeval tout, /* Timeout value for this call */ 1074 const struct netbuf *addr_ptr) /* Preallocated netbuf address */ 1075{ 1076 CLIENT *client; 1077 enum clnt_stat stat; 1078 struct r_rpcb_rmtcallargs a; 1079 struct r_rpcb_rmtcallres r; 1080 rpcvers_t rpcb_vers; 1081 1082 stat = RPC_FAILED; /* XXXGCC -Wuninitialized [dreamcast] */ 1083 1084 client = getclnthandle(host, nconf, NULL); 1085 if (client == NULL) { 1086 return (RPC_FAILED); 1087 } 1088 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, __UNCONST(&rmttimeout)); 1089 a.prog = prog; 1090 a.vers = vers; 1091 a.proc = proc; 1092 a.args.args_val = argsp; 1093 a.xdr_args = xdrargs; 1094 r.addr = NULL; 1095 r.results.results_val = resp; 1096 r.xdr_res = xdrres; 1097 1098 for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { 1099 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers); 1100 stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT, 1101 (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a, 1102 (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout); 1103 if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { 1104 struct netbuf *na; 1105 na = uaddr2taddr(__UNCONST(nconf), r.addr); 1106 if (!na) { 1107 stat = RPC_N2AXLATEFAILURE; 1108 ((struct netbuf *)__UNCONST(addr_ptr))->len = 0; 1109 goto error; 1110 } 1111 if (na->len > addr_ptr->maxlen) { 1112 /* Too long address */ 1113 stat = RPC_FAILED; /* XXX A better error no */ 1114 free(na->buf); 1115 free(na); 1116 ((struct netbuf *)__UNCONST(addr_ptr))->len = 0; 1117 goto error; 1118 } 1119 memcpy(addr_ptr->buf, na->buf, (size_t)na->len); 1120 ((struct netbuf *)__UNCONST(addr_ptr))->len = na->len; 1121 free(na->buf); 1122 free(na); 1123 break; 1124 } else if ((stat != RPC_PROGVERSMISMATCH) && 1125 (stat != RPC_PROGUNAVAIL)) { 1126 goto error; 1127 } 1128 } 1129error: 1130 CLNT_DESTROY(client); 1131 if (r.addr) 1132 xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr); 1133 return (stat); 1134} 1135 1136/* 1137 * Gets the time on the remote host. 1138 * Returns 1 if succeeds else 0. 1139 */ 1140bool_t 1141rpcb_gettime(const char *host, time_t *timep) 1142{ 1143 CLIENT *client = NULL; 1144 void *handle; 1145 struct netconfig *nconf; 1146 rpcvers_t vers; 1147 enum clnt_stat st; 1148 1149 1150 if ((host == NULL) || (host[0] == 0)) { 1151 time(timep); 1152 return (TRUE); 1153 } 1154 1155 if ((handle = __rpc_setconf("netpath")) == NULL) { 1156 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1157 return (FALSE); 1158 } 1159 rpc_createerr.cf_stat = RPC_SUCCESS; 1160 while (client == NULL) { 1161 if ((nconf = __rpc_getconf(handle)) == NULL) { 1162 if (rpc_createerr.cf_stat == RPC_SUCCESS) 1163 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1164 break; 1165 } 1166 client = getclnthandle(host, nconf, NULL); 1167 if (client) 1168 break; 1169 } 1170 __rpc_endconf(handle); 1171 if (client == NULL) { 1172 return (FALSE); 1173 } 1174 1175 st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 1176 (xdrproc_t) xdr_void, NULL, 1177 (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); 1178 1179 if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { 1180 CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 1181 if (vers == RPCBVERS4) { 1182 /* fall back to earlier version */ 1183 vers = RPCBVERS; 1184 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 1185 st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 1186 (xdrproc_t) xdr_void, NULL, 1187 (xdrproc_t) xdr_int, (char *)(void *)timep, 1188 tottimeout); 1189 } 1190 } 1191 CLNT_DESTROY(client); 1192 return (st == RPC_SUCCESS? TRUE: FALSE); 1193} 1194 1195/* 1196 * Converts taddr to universal address. This routine should never 1197 * really be called because local n2a libraries are always provided. 1198 */ 1199char * 1200rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr) 1201{ 1202 CLIENT *client; 1203 char *uaddr = NULL; 1204 1205 /* parameter checking */ 1206 if (nconf == NULL) { 1207 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1208 return (NULL); 1209 } 1210 if (taddr == NULL) { 1211 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1212 return (NULL); 1213 } 1214 client = local_rpcb(); 1215 if (! client) { 1216 return (NULL); 1217 } 1218 1219 if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR, 1220 (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 1221 (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout) 1222 != RPC_SUCCESS) { 1223 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 1224 clnt_geterr(client, &rpc_createerr.cf_error); 1225 } 1226 CLNT_DESTROY(client); 1227 return (uaddr); 1228} 1229 1230/* 1231 * Converts universal address to netbuf. This routine should never 1232 * really be called because local n2a libraries are always provided. 1233 */ 1234struct netbuf * 1235rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr) 1236{ 1237 CLIENT *client; 1238 struct netbuf *taddr; 1239 1240 1241 /* parameter checking */ 1242 if (nconf == NULL) { 1243 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1244 return (NULL); 1245 } 1246 if (uaddr == NULL) { 1247 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1248 return (NULL); 1249 } 1250 client = local_rpcb(); 1251 if (! client) { 1252 return (NULL); 1253 } 1254 1255 taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf)); 1256 if (taddr == NULL) { 1257 CLNT_DESTROY(client); 1258 return (NULL); 1259 } 1260 if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR, 1261 (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, 1262 (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 1263 tottimeout) != RPC_SUCCESS) { 1264 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 1265 clnt_geterr(client, &rpc_createerr.cf_error); 1266 free(taddr); 1267 taddr = NULL; 1268 } 1269 CLNT_DESTROY(client); 1270 return (taddr); 1271} 1272