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