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