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-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-4458 Incorrect directory listing response for non-UNICODE clients
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-4029 Hang listing directory with fksmbd
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3738 Should support SMB2_CAP_LARGE_MTU
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-3611 CLONE NEX-3550 Replace smb2_enable with max_protocol
Reviewed by: Yuri Pankov <Yuri.Pankov@nexenta.com>
NEX-2353 Codenomicon: SMB2 TC # 448950 - PANIC in SMB2.Compounded-commands...
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-56 extended security NTLMSSP, inbound
SMB-48 Panic with smbtorture raw.scan-eamax

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.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 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   *
  25      - * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
       25 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  26   26   */
  27   27  
  28   28  /*
  29   29   * SMB mbuf marshaling encode/decode.
  30   30   */
  31   31  
  32   32  #include <smbsrv/smb_kproto.h>
  33   33  
  34   34  
  35   35  #define MALLOC_QUANTUM  80
  36   36  
  37   37  #define DECODE_NO_ERROR         0
  38   38  #define DECODE_NO_MORE_DATA     1
  39   39  #define DECODE_ALLOCATION_ERROR 2
  40   40  #define DECODE_CONVERSION_ERROR 3
  41   41  
  42      -static int mbc_marshal_cstou8(char *, char *, size_t, char *, size_t);
  43   42  static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
  44   43  static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
  45   44  static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
  46   45  static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
  47   46  static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
  48   47  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);
       48 +static int mbc_marshal_put_oem_string(mbuf_chain_t *, char *, int);
  50   49  static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
  51   50  static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
  52   51  static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
  53   52  static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
  54   53  static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
  55   54  static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data);
  56   55  static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
  57   56  static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
  58   57  static uint64_t qswap(uint64_t ll);
  59   58  static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
  60   59  static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
  61      -static int mbc_marshal_get_ascii_string(smb_request_t *, mbuf_chain_t *,
  62      -    uint8_t **ascii, int);
       60 +static int mbc_marshal_get_oem_string(smb_request_t *, mbuf_chain_t *,
       61 +    char **, int);
  63   62  static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
  64      -    uint8_t **, int);
       63 +    char **, int);
  65   64  static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
  66   65  static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
  67   66  static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
  68   67  static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
  69   68  
  70   69  /*
  71   70   * smb_mbc_vdecodef
  72   71   *
  73   72   * This function reads the contents of the mbc chain passed in under the list
  74   73   * of arguments passed in.
↓ open down ↓ 70 lines elided ↑ open up ↑
 145  144   *      .       Skip the number of bytes indicated by the number preceding '.'.
 146  145   *
 147  146   *      ,       Same as '.' but take in account it is an unicode string.
 148  147   */
 149  148  int
 150  149  smb_mbc_vdecodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
 151  150  {
 152  151          uint8_t         c;
 153  152          uint8_t         cval;
 154  153          uint8_t         *cvalp;
 155      -        uint8_t         **cvalpp;
      154 +        char            **charpp;
 156  155          uint16_t        wval;
 157  156          uint16_t        *wvalp;
 158  157          uint32_t        *lvalp;
 159  158          uint64_t        *llvalp;
 160  159          smb_vdb_t       *vdp;
 161  160          smb_request_t   *sr = NULL;
 162  161          uint32_t        lval;
 163  162          int             unicode = 0;
 164  163          int             repc;
 165  164          boolean_t       repc_specified;
↓ open down ↓ 121 lines elided ↑ open up ↑
 287  286                                      &vdp->vdb_uio) != 0)
 288  287                                          return (-1);
 289  288                          }
 290  289                          break;
 291  290  
 292  291                  case 'L':
 293  292                          if (mbc_marshal_get_char(mbc, &cval) != 0)
 294  293                                  return (-1);
 295  294                          if (cval != 2)
 296  295                                  return (-1);
 297      -                        goto ascii_conversion;
      296 +                        goto oem_conversion;
 298  297  
 299  298                  case 'A':
 300  299                  case 'S':
 301  300                          if (mbc_marshal_get_char(mbc, &cval) != 0)
 302  301                                  return (-1);
 303  302                          if (((c == 'A' || c == 'S') && cval != 4) ||
 304  303                              (c == 'L' && cval != 2))
 305  304                                  return (-1);
 306  305                          /* FALLTHROUGH */
 307  306  
 308  307                  case 'u': /* Convert from unicode if flags are set */
 309  308                          if (unicode)
 310  309                                  goto unicode_translation;
 311  310                          /* FALLTHROUGH */
 312  311  
 313      -                case 's':
 314      -ascii_conversion:
      312 +                case 's':       /* get OEM string */
      313 +oem_conversion:
 315  314                          ASSERT(sr != NULL);
 316      -                        cvalpp = va_arg(ap, uint8_t **);
      315 +                        charpp = va_arg(ap, char **);
 317  316                          if (!repc_specified)
 318  317                                  repc = 0;
 319      -                        if (mbc_marshal_get_ascii_string(sr,
 320      -                            mbc, cvalpp, repc) != 0)
      318 +                        if (mbc_marshal_get_oem_string(sr,
      319 +                            mbc, charpp, repc) != 0)
 321  320                                  return (-1);
 322  321                          break;
 323  322  
 324      -                case 'U': /* Convert from unicode */
      323 +                case 'U':       /* get UTF-16 string */
 325  324  unicode_translation:
 326  325                          ASSERT(sr != 0);
 327      -                        cvalpp = va_arg(ap, uint8_t **);
      326 +                        charpp = va_arg(ap, char **);
 328  327                          if (!repc_specified)
 329  328                                  repc = 0;
 330      -                        if (mbc->chain_offset & 1)
 331      -                                mbc->chain_offset++;
 332  329                          if (mbc_marshal_get_unicode_string(sr,
 333      -                            mbc, cvalpp, repc) != 0)
      330 +                            mbc, charpp, repc) != 0)
 334  331                                  return (-1);
 335  332                          break;
 336  333  
 337  334                  case 'Y': /* dos time to unix time tt/dd */
 338  335                          lvalp = va_arg(ap, uint32_t *);
 339  336                          while (repc-- > 0) {
 340  337                                  short   d, t;
 341  338  
 342  339                                  if (mbc_marshal_get_short(mbc,
 343  340                                      (uint16_t *)&t) != 0)
↓ open down ↓ 168 lines elided ↑ open up ↑
 512  509   *              require 2 characters to be passed in. A unicode conversion is
 513  510   *              applied if appropriate.
 514  511   *
 515  512   *      .       Same as '`' without unicode conversion.
 516  513   *
 517  514   *      U       Align the offset of the mbuf chain on a 16bit boundary.
 518  515   */
 519  516  int
 520  517  smb_mbc_vencodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
 521  518  {
      519 +        char            *charp;
 522  520          uint8_t         *cvalp;
 523  521          timestruc_t     *tvp;
 524  522          smb_vdb_t       *vdp;
 525  523          smb_request_t   *sr = NULL;
 526  524          uint64_t        llval;
 527  525          int64_t         nt_time;
 528  526          uint32_t        lval;
 529  527          uint_t          tag;
 530  528          int             unicode = 0;
 531  529          int             repc;
↓ open down ↓ 10 lines elided ↑ open up ↑
 542  540                          repc = 0;
 543  541                          do {
 544  542                                  repc = repc * 10 + c - '0';
 545  543                                  c = *fmt++;
 546  544                          } while ('0' <= c && c <= '9');
 547  545                          repc_specified = B_TRUE;
 548  546                  } else if (c == '#') {
 549  547                          repc = va_arg(ap, int);
 550  548                          c = *fmt++;
 551  549                          repc_specified = B_TRUE;
 552      -
 553  550                  }
 554  551  
 555  552                  switch (c) {
 556  553                  case '%':
 557  554                          sr = va_arg(ap, struct smb_request *);
 558  555                          if (sr->session->dialect >= SMB_VERS_2_BASE) {
 559  556                                  unicode = 1;
 560  557                                  break;
 561  558                          }
 562  559                          unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
↓ open down ↓ 89 lines elided ↑ open up ↑
 652  649                          while (repc-- > 0) {
 653  650                                  llval = va_arg(ap, uint64_t);
 654  651                                  if (mbc_marshal_put_long_long(mbc, llval) != 0)
 655  652                                          return (DECODE_NO_MORE_DATA);
 656  653                          }
 657  654                          break;
 658  655  
 659  656  
 660  657                  case 'L':
 661  658                          tag = 2;
 662      -                        goto ascii_conversion;
      659 +                        goto oem_conversion;
 663  660  
 664  661                  case 'S':
 665  662                  case 'A':
 666  663                          tag = 4;
 667  664                          goto tagged_str;
 668  665  
 669  666                  case 'P':
 670  667                          tag = 3;
 671  668                          goto tagged_str;
 672  669  
 673  670                  tagged_str:
 674  671                          if (mbc_marshal_put_char(mbc, tag) != 0)
 675  672                                  return (DECODE_NO_MORE_DATA);
 676  673                          /* FALLTHROUGH */
 677  674  
 678  675                  case 'u':       /* Convert from unicode if flags are set */
 679  676                          if (unicode)
 680  677                                  goto unicode_translation;
 681  678                          /* FALLTHROUGH */
 682  679  
 683      -                case 's':       /* ASCII/multibyte string */
 684      -ascii_conversion:       cvalp = va_arg(ap, uint8_t *);
      680 +                case 's':       /* put OEM string */
      681 +oem_conversion:
      682 +                        charp = va_arg(ap, char *);
 685  683                          if (!repc_specified)
 686  684                                  repc = 0;
 687      -                        if (mbc_marshal_put_ascii_string(mbc,
 688      -                            (char *)cvalp, repc) != 0)
      685 +                        if (mbc_marshal_put_oem_string(mbc,
      686 +                            charp, repc) != 0)
 689  687                                  return (DECODE_NO_MORE_DATA);
 690  688                          break;
 691  689  
      690 +                case 'U':       /* put UTF-16 string */
      691 +unicode_translation:
      692 +                        charp = va_arg(ap, char *);
      693 +                        if (!repc_specified)
      694 +                                repc = 0;
      695 +                        if (mbc_marshal_put_unicode_string(mbc,
      696 +                            charp, repc) != 0)
      697 +                                return (DECODE_NO_MORE_DATA);
      698 +                        break;
      699 +
 692  700                  case 'Y':               /* int32_t, encode dos date/time */
 693  701                          while (repc-- > 0) {
 694  702                                  uint16_t        d, t;
 695  703  
 696  704                                  lval = va_arg(ap, uint32_t);
 697  705                                  smb_time_unix_to_dos(lval,
 698  706                                      (short *)&d, (short *)&t);
 699  707                                  if (mbc_marshal_put_short(mbc, t) != 0)
 700  708                                          return (DECODE_NO_MORE_DATA);
 701  709                                  if (mbc_marshal_put_short(mbc, d) != 0)
↓ open down ↓ 19 lines elided ↑ open up ↑
 721  729                          if (unicode)
 722  730                                  repc *= 2;
 723  731                          /* FALLTHROUGH */
 724  732  
 725  733                  case '.':
 726  734                          while (repc-- > 0)
 727  735                                  if (mbc_marshal_put_char(mbc, 0) != 0)
 728  736                                          return (DECODE_NO_MORE_DATA);
 729  737                          break;
 730  738  
 731      -                case 'U': /* Convert to unicode, align to word boundary */
 732      -unicode_translation:
 733      -                        if (mbc->chain_offset & 1)
 734      -                                mbc->chain_offset++;
 735      -                        cvalp = va_arg(ap, uint8_t *);
 736      -                        if (!repc_specified)
 737      -                                repc = 0;
 738      -                        if (mbc_marshal_put_unicode_string(mbc,
 739      -                            (char *)cvalp, repc) != 0)
 740      -                                return (DECODE_NO_MORE_DATA);
 741      -                        break;
 742      -
 743  739                  default:
 744  740                          ASSERT(0);
 745  741                          return (-1);
 746  742                  }
 747  743          }
 748  744          return (0);
 749  745  }
 750  746  
 751  747  /*
 752  748   * smb_mbc_encodef
↓ open down ↓ 160 lines elided ↑ open up ↑
 913  909                  bcopy(mem, m->m_data, tlen);
 914  910                  mbc->chain_offset += tlen;
 915  911                  mem += tlen;
 916  912                  mem_len -= tlen;
 917  913          }
 918  914  
 919  915          return (0);
 920  916  }
 921  917  
 922  918  /*
      919 + * Put padding sufficient to align to A, where
      920 + * A is some power of 2 greater than zero.
      921 + */
      922 +int
      923 +smb_mbc_put_align(mbuf_chain_t *mbc, int align)
      924 +{
      925 +        int mask = align - 1;
      926 +        int padsz;
      927 +
      928 +        ASSERT(align > 0 && (align & mask) == 0);
      929 +        if ((mbc->chain_offset & mask) == 0)
      930 +                return (0);
      931 +        padsz = align - (mbc->chain_offset & mask);
      932 +        return (smb_mbc_encodef(mbc, "#.", padsz));
      933 +}
      934 +
      935 +/*
 923  936   * Put data into mbuf chain allocating as needed.
 924  937   * Adds room to end of mbuf chain if needed.
 925  938   */
 926  939  static int
 927  940  mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
 928  941  {
 929  942          mbuf_t  *m;
 930  943          mbuf_t  *l;
 931  944          int32_t bytes_available;
 932  945  
↓ open down ↓ 128 lines elided ↑ open up ↑
1061 1074          mbc_marshal_store_byte(mbc, data >> 16);
1062 1075          mbc_marshal_store_byte(mbc, data >> 24);
1063 1076          mbc_marshal_store_byte(mbc, data >> 32);
1064 1077          mbc_marshal_store_byte(mbc, data >> 40);
1065 1078          mbc_marshal_store_byte(mbc, data >> 48);
1066 1079          mbc_marshal_store_byte(mbc, data >> 56);
1067 1080          return (0);
1068 1081  }
1069 1082  
1070 1083  /*
1071      - * When need to convert from UTF-8 (internal format) to a single
1072      - * byte string (external format ) when marshalling a string.
     1084 + * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset.
     1085 + * Also write a null unless the repc count limits the length we put.
     1086 + * When (repc > 0) the length we marshal must be exactly repc, and
     1087 + * truncate or pad the mbc data as necessary.
     1088 + * See also: msgbuf_put_oem_string
1073 1089   */
1074 1090  static int
1075      -mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc)
     1091 +mbc_marshal_put_oem_string(mbuf_chain_t *mbc, char *mbs, int repc)
