Merge branch 'secfix' of https://github.com/CendioOssman/rdesktop
This commit is contained in:
commit
a88cd226bb
14
asn.c
14
asn.c
@ -41,10 +41,16 @@ ber_parse_header(STREAM s, int tagval, uint32 *length)
|
||||
|
||||
if (tagval > 0xff)
|
||||
{
|
||||
if (!s_check_rem(s, 2)) {
|
||||
return False;
|
||||
}
|
||||
in_uint16_be(s, tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!s_check_rem(s, 1)) {
|
||||
return False;
|
||||
}
|
||||
in_uint8(s, tag);
|
||||
}
|
||||
|
||||
@ -54,11 +60,17 @@ ber_parse_header(STREAM s, int tagval, uint32 *length)
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!s_check_rem(s, 1)) {
|
||||
return False;
|
||||
}
|
||||
in_uint8(s, len);
|
||||
|
||||
if (len & 0x80)
|
||||
{
|
||||
len &= ~0x80;
|
||||
if (!s_check_rem(s, len)) {
|
||||
return False;
|
||||
}
|
||||
*length = 0;
|
||||
while (len--)
|
||||
next_be(s, *length);
|
||||
@ -66,7 +78,7 @@ ber_parse_header(STREAM s, int tagval, uint32 *length)
|
||||
else
|
||||
*length = len;
|
||||
|
||||
return s_check(s);
|
||||
return True;
|
||||
}
|
||||
|
||||
void
|
||||
|
147
channels.c
147
channels.c
@ -80,65 +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->end - s->p - 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_uint8p(s, data, thislength);
|
||||
s_mark_end(s);
|
||||
sec_send_to_channel(s, g_encryption ? SEC_ENCRYPT : 0, channel->mcs_id);
|
||||
/* 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
|
||||
@ -150,7 +186,6 @@ void
|
||||
channel_process(STREAM s, uint16 mcs_channel)
|
||||
{
|
||||
uint32 length, flags;
|
||||
uint32 thislength;
|
||||
VCHANNEL *channel = NULL;
|
||||
unsigned int i;
|
||||
STREAM in;
|
||||
@ -178,22 +213,16 @@ channel_process(STREAM s, uint16 mcs_channel)
|
||||
in = &channel->in;
|
||||
if (flags & CHANNEL_FLAG_FIRST)
|
||||
{
|
||||
if (length > in->size)
|
||||
{
|
||||
in->data = (uint8 *) xrealloc(in->data, length);
|
||||
in->size = length;
|
||||
}
|
||||
in->p = in->data;
|
||||
s_realloc(in, length);
|
||||
s_reset(in);
|
||||
}
|
||||
|
||||
thislength = MIN(s->end - s->p, in->data + in->size - in->p);
|
||||
memcpy(in->p, s->p, thislength);
|
||||
in->p += thislength;
|
||||
out_uint8stream(in, s, s_remaining(s));
|
||||
|
||||
if (flags & CHANNEL_FLAG_LAST)
|
||||
{
|
||||
in->end = in->p;
|
||||
in->p = in->data;
|
||||
s_mark_end(in);
|
||||
s_seek(in, 0);
|
||||
channel->process(in);
|
||||
}
|
||||
}
|
||||
|
12
cliprdr.c
12
cliprdr.c
@ -48,10 +48,11 @@ cliprdr_send_packet(uint16 type, uint16 status, uint8 * data, uint32 length)
|
||||
out_uint16_le(s, type);
|
||||
out_uint16_le(s, status);
|
||||
out_uint32_le(s, length);
|
||||
out_uint8p(s, data, length);
|
||||
out_uint8a(s, data, length);
|
||||
out_uint32(s, 0); /* pad? */
|
||||
s_mark_end(s);
|
||||
channel_send(s, cliprdr_channel);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Helper which announces our readiness to supply clipboard data
|
||||
@ -118,21 +119,14 @@ cliprdr_process(STREAM s)
|
||||
uint16 type, status;
|
||||
uint32 length, format;
|
||||
uint8 *data;
|
||||
struct stream packet = *s;
|
||||
|
||||
in_uint16_le(s, type);
|
||||
in_uint16_le(s, status);
|
||||
in_uint32_le(s, length);
|
||||
data = s->p;
|
||||
|
||||
logger(Clipboard, Debug, "cliprdr_process(), type=%d, status=%d, length=%d", type, status,
|
||||
length);
|
||||
|
||||
if (!s_check_rem(s, length))
|
||||
{
|
||||
rdp_protocol_error("cliprdr_process(), consume of packet from stream would overrun", &packet);
|
||||
}
|
||||
|
||||
if (status == CLIPRDR_ERROR)
|
||||
{
|
||||
switch (type)
|
||||
@ -160,6 +154,7 @@ cliprdr_process(STREAM s)
|
||||
ui_clip_sync();
|
||||
break;
|
||||
case CLIPRDR_FORMAT_ANNOUNCE:
|
||||
in_uint8p(s, data, length);
|
||||
ui_clip_format_announce(data, length);
|
||||
cliprdr_send_packet(CLIPRDR_FORMAT_ACK, CLIPRDR_RESPONSE, NULL, 0);
|
||||
return;
|
||||
@ -170,6 +165,7 @@ cliprdr_process(STREAM s)
|
||||
ui_clip_request_data(format);
|
||||
break;
|
||||
case CLIPRDR_DATA_RESPONSE:
|
||||
in_uint8p(s, data, length);
|
||||
ui_clip_handle_data(data, length);
|
||||
break;
|
||||
case 7: /* TODO: W2K3 SP1 sends this on connect with a value of 1 */
|
||||
|
268
cssp.c
268
cssp.c
@ -36,14 +36,9 @@ ber_wrap_hdr_data(int tagval, STREAM in)
|
||||
STREAM out;
|
||||
int size = s_length(in) + 16;
|
||||
|
||||
out = xmalloc(sizeof(struct stream));
|
||||
memset(out, 0, sizeof(struct stream));
|
||||
out->data = xmalloc(size);
|
||||
out->size = size;
|
||||
out->p = out->data;
|
||||
|
||||
out = s_alloc(size);
|
||||
ber_out_header(out, tagval, s_length(in));
|
||||
out_uint8p(out, in->data, s_length(in));
|
||||
out_stream(out, in);
|
||||
s_mark_end(out);
|
||||
|
||||
return out;
|
||||
@ -144,16 +139,19 @@ cssp_gss_get_service_name(char *server, gss_name_t * name)
|
||||
|
||||
}
|
||||
|
||||
static RD_BOOL
|
||||
cssp_gss_wrap(gss_ctx_id_t ctx, STREAM in, STREAM out)
|
||||
static STREAM
|
||||
cssp_gss_wrap(gss_ctx_id_t ctx, STREAM in)
|
||||
{
|
||||
int conf_state;
|
||||
OM_uint32 major_status;
|
||||
OM_uint32 minor_status;
|
||||
gss_buffer_desc inbuf, outbuf;
|
||||
STREAM out;
|
||||
|
||||
inbuf.value = in->data;
|
||||
s_seek(in, 0);
|
||||
inbuf.length = s_length(in);
|
||||
in_uint8p(in, inbuf.value, s_length(in));
|
||||
s_seek(in, 0);
|
||||
|
||||
major_status = gss_wrap(&minor_status, ctx, True,
|
||||
GSS_C_QOP_DEFAULT, &inbuf, &conf_state, &outbuf);
|
||||
@ -162,38 +160,41 @@ cssp_gss_wrap(gss_ctx_id_t ctx, STREAM in, STREAM out)
|
||||
{
|
||||
cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to encrypt and sign message",
|
||||
major_status, minor_status);
|
||||
return False;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!conf_state)
|
||||
{
|
||||
logger(Core, Error,
|
||||
"cssp_gss_wrap(), GSS Confidentiality failed, no encryption of message performed.");
|
||||
return False;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// write enc data to out stream
|
||||
out->data = out->p = xmalloc(outbuf.length);
|
||||
out->size = outbuf.length;
|
||||
out_uint8p(out, outbuf.value, outbuf.length);
|
||||
out = s_alloc(outbuf.length);
|
||||
out_uint8a(out, outbuf.value, outbuf.length);
|
||||
s_mark_end(out);
|
||||
s_seek(out, 0);
|
||||
|
||||
gss_release_buffer(&minor_status, &outbuf);
|
||||
|
||||
return True;
|
||||
return out;
|
||||
}
|
||||
|
||||
static RD_BOOL
|
||||
cssp_gss_unwrap(gss_ctx_id_t ctx, STREAM in, STREAM out)
|
||||
static STREAM
|
||||
cssp_gss_unwrap(gss_ctx_id_t ctx, STREAM in)
|
||||
{
|
||||
OM_uint32 major_status;
|
||||
OM_uint32 minor_status;
|
||||
gss_qop_t qop_state;
|
||||
gss_buffer_desc inbuf, outbuf;
|
||||
int conf_state;
|
||||
STREAM out;
|
||||
|
||||
inbuf.value = in->data;
|
||||
s_seek(in, 0);
|
||||
inbuf.length = s_length(in);
|
||||
in_uint8p(in, inbuf.value, s_length(in));
|
||||
s_seek(in, 0);
|
||||
|
||||
major_status = gss_unwrap(&minor_status, ctx, &inbuf, &outbuf, &conf_state, &qop_state);
|
||||
|
||||
@ -201,17 +202,17 @@ cssp_gss_unwrap(gss_ctx_id_t ctx, STREAM in, STREAM out)
|
||||
{
|
||||
cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to decrypt message",
|
||||
major_status, minor_status);
|
||||
return False;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out->data = out->p = xmalloc(outbuf.length);
|
||||
out->size = outbuf.length;
|
||||
out_uint8p(out, outbuf.value, outbuf.length);
|
||||
out = s_alloc(outbuf.length);
|
||||
out_uint8a(out, outbuf.value, outbuf.length);
|
||||
s_mark_end(out);
|
||||
s_seek(out, 0);
|
||||
|
||||
gss_release_buffer(&minor_status, &outbuf);
|
||||
|
||||
return True;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@ -234,7 +235,7 @@ cssp_encode_tspasswordcreds(char *username, char *password, char *domain)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -247,7 +248,7 @@ cssp_encode_tspasswordcreds(char *username, char *password, char *domain)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -259,7 +260,7 @@ cssp_encode_tspasswordcreds(char *username, char *password, char *domain)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -295,7 +296,7 @@ cssp_encode_tscspdatadetail(unsigned char keyspec, char *card, char *reader, cha
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -309,7 +310,7 @@ cssp_encode_tscspdatadetail(unsigned char keyspec, char *card, char *reader, cha
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -324,7 +325,7 @@ cssp_encode_tscspdatadetail(unsigned char keyspec, char *card, char *reader, cha
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -339,7 +340,7 @@ cssp_encode_tscspdatadetail(unsigned char keyspec, char *card, char *reader, cha
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -354,7 +355,7 @@ cssp_encode_tscspdatadetail(unsigned char keyspec, char *card, char *reader, cha
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 4, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -387,7 +388,7 @@ cssp_encode_tssmartcardcreds(char *username, char *password, char *domain)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -397,7 +398,7 @@ cssp_encode_tssmartcardcreds(char *username, char *password, char *domain)
|
||||
g_sc_container_name, g_sc_csp_name);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -411,7 +412,7 @@ cssp_encode_tssmartcardcreds(char *username, char *password, char *domain)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -426,7 +427,7 @@ cssp_encode_tssmartcardcreds(char *username, char *password, char *domain)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -467,7 +468,7 @@ cssp_encode_tscredentials(char *username, char *password, char *domain)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -485,7 +486,7 @@ cssp_encode_tscredentials(char *username, char *password, char *domain)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, h3);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h3);
|
||||
s_free(h2);
|
||||
@ -521,7 +522,7 @@ cssp_send_tsrequest(STREAM token, STREAM auth, STREAM pubkey)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -535,7 +536,7 @@ cssp_send_tsrequest(STREAM token, STREAM auth, STREAM pubkey)
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, h3);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h5);
|
||||
s_free(h4);
|
||||
@ -551,7 +552,7 @@ cssp_send_tsrequest(STREAM token, STREAM auth, STREAM pubkey)
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
|
||||
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -564,7 +565,7 @@ cssp_send_tsrequest(STREAM token, STREAM auth, STREAM pubkey)
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
|
||||
|
||||
s_realloc(&message, s_length(&message) + s_length(h1));
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
out_stream(&message, h1);
|
||||
s_mark_end(&message);
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
@ -575,11 +576,12 @@ cssp_send_tsrequest(STREAM token, STREAM auth, STREAM pubkey)
|
||||
// Todo: can h1 be send directly instead of tcp_init() approach
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message);
|
||||
s = tcp_init(s_length(h1));
|
||||
out_uint8p(s, h1->data, s_length(h1));
|
||||
out_stream(s, h1);
|
||||
s_mark_end(s);
|
||||
s_free(h1);
|
||||
|
||||
tcp_send(s);
|
||||
s_free(s);
|
||||
|
||||
// cleanup
|
||||
xfree(message.data);
|
||||
@ -589,10 +591,10 @@ cssp_send_tsrequest(STREAM token, STREAM auth, STREAM pubkey)
|
||||
}
|
||||
|
||||
|
||||
RD_BOOL
|
||||
cssp_read_tsrequest(STREAM token, STREAM pubkey)
|
||||
STREAM
|
||||
cssp_read_tsrequest(RD_BOOL pubkey)
|
||||
{
|
||||
STREAM s;
|
||||
STREAM s, out;
|
||||
int length;
|
||||
int tagval;
|
||||
struct stream packet;
|
||||
@ -600,96 +602,83 @@ cssp_read_tsrequest(STREAM token, STREAM pubkey)
|
||||
s = tcp_recv(NULL, 4);
|
||||
|
||||
if (s == NULL)
|
||||
return False;
|
||||
return NULL;
|
||||
|
||||
// verify ASN.1 header
|
||||
if (s->p[0] != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
|
||||
{
|
||||
logger(Protocol, Error,
|
||||
"cssp_read_tsrequest(), expected BER_TAG_SEQUENCE|BER_TAG_CONSTRUCTED, got %x",
|
||||
s->p[0]);
|
||||
return False;
|
||||
}
|
||||
// get and verify the header
|
||||
if (!ber_in_header(s, &tagval, &length) ||
|
||||
tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
|
||||
return NULL;
|
||||
|
||||
// peek at first 4 bytes to get full message length
|
||||
if (s->p[1] < 0x80)
|
||||
length = s->p[1] - 2;
|
||||
else if (s->p[1] == 0x81)
|
||||
length = s->p[2] - 1;
|
||||
else if (s->p[1] == 0x82)
|
||||
length = (s->p[2] << 8) | s->p[3];
|
||||
else
|
||||
return False;
|
||||
// We've already read 4 bytes, but the header might have been
|
||||
// less than that, so we need to adjust the length
|
||||
length -= s_remaining(s);
|
||||
|
||||
// receive the remainings of message
|
||||
s = tcp_recv(s, length);
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
packet = *s;
|
||||
|
||||
// parse the response and into nego token
|
||||
if (!ber_in_header(s, &tagval, &length) ||
|
||||
tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
|
||||
return False;
|
||||
|
||||
// version [0]
|
||||
if (!ber_in_header(s, &tagval, &length) ||
|
||||
tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0))
|
||||
return False;
|
||||
return NULL;
|
||||
|
||||
if (!s_check_rem(s, length))
|
||||
{
|
||||
rdp_protocol_error("cssp_read_tsrequest(), consume of version from stream would overrun",
|
||||
rdp_protocol_error("consume of version from stream would overrun",
|
||||
&packet);
|
||||
}
|
||||
in_uint8s(s, length);
|
||||
|
||||
// negoToken [1]
|
||||
if (token)
|
||||
if (!pubkey)
|
||||
{
|
||||
if (!ber_in_header(s, &tagval, &length)
|
||||
|| tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1))
|
||||
return False;
|
||||
return NULL;
|
||||
if (!ber_in_header(s, &tagval, &length)
|
||||
|| tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
|
||||
return False;
|
||||
return NULL;
|
||||
if (!ber_in_header(s, &tagval, &length)
|
||||
|| tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
|
||||
return False;
|
||||
return NULL;
|
||||
if (!ber_in_header(s, &tagval, &length)
|
||||
|| tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0))
|
||||
return False;
|
||||
return NULL;
|
||||
|
||||
if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING)
|
||||
return False;
|
||||
return NULL;
|
||||
|
||||
if (!s_check_rem(s, length))
|
||||
{
|
||||
rdp_protocol_error("cssp_read_tsrequest(), consume of token from stream would overrun",
|
||||
rdp_protocol_error("consume of token from stream would overrun",
|
||||
&packet);
|
||||
}
|
||||
|
||||
s_realloc(token, length);
|
||||
s_reset(token);
|
||||
out_uint8p(token, s->p, length);
|
||||
s_mark_end(token);
|
||||
out = s_alloc(length);
|
||||
out_uint8stream(out, s, length);
|
||||
s_mark_end(out);
|
||||
s_seek(out, 0);
|
||||
}
|
||||
|
||||
// pubKey [3]
|
||||
if (pubkey)
|
||||
else
|
||||
{
|
||||
if (!ber_in_header(s, &tagval, &length)
|
||||
|| tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3))
|
||||
return False;
|
||||
return NULL;
|
||||
|
||||
if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING)
|
||||
return False;
|
||||
return NULL;
|
||||
|
||||
pubkey->data = pubkey->p = s->p;
|
||||
pubkey->end = pubkey->data + length;
|
||||
pubkey->size = length;
|
||||
out = s_alloc(length);
|
||||
out_uint8stream(out, s, length);
|
||||
s_mark_end(out);
|
||||
s_seek(out, 0);
|
||||
}
|
||||
|
||||
|
||||
return True;
|
||||
return out;
|
||||
}
|
||||
|
||||
RD_BOOL
|
||||
@ -706,9 +695,14 @@ cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
|
||||
gss_OID desired_mech = &_gss_spnego_krb5_mechanism_oid_desc;
|
||||
|
||||
STREAM ts_creds;
|
||||
struct stream token = { 0 };
|
||||
struct stream pubkey = { 0 };
|
||||
struct stream pubkey_cmp = { 0 };
|
||||
STREAM token;
|
||||
STREAM pubkey, pubkey_cmp;
|
||||
unsigned char *pubkey_data;
|
||||
unsigned char *pubkey_cmp_data;
|
||||
unsigned char first_byte;
|
||||
|
||||
RD_BOOL ret;
|
||||
STREAM blob;
|
||||
|
||||
// Verify that system gss support spnego
|
||||
if (!cssp_gss_mech_available(desired_mech))
|
||||
@ -732,16 +726,19 @@ cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
|
||||
return False;
|
||||
}
|
||||
|
||||
tcp_tls_get_server_pubkey(&pubkey);
|
||||
pubkey = tcp_tls_get_server_pubkey();
|
||||
if (pubkey == NULL)
|
||||
return False;
|
||||
pubkey_cmp = NULL;
|
||||
|
||||
// Enter the spnego loop
|
||||
OM_uint32 actual_services;
|
||||
gss_OID actual_mech;
|
||||
struct stream blob = { 0 };
|
||||
|
||||
gss_ctx = GSS_C_NO_CONTEXT;
|
||||
cred = GSS_C_NO_CREDENTIAL;
|
||||
|
||||
token = NULL;
|
||||
input_tok.length = 0;
|
||||
output_tok.length = 0;
|
||||
minor_status = 0;
|
||||
@ -762,6 +759,11 @@ cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
|
||||
&actual_mech,
|
||||
&output_tok, &actual_services, &actual_time);
|
||||
|
||||
// input_tok might have pointed to token's data,
|
||||
// but it's safe to free it now after the call
|
||||
s_free(token);
|
||||
token = NULL;
|
||||
|
||||
if (GSS_ERROR(major_status))
|
||||
{
|
||||
if (i == 0)
|
||||
@ -786,39 +788,44 @@ cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
|
||||
// Send token to server
|
||||
if (output_tok.length != 0)
|
||||
{
|
||||
if (output_tok.length > token.size)
|
||||
s_realloc(&token, output_tok.length);
|
||||
s_reset(&token);
|
||||
token = s_alloc(output_tok.length);
|
||||
out_uint8a(token, output_tok.value, output_tok.length);
|
||||
s_mark_end(token);
|
||||
|
||||
out_uint8p(&token, output_tok.value, output_tok.length);
|
||||
s_mark_end(&token);
|
||||
|
||||
if (!cssp_send_tsrequest(&token, NULL, NULL))
|
||||
goto bail_out;
|
||||
ret = cssp_send_tsrequest(token, NULL, NULL);
|
||||
|
||||
s_free(token);
|
||||
token = NULL;
|
||||
(void) gss_release_buffer(&minor_status, &output_tok);
|
||||
|
||||
if (!ret)
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
// Read token from server
|
||||
if (major_status & GSS_S_CONTINUE_NEEDED)
|
||||
{
|
||||
(void) gss_release_buffer(&minor_status, &input_tok);
|
||||
|
||||
if (!cssp_read_tsrequest(&token, NULL))
|
||||
token = cssp_read_tsrequest(False);
|
||||
if (token == NULL)
|
||||
goto bail_out;
|
||||
|
||||
input_tok.value = token.data;
|
||||
input_tok.length = s_length(&token);
|
||||
input_tok.length = s_length(token);
|
||||
in_uint8p(token, input_tok.value, input_tok.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send encrypted pubkey for verification to server
|
||||
context_established = 1;
|
||||
|
||||
if (!cssp_gss_wrap(gss_ctx, &pubkey, &blob))
|
||||
blob = cssp_gss_wrap(gss_ctx, pubkey);
|
||||
if (blob == NULL)
|
||||
goto bail_out;
|
||||
|
||||
if (!cssp_send_tsrequest(NULL, NULL, &blob))
|
||||
ret = cssp_send_tsrequest(NULL, NULL, blob);
|
||||
|
||||
s_free(blob);
|
||||
|
||||
if (!ret)
|
||||
goto bail_out;
|
||||
|
||||
context_established = 1;
|
||||
@ -829,37 +836,62 @@ cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
|
||||
}
|
||||
while (!context_established);
|
||||
|
||||
s_free(token);
|
||||
|
||||
// read tsrequest response and decrypt for public key validation
|
||||
if (!cssp_read_tsrequest(NULL, &blob))
|
||||
blob = cssp_read_tsrequest(True);
|
||||
if (blob == NULL)
|
||||
goto bail_out;
|
||||
|
||||
if (!cssp_gss_unwrap(gss_ctx, &blob, &pubkey_cmp))
|
||||
pubkey_cmp = cssp_gss_unwrap(gss_ctx, blob);
|
||||
s_free(blob);
|
||||
if (pubkey_cmp == NULL)
|
||||
goto bail_out;
|
||||
|
||||
pubkey_cmp.data[0] -= 1;
|
||||
// the first byte gets 1 added before being sent by the server
|
||||
// in order to protect against replays of the data sent earlier
|
||||
// by the client
|
||||
in_uint8(pubkey_cmp, first_byte);
|
||||
s_seek(pubkey_cmp, 0);
|
||||
out_uint8(pubkey_cmp, first_byte - 1);
|
||||
s_seek(pubkey_cmp, 0);
|
||||
|
||||
// validate public key
|
||||
if (memcmp(pubkey.data, pubkey_cmp.data, s_length(&pubkey)) != 0)
|
||||
in_uint8p(pubkey, pubkey_data, s_length(pubkey));
|
||||
in_uint8p(pubkey_cmp, pubkey_cmp_data, s_length(pubkey_cmp));
|
||||
if ((s_length(pubkey) != s_length(pubkey_cmp)) ||
|
||||
(memcmp(pubkey_data, pubkey_cmp_data, s_length(pubkey)) != 0))
|
||||
{
|
||||
logger(Core, Error,
|
||||
"cssp_connect(), public key mismatch, cannot guarantee integrity of server connection");
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
s_free(pubkey);
|
||||
s_free(pubkey_cmp);
|
||||
|
||||
// Send TSCredentials
|
||||
ts_creds = cssp_encode_tscredentials(user, password, domain);
|
||||
|
||||
if (!cssp_gss_wrap(gss_ctx, ts_creds, &blob))
|
||||
goto bail_out;
|
||||
blob = cssp_gss_wrap(gss_ctx, ts_creds);
|
||||
|
||||
s_free(ts_creds);
|
||||
|
||||
if (!cssp_send_tsrequest(NULL, &blob, NULL))
|
||||
if (blob == NULL)
|
||||
goto bail_out;
|
||||
|
||||
ret = cssp_send_tsrequest(NULL, blob, NULL);
|
||||
|
||||
s_free(blob);
|
||||
|
||||
if (!ret)
|
||||
goto bail_out;
|
||||
|
||||
return True;
|
||||
|
||||
bail_out:
|
||||
xfree(token.data);
|
||||
s_free(token);
|
||||
s_free(pubkey);
|
||||
s_free(pubkey_cmp);
|
||||
return False;
|
||||
}
|
||||
|
57
disk.c
57
disk.c
@ -1131,10 +1131,7 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
||||
struct STATFS_T stat_fs;
|
||||
struct fileinfo *pfinfo;
|
||||
FsInfoType *fsinfo;
|
||||
struct stream stmp;
|
||||
|
||||
memset(&stmp, 0, sizeof(stmp));
|
||||
s_realloc(&stmp, PATH_MAX * 4);
|
||||
STREAM stmp;
|
||||
|
||||
logger(Disk, Debug, "disk_query_volume_information(handle=0x%x, info_class=0x%x)", handle,
|
||||
info_class);
|
||||
@ -1153,16 +1150,17 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
||||
switch (info_class)
|
||||
{
|
||||
case FileFsVolumeInformation:
|
||||
s_reset(&stmp);
|
||||
out_utf16s(&stmp, fsinfo->label);
|
||||
s_mark_end(&stmp);
|
||||
stmp = s_alloc(PATH_MAX * 4);
|
||||
out_utf16s(stmp, fsinfo->label);
|
||||
s_mark_end(stmp);
|
||||
|
||||
out_uint32_le(out, 0); /* volume creation time low */
|
||||
out_uint32_le(out, 0); /* volume creation time high */
|
||||
out_uint32_le(out, fsinfo->serial); /* serial */
|
||||
out_uint32_le(out, s_length(&stmp)); /* length of string */
|
||||
out_uint32_le(out, s_length(stmp)); /* length of string */
|
||||
out_uint8(out, 0); /* support objects? */
|
||||
out_stream(out, &stmp); /* fsinfo->label string */
|
||||
out_stream(out, stmp); /* fsinfo->label string */
|
||||
s_free(stmp);
|
||||
break;
|
||||
|
||||
case FileFsSizeInformation:
|
||||
@ -1183,15 +1181,16 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
||||
break;
|
||||
|
||||
case FileFsAttributeInformation:
|
||||
s_reset(&stmp);
|
||||
out_utf16s_no_eos(&stmp, fsinfo->type);
|
||||
s_mark_end(&stmp);
|
||||
stmp = s_alloc(PATH_MAX * 4);
|
||||
out_utf16s_no_eos(stmp, fsinfo->type);
|
||||
s_mark_end(stmp);
|
||||
|
||||
out_uint32_le(out, FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED); /* fs attributes */
|
||||
out_uint32_le(out, F_NAMELEN(stat_fs)); /* max length of filename */
|
||||
|
||||
out_uint32_le(out, s_length(&stmp)); /* length of fsinfo->type string */
|
||||
out_stream(out, &stmp); /* fsinfo->typ string */
|
||||
out_uint32_le(out, s_length(stmp)); /* length of fsinfo->type string */
|
||||
out_stream(out, stmp); /* fsinfo->typ string */
|
||||
s_free(stmp);
|
||||
break;
|
||||
|
||||
case FileFsLabelInformation:
|
||||
@ -1218,7 +1217,7 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
||||
struct dirent *pdirent;
|
||||
struct stat filestat;
|
||||
struct fileinfo *pfinfo;
|
||||
struct stream stmp;
|
||||
STREAM stmp;
|
||||
|
||||
logger(Disk, Debug, "disk_query_directory(handle=0x%x, info_class=0x%x, pattern=%s, ...)",
|
||||
handle, info_class, pattern);
|
||||
@ -1228,9 +1227,6 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
||||
dirname = pfinfo->path;
|
||||
file_attributes = 0;
|
||||
|
||||
memset(&stmp, 0, sizeof(stmp));
|
||||
s_realloc(&stmp, PATH_MAX * 4);
|
||||
|
||||
switch (info_class)
|
||||
{
|
||||
case FileBothDirectoryInformation:
|
||||
@ -1299,9 +1295,9 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
||||
}
|
||||
|
||||
// Write entry name as utf16 into stmp
|
||||
s_reset(&stmp);
|
||||
out_utf16s_no_eos(&stmp, pdirent->d_name);
|
||||
s_mark_end(&stmp);
|
||||
stmp = s_alloc(PATH_MAX * 4);
|
||||
out_utf16s_no_eos(stmp, pdirent->d_name);
|
||||
s_mark_end(stmp);
|
||||
|
||||
switch (info_class)
|
||||
{
|
||||
@ -1327,11 +1323,11 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
||||
out_uint64_le(out, filestat.st_size); /* filesize */
|
||||
out_uint64_le(out, filestat.st_size); /* filesize */
|
||||
out_uint32_le(out, file_attributes); /* FileAttributes */
|
||||
out_uint32_le(out, s_length(&stmp)); /* length of dir entry name string */
|
||||
out_uint32_le(out, s_length(stmp)); /* length of dir entry name string */
|
||||
out_uint32_le(out, 0); /* EaSize */
|
||||
out_uint8(out, 0); /* ShortNameLength */
|
||||
out_uint8s(out, 24); /* ShortName (8.3 name) */
|
||||
out_stream(out, &stmp); /* dir entry name string */
|
||||
out_stream(out, stmp); /* dir entry name string */
|
||||
break;
|
||||
|
||||
|
||||
@ -1357,8 +1353,8 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
||||
out_uint64_le(out, filestat.st_size); /* filesize */
|
||||
out_uint64_le(out, filestat.st_size); /* filesize */
|
||||
out_uint32_le(out, file_attributes);
|
||||
out_uint32_le(out, s_length(&stmp)); /* dir entry name string length */
|
||||
out_stream(out, &stmp); /* dir entry name */
|
||||
out_uint32_le(out, s_length(stmp)); /* dir entry name string length */
|
||||
out_stream(out, stmp); /* dir entry name */
|
||||
break;
|
||||
|
||||
|
||||
@ -1384,16 +1380,16 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
||||
out_uint64_le(out, filestat.st_size); /* filesize */
|
||||
out_uint64_le(out, filestat.st_size); /* filesize */
|
||||
out_uint32_le(out, file_attributes);
|
||||
out_uint32_le(out, s_length(&stmp)); /* dir entry name string length */
|
||||
out_uint32_le(out, s_length(stmp)); /* dir entry name string length */
|
||||
out_uint32_le(out, 0); /* EaSize */
|
||||
out_stream(out, &stmp); /* dir entry name */
|
||||
out_stream(out, stmp); /* dir entry name */
|
||||
break;
|
||||
|
||||
|
||||
case FileNamesInformation:
|
||||
|
||||
out_uint32_le(out, s_length(&stmp)); /* dir entry name string length */
|
||||
out_stream(out, &stmp); /* dir entry name */
|
||||
out_uint32_le(out, s_length(stmp)); /* dir entry name string length */
|
||||
out_stream(out, stmp); /* dir entry name */
|
||||
break;
|
||||
|
||||
|
||||
@ -1401,9 +1397,12 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
||||
logger(Disk, Warning,
|
||||
"disk_query_directory(), unhandled directory info class 0x%x",
|
||||
info_class);
|
||||
s_free(stmp);
|
||||
return RD_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
s_free(stmp);
|
||||
|
||||
return RD_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
3
dvc.c
3
dvc.c
@ -268,6 +268,7 @@ dvc_send(const char *name, STREAM s)
|
||||
s_mark_end(ls);
|
||||
|
||||
channel_send(ls, dvc_channel);
|
||||
s_free(ls);
|
||||
}
|
||||
|
||||
|
||||
@ -292,6 +293,7 @@ dvc_send_capabilities_response()
|
||||
s_mark_end(s);
|
||||
|
||||
channel_send(s, dvc_channel);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -320,6 +322,7 @@ dvc_send_create_response(RD_BOOL success, dvc_hdr_t hdr, uint32 channelid)
|
||||
s_mark_end(s);
|
||||
|
||||
channel_send(s, dvc_channel);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
static void
|
||||
|
8
iso.c
8
iso.c
@ -55,6 +55,7 @@ iso_send_msg(uint8 code)
|
||||
|
||||
s_mark_end(s);
|
||||
tcp_send(s);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -78,8 +79,8 @@ iso_send_connection_request(char *username, uint32 neg_proto)
|
||||
out_uint16(s, 0); /* src_ref */
|
||||
out_uint8(s, 0); /* class */
|
||||
|
||||
out_uint8p(s, "Cookie: mstshash=", strlen("Cookie: mstshash="));
|
||||
out_uint8p(s, username, strlen(username));
|
||||
out_uint8a(s, "Cookie: mstshash=", strlen("Cookie: mstshash="));
|
||||
out_uint8a(s, username, strlen(username));
|
||||
|
||||
out_uint8(s, 0x0d); /* cookie termination string: CR+LF */
|
||||
out_uint8(s, 0x0a);
|
||||
@ -95,6 +96,7 @@ iso_send_connection_request(char *username, uint32 neg_proto)
|
||||
|
||||
s_mark_end(s);
|
||||
tcp_send(s);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Receive a message on the ISO layer, return code */
|
||||
@ -177,7 +179,7 @@ iso_send(STREAM s)
|
||||
uint16 length;
|
||||
|
||||
s_pop_layer(s, iso_hdr);
|
||||
length = s->end - s->p;
|
||||
length = s_remaining(s);
|
||||
|
||||
out_uint8(s, T123_HEADER_VERSION); /* version */
|
||||
out_uint8(s, 0); /* reserved */
|
||||
|
37
licence.c
37
licence.c
@ -79,24 +79,25 @@ licence_info(uint8 * client_random, uint8 * rsa_data,
|
||||
out_uint16(s, 0);
|
||||
out_uint16_le(s, 0x0201);
|
||||
|
||||
out_uint8p(s, client_random, SEC_RANDOM_SIZE);
|
||||
out_uint8a(s, client_random, SEC_RANDOM_SIZE);
|
||||
out_uint16_le(s, 2);
|
||||
out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE));
|
||||
out_uint8p(s, rsa_data, SEC_MODULUS_SIZE);
|
||||
out_uint8a(s, rsa_data, SEC_MODULUS_SIZE);
|
||||
out_uint8s(s, SEC_PADDING_SIZE);
|
||||
|
||||
out_uint16_le(s, 1);
|
||||
out_uint16_le(s, licence_size);
|
||||
out_uint8p(s, licence_data, licence_size);
|
||||
out_uint8a(s, licence_data, licence_size);
|
||||
|
||||
out_uint16_le(s, 1);
|
||||
out_uint16_le(s, LICENCE_HWID_SIZE);
|
||||
out_uint8p(s, hwid, LICENCE_HWID_SIZE);
|
||||
out_uint8a(s, hwid, LICENCE_HWID_SIZE);
|
||||
|
||||
out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE);
|
||||
out_uint8a(s, signature, LICENCE_SIGNATURE_SIZE);
|
||||
|
||||
s_mark_end(s);
|
||||
sec_send(s, sec_flags);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Send a new licence request packet */
|
||||
@ -120,24 +121,25 @@ licence_send_new_licence_request(uint8 * client_random, uint8 * rsa_data, char *
|
||||
out_uint16(s, 0);
|
||||
out_uint16_le(s, 0xff01);
|
||||
|
||||
out_uint8p(s, client_random, SEC_RANDOM_SIZE);
|
||||
out_uint8a(s, client_random, SEC_RANDOM_SIZE);
|
||||
out_uint16_le(s, 2);
|
||||
out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE));
|
||||
out_uint8p(s, rsa_data, SEC_MODULUS_SIZE);
|
||||
out_uint8a(s, rsa_data, SEC_MODULUS_SIZE);
|
||||
out_uint8s(s, SEC_PADDING_SIZE);
|
||||
|
||||
/* Username LICENSE_BINARY_BLOB */
|
||||
out_uint16_le(s, BB_CLIENT_USER_NAME_BLOB);
|
||||
out_uint16_le(s, userlen);
|
||||
out_uint8p(s, user, userlen);
|
||||
out_uint8a(s, user, userlen);
|
||||
|
||||
/* Machinename LICENSE_BINARY_BLOB */
|
||||
out_uint16_le(s, BB_CLIENT_MACHINE_NAME_BLOB);
|
||||
out_uint16_le(s, hostlen);
|
||||
out_uint8p(s, host, hostlen);
|
||||
out_uint8a(s, host, hostlen);
|
||||
|
||||
s_mark_end(s);
|
||||
sec_send(s, sec_flags);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Process a licence request packet */
|
||||
@ -204,16 +206,17 @@ licence_send_platform_challenge_response(uint8 * token, uint8 * crypt_hwid, uint
|
||||
|
||||
out_uint16_le(s, 1);
|
||||
out_uint16_le(s, LICENCE_TOKEN_SIZE);
|
||||
out_uint8p(s, token, LICENCE_TOKEN_SIZE);
|
||||
out_uint8a(s, token, LICENCE_TOKEN_SIZE);
|
||||
|
||||
out_uint16_le(s, 1);
|
||||
out_uint16_le(s, LICENCE_HWID_SIZE);
|
||||
out_uint8p(s, crypt_hwid, LICENCE_HWID_SIZE);
|
||||
out_uint8a(s, crypt_hwid, LICENCE_HWID_SIZE);
|
||||
|
||||
out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE);
|
||||
out_uint8a(s, signature, LICENCE_SIGNATURE_SIZE);
|
||||
|
||||
s_mark_end(s);
|
||||
sec_send(s, sec_flags);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Parse an platform challenge request packet */
|
||||
@ -274,6 +277,7 @@ licence_process_platform_challenge(STREAM s)
|
||||
static void
|
||||
licence_process_new_license(STREAM s)
|
||||
{
|
||||
unsigned char *data;
|
||||
RDSSL_RC4 crypt_key;
|
||||
uint32 length;
|
||||
int i;
|
||||
@ -283,8 +287,12 @@ licence_process_new_license(STREAM s)
|
||||
if (!s_check_rem(s, length))
|
||||
return;
|
||||
|
||||
inout_uint8p(s, data, length);
|
||||
|
||||
rdssl_rc4_set_key(&crypt_key, g_licence_key, 16);
|
||||
rdssl_rc4_crypt(&crypt_key, s->p, s->p, length);
|
||||
rdssl_rc4_crypt(&crypt_key, data, data, length);
|
||||
|
||||
s_seek(s, s_tell(s) - length);
|
||||
|
||||
/* Parse NEW_LICENSE_INFO block */
|
||||
in_uint8s(s, 4); // skip dwVersion
|
||||
@ -301,7 +309,8 @@ licence_process_new_license(STREAM s)
|
||||
}
|
||||
|
||||
g_licence_issued = True;
|
||||
save_licence(s->p, length);
|
||||
in_uint8p(s, data, length);
|
||||
save_licence(data, length);
|
||||
}
|
||||
|
||||
/* process a licence error alert packet */
|
||||
|
14
lspci.c
14
lspci.c
@ -135,17 +135,12 @@ lspci_process(STREAM s)
|
||||
unsigned int pkglen;
|
||||
static char *rest = NULL;
|
||||
char *buf;
|
||||
struct stream packet = *s;
|
||||
|
||||
if (!s_check(s))
|
||||
{
|
||||
rdp_protocol_error("lspci_process(), stream is in unstable state", &packet);
|
||||
}
|
||||
|
||||
pkglen = s->end - s->p;
|
||||
pkglen = s_remaining(s);
|
||||
/* str_handle_lines requires null terminated strings */
|
||||
buf = xmalloc(pkglen + 1);
|
||||
STRNCPY(buf, (char *) s->p, pkglen + 1);
|
||||
in_uint8a(s, buf, pkglen);
|
||||
buf[pkglen] = '\0';
|
||||
str_handle_lines(buf, &rest, lspci_process_line, NULL);
|
||||
xfree(buf);
|
||||
}
|
||||
@ -169,6 +164,7 @@ lspci_send(const char *output)
|
||||
|
||||
len = strlen(output);
|
||||
s = channel_init(lspci_channel, len);
|
||||
out_uint8p(s, output, len) s_mark_end(s);
|
||||
out_uint8a(s, output, len) s_mark_end(s);
|
||||
channel_send(s, lspci_channel);
|
||||
s_free(s);
|
||||
}
|
||||
|
31
mcs.c
31
mcs.c
@ -42,7 +42,7 @@ mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens,
|
||||
}
|
||||
|
||||
/* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */
|
||||
static RD_BOOL
|
||||
static void
|
||||
mcs_parse_domain_params(STREAM s)
|
||||
{
|
||||
uint32 length;
|
||||
@ -52,19 +52,17 @@ mcs_parse_domain_params(STREAM s)
|
||||
|
||||
if (!s_check_rem(s, length))
|
||||
{
|
||||
rdp_protocol_error("mcs_parse_domain_params(), consume domain params from stream would overrun", &packet);
|
||||
rdp_protocol_error("consume domain params from stream would overrun", &packet);
|
||||
}
|
||||
|
||||
in_uint8s(s, length);
|
||||
|
||||
return s_check(s);
|
||||
}
|
||||
|
||||
/* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */
|
||||
static void
|
||||
mcs_send_connect_initial(STREAM mcs_data)
|
||||
{
|
||||
int datalen = mcs_data->end - mcs_data->data;
|
||||
int datalen = s_length(mcs_data);
|
||||
int length = 9 + 3 * 34 + 4 + datalen;
|
||||
STREAM s;
|
||||
logger(Protocol, Debug, "%s()", __func__);
|
||||
@ -84,10 +82,11 @@ mcs_send_connect_initial(STREAM mcs_data)
|
||||
mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */
|
||||
|
||||
ber_out_header(s, BER_TAG_OCTET_STRING, datalen);
|
||||
out_uint8p(s, mcs_data->data, datalen);
|
||||
out_uint8a(s, mcs_data->data, datalen);
|
||||
|
||||
s_mark_end(s);
|
||||
iso_send(s);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */
|
||||
@ -125,7 +124,7 @@ mcs_recv_connect_response(STREAM mcs_data)
|
||||
|
||||
if (!s_check_rem(s, length))
|
||||
{
|
||||
rdp_protocol_error("mcs_recv_connect_response(), consume connect id from stream would overrun", &packet);
|
||||
rdp_protocol_error("consume connect id from stream would overrun", &packet);
|
||||
}
|
||||
|
||||
mcs_parse_domain_params(s);
|
||||
@ -140,9 +139,10 @@ mcs_recv_connect_response(STREAM mcs_data)
|
||||
length = mcs_data->size;
|
||||
}
|
||||
|
||||
in_uint8a(s, mcs_data->data, length);
|
||||
mcs_data->p = mcs_data->data;
|
||||
mcs_data->end = mcs_data->data + length;
|
||||
s_reset(mcs_data);
|
||||
in_uint8stream(s, mcs_data, length);
|
||||
s_mark_end(mcs_data);
|
||||
s_seek(mcs_data, 0);
|
||||
*/
|
||||
return s_check_end(s);
|
||||
}
|
||||
@ -161,6 +161,7 @@ mcs_send_edrq(void)
|
||||
|
||||
s_mark_end(s);
|
||||
iso_send(s);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Send an AUrq message (ASN.1 PER) */
|
||||
@ -175,6 +176,7 @@ mcs_send_aurq(void)
|
||||
|
||||
s_mark_end(s);
|
||||
iso_send(s);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Expect a AUcf message (ASN.1 PER) */
|
||||
@ -228,6 +230,7 @@ mcs_send_cjrq(uint16 chanid)
|
||||
|
||||
s_mark_end(s);
|
||||
iso_send(s);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Expect a CJcf message (ASN.1 PER) */
|
||||
@ -275,10 +278,7 @@ mcs_send_dpu(unsigned short reason)
|
||||
|
||||
logger(Protocol, Debug, "mcs_send_dpu(), reason=%d", reason);
|
||||
|
||||
contents = malloc(sizeof(struct stream));
|
||||
memset(contents, 0, sizeof(struct stream));
|
||||
s_realloc(contents, 6);
|
||||
s_reset(contents);
|
||||
contents = s_alloc(6);
|
||||
ber_out_integer(contents, reason); /* Reason */
|
||||
ber_out_sequence(contents, NULL); /* SEQUENCE OF NonStandradParameters OPTIONAL */
|
||||
s_mark_end(contents);
|
||||
@ -290,6 +290,7 @@ mcs_send_dpu(unsigned short reason)
|
||||
s_mark_end(s);
|
||||
|
||||
iso_send(s);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Initialise an MCS transport data packet */
|
||||
@ -311,7 +312,7 @@ mcs_send_to_channel(STREAM s, uint16 channel)
|
||||
uint16 length;
|
||||
|
||||
s_pop_layer(s, mcs_hdr);
|
||||
length = s->end - s->p - 8;
|
||||
length = s_remaining(s) - 8;
|
||||
length |= 0x8000;
|
||||
|
||||
out_uint8(s, (MCS_SDRQ << 2));
|
||||
|
26
orders.c
26
orders.c
@ -20,7 +20,7 @@
|
||||
#include "rdesktop.h"
|
||||
#include "orders.h"
|
||||
|
||||
extern uint8 *g_next_packet;
|
||||
extern size_t g_next_packet;
|
||||
static RDP_ORDER_STATE g_order_state;
|
||||
extern RDP_VERSION g_rdp_version;
|
||||
|
||||
@ -101,7 +101,7 @@ rdp_in_colour(STREAM s, uint32 * colour)
|
||||
}
|
||||
|
||||
/* Parse bounds information */
|
||||
static RD_BOOL
|
||||
static void
|
||||
rdp_parse_bounds(STREAM s, BOUNDS * bounds)
|
||||
{
|
||||
uint8 present;
|
||||
@ -127,12 +127,10 @@ rdp_parse_bounds(STREAM s, BOUNDS * bounds)
|
||||
rdp_in_coord(s, &bounds->bottom, False);
|
||||
else if (present & 128)
|
||||
rdp_in_coord(s, &bounds->bottom, True);
|
||||
|
||||
return s_check(s);
|
||||
}
|
||||
|
||||
/* Parse a pen */
|
||||
static RD_BOOL
|
||||
static void
|
||||
rdp_parse_pen(STREAM s, PEN * pen, uint32 present)
|
||||
{
|
||||
if (present & 1)
|
||||
@ -143,8 +141,6 @@ rdp_parse_pen(STREAM s, PEN * pen, uint32 present)
|
||||
|
||||
if (present & 4)
|
||||
rdp_in_colour(s, &pen->colour);
|
||||
|
||||
return s_check(s);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -176,7 +172,7 @@ setup_brush(BRUSH * out_brush, BRUSH * in_brush)
|
||||
}
|
||||
|
||||
/* Parse a brush */
|
||||
static RD_BOOL
|
||||
static void
|
||||
rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present)
|
||||
{
|
||||
if (present & 1)
|
||||
@ -193,8 +189,6 @@ rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present)
|
||||
|
||||
if (present & 16)
|
||||
in_uint8a(s, &brush->pattern[1], 7);
|
||||
|
||||
return s_check(s);
|
||||
}
|
||||
|
||||
/* Process a destination blt order */
|
||||
@ -1258,7 +1252,7 @@ process_secondary_order(STREAM s)
|
||||
sint16 length;
|
||||
uint16 flags;
|
||||
uint8 type;
|
||||
uint8 *next_order;
|
||||
size_t next_order;
|
||||
struct stream packet = *s;
|
||||
|
||||
in_uint16_le(s, length);
|
||||
@ -1272,10 +1266,10 @@ process_secondary_order(STREAM s)
|
||||
|
||||
if (!s_check_rem(s, length))
|
||||
{
|
||||
rdp_protocol_error("process_secondary_order(), next order pointer would overrun stream", &packet);
|
||||
rdp_protocol_error("next order pointer would overrun stream", &packet);
|
||||
}
|
||||
|
||||
next_order = s->p + length;
|
||||
next_order = s_tell(s) + length;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -1312,7 +1306,7 @@ process_secondary_order(STREAM s)
|
||||
"process_secondary_order(), unhandled secondary order %d", type);
|
||||
}
|
||||
|
||||
s->p = next_order;
|
||||
s_seek(s, next_order);
|
||||
}
|
||||
|
||||
/* Process an order PDU */
|
||||
@ -1454,9 +1448,9 @@ process_orders(STREAM s, uint16 num_orders)
|
||||
}
|
||||
#if 0
|
||||
/* not true when RDP_COMPRESSION is set */
|
||||
if (s->p != g_next_packet)
|
||||
if (s_tell(s) != g_next_packet)
|
||||
logger(Graphics, Error, "process_orders(), %d bytes remaining",
|
||||
(int) (g_next_packet - s->p));
|
||||
(int) (g_next_packet - s_tell(s)));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -238,6 +238,8 @@ printercache_process(STREAM s)
|
||||
{
|
||||
uint32 type, printer_length, driver_length, printer_unicode_length, blob_length;
|
||||
char device_name[9], *printer, *driver;
|
||||
size_t blob_start;
|
||||
unsigned char *blob;
|
||||
|
||||
printer = driver = NULL;
|
||||
|
||||
@ -279,8 +281,10 @@ printercache_process(STREAM s)
|
||||
{
|
||||
rdp_in_unistr(s, printer_unicode_length, &printer,
|
||||
&printer_unicode_length);
|
||||
if (printer)
|
||||
printercache_save_blob(printer, s->p, blob_length);
|
||||
if (printer) {
|
||||
in_uint8p(s, blob, blob_length);
|
||||
printercache_save_blob(printer, blob, blob_length);
|
||||
}
|
||||
free(printer);
|
||||
}
|
||||
break;
|
||||
@ -289,6 +293,7 @@ printercache_process(STREAM s)
|
||||
in_uint8a(s, device_name, 5); /* get LPTx/COMx name */
|
||||
|
||||
/* need to fetch this data so that we can get the length of the packet to store. */
|
||||
blob_start = s_tell(s);
|
||||
in_uint8s(s, 0x2); /* ??? */
|
||||
in_uint8s(s, 0x2) /* pad?? */
|
||||
in_uint32_be(s, driver_length);
|
||||
@ -302,10 +307,11 @@ printercache_process(STREAM s)
|
||||
/* rewind stream so that we can save this blob */
|
||||
/* length is driver_length + printer_length + 19 */
|
||||
/* rewind stream */
|
||||
s->p = s->p - 19;
|
||||
s_seek(s, blob_start);
|
||||
|
||||
printercache_save_blob(device_name, s->p,
|
||||
driver_length + printer_length + 19);
|
||||
blob_length = driver_length + printer_length + 19;
|
||||
in_uint8p(s, blob, blob_length);
|
||||
printercache_save_blob(device_name, blob, blob_length);
|
||||
break;
|
||||
default:
|
||||
logger(Protocol, Warning,
|
||||
|
11
proto.h
11
proto.h
@ -25,6 +25,11 @@ extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
#define UNUSED(param) ((void)param)
|
||||
#ifdef __GNUC__
|
||||
# define NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
# define NORETURN
|
||||
#endif // __GNUC__
|
||||
/* bitmap.c */
|
||||
RD_BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp);
|
||||
/* cache.c */
|
||||
@ -165,7 +170,9 @@ RD_BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, ch
|
||||
char *directory, RD_BOOL reconnect);
|
||||
void rdp_reset_state(void);
|
||||
void rdp_disconnect(void);
|
||||
void rdp_protocol_error(const char *message, STREAM s);
|
||||
#define rdp_protocol_error(m, s) _rdp_protocol_error(__FILE__, __LINE__, __func__, m, s)
|
||||
void _rdp_protocol_error(const char *file, int line, const char *func,
|
||||
const char *message, STREAM s) NORETURN;
|
||||
/* rdpdr.c */
|
||||
int get_device_index(RD_NTHANDLE handle);
|
||||
void convert_to_unix_filename(char *filename);
|
||||
@ -220,7 +227,7 @@ char *tcp_get_address(void);
|
||||
RD_BOOL tcp_is_connected(void);
|
||||
void tcp_reset_state(void);
|
||||
RD_BOOL tcp_tls_connect(void);
|
||||
RD_BOOL tcp_tls_get_server_pubkey(STREAM s);
|
||||
STREAM tcp_tls_get_server_pubkey();
|
||||
void tcp_run_ui(RD_BOOL run);
|
||||
|
||||
/* asn.c */
|
||||
|
@ -836,7 +836,7 @@ main(int argc, char *argv[])
|
||||
|
||||
case 'u':
|
||||
g_username = (char *) xmalloc(strlen(optarg) + 1);
|
||||
STRNCPY(g_username, optarg, strlen(optarg) + 1);
|
||||
strcpy(g_username, optarg);
|
||||
username_option = 1;
|
||||
break;
|
||||
|
||||
@ -1355,7 +1355,7 @@ main(int argc, char *argv[])
|
||||
STRNCPY(domain, g_redirect_domain, sizeof(domain));
|
||||
xfree(g_username);
|
||||
g_username = (char *) xmalloc(strlen(g_redirect_username) + 1);
|
||||
STRNCPY(g_username, g_redirect_username, strlen(g_redirect_username) + 1);
|
||||
strcpy(g_username, g_redirect_username);
|
||||
STRNCPY(server, g_redirect_server, sizeof(server));
|
||||
flags |= RDP_INFO_AUTOLOGON;
|
||||
|
||||
@ -1790,7 +1790,7 @@ str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler,
|
||||
buf[0] = '\0';
|
||||
if (*rest)
|
||||
STRNCPY(buf, *rest, buflen);
|
||||
strncat(buf, input, inputlen);
|
||||
strncat(buf, input, buflen);
|
||||
p = buf;
|
||||
|
||||
while (1)
|
||||
|
118
rdp.c
118
rdp.c
@ -59,7 +59,7 @@ extern RD_BOOL g_dynamic_session_resize;
|
||||
|
||||
RD_BOOL g_exit_mainloop = False;
|
||||
|
||||
uint8 *g_next_packet;
|
||||
size_t g_next_packet;
|
||||
uint32 g_rdp_shareid;
|
||||
|
||||
extern RDPCOMP g_mppc_dict;
|
||||
@ -128,6 +128,9 @@ rdp_ts_in_share_control_header(STREAM s, uint8 * type, uint16 * length)
|
||||
|
||||
*type = pdu_type & 0xf;
|
||||
|
||||
/* Give just the size of the data */
|
||||
*length -= 6;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
@ -142,7 +145,7 @@ rdp_recv(uint8 * type)
|
||||
while (1)
|
||||
{
|
||||
/* fill stream with data if needed for parsing a new packet */
|
||||
if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL))
|
||||
if (g_next_packet == 0)
|
||||
{
|
||||
rdp_s = sec_recv(&is_fastpath);
|
||||
if (rdp_s == NULL)
|
||||
@ -155,11 +158,16 @@ rdp_recv(uint8 * type)
|
||||
continue;
|
||||
}
|
||||
|
||||
g_next_packet = rdp_s->p;
|
||||
g_next_packet = s_tell(rdp_s);
|
||||
}
|
||||
else
|
||||
{
|
||||
rdp_s->p = g_next_packet;
|
||||
s_seek(rdp_s, g_next_packet);
|
||||
if (s_check_end(rdp_s))
|
||||
{
|
||||
g_next_packet = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* parse a TS_SHARECONTROLHEADER */
|
||||
@ -171,7 +179,13 @@ rdp_recv(uint8 * type)
|
||||
|
||||
logger(Protocol, Debug, "rdp_recv(), RDP packet #%d, type 0x%x", ++g_packetno, *type);
|
||||
|
||||
g_next_packet += length;
|
||||
if (!s_check_rem(rdp_s, length))
|
||||
{
|
||||
rdp_protocol_error("not enough data for PDU", rdp_s);
|
||||
}
|
||||
|
||||
g_next_packet = s_tell(rdp_s) + length;
|
||||
|
||||
return rdp_s;
|
||||
}
|
||||
|
||||
@ -194,7 +208,7 @@ rdp_send_data(STREAM s, uint8 data_pdu_type)
|
||||
uint16 length;
|
||||
|
||||
s_pop_layer(s, rdp_hdr);
|
||||
length = s->end - s->p;
|
||||
length = s_remaining(s);
|
||||
|
||||
out_uint16_le(s, length);
|
||||
out_uint16_le(s, (RDP_PDU_DATA | 0x10));
|
||||
@ -241,7 +255,8 @@ rdp_out_unistr(STREAM s, char *string, int len)
|
||||
*/
|
||||
static iconv_t icv_local_to_utf16;
|
||||
size_t ibl, obl;
|
||||
char *pin, *pout;
|
||||
char *pin;
|
||||
unsigned char *pout;
|
||||
|
||||
|
||||
if (string == NULL || len == 0)
|
||||
@ -263,18 +278,16 @@ rdp_out_unistr(STREAM s, char *string, int len)
|
||||
ibl = strlen(string);
|
||||
obl = len + 2;
|
||||
pin = string;
|
||||
pout = (char *) s->p;
|
||||
out_uint8p(s, pout, len + 2);
|
||||
|
||||
memset(pout, 0, len + 4);
|
||||
memset(pout, 0, len + 2);
|
||||
|
||||
|
||||
if (iconv(icv_local_to_utf16, (char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
|
||||
if (iconv(icv_local_to_utf16, (char **) &pin, &ibl, (char **)&pout, &obl) == (size_t) - 1)
|
||||
{
|
||||
logger(Protocol, Error, "rdp_out_unistr(), iconv(2) fail, errno %d", errno);
|
||||
abort();
|
||||
}
|
||||
|
||||
s->p += len + 2;
|
||||
}
|
||||
|
||||
/* Input a string in Unicode
|
||||
@ -286,7 +299,8 @@ rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size)
|
||||
{
|
||||
static iconv_t icv_utf16_to_local;
|
||||
size_t ibl, obl;
|
||||
char *pin, *pout;
|
||||
unsigned char *pin;
|
||||
char *pout;
|
||||
|
||||
struct stream packet = *s;
|
||||
|
||||
@ -296,9 +310,20 @@ rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size)
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Corner case. We still want to return a null terminated string... */
|
||||
if (in_len == 0) {
|
||||
if (*string == NULL)
|
||||
{
|
||||
*string = xmalloc(1);
|
||||
}
|
||||
**string = '\0';
|
||||
*str_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s_check_rem(s, in_len))
|
||||
{
|
||||
rdp_protocol_error("rdp_in_unistr(), consume of unicode data from stream would overrun", &packet);
|
||||
rdp_protocol_error("consume of unicode data from stream would overrun", &packet);
|
||||
}
|
||||
|
||||
// if not already open
|
||||
@ -323,7 +348,7 @@ rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size)
|
||||
|
||||
ibl = in_len;
|
||||
obl = *str_size - 1;
|
||||
pin = (char *) s->p;
|
||||
in_uint8p(s, pin, in_len);
|
||||
pout = *string;
|
||||
|
||||
if (iconv(icv_utf16_to_local, (char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
|
||||
@ -344,9 +369,7 @@ rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size)
|
||||
abort();
|
||||
}
|
||||
|
||||
/* we must update the location of the current STREAM for future reads of s->p */
|
||||
s->p += in_len;
|
||||
|
||||
/* Always force the last byte to be a null */
|
||||
*pout = 0;
|
||||
|
||||
if (*string)
|
||||
@ -469,7 +492,7 @@ rdp_send_client_info_pdu(uint32 flags, char *domain, char *user,
|
||||
|
||||
if (g_redirect == True && 0 < g_redirect_cookie_len)
|
||||
{
|
||||
out_uint8p(s, g_redirect_cookie, g_redirect_cookie_len);
|
||||
out_uint8a(s, g_redirect_cookie, g_redirect_cookie_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -535,6 +558,7 @@ rdp_send_client_info_pdu(uint32 flags, char *domain, char *user,
|
||||
g_redirect = False;
|
||||
|
||||
sec_send(s, sec_flags);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Send a control PDU */
|
||||
@ -551,6 +575,7 @@ rdp_send_control(uint16 action)
|
||||
|
||||
s_mark_end(s);
|
||||
rdp_send_data(s, RDP_DATA_PDU_CONTROL);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Send a synchronisation PDU */
|
||||
@ -568,6 +593,7 @@ rdp_send_synchronise(void)
|
||||
|
||||
s_mark_end(s);
|
||||
rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Send a single input event */
|
||||
@ -591,6 +617,7 @@ rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 par
|
||||
|
||||
s_mark_end(s);
|
||||
rdp_send_data(s, RDP_DATA_PDU_INPUT);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Send a Suppress Output PDU */
|
||||
@ -625,6 +652,7 @@ rdp_send_suppress_output_pdu(enum RDP_SUPPRESS_STATUS allowupdates)
|
||||
|
||||
s_mark_end(s);
|
||||
rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS);
|
||||
s_free(s);
|
||||
current_status = allowupdates;
|
||||
}
|
||||
|
||||
@ -669,6 +697,7 @@ rdp_enum_bmpcache2(void)
|
||||
|
||||
s_mark_end(s);
|
||||
rdp_send_data(s, 0x2b);
|
||||
s_free(s);
|
||||
|
||||
offset += 169;
|
||||
}
|
||||
@ -691,6 +720,7 @@ rdp_send_fonts(uint16 seq)
|
||||
|
||||
s_mark_end(s);
|
||||
rdp_send_data(s, RDP_DATA_PDU_FONT2);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Output general capability set (TS_GENERAL_CAPABILITYSET) */
|
||||
@ -792,7 +822,7 @@ rdp_out_ts_order_capabilityset(STREAM s)
|
||||
out_uint16_le(s, 1); /* maximumOrderLevel (ignored, should be 1) */
|
||||
out_uint16_le(s, 0); /* numberFonts (ignored, should be 0) */
|
||||
out_uint16_le(s, orderflags); /* orderFlags */
|
||||
out_uint8p(s, order_caps, 32); /* orderSupport */
|
||||
out_uint8a(s, order_caps, 32); /* orderSupport */
|
||||
out_uint16_le(s, 0); /* textFlags (ignored) */
|
||||
out_uint16_le(s, 0); /* orderSupportExFlags */
|
||||
out_uint32_le(s, 0); /* pad4OctetsB */
|
||||
@ -948,6 +978,7 @@ rdp_process_virtchan_caps(STREAM s)
|
||||
in_uint32_le(s, flags);
|
||||
in_uint32_le(s, chunk_size);
|
||||
|
||||
UNUSED(flags);
|
||||
vc_chunk_size = chunk_size;
|
||||
}
|
||||
|
||||
@ -1095,7 +1126,7 @@ rdp_send_confirm_active(void)
|
||||
out_uint16_le(s, sizeof(RDP_SOURCE));
|
||||
out_uint16_le(s, caplen);
|
||||
|
||||
out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
|
||||
out_uint8a(s, RDP_SOURCE, sizeof(RDP_SOURCE));
|
||||
out_uint16_le(s, 17); /* num_caps */
|
||||
out_uint8s(s, 2); /* pad */
|
||||
|
||||
@ -1128,6 +1159,7 @@ rdp_send_confirm_active(void)
|
||||
|
||||
s_mark_end(s);
|
||||
sec_send(s, sec_flags);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Process a general capability set */
|
||||
@ -1210,25 +1242,25 @@ static void
|
||||
rdp_process_server_caps(STREAM s, uint16 length)
|
||||
{
|
||||
int n;
|
||||
uint8 *next, *start;
|
||||
size_t next, start;
|
||||
uint16 ncapsets, capset_type, capset_length;
|
||||
|
||||
logger(Protocol, Debug, "%s()", __func__);
|
||||
|
||||
start = s->p;
|
||||
start = s_tell(s);
|
||||
|
||||
in_uint16_le(s, ncapsets);
|
||||
in_uint8s(s, 2); /* pad */
|
||||
|
||||
for (n = 0; n < ncapsets; n++)
|
||||
{
|
||||
if (s->p > start + length)
|
||||
if (s_tell(s) > start + length)
|
||||
return;
|
||||
|
||||
in_uint16_le(s, capset_type);
|
||||
in_uint16_le(s, capset_length);
|
||||
|
||||
next = s->p + capset_length - 4;
|
||||
next = s_tell(s) + capset_length - 4;
|
||||
|
||||
switch (capset_type)
|
||||
{
|
||||
@ -1247,7 +1279,7 @@ rdp_process_server_caps(STREAM s, uint16 length)
|
||||
break;
|
||||
}
|
||||
|
||||
s->p = next;
|
||||
s_seek(s, next);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1268,7 +1300,7 @@ process_demand_active(STREAM s)
|
||||
|
||||
if (!s_check_rem(s, len_src_descriptor))
|
||||
{
|
||||
rdp_protocol_error("rdp_demand_active(), consume of source descriptor from stream would overrun", &packet);
|
||||
rdp_protocol_error("consume of source descriptor from stream would overrun", &packet);
|
||||
}
|
||||
in_uint8s(s, len_src_descriptor);
|
||||
|
||||
@ -1416,8 +1448,7 @@ process_pointer_pdu(STREAM s)
|
||||
case RDP_POINTER_MOVE:
|
||||
in_uint16_le(s, x);
|
||||
in_uint16_le(s, y);
|
||||
if (s_check(s))
|
||||
ui_move_pointer(x, y);
|
||||
ui_move_pointer(x, y);
|
||||
break;
|
||||
|
||||
case RDP_POINTER_COLOR:
|
||||
@ -1521,7 +1552,7 @@ process_bitmap_data(STREAM s)
|
||||
/* read compressed bitmap data */
|
||||
if (!s_check_rem(s, size))
|
||||
{
|
||||
rdp_protocol_error("process_bitmap_data(), consume of bitmap data from stream would overrun", &packet);
|
||||
rdp_protocol_error("consume of bitmap data from stream would overrun", &packet);
|
||||
}
|
||||
in_uint8p(s, data, size);
|
||||
bmpdata = (uint8 *) xmalloc(width * height * Bpp);
|
||||
@ -1718,6 +1749,7 @@ process_data_pdu(STREAM s, uint32 * ext_disc_reason)
|
||||
uint16 clen;
|
||||
uint32 len;
|
||||
|
||||
uint8 *buf;
|
||||
uint32 roff, rlen;
|
||||
|
||||
struct stream *ns = &(g_mppc_dict.ns);
|
||||
@ -1734,21 +1766,22 @@ process_data_pdu(STREAM s, uint32 * ext_disc_reason)
|
||||
if (len > RDP_MPPC_DICT_SIZE)
|
||||
logger(Protocol, Error,
|
||||
"process_data_pdu(), error decompressed packet size exceeds max");
|
||||
if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1)
|
||||
in_uint8p(s, buf, clen);
|
||||
if (mppc_expand(buf, clen, ctype, &roff, &rlen) == -1)
|
||||
logger(Protocol, Error,
|
||||
"process_data_pdu(), error while decompressing packet");
|
||||
|
||||
/* len -= 18; */
|
||||
|
||||
/* allocate memory and copy the uncompressed data into the temporary stream */
|
||||
ns->data = (uint8 *) xrealloc(ns->data, rlen);
|
||||
s_realloc(ns, rlen);
|
||||
s_reset(ns);
|
||||
|
||||
memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen);
|
||||
out_uint8a(ns, (unsigned char *) (g_mppc_dict.hist + roff), rlen);
|
||||
|
||||
ns->size = rlen;
|
||||
ns->end = (ns->data + ns->size);
|
||||
ns->p = ns->data;
|
||||
ns->rdp_hdr = ns->p;
|
||||
s_mark_end(ns);
|
||||
s_seek(ns, 0);
|
||||
s_push_layer(ns, rdp_hdr, 0);
|
||||
|
||||
s = ns;
|
||||
}
|
||||
@ -2048,7 +2081,7 @@ rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
|
||||
logger(Protocol, Warning,
|
||||
"rdp_loop(), unhandled PDU type %d received", type);
|
||||
}
|
||||
cont = g_next_packet < s->end;
|
||||
cont = g_next_packet < s_length(s);
|
||||
}
|
||||
return True;
|
||||
}
|
||||
@ -2086,7 +2119,7 @@ void
|
||||
rdp_reset_state(void)
|
||||
{
|
||||
logger(Protocol, Debug, "%s()", __func__);
|
||||
g_next_packet = NULL; /* reset the packet information */
|
||||
g_next_packet = 0; /* reset the packet information */
|
||||
g_rdp_shareid = 0;
|
||||
g_exit_mainloop = False;
|
||||
g_first_bitmap_caps = True;
|
||||
@ -2111,10 +2144,11 @@ rdp_disconnect(void)
|
||||
|
||||
*/
|
||||
void
|
||||
rdp_protocol_error(const char *message, STREAM s)
|
||||
_rdp_protocol_error(const char *file, int line, const char *func,
|
||||
const char *message, STREAM s)
|
||||
{
|
||||
logger(Protocol, Error, "%s(), %s", __func__, message);
|
||||
logger(Protocol, Error, "%s:%d: %s(), %s", file, line, func, message);
|
||||
if (s)
|
||||
hexdump(s->p, s_length(s));
|
||||
hexdump(s->data, s_length(s));
|
||||
exit(0);
|
||||
}
|
||||
|
41
rdp5.c
41
rdp5.c
@ -21,7 +21,7 @@
|
||||
|
||||
#include "rdesktop.h"
|
||||
|
||||
extern uint8 *g_next_packet;
|
||||
extern size_t g_next_packet;
|
||||
|
||||
extern RDPCOMP g_mppc_dict;
|
||||
|
||||
@ -56,8 +56,7 @@ process_ts_fp_update_by_code(STREAM s, uint8 code)
|
||||
case FASTPATH_UPDATETYPE_PTR_POSITION:
|
||||
in_uint16_le(s, x);
|
||||
in_uint16_le(s, y);
|
||||
if (s_check(s))
|
||||
ui_move_pointer(x, y);
|
||||
ui_move_pointer(x, y);
|
||||
break;
|
||||
case FASTPATH_UPDATETYPE_COLOR:
|
||||
process_colour_pointer_pdu(s);
|
||||
@ -79,16 +78,17 @@ process_ts_fp_updates(STREAM s)
|
||||
{
|
||||
uint16 length;
|
||||
uint8 hdr, code, frag, comp, ctype = 0;
|
||||
uint8 *next;
|
||||
size_t next;
|
||||
|
||||
uint8 *buf;
|
||||
uint32 roff, rlen;
|
||||
struct stream *ns = &(g_mppc_dict.ns);
|
||||
struct stream *ts;
|
||||
|
||||
static STREAM assembled[0x0F] = { 0 };
|
||||
static STREAM assembled[16] = { 0 };
|
||||
|
||||
ui_begin_update();
|
||||
while (s->p < s->end)
|
||||
while (!s_check_end(s))
|
||||
{
|
||||
/* Reading a number of TS_FP_UPDATE structures from the stream here.. */
|
||||
in_uint8(s, hdr); /* updateHeader */
|
||||
@ -101,23 +101,24 @@ process_ts_fp_updates(STREAM s)
|
||||
|
||||
in_uint16_le(s, length); /* length */
|
||||
|
||||
g_next_packet = next = s->p + length;
|
||||
g_next_packet = next = s_tell(s) + length;
|
||||
|
||||
if (ctype & RDP_MPPC_COMPRESSED)
|
||||
{
|
||||
if (mppc_expand(s->p, length, ctype, &roff, &rlen) == -1)
|
||||
in_uint8p(s, buf, length);
|
||||
if (mppc_expand(buf, length, ctype, &roff, &rlen) == -1)
|
||||
logger(Protocol, Error,
|
||||
"process_ts_fp_update_pdu(), error while decompressing packet");
|
||||
|
||||
/* allocate memory and copy the uncompressed data into the temporary stream */
|
||||
ns->data = (uint8 *) xrealloc(ns->data, rlen);
|
||||
s_realloc(ns, rlen);
|
||||
s_reset(ns);
|
||||
|
||||
memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen);
|
||||
out_uint8a(ns, (unsigned char *) (g_mppc_dict.hist + roff), rlen);
|
||||
|
||||
ns->size = rlen;
|
||||
ns->end = (ns->data + ns->size);
|
||||
ns->p = ns->data;
|
||||
ns->rdp_hdr = ns->p;
|
||||
s_mark_end(ns);
|
||||
s_seek(ns, 0);
|
||||
s_push_layer(ns, rdp_hdr, 0);
|
||||
|
||||
length = rlen;
|
||||
ts = ns;
|
||||
@ -133,11 +134,7 @@ process_ts_fp_updates(STREAM s)
|
||||
{
|
||||
if (assembled[code] == NULL)
|
||||
{
|
||||
assembled[code] = xmalloc(sizeof(struct stream));
|
||||
memset(assembled[code], 0, sizeof(struct stream));
|
||||
s_realloc(assembled[code],
|
||||
RDESKTOP_FASTPATH_MULTIFRAGMENT_MAX_SIZE);
|
||||
s_reset(assembled[code]);
|
||||
assembled[code] = s_alloc(RDESKTOP_FASTPATH_MULTIFRAGMENT_MAX_SIZE);
|
||||
}
|
||||
|
||||
if (frag == FASTPATH_FRAGMENT_FIRST)
|
||||
@ -145,17 +142,17 @@ process_ts_fp_updates(STREAM s)
|
||||
s_reset(assembled[code]);
|
||||
}
|
||||
|
||||
out_uint8p(assembled[code], ts->p, length);
|
||||
out_uint8stream(assembled[code], ts, length);
|
||||
|
||||
if (frag == FASTPATH_FRAGMENT_LAST)
|
||||
{
|
||||
s_mark_end(assembled[code]);
|
||||
assembled[code]->p = assembled[code]->data;
|
||||
s_seek(assembled[code], 0);
|
||||
process_ts_fp_update_by_code(assembled[code], code);
|
||||
}
|
||||
}
|
||||
|
||||
s->p = next;
|
||||
s_seek(s, next);
|
||||
}
|
||||
ui_end_update();
|
||||
}
|
||||
|
142
rdpdr.c
142
rdpdr.c
@ -204,6 +204,7 @@ rdpdr_send_client_announce_reply(void)
|
||||
out_uint32_be(s, g_client_id); /* ClientID */
|
||||
s_mark_end(s);
|
||||
channel_send(s, rdpdr_channel);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
|
||||
@ -233,6 +234,7 @@ rdpdr_send_client_name_request(void)
|
||||
out_stream(s, &name);
|
||||
s_mark_end(s);
|
||||
channel_send(s, rdpdr_channel);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Returns the size of the payload of the announce packet */
|
||||
@ -300,7 +302,7 @@ rdpdr_send_client_device_list_announce(void)
|
||||
{
|
||||
out_uint32_le(s, g_rdpdr_device[i].device_type);
|
||||
out_uint32_le(s, i); /* RDP Device ID */
|
||||
out_uint8p(s, g_rdpdr_device[i].name, 8); /* preferredDosName, limited to 8 characters */
|
||||
out_uint8a(s, g_rdpdr_device[i].name, 8); /* preferredDosName, limited to 8 characters */
|
||||
switch (g_rdpdr_device[i].device_type)
|
||||
{
|
||||
case DEVICE_TYPE_DISK:
|
||||
@ -314,7 +316,7 @@ rdpdr_send_client_device_list_announce(void)
|
||||
disklen = strlen(diskinfo->name) + 1;
|
||||
|
||||
out_uint32_le(s, disklen); /* DeviceDataLength */
|
||||
out_uint8p(s, diskinfo->name, disklen); /* DeviceData */
|
||||
out_uint8a(s, diskinfo->name, disklen); /* DeviceData */
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_PRINTER:
|
||||
@ -357,6 +359,7 @@ rdpdr_send_client_device_list_announce(void)
|
||||
|
||||
s_mark_end(s);
|
||||
channel_send(s, rdpdr_channel);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
void
|
||||
@ -385,13 +388,14 @@ rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, ui
|
||||
out_uint32_le(s, status);
|
||||
out_uint32_le(s, result);
|
||||
if (length)
|
||||
out_uint8p(s, buffer, length);
|
||||
out_uint8a(s, buffer, length);
|
||||
s_mark_end(s);
|
||||
|
||||
logger(Protocol, Debug, "rdpdr_send_completion()");
|
||||
/* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
|
||||
|
||||
channel_send(s, rdpdr_channel);
|
||||
s_free(s);
|
||||
#ifdef WITH_SCARD
|
||||
scard_unlock(SCARD_LOCK_RDPDR);
|
||||
#endif
|
||||
@ -407,7 +411,6 @@ rdpdr_process_irp(STREAM s)
|
||||
request,
|
||||
file,
|
||||
info_level,
|
||||
buffer_len,
|
||||
id,
|
||||
major,
|
||||
minor,
|
||||
@ -420,8 +423,8 @@ rdpdr_process_irp(STREAM s)
|
||||
char *filename;
|
||||
uint32 filename_len;
|
||||
|
||||
uint8 *buffer, *pst_buf;
|
||||
struct stream out;
|
||||
uint8 *pst_buf;
|
||||
STREAM out;
|
||||
DEVICE_FNS *fns;
|
||||
RD_BOOL rw_blocking = True;
|
||||
RD_NTSTATUS status = RD_STATUS_INVALID_DEVICE_REQUEST;
|
||||
@ -434,16 +437,13 @@ rdpdr_process_irp(STREAM s)
|
||||
|
||||
filename = NULL;
|
||||
|
||||
buffer_len = 0;
|
||||
buffer = (uint8 *) xmalloc(1024);
|
||||
buffer[0] = 0;
|
||||
out = NULL;
|
||||
|
||||
if (device >= RDPDR_MAX_DEVICES)
|
||||
{
|
||||
logger(Protocol, Error,
|
||||
"rdpdr_process_irp(), invalid irp device=0x%lx, file=0x%lx, id=0x%lx, major=0x%lx, minor=0x%lx",
|
||||
device, file, id, major, minor);
|
||||
xfree(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -482,7 +482,6 @@ rdpdr_process_irp(STREAM s)
|
||||
logger(Protocol, Error,
|
||||
"rdpdr_process_irp(), received IRP for unknown device type %ld",
|
||||
device);
|
||||
xfree(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -516,7 +515,9 @@ rdpdr_process_irp(STREAM s)
|
||||
flags_and_attributes, filename, &result);
|
||||
|
||||
free(filename);
|
||||
buffer_len = 1;
|
||||
out = s_alloc(1);
|
||||
out_uint8(out, 0);
|
||||
s_mark_end(out);
|
||||
break;
|
||||
|
||||
case IRP_MJ_CLOSE:
|
||||
@ -553,14 +554,14 @@ rdpdr_process_irp(STREAM s)
|
||||
|
||||
if (rw_blocking) /* Complete read immediately */
|
||||
{
|
||||
buffer = (uint8 *) xrealloc((void *) buffer, length);
|
||||
if (!buffer)
|
||||
{
|
||||
status = RD_STATUS_CANCELLED;
|
||||
break;
|
||||
}
|
||||
uint8* buffer;
|
||||
out = s_alloc(length);
|
||||
out_uint8p(out, buffer, length);
|
||||
status = fns->read(file, buffer, length, offset, &result);
|
||||
buffer_len = result;
|
||||
/* Might have read less */
|
||||
s_mark_end(out);
|
||||
s_seek(out, result);
|
||||
s_mark_end(out);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -584,7 +585,9 @@ rdpdr_process_irp(STREAM s)
|
||||
break;
|
||||
case IRP_MJ_WRITE:
|
||||
|
||||
buffer_len = 1;
|
||||
out = s_alloc(1);
|
||||
out_uint8(out, 0);
|
||||
s_mark_end(out);
|
||||
|
||||
if (!fns->write)
|
||||
{
|
||||
@ -608,7 +611,9 @@ rdpdr_process_irp(STREAM s)
|
||||
|
||||
if (rw_blocking) /* Complete immediately */
|
||||
{
|
||||
status = fns->write(file, s->p, length, offset, &result);
|
||||
unsigned char *data;
|
||||
in_uint8p(s, data, length);
|
||||
status = fns->write(file, data, length, offset, &result);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -641,10 +646,10 @@ rdpdr_process_irp(STREAM s)
|
||||
}
|
||||
in_uint32_le(s, info_level);
|
||||
|
||||
out.data = out.p = buffer;
|
||||
out.size = sizeof(buffer);
|
||||
status = disk_query_information(file, info_level, &out);
|
||||
result = buffer_len = out.p - out.data;
|
||||
out = s_alloc(1024);
|
||||
status = disk_query_information(file, info_level, out);
|
||||
s_mark_end(out);
|
||||
result = s_length(out);
|
||||
|
||||
break;
|
||||
|
||||
@ -658,10 +663,10 @@ rdpdr_process_irp(STREAM s)
|
||||
|
||||
in_uint32_le(s, info_level);
|
||||
|
||||
out.data = out.p = buffer;
|
||||
out.size = sizeof(buffer);
|
||||
status = disk_set_information(file, info_level, s, &out);
|
||||
result = buffer_len = out.p - out.data;
|
||||
out = s_alloc(1024);
|
||||
status = disk_set_information(file, info_level, s, out);
|
||||
s_mark_end(out);
|
||||
result = s_length(out);
|
||||
break;
|
||||
|
||||
case IRP_MJ_QUERY_VOLUME_INFORMATION:
|
||||
@ -674,10 +679,10 @@ rdpdr_process_irp(STREAM s)
|
||||
|
||||
in_uint32_le(s, info_level);
|
||||
|
||||
out.data = out.p = buffer;
|
||||
out.size = sizeof(buffer);
|
||||
status = disk_query_volume_information(file, info_level, &out);
|
||||
result = buffer_len = out.p - out.data;
|
||||
out = s_alloc(1024);
|
||||
status = disk_query_volume_information(file, info_level, out);
|
||||
s_mark_end(out);
|
||||
result = s_length(out);
|
||||
break;
|
||||
|
||||
case IRP_MJ_DIRECTORY_CONTROL:
|
||||
@ -703,13 +708,16 @@ rdpdr_process_irp(STREAM s)
|
||||
convert_to_unix_filename(filename);
|
||||
}
|
||||
|
||||
out.data = out.p = buffer;
|
||||
out.size = sizeof(buffer);
|
||||
out = s_alloc(1024);
|
||||
status = disk_query_directory(file, info_level, filename,
|
||||
&out);
|
||||
result = buffer_len = out.p - out.data;
|
||||
if (!buffer_len)
|
||||
buffer_len++;
|
||||
out);
|
||||
s_mark_end(out);
|
||||
if (!s_length(out))
|
||||
{
|
||||
out_uint8(out, 0);
|
||||
s_mark_end(out);
|
||||
}
|
||||
result = s_length(out);
|
||||
|
||||
free(filename);
|
||||
break;
|
||||
@ -756,23 +764,14 @@ rdpdr_process_irp(STREAM s)
|
||||
in_uint8s(s, 0x14);
|
||||
|
||||
/* TODO: Why do we need to increase length by padlen? Or is it hdr len? */
|
||||
buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14);
|
||||
if (!buffer)
|
||||
{
|
||||
status = RD_STATUS_CANCELLED;
|
||||
break;
|
||||
}
|
||||
|
||||
out.data = out.p = buffer;
|
||||
/* Guess, just a simple mistype. Check others */
|
||||
//out.size = sizeof(buffer);
|
||||
out.size = bytes_out + 0x14;
|
||||
out = s_alloc(bytes_out + 0x14);
|
||||
|
||||
#ifdef WITH_SCARD
|
||||
scardSetInfo(g_epoch, device, id, bytes_out + 0x14);
|
||||
#endif
|
||||
status = fns->device_control(file, request, s, &out);
|
||||
result = buffer_len = out.p - out.data;
|
||||
status = fns->device_control(file, request, s, out);
|
||||
s_mark_end(out);
|
||||
result = s_length(out);
|
||||
|
||||
/* Serial SERIAL_WAIT_ON_MASK */
|
||||
if (status == RD_STATUS_PENDING)
|
||||
@ -801,12 +800,12 @@ rdpdr_process_irp(STREAM s)
|
||||
|
||||
in_uint32_le(s, info_level);
|
||||
|
||||
out.data = out.p = buffer;
|
||||
out.size = sizeof(buffer);
|
||||
out = s_alloc(1024);
|
||||
/* FIXME: Perhaps consider actually *do*
|
||||
something here :-) */
|
||||
status = RD_STATUS_SUCCESS;
|
||||
result = buffer_len = out.p - out.data;
|
||||
s_mark_end(out);
|
||||
result = s_length(out);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -818,11 +817,25 @@ rdpdr_process_irp(STREAM s)
|
||||
|
||||
if (status != RD_STATUS_PENDING)
|
||||
{
|
||||
size_t buffer_len;
|
||||
uint8 *buffer;
|
||||
|
||||
if (out != NULL)
|
||||
{
|
||||
buffer_len = s_length(out);
|
||||
s_seek(out, 0);
|
||||
in_uint8p(out, buffer, buffer_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_len = 0;
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
|
||||
}
|
||||
if (buffer)
|
||||
xfree(buffer);
|
||||
buffer = NULL;
|
||||
if (out)
|
||||
s_free(out);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -868,6 +881,7 @@ rdpdr_send_client_capability_response(void)
|
||||
|
||||
s_mark_end(s);
|
||||
channel_send(s, rdpdr_channel);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -877,10 +891,9 @@ rdpdr_process(STREAM s)
|
||||
uint16 vmin;
|
||||
uint16 component;
|
||||
uint16 pakid;
|
||||
struct stream packet = *s;
|
||||
|
||||
logger(Protocol, Debug, "rdpdr_process()");
|
||||
/* hexdump(s->p, s->end - s->p); */
|
||||
/* hexdump(s->p, s_remaining(s)); */
|
||||
|
||||
in_uint16(s, component); /* RDPDR_HEADER.Component */
|
||||
in_uint16(s, pakid); /* RDPDR_HEADER.PacketId */
|
||||
@ -900,15 +913,6 @@ rdpdr_process(STREAM s)
|
||||
|
||||
in_uint32_le(s, g_client_id); /* ClientID */
|
||||
|
||||
/* g_client_id is sent back to server,
|
||||
so lets check that we actually got
|
||||
valid data from stream to prevent
|
||||
that we leak back data to server */
|
||||
if (!s_check(s))
|
||||
{
|
||||
rdp_protocol_error("rdpdr_process(), consume of g_client_id from stream did overrun", &packet);
|
||||
}
|
||||
|
||||
/* The RDP client is responsibility to provide a random client id
|
||||
if server version is < 12 */
|
||||
if (vmin < 0x000c)
|
||||
|
@ -64,7 +64,7 @@ rdpedisp_process_pdu(STREAM s)
|
||||
|
||||
/* Read DISPLAYCONTROL_HEADER */
|
||||
in_uint32_le(s, type); /* type */
|
||||
in_skip(s, 4); /* length */
|
||||
in_uint8s(s, 4); /* length */
|
||||
|
||||
logger(Protocol, Debug, "rdpedisp_process_pdu(), Got PDU type %d", type);
|
||||
|
||||
|
78
rdpsnd.c
78
rdpsnd.c
@ -64,6 +64,7 @@ unsigned int queue_hi, queue_lo, queue_pending;
|
||||
struct audio_packet packet_queue[MAX_QUEUE];
|
||||
|
||||
static uint8 packet_opcode;
|
||||
static size_t packet_len;
|
||||
static struct stream packet;
|
||||
|
||||
void (*wave_out_play) (void);
|
||||
@ -103,6 +104,7 @@ rdpsnd_send_waveconfirm(uint16 tick, uint8 packet_index)
|
||||
out_uint8(s, 0);
|
||||
s_mark_end(s);
|
||||
rdpsnd_send(s);
|
||||
s_free(s);
|
||||
|
||||
logger(Sound, Debug, "rdpsnd_send_waveconfirm(), tick=%u, index=%u",
|
||||
(unsigned) tick, (unsigned) packet_index);
|
||||
@ -259,6 +261,7 @@ rdpsnd_process_negotiate(STREAM in)
|
||||
(int) format_count);
|
||||
|
||||
rdpsnd_send(out);
|
||||
s_free(out);
|
||||
|
||||
rdpsnd_negotiated = True;
|
||||
}
|
||||
@ -273,7 +276,7 @@ rdpsnd_process_training(STREAM in)
|
||||
|
||||
if (!s_check_rem(in, 4))
|
||||
{
|
||||
rdp_protocol_error("rdpsnd_process_training(), consume of training data from stream would overrun", &packet);
|
||||
rdp_protocol_error("consume of training data from stream would overrun", &packet);
|
||||
}
|
||||
|
||||
in_uint16_le(in, tick);
|
||||
@ -286,14 +289,18 @@ rdpsnd_process_training(STREAM in)
|
||||
out_uint16_le(out, packsize);
|
||||
s_mark_end(out);
|
||||
rdpsnd_send(out);
|
||||
s_free(out);
|
||||
}
|
||||
|
||||
static void
|
||||
rdpsnd_process_packet(uint8 opcode, STREAM s)
|
||||
{
|
||||
uint16 vol_left, vol_right;
|
||||
static uint16 tick, format;
|
||||
static uint8 packet_index;
|
||||
|
||||
uint16 tick, format;
|
||||
uint8 packet_index;
|
||||
unsigned int size;
|
||||
unsigned char *data;
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
@ -342,9 +349,12 @@ rdpsnd_process_packet(uint8 opcode, STREAM s)
|
||||
current_format = format;
|
||||
}
|
||||
|
||||
rdpsnd_queue_write(rdpsnd_dsp_process
|
||||
(s->p, s->end - s->p, current_driver,
|
||||
&formats[current_format]), tick, packet_index);
|
||||
size = s_remaining(s);
|
||||
in_uint8p(s, data, size);
|
||||
rdpsnd_queue_write(rdpsnd_dsp_process(data, size,
|
||||
current_driver,
|
||||
&formats[current_format]),
|
||||
tick, packet_index);
|
||||
return;
|
||||
break;
|
||||
case SNDC_CLOSE:
|
||||
@ -379,14 +389,12 @@ rdpsnd_process_packet(uint8 opcode, STREAM s)
|
||||
static void
|
||||
rdpsnd_process(STREAM s)
|
||||
{
|
||||
uint16 len;
|
||||
|
||||
while (!s_check_end(s))
|
||||
{
|
||||
/* New packet */
|
||||
if (packet.size == 0)
|
||||
if (packet_len == 0)
|
||||
{
|
||||
if ((s->end - s->p) < 4)
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
logger(Sound, Error,
|
||||
"rdpsnd_process(), split at packet header, things will go south from here...");
|
||||
@ -394,25 +402,23 @@ rdpsnd_process(STREAM s)
|
||||
}
|
||||
in_uint8(s, packet_opcode);
|
||||
in_uint8s(s, 1); /* Padding */
|
||||
in_uint16_le(s, len);
|
||||
in_uint16_le(s, packet_len);
|
||||
|
||||
logger(Sound, Debug, "rdpsnd_process(), Opcode = 0x%x Length= %d",
|
||||
(int) packet_opcode, (int) len);
|
||||
|
||||
packet.p = packet.data;
|
||||
packet.end = packet.data + len;
|
||||
packet.size = len;
|
||||
(int) packet_opcode, (int) packet_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = MIN(s->end - s->p, packet.end - packet.p);
|
||||
uint16 len;
|
||||
|
||||
len = MIN(s_remaining(s), packet_len - s_length(&packet));
|
||||
|
||||
/* Microsoft's server is so broken it's not even funny... */
|
||||
if (packet_opcode == SNDC_WAVE)
|
||||
{
|
||||
if ((packet.p - packet.data) < 12)
|
||||
len = MIN(len, 12 - (packet.p - packet.data));
|
||||
else if ((packet.p - packet.data) == 12)
|
||||
if (s_length(&packet) < 12)
|
||||
len = MIN(len, 12 - s_length(&packet));
|
||||
else if (s_length(&packet) == 12)
|
||||
{
|
||||
logger(Sound, Debug,
|
||||
"rdpsnd_process(), eating 4 bytes of %d bytes...",
|
||||
@ -422,16 +428,18 @@ rdpsnd_process(STREAM s)
|
||||
}
|
||||
}
|
||||
|
||||
in_uint8a(s, packet.p, len);
|
||||
packet.p += len;
|
||||
in_uint8stream(s, &packet, len);
|
||||
/* Always end it so s_length() works */
|
||||
s_mark_end(&packet);
|
||||
}
|
||||
|
||||
/* Packet fully assembled */
|
||||
if (packet.p == packet.end)
|
||||
if (s_length(&packet) == packet_len)
|
||||
{
|
||||
packet.p = packet.data;
|
||||
s_seek(&packet, 0);
|
||||
rdpsnd_process_packet(packet_opcode, &packet);
|
||||
packet.size = 0;
|
||||
packet_len = 0;
|
||||
s_reset(&packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -451,15 +459,11 @@ rdpsnddbg_process(STREAM s)
|
||||
static char *rest = NULL;
|
||||
char *buf;
|
||||
|
||||
if (!s_check(s))
|
||||
{
|
||||
rdp_protocol_error("rdpsnddbg_process(), stream is in unstable state", s);
|
||||
}
|
||||
|
||||
pkglen = s->end - s->p;
|
||||
pkglen = s_remaining(s);
|
||||
/* str_handle_lines requires null terminated strings */
|
||||
buf = (char *) xmalloc(pkglen + 1);
|
||||
STRNCPY(buf, (char *) s->p, pkglen + 1);
|
||||
in_uint8a(s, buf, pkglen);
|
||||
buf[pkglen] = '\0';
|
||||
|
||||
str_handle_lines(buf, &rest, rdpsnddbg_line_handler, NULL);
|
||||
|
||||
@ -515,9 +519,7 @@ rdpsnd_init(char *optarg)
|
||||
|
||||
drivers = NULL;
|
||||
|
||||
packet.data = (uint8 *) xmalloc(65536);
|
||||
packet.p = packet.end = packet.data;
|
||||
packet.size = 0;
|
||||
s_realloc(&packet, 65536);
|
||||
|
||||
rdpsnd_channel =
|
||||
channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
|
||||
@ -643,7 +645,7 @@ rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index)
|
||||
|
||||
queue_hi = next_hi;
|
||||
|
||||
packet->s = *s;
|
||||
packet->s = s;
|
||||
packet->tick = tick;
|
||||
packet->index = index;
|
||||
|
||||
@ -677,7 +679,7 @@ rdpsnd_queue_clear(void)
|
||||
while (queue_pending != queue_hi)
|
||||
{
|
||||
packet = &packet_queue[queue_pending];
|
||||
xfree(packet->s.data);
|
||||
s_free(packet->s);
|
||||
queue_pending = (queue_pending + 1) % MAX_QUEUE;
|
||||
}
|
||||
|
||||
@ -742,7 +744,7 @@ rdpsnd_queue_complete_pending(void)
|
||||
(packet->completion_tv.tv_usec - packet->arrive_tv.tv_usec);
|
||||
elapsed /= 1000;
|
||||
|
||||
xfree(packet->s.data);
|
||||
s_free(packet->s);
|
||||
rdpsnd_send_waveconfirm((packet->tick + elapsed) % 65536, packet->index);
|
||||
queue_pending = (queue_pending + 1) % MAX_QUEUE;
|
||||
}
|
||||
|
2
rdpsnd.h
2
rdpsnd.h
@ -19,7 +19,7 @@
|
||||
|
||||
struct audio_packet
|
||||
{
|
||||
struct stream s;
|
||||
STREAM s;
|
||||
uint16 tick;
|
||||
uint8 index;
|
||||
|
||||
|
@ -358,6 +358,8 @@ alsa_play(void)
|
||||
struct audio_packet *packet;
|
||||
STREAM out;
|
||||
int len;
|
||||
const unsigned char *data;
|
||||
size_t before;
|
||||
static long prev_s, prev_us;
|
||||
int duration;
|
||||
struct timeval tv;
|
||||
@ -376,17 +378,25 @@ alsa_play(void)
|
||||
return;
|
||||
|
||||
packet = rdpsnd_queue_current_packet();
|
||||
out = &packet->s;
|
||||
out = packet->s;
|
||||
|
||||
next_tick = rdpsnd_queue_next_tick();
|
||||
|
||||
len = (out->end - out->p) / (samplewidth_out * audiochannels_out);
|
||||
if ((len = snd_pcm_writei(out_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)
|
||||
before = s_tell(out);
|
||||
|
||||
len = s_remaining(out) / (samplewidth_out * audiochannels_out);
|
||||
len = MIN(len, MAX_FRAMES);
|
||||
in_uint8p(out, data, len);
|
||||
|
||||
len = snd_pcm_writei(out_handle, data, len);
|
||||
if (len < 0)
|
||||
{
|
||||
snd_pcm_prepare(out_handle);
|
||||
len = 0;
|
||||
}
|
||||
out->p += (len * samplewidth_out * audiochannels_out);
|
||||
|
||||
/* We might not have written everything */
|
||||
s_seek(out, before + len * samplewidth_out * audiochannels_out);
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
@ -395,7 +405,7 @@ alsa_play(void)
|
||||
if (packet->tick > next_tick)
|
||||
next_tick += 65536;
|
||||
|
||||
if ((out->p == out->end) || duration > next_tick - packet->tick + 500)
|
||||
if (s_check_end(out) || duration > next_tick - packet->tick + 500)
|
||||
{
|
||||
snd_pcm_sframes_t delay_frames;
|
||||
unsigned long delay_us;
|
||||
|
52
rdpsnd_dsp.c
52
rdpsnd_dsp.c
@ -175,8 +175,8 @@ rdpsnd_dsp_resample_supported(RD_WAVEFORMATEX * format)
|
||||
return True;
|
||||
}
|
||||
|
||||
uint32
|
||||
rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
|
||||
STREAM
|
||||
rdpsnd_dsp_resample(unsigned char *in, unsigned int size,
|
||||
RD_WAVEFORMATEX * format, RD_BOOL stream_be)
|
||||
{
|
||||
UNUSED(stream_be);
|
||||
@ -190,13 +190,15 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
|
||||
int innum, outnum;
|
||||
unsigned char *tmpdata = NULL, *tmp = NULL;
|
||||
int samplewidth = format->wBitsPerSample / 8;
|
||||
STREAM out;
|
||||
int outsize = 0;
|
||||
unsigned char *data;
|
||||
int i;
|
||||
|
||||
if ((resample_to_bitspersample == format->wBitsPerSample) &&
|
||||
(resample_to_channels == format->nChannels) &&
|
||||
(resample_to_srate == format->nSamplesPerSec))
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
#ifdef B_ENDIAN
|
||||
if (!stream_be)
|
||||
@ -260,7 +262,7 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
|
||||
{
|
||||
logger(Sound, Warning,
|
||||
"rdpsndp_dsp_resample_set(), no sample rate converter available");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
outnum = ((float) innum * ((float) resample_to_srate / (float) format->nSamplesPerSec)) + 1;
|
||||
@ -285,8 +287,9 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
|
||||
xfree(infloat);
|
||||
|
||||
outsize = resample_data.output_frames_gen * resample_to_channels * samplewidth;
|
||||
*out = (unsigned char *) xmalloc(outsize);
|
||||
src_float_to_short_array(outfloat, (short *) *out,
|
||||
out = s_alloc(outsize);
|
||||
out_uint8p(out, data, outsize);
|
||||
src_float_to_short_array(outfloat, (short *) data,
|
||||
resample_data.output_frames_gen * resample_to_channels);
|
||||
xfree(outfloat);
|
||||
|
||||
@ -302,8 +305,9 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
|
||||
outnum = (innum * ratio1k) / 1000;
|
||||
|
||||
outsize = outnum * samplewidth;
|
||||
*out = (unsigned char *) xmalloc(outsize);
|
||||
bzero(*out, outsize);
|
||||
out = s_alloc(outsize);
|
||||
out_uint8p(out, data, outsize);
|
||||
bzero(data, outsize);
|
||||
|
||||
for (i = 0; i < outsize / (resample_to_channels * samplewidth); i++)
|
||||
{
|
||||
@ -331,7 +335,7 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
|
||||
|
||||
cval1 += (sint8) (cval2 * part) / 100;
|
||||
|
||||
memcpy(*out + (i * resample_to_channels * samplewidth) +
|
||||
memcpy(data + (i * resample_to_channels * samplewidth) +
|
||||
(samplewidth * j), &cval1, samplewidth);
|
||||
}
|
||||
}
|
||||
@ -349,14 +353,14 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
|
||||
|
||||
sval1 += (sint16) (sval2 * part) / 100;
|
||||
|
||||
memcpy(*out + (i * resample_to_channels * samplewidth) +
|
||||
memcpy(data + (i * resample_to_channels * samplewidth) +
|
||||
(samplewidth * j), &sval1, samplewidth);
|
||||
}
|
||||
}
|
||||
#else /* Nearest neighbor search */
|
||||
for (j = 0; j < resample_to_channels; j++)
|
||||
{
|
||||
memcpy(*out + (i * resample_to_channels * samplewidth) + (samplewidth * j),
|
||||
memcpy(out + (i * resample_to_channels * samplewidth) + (samplewidth * j),
|
||||
in + (source * resample_to_channels * samplewidth) +
|
||||
(samplewidth * j), samplewidth);
|
||||
}
|
||||
@ -378,7 +382,7 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
|
||||
{
|
||||
for (i = 0; i < outsize; i++)
|
||||
{
|
||||
*out[i] = *out[i * 2];
|
||||
data[i] = data[i * 2];
|
||||
}
|
||||
outsize /= 2;
|
||||
}
|
||||
@ -386,16 +390,17 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
|
||||
|
||||
#ifdef B_ENDIAN
|
||||
if (!stream_be)
|
||||
rdpsnd_dsp_swapbytes(*out, outsize, format);
|
||||
rdpsnd_dsp_swapbytes(data, outsize, format);
|
||||
#endif
|
||||
return outsize;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
STREAM
|
||||
rdpsnd_dsp_process(unsigned char *data, unsigned int size, struct audio_driver * current_driver,
|
||||
RD_WAVEFORMATEX * format)
|
||||
{
|
||||
static struct stream out;
|
||||
STREAM out;
|
||||
RD_BOOL stream_be = False;
|
||||
|
||||
/* softvol and byteswap do not change the amount of data they
|
||||
@ -411,20 +416,19 @@ rdpsnd_dsp_process(unsigned char *data, unsigned int size, struct audio_driver *
|
||||
}
|
||||
#endif
|
||||
|
||||
out.data = NULL;
|
||||
out = NULL;
|
||||
|
||||
if (current_driver->need_resampling)
|
||||
out.size = rdpsnd_dsp_resample(&out.data, data, size, format, stream_be);
|
||||
out = rdpsnd_dsp_resample(data, size, format, stream_be);
|
||||
|
||||
if (out.data == NULL)
|
||||
if (out == NULL)
|
||||
{
|
||||
out.data = (unsigned char *) xmalloc(size);
|
||||
memcpy(out.data, data, size);
|
||||
out.size = size;
|
||||
out = s_alloc(size);
|
||||
out_uint8a(out, data, size);
|
||||
}
|
||||
|
||||
out.p = out.data;
|
||||
out.end = out.p + out.size;
|
||||
s_mark_end(out);
|
||||
s_seek(out, 0);
|
||||
|
||||
return &out;
|
||||
return out;
|
||||
}
|
||||
|
@ -148,6 +148,7 @@ libao_play(void)
|
||||
{
|
||||
struct audio_packet *packet;
|
||||
STREAM out;
|
||||
unsigned char *data;
|
||||
int len;
|
||||
static long prev_s, prev_us;
|
||||
int duration;
|
||||
@ -167,13 +168,13 @@ libao_play(void)
|
||||
return;
|
||||
|
||||
packet = rdpsnd_queue_current_packet();
|
||||
out = &packet->s;
|
||||
out = packet->s;
|
||||
|
||||
next_tick = rdpsnd_queue_next_tick();
|
||||
|
||||
len = (WAVEOUTLEN > (out->end - out->p)) ? (out->end - out->p) : WAVEOUTLEN;
|
||||
ao_play(o_device, (char *) out->p, len);
|
||||
out->p += len;
|
||||
len = MIN(WAVEOUTLEN, s_remaining(out));
|
||||
in_uint8p(out, data, len);
|
||||
ao_play(o_device, (char *) data, len);
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
@ -182,7 +183,7 @@ libao_play(void)
|
||||
if (packet->tick > next_tick)
|
||||
next_tick += 65536;
|
||||
|
||||
if ((out->p == out->end) || duration > next_tick - packet->tick + 500)
|
||||
if (s_check_end(out) || duration > next_tick - packet->tick + 500)
|
||||
{
|
||||
unsigned int delay_us;
|
||||
|
||||
|
16
rdpsnd_oss.c
16
rdpsnd_oss.c
@ -402,6 +402,8 @@ oss_play(void)
|
||||
struct audio_packet *packet;
|
||||
ssize_t len;
|
||||
STREAM out;
|
||||
size_t before;
|
||||
const unsigned char *data;
|
||||
|
||||
assert(dsp_fd != -1);
|
||||
|
||||
@ -410,11 +412,14 @@ oss_play(void)
|
||||
return;
|
||||
|
||||
packet = rdpsnd_queue_current_packet();
|
||||
out = &packet->s;
|
||||
out = packet->s;
|
||||
|
||||
len = out->end - out->p;
|
||||
before = s_tell(out);
|
||||
|
||||
len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
|
||||
len = MIN(s_remaining(out), MAX_LEN);
|
||||
in_uint8p(out, data, len);
|
||||
|
||||
len = write(dsp_fd, data, len);
|
||||
if (len == -1)
|
||||
{
|
||||
if (errno != EWOULDBLOCK)
|
||||
@ -429,9 +434,10 @@ oss_play(void)
|
||||
|
||||
dsp_broken = False;
|
||||
|
||||
out->p += len;
|
||||
/* We might not have written everything */
|
||||
s_seek(out, before + len);
|
||||
|
||||
if (out->p == out->end)
|
||||
if (s_check_end(out))
|
||||
{
|
||||
int delay_bytes;
|
||||
unsigned long delay_us;
|
||||
|
@ -1154,7 +1154,7 @@ pulse_play(void)
|
||||
do
|
||||
{
|
||||
packet = rdpsnd_queue_current_packet();
|
||||
out = &packet->s;
|
||||
out = packet->s;
|
||||
|
||||
ti = pa_stream_get_timing_info(playback_stream);
|
||||
if (ti == NULL)
|
||||
@ -1192,11 +1192,14 @@ pulse_play(void)
|
||||
playback_seek = PA_SEEK_RELATIVE;
|
||||
|
||||
avail_space = pa_stream_writable_size(playback_stream);
|
||||
audio_size = out->end - out->p <= avail_space ? out->end - out->p : avail_space;
|
||||
audio_size = MIN(s_remaining(out), avail_space);
|
||||
if (audio_size)
|
||||
{
|
||||
unsigned char *data;
|
||||
|
||||
in_uint8p(out, data, audio_size);
|
||||
if (pa_stream_write
|
||||
(playback_stream, out->p, audio_size, NULL, 0, playback_seek) != 0)
|
||||
(playback_stream, data, audio_size, NULL, 0, playback_seek) != 0)
|
||||
{
|
||||
err = pa_context_errno(context);
|
||||
logger(Sound, Error, "pulse_play(), pa_stream_write: %s",
|
||||
@ -1207,9 +1210,7 @@ pulse_play(void)
|
||||
playback_seek = PA_SEEK_RELATIVE;
|
||||
}
|
||||
|
||||
out->p += audio_size;
|
||||
|
||||
if (out->p == out->end)
|
||||
if (s_check_end(out))
|
||||
{
|
||||
ret = pa_stream_get_latency(playback_stream, &delay, NULL);
|
||||
if (ret != 0 && (err = pa_context_errno(context)) == PA_ERR_NODATA)
|
||||
@ -1251,7 +1252,7 @@ pulse_play(void)
|
||||
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
|
||||
if (out->p == out->end)
|
||||
if (s_check_end(out))
|
||||
rdpsnd_queue_next(delay);
|
||||
|
||||
return result;
|
||||
|
11
rdpsnd_sgi.c
11
rdpsnd_sgi.c
@ -246,6 +246,7 @@ sgi_play(void)
|
||||
struct audio_packet *packet;
|
||||
ssize_t len;
|
||||
STREAM out;
|
||||
unsigned char *data;
|
||||
int gf;
|
||||
|
||||
while (1)
|
||||
@ -254,14 +255,14 @@ sgi_play(void)
|
||||
return;
|
||||
|
||||
packet = rdpsnd_queue_current_packet();
|
||||
out = (STREAM) (void *) &(packet->s);
|
||||
out = packet->s;
|
||||
|
||||
len = out->end - out->p;
|
||||
len = s_remaining(out);
|
||||
in_uint8p(out, data, len);
|
||||
|
||||
alWriteFrames(output_port, out->p, len / combinedFrameSize);
|
||||
alWriteFrames(output_port, data, len / combinedFrameSize);
|
||||
|
||||
out->p += len;
|
||||
if (out->p == out->end)
|
||||
if (s_check_end(out))
|
||||
{
|
||||
gf = alGetFilled(output_port);
|
||||
if (gf < (4 * maxFillable / 10))
|
||||
|
16
rdpsnd_sun.c
16
rdpsnd_sun.c
@ -411,17 +411,22 @@ sun_play(void)
|
||||
struct audio_packet *packet;
|
||||
ssize_t len;
|
||||
STREAM out;
|
||||
size_t before;
|
||||
const unsigned char *data;
|
||||
|
||||
/* We shouldn't be called if the queue is empty, but still */
|
||||
if (rdpsnd_queue_empty())
|
||||
return;
|
||||
|
||||
packet = rdpsnd_queue_current_packet();
|
||||
out = &packet->s;
|
||||
out = packet->s;
|
||||
|
||||
len = out->end - out->p;
|
||||
before = s_tell(out);
|
||||
|
||||
len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
|
||||
len = MIN(s_remaining(out), MAX_LEN);
|
||||
in_uint8p(out, data, len);
|
||||
|
||||
len = write(dsp_fd, data, len);
|
||||
if (len == -1)
|
||||
{
|
||||
if (errno != EWOULDBLOCK)
|
||||
@ -439,9 +444,10 @@ sun_play(void)
|
||||
|
||||
dsp_broken = False;
|
||||
|
||||
out->p += len;
|
||||
/* We might not have written everything */
|
||||
s_seek(out, before + len);
|
||||
|
||||
if (out->p == out->end)
|
||||
if (s_check_end(out))
|
||||
{
|
||||
audio_info_t info;
|
||||
uint_t delay_samples;
|
||||
|
191
scard.c
191
scard.c
@ -237,10 +237,8 @@ scard_enum_devices(uint32 * id, char *optarg)
|
||||
|
||||
tmpMap = nameMapList + nameMapCount - 1;
|
||||
|
||||
len = strlen(alias);
|
||||
strncpy(tmpMap->alias, alias, (len > 127) ? (127) : (len));
|
||||
len = strlen(name);
|
||||
strncpy(tmpMap->name, name, (len > 127) ? (127) : (len));
|
||||
STRNCPY(tmpMap->alias, alias, sizeof(tmpMap->alias));
|
||||
STRNCPY(tmpMap->name, name, sizeof(tmpMap->name));
|
||||
|
||||
if (vendor)
|
||||
{
|
||||
@ -248,8 +246,8 @@ scard_enum_devices(uint32 * id, char *optarg)
|
||||
if (len > 0)
|
||||
{
|
||||
memset(tmpMap->vendor, 0, 128);
|
||||
strncpy(tmpMap->vendor, vendor,
|
||||
(len > 127) ? (127) : (len));
|
||||
STRNCPY(tmpMap->vendor, vendor,
|
||||
sizeof(tmpMap->vendor));
|
||||
}
|
||||
else
|
||||
tmpMap->vendor[0] = '\0';
|
||||
@ -550,7 +548,7 @@ outBufferFinishWithLimit(STREAM out, char *buffer, unsigned int length, unsigned
|
||||
{
|
||||
if (header < length)
|
||||
length = header;
|
||||
out_uint8p(out, buffer, length);
|
||||
out_uint8a(out, buffer, length);
|
||||
outRepos(out, length);
|
||||
}
|
||||
}
|
||||
@ -564,7 +562,7 @@ outBufferFinish(STREAM out, char *buffer, unsigned int length)
|
||||
static void
|
||||
outForceAlignment(STREAM out, unsigned int seed)
|
||||
{
|
||||
SERVER_DWORD add = (seed - (out->p - out->data) % seed) % seed;
|
||||
SERVER_DWORD add = (seed - s_tell(out) % seed) % seed;
|
||||
if (add > 0)
|
||||
out_uint8s(out, add);
|
||||
}
|
||||
@ -626,11 +624,11 @@ outString(STREAM out, char *source, RD_BOOL wide)
|
||||
buffer[2 * i] = reader[i];
|
||||
buffer[2 * i + 1] = '\0';
|
||||
}
|
||||
out_uint8p(out, buffer, 2 * dataLength);
|
||||
out_uint8a(out, buffer, 2 * dataLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_uint8p(out, reader, dataLength);
|
||||
out_uint8a(out, reader, dataLength);
|
||||
}
|
||||
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
@ -641,7 +639,7 @@ static void
|
||||
inReaderName(PMEM_HANDLE * handle, STREAM in, char **destination, RD_BOOL wide)
|
||||
{
|
||||
SERVER_DWORD dataLength;
|
||||
in->p += 0x08;
|
||||
in_uint8s(in, 0x08);
|
||||
in_uint32_le(in, dataLength);
|
||||
inRepos(in, inString(handle, in, destination, dataLength, wide));
|
||||
}
|
||||
@ -719,6 +717,7 @@ TS_SCardEstablishContext(STREAM in, STREAM out)
|
||||
out_uint32_le(out, 0x00000004);
|
||||
out_uint32_le(out, hContext);
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -729,7 +728,7 @@ TS_SCardReleaseContext(STREAM in, STREAM out)
|
||||
MYPCSC_SCARDCONTEXT myHContext;
|
||||
SERVER_SCARDCONTEXT hContext;
|
||||
|
||||
in->p += 0x1C;
|
||||
in_uint8s(in, 0x1C);
|
||||
in_uint32_le(in, hContext);
|
||||
myHContext = _scard_handle_list_get_pcsc_handle(hContext);
|
||||
|
||||
@ -754,6 +753,7 @@ TS_SCardReleaseContext(STREAM in, STREAM out)
|
||||
}
|
||||
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -764,7 +764,7 @@ TS_SCardIsValidContext(STREAM in, STREAM out)
|
||||
SERVER_SCARDCONTEXT hContext;
|
||||
MYPCSC_SCARDCONTEXT myHContext;
|
||||
|
||||
in->p += 0x1C;
|
||||
in_uint8s(in, 0x1C);
|
||||
in_uint32_le(in, hContext);
|
||||
|
||||
myHContext = _scard_handle_list_get_pcsc_handle(hContext);
|
||||
@ -788,6 +788,7 @@ TS_SCardIsValidContext(STREAM in, STREAM out)
|
||||
}
|
||||
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -801,21 +802,21 @@ TS_SCardListReaders(STREAM in, STREAM out, RD_BOOL wide)
|
||||
MYPCSC_SCARDCONTEXT myHContext;
|
||||
SERVER_DWORD dataLength;
|
||||
MYPCSC_DWORD cchReaders = readerArraySize;
|
||||
unsigned char *plen1, *plen2, *pend;
|
||||
size_t plen1, plen2, pend;
|
||||
char *readers, *cur;
|
||||
PMEM_HANDLE lcHandle = NULL;
|
||||
|
||||
in->p += 0x2C;
|
||||
in_uint8s(in, 0x2C);
|
||||
in_uint32_le(in, hContext);
|
||||
myHContext = _scard_handle_list_get_pcsc_handle(hContext);
|
||||
|
||||
logger(SmartCard, Debug, "TS_SCardListReaders(), context: 0x%08x [0x%lx])",
|
||||
(unsigned) hContext, myHContext);
|
||||
|
||||
plen1 = out->p;
|
||||
plen1 = s_tell(out);
|
||||
out_uint32_le(out, 0x00000000); /* Temp value for data length as 0x0 */
|
||||
out_uint32_le(out, 0x01760650);
|
||||
plen2 = out->p;
|
||||
plen2 = s_tell(out);
|
||||
out_uint32_le(out, 0x00000000); /* Temp value for data length as 0x0 */
|
||||
|
||||
dataLength = 0;
|
||||
@ -865,14 +866,17 @@ TS_SCardListReaders(STREAM in, STREAM out, RD_BOOL wide)
|
||||
dataLength += outString(out, "\0", wide);
|
||||
outRepos(out, dataLength);
|
||||
|
||||
pend = out->p;
|
||||
out->p = plen1;
|
||||
s_mark_end(out);
|
||||
|
||||
pend = s_tell(out);
|
||||
s_seek(out, plen1);
|
||||
out_uint32_le(out, dataLength);
|
||||
out->p = plen2;
|
||||
s_seek(out, plen2);
|
||||
out_uint32_le(out, dataLength);
|
||||
out->p = pend;
|
||||
s_seek(out, pend);
|
||||
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -893,11 +897,11 @@ TS_SCardConnect(STREAM in, STREAM out, RD_BOOL wide)
|
||||
MYPCSC_DWORD dwActiveProtocol;
|
||||
PMEM_HANDLE lcHandle = NULL;
|
||||
|
||||
in->p += 0x1C;
|
||||
in_uint8s(in, 0x1C);
|
||||
in_uint32_le(in, dwShareMode);
|
||||
in_uint32_le(in, dwPreferredProtocol);
|
||||
inReaderName(&lcHandle, in, &szReader, wide);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, hContext);
|
||||
|
||||
myHContext = _scard_handle_list_get_pcsc_handle(hContext);
|
||||
@ -968,6 +972,7 @@ TS_SCardConnect(STREAM in, STREAM out, RD_BOOL wide)
|
||||
out_uint32_le(out, hCard);
|
||||
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -984,13 +989,13 @@ TS_SCardReconnect(STREAM in, STREAM out)
|
||||
SERVER_DWORD dwInitialization;
|
||||
MYPCSC_DWORD dwActiveProtocol;
|
||||
|
||||
in->p += 0x20;
|
||||
in_uint8s(in, 0x20);
|
||||
in_uint32_le(in, dwShareMode);
|
||||
in_uint32_le(in, dwPreferredProtocol);
|
||||
in_uint32_le(in, dwInitialization);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, hContext);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, hCard);
|
||||
|
||||
|
||||
@ -1016,6 +1021,7 @@ TS_SCardReconnect(STREAM in, STREAM out)
|
||||
|
||||
out_uint32_le(out, (SERVER_DWORD) dwActiveProtocol);
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1029,11 +1035,11 @@ TS_SCardDisconnect(STREAM in, STREAM out)
|
||||
MYPCSC_SCARDHANDLE myHCard;
|
||||
SERVER_DWORD dwDisposition;
|
||||
|
||||
in->p += 0x20;
|
||||
in_uint8s(in, 0x20);
|
||||
in_uint32_le(in, dwDisposition);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, hContext);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, hCard);
|
||||
|
||||
myHContext = _scard_handle_list_get_pcsc_handle(hContext);
|
||||
@ -1078,6 +1084,7 @@ TS_SCardDisconnect(STREAM in, STREAM out)
|
||||
}
|
||||
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1164,12 +1171,12 @@ TS_SCardGetStatusChange(STREAM in, STREAM out, RD_BOOL wide)
|
||||
long i;
|
||||
PMEM_HANDLE lcHandle = NULL;
|
||||
|
||||
in->p += 0x18;
|
||||
in_uint8s(in, 0x18);
|
||||
in_uint32_le(in, dwTimeout);
|
||||
in_uint32_le(in, dwCount);
|
||||
in->p += 0x08;
|
||||
in_uint8s(in, 0x08);
|
||||
in_uint32_le(in, hContext);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
|
||||
myHContext = _scard_handle_list_get_pcsc_handle(hContext);
|
||||
|
||||
@ -1199,7 +1206,7 @@ TS_SCardGetStatusChange(STREAM in, STREAM out, RD_BOOL wide)
|
||||
{
|
||||
SERVER_DWORD dataLength;
|
||||
|
||||
in->p += 0x08;
|
||||
in_uint8s(in, 0x08);
|
||||
in_uint32_le(in, dataLength);
|
||||
inRepos(in,
|
||||
inString(&lcHandle, in, (char **) &(cur->szReader),
|
||||
@ -1257,10 +1264,11 @@ TS_SCardGetStatusChange(STREAM in, STREAM out, RD_BOOL wide)
|
||||
cur->dwEventState = swap32(cur->dwEventState);
|
||||
cur->cbAtr = swap32(cur->cbAtr);
|
||||
|
||||
out_uint8p(out, (void *) ((unsigned char **) cur + 2),
|
||||
out_uint8a(out, (void *) ((unsigned char **) cur + 2),
|
||||
sizeof(SERVER_SCARD_READERSTATE_A) - 2 * sizeof(unsigned char *));
|
||||
}
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -1272,7 +1280,7 @@ TS_SCardCancel(STREAM in, STREAM out)
|
||||
SERVER_SCARDCONTEXT hContext;
|
||||
MYPCSC_SCARDCONTEXT myHContext;
|
||||
|
||||
in->p += 0x1C;
|
||||
in_uint8s(in, 0x1C);
|
||||
in_uint32_le(in, hContext);
|
||||
|
||||
myHContext = _scard_handle_list_get_pcsc_handle(hContext);
|
||||
@ -1291,6 +1299,7 @@ TS_SCardCancel(STREAM in, STREAM out)
|
||||
logger(SmartCard, Debug, "TS_SCardCancel(), success");
|
||||
}
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1311,7 +1320,7 @@ TS_SCardLocateCardsByATR(STREAM in, STREAM out, RD_BOOL wide)
|
||||
MYPCSC_LPSCARD_READERSTATE_A myRsArray;
|
||||
PMEM_HANDLE lcHandle = NULL;
|
||||
|
||||
in->p += 0x2C;
|
||||
in_uint8s(in, 0x2C);
|
||||
in_uint32_le(in, hContext);
|
||||
in_uint32_le(in, atrMaskCount);
|
||||
pAtrMasks = SC_xmalloc(&lcHandle, atrMaskCount * sizeof(SCARD_ATRMASK_L));
|
||||
@ -1421,11 +1430,12 @@ TS_SCardLocateCardsByATR(STREAM in, STREAM out, RD_BOOL wide)
|
||||
rsCur->dwEventState = swap32(rsCur->dwEventState);
|
||||
rsCur->cbAtr = swap32(rsCur->cbAtr);
|
||||
|
||||
out_uint8p(out, (void *) ((unsigned char **) rsCur + 2),
|
||||
out_uint8a(out, (void *) ((unsigned char **) rsCur + 2),
|
||||
sizeof(SCARD_READERSTATE) - 2 * sizeof(unsigned char *));
|
||||
}
|
||||
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -1437,7 +1447,7 @@ TS_SCardBeginTransaction(STREAM in, STREAM out)
|
||||
SERVER_SCARDCONTEXT hCard;
|
||||
MYPCSC_SCARDCONTEXT myHCard;
|
||||
|
||||
in->p += 0x30;
|
||||
in_uint8s(in, 0x30);
|
||||
in_uint32_le(in, hCard);
|
||||
myHCard = _scard_handle_list_get_pcsc_handle(hCard);
|
||||
logger(SmartCard, Debug, "TS_SCardBeginTransaction(), hcard: 0x%08x [0x%lx])",
|
||||
@ -1453,6 +1463,7 @@ TS_SCardBeginTransaction(STREAM in, STREAM out)
|
||||
logger(SmartCard, Debug, "TS_SCardBeginTransaction(), success");
|
||||
}
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1464,9 +1475,9 @@ TS_SCardEndTransaction(STREAM in, STREAM out)
|
||||
MYPCSC_SCARDCONTEXT myHCard;
|
||||
SERVER_DWORD dwDisposition = 0;
|
||||
|
||||
in->p += 0x20;
|
||||
in_uint8s(in, 0x20);
|
||||
in_uint32_le(in, dwDisposition);
|
||||
in->p += 0x0C;
|
||||
in_uint8s(in, 0x0C);
|
||||
in_uint32_le(in, hCard);
|
||||
|
||||
myHCard = _scard_handle_list_get_pcsc_handle(hCard);
|
||||
@ -1485,6 +1496,7 @@ TS_SCardEndTransaction(STREAM in, STREAM out)
|
||||
logger(SmartCard, Debug, "TS_SCardEndTransaction(), success");
|
||||
}
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1533,9 +1545,9 @@ TS_SCardTransmit(STREAM in, STREAM out, uint32 srv_buf_len)
|
||||
PMEM_HANDLE lcHandle = NULL;
|
||||
|
||||
|
||||
in->p += 0x14;
|
||||
in_uint8s(in, 0x14);
|
||||
in_uint32_le(in, map[0]);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, map[1]);
|
||||
pioSendPci = SC_xmalloc(&lcHandle, sizeof(SERVER_SCARD_IO_REQUEST));
|
||||
if (!pioSendPci)
|
||||
@ -1553,7 +1565,7 @@ TS_SCardTransmit(STREAM in, STREAM out, uint32 srv_buf_len)
|
||||
if (srv_buf_len <= cbRecvLength)
|
||||
cbRecvLength = srv_buf_len;
|
||||
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, hCard);
|
||||
myHCard = _scard_handle_list_get_pcsc_handle(hCard);
|
||||
|
||||
@ -1697,6 +1709,7 @@ TS_SCardTransmit(STREAM in, STREAM out, uint32 srv_buf_len)
|
||||
outBufferFinish(out, (char *) recvBuf, cbRecvLength);
|
||||
}
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -1714,12 +1727,12 @@ TS_SCardStatus(STREAM in, STREAM out, RD_BOOL wide)
|
||||
char *readerName;
|
||||
unsigned char *atr;
|
||||
|
||||
in->p += 0x24;
|
||||
in_uint8s(in, 0x24);
|
||||
in_uint32_le(in, dwReaderLen);
|
||||
in_uint32_le(in, dwAtrLen);
|
||||
in->p += 0x0C;
|
||||
in_uint8s(in, 0x0C);
|
||||
in_uint32_le(in, hCard);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
myHCard = _scard_handle_list_get_pcsc_handle(hCard);
|
||||
logger(SmartCard, Debug,
|
||||
"TS_SCardStatus(), hcard: 0x%08x [0x%08lx], reader len: %d bytes, atr len: %d bytes",
|
||||
@ -1792,31 +1805,33 @@ TS_SCardStatus(STREAM in, STREAM out, RD_BOOL wide)
|
||||
else
|
||||
dwState = 0x00000000;
|
||||
|
||||
void *p_len1 = out->p;
|
||||
size_t p_len1 = s_tell(out);
|
||||
out_uint32_le(out, dwReaderLen);
|
||||
out_uint32_le(out, 0x00020000);
|
||||
out_uint32_le(out, dwState);
|
||||
out_uint32_le(out, dwProtocol);
|
||||
out_uint8p(out, atr, dwAtrLen);
|
||||
out_uint8a(out, atr, dwAtrLen);
|
||||
if (dwAtrLen < 32)
|
||||
{
|
||||
out_uint8s(out, 32 - dwAtrLen);
|
||||
}
|
||||
out_uint32_le(out, dwAtrLen);
|
||||
|
||||
void *p_len2 = out->p;
|
||||
size_t p_len2 = s_tell(out);
|
||||
out_uint32_le(out, dwReaderLen);
|
||||
dataLength = outString(out, readerName, wide);
|
||||
dataLength += outString(out, "\0", wide);
|
||||
outRepos(out, dataLength);
|
||||
void *psave = out->p;
|
||||
out->p = p_len1;
|
||||
s_mark_end(out);
|
||||
size_t psave = s_tell(out);
|
||||
s_seek(out, p_len1);
|
||||
out_uint32_le(out, dataLength);
|
||||
out->p = p_len2;
|
||||
s_seek(out, p_len2);
|
||||
out_uint32_le(out, dataLength);
|
||||
out->p = psave;
|
||||
s_seek(out, psave);
|
||||
}
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -1833,11 +1848,11 @@ TS_SCardState(STREAM in, STREAM out)
|
||||
char *readerName;
|
||||
unsigned char *atr;
|
||||
|
||||
in->p += 0x24;
|
||||
in_uint8s(in, 0x24);
|
||||
in_uint32_le(in, dwAtrLen);
|
||||
in->p += 0x0C;
|
||||
in_uint8s(in, 0x0C);
|
||||
in_uint32_le(in, hCard);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
myHCard = _scard_handle_list_get_pcsc_handle(hCard);
|
||||
|
||||
logger(SmartCard, Debug, "TS_SCardState(), hcard: 0x%08x [0x%08lx], atrlen: %d bytes",
|
||||
@ -1903,10 +1918,11 @@ TS_SCardState(STREAM in, STREAM out)
|
||||
out_uint32_le(out, dwAtrLen);
|
||||
out_uint32_le(out, 0x00000001);
|
||||
out_uint32_le(out, dwAtrLen);
|
||||
out_uint8p(out, atr, dwAtrLen);
|
||||
out_uint8a(out, atr, dwAtrLen);
|
||||
outRepos(out, dwAtrLen);
|
||||
}
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -1928,9 +1944,9 @@ TS_SCardListReaderGroups(STREAM in, STREAM out)
|
||||
char *szGroups;
|
||||
PMEM_HANDLE lcHandle = NULL;
|
||||
|
||||
in->p += 0x20;
|
||||
in_uint8s(in, 0x20);
|
||||
in_uint32_le(in, dwGroups);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, hContext);
|
||||
|
||||
myHContext = _scard_handle_list_get_pcsc_handle(hContext);
|
||||
@ -1976,6 +1992,7 @@ TS_SCardListReaderGroups(STREAM in, STREAM out)
|
||||
out_uint32_le(out, 0x00000000);
|
||||
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -1992,11 +2009,11 @@ TS_SCardGetAttrib(STREAM in, STREAM out)
|
||||
unsigned char *pbAttr;
|
||||
PMEM_HANDLE lcHandle = NULL;
|
||||
|
||||
in->p += 0x20;
|
||||
in_uint8s(in, 0x20);
|
||||
in_uint32_le(in, dwAttrId);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, dwAttrLen);
|
||||
in->p += 0x0C;
|
||||
in_uint8s(in, 0x0C);
|
||||
in_uint32_le(in, hCard);
|
||||
myHCard = _scard_handle_list_get_pcsc_handle(hCard);
|
||||
|
||||
@ -2040,12 +2057,13 @@ TS_SCardGetAttrib(STREAM in, STREAM out)
|
||||
}
|
||||
else
|
||||
{
|
||||
out_uint8p(out, pbAttr, dwAttrLen);
|
||||
out_uint8a(out, pbAttr, dwAttrLen);
|
||||
}
|
||||
outRepos(out, dwAttrLen);
|
||||
out_uint32_le(out, 0x00000000);
|
||||
}
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -2062,11 +2080,11 @@ TS_SCardSetAttrib(STREAM in, STREAM out)
|
||||
unsigned char *pbAttr;
|
||||
PMEM_HANDLE lcHandle = NULL;
|
||||
|
||||
in->p += 0x20;
|
||||
in_uint8s(in, 0x20);
|
||||
in_uint32_le(in, dwAttrId);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, dwAttrLen);
|
||||
in->p += 0x0C;
|
||||
in_uint8s(in, 0x0C);
|
||||
in_uint32_le(in, hCard);
|
||||
myHCard = scHandleToMyPCSC(hCard);
|
||||
|
||||
@ -2100,6 +2118,7 @@ TS_SCardSetAttrib(STREAM in, STREAM out)
|
||||
out_uint32_le(out, 0x00000000);
|
||||
out_uint32_le(out, 0x00000000);
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -2125,18 +2144,18 @@ TS_SCardControl(STREAM in, STREAM out)
|
||||
pInBuffer = NULL;
|
||||
pOutBuffer = NULL;
|
||||
|
||||
in->p += 0x14;
|
||||
in_uint8s(in, 0x14);
|
||||
in_uint32_le(in, map[0]);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, map[1]);
|
||||
in_uint32_le(in, dwControlCode);
|
||||
in_uint32_le(in, nInBufferSize);
|
||||
in_uint32_le(in, map[2]);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, nOutBufferSize);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, hContext);
|
||||
in->p += 0x04;
|
||||
in_uint8s(in, 0x04);
|
||||
in_uint32_le(in, hCard);
|
||||
if (map[2] & INPUT_LINKED)
|
||||
{
|
||||
@ -2238,11 +2257,12 @@ TS_SCardControl(STREAM in, STREAM out)
|
||||
out_uint32_le(out, nBytesReturned);
|
||||
if (nBytesReturned > 0)
|
||||
{
|
||||
out_uint8p(out, pOutBuffer, nBytesReturned);
|
||||
out_uint8a(out, pOutBuffer, nBytesReturned);
|
||||
outRepos(out, nBytesReturned);
|
||||
}
|
||||
|
||||
outForceAlignment(out, 8);
|
||||
s_mark_end(out);
|
||||
SC_xfreeallmemory(&lcHandle);
|
||||
return rv;
|
||||
}
|
||||
@ -2262,7 +2282,7 @@ scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out,
|
||||
{
|
||||
UNUSED(handle);
|
||||
SERVER_DWORD Result = 0x00000000;
|
||||
unsigned char *psize, *pend, *pStatusCode;
|
||||
size_t psize, pend, pStatusCode;
|
||||
SERVER_DWORD addToEnd = 0;
|
||||
|
||||
/* Processing request */
|
||||
@ -2272,11 +2292,11 @@ scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out,
|
||||
/* Set CommonTypeHeader (MS-RPCE 2.2.6.1) */
|
||||
out_uint32_le(out, 0x00081001); /* Header lines */
|
||||
out_uint32_le(out, 0xCCCCCCCC);
|
||||
psize = out->p;
|
||||
psize = s_tell(out);
|
||||
/* Set PrivateTypeHeader (MS-RPCE 2.2.6.2) */
|
||||
out_uint32_le(out, 0x00000000); /* Size of data portion */
|
||||
out_uint32_le(out, 0x00000000); /* Zero bytes (may be useful) */
|
||||
pStatusCode = out->p;
|
||||
pStatusCode = s_tell(out);
|
||||
out_uint32_le(out, 0x00000000); /* Status Code */
|
||||
|
||||
switch (request)
|
||||
@ -2412,22 +2432,25 @@ scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out,
|
||||
#if 0
|
||||
out_uint32_le(out, 0x00000000);
|
||||
#endif
|
||||
s_mark_end(out);
|
||||
|
||||
/* Setting modified variables */
|
||||
pend = out->p;
|
||||
pend = s_tell(out);
|
||||
/* setting data size */
|
||||
out->p = psize;
|
||||
s_seek(out, psize);
|
||||
out_uint32_le(out, pend - psize - 16);
|
||||
/* setting status code */
|
||||
out->p = pStatusCode;
|
||||
s_seek(out, pStatusCode);
|
||||
out_uint32_le(out, Result);
|
||||
/* finish */
|
||||
out->p = pend;
|
||||
s_seek(out, pend);
|
||||
|
||||
/* TODO: Check MS-RPCE 2.2.6.2 for alignment requirements (IIRC length must be integral multiple of 8) */
|
||||
addToEnd = (pend - pStatusCode) % 16;
|
||||
if (addToEnd < 16 && addToEnd > 0)
|
||||
{
|
||||
out_uint8s(out, addToEnd);
|
||||
s_mark_end(out);
|
||||
}
|
||||
|
||||
if (Result == SCARD_E_INSUFFICIENT_BUFFER) return RD_STATUS_BUFFER_TOO_SMALL;
|
||||
@ -2440,6 +2463,7 @@ scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out,
|
||||
static STREAM
|
||||
duplicateStream(PMEM_HANDLE * handle, STREAM s, uint32 buffer_size, RD_BOOL isInputStream)
|
||||
{
|
||||
// FIXME: Shouldn't be allocating streams manually
|
||||
STREAM d = SC_xmalloc(handle, sizeof(struct stream));
|
||||
if (d != NULL)
|
||||
{
|
||||
@ -2575,13 +2599,18 @@ SC_deviceControl(PSCThreadData data)
|
||||
RD_NTSTATUS status;
|
||||
size_t buffer_len = 0;
|
||||
status = scard_device_control(data->handle, data->request, data->in, data->out, data->srv_buf_len);
|
||||
buffer_len = (size_t) data->out->p - (size_t) data->out->data;
|
||||
buffer_len = s_tell(data->out);
|
||||
|
||||
/* if iorequest belongs to another epoch, don't send response
|
||||
back to server due to it's considered as abandoned.
|
||||
*/
|
||||
if (data->epoch == curEpoch)
|
||||
rdpdr_send_completion(data->device, data->id, status, buffer_len, data->out->data, buffer_len);
|
||||
{
|
||||
uint8 *buf;
|
||||
s_seek(data->out, 0);
|
||||
in_uint8p(data->out, buf, buffer_len);
|
||||
rdpdr_send_completion(data->device, data->id, status, buffer_len, buf, buffer_len);
|
||||
}
|
||||
|
||||
SC_destroyThreadData(data);
|
||||
}
|
||||
|
14
seamless.c
14
seamless.c
@ -376,17 +376,12 @@ seamless_process(STREAM s)
|
||||
{
|
||||
unsigned int pkglen;
|
||||
char *buf;
|
||||
struct stream packet = *s;
|
||||
|
||||
if (!s_check(s))
|
||||
{
|
||||
rdp_protocol_error("seamless_process(), stream is in unstable state", &packet);
|
||||
}
|
||||
|
||||
pkglen = s->end - s->p;
|
||||
pkglen = s_remaining(s);
|
||||
/* str_handle_lines requires null terminated strings */
|
||||
buf = xmalloc(pkglen + 1);
|
||||
STRNCPY(buf, (char *) s->p, pkglen + 1);
|
||||
in_uint8a(s, buf, pkglen);
|
||||
buf[pkglen] = '\0';
|
||||
str_handle_lines(buf, &seamless_rest, seamless_line_handler, NULL);
|
||||
|
||||
xfree(buf);
|
||||
@ -446,11 +441,12 @@ seamless_send(const char *command, const char *format, ...)
|
||||
len++;
|
||||
|
||||
s = channel_init(seamless_channel, len);
|
||||
out_uint8p(s, buf, len) s_mark_end(s);
|
||||
out_uint8a(s, buf, len) s_mark_end(s);
|
||||
|
||||
logger(Core, Debug, "seamless_send(), sending '%s'", buf);
|
||||
|
||||
channel_send(s, seamless_channel);
|
||||
s_free(s);
|
||||
|
||||
return seamless_serial++;
|
||||
}
|
||||
|
123
secure.c
123
secure.c
@ -351,10 +351,12 @@ sec_send_to_channel(STREAM s, uint32 flags, uint16 channel)
|
||||
|
||||
if (flags & SEC_ENCRYPT)
|
||||
{
|
||||
unsigned char *data;
|
||||
flags &= ~SEC_ENCRYPT;
|
||||
datalen = s->end - s->p - 8;
|
||||
sec_sign(s->p, 8, g_sec_sign_key, g_rc4_key_len, s->p + 8, datalen);
|
||||
sec_encrypt(s->p + 8, datalen);
|
||||
datalen = s_remaining(s) - 8;
|
||||
inout_uint8p(s, data, datalen + 8);
|
||||
sec_sign(data, 8, g_sec_sign_key, g_rc4_key_len, data + 8, datalen);
|
||||
sec_encrypt(data + 8, datalen);
|
||||
}
|
||||
|
||||
mcs_send_to_channel(s, channel);
|
||||
@ -384,11 +386,12 @@ sec_establish_key(void)
|
||||
s = sec_init(flags, length + 4);
|
||||
|
||||
out_uint32_le(s, length);
|
||||
out_uint8p(s, g_sec_crypted_random, g_server_public_key_len);
|
||||
out_uint8a(s, g_sec_crypted_random, g_server_public_key_len);
|
||||
out_uint8s(s, SEC_PADDING_SIZE);
|
||||
|
||||
s_mark_end(s);
|
||||
sec_send(s, flags);
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/* Output connect initial data blob */
|
||||
@ -523,6 +526,10 @@ sec_parse_public_key(STREAM s, uint8 * modulus, uint8 * exponent)
|
||||
{
|
||||
uint32 magic, modulus_len;
|
||||
|
||||
if (!s_check_rem(s, 8)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
in_uint32_le(s, magic);
|
||||
if (magic != SEC_RSA_MAGIC)
|
||||
{
|
||||
@ -541,13 +548,17 @@ sec_parse_public_key(STREAM s, uint8 * modulus, uint8 * exponent)
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!s_check_rem(s, 1 + SEC_EXPONENT_SIZE + modulus_len + SEC_PADDING_SIZE)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
in_uint8s(s, 8); /* modulus_bits, unknown */
|
||||
in_uint8a(s, exponent, SEC_EXPONENT_SIZE);
|
||||
in_uint8a(s, modulus, modulus_len);
|
||||
in_uint8s(s, SEC_PADDING_SIZE);
|
||||
g_server_public_key_len = modulus_len;
|
||||
|
||||
return s_check(s);
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Parse a public signature structure */
|
||||
@ -578,7 +589,7 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
|
||||
RDSSL_CERT *cacert, *server_cert;
|
||||
RDSSL_RKEY *server_public_key;
|
||||
uint16 tag, length;
|
||||
uint8 *next_tag, *end;
|
||||
size_t next_tag;
|
||||
|
||||
logger(Protocol, Debug, "%s()", __func__);
|
||||
|
||||
@ -604,10 +615,9 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
|
||||
in_uint8p(s, *server_random, random_len);
|
||||
|
||||
/* RSA info */
|
||||
end = s->p + rsa_info_len;
|
||||
if (end > s->end)
|
||||
if (!s_check_rem(s, rsa_info_len))
|
||||
{
|
||||
logger(Protocol, Error, "sec_parse_crypt_info(), end > s->end");
|
||||
logger(Protocol, Error, "sec_parse_crypt_info(), !s_check_rem(s, rsa_info_len)");
|
||||
return False;
|
||||
}
|
||||
|
||||
@ -618,12 +628,12 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
|
||||
"sec_parse_crypt_info(), We're going for the RDP4-style encryption");
|
||||
in_uint8s(s, 8); /* unknown */
|
||||
|
||||
while (s->p < end)
|
||||
while (!s_check_end(s))
|
||||
{
|
||||
in_uint16_le(s, tag);
|
||||
in_uint16_le(s, length);
|
||||
|
||||
next_tag = s->p + length;
|
||||
next_tag = s_tell(s) + length;
|
||||
|
||||
switch (tag)
|
||||
{
|
||||
@ -654,12 +664,13 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
|
||||
tag);
|
||||
}
|
||||
|
||||
s->p = next_tag;
|
||||
s_seek(s, next_tag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 certcount;
|
||||
unsigned char *certdata;
|
||||
|
||||
logger(Protocol, Debug,
|
||||
"sec_parse_crypt_info(), We're going for the RDP5-style encryption");
|
||||
@ -674,10 +685,11 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
|
||||
{ /* ignore all the certificates between the root and the signing CA */
|
||||
uint32 ignorelen;
|
||||
RDSSL_CERT *ignorecert;
|
||||
unsigned char *ignoredata;
|
||||
|
||||
in_uint32_le(s, ignorelen);
|
||||
ignorecert = rdssl_cert_read(s->p, ignorelen);
|
||||
in_uint8s(s, ignorelen);
|
||||
in_uint8p(s, ignoredata, ignorelen);
|
||||
ignorecert = rdssl_cert_read(ignoredata, ignorelen);
|
||||
if (ignorecert == NULL)
|
||||
{ /* XXX: error out? */
|
||||
logger(Protocol, Error,
|
||||
@ -697,10 +709,10 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
|
||||
http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
|
||||
*/
|
||||
in_uint32_le(s, cacert_len);
|
||||
in_uint8p(s, certdata, cacert_len);
|
||||
logger(Protocol, Debug,
|
||||
"sec_parse_crypt_info(), server CA Certificate length is %d", cacert_len);
|
||||
cacert = rdssl_cert_read(s->p, cacert_len);
|
||||
in_uint8s(s, cacert_len);
|
||||
cacert = rdssl_cert_read(certdata, cacert_len);
|
||||
if (NULL == cacert)
|
||||
{
|
||||
logger(Protocol, Error,
|
||||
@ -708,10 +720,10 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
|
||||
return False;
|
||||
}
|
||||
in_uint32_le(s, cert_len);
|
||||
in_uint8p(s, certdata, cert_len);
|
||||
logger(Protocol, Debug, "sec_parse_crypt_info(), certificate length is %d",
|
||||
cert_len);
|
||||
server_cert = rdssl_cert_read(s->p, cert_len);
|
||||
in_uint8s(s, cert_len);
|
||||
server_cert = rdssl_cert_read(certdata, cert_len);
|
||||
if (NULL == server_cert)
|
||||
{
|
||||
rdssl_cert_free(cacert);
|
||||
@ -805,7 +817,7 @@ void
|
||||
sec_process_mcs_data(STREAM s)
|
||||
{
|
||||
uint16 tag, length;
|
||||
uint8 *next_tag;
|
||||
size_t next_tag;
|
||||
uint8 len;
|
||||
|
||||
in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */
|
||||
@ -814,7 +826,7 @@ sec_process_mcs_data(STREAM s)
|
||||
in_uint8(s, len);
|
||||
logger(Protocol, Debug, "%s()", __func__);
|
||||
|
||||
while (s->p < s->end)
|
||||
while (!s_check_end(s))
|
||||
{
|
||||
in_uint16_le(s, tag);
|
||||
in_uint16_le(s, length);
|
||||
@ -822,7 +834,7 @@ sec_process_mcs_data(STREAM s)
|
||||
if (length <= 4)
|
||||
return;
|
||||
|
||||
next_tag = s->p + length - 4;
|
||||
next_tag = s_tell(s) + length - 4;
|
||||
|
||||
switch (tag)
|
||||
{
|
||||
@ -847,7 +859,7 @@ sec_process_mcs_data(STREAM s)
|
||||
logger(Protocol, Warning, "Unhandled response tag 0x%x", tag);
|
||||
}
|
||||
|
||||
s->p = next_tag;
|
||||
s_seek(s, next_tag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -860,6 +872,8 @@ sec_recv(RD_BOOL * is_fastpath)
|
||||
uint16 channel;
|
||||
STREAM s;
|
||||
struct stream packet;
|
||||
size_t data_offset;
|
||||
unsigned char *data;
|
||||
|
||||
while ((s = mcs_recv(&channel, is_fastpath, &fastpath_hdr)) != NULL)
|
||||
{
|
||||
@ -873,35 +887,50 @@ sec_recv(RD_BOOL * is_fastpath)
|
||||
if (fastpath_flags & FASTPATH_OUTPUT_ENCRYPTED)
|
||||
{
|
||||
if (!s_check_rem(s, 8)) {
|
||||
rdp_protocol_error("sec_recv(), consume fastpath signature from stream would overrun", &packet);
|
||||
rdp_protocol_error("consume fastpath signature from stream would overrun", &packet);
|
||||
}
|
||||
|
||||
in_uint8s(s, 8); /* signature */
|
||||
sec_decrypt(s->p, s->end - s->p);
|
||||
|
||||
data_offset = s_tell(s);
|
||||
|
||||
inout_uint8p(s, data, s_remaining(s));
|
||||
sec_decrypt(data, s_remaining(s));
|
||||
|
||||
s_seek(s, data_offset);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
if (g_encryption || (!g_licence_issued && !g_licence_error_result))
|
||||
{
|
||||
data_offset = s_tell(s);
|
||||
|
||||
/* TS_SECURITY_HEADER */
|
||||
in_uint16_le(s, sec_flags);
|
||||
in_uint8s(s, 2); /* skip sec_flags_hi */
|
||||
|
||||
if (g_encryption)
|
||||
{
|
||||
data_offset = s_tell(s);
|
||||
|
||||
if (sec_flags & SEC_ENCRYPT)
|
||||
{
|
||||
if (!s_check_rem(s, 8)) {
|
||||
rdp_protocol_error("sec_recv(), consume encrypt signature from stream would overrun", &packet);
|
||||
rdp_protocol_error("consume encrypt signature from stream would overrun", &packet);
|
||||
}
|
||||
|
||||
in_uint8s(s, 8); /* signature */
|
||||
sec_decrypt(s->p, s->end - s->p);
|
||||
|
||||
data_offset = s_tell(s);
|
||||
|
||||
inout_uint8p(s, data, s_remaining(s));
|
||||
sec_decrypt(data, s_remaining(s));
|
||||
}
|
||||
|
||||
if (sec_flags & SEC_LICENSE_PKT)
|
||||
{
|
||||
s_seek(s, data_offset);
|
||||
licence_process(s);
|
||||
continue;
|
||||
}
|
||||
@ -911,14 +940,18 @@ sec_recv(RD_BOOL * is_fastpath)
|
||||
uint8 swapbyte;
|
||||
|
||||
if (!s_check_rem(s, 8)) {
|
||||
rdp_protocol_error("sec_recv(), consume redirect signature from stream would overrun", &packet);
|
||||
rdp_protocol_error("consume redirect signature from stream would overrun", &packet);
|
||||
}
|
||||
|
||||
in_uint8s(s, 8); /* signature */
|
||||
sec_decrypt(s->p, s->end - s->p);
|
||||
|
||||
data_offset = s_tell(s);
|
||||
|
||||
inout_uint8p(s, data, s_remaining(s));
|
||||
sec_decrypt(data, s_remaining(s));
|
||||
|
||||
/* Check for a redirect packet, starts with 00 04 */
|
||||
if (s->p[0] == 0 && s->p[1] == 4)
|
||||
if (data[0] == 0 && data[1] == 4)
|
||||
{
|
||||
/* for some reason the PDU and the length seem to be swapped.
|
||||
This isn't good, but we're going to do a byte for byte
|
||||
@ -926,17 +959,17 @@ sec_recv(RD_BOOL * is_fastpath)
|
||||
where XX YY is the little endian length. We're going to
|
||||
use 04 00 as the PDU type, so after our swap this will look
|
||||
like: XX YY 04 00 */
|
||||
swapbyte = s->p[0];
|
||||
s->p[0] = s->p[2];
|
||||
s->p[2] = swapbyte;
|
||||
swapbyte = data[0];
|
||||
data[0] = data[2];
|
||||
data[2] = swapbyte;
|
||||
|
||||
swapbyte = s->p[1];
|
||||
s->p[1] = s->p[3];
|
||||
s->p[3] = swapbyte;
|
||||
swapbyte = data[1];
|
||||
data[1] = data[3];
|
||||
data[3] = swapbyte;
|
||||
|
||||
swapbyte = s->p[2];
|
||||
s->p[2] = s->p[3];
|
||||
s->p[3] = swapbyte;
|
||||
swapbyte = data[2];
|
||||
data[2] = data[3];
|
||||
data[3] = swapbyte;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -947,8 +980,9 @@ sec_recv(RD_BOOL * is_fastpath)
|
||||
licence_process(s);
|
||||
continue;
|
||||
}
|
||||
s->p -= 4;
|
||||
}
|
||||
|
||||
s_seek(s, data_offset);
|
||||
}
|
||||
|
||||
if (channel != MCS_GLOBAL_CHANNEL)
|
||||
@ -968,25 +1002,24 @@ RD_BOOL
|
||||
sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect)
|
||||
{
|
||||
uint32 selected_proto;
|
||||
struct stream mcs_data;
|
||||
STREAM mcs_data;
|
||||
|
||||
/* Start a MCS connect sequence */
|
||||
if (!mcs_connect_start(server, username, domain, password, reconnect, &selected_proto))
|
||||
return False;
|
||||
|
||||
/* We exchange some RDP data during the MCS-Connect */
|
||||
mcs_data.size = 512;
|
||||
mcs_data.p = mcs_data.data = (uint8 *) xmalloc(mcs_data.size);
|
||||
sec_out_mcs_connect_initial_pdu(&mcs_data, selected_proto);
|
||||
mcs_data = s_alloc(512);
|
||||
sec_out_mcs_connect_initial_pdu(mcs_data, selected_proto);
|
||||
|
||||
/* finalize the MCS connect sequence */
|
||||
if (!mcs_connect_finalize(&mcs_data))
|
||||
if (!mcs_connect_finalize(mcs_data))
|
||||
return False;
|
||||
|
||||
/* sec_process_mcs_data(&mcs_data); */
|
||||
if (g_encryption)
|
||||
sec_establish_key();
|
||||
xfree(mcs_data.data);
|
||||
s_free(mcs_data);
|
||||
return True;
|
||||
}
|
||||
|
||||
|
14
ssl.c
14
ssl.c
@ -74,20 +74,6 @@ rdssl_rc4_crypt(RDSSL_RC4 * rc4, uint8 * in_data, uint8 * out_data, uint32 len)
|
||||
arcfour_crypt(rc4, len, out_data, in_data);
|
||||
}
|
||||
|
||||
static void
|
||||
reverse(uint8 * p, int len)
|
||||
{
|
||||
int i, j;
|
||||
uint8 temp;
|
||||
|
||||
for (i = 0, j = len - 1; i < j; i++, j--)
|
||||
{
|
||||
temp = p[i];
|
||||
p[i] = p[j];
|
||||
p[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus,
|
||||
uint8 * exponent)
|
||||
|
27
stream.c
27
stream.c
@ -25,6 +25,31 @@
|
||||
|
||||
extern char g_codepage[16];
|
||||
|
||||
STREAM
|
||||
s_alloc(unsigned int size)
|
||||
{
|
||||
STREAM s;
|
||||
|
||||
s = xmalloc(sizeof(struct stream));
|
||||
memset(s, 0, sizeof(struct stream));
|
||||
s_realloc(s, size);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
STREAM
|
||||
s_inherit(unsigned char *data, unsigned int size)
|
||||
{
|
||||
STREAM s;
|
||||
|
||||
s = xmalloc(sizeof(struct stream));
|
||||
memset(s, 0, sizeof(struct stream));
|
||||
s->p = s->data = data;
|
||||
s->size = size;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
s_realloc(STREAM s, unsigned int size)
|
||||
{
|
||||
@ -59,6 +84,8 @@ s_reset(STREAM s)
|
||||
void
|
||||
s_free(STREAM s)
|
||||
{
|
||||
if (s == NULL)
|
||||
return;
|
||||
free(s->data);
|
||||
free(s);
|
||||
}
|
||||
|
118
stream.h
118
stream.h
@ -41,8 +41,15 @@ typedef struct stream
|
||||
}
|
||||
*STREAM;
|
||||
|
||||
/* Return a newly allocated STREAM object of the specified size */
|
||||
STREAM s_alloc(unsigned int size);
|
||||
/* Wrap an existing buffer in a STREAM object, transferring ownership */
|
||||
STREAM s_inherit(unsigned char *data, unsigned int size);
|
||||
/* Resize an existing STREAM object, keeping all data and offsets intact */
|
||||
void s_realloc(STREAM s, unsigned int size);
|
||||
/* Free STREAM object and its associated buffer */
|
||||
void s_free(STREAM s);
|
||||
/* Reset all internal offsets, but keep the allocated size */
|
||||
void s_reset(STREAM s);
|
||||
|
||||
void out_utf16s(STREAM s, const char *string);
|
||||
@ -52,42 +59,60 @@ void out_utf16s_no_eos(STREAM s, const char *string);
|
||||
size_t in_ansi_string(STREAM s, char *string, size_t len);
|
||||
|
||||
|
||||
/* Store current offset as header h and skip n bytes */
|
||||
#define s_push_layer(s,h,n) { (s)->h = (s)->p; (s)->p += n; }
|
||||
/* Set header h as current offset */
|
||||
#define s_pop_layer(s,h) (s)->p = (s)->h;
|
||||
/* Mark current offset as end of readable data */
|
||||
#define s_mark_end(s) (s)->end = (s)->p;
|
||||
#define s_check(s) ((s)->p <= (s)->end)
|
||||
#define s_check_rem(s,n) (s_check(s) && (n <= (s)->end - (s)->p))
|
||||
/* Return current read offset in the STREAM */
|
||||
#define s_tell(s) (size_t)((s)->p - (s)->data)
|
||||
/* Set current read offset in the STREAM */
|
||||
#define s_seek(s,o) (s)->p = (s)->data; s_assert_r(s,o); (s)->p += o;
|
||||
/* Returns number of bytes that can still be read from STREAM */
|
||||
#define s_remaining(s) (size_t)((s)->end - (s)->p)
|
||||
/* True if at least n bytes can still be read */
|
||||
#define s_check_rem(s,n) (((s)->p <= (s)->end) && ((size_t)n <= s_remaining(s)))
|
||||
/* True if all data has been read */
|
||||
#define s_check_end(s) ((s)->p == (s)->end)
|
||||
/* Return the total number of bytes that can be read */
|
||||
#define s_length(s) ((s)->end - (s)->data)
|
||||
#define s_left(s) ((s)->size - ((s)->p - (s)->data))
|
||||
/* Return the number of bytes that can still be written */
|
||||
#define s_left(s) ((s)->size - (size_t)((s)->p - (s)->data))
|
||||
|
||||
/* Verify that there is enough data/space before accessing a STREAM */
|
||||
#define s_assert_r(s,n) { if (!s_check_rem(s, n)) rdp_protocol_error( "unexpected stream overrun", s); }
|
||||
#define s_assert_w(s,n) { if (s_left(s) < (size_t)n) { logger(Core, Error, "%s:%d: %s(), %s", __FILE__, __LINE__, __func__, "unexpected stream overrun"); exit(0); } }
|
||||
|
||||
/* Read/write an unsigned integer in little-endian order */
|
||||
#if defined(L_ENDIAN) && !defined(NEED_ALIGN)
|
||||
#define in_uint16_le(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
|
||||
#define in_uint32_le(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
|
||||
#define in_uint64_le(s,v) { v = *(uint64 *)((s)->p); (s)->p += 8; }
|
||||
#define out_uint16_le(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
||||
#define out_uint32_le(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
||||
#define out_uint64_le(s,v) { *(uint64 *)((s)->p) = v; (s)->p += 8; }
|
||||
#define in_uint16_le(s,v) { s_assert_r(s, 2); v = *(uint16 *)((s)->p); (s)->p += 2; }
|
||||
#define in_uint32_le(s,v) { s_assert_r(s, 4); v = *(uint32 *)((s)->p); (s)->p += 4; }
|
||||
#define in_uint64_le(s,v) { s_assert_r(s, 8); v = *(uint64 *)((s)->p); (s)->p += 8; }
|
||||
#define out_uint16_le(s,v) { s_assert_w(s, 2); *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
||||
#define out_uint32_le(s,v) { s_assert_w(s, 4); *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
||||
#define out_uint64_le(s,v) { s_assert_w(s, 8); *(uint64 *)((s)->p) = v; (s)->p += 8; }
|
||||
#else
|
||||
#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; }
|
||||
#define in_uint32_le(s,v) { in_uint16_le(s,v) \
|
||||
#define in_uint16_le(s,v) { s_assert_r(s, 2); v = *((s)->p++); v += *((s)->p++) << 8; }
|
||||
#define in_uint32_le(s,v) { s_assert_r(s, 4); in_uint16_le(s,v) \
|
||||
v += *((s)->p++) << 16; v += *((s)->p++) << 24; }
|
||||
#define in_uint64_le(s,v) { in_uint32_le(s,v) \
|
||||
#define in_uint64_le(s,v) { s_assert_r(s, 8); in_uint32_le(s,v) \
|
||||
v += *((s)->p++) << 32; v += *((s)->p++) << 40; \
|
||||
v += *((s)->p++) << 48; v += *((s)->p++) << 56; }
|
||||
#define out_uint16_le(s,v) { *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; }
|
||||
#define out_uint32_le(s,v) { out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); }
|
||||
#define out_uint64_le(s,v) { out_uint32_le(s, (v) & 0xffffffff); out_uint32_le(s, ((v) >> 32) & 0xffffffff); }
|
||||
#define out_uint16_le(s,v) { s_assert_w(s, 2); *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; }
|
||||
#define out_uint32_le(s,v) { s_assert_w(s, 4); out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); }
|
||||
#define out_uint64_le(s,v) { s_assert_w(s, 8); out_uint32_le(s, (v) & 0xffffffff); out_uint32_le(s, ((v) >> 32) & 0xffffffff); }
|
||||
#endif
|
||||
|
||||
|
||||
/* Read/write an unsigned integer in big-endian order */
|
||||
#if defined(B_ENDIAN) && !defined(NEED_ALIGN)
|
||||
#define in_uint16_be(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
|
||||
#define in_uint32_be(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
|
||||
#define in_uint64_be(s,v) { v = *(uint64 *)((s)->p); (s)->p += 8; }
|
||||
#define out_uint16_be(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
||||
#define out_uint32_be(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
||||
#define out_uint64_be(s,v) { *(uint64 *)((s)->p) = v; (s)->p += 8; }
|
||||
#define in_uint16_be(s,v) { s_assert_r(s, 2); v = *(uint16 *)((s)->p); (s)->p += 2; }
|
||||
#define in_uint32_be(s,v) { s_assert_r(s, 4); v = *(uint32 *)((s)->p); (s)->p += 4; }
|
||||
#define in_uint64_be(s,v) { s_assert_r(s, 8); v = *(uint64 *)((s)->p); (s)->p += 8; }
|
||||
#define out_uint16_be(s,v) { s_assert_w(s, 2); *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
||||
#define out_uint32_be(s,v) { s_assert_w(s, 4); *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
||||
#define out_uint64_be(s,v) { s_assert_w(s, 8); *(uint64 *)((s)->p) = v; (s)->p += 8; }
|
||||
|
||||
#define B_ENDIAN_PREFERRED
|
||||
#define in_uint16(s,v) in_uint16_be(s,v)
|
||||
@ -99,12 +124,12 @@ size_t in_ansi_string(STREAM s, char *string, size_t len);
|
||||
#define out_uint64(s,v) out_uint64_be(s,v)
|
||||
|
||||
#else
|
||||
#define in_uint16_be(s,v) { v = *((s)->p++); next_be(s,v); }
|
||||
#define in_uint32_be(s,v) { in_uint16_be(s,v); next_be(s,v); next_be(s,v); }
|
||||
#define in_uint64_be(s,v) { in_uint32_be(s,v); next_be(s,v); next_be(s,v); next_be(s,v); next_be(s,v); }
|
||||
#define out_uint16_be(s,v) { *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; }
|
||||
#define out_uint32_be(s,v) { out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); }
|
||||
#define out_uint64_be(s,v) { out_uint32_be(s, ((v) >> 32) & 0xffffffff); out_uint32_be(s, (v) & 0xffffffff); }
|
||||
#define in_uint16_be(s,v) { s_assert_r(s, 2); v = *((s)->p++); next_be(s,v); }
|
||||
#define in_uint32_be(s,v) { s_assert_r(s, 4); in_uint16_be(s,v); next_be(s,v); next_be(s,v); }
|
||||
#define in_uint64_be(s,v) { s_assert_r(s, 8); in_uint32_be(s,v); next_be(s,v); next_be(s,v); next_be(s,v); next_be(s,v); }
|
||||
#define out_uint16_be(s,v) { s_assert_w(s, 2); *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; }
|
||||
#define out_uint32_be(s,v) { s_assert_w(s, 4); out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); }
|
||||
#define out_uint64_be(s,v) { s_assert_w(s, 8); out_uint32_be(s, ((v) >> 32) & 0xffffffff); out_uint32_be(s, (v) & 0xffffffff); }
|
||||
#endif
|
||||
|
||||
#ifndef B_ENDIAN_PREFERRED
|
||||
@ -116,18 +141,35 @@ size_t in_ansi_string(STREAM s, char *string, size_t len);
|
||||
#define out_uint64(s,v) out_uint64_le(s,v)
|
||||
#endif
|
||||
|
||||
#define in_uint8(s,v) v = *((s)->p++);
|
||||
#define in_uint8p(s,v,n) { v = (s)->p; (s)->p += n; }
|
||||
#define in_uint8a(s,v,n) { memcpy(v,(s)->p,n); (s)->p += n; }
|
||||
#define in_uint8s(s,n) (s)->p += n;
|
||||
#define in_skip(s,n) in_uint8s(s,n)
|
||||
#define out_uint8(s,v) *((s)->p++) = v;
|
||||
#define out_uint8p(s,v,n) { memcpy((s)->p,v,n); (s)->p += n; }
|
||||
#define out_uint8a(s,v,n) out_uint8p(s,v,n);
|
||||
#define out_uint8s(s,n) { memset((s)->p,0,n); (s)->p += n; }
|
||||
#define out_stream(s, v) out_uint8p(s, (v)->data, s_length((v)))
|
||||
/* Read a single unsigned byte in v from STREAM s */
|
||||
#define in_uint8(s,v) { s_assert_r(s, 1); v = *((s)->p++); }
|
||||
/* Return a pointer in v to manually read n bytes from STREAM s */
|
||||
#define in_uint8p(s,v,n) { s_assert_r(s, n); v = (s)->p; (s)->p += n; }
|
||||
/* Copy n bytes from STREAM s in to array v */
|
||||
#define in_uint8a(s,v,n) { s_assert_r(s, n); memcpy(v,(s)->p,n); (s)->p += n; }
|
||||
/* Skip reading n bytes in STREAM s */
|
||||
#define in_uint8s(s,n) { s_assert_r(s, n); (s)->p += n; }
|
||||
/* Write a single unsigned byte from v to STREAM s */
|
||||
#define out_uint8(s,v) { s_assert_w(s, 1); *((s)->p++) = v; }
|
||||
/* Return a pointer in v to manually fill in n bytes in STREAM s */
|
||||
#define out_uint8p(s,v,n) { s_assert_w(s, n); v = (s)->p; (s)->p += n; }
|
||||
/* 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; }
|
||||
/* Fill n bytes with 0:s in STREAM s */
|
||||
#define out_uint8s(s,n) { s_assert_w(s, n); memset((s)->p,0,n); (s)->p += n; }
|
||||
|
||||
#define next_be(s,v) v = ((v) << 8) + *((s)->p++);
|
||||
/* 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)))
|
||||
|
||||
/* Return a pointer in v to manually modify n bytes of STREAM s in place */
|
||||
#define inout_uint8p(s,v,n) { s_assert_r(s, n); s_assert_w(s, n); v = (s)->p; (s)->p += n; }
|
||||
|
||||
/* Read one more byte of an unsigned big-endian integer */
|
||||
#define next_be(s,v) { s_assert_r(s, 1); v = ((v) << 8) + *((s)->p++); }
|
||||
|
||||
|
||||
#endif /* _STREAM_H */
|
||||
|
122
tcp.c
122
tcp.c
@ -58,12 +58,6 @@
|
||||
#define INADDR_NONE ((unsigned long) -1)
|
||||
#endif
|
||||
|
||||
#ifdef WITH_SCARD
|
||||
#define STREAM_COUNT 8
|
||||
#else
|
||||
#define STREAM_COUNT 1
|
||||
#endif
|
||||
|
||||
#ifdef IPv6
|
||||
static struct addrinfo *g_server_address = NULL;
|
||||
#else
|
||||
@ -75,7 +69,6 @@ static RD_BOOL g_ssl_initialized = False;
|
||||
static int g_sock;
|
||||
static RD_BOOL g_run_ui = False;
|
||||
static struct stream g_in;
|
||||
static struct stream g_out[STREAM_COUNT];
|
||||
int g_tcp_port_rdp = TCP_PORT_RDP;
|
||||
|
||||
extern RD_BOOL g_exit_mainloop;
|
||||
@ -109,28 +102,16 @@ tcp_can_send(int sck, int millis)
|
||||
STREAM
|
||||
tcp_init(uint32 maxlen)
|
||||
{
|
||||
static int cur_stream_id = 0;
|
||||
STREAM result = NULL;
|
||||
|
||||
#ifdef WITH_SCARD
|
||||
scard_lock(SCARD_LOCK_TCP);
|
||||
#endif
|
||||
result = &g_out[cur_stream_id];
|
||||
s_realloc(result, maxlen);
|
||||
s_reset(result);
|
||||
cur_stream_id = (cur_stream_id + 1) % STREAM_COUNT;
|
||||
#ifdef WITH_SCARD
|
||||
scard_unlock(SCARD_LOCK_TCP);
|
||||
#endif
|
||||
return result;
|
||||
return s_alloc(maxlen);
|
||||
}
|
||||
|
||||
/* Send TCP transport data packet */
|
||||
void
|
||||
tcp_send(STREAM s)
|
||||
{
|
||||
int length = s->end - s->data;
|
||||
int sent, total = 0;
|
||||
size_t before;
|
||||
int length, sent;
|
||||
unsigned char *data;
|
||||
|
||||
if (g_network_error == True)
|
||||
return;
|
||||
@ -139,10 +120,16 @@ tcp_send(STREAM s)
|
||||
scard_lock(SCARD_LOCK_TCP);
|
||||
#endif
|
||||
|
||||
while (total < length)
|
||||
s_seek(s, 0);
|
||||
|
||||
while (!s_check_end(s))
|
||||
{
|
||||
before = s_tell(s);
|
||||
length = s_remaining(s);
|
||||
in_uint8p(s, data, length);
|
||||
|
||||
if (g_ssl_initialized) {
|
||||
sent = gnutls_record_send(g_tls_session, s->data + total, length - total);
|
||||
sent = gnutls_record_send(g_tls_session, data, length);
|
||||
if (sent <= 0) {
|
||||
if (gnutls_error_is_fatal(sent)) {
|
||||
#ifdef WITH_SCARD
|
||||
@ -159,7 +146,7 @@ tcp_send(STREAM s)
|
||||
}
|
||||
else
|
||||
{
|
||||
sent = send(g_sock, s->data + total, length - total, 0);
|
||||
sent = send(g_sock, data, length, 0);
|
||||
if (sent <= 0)
|
||||
{
|
||||
if (sent == -1 && TCP_BLOCKS)
|
||||
@ -179,7 +166,9 @@ tcp_send(STREAM s)
|
||||
}
|
||||
}
|
||||
}
|
||||
total += sent;
|
||||
|
||||
/* Everything might not have been sent */
|
||||
s_seek(s, before + sent);
|
||||
}
|
||||
#ifdef WITH_SCARD
|
||||
scard_unlock(SCARD_LOCK_TCP);
|
||||
@ -190,7 +179,8 @@ tcp_send(STREAM s)
|
||||
STREAM
|
||||
tcp_recv(STREAM s, uint32 length)
|
||||
{
|
||||
uint32 new_length, end_offset, p_offset;
|
||||
size_t before;
|
||||
unsigned char *data;
|
||||
int rcvd = 0;
|
||||
|
||||
if (g_network_error == True)
|
||||
@ -199,27 +189,14 @@ tcp_recv(STREAM s, uint32 length)
|
||||
if (s == NULL)
|
||||
{
|
||||
/* read into "new" stream */
|
||||
if (length > g_in.size)
|
||||
{
|
||||
g_in.data = (uint8 *) xrealloc(g_in.data, length);
|
||||
g_in.size = length;
|
||||
}
|
||||
g_in.end = g_in.p = g_in.data;
|
||||
s_realloc(&g_in, length);
|
||||
s_reset(&g_in);
|
||||
s = &g_in;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* append to existing stream */
|
||||
new_length = (s->end - s->data) + length;
|
||||
if (new_length > s->size)
|
||||
{
|
||||
p_offset = s->p - s->data;
|
||||
end_offset = s->end - s->data;
|
||||
s->data = (uint8 *) xrealloc(s->data, new_length);
|
||||
s->size = new_length;
|
||||
s->p = s->data + p_offset;
|
||||
s->end = s->data + end_offset;
|
||||
}
|
||||
s_realloc(s, s_length(s) + length);
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
@ -235,8 +212,15 @@ tcp_recv(STREAM s, uint32 length)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
before = s_tell(s);
|
||||
s_seek(s, s_length(s));
|
||||
|
||||
out_uint8p(s, data, length);
|
||||
|
||||
s_seek(s, before);
|
||||
|
||||
if (g_ssl_initialized) {
|
||||
rcvd = gnutls_record_recv(g_tls_session, s->end, length);
|
||||
rcvd = gnutls_record_recv(g_tls_session, data, length);
|
||||
|
||||
if (rcvd < 0) {
|
||||
if (gnutls_error_is_fatal(rcvd)) {
|
||||
@ -251,7 +235,7 @@ tcp_recv(STREAM s, uint32 length)
|
||||
}
|
||||
else
|
||||
{
|
||||
rcvd = recv(g_sock, s->end, length, 0);
|
||||
rcvd = recv(g_sock, data, length, 0);
|
||||
if (rcvd < 0)
|
||||
{
|
||||
if (rcvd == -1 && TCP_BLOCKS)
|
||||
@ -273,6 +257,7 @@ tcp_recv(STREAM s, uint32 length)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Should probably have a macro for this
|
||||
s->end += rcvd;
|
||||
length -= rcvd;
|
||||
}
|
||||
@ -349,9 +334,6 @@ tcp_tls_connect(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
int type;
|
||||
int status;
|
||||
gnutls_datum_t out;
|
||||
gnutls_certificate_credentials_t xcred;
|
||||
|
||||
/* Initialize TLS session */
|
||||
@ -422,8 +404,8 @@ fail:
|
||||
}
|
||||
|
||||
/* Get public key from server of TLS 1.x connection */
|
||||
RD_BOOL
|
||||
tcp_tls_get_server_pubkey(STREAM s)
|
||||
STREAM
|
||||
tcp_tls_get_server_pubkey()
|
||||
{
|
||||
int ret;
|
||||
unsigned int list_size;
|
||||
@ -436,8 +418,7 @@ tcp_tls_get_server_pubkey(STREAM s)
|
||||
int pk_size;
|
||||
uint8_t pk_data[1024];
|
||||
|
||||
s->data = s->p = NULL;
|
||||
s->size = 0;
|
||||
STREAM s = NULL;
|
||||
|
||||
cert_list = gnutls_certificate_get_peers(g_tls_session, &list_size);
|
||||
|
||||
@ -489,11 +470,10 @@ tcp_tls_get_server_pubkey(STREAM s)
|
||||
goto out;
|
||||
}
|
||||
|
||||
s->size = pk_size;
|
||||
s->data = s->p = xmalloc(s->size);
|
||||
memcpy((void *)s->data, (void *)pk_data, pk_size);
|
||||
s->p = s->data;
|
||||
s->end = s->p + s->size;
|
||||
s = s_alloc(pk_size);
|
||||
out_uint8a(s, pk_data, pk_size);
|
||||
s_mark_end(s);
|
||||
s_seek(s, 0);
|
||||
|
||||
out:
|
||||
if ((e.size != 0) && (e.data)) {
|
||||
@ -504,7 +484,7 @@ out:
|
||||
free(m.data);
|
||||
}
|
||||
|
||||
return (s->size != 0);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Helper function to determine if rdesktop should resolve hostnames again or not */
|
||||
@ -530,7 +510,6 @@ tcp_connect(char *server)
|
||||
{
|
||||
socklen_t option_len;
|
||||
uint32 option_value;
|
||||
int i;
|
||||
char buf[NI_MAXHOST];
|
||||
|
||||
#ifdef IPv6
|
||||
@ -681,12 +660,6 @@ tcp_connect(char *server)
|
||||
g_in.size = 4096;
|
||||
g_in.data = (uint8 *) xmalloc(g_in.size);
|
||||
|
||||
for (i = 0; i < STREAM_COUNT; i++)
|
||||
{
|
||||
g_out[i].size = 4096;
|
||||
g_out[i].data = (uint8 *) xmalloc(g_out[i].size);
|
||||
}
|
||||
|
||||
/* After successful connect: update the last server name */
|
||||
if (g_last_server_name)
|
||||
xfree(g_last_server_name);
|
||||
@ -698,8 +671,6 @@ tcp_connect(char *server)
|
||||
void
|
||||
tcp_disconnect(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (g_ssl_initialized) {
|
||||
(void)gnutls_bye(g_tls_session, GNUTLS_SHUT_WR);
|
||||
gnutls_deinit(g_tls_session);
|
||||
@ -715,13 +686,6 @@ tcp_disconnect(void)
|
||||
g_in.size = 0;
|
||||
xfree(g_in.data);
|
||||
g_in.data = NULL;
|
||||
|
||||
for (i = 0; i < STREAM_COUNT; i++)
|
||||
{
|
||||
g_out[i].size = 0;
|
||||
xfree(g_out[i].data);
|
||||
g_out[i].data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
@ -755,16 +719,8 @@ tcp_is_connected()
|
||||
void
|
||||
tcp_reset_state(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Clear the incoming stream */
|
||||
s_reset(&g_in);
|
||||
|
||||
/* Clear the outgoing stream(s) */
|
||||
for (i = 0; i < STREAM_COUNT; i++)
|
||||
{
|
||||
s_reset(&g_out[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -46,23 +46,13 @@ xfree(void *mem)
|
||||
free(mem);
|
||||
}
|
||||
|
||||
static struct stream *stream_new(size_t size) {
|
||||
struct stream *s;
|
||||
s = malloc(sizeof(struct stream));
|
||||
memset(s, 0, sizeof(struct stream));
|
||||
s_realloc(s, size);
|
||||
s_reset(s);
|
||||
return(s);
|
||||
}
|
||||
|
||||
|
||||
Ensure(ASN1, can_create_empty_sequence)
|
||||
{
|
||||
struct stream *s, *empty;
|
||||
uint8_t expected_data[] = {0x30, 0x00};
|
||||
|
||||
s = stream_new(100);
|
||||
empty = stream_new(100);
|
||||
s = s_alloc(100);
|
||||
empty = s_alloc(100);
|
||||
|
||||
ber_out_sequence(s, empty);
|
||||
s_mark_end(s);
|
||||
@ -76,7 +66,7 @@ Ensure(ASN1, can_create_empty_sequence_using_null)
|
||||
struct stream *s;
|
||||
uint8_t expected_data[] = {0x30, 0x00};
|
||||
|
||||
s = stream_new(100);
|
||||
s = s_alloc(100);
|
||||
|
||||
ber_out_sequence(s, NULL);
|
||||
s_mark_end(s);
|
||||
@ -90,8 +80,8 @@ Ensure(ASN1, can_create_sequence_of_two_integers)
|
||||
struct stream *s, *content;
|
||||
uint8_t expected_data[] = {0x30, 0x08, 0x02, 0x02, 0x00, 0xbe, 0x02, 0x02, 0x00, 0xef};
|
||||
|
||||
s = stream_new(100);
|
||||
content = stream_new(100);
|
||||
s = s_alloc(100);
|
||||
content = s_alloc(100);
|
||||
|
||||
ber_out_integer(content, 0xbe);
|
||||
ber_out_integer(content, 0xef);
|
||||
@ -109,8 +99,8 @@ Ensure(ASN1, can_create_sequence_of_one_integer)
|
||||
struct stream *s, *content;
|
||||
uint8_t expected_data[] = {0x30, 0x04, 0x02, 0x02, 0x00, 0xbe};
|
||||
|
||||
s = stream_new(100);
|
||||
content = stream_new(100);
|
||||
s = s_alloc(100);
|
||||
content = s_alloc(100);
|
||||
|
||||
ber_out_integer(content, 0xbe);
|
||||
s_mark_end(content);
|
||||
|
@ -52,15 +52,6 @@ xfree(void *mem)
|
||||
free(mem);
|
||||
}
|
||||
|
||||
static struct stream *stream_new(size_t size) {
|
||||
struct stream *s;
|
||||
s = malloc(sizeof(struct stream));
|
||||
memset(s, 0, sizeof(struct stream));
|
||||
s_realloc(s, size);
|
||||
s_reset(s);
|
||||
return(s);
|
||||
}
|
||||
|
||||
|
||||
/* Test function */
|
||||
Ensure(MCS, should_produce_valid_packet_for_McsSendCJrq)
|
||||
@ -69,7 +60,7 @@ Ensure(MCS, should_produce_valid_packet_for_McsSendCJrq)
|
||||
uint8_t content[] = {0x38, 0x00, 0x2A, 0x00, 0x0D};
|
||||
|
||||
struct stream *s;
|
||||
s = stream_new(5);
|
||||
s = s_alloc(5);
|
||||
|
||||
chan_id = 13;
|
||||
g_mcs_userid = 42;
|
||||
@ -89,7 +80,7 @@ Ensure(MCS, should_produce_valid_packet_for_McsSendDPU)
|
||||
struct stream *s;
|
||||
uint8_t content[] = {0x30, 0x06, 0x02, 0x02, 0x00, reason, 0x30, 0x00};
|
||||
|
||||
s = stream_new(8);
|
||||
s = s_alloc(8);
|
||||
|
||||
expect(logger);
|
||||
expect(iso_init, will_return(s));
|
||||
|
@ -412,17 +412,6 @@ Ensure(Resize, UsingRDPEDISPHonoursServerSessionWidthConstraintMustBeEven)
|
||||
free(s.data);
|
||||
}
|
||||
|
||||
/* FIXME: promote to actual function in stream.c */
|
||||
STREAM s_alloc(size_t capacity)
|
||||
{
|
||||
STREAM s;
|
||||
s = xmalloc(sizeof(struct stream));
|
||||
memset(s, 0, sizeof(struct stream));
|
||||
s_realloc(s, capacity);
|
||||
s_reset(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void get_width_and_height_from_mcs_connect_initial(int *width, int *height)
|
||||
{
|
||||
STREAM s;
|
||||
@ -433,7 +422,7 @@ void get_width_and_height_from_mcs_connect_initial(int *width, int *height)
|
||||
|
||||
/* Rewind and extract the requested session size */
|
||||
s_reset(s);
|
||||
in_skip(s, 31);
|
||||
in_uint8s(s, 31);
|
||||
in_uint16_le(s, *width); /* desktopWidth */
|
||||
in_uint16_le(s, *height); /* desktopHeight */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user