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