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