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>
29 #include <freerdp/api.h>
30 #include <freerdp/build-config.h>
32 #include <freerdp/server/proxy/proxy_log.h>
33 #include <freerdp/server/proxy/proxy_modules_api.h>
35 #include <freerdp/server/proxy/proxy_context.h>
36 #include "proxy_modules.h"
38 #define TAG PROXY_TAG("modules")
40 #define MODULE_ENTRY_POINT "proxy_module_entry_point"
44 proxyPluginsManager mgr;
49 static const char* pf_modules_get_filter_type_string(PF_FILTER_TYPE result)
53 case FILTER_TYPE_KEYBOARD:
54 return "FILTER_TYPE_KEYBOARD";
55 case FILTER_TYPE_UNICODE:
56 return "FILTER_TYPE_UNICODE";
57 case FILTER_TYPE_MOUSE:
58 return "FILTER_TYPE_MOUSE";
59 case FILTER_TYPE_MOUSE_EX:
60 return "FILTER_TYPE_MOUSE_EX";
61 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA:
62 return "FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA";
63 case FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA:
64 return "FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA";
65 case FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE:
66 return "FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE";
67 case FILTER_TYPE_SERVER_FETCH_TARGET_ADDR:
68 return "FILTER_TYPE_SERVER_FETCH_TARGET_ADDR";
69 case FILTER_TYPE_SERVER_PEER_LOGON:
70 return "FILTER_TYPE_SERVER_PEER_LOGON";
71 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE:
72 return "FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE";
76 return "FILTER_UNKNOWN";
80 static const char* pf_modules_get_hook_type_string(PF_HOOK_TYPE result)
84 case HOOK_TYPE_CLIENT_INIT_CONNECT:
85 return "HOOK_TYPE_CLIENT_INIT_CONNECT";
86 case HOOK_TYPE_CLIENT_UNINIT_CONNECT:
87 return "HOOK_TYPE_CLIENT_UNINIT_CONNECT";
88 case HOOK_TYPE_CLIENT_PRE_CONNECT:
89 return "HOOK_TYPE_CLIENT_PRE_CONNECT";
90 case HOOK_TYPE_CLIENT_POST_CONNECT:
91 return "HOOK_TYPE_CLIENT_POST_CONNECT";
92 case HOOK_TYPE_CLIENT_POST_DISCONNECT:
93 return "HOOK_TYPE_CLIENT_POST_DISCONNECT";
94 case HOOK_TYPE_CLIENT_REDIRECT:
95 return "HOOK_TYPE_CLIENT_REDIRECT";
96 case HOOK_TYPE_CLIENT_VERIFY_X509:
97 return "HOOK_TYPE_CLIENT_VERIFY_X509";
98 case HOOK_TYPE_CLIENT_LOGIN_FAILURE:
99 return "HOOK_TYPE_CLIENT_LOGIN_FAILURE";
100 case HOOK_TYPE_CLIENT_END_PAINT:
101 return "HOOK_TYPE_CLIENT_END_PAINT";
102 case HOOK_TYPE_SERVER_POST_CONNECT:
103 return "HOOK_TYPE_SERVER_POST_CONNECT";
104 case HOOK_TYPE_SERVER_ACTIVATE:
105 return "HOOK_TYPE_SERVER_ACTIVATE";
106 case HOOK_TYPE_SERVER_CHANNELS_INIT:
107 return "HOOK_TYPE_SERVER_CHANNELS_INIT";
108 case HOOK_TYPE_SERVER_CHANNELS_FREE:
109 return "HOOK_TYPE_SERVER_CHANNELS_FREE";
110 case HOOK_TYPE_SERVER_SESSION_END:
111 return "HOOK_TYPE_SERVER_SESSION_END";
112 case HOOK_TYPE_CLIENT_LOAD_CHANNELS:
113 return "HOOK_TYPE_CLIENT_LOAD_CHANNELS";
114 case HOOK_TYPE_SERVER_SESSION_INITIALIZE:
115 return "HOOK_TYPE_SERVER_SESSION_INITIALIZE";
116 case HOOK_TYPE_SERVER_SESSION_STARTED:
117 return "HOOK_TYPE_SERVER_SESSION_STARTED";
121 return "HOOK_TYPE_UNKNOWN";
125 static BOOL pf_modules_proxy_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
127 proxyPlugin* plugin = (proxyPlugin*)data;
132 PF_HOOK_TYPE type = va_arg(ap, PF_HOOK_TYPE);
133 proxyData* pdata = va_arg(ap, proxyData*);
134 void* custom = va_arg(ap,
void*);
136 WLog_VRB(TAG,
"running hook %s.%s", plugin->name, pf_modules_get_hook_type_string(type));
140 case HOOK_TYPE_CLIENT_INIT_CONNECT:
141 ok = IFCALLRESULT(TRUE, plugin->ClientInitConnect, plugin, pdata, custom);
143 case HOOK_TYPE_CLIENT_UNINIT_CONNECT:
144 ok = IFCALLRESULT(TRUE, plugin->ClientUninitConnect, plugin, pdata, custom);
146 case HOOK_TYPE_CLIENT_PRE_CONNECT:
147 ok = IFCALLRESULT(TRUE, plugin->ClientPreConnect, plugin, pdata, custom);
150 case HOOK_TYPE_CLIENT_POST_CONNECT:
151 ok = IFCALLRESULT(TRUE, plugin->ClientPostConnect, plugin, pdata, custom);
154 case HOOK_TYPE_CLIENT_REDIRECT:
155 ok = IFCALLRESULT(TRUE, plugin->ClientRedirect, plugin, pdata, custom);
158 case HOOK_TYPE_CLIENT_POST_DISCONNECT:
159 ok = IFCALLRESULT(TRUE, plugin->ClientPostDisconnect, plugin, pdata, custom);
162 case HOOK_TYPE_CLIENT_VERIFY_X509:
163 ok = IFCALLRESULT(TRUE, plugin->ClientX509Certificate, plugin, pdata, custom);
166 case HOOK_TYPE_CLIENT_LOGIN_FAILURE:
167 ok = IFCALLRESULT(TRUE, plugin->ClientLoginFailure, plugin, pdata, custom);
170 case HOOK_TYPE_CLIENT_END_PAINT:
171 ok = IFCALLRESULT(TRUE, plugin->ClientEndPaint, plugin, pdata, custom);
174 case HOOK_TYPE_CLIENT_LOAD_CHANNELS:
175 ok = IFCALLRESULT(TRUE, plugin->ClientLoadChannels, plugin, pdata, custom);
178 case HOOK_TYPE_SERVER_POST_CONNECT:
179 ok = IFCALLRESULT(TRUE, plugin->ServerPostConnect, plugin, pdata, custom);
182 case HOOK_TYPE_SERVER_ACTIVATE:
183 ok = IFCALLRESULT(TRUE, plugin->ServerPeerActivate, plugin, pdata, custom);
186 case HOOK_TYPE_SERVER_CHANNELS_INIT:
187 ok = IFCALLRESULT(TRUE, plugin->ServerChannelsInit, plugin, pdata, custom);
190 case HOOK_TYPE_SERVER_CHANNELS_FREE:
191 ok = IFCALLRESULT(TRUE, plugin->ServerChannelsFree, plugin, pdata, custom);
194 case HOOK_TYPE_SERVER_SESSION_END:
195 ok = IFCALLRESULT(TRUE, plugin->ServerSessionEnd, plugin, pdata, custom);
198 case HOOK_TYPE_SERVER_SESSION_INITIALIZE:
199 ok = IFCALLRESULT(TRUE, plugin->ServerSessionInitialize, plugin, pdata, custom);
202 case HOOK_TYPE_SERVER_SESSION_STARTED:
203 ok = IFCALLRESULT(TRUE, plugin->ServerSessionStarted, plugin, pdata, custom);
208 WLog_ERR(TAG,
"invalid hook called");
213 WLog_INFO(TAG,
"plugin %s, hook %s failed!", plugin->name,
214 pf_modules_get_hook_type_string(type));
226 BOOL pf_modules_run_hook(proxyModule* module, PF_HOOK_TYPE type, proxyData* pdata,
void* custom)
228 WINPR_ASSERT(module);
229 WINPR_ASSERT(module->plugins);
230 return ArrayList_ForEach(module->plugins, pf_modules_proxy_ArrayList_ForEachFkt, type, pdata,
234 static BOOL pf_modules_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
236 proxyPlugin* plugin = (proxyPlugin*)data;
241 PF_FILTER_TYPE type = va_arg(ap, PF_FILTER_TYPE);
242 proxyData* pdata = va_arg(ap, proxyData*);
243 void* param = va_arg(ap,
void*);
245 WLog_VRB(TAG,
"running filter: %s", plugin->name);
249 case FILTER_TYPE_KEYBOARD:
250 result = IFCALLRESULT(TRUE, plugin->KeyboardEvent, plugin, pdata, param);
253 case FILTER_TYPE_UNICODE:
254 result = IFCALLRESULT(TRUE, plugin->UnicodeEvent, plugin, pdata, param);
257 case FILTER_TYPE_MOUSE:
258 result = IFCALLRESULT(TRUE, plugin->MouseEvent, plugin, pdata, param);
261 case FILTER_TYPE_MOUSE_EX:
262 result = IFCALLRESULT(TRUE, plugin->MouseExEvent, plugin, pdata, param);
265 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA:
266 result = IFCALLRESULT(TRUE, plugin->ClientChannelData, plugin, pdata, param);
269 case FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA:
270 result = IFCALLRESULT(TRUE, plugin->ServerChannelData, plugin, pdata, param);
273 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE:
274 result = IFCALLRESULT(TRUE, plugin->ChannelCreate, plugin, pdata, param);
277 case FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE:
278 result = IFCALLRESULT(TRUE, plugin->DynamicChannelCreate, plugin, pdata, param);
281 case FILTER_TYPE_SERVER_FETCH_TARGET_ADDR:
282 result = IFCALLRESULT(TRUE, plugin->ServerFetchTargetAddr, plugin, pdata, param);
285 case FILTER_TYPE_SERVER_PEER_LOGON:
286 result = IFCALLRESULT(TRUE, plugin->ServerPeerLogon, plugin, pdata, param);
289 case FILTER_TYPE_INTERCEPT_CHANNEL:
290 result = IFCALLRESULT(TRUE, plugin->DynChannelIntercept, plugin, pdata, param);
293 case FILTER_TYPE_DYN_INTERCEPT_LIST:
294 result = IFCALLRESULT(TRUE, plugin->DynChannelToIntercept, plugin, pdata, param);
297 case FILTER_TYPE_STATIC_INTERCEPT_LIST:
298 result = IFCALLRESULT(TRUE, plugin->StaticChannelToIntercept, plugin, pdata, param);
303 WLog_ERR(TAG,
"invalid filter called");
309 WLog_DBG(TAG,
"plugin %s, filter type [%s] returned FALSE", plugin->name,
310 pf_modules_get_filter_type_string(type));
321 BOOL pf_modules_run_filter(proxyModule* module, PF_FILTER_TYPE type, proxyData* pdata,
void* param)
323 WINPR_ASSERT(module);
324 WINPR_ASSERT(module->plugins);
326 return ArrayList_ForEach(module->plugins, pf_modules_ArrayList_ForEachFkt, type, pdata, param);
335 static BOOL pf_modules_set_plugin_data(proxyPluginsManager* mgr,
const char* plugin_name,
336 proxyData* pdata,
void* data)
344 WINPR_ASSERT(plugin_name);
346 ccharconv.ccp = plugin_name;
350 if (!HashTable_Insert(pdata->modules_info, ccharconv.cp, data))
352 WLog_ERR(TAG,
"[%s]: HashTable_Insert failed!");
366 static void* pf_modules_get_plugin_data(proxyPluginsManager* mgr,
const char* plugin_name,
374 WINPR_ASSERT(plugin_name);
376 ccharconv.ccp = plugin_name;
378 return HashTable_GetItemValue(pdata->modules_info, ccharconv.cp);
381 static void pf_modules_abort_connect(proxyPluginsManager* mgr, proxyData* pdata)
384 WLog_DBG(TAG,
"is called!");
385 proxy_data_abort_connect(pdata);
388 static BOOL pf_modules_register_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
390 proxyPlugin* plugin = (proxyPlugin*)data;
391 proxyPlugin* plugin_to_register = va_arg(ap, proxyPlugin*);
395 if (strcmp(plugin->name, plugin_to_register->name) == 0)
397 WLog_ERR(TAG,
"can not register plugin '%s', it is already registered!", plugin->name);
403 static BOOL pf_modules_register_plugin(proxyPluginsManager* mgr,
404 const proxyPlugin* plugin_to_register)
406 proxyPlugin
internal = { 0 };
407 proxyModule* module = (proxyModule*)mgr;
408 WINPR_ASSERT(module);
410 if (!plugin_to_register)
413 internal = *plugin_to_register;
417 if (!ArrayList_ForEach(module->plugins, pf_modules_register_ArrayList_ForEachFkt, &
internal))
420 if (!ArrayList_Append(module->plugins, &
internal))
422 WLog_ERR(TAG,
"failed adding plugin to list: %s", plugin_to_register->name);
429 static BOOL pf_modules_load_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
431 proxyPlugin* plugin = (proxyPlugin*)data;
432 const char* plugin_name = va_arg(ap,
const char*);
433 BOOL* res = va_arg(ap, BOOL*);
439 if (strcmp(plugin->name, plugin_name) == 0)
444 BOOL pf_modules_is_plugin_loaded(proxyModule* module,
const char* plugin_name)
447 WINPR_ASSERT(module);
448 if (ArrayList_Count(module->plugins) < 1)
450 if (!ArrayList_ForEach(module->plugins, pf_modules_load_ArrayList_ForEachFkt, plugin_name, &rc))
455 static BOOL pf_modules_print_ArrayList_ForEachFkt(
void* data,
size_t index, va_list ap)
457 proxyPlugin* plugin = (proxyPlugin*)data;
462 WLog_INFO(TAG,
"\tName: %s", plugin->name);
463 WLog_INFO(TAG,
"\tDescription: %s", plugin->description);
467 void pf_modules_list_loaded_plugins(proxyModule* module)
471 WINPR_ASSERT(module);
472 WINPR_ASSERT(module->plugins);
474 count = ArrayList_Count(module->plugins);
477 WLog_INFO(TAG,
"Loaded plugins:");
479 ArrayList_ForEach(module->plugins, pf_modules_print_ArrayList_ForEachFkt);
482 static BOOL pf_modules_load_module(
const char* module_path, proxyModule* module,
void* userdata)
484 WINPR_ASSERT(module);
486 HANDLE handle = LoadLibraryX(module_path);
490 WLog_ERR(TAG,
"failed loading external library: %s", module_path);
494 proxyModuleEntryPoint pEntryPoint =
495 GetProcAddressAs(handle, MODULE_ENTRY_POINT, proxyModuleEntryPoint);
498 WLog_ERR(TAG,
"GetProcAddress failed while loading %s", module_path);
501 if (!ArrayList_Append(module->handles, handle))
503 WLog_ERR(TAG,
"ArrayList_Append failed!");
506 return pf_modules_add(module, pEntryPoint, userdata);
513 static void free_handle(
void* obj)
515 HANDLE handle = (HANDLE)obj;
520 static void free_plugin(
void* obj)
522 proxyPlugin* plugin = (proxyPlugin*)obj;
523 WINPR_ASSERT(plugin);
525 if (!IFCALLRESULT(TRUE, plugin->PluginUnload, plugin))
526 WLog_WARN(TAG,
"PluginUnload failed for plugin '%s'", plugin->name);
531 static void* new_plugin(
const void* obj)
533 const proxyPlugin* src = obj;
534 proxyPlugin* proxy = calloc(1,
sizeof(proxyPlugin));
541 proxyModule* pf_modules_new(
const char* root_dir,
const char** modules,
size_t count)
545 proxyModule* module = calloc(1,
sizeof(proxyModule));
549 module->mgr.RegisterPlugin = pf_modules_register_plugin;
550 module->mgr.SetPluginData = pf_modules_set_plugin_data;
551 module->mgr.GetPluginData = pf_modules_get_plugin_data;
552 module->mgr.AbortConnect = pf_modules_abort_connect;
553 module->plugins = ArrayList_New(FALSE);
555 if (module->plugins == NULL)
557 WLog_ERR(TAG,
"ArrayList_New failed!");
560 obj = ArrayList_Object(module->plugins);
563 obj->fnObjectFree = free_plugin;
564 obj->fnObjectNew = new_plugin;
566 module->handles = ArrayList_New(FALSE);
567 if (module->handles == NULL)
570 WLog_ERR(TAG,
"ArrayList_New failed!");
573 ArrayList_Object(module->handles)->fnObjectFree = free_handle;
577 WINPR_ASSERT(root_dir);
578 if (!winpr_PathFileExists(root_dir))
579 path = GetCombinedPath(FREERDP_INSTALL_PREFIX, root_dir);
581 path = _strdup(root_dir);
583 if (!winpr_PathFileExists(path))
585 if (!winpr_PathMakePath(path, NULL))
587 WLog_ERR(TAG,
"error occurred while creating modules directory: %s", root_dir);
592 if (winpr_PathFileExists(path))
593 WLog_DBG(TAG,
"modules root directory: %s", path);
595 for (
size_t i = 0; i < count; i++)
597 char name[8192] = { 0 };
598 char* fullpath = NULL;
599 (void)_snprintf(name,
sizeof(name),
"proxy-%s-plugin%s", modules[i],
600 FREERDP_SHARED_LIBRARY_SUFFIX);
601 fullpath = GetCombinedPath(path, name);
602 pf_modules_load_module(fullpath, module, NULL);
612 pf_modules_free(module);
616 void pf_modules_free(proxyModule* module)
621 ArrayList_Free(module->plugins);
622 ArrayList_Free(module->handles);
626 BOOL pf_modules_add(proxyModule* module, proxyModuleEntryPoint ep,
void* userdata)
628 WINPR_ASSERT(module);
631 return ep(&module->mgr, userdata);
This struct contains function pointer to initialize/free objects.