xref: /illumos-gate/usr/src/lib/libnsl/rpc/rpc_generic.c (revision 43a291055ab3951f6372241323fd4e2486098fff)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 /*
30  * Portions of this source code were derived from Berkeley
31  * 4.3 BSD under license from the Regents of the University of
32  * California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 /*
38  * rpc_generic.c, Miscl routines for RPC.
39  *
40  */
41 
42 #include "mt.h"
43 #include "rpc_mt.h"
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <rpc/rpc.h>
47 #include <rpc/nettype.h>
48 #include <sys/param.h>
49 #include <sys/mkdev.h>
50 #include <sys/stat.h>
51 #include <ctype.h>
52 #include <errno.h>
53 #include <sys/resource.h>
54 #include <netconfig.h>
55 #include <malloc.h>
56 #include <syslog.h>
57 #include <string.h>
58 #include <sys/systeminfo.h>
59 #include <netdir.h>
60 #include <netdb.h>
61 
62 #if defined(sparc)
63 #define	_STAT _stat
64 #define	_FSTAT _fstat
65 #else  /* !sparc */
66 #define	_STAT stat
67 #define	_FSTAT fstat
68 #endif /* sparc */
69 
70 struct handle {
71 	NCONF_HANDLE *nhandle;
72 	int nflag;		/* Whether NETPATH or NETCONFIG */
73 	int nettype;
74 };
75 
76 struct _rpcnettype {
77 	const char *name;
78 	const int type;
79 } _rpctypelist[] = {
80 	"netpath", _RPC_NETPATH,
81 	"visible", _RPC_VISIBLE,
82 	"circuit_v", _RPC_CIRCUIT_V,
83 	"datagram_v", _RPC_DATAGRAM_V,
84 	"circuit_n", _RPC_CIRCUIT_N,
85 	"datagram_n", _RPC_DATAGRAM_N,
86 	"tcp", _RPC_TCP,
87 	"udp", _RPC_UDP,
88 	"local", _RPC_LOCAL,
89 	"door", _RPC_DOOR,
90 	"door_local", _RPC_DOOR_LOCAL,
91 	"door_netpath", _RPC_DOOR_NETPATH,
92 	0, _RPC_NONE
93 };
94 
95 /*
96  * Cache the result of getrlimit(), so we don't have to do an
97  * expensive call every time. Since many old programs assume
98  * it will not return more than 1024 and use svc_fdset, return
99  * maximum of FD_SETSIZE.
100  */
101 int
102 __rpc_dtbsize(void)
103 {
104 	static int tbsize;
105 	struct rlimit rl;
106 
107 	if (tbsize)
108 		return (tbsize);
109 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
110 		tbsize = rl.rlim_max;
111 		/*
112 		 * backward compatibility; too many places
113 		 * this function is called assuming it returns
114 		 * maximum of 1024.
115 		 */
116 		if (tbsize > FD_SETSIZE)
117 			tbsize = FD_SETSIZE;
118 		return (tbsize);
119 	}
120 	/*
121 	 * Something wrong.  I'll try to save face by returning a
122 	 * pessimistic number.
123 	 */
124 	return (32);
125 }
126 
127 /*
128  * Find the appropriate buffer size
129  */
130 uint_t
131 __rpc_get_t_size(
132 	t_scalar_t size,	/* Size requested */
133 	t_scalar_t bufsize)	/* Supported by the transport */
134 {
135 	if (bufsize == -2)	/* transfer of data unsupported */
136 		return ((uint_t)0);
137 	if (size == 0) {
138 		if ((bufsize == -1) || (bufsize == 0)) {
139 			/*
140 			 * bufsize == -1 : No limit on the size
141 			 * bufsize == 0 : Concept of tsdu foreign. Choose
142 			 *			a value.
143 			 */
144 			return ((uint_t)RPC_MAXDATASIZE);
145 		}
146 		return ((uint_t)bufsize);
147 	}
148 	if ((bufsize == -1) || (bufsize == 0))
149 		return ((uint_t)size);
150 	/* Check whether the value is within the upper max limit */
151 	return (size > bufsize ? (uint_t)bufsize : (uint_t)size);
152 }
153 
154 /*
155  * Find the appropriate address buffer size
156  */
157 uint_t
158 __rpc_get_a_size(
159 	t_scalar_t size)	/* normally tinfo.addr */
160 {
161 	if (size >= 0)
162 		return ((uint_t)size);
163 	if (size <= -2)
164 		return ((uint_t)0);
165 	/*
166 	 * (size == -1) No limit on the size. we impose a limit here.
167 	 */
168 	return ((uint_t)RPC_MAXADDRSIZE);
169 }
170 
171 /*
172  * Returns the type of the network as defined in <rpc/nettype.h>
173  * If nettype is NULL, it defaults to NETPATH.
174  */
175 static int
176 getnettype(const char *nettype)
177 {
178 	int i;
179 
180 	if ((nettype == NULL) || (nettype[0] == NULL))
181 		return (_RPC_NETPATH);	/* Default */
182 
183 	for (i = 0; _rpctypelist[i].name; i++)
184 		if (strcasecmp(nettype, _rpctypelist[i].name) == 0)
185 			return (_rpctypelist[i].type);
186 	return (_rpctypelist[i].type);
187 }
188 
189 /*
190  * For the given nettype (tcp or udp only), return the first structure found.
191  * This should be freed by calling freenetconfigent()
192  */
193 struct netconfig *
194 __rpc_getconfip(char *nettype)
195 {
196 	char *netid;
197 	char *netid_tcp = NULL;
198 	char *netid_udp = NULL;
199 	static char *netid_tcp_main;
200 	static char *netid_udp_main;
201 	static pthread_key_t tcp_key, udp_key;
202 	int main_thread;
203 	extern mutex_t tsd_lock;
204 
205 	if ((main_thread = thr_main())) {
206 		netid_udp = netid_udp_main;
207 		netid_tcp = netid_tcp_main;
208 	} else {
209 		if (tcp_key == 0) {
210 			(void) mutex_lock(&tsd_lock);
211 			if (tcp_key == 0)
212 				(void) pthread_key_create(&tcp_key, free);
213 			(void) mutex_unlock(&tsd_lock);
214 		}
215 		netid_tcp = pthread_getspecific(tcp_key);
216 		if (udp_key == 0) {
217 			(void) mutex_lock(&tsd_lock);
218 			if (udp_key == 0)
219 				(void) pthread_key_create(&udp_key, free);
220 			(void) mutex_unlock(&tsd_lock);
221 		}
222 		netid_udp = pthread_getspecific(udp_key);
223 	}
224 	if (!netid_udp && !netid_tcp) {
225 		struct netconfig *nconf;
226 		void *confighandle;
227 
228 		if (!(confighandle = setnetconfig()))
229 			return (NULL);
230 		while (nconf = getnetconfig(confighandle)) {
231 			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
232 				if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
233 					netid_tcp = strdup(nconf->nc_netid);
234 					if (netid_tcp == NULL) {
235 						syslog(LOG_ERR,
236 							"__rpc_getconfip : "
237 							"strdup failed");
238 						return (NULL);
239 					}
240 					if (main_thread)
241 						netid_tcp_main = netid_tcp;
242 					else
243 						(void) pthread_setspecific(
244 							tcp_key,
245 							(void *)netid_tcp);
246 				} else
247 				if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
248 					netid_udp = strdup(nconf->nc_netid);
249 					if (netid_udp == NULL) {
250 						syslog(LOG_ERR,
251 							"__rpc_getconfip : "
252 							"strdup failed");
253 						return (NULL);
254 					}
255 					if (main_thread)
256 						netid_udp_main = netid_udp;
257 					else
258 						(void) pthread_setspecific(
259 							udp_key,
260 							(void *)netid_udp);
261 				}
262 			}
263 		}
264 		(void) endnetconfig(confighandle);
265 	}
266 	if (strcmp(nettype, "udp") == 0)
267 		netid = netid_udp;
268 	else if (strcmp(nettype, "tcp") == 0)
269 		netid = netid_tcp;
270 	else
271 		return (NULL);
272 	if ((netid == NULL) || (netid[0] == NULL))
273 		return (NULL);
274 	return (getnetconfigent(netid));
275 }
276 
277 
278 /*
279  * Returns the type of the nettype, which should then be used with
280  * __rpc_getconf().
281  */
282 void *
283 __rpc_setconf(char *nettype)
284 {
285 	struct handle *handle;
286 
287 	handle = malloc(sizeof (struct handle));
288 	if (handle == NULL)
289 		return (NULL);
290 	switch (handle->nettype = getnettype(nettype)) {
291 	case _RPC_DOOR_NETPATH:
292 	case _RPC_NETPATH:
293 	case _RPC_CIRCUIT_N:
294 	case _RPC_DATAGRAM_N:
295 		if (!(handle->nhandle = setnetpath())) {
296 			free(handle);
297 			return (NULL);
298 		}
299 		handle->nflag = TRUE;
300 		break;
301 	case _RPC_VISIBLE:
302 	case _RPC_CIRCUIT_V:
303 	case _RPC_DATAGRAM_V:
304 	case _RPC_TCP:
305 	case _RPC_UDP:
306 	case _RPC_LOCAL:
307 	case _RPC_DOOR_LOCAL:
308 		if (!(handle->nhandle = setnetconfig())) {
309 			free(handle);
310 			return (NULL);
311 		}
312 		handle->nflag = FALSE;
313 		break;
314 	default:
315 		free(handle);
316 		return (NULL);
317 	}
318 
319 	return (handle);
320 }
321 
322 /*
323  * Returns the next netconfig struct for the given "net" type.
324  * __rpc_setconf() should have been called previously.
325  */
326 struct netconfig *
327 __rpc_getconf(void *vhandle)
328 {
329 	struct handle *handle;
330 	struct netconfig *nconf;
331 
332 	handle = (struct handle *)vhandle;
333 	if (handle == NULL)
334 		return (NULL);
335 	for (;;) {
336 		if (handle->nflag)
337 			nconf = getnetpath(handle->nhandle);
338 		else
339 			nconf = getnetconfig(handle->nhandle);
340 		if (nconf == NULL)
341 			break;
342 		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
343 		    (nconf->nc_semantics != NC_TPI_COTS) &&
344 		    (nconf->nc_semantics != NC_TPI_COTS_ORD))
345 			continue;
346 		switch (handle->nettype) {
347 		case _RPC_VISIBLE:
348 			if (!(nconf->nc_flag & NC_VISIBLE))
349 				continue;
350 			/*FALLTHROUGH*/
351 		case _RPC_DOOR_NETPATH:
352 			/*FALLTHROUGH*/
353 		case _RPC_NETPATH:	/* Be happy */
354 			break;
355 		case _RPC_CIRCUIT_V:
356 			if (!(nconf->nc_flag & NC_VISIBLE))
357 				continue;
358 			/*FALLTHROUGH*/
359 		case _RPC_CIRCUIT_N:
360 			if ((nconf->nc_semantics != NC_TPI_COTS) &&
361 			    (nconf->nc_semantics != NC_TPI_COTS_ORD))
362 				continue;
363 			break;
364 		case _RPC_DATAGRAM_V:
365 			if (!(nconf->nc_flag & NC_VISIBLE))
366 				continue;
367 			/*FALLTHROUGH*/
368 		case _RPC_DATAGRAM_N:
369 			if (nconf->nc_semantics != NC_TPI_CLTS)
370 				continue;
371 			break;
372 		case _RPC_TCP:
373 			if (((nconf->nc_semantics != NC_TPI_COTS) &&
374 			    (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
375 			    (strcmp(nconf->nc_protofmly, NC_INET) &&
376 			    strcmp(nconf->nc_protofmly, NC_INET6)) ||
377 			    strcmp(nconf->nc_proto, NC_TCP))
378 				continue;
379 			break;
380 		case _RPC_UDP:
381 			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
382 			    (strcmp(nconf->nc_protofmly, NC_INET) &&
383 			    strcmp(nconf->nc_protofmly, NC_INET6)) ||
384 			    strcmp(nconf->nc_proto, NC_UDP))
385 				continue;
386 			break;
387 		case _RPC_LOCAL:
388 		case _RPC_DOOR_LOCAL:
389 			if (!(nconf->nc_flag & NC_VISIBLE))
390 				continue;
391 			if (strcmp(nconf->nc_protofmly, NC_LOOPBACK))
392 				continue;
393 			break;
394 		}
395 		break;
396 	}
397 	return (nconf);
398 }
399 
400 void
401 __rpc_endconf(void *vhandle)
402 {
403 	struct handle *handle;
404 
405 	handle = (struct handle *)vhandle;
406 	if (handle == NULL)
407 		return;
408 	if (handle->nflag) {
409 		(void) endnetpath(handle->nhandle);
410 	} else {
411 		(void) endnetconfig(handle->nhandle);
412 	}
413 	free(handle);
414 }
415 
416 /*
417  * Used to ping the NULL procedure for clnt handle.
418  * Returns NULL if fails, else a non-NULL pointer.
419  */
420 void *
421 rpc_nullproc(CLIENT *clnt)
422 {
423 	struct timeval TIMEOUT = {25, 0};
424 
425 	if (clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, NULL,
426 			(xdrproc_t)xdr_void, NULL, TIMEOUT) != RPC_SUCCESS)
427 		return (NULL);
428 	return ((void *)clnt);
429 }
430 
431 /*
432  * Given a fd, find the transport device it is using and return the
433  * netconf entry corresponding to it.
434  * Note: It assumes servtpe parameter is 0 when uninitialized.
435  *	That is true for xprt->xp_type field.
436  */
437 struct netconfig *
438 __rpcfd_to_nconf(int fd, int servtype)
439 {
440 	struct stat statbuf;
441 	void *hndl;
442 	struct netconfig *nconf, *newnconf = NULL;
443 	major_t fdmajor;
444 	struct t_info tinfo;
445 
446 	if (_FSTAT(fd, &statbuf) == -1)
447 		return (NULL);
448 
449 	fdmajor = major(statbuf.st_rdev);
450 	if (servtype == 0) {
451 		if (t_getinfo(fd, &tinfo) == -1) {
452 			char errorstr[100];
453 
454 			__tli_sys_strerror(errorstr, sizeof (errorstr),
455 					t_errno, errno);
456 			(void) syslog(LOG_ERR, "__rpcfd_to_nconf : %s : %s",
457 					"could not get transport information",
458 					errorstr);
459 			return (NULL);
460 		}
461 		servtype = tinfo.servtype;
462 	}
463 
464 	hndl = setnetconfig();
465 	if (hndl == NULL)
466 		return (NULL);
467 	/*
468 	 * Go through all transports listed in /etc/netconfig looking for
469 	 *	transport device in use on fd.
470 	 * - Match on service type first
471 	 * - if that succeeds, match on major numbers (used for new local
472 	 *	transport code that is self cloning)
473 	 * - if that fails, assume transport device uses clone driver
474 	 *	and try match the fdmajor with minor number of device path
475 	 *	which will be the major number of transport device since it
476 	 *	uses the clone driver.
477 	 */
478 
479 	while (nconf = getnetconfig(hndl)) {
480 		if (__rpc_matchserv(servtype, nconf->nc_semantics) == TRUE) {
481 			if (!_STAT(nconf->nc_device, &statbuf)) {
482 				if (fdmajor == major(statbuf.st_rdev))
483 					break; /* self cloning driver ? */
484 				if (fdmajor == minor(statbuf.st_rdev))
485 					break; /* clone driver! */
486 			}
487 		}
488 	}
489 	if (nconf)
490 		newnconf = getnetconfigent(nconf->nc_netid);
491 	(void) endnetconfig(hndl);
492 	return (newnconf);
493 }
494 
495 int
496 __rpc_matchserv(int servtype, unsigned int nc_semantics)
497 {
498 	switch (servtype) {
499 	case T_COTS:
500 		if (nc_semantics == NC_TPI_COTS)
501 			return (TRUE);
502 		break;
503 
504 	case T_COTS_ORD:
505 		if (nc_semantics == NC_TPI_COTS_ORD)
506 			return (TRUE);
507 		break;
508 
509 	case T_CLTS:
510 		if (nc_semantics == NC_TPI_CLTS)
511 			return (TRUE);
512 		break;
513 
514 	default:
515 		/* FALSE! */
516 		break;
517 
518 	}
519 	return (FALSE);
520 }
521 
522 /*
523  * Routines for RPC/Doors support.
524  */
525 
526 extern bool_t __inet_netdir_is_my_host(const char *);
527 
528 bool_t
529 __rpc_is_local_host(const char *host)
530 {
531 	char	buf[MAXHOSTNAMELEN + 1];
532 
533 	if (host == NULL || strcmp(host, "localhost") == 0 ||
534 			strcmp(host, HOST_SELF) == 0 ||
535 			strcmp(host, HOST_SELF_CONNECT) == 0 ||
536 			strlen(host) == 0)
537 		return (TRUE);
538 	if (sysinfo(SI_HOSTNAME, buf, sizeof (buf)) < 0)
539 		return (FALSE);
540 	if (strcmp(host, buf) == 0)
541 		return (TRUE);
542 	return (__inet_netdir_is_my_host(host));
543 }
544 
545 bool_t
546 __rpc_try_doors(const char *nettype, bool_t *try_others)
547 {
548 	switch (getnettype(nettype)) {
549 	case _RPC_DOOR:
550 		*try_others = FALSE;
551 		return (TRUE);
552 	case _RPC_DOOR_LOCAL:
553 	case _RPC_DOOR_NETPATH:
554 		*try_others = TRUE;
555 		return (TRUE);
556 	default:
557 		*try_others = TRUE;
558 		return (FALSE);
559 	}
560 }
561