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