mirror of
https://github.com/FreeRDP/FreeRDP.git
synced 2025-06-03 00:00:20 +00:00
server: proxy: rewrite modules API
* Add support for C++ plugins. * Seperate between a "module" and a "plugin": a module is a shared library that exposes a function called "proxy_module_entry_point". This function gets a parameter to `proxyPluginsManager*`, which can be used to register plugins. * Refine the API of the modules infrastructure: * use proxyData* instead of rdpContext* when firing a hook or calling a filter. * use clearer names. * Instead of having to specify a path for each module to be loaded in the configuration, the proxy now loads modules from specificed directory, using the CMAKE variable PROXY_PLUGINDIR. * Add an option to specify required plugins: plugins that the proxy wouldn't start without having them fully loaded.
This commit is contained in:
parent
1543664343
commit
b2fad50cd3
@ -982,6 +982,14 @@ set(FREERDP_ADDIN_PATH "${FREERDP_PLUGIN_PATH}")
|
|||||||
# Path to put extensions
|
# Path to put extensions
|
||||||
set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}/extensions")
|
set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}/extensions")
|
||||||
|
|
||||||
|
# Proxy plugins path
|
||||||
|
if(NOT DEFINED PROXY_PLUGINDIR)
|
||||||
|
message("using default plugins location")
|
||||||
|
set(FREERDP_PROXY_PLUGINDIR "${CMAKE_BINARY_DIR}/server/proxy/plugins")
|
||||||
|
else()
|
||||||
|
set(FREERDP_PROXY_PLUGINDIR "${PROXY_PLUGINDIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Include directories
|
# Include directories
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
|
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
|
||||||
|
@ -17,4 +17,6 @@
|
|||||||
#define FREERDP_VENDOR_STRING "${VENDOR}"
|
#define FREERDP_VENDOR_STRING "${VENDOR}"
|
||||||
#define FREERDP_PRODUCT_STRING "${PRODUCT}"
|
#define FREERDP_PRODUCT_STRING "${PRODUCT}"
|
||||||
|
|
||||||
|
#define FREERDP_PROXY_PLUGINDIR "${FREERDP_PROXY_PLUGINDIR}"
|
||||||
|
|
||||||
#endif /* FREERDP_BUILD_CONFIG_H */
|
#endif /* FREERDP_BUILD_CONFIG_H */
|
||||||
|
@ -40,5 +40,5 @@ RemoteApp = TRUE
|
|||||||
TextOnly = FALSE
|
TextOnly = FALSE
|
||||||
MaxTextLength = 10 # 0 for no limit.
|
MaxTextLength = 10 # 0 for no limit.
|
||||||
|
|
||||||
[Modules]
|
[Plugins]
|
||||||
Demo = "modules/demo/libdemo.so"
|
Required = "demo"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "pf_log.h"
|
#include "pf_log.h"
|
||||||
#include "pf_modules.h"
|
#include "pf_modules.h"
|
||||||
|
|
||||||
|
#include <freerdp/build-config.h>
|
||||||
#include <winpr/collections.h>
|
#include <winpr/collections.h>
|
||||||
|
|
||||||
#define TAG PROXY_TAG("server")
|
#define TAG PROXY_TAG("server")
|
||||||
@ -40,8 +41,13 @@ int main(int argc, char* argv[])
|
|||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
cfg = argv[1];
|
cfg = argv[1];
|
||||||
|
|
||||||
if (!pf_modules_init())
|
if (!pf_modules_init(FREERDP_PROXY_PLUGINDIR))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "failed to initialize proxy plugins!");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
pf_modules_list_loaded_plugins();
|
||||||
|
|
||||||
if (!pf_server_config_load(cfg, config))
|
if (!pf_server_config_load(cfg, config))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1,4 +1,29 @@
|
|||||||
|
#
|
||||||
|
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
# FreeRDP Proxy Server Demo C++ Module
|
||||||
|
#
|
||||||
|
# Copyright 2019 Kobi Mizrachi <kmizrachi18@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.
|
||||||
|
#
|
||||||
|
|
||||||
add_library(demo SHARED
|
set(PLUGIN_NAME "proxy-demo-plugin")
|
||||||
demo.c
|
|
||||||
|
add_library(${PLUGIN_NAME} MODULE
|
||||||
|
demo.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(${PLUGIN_NAME} PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(${PLUGIN_NAME} PROPERTIES NO_SONAME 1)
|
||||||
|
set_target_properties(${PLUGIN_NAME} PROPERTIES
|
||||||
|
LIBRARY_OUTPUT_DIRECTORY "${FREERDP_PROXY_PLUGINDIR}")
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
||||||
* FreeRDP Proxy Server
|
|
||||||
*
|
|
||||||
* Copyright 2019 Kobi Mizrachi <kmizrachi18@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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "modules_api.h"
|
|
||||||
|
|
||||||
static BOOL demo_filter_keyboard_event(moduleOperations* module, rdpContext* context, void* param)
|
|
||||||
{
|
|
||||||
proxyKeyboardEventInfo* event_data = (proxyKeyboardEventInfo*)param;
|
|
||||||
WINPR_UNUSED(event_data);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL demo_filter_mouse_event(moduleOperations* module, rdpContext* context, void* param)
|
|
||||||
{
|
|
||||||
proxyMouseEventInfo* event_data = (proxyMouseEventInfo*)param;
|
|
||||||
|
|
||||||
if (event_data->x % 100 == 0)
|
|
||||||
{
|
|
||||||
printf("filter_demo: mouse x is currently %" PRIu16 "\n", event_data->x);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL module_init(moduleOperations* module)
|
|
||||||
{
|
|
||||||
module->KeyboardEvent = demo_filter_keyboard_event;
|
|
||||||
module->MouseEvent = demo_filter_mouse_event;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL module_exit(moduleOperations* module)
|
|
||||||
{
|
|
||||||
printf("bye bye\n");
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
71
server/proxy/modules/demo/demo.cpp
Normal file
71
server/proxy/modules/demo/demo.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* FreeRDP Proxy Server Demo C++ Module
|
||||||
|
*
|
||||||
|
* Copyright 2019 Kobi Mizrachi <kmizrachi18@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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "modules_api.h"
|
||||||
|
|
||||||
|
#define TAG MODULE_TAG("demo")
|
||||||
|
|
||||||
|
static constexpr char plugin_name[] = "demo";
|
||||||
|
static constexpr char plugin_desc[] = "this is a test plugin";
|
||||||
|
|
||||||
|
static proxyPluginsManager* g_plugins_manager = NULL;
|
||||||
|
|
||||||
|
static BOOL demo_filter_keyboard_event(proxyData* pdata, void* param)
|
||||||
|
{
|
||||||
|
auto event_data = static_cast<proxyKeyboardEventInfo*>(param);
|
||||||
|
if (event_data == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (event_data->rdp_scan_code == RDP_SCANCODE_KEY_B)
|
||||||
|
{
|
||||||
|
/* user typed 'B', that means bye :) */
|
||||||
|
std::cout << "C++ demo plugin: aborting connection" << std::endl;
|
||||||
|
g_plugins_manager->AbortConnect(pdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL demo_plugin_unload()
|
||||||
|
{
|
||||||
|
std::cout << "C++ demo plugin: unloading..." << std::endl;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static proxyPlugin demo_plugin = {
|
||||||
|
plugin_name, /* name */
|
||||||
|
plugin_desc, /* description */
|
||||||
|
NULL, /* ClientPreConnect */
|
||||||
|
NULL, /* ClientLoginFailure */
|
||||||
|
NULL, /* ServerPostConnect */
|
||||||
|
NULL, /* ServerChannelsInit */
|
||||||
|
NULL, /* ServerChannelsFree */
|
||||||
|
demo_filter_keyboard_event, /* KeyboardEvent */
|
||||||
|
NULL, /* MouseEvent */
|
||||||
|
demo_plugin_unload /* PluginUnload */
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager)
|
||||||
|
{
|
||||||
|
g_plugins_manager = plugins_manager;
|
||||||
|
|
||||||
|
return plugins_manager->RegisterPlugin(&demo_plugin);
|
||||||
|
}
|
@ -24,78 +24,89 @@
|
|||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <winpr/winpr.h>
|
#include <winpr/winpr.h>
|
||||||
|
|
||||||
#define PROXY_API FREERDP_API
|
#include "../pf_context.h"
|
||||||
|
|
||||||
typedef struct module_operations moduleOperations;
|
#define MODULE_TAG(module) "proxy.modules." module
|
||||||
|
|
||||||
/* used for filtering */
|
/* hook callback. should return TRUE on success or FALSE on error. */
|
||||||
typedef BOOL (*proxyFilterFn)(moduleOperations*, rdpContext*, void*);
|
typedef BOOL (*proxyHookFn)(proxyData*);
|
||||||
|
|
||||||
/* used for hooks */
|
|
||||||
typedef BOOL (*proxyHookFn)(moduleOperations*, rdpContext*);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* used for per-session info.
|
* Filter callback:
|
||||||
*
|
* It MUST return TRUE if the related event should be proxied,
|
||||||
* each module is allowed to store data per session.
|
* or FALSE if it should be ignored.
|
||||||
* it is useful, for example, when a module wants to create a server channel in runtime,
|
|
||||||
* or to save information about a session (for example, the count of mouse clicks in the last
|
|
||||||
* minute), and then do something with this information (maybe abort the connection).
|
|
||||||
*/
|
*/
|
||||||
typedef BOOL (*moduleSetSessionData)(moduleOperations*, rdpContext*, void*);
|
typedef BOOL (*proxyFilterFn)(proxyData*, void*);
|
||||||
typedef void* (*moduleGetSessionData)(moduleOperations*, rdpContext*);
|
|
||||||
|
|
||||||
/*
|
/* describes a plugin: name, description and callbacks to execute. */
|
||||||
* used for connection management. when a module wants to forcibly close a connection, it should
|
typedef struct proxy_plugin
|
||||||
* call this method.
|
|
||||||
*/
|
|
||||||
typedef void (*moduleAbortConnect)(moduleOperations*, rdpContext*);
|
|
||||||
|
|
||||||
typedef struct connection_info connectionInfo;
|
|
||||||
typedef struct proxy_keyboard_event_info proxyKeyboardEventInfo;
|
|
||||||
typedef struct proxy_mouse_event_info proxyMouseEventInfo;
|
|
||||||
|
|
||||||
/* represents a set of operations that a module can do */
|
|
||||||
struct module_operations
|
|
||||||
{
|
{
|
||||||
/* per-session API. a module must not change these function pointers. */
|
const char* name; /* unique module name */
|
||||||
moduleSetSessionData SetSessionData;
|
const char* description; /* module description */
|
||||||
moduleGetSessionData GetSessionData;
|
|
||||||
moduleAbortConnect AbortConnect;
|
|
||||||
|
|
||||||
/* proxy hooks. a module can set these function pointers to register hooks. */
|
/* proxy hooks. a module can set these function pointers to register hooks */
|
||||||
proxyHookFn ClientPreConnect;
|
proxyHookFn ClientPreConnect;
|
||||||
|
proxyHookFn ClientLoginFailure;
|
||||||
|
proxyHookFn ServerPostConnect;
|
||||||
proxyHookFn ServerChannelsInit;
|
proxyHookFn ServerChannelsInit;
|
||||||
proxyHookFn ServerChannelsFree;
|
proxyHookFn ServerChannelsFree;
|
||||||
|
|
||||||
/* proxy filters a module can set these function pointers to register filters. */
|
/* proxy filters. a module can set these function pointers to register filters */
|
||||||
proxyFilterFn KeyboardEvent;
|
proxyFilterFn KeyboardEvent;
|
||||||
proxyFilterFn MouseEvent;
|
proxyFilterFn MouseEvent;
|
||||||
};
|
|
||||||
|
BOOL (*PluginUnload)();
|
||||||
|
} proxyPlugin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main API for use by external modules.
|
||||||
|
* Supports:
|
||||||
|
* - Registering a plugin.
|
||||||
|
* - Setting/getting plugin's per-session specific data.
|
||||||
|
* - Aborting a session.
|
||||||
|
*/
|
||||||
|
typedef struct proxy_plugins_manager
|
||||||
|
{
|
||||||
|
/* used for registering a fresh new proxy plugin. */
|
||||||
|
BOOL (*RegisterPlugin)(proxyPlugin* plugin);
|
||||||
|
|
||||||
|
/* used for setting plugin's per-session info. */
|
||||||
|
BOOL (*SetPluginData)(const char*, proxyData*, void*);
|
||||||
|
|
||||||
|
/* used for getting plugin's per-session info. */
|
||||||
|
void* (*GetPluginData)(const char*, proxyData*);
|
||||||
|
|
||||||
|
/* used for aborting a session. */
|
||||||
|
void (*AbortConnect)(proxyData*);
|
||||||
|
} proxyPluginsManager;
|
||||||
|
|
||||||
/* filter events parameters */
|
/* filter events parameters */
|
||||||
#define WINPR_PACK_PUSH
|
#define WINPR_PACK_PUSH
|
||||||
#include <winpr/pack.h>
|
#include <winpr/pack.h>
|
||||||
struct proxy_keyboard_event_info
|
typedef struct proxy_keyboard_event_info
|
||||||
{
|
{
|
||||||
UINT16 flags;
|
UINT16 flags;
|
||||||
UINT16 rdp_scan_code;
|
UINT16 rdp_scan_code;
|
||||||
};
|
} proxyKeyboardEventInfo;
|
||||||
|
|
||||||
struct proxy_mouse_event_info
|
typedef struct proxy_mouse_event_info
|
||||||
{
|
{
|
||||||
UINT16 flags;
|
UINT16 flags;
|
||||||
UINT16 x;
|
UINT16 x;
|
||||||
UINT16 y;
|
UINT16 y;
|
||||||
};
|
} proxyMouseEventInfo;
|
||||||
#define WINPR_PACK_POP
|
#define WINPR_PACK_POP
|
||||||
#include <winpr/pack.h>
|
#include <winpr/pack.h>
|
||||||
|
|
||||||
/*
|
#ifdef __cplusplus
|
||||||
* these two functions must be implemented by any proxy module.
|
extern "C"
|
||||||
* module_init: used for module initialization, hooks and filters registration.
|
{
|
||||||
*/
|
#endif
|
||||||
PROXY_API BOOL module_init(moduleOperations* module);
|
|
||||||
PROXY_API BOOL module_exit(moduleOperations* module);
|
FREERDP_API BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* FREERDP_SERVER_PROXY_MODULES_API_H */
|
#endif /* FREERDP_SERVER_PROXY_MODULES_API_H */
|
||||||
|
@ -230,7 +230,7 @@ BOOL pf_server_channels_init(pServerContext* ps)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pf_modules_run_hook(HOOK_TYPE_SERVER_CHANNELS_INIT, context);
|
return pf_modules_run_hook(HOOK_TYPE_SERVER_CHANNELS_INIT, ps->pdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pf_server_channels_free(pServerContext* ps)
|
void pf_server_channels_free(pServerContext* ps)
|
||||||
@ -265,5 +265,5 @@ void pf_server_channels_free(pServerContext* ps)
|
|||||||
ps->rail = NULL;
|
ps->rail = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pf_modules_run_hook(HOOK_TYPE_SERVER_CHANNELS_FREE, (rdpContext*)ps);
|
pf_modules_run_hook(HOOK_TYPE_SERVER_CHANNELS_FREE, ps->pdata);
|
||||||
}
|
}
|
||||||
|
@ -343,6 +343,7 @@ static BOOL pf_client_connect(freerdp* instance)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
LOG_ERR(TAG, pc, "failed to connect with NLA. retrying to connect without NLA");
|
LOG_ERR(TAG, pc, "failed to connect with NLA. retrying to connect without NLA");
|
||||||
|
pf_modules_run_hook(HOOK_TYPE_CLIENT_LOGIN_FAILURE, pc->pdata);
|
||||||
|
|
||||||
if (!pf_client_connect_without_nla(pc))
|
if (!pf_client_connect_without_nla(pc))
|
||||||
{
|
{
|
||||||
@ -366,7 +367,6 @@ static DWORD WINAPI pf_client_thread_proc(LPVOID arg)
|
|||||||
{
|
{
|
||||||
freerdp* instance = (freerdp*)arg;
|
freerdp* instance = (freerdp*)arg;
|
||||||
pClientContext* pc = (pClientContext*)instance->context;
|
pClientContext* pc = (pClientContext*)instance->context;
|
||||||
pServerContext* ps = pc->pdata->ps;
|
|
||||||
proxyData* pdata = pc->pdata;
|
proxyData* pdata = pc->pdata;
|
||||||
DWORD nCount;
|
DWORD nCount;
|
||||||
DWORD status;
|
DWORD status;
|
||||||
@ -381,7 +381,7 @@ static DWORD WINAPI pf_client_thread_proc(LPVOID arg)
|
|||||||
*/
|
*/
|
||||||
handles[64] = pdata->abort_event;
|
handles[64] = pdata->abort_event;
|
||||||
|
|
||||||
if (!pf_modules_run_hook(HOOK_TYPE_CLIENT_PRE_CONNECT, (rdpContext*)ps))
|
if (!pf_modules_run_hook(HOOK_TYPE_CLIENT_PRE_CONNECT, pdata))
|
||||||
{
|
{
|
||||||
proxy_data_abort_connect(pdata);
|
proxy_data_abort_connect(pdata);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -399,7 +399,7 @@ static DWORD WINAPI pf_client_thread_proc(LPVOID arg)
|
|||||||
|
|
||||||
if (nCount == 0)
|
if (nCount == 0)
|
||||||
{
|
{
|
||||||
LOG_ERR(TAG, ps, "freerdp_get_event_handles failed!");
|
LOG_ERR(TAG, pc, "freerdp_get_event_handles failed!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ const char* pf_config_get_str(wIniFile* ini, const char* section, const char* ke
|
|||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "[%s]: key '%s.%s' not found.", __FUNCTION__, key, section);
|
WLog_ERR(TAG, "[%s]: key '%s.%s' not found.", __FUNCTION__, section, key);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,31 +188,27 @@ static BOOL pf_config_load_clipboard(wIniFile* ini, proxyConfig* config)
|
|||||||
|
|
||||||
static BOOL pf_config_load_modules(wIniFile* ini, proxyConfig* config)
|
static BOOL pf_config_load_modules(wIniFile* ini, proxyConfig* config)
|
||||||
{
|
{
|
||||||
int index;
|
const char* required_modules;
|
||||||
int modules_count = 0;
|
char* tmp;
|
||||||
char** module_names = NULL;
|
|
||||||
|
|
||||||
module_names = IniFile_GetSectionKeyNames(ini, "Modules", &modules_count);
|
/* make sure that all required modules are loaded */
|
||||||
|
required_modules = IniFile_GetKeyValueString(ini, "Plugins", "Required");
|
||||||
|
if (!required_modules)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
for (index = 0; index < modules_count; index++)
|
tmp = strtok((char*)required_modules, ",");
|
||||||
|
|
||||||
|
while (tmp != NULL)
|
||||||
{
|
{
|
||||||
char* module_name = module_names[index];
|
if (!pf_modules_is_plugin_loaded(tmp))
|
||||||
const char* path = pf_config_get_str(ini, "Modules", module_name);
|
|
||||||
|
|
||||||
if (!path)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!pf_modules_register_new(path, module_name))
|
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "pf_config_load_modules(): failed to register %s (%s)", module_name,
|
WLog_ERR(TAG, "Required plugin '%s' is not loaded. stopping.", tmp);
|
||||||
path);
|
return FALSE;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WLog_INFO(TAG, "module '%s' is loaded!", module_name);
|
tmp = strtok(NULL, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
free(module_names);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,11 +29,6 @@
|
|||||||
static BOOL client_to_proxy_context_new(freerdp_peer* client, pServerContext* context)
|
static BOOL client_to_proxy_context_new(freerdp_peer* client, pServerContext* context)
|
||||||
{
|
{
|
||||||
context->dynvcReady = NULL;
|
context->dynvcReady = NULL;
|
||||||
context->modules_info = NULL;
|
|
||||||
|
|
||||||
context->modules_info = HashTable_New(TRUE);
|
|
||||||
if (!context->modules_info)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
context->vcm = WTSOpenServerA((LPSTR)client->context);
|
context->vcm = WTSOpenServerA((LPSTR)client->context);
|
||||||
|
|
||||||
@ -46,7 +41,6 @@ static BOOL client_to_proxy_context_new(freerdp_peer* client, pServerContext* co
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
HashTable_Free(context->modules_info);
|
|
||||||
WTSCloseServer((HANDLE)context->vcm);
|
WTSCloseServer((HANDLE)context->vcm);
|
||||||
context->vcm = NULL;
|
context->vcm = NULL;
|
||||||
|
|
||||||
@ -74,8 +68,6 @@ static void client_to_proxy_context_free(freerdp_peer* client, pServerContext* c
|
|||||||
CloseHandle(context->dynvcReady);
|
CloseHandle(context->dynvcReady);
|
||||||
context->dynvcReady = NULL;
|
context->dynvcReady = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTable_Free(context->modules_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL pf_context_init_server_context(freerdp_peer* client)
|
BOOL pf_context_init_server_context(freerdp_peer* client)
|
||||||
@ -198,6 +190,17 @@ proxyData* proxy_data_new(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(pdata->modules_info = HashTable_New(FALSE)))
|
||||||
|
{
|
||||||
|
proxy_data_free(pdata);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* modules_info maps between plugin name to custom data */
|
||||||
|
pdata->modules_info->hash = HashTable_StringHash;
|
||||||
|
pdata->modules_info->keyCompare = HashTable_StringCompare;
|
||||||
|
pdata->modules_info->keyClone = HashTable_StringClone;
|
||||||
|
pdata->modules_info->keyFree = HashTable_StringFree;
|
||||||
return pdata;
|
return pdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +241,9 @@ void proxy_data_free(proxyData* pdata)
|
|||||||
if (pdata->session_id)
|
if (pdata->session_id)
|
||||||
free(pdata->session_id);
|
free(pdata->session_id);
|
||||||
|
|
||||||
|
if (pdata->modules_info)
|
||||||
|
HashTable_Free(pdata->modules_info);
|
||||||
|
|
||||||
free(pdata);
|
free(pdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,9 +56,6 @@ struct p_server_context
|
|||||||
DispServerContext* disp;
|
DispServerContext* disp;
|
||||||
CliprdrServerContext* cliprdr;
|
CliprdrServerContext* cliprdr;
|
||||||
RdpsndServerContext* rdpsnd;
|
RdpsndServerContext* rdpsnd;
|
||||||
|
|
||||||
/* used to external modules to store per-session info */
|
|
||||||
wHashTable* modules_info;
|
|
||||||
};
|
};
|
||||||
typedef struct p_server_context pServerContext;
|
typedef struct p_server_context pServerContext;
|
||||||
|
|
||||||
@ -110,6 +107,9 @@ struct proxy_data
|
|||||||
HANDLE gfx_server_ready;
|
HANDLE gfx_server_ready;
|
||||||
|
|
||||||
char* session_id;
|
char* session_id;
|
||||||
|
|
||||||
|
/* used to external modules to store per-session info */
|
||||||
|
wHashTable* modules_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src);
|
BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src);
|
||||||
|
@ -43,7 +43,7 @@ static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
|||||||
event.flags = flags;
|
event.flags = flags;
|
||||||
event.rdp_scan_code = code;
|
event.rdp_scan_code = code;
|
||||||
|
|
||||||
if (pf_modules_run_filter(FILTER_TYPE_KEYBOARD, input->context, &event))
|
if (pf_modules_run_filter(FILTER_TYPE_KEYBOARD, pc->pdata, &event))
|
||||||
return freerdp_input_send_keyboard_event(pc->context.input, flags, code);
|
return freerdp_input_send_keyboard_event(pc->context.input, flags, code);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -75,7 +75,7 @@ static BOOL pf_server_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1
|
|||||||
event.x = x;
|
event.x = x;
|
||||||
event.y = y;
|
event.y = y;
|
||||||
|
|
||||||
if (pf_modules_run_filter(FILTER_TYPE_MOUSE, input->context, &event))
|
if (pf_modules_run_filter(FILTER_TYPE_MOUSE, pc->pdata, &event))
|
||||||
return freerdp_input_send_mouse_event(pc->context.input, flags, x, y);
|
return freerdp_input_send_mouse_event(pc->context.input, flags, x, y);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -20,9 +20,11 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <winpr/file.h>
|
||||||
#include <winpr/wlog.h>
|
#include <winpr/wlog.h>
|
||||||
#include <winpr/library.h>
|
#include <winpr/library.h>
|
||||||
#include <freerdp/api.h>
|
#include <freerdp/api.h>
|
||||||
|
#include <freerdp/build-config.h>
|
||||||
|
|
||||||
#include "pf_log.h"
|
#include "pf_log.h"
|
||||||
#include "pf_modules.h"
|
#include "pf_modules.h"
|
||||||
@ -30,14 +32,12 @@
|
|||||||
|
|
||||||
#define TAG PROXY_TAG("modules")
|
#define TAG PROXY_TAG("modules")
|
||||||
|
|
||||||
#define MODULE_INIT_METHOD "module_init"
|
#define MODULE_ENTRY_POINT "proxy_module_entry_point"
|
||||||
#define MODULE_EXIT_METHOD "module_exit"
|
|
||||||
|
|
||||||
static modules_list* proxy_modules = NULL;
|
static wArrayList* plugins_list = NULL; /* list of all loaded plugins */
|
||||||
|
static wArrayList* handles_list = NULL; /* list of module handles to free at shutdown */
|
||||||
|
|
||||||
/* module init/exit methods */
|
typedef BOOL (*moduleEntryPoint)(proxyPluginsManager* plugins_manager);
|
||||||
typedef BOOL (*moduleInitFn)(moduleOperations* ops);
|
|
||||||
typedef BOOL (*moduleExitFn)(moduleOperations* ops);
|
|
||||||
|
|
||||||
static const char* FILTER_TYPE_STRINGS[] = {
|
static const char* FILTER_TYPE_STRINGS[] = {
|
||||||
"KEYBOARD_EVENT",
|
"KEYBOARD_EVENT",
|
||||||
@ -45,14 +45,13 @@ static const char* FILTER_TYPE_STRINGS[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const char* HOOK_TYPE_STRINGS[] = {
|
static const char* HOOK_TYPE_STRINGS[] = {
|
||||||
"CLIENT_PRE_CONNECT",
|
"CLIENT_PRE_CONNECT", "CLIENT_LOGIN_FAILURE", "SERVER_POST_CONNECT",
|
||||||
"SERVER_CHANNELS_INIT",
|
"SERVER_CHANNELS_INIT", "SERVER_CHANNELS_FREE",
|
||||||
"SERVER_CHANNELS_FREE",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* pf_modules_get_filter_type_string(PF_FILTER_TYPE result)
|
static const char* pf_modules_get_filter_type_string(PF_FILTER_TYPE result)
|
||||||
{
|
{
|
||||||
if (result >= FILTER_TYPE_KEYBOARD && result <= FILTER_TYPE_MOUSE)
|
if (result >= FILTER_TYPE_KEYBOARD && result < FILTER_LAST)
|
||||||
return FILTER_TYPE_STRINGS[result];
|
return FILTER_TYPE_STRINGS[result];
|
||||||
else
|
else
|
||||||
return "FILTER_UNKNOWN";
|
return "FILTER_UNKNOWN";
|
||||||
@ -60,65 +59,57 @@ static const char* pf_modules_get_filter_type_string(PF_FILTER_TYPE result)
|
|||||||
|
|
||||||
static const char* pf_modules_get_hook_type_string(PF_HOOK_TYPE result)
|
static const char* pf_modules_get_hook_type_string(PF_HOOK_TYPE result)
|
||||||
{
|
{
|
||||||
if (result >= HOOK_TYPE_CLIENT_PRE_CONNECT && result <= HOOK_TYPE_SERVER_CHANNELS_FREE)
|
if (result >= HOOK_TYPE_CLIENT_PRE_CONNECT && result < HOOK_LAST)
|
||||||
return HOOK_TYPE_STRINGS[result];
|
return HOOK_TYPE_STRINGS[result];
|
||||||
else
|
else
|
||||||
return "HOOK_UNKNOWN";
|
return "HOOK_UNKNOWN";
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL pf_modules_init(void)
|
|
||||||
{
|
|
||||||
proxy_modules = ArrayList_New(FALSE);
|
|
||||||
|
|
||||||
if (proxy_modules == NULL)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_modules_init(): ArrayList_New failed!");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* runs all hooks of type `type`.
|
* runs all hooks of type `type`.
|
||||||
*
|
*
|
||||||
* @type: hook type to run.
|
* @type: hook type to run.
|
||||||
* @server: pointer of server's rdpContext struct of the current session.
|
* @server: pointer of server's rdpContext struct of the current session.
|
||||||
*/
|
*/
|
||||||
BOOL pf_modules_run_hook(PF_HOOK_TYPE type, rdpContext* context)
|
BOOL pf_modules_run_hook(PF_HOOK_TYPE type, proxyData* pdata)
|
||||||
{
|
{
|
||||||
|
|
||||||
proxyModule* module;
|
|
||||||
moduleOperations* ops;
|
|
||||||
BOOL ok = TRUE;
|
BOOL ok = TRUE;
|
||||||
const size_t count = (size_t)ArrayList_Count(proxy_modules);
|
|
||||||
size_t index;
|
size_t index;
|
||||||
|
proxyPlugin* plugin;
|
||||||
|
|
||||||
for (index = 0; index < count; index++)
|
ArrayList_ForEach(plugins_list, proxyPlugin*, index, plugin)
|
||||||
{
|
{
|
||||||
module = (proxyModule*)ArrayList_GetItem(proxy_modules, index);
|
WLog_VRB(TAG, "running hook %s.%s", plugin->name, pf_modules_get_hook_type_string(type));
|
||||||
ops = module->ops;
|
|
||||||
WLog_VRB(TAG, "[%s]: Running module %s, hook %s", __FUNCTION__, module->name,
|
|
||||||
pf_modules_get_hook_type_string(type));
|
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case HOOK_TYPE_CLIENT_PRE_CONNECT:
|
case HOOK_TYPE_CLIENT_PRE_CONNECT:
|
||||||
IFCALLRET(ops->ClientPreConnect, ok, ops, context);
|
IFCALLRET(plugin->ClientPreConnect, ok, pdata);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HOOK_TYPE_CLIENT_LOGIN_FAILURE:
|
||||||
|
IFCALLRET(plugin->ClientLoginFailure, ok, pdata);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HOOK_TYPE_SERVER_POST_CONNECT:
|
||||||
|
IFCALLRET(plugin->ServerPostConnect, ok, pdata);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HOOK_TYPE_SERVER_CHANNELS_INIT:
|
case HOOK_TYPE_SERVER_CHANNELS_INIT:
|
||||||
IFCALLRET(ops->ServerChannelsInit, ok, ops, context);
|
IFCALLRET(plugin->ServerChannelsInit, ok, pdata);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HOOK_TYPE_SERVER_CHANNELS_FREE:
|
case HOOK_TYPE_SERVER_CHANNELS_FREE:
|
||||||
IFCALLRET(ops->ServerChannelsFree, ok, ops, context);
|
IFCALLRET(plugin->ServerChannelsFree, ok, pdata);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
WLog_ERR(TAG, "invalid hook called");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
{
|
{
|
||||||
WLog_INFO(TAG, "Module %s, hook %s failed!", module->name,
|
WLog_INFO(TAG, "plugin %s, hook %s failed!", plugin->name,
|
||||||
pf_modules_get_hook_type_string(type));
|
pf_modules_get_hook_type_string(type));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -133,35 +124,34 @@ BOOL pf_modules_run_hook(PF_HOOK_TYPE type, rdpContext* context)
|
|||||||
* @type: filter type to run.
|
* @type: filter type to run.
|
||||||
* @server: pointer of server's rdpContext struct of the current session.
|
* @server: pointer of server's rdpContext struct of the current session.
|
||||||
*/
|
*/
|
||||||
BOOL pf_modules_run_filter(PF_FILTER_TYPE type, rdpContext* server, void* param)
|
BOOL pf_modules_run_filter(PF_FILTER_TYPE type, proxyData* pdata, void* param)
|
||||||
{
|
{
|
||||||
proxyModule* module;
|
|
||||||
moduleOperations* ops;
|
|
||||||
BOOL result = TRUE;
|
BOOL result = TRUE;
|
||||||
const size_t count = (size_t)ArrayList_Count(proxy_modules);
|
|
||||||
size_t index;
|
size_t index;
|
||||||
|
proxyPlugin* plugin;
|
||||||
|
|
||||||
for (index = 0; index < count; index++)
|
ArrayList_ForEach(plugins_list, proxyPlugin*, index, plugin)
|
||||||
{
|
{
|
||||||
module = (proxyModule*)ArrayList_GetItem(proxy_modules, index);
|
WLog_VRB(TAG, "[%s]: running filter: %s", __FUNCTION__, plugin->name);
|
||||||
ops = module->ops;
|
|
||||||
WLog_VRB(TAG, "[%s]: running filter: %s", __FUNCTION__, module->name);
|
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case FILTER_TYPE_KEYBOARD:
|
case FILTER_TYPE_KEYBOARD:
|
||||||
IFCALLRET(ops->KeyboardEvent, result, ops, server, param);
|
IFCALLRET(plugin->KeyboardEvent, result, pdata, param);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FILTER_TYPE_MOUSE:
|
case FILTER_TYPE_MOUSE:
|
||||||
IFCALLRET(ops->MouseEvent, result, ops, server, param);
|
IFCALLRET(plugin->MouseEvent, result, pdata, param);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
WLog_ERR(TAG, "invalid filter called");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
/* current filter return FALSE, no need to run other filters. */
|
/* current filter return FALSE, no need to run other filters. */
|
||||||
WLog_INFO(TAG, "module %s, filter type [%s] returned FALSE", module->name,
|
WLog_INFO(TAG, "plugin %s, filter type [%s] returned FALSE", plugin->name,
|
||||||
pf_modules_get_filter_type_string(type));
|
pf_modules_get_filter_type_string(type));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -171,73 +161,20 @@ BOOL pf_modules_run_filter(PF_FILTER_TYPE type, rdpContext* server, void* param)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pf_modules_module_free(proxyModule* module)
|
|
||||||
{
|
|
||||||
moduleExitFn exitFn;
|
|
||||||
|
|
||||||
assert(module);
|
|
||||||
assert(module->handle);
|
|
||||||
|
|
||||||
exitFn = (moduleExitFn)GetProcAddress(module->handle, MODULE_EXIT_METHOD);
|
|
||||||
|
|
||||||
if (!exitFn)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "[%s]: GetProcAddress module_exit for %s failed!", __FUNCTION__,
|
|
||||||
module->name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!exitFn(module->ops))
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "[%s]: module_exit failed for %s!", __FUNCTION__, module->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeLibrary(module->handle);
|
|
||||||
module->handle = NULL;
|
|
||||||
|
|
||||||
free(module->name);
|
|
||||||
free(module->ops);
|
|
||||||
free(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pf_modules_free(void)
|
|
||||||
{
|
|
||||||
size_t index, count;
|
|
||||||
|
|
||||||
if (proxy_modules == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
count = (size_t)ArrayList_Count(proxy_modules);
|
|
||||||
|
|
||||||
for (index = 0; index < count; index++)
|
|
||||||
{
|
|
||||||
proxyModule* module = (proxyModule*)ArrayList_GetItem(proxy_modules, index);
|
|
||||||
WLog_INFO(TAG, "[%s]: freeing module: %s", __FUNCTION__, module->name);
|
|
||||||
pf_modules_module_free(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList_Free(proxy_modules);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* stores per-session data needed by module.
|
* stores per-session data needed by a plugin.
|
||||||
*
|
*
|
||||||
* @context: current session server's rdpContext instance.
|
* @context: current session server's rdpContext instance.
|
||||||
* @info: pointer to per-session data.
|
* @info: pointer to per-session data.
|
||||||
*/
|
*/
|
||||||
static BOOL pf_modules_set_session_data(moduleOperations* module, rdpContext* context, void* data)
|
static BOOL pf_modules_set_plugin_data(const char* plugin_name, proxyData* pdata, void* data)
|
||||||
{
|
{
|
||||||
pServerContext* ps;
|
assert(plugin_name);
|
||||||
|
|
||||||
assert(module);
|
|
||||||
assert(context);
|
|
||||||
|
|
||||||
if (data == NULL) /* no need to store anything */
|
if (data == NULL) /* no need to store anything */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
ps = (pServerContext*)context;
|
if (HashTable_Add(pdata->modules_info, (void*)plugin_name, data) < 0)
|
||||||
if (HashTable_Add(ps->modules_info, (void*)module, data) < 0)
|
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "[%s]: HashTable_Add failed!");
|
WLog_ERR(TAG, "[%s]: HashTable_Add failed!");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -247,104 +184,215 @@ static BOOL pf_modules_set_session_data(moduleOperations* module, rdpContext* co
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns per-session data needed by module.
|
* returns per-session data needed a plugin.
|
||||||
*
|
*
|
||||||
* @context: current session server's rdpContext instance.
|
* @context: current session server's rdpContext instance.
|
||||||
* if there's no data related to `module` in `context` (current session), a NULL will be returned.
|
* if there's no data related to `plugin_name` in `context` (current session), a NULL will be
|
||||||
|
* returned.
|
||||||
*/
|
*/
|
||||||
static void* pf_modules_get_session_data(moduleOperations* module, rdpContext* context)
|
static void* pf_modules_get_plugin_data(const char* plugin_name, proxyData* pdata)
|
||||||
{
|
{
|
||||||
pServerContext* ps;
|
assert(plugin_name);
|
||||||
|
assert(pdata);
|
||||||
|
|
||||||
assert(module);
|
return HashTable_GetItemValue(pdata->modules_info, (void*)plugin_name);
|
||||||
assert(context);
|
|
||||||
|
|
||||||
ps = (pServerContext*)context;
|
|
||||||
return HashTable_GetItemValue(ps->modules_info, module);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pf_modules_abort_connect(moduleOperations* module, rdpContext* context)
|
static void pf_modules_abort_connect(proxyData* pdata)
|
||||||
{
|
{
|
||||||
pServerContext* ps;
|
assert(pdata);
|
||||||
|
WLog_DBG(TAG, "%s is called!", __FUNCTION__);
|
||||||
assert(module);
|
proxy_data_abort_connect(pdata);
|
||||||
assert(context);
|
|
||||||
|
|
||||||
WLog_INFO(TAG, "%s is called!", __FUNCTION__);
|
|
||||||
|
|
||||||
ps = (pServerContext*)context;
|
|
||||||
proxy_data_abort_connect(ps->pdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL pf_modules_register_new(const char* module_path, const char* module_name)
|
static BOOL pf_modules_register_plugin(proxyPlugin* plugin_to_register)
|
||||||
|
{
|
||||||
|
size_t index;
|
||||||
|
proxyPlugin* plugin;
|
||||||
|
|
||||||
|
assert(plugins_list != NULL);
|
||||||
|
|
||||||
|
/* make sure there's no other loaded plugin with the same name of `plugin_to_register`. */
|
||||||
|
ArrayList_ForEach(plugins_list, proxyPlugin*, index, plugin)
|
||||||
|
{
|
||||||
|
if (strcmp(plugin->name, plugin_to_register->name) == 0)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "can not register plugin '%s', it is already registered!");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ArrayList_Add(plugins_list, plugin_to_register) < 0)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "[%s]: failed adding plugin to list: %s", __FUNCTION__, plugin->name);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL pf_modules_is_plugin_loaded(const char* plugin_name)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
proxyPlugin* plugin;
|
||||||
|
|
||||||
|
if (plugins_list == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ArrayList_ForEach(plugins_list, proxyPlugin*, i, plugin)
|
||||||
|
{
|
||||||
|
if (strcmp(plugin->name, plugin_name) == 0)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pf_modules_list_loaded_plugins(void)
|
||||||
|
{
|
||||||
|
size_t count;
|
||||||
|
size_t i;
|
||||||
|
proxyPlugin* plugin;
|
||||||
|
|
||||||
|
if (plugins_list == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
count = (size_t)ArrayList_Count(plugins_list);
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
WLog_INFO(TAG, "Loaded plugins:");
|
||||||
|
|
||||||
|
ArrayList_ForEach(plugins_list, proxyPlugin*, i, plugin)
|
||||||
|
{
|
||||||
|
|
||||||
|
WLog_INFO(TAG, "\tName: %s", plugin->name);
|
||||||
|
WLog_INFO(TAG, "\tDescription: %s", plugin->description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static proxyPluginsManager plugins_manager = { pf_modules_register_plugin,
|
||||||
|
pf_modules_set_plugin_data,
|
||||||
|
pf_modules_get_plugin_data,
|
||||||
|
pf_modules_abort_connect };
|
||||||
|
|
||||||
|
static BOOL pf_modules_load_module(const char* module_path)
|
||||||
{
|
{
|
||||||
moduleOperations* ops = NULL;
|
|
||||||
proxyModule* module = NULL;
|
|
||||||
HMODULE handle = NULL;
|
HMODULE handle = NULL;
|
||||||
moduleInitFn fn;
|
moduleEntryPoint pEntryPoint;
|
||||||
|
|
||||||
assert(proxy_modules != NULL);
|
|
||||||
handle = LoadLibraryA(module_path);
|
handle = LoadLibraryA(module_path);
|
||||||
|
|
||||||
if (handle == NULL)
|
if (handle == NULL)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "pf_modules_register_new(): failed loading external module: %s", module_path);
|
WLog_ERR(TAG, "[%s]: failed loading external library: %s", __FUNCTION__, module_path);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(fn = (moduleInitFn)GetProcAddress(handle, MODULE_INIT_METHOD)))
|
if (!(pEntryPoint = (moduleEntryPoint)GetProcAddress(handle, MODULE_ENTRY_POINT)))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "pf_modules_register_new(): GetProcAddress failed while loading %s",
|
WLog_ERR(TAG, "[%s]: GetProcAddress failed while loading %s", __FUNCTION__, module_path);
|
||||||
module_path);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
module = (proxyModule*)calloc(1, sizeof(proxyModule));
|
if (!pEntryPoint(&plugins_manager))
|
||||||
|
|
||||||
if (module == NULL)
|
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "pf_modules_register_new(): malloc failed");
|
WLog_ERR(TAG, "[%s]: module %s entry point failed!", __FUNCTION__, module_path);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ops = calloc(1, sizeof(moduleOperations));
|
/* save module handle for freeing the module later */
|
||||||
|
if (ArrayList_Add(handles_list, handle) < 0)
|
||||||
if (ops == NULL)
|
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "pf_modules_register_new(): calloc moduleOperations failed");
|
WLog_ERR(TAG, "ArrayList_Add failed!");
|
||||||
goto error;
|
return FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
ops->AbortConnect = pf_modules_abort_connect;
|
|
||||||
ops->SetSessionData = pf_modules_set_session_data;
|
|
||||||
ops->GetSessionData = pf_modules_get_session_data;
|
|
||||||
|
|
||||||
if (!fn(ops))
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_modules_register_new(): failed to initialize module %s", module_path);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
module->name = _strdup(module_name);
|
|
||||||
if (!module->name)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_modules_register_new(): _strdup failed while loading %s", module_path);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
module->handle = handle;
|
|
||||||
module->ops = ops;
|
|
||||||
module->enabled = TRUE;
|
|
||||||
|
|
||||||
if (ArrayList_Add(proxy_modules, module) < 0)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_modules_register_new(): failed adding module to list: %s", module_path);
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
pf_modules_module_free(module);
|
FreeLibrary(handle);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL pf_modules_init(const char* modules_directory)
|
||||||
|
{
|
||||||
|
WIN32_FIND_DATA ffd;
|
||||||
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
WLog_DBG(TAG, "Searching plugins in directory %s", modules_directory);
|
||||||
|
|
||||||
|
hFind = FindFirstFile(modules_directory, &ffd);
|
||||||
|
|
||||||
|
if (INVALID_HANDLE_VALUE == hFind)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "FindFirstFile failed!");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins_list = ArrayList_New(FALSE);
|
||||||
|
|
||||||
|
if (plugins_list == NULL)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "[%s]: ArrayList_New failed!", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
handles_list = ArrayList_New(FALSE);
|
||||||
|
if (handles_list == NULL)
|
||||||
|
{
|
||||||
|
ArrayList_Free(plugins_list);
|
||||||
|
plugins_list = NULL;
|
||||||
|
|
||||||
|
WLog_ERR(TAG, "[%s]: ArrayList_New failed!", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
||||||
|
{
|
||||||
|
char* fullpath = GetCombinedPath(modules_directory, ffd.cFileName);
|
||||||
|
char* dot = strrchr(ffd.cFileName, '.');
|
||||||
|
|
||||||
|
if (dot && strcmp(dot, FREERDP_SHARED_LIBRARY_SUFFIX) == 0)
|
||||||
|
pf_modules_load_module(fullpath);
|
||||||
|
|
||||||
|
free(fullpath);
|
||||||
|
}
|
||||||
|
} while (FindNextFile(hFind, &ffd) != 0);
|
||||||
|
|
||||||
|
FindClose(hFind);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pf_modules_free(void)
|
||||||
|
{
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
if (plugins_list)
|
||||||
|
{
|
||||||
|
proxyPlugin* plugin;
|
||||||
|
|
||||||
|
ArrayList_ForEach(plugins_list, proxyPlugin*, index, plugin)
|
||||||
|
{
|
||||||
|
if (!IFCALLRESULT(TRUE, plugin->PluginUnload))
|
||||||
|
WLog_WARN(TAG, "PluginUnload failed for plugin '%s'", plugin->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList_Free(plugins_list);
|
||||||
|
plugins_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handles_list)
|
||||||
|
{
|
||||||
|
HANDLE handle;
|
||||||
|
|
||||||
|
ArrayList_ForEach(handles_list, HANDLE, index, handle)
|
||||||
|
{
|
||||||
|
if (handle)
|
||||||
|
FreeLibrary(handle);
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrayList_Free(handles_list);
|
||||||
|
handles_list = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -26,39 +26,34 @@
|
|||||||
|
|
||||||
#include "modules/modules_api.h"
|
#include "modules/modules_api.h"
|
||||||
|
|
||||||
typedef wArrayList modules_list;
|
|
||||||
typedef struct proxy_module proxyModule;
|
|
||||||
|
|
||||||
typedef enum _PF_FILTER_TYPE PF_FILTER_TYPE;
|
typedef enum _PF_FILTER_TYPE PF_FILTER_TYPE;
|
||||||
enum _PF_FILTER_TYPE
|
enum _PF_FILTER_TYPE
|
||||||
{
|
{
|
||||||
FILTER_TYPE_KEYBOARD,
|
FILTER_TYPE_KEYBOARD,
|
||||||
FILTER_TYPE_MOUSE
|
FILTER_TYPE_MOUSE,
|
||||||
|
|
||||||
|
FILTER_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum _PF_HOOK_TYPE PF_HOOK_TYPE;
|
typedef enum _PF_HOOK_TYPE PF_HOOK_TYPE;
|
||||||
enum _PF_HOOK_TYPE
|
enum _PF_HOOK_TYPE
|
||||||
{
|
{
|
||||||
HOOK_TYPE_CLIENT_PRE_CONNECT,
|
HOOK_TYPE_CLIENT_PRE_CONNECT,
|
||||||
|
HOOK_TYPE_CLIENT_LOGIN_FAILURE,
|
||||||
|
|
||||||
|
HOOK_TYPE_SERVER_POST_CONNECT,
|
||||||
HOOK_TYPE_SERVER_CHANNELS_INIT,
|
HOOK_TYPE_SERVER_CHANNELS_INIT,
|
||||||
HOOK_TYPE_SERVER_CHANNELS_FREE,
|
HOOK_TYPE_SERVER_CHANNELS_FREE,
|
||||||
|
|
||||||
|
HOOK_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
struct proxy_module
|
BOOL pf_modules_init(const char* modules_directory_path);
|
||||||
{
|
BOOL pf_modules_is_plugin_loaded(const char* plugin_name);
|
||||||
/* Handle to the loaded library. Used for freeing the library */
|
void pf_modules_list_loaded_plugins(void);
|
||||||
HMODULE handle;
|
|
||||||
|
|
||||||
char* name;
|
BOOL pf_modules_run_filter(PF_FILTER_TYPE type, proxyData* pdata, void* param);
|
||||||
BOOL enabled;
|
BOOL pf_modules_run_hook(PF_HOOK_TYPE type, proxyData* pdata);
|
||||||
moduleOperations* ops;
|
|
||||||
};
|
|
||||||
|
|
||||||
BOOL pf_modules_init(void);
|
|
||||||
BOOL pf_modules_register_new(const char* module_path, const char* module_name);
|
|
||||||
|
|
||||||
BOOL pf_modules_run_filter(PF_FILTER_TYPE type, rdpContext* server, void* param);
|
|
||||||
BOOL pf_modules_run_hook(PF_HOOK_TYPE type, rdpContext* context);
|
|
||||||
|
|
||||||
void pf_modules_free(void);
|
void pf_modules_free(void);
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "pf_disp.h"
|
#include "pf_disp.h"
|
||||||
#include "pf_rail.h"
|
#include "pf_rail.h"
|
||||||
#include "pf_channels.h"
|
#include "pf_channels.h"
|
||||||
|
#include "pf_modules.h"
|
||||||
|
|
||||||
#define TAG PROXY_TAG("server")
|
#define TAG PROXY_TAG("server")
|
||||||
|
|
||||||
@ -189,7 +190,7 @@ static BOOL pf_server_post_connect(freerdp_peer* peer)
|
|||||||
|
|
||||||
pf_server_register_input_callbacks(peer->input);
|
pf_server_register_input_callbacks(peer->input);
|
||||||
pf_server_register_update_callbacks(peer->update);
|
pf_server_register_update_callbacks(peer->update);
|
||||||
return TRUE;
|
return pf_modules_run_hook(HOOK_TYPE_SERVER_POST_CONNECT, pdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL pf_server_activate(freerdp_peer* peer)
|
static BOOL pf_server_activate(freerdp_peer* peer)
|
||||||
|
Loading…
Reference in New Issue
Block a user