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