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