Skip to content

Commit

Permalink
Fix message ordering in devredir
Browse files Browse the repository at this point in the history
The drive redirector is not compliant with the message ordering
in [MS-RDPEFS], causing FreeRDP 2.11.2 ro fail on redirecting drives.
  • Loading branch information
matt335672 committed Oct 26, 2023
1 parent b782340 commit 6500949
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 25 deletions.
5 changes: 5 additions & 0 deletions common/ms-rdpefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,10 @@ enum IRP_MN
IRP_MN_NOTIFY_CHANGE_DIRECTORY = 0x00000002
};

/*
* General Capability Set (2.2.2.7.1)
*/
/* extendedPDU fields */
#define RDPDR_USER_LOGGEDON_PDU 0x00000004

#endif /* MS_RDPEFS_H */
125 changes: 100 additions & 25 deletions sesman/chansrv/devredir.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,20 @@ enum COMPLETION_TYPE

/* globals */
extern int g_rdpdr_chan_id; /* in chansrv.c */
int g_is_printer_redir_supported = 0;
int g_is_port_redir_supported = 0;
int g_is_drive_redir_supported = 0;
int g_is_smartcard_redir_supported = 0;
int g_drive_redir_version = 1;

/* Capabilities from GENERAL_CAPS_SET in Client Core Capability Response */
struct client_caps
{
tui32 extended_pdu;
int printer_redir_supported;
int port_redir_supported;
int drive_redir_supported;
int smartcard_redir_supported;
unsigned int drive_redir_version;
};

static struct client_caps g_ccap;

tui32 g_completion_id = 1;

tui32 g_clientID; /* unique client ID - announced by client */
Expand Down Expand Up @@ -370,26 +379,38 @@ devredir_data_in(struct stream *s, int chan_id, int chan_flags, int length,
case RDP_CLIENT_60_61:
break;
}
// LK_TODO devredir_send_server_clientID_confirm();
}
break;

case PAKID_CORE_CLIENT_NAME:
/* client is telling us its computer name; do we even care? */

/* let client know login was successful */
devredir_send_server_user_logged_on();
usleep(1000 * 100);

/* let client know our capabilities */
devredir_send_server_core_cap_req();
/* See 3.3.5.1.6 for sequencing rules */
if (g_client_rdp_version >= RDP_CLIENT_51)
{
/* let client know our capabilities */
devredir_send_server_core_cap_req();
}

/* send confirm clientID */
devredir_send_server_clientID_confirm();
break;

case PAKID_CORE_CLIENT_CAPABILITY:
rv = devredir_proc_client_core_cap_resp(ls);
if (rv == 0)
{
if ((g_ccap.extended_pdu & RDPDR_USER_LOGGEDON_PDU) != 0)
{
/* Tell client to announce remaining devices */
devredir_send_server_user_logged_on();
}
else if (g_client_rdp_version >= RDP_CLIENT_51)
{
/* See 3.3.5.1.7 */
devredir_send_server_clientID_confirm();
}
}
break;

