Print this page
NEX-19025 CIFS gets confused with filenames containing enhanced Unicode
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
and: (fix build, check-rtime)
NEX-2460 libfksmbd should not link with libsmb
SMB-56 extended security NTLMSSP, inbound

Split Close
Expand all
Collapse all
          --- old/usr/src/common/smbsrv/smb_msgbuf.c
          +++ new/usr/src/common/smbsrv/smb_msgbuf.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   *
  25      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       25 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  26   26   */
  27   27  
  28   28  /*
  29   29   * Msgbuf buffer management implementation. The smb_msgbuf interface is
  30   30   * typically used to encode or decode SMB data using sprintf/scanf
  31   31   * style operations. It contains special handling for the SMB header.
  32   32   * It can also be used for general purpose encoding and decoding.
  33   33   */
  34   34  
  35   35  #include <sys/types.h>
↓ open down ↓ 10 lines elided ↑ open up ↑
  46   46  #endif
  47   47  #include <smbsrv/string.h>
  48   48  #include <smbsrv/msgbuf.h>
  49   49  #include <smbsrv/smb.h>
  50   50  
  51   51  static int buf_decode(smb_msgbuf_t *, char *, va_list ap);
  52   52  static int buf_encode(smb_msgbuf_t *, char *, va_list ap);
  53   53  static void *smb_msgbuf_malloc(smb_msgbuf_t *, size_t);
  54   54  static int smb_msgbuf_chkerc(char *text, int erc);
  55   55  
       56 +static int msgbuf_get_oem_string(smb_msgbuf_t *, char **, int);
       57 +static int msgbuf_get_unicode_string(smb_msgbuf_t *, char **, int);
       58 +static int msgbuf_put_oem_string(smb_msgbuf_t *, char *, int);
       59 +static int msgbuf_put_unicode_string(smb_msgbuf_t *, char *, int);
       60 +
       61 +
  56   62  /*
  57   63   * Returns the offset or number of bytes used within the buffer.
  58   64   */
  59   65  size_t
  60   66  smb_msgbuf_used(smb_msgbuf_t *mb)
  61   67  {
  62   68          /*LINTED E_PTRDIFF_OVERFLOW*/
  63   69          return (mb->scan - mb->base);
  64   70  }
  65   71  
