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