case PAKID_CORE_DEVICELIST_ANNOUNCE:
Expand Down Expand Up @@ -424,7 +445,7 @@ devredir_data_in(struct stream *s, int chan_id, int chan_flags, int length,
int
devredir_get_wait_objs(tbus *objs, int *count, int *timeout)
{
if (g_is_smartcard_redir_supported)
if (g_ccap.smartcard_redir_supported)
{
return scard_get_wait_objs(objs, count, timeout);
}
Expand All @@ -435,7 +456,7 @@ devredir_get_wait_objs(tbus *objs, int *count, int *timeout)
int
devredir_check_wait_objs(void)
{
if (g_is_smartcard_redir_supported)
if (g_ccap.smartcard_redir_supported)
{
return scard_check_wait_objs();
}
Expand Down Expand Up @@ -734,6 +755,47 @@ devredir_send_drive_dir_request(IRP *irp, tui32 device_id,
** process data received from client **
******************************************************************************/

/**
* Process a GENERAL_CAPS_SET packet from the client
* @param s Stream. CAPABILITY_HEADER is already read
* @param cap_len Amount of data left in stream for the packet
* @return 0 for success, -1 otherwise
*
* Caller is responsible for skipping unused data from this
* capability in the input stream.
*/
static int
process_client_general_caps_set(struct stream *s, unsigned int cap_len,
struct client_caps *ccap)
{
int rv = -1;

// Data we don't check at the start of the packet
#define PACKET_SKIP_LENGTH ( \
4 + /* osType */ \
4 + /* osVersion */ \
2 + /* protocolMajorVersion */ \
2 + /* protocolMinorVersion */ \
4 + /* ioCode1 */ \
4) /* ioCode2 */

if (cap_len < (PACKET_SKIP_LENGTH + 4))
{
LOG(LOG_LEVEL_ERROR,
"[MS-RDPEFS] GENERAL_CAPS_SET: Short packet (%u bytes) encountered",
cap_len);
}
else
{
xstream_seek(s, PACKET_SKIP_LENGTH);
xstream_rd_u32_le(s, ccap->extended_pdu);
rv = 0;
}

return rv;
#undef PACKET_SKIP_LENGTH
}

/**
* @brief process client's response to our core_capability_req() msg
*
Expand All @@ -743,12 +805,16 @@ devredir_send_drive_dir_request(IRP *irp, tui32 device_id,
static int
devredir_proc_client_core_cap_resp(struct stream *s)
{
#define CAPABILITY_HEADER_LEN 8
int i;
tui16 num_caps;
tui16 cap_type;
tui16 cap_len;
tui32 cap_version;
char *holdp;

// Reset to defaults
memset(&g_ccap, 0, sizeof(g_ccap));
g_ccap.drive_redir_version = 1;

if (!s_check_rem_and_log(s, 4, "Parsing [MS-RDPEFS] DR_CORE_CAPABLITY_RSP"))
{
Expand All @@ -759,8 +825,8 @@ devredir_proc_client_core_cap_resp(struct stream *s)

for (i = 0; i < num_caps; i++)
{
holdp = s->p;
if (!s_check_rem_and_log(s, 8, "Parsing [MS-RDPEFS] CAPABILITY_HEADER"))
if (!s_check_rem_and_log(s, CAPABILITY_HEADER_LEN,
"Parsing [MS-RDPEFS] CAPABILITY_HEADER"))
{
return -1;
}
Expand All @@ -769,46 +835,55 @@ devredir_proc_client_core_cap_resp(struct stream *s)
xstream_rd_u32_le(s, cap_version);
/* Convert the length to a remaining length. Underflow is possible,
* but this is an unsigned type so that's OK */
cap_len -= (s->p - holdp);
if (cap_len > 0 &&
!s_check_rem_and_log(s, cap_len, "Parsing [MS-RDPEFS] CAPABILITY_HEADER length"))
cap_len -= CAPABILITY_HEADER_LEN;
if (!s_check_rem_and_log(s, cap_len,
"Parsing [MS-RDPEFS] CAPABILITY_HEADER data"))
{
return -1;
}

// Save our stream position. iso_hdr is otherwise
// unused in this stream
s_push_layer(s, iso_hdr, 0);
switch (cap_type)
{
case CAP_GENERAL_TYPE:
LOG_DEVEL(LOG_LEVEL_DEBUG, "got CAP_GENERAL_TYPE");
if (process_client_general_caps_set(s, cap_len, &g_ccap) < 0)
{
return -1;
}
break;

case CAP_PRINTER_TYPE:
LOG_DEVEL(LOG_LEVEL_DEBUG, "got CAP_PRINTER_TYPE");
g_is_printer_redir_supported = 1;
g_ccap.printer_redir_supported = 1;
break;

case CAP_PORT_TYPE:
LOG_DEVEL(LOG_LEVEL_DEBUG, "got CAP_PORT_TYPE");
g_is_port_redir_supported = 1;
g_ccap.port_redir_supported = 1;
break;

case CAP_DRIVE_TYPE:
LOG_DEVEL(LOG_LEVEL_DEBUG, "got CAP_DRIVE_TYPE");
g_is_drive_redir_supported = 1;
g_ccap.drive_redir_supported = 1;
if (cap_version == 2)
{
g_drive_redir_version = 2;
g_ccap.drive_redir_version = 2;
}
break;

case CAP_SMARTCARD_TYPE:
LOG_DEVEL(LOG_LEVEL_DEBUG, "got CAP_SMARTCARD_TYPE");
g_is_smartcard_redir_supported = (scard_init() == 0);
g_ccap.smartcard_redir_supported = (scard_init() == 0);
break;
}
s_pop_layer(s, iso_hdr); // Move back to start of capability data
xstream_seek(s, cap_len);
}
return 0;
#undef CAPABILITY_HEADER_LEN
}

static int
Expand Down

0 comments on commit 6500949

Please sign in to comment.