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 ----