This commit is contained in:
Pierre Ossman 2019-05-08 13:55:46 +02:00
commit a88cd226bb
37 changed files with 1012 additions and 821 deletions

14
asn.c
View File

@ -41,10 +41,16 @@ ber_parse_header(STREAM s, int tagval, uint32 *length)
if (tagval > 0xff) if (tagval > 0xff)
{ {
if (!s_check_rem(s, 2)) {
return False;
}
in_uint16_be(s, tag); in_uint16_be(s, tag);
} }
else else
{ {
if (!s_check_rem(s, 1)) {
return False;
}
in_uint8(s, tag); in_uint8(s, tag);
} }
@ -54,11 +60,17 @@ ber_parse_header(STREAM s, int tagval, uint32 *length)
return False; return False;
} }
if (!s_check_rem(s, 1)) {
return False;
}
in_uint8(s, len); in_uint8(s, len);
if (len & 0x80) if (len & 0x80)
{ {
len &= ~0x80; len &= ~0x80;
if (!s_check_rem(s, len)) {
return False;
}
*length = 0; *length = 0;
while (len--) while (len--)
next_be(s, *length); next_be(s, *length);
@ -66,7 +78,7 @@ ber_parse_header(STREAM s, int tagval, uint32 *length)
else else
*length = len; *length = len;
return s_check(s); return True;
} }
void void

View File

@ -80,65 +80,101 @@ channel_init(VCHANNEL * channel, uint32 length)
return s; return s;
} }
void static void
channel_send(STREAM s, VCHANNEL * channel) channel_send_chunk(STREAM s, VCHANNEL * channel, uint32 length)
{ {
uint32 length, flags; uint32 flags;
uint32 thislength, remaining; uint32 thislength;
uint8 *data; RD_BOOL inplace;
STREAM chunk;
#ifdef WITH_SCARD /* Note: In the original clipboard implementation, this number was
scard_lock(SCARD_LOCK_CHANNEL); 1592, not 1600. However, I don't remember the reason and 1600 seems
#endif to work so.. This applies only to *this* length, not the length of
continuation or ending packets. */
/* 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. */
/* Actually, CHANNEL_CHUNK_LENGTH (default value is 1600 bytes) is described /* 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 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) */ in the optional field VCChunkSize of VC Caps) */
remaining = length - thislength; thislength = MIN(s_remaining(s), vc_chunk_size);
flags = (remaining == 0) ? CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST : CHANNEL_FLAG_FIRST;
if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
out_uint32_le(s, length); flags = 0;
out_uint32_le(s, flags); if (length == s_remaining(s))
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)
{ {
thislength = MIN(remaining, vc_chunk_size); flags |= CHANNEL_FLAG_FIRST;
remaining -= thislength; }
flags = (remaining == 0) ? CHANNEL_FLAG_LAST : 0; if (s_remaining(s) == thislength)
if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL) {
flags |= CHANNEL_FLAG_SHOW_PROTOCOL; 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", logger(Protocol, Debug, "channel_send_chunk(), sending %d bytes with flags 0x%x",
thislength, flags); thislength, flags);
s = sec_init(g_encryption ? SEC_ENCRYPT : 0, thislength + 8); /* first fragment sent in-place */
out_uint32_le(s, length); inplace = False;
out_uint32_le(s, flags); if ((flags & (CHANNEL_FLAG_FIRST|CHANNEL_FLAG_LAST)) ==
out_uint8p(s, data, thislength); (CHANNEL_FLAG_FIRST|CHANNEL_FLAG_LAST))
s_mark_end(s); {
sec_send_to_channel(s, g_encryption ? SEC_ENCRYPT : 0, channel->mcs_id); 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 #ifdef WITH_SCARD
@ -150,7 +186,6 @@ void
channel_process(STREAM s, uint16 mcs_channel) channel_process(STREAM s, uint16 mcs_channel)
{ {
uint32 length, flags; uint32 length, flags;
uint32 thislength;
VCHANNEL *channel = NULL; VCHANNEL *channel = NULL;
unsigned int i; unsigned int i;
STREAM in; STREAM in;
@ -178,22 +213,16 @@ channel_process(STREAM s, uint16 mcs_channel)
in = &channel->in; in = &channel->in;
if (flags & CHANNEL_FLAG_FIRST) if (flags & CHANNEL_FLAG_FIRST)
{ {
if (length > in->size) s_realloc(in, length);
{ s_reset(in);
in->data = (uint8 *) xrealloc(in->data, length);
in->size = length;
}
in->p = in->data;
} }
thislength = MIN(s->end - s->p, in->data + in->size - in->p); out_uint8stream(in, s, s_remaining(s));
memcpy(in->p, s->p, thislength);
in->p += thislength;
if (flags & CHANNEL_FLAG_LAST) if (flags & CHANNEL_FLAG_LAST)
{ {
in->end = in->p; s_mark_end(in);
in->p = in->data; s_seek(in, 0);
channel->process(in); channel->process(in);
} }
} }

View File

@ -48,10 +48,11 @@ cliprdr_send_packet(uint16 type, uint16 status, uint8 * data, uint32 length)
out_uint16_le(s, type); out_uint16_le(s, type);
out_uint16_le(s, status); out_uint16_le(s, status);
out_uint32_le(s, length); out_uint32_le(s, length);
out_uint8p(s, data, length); out_uint8a(s, data, length);
out_uint32(s, 0); /* pad? */ out_uint32(s, 0); /* pad? */
s_mark_end(s); s_mark_end(s);
channel_send(s, cliprdr_channel); channel_send(s, cliprdr_channel);
s_free(s);
} }
/* Helper which announces our readiness to supply clipboard data /* Helper which announces our readiness to supply clipboard data
@ -118,21 +119,14 @@ cliprdr_process(STREAM s)
uint16 type, status; uint16 type, status;
uint32 length, format; uint32 length, format;
uint8 *data; uint8 *data;
struct stream packet = *s;
in_uint16_le(s, type); in_uint16_le(s, type);
in_uint16_le(s, status); in_uint16_le(s, status);
in_uint32_le(s, length); in_uint32_le(s, length);
data = s->p;
logger(Clipboard, Debug, "cliprdr_process(), type=%d, status=%d, length=%d", type, status, logger(Clipboard, Debug, "cliprdr_process(), type=%d, status=%d, length=%d", type, status,
length); length);
if (!s_check_rem(s, length))
{
rdp_protocol_error("cliprdr_process(), consume of packet from stream would overrun", &packet);
}
if (status == CLIPRDR_ERROR) if (status == CLIPRDR_ERROR)
{ {
switch (type) switch (type)
@ -160,6 +154,7 @@ cliprdr_process(STREAM s)
ui_clip_sync(); ui_clip_sync();
break; break;
case CLIPRDR_FORMAT_ANNOUNCE: case CLIPRDR_FORMAT_ANNOUNCE:
in_uint8p(s, data, length);
ui_clip_format_announce(data, length); ui_clip_format_announce(data, length);
cliprdr_send_packet(CLIPRDR_FORMAT_ACK, CLIPRDR_RESPONSE, NULL, 0); cliprdr_send_packet(CLIPRDR_FORMAT_ACK, CLIPRDR_RESPONSE, NULL, 0);
return; return;
@ -170,6 +165,7 @@ cliprdr_process(STREAM s)
ui_clip_request_data(format); ui_clip_request_data(format);
break; break;
case CLIPRDR_DATA_RESPONSE: case CLIPRDR_DATA_RESPONSE:
in_uint8p(s, data, length);
ui_clip_handle_data(data, length); ui_clip_handle_data(data, length);
break; break;
case 7: /* TODO: W2K3 SP1 sends this on connect with a value of 1 */ case 7: /* TODO: W2K3 SP1 sends this on connect with a value of 1 */

268
cssp.c
View File

@ -36,14 +36,9 @@ ber_wrap_hdr_data(int tagval, STREAM in)
STREAM out; STREAM out;
int size = s_length(in) + 16; int size = s_length(in) + 16;
out = xmalloc(sizeof(struct stream)); out = s_alloc(size);
memset(out, 0, sizeof(struct stream));
out->data = xmalloc(size);
out->size = size;
out->p = out->data;
ber_out_header(out, tagval, s_length(in)); ber_out_header(out, tagval, s_length(in));
out_uint8p(out, in->data, s_length(in)); out_stream(out, in);
s_mark_end(out); s_mark_end(out);
return out; return out;
@ -144,16 +139,19 @@ cssp_gss_get_service_name(char *server, gss_name_t * name)
} }
static RD_BOOL static STREAM
cssp_gss_wrap(gss_ctx_id_t ctx, STREAM in, STREAM out) cssp_gss_wrap(gss_ctx_id_t ctx, STREAM in)
{ {
int conf_state; int conf_state;
OM_uint32 major_status; OM_uint32 major_status;
OM_uint32 minor_status; OM_uint32 minor_status;
gss_buffer_desc inbuf, outbuf; gss_buffer_desc inbuf, outbuf;
STREAM out;
inbuf.value = in->data; s_seek(in, 0);
inbuf.length = s_length(in); 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, major_status = gss_wrap(&minor_status, ctx, True,
GSS_C_QOP_DEFAULT, &inbuf, &conf_state, &outbuf); 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", cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to encrypt and sign message",
major_status, minor_status); major_status, minor_status);
return False; return NULL;
} }
if (!conf_state) if (!conf_state)
{ {
logger(Core, Error, logger(Core, Error,
"cssp_gss_wrap(), GSS Confidentiality failed, no encryption of message performed."); "cssp_gss_wrap(), GSS Confidentiality failed, no encryption of message performed.");
return False; return NULL;
} }
// write enc data to out stream // write enc data to out stream
out->data = out->p = xmalloc(outbuf.length); out = s_alloc(outbuf.length);
out->size = outbuf.length; out_uint8a(out, outbuf.value, outbuf.length);
out_uint8p(out, outbuf.value, outbuf.length);
s_mark_end(out); s_mark_end(out);
s_seek(out, 0);
gss_release_buffer(&minor_status, &outbuf); gss_release_buffer(&minor_status, &outbuf);
return True; return out;
} }
static RD_BOOL static STREAM
cssp_gss_unwrap(gss_ctx_id_t ctx, STREAM in, STREAM out) cssp_gss_unwrap(gss_ctx_id_t ctx, STREAM in)
{ {
OM_uint32 major_status; OM_uint32 major_status;
OM_uint32 minor_status; OM_uint32 minor_status;
gss_qop_t qop_state; gss_qop_t qop_state;
gss_buffer_desc inbuf, outbuf; gss_buffer_desc inbuf, outbuf;
int conf_state; int conf_state;
STREAM out;
inbuf.value = in->data; s_seek(in, 0);
inbuf.length = s_length(in); 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); 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", cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to decrypt message",
major_status, minor_status); major_status, minor_status);
return False; return NULL;
} }
out->data = out->p = xmalloc(outbuf.length); out = s_alloc(outbuf.length);
out->size = outbuf.length; out_uint8a(out, outbuf.value, outbuf.length);
out_uint8p(out, outbuf.value, outbuf.length);
s_mark_end(out); s_mark_end(out);
s_seek(out, 0);
gss_release_buffer(&minor_status, &outbuf); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 4, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 4, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); s_free(h1);
@ -397,7 +398,7 @@ cssp_encode_tssmartcardcreds(char *username, char *password, char *domain)
g_sc_container_name, g_sc_csp_name); g_sc_container_name, g_sc_csp_name);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, h3);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h3); s_free(h3);
s_free(h2); 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); h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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); 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); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h5); s_free(h5);
s_free(h4); 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); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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(h2);
s_free(h1); 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); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
s_realloc(&message, s_length(&message) + s_length(h1)); 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_mark_end(&message);
s_free(h2); s_free(h2);
s_free(h1); 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 // Todo: can h1 be send directly instead of tcp_init() approach
h1 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message); h1 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message);
s = tcp_init(s_length(h1)); s = tcp_init(s_length(h1));
out_uint8p(s, h1->data, s_length(h1)); out_stream(s, h1);
s_mark_end(s); s_mark_end(s);
s_free(h1); s_free(h1);
tcp_send(s); tcp_send(s);
s_free(s);
// cleanup // cleanup
xfree(message.data); xfree(message.data);
@ -589,10 +591,10 @@ cssp_send_tsrequest(STREAM token, STREAM auth, STREAM pubkey)
} }
RD_BOOL STREAM
cssp_read_tsrequest(STREAM token, STREAM pubkey) cssp_read_tsrequest(RD_BOOL pubkey)
{ {
STREAM s; STREAM s, out;
int length; int length;
int tagval; int tagval;
struct stream packet; struct stream packet;
@ -600,96 +602,83 @@ cssp_read_tsrequest(STREAM token, STREAM pubkey)
s = tcp_recv(NULL, 4); s = tcp_recv(NULL, 4);
if (s == NULL) if (s == NULL)
return False; return NULL;
// verify ASN.1 header // get and verify the header
if (s->p[0] != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED)) if (!ber_in_header(s, &tagval, &length) ||
{ tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
logger(Protocol, Error, return NULL;
"cssp_read_tsrequest(), expected BER_TAG_SEQUENCE|BER_TAG_CONSTRUCTED, got %x",
s->p[0]);
return False;
}
// peek at first 4 bytes to get full message length // We've already read 4 bytes, but the header might have been
if (s->p[1] < 0x80) // less than that, so we need to adjust the length
length = s->p[1] - 2; length -= s_remaining(s);
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;
// receive the remainings of message // receive the remainings of message
s = tcp_recv(s, length); s = tcp_recv(s, length);
if (s == NULL)
return NULL;
packet = *s; 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] // version [0]
if (!ber_in_header(s, &tagval, &length) || if (!ber_in_header(s, &tagval, &length) ||
tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0)) tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0))
return False; return NULL;
if (!s_check_rem(s, length)) 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); &packet);
} }
in_uint8s(s, length); in_uint8s(s, length);
// negoToken [1] // negoToken [1]
if (token) if (!pubkey)
{ {
if (!ber_in_header(s, &tagval, &length) if (!ber_in_header(s, &tagval, &length)
|| tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1)) || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1))
return False; return NULL;
if (!ber_in_header(s, &tagval, &length) if (!ber_in_header(s, &tagval, &length)
|| tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED)) || tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
return False; return NULL;
if (!ber_in_header(s, &tagval, &length) if (!ber_in_header(s, &tagval, &length)
|| tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED)) || tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
return False; return NULL;
if (!ber_in_header(s, &tagval, &length) if (!ber_in_header(s, &tagval, &length)
|| tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0)) || 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) if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING)
return False; return NULL;
if (!s_check_rem(s, length)) 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); &packet);
} }
s_realloc(token, length); out = s_alloc(length);
s_reset(token); out_uint8stream(out, s, length);
out_uint8p(token, s->p, length); s_mark_end(out);
s_mark_end(token); s_seek(out, 0);
} }
// pubKey [3] // pubKey [3]
if (pubkey) else
{ {
if (!ber_in_header(s, &tagval, &length) if (!ber_in_header(s, &tagval, &length)
|| tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3)) || 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) if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING)
return False; return NULL;
pubkey->data = pubkey->p = s->p; out = s_alloc(length);
pubkey->end = pubkey->data + length; out_uint8stream(out, s, length);
pubkey->size = length; s_mark_end(out);
s_seek(out, 0);
} }
return True; return out;
} }
RD_BOOL 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; gss_OID desired_mech = &_gss_spnego_krb5_mechanism_oid_desc;
STREAM ts_creds; STREAM ts_creds;
struct stream token = { 0 }; STREAM token;
struct stream pubkey = { 0 }; STREAM pubkey, pubkey_cmp;
struct stream pubkey_cmp = { 0 }; unsigned char *pubkey_data;
unsigned char *pubkey_cmp_data;
unsigned char first_byte;
RD_BOOL ret;
STREAM blob;
// Verify that system gss support spnego // Verify that system gss support spnego
if (!cssp_gss_mech_available(desired_mech)) 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; 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 // Enter the spnego loop
OM_uint32 actual_services; OM_uint32 actual_services;
gss_OID actual_mech; gss_OID actual_mech;
struct stream blob = { 0 };
gss_ctx = GSS_C_NO_CONTEXT; gss_ctx = GSS_C_NO_CONTEXT;
cred = GSS_C_NO_CREDENTIAL; cred = GSS_C_NO_CREDENTIAL;
token = NULL;
input_tok.length = 0; input_tok.length = 0;
output_tok.length = 0; output_tok.length = 0;
minor_status = 0; minor_status = 0;
@ -762,6 +759,11 @@ cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
&actual_mech, &actual_mech,
&output_tok, &actual_services, &actual_time); &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 (GSS_ERROR(major_status))
{ {
if (i == 0) if (i == 0)
@ -786,39 +788,44 @@ cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
// Send token to server // Send token to server
if (output_tok.length != 0) if (output_tok.length != 0)
{ {
if (output_tok.length > token.size) token = s_alloc(output_tok.length);
s_realloc(&token, output_tok.length); out_uint8a(token, output_tok.value, output_tok.length);
s_reset(&token); s_mark_end(token);
out_uint8p(&token, output_tok.value, output_tok.length); ret = cssp_send_tsrequest(token, NULL, NULL);
s_mark_end(&token);
if (!cssp_send_tsrequest(&token, NULL, NULL))
goto bail_out;
s_free(token);
token = NULL;
(void) gss_release_buffer(&minor_status, &output_tok); (void) gss_release_buffer(&minor_status, &output_tok);
if (!ret)
goto bail_out;
} }
// Read token from server // Read token from server
if (major_status & GSS_S_CONTINUE_NEEDED) if (major_status & GSS_S_CONTINUE_NEEDED)
{ {
(void) gss_release_buffer(&minor_status, &input_tok); token = cssp_read_tsrequest(False);
if (token == NULL)
if (!cssp_read_tsrequest(&token, NULL))
goto bail_out; 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 else
{ {
// Send encrypted pubkey for verification to server // Send encrypted pubkey for verification to server
context_established = 1; context_established = 1;
if (!cssp_gss_wrap(gss_ctx, &pubkey, &blob)) blob = cssp_gss_wrap(gss_ctx, pubkey);
if (blob == NULL)
goto bail_out; 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; goto bail_out;
context_established = 1; context_established = 1;
@ -829,37 +836,62 @@ cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
} }
while (!context_established); while (!context_established);
s_free(token);
// read tsrequest response and decrypt for public key validation // 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; 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; 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 // 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, logger(Core, Error,
"cssp_connect(), public key mismatch, cannot guarantee integrity of server connection"); "cssp_connect(), public key mismatch, cannot guarantee integrity of server connection");
goto bail_out; goto bail_out;
} }
s_free(pubkey);
s_free(pubkey_cmp);
// Send TSCredentials // Send TSCredentials
ts_creds = cssp_encode_tscredentials(user, password, domain); ts_creds = cssp_encode_tscredentials(user, password, domain);
if (!cssp_gss_wrap(gss_ctx, ts_creds, &blob)) blob = cssp_gss_wrap(gss_ctx, ts_creds);
goto bail_out;
s_free(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; goto bail_out;
return True; return True;
bail_out: bail_out:
xfree(token.data); s_free(token);
s_free(pubkey);
s_free(pubkey_cmp);
return False; return False;
} }

