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*/
__rpc_get_t_size(int af,int proto,int size)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
__rpc_get_a_size(int af)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
__rpc_socket2sockinfo(struct socket * so,struct __rpc_sockinfo * sip)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
__rpc_nconf2sockinfo(const struct netconfig * nconf,struct __rpc_sockinfo * sip)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 *
__rpc_nconf2socket(const struct netconfig * nconf)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 *
taddr2uaddr(const struct netconfig * nconf,const struct netbuf * nbuf)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 *
uaddr2taddr(const struct netconfig * nconf,const char * uaddr)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 *
__rpc_taddr2uaddr_af(int af,const struct netbuf * nbuf)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 *
__rpc_uaddr2taddr_af(int af,const char * uaddr)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
__rpc_seman2socktype(int semantics)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
__rpc_socktype2seman(int socktype)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
getnettype(const char * nettype)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 *
__rpc_getconfip(const char * nettype)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 *
__rpc_setconf(const char * nettype)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 *
__rpc_getconf(void * vhandle)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
__rpc_endconf(void * vhandle)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
__rpc_sockisbound(struct socket * so)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
clnt_call_private(CLIENT * cl,struct rpc_callextra * ext,rpcproc_t proc,xdrproc_t xargs,void * argsp,xdrproc_t xresults,void * resultsp,struct timeval utimeout)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
bindresvport(struct socket * so,struct sockaddr * sa)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 *
_rpc_copym_into_ext_pgs(struct mbuf * mp,int maxextsiz)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
krpc_modevent(module_t mod,int type,void * data)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