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