↓ open down ↓ 104 lines elided ↑ open up ↑
 170  176          }
 171  177  }
 172  178  
 173  179  
 174  180  /*
 175  181   * smb_msgbuf_decode
 176  182   *
 177  183   * Decode a smb_msgbuf buffer as indicated by the format string into
 178  184   * the variable arg list. This is similar to a scanf operation.
 179  185   *
 180      - * On success, returns the number of bytes encoded. Otherwise
      186 + * On success, returns the number of bytes decoded. Otherwise
 181  187   * returns a -ve error code.
 182  188   */
 183  189  int
 184  190  smb_msgbuf_decode(smb_msgbuf_t *mb, char *fmt, ...)
 185  191  {
 186  192          int rc;
 187  193          uint8_t *orig_scan;
 188  194          va_list ap;
 189  195  
 190  196          va_start(ap, fmt);
↓ open down ↓ 15 lines elided ↑ open up ↑
 206  212  /*
 207  213   * buf_decode
 208  214   *
 209  215   * Private decode function, where the real work of decoding the smb_msgbuf
 210  216   * is done. This function should only be called via smb_msgbuf_decode to
 211  217   * ensure correct behaviour and error handling.
 212  218   */
 213  219  static int
 214  220  buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
 215  221  {
 216      -        uint32_t ival;
 217  222          uint8_t c;
 218  223          uint8_t *bvalp;
 219  224          uint16_t *wvalp;
 220  225          uint32_t *lvalp;
 221  226          uint64_t *llvalp;
 222      -        char *cvalp;
 223  227          char **cvalpp;
 224      -        smb_wchar_t wchar;
 225  228          boolean_t repc_specified;
 226  229          int repc;
 227  230          int rc;
 228  231  
 229  232          while ((c = *fmt++) != 0) {
 230  233                  repc_specified = B_FALSE;
 231  234                  repc = 1;
 232  235  
 233  236                  if (c == ' ' || c == '\t')
 234  237                          continue;
↓ open down ↓ 82 lines elided ↑ open up ↑
 317  320                                  *llvalp++ = LE_IN64(mb->scan);
 318  321                                  mb->scan += sizeof (int64_t);
 319  322                          }
 320  323                          break;
 321  324  
 322  325                  case 'u': /* Convert from unicode if flags are set */
 323  326                          if (mb->flags & SMB_MSGBUF_UNICODE)
 324  327                                  goto unicode_translation;
 325  328                          /*FALLTHROUGH*/
 326  329  
 327      -                case 's': /* get string */
 328      -                        if (!repc_specified)
 329      -                                repc = strlen((const char *)mb->scan) + 1;
 330      -                        if (smb_msgbuf_has_space(mb, repc) == 0)
 331      -                                return (SMB_MSGBUF_UNDERFLOW);
 332      -                        if ((cvalp = smb_msgbuf_malloc(mb, repc * 2)) == 0)
 333      -                                return (SMB_MSGBUF_UNDERFLOW);
      330 +                case 's': /* get OEM string */
 334  331                          cvalpp = va_arg(ap, char **);
 335      -                        *cvalpp = cvalp;
 336      -                        /* Translate OEM to mbs */
 337      -                        while (repc > 0) {
 338      -                                wchar = *mb->scan++;
 339      -                                repc--;
 340      -                                if (wchar == 0)
 341      -                                        break;
 342      -                                ival = smb_wctomb(cvalp, wchar);
 343      -                                cvalp += ival;
 344      -                        }
 345      -                        *cvalp = '\0';
 346      -                        if (repc > 0)
 347      -                                mb->scan += repc;
      332 +                        if (!repc_specified)
      333 +                                repc = 0;
      334 +                        rc = msgbuf_get_oem_string(mb, cvalpp, repc);
      335 +                        if (rc != 0)
      336 +                                return (rc);
 348  337                          break;
 349  338  
 350      -                case 'U': /* get unicode string */
      339 +                case 'U': /* get UTF-16 string */
 351  340  unicode_translation:
 352      -                        /*
 353      -                         * Unicode strings are always word aligned.
 354      -                         * The malloc'd area is larger than the
 355      -                         * original string because the UTF-8 chars
 356      -                         * may be longer than the wide-chars.
 357      -                         */
 358      -                        smb_msgbuf_word_align(mb);
 359      -                        if (!repc_specified) {
 360      -                                /*
 361      -                                 * Count bytes, including the null.
 362      -                                 */
 363      -                                uint8_t *tmp_scan = mb->scan;
 364      -                                repc = 2; /* the null */
 365      -                                while ((wchar = LE_IN16(tmp_scan)) != 0) {
 366      -                                        tmp_scan += 2;
 367      -                                        repc += 2;
 368      -                                }
 369      -                        }
 370      -                        if (smb_msgbuf_has_space(mb, repc) == 0)
 371      -                                return (SMB_MSGBUF_UNDERFLOW);
 372      -                        /*
 373      -                         * Get space for translated string
 374      -                         * Allocates worst-case size.
 375      -                         */
 376      -                        if ((cvalp = smb_msgbuf_malloc(mb, repc * 2)) == 0)
 377      -                                return (SMB_MSGBUF_UNDERFLOW);
 378  341                          cvalpp = va_arg(ap, char **);
 379      -                        *cvalpp = cvalp;
 380      -                        /*
 381      -                         * Translate unicode to mbs, stopping after
 382      -                         * null or repc limit.
 383      -                         */
 384      -                        while (repc >= 2) {
 385      -                                wchar = LE_IN16(mb->scan);
 386      -                                mb->scan += 2;
 387      -                                repc -= 2;
 388      -                                if (wchar == 0)
 389      -                                        break;
 390      -                                ival = smb_wctomb(cvalp, wchar);
 391      -                                cvalp += ival;
 392      -                        }
 393      -                        *cvalp = '\0';
 394      -                        if (repc > 0)
 395      -                                mb->scan += repc;
      342 +                        if (!repc_specified)
      343 +                                repc = 0;
      344 +                        rc = msgbuf_get_unicode_string(mb, cvalpp, repc);
      345 +                        if (rc != 0)
      346 +                                return (rc);
 396  347                          break;
 397  348  
 398  349                  case 'M':
 399  350                          if (smb_msgbuf_has_space(mb, 4) == 0)
 400  351                                  return (SMB_MSGBUF_UNDERFLOW);
 401  352  
 402  353                          if (mb->scan[0] != 0xFF ||
 403  354                              mb->scan[1] != 'S' ||
 404  355                              mb->scan[2] != 'M' ||
 405  356                              mb->scan[3] != 'B') {
↓ open down ↓ 3 lines elided ↑ open up ↑
 409  360                          break;
 410  361  
 411  362                  default:
 412  363                          return (SMB_MSGBUF_INVALID_FORMAT);
 413  364                  }
 414  365          }
 415  366  
 416  367          return (SMB_MSGBUF_SUCCESS);
 417  368  }
 418  369  
      370 +/*
      371 + * msgbuf_get_oem_string
      372 + *
      373 + * Decode an OEM string, returning its UTF-8 form in strpp,
      374 + * allocated using smb_msgbuf_malloc (automatically freed).
      375 + * If max_bytes != 0, consume at most max_bytes of the mb.
      376 + * See also: mbc_marshal_get_oem_string
      377 + */
      378 +static int
      379 +msgbuf_get_oem_string(smb_msgbuf_t *mb, char **strpp, int max_bytes)
      380 +{
      381 +        char            *mbs;
      382 +        uint8_t         *oembuf = NULL;
      383 +        int             oemlen;         // len of OEM string, w/o null
      384 +        int             datalen;        // OtW data len
      385 +        int             mbsmax;         // max len of ret str
      386 +        int             rlen;
 419  387  
      388 +        if (max_bytes == 0)
      389 +                max_bytes = 0xffff;
      390 +
      391 +        /*
      392 +         * Determine the OtW data length and OEM string length
      393 +         * Note: oemlen is the string length (w/o null) and
      394 +         * datalen is how much we move mb->scan
      395 +         */
      396 +        datalen = 0;
      397 +        oemlen = 0;
      398 +        for (;;) {
      399 +                if (datalen >= max_bytes)
      400 +                        break;
      401 +                /* in-line smb_msgbuf_has_space */
      402 +                if ((mb->scan + datalen) >= mb->end)
      403 +                        return (SMB_MSGBUF_UNDERFLOW);
      404 +                datalen++;
      405 +                if (mb->scan[datalen - 1] == 0)
      406 +                        break;
      407 +                oemlen++;
      408 +        }
      409 +
      410 +        /*
      411 +         * Get datalen bytes into a temp buffer
      412 +         * sized with room to add a null.
      413 +         * Free oembuf in smb_msgbuf_term
      414 +         */
      415 +        oembuf = smb_msgbuf_malloc(mb, datalen + 1);
      416 +        if (oembuf == NULL)
      417 +                return (SMB_MSGBUF_UNDERFLOW);
      418 +        bcopy(mb->scan, oembuf, datalen);
      419 +        mb->scan += datalen;
      420 +        oembuf[oemlen] = '\0';
      421 +
      422 +        /*
      423 +         * Get the buffer we'll return and convert to UTF-8.
      424 +         * May take as much as double the space.
      425 +         */
      426 +        mbsmax = oemlen * 2;
      427 +        mbs = smb_msgbuf_malloc(mb, mbsmax + 1);
      428 +        if (mbs == NULL)
      429 +                return (SMB_MSGBUF_UNDERFLOW);
      430 +        rlen = smb_oemtombs(mbs, oembuf, mbsmax);
      431 +        if (rlen < 0)
      432 +                return (SMB_MSGBUF_UNDERFLOW);
      433 +        if (rlen > mbsmax)
      434 +                rlen = mbsmax;
      435 +        mbs[rlen] = '\0';
      436 +        *strpp = mbs;
      437 +        return (0);
      438 +}
      439 +
 420  440  /*
      441 + * msgbuf_get_unicode_string
      442 + *
      443 + * Decode a UTF-16 string, returning its UTF-8 form in strpp,
      444 + * allocated using smb_msgbuf_malloc (automatically freed).
      445 + * If max_bytes != 0, consume at most max_bytes of the mb.
      446 + * See also: mbc_marshal_get_unicode_string
      447 + */
      448 +static int
      449 +msgbuf_get_unicode_string(smb_msgbuf_t *mb, char **strpp, int max_bytes)
      450 +{
      451 +        char            *mbs;
      452 +        uint16_t        *wcsbuf = NULL;
      453 +        int             wcslen;         // wchar count
      454 +        int             datalen;        // OtW data len
      455 +        size_t          mbsmax;         // max len of ret str
      456 +        size_t          rlen;
      457 +
      458 +        if (max_bytes == 0)
      459 +                max_bytes = 0xffff;
      460 +
      461 +        /*
      462 +         * Unicode strings are always word aligned.
      463 +         */
      464 +        smb_msgbuf_word_align(mb);
      465 +
      466 +        /*
      467 +         * Determine the OtW data length and (WC) string length
      468 +         * Note: wcslen counts 16-bit wide_chars (w/o null),
      469 +         * and datalen is how much we move mb->scan
      470 +         */
      471 +        datalen = 0;
      472 +        wcslen = 0;
      473 +        for (;;) {
      474 +                if (datalen >= max_bytes)
      475 +                        break;
      476 +                /* in-line smb_msgbuf_has_space */
      477 +                if ((mb->scan + datalen) >= mb->end)
      478 +                        return (SMB_MSGBUF_UNDERFLOW);
      479 +                datalen += 2;
      480 +                if (mb->scan[datalen - 2] == 0 &&
      481 +                    mb->scan[datalen - 1] == 0)
      482 +                        break;
      483 +                wcslen++;
      484 +        }
      485 +
      486 +        /*
      487 +         * Get datalen bytes into a temp buffer
      488 +         * sized with room to add a (WC) null.
      489 +         * Note: wcsbuf has little-endian order
      490 +         */
      491 +        wcsbuf = smb_msgbuf_malloc(mb, datalen + 2);
      492 +        if (wcsbuf == NULL)
      493 +                return (SMB_MSGBUF_UNDERFLOW);
      494 +        bcopy(mb->scan, wcsbuf, datalen);
      495 +        mb->scan += datalen;
      496 +        wcsbuf[wcslen] = 0;
      497 +
      498 +        /*
      499 +         * Get the buffer we'll return and convert to UTF-8.
      500 +         * May take as much 4X number of wide chars.
      501 +         */
      502 +        mbsmax = wcslen * MTS_MB_CUR_MAX;
      503 +        mbs = smb_msgbuf_malloc(mb, mbsmax + 1);
      504 +        if (mbs == NULL)
      505 +                return (SMB_MSGBUF_UNDERFLOW);
      506 +        rlen = smb_wcstombs(mbs, wcsbuf, mbsmax);
      507 +        if (rlen == (size_t)-1)
      508 +                return (SMB_MSGBUF_UNDERFLOW);
      509 +        if (rlen > mbsmax)
      510 +                rlen = mbsmax;
      511 +        mbs[rlen] = '\0';
      512 +        *strpp = mbs;
      513 +        return (0);
      514 +}
      515 +
      516 +/*
 421  517   * smb_msgbuf_encode
 422  518   *
 423  519   * Encode a smb_msgbuf buffer as indicated by the format string using
 424  520   * the variable arg list. This is similar to a sprintf operation.
 425  521   *
 426  522   * On success, returns the number of bytes encoded. Otherwise
 427  523   * returns a -ve error code.
 428  524   */
 429  525  int
 430  526  smb_msgbuf_encode(smb_msgbuf_t *mb, char *fmt, ...)
