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