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