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