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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2013-2021 Tintri by DDN, Inc. All rights reserved. 26 */ 27 28 /* 29 * SMB mbuf marshaling encode/decode. 30 */ 31 32 #include <smbsrv/smb_kproto.h> 33 34 35 #define MALLOC_QUANTUM 80 36 37 #define DECODE_NO_ERROR 0 38 #define DECODE_NO_MORE_DATA 1 39 #define DECODE_ALLOCATION_ERROR 2 40 #define DECODE_CONVERSION_ERROR 3 41 42 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t); 43 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t); 44 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t); 45 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t); 46 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t); 47 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t); 48 static int mbc_marshal_put_oem_string(mbuf_chain_t *, char *, int); 49 static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int); 50 static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *); 51 static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m); 52 static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc); 53 static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc); 54 static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data); 55 static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data); 56 static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data); 57 static uint64_t qswap(uint64_t ll); 58 static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data); 59 static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data); 60 static int mbc_marshal_get_oem_string(smb_request_t *, mbuf_chain_t *, 61 char **, int); 62 static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *, 63 char **, int); 64 static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **); 65 static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *); 66 static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *); 67 static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t); 68 69 /* 70 * smb_mbc_vdecodef 71 * 72 * This function reads the contents of the mbc chain passed in under the list 73 * of arguments passed in. 74 * 75 * The format string provides a description of the parameters passed in as well 76 * as an action to be taken by smb_mbc_vdecodef(). 77 * 78 * % Pointer to an SMB request structure (smb_request_t *). There 79 * should be only one of these in the string. 80 * 81 * C Pointer to an mbuf chain. Copy to that mbuf chain the number of 82 * bytes specified (number preceding C). 83 * 84 * m Pointer to an mbuf. Copy to that mbuf the number of bytes 85 * specified (number preceding m). 86 * 87 * M Read the 32 bit value at the current location of the mbuf chain 88 * and check if it matches the signature of an SMB1 request (SMBx). 89 * 90 * N Read the 32 bit value at the current location of the mbuf chain 91 * and check if it matches the signature of an SMB2 request (SMBx). 92 * 93 * b Pointer to a buffer. Copy to that buffer the number of bytes 94 * specified (number preceding b). 95 * 96 * c Same as 'b'. 97 * 98 * w Pointer to a word (16bit value). Copy the next 16bit value into 99 * that location. 100 * 101 * l Pointer to a long (32bit value). Copy the next 32bit value into 102 * that location. 103 * 104 * q Pointer to a quad (64bit value). Copy the next 64bit value into 105 * that location. 106 * 107 * Q Same as above with a call to qswap(). 108 * 109 * B Pointer to a vardata_block structure. That structure is used to 110 * retrieve data from the mbuf chain (an iovec type structure is 111 * embedded in a vardata_block). 112 * 113 * D Pointer to a vardata_block structure. That structure is used to 114 * retrieve data from the mbuf chain, however, two fields of the 115 * vardata_block structure (tag and len) are first initialized 116 * using the mbuf chain itself. 117 * 118 * V Same as 'D'. 119 * 120 * L 121 * 122 * A 123 * 124 * P Same as 'A' 125 * 126 * S Same as 'A' 127 * 128 * u Pointer to a string pointer. Allocate memory and retrieve the 129 * string at the current location in the mbuf chain. Store the 130 * address to the buffer allocated at the address specified by 131 * the pointer. In addition if an sr was passed and it indicates 132 * that the string is an unicode string, convert it. 133 * 134 * s Same as 'u' without convertion. 135 * 136 * U Same as 'u'. The string to retrieve is unicode. 137 * 138 * y Pointer to a 32bit value. Read the dos time at the current mbuf 139 * chain location, convert it to unix time and store it at the 140 * location indicated by the pointer. 141 * 142 * Y Same as 'y' bt the dos time coded in the mbuf chain is inverted. 143 * 144 * . Skip the number of bytes indicated by the number preceding '.'. 145 * 146 * , Same as '.' but take in account it is an unicode string. 147 */ 148 int 149 smb_mbc_vdecodef(mbuf_chain_t *mbc, const char *fmt, va_list ap) 150 { 151 uint8_t c; 152 uint8_t cval; 153 uint8_t *cvalp; 154 char **charpp; 155 uint16_t wval; 156 uint16_t *wvalp; 157 uint32_t *lvalp; 158 uint64_t *llvalp; 159 smb_vdb_t *vdp; 160 smb_request_t *sr = NULL; 161 uint32_t lval; 162 int unicode = 0; 163 int repc; 164 boolean_t repc_specified; 165 166 while ((c = *fmt++) != 0) { 167 repc_specified = B_FALSE; 168 repc = 1; 169 170 if ('0' <= c && c <= '9') { 171 repc = 0; 172 do { 173 repc = repc * 10 + c - '0'; 174 c = *fmt++; 175 } while ('0' <= c && c <= '9'); 176 repc_specified = B_TRUE; 177 } else if (c == '#') { 178 repc = va_arg(ap, int); 179 c = *fmt++; 180 repc_specified = B_TRUE; 181 } 182 183 switch (c) { 184 case '%': 185 sr = va_arg(ap, struct smb_request *); 186 if (sr->session->dialect >= SMB_VERS_2_BASE) { 187 unicode = 1; 188 break; 189 } 190 unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE; 191 break; 192 193 case 'C': /* Mbuf_chain */ 194 if (mbc_marshal_get_mbuf_chain(mbc, repc, 195 va_arg(ap, mbuf_chain_t *)) != 0) 196 return (-1); 197 break; 198 199 case 'm': /* struct_mbuf */ 200 if (mbc_marshal_get_mbufs(mbc, repc, 201 va_arg(ap, mbuf_t **)) != 0) 202 return (-1); 203 break; 204 205 case 'M': 206 if (mbc_marshal_get_long(mbc, &lval) != 0) 207 return (-1); 208 if (lval != 0x424D53FF) /* 0xFF S M B */ 209 return (-1); 210 break; 211 212 case 'N': 213 if (mbc_marshal_get_long(mbc, &lval) != 0) 214 return (-1); 215 if (lval != 0x424D53FE) /* 0xFE S M B */ 216 return (-1); 217 break; 218 219 case 'b': 220 case 'c': 221 cvalp = va_arg(ap, uint8_t *); 222 if (MBC_ROOM_FOR(mbc, repc) == 0) 223 /* Data will never be available */ 224 return (-1); 225 226 while (repc-- > 0) 227 *cvalp++ = mbc_marshal_fetch_byte(mbc); 228 break; 229 230 case 'w': 231 wvalp = va_arg(ap, uint16_t *); 232 while (repc-- > 0) 233 if (mbc_marshal_get_short(mbc, wvalp++) != 0) 234 return (-1); 235 break; 236 237 case 'l': 238 lvalp = va_arg(ap, uint32_t *); 239 while (repc-- > 0) 240 if (mbc_marshal_get_long(mbc, lvalp++) != 0) 241 return (-1); 242 break; 243 244 case 'q': 245 llvalp = va_arg(ap, uint64_t *); 246 while (repc-- > 0) 247 if (mbc_marshal_get_long_long( 248 mbc, llvalp++) != 0) 249 return (-1); 250 break; 251 252 case 'Q': 253 llvalp = va_arg(ap, uint64_t *); 254 while (repc-- > 0) 255 if (mbc_marshal_get_odd_long_long( 256 mbc, llvalp++) != 0) 257 return (-1); 258 break; 259 260 case 'B': 261 vdp = va_arg(ap, struct vardata_block *); 262 vdp->vdb_tag = 0; 263 vdp->vdb_len = repc; 264 vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; 265 vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; 266 vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 267 vdp->vdb_uio.uio_resid = repc; 268 if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0) 269 return (-1); 270 break; 271 272 case 'D': 273 case 'V': 274 vdp = va_arg(ap, struct vardata_block *); 275 if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0) 276 return (-1); 277 if (mbc_marshal_get_short(mbc, &wval) != 0) 278 return (-1); 279 vdp->vdb_len = (uint32_t)wval; 280 vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; 281 vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; 282 vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 283 vdp->vdb_uio.uio_resid = vdp->vdb_len; 284 if (vdp->vdb_len != 0) { 285 if (mbc_marshal_get_uio(mbc, 286 &vdp->vdb_uio) != 0) 287 return (-1); 288 } 289 break; 290 291 case 'L': 292 if (mbc_marshal_get_char(mbc, &cval) != 0) 293 return (-1); 294 if (cval != 2) 295 return (-1); 296 goto oem_conversion; 297 298 case 'A': 299 case 'S': 300 if (mbc_marshal_get_char(mbc, &cval) != 0) 301 return (-1); 302 if (((c == 'A' || c == 'S') && cval != 4) || 303 (c == 'L' && cval != 2)) 304 return (-1); 305 /* FALLTHROUGH */ 306 307 case 'u': /* Convert from unicode if flags are set */ 308 if (unicode) 309 goto unicode_translation; 310 /* FALLTHROUGH */ 311 312 case 's': /* get OEM string */ 313 oem_conversion: 314 ASSERT(sr != NULL); 315 charpp = va_arg(ap, char **); 316 if (!repc_specified) 317 repc = 0; 318 if (mbc_marshal_get_oem_string(sr, 319 mbc, charpp, repc) != 0) 320 return (-1); 321 break; 322 323 case 'U': /* get UTF-16 string */ 324 unicode_translation: 325 ASSERT(sr != 0); 326 charpp = va_arg(ap, char **); 327 if (!repc_specified) 328 repc = 0; 329 if (mbc_marshal_get_unicode_string(sr, 330 mbc, charpp, repc) != 0) 331 return (-1); 332 break; 333 334 case 'Y': /* dos time to unix time tt/dd */ 335 lvalp = va_arg(ap, uint32_t *); 336 while (repc-- > 0) { 337 short d, t; 338 339 if (mbc_marshal_get_short(mbc, 340 (uint16_t *)&t) != 0) 341 return (-1); 342 if (mbc_marshal_get_short(mbc, 343 (uint16_t *)&d) != 0) 344 return (-1); 345 *lvalp++ = smb_time_dos_to_unix(d, t); 346 } 347 break; 348 349 case 'y': /* dos time to unix time dd/tt */ 350 lvalp = va_arg(ap, uint32_t *); 351 while (repc-- > 0) { 352 short d, t; 353 354 if (mbc_marshal_get_short(mbc, 355 (uint16_t *)&d) != 0) 356 return (-1); 357 if (mbc_marshal_get_short(mbc, 358 (uint16_t *)&t) != 0) 359 return (-1); 360 *lvalp++ = smb_time_dos_to_unix(d, t); 361 } 362 break; 363 364 case ',': 365 if (unicode) 366 repc *= 2; 367 /* FALLTHROUGH */ 368 369 case '.': 370 if (mbc_marshal_get_skip(mbc, repc) != 0) 371 return (-1); 372 break; 373 374 default: 375 ASSERT(0); 376 return (-1); 377 } 378 } 379 return (0); 380 } 381 382 /* 383 * smb_mbc_decodef 384 * 385 * This function reads the contents of the mbc chain passed in under the 386 * control of the format fmt. 387 * 388 * (for a description of the format string see smb_mbc_vencodef()). 389 */ 390 int 391 smb_mbc_decodef(mbuf_chain_t *mbc, const char *fmt, ...) 392 { 393 int xx; 394 va_list ap; 395 396 va_start(ap, fmt); 397 xx = smb_mbc_vdecodef(mbc, fmt, ap); 398 va_end(ap); 399 return (xx); 400 } 401 402 /* 403 * smb_mbc_peek 404 * 405 * This function reads the contents of the mbc passed in at the specified offset 406 * under the control of the format fmt. The offset of the chain passed in is not 407 * modified. 408 * 409 * (for a description of the format string see smb_mbc_vdecodef()). 410 */ 411 int 412 smb_mbc_peek(mbuf_chain_t *mbc, int offset, const char *fmt, ...) 413 { 414 mbuf_chain_t tmp; 415 va_list ap; 416 int xx; 417 418 va_start(ap, fmt); 419 420 (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset); 421 xx = smb_mbc_vdecodef(&tmp, fmt, ap); 422 va_end(ap); 423 return (xx); 424 } 425 426 /* 427 * smb_mbc_vencodef 428 * 429 * This function builds a stream of bytes in the mbc chain passed in under the 430 * control of the list of arguments passed in. 431 * 432 * The format string provides a description of the parameters passed in as well 433 * as an action to be taken by smb_mbc_vencodef(). 434 * 435 * \b Restore the mbuf chain offset to its initial value. 436 * 437 * % Pointer to an SMB request structure (smb_request_t *). There 438 * should be only one of these in the string. If an sr in present 439 * it will be used to determine if unicode conversion should be 440 * applied to the strings. 441 * 442 * C Pointer to an mbuf chain. Copy that mbuf chain into the 443 * destination mbuf chain. 444 * 445 * D Pointer to a vardata_block structure. Copy the data described 446 * by that structure into the mbuf chain. The tag field is hard 447 * coded to '1'. 448 * 449 * M Write the SMB1 request signature ('SMBX') into the mbuf chain. 450 * 451 * N Write the SMB2 request signature ('SMBX') into the mbuf chain. 452 * 453 * T Pointer to a timestruc_t. Convert the content of the structure 454 * into NT time and store the result of the conversion in the 455 * mbuf chain. 456 * 457 * V Same as 'D' but the tag field is hard coded to '5'. 458 * 459 * b Byte. Store the byte or the nymber of bytes specified into the 460 * the mbuf chain. A format string like this "2b" would require 2 461 * bytes to be passed in. 462 * 463 * m Pointer to an mbuf. Copy the contents of the mbuf into the mbuf 464 * chain. 465 * 466 * c Pointer to a buffer. Copy the buffer into the mbuf chain. The 467 * size of the buffer is indicated by the number preceding 'c'. 468 * 469 * w Word (16bit value). Store the word or the number of words 470 * specified into the the mbuf chain. A format string like this 471 * "2w" would require 2 words to be passed in. 472 * 473 * l Long (32bit value). Store the long or the number of longs 474 * specified into the the mbuf chain. A format string like this 475 * "2l" would require 2 longs to be passed in. 476 * 477 * q Quad (64bit value). Store the quad or the number of quads 478 * specified into the the mbuf chain. A format string like this 479 * "2q" would require 2 quads to be passed in. 480 * 481 * L Pointer to a string. Store the string passed in into the mbuf 482 * chain preceded with a tag value of '2'. 483 * 484 * S Pointer to a string. Store the string passed in into the mbuf 485 * chain preceded with a tag value of '4'. Applied a unicode 486 * conversion is appropriate. 487 * 488 * A Same as 'S' 489 * 490 * P Pointer to a string. Store the string passed in into the mbuf 491 * chain preceded with a tag value of '5'. Applied a unicode 492 * conversion is appropriate. 493 * 494 * u Pointer to a string. Store the string passed in into the mbuf 495 * chain. Applied a unicode conversion is appropriate. 496 * 497 * s Pointer to a string. Store the string passed in into the mbuf 498 * chain. 499 * 500 * Y Date/Time. Store the Date/Time or the number of Date/Time(s) 501 * specified into the the mbuf chain. A format string like this 502 * "2Y" would require 2 Date/Time values. The Date/Time is 503 * converted to DOS before storing. 504 * 505 * y Same as 'Y'. The order of Date and Time is reversed. 506 * 507 * , Character. Store the character or number of character specified 508 * into the mbuf chain. A format string like this "2c" would 509 * require 2 characters to be passed in. A unicode conversion is 510 * applied if appropriate. 511 * 512 * . Same as '`' without unicode conversion. 513 * 514 * U Align the offset of the mbuf chain on a 16bit boundary. 515 */ 516 int 517 smb_mbc_vencodef(mbuf_chain_t *mbc, const char *fmt, va_list ap) 518 { 519 char *charp; 520 uint8_t *cvalp; 521 timestruc_t *tvp; 522 smb_vdb_t *vdp; 523 smb_request_t *sr = NULL; 524 uint64_t llval; 525 int64_t nt_time; 526 uint32_t lval; 527 uint_t tag; 528 int unicode = 0; 529 int repc; 530 boolean_t repc_specified; 531 uint16_t wval; 532 uint8_t cval; 533 uint8_t c; 534 535 while ((c = *fmt++) != 0) { 536 repc_specified = B_FALSE; 537 repc = 1; 538 539 if ('0' <= c && c <= '9') { 540 repc = 0; 541 do { 542 repc = repc * 10 + c - '0'; 543 c = *fmt++; 544 } while ('0' <= c && c <= '9'); 545 repc_specified = B_TRUE; 546 } else if (c == '#') { 547 repc = va_arg(ap, int); 548 c = *fmt++; 549 repc_specified = B_TRUE; 550 } 551 552 switch (c) { 553 case '%': 554 sr = va_arg(ap, struct smb_request *); 555 if (sr->session->dialect >= SMB_VERS_2_BASE) { 556 unicode = 1; 557 break; 558 } 559 unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE; 560 break; 561 562 case 'C': /* Mbuf_chain */ 563 if (mbc_marshal_put_mbuf_chain(mbc, 564 va_arg(ap, mbuf_chain_t *)) != 0) 565 return (DECODE_NO_MORE_DATA); 566 break; 567 568 case 'D': 569 vdp = va_arg(ap, struct vardata_block *); 570 571 if (mbc_marshal_put_char(mbc, 1) != 0) 572 return (DECODE_NO_MORE_DATA); 573 if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0) 574 return (DECODE_NO_MORE_DATA); 575 if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0) 576 return (DECODE_NO_MORE_DATA); 577 break; 578 579 case 'M': 580 /* 0xFF S M B */ 581 if (mbc_marshal_put_long(mbc, 0x424D53FF)) 582 return (DECODE_NO_MORE_DATA); 583 break; 584 585 case 'N': 586 /* 0xFE S M B */ 587 if (mbc_marshal_put_long(mbc, 0x424D53FE)) 588 return (DECODE_NO_MORE_DATA); 589 break; 590 591 case 'T': 592 tvp = va_arg(ap, timestruc_t *); 593 nt_time = smb_time_unix_to_nt(tvp); 594 if (mbc_marshal_put_long_long(mbc, nt_time) != 0) 595 return (DECODE_NO_MORE_DATA); 596 break; 597 598 case 'V': 599 vdp = va_arg(ap, struct vardata_block *); 600 601 if (mbc_marshal_put_char(mbc, 5) != 0) 602 return (DECODE_NO_MORE_DATA); 603 if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0) 604 return (DECODE_NO_MORE_DATA); 605 if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0) 606 return (DECODE_NO_MORE_DATA); 607 break; 608 609 case 'b': 610 while (repc-- > 0) { 611 cval = va_arg(ap, int); 612 if (mbc_marshal_put_char(mbc, cval) != 0) 613 return (DECODE_NO_MORE_DATA); 614 } 615 break; 616 617 case 'm': /* struct_mbuf */ 618 if (mbc_marshal_put_mbufs(mbc, 619 va_arg(ap, mbuf_t *)) != 0) 620 return (DECODE_NO_MORE_DATA); 621 break; 622 623 case 'c': 624 cvalp = va_arg(ap, uint8_t *); 625 while (repc-- > 0) { 626 if (mbc_marshal_put_char(mbc, 627 *cvalp++) != 0) 628 return (DECODE_NO_MORE_DATA); 629 } 630 break; 631 632 case 'w': 633 while (repc-- > 0) { 634 wval = va_arg(ap, int); 635 if (mbc_marshal_put_short(mbc, wval) != 0) 636 return (DECODE_NO_MORE_DATA); 637 } 638 break; 639 640 case 'l': 641 while (repc-- > 0) { 642 lval = va_arg(ap, uint32_t); 643 if (mbc_marshal_put_long(mbc, lval) != 0) 644 return (DECODE_NO_MORE_DATA); 645 } 646 break; 647 648 case 'q': 649 while (repc-- > 0) { 650 llval = va_arg(ap, uint64_t); 651 if (mbc_marshal_put_long_long(mbc, llval) != 0) 652 return (DECODE_NO_MORE_DATA); 653 } 654 break; 655 656 657 case 'L': 658 tag = 2; 659 goto oem_conversion; 660 661 case 'S': 662 case 'A': 663 tag = 4; 664 goto tagged_str; 665 666 case 'P': 667 tag = 3; 668 goto tagged_str; 669 670 tagged_str: 671 if (mbc_marshal_put_char(mbc, tag) != 0) 672 return (DECODE_NO_MORE_DATA); 673 /* FALLTHROUGH */ 674 675 case 'u': /* Convert from unicode if flags are set */ 676 if (unicode) 677 goto unicode_translation; 678 /* FALLTHROUGH */ 679 680 case 's': /* put OEM string */ 681 oem_conversion: 682 charp = va_arg(ap, char *); 683 if (!repc_specified) 684 repc = 0; 685 if (mbc_marshal_put_oem_string(mbc, 686 charp, repc) != 0) 687 return (DECODE_NO_MORE_DATA); 688 break; 689 690 case 'U': /* put UTF-16 string */ 691 unicode_translation: 692 charp = va_arg(ap, char *); 693 if (!repc_specified) 694 repc = 0; 695 if (mbc_marshal_put_unicode_string(mbc, 696 charp, repc) != 0) 697 return (DECODE_NO_MORE_DATA); 698 break; 699 700 case 'Y': /* int32_t, encode dos date/time */ 701 while (repc-- > 0) { 702 uint16_t d, t; 703 704 lval = va_arg(ap, uint32_t); 705 smb_time_unix_to_dos(lval, 706 (short *)&d, (short *)&t); 707 if (mbc_marshal_put_short(mbc, t) != 0) 708 return (DECODE_NO_MORE_DATA); 709 if (mbc_marshal_put_short(mbc, d) != 0) 710 return (DECODE_NO_MORE_DATA); 711 } 712 break; 713 714 case 'y': /* int32_t, encode dos date/time */ 715 while (repc-- > 0) { 716 uint16_t d, t; 717 718 lval = va_arg(ap, uint32_t); 719 smb_time_unix_to_dos(lval, 720 (short *)&d, (short *)&t); 721 if (mbc_marshal_put_short(mbc, d) != 0) 722 return (DECODE_NO_MORE_DATA); 723 if (mbc_marshal_put_short(mbc, t) != 0) 724 return (DECODE_NO_MORE_DATA); 725 } 726 break; 727 728 case ',': 729 if (unicode) 730 repc *= 2; 731 /* FALLTHROUGH */ 732 733 case '.': 734 while (repc-- > 0) 735 if (mbc_marshal_put_char(mbc, 0) != 0) 736 return (DECODE_NO_MORE_DATA); 737 break; 738 739 default: 740 ASSERT(0); 741 return (-1); 742 } 743 } 744 return (0); 745 } 746 747 /* 748 * smb_mbc_encodef 749 * 750 * This function builds a stream of bytes in the mbc chain passed in under the 751 * control of the format fmt. 752 * 753 * (for a description of the format string see smb_mbc_vencodef()). 754 */ 755 int 756 smb_mbc_encodef(mbuf_chain_t *mbc, const char *fmt, ...) 757 { 758 int rc; 759 va_list ap; 760 761 va_start(ap, fmt); 762 rc = smb_mbc_vencodef(mbc, fmt, ap); 763 va_end(ap); 764 return (rc); 765 } 766 767 /* 768 * smb_mbc_poke 769 * 770 * This function writes a stream of bytes in the mbc passed in at the specified 771 * offset under the control of the format fmt. The offset of the chain passed in 772 * is not modified. 773 * 774 * (for a description of the format string see smb_mbc_vencodef()). 775 */ 776 int 777 smb_mbc_poke(mbuf_chain_t *mbc, int offset, const char *fmt, ...) 778 { 779 int len, rc; 780 mbuf_chain_t tmp; 781 va_list ap; 782 783 if ((len = mbc->max_bytes - offset) < 0) 784 return (DECODE_NO_MORE_DATA); 785 rc = MBC_SHADOW_CHAIN(&tmp, mbc, offset, len); 786 if (rc) 787 return (DECODE_NO_MORE_DATA); 788 789 va_start(ap, fmt); 790 rc = smb_mbc_vencodef(&tmp, fmt, ap); 791 va_end(ap); 792 793 return (rc); 794 } 795 796 /* 797 * Copy data from the src mbuf chain to the dst mbuf chain, 798 * at the given offset in the src and current offset in dst, 799 * for copy_len bytes. Does NOT update src->chain_offset. 800 */ 801 int 802 smb_mbc_copy(mbuf_chain_t *dst_mbc, const mbuf_chain_t *src_mbc, 803 int copy_offset, int copy_len) 804 { 805 mbuf_t *src_m; 806 int offset, len; 807 int rc; 808 809 if (copy_len <= 0) 810 return (0); 811 if (copy_offset < 0) 812 return (EINVAL); 813 if ((copy_offset + copy_len) > src_mbc->max_bytes) 814 return (EMSGSIZE); 815 816 /* 817 * Advance to the src mbuf where we start copying. 818 */ 819 offset = copy_offset; 820 src_m = src_mbc->chain; 821 while (src_m && offset >= src_m->m_len) { 822 offset -= src_m->m_len; 823 src_m = src_m->m_next; 824 } 825 if (src_m == NULL) 826 return (EFAULT); 827 828 /* 829 * Copy the first part, which may start somewhere past 830 * the beginning of the current mbuf. 831 */ 832 len = src_m->m_len - offset; 833 if (len > copy_len) 834 len = copy_len; 835 rc = smb_mbc_put_mem(dst_mbc, src_m->m_data + offset, len); 836 if (rc != 0) 837 return (rc); 838 copy_len -= len; 839 840 /* 841 * Copy remaining mbufs... 842 */ 843 while (copy_len > 0) { 844 src_m = src_m->m_next; 845 if (src_m == NULL) 846 break; 847 len = src_m->m_len; 848 if (len > copy_len) 849 len = copy_len; 850 rc = smb_mbc_put_mem(dst_mbc, src_m->m_data, len); 851 copy_len -= len; 852 } 853 854 return (0); 855 } 856 857 /* 858 * Copy data from the passed memory buffer into the mbuf chain 859 * at the current offset. 860 */ 861 int 862 smb_mbc_put_mem(mbuf_chain_t *mbc, void *vmem, int mem_len) 863 { 864 caddr_t mem = vmem; 865 mbuf_t *m; 866 int32_t offset, tlen; 867 int rc; 868 869 if (mem_len <= 0) 870 return (0); 871 872 if ((rc = mbc_marshal_make_room(mbc, mem_len)) != 0) 873 return (rc); 874 875 /* 876 * Advance to the dst mbuf where we start copying. 877 * Allocations were done by _make_room(). 878 */ 879 offset = mbc->chain_offset; 880 m = mbc->chain; 881 while (offset >= m->m_len) { 882 ASSERT(m->m_len > 0); 883 offset -= m->m_len; 884 m = m->m_next; 885 } 886 887 /* 888 * Copy the first part, which may start somewhere past 889 * the beginning of the current mbuf. 890 */ 891 tlen = m->m_len - offset; 892 if (tlen > mem_len) 893 tlen = mem_len; 894 bcopy(mem, m->m_data + offset, tlen); 895 mbc->chain_offset += tlen; 896 mem += tlen; 897 mem_len -= tlen; 898 899 /* 900 * Copy remaining mem into mbufs. These all start 901 * at the beginning of each mbuf, and the last may 902 * end somewhere short of m_len. 903 */ 904 while (mem_len > 0) { 905 m = m->m_next; 906 tlen = m->m_len; 907 if (tlen > mem_len) 908 tlen = mem_len; 909 bcopy(mem, m->m_data, tlen); 910 mbc->chain_offset += tlen; 911 mem += tlen; 912 mem_len -= tlen; 913 } 914 915 return (0); 916 } 917 918 /* 919 * Put padding sufficient to align to A, where 920 * A is some power of 2 greater than zero. 921 */ 922 int 923 smb_mbc_put_align(mbuf_chain_t *mbc, int align) 924 { 925 int mask = align - 1; 926 int padsz; 927 928 ASSERT(align > 0 && (align & mask) == 0); 929 if ((mbc->chain_offset & mask) == 0) 930 return (0); 931 padsz = align - (mbc->chain_offset & mask); 932 return (smb_mbc_encodef(mbc, "#.", padsz)); 933 } 934 935 /* 936 * Put data into mbuf chain allocating as needed. 937 * Adds room to end of mbuf chain if needed. 938 */ 939 static int 940 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed) 941 { 942 mbuf_t *m; 943 mbuf_t *last; 944 int32_t bytes_available; 945 946 bytes_needed += mbc->chain_offset; 947 if (bytes_needed > mbc->max_bytes) 948 return (EMSGSIZE); 949 950 /* 951 * First mbuf in chain should have prepend space. 952 * See M_LEADINGSPACE() below. 953 */ 954 if ((m = mbc->chain) == NULL) { 955 MGET(m, M_WAIT, MT_DATA); 956 m->m_len = 0; 957 MCLGET(m, M_WAIT); 958 m->m_data += MH_PREPEND_SPACE; 959 mbc->chain = m; 960 /* xxxx */ 961 /* ^ */ 962 } 963 964 /* ---- ----- --xx ---xxx */ 965 /* ^ */ 966 967 last = NULL; 968 while ((m != NULL) && (bytes_needed >= m->m_len)) { 969 last = m; 970 bytes_needed -= m->m_len; 971 m = m->m_next; 972 } 973 974 if ((bytes_needed == 0) || (m != NULL)) { 975 /* We have enough room already */ 976 return (0); 977 } 978 979 /* ---- ----- --xx ---xxx */ 980 /* ^ */ 981 /* Back up to start of last mbuf */ 982 m = last; 983 bytes_needed += m->m_len; 984 985 /* ---- ----- --xx ---xxx */ 986 /* ^ */ 987 bytes_available = M_SIZE(m) - M_LEADINGSPACE(m); 988 989 /* ---- ----- --xx ---xxx */ 990 /* ^ */ 991 while ((bytes_needed != 0) && (bytes_needed > bytes_available)) { 992 m->m_len = bytes_available; 993 bytes_needed -= m->m_len; 994 /* ---- ----- --xx ------ */ 995 /* ^ */ 996 997 MGET(m->m_next, M_WAIT, MT_DATA); 998 m = m->m_next; 999 m->m_len = 0; 1000 MCLGET(m, M_WAIT); 1001 1002 ASSERT(M_LEADINGSPACE(m) == 0); 1003 bytes_available = M_SIZE(m); 1004 1005 /* ---- ----- --xx ------ xxxx */ 1006 /* ^ */ 1007 } 1008 1009 /* ---- ----- --xx ------ xxxx */ 1010 /* ^ */ 1011 /* Expand last tail as needed */ 1012 if (m->m_len <= bytes_needed) { 1013 m->m_len = bytes_needed; 1014 /* ---- ----- --xx ------ --xx */ 1015 /* ^ */ 1016 } 1017 1018 return (0); 1019 } 1020 1021 static void 1022 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data) 1023 { 1024 mbuf_t *m = mbc->chain; 1025 int32_t cur_offset = mbc->chain_offset; 1026 1027 /* 1028 * Scan forward looking for the last data currently in chain. 1029 */ 1030 while (cur_offset >= m->m_len) { 1031 cur_offset -= m->m_len; 1032 m = m->m_next; 1033 } 1034 ((char *)m->m_data)[cur_offset] = data; 1035 mbc->chain_offset++; 1036 } 1037 1038 static int 1039 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data) 1040 { 1041 if (mbc_marshal_make_room(mbc, sizeof (char)) != 0) 1042 return (DECODE_NO_MORE_DATA); 1043 mbc_marshal_store_byte(mbc, data); 1044 return (0); 1045 } 1046 1047 static int 1048 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data) 1049 { 1050 if (mbc_marshal_make_room(mbc, sizeof (short))) 1051 return (DECODE_NO_MORE_DATA); 1052 mbc_marshal_store_byte(mbc, data); 1053 mbc_marshal_store_byte(mbc, data >> 8); 1054 return (0); 1055 } 1056 1057 static int 1058 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data) 1059 { 1060 if (mbc_marshal_make_room(mbc, sizeof (int32_t))) 1061 return (DECODE_NO_MORE_DATA); 1062 mbc_marshal_store_byte(mbc, data); 1063 mbc_marshal_store_byte(mbc, data >> 8); 1064 mbc_marshal_store_byte(mbc, data >> 16); 1065 mbc_marshal_store_byte(mbc, data >> 24); 1066 return (0); 1067 } 1068 1069 static int 1070 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data) 1071 { 1072 if (mbc_marshal_make_room(mbc, sizeof (int64_t))) 1073 return (DECODE_NO_MORE_DATA); 1074 1075 mbc_marshal_store_byte(mbc, data); 1076 mbc_marshal_store_byte(mbc, data >> 8); 1077 mbc_marshal_store_byte(mbc, data >> 16); 1078 mbc_marshal_store_byte(mbc, data >> 24); 1079 mbc_marshal_store_byte(mbc, data >> 32); 1080 mbc_marshal_store_byte(mbc, data >> 40); 1081 mbc_marshal_store_byte(mbc, data >> 48); 1082 mbc_marshal_store_byte(mbc, data >> 56); 1083 return (0); 1084 } 1085 1086 /* 1087 * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset. 1088 * Also write a null unless the repc count limits the length we put. 1089 * When (repc > 0) the length we marshal must be exactly repc, and 1090 * truncate or pad the mbc data as necessary. 1091 * See also: msgbuf_put_oem_string 1092 */ 1093 static int 1094 mbc_marshal_put_oem_string(mbuf_chain_t *mbc, char *mbs, int repc) 1095 { 1096 uint8_t *oembuf = NULL; 1097 uint8_t *s; 1098 int oemlen; 1099 int rlen; 1100 int rc; 1101 1102 /* 1103 * Compute length of converted OEM string, 1104 * NOT including null terminator 1105 */ 1106 if ((oemlen = smb_sbequiv_strlen(mbs)) == -1) 1107 return (DECODE_NO_MORE_DATA); 1108 1109 /* 1110 * If repc not specified, put whole string + NULL, 1111 * otherwise will truncate or pad as needed. 1112 */ 1113 if (repc <= 0) 1114 repc = oemlen + 1; 1115 1116 /* 1117 * Convert into a temporary buffer 1118 * Free oembuf before return. 1119 */ 1120 oembuf = smb_mem_zalloc(oemlen + 1); 1121 ASSERT(oembuf != NULL); 1122 rlen = smb_mbstooem(oembuf, mbs, oemlen); 1123 if (rlen < 0) { 1124 rc = DECODE_NO_MORE_DATA; 1125 goto out; 1126 } 1127 if (rlen > oemlen) 1128 rlen = oemlen; 1129 oembuf[rlen] = '\0'; 1130 1131 /* 1132 * Copy the converted string into the message, 1133 * truncated or paded as required. 1134 */ 1135 s = oembuf; 1136 while (repc > 0) { 1137 if (mbc_marshal_make_room(mbc, 1)) { 1138 rc = DECODE_NO_MORE_DATA; 1139 goto out; 1140 } 1141 mbc_marshal_store_byte(mbc, *s); 1142 if (*s != '\0') 1143 s++; 1144 repc--; 1145 } 1146 rc = 0; 1147 1148 out: 1149 if (oembuf != NULL) 1150 smb_mem_free(oembuf); 1151 return (rc); 1152 } 1153 1154 /* 1155 * Marshal a UTF-8 string (str) into mbc, converting to UTF-16. 1156 * Also write a null unless the repc count limits the length. 1157 * When (repc > 0) the length we marshal must be exactly repc, 1158 * and truncate or pad the mbc data as necessary. 1159 * See also: msgbuf_put_unicode_string 1160 */ 1161 static int 1162 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *mbs, int repc) 1163 { 1164 smb_wchar_t *wcsbuf = NULL; 1165 smb_wchar_t *wp; 1166 smb_wchar_t wchar; 1167 size_t wcslen, wcsbytes; 1168 size_t rlen; 1169 int rc; 1170 1171 /* align to word boundary */ 1172 if (mbc->chain_offset & 1) { 1173 if (mbc_marshal_make_room(mbc, 1)) 1174 return (DECODE_NO_MORE_DATA); 1175 mbc_marshal_store_byte(mbc, 0); 1176 } 1177 1178 /* 1179 * Compute length of converted UTF-16 string, 1180 * NOT including null terminator (in bytes). 1181 */ 1182 wcsbytes = smb_wcequiv_strlen(mbs); 1183 if (wcsbytes == (size_t)-1) 1184 return (DECODE_NO_MORE_DATA); 1185 1186 /* 1187 * If repc not specified, put whole string + NULL, 1188 * otherwise will truncate or pad as needed. 1189 */ 1190 if (repc <= 0) 1191 repc = wcsbytes + 2; 1192 1193 /* 1194 * Convert into a temporary buffer 1195 * Free wcsbuf before return. 1196 */ 1197 wcslen = wcsbytes / 2; 1198 wcsbuf = smb_mem_zalloc(wcsbytes + 2); 1199 ASSERT(wcsbuf != NULL); 1200 rlen = smb_mbstowcs(wcsbuf, mbs, wcslen); 1201 if (rlen == (size_t)-1) { 1202 rc = DECODE_NO_MORE_DATA; 1203 goto out; 1204 } 1205 if (rlen > wcslen) 1206 rlen = wcslen; 1207 wcsbuf[rlen] = 0; 1208 1209 /* 1210 * Copy the converted string into the message, 1211 * truncated or paded as required. Preserve 1212 * little-endian order while copying. 1213 */ 1214 wp = wcsbuf; 1215 while (repc >= sizeof (smb_wchar_t)) { 1216 if (mbc_marshal_make_room(mbc, sizeof (smb_wchar_t))) { 1217 rc = DECODE_NO_MORE_DATA; 1218 goto out; 1219 } 1220 wchar = LE_IN16(wp); 1221 mbc_marshal_store_byte(mbc, wchar); 1222 mbc_marshal_store_byte(mbc, wchar >> 8); 1223 if (wchar != 0) 1224 wp++; 1225 repc -= sizeof (smb_wchar_t); 1226 } 1227 if (repc > 0) { 1228 if (mbc_marshal_make_room(mbc, 1)) { 1229 rc = DECODE_NO_MORE_DATA; 1230 goto out; 1231 } 1232 mbc_marshal_store_byte(mbc, 0); 1233 } 1234 rc = 0; 1235 1236 out: 1237 if (wcsbuf != NULL) 1238 smb_mem_free(wcsbuf); 1239 return (rc); 1240 } 1241 1242 static void /*ARGSUSED*/ 1243 uiorefnoop(mbuf_t *m) 1244 { 1245 } 1246 1247 static int 1248 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio) 1249 { 1250 mbuf_t **t; 1251 mbuf_t *m = NULL; 1252 struct iovec *iov = uio->uio_iov; 1253 int32_t i, iov_cnt = uio->uio_iovcnt; 1254 1255 iov = uio->uio_iov; 1256 t = &mbc->chain; 1257 for (i = 0; i < iov_cnt; i++) { 1258 MGET(m, M_WAIT, MT_DATA); 1259 m->m_ext.ext_buf = iov->iov_base; 1260 m->m_ext.ext_free = uiorefnoop; 1261 m->m_data = m->m_ext.ext_buf; 1262 m->m_flags |= M_EXT; 1263 m->m_len = m->m_ext.ext_size = iov->iov_len; 1264 mbc->max_bytes += m->m_len; 1265 m->m_next = 0; 1266 *t = m; 1267 t = &m->m_next; 1268 iov++; 1269 } 1270 return (0); 1271 } 1272 1273 int smb_mbuf_put_copy_threshold = 128; 1274 /* 1275 * Append an mbuf to the chain at chain_offset, with some optimizations: 1276 * If the chain is empty, just set the head (done). 1277 * If m is no larger than the copy threshold, copy. 1278 * Always consumes (or free's) the mbuf passed in. 1279 */ 1280 static int 1281 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *mbuf) 1282 { 1283 mbuf_t *m; 1284 int bytes, rc; 1285 1286 /* 1287 * Length of mbuf(s) to be appended 1288 */ 1289 bytes = 0; 1290 m = mbuf; 1291 while (m != NULL) { 1292 bytes += m->m_len; 1293 m = m->m_next; 1294 } 1295 if (bytes == 0) { 1296 m_freem(mbuf); 1297 return (0); 1298 } 1299 1300 /* 1301 * Check for space vs max_bytes 1302 */ 1303 if (!MBC_ROOM_FOR(mbc, bytes)) { 1304 m_freem(mbuf); 1305 return (EMSGSIZE); 1306 } 1307 1308 /* 1309 * Empty mbc? (probably rare) 1310 */ 1311 if (mbc->chain == NULL) { 1312 mbc->chain = mbuf; 1313 mbc->chain_offset = bytes; 1314 return (0); 1315 } 1316 1317 /* 1318 * Copy optimization. We've already checked that there's room 1319 * for the _put_mem operations, and that's the only error case 1320 * for that call, so just assert success and continue. 1321 */ 1322 if (bytes <= smb_mbuf_put_copy_threshold) { 1323 m = mbuf; 1324 while (m != NULL) { 1325 rc = smb_mbc_put_mem(mbc, m->m_data, m->m_len); 1326 ASSERT3S(rc, ==, 0); 1327 m = m_free(m); 1328 } 1329 return (0); 1330 } 1331 1332 /* 1333 * Trim existing chain and append 1334 */ 1335 smb_mbuf_trim(mbc->chain, mbc->chain_offset); 1336 m = mbc->chain; 1337 while (m->m_next != NULL) 1338 m = m->m_next; 1339 m->m_next = mbuf; 1340 mbc->chain_offset += bytes; 1341 1342 return (0); 1343 } 1344 1345 /* 1346 * Append a new mbc (nmbc) to the existing chain mbc 1347 * Assumes the new mbc has been "trimmed" to length. 1348 * (This ignores nmbc.chain_offset) 1349 * 1350 * Always consume or dispose of nmbc->chain 1351 */ 1352 static int 1353 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc) 1354 { 1355 int rc = 0; 1356 1357 if (nmbc->chain != NULL) { 1358 rc = mbc_marshal_put_mbufs(mbc, nmbc->chain); 1359 nmbc->chain = NULL; 1360 } 1361 return (rc); 1362 } 1363 1364 static uint8_t 1365 mbc_marshal_fetch_byte(mbuf_chain_t *mbc) 1366 { 1367 uint8_t data; 1368 mbuf_t *m = mbc->chain; 1369 int32_t offset = mbc->chain_offset; 1370 1371 while (offset >= m->m_len) { 1372 offset -= m->m_len; 1373 m = m->m_next; 1374 } 1375 data = ((uint8_t *)m->m_data)[offset]; 1376 mbc->chain_offset++; 1377 return (data); 1378 } 1379 1380 static int 1381 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data) 1382 { 1383 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) { 1384 /* Data will never be available */ 1385 return (DECODE_NO_MORE_DATA); 1386 } 1387 *data = mbc_marshal_fetch_byte(mbc); 1388 return (0); 1389 } 1390 1391 static int 1392 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data) 1393 { 1394 uint16_t tmp; 1395 mbuf_t *m = mbc->chain; 1396 int32_t offset = mbc->chain_offset; 1397 1398 if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) { 1399 /* Data will never be available */ 1400 return (DECODE_NO_MORE_DATA); 1401 } 1402 1403 while (offset >= m->m_len) { 1404 offset -= m->m_len; 1405 m = m->m_next; 1406 } 1407 if ((m->m_len - offset) >= sizeof (short)) { 1408 *data = LE_IN16(m->m_data + offset); 1409 mbc->chain_offset += sizeof (short); 1410 } else { 1411 tmp = (uint16_t)mbc_marshal_fetch_byte(mbc); 1412 tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8; 1413 *data = tmp; 1414 } 1415 return (0); 1416 } 1417 1418 static int 1419 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data) 1420 { 1421 uint32_t tmp; 1422 mbuf_t *m = mbc->chain; 1423 int32_t offset = mbc->chain_offset; 1424 1425 if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) { 1426 /* Data will never be available */ 1427 return (DECODE_NO_MORE_DATA); 1428 } 1429 while (offset >= m->m_len) { 1430 offset -= m->m_len; 1431 m = m->m_next; 1432 } 1433 if ((m->m_len - offset) >= sizeof (int32_t)) { 1434 *data = LE_IN32(m->m_data + offset); 1435 mbc->chain_offset += sizeof (int32_t); 1436 } else { 1437 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc); 1438 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8; 1439 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16; 1440 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24; 1441 *data = tmp; 1442 } 1443 return (0); 1444 } 1445 1446 static uint64_t 1447 qswap(uint64_t ll) 1448 { 1449 uint64_t v; 1450 1451 v = ll >> 32; 1452 v |= ll << 32; 1453 1454 return (v); 1455 } 1456 1457 static int 1458 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data) 1459 { 1460 uint64_t tmp; 1461 mbuf_t *m = mbc->chain; 1462 int32_t offset = mbc->chain_offset; 1463 1464 if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) { 1465 /* Data will never be available */ 1466 return (DECODE_NO_MORE_DATA); 1467 } 1468 while (offset >= m->m_len) { 1469 offset -= m->m_len; 1470 m = m->m_next; 1471 } 1472 1473 if ((m->m_len - offset) >= sizeof (int64_t)) { 1474 *data = qswap(LE_IN64(m->m_data + offset)); 1475 mbc->chain_offset += sizeof (int64_t); 1476 } else { 1477 tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32; 1478 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40; 1479 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48; 1480 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56; 1481 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc); 1482 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8; 1483 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16; 1484 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24; 1485 1486 *(uint64_t *)data = tmp; 1487 } 1488 return (0); 1489 } 1490 1491 static int 1492 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data) 1493 { 1494 uint64_t tmp; 1495 mbuf_t *m = mbc->chain; 1496 int32_t offset = mbc->chain_offset; 1497 1498 if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) { 1499 /* Data will never be available */ 1500 return (DECODE_NO_MORE_DATA); 1501 } 1502 while (offset >= m->m_len) { 1503 offset -= m->m_len; 1504 m = m->m_next; 1505 } 1506 if ((m->m_len - offset) >= sizeof (int64_t)) { 1507 *data = LE_IN64(m->m_data + offset); 1508 mbc->chain_offset += sizeof (int64_t); 1509 } else { 1510 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc); 1511 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8; 1512 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16; 1513 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24; 1514 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32; 1515 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40; 1516 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48; 1517 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56; 1518 *(uint64_t *)data = tmp; 1519 } 1520 return (0); 1521 } 1522 1523 /* 1524 * mbc_marshal_get_oem_string 1525 * 1526 * Decode an OEM string, returning its UTF-8 form in strpp, 1527 * allocated using smb_srm_zalloc (automatically freed). 1528 * If max_bytes != 0, consume at most max_bytes of the mbc. 1529 * See also: msgbuf_get_oem_string 1530 */ 1531 static int 1532 mbc_marshal_get_oem_string(smb_request_t *sr, 1533 mbuf_chain_t *mbc, char **strpp, int max_bytes) 1534 { 1535 char *mbs; 1536 uint8_t *oembuf = NULL; 1537 int oemlen, oemmax; 1538 int mbsmax; 1539 int rlen; 1540 int rc; 1541 1542 if (max_bytes == 0) 1543 max_bytes = 0xffff; 1544 1545 /* 1546 * Get the OtW data into a temporary buffer. 1547 * Free oembuf before return. 1548 */ 1549 oemlen = 0; 1550 oemmax = MALLOC_QUANTUM; 1551 oembuf = smb_mem_alloc(oemmax); 1552 for (;;) { 1553 uint8_t ch; 1554 1555 if (oemlen >= max_bytes) 1556 break; 1557 if ((oemlen + 2) >= oemmax) { 1558 oemmax += MALLOC_QUANTUM; 1559 oembuf = smb_mem_realloc(oembuf, oemmax); 1560 } 1561 if (mbc_marshal_get_char(mbc, &ch) != 0) { 1562 rc = DECODE_NO_MORE_DATA; 1563 goto out; 1564 } 1565 if (ch == 0) 1566 break; 1567 oembuf[oemlen++] = ch; 1568 } 1569 oembuf[oemlen] = '\0'; 1570 1571 /* 1572 * Get the buffer we'll return and convert to UTF-8. 1573 * May take as much as double the space. 1574 */ 1575 mbsmax = oemlen * 2; 1576 mbs = smb_srm_zalloc(sr, mbsmax + 1); 1577 ASSERT(mbs != NULL); 1578 rlen = smb_oemtombs(mbs, oembuf, mbsmax); 1579 if (rlen < 0) { 1580 rc = DECODE_NO_MORE_DATA; 1581 goto out; 1582 } 1583 if (rlen > mbsmax) 1584 rlen = mbsmax; 1585 mbs[rlen] = '\0'; 1586 *strpp = mbs; 1587 rc = 0; 1588 1589 out: 1590 if (oembuf != NULL) 1591 smb_mem_free(oembuf); 1592 return (rc); 1593 } 1594 1595 /* 1596 * mbc_marshal_get_unicode_string 1597 * 1598 * Decode a UTF-16 string, returning its UTF-8 form in strpp, 1599 * allocated using smb_srm_zalloc (automatically freed). 1600 * If max_bytes != 0, consume at most max_bytes of the mbc. 1601 * See also: msgbuf_get_unicode_string 1602 */ 1603 static int 1604 mbc_marshal_get_unicode_string(smb_request_t *sr, 1605 mbuf_chain_t *mbc, char **strpp, int max_bytes) 1606 { 1607 char *mbs; 1608 uint16_t *wcsbuf = NULL; 1609 int wcslen; // wchar count 1610 int wcsmax; // byte count 1611 size_t mbsmax; 1612 size_t rlen; 1613 int rc; 1614 1615 if (max_bytes == 0) 1616 max_bytes = 0xffff; 1617 1618 /* 1619 * Unicode strings are always word aligned. 1620 */ 1621 if (mbc->chain_offset & 1) { 1622 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) 1623 return (DECODE_NO_MORE_DATA); 1624 mbc->chain_offset++; 1625 } 1626 1627 /* 1628 * Get the OtW data into a temporary buffer. 1629 * Free wcsbuf before return. 1630 */ 1631 wcslen = 0; 1632 wcsmax = MALLOC_QUANTUM; 1633 wcsbuf = smb_mem_alloc(wcsmax); 1634 for (;;) { 1635 uint16_t wchar; 1636 1637 if ((wcslen * 2) >= max_bytes) 1638 break; 1639 if (((wcslen * 2) + 4) >= wcsmax) { 1640 wcsmax += MALLOC_QUANTUM; 1641 wcsbuf = smb_mem_realloc(wcsbuf, wcsmax); 1642 } 1643 if (mbc_marshal_get_short(mbc, &wchar) != 0) { 1644 rc = DECODE_NO_MORE_DATA; 1645 goto out; 1646 } 1647 if (wchar == 0) 1648 break; 1649 /* Keep in little-endian form. */ 1650 LE_OUT16(wcsbuf + wcslen, wchar); 1651 wcslen++; 1652 } 1653 wcsbuf[wcslen] = 0; 1654 1655 /* 1656 * Get the buffer we'll return and convert to UTF-8. 1657 * May take as much 4X number of wide chars. 1658 */ 1659 mbsmax = wcslen * MTS_MB_CUR_MAX; 1660 mbs = smb_srm_zalloc(sr, mbsmax + 1); 1661 ASSERT(mbs != NULL); 1662 rlen = smb_wcstombs(mbs, wcsbuf, mbsmax); 1663 if (rlen == (size_t)-1) { 1664 rc = DECODE_NO_MORE_DATA; 1665 goto out; 1666 } 1667 if (rlen > mbsmax) 1668 rlen = mbsmax; 1669 mbs[rlen] = '\0'; 1670 *strpp = mbs; 1671 rc = 0; 1672 1673 out: 1674 if (wcsbuf != NULL) 1675 smb_mem_free(wcsbuf); 1676 return (rc); 1677 } 1678 1679 static int /*ARGSUSED*/ 1680 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m) 1681 { 1682 *m = NULL; 1683 if (MBC_ROOM_FOR(mbc, bytes) == 0) { 1684 /* Data will never be available */ 1685 return (DECODE_NO_MORE_DATA); 1686 } 1687 /* not yet implemented */ 1688 return (-1); 1689 } 1690 1691 static int 1692 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc) 1693 { 1694 int rc; 1695 mbuf_t *m; 1696 1697 if (bytes == 0) { 1698 /* Get all the rest */ 1699 bytes = mbc->max_bytes - mbc->chain_offset; 1700 } 1701 1702 MBC_SETUP(nmbc, mbc->max_bytes); 1703 if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) { 1704 if (m) 1705 m_freem(m); 1706 return (rc); 1707 } 1708 nmbc->chain = m; 1709 while (m != 0) { 1710 bytes += m->m_len; 1711 m = m->m_next; 1712 } 1713 nmbc->max_bytes = bytes; 1714 return (0); 1715 } 1716 1717 static int 1718 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio) 1719 { 1720 int i, offset; 1721 int32_t bytes = uio->uio_resid; 1722 int32_t remainder; 1723 struct iovec *iov; 1724 mbuf_t *m; 1725 1726 /* 1727 * The residual count is tested because in the case of write requests 1728 * with no data (smbtorture RAW-WRITE test will generate that type of 1729 * request) this function is called with a residual count of zero 1730 * bytes. 1731 */ 1732 if (bytes != 0) { 1733 iov = uio->uio_iov; 1734 uio->uio_segflg = UIO_SYSSPACE; 1735 uio->uio_extflg = UIO_COPY_DEFAULT; 1736 1737 if (MBC_ROOM_FOR(mbc, bytes) == 0) { 1738 /* Data will never be available */ 1739 return (DECODE_NO_MORE_DATA); 1740 } 1741 1742 m = mbc->chain; 1743 offset = mbc->chain_offset; 1744 while (offset >= m->m_len) { 1745 offset -= m->m_len; 1746 m = m->m_next; 1747 ASSERT((offset == 0) || (offset && m)); 1748 } 1749 1750 for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) { 1751 iov[i].iov_base = &m->m_data[offset]; 1752 remainder = m->m_len - offset; 1753 if (remainder >= bytes) { 1754 iov[i].iov_len = bytes; 1755 mbc->chain_offset += bytes; 1756 uio->uio_iovcnt = i + 1; 1757 return (0); 1758 } 1759 iov[i].iov_len = remainder; 1760 mbc->chain_offset += remainder; 1761 bytes -= remainder; 1762 m = m->m_next; 1763 offset = 0; 1764 } 1765 return (DECODE_NO_MORE_DATA); 1766 } 1767 return (0); 1768 } 1769 1770 static int 1771 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip) 1772 { 1773 if (MBC_ROOM_FOR(mbc, skip) == 0) 1774 return (DECODE_NO_MORE_DATA); 1775 mbc->chain_offset += skip; 1776 return (0); 1777 } 1778