57
disk.c
View File

@ -1131,10 +1131,7 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
struct STATFS_T stat_fs; struct STATFS_T stat_fs;
struct fileinfo *pfinfo; struct fileinfo *pfinfo;
FsInfoType *fsinfo; FsInfoType *fsinfo;
struct stream stmp; STREAM stmp;
memset(&stmp, 0, sizeof(stmp));
s_realloc(&stmp, PATH_MAX * 4);
logger(Disk, Debug, "disk_query_volume_information(handle=0x%x, info_class=0x%x)", handle, logger(Disk, Debug, "disk_query_volume_information(handle=0x%x, info_class=0x%x)", handle,
info_class); info_class);
@ -1153,16 +1150,17 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
switch (info_class) switch (info_class)
{ {
case FileFsVolumeInformation: case FileFsVolumeInformation:
s_reset(&stmp); stmp = s_alloc(PATH_MAX * 4);
out_utf16s(&stmp, fsinfo->label); out_utf16s(stmp, fsinfo->label);
s_mark_end(&stmp); s_mark_end(stmp);
out_uint32_le(out, 0); /* volume creation time low */ out_uint32_le(out, 0); /* volume creation time low */
out_uint32_le(out, 0); /* volume creation time high */ out_uint32_le(out, 0); /* volume creation time high */
out_uint32_le(out, fsinfo->serial); /* serial */ 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_uint8(out, 0); /* support objects? */
out_stream(out, &stmp); /* fsinfo->label string */ out_stream(out, stmp); /* fsinfo->label string */
s_free(stmp);
break; break;
case FileFsSizeInformation: case FileFsSizeInformation:
@ -1183,15 +1181,16 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
break; break;
case FileFsAttributeInformation: case FileFsAttributeInformation:
s_reset(&stmp); stmp = s_alloc(PATH_MAX * 4);
out_utf16s_no_eos(&stmp, fsinfo->type); out_utf16s_no_eos(stmp, fsinfo->type);
s_mark_end(&stmp); s_mark_end(stmp);
out_uint32_le(out, FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED); /* fs attributes */ 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, F_NAMELEN(stat_fs)); /* max length of filename */
out_uint32_le(out, s_length(&stmp)); /* length of fsinfo->type string */ out_uint32_le(out, s_length(stmp)); /* length of fsinfo->type string */
out_stream(out, &stmp); /* fsinfo->typ string */ out_stream(out, stmp); /* fsinfo->typ string */
s_free(stmp);
break; break;
case FileFsLabelInformation: case FileFsLabelInformation:
@ -1218,7 +1217,7 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
struct dirent *pdirent; struct dirent *pdirent;
struct stat filestat; struct stat filestat;
struct fileinfo *pfinfo; struct fileinfo *pfinfo;
struct stream stmp; STREAM stmp;
logger(Disk, Debug, "disk_query_directory(handle=0x%x, info_class=0x%x, pattern=%s, ...)", logger(Disk, Debug, "disk_query_directory(handle=0x%x, info_class=0x%x, pattern=%s, ...)",
handle, info_class, pattern); handle, info_class, pattern);
@ -1228,9 +1227,6 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
dirname = pfinfo->path; dirname = pfinfo->path;
file_attributes = 0; file_attributes = 0;
memset(&stmp, 0, sizeof(stmp));
s_realloc(&stmp, PATH_MAX * 4);
switch (info_class) switch (info_class)
{ {
case FileBothDirectoryInformation: 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 // Write entry name as utf16 into stmp
s_reset(&stmp); stmp = s_alloc(PATH_MAX * 4);
out_utf16s_no_eos(&stmp, pdirent->d_name); out_utf16s_no_eos(stmp, pdirent->d_name);
s_mark_end(&stmp); s_mark_end(stmp);
switch (info_class) 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_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, 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_uint32_le(out, 0); /* EaSize */
out_uint8(out, 0); /* ShortNameLength */ out_uint8(out, 0); /* ShortNameLength */
out_uint8s(out, 24); /* ShortName (8.3 name) */ 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; 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_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, 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_stream(out, &stmp); /* dir entry name */ out_stream(out, stmp); /* dir entry name */
break; 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_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, 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_uint32_le(out, 0); /* EaSize */
out_stream(out, &stmp); /* dir entry name */ out_stream(out, stmp); /* dir entry name */
break; break;
case FileNamesInformation: case FileNamesInformation:
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_stream(out, &stmp); /* dir entry name */ out_stream(out, stmp); /* dir entry name */
break; break;
@ -1401,9 +1397,12 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
logger(Disk, Warning, logger(Disk, Warning,
"disk_query_directory(), unhandled directory info class 0x%x", "disk_query_directory(), unhandled directory info class 0x%x",
info_class); info_class);
s_free(stmp);
return RD_STATUS_INVALID_PARAMETER; return RD_STATUS_INVALID_PARAMETER;
} }
s_free(stmp);
return RD_STATUS_SUCCESS; return RD_STATUS_SUCCESS;
} }

3
dvc.c
View File

@ -268,6 +268,7 @@ dvc_send(const char *name, STREAM s)
s_mark_end(ls); s_mark_end(ls);
channel_send(ls, dvc_channel); channel_send(ls, dvc_channel);
s_free(ls);
} }
@ -292,6 +293,7 @@ dvc_send_capabilities_response()
s_mark_end(s); s_mark_end(s);
channel_send(s, dvc_channel); channel_send(s, dvc_channel);
s_free(s);
} }
static void static void
@ -320,6 +322,7 @@ dvc_send_create_response(RD_BOOL success, dvc_hdr_t hdr, uint32 channelid)
s_mark_end(s); s_mark_end(s);
channel_send(s, dvc_channel); channel_send(s, dvc_channel);
s_free(s);
} }
static void static void

8
iso.c
View File

@ -55,6 +55,7 @@ iso_send_msg(uint8 code)
s_mark_end(s); s_mark_end(s);
tcp_send(s); tcp_send(s);
s_free(s);
} }
static void static void
@ -78,8 +79,8 @@ iso_send_connection_request(char *username, uint32 neg_proto)
out_uint16(s, 0); /* src_ref */ out_uint16(s, 0); /* src_ref */
out_uint8(s, 0); /* class */ out_uint8(s, 0); /* class */
out_uint8p(s, "Cookie: mstshash=", strlen("Cookie: mstshash=")); out_uint8a(s, "Cookie: mstshash=", strlen("Cookie: mstshash="));
out_uint8p(s, username, strlen(username)); out_uint8a(s, username, strlen(username));
out_uint8(s, 0x0d); /* cookie termination string: CR+LF */ out_uint8(s, 0x0d); /* cookie termination string: CR+LF */
out_uint8(s, 0x0a); out_uint8(s, 0x0a);
@ -95,6 +96,7 @@ iso_send_connection_request(char *username, uint32 neg_proto)
s_mark_end(s); s_mark_end(s);
tcp_send(s); tcp_send(s);
s_free(s);
} }
/* Receive a message on the ISO layer, return code */ /* Receive a message on the ISO layer, return code */
@ -177,7 +179,7 @@ iso_send(STREAM s)
uint16 length; uint16 length;
s_pop_layer(s, iso_hdr); 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, T123_HEADER_VERSION); /* version */
out_uint8(s, 0); /* reserved */ out_uint8(s, 0); /* reserved */

View File

@ -79,24 +79,25 @@ licence_info(uint8 * client_random, uint8 * rsa_data,
out_uint16(s, 0); out_uint16(s, 0);
out_uint16_le(s, 0x0201); 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, 2);
out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); 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_uint8s(s, SEC_PADDING_SIZE);
out_uint16_le(s, 1); out_uint16_le(s, 1);
out_uint16_le(s, licence_size); 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, 1);
out_uint16_le(s, LICENCE_HWID_SIZE); 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); s_mark_end(s);
sec_send(s, sec_flags); sec_send(s, sec_flags);
s_free(s);
} }
/* Send a new licence request packet */ /* 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(s, 0);
out_uint16_le(s, 0xff01); 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, 2);
out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); 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_uint8s(s, SEC_PADDING_SIZE);
/* Username LICENSE_BINARY_BLOB */ /* Username LICENSE_BINARY_BLOB */
out_uint16_le(s, BB_CLIENT_USER_NAME_BLOB); out_uint16_le(s, BB_CLIENT_USER_NAME_BLOB);
out_uint16_le(s, userlen); out_uint16_le(s, userlen);
out_uint8p(s, user, userlen); out_uint8a(s, user, userlen);
/* Machinename LICENSE_BINARY_BLOB */ /* Machinename LICENSE_BINARY_BLOB */
out_uint16_le(s, BB_CLIENT_MACHINE_NAME_BLOB); out_uint16_le(s, BB_CLIENT_MACHINE_NAME_BLOB);
out_uint16_le(s, hostlen); out_uint16_le(s, hostlen);
out_uint8p(s, host, hostlen); out_uint8a(s, host, hostlen);
s_mark_end(s); s_mark_end(s);
sec_send(s, sec_flags); sec_send(s, sec_flags);
s_free(s);
} }
/* Process a licence request packet */ /* 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, 1);
out_uint16_le(s, LICENCE_TOKEN_SIZE); 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, 1);
out_uint16_le(s, LICENCE_HWID_SIZE); 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); s_mark_end(s);
sec_send(s, sec_flags); sec_send(s, sec_flags);
s_free(s);
} }
/* Parse an platform challenge request packet */ /* Parse an platform challenge request packet */
@ -274,6 +277,7 @@ licence_process_platform_challenge(STREAM s)
static void static void
licence_process_new_license(STREAM s) licence_process_new_license(STREAM s)
{ {
unsigned char *data;
RDSSL_RC4 crypt_key; RDSSL_RC4 crypt_key;
uint32 length; uint32 length;
int i; int i;
@ -283,8 +287,12 @@ licence_process_new_license(STREAM s)
if (!s_check_rem(s, length)) if (!s_check_rem(s, length))
return; return;
inout_uint8p(s, data, length);
rdssl_rc4_set_key(&crypt_key, g_licence_key, 16); 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 */ /* Parse NEW_LICENSE_INFO block */
in_uint8s(s, 4); // skip dwVersion in_uint8s(s, 4); // skip dwVersion
@ -301,7 +309,8 @@ licence_process_new_license(STREAM s)
} }
g_licence_issued = True; g_licence_issued = True;
save_licence(s->p, length); in_uint8p(s, data, length);
save_licence(data, length);
} }
/* process a licence error alert packet */ /* process a licence error alert packet */

14
lspci.c
View File

@ -135,17 +135,12 @@ lspci_process(STREAM s)
unsigned int pkglen; unsigned int pkglen;
static char *rest = NULL; static char *rest = NULL;
char *buf; char *buf;
struct stream packet = *s;
if (!s_check(s)) pkglen = s_remaining(s);
{
rdp_protocol_error("lspci_process(), stream is in unstable state", &packet);
}
pkglen = s->end - s->p;
/* str_handle_lines requires null terminated strings */ /* str_handle_lines requires null terminated strings */
buf = xmalloc(pkglen + 1); 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); str_handle_lines(buf, &rest, lspci_process_line, NULL);
xfree(buf); xfree(buf);
} }
@ -169,6 +164,7 @@ lspci_send(const char *output)
len = strlen(output); len = strlen(output);
s = channel_init(lspci_channel, len); 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); channel_send(s, lspci_channel);
s_free(s);
} }

31
mcs.c
View File

@ -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) */ /* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */
static RD_BOOL static void
mcs_parse_domain_params(STREAM s) mcs_parse_domain_params(STREAM s)
{ {
uint32 length; uint32 length;
@ -52,19 +52,17 @@ mcs_parse_domain_params(STREAM s)
if (!s_check_rem(s, length)) 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); in_uint8s(s, length);
return s_check(s);
} }
/* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */ /* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */
static void static void
mcs_send_connect_initial(STREAM mcs_data) 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; int length = 9 + 3 * 34 + 4 + datalen;
STREAM s; STREAM s;
logger(Protocol, Debug, "%s()", __func__); 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 */ mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */
ber_out_header(s, BER_TAG_OCTET_STRING, datalen); 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); s_mark_end(s);
iso_send(s); iso_send(s);
s_free(s);
} }
/* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */ /* 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)) 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); mcs_parse_domain_params(s);
@ -140,9 +139,10 @@ mcs_recv_connect_response(STREAM mcs_data)
length = mcs_data->size; length = mcs_data->size;
} }
in_uint8a(s, mcs_data->data, length); s_reset(mcs_data);
mcs_data->p = mcs_data->data; in_uint8stream(s, mcs_data, length);
mcs_data->end = mcs_data->data + length; s_mark_end(mcs_data);
s_seek(mcs_data, 0);
*/ */
return s_check_end(s); return s_check_end(s);
} }
@ -161,6 +161,7 @@ mcs_send_edrq(void)
s_mark_end(s); s_mark_end(s);
iso_send(s); iso_send(s);
s_free(s);
} }
/* Send an AUrq message (ASN.1 PER) */ /* Send an AUrq message (ASN.1 PER) */
@ -175,6 +176,7 @@ mcs_send_aurq(void)
s_mark_end(s); s_mark_end(s);
iso_send(s); iso_send(s);
s_free(s);
} }
/* Expect a AUcf message (ASN.1 PER) */ /* Expect a AUcf message (ASN.1 PER) */
@ -228,6 +230,7 @@ mcs_send_cjrq(uint16 chanid)
s_mark_end(s); s_mark_end(s);
iso_send(s); iso_send(s);
s_free(s);
} }
/* Expect a CJcf message (ASN.1 PER) */ /* 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); logger(Protocol, Debug, "mcs_send_dpu(), reason=%d", reason);
contents = malloc(sizeof(struct stream)); contents = s_alloc(6);
memset(contents, 0, sizeof(struct stream));
s_realloc(contents, 6);
s_reset(contents);
ber_out_integer(contents, reason); /* Reason */ ber_out_integer(contents, reason); /* Reason */
ber_out_sequence(contents, NULL); /* SEQUENCE OF NonStandradParameters OPTIONAL */ ber_out_sequence(contents, NULL); /* SEQUENCE OF NonStandradParameters OPTIONAL */
s_mark_end(contents); s_mark_end(contents);
@ -290,6 +290,7 @@ mcs_send_dpu(unsigned short reason)
s_mark_end(s); s_mark_end(s);
iso_send(s); iso_send(s);
s_free(s);
} }
/* Initialise an MCS transport data packet */ /* Initialise an MCS transport data packet */
@ -311,7 +312,7 @@ mcs_send_to_channel(STREAM s, uint16 channel)
uint16 length; uint16 length;
s_pop_layer(s, mcs_hdr); s_pop_layer(s, mcs_hdr);
length = s->end - s->p - 8; length = s_remaining(s) - 8;
length |= 0x8000; length |= 0x8000;
out_uint8(s, (MCS_SDRQ << 2)); out_uint8(s, (MCS_SDRQ << 2));

View File

