From f6d1d083e99cfdd1d0e2cf806bf84cefd4e280e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 15 Jul 2014 18:38:32 -0400 Subject: [PATCH] channels/remdesk: initial dummy server-side remote assistance message parsing --- channels/remdesk/client/remdesk_main.c | 30 +- channels/remdesk/server/remdesk_main.c | 407 ++++++++++++++++++++++++- channels/remdesk/server/remdesk_main.h | 2 + include/freerdp/channels/remdesk.h | 8 + server/shadow/shadow_client.c | 12 + server/shadow/shadow_remdesk.c | 6 +- 6 files changed, 443 insertions(+), 22 deletions(-) diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index 8527b59c8..66b7ed16a 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -98,7 +98,7 @@ int remdesk_generate_expert_blob(remdeskPlugin* remdesk) return 1; } -int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) +static int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) { int status; UINT32 ChannelNameLen; @@ -133,7 +133,7 @@ int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) return 1; } -int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) +static int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) { int index; UINT32 ChannelNameLen; @@ -156,14 +156,14 @@ int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) return 1; } -int remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) +static int remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) { remdesk_write_channel_header(s, (REMDESK_CHANNEL_HEADER*) ctlHeader); Stream_Write_UINT32(s, ctlHeader->msgType); /* msgType (4 bytes) */ return 1; } -int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize) +static int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize) { ctlHeader->msgType = msgType; strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME); @@ -171,12 +171,12 @@ int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UI return 1; } -int remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) +static int remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) { return 1; } -int remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) +static int remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) { UINT32 versionMajor; UINT32 versionMinor; @@ -190,7 +190,7 @@ int remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, wStream* s, REMDES return 1; } -int remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk) +static int remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk) { wStream* s; REMDESK_CTL_VERSION_INFO_PDU pdu; @@ -214,7 +214,7 @@ int remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk) return 1; } -int remdesk_recv_result_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header, UINT32 *pResult) +static int remdesk_recv_ctl_result_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header, UINT32 *pResult) { UINT32 result; @@ -230,7 +230,7 @@ int remdesk_recv_result_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_ return 1; } -int remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) +static int remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) { int status; wStream* s; @@ -282,7 +282,7 @@ int remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) return 1; } -int remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk) +static int remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk) { int status; wStream* s; @@ -316,7 +316,7 @@ int remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk) return 1; } -int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) +static int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) { int status; wStream* s; @@ -355,7 +355,7 @@ int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) return 1; } -int remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk) +static int remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk) { int status; wStream* s; @@ -385,7 +385,7 @@ int remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk) return 1; } -int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) +static int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) { int status = 1; UINT32 msgType = 0; @@ -404,7 +404,7 @@ int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEA break; case REMDESK_CTL_RESULT: - status = remdesk_recv_result_pdu(remdesk, s, header, &result); + status = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result); break; case REMDESK_CTL_AUTHENTICATE: @@ -469,7 +469,7 @@ int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEA return status; } -int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) +static int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) { int status = 1; REMDESK_CHANNEL_HEADER header; diff --git a/channels/remdesk/server/remdesk_main.c b/channels/remdesk/server/remdesk_main.c index 3cd00ad63..8c193e0fc 100644 --- a/channels/remdesk/server/remdesk_main.c +++ b/channels/remdesk/server/remdesk_main.c @@ -27,9 +27,391 @@ #include "remdesk_main.h" +int remdesk_virtual_channel_write(RemdeskServerContext* context, wStream* s) +{ + BOOL status; + ULONG BytesWritten = 0; + + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, + (PCHAR) Stream_Buffer(s), Stream_Length(s), &BytesWritten); + + return (status) ? 1 : -1; +} + +static int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + UINT32 ChannelNameLen; + char* pChannelName = NULL; + + if (Stream_GetRemainingLength(s) < 8) + return -1; + + Stream_Read_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Read_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ + + if (ChannelNameLen > 64) + return -1; + + if ((ChannelNameLen % 2) != 0) + return -1; + + if (Stream_GetRemainingLength(s) < ChannelNameLen) + return -1; + + ZeroMemory(header->ChannelName, sizeof(header->ChannelName)); + + pChannelName = (char*) header->ChannelName; + status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), + ChannelNameLen / 2, &pChannelName, 32, NULL, NULL); + + Stream_Seek(s, ChannelNameLen); + + if (status <= 0) + return -1; + + return 1; +} + +static int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int index; + UINT32 ChannelNameLen; + WCHAR ChannelNameW[32]; + + ZeroMemory(ChannelNameW, sizeof(ChannelNameW)); + + for (index = 0; index < 32; index++) + { + ChannelNameW[index] = (WCHAR) header->ChannelName[index]; + } + + ChannelNameLen = (strlen(header->ChannelName) + 1) * 2; + + Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ + + Stream_Write(s, ChannelNameW, ChannelNameLen); /* ChannelName (variable) */ + + return 1; +} + +static int remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) +{ + remdesk_write_channel_header(s, (REMDESK_CHANNEL_HEADER*) ctlHeader); + Stream_Write_UINT32(s, ctlHeader->msgType); /* msgType (4 bytes) */ + return 1; +} + +static int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize) +{ + ctlHeader->msgType = msgType; + strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME); + ctlHeader->DataLength = 4 + msgSize; + return 1; +} + +static int remdesk_send_ctl_result_pdu(RemdeskServerContext* context, UINT32 result) +{ + wStream* s; + REMDESK_CTL_RESULT_PDU pdu; + + pdu.result = result; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_RESULT, 4); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write_UINT32(s, pdu.result); /* result (4 bytes) */ + + Stream_SealLength(s); + + remdesk_virtual_channel_write(context, s); + + Stream_Free(s, TRUE); + + return 1; +} + +static int remdesk_send_ctl_version_info_pdu(RemdeskServerContext* context) +{ + wStream* s; + REMDESK_CTL_VERSION_INFO_PDU pdu; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8); + + pdu.versionMajor = 1; + pdu.versionMinor = 2; + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write_UINT32(s, pdu.versionMajor); /* versionMajor (4 bytes) */ + Stream_Write_UINT32(s, pdu.versionMinor); /* versionMinor (4 bytes) */ + + Stream_SealLength(s); + + remdesk_virtual_channel_write(context, s); + + return 1; +} + +static int remdesk_recv_ctl_version_info_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + UINT32 versionMajor; + UINT32 versionMinor; + + if (Stream_GetRemainingLength(s) < 8) + return -1; + + Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */ + Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */ + + return 1; +} + +static int remdesk_recv_ctl_remote_control_desktop_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + int cchStringW; + WCHAR* pStringW; + UINT32 msgLength; + int cbRaConnectionStringW = 0; + WCHAR* raConnectionStringW = NULL; + REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU pdu; + + msgLength = header->DataLength - 4; + + pStringW = (WCHAR*) Stream_Pointer(s); + raConnectionStringW = pStringW; + cchStringW = 0; + + while ((msgLength > 0) && pStringW[cchStringW]) + { + msgLength -= 2; + cchStringW++; + } + + if (pStringW[cchStringW] || !cchStringW) + return -1; + + cchStringW++; + cbRaConnectionStringW = cchStringW * 2; + + pdu.raConnectionString = NULL; + + status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, + cbRaConnectionStringW / 2, &pdu.raConnectionString, 0, NULL, NULL); + + if (status <= 0) + return -1; + + printf("RaConnectionString: %s\n", + pdu.raConnectionString); + + free(pdu.raConnectionString); + + remdesk_send_ctl_result_pdu(context, 0); + + return 1; +} + +static int remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + int cchStringW; + WCHAR* pStringW; + UINT32 msgLength; + int cbExpertBlobW = 0; + WCHAR* expertBlobW = NULL; + int cbRaConnectionStringW = 0; + WCHAR* raConnectionStringW = NULL; + REMDESK_CTL_AUTHENTICATE_PDU pdu; + + msgLength = header->DataLength - 4; + + pStringW = (WCHAR*) Stream_Pointer(s); + raConnectionStringW = pStringW; + cchStringW = 0; + + while ((msgLength > 0) && pStringW[cchStringW]) + { + msgLength -= 2; + cchStringW++; + } + + if (pStringW[cchStringW] || !cchStringW) + return -1; + + cchStringW++; + cbRaConnectionStringW = cchStringW * 2; + + pStringW += cchStringW; + expertBlobW = pStringW; + cchStringW = 0; + + while ((msgLength > 0) && pStringW[cchStringW]) + { + msgLength -= 2; + cchStringW++; + } + + if (pStringW[cchStringW] || !cchStringW) + return -1; + + cchStringW++; + cbExpertBlobW = cchStringW * 2; + + pdu.raConnectionString = NULL; + + status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, + cbRaConnectionStringW / 2, &pdu.raConnectionString, 0, NULL, NULL); + + if (status <= 0) + return -1; + + pdu.expertBlob = NULL; + + status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, + cbExpertBlobW / 2, &pdu.expertBlob, 0, NULL, NULL); + + if (status <= 0) + return -1; + + printf("RaConnectionString: %s ExpertBlob: %s\n", + pdu.raConnectionString, pdu.expertBlob); + + free(pdu.raConnectionString); + free(pdu.expertBlob); + + return 1; +} + +static int remdesk_recv_ctl_verify_password_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + int cbExpertBlobW = 0; + WCHAR* expertBlobW = NULL; + REMDESK_CTL_VERIFY_PASSWORD_PDU pdu; + + if (Stream_GetRemainingLength(s) < 8) + return -1; + + pdu.expertBlob = NULL; + expertBlobW = (WCHAR*) Stream_Pointer(s); + cbExpertBlobW = header->DataLength - 4; + + status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, cbExpertBlobW / 2, &pdu.expertBlob, 0, NULL, NULL); + + printf("ExpertBlob: %s\n", pdu.expertBlob); + + remdesk_send_ctl_result_pdu(context, 0); + + return 1; +} + +static int remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status = 1; + UINT32 msgType = 0; + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */ + + printf("msgType: %d\n", msgType); + + switch (msgType) + { + case REMDESK_CTL_REMOTE_CONTROL_DESKTOP: + status = remdesk_recv_ctl_remote_control_desktop_pdu(context, s, header); + break; + + case REMDESK_CTL_AUTHENTICATE: + status = remdesk_recv_ctl_authenticate_pdu(context, s, header); + break; + + case REMDESK_CTL_DISCONNECT: + break; + + case REMDESK_CTL_VERSIONINFO: + status = remdesk_recv_ctl_version_info_pdu(context, s, header); + break; + + case REMDESK_CTL_ISCONNECTED: + break; + + case REMDESK_CTL_VERIFY_PASSWORD: + status = remdesk_recv_ctl_verify_password_pdu(context, s, header); + break; + + case REMDESK_CTL_EXPERT_ON_VISTA: + break; + + case REMDESK_CTL_RANOVICE_NAME: + break; + + case REMDESK_CTL_RAEXPERT_NAME: + break; + + case REMDESK_CTL_TOKEN: + break; + + default: + fprintf(stderr, "remdesk_recv_control_pdu: unknown msgType: %d\n", msgType); + status = -1; + break; + } + + return status; +} + static int remdesk_server_receive_pdu(RemdeskServerContext* context, wStream* s) { - return 0; + int status = 1; + REMDESK_CHANNEL_HEADER header; + +#if 0 + printf("RemdeskReceive: %d\n", Stream_GetRemainingLength(s)); + winpr_HexDump(Stream_Pointer(s), Stream_GetRemainingLength(s)); +#endif + + remdesk_read_channel_header(s, &header); + + if (strcmp(header.ChannelName, "RC_CTL") == 0) + { + status = remdesk_recv_ctl_pdu(context, s, &header); + } + else if (strcmp(header.ChannelName, "70") == 0) + { + + } + else if (strcmp(header.ChannelName, "71") == 0) + { + + } + else if (strcmp(header.ChannelName, ".") == 0) + { + + } + else if (strcmp(header.ChannelName, "1000.") == 0) + { + + } + else if (strcmp(header.ChannelName, "RA_FX") == 0) + { + + } + else + { + + } + + return 1; } static void* remdesk_server_thread(void* arg) @@ -38,6 +420,8 @@ static void* remdesk_server_thread(void* arg) DWORD status; DWORD nCount; void* buffer; + UINT32* pHeader; + UINT32 PduLength; HANDLE events[8]; HANDLE ChannelEvent; DWORD BytesReturned; @@ -63,6 +447,8 @@ static void* remdesk_server_thread(void* arg) events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; + remdesk_send_ctl_version_info_pdu(context); + while (1) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); @@ -83,9 +469,18 @@ static void* remdesk_server_thread(void* arg) Stream_EnsureRemainingCapacity(s, BytesReturned); } - if (0) + if (Stream_GetPosition(s) >= 8) { - remdesk_server_receive_pdu(context, s); + pHeader = (UINT32*) Stream_Buffer(s); + PduLength = pHeader[0] + pHeader[1] + 8; + + if (PduLength >= Stream_GetPosition(s)) + { + Stream_SealLength(s); + Stream_SetPosition(s, 0); + remdesk_server_receive_pdu(context, s); + Stream_SetPosition(s, 0); + } } } @@ -106,7 +501,7 @@ static int remdesk_server_start(RemdeskServerContext* context) context->priv->Thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) remdesk_server_thread, (void*) context, 0, NULL); - return 0; + return 1; } static int remdesk_server_stop(RemdeskServerContext* context) @@ -116,7 +511,7 @@ static int remdesk_server_stop(RemdeskServerContext* context) WaitForSingleObject(context->priv->Thread, INFINITE); CloseHandle(context->priv->Thread); - return 0; + return 1; } RemdeskServerContext* remdesk_server_context_new(HANDLE vcm) @@ -136,7 +531,7 @@ RemdeskServerContext* remdesk_server_context_new(HANDLE vcm) if (context->priv) { - + context->priv->Version = 1; } } diff --git a/channels/remdesk/server/remdesk_main.h b/channels/remdesk/server/remdesk_main.h index 42b504c1a..94184aeb9 100644 --- a/channels/remdesk/server/remdesk_main.h +++ b/channels/remdesk/server/remdesk_main.h @@ -31,6 +31,8 @@ struct _remdesk_server_private HANDLE Thread; HANDLE StopEvent; void* ChannelHandle; + + UINT32 Version; }; #endif /* FREERDP_CHANNEL_SERVER_REMDESK_MAIN_H */ diff --git a/include/freerdp/channels/remdesk.h b/include/freerdp/channels/remdesk.h index a3fa55ac2..0400bb9fd 100644 --- a/include/freerdp/channels/remdesk.h +++ b/include/freerdp/channels/remdesk.h @@ -57,6 +57,14 @@ typedef struct _REMDESK_CTL_HEADER REMDESK_CTL_HEADER; #define REMDESK_CTL_RAEXPERT_NAME 11 #define REMDESK_CTL_TOKEN 12 +struct _REMDESK_CTL_RESULT_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + UINT32 result; +}; +typedef struct _REMDESK_CTL_RESULT_PDU REMDESK_CTL_RESULT_PDU; + struct _REMDESK_CTL_VERSION_INFO_PDU { REMDESK_CTL_HEADER ctlHeader; diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 743cb5d4e..7ee3f8d4a 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -600,6 +600,7 @@ void* shadow_client_thread(rdpShadowClient* client) HANDLE events[32]; HANDLE StopEvent; HANDLE ClientEvent; + HANDLE ChannelEvent; freerdp_peer* peer; rdpSettings* settings; rdpShadowServer* server; @@ -633,12 +634,14 @@ void* shadow_client_thread(rdpShadowClient* client) StopEvent = client->StopEvent; ClientEvent = peer->GetEventHandle(peer); + ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm); while (1) { nCount = 0; events[nCount++] = StopEvent; events[nCount++] = ClientEvent; + events[nCount++] = ChannelEvent; cTime = GetTickCount64(); dwTimeout = (cTime > frameTime) ? 0 : frameTime - cTime; @@ -659,6 +662,15 @@ void* shadow_client_thread(rdpShadowClient* client) } } + if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0) + { + if (WTSVirtualChannelManagerCheckFileDescriptor(client->vcm) != TRUE) + { + fprintf(stderr, "WTSVirtualChannelManagerCheckFileDescriptor failure\n"); + break; + } + } + if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime)) { if (client->activated) diff --git a/server/shadow/shadow_remdesk.c b/server/shadow/shadow_remdesk.c index c88681352..62af21729 100644 --- a/server/shadow/shadow_remdesk.c +++ b/server/shadow/shadow_remdesk.c @@ -26,7 +26,11 @@ int shadow_client_remdesk_init(rdpShadowClient* client) { - client->remdesk = remdesk_server_context_new(client->vcm); + RemdeskServerContext* remdesk; + + remdesk = client->remdesk = remdesk_server_context_new(client->vcm); + + remdesk->custom = (void*) client; if (client->remdesk) client->remdesk->Start(client->remdesk);