174462Salfred/*	$NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $	*/
274462Salfred
3261046Smav/*-
4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc.
5261046Smav * All rights reserved.
6261046Smav *
7261046Smav * Redistribution and use in source and binary forms, with or without
8261046Smav * modification, are permitted provided that the following conditions are met:
9261046Smav * - Redistributions of source code must retain the above copyright notice,
10261046Smav *   this list of conditions and the following disclaimer.
11261046Smav * - Redistributions in binary form must reproduce the above copyright notice,
12261046Smav *   this list of conditions and the following disclaimer in the documentation
13261046Smav *   and/or other materials provided with the distribution.
14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its
15261046Smav *   contributors may be used to endorse or promote products derived
16261046Smav *   from this software without specific prior written permission.
1774462Salfred *
18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28261046Smav * 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: stable/10/lib/libc/rpc/rpc_generic.c 319615 2017-06-06 07:22:26Z delphij $");
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
114309487Sngie__rpc_dtbsize(void)
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
135309487Sngie *
136309487Sngie * size - Size requested
13774462Salfred */
13874462Salfredu_int
13974462Salfred/*ARGSUSED*/
140309487Sngie__rpc_get_t_size(int af, int proto, int size)
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
167309487Sngie__rpc_get_a_size(int af)
16874462Salfred{
16974462Salfred	switch (af) {
17074462Salfred	case AF_INET:
17174462Salfred		return sizeof (struct sockaddr_in);
17274462Salfred#ifdef INET6
17374462Salfred	case AF_INET6:
17474462Salfred		return sizeof (struct sockaddr_in6);
17574462Salfred#endif
17674462Salfred	case AF_LOCAL:
17774462Salfred		return sizeof (struct sockaddr_un);
17874462Salfred	default:
17974462Salfred		break;
18074462Salfred	}
18174462Salfred	return ((u_int)RPC_MAXADDRSIZE);
18274462Salfred}
18374462Salfred
18474462Salfred#if 0
18574462Salfredstatic char *
186309487Sngiestrlocase(char *p)
18774462Salfred{
18874462Salfred	char *t = p;
18974462Salfred
19074462Salfred	for (; *p; p++)
19174462Salfred		if (isupper(*p))
19274462Salfred			*p = tolower(*p);
19374462Salfred	return (t);
19474462Salfred}
19574462Salfred#endif
19674462Salfred
19774462Salfred/*
19874462Salfred * Returns the type of the network as defined in <rpc/nettype.h>
19974462Salfred * If nettype is NULL, it defaults to NETPATH.
20074462Salfred */
20174462Salfredstatic int
202309487Sngiegetnettype(const char *nettype)
20374462Salfred{
20474462Salfred	int i;
20574462Salfred
206121652Smbr	if ((nettype == NULL) || (nettype[0] == 0)) {
20774462Salfred		return (_RPC_NETPATH);	/* Default */
20874462Salfred	}
20974462Salfred
21074462Salfred#if 0
21174462Salfred	nettype = strlocase(nettype);
21274462Salfred#endif
21374462Salfred	for (i = 0; _rpctypelist[i].name; i++)
21474462Salfred		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
21574462Salfred			return (_rpctypelist[i].type);
21674462Salfred		}
21774462Salfred	return (_rpctypelist[i].type);
21874462Salfred}
21974462Salfred
220204950Sjhbstatic thread_key_t tcp_key, udp_key;
221204950Sjhbstatic once_t keys_once = ONCE_INITIALIZER;
222204950Sjhbstatic int tcp_key_error, udp_key_error;
223204950Sjhb
224204950Sjhbstatic void
225204950Sjhbkeys_init(void)
226204950Sjhb{
227204950Sjhb
228204950Sjhb	tcp_key_error = thr_keycreate(&tcp_key, free);
229204950Sjhb	udp_key_error = thr_keycreate(&udp_key, free);
230204950Sjhb}
231204950Sjhb
23274462Salfred/*
23374462Salfred * For the given nettype (tcp or udp only), return the first structure found.
23474462Salfred * This should be freed by calling freenetconfigent()
23574462Salfred */
23674462Salfredstruct netconfig *
237309487Sngie__rpc_getconfip(const char *nettype)
23874462Salfred{
23974462Salfred	char *netid;
24074462Salfred	char *netid_tcp = (char *) NULL;
24174462Salfred	char *netid_udp = (char *) NULL;
24274462Salfred	static char *netid_tcp_main;
24374462Salfred	static char *netid_udp_main;
24474462Salfred	struct netconfig *dummy;
24574462Salfred	int main_thread;
24674462Salfred
24774462Salfred	if ((main_thread = thr_main())) {
24874462Salfred		netid_udp = netid_udp_main;
24974462Salfred		netid_tcp = netid_tcp_main;
25074462Salfred	} else {
251204950Sjhb		if (thr_once(&keys_once, keys_init) != 0 ||
252204950Sjhb		    tcp_key_error != 0 || udp_key_error != 0)
253204950Sjhb			return (NULL);
25474462Salfred		netid_tcp = (char *)thr_getspecific(tcp_key);
25574462Salfred		netid_udp = (char *)thr_getspecific(udp_key);
25674462Salfred	}
25774462Salfred	if (!netid_udp && !netid_tcp) {
25874462Salfred		struct netconfig *nconf;
25974462Salfred		void *confighandle;
26074462Salfred
26174462Salfred		if (!(confighandle = setnetconfig())) {
26274462Salfred			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
26374462Salfred			return (NULL);
26474462Salfred		}
26574462Salfred		while ((nconf = getnetconfig(confighandle)) != NULL) {
26674462Salfred			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
267241142Spfg				if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
268241142Spfg				    netid_tcp == NULL) {
26974462Salfred					netid_tcp = strdup(nconf->nc_netid);
27074462Salfred					if (main_thread)
27174462Salfred						netid_tcp_main = netid_tcp;
27274462Salfred					else
27374462Salfred						thr_setspecific(tcp_key,
27474462Salfred							(void *) netid_tcp);
27574462Salfred				} else
276241142Spfg				if (strcmp(nconf->nc_proto, NC_UDP) == 0 &&
277241142Spfg				    netid_udp == NULL) {
27874462Salfred					netid_udp = strdup(nconf->nc_netid);
27974462Salfred					if (main_thread)
28074462Salfred						netid_udp_main = netid_udp;
28174462Salfred					else
28274462Salfred						thr_setspecific(udp_key,
28374462Salfred						(void *) netid_udp);
28474462Salfred				}
28574462Salfred			}
28674462Salfred		}
28774462Salfred		endnetconfig(confighandle);
28874462Salfred	}
28974462Salfred	if (strcmp(nettype, "udp") == 0)
29074462Salfred		netid = netid_udp;
29174462Salfred	else if (strcmp(nettype, "tcp") == 0)
29274462Salfred		netid = netid_tcp;
29374462Salfred	else {
29474462Salfred		return (NULL);
29574462Salfred	}
296121652Smbr	if ((netid == NULL) || (netid[0] == 0)) {
29774462Salfred		return (NULL);
29874462Salfred	}
29974462Salfred	dummy = getnetconfigent(netid);
30074462Salfred	return (dummy);
30174462Salfred}
30274462Salfred
30374462Salfred/*
30474462Salfred * Returns the type of the nettype, which should then be used with
30574462Salfred * __rpc_getconf().
30674462Salfred */
30774462Salfredvoid *
308309487Sngie__rpc_setconf(const char *nettype)
30974462Salfred{
31074462Salfred	struct handle *handle;
31174462Salfred
31274462Salfred	handle = (struct handle *) malloc(sizeof (struct handle));
31374462Salfred	if (handle == NULL) {
31474462Salfred		return (NULL);
31574462Salfred	}
31674462Salfred	switch (handle->nettype = getnettype(nettype)) {
31774462Salfred	case _RPC_NETPATH:
31874462Salfred	case _RPC_CIRCUIT_N:
31974462Salfred	case _RPC_DATAGRAM_N:
320172259Smatteo		if (!(handle->nhandle = setnetpath()))
321172259Smatteo			goto failed;
32274462Salfred		handle->nflag = TRUE;
32374462Salfred		break;
32474462Salfred	case _RPC_VISIBLE:
32574462Salfred	case _RPC_CIRCUIT_V:
32674462Salfred	case _RPC_DATAGRAM_V:
32774462Salfred	case _RPC_TCP:
32874462Salfred	case _RPC_UDP:
32974462Salfred		if (!(handle->nhandle = setnetconfig())) {
33074462Salfred		        syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
331172259Smatteo			goto failed;
33274462Salfred		}
33374462Salfred		handle->nflag = FALSE;
33474462Salfred		break;
33574462Salfred	default:
336172259Smatteo		goto failed;
33774462Salfred	}
33874462Salfred
33974462Salfred	return (handle);
340172259Smatteo
341172259Smatteofailed:
342172259Smatteo	free(handle);
343172259Smatteo	return (NULL);
34474462Salfred}
34574462Salfred
34674462Salfred/*
34774462Salfred * Returns the next netconfig struct for the given "net" type.
34874462Salfred * __rpc_setconf() should have been called previously.
34974462Salfred */
35074462Salfredstruct netconfig *
351309487Sngie__rpc_getconf(void *vhandle)
35274462Salfred{
35374462Salfred	struct handle *handle;
35474462Salfred	struct netconfig *nconf;
35574462Salfred
35674462Salfred	handle = (struct handle *)vhandle;
35774462Salfred	if (handle == NULL) {
35874462Salfred		return (NULL);
35974462Salfred	}
36074462Salfred	for (;;) {
36174462Salfred		if (handle->nflag)
36274462Salfred			nconf = getnetpath(handle->nhandle);
36374462Salfred		else
36474462Salfred			nconf = getnetconfig(handle->nhandle);
36574462Salfred		if (nconf == NULL)
36674462Salfred			break;
36774462Salfred		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
36874462Salfred			(nconf->nc_semantics != NC_TPI_COTS) &&
36974462Salfred			(nconf->nc_semantics != NC_TPI_COTS_ORD))
37074462Salfred			continue;
37174462Salfred		switch (handle->nettype) {
37274462Salfred		case _RPC_VISIBLE:
37374462Salfred			if (!(nconf->nc_flag & NC_VISIBLE))
37474462Salfred				continue;
37574462Salfred			/* FALLTHROUGH */
37674462Salfred		case _RPC_NETPATH:	/* Be happy */
37774462Salfred			break;
37874462Salfred		case _RPC_CIRCUIT_V:
37974462Salfred			if (!(nconf->nc_flag & NC_VISIBLE))
38074462Salfred				continue;
38174462Salfred			/* FALLTHROUGH */
38274462Salfred		case _RPC_CIRCUIT_N:
38374462Salfred			if ((nconf->nc_semantics != NC_TPI_COTS) &&
38474462Salfred				(nconf->nc_semantics != NC_TPI_COTS_ORD))
38574462Salfred				continue;
38674462Salfred			break;
38774462Salfred		case _RPC_DATAGRAM_V:
38874462Salfred			if (!(nconf->nc_flag & NC_VISIBLE))
38974462Salfred				continue;
39074462Salfred			/* FALLTHROUGH */
39174462Salfred		case _RPC_DATAGRAM_N:
39274462Salfred			if (nconf->nc_semantics != NC_TPI_CLTS)
39374462Salfred				continue;
39474462Salfred			break;
39574462Salfred		case _RPC_TCP:
39674462Salfred			if (((nconf->nc_semantics != NC_TPI_COTS) &&
39774462Salfred				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
39874462Salfred				(strcmp(nconf->nc_protofmly, NC_INET)
39974462Salfred#ifdef INET6
40074462Salfred				 && strcmp(nconf->nc_protofmly, NC_INET6))
40174462Salfred#else
40274462Salfred				)
40374462Salfred#endif
40474462Salfred				||
40574462Salfred				strcmp(nconf->nc_proto, NC_TCP))
40674462Salfred				continue;
40774462Salfred			break;
40874462Salfred		case _RPC_UDP:
40974462Salfred			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
41074462Salfred				(strcmp(nconf->nc_protofmly, NC_INET)
41174462Salfred#ifdef INET6
41274462Salfred				&& strcmp(nconf->nc_protofmly, NC_INET6))
41374462Salfred#else
41474462Salfred				)
41574462Salfred#endif
41674462Salfred				||
41774462Salfred				strcmp(nconf->nc_proto, NC_UDP))
41874462Salfred				continue;
41974462Salfred			break;
42074462Salfred		}
42174462Salfred		break;
42274462Salfred	}
42374462Salfred	return (nconf);
42474462Salfred}
42574462Salfred
42674462Salfredvoid
427309487Sngie__rpc_endconf(void *vhandle)
42874462Salfred{
42974462Salfred	struct handle *handle;
43074462Salfred
43174462Salfred	handle = (struct handle *) vhandle;
43274462Salfred	if (handle == NULL) {
43374462Salfred		return;
43474462Salfred	}
43574462Salfred	if (handle->nflag) {
43674462Salfred		endnetpath(handle->nhandle);
43774462Salfred	} else {
43874462Salfred		endnetconfig(handle->nhandle);
43974462Salfred	}
44074462Salfred	free(handle);
44174462Salfred}
44274462Salfred
44374462Salfred/*
44474462Salfred * Used to ping the NULL procedure for clnt handle.
44574462Salfred * Returns NULL if fails, else a non-NULL pointer.
44674462Salfred */
44774462Salfredvoid *
448309487Sngierpc_nullproc(CLIENT *clnt)
44974462Salfred{
45074462Salfred	struct timeval TIMEOUT = {25, 0};
45174462Salfred
45274462Salfred	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
45374462Salfred		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
45474462Salfred		return (NULL);
45574462Salfred	}
45674462Salfred	return ((void *) clnt);
45774462Salfred}
45874462Salfred
45974462Salfred/*
46074462Salfred * Try all possible transports until
46174462Salfred * one succeeds in finding the netconf for the given fd.
46274462Salfred */
46374462Salfredstruct netconfig *
464309487Sngie__rpcgettp(int fd)
46574462Salfred{
46674462Salfred	const char *netid;
46774462Salfred	struct __rpc_sockinfo si;
46874462Salfred
46974462Salfred	if (!__rpc_fd2sockinfo(fd, &si))
47074462Salfred		return NULL;
47174462Salfred
47274462Salfred	if (!__rpc_sockinfo2netid(&si, &netid))
47374462Salfred		return NULL;
47474462Salfred
47574462Salfred	/*LINTED const castaway*/
47674462Salfred	return getnetconfigent((char *)netid);
47774462Salfred}
47874462Salfred
47974462Salfredint
48074462Salfred__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
48174462Salfred{
48274462Salfred	socklen_t len;
48374462Salfred	int type, proto;
48474462Salfred	struct sockaddr_storage ss;
48574462Salfred
48674462Salfred	len = sizeof ss;
48774462Salfred	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
48874462Salfred		return 0;
48974462Salfred	sip->si_alen = len;
49074462Salfred
49174462Salfred	len = sizeof type;
49274462Salfred	if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
49374462Salfred		return 0;
49474462Salfred
49574462Salfred	/* XXX */
49674462Salfred	if (ss.ss_family != AF_LOCAL) {
49774462Salfred		if (type == SOCK_STREAM)
49874462Salfred			proto = IPPROTO_TCP;
49974462Salfred		else if (type == SOCK_DGRAM)
50074462Salfred			proto = IPPROTO_UDP;
50174462Salfred		else
50274462Salfred			return 0;
50374462Salfred	} else
50474462Salfred		proto = 0;
50574462Salfred
50674462Salfred	sip->si_af = ss.ss_family;
50774462Salfred	sip->si_proto = proto;
50874462Salfred	sip->si_socktype = type;
50974462Salfred
51074462Salfred	return 1;
51174462Salfred}
51274462Salfred
51374462Salfred/*
51474462Salfred * Linear search, but the number of entries is small.
51574462Salfred */
51674462Salfredint
51774462Salfred__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
51874462Salfred{
51974462Salfred	int i;
52074462Salfred
52174462Salfred	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
522107952Smbr		if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
523107952Smbr		    strcmp(nconf->nc_netid, "unix") == 0 &&
524107952Smbr		    strcmp(na_cvt[i].netid, "local") == 0)) {
52574462Salfred			sip->si_af = na_cvt[i].af;
52674462Salfred			sip->si_proto = na_cvt[i].protocol;
52774462Salfred			sip->si_socktype =
52874462Salfred			    __rpc_seman2socktype((int)nconf->nc_semantics);
52974462Salfred			if (sip->si_socktype == -1)
53074462Salfred				return 0;
53174462Salfred			sip->si_alen = __rpc_get_a_size(sip->si_af);
53274462Salfred			return 1;
53374462Salfred		}
53474462Salfred
53574462Salfred	return 0;
53674462Salfred}
53774462Salfred
53874462Salfredint
53974462Salfred__rpc_nconf2fd(const struct netconfig *nconf)
54074462Salfred{
54174462Salfred	struct __rpc_sockinfo si;
54274462Salfred
54374462Salfred	if (!__rpc_nconf2sockinfo(nconf, &si))
54474462Salfred		return 0;
54574462Salfred
54674462Salfred	return _socket(si.si_af, si.si_socktype, si.si_proto);
54774462Salfred}
54874462Salfred
54974462Salfredint
55074462Salfred__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
55174462Salfred{
55274462Salfred	int i;
553109384Smbr	struct netconfig *nconf;
55474462Salfred
555109384Smbr	nconf = getnetconfigent("local");
556109384Smbr
557107952Smbr	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
55874462Salfred		if (na_cvt[i].af == sip->si_af &&
55974462Salfred		    na_cvt[i].protocol == sip->si_proto) {
560109384Smbr			if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
561107952Smbr				if (netid)
562107952Smbr					*netid = "unix";
563107952Smbr			} else {
564107952Smbr				if (netid)
565107952Smbr					*netid = na_cvt[i].netid;
566107952Smbr			}
567109384Smbr			if (nconf != NULL)
568109384Smbr				freenetconfigent(nconf);
56974462Salfred			return 1;
57074462Salfred		}
571107952Smbr	}
572109384Smbr	if (nconf != NULL)
573109384Smbr		freenetconfigent(nconf);
57474462Salfred
57574462Salfred	return 0;
57674462Salfred}
57774462Salfred
57874462Salfredchar *
57974462Salfredtaddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
58074462Salfred{
58174462Salfred	struct __rpc_sockinfo si;
58274462Salfred
58374462Salfred	if (!__rpc_nconf2sockinfo(nconf, &si))
58474462Salfred		return NULL;
58574462Salfred	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
58674462Salfred}
58774462Salfred
58874462Salfredstruct netbuf *
58974462Salfreduaddr2taddr(const struct netconfig *nconf, const char *uaddr)
59074462Salfred{
59174462Salfred	struct __rpc_sockinfo si;
59274462Salfred
59374462Salfred	if (!__rpc_nconf2sockinfo(nconf, &si))
59474462Salfred		return NULL;
59574462Salfred	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
59674462Salfred}
59774462Salfred
59874462Salfredchar *
59974462Salfred__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
60074462Salfred{
60174462Salfred	char *ret;
60274462Salfred	struct sockaddr_in *sin;
60374462Salfred	struct sockaddr_un *sun;
60474462Salfred	char namebuf[INET_ADDRSTRLEN];
60574462Salfred#ifdef INET6
60674462Salfred	struct sockaddr_in6 *sin6;
60774462Salfred	char namebuf6[INET6_ADDRSTRLEN];
60874462Salfred#endif
60974462Salfred	u_int16_t port;
61074462Salfred
61174462Salfred	switch (af) {
61274462Salfred	case AF_INET:
613319615Sdelphij		if (nbuf->len < sizeof(*sin))
614319615Sdelphij			return NULL;
61574462Salfred		sin = nbuf->buf;
61674462Salfred		if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
61774462Salfred		    == NULL)
61874462Salfred			return NULL;
61974462Salfred		port = ntohs(sin->sin_port);
62074462Salfred		if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
62174462Salfred		    port & 0xff) < 0)
62274462Salfred			return NULL;
62374462Salfred		break;
62474462Salfred#ifdef INET6
62574462Salfred	case AF_INET6:
626319615Sdelphij		if (nbuf->len < sizeof(*sin6))
627319615Sdelphij			return NULL;
62874462Salfred		sin6 = nbuf->buf;
62974462Salfred		if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
63074462Salfred		    == NULL)
63174462Salfred			return NULL;
63274462Salfred		port = ntohs(sin6->sin6_port);
63374462Salfred		if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
63474462Salfred		    port & 0xff) < 0)
63574462Salfred			return NULL;
63674462Salfred		break;
63774462Salfred#endif
63874462Salfred	case AF_LOCAL:
63974462Salfred		sun = nbuf->buf;
64076523Siedowse		if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
64176523Siedowse		    offsetof(struct sockaddr_un, sun_path)),
64276523Siedowse		    sun->sun_path) < 0)
64376523Siedowse			return (NULL);
64474462Salfred		break;
64574462Salfred	default:
64674462Salfred		return NULL;
64774462Salfred	}
64874462Salfred
64974462Salfred	return ret;
65074462Salfred}
65174462Salfred
65274462Salfredstruct netbuf *
65374462Salfred__rpc_uaddr2taddr_af(int af, const char *uaddr)
65474462Salfred{
65574462Salfred	struct netbuf *ret = NULL;
65674462Salfred	char *addrstr, *p;
65774462Salfred	unsigned port, portlo, porthi;
65874462Salfred	struct sockaddr_in *sin;
65974462Salfred#ifdef INET6
66074462Salfred	struct sockaddr_in6 *sin6;
66174462Salfred#endif
66274462Salfred	struct sockaddr_un *sun;
66374462Salfred
66490271Salfred	port = 0;
66590271Salfred	sin = NULL;
666319615Sdelphij
667319615Sdelphij	if (uaddr == NULL)
668319615Sdelphij		return NULL;
669319615Sdelphij
67074462Salfred	addrstr = strdup(uaddr);
67174462Salfred	if (addrstr == NULL)
67274462Salfred		return NULL;
67374462Salfred
67474462Salfred	/*
67574462Salfred	 * AF_LOCAL addresses are expected to be absolute
67674462Salfred	 * pathnames, anything else will be AF_INET or AF_INET6.
67774462Salfred	 */
67874462Salfred	if (*addrstr != '/') {
67974462Salfred		p = strrchr(addrstr, '.');
68074462Salfred		if (p == NULL)
68174462Salfred			goto out;
68274462Salfred		portlo = (unsigned)atoi(p + 1);
68374462Salfred		*p = '\0';
68474462Salfred
68574462Salfred		p = strrchr(addrstr, '.');
68674462Salfred		if (p == NULL)
68774462Salfred			goto out;
68874462Salfred		porthi = (unsigned)atoi(p + 1);
68974462Salfred		*p = '\0';
69074462Salfred		port = (porthi << 8) | portlo;
69174462Salfred	}
69274462Salfred
69374462Salfred	ret = (struct netbuf *)malloc(sizeof *ret);
694109951Smbr	if (ret == NULL)
695109951Smbr		goto out;
69674462Salfred
69774462Salfred	switch (af) {
69874462Salfred	case AF_INET:
69974462Salfred		sin = (struct sockaddr_in *)malloc(sizeof *sin);
70074462Salfred		if (sin == NULL)
70174462Salfred			goto out;
70274462Salfred		memset(sin, 0, sizeof *sin);
70374462Salfred		sin->sin_family = AF_INET;
70474462Salfred		sin->sin_port = htons(port);
70574462Salfred		if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
70674462Salfred			free(sin);
70774462Salfred			free(ret);
70874462Salfred			ret = NULL;
70974462Salfred			goto out;
71074462Salfred		}
71174462Salfred		sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
71274462Salfred		ret->buf = sin;
71374462Salfred		break;
71474462Salfred#ifdef INET6
71574462Salfred	case AF_INET6:
71674462Salfred		sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
71774462Salfred		if (sin6 == NULL)
71874462Salfred			goto out;
71974462Salfred		memset(sin6, 0, sizeof *sin6);
72074462Salfred		sin6->sin6_family = AF_INET6;
72174462Salfred		sin6->sin6_port = htons(port);
72274462Salfred		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
723109951Smbr			free(sin6);
72474462Salfred			free(ret);
72574462Salfred			ret = NULL;
72674462Salfred			goto out;
72774462Salfred		}
72874462Salfred		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
72974462Salfred		ret->buf = sin6;
73074462Salfred		break;
73174462Salfred#endif
73274462Salfred	case AF_LOCAL:
73374462Salfred		sun = (struct sockaddr_un *)malloc(sizeof *sun);
73474462Salfred		if (sun == NULL)
73574462Salfred			goto out;
73674462Salfred		memset(sun, 0, sizeof *sun);
73774462Salfred		sun->sun_family = AF_LOCAL;
73874462Salfred		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
73976044Siedowse		ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
74076044Siedowse		ret->buf = sun;
74174462Salfred		break;
74274462Salfred	default:
74374462Salfred		break;
74474462Salfred	}
74574462Salfredout:
74674462Salfred	free(addrstr);
74774462Salfred	return ret;
74874462Salfred}
74974462Salfred
75074462Salfredint
75174462Salfred__rpc_seman2socktype(int semantics)
75274462Salfred{
75374462Salfred	switch (semantics) {
75474462Salfred	case NC_TPI_CLTS:
75574462Salfred		return SOCK_DGRAM;
75674462Salfred	case NC_TPI_COTS_ORD:
75774462Salfred		return SOCK_STREAM;
75874462Salfred	case NC_TPI_RAW:
75974462Salfred		return SOCK_RAW;
76074462Salfred	default:
76174462Salfred		break;
76274462Salfred	}
76374462Salfred
76474462Salfred	return -1;
76574462Salfred}
76674462Salfred
76774462Salfredint
76874462Salfred__rpc_socktype2seman(int socktype)
76974462Salfred{
77074462Salfred	switch (socktype) {
77174462Salfred	case SOCK_DGRAM:
77274462Salfred		return NC_TPI_CLTS;
77374462Salfred	case SOCK_STREAM:
77474462Salfred		return NC_TPI_COTS_ORD;
77574462Salfred	case SOCK_RAW:
77674462Salfred		return NC_TPI_RAW;
77774462Salfred	default:
77874462Salfred		break;
77974462Salfred	}
78074462Salfred
78174462Salfred	return -1;
78274462Salfred}
78374462Salfred
78474462Salfred/*
78574462Salfred * XXXX - IPv6 scope IDs can't be handled in universal addresses.
78674462Salfred * Here, we compare the original server address to that of the RPC
78774462Salfred * service we just received back from a call to rpcbind on the remote
78874462Salfred * machine. If they are both "link local" or "site local", copy
78974462Salfred * the scope id of the server address over to the service address.
79074462Salfred */
79174462Salfredint
79274462Salfred__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
79374462Salfred{
79474462Salfred#ifdef INET6
79574462Salfred	struct sockaddr *sa_new, *sa_svc;
79674462Salfred	struct sockaddr_in6 *sin6_new, *sin6_svc;
79774462Salfred
79874462Salfred	sa_svc = (struct sockaddr *)svc->buf;
79974462Salfred	sa_new = (struct sockaddr *)new->buf;
80074462Salfred
80174462Salfred	if (sa_new->sa_family == sa_svc->sa_family &&
80274462Salfred	    sa_new->sa_family == AF_INET6) {
80374462Salfred		sin6_new = (struct sockaddr_in6 *)new->buf;
80474462Salfred		sin6_svc = (struct sockaddr_in6 *)svc->buf;
80574462Salfred
80674462Salfred		if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
80774462Salfred		     IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
80874462Salfred		    (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
80974462Salfred		     IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
81074462Salfred			sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
81174462Salfred		}
81274462Salfred	}
81374462Salfred#endif
81474462Salfred	return 1;
81574462Salfred}
81674462Salfred
81774462Salfredint
81874462Salfred__rpc_sockisbound(int fd)
81974462Salfred{
82074462Salfred	struct sockaddr_storage ss;
82174462Salfred	socklen_t slen;
82274462Salfred
82374462Salfred	slen = sizeof (struct sockaddr_storage);
82474462Salfred	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
82574462Salfred		return 0;
82674462Salfred
82774462Salfred	switch (ss.ss_family) {
82874462Salfred		case AF_INET:
82974462Salfred			return (((struct sockaddr_in *)
83074462Salfred			    (void *)&ss)->sin_port != 0);
83174462Salfred#ifdef INET6
83274462Salfred		case AF_INET6:
83374462Salfred			return (((struct sockaddr_in6 *)
83474462Salfred			    (void *)&ss)->sin6_port != 0);
83574462Salfred#endif
83674462Salfred		case AF_LOCAL:
83774462Salfred			/* XXX check this */
83874462Salfred			return (((struct sockaddr_un *)
83974462Salfred			    (void *)&ss)->sun_path[0] != '\0');
84074462Salfred		default:
84174462Salfred			break;
84274462Salfred	}
84374462Salfred
84474462Salfred	return 0;
84574462Salfred}
846