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 /* 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 #include <rpc/rpcsec_tls.h> 64 65 #include <rpc/rpc_com.h> 66 #include <rpc/krpc.h> 67 68 #include <vm/vm.h> 69 #include <vm/pmap.h> 70 #include <vm/vm_param.h> 71 72 extern u_long sb_max_adj; /* not defined in socketvar.h */ 73 74 /* Provide an entry point hook for the rpcsec_gss module. */ 75 struct rpc_gss_entries rpc_gss_entries; 76 77 struct handle { 78 NCONF_HANDLE *nhandle; 79 int nflag; /* Whether NETPATH or NETCONFIG */ 80 int nettype; 81 }; 82 83 static const struct _rpcnettype { 84 const char *name; 85 const int type; 86 } _rpctypelist[] = { 87 { "netpath", _RPC_NETPATH }, 88 { "visible", _RPC_VISIBLE }, 89 { "circuit_v", _RPC_CIRCUIT_V }, 90 { "datagram_v", _RPC_DATAGRAM_V }, 91 { "circuit_n", _RPC_CIRCUIT_N }, 92 { "datagram_n", _RPC_DATAGRAM_N }, 93 { "tcp", _RPC_TCP }, 94 { "udp", _RPC_UDP }, 95 { 0, _RPC_NONE } 96 }; 97 98 struct netid_af { 99 const char *netid; 100 int af; 101 int protocol; 102 }; 103 104 static const struct netid_af na_cvt[] = { 105 { "udp", AF_INET, IPPROTO_UDP }, 106 { "tcp", AF_INET, IPPROTO_TCP }, 107 #ifdef INET6 108 { "udp6", AF_INET6, IPPROTO_UDP }, 109 { "tcp6", AF_INET6, IPPROTO_TCP }, 110 #endif 111 { "local", AF_LOCAL, 0 } 112 }; 113 114 struct rpc_createerr rpc_createerr; 115 116 /* 117 * Find the appropriate buffer size 118 */ 119 u_int 120 /*ARGSUSED*/ 121 __rpc_get_t_size(int af, int proto, int size) 122 { 123 int defsize; 124 125 switch (proto) { 126 case IPPROTO_TCP: 127 defsize = 64 * 1024; /* XXX */ 128 break; 129 case IPPROTO_UDP: 130 defsize = UDPMSGSIZE; 131 break; 132 default: 133 defsize = RPC_MAXDATASIZE; 134 break; 135 } 136 if (size == 0) 137 return defsize; 138 139 /* Check whether the value is within the upper max limit */ 140 return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size); 141 } 142 143 /* 144 * Find the appropriate address buffer size 145 */ 146 u_int 147 __rpc_get_a_size(int af) 148 { 149 switch (af) { 150 case AF_INET: 151 return sizeof (struct sockaddr_in); 152 #ifdef INET6 153 case AF_INET6: 154 return sizeof (struct sockaddr_in6); 155 #endif 156 case AF_LOCAL: 157 return sizeof (struct sockaddr_un); 158 default: 159 break; 160 } 161 return ((u_int)RPC_MAXADDRSIZE); 162 } 163 164 #if 0 165 166 /* 167 * Used to ping the NULL procedure for clnt handle. 168 * Returns NULL if fails, else a non-NULL pointer. 169 */ 170 void * 171 rpc_nullproc(clnt) 172 CLIENT *clnt; 173 { 174 struct timeval TIMEOUT = {25, 0}; 175 176 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 177 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 178 return (NULL); 179 } 180 return ((void *) clnt); 181 } 182 183 #endif 184 185 int 186 __rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip) 187 { 188 int type, proto; 189 struct sockaddr *sa; 190 sa_family_t family; 191 struct sockopt opt; 192 int error; 193 194 CURVNET_SET(so->so_vnet); 195 error = so->so_proto->pr_sockaddr(so, &sa); 196 CURVNET_RESTORE(); 197 if (error) 198 return 0; 199 200 sip->si_alen = sa->sa_len; 201 family = sa->sa_family; 202 free(sa, M_SONAME); 203 204 opt.sopt_dir = SOPT_GET; 205 opt.sopt_level = SOL_SOCKET; 206 opt.sopt_name = SO_TYPE; 207 opt.sopt_val = &type; 208 opt.sopt_valsize = sizeof type; 209 opt.sopt_td = NULL; 210 error = sogetopt(so, &opt); 211 if (error) 212 return 0; 213 214 /* XXX */ 215 if (family != AF_LOCAL) { 216 if (type == SOCK_STREAM) 217 proto = IPPROTO_TCP; 218 else if (type == SOCK_DGRAM) 219 proto = IPPROTO_UDP; 220 else 221 return 0; 222 } else 223 proto = 0; 224 225 sip->si_af = family; 226 sip->si_proto = proto; 227 sip->si_socktype = type; 228 229 return 1; 230 } 231 232 /* 233 * Linear search, but the number of entries is small. 234 */ 235 int 236 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 237 { 238 int i; 239 240 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 241 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( 242 strcmp(nconf->nc_netid, "unix") == 0 && 243 strcmp(na_cvt[i].netid, "local") == 0)) { 244 sip->si_af = na_cvt[i].af; 245 sip->si_proto = na_cvt[i].protocol; 246 sip->si_socktype = 247 __rpc_seman2socktype((int)nconf->nc_semantics); 248 if (sip->si_socktype == -1) 249 return 0; 250 sip->si_alen = __rpc_get_a_size(sip->si_af); 251 return 1; 252 } 253 254 return 0; 255 } 256 257 struct socket * 258 __rpc_nconf2socket(const struct netconfig *nconf) 259 { 260 struct __rpc_sockinfo si; 261 struct socket *so; 262 int error; 263 264 if (!__rpc_nconf2sockinfo(nconf, &si)) 265 return 0; 266 267 so = NULL; 268 error = socreate(si.si_af, &so, si.si_socktype, si.si_proto, 269 curthread->td_ucred, curthread); 270 271 if (error) 272 return NULL; 273 else 274 return so; 275 } 276 277 char * 278 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 279 { 280 struct __rpc_sockinfo si; 281 282 if (!__rpc_nconf2sockinfo(nconf, &si)) 283 return NULL; 284 return __rpc_taddr2uaddr_af(si.si_af, nbuf); 285 } 286 287 struct netbuf * 288 uaddr2taddr(const struct netconfig *nconf, const char *uaddr) 289 { 290 struct __rpc_sockinfo si; 291 292 if (!__rpc_nconf2sockinfo(nconf, &si)) 293 return NULL; 294 return __rpc_uaddr2taddr_af(si.si_af, uaddr); 295 } 296 297 char * 298 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 299 { 300 char *ret; 301 struct sbuf sb; 302 struct sockaddr_in *sin; 303 struct sockaddr_un *sun; 304 char namebuf[INET_ADDRSTRLEN]; 305 #ifdef INET6 306 struct sockaddr_in6 *sin6; 307 char namebuf6[INET6_ADDRSTRLEN]; 308 #endif 309 uint16_t port; 310 311 sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND); 312 313 switch (af) { 314 case AF_INET: 315 if (nbuf->len < sizeof(*sin)) 316 return NULL; 317 sin = nbuf->buf; 318 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) 319 == NULL) 320 return NULL; 321 port = ntohs(sin->sin_port); 322 if (sbuf_printf(&sb, "%s.%u.%u", namebuf, 323 ((uint32_t)port) >> 8, 324 port & 0xff) < 0) 325 return NULL; 326 break; 327 #ifdef INET6 328 case AF_INET6: 329 if (nbuf->len < sizeof(*sin6)) 330 return NULL; 331 sin6 = nbuf->buf; 332 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) 333 == NULL) 334 return NULL; 335 port = ntohs(sin6->sin6_port); 336 if (sbuf_printf(&sb, "%s.%u.%u", namebuf6, 337 ((uint32_t)port) >> 8, 338 port & 0xff) < 0) 339 return NULL; 340 break; 341 #endif 342 case AF_LOCAL: 343 sun = nbuf->buf; 344 if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len - 345 offsetof(struct sockaddr_un, sun_path)), 346 sun->sun_path) < 0) 347 return (NULL); 348 break; 349 default: 350 return NULL; 351 } 352 353 sbuf_finish(&sb); 354 ret = strdup(sbuf_data(&sb), M_RPC); 355 sbuf_delete(&sb); 356 357 return ret; 358 } 359 360 struct netbuf * 361 __rpc_uaddr2taddr_af(int af, const char *uaddr) 362 { 363 struct netbuf *ret = NULL; 364 char *addrstr, *p; 365 unsigned port, portlo, porthi; 366 struct sockaddr_in *sin; 367 #ifdef INET6 368 struct sockaddr_in6 *sin6; 369 #endif 370 struct sockaddr_un *sun; 371 372 port = 0; 373 sin = NULL; 374 375 if (uaddr == NULL) 376 return NULL; 377 378 addrstr = strdup(uaddr, M_RPC); 379 if (addrstr == NULL) 380 return NULL; 381 382 /* 383 * AF_LOCAL addresses are expected to be absolute 384 * pathnames, anything else will be AF_INET or AF_INET6. 385 */ 386 if (*addrstr != '/') { 387 p = strrchr(addrstr, '.'); 388 if (p == NULL) 389 goto out; 390 portlo = (unsigned)strtol(p + 1, NULL, 10); 391 *p = '\0'; 392 393 p = strrchr(addrstr, '.'); 394 if (p == NULL) 395 goto out; 396 porthi = (unsigned)strtol(p + 1, NULL, 10); 397 *p = '\0'; 398 port = (porthi << 8) | portlo; 399 } 400 401 ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK); 402 403 switch (af) { 404 case AF_INET: 405 sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC, 406 M_WAITOK); 407 memset(sin, 0, sizeof *sin); 408 sin->sin_family = AF_INET; 409 sin->sin_port = htons(port); 410 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { 411 free(sin, M_RPC); 412 free(ret, M_RPC); 413 ret = NULL; 414 goto out; 415 } 416 sin->sin_len = ret->maxlen = ret->len = sizeof *sin; 417 ret->buf = sin; 418 break; 419 #ifdef INET6 420 case AF_INET6: 421 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC, 422 M_WAITOK); 423 memset(sin6, 0, sizeof *sin6); 424 sin6->sin6_family = AF_INET6; 425 sin6->sin6_port = htons(port); 426 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 427 free(sin6, M_RPC); 428 free(ret, M_RPC); 429 ret = NULL; 430 goto out; 431 } 432 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 433 ret->buf = sin6; 434 break; 435 #endif 436 case AF_LOCAL: 437 sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC, 438 M_WAITOK); 439 memset(sun, 0, sizeof *sun); 440 sun->sun_family = AF_LOCAL; 441 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 442 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); 443 ret->buf = sun; 444 break; 445 default: 446 break; 447 } 448 out: 449 free(addrstr, M_RPC); 450 return ret; 451 } 452 453 int 454 __rpc_seman2socktype(int semantics) 455 { 456 switch (semantics) { 457 case NC_TPI_CLTS: 458 return SOCK_DGRAM; 459 case NC_TPI_COTS_ORD: 460 return SOCK_STREAM; 461 case NC_TPI_RAW: 462 return SOCK_RAW; 463 default: 464 break; 465 } 466 467 return -1; 468 } 469 470 int 471 __rpc_socktype2seman(int socktype) 472 { 473 switch (socktype) { 474 case SOCK_DGRAM: 475 return NC_TPI_CLTS; 476 case SOCK_STREAM: 477 return NC_TPI_COTS_ORD; 478 case SOCK_RAW: 479 return NC_TPI_RAW; 480 default: 481 break; 482 } 483 484 return -1; 485 } 486 487 /* 488 * Returns the type of the network as defined in <rpc/nettype.h> 489 * If nettype is NULL, it defaults to NETPATH. 490 */ 491 static int 492 getnettype(const char *nettype) 493 { 494 int i; 495 496 if ((nettype == NULL) || (nettype[0] == 0)) { 497 return (_RPC_NETPATH); /* Default */ 498 } 499 500 #if 0 501 nettype = strlocase(nettype); 502 #endif 503 for (i = 0; _rpctypelist[i].name; i++) 504 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 505 return (_rpctypelist[i].type); 506 } 507 return (_rpctypelist[i].type); 508 } 509 510 /* 511 * For the given nettype (tcp or udp only), return the first structure found. 512 * This should be freed by calling freenetconfigent() 513 */ 514 struct netconfig * 515 __rpc_getconfip(const char *nettype) 516 { 517 char *netid; 518 static char *netid_tcp = (char *) NULL; 519 static char *netid_udp = (char *) NULL; 520 struct netconfig *dummy; 521 522 if (!netid_udp && !netid_tcp) { 523 struct netconfig *nconf; 524 void *confighandle; 525 526 if (!(confighandle = setnetconfig())) { 527 log(LOG_ERR, "rpc: failed to open " NETCONFIG); 528 return (NULL); 529 } 530 while ((nconf = getnetconfig(confighandle)) != NULL) { 531 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 532 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 533 netid_tcp = strdup(nconf->nc_netid, 534 M_RPC); 535 } else 536 if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 537 netid_udp = strdup(nconf->nc_netid, 538 M_RPC); 539 } 540 } 541 } 542 endnetconfig(confighandle); 543 } 544 if (strcmp(nettype, "udp") == 0) 545 netid = netid_udp; 546 else if (strcmp(nettype, "tcp") == 0) 547 netid = netid_tcp; 548 else { 549 return (NULL); 550 } 551 if ((netid == NULL) || (netid[0] == 0)) { 552 return (NULL); 553 } 554 dummy = getnetconfigent(netid); 555 return (dummy); 556 } 557 558 /* 559 * Returns the type of the nettype, which should then be used with 560 * __rpc_getconf(). 561 * 562 * For simplicity in the kernel, we don't support the NETPATH 563 * environment variable. We behave as userland would then NETPATH is 564 * unset, i.e. iterate over all visible entries in netconfig. 565 */ 566 void * 567 __rpc_setconf(const char *nettype) 568 { 569 struct handle *handle; 570 571 handle = (struct handle *) malloc(sizeof (struct handle), 572 M_RPC, M_WAITOK); 573 switch (handle->nettype = getnettype(nettype)) { 574 case _RPC_NETPATH: 575 case _RPC_CIRCUIT_N: 576 case _RPC_DATAGRAM_N: 577 if (!(handle->nhandle = setnetconfig())) 578 goto failed; 579 handle->nflag = TRUE; 580 break; 581 case _RPC_VISIBLE: 582 case _RPC_CIRCUIT_V: 583 case _RPC_DATAGRAM_V: 584 case _RPC_TCP: 585 case _RPC_UDP: 586 if (!(handle->nhandle = setnetconfig())) { 587 log(LOG_ERR, "rpc: failed to open " NETCONFIG); 588 goto failed; 589 } 590 handle->nflag = FALSE; 591 break; 592 default: 593 goto failed; 594 } 595 596 return (handle); 597 598 failed: 599 free(handle, M_RPC); 600 return (NULL); 601 } 602 603 /* 604 * Returns the next netconfig struct for the given "net" type. 605 * __rpc_setconf() should have been called previously. 606 */ 607 struct netconfig * 608 __rpc_getconf(void *vhandle) 609 { 610 struct handle *handle; 611 struct netconfig *nconf; 612 613 handle = (struct handle *)vhandle; 614 if (handle == NULL) { 615 return (NULL); 616 } 617 for (;;) { 618 if (handle->nflag) { 619 nconf = getnetconfig(handle->nhandle); 620 if (nconf && !(nconf->nc_flag & NC_VISIBLE)) 621 continue; 622 } else { 623 nconf = getnetconfig(handle->nhandle); 624 } 625 if (nconf == NULL) 626 break; 627 if ((nconf->nc_semantics != NC_TPI_CLTS) && 628 (nconf->nc_semantics != NC_TPI_COTS) && 629 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 630 continue; 631 switch (handle->nettype) { 632 case _RPC_VISIBLE: 633 if (!(nconf->nc_flag & NC_VISIBLE)) 634 continue; 635 /* FALLTHROUGH */ 636 case _RPC_NETPATH: /* Be happy */ 637 break; 638 case _RPC_CIRCUIT_V: 639 if (!(nconf->nc_flag & NC_VISIBLE)) 640 continue; 641 /* FALLTHROUGH */ 642 case _RPC_CIRCUIT_N: 643 if ((nconf->nc_semantics != NC_TPI_COTS) && 644 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 645 continue; 646 break; 647 case _RPC_DATAGRAM_V: 648 if (!(nconf->nc_flag & NC_VISIBLE)) 649 continue; 650 /* FALLTHROUGH */ 651 case _RPC_DATAGRAM_N: 652 if (nconf->nc_semantics != NC_TPI_CLTS) 653 continue; 654 break; 655 case _RPC_TCP: 656 if (((nconf->nc_semantics != NC_TPI_COTS) && 657 (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 658 (strcmp(nconf->nc_protofmly, NC_INET) 659 #ifdef INET6 660 && strcmp(nconf->nc_protofmly, NC_INET6)) 661 #else 662 ) 663 #endif 664 || 665 strcmp(nconf->nc_proto, NC_TCP)) 666 continue; 667 break; 668 case _RPC_UDP: 669 if ((nconf->nc_semantics != NC_TPI_CLTS) || 670 (strcmp(nconf->nc_protofmly, NC_INET) 671 #ifdef INET6 672 && strcmp(nconf->nc_protofmly, NC_INET6)) 673 #else 674 ) 675 #endif 676 || 677 strcmp(nconf->nc_proto, NC_UDP)) 678 continue; 679 break; 680 } 681 break; 682 } 683 return (nconf); 684 } 685 686 void 687 __rpc_endconf(void *vhandle) 688 { 689 struct handle *handle; 690 691 handle = (struct handle *) vhandle; 692 if (handle == NULL) { 693 return; 694 } 695 endnetconfig(handle->nhandle); 696 free(handle, M_RPC); 697 } 698 699 int 700 __rpc_sockisbound(struct socket *so) 701 { 702 struct sockaddr *sa; 703 int error, bound; 704 705 CURVNET_SET(so->so_vnet); 706 error = so->so_proto->pr_sockaddr(so, &sa); 707 CURVNET_RESTORE(); 708 if (error) 709 return (0); 710 711 switch (sa->sa_family) { 712 case AF_INET: 713 bound = (((struct sockaddr_in *) sa)->sin_port != 0); 714 break; 715 #ifdef INET6 716 case AF_INET6: 717 bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0); 718 break; 719 #endif 720 case AF_LOCAL: 721 /* XXX check this */ 722 bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0'); 723 break; 724 default: 725 bound = FALSE; 726 break; 727 } 728 729 free(sa, M_SONAME); 730 731 return bound; 732 } 733 734 /* 735 * Implement XDR-style API for RPC call. 736 */ 737 enum clnt_stat 738 clnt_call_private( 739 CLIENT *cl, /* client handle */ 740 struct rpc_callextra *ext, /* call metadata */ 741 rpcproc_t proc, /* procedure number */ 742 xdrproc_t xargs, /* xdr routine for args */ 743 void *argsp, /* pointer to args */ 744 xdrproc_t xresults, /* xdr routine for results */ 745 void *resultsp, /* pointer to results */ 746 struct timeval utimeout) /* seconds to wait before giving up */ 747 { 748 XDR xdrs; 749 struct mbuf *mreq; 750 struct mbuf *mrep; 751 enum clnt_stat stat; 752 753 mreq = m_getcl(M_WAITOK, MT_DATA, 0); 754 755 xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 756 if (!xargs(&xdrs, argsp)) { 757 m_freem(mreq); 758 return (RPC_CANTENCODEARGS); 759 } 760 XDR_DESTROY(&xdrs); 761 762 stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout); 763 m_freem(mreq); 764 765 if (stat == RPC_SUCCESS) { 766 xdrmbuf_create(&xdrs, mrep, XDR_DECODE); 767 if (!xresults(&xdrs, resultsp)) { 768 XDR_DESTROY(&xdrs); 769 return (RPC_CANTDECODERES); 770 } 771 XDR_DESTROY(&xdrs); 772 } 773 774 return (stat); 775 } 776 777 /* 778 * Bind a socket to a privileged IP port 779 */ 780 int 781 bindresvport(struct socket *so, struct sockaddr *sa) 782 { 783 int old, error, af; 784 bool_t freesa = FALSE; 785 struct sockaddr_in *sin; 786 #ifdef INET6 787 struct sockaddr_in6 *sin6; 788 #endif 789 struct sockopt opt; 790 int proto, portrange, portlow; 791 uint16_t *portp; 792 socklen_t salen; 793 794 if (sa == NULL) { 795 CURVNET_SET(so->so_vnet); 796 error = so->so_proto->pr_sockaddr(so, &sa); 797 CURVNET_RESTORE(); 798 if (error) 799 return (error); 800 freesa = TRUE; 801 af = sa->sa_family; 802 salen = sa->sa_len; 803 memset(sa, 0, sa->sa_len); 804 } else { 805 af = sa->sa_family; 806 salen = sa->sa_len; 807 } 808 809 switch (af) { 810 case AF_INET: 811 proto = IPPROTO_IP; 812 portrange = IP_PORTRANGE; 813 portlow = IP_PORTRANGE_LOW; 814 sin = (struct sockaddr_in *)sa; 815 portp = &sin->sin_port; 816 break; 817 #ifdef INET6 818 case AF_INET6: 819 proto = IPPROTO_IPV6; 820 portrange = IPV6_PORTRANGE; 821 portlow = IPV6_PORTRANGE_LOW; 822 sin6 = (struct sockaddr_in6 *)sa; 823 portp = &sin6->sin6_port; 824 break; 825 #endif 826 default: 827 return (EPFNOSUPPORT); 828 } 829 830 sa->sa_family = af; 831 sa->sa_len = salen; 832 833 if (*portp == 0) { 834 bzero(&opt, sizeof(opt)); 835 opt.sopt_dir = SOPT_GET; 836 opt.sopt_level = proto; 837 opt.sopt_name = portrange; 838 opt.sopt_val = &old; 839 opt.sopt_valsize = sizeof(old); 840 error = sogetopt(so, &opt); 841 if (error) { 842 goto out; 843 } 844 845 opt.sopt_dir = SOPT_SET; 846 opt.sopt_val = &portlow; 847 error = sosetopt(so, &opt); 848 if (error) 849 goto out; 850 } 851 852 error = sobind(so, sa, curthread); 853 854 if (*portp == 0) { 855 if (error) { 856 opt.sopt_dir = SOPT_SET; 857 opt.sopt_val = &old; 858 sosetopt(so, &opt); 859 } 860 } 861 out: 862 if (freesa) 863 free(sa, M_SONAME); 864 865 return (error); 866 } 867 868 /* 869 * Make sure an mbuf list is made up entirely of ext_pgs mbufs. 870 * This is needed for sosend() when KERN_TLS is being used. 871 * (There might also be a performance improvement for certain 872 * network interfaces that handle ext_pgs mbufs efficiently.) 873 * It expects at least one non-ext_pgs mbuf followed by zero 874 * or more ext_pgs mbufs. It does not handle the case where 875 * non-ext_pgs mbuf(s) follow ext_pgs ones. 876 * It also performs sanity checks on the resultant list. 877 * The "mp" argument list is consumed. 878 * The "maxextsiz" argument is the upper bound on the data 879 * size for each mbuf (usually 16K for KERN_TLS). 880 */ 881 struct mbuf * 882 _rpc_copym_into_ext_pgs(struct mbuf *mp, int maxextsiz) 883 { 884 struct mbuf *m, *m2, *m3, *mhead; 885 int tlen; 886 887 KASSERT((mp->m_flags & (M_EXT | M_EXTPG)) != 888 (M_EXT | M_EXTPG), ("_rpc_copym_into_ext_pgs:" 889 " first mbuf is an ext_pgs")); 890 /* 891 * Find the last non-ext_pgs mbuf and the total 892 * length of the non-ext_pgs mbuf(s). 893 * The first mbuf must always be a non-ext_pgs 894 * mbuf. 895 */ 896 tlen = mp->m_len; 897 m2 = mp; 898 for (m = mp->m_next; m != NULL; m = m->m_next) { 899 if ((m->m_flags & M_EXTPG) != 0) 900 break; 901 tlen += m->m_len; 902 m2 = m; 903 } 904 905 /* 906 * Copy the non-ext_pgs mbuf(s) into an ext_pgs 907 * mbuf list. 908 */ 909 m2->m_next = NULL; 910 mhead = mb_mapped_to_unmapped(mp, tlen, maxextsiz, 911 M_WAITOK, &m2); 912 913 /* 914 * Link the ext_pgs list onto the newly copied 915 * list and free up the non-ext_pgs mbuf(s). 916 */ 917 m2->m_next = m; 918 m_freem(mp); 919 920 /* 921 * Sanity check the resultant mbuf list. Check for and 922 * remove any 0 length mbufs in the list, since the 923 * KERN_TLS code does not expect any 0 length mbuf(s) 924 * in the list. 925 */ 926 m3 = NULL; 927 m2 = mhead; 928 tlen = 0; 929 while (m2 != NULL) { 930 KASSERT(m2->m_len >= 0, ("_rpc_copym_into_ext_pgs:" 931 " negative m_len")); 932 KASSERT((m2->m_flags & (M_EXT | M_EXTPG)) == 933 (M_EXT | M_EXTPG), ("_rpc_copym_into_ext_pgs:" 934 " non-nomap mbuf in list")); 935 if (m2->m_len == 0) { 936 if (m3 != NULL) 937 m3->m_next = m2->m_next; 938 else 939 m = m2->m_next; 940 m2->m_next = NULL; 941 m_free(m2); 942 if (m3 != NULL) 943 m2 = m3->m_next; 944 else 945 m2 = m; 946 } else { 947 MBUF_EXT_PGS_ASSERT_SANITY(m2); 948 m3 = m2; 949 tlen += m2->m_len; 950 m2 = m2->m_next; 951 } 952 } 953 return (mhead); 954 } 955 956 /* 957 * Kernel module glue 958 */ 959 static int 960 krpc_modevent(module_t mod, int type, void *data) 961 { 962 int error = 0; 963 964 switch (type) { 965 case MOD_LOAD: 966 error = rpctls_init(); 967 break; 968 case MOD_UNLOAD: 969 /* 970 * Cannot be unloaded, since the rpctlssd or rpctlscd daemons 971 * might be performing a rpctls syscall. 972 */ 973 /* FALLTHROUGH */ 974 default: 975 error = EOPNOTSUPP; 976 } 977 return (error); 978 } 979 static moduledata_t krpc_mod = { 980 "krpc", 981 krpc_modevent, 982 NULL, 983 }; 984 DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY); 985 986 /* So that loader and kldload(2) can find us, wherever we are.. */ 987 MODULE_VERSION(krpc, 1); 988 MODULE_DEPEND(krpc, xdr, 1, 1, 1); 989