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