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