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