1076 1092  {
1077      -        smb_wchar_t     wide_char;
1078      -        int             nbytes;
1079      -        int             length;
     1093 +        uint8_t         *oembuf = NULL;
     1094 +        uint8_t         *s;
     1095 +        int             oemlen;
     1096 +        int             rlen;
     1097 +        int             rc;
1080 1098  
1081      -        if ((length = smb_sbequiv_strlen(mbs)) == -1)
     1099 +        /*
     1100 +         * Compute length of converted OEM string,
     1101 +         * NOT including null terminator
     1102 +         */
     1103 +        if ((oemlen = smb_sbequiv_strlen(mbs)) == -1)
1082 1104                  return (DECODE_NO_MORE_DATA);
1083 1105  
1084      -        length += sizeof (char);
1085      -
1086      -        if ((repc > 0) && (repc < length))
1087      -                length = repc;
1088      -        if (mbc_marshal_make_room(mbc, length))
     1106 +        /*
     1107 +         * If repc not specified, put whole string + NULL,
     1108 +         * otherwise will truncate or pad as needed.
     1109 +         */
     1110 +        if (repc <= 0)
     1111 +                repc = oemlen + 1;
     1112 +        if (mbc_marshal_make_room(mbc, repc))
1089 1113                  return (DECODE_NO_MORE_DATA);
1090 1114  
1091      -        while (*mbs) {
1092      -                /*
1093      -                 * We should restore oem chars here.
1094      -                 */
1095      -                nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
1096      -                if (nbytes == -1)
1097      -                        return (DECODE_NO_MORE_DATA);
     1115 +        /*
     1116 +         * Convert into a temporary buffer
     1117 +         * Free oembuf before return.
     1118 +         */
     1119 +        oembuf = smb_mem_zalloc(oemlen + 1);
     1120 +        ASSERT(oembuf != NULL);
     1121 +        rlen = smb_mbstooem(oembuf, mbs, oemlen);
     1122 +        if (rlen < 0) {
     1123 +                rc = DECODE_NO_MORE_DATA;
     1124 +                goto out;
     1125 +        }
     1126 +        if (rlen > oemlen)
     1127 +                rlen = oemlen;
     1128 +        oembuf[rlen] = '\0';
1098 1129  
1099      -                mbc_marshal_store_byte(mbc, (uint8_t)wide_char);
1100      -
1101      -                if (wide_char & 0xFF00)
1102      -                        mbc_marshal_store_byte(mbc, wide_char >> 8);
1103      -
1104      -                mbs += nbytes;
     1130 +        /*
     1131 +         * Copy the converted string into the message,
     1132 +         * truncated or paded as required.
     1133 +         */
     1134 +        s = oembuf;
     1135 +        while (repc > 0) {
     1136 +                mbc_marshal_store_byte(mbc, *s);
     1137 +                if (*s != '\0')
     1138 +                        s++;
     1139 +                repc--;
1105 1140          }
     1141 +        rc = 0;
1106 1142  
1107      -        mbc_marshal_store_byte(mbc, 0);
1108      -        return (0);
     1143 +out:
     1144 +        if (oembuf != NULL)
     1145 +                smb_mem_free(oembuf);
     1146 +        return (rc);
1109 1147  }
1110 1148  
     1149 +/*
     1150 + * Marshal a UTF-8 string (str) into mbc, converting to UTF-16.
     1151 + * Also write a null unless the repc count limits the length.
     1152 + * When (repc > 0) the length we marshal must be exactly repc,
     1153 + * and truncate or pad the mbc data as necessary.
     1154 + * See also: msgbuf_put_unicode_string
     1155 + */
1111 1156  static int
1112      -mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc)
     1157 +mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *mbs, int repc)
