From 19397d47fd699b1d6e824fb15ad1650e3c41491e Mon Sep 17 00:00:00 2001 From: erbth Date: Wed, 11 Jun 2014 21:45:53 +0200 Subject: [PATCH 01/23] fixed getstatuschangeA rdp-return value in case of failure --- channels/smartcard/client/smartcard_operations.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/channels/smartcard/client/smartcard_operations.c b/channels/smartcard/client/smartcard_operations.c index 47f77c4e9..13ded0b8d 100644 --- a/channels/smartcard/client/smartcard_operations.c +++ b/channels/smartcard/client/smartcard_operations.c @@ -388,8 +388,9 @@ static UINT32 smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard, SMART status = ret.ReturnCode = SCardGetStatusChangeA(operation->hContext, call->dwTimeOut, call->rgReaderStates, call->cReaders); - if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED)) - return status; + if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED)){ + call->cReaders=0; + } ret.cReaders = call->cReaders; ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return)); From 1a01949b6887ebaf3b52120745ea739353ff6ad0 Mon Sep 17 00:00:00 2001 From: erbth Date: Wed, 11 Jun 2014 21:47:14 +0200 Subject: [PATCH 02/23] drive hotpluging: register mounted drives already before first hotplug --- channels/rdpdr/client/rdpdr_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 5759b5154..c1b4975c2 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -460,6 +460,8 @@ static void* drive_hotplug_thread_func(void* arg) tv.tv_sec = 1; tv.tv_usec = 0; + handle_hotplug(rdpdr); + while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0) { if (WaitForSingleObject(rdpdr->stopEvent, 0) == WAIT_OBJECT_0) From 08424758766a5336a548ce1e7e791398933c6522 Mon Sep 17 00:00:00 2001 From: erbth Date: Thu, 12 Jun 2014 17:19:08 +0200 Subject: [PATCH 03/23] fixed getstatuschangeW rdp-return value in case of failure --- channels/smartcard/client/smartcard_operations.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/channels/smartcard/client/smartcard_operations.c b/channels/smartcard/client/smartcard_operations.c index 13ded0b8d..0e9fad24e 100644 --- a/channels/smartcard/client/smartcard_operations.c +++ b/channels/smartcard/client/smartcard_operations.c @@ -454,8 +454,9 @@ static UINT32 smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard, SMART status = ret.ReturnCode = SCardGetStatusChangeW(operation->hContext, call->dwTimeOut, call->rgReaderStates, call->cReaders); - if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED)) - return status; + if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED)){ + call->cReaders=0; + } ret.cReaders = call->cReaders; ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return)); From 64b8ded9f2de778a5758c4f89e3816d3b4a0d67f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 23 Jun 2014 16:18:03 -0400 Subject: [PATCH 04/23] encomsp: stub client/server virtual channel --- channels/encomsp/CMakeLists.txt | 26 ++ channels/encomsp/ChannelOptions.cmake | 13 + channels/encomsp/client/CMakeLists.txt | 35 +++ channels/encomsp/client/encomsp_main.c | 315 +++++++++++++++++++++++++ channels/encomsp/client/encomsp_main.h | 48 ++++ channels/encomsp/server/CMakeLists.txt | 37 +++ channels/encomsp/server/encomsp_main.c | 157 ++++++++++++ channels/encomsp/server/encomsp_main.h | 36 +++ include/freerdp/channels/encomsp.h | 29 +++ include/freerdp/client/encomsp.h | 37 +++ include/freerdp/server/encomsp.h | 52 ++++ 11 files changed, 785 insertions(+) create mode 100644 channels/encomsp/CMakeLists.txt create mode 100644 channels/encomsp/ChannelOptions.cmake create mode 100644 channels/encomsp/client/CMakeLists.txt create mode 100644 channels/encomsp/client/encomsp_main.c create mode 100644 channels/encomsp/client/encomsp_main.h create mode 100644 channels/encomsp/server/CMakeLists.txt create mode 100644 channels/encomsp/server/encomsp_main.c create mode 100644 channels/encomsp/server/encomsp_main.h create mode 100644 include/freerdp/channels/encomsp.h create mode 100644 include/freerdp/client/encomsp.h create mode 100644 include/freerdp/server/encomsp.h diff --git a/channels/encomsp/CMakeLists.txt b/channels/encomsp/CMakeLists.txt new file mode 100644 index 000000000..be2d3748d --- /dev/null +++ b/channels/encomsp/CMakeLists.txt @@ -0,0 +1,26 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel("encomsp") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() + +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/encomsp/ChannelOptions.cmake b/channels/encomsp/ChannelOptions.cmake new file mode 100644 index 000000000..82ef07eab --- /dev/null +++ b/channels/encomsp/ChannelOptions.cmake @@ -0,0 +1,13 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "encomsp" TYPE "static" + DESCRIPTION "Multiparty Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPEMC]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) + diff --git a/channels/encomsp/client/CMakeLists.txt b/channels/encomsp/client/CMakeLists.txt new file mode 100644 index 000000000..ffa8435ab --- /dev/null +++ b/channels/encomsp/client/CMakeLists.txt @@ -0,0 +1,35 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_client("encomsp") + +set(${MODULE_PREFIX}_SRCS + encomsp_main.c + encomsp_main.h) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-crt) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/encomsp/client/encomsp_main.c b/channels/encomsp/client/encomsp_main.c new file mode 100644 index 000000000..4d51c55e9 --- /dev/null +++ b/channels/encomsp/client/encomsp_main.c @@ -0,0 +1,315 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "encomsp_main.h" + +static void encomsp_process_connect(encomspPlugin* encomsp) +{ + +} + +static void encomsp_process_receive(encomspPlugin* encomsp, wStream* s) +{ + +} + + +/****************************************************************************************/ + + +static wListDictionary* g_InitHandles; +static wListDictionary* g_OpenHandles; + +void encomsp_add_init_handle_data(void* pInitHandle, void* pUserData) +{ + if (!g_InitHandles) + g_InitHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_InitHandles, pInitHandle, pUserData); +} + +void* encomsp_get_init_handle_data(void* pInitHandle) +{ + void* pUserData = NULL; + pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle); + return pUserData; +} + +void encomsp_remove_init_handle_data(void* pInitHandle) +{ + ListDictionary_Remove(g_InitHandles, pInitHandle); +} + +void encomsp_add_open_handle_data(DWORD openHandle, void* pUserData) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + + if (!g_OpenHandles) + g_OpenHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData); +} + +void* encomsp_get_open_handle_data(DWORD openHandle) +{ + void* pUserData = NULL; + void* pOpenHandle = (void*) (size_t) openHandle; + pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle); + return pUserData; +} + +void encomsp_remove_open_handle_data(DWORD openHandle) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + ListDictionary_Remove(g_OpenHandles, pOpenHandle); +} + +int encomsp_send(encomspPlugin* encomsp, wStream* s) +{ + UINT32 status = 0; + encomspPlugin* plugin = (encomspPlugin*) encomsp; + + if (!plugin) + { + status = CHANNEL_RC_BAD_INIT_HANDLE; + } + else + { + status = plugin->channelEntryPoints.pVirtualChannelWrite(plugin->OpenHandle, + Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + } + + if (status != CHANNEL_RC_OK) + { + Stream_Free(s, TRUE); + fprintf(stderr, "encomsp_send: VirtualChannelWrite failed %d\n", status); + } + + return status; +} + +static void encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, + void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + wStream* data_in; + + if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME)) + { + return; + } + + if (dataFlags & CHANNEL_FLAG_FIRST) + { + if (encomsp->data_in) + Stream_Free(encomsp->data_in, TRUE); + + encomsp->data_in = Stream_New(NULL, totalLength); + } + + data_in = encomsp->data_in; + Stream_EnsureRemainingCapacity(data_in, (int) dataLength); + Stream_Write(data_in, pData, dataLength); + + if (dataFlags & CHANNEL_FLAG_LAST) + { + if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) + { + fprintf(stderr, "encomsp_plugin_process_received: read error\n"); + } + + encomsp->data_in = NULL; + Stream_SealLength(data_in); + Stream_SetPosition(data_in, 0); + + MessageQueue_Post(encomsp->MsgPipe->In, NULL, 0, (void*) data_in, NULL); + } +} + +static VOID VCAPITYPE encomsp_virtual_channel_open_event(DWORD openHandle, UINT event, + LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + encomspPlugin* encomsp; + + encomsp = (encomspPlugin*) encomsp_get_open_handle_data(openHandle); + + if (!encomsp) + { + fprintf(stderr, "encomsp_virtual_channel_open_event: error no match\n"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_DATA_RECEIVED: + encomsp_virtual_channel_event_data_received(encomsp, pData, dataLength, totalLength, dataFlags); + break; + + case CHANNEL_EVENT_WRITE_COMPLETE: + Stream_Free((wStream*) pData, TRUE); + break; + + case CHANNEL_EVENT_USER: + break; + } +} + +static void* encomsp_virtual_channel_client_thread(void* arg) +{ + wStream* data; + wMessage message; + encomspPlugin* encomsp = (encomspPlugin*) arg; + + encomsp_process_connect(encomsp); + + while (1) + { + if (!MessageQueue_Wait(encomsp->MsgPipe->In)) + break; + + if (MessageQueue_Peek(encomsp->MsgPipe->In, &message, TRUE)) + { + if (message.id == WMQ_QUIT) + break; + + if (message.id == 0) + { + data = (wStream*) message.wParam; + encomsp_process_receive(encomsp, data); + } + } + } + + ExitThread(0); + return NULL; +} + +static void encomsp_virtual_channel_event_connected(encomspPlugin* encomsp, LPVOID pData, UINT32 dataLength) +{ + UINT32 status; + + status = encomsp->channelEntryPoints.pVirtualChannelOpen(encomsp->InitHandle, + &encomsp->OpenHandle, encomsp->channelDef.name, encomsp_virtual_channel_open_event); + + encomsp_add_open_handle_data(encomsp->OpenHandle, encomsp); + + if (status != CHANNEL_RC_OK) + { + fprintf(stderr, "encomsp_virtual_channel_event_connected: open failed: status: %d\n", status); + return; + } + + encomsp->MsgPipe = MessagePipe_New(); + + encomsp->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) encomsp_virtual_channel_client_thread, (void*) encomsp, 0, NULL); +} + +static void encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp) +{ + MessagePipe_PostQuit(encomsp->MsgPipe, 0); + WaitForSingleObject(encomsp->thread, INFINITE); + + MessagePipe_Free(encomsp->MsgPipe); + CloseHandle(encomsp->thread); + + encomsp->channelEntryPoints.pVirtualChannelClose(encomsp->OpenHandle); + + if (encomsp->data_in) + { + Stream_Free(encomsp->data_in, TRUE); + encomsp->data_in = NULL; + } + + encomsp_remove_open_handle_data(encomsp->OpenHandle); + encomsp_remove_init_handle_data(encomsp->InitHandle); +} + +static VOID VCAPITYPE encomsp_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) +{ + encomspPlugin* encomsp; + + encomsp = (encomspPlugin*) encomsp_get_init_handle_data(pInitHandle); + + if (!encomsp) + { + fprintf(stderr, "encomsp_virtual_channel_init_event: error no match\n"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_CONNECTED: + encomsp_virtual_channel_event_connected(encomsp, pData, dataLength); + break; + + case CHANNEL_EVENT_DISCONNECTED: + break; + + case CHANNEL_EVENT_TERMINATED: + encomsp_virtual_channel_event_terminated(encomsp); + break; + } +} + +/* encomsp is always built-in */ +#define VirtualChannelEntry encomsp_VirtualChannelEntry + +BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) +{ + encomspPlugin* encomsp; + EncomspClientContext* context; + CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx; + + encomsp = (encomspPlugin*) calloc(1, sizeof(encomspPlugin)); + + encomsp->channelDef.options = + CHANNEL_OPTION_INITIALIZED | + CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP | + CHANNEL_OPTION_SHOW_PROTOCOL; + + strcpy(encomsp->channelDef.name, "encomsp"); + + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints; + + if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) && + (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) + { + context = (EncomspClientContext*) calloc(1, sizeof(EncomspClientContext)); + + context->handle = (void*) encomsp; + + *(pEntryPointsEx->ppInterface) = (void*) context; + } + + CopyMemory(&(encomsp->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP)); + + encomsp->channelEntryPoints.pVirtualChannelInit(&encomsp->InitHandle, + &encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, encomsp_virtual_channel_init_event); + + encomsp_add_init_handle_data(encomsp->InitHandle, (void*) encomsp); + + return 1; +} diff --git a/channels/encomsp/client/encomsp_main.h b/channels/encomsp/client/encomsp_main.h new file mode 100644 index 000000000..d67c92fac --- /dev/null +++ b/channels/encomsp/client/encomsp_main.h @@ -0,0 +1,48 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H +#define FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +struct encomsp_plugin +{ + CHANNEL_DEF channelDef; + CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints; + + HANDLE thread; + wStream* data_in; + void* InitHandle; + DWORD OpenHandle; + wMessagePipe* MsgPipe; +}; +typedef struct encomsp_plugin encomspPlugin; + +#endif /* FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H */ diff --git a/channels/encomsp/server/CMakeLists.txt b/channels/encomsp/server/CMakeLists.txt new file mode 100644 index 000000000..494d7ff99 --- /dev/null +++ b/channels/encomsp/server/CMakeLists.txt @@ -0,0 +1,37 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_server("encomsp") + +set(${MODULE_PREFIX}_SRCS + encomsp_main.c + encomsp_main.h) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-crt) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/encomsp/server/encomsp_main.c b/channels/encomsp/server/encomsp_main.c new file mode 100644 index 000000000..9d7fc5ae5 --- /dev/null +++ b/channels/encomsp/server/encomsp_main.c @@ -0,0 +1,157 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "encomsp_main.h" + +static int encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s) +{ + return 0; +} + +static void* encomsp_server_thread(void* arg) +{ + wStream* s; + DWORD status; + DWORD nCount; + void* buffer; + HANDLE events[8]; + HANDLE ChannelEvent; + DWORD BytesReturned; + EncomspServerContext* context; + + context = (EncomspServerContext*) arg; + + buffer = NULL; + BytesReturned = 0; + ChannelEvent = NULL; + + s = Stream_New(NULL, 4096); + + if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + nCount = 0; + events[nCount++] = ChannelEvent; + events[nCount++] = context->priv->StopEvent; + + while (1) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) + { + break; + } + + if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, + (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + { + if (BytesReturned) + Stream_Seek(s, BytesReturned); + } + else + { + Stream_EnsureRemainingCapacity(s, BytesReturned); + } + + if (0) + { + encomsp_server_receive_pdu(context, s); + } + } + + Stream_Free(s, TRUE); + + return NULL; +} + +static int encomsp_server_start(EncomspServerContext* context) +{ + context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "encomsp"); + + if (!context->priv->ChannelHandle) + return -1; + + context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + context->priv->Thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) encomsp_server_thread, (void*) context, 0, NULL); + + return 0; +} + +static int encomsp_server_stop(EncomspServerContext* context) +{ + SetEvent(context->priv->StopEvent); + + WaitForSingleObject(context->priv->Thread, INFINITE); + CloseHandle(context->priv->Thread); + + return 0; +} + +EncomspServerContext* encomsp_server_context_new(HANDLE vcm) +{ + EncomspServerContext* context; + + context = (EncomspServerContext*) calloc(1, sizeof(EncomspServerContext)); + + if (context) + { + context->vcm = vcm; + + context->Start = encomsp_server_start; + context->Stop = encomsp_server_stop; + + context->priv = (EncomspServerPrivate*) calloc(1, sizeof(EncomspServerPrivate)); + + if (context->priv) + { + + } + } + + return context; +} + +void encomsp_server_context_free(EncomspServerContext* context) +{ + if (context) + { + if (context->priv) + { + free(context->priv); + } + + free(context); + } +} diff --git a/channels/encomsp/server/encomsp_main.h b/channels/encomsp/server/encomsp_main.h new file mode 100644 index 000000000..1338f6ee0 --- /dev/null +++ b/channels/encomsp/server/encomsp_main.h @@ -0,0 +1,36 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_SERVER_ENCOMSP_MAIN_H +#define FREERDP_CHANNEL_SERVER_ENCOMSP_MAIN_H + +#include +#include +#include + +#include + +struct _encomsp_server_private +{ + HANDLE Thread; + HANDLE StopEvent; + void* ChannelHandle; +}; + +#endif /* FREERDP_CHANNEL_SERVER_ENCOMSP_MAIN_H */ diff --git a/include/freerdp/channels/encomsp.h b/include/freerdp/channels/encomsp.h new file mode 100644 index 000000000..179d98a83 --- /dev/null +++ b/include/freerdp/channels/encomsp.h @@ -0,0 +1,29 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_ENCOMSP_H +#define FREERDP_CHANNEL_ENCOMSP_H + +#include +#include + +#define ENCOMSP_SVC_CHANNEL_NAME "encomsp" + +#endif /* FREERDP_CHANNEL_ENCOMSP_H */ + diff --git a/include/freerdp/client/encomsp.h b/include/freerdp/client/encomsp.h new file mode 100644 index 000000000..f97732908 --- /dev/null +++ b/include/freerdp/client/encomsp.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_CLIENT_ENCOMSP_H +#define FREERDP_CHANNEL_CLIENT_ENCOMSP_H + +#include + +/** + * Client Interface + */ + +typedef struct _encomsp_client_context EncomspClientContext; + +struct _encomsp_client_context +{ + void* handle; + void* custom; +}; + +#endif /* FREERDP_CHANNEL_CLIENT_ENCOMSP_H */ diff --git a/include/freerdp/server/encomsp.h b/include/freerdp/server/encomsp.h new file mode 100644 index 000000000..f692073b8 --- /dev/null +++ b/include/freerdp/server/encomsp.h @@ -0,0 +1,52 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_SERVER_ENCOMSP_H +#define FREERDP_CHANNEL_SERVER_ENCOMSP_H + +#include +#include +#include + +#include + +/** + * Server Interface + */ + +typedef struct _encomsp_server_context EncomspServerContext; +typedef struct _encomsp_server_private EncomspServerPrivate; + +typedef int (*psEncomspStart)(EncomspServerContext* context); +typedef int (*psEncomspStop)(EncomspServerContext* context); + +struct _encomsp_server_context +{ + HANDLE vcm; + + psEncomspStart Start; + psEncomspStop Stop; + + EncomspServerPrivate* priv; +}; + +FREERDP_API EncomspServerContext* encomsp_server_context_new(HANDLE vcm); +FREERDP_API void encomsp_server_context_free(EncomspServerContext* context); + +#endif /* FREERDP_CHANNEL_SERVER_ENCOMSP_H */ From 014d8972e3b42ed6eca4d66d72f55944d3a488a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 23 Jun 2014 18:17:26 -0400 Subject: [PATCH 05/23] channels/encomsp: initial client-side implementation --- channels/encomsp/client/encomsp_main.c | 583 ++++++++++++++++++++++++- include/freerdp/channels/encomsp.h | 157 +++++++ include/freerdp/client/encomsp.h | 24 + 3 files changed, 757 insertions(+), 7 deletions(-) diff --git a/channels/encomsp/client/encomsp_main.c b/channels/encomsp/client/encomsp_main.c index 4d51c55e9..9eba47095 100644 --- a/channels/encomsp/client/encomsp_main.c +++ b/channels/encomsp/client/encomsp_main.c @@ -25,20 +25,577 @@ #include "encomsp_main.h" +EncomspClientContext* encomsp_get_client_interface(encomspPlugin* encomsp) +{ + EncomspClientContext* pInterface; + pInterface = (EncomspClientContext*) encomsp->channelEntryPoints.pInterface; + return pInterface; +} + +int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE) + return -1; + + Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Read_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)); + + if (Stream_GetRemainingLength(s) < 2) + return -1; + + Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */ + + if (str->cchString > 1024) + return -1; + + if (Stream_GetRemainingLength(s) < (str->cchString * 2)) + return -1; + + Stream_Read(s, &(str->wString), (str->cchString * 2)); /* String (variable) */ + + return 1; +} + +int encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_FILTER_UPDATED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 1) + return -1; + + Stream_Read_UINT8(s, pdu.Flags); /* Flags (1 byte) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->FilterUpdated) + { + return context->FilterUpdated(context, &pdu); + } + + return 1; +} + +int encomsp_recv_application_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_APPLICATION_CREATED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 6) + return -1; + + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */ + + if (encomsp_read_unicode_string(s, &(pdu.Name)) < 0) + return -1; + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ApplicationCreated) + { + return context->ApplicationCreated(context, &pdu); + } + + return 1; +} + +int encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_APPLICATION_REMOVED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ApplicationRemoved) + { + return context->ApplicationRemoved(context, &pdu); + } + + return 1; +} + +int encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_WINDOW_CREATED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 10) + return -1; + + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */ + Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */ + + if (encomsp_read_unicode_string(s, &(pdu.Name)) < 0) + return -1; + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->WindowCreated) + { + return context->WindowCreated(context, &pdu); + } + + return 1; +} + +int encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_WINDOW_REMOVED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->WindowRemoved) + { + return context->WindowRemoved(context, &pdu); + } + + return 1; +} + +int encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_SHOW_WINDOW_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ShowWindow) + { + return context->ShowWindow(context, &pdu); + } + + return 1; +} + +int encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_PARTICIPANT_CREATED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 10) + return -1; + + Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ + Stream_Read_UINT32(s, pdu.GroupId); /* GroupId (4 bytes) */ + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + + if (encomsp_read_unicode_string(s, &(pdu.FriendlyName)) < 0) + return -1; + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ParticipantCreated) + { + return context->ParticipantCreated(context, &pdu); + } + + return 1; +} + +int encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_PARTICIPANT_REMOVED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 12) + return -1; + + Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ + Stream_Read_UINT32(s, pdu.DiscType); /* DiscType (4 bytes) */ + Stream_Read_UINT32(s, pdu.DiscCode); /* DiscCode (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ParticipantRemoved) + { + return context->ParticipantRemoved(context, &pdu); + } + + return 1; +} + +int encomsp_recv_change_participant_control_level_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 6) + return -1; + + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ChangeParticipantControlLevel) + { + return context->ChangeParticipantControlLevel(context, &pdu); + } + + return 1; +} + +int encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->GraphicsStreamPaused) + { + return context->GraphicsStreamPaused(context, &pdu); + } + + return 1; +} + +int encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->GraphicsStreamResumed) + { + return context->GraphicsStreamResumed(context, &pdu); + } + + return 1; +} + +static int encomsp_process_receive(encomspPlugin* encomsp, wStream* s) +{ + int status = 1; + ENCOMSP_ORDER_HEADER header; + + while (Stream_GetRemainingLength(s) > 0) + { + if (encomsp_read_header(s, &header) < 0) + return -1; + + switch (header.Type) + { + case ODTYPE_FILTER_STATE_UPDATED: + status = encomsp_recv_filter_updated_pdu(encomsp, s, &header); + break; + + case ODTYPE_APP_REMOVED: + status = encomsp_recv_application_removed_pdu(encomsp, s, &header); + break; + + case ODTYPE_APP_CREATED: + status = encomsp_recv_application_created_pdu(encomsp, s, &header); + break; + + case ODTYPE_WND_REMOVED: + status = encomsp_recv_window_removed_pdu(encomsp, s, &header); + break; + + case ODTYPE_WND_CREATED: + status = encomsp_recv_window_created_pdu(encomsp, s, &header); + break; + + case ODTYPE_WND_SHOW: + status = encomsp_recv_show_window_pdu(encomsp, s, &header); + break; + + case ODTYPE_PARTICIPANT_REMOVED: + status = encomsp_recv_participant_removed_pdu(encomsp, s, &header); + break; + + case ODTYPE_PARTICIPANT_CREATED: + status = encomsp_recv_participant_created_pdu(encomsp, s, &header); + break; + + case ODTYPE_PARTICIPANT_CTRL_CHANGED: + status = encomsp_recv_change_participant_control_level_pdu(encomsp, s, &header); + break; + + case ODTYPE_GRAPHICS_STREAM_PAUSED: + status = encomsp_recv_graphics_stream_paused_pdu(encomsp, s, &header); + break; + + case ODTYPE_GRAPHICS_STREAM_RESUMED: + status = encomsp_recv_graphics_stream_resumed_pdu(encomsp, s, &header); + break; + + default: + status = -1; + break; + } + + if (status < 0) + return -1; + } + + return status; +} + static void encomsp_process_connect(encomspPlugin* encomsp) { } -static void encomsp_process_receive(encomspPlugin* encomsp, wStream* s) -{ - -} - - /****************************************************************************************/ - static wListDictionary* g_InitHandles; static wListDictionary* g_OpenHandles; @@ -301,6 +858,18 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) context->handle = (void*) encomsp; + context->FilterUpdated = NULL; + context->ApplicationCreated = NULL; + context->ApplicationRemoved = NULL; + context->WindowCreated = NULL; + context->WindowRemoved = NULL; + context->ShowWindow = NULL; + context->ParticipantCreated = NULL; + context->ParticipantRemoved = NULL; + context->ChangeParticipantControlLevel = NULL; + context->GraphicsStreamPaused = NULL; + context->GraphicsStreamResumed = NULL; + *(pEntryPointsEx->ppInterface) = (void*) context; } diff --git a/include/freerdp/channels/encomsp.h b/include/freerdp/channels/encomsp.h index 179d98a83..b2fffc5b4 100644 --- a/include/freerdp/channels/encomsp.h +++ b/include/freerdp/channels/encomsp.h @@ -25,5 +25,162 @@ #define ENCOMSP_SVC_CHANNEL_NAME "encomsp" +struct _ENCOMSP_UNICODE_STRING +{ + UINT16 cchString; + WCHAR wString[1024]; +}; +typedef struct _ENCOMSP_UNICODE_STRING ENCOMSP_UNICODE_STRING; + +/* Filter Updated PDU Flags */ + +#define ENCOMSP_FILTER_ENABLED 0x0001 + +/* Application Created PDU Flags */ + +#define ENCOMSP_APPLICATION_SHARED 0x0001 + +/* Window Created PDU Flags */ + +#define ENCOMSP_WINDOW_SHARED 0x0001 + +/* Participant Created PDU Flags */ + +#define ENCOMSP_MAY_VIEW 0x0001 +#define ENCOMSP_MAY_INTERACT 0x0002 +#define ENCOMSP_IS_PARTICIPANT 0x0004 + +/* Participant Removed PDU Disconnection Types */ + +#define ENCOMSP_PARTICIPANT_DISCONNECTION_REASON_APP 0x00000000 +#define ENCOMSP_PARTICIPANT_DISCONNECTION_REASON_CLI 0x00000002 + +/* Change Participant Control Level PDU Flags */ + +#define ENCOMSP_REQUEST_VIEW 0x0001 +#define ENCOMSP_REQUEST_INTERACT 0x0002 +#define ENCOMSP_ALLOW_CONTROL_REQUESTS 0x0008 + +/* PDU Order Types */ + +#define ODTYPE_FILTER_STATE_UPDATED 0x0001 +#define ODTYPE_APP_REMOVED 0x0002 +#define ODTYPE_APP_CREATED 0x0003 +#define ODTYPE_WND_REMOVED 0x0004 +#define ODTYPE_WND_CREATED 0x0005 +#define ODTYPE_WND_SHOW 0x0006 +#define ODTYPE_PARTICIPANT_REMOVED 0x0007 +#define ODTYPE_PARTICIPANT_CREATED 0x0008 +#define ODTYPE_PARTICIPANT_CTRL_CHANGED 0x0009 +#define ODTYPE_GRAPHICS_STREAM_PAUSED 0x000A +#define ODTYPE_GRAPHICS_STREAM_RESUMED 0x000B + +#define DEFINE_ENCOMSP_HEADER_COMMON() \ + UINT16 Type; \ + UINT16 Length + +#define ENCOMSP_ORDER_HEADER_SIZE 4 + +struct _ENCOMSP_ORDER_HEADER +{ + DEFINE_ENCOMSP_HEADER_COMMON(); +}; +typedef struct _ENCOMSP_ORDER_HEADER ENCOMSP_ORDER_HEADER; + +struct _ENCOMSP_FILTER_UPDATED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + BYTE Flags; +}; +typedef struct _ENCOMSP_FILTER_UPDATED_PDU ENCOMSP_FILTER_UPDATED_PDU; + +struct _ENCOMSP_APPLICATION_CREATED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT16 Flags; + UINT32 AppId; + ENCOMSP_UNICODE_STRING Name; +}; +typedef struct _ENCOMSP_APPLICATION_CREATED_PDU ENCOMSP_APPLICATION_CREATED_PDU; + +struct _ENCOMSP_APPLICATION_REMOVED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 AppId; +}; +typedef struct _ENCOMSP_APPLICATION_REMOVED_PDU ENCOMSP_APPLICATION_REMOVED_PDU; + +struct _ENCOMSP_WINDOW_CREATED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT16 Flags; + UINT32 AppId; + UINT32 WndId; + ENCOMSP_UNICODE_STRING Name; +}; +typedef struct _ENCOMSP_WINDOW_CREATED_PDU ENCOMSP_WINDOW_CREATED_PDU; + +struct _ENCOMSP_WINDOW_REMOVED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 WndId; +}; +typedef struct _ENCOMSP_WINDOW_REMOVED_PDU ENCOMSP_WINDOW_REMOVED_PDU; + +struct _ENCOMSP_SHOW_WINDOW_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 WndId; +}; +typedef struct _ENCOMSP_SHOW_WINDOW_PDU ENCOMSP_SHOW_WINDOW_PDU; + +struct _ENCOMSP_PARTICIPANT_CREATED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 ParticipantId; + UINT32 GroupId; + UINT16 Flags; + ENCOMSP_UNICODE_STRING FriendlyName; +}; +typedef struct _ENCOMSP_PARTICIPANT_CREATED_PDU ENCOMSP_PARTICIPANT_CREATED_PDU; + +struct _ENCOMSP_PARTICIPANT_REMOVED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 ParticipantId; + UINT32 DiscType; + UINT32 DiscCode; +}; +typedef struct _ENCOMSP_PARTICIPANT_REMOVED_PDU ENCOMSP_PARTICIPANT_REMOVED_PDU; + +struct _ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT16 Flags; + UINT32 ParticipantId; +}; +typedef struct _ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU; + +struct _ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); +}; +typedef struct _ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU; + +struct _ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); +}; +typedef struct _ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU; + #endif /* FREERDP_CHANNEL_ENCOMSP_H */ diff --git a/include/freerdp/client/encomsp.h b/include/freerdp/client/encomsp.h index f97732908..e8b8466e1 100644 --- a/include/freerdp/client/encomsp.h +++ b/include/freerdp/client/encomsp.h @@ -28,10 +28,34 @@ typedef struct _encomsp_client_context EncomspClientContext; +typedef int (*pcEncomspFilterUpdated)(EncomspClientContext* context, ENCOMSP_FILTER_UPDATED_PDU* filterUpdated); +typedef int (*pcEncomspApplicationCreated)(EncomspClientContext* context, ENCOMSP_APPLICATION_CREATED_PDU* applicationCreated); +typedef int (*pcEncomspApplicationRemoved)(EncomspClientContext* context, ENCOMSP_APPLICATION_REMOVED_PDU* applicationRemoved); +typedef int (*pcEncomspWindowCreated)(EncomspClientContext* context, ENCOMSP_WINDOW_CREATED_PDU* windowCreated); +typedef int (*pcEncomspWindowRemoved)(EncomspClientContext* context, ENCOMSP_WINDOW_REMOVED_PDU* windowRemoved); +typedef int (*pcEncomspShowWindow)(EncomspClientContext* context, ENCOMSP_SHOW_WINDOW_PDU* showWindow); +typedef int (*pcEncomspParticipantCreated)(EncomspClientContext* context, ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated); +typedef int (*pcEncomspParticipantRemoved)(EncomspClientContext* context, ENCOMSP_PARTICIPANT_REMOVED_PDU* participantRemoved); +typedef int (*pcEncomspChangeParticipantControlLevel)(EncomspClientContext* context, ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* changeParticipantControlLevel); +typedef int (*pcEncomspGraphicsStreamPaused)(EncomspClientContext* context, ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU* graphicsStreamPaused); +typedef int (*pcEncomspGraphicsStreamResumed)(EncomspClientContext* context, ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU* graphicsStreamResumed); + struct _encomsp_client_context { void* handle; void* custom; + + pcEncomspFilterUpdated FilterUpdated; + pcEncomspApplicationCreated ApplicationCreated; + pcEncomspApplicationRemoved ApplicationRemoved; + pcEncomspWindowCreated WindowCreated; + pcEncomspWindowRemoved WindowRemoved; + pcEncomspShowWindow ShowWindow; + pcEncomspParticipantCreated ParticipantCreated; + pcEncomspParticipantRemoved ParticipantRemoved; + pcEncomspChangeParticipantControlLevel ChangeParticipantControlLevel; + pcEncomspGraphicsStreamPaused GraphicsStreamPaused; + pcEncomspGraphicsStreamResumed GraphicsStreamResumed; }; #endif /* FREERDP_CHANNEL_CLIENT_ENCOMSP_H */ From f07ab94703807aa1046931c48392e6a29f701a10 Mon Sep 17 00:00:00 2001 From: Hardening Date: Wed, 25 Jun 2014 17:35:20 +0200 Subject: [PATCH 06/23] Fix conflicting define WTSVirtualEventHandle and WTSVirtualChannelReady are already defined in wtsapi.h and with different values. --- include/freerdp/channels/wtsvc.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/freerdp/channels/wtsvc.h b/include/freerdp/channels/wtsvc.h index df6dead5d..66ee9eb24 100644 --- a/include/freerdp/channels/wtsvc.h +++ b/include/freerdp/channels/wtsvc.h @@ -37,12 +37,8 @@ #include #include - #include -#define WTSVirtualEventHandle 3 /* Extended */ -#define WTSVirtualChannelReady 4 /* Extended */ - #ifdef __cplusplus extern "C" { #endif From f1a866340ec9e4f348b6d8cabeccfeb6a992c614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 25 Jun 2014 15:21:02 -0400 Subject: [PATCH 07/23] server/Sample: stub server-side encomsp channel --- server/Sample/CMakeLists.txt | 4 +++- server/Sample/sf_encomsp.c | 37 ++++++++++++++++++++++++++++++++++++ server/Sample/sf_encomsp.h | 31 ++++++++++++++++++++++++++++++ server/Sample/sfreerdp.c | 11 ++++++++++- server/Sample/sfreerdp.h | 2 ++ 5 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 server/Sample/sf_encomsp.c create mode 100644 server/Sample/sf_encomsp.h diff --git a/server/Sample/CMakeLists.txt b/server/Sample/CMakeLists.txt index 972cc29f6..638a5fef0 100644 --- a/server/Sample/CMakeLists.txt +++ b/server/Sample/CMakeLists.txt @@ -24,7 +24,9 @@ set(${MODULE_PREFIX}_SRCS sf_audin.c sf_audin.h sf_rdpsnd.c - sf_rdpsnd.h) + sf_rdpsnd.h + sf_encomsp.c + sf_encomsp.h) add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) diff --git a/server/Sample/sf_encomsp.c b/server/Sample/sf_encomsp.c new file mode 100644 index 000000000..a152182aa --- /dev/null +++ b/server/Sample/sf_encomsp.c @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Sample Server (Lync Multiparty) + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "sf_encomsp.h" + +BOOL sf_peer_encomsp_init(testPeerContext* context) +{ + context->encomsp = encomsp_server_context_new(context->vcm); + + if (!context->encomsp) + return FALSE; + + if (context->encomsp->Start(context->encomsp) < 0) + return FALSE; + + return TRUE; +} diff --git a/server/Sample/sf_encomsp.h b/server/Sample/sf_encomsp.h new file mode 100644 index 000000000..f2abd3116 --- /dev/null +++ b/server/Sample/sf_encomsp.h @@ -0,0 +1,31 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Sample Server (Lync Multiparty) + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SF_ENCOMSP_H +#define SF_ENCOMSP_H + +#include +#include +#include + +#include "sfreerdp.h" + +BOOL sf_peer_encomsp_init(testPeerContext* context); + +#endif /* SF_ENCOMSP_H */ diff --git a/server/Sample/sfreerdp.c b/server/Sample/sfreerdp.c index 3a2d36d06..a990d4a73 100644 --- a/server/Sample/sfreerdp.c +++ b/server/Sample/sfreerdp.c @@ -30,16 +30,17 @@ #include #include + #include #include - #include #include #include #include "sf_audin.h" #include "sf_rdpsnd.h" +#include "sf_encomsp.h" #include "sfreerdp.h" @@ -96,6 +97,9 @@ void test_peer_context_free(freerdp_peer* client, testPeerContext* context) if (context->rdpsnd) rdpsnd_server_context_free(context->rdpsnd); + if (context->encomsp) + encomsp_server_context_free(context->encomsp); + WTSCloseServer((HANDLE) context->vcm); } } @@ -516,6 +520,11 @@ BOOL tf_peer_post_connect(freerdp_peer* client) sf_peer_rdpsnd_init(context); /* Audio Output */ } + if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "encomsp")) + { + sf_peer_encomsp_init(context); /* Lync Multiparty */ + } + /* Dynamic Virtual Channels */ sf_peer_audin_init(context); /* Audio Input */ diff --git a/server/Sample/sfreerdp.h b/server/Sample/sfreerdp.h index a052da93d..0c0e1cf13 100644 --- a/server/Sample/sfreerdp.h +++ b/server/Sample/sfreerdp.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,7 @@ struct test_peer_context BOOL audin_open; UINT32 frame_id; RdpsndServerContext* rdpsnd; + EncomspServerContext* encomsp; }; typedef struct test_peer_context testPeerContext; From d2d04f764d09389b66786c7fbb19ffc13f2bec4a Mon Sep 17 00:00:00 2001 From: bjcollins Date: Fri, 27 Jun 2014 14:46:27 -0500 Subject: [PATCH 08/23] Find glibconfig.h cmake should use pkgconfig information instead of a hard coded path to /usr/lib. the OnOpen callback should be called when set to avoid a segfault. --- channels/drdynvc/client/dvcman.c | 3 ++- channels/tsmf/client/tsmf_main.c | 1 + cmake/FindGlib.cmake | 5 ++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/channels/drdynvc/client/dvcman.c b/channels/drdynvc/client/dvcman.c index bd3718a60..a29e5509e 100644 --- a/channels/drdynvc/client/dvcman.c +++ b/channels/drdynvc/client/dvcman.c @@ -409,7 +409,8 @@ int dvcman_open_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId if (channel->status == 0) { pCallback = channel->channel_callback; - pCallback->OnOpen(pCallback); + if (pCallback->OnOpen) + pCallback->OnOpen(pCallback); } return 0; diff --git a/channels/tsmf/client/tsmf_main.c b/channels/tsmf/client/tsmf_main.c index ec0426fba..e6fd20530 100644 --- a/channels/tsmf/client/tsmf_main.c +++ b/channels/tsmf/client/tsmf_main.c @@ -329,6 +329,7 @@ static int tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallbac ZeroMemory(callback, sizeof(TSMF_CHANNEL_CALLBACK)); callback->iface.OnDataReceived = tsmf_on_data_received; callback->iface.OnClose = tsmf_on_close; + callback->iface.OnOpen = NULL; callback->plugin = listener_callback->plugin; callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; diff --git a/cmake/FindGlib.cmake b/cmake/FindGlib.cmake index 3e22eb075..8005ce12b 100644 --- a/cmake/FindGlib.cmake +++ b/cmake/FindGlib.cmake @@ -28,11 +28,10 @@ find_library(Gobject_LIBRARY PATHS ${Glib_PKGCONF_LIBRARY_DIRS} ${GLIB_ROOT_DIR} ) -# Glib-related libraries also use a separate config header, which is in lib dir +# Glib-related libraries also use a separate config header, which is relative to lib dir find_path(GlibConfig_INCLUDE_DIR NAMES glibconfig.h - PATHS ${Glib_PKGCONF_INCLUDE_DIRS} /usr ${GLIB_ROOT_DIR} - PATH_SUFFIXES lib/glib-2.0/include glib-2.0/include + PATHS ${Glib_PKGCONF_INCLUDE_DIRS} ${GLIB_ROOT_DIR} ) # Set the include dir variables and the libraries and let libfind_process do the rest. From f6b6c1188b41dfb4c52da21717e2b37aa0526b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 28 Jun 2014 16:04:49 -0400 Subject: [PATCH 09/23] client/common: start parsing of .msrcIncident Remote Assistance file --- client/common/CMakeLists.txt | 6 +- client/common/assistance.c | 443 ++++++++++++++++++++++ client/common/test/CMakeLists.txt | 3 +- client/common/test/TestClientAssistance.c | 77 ++++ include/freerdp/client/assistance.h | 59 +++ 5 files changed, 585 insertions(+), 3 deletions(-) create mode 100644 client/common/assistance.c create mode 100644 client/common/test/TestClientAssistance.c create mode 100644 include/freerdp/client/assistance.h diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index a7a39de91..bde787ec1 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -28,6 +28,7 @@ endif() set(${MODULE_PREFIX}_SRCS client.c cmdline.c + assistance.c compatibility.c compatibility.h file.c) @@ -52,6 +53,9 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVER set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${FREERDP_CHANNELS_CLIENT_LIBS}) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} + ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES}) + set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp MODULES freerdp-core) @@ -60,8 +64,6 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHI MODULE winpr MODULES winpr-crt winpr-utils) - - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT FreeRDPTargets) diff --git a/client/common/assistance.c b/client/common/assistance.c new file mode 100644 index 000000000..1aa9ab169 --- /dev/null +++ b/client/common/assistance.c @@ -0,0 +1,443 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/** + * CryptDeriveKey Function: + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa379916/ + * + * Let n be the required derived key length, in bytes. + * The derived key is the first n bytes of the hash value after the hash computation + * has been completed by CryptDeriveKey. If the hash is not a member of the SHA-2 + * family and the required key is for either 3DES or AES, the key is derived as follows: + * + * Form a 64-byte buffer by repeating the constant 0x36 64 times. + * Let k be the length of the hash value that is represented by the input parameter hBaseData. + * Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes + * of the buffer with the hash value that is represented by the input parameter hBaseData. + * + * Form a 64-byte buffer by repeating the constant 0x5C 64 times. + * Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes + * of the buffer with the hash value that is represented by the input parameter hBaseData. + * + * Hash the result of step 1 by using the same hash algorithm as that used to compute the hash + * value that is represented by the hBaseData parameter. + * + * Hash the result of step 2 by using the same hash algorithm as that used to compute the hash + * value that is represented by the hBaseData parameter. + * + * Concatenate the result of step 3 with the result of step 4. + * Use the first n bytes of the result of step 5 as the derived key. + */ + +int freerdp_client_assistance_crypt_derive_key(BYTE* hash, int hashLength, BYTE* key, int keyLength) +{ + int i; + BYTE* bufferHash; + BYTE buffer36[64]; + BYTE buffer5c[64]; + + memset(buffer36, 0x36, sizeof(buffer36)); + memset(buffer5c, 0x5C, sizeof(buffer5c)); + + for (i = 0; i < hashLength; i++) + { + buffer36[i] ^= hash[i]; + buffer5c[i] ^= hash[i]; + } + + bufferHash = (BYTE*) calloc(1, hashLength * 2); + + if (!bufferHash) + return -1; + + SHA1(buffer36, 64, bufferHash); + SHA1(buffer5c, 64, &bufferHash[hashLength]); + + CopyMemory(key, bufferHash, keyLength); + + free(bufferHash); + + return 1; +} + +int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* password) +{ + int status; + SHA_CTX shaCtx; + int cbOut, cbFinal; + EVP_CIPHER_CTX aesDec; + WCHAR* PasswordW = NULL; + BYTE EncryptionKey[AES_BLOCK_SIZE]; + BYTE PasswordHash[SHA_DIGEST_LENGTH]; + + status = ConvertToUnicode(CP_UTF8, 0, password, -1, &PasswordW, 0); + + if (status <= 0) + return -1; + + SHA_Init(&shaCtx); + SHA_Update(&shaCtx, PasswordW, status * 2); + SHA_Final((void*) PasswordHash, &shaCtx); + + status = freerdp_client_assistance_crypt_derive_key(PasswordHash, sizeof(PasswordHash), + EncryptionKey, sizeof(EncryptionKey)); + + if (status < 0) + return -1; + + EVP_CIPHER_CTX_init(&aesDec); + + status = EVP_DecryptInit(&aesDec, EVP_aes_128_cbc(), EncryptionKey, NULL); + + if (status != 1) + return -1; + + cbOut = file->EncryptedConnectionStringLength; + file->ConnectionString = (char*) calloc(1, cbOut); + + if (!file->ConnectionString) + return -1; + + status = EVP_DecryptUpdate(&aesDec, (BYTE*) file->ConnectionString, &cbOut, + (BYTE*) file->EncryptedConnectionString, file->EncryptedConnectionStringLength); + if (status != 1) + return -1; + + status = EVP_DecryptFinal(&aesDec, (BYTE*) &file->ConnectionString[cbOut], &cbFinal); + + /* FIXME: still fails */ + + if (status != 1) + return -1; + + return 1; +} + +BYTE* freerdp_client_assistance_parse_hex_string(const char* hexStr, int* size) +{ + char c; + int length; + BYTE* buffer; + int i, ln, hn; + + length = strlen(hexStr); + + if ((length % 2) != 0) + return NULL; + + length /= 2; + *size = length; + + buffer = (BYTE*) malloc(length); + + if (!buffer) + return NULL; + + for (i = 0; i < length; i++) + { + hn = ln = 0; + + c = hexStr[(i * 2) + 0]; + + if ((c >= '0') && (c <= '9')) + hn = c - '0'; + else if ((c >= 'a') && (c <= 'f')) + hn = (c - 'a') + 10; + else if ((c >= 'A') && (c <= 'F')) + hn = (c - 'A') + 10; + + c = hexStr[(i * 2) + 1]; + + if ((c >= '0') && (c <= '9')) + ln = c - '0'; + else if ((c >= 'a') && (c <= 'f')) + ln = (c - 'a') + 10; + else if ((c >= 'A') && (c <= 'F')) + ln = (c - 'A') + 10; + + buffer[i] = (hn << 4) | ln; + } + + return buffer; +} + +int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size) +{ + char* p; + char* q; + char* r; + int value; + size_t length; + + p = strstr(buffer, "UPLOADINFO"); + + if (!p) + return -1; + + p = strstr(p + sizeof("UPLOADINFO") - 1, "TYPE=\""); + + if (!p) + return -1; + + p = strstr(buffer, "UPLOADDATA"); + + if (!p) + return -1; + + /* Parse USERNAME */ + + p = strstr(buffer, "USERNAME=\""); + + if (p) + { + p += sizeof("USERNAME=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + file->Username = (char*) malloc(length + 1); + + if (!file->Username) + return -1; + + CopyMemory(file->Username, p, length); + file->Username[length] = '\0'; + } + + /* Parse LHTICKET */ + + p = strstr(buffer, "LHTICKET=\""); + + if (p) + { + p += sizeof("LHTICKET=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + file->LHTicket = (char*) malloc(length + 1); + + if (!file->LHTicket) + return -1; + + CopyMemory(file->LHTicket, p, length); + file->LHTicket[length] = '\0'; + } + + /* Parse RCTICKET */ + + p = strstr(buffer, "RCTICKET=\""); + + if (p) + { + p += sizeof("RCTICKET=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + file->RCTicket = (char*) malloc(length + 1); + + if (!file->RCTicket) + return -1; + + CopyMemory(file->RCTicket, p, length); + file->RCTicket[length] = '\0'; + } + + /* Parse RCTICKETENCRYPTED */ + + p = strstr(buffer, "RCTICKETENCRYPTED=\""); + + if (p) + { + p += sizeof("RCTICKETENCRYPTED=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + + if ((length == 1) && (p[0] == '1')) + file->RCTicketEncrypted = TRUE; + } + + /* Parse PassStub */ + + p = strstr(buffer, "PassStub=\""); + + if (p) + { + p += sizeof("PassStub=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + file->PassStub = (char*) malloc(length + 1); + + if (!file->PassStub) + return -1; + + CopyMemory(file->PassStub, p, length); + file->PassStub[length] = '\0'; + } + + /* Parse DtStart */ + + p = strstr(buffer, "DtStart=\""); + + if (p) + { + p += sizeof("DtStart=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + + r = (char*) malloc(length + 1); + + if (!r) + return -1; + + CopyMemory(r, p, length); + r[length] = '\0'; + + value = atoi(r); + free(r); + + if (value < 0) + return -1; + + file->DtStart = (UINT32) value; + } + + /* Parse DtLength */ + + p = strstr(buffer, "DtLength=\""); + + if (p) + { + p += sizeof("DtLength=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + + r = (char*) malloc(length + 1); + + if (!r) + return -1; + + CopyMemory(r, p, length); + r[length] = '\0'; + + value = atoi(r); + free(r); + + if (value < 0) + return -1; + + file->DtLength = (UINT32) value; + } + + /* Parse L (LowSpeed) */ + + p = strstr(buffer, " L=\""); + + if (p) + { + p += sizeof(" L=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + + if ((length == 1) && (p[0] == '1')) + file->LowSpeed = TRUE; + } + + file->EncryptedConnectionString = freerdp_client_assistance_parse_hex_string(file->LHTicket, + &file->EncryptedConnectionStringLength); + + return 1; +} + +rdpAssistanceFile* freerdp_client_assistance_file_new() +{ + rdpAssistanceFile* file; + + file = (rdpAssistanceFile*) calloc(1, sizeof(rdpAssistanceFile)); + + if (file) + { + + } + + return file; +} + +void freerdp_client_assistance_file_free(rdpAssistanceFile* file) +{ + if (!file) + return; + + free(file->Username); + free(file->LHTicket); + free(file->RCTicket); + free(file->PassStub); + free(file->ConnectionString); + free(file->EncryptedConnectionString); + + free(file); +} diff --git a/client/common/test/CMakeLists.txt b/client/common/test/CMakeLists.txt index b68ac11e7..bdb18ede5 100644 --- a/client/common/test/CMakeLists.txt +++ b/client/common/test/CMakeLists.txt @@ -6,7 +6,8 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS TestClientRdpFile.c - TestClientChannels.c) + TestClientChannels.c + TestClientAssistance.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} diff --git a/client/common/test/TestClientAssistance.c b/client/common/test/TestClientAssistance.c new file mode 100644 index 000000000..54fa1dcb3 --- /dev/null +++ b/client/common/test/TestClientAssistance.c @@ -0,0 +1,77 @@ + +#include +#include + +#include + +const char* TEST_MSRC_INCIDENT_PASSWORD = "48BJQ853X3B4"; + +static const char* TEST_MSRC_INCIDENT_FILE = +"" +"" +"" +""; + +int TestClientAssistance(int argc, char* argv[]) +{ + int status; + rdpAssistanceFile* file; + + file = freerdp_client_assistance_file_new(); + + status = freerdp_client_assistance_parse_file_buffer(file, TEST_MSRC_INCIDENT_FILE, sizeof(TEST_MSRC_INCIDENT_FILE)); + + printf("freerdp_client_assistance_parse_file_buffer: %d\n", status); + + if (status < 0) + return -1; + + printf("Username: %s\n", file->Username); + printf("LHTicket: %s\n", file->LHTicket); + printf("RCTicket: %s\n", file->RCTicket); + printf("RCTicketEncrypted: %d\n", file->RCTicketEncrypted); + printf("PassStub: %s\n", file->PassStub); + printf("DtStart: %d\n", file->DtStart); + printf("DtLength: %d\n", file->DtLength); + printf("LowSpeed: %d\n", file->LowSpeed); + + status = freerdp_client_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD); + + printf("freerdp_client_assistance_decrypt: %d\n", status); + + if (status < 0) + return -1; + + freerdp_client_assistance_file_free(file); + + return 0; +} + diff --git a/include/freerdp/client/assistance.h b/include/freerdp/client/assistance.h new file mode 100644 index 000000000..fb1542192 --- /dev/null +++ b/include/freerdp/client/assistance.h @@ -0,0 +1,59 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CLIENT_ASSISTANCE_H +#define FREERDP_CLIENT_ASSISTANCE_H + +#include +#include + +struct rdp_assistance_file +{ + char* Type; + char* Username; + char* LHTicket; + char* RCTicket; + char* PassStub; + UINT32 DtStart; + UINT32 DtLength; + BOOL LowSpeed; + BOOL RCTicketEncrypted; + + char* ConnectionString; + BYTE* EncryptedConnectionString; + int EncryptedConnectionStringLength; +}; +typedef struct rdp_assistance_file rdpAssistanceFile; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size); +FREERDP_API int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* password); + +FREERDP_API rdpAssistanceFile* freerdp_client_assistance_file_new(); +FREERDP_API void freerdp_client_assistance_file_free(rdpAssistanceFile* file); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CLIENT_ASSISTANCE_H */ + From 1d8221d95bc5a047a8e7186e5a6f1752e53bac90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 28 Jun 2014 17:03:16 -0400 Subject: [PATCH 10/23] client/common: parse RCTICKET Connection String 1 --- client/common/assistance.c | 184 ++++++++++++++++++++-- client/common/test/TestClientAssistance.c | 5 + include/freerdp/client/assistance.h | 16 +- 3 files changed, 191 insertions(+), 14 deletions(-) diff --git a/client/common/assistance.c b/client/common/assistance.c index 1aa9ab169..45408bfc6 100644 --- a/client/common/assistance.c +++ b/client/common/assistance.c @@ -97,7 +97,54 @@ int freerdp_client_assistance_crypt_derive_key(BYTE* hash, int hashLength, BYTE* return 1; } -int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* password) +int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* password) +{ + int status; + RC4_KEY rc4; + MD5_CTX md5Ctx; + int PassStubLength; + BYTE* PlainBlob = NULL; + WCHAR* PasswordW = NULL; + BYTE EncryptionKey[AES_BLOCK_SIZE]; + BYTE PasswordHash[MD5_DIGEST_LENGTH]; + + status = ConvertToUnicode(CP_UTF8, 0, password, -1, &PasswordW, 0); + + if (status <= 0) + return -1; + + MD5_Init(&md5Ctx); + MD5_Update(&md5Ctx, PasswordW, status * 2); + MD5_Final((void*) PasswordHash, &md5Ctx); + + status = freerdp_client_assistance_crypt_derive_key(PasswordHash, sizeof(PasswordHash), + EncryptionKey, sizeof(EncryptionKey)); + + if (status < 0) + return -1; + + PassStubLength = strlen(file->PassStub); + file->EncryptedPassStubLength = PassStubLength + 4; + + PlainBlob = (BYTE*) calloc(1, file->EncryptedPassStubLength); + file->EncryptedPassStub = (BYTE*) calloc(1, file->EncryptedPassStubLength); + + if (!PlainBlob) + return -1; + + if (!file->EncryptedPassStubLength) + return -1; + + *((UINT32*) PlainBlob) = PassStubLength; + CopyMemory(&PlainBlob[4], file->PassStub, PassStubLength); + + RC4_set_key(&rc4, sizeof(EncryptionKey), EncryptionKey); + RC4(&rc4, file->EncryptedPassStubLength, PlainBlob, file->EncryptedPassStub); + + return 1; +} + +int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* password) { int status; SHA_CTX shaCtx; @@ -129,18 +176,18 @@ int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* passw if (status != 1) return -1; - cbOut = file->EncryptedConnectionStringLength; - file->ConnectionString = (char*) calloc(1, cbOut); + cbOut = file->EncryptedLHTicketLength; + file->ConnectionString2 = (char*) calloc(1, cbOut); - if (!file->ConnectionString) + if (!file->ConnectionString2) return -1; - status = EVP_DecryptUpdate(&aesDec, (BYTE*) file->ConnectionString, &cbOut, - (BYTE*) file->EncryptedConnectionString, file->EncryptedConnectionStringLength); + status = EVP_DecryptUpdate(&aesDec, (BYTE*) file->ConnectionString2, &cbOut, + (BYTE*) file->EncryptedLHTicket, file->EncryptedLHTicketLength); if (status != 1) return -1; - status = EVP_DecryptFinal(&aesDec, (BYTE*) &file->ConnectionString[cbOut], &cbFinal); + status = EVP_DecryptFinal(&aesDec, (BYTE*) &file->ConnectionString2[cbOut], &cbFinal); /* FIXME: still fails */ @@ -150,6 +197,17 @@ int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* passw return 1; } +int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* password) +{ + int status; + + status = freerdp_client_assistance_decrypt1(file, password); + + freerdp_client_assistance_decrypt2(file, password); + + return status; +} + BYTE* freerdp_client_assistance_parse_hex_string(const char* hexStr, int* size) { char c; @@ -198,12 +256,108 @@ BYTE* freerdp_client_assistance_parse_hex_string(const char* hexStr, int* size) return buffer; } +int freerdp_client_assistance_parse_connection_string1(rdpAssistanceFile* file) +{ + int i; + char* p; + char* q; + char* str; + int count; + int length; + char* list; + char* tokens[8]; + + /** + * ,,,, + * ,,, + */ + + count = 1; + str = _strdup(file->RCTicket); + + if (!str) + return -1; + + length = strlen(str); + + for (i = 0; i < length; i++) + { + if (str[i] == ',') + count++; + } + + if (count != 8) + return -1; + + count = 0; + tokens[count++] = str; + + for (i = 0; i < length; i++) + { + if (str[i] == ',') + { + str[i] = '\0'; + tokens[count++] = &str[i + 1]; + } + } + + if (strcmp(tokens[0], "65538") != 0) + return -1; + + if (strcmp(tokens[1], "1") != 0) + return -1; + + if (strcmp(tokens[3], "*") != 0) + return -1; + + if (strcmp(tokens[5], "*") != 0) + return -1; + + if (strcmp(tokens[6], "*") != 0) + return -1; + + file->RASessionId = _strdup(tokens[4]); + + if (!file->RASessionId) + return -1; + + file->RASpecificParams = _strdup(tokens[7]); + + 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); + + free(str); + + return 1; +} + int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size) { char* p; char* q; char* r; int value; + int status; size_t length; p = strstr(buffer, "UPLOADINFO"); @@ -407,8 +561,16 @@ int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const c file->LowSpeed = TRUE; } - file->EncryptedConnectionString = freerdp_client_assistance_parse_hex_string(file->LHTicket, - &file->EncryptedConnectionStringLength); + file->EncryptedLHTicket = freerdp_client_assistance_parse_hex_string(file->LHTicket, + &file->EncryptedLHTicketLength); + + status = freerdp_client_assistance_parse_connection_string1(file); + + if (status < 0) + { + fprintf(stderr, "freerdp_client_assistance_parse_connection_string1 failure: %d\n", status); + return -1; + } return 1; } @@ -436,8 +598,8 @@ void freerdp_client_assistance_file_free(rdpAssistanceFile* file) free(file->LHTicket); free(file->RCTicket); free(file->PassStub); - free(file->ConnectionString); - free(file->EncryptedConnectionString); + free(file->ConnectionString2); + free(file->EncryptedLHTicket); free(file); } diff --git a/client/common/test/TestClientAssistance.c b/client/common/test/TestClientAssistance.c index 54fa1dcb3..7aeef14e5 100644 --- a/client/common/test/TestClientAssistance.c +++ b/client/common/test/TestClientAssistance.c @@ -63,6 +63,11 @@ int TestClientAssistance(int argc, char* argv[]) printf("DtLength: %d\n", file->DtLength); printf("LowSpeed: %d\n", file->LowSpeed); + printf("RASessionId: %s\n", file->RASessionId); + printf("RASpecificParams: %s\n", file->RASpecificParams); + printf("MachineAddress: %s\n", file->MachineAddress); + printf("MachinePort: %d\n", (int) file->MachinePort); + status = freerdp_client_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD); printf("freerdp_client_assistance_decrypt: %d\n", status); diff --git a/include/freerdp/client/assistance.h b/include/freerdp/client/assistance.h index fb1542192..00068a73e 100644 --- a/include/freerdp/client/assistance.h +++ b/include/freerdp/client/assistance.h @@ -35,9 +35,19 @@ struct rdp_assistance_file BOOL LowSpeed; BOOL RCTicketEncrypted; - char* ConnectionString; - BYTE* EncryptedConnectionString; - int EncryptedConnectionStringLength; + char* ConnectionString1; + char* ConnectionString2; + + BYTE* EncryptedPassStub; + int EncryptedPassStubLength; + + BYTE* EncryptedLHTicket; + int EncryptedLHTicketLength; + + char* MachineAddress; + UINT32 MachinePort; + char* RASessionId; + char* RASpecificParams; }; typedef struct rdp_assistance_file rdpAssistanceFile; From f7f07c56ba380c26a78392b078818188f1bf562b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 28 Jun 2014 17:24:44 -0400 Subject: [PATCH 11/23] channels/remdesk: stub virtual channel --- channels/remdesk/CMakeLists.txt | 26 ++ channels/remdesk/ChannelOptions.cmake | 12 + channels/remdesk/client/CMakeLists.txt | 35 +++ channels/remdesk/client/remdesk_main.c | 330 +++++++++++++++++++++++++ channels/remdesk/client/remdesk_main.h | 48 ++++ channels/remdesk/server/CMakeLists.txt | 37 +++ channels/remdesk/server/remdesk_main.c | 157 ++++++++++++ channels/remdesk/server/remdesk_main.h | 37 +++ include/freerdp/channels/remdesk.h | 29 +++ include/freerdp/client/remdesk.h | 38 +++ include/freerdp/server/remdesk.h | 53 ++++ 11 files changed, 802 insertions(+) create mode 100644 channels/remdesk/CMakeLists.txt create mode 100644 channels/remdesk/ChannelOptions.cmake create mode 100644 channels/remdesk/client/CMakeLists.txt create mode 100644 channels/remdesk/client/remdesk_main.c create mode 100644 channels/remdesk/client/remdesk_main.h create mode 100644 channels/remdesk/server/CMakeLists.txt create mode 100644 channels/remdesk/server/remdesk_main.c create mode 100644 channels/remdesk/server/remdesk_main.h create mode 100644 include/freerdp/channels/remdesk.h create mode 100644 include/freerdp/client/remdesk.h create mode 100644 include/freerdp/server/remdesk.h diff --git a/channels/remdesk/CMakeLists.txt b/channels/remdesk/CMakeLists.txt new file mode 100644 index 000000000..23f1cf7b2 --- /dev/null +++ b/channels/remdesk/CMakeLists.txt @@ -0,0 +1,26 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel("remdesk") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() + +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/remdesk/ChannelOptions.cmake b/channels/remdesk/ChannelOptions.cmake new file mode 100644 index 000000000..17518e619 --- /dev/null +++ b/channels/remdesk/ChannelOptions.cmake @@ -0,0 +1,12 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "remdesk" TYPE "static" + DESCRIPTION "Remote Assistance Virtual Channel Extension" + SPECIFICATIONS "[MS-RA]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) diff --git a/channels/remdesk/client/CMakeLists.txt b/channels/remdesk/client/CMakeLists.txt new file mode 100644 index 000000000..9d8323634 --- /dev/null +++ b/channels/remdesk/client/CMakeLists.txt @@ -0,0 +1,35 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_client("remdesk") + +set(${MODULE_PREFIX}_SRCS + remdesk_main.c + remdesk_main.h) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-crt) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c new file mode 100644 index 000000000..feeb7e4db --- /dev/null +++ b/channels/remdesk/client/remdesk_main.c @@ -0,0 +1,330 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include "remdesk_main.h" + +RemdeskClientContext* remdesk_get_client_interface(remdeskPlugin* remdesk) +{ + RemdeskClientContext* pInterface; + pInterface = (RemdeskClientContext*) remdesk->channelEntryPoints.pInterface; + return pInterface; +} + +static int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) +{ + int status = 1; + + printf("RemDeskReceive: %d\n", Stream_Length(s)); + winpr_HexDump(Stream_Buffer(s), Stream_Length(s)); + + return status; +} + +static void remdesk_process_connect(remdeskPlugin* remdesk) +{ + printf("RemdeskProcessConnect\n"); +} + +/****************************************************************************************/ + +static wListDictionary* g_InitHandles; +static wListDictionary* g_OpenHandles; + +void remdesk_add_init_handle_data(void* pInitHandle, void* pUserData) +{ + if (!g_InitHandles) + g_InitHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_InitHandles, pInitHandle, pUserData); +} + +void* remdesk_get_init_handle_data(void* pInitHandle) +{ + void* pUserData = NULL; + pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle); + return pUserData; +} + +void remdesk_remove_init_handle_data(void* pInitHandle) +{ + ListDictionary_Remove(g_InitHandles, pInitHandle); +} + +void remdesk_add_open_handle_data(DWORD openHandle, void* pUserData) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + + if (!g_OpenHandles) + g_OpenHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData); +} + +void* remdesk_get_open_handle_data(DWORD openHandle) +{ + void* pUserData = NULL; + void* pOpenHandle = (void*) (size_t) openHandle; + pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle); + return pUserData; +} + +void remdesk_remove_open_handle_data(DWORD openHandle) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + ListDictionary_Remove(g_OpenHandles, pOpenHandle); +} + +int remdesk_send(remdeskPlugin* remdesk, wStream* s) +{ + UINT32 status = 0; + remdeskPlugin* plugin = (remdeskPlugin*) remdesk; + + if (!plugin) + { + status = CHANNEL_RC_BAD_INIT_HANDLE; + } + else + { + status = plugin->channelEntryPoints.pVirtualChannelWrite(plugin->OpenHandle, + Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + } + + if (status != CHANNEL_RC_OK) + { + Stream_Free(s, TRUE); + fprintf(stderr, "remdesk_send: VirtualChannelWrite failed %d\n", status); + } + + return status; +} + +static void remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, + void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + wStream* data_in; + + if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME)) + { + return; + } + + if (dataFlags & CHANNEL_FLAG_FIRST) + { + if (remdesk->data_in) + Stream_Free(remdesk->data_in, TRUE); + + remdesk->data_in = Stream_New(NULL, totalLength); + } + + data_in = remdesk->data_in; + Stream_EnsureRemainingCapacity(data_in, (int) dataLength); + Stream_Write(data_in, pData, dataLength); + + if (dataFlags & CHANNEL_FLAG_LAST) + { + if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) + { + fprintf(stderr, "remdesk_plugin_process_received: read error\n"); + } + + remdesk->data_in = NULL; + Stream_SealLength(data_in); + Stream_SetPosition(data_in, 0); + + MessageQueue_Post(remdesk->MsgPipe->In, NULL, 0, (void*) data_in, NULL); + } +} + +static VOID VCAPITYPE remdesk_virtual_channel_open_event(DWORD openHandle, UINT event, + LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + remdeskPlugin* remdesk; + + remdesk = (remdeskPlugin*) remdesk_get_open_handle_data(openHandle); + + if (!remdesk) + { + fprintf(stderr, "remdesk_virtual_channel_open_event: error no match\n"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_DATA_RECEIVED: + remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength, totalLength, dataFlags); + break; + + case CHANNEL_EVENT_WRITE_COMPLETE: + Stream_Free((wStream*) pData, TRUE); + break; + + case CHANNEL_EVENT_USER: + break; + } +} + +static void* remdesk_virtual_channel_client_thread(void* arg) +{ + wStream* data; + wMessage message; + remdeskPlugin* remdesk = (remdeskPlugin*) arg; + + remdesk_process_connect(remdesk); + + while (1) + { + if (!MessageQueue_Wait(remdesk->MsgPipe->In)) + break; + + if (MessageQueue_Peek(remdesk->MsgPipe->In, &message, TRUE)) + { + if (message.id == WMQ_QUIT) + break; + + if (message.id == 0) + { + data = (wStream*) message.wParam; + remdesk_process_receive(remdesk, data); + } + } + } + + ExitThread(0); + return NULL; +} + +static void remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, LPVOID pData, UINT32 dataLength) +{ + UINT32 status; + + status = remdesk->channelEntryPoints.pVirtualChannelOpen(remdesk->InitHandle, + &remdesk->OpenHandle, remdesk->channelDef.name, remdesk_virtual_channel_open_event); + + remdesk_add_open_handle_data(remdesk->OpenHandle, remdesk); + + if (status != CHANNEL_RC_OK) + { + fprintf(stderr, "remdesk_virtual_channel_event_connected: open failed: status: %d\n", status); + return; + } + + remdesk->MsgPipe = MessagePipe_New(); + + remdesk->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) remdesk_virtual_channel_client_thread, (void*) remdesk, 0, NULL); +} + +static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk) +{ + MessagePipe_PostQuit(remdesk->MsgPipe, 0); + WaitForSingleObject(remdesk->thread, INFINITE); + + MessagePipe_Free(remdesk->MsgPipe); + CloseHandle(remdesk->thread); + + remdesk->channelEntryPoints.pVirtualChannelClose(remdesk->OpenHandle); + + if (remdesk->data_in) + { + Stream_Free(remdesk->data_in, TRUE); + remdesk->data_in = NULL; + } + + remdesk_remove_open_handle_data(remdesk->OpenHandle); + remdesk_remove_init_handle_data(remdesk->InitHandle); +} + +static VOID VCAPITYPE remdesk_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) +{ + remdeskPlugin* remdesk; + + remdesk = (remdeskPlugin*) remdesk_get_init_handle_data(pInitHandle); + + if (!remdesk) + { + fprintf(stderr, "remdesk_virtual_channel_init_event: error no match\n"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_CONNECTED: + remdesk_virtual_channel_event_connected(remdesk, pData, dataLength); + break; + + case CHANNEL_EVENT_DISCONNECTED: + break; + + case CHANNEL_EVENT_TERMINATED: + remdesk_virtual_channel_event_terminated(remdesk); + break; + } +} + +/* remdesk is always built-in */ +#define VirtualChannelEntry remdesk_VirtualChannelEntry + +BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) +{ + remdeskPlugin* remdesk; + RemdeskClientContext* context; + CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx; + + remdesk = (remdeskPlugin*) calloc(1, sizeof(remdeskPlugin)); + + remdesk->channelDef.options = + CHANNEL_OPTION_INITIALIZED | + CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP | + CHANNEL_OPTION_SHOW_PROTOCOL; + + printf("remdesk_VirtualChannelEntry\n"); + + strcpy(remdesk->channelDef.name, "remdesk"); + + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints; + + if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) && + (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) + { + context = (RemdeskClientContext*) calloc(1, sizeof(RemdeskClientContext)); + + context->handle = (void*) remdesk; + + *(pEntryPointsEx->ppInterface) = (void*) context; + } + + CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP)); + + remdesk->channelEntryPoints.pVirtualChannelInit(&remdesk->InitHandle, + &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, remdesk_virtual_channel_init_event); + + remdesk_add_init_handle_data(remdesk->InitHandle, (void*) remdesk); + + return 1; +} diff --git a/channels/remdesk/client/remdesk_main.h b/channels/remdesk/client/remdesk_main.h new file mode 100644 index 000000000..56e6f133c --- /dev/null +++ b/channels/remdesk/client/remdesk_main.h @@ -0,0 +1,48 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_REMDESK_CLIENT_MAIN_H +#define FREERDP_CHANNEL_REMDESK_CLIENT_MAIN_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +struct remdesk_plugin +{ + CHANNEL_DEF channelDef; + CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints; + + HANDLE thread; + wStream* data_in; + void* InitHandle; + DWORD OpenHandle; + wMessagePipe* MsgPipe; +}; +typedef struct remdesk_plugin remdeskPlugin; + +#endif /* FREERDP_CHANNEL_REMDESK_CLIENT_MAIN_H */ diff --git a/channels/remdesk/server/CMakeLists.txt b/channels/remdesk/server/CMakeLists.txt new file mode 100644 index 000000000..3139058b9 --- /dev/null +++ b/channels/remdesk/server/CMakeLists.txt @@ -0,0 +1,37 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_server("remdesk") + +set(${MODULE_PREFIX}_SRCS + remdesk_main.c + remdesk_main.h) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-crt) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/remdesk/server/remdesk_main.c b/channels/remdesk/server/remdesk_main.c new file mode 100644 index 000000000..3cd00ad63 --- /dev/null +++ b/channels/remdesk/server/remdesk_main.c @@ -0,0 +1,157 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "remdesk_main.h" + +static int remdesk_server_receive_pdu(RemdeskServerContext* context, wStream* s) +{ + return 0; +} + +static void* remdesk_server_thread(void* arg) +{ + wStream* s; + DWORD status; + DWORD nCount; + void* buffer; + HANDLE events[8]; + HANDLE ChannelEvent; + DWORD BytesReturned; + RemdeskServerContext* context; + + context = (RemdeskServerContext*) arg; + + buffer = NULL; + BytesReturned = 0; + ChannelEvent = NULL; + + s = Stream_New(NULL, 4096); + + if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + nCount = 0; + events[nCount++] = ChannelEvent; + events[nCount++] = context->priv->StopEvent; + + while (1) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) + { + break; + } + + if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, + (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + { + if (BytesReturned) + Stream_Seek(s, BytesReturned); + } + else + { + Stream_EnsureRemainingCapacity(s, BytesReturned); + } + + if (0) + { + remdesk_server_receive_pdu(context, s); + } + } + + Stream_Free(s, TRUE); + + return NULL; +} + +static int remdesk_server_start(RemdeskServerContext* context) +{ + context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "remdesk"); + + if (!context->priv->ChannelHandle) + return -1; + + context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + context->priv->Thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) remdesk_server_thread, (void*) context, 0, NULL); + + return 0; +} + +static int remdesk_server_stop(RemdeskServerContext* context) +{ + SetEvent(context->priv->StopEvent); + + WaitForSingleObject(context->priv->Thread, INFINITE); + CloseHandle(context->priv->Thread); + + return 0; +} + +RemdeskServerContext* remdesk_server_context_new(HANDLE vcm) +{ + RemdeskServerContext* context; + + context = (RemdeskServerContext*) calloc(1, sizeof(RemdeskServerContext)); + + if (context) + { + context->vcm = vcm; + + context->Start = remdesk_server_start; + context->Stop = remdesk_server_stop; + + context->priv = (RemdeskServerPrivate*) calloc(1, sizeof(RemdeskServerPrivate)); + + if (context->priv) + { + + } + } + + return context; +} + +void remdesk_server_context_free(RemdeskServerContext* context) +{ + if (context) + { + if (context->priv) + { + free(context->priv); + } + + free(context); + } +} diff --git a/channels/remdesk/server/remdesk_main.h b/channels/remdesk/server/remdesk_main.h new file mode 100644 index 000000000..42b504c1a --- /dev/null +++ b/channels/remdesk/server/remdesk_main.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_SERVER_REMDESK_MAIN_H +#define FREERDP_CHANNEL_SERVER_REMDESK_MAIN_H + +#include +#include +#include + +#include + +struct _remdesk_server_private +{ + HANDLE Thread; + HANDLE StopEvent; + void* ChannelHandle; +}; + +#endif /* FREERDP_CHANNEL_SERVER_REMDESK_MAIN_H */ + diff --git a/include/freerdp/channels/remdesk.h b/include/freerdp/channels/remdesk.h new file mode 100644 index 000000000..630ad3bf3 --- /dev/null +++ b/include/freerdp/channels/remdesk.h @@ -0,0 +1,29 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_REMDESK_H +#define FREERDP_CHANNEL_REMDESK_H + +#include +#include + +#define REMDESK_SVC_CHANNEL_NAME "remdesk" + +#endif /* FREERDP_CHANNEL_REMDESK_H */ + diff --git a/include/freerdp/client/remdesk.h b/include/freerdp/client/remdesk.h new file mode 100644 index 000000000..600a421ce --- /dev/null +++ b/include/freerdp/client/remdesk.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_CLIENT_REMDESK_H +#define FREERDP_CHANNEL_CLIENT_REMDESK_H + +#include + +/** + * Client Interface + */ + +typedef struct _remdesk_client_context RemdeskClientContext; + +struct _remdesk_client_context +{ + void* handle; + void* custom; +}; + +#endif /* FREERDP_CHANNEL_CLIENT_REMDESK_H */ + diff --git a/include/freerdp/server/remdesk.h b/include/freerdp/server/remdesk.h new file mode 100644 index 000000000..75b1e0a93 --- /dev/null +++ b/include/freerdp/server/remdesk.h @@ -0,0 +1,53 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_SERVER_REMDESK_H +#define FREERDP_CHANNEL_SERVER_REMDESK_H + +#include +#include +#include + +#include + +/** + * Server Interface + */ + +typedef struct _remdesk_server_context RemdeskServerContext; +typedef struct _remdesk_server_private RemdeskServerPrivate; + +typedef int (*psRemdeskStart)(RemdeskServerContext* context); +typedef int (*psRemdeskStop)(RemdeskServerContext* context); + +struct _remdesk_server_context +{ + HANDLE vcm; + + psRemdeskStart Start; + psRemdeskStop Stop; + + RemdeskServerPrivate* priv; +}; + +FREERDP_API RemdeskServerContext* remdesk_server_context_new(HANDLE vcm); +FREERDP_API void remdesk_server_context_free(RemdeskServerContext* context); + +#endif /* FREERDP_CHANNEL_SERVER_REMDESK_H */ + From af1be38775a949bd2ae119019569cc9a5aade264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 28 Jun 2014 18:33:46 -0400 Subject: [PATCH 12/23] client/common: parse and use remote assistance file --- .gitignore | 1 + channels/remdesk/client/remdesk_main.c | 6 +- client/common/assistance.c | 62 +++++++++++++++++++ client/common/client.c | 31 ++++++++++ client/common/cmdline.c | 37 ++++++++++++ include/freerdp/client.h | 3 + include/freerdp/client/assistance.h | 3 + include/freerdp/settings.h | 12 +++- libfreerdp/common/settings.c | 26 ++++++++ libfreerdp/core/info.c | 84 ++++++++++++++++++-------- libfreerdp/core/settings.c | 6 ++ 11 files changed, 239 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index 415c5441b..a53e90543 100755 --- a/.gitignore +++ b/.gitignore @@ -113,6 +113,7 @@ Release Win32 build*/ *.orig +*.msrcIncident default.log *Amplifier XE* diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index feeb7e4db..546cdb9e4 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -39,8 +39,8 @@ static int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) { int status = 1; - printf("RemDeskReceive: %d\n", Stream_Length(s)); - winpr_HexDump(Stream_Buffer(s), Stream_Length(s)); + printf("RemdeskReceive: %d\n", Stream_GetRemainingLength(s)); + winpr_HexDump(Stream_Pointer(s), Stream_GetRemainingLength(s)); return status; } @@ -303,8 +303,6 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; - printf("remdesk_VirtualChannelEntry\n"); - strcpy(remdesk->channelDef.name, "remdesk"); pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints; diff --git a/client/common/assistance.c b/client/common/assistance.c index 45408bfc6..206780547 100644 --- a/client/common/assistance.c +++ b/client/common/assistance.c @@ -575,6 +575,68 @@ int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const c return 1; } +int freerdp_client_assistance_parse_file(rdpAssistanceFile* file, const char* name) +{ + int status; + BYTE* buffer; + FILE* fp = NULL; + size_t readSize; + long int fileSize; + + fp = fopen(name, "r"); + + if (!fp) + return -1; + + fseek(fp, 0, SEEK_END); + fileSize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + if (fileSize < 1) + { + fclose(fp); + return -1; + } + + buffer = (BYTE*) malloc(fileSize + 2); + readSize = fread(buffer, fileSize, 1, fp); + + if (!readSize) + { + if (!ferror(fp)) + readSize = fileSize; + } + fclose(fp); + + if (readSize < 1) + { + free(buffer); + buffer = NULL; + return -1; + } + + buffer[fileSize] = '\0'; + buffer[fileSize + 1] = '\0'; + + status = freerdp_client_assistance_parse_file_buffer(file, (char*) buffer, fileSize); + + free(buffer); + + return status; +} + +int freerdp_client_populate_settings_from_assistance_file(rdpAssistanceFile* file, rdpSettings* settings) +{ + freerdp_set_param_bool(settings, FreeRDP_RemoteAssistanceMode, TRUE); + + if (!file->RASessionId) + return -1; + + freerdp_set_param_string(settings, FreeRDP_RemoteAssistanceSessionId, file->RASessionId); + + return 1; +} + rdpAssistanceFile* freerdp_client_assistance_file_new() { rdpAssistanceFile* file; diff --git a/client/common/client.c b/client/common/client.c index 1fc565f9a..13b46b6bf 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -27,6 +27,7 @@ #include #include #include +#include int freerdp_client_common_new(freerdp* instance, rdpContext* context) { @@ -118,6 +119,11 @@ int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, status = freerdp_client_settings_parse_connection_file(settings, settings->ConnectionFile); } + if (settings->AssistanceFile) + { + status = freerdp_client_settings_parse_assistance_file(settings, settings->AssistanceFile); + } + return status; } @@ -167,3 +173,28 @@ int freerdp_client_settings_write_connection_file(const rdpSettings* settings, c return 0; } + +int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, const char* filename) +{ + int status; + rdpAssistanceFile* file; + + file = freerdp_client_assistance_file_new(); + + if (!file) + return -1; + + status = freerdp_client_assistance_parse_file(file, filename); + + if (status < 0) + return -1; + + status = freerdp_client_populate_settings_from_assistance_file(file, settings); + + if (status < 0) + return -1; + + freerdp_client_assistance_file_free(file); + + return 0; +} diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 34bbd0b6b..71641ea6b 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -156,6 +156,7 @@ COMMAND_LINE_ARGUMENT_A args[] = { "print-reconnect-cookie", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Print base64 reconnect cookie after connecting" }, { "heartbeat", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support heartbeat PDUs" }, { "multitransport", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support multitransport protocol" }, + { "assistance", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Remote assistance mode" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; @@ -284,6 +285,17 @@ int freerdp_client_command_line_pre_filter(void* context, int index, int argc, L return 1; } } + + if (length > 13) + { + if (_stricmp(&(argv[index])[length - 13], ".msrcIncident") == 0) + { + settings = (rdpSettings*) context; + settings->AssistanceFile = _strdup(argv[index]); + + return 1; + } + } } return 0; @@ -1845,6 +1857,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->PrintReconnectCookie = arg->Value ? TRUE : FALSE; } + CommandLineSwitchCase(arg, "assistance") + { + settings->RemoteAssistanceMode = arg->Value ? TRUE : FALSE; + } CommandLineSwitchDefault(arg) { } @@ -2023,6 +2039,27 @@ int freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) } } + if (settings->RemoteAssistanceMode) + { + if (!freerdp_static_channel_collection_find(settings, "encomsp")) + { + char* params[1]; + + params[0] = "encomsp"; + + freerdp_client_add_static_channel(settings, 1, (char**) params); + } + + if (!freerdp_static_channel_collection_find(settings, "remdesk")) + { + char* params[1]; + + params[0] = "remdesk"; + + freerdp_client_add_static_channel(settings, 1, (char**) params); + } + } + for (index = 0; index < settings->StaticChannelCount; index++) { args = settings->StaticChannelArray[index]; diff --git a/include/freerdp/client.h b/include/freerdp/client.h index 661f3bac4..d4241f6a1 100644 --- a/include/freerdp/client.h +++ b/include/freerdp/client.h @@ -86,10 +86,13 @@ FREERDP_API freerdp* freerdp_client_get_instance(rdpContext* context); FREERDP_API HANDLE freerdp_client_get_thread(rdpContext* context); FREERDP_API int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, char** argv); + FREERDP_API int freerdp_client_settings_parse_connection_file(rdpSettings* settings, const char* filename); FREERDP_API int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, const BYTE* buffer, size_t size); FREERDP_API int freerdp_client_settings_write_connection_file(const rdpSettings* settings, const char* filename, BOOL unicode); +FREERDP_API int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, const char* filename); + #ifdef __cplusplus } #endif diff --git a/include/freerdp/client/assistance.h b/include/freerdp/client/assistance.h index 00068a73e..70e600884 100644 --- a/include/freerdp/client/assistance.h +++ b/include/freerdp/client/assistance.h @@ -56,8 +56,11 @@ extern "C" { #endif FREERDP_API int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size); +FREERDP_API int freerdp_client_assistance_parse_file(rdpAssistanceFile* file, const char* name); FREERDP_API int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* password); +FREERDP_API int freerdp_client_populate_settings_from_assistance_file(rdpAssistanceFile* file, rdpSettings* settings); + FREERDP_API rdpAssistanceFile* freerdp_client_assistance_file_new(); FREERDP_API void freerdp_client_assistance_file_free(rdpAssistanceFile* file); diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index cb9e25cb7..2695a70cc 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -585,6 +585,8 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_DisableCursorShadow 966 #define FreeRDP_DisableCursorBlinking 967 #define FreeRDP_AllowDesktopComposition 968 +#define FreeRDP_RemoteAssistanceMode 1024 +#define FreeRDP_RemoteAssistanceSessionId 1025 #define FreeRDP_TlsSecurity 1088 #define FreeRDP_NlaSecurity 1089 #define FreeRDP_RdpSecurity 1090 @@ -654,6 +656,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_CredentialsFromStdin 1604 #define FreeRDP_ComputerName 1664 #define FreeRDP_ConnectionFile 1728 +#define FreeRDP_AssistanceFile 1729 #define FreeRDP_HomePath 1792 #define FreeRDP_ConfigPath 1793 #define FreeRDP_CurrentPath 1794 @@ -935,7 +938,11 @@ struct rdp_settings ALIGN64 BOOL DisableCursorBlinking; /* 967 */ ALIGN64 BOOL AllowDesktopComposition; /* 968 */ UINT64 padding1024[1024 - 969]; /* 969 */ - UINT64 padding1088[1088 - 1024]; /* 1024 */ + + /* Remote Assistance */ + ALIGN64 BOOL RemoteAssistanceMode; /* 1024 */ + ALIGN64 char* RemoteAssistanceSessionId; /* 1025 */ + UINT64 padding1088[1088 - 1026]; /* 1026 */ /** * X.224 Connection Request/Confirm @@ -1047,7 +1054,8 @@ struct rdp_settings /* Files */ ALIGN64 char* ConnectionFile; /* 1728 */ - UINT64 padding1792[1792 - 1729]; /* 1729 */ + ALIGN64 char* AssistanceFile; /* 1729 */ + UINT64 padding1792[1792 - 1730]; /* 1730 */ /* Paths */ ALIGN64 char* HomePath; /* 1792 */ diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index e04230f37..12fe064a6 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -809,6 +809,10 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id) return settings->AllowDesktopComposition; break; + case FreeRDP_RemoteAssistanceMode: + return settings->RemoteAssistanceMode; + break; + case FreeRDP_TlsSecurity: return settings->TlsSecurity; break; @@ -1294,6 +1298,10 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) settings->AllowDesktopComposition = param; break; + case FreeRDP_RemoteAssistanceMode: + settings->RemoteAssistanceMode = param; + break; + case FreeRDP_TlsSecurity: settings->TlsSecurity = param; break; @@ -2368,6 +2376,10 @@ char* freerdp_get_param_string(rdpSettings* settings, int id) return settings->DynamicDSTTimeZoneKeyName; break; + case FreeRDP_RemoteAssistanceSessionId: + return settings->RemoteAssistanceSessionId; + break; + case FreeRDP_AuthenticationServiceClass: return settings->AuthenticationServiceClass; break; @@ -2412,6 +2424,10 @@ char* freerdp_get_param_string(rdpSettings* settings, int id) return settings->ConnectionFile; break; + case FreeRDP_AssistanceFile: + return settings->AssistanceFile; + break; + case FreeRDP_HomePath: return settings->HomePath; break; @@ -2553,6 +2569,11 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param) settings->DynamicDSTTimeZoneKeyName = _strdup(param); break; + case FreeRDP_RemoteAssistanceSessionId: + free(settings->RemoteAssistanceSessionId); + settings->RemoteAssistanceSessionId = _strdup(param); + break; + case FreeRDP_AuthenticationServiceClass: free(settings->AuthenticationServiceClass); settings->AuthenticationServiceClass = _strdup(param); @@ -2608,6 +2629,11 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param) settings->ConnectionFile = _strdup(param); break; + case FreeRDP_AssistanceFile: + free(settings->AssistanceFile); + settings->AssistanceFile = _strdup(param); + break; + case FreeRDP_HomePath: free(settings->HomePath); settings->HomePath = _strdup(param); diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 6e1696833..f68dff17b 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -393,15 +393,15 @@ BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings) void rdp_write_info_packet(wStream* s, rdpSettings* settings) { UINT32 flags; - WCHAR* domain = NULL; + WCHAR* domainW = NULL; int cbDomain = 0; - WCHAR* userName = NULL; + WCHAR* userNameW = NULL; int cbUserName = 0; - WCHAR* password = NULL; + WCHAR* passwordW = NULL; int cbPassword = 0; - WCHAR* alternateShell = NULL; + WCHAR* alternateShellW = NULL; int cbAlternateShell = 0; - WCHAR* workingDir = NULL; + WCHAR* workingDirW = NULL; int cbWorkingDir = 0; BOOL usedPasswordCookie = FALSE; @@ -439,30 +439,62 @@ void rdp_write_info_packet(wStream* s, rdpSettings* settings) if (settings->Domain) { - cbDomain = ConvertToUnicode(CP_UTF8, 0, settings->Domain, -1, &domain, 0) * 2; + cbDomain = ConvertToUnicode(CP_UTF8, 0, settings->Domain, -1, &domainW, 0) * 2; } else { - domain = NULL; + domainW = NULL; cbDomain = 0; } - cbUserName = ConvertToUnicode(CP_UTF8, 0, settings->Username, -1, &userName, 0) * 2; - - if (settings->RedirectionPassword && settings->RedirectionPasswordLength > 0) + if (!settings->RemoteAssistanceMode) { - usedPasswordCookie = TRUE; - password = (WCHAR*) settings->RedirectionPassword; - cbPassword = settings->RedirectionPasswordLength - 2; /* Strip double zero termination */ + cbUserName = ConvertToUnicode(CP_UTF8, 0, settings->Username, -1, &userNameW, 0) * 2; } else { - cbPassword = ConvertToUnicode(CP_UTF8, 0, settings->Password, -1, &password, 0) * 2; + /* user name provided by the expert for connecting to the novice computer */ + cbUserName = ConvertToUnicode(CP_UTF8, 0, settings->Username, -1, &userNameW, 0) * 2; } - cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, settings->AlternateShell, -1, &alternateShell, 0) * 2; + if (!settings->RemoteAssistanceMode) + { + if (settings->RedirectionPassword && settings->RedirectionPasswordLength > 0) + { + usedPasswordCookie = TRUE; + passwordW = (WCHAR*) settings->RedirectionPassword; + cbPassword = settings->RedirectionPasswordLength - 2; /* Strip double zero termination */ + } + else + { + cbPassword = ConvertToUnicode(CP_UTF8, 0, settings->Password, -1, &passwordW, 0) * 2; + } + } + else + { + /* This field MUST be filled with "*" */ + cbPassword = ConvertToUnicode(CP_UTF8, 0, "*", -1, &passwordW, 0) * 2; + } - cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->ShellWorkingDirectory, -1, &workingDir, 0) * 2; + if (!settings->RemoteAssistanceMode) + { + cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, settings->AlternateShell, -1, &alternateShellW, 0) * 2; + } + else + { + /* This field MUST be filled with "*" */ + cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, "*", -1, &alternateShellW, 0) * 2; + } + + if (!settings->RemoteAssistanceMode) + { + cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->ShellWorkingDirectory, -1, &workingDirW, 0) * 2; + } + else + { + /* Remote Assistance Session Id */ + cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->RemoteAssistanceSessionId, -1, &workingDirW, 0) * 2; + } Stream_Write_UINT32(s, 0); /* CodePage */ Stream_Write_UINT32(s, flags); /* flags */ @@ -474,32 +506,32 @@ void rdp_write_info_packet(wStream* s, rdpSettings* settings) Stream_Write_UINT16(s, cbWorkingDir); /* cbWorkingDir */ if (cbDomain > 0) - Stream_Write(s, domain, cbDomain); + Stream_Write(s, domainW, cbDomain); Stream_Write_UINT16(s, 0); if (cbUserName > 0) - Stream_Write(s, userName, cbUserName); + Stream_Write(s, userNameW, cbUserName); Stream_Write_UINT16(s, 0); if (cbPassword > 0) - Stream_Write(s, password, cbPassword); + Stream_Write(s, passwordW, cbPassword); Stream_Write_UINT16(s, 0); if (cbAlternateShell > 0) - Stream_Write(s, alternateShell, cbAlternateShell); + Stream_Write(s, alternateShellW, cbAlternateShell); Stream_Write_UINT16(s, 0); if (cbWorkingDir > 0) - Stream_Write(s, workingDir, cbWorkingDir); + Stream_Write(s, workingDirW, cbWorkingDir); Stream_Write_UINT16(s, 0); - free(domain); - free(userName); - free(alternateShell); - free(workingDir); + free(domainW); + free(userNameW); + free(alternateShellW); + free(workingDirW); if (!usedPasswordCookie) - free(password); + free(passwordW); if (settings->RdpVersion >= 5) rdp_write_extended_info_packet(s, settings); /* extraInfo */ diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 6c0de1e7f..0843bbdd6 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -464,6 +464,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->ClientAddress = _strdup(settings->ClientAddress); /* 769 */ _settings->ClientDir = _strdup(settings->ClientDir); /* 770 */ _settings->DynamicDSTTimeZoneKeyName = _strdup(settings->DynamicDSTTimeZoneKeyName); /* 897 */ + _settings->RemoteAssistanceSessionId = _strdup(settings->RemoteAssistanceSessionId); /* 1025 */ _settings->AuthenticationServiceClass = _strdup(settings->AuthenticationServiceClass); /* 1098 */ _settings->PreconnectionBlob = _strdup(settings->PreconnectionBlob); /* 1155 */ _settings->KerberosKdc = _strdup(settings->KerberosKdc); /* 1344 */ @@ -476,6 +477,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->WmClass = _strdup(settings->WmClass); /* 1549 */ _settings->ComputerName = _strdup(settings->ComputerName); /* 1664 */ _settings->ConnectionFile = _strdup(settings->ConnectionFile); /* 1728 */ + _settings->AssistanceFile = _strdup(settings->AssistanceFile); /* 1729 */ _settings->HomePath = _strdup(settings->HomePath); /* 1792 */ _settings->ConfigPath = _strdup(settings->ConfigPath); /* 1793 */ _settings->CurrentPath = _strdup(settings->CurrentPath); /* 1794 */ @@ -624,6 +626,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->DisableCursorShadow = settings->DisableCursorShadow; /* 966 */ _settings->DisableCursorBlinking = settings->DisableCursorBlinking; /* 967 */ _settings->AllowDesktopComposition = settings->AllowDesktopComposition; /* 968 */ + _settings->RemoteAssistanceMode = settings->RemoteAssistanceMode; /* 1024 */ _settings->TlsSecurity = settings->TlsSecurity; /* 1088 */ _settings->NlaSecurity = settings->NlaSecurity; /* 1089 */ _settings->RdpSecurity = settings->RdpSecurity; /* 1090 */ @@ -810,6 +813,8 @@ void freerdp_settings_free(rdpSettings* settings) free(settings->ClientDir); free(settings->CertificateFile); free(settings->PrivateKeyFile); + free(settings->ConnectionFile); + free(settings->AssistanceFile); free(settings->ReceivedCapabilities); free(settings->OrderSupport); free(settings->ClientHostname); @@ -837,6 +842,7 @@ void freerdp_settings_free(rdpSettings* settings) free(settings->RedirectionDomain); free(settings->RedirectionPassword); free(settings->RedirectionTsvUrl); + free(settings->RemoteAssistanceSessionId); free(settings->AuthenticationServiceClass); freerdp_target_net_addresses_free(settings); freerdp_device_collection_free(settings); From 06c7f83bc25adeef0fb4f97af1ec42be6a04992a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 28 Jun 2014 20:22:36 -0400 Subject: [PATCH 13/23] channels/remdesk: start parsing messages --- channels/remdesk/client/remdesk_main.c | 244 ++++++++++++++++++++++++- channels/remdesk/client/remdesk_main.h | 2 + client/common/assistance.c | 6 + include/freerdp/channels/remdesk.h | 41 +++++ 4 files changed, 292 insertions(+), 1 deletion(-) diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index 546cdb9e4..f740086eb 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -35,13 +35,250 @@ RemdeskClientContext* remdesk_get_client_interface(remdeskPlugin* remdesk) return pInterface; } -static int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) +int remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s) +{ + UINT32 status = 0; + + if (!remdesk) + return -1; + + status = remdesk->channelEntryPoints.pVirtualChannelWrite(remdesk->OpenHandle, + Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + + if (status != CHANNEL_RC_OK) + { + fprintf(stderr, "remdesk_virtual_channel_write: VirtualChannelWrite failed %d\n", status); + return -1; + } + + Stream_Free(s, TRUE); + + return 1; +} + +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; +} + +int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + UINT32 ChannelNameLen; + WCHAR ChannelNameW[32]; + WCHAR* pChannelName = NULL; + + ZeroMemory(ChannelNameW, sizeof(ChannelNameW)); + + pChannelName = (WCHAR*) ChannelNameW; + status = ConvertToUnicode(CP_UTF8, 0, header->ChannelName, -1, &pChannelName, 32); + + if (status <= 0) + return -1; + + ChannelNameLen = (status + 1) * 2; + + Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ + + Stream_Write(s, pChannelName, ChannelNameLen); /* ChannelName (variable) */ + + return 1; +} + +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) +{ + ctlHeader->msgType = REMDESK_CTL_VERSIONINFO; + strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME); + ctlHeader->DataLength = 4 + msgSize; + return 1; +} + +int remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + printf("RemdeskServerAnnounce\n"); + + return 1; +} + +int remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, 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) */ + + printf("RemdeskVersionInfo: versionMajor: 0x%04X versionMinor: 0x%04X\n", + versionMajor, versionMinor); + + return 1; +} + +int remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk) +{ + 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(remdesk, s); + + return 1; +} + +int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) { int status = 1; + UINT32 msgType; + + 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: + break; + + case REMDESK_CTL_RESULT: + break; + + case REMDESK_CTL_AUTHENTICATE: + break; + + case REMDESK_CTL_SERVER_ANNOUNCE: + status = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header); + break; + + case REMDESK_CTL_DISCONNECT: + break; + + case REMDESK_CTL_VERSIONINFO: + status = remdesk_recv_ctl_version_info_pdu(remdesk, s, header); + break; + + case REMDESK_CTL_ISCONNECTED: + break; + + case REMDESK_CTL_VERIFY_PASSWORD: + 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; +} + +int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) +{ + int status = 1; + REMDESK_CHANNEL_HEADER header; printf("RemdeskReceive: %d\n", Stream_GetRemainingLength(s)); winpr_HexDump(Stream_Pointer(s), Stream_GetRemainingLength(s)); + remdesk_read_channel_header(s, &header); + + if (strcmp(header.ChannelName, "RC_CTL") == 0) + { + status = remdesk_recv_ctl_pdu(remdesk, 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 status; } @@ -297,6 +534,9 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) remdesk = (remdeskPlugin*) calloc(1, sizeof(remdeskPlugin)); + if (!remdesk) + return FALSE; + remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | @@ -305,6 +545,8 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) strcpy(remdesk->channelDef.name, "remdesk"); + remdesk->Version = 2; + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) && diff --git a/channels/remdesk/client/remdesk_main.h b/channels/remdesk/client/remdesk_main.h index 56e6f133c..0a2261e34 100644 --- a/channels/remdesk/client/remdesk_main.h +++ b/channels/remdesk/client/remdesk_main.h @@ -42,6 +42,8 @@ struct remdesk_plugin void* InitHandle; DWORD OpenHandle; wMessagePipe* MsgPipe; + + UINT32 Version; }; typedef struct remdesk_plugin remdeskPlugin; diff --git a/client/common/assistance.c b/client/common/assistance.c index 206780547..bfd610564 100644 --- a/client/common/assistance.c +++ b/client/common/assistance.c @@ -634,6 +634,12 @@ int freerdp_client_populate_settings_from_assistance_file(rdpAssistanceFile* fil freerdp_set_param_string(settings, FreeRDP_RemoteAssistanceSessionId, file->RASessionId); + if (!file->MachineAddress) + return -1; + + freerdp_set_param_string(settings, FreeRDP_ServerHostname, file->MachineAddress); + freerdp_set_param_uint32(settings, FreeRDP_ServerPort, file->MachinePort); + return 1; } diff --git a/include/freerdp/channels/remdesk.h b/include/freerdp/channels/remdesk.h index 630ad3bf3..f8557ca38 100644 --- a/include/freerdp/channels/remdesk.h +++ b/include/freerdp/channels/remdesk.h @@ -25,5 +25,46 @@ #define REMDESK_SVC_CHANNEL_NAME "remdesk" +struct _REMDESK_CHANNEL_HEADER +{ + UINT32 DataLength; + char ChannelName[32]; +}; +typedef struct _REMDESK_CHANNEL_HEADER REMDESK_CHANNEL_HEADER; + +#define REMDESK_CHANNEL_CTL_NAME "RC_CTL" +#define REMDESK_CHANNEL_CTL_SIZE 22 + +struct _REMDESK_CTL_HEADER +{ + UINT32 DataLength; + char ChannelName[32]; + + UINT32 msgType; +}; +typedef struct _REMDESK_CTL_HEADER REMDESK_CTL_HEADER; + +#define REMDESK_CTL_REMOTE_CONTROL_DESKTOP 1 +#define REMDESK_CTL_RESULT 2 +#define REMDESK_CTL_AUTHENTICATE 3 +#define REMDESK_CTL_SERVER_ANNOUNCE 4 +#define REMDESK_CTL_DISCONNECT 5 +#define REMDESK_CTL_VERSIONINFO 6 +#define REMDESK_CTL_ISCONNECTED 7 +#define REMDESK_CTL_VERIFY_PASSWORD 8 +#define REMDESK_CTL_EXPERT_ON_VISTA 9 +#define REMDESK_CTL_RANOVICE_NAME 10 +#define REMDESK_CTL_RAEXPERT_NAME 11 +#define REMDESK_CTL_TOKEN 12 + +struct _REMDESK_CTL_VERSION_INFO_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + UINT32 versionMajor; + UINT32 versionMinor; +}; +typedef struct _REMDESK_CTL_VERSION_INFO_PDU REMDESK_CTL_VERSION_INFO_PDU; + #endif /* FREERDP_CHANNEL_REMDESK_H */ From fc315365f609d079ff9e54112b297b8a87aa04fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 29 Jun 2014 12:36:28 -0400 Subject: [PATCH 14/23] client/common: add .msrcIncident type 1 file test --- client/common/assistance.c | 72 ++++++++++++++++++--- client/common/test/TestClientAssistance.c | 77 +++++++++++++++++++++-- include/freerdp/client/assistance.h | 3 +- 3 files changed, 138 insertions(+), 14 deletions(-) diff --git a/client/common/assistance.c b/client/common/assistance.c index bfd610564..42509bea7 100644 --- a/client/common/assistance.c +++ b/client/common/assistance.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -38,6 +39,14 @@ #include +/** + * Password encryption in establishing a remote assistance session of type 1: + * http://blogs.msdn.com/b/openspecification/archive/2011/10/31/password-encryption-in-establishing-a-remote-assistance-session-of-type-1.aspx + * + * Creation of PassStub for the Remote Assistance Ticket: + * http://social.msdn.microsoft.com/Forums/en-US/6316c3f4-ea09-4343-a4a1-9cca46d70d28/creation-of-passstub-for-the-remote-assistance-ticket?forum=os_windowsprotocols + */ + /** * CryptDeriveKey Function: * http://msdn.microsoft.com/en-us/library/windows/desktop/aa379916/ @@ -102,29 +111,59 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass int status; RC4_KEY rc4; MD5_CTX md5Ctx; - int PassStubLength; + int cbPasswordW; + int cbPassStubW; BYTE* PlainBlob = NULL; WCHAR* PasswordW = NULL; + WCHAR* PassStubW = NULL; BYTE EncryptionKey[AES_BLOCK_SIZE]; BYTE PasswordHash[MD5_DIGEST_LENGTH]; + /** + * PROV_RSA_FULL provider + * CALG_MD5 hashing + * CALG_RC4 encryption + * Key Length: 40 bits + * Salt Length: 88 bits + */ + status = ConvertToUnicode(CP_UTF8, 0, password, -1, &PasswordW, 0); if (status <= 0) return -1; + cbPasswordW = (status - 1) * 2; + + printf("PasswordW (%d)\n", cbPasswordW); + winpr_HexDump(PasswordW, cbPasswordW); + MD5_Init(&md5Ctx); - MD5_Update(&md5Ctx, PasswordW, status * 2); + MD5_Update(&md5Ctx, PasswordW, cbPasswordW); MD5_Final((void*) PasswordHash, &md5Ctx); + printf("PasswordHash (%s):\n", password); + winpr_HexDump(PasswordHash, sizeof(PasswordHash)); + status = freerdp_client_assistance_crypt_derive_key(PasswordHash, sizeof(PasswordHash), EncryptionKey, sizeof(EncryptionKey)); if (status < 0) return -1; - PassStubLength = strlen(file->PassStub); - file->EncryptedPassStubLength = PassStubLength + 4; + printf("DerivedKey (%d):\n", sizeof(EncryptionKey)); + winpr_HexDump(EncryptionKey, sizeof(EncryptionKey)); + + status = ConvertToUnicode(CP_UTF8, 0, file->PassStub, -1, &PassStubW, 0); + + if (status <= 0) + return -1; + + cbPassStubW = (status - 1) * 2; + + printf("PassStubW (%d)\n", cbPassStubW); + winpr_HexDump(PassStubW, cbPassStubW); + + file->EncryptedPassStubLength = cbPassStubW + 4; PlainBlob = (BYTE*) calloc(1, file->EncryptedPassStubLength); file->EncryptedPassStub = (BYTE*) calloc(1, file->EncryptedPassStubLength); @@ -135,12 +174,24 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass if (!file->EncryptedPassStubLength) return -1; - *((UINT32*) PlainBlob) = PassStubLength; - CopyMemory(&PlainBlob[4], file->PassStub, PassStubLength); + *((UINT32*) PlainBlob) = cbPassStubW; + CopyMemory(&PlainBlob[4], PassStubW, cbPassStubW); + + printf("PlainBlob (%d)\n", file->EncryptedPassStubLength); + winpr_HexDump(PlainBlob, file->EncryptedPassStubLength); + +#if 0 + void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data); + void RC4(RC4_KEY *key, size_t len, const unsigned char *indata, + unsigned char *outdata); +#endif RC4_set_key(&rc4, sizeof(EncryptionKey), EncryptionKey); RC4(&rc4, file->EncryptedPassStubLength, PlainBlob, file->EncryptedPassStub); + printf("EncryptedPassStub (%d):\n", file->EncryptedPassStubLength); + winpr_HexDump(file->EncryptedPassStub, file->EncryptedPassStubLength); + return 1; } @@ -561,8 +612,13 @@ int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const c file->LowSpeed = TRUE; } - file->EncryptedLHTicket = freerdp_client_assistance_parse_hex_string(file->LHTicket, - &file->EncryptedLHTicketLength); + file->Type = (file->LHTicket) ? 2 : 1; + + if (file->LHTicket) + { + file->EncryptedLHTicket = freerdp_client_assistance_parse_hex_string(file->LHTicket, + &file->EncryptedLHTicketLength); + } status = freerdp_client_assistance_parse_connection_string1(file); diff --git a/client/common/test/TestClientAssistance.c b/client/common/test/TestClientAssistance.c index 7aeef14e5..9fc92b450 100644 --- a/client/common/test/TestClientAssistance.c +++ b/client/common/test/TestClientAssistance.c @@ -4,9 +4,25 @@ #include -const char* TEST_MSRC_INCIDENT_PASSWORD = "48BJQ853X3B4"; +const char* TEST_MSRC_INCIDENT_PASSWORD_TYPE1 = "Password1"; -static const char* TEST_MSRC_INCIDENT_FILE = +static const char* TEST_MSRC_INCIDENT_FILE_TYPE1 = +"" +"" +"" +""; + +const char* TEST_MSRC_INCIDENT_PASSWORD_TYPE2 = "48BJQ853X3B4"; + +static const char* TEST_MSRC_INCIDENT_FILE_TYPE2 = "" "" "" ""; -int TestClientAssistance(int argc, char* argv[]) +int test_msrsc_incident_file_type1() { int status; rdpAssistanceFile* file; file = freerdp_client_assistance_file_new(); - status = freerdp_client_assistance_parse_file_buffer(file, TEST_MSRC_INCIDENT_FILE, sizeof(TEST_MSRC_INCIDENT_FILE)); + status = freerdp_client_assistance_parse_file_buffer(file, + TEST_MSRC_INCIDENT_FILE_TYPE1, sizeof(TEST_MSRC_INCIDENT_FILE_TYPE1)); printf("freerdp_client_assistance_parse_file_buffer: %d\n", status); @@ -68,7 +85,7 @@ int TestClientAssistance(int argc, char* argv[]) printf("MachineAddress: %s\n", file->MachineAddress); printf("MachinePort: %d\n", (int) file->MachinePort); - status = freerdp_client_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD); + status = freerdp_client_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD_TYPE1); printf("freerdp_client_assistance_decrypt: %d\n", status); @@ -80,3 +97,53 @@ int TestClientAssistance(int argc, char* argv[]) return 0; } +int test_msrsc_incident_file_type2() +{ + int status; + rdpAssistanceFile* file; + + file = freerdp_client_assistance_file_new(); + + status = freerdp_client_assistance_parse_file_buffer(file, + TEST_MSRC_INCIDENT_FILE_TYPE2, sizeof(TEST_MSRC_INCIDENT_FILE_TYPE2)); + + printf("freerdp_client_assistance_parse_file_buffer: %d\n", status); + + if (status < 0) + return -1; + + printf("Username: %s\n", file->Username); + printf("LHTicket: %s\n", file->LHTicket); + printf("RCTicket: %s\n", file->RCTicket); + printf("RCTicketEncrypted: %d\n", file->RCTicketEncrypted); + printf("PassStub: %s\n", file->PassStub); + printf("DtStart: %d\n", file->DtStart); + printf("DtLength: %d\n", file->DtLength); + printf("LowSpeed: %d\n", file->LowSpeed); + + printf("RASessionId: %s\n", file->RASessionId); + printf("RASpecificParams: %s\n", file->RASpecificParams); + printf("MachineAddress: %s\n", file->MachineAddress); + printf("MachinePort: %d\n", (int) file->MachinePort); + + status = freerdp_client_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD_TYPE2); + + printf("freerdp_client_assistance_decrypt: %d\n", status); + + if (status < 0) + return -1; + + freerdp_client_assistance_file_free(file); + + return 0; +} + +int TestClientAssistance(int argc, char* argv[]) +{ + test_msrsc_incident_file_type1(); + + //test_msrsc_incident_file_type2(); + + return 0; +} + diff --git a/include/freerdp/client/assistance.h b/include/freerdp/client/assistance.h index 70e600884..6af76c668 100644 --- a/include/freerdp/client/assistance.h +++ b/include/freerdp/client/assistance.h @@ -25,7 +25,8 @@ struct rdp_assistance_file { - char* Type; + UINT32 Type; + char* Username; char* LHTicket; char* RCTicket; From 90ea6095763451ce033a64c44af9f7da49ba0ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 29 Jun 2014 18:48:37 -0400 Subject: [PATCH 15/23] client/common: improve remote assistance blob encryption --- client/common/assistance.c | 168 ++++++++++++++++------ client/common/test/TestClientAssistance.c | 4 + 2 files changed, 131 insertions(+), 41 deletions(-) diff --git a/client/common/assistance.c b/client/common/assistance.c index 42509bea7..5ea6793cb 100644 --- a/client/common/assistance.c +++ b/client/common/assistance.c @@ -75,33 +75,76 @@ * Use the first n bytes of the result of step 5 as the derived key. */ -int freerdp_client_assistance_crypt_derive_key(BYTE* hash, int hashLength, BYTE* key, int keyLength) +int freerdp_client_assistance_crypt_derive_key_md5(BYTE* hash, int hashLength, BYTE* key, int keyLength) { int i; - BYTE* bufferHash; - BYTE buffer36[64]; - BYTE buffer5c[64]; + BYTE* buffer; + BYTE pad1[64]; + BYTE pad2[64]; + MD5_CTX hashCtx; - memset(buffer36, 0x36, sizeof(buffer36)); - memset(buffer5c, 0x5C, sizeof(buffer5c)); + memset(pad1, 0x36, 64); + memset(pad2, 0x5C, 64); for (i = 0; i < hashLength; i++) { - buffer36[i] ^= hash[i]; - buffer5c[i] ^= hash[i]; + pad1[i] ^= hash[i]; + pad2[i] ^= hash[i]; } - bufferHash = (BYTE*) calloc(1, hashLength * 2); + buffer = (BYTE*) calloc(1, hashLength * 2); - if (!bufferHash) + if (!buffer) return -1; - SHA1(buffer36, 64, bufferHash); - SHA1(buffer5c, 64, &bufferHash[hashLength]); + MD5_Init(&hashCtx); + MD5_Update(&hashCtx, pad1, 64); + MD5_Final((void*) buffer, &hashCtx); - CopyMemory(key, bufferHash, keyLength); + MD5_Init(&hashCtx); + MD5_Update(&hashCtx, pad2, 64); + MD5_Final((void*) &buffer[hashLength], &hashCtx); - free(bufferHash); + CopyMemory(key, buffer, keyLength); + + free(buffer); + + return 1; +} + +int freerdp_client_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* key, int keyLength) +{ + int i; + BYTE* buffer; + BYTE pad1[64]; + BYTE pad2[64]; + SHA_CTX hashCtx; + + memset(pad1, 0x36, 64); + memset(pad2, 0x5C, 64); + + for (i = 0; i < hashLength; i++) + { + pad1[i] ^= hash[i]; + pad2[i] ^= hash[i]; + } + + buffer = (BYTE*) calloc(1, hashLength * 2); + + if (!buffer) + return -1; + + SHA_Init(&hashCtx); + SHA_Update(&hashCtx, pad1, 64); + SHA_Final((void*) buffer, &hashCtx); + + SHA_Init(&hashCtx); + SHA_Update(&hashCtx, pad2, 64); + SHA_Final((void*) &buffer[hashLength], &hashCtx); + + CopyMemory(key, buffer, keyLength); + + free(buffer); return 1; } @@ -109,14 +152,16 @@ int freerdp_client_assistance_crypt_derive_key(BYTE* hash, int hashLength, BYTE* int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* password) { int status; - RC4_KEY rc4; + int cbOutLen; MD5_CTX md5Ctx; int cbPasswordW; int cbPassStubW; + EVP_CIPHER_CTX rc4Ctx; BYTE* PlainBlob = NULL; WCHAR* PasswordW = NULL; WCHAR* PassStubW = NULL; - BYTE EncryptionKey[AES_BLOCK_SIZE]; + BYTE DerivedKey[16]; + BYTE InitializationVector[16]; BYTE PasswordHash[MD5_DIGEST_LENGTH]; /** @@ -135,7 +180,7 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass cbPasswordW = (status - 1) * 2; printf("PasswordW (%d)\n", cbPasswordW); - winpr_HexDump(PasswordW, cbPasswordW); + winpr_HexDump((BYTE*) PasswordW, cbPasswordW); MD5_Init(&md5Ctx); MD5_Update(&md5Ctx, PasswordW, cbPasswordW); @@ -144,14 +189,16 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass printf("PasswordHash (%s):\n", password); winpr_HexDump(PasswordHash, sizeof(PasswordHash)); - status = freerdp_client_assistance_crypt_derive_key(PasswordHash, sizeof(PasswordHash), - EncryptionKey, sizeof(EncryptionKey)); + status = freerdp_client_assistance_crypt_derive_key_md5(PasswordHash, sizeof(PasswordHash), + DerivedKey, sizeof(DerivedKey)); if (status < 0) return -1; - printf("DerivedKey (%d):\n", sizeof(EncryptionKey)); - winpr_HexDump(EncryptionKey, sizeof(EncryptionKey)); + printf("DerivedKey (%d):\n", sizeof(DerivedKey)); + winpr_HexDump(DerivedKey, sizeof(DerivedKey)); + + ZeroMemory(InitializationVector, sizeof(InitializationVector)); status = ConvertToUnicode(CP_UTF8, 0, file->PassStub, -1, &PassStubW, 0); @@ -161,7 +208,7 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass cbPassStubW = (status - 1) * 2; printf("PassStubW (%d)\n", cbPassStubW); - winpr_HexDump(PassStubW, cbPassStubW); + winpr_HexDump((BYTE*) PassStubW, cbPassStubW); file->EncryptedPassStubLength = cbPassStubW + 4; @@ -180,14 +227,34 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass printf("PlainBlob (%d)\n", file->EncryptedPassStubLength); winpr_HexDump(PlainBlob, file->EncryptedPassStubLength); -#if 0 - void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data); - void RC4(RC4_KEY *key, size_t len, const unsigned char *indata, - unsigned char *outdata); -#endif + EVP_CIPHER_CTX_init(&rc4Ctx); - RC4_set_key(&rc4, sizeof(EncryptionKey), EncryptionKey); - RC4(&rc4, file->EncryptedPassStubLength, PlainBlob, file->EncryptedPassStub); + status = EVP_EncryptInit_ex(&rc4Ctx, EVP_rc4(), NULL, DerivedKey, InitializationVector); + + if (!status) + { + fprintf(stderr, "EVP_CipherInit_ex failure\n"); + return -1; + } + + cbOutLen = file->EncryptedPassStubLength; + status = EVP_EncryptUpdate(&rc4Ctx, file->EncryptedPassStub, &cbOutLen, PlainBlob, file->EncryptedPassStubLength); + + if (!status) + { + fprintf(stderr, "EVP_CipherUpdate failure\n"); + return -1; + } + + status = EVP_EncryptFinal_ex(&rc4Ctx, file->EncryptedPassStub, &cbOutLen); + + if (!status) + { + fprintf(stderr, "EVP_CipherFinal_ex failure\n"); + return -1; + } + + EVP_CIPHER_CTX_cleanup(&rc4Ctx); printf("EncryptedPassStub (%d):\n", file->EncryptedPassStubLength); winpr_HexDump(file->EncryptedPassStub, file->EncryptedPassStubLength); @@ -199,10 +266,12 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass { int status; SHA_CTX shaCtx; - int cbOut, cbFinal; + int cbPasswordW; EVP_CIPHER_CTX aesDec; WCHAR* PasswordW = NULL; - BYTE EncryptionKey[AES_BLOCK_SIZE]; + BYTE *pbIn, *pbOut; + int cbOut, cbIn, cbFinal; + BYTE DerivedKey[AES_BLOCK_SIZE]; BYTE PasswordHash[SHA_DIGEST_LENGTH]; status = ConvertToUnicode(CP_UTF8, 0, password, -1, &PasswordW, 0); @@ -210,40 +279,54 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass if (status <= 0) return -1; + cbPasswordW = (status - 1) * 2; + SHA_Init(&shaCtx); - SHA_Update(&shaCtx, PasswordW, status * 2); + SHA_Update(&shaCtx, PasswordW, cbPasswordW); SHA_Final((void*) PasswordHash, &shaCtx); - status = freerdp_client_assistance_crypt_derive_key(PasswordHash, sizeof(PasswordHash), - EncryptionKey, sizeof(EncryptionKey)); + status = freerdp_client_assistance_crypt_derive_key_sha1(PasswordHash, sizeof(PasswordHash), + DerivedKey, sizeof(DerivedKey)); if (status < 0) return -1; EVP_CIPHER_CTX_init(&aesDec); - status = EVP_DecryptInit(&aesDec, EVP_aes_128_cbc(), EncryptionKey, NULL); + EVP_CIPHER_CTX_set_padding(&aesDec, 0); + + status = EVP_DecryptInit_ex(&aesDec, EVP_aes_128_cbc(), NULL, DerivedKey, NULL); if (status != 1) return -1; - cbOut = file->EncryptedLHTicketLength; - file->ConnectionString2 = (char*) calloc(1, cbOut); + cbOut = cbFinal = 0; + cbIn = file->EncryptedLHTicketLength; + + file->ConnectionString2 = (char*) calloc(1, cbOut + AES_BLOCK_SIZE); if (!file->ConnectionString2) return -1; - status = EVP_DecryptUpdate(&aesDec, (BYTE*) file->ConnectionString2, &cbOut, - (BYTE*) file->EncryptedLHTicket, file->EncryptedLHTicketLength); + pbIn = (BYTE*) file->EncryptedLHTicket; + pbOut = (BYTE*) file->ConnectionString2; + + status = EVP_DecryptUpdate(&aesDec, pbOut, &cbOut, pbIn, cbIn); + if (status != 1) return -1; - status = EVP_DecryptFinal(&aesDec, (BYTE*) &file->ConnectionString2[cbOut], &cbFinal); + status = EVP_DecryptFinal_ex(&aesDec, pbOut + cbOut, &cbFinal); /* FIXME: still fails */ if (status != 1) + { + fprintf(stderr, "EVP_DecryptFinal_ex failure\n"); return -1; + } + + EVP_CIPHER_CTX_cleanup(&aesDec); return 1; } @@ -254,7 +337,10 @@ int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* passw status = freerdp_client_assistance_decrypt1(file, password); - freerdp_client_assistance_decrypt2(file, password); + if (file->Type > 1) + { + status = freerdp_client_assistance_decrypt2(file, password); + } return status; } diff --git a/client/common/test/TestClientAssistance.c b/client/common/test/TestClientAssistance.c index 9fc92b450..c6ec99dc1 100644 --- a/client/common/test/TestClientAssistance.c +++ b/client/common/test/TestClientAssistance.c @@ -20,6 +20,10 @@ static const char* TEST_MSRC_INCIDENT_FILE_TYPE1 = "L=\"0\" />" ""; +const BYTE TEST_MSRC_INCIDENT_EXPERT_BLOB_TYPE1[32] = + "\x3C\x9C\xAE\x0B\xCE\x7A\xB1\x5C\x8A\xAC\x01\xD6\x76\x04\x5E\xDF" + "\x3F\xFA\xF0\x92\xE2\xDE\x36\x8A\x20\x17\xE6\x8A\x0D\xED\x7C\x90"; + const char* TEST_MSRC_INCIDENT_PASSWORD_TYPE2 = "48BJQ853X3B4"; static const char* TEST_MSRC_INCIDENT_FILE_TYPE2 = From 01a013f82673b7cc5e0c6140819e1e56f35b3294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 29 Jun 2014 19:57:46 -0400 Subject: [PATCH 16/23] client/common: fix Remote Assistance memory leaks --- channels/remdesk/client/remdesk_main.c | 136 +++++++++++++++++++++- client/common/assistance.c | 44 ++++--- client/common/test/TestClientAssistance.c | 2 +- include/freerdp/channels/remdesk.h | 26 +++++ 4 files changed, 190 insertions(+), 18 deletions(-) diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index f740086eb..4c41f64a2 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -43,7 +43,7 @@ int remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s) return -1; status = remdesk->channelEntryPoints.pVirtualChannelWrite(remdesk->OpenHandle, - Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + Stream_Buffer(s), (UINT32) Stream_Length(s), s); if (status != CHANNEL_RC_OK) { @@ -51,8 +51,6 @@ int remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s) return -1; } - Stream_Free(s, TRUE); - return 1; } @@ -179,10 +177,135 @@ 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) +{ + UINT32 result; + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, result); /* result (4 bytes) */ + + *pResult = result; + + printf("RemdeskRecvResult: 0x%04X\n", result); + + return 1; +} + +int remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) +{ + int status; + wStream* s; + int cbExpertBlobW = 0; + WCHAR* expertBlobW = NULL; + int cbRaConnectionStringW = 0; + WCHAR* raConnectionStringW = NULL; + REMDESK_CTL_AUTHENTICATE_PDU pdu; + + pdu.expertBlob = NULL; + pdu.raConnectionString = NULL; + + status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0); + + if (status <= 0) + return -1; + + cbRaConnectionStringW = status * 2; + + status = ConvertToUnicode(CP_UTF8, 0, pdu.expertBlob, -1, &expertBlobW, 0); + + if (status <= 0) + return -1; + + cbExpertBlobW = status * 2; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_AUTHENTICATE, + cbRaConnectionStringW + cbExpertBlobW); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write(s, (BYTE*) raConnectionStringW, cbRaConnectionStringW); + Stream_Write(s, (BYTE*) expertBlobW, cbExpertBlobW); + + Stream_SealLength(s); + + remdesk_virtual_channel_write(remdesk, s); + + free(raConnectionStringW); + free(expertBlobW); + + return 1; +} + +int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) +{ + int status; + wStream* s; + int cbExpertBlobW = 0; + WCHAR* expertBlobW = NULL; + REMDESK_CTL_VERIFY_PASSWORD_PDU pdu; + + pdu.expertBlob = NULL; + + status = ConvertToUnicode(CP_UTF8, 0, pdu.expertBlob, -1, &expertBlobW, 0); + + if (status <= 0) + return -1; + + cbExpertBlobW = status * 2; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_AUTHENTICATE, cbExpertBlobW); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write(s, (BYTE*) expertBlobW, cbExpertBlobW); + + Stream_SealLength(s); + + remdesk_virtual_channel_write(remdesk, s); + + free(expertBlobW); + + return 1; +} + +int remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk) +{ + wStream* s; + BYTE EncryptedPassword[32]; + REMDESK_CTL_EXPERT_ON_VISTA_PDU pdu; + + ZeroMemory(EncryptedPassword, 32); + + pdu.EncryptedPasswordLength = 32; + pdu.EncryptedPassword = (BYTE*) EncryptedPassword; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA, + pdu.EncryptedPasswordLength); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength); + + Stream_SealLength(s); + + remdesk_virtual_channel_write(remdesk, s); + + return 1; +} + int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) { int status = 1; - UINT32 msgType; + UINT32 msgType = 0; + UINT32 result = 0; if (Stream_GetRemainingLength(s) < 4) return -1; @@ -197,6 +320,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); break; case REMDESK_CTL_AUTHENTICATE: @@ -211,6 +335,10 @@ int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEA case REMDESK_CTL_VERSIONINFO: status = remdesk_recv_ctl_version_info_pdu(remdesk, s, header); + + if (status >= 0) + status = remdesk_send_ctl_version_info_pdu(remdesk); + break; case REMDESK_CTL_ISCONNECTED: diff --git a/client/common/assistance.c b/client/common/assistance.c index 5ea6793cb..d0544a418 100644 --- a/client/common/assistance.c +++ b/client/common/assistance.c @@ -134,13 +134,13 @@ int freerdp_client_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, if (!buffer) return -1; - SHA_Init(&hashCtx); - SHA_Update(&hashCtx, pad1, 64); - SHA_Final((void*) buffer, &hashCtx); + SHA1_Init(&hashCtx); + SHA1_Update(&hashCtx, pad1, 64); + SHA1_Final((void*) buffer, &hashCtx); - SHA_Init(&hashCtx); - SHA_Update(&hashCtx, pad2, 64); - SHA_Final((void*) &buffer[hashLength], &hashCtx); + SHA1_Init(&hashCtx); + SHA1_Update(&hashCtx, pad2, 64); + SHA1_Final((void*) &buffer[hashLength], &hashCtx); CopyMemory(key, buffer, keyLength); @@ -259,6 +259,10 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass printf("EncryptedPassStub (%d):\n", file->EncryptedPassStubLength); winpr_HexDump(file->EncryptedPassStub, file->EncryptedPassStubLength); + free(PlainBlob); + free(PasswordW); + free(PassStubW); + return 1; } @@ -272,6 +276,7 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass BYTE *pbIn, *pbOut; int cbOut, cbIn, cbFinal; BYTE DerivedKey[AES_BLOCK_SIZE]; + BYTE InitializationVector[AES_BLOCK_SIZE]; BYTE PasswordHash[SHA_DIGEST_LENGTH]; status = ConvertToUnicode(CP_UTF8, 0, password, -1, &PasswordW, 0); @@ -281,9 +286,9 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass cbPasswordW = (status - 1) * 2; - SHA_Init(&shaCtx); - SHA_Update(&shaCtx, PasswordW, cbPasswordW); - SHA_Final((void*) PasswordHash, &shaCtx); + SHA1_Init(&shaCtx); + SHA1_Update(&shaCtx, PasswordW, cbPasswordW); + SHA1_Final((void*) PasswordHash, &shaCtx); status = freerdp_client_assistance_crypt_derive_key_sha1(PasswordHash, sizeof(PasswordHash), DerivedKey, sizeof(DerivedKey)); @@ -291,11 +296,19 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass if (status < 0) return -1; + ZeroMemory(InitializationVector, sizeof(InitializationVector)); + EVP_CIPHER_CTX_init(&aesDec); + status = EVP_DecryptInit_ex(&aesDec, EVP_aes_128_cbc(), NULL, NULL, NULL); + + if (status != 1) + return -1; + + EVP_CIPHER_CTX_set_key_length(&aesDec, (128 / 8)); EVP_CIPHER_CTX_set_padding(&aesDec, 0); - status = EVP_DecryptInit_ex(&aesDec, EVP_aes_128_cbc(), NULL, DerivedKey, NULL); + status = EVP_DecryptInit_ex(&aesDec, EVP_aes_128_cbc(), NULL, DerivedKey, InitializationVector); if (status != 1) return -1; @@ -303,7 +316,7 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass cbOut = cbFinal = 0; cbIn = file->EncryptedLHTicketLength; - file->ConnectionString2 = (char*) calloc(1, cbOut + AES_BLOCK_SIZE); + file->ConnectionString2 = (char*) calloc(1, cbIn + AES_BLOCK_SIZE); if (!file->ConnectionString2) return -1; @@ -318,8 +331,6 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass status = EVP_DecryptFinal_ex(&aesDec, pbOut + cbOut, &cbFinal); - /* FIXME: still fails */ - if (status != 1) { fprintf(stderr, "EVP_DecryptFinal_ex failure\n"); @@ -328,6 +339,8 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass EVP_CIPHER_CTX_cleanup(&aesDec); + free(PasswordW); + return 1; } @@ -808,8 +821,13 @@ void freerdp_client_assistance_file_free(rdpAssistanceFile* file) free(file->LHTicket); free(file->RCTicket); free(file->PassStub); + free(file->ConnectionString1); free(file->ConnectionString2); free(file->EncryptedLHTicket); + free(file->RASessionId); + free(file->RASpecificParams); + free(file->MachineAddress); + free(file->EncryptedPassStub); free(file); } diff --git a/client/common/test/TestClientAssistance.c b/client/common/test/TestClientAssistance.c index c6ec99dc1..b2802f53d 100644 --- a/client/common/test/TestClientAssistance.c +++ b/client/common/test/TestClientAssistance.c @@ -146,7 +146,7 @@ int TestClientAssistance(int argc, char* argv[]) { test_msrsc_incident_file_type1(); - //test_msrsc_incident_file_type2(); + test_msrsc_incident_file_type2(); return 0; } diff --git a/include/freerdp/channels/remdesk.h b/include/freerdp/channels/remdesk.h index f8557ca38..1613e2ebb 100644 --- a/include/freerdp/channels/remdesk.h +++ b/include/freerdp/channels/remdesk.h @@ -66,5 +66,31 @@ struct _REMDESK_CTL_VERSION_INFO_PDU }; typedef struct _REMDESK_CTL_VERSION_INFO_PDU REMDESK_CTL_VERSION_INFO_PDU; +struct _REMDESK_CTL_AUTHENTICATE_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + char* raConnectionString; + char* expertBlob; +}; +typedef struct _REMDESK_CTL_AUTHENTICATE_PDU REMDESK_CTL_AUTHENTICATE_PDU; + +struct _REMDESK_CTL_VERIFY_PASSWORD_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + char* expertBlob; +}; +typedef struct _REMDESK_CTL_VERIFY_PASSWORD_PDU REMDESK_CTL_VERIFY_PASSWORD_PDU; + +struct _REMDESK_CTL_EXPERT_ON_VISTA_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + BYTE* EncryptedPassword; + UINT32 EncryptedPasswordLength; +}; +typedef struct _REMDESK_CTL_EXPERT_ON_VISTA_PDU REMDESK_CTL_EXPERT_ON_VISTA_PDU; + #endif /* FREERDP_CHANNEL_REMDESK_H */ From b83685cdef102ce6fae3eebb36c66a311197cc74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 29 Jun 2014 20:38:33 -0400 Subject: [PATCH 17/23] client/common: start parsing Remote Assistance Connection String 2 --- client/common/assistance.c | 316 +++++++++++++++------- client/common/test/TestClientAssistance.c | 18 ++ 2 files changed, 232 insertions(+), 102 deletions(-) diff --git a/client/common/assistance.c b/client/common/assistance.c index d0544a418..a6971f4e6 100644 --- a/client/common/assistance.c +++ b/client/common/assistance.c @@ -149,6 +149,197 @@ int freerdp_client_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, return 1; } +int freerdp_client_assistance_parse_connection_string1(rdpAssistanceFile* file) +{ + int i; + char* p; + char* q; + char* str; + int count; + int length; + char* list; + char* tokens[8]; + + /** + * ,,,, + * ,,, + */ + + count = 1; + str = _strdup(file->RCTicket); + + if (!str) + return -1; + + length = strlen(str); + + for (i = 0; i < length; i++) + { + if (str[i] == ',') + count++; + } + + if (count != 8) + return -1; + + count = 0; + tokens[count++] = str; + + for (i = 0; i < length; i++) + { + if (str[i] == ',') + { + str[i] = '\0'; + tokens[count++] = &str[i + 1]; + } + } + + if (strcmp(tokens[0], "65538") != 0) + return -1; + + if (strcmp(tokens[1], "1") != 0) + return -1; + + if (strcmp(tokens[3], "*") != 0) + return -1; + + if (strcmp(tokens[5], "*") != 0) + return -1; + + if (strcmp(tokens[6], "*") != 0) + return -1; + + file->RASessionId = _strdup(tokens[4]); + + if (!file->RASessionId) + return -1; + + file->RASpecificParams = _strdup(tokens[7]); + + 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); + + free(str); + + return 1; +} + +/** + * Decrypted Connection String 2: + * + * + * + * + * + * + * + * + * + * + * + * + */ + +int freerdp_client_assistance_parse_connection_string2(rdpAssistanceFile* file) +{ + char* p; + char* q; + char* str; + size_t length; + + str = _strdup(file->ConnectionString2); + + if (!str) + return -1; + + p = strstr(str, ""); + + if (!p) + return -1; + + p = strstr(str, ""); + + if (!p) + return -1; + + /* Auth String Node () */ + + p = strstr(str, "RASpecificParams); + file->RASpecificParams = (char*) malloc(length + 1); + + if (!file->RASpecificParams) + return -1; + + CopyMemory(file->RASpecificParams, p, length); + file->RASpecificParams[length] = '\0'; + + p += length; + } + + p = strstr(p, "ID=\""); + + if (p) + { + p += sizeof("ID=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + free(file->RASessionId); + file->RASessionId = (char*) malloc(length + 1); + + if (!file->RASessionId) + return -1; + + CopyMemory(file->RASessionId, p, length); + file->RASessionId[length] = '\0'; + + p += length; + } + + free(str); + + return 1; +} + int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* password) { int status; @@ -271,6 +462,8 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass int status; SHA_CTX shaCtx; int cbPasswordW; + int cchOutW = 0; + WCHAR* pbOutW = NULL; EVP_CIPHER_CTX aesDec; WCHAR* PasswordW = NULL; BYTE *pbIn, *pbOut; @@ -315,14 +508,11 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass cbOut = cbFinal = 0; cbIn = file->EncryptedLHTicketLength; - - file->ConnectionString2 = (char*) calloc(1, cbIn + AES_BLOCK_SIZE); - - if (!file->ConnectionString2) - return -1; - pbIn = (BYTE*) file->EncryptedLHTicket; - pbOut = (BYTE*) file->ConnectionString2; + pbOut = (BYTE*) calloc(1, cbIn + AES_BLOCK_SIZE + 2); + + if (!pbOut) + return -1; status = EVP_DecryptUpdate(&aesDec, pbOut, &cbOut, pbIn, cbIn); @@ -339,7 +529,24 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass EVP_CIPHER_CTX_cleanup(&aesDec); + cbOut += cbFinal; + cbFinal = 0; + + pbOutW = (WCHAR*) pbOut; + cchOutW = cbOut / 2; + + file->ConnectionString2 = NULL; + status = ConvertFromUnicode(CP_UTF8, 0, pbOutW, cchOutW, &file->ConnectionString2, 0, NULL, NULL); + + if (status <= 0) + return -1; + free(PasswordW); + free(pbOut); + + status = freerdp_client_assistance_parse_connection_string2(file); + + printf("freerdp_client_assistance_parse_connection_string2: %d\n", status); return 1; } @@ -406,101 +613,6 @@ BYTE* freerdp_client_assistance_parse_hex_string(const char* hexStr, int* size) return buffer; } -int freerdp_client_assistance_parse_connection_string1(rdpAssistanceFile* file) -{ - int i; - char* p; - char* q; - char* str; - int count; - int length; - char* list; - char* tokens[8]; - - /** - * ,,,, - * ,,, - */ - - count = 1; - str = _strdup(file->RCTicket); - - if (!str) - return -1; - - length = strlen(str); - - for (i = 0; i < length; i++) - { - if (str[i] == ',') - count++; - } - - if (count != 8) - return -1; - - count = 0; - tokens[count++] = str; - - for (i = 0; i < length; i++) - { - if (str[i] == ',') - { - str[i] = '\0'; - tokens[count++] = &str[i + 1]; - } - } - - if (strcmp(tokens[0], "65538") != 0) - return -1; - - if (strcmp(tokens[1], "1") != 0) - return -1; - - if (strcmp(tokens[3], "*") != 0) - return -1; - - if (strcmp(tokens[5], "*") != 0) - return -1; - - if (strcmp(tokens[6], "*") != 0) - return -1; - - file->RASessionId = _strdup(tokens[4]); - - if (!file->RASessionId) - return -1; - - file->RASpecificParams = _strdup(tokens[7]); - - 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); - - free(str); - - return 1; -} - int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size) { char* p; diff --git a/client/common/test/TestClientAssistance.c b/client/common/test/TestClientAssistance.c index b2802f53d..ab645e8be 100644 --- a/client/common/test/TestClientAssistance.c +++ b/client/common/test/TestClientAssistance.c @@ -60,6 +60,22 @@ static const char* TEST_MSRC_INCIDENT_FILE_TYPE2 = "L=\"0\"/>" ""; +/** + * Decrypted Connection String 2: + * + * + * + * + * + * + * + * + * + * + * + * + */ + int test_msrsc_incident_file_type1() { int status; @@ -137,6 +153,8 @@ int test_msrsc_incident_file_type2() if (status < 0) return -1; + printf("ConnectionString2: %s\n", file->ConnectionString2); + freerdp_client_assistance_file_free(file); return 0; From dadba85f99432dd836c929c5392b10ed0940b64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 30 Jun 2014 09:21:45 -0400 Subject: [PATCH 18/23] client/common: fix remote assistance expert blob --- client/common/assistance.c | 70 ++++++++++++-------------------------- 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/client/common/assistance.c b/client/common/assistance.c index a6971f4e6..eb57d614f 100644 --- a/client/common/assistance.c +++ b/client/common/assistance.c @@ -75,43 +75,6 @@ * Use the first n bytes of the result of step 5 as the derived key. */ -int freerdp_client_assistance_crypt_derive_key_md5(BYTE* hash, int hashLength, BYTE* key, int keyLength) -{ - int i; - BYTE* buffer; - BYTE pad1[64]; - BYTE pad2[64]; - MD5_CTX hashCtx; - - memset(pad1, 0x36, 64); - memset(pad2, 0x5C, 64); - - for (i = 0; i < hashLength; i++) - { - pad1[i] ^= hash[i]; - pad2[i] ^= hash[i]; - } - - buffer = (BYTE*) calloc(1, hashLength * 2); - - if (!buffer) - return -1; - - MD5_Init(&hashCtx); - MD5_Update(&hashCtx, pad1, 64); - MD5_Final((void*) buffer, &hashCtx); - - MD5_Init(&hashCtx); - MD5_Update(&hashCtx, pad2, 64); - MD5_Final((void*) &buffer[hashLength], &hashCtx); - - CopyMemory(key, buffer, keyLength); - - free(buffer); - - return 1; -} - int freerdp_client_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* key, int keyLength) { int i; @@ -343,7 +306,6 @@ int freerdp_client_assistance_parse_connection_string2(rdpAssistanceFile* file) int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* password) { int status; - int cbOutLen; MD5_CTX md5Ctx; int cbPasswordW; int cbPassStubW; @@ -351,9 +313,11 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass BYTE* PlainBlob = NULL; WCHAR* PasswordW = NULL; WCHAR* PassStubW = NULL; + BYTE *pbIn, *pbOut; + int cbOut, cbIn, cbFinal; BYTE DerivedKey[16]; BYTE InitializationVector[16]; - BYTE PasswordHash[MD5_DIGEST_LENGTH]; + BYTE PasswordHash[16]; /** * PROV_RSA_FULL provider @@ -380,11 +344,7 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass printf("PasswordHash (%s):\n", password); winpr_HexDump(PasswordHash, sizeof(PasswordHash)); - status = freerdp_client_assistance_crypt_derive_key_md5(PasswordHash, sizeof(PasswordHash), - DerivedKey, sizeof(DerivedKey)); - - if (status < 0) - return -1; + CopyMemory(DerivedKey, PasswordHash, 16); printf("DerivedKey (%d):\n", sizeof(DerivedKey)); winpr_HexDump(DerivedKey, sizeof(DerivedKey)); @@ -420,7 +380,7 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass EVP_CIPHER_CTX_init(&rc4Ctx); - status = EVP_EncryptInit_ex(&rc4Ctx, EVP_rc4(), NULL, DerivedKey, InitializationVector); + status = EVP_EncryptInit_ex(&rc4Ctx, EVP_rc4(), NULL, NULL, NULL); if (!status) { @@ -428,8 +388,22 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass return -1; } - cbOutLen = file->EncryptedPassStubLength; - status = EVP_EncryptUpdate(&rc4Ctx, file->EncryptedPassStub, &cbOutLen, PlainBlob, file->EncryptedPassStubLength); + EVP_CIPHER_CTX_set_padding(&rc4Ctx, 0); + + status = EVP_EncryptInit_ex(&rc4Ctx, NULL, NULL, DerivedKey, InitializationVector); + + if (!status) + { + fprintf(stderr, "EVP_CipherInit_ex failure\n"); + return -1; + } + + cbOut = cbFinal = 0; + cbIn = file->EncryptedPassStubLength; + pbOut = file->EncryptedPassStub; + pbIn = PlainBlob; + + status = EVP_EncryptUpdate(&rc4Ctx, pbOut, &cbOut, pbIn, cbIn); if (!status) { @@ -437,7 +411,7 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass return -1; } - status = EVP_EncryptFinal_ex(&rc4Ctx, file->EncryptedPassStub, &cbOutLen); + status = EVP_EncryptFinal_ex(&rc4Ctx, pbOut + cbOut, &cbFinal); if (!status) { From 7a50525880ff9fe924f6d99ef875d16b83ea1d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 30 Jun 2014 09:40:24 -0400 Subject: [PATCH 19/23] libfreerdp-common: move assistance code --- client/common/CMakeLists.txt | 2 +- client/common/client.c | 2 +- client/common/test/CMakeLists.txt | 3 +- include/freerdp/{client => }/assistance.h | 6 ++-- libfreerdp/common/CMakeLists.txt | 12 ++++++- {client => libfreerdp}/common/assistance.c | 2 +- libfreerdp/common/test/.gitignore | 3 ++ libfreerdp/common/test/CMakeLists.txt | 31 +++++++++++++++++++ .../common/test/TestCommonAssistance.c | 4 +-- 9 files changed, 54 insertions(+), 11 deletions(-) rename include/freerdp/{client => }/assistance.h (94%) rename {client => libfreerdp}/common/assistance.c (99%) create mode 100644 libfreerdp/common/test/.gitignore create mode 100644 libfreerdp/common/test/CMakeLists.txt rename client/common/test/TestClientAssistance.c => libfreerdp/common/test/TestCommonAssistance.c (98%) diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index bde787ec1..9724af1d8 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -28,7 +28,6 @@ endif() set(${MODULE_PREFIX}_SRCS client.c cmdline.c - assistance.c compatibility.c compatibility.h file.c) @@ -73,4 +72,5 @@ set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Common") if(BUILD_TESTING) add_subdirectory(test) endif() + export_complex_library(LIBNAME ${MODULE_NAME}) diff --git a/client/common/client.c b/client/common/client.c index 13b46b6bf..b3b5ff391 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -24,10 +24,10 @@ #include #include +#include #include #include #include -#include int freerdp_client_common_new(freerdp* instance, rdpContext* context) { diff --git a/client/common/test/CMakeLists.txt b/client/common/test/CMakeLists.txt index bdb18ede5..b68ac11e7 100644 --- a/client/common/test/CMakeLists.txt +++ b/client/common/test/CMakeLists.txt @@ -6,8 +6,7 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS TestClientRdpFile.c - TestClientChannels.c - TestClientAssistance.c) + TestClientChannels.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} diff --git a/include/freerdp/client/assistance.h b/include/freerdp/assistance.h similarity index 94% rename from include/freerdp/client/assistance.h rename to include/freerdp/assistance.h index 6af76c668..00bd33a35 100644 --- a/include/freerdp/client/assistance.h +++ b/include/freerdp/assistance.h @@ -17,8 +17,8 @@ * limitations under the License. */ -#ifndef FREERDP_CLIENT_ASSISTANCE_H -#define FREERDP_CLIENT_ASSISTANCE_H +#ifndef FREERDP_REMOTE_ASSISTANCE_H +#define FREERDP_REMOTE_ASSISTANCE_H #include #include @@ -69,5 +69,5 @@ FREERDP_API void freerdp_client_assistance_file_free(rdpAssistanceFile* file); } #endif -#endif /* FREERDP_CLIENT_ASSISTANCE_H */ +#endif /* FREERDP_REMOTE_ASSISTANCE_H */ diff --git a/libfreerdp/common/CMakeLists.txt b/libfreerdp/common/CMakeLists.txt index 2a22526e6..bbdaa70bb 100644 --- a/libfreerdp/common/CMakeLists.txt +++ b/libfreerdp/common/CMakeLists.txt @@ -20,15 +20,22 @@ set(MODULE_PREFIX "FREERDP_COMMON") set(${MODULE_PREFIX}_SRCS addin.c - settings.c) + settings.c + assistance.c) add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" MONOLITHIC ${MONOLITHIC_BUILD} SOURCES ${${MODULE_PREFIX}_SRCS} EXPORT) +include_directories(${OPENSSL_INCLUDE_DIR}) +include_directories(${ZLIB_INCLUDE_DIRS}) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib") +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} + ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES}) + set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE winpr MODULES winpr-crt winpr-path winpr-file winpr-library winpr-utils) @@ -42,3 +49,6 @@ endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/client/common/assistance.c b/libfreerdp/common/assistance.c similarity index 99% rename from client/common/assistance.c rename to libfreerdp/common/assistance.c index eb57d614f..a9103a502 100644 --- a/client/common/assistance.c +++ b/libfreerdp/common/assistance.c @@ -37,7 +37,7 @@ #include #include -#include +#include /** * Password encryption in establishing a remote assistance session of type 1: diff --git a/libfreerdp/common/test/.gitignore b/libfreerdp/common/test/.gitignore new file mode 100644 index 000000000..fc0d9cf4c --- /dev/null +++ b/libfreerdp/common/test/.gitignore @@ -0,0 +1,3 @@ +TestCommon +TestCommon.c + diff --git a/libfreerdp/common/test/CMakeLists.txt b/libfreerdp/common/test/CMakeLists.txt new file mode 100644 index 000000000..e8096b5df --- /dev/null +++ b/libfreerdp/common/test/CMakeLists.txt @@ -0,0 +1,31 @@ + +set(MODULE_NAME "TestCommon") +set(MODULE_PREFIX "TEST_COMMON") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestCommonAssistance.c) + +create_test_sourcelist(${MODULE_PREFIX}_SRCS + ${${MODULE_PREFIX}_DRIVER} + ${${MODULE_PREFIX}_TESTS}) + +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE freerdp + MODULES freerdp-common) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") + +foreach(test ${${MODULE_PREFIX}_TESTS}) + get_filename_component(TestName ${test} NAME_WE) + add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName}) +endforeach() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Common/Test") + diff --git a/client/common/test/TestClientAssistance.c b/libfreerdp/common/test/TestCommonAssistance.c similarity index 98% rename from client/common/test/TestClientAssistance.c rename to libfreerdp/common/test/TestCommonAssistance.c index ab645e8be..697d3e303 100644 --- a/client/common/test/TestClientAssistance.c +++ b/libfreerdp/common/test/TestCommonAssistance.c @@ -2,7 +2,7 @@ #include #include -#include +#include const char* TEST_MSRC_INCIDENT_PASSWORD_TYPE1 = "Password1"; @@ -160,7 +160,7 @@ int test_msrsc_incident_file_type2() return 0; } -int TestClientAssistance(int argc, char* argv[]) +int TestCommonAssistance(int argc, char* argv[]) { test_msrsc_incident_file_type1(); From b60eff8e42edd011fdf5fd2b6aa34880aae2c733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 30 Jun 2014 12:51:27 -0400 Subject: [PATCH 20/23] channels/remdesk: start sending authentication data --- channels/remdesk/client/CMakeLists.txt | 5 + channels/remdesk/client/remdesk_main.c | 77 ++++++- channels/remdesk/client/remdesk_main.h | 5 + client/common/client.c | 6 +- client/common/cmdline.c | 26 +-- include/freerdp/assistance.h | 16 +- include/freerdp/settings.h | 8 +- libfreerdp/common/assistance.c | 194 ++++++++++-------- libfreerdp/common/settings.c | 27 +++ libfreerdp/common/test/TestCommonAssistance.c | 36 ++-- libfreerdp/core/settings.c | 3 + 11 files changed, 270 insertions(+), 133 deletions(-) diff --git a/channels/remdesk/client/CMakeLists.txt b/channels/remdesk/client/CMakeLists.txt index 9d8323634..bcc67307b 100644 --- a/channels/remdesk/client/CMakeLists.txt +++ b/channels/remdesk/client/CMakeLists.txt @@ -25,6 +25,11 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE freerdp + MODULES freerdp-common) + set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE winpr diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index 4c41f64a2..724ec0fee 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -24,6 +24,8 @@ #include #include +#include + #include #include "remdesk_main.h" @@ -42,6 +44,9 @@ 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); @@ -54,6 +59,48 @@ int remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s) return 1; } +int remdesk_generate_expert_blob(remdeskPlugin* remdesk) +{ + char* name; + char* pass; + char* password; + rdpSettings* settings = remdesk->settings; + + if (remdesk->ExpertBlob) + return 1; + + if (settings->RemoteAssistancePassword) + password = settings->RemoteAssistancePassword; + else + password = settings->Password; + + if (!password) + return -1; + + name = settings->Username; + + if (!name) + name = "Expert"; + + remdesk->EncryptedPassStub = freerdp_assistance_encrypt_pass_stub(password, + settings->RemoteAssistancePassStub, &(remdesk->EncryptedPassStubSize)); + + if (!remdesk->EncryptedPassStub) + return -1; + + pass = freerdp_assistance_bin_to_hex_string(remdesk->EncryptedPassStub, remdesk->EncryptedPassStubSize); + + if (!pass) + return -1; + + remdesk->ExpertBlob = freerdp_assistance_construct_expert_blob(name, pass); + + if (!remdesk->ExpertBlob) + return -1; + + return 1; +} + int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) { int status; @@ -91,25 +138,23 @@ int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) { - int status; + int index; UINT32 ChannelNameLen; WCHAR ChannelNameW[32]; - WCHAR* pChannelName = NULL; ZeroMemory(ChannelNameW, sizeof(ChannelNameW)); - pChannelName = (WCHAR*) ChannelNameW; - status = ConvertToUnicode(CP_UTF8, 0, header->ChannelName, -1, &pChannelName, 32); + for (index = 0; index < 32; index++) + { + ChannelNameW[index] = (WCHAR) header->ChannelName[index]; + } - if (status <= 0) - return -1; - - ChannelNameLen = (status + 1) * 2; + ChannelNameLen = strlen(header->ChannelName) * 2; Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ - Stream_Write(s, pChannelName, ChannelNameLen); /* ChannelName (variable) */ + Stream_Write(s, ChannelNameW, ChannelNameLen); /* ChannelName (variable) */ return 1; } @@ -203,8 +248,13 @@ int remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) WCHAR* raConnectionStringW = NULL; REMDESK_CTL_AUTHENTICATE_PDU pdu; - pdu.expertBlob = NULL; - pdu.raConnectionString = NULL; + status = remdesk_generate_expert_blob(remdesk); + + if (status < 0) + return -1; + + pdu.expertBlob = remdesk->ExpertBlob; + pdu.raConnectionString = remdesk->settings->RemoteAssistanceRCTicket; status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0); @@ -339,6 +389,9 @@ int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEA if (status >= 0) status = remdesk_send_ctl_version_info_pdu(remdesk); + if (status >= 0) + status = remdesk_send_ctl_authenticate_pdu(remdesk); + break; case REMDESK_CTL_ISCONNECTED: @@ -413,6 +466,8 @@ int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) static void remdesk_process_connect(remdeskPlugin* remdesk) { printf("RemdeskProcessConnect\n"); + + remdesk->settings = (rdpSettings*) remdesk->channelEntryPoints.pExtendedData; } /****************************************************************************************/ diff --git a/channels/remdesk/client/remdesk_main.h b/channels/remdesk/client/remdesk_main.h index 0a2261e34..031353be5 100644 --- a/channels/remdesk/client/remdesk_main.h +++ b/channels/remdesk/client/remdesk_main.h @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -42,8 +43,12 @@ struct remdesk_plugin void* InitHandle; DWORD OpenHandle; wMessagePipe* MsgPipe; + rdpSettings* settings; UINT32 Version; + char* ExpertBlob; + BYTE* EncryptedPassStub; + int EncryptedPassStubSize; }; typedef struct remdesk_plugin remdeskPlugin; diff --git a/client/common/client.c b/client/common/client.c index b3b5ff391..c3fea6fb2 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -179,12 +179,12 @@ int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, const c int status; rdpAssistanceFile* file; - file = freerdp_client_assistance_file_new(); + file = freerdp_assistance_file_new(); if (!file) return -1; - status = freerdp_client_assistance_parse_file(file, filename); + status = freerdp_assistance_parse_file(file, filename); if (status < 0) return -1; @@ -194,7 +194,7 @@ int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, const c if (status < 0) return -1; - freerdp_client_assistance_file_free(file); + freerdp_assistance_file_free(file); return 0; } diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 71641ea6b..392f39da2 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -156,7 +156,7 @@ COMMAND_LINE_ARGUMENT_A args[] = { "print-reconnect-cookie", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Print base64 reconnect cookie after connecting" }, { "heartbeat", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support heartbeat PDUs" }, { "multitransport", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support multitransport protocol" }, - { "assistance", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Remote assistance mode" }, + { "assistance", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Remote assistance password" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; @@ -1859,7 +1859,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "assistance") { - settings->RemoteAssistanceMode = arg->Value ? TRUE : FALSE; + settings->RemoteAssistanceMode = TRUE; + settings->RemoteAssistancePassword = _strdup(arg->Value); + + printf("AssistancePassword: %s settings: %p\n", settings->RemoteAssistancePassword, settings); } CommandLineSwitchDefault(arg) { @@ -2041,23 +2044,8 @@ int freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) if (settings->RemoteAssistanceMode) { - if (!freerdp_static_channel_collection_find(settings, "encomsp")) - { - char* params[1]; - - params[0] = "encomsp"; - - freerdp_client_add_static_channel(settings, 1, (char**) params); - } - - if (!freerdp_static_channel_collection_find(settings, "remdesk")) - { - char* params[1]; - - params[0] = "remdesk"; - - freerdp_client_add_static_channel(settings, 1, (char**) params); - } + freerdp_client_load_static_channel_addin(channels, settings, "encomsp", settings); + freerdp_client_load_static_channel_addin(channels, settings, "remdesk", settings); } for (index = 0; index < settings->StaticChannelCount; index++) diff --git a/include/freerdp/assistance.h b/include/freerdp/assistance.h index 00bd33a35..a2fe426d6 100644 --- a/include/freerdp/assistance.h +++ b/include/freerdp/assistance.h @@ -56,14 +56,20 @@ typedef struct rdp_assistance_file rdpAssistanceFile; extern "C" { #endif -FREERDP_API int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size); -FREERDP_API int freerdp_client_assistance_parse_file(rdpAssistanceFile* file, const char* name); -FREERDP_API int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* password); +FREERDP_API BYTE* freerdp_assistance_hex_string_to_bin(const char* str, int* size); +FREERDP_API char* freerdp_assistance_bin_to_hex_string(const BYTE* data, int size); + +FREERDP_API char* freerdp_assistance_construct_expert_blob(const char* name, const char* pass); +FREERDP_API BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* passStub, int* pEncryptedSize); + +FREERDP_API int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size); +FREERDP_API int freerdp_assistance_parse_file(rdpAssistanceFile* file, const char* name); +FREERDP_API int freerdp_assistance_decrypt(rdpAssistanceFile* file, const char* password); FREERDP_API int freerdp_client_populate_settings_from_assistance_file(rdpAssistanceFile* file, rdpSettings* settings); -FREERDP_API rdpAssistanceFile* freerdp_client_assistance_file_new(); -FREERDP_API void freerdp_client_assistance_file_free(rdpAssistanceFile* file); +FREERDP_API rdpAssistanceFile* freerdp_assistance_file_new(); +FREERDP_API void freerdp_assistance_file_free(rdpAssistanceFile* file); #ifdef __cplusplus } diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 2695a70cc..07fc0d354 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -587,6 +587,9 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_AllowDesktopComposition 968 #define FreeRDP_RemoteAssistanceMode 1024 #define FreeRDP_RemoteAssistanceSessionId 1025 +#define FreeRDP_RemoteAssistancePassStub 1026 +#define FreeRDP_RemoteAssistancePassword 1027 +#define FreeRDP_RemoteAssistanceRCTicket 1028 #define FreeRDP_TlsSecurity 1088 #define FreeRDP_NlaSecurity 1089 #define FreeRDP_RdpSecurity 1090 @@ -942,7 +945,10 @@ struct rdp_settings /* Remote Assistance */ ALIGN64 BOOL RemoteAssistanceMode; /* 1024 */ ALIGN64 char* RemoteAssistanceSessionId; /* 1025 */ - UINT64 padding1088[1088 - 1026]; /* 1026 */ + ALIGN64 char* RemoteAssistancePassStub; /* 1026 */ + ALIGN64 char* RemoteAssistancePassword; /* 1027 */ + ALIGN64 char* RemoteAssistanceRCTicket; /* 1028 */ + UINT64 padding1088[1088 - 1029]; /* 1029 */ /** * X.224 Connection Request/Confirm diff --git a/libfreerdp/common/assistance.c b/libfreerdp/common/assistance.c index a9103a502..87e602d4d 100644 --- a/libfreerdp/common/assistance.c +++ b/libfreerdp/common/assistance.c @@ -75,7 +75,7 @@ * Use the first n bytes of the result of step 5 as the derived key. */ -int freerdp_client_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* key, int keyLength) +int freerdp_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* key, int keyLength) { int i; BYTE* buffer; @@ -112,7 +112,7 @@ int freerdp_client_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, return 1; } -int freerdp_client_assistance_parse_connection_string1(rdpAssistanceFile* file) +int freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file) { int i; char* p; @@ -223,7 +223,7 @@ int freerdp_client_assistance_parse_connection_string1(rdpAssistanceFile* file) * */ -int freerdp_client_assistance_parse_connection_string2(rdpAssistanceFile* file) +int freerdp_assistance_parse_connection_string2(rdpAssistanceFile* file) { char* p; char* q; @@ -303,80 +303,79 @@ int freerdp_client_assistance_parse_connection_string2(rdpAssistanceFile* file) return 1; } -int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* password) +char* freerdp_assistance_construct_expert_blob(const char* name, const char* pass) +{ + int size; + int nameLength; + int passLength; + char* ExpertBlob = NULL; + + if (!name || !pass) + return NULL; + + nameLength = strlen(name) + strlen("NAME="); + passLength = strlen(pass) + strlen("PASS="); + + size = nameLength + passLength + 64; + ExpertBlob = (char*) calloc(1, size); + + if (!ExpertBlob) + return NULL; + + sprintf_s(ExpertBlob, size, "%d;NAME=%s%d;PASS=%s", + nameLength, name, passLength, pass); + + return ExpertBlob; +} + +BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* passStub, int* pEncryptedSize) { int status; MD5_CTX md5Ctx; int cbPasswordW; int cbPassStubW; + int EncryptedSize; + BYTE PasswordHash[16]; EVP_CIPHER_CTX rc4Ctx; - BYTE* PlainBlob = NULL; - WCHAR* PasswordW = NULL; - WCHAR* PassStubW = NULL; BYTE *pbIn, *pbOut; int cbOut, cbIn, cbFinal; - BYTE DerivedKey[16]; - BYTE InitializationVector[16]; - BYTE PasswordHash[16]; - - /** - * PROV_RSA_FULL provider - * CALG_MD5 hashing - * CALG_RC4 encryption - * Key Length: 40 bits - * Salt Length: 88 bits - */ + WCHAR* PasswordW = NULL; + WCHAR* PassStubW = NULL; status = ConvertToUnicode(CP_UTF8, 0, password, -1, &PasswordW, 0); if (status <= 0) - return -1; + return NULL; cbPasswordW = (status - 1) * 2; - printf("PasswordW (%d)\n", cbPasswordW); - winpr_HexDump((BYTE*) PasswordW, cbPasswordW); - MD5_Init(&md5Ctx); MD5_Update(&md5Ctx, PasswordW, cbPasswordW); MD5_Final((void*) PasswordHash, &md5Ctx); - printf("PasswordHash (%s):\n", password); - winpr_HexDump(PasswordHash, sizeof(PasswordHash)); - - CopyMemory(DerivedKey, PasswordHash, 16); - - printf("DerivedKey (%d):\n", sizeof(DerivedKey)); - winpr_HexDump(DerivedKey, sizeof(DerivedKey)); - - ZeroMemory(InitializationVector, sizeof(InitializationVector)); - - status = ConvertToUnicode(CP_UTF8, 0, file->PassStub, -1, &PassStubW, 0); + status = ConvertToUnicode(CP_UTF8, 0, passStub, -1, &PassStubW, 0); if (status <= 0) - return -1; + return NULL; cbPassStubW = (status - 1) * 2; - printf("PassStubW (%d)\n", cbPassStubW); - winpr_HexDump((BYTE*) PassStubW, cbPassStubW); + EncryptedSize = cbPassStubW + 4; - file->EncryptedPassStubLength = cbPassStubW + 4; + pbIn = (BYTE*) calloc(1, EncryptedSize); + pbOut = (BYTE*) calloc(1, EncryptedSize); - PlainBlob = (BYTE*) calloc(1, file->EncryptedPassStubLength); - file->EncryptedPassStub = (BYTE*) calloc(1, file->EncryptedPassStubLength); + if (!pbIn) + return NULL; - if (!PlainBlob) - return -1; + if (!EncryptedSize) + return NULL; - if (!file->EncryptedPassStubLength) - return -1; + *((UINT32*) pbIn) = cbPassStubW; + CopyMemory(&pbIn[4], PassStubW, cbPassStubW); - *((UINT32*) PlainBlob) = cbPassStubW; - CopyMemory(&PlainBlob[4], PassStubW, cbPassStubW); - - printf("PlainBlob (%d)\n", file->EncryptedPassStubLength); - winpr_HexDump(PlainBlob, file->EncryptedPassStubLength); + printf("PlainBlob (%d)\n", EncryptedSize); + winpr_HexDump(pbIn, EncryptedSize); EVP_CIPHER_CTX_init(&rc4Ctx); @@ -385,30 +384,26 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass if (!status) { fprintf(stderr, "EVP_CipherInit_ex failure\n"); - return -1; + return NULL; } - EVP_CIPHER_CTX_set_padding(&rc4Ctx, 0); - - status = EVP_EncryptInit_ex(&rc4Ctx, NULL, NULL, DerivedKey, InitializationVector); + status = EVP_EncryptInit_ex(&rc4Ctx, NULL, NULL, PasswordHash, NULL); if (!status) { fprintf(stderr, "EVP_CipherInit_ex failure\n"); - return -1; + return NULL; } cbOut = cbFinal = 0; - cbIn = file->EncryptedPassStubLength; - pbOut = file->EncryptedPassStub; - pbIn = PlainBlob; + cbIn = EncryptedSize; status = EVP_EncryptUpdate(&rc4Ctx, pbOut, &cbOut, pbIn, cbIn); if (!status) { fprintf(stderr, "EVP_CipherUpdate failure\n"); - return -1; + return NULL; } status = EVP_EncryptFinal_ex(&rc4Ctx, pbOut + cbOut, &cbFinal); @@ -416,22 +411,24 @@ int freerdp_client_assistance_decrypt1(rdpAssistanceFile* file, const char* pass if (!status) { fprintf(stderr, "EVP_CipherFinal_ex failure\n"); - return -1; + return NULL; } EVP_CIPHER_CTX_cleanup(&rc4Ctx); - printf("EncryptedPassStub (%d):\n", file->EncryptedPassStubLength); - winpr_HexDump(file->EncryptedPassStub, file->EncryptedPassStubLength); + printf("EncryptedBlob (%d):\n", EncryptedSize); + winpr_HexDump(pbOut, EncryptedSize); - free(PlainBlob); + free(pbIn); free(PasswordW); free(PassStubW); - return 1; + *pEncryptedSize = EncryptedSize; + + return pbOut; } -int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* password) +int freerdp_assistance_decrypt2(rdpAssistanceFile* file, const char* password) { int status; SHA_CTX shaCtx; @@ -457,7 +454,7 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass SHA1_Update(&shaCtx, PasswordW, cbPasswordW); SHA1_Final((void*) PasswordHash, &shaCtx); - status = freerdp_client_assistance_crypt_derive_key_sha1(PasswordHash, sizeof(PasswordHash), + status = freerdp_assistance_crypt_derive_key_sha1(PasswordHash, sizeof(PasswordHash), DerivedKey, sizeof(DerivedKey)); if (status < 0) @@ -518,35 +515,39 @@ int freerdp_client_assistance_decrypt2(rdpAssistanceFile* file, const char* pass free(PasswordW); free(pbOut); - status = freerdp_client_assistance_parse_connection_string2(file); + status = freerdp_assistance_parse_connection_string2(file); - printf("freerdp_client_assistance_parse_connection_string2: %d\n", status); + printf("freerdp_assistance_parse_connection_string2: %d\n", status); return 1; } -int freerdp_client_assistance_decrypt(rdpAssistanceFile* file, const char* password) +int freerdp_assistance_decrypt(rdpAssistanceFile* file, const char* password) { - int status; + int status = 1; - status = freerdp_client_assistance_decrypt1(file, password); + file->EncryptedPassStub = freerdp_assistance_encrypt_pass_stub(password, + file->PassStub, &file->EncryptedPassStubLength); + + if (!file->EncryptedPassStub) + return -1; if (file->Type > 1) { - status = freerdp_client_assistance_decrypt2(file, password); + status = freerdp_assistance_decrypt2(file, password); } return status; } -BYTE* freerdp_client_assistance_parse_hex_string(const char* hexStr, int* size) +BYTE* freerdp_assistance_hex_string_to_bin(const char* str, int* size) { char c; int length; BYTE* buffer; int i, ln, hn; - length = strlen(hexStr); + length = strlen(str); if ((length % 2) != 0) return NULL; @@ -563,7 +564,7 @@ BYTE* freerdp_client_assistance_parse_hex_string(const char* hexStr, int* size) { hn = ln = 0; - c = hexStr[(i * 2) + 0]; + c = str[(i * 2) + 0]; if ((c >= '0') && (c <= '9')) hn = c - '0'; @@ -572,7 +573,7 @@ BYTE* freerdp_client_assistance_parse_hex_string(const char* hexStr, int* size) else if ((c >= 'A') && (c <= 'F')) hn = (c - 'A') + 10; - c = hexStr[(i * 2) + 1]; + c = str[(i * 2) + 1]; if ((c >= '0') && (c <= '9')) ln = c - '0'; @@ -587,7 +588,30 @@ BYTE* freerdp_client_assistance_parse_hex_string(const char* hexStr, int* size) return buffer; } -int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size) +char* freerdp_assistance_bin_to_hex_string(const BYTE* data, int size) +{ + int i; + char* p; + int ln, hn; + char bin2hex[] = "0123456789ABCDEF"; + + p = (char*) malloc((size + 1) * 2); + + for (i = 0; i < size; i++) + { + ln = data[i] & 0xF; + hn = (data[i] >> 4) & 0xF; + + p[i * 2] = bin2hex[hn]; + p[(i * 2) + 1] = bin2hex[ln]; + } + + p[size * 2] = '\0'; + + return p; +} + +int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size) { char* p; char* q; @@ -801,22 +825,22 @@ int freerdp_client_assistance_parse_file_buffer(rdpAssistanceFile* file, const c if (file->LHTicket) { - file->EncryptedLHTicket = freerdp_client_assistance_parse_hex_string(file->LHTicket, + file->EncryptedLHTicket = freerdp_assistance_hex_string_to_bin(file->LHTicket, &file->EncryptedLHTicketLength); } - status = freerdp_client_assistance_parse_connection_string1(file); + status = freerdp_assistance_parse_connection_string1(file); if (status < 0) { - fprintf(stderr, "freerdp_client_assistance_parse_connection_string1 failure: %d\n", status); + fprintf(stderr, "freerdp_assistance_parse_connection_string1 failure: %d\n", status); return -1; } return 1; } -int freerdp_client_assistance_parse_file(rdpAssistanceFile* file, const char* name) +int freerdp_assistance_parse_file(rdpAssistanceFile* file, const char* name) { int status; BYTE* buffer; @@ -859,7 +883,7 @@ int freerdp_client_assistance_parse_file(rdpAssistanceFile* file, const char* na buffer[fileSize] = '\0'; buffer[fileSize + 1] = '\0'; - status = freerdp_client_assistance_parse_file_buffer(file, (char*) buffer, fileSize); + status = freerdp_assistance_parse_file_buffer(file, (char*) buffer, fileSize); free(buffer); @@ -875,6 +899,12 @@ int freerdp_client_populate_settings_from_assistance_file(rdpAssistanceFile* fil freerdp_set_param_string(settings, FreeRDP_RemoteAssistanceSessionId, file->RASessionId); + if (file->RCTicket) + freerdp_set_param_string(settings, FreeRDP_RemoteAssistanceRCTicket, file->RCTicket); + + if (file->PassStub) + freerdp_set_param_string(settings, FreeRDP_RemoteAssistancePassStub, file->PassStub); + if (!file->MachineAddress) return -1; @@ -884,7 +914,7 @@ int freerdp_client_populate_settings_from_assistance_file(rdpAssistanceFile* fil return 1; } -rdpAssistanceFile* freerdp_client_assistance_file_new() +rdpAssistanceFile* freerdp_assistance_file_new() { rdpAssistanceFile* file; @@ -898,7 +928,7 @@ rdpAssistanceFile* freerdp_client_assistance_file_new() return file; } -void freerdp_client_assistance_file_free(rdpAssistanceFile* file) +void freerdp_assistance_file_free(rdpAssistanceFile* file) { if (!file) return; diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 12fe064a6..97df29b15 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -2380,6 +2380,18 @@ char* freerdp_get_param_string(rdpSettings* settings, int id) return settings->RemoteAssistanceSessionId; break; + case FreeRDP_RemoteAssistancePassStub: + return settings->RemoteAssistancePassStub; + break; + + case FreeRDP_RemoteAssistancePassword: + return settings->RemoteAssistancePassword; + break; + + case FreeRDP_RemoteAssistanceRCTicket: + return settings->RemoteAssistanceRCTicket; + break; + case FreeRDP_AuthenticationServiceClass: return settings->AuthenticationServiceClass; break; @@ -2574,6 +2586,21 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param) settings->RemoteAssistanceSessionId = _strdup(param); break; + case FreeRDP_RemoteAssistancePassStub: + free(settings->RemoteAssistancePassStub); + settings->RemoteAssistancePassStub = _strdup(param); + break; + + case FreeRDP_RemoteAssistancePassword: + free(settings->RemoteAssistancePassword); + settings->RemoteAssistancePassword = _strdup(param); + break; + + case FreeRDP_RemoteAssistanceRCTicket: + free(settings->RemoteAssistanceRCTicket); + settings->RemoteAssistanceRCTicket = _strdup(param); + break; + case FreeRDP_AuthenticationServiceClass: free(settings->AuthenticationServiceClass); settings->AuthenticationServiceClass = _strdup(param); diff --git a/libfreerdp/common/test/TestCommonAssistance.c b/libfreerdp/common/test/TestCommonAssistance.c index 697d3e303..411152508 100644 --- a/libfreerdp/common/test/TestCommonAssistance.c +++ b/libfreerdp/common/test/TestCommonAssistance.c @@ -79,14 +79,16 @@ static const char* TEST_MSRC_INCIDENT_FILE_TYPE2 = int test_msrsc_incident_file_type1() { int status; + char* pass; + char* expertBlob; rdpAssistanceFile* file; - file = freerdp_client_assistance_file_new(); + file = freerdp_assistance_file_new(); - status = freerdp_client_assistance_parse_file_buffer(file, + status = freerdp_assistance_parse_file_buffer(file, TEST_MSRC_INCIDENT_FILE_TYPE1, sizeof(TEST_MSRC_INCIDENT_FILE_TYPE1)); - printf("freerdp_client_assistance_parse_file_buffer: %d\n", status); + printf("freerdp_assistance_parse_file_buffer: %d\n", status); if (status < 0) return -1; @@ -105,14 +107,24 @@ int test_msrsc_incident_file_type1() printf("MachineAddress: %s\n", file->MachineAddress); printf("MachinePort: %d\n", (int) file->MachinePort); - status = freerdp_client_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD_TYPE1); + status = freerdp_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD_TYPE1); - printf("freerdp_client_assistance_decrypt: %d\n", status); + printf("freerdp_assistance_decrypt: %d\n", status); if (status < 0) return -1; - freerdp_client_assistance_file_free(file); + pass = freerdp_assistance_bin_to_hex_string(file->EncryptedPassStub, file->EncryptedPassStubLength); + + if (!pass) + return -1; + + expertBlob = freerdp_assistance_construct_expert_blob("Edgar Olougouna", pass); + + freerdp_assistance_file_free(file); + + free(pass); + free(expertBlob); return 0; } @@ -122,12 +134,12 @@ int test_msrsc_incident_file_type2() int status; rdpAssistanceFile* file; - file = freerdp_client_assistance_file_new(); + file = freerdp_assistance_file_new(); - status = freerdp_client_assistance_parse_file_buffer(file, + status = freerdp_assistance_parse_file_buffer(file, TEST_MSRC_INCIDENT_FILE_TYPE2, sizeof(TEST_MSRC_INCIDENT_FILE_TYPE2)); - printf("freerdp_client_assistance_parse_file_buffer: %d\n", status); + printf("freerdp_assistance_parse_file_buffer: %d\n", status); if (status < 0) return -1; @@ -146,16 +158,16 @@ int test_msrsc_incident_file_type2() printf("MachineAddress: %s\n", file->MachineAddress); printf("MachinePort: %d\n", (int) file->MachinePort); - status = freerdp_client_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD_TYPE2); + status = freerdp_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD_TYPE2); - printf("freerdp_client_assistance_decrypt: %d\n", status); + printf("freerdp_assistance_decrypt: %d\n", status); if (status < 0) return -1; printf("ConnectionString2: %s\n", file->ConnectionString2); - freerdp_client_assistance_file_free(file); + freerdp_assistance_file_free(file); return 0; } diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 0843bbdd6..fc40a0633 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -465,6 +465,9 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->ClientDir = _strdup(settings->ClientDir); /* 770 */ _settings->DynamicDSTTimeZoneKeyName = _strdup(settings->DynamicDSTTimeZoneKeyName); /* 897 */ _settings->RemoteAssistanceSessionId = _strdup(settings->RemoteAssistanceSessionId); /* 1025 */ + _settings->RemoteAssistancePassStub = _strdup(settings->RemoteAssistancePassStub); /* 1026 */ + _settings->RemoteAssistancePassword = _strdup(settings->RemoteAssistancePassword); /* 1027 */ + _settings->RemoteAssistanceRCTicket = _strdup(settings->RemoteAssistanceRCTicket); /* 1028 */ _settings->AuthenticationServiceClass = _strdup(settings->AuthenticationServiceClass); /* 1098 */ _settings->PreconnectionBlob = _strdup(settings->PreconnectionBlob); /* 1155 */ _settings->KerberosKdc = _strdup(settings->KerberosKdc); /* 1344 */ From 5606c64f618861c2c9d7d96515ebde02d83b970d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 30 Jun 2014 13:26:11 -0400 Subject: [PATCH 21/23] channels/remdesk: initial working Remote Assistance --- channels/remdesk/client/remdesk_main.c | 80 ++++++++++++++++++++++---- client/common/cmdline.c | 2 - include/freerdp/channels/remdesk.h | 8 +++ 3 files changed, 76 insertions(+), 14 deletions(-) diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index 724ec0fee..4973eabee 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -149,7 +149,7 @@ int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) ChannelNameW[index] = (WCHAR) header->ChannelName[index]; } - ChannelNameLen = strlen(header->ChannelName) * 2; + ChannelNameLen = (strlen(header->ChannelName) + 1) * 2; Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ @@ -168,7 +168,7 @@ int remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize) { - ctlHeader->msgType = REMDESK_CTL_VERSIONINFO; + ctlHeader->msgType = msgType; strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME); ctlHeader->DataLength = 4 + msgSize; return 1; @@ -290,6 +290,40 @@ int remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) return 1; } +int remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk) +{ + int status; + wStream* s; + int cbRaConnectionStringW = 0; + WCHAR* raConnectionStringW = NULL; + REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU pdu; + + pdu.raConnectionString = remdesk->settings->RemoteAssistanceRCTicket; + + status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0); + + if (status <= 0) + return -1; + + cbRaConnectionStringW = status * 2; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_REMOTE_CONTROL_DESKTOP, cbRaConnectionStringW); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write(s, (BYTE*) raConnectionStringW, cbRaConnectionStringW); + + Stream_SealLength(s); + + remdesk_virtual_channel_write(remdesk, s); + + free(raConnectionStringW); + + return 1; +} + int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) { int status; @@ -298,7 +332,12 @@ int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) WCHAR* expertBlobW = NULL; REMDESK_CTL_VERIFY_PASSWORD_PDU pdu; - pdu.expertBlob = NULL; + status = remdesk_generate_expert_blob(remdesk); + + if (status < 0) + return -1; + + pdu.expertBlob = remdesk->ExpertBlob; status = ConvertToUnicode(CP_UTF8, 0, pdu.expertBlob, -1, &expertBlobW, 0); @@ -307,7 +346,7 @@ int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) cbExpertBlobW = status * 2; - remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_AUTHENTICATE, cbExpertBlobW); + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW); s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); @@ -326,14 +365,17 @@ int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) int remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk) { + int status; wStream* s; - BYTE EncryptedPassword[32]; REMDESK_CTL_EXPERT_ON_VISTA_PDU pdu; - ZeroMemory(EncryptedPassword, 32); + status = remdesk_generate_expert_blob(remdesk); - pdu.EncryptedPasswordLength = 32; - pdu.EncryptedPassword = (BYTE*) EncryptedPassword; + if (status < 0) + return -1; + + pdu.EncryptedPasswordLength = remdesk->EncryptedPassStubSize; + pdu.EncryptedPassword = remdesk->EncryptedPassStub; remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA, pdu.EncryptedPasswordLength); @@ -386,11 +428,25 @@ int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEA case REMDESK_CTL_VERSIONINFO: status = remdesk_recv_ctl_version_info_pdu(remdesk, s, header); - if (status >= 0) - status = remdesk_send_ctl_version_info_pdu(remdesk); + if (remdesk->Version == 1) + { + if (status >= 0) + status = remdesk_send_ctl_version_info_pdu(remdesk); - if (status >= 0) - status = remdesk_send_ctl_authenticate_pdu(remdesk); + if (status >= 0) + status = remdesk_send_ctl_authenticate_pdu(remdesk); + + if (status >= 0) + status = remdesk_send_ctl_remote_control_desktop_pdu(remdesk); + } + else if (remdesk->Version == 2) + { + if (status >= 0) + status = remdesk_send_ctl_expert_on_vista_pdu(remdesk); + + if (status >= 0) + status = remdesk_send_ctl_verify_password_pdu(remdesk); + } break; diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 392f39da2..4d311366e 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -1861,8 +1861,6 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->RemoteAssistanceMode = TRUE; settings->RemoteAssistancePassword = _strdup(arg->Value); - - printf("AssistancePassword: %s settings: %p\n", settings->RemoteAssistancePassword, settings); } CommandLineSwitchDefault(arg) { diff --git a/include/freerdp/channels/remdesk.h b/include/freerdp/channels/remdesk.h index 1613e2ebb..a3fa55ac2 100644 --- a/include/freerdp/channels/remdesk.h +++ b/include/freerdp/channels/remdesk.h @@ -75,6 +75,14 @@ struct _REMDESK_CTL_AUTHENTICATE_PDU }; typedef struct _REMDESK_CTL_AUTHENTICATE_PDU REMDESK_CTL_AUTHENTICATE_PDU; +struct _REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + char* raConnectionString; +}; +typedef struct _REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU; + struct _REMDESK_CTL_VERIFY_PASSWORD_PDU { REMDESK_CTL_HEADER ctlHeader; 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 22/23] 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); From 4b6edb913c09002abdbf3be8d4f103158826405f Mon Sep 17 00:00:00 2001 From: Hardening Date: Wed, 2 Jul 2014 10:31:45 +0200 Subject: [PATCH 23/23] Make server sound thread optionnal This patch makes the server-side sound channel thread optionnal, and exposes functions to handle channel traffic from the outside. --- channels/rdpsnd/server/rdpsnd_main.c | 257 ++++++++++++++++----------- channels/rdpsnd/server/rdpsnd_main.h | 6 + include/freerdp/server/rdpsnd.h | 8 +- server/Sample/sf_rdpsnd.c | 2 +- 4 files changed, 163 insertions(+), 110 deletions(-) diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index d123b8177..8ad5cd984 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -31,7 +31,7 @@ #include "rdpsnd_main.h" -static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) +BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) { int pos; UINT16 i; @@ -187,49 +187,20 @@ out_free: static void* rdpsnd_server_thread(void* arg) { - wStream* s; - DWORD status; - DWORD nCount; - void* buffer; - BYTE msgType; - UINT16 BodySize; + DWORD nCount, status; HANDLE events[8]; - HANDLE ChannelEvent; - DWORD bytesReturned; RdpsndServerContext* context; BOOL doRun; - BOOL waitingHeader; - DWORD expectedBytes; context = (RdpsndServerContext *)arg; - - buffer = NULL; - bytesReturned = 0; - - s = Stream_New(NULL, 4096); - if (!s) - return NULL; - - if (!WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) - { - fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n", - __FUNCTION__, bytesReturned); - return NULL; - } - - CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); - WTSFreeMemory(buffer); - nCount = 0; - events[nCount++] = ChannelEvent; + events[nCount++] = context->priv->channelEvent; events[nCount++] = context->priv->StopEvent; - if (!rdpsnd_server_send_formats(context, s)) + if (!rdpsnd_server_send_formats(context, context->priv->rdpsnd_pdu)) goto out; doRun = TRUE; - waitingHeader = TRUE; - expectedBytes = 4; while (doRun) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); @@ -237,69 +208,17 @@ static void* rdpsnd_server_thread(void* arg) if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) break; - if (!WTSVirtualChannelRead(ChannelEvent, 0, (PCHAR)Stream_Pointer(s), expectedBytes, &bytesReturned)) - { - fprintf(stderr, "%s: channel connection closed\n", __FUNCTION__); + if (!rdpsnd_server_handle_messages(context)) break; - } - expectedBytes -= bytesReturned; - Stream_Seek(s, bytesReturned); - - if (expectedBytes) - continue; - - Stream_SetPosition(s, 0); - if (waitingHeader) - { - /* header case */ - Stream_Read_UINT8(s, msgType); - Stream_Seek_UINT8(s); /* bPad */ - Stream_Read_UINT16(s, BodySize); - - expectedBytes = BodySize; - waitingHeader = FALSE; - Stream_SetPosition(s, 0); - Stream_EnsureCapacity(s, BodySize); - if (expectedBytes) - continue; - } - - /* when here we have the header + the body */ - switch (msgType) - { - case SNDC_WAVECONFIRM: - doRun = rdpsnd_server_recv_waveconfirm(context, s); - break; - - case SNDC_QUALITYMODE: - doRun = rdpsnd_server_recv_quality_mode(context, s); - break; - - case SNDC_FORMATS: - doRun = rdpsnd_server_recv_formats(context, s); - if (doRun) - { - IFCALL(context->Activated, context); - } - break; - - default: - fprintf(stderr, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, msgType); - break; - } - - expectedBytes = 4; - waitingHeader = TRUE; - Stream_SetPosition(s, 0); } out: - Stream_Free(s, TRUE); return NULL; } -static BOOL rdpsnd_server_initialize(RdpsndServerContext* context) +static BOOL rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread) { + context->priv->ownThread = ownThread; return context->Start(context) >= 0; } @@ -546,22 +465,41 @@ static BOOL rdpsnd_server_close(RdpsndServerContext* context) static int rdpsnd_server_start(RdpsndServerContext* context) { - context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); - if (!context->priv->ChannelHandle) + void *buffer = NULL; + DWORD bytesReturned; + RdpsndServerPrivate *priv = context->priv; + + priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); + if (!priv->ChannelHandle) return -1; - context->priv->rdpsnd_pdu = Stream_New(NULL, 4096); - if (!context->priv->rdpsnd_pdu) + if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) + { + fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n", + __FUNCTION__, bytesReturned); + if (buffer) + WTSFreeMemory(buffer); + goto out_close; + } + CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE)); + WTSFreeMemory(buffer); + + priv->rdpsnd_pdu = Stream_New(NULL, 4096); + if (!priv->rdpsnd_pdu) goto out_close; - context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!context->priv->StopEvent) - goto out_pdu; - context->priv->Thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL); - if (!context->priv->Thread) - goto out_stopEvent; + if (priv->ownThread) + { + context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!context->priv->StopEvent) + goto out_pdu; + + context->priv->Thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL); + if (!context->priv->Thread) + goto out_stopEvent; + } return 0; @@ -579,12 +517,15 @@ out_close: static int rdpsnd_server_stop(RdpsndServerContext* context) { - if (context->priv->StopEvent) + if (context->priv->ownThread) { - SetEvent(context->priv->StopEvent); + if (context->priv->StopEvent) + { + SetEvent(context->priv->StopEvent); - WaitForSingleObject(context->priv->Thread, INFINITE); - CloseHandle(context->priv->Thread); + WaitForSingleObject(context->priv->Thread, INFINITE); + CloseHandle(context->priv->Thread); + } } return 0; @@ -593,8 +534,9 @@ static int rdpsnd_server_stop(RdpsndServerContext* context) RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) { RdpsndServerContext* context; + RdpsndServerPrivate *priv; - context = (RdpsndServerContext*) calloc(1, sizeof(RdpsndServerContext)); + context = (RdpsndServerContext *)calloc(1, sizeof(RdpsndServerContext)); if (!context) return NULL; @@ -610,16 +552,25 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) context->SetVolume = rdpsnd_server_set_volume; context->Close = rdpsnd_server_close; - context->priv = (RdpsndServerPrivate*) calloc(1, sizeof(RdpsndServerPrivate)); - if (!context->priv) + context->priv = priv = (RdpsndServerPrivate *)calloc(1, sizeof(RdpsndServerPrivate)); + if (!priv) goto out_free; - context->priv->dsp_context = freerdp_dsp_context_new(); - if (!context->priv->dsp_context) + priv->dsp_context = freerdp_dsp_context_new(); + if (!priv->dsp_context) goto out_free_priv; + priv->input_stream = Stream_New(NULL, 4); + if (!priv->input_stream) + goto out_free_dsp; + + priv->expectedBytes = 4; + priv->waitingHeader = TRUE; + priv->ownThread = TRUE; return context; +out_free_dsp: + freerdp_dsp_context_free(priv->dsp_context); out_free_priv: free(context->priv); out_free: @@ -627,6 +578,15 @@ out_free: return NULL; } + +void rdpsnd_server_context_reset(RdpsndServerContext *context) +{ + context->priv->expectedBytes = 4; + context->priv->waitingHeader = TRUE; + + Stream_SetPosition(context->priv->input_stream, 0); +} + void rdpsnd_server_context_free(RdpsndServerContext* context) { if (!context->priv->StopEvent) @@ -652,3 +612,84 @@ void rdpsnd_server_context_free(RdpsndServerContext* context) free(context); } + +HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext *context) +{ + return context->priv->channelEvent; +} + +BOOL rdpsnd_server_handle_messages(RdpsndServerContext *context) +{ + DWORD bytesReturned; + BOOL ret; + + RdpsndServerPrivate *priv = context->priv; + wStream *s = priv->input_stream; + + if (!WTSVirtualChannelRead(priv->channelEvent, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned)) + { + if (GetLastError() == ERROR_NO_DATA) + return TRUE; + + fprintf(stderr, "%s: channel connection closed\n", __FUNCTION__); + return FALSE; + } + priv->expectedBytes -= bytesReturned; + Stream_Seek(s, bytesReturned); + + if (priv->expectedBytes) + return TRUE; + + Stream_SetPosition(s, 0); + if (priv->waitingHeader) + { + /* header case */ + Stream_Read_UINT8(s, priv->msgType); + Stream_Seek_UINT8(s); /* bPad */ + Stream_Read_UINT16(s, priv->expectedBytes); + + priv->waitingHeader = FALSE; + Stream_SetPosition(s, 0); + if (priv->expectedBytes) + { + Stream_EnsureCapacity(s, priv->expectedBytes); + return TRUE; + } + } + + /* when here we have the header + the body */ +#ifdef WITH_DEBUG_SND + fprintf(stderr, "%s: message type %d\n", __FUNCTION__, priv->msgType); +#endif + priv->expectedBytes = 4; + priv->waitingHeader = TRUE; + + switch (priv->msgType) + { + case SNDC_WAVECONFIRM: + ret = rdpsnd_server_recv_waveconfirm(context, s); + break; + + case SNDC_FORMATS: + ret = rdpsnd_server_recv_formats(context, s); + break; + + case SNDC_QUALITYMODE: + ret = rdpsnd_server_recv_quality_mode(context, s); + Stream_SetPosition(s, 0); /* in case the Activated callback tries to treat some messages */ + + if (ret) + { + IFCALL(context->Activated, context); + } + break; + + default: + fprintf(stderr, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, priv->msgType); + ret = FALSE; + break; + } + Stream_SetPosition(s, 0); + + return ret; +} diff --git a/channels/rdpsnd/server/rdpsnd_main.h b/channels/rdpsnd/server/rdpsnd_main.h index 6322cee4a..667c211ee 100644 --- a/channels/rdpsnd/server/rdpsnd_main.h +++ b/channels/rdpsnd/server/rdpsnd_main.h @@ -31,10 +31,16 @@ struct _rdpsnd_server_private { + BOOL ownThread; HANDLE Thread; HANDLE StopEvent; + HANDLE channelEvent; void* ChannelHandle; + BOOL waitingHeader; + DWORD expectedBytes; + BYTE msgType; + wStream* input_stream; wStream* rdpsnd_pdu; BYTE* out_buffer; int out_buffer_size; diff --git a/include/freerdp/server/rdpsnd.h b/include/freerdp/server/rdpsnd.h index 96da14d5c..e886002c3 100644 --- a/include/freerdp/server/rdpsnd.h +++ b/include/freerdp/server/rdpsnd.h @@ -30,13 +30,14 @@ typedef struct _rdpsnd_server_private RdpsndServerPrivate; typedef int (*psRdpsndStart)(RdpsndServerContext* context); typedef int (*psRdpsndStop)(RdpsndServerContext* context); -typedef BOOL (*psRdpsndServerInitialize)(RdpsndServerContext* context); +typedef BOOL (*psRdpsndServerInitialize)(RdpsndServerContext* context, BOOL ownThread); typedef BOOL (*psRdpsndServerSelectFormat)(RdpsndServerContext* context, int client_format_index); typedef BOOL (*psRdpsndServerSendSamples)(RdpsndServerContext* context, const void* buf, int nframes, UINT16 wTimestamp); typedef BOOL (*psRdpsndServerConfirmBlock)(RdpsndServerContext* context, BYTE confirmBlockNum, UINT16 wtimestamp); typedef BOOL (*psRdpsndServerSetVolume)(RdpsndServerContext* context, int left, int right); typedef BOOL (*psRdpsndServerClose)(RdpsndServerContext* context); + typedef void (*psRdpsndServerActivated)(RdpsndServerContext* context); struct _rdpsnd_server_context @@ -111,7 +112,12 @@ extern "C" { #endif FREERDP_API RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm); +FREERDP_API void rdpsnd_server_context_reset(RdpsndServerContext *); FREERDP_API void rdpsnd_server_context_free(RdpsndServerContext* context); +FREERDP_API HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext *context); +FREERDP_API BOOL rdpsnd_server_handle_messages(RdpsndServerContext *context); +FREERDP_API BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s); + #ifdef __cplusplus } diff --git a/server/Sample/sf_rdpsnd.c b/server/Sample/sf_rdpsnd.c index 9a1b70bcb..4f42fa946 100644 --- a/server/Sample/sf_rdpsnd.c +++ b/server/Sample/sf_rdpsnd.c @@ -52,7 +52,7 @@ BOOL sf_peer_rdpsnd_init(testPeerContext* context) context->rdpsnd->Activated = sf_peer_rdpsnd_activated; - context->rdpsnd->Initialize(context->rdpsnd); + context->rdpsnd->Initialize(context->rdpsnd, TRUE); return TRUE; }