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
        
*** 20,30 ****
   */
  /*
   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
   *
!  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * SMB mbuf marshaling encode/decode.
   */
--- 20,30 ----
   */
  /*
   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
   *
!  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * SMB mbuf marshaling encode/decode.
   */
*** 37,54 ****
  #define DECODE_NO_ERROR         0
  #define DECODE_NO_MORE_DATA     1
  #define DECODE_ALLOCATION_ERROR 2
  #define DECODE_CONVERSION_ERROR 3
  
- static int mbc_marshal_cstou8(char *, char *, size_t, char *, size_t);
  static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
  static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
  static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
  static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
  static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
  static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
! static int mbc_marshal_put_ascii_string(mbuf_chain_t *, char *, int);
  static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
  static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
  static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
  static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
  static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
--- 37,53 ----
  #define DECODE_NO_ERROR         0
  #define DECODE_NO_MORE_DATA     1
  #define DECODE_ALLOCATION_ERROR 2
  #define DECODE_CONVERSION_ERROR 3
  
  static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
  static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
  static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
  static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
  static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
  static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
! static int mbc_marshal_put_oem_string(mbuf_chain_t *, char *, int);
  static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
  static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
  static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
  static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
  static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
*** 56,69 ****
  static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
  static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
  static uint64_t qswap(uint64_t ll);
  static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
  static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
! static int mbc_marshal_get_ascii_string(smb_request_t *, mbuf_chain_t *,
!     uint8_t **ascii, int);
  static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
!     uint8_t **, int);
  static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
  static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
  static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
  static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
  
--- 55,68 ----
  static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
  static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
  static uint64_t qswap(uint64_t ll);
  static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
  static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
! static int mbc_marshal_get_oem_string(smb_request_t *, mbuf_chain_t *,
!     char **, int);
  static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
!     char **, int);
  static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
  static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
  static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
  static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
  
