From a9bcc81f821d7c66f623779fa5147e728eb3c388 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 03:24:41 +0200 Subject: Adding upstream version 3.3.0+dfsg1. Signed-off-by: Daniel Baumann --- channels/echo/CMakeLists.txt | 26 +++ channels/echo/ChannelOptions.cmake | 13 ++ channels/echo/client/CMakeLists.txt | 30 +++ channels/echo/client/echo_main.c | 92 +++++++++ channels/echo/client/echo_main.h | 40 ++++ channels/echo/server/CMakeLists.txt | 27 +++ channels/echo/server/echo_main.c | 381 ++++++++++++++++++++++++++++++++++++ 7 files changed, 609 insertions(+) create mode 100644 channels/echo/CMakeLists.txt create mode 100644 channels/echo/ChannelOptions.cmake create mode 100644 channels/echo/client/CMakeLists.txt create mode 100644 channels/echo/client/echo_main.c create mode 100644 channels/echo/client/echo_main.h create mode 100644 channels/echo/server/CMakeLists.txt create mode 100644 channels/echo/server/echo_main.c (limited to 'channels/echo') diff --git a/channels/echo/CMakeLists.txt b/channels/echo/CMakeLists.txt new file mode 100644 index 0000000..bfa8297 --- /dev/null +++ b/channels/echo/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("echo") + +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/echo/ChannelOptions.cmake b/channels/echo/ChannelOptions.cmake new file mode 100644 index 0000000..eb4950a --- /dev/null +++ b/channels/echo/ChannelOptions.cmake @@ -0,0 +1,13 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "echo" TYPE "dynamic" + DESCRIPTION "Echo Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPEECO]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) + diff --git a/channels/echo/client/CMakeLists.txt b/channels/echo/client/CMakeLists.txt new file mode 100644 index 0000000..a66443d --- /dev/null +++ b/channels/echo/client/CMakeLists.txt @@ -0,0 +1,30 @@ +# 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("echo") + +set(${MODULE_PREFIX}_SRCS + echo_main.c + echo_main.h +) + +set(${MODULE_PREFIX}_LIBS + winpr +) +include_directories(..) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") diff --git a/channels/echo/client/echo_main.c b/channels/echo/client/echo_main.c new file mode 100644 index 0000000..c4e1c22 --- /dev/null +++ b/channels/echo/client/echo_main.c @@ -0,0 +1,92 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Echo Virtual Channel Extension + * + * Copyright 2013 Christian Hofstaedtler + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * + * 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. + */ + +#include + +#include +#include + +#include +#include +#include + +#include "echo_main.h" +#include +#include +#include + +#define TAG CHANNELS_TAG("echo.client") + +typedef struct +{ + GENERIC_DYNVC_PLUGIN baseDynPlugin; +} ECHO_PLUGIN; + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) +{ + GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback; + const BYTE* pBuffer = Stream_ConstPointer(data); + const size_t cbSize = Stream_GetRemainingLength(data); + + WINPR_ASSERT(callback); + WINPR_ASSERT(callback->channel); + WINPR_ASSERT(callback->channel->Write); + + if (cbSize > UINT32_MAX) + return ERROR_INVALID_PARAMETER; + + /* echo back what we have received. ECHO does not have any message IDs. */ + return callback->channel->Write(callback->channel, (ULONG)cbSize, pBuffer, NULL); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT echo_on_close(IWTSVirtualChannelCallback* pChannelCallback) +{ + GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback; + + free(callback); + + return CHANNEL_RC_OK; +} + +static const IWTSVirtualChannelCallback echo_callbacks = { echo_on_data_received, NULL, /* Open */ + echo_on_close, NULL }; + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +FREERDP_ENTRY_POINT(UINT echo_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)) +{ + return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, ECHO_DVC_CHANNEL_NAME, + sizeof(ECHO_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK), + &echo_callbacks, NULL, NULL); +} diff --git a/channels/echo/client/echo_main.h b/channels/echo/client/echo_main.h new file mode 100644 index 0000000..1286371 --- /dev/null +++ b/channels/echo/client/echo_main.h @@ -0,0 +1,40 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Echo Virtual Channel Extension + * + * Copyright 2013 Christian Hofstaedtler + * + * 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_ECHO_CLIENT_MAIN_H +#define FREERDP_CHANNEL_ECHO_CLIENT_MAIN_H + +#include + +#include +#include +#include +#include + +#define DVC_TAG CHANNELS_TAG("echo.client") +#ifdef WITH_DEBUG_DVC +#define DEBUG_DVC(...) WLog_DBG(DVC_TAG, __VA_ARGS__) +#else +#define DEBUG_DVC(...) \ + do \ + { \ + } while (0) +#endif + +#endif /* FREERDP_CHANNEL_ECHO_CLIENT_MAIN_H */ diff --git a/channels/echo/server/CMakeLists.txt b/channels/echo/server/CMakeLists.txt new file mode 100644 index 0000000..2d13946 --- /dev/null +++ b/channels/echo/server/CMakeLists.txt @@ -0,0 +1,27 @@ +# 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("echo") + +set(${MODULE_PREFIX}_SRCS + echo_main.c +) + +set(${MODULE_PREFIX}_LIBS + freerdp +) +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") diff --git a/channels/echo/server/echo_main.c b/channels/echo/server/echo_main.c new file mode 100644 index 0000000..9c16526 --- /dev/null +++ b/channels/echo/server/echo_main.c @@ -0,0 +1,381 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Echo Virtual Channel Extension + * + * Copyright 2014 Vic Lee + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * + * 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. + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define TAG CHANNELS_TAG("echo.server") + +typedef struct +{ + echo_server_context context; + + BOOL opened; + + HANDLE stopEvent; + + HANDLE thread; + void* echo_channel; + + DWORD SessionId; + +} echo_server; + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT echo_server_open_channel(echo_server* echo) +{ + DWORD Error = 0; + HANDLE hEvent = NULL; + DWORD StartTick = 0; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + + if (WTSQuerySessionInformationA(echo->context.vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return ERROR_INTERNAL_ERROR; + } + + echo->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + hEvent = WTSVirtualChannelManagerGetEventHandle(echo->context.vcm); + StartTick = GetTickCount(); + + while (echo->echo_channel == NULL) + { + if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED) + { + Error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error); + return Error; + } + + echo->echo_channel = WTSVirtualChannelOpenEx(echo->SessionId, ECHO_DVC_CHANNEL_NAME, + WTS_CHANNEL_OPTION_DYNAMIC); + + if (echo->echo_channel) + { + UINT32 channelId = 0; + BOOL status = TRUE; + + channelId = WTSChannelGetIdByHandle(echo->echo_channel); + + IFCALLRET(echo->context.ChannelIdAssigned, status, &echo->context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + return ERROR_INTERNAL_ERROR; + } + + break; + } + + Error = GetLastError(); + + if (Error == ERROR_NOT_FOUND) + break; + + if (GetTickCount() - StartTick > 5000) + break; + } + + return echo->echo_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; +} + +static DWORD WINAPI echo_server_thread_func(LPVOID arg) +{ + wStream* s = NULL; + void* buffer = NULL; + DWORD nCount = 0; + HANDLE events[8]; + BOOL ready = FALSE; + HANDLE ChannelEvent = NULL; + DWORD BytesReturned = 0; + echo_server* echo = (echo_server*)arg; + UINT error = 0; + DWORD status = 0; + + if ((error = echo_server_open_channel(echo))) + { + UINT error2 = 0; + WLog_ERR(TAG, "echo_server_open_channel failed with error %" PRIu32 "!", error); + IFCALLRET(echo->context.OpenResult, error2, &echo->context, + ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED); + + if (error2) + WLog_ERR(TAG, "echo server's OpenResult callback failed with error %" PRIu32 "", + error2); + + goto out; + } + + buffer = NULL; + BytesReturned = 0; + ChannelEvent = NULL; + + if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + nCount = 0; + events[nCount++] = echo->stopEvent; + events[nCount++] = ChannelEvent; + + /* Wait for the client to confirm that the Graphics Pipeline dynamic channel is ready */ + + while (1) + { + status = WaitForMultipleObjects(nCount, events, FALSE, 100); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); + break; + } + + if (status == WAIT_OBJECT_0) + { + IFCALLRET(echo->context.OpenResult, error, &echo->context, + ECHO_SERVER_OPEN_RESULT_CLOSED); + + if (error) + WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); + + break; + } + + if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualChannelReady, &buffer, + &BytesReturned) == FALSE) + { + IFCALLRET(echo->context.OpenResult, error, &echo->context, + ECHO_SERVER_OPEN_RESULT_ERROR); + + if (error) + WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); + + break; + } + + ready = *((BOOL*)buffer); + WTSFreeMemory(buffer); + + if (ready) + { + IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_OK); + + if (error) + WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); + + break; + } + } + + s = Stream_New(NULL, 4096); + + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + WTSVirtualChannelClose(echo->echo_channel); + ExitThread(ERROR_NOT_ENOUGH_MEMORY); + return ERROR_NOT_ENOUGH_MEMORY; + } + + while (ready) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); + break; + } + + if (status == WAIT_OBJECT_0) + break; + + Stream_SetPosition(s, 0); + WTSVirtualChannelRead(echo->echo_channel, 0, NULL, 0, &BytesReturned); + + if (BytesReturned < 1) + continue; + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + error = CHANNEL_RC_NO_MEMORY; + break; + } + + if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + error = ERROR_INTERNAL_ERROR; + break; + } + + IFCALLRET(echo->context.Response, error, &echo->context, (BYTE*)Stream_Buffer(s), + BytesReturned); + + if (error) + { + WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); + break; + } + } + + Stream_Free(s, TRUE); + WTSVirtualChannelClose(echo->echo_channel); + echo->echo_channel = NULL; +out: + + if (error && echo->context.rdpcontext) + setChannelError(echo->context.rdpcontext, error, + "echo_server_thread_func reported an error"); + + ExitThread(error); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT echo_server_open(echo_server_context* context) +{ + echo_server* echo = (echo_server*)context; + + if (echo->thread == NULL) + { + if (!(echo->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return ERROR_INTERNAL_ERROR; + } + + if (!(echo->thread = CreateThread(NULL, 0, echo_server_thread_func, (void*)echo, 0, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + CloseHandle(echo->stopEvent); + echo->stopEvent = NULL; + return ERROR_INTERNAL_ERROR; + } + } + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT echo_server_close(echo_server_context* context) +{ + UINT error = CHANNEL_RC_OK; + echo_server* echo = (echo_server*)context; + + if (echo->thread) + { + SetEvent(echo->stopEvent); + + if (WaitForSingleObject(echo->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); + return error; + } + + CloseHandle(echo->thread); + CloseHandle(echo->stopEvent); + echo->thread = NULL; + echo->stopEvent = NULL; + } + + return error; +} + +static BOOL echo_server_request(echo_server_context* context, const BYTE* buffer, UINT32 length) +{ + union + { + const BYTE* cpv; + CHAR* pv; + } cnv; + cnv.cpv = buffer; + echo_server* echo = (echo_server*)context; + WINPR_ASSERT(echo); + + return WTSVirtualChannelWrite(echo->echo_channel, cnv.pv, length, NULL); +} + +echo_server_context* echo_server_context_new(HANDLE vcm) +{ + echo_server* echo = NULL; + echo = (echo_server*)calloc(1, sizeof(echo_server)); + + if (echo) + { + echo->context.vcm = vcm; + echo->context.Open = echo_server_open; + echo->context.Close = echo_server_close; + echo->context.Request = echo_server_request; + } + else + WLog_ERR(TAG, "calloc failed!"); + + return (echo_server_context*)echo; +} + +void echo_server_context_free(echo_server_context* context) +{ + echo_server* echo = (echo_server*)context; + echo_server_close(context); + free(echo); +} -- cgit v1.2.3