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