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 66 #include <rpc/rpc_com.h> 67 68 extern u_long sb_max_adj; /* not defined in socketvar.h */ 69 70 #if __FreeBSD_version < 700000 71 #define strrchr rindex 72 #endif 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(af) 148 int af; 149 { 150 switch (af) { 151 case AF_INET: 152 return sizeof (struct sockaddr_in); 153 #ifdef INET6 154 case AF_INET6: 155 return sizeof (struct sockaddr_in6); 156 #endif 157 case AF_LOCAL: 158 return sizeof (struct sockaddr_un); 159 default: 160 break; 161 } 162 return ((u_int)RPC_MAXADDRSIZE); 163 } 164 165 #if 0 166 167 /* 168 * Used to ping the NULL procedure for clnt handle. 169 * Returns NULL if fails, else a non-NULL pointer. 170 */ 171 void * 172 rpc_nullproc(clnt) 173 CLIENT *clnt; 174 { 175 struct timeval TIMEOUT = {25, 0}; 176 177 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 178 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 179 return (NULL); 180 } 181 return ((void *) clnt); 182 } 183 184 #endif 185 186 int 187 __rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip) 188 { 189 int type, proto; 190 struct sockaddr *sa; 191 sa_family_t family; 192 struct sockopt opt; 193 int error; 194 195 CURVNET_SET(so->so_vnet); 196 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 197 CURVNET_RESTORE(); 198 if (error) 199 return 0; 200 201 sip->si_alen = sa->sa_len; 202 family = sa->sa_family; 203 free(sa, M_SONAME); 204 205 opt.sopt_dir = SOPT_GET; 206 opt.sopt_level = SOL_SOCKET; 207 opt.sopt_name = SO_TYPE; 208 opt.sopt_val = &type; 209 opt.sopt_valsize = sizeof type; 210 opt.sopt_td = NULL; 211 error = sogetopt(so, &opt); 212 if (error) 213 return 0; 214 215 /* XXX */ 216 if (family != AF_LOCAL) { 217 if (type == SOCK_STREAM) 218 proto = IPPROTO_TCP; 219 else if (type == SOCK_DGRAM) 220 proto = IPPROTO_UDP; 221 else 222 return 0; 223 } else 224 proto = 0; 225 226 sip->si_af = family; 227 sip->si_proto = proto; 228 sip->si_socktype = type; 229 230 return 1; 231 } 232 233 /* 234 * Linear search, but the number of entries is small. 235 */ 236 int 237 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 238 { 239 int i; 240 241 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 242 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( 243 strcmp(nconf->nc_netid, "unix") == 0 && 244 strcmp(na_cvt[i].netid, "local") == 0)) { 245 sip->si_af = na_cvt[i].af; 246 sip->si_proto = na_cvt[i].protocol; 247 sip->si_socktype = 248 __rpc_seman2socktype((int)nconf->nc_semantics); 249 if (sip->si_socktype == -1) 250 return 0; 251 sip->si_alen = __rpc_get_a_size(sip->si_af); 252 return 1; 253 } 254 255 return 0; 256 } 257 258 struct socket * 259 __rpc_nconf2socket(const struct netconfig *nconf) 260 { 261 struct __rpc_sockinfo si; 262 struct socket *so; 263 int error; 264 265 if (!__rpc_nconf2sockinfo(nconf, &si)) 266 return 0; 267 268 so = NULL; 269 error = socreate(si.si_af, &so, si.si_socktype, si.si_proto, 270 curthread->td_ucred, curthread); 271 272 if (error) 273 return NULL; 274 else 275 return so; 276 } 277 278 char * 279 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 280 { 281 struct __rpc_sockinfo si; 282 283 if (!__rpc_nconf2sockinfo(nconf, &si)) 284 return NULL; 285 return __rpc_taddr2uaddr_af(si.si_af, nbuf); 286 } 287 288 struct netbuf * 289 uaddr2taddr(const struct netconfig *nconf, const char *uaddr) 290 { 291 struct __rpc_sockinfo si; 292 293 if (!__rpc_nconf2sockinfo(nconf, &si)) 294 return NULL; 295 return __rpc_uaddr2taddr_af(si.si_af, uaddr); 296 } 297 298 char * 299 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 300 { 301 char *ret; 302 struct sbuf sb; 303 struct sockaddr_in *sin; 304 struct sockaddr_un *sun; 305 char namebuf[INET_ADDRSTRLEN]; 306 #ifdef INET6 307 struct sockaddr_in6 *sin6; 308 char namebuf6[INET6_ADDRSTRLEN]; 309 #endif 310 u_int16_t port; 311 312 sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND); 313 314 switch (af) { 315 case AF_INET: 316 if (nbuf->len < sizeof(*sin)) 317 return NULL; 318 sin = nbuf->buf; 319 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) 320 == NULL) 321 return NULL; 322 port = ntohs(sin->sin_port); 323 if (sbuf_printf(&sb, "%s.%u.%u", namebuf, 324 ((uint32_t)port) >> 8, 325 port & 0xff) < 0) 326 return NULL; 327 break; 328 #ifdef INET6 329 case AF_INET6: 330 if (nbuf->len < sizeof(*sin6)) 331 return NULL; 332 sin6 = nbuf->buf; 333 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) 334 == NULL) 335 return NULL; 336 port = ntohs(sin6->sin6_port); 337 if (sbuf_printf(&sb, "%s.%u.%u", namebuf6, 338 ((uint32_t)port) >> 8, 339 port & 0xff) < 0) 340 return NULL; 341 break; 342 #endif 343 case AF_LOCAL: 344 sun = nbuf->buf; 345 if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len - 346 offsetof(struct sockaddr_un, sun_path)), 347 sun->sun_path) < 0) 348 return (NULL); 349 break; 350 default: 351 return NULL; 352 } 353 354 sbuf_finish(&sb); 355 ret = strdup(sbuf_data(&sb), M_RPC); 356 sbuf_delete(&sb); 357 358 return ret; 359 } 360 361 struct netbuf * 362 __rpc_uaddr2taddr_af(int af, const char *uaddr) 363 { 364 struct netbuf *ret = NULL; 365 char *addrstr, *p; 366 unsigned port, portlo, porthi; 367 struct sockaddr_in *sin; 368 #ifdef INET6 369 struct sockaddr_in6 *sin6; 370 #endif 371 struct sockaddr_un *sun; 372 373 port = 0; 374 sin = NULL; 375 376 if (uaddr == NULL) 377 return NULL; 378 379 addrstr = strdup(uaddr, M_RPC); 380 if (addrstr == NULL) 381 return NULL; 382 383 /* 384 * AF_LOCAL addresses are expected to be absolute 385 * pathnames, anything else will be AF_INET or AF_INET6. 386 */ 387 if (*addrstr != '/') { 388 p = strrchr(addrstr, '.'); 389 if (p == NULL) 390 goto out; 391 portlo = (unsigned)strtol(p + 1, NULL, 10); 392 *p = '\0'; 393 394 p = strrchr(addrstr, '.'); 395 if (p == NULL) 396 goto out; 397 porthi = (unsigned)strtol(p + 1, NULL, 10); 398 *p = '\0'; 399 port = (porthi << 8) | portlo; 400 } 401 402 ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK); 403 404 switch (af) { 405 case AF_INET: 406 sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC, 407 M_WAITOK); 408 memset(sin, 0, sizeof *sin); 409 sin->sin_family = AF_INET; 410 sin->sin_port = htons(port); 411 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { 412 free(sin, M_RPC); 413 free(ret, M_RPC); 414 ret = NULL; 415 goto out; 416 } 417 sin->sin_len = ret->maxlen = ret->len = sizeof *sin; 418 ret->buf = sin; 419 break; 420 #ifdef INET6 421 case AF_INET6: 422 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC, 423 M_WAITOK); 424 memset(sin6, 0, sizeof *sin6); 425 sin6->sin6_family = AF_INET6; 426 sin6->sin6_port = htons(port); 427 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 428 free(sin6, M_RPC); 429 free(ret, M_RPC); 430 ret = NULL; 431 goto out; 432 } 433 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 434 ret->buf = sin6; 435 break; 436 #endif 437 case AF_LOCAL: 438 sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC, 439 M_WAITOK); 440 memset(sun, 0, sizeof *sun); 441 sun->sun_family = AF_LOCAL; 442 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 443 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); 444 ret->buf = sun; 445 break; 446 default: 447 break; 448 } 449 out: 450 free(addrstr, M_RPC); 451 return ret; 452 } 453 454 int 455 __rpc_seman2socktype(int semantics) 456 { 457 switch (semantics) { 458 case NC_TPI_CLTS: 459 return SOCK_DGRAM; 460 case NC_TPI_COTS_ORD: 461 return SOCK_STREAM; 462 case NC_TPI_RAW: 463 return SOCK_RAW; 464 default: 465 break; 466 } 467 468 return -1; 469 } 470 471 int 472 __rpc_socktype2seman(int socktype) 473 { 474 switch (socktype) { 475 case SOCK_DGRAM: 476 return NC_TPI_CLTS; 477 case SOCK_STREAM: 478 return NC_TPI_COTS_ORD; 479 case SOCK_RAW: 480 return NC_TPI_RAW; 481 default: 482 break; 483 } 484 485 return -1; 486 } 487 488 /* 489 * Returns the type of the network as defined in <rpc/nettype.h> 490 * If nettype is NULL, it defaults to NETPATH. 491 */ 492 static int 493 getnettype(const char *nettype) 494 { 495 int i; 496 497 if ((nettype == NULL) || (nettype[0] == 0)) { 498 return (_RPC_NETPATH); /* Default */ 499 } 500 501 #if 0 502 nettype = strlocase(nettype); 503 #endif 504 for (i = 0; _rpctypelist[i].name; i++) 505 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 506 return (_rpctypelist[i].type); 507 } 508 return (_rpctypelist[i].type); 509 } 510 511 /* 512 * For the given nettype (tcp or udp only), return the first structure found. 513 * This should be freed by calling freenetconfigent() 514 */ 515 struct netconfig * 516 __rpc_getconfip(const char *nettype) 517 { 518 char *netid; 519 static char *netid_tcp = (char *) NULL; 520 static char *netid_udp = (char *) NULL; 521 struct netconfig *dummy; 522 523 if (!netid_udp && !netid_tcp) { 524 struct netconfig *nconf; 525 void *confighandle; 526 527 if (!(confighandle = setnetconfig())) { 528 log(LOG_ERR, "rpc: failed to open " NETCONFIG); 529 return (NULL); 530 } 531 while ((nconf = getnetconfig(confighandle)) != NULL) { 532 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 533 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 534 netid_tcp = strdup(nconf->nc_netid, 535 M_RPC); 536 } else 537 if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 538 netid_udp = strdup(nconf->nc_netid, 539 M_RPC); 540 } 541 } 542 } 543 endnetconfig(confighandle); 544 } 545 if (strcmp(nettype, "udp") == 0) 546 netid = netid_udp; 547 else if (strcmp(nettype, "tcp") == 0) 548 netid = netid_tcp; 549 else { 550 return (NULL); 551 } 552 if ((netid == NULL) || (netid[0] == 0)) { 553 return (NULL); 554 } 555 dummy = getnetconfigent(netid); 556 return (dummy); 557 } 558 559 /* 560 * Returns the type of the nettype, which should then be used with 561 * __rpc_getconf(). 562 * 563 * For simplicity in the kernel, we don't support the NETPATH 564 * environment variable. We behave as userland would then NETPATH is 565 * unset, i.e. iterate over all visible entries in netconfig. 566 */ 567 void * 568 __rpc_setconf(nettype) 569 const char *nettype; 570 { 571 struct handle *handle; 572 573 handle = (struct handle *) malloc(sizeof (struct handle), 574 M_RPC, M_WAITOK); 575 switch (handle->nettype = getnettype(nettype)) { 576 case _RPC_NETPATH: 577 case _RPC_CIRCUIT_N: 578 case _RPC_DATAGRAM_N: 579 if (!(handle->nhandle = setnetconfig())) 580 goto failed; 581 handle->nflag = TRUE; 582 break; 583 case _RPC_VISIBLE: 584 case _RPC_CIRCUIT_V: 585 case _RPC_DATAGRAM_V: 586 case _RPC_TCP: 587 case _RPC_UDP: 588 if (!(handle->nhandle = setnetconfig())) { 589 log(LOG_ERR, "rpc: failed to open " NETCONFIG); 590 goto failed; 591 } 592 handle->nflag = FALSE; 593 break; 594 default: 595 goto failed; 596 } 597 598 return (handle); 599 600 failed: 601 free(handle, M_RPC); 602 return (NULL); 603 } 604 605 /* 606 * Returns the next netconfig struct for the given "net" type. 607 * __rpc_setconf() should have been called previously. 608 */ 609 struct netconfig * 610 __rpc_getconf(void *vhandle) 611 { 612 struct handle *handle; 613 struct netconfig *nconf; 614 615 handle = (struct handle *)vhandle; 616 if (handle == NULL) { 617 return (NULL); 618 } 619 for (;;) { 620 if (handle->nflag) { 621 nconf = getnetconfig(handle->nhandle); 622 if (nconf && !(nconf->nc_flag & NC_VISIBLE)) 623 continue; 624 } else { 625 nconf = getnetconfig(handle->nhandle); 626 } 627 if (nconf == NULL) 628 break; 629 if ((nconf->nc_semantics != NC_TPI_CLTS) && 630 (nconf->nc_semantics != NC_TPI_COTS) && 631 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 632 continue; 633 switch (handle->nettype) { 634 case _RPC_VISIBLE: 635 if (!(nconf->nc_flag & NC_VISIBLE)) 636 continue; 637 /* FALLTHROUGH */ 638 case _RPC_NETPATH: /* Be happy */ 639 break; 640 case _RPC_CIRCUIT_V: 641 if (!(nconf->nc_flag & NC_VISIBLE)) 642 continue; 643 /* FALLTHROUGH */ 644 case _RPC_CIRCUIT_N: 645 if ((nconf->nc_semantics != NC_TPI_COTS) && 646 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 647 continue; 648 break; 649 case _RPC_DATAGRAM_V: 650 if (!(nconf->nc_flag & NC_VISIBLE)) 651 continue; 652 /* FALLTHROUGH */ 653 case _RPC_DATAGRAM_N: 654 if (nconf->nc_semantics != NC_TPI_CLTS) 655 continue; 656 break; 657 case _RPC_TCP: 658 if (((nconf->nc_semantics != NC_TPI_COTS) && 659 (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 660 (strcmp(nconf->nc_protofmly, NC_INET) 661 #ifdef INET6 662 && strcmp(nconf->nc_protofmly, NC_INET6)) 663 #else 664 ) 665 #endif 666 || 667 strcmp(nconf->nc_proto, NC_TCP)) 668 continue; 669 break; 670 case _RPC_UDP: 671 if ((nconf->nc_semantics != NC_TPI_CLTS) || 672 (strcmp(nconf->nc_protofmly, NC_INET) 673 #ifdef INET6 674 && strcmp(nconf->nc_protofmly, NC_INET6)) 675 #else 676 ) 677 #endif 678 || 679 strcmp(nconf->nc_proto, NC_UDP)) 680 continue; 681 break; 682 } 683 break; 684 } 685 return (nconf); 686 } 687 688 void 689 __rpc_endconf(vhandle) 690 void * vhandle; 691 { 692 struct handle *handle; 693 694 handle = (struct handle *) vhandle; 695 if (handle == NULL) { 696 return; 697 } 698 endnetconfig(handle->nhandle); 699 free(handle, M_RPC); 700 } 701 702 int 703 __rpc_sockisbound(struct socket *so) 704 { 705 struct sockaddr *sa; 706 int error, bound; 707 708 CURVNET_SET(so->so_vnet); 709 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 710 CURVNET_RESTORE(); 711 if (error) 712 return (0); 713 714 switch (sa->sa_family) { 715 case AF_INET: 716 bound = (((struct sockaddr_in *) sa)->sin_port != 0); 717 break; 718 #ifdef INET6 719 case AF_INET6: 720 bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0); 721 break; 722 #endif 723 case AF_LOCAL: 724 /* XXX check this */ 725 bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0'); 726 break; 727 default: 728 bound = FALSE; 729 break; 730 } 731 732 free(sa, M_SONAME); 733 734 return bound; 735 } 736 737 /* 738 * Implement XDR-style API for RPC call. 739 */ 740 enum clnt_stat 741 clnt_call_private( 742 CLIENT *cl, /* client handle */ 743 struct rpc_callextra *ext, /* call metadata */ 744 rpcproc_t proc, /* procedure number */ 745 xdrproc_t xargs, /* xdr routine for args */ 746 void *argsp, /* pointer to args */ 747 xdrproc_t xresults, /* xdr routine for results */ 748 void *resultsp, /* pointer to results */ 749 struct timeval utimeout) /* seconds to wait before giving up */ 750 { 751 XDR xdrs; 752 struct mbuf *mreq; 753 struct mbuf *mrep; 754 enum clnt_stat stat; 755 756 mreq = m_getcl(M_WAITOK, MT_DATA, 0); 757 758 xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 759 if (!xargs(&xdrs, argsp)) { 760 m_freem(mreq); 761 return (RPC_CANTENCODEARGS); 762 } 763 XDR_DESTROY(&xdrs); 764 765 stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout); 766 m_freem(mreq); 767 768 if (stat == RPC_SUCCESS) { 769 xdrmbuf_create(&xdrs, mrep, XDR_DECODE); 770 if (!xresults(&xdrs, resultsp)) { 771 XDR_DESTROY(&xdrs); 772 return (RPC_CANTDECODERES); 773 } 774 XDR_DESTROY(&xdrs); 775 } 776 777 return (stat); 778 } 779 780 /* 781 * Bind a socket to a privileged IP port 782 */ 783 int 784 bindresvport(struct socket *so, struct sockaddr *sa) 785 { 786 int old, error, af; 787 bool_t freesa = FALSE; 788 struct sockaddr_in *sin; 789 #ifdef INET6 790 struct sockaddr_in6 *sin6; 791 #endif 792 struct sockopt opt; 793 int proto, portrange, portlow; 794 u_int16_t *portp; 795 socklen_t salen; 796 797 if (sa == NULL) { 798 CURVNET_SET(so->so_vnet); 799 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 800 CURVNET_RESTORE(); 801 if (error) 802 return (error); 803 freesa = TRUE; 804 af = sa->sa_family; 805 salen = sa->sa_len; 806 memset(sa, 0, sa->sa_len); 807 } else { 808 af = sa->sa_family; 809 salen = sa->sa_len; 810 } 811 812 switch (af) { 813 case AF_INET: 814 proto = IPPROTO_IP; 815 portrange = IP_PORTRANGE; 816 portlow = IP_PORTRANGE_LOW; 817 sin = (struct sockaddr_in *)sa; 818 portp = &sin->sin_port; 819 break; 820 #ifdef INET6 821 case AF_INET6: 822 proto = IPPROTO_IPV6; 823 portrange = IPV6_PORTRANGE; 824 portlow = IPV6_PORTRANGE_LOW; 825 sin6 = (struct sockaddr_in6 *)sa; 826 portp = &sin6->sin6_port; 827 break; 828 #endif 829 default: 830 return (EPFNOSUPPORT); 831 } 832 833 sa->sa_family = af; 834 sa->sa_len = salen; 835 836 if (*portp == 0) { 837 bzero(&opt, sizeof(opt)); 838 opt.sopt_dir = SOPT_GET; 839 opt.sopt_level = proto; 840 opt.sopt_name = portrange; 841 opt.sopt_val = &old; 842 opt.sopt_valsize = sizeof(old); 843 error = sogetopt(so, &opt); 844 if (error) { 845 goto out; 846 } 847 848 opt.sopt_dir = SOPT_SET; 849 opt.sopt_val = &portlow; 850 error = sosetopt(so, &opt); 851 if (error) 852 goto out; 853 } 854 855 error = sobind(so, sa, curthread); 856 857 if (*portp == 0) { 858 if (error) { 859 opt.sopt_dir = SOPT_SET; 860 opt.sopt_val = &old; 861 sosetopt(so, &opt); 862 } 863 } 864 out: 865 if (freesa) 866 free(sa, M_SONAME); 867 868 return (error); 869 } 870 871 /* 872 * Kernel module glue 873 */ 874 static int 875 krpc_modevent(module_t mod, int type, void *data) 876 { 877 878 return (0); 879 } 880 static moduledata_t krpc_mod = { 881 "krpc", 882 krpc_modevent, 883 NULL, 884 }; 885 DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY); 886 887 /* So that loader and kldload(2) can find us, wherever we are.. */ 888 MODULE_VERSION(krpc, 1); 889