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: stable/12/lib/libc/rpc/rpc_generic.c 373281 2023-12-01 21:18:25Z asomers $");
39
40 /*
41 * rpc_generic.c, Miscl routines for RPC.
42 *
43 */
44
45 #include "namespace.h"
46 #include "reentrant.h"
47 #include <sys/param.h>
48 #include <sys/socket.h>
49 #include <sys/time.h>
50 #include <sys/un.h>
51 #include <sys/resource.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <rpc/rpc.h>
55 #include <ctype.h>
56 #include <stddef.h>
57 #include <stdio.h>
58 #include <netdb.h>
59 #include <netconfig.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <syslog.h>
63 #include <rpc/nettype.h>
64 #include "un-namespace.h"
65 #include "rpc_com.h"
66 #include "mt_misc.h"
67
68 struct handle {
69 NCONF_HANDLE *nhandle;
70 int nflag; /* Whether NETPATH or NETCONFIG */
71 int nettype;
72 };
73
74 static const struct _rpcnettype {
75 const char *name;
76 const int type;
77 } _rpctypelist[] = {
78 { "netpath", _RPC_NETPATH },
79 { "visible", _RPC_VISIBLE },
80 { "circuit_v", _RPC_CIRCUIT_V },
81 { "datagram_v", _RPC_DATAGRAM_V },
82 { "circuit_n", _RPC_CIRCUIT_N },
83 { "datagram_n", _RPC_DATAGRAM_N },
84 { "tcp", _RPC_TCP },
85 { "udp", _RPC_UDP },
86 { 0, _RPC_NONE }
87 };
88
89 struct netid_af {
90 const char *netid;
91 int af;
92 int protocol;
93 };
94
95 static const struct netid_af na_cvt[] = {
96 { "udp", AF_INET, IPPROTO_UDP },
97 { "tcp", AF_INET, IPPROTO_TCP },
98 #ifdef INET6
99 { "udp6", AF_INET6, IPPROTO_UDP },
100 { "tcp6", AF_INET6, IPPROTO_TCP },
101 #endif
102 { "local", AF_LOCAL, 0 }
103 };
104
105 #if 0
106 static char *strlocase(char *);
107 #endif
108 static int getnettype(const char *);
109
110
111 /*
112 * Find the appropriate buffer size
113 *
114 * size - Size requested
115 */
116 u_int
117 /*ARGSUSED*/
__rpc_get_t_size(int af,int proto,int size)118 __rpc_get_t_size(int af, int proto, int size)
119 {
120 int maxsize, defsize;
121
122 maxsize = 256 * 1024; /* XXX */
123 switch (proto) {
124 case IPPROTO_TCP:
125 defsize = 64 * 1024; /* XXX */
126 break;
127 case IPPROTO_UDP:
128 defsize = UDPMSGSIZE;
129 break;
130 default:
131 defsize = RPC_MAXDATASIZE;
132 break;
133 }
134 if (size == 0)
135 return defsize;
136
137 /* Check whether the value is within the upper max limit */
138 return (size > maxsize ? (u_int)maxsize : (u_int)size);
139 }
140
141 /*
142 * Find the appropriate address buffer size
143 */
144 u_int
__rpc_get_a_size(int af)145 __rpc_get_a_size(int af)
146 {
147 switch (af) {
148 case AF_INET:
149 return sizeof (struct sockaddr_in);
150 #ifdef INET6
151 case AF_INET6:
152 return sizeof (struct sockaddr_in6);
153 #endif
154 case AF_LOCAL:
155 return sizeof (struct sockaddr_un);
156 default:
157 break;
158 }
159 return ((u_int)RPC_MAXADDRSIZE);
160 }
161
162 #if 0
163 static char *
164 strlocase(char *p)
165 {
166 char *t = p;
167
168 for (; *p; p++)
169 if (isupper(*p))
170 *p = tolower(*p);
171 return (t);
172 }
173 #endif
174
175 /*
176 * Returns the type of the network as defined in <rpc/nettype.h>
177 * If nettype is NULL, it defaults to NETPATH.
178 */
179 static int
getnettype(const char * nettype)180 getnettype(const char *nettype)
181 {
182 int i;
183
184 if ((nettype == NULL) || (nettype[0] == 0)) {
185 return (_RPC_NETPATH); /* Default */
186 }
187
188 #if 0
189 nettype = strlocase(nettype);
190 #endif
191 for (i = 0; _rpctypelist[i].name; i++)
192 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
193 return (_rpctypelist[i].type);
194 }
195 return (_rpctypelist[i].type);
196 }
197
198 static thread_key_t tcp_key, udp_key;
199 static once_t keys_once = ONCE_INITIALIZER;
200 static int tcp_key_error, udp_key_error;
201
202 static void
keys_init(void)203 keys_init(void)
204 {
205
206 tcp_key_error = thr_keycreate(&tcp_key, free);
207 udp_key_error = thr_keycreate(&udp_key, free);
208 }
209
210 /*
211 * For the given nettype (tcp or udp only), return the first structure found.
212 * This should be freed by calling freenetconfigent()
213 */
214 struct netconfig *
__rpc_getconfip(const char * nettype)215 __rpc_getconfip(const char *nettype)
216 {
217 char *netid;
218 char *netid_tcp = (char *) NULL;
219 char *netid_udp = (char *) NULL;
220 static char *netid_tcp_main;
221 static char *netid_udp_main;
222 struct netconfig *dummy;
223 int main_thread;
224
225 if ((main_thread = thr_main())) {
226 netid_udp = netid_udp_main;
227 netid_tcp = netid_tcp_main;
228 } else {
229 if (thr_once(&keys_once, keys_init) != 0 ||
230 tcp_key_error != 0 || udp_key_error != 0)
231 return (NULL);
232 netid_tcp = (char *)thr_getspecific(tcp_key);
233 netid_udp = (char *)thr_getspecific(udp_key);
234 }
235 if (!netid_udp && !netid_tcp) {
236 struct netconfig *nconf;
237 void *confighandle;
238
239 if (!(confighandle = setnetconfig())) {
240 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
241 return (NULL);
242 }
243 while ((nconf = getnetconfig(confighandle)) != NULL) {
244 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
245 if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
246 netid_tcp == NULL) {
247 netid_tcp = strdup(nconf->nc_netid);
248 if (main_thread)
249 netid_tcp_main = netid_tcp;
250 else
251 thr_setspecific(tcp_key,
252 (void *) netid_tcp);
253 } else
254 if (strcmp(nconf->nc_proto, NC_UDP) == 0 &&
255 netid_udp == NULL) {
256 netid_udp = strdup(nconf->nc_netid);
257 if (main_thread)
258 netid_udp_main = netid_udp;
259 else
260 thr_setspecific(udp_key,
261 (void *) netid_udp);
262 }
263 }
264 }
265 endnetconfig(confighandle);
266 }
267 if (strcmp(nettype, "udp") == 0)
268 netid = netid_udp;
269 else if (strcmp(nettype, "tcp") == 0)
270 netid = netid_tcp;
271 else {
272 return (NULL);
273 }
274 if ((netid == NULL) || (netid[0] == 0)) {
275 return (NULL);
276 }
277 dummy = getnetconfigent(netid);
278 return (dummy);
279 }
280
281 /*
282 * Returns the type of the nettype, which should then be used with
283 * __rpc_getconf().
284 */
285 void *
__rpc_setconf(const char * nettype)286 __rpc_setconf(const char *nettype)
287 {
288 struct handle *handle;
289
290 handle = (struct handle *) malloc(sizeof (struct handle));
291 if (handle == NULL) {
292 return (NULL);
293 }
294 switch (handle->nettype = getnettype(nettype)) {
295 case _RPC_NETPATH:
296 case _RPC_CIRCUIT_N:
297 case _RPC_DATAGRAM_N:
298 if (!(handle->nhandle = setnetpath()))
299 goto failed;
300 handle->nflag = TRUE;
301 break;
302 case _RPC_VISIBLE:
303 case _RPC_CIRCUIT_V:
304 case _RPC_DATAGRAM_V:
305 case _RPC_TCP:
306 case _RPC_UDP:
307 if (!(handle->nhandle = setnetconfig())) {
308 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
309 goto failed;
310 }
311 handle->nflag = FALSE;
312 break;
313 default:
314 goto failed;
315 }
316
317 return (handle);
318
319 failed:
320 free(handle);
321 return (NULL);
322 }
323
324 /*
325 * Returns the next netconfig struct for the given "net" type.
326 * __rpc_setconf() should have been called previously.
327 */
328 struct netconfig *
__rpc_getconf(void * vhandle)329 __rpc_getconf(void *vhandle)
330 {
331 struct handle *handle;
332 struct netconfig *nconf;
333
334 handle = (struct handle *)vhandle;
335 if (handle == NULL) {
336 return (NULL);
337 }
338 for (;;) {
339 if (handle->nflag)
340 nconf = getnetpath(handle->nhandle);
341 else
342 nconf = getnetconfig(handle->nhandle);
343 if (nconf == NULL)
344 break;
345 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
346 (nconf->nc_semantics != NC_TPI_COTS) &&
347 (nconf->nc_semantics != NC_TPI_COTS_ORD))
348 continue;
349 switch (handle->nettype) {
350 case _RPC_VISIBLE:
351 if (!(nconf->nc_flag & NC_VISIBLE))
352 continue;
353 /* FALLTHROUGH */
354 case _RPC_NETPATH: /* Be happy */
355 break;
356 case _RPC_CIRCUIT_V:
357 if (!(nconf->nc_flag & NC_VISIBLE))
358 continue;
359 /* FALLTHROUGH */
360 case _RPC_CIRCUIT_N:
361 if ((nconf->nc_semantics != NC_TPI_COTS) &&
362 (nconf->nc_semantics != NC_TPI_COTS_ORD))
363 continue;
364 break;
365 case _RPC_DATAGRAM_V:
366 if (!(nconf->nc_flag & NC_VISIBLE))
367 continue;
368 /* FALLTHROUGH */
369 case _RPC_DATAGRAM_N:
370 if (nconf->nc_semantics != NC_TPI_CLTS)
371 continue;
372 break;
373 case _RPC_TCP:
374 if (((nconf->nc_semantics != NC_TPI_COTS) &&
375 (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
376 (strcmp(nconf->nc_protofmly, NC_INET)
377 #ifdef INET6
378 && strcmp(nconf->nc_protofmly, NC_INET6))
379 #else
380 )
381 #endif
382 ||
383 strcmp(nconf->nc_proto, NC_TCP))
384 continue;
385 break;
386 case _RPC_UDP:
387 if ((nconf->nc_semantics != NC_TPI_CLTS) ||
388 (strcmp(nconf->nc_protofmly, NC_INET)
389 #ifdef INET6
390 && strcmp(nconf->nc_protofmly, NC_INET6))
391 #else
392 )
393 #endif
394 ||
395 strcmp(nconf->nc_proto, NC_UDP))
396 continue;
397 break;
398 }
399 break;
400 }
401 return (nconf);
402 }
403
404 void
__rpc_endconf(void * vhandle)405 __rpc_endconf(void *vhandle)
406 {
407 struct handle *handle;
408
409 handle = (struct handle *) vhandle;
410 if (handle == NULL) {
411 return;
412 }
413 if (handle->nflag) {
414 endnetpath(handle->nhandle);
415 } else {
416 endnetconfig(handle->nhandle);
417 }
418 free(handle);
419 }
420
421 /*
422 * Used to ping the NULL procedure for clnt handle.
423 * Returns NULL if fails, else a non-NULL pointer.
424 */
425 void *
rpc_nullproc(CLIENT * clnt)426 rpc_nullproc(CLIENT *clnt)
427 {
428 struct timeval TIMEOUT = {25, 0};
429
430 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
431 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
432 return (NULL);
433 }
434 return ((void *) clnt);
435 }
436
437 /*
438 * Try all possible transports until
439 * one succeeds in finding the netconf for the given fd.
440 */
441 struct netconfig *
__rpcgettp(int fd)442 __rpcgettp(int fd)
443 {
444 const char *netid;
445 struct __rpc_sockinfo si;
446
447 if (!__rpc_fd2sockinfo(fd, &si))
448 return NULL;
449
450 if (!__rpc_sockinfo2netid(&si, &netid))
451 return NULL;
452
453 /*LINTED const castaway*/
454 return getnetconfigent((char *)netid);
455 }
456
457 int
__rpc_fd2sockinfo(int fd,struct __rpc_sockinfo * sip)458 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
459 {
460 socklen_t len;
461 int type, proto;
462 struct sockaddr_storage ss;
463
464 len = sizeof ss;
465 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
466 return 0;
467 sip->si_alen = len;
468
469 len = sizeof type;
470 if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
471 return 0;
472
473 /* XXX */
474 if (ss.ss_family != AF_LOCAL) {
475 if (type == SOCK_STREAM)
476 proto = IPPROTO_TCP;
477 else if (type == SOCK_DGRAM)
478 proto = IPPROTO_UDP;
479 else
480 return 0;
481 } else
482 proto = 0;
483
484 sip->si_af = ss.ss_family;
485 sip->si_proto = proto;
486 sip->si_socktype = type;
487
488 return 1;
489 }
490
491 /*
492 * Linear search, but the number of entries is small.
493 */
494 int
__rpc_nconf2sockinfo(const struct netconfig * nconf,struct __rpc_sockinfo * sip)495 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
496 {
497 int i;
498
499 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
500 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
501 strcmp(nconf->nc_netid, "unix") == 0 &&
502 strcmp(na_cvt[i].netid, "local") == 0)) {
503 sip->si_af = na_cvt[i].af;
504 sip->si_proto = na_cvt[i].protocol;
505 sip->si_socktype =
506 __rpc_seman2socktype((int)nconf->nc_semantics);
507 if (sip->si_socktype == -1)
508 return 0;
509 sip->si_alen = __rpc_get_a_size(sip->si_af);
510 return 1;
511 }
512
513 return 0;
514 }
515
516 int
__rpc_nconf2fd(const struct netconfig * nconf)517 __rpc_nconf2fd(const struct netconfig *nconf)
518 {
519 struct __rpc_sockinfo si;
520
521 if (!__rpc_nconf2sockinfo(nconf, &si))
522 return 0;
523
524 return _socket(si.si_af, si.si_socktype, si.si_proto);
525 }
526
527 int
__rpc_sockinfo2netid(struct __rpc_sockinfo * sip,const char ** netid)528 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
529 {
530 int i;
531 struct netconfig *nconf;
532
533 nconf = getnetconfigent("local");
534
535 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
536 if (na_cvt[i].af == sip->si_af &&
537 na_cvt[i].protocol == sip->si_proto) {
538 if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
539 if (netid)
540 *netid = "unix";
541 } else {
542 if (netid)
543 *netid = na_cvt[i].netid;
544 }
545 if (nconf != NULL)
546 freenetconfigent(nconf);
547 return 1;
548 }
549 }
550 if (nconf != NULL)
551 freenetconfigent(nconf);
552
553 return 0;
554 }
555
556 char *
taddr2uaddr(const struct netconfig * nconf,const struct netbuf * nbuf)557 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
558 {
559 struct __rpc_sockinfo si;
560
561 if (!__rpc_nconf2sockinfo(nconf, &si))
562 return NULL;
563 return __rpc_taddr2uaddr_af(si.si_af, nbuf);
564 }
565
566 struct netbuf *
uaddr2taddr(const struct netconfig * nconf,const char * uaddr)567 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
568 {
569 struct __rpc_sockinfo si;
570
571 if (!__rpc_nconf2sockinfo(nconf, &si))
572 return NULL;
573 return __rpc_uaddr2taddr_af(si.si_af, uaddr);
574 }
575
576 char *
__rpc_taddr2uaddr_af(int af,const struct netbuf * nbuf)577 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
578 {
579 char *ret;
580 struct sockaddr_in *sin;
581 struct sockaddr_un *sun;
582 char namebuf[INET_ADDRSTRLEN];
583 #ifdef INET6
584 struct sockaddr_in6 *sin6;
585 char namebuf6[INET6_ADDRSTRLEN];
586 #endif
587 u_int16_t port;
588
589 switch (af) {
590 case AF_INET:
591 if (nbuf->len < sizeof(*sin))
592 return NULL;
593 sin = nbuf->buf;
594 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
595 == NULL)
596 return NULL;
597 port = ntohs(sin->sin_port);
598 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
599 port & 0xff) < 0)
600 return NULL;
601 break;
602 #ifdef INET6
603 case AF_INET6:
604 if (nbuf->len < sizeof(*sin6))
605 return NULL;
606 sin6 = nbuf->buf;
607 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
608 == NULL)
609 return NULL;
610 port = ntohs(sin6->sin6_port);
611 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
612 port & 0xff) < 0)
613 return NULL;
614 break;
615 #endif
616 case AF_LOCAL:
617 sun = nbuf->buf;
618 if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
619 offsetof(struct sockaddr_un, sun_path)),
620 sun->sun_path) < 0)
621 return (NULL);
622 break;
623 default:
624 return NULL;
625 }
626
627 return ret;
628 }
629
630 struct netbuf *
__rpc_uaddr2taddr_af(int af,const char * uaddr)631 __rpc_uaddr2taddr_af(int af, const char *uaddr)
632 {
633 struct netbuf *ret = NULL;
634 char *addrstr, *p;
635 unsigned port, portlo, porthi;
636 struct sockaddr_in *sin;
637 #ifdef INET6
638 struct sockaddr_in6 *sin6;
639 #endif
640 struct sockaddr_un *sun;
641
642 port = 0;
643 sin = NULL;
644
645 if (uaddr == NULL)
646 return NULL;
647
648 addrstr = strdup(uaddr);
649 if (addrstr == NULL)
650 return NULL;
651
652 /*
653 * AF_LOCAL addresses are expected to be absolute
654 * pathnames, anything else will be AF_INET or AF_INET6.
655 */
656 if (*addrstr != '/') {
657 p = strrchr(addrstr, '.');
658 if (p == NULL)
659 goto out;
660 portlo = (unsigned)atoi(p + 1);
661 *p = '\0';
662
663 p = strrchr(addrstr, '.');
664 if (p == NULL)
665 goto out;
666 porthi = (unsigned)atoi(p + 1);
667 *p = '\0';
668 port = (porthi << 8) | portlo;
669 }
670
671 ret = (struct netbuf *)malloc(sizeof *ret);
672 if (ret == NULL)
673 goto out;
674
675 switch (af) {
676 case AF_INET:
677 sin = (struct sockaddr_in *)malloc(sizeof *sin);
678 if (sin == NULL)
679 goto out;
680 memset(sin, 0, sizeof *sin);
681 sin->sin_family = AF_INET;
682 sin->sin_port = htons(port);
683 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
684 free(sin);
685 free(ret);
686 ret = NULL;
687 goto out;
688 }
689 sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
690 ret->buf = sin;
691 break;
692 #ifdef INET6
693 case AF_INET6:
694 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
695 if (sin6 == NULL)
696 goto out;
697 memset(sin6, 0, sizeof *sin6);
698 sin6->sin6_family = AF_INET6;
699 sin6->sin6_port = htons(port);
700 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
701 free(sin6);
702 free(ret);
703 ret = NULL;
704 goto out;
705 }
706 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
707 ret->buf = sin6;
708 break;
709 #endif
710 case AF_LOCAL:
711 sun = (struct sockaddr_un *)malloc(sizeof *sun);
712 if (sun == NULL)
713 goto out;
714 memset(sun, 0, sizeof *sun);
715 sun->sun_family = AF_LOCAL;
716 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
717 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
718 ret->buf = sun;
719 break;
720 default:
721 break;
722 }
723 out:
724 free(addrstr);
725 return ret;
726 }
727
728 int
__rpc_seman2socktype(int semantics)729 __rpc_seman2socktype(int semantics)
730 {
731 switch (semantics) {
732 case NC_TPI_CLTS:
733 return SOCK_DGRAM;
734 case NC_TPI_COTS_ORD:
735 return SOCK_STREAM;
736 case NC_TPI_RAW:
737 return SOCK_RAW;
738 default:
739 break;
740 }
741
742 return -1;
743 }
744
745 int
__rpc_socktype2seman(int socktype)746 __rpc_socktype2seman(int socktype)
747 {
748 switch (socktype) {
749 case SOCK_DGRAM:
750 return NC_TPI_CLTS;
751 case SOCK_STREAM:
752 return NC_TPI_COTS_ORD;
753 case SOCK_RAW:
754 return NC_TPI_RAW;
755 default:
756 break;
757 }
758
759 return -1;
760 }
761
762 /*
763 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
764 * Here, we compare the original server address to that of the RPC
765 * service we just received back from a call to rpcbind on the remote
766 * machine. If they are both "link local" or "site local", copy
767 * the scope id of the server address over to the service address.
768 */
769 int
__rpc_fixup_addr(struct netbuf * new,const struct netbuf * svc)770 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
771 {
772 #ifdef INET6
773 struct sockaddr *sa_new, *sa_svc;
774 struct sockaddr_in6 *sin6_new, *sin6_svc;
775
776 sa_svc = (struct sockaddr *)svc->buf;
777 sa_new = (struct sockaddr *)new->buf;
778
779 if (sa_new->sa_family == sa_svc->sa_family &&
780 sa_new->sa_family == AF_INET6) {
781 sin6_new = (struct sockaddr_in6 *)new->buf;
782 sin6_svc = (struct sockaddr_in6 *)svc->buf;
783
784 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
785 IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
786 (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
787 IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
788 sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
789 }
790 }
791 #endif
792 return 1;
793 }
794
795 int
__rpc_sockisbound(int fd)796 __rpc_sockisbound(int fd)
797 {
798 struct sockaddr_storage ss;
799 socklen_t slen;
800
801 slen = sizeof (struct sockaddr_storage);
802 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
803 return 0;
804
805 switch (ss.ss_family) {
806 case AF_INET:
807 return (((struct sockaddr_in *)
808 (void *)&ss)->sin_port != 0);
809 #ifdef INET6
810 case AF_INET6:
811 return (((struct sockaddr_in6 *)
812 (void *)&ss)->sin6_port != 0);
813 #endif
814 case AF_LOCAL:
815 /* XXX check this */
816 return (((struct sockaddr_un *)
817 (void *)&ss)->sun_path[0] != '\0');
818 default:
819 break;
820 }
821
822 return 0;
823 }
824