Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/rpc/rpc_generic.c
39536 views
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
rpcnl_init();
953
error = rpctls_init();
954
break;
955
case MOD_UNLOAD:
956
/*
957
* Cannot be unloaded, since the rpctlssd or rpctlscd daemons
958
* might be performing a rpctls syscall.
959
*/
960
/* FALLTHROUGH */
961
default:
962
error = EOPNOTSUPP;
963
}
964
return (error);
965
}
966
static moduledata_t krpc_mod = {
967
"krpc",
968
krpc_modevent,
969
NULL,
970
};
971
DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_FIRST);
972
973
/* So that loader and kldload(2) can find us, wherever we are.. */
974
MODULE_VERSION(krpc, 1);
975
MODULE_DEPEND(krpc, xdr, 1, 1, 1);
976
977