summaryrefslogtreecommitdiff
path: root/src/rdp
diff options
context:
space:
mode:
authorsss <sss@dark-alexandr.net>2023-01-17 00:38:19 +0300
committersss <sss@dark-alexandr.net>2023-01-17 00:38:19 +0300
commitcc3f33db7a8d3c4ad373e646b199808e01bc5d9b (patch)
treeec09d690c7656ab5f2cc72607e05fb359c24d8b2 /src/rdp
added webrdp public code
Diffstat (limited to 'src/rdp')
l---------src/rdp/.clang-format1
-rw-r--r--src/rdp/CMakeLists.txt82
l---------src/rdp/include/.clang-format1
-rw-r--r--src/rdp/include/rdp_backend_api.h17
-rw-r--r--src/rdp/rdp.project138
-rw-r--r--src/rdp/rdp_channels.c39
-rw-r--r--src/rdp/rdp_channels.h17
-rw-r--r--src/rdp/rdp_clipboard.c1524
-rw-r--r--src/rdp/rdp_clipboard.h52
-rw-r--r--src/rdp/rdp_display_output.c871
-rw-r--r--src/rdp/rdp_display_output.h17
-rw-r--r--src/rdp/rdp_ft.c129
-rw-r--r--src/rdp/rdp_ft.h17
-rw-r--r--src/rdp/rdp_impl.c637
-rw-r--r--src/rdp/rdp_impl.h127
-rw-r--r--src/rdp/rdp_io.c1492
-rw-r--r--src/rdp/rdp_module.c168
-rw-r--r--src/rdp/rdp_module.h7
-rw-r--r--src/rdp/rdp_png.c89
-rw-r--r--src/rdp/rdp_png.h22
-rw-r--r--src/rdp/rdp_rail.c173
-rw-r--r--src/rdp/rdp_rail.h14
-rw-r--r--src/rdp/rdp_settings.c2278
-rw-r--r--src/rdp/rdp_settings.h15
-rw-r--r--src/rdp/rdp_user_input.c458
-rw-r--r--src/rdp/rdp_user_input.h10
26 files changed, 8395 insertions, 0 deletions
diff --git a/src/rdp/.clang-format b/src/rdp/.clang-format
new file mode 120000
index 0000000..2d11237
--- /dev/null
+++ b/src/rdp/.clang-format
@@ -0,0 +1 @@
+../../.clang-format \ No newline at end of file
diff --git a/src/rdp/CMakeLists.txt b/src/rdp/CMakeLists.txt
new file mode 100644
index 0000000..29e7b9a
--- /dev/null
+++ b/src/rdp/CMakeLists.txt
@@ -0,0 +1,82 @@
+# -*- CMakeLists.txt generated by CodeLite IDE. Do not edit by hand -*-
+
+cmake_minimum_required(VERSION 2.8.11)
+
+project(rdp)
+
+# Define some variables
+set(PROJECT_rdp_PATH "${CMAKE_CURRENT_LIST_DIR}")
+set(WORKSPACE_PATH "${CMAKE_CURRENT_LIST_DIR}/..")
+
+
+
+#{{{{ User Code 1
+# Place your code here
+#}}}}
+
+include_directories(
+ .
+ ./include
+ ../../3rdparty/FreeRDP/include
+ ../../3rdparty/FreeRDP/winpr
+ ../../3rdparty/FreeRDP/winpr/include
+ ../../3rdparty/FreeRDP/build/winpr/include
+ ../../3rdparty/FreeRDP/build/include
+ ../../3rdparty/libev
+ ../core/include
+)
+
+
+# Compiler options
+add_definitions(-Wall)
+add_definitions(-D_XOPEN_SOURCE=500)
+add_definitions(-D_POSIX_C_SOURCE=200112L)
+
+# Linker options
+
+
+if(WIN32)
+ # Resource options
+endif(WIN32)
+
+# Library path
+set(CMAKE_LDFLAGS "${CMAKE_LDFLAGS} -L. ")
+
+# Define the C sources
+set ( C_SRCS
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_module.c
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_impl.c
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_png.c
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_settings.c
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_channels.c
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_display_output.c
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_clipboard.c
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_ft.c
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_user_input.c
+ ${CMAKE_CURRENT_LIST_DIR}/rdp_rail.c
+)
+
+set_source_files_properties(
+ ${C_SRCS} PROPERTIES COMPILE_FLAGS
+ " -Wall -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=200112L -fPIC")
+
+if(WIN32)
+ enable_language(RC)
+ set(CMAKE_RC_COMPILE_OBJECT
+ "<CMAKE_RC_COMPILER> ${RC_OPTIONS} -O coff -i <SOURCE> -o <OBJECT>")
+endif(WIN32)
+
+
+
+#{{{{ User Code 2
+# Place your code here
+#}}}}
+
+add_library(rdp ${RC_SRCS} ${CXX_SRCS} ${C_SRCS})
+
+
+
+#{{{{ User Code 3
+# Place your code here
+#}}}}
+
diff --git a/src/rdp/include/.clang-format b/src/rdp/include/.clang-format
new file mode 120000
index 0000000..3260daf
--- /dev/null
+++ b/src/rdp/include/.clang-format
@@ -0,0 +1 @@
+../../../.clang-format \ No newline at end of file
diff --git a/src/rdp/include/rdp_backend_api.h b/src/rdp/include/rdp_backend_api.h
new file mode 100644
index 0000000..4840765
--- /dev/null
+++ b/src/rdp/include/rdp_backend_api.h
@@ -0,0 +1,17 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+typedef enum
+{
+ rdp_conn_state_offline,
+ rdp_conn_state_connected
+} rdp_connection_state;
+
+bool rdp_create(wrdp_core_exports *core, wrdp_backend_module *module);
+
+void rdp_backend_destroy(void *backend);
diff --git a/src/rdp/rdp.project b/src/rdp/rdp.project
new file mode 100644
index 0000000..30925d4
--- /dev/null
+++ b/src/rdp/rdp.project
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CodeLite_Project Name="rdp" Version="11000" InternalType="Library">
+ <Plugins>
+ <Plugin Name="qmake">
+ <![CDATA[00010001N0005Debug000000000000]]>
+ </Plugin>
+ </Plugins>
+ <Description/>
+ <Dependencies/>
+ <VirtualDirectory Name="src">
+ <File Name="rdp_rail.h"/>
+ <File Name="rdp_rail.c"/>
+ <File Name="rdp_ft.h"/>
+ <File Name="rdp_ft.c"/>
+ <File Name="rdp_display_output.h"/>
+ <File Name="rdp_display_output.c"/>
+ <File Name="rdp_user_input.h"/>
+ <File Name="rdp_user_input.c"/>
+ <File Name="rdp_channels.h"/>
+ <File Name="rdp_channels.c"/>
+ <File Name="rdp_clipboard.h"/>
+ <File Name="rdp_clipboard.c"/>
+ <File Name="rdp_settings.h"/>
+ <File Name="rdp_settings.c"/>
+ <File Name="rdp_png.c"/>
+ <File Name="rdp_png.h"/>
+ <File Name="rdp_impl.c"/>
+ <File Name="rdp_impl.h"/>
+ <File Name="rdp_module.c"/>
+ <File Name="rdp_module.h"/>
+ </VirtualDirectory>
+ <VirtualDirectory Name="include">
+ <File Name="include/rdp_backend_api.h"/>
+ </VirtualDirectory>
+ <Settings Type="Static Library">
+ <GlobalSettings>
+ <Compiler Options="-fPIC" C_Options="-D_XOPEN_SOURCE=500;-D_POSIX_C_SOURCE=200112L" Assembler="">
+ <IncludePath Value="."/>
+ <IncludePath Value="./include"/>
+ <IncludePath Value="../../3rdparty/FreeRDP/include"/>
+ <IncludePath Value="../../3rdparty/libev"/>
+ <IncludePath Value="../../3rdparty/FreeRDP/winpr"/>
+ <IncludePath Value="../../3rdparty/FreeRDP/winpr/include"/>
+ <IncludePath Value="../../3rdparty/FreeRDP/build/winpr/include"/>
+ <IncludePath Value="../../3rdparty/FreeRDP/build/include"/>
+ <IncludePath Value="../core/include"/>
+ <IncludePath Value="/home/sss/.nix-profile/include"/>
+ </Compiler>
+ <Linker Options="">
+ <LibraryPath Value="."/>
+ </Linker>
+ <ResourceCompiler Options=""/>
+ </GlobalSettings>
+ <Configuration Name="Debug" CompilerType="clang" DebuggerType="GNU gdb debugger" Type="Static Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
+ <Compiler Options="-g;-Wall;-fsanitize=address;-O0" C_Options="-pg;-g;-Wall;-DDEBUG;-fsanitize=address;-O0" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0"/>
+ <Linker Options="-pg" Required="yes"/>
+ <ResourceCompiler Options="" Required="no"/>
+ <General OutputFile="$(IntermediateDirectory)/$(ProjectName).a" IntermediateDirectory="./Debug" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
+ <BuildSystem Name="Default"/>
+ <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
+ <![CDATA[]]>
+ </Environment>
+ <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="yes">
+ <DebuggerSearchPaths/>
+ <PostConnectCommands/>
+ <StartupCommands/>
+ </Debugger>
+ <PreBuild/>
+ <PostBuild/>
+ <CustomBuild Enabled="no">
+ <RebuildCommand/>
+ <CleanCommand/>
+ <BuildCommand/>
+ <PreprocessFileCommand/>
+ <SingleFileCommand/>
+ <MakefileGenerationCommand/>
+ <ThirdPartyToolName/>
+ <WorkingDirectory/>
+ </CustomBuild>
+ <AdditionalRules>
+ <CustomPostBuild/>
+ <CustomPreBuild/>
+ </AdditionalRules>
+ <Completion EnableCpp11="no" EnableCpp14="no">
+ <ClangCmpFlagsC/>
+ <ClangCmpFlags/>
+ <ClangPP/>
+ <SearchPaths/>
+ </Completion>
+ </Configuration>
+ <Configuration Name="Release" CompilerType="clang" DebuggerType="GNU gdb debugger" Type="Static Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
+ <Compiler Options="-Wall;-fPIC" C_Options="-std=c99;-Wall;-D_XOPEN_SOURCE=500;-D_POSIX_C_SOURCE=200112L" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
+ <IncludePath Value="."/>
+ <IncludePath Value="./include"/>
+ <IncludePath Value="../../3rdparty/FreeRDP/include"/>
+ <IncludePath Value="../../3rdparty/FreeRDP/winpr/include"/>
+ <IncludePath Value="../../3rdparty/FreeRDP/build/winpr/include"/>
+ <IncludePath Value="../../3rdparty/FreeRDP/build/include"/>
+ <IncludePath Value="../core/include"/>
+ <Preprocessor Value="NDEBUG"/>
+ </Compiler>
+ <Linker Options="-O2" Required="yes"/>
+ <ResourceCompiler Options="" Required="no"/>
+ <General OutputFile="$(IntermediateDirectory)/$(ProjectName).a" IntermediateDirectory="./Release" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
+ <BuildSystem Name="Default"/>
+ <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
+ <![CDATA[]]>
+ </Environment>
+ <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="yes">
+ <DebuggerSearchPaths/>
+ <PostConnectCommands/>
+ <StartupCommands/>
+ </Debugger>
+ <PreBuild/>
+ <PostBuild/>
+ <CustomBuild Enabled="no">
+ <RebuildCommand/>
+ <CleanCommand/>
+ <BuildCommand/>
+ <PreprocessFileCommand/>
+ <SingleFileCommand/>
+ <MakefileGenerationCommand/>
+ <ThirdPartyToolName/>
+ <WorkingDirectory/>
+ </CustomBuild>
+ <AdditionalRules>
+ <CustomPostBuild/>
+ <CustomPreBuild/>
+ </AdditionalRules>
+ <Completion EnableCpp11="no" EnableCpp14="no">
+ <ClangCmpFlagsC/>
+ <ClangCmpFlags/>
+ <ClangPP/>
+ <SearchPaths/>
+ </Completion>
+ </Configuration>
+ </Settings>
+</CodeLite_Project>
diff --git a/src/rdp/rdp_channels.c b/src/rdp/rdp_channels.c
new file mode 100644
index 0000000..a4d95eb
--- /dev/null
+++ b/src/rdp/rdp_channels.c
@@ -0,0 +1,39 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include <string.h>
+#include "rdp_channels.h"
+#include "rdp_clipboard.h"
+#include "rdp_rail.h"
+
+void
+rdp_on_channel_connected(void *context, const ChannelConnectedEventArgs *e)
+{
+ if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
+ {
+ rdp_cliprdr_init(
+ context, (CliprdrClientContext *)e->pInterface);
+ }
+ else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
+ {
+ rdp_rail_init(context, (RailClientContext *)e->pInterface);
+ }
+}
+
+void
+rdp_on_channel_disconnected(
+ void *context, const ChannelDisconnectedEventArgs *e)
+{
+ if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
+ {
+ rdp_cliprdr_uninit(
+ context, (CliprdrClientContext *)e->pInterface);
+ }
+ else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
+ {
+ rdp_rail_uninit(context, (RailClientContext *)e->pInterface);
+ }
+}
diff --git a/src/rdp/rdp_channels.h b/src/rdp/rdp_channels.h
new file mode 100644
index 0000000..2d895fb
--- /dev/null
+++ b/src/rdp/rdp_channels.h
@@ -0,0 +1,17 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+#include <freerdp/client/channels.h>
+#include <freerdp/client/cliprdr.h>
+#include <freerdp/client/rail.h>
+
+void rdp_on_channel_connected(
+ void *context, const ChannelConnectedEventArgs *e);
+
+void rdp_on_channel_disconnected(
+ void *context, const ChannelDisconnectedEventArgs *e);
diff --git a/src/rdp/rdp_clipboard.c b/src/rdp/rdp_clipboard.c
new file mode 100644
index 0000000..e8ab882
--- /dev/null
+++ b/src/rdp/rdp_clipboard.c
@@ -0,0 +1,1524 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+/* this code mostly ported from XFreeRDP */
+
+#include <arpa/inet.h>
+#include <iconv.h>
+
+#include "rdp_clipboard.h"
+#include "rdp_ft.h"
+
+static UINT
+rdp_clip_ServerCapabilities(
+ CliprdrClientContext *context, const CLIPRDR_CAPABILITIES *capabilities)
+{
+ UINT32 i;
+ const CLIPRDR_CAPABILITY_SET *caps;
+ const CLIPRDR_GENERAL_CAPABILITY_SET *generalCaps;
+ const BYTE *capsPtr = (const BYTE *)capabilities->capabilitySets;
+ my_rdp_clipboard *clipboard = (my_rdp_clipboard *)context->custom;
+ clipboard->streams_supported = false;
+
+ for (i = 0; i < capabilities->cCapabilitiesSets; i++)
+ {
+ caps = (const CLIPRDR_CAPABILITY_SET *)capsPtr;
+
+ if (caps->capabilitySetType == CB_CAPSTYPE_GENERAL)
+ {
+ generalCaps
+ = (const CLIPRDR_GENERAL_CAPABILITY_SET *)caps;
+
+ if (generalCaps->generalFlags
+ & CB_STREAM_FILECLIP_ENABLED)
+ {
+ clipboard->streams_supported = true;
+ }
+ }
+
+ capsPtr += caps->capabilitySetLength;
+ }
+ {
+ const char *msg
+ = "rdp_module: cliprdr: server capabilities received";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_trace, 0);
+ }
+
+ return CHANNEL_RC_OK;
+}
+
+/* unused for now
+ * static UINT
+rdp_clip_ClientCapabilities(CliprdrClientContext* context,
+ CLIPRDR_CAPABILITIES* capabilities)
+{
+ return CHANNEL_RC_OK;
+}*/
+
+static UINT
+rdp_cliprdr_send_client_capabilities(my_rdp_clipboard *clipboard)
+{
+ CLIPRDR_CAPABILITIES capabilities;
+ CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
+ capabilities.cCapabilitiesSets = 1;
+ capabilities.capabilitySets
+ = (CLIPRDR_CAPABILITY_SET *)&(generalCapabilitySet);
+ generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
+ generalCapabilitySet.capabilitySetLength = 12;
+ generalCapabilitySet.version = CB_CAPS_VERSION_2;
+ generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES;
+ /*|CB_CAN_LOCK_CLIPDATA; */
+
+ if (clipboard->streams_supported)
+ {
+ generalCapabilitySet.generalFlags |= CB_STREAM_FILECLIP_ENABLED
+ | CB_FILECLIP_NO_FILE_PATHS
+ | 0x00000020;
+ }
+
+ {
+ const char *msg
+ = "rdp_module: cliprdr: client capabilities sent";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_trace, 0);
+ }
+
+ return clipboard->clip_context->ClientCapabilities(
+ clipboard->clip_context, &capabilities);
+}
+
+static UINT
+rdp_cliprdr_send_client_format_list(my_rdp_clipboard *clipboard)
+{
+ const uint8_t format_count = 2;
+ CLIPRDR_FORMAT formats[format_count];
+ CLIPRDR_FORMAT_LIST formatList;
+ memset(formats, 0, sizeof(CLIPRDR_FORMAT) * format_count);
+ formats[0].formatId = CF_RAW;
+ formats[1].formatId = CF_TEXT;
+ formatList.common.msgFlags = CB_RESPONSE_OK;
+ formatList.numFormats = format_count;
+ formatList.formats = formats;
+
+ {
+ const char *msg
+ = "rdp_module: cliprdr: client format list sent";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_trace, 0);
+ }
+
+ return clipboard->clip_context->ClientFormatList(
+ clipboard->clip_context, &formatList);
+}
+
+static UINT
+rdp_clip_MonitorReady(
+ CliprdrClientContext *context, const CLIPRDR_MONITOR_READY *monitorReady)
+{
+ my_rdp_clipboard *clipboard = context->custom;
+ UINT ret;
+
+ if ((ret = rdp_cliprdr_send_client_capabilities(clipboard))
+ != CHANNEL_RC_OK)
+ return ret;
+
+ if ((ret = rdp_cliprdr_send_client_format_list(clipboard))
+ != CHANNEL_RC_OK)
+ return ret;
+
+ /* clipboard->sync = true; */
+ {
+ const char *msg
+ = "rdp_module: cliprdr: monitor ready message handled";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_trace, 0);
+ }
+ return CHANNEL_RC_OK;
+}
+
+/* unused for now
+ * static UINT
+rdp_clip_TempDirectory(CliprdrClientContext* context,
+ CLIPRDR_TEMP_DIRECTORY* tempDirectory)
+{
+ return CHANNEL_RC_OK;
+} */
+
+/* unused for now
+ * static UINT
+rdp_clip_ClientFormatList(CliprdrClientContext* context,
+ CLIPRDR_FORMAT_LIST* formatList)
+{
+ return CHANNEL_RC_OK;
+}*/
+
+static UINT
+rdp_cliprdr_send_client_format_list_response(
+ my_rdp_clipboard *clipboard, BOOL status)
+{
+ CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
+ formatListResponse.common.msgType = CB_FORMAT_LIST_RESPONSE;
+ formatListResponse.common.msgFlags
+ = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
+ formatListResponse.common.dataLen = 0;
+ return clipboard->clip_context->ClientFormatListResponse(
+ clipboard->clip_context, &formatListResponse);
+}
+
+static wrdp_enum_clip_format
+clip_format_from_string(const char *fmt)
+{
+ if (!strcmp(fmt, "FileGroupDescriptorW"))
+ {
+ return clip_format_file_list;
+ }
+ /*
+ * unused
+ else if (!strcmp(fmt, "FileContents"))
+ {
+ }
+ else if (!strcmp(fmt, "Preffered DropEffect"))
+ {
+ }
+ */
+ return clip_format_unsupported;
+}
+
+static wrdp_enum_clip_format
+clip_format_from_id(UINT32 id, my_rdp_clipboard *c)
+{
+ if (id == CF_TEXT || id == CF_OEMTEXT)
+ {
+ return clip_format_text;
+ }
+ else if (id == CF_RAW)
+ {
+ return clip_format_raw;
+ }
+ else if (id == CF_UNICODETEXT)
+ {
+ return clip_format_unicode;
+ }
+ else if (id == CB_FORMAT_TEXTURILIST)
+ {
+ return clip_format_file_list;
+ }
+ return clip_format_unsupported;
+}
+
+static UINT
+rdp_clip_ServerFormatList(
+ CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST *formatList)
+{
+ UINT32 i;
+ uint8_t num_supported_fmts = 0, *out_fmts = 0, num_server_formats;
+ my_rdp_clipboard *clipboard = context->custom;
+ my_clip_format *server_formats = 0;
+ UINT ret;
+
+ if (clipboard->my_rdp_context->ft_to_server->is_runing)
+ {
+ const char *msg
+ = "rdp_module: clipboard: new clipboard formats list "
+ "during runing filetransfer";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_warning, 0);
+ /* return CHANNEL_RC_OK; */
+ }
+
+ num_server_formats = formatList->numFormats + 1; /* +1 for CF_RAW */
+
+ if (!(server_formats
+ = calloc(num_server_formats, sizeof(my_clip_format))))
+ {
+ char buf[128];
+ snprintf(buf, 127,
+ "failed to allocate %d my_clip_format structs",
+ num_server_formats);
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)buf, strlen(buf),
+ wrdp_log_level_error, 0);
+ return CHANNEL_RC_NO_MEMORY;
+ }
+
+ if (clipboard->srv_fmts && clipboard->srv_fmts_count)
+ {
+ for (i = 0; i < clipboard->srv_fmts_count; ++i)
+ {
+ if (clipboard->srv_fmts[i].rdp_fmt.formatName)
+ {
+ free(clipboard->srv_fmts[i].rdp_fmt.formatName);
+ }
+ }
+ free(clipboard->srv_fmts);
+ }
+
+ clipboard->srv_fmts_count = formatList->numFormats;
+ for (i = 0; i < formatList->numFormats; i++)
+ {
+ CLIPRDR_FORMAT *format = &formatList->formats[i];
+ server_formats[i].rdp_fmt.formatId = format->formatId;
+ wrdp_enum_clip_format fmt
+ = clip_format_from_id(format->formatId, clipboard);
+ if (format->formatName)
+ {
+ server_formats[i].rdp_fmt.formatName
+ = strdup(format->formatName);
+ }
+ if (fmt == clip_format_unsupported && format->formatName)
+ {
+ fmt = clip_format_from_string(format->formatName);
+ }
+ if (fmt != clip_format_unsupported)
+ {
+ num_supported_fmts++;
+ }
+ server_formats[i].my_fmt = fmt;
+ }
+ /* CF_RAW is always implicitly supported by the server */
+ {
+ my_clip_format *format
+ = &server_formats[formatList->numFormats];
+ format->rdp_fmt.formatId = CF_RAW;
+ format->rdp_fmt.formatName = NULL;
+ format->my_fmt = clip_format_raw;
+ num_supported_fmts++;
+ }
+ {
+ out_fmts = calloc(num_supported_fmts, sizeof(uint8_t));
+ if (!out_fmts)
+ {
+ perror("calloc");
+ if (server_formats)
+ {
+ free(server_formats);
+ }
+ return CHANNEL_RC_NO_MEMORY;
+ }
+ uint8_t pos = 0;
+ for (i = 0; i < num_supported_fmts; ++i)
+ {
+ if (server_formats[i].my_fmt == clip_format_unsupported)
+ {
+ continue;
+ }
+ out_fmts[pos] = server_formats[i].my_fmt;
+ pos++;
+ }
+ clipboard->my_rdp_context->my_internals->core->api_clipboard
+ ->clipboard_changed(out_fmts, num_supported_fmts,
+ clipboard->my_rdp_context->my_internals->task_info);
+ free(out_fmts);
+ clipboard->srv_fmts = server_formats;
+ }
+
+ {
+ const char *msg = "rdp_module: cliprdr: server format list"
+ " changed message received";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_trace, 0);
+ }
+
+ ret = rdp_cliprdr_send_client_format_list_response(clipboard, TRUE);
+ return ret;
+}
+
+/* unused for now
+ * static UINT
+rdp_clip_ClientFormatListResponse(CliprdrClientContext* context,
+ CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
+{
+ return CHANNEL_RC_OK;
+}*/
+
+static UINT
+rdp_clip_ServerFormatListResponse(CliprdrClientContext *context,
+ const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse)
+{
+ return CHANNEL_RC_OK;
+}
+
+/* unused for now
+ * static UINT
+rdp_clip_ClientLockClipboardData(CliprdrClientContext* context,
+ CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
+{
+ return CHANNEL_RC_OK;
+}*/
+
+static UINT
+rdp_clip_ServerLockClipboardData(CliprdrClientContext *context,
+ const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData)
+{
+ /* my_rdp_clipboard* clipboard = context->custom;
+ clipboard->my_rdp_context->ft_to_server->clip_data_id =
+ lockClipboardData->clipDataId; */
+ return CHANNEL_RC_OK;
+}
+
+/*
+ * unused
+static UINT
+rdp_clip_ClientUnlockClipboardData(CliprdrClientContext* context,
+ CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
+{
+ return CHANNEL_RC_OK;
+}
+*/
+
+static UINT
+rdp_clip_ServerUnlockClipboardData(CliprdrClientContext *context,
+ const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData)
+{
+ /* TODO: */
+ return CHANNEL_RC_OK;
+}
+
+/* unused for now
+ * static UINT
+rdp_clip_ClientFormatDataRequest(CliprdrClientContext* context,
+ CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
+{
+ return CHANNEL_RC_OK;
+}*/
+
+static UINT
+rdp_clip_ServerFormatDataRequest(CliprdrClientContext *context,
+ const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest)
+{
+ my_rdp_clipboard *clipboard = context->custom;
+ wrdp_enum_clip_format fmt = clip_format_from_id(
+ formatDataRequest->requestedFormatId, clipboard);
+ clipboard->my_rdp_context->my_internals->core->api_clipboard
+ ->request_data(
+ fmt, clipboard->my_rdp_context->my_internals->task_info);
+
+ return CHANNEL_RC_OK;
+}
+
+/* unused for now
+ * static UINT
+rdp_clip_ClientFormatDataResponse(CliprdrClientContext* context,
+ CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
+{
+ return CHANNEL_RC_OK;
+}*/
+
+/*static UINT rdp_cliprdr_send_data_response(my_rdp_clipboard* clipboard,
+ BYTE* data, int size)
+{
+ CLIPRDR_FORMAT_DATA_RESPONSE response;
+ ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE));
+ response.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
+ response.dataLen = size;
+ response.requestedFormatData = data;
+ return clipboard->clip_context->ClientFormatDataResponse(
+ clipboard->clip_context, &response);
+} */
+
+static UINT
+rdp_clip_ServerFormatDataResponse(CliprdrClientContext *context,
+ const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse)
+{
+ UINT32 size = formatDataResponse->common.dataLen;
+ const BYTE *data = formatDataResponse->requestedFormatData;
+ my_rdp_clipboard *clipboard = context->custom;
+
+ if (!data)
+ {
+ const char *msg
+ = "rdp_module: cliprdr: failed to get clipboard data";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_error, 0);
+ return CHANNEL_RC_OK;
+ }
+
+ switch (clipboard->cli_req_fmt_id.my_fmt)
+ {
+ case clip_format_file_list:
+ {
+ /* TODO: check this */
+ UINT error = NO_ERROR;
+ FILEDESCRIPTORW *file_array = 0;
+ UINT32 file_count = 0, pos = 0;
+ uint8_t *msg_struct = 0, *msg = 0;
+ wrdp_backend_ft_list_entry *list = 0;
+ size_t msg_size_result = 0;
+ error = cliprdr_parse_file_list(
+ data, size, &file_array, &file_count);
+ if (error)
+ {
+ char buf[128];
+ snprintf(buf, 127,
+ "failed to deserialize"
+ " CLIPRDR_FILELIST: 0x%08X",
+ error);
+ clipboard->my_rdp_context->my_internals->core
+ ->api_utils->log_msg((const uint8_t *)buf,
+ strlen(buf), wrdp_log_level_error, 0);
+ return CHANNEL_RC_OK;
+ }
+ msg_struct = calloc(
+ file_count, sizeof(wrdp_backend_ft_list_entry));
+ if (!msg_struct)
+ {
+ perror("calloc");
+ if (file_count && file_array)
+ {
+ free(file_array);
+ }
+ return CHANNEL_RC_OK;
+ }
+ msg_size_result
+ = (file_count * sizeof(wrdp_backend_ft_list_entry))
+ + 3;
+ char *filename_array[file_count];
+ {
+ int i = 0;
+ for (; i < file_count; ++i)
+ {
+ filename_array[i] = 0;
+ }
+ }
+ list = (wrdp_backend_ft_list_entry *)msg_struct;
+ for (; file_array && pos < file_count; ++pos)
+ {
+ list[pos].file_id = pos;
+ if (file_array[pos].cFileName[0])
+ {
+ iconv_t utf16_to_utf8
+ = iconv_open("UTF-8", "UTF-16LE");
+ char *ptr_w, *ptr_r,
+ *tmp_buf
+ = calloc(520, sizeof(char));
+ size_t name_len_utf16
+ = 260 * sizeof(WCHAR),
+ name_len_utf8 = 520,
+ name_len_result = 0;
+ if (!tmp_buf)
+ {
+ perror("calloc");
+ iconv_close(utf16_to_utf8);
+ free(msg_struct);
+ if (file_count)
+ {
+ int i = 0;
+ for (; (i < file_count)
+ && filename_array
+ [i];
+ ++i)
+ {
+ free(
+ filename_array
+ [i]);
+ }
+ free(file_array);
+ }
+ return CHANNEL_RC_OK;
+ }
+ ptr_w = tmp_buf;
+ ptr_r
+ = (char *)file_array[pos].cFileName;
+ while (name_len_utf16 && name_len_utf8)
+ {
+ iconv(utf16_to_utf8, &ptr_r,
+ &name_len_utf16, &ptr_w,
+ &name_len_utf8);
+ }
+#ifdef DEBUG
+ if (!name_len_utf8 && name_len_utf16)
+ {
+ log_msg_info i = {0};
+ i.level = wrdp_log_level_trace;
+ i.buf = (const uint8_t
+ *)"rdp_module: "
+ "cliprdr: iconv: not "
+ "sufficient space in "
+ "output buffer";
+ i.task_info
+ = clipboard->my_internals
+ ->task_info;
+ clipboard->my_internals->core
+ ->api_utils->log_msg_ex(&i);
+ }
+#endif
+ iconv(utf16_to_utf8, 0, 0, &ptr_w,
+ &name_len_utf8);
+ name_len_result = strlen(tmp_buf);
+ msg_size_result += name_len_result;
+ list[pos].filename_len
+ = name_len_result;
+ filename_array[pos] = strdup(tmp_buf);
+ iconv_close(utf16_to_utf8);
+ free(tmp_buf);
+ }
+ /* TODO: check/change endianness */
+ memcpy(&(list[pos].file_size),
+ &file_array[pos].nFileSizeLow, 4);
+ memcpy(((uint8_t *)&(list[pos].file_size)) + 4,
+ &file_array[pos].nFileSizeHigh, 4);
+ }
+ msg = malloc(msg_size_result);
+ if (!msg)
+ {
+ perror("malloc");
+ for (pos = 0; pos < file_count; ++pos)
+ {
+ free(filename_array[pos]);
+ }
+ free(msg_struct);
+ return CHANNEL_RC_OK;
+ }
+ memset(msg, 0, msg_size_result);
+ *((uint8_t *)msg) = clip_format_file_list;
+ memcpy(msg + 1, &file_count, 2);
+ {
+ size_t msg_pos = 3;
+ for (pos = 0; pos < file_count; ++pos)
+ {
+ memcpy(msg + msg_pos,
+ &list[pos].filename_len, 2);
+ msg_pos += 2;
+ memcpy(msg + msg_pos,
+ &list[pos].file_id, 4);
+ msg_pos += 4;
+ memcpy(msg + msg_pos,
+ &list[pos].file_size, 8);
+ msg_pos += 8;
+ /* TODO: looks like i have missed
+ * something ... "Null pointer passed as
+ * an argument to a 'nonnull' parameter"
+ * just added null ptr check for now */
+ if (filename_array[pos])
+ {
+ memcpy(msg + msg_pos,
+ filename_array[pos],
+ list[pos].filename_len);
+ free(filename_array[pos]);
+ }
+ msg_pos += list[pos].filename_len;
+ }
+ }
+ free(msg_struct);
+ clipboard->my_rdp_context->my_internals->core
+ ->api_clipboard->send_data((uint8_t *)msg,
+ msg_size_result,
+ clipboard->my_rdp_context->my_internals
+ ->task_info);
+ free(msg);
+ if (file_count && file_array)
+ {
+ free(file_array);
+ }
+ return CHANNEL_RC_OK;
+ }
+ break;
+ case clip_format_raw:
+ case clip_format_text:
+ {
+ size_t msg_len = size + 1;
+ uint8_t *msg = malloc(msg_len);
+ if (!msg)
+ {
+ perror("malloc");
+ return CHANNEL_RC_OK;
+ }
+ *(uint8_t *)msg = clip_format_text;
+ memcpy(msg + 1, data, size);
+ clipboard->my_rdp_context->my_internals->core
+ ->api_clipboard->send_data(msg, msg_len,
+ clipboard->my_rdp_context->my_internals
+ ->task_info);
+ free(msg);
+ }
+ break;
+ case clip_format_unicode:
+ {
+ iconv_t utf16_to_utf8 = iconv_open("UTF-8", "UTF-16LE");
+ size_t in_left = size, out_left = size;
+ uint8_t *tmp_buf = malloc(out_left), *tmp_buf_ptr;
+ uint8_t *msg = 0;
+ if (!tmp_buf)
+ {
+ perror("malloc");
+ return CHANNEL_RC_OK;
+ }
+ tmp_buf_ptr = tmp_buf;
+ /* wcstombs((char*)msg + 1, tmp_buf, text_len); */
+ while (in_left && out_left)
+ {
+ if (iconv(utf16_to_utf8, (char **)&data,
+ &in_left, (char **)&tmp_buf_ptr,
+ &out_left)
+ == (size_t)-1)
+ {
+ log_msg_info mi = {0};
+ mi.level = wrdp_log_level_warning;
+ mi.buf = (const uint8_t
+ *)"rdp_module: cliprdr: iconv: "
+ "failed to encode outgoing "
+ "buffer from utf8 to utf16le";
+ mi.task_info = clipboard->my_internals
+ ->task_info;
+ clipboard->my_internals->core->api_utils
+ ->log_msg_ex(&mi);
+ free(tmp_buf);
+ iconv_close(utf16_to_utf8);
+ return CHANNEL_RC_NO_BUFFER;
+ }
+ }
+#ifdef DEBUG
+ if (!out_left && in_left)
+ {
+ log_msg_info i = {0};
+ i.level = wrdp_log_level_trace;
+ i.buf = (const uint8_t
+ *)"rdp_module: cliprdr: iconv: not "
+ "sufficient space in output buffer";
+ i.task_info
+ = clipboard->my_internals->task_info;
+ clipboard->my_internals->core->api_utils
+ ->log_msg_ex(&i);
+ }
+#endif
+ iconv(utf16_to_utf8, 0, 0, (char **)&tmp_buf_ptr,
+ &out_left);
+ iconv_close(utf16_to_utf8);
+ msg = malloc(size - out_left + 1);
+ if (!msg)
+ {
+ perror("malloc");
+ return CHANNEL_RC_OK;
+ }
+ *(uint8_t *)msg = clip_format_unicode;
+ memcpy(msg + 1, tmp_buf, size - out_left);
+#ifdef DEBUG
+ {
+ log_msg_info i = {0};
+ size_t len = 1024;
+ char msg_buf[len];
+ snprintf(msg_buf, len - 1,
+ "rdp_module: cliprdr: sending encoded from "
+ "utf16le to utf8 text: %s",
+ tmp_buf);
+ i.level = wrdp_log_level_trace;
+ i.buf = (const uint8_t *)msg_buf;
+ i.task_info
+ = clipboard->my_internals->task_info;
+ clipboard->my_internals->core->api_utils
+ ->log_msg_ex(&i);
+ }
+#endif
+ free(tmp_buf);
+ clipboard->my_rdp_context->my_internals->core
+ ->api_clipboard->send_data(msg, size - out_left + 1,
+ clipboard->my_rdp_context->my_internals
+ ->task_info);
+ free(msg);
+ }
+ break;
+ default:
+ {
+ const char *msg = "rdp_module: cliprdr: unsupported"
+ " clipboardformat requested";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_warning, 0);
+ }
+ break;
+ }
+ return CHANNEL_RC_OK;
+}
+
+/* unused for now
+ * static UINT
+rdp_clip_ClientFileContentsRequest(CliprdrClientContext* context,
+ CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
+{
+ return CHANNEL_RC_OK;
+}*/
+
+static UINT
+rdp_clip_ServerFileContentsRequest(CliprdrClientContext *context,
+ const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest)
+{
+ my_rdp_clipboard *clipboard = context->custom;
+ if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
+ {
+ CLIPRDR_FILE_CONTENTS_RESPONSE resp;
+ if (fileContentsRequest->nPositionLow
+ || fileContentsRequest->nPositionHigh
+ || (fileContentsRequest->cbRequested != 0x00000008))
+ {
+ const char *msg
+ = "rdp_module: ft: ServerFileContentsRequest: "
+ "malformed request";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_warning, 0);
+ return CHANNEL_RC_OK;
+ }
+ memset(&resp, 0, sizeof(CLIPRDR_FILE_CONTENTS_RESPONSE));
+ resp.common.msgType = CB_FILECONTENTS_RESPONSE;
+ resp.common.msgFlags = CB_RESPONSE_OK;
+ resp.streamId = fileContentsRequest->streamId;
+ resp.cbRequested = sizeof(uint64_t);
+ resp.requestedData = (BYTE *)&(
+ clipboard
+ ->client_filelist_cache[fileContentsRequest->listIndex]
+ .file_size);
+ clipboard->clip_context->ClientFileContentsResponse(
+ clipboard->clip_context, &resp);
+ }
+ else if (fileContentsRequest->dwFlags == FILECONTENTS_RANGE)
+ {
+ wrdp_backend_ft_file_request req;
+ memset(&req, 0, sizeof(wrdp_backend_ft_list_entry));
+ /* TODO: better way to detect runing transfer */
+ clipboard->my_rdp_context->ft_to_server->is_runing = true;
+ req.file_id = fileContentsRequest->listIndex;
+ req.req_size = fileContentsRequest->cbRequested;
+ clipboard->my_rdp_context->ft_to_server->transfer_id
+ = fileContentsRequest->streamId;
+ memcpy(
+ &req.file_offset, &(fileContentsRequest->nPositionLow), 4);
+ memcpy(((uint8_t *)&req.file_offset) + 4,
+ &(fileContentsRequest->nPositionHigh), 4);
+ clipboard->my_rdp_context->my_internals->core->api_filetransfers
+ ->ft_request(&req,
+ clipboard->my_rdp_context->my_internals->task_info);
+ }
+ return CHANNEL_RC_OK;
+}
+
+/* unused for now
+ * static UINT
+rdp_clip_ClientFileContentsResponse(CliprdrClientContext* context,
+ CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
+{
+ return CHANNEL_RC_OK;
+} */
+
+static UINT
+rdp_clip_ServerFileContentsResponse(
+ CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *resp)
+{
+ /* TODO: somehow avoid memory copying here */
+ my_rdp_clipboard *clipboard = context->custom;
+ wrdp_backend_ft_chunk chunk;
+ if (resp->common.msgFlags & CB_RESPONSE_FAIL)
+ {
+ const char *msg = "rdp_module: ft: ServerFileContentsResponse: "
+ "CB_RESPONSE_FAIL";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_error, 0);
+ goto transfer_failed;
+ }
+ if (!resp->cbRequested
+ && (clipboard->my_rdp_context->ft_to_client->transferred
+ != clipboard->my_rdp_context->ft_to_client->file_size))
+ {
+ char msg[128];
+ snprintf(msg, 127,
+ "rdp_module: ft: chunk with zero size received on"
+ " position %lu of %lu",
+ clipboard->my_rdp_context->ft_to_client->transferred,
+ clipboard->my_rdp_context->ft_to_client->file_size);
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_error, 0);
+ goto transfer_failed;
+ }
+ else if (clipboard->my_rdp_context->ft_to_client->transfer_id
+ != resp->streamId)
+ {
+ const char *msg
+ = "rdp_module: clipboard: ft: transfer_id mismatch in "
+ "ServerFileContentsResponse";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_error, 0);
+ goto transfer_failed;
+ }
+ else if (resp->cbRequested)
+ {
+ chunk.transfer_id = resp->streamId;
+ chunk.size = resp->cbRequested;
+ clipboard->my_rdp_context->my_internals->core->api_filetransfers
+ ->ft_send_chunk(&chunk, (uint8_t *)(resp->requestedData),
+ clipboard->my_rdp_context->my_internals->task_info);
+ clipboard->my_rdp_context->ft_to_client->transferred
+ += resp->cbRequested;
+ }
+ /* request next file chunk */
+ if (clipboard->my_rdp_context->ft_to_client->transferred
+ < clipboard->my_rdp_context->ft_to_client->file_size)
+ {
+ my_rdp_context *c = clipboard->my_rdp_context;
+ CLIPRDR_FILE_CONTENTS_REQUEST file_req;
+ uint32_t chunk_len = 512000;
+ uint64_t left = 0;
+ memset(&file_req, 0, sizeof(CLIPRDR_FILE_CONTENTS_REQUEST));
+
+ left
+ = c->ft_to_client->file_size - c->ft_to_client->transferred;
+ if (left < chunk_len)
+ {
+ chunk_len = left;
+ }
+ file_req.cbRequested = chunk_len;
+ c->ft_to_client->transfer_id = rand();
+ file_req.streamId = c->ft_to_client->transfer_id;
+ file_req.listIndex = c->ft_to_client->file_id;
+ file_req.dwFlags = FILECONTENTS_RANGE;
+
+ /* TODO: check/change endianness */
+ memcpy(&(file_req.nPositionLow),
+ &(c->ft_to_client->transferred), 4);
+ memcpy(&(file_req.nPositionHigh),
+ (((uint8_t *)&(c->ft_to_client->transferred)) + 4), 4);
+ c->clipboard->clip_context->ClientFileContentsRequest(
+ c->clipboard->clip_context, &file_req);
+ }
+ else if (clipboard->my_rdp_context->ft_to_client->is_runing == true)
+ {
+ my_rdp_context *c = clipboard->my_rdp_context;
+ wrdp_backend_ft_status status;
+ {
+ char msg[128];
+ snprintf(msg, 127,
+ "rdp_module: ft: status: transfer finished,"
+ " transfered size: %lu",
+ clipboard->my_rdp_context->ft_to_client
+ ->transferred);
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_trace, 0);
+ }
+ memset(&status, 0, sizeof(wrdp_backend_ft_status));
+ status.status = ft_status_success;
+ status.file_id = c->ft_to_client->file_id;
+ status.transfer_id = c->ft_to_client->transfer_id;
+ c->my_internals->core->api_filetransfers->ft_finish(
+ &status, c->my_internals->task_info);
+ clipboard->my_rdp_context->ft_to_client->file_size = 0;
+ clipboard->my_rdp_context->ft_to_client->transfer_id = 0;
+ clipboard->my_rdp_context->ft_to_client->file_id = 0;
+ clipboard->my_rdp_context->ft_to_client->is_runing = false;
+ clipboard->my_rdp_context->ft_to_client->transferred = 0;
+ }
+ else
+ {
+ const char *msg = "rdp_module: clipboard: ft:"
+ " unexpected data chunk on finished transfer";
+ clipboard->my_rdp_context->my_internals->core->api_utils
+ ->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_warning, 0);
+ }
+ return CHANNEL_RC_OK;
+transfer_failed:
+{
+ my_rdp_context *c = clipboard->my_rdp_context;
+ wrdp_backend_ft_status status;
+ memset(&status, 0, sizeof(wrdp_backend_ft_status));
+ status.status = ft_status_failure;
+ status.file_id = c->ft_to_client->file_id;
+ status.transfer_id = c->ft_to_client->transfer_id;
+ c->my_internals->core->api_filetransfers->ft_finish(
+ &status, c->my_internals->task_info);
+ clipboard->my_rdp_context->ft_to_client->file_size = 0;
+ clipboard->my_rdp_context->ft_to_client->transfer_id = 0;
+ clipboard->my_rdp_context->ft_to_client->file_id = 0;
+ clipboard->my_rdp_context->ft_to_client->is_runing = false;
+ clipboard->my_rdp_context->ft_to_client->transferred = 0;
+}
+ return CHANNEL_RC_OK;
+}
+
+void
+rdp_cliprdr_init(my_rdp_context *ctx, CliprdrClientContext *cliprdr)
+{
+ ctx->clipboard->clip_context = cliprdr;
+ cliprdr->custom = (void *)ctx->clipboard;
+ ctx->clipboard->my_internals = ctx->my_internals;
+ cliprdr->MonitorReady = rdp_clip_MonitorReady;
+ cliprdr->ServerCapabilities = rdp_clip_ServerCapabilities;
+ cliprdr->ServerFormatList = rdp_clip_ServerFormatList;
+ cliprdr->ServerFormatListResponse = rdp_clip_ServerFormatListResponse;
+ cliprdr->ServerFormatDataRequest = rdp_clip_ServerFormatDataRequest;
+ cliprdr->ServerFormatDataResponse = rdp_clip_ServerFormatDataResponse;
+ cliprdr->ServerFileContentsRequest = rdp_clip_ServerFileContentsRequest;
+ cliprdr->ServerFileContentsResponse
+ = rdp_clip_ServerFileContentsResponse;
+ cliprdr->ServerLockClipboardData = rdp_clip_ServerLockClipboardData;
+ cliprdr->ServerUnlockClipboardData = rdp_clip_ServerUnlockClipboardData;
+}
+
+void
+rdp_cliprdr_uninit(my_rdp_context *ctx, CliprdrClientContext *cliprdr)
+{
+ /* do not need to do it here, done during backend destruction */
+ /* cliprdr->custom = NULL;
+
+ if (ctx->clipboard)
+ ctx->clipboard->clip_context = NULL;
+ ctx->clipboard = NULL; */
+}
+
+/* unused for now
+ * static UINT
+ClientRequestFileSize(wClipboardDelegate* delegate,
+ const wClipboardFileSizeRequest* request)
+{
+ return 0;
+}*/
+
+static UINT
+ClipboardFileSizeSuccess(wClipboardDelegate *delegate,
+ const wClipboardFileSizeRequest *request, UINT64 fileSize)
+{
+ CLIPRDR_FILE_CONTENTS_RESPONSE response;
+ my_rdp_clipboard *clipboard = delegate->custom;
+ ZeroMemory(&response, sizeof(response));
+ response.common.msgFlags = CB_RESPONSE_OK;
+ response.streamId = request->streamId;
+ response.cbRequested = sizeof(UINT64);
+ response.requestedData = (BYTE *)&fileSize;
+ return clipboard->clip_context->ClientFileContentsResponse(
+ clipboard->clip_context, &response);
+ // return 0;
+}
+static UINT
+ClipboardFileSizeFailure(wClipboardDelegate *delegate,
+ const wClipboardFileSizeRequest *request, UINT errorCode)
+{
+ CLIPRDR_FILE_CONTENTS_RESPONSE response;
+ my_rdp_clipboard *clipboard = delegate->custom;
+ ZeroMemory(&response, sizeof(response));
+ response.common.msgFlags = CB_RESPONSE_FAIL;
+ response.streamId = request->streamId;
+ return clipboard->clip_context->ClientFileContentsResponse(
+ clipboard->clip_context, &response);
+}
+
+/* unused for now
+ * static UINT
+ClientRequestFileRange(wClipboardDelegate* delegate,
+ const wClipboardFileRangeRequest* request)
+{
+ return 0;
+} */
+
+static UINT
+ClipboardFileRangeSuccess(wClipboardDelegate *delegate,
+ const wClipboardFileRangeRequest *request, const BYTE *data, UINT32 size)
+{
+ CLIPRDR_FILE_CONTENTS_RESPONSE response;
+ my_rdp_clipboard *clipboard = delegate->custom;
+ ZeroMemory(&response, sizeof(response));
+ response.common.msgFlags = CB_RESPONSE_OK;
+ response.streamId = request->streamId;
+ response.cbRequested = size;
+ response.requestedData = (BYTE *)data;
+ return clipboard->clip_context->ClientFileContentsResponse(
+ clipboard->clip_context, &response);
+}
+
+static UINT
+ClipboardFileRangeFailure(wClipboardDelegate *delegate,
+ const wClipboardFileRangeRequest *request, UINT errorCode)
+{
+ CLIPRDR_FILE_CONTENTS_RESPONSE response;
+ my_rdp_clipboard *clipboard = delegate->custom;
+ ZeroMemory(&response, sizeof(response));
+ response.common.msgFlags = CB_RESPONSE_FAIL;
+ response.streamId = request->streamId;
+ return clipboard->clip_context->ClientFileContentsResponse(
+ clipboard->clip_context, &response);
+}
+
+my_rdp_clipboard *
+rdp_clipboard_new(my_rdp_context *context)
+{
+ my_rdp_clipboard *clip = calloc(1, sizeof(my_rdp_clipboard));
+ if (!clip)
+ {
+ perror("calloc");
+ return 0;
+ }
+ clip->my_rdp_context = context;
+ clip->clipboard = ClipboardCreate();
+ clip->delegate = ClipboardGetDelegate(clip->clipboard);
+ clip->delegate->custom = clip;
+
+ clip->delegate->ClipboardFileSizeSuccess = ClipboardFileSizeSuccess;
+ clip->delegate->ClipboardFileSizeFailure = ClipboardFileSizeFailure;
+ clip->delegate->ClipboardFileRangeSuccess = ClipboardFileRangeSuccess;
+ clip->delegate->ClipboardFileRangeFailure = ClipboardFileRangeFailure;
+
+ context->clipboard = clip;
+
+ return clip;
+}
+
+static UINT
+cliprdr_send_data_request(my_rdp_clipboard *clipboard)
+{
+ CLIPRDR_FORMAT_DATA_REQUEST request;
+ ZeroMemory(&request, sizeof(CLIPRDR_FORMAT_DATA_REQUEST));
+ request.requestedFormatId = clipboard->cli_req_fmt_id.rdp_fmt.formatId;
+ return clipboard->clip_context->ClientFormatDataRequest(
+ clipboard->clip_context, &request);
+}
+
+static bool
+clip_api_handle_request_data(
+ const wrdp_backend_clipbrd_data_request *request, void *backend_internals)
+{
+ rdp_internals *i = backend_internals;
+ i->context->clipboard->cli_req_fmt_id.my_fmt = request->format;
+ switch (request->format)
+ {
+ case clip_format_raw:
+ {
+ /* i->context->clipboard->cli_req_fmt_id = CF_RAW;
+ * raw format does not work for some reason
+ */
+ i->context->clipboard->cli_req_fmt_id.rdp_fmt.formatId
+ = CF_TEXT;
+ }
+ break;
+ case clip_format_text:
+ {
+ i->context->clipboard->cli_req_fmt_id.rdp_fmt.formatId
+ = CF_TEXT;
+ }
+ break;
+ case clip_format_file_list:
+ {
+ /* 4.5.3 Format Data Request PDU
+ The following is an annotated dump of a Format
+ Data Request PDU (section 2.2.5.1). The format being
+ requested is the File List that was advertised
+ in section 4.5.1 (the advertised ID in the Format
+ List PDU was 49273).
+ */
+ uint8_t p;
+ bool format_found = false;
+ for (p = 0; p < i->context->clipboard->srv_fmts_count;
+ ++p)
+ {
+ if (!strcmp("FileGroupDescriptorW",
+ i->context->clipboard->srv_fmts[p]
+ .rdp_fmt.formatName))
+ {
+ i->context->clipboard->cli_req_fmt_id
+ .rdp_fmt.formatId
+ = i->context->clipboard->srv_fmts[p]
+ .rdp_fmt.formatId;
+ format_found = true;
+ break;
+ }
+ }
+ if (!format_found)
+ {
+ const char *msg = "rdp_module: cliprdr: "
+ "requested data format"
+ " id not found";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_warning, 0);
+ i->context->clipboard->cli_req_fmt_id.rdp_fmt
+ .formatId
+ = CF_RAW;
+ }
+ }
+ break;
+ case clip_format_unicode:
+ {
+ i->context->clipboard->cli_req_fmt_id.rdp_fmt.formatId
+ = CF_UNICODETEXT;
+ }
+ break;
+ default:
+ {
+ const char *msg
+ = "rdp_module: cliprdr: unsuported data format"
+ " requested";
+ i->core->api_utils->log_msg((const uint8_t *)msg,
+ strlen(msg), wrdp_log_level_warning, 0);
+ }
+ break;
+ }
+ cliprdr_send_data_request(i->context->clipboard);
+ return true;
+}
+
+static bool
+clip_api_handle_data_changed(
+ const wrdp_backend_clipbrd_fmts *fmts, void *backend_internals)
+{
+ rdp_internals *i = backend_internals;
+ my_rdp_clipboard *clip = i->context->clipboard;
+ uint8_t pos = 0;
+
+ CLIPRDR_FORMAT *formats = 0;
+ CLIPRDR_FORMAT_LIST formatList;
+
+ if (!fmts->count)
+ {
+ const char *msg = "received empty clipboard formats list";
+ i->core->api_utils->log_msg((const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_warning, 0);
+ return false;
+ }
+ formats = calloc(fmts->count, sizeof(CLIPRDR_FORMAT));
+ if (!formats)
+ {
+ perror("calloc");
+ return false;
+ }
+
+ for (; pos < fmts->count; ++pos)
+ {
+ switch ((wrdp_enum_clip_format)fmts->formats[pos])
+ {
+ case clip_format_raw:
+ {
+ formats[pos].formatId = CF_RAW;
+ }
+ break;
+ case clip_format_text:
+ {
+ formats[pos].formatId = CF_TEXT;
+ }
+ break;
+ case clip_format_unicode:
+ {
+ formats[pos].formatId = CF_UNICODETEXT;
+ }
+ break;
+ case clip_format_file_list:
+ {
+ formats[pos].formatId = CB_FORMAT_TEXTURILIST;
+ formats[pos].formatName
+ = "FileGroupDescriptorW";
+ }
+ break;
+ default:
+ {
+ formats[pos].formatId = CF_RAW;
+ }
+ break;
+ }
+ }
+ formatList.common.msgFlags = CB_RESPONSE_OK;
+ formatList.numFormats = fmts->count;
+ formatList.formats = formats;
+ /* TODO: check return value of ClientFormatList */
+ clip->clip_context->ClientFormatList(clip->clip_context, &formatList);
+ free(formats);
+
+ return true;
+}
+
+static bool
+clip_api_handle_send_data(
+ const wrdp_backend_clipbrd_data *data, void *backend_internals)
+{
+ rdp_internals *i = backend_internals;
+ my_rdp_clipboard *clip = i->context->clipboard;
+ CLIPRDR_FORMAT_DATA_RESPONSE response;
+
+ uint8_t type = data->data[0];
+ memset(&response, 0, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE));
+ response.common.msgType = CB_FORMAT_DATA_RESPONSE;
+ response.common.msgFlags = CB_RESPONSE_FAIL;
+ response.common.dataLen = 0;
+ response.requestedFormatData = 0;
+#ifdef DEBUG
+ {
+ const char *msg
+ = "rdp_module: clipboard: from client: raw clipboard"
+ " data:";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_trace, 0);
+ i->core->api_utils->log_msg(data->data, data->size,
+ wrdp_log_level_trace, wrdp_log_flag_binary);
+ }
+#endif
+ switch (type)
+ {
+ case clip_format_raw:
+ case clip_format_text:
+ {
+ if (data->size > 1)
+ {
+ response.common.msgFlags = CB_RESPONSE_OK;
+ response.common.dataLen = data->size - 1;
+ response.requestedFormatData = data->data + 1;
+ }
+ clip->clip_context->ClientFormatDataResponse(
+ clip->clip_context, &response);
+ return true;
+ }
+ break;
+ case clip_format_unicode:
+ {
+ uint8_t *data_buf = 0;
+ BYTE *msg_buf = 0;
+ iconv_t utf8_to_utf16 = iconv_open("UTF-16LE", "UTF-8");
+ char *ptr_w, *ptr_r;
+ size_t text_len_utf16 = (data->size - 1) * 2,
+ text_len_utf8 = data->size - 1,
+ text_len_result = text_len_utf16;
+ data_buf = calloc(text_len_utf16, sizeof(uint8_t));
+ if (!data_buf)
+ {
+ perror("calloc");
+ return true;
+ }
+ ptr_w = (char *)data_buf;
+ ptr_r = (char *)(data->data + 1);
+ while (text_len_utf8 && text_len_utf16)
+ {
+ if (iconv(utf8_to_utf16, &ptr_r, &text_len_utf8,
+ &ptr_w, &text_len_utf16)
+ == (size_t)-1)
+ {
+ log_msg_info mi = {0};
+ free(data_buf);
+ clip->clip_context
+ ->ClientFormatDataResponse(
+ clip->clip_context, &response);
+ mi.level = wrdp_log_level_warning;
+ mi.buf = (const uint8_t
+ *)"rdp_module: cliprdr: iconv: "
+ "failed to encode outgoing "
+ "buffer from utf8 to utf16le";
+ mi.task_info = i->task_info;
+ i->core->api_utils->log_msg_ex(&mi);
+ iconv_close(utf8_to_utf16);
+ return true;
+ }
+ }
+#ifdef DEBUG
+ if (text_len_utf8 && !text_len_utf16)
+ {
+ log_msg_info mi = {0};
+ mi.level = wrdp_log_level_trace;
+ mi.buf = (const uint8_t
+ *)"rdp_module: cliprdr: iconv: not "
+ "sufficient space in output buffer";
+ mi.task_info = i->task_info;
+ i->core->api_utils->log_msg_ex(&mi);
+ }
+#endif
+ iconv(utf8_to_utf16, 0, 0, &ptr_w, &text_len_utf16);
+ text_len_result = text_len_result - text_len_utf16;
+ iconv_close(utf8_to_utf16);
+ if (text_len_result)
+ {
+ msg_buf = calloc(text_len_result, sizeof(BYTE));
+ memcpy(msg_buf, data_buf, text_len_result);
+ free(data_buf);
+ response.common.msgFlags = CB_RESPONSE_OK;
+ response.common.dataLen = text_len_result;
+ response.requestedFormatData = msg_buf;
+ }
+#ifdef DEBUG
+ if (msg_buf)
+ {
+ log_msg_info mi = {0};
+ mi.level = wrdp_log_level_trace;
+ mi.buf = (const uint8_t
+ *)"rdp_module: clipboard: to server:"
+ " utf16 encoded buffer";
+ mi.task_info = i->task_info;
+ i->core->api_utils->log_msg_ex(&mi);
+ mi.flags = wrdp_log_flag_binary;
+ mi.buf = msg_buf;
+ mi.buf_size = text_len_result;
+ i->core->api_utils->log_msg_ex(&mi);
+ }
+#endif
+ clip->clip_context->ClientFormatDataResponse(
+ clip->clip_context, &response);
+ if (msg_buf)
+ {
+ free(msg_buf);
+ }
+ return true;
+ }
+ break;
+ case clip_format_file_list:
+ {
+ uint16_t file_count;
+ bool broken_msg = false;
+ int _i;
+ uint64_t data_offset = 3;
+ FILEDESCRIPTORW *file_list = 0;
+ BYTE *format_data = 0;
+ UINT32 format_data_length = 0;
+ memcpy(&file_count, data->data + 1, 2);
+ if (!file_count)
+ {
+ const char *msg = "rdp_module: clipboard: ft: "
+ "empty file_list received";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_warning, 0);
+ return true;
+ }
+ if (clip->client_filelist_cache)
+ {
+ free(clip->client_filelist_cache);
+ }
+ clip->client_filelist_cache
+ = calloc(file_count, sizeof(file_list_cache_entry));
+ if (!clip->client_filelist_cache)
+ {
+ perror("calloc");
+ return false;
+ }
+ file_list = calloc(file_count, sizeof(FILEDESCRIPTOR));
+ if (!file_list)
+ {
+ perror("calloc");
+ return false;
+ }
+ for (_i = 0; _i < file_count; ++_i)
+ {
+ uint16_t filename_len;
+ uint32_t file_id;
+ uint64_t file_size;
+ char *filename, *ptr_w, *ptr_r;
+ iconv_t utf8_to_utf16
+ = iconv_open("UTF-16LE", "UTF-8");
+ size_t text_len_utf16 = 260 * sizeof(WCHAR),
+ text_len_utf8;
+ memcpy(
+ &filename_len, data->data + data_offset, 2);
+ data_offset += 2;
+ if (data_offset >= data->size)
+ {
+ broken_msg = true;
+ break;
+ }
+ text_len_utf8 = filename_len;
+ memcpy(&file_id, data->data + data_offset, 4);
+ clip->client_filelist_cache[_i].file_id
+ = file_id;
+ data_offset += 4;
+ if (data_offset >= data->size)
+ {
+ broken_msg = true;
+ break;
+ }
+ memcpy(&file_size, data->data + data_offset, 8);
+ clip->client_filelist_cache[_i].file_size
+ = file_size;
+ data_offset += 8;
+ if ((data_offset >= data->size)
+ && (_i < file_count))
+ {
+ broken_msg = true;
+ break;
+ }
+ filename = (char *)data->data + data_offset;
+ ptr_r = filename;
+ ptr_w = (char *)(file_list[_i].cFileName);
+ iconv(utf8_to_utf16, &ptr_r, &text_len_utf8,
+ &ptr_w, &text_len_utf16);
+ iconv(utf8_to_utf16, 0, 0, &ptr_w,
+ &text_len_utf16);
+ iconv_close(utf8_to_utf16);
+ data_offset += filename_len;
+ file_list[_i].dwFileAttributes
+ = FILE_ATTRIBUTE_NORMAL;
+ file_list[_i].dwFlags = FD_ATTRIBUTES
+ | FD_FILESIZE
+ | FD_SHOWPROGRESSUI;
+ memcpy(&(file_list[_i].nFileSizeLow),
+ &file_size, 4);
+ memcpy(&(file_list[_i].nFileSizeHigh),
+ ((uint8_t *)&file_size) + 4, 4);
+ }
+ if (broken_msg)
+ {
+ char msg[128];
+ snprintf(msg, 127,
+ "rdp_module: cliprdr: error: wrong file"
+ " list message size: %d, file count: %d\n",
+ data->size, file_count);
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_error, 0);
+ }
+ else
+ {
+ UINT error = NO_ERROR;
+ error = cliprdr_serialize_file_list(file_list,
+ file_count, &format_data,
+ &format_data_length);
+ if (error)
+ {
+ char buf[128];
+ snprintf(buf, 127,
+ "failed to serialize "
+ "CLIPRDR_FILELIST:"
+ " 0x%08X",
+ error);
+ i->core->api_utils->log_msg(
+ (const uint8_t *)buf, strlen(buf),
+ wrdp_log_level_error, 0);
+ }
+ }
+ free(file_list);
+ if (format_data_length)
+ {
+ response.common.msgFlags = CB_RESPONSE_OK;
+ response.common.dataLen = format_data_length;
+ response.requestedFormatData = format_data;
+ }
+ clip->clip_context->ClientFormatDataResponse(
+ clip->clip_context, &response);
+
+ free(format_data);
+ return true;
+ }
+ break;
+ default:
+ {
+ response.common.msgFlags = CB_RESPONSE_FAIL;
+ response.common.dataLen = 0;
+ response.requestedFormatData = 0;
+ clip->clip_context->ClientFormatDataResponse(
+ clip->clip_context, &response);
+ return true;
+ }
+ break;
+ }
+ /* TODO: check return code from ClientFormatDataResponse */
+ return true;
+}
+
+void
+register_clipboard(wrdp_backend_module *backend)
+{
+ backend->callbacks_clipbrd->request_data = clip_api_handle_request_data;
+ backend->callbacks_clipbrd->send_data = clip_api_handle_send_data;
+ backend->callbacks_clipbrd->data_changed = clip_api_handle_data_changed;
+}
diff --git a/src/rdp/rdp_clipboard.h b/src/rdp/rdp_clipboard.h
new file mode 100644
index 0000000..1536a2c
--- /dev/null
+++ b/src/rdp/rdp_clipboard.h
@@ -0,0 +1,52 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "webrdp_core_api.h"
+#include "webrdp_module_api.h"
+#include "rdp_backend_api.h"
+#include "rdp_impl.h"
+
+typedef struct
+{
+ CLIPRDR_FORMAT rdp_fmt;
+ wrdp_enum_clip_format my_fmt;
+} my_clip_format;
+
+typedef struct
+{
+ uint32_t file_id;
+ uint64_t file_size;
+} file_list_cache_entry;
+
+struct my_rdp_clipboard_s
+{
+ wClipboard *clipboard;
+ CliprdrClientContext *clip_context;
+ my_rdp_context *my_rdp_context;
+ wClipboardDelegate *delegate;
+ bool streams_supported;
+ uint8_t *data_raw;
+ /* we need to cache server side format list to know dynamic format id */
+ my_clip_format *srv_fmts, cli_req_fmt_id, srv_req_fmt_id;
+ uint8_t srv_fmts_count;
+ file_list_cache_entry *client_filelist_cache;
+
+ rdp_internals *my_internals;
+};
+
+my_rdp_clipboard *rdp_clipboard_new(my_rdp_context *context);
+
+void rdp_cliprdr_init(my_rdp_context *ctx, CliprdrClientContext *cliprdr);
+
+void rdp_cliprdr_uninit(my_rdp_context *ctx, CliprdrClientContext *cliprdr);
+
+void register_clipboard(wrdp_backend_module *backend);
diff --git a/src/rdp/rdp_display_output.c b/src/rdp/rdp_display_output.c
new file mode 100644
index 0000000..16f3c5d
--- /dev/null
+++ b/src/rdp/rdp_display_output.c
@@ -0,0 +1,871 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include <freerdp/client/cmdline.h>
+#include <freerdp/client/file.h>
+#include <freerdp/constants.h>
+#include <freerdp/freerdp.h>
+#include <freerdp/gdi/gdi.h>
+#include <freerdp/log.h>
+#include <winpr/crt.h>
+#include <winpr/synch.h>
+
+#include <webrdp_core_api.h>
+#include <webrdp_module_api.h>
+
+#include "rdp_backend_api.h"
+#include "rdp_impl.h"
+#include "rdp_png.h"
+
+#define RGB_555_888(_r, _g, _b) \
+ _r = (_r << 3 & ~0x7) | (_r >> 2); \
+ _g = (_g << 3 & ~0x7) | (_g >> 2); \
+ _b = (_b << 3 & ~0x7) | (_b >> 2);
+#define RGB_565_888(_r, _g, _b) \
+ _r = (_r << 3 & ~0x7) | (_r >> 2); \
+ _g = (_g << 2 & ~0x3) | (_g >> 4); \
+ _b = (_b << 3 & ~0x7) | (_b >> 2);
+#define GetRGB_555(_r, _g, _b, _p) \
+ _r = (_p & 0x7C00) >> 10; \
+ _g = (_p & 0x3E0) >> 5; \
+ _b = (_p & 0x1F);
+#define GetRGB_565(_r, _g, _b, _p) \
+ _r = (_p & 0xF800) >> 11; \
+ _g = (_p & 0x7E0) >> 5; \
+ _b = (_p & 0x1F);
+#define GetRGB15(_r, _g, _b, _p) \
+ GetRGB_555(_r, _g, _b, _p); \
+ RGB_555_888(_r, _g, _b);
+#define GetRGB16(_r, _g, _b, _p) \
+ GetRGB_565(_r, _g, _b, _p); \
+ RGB_565_888(_r, _g, _b);
+#define RGB24(_r, _g, _b) ((_r << 16) | (_g << 8) | _b)
+#define GetRGB24(_r, _g, _b, _p) \
+ _r = (_p & 0xFF0000) >> 16; \
+ _g = (_p & 0xFF00) >> 8; \
+ _b = (_p & 0xFF);
+#define GetRGB32(_r, _g, _b, _p) \
+ _r = (_p & 0xFF0000) >> 16; \
+ _g = (_p & 0xFF00) >> 8; \
+ _b = (_p & 0xFF);
+#define ARGB32(_a, _r, _g, _b) (_a << 24) | (_r << 16) | (_g << 8) | _b
+#define RGB16(_r, _g, _b) \
+ (((_r >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) \
+ | ((_b >> 3) & 0x1F)
+#define RGB15(_r, _g, _b) \
+ (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) \
+ | ((_b >> 3) & 0x1F)
+#define GetARGB32(_a, _r, _g, _b, _p) \
+ _a = (_p & 0xFF000000) >> 24; \
+ _r = (_p & 0xFF0000) >> 16; \
+ _g = (_p & 0xFF00) >> 8; \
+ _b = (_p & 0xFF);
+
+HCLRCONV
+freerdp_clrconv_new(UINT32 flags)
+{
+ HCLRCONV clrconv;
+
+ clrconv = (CLRCONV *)calloc(1, sizeof(CLRCONV));
+
+ if (!clrconv)
+ {
+ perror("calloc");
+ return 0;
+ }
+
+ clrconv->alpha = (flags & CLRCONV_ALPHA) ? TRUE : FALSE;
+ clrconv->invert = (flags & CLRCONV_INVERT) ? TRUE : FALSE;
+ clrconv->rgb555 = (flags & CLRCONV_RGB555) ? TRUE : FALSE;
+
+ clrconv->palette = (rdpPalette *)calloc(1, sizeof(rdpPalette));
+
+ if (!clrconv->palette)
+ {
+ perror("calloc");
+ free(clrconv);
+ return 0;
+ }
+
+ return clrconv;
+}
+
+void
+freerdp_clrconv_free(HCLRCONV clrconv)
+{
+ if (clrconv)
+ {
+ free(clrconv->palette);
+ free(clrconv);
+ }
+}
+
+static int
+freerdp_get_pixel(BYTE *data, int x, int y, int width, int height, int bpp)
+{
+ int start;
+ int shift;
+ UINT16 *src16;
+ UINT32 *src32;
+ int red, green, blue;
+
+ switch (bpp)
+ {
+ case 1:
+ width = (width + 7) / 8;
+ start = (y * width) + x / 8;
+ shift = x % 8;
+ return (data[start] & (0x80 >> shift)) != 0;
+ case 8:
+ return data[y * width + x];
+ case 15:
+ case 16:
+ src16 = (UINT16 *)data;
+ return src16[y * width + x];
+ case 24:
+ data += y * width * 3;
+ data += x * 3;
+ red = data[0];
+ green = data[1];
+ blue = data[2];
+ return RGB24(red, green, blue);
+ case 32:
+ src32 = (UINT32 *)data;
+ return src32[y * width + x];
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void
+freerdp_set_pixel(
+ BYTE *data, int x, int y, int width, int height, int bpp, int pixel)
+{
+ int start;
+ int shift;
+ int *dst32;
+
+ if (bpp == 1)
+ {
+ width = (width + 7) / 8;
+ start = (y * width) + x / 8;
+ shift = x % 8;
+ if (pixel)
+ data[start] = data[start] | (0x80 >> shift);
+ else
+ data[start] = data[start] & ~(0x80 >> shift);
+ }
+ else if (bpp == 32)
+ {
+ dst32 = (int *)data;
+ dst32[y * width + x] = pixel;
+ }
+}
+
+static void
+freerdp_color_split_rgb(UINT32 *color, int bpp, BYTE *red, BYTE *green,
+ BYTE *blue, BYTE *alpha, HCLRCONV clrconv)
+{
+ *red = *green = *blue = 0;
+ *alpha = (clrconv->alpha) ? 0xFF : 0x00;
+
+ switch (bpp)
+ {
+ case 32:
+ if (clrconv->alpha)
+ {
+ GetARGB32(*alpha, *red, *green, *blue, *color);
+ }
+ else
+ {
+ GetRGB32(*red, *green, *blue, *color);
+ }
+ break;
+
+ case 24:
+ GetRGB24(*red, *green, *blue, *color);
+ break;
+
+ case 16:
+ GetRGB16(*red, *green, *blue, *color);
+ break;
+
+ case 15:
+ GetRGB15(*red, *green, *blue, *color);
+ break;
+
+ case 8:
+ *color &= 0xFF;
+ *red = clrconv->palette->entries[*color].red;
+ *green = clrconv->palette->entries[*color].green;
+ *blue = clrconv->palette->entries[*color].blue;
+ break;
+
+ case 1:
+ if (*color != 0)
+ {
+ *red = 0xFF;
+ *green = 0xFF;
+ *blue = 0xFF;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+freerdp_color_make_rgb(UINT32 *color, int bpp, BYTE *red, BYTE *green,
+ BYTE *blue, BYTE *alpha, HCLRCONV clrconv)
+{
+ switch (bpp)
+ {
+ case 32:
+ *color = ARGB32(*alpha, *red, *green, *blue);
+ break;
+
+ case 24:
+ *color = RGB24(*red, *green, *blue);
+ break;
+
+ case 16:
+ if (clrconv->rgb555)
+ {
+ *color = RGB15(*red, *green, *blue);
+ }
+ else
+ {
+ *color = RGB16(*red, *green, *blue);
+ }
+ break;
+
+ case 15:
+ *color = RGB15(*red, *green, *blue);
+ break;
+
+ case 8:
+ *color = RGB24(*red, *green, *blue);
+ break;
+
+ case 1:
+ if ((*red != 0) || (*green != 0) || (*blue != 0))
+ *color = 1;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static UINT32
+freerdp_color_convert_rgb(
+ UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
+{
+ BYTE red = 0;
+ BYTE green = 0;
+ BYTE blue = 0;
+ BYTE alpha = 0xFF;
+ UINT32 dstColor = 0;
+
+ freerdp_color_split_rgb(
+ &srcColor, srcBpp, &red, &green, &blue, &alpha, clrconv);
+ freerdp_color_make_rgb(
+ &dstColor, dstBpp, &red, &green, &blue, &alpha, clrconv);
+
+ return dstColor;
+}
+
+static void
+freerdp_alpha_cursor_convert(BYTE *alphaData, BYTE *xorMask, BYTE *andMask,
+ int width, int height, int bpp, HCLRCONV clrconv)
+{
+ UINT32 xorPixel;
+ UINT32 andPixel;
+ UINT32 x, y, jj;
+
+ for (y = 0; y < height; y++)
+ {
+ jj = (bpp == 1) ? y : (height - 1) - y;
+
+ for (x = 0; x < width; x++)
+ {
+ xorPixel = freerdp_get_pixel(
+ xorMask, x, jj, width, height, bpp);
+ xorPixel = freerdp_color_convert_rgb(
+ xorPixel, bpp, 32, clrconv);
+ andPixel = freerdp_get_pixel(
+ andMask, x, jj, width, height, 1);
+
+ if (andPixel)
+ {
+ if ((xorPixel & 0xFFFFFF) == 0xFFFFFF)
+ {
+ /* use pattern (not solid black) for xor
+ * area */
+ xorPixel = (x & 1) == (y & 1);
+ xorPixel = xorPixel ? 0xFFFFFF : 0;
+ xorPixel |= 0xFF000000;
+ }
+ else if (xorPixel == 0xFF000000)
+ {
+ xorPixel = 0;
+ }
+ }
+
+ freerdp_set_pixel(
+ alphaData, x, y, width, height, 32, xorPixel);
+ }
+ }
+}
+
+static void
+freerdp_bitmap_flip(BYTE *src, BYTE *dst, int scanLineSz, int height)
+{
+ int i;
+
+ BYTE *bottomLine = dst + (scanLineSz * (height - 1));
+ BYTE *topLine = src;
+
+ /* Special processing if called for flip-in-place. */
+ if (src == dst)
+ {
+ /* Allocate a scanline buffer.
+ * (FIXME: malloc / xfree below should be replaced by "get/put
+ * scanline buffer from a pool/Q of fixed buffers" to reuse
+ * fixed size buffers (of max scanline size (or adaptative?) )
+ * -- would be much faster).
+ */
+ BYTE *tmpBfr = (BYTE *)winpr_aligned_malloc(scanLineSz, 16);
+ if (!tmpBfr)
+ {
+ return;
+ }
+ int half = height / 2;
+ /* Flip buffer in place by line permutations through the temp
+ * scan line buffer.
+ * Note that if height has an odd number of line, we don't need
+ * to move the center scanline anyway.
+ * Also note that in place flipping takes three memcpy() calls
+ * to process two scanlines while src to distinct dest would
+ * only requires two memcpy() calls for two scanlines.
+ */
+ height--;
+ for (i = 0; i < half; i++)
+ {
+ CopyMemory(tmpBfr, topLine, scanLineSz);
+ CopyMemory(topLine, bottomLine, scanLineSz);
+ CopyMemory(bottomLine, tmpBfr, scanLineSz);
+ topLine += scanLineSz;
+ bottomLine -= scanLineSz;
+ height--;
+ }
+ winpr_aligned_free(tmpBfr);
+ }
+ /* Flip from source buffer to destination buffer. */
+ else
+ {
+ for (i = 0; i < height; i++)
+ {
+ if (bottomLine && topLine && scanLineSz)
+ {
+ CopyMemory(bottomLine, topLine, scanLineSz);
+ topLine += scanLineSz;
+ bottomLine -= scanLineSz;
+ }
+ }
+ }
+}
+
+static BYTE *
+freerdp_image_flip(BYTE *srcData, BYTE *dstData, int width, int height, int bpp)
+{
+ int scanline;
+
+ scanline = width * ((bpp + 7) / 8);
+
+ if (!dstData)
+ dstData = (BYTE *)winpr_aligned_malloc(
+ width * height * ((bpp + 7) / 8), 16);
+
+ if (!dstData)
+ {
+ return NULL;
+ }
+
+ freerdp_bitmap_flip(srcData, dstData, scanline, height);
+
+ return dstData;
+}
+
+/* outgoing rdp protocol to client implementation */
+
+static BOOL
+Pointer_New(rdpContext *context, rdpPointer *pointer)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ HCLRCONV hclrconv = c->my_internals->clrconv;
+ size_t psize = pointer->width * pointer->height * 4;
+
+ my_rdp_pointer *p = (my_rdp_pointer *)pointer;
+ p->id = c->my_internals->m_ptrId++;
+ uint8_t *pixels = malloc(sizeof(uint8_t) * psize);
+ if (!pixels)
+ {
+ perror("malloc");
+ return FALSE;
+ }
+ memset(pixels, 0, psize);
+ if ((pointer->andMaskData != 0) && (pointer->xorMaskData != 0))
+ {
+ //XXX
+ freerdp_alpha_cursor_convert(pixels, pointer->xorMaskData,
+ pointer->andMaskData, pointer->width, pointer->height,
+ pointer->xorBpp, hclrconv);
+ }
+
+ //check if the cursor is fully transparent
+ bool transparent = TRUE;
+ for (int y = 0; y < pointer->height; y++)
+ {
+ for (int x = 0; x < pointer->width; x++)
+ {
+ if (pixels[0 + x * 4 + y * 4 * pointer->width] != 0)
+ {
+ transparent = FALSE;
+ }
+ }
+ }
+ if (transparent)
+ {
+ pixels[3] = 1;
+ }
+
+ rdp_png_buf png_buf;
+ memset(&png_buf, 0, sizeof(png_buf));
+ png_buf.buf_size
+ = (pointer->width * pointer->height * sizeof(uint32_t))
+ + 8 /* allocating fullsize 32but argb pixels + png header */;
+ png_buf.buf = malloc(png_buf.buf_size);
+ if (!png_buf.buf)
+ {
+ free(pixels);
+ perror("malloc");
+ return FALSE;
+ }
+ png_generate_from_argb(
+ pointer->width, pointer->height, pixels, &png_buf);
+
+ wrdp_core_display_cursor cur = {0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+ (unsigned char)pointer->width, (unsigned char)pointer->height, 0x00,
+ 0x00, (unsigned char)pointer->xPos,
+ (unsigned char)(pointer->xPos >> 8), (unsigned char)pointer->yPos,
+ (unsigned char)(pointer->yPos >> 8), (unsigned char)png_buf.written,
+ (unsigned char)(png_buf.written >> 8),
+ (unsigned char)(png_buf.written >> 16),
+ (unsigned char)(png_buf.written >> 24), 0x16, 0x00, 0x00, 0x00};
+
+ cur.data = png_buf.buf;
+ wrdp_core_display_cursor_info cursor_info
+ = {p->id, pointer->xPos, pointer->yPos, png_buf.written, &cur};
+
+ c->my_internals->core->api_paint->send_ptr_new(
+ &cursor_info, c->my_internals->task_info);
+ free(png_buf.buf);
+ free(pixels);
+ return TRUE;
+}
+
+static void
+Pointer_Free(rdpContext *context, rdpPointer *pointer)
+{
+ my_rdp_pointer *p = (my_rdp_pointer *)pointer;
+ my_rdp_context *c = (my_rdp_context *)context;
+ if (p->id)
+ {
+ c->my_internals->core->api_paint->send_ptr_free(
+ p->id, c->my_internals->task_info);
+ }
+}
+
+static BOOL
+Pointer_Set(rdpContext *context, rdpPointer *pointer)
+{
+ my_rdp_pointer *p = (my_rdp_pointer *)pointer;
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->api_paint->send_ptr_set(
+ p->id, c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+Pointer_SetNull(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->api_paint->send_ptr_set_null(
+ c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+Pointer_SetDefault(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->api_paint->send_ptr_set_default(
+ c->my_internals->task_info);
+ return TRUE;
+}
+
+void
+register_pointer(rdpPointer *p)
+{
+ p->New = Pointer_New;
+ p->Free = Pointer_Free;
+ p->Set = Pointer_Set;
+ p->SetNull = Pointer_SetNull;
+ p->SetDefault = Pointer_SetDefault;
+}
+
+static BOOL
+BeginPaint(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->api_paint->send_begin_paint(
+ c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+EndPaint(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->api_paint->send_end_paint(
+ c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+SetBounds(rdpContext *context, const rdpBounds *bounds)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ wrdp_core_display_bounds lB;
+ if (bounds)
+ {
+ lB.left = bounds->left;
+ lB.right = bounds->right + 1;
+ lB.top = bounds->top;
+ lB.bottom = bounds->bottom + 1;
+ }
+ else
+ {
+ memset(&lB, 0, sizeof(wrdp_core_display_bounds));
+ }
+ c->my_internals->core->api_paint->send_set_bounds(
+ &lB, c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+Synchronize(rdpContext *context)
+{
+ return TRUE;
+}
+
+static BOOL
+DesktopResize(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ char buf[64];
+ snprintf(buf, 63, "R:%dx%d", context->settings->DesktopWidth,
+ context->settings->DesktopHeight);
+ c->my_internals->core->api_msgs->send_text_msg(
+ buf, c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+BitmapUpdate(rdpContext *context, const BITMAP_UPDATE *bitmap)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ int i;
+ BITMAP_DATA *bmd;
+ for (i = 0; i < (int)bitmap->number; i++)
+ {
+ bmd = &bitmap->rectangles[i];
+ wrdp_core_display_bmp bmp = {bmd->destLeft, bmd->destTop,
+ bmd->width, bmd->height, bmd->destRight - bmd->destLeft + 1,
+ bmd->destBottom - bmd->destTop + 1, bmd->bitsPerPixel,
+ bmd->compressed, bmd->bitmapLength};
+ if (!bmd->compressed)
+ {
+ freerdp_image_flip(bmd->bitmapDataStream,
+ bmd->bitmapDataStream, bmd->width, bmd->height,
+ bmd->bitsPerPixel);
+ }
+ c->my_internals->core->api_paint->send_bitmap(
+ &bmp, bmd->bitmapDataStream, c->my_internals->task_info);
+ }
+ return TRUE;
+}
+
+static BOOL
+Palette(rdpContext *c, const PALETTE_UPDATE *p)
+{
+ return TRUE;
+}
+
+static BOOL
+PlaySound(rdpContext *c, const PLAY_SOUND_UPDATE *s)
+{
+ return TRUE;
+}
+
+static BOOL
+RefreshRect(rdpContext *c, UINT8 hz, const RECTANGLE_16 *r)
+{
+ return TRUE;
+}
+
+static BOOL
+SuppressOutput(rdpContext *c, UINT8 hz, const RECTANGLE_16 *r)
+{
+ return TRUE;
+}
+
+/*static BOOL
+SurfaceCommand(rdpContext* c, wStream* s)
+{
+ return TRUE;
+}*/
+
+static BOOL
+SurfaceBits(rdpContext *c, const SURFACE_BITS_COMMAND *sbc)
+{
+ return TRUE;
+}
+
+/*static BOOL
+SurfaceFrameMarker(rdpContext* c, SURFACE_FRAME_MARKER* sfm)
+{
+ return TRUE;
+} */
+
+void
+RegisterUpdate(freerdp *rdp)
+{
+ rdpUpdate *u = rdp->context->update;
+ u->BeginPaint = BeginPaint;
+ u->EndPaint = EndPaint;
+ u->SetBounds = SetBounds;
+ u->Synchronize = Synchronize;
+ u->DesktopResize = DesktopResize;
+ u->BitmapUpdate = BitmapUpdate;
+ u->Palette = Palette;
+ u->PlaySound = PlaySound;
+ u->SurfaceBits = SurfaceBits;
+
+ u->RefreshRect = RefreshRect;
+ u->SuppressOutput = SuppressOutput;
+}
+
+static BOOL
+DstBlt(rdpContext *c, const DSTBLT_ORDER *_do)
+{
+ return TRUE;
+}
+
+static BOOL
+PatBlt(rdpContext *ctx, PATBLT_ORDER *po)
+{
+ my_rdp_context *c = (my_rdp_context *)ctx;
+ uint32_t rop3 = gdi_rop3_code(po->bRop);
+ if (GDI_BS_SOLID == po->brush.style)
+ {
+ wrdp_core_display_patblt_order patblt
+ = {po->nLeftRect, po->nTopRect, po->nWidth, po->nHeight,
+ FreeRDPConvertColor(po->foreColor, PIXEL_FORMAT_BGR16,
+ PIXEL_FORMAT_ABGR32,
+ NULL), //XXX
+ rop3};
+ c->my_internals->core->api_paint->send_pat_blt(
+ &patblt, c->my_internals->task_info);
+ }
+ return TRUE;
+}
+
+static BOOL
+ScrBlt(rdpContext *ctx, const SCRBLT_ORDER *sbo)
+{
+ my_rdp_context *c = (my_rdp_context *)ctx;
+ uint32_t rop3 = gdi_rop3_code(sbo->bRop);
+ wrdp_core_display_scr_blt scr_blt = {rop3, sbo->nLeftRect,
+ sbo->nTopRect, sbo->nWidth, sbo->nHeight, sbo->nXSrc, sbo->nYSrc};
+ c->my_internals->core->api_paint->send_scr_blt(
+ &scr_blt, c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+OpaqueRect(rdpContext *context, const OPAQUE_RECT_ORDER *oro)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ wrdp_core_display_opaque_rect_order oro2;
+ oro2.color = oro->color;
+ oro2.nHeight = oro->nHeight;
+ oro2.nLeftRect = oro->nLeftRect;
+ oro2.nTopRect = oro->nTopRect;
+ oro2.nWidth = oro->nWidth;
+ oro2.color = FreeRDPConvertColor(
+ oro2.color, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_ABGR32, NULL);
+ c->my_internals->core->api_paint->send_opaque_rect_order(
+ &oro2, c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+DrawNineGrid(rdpContext *c, const DRAW_NINE_GRID_ORDER *dngo)
+{
+ return TRUE;
+}
+
+static BOOL
+MultiDstBlt(rdpContext *c, const MULTI_DSTBLT_ORDER *mdo)
+{
+ return TRUE;
+}
+
+static BOOL
+MultiPatBlt(rdpContext *c, const MULTI_PATBLT_ORDER *mpo)
+{
+ return TRUE;
+}
+
+static BOOL
+MultiScrBlt(rdpContext *c, const MULTI_SCRBLT_ORDER *mso)
+{
+ return TRUE;
+}
+
+static BOOL
+MultiOpaqueRect(rdpContext *context, const MULTI_OPAQUE_RECT_ORDER *moro)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ wrdp_core_display_m_opaque_rect mrect;
+ mrect.color = FreeRDPConvertColor(
+ moro->color, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_ABGR32, NULL);
+ mrect.num_rect = moro->numRectangles;
+ mrect.rects = (wrdp_core_display_delta_rect *)(moro->rectangles);
+ c->my_internals->core->api_paint->send_multi_opaque_rect(
+ &mrect, c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+MultiDrawNineGrid(rdpContext *c, const MULTI_DRAW_NINE_GRID_ORDER *mdngo)
+{
+ return TRUE;
+}
+
+static BOOL
+LineTo(rdpContext *c, const LINE_TO_ORDER *lto)
+{
+ return TRUE;
+}
+
+static BOOL
+Polyline(rdpContext *c, const POLYLINE_ORDER *po)
+{
+ return TRUE;
+}
+
+static BOOL
+MemBlt(rdpContext *c, MEMBLT_ORDER *mo)
+{
+ return TRUE;
+}
+
+static BOOL
+Mem3Blt(rdpContext *c, MEM3BLT_ORDER *mo)
+{
+ return TRUE;
+}
+
+static BOOL
+SaveBitmap(rdpContext *c, const SAVE_BITMAP_ORDER *sbo)
+{
+ return TRUE;
+}
+
+static BOOL
+GlyphIndex(rdpContext *c, GLYPH_INDEX_ORDER *gio)
+{
+ return TRUE;
+}
+
+static BOOL
+FastIndex(rdpContext *c, const FAST_INDEX_ORDER *fio)
+{
+ return TRUE;
+}
+
+static BOOL
+FastGlyph(rdpContext *c, const FAST_GLYPH_ORDER *fgo)
+{
+ return TRUE;
+}
+
+static BOOL
+PolygonSC(rdpContext *c, const POLYGON_SC_ORDER *pso)
+{
+ return TRUE;
+}
+
+static BOOL
+PolygonCB(rdpContext *c, POLYGON_CB_ORDER *pco)
+{
+ return TRUE;
+}
+
+static BOOL
+EllipseSC(rdpContext *c, const ELLIPSE_SC_ORDER *eso)
+{
+ return TRUE;
+}
+
+static BOOL
+EllipseCB(rdpContext *c, const ELLIPSE_CB_ORDER *eco)
+{
+ return TRUE;
+}
+void
+RegisterPrimary(freerdp *rdp)
+{
+ rdpPrimaryUpdate *p = rdp->context->update->primary;
+ p->DstBlt = DstBlt;
+ p->PatBlt = PatBlt;
+ p->ScrBlt = ScrBlt;
+ p->OpaqueRect = OpaqueRect;
+ p->DrawNineGrid = DrawNineGrid;
+ p->MultiDstBlt = MultiDstBlt;
+ p->MultiPatBlt = MultiPatBlt;
+ p->MultiScrBlt = MultiScrBlt;
+ p->MultiOpaqueRect = MultiOpaqueRect;
+ p->MultiDrawNineGrid = MultiDrawNineGrid;
+ p->LineTo = LineTo;
+ p->Polyline = Polyline;
+ p->MemBlt = MemBlt;
+ p->Mem3Blt = Mem3Blt;
+ p->SaveBitmap = SaveBitmap;
+ p->GlyphIndex = GlyphIndex;
+ p->FastIndex = FastIndex;
+ p->FastGlyph = FastGlyph;
+ p->PolygonSC = PolygonSC;
+ p->PolygonCB = PolygonCB;
+ p->EllipseSC = EllipseSC;
+ p->EllipseCB = EllipseCB;
+}
diff --git a/src/rdp/rdp_display_output.h b/src/rdp/rdp_display_output.h
new file mode 100644
index 0000000..14ae7f3
--- /dev/null
+++ b/src/rdp/rdp_display_output.h
@@ -0,0 +1,17 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+void RegisterUpdate(freerdp *rdp);
+void RegisterPrimary(freerdp *rdp);
+
+void rdp_register_base(freerdp *r);
+
+HCLRCONV
+freerdp_clrconv_new(UINT32 flags);
+
+void freerdp_clrconv_free(HCLRCONV clrconv);
diff --git a/src/rdp/rdp_ft.c b/src/rdp/rdp_ft.c
new file mode 100644
index 0000000..0c5575e
--- /dev/null
+++ b/src/rdp/rdp_ft.c
@@ -0,0 +1,129 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#include "webrdp_module_api.h"
+#include "webrdp_core_api.h"
+#include "rdp_backend_api.h"
+#include "rdp_impl.h"
+#include "rdp_ft.h"
+#include "rdp_clipboard.h"
+
+static bool
+ft_api_handle_request(
+ const wrdp_backend_ft_file_request *request, void *backend_internals)
+{
+ rdp_internals *i = backend_internals;
+ CLIPRDR_FILE_CONTENTS_REQUEST file_req;
+ uint32_t chunk_len = 512000;
+ size_t left = 0;
+ if (i->context->ft_to_client->is_runing)
+ {
+ const char *msg
+ = "rdp_module: clipboard: filetransfers: transfer "
+ "already runing, cannot start new one";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ return true;
+ }
+ memset(&file_req, 0, sizeof(CLIPRDR_FILE_CONTENTS_REQUEST));
+ i->context->ft_to_client->transfer_id = rand();
+ i->context->ft_to_client->file_size = request->req_size;
+ i->context->ft_to_client->file_id = request->file_id;
+
+ i->context->ft_to_client->transferred = request->file_offset;
+ i->context->ft_to_client->is_runing = true;
+
+ left = i->context->ft_to_client->file_size
+ - i->context->ft_to_client->transferred;
+ if (left < chunk_len)
+ {
+ chunk_len = left;
+ }
+ file_req.cbRequested = chunk_len;
+ file_req.listIndex = request->file_id;
+ file_req.streamId = i->context->ft_to_client->transfer_id;
+ file_req.dwFlags = FILECONTENTS_RANGE;
+ /* file_req.haveClipDataId = TRUE;
+ file_req.clipDataId =
+ i->context->ft_to_client->clipboard_data_id; */
+
+ /* TODO: check/change endianness */
+ memcpy(&(file_req.nPositionLow),
+ &(i->context->ft_to_client->transferred), 4);
+ memcpy(&(file_req.nPositionHigh),
+ (((uint8_t *)&(i->context->ft_to_client->transferred)) + 4), 4);
+ i->context->clipboard->clip_context->ClientFileContentsRequest(
+ i->context->clipboard->clip_context, &file_req);
+
+ return true;
+}
+
+static bool
+ft_api_handle_chunk(const wrdp_backend_ft_chunk *chunk, const uint8_t *data,
+ void *backend_internals)
+{
+ rdp_internals *i = backend_internals;
+ CLIPRDR_FILE_CONTENTS_RESPONSE resp;
+ memset(&resp, 0, sizeof(CLIPRDR_FILE_CONTENTS_RESPONSE));
+ resp.cbRequested = chunk->size;
+ resp.streamId = i->context->ft_to_server->transfer_id;
+ resp.common.msgFlags = CB_RESPONSE_OK;
+ resp.common.msgType = CB_FILECONTENTS_RESPONSE;
+ resp.requestedData = data;
+ i->context->clipboard->clip_context->ClientFileContentsResponse(
+ i->context->clipboard->clip_context, &resp);
+ i->context->ft_to_server->transferred += chunk->size;
+ if (i->context->ft_to_server->transferred
+ == i->context->ft_to_server->file_size)
+ {
+ i->context->ft_to_server->is_runing = false;
+ i->context->ft_to_server->transfer_id = 0;
+ i->context->ft_to_server->file_id = 0;
+ i->context->ft_to_server->file_size = 0;
+ i->context->ft_to_server->transferred = 0;
+ }
+ return true;
+}
+
+static bool
+ft_api_handle_finish(
+ const wrdp_backend_ft_status *status, void *backend_internals)
+{
+ /* TODO: handle errors */
+ rdp_internals *i = backend_internals;
+ if (status->status != ft_status_success)
+ {
+ /* TODO: test it */
+ CLIPRDR_FILE_CONTENTS_RESPONSE resp;
+ memset(&resp, 0, sizeof(CLIPRDR_FILE_CONTENTS_RESPONSE));
+ const char *msg = "filetransfer finished with error";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ resp.common.msgType = CB_FILECONTENTS_RESPONSE;
+ resp.common.msgFlags = CB_RESPONSE_FAIL;
+ resp.streamId = i->context->ft_to_server->transfer_id;
+ resp.cbRequested = 0;
+ resp.requestedData = 0;
+ i->context->clipboard->clip_context->ClientFileContentsResponse(
+ i->context->clipboard->clip_context, &resp);
+ }
+ i->context->ft_to_server->is_runing = false;
+ i->context->ft_to_server->transfer_id = 0;
+ i->context->ft_to_server->file_size
+ = i->context->ft_to_server->transferred = 0;
+ return true;
+}
+
+void
+register_ft(wrdp_backend_module *backend)
+{
+ backend->callbacks_ft->chunk = ft_api_handle_chunk;
+ backend->callbacks_ft->finish = ft_api_handle_finish;
+ backend->callbacks_ft->request = ft_api_handle_request;
+}
diff --git a/src/rdp/rdp_ft.h b/src/rdp/rdp_ft.h
new file mode 100644
index 0000000..38b6a34
--- /dev/null
+++ b/src/rdp/rdp_ft.h
@@ -0,0 +1,17 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+struct my_rdp_ft_s
+{
+ uint32_t transfer_id, file_id;
+ bool is_runing;
+ uint64_t file_size, transferred;
+};
+
+void register_ft(wrdp_backend_module *backend);
+
diff --git a/src/rdp/rdp_impl.c b/src/rdp/rdp_impl.c
new file mode 100644
index 0000000..3aa47e2
--- /dev/null
+++ b/src/rdp/rdp_impl.c
@@ -0,0 +1,637 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include <errno.h>
+#include <locale.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <sys/select.h>
+
+#include <freerdp/client/channels.h>
+#include <freerdp/client/cliprdr.h>
+#include <freerdp/client/cmdline.h>
+#include <freerdp/client/file.h>
+#include <freerdp/constants.h>
+#include <freerdp/freerdp.h>
+#include <freerdp/gdi/gdi.h>
+#include <winpr/crt.h>
+#include <winpr/synch.h>
+#include <freerdp/log.h>
+
+#include <webrdp_core_api.h>
+#include <webrdp_module_api.h>
+
+#include "rdp_backend_api.h"
+#include "rdp_impl.h"
+#include "rdp_display_output.h"
+#include "rdp_channels.h"
+#include "rdp_clipboard.h"
+#include "rdp_ft.h"
+#include "rdp_user_input.h"
+
+/* from winpr */
+
+typedef BOOL (*pcIsHandled)(HANDLE handle);
+typedef BOOL (*pcCloseHandle)(HANDLE handle);
+typedef int (*pcGetFd)(HANDLE handle);
+typedef DWORD (*pcCleanupHandle)(HANDLE handle);
+typedef BOOL (*pcReadFile)(PVOID Object, LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
+ LPOVERLAPPED lpOverlapped);
+typedef BOOL (*pcReadFileEx)(HANDLE hFile, LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead, LPOVERLAPPED lpOverlapped,
+ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+typedef BOOL (*pcReadFileScatter)(HANDLE hFile,
+ FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead,
+ LPDWORD lpReserved, LPOVERLAPPED lpOverlapped);
+typedef BOOL (*pcWriteFile)(PVOID Object, LPCVOID lpBuffer,
+ DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
+ LPOVERLAPPED lpOverlapped);
+typedef BOOL (*pcWriteFileEx)(HANDLE hFile, LPCVOID lpBuffer,
+ DWORD nNumberOfBytesToWrite, LPOVERLAPPED lpOverlapped,
+ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+typedef BOOL (*pcWriteFileGather)(HANDLE hFile,
+ FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToWrite,
+ LPDWORD lpReserved, LPOVERLAPPED lpOverlapped);
+typedef DWORD (*pcGetFileSize)(HANDLE handle, LPDWORD lpFileSizeHigh);
+typedef BOOL (*pcFlushFileBuffers)(HANDLE hFile);
+typedef BOOL (*pcSetEndOfFile)(HANDLE handle);
+typedef DWORD (*pcSetFilePointer)(HANDLE handle, LONG lDistanceToMove,
+ PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod);
+typedef BOOL (*pcSetFilePointerEx)(HANDLE hFile, LARGE_INTEGER liDistanceToMove,
+ PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod);
+typedef BOOL (*pcLockFile)(HANDLE hFile, DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh);
+typedef BOOL (*pcLockFileEx)(HANDLE hFile, DWORD dwFlags, DWORD dwReserved,
+ DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
+ LPOVERLAPPED lpOverlapped);
+typedef BOOL (*pcUnlockFile)(HANDLE hFile, DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow,
+ DWORD nNumberOfBytesToUnlockHigh);
+typedef BOOL (*pcUnlockFileEx)(HANDLE hFile, DWORD dwReserved,
+ DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh,
+ LPOVERLAPPED lpOverlapped);
+typedef BOOL (*pcSetFileTime)(HANDLE hFile, const FILETIME *lpCreationTime,
+ const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime);
+
+typedef struct _HANDLE_OPS
+{
+ pcIsHandled IsHandled;
+ pcCloseHandle CloseHandle;
+ pcGetFd GetFd;
+ pcCleanupHandle CleanupHandle;
+ pcReadFile ReadFile;
+ pcReadFileEx ReadFileEx;
+ pcReadFileScatter ReadFileScatter;
+ pcWriteFile WriteFile;
+ pcWriteFileEx WriteFileEx;
+ pcWriteFileGather WriteFileGather;
+ pcGetFileSize GetFileSize;
+ pcFlushFileBuffers FlushFileBuffers;
+ pcSetEndOfFile SetEndOfFile;
+ pcSetFilePointer SetFilePointer;
+ pcSetFilePointerEx SetFilePointerEx;
+ pcLockFile LockFile;
+ pcLockFileEx LockFileEx;
+ pcUnlockFile UnlockFile;
+ pcUnlockFileEx UnlockFileEx;
+ pcSetFileTime SetFileTime;
+} HANDLE_OPS;
+
+#define WINPR_HANDLE_DEF() \
+ ULONG Type; \
+ ULONG Mode; \
+ HANDLE_OPS *ops
+
+struct winpr_handle
+{
+ WINPR_HANDLE_DEF();
+};
+typedef struct winpr_handle WINPR_HANDLE;
+
+static INLINE BOOL
+winpr_Handle_GetInfo(HANDLE handle, ULONG *pType, WINPR_HANDLE **pObject)
+{
+ WINPR_HANDLE *wHandle;
+
+ if (handle == NULL || handle == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ wHandle = (WINPR_HANDLE *)handle;
+
+ *pType = wHandle->Type;
+ *pObject = handle;
+
+ return TRUE;
+}
+
+static INLINE int
+winpr_Handle_getFd(HANDLE handle)
+{
+ WINPR_HANDLE *hdl;
+ ULONG type;
+
+ if (!winpr_Handle_GetInfo(handle, &type, &hdl))
+ return -1;
+
+ if (!hdl || !hdl->ops || !hdl->ops->GetFd)
+ return -1;
+
+ return hdl->ops->GetFd(handle);
+}
+
+/* end from winpr */
+
+bool
+rdp_init_internals(void *internals)
+{
+ setlocale(LC_ALL, "");
+#ifdef DEBUG
+ setenv("WLOG_LEVEL", "DEBUG", 1);
+#else
+ setenv("WLOG_LEVEL", "ERROR", 1);
+#endif
+ rdp_internals *i = internals;
+ i->instance = freerdp_new();
+ if (!i->instance)
+ {
+ const char *msg
+ = "rdp_module: Failed to create FreeRDP instance";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ goto error;
+ }
+ rdp_register_base(i->instance);
+ i->instance->ContextSize = sizeof(my_rdp_context);
+ if (!freerdp_context_new(i->instance))
+ {
+ const char *msg
+ = "rdp_module: Failed to create FreeRDP context";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ goto error;
+ }
+ i->context = (my_rdp_context *)i->instance->context;
+ ((my_rdp_context *)i->instance->context)->my_internals = internals;
+ {
+ char **argv = malloc(sizeof(char *));
+ if (!argv)
+ {
+ perror("malloc");
+ goto error;
+ }
+ argv[0] = strdup("./core");
+ rdpSettings *settings = i->instance->context->settings;
+ freerdp_client_settings_parse_command_line(
+ settings, 1, argv, FALSE);
+ free(argv[0]);
+ free(argv);
+ if (!settings)
+ {
+ const char *msg
+ = "rdp_module: Failed to create FreeRDP settings";
+ i->core->api_utils->log_msg((const uint8_t *)msg,
+ strlen(msg), wrdp_log_level_error, 0);
+ goto error;
+ }
+ settings->ThreadingFlags = THREADING_FLAGS_DISABLE_THREADS;
+
+ settings->OsMajorType = OSMAJORTYPE_UNIX;
+ settings->OsMinorType = OSMINORTYPE_UNSPECIFIED;
+
+ /* unsupported */
+ settings->RemoteFxCodec = FALSE;
+ settings->NSCodec = FALSE;
+
+ /* turn on clipboard redirect */
+ settings->RedirectClipboard = TRUE;
+ }
+ i->context->ft_to_server = calloc(1, sizeof(my_rdp_ft));
+ if (!i->context->ft_to_server)
+ {
+ perror("calloc");
+ goto error;
+ }
+ i->context->ft_to_client = calloc(1, sizeof(my_rdp_ft));
+ if (!i->context->ft_to_client)
+ {
+ perror("calloc");
+ goto error;
+ }
+ freerdp_register_addin_provider(
+ freerdp_channels_load_static_addin_entry, 0);
+ i->settings = i->instance->context->settings;
+ //i->instance->settings = i->settings;
+ i->settings->instance = i->instance;
+ i->instance->context->settings = i->settings;
+ return true;
+error:
+ if (i->instance)
+ {
+ if (i->instance->context)
+ {
+ freerdp_context_free(i->instance);
+ }
+ freerdp_free(i->instance);
+ i->instance = 0;
+ }
+ if (i->context->ft_to_client)
+ {
+ free(i->context->ft_to_client);
+ }
+ if (i->context->ft_to_server)
+ {
+ free(i->context->ft_to_server);
+ }
+ {
+ const char *msg = "rdp_module: internal error";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ }
+ i->core->api_msgs->send_error_msg(
+ "rdp_module_internal_error", i->task_info);
+ return false;
+}
+
+static void
+rdp_check_all_fds(struct ev_loop *loop, ev_io *w)
+{
+ rdp_internals *i = w->data;
+ bool failure = false;
+ if (i->backend->stopped)
+ return;
+ if ((freerdp_check_event_handles(i->instance->context)) != TRUE)
+ {
+ uint32_t e;
+ e = freerdp_error_info(i->instance);
+ switch (e)
+ {
+ case 1:
+ case 2:
+ case 7:
+ case 9:
+ /* case 12: */
+ /* No really an error
+ * (Happens when you invoke Disconnect
+ * in Start-Menu) */
+ break;
+ case 5:
+ {
+ const char *msg
+ = "rdp_module: Another user connected to "
+ "the server,\nforcing the "
+ "disconnection of the "
+ "current connection.";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_debug, 0);
+ break;
+ }
+ default:
+ {
+ failure = true;
+ }
+ break;
+ }
+ if (failure)
+ {
+ char buf[512];
+ snprintf(buf, 511, "%s",
+ freerdp_get_last_error_name(
+ freerdp_get_last_error(i->instance->context)));
+ i->core->api_msgs->send_error_msg(buf, i->task_info);
+ i->core->api_utils->log_msg((const uint8_t *)buf,
+ strlen(buf), wrdp_log_level_error, 0);
+ goto cleanup;
+ }
+ }
+ if (freerdp_shall_disconnect_context(i->instance->context))
+ {
+ {
+ const char *msg = "rdp_module: disconnect, no error";
+ i->core->api_utils->log_msg((const uint8_t *)msg,
+ strlen(msg), wrdp_log_level_trace, 0);
+ }
+ freerdp_disconnect(i->instance);
+ i->conn_state = rdp_conn_state_offline;
+ i->core->api_msgs->send_error_msg(
+ "rdp_module_disconnect_no_error", i->task_info);
+ goto cleanup;
+ }
+ return;
+cleanup:
+ ev_io_stop(loop, w);
+ if (!failure)
+ {
+ i->core->api_msgs->send_termination_msg(i->task_info);
+ }
+ i->core->api_core->task_finished(true, i->task_info);
+}
+
+static void
+rdp_fd_readable_cb(struct ev_loop *loop, ev_io *w, int revents)
+{
+ rdp_check_all_fds(loop, w);
+}
+
+bool
+rdp_connect(void *internals)
+{
+ rdp_internals *_i = internals;
+#ifdef DEBUG
+ {
+ /* print settings before connect for debug */
+ char buf[512];
+ snprintf(buf, 511,
+ "rdp_module: settings:\n\tfntlm: %ld\n\t"
+ "height: %ld\n\thost: %s\n\tnomani: %ld\n\tnonla: %ld\n\t"
+ "notheme: %ld\n\tnotls: %ld\n\tnowallp: %ld\n\tnowdrag: "
+ "%ld\n\t"
+ "password: %s\n\tpcb: %s\n\tperf: %ld\n\tport: "
+ "%ld\n\tuser: %s\n\t"
+ "width: %ld",
+ _i->my_settings.fntlm.value, _i->my_settings.height.value,
+ _i->my_settings.host.value, _i->my_settings.nomani.value,
+ _i->my_settings.nonla.value, _i->my_settings.notheme.value,
+ _i->my_settings.notls.value, _i->my_settings.nowallp.value,
+ _i->my_settings.nowdrag.value,
+ _i->my_settings.password.value, _i->my_settings.pcb.value,
+ _i->my_settings.perf.value, _i->my_settings.port.value,
+ _i->my_settings.user.value, _i->my_settings.width.value);
+ _i->core->api_utils->log_msg(
+ (const uint8_t *)buf, strlen(buf), wrdp_log_level_trace, 0);
+ }
+#endif /* DEBUG */
+ if (!_i->my_settings.host.value || !_i->my_settings.host.value[0])
+ {
+ const char *msg = "rdp_module: host is not set";
+ _i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ _i->core->api_msgs->send_error_msg(
+ "rdp_module_param_error", _i->task_info);
+ return false;
+ }
+ if (!_i->my_settings.port.value)
+ {
+ const char *msg = "rdp_module: port is not set";
+ _i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ _i->core->api_msgs->send_error_msg(
+ "rdp_module_param_error", _i->task_info);
+ return false;
+ }
+ if (!_i->my_settings.user.value || !_i->my_settings.user.value[0])
+ {
+ const char *msg = "rdp_module: user is not set";
+ _i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ _i->core->api_msgs->send_error_msg(
+ "rdp_module_param_error", _i->task_info);
+ return false;
+ }
+ /* password can be optional ? */
+ if (freerdp_connect(_i->instance))
+ {
+ int fdcount = 0, i;
+ HANDLE *fds[256];
+ ZeroMemory(fds, sizeof(fds));
+
+ struct ev_loop *loop
+ = _i->core->api_core->get_libev_loop(_i->task_info);
+ fdcount = freerdp_get_event_handles(
+ _i->instance->context, (HANDLE *)fds, 256);
+ if (!fdcount)
+ {
+ const char *msg
+ = "Failed to get FreeRDP file descriptors";
+ _i->core->api_utils->log_msg((const uint8_t *)msg,
+ strlen(msg), wrdp_log_level_error, 0);
+ _i->core->api_msgs->send_error_msg(
+ "rdp_module_internal_error", _i->task_info);
+ return false;
+ }
+ _i->rdp_fd_count = fdcount;
+ for (i = 0; i < fdcount; ++i)
+ {
+ ULONG type;
+ WINPR_HANDLE *phandle = 0;
+ int fd = 0;
+ if (!winpr_Handle_GetInfo(fds[i], &type, &phandle))
+ {
+ /* TODO: assume what this is not fatal */
+ const char *msg = "winpr_Handle_GetInfo failed";
+ _i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg),
+ wrdp_log_level_error, 0);
+ continue;
+ }
+ fd = winpr_Handle_getFd(phandle);
+
+ /* TODO: check type here, and set EV_WRITE if needed
+ * for now watch only for read available event*/
+ ev_io_init(
+ &(_i->rdp_fd[i]), rdp_fd_readable_cb, fd, EV_READ);
+ _i->rdp_fd[i].data = internals;
+ ev_io_start(loop, &(_i->rdp_fd[i]));
+ }
+ return true;
+ }
+ {
+ const char *msg = freerdp_get_last_error_name(
+ freerdp_get_last_error(_i->instance->context));
+ _i->core->api_msgs->send_error_msg(msg, _i->task_info);
+ }
+
+ return false;
+}
+
+static BOOL
+rdp_pre_connect(freerdp *instance)
+{
+ rdpSettings *settings = instance->context->settings;
+ my_rdp_context *c = (my_rdp_context *)instance->context;
+
+ RegisterUpdate(instance);
+ RegisterPrimary(instance);
+
+ /* looks like this settings reducing artifacts level */
+ settings->OrderSupport[NEG_PATBLT_INDEX] = FALSE;
+ settings->OrderSupport[NEG_SCRBLT_INDEX] = FALSE;
+
+ /* causing random disconnects */
+ settings->OrderSupport[NEG_ATEXTOUT_INDEX] = FALSE;
+ settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
+ settings->NoBitmapCompressionHeader = TRUE;
+ settings->BitmapCompressionDisabled = TRUE;
+ settings->BitmapCacheEnabled = FALSE;
+ settings->BrushSupportLevel = 0;
+
+ /* causing connection failure on recent versions of freerdp */
+ settings->OffscreenSupportLevel = 0;
+ settings->OffscreenCacheSize = 0;
+
+ /* following required at least on windows 7 */
+ settings->OrderSupport[NEG_MEMBLT_INDEX] = FALSE;
+ settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE;
+
+ /* following required for windows 2012,2016 */
+ settings->FastPathOutput = 1;
+
+ /* testing */
+ /* wsgate settings */
+ // settings->ColorDepth = 16;
+ // settings->FrameAcknowledge = 1;
+ // settings->LargePointerFlag = 1;
+ // settings->BitmapCacheV3Enabled = FALSE;
+ // settings->BitmapCachePersistEnabled = FALSE;
+ // settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
+ // settings->OrderSupport[NEG_PATBLT_INDEX] = FALSE; // XXX
+ // settings->OrderSupport[NEG_SCRBLT_INDEX] = FALSE; // XXX
+ // settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
+ // settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = FALSE; //
+ //XXX settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
+ // settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
+ // settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
+ // settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
+ // settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
+ // settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
+ // settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
+ // settings->GlyphSupportLevel = GLYPH_SUPPORT_NONE;
+
+ PubSub_SubscribeChannelConnected(
+ instance->context->pubSub, rdp_on_channel_connected);
+ PubSub_SubscribeChannelDisconnected(
+ instance->context->pubSub, rdp_on_channel_disconnected);
+
+ freerdp_client_load_addins(instance->context->channels, settings);
+ instance->context->cache = cache_new(instance->context);
+
+ c->my_internals->clrconv
+ = freerdp_clrconv_new(CLRCONV_ALPHA | CLRCONV_INVERT);
+
+ if (!instance->context->cache)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL
+rdp_post_connect(freerdp *instance)
+{
+ my_rdp_context *c = (my_rdp_context *)instance->context;
+ my_rdp_clipboard *clip = 0;
+ rdpPointer p;
+ memset(&p, 0, sizeof(p));
+ p.size = sizeof(my_rdp_pointer);
+ register_pointer(&p);
+ graphics_register_pointer(instance->context->graphics, &p);
+ pointer_cache_register_callbacks(instance->context->update);
+
+ clip = rdp_clipboard_new(c);
+ if (!clip)
+ {
+ const char *msg = "rdp_module: \"rdp_clipboard_new\" failed";
+ c->my_internals->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ return FALSE;
+ }
+ c->clipboard = clip;
+
+ c->my_internals->conn_state = rdp_conn_state_connected;
+
+ {
+ const char *msg
+ = "rdp_module: \"C:RDP session connection started.\"";
+ c->my_internals->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_trace, 0);
+ }
+
+ c->my_internals->core->api_msgs->send_text_msg(
+ "C:RDP session connection started.", c->my_internals->task_info);
+
+ instance->context->update->DesktopResize(instance->context);
+
+ return TRUE;
+}
+
+static DWORD
+rdp_verify_certificate(freerdp *instance, const char *host, UINT16 port,
+ const char *common_name, const char *subject, const char *issuer,
+ const char *fingerprint, DWORD flags)
+{
+ my_rdp_context *c = (my_rdp_context *)instance->context;
+ char buf[512];
+ snprintf(buf, 511,
+ "Certificate details:\n\tSubject: %s\n\tIssuer:"
+ " %s\n\tThumbprint: %s\n"
+ "The above X.509 certificate could not be verified, possibly "
+ "because you do not have "
+ "the CA certificate in your certificate store, or the "
+ "certificate has expired. "
+ "Please look at the OpenSSL documentation on how to add a "
+ "private CA to the store.",
+ subject, issuer, fingerprint);
+ c->my_internals->core->api_utils->log_msg(
+ (const uint8_t *)buf, strlen(buf), wrdp_log_level_debug, 0);
+
+ return TRUE; /* ?? */
+}
+
+/*static int
+rdp_receive_channel_data (freerdp* instance,
+ UINT16 channelId,
+ BYTE* data,
+ int size,
+ int flags,
+ int total_size)
+{
+ return freerdp_channels_data (
+ instance, channelId, data, size, flags, total_size);
+}*/
+
+static BOOL
+rdp_context_new(freerdp *instance, rdpContext *context)
+{
+ return TRUE;
+}
+
+static void
+rdp_context_free(freerdp *instance, rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ if (context->cache)
+ {
+ cache_free(context->cache);
+ context->cache = NULL;
+ }
+ if (c->my_internals->clrconv)
+ {
+ freerdp_clrconv_free(c->my_internals->clrconv);
+ c->my_internals->clrconv = NULL;
+ }
+}
+
+void
+rdp_register_base(freerdp *r)
+{
+ r->PreConnect = rdp_pre_connect;
+ r->PostConnect = rdp_post_connect;
+ r->VerifyCertificateEx = rdp_verify_certificate;
+ // r->ReceiveChannelData = rdp_receive_channel_data;
+ r->ContextNew = rdp_context_new;
+ r->ContextFree = rdp_context_free;
+}
diff --git a/src/rdp/rdp_impl.h b/src/rdp/rdp_impl.h
new file mode 100644
index 0000000..0e561ed
--- /dev/null
+++ b/src/rdp/rdp_impl.h
@@ -0,0 +1,127 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+#include <ev.h>
+
+#include <freerdp/freerdp.h>
+#include <winpr/clipboard.h>
+#include <freerdp/client/cliprdr.h>
+
+#define CLRCONV_ALPHA 1
+#define CLRCONV_INVERT 2
+/* if defined RGB555 format is used when rendering with a 16-bit frame buffer
+ */
+#define CLRCONV_RGB555 4
+/* Supported Internal Buffer Formats */
+#define CLRBUF_16BPP 8
+#define CLRBUF_32BPP 32
+
+struct _CLRCONV
+{
+ int alpha;
+ int invert;
+ int rgb555;
+ rdpPalette *palette;
+};
+typedef struct _CLRCONV CLRCONV;
+typedef CLRCONV *HCLRCONV;
+
+/* #define TAG CLIENT_TAG ("RDP")*/
+
+typedef struct
+{
+ /* TODO: make variables list instead of static set */
+ backend_setting_str host, pcb, user, password,
+ /* new settings from freerdp header:*/
+ Domain, PasswordHash, AcceptedCert, ClientHostname, ClientProductId,
+ AlternateShell, ShellWorkingDirectory, ClientAddress, ClientDir,
+ DynamicDSTTimeZoneKeyName, RemoteAssistanceSessionId,
+ RemoteAssistancePassStub, RemoteAssistancePassword,
+ RemoteAssistanceRCTicket, AuthenticationServiceClass,
+ AllowedTlsCiphers, NtlmSamFile, PreconnectionBlob,
+ RedirectionAcceptedCert, KerberosKdc, KerberosRealm,
+ CertificateName, CertificateFile, PrivateKeyFile,
+ CertificateContent, PrivateKeyContent, WindowTitle, WmClass,
+ ComputerName, ConnectionFile, AssistanceFile, HomePath, ConfigPath,
+ CurrentPath, DumpRemoteFxFile, PlayRemoteFxFile, GatewayHostname,
+ GatewayUsername, GatewayPassword, GatewayDomain, GatewayAccessToken,
+ GatewayAcceptedCert, ProxyHostname, RemoteApplicationName,
+ RemoteApplicationIcon, RemoteApplicationProgram,
+ RemoteApplicationFile, RemoteApplicationGuid,
+ RemoteApplicationCmdLine, ImeFileName, DrivesToRedirect,
+ ActionScript;
+ backend_setting_int port, perf, fntlm, nowallp, nowdrag, nomani,
+ notheme, nonla, notls, width, height,
+ /* new settings from freerdp header:*/
+ ServerMode, WaitForOutputBufferFlush, MaxTimeInCheckLoop,
+ DesktopWidth, DesktopHeight, Workarea, Fullscreen, GrabKeyboard,
+ Decorations, RdpVersion, ColorDepth, ExtSecurity, NlaSecurity,
+ TlsSecurity, RdpSecurity, NegotiateSecurityLayer,
+ RestrictedAdminModeRequired, MstscCookieMode, CookieMaxLength,
+ ClientBuild, KeyboardType, KeyboardSubType, KeyboardFunctionKey,
+ KeyboardLayout, UseRdpSecurityLayer, SaltedChecksum, ServerPort,
+ GatewayPort, DesktopResize, ToggleFullscreen, Floatbar, DesktopPosX,
+ DesktopPosY, SoftwareGdi, UnmapButtons, PerformanceFlags,
+ AllowFontSmoothing, AllowDesktopComposition, DisableWallpaper,
+ DisableFullWindowDrag, DisableMenuAnims, DisableThemes,
+ ConnectionType, EncryptionMethods, EncryptionLevel, FIPSMode,
+ CompressionEnabled, LogonNotify, BrushSupportLevel,
+ RemoteApplicationMode, TcpAckTimeout;
+} my_rdp_settings;
+
+typedef struct
+{
+ rdpPointer pointer;
+ uint32_t id;
+} my_rdp_pointer;
+
+struct rdp_internals_s;
+typedef struct rdp_internals_s rdp_internals;
+
+struct my_rdp_clipboard_s;
+typedef struct my_rdp_clipboard_s my_rdp_clipboard;
+
+struct my_rdp_ft_s;
+typedef struct my_rdp_ft_s my_rdp_ft;
+
+typedef struct
+{
+ rdpContext context;
+ my_rdp_clipboard *clipboard;
+ my_rdp_ft *ft_to_client, *ft_to_server;
+ rdp_internals *my_internals;
+} my_rdp_context;
+
+struct rdp_internals_s
+{
+ freerdp *instance;
+ my_rdp_context *context;
+
+ rdpSettings *settings;
+
+ void *task_info;
+ wrdp_core_exports *core;
+ wrdp_backend_module *backend;
+
+ my_rdp_settings my_settings;
+ rdp_connection_state conn_state;
+
+ /* libev watchers */
+ /* TODO: dynamic allocation */
+ ev_io rdp_fd[32];
+ int rdp_fd_count;
+
+ HCLRCONV clrconv;
+ uint32_t m_ptrId;
+};
+
+bool rdp_init_internals(void *internals);
+
+bool rdp_connect(void *internals);
+
+bool rdp_init_settings(void *internals);
diff --git a/src/rdp/rdp_io.c b/src/rdp/rdp_io.c
new file mode 100644
index 0000000..5754997
--- /dev/null
+++ b/src/rdp/rdp_io.c
@@ -0,0 +1,1492 @@
+#include <freerdp/client/channels.h>
+#include <freerdp/client/cliprdr.h>
+#include <freerdp/client/cmdline.h>
+#include <freerdp/client/file.h>
+#include <freerdp/constants.h>
+#include <freerdp/freerdp.h>
+#include <freerdp/gdi/gdi.h>
+#include <freerdp/log.h>
+#include <winpr/crt.h>
+#include <winpr/synch.h>
+
+#include <webrdp_core_api.h>
+#include <webrdp_module_api.h>
+
+#include "rdp_backend_api.h"
+#include "rdp_impl.h"
+#include "rdp_png.h"
+
+const UINT32 ASCII_TO_SCANCODE[256] = {
+ 0, /* 0 */
+ 0, /* 1 */
+ 0, /* 2 */
+ 0, /* 3 */
+ 0, /* 4 */
+ 0, /* 5 */
+ 0, /* 6 */
+ 0, /* 7 */
+ RDP_SCANCODE_BACKSPACE, /* 8 */
+ RDP_SCANCODE_TAB, /* 9 */
+ VK_KEY_D, /* 10 */
+ VK_KEY_F, /* 11 */
+ VK_KEY_H, /* 12 */
+ RDP_SCANCODE_RETURN, /* 13 */
+ RDP_SCANCODE_BACKSPACE, /* 14 */
+ VK_KEY_X, /* 15 */
+ RDP_SCANCODE_LSHIFT, /* 16 */
+ RDP_SCANCODE_LCONTROL, /* 17 */
+ RDP_SCANCODE_LMENU, /* 18 */
+ RDP_SCANCODE_PAUSE, /* 19 */
+ RDP_SCANCODE_CAPSLOCK, /* 20 */
+ VK_KEY_W, /* 21 */
+ VK_KEY_E, /* 22 */
+ VK_KEY_R, /* 23 */
+ VK_KEY_Y, /* 24 */
+ VK_KEY_A, /* 25 */
+ VK_KEY_1, /* 26 */
+ RDP_SCANCODE_ESCAPE, /* 27 */
+ VK_KEY_3, /* 28 */
+ VK_KEY_4, /* 29 */
+ VK_KEY_6, /* 30 */
+ VK_KEY_5, /* 31 */
+ RDP_SCANCODE_SPACE, /* 32 */
+ RDP_SCANCODE_PRIOR, /* 33 */
+ RDP_SCANCODE_NEXT, /* 34 */
+ RDP_SCANCODE_END, /* 35 */
+ RDP_SCANCODE_HOME, /* 36 */
+ RDP_SCANCODE_LEFT, /* 37 */
+ RDP_SCANCODE_UP, /* 38 */
+ RDP_SCANCODE_RIGHT, /* 39 */
+ RDP_SCANCODE_DOWN, /* 40 */
+ RDP_SCANCODE_KEY_0, /* 41 */
+ RDP_SCANCODE_MULTIPLY, /* 42 */
+ RDP_SCANCODE_ADD, /* 43 */
+ RDP_SCANCODE_PRINTSCREEN, /* 44 */
+ RDP_SCANCODE_INSERT, /* 45 */
+ RDP_SCANCODE_DELETE, /* 46 */
+ RDP_SCANCODE_DIVIDE, /* 47 */
+ RDP_SCANCODE_KEY_0, /* 48 */
+ RDP_SCANCODE_KEY_1, /* 49 */
+ RDP_SCANCODE_KEY_2, /* 50 */
+ RDP_SCANCODE_KEY_3, /* 51 */
+ RDP_SCANCODE_KEY_4, /* 52 */
+ RDP_SCANCODE_KEY_5, /* 53 */
+ RDP_SCANCODE_KEY_6, /* 54 */
+ RDP_SCANCODE_KEY_7, /* 55 */
+ RDP_SCANCODE_KEY_8, /* 56 */
+ RDP_SCANCODE_KEY_9, /* 57 */
+ RDP_SCANCODE_OEM_1, /* 58 */
+ RDP_SCANCODE_OEM_1, /* 59 */
+ RDP_SCANCODE_OEM_COMMA, /* 60 */
+ RDP_SCANCODE_OEM_PLUS, /* 61 */
+ RDP_SCANCODE_OEM_PERIOD, /* 62 */
+ RDP_SCANCODE_DIVIDE, /* 63 */
+ RDP_SCANCODE_KEY_2, /* 64 */
+ RDP_SCANCODE_KEY_A, /* 65 */
+ RDP_SCANCODE_KEY_B, /* 66 */
+ RDP_SCANCODE_KEY_C, /* 67 */
+ RDP_SCANCODE_KEY_D, /* 68 */
+ RDP_SCANCODE_KEY_E, /* 69 */
+ RDP_SCANCODE_KEY_F, /* 70 */
+ RDP_SCANCODE_KEY_G, /* 71 */
+ RDP_SCANCODE_KEY_H, /* 72 */
+ RDP_SCANCODE_KEY_I, /* 73 */
+ RDP_SCANCODE_KEY_J, /* 74 */
+ RDP_SCANCODE_KEY_K, /* 75 */
+ RDP_SCANCODE_KEY_L, /* 76 */
+ RDP_SCANCODE_KEY_M, /* 77 */
+ RDP_SCANCODE_KEY_N, /* 78 */
+ RDP_SCANCODE_KEY_O, /* 79 */
+ RDP_SCANCODE_KEY_P, /* 80 */
+ RDP_SCANCODE_KEY_Q, /* 81 */
+ RDP_SCANCODE_KEY_R, /* 82 */
+ RDP_SCANCODE_KEY_S, /* 83 */
+ RDP_SCANCODE_KEY_T, /* 84 */
+ RDP_SCANCODE_KEY_U, /* 85 */
+ RDP_SCANCODE_KEY_V, /* 86 */
+ RDP_SCANCODE_KEY_W, /* 87 */
+ RDP_SCANCODE_KEY_X, /* 88 */
+ RDP_SCANCODE_KEY_Y, /* 89 */
+ RDP_SCANCODE_KEY_Z, /* 90 */
+ RDP_SCANCODE_LWIN, /* 91 */
+ RDP_SCANCODE_RWIN, /* 92 */
+ RDP_SCANCODE_APPS, /* 93 */
+ RDP_SCANCODE_KEY_6, /* 94 */
+ RDP_SCANCODE_OEM_MINUS, /* 95 */
+ RDP_SCANCODE_NUMPAD0, /* 96 */
+ RDP_SCANCODE_NUMPAD1, /* 97 */
+ RDP_SCANCODE_NUMPAD2, /* 98 */
+ RDP_SCANCODE_NUMPAD3, /* 99 */
+ RDP_SCANCODE_NUMPAD4, /* 100 */
+ RDP_SCANCODE_NUMPAD5, /* 101 */
+ RDP_SCANCODE_NUMPAD6, /* 102 */
+ RDP_SCANCODE_NUMPAD7, /* 103 */
+ RDP_SCANCODE_NUMPAD8, /* 104 */
+ RDP_SCANCODE_NUMPAD9, /* 105 */
+ RDP_SCANCODE_MULTIPLY, /* 106 */
+ RDP_SCANCODE_ADD, /* 107 */
+ 0, /* 108 */
+ RDP_SCANCODE_SUBTRACT, /* 109 */
+ RDP_SCANCODE_DELETE, /* 110 */
+ RDP_SCANCODE_DIVIDE, /* 111 */
+ RDP_SCANCODE_F1, /* 112 */
+ RDP_SCANCODE_F2, /* 113 */
+ RDP_SCANCODE_F3, /* 114 */
+ RDP_SCANCODE_F4, /* 115 */
+ RDP_SCANCODE_F5, /* 116 */
+ RDP_SCANCODE_F6, /* 117 */
+ RDP_SCANCODE_F7, /* 118 */
+ RDP_SCANCODE_F8, /* 119 */
+ RDP_SCANCODE_F9, /* 120 */
+ RDP_SCANCODE_F10, /* 121 */
+ RDP_SCANCODE_F11, /* 122 */
+ RDP_SCANCODE_F12, /* 123 */
+ RDP_SCANCODE_OEM_5, /* 124 */
+ RDP_SCANCODE_OEM_6, /* 125 */
+ VK_F4, /* 126 */
+ VK_END, /* 127 */
+ VK_F2, /* 128 */
+ VK_NEXT, /* 129 */
+ VK_F1, /* 130 */
+ VK_LEFT, /* 131 */
+ VK_RIGHT, /* 132 */
+ VK_DOWN, /* 133 */
+ VK_UP, /* 134 */
+ 0, /* 135 */
+ 0, /* 136 */
+ 0, /* 137 */
+ 0, /* 138 */
+ 0, /* 139 */
+ 0, /* 140 */
+ 0, /* 141 */
+ 0, /* 142 */
+ 0, /* 143 */
+ RDP_SCANCODE_NUMLOCK, /* 144 */
+ RDP_SCANCODE_SCROLLLOCK, /* 145 */
+ 0, /* 146 */
+ 0, /* 147 */
+ 0, /* 148 */
+ 0, /* 149 */
+ 0, /* 150 */
+ 0, /* 151 */
+ 0, /* 152 */
+ 0, /* 153 */
+ 0, /* 154 */
+ 0, /* 155 */
+ 0, /* 156 */
+ 0, /* 157 */
+ 0, /* 158 */
+ 0, /* 159 */
+ 0, /* 160 */
+ 0, /* 161 */
+ 0, /* 162 */
+ 0, /* 163 */
+ 0, /* 164 */
+ 0, /* 165 */
+ 0, /* 166 */
+ 0, /* 167 */
+ 0, /* 168 */
+ 0, /* 169 */
+ 0, /* 170 */
+ 0, /* 171 */
+ 0, /* 172 */
+ RDP_SCANCODE_OEM_MINUS, /* 173 */
+ 0, /* 174 */
+ 0, /* 175 */
+ 0, /* 176 */
+ 0, /* 177 */
+ 0, /* 178 */
+ 0, /* 179 */
+ 0, /* 180 */
+ 0, /* 181 */
+ 0, /* 182 */
+ 0, /* 183 */
+ 0, /* 184 */
+ 0, /* 185 */
+ RDP_SCANCODE_OEM_1, /* 186 */
+ RDP_SCANCODE_OEM_PLUS, /* 187 */
+ RDP_SCANCODE_OEM_COMMA, /* 188 */
+ RDP_SCANCODE_OEM_MINUS, /* 189 */
+ RDP_SCANCODE_OEM_PERIOD, /* 190 */
+ RDP_SCANCODE_OEM_2, /* 191 */
+ RDP_SCANCODE_OEM_3, /* 192 */
+ 0, /* 193 */
+ 0, /* 194 */
+ 0, /* 195 */
+ 0, /* 196 */
+ 0, /* 197 */
+ 0, /* 198 */
+ 0, /* 199 */
+ 0, /* 200 */
+ 0, /* 201 */
+ 0, /* 202 */
+ 0, /* 203 */
+ 0, /* 204 */
+ 0, /* 205 */
+ 0, /* 206 */
+ 0, /* 207 */
+ 0, /* 208 */
+ 0, /* 209 */
+ 0, /* 210 */
+ 0, /* 211 */
+ 0, /* 212 */
+ 0, /* 213 */
+ 0, /* 214 */
+ 0, /* 215 */
+ 0, /* 216 */
+ 0, /* 217 */
+ 0, /* 218 */
+ RDP_SCANCODE_OEM_4, /* 219 */
+ RDP_SCANCODE_OEM_5, /* 220 */
+ RDP_SCANCODE_OEM_6, /* 221 */
+ RDP_SCANCODE_OEM_7, /* 222 */
+ 0, /* 223 */
+ 0, /* 224 */
+ 0, /* 225 */
+ 0, /* 226 */
+ 0, /* 227 */
+ 0, /* 228 */
+ 0, /* 229 */
+ 0, /* 230 */
+ 0, /* 231 */
+ 0, /* 232 */
+ 0, /* 233 */
+ 0, /* 234 */
+ 0, /* 235 */
+ 0, /* 236 */
+ 0, /* 237 */
+ 0, /* 238 */
+ 0, /* 239 */
+ 0, /* 240 */
+ 0, /* 241 */
+ 0, /* 242 */
+ 0, /* 243 */
+ 0, /* 244 */
+ 0, /* 245 */
+ 0, /* 246 */
+ 0, /* 247 */
+ 0, /* 248 */
+ 0, /* 249 */
+ 0, /* 250 */
+ 0, /* 251 */
+ 0, /* 252 */
+ 0, /* 253 */
+ 0, /* 254 */
+ 0 /* 255 */
+};
+
+#define RGB_555_888(_r, _g, _b) \
+ _r = (_r << 3 & ~0x7) | (_r >> 2); \
+ _g = (_g << 3 & ~0x7) | (_g >> 2); \
+ _b = (_b << 3 & ~0x7) | (_b >> 2);
+#define RGB_565_888(_r, _g, _b) \
+ _r = (_r << 3 & ~0x7) | (_r >> 2); \
+ _g = (_g << 2 & ~0x3) | (_g >> 4); \
+ _b = (_b << 3 & ~0x7) | (_b >> 2);
+#define GetRGB_555(_r, _g, _b, _p) \
+ _r = (_p & 0x7C00) >> 10; \
+ _g = (_p & 0x3E0) >> 5; \
+ _b = (_p & 0x1F);
+#define GetRGB_565(_r, _g, _b, _p) \
+ _r = (_p & 0xF800) >> 11; \
+ _g = (_p & 0x7E0) >> 5; \
+ _b = (_p & 0x1F);
+#define GetRGB15(_r, _g, _b, _p) \
+ GetRGB_555(_r, _g, _b, _p); \
+ RGB_555_888(_r, _g, _b);
+#define GetRGB16(_r, _g, _b, _p) \
+ GetRGB_565(_r, _g, _b, _p); \
+ RGB_565_888(_r, _g, _b);
+#define RGB24(_r, _g, _b) ((_r << 16) | (_g << 8) | _b)
+#define GetRGB24(_r, _g, _b, _p) \
+ _r = (_p & 0xFF0000) >> 16; \
+ _g = (_p & 0xFF00) >> 8; \
+ _b = (_p & 0xFF);
+#define GetRGB32(_r, _g, _b, _p) \
+ _r = (_p & 0xFF0000) >> 16; \
+ _g = (_p & 0xFF00) >> 8; \
+ _b = (_p & 0xFF);
+#define ARGB32(_a, _r, _g, _b) (_a << 24) | (_r << 16) | (_g << 8) | _b
+#define RGB16(_r, _g, _b) \
+ (((_r >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) \
+ | ((_b >> 3) & 0x1F)
+#define RGB15(_r, _g, _b) \
+ (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) \
+ | ((_b >> 3) & 0x1F)
+#define GetARGB32(_a, _r, _g, _b, _p) \
+ _a = (_p & 0xFF000000) >> 24; \
+ _r = (_p & 0xFF0000) >> 16; \
+ _g = (_p & 0xFF00) >> 8; \
+ _b = (_p & 0xFF);
+
+static HCLRCONV
+freerdp_clrconv_new(UINT32 flags)
+{
+ HCLRCONV clrconv;
+
+ clrconv = (CLRCONV *)calloc(1, sizeof(CLRCONV));
+
+ if (!clrconv)
+ return NULL;
+
+ clrconv->alpha = (flags & CLRCONV_ALPHA) ? TRUE : FALSE;
+ clrconv->invert = (flags & CLRCONV_INVERT) ? TRUE : FALSE;
+ clrconv->rgb555 = (flags & CLRCONV_RGB555) ? TRUE : FALSE;
+
+ clrconv->palette = (rdpPalette *)calloc(1, sizeof(rdpPalette));
+
+ if (!clrconv->palette)
+ {
+ free(clrconv);
+ return NULL;
+ }
+
+ return clrconv;
+}
+
+static void
+freerdp_clrconv_free(HCLRCONV clrconv)
+{
+ if (clrconv)
+ {
+ free(clrconv->palette);
+ free(clrconv);
+ }
+}
+
+static int
+freerdp_get_pixel(BYTE *data, int x, int y, int width, int height, int bpp)
+{
+ int start;
+ int shift;
+ UINT16 *src16;
+ UINT32 *src32;
+ int red, green, blue;
+
+ switch (bpp)
+ {
+ case 1:
+ width = (width + 7) / 8;
+ start = (y * width) + x / 8;
+ shift = x % 8;
+ return (data[start] & (0x80 >> shift)) != 0;
+ case 8:
+ return data[y * width + x];
+ case 15:
+ case 16:
+ src16 = (UINT16 *)data;
+ return src16[y * width + x];
+ case 24:
+ data += y * width * 3;
+ data += x * 3;
+ red = data[0];
+ green = data[1];
+ blue = data[2];
+ return RGB24(red, green, blue);
+ case 32:
+ src32 = (UINT32 *)data;
+ return src32[y * width + x];
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void
+freerdp_set_pixel(
+ BYTE *data, int x, int y, int width, int height, int bpp, int pixel)
+{
+ int start;
+ int shift;
+ int *dst32;
+
+ if (bpp == 1)
+ {
+ width = (width + 7) / 8;
+ start = (y * width) + x / 8;
+ shift = x % 8;
+ if (pixel)
+ data[start] = data[start] | (0x80 >> shift);
+ else
+ data[start] = data[start] & ~(0x80 >> shift);
+ }
+ else if (bpp == 32)
+ {
+ dst32 = (int *)data;
+ dst32[y * width + x] = pixel;
+ }
+}
+
+static void
+freerdp_color_split_rgb(UINT32 *color, int bpp, BYTE *red, BYTE *green,
+ BYTE *blue, BYTE *alpha, HCLRCONV clrconv)
+{
+ *red = *green = *blue = 0;
+ *alpha = (clrconv->alpha) ? 0xFF : 0x00;
+
+ switch (bpp)
+ {
+ case 32:
+ if (clrconv->alpha)
+ {
+ GetARGB32(*alpha, *red, *green, *blue, *color);
+ }
+ else
+ {
+ GetRGB32(*red, *green, *blue, *color);
+ }
+ break;
+
+ case 24:
+ GetRGB24(*red, *green, *blue, *color);
+ break;
+
+ case 16:
+ GetRGB16(*red, *green, *blue, *color);
+ break;
+
+ case 15:
+ GetRGB15(*red, *green, *blue, *color);
+ break;
+
+ case 8:
+ *color &= 0xFF;
+ *red = clrconv->palette->entries[*color].red;
+ *green = clrconv->palette->entries[*color].green;
+ *blue = clrconv->palette->entries[*color].blue;
+ break;
+
+ case 1:
+ if (*color != 0)
+ {
+ *red = 0xFF;
+ *green = 0xFF;
+ *blue = 0xFF;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+freerdp_color_make_rgb(UINT32 *color, int bpp, BYTE *red, BYTE *green,
+ BYTE *blue, BYTE *alpha, HCLRCONV clrconv)
+{
+ switch (bpp)
+ {
+ case 32:
+ *color = ARGB32(*alpha, *red, *green, *blue);
+ break;
+
+ case 24:
+ *color = RGB24(*red, *green, *blue);
+ break;
+
+ case 16:
+ if (clrconv->rgb555)
+ {
+ *color = RGB15(*red, *green, *blue);
+ }
+ else
+ {
+ *color = RGB16(*red, *green, *blue);
+ }
+ break;
+
+ case 15:
+ *color = RGB15(*red, *green, *blue);
+ break;
+
+ case 8:
+ *color = RGB24(*red, *green, *blue);
+ break;
+
+ case 1:
+ if ((*red != 0) || (*green != 0) || (*blue != 0))
+ *color = 1;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static UINT32
+freerdp_color_convert_rgb(
+ UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
+{
+ BYTE red = 0;
+ BYTE green = 0;
+ BYTE blue = 0;
+ BYTE alpha = 0xFF;
+ UINT32 dstColor = 0;
+
+ freerdp_color_split_rgb(
+ &srcColor, srcBpp, &red, &green, &blue, &alpha, clrconv);
+ freerdp_color_make_rgb(
+ &dstColor, dstBpp, &red, &green, &blue, &alpha, clrconv);
+
+ return dstColor;
+}
+
+static void
+freerdp_alpha_cursor_convert(BYTE *alphaData, BYTE *xorMask, BYTE *andMask,
+ int width, int height, int bpp, HCLRCONV clrconv)
+{
+ UINT32 xorPixel;
+ UINT32 andPixel;
+ UINT32 x, y, jj;
+
+ for (y = 0; y < height; y++)
+ {
+ jj = (bpp == 1) ? y : (height - 1) - y;
+
+ for (x = 0; x < width; x++)
+ {
+ xorPixel = freerdp_get_pixel(
+ xorMask, x, jj, width, height, bpp);
+ xorPixel = freerdp_color_convert_rgb(
+ xorPixel, bpp, 32, clrconv);
+ andPixel = freerdp_get_pixel(
+ andMask, x, jj, width, height, 1);
+
+ if (andPixel)
+ {
+ if ((xorPixel & 0xFFFFFF) == 0xFFFFFF)
+ {
+ /* use pattern (not solid black) for xor
+ * area */
+ xorPixel = (x & 1) == (y & 1);
+ xorPixel = xorPixel ? 0xFFFFFF : 0;
+ xorPixel |= 0xFF000000;
+ }
+ else if (xorPixel == 0xFF000000)
+ {
+ xorPixel = 0;
+ }
+ }
+
+ freerdp_set_pixel(
+ alphaData, x, y, width, height, 32, xorPixel);
+ }
+ }
+}
+
+static void
+freerdp_bitmap_flip(BYTE *src, BYTE *dst, int scanLineSz, int height)
+{
+ int i;
+
+ BYTE *bottomLine = dst + (scanLineSz * (height - 1));
+ BYTE *topLine = src;
+
+ /* Special processing if called for flip-in-place. */
+ if (src == dst)
+ {
+ /* Allocate a scanline buffer.
+ * (FIXME: malloc / xfree below should be replaced by "get/put
+ * scanline buffer from a pool/Q of fixed buffers" to reuse
+ * fixed size buffers (of max scanline size (or adaptative?) )
+ * -- would be much faster).
+ */
+ BYTE *tmpBfr = (BYTE *)_aligned_malloc(scanLineSz, 16);
+ int half = height / 2;
+ /* Flip buffer in place by line permutations through the temp
+ * scan line buffer.
+ * Note that if height has an odd number of line, we don't need
+ * to move the center scanline anyway.
+ * Also note that in place flipping takes three memcpy() calls
+ * to process two scanlines while src to distinct dest would
+ * only requires two memcpy() calls for two scanlines.
+ */
+ height--;
+ for (i = 0; i < half; i++)
+ {
+ CopyMemory(tmpBfr, topLine, scanLineSz);
+ CopyMemory(topLine, bottomLine, scanLineSz);
+ CopyMemory(bottomLine, tmpBfr, scanLineSz);
+ topLine += scanLineSz;
+ bottomLine -= scanLineSz;
+ height--;
+ }
+ _aligned_free(tmpBfr);
+ }
+ /* Flip from source buffer to destination buffer. */
+ else
+ {
+
+ for (i = 0; i < height; i++)
+ {
+ CopyMemory(bottomLine, topLine, scanLineSz);
+ topLine += scanLineSz;
+ bottomLine -= scanLineSz;
+ }
+ }
+}
+
+static BYTE *
+freerdp_image_flip(BYTE *srcData, BYTE *dstData, int width, int height, int bpp)
+{
+ int scanline;
+
+ scanline = width * ((bpp + 7) / 8);
+
+ if (!dstData)
+ dstData = (BYTE *)_aligned_malloc(
+ width * height * ((bpp + 7) / 8), 16);
+
+ if (!dstData)
+ {
+ return NULL;
+ }
+
+ freerdp_bitmap_flip(srcData, dstData, scanline, height);
+
+ return dstData;
+}
+
+/* outgoing rdp protocol to client implementation */
+
+static BOOL
+Pointer_New(rdpContext *context, rdpPointer *pointer)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ HCLRCONV hclrconv = c->my_internals->clrconv;
+ size_t psize = pointer->width * pointer->height * 4;
+
+ my_rdp_pointer *p = (my_rdp_pointer *)pointer;
+ p->id = c->my_internals->m_ptrId++;
+ uint8_t *pixels = malloc(sizeof(uint8_t) * psize);
+ memset(pixels, 0, psize);
+ if ((pointer->andMaskData != 0) && (pointer->xorMaskData != 0))
+ {
+ //XXX
+ freerdp_alpha_cursor_convert(pixels, pointer->xorMaskData,
+ pointer->andMaskData, pointer->width, pointer->height,
+ pointer->xorBpp, hclrconv);
+ }
+
+ //check if the cursor is fully transparent
+ bool transparent = TRUE;
+ for (int y = 0; y < pointer->height; y++)
+ {
+ for (int x = 0; x < pointer->width; x++)
+ {
+ if (pixels[0 + x * 4 + y * 4 * pointer->width] != 0)
+ {
+ transparent = FALSE;
+ }
+ }
+ }
+ if (transparent)
+ {
+ pixels[3] = 1;
+ }
+
+ rdp_png_buf png_buf;
+ memset(&png_buf, 0, sizeof(png_buf));
+ png_buf.buf_size
+ = (pointer->width * pointer->height * sizeof(uint32_t))
+ + 8 /* allocating fullsize 32but argb pixels + png header */;
+ png_buf.buf = malloc(png_buf.buf_size);
+ png_generate_from_argb(
+ pointer->width, pointer->height, pixels, &png_buf);
+
+ struct
+ {
+ unsigned char resL; //2 bytes reserved must always be 0
+ unsigned char resH;
+ unsigned char imgTypeL; //2 bytes image type. 1 = ICO, 2 = CUR
+ unsigned char imgTypeH;
+ unsigned char nbImgL; //2 bytes number of images
+ unsigned char nbImgH;
+ unsigned char width; //1 byte image width in pixels
+ unsigned char height; //1 byte image height in pixels
+ unsigned char nbColors; //1 bytenumber of colors. 0 if not using
+ //a color pallete
+ unsigned char res; //1 byte reserved, should be 0
+ unsigned char xPosL; //2 bytes of hot spot x (for ICO, color
+ //planes, 0 or 1)
+ unsigned char xPosH;
+ unsigned char
+ yPosL; //2 bytes of hot spot y (for ICO bits per pixel)
+ unsigned char yPosH;
+ unsigned char sizeLL; //4 bytes of image size
+ unsigned char sizeLH;
+ unsigned char sizeHL;
+ unsigned char sizeHH;
+ unsigned char offsetLL; //4 bytes of offset of the data
+ unsigned char offsetLH;
+ unsigned char offsetHL;
+ unsigned char offsetHH;
+ } curHeader = {0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+ (unsigned char)pointer->width, (unsigned char)pointer->height, 0x00,
+ 0x00, (unsigned char)pointer->xPos,
+ (unsigned char)(pointer->xPos >> 8), (unsigned char)pointer->yPos,
+ (unsigned char)(pointer->yPos >> 8), (unsigned char)png_buf.written,
+ (unsigned char)(png_buf.written >> 8),
+ (unsigned char)(png_buf.written >> 16),
+ (unsigned char)(png_buf.written >> 24), 0x16, 0x00, 0x00, 0x00};
+
+ size_t cursor_buf_size = png_buf.written + sizeof(curHeader);
+ uint8_t *cursor_buf = malloc(cursor_buf_size);
+
+ memcpy(cursor_buf, &curHeader, sizeof(curHeader));
+ memcpy(cursor_buf + sizeof(curHeader), png_buf.buf, png_buf.written);
+ free(png_buf.buf);
+
+ /* rdp_cursor_add (p->id, cursor_buf, cursor_buf_size,
+ * c->my_internals); */
+
+ free(pixels);
+ struct
+ {
+ uint32_t id;
+ uint32_t hx;
+ uint32_t hy;
+ } tmp = {p->id, pointer->xPos, pointer->yPos};
+ size_t send_buf_size = sizeof(tmp) + cursor_buf_size;
+ uint8_t *send_buf = malloc(send_buf_size);
+ memcpy(send_buf, &tmp, sizeof(tmp));
+ memcpy(send_buf + sizeof(tmp), cursor_buf, cursor_buf_size);
+ free(cursor_buf);
+ c->my_internals->core->send_ptr_new(
+ send_buf, send_buf_size, c->my_internals->task_info);
+ return TRUE;
+}
+
+static void
+Pointer_Free(rdpContext *context, rdpPointer *pointer)
+{
+ my_rdp_pointer *p = (my_rdp_pointer *)pointer;
+ my_rdp_context *c = (my_rdp_context *)context;
+ if (p->id)
+ {
+ /* rdp_cursor_erase (p->id, c->my_internals); */
+ c->my_internals->core->send_ptr_free((uint8_t *)&(p->id),
+ sizeof(uint32_t), c->my_internals->task_info);
+ }
+}
+
+static BOOL
+Pointer_Set(rdpContext *context, const rdpPointer *pointer)
+{
+ my_rdp_pointer *p = (my_rdp_pointer *)pointer;
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->send_ptr_set(
+ (uint8_t *)&(p->id), sizeof(uint32_t), c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+Pointer_SetNull(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->send_ptr_set_null(c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+Pointer_SetDefault(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->send_ptr_set_default(c->my_internals->task_info);
+ return TRUE;
+}
+
+void
+register_pointer(rdpPointer *p)
+{
+ p->New = Pointer_New;
+ p->Free = Pointer_Free;
+ p->Set = Pointer_Set;
+ p->SetNull = Pointer_SetNull;
+ p->SetDefault = Pointer_SetDefault;
+}
+
+static BOOL
+rdp_context_new(freerdp *instance, rdpContext *context)
+{
+ return TRUE;
+}
+
+static void
+rdp_context_free(freerdp *instance, rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ if (context->cache)
+ {
+ cache_free(context->cache);
+ context->cache = NULL;
+ }
+ if (c->my_internals->clrconv)
+ {
+ freerdp_clrconv_free(c->my_internals->clrconv);
+ c->my_internals->clrconv = NULL;
+ }
+}
+
+static BOOL
+BeginPaint(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->send_begin_paint(c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+EndPaint(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ c->my_internals->core->send_end_paint(c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+SetBounds(rdpContext *context, const rdpBounds *bounds)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ rdpBounds lB;
+ if (bounds)
+ {
+ memcpy(&lB, bounds, sizeof(rdpBounds));
+ lB.right++;
+ lB.bottom++;
+ }
+ else
+ {
+ memset(&lB, 0, sizeof(rdpBounds));
+ }
+ c->my_internals->core->send_set_bounds(
+ (uint8_t *)&lB, sizeof(lB), c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+Synchronize(rdpContext *context)
+{
+ return TRUE;
+}
+
+static BOOL
+DesktopResize(rdpContext *context)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ char buf[64];
+ snprintf(buf, 63, "R:%dx%d", context->settings->DesktopWidth,
+ context->settings->DesktopHeight);
+ c->my_internals->core->send_text_msg(buf, c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+BitmapUpdate(rdpContext *context, const BITMAP_UPDATE *bitmap)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ int i;
+ BITMAP_DATA *bmd;
+ for (i = 0; i < (int)bitmap->number; i++)
+ {
+ bmd = &bitmap->rectangles[i];
+ struct
+ {
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+ uint32_t h;
+ uint32_t dw;
+ uint32_t dh;
+ uint32_t bpp;
+ uint32_t cf;
+ uint32_t sz;
+ } wxbm = {bmd->destLeft, bmd->destTop, bmd->width, bmd->height,
+ bmd->destRight - bmd->destLeft + 1,
+ bmd->destBottom - bmd->destTop + 1, bmd->bitsPerPixel,
+ (uint32_t)bmd->compressed, bmd->bitmapLength};
+ if (!bmd->compressed)
+ {
+ freerdp_image_flip(bmd->bitmapDataStream,
+ bmd->bitmapDataStream, bmd->width, bmd->height,
+ bmd->bitsPerPixel);
+ }
+ size_t buf_size = sizeof(wxbm) + bmd->bitmapLength;
+ uint8_t *buf = malloc(buf_size);
+ memcpy(buf, &wxbm, sizeof(wxbm));
+ memcpy(buf + sizeof(wxbm), bmd->bitmapDataStream,
+ bmd->bitmapLength);
+ c->my_internals->core->send_bitmap(
+ buf, buf_size, c->my_internals->task_info);
+ free(buf);
+ }
+ return TRUE;
+}
+
+static BOOL
+Palette(rdpContext *c, const PALETTE_UPDATE *p)
+{
+ return TRUE;
+}
+
+static BOOL
+PlaySound(rdpContext *c, const PLAY_SOUND_UPDATE *s)
+{
+ return TRUE;
+}
+
+static BOOL
+RefreshRect(rdpContext *c, UINT8 hz, const RECTANGLE_16 *r)
+{
+ return TRUE;
+}
+
+static BOOL
+SuppressOutput(rdpContext *c, UINT8 hz, const RECTANGLE_16 *r)
+{
+ return TRUE;
+}
+
+/*static BOOL
+SurfaceCommand(rdpContext* c, wStream* s)
+{
+ return TRUE;
+}*/
+
+static BOOL
+SurfaceBits(rdpContext *c, const SURFACE_BITS_COMMAND *sbc)
+{
+ return TRUE;
+}
+
+/*static BOOL
+SurfaceFrameMarker(rdpContext* c, SURFACE_FRAME_MARKER* sfm)
+{
+ return TRUE;
+} */
+
+void
+RegisterUpdate(freerdp *rdp)
+{
+ rdp->update->BeginPaint = BeginPaint;
+ rdp->update->EndPaint = EndPaint;
+ rdp->update->SetBounds = SetBounds;
+ rdp->update->Synchronize = Synchronize;
+ rdp->update->DesktopResize = DesktopResize;
+ rdp->update->BitmapUpdate = BitmapUpdate;
+ rdp->update->Palette = Palette;
+ rdp->update->PlaySound = PlaySound;
+ rdp->update->SurfaceBits = SurfaceBits;
+
+ rdp->update->RefreshRect = RefreshRect;
+ rdp->update->SuppressOutput = SuppressOutput;
+}
+
+static BOOL
+DstBlt(rdpContext *c, const DSTBLT_ORDER *_do)
+{
+ return TRUE;
+}
+
+static BOOL
+PatBlt(rdpContext *ctx, PATBLT_ORDER *po)
+{
+ my_rdp_context *c = (my_rdp_context *)ctx;
+ uint32_t rop3 = gdi_rop3_code(po->bRop);
+ if (GDI_BS_SOLID == po->brush.style)
+ {
+ struct
+ {
+ int32_t x;
+ int32_t y;
+ int32_t w;
+ int32_t h;
+ uint32_t fg;
+ uint32_t rop;
+ } tmp = {po->nLeftRect, po->nTopRect, po->nWidth, po->nHeight,
+ ConvertColor(po->foreColor, PIXEL_FORMAT_BGR16,
+ PIXEL_FORMAT_ABGR32,
+ NULL), //XXX
+ rop3};
+ c->my_internals->core->send_pat_blt(
+ (uint8_t *)&tmp, sizeof(tmp), c->my_internals->task_info);
+ }
+ return TRUE;
+}
+
+static BOOL
+ScrBlt(rdpContext *ctx, const SCRBLT_ORDER *sbo)
+{
+ my_rdp_context *c = (my_rdp_context *)ctx;
+ uint32_t rop3 = gdi_rop3_code(sbo->bRop);
+ struct
+ {
+ uint32_t rop;
+ int32_t x;
+ int32_t y;
+ int32_t w;
+ int32_t h;
+ int32_t sx;
+ int32_t sy;
+ } tmp = {rop3, sbo->nLeftRect, sbo->nTopRect, sbo->nWidth, sbo->nHeight,
+ sbo->nXSrc, sbo->nYSrc};
+ c->my_internals->core->send_scr_blt(
+ (uint8_t *)&tmp, sizeof(tmp), c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+OpaqueRect(rdpContext *context, const OPAQUE_RECT_ORDER *oro)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ OPAQUE_RECT_ORDER oro2 = *oro;
+ oro2.color = ConvertColor(
+ oro2.color, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_ABGR32, NULL);
+ c->my_internals->core->send_opaque_rect_order((uint8_t *)&oro2,
+ sizeof(OPAQUE_RECT_ORDER), c->my_internals->task_info);
+ return TRUE;
+}
+
+static BOOL
+DrawNineGrid(rdpContext *c, const DRAW_NINE_GRID_ORDER *dngo)
+{
+ return TRUE;
+}
+
+static BOOL
+MultiDstBlt(rdpContext *c, const MULTI_DSTBLT_ORDER *mdo)
+{
+ return TRUE;
+}
+
+static BOOL
+MultiPatBlt(rdpContext *c, const MULTI_PATBLT_ORDER *mpo)
+{
+ return TRUE;
+}
+
+static BOOL
+MultiScrBlt(rdpContext *c, const MULTI_SCRBLT_ORDER *mso)
+{
+ return TRUE;
+}
+
+static BOOL
+MultiOpaqueRect(rdpContext *context, const MULTI_OPAQUE_RECT_ORDER *moro)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ uint32_t color = ConvertColor(
+ moro->color, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_ABGR32, NULL);
+ uint32_t nr = moro->numRectangles;
+ size_t buf_size
+ = (sizeof(color) + sizeof(nr)) + (sizeof(DELTA_RECT) * nr);
+ uint8_t *buf = malloc(buf_size);
+ memcpy(buf, (uint8_t *)&color, sizeof(color));
+ memcpy(buf + sizeof(color), (uint8_t *)&nr, sizeof(nr));
+ memcpy(buf + (sizeof(color) + sizeof(color)),
+ (uint8_t *)&moro->rectangles[1], sizeof(DELTA_RECT) * nr);
+ c->my_internals->core->send_multi_opaque_rect(
+ buf, buf_size, c->my_internals->task_info);
+ free(buf);
+ return TRUE;
+}
+
+static BOOL
+MultiDrawNineGrid(rdpContext *c, const MULTI_DRAW_NINE_GRID_ORDER *mdngo)
+{
+ return TRUE;
+}
+
+static BOOL
+LineTo(rdpContext *c, const LINE_TO_ORDER *lto)
+{
+ return TRUE;
+}
+
+static BOOL
+Polyline(rdpContext *c, const POLYLINE_ORDER *po)
+{
+ return TRUE;
+}
+
+static BOOL
+MemBlt(rdpContext *c, MEMBLT_ORDER *mo)
+{
+ return TRUE;
+}
+
+static BOOL
+Mem3Blt(rdpContext *c, MEM3BLT_ORDER *mo)
+{
+ return TRUE;
+}
+
+static BOOL
+SaveBitmap(rdpContext *c, const SAVE_BITMAP_ORDER *sbo)
+{
+ return TRUE;
+}
+
+static BOOL
+GlyphIndex(rdpContext *c, GLYPH_INDEX_ORDER *gio)
+{
+ return TRUE;
+}
+
+static BOOL
+FastIndex(rdpContext *c, const FAST_INDEX_ORDER *fio)
+{
+ return TRUE;
+}
+
+static BOOL
+FastGlyph(rdpContext *c, const FAST_GLYPH_ORDER *fgo)
+{
+ return TRUE;
+}
+
+static BOOL
+PolygonSC(rdpContext *c, const POLYGON_SC_ORDER *pso)
+{
+ return TRUE;
+}
+
+static BOOL
+PolygonCB(rdpContext *c, POLYGON_CB_ORDER *pco)
+{
+ return TRUE;
+}
+
+static BOOL
+EllipseSC(rdpContext *c, const ELLIPSE_SC_ORDER *eso)
+{
+ return TRUE;
+}
+
+static BOOL
+EllipseCB(rdpContext *c, const ELLIPSE_CB_ORDER *eco)
+{
+ return TRUE;
+}
+void
+RegisterPrimary(freerdp *rdp)
+{
+ rdp->update->primary->DstBlt = DstBlt;
+ rdp->update->primary->PatBlt = PatBlt;
+ rdp->update->primary->ScrBlt = ScrBlt;
+ rdp->update->primary->OpaqueRect = OpaqueRect;
+ rdp->update->primary->DrawNineGrid = DrawNineGrid;
+ rdp->update->primary->MultiDstBlt = MultiDstBlt;
+ rdp->update->primary->MultiPatBlt = MultiPatBlt;
+ rdp->update->primary->MultiScrBlt = MultiScrBlt;
+ rdp->update->primary->MultiOpaqueRect = MultiOpaqueRect;
+ rdp->update->primary->MultiDrawNineGrid = MultiDrawNineGrid;
+ rdp->update->primary->LineTo = LineTo;
+ rdp->update->primary->Polyline = Polyline;
+ rdp->update->primary->MemBlt = MemBlt;
+ rdp->update->primary->Mem3Blt = Mem3Blt;
+ rdp->update->primary->SaveBitmap = SaveBitmap;
+ rdp->update->primary->GlyphIndex = GlyphIndex;
+ rdp->update->primary->FastIndex = FastIndex;
+ rdp->update->primary->FastGlyph = FastGlyph;
+ rdp->update->primary->PolygonSC = PolygonSC;
+ rdp->update->primary->PolygonCB = PolygonCB;
+ rdp->update->primary->EllipseSC = EllipseSC;
+ rdp->update->primary->EllipseCB = EllipseCB;
+}
+
+/* incomming input from client handlers */
+
+static bool
+rdp_backend_handle_input_mouse(ws_input_mouse input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->input;
+ _i->core->reset_idle(_i->task_info);
+ inp->MouseEvent(inp, input.flags, input.x, input.y);
+ return true;
+}
+
+static bool
+rdp_backend_handle_input_kupdown(ws_input_kupdown input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->input;
+ if (0 < input.code)
+ {
+ _i->core->reset_idle(_i->task_info);
+ /*log::info << "257 >> tcode: " << input.code << "\n"; */
+ /* make byte */
+ input.code = RDP_SCANCODE_CODE(input.code);
+ /* apply extended */
+ input.code = ASCII_TO_SCANCODE[input.code];
+ /* extract extended sepparatelly in tflag */
+ uint32_t tflag = RDP_SCANCODE_EXTENDED(input.code) ?
+ KBD_FLAGS_EXTENDED :
+ 0;
+ /* now make the call */
+ freerdp_input_send_keyboard_event(inp,
+ (input.down ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE) | tflag,
+ input.code);
+ }
+ return true;
+}
+
+static bool
+rdp_backend_handle_input_kpress(ws_input_kpress input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->input;
+ _i->core->reset_idle(_i->task_info);
+ if (0x20 < input.code)
+ {
+ if (input.shiftstate & 6)
+ {
+ //Control and or Alt: Must use scan-codes since
+ //unicode-event can't handle these
+ if (((64 < input.code) && (91 > input.code))
+ || ((96 < input.code) && (123 > input.code)))
+ {
+ input.code -= (input.shiftstate & 1) ? 0 : 32;
+ input.code
+ = GetVirtualScanCodeFromVirtualKeyCode(
+ input.code, 4);
+ if (0 < input.code)
+ {
+ freerdp_input_send_unicode_keyboard_event(
+ inp, KBD_FLAGS_DOWN,
+ ASCII_TO_SCANCODE[input.code]);
+ freerdp_input_send_unicode_keyboard_event(
+ inp, KBD_FLAGS_RELEASE,
+ ASCII_TO_SCANCODE[input.code]);
+ }
+ }
+ }
+ else
+ {
+ if (0 < input.code)
+ {
+ if (input.code == 96)
+ {
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_DOWN,
+ RDP_SCANCODE_LCONTROL);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_DOWN, RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_DOWN,
+ RDP_SCANCODE_DELETE);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE,
+ RDP_SCANCODE_LCONTROL);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE,
+ RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE,
+ RDP_SCANCODE_DELETE);
+ }
+
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_DOWN,
+ ASCII_TO_SCANCODE[input.code]);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE,
+ ASCII_TO_SCANCODE[input.code]);
+ }
+ }
+ }
+ else
+ {
+ if (0 < input.code)
+ {
+ input.code = RDP_SCANCODE_CODE(input.code);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, ASCII_TO_SCANCODE[input.code]);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE, ASCII_TO_SCANCODE[input.code]);
+ }
+ }
+ return true;
+}
+
+static bool
+rdp_backend_handle_input_kcomb(ws_input_keycomb input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->input;
+ _i->core->reset_idle(_i->task_info);
+ switch (input)
+ {
+ case ws_keycomb_ctrlaltdel_press:
+ {
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LCONTROL);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, RDP_SCANCODE_DELETE);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LCONTROL);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_DELETE);
+ }
+ break;
+ case ws_keycomb_alttab_press:
+ {
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, RDP_SCANCODE_TAB);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_TAB);
+ }
+ break;
+ case ws_keycomb_alttab_release:
+ {
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LMENU);
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+static bool
+rdp_backend_handle_input_unicode(ws_input_unicode input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->input;
+ int i;
+ _i->core->reset_idle(_i->task_info);
+ for (i = 0; i < input.length; ++i)
+ {
+ freerdp_input_send_unicode_keyboard_event(
+ inp, KBD_FLAGS_DOWN, (UINT16)input.input[i]);
+ freerdp_input_send_unicode_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, (UINT16)input.input[i]);
+ }
+ return true;
+}
+
+void
+register_input(wrdp_backend_module *backend)
+{
+ backend->backend_handle_input_kcomb = rdp_backend_handle_input_kcomb;
+ backend->backend_handle_input_kupdown
+ = rdp_backend_handle_input_kupdown;
+ backend->backend_handle_input_kpress = rdp_backend_handle_input_kpress;
+ backend->backend_handle_input_mouse = rdp_backend_handle_input_mouse;
+ backend->backend_handle_input_unicode
+ = rdp_backend_handle_input_unicode;
+}
+
+static BOOL
+rdp_pre_connect(freerdp *instance)
+{
+ rdpSettings *settings = instance->settings;
+ my_rdp_context *c = (my_rdp_context *)instance->context;
+
+ RegisterUpdate(instance);
+ RegisterPrimary(instance);
+
+ /* looks like this settings reducing artifacts level */
+ settings->OrderSupport[NEG_PATBLT_INDEX] = FALSE;
+ settings->OrderSupport[NEG_SCRBLT_INDEX] = FALSE;
+
+ /* causing random disconnects */
+ settings->OrderSupport[NEG_ATEXTOUT_INDEX] = FALSE;
+ settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
+ settings->NoBitmapCompressionHeader = TRUE;
+ settings->BitmapCompressionDisabled = TRUE;
+ settings->FastPathOutput = FALSE;
+ settings->BitmapCacheEnabled = FALSE;
+ settings->BrushSupportLevel = 0;
+
+ /* causing connection failure on recent versions of freerdp */
+ settings->OffscreenSupportLevel = 0;
+ settings->OffscreenCacheSize = 0;
+
+ /* following required at least on windows 7 */
+ settings->OrderSupport[NEG_MEMBLT_INDEX] = FALSE;
+ settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE;
+
+ instance->context->cache = cache_new(settings);
+
+ c->my_internals->clrconv
+ = freerdp_clrconv_new(CLRCONV_ALPHA | CLRCONV_INVERT);
+
+ if (!instance->context->cache)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL
+rdp_post_connect(freerdp *instance)
+{
+ my_rdp_context *c = (my_rdp_context *)instance->context;
+ c->my_internals->conn_state = rdp_conn_state_connected;
+ rdpPointer p;
+ memset(&p, 0, sizeof(p));
+ p.size = sizeof(my_rdp_pointer);
+ register_pointer(&p);
+ graphics_register_pointer(instance->context->graphics, &p);
+ pointer_cache_register_callbacks(instance->update);
+
+ c->my_internals->core->send_text_msg(
+ "C:RDP session connection started.", c->my_internals->task_info);
+
+ instance->update->DesktopResize(instance->context);
+
+ return TRUE;
+}
+
+static DWORD
+rdp_verify_certificate(freerdp *instance, const char *common_name,
+ const char *subject, const char *issuer, const char *fingerprint,
+ BOOL host_mismatch)
+{
+ WLog_INFO(TAG, "Certificate details:");
+ WLog_INFO(TAG, "\tSubject: %s", subject);
+ WLog_INFO(TAG, "\tIssuer: %s", issuer);
+ WLog_INFO(TAG, "\tThumbprint: %s", fingerprint);
+ WLog_INFO(TAG,
+ "The above X.509 certificate could not be verified, possibly "
+ "because you do not have "
+ "the CA certificate in your certificate store, or the "
+ "certificate has expired. "
+ "Please look at the OpenSSL documentation on how to add a "
+ "private CA to the store.");
+
+ return TRUE; /* ?? */
+}
+
+/*static int
+rdp_receive_channel_data (freerdp* instance,
+ UINT16 channelId,
+ BYTE* data,
+ int size,
+ int flags,
+ int total_size)
+{
+ return freerdp_channels_data (
+ instance, channelId, data, size, flags, total_size);
+}*/
+
+void
+rdp_register_base(freerdp *r)
+{
+ r->PreConnect = rdp_pre_connect;
+ r->PostConnect = rdp_post_connect;
+ r->VerifyCertificate = rdp_verify_certificate;
+ // r->ReceiveChannelData = rdp_receive_channel_data;
+ r->ContextNew = rdp_context_new;
+ r->ContextFree = rdp_context_free;
+}
diff --git a/src/rdp/rdp_module.c b/src/rdp/rdp_module.c
new file mode 100644
index 0000000..a315325
--- /dev/null
+++ b/src/rdp/rdp_module.c
@@ -0,0 +1,168 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include <unistd.h>
+
+#include <freerdp/freerdp.h>
+#include <freerdp/gdi/gdi.h>
+
+#include <webrdp_core_api.h>
+#include <webrdp_module_api.h>
+
+#include "rdp_backend_api.h"
+#include "rdp_impl.h"
+#include "rdp_display_output.h"
+#include "rdp_user_input.h"
+#include "rdp_clipboard.h"
+#include "rdp_ft.h"
+#include "rdp_module.h"
+#include "rdp_settings.h"
+
+/* static void
+send_termination_message (rdp_internals* i)
+{
+ i->core->send_termination_msg (i->task_info);
+} */
+
+static bool
+rdp_init(void *internals)
+{
+ bool ret = true;
+ if (!rdp_init_internals(internals))
+ {
+ /* TODO: handle error */
+ return false;
+ }
+ if (!((rdp_internals *)internals)->instance)
+ {
+ /* TODO: handle error */
+ ret = false;
+ }
+ if (!rdp_init_settings(internals))
+ {
+ /* TODO: handle error */
+ ret = false;
+ }
+ if (!rdp_connect(internals))
+ {
+ /* TODO: handle error */
+ ret = false;
+ }
+ if (!ret)
+ {
+ rdp_internals *i = internals;
+ i->core->api_msgs->send_error_msg(
+ "rdp_module_internal_error", i->task_info);
+ /*send_termination_message (i);*/
+ i->core->api_core->task_finished(false, i->task_info);
+ }
+ return ret;
+}
+
+static void
+destroy_rdp(void *internals)
+{
+ rdp_internals *_i = internals;
+ /* stop all rdp fd's watchers */
+ int i;
+ for (i = 0; i < _i->rdp_fd_count; ++i)
+ {
+ if (ev_is_active(&(_i->rdp_fd[i])))
+ {
+ ev_io_stop(
+ _i->core->api_core->get_libev_loop(_i->task_info),
+ &(_i->rdp_fd[i]));
+ }
+ }
+ if (_i->conn_state == rdp_conn_state_connected)
+ {
+ freerdp_disconnect(_i->instance);
+ _i->conn_state = rdp_conn_state_offline;
+ }
+ _i->rdp_fd_count = 0;
+ if (_i->context)
+ {
+ if (_i->context->clipboard && _i->context->clipboard->srv_fmts
+ && _i->context->clipboard->srv_fmts_count)
+ {
+ for (i = 0; i < _i->context->clipboard->srv_fmts_count;
+ ++i)
+ {
+ if (_i->context->clipboard->srv_fmts[i]
+ .rdp_fmt.formatName)
+ {
+ free(_i->context->clipboard->srv_fmts[i]
+ .rdp_fmt.formatName);
+ }
+ }
+ free(_i->context->clipboard->srv_fmts);
+ }
+ if (_i->context->clipboard && _i->context->clipboard->clipboard)
+ {
+ ClipboardDestroy(_i->context->clipboard->clipboard);
+ }
+ if (_i->context->clipboard
+ && _i->context->clipboard->client_filelist_cache)
+ {
+ free(_i->context->clipboard->client_filelist_cache);
+ _i->context->clipboard->client_filelist_cache = 0;
+ }
+ free(_i->context->ft_to_client);
+ free(_i->context->ft_to_server);
+ }
+ if (_i->instance)
+ {
+ freerdp_context_free(_i->instance);
+ freerdp_free(_i->instance);
+ _i->instance = 0;
+ }
+ if (internals)
+ {
+ rdp_settings_free(internals);
+ internals = 0;
+ }
+}
+
+static void
+rdp_set_task_info(void *task_info, void *internals)
+{
+ rdp_internals *i = internals;
+ i->task_info = task_info;
+}
+
+bool
+rdp_create(wrdp_core_exports *core, wrdp_backend_module *module)
+{
+ wrdp_backend_module *backend = module;
+ if (!backend)
+ {
+ return false;
+ }
+ backend->callbacks_module->init = rdp_init;
+ backend->callbacks_module->destroy = destroy_rdp;
+ backend->callbacks_module->set_setting_int = rdp_set_setting_int;
+ backend->callbacks_module->set_setting_str = rdp_set_setting_str;
+ backend->callbacks_module->set_task_info = rdp_set_task_info;
+ register_input(backend);
+ register_clipboard(backend);
+ register_ft(backend);
+ backend->backend_internals = calloc(1, sizeof(rdp_internals));
+ if (!backend->backend_internals)
+ {
+ perror("calloc");
+ return false;
+ }
+ memset(&(((rdp_internals *)backend->backend_internals)->my_settings), 0,
+ sizeof(my_rdp_settings));
+ /* TODO: do we need to zero each option structure in settings ? */
+ {
+ rdp_internals *i = backend->backend_internals;
+ i->core = core;
+ i->backend = backend;
+ }
+
+ return true;
+}
diff --git a/src/rdp/rdp_module.h b/src/rdp/rdp_module.h
new file mode 100644
index 0000000..59842d3
--- /dev/null
+++ b/src/rdp/rdp_module.h
@@ -0,0 +1,7 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once \ No newline at end of file
diff --git a/src/rdp/rdp_png.c b/src/rdp/rdp_png.c
new file mode 100644
index 0000000..09f01a2
--- /dev/null
+++ b/src/rdp/rdp_png.c
@@ -0,0 +1,89 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include "rdp_png.h"
+#include <stdlib.h>
+#include <string.h>
+
+static void
+cbPngError(png_structp png, png_const_charp msg)
+{
+ printf("Png error: %s\n", (msg ? msg : "unknown error"));
+}
+
+static void
+cbPngWarn(png_structp png, png_const_charp msg)
+{
+ printf("Png warning: %s\n", (msg ? msg : "unknown error"));
+}
+
+static void
+cbPngWrite(png_structp png, png_bytep data, png_size_t len)
+{
+ rdp_png_buf *out_buf = (rdp_png_buf *)png_get_io_ptr(png);
+ uint8_t *ptr = out_buf->buf;
+ if (out_buf->written + len > out_buf->buf_size)
+ {
+ printf("error: rdp_png_buf is too small\n");
+ return;
+ }
+ ptr += out_buf->written;
+ memcpy(ptr, data, len);
+ out_buf->written += len;
+}
+
+static void
+cbPngFlush(png_structp png)
+{
+}
+
+bool
+png_generate_from_argb(
+ int width, int height, uint8_t *data, rdp_png_buf *out_buf)
+{
+ png_infop info_ptr;
+ png_structp png_ptr = png_create_write_struct(
+ PNG_LIBPNG_VER_STRING, 0, cbPngError, cbPngWarn);
+ if (!png_ptr)
+ {
+ printf("Could not allocate png_struct\n");
+ return false;
+ }
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ printf("Could not allocate png_info_struct\n");
+ return false;
+ }
+ png_set_write_fn(png_ptr, out_buf, cbPngWrite, cbPngFlush);
+ png_set_IHDR(png_ptr, info_ptr, width, height, 8,
+ PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ png_bytep *rows = malloc(sizeof(png_bytep) * height);
+ if (!rows)
+ {
+ perror("malloc");
+ return false;
+ }
+ for (int i = 0; i < height; ++i)
+ {
+ rows[i] = (png_bytep)data;
+ data += width * 4;
+ }
+ png_set_rows(png_ptr, info_ptr, rows);
+ png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+
+ free(rows);
+
+ return true;
+}
+
+void
+png_destroy(png_structp *p, png_infop *i)
+{
+ png_destroy_write_struct(p, i);
+}
diff --git a/src/rdp/rdp_png.h b/src/rdp/rdp_png.h
new file mode 100644
index 0000000..a3a3bfc
--- /dev/null
+++ b/src/rdp/rdp_png.h
@@ -0,0 +1,22 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+#include <png.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef struct
+{
+ uint8_t *buf;
+ size_t buf_size, written;
+} rdp_png_buf;
+
+void png_destroy(png_structp *p, png_infop *i);
+
+bool png_generate_from_argb(
+ int width, int height, uint8_t *data, rdp_png_buf *out_buf);
diff --git a/src/rdp/rdp_rail.c b/src/rdp/rdp_rail.c
new file mode 100644
index 0000000..bde1950
--- /dev/null
+++ b/src/rdp/rdp_rail.c
@@ -0,0 +1,173 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "webrdp_core_api.h"
+#include "webrdp_module_api.h"
+#include "rdp_backend_api.h"
+#include "rdp_rail.h"
+
+static UINT
+RailServerSystemParam(
+ RailClientContext *context, const RAIL_SYSPARAM_ORDER *sysparam)
+{
+ return CHANNEL_RC_OK;
+}
+
+static UINT
+RailServerHandshake(
+ RailClientContext *context, const RAIL_HANDSHAKE_ORDER *handshake)
+{
+ return client_rail_server_start_cmd(context);
+}
+
+static UINT
+RailServerHandshakeEx(
+ RailClientContext *context, const RAIL_HANDSHAKE_EX_ORDER *handshakeEx)
+{
+ return client_rail_server_start_cmd(context);
+}
+
+static UINT
+RailServerLocalMoveSize(
+ RailClientContext *context, const RAIL_LOCALMOVESIZE_ORDER *localMoveSize)
+{
+ return CHANNEL_RC_OK;
+}
+static UINT
+RailServerMinMaxInfo(
+ RailClientContext *context, const RAIL_MINMAXINFO_ORDER *minMaxInfo)
+{
+ return CHANNEL_RC_OK;
+}
+
+static UINT
+RailServerLanguageBarInfo(
+ RailClientContext *context, const RAIL_LANGBAR_INFO_ORDER *langBarInfo)
+{
+ return CHANNEL_RC_OK;
+}
+static UINT
+RailServerExecuteResult(
+ RailClientContext *context, const RAIL_EXEC_RESULT_ORDER *execResult)
+{
+ my_rdp_context *c = (my_rdp_context *)context;
+ if (execResult->execResult != RAIL_EXEC_S_OK)
+ {
+ const char *msg
+ = "rdp_module: rail: RailServerExecuteResult failure";
+ c->my_internals->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ }
+ return CHANNEL_RC_OK;
+}
+
+static UINT
+RailServerGetAppIdResponse(
+ RailClientContext *context, const RAIL_GET_APPID_RESP_ORDER *getAppIdResp)
+{
+ return CHANNEL_RC_OK;
+}
+
+static BOOL
+WindowCreate(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo,
+ const WINDOW_STATE_ORDER *window_state)
+{
+ return TRUE;
+}
+static BOOL
+WindowUpdate(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo,
+ const WINDOW_STATE_ORDER *window_state)
+{
+ return TRUE;
+}
+static BOOL
+WindowIcon(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo,
+ const WINDOW_ICON_ORDER *window_icon)
+{
+ return TRUE;
+}
+static BOOL
+WindowCachedIcon(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo,
+ const WINDOW_CACHED_ICON_ORDER *window_cached_icon)
+{
+ return TRUE;
+}
+static BOOL
+WindowDelete(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo)
+{
+ return TRUE;
+}
+static BOOL
+NotifyIconCreate(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo,
+ const NOTIFY_ICON_STATE_ORDER *notify_icon_state)
+{
+ return TRUE;
+}
+static BOOL
+NotifyIconUpdate(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo,
+ const NOTIFY_ICON_STATE_ORDER *notify_icon_state)
+{
+ return TRUE;
+}
+static BOOL
+NotifyIconDelete(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo)
+{
+ return TRUE;
+}
+static BOOL
+MonitoredDesktop(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo,
+ const MONITORED_DESKTOP_ORDER *monitored_desktop)
+{
+ return TRUE;
+}
+static BOOL
+NonMonitoredDesktop(rdpContext *context, const WINDOW_ORDER_INFO *orderInfo)
+{
+ return TRUE;
+}
+
+static void
+rdp_rail_register_update_callbacks(rdpUpdate *update)
+{
+ rdpWindowUpdate *window = update->window;
+ window->WindowCreate = WindowCreate;
+ window->WindowUpdate = WindowUpdate;
+ window->WindowDelete = WindowDelete;
+ window->WindowIcon = WindowIcon;
+ window->WindowCachedIcon = WindowCachedIcon;
+ window->NotifyIconCreate = NotifyIconCreate;
+ window->NotifyIconUpdate = NotifyIconUpdate;
+ window->NotifyIconDelete = NotifyIconDelete;
+ window->MonitoredDesktop = MonitoredDesktop;
+ window->NonMonitoredDesktop = NonMonitoredDesktop;
+}
+
+void
+rdp_rail_init(my_rdp_context *context, RailClientContext *rail)
+{
+ if (!context || !rail)
+ return;
+
+ rdp_rail_register_update_callbacks(context->context.update);
+ rail->custom = (void *)context;
+ rail->ServerExecuteResult = RailServerExecuteResult;
+ rail->ServerSystemParam = RailServerSystemParam;
+ rail->ServerHandshake = RailServerHandshake;
+ rail->ServerHandshakeEx = RailServerHandshakeEx;
+ rail->ServerLocalMoveSize = RailServerLocalMoveSize;
+ rail->ServerMinMaxInfo = RailServerMinMaxInfo;
+ rail->ServerLanguageBarInfo = RailServerLanguageBarInfo;
+ rail->ServerGetAppIdResponse = RailServerGetAppIdResponse;
+}
+
+void
+rdp_rail_uninit(my_rdp_context *context, RailClientContext *rail)
+{
+}
diff --git a/src/rdp/rdp_rail.h b/src/rdp/rdp_rail.h
new file mode 100644
index 0000000..0d3d7ba
--- /dev/null
+++ b/src/rdp/rdp_rail.h
@@ -0,0 +1,14 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+#include "rdp_channels.h"
+#include "rdp_impl.h"
+
+void rdp_rail_init(my_rdp_context *context, RailClientContext *rail);
+
+void rdp_rail_uninit(my_rdp_context *context, RailClientContext *rail);
diff --git a/src/rdp/rdp_settings.c b/src/rdp/rdp_settings.c
new file mode 100644
index 0000000..ecb1dcc
--- /dev/null
+++ b/src/rdp/rdp_settings.c
@@ -0,0 +1,2278 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <webrdp_module_api.h>
+#include <webrdp_core_api.h>
+
+#include "rdp_backend_api.h"
+#include "rdp_impl.h"
+
+/* this variable used in integer settng name field to indicate used setting */
+static const char *setting_used = "1";
+
+bool
+rdp_set_setting_str(backend_setting_str *setting, void *internals)
+{
+ rdp_internals *i = internals;
+#ifdef DEBUG
+ {
+ char buf[128];
+ snprintf(buf, 127,
+ "rdp backend handling setting string: \"%s: %s\"",
+ setting->name, setting->value);
+ i->core->api_utils->log_msg(
+ (const uint8_t *)buf, strlen(buf), wrdp_log_level_trace, 0);
+ }
+#endif /* DEBUG */
+ if (!strcmp(setting->name, "host"))
+ {
+ free(i->my_settings.host.value);
+ i->my_settings.host.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "pcb"))
+ {
+ /*
+ free (i->my_settings.pcb.value);
+ i->my_settings.pcb.value = strdup (setting->value); */
+ return true;
+ }
+ else if (!strcmp(setting->name, "user") && setting->value)
+ {
+ free(i->my_settings.user.value);
+ i->my_settings.user.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "password") && setting->value)
+ {
+ free(i->my_settings.password.value);
+ i->my_settings.password.value = strdup(setting->value);
+ return true;
+ }
+
+ /* handle int settings passed as strings */
+ if (!strcmp(setting->name, "port"))
+ {
+ i->my_settings.port.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.port.value = atoll(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "width"))
+ {
+ i->my_settings.width.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.width.value = atoll(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "height"))
+ {
+ i->my_settings.height.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.height.value = atoll(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "perf"))
+ {
+ i->my_settings.perf.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.perf.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "fntlm"))
+ {
+ i->my_settings.fntlm.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.fntlm.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "nowallp"))
+ {
+ i->my_settings.nowallp.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.nowallp.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "nowdrag"))
+ {
+ i->my_settings.nowdrag.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.nowdrag.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "nomani"))
+ {
+ i->my_settings.nomani.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.nomani.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "notheme"))
+ {
+ i->my_settings.notheme.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.notheme.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "nonla"))
+ {
+ i->my_settings.nonla.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.nonla.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "notls"))
+ {
+ i->my_settings.notls.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.notls.value = atoi(setting->value);
+ }
+ return true;
+ }
+
+ /*new settings from freerdp header (strings) begin */
+ else if (!strcmp(setting->name, "Domain") && setting->value)
+ {
+ free(i->my_settings.Domain.value);
+ i->my_settings.Domain.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "PasswordHash") && setting->value)
+ {
+ free(i->my_settings.PasswordHash.value);
+ i->my_settings.PasswordHash.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "AcceptedCert") && setting->value)
+ {
+ free(i->my_settings.AcceptedCert.value);
+ i->my_settings.AcceptedCert.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ClientHostname") && setting->value)
+ {
+ free(i->my_settings.ClientHostname.value);
+ i->my_settings.ClientHostname.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ClientProductId") && setting->value)
+ {
+ free(i->my_settings.ClientProductId.value);
+ i->my_settings.ClientProductId.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "AlternateShell") && setting->value)
+ {
+ free(i->my_settings.AlternateShell.value);
+ i->my_settings.AlternateShell.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ShellWorkingDirectory")
+ && setting->value)
+ {
+ free(i->my_settings.ShellWorkingDirectory.value);
+ i->my_settings.ShellWorkingDirectory.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ClientAddress") && setting->value)
+ {
+ free(i->my_settings.ClientAddress.value);
+ i->my_settings.ClientAddress.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ClientDir") && setting->value)
+ {
+ free(i->my_settings.ClientDir.value);
+ i->my_settings.ClientDir.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "DynamicDSTTimeZoneKeyName")
+ && setting->value)
+ {
+ free(i->my_settings.DynamicDSTTimeZoneKeyName.value);
+ i->my_settings.DynamicDSTTimeZoneKeyName.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteAssistanceSessionId")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteAssistanceSessionId.value);
+ i->my_settings.RemoteAssistanceSessionId.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteAssistancePassStub")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteAssistancePassStub.value);
+ i->my_settings.RemoteAssistancePassStub.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteAssistancePassword")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteAssistancePassword.value);
+ i->my_settings.RemoteAssistancePassword.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteAssistanceRCTicket")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteAssistanceRCTicket.value);
+ i->my_settings.RemoteAssistanceRCTicket.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "AuthenticationServiceClass")
+ && setting->value)
+ {
+ free(i->my_settings.AuthenticationServiceClass.value);
+ i->my_settings.AuthenticationServiceClass.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "AllowedTlsCiphers") && setting->value)
+ {
+ free(i->my_settings.AllowedTlsCiphers.value);
+ i->my_settings.AllowedTlsCiphers.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "NtlmSamFile") && setting->value)
+ {
+ free(i->my_settings.NtlmSamFile.value);
+ i->my_settings.NtlmSamFile.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "PreconnectionBlob") && setting->value)
+ {
+ free(i->my_settings.PreconnectionBlob.value);
+ i->my_settings.PreconnectionBlob.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RedirectionAcceptedCert")
+ && setting->value)
+ {
+ free(i->my_settings.RedirectionAcceptedCert.value);
+ i->my_settings.RedirectionAcceptedCert.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "KerberosKdc") && setting->value)
+ {
+ free(i->my_settings.KerberosKdc.value);
+ i->my_settings.KerberosKdc.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "KerberosRealm") && setting->value)
+ {
+ free(i->my_settings.KerberosRealm.value);
+ i->my_settings.KerberosRealm.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "CertificateName") && setting->value)
+ {
+ free(i->my_settings.CertificateName.value);
+ i->my_settings.CertificateName.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "CertificateFile") && setting->value)
+ {
+ free(i->my_settings.CertificateFile.value);
+ i->my_settings.CertificateFile.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "PrivateKeyFile") && setting->value)
+ {
+ free(i->my_settings.PrivateKeyFile.value);
+ i->my_settings.PrivateKeyFile.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "CertificateContent") && setting->value)
+ {
+ free(i->my_settings.CertificateContent.value);
+ i->my_settings.CertificateContent.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "PrivateKeyContent") && setting->value)
+ {
+ free(i->my_settings.PrivateKeyContent.value);
+ i->my_settings.PrivateKeyContent.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "WindowTitle") && setting->value)
+ {
+ free(i->my_settings.WindowTitle.value);
+ i->my_settings.WindowTitle.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "WmClass") && setting->value)
+ {
+ free(i->my_settings.WmClass.value);
+ i->my_settings.WmClass.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ComputerName") && setting->value)
+ {
+ free(i->my_settings.ComputerName.value);
+ i->my_settings.ComputerName.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ConnectionFile") && setting->value)
+ {
+ free(i->my_settings.ConnectionFile.value);
+ i->my_settings.ConnectionFile.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "AssistanceFile") && setting->value)
+ {
+ free(i->my_settings.AssistanceFile.value);
+ i->my_settings.AssistanceFile.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "HomePath") && setting->value)
+ {
+ free(i->my_settings.HomePath.value);
+ i->my_settings.HomePath.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ConfigPath") && setting->value)
+ {
+ free(i->my_settings.ConfigPath.value);
+ i->my_settings.ConfigPath.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "CurrentPath") && setting->value)
+ {
+ free(i->my_settings.CurrentPath.value);
+ i->my_settings.CurrentPath.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "DumpRemoteFxFile") && setting->value)
+ {
+ free(i->my_settings.DumpRemoteFxFile.value);
+ i->my_settings.DumpRemoteFxFile.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "PlayRemoteFxFile") && setting->value)
+ {
+ free(i->my_settings.PlayRemoteFxFile.value);
+ i->my_settings.PlayRemoteFxFile.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "GatewayHostname") && setting->value)
+ {
+ free(i->my_settings.GatewayHostname.value);
+ i->my_settings.GatewayHostname.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "GatewayUsername") && setting->value)
+ {
+ free(i->my_settings.GatewayUsername.value);
+ i->my_settings.GatewayUsername.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "GatewayPassword") && setting->value)
+ {
+ free(i->my_settings.GatewayPassword.value);
+ i->my_settings.GatewayPassword.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "GatewayDomain") && setting->value)
+ {
+ free(i->my_settings.GatewayDomain.value);
+ i->my_settings.GatewayDomain.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "GatewayAccessToken") && setting->value)
+ {
+ free(i->my_settings.GatewayAccessToken.value);
+ i->my_settings.GatewayAccessToken.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "GatewayAcceptedCert")
+ && setting->value)
+ {
+ free(i->my_settings.GatewayAcceptedCert.value);
+ i->my_settings.GatewayAcceptedCert.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ProxyHostname") && setting->value)
+ {
+ free(i->my_settings.ProxyHostname.value);
+ i->my_settings.ProxyHostname.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteApplicationName")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteApplicationName.value);
+ i->my_settings.RemoteApplicationName.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteApplicationIcon")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteApplicationIcon.value);
+ i->my_settings.RemoteApplicationIcon.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteApplicationProgram")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteApplicationProgram.value);
+ i->my_settings.RemoteApplicationProgram.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteApplicationFile")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteApplicationFile.value);
+ i->my_settings.RemoteApplicationFile.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteApplicationGuid")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteApplicationGuid.value);
+ i->my_settings.RemoteApplicationGuid.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteApplicationCmdLine")
+ && setting->value)
+ {
+ free(i->my_settings.RemoteApplicationCmdLine.value);
+ i->my_settings.RemoteApplicationCmdLine.value
+ = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ImeFileName") && setting->value)
+ {
+ free(i->my_settings.ImeFileName.value);
+ i->my_settings.ImeFileName.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "DrivesToRedirect") && setting->value)
+ {
+ free(i->my_settings.DrivesToRedirect.value);
+ i->my_settings.DrivesToRedirect.value = strdup(setting->value);
+ return true;
+ }
+ else if (!strcmp(setting->name, "ActionScript") && setting->value)
+ {
+ free(i->my_settings.ActionScript.value);
+ i->my_settings.ActionScript.value = strdup(setting->value);
+ return true;
+ }
+ /*new settings from freerdp header (strings) end */
+
+ /* TODO: handle also integer settings passed as strings */
+
+ /* new settings from freerdp header (integers as string) begin */
+
+ else if (!strcmp(setting->name, "ServerMode"))
+ {
+ i->my_settings.ServerMode.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.ServerMode.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "WaitForOutputBufferFlush"))
+ {
+ i->my_settings.WaitForOutputBufferFlush.name
+ = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.WaitForOutputBufferFlush.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "MaxTimeInCheckLoop"))
+ {
+ i->my_settings.MaxTimeInCheckLoop.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.MaxTimeInCheckLoop.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopWidth"))
+ {
+ i->my_settings.DesktopWidth.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.DesktopWidth.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopHeight"))
+ {
+ i->my_settings.DesktopHeight.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.DesktopHeight.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "Workarea"))
+ {
+ i->my_settings.Workarea.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.Workarea.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "Fullscreen"))
+ {
+ i->my_settings.Fullscreen.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.Fullscreen.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "GrabKeyboard"))
+ {
+ i->my_settings.GrabKeyboard.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.GrabKeyboard.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "Decorations"))
+ {
+ i->my_settings.Decorations.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.Decorations.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "RdpVersion"))
+ {
+ i->my_settings.RdpVersion.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.RdpVersion.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "ColorDepth"))
+ {
+ i->my_settings.ColorDepth.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.ColorDepth.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "ExtSecurity"))
+ {
+ i->my_settings.ExtSecurity.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.ExtSecurity.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "NlaSecurity"))
+ {
+ i->my_settings.NlaSecurity.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.NlaSecurity.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "TlsSecurity"))
+ {
+ i->my_settings.TlsSecurity.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.TlsSecurity.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "RdpSecurity"))
+ {
+ i->my_settings.RdpSecurity.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.RdpSecurity.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "NegotiateSecurityLayer"))
+ {
+ i->my_settings.NegotiateSecurityLayer.name
+ = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.NegotiateSecurityLayer.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "RestrictedAdminModeRequired"))
+ {
+ i->my_settings.RestrictedAdminModeRequired.name
+ = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.RestrictedAdminModeRequired.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "MstscCookieMode"))
+ {
+ i->my_settings.MstscCookieMode.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.MstscCookieMode.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "CookieMaxLength"))
+ {
+ i->my_settings.CookieMaxLength.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.CookieMaxLength.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "ClientBuild"))
+ {
+ i->my_settings.ClientBuild.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.ClientBuild.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "KeyboardType"))
+ {
+ i->my_settings.KeyboardType.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.KeyboardType.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "KeyboardSubType"))
+ {
+ i->my_settings.KeyboardSubType.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.KeyboardSubType.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "KeyboardFunctionKey"))
+ {
+ i->my_settings.KeyboardFunctionKey.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.KeyboardFunctionKey.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "KeyboardLayout"))
+ {
+ i->my_settings.KeyboardLayout.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.KeyboardLayout.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "UseRdpSecurityLayer"))
+ {
+ i->my_settings.UseRdpSecurityLayer.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.UseRdpSecurityLayer.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "SaltedChecksum"))
+ {
+ i->my_settings.SaltedChecksum.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.SaltedChecksum.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "ServerPort"))
+ {
+ i->my_settings.ServerPort.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.ServerPort.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "GatewayPort"))
+ {
+ i->my_settings.GatewayPort.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.GatewayPort.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopResize"))
+ {
+ i->my_settings.DesktopResize.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.DesktopResize.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "ToggleFullscreen"))
+ {
+ i->my_settings.ToggleFullscreen.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.ToggleFullscreen.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "Floatbar"))
+ {
+ i->my_settings.Floatbar.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.Floatbar.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopPosX"))
+ {
+ i->my_settings.DesktopPosX.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.DesktopPosX.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopPosY"))
+ {
+ i->my_settings.DesktopPosY.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.DesktopPosY.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "SoftwareGdi"))
+ {
+ i->my_settings.SoftwareGdi.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.SoftwareGdi.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "UnmapButtons"))
+ {
+ i->my_settings.UnmapButtons.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.UnmapButtons.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "PerformanceFlags"))
+ {
+ i->my_settings.PerformanceFlags.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.PerformanceFlags.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "AllowFontSmoothing"))
+ {
+ i->my_settings.AllowFontSmoothing.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.AllowFontSmoothing.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "AllowDesktopComposition"))
+ {
+ i->my_settings.AllowDesktopComposition.name
+ = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.AllowDesktopComposition.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "DisableWallpaper"))
+ {
+ i->my_settings.DisableWallpaper.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.DisableWallpaper.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "DisableFullWindowDrag"))
+ {
+ i->my_settings.DisableFullWindowDrag.name
+ = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.DisableFullWindowDrag.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "DisableMenuAnims"))
+ {
+ i->my_settings.DisableMenuAnims.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.DisableMenuAnims.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "DisableThemes"))
+ {
+ i->my_settings.DisableThemes.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.DisableThemes.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "ConnectionType"))
+ {
+ i->my_settings.ConnectionType.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.ConnectionType.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "EncryptionMethods"))
+ {
+ i->my_settings.EncryptionMethods.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.EncryptionMethods.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "EncryptionLevel"))
+ {
+ i->my_settings.EncryptionLevel.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.EncryptionLevel.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "FIPSMode"))
+ {
+ i->my_settings.FIPSMode.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.FIPSMode.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "CompressionEnabled"))
+ {
+ i->my_settings.CompressionEnabled.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.CompressionEnabled.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "LogonNotify"))
+ {
+ i->my_settings.LogonNotify.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.LogonNotify.value = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "BrushSupportLevel"))
+ {
+ i->my_settings.BrushSupportLevel.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.BrushSupportLevel.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteApplicationMode"))
+ {
+ i->my_settings.RemoteApplicationMode.name
+ = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.RemoteApplicationMode.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ else if (!strcmp(setting->name, "TcpAckTimeout"))
+ {
+ i->my_settings.TcpAckTimeout.name = (char *)setting_used;
+ if (setting->value)
+ {
+ i->my_settings.TcpAckTimeout.value
+ = atoi(setting->value);
+ }
+ return true;
+ }
+ /* new settings from freerdp header (integers as string) end */
+
+ /* error: unhandled setting */
+ {
+ char buf[128];
+ snprintf(buf, 127, "rdp_module: unknown setting string: %s",
+ setting->name);
+ i->core->api_utils->log_msg((const uint8_t *)buf, strlen(buf),
+ wrdp_log_level_warning, 0);
+ }
+ return false;
+}
+
+bool
+rdp_set_setting_int(backend_setting_int *setting, void *internals)
+{
+ rdp_internals *i = internals;
+#ifdef DEBUG
+ {
+ char buf[128];
+ snprintf(buf, 127,
+ "rdp backend handling setting int: \"%s: %ld\"",
+ setting->name, setting->value);
+ i->core->api_utils->log_msg(
+ (const uint8_t *)buf, strlen(buf), wrdp_log_level_trace, 0);
+ }
+#endif
+ if (!strcmp(setting->name, "port"))
+ {
+ i->my_settings.port.name = (char *)setting_used;
+ i->my_settings.port.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "width"))
+ {
+ i->my_settings.width.name = (char *)setting_used;
+ i->my_settings.width.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "height"))
+ {
+ i->my_settings.height.name = (char *)setting_used;
+ i->my_settings.height.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "perf"))
+ {
+ i->my_settings.perf.name = (char *)setting_used;
+ i->my_settings.perf.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "fntlm"))
+ {
+ i->my_settings.fntlm.name = (char *)setting_used;
+ i->my_settings.fntlm.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "nowallp"))
+ {
+ i->my_settings.nowallp.name = (char *)setting_used;
+ i->my_settings.nowallp.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "nowdrag"))
+ {
+ i->my_settings.nowdrag.name = (char *)setting_used;
+ i->my_settings.nowdrag.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "nomani"))
+ {
+ i->my_settings.nomani.name = (char *)setting_used;
+ i->my_settings.nomani.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "notheme"))
+ {
+ i->my_settings.notheme.name = (char *)setting_used;
+ i->my_settings.notheme.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "nonla"))
+ {
+ i->my_settings.nonla.name = (char *)setting_used;
+ i->my_settings.nonla.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "notls"))
+ {
+ i->my_settings.notls.name = (char *)setting_used;
+ i->my_settings.notls.value = setting->value;
+ return true;
+ }
+
+ /* new settings from freerdp header (integers) begin */
+ else if (!strcmp(setting->name, "ServerMode"))
+ {
+ i->my_settings.ServerMode.name = (char *)setting_used;
+ i->my_settings.ServerMode.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "WaitForOutputBufferFlush"))
+ {
+ i->my_settings.WaitForOutputBufferFlush.name
+ = (char *)setting_used;
+ i->my_settings.WaitForOutputBufferFlush.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "MaxTimeInCheckLoop"))
+ {
+ i->my_settings.MaxTimeInCheckLoop.name = (char *)setting_used;
+ i->my_settings.MaxTimeInCheckLoop.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopWidth"))
+ {
+ i->my_settings.DesktopWidth.name = (char *)setting_used;
+ i->my_settings.DesktopWidth.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopHeight"))
+ {
+ i->my_settings.DesktopHeight.name = (char *)setting_used;
+ i->my_settings.DesktopHeight.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "Workarea"))
+ {
+ i->my_settings.Workarea.name = (char *)setting_used;
+ i->my_settings.Workarea.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "Fullscreen"))
+ {
+ i->my_settings.Fullscreen.name = (char *)setting_used;
+ i->my_settings.Fullscreen.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "GrabKeyboard"))
+ {
+ i->my_settings.GrabKeyboard.name = (char *)setting_used;
+ i->my_settings.GrabKeyboard.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "Decorations"))
+ {
+ i->my_settings.Decorations.name = (char *)setting_used;
+ i->my_settings.Decorations.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "RdpVersion"))
+ {
+ i->my_settings.RdpVersion.name = (char *)setting_used;
+ i->my_settings.RdpVersion.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "ColorDepth"))
+ {
+ i->my_settings.ColorDepth.name = (char *)setting_used;
+ i->my_settings.ColorDepth.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "ExtSecurity"))
+ {
+ i->my_settings.ExtSecurity.name = (char *)setting_used;
+ i->my_settings.ExtSecurity.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "NlaSecurity"))
+ {
+ i->my_settings.NlaSecurity.name = (char *)setting_used;
+ i->my_settings.NlaSecurity.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "TlsSecurity"))
+ {
+ i->my_settings.TlsSecurity.name = (char *)setting_used;
+ i->my_settings.TlsSecurity.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "RdpSecurity"))
+ {
+ i->my_settings.RdpSecurity.name = (char *)setting_used;
+ i->my_settings.RdpSecurity.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "NegotiateSecurityLayer"))
+ {
+ i->my_settings.NegotiateSecurityLayer.name
+ = (char *)setting_used;
+ i->my_settings.NegotiateSecurityLayer.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "RestrictedAdminModeRequired"))
+ {
+ i->my_settings.RestrictedAdminModeRequired.name
+ = (char *)setting_used;
+ i->my_settings.RestrictedAdminModeRequired.value
+ = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "MstscCookieMode"))
+ {
+ i->my_settings.MstscCookieMode.name = (char *)setting_used;
+ i->my_settings.MstscCookieMode.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "CookieMaxLength"))
+ {
+ i->my_settings.CookieMaxLength.name = (char *)setting_used;
+ i->my_settings.CookieMaxLength.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "ClientBuild"))
+ {
+ i->my_settings.ClientBuild.name = (char *)setting_used;
+ i->my_settings.ClientBuild.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "KeyboardType"))
+ {
+ i->my_settings.KeyboardType.name = (char *)setting_used;
+ i->my_settings.KeyboardType.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "KeyboardSubType"))
+ {
+ i->my_settings.KeyboardSubType.name = (char *)setting_used;
+ i->my_settings.KeyboardSubType.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "KeyboardFunctionKey"))
+ {
+ i->my_settings.KeyboardFunctionKey.name = (char *)setting_used;
+ i->my_settings.KeyboardFunctionKey.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "KeyboardLayout"))
+ {
+ i->my_settings.KeyboardLayout.name = (char *)setting_used;
+ i->my_settings.KeyboardLayout.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "UseRdpSecurityLayer"))
+ {
+ i->my_settings.UseRdpSecurityLayer.name = (char *)setting_used;
+ i->my_settings.UseRdpSecurityLayer.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "SaltedChecksum"))
+ {
+ i->my_settings.SaltedChecksum.name = (char *)setting_used;
+ i->my_settings.SaltedChecksum.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "ServerPort"))
+ {
+ i->my_settings.ServerPort.name = (char *)setting_used;
+ i->my_settings.ServerPort.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "GatewayPort"))
+ {
+ i->my_settings.GatewayPort.name = (char *)setting_used;
+ i->my_settings.GatewayPort.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopResize"))
+ {
+ i->my_settings.DesktopResize.name = (char *)setting_used;
+ i->my_settings.DesktopResize.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "ToggleFullscreen"))
+ {
+ i->my_settings.ToggleFullscreen.name = (char *)setting_used;
+ i->my_settings.ToggleFullscreen.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "Floatbar"))
+ {
+ i->my_settings.Floatbar.name = (char *)setting_used;
+ i->my_settings.Floatbar.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopPosX"))
+ {
+ i->my_settings.DesktopPosX.name = (char *)setting_used;
+ i->my_settings.DesktopPosX.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "DesktopPosY"))
+ {
+ i->my_settings.DesktopPosY.name = (char *)setting_used;
+ i->my_settings.DesktopPosY.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "SoftwareGdi"))
+ {
+ i->my_settings.SoftwareGdi.name = (char *)setting_used;
+ i->my_settings.SoftwareGdi.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "UnmapButtons"))
+ {
+ i->my_settings.UnmapButtons.name = (char *)setting_used;
+ i->my_settings.UnmapButtons.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "PerformanceFlags"))
+ {
+ i->my_settings.PerformanceFlags.name = (char *)setting_used;
+ i->my_settings.PerformanceFlags.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "AllowFontSmoothing"))
+ {
+ i->my_settings.AllowFontSmoothing.name = (char *)setting_used;
+ i->my_settings.AllowFontSmoothing.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "AllowDesktopComposition"))
+ {
+ i->my_settings.AllowDesktopComposition.name
+ = (char *)setting_used;
+ i->my_settings.AllowDesktopComposition.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "DisableWallpaper"))
+ {
+ i->my_settings.DisableWallpaper.name = (char *)setting_used;
+ i->my_settings.DisableWallpaper.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "DisableFullWindowDrag"))
+ {
+ i->my_settings.DisableFullWindowDrag.name
+ = (char *)setting_used;
+ i->my_settings.DisableFullWindowDrag.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "DisableMenuAnims"))
+ {
+ i->my_settings.DisableMenuAnims.name = (char *)setting_used;
+ i->my_settings.DisableMenuAnims.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "DisableThemes"))
+ {
+ i->my_settings.DisableThemes.name = (char *)setting_used;
+ i->my_settings.DisableThemes.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "ConnectionType"))
+ {
+ i->my_settings.ConnectionType.name = (char *)setting_used;
+ i->my_settings.ConnectionType.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "EncryptionMethods"))
+ {
+ i->my_settings.EncryptionMethods.name = (char *)setting_used;
+ i->my_settings.EncryptionMethods.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "EncryptionLevel"))
+ {
+ i->my_settings.EncryptionLevel.name = (char *)setting_used;
+ i->my_settings.EncryptionLevel.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "FIPSMode"))
+ {
+ i->my_settings.FIPSMode.name = (char *)setting_used;
+ i->my_settings.FIPSMode.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "CompressionEnabled"))
+ {
+ i->my_settings.CompressionEnabled.name = (char *)setting_used;
+ i->my_settings.CompressionEnabled.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "LogonNotify"))
+ {
+ i->my_settings.LogonNotify.name = (char *)setting_used;
+ i->my_settings.LogonNotify.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "BrushSupportLevel"))
+ {
+ i->my_settings.BrushSupportLevel.name = (char *)setting_used;
+ i->my_settings.BrushSupportLevel.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "RemoteApplicationMode"))
+ {
+ i->my_settings.RemoteApplicationMode.name
+ = (char *)setting_used;
+ i->my_settings.RemoteApplicationMode.value = setting->value;
+ return true;
+ }
+ else if (!strcmp(setting->name, "TcpAckTimeout"))
+ {
+ i->my_settings.TcpAckTimeout.name = (char *)setting_used;
+ i->my_settings.TcpAckTimeout.value = setting->value;
+ return true;
+ }
+
+ /* new settings from freerdp header (integers) end */
+
+ /* error: unhandled setting */
+ {
+ char buf[128];
+ snprintf(buf, 127, "rdp_module: unknown setting int: %s",
+ setting->name);
+ i->core->api_utils->log_msg((const uint8_t *)buf, strlen(buf),
+ wrdp_log_level_warning, 0);
+ }
+ return false;
+}
+
+void
+rdp_settings_free(rdp_internals *internals)
+{
+ rdp_internals *i = internals;
+ if (i->my_settings.host.value)
+ {
+ free((void *)i->my_settings.host.value);
+ }
+ if (i->my_settings.pcb.value)
+ {
+ free((void *)i->my_settings.pcb.value);
+ }
+ if (i->my_settings.user.value)
+ {
+ free((void *)i->my_settings.user.value);
+ }
+ if (i->my_settings.password.value)
+ {
+ free((void *)i->my_settings.password.value);
+ }
+ /* new */
+ if (i->my_settings.Domain.value)
+ {
+ free((void *)i->my_settings.Domain.value);
+ }
+ if (i->my_settings.PasswordHash.value)
+ {
+ free((void *)i->my_settings.PasswordHash.value);
+ }
+ if (i->my_settings.AcceptedCert.value)
+ {
+ free((void *)i->my_settings.AcceptedCert.value);
+ }
+ if (i->my_settings.ClientHostname.value)
+ {
+ free((void *)i->my_settings.ClientHostname.value);
+ }
+ if (i->my_settings.ClientProductId.value)
+ {
+ free((void *)i->my_settings.ClientProductId.value);
+ }
+ if (i->my_settings.AlternateShell.value)
+ {
+ free((void *)i->my_settings.AlternateShell.value);
+ }
+ if (i->my_settings.ShellWorkingDirectory.value)
+ {
+ free((void *)i->my_settings.ShellWorkingDirectory.value);
+ }
+ if (i->my_settings.ClientAddress.value)
+ {
+ free((void *)i->my_settings.ClientAddress.value);
+ }
+ if (i->my_settings.ClientDir.value)
+ {
+ free((void *)i->my_settings.ClientDir.value);
+ }
+ if (i->my_settings.DynamicDSTTimeZoneKeyName.value)
+ {
+ free((void *)i->my_settings.DynamicDSTTimeZoneKeyName.value);
+ }
+ if (i->my_settings.RemoteAssistanceSessionId.value)
+ {
+ free((void *)i->my_settings.RemoteAssistanceSessionId.value);
+ }
+ if (i->my_settings.RemoteAssistancePassStub.value)
+ {
+ free((void *)i->my_settings.RemoteAssistancePassStub.value);
+ }
+ if (i->my_settings.RemoteAssistancePassword.value)
+ {
+ free((void *)i->my_settings.RemoteAssistancePassword.value);
+ }
+ if (i->my_settings.RemoteAssistanceRCTicket.value)
+ {
+ free((void *)i->my_settings.RemoteAssistanceRCTicket.value);
+ }
+ if (i->my_settings.AuthenticationServiceClass.value)
+ {
+ free((void *)i->my_settings.AuthenticationServiceClass.value);
+ }
+ if (i->my_settings.AllowedTlsCiphers.value)
+ {
+ free((void *)i->my_settings.AllowedTlsCiphers.value);
+ }
+ if (i->my_settings.NtlmSamFile.value)
+ {
+ free((void *)i->my_settings.NtlmSamFile.value);
+ }
+ if (i->my_settings.PreconnectionBlob.value)
+ {
+ free((void *)i->my_settings.PreconnectionBlob.value);
+ }
+ if (i->my_settings.RedirectionAcceptedCert.value)
+ {
+ free((void *)i->my_settings.RedirectionAcceptedCert.value);
+ }
+ if (i->my_settings.KerberosKdc.value)
+ {
+ free((void *)i->my_settings.KerberosKdc.value);
+ }
+ if (i->my_settings.KerberosRealm.value)
+ {
+ free((void *)i->my_settings.KerberosRealm.value);
+ }
+ if (i->my_settings.CertificateName.value)
+ {
+ free((void *)i->my_settings.CertificateName.value);
+ }
+ if (i->my_settings.CertificateFile.value)
+ {
+ free((void *)i->my_settings.CertificateFile.value);
+ }
+ if (i->my_settings.PrivateKeyFile.value)
+ {
+ free((void *)i->my_settings.PrivateKeyFile.value);
+ }
+ if (i->my_settings.CertificateContent.value)
+ {
+ free((void *)i->my_settings.CertificateContent.value);
+ }
+ if (i->my_settings.PrivateKeyContent.value)
+ {
+ free((void *)i->my_settings.PrivateKeyContent.value);
+ }
+ if (i->my_settings.WindowTitle.value)
+ {
+ free((void *)i->my_settings.WindowTitle.value);
+ }
+ if (i->my_settings.WmClass.value)
+ {
+ free((void *)i->my_settings.WmClass.value);
+ }
+ if (i->my_settings.ComputerName.value)
+ {
+ free((void *)i->my_settings.ComputerName.value);
+ }
+ if (i->my_settings.ConnectionFile.value)
+ {
+ free((void *)i->my_settings.ConnectionFile.value);
+ }
+ if (i->my_settings.AssistanceFile.value)
+ {
+ free((void *)i->my_settings.AssistanceFile.value);
+ }
+ if (i->my_settings.HomePath.value)
+ {
+ free((void *)i->my_settings.HomePath.value);
+ }
+ if (i->my_settings.ConfigPath.value)
+ {
+ free((void *)i->my_settings.ConfigPath.value);
+ }
+ if (i->my_settings.CurrentPath.value)
+ {
+ free((void *)i->my_settings.CurrentPath.value);
+ }
+ if (i->my_settings.DumpRemoteFxFile.value)
+ {
+ free((void *)i->my_settings.DumpRemoteFxFile.value);
+ }
+ if (i->my_settings.PlayRemoteFxFile.value)
+ {
+ free((void *)i->my_settings.PlayRemoteFxFile.value);
+ }
+ if (i->my_settings.GatewayHostname.value)
+ {
+ free((void *)i->my_settings.GatewayHostname.value);
+ }
+ if (i->my_settings.GatewayUsername.value)
+ {
+ free((void *)i->my_settings.GatewayUsername.value);
+ }
+ if (i->my_settings.GatewayPassword.value)
+ {
+ free((void *)i->my_settings.GatewayPassword.value);
+ }
+ if (i->my_settings.GatewayDomain.value)
+ {
+ free((void *)i->my_settings.GatewayDomain.value);
+ }
+ if (i->my_settings.GatewayAccessToken.value)
+ {
+ free((void *)i->my_settings.GatewayAccessToken.value);
+ }
+ if (i->my_settings.GatewayAcceptedCert.value)
+ {
+ free((void *)i->my_settings.GatewayAcceptedCert.value);
+ }
+ if (i->my_settings.ProxyHostname.value)
+ {
+ free((void *)i->my_settings.ProxyHostname.value);
+ }
+ if (i->my_settings.RemoteApplicationName.value)
+ {
+ free((void *)i->my_settings.RemoteApplicationName.value);
+ }
+ if (i->my_settings.RemoteApplicationIcon.value)
+ {
+ free((void *)i->my_settings.RemoteApplicationIcon.value);
+ }
+ if (i->my_settings.RemoteApplicationProgram.value)
+ {
+ free((void *)i->my_settings.RemoteApplicationProgram.value);
+ }
+ if (i->my_settings.RemoteApplicationFile.value)
+ {
+ free((void *)i->my_settings.RemoteApplicationFile.value);
+ }
+ if (i->my_settings.RemoteApplicationGuid.value)
+ {
+ free((void *)i->my_settings.RemoteApplicationGuid.value);
+ }
+ if (i->my_settings.RemoteApplicationCmdLine.value)
+ {
+ free((void *)i->my_settings.RemoteApplicationCmdLine.value);
+ }
+ if (i->my_settings.ImeFileName.value)
+ {
+ free((void *)i->my_settings.ImeFileName.value);
+ }
+ if (i->my_settings.DrivesToRedirect.value)
+ {
+ free((void *)i->my_settings.DrivesToRedirect.value);
+ }
+ if (i->my_settings.ActionScript.value)
+ {
+ free((void *)i->my_settings.ActionScript.value);
+ }
+}
+
+bool
+rdp_init_settings(void *internals)
+{
+ rdp_internals *i = internals;
+ rdpSettings *s = i->instance->context->settings;
+
+ /* via are not server here ) */
+ s->ServerMode = FALSE;
+
+ s->TlsSecurity = !(i->my_settings.notls.value);
+ if (i->my_settings.host.value && i->my_settings.host.value[0])
+ {
+ s->ServerHostname = strdup((char *)i->my_settings.host.value);
+ }
+ else
+ {
+ const char *msg = "rdp_module: server hostname does not set.";
+ i->core->api_utils->log_msg(
+ (const uint8_t *)msg, strlen(msg), wrdp_log_level_error, 0);
+ return FALSE;
+ }
+ if (i->my_settings.port.name && i->my_settings.port.name[0] == '1')
+ {
+ s->ServerPort = i->my_settings.port.value;
+ }
+ if (i->my_settings.user.value && i->my_settings.user.value[0])
+ {
+ s->Username = strdup((char *)i->my_settings.user.value);
+ }
+ if (i->my_settings.password.value && i->my_settings.password.value[0])
+ {
+ s->Password = strdup((char *)i->my_settings.password.value);
+ }
+ if (!i->my_settings.user.value && !i->my_settings.password.value)
+ {
+ /* TODO: disable authentication */
+ }
+ if (i->my_settings.nowallp.name
+ && i->my_settings.nowallp.name[0] == '1')
+ {
+ s->DisableWallpaper = i->my_settings.nowallp.value;
+ s->PerformanceFlags |= PERF_DISABLE_WALLPAPER;
+ }
+ if (i->my_settings.nowdrag.name
+ && i->my_settings.nowdrag.name[0] == '1')
+ {
+ s->DisableFullWindowDrag = i->my_settings.nowdrag.value;
+ s->PerformanceFlags |= PERF_DISABLE_FULLWINDOWDRAG;
+ }
+ if (i->my_settings.nomani.name && i->my_settings.nomani.name[0] == '1')
+ {
+ s->DisableMenuAnims = i->my_settings.nomani.value;
+ s->PerformanceFlags |= PERF_DISABLE_MENUANIMATIONS;
+ }
+ if (i->my_settings.notheme.name
+ && i->my_settings.notheme.name[0] == '1')
+ {
+ s->DisableThemes = i->my_settings.notheme.value;
+ s->PerformanceFlags |= PERF_DISABLE_THEMING;
+ }
+ if (i->my_settings.nonla.name && i->my_settings.nonla.name[0] == '1')
+ {
+ s->NlaSecurity = !(i->my_settings.nonla.value);
+ }
+ if (i->my_settings.width.name && i->my_settings.width.name[0] == '1')
+ {
+ s->DesktopWidth = i->my_settings.width.value;
+ }
+ if (i->my_settings.height.name && i->my_settings.height.name[0] == '1')
+ {
+ s->DesktopHeight = i->my_settings.height.value;
+ }
+ if (i->my_settings.pcb.value && i->my_settings.pcb.value[0])
+ {
+ s->SendPreconnectionPdu = TRUE;
+ s->PreconnectionBlob = strdup(i->my_settings.pcb.value);
+ }
+
+ s->IgnoreCertificate = TRUE;
+
+ if (i->my_settings.perf.name && i->my_settings.perf.name[0] == '1')
+ {
+ switch (i->my_settings.perf.value)
+ {
+ case 0:
+ //LAN
+ s->PerformanceFlags = PERF_FLAG_NONE;
+ s->ConnectionType = CONNECTION_TYPE_LAN;
+ s->AllowFontSmoothing = TRUE;
+ break;
+ case 1:
+ //Broadband
+ s->PerformanceFlags = PERF_DISABLE_WALLPAPER;
+ s->ConnectionType
+ = CONNECTION_TYPE_BROADBAND_HIGH;
+ break;
+ case 2:
+ //Modem
+ s->PerformanceFlags
+ = PERF_DISABLE_WALLPAPER
+ | PERF_DISABLE_FULLWINDOWDRAG
+ | PERF_DISABLE_MENUANIMATIONS
+ | PERF_DISABLE_THEMING;
+ s->ConnectionType = CONNECTION_TYPE_MODEM;
+ break;
+ }
+ }
+
+ /* new settings from freerdp header (strings) begin */
+
+ if (i->my_settings.Domain.value)
+ {
+ s->Domain = strdup(i->my_settings.Domain.value);
+ }
+ if (i->my_settings.PasswordHash.value)
+ {
+ s->PasswordHash = strdup(i->my_settings.PasswordHash.value);
+ }
+ if (i->my_settings.AcceptedCert.value)
+ {
+ s->AcceptedCert = strdup(i->my_settings.AcceptedCert.value);
+ }
+ if (i->my_settings.ClientHostname.value)
+ {
+ s->ClientHostname = strdup(i->my_settings.ClientHostname.value);
+ }
+ if (i->my_settings.ClientProductId.value)
+ {
+ s->ClientProductId
+ = strdup(i->my_settings.ClientProductId.value);
+ }
+ if (i->my_settings.AlternateShell.value)
+ {
+ s->AlternateShell = strdup(i->my_settings.AlternateShell.value);
+ }
+ if (i->my_settings.ShellWorkingDirectory.value)
+ {
+ s->ShellWorkingDirectory
+ = strdup(i->my_settings.ShellWorkingDirectory.value);
+ }
+ if (i->my_settings.ClientAddress.value)
+ {
+ s->ClientAddress = strdup(i->my_settings.ClientAddress.value);
+ }
+ if (i->my_settings.ClientDir.value)
+ {
+ s->ClientDir = strdup(i->my_settings.ClientDir.value);
+ }
+ if (i->my_settings.DynamicDSTTimeZoneKeyName.value)
+ {
+ s->DynamicDSTTimeZoneKeyName
+ = strdup(i->my_settings.DynamicDSTTimeZoneKeyName.value);
+ }
+ if (i->my_settings.RemoteAssistanceSessionId.value)
+ {
+ s->RemoteAssistanceSessionId
+ = strdup(i->my_settings.RemoteAssistanceSessionId.value);
+ }
+ if (i->my_settings.RemoteAssistancePassStub.value)
+ {
+ s->RemoteAssistancePassStub
+ = strdup(i->my_settings.RemoteAssistancePassStub.value);
+ }
+ if (i->my_settings.RemoteAssistancePassword.value)
+ {
+ s->RemoteAssistancePassword
+ = strdup(i->my_settings.RemoteAssistancePassword.value);
+ }
+ if (i->my_settings.RemoteAssistanceRCTicket.value)
+ {
+ s->RemoteAssistanceRCTicket
+ = strdup(i->my_settings.RemoteAssistanceRCTicket.value);
+ }
+ if (i->my_settings.AuthenticationServiceClass.value)
+ {
+ s->AuthenticationServiceClass
+ = strdup(i->my_settings.AuthenticationServiceClass.value);
+ }
+ if (i->my_settings.AllowedTlsCiphers.value)
+ {
+ s->AllowedTlsCiphers
+ = strdup(i->my_settings.AllowedTlsCiphers.value);
+ }
+ if (i->my_settings.NtlmSamFile.value)
+ {
+ s->NtlmSamFile = strdup(i->my_settings.NtlmSamFile.value);
+ }
+ if (i->my_settings.PreconnectionBlob.value)
+ {
+ s->PreconnectionBlob
+ = strdup(i->my_settings.PreconnectionBlob.value);
+ }
+ if (i->my_settings.RedirectionAcceptedCert.value)
+ {
+ s->RedirectionAcceptedCert
+ = strdup(i->my_settings.RedirectionAcceptedCert.value);
+ }
+ if (i->my_settings.KerberosKdc.value)
+ {
+ s->KerberosKdc = strdup(i->my_settings.KerberosKdc.value);
+ }
+ if (i->my_settings.KerberosRealm.value)
+ {
+ s->KerberosRealm = strdup(i->my_settings.KerberosRealm.value);
+ }
+ if (i->my_settings.CertificateName.value)
+ {
+ s->CertificateName
+ = strdup(i->my_settings.CertificateName.value);
+ }
+ if (i->my_settings.CertificateFile.value)
+ {
+ s->CertificateFile
+ = strdup(i->my_settings.CertificateFile.value);
+ }
+ if (i->my_settings.PrivateKeyFile.value)
+ {
+ s->PrivateKeyFile = strdup(i->my_settings.PrivateKeyFile.value);
+ }
+ if (i->my_settings.CertificateContent.value)
+ {
+ s->CertificateContent
+ = strdup(i->my_settings.CertificateContent.value);
+ }
+ if (i->my_settings.PrivateKeyContent.value)
+ {
+ s->PrivateKeyContent
+ = strdup(i->my_settings.PrivateKeyContent.value);
+ }
+ if (i->my_settings.WindowTitle.value)
+ {
+ s->WindowTitle = strdup(i->my_settings.WindowTitle.value);
+ }
+ if (i->my_settings.WmClass.value)
+ {
+ s->WmClass = strdup(i->my_settings.WmClass.value);
+ }
+ if (i->my_settings.ComputerName.value)
+ {
+ s->ComputerName = strdup(i->my_settings.ComputerName.value);
+ }
+ if (i->my_settings.ConnectionFile.value)
+ {
+ s->ConnectionFile = strdup(i->my_settings.ConnectionFile.value);
+ }
+ if (i->my_settings.AssistanceFile.value)
+ {
+ s->AssistanceFile = strdup(i->my_settings.AssistanceFile.value);
+ }
+ if (i->my_settings.HomePath.value)
+ {
+ s->HomePath = strdup(i->my_settings.HomePath.value);
+ }
+ if (i->my_settings.ConfigPath.value)
+ {
+ s->ConfigPath = strdup(i->my_settings.ConfigPath.value);
+ }
+ if (i->my_settings.CurrentPath.value)
+ {
+ s->CurrentPath = strdup(i->my_settings.CurrentPath.value);
+ }
+ if (i->my_settings.DumpRemoteFxFile.value)
+ {
+ s->DumpRemoteFxFile
+ = strdup(i->my_settings.DumpRemoteFxFile.value);
+ }
+ if (i->my_settings.PlayRemoteFxFile.value)
+ {
+ s->PlayRemoteFxFile
+ = strdup(i->my_settings.PlayRemoteFxFile.value);
+ }
+ if (i->my_settings.GatewayHostname.value)
+ {
+ s->GatewayHostname
+ = strdup(i->my_settings.GatewayHostname.value);
+ }
+ if (i->my_settings.GatewayUsername.value)
+ {
+ s->GatewayUsername
+ = strdup(i->my_settings.GatewayUsername.value);
+ }
+ if (i->my_settings.GatewayPassword.value)
+ {
+ s->GatewayPassword
+ = strdup(i->my_settings.GatewayPassword.value);
+ }
+ if (i->my_settings.GatewayDomain.value)
+ {
+ s->GatewayDomain = strdup(i->my_settings.GatewayDomain.value);
+ }
+ if (i->my_settings.GatewayAccessToken.value)
+ {
+ s->GatewayAccessToken
+ = strdup(i->my_settings.GatewayAccessToken.value);
+ }
+ if (i->my_settings.GatewayAcceptedCert.value)
+ {
+ s->GatewayAcceptedCert
+ = strdup(i->my_settings.GatewayAcceptedCert.value);
+ }
+ if (i->my_settings.ProxyHostname.value)
+ {
+ s->ProxyHostname = strdup(i->my_settings.ProxyHostname.value);
+ }
+ if (i->my_settings.RemoteApplicationName.value)
+ {
+ s->RemoteApplicationName
+ = strdup(i->my_settings.RemoteApplicationName.value);
+ }
+ if (i->my_settings.RemoteApplicationIcon.value)
+ {
+ s->RemoteApplicationIcon
+ = strdup(i->my_settings.RemoteApplicationIcon.value);
+ }
+ if (i->my_settings.RemoteApplicationProgram.value)
+ {
+ s->RemoteApplicationProgram
+ = strdup(i->my_settings.RemoteApplicationProgram.value);
+ }
+ if (i->my_settings.RemoteApplicationFile.value)
+ {
+ s->RemoteApplicationFile
+ = strdup(i->my_settings.RemoteApplicationFile.value);
+ }
+ if (i->my_settings.RemoteApplicationGuid.value)
+ {
+ s->RemoteApplicationGuid
+ = strdup(i->my_settings.RemoteApplicationGuid.value);
+ }
+ if (i->my_settings.RemoteApplicationCmdLine.value)
+ {
+ s->RemoteApplicationCmdLine
+ = strdup(i->my_settings.RemoteApplicationCmdLine.value);
+ }
+ if (i->my_settings.ImeFileName.value)
+ {
+ s->ImeFileName = strdup(i->my_settings.ImeFileName.value);
+ }
+ if (i->my_settings.DrivesToRedirect.value)
+ {
+ s->DrivesToRedirect
+ = strdup(i->my_settings.DrivesToRedirect.value);
+ }
+ if (i->my_settings.ActionScript.value)
+ {
+ s->ActionScript = strdup(i->my_settings.ActionScript.value);
+ }
+
+ /* new settings from freerdp header (strings) end */
+
+ /* new settings from freerdp header (integers) begin */
+
+ if (i->my_settings.ServerMode.name
+ && i->my_settings.ServerMode.name[0] == '1')
+ {
+ s->ServerMode = i->my_settings.ServerMode.value;
+ }
+ if (i->my_settings.WaitForOutputBufferFlush.name
+ && i->my_settings.WaitForOutputBufferFlush.name[0] == '1')
+ {
+ s->WaitForOutputBufferFlush
+ = i->my_settings.WaitForOutputBufferFlush.value;
+ }
+ if (i->my_settings.MaxTimeInCheckLoop.name
+ && i->my_settings.MaxTimeInCheckLoop.name[0] == '1')
+ {
+ s->MaxTimeInCheckLoop = i->my_settings.MaxTimeInCheckLoop.value;
+ }
+ if (i->my_settings.DesktopWidth.name
+ && i->my_settings.DesktopWidth.name[0] == '1')
+ {
+ s->DesktopWidth = i->my_settings.DesktopWidth.value;
+ }
+ if (i->my_settings.Workarea.name
+ && i->my_settings.Workarea.name[0] == '1')
+ {
+ s->Workarea = i->my_settings.Workarea.value;
+ }
+ if (i->my_settings.Fullscreen.name
+ && i->my_settings.Fullscreen.name[0] == '1')
+ {
+ s->Fullscreen = i->my_settings.Fullscreen.value;
+ }
+ if (i->my_settings.GrabKeyboard.name
+ && i->my_settings.GrabKeyboard.name[0] == '1')
+ {
+ s->GrabKeyboard = i->my_settings.GrabKeyboard.value;
+ }
+ if (i->my_settings.Decorations.name
+ && i->my_settings.Decorations.name[0] == '1')
+ {
+ s->Decorations = i->my_settings.Decorations.value;
+ }
+ if (i->my_settings.RdpVersion.name
+ && i->my_settings.RdpVersion.name[0] == '1')
+ {
+ s->RdpVersion = i->my_settings.RdpVersion.value;
+ }
+ if (i->my_settings.ColorDepth.name
+ && i->my_settings.ColorDepth.name[0] == '1')
+ {
+ s->ColorDepth = i->my_settings.ColorDepth.value;
+ }
+ if (i->my_settings.ExtSecurity.name
+ && i->my_settings.ExtSecurity.name[0] == '1')
+ {
+ s->ExtSecurity = i->my_settings.ExtSecurity.value;
+ }
+ if (i->my_settings.NlaSecurity.name
+ && i->my_settings.NlaSecurity.name[0] == '1')
+ {
+ s->NlaSecurity = i->my_settings.NlaSecurity.value;
+ }
+ if (i->my_settings.TlsSecurity.name
+ && i->my_settings.TlsSecurity.name[0] == '1')
+ {
+ s->TlsSecurity = i->my_settings.TlsSecurity.value;
+ }
+ if (i->my_settings.RdpSecurity.name
+ && i->my_settings.RdpSecurity.name[0] == '1')
+ {
+ s->RdpSecurity = i->my_settings.RdpSecurity.value;
+ }
+ if (i->my_settings.NegotiateSecurityLayer.name
+ && i->my_settings.NegotiateSecurityLayer.name[0] == '1')
+ {
+ s->NegotiateSecurityLayer
+ = i->my_settings.NegotiateSecurityLayer.value;
+ }
+ if (i->my_settings.RestrictedAdminModeRequired.name
+ && i->my_settings.RestrictedAdminModeRequired.name[0] == '1')
+ {
+ s->RestrictedAdminModeRequired
+ = i->my_settings.RestrictedAdminModeRequired.value;
+ }
+ if (i->my_settings.MstscCookieMode.name
+ && i->my_settings.MstscCookieMode.name[0] == '1')
+ {
+ s->MstscCookieMode = i->my_settings.MstscCookieMode.value;
+ }
+ if (i->my_settings.CookieMaxLength.name
+ && i->my_settings.CookieMaxLength.name[0] == '1')
+ {
+ s->CookieMaxLength = i->my_settings.CookieMaxLength.value;
+ }
+ if (i->my_settings.ClientBuild.name
+ && i->my_settings.ClientBuild.name[0] == '1')
+ {
+ s->ClientBuild = i->my_settings.ClientBuild.value;
+ }
+ if (i->my_settings.KeyboardType.name
+ && i->my_settings.KeyboardType.name[0] == '1')
+ {
+ s->KeyboardType = i->my_settings.KeyboardType.value;
+ }
+ if (i->my_settings.KeyboardSubType.name
+ && i->my_settings.KeyboardSubType.name[0] == '1')
+ {
+ s->KeyboardSubType = i->my_settings.KeyboardSubType.value;
+ }
+ if (i->my_settings.KeyboardFunctionKey.name
+ && i->my_settings.KeyboardFunctionKey.name[0] == '1')
+ {
+ s->KeyboardFunctionKey
+ = i->my_settings.KeyboardFunctionKey.value;
+ }
+ if (i->my_settings.KeyboardLayout.name
+ && i->my_settings.KeyboardLayout.name[0] == '1')
+ {
+ s->KeyboardLayout = i->my_settings.KeyboardLayout.value;
+ }
+ if (i->my_settings.UseRdpSecurityLayer.name
+ && i->my_settings.UseRdpSecurityLayer.name[0] == '1')
+ {
+ s->UseRdpSecurityLayer
+ = i->my_settings.UseRdpSecurityLayer.value;
+ }
+ if (i->my_settings.SaltedChecksum.name
+ && i->my_settings.SaltedChecksum.name[0] == '1')
+ {
+ s->SaltedChecksum = i->my_settings.SaltedChecksum.value;
+ }
+ if (i->my_settings.ServerPort.name
+ && i->my_settings.ServerPort.name[0] == '1')
+ {
+ s->ServerPort = i->my_settings.ServerPort.value;
+ }
+ if (i->my_settings.GatewayPort.name
+ && i->my_settings.GatewayPort.name[0] == '1')
+ {
+ s->GatewayPort = i->my_settings.GatewayPort.value;
+ }
+ if (i->my_settings.DesktopResize.name
+ && i->my_settings.DesktopResize.name[0] == '1')
+ {
+ s->DesktopResize = i->my_settings.DesktopResize.value;
+ }
+ if (i->my_settings.ToggleFullscreen.name
+ && i->my_settings.ToggleFullscreen.name[0] == '1')
+ {
+ s->ToggleFullscreen = i->my_settings.ToggleFullscreen.value;
+ }
+ if (i->my_settings.Floatbar.name
+ && i->my_settings.Floatbar.name[0] == '1')
+ {
+ s->Floatbar = i->my_settings.Floatbar.value;
+ }
+ if (i->my_settings.DesktopPosX.name
+ && i->my_settings.DesktopPosX.name[0] == '1')
+ {
+ s->DesktopPosX = i->my_settings.DesktopPosX.value;
+ }
+ if (i->my_settings.DesktopPosY.name
+ && i->my_settings.DesktopPosY.name[0] == '1')
+ {
+ s->DesktopPosY = i->my_settings.DesktopPosY.value;
+ }
+ if (i->my_settings.SoftwareGdi.name
+ && i->my_settings.SoftwareGdi.name[0] == '1')
+ {
+ s->SoftwareGdi = i->my_settings.SoftwareGdi.value;
+ }
+ if (i->my_settings.UnmapButtons.name
+ && i->my_settings.UnmapButtons.name[0] == '1')
+ {
+ s->UnmapButtons = i->my_settings.UnmapButtons.value;
+ }
+ if (i->my_settings.PerformanceFlags.name
+ && i->my_settings.PerformanceFlags.name[0] == '1')
+ {
+ s->PerformanceFlags = i->my_settings.PerformanceFlags.value;
+ }
+ if (i->my_settings.AllowFontSmoothing.name
+ && i->my_settings.AllowFontSmoothing.name[0] == '1')
+ {
+ s->AllowFontSmoothing = i->my_settings.AllowFontSmoothing.value;
+ }
+ if (i->my_settings.AllowDesktopComposition.name
+ && i->my_settings.AllowDesktopComposition.name[0] == '1')
+ {
+ s->AllowDesktopComposition
+ = i->my_settings.AllowDesktopComposition.value;
+ }
+ if (i->my_settings.DisableWallpaper.name
+ && i->my_settings.DisableWallpaper.name[0] == '1')
+ {
+ s->DisableWallpaper = i->my_settings.DisableWallpaper.value;
+ }
+ if (i->my_settings.DisableFullWindowDrag.name
+ && i->my_settings.DisableFullWindowDrag.name[0] == '1')
+ {
+ s->DisableFullWindowDrag
+ = i->my_settings.DisableFullWindowDrag.value;
+ }
+ if (i->my_settings.DisableMenuAnims.name
+ && i->my_settings.DisableMenuAnims.name[0] == '1')
+ {
+ s->DisableMenuAnims = i->my_settings.DisableMenuAnims.value;
+ }
+ if (i->my_settings.DisableThemes.name
+ && i->my_settings.DisableThemes.name[0] == '1')
+ {
+ s->DisableThemes = i->my_settings.DisableThemes.value;
+ }
+ if (i->my_settings.ConnectionType.name
+ && i->my_settings.ConnectionType.name[0] == '1')
+ {
+ s->ConnectionType = i->my_settings.ConnectionType.value;
+ }
+ if (i->my_settings.EncryptionMethods.name
+ && i->my_settings.EncryptionMethods.name[0] == '1')
+ {
+ s->EncryptionMethods = i->my_settings.EncryptionMethods.value;
+ }
+ if (i->my_settings.EncryptionLevel.name
+ && i->my_settings.EncryptionLevel.name[0] == '1')
+ {
+ s->EncryptionLevel = i->my_settings.EncryptionLevel.value;
+ }
+ if (i->my_settings.FIPSMode.name
+ && i->my_settings.FIPSMode.name[0] == '1')
+ {
+ s->FIPSMode = i->my_settings.FIPSMode.value;
+ }
+ if (i->my_settings.CompressionEnabled.name
+ && i->my_settings.CompressionEnabled.name[0] == '1')
+ {
+ s->CompressionEnabled = i->my_settings.CompressionEnabled.value;
+ }
+ if (i->my_settings.LogonNotify.name
+ && i->my_settings.LogonNotify.name[0] == '1')
+ {
+ s->LogonNotify = i->my_settings.LogonNotify.value;
+ }
+ if (i->my_settings.BrushSupportLevel.name
+ && i->my_settings.BrushSupportLevel.name[0] == '1')
+ {
+ s->BrushSupportLevel = i->my_settings.BrushSupportLevel.value;
+ }
+ if (i->my_settings.RemoteApplicationMode.name
+ && i->my_settings.RemoteApplicationMode.name[0] == '1')
+ {
+ s->RemoteApplicationMode
+ = i->my_settings.RemoteApplicationMode.value;
+ }
+ if (i->my_settings.TcpAckTimeout.name
+ && i->my_settings.TcpAckTimeout.name[0] == '1')
+ {
+ s->TcpAckTimeout = i->my_settings.TcpAckTimeout.value;
+ }
+ /* new settings from freerdp header (integers) end */
+
+ /* TODO: handle rest of options:
+ * fntlm
+ */
+
+ return true;
+}
diff --git a/src/rdp/rdp_settings.h b/src/rdp/rdp_settings.h
new file mode 100644
index 0000000..3fca325
--- /dev/null
+++ b/src/rdp/rdp_settings.h
@@ -0,0 +1,15 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+bool rdp_set_setting_str(backend_setting_str *setting, void *internals);
+
+bool rdp_set_setting_int(backend_setting_int *setting, void *internals);
+
+void rdp_settings_free(rdp_internals *internals);
+
+bool rdp_init_settings(void *internals);
diff --git a/src/rdp/rdp_user_input.c b/src/rdp/rdp_user_input.c
new file mode 100644
index 0000000..c79e5b1
--- /dev/null
+++ b/src/rdp/rdp_user_input.c
@@ -0,0 +1,458 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "webrdp_core_api.h"
+#include "webrdp_module_api.h"
+
+#include "rdp_backend_api.h"
+#include "rdp_impl.h"
+
+const UINT32 ASCII_TO_SCANCODE[256] = {
+ 0, /* 0 */
+ 0, /* 1 */
+ 0, /* 2 */
+ 0, /* 3 */
+ 0, /* 4 */
+ 0, /* 5 */
+ 0, /* 6 */
+ 0, /* 7 */
+ RDP_SCANCODE_BACKSPACE, /* 8 */
+ RDP_SCANCODE_TAB, /* 9 */
+ VK_KEY_D, /* 10 */
+ VK_KEY_F, /* 11 */
+ VK_KEY_H, /* 12 */
+ RDP_SCANCODE_RETURN, /* 13 */
+ RDP_SCANCODE_BACKSPACE, /* 14 */
+ VK_KEY_X, /* 15 */
+ RDP_SCANCODE_LSHIFT, /* 16 */
+ RDP_SCANCODE_LCONTROL, /* 17 */
+ RDP_SCANCODE_LMENU, /* 18 */
+ RDP_SCANCODE_PAUSE, /* 19 */
+ RDP_SCANCODE_CAPSLOCK, /* 20 */
+ VK_KEY_W, /* 21 */
+ VK_KEY_E, /* 22 */
+ VK_KEY_R, /* 23 */
+ VK_KEY_Y, /* 24 */
+ VK_KEY_A, /* 25 */
+ VK_KEY_1, /* 26 */
+ RDP_SCANCODE_ESCAPE, /* 27 */
+ VK_KEY_3, /* 28 */
+ VK_KEY_4, /* 29 */
+ VK_KEY_6, /* 30 */
+ VK_KEY_5, /* 31 */
+ RDP_SCANCODE_SPACE, /* 32 */
+ RDP_SCANCODE_PRIOR, /* 33 */
+ RDP_SCANCODE_NEXT, /* 34 */
+ RDP_SCANCODE_END, /* 35 */
+ RDP_SCANCODE_HOME, /* 36 */
+ RDP_SCANCODE_LEFT, /* 37 */
+ RDP_SCANCODE_UP, /* 38 */
+ RDP_SCANCODE_RIGHT, /* 39 */
+ RDP_SCANCODE_DOWN, /* 40 */
+ RDP_SCANCODE_KEY_0, /* 41 */
+ RDP_SCANCODE_MULTIPLY, /* 42 */
+ RDP_SCANCODE_ADD, /* 43 */
+ RDP_SCANCODE_PRINTSCREEN, /* 44 */
+ RDP_SCANCODE_INSERT, /* 45 */
+ RDP_SCANCODE_DELETE, /* 46 */
+ RDP_SCANCODE_DIVIDE, /* 47 */
+ RDP_SCANCODE_KEY_0, /* 48 */
+ RDP_SCANCODE_KEY_1, /* 49 */
+ RDP_SCANCODE_KEY_2, /* 50 */
+ RDP_SCANCODE_KEY_3, /* 51 */
+ RDP_SCANCODE_KEY_4, /* 52 */
+ RDP_SCANCODE_KEY_5, /* 53 */
+ RDP_SCANCODE_KEY_6, /* 54 */
+ RDP_SCANCODE_KEY_7, /* 55 */
+ RDP_SCANCODE_KEY_8, /* 56 */
+ RDP_SCANCODE_KEY_9, /* 57 */
+ RDP_SCANCODE_OEM_1, /* 58 */
+ RDP_SCANCODE_OEM_1, /* 59 */
+ RDP_SCANCODE_OEM_COMMA, /* 60 */
+ RDP_SCANCODE_OEM_PLUS, /* 61 */
+ RDP_SCANCODE_OEM_PERIOD, /* 62 */
+ RDP_SCANCODE_DIVIDE, /* 63 */
+ RDP_SCANCODE_KEY_2, /* 64 */
+ RDP_SCANCODE_KEY_A, /* 65 */
+ RDP_SCANCODE_KEY_B, /* 66 */
+ RDP_SCANCODE_KEY_C, /* 67 */
+ RDP_SCANCODE_KEY_D, /* 68 */
+ RDP_SCANCODE_KEY_E, /* 69 */
+ RDP_SCANCODE_KEY_F, /* 70 */
+ RDP_SCANCODE_KEY_G, /* 71 */
+ RDP_SCANCODE_KEY_H, /* 72 */
+ RDP_SCANCODE_KEY_I, /* 73 */
+ RDP_SCANCODE_KEY_J, /* 74 */
+ RDP_SCANCODE_KEY_K, /* 75 */
+ RDP_SCANCODE_KEY_L, /* 76 */
+ RDP_SCANCODE_KEY_M, /* 77 */
+ RDP_SCANCODE_KEY_N, /* 78 */
+ RDP_SCANCODE_KEY_O, /* 79 */
+ RDP_SCANCODE_KEY_P, /* 80 */
+ RDP_SCANCODE_KEY_Q, /* 81 */
+ RDP_SCANCODE_KEY_R, /* 82 */
+ RDP_SCANCODE_KEY_S, /* 83 */
+ RDP_SCANCODE_KEY_T, /* 84 */
+ RDP_SCANCODE_KEY_U, /* 85 */
+ RDP_SCANCODE_KEY_V, /* 86 */
+ RDP_SCANCODE_KEY_W, /* 87 */
+ RDP_SCANCODE_KEY_X, /* 88 */
+ RDP_SCANCODE_KEY_Y, /* 89 */
+ RDP_SCANCODE_KEY_Z, /* 90 */
+ RDP_SCANCODE_LWIN, /* 91 */
+ RDP_SCANCODE_RWIN, /* 92 */
+ RDP_SCANCODE_APPS, /* 93 */
+ RDP_SCANCODE_KEY_6, /* 94 */
+ RDP_SCANCODE_OEM_MINUS, /* 95 */
+ RDP_SCANCODE_NUMPAD0, /* 96 */
+ RDP_SCANCODE_NUMPAD1, /* 97 */
+ RDP_SCANCODE_NUMPAD2, /* 98 */
+ RDP_SCANCODE_NUMPAD3, /* 99 */
+ RDP_SCANCODE_NUMPAD4, /* 100 */
+ RDP_SCANCODE_NUMPAD5, /* 101 */
+ RDP_SCANCODE_NUMPAD6, /* 102 */
+ RDP_SCANCODE_NUMPAD7, /* 103 */
+ RDP_SCANCODE_NUMPAD8, /* 104 */
+ RDP_SCANCODE_NUMPAD9, /* 105 */
+ RDP_SCANCODE_MULTIPLY, /* 106 */
+ RDP_SCANCODE_ADD, /* 107 */
+ 0, /* 108 */
+ RDP_SCANCODE_SUBTRACT, /* 109 */
+ RDP_SCANCODE_DELETE, /* 110 */
+ RDP_SCANCODE_DIVIDE, /* 111 */
+ RDP_SCANCODE_F1, /* 112 */
+ RDP_SCANCODE_F2, /* 113 */
+ RDP_SCANCODE_F3, /* 114 */
+ RDP_SCANCODE_F4, /* 115 */
+ RDP_SCANCODE_F5, /* 116 */
+ RDP_SCANCODE_F6, /* 117 */
+ RDP_SCANCODE_F7, /* 118 */
+ RDP_SCANCODE_F8, /* 119 */
+ RDP_SCANCODE_F9, /* 120 */
+ RDP_SCANCODE_F10, /* 121 */
+ RDP_SCANCODE_F11, /* 122 */
+ RDP_SCANCODE_F12, /* 123 */
+ RDP_SCANCODE_OEM_5, /* 124 */
+ RDP_SCANCODE_OEM_6, /* 125 */
+ VK_F4, /* 126 */
+ VK_END, /* 127 */
+ VK_F2, /* 128 */
+ VK_NEXT, /* 129 */
+ VK_F1, /* 130 */
+ VK_LEFT, /* 131 */
+ VK_RIGHT, /* 132 */
+ VK_DOWN, /* 133 */
+ VK_UP, /* 134 */
+ 0, /* 135 */
+ 0, /* 136 */
+ 0, /* 137 */
+ 0, /* 138 */
+ 0, /* 139 */
+ 0, /* 140 */
+ 0, /* 141 */
+ 0, /* 142 */
+ 0, /* 143 */
+ RDP_SCANCODE_NUMLOCK, /* 144 */
+ RDP_SCANCODE_SCROLLLOCK, /* 145 */
+ 0, /* 146 */
+ 0, /* 147 */
+ 0, /* 148 */
+ 0, /* 149 */
+ 0, /* 150 */
+ 0, /* 151 */
+ 0, /* 152 */
+ 0, /* 153 */
+ 0, /* 154 */
+ 0, /* 155 */
+ 0, /* 156 */
+ 0, /* 157 */
+ 0, /* 158 */
+ 0, /* 159 */
+ 0, /* 160 */
+ 0, /* 161 */
+ 0, /* 162 */
+ 0, /* 163 */
+ 0, /* 164 */
+ 0, /* 165 */
+ 0, /* 166 */
+ 0, /* 167 */
+ 0, /* 168 */
+ 0, /* 169 */
+ 0, /* 170 */
+ 0, /* 171 */
+ 0, /* 172 */
+ RDP_SCANCODE_OEM_MINUS, /* 173 */
+ 0, /* 174 */
+ 0, /* 175 */
+ 0, /* 176 */
+ 0, /* 177 */
+ 0, /* 178 */
+ 0, /* 179 */
+ 0, /* 180 */
+ 0, /* 181 */
+ 0, /* 182 */
+ 0, /* 183 */
+ 0, /* 184 */
+ 0, /* 185 */
+ RDP_SCANCODE_OEM_1, /* 186 */
+ RDP_SCANCODE_OEM_PLUS, /* 187 */
+ RDP_SCANCODE_OEM_COMMA, /* 188 */
+ RDP_SCANCODE_OEM_MINUS, /* 189 */
+ RDP_SCANCODE_OEM_PERIOD, /* 190 */
+ RDP_SCANCODE_OEM_2, /* 191 */
+ RDP_SCANCODE_OEM_3, /* 192 */
+ 0, /* 193 */
+ 0, /* 194 */
+ 0, /* 195 */
+ 0, /* 196 */
+ 0, /* 197 */
+ 0, /* 198 */
+ 0, /* 199 */
+ 0, /* 200 */
+ 0, /* 201 */
+ 0, /* 202 */
+ 0, /* 203 */
+ 0, /* 204 */
+ 0, /* 205 */
+ 0, /* 206 */
+ 0, /* 207 */
+ 0, /* 208 */
+ 0, /* 209 */
+ 0, /* 210 */
+ 0, /* 211 */
+ 0, /* 212 */
+ 0, /* 213 */
+ 0, /* 214 */
+ 0, /* 215 */
+ 0, /* 216 */
+ 0, /* 217 */
+ 0, /* 218 */
+ RDP_SCANCODE_OEM_4, /* 219 */
+ RDP_SCANCODE_OEM_5, /* 220 */
+ RDP_SCANCODE_OEM_6, /* 221 */
+ RDP_SCANCODE_OEM_7, /* 222 */
+ 0, /* 223 */
+ 0, /* 224 */
+ 0, /* 225 */
+ 0, /* 226 */
+ 0, /* 227 */
+ 0, /* 228 */
+ 0, /* 229 */
+ 0, /* 230 */
+ 0, /* 231 */
+ 0, /* 232 */
+ 0, /* 233 */
+ 0, /* 234 */
+ 0, /* 235 */
+ 0, /* 236 */
+ 0, /* 237 */
+ 0, /* 238 */
+ 0, /* 239 */
+ 0, /* 240 */
+ 0, /* 241 */
+ 0, /* 242 */
+ 0, /* 243 */
+ 0, /* 244 */
+ 0, /* 245 */
+ 0, /* 246 */
+ 0, /* 247 */
+ 0, /* 248 */
+ 0, /* 249 */
+ 0, /* 250 */
+ 0, /* 251 */
+ 0, /* 252 */
+ 0, /* 253 */
+ 0, /* 254 */
+ 0 /* 255 */
+};
+
+static bool
+rdp_backend_handle_input_mouse(ws_input_mouse input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->context->input;
+ _i->core->api_core->reset_idle(_i->task_info);
+ inp->MouseEvent(inp, input.flags, input.x, input.y);
+ return true;
+}
+
+static bool
+rdp_backend_handle_input_kupdown(ws_input_kupdown input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->context->input;
+ if (0 < input.code)
+ {
+ _i->core->api_core->reset_idle(_i->task_info);
+ /* make byte */
+ input.code = RDP_SCANCODE_CODE(input.code);
+ /* apply extended */
+ input.code = ASCII_TO_SCANCODE[input.code];
+ /* extract extended sepparatelly in tflag */
+ uint32_t tflag = RDP_SCANCODE_EXTENDED(input.code) ?
+ KBD_FLAGS_EXTENDED :
+ 0;
+ freerdp_input_send_keyboard_event(inp,
+ (input.down ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE) | tflag,
+ input.code);
+ }
+ return true;
+}
+
+static bool
+rdp_backend_handle_input_kpress(ws_input_kpress input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->context->input;
+ _i->core->api_core->reset_idle(_i->task_info);
+ if (0x20 < input.code)
+ {
+ if (input.shiftstate & 6)
+ {
+ //Control and or Alt: Must use scan-codes since
+ //unicode-event can't handle these
+ if (((64 < input.code) && (91 > input.code))
+ || ((96 < input.code) && (123 > input.code)))
+ {
+ input.code -= (input.shiftstate & 1) ? 0 : 32;
+ input.code
+ = GetVirtualScanCodeFromVirtualKeyCode(
+ input.code, 4);
+ if (0 < input.code)
+ {
+ freerdp_input_send_unicode_keyboard_event(
+ inp, KBD_FLAGS_DOWN,
+ ASCII_TO_SCANCODE[input.code]);
+ freerdp_input_send_unicode_keyboard_event(
+ inp, KBD_FLAGS_RELEASE,
+ ASCII_TO_SCANCODE[input.code]);
+ }
+ }
+ }
+ else
+ {
+ if (0 < input.code)
+ {
+ if (input.code == 96)
+ {
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_DOWN,
+ RDP_SCANCODE_LCONTROL);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_DOWN, RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_DOWN,
+ (UINT8)RDP_SCANCODE_DELETE);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE,
+ RDP_SCANCODE_LCONTROL);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE,
+ RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE,
+ (UINT8)RDP_SCANCODE_DELETE);
+ }
+
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_DOWN,
+ ASCII_TO_SCANCODE[input.code]);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE,
+ ASCII_TO_SCANCODE[input.code]);
+ }
+ }
+ }
+ else
+ {
+ if (0 < input.code)
+ {
+ input.code = RDP_SCANCODE_CODE(input.code);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, ASCII_TO_SCANCODE[input.code]);
+ freerdp_input_send_keyboard_event(inp,
+ KBD_FLAGS_RELEASE, ASCII_TO_SCANCODE[input.code]);
+ }
+ }
+ return true;
+}
+
+static bool
+rdp_backend_handle_input_kcomb(ws_input_keycomb input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->context->input;
+ _i->core->api_core->reset_idle(_i->task_info);
+ switch (input)
+ {
+ case ws_keycomb_ctrlaltdel_press:
+ {
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LCONTROL);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, (UINT8)RDP_SCANCODE_DELETE);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LCONTROL);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, (UINT8)RDP_SCANCODE_DELETE);
+ }
+ break;
+ case ws_keycomb_alttab_press:
+ {
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LMENU);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_DOWN, RDP_SCANCODE_TAB);
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_TAB);
+ }
+ break;
+ case ws_keycomb_alttab_release:
+ {
+ freerdp_input_send_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LMENU);
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+static bool
+rdp_backend_handle_input_unicode(ws_input_unicode input, void *internals)
+{
+ rdp_internals *_i = internals;
+ rdpInput *inp = _i->instance->context->input;
+ int i;
+ _i->core->api_core->reset_idle(_i->task_info);
+ for (i = 0; i < input.length; ++i)
+ {
+ freerdp_input_send_unicode_keyboard_event(
+ inp, KBD_FLAGS_DOWN, (UINT16)input.input[i]);
+ freerdp_input_send_unicode_keyboard_event(
+ inp, KBD_FLAGS_RELEASE, (UINT16)input.input[i]);
+ }
+ return true;
+}
+
+void
+register_input(wrdp_backend_module *backend)
+{
+ backend->callbacks_input->kcomb = rdp_backend_handle_input_kcomb;
+ backend->callbacks_input->kupdown = rdp_backend_handle_input_kupdown;
+ backend->callbacks_input->kpress = rdp_backend_handle_input_kpress;
+ backend->callbacks_input->mouse = rdp_backend_handle_input_mouse;
+ backend->callbacks_input->unicode = rdp_backend_handle_input_unicode;
+}
diff --git a/src/rdp/rdp_user_input.h b/src/rdp/rdp_user_input.h
new file mode 100644
index 0000000..c7851e4
--- /dev/null
+++ b/src/rdp/rdp_user_input.h
@@ -0,0 +1,10 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#pragma once
+
+void register_input(wrdp_backend_module *backend);
+void register_pointer(rdpPointer *p);