From e42465372a2084aade53ba2147be7b1ad74db38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 30 Jun 2014 17:17:06 -0400 Subject: [PATCH] xfreerdp: initial remote assistance controls (ctrl+alt+c to request/release control) --- channels/encomsp/client/encomsp_main.c | 66 +++++++++++++++++- channels/remdesk/client/remdesk_main.c | 19 ++---- client/X11/xf_channels.c | 8 +++ client/X11/xf_channels.h | 1 + client/X11/xf_client.c | 49 +++++++++++++- client/X11/xf_keyboard.c | 10 +++ client/X11/xfreerdp.h | 6 ++ libfreerdp/common/assistance.c | 94 ++++++++++++++++++-------- 8 files changed, 212 insertions(+), 41 deletions(-) diff --git a/channels/encomsp/client/encomsp_main.c b/channels/encomsp/client/encomsp_main.c index 9eba47095..1ed31296f 100644 --- a/channels/encomsp/client/encomsp_main.c +++ b/channels/encomsp/client/encomsp_main.c @@ -21,6 +21,9 @@ #include "config.h" #endif +#include +#include + #include #include "encomsp_main.h" @@ -32,6 +35,30 @@ EncomspClientContext* encomsp_get_client_interface(encomspPlugin* encomsp) return pInterface; } +int encomsp_virtual_channel_write(encomspPlugin* encomsp, wStream* s) +{ + UINT32 status = 0; + + if (!encomsp) + return -1; + +#if 0 + printf("EncomspWrite (%d)\n", Stream_Length(s)); + winpr_HexDump(Stream_Buffer(s), Stream_Length(s)); +#endif + + status = encomsp->channelEntryPoints.pVirtualChannelWrite(encomsp->OpenHandle, + Stream_Buffer(s), (UINT32) Stream_Length(s), s); + + if (status != CHANNEL_RC_OK) + { + fprintf(stderr, "encomsp_virtual_channel_write: VirtualChannelWrite failed %d\n", status); + return -1; + } + + return 1; +} + int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) { if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE) @@ -43,6 +70,14 @@ int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) return 1; } +int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */ + + return 1; +} + int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str) { ZeroMemory(str, sizeof(ENCOMSP_UNICODE_STRING)); @@ -449,6 +484,30 @@ int encomsp_recv_change_participant_control_level_pdu(encomspPlugin* encomsp, wS return 1; } +int encomsp_send_change_participant_control_level_pdu(EncomspClientContext* context, ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu) +{ + wStream* s; + encomspPlugin* encomsp; + + encomsp = (encomspPlugin*) context->handle; + + pdu->Type = ODTYPE_PARTICIPANT_CTRL_CHANGED; + pdu->Length = ENCOMSP_ORDER_HEADER_SIZE + 6; + + s = Stream_New(NULL, pdu->Length); + + encomsp_write_header(s, (ENCOMSP_ORDER_HEADER*) pdu); + + Stream_Write_UINT16(s, pdu->Flags); /* Flags (2 bytes) */ + Stream_Write_UINT32(s, pdu->ParticipantId); /* ParticipantId (4 bytes) */ + + Stream_SealLength(s); + + encomsp_virtual_channel_write(encomsp, s); + + return 1; +} + int encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) { int beg, end; @@ -531,6 +590,8 @@ static int encomsp_process_receive(encomspPlugin* encomsp, wStream* s) if (encomsp_read_header(s, &header) < 0) return -1; + //printf("EncomspReceive: Type: %d Length: %d\n", header.Type, header.Length); + switch (header.Type) { case ODTYPE_FILTER_STATE_UPDATED: @@ -866,7 +927,7 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) context->ShowWindow = NULL; context->ParticipantCreated = NULL; context->ParticipantRemoved = NULL; - context->ChangeParticipantControlLevel = NULL; + context->ChangeParticipantControlLevel = encomsp_send_change_participant_control_level_pdu; context->GraphicsStreamPaused = NULL; context->GraphicsStreamResumed = NULL; @@ -878,6 +939,9 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) encomsp->channelEntryPoints.pVirtualChannelInit(&encomsp->InitHandle, &encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, encomsp_virtual_channel_init_event); + encomsp->channelEntryPoints.pInterface = *(encomsp->channelEntryPoints.ppInterface); + encomsp->channelEntryPoints.ppInterface = &(encomsp->channelEntryPoints.pInterface); + encomsp_add_init_handle_data(encomsp->InitHandle, (void*) encomsp); return 1; diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index 4973eabee..8527b59c8 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -44,9 +44,6 @@ int remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s) if (!remdesk) return -1; - printf("RemdeskWrite (%d)\n", Stream_Length(s)); - winpr_HexDump(Stream_Buffer(s), Stream_Length(s)); - status = remdesk->channelEntryPoints.pVirtualChannelWrite(remdesk->OpenHandle, Stream_Buffer(s), (UINT32) Stream_Length(s), s); @@ -176,8 +173,6 @@ int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UI int remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) { - printf("RemdeskServerAnnounce\n"); - return 1; } @@ -192,9 +187,6 @@ int remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, wStream* s, REMDES Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */ Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */ - printf("RemdeskVersionInfo: versionMajor: 0x%04X versionMinor: 0x%04X\n", - versionMajor, versionMinor); - return 1; } @@ -233,7 +225,7 @@ int remdesk_recv_result_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_ *pResult = result; - printf("RemdeskRecvResult: 0x%04X\n", result); + //printf("RemdeskRecvResult: 0x%04X\n", result); return 1; } @@ -404,7 +396,7 @@ int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEA Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */ - printf("msgType: %d\n", msgType); + //printf("msgType: %d\n", msgType); switch (msgType) { @@ -482,8 +474,10 @@ int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) 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); @@ -521,8 +515,6 @@ int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) static void remdesk_process_connect(remdeskPlugin* remdesk) { - printf("RemdeskProcessConnect\n"); - remdesk->settings = (rdpSettings*) remdesk->channelEntryPoints.pExtendedData; } @@ -803,6 +795,9 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) remdesk->channelEntryPoints.pVirtualChannelInit(&remdesk->InitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, remdesk_virtual_channel_init_event); + remdesk->channelEntryPoints.pInterface = *(remdesk->channelEntryPoints.ppInterface); + remdesk->channelEntryPoints.ppInterface = &(remdesk->channelEntryPoints.pInterface); + remdesk_add_init_handle_data(remdesk->InitHandle, (void*) remdesk); return 1; diff --git a/client/X11/xf_channels.c b/client/X11/xf_channels.c index 9bb36152e..e8e06ab31 100644 --- a/client/X11/xf_channels.c +++ b/client/X11/xf_channels.c @@ -40,6 +40,10 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEven { xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*) e->pInterface); } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + xf_encomsp_init(xfc, (EncomspClientContext*) e->pInterface); + } } void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) @@ -54,4 +58,8 @@ void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnect { xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*) e->pInterface); } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + xf_encomsp_uninit(xfc, (EncomspClientContext*) e->pInterface); + } } diff --git a/client/X11/xf_channels.h b/client/X11/xf_channels.h index dd5969d62..b2ca7a966 100644 --- a/client/X11/xf_channels.h +++ b/client/X11/xf_channels.h @@ -24,6 +24,7 @@ #include #include #include +#include int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface); int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface); diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 8011e6a82..ca53eb5af 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -468,7 +468,7 @@ void xf_create_window(xfContext *xfc) } } -void xf_toggle_fullscreen(xfContext *xfc) +void xf_toggle_fullscreen(xfContext* xfc) { Pixmap contents = 0; WindowStateChangeEventArgs e; @@ -486,6 +486,53 @@ void xf_toggle_fullscreen(xfContext *xfc) PubSub_OnWindowStateChange(((rdpContext *) xfc)->pubSub, xfc, &e); } +void xf_toggle_control(xfContext* xfc) +{ + EncomspClientContext* encomsp; + ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu; + + encomsp = xfc->encomsp; + + if (!encomsp) + return; + + pdu.ParticipantId = 0; + pdu.Flags = ENCOMSP_REQUEST_VIEW; + + if (!xfc->controlToggle) + pdu.Flags |= ENCOMSP_REQUEST_INTERACT; + + encomsp->ChangeParticipantControlLevel(encomsp, &pdu); + + xfc->controlToggle = !xfc->controlToggle; +} + +int xf_encomsp_participant_created(EncomspClientContext* context, ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated) +{ +#if 0 + xfContext* xfc = (xfContext*) context->custom; + + printf("ParticipantCreated: ParticipantId: %d GroupId: %d Flags: 0x%04X xfc: %p\n", + (int) participantCreated->ParticipantId, (int) participantCreated->GroupId, + (int) participantCreated->Flags, xfc); +#endif + + return 1; +} + +void xf_encomsp_init(xfContext* xfc, EncomspClientContext* encomsp) +{ + xfc->encomsp = encomsp; + encomsp->custom = (void*) xfc; + + encomsp->ParticipantCreated = xf_encomsp_participant_created; +} + +void xf_encomsp_uninit(xfContext* xfc, EncomspClientContext* encomsp) +{ + xfc->encomsp = NULL; +} + void xf_lock_x11(xfContext *xfc, BOOL display) { if(!xfc->UseXThreads) diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c index 358b6d099..175e83643 100644 --- a/client/X11/xf_keyboard.c +++ b/client/X11/xf_keyboard.c @@ -415,6 +415,16 @@ BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym) } } + if ((keysym == XK_c) || (keysym == XK_C)) + { + if (mod.Ctrl && mod.Alt) + { + /* Ctrl-Alt-C: toggle control */ + xf_toggle_control(xfc); + return TRUE; + } + } + if (keysym == XK_period) { if (mod.Ctrl && mod.Alt) diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index a1e6ebf16..1af93fa69 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -137,6 +137,7 @@ struct xf_context BOOL mouse_active; BOOL suppress_output; BOOL fullscreen_toggle; + BOOL controlToggle; UINT32 KeyboardLayout; BOOL KeyboardState[256]; XModifierKeymap* modifierMap; @@ -182,12 +183,17 @@ struct xf_context /* Channels */ RdpeiClientContext* rdpei; RdpgfxClientContext* gfx; + EncomspClientContext* encomsp; }; void xf_create_window(xfContext* xfc); void xf_toggle_fullscreen(xfContext* xfc); +void xf_toggle_control(xfContext* xfc); BOOL xf_post_connect(freerdp* instance); +void xf_encomsp_init(xfContext* xfc, EncomspClientContext* encomsp); +void xf_encomsp_uninit(xfContext* xfc, EncomspClientContext* encomsp); + enum XF_EXIT_CODE { /* section 0-15: protocol-independent codes */ diff --git a/libfreerdp/common/assistance.c b/libfreerdp/common/assistance.c index 87e602d4d..efeadaf08 100644 --- a/libfreerdp/common/assistance.c +++ b/libfreerdp/common/assistance.c @@ -112,7 +112,7 @@ int freerdp_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* k return 1; } -int freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file) +int freerdp_assistance_parse_address_list(rdpAssistanceFile* file, char* list) { int i; char* p; @@ -120,7 +120,71 @@ int freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file) char* str; int count; int length; - char* list; + char** tokens; + + count = 1; + str = _strdup(list); + + if (!str) + return -1; + + length = strlen(str); + + for (i = 0; i < length; i++) + { + if (str[i] == ';') + count++; + } + + tokens = (char**) malloc(sizeof(char*) * count); + + count = 0; + tokens[count++] = str; + + for (i = 0; i < length; i++) + { + if (str[i] == ';') + { + str[i] = '\0'; + tokens[count++] = &str[i + 1]; + } + } + + for (i = 0; i < count; i++) + { + length = strlen(tokens[i]); + + if (length > 8) + { + if (strncmp(tokens[i], "169.254.", 8) == 0) + continue; + } + + p = tokens[i]; + + q = strchr(p, ':'); + + if (!q) + return -1; + + q[0] = '\0'; + q++; + + file->MachineAddress = _strdup(p); + file->MachinePort = (UINT32) atoi(q); + + break; + } + + return 1; +} + +int freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file) +{ + int i; + char* str; + int count; + int length; char* tokens[8]; /** @@ -182,25 +246,7 @@ int freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file) if (!file->RASpecificParams) return -1; - list = tokens[2]; - - q = strchr(list, ';'); - - if (q) - q[0] = '\0'; - - p = list; - - q = strchr(p, ':'); - - if (!q) - return -1; - - q[0] = '\0'; - q++; - - file->MachineAddress = _strdup(p); - file->MachinePort = (UINT32) atoi(q); + freerdp_assistance_parse_address_list(file, tokens[2]); free(str); @@ -374,9 +420,6 @@ BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* pas *((UINT32*) pbIn) = cbPassStubW; CopyMemory(&pbIn[4], PassStubW, cbPassStubW); - printf("PlainBlob (%d)\n", EncryptedSize); - winpr_HexDump(pbIn, EncryptedSize); - EVP_CIPHER_CTX_init(&rc4Ctx); status = EVP_EncryptInit_ex(&rc4Ctx, EVP_rc4(), NULL, NULL, NULL); @@ -416,9 +459,6 @@ BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* pas EVP_CIPHER_CTX_cleanup(&rc4Ctx); - printf("EncryptedBlob (%d):\n", EncryptedSize); - winpr_HexDump(pbOut, EncryptedSize); - free(pbIn); free(PasswordW); free(PassStubW);