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