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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * SMB mbuf marshaling encode/decode. 28 */ 29 30 #include <smbsrv/smb_incl.h> 31 32 #include <sys/sunddi.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_cstou8(char *, char *, size_t, char *, size_t); 43 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t); 44 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t); 45 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t); 46 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t); 47 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t); 48 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t); 49 static int mbc_marshal_put_ascii_string(mbuf_chain_t *, char *, int); 50 static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int); 51 static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *); 52 static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m); 53 static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc); 54 static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc); 55 static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data); 56 static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data); 57 static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data); 58 static uint64_t qswap(uint64_t ll); 59 static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data); 60 static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data); 61 static int mbc_marshal_get_ascii_string(struct smb_malloc_list *, 62 mbuf_chain_t *, uint8_t **ascii, int); 63 static int mbc_marshal_get_unicode_string(struct smb_malloc_list *, 64 mbuf_chain_t *, uint8_t **, int); 65 static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **); 66 static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *); 67 static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *); 68 static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t); 69 70 /* 71 * smb_mbc_vdecodef 72 * 73 * This function reads the contents of the mbc chain passed in under the list 74 * of arguments passed in. 75 * 76 * The format string provides a description of the parameters passed in as well 77 * as an action to be taken by smb_mbc_vdecodef(). 78 * 79 * % Pointer to an SMB request structure (smb_request_t *). There 80 * should be only one of these in the string. 81 * 82 * C Pointer to an mbuf chain. Copy to that mbuf chain the number of 83 * bytes specified (number preceding C). 84 * 85 * m Pointer to an mbuf. Copy to that mbuf the number of bytes 86 * specified (number preceding m). 87 * 88 * M Read the 32 bit value at the current location of the mbuf chain 89 * and check if it matches the signature of an SMB request (SMBX). 90 * 91 * b Pointer to a buffer. Copy to that buffer the number of bytes 92 * specified (number preceding b). 93 * 94 * c Same as 'b'. 95 * 96 * w Pointer to a word (16bit value). Copy the next 16bit value into 97 * that location. 98 * 99 * l Pointer to a long (32bit value). Copy the next 32bit value into 100 * that location. 101 * 102 * q Pointer to a quad (64bit value). Copy the next 64bit value into 103 * that location. 104 * 105 * Q Same as above with a call to qswap(). 106 * 107 * B Pointer to a vardata_block structure. That structure is used to 108 * retrieve data from the mbuf chain (an iovec type structure is 109 * embedded in a vardata_block). 110 * 111 * D Pointer to a vardata_block structure. That structure is used to 112 * retrieve data from the mbuf chain, however, two fields of the 113 * vardata_block structure (tag and len) are first initialized 114 * using the mbuf chain itself. 115 * 116 * V Same as 'D'. 117 * 118 * L 119 * 120 * A 121 * 122 * P Same as 'A' 123 * 124 * S Same as 'A' 125 * 126 * u Pointer to a string pointer. Allocate memory and retrieve the 127 * string at the current location in the mbuf chain. Store the 128 * address to the buffer allocated at the address specified by 129 * the pointer. In addition if an sr was passed and it indicates 130 * that the string is an unicode string, convert it. 131 * 132 * s Same as 'u' without convertion. 133 * 134 * U Same as 'u'. The string to retrieve is unicode. 135 * 136 * y Pointer to a 32bit value. Read the dos time at the current mbuf 137 * chain location, convert it to unix time and store it at the 138 * location indicated by the pointer. 139 * 140 * Y Same as 'y' bt the dos time coded in the mbuf chain is inverted. 141 * 142 * . Skip the number of bytes indicated by the number preceding '.'. 143 * 144 * , Same as '.' but take in account it is an unicode string. 145 */ 146 int 147 smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap) 148 { 149 uint8_t c; 150 uint8_t cval; 151 uint8_t *cvalp; 152 uint8_t **cvalpp; 153 uint16_t wval; 154 uint16_t *wvalp; 155 uint32_t *lvalp; 156 uint64_t *llvalp; 157 smb_vdb_t *vdp; 158 smb_request_t *sr = NULL; 159 uint32_t lval; 160 int unicode = 0; 161 int repc; 162 163 while ((c = *fmt++) != 0) { 164 repc = 1; 165 166 if ('0' <= c && c <= '9') { 167 repc = 0; 168 do { 169 repc = repc * 10 + c - '0'; 170 c = *fmt++; 171 } while ('0' <= c && c <= '9'); 172 } else if (c == '#') { 173 repc = va_arg(ap, int); 174 c = *fmt++; 175 } 176 177 switch (c) { 178 case '%': 179 sr = va_arg(ap, struct smb_request *); 180 unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE; 181 break; 182 183 case 'C': /* Mbuf_chain */ 184 if (mbc_marshal_get_mbuf_chain(mbc, repc, 185 va_arg(ap, mbuf_chain_t *)) != 0) 186 return (-1); 187 break; 188 189 case 'm': /* struct_mbuf */ 190 if (mbc_marshal_get_mbufs(mbc, repc, 191 va_arg(ap, mbuf_t **)) != 0) 192 return (-1); 193 break; 194 195 case 'M': 196 if (mbc_marshal_get_long(mbc, &lval) != 0) 197 /* Data will never be available */ 198 return (-1); 199 200 if (lval != 0x424D53FF) /* 0xFF S M B */ 201 return (-1); 202 break; 203 204 case 'b': 205 case 'c': 206 cvalp = va_arg(ap, uint8_t *); 207 if (MBC_ROOM_FOR(mbc, repc) == 0) 208 /* Data will never be available */ 209 return (-1); 210 211 while (repc-- > 0) 212 *cvalp++ = mbc_marshal_fetch_byte(mbc); 213 break; 214 215 case 'w': 216 wvalp = va_arg(ap, uint16_t *); 217 while (repc-- > 0) 218 if (mbc_marshal_get_short(mbc, wvalp++) != 0) 219 return (-1); 220 break; 221 222 case 'l': 223 lvalp = va_arg(ap, uint32_t *); 224 while (repc-- > 0) 225 if (mbc_marshal_get_long(mbc, lvalp++) != 0) 226 return (-1); 227 break; 228 229 case 'q': 230 llvalp = va_arg(ap, uint64_t *); 231 while (repc-- > 0) 232 if (mbc_marshal_get_long_long( 233 mbc, llvalp++) != 0) 234 return (-1); 235 break; 236 237 case 'Q': 238 llvalp = va_arg(ap, uint64_t *); 239 while (repc-- > 0) 240 if (mbc_marshal_get_odd_long_long( 241 mbc, llvalp++) != 0) 242 return (-1); 243 break; 244 245 case 'B': 246 vdp = va_arg(ap, struct vardata_block *); 247 vdp->vdb_tag = 0; 248 vdp->vdb_len = repc; 249 vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; 250 vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; 251 vdp->vdb_uio.uio_resid = repc; 252 if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0) 253 return (-1); 254 break; 255 256 case 'D': 257 case 'V': 258 vdp = va_arg(ap, struct vardata_block *); 259 if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0) 260 return (-1); 261 if (mbc_marshal_get_short(mbc, &wval) != 0) 262 return (-1); 263 vdp->vdb_len = (uint32_t)wval; 264 vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; 265 vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; 266 vdp->vdb_uio.uio_resid = vdp->vdb_len; 267 if (vdp->vdb_len != 0) { 268 if (mbc_marshal_get_uio(mbc, 269 &vdp->vdb_uio) != 0) 270 return (-1); 271 } 272 break; 273 274 case 'L': 275 if (mbc_marshal_get_char(mbc, &cval) != 0) 276 return (-1); 277 if (cval != 2) 278 return (-1); 279 goto ascii_conversion; 280 281 case 'A': 282 case 'S': 283 if (mbc_marshal_get_char(mbc, &cval) != 0) 284 return (-1); 285 if (((c == 'A' || c == 'S') && cval != 4) || 286 (c == 'L' && cval != 2)) 287 return (-1); 288 /* FALLTHROUGH */ 289 290 case 'u': /* Convert from unicode if flags are set */ 291 if (unicode) 292 goto unicode_translation; 293 /* FALLTHROUGH */ 294 295 case 's': 296 ascii_conversion: 297 ASSERT(sr != NULL); 298 cvalpp = va_arg(ap, uint8_t **); 299 if (repc <= 1) 300 repc = 0; 301 if (mbc_marshal_get_ascii_string(&sr->request_storage, 302 mbc, cvalpp, repc) != 0) 303 return (-1); 304 break; 305 306 case 'U': /* Convert from unicode */ 307 unicode_translation: 308 ASSERT(sr != 0); 309 cvalpp = va_arg(ap, uint8_t **); 310 if (repc <= 1) 311 repc = 0; 312 if (mbc->chain_offset & 1) 313 mbc->chain_offset++; 314 if (mbc_marshal_get_unicode_string(&sr->request_storage, 315 mbc, cvalpp, repc) != 0) 316 return (-1); 317 break; 318 319 case 'Y': /* dos time to unix time tt/dd */ 320 lvalp = va_arg(ap, uint32_t *); 321 while (repc-- > 0) { 322 short d, t; 323 324 if (mbc_marshal_get_short(mbc, 325 (uint16_t *)&t) != 0) 326 return (-1); 327 if (mbc_marshal_get_short(mbc, 328 (uint16_t *)&d) != 0) 329 return (-1); 330 *lvalp++ = smb_time_dos_to_unix(d, t); 331 } 332 break; 333 334 case 'y': /* dos time to unix time dd/tt */ 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 *)&d) != 0) 341 return (-1); 342 if (mbc_marshal_get_short(mbc, 343 (uint16_t *)&t) != 0) 344 return (-1); 345 *lvalp++ = smb_time_dos_to_unix(d, t); 346 } 347 break; 348 349 case ',': 350 if (unicode) 351 repc *= 2; 352 /* FALLTHROUGH */ 353 354 case '.': 355 if (mbc_marshal_get_skip(mbc, repc) != 0) 356 return (-1); 357 break; 358 359 default: 360 ASSERT(0); 361 return (-1); 362 } 363 } 364 return (0); 365 } 366 367 /* 368 * smb_mbc_decodef 369 * 370 * This function reads the contents of the mbc chain passed in under the 371 * control of the format fmt. 372 * 373 * (for a description of the format string see smb_mbc_vencodef()). 374 */ 375 int 376 smb_mbc_decodef(mbuf_chain_t *mbc, char *fmt, ...) 377 { 378 int xx; 379 va_list ap; 380 381 va_start(ap, fmt); 382 xx = smb_mbc_vdecodef(mbc, fmt, ap); 383 va_end(ap); 384 return (xx); 385 } 386 387 /* 388 * smb_mbc_peek 389 * 390 * This function reads the contents of the mbc passed in at the specified offset 391 * under the control of the format fmt. The offset of the chain passed in is not 392 * modified. 393 * 394 * (for a description of the format string see smb_mbc_vdecodef()). 395 */ 396 int 397 smb_mbc_peek(mbuf_chain_t *mbc, int offset, char *fmt, ...) 398 { 399 mbuf_chain_t tmp; 400 va_list ap; 401 int xx; 402 403 va_start(ap, fmt); 404 405 (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset); 406 xx = smb_mbc_vdecodef(&tmp, fmt, ap); 407 va_end(ap); 408 return (xx); 409 } 410 411 /* 412 * smb_mbc_vencodef 413 * 414 * This function builds a stream of bytes in the mbc chain passed in under the 415 * control of the list of arguments passed in. 416 * 417 * The format string provides a description of the parameters passed in as well 418 * as an action to be taken by smb_mbc_vencodef(). 419 * 420 * \b Restore the mbuf chain offset to its initial value. 421 * 422 * % Pointer to an SMB request structure (smb_request_t *). There 423 * should be only one of these in the string. If an sr in present 424 * it will be used to determine if unicode conversion should be 425 * applied to the strings. 426 * 427 * C Pointer to an mbuf chain. Copy that mbuf chain into the 428 * destination mbuf chain. 429 * 430 * D Pointer to a vardata_block structure. Copy the data described 431 * by that structure into the mbuf chain. The tag field is hard 432 * coded to '1'. 433 * 434 * M Write the SMB request signature ('SMBX') into the mbuf chain. 435 * 436 * T Pointer to a timestruc_t. Convert the content of the structure 437 * into NT time and store the result of the conversion in the 438 * mbuf chain. 439 * 440 * V Same as 'D' but the tag field is hard coded to '5'. 441 * 442 * b Byte. Store the byte or the nymber of bytes specified into the 443 * the mbuf chain. A format string like this "2b" would require 2 444 * bytes to be passed in. 445 * 446 * m Pointer to an mbuf. Copy the contents of the mbuf into the mbuf 447 * chain. 448 * 449 * c Pointer to a buffer. Copy the buffer into the mbuf chain. The 450 * size of the buffer is indicated by the number preceding 'c'. 451 * 452 * w Word (16bit value). Store the word or the number of words 453 * specified into the the mbuf chain. A format string like this 454 * "2w" would require 2 words to be passed in. 455 * 456 * l Long (32bit value). Store the long or the number of longs 457 * specified into the the mbuf chain. A format string like this 458 * "2l" would require 2 longs to be passed in. 459 * 460 * q Quad (64bit value). Store the quad or the number of quads 461 * specified into the the mbuf chain. A format string like this 462 * "2q" would require 2 quads to be passed in. 463 * 464 * L Pointer to a string. Store the string passed in into the mbuf 465 * chain preceded with a tag value of '2'. 466 * 467 * S Pointer to a string. Store the string passed in into the mbuf 468 * chain preceded with a tag value of '4'. Applied a unicode 469 * conversion is appropriate. 470 * 471 * A Same as 'S' 472 * 473 * P Pointer to a string. Store the string passed in into the mbuf 474 * chain preceded with a tag value of '5'. Applied a unicode 475 * conversion is appropriate. 476 * 477 * u Pointer to a string. Store the string passed in into the mbuf 478 * chain. Applied a unicode conversion is appropriate. 479 * 480 * s Pointer to a string. Store the string passed in into the mbuf 481 * chain. 482 * 483 * Y Date/Time. Store the Date/Time or the number of Date/Time(s) 484 * specified into the the mbuf chain. A format string like this 485 * "2Y" would require 2 Date/Time values. The Date/Time is 486 * converted to DOS before storing. 487 * 488 * y Same as 'Y'. The order of Date and Time is reversed. 489 * 490 * , Character. Store the character or number of character specified 491 * into the mbuf chain. A format string like this "2c" would 492 * require 2 characters to be passed in. A unicode conversion is 493 * applied if appropriate. 494 * 495 * . Same as '`' without unicode conversion. 496 * 497 * U Align the offset of the mbuf chain on a 16bit boundary. 498 */ 499 int 500 smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap) 501 { 502 uint8_t *cvalp; 503 timestruc_t *tvp; 504 smb_vdb_t *vdp; 505 smb_request_t *sr = NULL; 506 uint64_t llval; 507 int64_t nt_time; 508 uint32_t lval; 509 uint_t tag; 510 int unicode = 0; 511 int repc = 1; 512 uint16_t wval; 513 uint8_t cval; 514 uint8_t c; 515 516 while ((c = *fmt++) != 0) { 517 repc = 1; 518 519 if ('0' <= c && c <= '9') { 520 repc = 0; 521 do { 522 repc = repc * 10 + c - '0'; 523 c = *fmt++; 524 } while ('0' <= c && c <= '9'); 525 } else if (c == '#') { 526 repc = va_arg(ap, int); 527 c = *fmt++; 528 } 529 530 switch (c) { 531 case '%': 532 sr = va_arg(ap, struct smb_request *); 533 unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE; 534 break; 535 536 case 'C': /* Mbuf_chain */ 537 if (mbc_marshal_put_mbuf_chain(mbc, 538 va_arg(ap, mbuf_chain_t *)) != 0) 539 return (DECODE_NO_MORE_DATA); 540 break; 541 542 case 'D': 543 vdp = va_arg(ap, struct vardata_block *); 544 545 if (mbc_marshal_put_char(mbc, 1) != 0) 546 return (DECODE_NO_MORE_DATA); 547 if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0) 548 return (DECODE_NO_MORE_DATA); 549 if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0) 550 return (DECODE_NO_MORE_DATA); 551 break; 552 553 case 'M': 554 /* 0xFF S M B */ 555 if (mbc_marshal_put_long(mbc, 0x424D53FF)) 556 return (DECODE_NO_MORE_DATA); 557 break; 558 559 case 'T': 560 tvp = va_arg(ap, timestruc_t *); 561 nt_time = smb_time_unix_to_nt(tvp); 562 if (mbc_marshal_put_long_long(mbc, nt_time) != 0) 563 return (DECODE_NO_MORE_DATA); 564 break; 565 566 case 'V': 567 vdp = va_arg(ap, struct vardata_block *); 568 569 if (mbc_marshal_put_char(mbc, 5) != 0) 570 return (DECODE_NO_MORE_DATA); 571 if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0) 572 return (DECODE_NO_MORE_DATA); 573 if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0) 574 return (DECODE_NO_MORE_DATA); 575 break; 576 577 case 'b': 578 while (repc-- > 0) { 579 cval = va_arg(ap, int); 580 if (mbc_marshal_put_char(mbc, cval) != 0) 581 return (DECODE_NO_MORE_DATA); 582 } 583 break; 584 585 case 'm': /* struct_mbuf */ 586 if (mbc_marshal_put_mbufs(mbc, 587 va_arg(ap, mbuf_t *)) != 0) 588 return (DECODE_NO_MORE_DATA); 589 break; 590 591 case 'c': 592 cvalp = va_arg(ap, uint8_t *); 593 while (repc-- > 0) { 594 if (mbc_marshal_put_char(mbc, 595 *cvalp++) != 0) 596 return (DECODE_NO_MORE_DATA); 597 } 598 break; 599 600 case 'w': 601 while (repc-- > 0) { 602 wval = va_arg(ap, int); 603 if (mbc_marshal_put_short(mbc, wval) != 0) 604 return (DECODE_NO_MORE_DATA); 605 } 606 break; 607 608 case 'l': 609 while (repc-- > 0) { 610 lval = va_arg(ap, uint32_t); 611 if (mbc_marshal_put_long(mbc, lval) != 0) 612 return (DECODE_NO_MORE_DATA); 613 } 614 break; 615 616 case 'q': 617 while (repc-- > 0) { 618 llval = va_arg(ap, uint64_t); 619 if (mbc_marshal_put_long_long(mbc, llval) != 0) 620 return (DECODE_NO_MORE_DATA); 621 } 622 break; 623 624 625 case 'L': 626 tag = 2; 627 goto ascii_conversion; 628 629 case 'S': 630 case 'A': 631 tag = 4; 632 goto tagged_str; 633 634 case 'P': 635 tag = 3; 636 goto tagged_str; 637 638 tagged_str: 639 if (mbc_marshal_put_char(mbc, tag) != 0) 640 return (DECODE_NO_MORE_DATA); 641 /* FALLTHROUGH */ 642 643 case 'u': /* Convert from unicode if flags are set */ 644 if (unicode) 645 goto unicode_translation; 646 /* FALLTHROUGH */ 647 648 case 's': /* ASCII/multibyte string */ 649 ascii_conversion: cvalp = va_arg(ap, uint8_t *); 650 if (mbc_marshal_put_ascii_string(mbc, 651 (char *)cvalp, repc) != 0) 652 return (DECODE_NO_MORE_DATA); 653 break; 654 655 case 'Y': /* int32_t, encode dos date/time */ 656 while (repc-- > 0) { 657 uint16_t d, t; 658 659 lval = va_arg(ap, uint32_t); 660 smb_time_unix_to_dos(lval, 661 (short *)&d, (short *)&t); 662 if (mbc_marshal_put_short(mbc, t) != 0) 663 return (DECODE_NO_MORE_DATA); 664 if (mbc_marshal_put_short(mbc, d) != 0) 665 return (DECODE_NO_MORE_DATA); 666 } 667 break; 668 669 case 'y': /* int32_t, encode dos date/time */ 670 while (repc-- > 0) { 671 uint16_t d, t; 672 673 lval = va_arg(ap, uint32_t); 674 smb_time_unix_to_dos(lval, 675 (short *)&d, (short *)&t); 676 if (mbc_marshal_put_short(mbc, d) != 0) 677 return (DECODE_NO_MORE_DATA); 678 if (mbc_marshal_put_short(mbc, t) != 0) 679 return (DECODE_NO_MORE_DATA); 680 } 681 break; 682 683 case ',': 684 if (unicode) 685 repc *= 2; 686 /* FALLTHROUGH */ 687 688 case '.': 689 while (repc-- > 0) 690 if (mbc_marshal_put_char(mbc, 0) != 0) 691 return (DECODE_NO_MORE_DATA); 692 break; 693 694 case 'U': /* Convert to unicode, align to word boundary */ 695 unicode_translation: 696 if (mbc->chain_offset & 1) 697 mbc->chain_offset++; 698 cvalp = va_arg(ap, uint8_t *); 699 if (mbc_marshal_put_unicode_string(mbc, 700 (char *)cvalp, repc) != 0) 701 return (DECODE_NO_MORE_DATA); 702 break; 703 704 default: 705 ASSERT(0); 706 return (-1); 707 } 708 } 709 return (0); 710 } 711 712 /* 713 * smb_mbc_encodef 714 * 715 * This function builds a stream of bytes in the mbc chain passed in under the 716 * control of the format fmt. 717 * 718 * (for a description of the format string see smb_mbc_vencodef()). 719 */ 720 int 721 smb_mbc_encodef(mbuf_chain_t *mbc, char *fmt, ...) 722 { 723 int rc; 724 va_list ap; 725 726 va_start(ap, fmt); 727 rc = smb_mbc_vencodef(mbc, fmt, ap); 728 va_end(ap); 729 return (rc); 730 } 731 732 /* 733 * smb_mbc_poke 734 * 735 * This function writes a stream of bytes in the mbc passed in at the specified 736 * offset under the control of the format fmt. The offset of the chain passed in 737 * is not modified. 738 * 739 * (for a description of the format string see smb_mbc_vencodef()). 740 */ 741 int 742 smb_mbc_poke(mbuf_chain_t *mbc, int offset, char *fmt, ...) 743 { 744 int xx; 745 mbuf_chain_t tmp; 746 va_list ap; 747 748 (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset); 749 va_start(ap, fmt); 750 xx = smb_mbc_vencodef(&tmp, fmt, ap); 751 va_end(ap); 752 return (xx); 753 } 754 755 /* 756 * Put data into mbuf chain allocating as needed. 757 * Adds room to end of mbuf chain if needed. 758 */ 759 static int 760 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed) 761 { 762 mbuf_t *m; 763 mbuf_t *l; 764 int32_t bytes_available; 765 766 bytes_needed += mbc->chain_offset; 767 if (bytes_needed > mbc->max_bytes) 768 return (EMSGSIZE); 769 770 if ((m = mbc->chain) == 0) { 771 MGET(m, M_WAIT, MT_DATA); 772 m->m_len = 0; 773 if (mbc->max_bytes > MLEN) 774 MCLGET(m, M_WAIT); 775 mbc->chain = m; 776 /* xxxx */ 777 /* ^ */ 778 } 779 780 /* ---- ----- --xx ---xxx */ 781 /* ^ */ 782 783 l = 0; 784 while ((m != 0) && (bytes_needed >= m->m_len)) { 785 l = m; 786 bytes_needed -= m->m_len; 787 m = m->m_next; 788 } 789 790 if ((bytes_needed == 0) || (m != 0)) { 791 /* We have enough room already */ 792 return (0); 793 } 794 795 /* ---- ----- --xx ---xxx */ 796 /* ^ */ 797 /* Back up to start of last mbuf */ 798 m = l; 799 bytes_needed += m->m_len; 800 801 /* ---- ----- --xx ---xxx */ 802 /* ^ */ 803 804 bytes_available = (m->m_flags & M_EXT) ? 805 m->m_ext.ext_size : MLEN; 806 807 /* ---- ----- --xx ---xxx */ 808 /* ^ */ 809 while ((bytes_needed != 0) && (bytes_needed > bytes_available)) { 810 m->m_len = bytes_available; 811 bytes_needed -= m->m_len; 812 /* ---- ----- --xx ------ */ 813 /* ^ */ 814 815 MGET(m->m_next, M_WAIT, MT_DATA); 816 m = m->m_next; 817 m->m_len = 0; 818 if (bytes_needed > MLEN) 819 MCLGET(m, M_WAIT); 820 821 bytes_available = (m->m_flags & M_EXT) ? 822 m->m_ext.ext_size : MLEN; 823 824 /* ---- ----- --xx ------ xxxx */ 825 /* ^ */ 826 } 827 828 /* ---- ----- --xx ------ xxxx */ 829 /* ^ */ 830 /* Expand last tail as needed */ 831 if (m->m_len <= bytes_needed) { 832 m->m_len = bytes_needed; 833 /* ---- ----- --xx ------ --xx */ 834 /* ^ */ 835 } 836 837 return (0); 838 } 839 840 static void 841 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data) 842 { 843 mbuf_t *m = mbc->chain; 844 int32_t cur_offset = mbc->chain_offset; 845 846 /* 847 * Scan forward looking for the last data currently in chain. 848 */ 849 while (cur_offset >= m->m_len) { 850 cur_offset -= m->m_len; 851 m = m->m_next; 852 } 853 ((char *)m->m_data)[cur_offset] = data; 854 mbc->chain_offset++; 855 } 856 857 static int 858 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data) 859 { 860 if (mbc_marshal_make_room(mbc, sizeof (char)) != 0) 861 return (DECODE_NO_MORE_DATA); 862 mbc_marshal_store_byte(mbc, data); 863 return (0); 864 } 865 866 static int 867 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data) 868 { 869 if (mbc_marshal_make_room(mbc, sizeof (short))) 870 return (DECODE_NO_MORE_DATA); 871 mbc_marshal_store_byte(mbc, data); 872 mbc_marshal_store_byte(mbc, data >> 8); 873 return (0); 874 } 875 876 static int 877 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data) 878 { 879 if (mbc_marshal_make_room(mbc, sizeof (int32_t))) 880 return (DECODE_NO_MORE_DATA); 881 mbc_marshal_store_byte(mbc, data); 882 mbc_marshal_store_byte(mbc, data >> 8); 883 mbc_marshal_store_byte(mbc, data >> 16); 884 mbc_marshal_store_byte(mbc, data >> 24); 885 return (0); 886 } 887 888 static int 889 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data) 890 { 891 if (mbc_marshal_make_room(mbc, sizeof (int64_t))) 892 return (DECODE_NO_MORE_DATA); 893 894 mbc_marshal_store_byte(mbc, data); 895 mbc_marshal_store_byte(mbc, data >> 8); 896 mbc_marshal_store_byte(mbc, data >> 16); 897 mbc_marshal_store_byte(mbc, data >> 24); 898 mbc_marshal_store_byte(mbc, data >> 32); 899 mbc_marshal_store_byte(mbc, data >> 40); 900 mbc_marshal_store_byte(mbc, data >> 48); 901 mbc_marshal_store_byte(mbc, data >> 56); 902 return (0); 903 } 904 905 /* 906 * When need to convert from UTF-8 (internal format) to a single 907 * byte string (external format ) when marshalling a string. 908 */ 909 static int 910 mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc) 911 { 912 mts_wchar_t wide_char; 913 int nbytes; 914 int length; 915 916 if ((length = mts_sbequiv_strlen(mbs)) == -1) 917 return (DECODE_NO_MORE_DATA); 918 919 length += sizeof (char); 920 921 if ((repc > 1) && (repc < length)) 922 length = repc; 923 if (mbc_marshal_make_room(mbc, length)) 924 return (DECODE_NO_MORE_DATA); 925 926 while (*mbs) { 927 /* 928 * We should restore oem chars here. 929 */ 930 nbytes = mts_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX); 931 if (nbytes == -1) 932 return (DECODE_NO_MORE_DATA); 933 934 mbc_marshal_store_byte(mbc, (uint8_t)wide_char); 935 936 if (wide_char & 0xFF00) 937 mbc_marshal_store_byte(mbc, wide_char >> 8); 938 939 mbs += nbytes; 940 } 941 942 mbc_marshal_store_byte(mbc, 0); 943 return (0); 944 } 945 946 static int 947 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc) 948 { 949 mts_wchar_t wchar; 950 int consumed; 951 int length; 952 953 if ((length = mts_wcequiv_strlen(ascii)) == -1) 954 return (DECODE_NO_MORE_DATA); 955 956 length += sizeof (mts_wchar_t); 957 958 if ((repc > 1) && (repc < length)) 959 length = repc; 960 961 if (mbc_marshal_make_room(mbc, length)) 962 return (DECODE_NO_MORE_DATA); 963 while (length > 0) { 964 consumed = mts_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX); 965 if (consumed == -1) 966 break; /* Invalid sequence */ 967 /* 968 * Note that consumed will be 0 when the null terminator 969 * is encountered and ascii will not be advanced beyond 970 * that point. Length will continue to be decremented so 971 * we won't get stuck here. 972 */ 973 ascii += consumed; 974 mbc_marshal_store_byte(mbc, wchar); 975 mbc_marshal_store_byte(mbc, wchar >> 8); 976 length -= sizeof (mts_wchar_t); 977 } 978 return (0); 979 } 980 981 static int 982 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio) 983 { 984 mbuf_t **t; 985 mbuf_t *m = NULL; 986 struct iovec *iov = uio->uio_iov; 987 int32_t i, iov_cnt = uio->uio_iovcnt; 988 989 iov = uio->uio_iov; 990 t = &mbc->chain; 991 for (i = 0; i < iov_cnt; i++) { 992 MGET(m, M_WAIT, MT_DATA); 993 m->m_ext.ext_buf = iov->iov_base; 994 m->m_ext.ext_ref = smb_noop; 995 m->m_data = m->m_ext.ext_buf; 996 m->m_flags |= M_EXT; 997 m->m_len = m->m_ext.ext_size = iov->iov_len; 998 mbc->max_bytes += m->m_len; 999 m->m_next = 0; 1000 *t = m; 1001 t = &m->m_next; 1002 iov++; 1003 } 1004 return (0); 1005 } 1006 1007 static int 1008 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m) 1009 { 1010 mbuf_t *mt; 1011 mbuf_t **t; 1012 int bytes; 1013 1014 if (m != NULL) { 1015 mt = m; 1016 bytes = mt->m_len; 1017 while (mt->m_next != 0) { 1018 mt = mt->m_next; 1019 bytes += mt->m_len; 1020 } 1021 if (bytes != 0) { 1022 t = &mbc->chain; 1023 while (*t != 0) { 1024 bytes += (*t)->m_len; 1025 t = &(*t)->m_next; 1026 } 1027 *t = m; 1028 mbc->chain_offset = bytes; 1029 } else { 1030 m_freem(m); 1031 } 1032 } 1033 return (0); 1034 } 1035 1036 static int 1037 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc) 1038 { 1039 if (nmbc->chain != 0) { 1040 if (mbc_marshal_put_mbufs(mbc, nmbc->chain)) 1041 return (DECODE_NO_MORE_DATA); 1042 MBC_SETUP(nmbc, nmbc->max_bytes); 1043 } 1044 return (0); 1045 } 1046 1047 static uint8_t 1048 mbc_marshal_fetch_byte(mbuf_chain_t *mbc) 1049 { 1050 uint8_t data; 1051 mbuf_t *m = mbc->chain; 1052 int32_t offset = mbc->chain_offset; 1053 1054 while (offset >= m->m_len) { 1055 offset -= m->m_len; 1056 m = m->m_next; 1057 } 1058 data = ((uint8_t *)m->m_data)[offset]; 1059 mbc->chain_offset++; 1060 return (data); 1061 } 1062 1063 static int 1064 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data) 1065 { 1066 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) { 1067 /* Data will never be available */ 1068 return (DECODE_NO_MORE_DATA); 1069 } 1070 *data = mbc_marshal_fetch_byte(mbc); 1071 return (0); 1072 } 1073 1074 static int 1075 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data) 1076 { 1077 uint16_t tmp; 1078 mbuf_t *m = mbc->chain; 1079 int32_t offset = mbc->chain_offset; 1080 1081 if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) { 1082 /* Data will never be available */ 1083 return (DECODE_NO_MORE_DATA); 1084 } 1085 1086 while (offset >= m->m_len) { 1087 offset -= m->m_len; 1088 m = m->m_next; 1089 } 1090 if ((m->m_len - offset) >= sizeof (short)) { 1091 *data = LE_IN16(m->m_data + offset); 1092 mbc->chain_offset += sizeof (short); 1093 } else { 1094 tmp = (uint16_t)mbc_marshal_fetch_byte(mbc); 1095 tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8; 1096 *data = tmp; 1097 } 1098 return (0); 1099 } 1100 1101 static int 1102 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data) 1103 { 1104 uint32_t tmp; 1105 mbuf_t *m = mbc->chain; 1106 int32_t offset = mbc->chain_offset; 1107 1108 if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) { 1109 /* Data will never be available */ 1110 return (DECODE_NO_MORE_DATA); 1111 } 1112 while (offset >= m->m_len) { 1113 offset -= m->m_len; 1114 m = m->m_next; 1115 } 1116 if ((m->m_len - offset) >= sizeof (int32_t)) { 1117 *data = LE_IN32(m->m_data + offset); 1118 mbc->chain_offset += sizeof (int32_t); 1119 } else { 1120 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc); 1121 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8; 1122 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16; 1123 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24; 1124 *data = tmp; 1125 } 1126 return (0); 1127 } 1128 1129 static uint64_t 1130 qswap(uint64_t ll) 1131 { 1132 uint64_t v; 1133 1134 v = ll >> 32; 1135 v |= ll << 32; 1136 1137 return (v); 1138 } 1139 1140 static int 1141 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data) 1142 { 1143 uint64_t tmp; 1144 mbuf_t *m = mbc->chain; 1145 int32_t offset = mbc->chain_offset; 1146 1147 if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) { 1148 /* Data will never be available */ 1149 return (DECODE_NO_MORE_DATA); 1150 } 1151 while (offset >= m->m_len) { 1152 offset -= m->m_len; 1153 m = m->m_next; 1154 } 1155 1156 if ((m->m_len - offset) >= sizeof (int64_t)) { 1157 *data = qswap(LE_IN64(m->m_data + offset)); 1158 mbc->chain_offset += sizeof (int64_t); 1159 } else { 1160 tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32; 1161 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40; 1162 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48; 1163 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56; 1164 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc); 1165 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8; 1166 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16; 1167 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24; 1168 1169 *(uint64_t *)data = tmp; 1170 } 1171 return (0); 1172 } 1173 1174 static int 1175 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data) 1176 { 1177 uint64_t tmp; 1178 mbuf_t *m = mbc->chain; 1179 int32_t offset = mbc->chain_offset; 1180 1181 if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) { 1182 /* Data will never be available */ 1183 return (DECODE_NO_MORE_DATA); 1184 } 1185 while (offset >= m->m_len) { 1186 offset -= m->m_len; 1187 m = m->m_next; 1188 } 1189 if ((m->m_len - offset) >= sizeof (int64_t)) { 1190 *data = LE_IN64(m->m_data + offset); 1191 mbc->chain_offset += sizeof (int64_t); 1192 } else { 1193 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc); 1194 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8; 1195 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16; 1196 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24; 1197 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32; 1198 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40; 1199 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48; 1200 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56; 1201 *(uint64_t *)data = tmp; 1202 } 1203 return (0); 1204 } 1205 1206 /* 1207 * mbc_marshal_get_ascii_string 1208 * 1209 * The ascii string in smb includes oem chars. Since the 1210 * system needs utf8 encodes unicode char, conversion is 1211 * required to convert the oem char to unicode and then 1212 * to encode the converted wchars to utf8 format. 1213 * Therefore, the **ascii returned will be in such format 1214 * instead of the real ASCII format. 1215 */ 1216 static int 1217 mbc_marshal_get_ascii_string( 1218 struct smb_malloc_list *ml, 1219 mbuf_chain_t *mbc, 1220 uint8_t **ascii, 1221 int max_ascii) 1222 { 1223 char *rcvbuf; 1224 char *ch; 1225 int max; 1226 int length = 0; 1227 1228 max = MALLOC_QUANTUM; 1229 rcvbuf = smbsr_malloc(ml, max); 1230 1231 if (max_ascii == 0) 1232 max_ascii = 0xffff; 1233 1234 ch = rcvbuf; 1235 for (;;) { 1236 while (length < max) { 1237 if (max_ascii-- <= 0) { 1238 *ch++ = 0; 1239 goto multibyte_encode; 1240 } 1241 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) { 1242 /* Data will never be available */ 1243 return (DECODE_NO_MORE_DATA); 1244 } 1245 if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0) 1246 goto multibyte_encode; 1247 length++; 1248 } 1249 max += MALLOC_QUANTUM; 1250 rcvbuf = smbsr_realloc(rcvbuf, max); 1251 ch = rcvbuf + length; 1252 } 1253 1254 multibyte_encode: 1255 /* 1256 * UTF-8 encode the string for internal system use. 1257 */ 1258 length = strlen(rcvbuf) + 1; 1259 *ascii = smbsr_malloc(ml, length * MTS_MB_CHAR_MAX); 1260 return (mbc_marshal_cstou8("CP850", (char *)*ascii, 1261 (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length)); 1262 } 1263 1264 static int 1265 mbc_marshal_get_unicode_string(struct smb_malloc_list *ml, 1266 mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode) 1267 { 1268 int max; 1269 uint16_t wchar; 1270 char *ch; 1271 int emitted; 1272 int length = 0; 1273 1274 if (max_unicode == 0) 1275 max_unicode = 0xffff; 1276 1277 max = MALLOC_QUANTUM; 1278 *ascii = smbsr_malloc(ml, max); 1279 1280 ch = (char *)*ascii; 1281 for (;;) { 1282 while ((length + MTS_MB_CHAR_MAX) < max) { 1283 if (max_unicode <= 0) 1284 goto done; 1285 max_unicode -= 2; 1286 1287 if (mbc_marshal_get_short(mbc, &wchar) != 0) 1288 return (DECODE_NO_MORE_DATA); 1289 1290 if (wchar == 0) goto done; 1291 1292 emitted = mts_wctomb(ch, wchar); 1293 length += emitted; 1294 ch += emitted; 1295 } 1296 max += MALLOC_QUANTUM; 1297 *ascii = smbsr_realloc(*ascii, max); 1298 ch = (char *)*ascii + length; 1299 } 1300 done: *ch = 0; 1301 return (0); 1302 } 1303 1304 static int /*ARGSUSED*/ 1305 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m) 1306 { 1307 if (MBC_ROOM_FOR(mbc, bytes) == 0) { 1308 /* Data will never be available */ 1309 return (DECODE_NO_MORE_DATA); 1310 } 1311 return (0); 1312 } 1313 1314 static int 1315 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc) 1316 { 1317 int rc; 1318 mbuf_t *m; 1319 1320 if (bytes == 0) { 1321 /* Get all the rest */ 1322 bytes = mbc->max_bytes - mbc->chain_offset; 1323 } 1324 1325 MBC_SETUP(nmbc, mbc->max_bytes); 1326 if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) { 1327 if (m) 1328 m_freem(m); 1329 return (rc); 1330 } 1331 nmbc->chain = m; 1332 while (m != 0) { 1333 bytes += m->m_len; 1334 m = m->m_next; 1335 } 1336 nmbc->max_bytes = bytes; 1337 return (0); 1338 } 1339 1340 static int 1341 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio) 1342 { 1343 int i, offset; 1344 int32_t bytes = uio->uio_resid; 1345 int32_t remainder; 1346 struct iovec *iov; 1347 mbuf_t *m; 1348 1349 /* 1350 * The residual count is tested because in the case of write requests 1351 * with no data (smbtorture RAW-WRITE test will generate that type of 1352 * request) this function is called with a residual count of zero 1353 * bytes. 1354 */ 1355 if (bytes) { 1356 iov = uio->uio_iov; 1357 uio->uio_segflg = UIO_SYSSPACE; 1358 1359 if (MBC_ROOM_FOR(mbc, bytes) == 0) { 1360 /* Data will never be available */ 1361 return (DECODE_NO_MORE_DATA); 1362 } 1363 1364 m = mbc->chain; 1365 offset = mbc->chain_offset; 1366 while (offset >= m->m_len) { 1367 offset -= m->m_len; 1368 m = m->m_next; 1369 ASSERT((offset == 0) || (offset && m)); 1370 } 1371 1372 for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) { 1373 iov[i].iov_base = &m->m_data[offset]; 1374 remainder = m->m_len - offset; 1375 if (remainder >= bytes) { 1376 iov[i].iov_len = bytes; 1377 mbc->chain_offset += bytes; 1378 break; 1379 } 1380 iov[i].iov_len = remainder; 1381 mbc->chain_offset += remainder; 1382 bytes -= remainder; 1383 m = m->m_next; 1384 offset = 0; 1385 } 1386 if (i == uio->uio_iovcnt) { 1387 return (DECODE_NO_MORE_DATA); 1388 } 1389 uio->uio_iovcnt = i; 1390 } 1391 return (0); 1392 } 1393 1394 static int 1395 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip) 1396 { 1397 if (MBC_ROOM_FOR(mbc, skip) == 0) 1398 return (DECODE_NO_MORE_DATA); 1399 mbc->chain_offset += skip; 1400 return (0); 1401 } 1402 1403 /* 1404 * Converts oem string to UTF-8 string with an output string of max 1405 * maxconv bytes. The string may be truncated or not null-terminated if 1406 * there is not enough room. 1407 * 1408 * returns -1, cnt (partial conversion) or 0 (success) 1409 */ 1410 1411 static int 1412 mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv, 1413 char *inbuf, size_t srcbytes) 1414 { 1415 kiconv_t t2u; 1416 size_t inlen = srcbytes; 1417 size_t outlen = maxconv; 1418 int err = 0; 1419 size_t rc; 1420 1421 if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1) 1422 return (-1); 1423 1424 rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err); 1425 (void) kiconv_close(t2u); 1426 return ((int)rc); 1427 } 1428