Clean up channel chunk sending code
Make sure the buffer handling is a bit more sane so we can verify offsets and boundaries. Also adds some more helper macros to shuffle data between two different STREAM instead of trying to poke around in the internals.
This commit is contained in:
parent
c6d8b933c8
commit
655c3d56df
131
channels.c
131
channels.c
@ -80,66 +80,101 @@ channel_init(VCHANNEL * channel, uint32 length)
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
channel_send(STREAM s, VCHANNEL * channel)
|
||||
static void
|
||||
channel_send_chunk(STREAM s, VCHANNEL * channel, uint32 length)
|
||||
{
|
||||
uint32 length, flags;
|
||||
uint32 thislength, remaining;
|
||||
uint8 *data;
|
||||
uint32 flags;
|
||||
uint32 thislength;
|
||||
RD_BOOL inplace;
|
||||
STREAM chunk;
|
||||
|
||||
#ifdef WITH_SCARD
|
||||
scard_lock(SCARD_LOCK_CHANNEL);
|
||||
#endif
|
||||
|
||||
/* first fragment sent in-place */
|
||||
s_pop_layer(s, channel_hdr);
|
||||
length = s_remaining(s) - 8;
|
||||
|
||||
logger(Protocol, Debug, "channel_send(), channel = %d, length = %d", channel->mcs_id,
|
||||
length);
|
||||
|
||||
thislength = MIN(length, vc_chunk_size);
|
||||
/* Note: In the original clipboard implementation, this number was
|
||||
1592, not 1600. However, I don't remember the reason and 1600 seems
|
||||
to work so.. This applies only to *this* length, not the length of
|
||||
continuation or ending packets. */
|
||||
/* Note: In the original clipboard implementation, this number was
|
||||
1592, not 1600. However, I don't remember the reason and 1600 seems
|
||||
to work so.. This applies only to *this* length, not the length of
|
||||
continuation or ending packets. */
|
||||
|
||||
/* Actually, CHANNEL_CHUNK_LENGTH (default value is 1600 bytes) is described
|
||||
in MS-RDPBCGR (s. 2.2.6, s.3.1.5.2.1) and can be set by server only
|
||||
in the optional field VCChunkSize of VC Caps) */
|
||||
|
||||
remaining = length - thislength;
|
||||
flags = (remaining == 0) ? CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST : CHANNEL_FLAG_FIRST;
|
||||
if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
|
||||
flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
|
||||
thislength = MIN(s_remaining(s), vc_chunk_size);
|
||||
|
||||
out_uint32_le(s, length);
|
||||
out_uint32_le(s, flags);
|
||||
data = s->end = s->p + thislength;
|
||||
logger(Protocol, Debug, "channel_send(), sending %d bytes with FLAG_FIRST set", thislength);
|
||||
sec_send_to_channel(s, g_encryption ? SEC_ENCRYPT : 0, channel->mcs_id);
|
||||
|
||||
/* subsequent segments copied (otherwise would have to generate headers backwards) */
|
||||
while (remaining > 0)
|
||||
flags = 0;
|
||||
if (length == s_remaining(s))
|
||||
{
|
||||
thislength = MIN(remaining, vc_chunk_size);
|
||||
remaining -= thislength;
|
||||
flags = (remaining == 0) ? CHANNEL_FLAG_LAST : 0;
|
||||
if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
|
||||
flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
|
||||
flags |= CHANNEL_FLAG_FIRST;
|
||||
}
|
||||
if (s_remaining(s) == thislength)
|
||||
{
|
||||
flags |= CHANNEL_FLAG_LAST;
|
||||
}
|
||||
if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
|
||||
{
|
||||
flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
|
||||
}
|
||||
|
||||
logger(Protocol, Debug, "channel_send(), sending %d bytes with flags 0x%x",
|
||||
thislength, flags);
|
||||
logger(Protocol, Debug, "channel_send_chunk(), sending %d bytes with flags 0x%x",
|
||||
thislength, flags);
|
||||
|
||||
s = sec_init(g_encryption ? SEC_ENCRYPT : 0, thislength + 8);
|
||||
out_uint32_le(s, length);
|
||||
out_uint32_le(s, flags);
|
||||
out_uint8a(s, data, thislength);
|
||||
s_mark_end(s);
|
||||
sec_send_to_channel(s, g_encryption ? SEC_ENCRYPT : 0, channel->mcs_id);
|
||||
s_free(s);
|
||||
/* first fragment sent in-place */
|
||||
inplace = False;
|
||||
if ((flags & (CHANNEL_FLAG_FIRST|CHANNEL_FLAG_LAST)) ==
|
||||
(CHANNEL_FLAG_FIRST|CHANNEL_FLAG_LAST))
|
||||
{
|
||||
inplace = True;
|
||||
}
|
||||
|
||||
data += thislength;
|
||||
if (inplace)
|
||||
{
|
||||
s_pop_layer(s, channel_hdr);
|
||||
chunk = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk = sec_init(g_encryption ? SEC_ENCRYPT : 0, thislength + 8);
|
||||
}
|
||||
|
||||
out_uint32_le(chunk, length);
|
||||
out_uint32_le(chunk, flags);
|
||||
if (!inplace)
|
||||
{
|
||||
out_uint8stream(chunk, s, thislength);
|
||||
s_mark_end(chunk);
|
||||
}
|
||||
sec_send_to_channel(chunk, g_encryption ? SEC_ENCRYPT : 0, channel->mcs_id);
|
||||
|
||||
/* Sending modifies the current offset, so make it is marked as
|
||||
fully completed. */
|
||||
if (inplace)
|
||||
{
|
||||
in_uint8s(s, s_remaining(s));
|
||||
}
|
||||
|
||||
if (!inplace)
|
||||
{
|
||||
s_free(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
channel_send(STREAM s, VCHANNEL * channel)
|
||||
{
|
||||
uint32 length;
|
||||
|
||||
#ifdef WITH_SCARD
|
||||
scard_lock(SCARD_LOCK_CHANNEL);
|
||||
#endif
|
||||
|
||||
s_pop_layer(s, channel_hdr);
|
||||
in_uint8s(s, 8);
|
||||
length = s_remaining(s);
|
||||
|
||||
logger(Protocol, Debug, "channel_send(), channel = %d, length = %d", channel->mcs_id,
|
||||
length);
|
||||
|
||||
while (!s_check_end(s))
|
||||
{
|
||||
channel_send_chunk(s, channel, length);
|
||||
}
|
||||
|
||||
#ifdef WITH_SCARD
|
||||
|
6
stream.h
6
stream.h
@ -138,6 +138,12 @@ size_t in_ansi_string(STREAM s, char *string, size_t len);
|
||||
/* Copy n bytes from array v in to STREAM s */
|
||||
#define out_uint8a(s,v,n) { s_assert_w(s, n); memcpy((s)->p,v,n); (s)->p += n; }
|
||||
#define out_uint8s(s,n) { s_assert_w(s, n); memset((s)->p,0,n); (s)->p += n; }
|
||||
|
||||
/* Copy n bytes from STREAM s in to STREAM v */
|
||||
#define in_uint8stream(s,v,n) { s_assert_r(s, n); out_uint8a((v), (s)->p, n); (s)->p += n; }
|
||||
/* Copy n bytes in to STREAM s from STREAM v */
|
||||
#define out_uint8stream(s,v,n) in_uint8stream(v,s,n)
|
||||
/* Copy the entire STREAM v (ignoring offsets) in to STREAM s */
|
||||
#define out_stream(s, v) out_uint8a(s, (v)->data, s_length((v)))
|
||||
|
||||
#define next_be(s,v) { s_assert_r(s, 1); v = ((v) << 8) + *((s)->p++); }
|
||||
|
Loading…
Reference in New Issue
Block a user