@ -20,7 +20,7 @@
#include "rdesktop.h" #include "rdesktop.h"
#include "orders.h" #include "orders.h"
extern uint8 *g_next_packet; extern size_t g_next_packet;
static RDP_ORDER_STATE g_order_state; static RDP_ORDER_STATE g_order_state;
extern RDP_VERSION g_rdp_version; extern RDP_VERSION g_rdp_version;
@ -101,7 +101,7 @@ rdp_in_colour(STREAM s, uint32 * colour)
} }
/* Parse bounds information */ /* Parse bounds information */
static RD_BOOL static void
rdp_parse_bounds(STREAM s, BOUNDS * bounds) rdp_parse_bounds(STREAM s, BOUNDS * bounds)
{ {
uint8 present; uint8 present;
@ -127,12 +127,10 @@ rdp_parse_bounds(STREAM s, BOUNDS * bounds)
rdp_in_coord(s, &bounds->bottom, False); rdp_in_coord(s, &bounds->bottom, False);
else if (present & 128) else if (present & 128)
rdp_in_coord(s, &bounds->bottom, True); rdp_in_coord(s, &bounds->bottom, True);
return s_check(s);
} }
/* Parse a pen */ /* Parse a pen */
static RD_BOOL static void
rdp_parse_pen(STREAM s, PEN * pen, uint32 present) rdp_parse_pen(STREAM s, PEN * pen, uint32 present)
{ {
if (present & 1) if (present & 1)
@ -143,8 +141,6 @@ rdp_parse_pen(STREAM s, PEN * pen, uint32 present)
if (present & 4) if (present & 4)
rdp_in_colour(s, &pen->colour); rdp_in_colour(s, &pen->colour);
return s_check(s);
} }
static void static void
@ -176,7 +172,7 @@ setup_brush(BRUSH * out_brush, BRUSH * in_brush)
} }
/* Parse a brush */ /* Parse a brush */
static RD_BOOL static void
rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present) rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present)
{ {
if (present & 1) if (present & 1)
@ -193,8 +189,6 @@ rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present)
if (present & 16) if (present & 16)
in_uint8a(s, &brush->pattern[1], 7); in_uint8a(s, &brush->pattern[1], 7);
return s_check(s);
} }
/* Process a destination blt order */ /* Process a destination blt order */
@ -1258,7 +1252,7 @@ process_secondary_order(STREAM s)
sint16 length; sint16 length;
uint16 flags; uint16 flags;
uint8 type; uint8 type;
uint8 *next_order; size_t next_order;
struct stream packet = *s; struct stream packet = *s;
in_uint16_le(s, length); in_uint16_le(s, length);
@ -1272,10 +1266,10 @@ process_secondary_order(STREAM s)
if (!s_check_rem(s, length)) 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) switch (type)
{ {
@ -1312,7 +1306,7 @@ process_secondary_order(STREAM s)
"process_secondary_order(), unhandled secondary order %d", type); "process_secondary_order(), unhandled secondary order %d", type);
} }
s->p = next_order; s_seek(s, next_order);
} }
/* Process an order PDU */ /* Process an order PDU */
@ -1454,9 +1448,9 @@ process_orders(STREAM s, uint16 num_orders)
} }
#if 0 #if 0
/* not true when RDP_COMPRESSION is set */ /* 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", logger(Graphics, Error, "process_orders(), %d bytes remaining",
(int) (g_next_packet - s->p)); (int) (g_next_packet - s_tell(s)));
#endif #endif
} }

View File

@ -238,6 +238,8 @@ printercache_process(STREAM s)
{ {
uint32 type, printer_length, driver_length, printer_unicode_length, blob_length; uint32 type, printer_length, driver_length, printer_unicode_length, blob_length;
char device_name[9], *printer, *driver; char device_name[9], *printer, *driver;
size_t blob_start;
unsigned char *blob;
printer = driver = NULL; printer = driver = NULL;
@ -279,8 +281,10 @@ printercache_process(STREAM s)
{ {
rdp_in_unistr(s, printer_unicode_length, &printer, rdp_in_unistr(s, printer_unicode_length, &printer,
&printer_unicode_length); &printer_unicode_length);
if (printer) if (printer) {
printercache_save_blob(printer, s->p, blob_length); in_uint8p(s, blob, blob_length);
printercache_save_blob(printer, blob, blob_length);
}
free(printer); free(printer);
} }
break; break;
@ -289,6 +293,7 @@ printercache_process(STREAM s)
in_uint8a(s, device_name, 5); /* get LPTx/COMx name */ 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. */ /* 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); /* ??? */
in_uint8s(s, 0x2) /* pad?? */ in_uint8s(s, 0x2) /* pad?? */
in_uint32_be(s, driver_length); in_uint32_be(s, driver_length);
@ -302,10 +307,11 @@ printercache_process(STREAM s)
/* rewind stream so that we can save this blob */ /* rewind stream so that we can save this blob */
/* length is driver_length + printer_length + 19 */ /* length is driver_length + printer_length + 19 */
/* rewind stream */ /* rewind stream */
s->p = s->p - 19; s_seek(s, blob_start);
printercache_save_blob(device_name, s->p, blob_length = driver_length + printer_length + 19;
driver_length + printer_length + 19); in_uint8p(s, blob, blob_length);
printercache_save_blob(device_name, blob, blob_length);
break; break;
default: default:
logger(Protocol, Warning, logger(Protocol, Warning,

11
proto.h
View File

@ -25,6 +25,11 @@ extern "C" {
#endif #endif
/* *INDENT-ON* */ /* *INDENT-ON* */
#define UNUSED(param) ((void)param) #define UNUSED(param) ((void)param)
#ifdef __GNUC__
# define NORETURN __attribute__((noreturn))
#else
# define NORETURN
#endif // __GNUC__
/* bitmap.c */ /* bitmap.c */
RD_BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp); RD_BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp);
/* cache.c */ /* cache.c */
@ -165,7 +170,9 @@ RD_BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, ch
char *directory, RD_BOOL reconnect); char *directory, RD_BOOL reconnect);
void rdp_reset_state(void); void rdp_reset_state(void);
void rdp_disconnect(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 */ /* rdpdr.c */
int get_device_index(RD_NTHANDLE handle); int get_device_index(RD_NTHANDLE handle);
void convert_to_unix_filename(char *filename); void convert_to_unix_filename(char *filename);
@ -220,7 +227,7 @@ char *tcp_get_address(void);
RD_BOOL tcp_is_connected(void); RD_BOOL tcp_is_connected(void);
void tcp_reset_state(void); void tcp_reset_state(void);
RD_BOOL tcp_tls_connect(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); void tcp_run_ui(RD_BOOL run);
/* asn.c */ /* asn.c */

View File

@ -836,7 +836,7 @@ main(int argc, char *argv[])
case 'u': case 'u':
g_username = (char *) xmalloc(strlen(optarg) + 1); g_username = (char *) xmalloc(strlen(optarg) + 1);
STRNCPY(g_username, optarg, strlen(optarg) + 1); strcpy(g_username, optarg);
username_option = 1; username_option = 1;
break; break;
@ -1355,7 +1355,7 @@ main(int argc, char *argv[])
STRNCPY(domain, g_redirect_domain, sizeof(domain)); STRNCPY(domain, g_redirect_domain, sizeof(domain));
xfree(g_username); xfree(g_username);
g_username = (char *) xmalloc(strlen(g_redirect_username) + 1); 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)); STRNCPY(server, g_redirect_server, sizeof(server));
flags |= RDP_INFO_AUTOLOGON; flags |= RDP_INFO_AUTOLOGON;
@ -1790,7 +1790,7 @@ str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler,
buf[0] = '\0'; buf[0] = '\0';
if (*rest) if (*rest)
STRNCPY(buf, *rest, buflen); STRNCPY(buf, *rest, buflen);
strncat(buf, input, inputlen); strncat(buf, input, buflen);
p = buf; p = buf;
while (1) while (1)

118
rdp.c
View File

@ -59,7 +59,7 @@ extern RD_BOOL g_dynamic_session_resize;
RD_BOOL g_exit_mainloop = False; RD_BOOL g_exit_mainloop = False;
uint8 *g_next_packet; size_t g_next_packet;
uint32 g_rdp_shareid; uint32 g_rdp_shareid;
extern RDPCOMP g_mppc_dict; 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; *type = pdu_type & 0xf;
/* Give just the size of the data */
*length -= 6;
return True; return True;
} }
@ -142,7 +145,7 @@ rdp_recv(uint8 * type)
while (1) while (1)
{ {
/* fill stream with data if needed for parsing a new packet */ /* 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); rdp_s = sec_recv(&is_fastpath);
if (rdp_s == NULL) if (rdp_s == NULL)
@ -155,11 +158,16 @@ rdp_recv(uint8 * type)
continue; continue;
} }
g_next_packet = rdp_s->p; g_next_packet = s_tell(rdp_s);
} }
else 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 */ /* 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); 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; return rdp_s;
} }
@ -194,7 +208,7 @@ rdp_send_data(STREAM s, uint8 data_pdu_type)
uint16 length; uint16 length;
s_pop_layer(s, rdp_hdr); s_pop_layer(s, rdp_hdr);
length = s->end - s->p; length = s_remaining(s);
out_uint16_le(s, length); out_uint16_le(s, length);
out_uint16_le(s, (RDP_PDU_DATA | 0x10)); 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; static iconv_t icv_local_to_utf16;
size_t ibl, obl; size_t ibl, obl;
char *pin, *pout; char *pin;
unsigned char *pout;
if (string == NULL || len == 0) if (string == NULL || len == 0)
@ -263,18 +278,16 @@ rdp_out_unistr(STREAM s, char *string, int len)
ibl = strlen(string); ibl = strlen(string);
obl = len + 2; obl = len + 2;
pin = string; 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); logger(Protocol, Error, "rdp_out_unistr(), iconv(2) fail, errno %d", errno);
abort(); abort();
} }
s->p += len + 2;
} }
/* Input a string in Unicode /* 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; static iconv_t icv_utf16_to_local;
size_t ibl, obl; size_t ibl, obl;
char *pin, *pout; unsigned char *pin;
char *pout;
struct stream packet = *s; struct stream packet = *s;
@ -296,9 +310,20 @@ rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size)
abort(); 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)) 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 // if not already open
@ -323,7 +348,7 @@ rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size)
ibl = in_len; ibl = in_len;
obl = *str_size - 1; obl = *str_size - 1;
pin = (char *) s->p; in_uint8p(s, pin, in_len);
pout = *string; pout = *string;
if (iconv(icv_utf16_to_local, (char **) &pin, &ibl, &pout, &obl) == (size_t) - 1) 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(); abort();
} }
/* we must update the location of the current STREAM for future reads of s->p */ /* Always force the last byte to be a null */
s->p += in_len;
*pout = 0; *pout = 0;
if (*string) 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) 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 else
{ {
@ -535,6 +558,7 @@ rdp_send_client_info_pdu(uint32 flags, char *domain, char *user,
g_redirect = False; g_redirect = False;
sec_send(s, sec_flags); sec_send(s, sec_flags);
s_free(s);
} }
/* Send a control PDU */ /* Send a control PDU */
@ -551,6 +575,7 @@ rdp_send_control(uint16 action)
s_mark_end(s); s_mark_end(s);
rdp_send_data(s, RDP_DATA_PDU_CONTROL); rdp_send_data(s, RDP_DATA_PDU_CONTROL);
s_free(s);
} }
/* Send a synchronisation PDU */ /* Send a synchronisation PDU */
@ -568,6 +593,7 @@ rdp_send_synchronise(void)
s_mark_end(s); s_mark_end(s);
rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE); rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE);
s_free(s);
} }
/* Send a single input event */ /* 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); s_mark_end(s);
rdp_send_data(s, RDP_DATA_PDU_INPUT); rdp_send_data(s, RDP_DATA_PDU_INPUT);
s_free(s);
} }
/* Send a Suppress Output PDU */ /* Send a Suppress Output PDU */
@ -625,6 +652,7 @@ rdp_send_suppress_output_pdu(enum RDP_SUPPRESS_STATUS allowupdates)
s_mark_end(s); s_mark_end(s);
rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS); rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS);
s_free(s);
current_status = allowupdates; current_status = allowupdates;
} }
@ -669,6 +697,7 @@ rdp_enum_bmpcache2(void)
s_mark_end(s); s_mark_end(s);
rdp_send_data(s, 0x2b); rdp_send_data(s, 0x2b);
s_free(s);
offset += 169; offset += 169;
} }
@ -691,6 +720,7 @@ rdp_send_fonts(uint16 seq)
s_mark_end(s); s_mark_end(s);
rdp_send_data(s, RDP_DATA_PDU_FONT2); rdp_send_data(s, RDP_DATA_PDU_FONT2);
s_free(s);
} }
/* Output general capability set (TS_GENERAL_CAPABILITYSET) */ /* 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, 1); /* maximumOrderLevel (ignored, should be 1) */
out_uint16_le(s, 0); /* numberFonts (ignored, should be 0) */ out_uint16_le(s, 0); /* numberFonts (ignored, should be 0) */
out_uint16_le(s, orderflags); /* orderFlags */ 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); /* textFlags (ignored) */
out_uint16_le(s, 0); /* orderSupportExFlags */ out_uint16_le(s, 0); /* orderSupportExFlags */
out_uint32_le(s, 0); /* pad4OctetsB */ 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, flags);
in_uint32_le(s, chunk_size); in_uint32_le(s, chunk_size);
UNUSED(flags);
vc_chunk_size = chunk_size; 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, sizeof(RDP_SOURCE));
out_uint16_le(s, caplen); 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_uint16_le(s, 17); /* num_caps */
out_uint8s(s, 2); /* pad */ out_uint8s(s, 2); /* pad */
@ -1128,6 +1159,7 @@ rdp_send_confirm_active(void)
s_mark_end(s); s_mark_end(s);
sec_send(s, sec_flags); sec_send(s, sec_flags);
s_free(s);
} }
/* Process a general capability set */ /* Process a general capability set */
@ -1210,25 +1242,25 @@ static void
rdp_process_server_caps(STREAM s, uint16 length) rdp_process_server_caps(STREAM s, uint16 length)
{ {
int n; int n;
uint8 *next, *start; size_t next, start;
uint16 ncapsets, capset_type, capset_length; uint16 ncapsets, capset_type, capset_length;
logger(Protocol, Debug, "%s()", __func__); logger(Protocol, Debug, "%s()", __func__);
start = s->p; start = s_tell(s);
in_uint16_le(s, ncapsets); in_uint16_le(s, ncapsets);
in_uint8s(s, 2); /* pad */ in_uint8s(s, 2); /* pad */
for (n = 0; n < ncapsets; n++) for (n = 0; n < ncapsets; n++)
{ {
if (s->p > start + length) if (s_tell(s) > start + length)
return; return;
in_uint16_le(s, capset_type); in_uint16_le(s, capset_type);
in_uint16_le(s, capset_length); in_uint16_le(s, capset_length);
next = s->p + capset_length - 4; next = s_tell(s) + capset_length - 4;
switch (capset_type) switch (capset_type)
{ {
@ -1247,7 +1279,7 @@ rdp_process_server_caps(STREAM s, uint16 length)
break; 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)) 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); in_uint8s(s, len_src_descriptor);
@ -1416,8 +1448,7 @@ process_pointer_pdu(STREAM s)
case RDP_POINTER_MOVE: case RDP_POINTER_MOVE:
in_uint16_le(s, x); in_uint16_le(s, x);
in_uint16_le(s, y); in_uint16_le(s, y);
if (s_check(s)) ui_move_pointer(x, y);
ui_move_pointer(x, y);
break; break;
case RDP_POINTER_COLOR: case RDP_POINTER_COLOR:
@ -1521,7 +1552,7 @@ process_bitmap_data(STREAM s)
/* read compressed bitmap data */ /* read compressed bitmap data */
if (!s_check_rem(s, size)) 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); in_uint8p(s, data, size);
bmpdata = (uint8 *) xmalloc(width * height * Bpp); bmpdata = (uint8 *) xmalloc(width * height * Bpp);
@ -1718,6 +1749,7 @@ process_data_pdu(STREAM s, uint32 * ext_disc_reason)
uint16 clen; uint16 clen;
uint32 len; uint32 len;
uint8 *buf;
uint32 roff, rlen; uint32 roff, rlen;
struct stream *ns = &(g_mppc_dict.ns); 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) if (len > RDP_MPPC_DICT_SIZE)
logger(Protocol, Error, logger(Protocol, Error,
"process_data_pdu(), error decompressed packet size exceeds max"); "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, logger(Protocol, Error,
"process_data_pdu(), error while decompressing packet"); "process_data_pdu(), error while decompressing packet");
/* len -= 18; */ /* len -= 18; */
/* allocate memory and copy the uncompressed data into the temporary stream */ /* 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; s_mark_end(ns);
ns->end = (ns->data + ns->size); s_seek(ns, 0);
ns->p = ns->data; s_push_layer(ns, rdp_hdr, 0);
ns->rdp_hdr = ns->p;
s = ns; s = ns;
} }
@ -2048,7 +2081,7 @@ rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
logger(Protocol, Warning, logger(Protocol, Warning,
"rdp_loop(), unhandled PDU type %d received", type); "rdp_loop(), unhandled PDU type %d received", type);
} }
cont = g_next_packet < s->end; cont = g_next_packet < s_length(s);
} }
return True; return True;
} }
@ -2086,7 +2119,7 @@ void
rdp_reset_state(void) rdp_reset_state(void)
{ {
logger(Protocol, Debug, "%s()", __func__); 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_rdp_shareid = 0;
g_exit_mainloop = False; g_exit_mainloop = False;
g_first_bitmap_caps = True; g_first_bitmap_caps = True;
@ -2111,10 +2144,11 @@ rdp_disconnect(void)
*/ */
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) if (s)
hexdump(s->p, s_length(s)); hexdump(s->data, s_length(s));
exit(0); exit(0);
} }

