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 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 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 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 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 * 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 * 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 * 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 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 * 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 * 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 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 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 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