23#include <winpr/assert.h>
25#include <winpr/file.h>
26#include <winpr/wlog.h>
27#include <winpr/path.h>
28#include <winpr/library.h>
30#include <freerdp/version.h>
31#include <freerdp/api.h>
32#include <freerdp/build-config.h>
34#include <freerdp/server/proxy/proxy_log.h>
35#include <freerdp/server/proxy/proxy_modules_api.h>
37#include <freerdp/server/proxy/proxy_context.h>
38#include "proxy_modules.h"
40#define TAG PROXY_TAG("modules")
42#define MODULE_ENTRY_POINT "proxy_module_entry_point"
46 proxyPluginsManager mgr;
52static const char* pf_modules_get_filter_type_string(PF_FILTER_TYPE result)
56 case FILTER_TYPE_KEYBOARD:
57 return "FILTER_TYPE_KEYBOARD";
58 case FILTER_TYPE_UNICODE:
59 return "FILTER_TYPE_UNICODE";
60 case FILTER_TYPE_MOUSE:
61 return "FILTER_TYPE_MOUSE";
62 case FILTER_TYPE_MOUSE_EX:
63 return "FILTER_TYPE_MOUSE_EX";
64 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA:
65 return "FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA";
66 case FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA:
67 return "FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA";
68 case FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE:
69 return "FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE";
70 case FILTER_TYPE_SERVER_FETCH_TARGET_ADDR:
71 return "FILTER_TYPE_SERVER_FETCH_TARGET_ADDR";
72 case FILTER_TYPE_SERVER_PEER_LOGON:
73 return "FILTER_TYPE_SERVER_PEER_LOGON";
74 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE:
75 return "FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE";
76 case FILTER_TYPE_STATIC_INTERCEPT_LIST:
77 return "FILTER_TYPE_STATIC_INTERCEPT_LIST";
78 case FILTER_TYPE_DYN_INTERCEPT_LIST:
79 return "FILTER_TYPE_DYN_INTERCEPT_LIST";
80 case FILTER_TYPE_INTERCEPT_CHANNEL:
81 return "FILTER_TYPE_INTERCEPT_CHANNEL";
85 return "FILTER_UNKNOWN";
90static const char* pf_modules_get_hook_type_string(PF_HOOK_TYPE result)
94 case HOOK_TYPE_CLIENT_INIT_CONNECT:
95 return "HOOK_TYPE_CLIENT_INIT_CONNECT";
96 case HOOK_TYPE_CLIENT_UNINIT_CONNECT:
97 return "HOOK_TYPE_CLIENT_UNINIT_CONNECT";
98 case HOOK_TYPE_CLIENT_PRE_CONNECT:
99 return "HOOK_TYPE_CLIENT_PRE_CONNECT";
100 case HOOK_TYPE_CLIENT_POST_CONNECT:
101 return "HOOK_TYPE_CLIENT_POST_CONNECT";
102 case HOOK_TYPE_CLIENT_POST_DISCONNECT:
103 return "HOOK_TYPE_CLIENT_POST_DISCONNECT";
104 case HOOK_TYPE_CLIENT_REDIRECT:
105 return "HOOK_TYPE_CLIENT_REDIRECT";
106 case HOOK_TYPE_CLIENT_VERIFY_X509:
107 return "HOOK_TYPE_CLIENT_VERIFY_X509";
108 case HOOK_TYPE_CLIENT_LOGIN_FAILURE:
109 return "HOOK_TYPE_CLIENT_LOGIN_FAILURE";
110 case HOOK_TYPE_CLIENT_END_PAINT:
111 return "HOOK_TYPE_CLIENT_END_PAINT";
112 case HOOK_TYPE_SERVER_POST_CONNECT:
113 return "HOOK_TYPE_SERVER_POST_CONNECT";
114 case HOOK_TYPE_SERVER_ACTIVATE:
115 return "HOOK_TYPE_SERVER_ACTIVATE";
116 case HOOK_TYPE_SERVER_CHANNELS_INIT:
117 return "HOOK_TYPE_SERVER_CHANNELS_INIT";
118 case HOOK_TYPE_SERVER_CHANNELS_FREE:
119 return "HOOK_TYPE_SERVER_CHANNELS_FREE";
120 case HOOK_TYPE_SERVER_SESSION_END:
121 return "HOOK_TYPE_SERVER_SESSION_END";
122 case HOOK_TYPE_CLIENT_LOAD_CHANNELS:
123 return "HOOK_TYPE_CLIENT_LOAD_CHANNELS";
124 case HOOK_TYPE_SERVER_SESSION_INITIALIZE:
125 return "HOOK_TYPE_SERVER_SESSION_INITIALIZE";
126 case HOOK_TYPE_SERVER_SESSION_STARTED:
127 return "HOOK_TYPE_SERVER_SESSION_STARTED";
131 return "HOOK_TYPE_UNKNOWN";
136static BOOL pf_modules_proxy_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
138 proxyPlugin* plugin = (proxyPlugin*)data;
143 PF_HOOK_TYPE type = va_arg(ap, PF_HOOK_TYPE);
144 proxyData* pdata = va_arg(ap, proxyData*);
145 void* custom = va_arg(ap,
void*);
147 WLog_VRB(TAG,
"running hook %s.%s", plugin->name, pf_modules_get_hook_type_string(type));
151 case HOOK_TYPE_CLIENT_INIT_CONNECT:
152 ok = IFCALLRESULT(TRUE, plugin->ClientInitConnect, plugin, pdata, custom);
154 case HOOK_TYPE_CLIENT_UNINIT_CONNECT:
155 ok = IFCALLRESULT(TRUE, plugin->ClientUninitConnect, plugin, pdata, custom);
157 case HOOK_TYPE_CLIENT_PRE_CONNECT:
158 ok = IFCALLRESULT(TRUE, plugin->ClientPreConnect, plugin, pdata, custom);
161 case HOOK_TYPE_CLIENT_POST_CONNECT:
162 ok = IFCALLRESULT(TRUE, plugin->ClientPostConnect, plugin, pdata, custom);
165 case HOOK_TYPE_CLIENT_REDIRECT:
166 ok = IFCALLRESULT(TRUE, plugin->ClientRedirect, plugin, pdata, custom);
169 case HOOK_TYPE_CLIENT_POST_DISCONNECT:
170 ok = IFCALLRESULT(TRUE, plugin->ClientPostDisconnect, plugin, pdata, custom);
177 case HOOK_TYPE_CLIENT_VERIFY_X509:
178 ok = IFCALLRESULT(FALSE, plugin->ClientX509Certificate, plugin, pdata, custom);
181 case HOOK_TYPE_CLIENT_LOGIN_FAILURE:
182 ok = IFCALLRESULT(TRUE, plugin->ClientLoginFailure, plugin, pdata, custom);
185 case HOOK_TYPE_CLIENT_END_PAINT:
186 ok = IFCALLRESULT(TRUE, plugin->ClientEndPaint, plugin, pdata, custom);
189 case HOOK_TYPE_CLIENT_LOAD_CHANNELS:
190 ok = IFCALLRESULT(TRUE, plugin->ClientLoadChannels, plugin, pdata, custom);
193 case HOOK_TYPE_SERVER_POST_CONNECT:
194 ok = IFCALLRESULT(TRUE, plugin->ServerPostConnect, plugin, pdata, custom);
197 case HOOK_TYPE_SERVER_ACTIVATE:
198 ok = IFCALLRESULT(TRUE, plugin->ServerPeerActivate, plugin, pdata, custom);
201 case HOOK_TYPE_SERVER_CHANNELS_INIT:
202 ok = IFCALLRESULT(TRUE, plugin->ServerChannelsInit, plugin, pdata, custom);
205 case HOOK_TYPE_SERVER_CHANNELS_FREE:
206 ok = IFCALLRESULT(TRUE, plugin->ServerChannelsFree, plugin, pdata, custom);
209 case HOOK_TYPE_SERVER_SESSION_END:
210 ok = IFCALLRESULT(TRUE, plugin->ServerSessionEnd, plugin, pdata, custom);
213 case HOOK_TYPE_SERVER_SESSION_INITIALIZE:
214 ok = IFCALLRESULT(TRUE, plugin->ServerSessionInitialize, plugin, pdata, custom);
217 case HOOK_TYPE_SERVER_SESSION_STARTED:
218 ok = IFCALLRESULT(TRUE, plugin->ServerSessionStarted, plugin, pdata, custom);
223 WLog_ERR(TAG,
"invalid hook called");
228 WLog_INFO(TAG,
"plugin %s, hook %s failed!", plugin->name,
229 pf_modules_get_hook_type_string(type));
241BOOL pf_modules_run_hook(proxyModule* module, PF_HOOK_TYPE type, proxyData* pdata,
void* custom)
243 WINPR_ASSERT(module);
244 WINPR_ASSERT(module->plugins);
245 return ArrayList_ForEach(module->plugins, pf_modules_proxy_ArrayList_ForEachFkt, type, pdata,
250static BOOL pf_modules_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
252 proxyPlugin* plugin = (proxyPlugin*)data;
257 PF_FILTER_TYPE type = va_arg(ap, PF_FILTER_TYPE);
258 proxyData* pdata = va_arg(ap, proxyData*);
259 void* param = va_arg(ap,
void*);
261 WLog_VRB(TAG,
"running filter: %s", plugin->name);
265 case FILTER_TYPE_KEYBOARD:
266 result = IFCALLRESULT(TRUE, plugin->KeyboardEvent, plugin, pdata, param);
269 case FILTER_TYPE_UNICODE:
270 result = IFCALLRESULT(TRUE, plugin->UnicodeEvent, plugin, pdata, param);
273 case FILTER_TYPE_MOUSE:
274 result = IFCALLRESULT(TRUE, plugin->MouseEvent, plugin, pdata, param);
277 case FILTER_TYPE_MOUSE_EX:
278 result = IFCALLRESULT(TRUE, plugin->MouseExEvent, plugin, pdata, param);
281 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA:
282 result = IFCALLRESULT(TRUE, plugin->ClientChannelData, plugin, pdata, param);
285 case FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA:
286 result = IFCALLRESULT(TRUE, plugin->ServerChannelData, plugin, pdata, param);
289 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE:
290 result = IFCALLRESULT(TRUE, plugin->ChannelCreate, plugin, pdata, param);
293 case FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE:
294 result = IFCALLRESULT(TRUE, plugin->DynamicChannelCreate, plugin, pdata, param);
297 case FILTER_TYPE_SERVER_FETCH_TARGET_ADDR:
298 result = IFCALLRESULT(TRUE, plugin->ServerFetchTargetAddr, plugin, pdata, param);
301 case FILTER_TYPE_SERVER_PEER_LOGON:
302 result = IFCALLRESULT(TRUE, plugin->ServerPeerLogon, plugin, pdata, param);
305 case FILTER_TYPE_INTERCEPT_CHANNEL:
306 result = IFCALLRESULT(TRUE, plugin->DynChannelIntercept, plugin, pdata, param);
309 case FILTER_TYPE_DYN_INTERCEPT_LIST:
310 result = IFCALLRESULT(TRUE, plugin->DynChannelToIntercept, plugin, pdata, param);
313 case FILTER_TYPE_STATIC_INTERCEPT_LIST:
314 result = IFCALLRESULT(TRUE, plugin->StaticChannelToIntercept, plugin, pdata, param);
319 WLog_ERR(TAG,
"invalid filter called");
325 WLog_DBG(TAG,
"plugin %s, filter type [%s] returned FALSE", plugin->name,
326 pf_modules_get_filter_type_string(type));
337BOOL pf_modules_run_filter(proxyModule* module, PF_FILTER_TYPE type, proxyData* pdata,
void* param)
339 WINPR_ASSERT(module);
340 WINPR_ASSERT(module->plugins);
342 return ArrayList_ForEach(module->plugins, pf_modules_ArrayList_ForEachFkt, type, pdata, param);
352static BOOL pf_modules_set_plugin_data(WINPR_ATTR_UNUSED proxyPluginsManager* mgr,
353 const char* plugin_name, proxyData* pdata,
void* data)
361 WINPR_ASSERT(plugin_name);
363 ccharconv.ccp = plugin_name;
367 if (!HashTable_Insert(pdata->modules_info, ccharconv.cp, data))
369 WLog_ERR(TAG,
"HashTable_Insert failed!");
384static void* pf_modules_get_plugin_data(WINPR_ATTR_UNUSED proxyPluginsManager* mgr,
385 const char* plugin_name, proxyData* pdata)
392 WINPR_ASSERT(plugin_name);
394 ccharconv.ccp = plugin_name;
396 return HashTable_GetItemValue(pdata->modules_info, ccharconv.cp);
399static void pf_modules_abort_connect(WINPR_ATTR_UNUSED proxyPluginsManager* mgr, proxyData* pdata)
402 WLog_DBG(TAG,
"is called!");
403 proxy_data_abort_connect(pdata);
407static BOOL pf_modules_register_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
409 proxyPlugin* plugin = (proxyPlugin*)data;
410 proxyPlugin* plugin_to_register = va_arg(ap, proxyPlugin*);
414 if (strcmp(plugin->name, plugin_to_register->name) == 0)
416 WLog_ERR(TAG,
"can not register plugin '%s', it is already registered!", plugin->name);
423static BOOL pf_modules_register_plugin(proxyPluginsManager* mgr,
424 const proxyPlugin* plugin_to_register)
426 proxyPlugin internal = WINPR_C_ARRAY_INIT;
427 proxyModule*
module = (proxyModule*)mgr;
428 WINPR_ASSERT(module);
430 if (!plugin_to_register)
433 internal = *plugin_to_register;
437 if (!ArrayList_ForEach(module->plugins, pf_modules_register_ArrayList_ForEachFkt, &internal))
440 if (!ArrayList_Append(module->plugins, &internal))
442 WLog_ERR(TAG,
"failed adding plugin to list: %s", plugin_to_register->name);
445 WLog_INFO(TAG,
"Successfully registered proxy plugin '%s'", plugin_to_register->name);
451static BOOL pf_modules_load_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
453 proxyPlugin* plugin = (proxyPlugin*)data;
454 const char* plugin_name = va_arg(ap,
const char*);
455 BOOL* res = va_arg(ap, BOOL*);
461 if (strcmp(plugin->name, plugin_name) == 0)
466BOOL pf_modules_is_plugin_loaded(proxyModule* module,
const char* plugin_name)
469 WINPR_ASSERT(module);
470 if (ArrayList_Count(module->plugins) < 1)
472 if (!ArrayList_ForEach(module->plugins, pf_modules_load_ArrayList_ForEachFkt, plugin_name, &rc))
478static BOOL pf_modules_print_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
480 proxyPlugin* plugin = (proxyPlugin*)data;
485 WLog_INFO(TAG,
"\tName: %s", plugin->name);
486 WLog_INFO(TAG,
"\tDescription: %s", plugin->description);
490BOOL pf_modules_list_loaded_plugins(proxyModule* module)
494 WINPR_ASSERT(module);
495 WINPR_ASSERT(module->plugins);
497 count = ArrayList_Count(module->plugins);
500 WLog_INFO(TAG,
"Loaded plugins:");
502 return ArrayList_ForEach(module->plugins, pf_modules_print_ArrayList_ForEachFkt);
506static BOOL pf_modules_load_static_module(
const char* module_name, proxyModule* module,
509 WINPR_ASSERT(module);
511 HANDLE handle = GetModuleHandleA(
nullptr);
513 if (handle ==
nullptr)
515 WLog_DBG(TAG,
"failed loading static library: %s", module_name);
519 char name[256] = WINPR_C_ARRAY_INIT;
520 (void)_snprintf(name,
sizeof(name),
"%s_%s", module_name, MODULE_ENTRY_POINT);
521 for (
size_t x = 0; x < strnlen(name,
sizeof(name)); x++)
527 proxyModuleEntryPoint pEntryPoint = GetProcAddressAs(handle, name, proxyModuleEntryPoint);
530 WLog_DBG(TAG,
"GetProcAddress failed for static %s (module %s)", name, module_name);
533 if (!ArrayList_Append(module->handles, handle))
535 WLog_ERR(TAG,
"ArrayList_Append failed!");
538 return pf_modules_add(module, pEntryPoint, userdata);
546static BOOL pf_modules_load_dynamic_module(
const char* module_path, proxyModule* module,
549 if (!winpr_PathFileExists(module_path))
551 WLog_DBG(TAG,
"failed loading external library: file '%s' does not exist", module_path);
555 HANDLE handle = LoadLibraryX(module_path);
557 if (handle ==
nullptr)
559 WLog_DBG(TAG,
"failed loading external library: %s", module_path);
563 proxyModuleEntryPoint pEntryPoint =
564 GetProcAddressAs(handle, MODULE_ENTRY_POINT, proxyModuleEntryPoint);
567 WLog_DBG(TAG,
"GetProcAddress failed while loading %s", module_path);
570 if (!ArrayList_Append(module->handles, handle))
572 WLog_ERR(TAG,
"ArrayList_Append failed!");
575 return pf_modules_add(module, pEntryPoint, userdata);
583static BOOL pf_modules_try_load_dynamic_module(
const char* module_path, proxyModule* module,
584 void* userdata,
size_t count,
const char* names[])
586 for (
size_t x = 0; x < count; x++)
588 const char* name = names[x];
590 char* fullpath = GetCombinedPath(module_path, name);
594 const BOOL rc = pf_modules_load_dynamic_module(fullpath, module, userdata);
603static BOOL pf_modules_load_module(
const char* module_path,
const char* module_name,
604 proxyModule* module,
void* userdata)
606 WINPR_ASSERT(module);
608 if (pf_modules_load_static_module(module_name, module, userdata))
611 char names[5][MAX_PATH] = WINPR_C_ARRAY_INIT;
612 (void)_snprintf(names[0],
sizeof(names[0]),
"proxy-%s-plugin%s", module_name,
613 FREERDP_SHARED_LIBRARY_SUFFIX);
614 (void)_snprintf(names[1],
sizeof(names[1]),
"%sproxy-%s-plugin%s",
615 FREERDP_SHARED_LIBRARY_PREFIX, module_name, FREERDP_SHARED_LIBRARY_SUFFIX);
616 (void)_snprintf(names[2],
sizeof(names[2]),
"%sproxy-%s-plugin%s.%d",
617 FREERDP_SHARED_LIBRARY_PREFIX, module_name, FREERDP_SHARED_LIBRARY_SUFFIX,
618 FREERDP_VERSION_MAJOR);
619 (void)_snprintf(names[3],
sizeof(names[3]),
"%sproxy-%s-plugin%d%s",
620 FREERDP_SHARED_LIBRARY_PREFIX, module_name, FREERDP_VERSION_MAJOR,
621 FREERDP_SHARED_LIBRARY_SUFFIX);
622 (void)_snprintf(names[4],
sizeof(names[4]),
"%sproxy-%s-plugin%d%s.%d",
623 FREERDP_SHARED_LIBRARY_PREFIX, module_name, FREERDP_VERSION_MAJOR,
624 FREERDP_SHARED_LIBRARY_SUFFIX, FREERDP_VERSION_MAJOR);
626 const char* cnames[5] = { names[0], names[1], names[2], names[3], names[4] };
627 return pf_modules_try_load_dynamic_module(module_path, module, userdata, ARRAYSIZE(cnames),
631static void free_handle(
void* obj)
633 HANDLE handle = (HANDLE)obj;
638static void free_plugin(
void* obj)
640 proxyPlugin* plugin = (proxyPlugin*)obj;
641 WINPR_ASSERT(plugin);
643 if (!IFCALLRESULT(TRUE, plugin->PluginUnload, plugin))
644 WLog_WARN(TAG,
"PluginUnload failed for plugin '%s'", plugin->name);
649WINPR_ATTR_MALLOC(free_plugin, 1)
651static
void* new_plugin(const
void* obj)
653 const proxyPlugin* src = obj;
654 proxyPlugin* proxy = calloc(1,
sizeof(proxyPlugin));
661proxyModule* pf_modules_new(
const char* root_dir,
const char** modules,
size_t count)
664 char* path =
nullptr;
665 proxyModule*
module = calloc(1, sizeof(proxyModule));
669 module->mgr.RegisterPlugin = pf_modules_register_plugin;
670 module->mgr.SetPluginData = pf_modules_set_plugin_data;
671 module->mgr.GetPluginData = pf_modules_get_plugin_data;
672 module->mgr.AbortConnect = pf_modules_abort_connect;
673 module->plugins = ArrayList_New(FALSE);
675 if (module->plugins ==
nullptr)
677 WLog_ERR(TAG,
"ArrayList_New failed!");
680 obj = ArrayList_Object(module->plugins);
686 module->handles = ArrayList_New(FALSE);
687 if (module->handles ==
nullptr)
690 WLog_ERR(TAG,
"ArrayList_New failed!");
693 ArrayList_Object(module->handles)->
fnObjectFree = free_handle;
697 WINPR_ASSERT(root_dir);
698 if (!winpr_PathFileExists(root_dir))
699 path = GetCombinedPath(FREERDP_INSTALL_PREFIX, root_dir);
701 path = _strdup(root_dir);
703 if (!winpr_PathFileExists(path))
705 if (!winpr_PathMakePath(path,
nullptr))
707 WLog_ERR(TAG,
"error occurred while creating modules directory: %s", root_dir);
711 if (winpr_PathFileExists(path))
712 WLog_DBG(TAG,
"modules root directory: %s", path);
714 for (
size_t i = 0; i < count; i++)
716 const char* module_name = modules[i];
717 if (!pf_modules_load_module(path, module_name, module,
nullptr))
718 WLog_WARN(TAG,
"Failed to load proxy module '%s'", module_name);
720 WLog_INFO(TAG,
"Successfully loaded proxy module '%s'", module_name);
729 pf_modules_free(module);
733void pf_modules_free(proxyModule* module)
738 ArrayList_Free(module->plugins);
739 ArrayList_Free(module->handles);
743BOOL pf_modules_add(proxyModule* module, proxyModuleEntryPoint ep,
void* userdata)
745 WINPR_ASSERT(module);
748 return ep(&module->mgr, userdata);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree
WINPR_ATTR_NODISCARD OBJECT_NEW_FN fnObjectNew