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