Print this page
1575 untangle libmlrpc ... (libmlrpc)
@@ -20,10 +20,11 @@
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Network Data Representation (NDR) is a compatible subset of the DCE RPC
* and MSRPC NDR. NDR is used to move parameters consisting of
@@ -32,18 +33,16 @@
#include <sys/byteorder.h>
#include <strings.h>
#include <assert.h>
#include <string.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <smbsrv/libsmb.h>
-#include <smbsrv/string.h>
-#include <smbsrv/libmlrpc.h>
+#include <libmlrpc.h>
+#include <ndr_wchar.h>
-#define NDR_STRING_MAX 4096
-
#define NDR_IS_UNION(T) \
(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
#define NDR_IS_STRING(T) \
(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
@@ -1208,21 +1207,26 @@
if (ti == &ndt_s_wchar) {
/*
* size_is is the number of characters in the
* (multibyte) string, including the null.
+ * In other words, symbols, not bytes.
*/
- size_is = smb_wcequiv_strlen(valp) /
- sizeof (smb_wchar_t);
-
- if (!(nds->flags & NDS_F_NONULL))
- ++size_is;
-
- if (size_is > NDR_STRING_MAX) {
+ size_t wlen;
+ wlen = ndr__mbstowcs(NULL, valp, NDR_STRING_MAX);
+ if (wlen == (size_t)-1) {
+ /* illegal sequence error? */
NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
return (0);
}
+ if ((nds->flags & NDS_F_NONULL) == 0)
+ wlen++;
+ if (wlen > NDR_STRING_MAX) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
+ return (0);
+ }
+ size_is = wlen;
} else {
valp = outer_ref->datum;
n_zeroes = 0;
for (ix = 0; ix < NDR_STRING_MAX; ix++) {
if (valp[ix] == 0) {
@@ -1286,11 +1290,11 @@
* Decoding Unicode to UTF-8; we need to allow
* for the maximum possible char size. It would
* be nice to use mbequiv_strlen but the string
* may not be null terminated.
*/
- n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX;
+ n_alloc = (size_is + 1) * NDR_MB_CHAR_MAX;
} else {
n_alloc = (size_is + 1) * is_varlen;
}
valp = NDS_MALLOC(nds, n_alloc, outer_ref);
@@ -1739,11 +1743,11 @@
myref.packed_alignment = 0;
myref.ti = ti;
myref.inner_flags = NDR_F_NONE;
for (i = 0; i < n_elem; i++) {
- (void) sprintf(name, "[%lu]", i);
+ (void) snprintf(name, sizeof (name), "[%lu]", i);
myref.name = name;
myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
if (!ndr_inner(&myref))
@@ -1794,20 +1798,20 @@
MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
int ndr_basic_integer(ndr_ref_t *, unsigned);
int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *);
+/* Comments to be nice to those searching for these types. */
+MAKE_BASIC_TYPE(_char, 1) /* ndt__char, ndt_s_char */
+MAKE_BASIC_TYPE(_uchar, 1) /* ndt__uchar, ndt_s_uchar */
+MAKE_BASIC_TYPE(_short, 2) /* ndt__short, ndt_s_short */
+MAKE_BASIC_TYPE(_ushort, 2) /* ndt__ushort, ndt_s_ushort */
+MAKE_BASIC_TYPE(_long, 4) /* ndt__long, ndt_s_long */
+MAKE_BASIC_TYPE(_ulong, 4) /* ndt__ulong, ndt_s_ulong */
-MAKE_BASIC_TYPE(_char, 1)
-MAKE_BASIC_TYPE(_uchar, 1)
-MAKE_BASIC_TYPE(_short, 2)
-MAKE_BASIC_TYPE(_ushort, 2)
-MAKE_BASIC_TYPE(_long, 4)
-MAKE_BASIC_TYPE(_ulong, 4)
+MAKE_BASIC_TYPE_BASE(_wchar, 2) /* ndt__wchar, ndt_s_wchar */
-MAKE_BASIC_TYPE_BASE(_wchar, 2)
-
int
ndr_basic_integer(ndr_ref_t *ref, unsigned size)
{
ndr_stream_t *nds = ref->stream;
char *valp = (char *)ref->datum;
@@ -1852,11 +1856,11 @@
myref.ti = type_under;
myref.inner_flags = NDR_F_NONE;
myref.name = name;
for (i = 0; i < NDR_STRING_MAX; i++) {
- (void) sprintf(name, "[%lu]", i);
+ (void) snprintf(name, sizeof (name), "[%lu]", i);
myref.pdu_offset = pdu_offset + i * size;
valp = encl_ref->datum + i * size;
myref.datum = valp;
if (!ndr_inner(&myref))
@@ -1895,32 +1899,32 @@
* Hand coded wchar function because all strings are transported
* as wide characters. During NDR_M_OP_MARSHALL, we convert from
* multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
* convert from wide characters to multi-byte.
*
- * It appeared that NT would sometimes leave a spurious character
- * in the data stream before the null wide_char, which would get
- * included in the string decode because we processed until the
- * null character. It now looks like NT does not always terminate
- * RPC Unicode strings and the terminating null is a side effect
- * of field alignment. So now we rely on the strlen_is (set up in
- * ndr_outer_string) of the enclosing reference. This may or may
- * not include the null but it doesn't matter, the algorithm will
- * get it right.
+ * The most critical thing to get right in this function is to
+ * marshall or unmarshall _exactly_ the number of elements the
+ * OtW length specifies, as saved by the caller in: strlen_is.
+ * Doing otherwise would leave us positioned at the wrong place
+ * in the data stream for whatever follows this. Note that the
+ * string data covered by strlen_is may or may not include any
+ * null termination, but the converted string provided by the
+ * caller or returned always has a null terminator.
*/
int
ndr_s_wchar(ndr_ref_t *encl_ref)
{
ndr_stream_t *nds = encl_ref->stream;
- unsigned short wide_char;
- char *valp;
+ char *valp = encl_ref->datum;
ndr_ref_t myref;
- unsigned long i;
char name[30];
- int count;
- int char_count = 0;
+ ndr_wchar_t wcs[NDR_STRING_MAX+1];
+ size_t i, slen, wlen;
+ /* This is enforced in ndr_outer_string() */
+ assert(encl_ref->strlen_is <= NDR_STRING_MAX);
+
if (nds->m_op == NDR_M_OP_UNMARSHALL) {
/*
* To avoid problems with zero length strings
* we can just null terminate here and be done.
*/
@@ -1928,65 +1932,66 @@
encl_ref->datum[0] = '\0';
return (1);
}
}
+ /*
+ * If we're marshalling, convert the given string
+ * from UTF-8 into a local UCS-2 string.
+ */
+ if (nds->m_op == NDR_M_OP_MARSHALL) {
+ wlen = ndr__mbstowcs(wcs, valp, NDR_STRING_MAX);
+ if (wlen == (size_t)-1)
+ return (0);
+ /*
+ * Add a nulls to make strlen_is.
+ * (always zero or one of them)
+ * Then null terminate at wlen,
+ * just for debug convenience.
+ */
+ while (wlen < encl_ref->strlen_is)
+ wcs[wlen++] = 0;
+ wcs[wlen] = 0;
+ }
+
+ /*
+ * Copy wire data to or from the local wc string.
+ * Always exactly strlen_is elements.
+ */
bzero(&myref, sizeof (myref));
myref.enclosing = encl_ref;
myref.stream = encl_ref->stream;
myref.packed_alignment = 0;
myref.ti = &ndt__wchar;
myref.inner_flags = NDR_F_NONE;
- myref.datum = (char *)&wide_char;
myref.name = name;
myref.pdu_offset = encl_ref->pdu_offset;
+ myref.datum = (char *)wcs;
+ wlen = encl_ref->strlen_is;
- valp = encl_ref->datum;
- count = 0;
-
- for (i = 0; i < NDR_STRING_MAX; i++) {
- (void) sprintf(name, "[%lu]", i);
-
- if (nds->m_op == NDR_M_OP_MARSHALL) {
- count = smb_mbtowc((smb_wchar_t *)&wide_char, valp,
- MTS_MB_CHAR_MAX);
- if (count < 0) {
+ for (i = 0; i < wlen; i++) {
+ (void) snprintf(name, sizeof (name), "[%lu]", i);
+ if (!ndr_inner(&myref))
return (0);
- } else if (count == 0) {
- if (encl_ref->strlen_is != encl_ref->size_is)
- break;
+ myref.pdu_offset += sizeof (ndr_wchar_t);
+ myref.datum += sizeof (ndr_wchar_t);
+ }
/*
- * If the input char is 0, mbtowc
- * returns 0 without setting wide_char.
- * Set wide_char to 0 and a count of 1.
+ * If this is unmarshall, convert the local UCS-2 string
+ * into a UTF-8 string in the caller's buffer. The caller
+ * previously determined the space required and provides a
+ * buffer of sufficient size.
*/
- wide_char = *valp;
- count = 1;
- }
- }
-
- if (!ndr_inner(&myref))
- return (0);
-
if (nds->m_op == NDR_M_OP_UNMARSHALL) {
- count = smb_wctomb(valp, wide_char);
-
- if ((++char_count) == encl_ref->strlen_is) {
- valp += count;
- *valp = '\0';
- break;
+ wcs[wlen] = 0;
+ slen = ndr__wcstombs(valp, wcs, wlen);
+ if (slen == (size_t)-1)
+ return (0);
+ valp[slen] = '\0';
}
- }
- if (!wide_char)
- break;
-
- myref.pdu_offset += sizeof (wide_char);
- valp += count;
- }
-
return (1);
}
/*
* Converts a multibyte character string to a little-endian, wide-char
@@ -1995,53 +2000,22 @@
*
* Returns the number of wide characters converted, not counting
* any terminating null wide character. Returns -1 if an invalid
* multibyte character is encountered.
*/
+/* ARGSUSED */
size_t
-ndr_mbstowcs(ndr_stream_t *nds, smb_wchar_t *wcs, const char *mbs,
+ndr_mbstowcs(ndr_stream_t *nds, ndr_wchar_t *wcs, const char *mbs,
size_t nwchars)
{
- smb_wchar_t *start = wcs;
- int nbytes;
+ size_t len;
- while (nwchars--) {
- nbytes = ndr_mbtowc(nds, wcs, mbs, MTS_MB_CHAR_MAX);
- if (nbytes < 0) {
- *wcs = 0;
- return ((size_t)-1);
- }
-
- if (*mbs == 0)
- break;
-
- ++wcs;
- mbs += nbytes;
- }
-
- return (wcs - start);
-}
-
-/*
- * Converts a multibyte character to a little-endian, wide-char, which
- * is stored in wcharp. Up to nbytes bytes are examined.
- *
- * If mbchar is valid, returns the number of bytes processed in mbchar.
- * If mbchar is invalid, returns -1. See also smb_mbtowc().
- */
-/*ARGSUSED*/
-int
-ndr_mbtowc(ndr_stream_t *nds, smb_wchar_t *wcharp, const char *mbchar,
- size_t nbytes)
-{
- int rc;
-
- if ((rc = smb_mbtowc(wcharp, mbchar, nbytes)) < 0)
- return (rc);
-
#ifdef _BIG_ENDIAN
- if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND))
- *wcharp = BSWAP_16(*wcharp);
+ if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) {
+ /* Make WC string in LE order. */
+ len = ndr__mbstowcs_le(wcs, mbs, nwchars);
+ } else
#endif
+ len = ndr__mbstowcs(wcs, mbs, nwchars);
- return (rc);
+ return (len);
}