smb_mbuf_marshaling.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*/
#include <smbsrv/smb_incl.h>
#define MALLOC_QUANTUM 80
#define DECODE_NO_ERROR 0
#define DECODE_NO_MORE_DATA 1
#define DECODE_ALLOCATION_ERROR 2
#define DECODE_CONVERSION_ERROR 3
/*
* Put data into mbuf chain allocating as needed.
* Adds room to end of mbuf chain if needed.
*/
int
{
struct mbuf *m;
struct mbuf *l;
return (EMSGSIZE);
m->m_len = 0;
/* xxxx */
/* ^ */
}
/* ---- ----- --xx ---xxx */
/* ^ */
l = 0;
while ((m != 0) && (bytes_needed >= m->m_len)) {
l = m;
bytes_needed -= m->m_len;
m = m->m_next;
}
if ((bytes_needed == 0) || (m != 0)) {
/* We have enough room already */
return (0);
}
/* ---- ----- --xx ---xxx */
/* ^ */
/* Back up to start of last mbuf */
m = l;
bytes_needed += m->m_len;
/* ---- ----- --xx ---xxx */
/* ^ */
/* ---- ----- --xx ---xxx */
/* ^ */
m->m_len = bytes_available;
bytes_needed -= m->m_len;
/* ---- ----- --xx ------ */
/* ^ */
m = m->m_next;
m->m_len = 0;
if (bytes_needed > MLEN)
/* ---- ----- --xx ------ xxxx */
/* ^ */
}
/* ---- ----- --xx ------ xxxx */
/* ^ */
/* Expand last tail as needed */
if (m->m_len <= bytes_needed) {
m->m_len = bytes_needed;
/* ---- ----- --xx ------ --xx */
/* ^ */
}
return (0);
}
void
{
/*
* Scan forward looking for the last data currently in chain.
*/
while (cur_offset >= m->m_len) {
cur_offset -= m->m_len;
m = m->m_next;
}
mbc->chain_offset++;
}
int
{
if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
return (DECODE_NO_MORE_DATA);
return (0);
}
int
{
if (mbc_marshal_make_room(mbc, sizeof (short)))
return (DECODE_NO_MORE_DATA);
return (0);
}
int
{
return (DECODE_NO_MORE_DATA);
return (0);
}
int
{
return (DECODE_NO_MORE_DATA);
return (0);
}
/*
* When need to convert from UTF-8 (internal format) to a single
* byte string (external format ) when marshalling a string.
*/
int
{
int nbytes;
int length;
return (DECODE_NO_MORE_DATA);
length += sizeof (char);
return (DECODE_NO_MORE_DATA);
while (*mbs) {
/*
* We should restore oem chars here.
*/
if (nbytes == -1)
return (DECODE_NO_MORE_DATA);
if (wide_char & 0xFF00)
}
return (0);
}
int
{
if (delta != 0) {
return (DECODE_NO_MORE_DATA);
while (align-- > 0)
}
return (0);
}
int
{
int consumed;
int length;
return (DECODE_NO_MORE_DATA);
length += sizeof (mts_wchar_t);
#if 0
return (DECODE_NO_MORE_DATA);
#endif
return (DECODE_NO_MORE_DATA);
while (length > 0) {
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.
*/
length -= sizeof (mts_wchar_t);
}
return (0);
}
int
{
struct mbuf **t;
struct mbuf *m = 0;
for (i = 0; i < iov_cnt; i++) {
m->m_next = 0;
*t = m;
t = &m->m_next;
iov++;
}
return (0);
}
int
{
struct mbuf **t;
int bytes;
if (m != 0) {
mt = m;
}
if (bytes != 0) {
while (*t != 0) {
t = &(*t)->m_next;
}
*t = m;
} else {
m_freem(m);
}
}
return (0);
}
int
{
return (DECODE_NO_MORE_DATA);
}
return (0);
}
int
{
int i;
return (DECODE_NO_MORE_DATA);
return (DECODE_NO_MORE_DATA);
for (i = 0; i < 6; i++) {
if (mbc_marshal_put_char(mbc,
return (DECODE_NO_MORE_DATA);
}
for (i = 0; i < pSid->SubAuthCount; i++) {
return (DECODE_NO_MORE_DATA);
}
return (0);
}
int
{
return (DECODE_NO_MORE_DATA);
while (skip-- > 0)
return (0);
}
unsigned char
{
unsigned char data;
m = m->m_next;
}
mbc->chain_offset++;
return (data);
}
int
{
if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
/* Data will never be available */
return (DECODE_NO_MORE_DATA);
}
return (0);
}
int
{
unsigned short tmp;
if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
/* Data will never be available */
return (DECODE_NO_MORE_DATA);
}
m = m->m_next;
}
mbc->chain_offset += sizeof (short);
} else {
}
return (0);
}
int
{
/* Data will never be available */
return (DECODE_NO_MORE_DATA);
}
m = m->m_next;
}
} else {
}
return (0);
}
{
uint64_t v;
v = ll >> 32;
v |= ll << 32;
return (v);
}
int
{
/* Data will never be available */
return (DECODE_NO_MORE_DATA);
}
m = m->m_next;
}
} else {
}
return (0);
}
int
{
/* Data will never be available */
return (DECODE_NO_MORE_DATA);
}
m = m->m_next;
}
} else {
}
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
struct smb_malloc_list *ml,
struct mbuf_chain *mbc,
unsigned char **ascii,
int max_ascii)
{
char *rcvbuf;
char *ch;
int max;
int length = 0;
unsigned int cpid = oem_get_smb_cpid();
if (max_ascii == 0)
max_ascii = 0xffff;
for (;;) {
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);
}
goto multibyte_encode;
length++;
}
max += MALLOC_QUANTUM;
}
/*
* UTF-8 encode the string for internal system use.
*/
else
return (0);
}
int
{
int max;
unsigned short wchar;
char *ch;
int emitted;
int length = 0;
if (max_unicode == 0)
max_unicode = 0xffff;
for (;;) {
if (max_unicode <= 0)
goto done;
max_unicode -= 2;
return (DECODE_NO_MORE_DATA);
}
max += MALLOC_QUANTUM;
}
return (0);
}
int /*ARGSUSED*/
{
/* Data will never be available */
return (DECODE_NO_MORE_DATA);
}
return (0);
}
int
{
int rc;
struct mbuf *m;
if (bytes == 0) {
/* Get all the rest */
}
if (m)
m_freem(m);
return (rc);
}
while (m != 0) {
m = m->m_next;
}
return (0);
}
int
{
int i, offset;
struct mbuf *m;
/*
* The residual count is tested because in the case of write requests
* with no data (smbtorture RAW-WRITE test will generate that type of
* request) this function is called with a residual count of zero
* bytes.
*/
if (bytes) {
/* Data will never be available */
return (DECODE_NO_MORE_DATA);
}
m = m->m_next;
}
break;
}
m = m->m_next;
offset = 0;
}
if (i == uio->uio_iovcnt) {
return (DECODE_NO_MORE_DATA);
}
uio->uio_iovcnt = i;
}
return (0);
}
int
{
int i;
return (DECODE_NO_MORE_DATA);
return (DECODE_NO_MORE_DATA);
for (i = 0; i < 6; i++) {
if (mbc_marshal_get_char(mbc,
return (DECODE_NO_MORE_DATA);
}
for (i = 0; i < pSid->SubAuthCount; i++) {
return (DECODE_NO_MORE_DATA);
}
return (0);
}
int
{
return (DECODE_NO_MORE_DATA);
return (0);
}
int
{
if (delta != 0) {
}
return (0);
}
/*
* The mbuf chain passed in contains the data to be decoded.
*
* The format string provides a description of the parameters passed in as well
* as an action to be taken by smb_mbc_decode().
*
* \b Restore the mbuf chain offset to its initial value.
*
* % Pointer to an SMB request structure (smb_request_t *). There
* should be only one of these in the string.
*
* C Pointer to an mbuf chain. Copy to that mbuf chain the number of
* bytes specified (number preceding C).
*
* m Pointer to an mbuf. Copy to that mbuf the number of bytes
* specified (number preceding m).
*
* M Read the 32 bit value at the current location of the mbuf chain
* and check if it matches the signature of an SMB request (SMBX).
*
* b Pointer to a buffer. Copy to that buffer the number of bytes
* specified (number preceding b).
*
* c Same as 'b'.
*
* w Pointer to a word (16bit value). Copy the next 16bit value into
* that location.
*
* l Pointer to a long (32bit value). Copy the next 32bit value into
* that location.
*
* q Pointer to a quad (64bit value). Copy the next 64bit value into
* that location.
*
* Q Same as above with a call to qswap().
*
* B Pointer to a vardata_block structure. That structure is used to
* retrieve data from the mbuf chain (an iovec type structure is
* embedded in a vardata_block).
*
* D Pointer to a vardata_block structure. That structure is used to
* retrieve data from the mbuf chain, however, two fields of the
* vardata_block structure (tag and len) are first initialized
* using the mbuf chain itself.
*
* V Same as 'D'.
*
* L
*
* A
*
* P Same as 'A'
*
* S Same as 'A'
*
* u Pointer to a string pointer. Allocate memory and retrieve the
* string at the current location in the mbuf chain. Store the
* address to the buffer allocated at the address specified by
* the pointer. In addition if an sr was passed and it indicates
* that the string is an unicode string, convert it.
*
* s Same as 'u' without convertion.
*
* U Same as 'u'. The string to retrieve is unicode.
*
* R Not used anymore.
*
* y Pointer to a 32bit value. Read the dos time at the current mbuf
* chain location, convert it to unix time and store it at the
* location indicated by the pointer.
*
* Y Same as 'y' bt the dos time coded in the mbuf chain is inverted.
*
* . Skip the number of bytes indicated by the number preceding '.'.
*
* , Same as '.' but take in account it is an unicode string.
*
* The parameters can be named in the format string. They have to appear between
* parenthesis (indicating they should be ignored bu the decoder).
*/
int
{
unsigned char c, cval;
unsigned char *cvalp;
unsigned char **cvalpp;
unsigned short *wvalp;
unsigned int *ivalp;
struct vardata_block *vdp;
unsigned char name[32];
int unicode = 0;
int repc;
/*LINTED E_FUNC_SET_NOT_USED*/
name[0] = 0;
while ((c = *fmt++) != 0) {
repc = 1;
if (c == ' ' || c == '\t') continue;
if (c == '(') {
while (((c = *fmt++) != 0) && c != ')') {
*nm++ = c;
}
*nm = 0;
if (!c) fmt--;
continue;
}
if (c == '{') {
unsigned char op[8];
while (((c = *fmt++) != 0) && c != '}') {
*nm++ = c;
}
*nm = 0;
if (!c) fmt--;
}
continue;
}
if ('0' <= c && c <= '9') {
repc = 0;
do {
c = *fmt++;
} while ('0' <= c && c <= '9');
} else if (c == '*') {
c = *fmt++;
} else if (c == '!') {
c = *fmt++;
} else if (c == '^') {
c = *fmt++;
} else if (c == '#') {
c = *fmt++;
}
switch (c) {
default:
goto format_mismatch;
case '\b':
break;
case '%':
break;
case 'C': /* Mbuf_chain */
goto underflow;
break;
case 'm': /* struct_mbuf */
goto underflow;
break;
case 'M':
/* Data will never be available */
goto underflow;
}
goto underflow;
break;
case 'b':
case 'c':
/* Data will never be available */
goto underflow;
}
while (repc-- > 0)
break;
case 'w':
while (repc-- > 0)
goto underflow;
break;
case 'l':
while (repc-- > 0)
goto underflow;
break;
case 'q':
while (repc-- > 0)
goto underflow;
break;
case 'Q':
while (repc-- > 0)
goto underflow;
break;
case 'B':
/*LINTED E_ASSIGN_NARROW_CONV (BYTE)*/
goto underflow;
break;
case 'D': case 'V':
goto underflow;
goto underflow;
goto underflow;
}
break;
case 'L':
goto underflow;
if (cval != 2)
goto format_mismatch;
goto ascii_conversion;
case 'A': case 'P': case 'S':
goto underflow;
goto format_mismatch;
/* FALLTHROUGH */
case 'u': /* Convert from unicode if flags are set */
if (unicode)
goto unicode_translation;
/* FALLTHROUGH */
case 's':
if (repc <= 1)
repc = 0;
goto underflow;
break;
case 'U': /* Convert from unicode */
if (repc <= 1)
repc = 0;
mbc->chain_offset++;
goto underflow;
break;
case 'R':
/*
* This was used to decode RPC format unicode strings
* prior to having a DCE RPC support. It is no longer
* required.
*/
ASSERT(0);
break;
while (repc-- > 0) {
short d, t;
if (mbc_marshal_get_short(mbc,
(unsigned short *)&t) != 0)
goto underflow;
if (mbc_marshal_get_short(mbc,
(unsigned short *)&d) != 0)
goto underflow;
*lvalp++ = dosfs_dos_to_ux_time(d, t);
}
break;
while (repc-- > 0) {
short d, t;
if (mbc_marshal_get_short(mbc,
(unsigned short *)&d) != 0)
goto underflow;
if (mbc_marshal_get_short(mbc,
(unsigned short *)&t) != 0)
goto underflow;
*lvalp++ = dosfs_dos_to_ux_time(d, t);
}
break;
case ',':
if (unicode)
repc *= 2;
/* FALLTHROUGH */
case '.':
goto underflow;
break;
}
}
return (0);
return (-1);
return (-1);
}
int
{
int xx;
return (xx);
}
int
{
int rc;
struct mbuf_chain mbc;
return (rc);
}
/*
* The mbuf chain passed in will receive the encoded data.
*
* The format string provides a description of the parameters passed in as well
* as an action to be taken by smb_mbc_encode().
*
* \b Restore the mbuf chain offset to its initial value.
*
* % Pointer to an SMB request structure (smb_request_t *). There
* should be only one of these in the string. If an sr in present
* it will be used to determine if unicode conversion should be
* applied to the strings.
*
* C Pointer to an mbuf chain. Copy that mbuf chain into the
* destination mbuf chain.
*
* D Pointer to a vardata_block structure. Copy the data described
* by that structure into the mbuf chain. The tag field is hard
* coded to '1'.
*
* M Write the SMB request signature ('SMBX') into the mbuf chain.
*
* T Pointer to a timestruc_t. Convert the content of the structure
* into NT time and store the result of the conversion in the
* mbuf chain.
*
* V Same as 'D' but the tag field is hard coded to '5'.
*
* b Byte. Store the byte or the nymber of bytes specified into the
* the mbuf chain. A format string like this "2b" would require 2
* bytes to be passed in.
*
* m Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
* chain.
*
* c Pointer to a buffer. Copy the buffer into the mbuf chain. The
* size of the buffer is indicated by the number preceding 'c'.
*
* w Word (16bit value). Store the word or the number of words
* specified into the the mbuf chain. A format string like this
* "2w" would require 2 words to be passed in.
*
* l Long (32bit value). Store the long or the number of longs
* specified into the the mbuf chain. A format string like this
* "2l" would require 2 longs to be passed in.
*
* q Quad (64bit value). Store the quad or the number of quads
* specified into the the mbuf chain. A format string like this
* "2q" would require 2 quads to be passed in.
*
* L Pointer to a string. Store the string passed in into the mbuf
* chain preceded with a tag value of '2'.
*
* S Pointer to a string. Store the string passed in into the mbuf
* chain preceded with a tag value of '4'. Applied a unicode
* conversion is appropriate.
*
* A Same as 'S'
*
* P Pointer to a string. Store the string passed in into the mbuf
* chain preceded with a tag value of '5'. Applied a unicode
* conversion is appropriate.
*
* u Pointer to a string. Store the string passed in into the mbuf
* chain. Applied a unicode conversion is appropriate.
*
* s Pointer to a string. Store the string passed in into the mbuf
* chain.
*
* specified into the the mbuf chain. A format string like this
* converted to DOS before storing.
*
* y Same as 'Y'. The order of Date and Time is reversed.
*
* , Character. Store the character or number of character specified
* into the mbuf chain. A format string like this "2c" would
* require 2 characters to be passed in. A unicode conversion is
* applied if appropriate.
*
* . Same as '`' without unicode conversion.
*
* U Align the offset of the mbuf chain on a 16bit boundary.
*
* Z Unicode string. Store the unicode string into the mbuf chain
* without alignment considerations.
*
* The parameters can be named in the format string. They have to appear between
* parenthesis (indicating they should be ignored bu the encoder).
*/
int
{
unsigned char name[32];
unsigned char cval, c;
unsigned short wval;
unsigned int tag;
unsigned char *cvalp;
unsigned int *ivalp;
struct vardata_block *vdp;
struct smb_request *sr = 0;
int unicode = 0;
int repc = 1;
/*LINTED E_FUNC_SET_NOT_USED*/
while ((c = *fmt++) != 0) {
name[0] = 0;
repc = 1;
if (c == ' ' || c == '\t') continue;
if (c == '(') {
while (((c = *fmt++) != 0) && c != ')') {
*nm++ = c;
}
*nm = 0;
if (!c) fmt--;
continue;
}
if (c == '{') {
unsigned char op[8];
while (((c = *fmt++) != 0) && c != '}') {
*nm++ = c;
}
*nm = 0;
if (!c) fmt--;
}
continue;
}
if ('0' <= c && c <= '9') {
repc = 0;
do {
c = *fmt++;
} while ('0' <= c && c <= '9');
} else if (c == '*') {
c = *fmt++;
} else if (c == '!') {
c = *fmt++;
} else if (c == '^') {
c = *fmt++;
} else if (c == '#') {
c = *fmt++;
}
switch (c) {
default:
goto format_mismatch;
case '%':
break;
case 'C': /* Mbuf_chain */
return (DECODE_NO_MORE_DATA);
break;
case 'D':
return (DECODE_NO_MORE_DATA);
return (DECODE_NO_MORE_DATA);
return (DECODE_NO_MORE_DATA);
break;
case 'M':
/* 0xFF S M B */
return (DECODE_NO_MORE_DATA);
break;
case 'T':
return (DECODE_NO_MORE_DATA);
break;
case 'V':
return (DECODE_NO_MORE_DATA);
return (DECODE_NO_MORE_DATA);
return (DECODE_NO_MORE_DATA);
break;
case 'b':
while (repc-- > 0) {
return (DECODE_NO_MORE_DATA);
}
break;
case 'm': /* struct_mbuf */
if (mbc_marshal_put_mbufs(mbc,
return (DECODE_NO_MORE_DATA);
break;
case 'c':
while (repc-- > 0) {
if (mbc_marshal_put_char(mbc,
*cvalp++) != 0)
return (DECODE_NO_MORE_DATA);
}
break;
case 'w':
while (repc-- > 0) {
return (DECODE_NO_MORE_DATA);
}
break;
case 'l':
while (repc-- > 0) {
return (DECODE_NO_MORE_DATA);
}
break;
case 'q':
while (repc-- > 0) {
return (DECODE_NO_MORE_DATA);
}
break;
case 'L':
tag = 2;
goto ascii_conversion;
case 'S':
return (DECODE_NO_MORE_DATA);
/* FALLTHROUGH */
case 'u': /* Convert from unicode if flags are set */
if (unicode)
goto unicode_translation;
/* FALLTHROUGH */
return (DECODE_NO_MORE_DATA);
break;
while (repc-- > 0) {
unsigned short d, t;
(void) dosfs_ux_to_dos_time(lval,
(short *)&d, (short *)&t);
if (mbc_marshal_put_short(mbc, t) != 0)
return (DECODE_NO_MORE_DATA);
if (mbc_marshal_put_short(mbc, d) != 0)
return (DECODE_NO_MORE_DATA);
}
break;
while (repc-- > 0) {
unsigned short d, t;
(void) dosfs_ux_to_dos_time(lval,
(short *)&d, (short *)&t);
if (mbc_marshal_put_short(mbc, d) != 0)
return (DECODE_NO_MORE_DATA);
if (mbc_marshal_put_short(mbc, t) != 0)
return (DECODE_NO_MORE_DATA);
}
break;
case ',':
if (unicode)
repc *= 2;
/* FALLTHROUGH */
case '.':
while (repc-- > 0)
if (mbc_marshal_put_char(mbc, 0) != 0)
return (DECODE_NO_MORE_DATA);
break;
case 'R':
/*
* This was used to encode RPC format unicode strings
* prior to having a DCE RPC support. It is no longer
* required.
*/
ASSERT(0);
break;
case 'U': /* Convert to unicode, align to word boundary */
mbc->chain_offset++;
/* FALLTHROUGH */
case 'Z': /* Convert to unicode, no alignment adjustment */
return (DECODE_NO_MORE_DATA);
break;
}
}
return (0);
return (-1);
}
int
{
int rc;
return (rc);
}
int
{
int rc;
struct mbuf_chain mbc;
return (rc);
}
int
{
int rc;
return (rc);
}
int
{
/* NOTREACHED */
}
return (0);
}
void
{
/* NOTREACHED */
}
/*LINTED E_ASSIGN_NARROW_CONV*/
/*LINTED E_ASSIGN_NARROW_CONV*/
}
int
{
int xx;
struct mbuf_chain tmp;
return (xx);
}
int
{
int xx;
struct mbuf_chain tmp;
return (xx);
}