*** 150,160 ****
  smb_mbc_vdecodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
  {
          uint8_t         c;
          uint8_t         cval;
          uint8_t         *cvalp;
!         uint8_t         **cvalpp;
          uint16_t        wval;
          uint16_t        *wvalp;
          uint32_t        *lvalp;
          uint64_t        *llvalp;
          smb_vdb_t       *vdp;
--- 149,159 ----
  smb_mbc_vdecodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
  {
          uint8_t         c;
          uint8_t         cval;
          uint8_t         *cvalp;
!         char            **charpp;
          uint16_t        wval;
          uint16_t        *wvalp;
          uint32_t        *lvalp;
          uint64_t        *llvalp;
          smb_vdb_t       *vdp;
*** 292,302 ****
                  case 'L':
                          if (mbc_marshal_get_char(mbc, &cval) != 0)
                                  return (-1);
                          if (cval != 2)
                                  return (-1);
!                         goto ascii_conversion;
  
                  case 'A':
                  case 'S':
                          if (mbc_marshal_get_char(mbc, &cval) != 0)
                                  return (-1);
--- 291,301 ----
                  case 'L':
                          if (mbc_marshal_get_char(mbc, &cval) != 0)
                                  return (-1);
                          if (cval != 2)
                                  return (-1);
!                         goto oem_conversion;
  
                  case 'A':
                  case 'S':
                          if (mbc_marshal_get_char(mbc, &cval) != 0)
                                  return (-1);
*** 308,338 ****
                  case 'u': /* Convert from unicode if flags are set */
                          if (unicode)
                                  goto unicode_translation;
                          /* FALLTHROUGH */
  
!                 case 's':
! ascii_conversion:
                          ASSERT(sr != NULL);
!                         cvalpp = va_arg(ap, uint8_t **);
                          if (!repc_specified)
                                  repc = 0;
!                         if (mbc_marshal_get_ascii_string(sr,
!                             mbc, cvalpp, repc) != 0)
                                  return (-1);
                          break;
  
!                 case 'U': /* Convert from unicode */
  unicode_translation:
                          ASSERT(sr != 0);
!                         cvalpp = va_arg(ap, uint8_t **);
                          if (!repc_specified)
                                  repc = 0;
-                         if (mbc->chain_offset & 1)
-                                 mbc->chain_offset++;
                          if (mbc_marshal_get_unicode_string(sr,
!                             mbc, cvalpp, repc) != 0)
                                  return (-1);
                          break;
  
                  case 'Y': /* dos time to unix time tt/dd */
                          lvalp = va_arg(ap, uint32_t *);
--- 307,335 ----
                  case 'u': /* Convert from unicode if flags are set */
                          if (unicode)
                                  goto unicode_translation;
                          /* FALLTHROUGH */
  
!                 case 's':       /* get OEM string */
! oem_conversion:
                          ASSERT(sr != NULL);
!                         charpp = va_arg(ap, char **);
                          if (!repc_specified)
                                  repc = 0;
!                         if (mbc_marshal_get_oem_string(sr,
!                             mbc, charpp, repc) != 0)
                                  return (-1);
                          break;
  
!                 case 'U':       /* get UTF-16 string */
  unicode_translation:
                          ASSERT(sr != 0);
!                         charpp = va_arg(ap, char **);
                          if (!repc_specified)
                                  repc = 0;
                          if (mbc_marshal_get_unicode_string(sr,
!                             mbc, charpp, repc) != 0)
                                  return (-1);
                          break;
  
                  case 'Y': /* dos time to unix time tt/dd */
                          lvalp = va_arg(ap, uint32_t *);
*** 517,526 ****
--- 514,524 ----
   *      U       Align the offset of the mbuf chain on a 16bit boundary.
   */
  int
  smb_mbc_vencodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
  {
+         char            *charp;
          uint8_t         *cvalp;
          timestruc_t     *tvp;
          smb_vdb_t       *vdp;
          smb_request_t   *sr = NULL;
          uint64_t        llval;
*** 547,557 ****
                          repc_specified = B_TRUE;
                  } else if (c == '#') {
                          repc = va_arg(ap, int);
                          c = *fmt++;
                          repc_specified = B_TRUE;
- 
                  }
  
                  switch (c) {
                  case '%':
                          sr = va_arg(ap, struct smb_request *);
--- 545,554 ----
*** 657,667 ****
                          break;
  
  
                  case 'L':
                          tag = 2;
!                         goto ascii_conversion;
  
                  case 'S':
                  case 'A':
                          tag = 4;
                          goto tagged_str;
--- 654,664 ----
                          break;
  
  
                  case 'L':
                          tag = 2;
!                         goto oem_conversion;
  
                  case 'S':
                  case 'A':
                          tag = 4;
                          goto tagged_str;
*** 678,696 ****
                  case 'u':       /* Convert from unicode if flags are set */
                          if (unicode)
                                  goto unicode_translation;
                          /* FALLTHROUGH */
  
!                 case 's':       /* ASCII/multibyte string */
! ascii_conversion:       cvalp = va_arg(ap, uint8_t *);
                          if (!repc_specified)
                                  repc = 0;
!                         if (mbc_marshal_put_ascii_string(mbc,
!                             (char *)cvalp, repc) != 0)
                                  return (DECODE_NO_MORE_DATA);
                          break;
  
                  case 'Y':               /* int32_t, encode dos date/time */
                          while (repc-- > 0) {
                                  uint16_t        d, t;
  
                                  lval = va_arg(ap, uint32_t);
--- 675,704 ----
                  case 'u':       /* Convert from unicode if flags are set */
                          if (unicode)
                                  goto unicode_translation;
                          /* FALLTHROUGH */
  
!                 case 's':       /* put OEM string */
! oem_conversion:
!                         charp = va_arg(ap, char *);
                          if (!repc_specified)
                                  repc = 0;
!                         if (mbc_marshal_put_oem_string(mbc,
!                             charp, repc) != 0)
                                  return (DECODE_NO_MORE_DATA);
                          break;
  
+                 case 'U':       /* put UTF-16 string */
+ unicode_translation:
+                         charp = va_arg(ap, char *);
+                         if (!repc_specified)
+                                 repc = 0;
+                         if (mbc_marshal_put_unicode_string(mbc,
+                             charp, repc) != 0)
+                                 return (DECODE_NO_MORE_DATA);
+                         break;
+ 
                  case 'Y':               /* int32_t, encode dos date/time */
                          while (repc-- > 0) {
                                  uint16_t        d, t;
  
                                  lval = va_arg(ap, uint32_t);
*** 726,747 ****
                          while (repc-- > 0)
                                  if (mbc_marshal_put_char(mbc, 0) != 0)
                                          return (DECODE_NO_MORE_DATA);
                          break;
  
-                 case 'U': /* Convert to unicode, align to word boundary */
- unicode_translation:
-                         if (mbc->chain_offset & 1)
-                                 mbc->chain_offset++;
-                         cvalp = va_arg(ap, uint8_t *);
-                         if (!repc_specified)
-                                 repc = 0;
-                         if (mbc_marshal_put_unicode_string(mbc,
-                             (char *)cvalp, repc) != 0)
-                                 return (DECODE_NO_MORE_DATA);
-                         break;
- 
                  default:
                          ASSERT(0);
                          return (-1);
                  }
          }
--- 734,743 ----
*** 918,927 ****
--- 914,940 ----
  
          return (0);
  }
  
  /*
+  * Put padding sufficient to align to A, where
+  * A is some power of 2 greater than zero.
+  */
+ int
+ smb_mbc_put_align(mbuf_chain_t *mbc, int align)
+ {
+         int mask = align - 1;
+         int padsz;
+ 
+         ASSERT(align > 0 && (align & mask) == 0);
+         if ((mbc->chain_offset & mask) == 0)
+                 return (0);
+         padsz = align - (mbc->chain_offset & mask);
+         return (smb_mbc_encodef(mbc, "#.", padsz));
+ }
+ 
+ /*
   * Put data into mbuf chain allocating as needed.
   * Adds room to end of mbuf chain if needed.
   */
  static int
  mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
*** 1066,1148 ****
          mbc_marshal_store_byte(mbc, data >> 56);
          return (0);
  }
  
  /*
!  * When need to convert from UTF-8 (internal format) to a single
!  * byte string (external format ) when marshalling a string.
   */
  static int
! mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc)
  {
!         smb_wchar_t     wide_char;
!         int             nbytes;
!         int             length;
  
!         if ((length = smb_sbequiv_strlen(mbs)) == -1)
                  return (DECODE_NO_MORE_DATA);
  
!         length += sizeof (char);
! 
!         if ((repc > 0) && (repc < length))
!                 length = repc;
!         if (mbc_marshal_make_room(mbc, length))
                  return (DECODE_NO_MORE_DATA);
  
-         while (*mbs) {
                  /*
!                  * We should restore oem chars here.
                   */
!                 nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
!                 if (nbytes == -1)
!                         return (DECODE_NO_MORE_DATA);
  
!                 mbc_marshal_store_byte(mbc, (uint8_t)wide_char);
! 
!                 if (wide_char & 0xFF00)
!                         mbc_marshal_store_byte(mbc, wide_char >> 8);
! 
!                 mbs += nbytes;
          }
  
!         mbc_marshal_store_byte(mbc, 0);
!         return (0);
  }
  
  static int
! mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc)
  {
!         smb_wchar_t     wchar;
!         int             consumed;
!         int             length;
  
!         if ((length = smb_wcequiv_strlen(ascii)) == -1)
                  return (DECODE_NO_MORE_DATA);
  
!         length += sizeof (smb_wchar_t);
  
!         if ((repc > 0) && (repc < length))
!                 length = repc;
! 
!         if (mbc_marshal_make_room(mbc, length))
                  return (DECODE_NO_MORE_DATA);
!         while (length > 0) {
!                 consumed = smb_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
!                 if (consumed == -1)
!                         break;  /* Invalid sequence */
                  /*
!                  * Note that consumed will be 0 when the null terminator
!                  * is encountered and ascii will not be advanced beyond
!                  * that point. Length will continue to be decremented so
!                  * we won't get stuck here.
                   */
!                 ascii += consumed;
                  mbc_marshal_store_byte(mbc, wchar);
                  mbc_marshal_store_byte(mbc, wchar >> 8);
!                 length -= sizeof (smb_wchar_t);
          }
!         return (0);
  }
  
  static int /*ARGSUSED*/
  uiorefnoop(caddr_t p, int size, int adj)
  {
--- 1079,1231 ----
          mbc_marshal_store_byte(mbc, data >> 56);
          return (0);
  }
  
  /*
!  * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset.
!  * Also write a null unless the repc count limits the length we put.
!  * When (repc > 0) the length we marshal must be exactly repc, and
!  * truncate or pad the mbc data as necessary.
!  * See also: msgbuf_put_oem_string
   */
  static int
