]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/rpc/rpc_generic.c
Add UPDATING entries and bump version.
[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
66 #include <rpc/rpc_com.h>
67
68 extern  u_long sb_max_adj;      /* not defined in socketvar.h */
69
70 #if __FreeBSD_version < 700000
71 #define strrchr rindex
72 #endif
73
74 /* Provide an entry point hook for the rpcsec_gss module. */
75 struct rpc_gss_entries  rpc_gss_entries;
76
77 struct handle {
78         NCONF_HANDLE *nhandle;
79         int nflag;              /* Whether NETPATH or NETCONFIG */
80         int nettype;
81 };
82
83 static const struct _rpcnettype {
84         const char *name;
85         const int type;
86 } _rpctypelist[] = {
87         { "netpath", _RPC_NETPATH },
88         { "visible", _RPC_VISIBLE },
89         { "circuit_v", _RPC_CIRCUIT_V },
90         { "datagram_v", _RPC_DATAGRAM_V },
91         { "circuit_n", _RPC_CIRCUIT_N },
92         { "datagram_n", _RPC_DATAGRAM_N },
93         { "tcp", _RPC_TCP },
94         { "udp", _RPC_UDP },
95         { 0, _RPC_NONE }
96 };
97
98 struct netid_af {
99         const char      *netid;
100         int             af;
101         int             protocol;
102 };
103
104 static const struct netid_af na_cvt[] = {
105         { "udp",  AF_INET,  IPPROTO_UDP },
106         { "tcp",  AF_INET,  IPPROTO_TCP },
107 #ifdef INET6
108         { "udp6", AF_INET6, IPPROTO_UDP },
109         { "tcp6", AF_INET6, IPPROTO_TCP },
110 #endif
111         { "local", AF_LOCAL, 0 }
112 };
113
114 struct rpc_createerr rpc_createerr;
115
116 /*
117  * Find the appropriate buffer size
118  */
119 u_int
120 /*ARGSUSED*/
121 __rpc_get_t_size(int af, int proto, int size)
122 {
123         int defsize;
124
125         switch (proto) {
126         case IPPROTO_TCP:
127                 defsize = 64 * 1024;    /* XXX */
128                 break;
129         case IPPROTO_UDP:
130                 defsize = UDPMSGSIZE;
131                 break;
132         default:
133                 defsize = RPC_MAXDATASIZE;
134                 break;
135         }
136         if (size == 0)
137                 return defsize;
138
139         /* Check whether the value is within the upper max limit */
140         return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size);
141 }
142
143 /*
144  * Find the appropriate address buffer size
145  */
146 u_int
147 __rpc_get_a_size(af)
148         int af;
149 {
150         switch (af) {
151         case AF_INET:
152                 return sizeof (struct sockaddr_in);
153 #ifdef INET6
154         case AF_INET6:
155                 return sizeof (struct sockaddr_in6);
156 #endif
157         case AF_LOCAL:
158                 return sizeof (struct sockaddr_un);
159         default:
160                 break;
161         }
162         return ((u_int)RPC_MAXADDRSIZE);
163 }
164
165 #if 0
166
167 /*
168  * Used to ping the NULL procedure for clnt handle.
169  * Returns NULL if fails, else a non-NULL pointer.
170  */
171 void *
172 rpc_nullproc(clnt)
173         CLIENT *clnt;
174 {
175         struct timeval TIMEOUT = {25, 0};
176
177         if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
178                 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
179                 return (NULL);
180         }
181         return ((void *) clnt);
182 }
183
184 #endif
185
186 int
187 __rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip)
188 {
189         int type, proto;
190         struct sockaddr *sa;
191         sa_family_t family;
192         struct sockopt opt;
193         int error;
194
195         CURVNET_SET(so->so_vnet);
196         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
197         CURVNET_RESTORE();
198         if (error)
199                 return 0;
200
201         sip->si_alen = sa->sa_len;
202         family = sa->sa_family;
203         free(sa, M_SONAME);
204
205         opt.sopt_dir = SOPT_GET;
206         opt.sopt_level = SOL_SOCKET;
207         opt.sopt_name = SO_TYPE;
208         opt.sopt_val = &type;
209         opt.sopt_valsize = sizeof type;
210         opt.sopt_td = NULL;
211         error = sogetopt(so, &opt);
212         if (error)
213                 return 0;
214
215         /* XXX */
216         if (family != AF_LOCAL) {
217                 if (type == SOCK_STREAM)
218                         proto = IPPROTO_TCP;
219                 else if (type == SOCK_DGRAM)
220                         proto = IPPROTO_UDP;
221                 else
222                         return 0;
223         } else
224                 proto = 0;
225
226         sip->si_af = family;
227         sip->si_proto = proto;
228         sip->si_socktype = type;
229
230         return 1;
231 }
232
233 /*
234  * Linear search, but the number of entries is small.
235  */
236 int
237 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
238 {
239         int i;
240
241         for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
242                 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
243                     strcmp(nconf->nc_netid, "unix") == 0 &&
244                     strcmp(na_cvt[i].netid, "local") == 0)) {
245                         sip->si_af = na_cvt[i].af;
246                         sip->si_proto = na_cvt[i].protocol;
247                         sip->si_socktype =
248                             __rpc_seman2socktype((int)nconf->nc_semantics);
249                         if (sip->si_socktype == -1)
250                                 return 0;
251                         sip->si_alen = __rpc_get_a_size(sip->si_af);
252                         return 1;
253                 }
254
255         return 0;
256 }
257
258 struct socket *
259 __rpc_nconf2socket(const struct netconfig *nconf)
260 {
261         struct __rpc_sockinfo si;
262         struct socket *so;
263         int error;
264
265         if (!__rpc_nconf2sockinfo(nconf, &si))
266                 return 0;
267
268         so = NULL;
269         error =  socreate(si.si_af, &so, si.si_socktype, si.si_proto,
270             curthread->td_ucred, curthread);
271
272         if (error)
273                 return NULL;
274         else
275                 return so;
276 }
277
278 char *
279 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
280 {
281         struct __rpc_sockinfo si;
282
283         if (!__rpc_nconf2sockinfo(nconf, &si))
284                 return NULL;
285         return __rpc_taddr2uaddr_af(si.si_af, nbuf);
286 }
287
288 struct netbuf *
289 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
290 {
291         struct __rpc_sockinfo si;
292         
293         if (!__rpc_nconf2sockinfo(nconf, &si))
294                 return NULL;
295         return __rpc_uaddr2taddr_af(si.si_af, uaddr);
296 }
297
298 char *
299 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
300 {
301         char *ret;
302         struct sbuf sb;
303         struct sockaddr_in *sin;
304         struct sockaddr_un *sun;
305         char namebuf[INET_ADDRSTRLEN];
306 #ifdef INET6
307         struct sockaddr_in6 *sin6;
308         char namebuf6[INET6_ADDRSTRLEN];
309 #endif
310         u_int16_t port;
311
312         sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND);
313
314         switch (af) {
315         case AF_INET:
316                 if (nbuf->len < sizeof(*sin))
317                         return NULL;
318                 sin = nbuf->buf;
319                 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
320                     == NULL)
321                         return NULL;
322                 port = ntohs(sin->sin_port);
323                 if (sbuf_printf(&sb, "%s.%u.%u", namebuf,
324                         ((uint32_t)port) >> 8,
325                         port & 0xff) < 0)
326                         return NULL;
327                 break;
328 #ifdef INET6
329         case AF_INET6:
330                 if (nbuf->len < sizeof(*sin6))
331                         return NULL;
332                 sin6 = nbuf->buf;
333                 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
334                     == NULL)
335                         return NULL;
336                 port = ntohs(sin6->sin6_port);
337                 if (sbuf_printf(&sb, "%s.%u.%u", namebuf6,
338                         ((uint32_t)port) >> 8,
339                         port & 0xff) < 0)
340                         return NULL;
341                 break;
342 #endif
343         case AF_LOCAL:
344                 sun = nbuf->buf;
345                 if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len -
346                             offsetof(struct sockaddr_un, sun_path)),
347                         sun->sun_path) < 0)
348                         return (NULL);
349                 break;
350         default:
351                 return NULL;
352         }
353
354         sbuf_finish(&sb);
355         ret = strdup(sbuf_data(&sb), M_RPC);
356         sbuf_delete(&sb);
357
358         return ret;
359 }
360
361 struct netbuf *
362 __rpc_uaddr2taddr_af(int af, const char *uaddr)
363 {
364         struct netbuf *ret = NULL;
365         char *addrstr, *p;
366         unsigned port, portlo, porthi;
367         struct sockaddr_in *sin;
368 #ifdef INET6
369         struct sockaddr_in6 *sin6;
370 #endif
371         struct sockaddr_un *sun;
372
373         port = 0;
374         sin = NULL;
375
376         if (uaddr == NULL)
377                 return NULL;
378
379         addrstr = strdup(uaddr, M_RPC);
380         if (addrstr == NULL)
381                 return NULL;
382
383         /*
384          * AF_LOCAL addresses are expected to be absolute
385          * pathnames, anything else will be AF_INET or AF_INET6.
386          */
387         if (*addrstr != '/') {
388                 p = strrchr(addrstr, '.');
389                 if (p == NULL)
390                         goto out;
391                 portlo = (unsigned)strtol(p + 1, NULL, 10);
392                 *p = '\0';
393
394                 p = strrchr(addrstr, '.');
395                 if (p == NULL)
396                         goto out;
397                 porthi = (unsigned)strtol(p + 1, NULL, 10);
398                 *p = '\0';
399                 port = (porthi << 8) | portlo;
400         }
401
402         ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK);
403         
404         switch (af) {
405         case AF_INET:
406                 sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC,
407                     M_WAITOK);
408                 memset(sin, 0, sizeof *sin);
409                 sin->sin_family = AF_INET;
410                 sin->sin_port = htons(port);
411                 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
412                         free(sin, M_RPC);
413                         free(ret, M_RPC);
414                         ret = NULL;
415                         goto out;
416                 }
417                 sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
418                 ret->buf = sin;
419                 break;
420 #ifdef INET6
421         case AF_INET6:
422                 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC,
423                     M_WAITOK);
424                 memset(sin6, 0, sizeof *sin6);
425                 sin6->sin6_family = AF_INET6;
426                 sin6->sin6_port = htons(port);
427                 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
428                         free(sin6, M_RPC);
429                         free(ret, M_RPC);
430                         ret = NULL;
431                         goto out;
432                 }
433                 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
434                 ret->buf = sin6;
435                 break;
436 #endif
437         case AF_LOCAL:
438                 sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC,
439                     M_WAITOK);
440                 memset(sun, 0, sizeof *sun);
441                 sun->sun_family = AF_LOCAL;
442                 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
443                 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
444                 ret->buf = sun;
445                 break;
446         default:
447                 break;
448         }
449 out:
450         free(addrstr, M_RPC);
451         return ret;
452 }
453
454 int
455 __rpc_seman2socktype(int semantics)
456 {
457         switch (semantics) {
458         case NC_TPI_CLTS:
459                 return SOCK_DGRAM;
460         case NC_TPI_COTS_ORD:
461                 return SOCK_STREAM;
462         case NC_TPI_RAW:
463                 return SOCK_RAW;
464         default:
465                 break;
466         }
467
468         return -1;
469 }
470
471 int
472 __rpc_socktype2seman(int socktype)
473 {
474         switch (socktype) {
475         case SOCK_DGRAM:
476                 return NC_TPI_CLTS;
477         case SOCK_STREAM:
478                 return NC_TPI_COTS_ORD;
479         case SOCK_RAW:
480                 return NC_TPI_RAW;
481         default:
482                 break;
483         }
484
485         return -1;
486 }
487
488 /*
489  * Returns the type of the network as defined in <rpc/nettype.h>
490  * If nettype is NULL, it defaults to NETPATH.
491  */
492 static int
493 getnettype(const char *nettype)
494 {
495         int i;
496
497         if ((nettype == NULL) || (nettype[0] == 0)) {
498                 return (_RPC_NETPATH);  /* Default */
499         }
500
501 #if 0
502         nettype = strlocase(nettype);
503 #endif
504         for (i = 0; _rpctypelist[i].name; i++)
505                 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
506                         return (_rpctypelist[i].type);
507                 }
508         return (_rpctypelist[i].type);
509 }
510
511 /*
512  * For the given nettype (tcp or udp only), return the first structure found.
513  * This should be freed by calling freenetconfigent()
514  */
515 struct netconfig *
516 __rpc_getconfip(const char *nettype)
517 {
518         char *netid;
519         static char *netid_tcp = (char *) NULL;
520         static char *netid_udp = (char *) NULL;
521         struct netconfig *dummy;
522
523         if (!netid_udp && !netid_tcp) {
524                 struct netconfig *nconf;
525                 void *confighandle;
526
527                 if (!(confighandle = setnetconfig())) {
528                         log(LOG_ERR, "rpc: failed to open " NETCONFIG);
529                         return (NULL);
530                 }
531                 while ((nconf = getnetconfig(confighandle)) != NULL) {
532                         if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
533                                 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
534                                         netid_tcp = strdup(nconf->nc_netid,
535                                             M_RPC);
536                                 } else
537                                 if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
538                                         netid_udp = strdup(nconf->nc_netid,
539                                             M_RPC);
540                                 }
541                         }
542                 }
543                 endnetconfig(confighandle);
544         }
545         if (strcmp(nettype, "udp") == 0)
546                 netid = netid_udp;
547         else if (strcmp(nettype, "tcp") == 0)
548                 netid = netid_tcp;
549         else {
550                 return (NULL);
551         }
552         if ((netid == NULL) || (netid[0] == 0)) {
553                 return (NULL);
554         }
555         dummy = getnetconfigent(netid);
556         return (dummy);
557 }
558
559 /*
560  * Returns the type of the nettype, which should then be used with
561  * __rpc_getconf().
562  *
563  * For simplicity in the kernel, we don't support the NETPATH
564  * environment variable. We behave as userland would then NETPATH is
565  * unset, i.e. iterate over all visible entries in netconfig.
566  */
567 void *
568 __rpc_setconf(nettype)
569         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(vhandle)
690         void * vhandle;
691 {
692         struct handle *handle;
693
694         handle = (struct handle *) vhandle;
695         if (handle == NULL) {
696                 return;
697         }
698         endnetconfig(handle->nhandle);
699         free(handle, M_RPC);
700 }
701
702 int
703 __rpc_sockisbound(struct socket *so)
704 {
705         struct sockaddr *sa;
706         int error, bound;
707
708         CURVNET_SET(so->so_vnet);
709         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
710         CURVNET_RESTORE();
711         if (error)
712                 return (0);
713
714         switch (sa->sa_family) {
715                 case AF_INET:
716                         bound = (((struct sockaddr_in *) sa)->sin_port != 0);
717                         break;
718 #ifdef INET6
719                 case AF_INET6:
720                         bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0);
721                         break;
722 #endif
723                 case AF_LOCAL:
724                         /* XXX check this */
725                         bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0');
726                         break;
727                 default:
728                         bound = FALSE;
729                         break;
730         }
731
732         free(sa, M_SONAME);
733
734         return bound;
735 }
736
737 /*
738  * Implement XDR-style API for RPC call.
739  */
740 enum clnt_stat
741 clnt_call_private(
742         CLIENT          *cl,            /* client handle */
743         struct rpc_callextra *ext,      /* call metadata */
744         rpcproc_t       proc,           /* procedure number */
745         xdrproc_t       xargs,          /* xdr routine for args */
746         void            *argsp,         /* pointer to args */
747         xdrproc_t       xresults,       /* xdr routine for results */
748         void            *resultsp,      /* pointer to results */
749         struct timeval  utimeout)       /* seconds to wait before giving up */
750 {
751         XDR xdrs;
752         struct mbuf *mreq;
753         struct mbuf *mrep;
754         enum clnt_stat stat;
755
756         mreq = m_getcl(M_WAITOK, MT_DATA, 0);
757
758         xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
759         if (!xargs(&xdrs, argsp)) {
760                 m_freem(mreq);
761                 return (RPC_CANTENCODEARGS);
762         }
763         XDR_DESTROY(&xdrs);
764
765         stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout);
766         m_freem(mreq);
767
768         if (stat == RPC_SUCCESS) {
769                 xdrmbuf_create(&xdrs, mrep, XDR_DECODE);
770                 if (!xresults(&xdrs, resultsp)) {
771                         XDR_DESTROY(&xdrs);
772                         return (RPC_CANTDECODERES);
773                 }
774                 XDR_DESTROY(&xdrs);
775         }
776
777         return (stat);
778 }
779
780 /*
781  * Bind a socket to a privileged IP port
782  */
783 int
784 bindresvport(struct socket *so, struct sockaddr *sa)
785 {
786         int old, error, af;
787         bool_t freesa = FALSE;
788         struct sockaddr_in *sin;
789 #ifdef INET6
790         struct sockaddr_in6 *sin6;
791 #endif
792         struct sockopt opt;
793         int proto, portrange, portlow;
794         u_int16_t *portp;
795         socklen_t salen;
796
797         if (sa == NULL) {
798                 CURVNET_SET(so->so_vnet);
799                 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
800                 CURVNET_RESTORE();
801                 if (error)
802                         return (error);
803                 freesa = TRUE;
804                 af = sa->sa_family;
805                 salen = sa->sa_len;
806                 memset(sa, 0, sa->sa_len);
807         } else {
808                 af = sa->sa_family;
809                 salen = sa->sa_len;
810         }
811
812         switch (af) {
813         case AF_INET:
814                 proto = IPPROTO_IP;
815                 portrange = IP_PORTRANGE;
816                 portlow = IP_PORTRANGE_LOW;
817                 sin = (struct sockaddr_in *)sa;
818                 portp = &sin->sin_port;
819                 break;
820 #ifdef INET6
821         case AF_INET6:
822                 proto = IPPROTO_IPV6;
823                 portrange = IPV6_PORTRANGE;
824                 portlow = IPV6_PORTRANGE_LOW;
825                 sin6 = (struct sockaddr_in6 *)sa;
826                 portp = &sin6->sin6_port;
827                 break;
828 #endif
829         default:
830                 return (EPFNOSUPPORT);
831         }
832
833         sa->sa_family = af;
834         sa->sa_len = salen;
835
836         if (*portp == 0) {
837                 bzero(&opt, sizeof(opt));
838                 opt.sopt_dir = SOPT_GET;
839                 opt.sopt_level = proto;
840                 opt.sopt_name = portrange;
841                 opt.sopt_val = &old;
842                 opt.sopt_valsize = sizeof(old);
843                 error = sogetopt(so, &opt);
844                 if (error) {
845                         goto out;
846                 }
847
848                 opt.sopt_dir = SOPT_SET;
849                 opt.sopt_val = &portlow;
850                 error = sosetopt(so, &opt);
851                 if (error)
852                         goto out;
853         }
854
855         error = sobind(so, sa, curthread);
856
857         if (*portp == 0) {
858                 if (error) {
859                         opt.sopt_dir = SOPT_SET;
860                         opt.sopt_val = &old;
861                         sosetopt(so, &opt);
862                 }
863         }
864 out:
865         if (freesa)
866                 free(sa, M_SONAME);
867
868         return (error);
869 }
870
871 /*
872  * Kernel module glue
873  */
874 static int
875 krpc_modevent(module_t mod, int type, void *data)
876 {
877
878         return (0);
879 }
880 static moduledata_t krpc_mod = {
881         "krpc",
882         krpc_modevent,
883         NULL,
884 };
885 DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY);
886
887 /* So that loader and kldload(2) can find us, wherever we are.. */
888 MODULE_VERSION(krpc, 1);
889 MODULE_DEPEND(krpc, xdr, 1, 1, 1);