Blame server/proxy/pf_modules.c

Packit Service 5a9772
/**
Packit Service 5a9772
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service 5a9772
 * FreeRDP Proxy Server modules API
Packit Service 5a9772
 *
Packit Service 5a9772
 * Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
Packit Service 5a9772
 * Copyright 2019 Idan Freiberg <speidy@gmail.com>
Packit Service 5a9772
 *
Packit Service 5a9772
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service 5a9772
 * you may not use this file except in compliance with the License.
Packit Service 5a9772
 * You may obtain a copy of the License at
Packit Service 5a9772
 *
Packit Service 5a9772
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service 5a9772
 *
Packit Service 5a9772
 * Unless required by applicable law or agreed to in writing, software
Packit Service 5a9772
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service 5a9772
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service 5a9772
 * See the License for the specific language governing permissions and
Packit Service 5a9772
 * limitations under the License.
Packit Service 5a9772
 */
Packit Service 5a9772
Packit Service 5a9772
#include <assert.h>
Packit Service 5a9772
Packit Service 5a9772
#include <winpr/file.h>
Packit Service 5a9772
#include <winpr/wlog.h>
Packit Service 5a9772
#include <winpr/library.h>
Packit Service 5a9772
#include <freerdp/api.h>
Packit Service 5a9772
#include <freerdp/build-config.h>
Packit Service 5a9772
Packit Service 5a9772
#include "pf_log.h"
Packit Service 5a9772
#include "pf_modules.h"
Packit Service 5a9772
#include "pf_context.h"
Packit Service 5a9772
Packit Service 5a9772
#define TAG PROXY_TAG("modules")
Packit Service 5a9772
Packit Service 5a9772
#define MODULE_ENTRY_POINT "proxy_module_entry_point"
Packit Service 5a9772
Packit Service 5a9772
static wArrayList* plugins_list = NULL; /* list of all loaded plugins */
Packit Service 5a9772
static wArrayList* handles_list = NULL; /* list of module handles to free at shutdown */
Packit Service 5a9772
Packit Service 5a9772
typedef BOOL (*moduleEntryPoint)(proxyPluginsManager* plugins_manager);
Packit Service 5a9772
Packit Service 5a9772
static const char* FILTER_TYPE_STRINGS[] = {
Packit Service 5a9772
	"KEYBOARD_EVENT",
Packit Service 5a9772
	"MOUSE_EVENT",
Packit Service 5a9772
	"CLIENT_CHANNEL_DATA",
Packit Service 5a9772
	"SERVER_CHANNEL_DATA",
Packit Service 5a9772
};
Packit Service 5a9772
Packit Service 5a9772
static const char* HOOK_TYPE_STRINGS[] = {
Packit Service 5a9772
	"CLIENT_PRE_CONNECT",   "CLIENT_LOGIN_FAILURE", "SERVER_POST_CONNECT",
Packit Service 5a9772
	"SERVER_CHANNELS_INIT", "SERVER_CHANNELS_FREE",
Packit Service 5a9772
};
Packit Service 5a9772
Packit Service 5a9772
static const char* pf_modules_get_filter_type_string(PF_FILTER_TYPE result)
Packit Service 5a9772
{
Packit Service 5a9772
	if (result >= FILTER_TYPE_KEYBOARD && result < FILTER_LAST)
Packit Service 5a9772
		return FILTER_TYPE_STRINGS[result];
Packit Service 5a9772
	else
Packit Service 5a9772
		return "FILTER_UNKNOWN";
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static const char* pf_modules_get_hook_type_string(PF_HOOK_TYPE result)
Packit Service 5a9772
{
Packit Service 5a9772
	if (result >= HOOK_TYPE_CLIENT_PRE_CONNECT && result < HOOK_LAST)
Packit Service 5a9772
		return HOOK_TYPE_STRINGS[result];
Packit Service 5a9772
	else
Packit Service 5a9772
		return "HOOK_UNKNOWN";
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/*
Packit Service 5a9772
 * runs all hooks of type `type`.
Packit Service 5a9772
 *
Packit Service 5a9772
 * @type: hook type to run.
Packit Service 5a9772
 * @server: pointer of server's rdpContext struct of the current session.
Packit Service 5a9772
 */
Packit Service 5a9772
BOOL pf_modules_run_hook(PF_HOOK_TYPE type, proxyData* pdata)
Packit Service 5a9772
{
Packit Service 5a9772
	BOOL ok = TRUE;
Packit Service 5a9772
	int index;
Packit Service 5a9772
	proxyPlugin* plugin;
Packit Service 5a9772
Packit Service 5a9772
	ArrayList_ForEach(plugins_list, proxyPlugin*, index, plugin)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_VRB(TAG, "running hook %s.%s", plugin->name, pf_modules_get_hook_type_string(type));
Packit Service 5a9772
Packit Service 5a9772
		switch (type)
Packit Service 5a9772
		{
Packit Service 5a9772
			case HOOK_TYPE_CLIENT_PRE_CONNECT:
Packit Service 5a9772
				IFCALLRET(plugin->ClientPreConnect, ok, pdata);
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case HOOK_TYPE_CLIENT_LOGIN_FAILURE:
Packit Service 5a9772
				IFCALLRET(plugin->ClientLoginFailure, ok, pdata);
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case HOOK_TYPE_SERVER_POST_CONNECT:
Packit Service 5a9772
				IFCALLRET(plugin->ServerPostConnect, ok, pdata);
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case HOOK_TYPE_SERVER_CHANNELS_INIT:
Packit Service 5a9772
				IFCALLRET(plugin->ServerChannelsInit, ok, pdata);
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case HOOK_TYPE_SERVER_CHANNELS_FREE:
Packit Service 5a9772
				IFCALLRET(plugin->ServerChannelsFree, ok, pdata);
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			default:
Packit Service 5a9772
				WLog_ERR(TAG, "invalid hook called");
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		if (!ok)
Packit Service 5a9772
		{
Packit Service 5a9772
			WLog_INFO(TAG, "plugin %s, hook %s failed!", plugin->name,
Packit Service 5a9772
			          pf_modules_get_hook_type_string(type));
Packit Service 5a9772
			return FALSE;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/*
Packit Service 5a9772
 * runs all filters of type `type`.
Packit Service 5a9772
 *
Packit Service 5a9772
 * @type: filter type to run.
Packit Service 5a9772
 * @server: pointer of server's rdpContext struct of the current session.
Packit Service 5a9772
 */
Packit Service 5a9772
BOOL pf_modules_run_filter(PF_FILTER_TYPE type, proxyData* pdata, void* param)
Packit Service 5a9772
{
Packit Service 5a9772
	BOOL result = TRUE;
Packit Service 5a9772
	int index;
Packit Service 5a9772
	proxyPlugin* plugin;
Packit Service 5a9772
Packit Service 5a9772
	ArrayList_ForEach(plugins_list, proxyPlugin*, index, plugin)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_VRB(TAG, "[%s]: running filter: %s", __FUNCTION__, plugin->name);
Packit Service 5a9772
Packit Service 5a9772
		switch (type)
Packit Service 5a9772
		{
Packit Service 5a9772
			case FILTER_TYPE_KEYBOARD:
Packit Service 5a9772
				IFCALLRET(plugin->KeyboardEvent, result, pdata, param);
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case FILTER_TYPE_MOUSE:
Packit Service 5a9772
				IFCALLRET(plugin->MouseEvent, result, pdata, param);
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA:
Packit Service 5a9772
				IFCALLRET(plugin->ClientChannelData, result, pdata, param);
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA:
Packit Service 5a9772
				IFCALLRET(plugin->ServerChannelData, result, pdata, param);
Packit Service 5a9772
				break;
Packit Service 5a9772
			default:
Packit Service 5a9772
				WLog_ERR(TAG, "invalid filter called");
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		if (!result)
Packit Service 5a9772
		{
Packit Service 5a9772
			/* current filter return FALSE, no need to run other filters. */
Packit Service 5a9772
			WLog_DBG(TAG, "plugin %s, filter type [%s] returned FALSE", plugin->name,
Packit Service 5a9772
			         pf_modules_get_filter_type_string(type));
Packit Service 5a9772
			return result;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	/* all filters returned TRUE */
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/*
Packit Service 5a9772
 * stores per-session data needed by a plugin.
Packit Service 5a9772
 *
Packit Service 5a9772
 * @context: current session server's rdpContext instance.
Packit Service 5a9772
 * @info: pointer to per-session data.
Packit Service 5a9772
 */
Packit Service 5a9772
static BOOL pf_modules_set_plugin_data(const char* plugin_name, proxyData* pdata, void* data)
Packit Service 5a9772
{
Packit Service 5a9772
	union {
Packit Service 5a9772
		const char* ccp;
Packit Service 5a9772
		char* cp;
Packit Service 5a9772
	} ccharconv;
Packit Service 5a9772
Packit Service 5a9772
	assert(plugin_name);
Packit Service 5a9772
Packit Service 5a9772
	ccharconv.ccp = plugin_name;
Packit Service 5a9772
	if (data == NULL) /* no need to store anything */
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (HashTable_Add(pdata->modules_info, ccharconv.cp, data) < 0)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "[%s]: HashTable_Add failed!");
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/*
Packit Service 5a9772
 * returns per-session data needed a plugin.
Packit Service 5a9772
 *
Packit Service 5a9772
 * @context: current session server's rdpContext instance.
Packit Service 5a9772
 * if there's no data related to `plugin_name` in `context` (current session), a NULL will be
Packit Service 5a9772
 * returned.
Packit Service 5a9772
 */
Packit Service 5a9772
static void* pf_modules_get_plugin_data(const char* plugin_name, proxyData* pdata)
Packit Service 5a9772
{
Packit Service 5a9772
	union {
Packit Service 5a9772
		const char* ccp;
Packit Service 5a9772
		char* cp;
Packit Service 5a9772
	} ccharconv;
Packit Service 5a9772
	assert(plugin_name);
Packit Service 5a9772
	assert(pdata);
Packit Service 5a9772
	ccharconv.ccp = plugin_name;
Packit Service 5a9772
Packit Service 5a9772
	return HashTable_GetItemValue(pdata->modules_info, ccharconv.cp);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void pf_modules_abort_connect(proxyData* pdata)
Packit Service 5a9772
{
Packit Service 5a9772
	assert(pdata);
Packit Service 5a9772
	WLog_DBG(TAG, "%s is called!", __FUNCTION__);
Packit Service 5a9772
	proxy_data_abort_connect(pdata);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL pf_modules_register_plugin(proxyPlugin* plugin_to_register)
Packit Service 5a9772
{
Packit Service 5a9772
	int index;
Packit Service 5a9772
	proxyPlugin* plugin;
Packit Service 5a9772
Packit Service 5a9772
	if (!plugin_to_register)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	/* make sure there's no other loaded plugin with the same name of `plugin_to_register`. */
Packit Service 5a9772
	ArrayList_ForEach(plugins_list, proxyPlugin*, index, plugin)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (strcmp(plugin->name, plugin_to_register->name) == 0)
Packit Service 5a9772
		{
Packit Service 5a9772
			WLog_ERR(TAG, "can not register plugin '%s', it is already registered!", plugin->name);
Packit Service 5a9772
			return FALSE;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (ArrayList_Add(plugins_list, plugin_to_register) < 0)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "[%s]: failed adding plugin to list: %s", __FUNCTION__,
Packit Service 5a9772
		         plugin_to_register->name);
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL pf_modules_is_plugin_loaded(const char* plugin_name)
Packit Service 5a9772
{
Packit Service 5a9772
	int i;
Packit Service 5a9772
	proxyPlugin* plugin;
Packit Service 5a9772
Packit Service 5a9772
	if (plugins_list == NULL)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	ArrayList_ForEach(plugins_list, proxyPlugin*, i, plugin)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (strcmp(plugin->name, plugin_name) == 0)
Packit Service 5a9772
			return TRUE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
void pf_modules_list_loaded_plugins(void)
Packit Service 5a9772
{
Packit Service 5a9772
	size_t count;
Packit Service 5a9772
	int i;
Packit Service 5a9772
	proxyPlugin* plugin;
Packit Service 5a9772
Packit Service 5a9772
	if (plugins_list == NULL)
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	count = (size_t)ArrayList_Count(plugins_list);
Packit Service 5a9772
Packit Service 5a9772
	if (count > 0)
Packit Service 5a9772
		WLog_INFO(TAG, "Loaded plugins:");
Packit Service 5a9772
Packit Service 5a9772
	ArrayList_ForEach(plugins_list, proxyPlugin*, i, plugin)
Packit Service 5a9772
	{
Packit Service 5a9772
Packit Service 5a9772
		WLog_INFO(TAG, "\tName: %s", plugin->name);
Packit Service 5a9772
		WLog_INFO(TAG, "\tDescription: %s", plugin->description);
Packit Service 5a9772
	}
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static proxyPluginsManager plugins_manager = { pf_modules_register_plugin,
Packit Service 5a9772
	                                           pf_modules_set_plugin_data,
Packit Service 5a9772
	                                           pf_modules_get_plugin_data,
Packit Service 5a9772
	                                           pf_modules_abort_connect };
Packit Service 5a9772
Packit Service 5a9772
static BOOL pf_modules_load_module(const char* module_path)
Packit Service 5a9772
{
Packit Service 5a9772
	HMODULE handle = NULL;
Packit Service 5a9772
	moduleEntryPoint pEntryPoint;
Packit Service 5a9772
	handle = LoadLibraryA(module_path);
Packit Service 5a9772
Packit Service 5a9772
	if (handle == NULL)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "[%s]: failed loading external library: %s", __FUNCTION__, module_path);
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (!(pEntryPoint = (moduleEntryPoint)GetProcAddress(handle, MODULE_ENTRY_POINT)))
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "[%s]: GetProcAddress failed while loading %s", __FUNCTION__, module_path);
Packit Service 5a9772
		goto error;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (!pEntryPoint(&plugins_manager))
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "[%s]: module %s entry point failed!", __FUNCTION__, module_path);
Packit Service 5a9772
		goto error;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	/* save module handle for freeing the module later */
Packit Service 5a9772
	if (ArrayList_Add(handles_list, handle) < 0)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "ArrayList_Add failed!");
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
Packit Service 5a9772
error:
Packit Service 5a9772
	FreeLibrary(handle);
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL pf_modules_init(const char* root_dir, const char** modules, size_t count)
Packit Service 5a9772
{
Packit Service 5a9772
	size_t i;
Packit Service 5a9772
Packit Service 5a9772
	if (!PathFileExistsA(root_dir))
Packit Service 5a9772
	{
Packit Service 5a9772
		if (!CreateDirectoryA(root_dir, NULL))
Packit Service 5a9772
		{
Packit Service 5a9772
			WLog_ERR(TAG, "error occurred while creating modules directory: %s", root_dir);
Packit Service 5a9772
			return FALSE;
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	WLog_DBG(TAG, "modules root directory: %s", root_dir);
Packit Service 5a9772
Packit Service 5a9772
	plugins_list = ArrayList_New(FALSE);
Packit Service 5a9772
Packit Service 5a9772
	if (plugins_list == NULL)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "[%s]: ArrayList_New failed!", __FUNCTION__);
Packit Service 5a9772
		goto error;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	handles_list = ArrayList_New(FALSE);
Packit Service 5a9772
	if (handles_list == NULL)
Packit Service 5a9772
	{
Packit Service 5a9772
Packit Service 5a9772
		WLog_ERR(TAG, "[%s]: ArrayList_New failed!", __FUNCTION__);
Packit Service 5a9772
		goto error;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	for (i = 0; i < count; i++)
Packit Service 5a9772
	{
Packit Service 5a9772
		char* fullpath = GetCombinedPath(root_dir, modules[i]);
Packit Service 5a9772
		pf_modules_load_module(fullpath);
Packit Service 5a9772
		free(fullpath);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
Packit Service 5a9772
error:
Packit Service 5a9772
	ArrayList_Free(plugins_list);
Packit Service 5a9772
	plugins_list = NULL;
Packit Service 5a9772
	ArrayList_Free(handles_list);
Packit Service 5a9772
	handles_list = NULL;
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
void pf_modules_free(void)
Packit Service 5a9772
{
Packit Service 5a9772
	int index;
Packit Service 5a9772
Packit Service 5a9772
	if (plugins_list)
Packit Service 5a9772
	{
Packit Service 5a9772
		proxyPlugin* plugin;
Packit Service 5a9772
Packit Service 5a9772
		ArrayList_ForEach(plugins_list, proxyPlugin*, index, plugin)
Packit Service 5a9772
		{
Packit Service 5a9772
			if (!IFCALLRESULT(TRUE, plugin->PluginUnload))
Packit Service 5a9772
				WLog_WARN(TAG, "PluginUnload failed for plugin '%s'", plugin->name);
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		ArrayList_Free(plugins_list);
Packit Service 5a9772
		plugins_list = NULL;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (handles_list)
Packit Service 5a9772
	{
Packit Service 5a9772
		HANDLE handle;
Packit Service 5a9772
Packit Service 5a9772
		ArrayList_ForEach(handles_list, HANDLE, index, handle)
Packit Service 5a9772
		{
Packit Service 5a9772
			if (handle)
Packit Service 5a9772
				FreeLibrary(handle);
Packit Service 5a9772
		};
Packit Service 5a9772
Packit Service 5a9772
		ArrayList_Free(handles_list);
Packit Service 5a9772
		handles_list = NULL;
Packit Service 5a9772
	}
Packit Service 5a9772
}