41
rdp5.c
View File

@ -21,7 +21,7 @@
#include "rdesktop.h" #include "rdesktop.h"
extern uint8 *g_next_packet; extern size_t g_next_packet;
extern RDPCOMP g_mppc_dict; extern RDPCOMP g_mppc_dict;
@ -56,8 +56,7 @@ process_ts_fp_update_by_code(STREAM s, uint8 code)
case FASTPATH_UPDATETYPE_PTR_POSITION: case FASTPATH_UPDATETYPE_PTR_POSITION:
in_uint16_le(s, x); in_uint16_le(s, x);
in_uint16_le(s, y); in_uint16_le(s, y);
if (s_check(s)) ui_move_pointer(x, y);
ui_move_pointer(x, y);
break; break;
case FASTPATH_UPDATETYPE_COLOR: case FASTPATH_UPDATETYPE_COLOR:
process_colour_pointer_pdu(s); process_colour_pointer_pdu(s);
@ -79,16 +78,17 @@ process_ts_fp_updates(STREAM s)
{ {
uint16 length; uint16 length;
uint8 hdr, code, frag, comp, ctype = 0; uint8 hdr, code, frag, comp, ctype = 0;
uint8 *next; size_t next;
uint8 *buf;
uint32 roff, rlen; uint32 roff, rlen;
struct stream *ns = &(g_mppc_dict.ns); struct stream *ns = &(g_mppc_dict.ns);
struct stream *ts; struct stream *ts;
static STREAM assembled[0x0F] = { 0 }; static STREAM assembled[16] = { 0 };
ui_begin_update(); 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.. */ /* Reading a number of TS_FP_UPDATE structures from the stream here.. */
in_uint8(s, hdr); /* updateHeader */ in_uint8(s, hdr); /* updateHeader */
@ -101,23 +101,24 @@ process_ts_fp_updates(STREAM s)
in_uint16_le(s, length); /* length */ 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 (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, logger(Protocol, Error,
"process_ts_fp_update_pdu(), error while decompressing packet"); "process_ts_fp_update_pdu(), error while decompressing packet");
/* allocate memory and copy the uncompressed data into the temporary stream */ /* 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; s_mark_end(ns);
ns->end = (ns->data + ns->size); s_seek(ns, 0);
ns->p = ns->data; s_push_layer(ns, rdp_hdr, 0);
ns->rdp_hdr = ns->p;
length = rlen; length = rlen;
ts = ns; ts = ns;
@ -133,11 +134,7 @@ process_ts_fp_updates(STREAM s)
{ {
if (assembled[code] == NULL) if (assembled[code] == NULL)
{ {
assembled[code] = xmalloc(sizeof(struct stream)); assembled[code] = s_alloc(RDESKTOP_FASTPATH_MULTIFRAGMENT_MAX_SIZE);
memset(assembled[code], 0, sizeof(struct stream));
s_realloc(assembled[code],
RDESKTOP_FASTPATH_MULTIFRAGMENT_MAX_SIZE);
s_reset(assembled[code]);
} }
if (frag == FASTPATH_FRAGMENT_FIRST) if (frag == FASTPATH_FRAGMENT_FIRST)
@ -145,17 +142,17 @@ process_ts_fp_updates(STREAM s)
s_reset(assembled[code]); s_reset(assembled[code]);
} }
out_uint8p(assembled[code], ts->p, length); out_uint8stream(assembled[code], ts, length);
if (frag == FASTPATH_FRAGMENT_LAST) if (frag == FASTPATH_FRAGMENT_LAST)
{ {
s_mark_end(assembled[code]); 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); process_ts_fp_update_by_code(assembled[code], code);
} }
} }
s->p = next; s_seek(s, next);
} }
ui_end_update(); ui_end_update();
} }

142
rdpdr.c
View File

@ -204,6 +204,7 @@ rdpdr_send_client_announce_reply(void)
out_uint32_be(s, g_client_id); /* ClientID */ out_uint32_be(s, g_client_id); /* ClientID */
s_mark_end(s); s_mark_end(s);
channel_send(s, rdpdr_channel); channel_send(s, rdpdr_channel);
s_free(s);
} }
@ -233,6 +234,7 @@ rdpdr_send_client_name_request(void)
out_stream(s, &name); out_stream(s, &name);
s_mark_end(s); s_mark_end(s);
channel_send(s, rdpdr_channel); channel_send(s, rdpdr_channel);
s_free(s);
} }
/* Returns the size of the payload of the announce packet */ /* 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, g_rdpdr_device[i].device_type);
out_uint32_le(s, i); /* RDP Device ID */ 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) switch (g_rdpdr_device[i].device_type)
{ {
case DEVICE_TYPE_DISK: case DEVICE_TYPE_DISK:
@ -314,7 +316,7 @@ rdpdr_send_client_device_list_announce(void)
disklen = strlen(diskinfo->name) + 1; disklen = strlen(diskinfo->name) + 1;
out_uint32_le(s, disklen); /* DeviceDataLength */ out_uint32_le(s, disklen); /* DeviceDataLength */
out_uint8p(s, diskinfo->name, disklen); /* DeviceData */ out_uint8a(s, diskinfo->name, disklen); /* DeviceData */
break; break;
case DEVICE_TYPE_PRINTER: case DEVICE_TYPE_PRINTER:
@ -357,6 +359,7 @@ rdpdr_send_client_device_list_announce(void)
s_mark_end(s); s_mark_end(s);
channel_send(s, rdpdr_channel); channel_send(s, rdpdr_channel);
s_free(s);
} }
void 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, status);
out_uint32_le(s, result); out_uint32_le(s, result);
if (length) if (length)
out_uint8p(s, buffer, length); out_uint8a(s, buffer, length);
s_mark_end(s); s_mark_end(s);
logger(Protocol, Debug, "rdpdr_send_completion()"); logger(Protocol, Debug, "rdpdr_send_completion()");
/* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */ /* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
channel_send(s, rdpdr_channel); channel_send(s, rdpdr_channel);
s_free(s);
#ifdef WITH_SCARD #ifdef WITH_SCARD
scard_unlock(SCARD_LOCK_RDPDR); scard_unlock(SCARD_LOCK_RDPDR);
#endif #endif
@ -407,7 +411,6 @@ rdpdr_process_irp(STREAM s)
request, request,
file, file,
info_level, info_level,
buffer_len,
id, id,
major, major,
minor, minor,
@ -420,8 +423,8 @@ rdpdr_process_irp(STREAM s)
char *filename; char *filename;
uint32 filename_len; uint32 filename_len;
uint8 *buffer, *pst_buf; uint8 *pst_buf;
struct stream out; STREAM out;
DEVICE_FNS *fns; DEVICE_FNS *fns;
RD_BOOL rw_blocking = True; RD_BOOL rw_blocking = True;
RD_NTSTATUS status = RD_STATUS_INVALID_DEVICE_REQUEST; RD_NTSTATUS status = RD_STATUS_INVALID_DEVICE_REQUEST;
@ -434,16 +437,13 @@ rdpdr_process_irp(STREAM s)
filename = NULL; filename = NULL;
buffer_len = 0; out = NULL;
buffer = (uint8 *) xmalloc(1024);
buffer[0] = 0;
if (device >= RDPDR_MAX_DEVICES) if (device >= RDPDR_MAX_DEVICES)
{ {
logger(Protocol, Error, logger(Protocol, Error,
"rdpdr_process_irp(), invalid irp device=0x%lx, file=0x%lx, id=0x%lx, major=0x%lx, minor=0x%lx", "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); device, file, id, major, minor);
xfree(buffer);
return; return;
} }
@ -482,7 +482,6 @@ rdpdr_process_irp(STREAM s)
logger(Protocol, Error, logger(Protocol, Error,
"rdpdr_process_irp(), received IRP for unknown device type %ld", "rdpdr_process_irp(), received IRP for unknown device type %ld",
device); device);
xfree(buffer);
return; return;
} }
@ -516,7 +515,9 @@ rdpdr_process_irp(STREAM s)
flags_and_attributes, filename, &result); flags_and_attributes, filename, &result);
free(filename); free(filename);
buffer_len = 1; out = s_alloc(1);
out_uint8(out, 0);
s_mark_end(out);
break; break;
case IRP_MJ_CLOSE: case IRP_MJ_CLOSE:
@ -553,14 +554,14 @@ rdpdr_process_irp(STREAM s)
if (rw_blocking) /* Complete read immediately */ if (rw_blocking) /* Complete read immediately */
{ {
buffer = (uint8 *) xrealloc((void *) buffer, length); uint8* buffer;
if (!buffer) out = s_alloc(length);
{ out_uint8p(out, buffer, length);
status = RD_STATUS_CANCELLED;
break;
}
status = fns->read(file, buffer, length, offset, &result); 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; break;
} }
@ -584,7 +585,9 @@ rdpdr_process_irp(STREAM s)
break; break;
case IRP_MJ_WRITE: case IRP_MJ_WRITE:
buffer_len = 1; out = s_alloc(1);
out_uint8(out, 0);
s_mark_end(out);
if (!fns->write) if (!fns->write)
{ {
@ -608,7 +611,9 @@ rdpdr_process_irp(STREAM s)
if (rw_blocking) /* Complete immediately */ 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; break;
} }
@ -641,10 +646,10 @@ rdpdr_process_irp(STREAM s)
} }
in_uint32_le(s, info_level); in_uint32_le(s, info_level);
out.data = out.p = buffer; out = s_alloc(1024);
out.size = sizeof(buffer); status = disk_query_information(file, info_level, out);
status = disk_query_information(file, info_level, &out); s_mark_end(out);
result = buffer_len = out.p - out.data; result = s_length(out);
break; break;
@ -658,10 +663,10 @@ rdpdr_process_irp(STREAM s)
in_uint32_le(s, info_level); in_uint32_le(s, info_level);
out.data = out.p = buffer; out = s_alloc(1024);
out.size = sizeof(buffer); status = disk_set_information(file, info_level, s, out);
status = disk_set_information(file, info_level, s, &out); s_mark_end(out);
result = buffer_len = out.p - out.data; result = s_length(out);
break; break;
case IRP_MJ_QUERY_VOLUME_INFORMATION: case IRP_MJ_QUERY_VOLUME_INFORMATION:
@ -674,10 +679,10 @@ rdpdr_process_irp(STREAM s)
in_uint32_le(s, info_level); in_uint32_le(s, info_level);
out.data = out.p = buffer; out = s_alloc(1024);
out.size = sizeof(buffer); status = disk_query_volume_information(file, info_level, out);
status = disk_query_volume_information(file, info_level, &out); s_mark_end(out);
result = buffer_len = out.p - out.data; result = s_length(out);
break; break;
case IRP_MJ_DIRECTORY_CONTROL: case IRP_MJ_DIRECTORY_CONTROL:
@ -703,13 +708,16 @@ rdpdr_process_irp(STREAM s)
convert_to_unix_filename(filename); convert_to_unix_filename(filename);
} }
out.data = out.p = buffer; out = s_alloc(1024);
out.size = sizeof(buffer);
status = disk_query_directory(file, info_level, filename, status = disk_query_directory(file, info_level, filename,
&out); out);
result = buffer_len = out.p - out.data; s_mark_end(out);
if (!buffer_len) if (!s_length(out))
buffer_len++; {
out_uint8(out, 0);
s_mark_end(out);
}
result = s_length(out);
free(filename); free(filename);
break; break;
@ -756,23 +764,14 @@ rdpdr_process_irp(STREAM s)
in_uint8s(s, 0x14); in_uint8s(s, 0x14);
/* TODO: Why do we need to increase length by padlen? Or is it hdr len? */ /* TODO: Why do we need to increase length by padlen? Or is it hdr len? */
buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14); out = s_alloc(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;
#ifdef WITH_SCARD #ifdef WITH_SCARD
scardSetInfo(g_epoch, device, id, bytes_out + 0x14); scardSetInfo(g_epoch, device, id, bytes_out + 0x14);
#endif #endif
status = fns->device_control(file, request, s, &out); status = fns->device_control(file, request, s, out);
result = buffer_len = out.p - out.data; s_mark_end(out);
result = s_length(out);
/* Serial SERIAL_WAIT_ON_MASK */ /* Serial SERIAL_WAIT_ON_MASK */
if (status == RD_STATUS_PENDING) if (status == RD_STATUS_PENDING)
@ -801,12 +800,12 @@ rdpdr_process_irp(STREAM s)
in_uint32_le(s, info_level); in_uint32_le(s, info_level);
out.data = out.p = buffer; out = s_alloc(1024);
out.size = sizeof(buffer);
/* FIXME: Perhaps consider actually *do* /* FIXME: Perhaps consider actually *do*
something here :-) */ something here :-) */
status = RD_STATUS_SUCCESS; status = RD_STATUS_SUCCESS;
result = buffer_len = out.p - out.data; s_mark_end(out);
result = s_length(out);
break; break;
default: default:
@ -818,11 +817,25 @@ rdpdr_process_irp(STREAM s)
if (status != RD_STATUS_PENDING) 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); rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
} }
if (buffer) if (out)
xfree(buffer); s_free(out);
buffer = NULL;
} }
static void static void
@ -868,6 +881,7 @@ rdpdr_send_client_capability_response(void)
s_mark_end(s); s_mark_end(s);
channel_send(s, rdpdr_channel); channel_send(s, rdpdr_channel);
s_free(s);
} }
static void static void
@ -877,10 +891,9 @@ rdpdr_process(STREAM s)
uint16 vmin; uint16 vmin;
uint16 component; uint16 component;
uint16 pakid; uint16 pakid;
struct stream packet = *s;
logger(Protocol, Debug, "rdpdr_process()"); 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, component); /* RDPDR_HEADER.Component */
in_uint16(s, pakid); /* RDPDR_HEADER.PacketId */ in_uint16(s, pakid); /* RDPDR_HEADER.PacketId */
@ -900,15 +913,6 @@ rdpdr_process(STREAM s)
in_uint32_le(s, g_client_id); /* ClientID */ 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 /* The RDP client is responsibility to provide a random client id
if server version is < 12 */ if server version is < 12 */
if (vmin < 0x000c) if (vmin < 0x000c)

View File

@ -64,7 +64,7 @@ rdpedisp_process_pdu(STREAM s)
/* Read DISPLAYCONTROL_HEADER */ /* Read DISPLAYCONTROL_HEADER */
in_uint32_le(s, type); /* type */ 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); logger(Protocol, Debug, "rdpedisp_process_pdu(), Got PDU type %d", type);

View File