1113 1158  {
1114      -        smb_wchar_t     wchar;
1115      -        int             consumed;
1116      -        int             length;
     1159 +        smb_wchar_t     *wcsbuf = NULL;
     1160 +        smb_wchar_t     *wp;
     1161 +        size_t          wcslen, wcsbytes;
     1162 +        size_t          rlen;
     1163 +        int             rc;
1117 1164  
1118      -        if ((length = smb_wcequiv_strlen(ascii)) == -1)
     1165 +        /* align to word boundary */
     1166 +        if (mbc->chain_offset & 1) {
     1167 +                if (mbc_marshal_make_room(mbc, 1))
     1168 +                        return (DECODE_NO_MORE_DATA);
     1169 +                mbc_marshal_store_byte(mbc, 0);
     1170 +        }
     1171 +
     1172 +        /*
     1173 +         * Compute length of converted UTF-16 string,
     1174 +         * NOT including null terminator (in bytes).
     1175 +         */
     1176 +        wcsbytes = smb_wcequiv_strlen(mbs);
     1177 +        if (wcsbytes == (size_t)-1)
1119 1178                  return (DECODE_NO_MORE_DATA);
1120 1179  
1121      -        length += sizeof (smb_wchar_t);
     1180 +        /*
     1181 +         * If repc not specified, put whole string + NULL,
     1182 +         * otherwise will truncate or pad as needed.
     1183 +         */
     1184 +        if (repc <= 0)
     1185 +                repc = wcsbytes + 2;
     1186 +        if (mbc_marshal_make_room(mbc, repc))
     1187 +                return (DECODE_NO_MORE_DATA);
1122 1188  
1123      -        if ((repc > 0) && (repc < length))
1124      -                length = repc;
     1189 +        /*
     1190 +         * Convert into a temporary buffer
     1191 +         * Free wcsbuf before return.
     1192 +         */
     1193 +        wcslen = wcsbytes / 2;
     1194 +        wcsbuf = smb_mem_zalloc(wcsbytes + 2);
     1195 +        ASSERT(wcsbuf != NULL);
     1196 +        rlen = smb_mbstowcs(wcsbuf, mbs, wcslen);
     1197 +        if (rlen == (size_t)-1) {
     1198 +                rc = DECODE_NO_MORE_DATA;
     1199 +                goto out;
     1200 +        }
     1201 +        if (rlen > wcslen)
     1202 +                rlen = wcslen;
     1203 +        wcsbuf[rlen] = 0;
1125 1204  
1126      -        if (mbc_marshal_make_room(mbc, length))
1127      -                return (DECODE_NO_MORE_DATA);
1128      -        while (length > 0) {
1129      -                consumed = smb_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
1130      -                if (consumed == -1)
1131      -                        break;  /* Invalid sequence */
1132      -                /*
1133      -                 * Note that consumed will be 0 when the null terminator
1134      -                 * is encountered and ascii will not be advanced beyond
1135      -                 * that point. Length will continue to be decremented so
1136      -                 * we won't get stuck here.
1137      -                 */
1138      -                ascii += consumed;
     1205 +        /*
     1206 +         * Copy the converted string into the message,
     1207 +         * truncated or paded as required.  Preserve
     1208 +         * little-endian order while copying.
     1209 +         */
     1210 +        wp = wcsbuf;
     1211 +        while (repc > 1) {
     1212 +                smb_wchar_t wchar = LE_IN16(wp);
1139 1213                  mbc_marshal_store_byte(mbc, wchar);
1140 1214                  mbc_marshal_store_byte(mbc, wchar >> 8);
1141      -                length -= sizeof (smb_wchar_t);
     1215 +                if (wchar != 0)
     1216 +                        wp++;
     1217 +                repc -= sizeof (smb_wchar_t);
1142 1218          }
1143      -        return (0);
     1219 +        if (repc > 0)
     1220 +                mbc_marshal_store_byte(mbc, 0);
     1221 +
     1222 +        rc = 0;
     1223 +out:
     1224 +        if (wcsbuf != NULL)
     1225 +                smb_mem_free(wcsbuf);
     1226 +        return (rc);
1144 1227  }
1145 1228  
1146 1229  static int /*ARGSUSED*/
1147 1230  uiorefnoop(caddr_t p, int size, int adj)
1148 1231  {
1149 1232          return (0);
1150 1233  }
1151 1234  
1152 1235  static int
1153 1236  mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
↓ open down ↓ 214 lines elided ↑ open up ↑
1368 1451                  tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
1369 1452                  tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
1370 1453                  tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
1371 1454                  tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
1372 1455                  *(uint64_t *)data = tmp;
1373 1456          }
1374 1457          return (0);
1375 1458  }
1376 1459  
1377 1460  /*
1378      - * mbc_marshal_get_ascii_string
     1461 + * mbc_marshal_get_oem_string
1379 1462   *
1380      - * The ascii string in smb includes oem chars. Since the
1381      - * system needs utf8 encodes unicode char, conversion is
1382      - * required to convert the oem char to unicode and then
1383      - * to encode the converted wchars to utf8 format.
1384      - * Therefore, the **ascii returned will be in such format
1385      - * instead of the real ASCII format.
     1463 + * Decode an OEM string, returning its UTF-8 form in strpp,
     1464 + * allocated using smb_srm_zalloc (automatically freed).
     1465 + * If max_bytes != 0, consume at most max_bytes of the mbc.
     1466 + * See also: msgbuf_get_oem_string
1386 1467   */
1387 1468  static int
1388      -mbc_marshal_get_ascii_string(
1389      -    smb_request_t       *sr,
1390      -    mbuf_chain_t        *mbc,
1391      -    uint8_t             **ascii,
1392      -    int                 max_ascii)
     1469 +mbc_marshal_get_oem_string(smb_request_t *sr,
     1470 +    mbuf_chain_t *mbc, char **strpp, int max_bytes)
