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