rpc_generic.c revision 177685
1/*	$NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $	*/
2
3/*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part.  Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California  94043
30 */
31/*
32 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
33 */
34
35/* #pragma ident	"@(#)rpc_generic.c	1.17	94/04/24 SMI" */
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: head/sys/rpc/rpc_generic.c 177685 2008-03-28 09:50:32Z dfr $");
38
39/*
40 * rpc_generic.c, Miscl routines for RPC.
41 *
42 */
43
44#include "opt_inet6.h"
45
46#include <sys/param.h>
47#include <sys/kernel.h>
48#include <sys/malloc.h>
49#include <sys/module.h>
50#include <sys/proc.h>
51#include <sys/protosw.h>
52#include <sys/sbuf.h>
53#include <sys/systm.h>
54#include <sys/socket.h>
55#include <sys/socketvar.h>
56#include <sys/syslog.h>
57
58#include <rpc/rpc.h>
59#include <rpc/nettype.h>
60
61#include <rpc/rpc_com.h>
62
63#if __FreeBSD_version < 700000
64#define strrchr rindex
65#endif
66
67struct handle {
68	NCONF_HANDLE *nhandle;
69	int nflag;		/* Whether NETPATH or NETCONFIG */
70	int nettype;
71};
72
73static const struct _rpcnettype {
74	const char *name;
75	const int type;
76} _rpctypelist[] = {
77	{ "netpath", _RPC_NETPATH },
78	{ "visible", _RPC_VISIBLE },
79	{ "circuit_v", _RPC_CIRCUIT_V },
80	{ "datagram_v", _RPC_DATAGRAM_V },
81	{ "circuit_n", _RPC_CIRCUIT_N },
82	{ "datagram_n", _RPC_DATAGRAM_N },
83	{ "tcp", _RPC_TCP },
84	{ "udp", _RPC_UDP },
85	{ 0, _RPC_NONE }
86};
87
88struct netid_af {
89	const char	*netid;
90	int		af;
91	int		protocol;
92};
93
94static const struct netid_af na_cvt[] = {
95	{ "udp",  AF_INET,  IPPROTO_UDP },
96	{ "tcp",  AF_INET,  IPPROTO_TCP },
97#ifdef INET6
98	{ "udp6", AF_INET6, IPPROTO_UDP },
99	{ "tcp6", AF_INET6, IPPROTO_TCP },
100#endif
101	{ "local", AF_LOCAL, 0 }
102};
103
104struct rpc_createerr rpc_createerr;
105
106/*
107 * Find the appropriate buffer size
108 */
109u_int
110/*ARGSUSED*/
111__rpc_get_t_size(int af, int proto, int size)
112{
113	int maxsize, defsize;
114
115	maxsize = 256 * 1024;	/* XXX */
116	switch (proto) {
117	case IPPROTO_TCP:
118		defsize = 64 * 1024;	/* XXX */
119		break;
120	case IPPROTO_UDP:
121		defsize = UDPMSGSIZE;
122		break;
123	default:
124		defsize = RPC_MAXDATASIZE;
125		break;
126	}
127	if (size == 0)
128		return defsize;
129
130	/* Check whether the value is within the upper max limit */
131	return (size > maxsize ? (u_int)maxsize : (u_int)size);
132}
133
134/*
135 * Find the appropriate address buffer size
136 */
137u_int
138__rpc_get_a_size(af)
139	int af;
140{
141	switch (af) {
142	case AF_INET:
143		return sizeof (struct sockaddr_in);
144#ifdef INET6
145	case AF_INET6:
146		return sizeof (struct sockaddr_in6);
147#endif
148	case AF_LOCAL:
149		return sizeof (struct sockaddr_un);
150	default:
151		break;
152	}
153	return ((u_int)RPC_MAXADDRSIZE);
154}
155
156#if 0
157
158/*
159 * Used to ping the NULL procedure for clnt handle.
160 * Returns NULL if fails, else a non-NULL pointer.
161 */
162void *
163rpc_nullproc(clnt)
164	CLIENT *clnt;
165{
166	struct timeval TIMEOUT = {25, 0};
167
168	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
169		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
170		return (NULL);
171	}
172	return ((void *) clnt);
173}
174
175#endif
176
177int
178__rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip)
179{
180	int type, proto;
181	struct sockaddr *sa;
182	sa_family_t family;
183	struct sockopt opt;
184	int error;
185
186	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
187	if (error)
188		return 0;
189
190	sip->si_alen = sa->sa_len;
191	family = sa->sa_family;
192	free(sa, M_SONAME);
193
194	opt.sopt_dir = SOPT_GET;
195	opt.sopt_level = SOL_SOCKET;
196	opt.sopt_name = SO_TYPE;
197	opt.sopt_val = &type;
198	opt.sopt_valsize = sizeof type;
199	opt.sopt_td = NULL;
200	error = sogetopt(so, &opt);
201	if (error)
202		return 0;
203
204	/* XXX */
205	if (family != AF_LOCAL) {
206		if (type == SOCK_STREAM)
207			proto = IPPROTO_TCP;
208		else if (type == SOCK_DGRAM)
209			proto = IPPROTO_UDP;
210		else
211			return 0;
212	} else
213		proto = 0;
214
215	sip->si_af = family;
216	sip->si_proto = proto;
217	sip->si_socktype = type;
218
219	return 1;
220}
221
222/*
223 * Linear search, but the number of entries is small.
224 */
225int
226__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
227{
228	int i;
229
230	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
231		if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
232		    strcmp(nconf->nc_netid, "unix") == 0 &&
233		    strcmp(na_cvt[i].netid, "local") == 0)) {
234			sip->si_af = na_cvt[i].af;
235			sip->si_proto = na_cvt[i].protocol;
236			sip->si_socktype =
237			    __rpc_seman2socktype((int)nconf->nc_semantics);
238			if (sip->si_socktype == -1)
239				return 0;
240			sip->si_alen = __rpc_get_a_size(sip->si_af);
241			return 1;
242		}
243
244	return 0;
245}
246
247struct socket *
248__rpc_nconf2socket(const struct netconfig *nconf)
249{
250	struct __rpc_sockinfo si;
251	struct socket *so;
252	int error;
253
254	if (!__rpc_nconf2sockinfo(nconf, &si))
255		return 0;
256
257	so = NULL;
258	error =  socreate(si.si_af, &so, si.si_socktype, si.si_proto,
259	    curthread->td_ucred, curthread);
260
261	if (error)
262		return NULL;
263	else
264		return so;
265}
266
267char *
268taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
269{
270	struct __rpc_sockinfo si;
271
272	if (!__rpc_nconf2sockinfo(nconf, &si))
273		return NULL;
274	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
275}
276
277struct netbuf *
278uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
279{
280	struct __rpc_sockinfo si;
281
282	if (!__rpc_nconf2sockinfo(nconf, &si))
283		return NULL;
284	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
285}
286
287char *
288__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
289{
290	char *ret;
291	struct sbuf sb;
292	struct sockaddr_in *sin;
293	struct sockaddr_un *sun;
294	char namebuf[INET_ADDRSTRLEN];
295#ifdef INET6
296	struct sockaddr_in6 *sin6;
297	char namebuf6[INET6_ADDRSTRLEN];
298#endif
299	u_int16_t port;
300
301	sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND);
302
303	switch (af) {
304	case AF_INET:
305		sin = nbuf->buf;
306		if (__rpc_inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
307		    == NULL)
308			return NULL;
309		port = ntohs(sin->sin_port);
310		if (sbuf_printf(&sb, "%s.%u.%u", namebuf,
311			((uint32_t)port) >> 8,
312			port & 0xff) < 0)
313			return NULL;
314		break;
315#ifdef INET6
316	case AF_INET6:
317		sin6 = nbuf->buf;
318		if (__rpc_inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
319		    == NULL)
320			return NULL;
321		port = ntohs(sin6->sin6_port);
322		if (sbuf_printf(&sb, "%s.%u.%u", namebuf6,
323			((uint32_t)port) >> 8,
324			port & 0xff) < 0)
325			return NULL;
326		break;
327#endif
328	case AF_LOCAL:
329		sun = nbuf->buf;
330		if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len -
331			    offsetof(struct sockaddr_un, sun_path)),
332			sun->sun_path) < 0)
333			return (NULL);
334		break;
335	default:
336		return NULL;
337	}
338
339	sbuf_finish(&sb);
340	ret = strdup(sbuf_data(&sb), M_RPC);
341	sbuf_delete(&sb);
342
343	return ret;
344}
345
346struct netbuf *
347__rpc_uaddr2taddr_af(int af, const char *uaddr)
348{
349	struct netbuf *ret = NULL;
350	char *addrstr, *p;
351	unsigned port, portlo, porthi;
352	struct sockaddr_in *sin;
353#ifdef INET6
354	struct sockaddr_in6 *sin6;
355#endif
356	struct sockaddr_un *sun;
357
358	port = 0;
359	sin = NULL;
360	addrstr = strdup(uaddr, M_RPC);
361	if (addrstr == NULL)
362		return NULL;
363
364	/*
365	 * AF_LOCAL addresses are expected to be absolute
366	 * pathnames, anything else will be AF_INET or AF_INET6.
367	 */
368	if (*addrstr != '/') {
369		p = strrchr(addrstr, '.');
370		if (p == NULL)
371			goto out;
372		portlo = (unsigned)strtol(p + 1, NULL, 10);
373		*p = '\0';
374
375		p = strrchr(addrstr, '.');
376		if (p == NULL)
377			goto out;
378		porthi = (unsigned)strtol(p + 1, NULL, 10);
379		*p = '\0';
380		port = (porthi << 8) | portlo;
381	}
382
383	ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK);
384	if (ret == NULL)
385		goto out;
386
387	switch (af) {
388	case AF_INET:
389		sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC,
390		    M_WAITOK);
391		if (sin == NULL)
392			goto out;
393		memset(sin, 0, sizeof *sin);
394		sin->sin_family = AF_INET;
395		sin->sin_port = htons(port);
396		if (__rpc_inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
397			free(sin, M_RPC);
398			free(ret, M_RPC);
399			ret = NULL;
400			goto out;
401		}
402		sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
403		ret->buf = sin;
404		break;
405#ifdef INET6
406	case AF_INET6:
407		sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC,
408		    M_WAITOK);
409		if (sin6 == NULL)
410			goto out;
411		memset(sin6, 0, sizeof *sin6);
412		sin6->sin6_family = AF_INET6;
413		sin6->sin6_port = htons(port);
414		if (__rpc_inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
415			free(sin6, M_RPC);
416			free(ret, M_RPC);
417			ret = NULL;
418			goto out;
419		}
420		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
421		ret->buf = sin6;
422		break;
423#endif
424	case AF_LOCAL:
425		sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC,
426		    M_WAITOK);
427		if (sun == NULL)
428			goto out;
429		memset(sun, 0, sizeof *sun);
430		sun->sun_family = AF_LOCAL;
431		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
432		ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
433		ret->buf = sun;
434		break;
435	default:
436		break;
437	}
438out:
439	free(addrstr, M_RPC);
440	return ret;
441}
442
443int
444__rpc_seman2socktype(int semantics)
445{
446	switch (semantics) {
447	case NC_TPI_CLTS:
448		return SOCK_DGRAM;
449	case NC_TPI_COTS_ORD:
450		return SOCK_STREAM;
451	case NC_TPI_RAW:
452		return SOCK_RAW;
453	default:
454		break;
455	}
456
457	return -1;
458}
459
460int
461__rpc_socktype2seman(int socktype)
462{
463	switch (socktype) {
464	case SOCK_DGRAM:
465		return NC_TPI_CLTS;
466	case SOCK_STREAM:
467		return NC_TPI_COTS_ORD;
468	case SOCK_RAW:
469		return NC_TPI_RAW;
470	default:
471		break;
472	}
473
474	return -1;
475}
476
477/*
478 * Returns the type of the network as defined in <rpc/nettype.h>
479 * If nettype is NULL, it defaults to NETPATH.
480 */
481static int
482getnettype(const char *nettype)
483{
484	int i;
485
486	if ((nettype == NULL) || (nettype[0] == 0)) {
487		return (_RPC_NETPATH);	/* Default */
488	}
489
490#if 0
491	nettype = strlocase(nettype);
492#endif
493	for (i = 0; _rpctypelist[i].name; i++)
494		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
495			return (_rpctypelist[i].type);
496		}
497	return (_rpctypelist[i].type);
498}
499
500/*
501 * For the given nettype (tcp or udp only), return the first structure found.
502 * This should be freed by calling freenetconfigent()
503 */
504struct netconfig *
505__rpc_getconfip(const char *nettype)
506{
507	char *netid;
508	static char *netid_tcp = (char *) NULL;
509	static char *netid_udp = (char *) NULL;
510	struct netconfig *dummy;
511
512	if (!netid_udp && !netid_tcp) {
513		struct netconfig *nconf;
514		void *confighandle;
515
516		if (!(confighandle = setnetconfig())) {
517			log(LOG_ERR, "rpc: failed to open " NETCONFIG);
518			return (NULL);
519		}
520		while ((nconf = getnetconfig(confighandle)) != NULL) {
521			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
522				if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
523					netid_tcp = strdup(nconf->nc_netid,
524					    M_RPC);
525				} else
526				if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
527					netid_udp = strdup(nconf->nc_netid,
528					    M_RPC);
529				}
530			}
531		}
532		endnetconfig(confighandle);
533	}
534	if (strcmp(nettype, "udp") == 0)
535		netid = netid_udp;
536	else if (strcmp(nettype, "tcp") == 0)
537		netid = netid_tcp;
538	else {
539		return (NULL);
540	}
541	if ((netid == NULL) || (netid[0] == 0)) {
542		return (NULL);
543	}
544	dummy = getnetconfigent(netid);
545	return (dummy);
546}
547
548/*
549 * Returns the type of the nettype, which should then be used with
550 * __rpc_getconf().
551 *
552 * For simplicity in the kernel, we don't support the NETPATH
553 * environment variable. We behave as userland would then NETPATH is
554 * unset, i.e. iterate over all visible entries in netconfig.
555 */
556void *
557__rpc_setconf(nettype)
558	const char *nettype;
559{
560	struct handle *handle;
561
562	handle = (struct handle *) malloc(sizeof (struct handle),
563	    M_RPC, M_WAITOK);
564	switch (handle->nettype = getnettype(nettype)) {
565	case _RPC_NETPATH:
566	case _RPC_CIRCUIT_N:
567	case _RPC_DATAGRAM_N:
568		if (!(handle->nhandle = setnetconfig()))
569			goto failed;
570		handle->nflag = TRUE;
571		break;
572	case _RPC_VISIBLE:
573	case _RPC_CIRCUIT_V:
574	case _RPC_DATAGRAM_V:
575	case _RPC_TCP:
576	case _RPC_UDP:
577		if (!(handle->nhandle = setnetconfig())) {
578		        log(LOG_ERR, "rpc: failed to open " NETCONFIG);
579			goto failed;
580		}
581		handle->nflag = FALSE;
582		break;
583	default:
584		goto failed;
585	}
586
587	return (handle);
588
589failed:
590	free(handle, M_RPC);
591	return (NULL);
592}
593
594/*
595 * Returns the next netconfig struct for the given "net" type.
596 * __rpc_setconf() should have been called previously.
597 */
598struct netconfig *
599__rpc_getconf(void *vhandle)
600{
601	struct handle *handle;
602	struct netconfig *nconf;
603
604	handle = (struct handle *)vhandle;
605	if (handle == NULL) {
606		return (NULL);
607	}
608	for (;;) {
609		if (handle->nflag) {
610			nconf = getnetconfig(handle->nhandle);
611			if (nconf && !(nconf->nc_flag & NC_VISIBLE))
612				continue;
613		} else {
614			nconf = getnetconfig(handle->nhandle);
615		}
616		if (nconf == NULL)
617			break;
618		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
619			(nconf->nc_semantics != NC_TPI_COTS) &&
620			(nconf->nc_semantics != NC_TPI_COTS_ORD))
621			continue;
622		switch (handle->nettype) {
623		case _RPC_VISIBLE:
624			if (!(nconf->nc_flag & NC_VISIBLE))
625				continue;
626			/* FALLTHROUGH */
627		case _RPC_NETPATH:	/* Be happy */
628			break;
629		case _RPC_CIRCUIT_V:
630			if (!(nconf->nc_flag & NC_VISIBLE))
631				continue;
632			/* FALLTHROUGH */
633		case _RPC_CIRCUIT_N:
634			if ((nconf->nc_semantics != NC_TPI_COTS) &&
635				(nconf->nc_semantics != NC_TPI_COTS_ORD))
636				continue;
637			break;
638		case _RPC_DATAGRAM_V:
639			if (!(nconf->nc_flag & NC_VISIBLE))
640				continue;
641			/* FALLTHROUGH */
642		case _RPC_DATAGRAM_N:
643			if (nconf->nc_semantics != NC_TPI_CLTS)
644				continue;
645			break;
646		case _RPC_TCP:
647			if (((nconf->nc_semantics != NC_TPI_COTS) &&
648				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
649				(strcmp(nconf->nc_protofmly, NC_INET)
650#ifdef INET6
651				 && strcmp(nconf->nc_protofmly, NC_INET6))
652#else
653				)
654#endif
655				||
656				strcmp(nconf->nc_proto, NC_TCP))
657				continue;
658			break;
659		case _RPC_UDP:
660			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
661				(strcmp(nconf->nc_protofmly, NC_INET)
662#ifdef INET6
663				&& strcmp(nconf->nc_protofmly, NC_INET6))
664#else
665				)
666#endif
667				||
668				strcmp(nconf->nc_proto, NC_UDP))
669				continue;
670			break;
671		}
672		break;
673	}
674	return (nconf);
675}
676
677void
678__rpc_endconf(vhandle)
679	void * vhandle;
680{
681	struct handle *handle;
682
683	handle = (struct handle *) vhandle;
684	if (handle == NULL) {
685		return;
686	}
687	endnetconfig(handle->nhandle);
688	free(handle, M_RPC);
689}
690
691int
692__rpc_sockisbound(struct socket *so)
693{
694	struct sockaddr *sa;
695	int error, bound;
696
697	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
698	if (error)
699		return (0);
700
701	switch (sa->sa_family) {
702		case AF_INET:
703			bound = (((struct sockaddr_in *) sa)->sin_port != 0);
704			break;
705#ifdef INET6
706		case AF_INET6:
707			bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0);
708			break;
709#endif
710		case AF_LOCAL:
711			/* XXX check this */
712			bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0');
713			break;
714		default:
715			bound = FALSE;
716			break;
717	}
718
719	free(sa, M_SONAME);
720
721	return bound;
722}
723
724/*
725 * Kernel module glue
726 */
727static int
728krpc_modevent(module_t mod, int type, void *data)
729{
730
731	return (0);
732}
733static moduledata_t krpc_mod = {
734	"krpc",
735	krpc_modevent,
736	NULL,
737};
738DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY);
739
740/* So that loader and kldload(2) can find us, wherever we are.. */
741MODULE_VERSION(krpc, 1);
742