1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * Copyright 2014 Gary Mills 29 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30 * Use is subject to license terms. 31 */ 32 33 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 34 /* All Rights Reserved */ 35 /* 36 * Portions of this source code were derived from Berkeley 37 * 4.3 BSD under license from the Regents of the University of 38 * California. 39 */ 40 41 /* 42 * interface to rpcbind rpc service. 43 */ 44 45 #include "mt.h" 46 #include "rpc_mt.h" 47 #include <assert.h> 48 #include <rpc/rpc.h> 49 #include <rpc/rpcb_prot.h> 50 #include <netconfig.h> 51 #include <netdir.h> 52 #include <netdb.h> 53 #include <rpc/nettype.h> 54 #include <syslog.h> 55 #ifdef PORTMAP 56 #include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */ 57 #include <rpc/pmap_prot.h> 58 #endif 59 #include <errno.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 static struct timeval tottimeout = { 60, 0 }; 65 static const struct timeval rmttimeout = { 3, 0 }; 66 static struct timeval rpcbrmttime = { 15, 0 }; 67 68 extern bool_t xdr_wrapstring(XDR *, char **); 69 70 static const char nullstring[] = "\000"; 71 72 extern CLIENT *_clnt_tli_create_timed(int, const struct netconfig *, 73 struct netbuf *, rpcprog_t, rpcvers_t, uint_t, uint_t, 74 const struct timeval *); 75 76 static CLIENT *_getclnthandle_timed(char *, struct netconfig *, char **, 77 struct timeval *); 78 79 80 /* 81 * The life time of a cached entry should not exceed 5 minutes 82 * since automountd attempts an unmount every 5 minutes. 83 * It is arbitrarily set a little lower (3 min = 180 sec) 84 * to reduce the time during which an entry is stale. 85 */ 86 #define CACHE_TTL 180 87 #define CACHESIZE 6 88 89 struct address_cache { 90 char *ac_host; 91 char *ac_netid; 92 char *ac_uaddr; 93 struct netbuf *ac_taddr; 94 struct address_cache *ac_next; 95 time_t ac_maxtime; 96 }; 97 98 static struct address_cache *front; 99 static int cachesize; 100 101 extern int lowvers; 102 extern int authdes_cachesz; 103 /* 104 * This routine adjusts the timeout used for calls to the remote rpcbind. 105 * Also, this routine can be used to set the use of portmapper version 2 106 * only when doing rpc_broadcasts 107 * These are private routines that may not be provided in future releases. 108 */ 109 bool_t 110 __rpc_control(int request, void *info) 111 { 112 switch (request) { 113 case CLCR_GET_RPCB_TIMEOUT: 114 *(struct timeval *)info = tottimeout; 115 break; 116 case CLCR_SET_RPCB_TIMEOUT: 117 tottimeout = *(struct timeval *)info; 118 break; 119 case CLCR_GET_LOWVERS: 120 *(int *)info = lowvers; 121 break; 122 case CLCR_SET_LOWVERS: 123 lowvers = *(int *)info; 124 break; 125 case CLCR_GET_RPCB_RMTTIME: 126 *(struct timeval *)info = rpcbrmttime; 127 break; 128 case CLCR_SET_RPCB_RMTTIME: 129 rpcbrmttime = *(struct timeval *)info; 130 break; 131 case CLCR_GET_CRED_CACHE_SZ: 132 *(int *)info = authdes_cachesz; 133 break; 134 case CLCR_SET_CRED_CACHE_SZ: 135 authdes_cachesz = *(int *)info; 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(char *host, char *netid) 163 { 164 struct address_cache *cptr; 165 166 /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ 167 168 assert(RW_READ_HELD(&rpcbaddr_cache_lock)); 169 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { 170 if ((strcmp(cptr->ac_host, host) == 0) && 171 (strcmp(cptr->ac_netid, netid) == 0) && 172 (time(NULL) <= cptr->ac_maxtime)) { 173 return (cptr); 174 } 175 } 176 return (NULL); 177 } 178 179 static void 180 delete_cache(struct netbuf *addr) 181 { 182 struct address_cache *cptr, *prevptr = NULL; 183 184 /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ 185 assert(RW_WRITE_HELD(&rpcbaddr_cache_lock)); 186 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { 187 if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { 188 free(cptr->ac_host); 189 free(cptr->ac_netid); 190 free(cptr->ac_taddr->buf); 191 free(cptr->ac_taddr); 192 if (cptr->ac_uaddr) 193 free(cptr->ac_uaddr); 194 if (prevptr) 195 prevptr->ac_next = cptr->ac_next; 196 else 197 front = cptr->ac_next; 198 free(cptr); 199 cachesize--; 200 break; 201 } 202 prevptr = cptr; 203 } 204 } 205 206 static void 207 add_cache(char *host, char *netid, struct netbuf *taddr, char *uaddr) 208 { 209 struct address_cache *ad_cache, *cptr, *prevptr; 210 211 ad_cache = malloc(sizeof (struct address_cache)); 212 if (!ad_cache) { 213 goto memerr; 214 } 215 ad_cache->ac_maxtime = time(NULL) + CACHE_TTL; 216 ad_cache->ac_host = strdup(host); 217 ad_cache->ac_netid = strdup(netid); 218 ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL; 219 ad_cache->ac_taddr = malloc(sizeof (struct netbuf)); 220 if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr || 221 (uaddr && !ad_cache->ac_uaddr)) { 222 goto memerr1; 223 } 224 225 ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len; 226 ad_cache->ac_taddr->buf = malloc(taddr->len); 227 if (ad_cache->ac_taddr->buf == NULL) { 228 goto memerr1; 229 } 230 231 (void) memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len); 232 233 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ 234 235 (void) rw_wrlock(&rpcbaddr_cache_lock); 236 if (cachesize < CACHESIZE) { 237 ad_cache->ac_next = front; 238 front = ad_cache; 239 cachesize++; 240 } else { 241 /* Free the last entry */ 242 cptr = front; 243 prevptr = NULL; 244 while (cptr->ac_next) { 245 prevptr = cptr; 246 cptr = cptr->ac_next; 247 } 248 249 free(cptr->ac_host); 250 free(cptr->ac_netid); 251 free(cptr->ac_taddr->buf); 252 free(cptr->ac_taddr); 253 if (cptr->ac_uaddr) 254 free(cptr->ac_uaddr); 255 256 if (prevptr) { 257 prevptr->ac_next = NULL; 258 ad_cache->ac_next = front; 259 front = ad_cache; 260 } else { 261 front = ad_cache; 262 ad_cache->ac_next = NULL; 263 } 264 free(cptr); 265 } 266 (void) rw_unlock(&rpcbaddr_cache_lock); 267 return; 268 memerr1: 269 if (ad_cache->ac_host) 270 free(ad_cache->ac_host); 271 if (ad_cache->ac_netid) 272 free(ad_cache->ac_netid); 273 if (ad_cache->ac_uaddr) 274 free(ad_cache->ac_uaddr); 275 if (ad_cache->ac_taddr) 276 free(ad_cache->ac_taddr); 277 free(ad_cache); 278 memerr: 279 syslog(LOG_ERR, "add_cache : out of memory."); 280 } 281 282 /* 283 * This routine will return a client handle that is connected to the 284 * rpcbind. Returns NULL on error and free's everything. 285 */ 286 static CLIENT * 287 getclnthandle(char *host, struct netconfig *nconf, char **targaddr) 288 { 289 return (_getclnthandle_timed(host, nconf, targaddr, NULL)); 290 } 291 292 /* 293 * Same as getclnthandle() except it takes an extra timeout argument. 294 * This is for bug 4049792: clnt_create_timed does not timeout. 295 * 296 * If tp is NULL, use default timeout to get a client handle. 297 */ 298 static CLIENT * 299 _getclnthandle_timed(char *host, struct netconfig *nconf, char **targaddr, 300 struct timeval *tp) 301 { 302 CLIENT *client = NULL; 303 struct netbuf *addr; 304 struct netbuf addr_to_delete; 305 struct nd_addrlist *nas; 306 struct nd_hostserv rpcbind_hs; 307 struct address_cache *ad_cache; 308 char *tmpaddr; 309 int neterr; 310 int j; 311 312 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ 313 314 /* Get the address of the rpcbind. Check cache first */ 315 addr_to_delete.len = 0; 316 (void) rw_rdlock(&rpcbaddr_cache_lock); 317 ad_cache = check_cache(host, nconf->nc_netid); 318 if (ad_cache != NULL) { 319 addr = ad_cache->ac_taddr; 320 client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr, 321 RPCBPROG, RPCBVERS4, 0, 0, tp); 322 if (client != NULL) { 323 if (targaddr) { 324 /* 325 * case where a client handle is created 326 * without a targaddr and the handle is 327 * requested with a targaddr 328 */ 329 if (ad_cache->ac_uaddr != NULL) { 330 *targaddr = strdup(ad_cache->ac_uaddr); 331 if (*targaddr == NULL) { 332 syslog(LOG_ERR, 333 "_getclnthandle_timed: strdup " 334 "failed."); 335 rpc_createerr.cf_stat = 336 RPC_SYSTEMERROR; 337 (void) rw_unlock( 338 &rpcbaddr_cache_lock); 339 return (NULL); 340 } 341 } else { 342 *targaddr = NULL; 343 } 344 } 345 (void) rw_unlock(&rpcbaddr_cache_lock); 346 return (client); 347 } 348 if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) { 349 (void) rw_unlock(&rpcbaddr_cache_lock); 350 return (NULL); 351 } 352 addr_to_delete.len = addr->len; 353 addr_to_delete.buf = malloc(addr->len); 354 if (addr_to_delete.buf == NULL) { 355 addr_to_delete.len = 0; 356 } else { 357 (void) memcpy(addr_to_delete.buf, addr->buf, addr->len); 358 } 359 } 360 (void) rw_unlock(&rpcbaddr_cache_lock); 361 if (addr_to_delete.len != 0) { 362 /* 363 * Assume this may be due to cache data being 364 * outdated 365 */ 366 (void) rw_wrlock(&rpcbaddr_cache_lock); 367 delete_cache(&addr_to_delete); 368 (void) rw_unlock(&rpcbaddr_cache_lock); 369 free(addr_to_delete.buf); 370 } 371 rpcbind_hs.h_host = host; 372 rpcbind_hs.h_serv = "rpcbind"; 373 374 if ((neterr = netdir_getbyname(nconf, &rpcbind_hs, &nas)) != 0) { 375 if (neterr == ND_NOHOST) 376 rpc_createerr.cf_stat = RPC_UNKNOWNHOST; 377 else 378 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 379 return (NULL); 380 } 381 /* XXX nas should perhaps be cached for better performance */ 382 383 for (j = 0; j < nas->n_cnt; j++) { 384 addr = &(nas->n_addrs[j]); 385 client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr, RPCBPROG, 386 RPCBVERS4, 0, 0, tp); 387 if (client) 388 break; 389 } 390 391 if (client) { 392 tmpaddr = targaddr ? taddr2uaddr(nconf, addr) : NULL; 393 add_cache(host, nconf->nc_netid, addr, tmpaddr); 394 if (targaddr) { 395 *targaddr = tmpaddr; 396 } 397 } 398 netdir_free((char *)nas, ND_ADDRLIST); 399 return (client); 400 } 401 402 /* 403 * This routine will return a client handle that is connected to the local 404 * rpcbind. Returns NULL on error. 405 */ 406 static CLIENT * 407 local_rpcb(void) 408 { 409 static struct netconfig *loopnconf; 410 extern mutex_t loopnconf_lock; 411 412 /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */ 413 (void) mutex_lock(&loopnconf_lock); 414 if (loopnconf == NULL) { 415 struct netconfig *nconf, *tmpnconf = NULL; 416 void *nc_handle; 417 418 nc_handle = setnetconfig(); 419 if (nc_handle == NULL) { 420 /* fails to open netconfig file */ 421 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 422 (void) mutex_unlock(&loopnconf_lock); 423 return (NULL); 424 } 425 while (nconf = getnetconfig(nc_handle)) { 426 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 427 tmpnconf = nconf; 428 if (nconf->nc_semantics == NC_TPI_CLTS) 429 break; 430 } 431 } 432 if (tmpnconf == NULL) { 433 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 434 (void) mutex_unlock(&loopnconf_lock); 435 return (NULL); 436 } 437 loopnconf = getnetconfigent(tmpnconf->nc_netid); 438 /* loopnconf is never freed */ 439 (void) endnetconfig(nc_handle); 440 } 441 (void) mutex_unlock(&loopnconf_lock); 442 return (getclnthandle(HOST_SELF_CONNECT, loopnconf, NULL)); 443 } 444 445 /* 446 * Set a mapping between program, version and address. 447 * Calls the rpcbind service to do the mapping. 448 */ 449 bool_t 450 rpcb_set(const rpcprog_t program, const rpcvers_t version, 451 const struct netconfig *nconf, const struct netbuf *address) 452 { 453 CLIENT *client; 454 bool_t rslt = FALSE; 455 RPCB parms; 456 char uidbuf[32]; 457 458 /* parameter checking */ 459 if (nconf == NULL) { 460 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 461 return (FALSE); 462 } 463 if (address == NULL) { 464 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 465 return (FALSE); 466 } 467 client = local_rpcb(); 468 if (!client) 469 return (FALSE); 470 471 parms.r_addr = taddr2uaddr((struct netconfig *)nconf, 472 (struct netbuf *)address); /* convert to universal */ 473 if (!parms.r_addr) { 474 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 475 return (FALSE); /* no universal address */ 476 } 477 parms.r_prog = program; 478 parms.r_vers = version; 479 parms.r_netid = nconf->nc_netid; 480 /* 481 * Though uid is not being used directly, we still send it for 482 * completeness. For non-unix platforms, perhaps some other 483 * string or an empty string can be sent. 484 */ 485 (void) sprintf(uidbuf, "%d", (int)geteuid()); 486 parms.r_owner = uidbuf; 487 488 CLNT_CALL(client, RPCBPROC_SET, (xdrproc_t)xdr_rpcb, (char *)&parms, 489 (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout); 490 491 CLNT_DESTROY(client); 492 free(parms.r_addr); 493 return (rslt); 494 } 495 496 /* 497 * Remove the mapping between program, version and netbuf address. 498 * Calls the rpcbind service to do the un-mapping. 499 * If netbuf is NULL, unset for all the transports, otherwise unset 500 * only for the given transport. 501 */ 502 bool_t 503 rpcb_unset(const rpcprog_t program, const rpcvers_t version, 504 const struct netconfig *nconf) 505 { 506 CLIENT *client; 507 bool_t rslt = FALSE; 508 RPCB parms; 509 char uidbuf[32]; 510 511 client = local_rpcb(); 512 if (!client) 513 return (FALSE); 514 515 parms.r_prog = program; 516 parms.r_vers = version; 517 if (nconf) 518 parms.r_netid = nconf->nc_netid; 519 else 520 parms.r_netid = (char *)&nullstring[0]; /* unsets all */ 521 parms.r_addr = (char *)&nullstring[0]; 522 (void) sprintf(uidbuf, "%d", (int)geteuid()); 523 parms.r_owner = uidbuf; 524 525 CLNT_CALL(client, RPCBPROC_UNSET, (xdrproc_t)xdr_rpcb, (char *)&parms, 526 (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout); 527 528 CLNT_DESTROY(client); 529 return (rslt); 530 } 531 532 /* 533 * From the merged list, find the appropriate entry 534 */ 535 static struct netbuf * 536 got_entry(rpcb_entry_list_ptr relp, struct netconfig *nconf) 537 { 538 struct netbuf *na = NULL; 539 rpcb_entry_list_ptr sp; 540 rpcb_entry *rmap; 541 542 for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) { 543 rmap = &sp->rpcb_entry_map; 544 if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) && 545 (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) && 546 (nconf->nc_semantics == rmap->r_nc_semantics) && 547 (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) { 548 na = uaddr2taddr(nconf, rmap->r_maddr); 549 break; 550 } 551 } 552 return (na); 553 } 554 555 /* 556 * Quick check to see if rpcbind is up. Tries to connect over 557 * local transport. 558 */ 559 bool_t 560 __rpcbind_is_up(void) 561 { 562 struct netbuf *addr; 563 int fd; 564 struct t_call *sndcall; 565 struct netconfig *netconf; 566 bool_t res; 567 568 if ((fd = t_open("/dev/ticotsord", O_RDWR, NULL)) == -1) 569 return (TRUE); 570 571 if (t_bind(fd, NULL, NULL) == -1) { 572 (void) t_close(fd); 573 return (TRUE); 574 } 575 576 /* LINTED pointer cast */ 577 if ((sndcall = (struct t_call *)t_alloc(fd, T_CALL, 0)) == NULL) { 578 (void) t_close(fd); 579 return (TRUE); 580 } 581 582 if ((netconf = getnetconfigent("ticotsord")) == NULL) { 583 (void) t_free((char *)sndcall, T_CALL); 584 (void) t_close(fd); 585 return (FALSE); 586 } 587 addr = uaddr2taddr(netconf, "localhost.rpc"); 588 freenetconfigent(netconf); 589 if (addr == NULL || addr->buf == NULL) { 590 if (addr) 591 free(addr); 592 (void) t_free((char *)sndcall, T_CALL); 593 (void) t_close(fd); 594 return (FALSE); 595 } 596 sndcall->addr.maxlen = addr->maxlen; 597 sndcall->addr.len = addr->len; 598 sndcall->addr.buf = addr->buf; 599 600 if (t_connect(fd, sndcall, NULL) == -1) 601 res = FALSE; 602 else 603 res = TRUE; 604 605 sndcall->addr.maxlen = sndcall->addr.len = 0; 606 sndcall->addr.buf = NULL; 607 (void) t_free((char *)sndcall, T_CALL); 608 free(addr->buf); 609 free(addr); 610 (void) t_close(fd); 611 612 return (res); 613 } 614 615 616 /* 617 * An internal function which optimizes rpcb_getaddr function. It returns 618 * the universal address of the remote service or NULL. It also optionally 619 * returns the client handle that it uses to contact the remote rpcbind. 620 * The caller will re-purpose the client handle to contact the remote service. 621 * 622 * The algorithm used: First try version 4. Then try version 3 (svr4). 623 * Finally, if the transport is TCP or UDP, try version 2 (portmap). 624 * Version 4 is now available with all current systems on the network. 625 * With this algorithm, we get performance as well as a plan for 626 * obsoleting version 2. 627 * 628 * XXX: Due to some problems with t_connect(), we do not reuse the same client 629 * handle for COTS cases and hence in these cases we do not return the 630 * client handle. This code will change if t_connect() ever 631 * starts working properly. Also look under clnt_vc.c. 632 */ 633 struct netbuf * 634 __rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version, 635 struct netconfig *nconf, char *host, CLIENT **clpp, struct timeval *tp) 636 { 637 static bool_t check_rpcbind = TRUE; 638 CLIENT *client = NULL; 639 RPCB parms; 640 enum clnt_stat clnt_st; 641 char *ua = NULL; 642 uint_t vers; 643 struct netbuf *address = NULL; 644 void *handle; 645 rpcb_entry_list_ptr relp = NULL; 646 bool_t tmp_client = FALSE; 647 648 /* parameter checking */ 649 if (nconf == NULL) { 650 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 651 /* 652 * Setting rpc_createerr.cf_stat is sufficient. 653 * No details in rpc_createerr.cf_error needed. 654 */ 655 return (NULL); 656 } 657 658 parms.r_addr = NULL; 659 660 /* 661 * Use default total timeout if no timeout is specified. 662 */ 663 if (tp == NULL) 664 tp = &tottimeout; 665 666 /* 667 * Check if rpcbind is up. This prevents needless delays when 668 * accessing applications such as the keyserver while booting 669 * disklessly. 670 */ 671 if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 672 if (!__rpcbind_is_up()) { 673 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 674 rpc_createerr.cf_error.re_errno = 0; 675 rpc_createerr.cf_error.re_terrno = 0; 676 goto error; 677 } 678 check_rpcbind = FALSE; 679 } 680 681 /* 682 * First try version 4. 683 */ 684 parms.r_prog = program; 685 parms.r_vers = version; 686 parms.r_owner = (char *)&nullstring[0]; /* not needed; */ 687 /* just for xdring */ 688 parms.r_netid = nconf->nc_netid; /* not really needed */ 689 690 /* 691 * If a COTS transport is being used, try getting address via CLTS 692 * transport. This works only with version 4. 693 */ 694 if (nconf->nc_semantics == NC_TPI_COTS_ORD || 695 nconf->nc_semantics == NC_TPI_COTS) { 696 tmp_client = TRUE; 697 if ((handle = __rpc_setconf("datagram_v")) != NULL) { 698 struct netconfig *nconf_clts; 699 700 while ((nconf_clts = __rpc_getconf(handle)) != NULL) { 701 if (strcmp(nconf_clts->nc_protofmly, 702 nconf->nc_protofmly) != 0) { 703 continue; 704 } 705 /* 706 * Sets rpc_createerr.cf_error members 707 * on failure 708 */ 709 client = _getclnthandle_timed(host, nconf_clts, 710 &parms.r_addr, tp); 711 break; 712 } 713 __rpc_endconf(handle); 714 } 715 } else { 716 /* Sets rpc_createerr.cf_error members on failure */ 717 client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp); 718 } 719 720 if (client != NULL) { 721 722 /* Set rpcbind version 4 */ 723 vers = RPCBVERS4; 724 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers); 725 726 /* 727 * We also send the remote system the address we used to 728 * contact it in case it can help it connect back with us 729 */ 730 if (parms.r_addr == NULL) { 731 parms.r_addr = strdup(""); /* for XDRing */ 732 if (parms.r_addr == NULL) { 733 syslog(LOG_ERR, "__rpcb_findaddr_timed: " 734 "strdup failed."); 735 /* Construct a system error */ 736 rpc_createerr.cf_error.re_errno = errno; 737 rpc_createerr.cf_error.re_terrno = 0; 738 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 739 goto error; 740 } 741 } 742 743 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, 744 (char *)&rpcbrmttime); 745 746 /* Sets error structure members in client handle */ 747 clnt_st = CLNT_CALL(client, RPCBPROC_GETADDRLIST, 748 (xdrproc_t)xdr_rpcb, (char *)&parms, 749 (xdrproc_t)xdr_rpcb_entry_list_ptr, (char *)&relp, *tp); 750 751 switch (clnt_st) { 752 case RPC_SUCCESS: /* Call succeeded */ 753 address = got_entry(relp, nconf); 754 xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr, 755 (char *)&relp); 756 if (address != NULL) { 757 /* Program number and version number matched */ 758 goto done; 759 } 760 /* Program and version not found for this transport */ 761 /* 762 * XXX: should have returned with RPC_PROGUNAVAIL 763 * or perhaps RPC_PROGNOTREGISTERED error but 764 * since the remote machine might not always be able 765 * to send the address on all transports, we try the 766 * regular way with version 3, then 2 767 */ 768 /* Try the next version */ 769 break; 770 case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */ 771 clnt_geterr(client, &rpc_createerr.cf_error); 772 if (rpc_createerr.cf_error.re_vers.low > vers) { 773 rpc_createerr.cf_stat = clnt_st; 774 goto error; /* a new version, can't handle */ 775 } 776 /* Try the next version */ 777 break; 778 case RPC_PROCUNAVAIL: /* Procedure unavailable */ 779 case RPC_PROGUNAVAIL: /* Program not available */ 780 case RPC_TIMEDOUT: /* Call timed out */ 781 /* Try the next version */ 782 break; 783 default: 784 clnt_geterr(client, &rpc_createerr.cf_error); 785 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 786 goto error; 787 break; 788 } 789 790 } else { 791 792 /* No client */ 793 tmp_client = FALSE; 794 795 } /* End of version 4 */ 796 797 /* Destroy a temporary client */ 798 if (client != NULL && tmp_client) { 799 CLNT_DESTROY(client); 800 client = NULL; 801 free(parms.r_addr); 802 parms.r_addr = NULL; 803 } 804 tmp_client = FALSE; 805 806 /* 807 * Try version 3 808 */ 809 810 /* Now the same transport is to be used to get the address */ 811 if (client == NULL) { 812 /* Sets rpc_createerr.cf_error members on failure */ 813 client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp); 814 } 815 address = NULL; 816 if (client != NULL) { 817 if (parms.r_addr == NULL) { 818 parms.r_addr = strdup(""); /* for XDRing */ 819 if (parms.r_addr == NULL) { 820 syslog(LOG_ERR, "__rpcb_findaddr_timed: " 821 "strdup failed."); 822 /* Construct a system error */ 823 rpc_createerr.cf_error.re_errno = errno; 824 rpc_createerr.cf_error.re_terrno = 0; 825 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 826 goto error; 827 } 828 } 829 830 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, 831 (char *)&rpcbrmttime); 832 vers = RPCBVERS; /* Set the version */ 833 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers); 834 835 /* Sets error structure members in client handle */ 836 clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR, 837 (xdrproc_t)xdr_rpcb, (char *)&parms, 838 (xdrproc_t)xdr_wrapstring, (char *)&ua, *tp); 839 840 switch (clnt_st) { 841 case RPC_SUCCESS: /* Call succeeded */ 842 if (ua != NULL) { 843 if (ua[0] != '\0') { 844 address = uaddr2taddr(nconf, ua); 845 } 846 xdr_free((xdrproc_t)xdr_wrapstring, 847 (char *)&ua); 848 849 if (address != NULL) { 850 goto done; 851 } 852 /* NULL universal address */ 853 /* But client call was successful */ 854 clnt_geterr(client, &rpc_createerr.cf_error); 855 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 856 goto error; 857 } 858 #ifndef PORTMAP 859 clnt_geterr(client, &rpc_createerr.cf_error); 860 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 861 goto error; 862 #endif 863 /* Try the next version */ 864 break; 865 case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */ 866 clnt_geterr(client, &rpc_createerr.cf_error); 867 #ifdef PORTMAP 868 if (rpc_createerr.cf_error.re_vers.low > vers) { 869 rpc_createerr.cf_stat = clnt_st; 870 goto error; /* a new version, can't handle */ 871 } 872 #else 873 rpc_createerr.cf_stat = clnt_st; 874 goto error; 875 #endif 876 /* Try the next version */ 877 break; 878 #ifdef PORTMAP 879 case RPC_PROCUNAVAIL: /* Procedure unavailable */ 880 case RPC_PROGUNAVAIL: /* Program not available */ 881 case RPC_TIMEDOUT: /* Call timed out */ 882 /* Try the next version */ 883 break; 884 #endif 885 default: 886 clnt_geterr(client, &rpc_createerr.cf_error); 887 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 888 goto error; 889 break; 890 } 891 } /* End of version 3 */ 892 #ifndef PORTMAP 893 /* cf_error members set by creation failure */ 894 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 895 #endif 896 /* 897 * Try version 2 898 */ 899 900 #ifdef PORTMAP 901 /* Try version 2 for TCP or UDP */ 902 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 903 ushort_t port = 0; 904 struct netbuf remote; 905 uint_t pmapvers = 2; 906 struct pmap pmapparms; 907 908 /* 909 * Try UDP only - there are some portmappers out 910 * there that use UDP only. 911 */ 912 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 913 struct netconfig *newnconf; 914 915 if (client != NULL) { 916 CLNT_DESTROY(client); 917 client = NULL; 918 free(parms.r_addr); 919 parms.r_addr = NULL; 920 } 921 if ((handle = __rpc_setconf("udp")) == NULL) { 922 /* Construct an unknown protocol error */ 923 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 924 goto error; 925 } 926 927 /* 928 * The following to reinforce that you can 929 * only request for remote address through 930 * the same transport you are requesting. 931 * ie. requesting unversial address 932 * of IPv4 has to be carried through IPv4. 933 * Can't use IPv6 to send out the request. 934 * The mergeaddr in rpcbind can't handle 935 * this. 936 */ 937 for (;;) { 938 if ((newnconf = __rpc_getconf(handle)) 939 == NULL) { 940 __rpc_endconf(handle); 941 /* 942 * Construct an unknown protocol 943 * error 944 */ 945 rpc_createerr.cf_stat = 946 RPC_UNKNOWNPROTO; 947 goto error; 948 } 949 /* 950 * here check the protocol family to 951 * be consistent with the request one 952 */ 953 if (strcmp(newnconf->nc_protofmly, 954 nconf->nc_protofmly) == 0) 955 break; 956 } 957 958 /* Sets rpc_createerr.cf_error members on failure */ 959 client = _getclnthandle_timed(host, newnconf, 960 &parms.r_addr, tp); 961 __rpc_endconf(handle); 962 tmp_client = TRUE; 963 } 964 if (client == NULL) { 965 /* 966 * rpc_createerr. cf_error members were set by 967 * creation failure 968 */ 969 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 970 tmp_client = FALSE; 971 goto error; 972 } 973 974 /* 975 * Set version and retry timeout. 976 */ 977 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); 978 CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); 979 980 pmapparms.pm_prog = program; 981 pmapparms.pm_vers = version; 982 pmapparms.pm_prot = (strcmp(nconf->nc_proto, NC_TCP) != 0) ? 983 IPPROTO_UDP : IPPROTO_TCP; 984 pmapparms.pm_port = 0; /* not needed */ 985 986 /* Sets error structure members in client handle */ 987 clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT, 988 (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms, 989 (xdrproc_t)xdr_u_short, (caddr_t)&port, *tp); 990 991 if (clnt_st != RPC_SUCCESS) { 992 clnt_geterr(client, &rpc_createerr.cf_error); 993 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 994 goto error; 995 } else if (port == 0) { 996 /* Will be NULL universal address */ 997 /* But client call was successful */ 998 clnt_geterr(client, &rpc_createerr.cf_error); 999 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 1000 goto error; 1001 } 1002 port = htons(port); 1003 CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); 1004 if (((address = malloc(sizeof (struct netbuf))) == NULL) || 1005 ((address->buf = malloc(remote.len)) == NULL)) { 1006 /* Construct a system error */ 1007 rpc_createerr.cf_error.re_errno = errno; 1008 rpc_createerr.cf_error.re_terrno = 0; 1009 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 1010 free(address); 1011 address = NULL; 1012 goto error; 1013 } 1014 (void) memcpy(address->buf, remote.buf, remote.len); 1015 (void) memcpy(&address->buf[sizeof (short)], &port, 1016 sizeof (short)); 1017 address->len = address->maxlen = remote.len; 1018 goto done; 1019 } else { 1020 /* 1021 * This is not NC_INET. 1022 * Always an error for version 2. 1023 */ 1024 if (client != NULL && clnt_st != RPC_SUCCESS) { 1025 /* There is a client that failed */ 1026 clnt_geterr(client, &rpc_createerr.cf_error); 1027 rpc_createerr.cf_stat = clnt_st; 1028 } else { 1029 /* Something else */ 1030 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1031 /* 1032 * Setting rpc_createerr.cf_stat is sufficient. 1033 * No details in rpc_createerr.cf_error needed. 1034 */ 1035 } 1036 } 1037 #endif 1038 1039 error: 1040 /* Return NULL address and NULL client */ 1041 address = NULL; 1042 if (client != NULL) { 1043 CLNT_DESTROY(client); 1044 client = NULL; 1045 } 1046 1047 done: 1048 /* Return an address and optional client */ 1049 if (client != NULL && tmp_client) { 1050 /* This client is the temporary one */ 1051 CLNT_DESTROY(client); 1052 client = NULL; 1053 } 1054 if (clpp != NULL) { 1055 *clpp = client; 1056 } else if (client != NULL) { 1057 CLNT_DESTROY(client); 1058 } 1059 free(parms.r_addr); 1060 return (address); 1061 } 1062 1063 1064 /* 1065 * Find the mapped address for program, version. 1066 * Calls the rpcbind service remotely to do the lookup. 1067 * Uses the transport specified in nconf. 1068 * Returns FALSE (0) if no map exists, else returns 1. 1069 * 1070 * Assuming that the address is all properly allocated 1071 */ 1072 int 1073 rpcb_getaddr(const rpcprog_t program, const rpcvers_t version, 1074 const struct netconfig *nconf, struct netbuf *address, const char *host) 1075 { 1076 struct netbuf *na; 1077 1078 if ((na = __rpcb_findaddr_timed(program, version, 1079 (struct netconfig *)nconf, (char *)host, NULL, NULL)) == NULL) 1080 return (FALSE); 1081 1082 if (na->len > address->maxlen) { 1083 /* Too long address */ 1084 netdir_free((char *)na, ND_ADDR); 1085 rpc_createerr.cf_stat = RPC_FAILED; 1086 return (FALSE); 1087 } 1088 (void) memcpy(address->buf, na->buf, (int)na->len); 1089 address->len = na->len; 1090 netdir_free((char *)na, ND_ADDR); 1091 return (TRUE); 1092 } 1093 1094 /* 1095 * Get a copy of the current maps. 1096 * Calls the rpcbind service remotely to get the maps. 1097 * 1098 * It returns only a list of the services 1099 * It returns NULL on failure. 1100 */ 1101 rpcblist * 1102 rpcb_getmaps(const struct netconfig *nconf, const char *host) 1103 { 1104 rpcblist_ptr head = NULL; 1105 CLIENT *client; 1106 enum clnt_stat clnt_st; 1107 int vers = 0; 1108 1109 client = getclnthandle((char *)host, 1110 (struct netconfig *)nconf, NULL); 1111 if (client == NULL) 1112 return (NULL); 1113 1114 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, 1115 (xdrproc_t)xdr_void, NULL, 1116 (xdrproc_t)xdr_rpcblist_ptr, 1117 (char *)&head, tottimeout); 1118 if (clnt_st == RPC_SUCCESS) 1119 goto done; 1120 1121 if ((clnt_st != RPC_PROGVERSMISMATCH) && 1122 (clnt_st != RPC_PROGUNAVAIL)) { 1123 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1124 clnt_geterr(client, &rpc_createerr.cf_error); 1125 goto done; 1126 } 1127 1128 /* fall back to earlier version */ 1129 CLNT_CONTROL(client, CLGET_VERS, (char *)&vers); 1130 if (vers == RPCBVERS4) { 1131 vers = RPCBVERS; 1132 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers); 1133 if (CLNT_CALL(client, RPCBPROC_DUMP, 1134 (xdrproc_t)xdr_void, 1135 NULL, (xdrproc_t)xdr_rpcblist_ptr, 1136 (char *)&head, tottimeout) == RPC_SUCCESS) 1137 goto done; 1138 } 1139 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1140 clnt_geterr(client, &rpc_createerr.cf_error); 1141 1142 done: 1143 CLNT_DESTROY(client); 1144 return (head); 1145 } 1146 1147 /* 1148 * rpcbinder remote-call-service interface. 1149 * This routine is used to call the rpcbind remote call service 1150 * which will look up a service program in the address maps, and then 1151 * remotely call that routine with the given parameters. This allows 1152 * programs to do a lookup and call in one step. 1153 */ 1154 enum clnt_stat 1155 rpcb_rmtcall(const struct netconfig *nconf, const char *host, 1156 const rpcprog_t prog, const rpcvers_t vers, const rpcproc_t proc, 1157 const xdrproc_t xdrargs, const caddr_t argsp, const xdrproc_t xdrres, 1158 const caddr_t resp, const struct timeval tout, struct netbuf *addr_ptr) 1159 { 1160 CLIENT *client; 1161 enum clnt_stat stat; 1162 struct r_rpcb_rmtcallargs a; 1163 struct r_rpcb_rmtcallres r; 1164 int rpcb_vers; 1165 1166 client = getclnthandle((char *)host, (struct netconfig *)nconf, NULL); 1167 if (client == NULL) 1168 return (RPC_FAILED); 1169 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rmttimeout); 1170 a.prog = prog; 1171 a.vers = vers; 1172 a.proc = proc; 1173 a.args.args_val = argsp; 1174 a.xdr_args = xdrargs; 1175 r.addr = NULL; 1176 r.results.results_val = resp; 1177 r.xdr_res = xdrres; 1178 1179 for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { 1180 CLNT_CONTROL(client, CLSET_VERS, (char *)&rpcb_vers); 1181 stat = CLNT_CALL(client, RPCBPROC_CALLIT, 1182 (xdrproc_t)xdr_rpcb_rmtcallargs, (char *)&a, 1183 (xdrproc_t)xdr_rpcb_rmtcallres, (char *)&r, tout); 1184 if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { 1185 struct netbuf *na; 1186 1187 na = uaddr2taddr((struct netconfig *)nconf, r.addr); 1188 if (!na) { 1189 stat = RPC_N2AXLATEFAILURE; 1190 ((struct netbuf *)addr_ptr)->len = 0; 1191 goto error; 1192 } 1193 if (na->len > addr_ptr->maxlen) { 1194 /* Too long address */ 1195 stat = RPC_FAILED; /* XXX A better error no */ 1196 netdir_free((char *)na, ND_ADDR); 1197 ((struct netbuf *)addr_ptr)->len = 0; 1198 goto error; 1199 } 1200 (void) memcpy(addr_ptr->buf, na->buf, (int)na->len); 1201 ((struct netbuf *)addr_ptr)->len = na->len; 1202 netdir_free((char *)na, ND_ADDR); 1203 break; 1204 } 1205 if ((stat != RPC_PROGVERSMISMATCH) && 1206 (stat != RPC_PROGUNAVAIL)) 1207 goto error; 1208 } 1209 error: 1210 CLNT_DESTROY(client); 1211 if (r.addr) 1212 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&r.addr); 1213 return (stat); 1214 } 1215 1216 /* 1217 * Gets the time on the remote host. 1218 * Returns 1 if succeeds else 0. 1219 */ 1220 bool_t 1221 rpcb_gettime(const char *host, time_t *timep) 1222 { 1223 CLIENT *client = NULL; 1224 void *handle; 1225 struct netconfig *nconf; 1226 int vers; 1227 enum clnt_stat st; 1228 1229 if ((host == NULL) || (host[0] == '\0')) { 1230 (void) time(timep); 1231 return (TRUE); 1232 } 1233 1234 if ((handle = __rpc_setconf("netpath")) == NULL) { 1235 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1236 return (FALSE); 1237 } 1238 rpc_createerr.cf_stat = RPC_SUCCESS; 1239 while (client == NULL) { 1240 if ((nconf = __rpc_getconf(handle)) == NULL) { 1241 if (rpc_createerr.cf_stat == RPC_SUCCESS) 1242 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1243 break; 1244 } 1245 client = getclnthandle((char *)host, nconf, NULL); 1246 if (client) 1247 break; 1248 } 1249 __rpc_endconf(handle); 1250 if (client == NULL) 1251 return (FALSE); 1252 1253 st = CLNT_CALL(client, RPCBPROC_GETTIME, 1254 (xdrproc_t)xdr_void, NULL, 1255 (xdrproc_t)xdr_time_t, (char *)timep, tottimeout); 1256 1257 if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { 1258 CLNT_CONTROL(client, CLGET_VERS, (char *)&vers); 1259 if (vers == RPCBVERS4) { 1260 /* fall back to earlier version */ 1261 vers = RPCBVERS; 1262 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers); 1263 st = CLNT_CALL(client, RPCBPROC_GETTIME, 1264 (xdrproc_t)xdr_void, NULL, 1265 (xdrproc_t)xdr_time_t, (char *)timep, 1266 tottimeout); 1267 } 1268 } 1269 CLNT_DESTROY(client); 1270 return (st == RPC_SUCCESS? TRUE : FALSE); 1271 } 1272 1273 /* 1274 * Converts taddr to universal address. This routine should never 1275 * really be called because local n2a libraries are always provided. 1276 */ 1277 char * 1278 rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr) 1279 { 1280 CLIENT *client; 1281 char *uaddr = NULL; 1282 1283 /* parameter checking */ 1284 if (nconf == NULL) { 1285 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1286 return (NULL); 1287 } 1288 if (taddr == NULL) { 1289 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1290 return (NULL); 1291 } 1292 client = local_rpcb(); 1293 if (!client) 1294 return (NULL); 1295 1296 CLNT_CALL(client, RPCBPROC_TADDR2UADDR, (xdrproc_t)xdr_netbuf, 1297 (char *)taddr, (xdrproc_t)xdr_wrapstring, (char *)&uaddr, 1298 tottimeout); 1299 CLNT_DESTROY(client); 1300 return (uaddr); 1301 } 1302 1303 /* 1304 * Converts universal address to netbuf. This routine should never 1305 * really be called because local n2a libraries are always provided. 1306 */ 1307 struct netbuf * 1308 rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr) 1309 { 1310 CLIENT *client; 1311 struct netbuf *taddr; 1312 1313 /* parameter checking */ 1314 if (nconf == NULL) { 1315 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1316 return (NULL); 1317 } 1318 if (uaddr == NULL) { 1319 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1320 return (NULL); 1321 } 1322 client = local_rpcb(); 1323 if (!client) 1324 return (NULL); 1325 1326 taddr = calloc(1, sizeof (struct netbuf)); 1327 if (taddr == NULL) { 1328 CLNT_DESTROY(client); 1329 return (NULL); 1330 } 1331 1332 if (CLNT_CALL(client, RPCBPROC_UADDR2TADDR, (xdrproc_t)xdr_wrapstring, 1333 (char *)&uaddr, (xdrproc_t)xdr_netbuf, (char *)taddr, 1334 tottimeout) != RPC_SUCCESS) { 1335 free(taddr); 1336 taddr = NULL; 1337 } 1338 CLNT_DESTROY(client); 1339 return (taddr); 1340 } 1341