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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 /* SVr4.0 1.1 */ 33 34 /* 35 * Miscellaneous support routines for kernel implementation of RPC. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/t_lock.h> 40 #include <sys/user.h> 41 #include <sys/vnode.h> 42 #include <sys/stream.h> 43 #include <sys/stropts.h> 44 #include <sys/strsubr.h> 45 #include <sys/socket.h> 46 #include <sys/tihdr.h> 47 #include <sys/timod.h> 48 #include <sys/tiuser.h> 49 #include <sys/systm.h> 50 #include <sys/cmn_err.h> 51 #include <sys/debug.h> 52 #include <netinet/in.h> 53 #include <rpc/types.h> 54 #include <rpc/auth.h> 55 #include <rpc/clnt.h> 56 #include <rpc/rpcb_prot.h> 57 #include <rpc/pmap_prot.h> 58 59 static int strtoi(char *, char **); 60 static void grow_netbuf(struct netbuf *, size_t); 61 static void loopb_u2t(const char *, struct netbuf *); 62 63 #define RPC_PMAP_TIMEOUT 15 64 /* 65 * define for max length of an ip address and port address, the value was 66 * calculated using INET6_ADDRSTRLEN (46) + max port address (12) + 67 * seperator "."'s in port address (2) + null (1) = 61. 68 * Then there is IPV6_TOKEN_LEN which is 64, so the value is 64 to be safe. 69 */ 70 #define RPC_MAX_IP_LENGTH 64 71 72 /* 73 * Kernel level debugging aid. The global variable "rpclog" is a bit 74 * mask which allows various types of debugging messages to be printed 75 * out. 76 * 77 * rpclog & 1 will cause actual failures to be printed. 78 * rpclog & 2 will cause informational messages to be 79 * printed on the client side of rpc. 80 * rpclog & 4 will cause informational messages to be 81 * printed on the server side of rpc. 82 * rpclog & 8 will cause informational messages for rare events to be 83 * printed on the client side of rpc. 84 * rpclog & 16 will cause informational messages for rare events to be 85 * printed on the server side of rpc. 86 * rpclog & 32 will cause informational messages for rare events to be 87 * printed on the common client/server code paths of rpc. 88 * rpclog & 64 will cause informational messages for manipulation 89 * client-side COTS dispatch list to be printed. 90 */ 91 92 uint_t rpclog = 0; 93 94 95 void 96 rpc_poptimod(vnode_t *vp) 97 { 98 int error, isfound, ret; 99 100 error = strioctl(vp, I_FIND, (intptr_t)"timod", 0, K_TO_K, kcred, 101 &isfound); 102 if (error) { 103 RPCLOG(1, "rpc_poptimod: I_FIND strioctl error %d\n", error); 104 return; 105 } 106 if (isfound) { 107 /* 108 * Pop timod module 109 */ 110 error = strioctl(vp, I_POP, 0, 0, K_TO_K, kcred, &ret); 111 if (error) { 112 RPCLOG(1, "rpc_poptimod: I_POP strioctl error %d\n", 113 error); 114 return; 115 } 116 } 117 } 118 119 /* 120 * Check the passed in ip address for correctness (limited) and return its 121 * type. 122 * 123 * an ipv4 looks like this: 124 * "IP.IP.IP.IP.PORT[top byte].PORT[bottom byte]" 125 * 126 * an ipv6 looks like this: 127 * fec0:A02::2:202:4FCD 128 * or 129 * ::10.9.2.1 130 */ 131 int 132 rpc_iptype( 133 char *ipaddr, 134 int *typeval) 135 { 136 char *cp; 137 int chcnt = 0; 138 int coloncnt = 0; 139 int dotcnt = 0; 140 int numcnt = 0; 141 int hexnumcnt = 0; 142 int othercnt = 0; 143 144 cp = ipaddr; 145 146 /* search for the different type of characters in the ip address */ 147 while ((*cp != '\0') && (chcnt < RPC_MAX_IP_LENGTH)) { 148 switch (*cp) { 149 case ':': 150 coloncnt++; 151 break; 152 case '.': 153 dotcnt++; 154 break; 155 case '0': 156 case '1': 157 case '2': 158 case '3': 159 case '4': 160 case '5': 161 case '6': 162 case '7': 163 case '8': 164 case '9': 165 numcnt++; 166 break; 167 case 'a': 168 case 'A': 169 case 'b': 170 case 'B': 171 case 'c': 172 case 'C': 173 case 'd': 174 case 'D': 175 case 'e': 176 case 'E': 177 case 'f': 178 case 'F': 179 hexnumcnt++; 180 break; 181 default: 182 othercnt++; 183 break; 184 } 185 chcnt++; 186 cp++; 187 } 188 189 /* check for bad ip strings */ 190 if ((chcnt == RPC_MAX_IP_LENGTH) || (othercnt)) 191 return (-1); 192 193 /* if we have a coloncnt, it can only be an ipv6 address */ 194 if (coloncnt) { 195 if ((coloncnt < 2) || (coloncnt > 7)) 196 return (-1); 197 198 *typeval = AF_INET6; 199 } else { 200 /* since there are no colons, make sure it is ipv4 */ 201 if ((hexnumcnt) || (dotcnt != 5)) 202 return (-1); 203 204 *typeval = AF_INET; 205 } 206 return (0); 207 } 208 209 /* 210 * Return a port number from a sockaddr_in expressed in universal address 211 * format. Note that this routine does not work for address families other 212 * than INET. Eventually, we should replace this routine with one that 213 * contacts the rpcbind running locally. 214 */ 215 int 216 rpc_uaddr2port(int af, char *addr) 217 { 218 int p1; 219 int p2; 220 char *next, *p; 221 222 if (af == AF_INET) { 223 /* 224 * A struct sockaddr_in expressed in universal address 225 * format looks like: 226 * 227 * "IP.IP.IP.IP.PORT[top byte].PORT[bottom byte]" 228 * 229 * Where each component expresses as a character, 230 * the corresponding part of the IP address 231 * and port number. 232 * Thus 127.0.0.1, port 2345 looks like: 233 * 234 * 49 50 55 46 48 46 48 46 49 46 57 46 52 49 235 * 1 2 7 . 0 . 0 . 1 . 9 . 4 1 236 * 237 * 2345 = 929base16 = 9.32+9 = 9.41 238 */ 239 (void) strtoi(addr, &next); 240 (void) strtoi(next, &next); 241 (void) strtoi(next, &next); 242 (void) strtoi(next, &next); 243 p1 = strtoi(next, &next); 244 p2 = strtoi(next, &next); 245 246 } else if (af == AF_INET6) { 247 /* 248 * An IPv6 address is expressed in following two formats 249 * fec0:A02::2:202:4FCD or 250 * ::10.9.2.1 251 * An universal address will have porthi.portlo appended to 252 * v6 address. So always look for the last two dots when 253 * extracting port number. 254 */ 255 next = addr; 256 while (next = strchr(next, '.')) { 257 p = ++next; 258 next = strchr(next, '.'); 259 next++; 260 } 261 p1 = strtoi(p, &p); 262 p2 = strtoi(p, &p); 263 RPCLOG(1, "rpc_uaddr2port: IPv6 port %d\n", ((p1 << 8) + p2)); 264 } 265 266 return ((p1 << 8) + p2); 267 } 268 269 /* 270 * Modified strtol(3). Should we be using mi_strtol() instead? 271 */ 272 static int 273 strtoi(char *str, char **ptr) 274 { 275 int c; 276 int val; 277 278 for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) { 279 val *= 10; 280 val += c - '0'; 281 } 282 *ptr = str; 283 return (val); 284 } 285 286 /* 287 * Utilities for manipulating netbuf's. 288 * 289 * Note that loopback addresses are not null-terminated, so these utilities 290 * typically use the strn* string routines. 291 */ 292 293 /* 294 * Utilities to patch a port number (for NC_INET protocols) or a 295 * port name (for NC_LOOPBACK) into a network address. 296 */ 297 298 299 /* 300 * PSARC 2003/523 Contract Private Interface 301 * put_inet_port 302 * Changes must be reviewed by Solaris File Sharing 303 * Changes must be communicated to contract-2003-523@sun.com 304 */ 305 void 306 put_inet_port(struct netbuf *addr, ushort_t port) 307 { 308 /* 309 * Easy - we always patch an unsigned short on top of an 310 * unsigned short. No changes to addr's len or maxlen are 311 * necessary. 312 */ 313 ((struct sockaddr_in *)(addr->buf))->sin_port = port; 314 } 315 316 void 317 put_inet6_port(struct netbuf *addr, ushort_t port) 318 { 319 ((struct sockaddr_in6 *)(addr->buf))->sin6_port = port; 320 } 321 322 void 323 put_loopback_port(struct netbuf *addr, char *port) 324 { 325 char *dot; 326 char *newbuf; 327 int newlen; 328 329 330 /* 331 * We must make sure the addr has enough space for us, 332 * patch in `port', and then adjust addr's len and maxlen 333 * to reflect the change. 334 */ 335 if ((dot = strnrchr(addr->buf, '.', addr->len)) == (char *)NULL) 336 return; 337 338 newlen = (int)((dot - addr->buf + 1) + strlen(port)); 339 if (newlen > addr->maxlen) { 340 newbuf = kmem_zalloc(newlen, KM_SLEEP); 341 bcopy(addr->buf, newbuf, addr->len); 342 kmem_free(addr->buf, addr->maxlen); 343 addr->buf = newbuf; 344 addr->len = addr->maxlen = newlen; 345 dot = strnrchr(addr->buf, '.', addr->len); 346 } else { 347 addr->len = newlen; 348 } 349 350 (void) strncpy(++dot, port, strlen(port)); 351 } 352 353 /* 354 * Convert a loopback universal address to a loopback transport address. 355 */ 356 static void 357 loopb_u2t(const char *ua, struct netbuf *addr) 358 { 359 size_t stringlen = strlen(ua) + 1; 360 const char *univp; /* ptr into universal addr */ 361 char *transp; /* ptr into transport addr */ 362 363 /* Make sure the netbuf will be big enough. */ 364 if (addr->maxlen < stringlen) { 365 grow_netbuf(addr, stringlen); 366 } 367 368 univp = ua; 369 transp = addr->buf; 370 while (*univp != NULL) { 371 if (*univp == '\\' && *(univp+1) == '\\') { 372 *transp = '\\'; 373 univp += 2; 374 } else if (*univp == '\\') { 375 /* octal character */ 376 *transp = (((*(univp+1) - '0') & 3) << 6) + 377 (((*(univp+2) - '0') & 7) << 3) + 378 ((*(univp+3) - '0') & 7); 379 univp += 4; 380 } else { 381 *transp = *univp; 382 univp++; 383 } 384 transp++; 385 } 386 387 addr->len = (unsigned int)(transp - addr->buf); 388 ASSERT(addr->len <= addr->maxlen); 389 } 390 391 /* 392 * Make sure the given netbuf has a maxlen at least as big as the given 393 * length. 394 */ 395 static void 396 grow_netbuf(struct netbuf *nb, size_t length) 397 { 398 char *newbuf; 399 400 if (nb->maxlen >= length) 401 return; 402 403 newbuf = kmem_zalloc(length, KM_SLEEP); 404 bcopy(nb->buf, newbuf, nb->len); 405 kmem_free(nb->buf, nb->maxlen); 406 nb->buf = newbuf; 407 nb->maxlen = (unsigned int)length; 408 } 409 410 /* 411 * Try to get the address for the desired service by using the rpcbind 412 * protocol. Ignores signals. If addr is a loopback address, it is 413 * expected to be initialized to "<hostname>.". 414 */ 415 416 enum clnt_stat 417 rpcbind_getaddr(struct knetconfig *config, rpcprog_t prog, rpcvers_t vers, 418 struct netbuf *addr) 419 { 420 char *ua = NULL; 421 enum clnt_stat status; 422 RPCB parms; 423 struct timeval tmo; 424 CLIENT *client = NULL; 425 k_sigset_t oldmask; 426 k_sigset_t newmask; 427 ushort_t port; 428 int iptype; 429 430 /* 431 * Call rpcbind (local or remote) to get an address we can use 432 * in an RPC client handle. 433 */ 434 tmo.tv_sec = RPC_PMAP_TIMEOUT; 435 tmo.tv_usec = 0; 436 parms.r_prog = prog; 437 parms.r_vers = vers; 438 parms.r_addr = parms.r_owner = ""; 439 440 if (strcmp(config->knc_protofmly, NC_INET) == 0) { 441 if (strcmp(config->knc_proto, NC_TCP) == 0) 442 parms.r_netid = "tcp"; 443 else 444 parms.r_netid = "udp"; 445 put_inet_port(addr, htons(PMAPPORT)); 446 } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) { 447 if (strcmp(config->knc_proto, NC_TCP) == 0) 448 parms.r_netid = "tcp6"; 449 else 450 parms.r_netid = "udp6"; 451 put_inet6_port(addr, htons(PMAPPORT)); 452 } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) { 453 ASSERT(strnrchr(addr->buf, '.', addr->len) != NULL); 454 if (config->knc_semantics == NC_TPI_COTS_ORD) 455 parms.r_netid = "ticotsord"; 456 else if (config->knc_semantics == NC_TPI_COTS) 457 parms.r_netid = "ticots"; 458 else 459 parms.r_netid = "ticlts"; 460 461 put_loopback_port(addr, "rpc"); 462 } else { 463 status = RPC_UNKNOWNPROTO; 464 goto out; 465 } 466 467 /* 468 * Mask signals for the duration of the handle creation and 469 * RPC calls. This allows relatively normal operation with a 470 * signal already posted to our thread (e.g., when we are 471 * sending an NLM_CANCEL in response to catching a signal). 472 * 473 * Any further exit paths from this routine must restore 474 * the original signal mask. 475 */ 476 sigfillset(&newmask); 477 sigreplace(&newmask, &oldmask); 478 479 if (clnt_tli_kcreate(config, addr, RPCBPROG, 480 RPCBVERS, 0, 0, CRED(), &client)) { 481 status = RPC_TLIERROR; 482 sigreplace(&oldmask, (k_sigset_t *)NULL); 483 goto out; 484 } 485 486 client->cl_nosignal = 1; 487 if ((status = CLNT_CALL(client, RPCBPROC_GETADDR, 488 xdr_rpcb, (char *)&parms, 489 xdr_wrapstring, (char *)&ua, 490 tmo)) != RPC_SUCCESS) { 491 sigreplace(&oldmask, (k_sigset_t *)NULL); 492 goto out; 493 } 494 495 sigreplace(&oldmask, (k_sigset_t *)NULL); 496 497 if (ua == NULL || *ua == NULL) { 498 status = RPC_PROGNOTREGISTERED; 499 goto out; 500 } 501 502 /* 503 * Convert the universal address to the transport address. 504 * Theoretically, we should call the local rpcbind to translate 505 * from the universal address to the transport address, but it gets 506 * complicated (e.g., there's no direct way to tell rpcbind that we 507 * want an IP address instead of a loopback address). Note that 508 * the transport address is potentially host-specific, so we can't 509 * just ask the remote rpcbind, because it might give us the wrong 510 * answer. 511 */ 512 if (strcmp(config->knc_protofmly, NC_INET) == 0) { 513 /* make sure that the ip address is the correct type */ 514 if (rpc_iptype(ua, &iptype) != 0) { 515 status = RPC_UNKNOWNADDR; 516 goto out; 517 } 518 port = rpc_uaddr2port(iptype, ua); 519 put_inet_port(addr, ntohs(port)); 520 } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) { 521 /* make sure that the ip address is the correct type */ 522 if (rpc_iptype(ua, &iptype) != 0) { 523 status = RPC_UNKNOWNADDR; 524 goto out; 525 } 526 port = rpc_uaddr2port(iptype, ua); 527 put_inet6_port(addr, ntohs(port)); 528 } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) { 529 loopb_u2t(ua, addr); 530 } else { 531 /* "can't happen" - should have been checked for above */ 532 cmn_err(CE_PANIC, "rpcbind_getaddr: bad protocol family"); 533 } 534 535 out: 536 if (client != NULL) { 537 auth_destroy(client->cl_auth); 538 clnt_destroy(client); 539 } 540 if (ua != NULL) 541 xdr_free(xdr_wrapstring, (char *)&ua); 542 return (status); 543 } 544 545 static const char *tpiprims[] = { 546 "T_CONN_REQ 0 connection request", 547 "T_CONN_RES 1 connection response", 548 "T_DISCON_REQ 2 disconnect request", 549 "T_DATA_REQ 3 data request", 550 "T_EXDATA_REQ 4 expedited data request", 551 "T_INFO_REQ 5 information request", 552 "T_BIND_REQ 6 bind request", 553 "T_UNBIND_REQ 7 unbind request", 554 "T_UNITDATA_REQ 8 unitdata request", 555 "T_OPTMGMT_REQ 9 manage options req", 556 "T_ORDREL_REQ 10 orderly release req", 557 "T_CONN_IND 11 connection indication", 558 "T_CONN_CON 12 connection confirmation", 559 "T_DISCON_IND 13 disconnect indication", 560 "T_DATA_IND 14 data indication", 561 "T_EXDATA_IND 15 expeditied data indication", 562 "T_INFO_ACK 16 information acknowledgment", 563 "T_BIND_ACK 17 bind acknowledment", 564 "T_ERROR_ACK 18 error acknowledgment", 565 "T_OK_ACK 19 ok acknowledgment", 566 "T_UNITDATA_IND 20 unitdata indication", 567 "T_UDERROR_IND 21 unitdata error indication", 568 "T_OPTMGMT_ACK 22 manage options ack", 569 "T_ORDREL_IND 23 orderly release ind" 570 }; 571 572 573 const char * 574 rpc_tpiprim2name(uint_t prim) 575 { 576 if (prim > (sizeof (tpiprims) / sizeof (tpiprims[0]) - 1)) 577 return ("unknown primitive"); 578 579 return (tpiprims[prim]); 580 } 581 582 static const char *tpierrs[] = { 583 "error zero 0", 584 "TBADADDR 1 incorrect addr format", 585 "TBADOPT 2 incorrect option format", 586 "TACCES 3 incorrect permissions", 587 "TBADF 4 illegal transport fd", 588 "TNOADDR 5 couldn't allocate addr", 589 "TOUTSTATE 6 out of state", 590 "TBADSEQ 7 bad call sequnce number", 591 "TSYSERR 8 system error", 592 "TLOOK 9 event requires attention", 593 "TBADDATA 10 illegal amount of data", 594 "TBUFOVFLW 11 buffer not large enough", 595 "TFLOW 12 flow control", 596 "TNODATA 13 no data", 597 "TNODIS 14 discon_ind not found on q", 598 "TNOUDERR 15 unitdata error not found", 599 "TBADFLAG 16 bad flags", 600 "TNOREL 17 no ord rel found on q", 601 "TNOTSUPPORT 18 primitive not supported", 602 "TSTATECHNG 19 state is in process of changing" 603 }; 604 605 606 const char * 607 rpc_tpierr2name(uint_t err) 608 { 609 if (err > (sizeof (tpierrs) / sizeof (tpierrs[0]) - 1)) 610 return ("unknown error"); 611 612 return (tpierrs[err]); 613 } 614 615 /* 616 * derive the code from user land inet_top6 617 * convert IPv6 binary address into presentation (printable) format 618 */ 619 #define INADDRSZ 4 620 #define IN6ADDRSZ 16 621 #define INT16SZ 2 622 const char * 623 kinet_ntop6(src, dst, size) 624 uchar_t *src; 625 char *dst; 626 size_t size; 627 { 628 /* 629 * Note that int32_t and int16_t need only be "at least" large enough 630 * to contain a value of the specified size. On some systems, like 631 * Crays, there is no such thing as an integer variable with 16 bits. 632 * Keep this in mind if you think this function should have been coded 633 * to use pointer overlays. All the world's not a VAX. 634 */ 635 char tmp[sizeof ("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; 636 char *tp; 637 struct { int base, len; } best, cur; 638 uint_t words[IN6ADDRSZ / INT16SZ]; 639 int i; 640 size_t len; /* this is used to track the sprintf len */ 641 642 /* 643 * Preprocess: 644 * Copy the input (bytewise) array into a wordwise array. 645 * Find the longest run of 0x00's in src[] for :: shorthanding. 646 */ 647 648 bzero(words, sizeof (words)); 649 for (i = 0; i < IN6ADDRSZ; i++) 650 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); 651 best.base = -1; 652 cur.base = -1; 653 654 for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 655 if (words[i] == 0) { 656 if (cur.base == -1) 657 cur.base = i, cur.len = 1; 658 else 659 cur.len++; 660 } else { 661 if (cur.base != -1) { 662 if (best.base == -1 || cur.len > best.len) 663 best = cur; 664 cur.base = -1; 665 } 666 } 667 } 668 if (cur.base != -1) { 669 if (best.base == -1 || cur.len > best.len) 670 best = cur; 671 } 672 673 if (best.base != -1 && best.len < 2) 674 best.base = -1; 675 676 /* 677 * Format the result. 678 */ 679 tp = tmp; 680 for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 681 /* Are we inside the best run of 0x00's? */ 682 if (best.base != -1 && i >= best.base && 683 i < (best.base + best.len)) { 684 if (i == best.base) 685 *tp++ = ':'; 686 continue; 687 } 688 /* Are we following an initial run of 0x00s or any real hex? */ 689 if (i != 0) 690 *tp++ = ':'; 691 (void) sprintf(tp, "%x", words[i]); 692 len = strlen(tp); 693 tp += len; 694 } 695 /* Was it a trailing run of 0x00's? */ 696 if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) 697 *tp++ = ':'; 698 *tp++ = '\0'; 699 700 /* 701 * Check for overflow, copy, and we're done. 702 */ 703 if ((int)(tp - tmp) > size) { 704 return (NULL); 705 } 706 (void) strcpy(dst, tmp); 707 return (dst); 708 } 709