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