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