1 /* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (c) 2009, Sun Microsystems, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are met: 11 * - Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * - Neither the name of Sun Microsystems, Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 /* 33 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 34 */ 35 36 /* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 /* 41 * rpc_generic.c, Miscl routines for RPC. 42 * 43 */ 44 45 #include "namespace.h" 46 #include "reentrant.h" 47 #include <sys/param.h> 48 #include <sys/socket.h> 49 #include <sys/time.h> 50 #include <sys/un.h> 51 #include <sys/resource.h> 52 #include <netinet/in.h> 53 #include <arpa/inet.h> 54 #include <rpc/rpc.h> 55 #include <ctype.h> 56 #include <stddef.h> 57 #include <stdio.h> 58 #include <netdb.h> 59 #include <netconfig.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <syslog.h> 63 #include <rpc/nettype.h> 64 #include "un-namespace.h" 65 #include "rpc_com.h" 66 #include "mt_misc.h" 67 68 struct handle { 69 NCONF_HANDLE *nhandle; 70 int nflag; /* Whether NETPATH or NETCONFIG */ 71 int nettype; 72 }; 73 74 static const struct _rpcnettype { 75 const char *name; 76 const int type; 77 } _rpctypelist[] = { 78 { "netpath", _RPC_NETPATH }, 79 { "visible", _RPC_VISIBLE }, 80 { "circuit_v", _RPC_CIRCUIT_V }, 81 { "datagram_v", _RPC_DATAGRAM_V }, 82 { "circuit_n", _RPC_CIRCUIT_N }, 83 { "datagram_n", _RPC_DATAGRAM_N }, 84 { "tcp", _RPC_TCP }, 85 { "udp", _RPC_UDP }, 86 { 0, _RPC_NONE } 87 }; 88 89 struct netid_af { 90 const char *netid; 91 int af; 92 int protocol; 93 }; 94 95 static const struct netid_af na_cvt[] = { 96 { "udp", AF_INET, IPPROTO_UDP }, 97 { "tcp", AF_INET, IPPROTO_TCP }, 98 #ifdef INET6 99 { "udp6", AF_INET6, IPPROTO_UDP }, 100 { "tcp6", AF_INET6, IPPROTO_TCP }, 101 #endif 102 { "local", AF_LOCAL, 0 } 103 }; 104 105 #if 0 106 static char *strlocase(char *); 107 #endif 108 static int getnettype(const char *); 109 110 /* 111 * Cache the result of getrlimit(), so we don't have to do an 112 * expensive call every time. 113 */ 114 int 115 __rpc_dtbsize(void) 116 { 117 static int tbsize; 118 struct rlimit rl; 119 120 if (tbsize) { 121 return (tbsize); 122 } 123 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 124 return (tbsize = (int)rl.rlim_max); 125 } 126 /* 127 * Something wrong. I'll try to save face by returning a 128 * pessimistic number. 129 */ 130 return (32); 131 } 132 133 134 /* 135 * Find the appropriate buffer size 136 * 137 * size - Size requested 138 */ 139 u_int 140 /*ARGSUSED*/ 141 __rpc_get_t_size(int af, int proto, int size) 142 { 143 int maxsize, defsize; 144 145 maxsize = 256 * 1024; /* XXX */ 146 switch (proto) { 147 case IPPROTO_TCP: 148 defsize = 64 * 1024; /* XXX */ 149 break; 150 case IPPROTO_UDP: 151 defsize = UDPMSGSIZE; 152 break; 153 default: 154 defsize = RPC_MAXDATASIZE; 155 break; 156 } 157 if (size == 0) 158 return defsize; 159 160 /* Check whether the value is within the upper max limit */ 161 return (size > maxsize ? (u_int)maxsize : (u_int)size); 162 } 163 164 /* 165 * Find the appropriate address buffer size 166 */ 167 u_int 168 __rpc_get_a_size(int af) 169 { 170 switch (af) { 171 case AF_INET: 172 return sizeof (struct sockaddr_in); 173 #ifdef INET6 174 case AF_INET6: 175 return sizeof (struct sockaddr_in6); 176 #endif 177 case AF_LOCAL: 178 return sizeof (struct sockaddr_un); 179 default: 180 break; 181 } 182 return ((u_int)RPC_MAXADDRSIZE); 183 } 184 185 #if 0 186 static char * 187 strlocase(char *p) 188 { 189 char *t = p; 190 191 for (; *p; p++) 192 if (isupper(*p)) 193 *p = tolower(*p); 194 return (t); 195 } 196 #endif 197 198 /* 199 * Returns the type of the network as defined in <rpc/nettype.h> 200 * If nettype is NULL, it defaults to NETPATH. 201 */ 202 static int 203 getnettype(const char *nettype) 204 { 205 int i; 206 207 if ((nettype == NULL) || (nettype[0] == 0)) { 208 return (_RPC_NETPATH); /* Default */ 209 } 210 211 #if 0 212 nettype = strlocase(nettype); 213 #endif 214 for (i = 0; _rpctypelist[i].name; i++) 215 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 216 return (_rpctypelist[i].type); 217 } 218 return (_rpctypelist[i].type); 219 } 220 221 static thread_key_t tcp_key, udp_key; 222 static once_t keys_once = ONCE_INITIALIZER; 223 static int tcp_key_error, udp_key_error; 224 225 static void 226 keys_init(void) 227 { 228 229 tcp_key_error = thr_keycreate(&tcp_key, free); 230 udp_key_error = thr_keycreate(&udp_key, free); 231 } 232 233 /* 234 * For the given nettype (tcp or udp only), return the first structure found. 235 * This should be freed by calling freenetconfigent() 236 */ 237 struct netconfig * 238 __rpc_getconfip(const char *nettype) 239 { 240 char *netid; 241 char *netid_tcp = (char *) NULL; 242 char *netid_udp = (char *) NULL; 243 static char *netid_tcp_main; 244 static char *netid_udp_main; 245 struct netconfig *dummy; 246 int main_thread; 247 248 if ((main_thread = thr_main())) { 249 netid_udp = netid_udp_main; 250 netid_tcp = netid_tcp_main; 251 } else { 252 if (thr_once(&keys_once, keys_init) != 0 || 253 tcp_key_error != 0 || udp_key_error != 0) 254 return (NULL); 255 netid_tcp = (char *)thr_getspecific(tcp_key); 256 netid_udp = (char *)thr_getspecific(udp_key); 257 } 258 if (!netid_udp && !netid_tcp) { 259 struct netconfig *nconf; 260 void *confighandle; 261 262 if (!(confighandle = setnetconfig())) { 263 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 264 return (NULL); 265 } 266 while ((nconf = getnetconfig(confighandle)) != NULL) { 267 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 268 if (strcmp(nconf->nc_proto, NC_TCP) == 0 && 269 netid_tcp == NULL) { 270 netid_tcp = strdup(nconf->nc_netid); 271 if (main_thread) 272 netid_tcp_main = netid_tcp; 273 else 274 thr_setspecific(tcp_key, 275 (void *) netid_tcp); 276 } else 277 if (strcmp(nconf->nc_proto, NC_UDP) == 0 && 278 netid_udp == NULL) { 279 netid_udp = strdup(nconf->nc_netid); 280 if (main_thread) 281 netid_udp_main = netid_udp; 282 else 283 thr_setspecific(udp_key, 284 (void *) netid_udp); 285 } 286 } 287 } 288 endnetconfig(confighandle); 289 } 290 if (strcmp(nettype, "udp") == 0) 291 netid = netid_udp; 292 else if (strcmp(nettype, "tcp") == 0) 293 netid = netid_tcp; 294 else { 295 return (NULL); 296 } 297 if ((netid == NULL) || (netid[0] == 0)) { 298 return (NULL); 299 } 300 dummy = getnetconfigent(netid); 301 return (dummy); 302 } 303 304 /* 305 * Returns the type of the nettype, which should then be used with 306 * __rpc_getconf(). 307 */ 308 void * 309 __rpc_setconf(const char *nettype) 310 { 311 struct handle *handle; 312 313 handle = (struct handle *) malloc(sizeof (struct handle)); 314 if (handle == NULL) { 315 return (NULL); 316 } 317 switch (handle->nettype = getnettype(nettype)) { 318 case _RPC_NETPATH: 319 case _RPC_CIRCUIT_N: 320 case _RPC_DATAGRAM_N: 321 if (!(handle->nhandle = setnetpath())) 322 goto failed; 323 handle->nflag = TRUE; 324 break; 325 case _RPC_VISIBLE: 326 case _RPC_CIRCUIT_V: 327 case _RPC_DATAGRAM_V: 328 case _RPC_TCP: 329 case _RPC_UDP: 330 if (!(handle->nhandle = setnetconfig())) { 331 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 332 goto failed; 333 } 334 handle->nflag = FALSE; 335 break; 336 default: 337 goto failed; 338 } 339 340 return (handle); 341 342 failed: 343 free(handle); 344 return (NULL); 345 } 346 347 /* 348 * Returns the next netconfig struct for the given "net" type. 349 * __rpc_setconf() should have been called previously. 350 */ 351 struct netconfig * 352 __rpc_getconf(void *vhandle) 353 { 354 struct handle *handle; 355 struct netconfig *nconf; 356 357 handle = (struct handle *)vhandle; 358 if (handle == NULL) { 359 return (NULL); 360 } 361 for (;;) { 362 if (handle->nflag) 363 nconf = getnetpath(handle->nhandle); 364 else 365 nconf = getnetconfig(handle->nhandle); 366 if (nconf == NULL) 367 break; 368 if ((nconf->nc_semantics != NC_TPI_CLTS) && 369 (nconf->nc_semantics != NC_TPI_COTS) && 370 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 371 continue; 372 switch (handle->nettype) { 373 case _RPC_VISIBLE: 374 if (!(nconf->nc_flag & NC_VISIBLE)) 375 continue; 376 /* FALLTHROUGH */ 377 case _RPC_NETPATH: /* Be happy */ 378 break; 379 case _RPC_CIRCUIT_V: 380 if (!(nconf->nc_flag & NC_VISIBLE)) 381 continue; 382 /* FALLTHROUGH */ 383 case _RPC_CIRCUIT_N: 384 if ((nconf->nc_semantics != NC_TPI_COTS) && 385 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 386 continue; 387 break; 388 case _RPC_DATAGRAM_V: 389 if (!(nconf->nc_flag & NC_VISIBLE)) 390 continue; 391 /* FALLTHROUGH */ 392 case _RPC_DATAGRAM_N: 393 if (nconf->nc_semantics != NC_TPI_CLTS) 394 continue; 395 break; 396 case _RPC_TCP: 397 if (((nconf->nc_semantics != NC_TPI_COTS) && 398 (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 399 (strcmp(nconf->nc_protofmly, NC_INET) 400 #ifdef INET6 401 && strcmp(nconf->nc_protofmly, NC_INET6)) 402 #else 403 ) 404 #endif 405 || 406 strcmp(nconf->nc_proto, NC_TCP)) 407 continue; 408 break; 409 case _RPC_UDP: 410 if ((nconf->nc_semantics != NC_TPI_CLTS) || 411 (strcmp(nconf->nc_protofmly, NC_INET) 412 #ifdef INET6 413 && strcmp(nconf->nc_protofmly, NC_INET6)) 414 #else 415 ) 416 #endif 417 || 418 strcmp(nconf->nc_proto, NC_UDP)) 419 continue; 420 break; 421 } 422 break; 423 } 424 return (nconf); 425 } 426 427 void 428 __rpc_endconf(void *vhandle) 429 { 430 struct handle *handle; 431 432 handle = (struct handle *) vhandle; 433 if (handle == NULL) { 434 return; 435 } 436 if (handle->nflag) { 437 endnetpath(handle->nhandle); 438 } else { 439 endnetconfig(handle->nhandle); 440 } 441 free(handle); 442 } 443 444 /* 445 * Used to ping the NULL procedure for clnt handle. 446 * Returns NULL if fails, else a non-NULL pointer. 447 */ 448 void * 449 rpc_nullproc(CLIENT *clnt) 450 { 451 struct timeval TIMEOUT = {25, 0}; 452 453 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 454 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 455 return (NULL); 456 } 457 return ((void *) clnt); 458 } 459 460 /* 461 * Try all possible transports until 462 * one succeeds in finding the netconf for the given fd. 463 */ 464 struct netconfig * 465 __rpcgettp(int fd) 466 { 467 const char *netid; 468 struct __rpc_sockinfo si; 469 470 if (!__rpc_fd2sockinfo(fd, &si)) 471 return NULL; 472 473 if (!__rpc_sockinfo2netid(&si, &netid)) 474 return NULL; 475 476 /*LINTED const castaway*/ 477 return getnetconfigent((char *)netid); 478 } 479 480 int 481 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip) 482 { 483 socklen_t len; 484 int type, proto; 485 struct sockaddr_storage ss; 486 487 len = sizeof ss; 488 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0) 489 return 0; 490 sip->si_alen = len; 491 492 len = sizeof type; 493 if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0) 494 return 0; 495 496 /* XXX */ 497 if (ss.ss_family != AF_LOCAL) { 498 if (type == SOCK_STREAM) 499 proto = IPPROTO_TCP; 500 else if (type == SOCK_DGRAM) 501 proto = IPPROTO_UDP; 502 else 503 return 0; 504 } else 505 proto = 0; 506 507 sip->si_af = ss.ss_family; 508 sip->si_proto = proto; 509 sip->si_socktype = type; 510 511 return 1; 512 } 513 514 /* 515 * Linear search, but the number of entries is small. 516 */ 517 int 518 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 519 { 520 int i; 521 522 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 523 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( 524 strcmp(nconf->nc_netid, "unix") == 0 && 525 strcmp(na_cvt[i].netid, "local") == 0)) { 526 sip->si_af = na_cvt[i].af; 527 sip->si_proto = na_cvt[i].protocol; 528 sip->si_socktype = 529 __rpc_seman2socktype((int)nconf->nc_semantics); 530 if (sip->si_socktype == -1) 531 return 0; 532 sip->si_alen = __rpc_get_a_size(sip->si_af); 533 return 1; 534 } 535 536 return 0; 537 } 538 539 int 540 __rpc_nconf2fd(const struct netconfig *nconf) 541 { 542 struct __rpc_sockinfo si; 543 544 if (!__rpc_nconf2sockinfo(nconf, &si)) 545 return 0; 546 547 return _socket(si.si_af, si.si_socktype, si.si_proto); 548 } 549 550 int 551 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) 552 { 553 int i; 554 struct netconfig *nconf; 555 556 nconf = getnetconfigent("local"); 557 558 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) { 559 if (na_cvt[i].af == sip->si_af && 560 na_cvt[i].protocol == sip->si_proto) { 561 if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) { 562 if (netid) 563 *netid = "unix"; 564 } else { 565 if (netid) 566 *netid = na_cvt[i].netid; 567 } 568 if (nconf != NULL) 569 freenetconfigent(nconf); 570 return 1; 571 } 572 } 573 if (nconf != NULL) 574 freenetconfigent(nconf); 575 576 return 0; 577 } 578 579 char * 580 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 581 { 582 struct __rpc_sockinfo si; 583 584 if (!__rpc_nconf2sockinfo(nconf, &si)) 585 return NULL; 586 return __rpc_taddr2uaddr_af(si.si_af, nbuf); 587 } 588 589 struct netbuf * 590 uaddr2taddr(const struct netconfig *nconf, const char *uaddr) 591 { 592 struct __rpc_sockinfo si; 593 594 if (!__rpc_nconf2sockinfo(nconf, &si)) 595 return NULL; 596 return __rpc_uaddr2taddr_af(si.si_af, uaddr); 597 } 598 599 char * 600 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 601 { 602 char *ret; 603 struct sockaddr_in *sin; 604 struct sockaddr_un *sun; 605 char namebuf[INET_ADDRSTRLEN]; 606 #ifdef INET6 607 struct sockaddr_in6 *sin6; 608 char namebuf6[INET6_ADDRSTRLEN]; 609 #endif 610 u_int16_t port; 611 612 switch (af) { 613 case AF_INET: 614 if (nbuf->len < sizeof(*sin)) 615 return NULL; 616 sin = nbuf->buf; 617 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) 618 == NULL) 619 return NULL; 620 port = ntohs(sin->sin_port); 621 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8, 622 port & 0xff) < 0) 623 return NULL; 624 break; 625 #ifdef INET6 626 case AF_INET6: 627 if (nbuf->len < sizeof(*sin6)) 628 return NULL; 629 sin6 = nbuf->buf; 630 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) 631 == NULL) 632 return NULL; 633 port = ntohs(sin6->sin6_port); 634 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8, 635 port & 0xff) < 0) 636 return NULL; 637 break; 638 #endif 639 case AF_LOCAL: 640 sun = nbuf->buf; 641 if (asprintf(&ret, "%.*s", (int)(sun->sun_len - 642 offsetof(struct sockaddr_un, sun_path)), 643 sun->sun_path) < 0) 644 return (NULL); 645 break; 646 default: 647 return NULL; 648 } 649 650 return ret; 651 } 652 653 struct netbuf * 654 __rpc_uaddr2taddr_af(int af, const char *uaddr) 655 { 656 struct netbuf *ret = NULL; 657 char *addrstr, *p; 658 unsigned port, portlo, porthi; 659 struct sockaddr_in *sin; 660 #ifdef INET6 661 struct sockaddr_in6 *sin6; 662 #endif 663 struct sockaddr_un *sun; 664 665 port = 0; 666 sin = NULL; 667 668 if (uaddr == NULL) 669 return NULL; 670 671 addrstr = strdup(uaddr); 672 if (addrstr == NULL) 673 return NULL; 674 675 /* 676 * AF_LOCAL addresses are expected to be absolute 677 * pathnames, anything else will be AF_INET or AF_INET6. 678 */ 679 if (*addrstr != '/') { 680 p = strrchr(addrstr, '.'); 681 if (p == NULL) 682 goto out; 683 portlo = (unsigned)atoi(p + 1); 684 *p = '\0'; 685 686 p = strrchr(addrstr, '.'); 687 if (p == NULL) 688 goto out; 689 porthi = (unsigned)atoi(p + 1); 690 *p = '\0'; 691 port = (porthi << 8) | portlo; 692 } 693 694 ret = (struct netbuf *)malloc(sizeof *ret); 695 if (ret == NULL) 696 goto out; 697 698 switch (af) { 699 case AF_INET: 700 sin = (struct sockaddr_in *)malloc(sizeof *sin); 701 if (sin == NULL) 702 goto out; 703 memset(sin, 0, sizeof *sin); 704 sin->sin_family = AF_INET; 705 sin->sin_port = htons(port); 706 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { 707 free(sin); 708 free(ret); 709 ret = NULL; 710 goto out; 711 } 712 sin->sin_len = ret->maxlen = ret->len = sizeof *sin; 713 ret->buf = sin; 714 break; 715 #ifdef INET6 716 case AF_INET6: 717 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6); 718 if (sin6 == NULL) 719 goto out; 720 memset(sin6, 0, sizeof *sin6); 721 sin6->sin6_family = AF_INET6; 722 sin6->sin6_port = htons(port); 723 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 724 free(sin6); 725 free(ret); 726 ret = NULL; 727 goto out; 728 } 729 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 730 ret->buf = sin6; 731 break; 732 #endif 733 case AF_LOCAL: 734 sun = (struct sockaddr_un *)malloc(sizeof *sun); 735 if (sun == NULL) 736 goto out; 737 memset(sun, 0, sizeof *sun); 738 sun->sun_family = AF_LOCAL; 739 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 740 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); 741 ret->buf = sun; 742 break; 743 default: 744 break; 745 } 746 out: 747 free(addrstr); 748 return ret; 749 } 750 751 int 752 __rpc_seman2socktype(int semantics) 753 { 754 switch (semantics) { 755 case NC_TPI_CLTS: 756 return SOCK_DGRAM; 757 case NC_TPI_COTS_ORD: 758 return SOCK_STREAM; 759 case NC_TPI_RAW: 760 return SOCK_RAW; 761 default: 762 break; 763 } 764 765 return -1; 766 } 767 768 int 769 __rpc_socktype2seman(int socktype) 770 { 771 switch (socktype) { 772 case SOCK_DGRAM: 773 return NC_TPI_CLTS; 774 case SOCK_STREAM: 775 return NC_TPI_COTS_ORD; 776 case SOCK_RAW: 777 return NC_TPI_RAW; 778 default: 779 break; 780 } 781 782 return -1; 783 } 784 785 /* 786 * XXXX - IPv6 scope IDs can't be handled in universal addresses. 787 * Here, we compare the original server address to that of the RPC 788 * service we just received back from a call to rpcbind on the remote 789 * machine. If they are both "link local" or "site local", copy 790 * the scope id of the server address over to the service address. 791 */ 792 int 793 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc) 794 { 795 #ifdef INET6 796 struct sockaddr *sa_new, *sa_svc; 797 struct sockaddr_in6 *sin6_new, *sin6_svc; 798 799 sa_svc = (struct sockaddr *)svc->buf; 800 sa_new = (struct sockaddr *)new->buf; 801 802 if (sa_new->sa_family == sa_svc->sa_family && 803 sa_new->sa_family == AF_INET6) { 804 sin6_new = (struct sockaddr_in6 *)new->buf; 805 sin6_svc = (struct sockaddr_in6 *)svc->buf; 806 807 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) && 808 IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) || 809 (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) && 810 IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) { 811 sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id; 812 } 813 } 814 #endif 815 return 1; 816 } 817 818 int 819 __rpc_sockisbound(int fd) 820 { 821 struct sockaddr_storage ss; 822 socklen_t slen; 823 824 slen = sizeof (struct sockaddr_storage); 825 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) 826 return 0; 827 828 switch (ss.ss_family) { 829 case AF_INET: 830 return (((struct sockaddr_in *) 831 (void *)&ss)->sin_port != 0); 832 #ifdef INET6 833 case AF_INET6: 834 return (((struct sockaddr_in6 *) 835 (void *)&ss)->sin6_port != 0); 836 #endif 837 case AF_LOCAL: 838 /* XXX check this */ 839 return (((struct sockaddr_un *) 840 (void *)&ss)->sun_path[0] != '\0'); 841 default: 842 break; 843 } 844 845 return 0; 846 } 847