Handle insufficient server side buffer for smartcard operations
We should pay attention to OutputBufferLength of DR_CONTROL_REQ and send STATUS_BUFFER_TOO_SMALL if it's insufficient for returned result.
This commit is contained in:
parent
d12204b424
commit
774a657975
11
channels.c
11
channels.c
@ -29,6 +29,8 @@
|
||||
extern RDP_VERSION g_rdp_version;
|
||||
extern RD_BOOL g_encryption;
|
||||
|
||||
uint32 vc_chunk_size = CHANNEL_CHUNK_LENGTH;
|
||||
|
||||
VCHANNEL g_channels[MAX_CHANNELS];
|
||||
unsigned int g_num_channels;
|
||||
|
||||
@ -95,11 +97,16 @@ channel_send(STREAM s, VCHANNEL * channel)
|
||||
logger(Protocol, Debug, "channel_send(), channel = %d, length = %d", channel->mcs_id,
|
||||
length);
|
||||
|
||||
thislength = MIN(length, CHANNEL_CHUNK_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
|
||||
in MS-RDPBCGR (s. 2.2.6, s.3.1.5.2.1) and can be set by server only
|
||||
in the optional field VCChunkSize of VC Caps) */
|
||||
|
||||
remaining = length - thislength;
|
||||
flags = (remaining == 0) ? CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST : CHANNEL_FLAG_FIRST;
|
||||
if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
|
||||
@ -114,7 +121,7 @@ channel_send(STREAM s, VCHANNEL * channel)
|
||||
/* subsequent segments copied (otherwise would have to generate headers backwards) */
|
||||
while (remaining > 0)
|
||||
{
|
||||
thislength = MIN(remaining, CHANNEL_CHUNK_LENGTH);
|
||||
thislength = MIN(remaining, vc_chunk_size);
|
||||
remaining -= thislength;
|
||||
flags = (remaining == 0) ? CHANNEL_FLAG_LAST : 0;
|
||||
if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
|
||||
|
@ -398,6 +398,9 @@ enum RDP_INPUT_DEVICE
|
||||
#define RDP_CAPSET_LARGE_POINTER 27
|
||||
#define RDP_CAPLEN_LARGE_POINTER 6
|
||||
|
||||
#define RDP_CAPSET_VC 20
|
||||
#define RDP_CAPLEN_VC 0x08
|
||||
|
||||
#define RDP_SOURCE "MSTSC"
|
||||
|
||||
/* Logon flags */
|
||||
@ -520,6 +523,7 @@ enum RDP_INPUT_DEVICE
|
||||
#define RD_STATUS_NO_SUCH_FILE 0xc000000f
|
||||
#define RD_STATUS_INVALID_DEVICE_REQUEST 0xc0000010
|
||||
#define RD_STATUS_ACCESS_DENIED 0xc0000022
|
||||
#define RD_STATUS_BUFFER_TOO_SMALL 0xc0000023
|
||||
#define RD_STATUS_OBJECT_NAME_COLLISION 0xc0000035
|
||||
#define RD_STATUS_DISK_FULL 0xc000007f
|
||||
#define RD_STATUS_FILE_IS_A_DIRECTORY 0xc00000ba
|
||||
|
37
rdp.c
37
rdp.c
@ -5,6 +5,7 @@
|
||||
Copyright 2003-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
|
||||
Copyright 2011-2018 Henrik Andersson <hean01@cendio.se> for Cendio AB
|
||||
Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB
|
||||
Copyright 2017 Alexander Zakharov <uglym8gmail.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -63,6 +64,8 @@ uint32 g_rdp_shareid;
|
||||
|
||||
extern RDPCOMP g_mppc_dict;
|
||||
|
||||
extern uint32 vc_chunk_size;
|
||||
|
||||
/* Session Directory support */
|
||||
extern RD_BOOL g_redirect;
|
||||
extern char *g_redirect_server;
|
||||
@ -926,6 +929,28 @@ rdp_out_brushcache_caps(STREAM s)
|
||||
out_uint32_le(s, 1); /* cache type */
|
||||
}
|
||||
|
||||
/* 2.2.7.1.10 MS-RDPBCGR */
|
||||
/* Output virtual channel capability set */
|
||||
static void
|
||||
rdp_out_virtchan_caps(STREAM s)
|
||||
{
|
||||
out_uint16_le(s, RDP_CAPSET_VC);
|
||||
out_uint16_le(s, RDP_CAPLEN_VC);
|
||||
/* VCCAPS_COMPR_SC */
|
||||
out_uint32_le(s, 0x00000001); /* compression flags */
|
||||
}
|
||||
|
||||
static void
|
||||
rdp_process_virtchan_caps(STREAM s)
|
||||
{
|
||||
uint32 flags, chunk_size;
|
||||
|
||||
in_uint32_le(s, flags);
|
||||
in_uint32_le(s, chunk_size);
|
||||
|
||||
vc_chunk_size = chunk_size;
|
||||
}
|
||||
|
||||
/* Output Input Capability Set */
|
||||
static void
|
||||
rdp_out_ts_input_capabilityset(STREAM s)
|
||||
@ -1043,7 +1068,8 @@ rdp_send_confirm_active(void)
|
||||
RDP_CAPLEN_SOUND +
|
||||
RDP_CAPLEN_GLYPHCACHE +
|
||||
RDP_CAPLEN_MULTIFRAGMENTUPDATE +
|
||||
RDP_CAPLEN_LARGE_POINTER + 4 /* w2k fix, sessionid */ ;
|
||||
RDP_CAPLEN_LARGE_POINTER +
|
||||
RDP_CAPLEN_VC + 4 /* w2k fix, sessionid */ ;
|
||||
|
||||
logger(Protocol, Debug, "%s()", __func__);
|
||||
|
||||
@ -1070,7 +1096,7 @@ rdp_send_confirm_active(void)
|
||||
out_uint16_le(s, caplen);
|
||||
|
||||
out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
|
||||
out_uint16_le(s, 16); /* num_caps */
|
||||
out_uint16_le(s, 17); /* num_caps */
|
||||
out_uint8s(s, 2); /* pad */
|
||||
|
||||
rdp_out_ts_general_capabilityset(s);
|
||||
@ -1091,6 +1117,7 @@ rdp_send_confirm_active(void)
|
||||
rdp_out_control_caps(s);
|
||||
rdp_out_share_caps(s);
|
||||
rdp_out_brushcache_caps(s);
|
||||
rdp_out_virtchan_caps(s);
|
||||
|
||||
rdp_out_ts_input_capabilityset(s);
|
||||
rdp_out_ts_sound_capabilityset(s);
|
||||
@ -1212,6 +1239,12 @@ rdp_process_server_caps(STREAM s, uint16 length)
|
||||
case RDP_CAPSET_BITMAP:
|
||||
rdp_process_bitmap_caps(s);
|
||||
break;
|
||||
case RDP_CAPSET_VC:
|
||||
/* Parse only if we got VCChunkSize */
|
||||
if (capset_length > 8) {
|
||||
rdp_process_virtchan_caps(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
s->p = next;
|
||||
|
53
rdpdr.c
53
rdpdr.c
@ -357,6 +357,50 @@ rdpdr_send_client_device_list_announce(void)
|
||||
channel_send(s, rdpdr_channel);
|
||||
}
|
||||
|
||||
void
|
||||
rdpdr_send_scard_io_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
|
||||
uint32 srv_buf_len)
|
||||
{
|
||||
int i;
|
||||
STREAM s;
|
||||
|
||||
#ifdef WITH_SCARD
|
||||
scard_lock(SCARD_LOCK_RDPDR);
|
||||
#endif
|
||||
|
||||
if (result > srv_buf_len) {
|
||||
/*
|
||||
* Not enough space has been allocated by server to store the result.
|
||||
* Send STATUS_BUFFER_TOO_SMALL error as a IoStatus.
|
||||
*/
|
||||
result = 0;
|
||||
status = RD_STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
s = channel_init(rdpdr_channel, 20 + result);
|
||||
out_uint16_le(s, RDPDR_CTYP_CORE);
|
||||
out_uint16_le(s, PAKID_CORE_DEVICE_IOCOMPLETION);
|
||||
out_uint32_le(s, device);
|
||||
out_uint32_le(s, id);
|
||||
|
||||
out_uint32_le(s, status);
|
||||
out_uint32_le(s, result);
|
||||
|
||||
if (result)
|
||||
out_uint8p(s, buffer, result);
|
||||
|
||||
s_mark_end(s);
|
||||
/* JIF */
|
||||
#ifdef WITH_DEBUG_RDP5
|
||||
printf("--> rdpdr_send_scard_io_completion\n");
|
||||
/* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
|
||||
#endif
|
||||
channel_send(s, rdpdr_channel);
|
||||
#ifdef WITH_SCARD
|
||||
scard_unlock(SCARD_LOCK_RDPDR);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
|
||||
uint32 length)
|
||||
@ -730,11 +774,15 @@ rdpdr_process_irp(STREAM s)
|
||||
break;
|
||||
}
|
||||
|
||||
/* DR_CONTROL_REQ (2.2.1.4.5 of MS-RDPEFS) */
|
||||
/* OutputBufferLength */
|
||||
in_uint32_le(s, bytes_out);
|
||||
in_uint8s(s, 4); /* skip bytes_in */
|
||||
in_uint32_le(s, request);
|
||||
/* Padding */
|
||||
in_uint8s(s, 0x14);
|
||||
|
||||
/* TODO: Why do we need to increase length by padlen? Or is it hdr len? */
|
||||
buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14);
|
||||
if (!buffer)
|
||||
{
|
||||
@ -743,7 +791,10 @@ rdpdr_process_irp(STREAM s)
|
||||
}
|
||||
|
||||
out.data = out.p = buffer;
|
||||
out.size = sizeof(buffer);
|
||||
/* Guess, just a simple mistype. Check others */
|
||||
//out.size = sizeof(buffer);
|
||||
out.size = bytes_out + 0x14;
|
||||
|
||||
|
||||
#ifdef WITH_SCARD
|
||||
scardSetInfo(g_epoch, device, id, bytes_out + 0x14);
|
||||
|
19
scard.c
19
scard.c
@ -1647,15 +1647,6 @@ TS_SCardTransmit(STREAM in, STREAM out)
|
||||
myPioRecvPci, recvBuf, &myCbRecvLength);
|
||||
cbRecvLength = myCbRecvLength;
|
||||
|
||||
/* FIXME: handle responses with length > 448 bytes */
|
||||
if (cbRecvLength > 448)
|
||||
{
|
||||
logger(SmartCard, Warning,
|
||||
"TS_SCardTransmit(), card response limit reached, %d truncated to 448 bytes",
|
||||
cbRecvLength);
|
||||
cbRecvLength = 448;
|
||||
}
|
||||
|
||||
if (pioRecvPci)
|
||||
{
|
||||
/*
|
||||
@ -2271,9 +2262,13 @@ scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out)
|
||||
|
||||
/* Processing request */
|
||||
|
||||
/* See MS-RSPESC 1.3 Overview for protocol flow */
|
||||
|
||||
/* Set CommonTypeHeader (MS-RPCE 2.2.6.1) */
|
||||
out_uint32_le(out, 0x00081001); /* Header lines */
|
||||
out_uint32_le(out, 0xCCCCCCCC);
|
||||
psize = out->p;
|
||||
/* Set PrivateTypeHeader (MS-RPCE 2.2.6.2) */
|
||||
out_uint32_le(out, 0x00000000); /* Size of data portion */
|
||||
out_uint32_le(out, 0x00000000); /* Zero bytes (may be useful) */
|
||||
pStatusCode = out->p;
|
||||
@ -2423,6 +2418,7 @@ scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out)
|
||||
/* finish */
|
||||
out->p = pend;
|
||||
|
||||
/* TODO: Check MS-RPCE 2.2.6.2 for alignment requirements (IIRC length must be integral multiple of 8) */
|
||||
addToEnd = (pend - pStatusCode) % 16;
|
||||
if (addToEnd < 16 && addToEnd > 0)
|
||||
{
|
||||
@ -2502,6 +2498,7 @@ SC_addToQueue(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out)
|
||||
data->epoch = curEpoch;
|
||||
data->handle = handle;
|
||||
data->request = request;
|
||||
data->srv_buf_len = curBytesOut - 0x14;
|
||||
data->in = duplicateStream(&(data->memHandle), in, 0, SC_TRUE);
|
||||
if (data->in == NULL)
|
||||
{
|
||||
@ -2576,8 +2573,8 @@ SC_deviceControl(PSCThreadData data)
|
||||
back to server due to it's considered as abandoned.
|
||||
*/
|
||||
if (data->epoch == curEpoch)
|
||||
rdpdr_send_completion(data->device, data->id, 0, buffer_len, data->out->data,
|
||||
buffer_len);
|
||||
rdpdr_send_scard_io_completion(data->device, data->id, 0, buffer_len, data->out->data,
|
||||
data->srv_buf_len);
|
||||
|
||||
SC_destroyThreadData(data);
|
||||
}
|
||||
|
1
scard.h
1
scard.h
@ -155,6 +155,7 @@ typedef struct _TSCThreadData
|
||||
uint32 device;
|
||||
uint32 id;
|
||||
uint32 epoch;
|
||||
uint32 srv_buf_len;
|
||||
RD_NTHANDLE handle;
|
||||
uint32 request;
|
||||
STREAM in;
|
||||
|
8
secure.c
8
secure.c
@ -435,8 +435,12 @@ sec_out_mcs_connect_initial_pdu(STREAM s, uint32 selected_protocol)
|
||||
out_uint16_le(s, g_requested_session_height); /* desktopHeight */
|
||||
out_uint16_le(s, RNS_UD_COLOR_8BPP); /* colorDepth */
|
||||
out_uint16_le(s, RNS_UD_SAS_DEL); /* SASSequence */
|
||||
out_uint32_le(s, g_keylayout); /* keyboardLayout */
|
||||
out_uint32_le(s, 2600); /* Client build. We are now 2600 compatible :-) */
|
||||
out_uint32_le(s, g_keylayout); /* keyboardLayout */
|
||||
/*
|
||||
* According to s.1.7 of MS-RDPESC if the build number is at least 4,304,
|
||||
* SCREDIR_VERSION_LONGHORN is assumed; otherwise SCREDIR_VERSIONXP is to be used
|
||||
*/
|
||||
out_uint32_le(s, 2600); /* Client build. We are now 2600 compatible :-) */
|
||||
|
||||
/* Unicode name of client, padded to 32 bytes */
|
||||
out_utf16s_padded(s, g_hostname, 32, 0x00);
|
||||
|
Loading…
Reference in New Issue
Block a user