1177633Sdfr/* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */ 2177633Sdfr 3261057Smav/*- 4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261057Smav * All rights reserved. 6261057Smav * 7261057Smav * Redistribution and use in source and binary forms, with or without 8261057Smav * modification, are permitted provided that the following conditions are met: 9261057Smav * - Redistributions of source code must retain the above copyright notice, 10261057Smav * this list of conditions and the following disclaimer. 11261057Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261057Smav * this list of conditions and the following disclaimer in the documentation 13261057Smav * and/or other materials provided with the distribution. 14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261057Smav * contributors may be used to endorse or promote products derived 16261057Smav * from this software without specific prior written permission. 17177633Sdfr * 18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261057Smav * POSSIBILITY OF SUCH DAMAGE. 29177633Sdfr */ 30177633Sdfr/* 31177633Sdfr * Copyright (c) 1986-1991 by Sun Microsystems Inc. 32177633Sdfr */ 33177633Sdfr 34177633Sdfr/* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ 35177633Sdfr#include <sys/cdefs.h> 36177633Sdfr__FBSDID("$FreeBSD$"); 37177633Sdfr 38177633Sdfr/* 39177633Sdfr * rpc_generic.c, Miscl routines for RPC. 40177633Sdfr * 41177633Sdfr */ 42177633Sdfr 43177633Sdfr#include "opt_inet6.h" 44177633Sdfr 45177633Sdfr#include <sys/param.h> 46177662Sdfr#include <sys/kernel.h> 47177633Sdfr#include <sys/malloc.h> 48184588Sdfr#include <sys/mbuf.h> 49177662Sdfr#include <sys/module.h> 50177633Sdfr#include <sys/proc.h> 51177633Sdfr#include <sys/protosw.h> 52177633Sdfr#include <sys/sbuf.h> 53177633Sdfr#include <sys/systm.h> 54177633Sdfr#include <sys/socket.h> 55177633Sdfr#include <sys/socketvar.h> 56177633Sdfr#include <sys/syslog.h> 57177633Sdfr 58196503Szec#include <net/vnet.h> 59196503Szec 60177633Sdfr#include <rpc/rpc.h> 61177633Sdfr#include <rpc/nettype.h> 62223309Srmacklem#include <rpc/rpcsec_gss.h> 63177633Sdfr 64177685Sdfr#include <rpc/rpc_com.h> 65177633Sdfr 66213756Srmacklemextern u_long sb_max_adj; /* not defined in socketvar.h */ 67213756Srmacklem 68177685Sdfr#if __FreeBSD_version < 700000 69177685Sdfr#define strrchr rindex 70177685Sdfr#endif 71177685Sdfr 72223309Srmacklem/* Provide an entry point hook for the rpcsec_gss module. */ 73223309Srmacklemstruct rpc_gss_entries rpc_gss_entries; 74223309Srmacklem 75177633Sdfrstruct handle { 76177633Sdfr NCONF_HANDLE *nhandle; 77177633Sdfr int nflag; /* Whether NETPATH or NETCONFIG */ 78177633Sdfr int nettype; 79177633Sdfr}; 80177633Sdfr 81177633Sdfrstatic const struct _rpcnettype { 82177633Sdfr const char *name; 83177633Sdfr const int type; 84177633Sdfr} _rpctypelist[] = { 85177633Sdfr { "netpath", _RPC_NETPATH }, 86177633Sdfr { "visible", _RPC_VISIBLE }, 87177633Sdfr { "circuit_v", _RPC_CIRCUIT_V }, 88177633Sdfr { "datagram_v", _RPC_DATAGRAM_V }, 89177633Sdfr { "circuit_n", _RPC_CIRCUIT_N }, 90177633Sdfr { "datagram_n", _RPC_DATAGRAM_N }, 91177633Sdfr { "tcp", _RPC_TCP }, 92177633Sdfr { "udp", _RPC_UDP }, 93177633Sdfr { 0, _RPC_NONE } 94177633Sdfr}; 95177633Sdfr 96177633Sdfrstruct netid_af { 97177633Sdfr const char *netid; 98177633Sdfr int af; 99177633Sdfr int protocol; 100177633Sdfr}; 101177633Sdfr 102177633Sdfrstatic const struct netid_af na_cvt[] = { 103177633Sdfr { "udp", AF_INET, IPPROTO_UDP }, 104177633Sdfr { "tcp", AF_INET, IPPROTO_TCP }, 105177633Sdfr#ifdef INET6 106177633Sdfr { "udp6", AF_INET6, IPPROTO_UDP }, 107177633Sdfr { "tcp6", AF_INET6, IPPROTO_TCP }, 108177633Sdfr#endif 109177633Sdfr { "local", AF_LOCAL, 0 } 110177633Sdfr}; 111177633Sdfr 112177633Sdfrstruct rpc_createerr rpc_createerr; 113177633Sdfr 114177633Sdfr/* 115177633Sdfr * Find the appropriate buffer size 116177633Sdfr */ 117177633Sdfru_int 118177633Sdfr/*ARGSUSED*/ 119177633Sdfr__rpc_get_t_size(int af, int proto, int size) 120177633Sdfr{ 121213756Srmacklem int defsize; 122177633Sdfr 123177633Sdfr switch (proto) { 124177633Sdfr case IPPROTO_TCP: 125177633Sdfr defsize = 64 * 1024; /* XXX */ 126177633Sdfr break; 127177633Sdfr case IPPROTO_UDP: 128177633Sdfr defsize = UDPMSGSIZE; 129177633Sdfr break; 130177633Sdfr default: 131177633Sdfr defsize = RPC_MAXDATASIZE; 132177633Sdfr break; 133177633Sdfr } 134177633Sdfr if (size == 0) 135177633Sdfr return defsize; 136177633Sdfr 137177633Sdfr /* Check whether the value is within the upper max limit */ 138213756Srmacklem return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size); 139177633Sdfr} 140177633Sdfr 141177633Sdfr/* 142177633Sdfr * Find the appropriate address buffer size 143177633Sdfr */ 144177633Sdfru_int 145177633Sdfr__rpc_get_a_size(af) 146177633Sdfr int af; 147177633Sdfr{ 148177633Sdfr switch (af) { 149177633Sdfr case AF_INET: 150177633Sdfr return sizeof (struct sockaddr_in); 151177633Sdfr#ifdef INET6 152177633Sdfr case AF_INET6: 153177633Sdfr return sizeof (struct sockaddr_in6); 154177633Sdfr#endif 155177633Sdfr case AF_LOCAL: 156177633Sdfr return sizeof (struct sockaddr_un); 157177633Sdfr default: 158177633Sdfr break; 159177633Sdfr } 160177633Sdfr return ((u_int)RPC_MAXADDRSIZE); 161177633Sdfr} 162177633Sdfr 163177633Sdfr#if 0 164177633Sdfr 165177633Sdfr/* 166177633Sdfr * Used to ping the NULL procedure for clnt handle. 167177633Sdfr * Returns NULL if fails, else a non-NULL pointer. 168177633Sdfr */ 169177633Sdfrvoid * 170177633Sdfrrpc_nullproc(clnt) 171177633Sdfr CLIENT *clnt; 172177633Sdfr{ 173177633Sdfr struct timeval TIMEOUT = {25, 0}; 174177633Sdfr 175177633Sdfr if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 176177633Sdfr (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 177177633Sdfr return (NULL); 178177633Sdfr } 179177633Sdfr return ((void *) clnt); 180177633Sdfr} 181177633Sdfr 182177633Sdfr#endif 183177633Sdfr 184177633Sdfrint 185177633Sdfr__rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip) 186177633Sdfr{ 187177633Sdfr int type, proto; 188177633Sdfr struct sockaddr *sa; 189177633Sdfr sa_family_t family; 190177633Sdfr struct sockopt opt; 191177633Sdfr int error; 192177633Sdfr 193218757Sbz CURVNET_SET(so->so_vnet); 194177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 195218757Sbz CURVNET_RESTORE(); 196177633Sdfr if (error) 197177633Sdfr return 0; 198177633Sdfr 199177633Sdfr sip->si_alen = sa->sa_len; 200177633Sdfr family = sa->sa_family; 201177633Sdfr free(sa, M_SONAME); 202177633Sdfr 203177633Sdfr opt.sopt_dir = SOPT_GET; 204177633Sdfr opt.sopt_level = SOL_SOCKET; 205177633Sdfr opt.sopt_name = SO_TYPE; 206177633Sdfr opt.sopt_val = &type; 207177633Sdfr opt.sopt_valsize = sizeof type; 208177633Sdfr opt.sopt_td = NULL; 209177633Sdfr error = sogetopt(so, &opt); 210177633Sdfr if (error) 211177633Sdfr return 0; 212177633Sdfr 213177633Sdfr /* XXX */ 214177633Sdfr if (family != AF_LOCAL) { 215177633Sdfr if (type == SOCK_STREAM) 216177633Sdfr proto = IPPROTO_TCP; 217177633Sdfr else if (type == SOCK_DGRAM) 218177633Sdfr proto = IPPROTO_UDP; 219177633Sdfr else 220177633Sdfr return 0; 221177633Sdfr } else 222177633Sdfr proto = 0; 223177633Sdfr 224177633Sdfr sip->si_af = family; 225177633Sdfr sip->si_proto = proto; 226177633Sdfr sip->si_socktype = type; 227177633Sdfr 228177633Sdfr return 1; 229177633Sdfr} 230177633Sdfr 231177633Sdfr/* 232177633Sdfr * Linear search, but the number of entries is small. 233177633Sdfr */ 234177633Sdfrint 235177633Sdfr__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 236177633Sdfr{ 237177633Sdfr int i; 238177633Sdfr 239177633Sdfr for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 240177633Sdfr if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( 241177633Sdfr strcmp(nconf->nc_netid, "unix") == 0 && 242177633Sdfr strcmp(na_cvt[i].netid, "local") == 0)) { 243177633Sdfr sip->si_af = na_cvt[i].af; 244177633Sdfr sip->si_proto = na_cvt[i].protocol; 245177633Sdfr sip->si_socktype = 246177633Sdfr __rpc_seman2socktype((int)nconf->nc_semantics); 247177633Sdfr if (sip->si_socktype == -1) 248177633Sdfr return 0; 249177633Sdfr sip->si_alen = __rpc_get_a_size(sip->si_af); 250177633Sdfr return 1; 251177633Sdfr } 252177633Sdfr 253177633Sdfr return 0; 254177633Sdfr} 255177633Sdfr 256177633Sdfrstruct socket * 257177633Sdfr__rpc_nconf2socket(const struct netconfig *nconf) 258177633Sdfr{ 259177633Sdfr struct __rpc_sockinfo si; 260177633Sdfr struct socket *so; 261177633Sdfr int error; 262177633Sdfr 263177633Sdfr if (!__rpc_nconf2sockinfo(nconf, &si)) 264177633Sdfr return 0; 265177633Sdfr 266177633Sdfr so = NULL; 267177633Sdfr error = socreate(si.si_af, &so, si.si_socktype, si.si_proto, 268177633Sdfr curthread->td_ucred, curthread); 269177633Sdfr 270177633Sdfr if (error) 271177633Sdfr return NULL; 272177633Sdfr else 273177633Sdfr return so; 274177633Sdfr} 275177633Sdfr 276177633Sdfrchar * 277177633Sdfrtaddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 278177633Sdfr{ 279177633Sdfr struct __rpc_sockinfo si; 280177633Sdfr 281177633Sdfr if (!__rpc_nconf2sockinfo(nconf, &si)) 282177633Sdfr return NULL; 283177633Sdfr return __rpc_taddr2uaddr_af(si.si_af, nbuf); 284177633Sdfr} 285177633Sdfr 286177633Sdfrstruct netbuf * 287177633Sdfruaddr2taddr(const struct netconfig *nconf, const char *uaddr) 288177633Sdfr{ 289177633Sdfr struct __rpc_sockinfo si; 290177633Sdfr 291177633Sdfr if (!__rpc_nconf2sockinfo(nconf, &si)) 292177633Sdfr return NULL; 293177633Sdfr return __rpc_uaddr2taddr_af(si.si_af, uaddr); 294177633Sdfr} 295177633Sdfr 296177633Sdfrchar * 297177633Sdfr__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 298177633Sdfr{ 299177633Sdfr char *ret; 300177633Sdfr struct sbuf sb; 301177633Sdfr struct sockaddr_in *sin; 302177633Sdfr struct sockaddr_un *sun; 303177633Sdfr char namebuf[INET_ADDRSTRLEN]; 304177633Sdfr#ifdef INET6 305177633Sdfr struct sockaddr_in6 *sin6; 306177633Sdfr char namebuf6[INET6_ADDRSTRLEN]; 307177633Sdfr#endif 308177633Sdfr u_int16_t port; 309177633Sdfr 310177633Sdfr sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND); 311177633Sdfr 312177633Sdfr switch (af) { 313177633Sdfr case AF_INET: 314177633Sdfr sin = nbuf->buf; 315213103Sattilio if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) 316177633Sdfr == NULL) 317177633Sdfr return NULL; 318177633Sdfr port = ntohs(sin->sin_port); 319177633Sdfr if (sbuf_printf(&sb, "%s.%u.%u", namebuf, 320177633Sdfr ((uint32_t)port) >> 8, 321177633Sdfr port & 0xff) < 0) 322177633Sdfr return NULL; 323177633Sdfr break; 324177633Sdfr#ifdef INET6 325177633Sdfr case AF_INET6: 326177633Sdfr sin6 = nbuf->buf; 327213103Sattilio if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) 328177633Sdfr == NULL) 329177633Sdfr return NULL; 330177633Sdfr port = ntohs(sin6->sin6_port); 331177633Sdfr if (sbuf_printf(&sb, "%s.%u.%u", namebuf6, 332177633Sdfr ((uint32_t)port) >> 8, 333177633Sdfr port & 0xff) < 0) 334177633Sdfr return NULL; 335177633Sdfr break; 336177633Sdfr#endif 337177633Sdfr case AF_LOCAL: 338177633Sdfr sun = nbuf->buf; 339177633Sdfr if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len - 340177633Sdfr offsetof(struct sockaddr_un, sun_path)), 341177633Sdfr sun->sun_path) < 0) 342177633Sdfr return (NULL); 343177633Sdfr break; 344177633Sdfr default: 345177633Sdfr return NULL; 346177633Sdfr } 347177633Sdfr 348177633Sdfr sbuf_finish(&sb); 349177633Sdfr ret = strdup(sbuf_data(&sb), M_RPC); 350177633Sdfr sbuf_delete(&sb); 351177633Sdfr 352177633Sdfr return ret; 353177633Sdfr} 354177633Sdfr 355177633Sdfrstruct netbuf * 356177633Sdfr__rpc_uaddr2taddr_af(int af, const char *uaddr) 357177633Sdfr{ 358177633Sdfr struct netbuf *ret = NULL; 359177633Sdfr char *addrstr, *p; 360177633Sdfr unsigned port, portlo, porthi; 361177633Sdfr struct sockaddr_in *sin; 362177633Sdfr#ifdef INET6 363177633Sdfr struct sockaddr_in6 *sin6; 364177633Sdfr#endif 365177633Sdfr struct sockaddr_un *sun; 366177633Sdfr 367177633Sdfr port = 0; 368177633Sdfr sin = NULL; 369177633Sdfr addrstr = strdup(uaddr, M_RPC); 370177633Sdfr if (addrstr == NULL) 371177633Sdfr return NULL; 372177633Sdfr 373177633Sdfr /* 374177633Sdfr * AF_LOCAL addresses are expected to be absolute 375177633Sdfr * pathnames, anything else will be AF_INET or AF_INET6. 376177633Sdfr */ 377177633Sdfr if (*addrstr != '/') { 378177633Sdfr p = strrchr(addrstr, '.'); 379177633Sdfr if (p == NULL) 380177633Sdfr goto out; 381177633Sdfr portlo = (unsigned)strtol(p + 1, NULL, 10); 382177633Sdfr *p = '\0'; 383177633Sdfr 384177633Sdfr p = strrchr(addrstr, '.'); 385177633Sdfr if (p == NULL) 386177633Sdfr goto out; 387177633Sdfr porthi = (unsigned)strtol(p + 1, NULL, 10); 388177633Sdfr *p = '\0'; 389177633Sdfr port = (porthi << 8) | portlo; 390177633Sdfr } 391177633Sdfr 392177633Sdfr ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK); 393177633Sdfr if (ret == NULL) 394177633Sdfr goto out; 395177633Sdfr 396177633Sdfr switch (af) { 397177633Sdfr case AF_INET: 398177633Sdfr sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC, 399177633Sdfr M_WAITOK); 400177633Sdfr if (sin == NULL) 401177633Sdfr goto out; 402177633Sdfr memset(sin, 0, sizeof *sin); 403177633Sdfr sin->sin_family = AF_INET; 404177633Sdfr sin->sin_port = htons(port); 405213103Sattilio if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { 406177633Sdfr free(sin, M_RPC); 407177633Sdfr free(ret, M_RPC); 408177633Sdfr ret = NULL; 409177633Sdfr goto out; 410177633Sdfr } 411177633Sdfr sin->sin_len = ret->maxlen = ret->len = sizeof *sin; 412177633Sdfr ret->buf = sin; 413177633Sdfr break; 414177633Sdfr#ifdef INET6 415177633Sdfr case AF_INET6: 416177633Sdfr sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC, 417177633Sdfr M_WAITOK); 418177633Sdfr if (sin6 == NULL) 419177633Sdfr goto out; 420177633Sdfr memset(sin6, 0, sizeof *sin6); 421177633Sdfr sin6->sin6_family = AF_INET6; 422177633Sdfr sin6->sin6_port = htons(port); 423213103Sattilio if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 424177633Sdfr free(sin6, M_RPC); 425177633Sdfr free(ret, M_RPC); 426177633Sdfr ret = NULL; 427177633Sdfr goto out; 428177633Sdfr } 429177633Sdfr sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 430177633Sdfr ret->buf = sin6; 431177633Sdfr break; 432177633Sdfr#endif 433177633Sdfr case AF_LOCAL: 434177633Sdfr sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC, 435177633Sdfr M_WAITOK); 436177633Sdfr if (sun == NULL) 437177633Sdfr goto out; 438177633Sdfr memset(sun, 0, sizeof *sun); 439177633Sdfr sun->sun_family = AF_LOCAL; 440177633Sdfr strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 441177633Sdfr ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); 442177633Sdfr ret->buf = sun; 443177633Sdfr break; 444177633Sdfr default: 445177633Sdfr break; 446177633Sdfr } 447177633Sdfrout: 448177633Sdfr free(addrstr, M_RPC); 449177633Sdfr return ret; 450177633Sdfr} 451177633Sdfr 452177633Sdfrint 453177633Sdfr__rpc_seman2socktype(int semantics) 454177633Sdfr{ 455177633Sdfr switch (semantics) { 456177633Sdfr case NC_TPI_CLTS: 457177633Sdfr return SOCK_DGRAM; 458177633Sdfr case NC_TPI_COTS_ORD: 459177633Sdfr return SOCK_STREAM; 460177633Sdfr case NC_TPI_RAW: 461177633Sdfr return SOCK_RAW; 462177633Sdfr default: 463177633Sdfr break; 464177633Sdfr } 465177633Sdfr 466177633Sdfr return -1; 467177633Sdfr} 468177633Sdfr 469177633Sdfrint 470177633Sdfr__rpc_socktype2seman(int socktype) 471177633Sdfr{ 472177633Sdfr switch (socktype) { 473177633Sdfr case SOCK_DGRAM: 474177633Sdfr return NC_TPI_CLTS; 475177633Sdfr case SOCK_STREAM: 476177633Sdfr return NC_TPI_COTS_ORD; 477177633Sdfr case SOCK_RAW: 478177633Sdfr return NC_TPI_RAW; 479177633Sdfr default: 480177633Sdfr break; 481177633Sdfr } 482177633Sdfr 483177633Sdfr return -1; 484177633Sdfr} 485177633Sdfr 486177633Sdfr/* 487177633Sdfr * Returns the type of the network as defined in <rpc/nettype.h> 488177633Sdfr * If nettype is NULL, it defaults to NETPATH. 489177633Sdfr */ 490177633Sdfrstatic int 491177633Sdfrgetnettype(const char *nettype) 492177633Sdfr{ 493177633Sdfr int i; 494177633Sdfr 495177633Sdfr if ((nettype == NULL) || (nettype[0] == 0)) { 496177633Sdfr return (_RPC_NETPATH); /* Default */ 497177633Sdfr } 498177633Sdfr 499177633Sdfr#if 0 500177633Sdfr nettype = strlocase(nettype); 501177633Sdfr#endif 502177633Sdfr for (i = 0; _rpctypelist[i].name; i++) 503177633Sdfr if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 504177633Sdfr return (_rpctypelist[i].type); 505177633Sdfr } 506177633Sdfr return (_rpctypelist[i].type); 507177633Sdfr} 508177633Sdfr 509177633Sdfr/* 510177633Sdfr * For the given nettype (tcp or udp only), return the first structure found. 511177633Sdfr * This should be freed by calling freenetconfigent() 512177633Sdfr */ 513177633Sdfrstruct netconfig * 514177633Sdfr__rpc_getconfip(const char *nettype) 515177633Sdfr{ 516177633Sdfr char *netid; 517177633Sdfr static char *netid_tcp = (char *) NULL; 518177633Sdfr static char *netid_udp = (char *) NULL; 519177633Sdfr struct netconfig *dummy; 520177633Sdfr 521177633Sdfr if (!netid_udp && !netid_tcp) { 522177633Sdfr struct netconfig *nconf; 523177633Sdfr void *confighandle; 524177633Sdfr 525177633Sdfr if (!(confighandle = setnetconfig())) { 526177633Sdfr log(LOG_ERR, "rpc: failed to open " NETCONFIG); 527177633Sdfr return (NULL); 528177633Sdfr } 529177633Sdfr while ((nconf = getnetconfig(confighandle)) != NULL) { 530177633Sdfr if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 531177633Sdfr if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 532177633Sdfr netid_tcp = strdup(nconf->nc_netid, 533177633Sdfr M_RPC); 534177633Sdfr } else 535177633Sdfr if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 536177633Sdfr netid_udp = strdup(nconf->nc_netid, 537177633Sdfr M_RPC); 538177633Sdfr } 539177633Sdfr } 540177633Sdfr } 541177633Sdfr endnetconfig(confighandle); 542177633Sdfr } 543177633Sdfr if (strcmp(nettype, "udp") == 0) 544177633Sdfr netid = netid_udp; 545177633Sdfr else if (strcmp(nettype, "tcp") == 0) 546177633Sdfr netid = netid_tcp; 547177633Sdfr else { 548177633Sdfr return (NULL); 549177633Sdfr } 550177633Sdfr if ((netid == NULL) || (netid[0] == 0)) { 551177633Sdfr return (NULL); 552177633Sdfr } 553177633Sdfr dummy = getnetconfigent(netid); 554177633Sdfr return (dummy); 555177633Sdfr} 556177633Sdfr 557177633Sdfr/* 558177633Sdfr * Returns the type of the nettype, which should then be used with 559177633Sdfr * __rpc_getconf(). 560177633Sdfr * 561177633Sdfr * For simplicity in the kernel, we don't support the NETPATH 562177633Sdfr * environment variable. We behave as userland would then NETPATH is 563177633Sdfr * unset, i.e. iterate over all visible entries in netconfig. 564177633Sdfr */ 565177633Sdfrvoid * 566177633Sdfr__rpc_setconf(nettype) 567177633Sdfr const char *nettype; 568177633Sdfr{ 569177633Sdfr struct handle *handle; 570177633Sdfr 571177633Sdfr handle = (struct handle *) malloc(sizeof (struct handle), 572177633Sdfr M_RPC, M_WAITOK); 573177633Sdfr switch (handle->nettype = getnettype(nettype)) { 574177633Sdfr case _RPC_NETPATH: 575177633Sdfr case _RPC_CIRCUIT_N: 576177633Sdfr case _RPC_DATAGRAM_N: 577177633Sdfr if (!(handle->nhandle = setnetconfig())) 578177633Sdfr goto failed; 579177633Sdfr handle->nflag = TRUE; 580177633Sdfr break; 581177633Sdfr case _RPC_VISIBLE: 582177633Sdfr case _RPC_CIRCUIT_V: 583177633Sdfr case _RPC_DATAGRAM_V: 584177633Sdfr case _RPC_TCP: 585177633Sdfr case _RPC_UDP: 586177633Sdfr if (!(handle->nhandle = setnetconfig())) { 587177633Sdfr log(LOG_ERR, "rpc: failed to open " NETCONFIG); 588177633Sdfr goto failed; 589177633Sdfr } 590177633Sdfr handle->nflag = FALSE; 591177633Sdfr break; 592177633Sdfr default: 593177633Sdfr goto failed; 594177633Sdfr } 595177633Sdfr 596177633Sdfr return (handle); 597177633Sdfr 598177633Sdfrfailed: 599177633Sdfr free(handle, M_RPC); 600177633Sdfr return (NULL); 601177633Sdfr} 602177633Sdfr 603177633Sdfr/* 604177633Sdfr * Returns the next netconfig struct for the given "net" type. 605177633Sdfr * __rpc_setconf() should have been called previously. 606177633Sdfr */ 607177633Sdfrstruct netconfig * 608177633Sdfr__rpc_getconf(void *vhandle) 609177633Sdfr{ 610177633Sdfr struct handle *handle; 611177633Sdfr struct netconfig *nconf; 612177633Sdfr 613177633Sdfr handle = (struct handle *)vhandle; 614177633Sdfr if (handle == NULL) { 615177633Sdfr return (NULL); 616177633Sdfr } 617177633Sdfr for (;;) { 618177633Sdfr if (handle->nflag) { 619177633Sdfr nconf = getnetconfig(handle->nhandle); 620177633Sdfr if (nconf && !(nconf->nc_flag & NC_VISIBLE)) 621177633Sdfr continue; 622177633Sdfr } else { 623177633Sdfr nconf = getnetconfig(handle->nhandle); 624177633Sdfr } 625177633Sdfr if (nconf == NULL) 626177633Sdfr break; 627177633Sdfr if ((nconf->nc_semantics != NC_TPI_CLTS) && 628177633Sdfr (nconf->nc_semantics != NC_TPI_COTS) && 629177633Sdfr (nconf->nc_semantics != NC_TPI_COTS_ORD)) 630177633Sdfr continue; 631177633Sdfr switch (handle->nettype) { 632177633Sdfr case _RPC_VISIBLE: 633177633Sdfr if (!(nconf->nc_flag & NC_VISIBLE)) 634177633Sdfr continue; 635177633Sdfr /* FALLTHROUGH */ 636177633Sdfr case _RPC_NETPATH: /* Be happy */ 637177633Sdfr break; 638177633Sdfr case _RPC_CIRCUIT_V: 639177633Sdfr if (!(nconf->nc_flag & NC_VISIBLE)) 640177633Sdfr continue; 641177633Sdfr /* FALLTHROUGH */ 642177633Sdfr case _RPC_CIRCUIT_N: 643177633Sdfr if ((nconf->nc_semantics != NC_TPI_COTS) && 644177633Sdfr (nconf->nc_semantics != NC_TPI_COTS_ORD)) 645177633Sdfr continue; 646177633Sdfr break; 647177633Sdfr case _RPC_DATAGRAM_V: 648177633Sdfr if (!(nconf->nc_flag & NC_VISIBLE)) 649177633Sdfr continue; 650177633Sdfr /* FALLTHROUGH */ 651177633Sdfr case _RPC_DATAGRAM_N: 652177633Sdfr if (nconf->nc_semantics != NC_TPI_CLTS) 653177633Sdfr continue; 654177633Sdfr break; 655177633Sdfr case _RPC_TCP: 656177633Sdfr if (((nconf->nc_semantics != NC_TPI_COTS) && 657177633Sdfr (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 658177633Sdfr (strcmp(nconf->nc_protofmly, NC_INET) 659177633Sdfr#ifdef INET6 660177633Sdfr && strcmp(nconf->nc_protofmly, NC_INET6)) 661177633Sdfr#else 662177633Sdfr ) 663177633Sdfr#endif 664177633Sdfr || 665177633Sdfr strcmp(nconf->nc_proto, NC_TCP)) 666177633Sdfr continue; 667177633Sdfr break; 668177633Sdfr case _RPC_UDP: 669177633Sdfr if ((nconf->nc_semantics != NC_TPI_CLTS) || 670177633Sdfr (strcmp(nconf->nc_protofmly, NC_INET) 671177633Sdfr#ifdef INET6 672177633Sdfr && strcmp(nconf->nc_protofmly, NC_INET6)) 673177633Sdfr#else 674177633Sdfr ) 675177633Sdfr#endif 676177633Sdfr || 677177633Sdfr strcmp(nconf->nc_proto, NC_UDP)) 678177633Sdfr continue; 679177633Sdfr break; 680177633Sdfr } 681177633Sdfr break; 682177633Sdfr } 683177633Sdfr return (nconf); 684177633Sdfr} 685177633Sdfr 686177633Sdfrvoid 687177633Sdfr__rpc_endconf(vhandle) 688177633Sdfr void * vhandle; 689177633Sdfr{ 690177633Sdfr struct handle *handle; 691177633Sdfr 692177633Sdfr handle = (struct handle *) vhandle; 693177633Sdfr if (handle == NULL) { 694177633Sdfr return; 695177633Sdfr } 696177633Sdfr endnetconfig(handle->nhandle); 697177633Sdfr free(handle, M_RPC); 698177633Sdfr} 699177633Sdfr 700177633Sdfrint 701177633Sdfr__rpc_sockisbound(struct socket *so) 702177633Sdfr{ 703177633Sdfr struct sockaddr *sa; 704177633Sdfr int error, bound; 705177633Sdfr 706177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 707177633Sdfr if (error) 708177633Sdfr return (0); 709177633Sdfr 710177633Sdfr switch (sa->sa_family) { 711177633Sdfr case AF_INET: 712177633Sdfr bound = (((struct sockaddr_in *) sa)->sin_port != 0); 713177633Sdfr break; 714177633Sdfr#ifdef INET6 715177633Sdfr case AF_INET6: 716177633Sdfr bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0); 717177633Sdfr break; 718177633Sdfr#endif 719177633Sdfr case AF_LOCAL: 720177633Sdfr /* XXX check this */ 721177633Sdfr bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0'); 722177633Sdfr break; 723177633Sdfr default: 724177633Sdfr bound = FALSE; 725177633Sdfr break; 726177633Sdfr } 727177633Sdfr 728177633Sdfr free(sa, M_SONAME); 729177633Sdfr 730177633Sdfr return bound; 731177633Sdfr} 732177662Sdfr 733177662Sdfr/* 734184588Sdfr * Implement XDR-style API for RPC call. 735184588Sdfr */ 736184588Sdfrenum clnt_stat 737184588Sdfrclnt_call_private( 738184588Sdfr CLIENT *cl, /* client handle */ 739184588Sdfr struct rpc_callextra *ext, /* call metadata */ 740184588Sdfr rpcproc_t proc, /* procedure number */ 741184588Sdfr xdrproc_t xargs, /* xdr routine for args */ 742184588Sdfr void *argsp, /* pointer to args */ 743184588Sdfr xdrproc_t xresults, /* xdr routine for results */ 744184588Sdfr void *resultsp, /* pointer to results */ 745184588Sdfr struct timeval utimeout) /* seconds to wait before giving up */ 746184588Sdfr{ 747184588Sdfr XDR xdrs; 748184588Sdfr struct mbuf *mreq; 749184588Sdfr struct mbuf *mrep; 750184588Sdfr enum clnt_stat stat; 751184588Sdfr 752184588Sdfr MGET(mreq, M_WAIT, MT_DATA); 753184588Sdfr MCLGET(mreq, M_WAIT); 754184588Sdfr mreq->m_len = 0; 755184588Sdfr 756184588Sdfr xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 757184588Sdfr if (!xargs(&xdrs, argsp)) { 758184588Sdfr m_freem(mreq); 759184588Sdfr return (RPC_CANTENCODEARGS); 760184588Sdfr } 761184588Sdfr XDR_DESTROY(&xdrs); 762184588Sdfr 763184588Sdfr stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout); 764184588Sdfr m_freem(mreq); 765184588Sdfr 766184588Sdfr if (stat == RPC_SUCCESS) { 767184588Sdfr xdrmbuf_create(&xdrs, mrep, XDR_DECODE); 768184588Sdfr if (!xresults(&xdrs, resultsp)) { 769184588Sdfr XDR_DESTROY(&xdrs); 770184588Sdfr return (RPC_CANTDECODERES); 771184588Sdfr } 772184588Sdfr XDR_DESTROY(&xdrs); 773184588Sdfr } 774184588Sdfr 775184588Sdfr return (stat); 776184588Sdfr} 777184588Sdfr 778184588Sdfr/* 779184588Sdfr * Bind a socket to a privileged IP port 780184588Sdfr */ 781184588Sdfrint 782184588Sdfrbindresvport(struct socket *so, struct sockaddr *sa) 783184588Sdfr{ 784184588Sdfr int old, error, af; 785184588Sdfr bool_t freesa = FALSE; 786184588Sdfr struct sockaddr_in *sin; 787184588Sdfr#ifdef INET6 788184588Sdfr struct sockaddr_in6 *sin6; 789184588Sdfr#endif 790184588Sdfr struct sockopt opt; 791184588Sdfr int proto, portrange, portlow; 792184588Sdfr u_int16_t *portp; 793184588Sdfr socklen_t salen; 794184588Sdfr 795184588Sdfr if (sa == NULL) { 796184588Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 797184588Sdfr if (error) 798184588Sdfr return (error); 799184588Sdfr freesa = TRUE; 800184588Sdfr af = sa->sa_family; 801184588Sdfr salen = sa->sa_len; 802184588Sdfr memset(sa, 0, sa->sa_len); 803184588Sdfr } else { 804184588Sdfr af = sa->sa_family; 805184588Sdfr salen = sa->sa_len; 806184588Sdfr } 807184588Sdfr 808184588Sdfr switch (af) { 809184588Sdfr case AF_INET: 810184588Sdfr proto = IPPROTO_IP; 811184588Sdfr portrange = IP_PORTRANGE; 812184588Sdfr portlow = IP_PORTRANGE_LOW; 813184588Sdfr sin = (struct sockaddr_in *)sa; 814184588Sdfr portp = &sin->sin_port; 815184588Sdfr break; 816184588Sdfr#ifdef INET6 817184588Sdfr case AF_INET6: 818184588Sdfr proto = IPPROTO_IPV6; 819184588Sdfr portrange = IPV6_PORTRANGE; 820184588Sdfr portlow = IPV6_PORTRANGE_LOW; 821184588Sdfr sin6 = (struct sockaddr_in6 *)sa; 822184588Sdfr portp = &sin6->sin6_port; 823184588Sdfr break; 824184588Sdfr#endif 825184588Sdfr default: 826184588Sdfr return (EPFNOSUPPORT); 827184588Sdfr } 828184588Sdfr 829184588Sdfr sa->sa_family = af; 830184588Sdfr sa->sa_len = salen; 831184588Sdfr 832184588Sdfr if (*portp == 0) { 833184588Sdfr bzero(&opt, sizeof(opt)); 834184588Sdfr opt.sopt_dir = SOPT_GET; 835184588Sdfr opt.sopt_level = proto; 836184588Sdfr opt.sopt_name = portrange; 837184588Sdfr opt.sopt_val = &old; 838184588Sdfr opt.sopt_valsize = sizeof(old); 839184588Sdfr error = sogetopt(so, &opt); 840196503Szec if (error) { 841184588Sdfr goto out; 842196503Szec } 843184588Sdfr 844184588Sdfr opt.sopt_dir = SOPT_SET; 845184588Sdfr opt.sopt_val = &portlow; 846184588Sdfr error = sosetopt(so, &opt); 847184588Sdfr if (error) 848184588Sdfr goto out; 849184588Sdfr } 850184588Sdfr 851184588Sdfr error = sobind(so, sa, curthread); 852184588Sdfr 853184588Sdfr if (*portp == 0) { 854184588Sdfr if (error) { 855184588Sdfr opt.sopt_dir = SOPT_SET; 856184588Sdfr opt.sopt_val = &old; 857184588Sdfr sosetopt(so, &opt); 858184588Sdfr } 859184588Sdfr } 860184588Sdfrout: 861184588Sdfr if (freesa) 862184588Sdfr free(sa, M_SONAME); 863184588Sdfr 864184588Sdfr return (error); 865184588Sdfr} 866184588Sdfr 867184588Sdfr/* 868177662Sdfr * Kernel module glue 869177662Sdfr */ 870177662Sdfrstatic int 871177662Sdfrkrpc_modevent(module_t mod, int type, void *data) 872177662Sdfr{ 873177662Sdfr 874177662Sdfr return (0); 875177662Sdfr} 876177662Sdfrstatic moduledata_t krpc_mod = { 877177662Sdfr "krpc", 878177662Sdfr krpc_modevent, 879177662Sdfr NULL, 880177662Sdfr}; 881177662SdfrDECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY); 882177662Sdfr 883177662Sdfr/* So that loader and kldload(2) can find us, wherever we are.. */ 884177662SdfrMODULE_VERSION(krpc, 1); 885