! mbc_marshal_put_oem_string(mbuf_chain_t *mbc, char *mbs, int repc)
  {
!         uint8_t         *oembuf = NULL;
!         uint8_t         *s;
!         int             oemlen;
!         int             rlen;
!         int             rc;
  
!         /*
!          * Compute length of converted OEM string,
!          * NOT including null terminator
!          */
!         if ((oemlen = smb_sbequiv_strlen(mbs)) == -1)
                  return (DECODE_NO_MORE_DATA);
  
!         /*
!          * If repc not specified, put whole string + NULL,
!          * otherwise will truncate or pad as needed.
!          */
!         if (repc <= 0)
!                 repc = oemlen + 1;
!         if (mbc_marshal_make_room(mbc, repc))
                  return (DECODE_NO_MORE_DATA);
  
          /*
!          * Convert into a temporary buffer
!          * Free oembuf before return.
           */
!         oembuf = smb_mem_zalloc(oemlen + 1);
!         ASSERT(oembuf != NULL);
!         rlen = smb_mbstooem(oembuf, mbs, oemlen);
!         if (rlen < 0) {
!                 rc = DECODE_NO_MORE_DATA;
!                 goto out;
!         }
!         if (rlen > oemlen)
!                 rlen = oemlen;
!         oembuf[rlen] = '\0';
  
!         /*
!          * Copy the converted string into the message,
!          * truncated or paded as required.
!          */
!         s = oembuf;
!         while (repc > 0) {
!                 mbc_marshal_store_byte(mbc, *s);
!                 if (*s != '\0')
!                         s++;
!                 repc--;
          }
+         rc = 0;
  
! out:
!         if (oembuf != NULL)
!                 smb_mem_free(oembuf);
!         return (rc);
  }
  
+ /*
+  * Marshal a UTF-8 string (str) into mbc, converting to UTF-16.
+  * Also write a null unless the repc count limits the length.
+  * When (repc > 0) the length we marshal must be exactly repc,
+  * and truncate or pad the mbc data as necessary.
+  * See also: msgbuf_put_unicode_string
+  */
  static int
! mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *mbs, int repc)
  {
!         smb_wchar_t     *wcsbuf = NULL;
!         smb_wchar_t     *wp;
!         size_t          wcslen, wcsbytes;
!         size_t          rlen;
!         int             rc;
  
!         /* align to word boundary */
!         if (mbc->chain_offset & 1) {
!                 if (mbc_marshal_make_room(mbc, 1))
                          return (DECODE_NO_MORE_DATA);
+                 mbc_marshal_store_byte(mbc, 0);
+         }
  
!         /*
!          * Compute length of converted UTF-16 string,
!          * NOT including null terminator (in bytes).
!          */
!         wcsbytes = smb_wcequiv_strlen(mbs);
!         if (wcsbytes == (size_t)-1)
!                 return (DECODE_NO_MORE_DATA);
  
!         /*
!          * If repc not specified, put whole string + NULL,
!          * otherwise will truncate or pad as needed.
!          */
!         if (repc <= 0)
!                 repc = wcsbytes + 2;
!         if (mbc_marshal_make_room(mbc, repc))
                  return (DECODE_NO_MORE_DATA);
! 
          /*
!          * Convert into a temporary buffer
!          * Free wcsbuf before return.
           */
!         wcslen = wcsbytes / 2;
!         wcsbuf = smb_mem_zalloc(wcsbytes + 2);
!         ASSERT(wcsbuf != NULL);
!         rlen = smb_mbstowcs(wcsbuf, mbs, wcslen);
!         if (rlen == (size_t)-1) {
!                 rc = DECODE_NO_MORE_DATA;
!                 goto out;
!         }
!         if (rlen > wcslen)
!                 rlen = wcslen;
!         wcsbuf[rlen] = 0;
! 
!         /*
!          * Copy the converted string into the message,
!          * truncated or paded as required.  Preserve
!          * little-endian order while copying.
!          */
!         wp = wcsbuf;
!         while (repc > 1) {
!                 smb_wchar_t wchar = LE_IN16(wp);
                  mbc_marshal_store_byte(mbc, wchar);
                  mbc_marshal_store_byte(mbc, wchar >> 8);
!                 if (wchar != 0)
!                         wp++;
!                 repc -= sizeof (smb_wchar_t);
          }
!         if (repc > 0)
!                 mbc_marshal_store_byte(mbc, 0);
! 
!         rc = 0;
! out:
!         if (wcsbuf != NULL)
!                 smb_mem_free(wcsbuf);
!         return (rc);
  }
  
  static int /*ARGSUSED*/
  uiorefnoop(caddr_t p, int size, int adj)
  {
*** 1373,1477 ****
          }
          return (0);
  }
  
  /*
!  * mbc_marshal_get_ascii_string
   *
!  * The ascii string in smb includes oem chars. Since the
!  * system needs utf8 encodes unicode char, conversion is
!  * required to convert the oem char to unicode and then
!  * to encode the converted wchars to utf8 format.
!  * Therefore, the **ascii returned will be in such format
!  * instead of the real ASCII format.
   */
  static int
! mbc_marshal_get_ascii_string(
!     smb_request_t       *sr,
!     mbuf_chain_t        *mbc,
!     uint8_t             **ascii,
!     int                 max_ascii)
  {
!         char            *rcvbuf;
!         char            *ch;
!         int             max;
!         int             length = 0;
  
!         max = MALLOC_QUANTUM;
!         rcvbuf = smb_srm_zalloc(sr, max);
  
!         if (max_ascii == 0)
!                 max_ascii = 0xffff;
! 
!         ch = rcvbuf;
          for (;;) {
!                 while (length < max) {
!                         if (max_ascii-- <= 0) {
!                                 *ch++ = 0;
!                                 goto multibyte_encode;
                          }
!                         if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
!                                 /* Data will never be available */
!                                 return (DECODE_NO_MORE_DATA);
                          }
!                         if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
!                                 goto multibyte_encode;
!                         length++;
                  }
!                 max += MALLOC_QUANTUM;
!                 rcvbuf = smb_srm_rezalloc(sr, rcvbuf, max);
!                 ch = rcvbuf + length;
!         }
  
- multibyte_encode:
          /*
!          * UTF-8 encode the string for internal system use.
           */
