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