↓ open down ↓ 28 lines elided ↑ open up ↑
 459  555  static int
 460  556  buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
 461  557  {
 462  558          uint8_t cval;
 463  559          uint16_t wval;
 464  560          uint32_t lval;
 465  561          uint64_t llval;
 466  562          uint8_t *bvalp;
 467  563          char *cvalp;
 468  564          uint8_t c;
 469      -        smb_wchar_t wchar;
 470      -        int count;
 471  565          boolean_t repc_specified;
 472  566          int repc;
 473  567          int rc;
 474  568  
 475  569          while ((c = *fmt++) != 0) {
 476  570                  repc_specified = B_FALSE;
 477  571                  repc = 1;
 478  572  
 479  573                  if (c == ' ' || c == '\t')
 480  574                          continue;
↓ open down ↓ 83 lines elided ↑ open up ↑
 564  658                                  LE_OUT64(mb->scan, llval);
 565  659                                  mb->scan += sizeof (uint64_t);
 566  660                          }
 567  661                          break;
 568  662  
 569  663                  case 'u': /* conditional unicode */
 570  664                          if (mb->flags & SMB_MSGBUF_UNICODE)
 571  665                                  goto unicode_translation;
 572  666                          /* FALLTHROUGH */
 573  667  
 574      -                case 's': /* put string */
      668 +                case 's': /* put OEM string */
 575  669                          cvalp = va_arg(ap, char *);
 576      -                        if (!repc_specified) {
 577      -                                repc = smb_sbequiv_strlen(cvalp);
 578      -                                if (repc == -1)
 579      -                                        return (SMB_MSGBUF_OVERFLOW);
 580      -                                if (!(mb->flags & SMB_MSGBUF_NOTERM))
 581      -                                        repc++;
 582      -                        }
 583      -                        if (smb_msgbuf_has_space(mb, repc) == 0)
 584      -                                return (SMB_MSGBUF_OVERFLOW);
 585      -                        while (repc > 0) {
 586      -                                count = smb_mbtowc(&wchar, cvalp,
 587      -                                    MTS_MB_CHAR_MAX);
 588      -                                if (count < 0)
 589      -                                        return (SMB_MSGBUF_DATA_ERROR);
 590      -                                cvalp += count;
 591      -                                if (wchar == 0)
 592      -                                        break;
 593      -                                *mb->scan++ = (uint8_t)wchar;
 594      -                                repc--;
 595      -                                if (wchar & 0xff00) {
 596      -                                        *mb->scan++ = wchar >> 8;
 597      -                                        repc--;
 598      -                                }
 599      -                        }
 600      -                        if (*cvalp == '\0' && repc > 0 &&
 601      -                            (mb->flags & SMB_MSGBUF_NOTERM) == 0) {
 602      -                                *mb->scan++ = 0;
 603      -                                repc--;
 604      -                        }
 605      -                        while (repc > 0) {
 606      -                                *mb->scan++ = 0;
 607      -                                repc--;
 608      -                        }
      670 +                        if (!repc_specified)
      671 +                                repc = 0;
      672 +                        rc = msgbuf_put_oem_string(mb, cvalp, repc);
      673 +                        if (rc != 0)
      674 +                                return (rc);
 609  675                          break;
 610  676  
 611      -                case 'U': /* put unicode string */
      677 +                case 'U': /* put UTF-16 string */
 612  678  unicode_translation:
 613      -                        /*
 614      -                         * Unicode strings are always word aligned.
 615      -                         */
 616      -                        smb_msgbuf_word_align(mb);
 617  679                          cvalp = va_arg(ap, char *);
 618      -                        if (!repc_specified) {
 619      -                                repc = smb_wcequiv_strlen(cvalp);
 620      -                                if (!(mb->flags & SMB_MSGBUF_NOTERM))
 621      -                                        repc += 2;
 622      -                        }
 623      -                        if (!smb_msgbuf_has_space(mb, repc))
 624      -                                return (SMB_MSGBUF_OVERFLOW);
 625      -                        while (repc >= 2) {
 626      -                                count = smb_mbtowc(&wchar, cvalp,
 627      -                                    MTS_MB_CHAR_MAX);
 628      -                                if (count < 0)
 629      -                                        return (SMB_MSGBUF_DATA_ERROR);
 630      -                                cvalp += count;
 631      -                                if (wchar == 0)
 632      -                                        break;
 633      -
 634      -                                LE_OUT16(mb->scan, wchar);
 635      -                                mb->scan += 2;
 636      -                                repc -= 2;
 637      -                        }
 638      -                        if (*cvalp == '\0' && repc >= 2 &&
 639      -                            (mb->flags & SMB_MSGBUF_NOTERM) == 0) {
 640      -                                LE_OUT16(mb->scan, 0);
 641      -                                mb->scan += 2;
 642      -                                repc -= 2;
 643      -                        }
 644      -                        while (repc > 0) {
 645      -                                *mb->scan++ = 0;
 646      -                                repc--;
 647      -                        }
      680 +                        if (!repc_specified)
      681 +                                repc = 0;
      682 +                        rc = msgbuf_put_unicode_string(mb, cvalp, repc);
      683 +                        if (rc != 0)
      684 +                                return (rc);
 648  685                          break;
 649  686  
 650  687                  case 'M':
 651  688                          if (smb_msgbuf_has_space(mb, 4) == 0)
 652  689                                  return (SMB_MSGBUF_OVERFLOW);
 653  690  
 654  691                          *mb->scan++ = 0xFF;
 655  692                          *mb->scan++ = 'S';
 656  693                          *mb->scan++ = 'M';
 657  694                          *mb->scan++ = 'B';
 658  695                          break;
 659  696  
 660  697                  default:
 661  698                          return (SMB_MSGBUF_INVALID_FORMAT);
 662  699                  }
 663  700          }
 664  701  
 665  702          return (SMB_MSGBUF_SUCCESS);
 666  703  }
 667  704  
      705 +/*
      706 + * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset.
      707 + * Also write a null unless the repc count limits the length we put.
      708 + * When (repc > 0) the length we marshal must be exactly repc, and
      709 + * truncate or pad the mb data as necessary.
      710 + * See also: mbc_marshal_put_oem_string
      711 + */
      712 +static int
      713 +msgbuf_put_oem_string(smb_msgbuf_t *mb, char *mbs, int repc)
      714 +{
      715 +        uint8_t         *oembuf = NULL;
      716 +        uint8_t         *s;
      717 +        int             oemlen;
      718 +        int             rlen;
 668  719  
      720 +        /*
      721 +         * Compute length of converted OEM string,
      722 +         * NOT including null terminator
      723 +         */
      724 +        if ((oemlen = smb_sbequiv_strlen(mbs)) == -1)
      725 +                return (SMB_MSGBUF_DATA_ERROR);
      726 +
      727 +        /*
      728 +         * If repc not specified, put whole string + NULL,
      729 +         * otherwise will truncate or pad as needed.
      730 +         */
      731 +        if (repc <= 0) {
      732 +                repc = oemlen;
      733 +                if ((mb->flags & SMB_MSGBUF_NOTERM) == 0)
      734 +                        repc += sizeof (char);
      735 +        }
      736 +        if (smb_msgbuf_has_space(mb, repc) == 0)
      737 +                return (SMB_MSGBUF_OVERFLOW);
      738 +
      739 +        /*
      740 +         * Convert into a temporary buffer
      741 +         * Free oembuf in smb_msgbuf_term.
      742 +         */
      743 +        oembuf = smb_msgbuf_malloc(mb, oemlen + 1);
      744 +        if (oembuf == NULL)
      745 +                return (SMB_MSGBUF_UNDERFLOW);
      746 +        rlen = smb_mbstooem(oembuf, mbs, oemlen);
      747 +        if (rlen < 0)
      748 +                return (SMB_MSGBUF_DATA_ERROR);
      749 +        if (rlen > oemlen)
      750 +                rlen = oemlen;
      751 +        oembuf[rlen] = '\0';
      752 +
      753 +        /*
      754 +         * Copy the converted string into the message,
      755 +         * truncated or paded as required.
      756 +         */
      757 +        s = oembuf;
      758 +        while (repc > 0) {
      759 +                *mb->scan++ = *s;
      760 +                if (*s != '\0')
      761 +                        s++;
      762 +                repc--;
      763 +        }
      764 +
      765 +        return (0);
      766 +}
      767 +
 669  768  /*
      769 + * Marshal a UTF-8 string (str) into mbc, converting to UTF-16.
      770 + * Also write a null unless the repc count limits the length.
      771 + * When (repc > 0) the length we marshal must be exactly repc,
      772 + * and truncate or pad the mb data as necessary.
      773 + * See also: mbc_marshal_put_unicode_string
      774 + */
      775 +static int
      776 +msgbuf_put_unicode_string(smb_msgbuf_t *mb, char *mbs, int repc)
      777 +{
      778 +        smb_wchar_t     *wcsbuf = NULL;
      779 +        smb_wchar_t     *wp;
      780 +        size_t          wcslen, wcsbytes;
      781 +        size_t          rlen;
      782 +
      783 +        /* align to word boundary */
      784 +        smb_msgbuf_word_align(mb);
      785 +
      786 +        /*
      787 +         * Compute length of converted UTF-16 string,
      788 +         * NOT including null terminator (in bytes).
      789 +         */
      790 +        wcsbytes = smb_wcequiv_strlen(mbs);
      791 +        if (wcsbytes == (size_t)-1)
      792 +                return (SMB_MSGBUF_DATA_ERROR);
      793 +
      794 +        /*
      795 +         * If repc not specified, put whole string + NULL,
      796 +         * otherwise will truncate or pad as needed.
      797 +         */
      798 +        if (repc <= 0) {
      799 +                repc = (int)wcsbytes;
      800 +                if ((mb->flags & SMB_MSGBUF_NOTERM) == 0)
      801 +                        repc += sizeof (smb_wchar_t);
      802 +        }
      803 +        if (smb_msgbuf_has_space(mb, repc) == 0)
      804 +                return (SMB_MSGBUF_OVERFLOW);
      805 +
      806 +        /*
      807 +         * Convert into a temporary buffer
      808 +         * Free wcsbuf in smb_msgbuf_term
      809 +         */
      810 +        wcslen = wcsbytes / 2;
      811 +        wcsbuf = smb_msgbuf_malloc(mb, wcsbytes + 2);
      812 +        if (wcsbuf == NULL)
      813 +                return (SMB_MSGBUF_UNDERFLOW);
      814 +        rlen = smb_mbstowcs(wcsbuf, mbs, wcslen);
      815 +        if (rlen == (size_t)-1)
      816 +                return (SMB_MSGBUF_DATA_ERROR);
      817 +        if (rlen > wcslen)
      818 +                rlen = wcslen;
      819 +        wcsbuf[rlen] = 0;
      820 +
      821 +        /*
      822 +         * Copy the converted string into the message,
      823 +         * truncated or paded as required.  Preserve
      824 +         * little-endian order while copying.
      825 +         */
      826 +        wp = wcsbuf;
      827 +        while (repc > 1) {
      828 +                smb_wchar_t wchar = LE_IN16(wp);
      829 +                LE_OUT16(mb->scan, wchar);
      830 +                mb->scan += 2;
      831 +                if (wchar != 0)
      832 +                        wp++;
      833 +                repc -= sizeof (smb_wchar_t);
      834 +        }
      835 +        if (repc > 0)
      836 +                *mb->scan++ = '\0';
      837 +
      838 +        return (0);
      839 +}
      840 +
      841 +/*
 670  842   * smb_msgbuf_malloc
 671  843   *
 672  844   * Allocate some memory for use with this smb_msgbuf. We increase the
 673  845   * requested size to hold the list pointer and return a pointer
 674  846   * to the area for use by the caller.
 675  847   */
 676  848  static void *
 677  849  smb_msgbuf_malloc(smb_msgbuf_t *mb, size_t size)
 678  850  {
 679  851          smb_msgbuf_mlist_t *item;
↓ open down ↓ 51 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX