FreeBSD/Linux Kernel Cross Reference
sys/rpc/rpc_generic.c
1 /* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */
2
3 /*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part. Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California 94043
30 */
31 /*
32 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
33 */
34
35 /* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 /*
40 * rpc_generic.c, Miscl routines for RPC.
41 *
42 */
43
44 #include "opt_inet6.h"
45
46 #include <sys/param.h>
47 #include <sys/kernel.h>
48 #include <sys/malloc.h>
49 #include <sys/mbuf.h>
50 #include <sys/module.h>
51 #include <sys/proc.h>
52 #include <sys/protosw.h>
53 #include <sys/sbuf.h>
54 #include <sys/systm.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/syslog.h>
58
59 #include <net/vnet.h>
60
61 #include <rpc/rpc.h>
62 #include <rpc/nettype.h>
63 #include <rpc/rpcsec_gss.h>
64
65 #include <rpc/rpc_com.h>
66
67 extern u_long sb_max_adj; /* not defined in socketvar.h */
68
69 #if __FreeBSD_version < 700000
70 #define strrchr rindex
71 #endif
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(af)
147 int af;
148 {
149 switch (af) {
150 case AF_INET:
151 return sizeof (struct sockaddr_in);
152 #ifdef INET6
153 case AF_INET6:
154 return sizeof (struct sockaddr_in6);
155 #endif
156 case AF_LOCAL:
157 return sizeof (struct sockaddr_un);
158 default:
159 break;
160 }
161 return ((u_int)RPC_MAXADDRSIZE);
162 }
163
164 #if 0
165
166 /*
167 * Used to ping the NULL procedure for clnt handle.
168 * Returns NULL if fails, else a non-NULL pointer.
169 */
170 void *
171 rpc_nullproc(clnt)
172 CLIENT *clnt;
173 {
174 struct timeval TIMEOUT = {25, 0};
175
176 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
177 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
178 return (NULL);
179 }
180 return ((void *) clnt);
181 }
182
183 #endif
184
185 int
186 __rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip)
187 {
188 int type, proto;
189 struct sockaddr *sa;
190 sa_family_t family;
191 struct sockopt opt;
192 int error;
193
194 CURVNET_SET(so->so_vnet);
195 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
196 CURVNET_RESTORE();
197 if (error)
198 return 0;
199
200 sip->si_alen = sa->sa_len;
201 family = sa->sa_family;
202 free(sa, M_SONAME);
203
204 opt.sopt_dir = SOPT_GET;
205 opt.sopt_level = SOL_SOCKET;
206 opt.sopt_name = SO_TYPE;
207 opt.sopt_val = &type;
208 opt.sopt_valsize = sizeof type;
209 opt.sopt_td = NULL;
210 error = sogetopt(so, &opt);
211 if (error)
212 return 0;
213
214 /* XXX */
215 if (family != AF_LOCAL) {
216 if (type == SOCK_STREAM)
217 proto = IPPROTO_TCP;
218 else if (type == SOCK_DGRAM)
219 proto = IPPROTO_UDP;
220 else
221 return 0;
222 } else
223 proto = 0;
224
225 sip->si_af = family;
226 sip->si_proto = proto;
227 sip->si_socktype = type;
228
229 return 1;
230 }
231
232 /*
233 * Linear search, but the number of entries is small.
234 */
235 int
236 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
237 {
238 int i;
239
240 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
241 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
242 strcmp(nconf->nc_netid, "unix") == 0 &&
243 strcmp(na_cvt[i].netid, "local") == 0)) {
244 sip->si_af = na_cvt[i].af;
245 sip->si_proto = na_cvt[i].protocol;
246 sip->si_socktype =
247 __rpc_seman2socktype((int)nconf->nc_semantics);
248 if (sip->si_socktype == -1)
249 return 0;
250 sip->si_alen = __rpc_get_a_size(sip->si_af);
251 return 1;
252 }
253
254 return 0;
255 }
256
257 struct socket *
258 __rpc_nconf2socket(const struct netconfig *nconf)
259 {
260 struct __rpc_sockinfo si;
261 struct socket *so;
262 int error;
263
264 if (!__rpc_nconf2sockinfo(nconf, &si))
265 return 0;
266
267 so = NULL;
268 error = socreate(si.si_af, &so, si.si_socktype, si.si_proto,
269 curthread->td_ucred, curthread);
270
271 if (error)
272 return NULL;
273 else
274 return so;
275 }
276
277 char *
278 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
279 {
280 struct __rpc_sockinfo si;
281
282 if (!__rpc_nconf2sockinfo(nconf, &si))
283 return NULL;
284 return __rpc_taddr2uaddr_af(si.si_af, nbuf);
285 }
286
287 struct netbuf *
288 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
289 {
290 struct __rpc_sockinfo si;
291
292 if (!__rpc_nconf2sockinfo(nconf, &si))
293 return NULL;
294 return __rpc_uaddr2taddr_af(si.si_af, uaddr);
295 }
296
297 char *
298 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
299 {
300 char *ret;
301 struct sbuf sb;
302 struct sockaddr_in *sin;
303 struct sockaddr_un *sun;
304 char namebuf[INET_ADDRSTRLEN];
305 #ifdef INET6
306 struct sockaddr_in6 *sin6;
307 char namebuf6[INET6_ADDRSTRLEN];
308 #endif
309 u_int16_t port;
310
311 sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND);
312
313 switch (af) {
314 case AF_INET:
315 sin = nbuf->buf;
316 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
317 == NULL)
318 return NULL;
319 port = ntohs(sin->sin_port);
320 if (sbuf_printf(&sb, "%s.%u.%u", namebuf,
321 ((uint32_t)port) >> 8,
322 port & 0xff) < 0)
323 return NULL;
324 break;
325 #ifdef INET6
326 case AF_INET6:
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 addrstr = strdup(uaddr, M_RPC);
371 if (addrstr == NULL)
372 return NULL;
373
374 /*
375 * AF_LOCAL addresses are expected to be absolute
376 * pathnames, anything else will be AF_INET or AF_INET6.
377 */
378 if (*addrstr != '/') {
379 p = strrchr(addrstr, '.');
380 if (p == NULL)
381 goto out;
382 portlo = (unsigned)strtol(p + 1, NULL, 10);
383 *p = '\0';
384
385 p = strrchr(addrstr, '.');
386 if (p == NULL)
387 goto out;
388 porthi = (unsigned)strtol(p + 1, NULL, 10);
389 *p = '\0';
390 port = (porthi << 8) | portlo;
391 }
392
393 ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK);
394 if (ret == NULL)
395 goto out;
396
397 switch (af) {
398 case AF_INET:
399 sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC,
400 M_WAITOK);
401 if (sin == NULL)
402 goto out;
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 if (sin6 == NULL)
420 goto out;
421 memset(sin6, 0, sizeof *sin6);
422 sin6->sin6_family = AF_INET6;
423 sin6->sin6_port = htons(port);
424 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
425 free(sin6, M_RPC);
426 free(ret, M_RPC);
427 ret = NULL;
428 goto out;
429 }
430 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
431 ret->buf = sin6;
432 break;
433 #endif
434 case AF_LOCAL:
435 sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC,
436 M_WAITOK);
437 if (sun == NULL)
438 goto out;
439 memset(sun, 0, sizeof *sun);
440 sun->sun_family = AF_LOCAL;
441 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
442 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
443 ret->buf = sun;
444 break;
445 default:
446 break;
447 }
448 out:
449 free(addrstr, M_RPC);
450 return ret;
451 }
452
453 int
454 __rpc_seman2socktype(int semantics)
455 {
456 switch (semantics) {
457 case NC_TPI_CLTS:
458 return SOCK_DGRAM;
459 case NC_TPI_COTS_ORD:
460 return SOCK_STREAM;
461 case NC_TPI_RAW:
462 return SOCK_RAW;
463 default:
464 break;
465 }
466
467 return -1;
468 }
469
470 int
471 __rpc_socktype2seman(int socktype)
472 {
473 switch (socktype) {
474 case SOCK_DGRAM:
475 return NC_TPI_CLTS;
476 case SOCK_STREAM:
477 return NC_TPI_COTS_ORD;
478 case SOCK_RAW:
479 return NC_TPI_RAW;
480 default:
481 break;
482 }
483
484 return -1;
485 }
486
487 /*
488 * Returns the type of the network as defined in <rpc/nettype.h>
489 * If nettype is NULL, it defaults to NETPATH.
490 */
491 static int
492 getnettype(const char *nettype)
493 {
494 int i;
495
496 if ((nettype == NULL) || (nettype[0] == 0)) {
497 return (_RPC_NETPATH); /* Default */
498 }
499
500 #if 0
501 nettype = strlocase(nettype);
502 #endif
503 for (i = 0; _rpctypelist[i].name; i++)
504 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
505 return (_rpctypelist[i].type);
506 }
507 return (_rpctypelist[i].type);
508 }
509
510 /*
511 * For the given nettype (tcp or udp only), return the first structure found.
512 * This should be freed by calling freenetconfigent()
513 */
514 struct netconfig *
515 __rpc_getconfip(const char *nettype)
516 {
517 char *netid;
518 static char *netid_tcp = (char *) NULL;
519 static char *netid_udp = (char *) NULL;
520 struct netconfig *dummy;
521
522 if (!netid_udp && !netid_tcp) {
523 struct netconfig *nconf;
524 void *confighandle;
525
526 if (!(confighandle = setnetconfig())) {
527 log(LOG_ERR, "rpc: failed to open " NETCONFIG);
528 return (NULL);
529 }
530 while ((nconf = getnetconfig(confighandle)) != NULL) {
531 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
532 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
533 netid_tcp = strdup(nconf->nc_netid,
534 M_RPC);
535 } else
536 if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
537 netid_udp = strdup(nconf->nc_netid,
538 M_RPC);
539 }
540 }
541 }
542 endnetconfig(confighandle);
543 }
544 if (strcmp(nettype, "udp") == 0)
545 netid = netid_udp;
546 else if (strcmp(nettype, "tcp") == 0)
547 netid = netid_tcp;
548 else {
549 return (NULL);
550 }
551 if ((netid == NULL) || (netid[0] == 0)) {
552 return (NULL);
553 }
554 dummy = getnetconfigent(netid);
555 return (dummy);
556 }
557
558 /*
559 * Returns the type of the nettype, which should then be used with
560 * __rpc_getconf().
561 *
562 * For simplicity in the kernel, we don't support the NETPATH
563 * environment variable. We behave as userland would then NETPATH is
564 * unset, i.e. iterate over all visible entries in netconfig.
565 */
566 void *
567 __rpc_setconf(nettype)
568 const char *nettype;
569 {
570 struct handle *handle;
571
572 handle = (struct handle *) malloc(sizeof (struct handle),
573 M_RPC, M_WAITOK);
574 switch (handle->nettype = getnettype(nettype)) {
575 case _RPC_NETPATH:
576 case _RPC_CIRCUIT_N:
577 case _RPC_DATAGRAM_N:
578 if (!(handle->nhandle = setnetconfig()))
579 goto failed;
580 handle->nflag = TRUE;
581 break;
582 case _RPC_VISIBLE:
583 case _RPC_CIRCUIT_V:
584 case _RPC_DATAGRAM_V:
585 case _RPC_TCP:
586 case _RPC_UDP:
587 if (!(handle->nhandle = setnetconfig())) {
588 log(LOG_ERR, "rpc: failed to open " NETCONFIG);
589 goto failed;
590 }
591 handle->nflag = FALSE;
592 break;
593 default:
594 goto failed;
595 }
596
597 return (handle);
598
599 failed:
600 free(handle, M_RPC);
601 return (NULL);
602 }
603
604 /*
605 * Returns the next netconfig struct for the given "net" type.
606 * __rpc_setconf() should have been called previously.
607 */
608 struct netconfig *
609 __rpc_getconf(void *vhandle)
610 {
611 struct handle *handle;
612 struct netconfig *nconf;
613
614 handle = (struct handle *)vhandle;
615 if (handle == NULL) {
616 return (NULL);
617 }
618 for (;;) {
619 if (handle->nflag) {
620 nconf = getnetconfig(handle->nhandle);
621 if (nconf && !(nconf->nc_flag & NC_VISIBLE))
622 continue;
623 } else {
624 nconf = getnetconfig(handle->nhandle);
625 }
626 if (nconf == NULL)
627 break;
628 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
629 (nconf->nc_semantics != NC_TPI_COTS) &&
630 (nconf->nc_semantics != NC_TPI_COTS_ORD))
631 continue;
632 switch (handle->nettype) {
633 case _RPC_VISIBLE:
634 if (!(nconf->nc_flag & NC_VISIBLE))
635 continue;
636 /* FALLTHROUGH */
637 case _RPC_NETPATH: /* Be happy */
638 break;
639 case _RPC_CIRCUIT_V:
640 if (!(nconf->nc_flag & NC_VISIBLE))
641 continue;
642 /* FALLTHROUGH */
643 case _RPC_CIRCUIT_N:
644 if ((nconf->nc_semantics != NC_TPI_COTS) &&
645 (nconf->nc_semantics != NC_TPI_COTS_ORD))
646 continue;
647 break;
648 case _RPC_DATAGRAM_V:
649 if (!(nconf->nc_flag & NC_VISIBLE))
650 continue;
651 /* FALLTHROUGH */
652 case _RPC_DATAGRAM_N:
653 if (nconf->nc_semantics != NC_TPI_CLTS)
654 continue;
655 break;
656 case _RPC_TCP:
657 if (((nconf->nc_semantics != NC_TPI_COTS) &&
658 (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
659 (strcmp(nconf->nc_protofmly, NC_INET)
660 #ifdef INET6
661 && strcmp(nconf->nc_protofmly, NC_INET6))
662 #else
663 )
664 #endif
665 ||
666 strcmp(nconf->nc_proto, NC_TCP))
667 continue;
668 break;
669 case _RPC_UDP:
670 if ((nconf->nc_semantics != NC_TPI_CLTS) ||
671 (strcmp(nconf->nc_protofmly, NC_INET)
672 #ifdef INET6
673 && strcmp(nconf->nc_protofmly, NC_INET6))
674 #else
675 )
676 #endif
677 ||
678 strcmp(nconf->nc_proto, NC_UDP))
679 continue;
680 break;
681 }
682 break;
683 }
684 return (nconf);
685 }
686
687 void
688 __rpc_endconf(vhandle)
689 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 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
708 if (error)
709 return (0);
710
711 switch (sa->sa_family) {
712 case AF_INET:
713 bound = (((struct sockaddr_in *) sa)->sin_port != 0);
714 break;
715 #ifdef INET6
716 case AF_INET6:
717 bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0);
718 break;
719 #endif
720 case AF_LOCAL:
721 /* XXX check this */
722 bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0');
723 break;
724 default:
725 bound = FALSE;
726 break;
727 }
728
729 free(sa, M_SONAME);
730
731 return bound;
732 }
733
734 /*
735 * Implement XDR-style API for RPC call.
736 */
737 enum clnt_stat
738 clnt_call_private(
739 CLIENT *cl, /* client handle */
740 struct rpc_callextra *ext, /* call metadata */
741 rpcproc_t proc, /* procedure number */
742 xdrproc_t xargs, /* xdr routine for args */
743 void *argsp, /* pointer to args */
744 xdrproc_t xresults, /* xdr routine for results */
745 void *resultsp, /* pointer to results */
746 struct timeval utimeout) /* seconds to wait before giving up */
747 {
748 XDR xdrs;
749 struct mbuf *mreq;
750 struct mbuf *mrep;
751 enum clnt_stat stat;
752
753 MGET(mreq, M_WAIT, MT_DATA);
754 MCLGET(mreq, M_WAIT);
755 mreq->m_len = 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 u_int16_t *portp;
794 socklen_t salen;
795
796 if (sa == NULL) {
797 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
798 if (error)
799 return (error);
800 freesa = TRUE;
801 af = sa->sa_family;
802 salen = sa->sa_len;
803 memset(sa, 0, sa->sa_len);
804 } else {
805 af = sa->sa_family;
806 salen = sa->sa_len;
807 }
808
809 switch (af) {
810 case AF_INET:
811 proto = IPPROTO_IP;
812 portrange = IP_PORTRANGE;
813 portlow = IP_PORTRANGE_LOW;
814 sin = (struct sockaddr_in *)sa;
815 portp = &sin->sin_port;
816 break;
817 #ifdef INET6
818 case AF_INET6:
819 proto = IPPROTO_IPV6;
820 portrange = IPV6_PORTRANGE;
821 portlow = IPV6_PORTRANGE_LOW;
822 sin6 = (struct sockaddr_in6 *)sa;
823 portp = &sin6->sin6_port;
824 break;
825 #endif
826 default:
827 return (EPFNOSUPPORT);
828 }
829
830 sa->sa_family = af;
831 sa->sa_len = salen;
832
833 if (*portp == 0) {
834 bzero(&opt, sizeof(opt));
835 opt.sopt_dir = SOPT_GET;
836 opt.sopt_level = proto;
837 opt.sopt_name = portrange;
838 opt.sopt_val = &old;
839 opt.sopt_valsize = sizeof(old);
840 error = sogetopt(so, &opt);
841 if (error) {
842 goto out;
843 }
844
845 opt.sopt_dir = SOPT_SET;
846 opt.sopt_val = &portlow;
847 error = sosetopt(so, &opt);
848 if (error)
849 goto out;
850 }
851
852 error = sobind(so, sa, curthread);
853
854 if (*portp == 0) {
855 if (error) {
856 opt.sopt_dir = SOPT_SET;
857 opt.sopt_val = &old;
858 sosetopt(so, &opt);
859 }
860 }
861 out:
862 if (freesa)
863 free(sa, M_SONAME);
864
865 return (error);
866 }
867
868 /*
869 * Kernel module glue
870 */
871 static int
872 krpc_modevent(module_t mod, int type, void *data)
873 {
874
875 return (0);
876 }
877 static moduledata_t krpc_mod = {
878 "krpc",
879 krpc_modevent,
880 NULL,
881 };
882 DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY);
883
884 /* So that loader and kldload(2) can find us, wherever we are.. */
885 MODULE_VERSION(krpc, 1);
Cache object: 735de1a17cdaf028e0275a0cbfdfb91b
|