174462Salfred/*	$NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $	*/
274462Salfred
3261057Smav/*-
4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc.
5261057Smav * All rights reserved.
6261057Smav *
7261057Smav * Redistribution and use in source and binary forms, with or without
8261057Smav * modification, are permitted provided that the following conditions are met:
9261057Smav * - Redistributions of source code must retain the above copyright notice,
10261057Smav *   this list of conditions and the following disclaimer.
11261057Smav * - Redistributions in binary form must reproduce the above copyright notice,
12261057Smav *   this list of conditions and the following disclaimer in the documentation
13261057Smav *   and/or other materials provided with the distribution.
14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its
15261057Smav *   contributors may be used to endorse or promote products derived
16261057Smav *   from this software without specific prior written permission.
1774462Salfred *
18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28261057Smav * POSSIBILITY OF SUCH DAMAGE.
2974462Salfred */
3074462Salfred/*
3174462Salfred * Copyright (c) 1986-1991 by Sun Microsystems Inc.
3274462Salfred */
3374462Salfred
3474462Salfred/* #pragma ident	"@(#)rpc_generic.c	1.17	94/04/24 SMI" */
3592990Sobrien#include <sys/cdefs.h>
3692990Sobrien__FBSDID("$FreeBSD$");
3774462Salfred
3874462Salfred/*
3974462Salfred * rpc_generic.c, Miscl routines for RPC.
4074462Salfred *
4174462Salfred */
4274462Salfred
4375094Siedowse#include "namespace.h"
4474462Salfred#include "reentrant.h"
4574462Salfred#include <sys/types.h>
4674462Salfred#include <sys/param.h>
4774462Salfred#include <sys/socket.h>
4874462Salfred#include <sys/time.h>
4974462Salfred#include <sys/un.h>
5074462Salfred#include <sys/resource.h>
5174462Salfred#include <netinet/in.h>
5274462Salfred#include <arpa/inet.h>
5374462Salfred#include <rpc/rpc.h>
5474462Salfred#include <ctype.h>
5576523Siedowse#include <stddef.h>
5674462Salfred#include <stdio.h>
5774462Salfred#include <netdb.h>
5874462Salfred#include <netconfig.h>
5974462Salfred#include <stdlib.h>
6074462Salfred#include <string.h>
6174462Salfred#include <syslog.h>
6274462Salfred#include <rpc/nettype.h>
6374462Salfred#include "un-namespace.h"
6474462Salfred#include "rpc_com.h"
65156090Sdeischen#include "mt_misc.h"
6674462Salfred
6774462Salfredstruct handle {
6874462Salfred	NCONF_HANDLE *nhandle;
6974462Salfred	int nflag;		/* Whether NETPATH or NETCONFIG */
7074462Salfred	int nettype;
7174462Salfred};
7274462Salfred
7374462Salfredstatic const struct _rpcnettype {
7474462Salfred	const char *name;
7574462Salfred	const int type;
7674462Salfred} _rpctypelist[] = {
7774462Salfred	{ "netpath", _RPC_NETPATH },
7874462Salfred	{ "visible", _RPC_VISIBLE },
7974462Salfred	{ "circuit_v", _RPC_CIRCUIT_V },
8074462Salfred	{ "datagram_v", _RPC_DATAGRAM_V },
8174462Salfred	{ "circuit_n", _RPC_CIRCUIT_N },
8274462Salfred	{ "datagram_n", _RPC_DATAGRAM_N },
8374462Salfred	{ "tcp", _RPC_TCP },
8474462Salfred	{ "udp", _RPC_UDP },
8574462Salfred	{ 0, _RPC_NONE }
8674462Salfred};
8774462Salfred
8874462Salfredstruct netid_af {
8974462Salfred	const char	*netid;
9074462Salfred	int		af;
9174462Salfred	int		protocol;
9274462Salfred};
9374462Salfred
9474462Salfredstatic const struct netid_af na_cvt[] = {
9574462Salfred	{ "udp",  AF_INET,  IPPROTO_UDP },
9674462Salfred	{ "tcp",  AF_INET,  IPPROTO_TCP },
9774462Salfred#ifdef INET6
9874462Salfred	{ "udp6", AF_INET6, IPPROTO_UDP },
9974462Salfred	{ "tcp6", AF_INET6, IPPROTO_TCP },
10074462Salfred#endif
101107952Smbr	{ "local", AF_LOCAL, 0 }
10274462Salfred};
10374462Salfred
10474462Salfred#if 0
10592905Sobrienstatic char *strlocase(char *);
10674462Salfred#endif
10792905Sobrienstatic int getnettype(const char *);
10874462Salfred
10974462Salfred/*
11074462Salfred * Cache the result of getrlimit(), so we don't have to do an
11174462Salfred * expensive call every time.
11274462Salfred */
11374462Salfredint
11474462Salfred__rpc_dtbsize()
11574462Salfred{
11674462Salfred	static int tbsize;
11774462Salfred	struct rlimit rl;
11874462Salfred
11974462Salfred	if (tbsize) {
12074462Salfred		return (tbsize);
12174462Salfred	}
12274462Salfred	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
12374462Salfred		return (tbsize = (int)rl.rlim_max);
12474462Salfred	}
12574462Salfred	/*
12674462Salfred	 * Something wrong.  I'll try to save face by returning a
12774462Salfred	 * pessimistic number.
12874462Salfred	 */
12974462Salfred	return (32);
13074462Salfred}
13174462Salfred
13274462Salfred
13374462Salfred/*
13474462Salfred * Find the appropriate buffer size
13574462Salfred */
13674462Salfredu_int
13774462Salfred/*ARGSUSED*/
13874462Salfred__rpc_get_t_size(af, proto, size)
13974462Salfred	int af, proto;
14074462Salfred	int size;	/* Size requested */
14174462Salfred{
14275314Siedowse	int maxsize, defsize;
14374462Salfred
14475314Siedowse	maxsize = 256 * 1024;	/* XXX */
14574462Salfred	switch (proto) {
14674462Salfred	case IPPROTO_TCP:
14775314Siedowse		defsize = 64 * 1024;	/* XXX */
14874462Salfred		break;
14974462Salfred	case IPPROTO_UDP:
15075314Siedowse		defsize = UDPMSGSIZE;
15174462Salfred		break;
15274462Salfred	default:
15375314Siedowse		defsize = RPC_MAXDATASIZE;
15474462Salfred		break;
15574462Salfred	}
15674462Salfred	if (size == 0)
15775314Siedowse		return defsize;
15874462Salfred
15974462Salfred	/* Check whether the value is within the upper max limit */
16074462Salfred	return (size > maxsize ? (u_int)maxsize : (u_int)size);
16174462Salfred}
16274462Salfred
16374462Salfred/*
16474462Salfred * Find the appropriate address buffer size
16574462Salfred */
16674462Salfredu_int
16774462Salfred__rpc_get_a_size(af)
16874462Salfred	int af;
16974462Salfred{
17074462Salfred	switch (af) {
17174462Salfred	case AF_INET:
17274462Salfred		return sizeof (struct sockaddr_in);
17374462Salfred#ifdef INET6
17474462Salfred	case AF_INET6:
17574462Salfred		return sizeof (struct sockaddr_in6);
17674462Salfred#endif
17774462Salfred	case AF_LOCAL:
17874462Salfred		return sizeof (struct sockaddr_un);
17974462Salfred	default:
18074462Salfred		break;
18174462Salfred	}
18274462Salfred	return ((u_int)RPC_MAXADDRSIZE);
18374462Salfred}
18474462Salfred
18574462Salfred#if 0
18674462Salfredstatic char *
18774462Salfredstrlocase(p)
18874462Salfred	char *p;
18974462Salfred{
19074462Salfred	char *t = p;
19174462Salfred
19274462Salfred	for (; *p; p++)
19374462Salfred		if (isupper(*p))
19474462Salfred			*p = tolower(*p);
19574462Salfred	return (t);
19674462Salfred}
19774462Salfred#endif
19874462Salfred
19974462Salfred/*
20074462Salfred * Returns the type of the network as defined in <rpc/nettype.h>
20174462Salfred * If nettype is NULL, it defaults to NETPATH.
20274462Salfred */
20374462Salfredstatic int
20474462Salfredgetnettype(nettype)
20574462Salfred	const char *nettype;
20674462Salfred{
20774462Salfred	int i;
20874462Salfred
209121652Smbr	if ((nettype == NULL) || (nettype[0] == 0)) {
21074462Salfred		return (_RPC_NETPATH);	/* Default */
21174462Salfred	}
21274462Salfred
21374462Salfred#if 0
21474462Salfred	nettype = strlocase(nettype);
21574462Salfred#endif
21674462Salfred	for (i = 0; _rpctypelist[i].name; i++)
21774462Salfred		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
21874462Salfred			return (_rpctypelist[i].type);
21974462Salfred		}
22074462Salfred	return (_rpctypelist[i].type);
22174462Salfred}
22274462Salfred
223204950Sjhbstatic thread_key_t tcp_key, udp_key;
224204950Sjhbstatic once_t keys_once = ONCE_INITIALIZER;
225204950Sjhbstatic int tcp_key_error, udp_key_error;
226204950Sjhb
227204950Sjhbstatic void
228204950Sjhbkeys_init(void)
229204950Sjhb{
230204950Sjhb
231204950Sjhb	tcp_key_error = thr_keycreate(&tcp_key, free);
232204950Sjhb	udp_key_error = thr_keycreate(&udp_key, free);
233204950Sjhb}
234204950Sjhb
23574462Salfred/*
23674462Salfred * For the given nettype (tcp or udp only), return the first structure found.
23774462Salfred * This should be freed by calling freenetconfigent()
23874462Salfred */
23974462Salfredstruct netconfig *
24074462Salfred__rpc_getconfip(nettype)
24174462Salfred	const char *nettype;
24274462Salfred{
24374462Salfred	char *netid;
24474462Salfred	char *netid_tcp = (char *) NULL;
24574462Salfred	char *netid_udp = (char *) NULL;
24674462Salfred	static char *netid_tcp_main;
24774462Salfred	static char *netid_udp_main;
24874462Salfred	struct netconfig *dummy;
24974462Salfred	int main_thread;
25074462Salfred
25174462Salfred	if ((main_thread = thr_main())) {
25274462Salfred		netid_udp = netid_udp_main;
25374462Salfred		netid_tcp = netid_tcp_main;
25474462Salfred	} else {
255204950Sjhb		if (thr_once(&keys_once, keys_init) != 0 ||
256204950Sjhb		    tcp_key_error != 0 || udp_key_error != 0)
257204950Sjhb			return (NULL);
25874462Salfred		netid_tcp = (char *)thr_getspecific(tcp_key);
25974462Salfred		netid_udp = (char *)thr_getspecific(udp_key);
26074462Salfred	}
26174462Salfred	if (!netid_udp && !netid_tcp) {
26274462Salfred		struct netconfig *nconf;
26374462Salfred		void *confighandle;
26474462Salfred
26574462Salfred		if (!(confighandle = setnetconfig())) {
26674462Salfred			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
26774462Salfred			return (NULL);
26874462Salfred		}
26974462Salfred		while ((nconf = getnetconfig(confighandle)) != NULL) {
27074462Salfred			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
271241408Spfg				if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
272241408Spfg				    netid_tcp == NULL) {
27374462Salfred					netid_tcp = strdup(nconf->nc_netid);
27474462Salfred					if (main_thread)
27574462Salfred						netid_tcp_main = netid_tcp;
27674462Salfred					else
27774462Salfred						thr_setspecific(tcp_key,
27874462Salfred							(void *) netid_tcp);
27974462Salfred				} else
280241408Spfg				if (strcmp(nconf->nc_proto, NC_UDP) == 0 &&
281241408Spfg				    netid_udp == NULL) {
28274462Salfred					netid_udp = strdup(nconf->nc_netid);
28374462Salfred					if (main_thread)
28474462Salfred						netid_udp_main = netid_udp;
28574462Salfred					else
28674462Salfred						thr_setspecific(udp_key,
28774462Salfred						(void *) netid_udp);
28874462Salfred				}
28974462Salfred			}
29074462Salfred		}
29174462Salfred		endnetconfig(confighandle);
29274462Salfred	}
29374462Salfred	if (strcmp(nettype, "udp") == 0)
29474462Salfred		netid = netid_udp;
29574462Salfred	else if (strcmp(nettype, "tcp") == 0)
29674462Salfred		netid = netid_tcp;
29774462Salfred	else {
29874462Salfred		return (NULL);
29974462Salfred	}
300121652Smbr	if ((netid == NULL) || (netid[0] == 0)) {
30174462Salfred		return (NULL);
30274462Salfred	}
30374462Salfred	dummy = getnetconfigent(netid);
30474462Salfred	return (dummy);
30574462Salfred}
30674462Salfred
30774462Salfred/*
30874462Salfred * Returns the type of the nettype, which should then be used with
30974462Salfred * __rpc_getconf().
31074462Salfred */
31174462Salfredvoid *
31274462Salfred__rpc_setconf(nettype)
31374462Salfred	const char *nettype;
31474462Salfred{
31574462Salfred	struct handle *handle;
31674462Salfred
31774462Salfred	handle = (struct handle *) malloc(sizeof (struct handle));
31874462Salfred	if (handle == NULL) {
31974462Salfred		return (NULL);
32074462Salfred	}
32174462Salfred	switch (handle->nettype = getnettype(nettype)) {
32274462Salfred	case _RPC_NETPATH:
32374462Salfred	case _RPC_CIRCUIT_N:
32474462Salfred	case _RPC_DATAGRAM_N:
325172259Smatteo		if (!(handle->nhandle = setnetpath()))
326172259Smatteo			goto failed;
32774462Salfred		handle->nflag = TRUE;
32874462Salfred		break;
32974462Salfred	case _RPC_VISIBLE:
33074462Salfred	case _RPC_CIRCUIT_V:
33174462Salfred	case _RPC_DATAGRAM_V:
33274462Salfred	case _RPC_TCP:
33374462Salfred	case _RPC_UDP:
33474462Salfred		if (!(handle->nhandle = setnetconfig())) {
33574462Salfred		        syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
336172259Smatteo			goto failed;
33774462Salfred		}
33874462Salfred		handle->nflag = FALSE;
33974462Salfred		break;
34074462Salfred	default:
341172259Smatteo		goto failed;
34274462Salfred	}
34374462Salfred
34474462Salfred	return (handle);
345172259Smatteo
346172259Smatteofailed:
347172259Smatteo	free(handle);
348172259Smatteo	return (NULL);
34974462Salfred}
35074462Salfred
35174462Salfred/*
35274462Salfred * Returns the next netconfig struct for the given "net" type.
35374462Salfred * __rpc_setconf() should have been called previously.
35474462Salfred */
35574462Salfredstruct netconfig *
35674462Salfred__rpc_getconf(vhandle)
35774462Salfred	void *vhandle;
35874462Salfred{
35974462Salfred	struct handle *handle;
36074462Salfred	struct netconfig *nconf;
36174462Salfred
36274462Salfred	handle = (struct handle *)vhandle;
36374462Salfred	if (handle == NULL) {
36474462Salfred		return (NULL);
36574462Salfred	}
36674462Salfred	for (;;) {
36774462Salfred		if (handle->nflag)
36874462Salfred			nconf = getnetpath(handle->nhandle);
36974462Salfred		else
37074462Salfred			nconf = getnetconfig(handle->nhandle);
37174462Salfred		if (nconf == NULL)
37274462Salfred			break;
37374462Salfred		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
37474462Salfred			(nconf->nc_semantics != NC_TPI_COTS) &&
37574462Salfred			(nconf->nc_semantics != NC_TPI_COTS_ORD))
37674462Salfred			continue;
37774462Salfred		switch (handle->nettype) {
37874462Salfred		case _RPC_VISIBLE:
37974462Salfred			if (!(nconf->nc_flag & NC_VISIBLE))
38074462Salfred				continue;
38174462Salfred			/* FALLTHROUGH */
38274462Salfred		case _RPC_NETPATH:	/* Be happy */
38374462Salfred			break;
38474462Salfred		case _RPC_CIRCUIT_V:
38574462Salfred			if (!(nconf->nc_flag & NC_VISIBLE))
38674462Salfred				continue;
38774462Salfred			/* FALLTHROUGH */
38874462Salfred		case _RPC_CIRCUIT_N:
38974462Salfred			if ((nconf->nc_semantics != NC_TPI_COTS) &&
39074462Salfred				(nconf->nc_semantics != NC_TPI_COTS_ORD))
39174462Salfred				continue;
39274462Salfred			break;
39374462Salfred		case _RPC_DATAGRAM_V:
39474462Salfred			if (!(nconf->nc_flag & NC_VISIBLE))
39574462Salfred				continue;
39674462Salfred			/* FALLTHROUGH */
39774462Salfred		case _RPC_DATAGRAM_N:
39874462Salfred			if (nconf->nc_semantics != NC_TPI_CLTS)
39974462Salfred				continue;
40074462Salfred			break;
40174462Salfred		case _RPC_TCP:
40274462Salfred			if (((nconf->nc_semantics != NC_TPI_COTS) &&
40374462Salfred				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
40474462Salfred				(strcmp(nconf->nc_protofmly, NC_INET)
40574462Salfred#ifdef INET6
40674462Salfred				 && strcmp(nconf->nc_protofmly, NC_INET6))
40774462Salfred#else
40874462Salfred				)
40974462Salfred#endif
41074462Salfred				||
41174462Salfred				strcmp(nconf->nc_proto, NC_TCP))
41274462Salfred				continue;
41374462Salfred			break;
41474462Salfred		case _RPC_UDP:
41574462Salfred			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
41674462Salfred				(strcmp(nconf->nc_protofmly, NC_INET)
41774462Salfred#ifdef INET6
41874462Salfred				&& strcmp(nconf->nc_protofmly, NC_INET6))
41974462Salfred#else
42074462Salfred				)
42174462Salfred#endif
42274462Salfred				||
42374462Salfred				strcmp(nconf->nc_proto, NC_UDP))
42474462Salfred				continue;
42574462Salfred			break;
42674462Salfred		}
42774462Salfred		break;
42874462Salfred	}
42974462Salfred	return (nconf);
43074462Salfred}
43174462Salfred
43274462Salfredvoid
43374462Salfred__rpc_endconf(vhandle)
43474462Salfred	void * vhandle;
43574462Salfred{
43674462Salfred	struct handle *handle;
43774462Salfred
43874462Salfred	handle = (struct handle *) vhandle;
43974462Salfred	if (handle == NULL) {
44074462Salfred		return;
44174462Salfred	}
44274462Salfred	if (handle->nflag) {
44374462Salfred		endnetpath(handle->nhandle);
44474462Salfred	} else {
44574462Salfred		endnetconfig(handle->nhandle);
44674462Salfred	}
44774462Salfred	free(handle);
44874462Salfred}
44974462Salfred
45074462Salfred/*
45174462Salfred * Used to ping the NULL procedure for clnt handle.
45274462Salfred * Returns NULL if fails, else a non-NULL pointer.
45374462Salfred */
45474462Salfredvoid *
45574462Salfredrpc_nullproc(clnt)
45674462Salfred	CLIENT *clnt;
45774462Salfred{
45874462Salfred	struct timeval TIMEOUT = {25, 0};
45974462Salfred
46074462Salfred	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
46174462Salfred		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
46274462Salfred		return (NULL);
46374462Salfred	}
46474462Salfred	return ((void *) clnt);
46574462Salfred}
46674462Salfred
46774462Salfred/*
46874462Salfred * Try all possible transports until
46974462Salfred * one succeeds in finding the netconf for the given fd.
47074462Salfred */
47174462Salfredstruct netconfig *
47274462Salfred__rpcgettp(fd)
47374462Salfred	int fd;
47474462Salfred{
47574462Salfred	const char *netid;
47674462Salfred	struct __rpc_sockinfo si;
47774462Salfred
47874462Salfred	if (!__rpc_fd2sockinfo(fd, &si))
47974462Salfred		return NULL;
48074462Salfred
48174462Salfred	if (!__rpc_sockinfo2netid(&si, &netid))
48274462Salfred		return NULL;
48374462Salfred
48474462Salfred	/*LINTED const castaway*/
48574462Salfred	return getnetconfigent((char *)netid);
48674462Salfred}
48774462Salfred
48874462Salfredint
48974462Salfred__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
49074462Salfred{
49174462Salfred	socklen_t len;
49274462Salfred	int type, proto;
49374462Salfred	struct sockaddr_storage ss;
49474462Salfred
49574462Salfred	len = sizeof ss;
49674462Salfred	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
49774462Salfred		return 0;
49874462Salfred	sip->si_alen = len;
49974462Salfred
50074462Salfred	len = sizeof type;
50174462Salfred	if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
50274462Salfred		return 0;
50374462Salfred
50474462Salfred	/* XXX */
50574462Salfred	if (ss.ss_family != AF_LOCAL) {
50674462Salfred		if (type == SOCK_STREAM)
50774462Salfred			proto = IPPROTO_TCP;
50874462Salfred		else if (type == SOCK_DGRAM)
50974462Salfred			proto = IPPROTO_UDP;
51074462Salfred		else
51174462Salfred			return 0;
51274462Salfred	} else
51374462Salfred		proto = 0;
51474462Salfred
51574462Salfred	sip->si_af = ss.ss_family;
51674462Salfred	sip->si_proto = proto;
51774462Salfred	sip->si_socktype = type;
51874462Salfred
51974462Salfred	return 1;
52074462Salfred}
52174462Salfred
52274462Salfred/*
52374462Salfred * Linear search, but the number of entries is small.
52474462Salfred */
52574462Salfredint
52674462Salfred__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
52774462Salfred{
52874462Salfred	int i;
52974462Salfred
53074462Salfred	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
531107952Smbr		if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
532107952Smbr		    strcmp(nconf->nc_netid, "unix") == 0 &&
533107952Smbr		    strcmp(na_cvt[i].netid, "local") == 0)) {
53474462Salfred			sip->si_af = na_cvt[i].af;
53574462Salfred			sip->si_proto = na_cvt[i].protocol;
53674462Salfred			sip->si_socktype =
53774462Salfred			    __rpc_seman2socktype((int)nconf->nc_semantics);
53874462Salfred			if (sip->si_socktype == -1)
53974462Salfred				return 0;
54074462Salfred			sip->si_alen = __rpc_get_a_size(sip->si_af);
54174462Salfred			return 1;
54274462Salfred		}
54374462Salfred
54474462Salfred	return 0;
54574462Salfred}
54674462Salfred
54774462Salfredint
54874462Salfred__rpc_nconf2fd(const struct netconfig *nconf)
54974462Salfred{
55074462Salfred	struct __rpc_sockinfo si;
55174462Salfred
55274462Salfred	if (!__rpc_nconf2sockinfo(nconf, &si))
55374462Salfred		return 0;
55474462Salfred
55574462Salfred	return _socket(si.si_af, si.si_socktype, si.si_proto);
55674462Salfred}
55774462Salfred
55874462Salfredint
55974462Salfred__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
56074462Salfred{
56174462Salfred	int i;
562109384Smbr	struct netconfig *nconf;
56374462Salfred
564109384Smbr	nconf = getnetconfigent("local");
565109384Smbr
566107952Smbr	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
56774462Salfred		if (na_cvt[i].af == sip->si_af &&
56874462Salfred		    na_cvt[i].protocol == sip->si_proto) {
569109384Smbr			if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
570107952Smbr				if (netid)
571107952Smbr					*netid = "unix";
572107952Smbr			} else {
573107952Smbr				if (netid)
574107952Smbr					*netid = na_cvt[i].netid;
575107952Smbr			}
576109384Smbr			if (nconf != NULL)
577109384Smbr				freenetconfigent(nconf);
57874462Salfred			return 1;
57974462Salfred		}
580107952Smbr	}
581109384Smbr	if (nconf != NULL)
582109384Smbr		freenetconfigent(nconf);
58374462Salfred
58474462Salfred	return 0;
58574462Salfred}
58674462Salfred
58774462Salfredchar *
58874462Salfredtaddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
58974462Salfred{
59074462Salfred	struct __rpc_sockinfo si;
59174462Salfred
59274462Salfred	if (!__rpc_nconf2sockinfo(nconf, &si))
59374462Salfred		return NULL;
59474462Salfred	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
59574462Salfred}
59674462Salfred
59774462Salfredstruct netbuf *
59874462Salfreduaddr2taddr(const struct netconfig *nconf, const char *uaddr)
59974462Salfred{
60074462Salfred	struct __rpc_sockinfo si;
60174462Salfred
60274462Salfred	if (!__rpc_nconf2sockinfo(nconf, &si))
60374462Salfred		return NULL;
60474462Salfred	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
60574462Salfred}
60674462Salfred
60774462Salfredchar *
60874462Salfred__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
60974462Salfred{
61074462Salfred	char *ret;
61174462Salfred	struct sockaddr_in *sin;
61274462Salfred	struct sockaddr_un *sun;
61374462Salfred	char namebuf[INET_ADDRSTRLEN];
61474462Salfred#ifdef INET6
61574462Salfred	struct sockaddr_in6 *sin6;
61674462Salfred	char namebuf6[INET6_ADDRSTRLEN];
61774462Salfred#endif
61874462Salfred	u_int16_t port;
61974462Salfred
62074462Salfred	switch (af) {
62174462Salfred	case AF_INET:
62274462Salfred		sin = nbuf->buf;
62374462Salfred		if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
62474462Salfred		    == NULL)
62574462Salfred			return NULL;
62674462Salfred		port = ntohs(sin->sin_port);
62774462Salfred		if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
62874462Salfred		    port & 0xff) < 0)
62974462Salfred			return NULL;
63074462Salfred		break;
63174462Salfred#ifdef INET6
63274462Salfred	case AF_INET6:
63374462Salfred		sin6 = nbuf->buf;
63474462Salfred		if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
63574462Salfred		    == NULL)
63674462Salfred			return NULL;
63774462Salfred		port = ntohs(sin6->sin6_port);
63874462Salfred		if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
63974462Salfred		    port & 0xff) < 0)
64074462Salfred			return NULL;
64174462Salfred		break;
64274462Salfred#endif
64374462Salfred	case AF_LOCAL:
64474462Salfred		sun = nbuf->buf;
64576523Siedowse		if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
64676523Siedowse		    offsetof(struct sockaddr_un, sun_path)),
64776523Siedowse		    sun->sun_path) < 0)
64876523Siedowse			return (NULL);
64974462Salfred		break;
65074462Salfred	default:
65174462Salfred		return NULL;
65274462Salfred	}
65374462Salfred
65474462Salfred	return ret;
65574462Salfred}
65674462Salfred
65774462Salfredstruct netbuf *
65874462Salfred__rpc_uaddr2taddr_af(int af, const char *uaddr)
65974462Salfred{
66074462Salfred	struct netbuf *ret = NULL;
66174462Salfred	char *addrstr, *p;
66274462Salfred	unsigned port, portlo, porthi;
66374462Salfred	struct sockaddr_in *sin;
66474462Salfred#ifdef INET6
66574462Salfred	struct sockaddr_in6 *sin6;
66674462Salfred#endif
66774462Salfred	struct sockaddr_un *sun;
66874462Salfred
66990271Salfred	port = 0;
67090271Salfred	sin = NULL;
67174462Salfred	addrstr = strdup(uaddr);
67274462Salfred	if (addrstr == NULL)
67374462Salfred		return NULL;
67474462Salfred
67574462Salfred	/*
67674462Salfred	 * AF_LOCAL addresses are expected to be absolute
67774462Salfred	 * pathnames, anything else will be AF_INET or AF_INET6.
67874462Salfred	 */
67974462Salfred	if (*addrstr != '/') {
68074462Salfred		p = strrchr(addrstr, '.');
68174462Salfred		if (p == NULL)
68274462Salfred			goto out;
68374462Salfred		portlo = (unsigned)atoi(p + 1);
68474462Salfred		*p = '\0';
68574462Salfred
68674462Salfred		p = strrchr(addrstr, '.');
68774462Salfred		if (p == NULL)
68874462Salfred			goto out;
68974462Salfred		porthi = (unsigned)atoi(p + 1);
69074462Salfred		*p = '\0';
69174462Salfred		port = (porthi << 8) | portlo;
69274462Salfred	}
69374462Salfred
69474462Salfred	ret = (struct netbuf *)malloc(sizeof *ret);
695109951Smbr	if (ret == NULL)
696109951Smbr		goto out;
69774462Salfred
69874462Salfred	switch (af) {
69974462Salfred	case AF_INET:
70074462Salfred		sin = (struct sockaddr_in *)malloc(sizeof *sin);
70174462Salfred		if (sin == NULL)
70274462Salfred			goto out;
70374462Salfred		memset(sin, 0, sizeof *sin);
70474462Salfred		sin->sin_family = AF_INET;
70574462Salfred		sin->sin_port = htons(port);
70674462Salfred		if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
70774462Salfred			free(sin);
70874462Salfred			free(ret);
70974462Salfred			ret = NULL;
71074462Salfred			goto out;
71174462Salfred		}
71274462Salfred		sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
71374462Salfred		ret->buf = sin;
71474462Salfred		break;
71574462Salfred#ifdef INET6
71674462Salfred	case AF_INET6:
71774462Salfred		sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
71874462Salfred		if (sin6 == NULL)
71974462Salfred			goto out;
72074462Salfred		memset(sin6, 0, sizeof *sin6);
72174462Salfred		sin6->sin6_family = AF_INET6;
72274462Salfred		sin6->sin6_port = htons(port);
72374462Salfred		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
724109951Smbr			free(sin6);
72574462Salfred			free(ret);
72674462Salfred			ret = NULL;
72774462Salfred			goto out;
72874462Salfred		}
72974462Salfred		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
73074462Salfred		ret->buf = sin6;
73174462Salfred		break;
73274462Salfred#endif
73374462Salfred	case AF_LOCAL:
73474462Salfred		sun = (struct sockaddr_un *)malloc(sizeof *sun);
73574462Salfred		if (sun == NULL)
73674462Salfred			goto out;
73774462Salfred		memset(sun, 0, sizeof *sun);
73874462Salfred		sun->sun_family = AF_LOCAL;
73974462Salfred		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
74076044Siedowse		ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
74176044Siedowse		ret->buf = sun;
74274462Salfred		break;
74374462Salfred	default:
74474462Salfred		break;
74574462Salfred	}
74674462Salfredout:
74774462Salfred	free(addrstr);
74874462Salfred	return ret;
74974462Salfred}
75074462Salfred
75174462Salfredint
75274462Salfred__rpc_seman2socktype(int semantics)
75374462Salfred{
75474462Salfred	switch (semantics) {
75574462Salfred	case NC_TPI_CLTS:
75674462Salfred		return SOCK_DGRAM;
75774462Salfred	case NC_TPI_COTS_ORD:
75874462Salfred		return SOCK_STREAM;
75974462Salfred	case NC_TPI_RAW:
76074462Salfred		return SOCK_RAW;
76174462Salfred	default:
76274462Salfred		break;
76374462Salfred	}
76474462Salfred
76574462Salfred	return -1;
76674462Salfred}
76774462Salfred
76874462Salfredint
76974462Salfred__rpc_socktype2seman(int socktype)
77074462Salfred{
77174462Salfred	switch (socktype) {
77274462Salfred	case SOCK_DGRAM:
77374462Salfred		return NC_TPI_CLTS;
77474462Salfred	case SOCK_STREAM:
77574462Salfred		return NC_TPI_COTS_ORD;
77674462Salfred	case SOCK_RAW:
77774462Salfred		return NC_TPI_RAW;
77874462Salfred	default:
77974462Salfred		break;
78074462Salfred	}
78174462Salfred
78274462Salfred	return -1;
78374462Salfred}
78474462Salfred
78574462Salfred/*
78674462Salfred * XXXX - IPv6 scope IDs can't be handled in universal addresses.
78774462Salfred * Here, we compare the original server address to that of the RPC
78874462Salfred * service we just received back from a call to rpcbind on the remote
78974462Salfred * machine. If they are both "link local" or "site local", copy
79074462Salfred * the scope id of the server address over to the service address.
79174462Salfred */
79274462Salfredint
79374462Salfred__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
79474462Salfred{
79574462Salfred#ifdef INET6
79674462Salfred	struct sockaddr *sa_new, *sa_svc;
79774462Salfred	struct sockaddr_in6 *sin6_new, *sin6_svc;
79874462Salfred
79974462Salfred	sa_svc = (struct sockaddr *)svc->buf;
80074462Salfred	sa_new = (struct sockaddr *)new->buf;
80174462Salfred
80274462Salfred	if (sa_new->sa_family == sa_svc->sa_family &&
80374462Salfred	    sa_new->sa_family == AF_INET6) {
80474462Salfred		sin6_new = (struct sockaddr_in6 *)new->buf;
80574462Salfred		sin6_svc = (struct sockaddr_in6 *)svc->buf;
80674462Salfred
80774462Salfred		if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
80874462Salfred		     IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
80974462Salfred		    (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
81074462Salfred		     IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
81174462Salfred			sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
81274462Salfred		}
81374462Salfred	}
81474462Salfred#endif
81574462Salfred	return 1;
81674462Salfred}
81774462Salfred
81874462Salfredint
81974462Salfred__rpc_sockisbound(int fd)
82074462Salfred{
82174462Salfred	struct sockaddr_storage ss;
82274462Salfred	socklen_t slen;
82374462Salfred
82474462Salfred	slen = sizeof (struct sockaddr_storage);
82574462Salfred	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
82674462Salfred		return 0;
82774462Salfred
82874462Salfred	switch (ss.ss_family) {
82974462Salfred		case AF_INET:
83074462Salfred			return (((struct sockaddr_in *)
83174462Salfred			    (void *)&ss)->sin_port != 0);
83274462Salfred#ifdef INET6
83374462Salfred		case AF_INET6:
83474462Salfred			return (((struct sockaddr_in6 *)
83574462Salfred			    (void *)&ss)->sin6_port != 0);
83674462Salfred#endif
83774462Salfred		case AF_LOCAL:
83874462Salfred			/* XXX check this */
83974462Salfred			return (((struct sockaddr_un *)
84074462Salfred			    (void *)&ss)->sun_path[0] != '\0');
84174462Salfred		default:
84274462Salfred			break;
84374462Salfred	}
84474462Salfred
84574462Salfred	return 0;
84674462Salfred}
847