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