server/proxy: Add external filters support
This commit is contained in:
parent
3d346b69df
commit
a39658fc2a
@ -43,6 +43,8 @@ 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_filters.h
|
||||||
pf_log.h)
|
pf_log.h)
|
||||||
|
|
||||||
# On windows create dll version information.
|
# On windows create dll version information.
|
||||||
|
@ -31,3 +31,7 @@ RdpSecurity = 1
|
|||||||
WhitelistMode = 0
|
WhitelistMode = 0
|
||||||
AllowedChannels = "cliprdr,Microsoft::Windows::RDS::Video::Control"
|
AllowedChannels = "cliprdr,Microsoft::Windows::RDS::Video::Control"
|
||||||
DeniedChannels = "Microsoft::Windows::RDS::Geometry"
|
DeniedChannels = "Microsoft::Windows::RDS::Geometry"
|
||||||
|
|
||||||
|
[Filters]
|
||||||
|
; FilterName = FilterPath
|
||||||
|
DemoFilter = "server/proxy/demo.so"
|
||||||
|
25
server/proxy/filters/filter_demo.c
Normal file
25
server/proxy/filters/filter_demo.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "filters_api.h"
|
||||||
|
|
||||||
|
static PF_FILTER_RESULT demo_filter_keyboard_event(connectionInfo* info, void* param)
|
||||||
|
{
|
||||||
|
proxyKeyboardEventInfo* event_data = (proxyKeyboardEventInfo*) param;
|
||||||
|
return FILTER_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PF_FILTER_RESULT demo_filter_mouse_event(connectionInfo* info, void* param)
|
||||||
|
{
|
||||||
|
proxyMouseEventInfo* event_data = (proxyMouseEventInfo*) param;
|
||||||
|
|
||||||
|
if (event_data->x % 100 == 0)
|
||||||
|
{
|
||||||
|
return FILTER_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FILTER_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool filter_init(proxyEvents* events)
|
||||||
|
{
|
||||||
|
events->KeyboardEvent = demo_filter_keyboard_event;
|
||||||
|
events->MouseEvent = demo_filter_mouse_event;
|
||||||
|
}
|
69
server/proxy/filters/filters_api.h
Normal file
69
server/proxy/filters/filters_api.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* 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 <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
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_t flags;
|
||||||
|
uint16_t rdp_scan_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct proxy_mouse_event_info {
|
||||||
|
uint16_t flags;
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
|
||||||
|
/* implement this method */
|
||||||
|
bool filter_init(proxyEvents* events);
|
||||||
|
|
||||||
|
#endif /* FREERDP_SERVER_PROXY_FILTERS_API_H */
|
@ -22,6 +22,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/collections.h>
|
||||||
|
|
||||||
#include "pf_log.h"
|
#include "pf_log.h"
|
||||||
#include "pf_server.h"
|
#include "pf_server.h"
|
||||||
#include "pf_config.h"
|
#include "pf_config.h"
|
||||||
@ -30,39 +32,49 @@
|
|||||||
|
|
||||||
#define CHANNELS_SEPERATOR ","
|
#define CHANNELS_SEPERATOR ","
|
||||||
|
|
||||||
static char** parse_channels_from_str(const char* str, UINT32* length)
|
wArrayList* parse_string_array_from_str(const char* str)
|
||||||
{
|
{
|
||||||
char* s = strdup(str);
|
wArrayList* list = ArrayList_New(FALSE);
|
||||||
size_t tokens_alloc = 1;
|
|
||||||
size_t tokens_count = 0;
|
if (list == NULL)
|
||||||
char** tokens = calloc(tokens_alloc, sizeof(char*));
|
{
|
||||||
|
WLog_ERR(TAG, "parse_string_array_from_str(): ArrayList_New failed!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* s = _strdup(str);
|
||||||
|
char* temp = s;
|
||||||
char* token;
|
char* token;
|
||||||
|
|
||||||
while ((token = StrSep(&s, CHANNELS_SEPERATOR)) != NULL)
|
if (s == NULL)
|
||||||
{
|
{
|
||||||
if (tokens_count == tokens_alloc)
|
WLog_ERR(TAG, "parse_string_array_from_str(): strdup failed!");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((token = StrSep(&temp, CHANNELS_SEPERATOR)) != NULL)
|
||||||
|
{
|
||||||
|
char* current_token = _strdup(token);
|
||||||
|
|
||||||
|
if (current_token == NULL)
|
||||||
{
|
{
|
||||||
tokens_alloc *= 2;
|
WLog_ERR(TAG, "parse_string_array_from_str(): strdup failed!");
|
||||||
tokens = realloc(tokens, tokens_alloc * sizeof(char*));
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens[tokens_count++] = strdup(token);
|
if (ArrayList_Add(list, current_token) < 0)
|
||||||
|
{
|
||||||
|
free(current_token);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tokens_count == 0) || (tokens_count > UINT32_MAX))
|
|
||||||
{
|
|
||||||
free(tokens);
|
|
||||||
tokens = NULL;
|
|
||||||
tokens_count = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tokens = realloc(tokens, tokens_count * sizeof(char*));
|
|
||||||
}
|
|
||||||
|
|
||||||
*length = (DWORD)tokens_count;
|
|
||||||
free(s);
|
free(s);
|
||||||
return tokens;
|
return list;
|
||||||
|
error:
|
||||||
|
free(s);
|
||||||
|
ArrayList_Free(list);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL pf_server_is_config_valid(proxyConfig* config)
|
static BOOL pf_server_is_config_valid(proxyConfig* config)
|
||||||
@ -100,7 +112,9 @@ static BOOL pf_server_is_config_valid(proxyConfig* config)
|
|||||||
DWORD pf_server_load_config(const char* path, proxyConfig* config)
|
DWORD pf_server_load_config(const char* path, proxyConfig* config)
|
||||||
{
|
{
|
||||||
const char* input;
|
const char* input;
|
||||||
|
char** filters_names;
|
||||||
int rc;
|
int rc;
|
||||||
|
int filters_count = 0;
|
||||||
DWORD result = CONFIG_PARSE_ERROR;
|
DWORD result = CONFIG_PARSE_ERROR;
|
||||||
wIniFile* ini = IniFile_New();
|
wIniFile* ini = IniFile_New();
|
||||||
|
|
||||||
@ -141,10 +155,11 @@ DWORD pf_server_load_config(const char* path, proxyConfig* config)
|
|||||||
/* channels filtering */
|
/* channels filtering */
|
||||||
config->WhitelistMode = IniFile_GetKeyValueInt(ini, "Channels", "WhitelistMode");
|
config->WhitelistMode = IniFile_GetKeyValueInt(ini, "Channels", "WhitelistMode");
|
||||||
input = IniFile_GetKeyValueString(ini, "Channels", "AllowedChannels");
|
input = IniFile_GetKeyValueString(ini, "Channels", "AllowedChannels");
|
||||||
|
/* filters api */
|
||||||
|
|
||||||
if (input)
|
if (input)
|
||||||
{
|
{
|
||||||
config->AllowedChannels = parse_channels_from_str(input, &config->AllowedChannelsCount);
|
config->AllowedChannels = parse_string_array_from_str(input);
|
||||||
|
|
||||||
if (config->AllowedChannels == NULL)
|
if (config->AllowedChannels == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
@ -154,13 +169,34 @@ DWORD pf_server_load_config(const char* path, proxyConfig* config)
|
|||||||
|
|
||||||
if (input)
|
if (input)
|
||||||
{
|
{
|
||||||
config->BlockedChannels = parse_channels_from_str(input, &config->BlockedChannelsCount);
|
config->BlockedChannels = parse_string_array_from_str(input);
|
||||||
|
|
||||||
if (config->BlockedChannels == NULL)
|
if (config->BlockedChannels == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = CONFIG_PARSE_SUCCESS;
|
result = CONFIG_PARSE_SUCCESS;
|
||||||
|
|
||||||
|
if (!pf_filters_init(&config->Filters))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
filters_names = IniFile_GetSectionKeyNames(ini, "Filters", &filters_count);
|
||||||
|
|
||||||
|
for (int i = 0; i < filters_count; i++)
|
||||||
|
{
|
||||||
|
char* filter_name = filters_names[i];
|
||||||
|
const char* path = IniFile_GetKeyValueString(ini, "Filters", filter_name);
|
||||||
|
|
||||||
|
if (!pf_filters_register_new(config->Filters, path, filter_name))
|
||||||
|
{
|
||||||
|
WLog_DBG(TAG, "pf_server_load_config(): failed to register %s (%s)", filter_name, path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WLog_DBG(TAG, "pf_server_load_config(): registered filter %s (%s) successfully", filter_name, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
IniFile_Free(ini);
|
IniFile_Free(ini);
|
||||||
|
|
||||||
@ -172,16 +208,9 @@ out:
|
|||||||
|
|
||||||
void pf_server_config_free(proxyConfig* config)
|
void pf_server_config_free(proxyConfig* config)
|
||||||
{
|
{
|
||||||
UINT32 i;
|
pf_filters_unregister_all(config->Filters);
|
||||||
|
ArrayList_Free(config->AllowedChannels);
|
||||||
for (i = 0; i < config->AllowedChannelsCount; i++)
|
ArrayList_Free(config->BlockedChannels);
|
||||||
free(config->AllowedChannels[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < config->BlockedChannelsCount; i++)
|
|
||||||
free(config->BlockedChannels[i]);
|
|
||||||
|
|
||||||
free(config->AllowedChannels);
|
|
||||||
free(config->BlockedChannels);
|
|
||||||
free(config->TargetHost);
|
free(config->TargetHost);
|
||||||
free(config->Host);
|
free(config->Host);
|
||||||
free(config);
|
free(config);
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
#include <winpr/ini.h>
|
#include <winpr/ini.h>
|
||||||
|
|
||||||
|
#include "pf_filters.h"
|
||||||
|
|
||||||
struct proxy_config
|
struct proxy_config
|
||||||
{
|
{
|
||||||
/* server */
|
/* server */
|
||||||
@ -59,8 +61,8 @@ struct proxy_config
|
|||||||
char** AllowedChannels;
|
char** AllowedChannels;
|
||||||
UINT32 AllowedChannelsCount;
|
UINT32 AllowedChannelsCount;
|
||||||
|
|
||||||
char** BlockedChannels;
|
/* filters */
|
||||||
UINT32 BlockedChannelsCount;
|
filters_list* Filters;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct proxy_config proxyConfig;
|
typedef struct proxy_config proxyConfig;
|
||||||
|
@ -79,3 +79,37 @@ rdpContext* p_client_context_create(rdpSettings* clientSettings,
|
|||||||
settings->RedirectClipboard = FALSE;
|
settings->RedirectClipboard = FALSE;
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pf_context_connection_info_free(connectionInfo* info)
|
||||||
|
{
|
||||||
|
free(info->TargetHostname);
|
||||||
|
free(info->ClientHostname);
|
||||||
|
free(info->Username);
|
||||||
|
free(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyData* pf_context_proxy_data_new()
|
||||||
|
{
|
||||||
|
proxyData* pdata = malloc(sizeof(proxyData));
|
||||||
|
|
||||||
|
if (pdata == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdata->info = pf_context_connection_info_new();
|
||||||
|
|
||||||
|
if (pdata->info == NULL)
|
||||||
|
{
|
||||||
|
free(pdata);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pf_context_proxy_data_free(proxyData* pdata)
|
||||||
|
{
|
||||||
|
pf_context_connection_info_free(pdata->info);
|
||||||
|
free(pdata);
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <freerdp/server/rdpgfx.h>
|
#include <freerdp/server/rdpgfx.h>
|
||||||
#include "pf_config.h"
|
#include "pf_config.h"
|
||||||
#include "pf_server.h"
|
#include "pf_server.h"
|
||||||
|
#include "pf_filters.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct proxy_data proxyData;
|
typedef struct proxy_data proxyData;
|
||||||
@ -75,9 +76,16 @@ struct proxy_data
|
|||||||
pClientContext* pc;
|
pClientContext* pc;
|
||||||
|
|
||||||
HANDLE connectionClosed;
|
HANDLE connectionClosed;
|
||||||
|
|
||||||
|
connectionInfo* info;
|
||||||
|
filters_list* filters;
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOL init_p_server_context(freerdp_peer* client);
|
BOOL init_p_server_context(freerdp_peer* client);
|
||||||
rdpContext* p_client_context_create(rdpSettings* clientSettings, char* host, DWORD port);
|
rdpContext* p_client_context_create(rdpSettings* clientSettings, char* host, DWORD port);
|
||||||
|
proxyData* pf_context_proxy_data_new();
|
||||||
|
void pf_context_proxy_data_free(proxyData* pdata);
|
||||||
|
connectionInfo* pf_context_connection_info_new();
|
||||||
|
void pf_context_connection_info_free(connectionInfo* info);
|
||||||
|
|
||||||
#endif /* FREERDP_SERVER_PROXY_PFCONTEXT_H */
|
#endif /* FREERDP_SERVER_PROXY_PFCONTEXT_H */
|
||||||
|
218
server/proxy/pf_filters.c
Normal file
218
server/proxy/pf_filters.c
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
/**
|
||||||
|
* 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_DBG(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)
|
||||||
|
{
|
||||||
|
assert(filter != NULL);
|
||||||
|
FreeLibrary(filter->handle);
|
||||||
|
free(filter->name);
|
||||||
|
free(filter->events);
|
||||||
|
free(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pf_filters_unregister_all(filters_list* list)
|
||||||
|
{
|
||||||
|
if (list == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const size_t count = (size_t) ArrayList_Count(list);
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (list == NULL)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "pf_filters_register_new(): list == NULL");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle = LoadLibraryA(module_path);
|
||||||
|
|
||||||
|
if (handle == NULL)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "pf_filters_register_new(): failed loading external module: %s", module_path);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = malloc(sizeof(proxyEvents));
|
||||||
|
|
||||||
|
if (events == NULL)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "pf_filters_register_new(): failed loading external module: %s", module_path);
|
||||||
|
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);
|
||||||
|
|
||||||
|
free(events);
|
||||||
|
free(filter);
|
||||||
|
return FALSE;
|
||||||
|
}
|
75
server/proxy/pf_filters.h
Normal file
75
server/proxy/pf_filters.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* 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,_cb,...) ({ \
|
||||||
|
({ BOOL result; switch(pf_filters_run_by_type(_filters,_type,_conn_info,_event_info)) { \
|
||||||
|
case FILTER_PASS: \
|
||||||
|
result = _cb(__VA_ARGS__); \
|
||||||
|
break; \
|
||||||
|
case FILTER_IGNORE: \
|
||||||
|
result = TRUE; \
|
||||||
|
break; \
|
||||||
|
case FILTER_DROP: \
|
||||||
|
default: \
|
||||||
|
result = FALSE; \
|
||||||
|
}; result; \
|
||||||
|
}); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif /* FREERDP_SERVER_PROXY_FILTERS_H */
|
@ -40,7 +40,13 @@ static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
|||||||
if (!config->Keyboard)
|
if (!config->Keyboard)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
return freerdp_input_send_keyboard_event(context->input, flags, code);
|
proxyKeyboardEventInfo info =
|
||||||
|
{
|
||||||
|
.flags = flags,
|
||||||
|
.rdp_scan_code = code
|
||||||
|
};
|
||||||
|
return RUN_FILTER(config->Filters, FILTER_TYPE_KEYBOARD, ps->pdata->info, &info,
|
||||||
|
freerdp_input_send_keyboard_event, context->input, flags, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL pf_server_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
static BOOL pf_server_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
||||||
@ -66,7 +72,13 @@ static BOOL pf_server_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1
|
|||||||
if (!config->Mouse)
|
if (!config->Mouse)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
return freerdp_input_send_mouse_event(context->input, flags, x, y);
|
proxyMouseEventInfo info =
|
||||||
|
{
|
||||||
|
.flags = flags,
|
||||||
|
.x = x, .y = y
|
||||||
|
};
|
||||||
|
return RUN_FILTER(config->Filters, FILTER_TYPE_MOUSE, ps->pdata->info, &info,
|
||||||
|
freerdp_input_send_mouse_event, context->input, flags, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL pf_server_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,
|
static BOOL pf_server_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,
|
||||||
|
@ -158,7 +158,9 @@ static BOOL pf_server_post_connect(freerdp_peer* client)
|
|||||||
connectionClosedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
connectionClosedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
/* keep both sides of the connection in pdata */
|
/* keep both sides of the connection in pdata */
|
||||||
pc->pdata = ps->pdata;
|
pc->pdata = ps->pdata;
|
||||||
pdata->pc = (pClientContext*) pc;
|
pdata->info->TargetHostname = _strdup(host);
|
||||||
|
pdata->info->Username = _strdup(client->settings->Username);
|
||||||
|
pdata->pc = pc;
|
||||||
pdata->ps = ps;
|
pdata->ps = ps;
|
||||||
pdata->connectionClosed = connectionClosedEvent;
|
pdata->connectionClosed = connectionClosedEvent;
|
||||||
pf_server_rdpgfx_init(ps);
|
pf_server_rdpgfx_init(ps);
|
||||||
@ -206,7 +208,15 @@ static DWORD WINAPI pf_server_handle_client(LPVOID arg)
|
|||||||
|
|
||||||
ps = (pServerContext*) client->context;
|
ps = (pServerContext*) client->context;
|
||||||
ps->dynvcReady = CreateEvent(NULL, TRUE, FALSE, NULL);
|
ps->dynvcReady = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
pdata = calloc(1, sizeof(proxyData));
|
pdata = pf_context_proxy_data_new();
|
||||||
|
|
||||||
|
if (pdata == NULL)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "pf_context_proxy_data_new failed!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdata->info->ClientHostname = _strdup(client->hostname);
|
||||||
ps->pdata = pdata;
|
ps->pdata = pdata;
|
||||||
/* keep configuration in proxyData */
|
/* keep configuration in proxyData */
|
||||||
pdata->config = client->ContextExtra;
|
pdata->config = client->ContextExtra;
|
||||||
@ -320,7 +330,7 @@ fail:
|
|||||||
|
|
||||||
pc = (rdpContext*) pdata->pc;
|
pc = (rdpContext*) pdata->pc;
|
||||||
freerdp_client_stop(pc);
|
freerdp_client_stop(pc);
|
||||||
free(pdata);
|
pf_context_proxy_data_free(pdata);
|
||||||
freerdp_client_context_free(pc);
|
freerdp_client_context_free(pc);
|
||||||
client->Disconnect(client);
|
client->Disconnect(client);
|
||||||
freerdp_peer_context_free(client);
|
freerdp_peer_context_free(client);
|
||||||
|
Loading…
Reference in New Issue
Block a user