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