mirror of
https://github.com/FreeRDP/FreeRDP.git
synced 2025-06-03 00:00:20 +00:00
server: proxy: improve modules api
This commit is contained in:
parent
8a865546d1
commit
32fff644da
@ -3,7 +3,8 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
|
# Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
|
||||||
# Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
# Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
||||||
#
|
# Copyright 2019 Idan Freiberg <speidy@gmail.com>
|
||||||
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
# You may obtain a copy of the License at
|
# You may obtain a copy of the License at
|
||||||
@ -43,11 +44,12 @@ set(${MODULE_PREFIX}_SRCS
|
|||||||
pf_config.h
|
pf_config.h
|
||||||
pf_graphics.c
|
pf_graphics.c
|
||||||
pf_graphics.h
|
pf_graphics.h
|
||||||
pf_filters.c
|
pf_modules.c
|
||||||
pf_filters.h
|
pf_modules.h
|
||||||
pf_log.h
|
|
||||||
pf_cliprdr.c
|
pf_cliprdr.c
|
||||||
pf_cliprdr.h)
|
pf_cliprdr.h
|
||||||
|
pf_log.h
|
||||||
|
)
|
||||||
|
|
||||||
# On windows create dll version information.
|
# On windows create dll version information.
|
||||||
# Vendor, product and year are already set in top level CMakeLists.txt
|
# Vendor, product and year are already set in top level CMakeLists.txt
|
||||||
@ -79,4 +81,4 @@ endif()
|
|||||||
|
|
||||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/proxy")
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/proxy")
|
||||||
|
|
||||||
add_subdirectory("filters")
|
add_subdirectory("modules")
|
||||||
|
@ -32,6 +32,5 @@ Clipboard = 1
|
|||||||
TextOnly = 1
|
TextOnly = 1
|
||||||
MaxTextLength = 10 # 0 for no limit.
|
MaxTextLength = 10 # 0 for no limit.
|
||||||
|
|
||||||
[Filters]
|
[Modules]
|
||||||
; FilterName = FilterPath
|
Demo = "modules/demo/libdemo.so"
|
||||||
DemoFilter = "server/proxy/filters/libdemo_filter.so"
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
add_library(demo_filter SHARED
|
|
||||||
filter_demo.c
|
|
||||||
)
|
|
@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
||||||
* FreeRDP Proxy Server
|
|
||||||
*
|
|
||||||
* Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
|
|
||||||
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
|
||||||
* Copyright 2019 Idan Freiberg <speidy@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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FREERDP_SERVER_PROXY_FILTERS_API_H
|
|
||||||
#define FREERDP_SERVER_PROXY_FILTERS_API_H
|
|
||||||
|
|
||||||
#include <freerdp/freerdp.h>
|
|
||||||
#include <winpr/winpr.h>
|
|
||||||
|
|
||||||
#define PROXY_API FREERDP_API
|
|
||||||
|
|
||||||
enum pf_filter_result {
|
|
||||||
FILTER_PASS = 0,
|
|
||||||
FILTER_DROP,
|
|
||||||
FILTER_IGNORE
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum pf_filter_result PF_FILTER_RESULT;
|
|
||||||
typedef struct connection_info connectionInfo;
|
|
||||||
typedef struct proxy_events proxyEvents;
|
|
||||||
typedef struct proxy_keyboard_event_info proxyKeyboardEventInfo;
|
|
||||||
typedef struct proxy_mouse_event_info proxyMouseEventInfo;
|
|
||||||
typedef PF_FILTER_RESULT(*proxyEvent)(connectionInfo* info, void* param);
|
|
||||||
|
|
||||||
struct connection_info {
|
|
||||||
char* TargetHostname;
|
|
||||||
char* ClientHostname;
|
|
||||||
char* Username;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct proxy_events {
|
|
||||||
proxyEvent KeyboardEvent;
|
|
||||||
proxyEvent MouseEvent;
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
struct proxy_keyboard_event_info {
|
|
||||||
UINT16 flags;
|
|
||||||
UINT16 rdp_scan_code;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct proxy_mouse_event_info {
|
|
||||||
UINT16 flags;
|
|
||||||
UINT16 x;
|
|
||||||
UINT16 y;
|
|
||||||
};
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
/* implement this method and register callbacks for proxy events
|
|
||||||
* return TRUE if initialization succeeded, otherwise FALSE.
|
|
||||||
**/
|
|
||||||
PROXY_API BOOL filter_init(proxyEvents* events);
|
|
||||||
|
|
||||||
#endif /* FREERDP_SERVER_PROXY_FILTERS_API_H */
|
|
@ -22,12 +22,13 @@
|
|||||||
#include "pf_server.h"
|
#include "pf_server.h"
|
||||||
#include "pf_config.h"
|
#include "pf_config.h"
|
||||||
#include "pf_log.h"
|
#include "pf_log.h"
|
||||||
#include "pf_filters.h"
|
#include "pf_modules.h"
|
||||||
|
|
||||||
#include <winpr/collections.h>
|
#include <winpr/collections.h>
|
||||||
|
|
||||||
#define TAG PROXY_TAG("server")
|
#define TAG PROXY_TAG("server")
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
const char* cfg = "config.ini";
|
const char* cfg = "config.ini";
|
||||||
@ -40,12 +41,16 @@ int main(int argc, char* argv[])
|
|||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
cfg = argv[1];
|
cfg = argv[1];
|
||||||
|
|
||||||
|
if (!pf_modules_init())
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (!pf_server_config_load(cfg, config))
|
if (!pf_server_config_load(cfg, config))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
pf_server_config_print(config);
|
pf_server_config_print(config);
|
||||||
status = pf_server_start(config);
|
status = pf_server_start(config);
|
||||||
fail:
|
fail:
|
||||||
|
pf_modules_free();
|
||||||
pf_server_config_free(config);
|
pf_server_config_free(config);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
33
server/proxy/modules/CMakeLists.txt
Normal file
33
server/proxy/modules/CMakeLists.txt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
# The third-party directory is meant for third-party components to be built
|
||||||
|
# as part of the main FreeRDP build system, making separate maintenance easier.
|
||||||
|
# Subdirectories of the third-party directory are ignored by git, but are
|
||||||
|
# automatically included by CMake when the -DWITH_THIRD_PARTY=on option is used.
|
||||||
|
|
||||||
|
# include proxy header files for proxy modules
|
||||||
|
include_directories("${CMAKE_SOURCE_DIR}/server/proxy")
|
||||||
|
include_directories("${CMAKE_SOURCE_DIR}/server/proxy/modules")
|
||||||
|
|
||||||
|
# taken from FreeRDP/third-party/CMakeLists.txt
|
||||||
|
file(GLOB all_valid_subdirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/CMakeLists.txt")
|
||||||
|
|
||||||
|
foreach(dir ${all_valid_subdirs})
|
||||||
|
if(${dir} MATCHES "^([^/]*)/+CMakeLists.txt")
|
||||||
|
string(REGEX REPLACE "^([^/]*)/+CMakeLists.txt" "\\1" dir_trimmed ${dir})
|
||||||
|
message(STATUS "Adding proxy module ${dir_trimmed}")
|
||||||
|
add_subdirectory(${dir_trimmed})
|
||||||
|
endif()
|
||||||
|
endforeach(dir)
|
4
server/proxy/modules/demo/CMakeLists.txt
Normal file
4
server/proxy/modules/demo/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
add_library(demo SHARED
|
||||||
|
demo.c
|
||||||
|
)
|
@ -19,33 +19,40 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "filters_api.h"
|
#include "modules_api.h"
|
||||||
|
|
||||||
static PF_FILTER_RESULT demo_filter_keyboard_event(connectionInfo* info, void* param)
|
static BOOL demo_filter_keyboard_event(moduleOperations* module, rdpContext* context, void* param)
|
||||||
{
|
{
|
||||||
proxyKeyboardEventInfo* event_data = (proxyKeyboardEventInfo*) param;
|
proxyKeyboardEventInfo* event_data = (proxyKeyboardEventInfo*) param;
|
||||||
WINPR_UNUSED(event_data);
|
WINPR_UNUSED(event_data);
|
||||||
|
|
||||||
return FILTER_PASS;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PF_FILTER_RESULT demo_filter_mouse_event(connectionInfo* info, void* param)
|
static BOOL demo_filter_mouse_event(moduleOperations* module, rdpContext* context, void* param)
|
||||||
{
|
{
|
||||||
proxyMouseEventInfo* event_data = (proxyMouseEventInfo*) param;
|
proxyMouseEventInfo* event_data = (proxyMouseEventInfo*) param;
|
||||||
|
|
||||||
if (event_data->x % 100 == 0)
|
if (event_data->x % 100 == 0)
|
||||||
{
|
{
|
||||||
|
module->AbortConnect(module, context);
|
||||||
printf("filter_demo: mouse x is currently %"PRIu16"\n", event_data->x);
|
printf("filter_demo: mouse x is currently %"PRIu16"\n", event_data->x);
|
||||||
return FILTER_PASS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FILTER_PASS;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL filter_init(proxyEvents* events)
|
BOOL module_init(moduleOperations* module)
|
||||||
{
|
{
|
||||||
events->KeyboardEvent = demo_filter_keyboard_event;
|
module->KeyboardEvent = demo_filter_keyboard_event;
|
||||||
events->MouseEvent = demo_filter_mouse_event;
|
module->MouseEvent = demo_filter_mouse_event;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL module_exit(moduleOperations* module)
|
||||||
|
{
|
||||||
|
printf("bye bye\n");
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
101
server/proxy/modules/modules_api.h
Normal file
101
server/proxy/modules/modules_api.h
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* FreeRDP Proxy Server
|
||||||
|
*
|
||||||
|
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
||||||
|
* Copyright 2019 Idan Freiberg <speidy@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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FREERDP_SERVER_PROXY_MODULES_API_H
|
||||||
|
#define FREERDP_SERVER_PROXY_MODULES_API_H
|
||||||
|
|
||||||
|
#include <freerdp/freerdp.h>
|
||||||
|
#include <winpr/winpr.h>
|
||||||
|
|
||||||
|
#define PROXY_API FREERDP_API
|
||||||
|
|
||||||
|
typedef struct module_operations moduleOperations;
|
||||||
|
|
||||||
|
/* used for filtering */
|
||||||
|
typedef BOOL (*proxyFilterFn)(moduleOperations*, rdpContext*, void*);
|
||||||
|
|
||||||
|
/* used for hooks */
|
||||||
|
typedef BOOL (*proxyHookFn)(moduleOperations*, rdpContext*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* used for per-session info.
|
||||||
|
*
|
||||||
|
* each module is allowed to store data per session.
|
||||||
|
* 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 void* (*moduleGetSessionData)(moduleOperations*, rdpContext*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* used for connection management. when a module wants to forcibly close a connection, it should
|
||||||
|
* 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. */
|
||||||
|
moduleSetSessionData SetSessionData;
|
||||||
|
moduleGetSessionData GetSessionData;
|
||||||
|
moduleAbortConnect AbortConnect;
|
||||||
|
|
||||||
|
/* proxy hooks. a module can set these function pointers to register hooks. */
|
||||||
|
proxyHookFn ClientPreConnect;
|
||||||
|
proxyHookFn ServerChannelsInit;
|
||||||
|
proxyHookFn ServerChannelsFree;
|
||||||
|
|
||||||
|
/* proxy filters a module can set these function pointers to register filters. */
|
||||||
|
proxyFilterFn KeyboardEvent;
|
||||||
|
proxyFilterFn MouseEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* filter events parameters */
|
||||||
|
#define WINPR_PACK_PUSH
|
||||||
|
#include <winpr/pack.h>
|
||||||
|
struct proxy_keyboard_event_info
|
||||||
|
{
|
||||||
|
UINT16 flags;
|
||||||
|
UINT16 rdp_scan_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct proxy_mouse_event_info
|
||||||
|
{
|
||||||
|
UINT16 flags;
|
||||||
|
UINT16 x;
|
||||||
|
UINT16 y;
|
||||||
|
};
|
||||||
|
#define WINPR_PACK_POP
|
||||||
|
#include <winpr/pack.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* these two functions must be implemented by any proxy module.
|
||||||
|
* module_init: used for module initialization, hooks and filters registration.
|
||||||
|
*/
|
||||||
|
PROXY_API BOOL module_init(moduleOperations* module);
|
||||||
|
PROXY_API BOOL module_exit(moduleOperations* module);
|
||||||
|
|
||||||
|
#endif /* FREERDP_SERVER_PROXY_MODULES_API_H */
|
@ -168,12 +168,6 @@ static BOOL pf_client_post_connect(freerdp* instance)
|
|||||||
pc = (pClientContext*) context;
|
pc = (pClientContext*) context;
|
||||||
ps = (rdpContext*) pc->pdata->ps;
|
ps = (rdpContext*) pc->pdata->ps;
|
||||||
|
|
||||||
if (!proxy_data_set_connection_info(pc->pdata, ps->settings, settings))
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "proxy_data_set_connection_info failed!");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gdi_init(instance, PIXEL_FORMAT_XRGB32))
|
if (!gdi_init(instance, PIXEL_FORMAT_XRGB32))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
* FreeRDP Proxy Server
|
* FreeRDP Proxy Server
|
||||||
*
|
*
|
||||||
* Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
|
|
||||||
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
||||||
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
|
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
|
||||||
*
|
*
|
||||||
@ -27,6 +26,7 @@
|
|||||||
#include "pf_log.h"
|
#include "pf_log.h"
|
||||||
#include "pf_server.h"
|
#include "pf_server.h"
|
||||||
#include "pf_config.h"
|
#include "pf_config.h"
|
||||||
|
#include "pf_modules.h"
|
||||||
|
|
||||||
#define TAG PROXY_TAG("config")
|
#define TAG PROXY_TAG("config")
|
||||||
|
|
||||||
@ -125,29 +125,26 @@ static BOOL pf_config_load_clipboard(wIniFile* ini, proxyConfig* config)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL pf_config_load_filters(wIniFile* ini, proxyConfig* config)
|
static BOOL pf_config_load_modules(wIniFile* ini, proxyConfig* config)
|
||||||
{
|
{
|
||||||
UINT32 index;
|
UINT32 index;
|
||||||
int filters_count;
|
int modules_count = 0;
|
||||||
char** filters_names;
|
char** module_names;
|
||||||
|
|
||||||
if (!pf_filters_init(&config->Filters))
|
module_names = IniFile_GetSectionKeyNames(ini, "Modules", &modules_count);
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
filters_names = IniFile_GetSectionKeyNames(ini, "Filters", &filters_count);
|
for (index = 0; index < modules_count; index++)
|
||||||
|
|
||||||
for (index = 0; index < filters_count; index++)
|
|
||||||
{
|
{
|
||||||
char* filter_name = filters_names[index];
|
char* module_name = module_names[index];
|
||||||
const char* path = CONFIG_GET_STR(ini, "Filters", filter_name);
|
const char* path = CONFIG_GET_STR(ini, "Modules", module_name);
|
||||||
|
|
||||||
if (!pf_filters_register_new(config->Filters, path, filter_name))
|
if (!pf_modules_register_new(path, module_name))
|
||||||
{
|
{
|
||||||
WLog_DBG(TAG, "pf_config_load_filters(): failed to register %s (%s)", filter_name, path);
|
WLog_DBG(TAG, "pf_config_load_modules(): failed to register %s (%s)", module_name, path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
WLog_DBG(TAG, "pf_config_load_filters(): filter %s is registered", filter_name);
|
WLog_INFO(TAG, "module '%s' is loaded!", module_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -185,7 +182,7 @@ BOOL pf_server_config_load(const char* path, proxyConfig* config)
|
|||||||
if (!pf_config_load_security(ini, config))
|
if (!pf_config_load_security(ini, config))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!pf_config_load_filters(ini, config))
|
if (!pf_config_load_modules(ini, config))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!pf_config_load_clipboard(ini, config))
|
if (!pf_config_load_clipboard(ini, config))
|
||||||
@ -234,7 +231,6 @@ void pf_server_config_print(proxyConfig* config)
|
|||||||
|
|
||||||
void pf_server_config_free(proxyConfig* config)
|
void pf_server_config_free(proxyConfig* config)
|
||||||
{
|
{
|
||||||
pf_filters_unregister_all(config->Filters);
|
|
||||||
free(config->TargetHost);
|
free(config->TargetHost);
|
||||||
free(config->Host);
|
free(config->Host);
|
||||||
free(config);
|
free(config);
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
* FreeRDP Proxy Server
|
* FreeRDP Proxy Server
|
||||||
*
|
*
|
||||||
* Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
|
|
||||||
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
||||||
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
|
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
|
||||||
*
|
*
|
||||||
@ -24,7 +23,10 @@
|
|||||||
|
|
||||||
#include <winpr/ini.h>
|
#include <winpr/ini.h>
|
||||||
|
|
||||||
#include "pf_filters.h"
|
#define CONFIG_GET_STR(ini, section, key) IniFile_GetKeyValueString(ini, section, key)
|
||||||
|
#define CONFIG_GET_BOOL(ini, section, key) IniFile_GetKeyValueInt(ini, section, key)
|
||||||
|
|
||||||
|
typedef struct proxy_config proxyConfig;
|
||||||
|
|
||||||
struct proxy_config
|
struct proxy_config
|
||||||
{
|
{
|
||||||
@ -52,9 +54,6 @@ struct proxy_config
|
|||||||
BOOL DisplayControl;
|
BOOL DisplayControl;
|
||||||
BOOL Clipboard;
|
BOOL Clipboard;
|
||||||
|
|
||||||
/* filters */
|
|
||||||
filters_list* Filters;
|
|
||||||
|
|
||||||
/* clipboard specific settings*/
|
/* clipboard specific settings*/
|
||||||
BOOL TextOnly;
|
BOOL TextOnly;
|
||||||
UINT32 MaxTextLength;
|
UINT32 MaxTextLength;
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
static BOOL client_to_proxy_context_new(freerdp_peer* client,
|
static BOOL client_to_proxy_context_new(freerdp_peer* client,
|
||||||
pServerContext* context)
|
pServerContext* context)
|
||||||
{
|
{
|
||||||
|
context->modules_info = HashTable_New(TRUE);
|
||||||
|
if (!context->modules_info)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
context->vcm = WTSOpenServerA((LPSTR) client->context);
|
context->vcm = WTSOpenServerA((LPSTR) client->context);
|
||||||
|
|
||||||
if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
|
if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
|
||||||
@ -33,6 +37,7 @@ static BOOL client_to_proxy_context_new(freerdp_peer* client,
|
|||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
fail_open_server:
|
fail_open_server:
|
||||||
|
HashTable_Free(context->modules_info);
|
||||||
context->vcm = NULL;
|
context->vcm = NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -53,6 +58,8 @@ static void client_to_proxy_context_free(freerdp_peer* client,
|
|||||||
CloseHandle(context->dynvcReady);
|
CloseHandle(context->dynvcReady);
|
||||||
context->dynvcReady = NULL;
|
context->dynvcReady = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashTable_Free(context->modules_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL init_p_server_context(freerdp_peer* client)
|
BOOL init_p_server_context(freerdp_peer* client)
|
||||||
@ -141,15 +148,7 @@ error:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void connection_info_free(connectionInfo* info)
|
proxyData* proxy_data_new(void)
|
||||||
{
|
|
||||||
free(info->TargetHostname);
|
|
||||||
free(info->ClientHostname);
|
|
||||||
free(info->Username);
|
|
||||||
free(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyData* proxy_data_new()
|
|
||||||
{
|
{
|
||||||
proxyData* pdata = calloc(1, sizeof(proxyData));
|
proxyData* pdata = calloc(1, sizeof(proxyData));
|
||||||
|
|
||||||
@ -158,14 +157,6 @@ proxyData* proxy_data_new()
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdata->info = calloc(1, sizeof(connectionInfo));
|
|
||||||
|
|
||||||
if (pdata->info == NULL)
|
|
||||||
{
|
|
||||||
free(pdata);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pdata->abort_event = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
if (!(pdata->abort_event = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||||
{
|
{
|
||||||
proxy_data_free(pdata);
|
proxy_data_free(pdata);
|
||||||
@ -175,27 +166,8 @@ proxyData* proxy_data_new()
|
|||||||
return pdata;
|
return pdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sets connection info values using the settings of both server & client */
|
|
||||||
BOOL proxy_data_set_connection_info(proxyData* pdata, rdpSettings* ps, rdpSettings* pc)
|
|
||||||
{
|
|
||||||
if (!(pdata->info->TargetHostname = _strdup(pc->ServerHostname)))
|
|
||||||
goto out_fail;
|
|
||||||
|
|
||||||
if (!(pdata->info->Username = _strdup(pc->Username)))
|
|
||||||
goto out_fail;
|
|
||||||
|
|
||||||
if (!(pdata->info->ClientHostname = _strdup(ps->ClientHostname)))
|
|
||||||
goto out_fail;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
out_fail:
|
|
||||||
proxy_data_free(pdata);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void proxy_data_free(proxyData* pdata)
|
void proxy_data_free(proxyData* pdata)
|
||||||
{
|
{
|
||||||
connection_info_free(pdata->info);
|
|
||||||
if (pdata->abort_event)
|
if (pdata->abort_event)
|
||||||
{
|
{
|
||||||
CloseHandle(pdata->abort_event);
|
CloseHandle(pdata->abort_event);
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#include "pf_config.h"
|
#include "pf_config.h"
|
||||||
#include "pf_server.h"
|
#include "pf_server.h"
|
||||||
#include "pf_filters.h"
|
#include "pf_modules.h"
|
||||||
|
|
||||||
typedef struct proxy_data proxyData;
|
typedef struct proxy_data proxyData;
|
||||||
|
|
||||||
@ -52,6 +52,9 @@ struct p_server_context
|
|||||||
RdpgfxServerContext* gfx;
|
RdpgfxServerContext* gfx;
|
||||||
DispServerContext* disp;
|
DispServerContext* disp;
|
||||||
CliprdrServerContext* cliprdr;
|
CliprdrServerContext* cliprdr;
|
||||||
|
|
||||||
|
/* used to external modules to store per-session info */
|
||||||
|
wHashTable* modules_info;
|
||||||
};
|
};
|
||||||
typedef struct p_server_context pServerContext;
|
typedef struct p_server_context pServerContext;
|
||||||
|
|
||||||
@ -93,18 +96,15 @@ struct proxy_data
|
|||||||
|
|
||||||
HANDLE abort_event;
|
HANDLE abort_event;
|
||||||
HANDLE client_thread;
|
HANDLE client_thread;
|
||||||
|
|
||||||
connectionInfo* info;
|
|
||||||
filters_list* filters;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* client */
|
/* client */
|
||||||
rdpContext* p_client_context_create(rdpSettings* clientSettings);
|
rdpContext* p_client_context_create(rdpSettings* clientSettings);
|
||||||
|
|
||||||
/* pdata */
|
/* pdata */
|
||||||
proxyData* proxy_data_new();
|
proxyData* proxy_data_new(void);
|
||||||
BOOL proxy_data_set_connection_info(proxyData* pdata, rdpSettings* ps, rdpSettings* pc);
|
|
||||||
void proxy_data_free(proxyData* pdata);
|
void proxy_data_free(proxyData* pdata);
|
||||||
|
|
||||||
BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src, BOOL is_dst_server);
|
BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src, BOOL is_dst_server);
|
||||||
void proxy_data_abort_connect(proxyData* pdata);
|
void proxy_data_abort_connect(proxyData* pdata);
|
||||||
BOOL proxy_data_shall_disconnect(proxyData* pdata);
|
BOOL proxy_data_shall_disconnect(proxyData* pdata);
|
||||||
|
@ -1,218 +0,0 @@
|
|||||||
/**
|
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
||||||
* FreeRDP Proxy Server
|
|
||||||
*
|
|
||||||
* Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
|
|
||||||
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
|
||||||
* Copyright 2019 Idan Freiberg <speidy@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 <assert.h>
|
|
||||||
|
|
||||||
#include <winpr/wlog.h>
|
|
||||||
#include <winpr/library.h>
|
|
||||||
#include <freerdp/api.h>
|
|
||||||
|
|
||||||
#include "pf_log.h"
|
|
||||||
#include "pf_filters.h"
|
|
||||||
|
|
||||||
#define TAG PROXY_TAG("filters")
|
|
||||||
#define FILTER_INIT_METHOD "filter_init"
|
|
||||||
|
|
||||||
static const char* FILTER_RESULT_STRINGS[] =
|
|
||||||
{
|
|
||||||
"FILTER_PASS",
|
|
||||||
"FILTER_DROP",
|
|
||||||
"FILTER_IGNORE",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* EVENT_TYPE_STRINGS[] =
|
|
||||||
{
|
|
||||||
"KEYBOARD_EVENT",
|
|
||||||
"MOUSE_EVENT",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* pf_filters_get_filter_result_string(PF_FILTER_RESULT result)
|
|
||||||
{
|
|
||||||
if (result >= FILTER_PASS && result <= FILTER_IGNORE)
|
|
||||||
return FILTER_RESULT_STRINGS[result];
|
|
||||||
else
|
|
||||||
return "FILTER_UNKNOWN";
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* pf_filters_get_event_type_string(PF_FILTER_TYPE result)
|
|
||||||
{
|
|
||||||
if (result >= FILTER_TYPE_KEYBOARD && result <= FILTER_TYPE_MOUSE)
|
|
||||||
return EVENT_TYPE_STRINGS[result];
|
|
||||||
else
|
|
||||||
return "EVENT_UNKNOWN";
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL pf_filters_init(filters_list** list)
|
|
||||||
{
|
|
||||||
if (list == NULL)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_filters_init(): list == NULL");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
*list = ArrayList_New(FALSE);
|
|
||||||
|
|
||||||
if (*list == NULL)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_filters_init(): ArrayList_New failed!");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PF_FILTER_RESULT pf_filters_run_by_type(filters_list* list, PF_FILTER_TYPE type,
|
|
||||||
connectionInfo* info,
|
|
||||||
void* param)
|
|
||||||
{
|
|
||||||
proxyFilter* filter;
|
|
||||||
proxyEvents* events;
|
|
||||||
PF_FILTER_RESULT result = FILTER_PASS;
|
|
||||||
const size_t count = (size_t) ArrayList_Count(list);
|
|
||||||
size_t index;
|
|
||||||
|
|
||||||
for (index = 0; index < count; index++)
|
|
||||||
{
|
|
||||||
filter = (proxyFilter*) ArrayList_GetItem(list, index);
|
|
||||||
events = filter->events;
|
|
||||||
WLog_VRB(TAG, "pf_filters_run_by_type(): Running filter: %s", filter->name);
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case FILTER_TYPE_KEYBOARD:
|
|
||||||
IFCALLRET(events->KeyboardEvent, result, info, param);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FILTER_TYPE_MOUSE:
|
|
||||||
IFCALLRET(events->MouseEvent, result, info, param);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != FILTER_PASS)
|
|
||||||
{
|
|
||||||
/* Filter returned FILTER_DROP or FILTER_IGNORE. There's no need to call next filters. */
|
|
||||||
WLog_INFO(TAG, "Filter %s [%s] returned %s", filter->name,
|
|
||||||
pf_filters_get_event_type_string(type), pf_filters_get_filter_result_string(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* all filters returned FILTER_PASS */
|
|
||||||
return FILTER_PASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pf_filters_filter_free(proxyFilter* filter)
|
|
||||||
{
|
|
||||||
if (!filter)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (filter->handle)
|
|
||||||
FreeLibrary(filter->handle);
|
|
||||||
|
|
||||||
free(filter->name);
|
|
||||||
free(filter->events);
|
|
||||||
free(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pf_filters_unregister_all(filters_list* list)
|
|
||||||
{
|
|
||||||
size_t count;
|
|
||||||
size_t index;
|
|
||||||
|
|
||||||
if (list == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
count = (size_t) ArrayList_Count(list);
|
|
||||||
|
|
||||||
for (index = 0; index < count; index++)
|
|
||||||
{
|
|
||||||
proxyFilter* filter = (proxyFilter*) ArrayList_GetItem(list, index);
|
|
||||||
WLog_DBG(TAG, "pf_filters_unregister_all(): freeing filter: %s", filter->name);
|
|
||||||
pf_filters_filter_free(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList_Free(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL pf_filters_register_new(filters_list* list, const char* module_path, const char* filter_name)
|
|
||||||
{
|
|
||||||
proxyEvents* events = NULL;
|
|
||||||
proxyFilter* filter = NULL;
|
|
||||||
HMODULE handle = NULL;
|
|
||||||
filterInitFn fn;
|
|
||||||
|
|
||||||
assert(list != NULL);
|
|
||||||
handle = LoadLibraryA(module_path);
|
|
||||||
|
|
||||||
if (handle == NULL)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_filters_register_new(): failed loading external module: %s", module_path);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(fn = (filterInitFn) GetProcAddress(handle, FILTER_INIT_METHOD)))
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_filters_register_new(): GetProcAddress failed while loading %s", module_path);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
filter = (proxyFilter*) malloc(sizeof(proxyFilter));
|
|
||||||
|
|
||||||
if (filter == NULL)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_filters_register_new(): malloc failed");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
events = calloc(1, sizeof(proxyEvents));
|
|
||||||
|
|
||||||
if (events == NULL)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_filters_register_new(): calloc proxyEvents failed");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fn(events))
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_filters_register_new(): failed calling external filter_init: %s", module_path);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
filter->handle = handle;
|
|
||||||
filter->name = _strdup(filter_name);
|
|
||||||
filter->events = events;
|
|
||||||
filter->enabled = TRUE;
|
|
||||||
|
|
||||||
if (ArrayList_Add(list, filter) < 0)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "pf_filters_register_new(): failed adding filter to list: %s", module_path);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
error:
|
|
||||||
|
|
||||||
if (handle)
|
|
||||||
FreeLibrary(handle);
|
|
||||||
|
|
||||||
pf_filters_filter_free(filter);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
/**
|
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
||||||
* FreeRDP Proxy Server
|
|
||||||
*
|
|
||||||
* Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
|
|
||||||
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
|
||||||
* Copyright 2019 Idan Freiberg <speidy@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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FREERDP_SERVER_PROXY_FILTERS_H
|
|
||||||
#define FREERDP_SERVER_PROXY_FILTERS_H
|
|
||||||
|
|
||||||
#include <winpr/wtypes.h>
|
|
||||||
#include <winpr/collections.h>
|
|
||||||
|
|
||||||
#include "filters/filters_api.h"
|
|
||||||
|
|
||||||
/* filter init method */
|
|
||||||
typedef BOOL (*filterInitFn)(proxyEvents* events);
|
|
||||||
|
|
||||||
typedef wArrayList filters_list;
|
|
||||||
typedef struct proxy_filter proxyFilter;
|
|
||||||
|
|
||||||
typedef enum _PF_FILTER_TYPE PF_FILTER_TYPE;
|
|
||||||
enum _PF_FILTER_TYPE
|
|
||||||
{
|
|
||||||
FILTER_TYPE_KEYBOARD,
|
|
||||||
FILTER_TYPE_MOUSE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct proxy_filter
|
|
||||||
{
|
|
||||||
/* Handle to the loaded library. Used for freeing the library */
|
|
||||||
HMODULE handle;
|
|
||||||
|
|
||||||
char* name;
|
|
||||||
BOOL enabled;
|
|
||||||
proxyEvents* events;
|
|
||||||
};
|
|
||||||
|
|
||||||
BOOL pf_filters_init(filters_list** list);
|
|
||||||
BOOL pf_filters_register_new(filters_list* list, const char* module_path, const char* filter_name);
|
|
||||||
PF_FILTER_RESULT pf_filters_run_by_type(filters_list* list, PF_FILTER_TYPE type,
|
|
||||||
connectionInfo* info,
|
|
||||||
void* param);
|
|
||||||
void pf_filters_unregister_all(filters_list* list);
|
|
||||||
|
|
||||||
#define RUN_FILTER(_filters,_type,_conn_info,_event_info,_ret,_cb,...) do { \
|
|
||||||
switch(pf_filters_run_by_type(_filters,_type,_conn_info,_event_info)) { \
|
|
||||||
case FILTER_PASS: \
|
|
||||||
_ret = _cb(__VA_ARGS__); \
|
|
||||||
break; \
|
|
||||||
case FILTER_IGNORE: \
|
|
||||||
_ret = TRUE; \
|
|
||||||
break; \
|
|
||||||
case FILTER_DROP: \
|
|
||||||
default: \
|
|
||||||
_ret = FALSE; \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#endif /* FREERDP_SERVER_PROXY_FILTERS_H */
|
|
350
server/proxy/pf_modules.c
Normal file
350
server/proxy/pf_modules.c
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* FreeRDP Proxy Server modules API
|
||||||
|
*
|
||||||
|
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
||||||
|
* Copyright 2019 Idan Freiberg <speidy@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 <assert.h>
|
||||||
|
|
||||||
|
#include <winpr/wlog.h>
|
||||||
|
#include <winpr/library.h>
|
||||||
|
#include <freerdp/api.h>
|
||||||
|
|
||||||
|
#include "pf_log.h"
|
||||||
|
#include "pf_modules.h"
|
||||||
|
#include "pf_context.h"
|
||||||
|
|
||||||
|
#define TAG PROXY_TAG("modules")
|
||||||
|
|
||||||
|
#define MODULE_INIT_METHOD "module_init"
|
||||||
|
#define MODULE_EXIT_METHOD "module_exit"
|
||||||
|
|
||||||
|
static modules_list* proxy_modules = NULL;
|
||||||
|
|
||||||
|
/* module init/exit methods */
|
||||||
|
typedef BOOL (*moduleInitFn)(moduleOperations* ops);
|
||||||
|
typedef BOOL (*moduleExitFn)(moduleOperations* ops);
|
||||||
|
|
||||||
|
static const char* FILTER_TYPE_STRINGS[] = {
|
||||||
|
"KEYBOARD_EVENT",
|
||||||
|
"MOUSE_EVENT",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* HOOK_TYPE_STRINGS[] = {
|
||||||
|
"CLIENT_PRE_CONNECT",
|
||||||
|
"SERVER_CHANNELS_INIT",
|
||||||
|
"SERVER_CHANNELS_FREE",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* pf_modules_get_filter_type_string(PF_FILTER_TYPE result)
|
||||||
|
{
|
||||||
|
if (result >= FILTER_TYPE_KEYBOARD && result <= FILTER_TYPE_MOUSE)
|
||||||
|
return FILTER_TYPE_STRINGS[result];
|
||||||
|
else
|
||||||
|
return "FILTER_UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
return HOOK_TYPE_STRINGS[result];
|
||||||
|
else
|
||||||
|
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`.
|
||||||
|
*
|
||||||
|
* @type: hook type to run.
|
||||||
|
* @server: pointer of server's rdpContext struct of the current session.
|
||||||
|
*/
|
||||||
|
BOOL pf_modules_run_hook(PF_HOOK_TYPE type, rdpContext* context)
|
||||||
|
{
|
||||||
|
|
||||||
|
proxyModule* module;
|
||||||
|
moduleOperations* ops;
|
||||||
|
BOOL ok = TRUE;
|
||||||
|
const size_t count = (size_t)ArrayList_Count(proxy_modules);
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
for (index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
module = (proxyModule*)ArrayList_GetItem(proxy_modules, index);
|
||||||
|
ops = module->ops;
|
||||||
|
WLog_VRB(TAG, "[%s]: Running module %s, hook %s", __FUNCTION__, module->name,
|
||||||
|
pf_modules_get_hook_type_string(type));
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case HOOK_TYPE_CLIENT_PRE_CONNECT:
|
||||||
|
IFCALLRET(ops->ClientPreConnect, ok, ops, context);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HOOK_TYPE_SERVER_CHANNELS_INIT:
|
||||||
|
IFCALLRET(ops->ServerChannelsInit, ok, ops, context);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HOOK_TYPE_SERVER_CHANNELS_FREE:
|
||||||
|
IFCALLRET(ops->ServerChannelsFree, ok, ops, context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
WLog_INFO(TAG, "Module %s, hook %s failed!", module->name,
|
||||||
|
pf_modules_get_hook_type_string(type));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* runs all filters of type `type`.
|
||||||
|
*
|
||||||
|
* @type: filter type to run.
|
||||||
|
* @server: pointer of server's rdpContext struct of the current session.
|
||||||
|
*/
|
||||||
|
BOOL pf_modules_run_filter(PF_FILTER_TYPE type, rdpContext* server, void* param)
|
||||||
|
{
|
||||||
|
proxyModule* module;
|
||||||
|
moduleOperations* ops;
|
||||||
|
BOOL result = TRUE;
|
||||||
|
const size_t count = (size_t)ArrayList_Count(proxy_modules);
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
for (index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
module = (proxyModule*)ArrayList_GetItem(proxy_modules, index);
|
||||||
|
ops = module->ops;
|
||||||
|
WLog_VRB(TAG, "[%s]: running filter: %s", __FUNCTION__, module->name);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case FILTER_TYPE_KEYBOARD:
|
||||||
|
IFCALLRET(ops->KeyboardEvent, result, ops, server, param);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILTER_TYPE_MOUSE:
|
||||||
|
IFCALLRET(ops->MouseEvent, result, ops, server, param);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
/* current filter return FALSE, no need to run other filters. */
|
||||||
|
WLog_INFO(TAG, "module %s, filter type [%s] returned FALSE", module->name,
|
||||||
|
pf_modules_get_filter_type_string(type));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all filters returned 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.
|
||||||
|
*
|
||||||
|
* @context: current session server's rdpContext instance.
|
||||||
|
* @info: pointer to per-session data.
|
||||||
|
*/
|
||||||
|
static BOOL pf_modules_set_session_data(moduleOperations* module, rdpContext* context, void* data)
|
||||||
|
{
|
||||||
|
pServerContext* ps;
|
||||||
|
|
||||||
|
assert(module);
|
||||||
|
assert(context);
|
||||||
|
|
||||||
|
if (data == NULL) /* no need to store anything */
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ps = (pServerContext*) context;
|
||||||
|
if (HashTable_Add(ps->modules_info, (void*)module, data) < 0)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "[%s]: HashTable_Add failed!");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* returns per-session data needed by module.
|
||||||
|
*
|
||||||
|
* @context: current session server's rdpContext instance.
|
||||||
|
* if there's no data related to `module` in `context` (current session), a NULL will be returned.
|
||||||
|
*/
|
||||||
|
static void* pf_modules_get_session_data(moduleOperations* module, rdpContext* context)
|
||||||
|
{
|
||||||
|
pServerContext* ps;
|
||||||
|
|
||||||
|
assert(module);
|
||||||
|
assert(context);
|
||||||
|
|
||||||
|
ps = (pServerContext*)context;
|
||||||
|
return HashTable_GetItemValue(ps->modules_info, module);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pf_modules_abort_connect(moduleOperations* module, rdpContext* context)
|
||||||
|
{
|
||||||
|
pServerContext* ps;
|
||||||
|
|
||||||
|
assert(module);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
moduleOperations* ops = NULL;
|
||||||
|
proxyModule* module = NULL;
|
||||||
|
HMODULE handle = NULL;
|
||||||
|
moduleInitFn fn;
|
||||||
|
|
||||||
|
assert(proxy_modules != NULL);
|
||||||
|
handle = LoadLibraryA(module_path);
|
||||||
|
|
||||||
|
if (handle == NULL)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "pf_modules_register_new(): failed loading external module: %s", module_path);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fn = (moduleInitFn)GetProcAddress(handle, MODULE_INIT_METHOD)))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "pf_modules_register_new(): GetProcAddress failed while loading %s",
|
||||||
|
module_path);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
module = (proxyModule*)calloc(1, sizeof(proxyModule));
|
||||||
|
|
||||||
|
if (module == NULL)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "pf_modules_register_new(): malloc failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = calloc(1, sizeof(moduleOperations));
|
||||||
|
|
||||||
|
if (ops == NULL)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "pf_modules_register_new(): calloc moduleOperations failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
error:
|
||||||
|
pf_modules_module_free(module);
|
||||||
|
return FALSE;
|
||||||
|
}
|
65
server/proxy/pf_modules.h
Normal file
65
server/proxy/pf_modules.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* FreeRDP Proxy Server
|
||||||
|
*
|
||||||
|
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
|
||||||
|
* Copyright 2019 Idan Freiberg <speidy@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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FREERDP_SERVER_PROXY_MODULES_H
|
||||||
|
#define FREERDP_SERVER_PROXY_MODULES_H
|
||||||
|
|
||||||
|
#include <winpr/wtypes.h>
|
||||||
|
#include <winpr/collections.h>
|
||||||
|
|
||||||
|
#include "modules/modules_api.h"
|
||||||
|
|
||||||
|
typedef wArrayList modules_list;
|
||||||
|
typedef struct proxy_module proxyModule;
|
||||||
|
|
||||||
|
typedef enum _PF_FILTER_TYPE PF_FILTER_TYPE;
|
||||||
|
enum _PF_FILTER_TYPE
|
||||||
|
{
|
||||||
|
FILTER_TYPE_KEYBOARD,
|
||||||
|
FILTER_TYPE_MOUSE
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum _PF_HOOK_TYPE PF_HOOK_TYPE;
|
||||||
|
enum _PF_HOOK_TYPE
|
||||||
|
{
|
||||||
|
HOOK_TYPE_CLIENT_PRE_CONNECT,
|
||||||
|
HOOK_TYPE_SERVER_CHANNELS_INIT,
|
||||||
|
HOOK_TYPE_SERVER_CHANNELS_FREE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct proxy_module
|
||||||
|
{
|
||||||
|
/* Handle to the loaded library. Used for freeing the library */
|
||||||
|
HMODULE handle;
|
||||||
|
|
||||||
|
char* name;
|
||||||
|
BOOL enabled;
|
||||||
|
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);
|
||||||
|
|
||||||
|
#endif /* FREERDP_SERVER_PROXY_MODULES_H */
|
Loading…
Reference in New Issue
Block a user