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