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