rpc_generic.c revision 331722
11558Srgrimes/*	$NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $	*/
21558Srgrimes
31558Srgrimes/*-
41558Srgrimes * Copyright (c) 2009, Sun Microsystems, Inc.
51558Srgrimes * All rights reserved.
61558Srgrimes *
71558Srgrimes * Redistribution and use in source and binary forms, with or without
81558Srgrimes * modification, are permitted provided that the following conditions are met:
91558Srgrimes * - Redistributions of source code must retain the above copyright notice,
101558Srgrimes *   this list of conditions and the following disclaimer.
111558Srgrimes * - Redistributions in binary form must reproduce the above copyright notice,
121558Srgrimes *   this list of conditions and the following disclaimer in the documentation
131558Srgrimes *   and/or other materials provided with the distribution.
141558Srgrimes * - Neither the name of Sun Microsystems, Inc. nor the names of its
151558Srgrimes *   contributors may be used to endorse or promote products derived
161558Srgrimes *   from this software without specific prior written permission.
171558Srgrimes *
181558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
191558Srgrimes * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
201558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
211558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
221558Srgrimes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
231558Srgrimes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
241558Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
251558Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
261558Srgrimes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
271558Srgrimes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
281558Srgrimes * POSSIBILITY OF SUCH DAMAGE.
291558Srgrimes */
301558Srgrimes/*
311558Srgrimes * Copyright (c) 1986-1991 by Sun Microsystems Inc.
321558Srgrimes */
331558Srgrimes
341558Srgrimes/* #pragma ident	"@(#)rpc_generic.c	1.17	94/04/24 SMI" */
3541477Sjulian#include <sys/cdefs.h>
3623675Speter__FBSDID("$FreeBSD: stable/11/lib/libc/rpc/rpc_generic.c 331722 2018-03-29 02:50:57Z eadler $");
3741477Sjulian
3841477Sjulian/*
3950476Speter * rpc_generic.c, Miscl routines for RPC.
401558Srgrimes *
411558Srgrimes */
421558Srgrimes
4323675Speter#include "namespace.h"
441558Srgrimes#include "reentrant.h"
4541474Sjulian#include <sys/param.h>
4623675Speter#include <sys/socket.h>
4723675Speter#include <sys/time.h>
481558Srgrimes#include <sys/un.h>
4923675Speter#include <sys/resource.h>
501558Srgrimes#include <netinet/in.h>
511558Srgrimes#include <arpa/inet.h>
527585Sbde#include <rpc/rpc.h>
5392839Simp#include <ctype.h>
541558Srgrimes#include <stddef.h>
5592806Sobrien#include <stdio.h>
5692806Sobrien#include <netdb.h>
5798542Smckusick#include <netconfig.h>
581558Srgrimes#include <stdlib.h>
5941474Sjulian#include <string.h>
601558Srgrimes#include <syslog.h>
6123675Speter#include <rpc/nettype.h>
621558Srgrimes#include "un-namespace.h"
631558Srgrimes#include "rpc_com.h"
6441474Sjulian#include "mt_misc.h"
6570050Siedowse
6670050Siedowsestruct handle {
6770050Siedowse	NCONF_HANDLE *nhandle;
6870050Siedowse	int nflag;		/* Whether NETPATH or NETCONFIG */
6970050Siedowse	int nettype;
7070050Siedowse};
7141474Sjulian
7241474Sjulianstatic const struct _rpcnettype {
7341474Sjulian	const char *name;
7441474Sjulian	const int type;
7541474Sjulian} _rpctypelist[] = {
7641474Sjulian	{ "netpath", _RPC_NETPATH },
771558Srgrimes	{ "visible", _RPC_VISIBLE },
7841474Sjulian	{ "circuit_v", _RPC_CIRCUIT_V },
7941474Sjulian	{ "datagram_v", _RPC_DATAGRAM_V },
8041474Sjulian	{ "circuit_n", _RPC_CIRCUIT_N },
8141474Sjulian	{ "datagram_n", _RPC_DATAGRAM_N },
8241474Sjulian	{ "tcp", _RPC_TCP },
8341474Sjulian	{ "udp", _RPC_UDP },
8441474Sjulian	{ 0, _RPC_NONE }
8541474Sjulian};
861558Srgrimes
871558Srgrimesstruct netid_af {
881558Srgrimes	const char	*netid;
891558Srgrimes	int		af;
901558Srgrimes	int		protocol;
911558Srgrimes};
921558Srgrimes
931558Srgrimesstatic const struct netid_af na_cvt[] = {
9441474Sjulian	{ "udp",  AF_INET,  IPPROTO_UDP },
9541474Sjulian	{ "tcp",  AF_INET,  IPPROTO_TCP },
961558Srgrimes#ifdef INET6
9741474Sjulian	{ "udp6", AF_INET6, IPPROTO_UDP },
9841474Sjulian	{ "tcp6", AF_INET6, IPPROTO_TCP },
9941474Sjulian#endif
1001558Srgrimes	{ "local", AF_LOCAL, 0 }
10141474Sjulian};
10241474Sjulian
10398542Smckusick#if 0
10441474Sjulianstatic char *strlocase(char *);
10541474Sjulian#endif
10641474Sjulianstatic int getnettype(const char *);
10741474Sjulian
10841474Sjulian/*
10941474Sjulian * Cache the result of getrlimit(), so we don't have to do an
1101558Srgrimes * expensive call every time.
1111558Srgrimes */
11241474Sjulianint
11341474Sjulian__rpc_dtbsize(void)
1141558Srgrimes{
11541474Sjulian	static int tbsize;
11641474Sjulian	struct rlimit rl;
11741474Sjulian
11841474Sjulian	if (tbsize) {
1191558Srgrimes		return (tbsize);
1201558Srgrimes	}
1211558Srgrimes	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
1221558Srgrimes		return (tbsize = (int)rl.rlim_max);
1237585Sbde	}
12492839Simp	/*
1251558Srgrimes	 * Something wrong.  I'll try to save face by returning a
12692806Sobrien	 * pessimistic number.
1271558Srgrimes	 */
12898542Smckusick	return (32);
1291558Srgrimes}
1301558Srgrimes
1311558Srgrimes
1321558Srgrimes/*
1331558Srgrimes * Find the appropriate buffer size
1341558Srgrimes *
1351558Srgrimes * size - Size requested
1361558Srgrimes */
1371558Srgrimesu_int
1381558Srgrimes/*ARGSUSED*/
1391558Srgrimes__rpc_get_t_size(int af, int proto, int size)
1401558Srgrimes{
1411558Srgrimes	int maxsize, defsize;
1421558Srgrimes
1431558Srgrimes	maxsize = 256 * 1024;	/* XXX */
1441558Srgrimes	switch (proto) {
1451558Srgrimes	case IPPROTO_TCP:
1461558Srgrimes		defsize = 64 * 1024;	/* XXX */
1471558Srgrimes		break;
1481558Srgrimes	case IPPROTO_UDP:
1491558Srgrimes		defsize = UDPMSGSIZE;
1501558Srgrimes		break;
151	default:
152		defsize = RPC_MAXDATASIZE;
153		break;
154	}
155	if (size == 0)
156		return defsize;
157
158	/* Check whether the value is within the upper max limit */
159	return (size > maxsize ? (u_int)maxsize : (u_int)size);
160}
161
162/*
163 * Find the appropriate address buffer size
164 */
165u_int
166__rpc_get_a_size(int af)
167{
168	switch (af) {
169	case AF_INET:
170		return sizeof (struct sockaddr_in);
171#ifdef INET6
172	case AF_INET6:
173		return sizeof (struct sockaddr_in6);
174#endif
175	case AF_LOCAL:
176		return sizeof (struct sockaddr_un);
177	default:
178		break;
179	}
180	return ((u_int)RPC_MAXADDRSIZE);
181}
182
183#if 0
184static char *
185strlocase(char *p)
186{
187	char *t = p;
188
189	for (; *p; p++)
190		if (isupper(*p))
191			*p = tolower(*p);
192	return (t);
193}
194#endif
195
196/*
197 * Returns the type of the network as defined in <rpc/nettype.h>
198 * If nettype is NULL, it defaults to NETPATH.
199 */
200static int
201getnettype(const char *nettype)
202{
203	int i;
204
205	if ((nettype == NULL) || (nettype[0] == 0)) {
206		return (_RPC_NETPATH);	/* Default */
207	}
208
209#if 0
210	nettype = strlocase(nettype);
211#endif
212	for (i = 0; _rpctypelist[i].name; i++)
213		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
214			return (_rpctypelist[i].type);
215		}
216	return (_rpctypelist[i].type);
217}
218
219static thread_key_t tcp_key, udp_key;
220static once_t keys_once = ONCE_INITIALIZER;
221static int tcp_key_error, udp_key_error;
222
223static void
224keys_init(void)
225{
226
227	tcp_key_error = thr_keycreate(&tcp_key, free);
228	udp_key_error = thr_keycreate(&udp_key, free);
229}
230
231/*
232 * For the given nettype (tcp or udp only), return the first structure found.
233 * This should be freed by calling freenetconfigent()
234 */
235struct netconfig *
236__rpc_getconfip(const char *nettype)
237{
238	char *netid;
239	char *netid_tcp = (char *) NULL;
240	char *netid_udp = (char *) NULL;
241	static char *netid_tcp_main;
242	static char *netid_udp_main;
243	struct netconfig *dummy;
244	int main_thread;
245
246	if ((main_thread = thr_main())) {
247		netid_udp = netid_udp_main;
248		netid_tcp = netid_tcp_main;
249	} else {
250		if (thr_once(&keys_once, keys_init) != 0 ||
251		    tcp_key_error != 0 || udp_key_error != 0)
252			return (NULL);
253		netid_tcp = (char *)thr_getspecific(tcp_key);
254		netid_udp = (char *)thr_getspecific(udp_key);
255	}
256	if (!netid_udp && !netid_tcp) {
257		struct netconfig *nconf;
258		void *confighandle;
259
260		if (!(confighandle = setnetconfig())) {
261			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
262			return (NULL);
263		}
264		while ((nconf = getnetconfig(confighandle)) != NULL) {
265			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
266				if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
267				    netid_tcp == NULL) {
268					netid_tcp = strdup(nconf->nc_netid);
269					if (main_thread)
270						netid_tcp_main = netid_tcp;
271					else
272						thr_setspecific(tcp_key,
273							(void *) netid_tcp);
274				} else
275				if (strcmp(nconf->nc_proto, NC_UDP) == 0 &&
276				    netid_udp == NULL) {
277					netid_udp = strdup(nconf->nc_netid);
278					if (main_thread)
279						netid_udp_main = netid_udp;
280					else
281						thr_setspecific(udp_key,
282						(void *) netid_udp);
283				}
284			}
285		}
286		endnetconfig(confighandle);
287	}
288	if (strcmp(nettype, "udp") == 0)
289		netid = netid_udp;
290	else if (strcmp(nettype, "tcp") == 0)
291		netid = netid_tcp;
292	else {
293		return (NULL);
294	}
295	if ((netid == NULL) || (netid[0] == 0)) {
296		return (NULL);
297	}
298	dummy = getnetconfigent(netid);
299	return (dummy);
300}
301
302/*
303 * Returns the type of the nettype, which should then be used with
304 * __rpc_getconf().
305 */
306void *
307__rpc_setconf(const char *nettype)
308{
309	struct handle *handle;
310
311	handle = (struct handle *) malloc(sizeof (struct handle));
312	if (handle == NULL) {
313		return (NULL);
314	}
315	switch (handle->nettype = getnettype(nettype)) {
316	case _RPC_NETPATH:
317	case _RPC_CIRCUIT_N:
318	case _RPC_DATAGRAM_N:
319		if (!(handle->nhandle = setnetpath()))
320			goto failed;
321		handle->nflag = TRUE;
322		break;
323	case _RPC_VISIBLE:
324	case _RPC_CIRCUIT_V:
325	case _RPC_DATAGRAM_V:
326	case _RPC_TCP:
327	case _RPC_UDP:
328		if (!(handle->nhandle = setnetconfig())) {
329		        syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
330			goto failed;
331		}
332		handle->nflag = FALSE;
333		break;
334	default:
335		goto failed;
336	}
337
338	return (handle);
339
340failed:
341	free(handle);
342	return (NULL);
343}
344
345/*
346 * Returns the next netconfig struct for the given "net" type.
347 * __rpc_setconf() should have been called previously.
348 */
349struct netconfig *
350__rpc_getconf(void *vhandle)
351{
352	struct handle *handle;
353	struct netconfig *nconf;
354
355	handle = (struct handle *)vhandle;
356	if (handle == NULL) {
357		return (NULL);
358	}
359	for (;;) {
360		if (handle->nflag)
361			nconf = getnetpath(handle->nhandle);
362		else
363			nconf = getnetconfig(handle->nhandle);
364		if (nconf == NULL)
365			break;
366		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
367			(nconf->nc_semantics != NC_TPI_COTS) &&
368			(nconf->nc_semantics != NC_TPI_COTS_ORD))
369			continue;
370		switch (handle->nettype) {
371		case _RPC_VISIBLE:
372			if (!(nconf->nc_flag & NC_VISIBLE))
373				continue;
374			/* FALLTHROUGH */
375		case _RPC_NETPATH:	/* Be happy */
376			break;
377		case _RPC_CIRCUIT_V:
378			if (!(nconf->nc_flag & NC_VISIBLE))
379				continue;
380			/* FALLTHROUGH */
381		case _RPC_CIRCUIT_N:
382			if ((nconf->nc_semantics != NC_TPI_COTS) &&
383				(nconf->nc_semantics != NC_TPI_COTS_ORD))
384				continue;
385			break;
386		case _RPC_DATAGRAM_V:
387			if (!(nconf->nc_flag & NC_VISIBLE))
388				continue;
389			/* FALLTHROUGH */
390		case _RPC_DATAGRAM_N:
391			if (nconf->nc_semantics != NC_TPI_CLTS)
392				continue;
393			break;
394		case _RPC_TCP:
395			if (((nconf->nc_semantics != NC_TPI_COTS) &&
396				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
397				(strcmp(nconf->nc_protofmly, NC_INET)
398#ifdef INET6
399				 && strcmp(nconf->nc_protofmly, NC_INET6))
400#else
401				)
402#endif
403				||
404				strcmp(nconf->nc_proto, NC_TCP))
405				continue;
406			break;
407		case _RPC_UDP:
408			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
409				(strcmp(nconf->nc_protofmly, NC_INET)
410#ifdef INET6
411				&& strcmp(nconf->nc_protofmly, NC_INET6))
412#else
413				)
414#endif
415				||
416				strcmp(nconf->nc_proto, NC_UDP))
417				continue;
418			break;
419		}
420		break;
421	}
422	return (nconf);
423}
424
425void
426__rpc_endconf(void *vhandle)
427{
428	struct handle *handle;
429
430	handle = (struct handle *) vhandle;
431	if (handle == NULL) {
432		return;
433	}
434	if (handle->nflag) {
435		endnetpath(handle->nhandle);
436	} else {
437		endnetconfig(handle->nhandle);
438	}
439	free(handle);
440}
441
442/*
443 * Used to ping the NULL procedure for clnt handle.
444 * Returns NULL if fails, else a non-NULL pointer.
445 */
446void *
447rpc_nullproc(CLIENT *clnt)
448{
449	struct timeval TIMEOUT = {25, 0};
450
451	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
452		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
453		return (NULL);
454	}
455	return ((void *) clnt);
456}
457
458/*
459 * Try all possible transports until
460 * one succeeds in finding the netconf for the given fd.
461 */
462struct netconfig *
463__rpcgettp(int fd)
464{
465	const char *netid;
466	struct __rpc_sockinfo si;
467
468	if (!__rpc_fd2sockinfo(fd, &si))
469		return NULL;
470
471	if (!__rpc_sockinfo2netid(&si, &netid))
472		return NULL;
473
474	/*LINTED const castaway*/
475	return getnetconfigent((char *)netid);
476}
477
478int
479__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
480{
481	socklen_t len;
482	int type, proto;
483	struct sockaddr_storage ss;
484
485	len = sizeof ss;
486	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
487		return 0;
488	sip->si_alen = len;
489
490	len = sizeof type;
491	if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
492		return 0;
493
494	/* XXX */
495	if (ss.ss_family != AF_LOCAL) {
496		if (type == SOCK_STREAM)
497			proto = IPPROTO_TCP;
498		else if (type == SOCK_DGRAM)
499			proto = IPPROTO_UDP;
500		else
501			return 0;
502	} else
503		proto = 0;
504
505	sip->si_af = ss.ss_family;
506	sip->si_proto = proto;
507	sip->si_socktype = type;
508
509	return 1;
510}
511
512/*
513 * Linear search, but the number of entries is small.
514 */
515int
516__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
517{
518	int i;
519
520	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
521		if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
522		    strcmp(nconf->nc_netid, "unix") == 0 &&
523		    strcmp(na_cvt[i].netid, "local") == 0)) {
524			sip->si_af = na_cvt[i].af;
525			sip->si_proto = na_cvt[i].protocol;
526			sip->si_socktype =
527			    __rpc_seman2socktype((int)nconf->nc_semantics);
528			if (sip->si_socktype == -1)
529				return 0;
530			sip->si_alen = __rpc_get_a_size(sip->si_af);
531			return 1;
532		}
533
534	return 0;
535}
536
537int
538__rpc_nconf2fd(const struct netconfig *nconf)
539{
540	struct __rpc_sockinfo si;
541
542	if (!__rpc_nconf2sockinfo(nconf, &si))
543		return 0;
544
545	return _socket(si.si_af, si.si_socktype, si.si_proto);
546}
547
548int
549__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
550{
551	int i;
552	struct netconfig *nconf;
553
554	nconf = getnetconfigent("local");
555
556	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
557		if (na_cvt[i].af == sip->si_af &&
558		    na_cvt[i].protocol == sip->si_proto) {
559			if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
560				if (netid)
561					*netid = "unix";
562			} else {
563				if (netid)
564					*netid = na_cvt[i].netid;
565			}
566			if (nconf != NULL)
567				freenetconfigent(nconf);
568			return 1;
569		}
570	}
571	if (nconf != NULL)
572		freenetconfigent(nconf);
573
574	return 0;
575}
576
577char *
578taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
579{
580	struct __rpc_sockinfo si;
581
582	if (!__rpc_nconf2sockinfo(nconf, &si))
583		return NULL;
584	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
585}
586
587struct netbuf *
588uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
589{
590	struct __rpc_sockinfo si;
591
592	if (!__rpc_nconf2sockinfo(nconf, &si))
593		return NULL;
594	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
595}
596
597char *
598__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
599{
600	char *ret;
601	struct sockaddr_in *sin;
602	struct sockaddr_un *sun;
603	char namebuf[INET_ADDRSTRLEN];
604#ifdef INET6
605	struct sockaddr_in6 *sin6;
606	char namebuf6[INET6_ADDRSTRLEN];
607#endif
608	u_int16_t port;
609
610	switch (af) {
611	case AF_INET:
612		if (nbuf->len < sizeof(*sin))
613			return NULL;
614		sin = nbuf->buf;
615		if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
616		    == NULL)
617			return NULL;
618		port = ntohs(sin->sin_port);
619		if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
620		    port & 0xff) < 0)
621			return NULL;
622		break;
623#ifdef INET6
624	case AF_INET6:
625		if (nbuf->len < sizeof(*sin6))
626			return NULL;
627		sin6 = nbuf->buf;
628		if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
629		    == NULL)
630			return NULL;
631		port = ntohs(sin6->sin6_port);
632		if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
633		    port & 0xff) < 0)
634			return NULL;
635		break;
636#endif
637	case AF_LOCAL:
638		sun = nbuf->buf;
639		if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
640		    offsetof(struct sockaddr_un, sun_path)),
641		    sun->sun_path) < 0)
642			return (NULL);
643		break;
644	default:
645		return NULL;
646	}
647
648	return ret;
649}
650
651struct netbuf *
652__rpc_uaddr2taddr_af(int af, const char *uaddr)
653{
654	struct netbuf *ret = NULL;
655	char *addrstr, *p;
656	unsigned port, portlo, porthi;
657	struct sockaddr_in *sin;
658#ifdef INET6
659	struct sockaddr_in6 *sin6;
660#endif
661	struct sockaddr_un *sun;
662
663	port = 0;
664	sin = NULL;
665
666	if (uaddr == NULL)
667		return NULL;
668
669	addrstr = strdup(uaddr);
670	if (addrstr == NULL)
671		return NULL;
672
673	/*
674	 * AF_LOCAL addresses are expected to be absolute
675	 * pathnames, anything else will be AF_INET or AF_INET6.
676	 */
677	if (*addrstr != '/') {
678		p = strrchr(addrstr, '.');
679		if (p == NULL)
680			goto out;
681		portlo = (unsigned)atoi(p + 1);
682		*p = '\0';
683
684		p = strrchr(addrstr, '.');
685		if (p == NULL)
686			goto out;
687		porthi = (unsigned)atoi(p + 1);
688		*p = '\0';
689		port = (porthi << 8) | portlo;
690	}
691
692	ret = (struct netbuf *)malloc(sizeof *ret);
693	if (ret == NULL)
694		goto out;
695
696	switch (af) {
697	case AF_INET:
698		sin = (struct sockaddr_in *)malloc(sizeof *sin);
699		if (sin == NULL)
700			goto out;
701		memset(sin, 0, sizeof *sin);
702		sin->sin_family = AF_INET;
703		sin->sin_port = htons(port);
704		if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
705			free(sin);
706			free(ret);
707			ret = NULL;
708			goto out;
709		}
710		sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
711		ret->buf = sin;
712		break;
713#ifdef INET6
714	case AF_INET6:
715		sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
716		if (sin6 == NULL)
717			goto out;
718		memset(sin6, 0, sizeof *sin6);
719		sin6->sin6_family = AF_INET6;
720		sin6->sin6_port = htons(port);
721		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
722			free(sin6);
723			free(ret);
724			ret = NULL;
725			goto out;
726		}
727		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
728		ret->buf = sin6;
729		break;
730#endif
731	case AF_LOCAL:
732		sun = (struct sockaddr_un *)malloc(sizeof *sun);
733		if (sun == NULL)
734			goto out;
735		memset(sun, 0, sizeof *sun);
736		sun->sun_family = AF_LOCAL;
737		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
738		ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
739		ret->buf = sun;
740		break;
741	default:
742		break;
743	}
744out:
745	free(addrstr);
746	return ret;
747}
748
749int
750__rpc_seman2socktype(int semantics)
751{
752	switch (semantics) {
753	case NC_TPI_CLTS:
754		return SOCK_DGRAM;
755	case NC_TPI_COTS_ORD:
756		return SOCK_STREAM;
757	case NC_TPI_RAW:
758		return SOCK_RAW;
759	default:
760		break;
761	}
762
763	return -1;
764}
765
766int
767__rpc_socktype2seman(int socktype)
768{
769	switch (socktype) {
770	case SOCK_DGRAM:
771		return NC_TPI_CLTS;
772	case SOCK_STREAM:
773		return NC_TPI_COTS_ORD;
774	case SOCK_RAW:
775		return NC_TPI_RAW;
776	default:
777		break;
778	}
779
780	return -1;
781}
782
783/*
784 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
785 * Here, we compare the original server address to that of the RPC
786 * service we just received back from a call to rpcbind on the remote
787 * machine. If they are both "link local" or "site local", copy
788 * the scope id of the server address over to the service address.
789 */
790int
791__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
792{
793#ifdef INET6
794	struct sockaddr *sa_new, *sa_svc;
795	struct sockaddr_in6 *sin6_new, *sin6_svc;
796
797	sa_svc = (struct sockaddr *)svc->buf;
798	sa_new = (struct sockaddr *)new->buf;
799
800	if (sa_new->sa_family == sa_svc->sa_family &&
801	    sa_new->sa_family == AF_INET6) {
802		sin6_new = (struct sockaddr_in6 *)new->buf;
803		sin6_svc = (struct sockaddr_in6 *)svc->buf;
804
805		if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
806		     IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
807		    (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
808		     IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
809			sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
810		}
811	}
812#endif
813	return 1;
814}
815
816int
817__rpc_sockisbound(int fd)
818{
819	struct sockaddr_storage ss;
820	socklen_t slen;
821
822	slen = sizeof (struct sockaddr_storage);
823	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
824		return 0;
825
826	switch (ss.ss_family) {
827		case AF_INET:
828			return (((struct sockaddr_in *)
829			    (void *)&ss)->sin_port != 0);
830#ifdef INET6
831		case AF_INET6:
832			return (((struct sockaddr_in6 *)
833			    (void *)&ss)->sin6_port != 0);
834#endif
835		case AF_LOCAL:
836			/* XXX check this */
837			return (((struct sockaddr_un *)
838			    (void *)&ss)->sun_path[0] != '\0');
839		default:
840			break;
841	}
842
843	return 0;
844}
845