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