@ -64,6 +64,7 @@ unsigned int queue_hi, queue_lo, queue_pending;
struct audio_packet packet_queue[MAX_QUEUE]; struct audio_packet packet_queue[MAX_QUEUE];
static uint8 packet_opcode; static uint8 packet_opcode;
static size_t packet_len;
static struct stream packet; static struct stream packet;
void (*wave_out_play) (void); void (*wave_out_play) (void);
@ -103,6 +104,7 @@ rdpsnd_send_waveconfirm(uint16 tick, uint8 packet_index)
out_uint8(s, 0); out_uint8(s, 0);
s_mark_end(s); s_mark_end(s);
rdpsnd_send(s); rdpsnd_send(s);
s_free(s);
logger(Sound, Debug, "rdpsnd_send_waveconfirm(), tick=%u, index=%u", logger(Sound, Debug, "rdpsnd_send_waveconfirm(), tick=%u, index=%u",
(unsigned) tick, (unsigned) packet_index); (unsigned) tick, (unsigned) packet_index);
@ -259,6 +261,7 @@ rdpsnd_process_negotiate(STREAM in)
(int) format_count); (int) format_count);
rdpsnd_send(out); rdpsnd_send(out);
s_free(out);
rdpsnd_negotiated = True; rdpsnd_negotiated = True;
} }
@ -273,7 +276,7 @@ rdpsnd_process_training(STREAM in)
if (!s_check_rem(in, 4)) 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); in_uint16_le(in, tick);
@ -286,14 +289,18 @@ rdpsnd_process_training(STREAM in)
out_uint16_le(out, packsize); out_uint16_le(out, packsize);
s_mark_end(out); s_mark_end(out);
rdpsnd_send(out); rdpsnd_send(out);
s_free(out);
} }
static void static void
rdpsnd_process_packet(uint8 opcode, STREAM s) rdpsnd_process_packet(uint8 opcode, STREAM s)
{ {
uint16 vol_left, vol_right; 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) switch (opcode)
{ {
@ -342,9 +349,12 @@ rdpsnd_process_packet(uint8 opcode, STREAM s)
current_format = format; current_format = format;
} }
rdpsnd_queue_write(rdpsnd_dsp_process size = s_remaining(s);
(s->p, s->end - s->p, current_driver, in_uint8p(s, data, size);
&formats[current_format]), tick, packet_index); rdpsnd_queue_write(rdpsnd_dsp_process(data, size,
current_driver,
&formats[current_format]),
tick, packet_index);
return; return;
break; break;
case SNDC_CLOSE: case SNDC_CLOSE:
@ -379,14 +389,12 @@ rdpsnd_process_packet(uint8 opcode, STREAM s)
static void static void
rdpsnd_process(STREAM s) rdpsnd_process(STREAM s)
{ {
uint16 len;
while (!s_check_end(s)) while (!s_check_end(s))
{ {
/* New packet */ /* 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, logger(Sound, Error,
"rdpsnd_process(), split at packet header, things will go south from here..."); "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_uint8(s, packet_opcode);
in_uint8s(s, 1); /* Padding */ 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", logger(Sound, Debug, "rdpsnd_process(), Opcode = 0x%x Length= %d",
(int) packet_opcode, (int) len); (int) packet_opcode, (int) packet_len);
packet.p = packet.data;
packet.end = packet.data + len;
packet.size = len;
} }
else 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... */ /* Microsoft's server is so broken it's not even funny... */
if (packet_opcode == SNDC_WAVE) if (packet_opcode == SNDC_WAVE)
{ {
if ((packet.p - packet.data) < 12) if (s_length(&packet) < 12)
len = MIN(len, 12 - (packet.p - packet.data)); len = MIN(len, 12 - s_length(&packet));
else if ((packet.p - packet.data) == 12) else if (s_length(&packet) == 12)
{ {
logger(Sound, Debug, logger(Sound, Debug,
"rdpsnd_process(), eating 4 bytes of %d bytes...", "rdpsnd_process(), eating 4 bytes of %d bytes...",
@ -422,16 +428,18 @@ rdpsnd_process(STREAM s)
} }
} }
in_uint8a(s, packet.p, len); in_uint8stream(s, &packet, len);
packet.p += len; /* Always end it so s_length() works */
s_mark_end(&packet);
} }
/* Packet fully assembled */ /* 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); 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; static char *rest = NULL;
char *buf; char *buf;
if (!s_check(s)) pkglen = s_remaining(s);
{
rdp_protocol_error("rdpsnddbg_process(), stream is in unstable state", s);
}
pkglen = s->end - s->p;
/* str_handle_lines requires null terminated strings */ /* str_handle_lines requires null terminated strings */
buf = (char *) xmalloc(pkglen + 1); 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); str_handle_lines(buf, &rest, rdpsnddbg_line_handler, NULL);
@ -515,9 +519,7 @@ rdpsnd_init(char *optarg)
drivers = NULL; drivers = NULL;
packet.data = (uint8 *) xmalloc(65536); s_realloc(&packet, 65536);
packet.p = packet.end = packet.data;
packet.size = 0;
rdpsnd_channel = rdpsnd_channel =
channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, 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; queue_hi = next_hi;
packet->s = *s; packet->s = s;
packet->tick = tick; packet->tick = tick;
packet->index = index; packet->index = index;
@ -677,7 +679,7 @@ rdpsnd_queue_clear(void)
while (queue_pending != queue_hi) while (queue_pending != queue_hi)
{ {
packet = &packet_queue[queue_pending]; packet = &packet_queue[queue_pending];
xfree(packet->s.data); s_free(packet->s);
queue_pending = (queue_pending + 1) % MAX_QUEUE; 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); (packet->completion_tv.tv_usec - packet->arrive_tv.tv_usec);
elapsed /= 1000; elapsed /= 1000;
xfree(packet->s.data); s_free(packet->s);
rdpsnd_send_waveconfirm((packet->tick + elapsed) % 65536, packet->index); rdpsnd_send_waveconfirm((packet->tick + elapsed) % 65536, packet->index);
queue_pending = (queue_pending + 1) % MAX_QUEUE; queue_pending = (queue_pending + 1) % MAX_QUEUE;
} }

View File

