rpcb_clnt.c revision 99775
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(lint) && defined(SCCSIDS) 56static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro"; 57#endif 58#include <sys/cdefs.h> 59__FBSDID("$FreeBSD: head/lib/libc/rpc/rpcb_clnt.c 99775 2002-07-11 16:23:04Z alfred $"); 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 93static struct timeval tottimeout = { 60, 0 }; 94static const struct timeval rmttimeout = { 3, 0 }; 95static struct timeval rpcbrmttime = { 15, 0 }; 96 97extern bool_t xdr_wrapstring(XDR *, char **); 98 99static const char nullstring[] = "\000"; 100 101#define CACHESIZE 6 102 103struct 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 111static struct address_cache *front; 112static int cachesize; 113 114#define CLCR_GET_RPCB_TIMEOUT 1 115#define CLCR_SET_RPCB_TIMEOUT 2 116 117 118extern int __rpc_lowvers; 119 120static struct address_cache *check_cache(const char *, const char *); 121static void delete_cache(struct netbuf *); 122static void add_cache(const char *, const char *, struct netbuf *, char *); 123static CLIENT *getclnthandle(const char *, const struct netconfig *, char **); 124static CLIENT *local_rpcb(void); 125static 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 */ 133bool_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 */ 168extern 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 175static struct address_cache * 176check_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 196static void 197delete_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 223static void 224add_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 */ 301static CLIENT * 302getclnthandle(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 */ 445static CLIENT * 446local_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 485try_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 */ 544bool_t 545rpcb_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 */ 605bool_t 606rpcb_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 */ 645static struct netbuf * 646got_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] != NULL)) { 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 */ 678bool_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)){ 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 */ 733struct 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 void *handle; 781 782 if ((handle = getnetconfigent("udp")) == NULL) { 783 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 784 return (NULL); 785 } 786 if ((newnconf = __rpc_getconf(handle)) == NULL) { 787 __rpc_endconf(handle); 788 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 789 return (NULL); 790 } 791 client = getclnthandle(host, newnconf, &parms.r_addr); 792 __rpc_endconf(handle); 793 } else { 794 client = getclnthandle(host, nconf, &parms.r_addr); 795 } 796 if (client == NULL) 797 return (NULL); 798 799 /* 800 * Set version and retry timeout. 801 */ 802 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); 803 CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); 804 805 pmapparms.pm_prog = program; 806 pmapparms.pm_vers = version; 807 pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? 808 IPPROTO_UDP : IPPROTO_TCP; 809 pmapparms.pm_port = 0; /* not needed */ 810 clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, 811 (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, 812 (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, 813 *tp); 814 if (clnt_st != RPC_SUCCESS) { 815 if ((clnt_st == RPC_PROGVERSMISMATCH) || 816 (clnt_st == RPC_PROGUNAVAIL)) 817 goto try_rpcbind; /* Try different versions */ 818 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 819 clnt_geterr(client, &rpc_createerr.cf_error); 820 goto error; 821 } else if (port == 0) { 822 address = NULL; 823 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 824 goto error; 825 } 826 port = htons(port); 827 CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); 828 if (((address = (struct netbuf *) 829 malloc(sizeof (struct netbuf))) == NULL) || 830 ((address->buf = (char *) 831 malloc(remote.len)) == NULL)) { 832 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 833 clnt_geterr(client, &rpc_createerr.cf_error); 834 if (address) { 835 free(address); 836 address = NULL; 837 } 838 goto error; 839 } 840 memcpy(address->buf, remote.buf, remote.len); 841 memcpy(&((char *)address->buf)[sizeof (short)], 842 (char *)(void *)&port, sizeof (short)); 843 address->len = address->maxlen = remote.len; 844 goto done; 845 } 846#endif /* PORTMAP */ 847 848try_rpcbind: 849 /* 850 * Check if rpcbind is up. This prevents needless delays when 851 * accessing applications such as the keyserver while booting 852 * disklessly. 853 */ 854 if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 855 if (!__rpcbind_is_up()) { 856 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 857 rpc_createerr.cf_error.re_errno = 0; 858 goto error; 859 } 860 check_rpcbind = FALSE; 861 } 862 863 /* 864 * Now we try version 4 and then 3. 865 * We also send the remote system the address we used to 866 * contact it in case it can help to connect back with us 867 */ 868 parms.r_prog = program; 869 parms.r_vers = version; 870 /*LINTED const castaway*/ 871 parms.r_owner = (char *) &nullstring[0]; /* not needed; */ 872 /* just for xdring */ 873 parms.r_netid = nconf->nc_netid; /* not really needed */ 874 875 /* 876 * If a COTS transport is being used, try getting address via CLTS 877 * transport. This works only with version 4. 878 */ 879 if (nconf->nc_semantics == NC_TPI_COTS_ORD || 880 nconf->nc_semantics == NC_TPI_COTS) { 881 882 void *handle; 883 struct netconfig *nconf_clts; 884 rpcb_entry_list_ptr relp = NULL; 885 886 if (client == NULL) { 887 /* This did not go through the above PORTMAP/TCP code */ 888 if ((handle = __rpc_setconf("datagram_v")) != NULL) { 889 while ((nconf_clts = __rpc_getconf(handle)) 890 != NULL) { 891 if (strcmp(nconf_clts->nc_protofmly, 892 nconf->nc_protofmly) != 0) { 893 continue; 894 } 895 client = getclnthandle(host, nconf_clts, 896 &parms.r_addr); 897 break; 898 } 899 __rpc_endconf(handle); 900 } 901 if (client == NULL) 902 goto regular_rpcbind; /* Go the regular way */ 903 } else { 904 /* This is a UDP PORTMAP handle. Change to version 4 */ 905 vers = RPCBVERS4; 906 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 907 } 908 /* 909 * We also send the remote system the address we used to 910 * contact it in case it can help it connect back with us 911 */ 912 if (parms.r_addr == NULL) { 913 /*LINTED const castaway*/ 914 parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ 915 } 916 917 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); 918 919 clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, 920 (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 921 (xdrproc_t) xdr_rpcb_entry_list_ptr, 922 (char *)(void *)&relp, *tp); 923 if (clnt_st == RPC_SUCCESS) { 924 if ((address = got_entry(relp, nconf)) != NULL) { 925 xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 926 (char *)(void *)&relp); 927 goto done; 928 } 929 /* Entry not found for this transport */ 930 xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, 931 (char *)(void *)&relp); 932 /* 933 * XXX: should have perhaps returned with error but 934 * since the remote machine might not always be able 935 * to send the address on all transports, we try the 936 * regular way with regular_rpcbind 937 */ 938 goto regular_rpcbind; 939 } else if ((clnt_st == RPC_PROGVERSMISMATCH) || 940 (clnt_st == RPC_PROGUNAVAIL)) { 941 start_vers = RPCBVERS; /* Try version 3 now */ 942 goto regular_rpcbind; /* Try different versions */ 943 } else { 944 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 945 clnt_geterr(client, &rpc_createerr.cf_error); 946 goto error; 947 } 948 } 949 950regular_rpcbind: 951 952 /* Now the same transport is to be used to get the address */ 953 if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || 954 (nconf->nc_semantics == NC_TPI_COTS))) { 955 /* A CLTS type of client - destroy it */ 956 CLNT_DESTROY(client); 957 client = NULL; 958 } 959 960 if (client == NULL) { 961 client = getclnthandle(host, nconf, &parms.r_addr); 962 if (client == NULL) { 963 goto error; 964 } 965 } 966 if (parms.r_addr == NULL) { 967 /*LINTED const castaway*/ 968 parms.r_addr = (char *) &nullstring[0]; 969 } 970 971 /* First try from start_vers and then version 3 (RPCBVERS) */ 972 973 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); 974 for (vers = start_vers; vers >= RPCBVERS; vers--) { 975 /* Set the version */ 976 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 977 clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, 978 (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, 979 (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp); 980 if (clnt_st == RPC_SUCCESS) { 981 if ((ua == NULL) || (ua[0] == NULL)) { 982 /* address unknown */ 983 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 984 goto error; 985 } 986 address = uaddr2taddr(nconf, ua); 987#ifdef ND_DEBUG 988 fprintf(stderr, "\tRemote address is [%s]\n", ua); 989 if (!address) 990 fprintf(stderr, 991 "\tCouldn't resolve remote address!\n"); 992#endif 993 xdr_free((xdrproc_t)xdr_wrapstring, 994 (char *)(void *)&ua); 995 996 if (! address) { 997 /* We don't know about your universal address */ 998 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 999 goto error; 1000 } 1001 CLNT_CONTROL(client, CLGET_SVC_ADDR, 1002 (char *)(void *)&servaddr); 1003 __rpc_fixup_addr(address, &servaddr); 1004 goto done; 1005 } else if (clnt_st == RPC_PROGVERSMISMATCH) { 1006 struct rpc_err rpcerr; 1007 1008 clnt_geterr(client, &rpcerr); 1009 if (rpcerr.re_vers.low > RPCBVERS4) 1010 goto error; /* a new version, can't handle */ 1011 } else if (clnt_st != RPC_PROGUNAVAIL) { 1012 /* Cant handle this error */ 1013 rpc_createerr.cf_stat = clnt_st; 1014 clnt_geterr(client, &rpc_createerr.cf_error); 1015 goto error; 1016 } 1017 } 1018 1019 if ((address == NULL) || (address->len == 0)) { 1020 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 1021 clnt_geterr(client, &rpc_createerr.cf_error); 1022 } 1023 1024error: 1025 if (client) { 1026 CLNT_DESTROY(client); 1027 client = NULL; 1028 } 1029done: 1030 if (nconf->nc_semantics != NC_TPI_CLTS) { 1031 /* This client is the connectionless one */ 1032 if (client) { 1033 CLNT_DESTROY(client); 1034 client = NULL; 1035 } 1036 } 1037 if (clpp) { 1038 *clpp = client; 1039 } else if (client) { 1040 CLNT_DESTROY(client); 1041 } 1042 if (parms.r_addr != NULL && parms.r_addr != nullstring) 1043 free(parms.r_addr); 1044 return (address); 1045} 1046 1047 1048/* 1049 * Find the mapped address for program, version. 1050 * Calls the rpcbind service remotely to do the lookup. 1051 * Uses the transport specified in nconf. 1052 * Returns FALSE (0) if no map exists, else returns 1. 1053 * 1054 * Assuming that the address is all properly allocated 1055 */ 1056int 1057rpcb_getaddr(program, version, nconf, address, host) 1058 rpcprog_t program; 1059 rpcvers_t version; 1060 const struct netconfig *nconf; 1061 struct netbuf *address; 1062 const char *host; 1063{ 1064 struct netbuf *na; 1065 1066 if ((na = __rpcb_findaddr_timed(program, version, 1067 (struct netconfig *) nconf, (char *) host, 1068 (CLIENT **) NULL, (struct timeval *) NULL)) == NULL) 1069 return (FALSE); 1070 1071 if (na->len > address->maxlen) { 1072 /* Too long address */ 1073 free(na->buf); 1074 free(na); 1075 rpc_createerr.cf_stat = RPC_FAILED; 1076 return (FALSE); 1077 } 1078 memcpy(address->buf, na->buf, (size_t)na->len); 1079 address->len = na->len; 1080 free(na->buf); 1081 free(na); 1082 return (TRUE); 1083} 1084 1085/* 1086 * Get a copy of the current maps. 1087 * Calls the rpcbind service remotely to get the maps. 1088 * 1089 * It returns only a list of the services 1090 * It returns NULL on failure. 1091 */ 1092rpcblist * 1093rpcb_getmaps(nconf, host) 1094 const struct netconfig *nconf; 1095 const char *host; 1096{ 1097 rpcblist_ptr head = NULL; 1098 CLIENT *client; 1099 enum clnt_stat clnt_st; 1100 rpcvers_t vers = 0; 1101 1102 client = getclnthandle(host, nconf, NULL); 1103 if (client == NULL) { 1104 return (head); 1105 } 1106 clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 1107 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 1108 (char *)(void *)&head, tottimeout); 1109 if (clnt_st == RPC_SUCCESS) 1110 goto done; 1111 1112 if ((clnt_st != RPC_PROGVERSMISMATCH) && 1113 (clnt_st != RPC_PROGUNAVAIL)) { 1114 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1115 clnt_geterr(client, &rpc_createerr.cf_error); 1116 goto done; 1117 } 1118 1119 /* fall back to earlier version */ 1120 CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 1121 if (vers == RPCBVERS4) { 1122 vers = RPCBVERS; 1123 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 1124 if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, 1125 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, 1126 (char *)(void *)&head, tottimeout) == RPC_SUCCESS) 1127 goto done; 1128 } 1129 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1130 clnt_geterr(client, &rpc_createerr.cf_error); 1131 1132done: 1133 CLNT_DESTROY(client); 1134 return (head); 1135} 1136 1137/* 1138 * rpcbinder remote-call-service interface. 1139 * This routine is used to call the rpcbind remote call service 1140 * which will look up a service program in the address maps, and then 1141 * remotely call that routine with the given parameters. This allows 1142 * programs to do a lookup and call in one step. 1143*/ 1144enum clnt_stat 1145rpcb_rmtcall(nconf, host, prog, vers, proc, xdrargs, argsp, 1146 xdrres, resp, tout, addr_ptr) 1147 const struct netconfig *nconf; /* Netconfig structure */ 1148 const char *host; /* Remote host name */ 1149 rpcprog_t prog; 1150 rpcvers_t vers; 1151 rpcproc_t proc; /* Remote proc identifiers */ 1152 xdrproc_t xdrargs, xdrres; /* XDR routines */ 1153 caddr_t argsp, resp; /* Argument and Result */ 1154 struct timeval tout; /* Timeout value for this call */ 1155 const struct netbuf *addr_ptr; /* Preallocated netbuf address */ 1156{ 1157 CLIENT *client; 1158 enum clnt_stat stat; 1159 struct r_rpcb_rmtcallargs a; 1160 struct r_rpcb_rmtcallres r; 1161 rpcvers_t rpcb_vers; 1162 1163 stat = 0; 1164 client = getclnthandle(host, nconf, NULL); 1165 if (client == NULL) { 1166 return (RPC_FAILED); 1167 } 1168 /*LINTED const castaway*/ 1169 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout); 1170 a.prog = prog; 1171 a.vers = vers; 1172 a.proc = proc; 1173 a.args.args_val = argsp; 1174 a.xdr_args = xdrargs; 1175 r.addr = NULL; 1176 r.results.results_val = resp; 1177 r.xdr_res = xdrres; 1178 1179 for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { 1180 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers); 1181 stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT, 1182 (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a, 1183 (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout); 1184 if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { 1185 struct netbuf *na; 1186 /*LINTED const castaway*/ 1187 na = uaddr2taddr((struct netconfig *) nconf, r.addr); 1188 if (!na) { 1189 stat = RPC_N2AXLATEFAILURE; 1190 /*LINTED const castaway*/ 1191 ((struct netbuf *) addr_ptr)->len = 0; 1192 goto error; 1193 } 1194 if (na->len > addr_ptr->maxlen) { 1195 /* Too long address */ 1196 stat = RPC_FAILED; /* XXX A better error no */ 1197 free(na->buf); 1198 free(na); 1199 /*LINTED const castaway*/ 1200 ((struct netbuf *) addr_ptr)->len = 0; 1201 goto error; 1202 } 1203 memcpy(addr_ptr->buf, na->buf, (size_t)na->len); 1204 /*LINTED const castaway*/ 1205 ((struct netbuf *)addr_ptr)->len = na->len; 1206 free(na->buf); 1207 free(na); 1208 break; 1209 } else if ((stat != RPC_PROGVERSMISMATCH) && 1210 (stat != RPC_PROGUNAVAIL)) { 1211 goto error; 1212 } 1213 } 1214error: 1215 CLNT_DESTROY(client); 1216 if (r.addr) 1217 xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr); 1218 return (stat); 1219} 1220 1221/* 1222 * Gets the time on the remote host. 1223 * Returns 1 if succeeds else 0. 1224 */ 1225bool_t 1226rpcb_gettime(host, timep) 1227 const char *host; 1228 time_t *timep; 1229{ 1230 CLIENT *client = NULL; 1231 void *handle; 1232 struct netconfig *nconf; 1233 rpcvers_t vers; 1234 enum clnt_stat st; 1235 1236 1237 if ((host == NULL) || (host[0] == NULL)) { 1238 time(timep); 1239 return (TRUE); 1240 } 1241 1242 if ((handle = __rpc_setconf("netpath")) == NULL) { 1243 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1244 return (FALSE); 1245 } 1246 rpc_createerr.cf_stat = RPC_SUCCESS; 1247 while (client == NULL) { 1248 if ((nconf = __rpc_getconf(handle)) == NULL) { 1249 if (rpc_createerr.cf_stat == RPC_SUCCESS) 1250 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1251 break; 1252 } 1253 client = getclnthandle(host, nconf, NULL); 1254 if (client) 1255 break; 1256 } 1257 __rpc_endconf(handle); 1258 if (client == (CLIENT *) NULL) { 1259 return (FALSE); 1260 } 1261 1262 st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 1263 (xdrproc_t) xdr_void, NULL, 1264 (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); 1265 1266 if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { 1267 CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); 1268 if (vers == RPCBVERS4) { 1269 /* fall back to earlier version */ 1270 vers = RPCBVERS; 1271 CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); 1272 st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, 1273 (xdrproc_t) xdr_void, NULL, 1274 (xdrproc_t) xdr_int, (char *)(void *)timep, 1275 tottimeout); 1276 } 1277 } 1278 CLNT_DESTROY(client); 1279 return (st == RPC_SUCCESS? TRUE: FALSE); 1280} 1281 1282/* 1283 * Converts taddr to universal address. This routine should never 1284 * really be called because local n2a libraries are always provided. 1285 */ 1286char * 1287rpcb_taddr2uaddr(nconf, taddr) 1288 struct netconfig *nconf; 1289 struct netbuf *taddr; 1290{ 1291 CLIENT *client; 1292 char *uaddr = NULL; 1293 1294 1295 /* parameter checking */ 1296 if (nconf == NULL) { 1297 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1298 return (NULL); 1299 } 1300 if (taddr == NULL) { 1301 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1302 return (NULL); 1303 } 1304 client = local_rpcb(); 1305 if (! client) { 1306 return (NULL); 1307 } 1308 1309 CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR, 1310 (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 1311 (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout); 1312 CLNT_DESTROY(client); 1313 return (uaddr); 1314} 1315 1316/* 1317 * Converts universal address to netbuf. This routine should never 1318 * really be called because local n2a libraries are always provided. 1319 */ 1320struct netbuf * 1321rpcb_uaddr2taddr(nconf, uaddr) 1322 struct netconfig *nconf; 1323 char *uaddr; 1324{ 1325 CLIENT *client; 1326 struct netbuf *taddr; 1327 1328 1329 /* parameter checking */ 1330 if (nconf == NULL) { 1331 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1332 return (NULL); 1333 } 1334 if (uaddr == NULL) { 1335 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 1336 return (NULL); 1337 } 1338 client = local_rpcb(); 1339 if (! client) { 1340 return (NULL); 1341 } 1342 1343 taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf)); 1344 if (taddr == NULL) { 1345 CLNT_DESTROY(client); 1346 return (NULL); 1347 } 1348 if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR, 1349 (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, 1350 (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, 1351 tottimeout) != RPC_SUCCESS) { 1352 free(taddr); 1353 taddr = NULL; 1354 } 1355 CLNT_DESTROY(client); 1356 return (taddr); 1357} 1358