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