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