FreeRDP
Loading...
Searching...
No Matches
pf_modules.c
1
23#include <winpr/assert.h>
24
25#include <winpr/file.h>
26#include <winpr/wlog.h>
27#include <winpr/path.h>
28#include <winpr/library.h>
29
30#include <freerdp/version.h>
31#include <freerdp/api.h>
32#include <freerdp/build-config.h>
33
34#include <freerdp/server/proxy/proxy_log.h>
35#include <freerdp/server/proxy/proxy_modules_api.h>
36
37#include <freerdp/server/proxy/proxy_context.h>
38#include "proxy_modules.h"
39
40#define TAG PROXY_TAG("modules")
41
42#define MODULE_ENTRY_POINT "proxy_module_entry_point"
43
44struct proxy_module
45{
46 proxyPluginsManager mgr;
47 wArrayList* plugins;
48 wArrayList* handles;
49};
50
51static const char* pf_modules_get_filter_type_string(PF_FILTER_TYPE result)
52{
53 switch (result)
54 {
55 case FILTER_TYPE_KEYBOARD:
56 return "FILTER_TYPE_KEYBOARD";
57 case FILTER_TYPE_UNICODE:
58 return "FILTER_TYPE_UNICODE";
59 case FILTER_TYPE_MOUSE:
60 return "FILTER_TYPE_MOUSE";
61 case FILTER_TYPE_MOUSE_EX:
62 return "FILTER_TYPE_MOUSE_EX";
63 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA:
64 return "FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA";
65 case FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA:
66 return "FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA";
67 case FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE:
68 return "FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE";
69 case FILTER_TYPE_SERVER_FETCH_TARGET_ADDR:
70 return "FILTER_TYPE_SERVER_FETCH_TARGET_ADDR";
71 case FILTER_TYPE_SERVER_PEER_LOGON:
72 return "FILTER_TYPE_SERVER_PEER_LOGON";
73 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE:
74 return "FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE";
75 case FILTER_TYPE_STATIC_INTERCEPT_LIST:
76 return "FILTER_TYPE_STATIC_INTERCEPT_LIST";
77 case FILTER_TYPE_DYN_INTERCEPT_LIST:
78 return "FILTER_TYPE_DYN_INTERCEPT_LIST";
79 case FILTER_TYPE_INTERCEPT_CHANNEL:
80 return "FILTER_TYPE_INTERCEPT_CHANNEL";
81 case FILTER_LAST:
82 return "FILTER_LAST";
83 default:
84 return "FILTER_UNKNOWN";
85 }
86}
87
88static const char* pf_modules_get_hook_type_string(PF_HOOK_TYPE result)
89{
90 switch (result)
91 {
92 case HOOK_TYPE_CLIENT_INIT_CONNECT:
93 return "HOOK_TYPE_CLIENT_INIT_CONNECT";
94 case HOOK_TYPE_CLIENT_UNINIT_CONNECT:
95 return "HOOK_TYPE_CLIENT_UNINIT_CONNECT";
96 case HOOK_TYPE_CLIENT_PRE_CONNECT:
97 return "HOOK_TYPE_CLIENT_PRE_CONNECT";
98 case HOOK_TYPE_CLIENT_POST_CONNECT:
99 return "HOOK_TYPE_CLIENT_POST_CONNECT";
100 case HOOK_TYPE_CLIENT_POST_DISCONNECT:
101 return "HOOK_TYPE_CLIENT_POST_DISCONNECT";
102 case HOOK_TYPE_CLIENT_REDIRECT:
103 return "HOOK_TYPE_CLIENT_REDIRECT";
104 case HOOK_TYPE_CLIENT_VERIFY_X509:
105 return "HOOK_TYPE_CLIENT_VERIFY_X509";
106 case HOOK_TYPE_CLIENT_LOGIN_FAILURE:
107 return "HOOK_TYPE_CLIENT_LOGIN_FAILURE";
108 case HOOK_TYPE_CLIENT_END_PAINT:
109 return "HOOK_TYPE_CLIENT_END_PAINT";
110 case HOOK_TYPE_SERVER_POST_CONNECT:
111 return "HOOK_TYPE_SERVER_POST_CONNECT";
112 case HOOK_TYPE_SERVER_ACTIVATE:
113 return "HOOK_TYPE_SERVER_ACTIVATE";
114 case HOOK_TYPE_SERVER_CHANNELS_INIT:
115 return "HOOK_TYPE_SERVER_CHANNELS_INIT";
116 case HOOK_TYPE_SERVER_CHANNELS_FREE:
117 return "HOOK_TYPE_SERVER_CHANNELS_FREE";
118 case HOOK_TYPE_SERVER_SESSION_END:
119 return "HOOK_TYPE_SERVER_SESSION_END";
120 case HOOK_TYPE_CLIENT_LOAD_CHANNELS:
121 return "HOOK_TYPE_CLIENT_LOAD_CHANNELS";
122 case HOOK_TYPE_SERVER_SESSION_INITIALIZE:
123 return "HOOK_TYPE_SERVER_SESSION_INITIALIZE";
124 case HOOK_TYPE_SERVER_SESSION_STARTED:
125 return "HOOK_TYPE_SERVER_SESSION_STARTED";
126 case HOOK_LAST:
127 return "HOOK_LAST";
128 default:
129 return "HOOK_TYPE_UNKNOWN";
130 }
131}
132
133static BOOL pf_modules_proxy_ArrayList_ForEachFkt(void* data, size_t index, va_list ap)
134{
135 proxyPlugin* plugin = (proxyPlugin*)data;
136 BOOL ok = FALSE;
137
138 WINPR_UNUSED(index);
139
140 PF_HOOK_TYPE type = va_arg(ap, PF_HOOK_TYPE);
141 proxyData* pdata = va_arg(ap, proxyData*);
142 void* custom = va_arg(ap, void*);
143
144 WLog_VRB(TAG, "running hook %s.%s", plugin->name, pf_modules_get_hook_type_string(type));
145
146 switch (type)
147 {
148 case HOOK_TYPE_CLIENT_INIT_CONNECT:
149 ok = IFCALLRESULT(TRUE, plugin->ClientInitConnect, plugin, pdata, custom);
150 break;
151 case HOOK_TYPE_CLIENT_UNINIT_CONNECT:
152 ok = IFCALLRESULT(TRUE, plugin->ClientUninitConnect, plugin, pdata, custom);
153 break;
154 case HOOK_TYPE_CLIENT_PRE_CONNECT:
155 ok = IFCALLRESULT(TRUE, plugin->ClientPreConnect, plugin, pdata, custom);
156 break;
157
158 case HOOK_TYPE_CLIENT_POST_CONNECT:
159 ok = IFCALLRESULT(TRUE, plugin->ClientPostConnect, plugin, pdata, custom);
160 break;
161
162 case HOOK_TYPE_CLIENT_REDIRECT:
163 ok = IFCALLRESULT(TRUE, plugin->ClientRedirect, plugin, pdata, custom);
164 break;
165
166 case HOOK_TYPE_CLIENT_POST_DISCONNECT:
167 ok = IFCALLRESULT(TRUE, plugin->ClientPostDisconnect, plugin, pdata, custom);
168 break;
169
170 case HOOK_TYPE_CLIENT_VERIFY_X509:
171 ok = IFCALLRESULT(TRUE, plugin->ClientX509Certificate, plugin, pdata, custom);
172 break;
173
174 case HOOK_TYPE_CLIENT_LOGIN_FAILURE:
175 ok = IFCALLRESULT(TRUE, plugin->ClientLoginFailure, plugin, pdata, custom);
176 break;
177
178 case HOOK_TYPE_CLIENT_END_PAINT:
179 ok = IFCALLRESULT(TRUE, plugin->ClientEndPaint, plugin, pdata, custom);
180 break;
181
182 case HOOK_TYPE_CLIENT_LOAD_CHANNELS:
183 ok = IFCALLRESULT(TRUE, plugin->ClientLoadChannels, plugin, pdata, custom);
184 break;
185
186 case HOOK_TYPE_SERVER_POST_CONNECT:
187 ok = IFCALLRESULT(TRUE, plugin->ServerPostConnect, plugin, pdata, custom);
188 break;
189
190 case HOOK_TYPE_SERVER_ACTIVATE:
191 ok = IFCALLRESULT(TRUE, plugin->ServerPeerActivate, plugin, pdata, custom);
192 break;
193
194 case HOOK_TYPE_SERVER_CHANNELS_INIT:
195 ok = IFCALLRESULT(TRUE, plugin->ServerChannelsInit, plugin, pdata, custom);
196 break;
197
198 case HOOK_TYPE_SERVER_CHANNELS_FREE:
199 ok = IFCALLRESULT(TRUE, plugin->ServerChannelsFree, plugin, pdata, custom);
200 break;
201
202 case HOOK_TYPE_SERVER_SESSION_END:
203 ok = IFCALLRESULT(TRUE, plugin->ServerSessionEnd, plugin, pdata, custom);
204 break;
205
206 case HOOK_TYPE_SERVER_SESSION_INITIALIZE:
207 ok = IFCALLRESULT(TRUE, plugin->ServerSessionInitialize, plugin, pdata, custom);
208 break;
209
210 case HOOK_TYPE_SERVER_SESSION_STARTED:
211 ok = IFCALLRESULT(TRUE, plugin->ServerSessionStarted, plugin, pdata, custom);
212 break;
213
214 case HOOK_LAST:
215 default:
216 WLog_ERR(TAG, "invalid hook called");
217 }
218
219 if (!ok)
220 {
221 WLog_INFO(TAG, "plugin %s, hook %s failed!", plugin->name,
222 pf_modules_get_hook_type_string(type));
223 return FALSE;
224 }
225 return TRUE;
226}
227
228/*
229 * runs all hooks of type `type`.
230 *
231 * @type: hook type to run.
232 * @server: pointer of server's rdpContext struct of the current session.
233 */
234BOOL pf_modules_run_hook(proxyModule* module, PF_HOOK_TYPE type, proxyData* pdata, void* custom)
235{
236 WINPR_ASSERT(module);
237 WINPR_ASSERT(module->plugins);
238 return ArrayList_ForEach(module->plugins, pf_modules_proxy_ArrayList_ForEachFkt, type, pdata,
239 custom);
240}
241
242static BOOL pf_modules_ArrayList_ForEachFkt(void* data, size_t index, va_list ap)
243{
244 proxyPlugin* plugin = (proxyPlugin*)data;
245 BOOL result = FALSE;
246
247 WINPR_UNUSED(index);
248
249 PF_FILTER_TYPE type = va_arg(ap, PF_FILTER_TYPE);
250 proxyData* pdata = va_arg(ap, proxyData*);
251 void* param = va_arg(ap, void*);
252
253 WLog_VRB(TAG, "running filter: %s", plugin->name);
254
255 switch (type)
256 {
257 case FILTER_TYPE_KEYBOARD:
258 result = IFCALLRESULT(TRUE, plugin->KeyboardEvent, plugin, pdata, param);
259 break;
260
261 case FILTER_TYPE_UNICODE:
262 result = IFCALLRESULT(TRUE, plugin->UnicodeEvent, plugin, pdata, param);
263 break;
264
265 case FILTER_TYPE_MOUSE:
266 result = IFCALLRESULT(TRUE, plugin->MouseEvent, plugin, pdata, param);
267 break;
268
269 case FILTER_TYPE_MOUSE_EX:
270 result = IFCALLRESULT(TRUE, plugin->MouseExEvent, plugin, pdata, param);
271 break;
272
273 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA:
274 result = IFCALLRESULT(TRUE, plugin->ClientChannelData, plugin, pdata, param);
275 break;
276
277 case FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA:
278 result = IFCALLRESULT(TRUE, plugin->ServerChannelData, plugin, pdata, param);
279 break;
280
281 case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE:
282 result = IFCALLRESULT(TRUE, plugin->ChannelCreate, plugin, pdata, param);
283 break;
284
285 case FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE:
286 result = IFCALLRESULT(TRUE, plugin->DynamicChannelCreate, plugin, pdata, param);
287 break;
288
289 case FILTER_TYPE_SERVER_FETCH_TARGET_ADDR:
290 result = IFCALLRESULT(TRUE, plugin->ServerFetchTargetAddr, plugin, pdata, param);
291 break;
292
293 case FILTER_TYPE_SERVER_PEER_LOGON:
294 result = IFCALLRESULT(TRUE, plugin->ServerPeerLogon, plugin, pdata, param);
295 break;
296
297 case FILTER_TYPE_INTERCEPT_CHANNEL:
298 result = IFCALLRESULT(TRUE, plugin->DynChannelIntercept, plugin, pdata, param);
299 break;
300
301 case FILTER_TYPE_DYN_INTERCEPT_LIST:
302 result = IFCALLRESULT(TRUE, plugin->DynChannelToIntercept, plugin, pdata, param);
303 break;
304
305 case FILTER_TYPE_STATIC_INTERCEPT_LIST:
306 result = IFCALLRESULT(TRUE, plugin->StaticChannelToIntercept, plugin, pdata, param);
307 break;
308
309 case FILTER_LAST:
310 default:
311 WLog_ERR(TAG, "invalid filter called");
312 }
313
314 if (!result)
315 {
316 /* current filter return FALSE, no need to run other filters. */
317 WLog_DBG(TAG, "plugin %s, filter type [%s] returned FALSE", plugin->name,
318 pf_modules_get_filter_type_string(type));
319 }
320 return result;
321}
322
323/*
324 * runs all filters of type `type`.
325 *
326 * @type: filter type to run.
327 * @server: pointer of server's rdpContext struct of the current session.
328 */
329BOOL pf_modules_run_filter(proxyModule* module, PF_FILTER_TYPE type, proxyData* pdata, void* param)
330{
331 WINPR_ASSERT(module);
332 WINPR_ASSERT(module->plugins);
333
334 return ArrayList_ForEach(module->plugins, pf_modules_ArrayList_ForEachFkt, type, pdata, param);
335}
336
337/*
338 * stores per-session data needed by a plugin.
339 *
340 * @context: current session server's rdpContext instance.
341 * @info: pointer to per-session data.
342 */
343static BOOL pf_modules_set_plugin_data(WINPR_ATTR_UNUSED proxyPluginsManager* mgr,
344 const char* plugin_name, proxyData* pdata, void* data)
345{
346 union
347 {
348 const char* ccp;
349 char* cp;
350 } ccharconv;
351
352 WINPR_ASSERT(plugin_name);
353
354 ccharconv.ccp = plugin_name;
355 if (data == NULL) /* no need to store anything */
356 return FALSE;
357
358 if (!HashTable_Insert(pdata->modules_info, ccharconv.cp, data))
359 {
360 WLog_ERR(TAG, "[%s]: HashTable_Insert failed!");
361 return FALSE;
362 }
363
364 return TRUE;
365}
366
367/*
368 * returns per-session data needed a plugin.
369 *
370 * @context: current session server's rdpContext instance.
371 * if there's no data related to `plugin_name` in `context` (current session), a NULL will be
372 * returned.
373 */
374static void* pf_modules_get_plugin_data(WINPR_ATTR_UNUSED proxyPluginsManager* mgr,
375 const char* plugin_name, proxyData* pdata)
376{
377 union
378 {
379 const char* ccp;
380 char* cp;
381 } ccharconv;
382 WINPR_ASSERT(plugin_name);
383 WINPR_ASSERT(pdata);
384 ccharconv.ccp = plugin_name;
385
386 return HashTable_GetItemValue(pdata->modules_info, ccharconv.cp);
387}
388
389static void pf_modules_abort_connect(WINPR_ATTR_UNUSED proxyPluginsManager* mgr, proxyData* pdata)
390{
391 WINPR_ASSERT(pdata);
392 WLog_DBG(TAG, "is called!");
393 proxy_data_abort_connect(pdata);
394}
395
396static BOOL pf_modules_register_ArrayList_ForEachFkt(void* data, size_t index, va_list ap)
397{
398 proxyPlugin* plugin = (proxyPlugin*)data;
399 proxyPlugin* plugin_to_register = va_arg(ap, proxyPlugin*);
400
401 WINPR_UNUSED(index);
402
403 if (strcmp(plugin->name, plugin_to_register->name) == 0)
404 {
405 WLog_ERR(TAG, "can not register plugin '%s', it is already registered!", plugin->name);
406 return FALSE;
407 }
408 return TRUE;
409}
410
411static BOOL pf_modules_register_plugin(proxyPluginsManager* mgr,
412 const proxyPlugin* plugin_to_register)
413{
414 proxyPlugin internal = { 0 };
415 proxyModule* module = (proxyModule*)mgr;
416 WINPR_ASSERT(module);
417
418 if (!plugin_to_register)
419 return FALSE;
420
421 internal = *plugin_to_register;
422 internal.mgr = mgr;
423
424 /* make sure there's no other loaded plugin with the same name of `plugin_to_register`. */
425 if (!ArrayList_ForEach(module->plugins, pf_modules_register_ArrayList_ForEachFkt, &internal))
426 return FALSE;
427
428 if (!ArrayList_Append(module->plugins, &internal))
429 {
430 WLog_ERR(TAG, "failed adding plugin to list: %s", plugin_to_register->name);
431 return FALSE;
432 }
433 WLog_INFO(TAG, "Successfully registered proxy plugin '%s'", plugin_to_register->name);
434
435 return TRUE;
436}
437
438static BOOL pf_modules_load_ArrayList_ForEachFkt(void* data, size_t index, va_list ap)
439{
440 proxyPlugin* plugin = (proxyPlugin*)data;
441 const char* plugin_name = va_arg(ap, const char*);
442 BOOL* res = va_arg(ap, BOOL*);
443
444 WINPR_UNUSED(index);
445 WINPR_UNUSED(ap);
446 WINPR_ASSERT(res);
447
448 if (strcmp(plugin->name, plugin_name) == 0)
449 *res = TRUE;
450 return TRUE;
451}
452
453BOOL pf_modules_is_plugin_loaded(proxyModule* module, const char* plugin_name)
454{
455 BOOL rc = FALSE;
456 WINPR_ASSERT(module);
457 if (ArrayList_Count(module->plugins) < 1)
458 return FALSE;
459 if (!ArrayList_ForEach(module->plugins, pf_modules_load_ArrayList_ForEachFkt, plugin_name, &rc))
460 return FALSE;
461 return rc;
462}
463
464static BOOL pf_modules_print_ArrayList_ForEachFkt(void* data, size_t index, va_list ap)
465{
466 proxyPlugin* plugin = (proxyPlugin*)data;
467
468 WINPR_UNUSED(index);
469 WINPR_UNUSED(ap);
470
471 WLog_INFO(TAG, "\tName: %s", plugin->name);
472 WLog_INFO(TAG, "\tDescription: %s", plugin->description);
473 return TRUE;
474}
475
476void pf_modules_list_loaded_plugins(proxyModule* module)
477{
478 size_t count = 0;
479
480 WINPR_ASSERT(module);
481 WINPR_ASSERT(module->plugins);
482
483 count = ArrayList_Count(module->plugins);
484
485 if (count > 0)
486 WLog_INFO(TAG, "Loaded plugins:");
487
488 ArrayList_ForEach(module->plugins, pf_modules_print_ArrayList_ForEachFkt);
489}
490
491static BOOL pf_modules_load_static_module(const char* module_name, proxyModule* module,
492 void* userdata)
493{
494 WINPR_ASSERT(module);
495
496 HANDLE handle = GetModuleHandleA(NULL);
497
498 if (handle == NULL)
499 {
500 WLog_DBG(TAG, "failed loading static library: %s", module_name);
501 return FALSE;
502 }
503
504 char name[256] = { 0 };
505 (void)_snprintf(name, sizeof(name), "%s_%s", module_name, MODULE_ENTRY_POINT);
506 for (size_t x = 0; x < strnlen(name, sizeof(name)); x++)
507 {
508 if (name[x] == '-')
509 name[x] = '_';
510 }
511
512 proxyModuleEntryPoint pEntryPoint = GetProcAddressAs(handle, name, proxyModuleEntryPoint);
513 if (!pEntryPoint)
514 {
515 WLog_DBG(TAG, "GetProcAddress failed for static %s (module %s)", name, module_name);
516 goto error;
517 }
518 if (!ArrayList_Append(module->handles, handle))
519 {
520 WLog_ERR(TAG, "ArrayList_Append failed!");
521 goto error;
522 }
523 return pf_modules_add(module, pEntryPoint, userdata);
524
525error:
526 FreeLibrary(handle);
527 return FALSE;
528}
529
530static BOOL pf_modules_load_dynamic_module(const char* module_path, proxyModule* module,
531 void* userdata)
532{
533 if (!winpr_PathFileExists(module_path))
534 {
535 WLog_DBG(TAG, "failed loading external library: file '%s' does not exist", module_path);
536 return FALSE;
537 }
538
539 HANDLE handle = LoadLibraryX(module_path);
540
541 if (handle == NULL)
542 {
543 WLog_DBG(TAG, "failed loading external library: %s", module_path);
544 return FALSE;
545 }
546
547 proxyModuleEntryPoint pEntryPoint =
548 GetProcAddressAs(handle, MODULE_ENTRY_POINT, proxyModuleEntryPoint);
549 if (!pEntryPoint)
550 {
551 WLog_DBG(TAG, "GetProcAddress failed while loading %s", module_path);
552 goto error;
553 }
554 if (!ArrayList_Append(module->handles, handle))
555 {
556 WLog_ERR(TAG, "ArrayList_Append failed!");
557 goto error;
558 }
559 return pf_modules_add(module, pEntryPoint, userdata);
560
561error:
562 FreeLibrary(handle);
563 return FALSE;
564}
565
566static BOOL pf_modules_try_load_dynamic_module(const char* module_path, proxyModule* module,
567 void* userdata, size_t count, const char* names[])
568{
569 for (size_t x = 0; x < count; x++)
570 {
571 const char* name = names[x];
572
573 char* fullpath = GetCombinedPath(module_path, name);
574 if (!fullpath)
575 continue;
576
577 const BOOL rc = pf_modules_load_dynamic_module(fullpath, module, userdata);
578 free(fullpath);
579 if (rc)
580 return TRUE;
581 }
582 return FALSE;
583}
584
585static BOOL pf_modules_load_module(const char* module_path, const char* module_name,
586 proxyModule* module, void* userdata)
587{
588 WINPR_ASSERT(module);
589
590 if (pf_modules_load_static_module(module_name, module, userdata))
591 return TRUE;
592
593 char names[5][MAX_PATH] = { 0 };
594 (void)_snprintf(names[0], sizeof(names[0]), "proxy-%s-plugin%s", module_name,
595 FREERDP_SHARED_LIBRARY_SUFFIX);
596 (void)_snprintf(names[1], sizeof(names[1]), "%sproxy-%s-plugin%s",
597 FREERDP_SHARED_LIBRARY_PREFIX, module_name, FREERDP_SHARED_LIBRARY_SUFFIX);
598 (void)_snprintf(names[2], sizeof(names[2]), "%sproxy-%s-plugin%s.%d",
599 FREERDP_SHARED_LIBRARY_PREFIX, module_name, FREERDP_SHARED_LIBRARY_SUFFIX,
600 FREERDP_VERSION_MAJOR);
601 (void)_snprintf(names[3], sizeof(names[3]), "%sproxy-%s-plugin%d%s",
602 FREERDP_SHARED_LIBRARY_PREFIX, module_name, FREERDP_VERSION_MAJOR,
603 FREERDP_SHARED_LIBRARY_SUFFIX);
604 (void)_snprintf(names[4], sizeof(names[4]), "%sproxy-%s-plugin%d%s.%d",
605 FREERDP_SHARED_LIBRARY_PREFIX, module_name, FREERDP_VERSION_MAJOR,
606 FREERDP_SHARED_LIBRARY_SUFFIX, FREERDP_VERSION_MAJOR);
607
608 const char* cnames[5] = { names[0], names[1], names[2], names[3], names[4] };
609 return pf_modules_try_load_dynamic_module(module_path, module, userdata, ARRAYSIZE(cnames),
610 cnames);
611}
612
613static void free_handle(void* obj)
614{
615 HANDLE handle = (HANDLE)obj;
616 if (handle)
617 FreeLibrary(handle);
618}
619
620static void free_plugin(void* obj)
621{
622 proxyPlugin* plugin = (proxyPlugin*)obj;
623 WINPR_ASSERT(plugin);
624
625 if (!IFCALLRESULT(TRUE, plugin->PluginUnload, plugin))
626 WLog_WARN(TAG, "PluginUnload failed for plugin '%s'", plugin->name);
627
628 free(plugin);
629}
630
631static void* new_plugin(const void* obj)
632{
633 const proxyPlugin* src = obj;
634 proxyPlugin* proxy = calloc(1, sizeof(proxyPlugin));
635 if (!proxy)
636 return NULL;
637 *proxy = *src;
638 return proxy;
639}
640
641proxyModule* pf_modules_new(const char* root_dir, const char** modules, size_t count)
642{
643 wObject* obj = NULL;
644 char* path = NULL;
645 proxyModule* module = calloc(1, sizeof(proxyModule));
646 if (!module)
647 return NULL;
648
649 module->mgr.RegisterPlugin = pf_modules_register_plugin;
650 module->mgr.SetPluginData = pf_modules_set_plugin_data;
651 module->mgr.GetPluginData = pf_modules_get_plugin_data;
652 module->mgr.AbortConnect = pf_modules_abort_connect;
653 module->plugins = ArrayList_New(FALSE);
654
655 if (module->plugins == NULL)
656 {
657 WLog_ERR(TAG, "ArrayList_New failed!");
658 goto error;
659 }
660 obj = ArrayList_Object(module->plugins);
661 WINPR_ASSERT(obj);
662
663 obj->fnObjectFree = free_plugin;
664 obj->fnObjectNew = new_plugin;
665
666 module->handles = ArrayList_New(FALSE);
667 if (module->handles == NULL)
668 {
669
670 WLog_ERR(TAG, "ArrayList_New failed!");
671 goto error;
672 }
673 ArrayList_Object(module->handles)->fnObjectFree = free_handle;
674
675 if (count > 0)
676 {
677 WINPR_ASSERT(root_dir);
678 if (!winpr_PathFileExists(root_dir))
679 path = GetCombinedPath(FREERDP_INSTALL_PREFIX, root_dir);
680 else
681 path = _strdup(root_dir);
682
683 if (!winpr_PathFileExists(path))
684 {
685 if (!winpr_PathMakePath(path, NULL))
686 {
687 WLog_ERR(TAG, "error occurred while creating modules directory: %s", root_dir);
688 }
689 }
690
691 if (winpr_PathFileExists(path))
692 WLog_DBG(TAG, "modules root directory: %s", path);
693
694 for (size_t i = 0; i < count; i++)
695 {
696 const char* module_name = modules[i];
697 if (!pf_modules_load_module(path, module_name, module, NULL))
698 WLog_WARN(TAG, "Failed to load proxy module '%s'", module_name);
699 else
700 WLog_INFO(TAG, "Successfully loaded proxy module '%s'", module_name);
701 }
702 }
703
704 free(path);
705 return module;
706
707error:
708 free(path);
709 pf_modules_free(module);
710 return NULL;
711}
712
713void pf_modules_free(proxyModule* module)
714{
715 if (!module)
716 return;
717
718 ArrayList_Free(module->plugins);
719 ArrayList_Free(module->handles);
720 free(module);
721}
722
723BOOL pf_modules_add(proxyModule* module, proxyModuleEntryPoint ep, void* userdata)
724{
725 WINPR_ASSERT(module);
726 WINPR_ASSERT(ep);
727
728 return ep(&module->mgr, userdata);
729}
This struct contains function pointer to initialize/free objects.
Definition collections.h:57