From a39658fc2a1e9dbfbe403582986334db8974ecf8 Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 12 May 2019 20:48:51 +0300 Subject: [PATCH 01/14] server/proxy: Add external filters support --- server/proxy/CMakeLists.txt | 2 + server/proxy/config.ini | 4 + server/proxy/filters/filter_demo.c | 25 ++++ server/proxy/filters/filters_api.h | 69 +++++++++ server/proxy/pf_config.c | 99 ++++++++----- server/proxy/pf_config.h | 6 +- server/proxy/pf_context.c | 34 +++++ server/proxy/pf_context.h | 8 ++ server/proxy/pf_filters.c | 218 +++++++++++++++++++++++++++++ server/proxy/pf_filters.h | 75 ++++++++++ server/proxy/pf_input.c | 16 ++- server/proxy/pf_server.c | 16 ++- 12 files changed, 530 insertions(+), 42 deletions(-) create mode 100644 server/proxy/filters/filter_demo.c create mode 100644 server/proxy/filters/filters_api.h create mode 100644 server/proxy/pf_filters.c create mode 100644 server/proxy/pf_filters.h diff --git a/server/proxy/CMakeLists.txt b/server/proxy/CMakeLists.txt index 6d749f577..46dc1208b 100644 --- a/server/proxy/CMakeLists.txt +++ b/server/proxy/CMakeLists.txt @@ -43,6 +43,8 @@ set(${MODULE_PREFIX}_SRCS pf_config.h pf_graphics.c pf_graphics.h + pf_filters.c + pf_filters.h pf_log.h) # On windows create dll version information. diff --git a/server/proxy/config.ini b/server/proxy/config.ini index 3a04dc6d1..c52804141 100644 --- a/server/proxy/config.ini +++ b/server/proxy/config.ini @@ -31,3 +31,7 @@ RdpSecurity = 1 WhitelistMode = 0 AllowedChannels = "cliprdr,Microsoft::Windows::RDS::Video::Control" DeniedChannels = "Microsoft::Windows::RDS::Geometry" + +[Filters] +; FilterName = FilterPath +DemoFilter = "server/proxy/demo.so" diff --git a/server/proxy/filters/filter_demo.c b/server/proxy/filters/filter_demo.c new file mode 100644 index 000000000..985dbcf85 --- /dev/null +++ b/server/proxy/filters/filter_demo.c @@ -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; +} diff --git a/server/proxy/filters/filters_api.h b/server/proxy/filters/filters_api.h new file mode 100644 index 000000000..c77386d42 --- /dev/null +++ b/server/proxy/filters/filters_api.h @@ -0,0 +1,69 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2019 Mati Shabtay + * Copyright 2019 Kobi Mizrachi + * Copyright 2019 Idan Freiberg + * + * 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 +#include + +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 */ diff --git a/server/proxy/pf_config.c b/server/proxy/pf_config.c index 388a1e5bb..88841e60b 100644 --- a/server/proxy/pf_config.c +++ b/server/proxy/pf_config.c @@ -22,6 +22,8 @@ #include #include #include +#include + #include "pf_log.h" #include "pf_server.h" #include "pf_config.h" @@ -30,39 +32,49 @@ #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); - size_t tokens_alloc = 1; - size_t tokens_count = 0; - char** tokens = calloc(tokens_alloc, sizeof(char*)); + wArrayList* list = ArrayList_New(FALSE); + + if (list == NULL) + { + WLog_ERR(TAG, "parse_string_array_from_str(): ArrayList_New failed!"); + return NULL; + } + + char* s = _strdup(str); + char* temp = s; 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; - tokens = realloc(tokens, tokens_alloc * sizeof(char*)); + WLog_ERR(TAG, "parse_string_array_from_str(): strdup failed!"); + 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); - return tokens; + return list; +error: + free(s); + ArrayList_Free(list); + return NULL; } 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) { const char* input; + char** filters_names; int rc; + int filters_count = 0; DWORD result = CONFIG_PARSE_ERROR; wIniFile* ini = IniFile_New(); @@ -141,10 +155,11 @@ DWORD pf_server_load_config(const char* path, proxyConfig* config) /* channels filtering */ config->WhitelistMode = IniFile_GetKeyValueInt(ini, "Channels", "WhitelistMode"); input = IniFile_GetKeyValueString(ini, "Channels", "AllowedChannels"); + /* filters api */ if (input) { - config->AllowedChannels = parse_channels_from_str(input, &config->AllowedChannelsCount); + config->AllowedChannels = parse_string_array_from_str(input); if (config->AllowedChannels == NULL) goto out; @@ -154,13 +169,34 @@ DWORD pf_server_load_config(const char* path, proxyConfig* config) if (input) { - config->BlockedChannels = parse_channels_from_str(input, &config->BlockedChannelsCount); + config->BlockedChannels = parse_string_array_from_str(input); if (config->BlockedChannels == NULL) goto out; } 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: IniFile_Free(ini); @@ -172,16 +208,9 @@ out: void pf_server_config_free(proxyConfig* config) { - UINT32 i; - - for (i = 0; i < config->AllowedChannelsCount; i++) - free(config->AllowedChannels[i]); - - for (i = 0; i < config->BlockedChannelsCount; i++) - free(config->BlockedChannels[i]); - - free(config->AllowedChannels); - free(config->BlockedChannels); + pf_filters_unregister_all(config->Filters); + ArrayList_Free(config->AllowedChannels); + ArrayList_Free(config->BlockedChannels); free(config->TargetHost); free(config->Host); free(config); diff --git a/server/proxy/pf_config.h b/server/proxy/pf_config.h index 3ae229977..26429a1d6 100644 --- a/server/proxy/pf_config.h +++ b/server/proxy/pf_config.h @@ -28,6 +28,8 @@ #include +#include "pf_filters.h" + struct proxy_config { /* server */ @@ -59,8 +61,8 @@ struct proxy_config char** AllowedChannels; UINT32 AllowedChannelsCount; - char** BlockedChannels; - UINT32 BlockedChannelsCount; + /* filters */ + filters_list* Filters; }; typedef struct proxy_config proxyConfig; diff --git a/server/proxy/pf_context.c b/server/proxy/pf_context.c index 0e00d4039..b8c516b2b 100644 --- a/server/proxy/pf_context.c +++ b/server/proxy/pf_context.c @@ -79,3 +79,37 @@ rdpContext* p_client_context_create(rdpSettings* clientSettings, settings->RedirectClipboard = FALSE; 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); +} diff --git a/server/proxy/pf_context.h b/server/proxy/pf_context.h index fa92168de..ae9856fc6 100644 --- a/server/proxy/pf_context.h +++ b/server/proxy/pf_context.h @@ -29,6 +29,7 @@ #include #include "pf_config.h" #include "pf_server.h" +#include "pf_filters.h" typedef struct proxy_data proxyData; @@ -75,9 +76,16 @@ struct proxy_data pClientContext* pc; HANDLE connectionClosed; + + connectionInfo* info; + filters_list* filters; }; BOOL init_p_server_context(freerdp_peer* client); 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 */ diff --git a/server/proxy/pf_filters.c b/server/proxy/pf_filters.c new file mode 100644 index 000000000..171cb4aaf --- /dev/null +++ b/server/proxy/pf_filters.c @@ -0,0 +1,218 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2019 Mati Shabtay + * Copyright 2019 Kobi Mizrachi + * Copyright 2019 Idan Freiberg + * + * 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 + +#include +#include +#include + +#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; +} diff --git a/server/proxy/pf_filters.h b/server/proxy/pf_filters.h new file mode 100644 index 000000000..8924bcade --- /dev/null +++ b/server/proxy/pf_filters.h @@ -0,0 +1,75 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2019 Mati Shabtay + * Copyright 2019 Kobi Mizrachi + * Copyright 2019 Idan Freiberg + * + * 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 +#include + +#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 */ diff --git a/server/proxy/pf_input.c b/server/proxy/pf_input.c index 6babb2b5d..396129224 100644 --- a/server/proxy/pf_input.c +++ b/server/proxy/pf_input.c @@ -40,7 +40,13 @@ static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) if (!config->Keyboard) 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) @@ -66,7 +72,13 @@ static BOOL pf_server_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1 if (!config->Mouse) 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, diff --git a/server/proxy/pf_server.c b/server/proxy/pf_server.c index c9e933fca..e85b4da49 100644 --- a/server/proxy/pf_server.c +++ b/server/proxy/pf_server.c @@ -158,7 +158,9 @@ static BOOL pf_server_post_connect(freerdp_peer* client) connectionClosedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* keep both sides of the connection in 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->connectionClosed = connectionClosedEvent; pf_server_rdpgfx_init(ps); @@ -206,7 +208,15 @@ static DWORD WINAPI pf_server_handle_client(LPVOID arg) ps = (pServerContext*) client->context; 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; /* keep configuration in proxyData */ pdata->config = client->ContextExtra; @@ -320,7 +330,7 @@ fail: pc = (rdpContext*) pdata->pc; freerdp_client_stop(pc); - free(pdata); + pf_context_proxy_data_free(pdata); freerdp_client_context_free(pc); client->Disconnect(client); freerdp_peer_context_free(client); From c4d72c6ad2f82147f5caa5e587d7eddbe98dbb5f Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 12 May 2019 20:49:37 +0300 Subject: [PATCH 02/14] server/proxy: Refactor pf_server_parse_target_from_routing_token --- server/proxy/pf_server.c | 62 ++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/server/proxy/pf_server.c b/server/proxy/pf_server.c index e85b4da49..a34188da7 100644 --- a/server/proxy/pf_server.c +++ b/server/proxy/pf_server.c @@ -82,37 +82,43 @@ static BOOL pf_server_parse_target_from_routing_token(freerdp_peer* client, DWORD routing_token_length; const char* routing_token = freerdp_nego_get_routing_token(client->context, &routing_token_length); - if (routing_token && - (routing_token_length > prefix_len) && (routing_token_length < TARGET_MAX)) + if (routing_token == NULL) { - len = routing_token_length - prefix_len; - *target = malloc(len + 1); - - if (!(*target)) - return FALSE; - - CopyMemory(*target, routing_token + prefix_len, len); - *(*target + len) = '\0'; - colon = strchr(*target, ':'); - WLog_INFO(TAG, "Target [parsed from routing token]: %s", *target); - - if (colon) - { - /* port is specified */ - unsigned long p = strtoul(colon + 1, NULL, 10); - - if (p > USHRT_MAX) - return FALSE; - - *port = (DWORD)p; - *colon = '\0'; - } - - return TRUE; + /* no routing token */ + return FALSE; } - /* no routing token */ - return FALSE; + if ((routing_token_length <= prefix_len) || (routing_token_length >= TARGET_MAX)) + { + WLog_ERR(TAG, "pf_server_parse_target_from_routing_token: bad routing token length: %i", + routing_token_length); + return FALSE; + } + + len = routing_token_length - prefix_len; + *target = malloc(len + 1); + + if (!(*target)) + return FALSE; + + CopyMemory(*target, routing_token + prefix_len, len); + *(*target + len) = '\0'; + colon = strchr(*target, ':'); + WLog_INFO(TAG, "Target [parsed from routing token]: %s", *target); + + if (colon) + { + /* port is specified */ + unsigned long p = strtoul(colon + 1, NULL, 10); + + if (p > USHRT_MAX) + return FALSE; + + *port = (DWORD)p; + *colon = '\0'; + } + + return TRUE; } /* Event callbacks */ From 3a750810f771572f7fe5546ac663f913a01cbd5f Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 12 May 2019 20:50:26 +0300 Subject: [PATCH 03/14] server/proxy: Refactor pf_server.c --- server/proxy/pf_server.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/server/proxy/pf_server.c b/server/proxy/pf_server.c index a34188da7..4a80d023a 100644 --- a/server/proxy/pf_server.c +++ b/server/proxy/pf_server.c @@ -134,7 +134,6 @@ static BOOL pf_server_post_connect(freerdp_peer* client) proxyConfig* config; pServerContext* ps; pClientContext* pc; - HANDLE connectionClosedEvent; proxyData* pdata; char* host = NULL; DWORD port = 3389; /* default port */ @@ -149,8 +148,6 @@ static BOOL pf_server_post_connect(freerdp_peer* client) WLog_ERR(TAG, "pf_server_parse_target_from_routing_token failed!"); return FALSE; } - - WLog_DBG(TAG, "Parsed target from load-balance-info: %s:%i", host, port); } else { @@ -161,14 +158,13 @@ static BOOL pf_server_post_connect(freerdp_peer* client) } pc = (pClientContext*) p_client_context_create(client->settings, host, port); - connectionClosedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* keep both sides of the connection in pdata */ pc->pdata = ps->pdata; pdata->info->TargetHostname = _strdup(host); pdata->info->Username = _strdup(client->settings->Username); pdata->pc = pc; pdata->ps = ps; - pdata->connectionClosed = connectionClosedEvent; + pdata->connectionClosed = CreateEvent(NULL, TRUE, FALSE, NULL); pf_server_rdpgfx_init(ps); /* Start a proxy's client in it's own thread */ From 96616bb18c8efc413c89a24e8dbc8fddb3e336fb Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 12 May 2019 20:51:54 +0300 Subject: [PATCH 04/14] server/proxy: Use new parse_string_array_from_str implementation (using ArrayList) --- server/proxy/freerdp_proxy.c | 11 +++++++---- server/proxy/pf_config.h | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/server/proxy/freerdp_proxy.c b/server/proxy/freerdp_proxy.c index d85afd44a..fa4ba92b1 100644 --- a/server/proxy/freerdp_proxy.c +++ b/server/proxy/freerdp_proxy.c @@ -22,6 +22,9 @@ #include "pf_server.h" #include "pf_config.h" #include "pf_log.h" +#include "pf_filters.h" + +#include #define TAG PROXY_TAG("server") @@ -59,15 +62,15 @@ int main(int argc, char* argv[]) { WLog_INFO(TAG, "Channels mode: WHITELIST"); - for (i = 0; i < config->AllowedChannelsCount; i++) - WLog_INFO(TAG, "Allowing %s", config->AllowedChannels[i]); + for (i = 0; i < ArrayList_Count(config->AllowedChannels); i++) + WLog_INFO(TAG, "Allowing %s", (char*) ArrayList_GetItem(config->AllowedChannels, i)); } else { WLog_INFO(TAG, "Channels mode: BLACKLIST"); - for (i = 0; i < config->BlockedChannelsCount; i++) - WLog_INFO(TAG, "Blocking %s", config->BlockedChannels[i]); + for (i = 0; i < ArrayList_Count(config->BlockedChannels); i++) + WLog_INFO(TAG, "Blocking %s", (char*) ArrayList_GetItem(config->BlockedChannels, i)); } status = pf_server_start(config); diff --git a/server/proxy/pf_config.h b/server/proxy/pf_config.h index 26429a1d6..a432cff63 100644 --- a/server/proxy/pf_config.h +++ b/server/proxy/pf_config.h @@ -58,8 +58,8 @@ struct proxy_config /* channels */ BOOL WhitelistMode; - char** AllowedChannels; - UINT32 AllowedChannelsCount; + wArrayList* AllowedChannels; + wArrayList* BlockedChannels; /* filters */ filters_list* Filters; From 7237624b37b0313dd5b7021ffbdfd607c3702631 Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 12 May 2019 14:02:50 +0300 Subject: [PATCH 05/14] bugfix: segfault when calling an event which is not implemented by filter --- server/proxy/pf_filters.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/proxy/pf_filters.c b/server/proxy/pf_filters.c index 171cb4aaf..92d53d2da 100644 --- a/server/proxy/pf_filters.c +++ b/server/proxy/pf_filters.c @@ -181,11 +181,11 @@ BOOL pf_filters_register_new(filters_list* list, const char* module_path, const goto error; } - events = malloc(sizeof(proxyEvents)); + events = calloc(1, sizeof(proxyEvents)); if (events == NULL) { - WLog_ERR(TAG, "pf_filters_register_new(): failed loading external module: %s", module_path); + WLog_ERR(TAG, "pf_filters_register_new(): calloc proxyEvents failed"); goto error; } From 98f698cf2b51192d474a8d94f72f344090ddefd7 Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 12 May 2019 15:04:44 +0300 Subject: [PATCH 06/14] Add README for filters API --- server/proxy/filters/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 server/proxy/filters/README.md diff --git a/server/proxy/filters/README.md b/server/proxy/filters/README.md new file mode 100644 index 000000000..c6b3b81c1 --- /dev/null +++ b/server/proxy/filters/README.md @@ -0,0 +1,27 @@ +# Proxy filter API + +`freerdp-proxy` has an API for filtering certain messages. A filter can register callbacks to events, allowing to record the data and control whether to pass/ignore the message, or right out drop the connection. + +During startup, the proxy loads its filters from the configuration: +```ini +[Filters] +; FilterName = FilterPath +DemoFilter = "server/proxy/demo.so" +``` + +## Currently supported events +* Mouse event +* Keyboard event + +## Developing a new filter +* Create a new file that includes `filters_api.h`. +* Implement the `filter_init` function and register the callbacks you are interested in. +* Each callback receives two parameters: + * `connectionInfo* info` holds connection info of the raised event. + * `void* param` holds the actual event data. It should be casted by the filter to the suitable struct from `filters_api.h`. +* Each callback must return a `PF_FILTER_RESULT`: + * `FILTER_IGNORE`: The event will not be proxied. + * `FILTER_PASS`: The event will be proxied. + * `FILTER_DROP`: The entire connection will be dropped. + +A demo can be found in `filter_demo.c`. \ No newline at end of file From 8e642c9d00180261ee277a307618770b75b31d46 Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 12 May 2019 21:24:35 +0300 Subject: [PATCH 07/14] server/proxy: Add return statement in demo_filter.c --- server/proxy/filters/filter_demo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/proxy/filters/filter_demo.c b/server/proxy/filters/filter_demo.c index 985dbcf85..c203c451a 100644 --- a/server/proxy/filters/filter_demo.c +++ b/server/proxy/filters/filter_demo.c @@ -22,4 +22,6 @@ bool filter_init(proxyEvents* events) { events->KeyboardEvent = demo_filter_keyboard_event; events->MouseEvent = demo_filter_mouse_event; + + return true; } From 212602432107457092f019607339365691dcaa67 Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 12 May 2019 21:25:00 +0300 Subject: [PATCH 08/14] server/proxy: Add docs in filters_api.h --- server/proxy/filters/filters_api.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/proxy/filters/filters_api.h b/server/proxy/filters/filters_api.h index c77386d42..648aa8485 100644 --- a/server/proxy/filters/filters_api.h +++ b/server/proxy/filters/filters_api.h @@ -63,7 +63,9 @@ struct proxy_mouse_event_info { #pragma pack(pop) -/* implement this method */ +/* implement this method and register callbacks for proxy events + * return TRUE if initialization succeeded, otherwise FALSE. + **/ bool filter_init(proxyEvents* events); #endif /* FREERDP_SERVER_PROXY_FILTERS_API_H */ From 20e503421e723402bb8bfac582b0be92fd6165e8 Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 12 May 2019 21:25:36 +0300 Subject: [PATCH 09/14] server/proxy: Remove unnecessary wrap for connection info --- server/proxy/pf_context.c | 2 +- server/proxy/pf_context.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/server/proxy/pf_context.c b/server/proxy/pf_context.c index b8c516b2b..8f45cf2e6 100644 --- a/server/proxy/pf_context.c +++ b/server/proxy/pf_context.c @@ -97,7 +97,7 @@ proxyData* pf_context_proxy_data_new() return NULL; } - pdata->info = pf_context_connection_info_new(); + pdata->info = malloc(sizeof(connectionInfo)); if (pdata->info == NULL) { diff --git a/server/proxy/pf_context.h b/server/proxy/pf_context.h index ae9856fc6..92d32bb29 100644 --- a/server/proxy/pf_context.h +++ b/server/proxy/pf_context.h @@ -85,7 +85,5 @@ BOOL init_p_server_context(freerdp_peer* client); 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 */ From 76012fb5d6ae86582818471fae2456cc73503fe6 Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 19 May 2019 15:04:38 +0300 Subject: [PATCH 10/14] server/proxy: Fix mem leak in pf_server_parse_target_from_routing_token --- server/proxy/pf_server.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/proxy/pf_server.c b/server/proxy/pf_server.c index 4a80d023a..eb7fb041e 100644 --- a/server/proxy/pf_server.c +++ b/server/proxy/pf_server.c @@ -112,7 +112,10 @@ static BOOL pf_server_parse_target_from_routing_token(freerdp_peer* client, unsigned long p = strtoul(colon + 1, NULL, 10); if (p > USHRT_MAX) + { + free(*target); return FALSE; + } *port = (DWORD)p; *colon = '\0'; From 7477ac19a711a37441214deeabd19db1d8d04614 Mon Sep 17 00:00:00 2001 From: kubistika Date: Mon, 13 May 2019 11:11:24 +0300 Subject: [PATCH 11/14] server/proxy: Fix free invalid memory when pf_server_parse_target_from_routing_token fails --- server/proxy/pf_context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/proxy/pf_context.c b/server/proxy/pf_context.c index 8f45cf2e6..c64c80ee2 100644 --- a/server/proxy/pf_context.c +++ b/server/proxy/pf_context.c @@ -90,14 +90,14 @@ static void pf_context_connection_info_free(connectionInfo* info) proxyData* pf_context_proxy_data_new() { - proxyData* pdata = malloc(sizeof(proxyData)); + proxyData* pdata = calloc(1, sizeof(proxyData)); if (pdata == NULL) { return NULL; } - pdata->info = malloc(sizeof(connectionInfo)); + pdata->info = calloc(1, sizeof(connectionInfo)); if (pdata->info == NULL) { From aa262d341d291c85f28c5494204ab0080cfdeabf Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 26 May 2019 15:29:41 +0300 Subject: [PATCH 12/14] server/proxy: Use winpr library in proxy/filters --- server/proxy/CMakeLists.txt | 2 ++ server/proxy/config.ini | 2 +- server/proxy/filters/CMakeLists.txt | 3 +++ server/proxy/filters/filter_demo.c | 25 +++++++++++++++++++++++-- server/proxy/filters/filters_api.h | 16 +++++++--------- server/proxy/freerdp_proxy.c | 7 +++++-- 6 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 server/proxy/filters/CMakeLists.txt diff --git a/server/proxy/CMakeLists.txt b/server/proxy/CMakeLists.txt index 46dc1208b..a944f005e 100644 --- a/server/proxy/CMakeLists.txt +++ b/server/proxy/CMakeLists.txt @@ -76,3 +76,5 @@ if (WITH_DEBUG_SYMBOLS AND MSVC) endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/proxy") + +add_subdirectory("filters") diff --git a/server/proxy/config.ini b/server/proxy/config.ini index c52804141..fe29861e4 100644 --- a/server/proxy/config.ini +++ b/server/proxy/config.ini @@ -34,4 +34,4 @@ DeniedChannels = "Microsoft::Windows::RDS::Geometry" [Filters] ; FilterName = FilterPath -DemoFilter = "server/proxy/demo.so" +DemoFilter = "server/proxy/filters/libdemo_filter.so" diff --git a/server/proxy/filters/CMakeLists.txt b/server/proxy/filters/CMakeLists.txt new file mode 100644 index 000000000..43f753469 --- /dev/null +++ b/server/proxy/filters/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(demo_filter SHARED + filter_demo.c +) diff --git a/server/proxy/filters/filter_demo.c b/server/proxy/filters/filter_demo.c index c203c451a..fd3a31079 100644 --- a/server/proxy/filters/filter_demo.c +++ b/server/proxy/filters/filter_demo.c @@ -1,8 +1,29 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2019 Kobi Mizrachi + * + * 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 "filters_api.h" static PF_FILTER_RESULT demo_filter_keyboard_event(connectionInfo* info, void* param) { proxyKeyboardEventInfo* event_data = (proxyKeyboardEventInfo*) param; + WINPR_UNUSED(event_data); + return FILTER_PASS; } @@ -18,10 +39,10 @@ static PF_FILTER_RESULT demo_filter_mouse_event(connectionInfo* info, void* para return FILTER_PASS; } -bool filter_init(proxyEvents* events) +BOOL filter_init(proxyEvents* events) { events->KeyboardEvent = demo_filter_keyboard_event; events->MouseEvent = demo_filter_mouse_event; - return true; + return TRUE; } diff --git a/server/proxy/filters/filters_api.h b/server/proxy/filters/filters_api.h index 648aa8485..644ebc962 100644 --- a/server/proxy/filters/filters_api.h +++ b/server/proxy/filters/filters_api.h @@ -22,8 +22,7 @@ #ifndef FREERDP_SERVER_PROXY_FILTERS_API_H #define FREERDP_SERVER_PROXY_FILTERS_API_H -#include -#include +#include enum pf_filter_result { FILTER_PASS = 0, @@ -51,21 +50,20 @@ struct proxy_events { #pragma pack(push, 1) struct proxy_keyboard_event_info { - uint16_t flags; - uint16_t rdp_scan_code; + UINT16 flags; + UINT16 rdp_scan_code; }; struct proxy_mouse_event_info { - uint16_t flags; - uint16_t x; - uint16_t y; + 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. **/ -bool filter_init(proxyEvents* events); +BOOL filter_init(proxyEvents* events); #endif /* FREERDP_SERVER_PROXY_FILTERS_API_H */ diff --git a/server/proxy/freerdp_proxy.c b/server/proxy/freerdp_proxy.c index fa4ba92b1..80fa85adf 100644 --- a/server/proxy/freerdp_proxy.c +++ b/server/proxy/freerdp_proxy.c @@ -34,6 +34,7 @@ int main(int argc, char* argv[]) int status = 0; DWORD ld; UINT32 i; + UINT32 count; proxyConfig* config = calloc(1, sizeof(proxyConfig)); if (!config) @@ -61,15 +62,17 @@ int main(int argc, char* argv[]) if (config->WhitelistMode) { WLog_INFO(TAG, "Channels mode: WHITELIST"); + count = ArrayList_Count(config->AllowedChannels); - for (i = 0; i < ArrayList_Count(config->AllowedChannels); i++) + for (i = 0; i < count; i++) WLog_INFO(TAG, "Allowing %s", (char*) ArrayList_GetItem(config->AllowedChannels, i)); } else { WLog_INFO(TAG, "Channels mode: BLACKLIST"); + count = ArrayList_Count(config->BlockedChannels); - for (i = 0; i < ArrayList_Count(config->BlockedChannels); i++) + for (i = 0; i < count; i++) WLog_INFO(TAG, "Blocking %s", (char*) ArrayList_GetItem(config->BlockedChannels, i)); } From 52e4baa949c53c064fbf0f32f4f6f8f067b918af Mon Sep 17 00:00:00 2001 From: kubistika Date: Sun, 26 May 2019 15:33:28 +0300 Subject: [PATCH 13/14] server/proxy: Code refactor --- server/proxy/filters/filter_demo.c | 8 +- server/proxy/pf_context.c | 37 +++++-- server/proxy/pf_context.h | 9 +- server/proxy/pf_filters.c | 7 +- server/proxy/pf_server.c | 157 +++++++++++++++-------------- 5 files changed, 121 insertions(+), 97 deletions(-) diff --git a/server/proxy/filters/filter_demo.c b/server/proxy/filters/filter_demo.c index fd3a31079..2653fec8d 100644 --- a/server/proxy/filters/filter_demo.c +++ b/server/proxy/filters/filter_demo.c @@ -31,10 +31,10 @@ static PF_FILTER_RESULT demo_filter_mouse_event(connectionInfo* info, void* para { proxyMouseEventInfo* event_data = (proxyMouseEventInfo*) param; - if (event_data->x % 100 == 0) - { - return FILTER_DROP; - } + if (event_data->x % 100 == 0) + { + return FILTER_DROP; + } return FILTER_PASS; } diff --git a/server/proxy/pf_context.c b/server/proxy/pf_context.c index c64c80ee2..90afd1ca0 100644 --- a/server/proxy/pf_context.c +++ b/server/proxy/pf_context.c @@ -56,8 +56,7 @@ BOOL init_p_server_context(freerdp_peer* client) return freerdp_peer_context_new(client); } -rdpContext* p_client_context_create(rdpSettings* clientSettings, - char* host, DWORD port) +rdpContext* p_client_context_create(rdpSettings* clientSettings) { RDP_CLIENT_ENTRY_POINTS clientEntryPoints; rdpContext* context; @@ -73,14 +72,12 @@ rdpContext* p_client_context_create(rdpSettings* clientSettings, settings->Username = _strdup(clientSettings->Username); settings->Password = _strdup(clientSettings->Password); settings->Domain = _strdup(clientSettings->Domain); - settings->ServerHostname = host; - settings->ServerPort = port; settings->SoftwareGdi = FALSE; settings->RedirectClipboard = FALSE; return context; } -static void pf_context_connection_info_free(connectionInfo* info) +static void connection_info_free(connectionInfo* info) { free(info->TargetHostname); free(info->ClientHostname); @@ -88,7 +85,7 @@ static void pf_context_connection_info_free(connectionInfo* info) free(info); } -proxyData* pf_context_proxy_data_new() +proxyData* proxy_data_new() { proxyData* pdata = calloc(1, sizeof(proxyData)); @@ -105,11 +102,35 @@ proxyData* pf_context_proxy_data_new() return NULL; } + if (!(pdata->connectionClosed = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + proxy_data_free(pdata); + return NULL; + } + return pdata; } -void pf_context_proxy_data_free(proxyData* pdata) +BOOL proxy_data_set_connection_info(proxyData* pdata, rdpSettings* clientSettings, + const char* target) { - pf_context_connection_info_free(pdata->info); + if (!(pdata->info->TargetHostname = _strdup(target))) + goto out_fail; + + if (!(pdata->info->ClientHostname = _strdup(clientSettings->ClientHostname))) + goto out_fail; + + if (!(pdata->info->Username = _strdup(clientSettings->Username))) + goto out_fail; + + return TRUE; +out_fail: + proxy_data_free(pdata); + return FALSE; +} + +void proxy_data_free(proxyData* pdata) +{ + connection_info_free(pdata->info); free(pdata); } diff --git a/server/proxy/pf_context.h b/server/proxy/pf_context.h index 92d32bb29..b63da7d8b 100644 --- a/server/proxy/pf_context.h +++ b/server/proxy/pf_context.h @@ -31,7 +31,6 @@ #include "pf_server.h" #include "pf_filters.h" - typedef struct proxy_data proxyData; /** @@ -82,8 +81,10 @@ struct proxy_data }; BOOL init_p_server_context(freerdp_peer* client); -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); +rdpContext* p_client_context_create(rdpSettings* clientSettings); +proxyData* proxy_data_new(); +BOOL proxy_data_set_connection_info(proxyData* pdata, rdpSettings* clientSettings, + const char* target); +void proxy_data_free(proxyData* pdata); #endif /* FREERDP_SERVER_PROXY_PFCONTEXT_H */ diff --git a/server/proxy/pf_filters.c b/server/proxy/pf_filters.c index 92d53d2da..41bad3e8a 100644 --- a/server/proxy/pf_filters.c +++ b/server/proxy/pf_filters.c @@ -153,12 +153,7 @@ BOOL pf_filters_register_new(filters_list* list, const char* module_path, const HMODULE handle = NULL; filterInitFn fn; - if (list == NULL) - { - WLog_ERR(TAG, "pf_filters_register_new(): list == NULL"); - goto error; - } - + assert(list != NULL); handle = LoadLibraryA(module_path); if (handle == NULL) diff --git a/server/proxy/pf_server.c b/server/proxy/pf_server.c index eb7fb041e..2a7558f87 100644 --- a/server/proxy/pf_server.c +++ b/server/proxy/pf_server.c @@ -71,7 +71,7 @@ static void pf_server_handle_client_disconnection(freerdp_peer* client) CloseHandle(ps->thread); } -static BOOL pf_server_parse_target_from_routing_token(freerdp_peer* client, +static BOOL pf_server_parse_target_from_routing_token(rdpContext* context, char** target, DWORD* port) { #define TARGET_MAX (100) @@ -80,7 +80,7 @@ static BOOL pf_server_parse_target_from_routing_token(freerdp_peer* client, size_t len; const size_t prefix_len = strlen(ROUTING_TOKEN_PREFIX); DWORD routing_token_length; - const char* routing_token = freerdp_nego_get_routing_token(client->context, &routing_token_length); + const char* routing_token = freerdp_nego_get_routing_token(context, &routing_token_length); if (routing_token == NULL) { @@ -124,6 +124,28 @@ static BOOL pf_server_parse_target_from_routing_token(freerdp_peer* client, return TRUE; } +static BOOL pf_server_get_target_info(rdpContext* context, rdpSettings* settings, + proxyConfig* config) +{ + WLog_INFO(TAG, "pf_server_get_target_info: UseLoadBalanceInfo = %d", config->UseLoadBalanceInfo); + + if (config->UseLoadBalanceInfo) + return pf_server_parse_target_from_routing_token(context, &settings->ServerHostname, + &settings->ServerPort); + + /* use hardcoded target info from configuration */ + if (!(settings->ServerHostname = _strdup(config->TargetHost))) + { + WLog_DBG(TAG, "pf_server_get_target_info(): strdup failed!"); + return FALSE; + } + + settings->ServerPort = config->TargetPort > 0 ? 3389 : settings->ServerPort; + WLog_INFO(TAG, "Using target host from config: %s:%i", settings->ServerHostname, + settings->ServerPort); + return TRUE; +} + /* Event callbacks */ /** * This callback is called when the entire connection sequence is done (as @@ -134,45 +156,35 @@ static BOOL pf_server_parse_target_from_routing_token(freerdp_peer* client, */ static BOOL pf_server_post_connect(freerdp_peer* client) { - proxyConfig* config; pServerContext* ps; - pClientContext* pc; + rdpContext* pc; proxyData* pdata; - char* host = NULL; - DWORD port = 3389; /* default port */ + ps = (pServerContext*)client->context; pdata = ps->pdata; - config = pdata->config; - if (config->UseLoadBalanceInfo) - { - if (!pf_server_parse_target_from_routing_token(client, &host, &port)) - { - WLog_ERR(TAG, "pf_server_parse_target_from_routing_token failed!"); - return FALSE; - } - } - else - { - /* use hardcoded target info from configuration */ - host = _strdup(config->TargetHost); - port = config->TargetPort > 0 ? config->TargetPort : port; - WLog_DBG(TAG, "Using hardcoded target host: %s:%i", host, port); - } + pc = p_client_context_create(client->settings); - pc = (pClientContext*) p_client_context_create(client->settings, host, port); /* keep both sides of the connection in pdata */ - pc->pdata = ps->pdata; - pdata->info->TargetHostname = _strdup(host); - pdata->info->Username = _strdup(client->settings->Username); - pdata->pc = pc; - pdata->ps = ps; - pdata->connectionClosed = CreateEvent(NULL, TRUE, FALSE, NULL); + ((pClientContext*)pc)->pdata = ps->pdata; + pdata->pc = (pClientContext*)pc; + + if (!pf_server_get_target_info(client->context, pc->settings, pdata->config)) + { + WLog_ERR(TAG, "pf_server_post_connect(): pf_server_get_target_info failed!"); + return FALSE; + } + + if (!proxy_data_set_connection_info(pdata, client->settings, pc->settings->ServerHostname)) + { + WLog_ERR(TAG, "proxy_data_set_connection_info failed!"); + return FALSE; + } + pf_server_rdpgfx_init(ps); /* Start a proxy's client in it's own thread */ - if (!(ps->thread = CreateThread(NULL, 0, pf_client_start, (rdpContext*) pc, 0, - NULL))) + if (!(ps->thread = CreateThread(NULL, 0, pf_client_start, pc, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); return FALSE; @@ -203,26 +215,25 @@ static DWORD WINAPI pf_server_handle_client(LPVOID arg) rdpContext* pc; proxyData* pdata; proxyConfig* config; - freerdp_peer* client = (freerdp_peer*) arg; + freerdp_peer* client = (freerdp_peer*)arg; if (!init_p_server_context(client)) + goto out_free_peer; + + ps = (pServerContext*)client->context; + if (!(ps->dynvcReady = CreateEvent(NULL, TRUE, FALSE, NULL))) { - freerdp_peer_free(client); - return 0; + WLog_ERR(TAG, "pf_server_post_connect(): CreateEvent failed!"); + goto out_free_peer; } - ps = (pServerContext*) client->context; - ps->dynvcReady = CreateEvent(NULL, TRUE, FALSE, NULL); - pdata = pf_context_proxy_data_new(); - - if (pdata == NULL) + if (!(pdata = ps->pdata = proxy_data_new())) { - WLog_ERR(TAG, "pf_context_proxy_data_new failed!"); - return 0; + WLog_ERR(TAG, "pf_server_post_connect(): proxy_data_new failed!"); + goto out_free_peer; } - pdata->info->ClientHostname = _strdup(client->hostname); - ps->pdata = pdata; + pdata->ps = ps; /* keep configuration in proxyData */ pdata->config = client->ContextExtra; config = pdata->config; @@ -232,12 +243,11 @@ static DWORD WINAPI pf_server_handle_client(LPVOID arg) client->settings->PrivateKeyFile = _strdup("server.key"); client->settings->RdpKeyFile = _strdup("server.key"); - if (!client->settings->CertificateFile || !client->settings->PrivateKeyFile - || !client->settings->RdpKeyFile) + if (!client->settings->CertificateFile || !client->settings->PrivateKeyFile || + !client->settings->RdpKeyFile) { WLog_ERR(TAG, "Memory allocation failed (strdup)"); - freerdp_peer_free(client); - return 0; + goto out_free_peer; } client->settings->RdpSecurity = config->RdpSecurity; @@ -253,8 +263,7 @@ static DWORD WINAPI pf_server_handle_client(LPVOID arg) pf_server_register_update_callbacks(client->update); client->settings->MultifragMaxRequestSize = 0xFFFFFF; /* FIXME */ client->Initialize(client); - WLog_INFO(TAG, "Client connected: %s", - client->local ? "(local)" : client->hostname); + WLog_INFO(TAG, "Client connected: %s", client->local ? "(local)" : client->hostname); /* Main client event handling loop */ ChannelEvent = WTSVirtualChannelManagerGetEventHandle(ps->vcm); @@ -262,8 +271,7 @@ static DWORD WINAPI pf_server_handle_client(LPVOID arg) { eventCount = 0; { - tmp = client->GetEventHandles(client, &eventHandles[eventCount], - 32 - eventCount); + tmp = client->GetEventHandles(client, &eventHandles[eventCount], 32 - eventCount); if (tmp == 0) { @@ -301,28 +309,28 @@ static DWORD WINAPI pf_server_handle_client(LPVOID arg) switch (WTSVirtualChannelManagerGetDrdynvcState(ps->vcm)) { - /* Dynamic channel status may have been changed after processing */ - case DRDYNVC_STATE_NONE: + /* Dynamic channel status may have been changed after processing */ + case DRDYNVC_STATE_NONE: - /* Initialize drdynvc channel */ - if (!WTSVirtualChannelManagerCheckFileDescriptor(ps->vcm)) - { - WLog_ERR(TAG, "Failed to initialize drdynvc channel"); - goto fail; - } + /* Initialize drdynvc channel */ + if (!WTSVirtualChannelManagerCheckFileDescriptor(ps->vcm)) + { + WLog_ERR(TAG, "Failed to initialize drdynvc channel"); + goto fail; + } - break; + break; - case DRDYNVC_STATE_READY: - if (WaitForSingleObject(ps->dynvcReady, 0) == WAIT_TIMEOUT) - { - SetEvent(ps->dynvcReady); - } + case DRDYNVC_STATE_READY: + if (WaitForSingleObject(ps->dynvcReady, 0) == WAIT_TIMEOUT) + { + SetEvent(ps->dynvcReady); + } - break; + break; - default: - break; + default: + break; } } @@ -333,24 +341,23 @@ fail: pf_server_handle_client_disconnection(client); } - pc = (rdpContext*) pdata->pc; + pc = (rdpContext*)pdata->pc; freerdp_client_stop(pc); - pf_context_proxy_data_free(pdata); + proxy_data_free(pdata); freerdp_client_context_free(pc); client->Disconnect(client); +out_free_peer: freerdp_peer_context_free(client); freerdp_peer_free(client); return 0; } -static BOOL pf_server_client_connected(freerdp_listener* listener, - freerdp_peer* client) +static BOOL pf_server_client_connected(freerdp_listener* listener, freerdp_peer* client) { HANDLE hThread; client->ContextExtra = listener->info; - if (!(hThread = CreateThread(NULL, 0, pf_server_handle_client, - (void*) client, 0, NULL))) + if (!(hThread = CreateThread(NULL, 0, pf_server_handle_client, (void*)client, 0, NULL))) return FALSE; CloseHandle(hThread); @@ -414,7 +421,7 @@ int pf_server_start(proxyConfig* config) } /* Determine filepath for local socket */ - sprintf_s(localSockName, sizeof(localSockName), "proxy.%"PRIu16"", config->Port); + sprintf_s(localSockName, sizeof(localSockName), "proxy.%" PRIu16 "", config->Port); localSockPath = GetKnownSubPath(KNOWN_PATH_TEMP, localSockName); if (!localSockPath) From 72952c679fac3a4ddea5b1236824e19e7c8ea39f Mon Sep 17 00:00:00 2001 From: kubistika Date: Mon, 27 May 2019 12:06:59 +0300 Subject: [PATCH 14/14] fix vs2010 errors --- server/proxy/filters/filter_demo.c | 2 +- server/proxy/pf_config.c | 18 +++++++++++++----- server/proxy/pf_filters.c | 15 +++++++++------ server/proxy/pf_filters.h | 15 +++++++-------- server/proxy/pf_input.c | 27 +++++++++++++++------------ 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/server/proxy/filters/filter_demo.c b/server/proxy/filters/filter_demo.c index 2653fec8d..55255f21f 100644 --- a/server/proxy/filters/filter_demo.c +++ b/server/proxy/filters/filter_demo.c @@ -29,7 +29,7 @@ static PF_FILTER_RESULT demo_filter_keyboard_event(connectionInfo* info, void* p static PF_FILTER_RESULT demo_filter_mouse_event(connectionInfo* info, void* param) { - proxyMouseEventInfo* event_data = (proxyMouseEventInfo*) param; + proxyMouseEventInfo* event_data = (proxyMouseEventInfo*) param; if (event_data->x % 100 == 0) { diff --git a/server/proxy/pf_config.c b/server/proxy/pf_config.c index 88841e60b..4802631b3 100644 --- a/server/proxy/pf_config.c +++ b/server/proxy/pf_config.c @@ -35,6 +35,9 @@ wArrayList* parse_string_array_from_str(const char* str) { wArrayList* list = ArrayList_New(FALSE); + char* s; + char* temp; + char* token; if (list == NULL) { @@ -42,9 +45,13 @@ wArrayList* parse_string_array_from_str(const char* str) return NULL; } - char* s = _strdup(str); - char* temp = s; - char* token; + + temp = s = _strdup(str); + if (!s) + { + WLog_ERR(TAG, "parse_string_array_from_str(): strdup failed!"); + return NULL; + } if (s == NULL) { @@ -115,6 +122,7 @@ DWORD pf_server_load_config(const char* path, proxyConfig* config) char** filters_names; int rc; int filters_count = 0; + UINT32 index; DWORD result = CONFIG_PARSE_ERROR; wIniFile* ini = IniFile_New(); @@ -182,9 +190,9 @@ DWORD pf_server_load_config(const char* path, proxyConfig* config) filters_names = IniFile_GetSectionKeyNames(ini, "Filters", &filters_count); - for (int i = 0; i < filters_count; i++) + for (index = 0; index < filters_count; index++) { - char* filter_name = filters_names[i]; + char* filter_name = filters_names[index]; const char* path = IniFile_GetKeyValueString(ini, "Filters", filter_name); if (!pf_filters_register_new(config->Filters, path, filter_name)) diff --git a/server/proxy/pf_filters.c b/server/proxy/pf_filters.c index 41bad3e8a..21c120f2c 100644 --- a/server/proxy/pf_filters.c +++ b/server/proxy/pf_filters.c @@ -122,7 +122,9 @@ PF_FILTER_RESULT pf_filters_run_by_type(filters_list* list, PF_FILTER_TYPE type, static void pf_filters_filter_free(proxyFilter* filter) { assert(filter != NULL); - FreeLibrary(filter->handle); + if (filter->handle) + FreeLibrary(filter->handle); + free(filter->name); free(filter->events); free(filter); @@ -130,11 +132,13 @@ static void pf_filters_filter_free(proxyFilter* filter) void pf_filters_unregister_all(filters_list* list) { + size_t count; + size_t index; + if (list == NULL) return; - const size_t count = (size_t) ArrayList_Count(list); - size_t index; + count = (size_t) ArrayList_Count(list); for (index = 0; index < count; index++) { @@ -159,7 +163,7 @@ BOOL pf_filters_register_new(filters_list* list, const char* module_path, const if (handle == NULL) { WLog_ERR(TAG, "pf_filters_register_new(): failed loading external module: %s", module_path); - goto error; + return FALSE; } if (!(fn = (filterInitFn) GetProcAddress(handle, FILTER_INIT_METHOD))) @@ -207,7 +211,6 @@ error: if (handle) FreeLibrary(handle); - free(events); - free(filter); + pf_filters_filter_free(filter); return FALSE; } diff --git a/server/proxy/pf_filters.h b/server/proxy/pf_filters.h index 8924bcade..d88cf72d3 100644 --- a/server/proxy/pf_filters.h +++ b/server/proxy/pf_filters.h @@ -57,19 +57,18 @@ PF_FILTER_RESULT pf_filters_run_by_type(filters_list* list, PF_FILTER_TYPE type, 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)) { \ +#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: \ - result = _cb(__VA_ARGS__); \ + _ret = _cb(__VA_ARGS__); \ break; \ case FILTER_IGNORE: \ - result = TRUE; \ + _ret = TRUE; \ break; \ case FILTER_DROP: \ default: \ - result = FALSE; \ - }; result; \ - }); \ - }) + _ret = FALSE; \ + } \ + } while(0) #endif /* FREERDP_SERVER_PROXY_FILTERS_H */ diff --git a/server/proxy/pf_input.c b/server/proxy/pf_input.c index 396129224..01b8862c3 100644 --- a/server/proxy/pf_input.c +++ b/server/proxy/pf_input.c @@ -32,21 +32,22 @@ static BOOL pf_server_synchronize_event(rdpInput* input, UINT32 flags) static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) { + BOOL result = FALSE; pServerContext* ps = (pServerContext*)input->context; pClientContext* pc = ps->pdata->pc; rdpContext* context = (rdpContext*) pc; proxyConfig* config = ps->pdata->config; + proxyKeyboardEventInfo event; if (!config->Keyboard) return TRUE; - proxyKeyboardEventInfo info = - { - .flags = flags, - .rdp_scan_code = code - }; - return RUN_FILTER(config->Filters, FILTER_TYPE_KEYBOARD, ps->pdata->info, &info, + event.flags = flags; + event.rdp_scan_code = code; + + RUN_FILTER(config->Filters, FILTER_TYPE_KEYBOARD, ps->pdata->info, &event, result, freerdp_input_send_keyboard_event, context->input, flags, code); + return result; } static BOOL pf_server_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) @@ -64,21 +65,23 @@ static BOOL pf_server_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT static BOOL pf_server_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { + BOOL result = FALSE; pServerContext* ps = (pServerContext*)input->context; pClientContext* pc = ps->pdata->pc; rdpContext* context = (rdpContext*) pc; proxyConfig* config = ps->pdata->config; + proxyMouseEventInfo event; if (!config->Mouse) return TRUE; - proxyMouseEventInfo info = - { - .flags = flags, - .x = x, .y = y - }; - return RUN_FILTER(config->Filters, FILTER_TYPE_MOUSE, ps->pdata->info, &info, + event.flags = flags; + event.x = x; + event.y = y; + + RUN_FILTER(config->Filters, FILTER_TYPE_MOUSE, ps->pdata->info, &event, result, freerdp_input_send_mouse_event, context->input, flags, x, y); + return result; } static BOOL pf_server_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,