@ -19,7 +19,7 @@
struct audio_packet struct audio_packet
{ {
struct stream s; STREAM s;
uint16 tick; uint16 tick;
uint8 index; uint8 index;

View File

@ -358,6 +358,8 @@ alsa_play(void)
struct audio_packet *packet; struct audio_packet *packet;
STREAM out; STREAM out;
int len; int len;
const unsigned char *data;
size_t before;
static long prev_s, prev_us; static long prev_s, prev_us;
int duration; int duration;
struct timeval tv; struct timeval tv;
@ -376,17 +378,25 @@ alsa_play(void)
return; return;
packet = rdpsnd_queue_current_packet(); packet = rdpsnd_queue_current_packet();
out = &packet->s; out = packet->s;
next_tick = rdpsnd_queue_next_tick(); next_tick = rdpsnd_queue_next_tick();
len = (out->end - out->p) / (samplewidth_out * audiochannels_out); before = s_tell(out);
if ((len = snd_pcm_writei(out_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)
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); snd_pcm_prepare(out_handle);
len = 0; 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); gettimeofday(&tv, NULL);
@ -395,7 +405,7 @@ alsa_play(void)
if (packet->tick > next_tick) if (packet->tick > next_tick)
next_tick += 65536; 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; snd_pcm_sframes_t delay_frames;
unsigned long delay_us; unsigned long delay_us;

View File

@ -175,8 +175,8 @@ rdpsnd_dsp_resample_supported(RD_WAVEFORMATEX * format)
return True; return True;
} }
uint32 STREAM
rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size, rdpsnd_dsp_resample(unsigned char *in, unsigned int size,
RD_WAVEFORMATEX * format, RD_BOOL stream_be) RD_WAVEFORMATEX * format, RD_BOOL stream_be)
{ {
UNUSED(stream_be); UNUSED(stream_be);
@ -190,13 +190,15 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
int innum, outnum; int innum, outnum;
unsigned char *tmpdata = NULL, *tmp = NULL; unsigned char *tmpdata = NULL, *tmp = NULL;
int samplewidth = format->wBitsPerSample / 8; int samplewidth = format->wBitsPerSample / 8;
STREAM out;
int outsize = 0; int outsize = 0;
unsigned char *data;
int i; int i;
if ((resample_to_bitspersample == format->wBitsPerSample) && if ((resample_to_bitspersample == format->wBitsPerSample) &&
(resample_to_channels == format->nChannels) && (resample_to_channels == format->nChannels) &&
(resample_to_srate == format->nSamplesPerSec)) (resample_to_srate == format->nSamplesPerSec))
return 0; return NULL;
#ifdef B_ENDIAN #ifdef B_ENDIAN
if (!stream_be) if (!stream_be)
@ -260,7 +262,7 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
{ {
logger(Sound, Warning, logger(Sound, Warning,
"rdpsndp_dsp_resample_set(), no sample rate converter available"); "rdpsndp_dsp_resample_set(), no sample rate converter available");
return 0; return NULL;
} }
outnum = ((float) innum * ((float) resample_to_srate / (float) format->nSamplesPerSec)) + 1; 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); xfree(infloat);
outsize = resample_data.output_frames_gen * resample_to_channels * samplewidth; outsize = resample_data.output_frames_gen * resample_to_channels * samplewidth;
*out = (unsigned char *) xmalloc(outsize); out = s_alloc(outsize);
src_float_to_short_array(outfloat, (short *) *out, out_uint8p(out, data, outsize);
src_float_to_short_array(outfloat, (short *) data,
resample_data.output_frames_gen * resample_to_channels); resample_data.output_frames_gen * resample_to_channels);
xfree(outfloat); xfree(outfloat);
@ -302,8 +305,9 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
outnum = (innum * ratio1k) / 1000; outnum = (innum * ratio1k) / 1000;
outsize = outnum * samplewidth; outsize = outnum * samplewidth;
*out = (unsigned char *) xmalloc(outsize); out = s_alloc(outsize);
bzero(*out, outsize); out_uint8p(out, data, outsize);
bzero(data, outsize);
for (i = 0; i < outsize / (resample_to_channels * samplewidth); i++) 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; cval1 += (sint8) (cval2 * part) / 100;
memcpy(*out + (i * resample_to_channels * samplewidth) + memcpy(data + (i * resample_to_channels * samplewidth) +
(samplewidth * j), &cval1, 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; sval1 += (sint16) (sval2 * part) / 100;
memcpy(*out + (i * resample_to_channels * samplewidth) + memcpy(data + (i * resample_to_channels * samplewidth) +
(samplewidth * j), &sval1, samplewidth); (samplewidth * j), &sval1, samplewidth);
} }
} }
#else /* Nearest neighbor search */ #else /* Nearest neighbor search */
for (j = 0; j < resample_to_channels; j++) 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) + in + (source * resample_to_channels * samplewidth) +
(samplewidth * j), 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++) for (i = 0; i < outsize; i++)
{ {
*out[i] = *out[i * 2]; data[i] = data[i * 2];
} }
outsize /= 2; outsize /= 2;
} }
@ -386,16 +390,17 @@ rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,
#ifdef B_ENDIAN #ifdef B_ENDIAN
if (!stream_be) if (!stream_be)
rdpsnd_dsp_swapbytes(*out, outsize, format); rdpsnd_dsp_swapbytes(data, outsize, format);
#endif #endif
return outsize;
return out;
} }
STREAM STREAM
rdpsnd_dsp_process(unsigned char *data, unsigned int size, struct audio_driver * current_driver, rdpsnd_dsp_process(unsigned char *data, unsigned int size, struct audio_driver * current_driver,
RD_WAVEFORMATEX * format) RD_WAVEFORMATEX * format)
{ {
static struct stream out; STREAM out;
RD_BOOL stream_be = False; RD_BOOL stream_be = False;
/* softvol and byteswap do not change the amount of data they /* 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 #endif
out.data = NULL; out = NULL;
if (current_driver->need_resampling) 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); out = s_alloc(size);
memcpy(out.data, data, size); out_uint8a(out, data, size);
out.size = size;
} }
out.p = out.data; s_mark_end(out);
out.end = out.p + out.size; s_seek(out, 0);
return &out; return out;
} }

View File

@ -148,6 +148,7 @@ libao_play(void)
{ {
struct audio_packet *packet; struct audio_packet *packet;
STREAM out; STREAM out;
unsigned char *data;
int len; int len;
static long prev_s, prev_us; static long prev_s, prev_us;
int duration; int duration;
@ -167,13 +168,13 @@ libao_play(void)
return; return;
packet = rdpsnd_queue_current_packet(); packet = rdpsnd_queue_current_packet();
out = &packet->s; out = packet->s;
next_tick = rdpsnd_queue_next_tick(); next_tick = rdpsnd_queue_next_tick();
len = (WAVEOUTLEN > (out->end - out->p)) ? (out->end - out->p) : WAVEOUTLEN; len = MIN(WAVEOUTLEN, s_remaining(out));
ao_play(o_device, (char *) out->p, len); in_uint8p(out, data, len);
out->p += len; ao_play(o_device, (char *) data, len);
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
@ -182,7 +183,7 @@ libao_play(void)
if (packet->tick > next_tick) if (packet->tick > next_tick)
next_tick += 65536; 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; unsigned int delay_us;

View File

@ -402,6 +402,8 @@ oss_play(void)
struct audio_packet *packet; struct audio_packet *packet;
ssize_t len; ssize_t len;
STREAM out; STREAM out;
size_t before;
const unsigned char *data;
assert(dsp_fd != -1); assert(dsp_fd != -1);
@ -410,11 +412,14 @@ oss_play(void)
return; return;
packet = rdpsnd_queue_current_packet(); 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 (len == -1)
{ {
if (errno != EWOULDBLOCK) if (errno != EWOULDBLOCK)
@ -429,9 +434,10 @@ oss_play(void)
dsp_broken = False; 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; int delay_bytes;
unsigned long delay_us; unsigned long delay_us;

View File

@ -1154,7 +1154,7 @@ pulse_play(void)
do do
{ {
packet = rdpsnd_queue_current_packet(); packet = rdpsnd_queue_current_packet();
out = &packet->s; out = packet->s;
ti = pa_stream_get_timing_info(playback_stream); ti = pa_stream_get_timing_info(playback_stream);
if (ti == NULL) if (ti == NULL)
@ -1192,11 +1192,14 @@ pulse_play(void)
playback_seek = PA_SEEK_RELATIVE; playback_seek = PA_SEEK_RELATIVE;
avail_space = pa_stream_writable_size(playback_stream); 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) if (audio_size)
{ {
unsigned char *data;
in_uint8p(out, data, audio_size);
if (pa_stream_write 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); err = pa_context_errno(context);
logger(Sound, Error, "pulse_play(), pa_stream_write: %s", logger(Sound, Error, "pulse_play(), pa_stream_write: %s",
@ -1207,9 +1210,7 @@ pulse_play(void)
playback_seek = PA_SEEK_RELATIVE; playback_seek = PA_SEEK_RELATIVE;
} }
out->p += audio_size; if (s_check_end(out))
if (out->p == out->end)
{ {
ret = pa_stream_get_latency(playback_stream, &delay, NULL); ret = pa_stream_get_latency(playback_stream, &delay, NULL);
if (ret != 0 && (err = pa_context_errno(context)) == PA_ERR_NODATA) if (ret != 0 && (err = pa_context_errno(context)) == PA_ERR_NODATA)
@ -1251,7 +1252,7 @@ pulse_play(void)
pa_threaded_mainloop_unlock(mainloop); pa_threaded_mainloop_unlock(mainloop);
if (out->p == out->end) if (s_check_end(out))
rdpsnd_queue_next(delay); rdpsnd_queue_next(delay);
return result; return result;

View File

@ -246,6 +246,7 @@ sgi_play(void)
struct audio_packet *packet; struct audio_packet *packet;
ssize_t len; ssize_t len;
STREAM out; STREAM out;
unsigned char *data;
int gf; int gf;
while (1) while (1)
@ -254,14 +255,14 @@ sgi_play(void)
return; return;
packet = rdpsnd_queue_current_packet(); 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 (s_check_end(out))
if (out->p == out->end)
{ {
gf = alGetFilled(output_port); gf = alGetFilled(output_port);
if (gf < (4 * maxFillable / 10)) if (gf < (4 * maxFillable / 10))

View File

@ -411,17 +411,22 @@ sun_play(void)
struct audio_packet *packet; struct audio_packet *packet;
ssize_t len; ssize_t len;
STREAM out; STREAM out;
size_t before;
const unsigned char *data;
/* We shouldn't be called if the queue is empty, but still */ /* We shouldn't be called if the queue is empty, but still */
if (rdpsnd_queue_empty()) if (rdpsnd_queue_empty())
return; return;
packet = rdpsnd_queue_current_packet(); 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 (len == -1)
{ {
if (errno != EWOULDBLOCK) if (errno != EWOULDBLOCK)
@ -439,9 +444,10 @@ sun_play(void)
dsp_broken = False; 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; audio_info_t info;
uint_t delay_samples; uint_t delay_samples;

191
scard.c
View File

@ -237,10 +237,8 @@ scard_enum_devices(uint32 * id, char *optarg)
tmpMap = nameMapList + nameMapCount - 1; tmpMap = nameMapList + nameMapCount - 1;
len = strlen(alias); STRNCPY(tmpMap->alias, alias, sizeof(tmpMap->alias));
strncpy(tmpMap->alias, alias, (len > 127) ? (127) : (len)); STRNCPY(tmpMap->name, name, sizeof(tmpMap->name));
len = strlen(name);
strncpy(tmpMap->name, name, (len > 127) ? (127) : (len));
if (vendor) if (vendor)
{ {
@ -248,8 +246,8 @@ scard_enum_devices(uint32 * id, char *optarg)
if (len > 0) if (len > 0)
{ {
memset(tmpMap->vendor, 0, 128); memset(tmpMap->vendor, 0, 128);
strncpy(tmpMap->vendor, vendor, STRNCPY(tmpMap->vendor, vendor,
(len > 127) ? (127) : (len)); sizeof(tmpMap->vendor));
} }
else else
tmpMap->vendor[0] = '\0'; tmpMap->vendor[0] = '\0';
@ -550,7 +548,7 @@ outBufferFinishWithLimit(STREAM out, char *buffer, unsigned int length, unsigned
{ {
if (header < length) if (header < length)
length = header; length = header;
out_uint8p(out, buffer, length); out_uint8a(out, buffer, length);
outRepos(out, length); outRepos(out, length);
} }
} }
@ -564,7 +562,7 @@ outBufferFinish(STREAM out, char *buffer, unsigned int length)
static void static void
outForceAlignment(STREAM out, unsigned int seed) 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) if (add > 0)
out_uint8s(out, add); out_uint8s(out, add);
} }
@ -626,11 +624,11 @@ outString(STREAM out, char *source, RD_BOOL wide)
buffer[2 * i] = reader[i]; buffer[2 * i] = reader[i];
buffer[2 * i + 1] = '\0'; buffer[2 * i + 1] = '\0';
} }
out_uint8p(out, buffer, 2 * dataLength); out_uint8a(out, buffer, 2 * dataLength);
} }
else else
{ {
out_uint8p(out, reader, dataLength); out_uint8a(out, reader, dataLength);
} }
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
@ -641,7 +639,7 @@ static void
inReaderName(PMEM_HANDLE * handle, STREAM in, char **destination, RD_BOOL wide) inReaderName(PMEM_HANDLE * handle, STREAM in, char **destination, RD_BOOL wide)
{ {
SERVER_DWORD dataLength; SERVER_DWORD dataLength;
in->p += 0x08; in_uint8s(in, 0x08);
in_uint32_le(in, dataLength); in_uint32_le(in, dataLength);
inRepos(in, inString(handle, in, destination, dataLength, wide)); 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, 0x00000004);
out_uint32_le(out, hContext); out_uint32_le(out, hContext);
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
return rv; return rv;
} }
@ -729,7 +728,7 @@ TS_SCardReleaseContext(STREAM in, STREAM out)
MYPCSC_SCARDCONTEXT myHContext; MYPCSC_SCARDCONTEXT myHContext;
SERVER_SCARDCONTEXT hContext; SERVER_SCARDCONTEXT hContext;
in->p += 0x1C; in_uint8s(in, 0x1C);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
myHContext = _scard_handle_list_get_pcsc_handle(hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext);
@ -754,6 +753,7 @@ TS_SCardReleaseContext(STREAM in, STREAM out)
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
return rv; return rv;
} }
@ -764,7 +764,7 @@ TS_SCardIsValidContext(STREAM in, STREAM out)
SERVER_SCARDCONTEXT hContext; SERVER_SCARDCONTEXT hContext;
MYPCSC_SCARDCONTEXT myHContext; MYPCSC_SCARDCONTEXT myHContext;
in->p += 0x1C; in_uint8s(in, 0x1C);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
myHContext = _scard_handle_list_get_pcsc_handle(hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext);
@ -788,6 +788,7 @@ TS_SCardIsValidContext(STREAM in, STREAM out)
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
return rv; return rv;
} }
@ -801,21 +802,21 @@ TS_SCardListReaders(STREAM in, STREAM out, RD_BOOL wide)
MYPCSC_SCARDCONTEXT myHContext; MYPCSC_SCARDCONTEXT myHContext;
SERVER_DWORD dataLength; SERVER_DWORD dataLength;
MYPCSC_DWORD cchReaders = readerArraySize; MYPCSC_DWORD cchReaders = readerArraySize;
unsigned char *plen1, *plen2, *pend; size_t plen1, plen2, pend;
char *readers, *cur; char *readers, *cur;
PMEM_HANDLE lcHandle = NULL; PMEM_HANDLE lcHandle = NULL;
in->p += 0x2C; in_uint8s(in, 0x2C);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
myHContext = _scard_handle_list_get_pcsc_handle(hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext);
logger(SmartCard, Debug, "TS_SCardListReaders(), context: 0x%08x [0x%lx])", logger(SmartCard, Debug, "TS_SCardListReaders(), context: 0x%08x [0x%lx])",
(unsigned) hContext, myHContext); (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, 0x00000000); /* Temp value for data length as 0x0 */
out_uint32_le(out, 0x01760650); out_uint32_le(out, 0x01760650);
plen2 = out->p; plen2 = s_tell(out);
out_uint32_le(out, 0x00000000); /* Temp value for data length as 0x0 */ out_uint32_le(out, 0x00000000); /* Temp value for data length as 0x0 */
dataLength = 0; dataLength = 0;
@ -865,14 +866,17 @@ TS_SCardListReaders(STREAM in, STREAM out, RD_BOOL wide)
dataLength += outString(out, "\0", wide); dataLength += outString(out, "\0", wide);
outRepos(out, dataLength); outRepos(out, dataLength);
pend = out->p; s_mark_end(out);
out->p = plen1;
pend = s_tell(out);
s_seek(out, plen1);
out_uint32_le(out, dataLength); out_uint32_le(out, dataLength);
out->p = plen2; s_seek(out, plen2);
out_uint32_le(out, dataLength); out_uint32_le(out, dataLength);
out->p = pend; s_seek(out, pend);
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -893,11 +897,11 @@ TS_SCardConnect(STREAM in, STREAM out, RD_BOOL wide)
MYPCSC_DWORD dwActiveProtocol; MYPCSC_DWORD dwActiveProtocol;
PMEM_HANDLE lcHandle = NULL; PMEM_HANDLE lcHandle = NULL;
in->p += 0x1C; in_uint8s(in, 0x1C);
in_uint32_le(in, dwShareMode); in_uint32_le(in, dwShareMode);
in_uint32_le(in, dwPreferredProtocol); in_uint32_le(in, dwPreferredProtocol);
inReaderName(&lcHandle, in, &szReader, wide); inReaderName(&lcHandle, in, &szReader, wide);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
myHContext = _scard_handle_list_get_pcsc_handle(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); out_uint32_le(out, hCard);
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -984,13 +989,13 @@ TS_SCardReconnect(STREAM in, STREAM out)
SERVER_DWORD dwInitialization; SERVER_DWORD dwInitialization;
MYPCSC_DWORD dwActiveProtocol; MYPCSC_DWORD dwActiveProtocol;
in->p += 0x20; in_uint8s(in, 0x20);
in_uint32_le(in, dwShareMode); in_uint32_le(in, dwShareMode);
in_uint32_le(in, dwPreferredProtocol); in_uint32_le(in, dwPreferredProtocol);
in_uint32_le(in, dwInitialization); in_uint32_le(in, dwInitialization);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
@ -1016,6 +1021,7 @@ TS_SCardReconnect(STREAM in, STREAM out)
out_uint32_le(out, (SERVER_DWORD) dwActiveProtocol); out_uint32_le(out, (SERVER_DWORD) dwActiveProtocol);
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
return rv; return rv;
} }
@ -1029,11 +1035,11 @@ TS_SCardDisconnect(STREAM in, STREAM out)
MYPCSC_SCARDHANDLE myHCard; MYPCSC_SCARDHANDLE myHCard;
SERVER_DWORD dwDisposition; SERVER_DWORD dwDisposition;
in->p += 0x20; in_uint8s(in, 0x20);
in_uint32_le(in, dwDisposition); in_uint32_le(in, dwDisposition);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
myHContext = _scard_handle_list_get_pcsc_handle(hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext);
@ -1078,6 +1084,7 @@ TS_SCardDisconnect(STREAM in, STREAM out)
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
return rv; return rv;
} }
@ -1164,12 +1171,12 @@ TS_SCardGetStatusChange(STREAM in, STREAM out, RD_BOOL wide)
long i; long i;
PMEM_HANDLE lcHandle = NULL; PMEM_HANDLE lcHandle = NULL;
in->p += 0x18; in_uint8s(in, 0x18);
in_uint32_le(in, dwTimeout); in_uint32_le(in, dwTimeout);
in_uint32_le(in, dwCount); in_uint32_le(in, dwCount);
in->p += 0x08; in_uint8s(in, 0x08);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
in->p += 0x04; in_uint8s(in, 0x04);
myHContext = _scard_handle_list_get_pcsc_handle(hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext);
@ -1199,7 +1206,7 @@ TS_SCardGetStatusChange(STREAM in, STREAM out, RD_BOOL wide)
{ {
SERVER_DWORD dataLength; SERVER_DWORD dataLength;
in->p += 0x08; in_uint8s(in, 0x08);
in_uint32_le(in, dataLength); in_uint32_le(in, dataLength);
inRepos(in, inRepos(in,
inString(&lcHandle, in, (char **) &(cur->szReader), 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->dwEventState = swap32(cur->dwEventState);
cur->cbAtr = swap32(cur->cbAtr); 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 *)); sizeof(SERVER_SCARD_READERSTATE_A) - 2 * sizeof(unsigned char *));
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -1272,7 +1280,7 @@ TS_SCardCancel(STREAM in, STREAM out)
SERVER_SCARDCONTEXT hContext; SERVER_SCARDCONTEXT hContext;
MYPCSC_SCARDCONTEXT myHContext; MYPCSC_SCARDCONTEXT myHContext;
in->p += 0x1C; in_uint8s(in, 0x1C);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
myHContext = _scard_handle_list_get_pcsc_handle(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"); logger(SmartCard, Debug, "TS_SCardCancel(), success");
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
return rv; return rv;
} }
@ -1311,7 +1320,7 @@ TS_SCardLocateCardsByATR(STREAM in, STREAM out, RD_BOOL wide)
MYPCSC_LPSCARD_READERSTATE_A myRsArray; MYPCSC_LPSCARD_READERSTATE_A myRsArray;
PMEM_HANDLE lcHandle = NULL; PMEM_HANDLE lcHandle = NULL;
in->p += 0x2C; in_uint8s(in, 0x2C);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
in_uint32_le(in, atrMaskCount); in_uint32_le(in, atrMaskCount);
pAtrMasks = SC_xmalloc(&lcHandle, atrMaskCount * sizeof(SCARD_ATRMASK_L)); 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->dwEventState = swap32(rsCur->dwEventState);
rsCur->cbAtr = swap32(rsCur->cbAtr); 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 *)); sizeof(SCARD_READERSTATE) - 2 * sizeof(unsigned char *));
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -1437,7 +1447,7 @@ TS_SCardBeginTransaction(STREAM in, STREAM out)
SERVER_SCARDCONTEXT hCard; SERVER_SCARDCONTEXT hCard;
MYPCSC_SCARDCONTEXT myHCard; MYPCSC_SCARDCONTEXT myHCard;
in->p += 0x30; in_uint8s(in, 0x30);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
myHCard = _scard_handle_list_get_pcsc_handle(hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard);
logger(SmartCard, Debug, "TS_SCardBeginTransaction(), hcard: 0x%08x [0x%lx])", 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"); logger(SmartCard, Debug, "TS_SCardBeginTransaction(), success");
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
return rv; return rv;
} }
@ -1464,9 +1475,9 @@ TS_SCardEndTransaction(STREAM in, STREAM out)
MYPCSC_SCARDCONTEXT myHCard; MYPCSC_SCARDCONTEXT myHCard;
SERVER_DWORD dwDisposition = 0; SERVER_DWORD dwDisposition = 0;
in->p += 0x20; in_uint8s(in, 0x20);
in_uint32_le(in, dwDisposition); in_uint32_le(in, dwDisposition);
in->p += 0x0C; in_uint8s(in, 0x0C);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
myHCard = _scard_handle_list_get_pcsc_handle(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"); logger(SmartCard, Debug, "TS_SCardEndTransaction(), success");
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
return rv; return rv;
} }
@ -1533,9 +1545,9 @@ TS_SCardTransmit(STREAM in, STREAM out, uint32 srv_buf_len)
PMEM_HANDLE lcHandle = NULL; PMEM_HANDLE lcHandle = NULL;
in->p += 0x14; in_uint8s(in, 0x14);
in_uint32_le(in, map[0]); in_uint32_le(in, map[0]);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, map[1]); in_uint32_le(in, map[1]);
pioSendPci = SC_xmalloc(&lcHandle, sizeof(SERVER_SCARD_IO_REQUEST)); pioSendPci = SC_xmalloc(&lcHandle, sizeof(SERVER_SCARD_IO_REQUEST));
if (!pioSendPci) if (!pioSendPci)
@ -1553,7 +1565,7 @@ TS_SCardTransmit(STREAM in, STREAM out, uint32 srv_buf_len)
if (srv_buf_len <= cbRecvLength) if (srv_buf_len <= cbRecvLength)
cbRecvLength = srv_buf_len; cbRecvLength = srv_buf_len;
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
myHCard = _scard_handle_list_get_pcsc_handle(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); outBufferFinish(out, (char *) recvBuf, cbRecvLength);
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -1714,12 +1727,12 @@ TS_SCardStatus(STREAM in, STREAM out, RD_BOOL wide)
char *readerName; char *readerName;
unsigned char *atr; unsigned char *atr;
in->p += 0x24; in_uint8s(in, 0x24);
in_uint32_le(in, dwReaderLen); in_uint32_le(in, dwReaderLen);
in_uint32_le(in, dwAtrLen); in_uint32_le(in, dwAtrLen);
in->p += 0x0C; in_uint8s(in, 0x0C);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
in->p += 0x04; in_uint8s(in, 0x04);
myHCard = _scard_handle_list_get_pcsc_handle(hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard);
logger(SmartCard, Debug, logger(SmartCard, Debug,
"TS_SCardStatus(), hcard: 0x%08x [0x%08lx], reader len: %d bytes, atr len: %d bytes", "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 else
dwState = 0x00000000; dwState = 0x00000000;
void *p_len1 = out->p; size_t p_len1 = s_tell(out);
out_uint32_le(out, dwReaderLen); out_uint32_le(out, dwReaderLen);
out_uint32_le(out, 0x00020000); out_uint32_le(out, 0x00020000);
out_uint32_le(out, dwState); out_uint32_le(out, dwState);
out_uint32_le(out, dwProtocol); out_uint32_le(out, dwProtocol);
out_uint8p(out, atr, dwAtrLen); out_uint8a(out, atr, dwAtrLen);
if (dwAtrLen < 32) if (dwAtrLen < 32)
{ {
out_uint8s(out, 32 - dwAtrLen); out_uint8s(out, 32 - dwAtrLen);
} }
out_uint32_le(out, dwAtrLen); out_uint32_le(out, dwAtrLen);
void *p_len2 = out->p; size_t p_len2 = s_tell(out);
out_uint32_le(out, dwReaderLen); out_uint32_le(out, dwReaderLen);
dataLength = outString(out, readerName, wide); dataLength = outString(out, readerName, wide);
dataLength += outString(out, "\0", wide); dataLength += outString(out, "\0", wide);
outRepos(out, dataLength); outRepos(out, dataLength);
void *psave = out->p; s_mark_end(out);
out->p = p_len1; size_t psave = s_tell(out);
s_seek(out, p_len1);
out_uint32_le(out, dataLength); out_uint32_le(out, dataLength);
out->p = p_len2; s_seek(out, p_len2);
out_uint32_le(out, dataLength); out_uint32_le(out, dataLength);
out->p = psave; s_seek(out, psave);
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -1833,11 +1848,11 @@ TS_SCardState(STREAM in, STREAM out)
char *readerName; char *readerName;
unsigned char *atr; unsigned char *atr;
in->p += 0x24; in_uint8s(in, 0x24);
in_uint32_le(in, dwAtrLen); in_uint32_le(in, dwAtrLen);
in->p += 0x0C; in_uint8s(in, 0x0C);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
in->p += 0x04; in_uint8s(in, 0x04);
myHCard = _scard_handle_list_get_pcsc_handle(hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard);
logger(SmartCard, Debug, "TS_SCardState(), hcard: 0x%08x [0x%08lx], atrlen: %d bytes", 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, dwAtrLen);
out_uint32_le(out, 0x00000001); out_uint32_le(out, 0x00000001);
out_uint32_le(out, dwAtrLen); out_uint32_le(out, dwAtrLen);
out_uint8p(out, atr, dwAtrLen); out_uint8a(out, atr, dwAtrLen);
outRepos(out, dwAtrLen); outRepos(out, dwAtrLen);
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -1928,9 +1944,9 @@ TS_SCardListReaderGroups(STREAM in, STREAM out)
char *szGroups; char *szGroups;
PMEM_HANDLE lcHandle = NULL; PMEM_HANDLE lcHandle = NULL;
in->p += 0x20; in_uint8s(in, 0x20);
in_uint32_le(in, dwGroups); in_uint32_le(in, dwGroups);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
myHContext = _scard_handle_list_get_pcsc_handle(hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext);
@ -1976,6 +1992,7 @@ TS_SCardListReaderGroups(STREAM in, STREAM out)
out_uint32_le(out, 0x00000000); out_uint32_le(out, 0x00000000);
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -1992,11 +2009,11 @@ TS_SCardGetAttrib(STREAM in, STREAM out)
unsigned char *pbAttr; unsigned char *pbAttr;
PMEM_HANDLE lcHandle = NULL; PMEM_HANDLE lcHandle = NULL;
in->p += 0x20; in_uint8s(in, 0x20);
in_uint32_le(in, dwAttrId); in_uint32_le(in, dwAttrId);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, dwAttrLen); in_uint32_le(in, dwAttrLen);
in->p += 0x0C; in_uint8s(in, 0x0C);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
myHCard = _scard_handle_list_get_pcsc_handle(hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard);
@ -2040,12 +2057,13 @@ TS_SCardGetAttrib(STREAM in, STREAM out)
} }
else else
{ {
out_uint8p(out, pbAttr, dwAttrLen); out_uint8a(out, pbAttr, dwAttrLen);
} }
outRepos(out, dwAttrLen); outRepos(out, dwAttrLen);
out_uint32_le(out, 0x00000000); out_uint32_le(out, 0x00000000);
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
return rv; return rv;
} }
@ -2062,11 +2080,11 @@ TS_SCardSetAttrib(STREAM in, STREAM out)
unsigned char *pbAttr; unsigned char *pbAttr;
PMEM_HANDLE lcHandle = NULL; PMEM_HANDLE lcHandle = NULL;
in->p += 0x20; in_uint8s(in, 0x20);
in_uint32_le(in, dwAttrId); in_uint32_le(in, dwAttrId);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, dwAttrLen); in_uint32_le(in, dwAttrLen);
in->p += 0x0C; in_uint8s(in, 0x0C);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
myHCard = scHandleToMyPCSC(hCard); myHCard = scHandleToMyPCSC(hCard);
@ -2100,6 +2118,7 @@ TS_SCardSetAttrib(STREAM in, STREAM out)
out_uint32_le(out, 0x00000000); out_uint32_le(out, 0x00000000);
out_uint32_le(out, 0x00000000); out_uint32_le(out, 0x00000000);
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -2125,18 +2144,18 @@ TS_SCardControl(STREAM in, STREAM out)
pInBuffer = NULL; pInBuffer = NULL;
pOutBuffer = NULL; pOutBuffer = NULL;
in->p += 0x14; in_uint8s(in, 0x14);
in_uint32_le(in, map[0]); in_uint32_le(in, map[0]);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, map[1]); in_uint32_le(in, map[1]);
in_uint32_le(in, dwControlCode); in_uint32_le(in, dwControlCode);
in_uint32_le(in, nInBufferSize); in_uint32_le(in, nInBufferSize);
in_uint32_le(in, map[2]); in_uint32_le(in, map[2]);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, nOutBufferSize); in_uint32_le(in, nOutBufferSize);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, hContext); in_uint32_le(in, hContext);
in->p += 0x04; in_uint8s(in, 0x04);
in_uint32_le(in, hCard); in_uint32_le(in, hCard);
if (map[2] & INPUT_LINKED) if (map[2] & INPUT_LINKED)
{ {
@ -2238,11 +2257,12 @@ TS_SCardControl(STREAM in, STREAM out)
out_uint32_le(out, nBytesReturned); out_uint32_le(out, nBytesReturned);
if (nBytesReturned > 0) if (nBytesReturned > 0)
{ {
out_uint8p(out, pOutBuffer, nBytesReturned); out_uint8a(out, pOutBuffer, nBytesReturned);
outRepos(out, nBytesReturned); outRepos(out, nBytesReturned);
} }
outForceAlignment(out, 8); outForceAlignment(out, 8);
s_mark_end(out);
SC_xfreeallmemory(&lcHandle); SC_xfreeallmemory(&lcHandle);
return rv; return rv;
} }
@ -2262,7 +2282,7 @@ scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out,
{ {
UNUSED(handle); UNUSED(handle);
SERVER_DWORD Result = 0x00000000; SERVER_DWORD Result = 0x00000000;
unsigned char *psize, *pend, *pStatusCode; size_t psize, pend, pStatusCode;
SERVER_DWORD addToEnd = 0; SERVER_DWORD addToEnd = 0;
/* Processing request */ /* 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) */ /* Set CommonTypeHeader (MS-RPCE 2.2.6.1) */
out_uint32_le(out, 0x00081001); /* Header lines */ out_uint32_le(out, 0x00081001); /* Header lines */
out_uint32_le(out, 0xCCCCCCCC); out_uint32_le(out, 0xCCCCCCCC);
psize = out->p; psize = s_tell(out);
/* Set PrivateTypeHeader (MS-RPCE 2.2.6.2) */ /* Set PrivateTypeHeader (MS-RPCE 2.2.6.2) */
out_uint32_le(out, 0x00000000); /* Size of data portion */ out_uint32_le(out, 0x00000000); /* Size of data portion */
out_uint32_le(out, 0x00000000); /* Zero bytes (may be useful) */ out_uint32_le(out, 0x00000000); /* Zero bytes (may be useful) */
pStatusCode = out->p; pStatusCode = s_tell(out);
out_uint32_le(out, 0x00000000); /* Status Code */ out_uint32_le(out, 0x00000000); /* Status Code */
switch (request) switch (request)
@ -2412,22 +2432,25 @@ scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out,
#if 0 #if 0
out_uint32_le(out, 0x00000000); out_uint32_le(out, 0x00000000);
#endif #endif
s_mark_end(out);
/* Setting modified variables */ /* Setting modified variables */
pend = out->p; pend = s_tell(out);
/* setting data size */ /* setting data size */
out->p = psize; s_seek(out, psize);
out_uint32_le(out, pend - psize - 16); out_uint32_le(out, pend - psize - 16);
/* setting status code */ /* setting status code */
out->p = pStatusCode; s_seek(out, pStatusCode);
out_uint32_le(out, Result); out_uint32_le(out, Result);
/* finish */ /* 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) */ /* TODO: Check MS-RPCE 2.2.6.2 for alignment requirements (IIRC length must be integral multiple of 8) */
addToEnd = (pend - pStatusCode) % 16; addToEnd = (pend - pStatusCode) % 16;
if (addToEnd < 16 && addToEnd > 0) if (addToEnd < 16 && addToEnd > 0)
{ {
out_uint8s(out, addToEnd); out_uint8s(out, addToEnd);
s_mark_end(out);
} }
if (Result == SCARD_E_INSUFFICIENT_BUFFER) return RD_STATUS_BUFFER_TOO_SMALL; 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 static STREAM
duplicateStream(PMEM_HANDLE * handle, STREAM s, uint32 buffer_size, RD_BOOL isInputStream) 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)); STREAM d = SC_xmalloc(handle, sizeof(struct stream));
if (d != NULL) if (d != NULL)
{ {
@ -2575,13 +2599,18 @@ SC_deviceControl(PSCThreadData data)
RD_NTSTATUS status; RD_NTSTATUS status;
size_t buffer_len = 0; size_t buffer_len = 0;
status = scard_device_control(data->handle, data->request, data->in, data->out, data->srv_buf_len); 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 /* if iorequest belongs to another epoch, don't send response
back to server due to it's considered as abandoned. back to server due to it's considered as abandoned.
*/ */
if (data->epoch == curEpoch) 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); SC_destroyThreadData(data);
} }

