xref: /freebsd/sys/rpc/rpc_generic.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*	$NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Copyright (c) 2009, Sun Microsystems, Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  * - Redistributions of source code must retain the above copyright notice,
12  *   this list of conditions and the following disclaimer.
13  * - Redistributions in binary form must reproduce the above copyright notice,
14  *   this list of conditions and the following disclaimer in the documentation
15  *   and/or other materials provided with the distribution.
16  * - Neither the name of Sun Microsystems, Inc. nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  * Copyright (c) 1986-1991 by Sun Microsystems Inc.
34  */
35 
36 /* #pragma ident	"@(#)rpc_generic.c	1.17	94/04/24 SMI" */
37 #include <sys/cdefs.h>
38 /*
39  * rpc_generic.c, Miscl routines for RPC.
40  *
41  */
42 
43 #include "opt_inet6.h"
44 
45 #include <sys/param.h>
46 #include <sys/kernel.h>
47 #include <sys/malloc.h>
48 #include <sys/mbuf.h>
49 #include <sys/module.h>
50 #include <sys/proc.h>
51 #include <sys/protosw.h>
52 #include <sys/sbuf.h>
53 #include <sys/systm.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <sys/syslog.h>
57 
58 #include <net/vnet.h>
59 
60 #include <rpc/rpc.h>
61 #include <rpc/nettype.h>
62 #include <rpc/rpcsec_gss.h>
63 #include <rpc/rpcsec_tls.h>
64 
65 #include <rpc/rpc_com.h>
66 #include <rpc/krpc.h>
67 
68 #include <vm/vm.h>
69 #include <vm/pmap.h>
70 #include <vm/vm_param.h>
71 
72 extern	u_long sb_max_adj;	/* not defined in socketvar.h */
73 
74 /* Provide an entry point hook for the rpcsec_gss module. */
75 struct rpc_gss_entries	rpc_gss_entries;
76 
77 struct handle {
78 	NCONF_HANDLE *nhandle;
79 	int nflag;		/* Whether NETPATH or NETCONFIG */
80 	int nettype;
81 };
82 
83 static const struct _rpcnettype {
84 	const char *name;
85 	const int type;
86 } _rpctypelist[] = {
87 	{ "netpath", _RPC_NETPATH },
88 	{ "visible", _RPC_VISIBLE },
89 	{ "circuit_v", _RPC_CIRCUIT_V },
90 	{ "datagram_v", _RPC_DATAGRAM_V },
91 	{ "circuit_n", _RPC_CIRCUIT_N },
92 	{ "datagram_n", _RPC_DATAGRAM_N },
93 	{ "tcp", _RPC_TCP },
94 	{ "udp", _RPC_UDP },
95 	{ 0, _RPC_NONE }
96 };
97 
98 struct netid_af {
99 	const char	*netid;
100 	int		af;
101 	int		protocol;
102 };
103 
104 static const struct netid_af na_cvt[] = {
105 	{ "udp",  AF_INET,  IPPROTO_UDP },
106 	{ "tcp",  AF_INET,  IPPROTO_TCP },
107 #ifdef INET6
108 	{ "udp6", AF_INET6, IPPROTO_UDP },
109 	{ "tcp6", AF_INET6, IPPROTO_TCP },
110 #endif
111 	{ "local", AF_LOCAL, 0 }
112 };
113 
114 struct rpc_createerr rpc_createerr;
115 
116 /*
117  * Find the appropriate buffer size
118  */
119 u_int
120 /*ARGSUSED*/
121 __rpc_get_t_size(int af, int proto, int size)
122 {
123 	int defsize;
124 
125 	switch (proto) {
126 	case IPPROTO_TCP:
127 		defsize = 64 * 1024;	/* XXX */
128 		break;
129 	case IPPROTO_UDP:
130 		defsize = UDPMSGSIZE;
131 		break;
132 	default:
133 		defsize = RPC_MAXDATASIZE;
134 		break;
135 	}
136 	if (size == 0)
137 		return defsize;
138 
139 	/* Check whether the value is within the upper max limit */
140 	return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size);
141 }
142 
143 /*
144  * Find the appropriate address buffer size
145  */
146 u_int
147 __rpc_get_a_size(int af)
148 {
149 	switch (af) {
150 	case AF_INET:
151 		return sizeof (struct sockaddr_in);
152 #ifdef INET6
153 	case AF_INET6:
154 		return sizeof (struct sockaddr_in6);
155 #endif
156 	case AF_LOCAL:
157 		return sizeof (struct sockaddr_un);
158 	default:
159 		break;
160 	}
161 	return ((u_int)RPC_MAXADDRSIZE);
162 }
163 
164 #if 0
165 
166 /*
167  * Used to ping the NULL procedure for clnt handle.
168  * Returns NULL if fails, else a non-NULL pointer.
169  */
170 void *
171 rpc_nullproc(clnt)
172 	CLIENT *clnt;
173 {
174 	struct timeval TIMEOUT = {25, 0};
175 
176 	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
177 		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
178 		return (NULL);
179 	}
180 	return ((void *) clnt);
181 }
182 
183 #endif
184 
185 int
186 __rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip)
187 {
188 	int type, proto;
189 	struct sockaddr *sa;
190 	sa_family_t family;
191 	struct sockopt opt;
192 	int error;
193 
194 	CURVNET_SET(so->so_vnet);
195 	error = so->so_proto->pr_sockaddr(so, &sa);
196 	CURVNET_RESTORE();
197 	if (error)
198 		return 0;
199 
200 	sip->si_alen = sa->sa_len;
201 	family = sa->sa_family;
202 	free(sa, M_SONAME);
203 
204 	opt.sopt_dir = SOPT_GET;
205 	opt.sopt_level = SOL_SOCKET;
206 	opt.sopt_name = SO_TYPE;
207 	opt.sopt_val = &type;
208 	opt.sopt_valsize = sizeof type;
209 	opt.sopt_td = NULL;
210 	error = sogetopt(so, &opt);
211 	if (error)
212 		return 0;
213 
214 	/* XXX */
215 	if (family != AF_LOCAL) {
216 		if (type == SOCK_STREAM)
217 			proto = IPPROTO_TCP;
218 		else if (type == SOCK_DGRAM)
219 			proto = IPPROTO_UDP;
220 		else
221 			return 0;
222 	} else
223 		proto = 0;
224 
225 	sip->si_af = family;
226 	sip->si_proto = proto;
227 	sip->si_socktype = type;
228 
229 	return 1;
230 }
231 
232 /*
233  * Linear search, but the number of entries is small.
234  */
235 int
236 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
237 {
238 	int i;
239 
240 	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
241 		if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
242 		    strcmp(nconf->nc_netid, "unix") == 0 &&
243 		    strcmp(na_cvt[i].netid, "local") == 0)) {
244 			sip->si_af = na_cvt[i].af;
245 			sip->si_proto = na_cvt[i].protocol;
246 			sip->si_socktype =
247 			    __rpc_seman2socktype((int)nconf->nc_semantics);
248 			if (sip->si_socktype == -1)
249 				return 0;
250 			sip->si_alen = __rpc_get_a_size(sip->si_af);
251 			return 1;
252 		}
253 
254 	return 0;
255 }
256 
257 struct socket *
258 __rpc_nconf2socket(const struct netconfig *nconf)
259 {
260 	struct __rpc_sockinfo si;
261 	struct socket *so;
262 	int error;
263 
264 	if (!__rpc_nconf2sockinfo(nconf, &si))
265 		return 0;
266 
267 	so = NULL;
268 	error =  socreate(si.si_af, &so, si.si_socktype, si.si_proto,
269 	    curthread->td_ucred, curthread);
270 
271 	if (error)
272 		return NULL;
273 	else
274 		return so;
275 }
276 
277 char *
278 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
279 {
280 	struct __rpc_sockinfo si;
281 
282 	if (!__rpc_nconf2sockinfo(nconf, &si))
283 		return NULL;
284 	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
285 }
286 
287 struct netbuf *
288 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
289 {
290 	struct __rpc_sockinfo si;
291 
292 	if (!__rpc_nconf2sockinfo(nconf, &si))
293 		return NULL;
294 	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
295 }
296 
297 char *
298 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
299 {
300 	char *ret;
301 	struct sbuf sb;
302 	struct sockaddr_in *sin;
303 	struct sockaddr_un *sun;
304 	char namebuf[INET_ADDRSTRLEN];
305 #ifdef INET6
306 	struct sockaddr_in6 *sin6;
307 	char namebuf6[INET6_ADDRSTRLEN];
308 #endif
309 	uint16_t port;
310 
311 	sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND);
312 
313 	switch (af) {
314 	case AF_INET:
315 		if (nbuf->len < sizeof(*sin))
316 			return NULL;
317 		sin = nbuf->buf;
318 		if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
319 		    == NULL)
320 			return NULL;
321 		port = ntohs(sin->sin_port);
322 		if (sbuf_printf(&sb, "%s.%u.%u", namebuf,
323 			((uint32_t)port) >> 8,
324 			port & 0xff) < 0)
325 			return NULL;
326 		break;
327 #ifdef INET6
328 	case AF_INET6:
329 		if (nbuf->len < sizeof(*sin6))
330 			return NULL;
331 		sin6 = nbuf->buf;
332 		if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
333 		    == NULL)
334 			return NULL;
335 		port = ntohs(sin6->sin6_port);
336 		if (sbuf_printf(&sb, "%s.%u.%u", namebuf6,
337 			((uint32_t)port) >> 8,
338 			port & 0xff) < 0)
339 			return NULL;
340 		break;
341 #endif
342 	case AF_LOCAL:
343 		sun = nbuf->buf;
344 		if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len -
345 			    offsetof(struct sockaddr_un, sun_path)),
346 			sun->sun_path) < 0)
347 			return (NULL);
348 		break;
349 	default:
350 		return NULL;
351 	}
352 
353 	sbuf_finish(&sb);
354 	ret = strdup(sbuf_data(&sb), M_RPC);
355 	sbuf_delete(&sb);
356 
357 	return ret;
358 }
359 
360 struct netbuf *
361 __rpc_uaddr2taddr_af(int af, const char *uaddr)
362 {
363 	struct netbuf *ret = NULL;
364 	char *addrstr, *p;
365 	unsigned port, portlo, porthi;
366 	struct sockaddr_in *sin;
367 #ifdef INET6
368 	struct sockaddr_in6 *sin6;
369 #endif
370 	struct sockaddr_un *sun;
371 
372 	port = 0;
373 	sin = NULL;
374 
375 	if (uaddr == NULL)
376 		return NULL;
377 
378 	addrstr = strdup(uaddr, M_RPC);
379 	if (addrstr == NULL)
380 		return NULL;
381 
382 	/*
383 	 * AF_LOCAL addresses are expected to be absolute
384 	 * pathnames, anything else will be AF_INET or AF_INET6.
385 	 */
386 	if (*addrstr != '/') {
387 		p = strrchr(addrstr, '.');
388 		if (p == NULL)
389 			goto out;
390 		portlo = (unsigned)strtol(p + 1, NULL, 10);
391 		*p = '\0';
392 
393 		p = strrchr(addrstr, '.');
394 		if (p == NULL)
395 			goto out;
396 		porthi = (unsigned)strtol(p + 1, NULL, 10);
397 		*p = '\0';
398 		port = (porthi << 8) | portlo;
399 	}
400 
401 	ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK);
402 
403 	switch (af) {
404 	case AF_INET:
405 		sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC,
406 		    M_WAITOK);
407 		memset(sin, 0, sizeof *sin);
408 		sin->sin_family = AF_INET;
409 		sin->sin_port = htons(port);
410 		if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
411 			free(sin, M_RPC);
412 			free(ret, M_RPC);
413 			ret = NULL;
414 			goto out;
415 		}
416 		sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
417 		ret->buf = sin;
418 		break;
419 #ifdef INET6
420 	case AF_INET6:
421 		sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC,
422 		    M_WAITOK);
423 		memset(sin6, 0, sizeof *sin6);
424 		sin6->sin6_family = AF_INET6;
425 		sin6->sin6_port = htons(port);
426 		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
427 			free(sin6, M_RPC);
428 			free(ret, M_RPC);
429 			ret = NULL;
430 			goto out;
431 		}
432 		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
433 		ret->buf = sin6;
434 		break;
435 #endif
436 	case AF_LOCAL:
437 		sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC,
438 		    M_WAITOK);
439 		memset(sun, 0, sizeof *sun);
440 		sun->sun_family = AF_LOCAL;
441 		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
442 		ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
443 		ret->buf = sun;
444 		break;
445 	default:
446 		break;
447 	}
448 out:
449 	free(addrstr, M_RPC);
450 	return ret;
451 }
452 
453 int
454 __rpc_seman2socktype(int semantics)
455 {
456 	switch (semantics) {
457 	case NC_TPI_CLTS:
458 		return SOCK_DGRAM;
459 	case NC_TPI_COTS_ORD:
460 		return SOCK_STREAM;
461 	case NC_TPI_RAW:
462 		return SOCK_RAW;
463 	default:
464 		break;
465 	}
466 
467 	return -1;
468 }
469 
470 int
471 __rpc_socktype2seman(int socktype)
472 {
473 	switch (socktype) {
474 	case SOCK_DGRAM:
475 		return NC_TPI_CLTS;
476 	case SOCK_STREAM:
477 		return NC_TPI_COTS_ORD;
478 	case SOCK_RAW:
479 		return NC_TPI_RAW;
480 	default:
481 		break;
482 	}
483 
484 	return -1;
485 }
486 
487 /*
488  * Returns the type of the network as defined in <rpc/nettype.h>
489  * If nettype is NULL, it defaults to NETPATH.
490  */
491 static int
492 getnettype(const char *nettype)
493 {
494 	int i;
495 
496 	if ((nettype == NULL) || (nettype[0] == 0)) {
497 		return (_RPC_NETPATH);	/* Default */
498 	}
499 
500 #if 0
501 	nettype = strlocase(nettype);
502 #endif
503 	for (i = 0; _rpctypelist[i].name; i++)
504 		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
505 			return (_rpctypelist[i].type);
506 		}
507 	return (_rpctypelist[i].type);
508 }
509 
510 /*
511  * For the given nettype (tcp or udp only), return the first structure found.
512  * This should be freed by calling freenetconfigent()
513  */
514 struct netconfig *
515 __rpc_getconfip(const char *nettype)
516 {
517 	char *netid;
518 	static char *netid_tcp = (char *) NULL;
519 	static char *netid_udp = (char *) NULL;
520 	struct netconfig *dummy;
521 
522 	if (!netid_udp && !netid_tcp) {
523 		struct netconfig *nconf;
524 		void *confighandle;
525 
526 		if (!(confighandle = setnetconfig())) {
527 			log(LOG_ERR, "rpc: failed to open " NETCONFIG);
528 			return (NULL);
529 		}
530 		while ((nconf = getnetconfig(confighandle)) != NULL) {
531 			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
532 				if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
533 					netid_tcp = strdup(nconf->nc_netid,
534 					    M_RPC);
535 				} else
536 				if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
537 					netid_udp = strdup(nconf->nc_netid,
538 					    M_RPC);
539 				}
540 			}
541 		}
542 		endnetconfig(confighandle);
543 	}
544 	if (strcmp(nettype, "udp") == 0)
545 		netid = netid_udp;
546 	else if (strcmp(nettype, "tcp") == 0)
547 		netid = netid_tcp;
548 	else {
549 		return (NULL);
550 	}
551 	if ((netid == NULL) || (netid[0] == 0)) {
552 		return (NULL);
553 	}
554 	dummy = getnetconfigent(netid);
555 	return (dummy);
556 }
557 
558 /*
559  * Returns the type of the nettype, which should then be used with
560  * __rpc_getconf().
561  *
562  * For simplicity in the kernel, we don't support the NETPATH
563  * environment variable. We behave as userland would then NETPATH is
564  * unset, i.e. iterate over all visible entries in netconfig.
565  */
566 void *
567 __rpc_setconf(const char *nettype)
568 {
569 	struct handle *handle;
570 
571 	handle = (struct handle *) malloc(sizeof (struct handle),
572 	    M_RPC, M_WAITOK);
573 	switch (handle->nettype = getnettype(nettype)) {
574 	case _RPC_NETPATH:
575 	case _RPC_CIRCUIT_N:
576 	case _RPC_DATAGRAM_N:
577 		if (!(handle->nhandle = setnetconfig()))
578 			goto failed;
579 		handle->nflag = TRUE;
580 		break;
581 	case _RPC_VISIBLE:
582 	case _RPC_CIRCUIT_V:
583 	case _RPC_DATAGRAM_V:
584 	case _RPC_TCP:
585 	case _RPC_UDP:
586 		if (!(handle->nhandle = setnetconfig())) {
587 		        log(LOG_ERR, "rpc: failed to open " NETCONFIG);
588 			goto failed;
589 		}
590 		handle->nflag = FALSE;
591 		break;
592 	default:
593 		goto failed;
594 	}
595 
596 	return (handle);
597 
598 failed:
599 	free(handle, M_RPC);
600 	return (NULL);
601 }
602 
603 /*
604  * Returns the next netconfig struct for the given "net" type.
605  * __rpc_setconf() should have been called previously.
606  */
607 struct netconfig *
608 __rpc_getconf(void *vhandle)
609 {
610 	struct handle *handle;
611 	struct netconfig *nconf;
612 
613 	handle = (struct handle *)vhandle;
614 	if (handle == NULL) {
615 		return (NULL);
616 	}
617 	for (;;) {
618 		if (handle->nflag) {
619 			nconf = getnetconfig(handle->nhandle);
620 			if (nconf && !(nconf->nc_flag & NC_VISIBLE))
621 				continue;
622 		} else {
623 			nconf = getnetconfig(handle->nhandle);
624 		}
625 		if (nconf == NULL)
626 			break;
627 		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
628 			(nconf->nc_semantics != NC_TPI_COTS) &&
629 			(nconf->nc_semantics != NC_TPI_COTS_ORD))
630 			continue;
631 		switch (handle->nettype) {
632 		case _RPC_VISIBLE:
633 			if (!(nconf->nc_flag & NC_VISIBLE))
634 				continue;
635 			/* FALLTHROUGH */
636 		case _RPC_NETPATH:	/* Be happy */
637 			break;
638 		case _RPC_CIRCUIT_V:
639 			if (!(nconf->nc_flag & NC_VISIBLE))
640 				continue;
641 			/* FALLTHROUGH */
642 		case _RPC_CIRCUIT_N:
643 			if ((nconf->nc_semantics != NC_TPI_COTS) &&
644 				(nconf->nc_semantics != NC_TPI_COTS_ORD))
645 				continue;
646 			break;
647 		case _RPC_DATAGRAM_V:
648 			if (!(nconf->nc_flag & NC_VISIBLE))
649 				continue;
650 			/* FALLTHROUGH */
651 		case _RPC_DATAGRAM_N:
652 			if (nconf->nc_semantics != NC_TPI_CLTS)
653 				continue;
654 			break;
655 		case _RPC_TCP:
656 			if (((nconf->nc_semantics != NC_TPI_COTS) &&
657 				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
658 				(strcmp(nconf->nc_protofmly, NC_INET)
659 #ifdef INET6
660 				 && strcmp(nconf->nc_protofmly, NC_INET6))
661 #else
662 				)
663 #endif
664 				||
665 				strcmp(nconf->nc_proto, NC_TCP))
666 				continue;
667 			break;
668 		case _RPC_UDP:
669 			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
670 				(strcmp(nconf->nc_protofmly, NC_INET)
671 #ifdef INET6
672 				&& strcmp(nconf->nc_protofmly, NC_INET6))
673 #else
674 				)
675 #endif
676 				||
677 				strcmp(nconf->nc_proto, NC_UDP))
678 				continue;
679 			break;
680 		}
681 		break;
682 	}
683 	return (nconf);
684 }
685 
686 void
687 __rpc_endconf(void *vhandle)
688 {
689 	struct handle *handle;
690 
691 	handle = (struct handle *) vhandle;
692 	if (handle == NULL) {
693 		return;
694 	}
695 	endnetconfig(handle->nhandle);
696 	free(handle, M_RPC);
697 }
698 
699 int
700 __rpc_sockisbound(struct socket *so)
701 {
702 	struct sockaddr *sa;
703 	int error, bound;
704 
705 	CURVNET_SET(so->so_vnet);
706 	error = so->so_proto->pr_sockaddr(so, &sa);
707 	CURVNET_RESTORE();
708 	if (error)
709 		return (0);
710 
711 	switch (sa->sa_family) {
712 		case AF_INET:
713 			bound = (((struct sockaddr_in *) sa)->sin_port != 0);
714 			break;
715 #ifdef INET6
716 		case AF_INET6:
717 			bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0);
718 			break;
719 #endif
720 		case AF_LOCAL:
721 			/* XXX check this */
722 			bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0');
723 			break;
724 		default:
725 			bound = FALSE;
726 			break;
727 	}
728 
729 	free(sa, M_SONAME);
730 
731 	return bound;
732 }
733 
734 /*
735  * Implement XDR-style API for RPC call.
736  */
737 enum clnt_stat
738 clnt_call_private(
739 	CLIENT		*cl,		/* client handle */
740 	struct rpc_callextra *ext,	/* call metadata */
741 	rpcproc_t	proc,		/* procedure number */
742 	xdrproc_t	xargs,		/* xdr routine for args */
743 	void		*argsp,		/* pointer to args */
744 	xdrproc_t	xresults,	/* xdr routine for results */
745 	void		*resultsp,	/* pointer to results */
746 	struct timeval	utimeout)	/* seconds to wait before giving up */
747 {
748 	XDR xdrs;
749 	struct mbuf *mreq;
750 	struct mbuf *mrep;
751 	enum clnt_stat stat;
752 
753 	mreq = m_getcl(M_WAITOK, MT_DATA, 0);
754 
755 	xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
756 	if (!xargs(&xdrs, argsp)) {
757 		m_freem(mreq);
758 		return (RPC_CANTENCODEARGS);
759 	}
760 	XDR_DESTROY(&xdrs);
761 
762 	stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout);
763 	m_freem(mreq);
764 
765 	if (stat == RPC_SUCCESS) {
766 		xdrmbuf_create(&xdrs, mrep, XDR_DECODE);
767 		if (!xresults(&xdrs, resultsp)) {
768 			XDR_DESTROY(&xdrs);
769 			return (RPC_CANTDECODERES);
770 		}
771 		XDR_DESTROY(&xdrs);
772 	}
773 
774 	return (stat);
775 }
776 
777 /*
778  * Bind a socket to a privileged IP port
779  */
780 int
781 bindresvport(struct socket *so, struct sockaddr *sa)
782 {
783 	int old, error, af;
784 	bool_t freesa = FALSE;
785 	struct sockaddr_in *sin;
786 #ifdef INET6
787 	struct sockaddr_in6 *sin6;
788 #endif
789 	struct sockopt opt;
790 	int proto, portrange, portlow;
791 	uint16_t *portp;
792 	socklen_t salen;
793 
794 	if (sa == NULL) {
795 		CURVNET_SET(so->so_vnet);
796 		error = so->so_proto->pr_sockaddr(so, &sa);
797 		CURVNET_RESTORE();
798 		if (error)
799 			return (error);
800 		freesa = TRUE;
801 		af = sa->sa_family;
802 		salen = sa->sa_len;
803 		memset(sa, 0, sa->sa_len);
804 	} else {
805 		af = sa->sa_family;
806 		salen = sa->sa_len;
807 	}
808 
809 	switch (af) {
810 	case AF_INET:
811 		proto = IPPROTO_IP;
812 		portrange = IP_PORTRANGE;
813 		portlow = IP_PORTRANGE_LOW;
814 		sin = (struct sockaddr_in *)sa;
815 		portp = &sin->sin_port;
816 		break;
817 #ifdef INET6
818 	case AF_INET6:
819 		proto = IPPROTO_IPV6;
820 		portrange = IPV6_PORTRANGE;
821 		portlow = IPV6_PORTRANGE_LOW;
822 		sin6 = (struct sockaddr_in6 *)sa;
823 		portp = &sin6->sin6_port;
824 		break;
825 #endif
826 	default:
827 		return (EPFNOSUPPORT);
828 	}
829 
830 	sa->sa_family = af;
831 	sa->sa_len = salen;
832 
833 	if (*portp == 0) {
834 		bzero(&opt, sizeof(opt));
835 		opt.sopt_dir = SOPT_GET;
836 		opt.sopt_level = proto;
837 		opt.sopt_name = portrange;
838 		opt.sopt_val = &old;
839 		opt.sopt_valsize = sizeof(old);
840 		error = sogetopt(so, &opt);
841 		if (error) {
842 			goto out;
843 		}
844 
845 		opt.sopt_dir = SOPT_SET;
846 		opt.sopt_val = &portlow;
847 		error = sosetopt(so, &opt);
848 		if (error)
849 			goto out;
850 	}
851 
852 	error = sobind(so, sa, curthread);
853 
854 	if (*portp == 0) {
855 		if (error) {
856 			opt.sopt_dir = SOPT_SET;
857 			opt.sopt_val = &old;
858 			sosetopt(so, &opt);
859 		}
860 	}
861 out:
862 	if (freesa)
863 		free(sa, M_SONAME);
864 
865 	return (error);
866 }
867 
868 /*
869  * Make sure an mbuf list is made up entirely of ext_pgs mbufs.
870  * This is needed for sosend() when KERN_TLS is being used.
871  * (There might also be a performance improvement for certain
872  *  network interfaces that handle ext_pgs mbufs efficiently.)
873  * It expects at least one non-ext_pgs mbuf followed by zero
874  * or more ext_pgs mbufs.  It does not handle the case where
875  * non-ext_pgs mbuf(s) follow ext_pgs ones.
876  * It also performs sanity checks on the resultant list.
877  * The "mp" argument list is consumed.
878  * The "maxextsiz" argument is the upper bound on the data
879  * size for each mbuf (usually 16K for KERN_TLS).
880  */
881 struct mbuf *
882 _rpc_copym_into_ext_pgs(struct mbuf *mp, int maxextsiz)
883 {
884 	struct mbuf *m, *m2, *m3, *mhead;
885 	int tlen;
886 
887 	KASSERT((mp->m_flags & (M_EXT | M_EXTPG)) !=
888 	    (M_EXT | M_EXTPG), ("_rpc_copym_into_ext_pgs:"
889 	    " first mbuf is an ext_pgs"));
890 	/*
891 	 * Find the last non-ext_pgs mbuf and the total
892 	 * length of the non-ext_pgs mbuf(s).
893 	 * The first mbuf must always be a non-ext_pgs
894 	 * mbuf.
895 	 */
896 	tlen = mp->m_len;
897 	m2 = mp;
898 	for (m = mp->m_next; m != NULL; m = m->m_next) {
899 		if ((m->m_flags & M_EXTPG) != 0)
900 			break;
901 		tlen += m->m_len;
902 		m2 = m;
903 	}
904 
905 	/*
906 	 * Copy the non-ext_pgs mbuf(s) into an ext_pgs
907 	 * mbuf list.
908 	 */
909 	m2->m_next = NULL;
910 	mhead = mb_mapped_to_unmapped(mp, tlen, maxextsiz,
911 	    M_WAITOK, &m2);
912 
913 	/*
914 	 * Link the ext_pgs list onto the newly copied
915 	 * list and free up the non-ext_pgs mbuf(s).
916 	 */
917 	m2->m_next = m;
918 	m_freem(mp);
919 
920 	/*
921 	 * Sanity check the resultant mbuf list.  Check for and
922 	 * remove any 0 length mbufs in the list, since the
923 	 * KERN_TLS code does not expect any 0 length mbuf(s)
924 	 * in the list.
925 	 */
926 	m3 = NULL;
927 	m2 = mhead;
928 	tlen = 0;
929 	while (m2 != NULL) {
930 		KASSERT(m2->m_len >= 0, ("_rpc_copym_into_ext_pgs:"
931 		    " negative m_len"));
932 		KASSERT((m2->m_flags & (M_EXT | M_EXTPG)) ==
933 		    (M_EXT | M_EXTPG), ("_rpc_copym_into_ext_pgs:"
934 			    " non-nomap mbuf in list"));
935 		if (m2->m_len == 0) {
936 			if (m3 != NULL)
937 				m3->m_next = m2->m_next;
938 			else
939 				m = m2->m_next;
940 			m2->m_next = NULL;
941 			m_free(m2);
942 			if (m3 != NULL)
943 				m2 = m3->m_next;
944 			else
945 				m2 = m;
946 		} else {
947 			MBUF_EXT_PGS_ASSERT_SANITY(m2);
948 			m3 = m2;
949 			tlen += m2->m_len;
950 			m2 = m2->m_next;
951 		}
952 	}
953 	return (mhead);
954 }
955 
956 /*
957  * Kernel module glue
958  */
959 static int
960 krpc_modevent(module_t mod, int type, void *data)
961 {
962 	int error = 0;
963 
964 	switch (type) {
965 	case MOD_LOAD:
966 		error = rpctls_init();
967 		break;
968 	case MOD_UNLOAD:
969 		/*
970 		 * Cannot be unloaded, since the rpctlssd or rpctlscd daemons
971 		 * might be performing a rpctls syscall.
972 		 */
973 		/* FALLTHROUGH */
974 	default:
975 		error = EOPNOTSUPP;
976 	}
977 	return (error);
978 }
979 static moduledata_t krpc_mod = {
980 	"krpc",
981 	krpc_modevent,
982 	NULL,
983 };
984 DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY);
985 
986 /* So that loader and kldload(2) can find us, wherever we are.. */
987 MODULE_VERSION(krpc, 1);
988 MODULE_DEPEND(krpc, xdr, 1, 1, 1);
989