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 = check_cache(host, nconf->nc_netid); 308 if (ad_cache != NULL) { 309 addr = ad_cache->ac_taddr; 310 client = clnt_tli_create(RPC_ANYFD, nconf, addr, 311 (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); 312 if (client != NULL) { 313 if (targaddr) 314 *targaddr = strdup(ad_cache->ac_uaddr); 315 rwlock_unlock(&rpcbaddr_cache_lock); 316 return (client); 317 } 318 addr_to_delete.len = addr->len; 319 addr_to_delete.buf = (char *)malloc(addr->len); 320 if (addr_to_delete.buf == NULL) { 321 addr_to_delete.len = 0; 322 } else { 323 memcpy(addr_to_delete.buf, addr->buf, addr->len); 324 } 325 } 326 rwlock_unlock(&rpcbaddr_cache_lock); 327 if (addr_to_delete.len != 0) { 328 /* 329 * Assume this may be due to cache data being 330 * outdated 331 */ 332 rwlock_wrlock(&rpcbaddr_cache_lock); 333 delete_cache(&addr_to_delete); 334 rwlock_unlock(&rpcbaddr_cache_lock); 335 free(addr_to_delete.buf); 336 } 337 if (!__rpc_nconf2sockinfo(nconf, &si)) { 338 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 339 return NULL; 340 } 341 342 memset(&hints, 0, sizeof hints); 343 hints.ai_family = si.si_af; 344 hints.ai_socktype = si.si_socktype; 345 hints.ai_protocol = si.si_proto; 346 347 #ifdef CLNT_DEBUG 348 printf("trying netid %s family %d proto %d socktype %d\n", 349 nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype); 350 #endif 351 352 if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) { 353 rpc_createerr.cf_stat = RPC_UNKNOWNHOST; 354 return NULL; 355 } 356 357 for (tres = res; tres != NULL; tres = tres->ai_next) { 358 taddr.buf = tres->ai_addr; 359 taddr.len = taddr.maxlen = tres->ai_addrlen; 360 361 #ifdef ND_DEBUG 362 { 363 char *ua; 364 365 ua = taddr2uaddr(nconf, &taddr); 366 fprintf(stderr, "Got it [%s]\n", ua); 367 free(ua); 368 } 369 #endif 370 371 #ifdef ND_DEBUG 372 { 373 int i; 374 375 fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n", 376 taddr.len, taddr.maxlen); 377 fprintf(stderr, "\tAddress is "); 378 for (i = 0; i < taddr.len; i++) 379 fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]); 380 fprintf(stderr, "\n"); 381 } 382 #endif 383 client = clnt_tli_create(RPC_ANYFD, nconf, &taddr, 384 (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); 385 #ifdef ND_DEBUG 386 if (! client) { 387 clnt_pcreateerror("rpcbind clnt interface"); 388 } 389 #endif 390 391 if (client) { 392 tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL; 393 add_cache(host, nconf->nc_netid, &taddr, tmpaddr); 394 if (targaddr) 395 *targaddr = tmpaddr; 396 break; 397 } 398 } 399 freeaddrinfo(res); 400 return (client); 401 } 402 403 /* XXX */ 404 #define IN4_LOCALHOST_STRING "127.0.0.1" 405 #define IN6_LOCALHOST_STRING "::1" 406 407 /* 408 * This routine will return a client handle that is connected to the local 409 * rpcbind. Returns NULL on error and free's everything. 410 */ 411 static CLIENT * 412 local_rpcb() 413 { 414 CLIENT *client; 415 static struct netconfig *loopnconf; 416 static char *hostname; 417 extern mutex_t loopnconf_lock; 418 int sock; 419 size_t tsize; 420 struct netbuf nbuf; 421 struct sockaddr_un sun; 422 423 /* 424 * Try connecting to the local rpcbind through a local socket 425 * first. If this doesn't work, try all transports defined in 426 * the netconfig file. 427 */ 428 memset(&sun, 0, sizeof sun); 429 sock = _socket(AF_LOCAL, SOCK_STREAM, 0); 430 if (sock < 0) 431 goto try_nconf; 432 sun.sun_family = AF_LOCAL; 433 strcpy(sun.sun_path, _PATH_RPCBINDSOCK); 434 nbuf.len = sun.sun_len = SUN_LEN(&sun); 435 nbuf.maxlen = sizeof (struct sockaddr_un); 436 nbuf.buf = &sun; 437 438 tsize = __rpc_get_t_size(AF_LOCAL, 0, 0); 439 client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG, 440 (rpcvers_t)RPCBVERS, tsize, tsize); 441 442 if (client != NULL) 443 return client; 444 445 try_nconf: 446 447 /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */ 448 mutex_lock(&loopnconf_lock); 449 if (loopnconf == NULL) { 450 struct netconfig *nconf, *tmpnconf = NULL; 451 void *nc_handle; 452 int fd; 453 454 nc_handle = setnetconfig(); 455 if (nc_handle == NULL) { 456 /* fails to open netconfig file */ 457 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 458 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 459 mutex_unlock(&loopnconf_lock); 460 return (NULL); 461 } 462 while ((nconf = getnetconfig(nc_handle)) != NULL) { 463 #ifdef INET6 464 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 || 465 #else 466 if (( 467 #endif 468 strcmp(nconf->nc_protofmly, NC_INET) == 0) && 469 (nconf->nc_semantics == NC_TPI_COTS || 470 nconf->nc_semantics == NC_TPI_COTS_ORD)) { 471 fd = __rpc_nconf2fd(nconf); 472 /* 473 * Can't create a socket, assume that 474 * this family isn't configured in the kernel. 475 */ 476 if (fd < 0) 477 continue; 478 _close(fd); 479 tmpnconf = nconf; 480 if (!strcmp(nconf->nc_protofmly, NC_INET)) 481 hostname = IN4_LOCALHOST_STRING; 482 else 483 hostname = IN6_LOCALHOST_STRING; 484 } 485 } 486 if (tmpnconf == NULL) { 487 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 488 mutex_unlock(&loopnconf_lock); 489 return (NULL); 490 } 491 loopnconf = getnetconfigent(tmpnconf->nc_netid); 492 /* loopnconf is never freed */ 493 endnetconfig(nc_handle); 494 } 495 mutex_unlock(&loopnconf_lock); 496 client = getclnthandle(hostname, loopnconf, NULL); 497 return (client); 498 } 499 500 /* 501 * Set a mapping between program, version and address. 502 * Calls the rpcbind service to do the mapping. 503 */ 504 bool_t 505 rpcb_set(program, version, nconf, address) 506 rpcprog_t program; 507 rpcvers_t version; 508 const struct netconfig *nconf; /* Network structure of transport */ 509 const struct netbuf *address; /* Services netconfig address */ 510 { 511 CLIENT *client; 512 bool_t rslt = FALSE; 513 RPCB parms; 514 char uidbuf[32]; 515 516 /* parameter checking */ 517 if (nconf == NULL) { 518 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 519 return (FALSE); 520 } 521 if (address == NULL) { 522 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 523 return (FALSE); 524 } 525 client = local_rpcb(); 526 if (! client) { 527 return (FALSE); 528 } 529 530 /* convert to universal */ 531 /*LINTED const castaway*/ 532 parms.r_addr = taddr2uaddr((struct netconfig *) nconf, 533 (struct netbuf *)address); 534 if (!parms.r_addr) { 535 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 536 return (FALSE); /* no universal address */ 537 } 538 parms.r_prog = program; 539 parms.r_vers = version; 540 parms.r_netid = nconf->nc_netid; 541 /* 542 * Though uid is not being used directly, we still send it for 543 * completeness. For non-unix platforms, perhaps some other 544 * string or an empty string can be sent. 545 */ 546 (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); 547 parms.r_owner = uidbuf; 548 549 CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb, 550 (char *)(void *)&parms, (xdrproc_t) xdr_bool, 551 (char *)(void *)&rslt, tottimeout); 552 553 CLNT_DESTROY(client); 554 free(parms.r_addr); 555 return (rslt); 556 } 557 558 /* 559 * Remove the mapping between program, version and netbuf address. 560 * Calls the rpcbind service to do the un-mapping. 561 * If netbuf is NULL, unset for all the transports, otherwise unset 562 * only for the given transport. 563 */ 564 bool_t 565 rpcb_unset(program, version, nconf) 566 rpcprog_t program; 567 rpcvers_t version; 568 const struct netconfig *nconf; 569 { 570 CLIENT *client; 571 bool_t rslt = FALSE; 572 RPCB parms; 573 char uidbuf[32]; 574 575 client = local_rpcb(); 576 if (! client) { 577 return (FALSE); 578 } 579 580 parms.r_prog = program; 581 parms.r_vers = version; 582 if (nconf) 583 parms.r_netid = nconf->nc_netid; 584 else { 585 /*LINTED const castaway*/ 586 parms.r_netid = (char *) &nullstring[0]; /* unsets all */ 587 } 588 /*LINTED const castaway*/ 589 parms.r_addr = (char *) &nullstring[0]; 590 (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); 591 parms.r_owner = uidbuf; 592 593 CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb, 594 (char *)(void *)&parms, (xdrproc_t) xdr_bool, 595 (char *)(void *)&rslt, tottimeout); 596 597 CLNT_DESTROY(client); 598 return (rslt); 599 } 600 601 /* 602 * From the merged list, find the appropriate entry 603 */ 604 static struct netbuf * 605 got_entry(relp, nconf) 606 rpcb_entry_list_ptr relp; 607 const struct netconfig *nconf; 608 { 609 struct netbuf *na = NULL; 610 rpcb_entry_list_ptr sp; 611 rpcb_entry *rmap; 612 613 for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) { 614 rmap = &sp->rpcb_entry_map; 615 if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) && 616 (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) && 617 (nconf->nc_semantics == rmap->r_nc_semantics) && 618 (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != NULL)) { 619 na = uaddr2taddr(nconf, rmap->r_maddr); 620 #ifdef ND_DEBUG 621 fprintf(stderr, "\tRemote address is [%s].\n", 622 rmap->r_maddr); 623 if (!na) 624 fprintf(stderr, 625 "\tCouldn't resolve remote address!\n"); 626 #endif 627 break; 628 } 629 } 630 return (na); 631 } 632 633 /* 634 * An internal function which optimizes rpcb_getaddr function. It also 635 * returns the client handle that it uses to contact the remote rpcbind. 636 * 637 * The algorithm used: If the transports is TCP or UDP, it first tries 638 * version 2 (portmap), 4 and then 3 (svr4). This order should be 639 * changed in the next OS release to 4, 2 and 3. We are assuming that by 640 * that time, version 4 would be available on many machines on the network. 641 * With this algorithm, we get performance as well as a plan for 642 * obsoleting version 2. 643 * 644 * For all other transports, the algorithm remains as 4 and then 3. 645 * 646 * XXX: Due to some problems with t_connect(), we do not reuse the same client 647 * handle for COTS cases and hence in these cases we do not return the 648 * client handle. This code will change if t_connect() ever 649 * starts working properly. Also look under clnt_vc.c. 650 */ 651 struct netbuf * 652 __rpcb_findaddr(program, version, nconf, host, clpp) 653 rpcprog_t program; 654 rpcvers_t version; 655 const struct netconfig *nconf; 656 const char *host; 657 CLIENT **clpp; 658 { 659 CLIENT *client = NULL; 660 RPCB parms; 661 enum clnt_stat clnt_st; 662 char *ua = NULL; 663 rpcvers_t vers; 664 struct netbuf *address = NULL; 665 rpcvers_t start_vers = RPCBVERS4; 666 struct netbuf servaddr; 667 668 /* parameter checking */ 669 if (nconf == NULL) { 670 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 671 return (NULL); 672 } 673 674 parms.r_addr = NULL; 675 676 #ifdef PORTMAP 677 /* Try version 2 for TCP or UDP */ 678 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 679 u_short port = 0; 680 struct netbuf remote; 681 rpcvers_t pmapvers = 2; 682 struct pmap pmapparms; 683 684 /* 685 * Try UDP only - there are some portmappers out 686 * there that use UDP only. 687 */ 688 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 689 struct netconfig *newnconf; 690 691 if ((newnconf = getnetconfigent("udp")) == NULL) { 692 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 693 return (NULL); 694 } 695 client = getclnthandle(host, newnconf, &parms.r_addr); 696 freenetconfigent(newnconf); 697 } else { 698 client = getclnthandle(host, nconf, &parms.r_addr); 699 } 700 if (client == NULL) { 701 return (NULL); 702 } 703 704 /* Set the version */ 705 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&pmapvers); 706 pmapparms.pm_prog = program; 707 pmapparms.pm_vers = version; 708 pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? 709 IPPROTO_UDP : IPPROTO_TCP; 710 pmapparms.pm_port = 0; /* not needed */ 711 clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, 712 (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, 713 (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, 714 tottimeout); 715 if (clnt_st != RPC_SUCCESS) { 716 if ((clnt_st == RPC_PROGVERSMISMATCH) || 717 (clnt_st == RPC_PROGUNAVAIL)) 718 goto try_rpcbind; /* Try different versions */ 719 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 720 clnt_geterr(client, &rpc_createerr.cf_error); 721 goto error; 722 } else if (port == 0) { 723 address = NULL; 724 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 725 goto error; 726 } 727 port = htons(port); 728 CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)(void *)&remote); 729 if (((address = (struct netbuf *) 730 malloc(sizeof (struct netbuf))) == NULL) || 731 ((address->buf = (char *) 732 malloc(remote.len)) == NULL)) { 733 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 734 clnt_geterr(client, &rpc_createerr.cf_error); 735 if (address) { 736 free(address); 737 address = NULL; 738 } 739 goto error; 740 } 741 memcpy(address->buf, remote.buf, remote.len); 742 memcpy(&((char *)address->buf)[sizeof (short)], 743 (char *)(void *)&port, sizeof (short)); 744 address->len = address->maxlen = remote.len; 745 goto done; 746 } 747 #endif /* PORTMAP */ 748 749 try_rpcbind: 750 /* 751 * Now we try version 4 and then 3. 752 * We also send the remote system the address we used to 753 * contact it in case it can help to connect back with us 754 */ 755 parms.r_prog = program; 756 parms.r_vers = version; 757 /*LINTED const castaway*/ 758 parms.r_owner = (char *) &nullstring[0]; /* not needed; */ 759 /* just for xdring */ 760 parms.r_netid = nconf->nc_netid; /* not really needed */ 761 762 /* 763 * If a COTS transport is being used, try getting address via CLTS 764 * transport. This works only with version 4. 765 * NOTE: This is being done for all transports EXCEPT LOOPBACK 766 * because with loopback the cost to go to a COTS is same as 767 * the cost to go through CLTS, plus you get the advantage of 768 * finding out immediately if the local rpcbind process is dead. 769 */ 770 #if 1 771 if ((nconf->nc_semantics == NC_TPI_COTS_ORD || 772 nconf->nc_semantics == NC_TPI_COTS) && 773 (strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0)) { 774 #else 775 if (client != NULL) { 776 CLNT_DESTROY(client); 777 client = NULL; 778 } 779 if (nconf->nc_semantics == NC_TPI_CLTS) { 780 #endif 781 void *handle; 782 struct netconfig *nconf_clts; 783 rpcb_entry_list_ptr relp = NULL; 784 785 if (client == NULL) { 786 /* This did not go through the above PORTMAP/TCP code */ 787 #if 1 788 if ((handle = __rpc_setconf("datagram_v")) != NULL) { 789 #else 790 if ((handle = __rpc_setconf("circuit_v")) != NULL) { 791 #endif 792 while ((nconf_clts = __rpc_getconf(handle)) 793 != NULL) { 794 if (strcmp(nconf_clts->nc_protofmly, 795 nconf->nc_protofmly) != 0) { 796 continue; 797 } 798 client = getclnthandle(host, nconf_clts, 799 &parms.r_addr); 800 break; 801 } 802 __rpc_endconf(handle); 803 } 804 if (client == NULL) 805 goto regular_rpcbind; /* Go the regular way */ 806 } else { 807 /* This is a UDP PORTMAP handle. Change to version 4 */ 808 vers = RPCBVERS4; 809 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 810 } 811 /* 812 * We also send the remote system the address we used to 813 * contact it in case it can help it connect back with us 814 */ 815 if (parms.r_addr == NULL) { 816 /*LINTED const castaway*/ 817 parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ 818 } 819 clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, 820 (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 821 (xdrproc_t) xdr_rpcb_entry_list_ptr, 822 (char *)(void *)&relp, tottimeout); 823 if (clnt_st == RPC_SUCCESS) { 824 if ((address = got_entry(relp, nconf)) != NULL) { 825 xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 826 (char *)(void *)&relp); 827 goto done; 828 } 829 /* Entry not found for this transport */ 830 xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 831 (char *)(void *)&relp); 832 /* 833 * XXX: should have perhaps returned with error but 834 * since the remote machine might not always be able 835 * to send the address on all transports, we try the 836 * regular way with regular_rpcbind 837 */ 838 goto regular_rpcbind; 839 } else if ((clnt_st == RPC_PROGVERSMISMATCH) || 840 (clnt_st == RPC_PROGUNAVAIL)) { 841 start_vers = RPCBVERS; /* Try version 3 now */ 842 goto regular_rpcbind; /* Try different versions */ 843 } else { 844 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 845 clnt_geterr(client, &rpc_createerr.cf_error); 846 goto error; 847 } 848 } 849 850 regular_rpcbind: 851 852 /* Now the same transport is to be used to get the address */ 853 #if 1 854 if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || 855 (nconf->nc_semantics == NC_TPI_COTS))) { 856 #else 857 if (client && nconf->nc_semantics == NC_TPI_CLTS) { 858 #endif 859 /* A CLTS type of client - destroy it */ 860 CLNT_DESTROY(client); 861 client = NULL; 862 } 863 864 if (client == NULL) { 865 client = getclnthandle(host, nconf, &parms.r_addr); 866 if (client == NULL) { 867 goto error; 868 } 869 } 870 if (parms.r_addr == NULL) { 871 /*LINTED const castaway*/ 872 parms.r_addr = (char *) &nullstring[0]; 873 } 874 875 /* First try from start_vers and then version 3 (RPCBVERS) */ 876 for (vers = start_vers; vers >= RPCBVERS; vers--) { 877 /* Set the version */ 878 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 879 clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, 880 (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 881 (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, 882 tottimeout); 883 if (clnt_st == RPC_SUCCESS) { 884 if ((ua == NULL) || (ua[0] == NULL)) { 885 /* address unknown */ 886 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 887 goto error; 888 } 889 address = uaddr2taddr(nconf, ua); 890 #ifdef ND_DEBUG 891 fprintf(stderr, "\tRemote address is [%s]\n", ua); 892 if (!address) 893 fprintf(stderr, 894 "\tCouldn't resolve remote address!\n"); 895 #endif 896 xdr_free((xdrproc_t)xdr_wrapstring, 897 (char *)(void *)&ua); 898 899 if (! address) { 900 /* We don't know about your universal address */ 901 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 902 goto error; 903 } 904 CLNT_CONTROL(client, CLGET_SVC_ADDR, 905 (char *)(void *)&servaddr); 906 __rpc_fixup_addr(address, &servaddr); 907 goto done; 908 } else if (clnt_st == RPC_PROGVERSMISMATCH) { 909 struct rpc_err rpcerr; 910 911 clnt_geterr(client, &rpcerr); 912 if (rpcerr.re_vers.low > RPCBVERS4) 913 goto error; /* a new version, can't handle */ 914 } else if (clnt_st != RPC_PROGUNAVAIL) { 915 /* Cant handle this error */ 916 rpc_createerr.cf_stat = clnt_st; 917 clnt_geterr(client, &rpc_createerr.cf_error); 918 goto error; 919 } 920 } 921 922 if ((address == NULL) || (address->len == 0)) { 923 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 924 clnt_geterr(client, &rpc_createerr.cf_error); 925 } 926 927 error: 928 if (client) { 929 CLNT_DESTROY(client); 930 client = NULL; 931 } 932 done: 933 if (nconf->nc_semantics != NC_TPI_CLTS) { 934 /* This client is the connectionless one */ 935 if (client) { 936 CLNT_DESTROY(client); 937 client = NULL; 938 } 939 } 940 if (clpp) { 941 *clpp = client; 942 } else if (client) { 943 CLNT_DESTROY(client); 944 } 945 if (parms.r_addr != NULL && parms.r_addr != nullstring) 946 free(parms.r_addr); 947 return (address); 948 } 949 950 951 /* 952 * Find the mapped address for program, version. 953 * Calls the rpcbind service remotely to do the lookup. 954 * Uses the transport specified in nconf. 955 * Returns FALSE (0) if no map exists, else returns 1. 956 * 957 * Assuming that the address is all properly allocated 958 */ 959 int 960 rpcb_getaddr(program, version, nconf, address, host) 961 rpcprog_t program; 962 rpcvers_t version; 963 const struct netconfig *nconf; 964 struct netbuf *address; 965 const char *host; 966 { 967 struct netbuf *na; 968 969 if ((na = __rpcb_findaddr(program, version, nconf, 970 host, (CLIENT **) NULL)) == NULL) 971 return (FALSE); 972 973 if (na->len > address->maxlen) { 974 /* Too long address */ 975 free(na->buf); 976 free(na); 977 rpc_createerr.cf_stat = RPC_FAILED; 978 return (FALSE); 979 } 980 memcpy(address->buf, na->buf, (size_t)na->len); 981 address->len = na->len; 982 free(na->buf); 983 free(na); 984 return (TRUE); 985 } 986 987 /* 988 * Get a copy of the current maps. 989 * Calls the rpcbind service remotely to get the maps. 990 * 991 * It returns only a list of the services 992 * It returns NULL on failure. 993 */ 994 rpcblist * 995 rpcb_getmaps(nconf, host) 996 const struct netconfig *nconf; 997 const char *host; 998 { 999 rpcblist_ptr head = NULL; 1000 CLIENT *client; 1001 enum clnt_stat clnt_st; 1002 rpcvers_t vers = 0; 1003 1004 client = getclnthandle(host, nconf, NULL); 1005 if (client == NULL) { 1006 return (head); 1007 } 1008 clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 1009 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 1010 (char *)(void *)&head, tottimeout); 1011 if (clnt_st == RPC_SUCCESS) 1012 goto done; 1013 1014 if ((clnt_st != RPC_PROGVERSMISMATCH) && 1015 (clnt_st != RPC_PROGUNAVAIL)) { 1016 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1017 clnt_geterr(client, &rpc_createerr.cf_error); 1018 goto done; 1019 } 1020 1021 /* fall back to earlier version */ 1022 CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 1023 if (vers == RPCBVERS4) { 1024 vers = RPCBVERS; 1025 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 1026 if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 1027 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 1028 (char *)(void *)&head, tottimeout) == RPC_SUCCESS) 1029 goto done; 1030 } 1031 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1032 clnt_geterr(client, &rpc_createerr.cf_error); 1033 1034 done: 1035 CLNT_DESTROY(client); 1036 return (head); 1037 } 1038 1039 /* 1040 * rpcbinder remote-call-service interface. 1041 * This routine is used to call the rpcbind remote call service 1042 * which will look up a service program in the address maps, and then 1043 * remotely call that routine with the given parameters. This allows 1044 * programs to do a lookup and call in one step. 1045 */ 1046 enum clnt_stat 1047 rpcb_rmtcall(nconf, host, prog, vers, proc, xdrargs, argsp, 1048 xdrres, resp, tout, addr_ptr) 1049 const struct netconfig *nconf; /* Netconfig structure */ 1050 const char *host; /* Remote host name */ 1051 rpcprog_t prog; 1052 rpcvers_t vers; 1053 rpcproc_t proc; /* Remote proc identifiers */ 1054 xdrproc_t xdrargs, xdrres; /* XDR routines */ 1055 caddr_t argsp, resp; /* Argument and Result */ 1056 struct timeval tout; /* Timeout value for this call */ 1057 const struct netbuf *addr_ptr; /* Preallocated netbuf address */ 1058 { 1059 CLIENT *client; 1060 enum clnt_stat stat; 1061 struct r_rpcb_rmtcallargs a; 1062 struct r_rpcb_rmtcallres r; 1063 rpcvers_t rpcb_vers; 1064 1065 stat = 0; 1066 client = getclnthandle(host, nconf, NULL); 1067 if (client == NULL) { 1068 return (RPC_FAILED); 1069 } 1070 /*LINTED const castaway*/ 1071 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout); 1072 a.prog = prog; 1073 a.vers = vers; 1074 a.proc = proc; 1075 a.args.args_val = argsp; 1076 a.xdr_args = xdrargs; 1077 r.addr = NULL; 1078 r.results.results_val = resp; 1079 r.xdr_res = xdrres; 1080 1081 for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { 1082 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers); 1083 stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT, 1084 (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a, 1085 (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout); 1086 if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { 1087 struct netbuf *na; 1088 /*LINTED const castaway*/ 1089 na = uaddr2taddr((struct netconfig *) nconf, r.addr); 1090 if (!na) { 1091 stat = RPC_N2AXLATEFAILURE; 1092 /*LINTED const castaway*/ 1093 ((struct netbuf *) addr_ptr)->len = 0; 1094 goto error; 1095 } 1096 if (na->len > addr_ptr->maxlen) { 1097 /* Too long address */ 1098 stat = RPC_FAILED; /* XXX A better error no */ 1099 free(na->buf); 1100 free(na); 1101 /*LINTED const castaway*/ 1102 ((struct netbuf *) addr_ptr)->len = 0; 1103 goto error; 1104 } 1105 memcpy(addr_ptr->buf, na->buf, (size_t)na->len); 1106 /*LINTED const castaway*/ 1107 ((struct netbuf *)addr_ptr)->len = na->len; 1108 free(na->buf); 1109 free(na); 1110 break; 1111 } else if ((stat != RPC_PROGVERSMISMATCH) && 1112 (stat != RPC_PROGUNAVAIL)) { 1113 goto error; 1114 } 1115 } 1116 error: 1117 CLNT_DESTROY(client); 1118 if (r.addr) 1119 xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr); 1120 return (stat); 1121 } 1122 1123 /* 1124 * Gets the time on the remote host. 1125 * Returns 1 if succeeds else 0. 1126 */ 1127 bool_t 1128 rpcb_gettime(host, timep) 1129 const char *host; 1130 time_t *timep; 1131 { 1132 CLIENT *client = NULL; 1133 void *handle; 1134 struct netconfig *nconf; 1135 rpcvers_t vers; 1136 enum clnt_stat st; 1137 1138 1139 if ((host == NULL) || (host[0] == NULL)) { 1140 time(timep); 1141 return (TRUE); 1142 } 1143 1144 if ((handle = __rpc_setconf("netpath")) == NULL) { 1145 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1146 return (FALSE); 1147 } 1148 rpc_createerr.cf_stat = RPC_SUCCESS; 1149 while (client == NULL) { 1150 if ((nconf = __rpc_getconf(handle)) == NULL) { 1151 if (rpc_createerr.cf_stat == RPC_SUCCESS) 1152 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1153 break; 1154 } 1155 client = getclnthandle(host, nconf, NULL); 1156 if (client) 1157 break; 1158 } 1159 __rpc_endconf(handle); 1160 if (client == (CLIENT *) NULL) { 1161 return (FALSE); 1162 } 1163 1164 st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 1165 (xdrproc_t) xdr_void, NULL, 1166 (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); 1167 1168 if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { 1169 CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 1170 if (vers == RPCBVERS4) { 1171 /* fall back to earlier version */ 1172 vers = RPCBVERS; 1173 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 1174 st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 1175 (xdrproc_t) xdr_void, NULL, 1176 (xdrproc_t) xdr_int, (char *)(void *)timep, 1177 tottimeout); 1178 } 1179 } 1180 CLNT_DESTROY(client); 1181 return (st == RPC_SUCCESS? TRUE: FALSE); 1182 } 1183 1184 /* 1185 * Converts taddr to universal address. This routine should never 1186 * really be called because local n2a libraries are always provided. 1187 */ 1188 char * 1189 rpcb_taddr2uaddr(nconf, taddr) 1190 struct netconfig *nconf; 1191 struct netbuf *taddr; 1192 { 1193 CLIENT *client; 1194 char *uaddr = NULL; 1195 1196 1197 /* parameter checking */ 1198 if (nconf == NULL) { 1199 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1200 return (NULL); 1201 } 1202 if (taddr == NULL) { 1203 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1204 return (NULL); 1205 } 1206 client = local_rpcb(); 1207 if (! client) { 1208 return (NULL); 1209 } 1210 1211 CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR, 1212 (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 1213 (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout); 1214 CLNT_DESTROY(client); 1215 return (uaddr); 1216 } 1217 1218 /* 1219 * Converts universal address to netbuf. This routine should never 1220 * really be called because local n2a libraries are always provided. 1221 */ 1222 struct netbuf * 1223 rpcb_uaddr2taddr(nconf, uaddr) 1224 struct netconfig *nconf; 1225 char *uaddr; 1226 { 1227 CLIENT *client; 1228 struct netbuf *taddr; 1229 1230 1231 /* parameter checking */ 1232 if (nconf == NULL) { 1233 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1234 return (NULL); 1235 } 1236 if (uaddr == NULL) { 1237 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1238 return (NULL); 1239 } 1240 client = local_rpcb(); 1241 if (! client) { 1242 return (NULL); 1243 } 1244 1245 taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf)); 1246 if (taddr == NULL) { 1247 CLNT_DESTROY(client); 1248 return (NULL); 1249 } 1250 if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR, 1251 (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, 1252 (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 1253 tottimeout) != RPC_SUCCESS) { 1254 free(taddr); 1255 taddr = NULL; 1256 } 1257 CLNT_DESTROY(client); 1258 return (taddr); 1259 } 1260