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