Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
165
third_party/FreeRDP/channels/client/CMakeLists.txt
vendored
Normal file
165
third_party/FreeRDP/channels/client/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
# Copyright 2024 Armin Novak <anovak@thincast.com>
|
||||
# Copyright 2024 Thincast Technologies GmbH
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set(MODULE_NAME "freerdp-channels-client")
|
||||
set(MODULE_PREFIX "FREERDP_CHANNELS_CLIENT")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/tables.c ${CMAKE_CURRENT_SOURCE_DIR}/tables.h ${CMAKE_CURRENT_SOURCE_DIR}/addin.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/addin.h ${CMAKE_CURRENT_SOURCE_DIR}/generic_dynvc.c
|
||||
)
|
||||
|
||||
if(CHANNEL_STATIC_CLIENT_ENTRIES)
|
||||
list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES)
|
||||
endif()
|
||||
|
||||
foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES})
|
||||
foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
|
||||
foreach(ENTRY ${${STATIC_MODULE}_CLIENT_ENTRY})
|
||||
if(${ENTRY} STREQUAL ${STATIC_ENTRY})
|
||||
set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME})
|
||||
set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL})
|
||||
list(APPEND ${MODULE_PREFIX}_LIBS ${STATIC_MODULE_NAME})
|
||||
|
||||
set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${ENTRY}")
|
||||
if(${ENTRY} STREQUAL "VirtualChannelEntry")
|
||||
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS);")
|
||||
elseif(${ENTRY} STREQUAL "VirtualChannelEntryEx")
|
||||
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS_EX,PVOID);")
|
||||
elseif(${ENTRY} MATCHES "DVCPluginEntry$")
|
||||
set(ENTRY_POINT_IMPORT "extern UINT VCAPITYPE ${ENTRY_POINT_NAME}(IDRDYNVC_ENTRY_POINTS* pEntryPoints);")
|
||||
elseif(${ENTRY} MATCHES "DeviceServiceEntry$")
|
||||
set(ENTRY_POINT_IMPORT
|
||||
"extern UINT VCAPITYPE ${ENTRY_POINT_NAME}(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints);"
|
||||
)
|
||||
else()
|
||||
set(ENTRY_POINT_IMPORT "extern UINT VCAPITYPE ${ENTRY_POINT_NAME}(void);")
|
||||
endif()
|
||||
|
||||
string(APPEND ${STATIC_ENTRY}_IMPORTS "\n${ENTRY_POINT_IMPORT}")
|
||||
string(APPEND ${STATIC_ENTRY}_TABLE "\n\t{ \"${STATIC_MODULE_CHANNEL}\", ${ENTRY_POINT_NAME} },")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
string(APPEND CLIENT_STATIC_ENTRY_TABLES_LIST "\nextern const STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[];\n")
|
||||
string(APPEND CLIENT_STATIC_ENTRY_TABLES_LIST "const STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[] =\n{")
|
||||
|
||||
foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES})
|
||||
set(CLIENT_STATIC_ENTRY_IMPORTS "${CLIENT_STATIC_ENTRY_IMPORTS}\n${${STATIC_ENTRY}_IMPORTS}")
|
||||
if(${STATIC_ENTRY} STREQUAL "VirtualChannelEntry")
|
||||
set(CLIENT_STATIC_ENTRY_TYPE "STATIC_ENTRY_VC")
|
||||
set(CLIENT_STATIC_ENTRY_INITIALIZER ".csevc")
|
||||
elseif(${STATIC_ENTRY} STREQUAL "VirtualChannelEntryEx")
|
||||
set(CLIENT_STATIC_ENTRY_TYPE "STATIC_ENTRY_VCEX")
|
||||
set(CLIENT_STATIC_ENTRY_INITIALIZER ".csevcex")
|
||||
elseif(${STATIC_ENTRY} MATCHES "DVCPluginEntry$")
|
||||
set(CLIENT_STATIC_ENTRY_TYPE "STATIC_ENTRY_DVC")
|
||||
set(CLIENT_STATIC_ENTRY_INITIALIZER ".csedvc")
|
||||
elseif(${STATIC_ENTRY} MATCHES "DeviceServiceEntry$")
|
||||
set(CLIENT_STATIC_ENTRY_TYPE "STATIC_ENTRY_DSE")
|
||||
set(CLIENT_STATIC_ENTRY_INITIALIZER ".csedse")
|
||||
else()
|
||||
set(CLIENT_STATIC_ENTRY_TYPE "STATIC_ENTRY")
|
||||
set(CLIENT_STATIC_ENTRY_INITIALIZER ".cse")
|
||||
endif()
|
||||
|
||||
string(APPEND CLIENT_STATIC_ENTRY_TABLES
|
||||
"\nextern const ${CLIENT_STATIC_ENTRY_TYPE} CLIENT_${STATIC_ENTRY}_TABLE[];\n"
|
||||
)
|
||||
string(APPEND CLIENT_STATIC_ENTRY_TABLES "const ${CLIENT_STATIC_ENTRY_TYPE} CLIENT_${STATIC_ENTRY}_TABLE[] =\n{")
|
||||
string(APPEND CLIENT_STATIC_ENTRY_TABLES "\n${${STATIC_ENTRY}_TABLE}")
|
||||
string(APPEND CLIENT_STATIC_ENTRY_TABLES "\n\t{ nullptr, nullptr }\n};")
|
||||
string(APPEND CLIENT_STATIC_ENTRY_TABLES_LIST
|
||||
"\n\t{ \"${STATIC_ENTRY}\", { ${CLIENT_STATIC_ENTRY_INITIALIZER} = CLIENT_${STATIC_ENTRY}_TABLE } },"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
string(APPEND CLIENT_STATIC_ENTRY_TABLES_LIST "\n\t{ nullptr, { .cse = nullptr } }\n};")
|
||||
|
||||
set(CLIENT_STATIC_ADDIN_TABLE "extern const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[];\n")
|
||||
string(APPEND CLIENT_STATIC_ADDIN_TABLE "const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[] =\n{")
|
||||
|
||||
foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
|
||||
set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME})
|
||||
set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL})
|
||||
string(TOUPPER "CLIENT_${STATIC_MODULE_CHANNEL}_SUBSYSTEM_TABLE" SUBSYSTEM_TABLE_NAME)
|
||||
set(SUBSYSTEM_TABLE
|
||||
"extern const STATIC_SUBSYSTEM_ENTRY ${SUBSYSTEM_TABLE_NAME}[];\nconst STATIC_SUBSYSTEM_ENTRY ${SUBSYSTEM_TABLE_NAME}[] =\n{"
|
||||
)
|
||||
get_target_property(CHANNEL_SUBSYSTEMS ${STATIC_MODULE_NAME} SUBSYSTEMS)
|
||||
if(CHANNEL_SUBSYSTEMS MATCHES "NOTFOUND")
|
||||
set(CHANNEL_SUBSYSTEMS "")
|
||||
endif()
|
||||
foreach(STATIC_SUBSYSTEM ${CHANNEL_SUBSYSTEMS})
|
||||
if(${STATIC_SUBSYSTEM} MATCHES "^([^-]*)-(.*)")
|
||||
string(REGEX REPLACE "^([^-]*)-(.*)" "\\1" STATIC_SUBSYSTEM_NAME ${STATIC_SUBSYSTEM})
|
||||
string(REGEX REPLACE "^([^-]*)-(.*)" "\\2" STATIC_SUBSYSTEM_TYPE ${STATIC_SUBSYSTEM})
|
||||
else()
|
||||
set(STATIC_SUBSYSTEM_NAME "${STATIC_SUBSYSTEM}")
|
||||
set(STATIC_SUBSYSTEM_TYPE "")
|
||||
endif()
|
||||
string(LENGTH "${STATIC_SUBSYSTEM_TYPE}" _type_length)
|
||||
set(SUBSYSTEM_MODULE_NAME "${STATIC_MODULE_NAME}-${STATIC_SUBSYSTEM}")
|
||||
list(APPEND ${MODULE_PREFIX}_LIBS ${SUBSYSTEM_MODULE_NAME})
|
||||
if(_type_length GREATER 0)
|
||||
set(STATIC_SUBSYSTEM_ENTRY
|
||||
"${STATIC_SUBSYSTEM_NAME}_freerdp_${STATIC_MODULE_CHANNEL}_client_${STATIC_SUBSYSTEM_TYPE}_subsystem_entry"
|
||||
)
|
||||
else()
|
||||
set(STATIC_SUBSYSTEM_ENTRY "${STATIC_SUBSYSTEM_NAME}_freerdp_${STATIC_MODULE_CHANNEL}_client_subsystem_entry")
|
||||
endif()
|
||||
string(APPEND SUBSYSTEM_TABLE
|
||||
"\n\t{ \"${STATIC_SUBSYSTEM_NAME}\", \"${STATIC_SUBSYSTEM_TYPE}\", ${STATIC_SUBSYSTEM_ENTRY} },"
|
||||
)
|
||||
set(SUBSYSTEM_IMPORT "extern UINT VCAPITYPE ${STATIC_SUBSYSTEM_ENTRY}(void*);")
|
||||
string(APPEND CLIENT_STATIC_SUBSYSTEM_IMPORTS "\n${SUBSYSTEM_IMPORT}")
|
||||
endforeach()
|
||||
string(APPEND SUBSYSTEM_TABLE "\n\t{ nullptr, nullptr, nullptr }\n};")
|
||||
string(APPEND CLIENT_STATIC_SUBSYSTEM_TABLES "\n${SUBSYSTEM_TABLE}")
|
||||
|
||||
foreach(ENTRY ${${STATIC_MODULE}_CLIENT_ENTRY})
|
||||
set(ENTRY_POINT_NAME ${STATIC_MODULE_CHANNEL}_${ENTRY})
|
||||
if(${ENTRY} STREQUAL "VirtualChannelEntry")
|
||||
set(ENTRY_INITIALIZER ".csevc")
|
||||
elseif(${ENTRY} STREQUAL "VirtualChannelEntryEx")
|
||||
set(ENTRY_INITIALIZER ".csevcex")
|
||||
elseif(${ENTRY} MATCHES "DVCPluginEntry$")
|
||||
set(ENTRY_INITIALIZER ".csedvc")
|
||||
elseif(${ENTRY} MATCHES "DeviceServiceEntry$")
|
||||
set(ENTRY_INITIALIZER ".csedse")
|
||||
else()
|
||||
set(ENTRY_INITIALIZER ".cse")
|
||||
endif()
|
||||
string(
|
||||
APPEND
|
||||
CLIENT_STATIC_ADDIN_TABLE
|
||||
"\n\t{ \"${STATIC_MODULE_CHANNEL}\", \"${ENTRY}\", { ${ENTRY_INITIALIZER} = ${ENTRY_POINT_NAME} }, ${SUBSYSTEM_TABLE_NAME} },"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
string(APPEND CLIENT_STATIC_ADDIN_TABLE "\n\t{ nullptr, nullptr, { .cse = nullptr }, nullptr }\n};")
|
||||
|
||||
cleaning_configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c)
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp winpr)
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} PARENT_SCOPE)
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
|
||||
759
third_party/FreeRDP/channels/client/addin.c
vendored
Normal file
759
third_party/FreeRDP/channels/client/addin.c
vendored
Normal file
@@ -0,0 +1,759 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Channel Addins
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/string.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/library.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/addin.h>
|
||||
#include <freerdp/build-config.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
|
||||
#include "tables.h"
|
||||
|
||||
#include "addin.h"
|
||||
|
||||
#include <freerdp/channels/log.h>
|
||||
#define TAG CHANNELS_TAG("addin")
|
||||
|
||||
extern const STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[];
|
||||
|
||||
static void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* table,
|
||||
const char* identifier)
|
||||
{
|
||||
size_t index = 0;
|
||||
const STATIC_ENTRY* pEntry = &table->table.cse[index++];
|
||||
|
||||
while (pEntry->entry != nullptr)
|
||||
{
|
||||
static_entry_fn_t fkt = pEntry->entry;
|
||||
if (strcmp(pEntry->name, identifier) == 0)
|
||||
return WINPR_FUNC_PTR_CAST(fkt, void*);
|
||||
|
||||
pEntry = &table->table.cse[index++];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* freerdp_channels_client_find_static_entry(const char* name, const char* identifier)
|
||||
{
|
||||
size_t index = 0;
|
||||
const STATIC_ENTRY_TABLE* pEntry = &CLIENT_STATIC_ENTRY_TABLES[index++];
|
||||
|
||||
while (pEntry->table.cse != nullptr)
|
||||
{
|
||||
if (strcmp(pEntry->name, name) == 0)
|
||||
{
|
||||
return freerdp_channels_find_static_entry_in_table(pEntry, identifier);
|
||||
}
|
||||
|
||||
pEntry = &CLIENT_STATIC_ENTRY_TABLES[index++];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[];
|
||||
|
||||
static FREERDP_ADDIN** freerdp_channels_list_client_static_addins(
|
||||
WINPR_ATTR_UNUSED LPCSTR pszName, WINPR_ATTR_UNUSED LPCSTR pszSubsystem,
|
||||
WINPR_ATTR_UNUSED LPCSTR pszType, WINPR_ATTR_UNUSED DWORD dwFlags)
|
||||
{
|
||||
DWORD nAddins = 0;
|
||||
FREERDP_ADDIN** ppAddins = nullptr;
|
||||
const STATIC_SUBSYSTEM_ENTRY* subsystems = nullptr;
|
||||
nAddins = 0;
|
||||
ppAddins = (FREERDP_ADDIN**)calloc(128, sizeof(FREERDP_ADDIN*));
|
||||
|
||||
if (!ppAddins)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ppAddins[nAddins] = nullptr;
|
||||
|
||||
for (size_t i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != nullptr; i++)
|
||||
{
|
||||
FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
|
||||
const STATIC_ADDIN_TABLE* table = &CLIENT_STATIC_ADDIN_TABLE[i];
|
||||
if (!pAddin)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
(void)sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", table->name);
|
||||
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
|
||||
ppAddins[nAddins++] = pAddin;
|
||||
subsystems = table->table;
|
||||
|
||||
for (size_t j = 0; subsystems[j].name != nullptr; j++)
|
||||
{
|
||||
pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
|
||||
|
||||
if (!pAddin)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
(void)sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", table->name);
|
||||
(void)sprintf_s(pAddin->cSubsystem, ARRAYSIZE(pAddin->cSubsystem), "%s",
|
||||
subsystems[j].name);
|
||||
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
|
||||
ppAddins[nAddins++] = pAddin;
|
||||
}
|
||||
}
|
||||
|
||||
return ppAddins;
|
||||
error_out:
|
||||
freerdp_channels_addin_list_free(ppAddins);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static HANDLE FindFirstFileUTF8(LPCSTR pszSearchPath, WIN32_FIND_DATAW* FindData)
|
||||
{
|
||||
HANDLE hdl = INVALID_HANDLE_VALUE;
|
||||
if (!pszSearchPath)
|
||||
return hdl;
|
||||
WCHAR* wpath = ConvertUtf8ToWCharAlloc(pszSearchPath, nullptr);
|
||||
if (!wpath)
|
||||
return hdl;
|
||||
|
||||
hdl = FindFirstFileW(wpath, FindData);
|
||||
free(wpath);
|
||||
|
||||
return hdl;
|
||||
}
|
||||
|
||||
static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCSTR pszSubsystem,
|
||||
LPCSTR pszType,
|
||||
WINPR_ATTR_UNUSED DWORD dwFlags)
|
||||
{
|
||||
int nDashes = 0;
|
||||
HANDLE hFind = nullptr;
|
||||
DWORD nAddins = 0;
|
||||
LPSTR pszPattern = nullptr;
|
||||
size_t cchPattern = 0;
|
||||
LPCSTR pszAddinPath = FREERDP_ADDIN_PATH;
|
||||
LPCSTR pszInstallPrefix = FREERDP_INSTALL_PREFIX;
|
||||
LPCSTR pszExtension = nullptr;
|
||||
LPSTR pszSearchPath = nullptr;
|
||||
size_t cchSearchPath = 0;
|
||||
size_t cchAddinPath = 0;
|
||||
size_t cchInstallPrefix = 0;
|
||||
FREERDP_ADDIN** ppAddins = nullptr;
|
||||
WIN32_FIND_DATAW FindData = WINPR_C_ARRAY_INIT;
|
||||
cchAddinPath = strnlen(pszAddinPath, sizeof(FREERDP_ADDIN_PATH));
|
||||
cchInstallPrefix = strnlen(pszInstallPrefix, sizeof(FREERDP_INSTALL_PREFIX));
|
||||
pszExtension = PathGetSharedLibraryExtensionA(0);
|
||||
cchPattern = 128 + strnlen(pszExtension, MAX_PATH) + 2;
|
||||
pszPattern = (LPSTR)malloc(cchPattern + 1);
|
||||
|
||||
if (!pszPattern)
|
||||
{
|
||||
WLog_ERR(TAG, "malloc failed!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (pszName && pszSubsystem && pszType)
|
||||
{
|
||||
(void)sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client-%s-%s.%s",
|
||||
pszName, pszSubsystem, pszType, pszExtension);
|
||||
}
|
||||
else if (pszName && pszType)
|
||||
{
|
||||
(void)sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client-?-%s.%s",
|
||||
pszName, pszType, pszExtension);
|
||||
}
|
||||
else if (pszName)
|
||||
{
|
||||
(void)sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client*.%s",
|
||||
pszName, pszExtension);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "?-client*.%s",
|
||||
pszExtension);
|
||||
}
|
||||
|
||||
cchPattern = strnlen(pszPattern, cchPattern);
|
||||
cchSearchPath = cchInstallPrefix + cchAddinPath + cchPattern + 3;
|
||||
pszSearchPath = (LPSTR)calloc(cchSearchPath + 1, sizeof(char));
|
||||
|
||||
if (!pszSearchPath)
|
||||
{
|
||||
WLog_ERR(TAG, "malloc failed!");
|
||||
free(pszPattern);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CopyMemory(pszSearchPath, pszInstallPrefix, cchInstallPrefix);
|
||||
pszSearchPath[cchInstallPrefix] = '\0';
|
||||
const HRESULT hr1 = NativePathCchAppendA(pszSearchPath, cchSearchPath + 1, pszAddinPath);
|
||||
const HRESULT hr2 = NativePathCchAppendA(pszSearchPath, cchSearchPath + 1, pszPattern);
|
||||
free(pszPattern);
|
||||
|
||||
if (FAILED(hr1) || FAILED(hr2))
|
||||
{
|
||||
free(pszSearchPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hFind = FindFirstFileUTF8(pszSearchPath, &FindData);
|
||||
|
||||
free(pszSearchPath);
|
||||
nAddins = 0;
|
||||
ppAddins = (FREERDP_ADDIN**)calloc(128, sizeof(FREERDP_ADDIN*));
|
||||
|
||||
if (!ppAddins)
|
||||
{
|
||||
FindClose(hFind);
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
return ppAddins;
|
||||
|
||||
do
|
||||
{
|
||||
char* cFileName = nullptr;
|
||||
BOOL used = FALSE;
|
||||
FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
|
||||
|
||||
if (!pAddin)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
cFileName =
|
||||
ConvertWCharNToUtf8Alloc(FindData.cFileName, ARRAYSIZE(FindData.cFileName), nullptr);
|
||||
if (!cFileName)
|
||||
goto skip;
|
||||
|
||||
nDashes = 0;
|
||||
for (size_t index = 0; cFileName[index]; index++)
|
||||
nDashes += (cFileName[index] == '-') ? 1 : 0;
|
||||
|
||||
if (nDashes == 1)
|
||||
{
|
||||
size_t len = 0;
|
||||
char* p[2] = WINPR_C_ARRAY_INIT;
|
||||
/* <name>-client.<extension> */
|
||||
p[0] = cFileName;
|
||||
p[1] = strchr(p[0], '-');
|
||||
if (!p[1])
|
||||
goto skip;
|
||||
p[1] += 1;
|
||||
|
||||
len = (size_t)(p[1] - p[0]);
|
||||
if (len < 1)
|
||||
{
|
||||
WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
|
||||
goto skip;
|
||||
}
|
||||
strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
|
||||
|
||||
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
|
||||
ppAddins[nAddins++] = pAddin;
|
||||
|
||||
used = TRUE;
|
||||
}
|
||||
else if (nDashes == 2)
|
||||
{
|
||||
size_t len = 0;
|
||||
char* p[4] = WINPR_C_ARRAY_INIT;
|
||||
/* <name>-client-<subsystem>.<extension> */
|
||||
p[0] = cFileName;
|
||||
p[1] = strchr(p[0], '-');
|
||||
if (!p[1])
|
||||
goto skip;
|
||||
p[1] += 1;
|
||||
p[2] = strchr(p[1], '-');
|
||||
if (!p[2])
|
||||
goto skip;
|
||||
p[2] += 1;
|
||||
p[3] = strchr(p[2], '.');
|
||||
if (!p[3])
|
||||
goto skip;
|
||||
p[3] += 1;
|
||||
|
||||
len = (size_t)(p[1] - p[0]);
|
||||
if (len < 1)
|
||||
{
|
||||
WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
|
||||
goto skip;
|
||||
}
|
||||
strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
|
||||
|
||||
len = (size_t)(p[3] - p[2]);
|
||||
if (len < 1)
|
||||
{
|
||||
WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
|
||||
goto skip;
|
||||
}
|
||||
strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1));
|
||||
|
||||
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
|
||||
ppAddins[nAddins++] = pAddin;
|
||||
|
||||
used = TRUE;
|
||||
}
|
||||
else if (nDashes == 3)
|
||||
{
|
||||
size_t len = 0;
|
||||
char* p[5] = WINPR_C_ARRAY_INIT;
|
||||
/* <name>-client-<subsystem>-<type>.<extension> */
|
||||
p[0] = cFileName;
|
||||
p[1] = strchr(p[0], '-');
|
||||
if (!p[1])
|
||||
goto skip;
|
||||
p[1] += 1;
|
||||
p[2] = strchr(p[1], '-');
|
||||
if (!p[2])
|
||||
goto skip;
|
||||
p[2] += 1;
|
||||
p[3] = strchr(p[2], '-');
|
||||
if (!p[3])
|
||||
goto skip;
|
||||
p[3] += 1;
|
||||
p[4] = strchr(p[3], '.');
|
||||
if (!p[4])
|
||||
goto skip;
|
||||
p[4] += 1;
|
||||
|
||||
len = (size_t)(p[1] - p[0]);
|
||||
if (len < 1)
|
||||
{
|
||||
WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
|
||||
goto skip;
|
||||
}
|
||||
strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
|
||||
|
||||
len = (size_t)(p[3] - p[2]);
|
||||
if (len < 1)
|
||||
{
|
||||
WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
|
||||
goto skip;
|
||||
}
|
||||
strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1));
|
||||
|
||||
len = (size_t)(p[4] - p[3]);
|
||||
if (len < 1)
|
||||
{
|
||||
WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
|
||||
goto skip;
|
||||
}
|
||||
strncpy(pAddin->cType, p[3], MIN(ARRAYSIZE(pAddin->cType), len - 1));
|
||||
|
||||
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
|
||||
pAddin->dwFlags |= FREERDP_ADDIN_TYPE;
|
||||
ppAddins[nAddins++] = pAddin;
|
||||
|
||||
used = TRUE;
|
||||
}
|
||||
|
||||
skip:
|
||||
free(cFileName);
|
||||
if (!used)
|
||||
free(pAddin);
|
||||
|
||||
} while (FindNextFileW(hFind, &FindData));
|
||||
|
||||
FindClose(hFind);
|
||||
ppAddins[nAddins] = nullptr;
|
||||
return ppAddins;
|
||||
error_out:
|
||||
FindClose(hFind);
|
||||
freerdp_channels_addin_list_free(ppAddins);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FREERDP_ADDIN** freerdp_channels_list_addins(LPCSTR pszName, LPCSTR pszSubsystem, LPCSTR pszType,
|
||||
DWORD dwFlags)
|
||||
{
|
||||
if (dwFlags & FREERDP_ADDIN_STATIC)
|
||||
return freerdp_channels_list_client_static_addins(pszName, pszSubsystem, pszType, dwFlags);
|
||||
else if (dwFlags & FREERDP_ADDIN_DYNAMIC)
|
||||
return freerdp_channels_list_dynamic_addins(pszName, pszSubsystem, pszType, dwFlags);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins)
|
||||
{
|
||||
if (!ppAddins)
|
||||
return;
|
||||
|
||||
for (size_t index = 0; ppAddins[index] != nullptr; index++)
|
||||
free(ppAddins[index]);
|
||||
|
||||
free((void*)ppAddins);
|
||||
}
|
||||
|
||||
extern const STATIC_ENTRY CLIENT_VirtualChannelEntryEx_TABLE[];
|
||||
|
||||
static BOOL freerdp_channels_is_virtual_channel_entry_ex(LPCSTR pszName)
|
||||
{
|
||||
for (size_t i = 0; CLIENT_VirtualChannelEntryEx_TABLE[i].name != nullptr; i++)
|
||||
{
|
||||
const STATIC_ENTRY* entry = &CLIENT_VirtualChannelEntryEx_TABLE[i];
|
||||
|
||||
if (!strncmp(entry->name, pszName, MAX_PATH))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LPCSTR pszSubsystem,
|
||||
LPCSTR pszType, DWORD dwFlags)
|
||||
{
|
||||
const STATIC_ADDIN_TABLE* table = CLIENT_STATIC_ADDIN_TABLE;
|
||||
const char* type = nullptr;
|
||||
|
||||
if (!pszName)
|
||||
return nullptr;
|
||||
|
||||
if (dwFlags & FREERDP_ADDIN_CHANNEL_DYNAMIC)
|
||||
type = "DVCPluginEntry";
|
||||
else if (dwFlags & FREERDP_ADDIN_CHANNEL_DEVICE)
|
||||
type = "DeviceServiceEntry";
|
||||
else if (dwFlags & FREERDP_ADDIN_CHANNEL_STATIC)
|
||||
{
|
||||
if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX)
|
||||
type = "VirtualChannelEntryEx";
|
||||
else
|
||||
type = "VirtualChannelEntry";
|
||||
}
|
||||
|
||||
for (; table->name != nullptr; table++)
|
||||
{
|
||||
if (strncmp(table->name, pszName, MAX_PATH) == 0)
|
||||
{
|
||||
if (type && (strncmp(table->type, type, MAX_PATH) != 0))
|
||||
continue;
|
||||
|
||||
if (pszSubsystem != nullptr)
|
||||
{
|
||||
const STATIC_SUBSYSTEM_ENTRY* subsystems = table->table;
|
||||
|
||||
for (; subsystems->name != nullptr; subsystems++)
|
||||
{
|
||||
/* If the pszSubsystem is an empty string use the default backend. */
|
||||
if ((strnlen(pszSubsystem, 1) ==
|
||||
0) || /* we only want to know if strnlen is > 0 */
|
||||
(strncmp(subsystems->name, pszSubsystem, MAX_PATH) == 0))
|
||||
{
|
||||
static_subsystem_entry_fn_t fkt = subsystems->entry;
|
||||
|
||||
if (pszType)
|
||||
{
|
||||
if (strncmp(subsystems->type, pszType, MAX_PATH) == 0)
|
||||
return WINPR_FUNC_PTR_CAST(fkt, PVIRTUALCHANNELENTRY);
|
||||
}
|
||||
else
|
||||
return WINPR_FUNC_PTR_CAST(fkt, PVIRTUALCHANNELENTRY);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX)
|
||||
{
|
||||
if (!freerdp_channels_is_virtual_channel_entry_ex(pszName))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return table->entry.csevc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
wMessageQueue* queue;
|
||||
wStream* data_in;
|
||||
HANDLE thread;
|
||||
char* channel_name;
|
||||
rdpContext* ctx;
|
||||
LPVOID userdata;
|
||||
MsgHandler msg_handler;
|
||||
} msg_proc_internals;
|
||||
|
||||
static DWORD WINAPI channel_client_thread_proc(LPVOID userdata)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
wStream* data = nullptr;
|
||||
wMessage message = WINPR_C_ARRAY_INIT;
|
||||
msg_proc_internals* internals = userdata;
|
||||
|
||||
WINPR_ASSERT(internals);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!MessageQueue_Wait(internals->queue))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Wait failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
if (!MessageQueue_Peek(internals->queue, &message, TRUE))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Peek failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (message.id == WMQ_QUIT)
|
||||
break;
|
||||
|
||||
if (message.id == 0)
|
||||
{
|
||||
data = (wStream*)message.wParam;
|
||||
|
||||
if ((error = internals->msg_handler(internals->userdata, data)))
|
||||
{
|
||||
WLog_ERR(TAG, "msg_handler failed with error %" PRIu32 "!", error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (error && internals->ctx)
|
||||
{
|
||||
char msg[128];
|
||||
(void)_snprintf(msg, 127,
|
||||
"%s_virtual_channel_client_thread reported an"
|
||||
" error",
|
||||
internals->channel_name);
|
||||
setChannelError(internals->ctx, error, msg);
|
||||
}
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void free_msg(void* obj)
|
||||
{
|
||||
wMessage* msg = (wMessage*)obj;
|
||||
|
||||
if (msg && (msg->id == 0))
|
||||
{
|
||||
wStream* s = (wStream*)msg->wParam;
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void channel_client_handler_free(msg_proc_internals* internals)
|
||||
{
|
||||
if (!internals)
|
||||
return;
|
||||
|
||||
if (internals->thread)
|
||||
(void)CloseHandle(internals->thread);
|
||||
MessageQueue_Free(internals->queue);
|
||||
Stream_Free(internals->data_in, TRUE);
|
||||
free(internals->channel_name);
|
||||
free(internals);
|
||||
}
|
||||
|
||||
/* Create message queue and thread or not, depending on settings */
|
||||
void* channel_client_create_handler(rdpContext* ctx, LPVOID userdata, MsgHandler msg_handler,
|
||||
const char* channel_name)
|
||||
{
|
||||
msg_proc_internals* internals = calloc(1, sizeof(msg_proc_internals));
|
||||
if (!internals)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return nullptr;
|
||||
}
|
||||
internals->msg_handler = msg_handler;
|
||||
internals->userdata = userdata;
|
||||
if (channel_name)
|
||||
{
|
||||
internals->channel_name = _strdup(channel_name);
|
||||
if (!internals->channel_name)
|
||||
goto fail;
|
||||
}
|
||||
WINPR_ASSERT(ctx);
|
||||
WINPR_ASSERT(ctx->settings);
|
||||
internals->ctx = ctx;
|
||||
if ((freerdp_settings_get_uint32(ctx->settings, FreeRDP_ThreadingFlags) &
|
||||
THREADING_FLAGS_DISABLE_THREADS) == 0)
|
||||
{
|
||||
wObject obj = WINPR_C_ARRAY_INIT;
|
||||
obj.fnObjectFree = free_msg;
|
||||
internals->queue = MessageQueue_New(&obj);
|
||||
if (!internals->queue)
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_New failed!");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(internals->thread = CreateThread(nullptr, 0, channel_client_thread_proc,
|
||||
(void*)internals, 0, nullptr)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return internals;
|
||||
|
||||
fail:
|
||||
channel_client_handler_free(internals);
|
||||
return nullptr;
|
||||
}
|
||||
/* post a message in the queue or directly call the processing handler */
|
||||
UINT channel_client_post_message(void* MsgsHandle, LPVOID pData, UINT32 dataLength,
|
||||
UINT32 totalLength, UINT32 dataFlags)
|
||||
{
|
||||
msg_proc_internals* internals = MsgsHandle;
|
||||
wStream* data_in = nullptr;
|
||||
|
||||
if (!internals)
|
||||
{
|
||||
/* TODO: return some error here */
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
|
||||
{
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
if (dataFlags & CHANNEL_FLAG_FIRST)
|
||||
{
|
||||
if (internals->data_in)
|
||||
{
|
||||
if (!Stream_EnsureCapacity(internals->data_in, totalLength))
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
else
|
||||
internals->data_in = Stream_New(nullptr, totalLength);
|
||||
}
|
||||
|
||||
if (!(data_in = internals->data_in))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
|
||||
{
|
||||
Stream_Free(internals->data_in, TRUE);
|
||||
internals->data_in = nullptr;
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
Stream_Write(data_in, pData, dataLength);
|
||||
|
||||
if (dataFlags & CHANNEL_FLAG_LAST)
|
||||
{
|
||||
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
|
||||
{
|
||||
WLog_ERR(TAG, "%s_plugin_process_received: read error", internals->channel_name);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
internals->data_in = nullptr;
|
||||
Stream_SealLength(data_in);
|
||||
Stream_ResetPosition(data_in);
|
||||
|
||||
if ((freerdp_settings_get_uint32(internals->ctx->settings, FreeRDP_ThreadingFlags) &
|
||||
THREADING_FLAGS_DISABLE_THREADS) != 0)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
if ((error = internals->msg_handler(internals->userdata, data_in)))
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"msg_handler failed with error"
|
||||
" %" PRIu32 "!",
|
||||
error);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
else if (!MessageQueue_Post(internals->queue, nullptr, 0, (void*)data_in, nullptr))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Post failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
/* Tear down queue and thread */
|
||||
UINT channel_client_quit_handler(void* MsgsHandle)
|
||||
{
|
||||
msg_proc_internals* internals = MsgsHandle;
|
||||
UINT rc = 0;
|
||||
if (!internals)
|
||||
{
|
||||
/* TODO: return some error here */
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(internals->ctx);
|
||||
WINPR_ASSERT(internals->ctx->settings);
|
||||
|
||||
if ((freerdp_settings_get_uint32(internals->ctx->settings, FreeRDP_ThreadingFlags) &
|
||||
THREADING_FLAGS_DISABLE_THREADS) == 0)
|
||||
{
|
||||
if (internals->queue && internals->thread)
|
||||
{
|
||||
if (MessageQueue_PostQuit(internals->queue, 0) &&
|
||||
(WaitForSingleObject(internals->thread, INFINITE) == WAIT_FAILED))
|
||||
{
|
||||
rc = GetLastError();
|
||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
channel_client_handler_free(internals);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
36
third_party/FreeRDP/channels/client/addin.h
vendored
Normal file
36
third_party/FreeRDP/channels/client/addin.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Channel Addins
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/api.h>
|
||||
|
||||
typedef UINT (*MsgHandler)(LPVOID userdata, wStream* data);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_API void* channel_client_create_handler(rdpContext* ctx, LPVOID userdata,
|
||||
MsgHandler handler, const char* channel_name);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL UINT channel_client_post_message(void* MsgsHandle, LPVOID pData, UINT32 dataLength,
|
||||
UINT32 totalLength, UINT32 dataFlags);
|
||||
|
||||
FREERDP_LOCAL UINT channel_client_quit_handler(void* MsgsHandle);
|
||||
215
third_party/FreeRDP/channels/client/generic_dynvc.c
vendored
Normal file
215
third_party/FreeRDP/channels/client/generic_dynvc.c
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Dynamic channel
|
||||
*
|
||||
* Copyright 2022 David Fort <contact@hardening-consulting.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
|
||||
#define TAG FREERDP_TAG("genericdynvc")
|
||||
|
||||
static UINT generic_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
||||
IWTSVirtualChannel* pChannel,
|
||||
WINPR_ATTR_UNUSED BYTE* Data,
|
||||
WINPR_ATTR_UNUSED BOOL* pbAccept,
|
||||
IWTSVirtualChannelCallback** ppCallback)
|
||||
{
|
||||
GENERIC_CHANNEL_CALLBACK* callback = nullptr;
|
||||
GENERIC_DYNVC_PLUGIN* plugin = nullptr;
|
||||
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
|
||||
|
||||
if (!listener_callback || !listener_callback->plugin)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
plugin = (GENERIC_DYNVC_PLUGIN*)listener_callback->plugin;
|
||||
WLog_Print(plugin->log, WLOG_TRACE, "...");
|
||||
|
||||
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, plugin->channelCallbackSize);
|
||||
if (!callback)
|
||||
{
|
||||
WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* implant configured channel callbacks */
|
||||
callback->iface = *plugin->channel_callbacks;
|
||||
|
||||
callback->plugin = listener_callback->plugin;
|
||||
callback->channel_mgr = listener_callback->channel_mgr;
|
||||
callback->channel = pChannel;
|
||||
|
||||
listener_callback->channel_callback = callback;
|
||||
listener_callback->channel = pChannel;
|
||||
|
||||
*ppCallback = &callback->iface;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static UINT generic_dynvc_plugin_initialize(IWTSPlugin* pPlugin,
|
||||
IWTSVirtualChannelManager* pChannelMgr)
|
||||
{
|
||||
UINT rc = 0;
|
||||
GENERIC_LISTENER_CALLBACK* listener_callback = nullptr;
|
||||
GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
|
||||
|
||||
if (!plugin)
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||
|
||||
if (!pChannelMgr)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (plugin->initialized)
|
||||
{
|
||||
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", plugin->dynvc_name);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
WLog_Print(plugin->log, WLOG_TRACE, "...");
|
||||
listener_callback = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
|
||||
if (!listener_callback)
|
||||
{
|
||||
WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
plugin->listener_callback = listener_callback;
|
||||
listener_callback->iface.OnNewChannelConnection = generic_on_new_channel_connection;
|
||||
listener_callback->plugin = pPlugin;
|
||||
listener_callback->channel_mgr = pChannelMgr;
|
||||
rc = pChannelMgr->CreateListener(pChannelMgr, plugin->dynvc_name, 0, &listener_callback->iface,
|
||||
&plugin->listener);
|
||||
|
||||
plugin->listener->pInterface = plugin->iface.pInterface;
|
||||
plugin->initialized = (rc == CHANNEL_RC_OK);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static UINT generic_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
{
|
||||
GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!plugin)
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||
|
||||
WLog_Print(plugin->log, WLOG_TRACE, "...");
|
||||
|
||||
/* some channels (namely rdpei), look at initialized to see if they should continue to run */
|
||||
plugin->initialized = FALSE;
|
||||
|
||||
if (plugin->terminatePluginFn)
|
||||
plugin->terminatePluginFn(plugin);
|
||||
|
||||
if (plugin->listener_callback)
|
||||
{
|
||||
IWTSVirtualChannelManager* mgr = plugin->listener_callback->channel_mgr;
|
||||
if (mgr)
|
||||
IFCALL(mgr->DestroyListener, mgr, plugin->listener);
|
||||
}
|
||||
|
||||
free(plugin->listener_callback);
|
||||
free(plugin->dynvc_name);
|
||||
free(plugin);
|
||||
return error;
|
||||
}
|
||||
|
||||
static UINT generic_dynvc_plugin_attached(IWTSPlugin* pPlugin)
|
||||
{
|
||||
GENERIC_DYNVC_PLUGIN* pluginn = (GENERIC_DYNVC_PLUGIN*)pPlugin;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!pluginn)
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||
|
||||
pluginn->attached = TRUE;
|
||||
return error;
|
||||
}
|
||||
|
||||
static UINT generic_dynvc_plugin_detached(IWTSPlugin* pPlugin)
|
||||
{
|
||||
GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!plugin)
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||
|
||||
plugin->attached = FALSE;
|
||||
return error;
|
||||
}
|
||||
|
||||
UINT freerdp_generic_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* logTag,
|
||||
const char* name, size_t pluginSize, size_t channelCallbackSize,
|
||||
const IWTSVirtualChannelCallback* channel_callbacks,
|
||||
DYNVC_PLUGIN_INIT_FN initPluginFn,
|
||||
DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn)
|
||||
{
|
||||
GENERIC_DYNVC_PLUGIN* plugin = nullptr;
|
||||
UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
|
||||
WINPR_ASSERT(pEntryPoints);
|
||||
WINPR_ASSERT(pEntryPoints->GetPlugin);
|
||||
WINPR_ASSERT(logTag);
|
||||
WINPR_ASSERT(name);
|
||||
WINPR_ASSERT(pluginSize >= sizeof(*plugin));
|
||||
WINPR_ASSERT(channelCallbackSize >= sizeof(GENERIC_CHANNEL_CALLBACK));
|
||||
|
||||
plugin = (GENERIC_DYNVC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, name);
|
||||
if (plugin != nullptr)
|
||||
return CHANNEL_RC_ALREADY_INITIALIZED;
|
||||
|
||||
plugin = (GENERIC_DYNVC_PLUGIN*)calloc(1, pluginSize);
|
||||
if (!plugin)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
plugin->log = WLog_Get(logTag);
|
||||
plugin->attached = TRUE;
|
||||
plugin->channel_callbacks = channel_callbacks;
|
||||
plugin->channelCallbackSize = channelCallbackSize;
|
||||
plugin->iface.Initialize = generic_dynvc_plugin_initialize;
|
||||
plugin->iface.Connected = nullptr;
|
||||
plugin->iface.Disconnected = nullptr;
|
||||
plugin->iface.Terminated = generic_plugin_terminated;
|
||||
plugin->iface.Attached = generic_dynvc_plugin_attached;
|
||||
plugin->iface.Detached = generic_dynvc_plugin_detached;
|
||||
plugin->terminatePluginFn = terminatePluginFn;
|
||||
|
||||
if (initPluginFn)
|
||||
{
|
||||
rdpSettings* settings = pEntryPoints->GetRdpSettings(pEntryPoints);
|
||||
rdpContext* context = pEntryPoints->GetRdpContext(pEntryPoints);
|
||||
|
||||
error = initPluginFn(plugin, context, settings);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
goto error;
|
||||
}
|
||||
|
||||
plugin->dynvc_name = _strdup(name);
|
||||
if (!plugin->dynvc_name)
|
||||
goto error;
|
||||
|
||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, name, &plugin->iface);
|
||||
if (error == CHANNEL_RC_OK)
|
||||
return error;
|
||||
|
||||
error:
|
||||
generic_plugin_terminated(&plugin->iface);
|
||||
return error;
|
||||
}
|
||||
33
third_party/FreeRDP/channels/client/tables.c.in
vendored
Normal file
33
third_party/FreeRDP/channels/client/tables.c.in
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Static Entry Point Tables
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/dvc.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
#include "tables.h"
|
||||
|
||||
${CLIENT_STATIC_TYPEDEFS}
|
||||
${CLIENT_STATIC_ENTRY_IMPORTS}
|
||||
${CLIENT_STATIC_SUBSYSTEM_IMPORTS}
|
||||
${CLIENT_STATIC_ENTRY_TABLES}
|
||||
${CLIENT_STATIC_ENTRY_TABLES_LIST}
|
||||
${CLIENT_STATIC_SUBSYSTEM_TABLES}
|
||||
${CLIENT_STATIC_ADDIN_TABLE}
|
||||
|
||||
107
third_party/FreeRDP/channels/client/tables.h
vendored
Normal file
107
third_party/FreeRDP/channels/client/tables.h
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Static Entry Point Tables
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <winpr/platform.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <freerdp/svc.h>
|
||||
#include <freerdp/dvc.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
|
||||
/* The 'entry' function pointers have variable arguments. */
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_STRICT_PROTOTYPES
|
||||
|
||||
typedef UINT(VCAPITYPE* static_entry_fn_t)();
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
WINPR_ATTR_NODISCARD static_entry_fn_t entry;
|
||||
} STATIC_ENTRY;
|
||||
|
||||
typedef BOOL(VCAPITYPE* static_entry_vc_fn_t)(PCHANNEL_ENTRY_POINTS);
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
WINPR_ATTR_NODISCARD static_entry_vc_fn_t entry;
|
||||
} STATIC_ENTRY_VC;
|
||||
|
||||
typedef BOOL(VCAPITYPE* static_entry_vcex_fn_t)(PCHANNEL_ENTRY_POINTS_EX, PVOID);
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
WINPR_ATTR_NODISCARD static_entry_vcex_fn_t entry;
|
||||
} STATIC_ENTRY_VCEX;
|
||||
|
||||
typedef UINT(VCAPITYPE* static_entry_dvc_fn_t)(IDRDYNVC_ENTRY_POINTS*);
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
WINPR_ATTR_NODISCARD static_entry_dvc_fn_t entry;
|
||||
} STATIC_ENTRY_DVC;
|
||||
|
||||
typedef UINT(VCAPITYPE* static_entry_dse_fn_t)(PDEVICE_SERVICE_ENTRY_POINTS);
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
WINPR_ATTR_NODISCARD static_entry_dse_fn_t entry;
|
||||
} STATIC_ENTRY_DSE;
|
||||
|
||||
typedef union
|
||||
{
|
||||
const STATIC_ENTRY* cse;
|
||||
const STATIC_ENTRY_VC* csevc;
|
||||
const STATIC_ENTRY_VCEX* csevcex;
|
||||
const STATIC_ENTRY_DVC* csedvc;
|
||||
const STATIC_ENTRY_DSE* csedse;
|
||||
} static_entry_u;
|
||||
|
||||
typedef union
|
||||
{
|
||||
WINPR_ATTR_NODISCARD static_entry_fn_t cse;
|
||||
WINPR_ATTR_NODISCARD static_entry_vc_fn_t csevc;
|
||||
WINPR_ATTR_NODISCARD static_entry_vcex_fn_t csevcex;
|
||||
WINPR_ATTR_NODISCARD static_entry_dvc_fn_t csedvc;
|
||||
WINPR_ATTR_NODISCARD static_entry_dse_fn_t csedse;
|
||||
} static_entry_fn_u;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
static_entry_u table;
|
||||
} STATIC_ENTRY_TABLE;
|
||||
|
||||
typedef UINT(VCAPITYPE* static_subsystem_entry_fn_t)(void*);
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const char* type;
|
||||
WINPR_ATTR_NODISCARD static_subsystem_entry_fn_t entry;
|
||||
} STATIC_SUBSYSTEM_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const char* type;
|
||||
static_entry_fn_u entry;
|
||||
const STATIC_SUBSYSTEM_ENTRY* table;
|
||||
} STATIC_ADDIN_TABLE;
|
||||
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
Reference in New Issue
Block a user