1393 1471  {
1394      -        char            *rcvbuf;
1395      -        char            *ch;
1396      -        int             max;
1397      -        int             length = 0;
     1472 +        char            *mbs;
     1473 +        uint8_t         *oembuf = NULL;
     1474 +        int             oemlen, oemmax;
     1475 +        int             mbsmax;
     1476 +        int             rlen;
     1477 +        int             rc;
1398 1478  
1399      -        max = MALLOC_QUANTUM;
1400      -        rcvbuf = smb_srm_zalloc(sr, max);
     1479 +        if (max_bytes == 0)
     1480 +                max_bytes = 0xffff;
1401 1481  
1402      -        if (max_ascii == 0)
1403      -                max_ascii = 0xffff;
1404      -
1405      -        ch = rcvbuf;
     1482 +        /*
     1483 +         * Get the OtW data into a temporary buffer.
     1484 +         * Free oembuf before return.
     1485 +         */
     1486 +        oemlen = 0;
     1487 +        oemmax = MALLOC_QUANTUM;
     1488 +        oembuf = smb_mem_alloc(oemmax);
1406 1489          for (;;) {
1407      -                while (length < max) {
1408      -                        if (max_ascii-- <= 0) {
1409      -                                *ch++ = 0;
1410      -                                goto multibyte_encode;
1411      -                        }
1412      -                        if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1413      -                                /* Data will never be available */
1414      -                                return (DECODE_NO_MORE_DATA);
1415      -                        }
1416      -                        if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
1417      -                                goto multibyte_encode;
1418      -                        length++;
     1490 +                uint8_t ch;
     1491 +
     1492 +                if (oemlen >= max_bytes)
     1493 +                        break;
     1494 +                if ((oemlen + 2) >= oemmax) {
     1495 +                        oemmax += MALLOC_QUANTUM;
     1496 +                        oembuf = smb_mem_realloc(oembuf, oemmax);
1419 1497                  }
1420      -                max += MALLOC_QUANTUM;
1421      -                rcvbuf = smb_srm_rezalloc(sr, rcvbuf, max);
1422      -                ch = rcvbuf + length;
     1498 +                if (mbc_marshal_get_char(mbc, &ch) != 0) {
     1499 +                        rc = DECODE_NO_MORE_DATA;
     1500 +                        goto out;
     1501 +                }
     1502 +                if (ch == 0)
     1503 +                        break;
     1504 +                oembuf[oemlen++] = ch;
1423 1505          }
     1506 +        oembuf[oemlen] = '\0';
1424 1507  
1425      -multibyte_encode:
1426 1508          /*
1427      -         * UTF-8 encode the string for internal system use.
     1509 +         * Get the buffer we'll return and convert to UTF-8.
     1510 +         * May take as much as double the space.
1428 1511           */
1429      -        length = strlen(rcvbuf) + 1;
1430      -        *ascii = smb_srm_zalloc(sr, length * MTS_MB_CHAR_MAX);
1431      -        return (mbc_marshal_cstou8("CP850", (char *)*ascii,
1432      -            (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
     1512 +        mbsmax = oemlen * 2;
     1513 +        mbs = smb_srm_zalloc(sr, mbsmax + 1);
     1514 +        ASSERT(mbs != NULL);
     1515 +        rlen = smb_oemtombs(mbs, oembuf, mbsmax);
     1516 +        if (rlen < 0) {
     1517 +                rc = DECODE_NO_MORE_DATA;
     1518 +                goto out;
     1519 +        }
     1520 +        if (rlen > mbsmax)
     1521 +                rlen = mbsmax;
     1522 +        mbs[rlen] = '\0';
     1523 +        *strpp = mbs;
     1524 +        rc = 0;
     1525 +
     1526 +out:
     1527 +        if (oembuf != NULL)
     1528 +                smb_mem_free(oembuf);
     1529 +        return (rc);
1433 1530  }
1434 1531  
     1532 +/*
     1533 + * mbc_marshal_get_unicode_string
     1534 + *
     1535 + * Decode a UTF-16 string, returning its UTF-8 form in strpp,
     1536 + * allocated using smb_srm_zalloc (automatically freed).
     1537 + * If max_bytes != 0, consume at most max_bytes of the mbc.
     1538 + * See also: msgbuf_get_unicode_string
     1539 + */
1435 1540  static int
1436 1541  mbc_marshal_get_unicode_string(smb_request_t *sr,
1437      -    mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode)
     1542 +    mbuf_chain_t *mbc, char **strpp, int max_bytes)
1438 1543  {
1439      -        int             max;
1440      -        uint16_t        wchar;
1441      -        char            *ch;
1442      -        int             emitted;
1443      -        int             length = 0;
     1544 +        char            *mbs;
     1545 +        uint16_t        *wcsbuf = NULL;
     1546 +        int             wcslen;         // wchar count
     1547 +        int             wcsmax;         // byte count
     1548 +        size_t          mbsmax;
     1549 +        size_t          rlen;
     1550 +        int             rc;
1444 1551  
1445      -        if (max_unicode == 0)
1446      -                max_unicode = 0xffff;
     1552 +        if (max_bytes == 0)
     1553 +                max_bytes = 0xffff;
1447 1554  
1448      -        max = MALLOC_QUANTUM;
1449      -        *ascii = smb_srm_zalloc(sr, max);
     1555 +        /*
     1556 +         * Unicode strings are always word aligned.
     1557 +         */
     1558 +        if (mbc->chain_offset & 1) {
     1559 +                if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0)
     1560 +                        return (DECODE_NO_MORE_DATA);
     1561 +                mbc->chain_offset++;
     1562 +        }
1450 1563  
1451      -        ch = (char *)*ascii;
     1564 +        /*
     1565 +         * Get the OtW data into a temporary buffer.
     1566 +         * Free wcsbuf before return.
     1567 +         */
     1568 +        wcslen = 0;
     1569 +        wcsmax = MALLOC_QUANTUM;
     1570 +        wcsbuf = smb_mem_alloc(wcsmax);
1452 1571          for (;;) {
1453      -                while ((length + MTS_MB_CHAR_MAX) < max) {
1454      -                        if (max_unicode <= 0)
1455      -                                goto done;
1456      -                        max_unicode -= 2;
     1572 +                uint16_t        wchar;
1457 1573  
1458      -                        if (mbc_marshal_get_short(mbc, &wchar) != 0)
1459      -                                return (DECODE_NO_MORE_DATA);
1460      -
1461      -                        if (wchar == 0) goto done;
1462      -
1463      -                        emitted = smb_wctomb(ch, wchar);
1464      -                        length += emitted;
1465      -                        ch += emitted;
     1574 +                if ((wcslen * 2) >= max_bytes)
     1575 +                        break;
     1576 +                if (((wcslen * 2) + 4) >= wcsmax) {
     1577 +                        wcsmax += MALLOC_QUANTUM;
     1578 +                        wcsbuf = smb_mem_realloc(wcsbuf, wcsmax);
1466 1579                  }
1467      -                max += MALLOC_QUANTUM;
1468      -                *ascii = smb_srm_rezalloc(sr, *ascii, max);
1469      -                ch = (char *)*ascii + length;
     1580 +                if (mbc_marshal_get_short(mbc, &wchar) != 0) {
     1581 +                        rc = DECODE_NO_MORE_DATA;
     1582 +                        goto out;
     1583 +                }
     1584 +                if (wchar == 0)
     1585 +                        break;
     1586 +                /* Keep in little-endian form. */
     1587 +                LE_OUT16(wcsbuf + wcslen, wchar);
     1588 +                wcslen++;
1470 1589          }
1471      -done:   *ch = 0;
1472      -        return (0);
     1590 +        wcsbuf[wcslen] = 0;
     1591 +
     1592 +        /*
     1593 +         * Get the buffer we'll return and convert to UTF-8.
     1594 +         * May take as much 4X number of wide chars.
     1595 +         */
     1596 +        mbsmax = wcslen * MTS_MB_CUR_MAX;
     1597 +        mbs = smb_srm_zalloc(sr, mbsmax + 1);
     1598 +        ASSERT(mbs != NULL);
     1599 +        rlen = smb_wcstombs(mbs, wcsbuf, mbsmax);
     1600 +        if (rlen == (size_t)-1) {
     1601 +                rc = DECODE_NO_MORE_DATA;
     1602 +                goto out;
     1603 +        }
     1604 +        if (rlen > mbsmax)
     1605 +                rlen = mbsmax;
     1606 +        mbs[rlen] = '\0';
     1607 +        *strpp = mbs;
     1608 +        rc = 0;
     1609 +
     1610 +out:
     1611 +        if (wcsbuf != NULL)
     1612 +                smb_mem_free(wcsbuf);
     1613 +        return (rc);
1473 1614  }
1474 1615  
1475 1616  static int /*ARGSUSED*/
1476 1617  mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
1477 1618  {
1478 1619          *m = NULL;
1479 1620          if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1480 1621                  /* Data will never be available */
1481 1622                  return (DECODE_NO_MORE_DATA);
1482 1623          }
↓ open down ↓ 80 lines elided ↑ open up ↑
1563 1704          return (0);
1564 1705  }
1565 1706  
1566 1707  static int
1567 1708  mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
1568 1709  {
1569 1710          if (MBC_ROOM_FOR(mbc, skip) == 0)
1570 1711                  return (DECODE_NO_MORE_DATA);
1571 1712          mbc->chain_offset += skip;
1572 1713          return (0);
1573      -}
1574      -
1575      -/*
1576      - * Converts oem string to UTF-8 string with an output string of max
1577      - * maxconv bytes.  The string may be truncated or not null-terminated if
1578      - * there is not enough room.
1579      - *
1580      - * returns -1, cnt (partial conversion)  or 0 (success)
1581      - */
1582      -
1583      -static int
1584      -mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
1585      -    char *inbuf, size_t srcbytes)
1586      -{
1587      -        kiconv_t        t2u;
1588      -        size_t          inlen = srcbytes;
1589      -        size_t          outlen = maxconv;
1590      -        int             err = 0;
1591      -        size_t          rc;
1592      -
1593      -        if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
1594      -                return (-1);
1595      -
1596      -        rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
1597      -        (void) kiconv_close(t2u);
1598      -        return ((int)rc);
1599 1714  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX