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