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