!         length = strlen(rcvbuf) + 1;
!         *ascii = smb_srm_zalloc(sr, length * MTS_MB_CHAR_MAX);
!         return (mbc_marshal_cstou8("CP850", (char *)*ascii,
!             (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
  }
  
  static int
  mbc_marshal_get_unicode_string(smb_request_t *sr,
!     mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode)
  {
!         int             max;
!         uint16_t        wchar;
!         char            *ch;
!         int             emitted;
!         int             length = 0;
  
!         if (max_unicode == 0)
!                 max_unicode = 0xffff;
  
!         max = MALLOC_QUANTUM;
!         *ascii = smb_srm_zalloc(sr, max);
  
!         ch = (char *)*ascii;
          for (;;) {
!                 while ((length + MTS_MB_CHAR_MAX) < max) {
!                         if (max_unicode <= 0)
!                                 goto done;
!                         max_unicode -= 2;
  
!                         if (mbc_marshal_get_short(mbc, &wchar) != 0)
!                                 return (DECODE_NO_MORE_DATA);
! 
!                         if (wchar == 0) goto done;
! 
!                         emitted = smb_wctomb(ch, wchar);
!                         length += emitted;
!                         ch += emitted;
                  }
!                 max += MALLOC_QUANTUM;
!                 *ascii = smb_srm_rezalloc(sr, *ascii, max);
!                 ch = (char *)*ascii + length;
          }
! done:   *ch = 0;
!         return (0);
  }
  
  static int /*ARGSUSED*/
  mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
  {
--- 1456,1618 ----
          }
          return (0);
  }
  
  /*
!  * mbc_marshal_get_oem_string
   *
!  * Decode an OEM string, returning its UTF-8 form in strpp,
!  * allocated using smb_srm_zalloc (automatically freed).
!  * If max_bytes != 0, consume at most max_bytes of the mbc.
!  * See also: msgbuf_get_oem_string
   */
  static int
! mbc_marshal_get_oem_string(smb_request_t *sr,
!     mbuf_chain_t *mbc, char **strpp, int max_bytes)
  {
!         char            *mbs;
!         uint8_t         *oembuf = NULL;
!         int             oemlen, oemmax;
!         int             mbsmax;
!         int             rlen;
!         int             rc;
  
!         if (max_bytes == 0)
!                 max_bytes = 0xffff;
  
!         /*
!          * Get the OtW data into a temporary buffer.
!          * Free oembuf before return.
!          */
!         oemlen = 0;
!         oemmax = MALLOC_QUANTUM;
!         oembuf = smb_mem_alloc(oemmax);
          for (;;) {
!                 uint8_t ch;
! 
!                 if (oemlen >= max_bytes)
!                         break;
!                 if ((oemlen + 2) >= oemmax) {
!                         oemmax += MALLOC_QUANTUM;
!                         oembuf = smb_mem_realloc(oembuf, oemmax);
                  }
!                 if (mbc_marshal_get_char(mbc, &ch) != 0) {
!                         rc = DECODE_NO_MORE_DATA;
!                         goto out;
                  }
!                 if (ch == 0)
!                         break;
!                 oembuf[oemlen++] = ch;
          }
!         oembuf[oemlen] = '\0';
  
          /*
!          * Get the buffer we'll return and convert to UTF-8.
!          * May take as much as double the space.
           */
!         mbsmax = oemlen * 2;
!         mbs = smb_srm_zalloc(sr, mbsmax + 1);
!         ASSERT(mbs != NULL);
!         rlen = smb_oemtombs(mbs, oembuf, mbsmax);
!         if (rlen < 0) {
!                 rc = DECODE_NO_MORE_DATA;
!                 goto out;
!         }
!         if (rlen > mbsmax)
!                 rlen = mbsmax;
!         mbs[rlen] = '\0';
!         *strpp = mbs;
!         rc = 0;
! 
! out:
!         if (oembuf != NULL)
!                 smb_mem_free(oembuf);
!         return (rc);
  }
  
+ /*
+  * mbc_marshal_get_unicode_string
+  *
+  * Decode a UTF-16 string, returning its UTF-8 form in strpp,
+  * allocated using smb_srm_zalloc (automatically freed).
+  * If max_bytes != 0, consume at most max_bytes of the mbc.
+  * See also: msgbuf_get_unicode_string
+  */
  static int
  mbc_marshal_get_unicode_string(smb_request_t *sr,
!     mbuf_chain_t *mbc, char **strpp, int max_bytes)
  {
!         char            *mbs;
!         uint16_t        *wcsbuf = NULL;
!         int             wcslen;         // wchar count
!         int             wcsmax;         // byte count
!         size_t          mbsmax;
!         size_t          rlen;
!         int             rc;
  
!         if (max_bytes == 0)
!                 max_bytes = 0xffff;
  
!         /*
!          * Unicode strings are always word aligned.
!          */
!         if (mbc->chain_offset & 1) {
!                 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0)
!                         return (DECODE_NO_MORE_DATA);
!                 mbc->chain_offset++;
!         }
  
!         /*
!          * Get the OtW data into a temporary buffer.
!          * Free wcsbuf before return.
!          */
!         wcslen = 0;
!         wcsmax = MALLOC_QUANTUM;
!         wcsbuf = smb_mem_alloc(wcsmax);
          for (;;) {
!                 uint16_t        wchar;
  
!                 if ((wcslen * 2) >= max_bytes)
!                         break;
!                 if (((wcslen * 2) + 4) >= wcsmax) {
!                         wcsmax += MALLOC_QUANTUM;
!                         wcsbuf = smb_mem_realloc(wcsbuf, wcsmax);
                  }
!                 if (mbc_marshal_get_short(mbc, &wchar) != 0) {
!                         rc = DECODE_NO_MORE_DATA;
!                         goto out;
                  }
!                 if (wchar == 0)
!                         break;
!                 /* Keep in little-endian form. */
!                 LE_OUT16(wcsbuf + wcslen, wchar);
!                 wcslen++;
!         }
!         wcsbuf[wcslen] = 0;
! 
!         /*
!          * Get the buffer we'll return and convert to UTF-8.
!          * May take as much 4X number of wide chars.
!          */
!         mbsmax = wcslen * MTS_MB_CUR_MAX;
!         mbs = smb_srm_zalloc(sr, mbsmax + 1);
!         ASSERT(mbs != NULL);
!         rlen = smb_wcstombs(mbs, wcsbuf, mbsmax);
!         if (rlen == (size_t)-1) {
!                 rc = DECODE_NO_MORE_DATA;
!                 goto out;
!         }
!         if (rlen > mbsmax)
!                 rlen = mbsmax;
!         mbs[rlen] = '\0';
!         *strpp = mbs;
!         rc = 0;
! 
! out:
!         if (wcsbuf != NULL)
!                 smb_mem_free(wcsbuf);
!         return (rc);
  }
  
  static int /*ARGSUSED*/
  mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
  {
*** 1568,1599 ****
  {
          if (MBC_ROOM_FOR(mbc, skip) == 0)
                  return (DECODE_NO_MORE_DATA);
          mbc->chain_offset += skip;
          return (0);
- }
- 
- /*
-  * Converts oem string to UTF-8 string with an output string of max
-  * maxconv bytes.  The string may be truncated or not null-terminated if
-  * there is not enough room.
-  *
-  * returns -1, cnt (partial conversion)  or 0 (success)
-  */
- 
- static int
- mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
-     char *inbuf, size_t srcbytes)
- {
-         kiconv_t        t2u;
-         size_t          inlen = srcbytes;
-         size_t          outlen = maxconv;
-         int             err = 0;
-         size_t          rc;
- 
-         if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
-                 return (-1);
- 
-         rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
-         (void) kiconv_close(t2u);
-         return ((int)rc);
  }
--- 1709,1714 ----