View File

@ -376,17 +376,12 @@ seamless_process(STREAM s)
{ {
unsigned int pkglen; unsigned int pkglen;
char *buf; char *buf;
struct stream packet = *s;
if (!s_check(s)) pkglen = s_remaining(s);
{
rdp_protocol_error("seamless_process(), stream is in unstable state", &packet);
}
pkglen = s->end - s->p;
/* str_handle_lines requires null terminated strings */ /* str_handle_lines requires null terminated strings */
buf = xmalloc(pkglen + 1); 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); str_handle_lines(buf, &seamless_rest, seamless_line_handler, NULL);
xfree(buf); xfree(buf);
@ -446,11 +441,12 @@ seamless_send(const char *command, const char *format, ...)
len++; len++;
s = channel_init(seamless_channel, 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); logger(Core, Debug, "seamless_send(), sending '%s'", buf);
channel_send(s, seamless_channel); channel_send(s, seamless_channel);
s_free(s);
return seamless_serial++; return seamless_serial++;
} }

123
secure.c
View File

@ -351,10 +351,12 @@ sec_send_to_channel(STREAM s, uint32 flags, uint16 channel)
if (flags & SEC_ENCRYPT) if (flags & SEC_ENCRYPT)
{ {
unsigned char *data;
flags &= ~SEC_ENCRYPT; flags &= ~SEC_ENCRYPT;
datalen = s->end - s->p - 8; datalen = s_remaining(s) - 8;
sec_sign(s->p, 8, g_sec_sign_key, g_rc4_key_len, s->p + 8, datalen); inout_uint8p(s, data, datalen + 8);
sec_encrypt(s->p + 8, datalen); 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); mcs_send_to_channel(s, channel);
@ -384,11 +386,12 @@ sec_establish_key(void)
s = sec_init(flags, length + 4); s = sec_init(flags, length + 4);
out_uint32_le(s, length); 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); out_uint8s(s, SEC_PADDING_SIZE);
s_mark_end(s); s_mark_end(s);
sec_send(s, flags); sec_send(s, flags);
s_free(s);
} }
/* Output connect initial data blob */ /* Output connect initial data blob */
@ -523,6 +526,10 @@ sec_parse_public_key(STREAM s, uint8 * modulus, uint8 * exponent)
{ {
uint32 magic, modulus_len; uint32 magic, modulus_len;
if (!s_check_rem(s, 8)) {
return False;
}
in_uint32_le(s, magic); in_uint32_le(s, magic);
if (magic != SEC_RSA_MAGIC) if (magic != SEC_RSA_MAGIC)
{ {
@ -541,13 +548,17 @@ sec_parse_public_key(STREAM s, uint8 * modulus, uint8 * exponent)
return False; 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_uint8s(s, 8); /* modulus_bits, unknown */
in_uint8a(s, exponent, SEC_EXPONENT_SIZE); in_uint8a(s, exponent, SEC_EXPONENT_SIZE);
in_uint8a(s, modulus, modulus_len); in_uint8a(s, modulus, modulus_len);
in_uint8s(s, SEC_PADDING_SIZE); in_uint8s(s, SEC_PADDING_SIZE);
g_server_public_key_len = modulus_len; g_server_public_key_len = modulus_len;
return s_check(s); return True;
} }
/* Parse a public signature structure */ /* 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_CERT *cacert, *server_cert;
RDSSL_RKEY *server_public_key; RDSSL_RKEY *server_public_key;
uint16 tag, length; uint16 tag, length;
uint8 *next_tag, *end; size_t next_tag;
logger(Protocol, Debug, "%s()", __func__); 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); in_uint8p(s, *server_random, random_len);
/* RSA info */ /* RSA info */
end = s->p + rsa_info_len; if (!s_check_rem(s, rsa_info_len))
if (end > s->end)
{ {
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; 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"); "sec_parse_crypt_info(), We're going for the RDP4-style encryption");
in_uint8s(s, 8); /* unknown */ in_uint8s(s, 8); /* unknown */
while (s->p < end) while (!s_check_end(s))
{ {
in_uint16_le(s, tag); in_uint16_le(s, tag);
in_uint16_le(s, length); in_uint16_le(s, length);
next_tag = s->p + length; next_tag = s_tell(s) + length;
switch (tag) switch (tag)
{ {
@ -654,12 +664,13 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
tag); tag);
} }
s->p = next_tag; s_seek(s, next_tag);
} }
} }
else else
{ {
uint32 certcount; uint32 certcount;
unsigned char *certdata;
logger(Protocol, Debug, logger(Protocol, Debug,
"sec_parse_crypt_info(), We're going for the RDP5-style encryption"); "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 */ { /* ignore all the certificates between the root and the signing CA */
uint32 ignorelen; uint32 ignorelen;
RDSSL_CERT *ignorecert; RDSSL_CERT *ignorecert;
unsigned char *ignoredata;
in_uint32_le(s, ignorelen); in_uint32_le(s, ignorelen);
ignorecert = rdssl_cert_read(s->p, ignorelen); in_uint8p(s, ignoredata, ignorelen);
in_uint8s(s, ignorelen); ignorecert = rdssl_cert_read(ignoredata, ignorelen);
if (ignorecert == NULL) if (ignorecert == NULL)
{ /* XXX: error out? */ { /* XXX: error out? */
logger(Protocol, Error, 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 http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
*/ */
in_uint32_le(s, cacert_len); in_uint32_le(s, cacert_len);
in_uint8p(s, certdata, cacert_len);
logger(Protocol, Debug, logger(Protocol, Debug,
"sec_parse_crypt_info(), server CA Certificate length is %d", cacert_len); "sec_parse_crypt_info(), server CA Certificate length is %d", cacert_len);
cacert = rdssl_cert_read(s->p, cacert_len); cacert = rdssl_cert_read(certdata, cacert_len);
in_uint8s(s, cacert_len);
if (NULL == cacert) if (NULL == cacert)
{ {
logger(Protocol, Error, logger(Protocol, Error,
@ -708,10 +720,10 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
return False; return False;
} }
in_uint32_le(s, cert_len); in_uint32_le(s, cert_len);
in_uint8p(s, certdata, cert_len);
logger(Protocol, Debug, "sec_parse_crypt_info(), certificate length is %d", logger(Protocol, Debug, "sec_parse_crypt_info(), certificate length is %d",
cert_len); cert_len);
server_cert = rdssl_cert_read(s->p, cert_len); server_cert = rdssl_cert_read(certdata, cert_len);
in_uint8s(s, cert_len);
if (NULL == server_cert) if (NULL == server_cert)
{ {
rdssl_cert_free(cacert); rdssl_cert_free(cacert);
@ -805,7 +817,7 @@ void
sec_process_mcs_data(STREAM s) sec_process_mcs_data(STREAM s)
{ {
uint16 tag, length; uint16 tag, length;
uint8 *next_tag; size_t next_tag;
uint8 len; uint8 len;
in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */ in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */
@ -814,7 +826,7 @@ sec_process_mcs_data(STREAM s)
in_uint8(s, len); in_uint8(s, len);
logger(Protocol, Debug, "%s()", __func__); logger(Protocol, Debug, "%s()", __func__);
while (s->p < s->end) while (!s_check_end(s))
{ {
in_uint16_le(s, tag); in_uint16_le(s, tag);
in_uint16_le(s, length); in_uint16_le(s, length);
@ -822,7 +834,7 @@ sec_process_mcs_data(STREAM s)
if (length <= 4) if (length <= 4)
return; return;
next_tag = s->p + length - 4; next_tag = s_tell(s) + length - 4;
switch (tag) switch (tag)
{ {
@ -847,7 +859,7 @@ sec_process_mcs_data(STREAM s)
logger(Protocol, Warning, "Unhandled response tag 0x%x", tag); 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; uint16 channel;
STREAM s; STREAM s;
struct stream packet; struct stream packet;
size_t data_offset;
unsigned char *data;
while ((s = mcs_recv(&channel, is_fastpath, &fastpath_hdr)) != NULL) 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 (fastpath_flags & FASTPATH_OUTPUT_ENCRYPTED)
{ {
if (!s_check_rem(s, 8)) { 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 */ 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; return s;
} }
if (g_encryption || (!g_licence_issued && !g_licence_error_result)) if (g_encryption || (!g_licence_issued && !g_licence_error_result))
{ {
data_offset = s_tell(s);
/* TS_SECURITY_HEADER */ /* TS_SECURITY_HEADER */
in_uint16_le(s, sec_flags); in_uint16_le(s, sec_flags);
in_uint8s(s, 2); /* skip sec_flags_hi */ in_uint8s(s, 2); /* skip sec_flags_hi */
if (g_encryption) if (g_encryption)
{ {
data_offset = s_tell(s);
if (sec_flags & SEC_ENCRYPT) if (sec_flags & SEC_ENCRYPT)
{ {
if (!s_check_rem(s, 8)) { 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 */ 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) if (sec_flags & SEC_LICENSE_PKT)
{ {
s_seek(s, data_offset);
licence_process(s); licence_process(s);
continue; continue;
} }
@ -911,14 +940,18 @@ sec_recv(RD_BOOL * is_fastpath)
uint8 swapbyte; uint8 swapbyte;
if (!s_check_rem(s, 8)) { 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 */ 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 */ /* 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. /* 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 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 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 use 04 00 as the PDU type, so after our swap this will look
like: XX YY 04 00 */ like: XX YY 04 00 */
swapbyte = s->p[0]; swapbyte = data[0];
s->p[0] = s->p[2]; data[0] = data[2];
s->p[2] = swapbyte; data[2] = swapbyte;
swapbyte = s->p[1]; swapbyte = data[1];
s->p[1] = s->p[3]; data[1] = data[3];
s->p[3] = swapbyte; data[3] = swapbyte;
swapbyte = s->p[2]; swapbyte = data[2];
s->p[2] = s->p[3]; data[2] = data[3];
s->p[3] = swapbyte; data[3] = swapbyte;
} }
} }
} }
@ -947,8 +980,9 @@ sec_recv(RD_BOOL * is_fastpath)
licence_process(s); licence_process(s);
continue; continue;
} }
s->p -= 4;
} }
s_seek(s, data_offset);
} }
if (channel != MCS_GLOBAL_CHANNEL) if (channel != MCS_GLOBAL_CHANNEL)
@ -968,25 +1002,24 @@ RD_BOOL
sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect) sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect)
{ {
uint32 selected_proto; uint32 selected_proto;
struct stream mcs_data; STREAM mcs_data;
/* Start a MCS connect sequence */ /* Start a MCS connect sequence */
if (!mcs_connect_start(server, username, domain, password, reconnect, &selected_proto)) if (!mcs_connect_start(server, username, domain, password, reconnect, &selected_proto))
return False; return False;
/* We exchange some RDP data during the MCS-Connect */ /* We exchange some RDP data during the MCS-Connect */
mcs_data.size = 512; mcs_data = s_alloc(512);
mcs_data.p = mcs_data.data = (uint8 *) xmalloc(mcs_data.size); sec_out_mcs_connect_initial_pdu(mcs_data, selected_proto);
sec_out_mcs_connect_initial_pdu(&mcs_data, selected_proto);
/* finalize the MCS connect sequence */ /* finalize the MCS connect sequence */
if (!mcs_connect_finalize(&mcs_data)) if (!mcs_connect_finalize(mcs_data))
return False; return False;
/* sec_process_mcs_data(&mcs_data); */ /* sec_process_mcs_data(&mcs_data); */
if (g_encryption) if (g_encryption)
sec_establish_key(); sec_establish_key();
xfree(mcs_data.data); s_free(mcs_data);
return True; return True;
} }

14
ssl.c
View File

@ -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); 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 void
rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus,
uint8 * exponent) uint8 * exponent)

View File

@ -25,6 +25,31 @@
extern char g_codepage[16]; 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 void
s_realloc(STREAM s, unsigned int size) s_realloc(STREAM s, unsigned int size)
{ {
@ -59,6 +84,8 @@ s_reset(STREAM s)
void void
s_free(STREAM s) s_free(STREAM s)
{ {
if (s == NULL)
return;
free(s->data); free(s->data);
free(s); free(s);
} }

118
stream.h
View File

@ -41,8 +41,15 @@ typedef struct stream
} }
*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); void s_realloc(STREAM s, unsigned int size);
/* Free STREAM object and its associated buffer */
void s_free(STREAM s); void s_free(STREAM s);
/* Reset all internal offsets, but keep the allocated size */
void s_reset(STREAM s); void s_reset(STREAM s);
void out_utf16s(STREAM s, const char *string); 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); 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; } #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; #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_mark_end(s) (s)->end = (s)->p;
#define s_check(s) ((s)->p <= (s)->end) /* Return current read offset in the STREAM */
#define s_check_rem(s,n) (s_check(s) && (n <= (s)->end - (s)->p)) #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) #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_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) #if defined(L_ENDIAN) && !defined(NEED_ALIGN)
#define in_uint16_le(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; } #define in_uint16_le(s,v) { s_assert_r(s, 2); v = *(uint16 *)((s)->p); (s)->p += 2; }
#define in_uint32_le(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; } #define in_uint32_le(s,v) { s_assert_r(s, 4); v = *(uint32 *)((s)->p); (s)->p += 4; }
#define in_uint64_le(s,v) { v = *(uint64 *)((s)->p); (s)->p += 8; } #define in_uint64_le(s,v) { s_assert_r(s, 8); v = *(uint64 *)((s)->p); (s)->p += 8; }
#define out_uint16_le(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; } #define out_uint16_le(s,v) { s_assert_w(s, 2); *(uint16 *)((s)->p) = v; (s)->p += 2; }
#define out_uint32_le(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; } #define out_uint32_le(s,v) { s_assert_w(s, 4); *(uint32 *)((s)->p) = v; (s)->p += 4; }
#define out_uint64_le(s,v) { *(uint64 *)((s)->p) = v; (s)->p += 8; } #define out_uint64_le(s,v) { s_assert_w(s, 8); *(uint64 *)((s)->p) = v; (s)->p += 8; }
#else #else
#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; } #define in_uint16_le(s,v) { s_assert_r(s, 2); v = *((s)->p++); v += *((s)->p++) << 8; }
#define in_uint32_le(s,v) { in_uint16_le(s,v) \ #define in_uint32_le(s,v) { s_assert_r(s, 4); in_uint16_le(s,v) \
v += *((s)->p++) << 16; v += *((s)->p++) << 24; } 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++) << 32; v += *((s)->p++) << 40; \
v += *((s)->p++) << 48; v += *((s)->p++) << 56; } 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_uint16_le(s,v) { s_assert_w(s, 2); *((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_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) { out_uint32_le(s, (v) & 0xffffffff); out_uint32_le(s, ((v) >> 32) & 0xffffffff); } #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 #endif
/* Read/write an unsigned integer in big-endian order */
#if defined(B_ENDIAN) && !defined(NEED_ALIGN) #if defined(B_ENDIAN) && !defined(NEED_ALIGN)
#define in_uint16_be(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; } #define in_uint16_be(s,v) { s_assert_r(s, 2); v = *(uint16 *)((s)->p); (s)->p += 2; }
#define in_uint32_be(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; } #define in_uint32_be(s,v) { s_assert_r(s, 4); v = *(uint32 *)((s)->p); (s)->p += 4; }
#define in_uint64_be(s,v) { v = *(uint64 *)((s)->p); (s)->p += 8; } #define in_uint64_be(s,v) { s_assert_r(s, 8); v = *(uint64 *)((s)->p); (s)->p += 8; }
#define out_uint16_be(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; } #define out_uint16_be(s,v) { s_assert_w(s, 2); *(uint16 *)((s)->p) = v; (s)->p += 2; }
#define out_uint32_be(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; } #define out_uint32_be(s,v) { s_assert_w(s, 4); *(uint32 *)((s)->p) = v; (s)->p += 4; }
#define out_uint64_be(s,v) { *(uint64 *)((s)->p) = v; (s)->p += 8; } #define out_uint64_be(s,v) { s_assert_w(s, 8); *(uint64 *)((s)->p) = v; (s)->p += 8; }
#define B_ENDIAN_PREFERRED #define B_ENDIAN_PREFERRED
#define in_uint16(s,v) in_uint16_be(s,v) #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) #define out_uint64(s,v) out_uint64_be(s,v)
#else #else
#define in_uint16_be(s,v) { v = *((s)->p++); next_be(s,v); } #define in_uint16_be(s,v) { s_assert_r(s, 2); 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_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) { in_uint32_be(s,v); next_be(s,v); next_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)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; } #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) { out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); } #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) { out_uint32_be(s, ((v) >> 32) & 0xffffffff); out_uint32_be(s, (v) & 0xffffffff); } #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 #endif
#ifndef B_ENDIAN_PREFERRED #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) #define out_uint64(s,v) out_uint64_le(s,v)
#endif #endif
#define in_uint8(s,v) v = *((s)->p++); /* Read a single unsigned byte in v from STREAM s */
#define in_uint8p(s,v,n) { v = (s)->p; (s)->p += n; } #define in_uint8(s,v) { s_assert_r(s, 1); v = *((s)->p++); }
#define in_uint8a(s,v,n) { memcpy(v,(s)->p,n); (s)->p += n; } /* Return a pointer in v to manually read n bytes from STREAM s */
#define in_uint8s(s,n) (s)->p += n; #define in_uint8p(s,v,n) { s_assert_r(s, n); v = (s)->p; (s)->p += n; }
#define in_skip(s,n) in_uint8s(s,n) /* Copy n bytes from STREAM s in to array v */
#define out_uint8(s,v) *((s)->p++) = v; #define in_uint8a(s,v,n) { s_assert_r(s, n); memcpy(v,(s)->p,n); (s)->p += n; }
#define out_uint8p(s,v,n) { memcpy((s)->p,v,n); (s)->p += n; } /* Skip reading n bytes in STREAM s */
#define out_uint8a(s,v,n) out_uint8p(s,v,n); #define in_uint8s(s,n) { s_assert_r(s, n); (s)->p += n; }
#define out_uint8s(s,n) { memset((s)->p,0,n); (s)->p += n; } /* Write a single unsigned byte from v to STREAM s */
#define out_stream(s, v) out_uint8p(s, (v)->data, s_length((v))) #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 */ #endif /* _STREAM_H */

122
tcp.c
View File

@ -58,12 +58,6 @@
#define INADDR_NONE ((unsigned long) -1) #define INADDR_NONE ((unsigned long) -1)
#endif #endif
#ifdef WITH_SCARD
#define STREAM_COUNT 8
#else
#define STREAM_COUNT 1
#endif
#ifdef IPv6 #ifdef IPv6
static struct addrinfo *g_server_address = NULL; static struct addrinfo *g_server_address = NULL;
#else #else
@ -75,7 +69,6 @@ static RD_BOOL g_ssl_initialized = False;
static int g_sock; static int g_sock;
static RD_BOOL g_run_ui = False; static RD_BOOL g_run_ui = False;
static struct stream g_in; static struct stream g_in;
static struct stream g_out[STREAM_COUNT];
int g_tcp_port_rdp = TCP_PORT_RDP; int g_tcp_port_rdp = TCP_PORT_RDP;
extern RD_BOOL g_exit_mainloop; extern RD_BOOL g_exit_mainloop;
@ -109,28 +102,16 @@ tcp_can_send(int sck, int millis)
STREAM STREAM
tcp_init(uint32 maxlen) tcp_init(uint32 maxlen)
{ {
static int cur_stream_id = 0; return s_alloc(maxlen);
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;
} }
/* Send TCP transport data packet */ /* Send TCP transport data packet */
void void
tcp_send(STREAM s) tcp_send(STREAM s)
{ {
int length = s->end - s->data; size_t before;
int sent, total = 0; int length, sent;
unsigned char *data;
if (g_network_error == True) if (g_network_error == True)
return; return;
@ -139,10 +120,16 @@ tcp_send(STREAM s)
scard_lock(SCARD_LOCK_TCP); scard_lock(SCARD_LOCK_TCP);
#endif #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) { 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 (sent <= 0) {
if (gnutls_error_is_fatal(sent)) { if (gnutls_error_is_fatal(sent)) {
#ifdef WITH_SCARD #ifdef WITH_SCARD
@ -159,7 +146,7 @@ tcp_send(STREAM s)
} }
else else
{ {
sent = send(g_sock, s->data + total, length - total, 0); sent = send(g_sock, data, length, 0);
if (sent <= 0) if (sent <= 0)
{ {
if (sent == -1 && TCP_BLOCKS) 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 #ifdef WITH_SCARD
scard_unlock(SCARD_LOCK_TCP); scard_unlock(SCARD_LOCK_TCP);
@ -190,7 +179,8 @@ tcp_send(STREAM s)
STREAM STREAM
tcp_recv(STREAM s, uint32 length) tcp_recv(STREAM s, uint32 length)
{ {
uint32 new_length, end_offset, p_offset; size_t before;
unsigned char *data;
int rcvd = 0; int rcvd = 0;
if (g_network_error == True) if (g_network_error == True)
@ -199,27 +189,14 @@ tcp_recv(STREAM s, uint32 length)
if (s == NULL) if (s == NULL)
{ {
/* read into "new" stream */ /* read into "new" stream */
if (length > g_in.size) s_realloc(&g_in, length);
{ s_reset(&g_in);
g_in.data = (uint8 *) xrealloc(g_in.data, length);
g_in.size = length;
}
g_in.end = g_in.p = g_in.data;
s = &g_in; s = &g_in;
} }
else else
{ {
/* append to existing stream */ /* append to existing stream */
new_length = (s->end - s->data) + length; s_realloc(s, s_length(s) + 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;
}
} }
while (length > 0) while (length > 0)
@ -235,8 +212,15 @@ tcp_recv(STREAM s, uint32 length)
return NULL; 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) { 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 (rcvd < 0) {
if (gnutls_error_is_fatal(rcvd)) { if (gnutls_error_is_fatal(rcvd)) {
@ -251,7 +235,7 @@ tcp_recv(STREAM s, uint32 length)
} }
else else
{ {
rcvd = recv(g_sock, s->end, length, 0); rcvd = recv(g_sock, data, length, 0);
if (rcvd < 0) if (rcvd < 0)
{ {
if (rcvd == -1 && TCP_BLOCKS) 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; s->end += rcvd;
length -= rcvd; length -= rcvd;
} }
@ -349,9 +334,6 @@ tcp_tls_connect(void)
{ {
int err; int err;
int type;
int status;
gnutls_datum_t out;
gnutls_certificate_credentials_t xcred; gnutls_certificate_credentials_t xcred;
/* Initialize TLS session */ /* Initialize TLS session */
@ -422,8 +404,8 @@ fail:
} }
/* Get public key from server of TLS 1.x connection */ /* Get public key from server of TLS 1.x connection */
RD_BOOL STREAM
tcp_tls_get_server_pubkey(STREAM s) tcp_tls_get_server_pubkey()
{ {
int ret; int ret;
unsigned int list_size; unsigned int list_size;
@ -436,8 +418,7 @@ tcp_tls_get_server_pubkey(STREAM s)
int pk_size; int pk_size;
uint8_t pk_data[1024]; uint8_t pk_data[1024];
s->data = s->p = NULL; STREAM s = NULL;
s->size = 0;
cert_list = gnutls_certificate_get_peers(g_tls_session, &list_size); cert_list = gnutls_certificate_get_peers(g_tls_session, &list_size);
@ -489,11 +470,10 @@ tcp_tls_get_server_pubkey(STREAM s)
goto out; goto out;
} }
s->size = pk_size; s = s_alloc(pk_size);
s->data = s->p = xmalloc(s->size); out_uint8a(s, pk_data, pk_size);
memcpy((void *)s->data, (void *)pk_data, pk_size); s_mark_end(s);
s->p = s->data; s_seek(s, 0);
s->end = s->p + s->size;
out: out:
if ((e.size != 0) && (e.data)) { if ((e.size != 0) && (e.data)) {
@ -504,7 +484,7 @@ out:
free(m.data); free(m.data);
} }
return (s->size != 0); return s;
} }
/* Helper function to determine if rdesktop should resolve hostnames again or not */ /* Helper function to determine if rdesktop should resolve hostnames again or not */
@ -530,7 +510,6 @@ tcp_connect(char *server)
{ {
socklen_t option_len; socklen_t option_len;
uint32 option_value; uint32 option_value;
int i;
char buf[NI_MAXHOST]; char buf[NI_MAXHOST];
#ifdef IPv6 #ifdef IPv6
@ -681,12 +660,6 @@ tcp_connect(char *server)
g_in.size = 4096; g_in.size = 4096;
g_in.data = (uint8 *) xmalloc(g_in.size); 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 */ /* After successful connect: update the last server name */
if (g_last_server_name) if (g_last_server_name)
xfree(g_last_server_name); xfree(g_last_server_name);
@ -698,8 +671,6 @@ tcp_connect(char *server)
void void
tcp_disconnect(void) tcp_disconnect(void)
{ {
int i;
if (g_ssl_initialized) { if (g_ssl_initialized) {
(void)gnutls_bye(g_tls_session, GNUTLS_SHUT_WR); (void)gnutls_bye(g_tls_session, GNUTLS_SHUT_WR);
gnutls_deinit(g_tls_session); gnutls_deinit(g_tls_session);
@ -715,13 +686,6 @@ tcp_disconnect(void)
g_in.size = 0; g_in.size = 0;
xfree(g_in.data); xfree(g_in.data);
g_in.data = NULL; 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 * char *
@ -755,16 +719,8 @@ tcp_is_connected()
void void
tcp_reset_state(void) tcp_reset_state(void)
{ {
int i;
/* Clear the incoming stream */ /* Clear the incoming stream */
s_reset(&g_in); s_reset(&g_in);
/* Clear the outgoing stream(s) */
for (i = 0; i < STREAM_COUNT; i++)
{
s_reset(&g_out[i]);
}
} }
void void

View File

@ -46,23 +46,13 @@ xfree(void *mem)
free(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) Ensure(ASN1, can_create_empty_sequence)
{ {
struct stream *s, *empty; struct stream *s, *empty;
uint8_t expected_data[] = {0x30, 0x00}; uint8_t expected_data[] = {0x30, 0x00};
s = stream_new(100); s = s_alloc(100);
empty = stream_new(100); empty = s_alloc(100);
ber_out_sequence(s, empty); ber_out_sequence(s, empty);
s_mark_end(s); s_mark_end(s);
@ -76,7 +66,7 @@ Ensure(ASN1, can_create_empty_sequence_using_null)
struct stream *s; struct stream *s;
uint8_t expected_data[] = {0x30, 0x00}; uint8_t expected_data[] = {0x30, 0x00};
s = stream_new(100); s = s_alloc(100);
ber_out_sequence(s, NULL); ber_out_sequence(s, NULL);
s_mark_end(s); s_mark_end(s);
@ -90,8 +80,8 @@ Ensure(ASN1, can_create_sequence_of_two_integers)
struct stream *s, *content; struct stream *s, *content;
uint8_t expected_data[] = {0x30, 0x08, 0x02, 0x02, 0x00, 0xbe, 0x02, 0x02, 0x00, 0xef}; uint8_t expected_data[] = {0x30, 0x08, 0x02, 0x02, 0x00, 0xbe, 0x02, 0x02, 0x00, 0xef};
s = stream_new(100); s = s_alloc(100);
content = stream_new(100); content = s_alloc(100);
ber_out_integer(content, 0xbe); ber_out_integer(content, 0xbe);
ber_out_integer(content, 0xef); ber_out_integer(content, 0xef);
@ -109,8 +99,8 @@ Ensure(ASN1, can_create_sequence_of_one_integer)
struct stream *s, *content; struct stream *s, *content;
uint8_t expected_data[] = {0x30, 0x04, 0x02, 0x02, 0x00, 0xbe}; uint8_t expected_data[] = {0x30, 0x04, 0x02, 0x02, 0x00, 0xbe};
s = stream_new(100); s = s_alloc(100);
content = stream_new(100); content = s_alloc(100);
ber_out_integer(content, 0xbe); ber_out_integer(content, 0xbe);
s_mark_end(content); s_mark_end(content);

View File

@ -52,15 +52,6 @@ xfree(void *mem)
free(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 */ /* Test function */
Ensure(MCS, should_produce_valid_packet_for_McsSendCJrq) 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}; uint8_t content[] = {0x38, 0x00, 0x2A, 0x00, 0x0D};
struct stream *s; struct stream *s;
s = stream_new(5); s = s_alloc(5);
chan_id = 13; chan_id = 13;
g_mcs_userid = 42; g_mcs_userid = 42;
@ -89,7 +80,7 @@ Ensure(MCS, should_produce_valid_packet_for_McsSendDPU)
struct stream *s; struct stream *s;
uint8_t content[] = {0x30, 0x06, 0x02, 0x02, 0x00, reason, 0x30, 0x00}; uint8_t content[] = {0x30, 0x06, 0x02, 0x02, 0x00, reason, 0x30, 0x00};
s = stream_new(8); s = s_alloc(8);
expect(logger); expect(logger);
expect(iso_init, will_return(s)); expect(iso_init, will_return(s));

View File

@ -412,17 +412,6 @@ Ensure(Resize, UsingRDPEDISPHonoursServerSessionWidthConstraintMustBeEven)
free(s.data); 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) void get_width_and_height_from_mcs_connect_initial(int *width, int *height)
{ {
STREAM s; 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 */ /* Rewind and extract the requested session size */
s_reset(s); s_reset(s);
in_skip(s, 31); in_uint8s(s, 31);
in_uint16_le(s, *width); /* desktopWidth */ in_uint16_le(s, *width); /* desktopWidth */
in_uint16_le(s, *height); /* desktopHeight */ in_uint16_le(s, *height); /* desktopHeight */