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