Refactored proxy and proxy-modules:

* Split out proxy headers and moved to public API to allow external
  modules to be built.
* Split proxy into proxy library and proxy binary. The library
  can be used by other applications and provides a simple API
* Improved channel passthrough, now all channels including dynamic
  channels work.
* Extended module API to hook more events, improved module samples
* Cleaned up proxy code, removed global static variables used,
  added WINPR_ASSERT
This commit is contained in:
Armin Novak 2021-08-24 12:50:13 +02:00 committed by akallabeth
parent 81a2f9e434
commit 976c3c2ab9
52 changed files with 4575 additions and 1460 deletions

View File

@ -882,7 +882,7 @@ set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp${FREERDP_VERSIO
# Proxy plugins path
if(NOT DEFINED PROXY_PLUGINDIR)
message("using default plugins location")
set(FREERDP_PROXY_PLUGINDIR "${PROJECT_BINARY_DIR}/server/proxy/plugins")
set(FREERDP_PROXY_PLUGINDIR "${FREERDP_PLUGIN_PATH}/proxy/")
else()
set(FREERDP_PROXY_PLUGINDIR "${PROXY_PLUGINDIR}")
endif()

View File

@ -34,7 +34,7 @@
#include <freerdp/client/rdpsnd.h>
#include "rdpsnd_main.h"
#include "../../../../server/proxy/pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
typedef struct rdpsnd_proxy_plugin rdpsndProxyPlugin;

View File

@ -1,6 +1,7 @@
message("PRELOADING windows cache")
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
set (WITH_SERVER "ON" CACHE BOOL "Build server binaries")
set (WITH_PROXY_MODULES "OFF" CACHE BOOL "Do not build proxy modules")
set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection")
set (BUILD_TESTING ON CACHE BOOL "build testing")
set (WITH_SANITIZE_ADDRESS ON)

View File

@ -0,0 +1,185 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2021 Armin Novak <armin.novak@thincast.com>
* Copyright 2021 Thincast Technologies GmbH
*
* 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_CONFIG_H
#define FREERDP_SERVER_PROXY_CONFIG_H
#include <winpr/wtypes.h>
#include <winpr/ini.h>
#include <freerdp/api.h>
typedef struct proxy_config proxyConfig;
struct proxy_config
{
/* server */
char* Host;
UINT16 Port;
/* target */
BOOL FixedTarget;
char* TargetHost;
UINT16 TargetPort;
/* input */
BOOL Keyboard;
BOOL Mouse;
/* server security */
BOOL ServerTlsSecurity;
BOOL ServerRdpSecurity;
BOOL ServerNlaSecurity;
/* client security */
BOOL ClientNlaSecurity;
BOOL ClientTlsSecurity;
BOOL ClientRdpSecurity;
BOOL ClientAllowFallbackToTls;
/* channels */
BOOL GFX;
BOOL DisplayControl;
BOOL Clipboard;
BOOL AudioOutput;
BOOL RemoteApp;
BOOL PassthroughIsBlacklist;
char** Passthrough;
size_t PassthroughCount;
/* clipboard specific settings */
BOOL TextOnly;
UINT32 MaxTextLength;
/* gfx settings */
BOOL DecodeGFX;
/* modules */
char** Modules; /* module file names to load */
size_t ModulesCount;
char** RequiredPlugins; /* required plugin names */
size_t RequiredPluginsCount;
char* CertificateFile;
char* CertificateContent;
char* PrivateKeyFile;
char* PrivateKeyContent;
char* RdpKeyFile;
char* RdpKeyContent;
};
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief server_config_load_ini Create a proxyConfig from a already loaded
* INI file.
*
* @param ini A pointer to the parsed INI file. Must NOT be NULL.
*
* @return A proxyConfig or NULL in case of failure.
*/
FREERDP_API proxyConfig* server_config_load_ini(wIniFile* ini);
/**
* @brief pf_server_config_load_file Create a proxyConfig from a INI file found at path.
*
* @param path The path of the INI file
*
* @return A proxyConfig or NULL in case of failure.
*/
FREERDP_API proxyConfig* pf_server_config_load_file(const char* path);
/**
* @brief pf_server_config_load_buffer Create a proxyConfig from a memory string buffer in INI
* file format
*
* @param buffer A pointer to the '\0' terminated INI string.
*
* @return A proxyConfig or NULL in case of failure.
*/
FREERDP_API proxyConfig* pf_server_config_load_buffer(const char* buffer);
/**
* @brief pf_server_config_print Print the configuration to stdout
*
* @param config A pointer to the configuration to print. Must NOT be NULL.
*/
FREERDP_API void pf_server_config_print(const proxyConfig* config);
/**
* @brief pf_server_config_free Releases all resources associated with proxyConfig
*
* @param config A pointer to the proxyConfig to clean up. Might be NULL.
*/
FREERDP_API void pf_server_config_free(proxyConfig* config);
/**
* @brief pf_config_required_plugins_count
*
* @param config A pointer to the proxyConfig. Must NOT be NULL.
*
* @return The number of required plugins configured.
*/
FREERDP_API size_t pf_config_required_plugins_count(const proxyConfig* config);
/**
* @brief pf_config_required_plugin
* @param config A pointer to the proxyConfig. Must NOT be NULL.
* @param index The index of the plugin to return
*
* @return The name of the plugin or NULL.
*/
FREERDP_API const char* pf_config_required_plugin(const proxyConfig* config, size_t index);
/**
* @brief pf_config_modules_count
*
* @param config A pointer to the proxyConfig. Must NOT be NULL.
*
* @return The number of proxy modules configured.
*/
FREERDP_API size_t pf_config_modules_count(const proxyConfig* config);
/**
* @brief pf_config_modules
* @param config A pointer to the proxyConfig. Must NOT be NULL.
*
* @return An array of strings of size pf_config_modules_count with the module names.
*/
FREERDP_API const char** pf_config_modules(const proxyConfig* config);
/**
* @brief pf_config_clone Create a copy of the configuration
* @param dst A pointer that receives the newly allocated copy
* @param config The source configuration to copy
*
* @return TRUE for success, FALSE otherwise
*/
FREERDP_API BOOL pf_config_clone(proxyConfig** dst, const proxyConfig* config);
#ifdef __cplusplus
};
#endif
#endif /* FREERDP_SERVER_PROXY_CONFIG_H */

View File

@ -34,12 +34,13 @@
#include <freerdp/server/cliprdr.h>
#include <freerdp/server/rdpsnd.h>
#include "pf_config.h"
#include "pf_server.h"
#include <freerdp/server/proxy/proxy_config.h>
#define PROXY_SESSION_ID_LENGTH 32
typedef struct proxy_data proxyData;
typedef struct proxy_module proxyModule;
typedef struct channel_data_event_info proxyChannelDataEventInfo;
/**
* Wraps rdpContext and holds the state for the proxy's server.
@ -58,15 +59,14 @@ struct p_server_context
DispServerContext* disp;
CliprdrServerContext* cliprdr;
RdpsndServerContext* rdpsnd;
HANDLE* vc_handles; /* static virtual channels open handles */
wHashTable* vc_ids; /* channel_name -> channel_id map */
};
typedef struct p_server_context pServerContext;
/**
* Wraps rdpContext and holds the state for the proxy's client.
*/
typedef struct p_client_context pClientContext;
struct p_client_context
{
rdpContext context;
@ -91,16 +91,26 @@ struct p_client_context
*/
BOOL allow_next_conn_failure;
wHashTable* vc_ids; /* channel_name -> channel_id map */
BOOL connected; /* Set after client post_connect. */
pReceiveChannelData client_receive_channel_data_original;
wArrayList* cached_server_channel_data;
BOOL (*sendChannelData)(pClientContext* pc, const proxyChannelDataEventInfo* ev);
/* X509 specific */
char* remote_hostname;
wStream* remote_pem;
UINT16 remote_port;
UINT32 remote_flags;
};
typedef struct p_client_context pClientContext;
/**
* Holds data common to both sides of a proxy's session.
*/
struct proxy_data
{
proxyConfig* config;
proxyModule* module;
const proxyConfig* config;
pServerContext* ps;
pClientContext* pc;
@ -113,6 +123,7 @@ struct proxy_data
/* used to external modules to store per-session info */
wHashTable* modules_info;
psPeerReceiveChannelData server_receive_channel_data_original;
};
BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src);

View File

@ -19,8 +19,8 @@
* limitations under the License.
*/
#ifndef FREERDP_SERVER_PROXY_PFLOG_H
#define FREERDP_SERVER_PROXY_PFLOG_H
#ifndef FREERDP_SERVER_PROXY_LOG_H
#define FREERDP_SERVER_PROXY_LOG_H
#include <winpr/wlog.h>
@ -34,17 +34,17 @@
*/
/* log macros that prepends session id and function name tp the log message */
#define LOG_INFO(_tag, _context, _format, ...) \
#define PROXY_LOG_INFO(_tag, _context, _format, ...) \
WLog_INFO(TAG, "[SessionID=%s][%s]: " _format, _context->pdata->session_id, __FUNCTION__, \
##__VA_ARGS__)
#define LOG_ERR(_tag, _context, _format, ...) \
#define PROXY_LOG_ERR(_tag, _context, _format, ...) \
WLog_ERR(TAG, "[SessionID=%s][%s]: " _format, _context->pdata->session_id, __FUNCTION__, \
##__VA_ARGS__)
#define LOG_DBG(_tag, _context, _format, ...) \
#define PROXY_LOG_DBG(_tag, _context, _format, ...) \
WLog_DBG(TAG, "[SessionID=%s][%s]: " _format, _context->pdata->session_id, __FUNCTION__, \
##__VA_ARGS__)
#define LOG_WARN(_tag, _context, _format, ...) \
#define PROXY_LOG_WARN(_tag, _context, _format, ...) \
WLog_WARN(TAG, "[SessionID=%s][%s]: " _format, _context->pdata->session_id, __FUNCTION__, \
##__VA_ARGS__)
#endif /* FREERDP_SERVER_PROXY_PFLOG_H */
#endif /* FREERDP_SERVER_PROXY_LOG_H */

View File

@ -0,0 +1,187 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
*
* 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_MODULES_API_H
#define FREERDP_SERVER_PROXY_MODULES_API_H
#include <freerdp/freerdp.h>
#include <winpr/winpr.h>
#include <winpr/sspi.h>
#define MODULE_TAG(module) "proxy.modules." module
typedef struct proxy_data proxyData;
typedef struct proxy_module proxyModule;
typedef struct proxy_plugin proxyPlugin;
typedef struct proxy_plugins_manager proxyPluginsManager;
/* hook callback. should return TRUE on success or FALSE on error. */
typedef BOOL (*proxyHookFn)(proxyPlugin*, proxyData*, void*);
/*
* Filter callback:
* It MUST return TRUE if the related event should be proxied,
* or FALSE if it should be ignored.
*/
typedef BOOL (*proxyFilterFn)(proxyPlugin*, proxyData*, void*);
/* describes a plugin: name, description and callbacks to execute.
*
* This is public API, so always add new fields at the end of the struct to keep
* some backward compatibility.
*/
struct proxy_plugin
{
const char* name; /* 0: unique module name */
const char* description; /* 1: module description */
UINT64 reserved1[32 - 2]; /* 2-32 */
BOOL (*PluginUnload)(proxyPlugin* plugin); /* 33 */
UINT64 reserved2[66 - 34]; /* 34 - 65 */
/* proxy hooks. a module can set these function pointers to register hooks */
proxyHookFn ClientInitConnect; /* 66 custom=rdpContext* */
proxyHookFn ClientUninitConnect; /* 67 custom=rdpContext* */
proxyHookFn ClientPreConnect; /* 68 custom=rdpContext* */
proxyHookFn ClientPostConnect; /* 69 custom=rdpContext* */
proxyHookFn ClientPostDisconnect; /* 70 custom=rdpContext* */
proxyHookFn ClientX509Certificate; /* 71 custom=rdpContext* */
proxyHookFn ClientLoginFailure; /* 72 custom=rdpContext* */
proxyHookFn ClientEndPaint; /* 73 custom=rdpContext* */
UINT64 reserved3[96 - 74]; /* 74-95 */
proxyHookFn ServerPostConnect; /* 96 custom=freerdp_peer* */
proxyHookFn ServerPeerActivate; /* 97 custom=freerdp_peer* */
proxyHookFn ServerChannelsInit; /* 98 custom=freerdp_peer* */
proxyHookFn ServerChannelsFree; /* 99 custom=freerdp_peer* */
proxyHookFn ServerSessionEnd; /* 100 custom=freerdp_peer* */
UINT64 reserved4[128 - 101]; /* 101 - 127 */
/* proxy filters. a module can set these function pointers to register filters */
proxyFilterFn KeyboardEvent; /* 128 */
proxyFilterFn MouseEvent; /* 129 */
proxyFilterFn ClientChannelData; /* 130 passthrough channels data */
proxyFilterFn ServerChannelData; /* 131 passthrough channels data */
proxyFilterFn DynamicChannelCreate; /* 132 passthrough drdynvc channel create data */
proxyFilterFn ServerFetchTargetAddr; /* 133 */
proxyFilterFn ServerPeerLogon; /* 134 */
UINT64 reserved5[160 - 135]; /* 135-159 */
/* Runtime data fields */
proxyPluginsManager* mgr; /* 160 */ /** Set during plugin registration */
void* userdata; /* 161 */ /** Custom data provided with RegisterPlugin, memory managed
outside of plugin. */
void* custom; /* 162 */ /** Custom configuration data, must be allocated in RegisterPlugin and
freed in PluginUnload */
UINT64 reserved6[192 - 163]; /* 163-191 Add some filler data to allow for new callbacks or
* fields without breaking API */
};
/*
* Main API for use by external modules.
* Supports:
* - Registering a plugin.
* - Setting/getting plugin's per-session specific data.
* - Aborting a session.
*/
struct proxy_plugins_manager
{
/* 0 used for registering a fresh new proxy plugin. */
BOOL(*RegisterPlugin)
(struct proxy_plugins_manager* mgr, const proxyPlugin* plugin);
/* 1 used for setting plugin's per-session info. */
BOOL (*SetPluginData)(struct proxy_plugins_manager* mgr, const char*, proxyData*, void*);
/* 2 used for getting plugin's per-session info. */
void* (*GetPluginData)(struct proxy_plugins_manager* mgr, const char*, proxyData*);
/* 3 used for aborting a session. */
void (*AbortConnect)(struct proxy_plugins_manager* mgr, proxyData*);
UINT64 reserved[128 - 4]; /* 4-127 reserved fields */
};
typedef BOOL (*proxyModuleEntryPoint)(proxyPluginsManager* plugins_manager, void* userdata);
/* filter events parameters */
#define WINPR_PACK_PUSH
#include <winpr/pack.h>
typedef struct proxy_keyboard_event_info
{
UINT16 flags;
UINT16 rdp_scan_code;
} proxyKeyboardEventInfo;
typedef struct proxy_mouse_event_info
{
UINT16 flags;
UINT16 x;
UINT16 y;
} proxyMouseEventInfo;
typedef struct channel_data_event_info
{
/* channel metadata */
const char* channel_name;
UINT16 channel_id;
/* actual data */
const BYTE* data;
size_t data_len;
size_t total_size;
UINT32 flags;
} proxyChannelDataEventInfo;
typedef enum proxy_fetch_target_method
{
PROXY_FETCH_TARGET_METHOD_DEFAULT,
PROXY_FETCH_TARGET_METHOD_CONFIG,
PROXY_FETCH_TARGET_METHOD_LOAD_BALANCE_INFO,
PROXY_FETCH_TARGET_USE_CUSTOM_ADDR
} ProxyFetchTargetMethod;
typedef struct fetch_target_event_info
{
/* out values */
char* target_address;
UINT16 target_port;
/*
* If this value is set to true by a plugin, target info will be fetched from config and proxy
* will connect any client to the same remote server.
*/
ProxyFetchTargetMethod fetch_method;
} proxyFetchTargetEventInfo;
typedef struct server_peer_logon
{
const SEC_WINNT_AUTH_IDENTITY* identity;
BOOL automatic;
} proxyServerPeerLogon;
#define WINPR_PACK_POP
#include <winpr/pack.h>
#endif /* FREERDP_SERVER_PROXY_MODULES_API_H */

View File

@ -0,0 +1,114 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2021 Armin Novak <armin.novak@thincast.com>
* Copyright 2021 Thincast Technologies GmbH
*
* 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_SERVER_H
#define FREERDP_SERVER_PROXY_SERVER_H
#include <freerdp/api.h>
#include <freerdp/server/proxy/proxy_config.h>
#include <freerdp/server/proxy/proxy_modules_api.h>
typedef struct proxy_server proxyServer;
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief pf_server_new Creates a new proxy server instance
*
* @param config The proxy server configuration to use. Must NOT be NULL.
*
* @return A new proxy server instance or NULL on failure.
*/
FREERDP_API proxyServer* pf_server_new(const proxyConfig* config);
/**
* @brief pf_server_free Cleans up a (stopped) proxy server instance.
*
* @param server The proxy server to clean up. Might be NULL.
*/
FREERDP_API void pf_server_free(proxyServer* server);
/**
* @brief pf_server_add_module Allows registering proxy modules that are
* build-in instead of shipped as separate
* module loaded at runtime.
*
* @param server A proxy instance to add the module to. Must NOT be NULL
* @param ep The proxy entry function to add. Must NOT be NULL
* @param userdata Custom data for the module. May be NULL
*
* @return TRUE for success, FALSE otherwise.
*/
FREERDP_API BOOL pf_server_add_module(proxyServer* server, proxyModuleEntryPoint ep,
void* userdata);
/**
* @brief pf_server_start Starts the proxy, binding the configured port.
*
* @param server The server instance. Must NOT be NULL.
*
* @return TRUE for success, FALSE on error
*/
FREERDP_API BOOL pf_server_start(proxyServer* server);
/**
* @brief pf_server_start_from_socket Starts the proxy using an existing bound socket
*
* @param server The server instance. Must NOT be NULL.
* @param socket The bound socket to wait for events on.
*
* @return TRUE for success, FALSE on error
*/
FREERDP_API BOOL pf_server_start_from_socket(proxyServer* server, int socket);
/**
* @brief pf_server_start_with_peer_socket Use existing peer socket
*
* @param server The server instance. Must NOT be NULL.
* @param socket Ready to use peer socket
*
* @return TRUE for success, FALSE on error
*/
FREERDP_API BOOL pf_server_start_with_peer_socket(proxyServer* server, int socket);
/**
* @brief pf_server_stop Stops a server instance asynchronously.
* Can be called from any thread to stop a running server instance.
* @param server A pointer to the server instance to stop. May be NULL.
*/
FREERDP_API void pf_server_stop(proxyServer* server);
/**
* @brief pf_server_run This (blocking) function runs the main loop of the
* proxy.
*
* @param server The server instance. Must NOT be NULL.
*
* @return TRUE for successful termination, FALSE otherwise.
*/
FREERDP_API BOOL pf_server_run(proxyServer* server);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_SERVER_PROXY_SERVER_H */

View File

@ -329,7 +329,6 @@ BOOL freerdp_peer_set_local_and_hostname(freerdp_peer* client,
return TRUE;
}
static BOOL freerdp_listener_check_fds(freerdp_listener* instance)
{
int i;

View File

@ -893,6 +893,7 @@ BOOL tls_accept(rdpTls* tls, BIO* underlying, rdpSettings* settings)
BIO* bio;
EVP_PKEY* privkey;
X509* x509;
/**
* SSL_OP_NO_SSLv2:
*

View File

@ -18,13 +18,11 @@
# limitations under the License.
include(CMakeDependentOption)
set(MODULE_NAME "freerdp-proxy")
set(MODULE_NAME "freerdp-server-proxy")
set(MODULE_PREFIX "FREERDP_SERVER_PROXY")
set(${MODULE_PREFIX}_SRCS
freerdp_proxy.c
pf_context.c
pf_context.h
pf_channels.c
pf_channels.h
pf_client.c
@ -44,18 +42,19 @@ set(${MODULE_PREFIX}_SRCS
pf_gdi.c
pf_gdi.h
pf_config.c
pf_config.h
pf_graphics.c
pf_graphics.h
pf_modules.c
pf_modules.h
pf_cliprdr.c
pf_cliprdr.h
pf_rdpsnd.c
pf_rdpsnd.h
pf_log.h
pf_utils.h
pf_utils.c
)
set(PROXY_APP_SRCS freerdp_proxy.c)
# On windows create dll version information.
# Vendor, product and year are already set in top level CMakeLists.txt
if (WIN32)
@ -70,24 +69,61 @@ if (WIN32)
@ONLY)
set ( ${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
list(APPEND PROXY_APP_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif()
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME ${MODULE_NAME}${FREERDP_API_VERSION})
if (WITH_LIBRARY_VERSIONING)
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION})
endif()
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rdpgfx-client)
if (NOT BUILTIN_CHANNELS)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rdpgfx-client)
get_target_property(CUR_INSTALL_RPATH ${MODULE_NAME} INSTALL_RPATH)
if (NOT APPLE)
set(CUR_INSTALL_RPATH "${CUR_INSTALL_RPATH}:\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}")
endif()
set_target_properties(${MODULE_NAME} PROPERTIES INSTALL_RPATH ${CUR_INSTALL_RPATH})
endif()
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server)
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT server EXPORT FreeRDP-ProxyTargets)
if (WITH_DEBUG_SYMBOLS AND MSVC)
install(FILES ${CMAKE_PDB_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT symbols)
install(FILES ${CMAKE_PDB_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT symbols)
endif()
# pkg-config
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp-proxy.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp-server-proxy${FREERDP_VERSION_MAJOR}.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp-server-proxy${FREERDP_VERSION_MAJOR}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
export(PACKAGE freerdp-proxy)
SetFreeRDPCMakeInstallDir(FREERDP_PROXY_CMAKE_INSTALL_DIR "FreeRDP-Proxy${FREERDP_VERSION_MAJOR}")
configure_package_config_file(FreeRDP-ProxyConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ProxyConfig.cmake
INSTALL_DESTINATION ${FREERDP_PROXY_CMAKE_INSTALL_DIR}
PATH_VARS FREERDP_INCLUDE_DIR)
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ProxyConfigVersion.cmake
VERSION ${FREERDP_VERSION} COMPATIBILITY SameMajorVersion)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ProxyConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ProxyConfigVersion.cmake
DESTINATION ${FREERDP_PROXY_CMAKE_INSTALL_DIR})
install(EXPORT FreeRDP-ProxyTargets DESTINATION ${FREERDP_PROXY_CMAKE_INSTALL_DIR})
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/proxy")
CMAKE_DEPENDENT_OPTION(WITH_PROXY_MODULES "Compile proxy modules" OFF "WITH_PROXY" OFF)
option(WITH_PROXY_APP "Compile proxy application" ON)
if (WITH_PROXY_APP)
add_subdirectory("cli")
endif()
option(WITH_PROXY_MODULES "Compile proxy modules" ON)
if (WITH_PROXY_MODULES)
add_subdirectory("modules")
endif()

View File

@ -0,0 +1,10 @@
@PACKAGE_INIT@
set(FreeRDP-Proxy_VERSION_MAJOR "@FREERDP_VERSION_MAJOR@")
set(FreeRDP-Proxy_VERSION_MINOR "@FREERDP_VERSION_MINOR@")
set(FreeRDP-Proxy_VERSION_REVISION "@FREERDP_VERSION_REVISION@")
set_and_check(FreeRDP-Proxy_INCLUDE_DIR "@PACKAGE_FREERDP_INCLUDE_DIR@")
include("${CMAKE_CURRENT_LIST_DIR}/FreeRDP-ProxyTargets.cmake")

View File

@ -0,0 +1,46 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP Proxy Server
#
# Copyright 2021 Armin Novak <armin.novak@thincast.com>
# Copyright 2021 Thincast Technologies GmbH
#
# 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.
set(PROXY_APP_SRCS freerdp_proxy.c)
# On windows create dll version information.
# Vendor, product and year are already set in top level CMakeLists.txt
if (WIN32)
set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR})
set (RC_VERSION_MINOR ${FREERDP_VERSION_MINOR})
set (RC_VERSION_BUILD ${FREERDP_VERSION_REVISION})
set (RC_VERSION_FILE "${MODULE_NAME}${CMAKE_EXECUTABLE_SUFFIX}" )
configure_file(
${PROJECT_SOURCE_DIR}/cmake/WindowsDLLVersion.rc.in
${CMAKE_CURRENT_BINARY_DIR}/version.rc
@ONLY)
list(APPEND PROXY_APP_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif()
set(APP_NAME "freerdp-proxy")
add_executable(${APP_NAME}
${PROXY_APP_SRCS})
target_link_libraries(${APP_NAME} ${MODULE_NAME})
install(TARGETS ${APP_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server)
if (WITH_DEBUG_SYMBOLS AND MSVC)
install(FILES ${CMAKE_PDB_BINARY_DIR}/${APP_NAME}.pdb DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT symbols)
endif()
set_property(TARGET ${APP_NAME} PROPERTY FOLDER "Server/proxy")

View File

@ -19,14 +19,14 @@
* limitations under the License.
*/
#include "pf_server.h"
#include "pf_config.h"
#include "pf_log.h"
#include "pf_modules.h"
#include <winpr/collections.h>
#include <freerdp/version.h>
#include <freerdp/build-config.h>
#include <winpr/collections.h>
#include <freerdp/freerdp.h>
#include <freerdp/server/proxy/proxy_server.h>
#include <freerdp/server/proxy/proxy_log.h>
#include <stdlib.h>
#include <signal.h>
@ -34,22 +34,29 @@
static proxyServer* server = NULL;
static WINPR_NORETURN(void cleanup_handler(int signum))
#if defined(_WIN32)
static const char* strsignal(int signum)
{
switch (signum)
{
case SIGINT:
return "SIGINT";
case SIGTERM:
return "SIGTERM";
default:
return "UNKNOWN";
}
}
#endif
static void cleanup_handler(int signum)
{
printf("\n");
WLog_INFO(TAG, "[%s]: caught signal %d, starting cleanup...", __FUNCTION__, signum);
WLog_INFO(TAG, "[%s]: caught signal %s [%d], starting cleanup...", __FUNCTION__,
strsignal(signum), signum);
WLog_INFO(TAG, "stopping all connections.");
pf_server_stop(server);
WLog_INFO(TAG, "freeing loaded modules and plugins.");
pf_modules_free();
pf_server_config_free(server->config);
pf_server_free(server);
WLog_INFO(TAG, "exiting.");
exit(0);
}
static void pf_server_register_signal_handlers(void)
@ -62,30 +69,14 @@ static void pf_server_register_signal_handlers(void)
#endif
}
static BOOL is_all_required_modules_loaded(proxyConfig* config)
{
size_t i;
for (i = 0; i < config->RequiredPluginsCount; i++)
{
const char* plugin_name = config->RequiredPlugins[i];
if (!pf_modules_is_plugin_loaded(plugin_name))
{
WLog_ERR(TAG, "Required plugin '%s' is not loaded. stopping.", plugin_name);
return FALSE;
}
}
return TRUE;
}
int main(int argc, char* argv[])
{
proxyConfig* config = NULL;
char* config_path = "config.ini";
int status = -1;
pf_server_register_signal_handlers();
WLog_INFO(TAG, "freerdp-proxy version info:");
WLog_INFO(TAG, "\tFreeRDP version: %s", FREERDP_VERSION_FULL);
WLog_INFO(TAG, "\tGit commit: %s", FREERDP_GIT_REVISION);
@ -94,25 +85,12 @@ int main(int argc, char* argv[])
if (argc >= 2)
config_path = argv[1];
config = pf_server_config_load(config_path);
config = pf_server_config_load_file(config_path);
if (!config)
goto fail;
pf_server_config_print(config);
if (!pf_modules_init(FREERDP_PROXY_PLUGINDIR, (const char**)config->Modules,
config->ModulesCount))
{
WLog_ERR(TAG, "failed to initialize proxy modules!");
goto fail;
}
pf_modules_list_loaded_plugins();
if (!is_all_required_modules_loaded(config))
goto fail;
pf_server_register_signal_handlers();
server = pf_server_new(config);
if (!server)
goto fail;
@ -120,13 +98,14 @@ int main(int argc, char* argv[])
if (!pf_server_start(server))
goto fail;
if (WaitForSingleObject(server->thread, INFINITE) != WAIT_OBJECT_0)
if (!pf_server_run(server))
goto fail;
status = 0;
fail:
pf_server_free(server);
pf_modules_free();
pf_server_config_free(config);
return status;
}

View File

@ -0,0 +1,16 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=${prefix}/@FREERDP_INCLUDE_DIR@
libs=-lfreerdp-server-proxy@FREERDP_API_VERSION@
Name: FreeRDP proxy
Description: FreeRDP: A Remote Desktop Protocol Implementation
URL: http://www.freerdp.com/
Version: @FREERDP_VERSION@
Requires:
Requires.private: @WINPR_PKG_CONFIG_FILENAME@ freerdp@FREERDP_VERSION_MAJOR@ freerdp-server@FREERDP_VERSION_MAJOR@ freerdp-client@FREERDP_VERSION_MAJOR@
Libs: -L${libdir} ${libs}
Libs.private: -ldl -lpthread
Cflags: -I${includedir}

View File

@ -1,27 +1,66 @@
# Proxy filter API
# Proxy module 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.
`freerdp-proxy` has an API for hooking/filtering certain events/messages.
A module can register callbacks to events, allowing to record the data and control whether to pass/ignore, or right out drop the connection.
During startup, the proxy reads its modules from the configuration:
During startup, the proxy loads its filters from the configuration:
```ini
[Filters]
; FilterName = FilterPath
DemoFilter = "server/proxy/demo.so"
[Plugins]
Modules = demo,cap
```
## Currently supported events
* Mouse event
* Keyboard event
These modules are loaded in a best effort manner. Additionally there is a configuration field for modules that must be loaded,
so the proxy refuses to start if they are not found:
## 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.
```ini
[Plugins]
Required = demo,cap
```
Modules must be installed as shared libraris in the `<base install>/lib/freerdp3/proxy` folder and match the pattern
`proxy-<name>-plugin.<ext>` (e.g. `proxy-demo-plugin.so`) to be found.
For security reasons loading by full path is not supported and only the installation path is used for lookup.
## Currently supported hook events
### Client
* ClientInitConnect: Called before the client tries to open a connection
* ClientUninitConnect: Called after the client has disconnected
* ClientPreConnect: Called in client PreConnect callback
* ClientPostConnect: Called in client PostConnect callback
* ClientPostDisconnect: Called in client PostDisconnect callback
* ClientX509Certificate: Called in client X509 certificate verification callback
* ClientLoginFailure: Called in client login failure callback
* ClientEndPaint: Called in client EndPaint callback
### Server
* ServerPostConnect: Called after a client has connected
* ServerPeerActivate: Called after a client has activated
* ServerChannelsInit: Called after channels are initialized
* ServerChannelsFree: Called after channels are cleaned up
* ServerSessionEnd: Called after the client connection disconnected
## Currently supported filter events
* KeyboardEvent: Keyboard event, e.g. all key press and release events
* MouseEvent: Mouse event, e.g. mouse movement and button press/release events
* ClientChannelData: Client static channel data
* ServerChannelData: Server static channel data
* DynamicChannelCreate: Dynamic channel create
* ServerFetchTargetAddr: Fetch target address (e.g. RDP TargetInfo)
* ServerPeerLogon: A peer is logging on
## Developing a new module
* Create a new file that includes `freerdp/server/proxy/proxy_modules_api.h`.
* Implement the `proxy_module_entry_point` 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.
* Each callback must return a `BOOL`:
* `FALSE`: The event will not be proxied.
* `TRUE`: The event will be proxied.
A demo can be found in `filter_demo.c`.

View File

@ -17,9 +17,11 @@
# limitations under the License.
#
set(PLUGIN_NAME "proxy-capture-plugin")
cmake_minimum_required(VERSION 3.4)
add_library(${PLUGIN_NAME} MODULE
project(proxy-capture-plugin VERSION 1.0.0 LANGUAGES C)
add_library(${PROJECT_NAME} MODULE
cap_main.c
cap_config.c
cap_config.h
@ -27,7 +29,9 @@ add_library(${PLUGIN_NAME} MODULE
cap_protocol.h
)
set_target_properties(${PLUGIN_NAME} PROPERTIES PREFIX "")
set_target_properties(${PLUGIN_NAME} PROPERTIES NO_SONAME 1)
set_target_properties(${PLUGIN_NAME} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${FREERDP_PROXY_PLUGINDIR}")
target_link_libraries(${PROJECT_NAME} winpr)
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
set_target_properties(${PROJECT_NAME} PROPERTIES NO_SONAME 1)
install(TARGETS ${PROJECT_NAME} DESTINATION ${FREERDP_PROXY_PLUGINDIR})

View File

@ -75,7 +75,7 @@ BOOL capture_plugin_init_config(captureConfig* config)
return FALSE;
}
config->port = port;
config->port = (UINT16)port;
free(tmp);
}
else

View File

@ -17,40 +17,41 @@
* limitations under the License.
*/
#define TAG MODULE_TAG("capture")
#define PLUGIN_NAME "capture"
#define PLUGIN_DESC "stream egfx connections over tcp"
#include <errno.h>
#include <winpr/image.h>
#include <freerdp/gdi/gdi.h>
#include <winpr/winsock.h>
#include "pf_log.h"
#include "modules_api.h"
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_modules_api.h>
#include <freerdp/server/proxy/proxy_log.h>
#include <freerdp/server/proxy/proxy_context.h>
#include "cap_config.h"
#include "cap_protocol.h"
#define TAG MODULE_TAG("capture")
#define PLUGIN_NAME "capture"
#define PLUGIN_DESC "stream egfx connections over tcp"
#define BUFSIZE 8092
static proxyPluginsManager* g_plugins_manager = NULL;
static captureConfig config = { 0 };
static SOCKET capture_plugin_init_socket(void)
static SOCKET capture_plugin_init_socket(const captureConfig* cconfig)
{
int status;
int sockfd;
SOCKET sockfd;
struct sockaddr_in addr = { 0 };
WINPR_ASSERT(cconfig);
sockfd = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd == -1)
if (sockfd == (SOCKET)-1)
return -1;
addr.sin_family = AF_INET;
addr.sin_port = htons(config.port);
inet_pton(AF_INET, config.host, &(addr.sin_addr));
addr.sin_port = htons(cconfig->port);
inet_pton(AF_INET, cconfig->host, &(addr.sin_addr));
status = _connect(sockfd, (const struct sockaddr*)&addr, sizeof(addr));
if (status < 0)
@ -64,7 +65,6 @@ static SOCKET capture_plugin_init_socket(void)
static BOOL capture_plugin_send_data(SOCKET sockfd, const BYTE* buffer, size_t len)
{
size_t chunk_len;
int nsent;
if (!buffer)
@ -72,7 +72,7 @@ static BOOL capture_plugin_send_data(SOCKET sockfd, const BYTE* buffer, size_t l
while (len > 0)
{
chunk_len = len > BUFSIZE ? BUFSIZE : len;
int chunk_len = len > BUFSIZE ? BUFSIZE : len;
nsent = _send(sockfd, (const char*)buffer, chunk_len, 0);
if (nsent == -1)
return FALSE;
@ -109,24 +109,32 @@ error:
return result;
}
static SOCKET capture_plugin_get_socket(proxyData* pdata)
static SOCKET capture_plugin_get_socket(proxyPlugin* plugin, proxyData* pdata)
{
void* custom;
custom = g_plugins_manager->GetPluginData(PLUGIN_NAME, pdata);
WINPR_ASSERT(plugin);
WINPR_ASSERT(plugin->mgr);
custom = plugin->mgr->GetPluginData(plugin->mgr, PLUGIN_NAME, pdata);
if (!custom)
return -1;
return (SOCKET)custom;
}
static BOOL capture_plugin_session_end(proxyData* pdata)
static BOOL capture_plugin_session_end(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
SOCKET socket;
BOOL ret;
wStream* s;
socket = capture_plugin_get_socket(pdata);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WINPR_ASSERT(plugin);
WINPR_ASSERT(plugin->mgr);
socket = capture_plugin_get_socket(plugin, pdata);
if (socket == INVALID_SOCKET)
return FALSE;
@ -146,7 +154,11 @@ static BOOL capture_plugin_send_frame(pClientContext* pc, SOCKET socket, const B
BOOL ret = FALSE;
wStream* s = NULL;
BYTE* bmp_header = NULL;
rdpSettings* settings = pc->context.settings;
rdpSettings* settings;
WINPR_ASSERT(pc);
settings = pc->context.settings;
WINPR_ASSERT(settings);
frame_size = settings->DesktopWidth * settings->DesktopHeight * (settings->ColorDepth / 8);
bmp_header = winpr_bitmap_construct_header(settings->DesktopWidth, settings->DesktopHeight,
@ -178,19 +190,24 @@ error:
return ret;
}
static BOOL capture_plugin_client_end_paint(proxyData* pdata)
static BOOL capture_plugin_client_end_paint(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
pClientContext* pc = pdata->pc;
rdpGdi* gdi = pc->context.gdi;
SOCKET socket;
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WINPR_ASSERT(plugin);
WINPR_ASSERT(plugin->mgr);
if (gdi->suppressOutput)
return TRUE;
if (gdi->primary->hdc->hwnd->ninvalid < 1)
return TRUE;
socket = capture_plugin_get_socket(pdata);
socket = capture_plugin_get_socket(plugin, pdata);
if (socket == INVALID_SOCKET)
return FALSE;
@ -205,19 +222,28 @@ static BOOL capture_plugin_client_end_paint(proxyData* pdata)
return TRUE;
}
static BOOL capture_plugin_client_post_connect(proxyData* pdata)
static BOOL capture_plugin_client_post_connect(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
captureConfig* cconfig;
SOCKET socket;
wStream* s;
socket = capture_plugin_init_socket();
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WINPR_ASSERT(plugin);
WINPR_ASSERT(plugin->mgr);
cconfig = plugin->custom;
WINPR_ASSERT(cconfig);
socket = capture_plugin_init_socket(cconfig);
if (socket == INVALID_SOCKET)
{
WLog_ERR(TAG, "failed to establish a connection");
return FALSE;
}
g_plugins_manager->SetPluginData(PLUGIN_NAME, pdata, (void*)socket);
plugin->mgr->SetPluginData(plugin->mgr, PLUGIN_NAME, pdata, (void*)socket);
s = capture_plugin_create_session_info_packet(pdata->pc);
if (!s)
@ -226,11 +252,24 @@ static BOOL capture_plugin_client_post_connect(proxyData* pdata)
return capture_plugin_send_packet(socket, s);
}
static BOOL capture_plugin_server_post_connect(proxyData* pdata)
static BOOL capture_plugin_server_post_connect(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
pServerContext* ps = pdata->ps;
proxyConfig* config = pdata->config;
rdpSettings* settings = ps->context.settings;
pServerContext* ps;
const proxyConfig* config;
rdpSettings* settings;
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
ps = pdata->ps;
WINPR_ASSERT(ps);
config = pdata->config;
WINPR_ASSERT(config);
settings = ps->context.settings;
WINPR_ASSERT(settings);
if (!config->GFX || !config->DecodeGFX)
{
@ -248,41 +287,51 @@ static BOOL capture_plugin_server_post_connect(proxyData* pdata)
return TRUE;
}
static BOOL capture_plugin_unload(void)
static BOOL capture_plugin_unload(proxyPlugin* plugin)
{
capture_plugin_config_free_internal(&config);
if (plugin)
{
captureConfig* cconfig = plugin->custom;
WINPR_ASSERT(cconfig);
capture_plugin_config_free_internal(cconfig);
free(cconfig);
}
return TRUE;
}
static proxyPlugin demo_plugin = {
PLUGIN_NAME, /* name */
PLUGIN_DESC, /* description */
capture_plugin_unload, /* PluginUnload */
NULL, /* ClientPreConnect */
capture_plugin_client_post_connect, /* ClientPostConnect */
NULL, /* ClientLoginFailure */
capture_plugin_client_end_paint, /* ClientEndPaint */
capture_plugin_server_post_connect, /* ServerPostConnect */
NULL, /* ServerChannelsInit */
NULL, /* ServerChannelsFree */
capture_plugin_session_end, /* Session End */
NULL, /* KeyboardEvent */
NULL, /* MouseEvent */
NULL, /* ClientChannelData */
NULL, /* ServerChannelData */
NULL /* ServerFetchTargetAddr */
};
BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager)
#ifdef __cplusplus
extern "C"
{
g_plugins_manager = plugins_manager;
#endif
FREERDP_API BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager, void* userdata);
#ifdef __cplusplus
}
#endif
if (!capture_plugin_init_config(&config))
BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager, void* userdata)
{
proxyPlugin plugin = { 0 };
plugin.name = PLUGIN_NAME; /* name */
plugin.description = PLUGIN_DESC; /* description */
plugin.PluginUnload = capture_plugin_unload; /* PluginUnload */
plugin.ClientPostConnect = capture_plugin_client_post_connect; /* ClientPostConnect */
plugin.ClientEndPaint = capture_plugin_client_end_paint; /* ClientEndPaint */
plugin.ServerPostConnect = capture_plugin_server_post_connect; /* ServerPostConnect */
plugin.ServerSessionEnd = capture_plugin_session_end; /* Session End */
plugin.userdata = userdata; /* userdata */
captureConfig* cconfig = calloc(1, sizeof(captureConfig));
if (!cconfig)
return FALSE;
plugin.custom = cconfig;
if (!capture_plugin_init_config(cconfig))
{
WLog_ERR(TAG, "failed to load config");
return FALSE;
}
WLog_INFO(TAG, "host: %s, port: %" PRIu16 "", config.host, config.port);
return plugins_manager->RegisterPlugin(&demo_plugin);
WLog_INFO(TAG, "host: %s, port: %" PRIu16 "", cconfig->host, cconfig->port);
return plugins_manager->RegisterPlugin(plugins_manager, &plugin);
}

View File

@ -33,7 +33,7 @@ wStream* capture_plugin_packet_new(UINT32 payload_size, UINT16 type)
wStream* capture_plugin_create_session_info_packet(pClientContext* pc)
{
UINT16 username_length;
size_t username_length;
wStream* s = NULL;
rdpSettings* settings;
@ -46,7 +46,7 @@ wStream* capture_plugin_create_session_info_packet(pClientContext* pc)
return NULL;
username_length = strlen(settings->Username);
if (username_length == 0)
if ((username_length == 0) || (username_length > UINT16_MAX))
return NULL;
s = capture_plugin_packet_new(SESSION_INFO_PDU_BASE_SIZE + username_length,

View File

@ -20,7 +20,7 @@
#include <winpr/stream.h>
#include <freerdp/settings.h>
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
/* protocol message sizes */
#define HEADER_SIZE 6

View File

@ -17,14 +17,20 @@
# limitations under the License.
#
set(PLUGIN_NAME "proxy-demo-plugin")
cmake_minimum_required(VERSION 3.4)
add_library(${PLUGIN_NAME} MODULE
project(proxy-demo-plugin VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(${PROJECT_NAME} MODULE
demo.cpp
)
set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_STANDARD 11)
set_target_properties(${PLUGIN_NAME} PROPERTIES PREFIX "")
set_target_properties(${PLUGIN_NAME} PROPERTIES NO_SONAME 1)
set_target_properties(${PLUGIN_NAME} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${FREERDP_PROXY_PLUGINDIR}")
target_link_libraries(${PROJECT_NAME} winpr)
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
set_target_properties(${PROJECT_NAME} PROPERTIES NO_SONAME 1)
install(TARGETS ${PROJECT_NAME} DESTINATION ${FREERDP_PROXY_PLUGINDIR})

View File

@ -19,59 +19,309 @@
#include <iostream>
#include "modules_api.h"
#include <freerdp/server/proxy/proxy_modules_api.h>
#define TAG MODULE_TAG("demo")
static constexpr char plugin_name[] = "demo";
static constexpr char plugin_desc[] = "this is a test plugin";
static proxyPluginsManager* g_plugins_manager = NULL;
static BOOL demo_filter_keyboard_event(proxyData* pdata, void* param)
static BOOL demo_plugin_unload(proxyPlugin* plugin)
{
auto event_data = static_cast<proxyKeyboardEventInfo*>(param);
if (event_data == NULL)
WINPR_ASSERT(plugin);
std::cout << "C++ demo plugin: unloading..." << std::endl;
/* Here we have to free up our custom data storage. */
if (plugin)
free(plugin->custom);
return TRUE;
}
static BOOL demo_client_init_connect(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_client_uninit_connect(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_client_pre_connect(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_client_post_connect(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_client_post_disconnect(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_client_x509_certificate(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_client_login_failure(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_client_end_paint(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_server_post_connect(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_server_peer_activate(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_server_channels_init(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_server_channels_free(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_server_session_end(proxyPlugin* plugin, proxyData* pdata, void* custom)
{
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(custom);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_filter_keyboard_event(proxyPlugin* plugin, proxyData* pdata, void* param)
{
proxyPluginsManager* mgr;
auto event_data = static_cast<const proxyKeyboardEventInfo*>(param);
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(event_data);
mgr = plugin->mgr;
WINPR_ASSERT(mgr);
if (event_data == nullptr)
return FALSE;
if (event_data->rdp_scan_code == RDP_SCANCODE_KEY_B)
{
/* user typed 'B', that means bye :) */
std::cout << "C++ demo plugin: aborting connection" << std::endl;
g_plugins_manager->AbortConnect(pdata);
mgr->AbortConnect(mgr, pdata);
}
return TRUE;
}
static BOOL demo_plugin_unload()
static BOOL demo_mouse_event(proxyPlugin* plugin, proxyData* pdata, void* param)
{
std::cout << "C++ demo plugin: unloading..." << std::endl;
auto event_data = static_cast<const proxyMouseEventInfo*>(param);
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(event_data);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static proxyPlugin demo_plugin = {
plugin_name, /* name */
plugin_desc, /* description */
demo_plugin_unload, /* PluginUnload */
NULL, /* ClientPreConnect */
NULL, /* ClientPostConnect */
NULL, /* ClientLoginFailure */
NULL, /* ClientEndPaint */
NULL, /* ServerPostConnect */
NULL, /* ServerChannelsInit */
NULL, /* ServerChannelsFree */
NULL, /* ServerSessionEnd */
demo_filter_keyboard_event, /* KeyboardEvent */
NULL, /* MouseEvent */
NULL, /* ClientChannelData */
NULL, /* ServerChannelData */
NULL /* ServerFetchTargetAddr */
};
BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager)
static BOOL demo_client_channel_data(proxyPlugin* plugin, proxyData* pdata, void* param)
{
g_plugins_manager = plugins_manager;
const proxyChannelDataEventInfo* channel = static_cast<const proxyChannelDataEventInfo*>(param);
return plugins_manager->RegisterPlugin(&demo_plugin);
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(channel);
WLog_INFO(TAG, "%s: %s [0x%04" PRIx16 "] got %" PRIuz, __FUNCTION__, channel->channel_name,
channel->channel_id, channel->data_len);
return TRUE;
}
static BOOL demo_server_channel_data(proxyPlugin* plugin, proxyData* pdata, void* param)
{
const proxyChannelDataEventInfo* channel = static_cast<const proxyChannelDataEventInfo*>(param);
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(channel);
WLog_WARN(TAG, "%s: %s [0x%04" PRIx16 "] got %" PRIuz, __FUNCTION__, channel->channel_name,
channel->channel_id, channel->data_len);
return TRUE;
}
static BOOL demo_dynamic_channel_create(proxyPlugin* plugin, proxyData* pdata, void* param)
{
const proxyChannelDataEventInfo* channel = static_cast<const proxyChannelDataEventInfo*>(param);
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(channel);
WLog_WARN(TAG, "%s: %s [0x%04" PRIx16 "]", __FUNCTION__, channel->channel_name,
channel->channel_id);
return TRUE;
}
static BOOL demo_server_fetch_target_addr(proxyPlugin* plugin, proxyData* pdata, void* param)
{
auto event_data = static_cast<const proxyFetchTargetEventInfo*>(param);
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(event_data);
WLog_INFO(TAG, "%s", __FUNCTION__);
return TRUE;
}
static BOOL demo_server_peer_logon(proxyPlugin* plugin, proxyData* pdata, void* param)
{
auto info = static_cast<const proxyServerPeerLogon*>(param);
WINPR_ASSERT(plugin);
WINPR_ASSERT(pdata);
WINPR_ASSERT(info);
WINPR_ASSERT(info->identity);
WLog_INFO(TAG, "%s: %d", __FUNCTION__, info->automatic);
return TRUE;
}
#ifdef __cplusplus
extern "C"
{
#endif
FREERDP_API BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager, void* userdata);
#ifdef __cplusplus
}
#endif
BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager, void* userdata)
{
struct demo_custom_data
{
proxyPluginsManager* mgr;
int somesetting;
};
struct demo_custom_data* custom;
proxyPlugin plugin;
plugin.name = plugin_name;
plugin.description = plugin_desc;
plugin.PluginUnload = demo_plugin_unload;
plugin.ClientInitConnect = demo_client_init_connect;
plugin.ClientUninitConnect = demo_client_uninit_connect;
plugin.ClientPreConnect = demo_client_pre_connect;
plugin.ClientPostConnect = demo_client_post_connect;
plugin.ClientPostDisconnect = demo_client_post_disconnect;
plugin.ClientX509Certificate = demo_client_x509_certificate;
plugin.ClientLoginFailure = demo_client_login_failure;
plugin.ClientEndPaint = demo_client_end_paint;
plugin.ServerPostConnect = demo_server_post_connect;
plugin.ServerPeerActivate = demo_server_peer_activate;
plugin.ServerChannelsInit = demo_server_channels_init;
plugin.ServerChannelsFree = demo_server_channels_free;
plugin.ServerSessionEnd = demo_server_session_end;
plugin.KeyboardEvent = demo_filter_keyboard_event;
plugin.MouseEvent = demo_mouse_event;
plugin.ClientChannelData = demo_client_channel_data;
plugin.ServerChannelData = demo_server_channel_data;
plugin.DynamicChannelCreate = demo_dynamic_channel_create;
plugin.ServerFetchTargetAddr = demo_server_fetch_target_addr;
plugin.ServerPeerLogon = demo_server_peer_logon;
plugin.userdata = userdata;
custom = (struct demo_custom_data*)calloc(1, sizeof(struct demo_custom_data));
if (!custom)
return FALSE;
custom->mgr = plugins_manager;
custom->somesetting = 42;
plugin.custom = custom;
plugin.userdata = userdata;
return plugins_manager->RegisterPlugin(plugins_manager, &plugin);
}

View File

@ -1,150 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
*
* 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_MODULES_API_H
#define FREERDP_SERVER_PROXY_MODULES_API_H
#include <freerdp/freerdp.h>
#include <winpr/winpr.h>
#include "../pf_context.h"
#define MODULE_TAG(module) "proxy.modules." module
/* hook callback. should return TRUE on success or FALSE on error. */
typedef BOOL (*proxyHookFn)(proxyData*);
/*
* Filter callback:
* It MUST return TRUE if the related event should be proxied,
* or FALSE if it should be ignored.
*/
typedef BOOL (*proxyFilterFn)(proxyData*, void*);
/* describes a plugin: name, description and callbacks to execute. */
typedef struct proxy_plugin
{
const char* name; /* unique module name */
const char* description; /* module description */
BOOL (*PluginUnload)(void);
/* proxy hooks. a module can set these function pointers to register hooks */
proxyHookFn ClientPreConnect;
proxyHookFn ClientPostConnect;
proxyHookFn ClientLoginFailure;
proxyHookFn ClientEndPaint;
proxyHookFn ServerPostConnect;
proxyHookFn ServerChannelsInit;
proxyHookFn ServerChannelsFree;
proxyHookFn ServerSessionEnd;
/* proxy filters. a module can set these function pointers to register filters */
proxyFilterFn KeyboardEvent;
proxyFilterFn MouseEvent;
proxyFilterFn ClientChannelData; /* passthrough channels data */
proxyFilterFn ServerChannelData; /* passthrough channels data */
proxyFilterFn ServerFetchTargetAddr;
} proxyPlugin;
/*
* Main API for use by external modules.
* Supports:
* - Registering a plugin.
* - Setting/getting plugin's per-session specific data.
* - Aborting a session.
*/
typedef struct proxy_plugins_manager
{
/* used for registering a fresh new proxy plugin. */
BOOL (*RegisterPlugin)(proxyPlugin* plugin);
/* used for setting plugin's per-session info. */
BOOL (*SetPluginData)(const char*, proxyData*, void*);
/* used for getting plugin's per-session info. */
void* (*GetPluginData)(const char*, proxyData*);
/* used for aborting a session. */
void (*AbortConnect)(proxyData*);
} proxyPluginsManager;
/* filter events parameters */
#define WINPR_PACK_PUSH
#include <winpr/pack.h>
typedef struct proxy_keyboard_event_info
{
UINT16 flags;
UINT16 rdp_scan_code;
} proxyKeyboardEventInfo;
typedef struct proxy_mouse_event_info
{
UINT16 flags;
UINT16 x;
UINT16 y;
} proxyMouseEventInfo;
typedef struct channel_data_event_info
{
/* channel metadata */
const char* channel_name;
UINT16 channel_id;
/* actual data */
const BYTE* data;
size_t data_len;
} proxyChannelDataEventInfo;
typedef enum proxy_fetch_target_method
{
PROXY_FETCH_TARGET_METHOD_DEFAULT,
PROXY_FETCH_TARGET_METHOD_CONFIG,
PROXY_FETCH_TARGET_METHOD_LOAD_BALANCE_INFO,
PROXY_FETCH_TARGET_USE_CUSTOM_ADDR
} ProxyFetchTargetMethod;
typedef struct fetch_target_event_info
{
/* out values */
char* target_address;
UINT16 target_port;
/*
* If this value is set to true by a plugin, target info will be fetched from config and proxy
* will connect any client to the same remote server.
*/
ProxyFetchTargetMethod fetch_method;
} proxyFetchTargetEventInfo;
#define WINPR_PACK_POP
#include <winpr/pack.h>
#ifdef __cplusplus
extern "C"
{
#endif
FREERDP_API BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager);
#ifdef __cplusplus
};
#endif
#endif /* FREERDP_SERVER_PROXY_MODULES_API_H */

View File

@ -23,6 +23,8 @@
#include "config.h"
#endif
#include <winpr/assert.h>
#include <freerdp/gdi/gfx.h>
#include <freerdp/client/rdpei.h>
@ -31,21 +33,26 @@
#include <freerdp/client/rdpgfx.h>
#include <freerdp/client/disp.h>
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_channels.h"
#include "pf_client.h"
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_config.h>
#include <freerdp/server/proxy/proxy_context.h>
#include "pf_rail.h"
#include "pf_rdpgfx.h"
#include "pf_cliprdr.h"
#include "pf_disp.h"
#include "pf_log.h"
#include "pf_modules.h"
#include "proxy_modules.h"
#include "pf_rdpsnd.h"
#define TAG PROXY_TAG("channels")
static void pf_channels_wait_for_server_dynvc(pServerContext* ps)
{
WINPR_ASSERT(ps);
WLog_DBG(TAG, "pf_channels_wait_for_server_dynvc(): waiting for server's drdynvc to be ready");
WaitForSingleObject(ps->dynvcReady, INFINITE);
WLog_DBG(TAG, "pf_channels_wait_for_server_dynvc(): server's drdynvc is ready!");
@ -54,8 +61,17 @@ static void pf_channels_wait_for_server_dynvc(pServerContext* ps)
void pf_channels_on_client_channel_connect(void* data, ChannelConnectedEventArgs* e)
{
pClientContext* pc = (pClientContext*)data;
pServerContext* ps = pc->pdata->ps;
LOG_INFO(TAG, pc, "Channel connected: %s", e->name);
pServerContext* ps;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
WINPR_ASSERT(e);
WINPR_ASSERT(e->name);
ps = pc->pdata->ps;
WINPR_ASSERT(ps);
PROXY_LOG_INFO(TAG, pc, "Channel connected: %s", e->name);
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
{
@ -141,9 +157,19 @@ void pf_channels_on_client_channel_connect(void* data, ChannelConnectedEventArgs
void pf_channels_on_client_channel_disconnect(void* data, ChannelDisconnectedEventArgs* e)
{
rdpContext* context = (rdpContext*)data;
pClientContext* pc = (pClientContext*)context;
pServerContext* ps = pc->pdata->ps;
LOG_INFO(TAG, pc, "Channel disconnected: %s", e->name);
pClientContext* pc = (pClientContext*)data;
pServerContext* ps;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
WINPR_ASSERT(e);
WINPR_ASSERT(e->name);
ps = pc->pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(context);
PROXY_LOG_INFO(TAG, pc, "Channel disconnected: %s", e->name);
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
{
@ -151,6 +177,9 @@ void pf_channels_on_client_channel_disconnect(void* data, ChannelDisconnectedEve
}
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
{
if (!ps->gfx)
return;
WINPR_ASSERT(ps->gfx->Close);
if (!ps->gfx->Close(ps->gfx))
WLog_ERR(TAG, "failed to close gfx server");
@ -159,6 +188,9 @@ void pf_channels_on_client_channel_disconnect(void* data, ChannelDisconnectedEve
}
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
{
if (!ps->rail)
return;
WINPR_ASSERT(ps->rail->Stop);
if (!ps->rail->Stop(ps->rail))
WLog_ERR(TAG, "failed to close rail server");
@ -166,6 +198,9 @@ void pf_channels_on_client_channel_disconnect(void* data, ChannelDisconnectedEve
}
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
{
if (!ps->disp)
return;
WINPR_ASSERT(ps->disp->Close);
if (ps->disp->Close(ps->disp) != CHANNEL_RC_OK)
WLog_ERR(TAG, "failed to close disp server");
@ -173,6 +208,9 @@ void pf_channels_on_client_channel_disconnect(void* data, ChannelDisconnectedEve
}
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
{
if (!ps->cliprdr)
return;
WINPR_ASSERT(ps->cliprdr->Stop);
if (ps->cliprdr->Stop(ps->cliprdr) != CHANNEL_RC_OK)
WLog_ERR(TAG, "failed to stop cliprdr server");
@ -184,16 +222,28 @@ void pf_channels_on_client_channel_disconnect(void* data, ChannelDisconnectedEve
if (ps->rdpsnd == NULL)
return;
WINPR_ASSERT(ps->rdpsnd->Stop);
if (ps->rdpsnd->Stop(ps->rdpsnd) != CHANNEL_RC_OK)
WLog_ERR(TAG, "failed to close rdpsnd server");
}
}
BOOL pf_server_channels_init(pServerContext* ps)
BOOL pf_server_channels_init(pServerContext* ps, freerdp_peer* peer)
{
rdpContext* context = (rdpContext*)ps;
rdpContext* client = (rdpContext*)ps->pdata->pc;
proxyConfig* config = ps->pdata->config;
rdpContext* client;
const proxyConfig* config;
WINPR_ASSERT(peer);
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
WINPR_ASSERT(context);
client = (rdpContext*)ps->pdata->pc;
WINPR_ASSERT(client);
config = ps->pdata->config;
WINPR_ASSERT(config);
WINPR_ASSERT(context->settings);
if (context->settings->SupportGraphicsPipeline && config->GFX)
{
@ -230,38 +280,15 @@ BOOL pf_server_channels_init(pServerContext* ps)
return FALSE;
}
{
/* open static channels for passthrough */
size_t i;
for (i = 0; i < config->PassthroughCount; i++)
{
char* channel_name = config->Passthrough[i];
UINT64 channel_id;
/* only open channel if client joined with it */
if (!WTSVirtualChannelManagerIsChannelJoined(ps->vcm, channel_name))
continue;
ps->vc_handles[i] = WTSVirtualChannelOpen(ps->vcm, WTS_CURRENT_SESSION, channel_name);
if (!ps->vc_handles[i])
{
LOG_ERR(TAG, ps, "WTSVirtualChannelOpen failed for passthrough channel: %s",
channel_name);
return FALSE;
}
channel_id = (UINT64)WTSChannelGetId(ps->context.peer, channel_name);
HashTable_Insert(ps->vc_ids, channel_name, (void*)channel_id);
}
}
return pf_modules_run_hook(HOOK_TYPE_SERVER_CHANNELS_INIT, ps->pdata);
return pf_modules_run_hook(ps->pdata->module, HOOK_TYPE_SERVER_CHANNELS_INIT, ps->pdata, peer);
}
void pf_server_channels_free(pServerContext* ps)
void pf_server_channels_free(pServerContext* ps, freerdp_peer* peer)
{
WINPR_ASSERT(peer);
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
if (ps->gfx)
{
rdpgfx_server_context_free(ps->gfx);
@ -292,13 +319,5 @@ void pf_server_channels_free(pServerContext* ps)
ps->rail = NULL;
}
{
/* close passthrough channels */
size_t i;
for (i = 0; i < ps->pdata->config->PassthroughCount; i++)
WTSVirtualChannelClose(ps->vc_handles[i]);
}
pf_modules_run_hook(HOOK_TYPE_SERVER_CHANNELS_FREE, ps->pdata);
pf_modules_run_hook(ps->pdata->module, HOOK_TYPE_SERVER_CHANNELS_FREE, ps->pdata, peer);
}

View File

@ -25,12 +25,12 @@
#include <freerdp/freerdp.h>
#include <freerdp/client/channels.h>
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
void pf_channels_on_client_channel_connect(void* context, ChannelConnectedEventArgs* e);
void pf_channels_on_client_channel_disconnect(void* context, ChannelDisconnectedEventArgs* e);
BOOL pf_server_channels_init(pServerContext* ps);
void pf_server_channels_free(pServerContext* ps);
BOOL pf_server_channels_init(pServerContext* ps, freerdp_peer* peer);
void pf_server_channels_free(pServerContext* ps, freerdp_peer* peer);
#endif /* FREERDP_SERVER_PROXY_PFCHANNELS_H */

View File

@ -27,22 +27,29 @@
#include <freerdp/gdi/gdi.h>
#include <freerdp/client/cmdline.h>
#include <freerdp/server/proxy/proxy_log.h>
#include <freerdp/channels/drdynvc.h>
#include <freerdp/channels/encomsp.h>
#include <freerdp/channels/rdpdr.h>
#include "pf_channels.h"
#include "pf_gdi.h"
#include "pf_graphics.h"
#include "pf_client.h"
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
#include "pf_update.h"
#include "pf_log.h"
#include "pf_modules.h"
#include "pf_input.h"
#include <freerdp/server/proxy/proxy_config.h>
#include "proxy_modules.h"
#include "pf_utils.h"
#define TAG PROXY_TAG("client")
static pReceiveChannelData client_receive_channel_data_original = NULL;
static BOOL proxy_server_reactivate(rdpContext* ps, const rdpContext* pc)
{
WINPR_ASSERT(ps);
WINPR_ASSERT(pc);
if (!pf_context_copy_settings(ps->settings, pc->settings))
return FALSE;
@ -50,6 +57,7 @@ static BOOL proxy_server_reactivate(rdpContext* ps, const rdpContext* pc)
* DesktopResize causes internal function rdp_server_reactivate to be called,
* which causes the reactivation.
*/
WINPR_ASSERT(ps->update);
if (!ps->update->DesktopResize(ps))
return FALSE;
@ -59,12 +67,18 @@ static BOOL proxy_server_reactivate(rdpContext* ps, const rdpContext* pc)
static void pf_client_on_error_info(void* ctx, ErrorInfoEventArgs* e)
{
pClientContext* pc = (pClientContext*)ctx;
pServerContext* ps = pc->pdata->ps;
pServerContext* ps;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
WINPR_ASSERT(e);
ps = pc->pdata->ps;
WINPR_ASSERT(ps);
if (e->code == ERRINFO_NONE)
return;
LOG_WARN(TAG, pc, "received ErrorInfo PDU. code=0x%08" PRIu32 ", message: %s", e->code,
PROXY_LOG_WARN(TAG, pc, "received ErrorInfo PDU. code=0x%08" PRIu32 ", message: %s", e->code,
freerdp_get_error_info_string(e->code));
/* forward error back to client */
@ -75,10 +89,19 @@ static void pf_client_on_error_info(void* ctx, ErrorInfoEventArgs* e)
static void pf_client_on_activated(void* ctx, ActivatedEventArgs* e)
{
pClientContext* pc = (pClientContext*)ctx;
pServerContext* ps = pc->pdata->ps;
freerdp_peer* peer = ps->context.peer;
pServerContext* ps;
freerdp_peer* peer;
LOG_INFO(TAG, pc, "client activated, registering server input callbacks");
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
WINPR_ASSERT(e);
ps = pc->pdata->ps;
WINPR_ASSERT(ps);
peer = ps->context.peer;
WINPR_ASSERT(peer);
PROXY_LOG_INFO(TAG, pc, "client activated, registering server input callbacks");
/* Register server input/update callbacks only after proxy client is fully activated */
pf_server_register_input_callbacks(peer->context->input);
@ -88,8 +111,15 @@ static void pf_client_on_activated(void* ctx, ActivatedEventArgs* e)
static BOOL pf_client_load_rdpsnd(pClientContext* pc)
{
rdpContext* context = (rdpContext*)pc;
pServerContext* ps = pc->pdata->ps;
proxyConfig* config = pc->pdata->config;
pServerContext* ps;
const proxyConfig* config;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
ps = pc->pdata->ps;
WINPR_ASSERT(ps);
config = pc->pdata->config;
WINPR_ASSERT(config);
/*
* if AudioOutput is enabled in proxy and client connected with rdpsnd, use proxy as rdpsnd
@ -113,48 +143,21 @@ static BOOL pf_client_load_rdpsnd(pClientContext* pc)
return TRUE;
}
static BOOL pf_client_passthrough_channels_init(pClientContext* pc)
{
pServerContext* ps = pc->pdata->ps;
rdpSettings* settings = pc->context.settings;
proxyConfig* config = pc->pdata->config;
size_t i;
if (settings->ChannelCount + config->PassthroughCount >= settings->ChannelDefArraySize)
{
LOG_ERR(TAG, pc, "too many channels");
return FALSE;
}
for (i = 0; i < config->PassthroughCount; i++)
{
const char* channel_name = config->Passthrough[i];
CHANNEL_DEF channel = { 0 };
/* only connect connect this channel if already joined in peer connection */
if (!WTSVirtualChannelManagerIsChannelJoined(ps->vcm, channel_name))
{
LOG_INFO(TAG, ps, "client did not connected with channel %s, skipping passthrough",
channel_name);
continue;
}
channel.options = CHANNEL_OPTION_INITIALIZED; /* TODO: Export to config. */
strncpy(channel.name, channel_name, CHANNEL_NAME_LEN);
settings->ChannelDefArray[settings->ChannelCount++] = channel;
}
return TRUE;
}
static BOOL pf_client_use_peer_load_balance_info(pClientContext* pc)
{
pServerContext* ps = pc->pdata->ps;
rdpSettings* settings = pc->context.settings;
pServerContext* ps;
rdpSettings* settings;
DWORD lb_info_len;
const char* lb_info = freerdp_nego_get_routing_token(&ps->context, &lb_info_len);
const char* lb_info;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
ps = pc->pdata->ps;
WINPR_ASSERT(ps);
settings = pc->context.settings;
WINPR_ASSERT(settings);
lb_info = freerdp_nego_get_routing_token(&ps->context, &lb_info_len);
if (!lb_info)
return TRUE;
@ -172,10 +175,22 @@ static BOOL pf_client_use_peer_load_balance_info(pClientContext* pc)
static BOOL pf_client_pre_connect(freerdp* instance)
{
pClientContext* pc = (pClientContext*)instance->context;
pServerContext* ps = pc->pdata->ps;
proxyConfig* config = ps->pdata->config;
rdpSettings* settings = instance->settings;
pClientContext* pc;
pServerContext* ps;
const proxyConfig* config;
rdpSettings* settings;
WINPR_ASSERT(instance);
pc = (pClientContext*)instance->context;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
ps = pc->pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
config = ps->pdata->config;
WINPR_ASSERT(config);
settings = instance->settings;
WINPR_ASSERT(settings);
/*
* as the client's settings are copied from the server's, GlyphSupportLevel might not be
@ -187,19 +202,27 @@ static BOOL pf_client_pre_connect(freerdp* instance)
settings->GlyphSupportLevel = GLYPH_SUPPORT_NONE;
ZeroMemory(settings->OrderSupport, 32);
if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, DRDYNVC_SVC_CHANNEL_NAME))
settings->SupportDynamicChannels = TRUE;
/* Multimon */
settings->UseMultimon = TRUE;
/* Sound */
settings->AudioPlayback = FALSE;
settings->AudioPlayback = config->AudioOutput;
if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, "rdpdr"))
settings->DeviceRedirection = TRUE;
/* Display control */
settings->SupportDisplayControl = config->DisplayControl;
settings->DynamicResolutionUpdate = config->DisplayControl;
if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, ENCOMSP_SVC_CHANNEL_NAME))
settings->EncomspVirtualChannel = TRUE;
if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, CLIPRDR_SVC_CHANNEL_NAME))
settings->RedirectClipboard = config->Clipboard;
settings->AutoReconnectionEnabled = TRUE;
/**
@ -216,73 +239,211 @@ static BOOL pf_client_pre_connect(freerdp* instance)
* Load all required plugins / channels / libraries specified by current
* settings.
*/
LOG_INFO(TAG, pc, "Loading addins");
PROXY_LOG_INFO(TAG, pc, "Loading addins");
if (!pf_client_use_peer_load_balance_info(pc))
return FALSE;
if (!pf_client_passthrough_channels_init(pc))
return FALSE;
if (!pf_client_load_rdpsnd(pc))
{
LOG_ERR(TAG, pc, "Failed to load rdpsnd client");
PROXY_LOG_ERR(TAG, pc, "Failed to load rdpsnd client");
return FALSE;
}
if (!freerdp_client_load_addins(instance->context->channels, instance->settings))
{
LOG_ERR(TAG, pc, "Failed to load addins");
PROXY_LOG_ERR(TAG, pc, "Failed to load addins");
return FALSE;
}
return TRUE;
return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_PRE_CONNECT, pc->pdata, pc);
}
static BOOL pf_client_receive_channel_data_hook(freerdp* instance, UINT16 channelId,
const BYTE* data, size_t size, UINT32 flags,
size_t totalSize)
{
pClientContext* pc = (pClientContext*)instance->context;
pServerContext* ps = pc->pdata->ps;
proxyData* pdata = ps->pdata;
proxyConfig* config = pdata->config;
size_t i;
const char* channel_name = freerdp_channels_get_name_by_id(instance, channelId);
pClientContext* pc;
pServerContext* ps;
proxyData* pdata;
const proxyConfig* config;
int pass;
for (i = 0; i < config->PassthroughCount; i++)
WINPR_ASSERT(instance);
WINPR_ASSERT(data || (size == 0));
pc = (pClientContext*)instance->context;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
ps = pc->pdata->ps;
WINPR_ASSERT(ps);
pdata = ps->pdata;
WINPR_ASSERT(pdata);
config = pdata->config;
WINPR_ASSERT(config);
pass = pf_utils_channel_is_passthrough(config, channel_name);
switch (pass)
{
if (strncmp(channel_name, config->Passthrough[i], CHANNEL_NAME_LEN) == 0)
case 0:
return TRUE; /* Silently drop */
case 1:
{
proxyChannelDataEventInfo ev;
UINT64 server_channel_id;
UINT16 server_channel_id;
ev.channel_id = channelId;
ev.channel_name = channel_name;
ev.data = data;
ev.data_len = size;
ev.flags = flags;
ev.total_size = totalSize;
if (!pf_modules_run_filter(FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA, pdata, &ev))
if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA,
pdata, &ev))
return TRUE; /* Silently drop */
/* Dynamic channels need special treatment
*
* We need to check every message with CHANNEL_FLAG_FIRST set if it
* is a CREATE_REQUEST_PDU (0x01) and extract channelId and name
* from it.
*
* To avoid issues with (misbehaving) clients assume all packets
* that do not have at least a length of 1 byte and all incomplete
* CREATE_REQUEST_PDU (0x01) packets as invalid.
*/
if ((flags & CHANNEL_FLAG_FIRST) &&
(strncmp(channel_name, DRDYNVC_SVC_CHANNEL_NAME, CHANNEL_NAME_LEN + 1) == 0))
{
BYTE cmd;
if (size < 1)
return FALSE;
server_channel_id =
(UINT64)HashTable_GetItemValue(ps->vc_ids, (const void*)channel_name);
return ps->context.peer->SendChannelData(ps->context.peer, (UINT16)server_channel_id,
data, size);
}
cmd = data[0] >> 4;
if (cmd == 0x01)
{
proxyChannelDataEventInfo dev;
size_t len, nameLen;
const char* name;
UINT32 dynChannelId;
BYTE cbId = data[0] & 0x03;
switch (cbId)
{
case 0x00:
if (size < 2)
return FALSE;
dynChannelId = data[1];
name = (const char*)&data[2];
nameLen = size - 2;
break;
case 0x01:
if (size < 3)
return FALSE;
dynChannelId = data[2] << 8 | data[1];
name = (const char*)&data[3];
nameLen = size - 3;
break;
case 0x02:
if (size < 5)
return FALSE;
dynChannelId = data[4] << 24 | data[3] << 16 | data[2] << 8 | data[1];
name = (const char*)&data[5];
nameLen = size - 5;
break;
default:
return FALSE;
}
return client_receive_channel_data_original(instance, channelId, data, size, flags, totalSize);
len = strnlen(name, nameLen);
if ((len == 0) || (len == nameLen))
return FALSE;
dev.channel_id = dynChannelId;
dev.channel_name = name;
dev.data = data;
dev.data_len = size;
dev.flags = flags;
dev.total_size = totalSize;
if (!pf_modules_run_filter(pdata->module,
FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE,
pdata, &dev))
return TRUE; /* Silently drop */
}
}
server_channel_id = WTSChannelGetId(ps->context.peer, channel_name);
/* Ignore messages for channels that can not be mapped.
* The client might not have enabled support for this specific channel,
* so just drop the message. */
if (server_channel_id == 0)
return TRUE;
return ps->context.peer->SendChannelPacket(ps->context.peer, server_channel_id,
totalSize, flags, data, size);
}
default:
WINPR_ASSERT(pc->client_receive_channel_data_original);
return pc->client_receive_channel_data_original(instance, channelId, data, size, flags,
totalSize);
}
}
static BOOL pf_client_on_server_heartbeat(freerdp* instance, BYTE period, BYTE count1, BYTE count2)
{
pClientContext* pc = (pClientContext*)instance->context;
pServerContext* ps = pc->pdata->ps;
pClientContext* pc;
pServerContext* ps;
WINPR_ASSERT(instance);
pc = (pClientContext*)instance->context;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
ps = pc->pdata->ps;
WINPR_ASSERT(ps);
return freerdp_heartbeat_send_heartbeat_pdu(ps->context.peer, period, count1, count2);
}
static BOOL pf_client_send_channel_data(pClientContext* pc, const proxyChannelDataEventInfo* ev)
{
WINPR_ASSERT(pc);
WINPR_ASSERT(ev);
if (!pc->connected)
{
ArrayList_Append(pc->cached_server_channel_data, ev);
return TRUE;
}
else
{
UINT16 channelId;
WINPR_ASSERT(pc->context.instance);
channelId = freerdp_channels_get_id_by_name(pc->context.instance, ev->channel_name);
/* Ignore unmappable channels */
if ((channelId == 0) || (channelId == UINT16_MAX))
return TRUE;
WINPR_ASSERT(pc->context.instance->SendChannelPacket);
return pc->context.instance->SendChannelPacket(
pc->context.instance, channelId, ev->total_size, ev->flags, ev->data, ev->data_len);
}
}
static BOOL send_channel_data(void* data, size_t index, va_list ap)
{
pClientContext* pc = va_arg(ap, pClientContext*);
proxyChannelDataEventInfo* ev = data;
WINPR_ASSERT(ev);
WINPR_ASSERT(pc);
WINPR_UNUSED(index);
return pf_client_send_channel_data(pc, ev);
}
/**
* Called after a RDP connection was successfully established.
* Settings might have changed during negotiation of client / server feature
@ -299,16 +460,24 @@ static BOOL pf_client_post_connect(freerdp* instance)
rdpUpdate* update;
rdpContext* ps;
pClientContext* pc;
proxyConfig* config;
const proxyConfig* config;
WINPR_ASSERT(instance);
context = instance->context;
WINPR_ASSERT(context);
settings = instance->settings;
WINPR_ASSERT(settings);
update = instance->update;
WINPR_ASSERT(update);
pc = (pClientContext*)context;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
ps = (rdpContext*)pc->pdata->ps;
WINPR_ASSERT(ps);
config = pc->pdata->config;
WINPR_ASSERT(config);
if (!pf_modules_run_hook(HOOK_TYPE_CLIENT_POST_CONNECT, pc->pdata))
if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_POST_CONNECT, pc->pdata, pc))
return FALSE;
if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
@ -321,7 +490,7 @@ static BOOL pf_client_post_connect(freerdp* instance)
{
if (!pf_register_graphics(context->graphics))
{
LOG_ERR(TAG, pc, "failed to register graphics");
PROXY_LOG_ERR(TAG, pc, "failed to register graphics");
return FALSE;
}
@ -336,22 +505,19 @@ static BOOL pf_client_post_connect(freerdp* instance)
pf_client_register_update_callbacks(update);
/* virtual channels receive data hook */
client_receive_channel_data_original = instance->ReceiveChannelData;
pc->client_receive_channel_data_original = instance->ReceiveChannelData;
instance->ReceiveChannelData = pf_client_receive_channel_data_hook;
/* populate channel name -> channel ids map */
{
size_t i;
for (i = 0; i < config->PassthroughCount; i++)
{
char* channel_name = config->Passthrough[i];
UINT64 channel_id = (UINT64)freerdp_channels_get_id_by_name(instance, channel_name);
HashTable_Insert(pc->vc_ids, (void*)channel_name, (void*)channel_id);
}
}
instance->heartbeat->ServerHeartbeat = pf_client_on_server_heartbeat;
pc->connected = TRUE;
/* Send cached channel data */
ArrayList_Lock(pc->cached_server_channel_data);
ArrayList_ForEach(pc->cached_server_channel_data, send_channel_data, pc);
ArrayList_Clear(pc->cached_server_channel_data);
ArrayList_Unlock(pc->cached_server_channel_data);
/*
* after the connection fully established and settings were negotiated with target server,
* send a reactivation sequence to the client with the negotiated settings. This way,
@ -365,7 +531,7 @@ static BOOL pf_client_post_connect(freerdp* instance)
*/
static void pf_client_post_disconnect(freerdp* instance)
{
pClientContext* context;
pClientContext* pc;
proxyData* pdata;
if (!instance)
@ -374,8 +540,13 @@ static void pf_client_post_disconnect(freerdp* instance)
if (!instance->context)
return;
context = (pClientContext*)instance->context;
pdata = context->pdata;
pc = (pClientContext*)instance->context;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
pc->connected = FALSE;
pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_POST_CONNECT, pc->pdata, pc);
PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
pf_channels_on_client_channel_connect);
@ -385,7 +556,7 @@ static void pf_client_post_disconnect(freerdp* instance)
gdi_free(instance);
/* Only close the connection if NLA fallback process is done */
if (!context->allow_next_conn_failure)
if (!pc->allow_next_conn_failure)
proxy_data_abort_connect(pdata);
}
@ -397,8 +568,15 @@ static void pf_client_post_disconnect(freerdp* instance)
*/
static BOOL pf_client_should_retry_without_nla(pClientContext* pc)
{
rdpSettings* settings = pc->context.settings;
proxyConfig* config = pc->pdata->config;
rdpSettings* settings;
const proxyConfig* config;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
settings = pc->context.settings;
WINPR_ASSERT(settings);
config = pc->pdata->config;
WINPR_ASSERT(config);
if (!config->ClientAllowFallbackToTls || !settings->NlaSecurity)
return FALSE;
@ -408,26 +586,41 @@ static BOOL pf_client_should_retry_without_nla(pClientContext* pc)
static void pf_client_set_security_settings(pClientContext* pc)
{
rdpSettings* settings = pc->context.settings;
proxyConfig* config = pc->pdata->config;
rdpSettings* settings;
const proxyConfig* config;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->pdata);
settings = pc->context.settings;
WINPR_ASSERT(settings);
config = pc->pdata->config;
WINPR_ASSERT(config);
settings->RdpSecurity = config->ClientRdpSecurity;
settings->TlsSecurity = config->ClientTlsSecurity;
settings->NlaSecurity = FALSE;
settings->NlaSecurity = config->ClientNlaSecurity;
if (!config->ClientNlaSecurity)
return;
if (!settings->Username || !settings->Password)
return;
settings->NlaSecurity = TRUE;
}
static BOOL pf_client_connect_without_nla(pClientContext* pc)
{
freerdp* instance = pc->context.instance;
rdpSettings* settings = pc->context.settings;
freerdp* instance;
rdpSettings* settings;
WINPR_ASSERT(pc);
instance = pc->context.instance;
WINPR_ASSERT(instance);
settings = pc->context.settings;
WINPR_ASSERT(settings);
/* If already disabled abort early. */
if (!settings->NlaSecurity)
return FALSE;
/* disable NLA */
settings->NlaSecurity = FALSE;
@ -439,19 +632,25 @@ static BOOL pf_client_connect_without_nla(pClientContext* pc)
static BOOL pf_client_connect(freerdp* instance)
{
pClientContext* pc = (pClientContext*)instance->context;
rdpSettings* settings = instance->settings;
pClientContext* pc;
rdpSettings* settings;
BOOL rc = FALSE;
BOOL retry = FALSE;
LOG_INFO(TAG, pc, "connecting using client info: Username: %s, Domain: %s", settings->Username,
settings->Domain);
WINPR_ASSERT(instance);
pc = (pClientContext*)instance->context;
WINPR_ASSERT(pc);
settings = instance->settings;
WINPR_ASSERT(settings);
PROXY_LOG_INFO(TAG, pc, "connecting using client info: Username: %s, Domain: %s",
settings->Username, settings->Domain);
pf_client_set_security_settings(pc);
if (pf_client_should_retry_without_nla(pc))
retry = pc->allow_next_conn_failure = TRUE;
LOG_INFO(TAG, pc, "connecting using security settings: rdp=%d, tls=%d, nla=%d",
PROXY_LOG_INFO(TAG, pc, "connecting using security settings: rdp=%d, tls=%d, nla=%d",
settings->RdpSecurity, settings->TlsSecurity, settings->NlaSecurity);
if (!freerdp_connect(instance))
@ -459,12 +658,12 @@ static BOOL pf_client_connect(freerdp* instance)
if (!retry)
goto out;
LOG_ERR(TAG, pc, "failed to connect with NLA. retrying to connect without NLA");
pf_modules_run_hook(HOOK_TYPE_CLIENT_LOGIN_FAILURE, pc->pdata);
PROXY_LOG_ERR(TAG, pc, "failed to connect with NLA. retrying to connect without NLA");
pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_LOGIN_FAILURE, pc->pdata, pc);
if (!pf_client_connect_without_nla(pc))
{
LOG_ERR(TAG, pc, "pf_client_connect_without_nla failed!");
PROXY_LOG_ERR(TAG, pc, "pf_client_connect_without_nla failed!");
goto out;
}
}
@ -483,12 +682,17 @@ out:
static DWORD WINAPI pf_client_thread_proc(LPVOID arg)
{
freerdp* instance = (freerdp*)arg;
pClientContext* pc = (pClientContext*)instance->context;
proxyData* pdata = pc->pdata;
DWORD nCount;
pClientContext* pc;
proxyData* pdata;
DWORD nCount = 0;
DWORD status;
HANDLE handles[65];
HANDLE handles[65] = { 0 };
WINPR_ASSERT(instance);
pc = (pClientContext*)instance->context;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
/*
* during redirection, freerdp's abort event might be overriden (reset) by the library, after
* the server set it in order to shutdown the connection. it means that the server might signal
@ -496,9 +700,9 @@ static DWORD WINAPI pf_client_thread_proc(LPVOID arg)
* continue its work instead of exiting. That's why the client must wait on `pdata->abort_event`
* too, which will never be modified by the library.
*/
handles[64] = pdata->abort_event;
handles[nCount++] = pdata->abort_event;
if (!pf_modules_run_hook(HOOK_TYPE_CLIENT_PRE_CONNECT, pdata))
if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_CLIENT_INIT_CONNECT, pdata, pc))
{
proxy_data_abort_connect(pdata);
return FALSE;
@ -512,15 +716,16 @@ static DWORD WINAPI pf_client_thread_proc(LPVOID arg)
while (!freerdp_shall_disconnect(instance))
{
nCount = freerdp_get_event_handles(instance->context, &handles[0], 64);
UINT32 tmp = freerdp_get_event_handles(instance->context, &handles[nCount],
ARRAYSIZE(handles) - nCount);
if (nCount == 0)
if (tmp == 0)
{
LOG_ERR(TAG, pc, "freerdp_get_event_handles failed!");
PROXY_LOG_ERR(TAG, pc, "freerdp_get_event_handles failed!");
break;
}
status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
status = WaitForMultipleObjects(nCount + tmp, handles, FALSE, INFINITE);
if (status == WAIT_FAILED)
{
@ -529,6 +734,10 @@ static DWORD WINAPI pf_client_thread_proc(LPVOID arg)
break;
}
/* abort_event triggered */
if (status == WAIT_OBJECT_0)
break;
if (freerdp_shall_disconnect(instance))
break;
@ -545,6 +754,9 @@ static DWORD WINAPI pf_client_thread_proc(LPVOID arg)
}
freerdp_disconnect(instance);
pf_modules_run_hook(pdata->module, HOOK_TYPE_CLIENT_UNINIT_CONNECT, pdata, pc);
return 0;
}
@ -560,91 +772,126 @@ static int pf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
return 1;
}
/**
* Callback set in the rdp_freerdp structure, and used to make a certificate validation
* when the connection requires it.
* This function will actually be called by tls_verify_certificate().
* @see rdp_client_connect() and tls_connect()
* @param instance pointer to the rdp_freerdp structure that contains the connection settings
* @param host The host currently connecting to
* @param port The port currently connecting to
* @param common_name The common name of the certificate, should match host or an alias of it
* @param subject The subject of the certificate
* @param issuer The certificate issuer name
* @param fingerprint The fingerprint of the certificate
* @param flags See VERIFY_CERT_FLAG_* for possible values.
*
* @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise.
*/
static DWORD pf_client_verify_certificate_ex(freerdp* instance, const char* host, UINT16 port,
const char* common_name, const char* subject,
const char* issuer, const char* fingerprint,
DWORD flags)
{
/* TODO: Add trust level to proxy configurable settings */
return 1;
}
/**
* Callback set in the rdp_freerdp structure, and used to make a certificate validation
* when a stored certificate does not match the remote counterpart.
* This function will actually be called by tls_verify_certificate().
* @see rdp_client_connect() and tls_connect()
* @param instance pointer to the rdp_freerdp structure that contains the connection settings
* @param host The host currently connecting to
* @param port The port currently connecting to
* @param common_name The common name of the certificate, should match host or an alias of it
* @param subject The subject of the certificate
* @param issuer The certificate issuer name
* @param fingerprint The fingerprint of the certificate
* @param old_subject The subject of the previous certificate
* @param old_issuer The previous certificate issuer name
* @param old_fingerprint The fingerprint of the previous certificate
* @param flags See VERIFY_CERT_FLAG_* for possible values.
*
* @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise.
*/
static DWORD pf_client_verify_changed_certificate_ex(
freerdp* instance, const char* host, UINT16 port, const char* common_name, const char* subject,
const char* issuer, const char* fingerprint, const char* old_subject, const char* old_issuer,
const char* old_fingerprint, DWORD flags)
{
/* TODO: Add trust level to proxy configurable settings */
return 1;
}
static void pf_client_context_free(freerdp* instance, rdpContext* context)
{
pClientContext* pc = (pClientContext*)context;
WINPR_UNUSED(instance);
if (!pc)
return;
HashTable_Free(pc->vc_ids);
pc->sendChannelData = NULL;
ArrayList_Free(pc->cached_server_channel_data);
Stream_Free(pc->remote_pem, TRUE);
free(pc->remote_hostname);
}
static int pf_client_verify_X509_certificate(freerdp* instance, const BYTE* data, size_t length,
const char* hostname, UINT16 port, DWORD flags)
{
pClientContext* pc;
WINPR_ASSERT(instance);
WINPR_ASSERT(data);
WINPR_ASSERT(length > 0);
WINPR_ASSERT(hostname);
pc = (pClientContext*)instance->context;
WINPR_ASSERT(pc);
if (!Stream_EnsureCapacity(pc->remote_pem, length))
return 0;
Stream_SetPosition(pc->remote_pem, 0);
free(pc->remote_hostname);
pc->remote_hostname = NULL;
if (length > 0)
Stream_Write(pc->remote_pem, data, length);
if (hostname)
pc->remote_hostname = _strdup(hostname);
pc->remote_port = port;
pc->remote_flags = flags;
Stream_SealLength(pc->remote_pem);
if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_VERIFY_X509, pc->pdata, pc))
return 0;
return 1;
}
static void* channel_data_copy(const void* obj)
{
const proxyChannelDataEventInfo* src = obj;
proxyChannelDataEventInfo* dst;
WINPR_ASSERT(src);
dst = calloc(1, sizeof(proxyChannelDataEventInfo));
WINPR_ASSERT(dst);
*dst = *src;
if (src->channel_name)
{
dst->channel_name = _strdup(src->channel_name);
WINPR_ASSERT(dst->channel_name);
}
dst->data = malloc(src->data_len);
WINPR_ASSERT(dst->data);
memcpy((void*)dst->data, src->data, src->data_len);
return dst;
}
static void channel_data_free(void* obj)
{
proxyChannelDataEventInfo* dst = obj;
if (dst)
{
free((void*)dst->data);
free((void*)dst->channel_name);
free(dst);
}
}
static BOOL pf_client_client_new(freerdp* instance, rdpContext* context)
{
wObject* obj;
pClientContext* pc = (pClientContext*)context;
if (!instance || !context)
return FALSE;
instance->PreConnect = pf_client_pre_connect;
instance->PostConnect = pf_client_post_connect;
instance->PostDisconnect = pf_client_post_disconnect;
instance->VerifyCertificateEx = pf_client_verify_certificate_ex;
instance->VerifyChangedCertificateEx = pf_client_verify_changed_certificate_ex;
instance->LogonErrorInfo = pf_logon_error_info;
instance->ContextFree = pf_client_context_free;
instance->VerifyX509Certificate = pf_client_verify_X509_certificate;
pc->remote_pem = Stream_New(NULL, 4096);
if (!pc->remote_pem)
return FALSE;
pc->sendChannelData = pf_client_send_channel_data;
pc->cached_server_channel_data = ArrayList_New(TRUE);
if (!pc->cached_server_channel_data)
return FALSE;
obj = ArrayList_Object(pc->cached_server_channel_data);
WINPR_ASSERT(obj);
obj->fnObjectNew = channel_data_copy;
obj->fnObjectFree = channel_data_free;
return TRUE;
}
static int pf_client_client_stop(rdpContext* context)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
proxyData* pdata;
LOG_DBG(TAG, pc, "aborting client connection");
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
PROXY_LOG_DBG(TAG, pc, "aborting client connection");
proxy_data_abort_connect(pdata);
freerdp_abort_connect(context->instance);
@ -654,9 +901,9 @@ static int pf_client_client_stop(rdpContext* context)
* Wait for client thread to finish. No need to call CloseHandle() here, as
* it is the responsibility of `proxy_data_free`.
*/
LOG_DBG(TAG, pc, "waiting for client thread to finish");
PROXY_LOG_DBG(TAG, pc, "waiting for client thread to finish");
WaitForSingleObject(pdata->client_thread, INFINITE);
LOG_DBG(TAG, pc, "thread finished");
PROXY_LOG_DBG(TAG, pc, "thread finished");
}
return 0;
@ -664,12 +911,15 @@ static int pf_client_client_stop(rdpContext* context)
int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
{
WINPR_ASSERT(pEntryPoints);
ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS));
pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
pEntryPoints->ContextSize = sizeof(pClientContext);
/* Client init and finish */
pEntryPoints->ClientNew = pf_client_client_new;
pEntryPoints->ClientFree = pf_client_context_free;
pEntryPoints->ClientStop = pf_client_client_stop;
return 0;
}
@ -681,6 +931,7 @@ DWORD WINAPI pf_client_start(LPVOID arg)
{
rdpContext* context = (rdpContext*)arg;
WINPR_ASSERT(context);
if (freerdp_client_start(context) != 0)
return 1;

View File

@ -18,8 +18,11 @@
* limitations under the License.
*/
#include <winpr/assert.h>
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_cliprdr.h"
#include "pf_log.h"
#include <freerdp/server/proxy/proxy_config.h>
#define TAG PROXY_TAG("cliprdr")
#define TEXT_FORMATS_COUNT 2
@ -30,6 +33,8 @@ static CLIPRDR_FORMAT g_text_formats[] = { { CF_TEXT, "\0" }, { CF_UNICODETEXT,
BOOL pf_server_cliprdr_init(pServerContext* ps)
{
CliprdrServerContext* cliprdr;
WINPR_ASSERT(ps);
cliprdr = ps->cliprdr = cliprdr_server_context_new(ps->vcm);
if (!cliprdr)
@ -66,6 +71,7 @@ static INLINE BOOL pf_cliprdr_is_text_format(UINT32 format)
static INLINE void pf_cliprdr_create_text_only_format_list(CLIPRDR_FORMAT_LIST* list)
{
WINPR_ASSERT(list);
list->msgFlags = CB_RESPONSE_OK;
list->msgType = CB_FORMAT_LIST;
list->dataLen = (4 + 1) * TEXT_FORMATS_COUNT;
@ -77,10 +83,14 @@ static INLINE void pf_cliprdr_create_text_only_format_list(CLIPRDR_FORMAT_LIST*
* pf_cliprdr_is_copy_paste_valid returns TRUE if the length of the copied
* text is valid according to the configuration value of `MaxTextLength`.
*/
static BOOL pf_cliprdr_is_copy_paste_valid(proxyConfig* config,
static BOOL pf_cliprdr_is_copy_paste_valid(const proxyConfig* config,
const CLIPRDR_FORMAT_DATA_RESPONSE* pdu, UINT32 format)
{
size_t copy_len;
WINPR_ASSERT(config);
WINPR_ASSERT(pdu);
if (config->MaxTextLength == 0)
{
/* no size limit */
@ -126,6 +136,8 @@ static BOOL pf_cliprdr_is_copy_paste_valid(proxyConfig* config,
*/
static INLINE void pf_cliprdr_create_failed_format_data_response(CLIPRDR_FORMAT_DATA_RESPONSE* dst)
{
WINPR_ASSERT(dst);
dst->requestedFormatData = NULL;
dst->dataLen = 0;
dst->msgType = CB_FORMAT_DATA_RESPONSE;
@ -136,8 +148,20 @@ static INLINE void pf_cliprdr_create_failed_format_data_response(CLIPRDR_FORMAT_
static UINT pf_cliprdr_ClientCapabilities(CliprdrServerContext* context,
const CLIPRDR_CAPABILITIES* capabilities)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(capabilities);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientCapabilities);
WLog_VRB(TAG, __FUNCTION__);
return client->ClientCapabilities(client, capabilities);
}
@ -145,8 +169,20 @@ static UINT pf_cliprdr_ClientCapabilities(CliprdrServerContext* context,
static UINT pf_cliprdr_TempDirectory(CliprdrServerContext* context,
const CLIPRDR_TEMP_DIRECTORY* tempDirectory)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(tempDirectory);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->TempDirectory);
WLog_VRB(TAG, __FUNCTION__);
return client->TempDirectory(client, tempDirectory);
}
@ -154,13 +190,25 @@ static UINT pf_cliprdr_TempDirectory(CliprdrServerContext* context,
static UINT pf_cliprdr_ClientFormatList(CliprdrServerContext* context,
const CLIPRDR_FORMAT_LIST* formatList)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(formatList);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientFormatList);
WLog_VRB(TAG, __FUNCTION__);
if (pdata->config->TextOnly)
{
CLIPRDR_FORMAT_LIST list;
CLIPRDR_FORMAT_LIST list = { 0 };
pf_cliprdr_create_text_only_format_list(&list);
return client->ClientFormatList(client, &list);
}
@ -173,8 +221,20 @@ static UINT
pf_cliprdr_ClientFormatListResponse(CliprdrServerContext* context,
const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(formatListResponse);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientFormatListResponse);
WLog_VRB(TAG, __FUNCTION__);
return client->ClientFormatListResponse(client, formatListResponse);
}
@ -182,8 +242,20 @@ pf_cliprdr_ClientFormatListResponse(CliprdrServerContext* context,
static UINT pf_cliprdr_ClientLockClipboardData(CliprdrServerContext* context,
const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(lockClipboardData);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientLockClipboardData);
WLog_VRB(TAG, __FUNCTION__);
return client->ClientLockClipboardData(client, lockClipboardData);
}
@ -192,8 +264,20 @@ static UINT
pf_cliprdr_ClientUnlockClipboardData(CliprdrServerContext* context,
const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(unlockClipboardData);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientUnlockClipboardData);
WLog_VRB(TAG, __FUNCTION__);
return client->ClientUnlockClipboardData(client, unlockClipboardData);
}
@ -201,18 +285,36 @@ pf_cliprdr_ClientUnlockClipboardData(CliprdrServerContext* context,
static UINT pf_cliprdr_ClientFormatDataRequest(CliprdrServerContext* context,
const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
CliprdrServerContext* server = pdata->ps->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(formatDataRequest);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->pc);
WLog_VRB(TAG, __FUNCTION__);
if (pdata->config->TextOnly && !pf_cliprdr_is_text_format(formatDataRequest->requestedFormatId))
{
CLIPRDR_FORMAT_DATA_RESPONSE resp;
CLIPRDR_FORMAT_DATA_RESPONSE resp = { 0 };
CliprdrServerContext* server;
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerFormatDataResponse);
pf_cliprdr_create_failed_format_data_response(&resp);
return server->ServerFormatDataResponse(server, &resp);
}
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientFormatDataRequest);
return client->ClientFormatDataRequest(client, formatDataRequest);
}
@ -220,8 +322,21 @@ static UINT
pf_cliprdr_ClientFormatDataResponse(CliprdrServerContext* context,
const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(formatDataResponse);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientFormatDataResponse);
WLog_VRB(TAG, __FUNCTION__);
if (pf_cliprdr_is_text_format(client->lastRequestedFormatId))
@ -242,8 +357,21 @@ static UINT
pf_cliprdr_ClientFileContentsRequest(CliprdrServerContext* context,
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(fileContentsRequest);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientFileContentsRequest);
WLog_VRB(TAG, __FUNCTION__);
if (pdata->config->TextOnly)
@ -256,8 +384,21 @@ static UINT
pf_cliprdr_ClientFileContentsResponse(CliprdrServerContext* context,
const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrClientContext* client = pdata->pc->cliprdr;
proxyData* pdata;
CliprdrClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(fileContentsResponse);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientFileContentsResponse);
WLog_VRB(TAG, __FUNCTION__);
if (pdata->config->TextOnly)
@ -271,8 +412,21 @@ pf_cliprdr_ClientFileContentsResponse(CliprdrServerContext* context,
static UINT pf_cliprdr_ServerCapabilities(CliprdrClientContext* context,
const CLIPRDR_CAPABILITIES* capabilities)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(capabilities);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerCapabilities);
WLog_VRB(TAG, __FUNCTION__);
return server->ServerCapabilities(server, capabilities);
}
@ -280,8 +434,21 @@ static UINT pf_cliprdr_ServerCapabilities(CliprdrClientContext* context,
static UINT pf_cliprdr_MonitorReady(CliprdrClientContext* context,
const CLIPRDR_MONITOR_READY* monitorReady)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(monitorReady);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->MonitorReady);
WLog_VRB(TAG, __FUNCTION__);
return server->MonitorReady(server, monitorReady);
}
@ -289,8 +456,21 @@ static UINT pf_cliprdr_MonitorReady(CliprdrClientContext* context,
static UINT pf_cliprdr_ServerFormatList(CliprdrClientContext* context,
const CLIPRDR_FORMAT_LIST* formatList)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(formatList);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerFormatList);
WLog_VRB(TAG, __FUNCTION__);
if (pdata->config->TextOnly)
@ -307,8 +487,21 @@ static UINT
pf_cliprdr_ServerFormatListResponse(CliprdrClientContext* context,
const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(formatListResponse);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerFormatListResponse);
WLog_VRB(TAG, __FUNCTION__);
return server->ServerFormatListResponse(server, formatListResponse);
}
@ -316,8 +509,21 @@ pf_cliprdr_ServerFormatListResponse(CliprdrClientContext* context,
static UINT pf_cliprdr_ServerLockClipboardData(CliprdrClientContext* context,
const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(lockClipboardData);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerLockClipboardData);
WLog_VRB(TAG, __FUNCTION__);
return server->ServerLockClipboardData(server, lockClipboardData);
}
@ -326,8 +532,21 @@ static UINT
pf_cliprdr_ServerUnlockClipboardData(CliprdrClientContext* context,
const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(unlockClipboardData);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerUnlockClipboardData);
WLog_VRB(TAG, __FUNCTION__);
return server->ServerUnlockClipboardData(server, unlockClipboardData);
}
@ -335,19 +554,37 @@ pf_cliprdr_ServerUnlockClipboardData(CliprdrClientContext* context,
static UINT pf_cliprdr_ServerFormatDataRequest(CliprdrClientContext* context,
const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrClientContext* client = pdata->pc->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(formatDataRequest);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WLog_VRB(TAG, __FUNCTION__);
if (pdata->config->TextOnly && !pf_cliprdr_is_text_format(formatDataRequest->requestedFormatId))
{
/* proxy's client needs to return a failed response directly to the client */
CLIPRDR_FORMAT_DATA_RESPONSE resp;
CLIPRDR_FORMAT_DATA_RESPONSE resp = { 0 };
CliprdrClientContext* client;
WINPR_ASSERT(pdata->pc);
client = pdata->pc->cliprdr;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientFormatDataResponse);
pf_cliprdr_create_failed_format_data_response(&resp);
return client->ClientFormatDataResponse(client, &resp);
}
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerFormatDataRequest);
return server->ServerFormatDataRequest(server, formatDataRequest);
}
@ -355,8 +592,21 @@ static UINT
pf_cliprdr_ServerFormatDataResponse(CliprdrClientContext* context,
const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(formatDataResponse);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerFormatDataResponse);
WLog_VRB(TAG, __FUNCTION__);
if (pf_cliprdr_is_text_format(server->lastRequestedFormatId))
@ -377,8 +627,21 @@ static UINT
pf_cliprdr_ServerFileContentsRequest(CliprdrClientContext* context,
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(fileContentsRequest);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerFileContentsRequest);
WLog_VRB(TAG, __FUNCTION__);
if (pdata->config->TextOnly)
@ -391,8 +654,21 @@ static UINT
pf_cliprdr_ServerFileContentsResponse(CliprdrClientContext* context,
const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
{
proxyData* pdata = (proxyData*)context->custom;
CliprdrServerContext* server = pdata->ps->cliprdr;
CliprdrServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(fileContentsResponse);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->config);
WINPR_ASSERT(pdata->ps);
server = pdata->ps->cliprdr;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerFileContentsResponse);
WLog_VRB(TAG, __FUNCTION__);
if (pdata->config->TextOnly)
@ -404,6 +680,10 @@ pf_cliprdr_ServerFileContentsResponse(CliprdrClientContext* context,
void pf_cliprdr_register_callbacks(CliprdrClientContext* cliprdr_client,
CliprdrServerContext* cliprdr_server, proxyData* pdata)
{
WINPR_ASSERT(cliprdr_client);
WINPR_ASSERT(cliprdr_server);
WINPR_ASSERT(pdata);
/* Set server and client side references to proxy data */
cliprdr_server->custom = (void*)pdata;
cliprdr_client->custom = (void*)pdata;

View File

@ -24,7 +24,7 @@
#include <freerdp/client/cliprdr.h>
#include <freerdp/server/cliprdr.h>
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
BOOL pf_server_cliprdr_init(pServerContext* ps);
void pf_cliprdr_register_callbacks(CliprdrClientContext* cliprdr_client,

View File

@ -24,15 +24,18 @@
#include <winpr/collections.h>
#include <winpr/cmdline.h>
#include "pf_log.h"
#include "pf_server.h"
#include "pf_config.h"
#include "pf_modules.h"
#include <freerdp/server/proxy/proxy_config.h>
#include <freerdp/server/proxy/proxy_config.h>
#include <freerdp/server/proxy/proxy_log.h>
#define TAG PROXY_TAG("config")
#define CONFIG_PRINT_SECTION(section) WLog_INFO(TAG, "\t%s:", section)
#define CONFIG_PRINT_STR(config, key) WLog_INFO(TAG, "\t\t%s: %s", #key, config->key)
#define CONFIG_PRINT_STR_CONTENT(config, key) \
WLog_INFO(TAG, "\t\t%s: %s", #key, config->key ? "set" : NULL)
#define CONFIG_PRINT_BOOL(config, key) \
WLog_INFO(TAG, "\t\t%s: %s", #key, config->key ? "TRUE" : "FALSE")
#define CONFIG_PRINT_UINT16(config, key) WLog_INFO(TAG, "\t\t%s: %" PRIu16 "", #key, config->key)
@ -52,12 +55,22 @@ static char** pf_config_parse_comma_separated_list(const char* list, size_t* cou
return CommandLineParseCommaSeparatedValues(list, count);
}
BOOL pf_config_get_uint16(wIniFile* ini, const char* section, const char* key, UINT16* result)
static BOOL pf_config_get_uint16(wIniFile* ini, const char* section, const char* key,
UINT16* result, BOOL required)
{
int val;
const char* strval;
WINPR_ASSERT(result);
strval = IniFile_GetKeyValueString(ini, section, key);
if (!strval && required)
{
WLog_ERR(TAG, "[%s]: key '%s.%s' does not exist.", __FUNCTION__, section, key);
return FALSE;
}
val = IniFile_GetKeyValueInt(ini, section, key);
if ((val < 0) || (val > UINT16_MAX))
if ((val <= 0) || (val > UINT16_MAX))
{
WLog_ERR(TAG, "[%s]: invalid value %d for key '%s.%s'.", __FUNCTION__, val, section, key);
return FALSE;
@ -67,9 +80,20 @@ BOOL pf_config_get_uint16(wIniFile* ini, const char* section, const char* key, U
return TRUE;
}
BOOL pf_config_get_uint32(wIniFile* ini, const char* section, const char* key, UINT32* result)
static BOOL pf_config_get_uint32(wIniFile* ini, const char* section, const char* key,
UINT32* result, BOOL required)
{
int val;
const char* strval;
WINPR_ASSERT(result);
strval = IniFile_GetKeyValueString(ini, section, key);
if (!strval && required)
{
WLog_ERR(TAG, "[%s]: key '%s.%s' does not exist.", __FUNCTION__, section, key);
return FALSE;
}
val = IniFile_GetKeyValueInt(ini, section, key);
if ((val < 0) || (val > INT32_MAX))
@ -82,7 +106,7 @@ BOOL pf_config_get_uint32(wIniFile* ini, const char* section, const char* key, U
return TRUE;
}
BOOL pf_config_get_bool(wIniFile* ini, const char* section, const char* key)
static BOOL pf_config_get_bool(wIniFile* ini, const char* section, const char* key, BOOL fallback)
{
int num_value;
const char* str_value;
@ -90,23 +114,26 @@ BOOL pf_config_get_bool(wIniFile* ini, const char* section, const char* key)
str_value = IniFile_GetKeyValueString(ini, section, key);
if (!str_value)
{
WLog_WARN(TAG, "[%s]: key '%s.%s' not found, value defaults to false.", __FUNCTION__,
section, key);
return FALSE;
WLog_WARN(TAG, "[%s]: key '%s.%s' not found, value defaults to %s.", __FUNCTION__, section,
key, fallback ? "true" : "false");
return fallback;
}
if (strcmp(str_value, "TRUE") == 0 || strcmp(str_value, "true") == 0)
if (_stricmp(str_value, "TRUE") == 0)
return TRUE;
if (_stricmp(str_value, "FALSE") == 0)
return FALSE;
num_value = IniFile_GetKeyValueInt(ini, section, key);
if (num_value == 1)
if (num_value != 0)
return TRUE;
return FALSE;
}
const char* pf_config_get_str(wIniFile* ini, const char* section, const char* key)
static const char* pf_config_get_str(wIniFile* ini, const char* section, const char* key,
BOOL required)
{
const char* value;
@ -114,6 +141,7 @@ const char* pf_config_get_str(wIniFile* ini, const char* section, const char* ke
if (!value)
{
if (required)
WLog_ERR(TAG, "[%s]: key '%s.%s' not found.", __FUNCTION__, section, key);
return NULL;
}
@ -125,19 +153,20 @@ static BOOL pf_config_load_server(wIniFile* ini, proxyConfig* config)
{
const char* host;
if (!pf_config_get_uint16(ini, "Server", "Port", &config->Port))
return FALSE;
host = pf_config_get_str(ini, "Server", "Host");
WINPR_ASSERT(config);
host = pf_config_get_str(ini, "Server", "Host", FALSE);
if (!host)
return FALSE;
return TRUE;
config->Host = _strdup(host);
if (!config->Host)
return FALSE;
if (!pf_config_get_uint16(ini, "Server", "Port", &config->Port, TRUE))
return FALSE;
return TRUE;
}
@ -145,10 +174,13 @@ static BOOL pf_config_load_target(wIniFile* ini, proxyConfig* config)
{
const char* target_host;
if (!pf_config_get_uint16(ini, "Target", "Port", &config->TargetPort))
WINPR_ASSERT(config);
config->FixedTarget = pf_config_get_bool(ini, "Target", "FixedTarget", FALSE);
if (!pf_config_get_uint16(ini, "Target", "Port", &config->TargetPort, config->FixedTarget))
return FALSE;
target_host = pf_config_get_str(ini, "Target", "Host");
target_host = pf_config_get_str(ini, "Target", "Host", config->FixedTarget);
if (!target_host)
return FALSE;
@ -157,19 +189,22 @@ static BOOL pf_config_load_target(wIniFile* ini, proxyConfig* config)
if (!config->TargetHost)
return FALSE;
config->FixedTarget = pf_config_get_bool(ini, "Target", "FixedTarget");
return TRUE;
}
static BOOL pf_config_load_channels(wIniFile* ini, proxyConfig* config)
{
config->GFX = pf_config_get_bool(ini, "Channels", "GFX");
config->DisplayControl = pf_config_get_bool(ini, "Channels", "DisplayControl");
config->Clipboard = pf_config_get_bool(ini, "Channels", "Clipboard");
config->AudioOutput = pf_config_get_bool(ini, "Channels", "AudioOutput");
config->RemoteApp = pf_config_get_bool(ini, "Channels", "RemoteApp");
WINPR_ASSERT(config);
config->GFX = pf_config_get_bool(ini, "Channels", "GFX", TRUE);
config->DisplayControl = pf_config_get_bool(ini, "Channels", "DisplayControl", TRUE);
config->Clipboard = pf_config_get_bool(ini, "Channels", "Clipboard", FALSE);
config->AudioOutput = pf_config_get_bool(ini, "Channels", "AudioOutput", TRUE);
config->RemoteApp = pf_config_get_bool(ini, "Channels", "RemoteApp", FALSE);
config->PassthroughIsBlacklist =
pf_config_get_bool(ini, "Channels", "PassthroughIsBlacklist", FALSE);
config->Passthrough = pf_config_parse_comma_separated_list(
pf_config_get_str(ini, "Channels", "Passthrough"), &config->PassthroughCount);
pf_config_get_str(ini, "Channels", "Passthrough", FALSE), &config->PassthroughCount);
{
/* validate channel name length */
@ -177,7 +212,8 @@ static BOOL pf_config_load_channels(wIniFile* ini, proxyConfig* config)
for (i = 0; i < config->PassthroughCount; i++)
{
if (strlen(config->Passthrough[i]) > CHANNEL_NAME_LEN)
const char* name = config->Passthrough[i];
if (strlen(name) > CHANNEL_NAME_LEN)
{
WLog_ERR(TAG, "passthrough channel: %s: name too long!", config->Passthrough[i]);
return FALSE;
@ -190,29 +226,33 @@ static BOOL pf_config_load_channels(wIniFile* ini, proxyConfig* config)
static BOOL pf_config_load_input(wIniFile* ini, proxyConfig* config)
{
config->Keyboard = pf_config_get_bool(ini, "Input", "Keyboard");
config->Mouse = pf_config_get_bool(ini, "Input", "Mouse");
WINPR_ASSERT(config);
config->Keyboard = pf_config_get_bool(ini, "Input", "Keyboard", TRUE);
config->Mouse = pf_config_get_bool(ini, "Input", "Mouse", TRUE);
return TRUE;
}
static BOOL pf_config_load_security(wIniFile* ini, proxyConfig* config)
{
config->ServerTlsSecurity = pf_config_get_bool(ini, "Security", "ServerTlsSecurity");
config->ServerRdpSecurity = pf_config_get_bool(ini, "Security", "ServerRdpSecurity");
WINPR_ASSERT(config);
config->ServerTlsSecurity = pf_config_get_bool(ini, "Security", "ServerTlsSecurity", TRUE);
config->ServerNlaSecurity = pf_config_get_bool(ini, "Security", "ServerNlaSecurity", FALSE);
config->ServerRdpSecurity = pf_config_get_bool(ini, "Security", "ServerRdpSecurity", TRUE);
config->ClientTlsSecurity = pf_config_get_bool(ini, "Security", "ClientTlsSecurity");
config->ClientNlaSecurity = pf_config_get_bool(ini, "Security", "ClientNlaSecurity");
config->ClientRdpSecurity = pf_config_get_bool(ini, "Security", "ClientRdpSecurity");
config->ClientTlsSecurity = pf_config_get_bool(ini, "Security", "ClientTlsSecurity", TRUE);
config->ClientNlaSecurity = pf_config_get_bool(ini, "Security", "ClientNlaSecurity", TRUE);
config->ClientRdpSecurity = pf_config_get_bool(ini, "Security", "ClientRdpSecurity", TRUE);
config->ClientAllowFallbackToTls =
pf_config_get_bool(ini, "Security", "ClientAllowFallbackToTls");
pf_config_get_bool(ini, "Security", "ClientAllowFallbackToTls", TRUE);
return TRUE;
}
static BOOL pf_config_load_clipboard(wIniFile* ini, proxyConfig* config)
{
config->TextOnly = pf_config_get_bool(ini, "Clipboard", "TextOnly");
WINPR_ASSERT(config);
config->TextOnly = pf_config_get_bool(ini, "Clipboard", "TextOnly", FALSE);
if (!pf_config_get_uint32(ini, "Clipboard", "MaxTextLength", &config->MaxTextLength))
if (!pf_config_get_uint32(ini, "Clipboard", "MaxTextLength", &config->MaxTextLength, FALSE))
return FALSE;
return TRUE;
@ -226,6 +266,7 @@ static BOOL pf_config_load_modules(wIniFile* ini, proxyConfig* config)
modules_to_load = IniFile_GetKeyValueString(ini, "Plugins", "Modules");
required_modules = IniFile_GetKeyValueString(ini, "Plugins", "Required");
WINPR_ASSERT(config);
config->Modules = pf_config_parse_comma_separated_list(modules_to_load, &config->ModulesCount);
config->RequiredPlugins =
@ -235,29 +276,131 @@ static BOOL pf_config_load_modules(wIniFile* ini, proxyConfig* config)
static BOOL pf_config_load_gfx_settings(wIniFile* ini, proxyConfig* config)
{
config->DecodeGFX = pf_config_get_bool(ini, "GFXSettings", "DecodeGFX");
WINPR_ASSERT(config);
config->DecodeGFX = pf_config_get_bool(ini, "GFXSettings", "DecodeGFX", FALSE);
return TRUE;
}
proxyConfig* pf_server_config_load(const char* path)
static BOOL pf_config_load_certificates(wIniFile* ini, proxyConfig* config)
{
proxyConfig* config = NULL;
wIniFile* ini = IniFile_New();
const char* tmp1;
const char* tmp2;
if (!ini)
WINPR_ASSERT(ini);
WINPR_ASSERT(config);
tmp1 = pf_config_get_str(ini, "Certificates", "CertificateFile", FALSE);
if (tmp1)
{
WLog_ERR(TAG, "[%s]: IniFile_New() failed!", __FUNCTION__);
if (!winpr_PathFileExists(tmp1))
{
WLog_ERR(TAG, "Certificates/CertificateFile file %s does not exist", tmp1);
return FALSE;
}
config->CertificateFile = _strdup(tmp1);
}
tmp2 = pf_config_get_str(ini, "Certificates", "CertificateContent", FALSE);
if (tmp2)
{
if (strlen(tmp2) < 1)
{
WLog_ERR(TAG, "Certificates/CertificateContent has invalid empty value");
return FALSE;
}
config->CertificateContent = _strdup(tmp2);
}
if (tmp1 && tmp2)
{
WLog_ERR(TAG, "Certificates/CertificateFile and Certificates/CertificateContent are "
"mutually exclusive options");
return FALSE;
}
else if (!tmp1 && !tmp2)
{
WLog_ERR(TAG, "Certificates/CertificateFile or Certificates/CertificateContent are "
"required settings");
return FALSE;
}
if (IniFile_ReadFile(ini, path) < 0)
tmp1 = pf_config_get_str(ini, "Certificates", "PrivateKeyFile", FALSE);
if (tmp1)
{
WLog_ERR(TAG, "[%s] failed to parse ini file: '%s'", __FUNCTION__, path);
goto out;
if (!winpr_PathFileExists(tmp1))
{
WLog_ERR(TAG, "Certificates/PrivateKeyFile file %s does not exist", tmp1);
return FALSE;
}
config->PrivateKeyFile = _strdup(tmp1);
}
tmp2 = pf_config_get_str(ini, "Certificates", "PrivateKeyContent", FALSE);
if (tmp2)
{
if (strlen(tmp2) < 1)
{
WLog_ERR(TAG, "Certificates/PrivateKeyContent has invalid empty value");
return FALSE;
}
config->PrivateKeyContent = _strdup(tmp2);
}
config = calloc(1, sizeof(proxyConfig));
if (tmp1 && tmp2)
{
WLog_ERR(TAG, "Certificates/PrivateKeyFile and Certificates/PrivateKeyContent are "
"mutually exclusive options");
return FALSE;
}
else if (!tmp1 && !tmp2)
{
WLog_ERR(TAG, "Certificates/PrivateKeyFile or Certificates/PrivateKeyContent are "
"are required settings");
return FALSE;
}
tmp1 = pf_config_get_str(ini, "Certificates", "RdpKeyFile", FALSE);
if (tmp1)
{
if (!winpr_PathFileExists(tmp1))
{
WLog_ERR(TAG, "Certificates/RdpKeyFile file %s does not exist", tmp1);
return FALSE;
}
config->RdpKeyFile = _strdup(tmp1);
}
tmp2 = pf_config_get_str(ini, "Certificates", "RdpKeyContent", FALSE);
if (tmp2)
{
if (strlen(tmp2) < 1)
{
WLog_ERR(TAG, "Certificates/RdpKeyContent has invalid empty value");
return FALSE;
}
config->RdpKeyContent = _strdup(tmp2);
}
if (tmp1 && tmp2)
{
WLog_ERR(TAG, "Certificates/RdpKeyFile and Certificates/RdpKeyContent are mutually "
"exclusive options");
return FALSE;
}
else if (!tmp1 && !tmp2)
{
WLog_ERR(TAG, "Certificates/RdpKeyFile or Certificates/RdpKeyContent are "
"required settings");
return FALSE;
}
return TRUE;
}
proxyConfig* server_config_load_ini(wIniFile* ini)
{
proxyConfig* config = NULL;
WINPR_ASSERT(ini);
config = calloc(1, sizeof(proxyConfig));
if (config)
{
if (!pf_config_load_server(ini, config))
goto out;
@ -282,25 +425,77 @@ proxyConfig* pf_server_config_load(const char* path)
if (!pf_config_load_gfx_settings(ini, config))
goto out;
IniFile_Free(ini);
if (!pf_config_load_certificates(ini, config))
goto out;
}
return config;
out:
IniFile_Free(ini);
pf_server_config_free(config);
return NULL;
}
proxyConfig* pf_server_config_load_buffer(const char* buffer)
{
proxyConfig* config = NULL;
wIniFile* ini;
ini = IniFile_New();
if (!ini)
{
WLog_ERR(TAG, "[%s]: IniFile_New() failed!", __FUNCTION__);
return NULL;
}
if (IniFile_ReadBuffer(ini, buffer) < 0)
{
WLog_ERR(TAG, "[%s] failed to parse ini: '%s'", __FUNCTION__, buffer);
goto out;
}
config = server_config_load_ini(ini);
out:
IniFile_Free(ini);
return config;
}
proxyConfig* pf_server_config_load_file(const char* path)
{
proxyConfig* config = NULL;
wIniFile* ini = IniFile_New();
if (!ini)
{
WLog_ERR(TAG, "[%s]: IniFile_New() failed!", __FUNCTION__);
return NULL;
}
if (IniFile_ReadFile(ini, path) < 0)
{
WLog_ERR(TAG, "[%s] failed to parse ini file: '%s'", __FUNCTION__, path);
goto out;
}
config = server_config_load_ini(ini);
out:
IniFile_Free(ini);
return config;
}
static void pf_server_config_print_list(char** list, size_t count)
{
size_t i;
WINPR_ASSERT(list);
for (i = 0; i < count; i++)
WLog_INFO(TAG, "\t\t- %s", list[i]);
}
void pf_server_config_print(proxyConfig* config)
void pf_server_config_print(const proxyConfig* config)
{
size_t x;
WINPR_ASSERT(config);
WLog_INFO(TAG, "Proxy configuration:");
CONFIG_PRINT_SECTION("Server");
@ -334,6 +529,7 @@ void pf_server_config_print(proxyConfig* config)
CONFIG_PRINT_BOOL(config, Clipboard);
CONFIG_PRINT_BOOL(config, AudioOutput);
CONFIG_PRINT_BOOL(config, RemoteApp);
CONFIG_PRINT_BOOL(config, PassthroughIsBlacklist);
if (config->PassthroughCount)
{
@ -348,6 +544,24 @@ void pf_server_config_print(proxyConfig* config)
CONFIG_PRINT_SECTION("GFXSettings");
CONFIG_PRINT_BOOL(config, DecodeGFX);
/* modules */
CONFIG_PRINT_SECTION("Plugins/Modules");
for (x = 0; x < config->ModulesCount; x++)
CONFIG_PRINT_STR(config, Modules[x]);
/* Required plugins */
CONFIG_PRINT_SECTION("Plugins/Required");
for (x = 0; x < config->RequiredPluginsCount; x++)
CONFIG_PRINT_STR(config, RequiredPlugins[x]);
CONFIG_PRINT_SECTION("Certificates");
CONFIG_PRINT_STR(config, CertificateFile);
CONFIG_PRINT_STR_CONTENT(config, CertificateContent);
CONFIG_PRINT_STR(config, PrivateKeyFile);
CONFIG_PRINT_STR_CONTENT(config, PrivateKeyContent);
CONFIG_PRINT_STR(config, RdpKeyFile);
CONFIG_PRINT_STR_CONTENT(config, RdpKeyContent);
}
void pf_server_config_free(proxyConfig* config)
@ -360,5 +574,113 @@ void pf_server_config_free(proxyConfig* config)
free(config->Modules);
free(config->TargetHost);
free(config->Host);
free(config->CertificateFile);
free(config->CertificateContent);
free(config->PrivateKeyFile);
free(config->PrivateKeyContent);
free(config->RdpKeyFile);
free(config->RdpKeyContent);
free(config);
}
size_t pf_config_required_plugins_count(const proxyConfig* config)
{
WINPR_ASSERT(config);
return config->RequiredPluginsCount;
}
const char* pf_config_required_plugin(const proxyConfig* config, size_t index)
{
WINPR_ASSERT(config);
if (index >= config->RequiredPluginsCount)
return NULL;
return config->RequiredPlugins[index];
}
size_t pf_config_modules_count(const proxyConfig* config)
{
WINPR_ASSERT(config);
return config->ModulesCount;
}
const char** pf_config_modules(const proxyConfig* config)
{
WINPR_ASSERT(config);
return config->Modules;
}
static BOOL pf_config_copy_string(char** dst, const char* src)
{
*dst = NULL;
if (src)
*dst = _strdup(src);
return TRUE;
}
static BOOL pf_config_copy_string_list(char*** dst, size_t* size, char** src, size_t srcSize)
{
WINPR_ASSERT(dst);
WINPR_ASSERT(size);
WINPR_ASSERT(src || (srcSize == 0));
*dst = NULL;
*size = 0;
if (srcSize == 0)
return TRUE;
{
char* csv = CommandLineToCommaSeparatedValues(srcSize, src);
*dst = CommandLineParseCommaSeparatedValues(csv, size);
free(csv);
}
return TRUE;
}
BOOL pf_config_clone(proxyConfig** dst, const proxyConfig* config)
{
proxyConfig* tmp = calloc(1, sizeof(proxyConfig));
WINPR_ASSERT(dst);
WINPR_ASSERT(config);
if (!tmp)
return FALSE;
*tmp = *config;
if (!pf_config_copy_string(&tmp->Host, config->Host))
goto fail;
if (!pf_config_copy_string(&tmp->TargetHost, config->TargetHost))
goto fail;
if (!pf_config_copy_string_list(&tmp->Passthrough, &tmp->PassthroughCount, config->Passthrough,
config->PassthroughCount))
goto fail;
if (!pf_config_copy_string_list(&tmp->Modules, &tmp->ModulesCount, config->Modules,
config->ModulesCount))
goto fail;
if (!pf_config_copy_string_list(&tmp->RequiredPlugins, &tmp->RequiredPluginsCount,
config->RequiredPlugins, config->RequiredPluginsCount))
goto fail;
if (!pf_config_copy_string(&tmp->CertificateFile, config->CertificateFile))
goto fail;
if (!pf_config_copy_string(&tmp->CertificateContent, config->CertificateContent))
goto fail;
if (!pf_config_copy_string(&tmp->PrivateKeyFile, config->PrivateKeyFile))
goto fail;
if (!pf_config_copy_string(&tmp->PrivateKeyContent, config->PrivateKeyContent))
goto fail;
if (!pf_config_copy_string(&tmp->RdpKeyFile, config->RdpKeyFile))
goto fail;
if (!pf_config_copy_string(&tmp->RdpKeyContent, config->RdpKeyContent))
goto fail;
*dst = tmp;
return TRUE;
fail:
pf_server_config_free(tmp);
return FALSE;
}

View File

@ -1,101 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
*
* 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_PFCONFIG_H
#define FREERDP_SERVER_PROXY_PFCONFIG_H
#include <freerdp/api.h>
#include <winpr/ini.h>
#include <winpr/path.h>
typedef struct proxy_config proxyConfig;
struct proxy_config
{
/* server */
char* Host;
UINT16 Port;
/* target */
BOOL FixedTarget;
char* TargetHost;
UINT16 TargetPort;
/* input */
BOOL Keyboard;
BOOL Mouse;
/* server security */
BOOL ServerTlsSecurity;
BOOL ServerRdpSecurity;
/* client security */
BOOL ClientNlaSecurity;
BOOL ClientTlsSecurity;
BOOL ClientRdpSecurity;
BOOL ClientAllowFallbackToTls;
/* channels */
BOOL GFX;
BOOL DisplayControl;
BOOL Clipboard;
BOOL AudioOutput;
BOOL RemoteApp;
char** Passthrough;
size_t PassthroughCount;
/* clipboard specific settings */
BOOL TextOnly;
UINT32 MaxTextLength;
/* gfx settings */
BOOL DecodeGFX;
/* modules */
char** Modules; /* module file names to load */
size_t ModulesCount;
char** RequiredPlugins; /* required plugin names */
size_t RequiredPluginsCount;
};
typedef struct proxy_config proxyConfig;
#ifdef __cplusplus
extern "C"
{
#endif
FREERDP_API BOOL pf_config_get_uint16(wIniFile* ini, const char* section, const char* key,
UINT16* result);
FREERDP_API BOOL pf_config_get_uint32(wIniFile* ini, const char* section, const char* key,
UINT32* result);
FREERDP_API BOOL pf_config_get_bool(wIniFile* ini, const char* section, const char* key);
FREERDP_API const char* pf_config_get_str(wIniFile* ini, const char* section, const char* key);
#ifdef __cplusplus
};
#endif
proxyConfig* pf_server_config_load(const char* path);
void pf_server_config_print(proxyConfig* config);
void pf_server_config_free(proxyConfig* config);
#endif /* FREERDP_SERVER_PROXY_PFCONFIG_H */

View File

@ -22,30 +22,18 @@
#include <winpr/crypto.h>
#include <winpr/print.h>
#include <freerdp/server/proxy/proxy_server.h>
#include "pf_client.h"
#include "pf_context.h"
static wHashTable* create_channel_ids_map()
{
wHashTable* table = HashTable_New(TRUE);
if (!table)
return NULL;
if (!HashTable_SetupForStringData(table, FALSE))
goto fail;
return table;
fail:
HashTable_Free(table);
return NULL;
}
#include <freerdp/server/proxy/proxy_context.h>
/* Proxy context initialization callback */
static BOOL client_to_proxy_context_new(freerdp_peer* client, rdpContext* ctx)
{
pServerContext* context = (pServerContext*)ctx;
proxyServer* server = (proxyServer*)client->ContextExtra;
proxyConfig* config = server->config;
WINPR_ASSERT(client);
WINPR_ASSERT(context);
context->dynvcReady = NULL;
@ -57,14 +45,6 @@ static BOOL client_to_proxy_context_new(freerdp_peer* client, rdpContext* ctx)
if (!(context->dynvcReady = CreateEvent(NULL, TRUE, FALSE, NULL)))
goto error;
context->vc_handles = (HANDLE*)calloc(config->PassthroughCount, sizeof(HANDLE));
if (!context->vc_handles)
goto error;
context->vc_ids = create_channel_ids_map();
if (!context->vc_ids)
goto error;
return TRUE;
error:
@ -77,10 +57,6 @@ error:
context->dynvcReady = NULL;
}
free(context->vc_handles);
context->vc_handles = NULL;
HashTable_Free(context->vc_ids);
context->vc_ids = NULL;
return FALSE;
}
@ -99,13 +75,12 @@ static void client_to_proxy_context_free(freerdp_peer* client, rdpContext* ctx)
CloseHandle(context->dynvcReady);
context->dynvcReady = NULL;
}
HashTable_Free(context->vc_ids);
free(context->vc_handles);
}
BOOL pf_context_init_server_context(freerdp_peer* client)
{
WINPR_ASSERT(client);
client->ContextSize = sizeof(pServerContext);
client->ContextNew = client_to_proxy_context_new;
client->ContextFree = client_to_proxy_context_free;
@ -113,10 +88,33 @@ BOOL pf_context_init_server_context(freerdp_peer* client)
return freerdp_peer_context_new(client);
}
static BOOL pf_context_revert_str_settings(rdpSettings* dst, const rdpSettings* before, size_t nr,
const size_t* ids)
{
size_t x;
WINPR_ASSERT(dst);
WINPR_ASSERT(before);
WINPR_ASSERT(ids || (nr == 0));
for (x = 0; x < nr; x++)
{
size_t id = ids[x];
const char* what = freerdp_settings_get_string(before, id);
if (!freerdp_settings_set_string(dst, id, what))
return FALSE;
}
return TRUE;
}
BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src)
{
BOOL rc = FALSE;
rdpSettings* before_copy;
const size_t to_revert[] = { FreeRDP_ConfigPath, FreeRDP_PrivateKeyContent,
FreeRDP_RdpKeyContent, FreeRDP_RdpKeyFile,
FreeRDP_PrivateKeyFile, FreeRDP_CertificateFile,
FreeRDP_CertificateName, FreeRDP_CertificateContent };
if (!dst || !src)
return FALSE;
@ -125,12 +123,6 @@ BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src)
if (!before_copy)
return FALSE;
#define REVERT_STR_VALUE(name) \
free(dst->name); \
dst->name = NULL; \
if (before_copy->name && !(dst->name = _strdup(before_copy->name))) \
goto out_fail
if (!freerdp_settings_copy(dst, src))
{
freerdp_settings_free(before_copy);
@ -141,14 +133,8 @@ BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src)
dst->ServerMode = before_copy->ServerMode;
/* revert some values that must not be changed */
REVERT_STR_VALUE(ConfigPath);
REVERT_STR_VALUE(PrivateKeyContent);
REVERT_STR_VALUE(RdpKeyContent);
REVERT_STR_VALUE(RdpKeyFile);
REVERT_STR_VALUE(PrivateKeyFile);
REVERT_STR_VALUE(CertificateFile);
REVERT_STR_VALUE(CertificateName);
REVERT_STR_VALUE(CertificateContent);
if (!pf_context_revert_str_settings(dst, before_copy, ARRAYSIZE(to_revert), to_revert))
return FALSE;
if (!dst->ServerMode)
{
@ -160,13 +146,13 @@ BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src)
* it must be freed before setting it to NULL to avoid a memory leak!
*/
free(dst->RdpServerRsaKey->Modulus);
free(dst->RdpServerRsaKey->PrivateExponent);
free(dst->RdpServerRsaKey);
dst->RdpServerRsaKey = NULL;
if (!freerdp_settings_set_pointer_len(dst, FreeRDP_RdpServerRsaKey, NULL,
sizeof(rdpRsaKey)))
goto out_fail;
}
rc = TRUE;
/* We handle certificate management for this client ourselfes. */
rc = freerdp_settings_set_bool(dst, FreeRDP_ExternalCertificateManagement, TRUE);
out_fail:
freerdp_settings_free(before_copy);
@ -178,6 +164,9 @@ pClientContext* pf_context_create_client_context(rdpSettings* clientSettings)
RDP_CLIENT_ENTRY_POINTS clientEntryPoints;
pClientContext* pc;
rdpContext* context;
WINPR_ASSERT(clientSettings);
RdpClientEntry(&clientEntryPoints);
context = freerdp_client_context_new(&clientEntryPoints);
@ -189,10 +178,6 @@ pClientContext* pf_context_create_client_context(rdpSettings* clientSettings)
if (!pf_context_copy_settings(context->settings, clientSettings))
goto error;
pc->vc_ids = create_channel_ids_map();
if (!pc->vc_ids)
goto error;
return pc;
error:
freerdp_client_context_free(context);
@ -240,6 +225,8 @@ error:
/* updates circular pointers between proxyData and pClientContext instances */
void proxy_data_set_client_context(proxyData* pdata, pClientContext* context)
{
WINPR_ASSERT(pdata);
WINPR_ASSERT(context);
pdata->pc = context;
context->pdata = pdata;
}
@ -247,29 +234,25 @@ void proxy_data_set_client_context(proxyData* pdata, pClientContext* context)
/* updates circular pointers between proxyData and pServerContext instances */
void proxy_data_set_server_context(proxyData* pdata, pServerContext* context)
{
WINPR_ASSERT(pdata);
WINPR_ASSERT(context);
pdata->ps = context;
context->pdata = pdata;
}
void proxy_data_free(proxyData* pdata)
{
if (!pdata)
return;
if (pdata->abort_event)
{
CloseHandle(pdata->abort_event);
pdata->abort_event = NULL;
}
if (pdata->client_thread)
{
CloseHandle(pdata->client_thread);
pdata->client_thread = NULL;
}
if (pdata->gfx_server_ready)
{
CloseHandle(pdata->gfx_server_ready);
pdata->gfx_server_ready = NULL;
}
if (pdata->modules_info)
HashTable_Free(pdata->modules_info);
@ -279,10 +262,14 @@ void proxy_data_free(proxyData* pdata)
void proxy_data_abort_connect(proxyData* pdata)
{
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->abort_event);
SetEvent(pdata->abort_event);
}
BOOL proxy_data_shall_disconnect(proxyData* pdata)
{
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->abort_event);
return WaitForSingleObject(pdata->abort_event, 0) == WAIT_OBJECT_0;
}

View File

@ -17,16 +17,18 @@
* limitations under the License.
*/
#include <winpr/assert.h>
#include <freerdp/server/disp.h>
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_disp.h"
#include "pf_log.h"
#define TAG PROXY_TAG("disp")
BOOL pf_server_disp_init(pServerContext* ps)
{
DispServerContext* disp;
WINPR_ASSERT(ps);
disp = ps->disp = disp_server_context_new(ps->vcm);
if (!disp)
@ -41,8 +43,20 @@ BOOL pf_server_disp_init(pServerContext* ps)
static UINT pf_disp_monitor_layout(DispServerContext* context,
const DISPLAY_CONTROL_MONITOR_LAYOUT_PDU* pdu)
{
proxyData* pdata = (proxyData*)context->custom;
DispClientContext* client = (DispClientContext*)pdata->pc->disp;
proxyData* pdata;
DispClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(pdu);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (DispClientContext*)pdata->pc->disp;
WINPR_ASSERT(client);
WINPR_ASSERT(client->SendMonitorLayout);
WLog_DBG(TAG, __FUNCTION__);
return client->SendMonitorLayout(client, pdu->NumMonitors, pdu->Monitors);
}
@ -50,9 +64,21 @@ static UINT pf_disp_monitor_layout(DispServerContext* context,
static UINT pf_disp_on_caps_control(DispClientContext* context, UINT32 MaxNumMonitors,
UINT32 MaxMonitorAreaFactorA, UINT32 MaxMonitorAreaFactorB)
{
proxyData* pdata = (proxyData*)context->custom;
DispServerContext* server = (DispServerContext*)pdata->ps->disp;
DispServerContext* server;
proxyData* pdata;
WINPR_ASSERT(context);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
server = (DispServerContext*)pdata->ps->disp;
WINPR_ASSERT(server);
WINPR_ASSERT(server->DisplayControlCaps);
WLog_DBG(TAG, __FUNCTION__);
/* Update caps of proxy's disp server */
server->MaxMonitorAreaFactorA = MaxMonitorAreaFactorA;
server->MaxMonitorAreaFactorB = MaxMonitorAreaFactorB;
@ -64,6 +90,10 @@ static UINT pf_disp_on_caps_control(DispClientContext* context, UINT32 MaxNumMon
void pf_disp_register_callbacks(DispClientContext* client, DispServerContext* server,
proxyData* pdata)
{
WINPR_ASSERT(client);
WINPR_ASSERT(server);
WINPR_ASSERT(pdata);
client->custom = (void*)pdata;
server->custom = (void*)pdata;
/* client receives from server, forward using disp server to original client */

View File

@ -23,7 +23,7 @@
#include <freerdp/client/disp.h>
#include <freerdp/server/disp.h>
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
BOOL pf_server_disp_init(pServerContext* ps);
void pf_disp_register_callbacks(DispClientContext* client, DispServerContext* server,

View File

@ -23,6 +23,8 @@
#include "config.h"
#endif
#include <winpr/assert.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/codec/nsc.h>
@ -30,39 +32,55 @@
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
#include <freerdp/freerdp.h>
#include "pf_gdi.h"
#include "pf_log.h"
#include <freerdp/log.h>
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_gdi.h"
#define TAG PROXY_TAG("gdi")
/* TODO: Figure how to use functions decleared in update.c */
static BOOL pf_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds)
{
WINPR_ASSERT(context);
WINPR_ASSERT(bounds);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)
{
WINPR_ASSERT(context);
WINPR_ASSERT(dstblt);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
{
WINPR_ASSERT(context);
WINPR_ASSERT(patblt);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)
{
WINPR_ASSERT(context);
WINPR_ASSERT(scrblt);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)
{
WINPR_ASSERT(context);
WINPR_ASSERT(opaque_rect);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
@ -70,42 +88,63 @@ static BOOL pf_gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opa
static BOOL pf_gdi_multi_opaque_rect(rdpContext* context,
const MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
{
WINPR_ASSERT(context);
WINPR_ASSERT(multi_opaque_rect);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_line_to(rdpContext* context, const LINE_TO_ORDER* line_to)
{
WINPR_ASSERT(context);
WINPR_ASSERT(line_to);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline)
{
WINPR_ASSERT(context);
WINPR_ASSERT(polyline);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
{
WINPR_ASSERT(context);
WINPR_ASSERT(memblt);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
{
WINPR_ASSERT(context);
WINPR_ASSERT(mem3blt);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_polygon_sc(rdpContext* context, const POLYGON_SC_ORDER* polygon_sc)
{
WINPR_ASSERT(context);
WINPR_ASSERT(polygon_sc);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
{
WINPR_ASSERT(context);
WINPR_ASSERT(polygon_cb);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
@ -113,19 +152,30 @@ static BOOL pf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
static BOOL pf_gdi_surface_frame_marker(rdpContext* context,
const SURFACE_FRAME_MARKER* surface_frame_marker)
{
WINPR_ASSERT(context);
WINPR_ASSERT(surface_frame_marker);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
static BOOL pf_gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd)
{
WINPR_ASSERT(context);
WINPR_ASSERT(cmd);
WLog_INFO(TAG, __FUNCTION__);
return TRUE;
}
void pf_gdi_register_update_callbacks(rdpUpdate* update)
{
rdpPrimaryUpdate* primary = update->primary;
rdpPrimaryUpdate* primary;
WINPR_ASSERT(update);
primary = update->primary;
WINPR_ASSERT(primary);
update->SetBounds = pf_gdi_set_bounds;
primary->DstBlt = pf_gdi_dstblt;
primary->PatBlt = pf_gdi_patblt;

View File

@ -24,13 +24,15 @@
#endif
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <freerdp/codec/bitmap.h>
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_graphics.h"
#include "pf_log.h"
#include "pf_gdi.h"
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
#include <freerdp/gdi/dc.h>
#include <freerdp/gdi/shape.h>
@ -44,105 +46,139 @@
/* Bitmap Class */
static BOOL pf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
{
WINPR_ASSERT(context);
WINPR_ASSERT(bitmap);
return TRUE;
}
static void pf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
{
WINPR_ASSERT(context);
WINPR_ASSERT(bitmap);
}
static BOOL pf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
{
WINPR_ASSERT(context);
WINPR_ASSERT(bitmap);
return TRUE;
}
static BOOL pf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
{
WINPR_ASSERT(context);
WINPR_ASSERT(bitmap);
return TRUE;
}
/* Pointer Class */
static BOOL pf_Pointer_New(rdpContext* context, rdpPointer* pointer)
{
WINPR_ASSERT(context);
WINPR_ASSERT(pointer);
return TRUE;
}
static void pf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
{
WINPR_ASSERT(context);
WINPR_ASSERT(pointer);
}
static BOOL pf_Pointer_Set(rdpContext* context, const rdpPointer* pointer)
{
WINPR_ASSERT(context);
WINPR_ASSERT(pointer);
return TRUE;
}
static BOOL pf_Pointer_SetNull(rdpContext* context)
{
WINPR_ASSERT(context);
return TRUE;
}
static BOOL pf_Pointer_SetDefault(rdpContext* context)
{
WINPR_ASSERT(context);
return TRUE;
}
static BOOL pf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
{
WINPR_ASSERT(context);
return TRUE;
}
/* Glyph Class */
static BOOL pf_Glyph_New(rdpContext* context, rdpGlyph* glyph)
{
WINPR_ASSERT(context);
WINPR_ASSERT(glyph);
return TRUE;
}
static void pf_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
{
WINPR_ASSERT(context);
WINPR_ASSERT(glyph);
}
static BOOL pf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, INT32 y, INT32 w,
INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
{
WINPR_ASSERT(context);
return TRUE;
}
static BOOL pf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
{
WINPR_ASSERT(context);
return TRUE;
}
static BOOL pf_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
UINT32 bgcolor, UINT32 fgcolor)
{
WINPR_ASSERT(context);
return TRUE;
}
/* Graphics Module */
BOOL pf_register_pointer(rdpGraphics* graphics)
{
rdpPointer* pointer = NULL;
rdpPointer pointer = { 0 };
if (!(pointer = (rdpPointer*)calloc(1, sizeof(rdpPointer))))
return FALSE;
WINPR_ASSERT(graphics);
pointer->size = sizeof(rdpPointer);
pointer->New = pf_Pointer_New;
pointer->Free = pf_Pointer_Free;
pointer->Set = pf_Pointer_Set;
pointer->SetNull = pf_Pointer_SetNull;
pointer->SetDefault = pf_Pointer_SetDefault;
pointer->SetPosition = pf_Pointer_SetPosition;
graphics_register_pointer(graphics, pointer);
free(pointer);
pointer.size = sizeof(rdpPointer);
pointer.New = pf_Pointer_New;
pointer.Free = pf_Pointer_Free;
pointer.Set = pf_Pointer_Set;
pointer.SetNull = pf_Pointer_SetNull;
pointer.SetDefault = pf_Pointer_SetDefault;
pointer.SetPosition = pf_Pointer_SetPosition;
graphics_register_pointer(graphics, &pointer);
return TRUE;
}
BOOL pf_register_graphics(rdpGraphics* graphics)
{
rdpBitmap bitmap;
rdpGlyph glyph;
rdpBitmap bitmap = { 0 };
rdpGlyph glyph = { 0 };
if (!graphics || !graphics->Bitmap_Prototype || !graphics->Glyph_Prototype)
return FALSE;
@ -155,6 +191,7 @@ BOOL pf_register_graphics(rdpGraphics* graphics)
bitmap.Paint = pf_Bitmap_Paint;
bitmap.SetSurface = pf_Bitmap_SetSurface;
graphics_register_bitmap(graphics, &bitmap);
glyph.size = sizeof(rdpGlyph);
glyph.New = pf_Glyph_New;
glyph.Free = pf_Glyph_Free;

View File

@ -19,23 +19,46 @@
* limitations under the License.
*/
#include <winpr/assert.h>
#include "pf_input.h"
#include "pf_context.h"
#include "pf_modules.h"
#include <freerdp/server/proxy/proxy_config.h>
#include <freerdp/server/proxy/proxy_context.h>
#include "proxy_modules.h"
static BOOL pf_server_synchronize_event(rdpInput* input, UINT32 flags)
{
pServerContext* ps = (pServerContext*)input->context;
pClientContext* pc = ps->pdata->pc;
pServerContext* ps;
pClientContext* pc;
WINPR_ASSERT(input);
ps = (pServerContext*)input->context;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
pc = ps->pdata->pc;
WINPR_ASSERT(pc);
return freerdp_input_send_synchronize_event(pc->context.input, flags);
}
static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
{
pServerContext* ps = (pServerContext*)input->context;
pClientContext* pc = ps->pdata->pc;
proxyConfig* config = ps->pdata->config;
const proxyConfig* config;
proxyKeyboardEventInfo event;
pServerContext* ps;
pClientContext* pc;
WINPR_ASSERT(input);
ps = (pServerContext*)input->context;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
pc = ps->pdata->pc;
WINPR_ASSERT(pc);
config = ps->pdata->config;
WINPR_ASSERT(config);
if (!config->Keyboard)
return TRUE;
@ -43,7 +66,7 @@ static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
event.flags = flags;
event.rdp_scan_code = code;
if (pf_modules_run_filter(FILTER_TYPE_KEYBOARD, pc->pdata, &event))
if (pf_modules_run_filter(pc->pdata->module, FILTER_TYPE_KEYBOARD, pc->pdata, &event))
return freerdp_input_send_keyboard_event(pc->context.input, flags, code);
return TRUE;
@ -51,9 +74,20 @@ static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
static BOOL pf_server_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
{
pServerContext* ps = (pServerContext*)input->context;
pClientContext* pc = ps->pdata->pc;
proxyConfig* config = ps->pdata->config;
const proxyConfig* config;
pServerContext* ps;
pClientContext* pc;
WINPR_ASSERT(input);
ps = (pServerContext*)input->context;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
pc = ps->pdata->pc;
WINPR_ASSERT(pc);
config = ps->pdata->config;
WINPR_ASSERT(config);
if (!config->Keyboard)
return TRUE;
@ -63,10 +97,21 @@ 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)
{
pServerContext* ps = (pServerContext*)input->context;
pClientContext* pc = ps->pdata->pc;
proxyConfig* config = ps->pdata->config;
proxyMouseEventInfo event;
const proxyConfig* config;
pServerContext* ps;
pClientContext* pc;
WINPR_ASSERT(input);
ps = (pServerContext*)input->context;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
pc = ps->pdata->pc;
WINPR_ASSERT(pc);
config = ps->pdata->config;
WINPR_ASSERT(config);
if (!config->Mouse)
return TRUE;
@ -75,7 +120,7 @@ static BOOL pf_server_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1
event.x = x;
event.y = y;
if (pf_modules_run_filter(FILTER_TYPE_MOUSE, pc->pdata, &event))
if (pf_modules_run_filter(pc->pdata->module, FILTER_TYPE_MOUSE, pc->pdata, &event))
return freerdp_input_send_mouse_event(pc->context.input, flags, x, y);
return TRUE;
@ -83,9 +128,20 @@ static BOOL pf_server_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1
static BOOL pf_server_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
{
pServerContext* ps = (pServerContext*)input->context;
pClientContext* pc = ps->pdata->pc;
proxyConfig* config = ps->pdata->config;
const proxyConfig* config;
pServerContext* ps;
pClientContext* pc;
WINPR_ASSERT(input);
ps = (pServerContext*)input->context;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
pc = ps->pdata->pc;
WINPR_ASSERT(pc);
config = ps->pdata->config;
WINPR_ASSERT(config);
if (!config->Mouse)
return TRUE;
@ -95,6 +151,8 @@ static BOOL pf_server_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16
void pf_server_register_input_callbacks(rdpInput* input)
{
WINPR_ASSERT(input);
input->SynchronizeEvent = pf_server_synchronize_event;
input->KeyboardEvent = pf_server_keyboard_event;
input->UnicodeKeyboardEvent = pf_server_unicode_keyboard_event;

View File

@ -22,22 +22,27 @@
#include <winpr/file.h>
#include <winpr/wlog.h>
#include <winpr/path.h>
#include <winpr/library.h>
#include <freerdp/api.h>
#include <freerdp/build-config.h>
#include "pf_log.h"
#include "pf_modules.h"
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_log.h>
#include <freerdp/server/proxy/proxy_modules_api.h>
#include <freerdp/server/proxy/proxy_context.h>
#include "proxy_modules.h"
#define TAG PROXY_TAG("modules")
#define MODULE_ENTRY_POINT "proxy_module_entry_point"
static wArrayList* plugins_list = NULL; /* list of all loaded plugins */
static wArrayList* handles_list = NULL; /* list of module handles to free at shutdown */
typedef BOOL (*moduleEntryPoint)(proxyPluginsManager* plugins_manager);
struct proxy_module
{
proxyPluginsManager mgr;
wArrayList* plugins;
wArrayList* handles;
};
static const char* FILTER_TYPE_STRINGS[] = { "KEYBOARD_EVENT", "MOUSE_EVENT", "CLIENT_CHANNEL_DATA",
"SERVER_CHANNEL_DATA", "SERVER_FETCH_TARGET_ADDR" };
@ -68,45 +73,67 @@ static BOOL pf_modules_proxy_ArrayList_ForEachFkt(void* data, size_t index, va_l
proxyPlugin* plugin = (proxyPlugin*)data;
PF_HOOK_TYPE type;
proxyData* pdata;
void* custom;
BOOL ok = FALSE;
WINPR_UNUSED(index);
type = va_arg(ap, PF_HOOK_TYPE);
pdata = va_arg(ap, proxyData*);
custom = va_arg(ap, void*);
WLog_VRB(TAG, "running hook %s.%s", plugin->name, pf_modules_get_hook_type_string(type));
switch (type)
{
case HOOK_TYPE_CLIENT_INIT_CONNECT:
ok = IFCALLRESULT(TRUE, plugin->ClientInitConnect, plugin, pdata, custom);
break;
case HOOK_TYPE_CLIENT_UNINIT_CONNECT:
ok = IFCALLRESULT(TRUE, plugin->ClientUninitConnect, plugin, pdata, custom);
break;
case HOOK_TYPE_CLIENT_PRE_CONNECT:
IFCALLRET(plugin->ClientPreConnect, ok, pdata);
ok = IFCALLRESULT(TRUE, plugin->ClientPreConnect, plugin, pdata, custom);
break;
case HOOK_TYPE_CLIENT_POST_CONNECT:
IFCALLRET(plugin->ClientPostConnect, ok, pdata);
ok = IFCALLRESULT(TRUE, plugin->ClientPostConnect, plugin, pdata, custom);
break;
case HOOK_TYPE_CLIENT_POST_DISCONNECT:
ok = IFCALLRESULT(TRUE, plugin->ClientPostDisconnect, plugin, pdata, custom);
break;
case HOOK_TYPE_CLIENT_VERIFY_X509:
ok = IFCALLRESULT(TRUE, plugin->ClientX509Certificate, plugin, pdata, custom);
break;
case HOOK_TYPE_CLIENT_LOGIN_FAILURE:
IFCALLRET(plugin->ClientLoginFailure, ok, pdata);
ok = IFCALLRESULT(TRUE, plugin->ClientLoginFailure, plugin, pdata, custom);
break;
case HOOK_TYPE_CLIENT_END_PAINT:
IFCALLRET(plugin->ClientEndPaint, ok, pdata);
ok = IFCALLRESULT(TRUE, plugin->ClientEndPaint, plugin, pdata, custom);
break;
case HOOK_TYPE_SERVER_POST_CONNECT:
IFCALLRET(plugin->ServerPostConnect, ok, pdata);
ok = IFCALLRESULT(TRUE, plugin->ServerPostConnect, plugin, pdata, custom);
break;
case HOOK_TYPE_SERVER_ACTIVATE:
ok = IFCALLRESULT(TRUE, plugin->ServerPeerActivate, plugin, pdata, custom);
break;
case HOOK_TYPE_SERVER_CHANNELS_INIT:
IFCALLRET(plugin->ServerChannelsInit, ok, pdata);
ok = IFCALLRESULT(TRUE, plugin->ServerChannelsInit, plugin, pdata, custom);
break;
case HOOK_TYPE_SERVER_CHANNELS_FREE:
IFCALLRET(plugin->ServerChannelsFree, ok, pdata);
ok = IFCALLRESULT(TRUE, plugin->ServerChannelsFree, plugin, pdata, custom);
break;
case HOOK_TYPE_SERVER_SESSION_END:
IFCALLRET(plugin->ServerSessionEnd, ok, pdata);
ok = IFCALLRESULT(TRUE, plugin->ServerSessionEnd, plugin, pdata, custom);
break;
case HOOK_LAST:
@ -129,9 +156,12 @@ static BOOL pf_modules_proxy_ArrayList_ForEachFkt(void* data, size_t index, va_l
* @type: hook type to run.
* @server: pointer of server's rdpContext struct of the current session.
*/
BOOL pf_modules_run_hook(PF_HOOK_TYPE type, proxyData* pdata)
BOOL pf_modules_run_hook(proxyModule* module, PF_HOOK_TYPE type, proxyData* pdata, void* custom)
{
return ArrayList_ForEach(plugins_list, pf_modules_proxy_ArrayList_ForEachFkt, type, pdata);
WINPR_ASSERT(module);
WINPR_ASSERT(module->plugins);
return ArrayList_ForEach(module->plugins, pf_modules_proxy_ArrayList_ForEachFkt, type, pdata,
custom);
}
static BOOL pf_modules_ArrayList_ForEachFkt(void* data, size_t index, va_list ap)
@ -153,23 +183,31 @@ static BOOL pf_modules_ArrayList_ForEachFkt(void* data, size_t index, va_list ap
switch (type)
{
case FILTER_TYPE_KEYBOARD:
IFCALLRET(plugin->KeyboardEvent, result, pdata, param);
result = IFCALLRESULT(TRUE, plugin->KeyboardEvent, plugin, pdata, param);
break;
case FILTER_TYPE_MOUSE:
IFCALLRET(plugin->MouseEvent, result, pdata, param);
result = IFCALLRESULT(TRUE, plugin->MouseEvent, plugin, pdata, param);
break;
case FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA:
IFCALLRET(plugin->ClientChannelData, result, pdata, param);
result = IFCALLRESULT(TRUE, plugin->ClientChannelData, plugin, pdata, param);
break;
case FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA:
IFCALLRET(plugin->ServerChannelData, result, pdata, param);
result = IFCALLRESULT(TRUE, plugin->ServerChannelData, plugin, pdata, param);
break;
case FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE:
result = IFCALLRESULT(TRUE, plugin->DynamicChannelCreate, plugin, pdata, param);
break;
case FILTER_TYPE_SERVER_FETCH_TARGET_ADDR:
IFCALLRET(plugin->ServerFetchTargetAddr, result, pdata, param);
result = IFCALLRESULT(TRUE, plugin->ServerFetchTargetAddr, plugin, pdata, param);
break;
case FILTER_TYPE_SERVER_PEER_LOGON:
result = IFCALLRESULT(TRUE, plugin->ServerPeerLogon, plugin, pdata, param);
break;
case FILTER_LAST:
@ -192,10 +230,12 @@ static BOOL pf_modules_ArrayList_ForEachFkt(void* data, size_t index, va_list ap
* @type: filter type to run.
* @server: pointer of server's rdpContext struct of the current session.
*/
BOOL pf_modules_run_filter(PF_FILTER_TYPE type, proxyData* pdata, void* param)
BOOL pf_modules_run_filter(proxyModule* module, PF_FILTER_TYPE type, proxyData* pdata, void* param)
{
WINPR_ASSERT(module);
WINPR_ASSERT(module->plugins);
return ArrayList_ForEach(plugins_list, pf_modules_ArrayList_ForEachFkt, type, pdata, param);
return ArrayList_ForEach(module->plugins, pf_modules_ArrayList_ForEachFkt, type, pdata, param);
}
/*
@ -204,7 +244,8 @@ BOOL pf_modules_run_filter(PF_FILTER_TYPE type, proxyData* pdata, void* param)
* @context: current session server's rdpContext instance.
* @info: pointer to per-session data.
*/
static BOOL pf_modules_set_plugin_data(const char* plugin_name, proxyData* pdata, void* data)
static BOOL pf_modules_set_plugin_data(proxyPluginsManager* mgr, const char* plugin_name,
proxyData* pdata, void* data)
{
union {
const char* ccp;
@ -233,7 +274,8 @@ static BOOL pf_modules_set_plugin_data(const char* plugin_name, proxyData* pdata
* if there's no data related to `plugin_name` in `context` (current session), a NULL will be
* returned.
*/
static void* pf_modules_get_plugin_data(const char* plugin_name, proxyData* pdata)
static void* pf_modules_get_plugin_data(proxyPluginsManager* mgr, const char* plugin_name,
proxyData* pdata)
{
union {
const char* ccp;
@ -246,7 +288,7 @@ static void* pf_modules_get_plugin_data(const char* plugin_name, proxyData* pdat
return HashTable_GetItemValue(pdata->modules_info, ccharconv.cp);
}
static void pf_modules_abort_connect(proxyData* pdata)
static void pf_modules_abort_connect(proxyPluginsManager* mgr, proxyData* pdata)
{
WINPR_ASSERT(pdata);
WLog_DBG(TAG, "%s is called!", __FUNCTION__);
@ -268,17 +310,24 @@ static BOOL pf_modules_register_ArrayList_ForEachFkt(void* data, size_t index, v
return TRUE;
}
static BOOL pf_modules_register_plugin(proxyPlugin* plugin_to_register)
static BOOL pf_modules_register_plugin(proxyPluginsManager* mgr,
const proxyPlugin* plugin_to_register)
{
proxyPlugin internal = { 0 };
proxyModule* module = (proxyModule*)mgr;
WINPR_ASSERT(module);
if (!plugin_to_register)
return FALSE;
internal = *plugin_to_register;
internal.mgr = mgr;
/* make sure there's no other loaded plugin with the same name of `plugin_to_register`. */
if (!ArrayList_ForEach(plugins_list, pf_modules_register_ArrayList_ForEachFkt,
plugin_to_register))
if (!ArrayList_ForEach(module->plugins, pf_modules_register_ArrayList_ForEachFkt, &internal))
return FALSE;
if (!ArrayList_Append(plugins_list, plugin_to_register))
if (!ArrayList_Append(module->plugins, &internal))
{
WLog_ERR(TAG, "[%s]: failed adding plugin to list: %s", __FUNCTION__,
plugin_to_register->name);
@ -301,12 +350,12 @@ static BOOL pf_modules_load_ArrayList_ForEachFkt(void* data, size_t index, va_li
return FALSE;
}
BOOL pf_modules_is_plugin_loaded(const char* plugin_name)
BOOL pf_modules_is_plugin_loaded(proxyModule* module, const char* plugin_name)
{
if (plugins_list == NULL)
WINPR_ASSERT(module);
if (ArrayList_Count(module->plugins) < 1)
return FALSE;
return ArrayList_ForEach(plugins_list, pf_modules_load_ArrayList_ForEachFkt, plugin_name);
return ArrayList_ForEach(module->plugins, pf_modules_load_ArrayList_ForEachFkt, plugin_name);
}
static BOOL pf_modules_print_ArrayList_ForEachFkt(void* data, size_t index, va_list ap)
@ -321,31 +370,28 @@ static BOOL pf_modules_print_ArrayList_ForEachFkt(void* data, size_t index, va_l
return TRUE;
}
void pf_modules_list_loaded_plugins(void)
void pf_modules_list_loaded_plugins(proxyModule* module)
{
size_t count;
if (plugins_list == NULL)
return;
WINPR_ASSERT(module);
WINPR_ASSERT(module->plugins);
count = (size_t)ArrayList_Count(plugins_list);
count = ArrayList_Count(module->plugins);
if (count > 0)
WLog_INFO(TAG, "Loaded plugins:");
ArrayList_ForEach(plugins_list, pf_modules_print_ArrayList_ForEachFkt);
ArrayList_ForEach(module->plugins, pf_modules_print_ArrayList_ForEachFkt);
}
static proxyPluginsManager plugins_manager = { pf_modules_register_plugin,
pf_modules_set_plugin_data,
pf_modules_get_plugin_data,
pf_modules_abort_connect };
static BOOL pf_modules_load_module(const char* module_path)
static BOOL pf_modules_load_module(const char* module_path, proxyModule* module, void* userdata)
{
HMODULE handle = NULL;
moduleEntryPoint pEntryPoint;
handle = LoadLibraryA(module_path);
proxyModuleEntryPoint pEntryPoint;
WINPR_ASSERT(module);
handle = LoadLibraryX(module_path);
if (handle == NULL)
{
@ -353,118 +399,142 @@ static BOOL pf_modules_load_module(const char* module_path)
return FALSE;
}
if (!(pEntryPoint = (moduleEntryPoint)GetProcAddress(handle, MODULE_ENTRY_POINT)))
pEntryPoint = (proxyModuleEntryPoint)GetProcAddress(handle, MODULE_ENTRY_POINT);
if (!pEntryPoint)
{
WLog_ERR(TAG, "[%s]: GetProcAddress failed while loading %s", __FUNCTION__, module_path);
goto error;
}
if (!pEntryPoint(&plugins_manager))
{
WLog_ERR(TAG, "[%s]: module %s entry point failed!", __FUNCTION__, module_path);
goto error;
}
/* save module handle for freeing the module later */
if (!ArrayList_Append(handles_list, handle))
if (!ArrayList_Append(module->handles, handle))
{
WLog_ERR(TAG, "ArrayList_Append failed!");
return FALSE;
goto error;
}
return TRUE;
return pf_modules_add(module, pEntryPoint, userdata);
error:
FreeLibrary(handle);
return FALSE;
}
BOOL pf_modules_init(const char* root_dir, const char** modules, size_t count)
static void free_handle(void* obj)
{
HANDLE handle = (HANDLE)obj;
if (handle)
FreeLibrary(handle);
}
static void free_plugin(void* obj)
{
proxyPlugin* plugin = (proxyPlugin*)obj;
WINPR_ASSERT(plugin);
if (!IFCALLRESULT(TRUE, plugin->PluginUnload, plugin))
WLog_WARN(TAG, "PluginUnload failed for plugin '%s'", plugin->name);
free(plugin);
}
static void* new_plugin(const void* obj)
{
const proxyPlugin* src = obj;
proxyPlugin* proxy = calloc(1, sizeof(proxyPlugin));
if (!proxy)
return NULL;
*proxy = *src;
return proxy;
}
proxyModule* pf_modules_new(const char* root_dir, const char** modules, size_t count)
{
size_t i;
wObject* obj;
char* path = NULL;
proxyModule* module = calloc(1, sizeof(proxyModule));
if (!module)
return NULL;
if (!PathFileExistsA(root_dir))
module->mgr.RegisterPlugin = pf_modules_register_plugin;
module->mgr.SetPluginData = pf_modules_set_plugin_data;
module->mgr.GetPluginData = pf_modules_get_plugin_data;
module->mgr.AbortConnect = pf_modules_abort_connect;
module->plugins = ArrayList_New(FALSE);
if (module->plugins == NULL)
{
if (!CreateDirectoryA(root_dir, NULL))
WLog_ERR(TAG, "[%s]: ArrayList_New failed!", __FUNCTION__);
goto error;
}
obj = ArrayList_Object(module->plugins);
WINPR_ASSERT(obj);
obj->fnObjectFree = free_plugin;
obj->fnObjectNew = new_plugin;
module->handles = ArrayList_New(FALSE);
if (module->handles == NULL)
{
WLog_ERR(TAG, "[%s]: ArrayList_New failed!", __FUNCTION__);
goto error;
}
ArrayList_Object(module->handles)->fnObjectFree = free_handle;
if (count > 0)
{
WINPR_ASSERT(root_dir);
if (!winpr_PathFileExists(root_dir))
path = GetCombinedPath(FREERDP_INSTALL_PREFIX, root_dir);
else
path = _strdup(root_dir);
if (!winpr_PathFileExists(path))
{
if (!winpr_PathMakePath(path, NULL))
{
WLog_ERR(TAG, "error occurred while creating modules directory: %s", root_dir);
return FALSE;
}
return TRUE;
}
WLog_DBG(TAG, "modules root directory: %s", root_dir);
plugins_list = ArrayList_New(FALSE);
if (plugins_list == NULL)
{
WLog_ERR(TAG, "[%s]: ArrayList_New failed!", __FUNCTION__);
goto error;
}
handles_list = ArrayList_New(FALSE);
if (handles_list == NULL)
{
WLog_ERR(TAG, "[%s]: ArrayList_New failed!", __FUNCTION__);
goto error;
}
if (winpr_PathFileExists(path))
WLog_DBG(TAG, "modules root directory: %s", path);
for (i = 0; i < count; i++)
{
char* fullpath = GetCombinedPath(root_dir, modules[i]);
pf_modules_load_module(fullpath);
char name[8192] = { 0 };
char* fullpath;
_snprintf(name, sizeof(name), "proxy-%s-plugin%s", modules[i],
FREERDP_SHARED_LIBRARY_SUFFIX);
fullpath = GetCombinedPath(path, name);
pf_modules_load_module(fullpath, module, NULL);
free(fullpath);
}
}
return TRUE;
free(path);
return module;
error:
ArrayList_Free(plugins_list);
plugins_list = NULL;
ArrayList_Free(handles_list);
handles_list = NULL;
return FALSE;
free(path);
pf_modules_free(module);
return NULL;
}
static BOOL pf_modules_free_ArrayList_ForEachFkt(void* data, size_t index, va_list ap)
void pf_modules_free(proxyModule* module)
{
proxyPlugin* plugin = (proxyPlugin*)data;
if (!module)
return;
WINPR_UNUSED(index);
WINPR_UNUSED(ap);
if (!IFCALLRESULT(TRUE, plugin->PluginUnload))
WLog_WARN(TAG, "PluginUnload failed for plugin '%s'", plugin->name);
return TRUE;
ArrayList_Free(module->plugins);
ArrayList_Free(module->handles);
free(module);
}
static BOOL pf_modules_free_handles_ArrayList_ForEachFkt(void* data, size_t index, va_list ap)
BOOL pf_modules_add(proxyModule* module, proxyModuleEntryPoint ep, void* userdata)
{
HANDLE handle = (HANDLE)data;
WINPR_ASSERT(module);
WINPR_ASSERT(ep);
WINPR_UNUSED(index);
WINPR_UNUSED(ap);
if (handle)
FreeLibrary(handle);
return TRUE;
}
void pf_modules_free(void)
{
if (plugins_list)
{
ArrayList_ForEach(plugins_list, pf_modules_free_ArrayList_ForEachFkt);
ArrayList_Free(plugins_list);
plugins_list = NULL;
}
if (handles_list)
{
ArrayList_ForEach(handles_list, pf_modules_free_handles_ArrayList_ForEachFkt);
ArrayList_Free(handles_list);
handles_list = NULL;
}
return ep(&module->mgr, userdata);
}

View File

@ -1,67 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
*
* 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_MODULES_H
#define FREERDP_SERVER_PROXY_MODULES_H
#include <winpr/wtypes.h>
#include <winpr/collections.h>
#include "modules/modules_api.h"
enum _PF_FILTER_TYPE
{
FILTER_TYPE_KEYBOARD,
FILTER_TYPE_MOUSE,
FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA,
FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA,
FILTER_TYPE_SERVER_FETCH_TARGET_ADDR,
FILTER_LAST
};
typedef enum _PF_FILTER_TYPE PF_FILTER_TYPE;
enum _PF_HOOK_TYPE
{
HOOK_TYPE_CLIENT_PRE_CONNECT,
HOOK_TYPE_CLIENT_POST_CONNECT,
HOOK_TYPE_CLIENT_LOGIN_FAILURE,
HOOK_TYPE_CLIENT_END_PAINT,
HOOK_TYPE_SERVER_POST_CONNECT,
HOOK_TYPE_SERVER_CHANNELS_INIT,
HOOK_TYPE_SERVER_CHANNELS_FREE,
HOOK_TYPE_SERVER_SESSION_END,
HOOK_LAST
};
typedef enum _PF_HOOK_TYPE PF_HOOK_TYPE;
BOOL pf_modules_init(const char* root_dir, const char** modules, size_t count);
BOOL pf_modules_is_plugin_loaded(const char* plugin_name);
void pf_modules_list_loaded_plugins(void);
BOOL pf_modules_run_filter(PF_FILTER_TYPE type, proxyData* pdata, void* param);
BOOL pf_modules_run_hook(PF_HOOK_TYPE type, proxyData* pdata);
void pf_modules_free(void);
#endif /* FREERDP_SERVER_PROXY_MODULES_H */

View File

@ -19,18 +19,23 @@
* limitations under the License.
*/
#include <winpr/assert.h>
#include <freerdp/client/rail.h>
#include <freerdp/server/rail.h>
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_rail.h"
#include "pf_context.h"
#include "pf_log.h"
#include <freerdp/server/proxy/proxy_context.h>
#define TAG PROXY_TAG("rail")
BOOL pf_rail_context_init(pServerContext* ps)
{
RailServerContext* rail;
WINPR_ASSERT(ps);
rail = ps->rail = rail_server_context_new(ps->vcm);
if (!rail)
@ -53,6 +58,9 @@ BOOL pf_rail_context_init(pServerContext* ps)
static UINT pf_rail_client_on_open(RailClientContext* context, BOOL* sendHandshake)
{
WINPR_ASSERT(context);
WINPR_ASSERT(sendHandshake);
if (NULL != sendHandshake)
*sendHandshake = FALSE;
@ -63,8 +71,20 @@ static UINT pf_rail_client_on_open(RailClientContext* context, BOOL* sendHandsha
static UINT pf_rail_server_handshake(RailClientContext* client,
const RAIL_HANDSHAKE_ORDER* handshake)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(handshake);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerHandshake);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerHandshake(server, handshake);
}
@ -72,16 +92,40 @@ static UINT pf_rail_server_handshake(RailClientContext* client,
static UINT pf_rail_server_handshake_ex(RailClientContext* client,
const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(handshakeEx);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerHandshakeEx);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerHandshakeEx(server, handshakeEx);
}
static UINT pf_rail_server_sysparam(RailClientContext* client, const RAIL_SYSPARAM_ORDER* sysparam)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(sysparam);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerSysparam);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerSysparam(server, sysparam);
}
@ -89,8 +133,20 @@ static UINT pf_rail_server_sysparam(RailClientContext* client, const RAIL_SYSPAR
static UINT pf_rail_server_local_move_size(RailClientContext* client,
const RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(localMoveSize);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerLocalMoveSize);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerLocalMoveSize(server, localMoveSize);
}
@ -98,8 +154,20 @@ static UINT pf_rail_server_local_move_size(RailClientContext* client,
static UINT pf_rail_server_min_max_info(RailClientContext* client,
const RAIL_MINMAXINFO_ORDER* minMaxInfo)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(minMaxInfo);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerMinMaxInfo);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerMinMaxInfo(server, minMaxInfo);
}
@ -107,8 +175,20 @@ static UINT pf_rail_server_min_max_info(RailClientContext* client,
static UINT pf_rail_server_taskbar_info(RailClientContext* client,
const RAIL_TASKBAR_INFO_ORDER* taskbarInfo)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(taskbarInfo);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerTaskbarInfo);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerTaskbarInfo(server, taskbarInfo);
}
@ -116,8 +196,20 @@ static UINT pf_rail_server_taskbar_info(RailClientContext* client,
static UINT pf_rail_server_langbar_info(RailClientContext* client,
const RAIL_LANGBAR_INFO_ORDER* langbarInfo)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(langbarInfo);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerLangbarInfo);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerLangbarInfo(server, langbarInfo);
}
@ -125,8 +217,20 @@ static UINT pf_rail_server_langbar_info(RailClientContext* client,
static UINT pf_rail_server_exec_result(RailClientContext* client,
const RAIL_EXEC_RESULT_ORDER* execResult)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(execResult);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerExecResult);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerExecResult(server, execResult);
}
@ -134,16 +238,40 @@ static UINT pf_rail_server_exec_result(RailClientContext* client,
static UINT pf_rail_server_z_order_sync(RailClientContext* client,
const RAIL_ZORDER_SYNC* zOrderSync)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(zOrderSync);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerZOrderSync);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerZOrderSync(server, zOrderSync);
}
static UINT pf_rail_server_cloak(RailClientContext* client, const RAIL_CLOAK* cloak)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(cloak);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerCloak);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerCloak(server, cloak);
}
@ -152,8 +280,20 @@ static UINT
pf_rail_server_power_display_request(RailClientContext* client,
const RAIL_POWER_DISPLAY_REQUEST* powerDisplayRequest)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(powerDisplayRequest);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerPowerDisplayRequest);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerPowerDisplayRequest(server, powerDisplayRequest);
}
@ -161,8 +301,20 @@ pf_rail_server_power_display_request(RailClientContext* client,
static UINT pf_rail_server_get_appid_resp(RailClientContext* client,
const RAIL_GET_APPID_RESP_ORDER* getAppidResp)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(getAppidResp);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerGetAppidResp);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerGetAppidResp(server, getAppidResp);
}
@ -170,8 +322,20 @@ static UINT pf_rail_server_get_appid_resp(RailClientContext* client,
static UINT pf_rail_server_get_appid_resp_ex(RailClientContext* client,
const RAIL_GET_APPID_RESP_EX* getAppidRespEx)
{
proxyData* pdata = (proxyData*)client->custom;
RailServerContext* server = (RailServerContext*)pdata->ps->rail;
proxyData* pdata;
RailServerContext* server;
WINPR_ASSERT(client);
WINPR_ASSERT(getAppidRespEx);
pdata = (proxyData*)client->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->ps);
server = (RailServerContext*)pdata->ps->rail;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ServerGetAppidRespEx);
WLog_DBG(TAG, __FUNCTION__);
return server->ServerGetAppidRespEx(server, getAppidRespEx);
}
@ -181,8 +345,20 @@ static UINT pf_rail_server_get_appid_resp_ex(RailClientContext* client,
static UINT pf_rail_client_handshake(RailServerContext* server,
const RAIL_HANDSHAKE_ORDER* handshake)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(handshake);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientHandshake);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientHandshake(client, handshake);
}
@ -190,40 +366,100 @@ static UINT pf_rail_client_handshake(RailServerContext* server,
static UINT pf_rail_client_client_status(RailServerContext* server,
const RAIL_CLIENT_STATUS_ORDER* clientStatus)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(clientStatus);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientInformation);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientInformation(client, clientStatus);
}
static UINT pf_rail_client_exec(RailServerContext* server, const RAIL_EXEC_ORDER* exec)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(exec);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientExecute);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientExecute(client, exec);
}
static UINT pf_rail_client_sysparam(RailServerContext* server, const RAIL_SYSPARAM_ORDER* sysparam)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(sysparam);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientSystemParam);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientSystemParam(client, sysparam);
}
static UINT pf_rail_client_activate(RailServerContext* server, const RAIL_ACTIVATE_ORDER* activate)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(activate);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientActivate);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientActivate(client, activate);
}
static UINT pf_rail_client_sysmenu(RailServerContext* server, const RAIL_SYSMENU_ORDER* sysmenu)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(sysmenu);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientSystemMenu);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientSystemMenu(client, sysmenu);
}
@ -231,8 +467,20 @@ static UINT pf_rail_client_sysmenu(RailServerContext* server, const RAIL_SYSMENU
static UINT pf_rail_client_syscommand(RailServerContext* server,
const RAIL_SYSCOMMAND_ORDER* syscommand)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(syscommand);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientSystemCommand);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientSystemCommand(client, syscommand);
}
@ -240,8 +488,20 @@ static UINT pf_rail_client_syscommand(RailServerContext* server,
static UINT pf_rail_client_notify_event(RailServerContext* server,
const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(notifyEvent);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientNotifyEvent);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientNotifyEvent(client, notifyEvent);
}
@ -249,8 +509,20 @@ static UINT pf_rail_client_notify_event(RailServerContext* server,
static UINT pf_rail_client_window_move(RailServerContext* server,
const RAIL_WINDOW_MOVE_ORDER* windowMove)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(windowMove);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientWindowMove);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientWindowMove(client, windowMove);
}
@ -258,8 +530,20 @@ static UINT pf_rail_client_window_move(RailServerContext* server,
static UINT pf_rail_client_snap_arrange(RailServerContext* server,
const RAIL_SNAP_ARRANGE* snapArrange)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(snapArrange);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientSnapArrange);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientSnapArrange(client, snapArrange);
}
@ -267,8 +551,20 @@ static UINT pf_rail_client_snap_arrange(RailServerContext* server,
static UINT pf_rail_client_get_appid_req(RailServerContext* server,
const RAIL_GET_APPID_REQ_ORDER* getAppidReq)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(getAppidReq);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientGetAppIdRequest);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientGetAppIdRequest(client, getAppidReq);
}
@ -276,8 +572,20 @@ static UINT pf_rail_client_get_appid_req(RailServerContext* server,
static UINT pf_rail_client_langbar_info(RailServerContext* server,
const RAIL_LANGBAR_INFO_ORDER* langbarInfo)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(langbarInfo);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientLanguageBarInfo);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientLanguageBarInfo(client, langbarInfo);
}
@ -285,8 +593,20 @@ static UINT pf_rail_client_langbar_info(RailServerContext* server,
static UINT pf_rail_client_language_ime_info(RailServerContext* server,
const RAIL_LANGUAGEIME_INFO_ORDER* languageImeInfo)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(languageImeInfo);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientLanguageIMEInfo);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientLanguageIMEInfo(client, languageImeInfo);
}
@ -294,20 +614,49 @@ static UINT pf_rail_client_language_ime_info(RailServerContext* server,
static UINT pf_rail_client_compartment_info(RailServerContext* server,
const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
{
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(compartmentInfo);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WLog_DBG(TAG, __FUNCTION__);
return 0;
}
static UINT pf_rail_client_cloak(RailServerContext* server, const RAIL_CLOAK* cloak)
{
proxyData* pdata = (proxyData*)server->custom;
RailClientContext* client = (RailClientContext*)pdata->pc->rail;
proxyData* pdata;
RailClientContext* client;
WINPR_ASSERT(server);
WINPR_ASSERT(cloak);
pdata = (proxyData*)server->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RailClientContext*)pdata->pc->rail;
WINPR_ASSERT(client);
WINPR_ASSERT(client->ClientCloak);
WLog_DBG(TAG, __FUNCTION__);
return client->ClientCloak(client, cloak);
}
void pf_rail_pipeline_init(RailClientContext* client, RailServerContext* server, proxyData* pdata)
{
WINPR_ASSERT(client);
WINPR_ASSERT(server);
WINPR_ASSERT(pdata);
/* Set server and client side references to proxy data */
client->custom = (void*)pdata;
server->custom = (void*)pdata;

View File

@ -25,7 +25,7 @@
#include <freerdp/client/rail.h>
#include <freerdp/server/rail.h>
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
BOOL pf_rail_context_init(pServerContext* ps);
void pf_rail_pipeline_init(RailClientContext* client, RailServerContext* server, proxyData* pdata);

View File

@ -21,18 +21,22 @@
#include <freerdp/client/rdpgfx.h>
#include <freerdp/server/rdpgfx.h>
#include <freerdp/server/proxy/proxy_log.h>
#include <winpr/synch.h>
#include <winpr/assert.h>
#include "pf_rdpgfx.h"
#include "pf_context.h"
#include "pf_log.h"
#include <freerdp/server/proxy/proxy_config.h>
#include <freerdp/server/proxy/proxy_context.h>
#define TAG PROXY_TAG("gfx")
BOOL pf_server_rdpgfx_init(pServerContext* ps)
{
RdpgfxServerContext* gfx;
WINPR_ASSERT(ps);
gfx = ps->gfx = rdpgfx_server_context_new(ps->vcm);
if (!gfx)
@ -48,10 +52,26 @@ static UINT pf_rdpgfx_reset_graphics(RdpgfxClientContext* context,
const RDPGFX_RESET_GRAPHICS_PDU* resetGraphics)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(resetGraphics);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->ResetGraphics);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->ResetGraphics(server, resetGraphics)))
@ -60,6 +80,9 @@ static UINT pf_rdpgfx_reset_graphics(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->ResetGraphics);
return gfx_decoder->ResetGraphics(gfx_decoder, resetGraphics);
}
@ -67,10 +90,26 @@ static UINT pf_rdpgfx_start_frame(RdpgfxClientContext* context,
const RDPGFX_START_FRAME_PDU* startFrame)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(startFrame);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->StartFrame);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->StartFrame(server, startFrame)))
@ -79,16 +118,35 @@ static UINT pf_rdpgfx_start_frame(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->StartFrame);
return gfx_decoder->StartFrame(gfx_decoder, startFrame);
}
static UINT pf_rdpgfx_end_frame(RdpgfxClientContext* context, const RDPGFX_END_FRAME_PDU* endFrame)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(endFrame);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->EndFrame);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->EndFrame(server, endFrame)))
@ -97,6 +155,9 @@ static UINT pf_rdpgfx_end_frame(RdpgfxClientContext* context, const RDPGFX_END_F
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->EndFrame);
return gfx_decoder->EndFrame(gfx_decoder, endFrame);
}
@ -104,10 +165,26 @@ static UINT pf_rdpgfx_surface_command(RdpgfxClientContext* context,
const RDPGFX_SURFACE_COMMAND* cmd)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(cmd);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->SurfaceCommand);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->SurfaceCommand(server, cmd)))
@ -116,6 +193,9 @@ static UINT pf_rdpgfx_surface_command(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->SurfaceCommand);
return gfx_decoder->SurfaceCommand(gfx_decoder, cmd);
}
@ -124,10 +204,26 @@ pf_rdpgfx_delete_encoding_context(RdpgfxClientContext* context,
const RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(deleteEncodingContext);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->DeleteEncodingContext);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->DeleteEncodingContext(server, deleteEncodingContext)))
@ -136,6 +232,9 @@ pf_rdpgfx_delete_encoding_context(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->DeleteEncodingContext);
return gfx_decoder->DeleteEncodingContext(gfx_decoder, deleteEncodingContext);
}
@ -143,10 +242,26 @@ static UINT pf_rdpgfx_create_surface(RdpgfxClientContext* context,
const RDPGFX_CREATE_SURFACE_PDU* createSurface)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(createSurface);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->CreateSurface);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->CreateSurface(server, createSurface)))
@ -155,6 +270,9 @@ static UINT pf_rdpgfx_create_surface(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->CreateSurface);
return gfx_decoder->CreateSurface(gfx_decoder, createSurface);
}
@ -162,10 +280,26 @@ static UINT pf_rdpgfx_delete_surface(RdpgfxClientContext* context,
const RDPGFX_DELETE_SURFACE_PDU* deleteSurface)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(deleteSurface);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->DeleteSurface);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->DeleteSurface(server, deleteSurface)))
@ -174,6 +308,9 @@ static UINT pf_rdpgfx_delete_surface(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->DeleteSurface);
return gfx_decoder->DeleteSurface(gfx_decoder, deleteSurface);
}
@ -181,10 +318,26 @@ static UINT pf_rdpgfx_solid_fill(RdpgfxClientContext* context,
const RDPGFX_SOLID_FILL_PDU* solidFill)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(solidFill);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->SolidFill);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->SolidFill(server, solidFill)))
@ -193,6 +346,9 @@ static UINT pf_rdpgfx_solid_fill(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->SolidFill);
return gfx_decoder->SolidFill(gfx_decoder, solidFill);
}
@ -200,10 +356,26 @@ static UINT pf_rdpgfx_surface_to_surface(RdpgfxClientContext* context,
const RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(surfaceToSurface);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->SurfaceToSurface);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->SurfaceToSurface(server, surfaceToSurface)))
@ -212,6 +384,9 @@ static UINT pf_rdpgfx_surface_to_surface(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->SurfaceToSurface);
return gfx_decoder->SurfaceToSurface(gfx_decoder, surfaceToSurface);
}
@ -219,10 +394,26 @@ static UINT pf_rdpgfx_surface_to_cache(RdpgfxClientContext* context,
const RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(surfaceToCache);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->SurfaceToCache);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->SurfaceToCache(server, surfaceToCache)))
@ -231,6 +422,9 @@ static UINT pf_rdpgfx_surface_to_cache(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->SurfaceToCache);
return gfx_decoder->SurfaceToCache(gfx_decoder, surfaceToCache);
}
@ -238,10 +432,26 @@ static UINT pf_rdpgfx_cache_to_surface(RdpgfxClientContext* context,
const RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(cacheToSurface);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->CacheToSurface);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->CacheToSurface(server, cacheToSurface)))
@ -250,14 +460,30 @@ static UINT pf_rdpgfx_cache_to_surface(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->CacheToSurface);
return gfx_decoder->CacheToSurface(gfx_decoder, cacheToSurface);
}
static UINT pf_rdpgfx_cache_import_reply(RdpgfxClientContext* context,
const RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply)
{
proxyData* pdata = (proxyData*)context->custom;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
proxyData* pdata;
RdpgfxServerContext* server;
WINPR_ASSERT(context);
WINPR_ASSERT(cacheImportReply);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->CacheImportReply);
WLog_VRB(TAG, __FUNCTION__);
return server->CacheImportReply(server, cacheImportReply);
}
@ -266,10 +492,26 @@ static UINT pf_rdpgfx_evict_cache_entry(RdpgfxClientContext* context,
const RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(evictCacheEntry);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->EvictCacheEntry);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->EvictCacheEntry(server, evictCacheEntry)))
@ -278,6 +520,9 @@ static UINT pf_rdpgfx_evict_cache_entry(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->EvictCacheEntry);
return gfx_decoder->EvictCacheEntry(gfx_decoder, evictCacheEntry);
}
@ -285,10 +530,26 @@ static UINT pf_rdpgfx_map_surface_to_output(RdpgfxClientContext* context,
const RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(surfaceToOutput);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->MapSurfaceToOutput);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->MapSurfaceToOutput(server, surfaceToOutput)))
@ -297,6 +558,9 @@ static UINT pf_rdpgfx_map_surface_to_output(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->MapSurfaceToOutput);
return gfx_decoder->MapSurfaceToOutput(gfx_decoder, surfaceToOutput);
}
@ -304,10 +568,26 @@ static UINT pf_rdpgfx_map_surface_to_window(RdpgfxClientContext* context,
const RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(surfaceToWindow);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->MapSurfaceToWindow);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->MapSurfaceToWindow(server, surfaceToWindow)))
@ -316,6 +596,9 @@ static UINT pf_rdpgfx_map_surface_to_window(RdpgfxClientContext* context,
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->MapSurfaceToWindow);
return gfx_decoder->MapSurfaceToWindow(gfx_decoder, surfaceToWindow);
}
@ -324,10 +607,26 @@ static UINT pf_rdpgfx_map_surface_to_scaled_window(
const RDPGFX_MAP_SURFACE_TO_SCALED_WINDOW_PDU* surfaceToScaledWindow)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(surfaceToScaledWindow);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->MapSurfaceToScaledWindow);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->MapSurfaceToScaledWindow(server, surfaceToScaledWindow)))
@ -336,6 +635,9 @@ static UINT pf_rdpgfx_map_surface_to_scaled_window(
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->MapSurfaceToScaledWindow);
return gfx_decoder->MapSurfaceToScaledWindow(gfx_decoder, surfaceToScaledWindow);
}
@ -344,10 +646,26 @@ static UINT pf_rdpgfx_map_surface_to_scaled_output(
const RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU* surfaceToScaledOutput)
{
UINT error;
proxyData* pdata = (proxyData*)context->custom;
proxyConfig* config = pdata->config;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
RdpgfxClientContext* gfx_decoder = pdata->pc->gfx_decoder;
proxyData* pdata;
const proxyConfig* config;
RdpgfxServerContext* server;
RdpgfxClientContext* gfx_decoder;
WINPR_ASSERT(context);
WINPR_ASSERT(surfaceToScaledOutput);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
config = pdata->config;
WINPR_ASSERT(config);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->MapSurfaceToScaledOutput);
WLog_VRB(TAG, __FUNCTION__);
if ((error = server->MapSurfaceToScaledOutput(server, surfaceToScaledOutput)))
@ -356,13 +674,25 @@ static UINT pf_rdpgfx_map_surface_to_scaled_output(
if (!config->DecodeGFX)
return CHANNEL_RC_OK;
gfx_decoder = pdata->pc->gfx_decoder;
WINPR_ASSERT(gfx_decoder);
WINPR_ASSERT(gfx_decoder->MapSurfaceToScaledOutput);
return gfx_decoder->MapSurfaceToScaledOutput(gfx_decoder, surfaceToScaledOutput);
}
static UINT pf_rdpgfx_on_open(RdpgfxClientContext* context, BOOL* do_caps_advertise,
BOOL* send_frame_acks)
{
proxyData* pdata = (proxyData*)context->custom;
proxyData* pdata;
WINPR_ASSERT(context);
WINPR_ASSERT(do_caps_advertise);
WINPR_ASSERT(send_frame_acks);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->gfx_server_ready);
WLog_VRB(TAG, __FUNCTION__);
if (NULL != do_caps_advertise)
@ -379,9 +709,23 @@ static UINT pf_rdpgfx_on_open(RdpgfxClientContext* context, BOOL* do_caps_advert
static UINT pf_rdpgfx_caps_confirm(RdpgfxClientContext* context,
const RDPGFX_CAPS_CONFIRM_PDU* capsConfirm)
{
proxyData* pdata = (proxyData*)context->custom;
RdpgfxServerContext* server = (RdpgfxServerContext*)pdata->ps->gfx;
proxyData* pdata;
RdpgfxServerContext* server;
WINPR_ASSERT(context);
WINPR_ASSERT(capsConfirm);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
WINPR_ASSERT(pdata->ps);
server = (RdpgfxServerContext*)pdata->ps->gfx;
WINPR_ASSERT(server);
WINPR_ASSERT(server->CapsConfirm);
WLog_VRB(TAG, __FUNCTION__);
return server->CapsConfirm(server, capsConfirm);
}
@ -389,14 +733,22 @@ static UINT pf_rdpgfx_caps_confirm(RdpgfxClientContext* context,
static UINT pf_rdpgfx_caps_advertise(RdpgfxServerContext* context,
const RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise)
{
proxyData* pdata = (proxyData*)context->custom;
RdpgfxClientContext* client = (RdpgfxClientContext*)pdata->pc->gfx_proxy;
UINT16 index;
UINT16 proxySupportedCapsSetCount = 0;
RDPGFX_CAPS_ADVERTISE_PDU supportedCapsAdvertise;
RDPGFX_CAPS_ADVERTISE_PDU supportedCapsAdvertise = { 0 };
RDPGFX_CAPSET* proxySupportedCapsSet;
RDPGFX_CAPSET proxySupportedCapsSets[RDPGFX_NUMBER_CAPSETS] = { 0 };
proxyData* pdata;
RdpgfxClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(capsAdvertise);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RdpgfxClientContext*)pdata->pc->gfx_proxy;
for (index = 0; index < capsAdvertise->capsSetCount; index++)
{
const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
@ -417,15 +769,30 @@ static UINT pf_rdpgfx_caps_advertise(RdpgfxServerContext* context,
supportedCapsAdvertise.capsSetCount = proxySupportedCapsSetCount;
supportedCapsAdvertise.capsSets = proxySupportedCapsSets;
WLog_VRB(TAG, __FUNCTION__);
WINPR_ASSERT(client);
WINPR_ASSERT(client->CapsAdvertise);
return client->CapsAdvertise(client, &supportedCapsAdvertise);
}
static UINT pf_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
const RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge)
{
proxyData* pdata = (proxyData*)context->custom;
RdpgfxClientContext* client = (RdpgfxClientContext*)pdata->pc->gfx_proxy;
proxyData* pdata;
RdpgfxClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(frameAcknowledge);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RdpgfxClientContext*)pdata->pc->gfx_proxy;
WLog_VRB(TAG, __FUNCTION__);
WINPR_ASSERT(client);
WINPR_ASSERT(client->FrameAcknowledge);
return client->FrameAcknowledge(client, frameAcknowledge);
}
@ -433,17 +800,39 @@ static UINT
pf_rdpgfx_qoe_frame_acknowledge(RdpgfxServerContext* context,
const RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* qoeFrameAcknowledge)
{
proxyData* pdata = (proxyData*)context->custom;
RdpgfxClientContext* client = (RdpgfxClientContext*)pdata->pc->gfx_proxy;
proxyData* pdata;
RdpgfxClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(qoeFrameAcknowledge);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RdpgfxClientContext*)pdata->pc->gfx_proxy;
WLog_VRB(TAG, __FUNCTION__);
WINPR_ASSERT(client);
WINPR_ASSERT(client->QoeFrameAcknowledge);
return client->QoeFrameAcknowledge(client, qoeFrameAcknowledge);
}
static UINT pf_rdpgfx_cache_import_offer(RdpgfxServerContext* context,
const RDPGFX_CACHE_IMPORT_OFFER_PDU* cacheImportOffer)
{
proxyData* pdata = (proxyData*)context->custom;
RdpgfxClientContext* client = (RdpgfxClientContext*)pdata->pc->gfx_proxy;
proxyData* pdata;
RdpgfxClientContext* client;
WINPR_ASSERT(context);
WINPR_ASSERT(cacheImportOffer);
pdata = (proxyData*)context->custom;
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->pc);
client = (RdpgfxClientContext*)pdata->pc->gfx_proxy;
WLog_VRB(TAG, __FUNCTION__);
if (pdata->config->DecodeGFX)
@ -452,13 +841,22 @@ static UINT pf_rdpgfx_cache_import_offer(RdpgfxServerContext* context,
return CHANNEL_RC_OK;
}
WINPR_ASSERT(client);
WINPR_ASSERT(client->CacheImportOffer);
return client->CacheImportOffer(client, cacheImportOffer);
}
void pf_rdpgfx_pipeline_init(RdpgfxClientContext* gfx, RdpgfxServerContext* server,
proxyData* pdata)
{
pClientContext* pc = pdata->pc;
pClientContext* pc;
WINPR_ASSERT(gfx);
WINPR_ASSERT(server);
WINPR_ASSERT(pdata);
pc = pdata->pc;
WINPR_ASSERT(pc);
/* create another gfx client and register it to the gdi graphics pipeline */
pc->gfx_decoder = rdpgfx_client_context_new(pc->context.settings);

View File

@ -26,7 +26,7 @@
#include <freerdp/server/rdpgfx.h>
#include <freerdp/gdi/gfx.h>
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
BOOL pf_server_rdpgfx_init(pServerContext* ps);
void pf_rdpgfx_pipeline_init(RdpgfxClientContext* gfx, RdpgfxServerContext* server,

View File

@ -18,13 +18,15 @@
*/
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <freerdp/log.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/server/rdpsnd.h>
#include <freerdp/server/server-common.h>
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_rdpsnd.h"
#include "pf_log.h"
#define TAG PROXY_TAG("rdpsnd")
@ -33,10 +35,13 @@ static void rdpsnd_activated(RdpsndServerContext* context)
const AUDIO_FORMAT* agreed_format = NULL;
UINT16 i = 0, j = 0;
WINPR_ASSERT(context);
for (i = 0; i < context->num_client_formats; i++)
{
for (j = 0; j < context->num_server_formats; j++)
{
WINPR_ASSERT(context->server_formats);
WINPR_ASSERT(context->client_formats);
if (audio_format_compatible(&context->server_formats[j], &context->client_formats[i]))
{
agreed_format = &context->server_formats[j];
@ -54,12 +59,16 @@ static void rdpsnd_activated(RdpsndServerContext* context)
return;
}
WINPR_ASSERT(context->SelectFormat);
context->SelectFormat(context, i);
}
BOOL pf_server_rdpsnd_init(pServerContext* ps)
{
RdpsndServerContext* rdpsnd;
WINPR_ASSERT(ps);
rdpsnd = ps->rdpsnd = rdpsnd_server_context_new(ps->vcm);
if (!rdpsnd)

View File

@ -23,7 +23,7 @@
#include <freerdp/client/rdpsnd.h>
#include <freerdp/server/rdpsnd.h>
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
BOOL pf_server_rdpsnd_init(pServerContext* ps);
void pf_server_rdpsnd_free(pServerContext* ps);

View File

@ -30,23 +30,25 @@
#include <freerdp/freerdp.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/channels/channels.h>
#include <freerdp/build-config.h>
#include <freerdp/server/proxy/proxy_server.h>
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_server.h"
#include "pf_log.h"
#include "pf_config.h"
#include <freerdp/server/proxy/proxy_config.h>
#include "pf_client.h"
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
#include "pf_update.h"
#include "pf_rdpgfx.h"
#include "pf_disp.h"
#include "pf_rail.h"
#include "pf_channels.h"
#include "pf_modules.h"
#include "proxy_modules.h"
#include "pf_utils.h"
#define TAG PROXY_TAG("server")
static psPeerReceiveChannelData server_receive_channel_data_original = NULL;
static BOOL pf_server_parse_target_from_routing_token(rdpContext* context, char** target,
DWORD* port)
{
@ -64,7 +66,7 @@ static BOOL pf_server_parse_target_from_routing_token(rdpContext* context, char*
if ((routing_token_length <= prefix_len) || (routing_token_length >= TARGET_MAX))
{
LOG_ERR(TAG, ps, "invalid routing token length: %" PRIu32 "", routing_token_length);
PROXY_LOG_ERR(TAG, ps, "invalid routing token length: %" PRIu32 "", routing_token_length);
return FALSE;
}
@ -97,15 +99,20 @@ static BOOL pf_server_parse_target_from_routing_token(rdpContext* context, char*
}
static BOOL pf_server_get_target_info(rdpContext* context, rdpSettings* settings,
proxyConfig* config)
const proxyConfig* config)
{
pServerContext* ps = (pServerContext*)context;
proxyFetchTargetEventInfo ev = { 0 };
WINPR_ASSERT(settings);
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
ev.fetch_method = config->FixedTarget ? PROXY_FETCH_TARGET_METHOD_CONFIG
: PROXY_FETCH_TARGET_METHOD_LOAD_BALANCE_INFO;
if (!pf_modules_run_filter(FILTER_TYPE_SERVER_FETCH_TARGET_ADDR, ps->pdata, &ev))
if (!pf_modules_run_filter(ps->pdata->module, FILTER_TYPE_SERVER_FETCH_TARGET_ADDR, ps->pdata,
&ev))
return FALSE;
switch (ev.fetch_method)
@ -117,12 +124,13 @@ static BOOL pf_server_get_target_info(rdpContext* context, rdpSettings* settings
case PROXY_FETCH_TARGET_METHOD_CONFIG:
{
WINPR_ASSERT(config);
settings->ServerPort = config->TargetPort > 0 ? 3389 : settings->ServerPort;
settings->ServerHostname = _strdup(config->TargetHost);
if (!settings->ServerHostname)
{
LOG_ERR(TAG, ps, "strdup failed!");
PROXY_LOG_ERR(TAG, ps, "strdup failed!");
return FALSE;
}
@ -139,7 +147,7 @@ static BOOL pf_server_get_target_info(rdpContext* context, rdpSettings* settings
settings->ServerHostname = _strdup(ev.target_address);
if (!settings->ServerHostname)
{
LOG_ERR(TAG, ps, "strdup failed!");
PROXY_LOG_ERR(TAG, ps, "strdup failed!");
return FALSE;
}
@ -173,15 +181,20 @@ static BOOL pf_server_post_connect(freerdp_peer* peer)
size_t accepted_channels_count;
size_t i;
ps = (pServerContext*)peer->context;
pdata = ps->pdata;
WINPR_ASSERT(peer);
LOG_INFO(TAG, ps, "Accepted client: %s", peer->settings->ClientHostname);
ps = (pServerContext*)peer->context;
WINPR_ASSERT(ps);
pdata = ps->pdata;
WINPR_ASSERT(pdata);
PROXY_LOG_INFO(TAG, ps, "Accepted client: %s", peer->settings->ClientHostname);
accepted_channels = WTSGetAcceptedChannelNames(peer, &accepted_channels_count);
if (accepted_channels)
{
for (i = 0; i < accepted_channels_count; i++)
LOG_INFO(TAG, ps, "Accepted channel: %s", accepted_channels[i]);
PROXY_LOG_INFO(TAG, ps, "Accepted channel: %s", accepted_channels[i]);
free(accepted_channels);
}
@ -189,7 +202,7 @@ static BOOL pf_server_post_connect(freerdp_peer* peer)
pc = pf_context_create_client_context(peer->settings);
if (pc == NULL)
{
LOG_ERR(TAG, ps, "failed to create client context!");
PROXY_LOG_ERR(TAG, ps, "failed to create client context!");
return FALSE;
}
@ -200,26 +213,26 @@ static BOOL pf_server_post_connect(freerdp_peer* peer)
if (!pf_server_get_target_info(peer->context, client_settings, pdata->config))
{
LOG_INFO(TAG, ps, "pf_server_get_target_info failed!");
PROXY_LOG_INFO(TAG, ps, "pf_server_get_target_info failed!");
return FALSE;
}
LOG_INFO(TAG, ps, "remote target is %s:%" PRIu16 "", client_settings->ServerHostname,
PROXY_LOG_INFO(TAG, ps, "remote target is %s:%" PRIu16 "", client_settings->ServerHostname,
client_settings->ServerPort);
if (!pf_server_channels_init(ps))
if (!pf_server_channels_init(ps, peer))
{
LOG_INFO(TAG, ps, "failed to initialize server's channels!");
PROXY_LOG_INFO(TAG, ps, "failed to initialize server's channels!");
return FALSE;
}
if (!pf_modules_run_hook(HOOK_TYPE_SERVER_POST_CONNECT, pdata))
if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_POST_CONNECT, pdata, peer))
return FALSE;
/* Start a proxy's client in it's own thread */
if (!(pdata->client_thread = CreateThread(NULL, 0, pf_client_start, pc, 0, NULL)))
{
LOG_ERR(TAG, ps, "failed to create client thread");
PROXY_LOG_ERR(TAG, ps, "failed to create client thread");
return FALSE;
}
@ -228,12 +241,51 @@ static BOOL pf_server_post_connect(freerdp_peer* peer)
static BOOL pf_server_activate(freerdp_peer* peer)
{
pServerContext* ps;
proxyData* pdata;
WINPR_ASSERT(peer);
ps = (pServerContext*)peer->context;
WINPR_ASSERT(ps);
pdata = ps->pdata;
WINPR_ASSERT(pdata);
WINPR_ASSERT(peer->settings);
peer->settings->CompressionLevel = PACKET_COMPR_TYPE_RDP8;
if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_ACTIVATE, pdata, peer))
return FALSE;
return TRUE;
}
static BOOL pf_server_logon(freerdp_peer* peer, const SEC_WINNT_AUTH_IDENTITY* identity,
BOOL automatic)
{
pServerContext* ps;
proxyData* pdata;
proxyServerPeerLogon info = { 0 };
WINPR_ASSERT(peer);
ps = (pServerContext*)peer->context;
WINPR_ASSERT(ps);
pdata = ps->pdata;
WINPR_ASSERT(pdata);
WINPR_ASSERT(peer->settings);
WINPR_ASSERT(identity);
info.identity = identity;
info.automatic = automatic;
if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_SERVER_PEER_LOGON, pdata, &info))
return FALSE;
return TRUE;
}
static BOOL pf_server_adjust_monitor_layout(freerdp_peer* peer)
{
WINPR_ASSERT(peer);
/* proxy as is, there's no need to do anything here */
return TRUE;
}
@ -242,13 +294,24 @@ static BOOL pf_server_receive_channel_data_hook(freerdp_peer* peer, UINT16 chann
const BYTE* data, size_t size, UINT32 flags,
size_t totalSize)
{
pServerContext* ps = (pServerContext*)peer->context;
pClientContext* pc = ps->pdata->pc;
proxyData* pdata = ps->pdata;
proxyConfig* config = pdata->config;
size_t i;
pServerContext* ps;
pClientContext* pc;
proxyData* pdata;
const proxyConfig* config;
int pass;
const char* channel_name = WTSChannelGetName(peer, channelId);
WINPR_ASSERT(peer);
ps = (pServerContext*)peer->context;
WINPR_ASSERT(ps);
pdata = ps->pdata;
WINPR_ASSERT(pdata);
pc = pdata->pc;
config = pdata->config;
WINPR_ASSERT(config);
/*
* client side is not initialized yet, call original callback.
* this is probably a drdynvc message between peer and proxy server,
@ -257,40 +320,52 @@ static BOOL pf_server_receive_channel_data_hook(freerdp_peer* peer, UINT16 chann
if (!pc)
goto original_cb;
for (i = 0; i < config->PassthroughCount; i++)
pass = pf_utils_channel_is_passthrough(config, channel_name);
switch (pass)
{
if (strncmp(channel_name, config->Passthrough[i], CHANNEL_NAME_LEN) == 0)
case 0:
return TRUE;
case 1:
{
proxyChannelDataEventInfo ev;
UINT64 client_channel_id;
ev.channel_id = channelId;
ev.channel_name = channel_name;
ev.data = data;
ev.data_len = size;
ev.flags = flags;
ev.total_size = totalSize;
if (!pf_modules_run_filter(FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA, pdata, &ev))
return FALSE;
if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA,
pdata, &ev))
return TRUE; /* Silently ignore */
client_channel_id = (UINT64)HashTable_GetItemValue(pc->vc_ids, channel_name);
return pc->context.instance->SendChannelData(pc->context.instance,
(UINT16)client_channel_id, data, size);
return IFCALLRESULT(TRUE, pc->sendChannelData, pc, &ev);
}
default:
break;
}
original_cb:
return server_receive_channel_data_original(peer, channelId, data, size, flags, totalSize);
WINPR_ASSERT(pdata->server_receive_channel_data_original);
return pdata->server_receive_channel_data_original(peer, channelId, data, size, flags,
totalSize);
}
static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
{
pServerContext* ps = (pServerContext*)peer->context;
rdpSettings* settings = peer->settings;
pServerContext* ps;
rdpSettings* settings;
proxyData* pdata;
proxyConfig* config;
const proxyConfig* config;
proxyServer* server;
WINPR_ASSERT(peer);
settings = peer->settings;
WINPR_ASSERT(settings);
ps = (pServerContext*)peer->context;
if (!ps)
return FALSE;
@ -301,6 +376,7 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
proxy_data_set_server_context(pdata, ps);
server = (proxyServer*)peer->ContextExtra;
pdata->module = server->module;
config = pdata->config = server->config;
/* currently not supporting GDI orders */
@ -309,9 +385,18 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
settings->SupportMonitorLayoutPdu = TRUE;
settings->SupportGraphicsPipeline = config->GFX;
settings->CertificateFile = _strdup("server.crt");
settings->PrivateKeyFile = _strdup("server.key");
settings->RdpKeyFile = _strdup("server.key");
if (!freerdp_settings_set_string(settings, FreeRDP_CertificateFile, config->CertificateFile) ||
!freerdp_settings_set_string(settings, FreeRDP_CertificateContent,
config->CertificateContent) ||
!freerdp_settings_set_string(settings, FreeRDP_PrivateKeyFile, config->PrivateKeyFile) ||
!freerdp_settings_set_string(settings, FreeRDP_PrivateKeyContent,
config->PrivateKeyContent) ||
!freerdp_settings_set_string(settings, FreeRDP_RdpKeyFile, config->RdpKeyFile) ||
!freerdp_settings_set_string(settings, FreeRDP_RdpKeyContent, config->RdpKeyContent))
{
WLog_ERR(TAG, "Memory allocation failed (strdup)");
return FALSE;
}
if (config->RemoteApp)
{
@ -324,15 +409,9 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
settings->RemoteAppLanguageBarSupported = TRUE;
}
if (!settings->CertificateFile || !settings->PrivateKeyFile || !settings->RdpKeyFile)
{
WLog_ERR(TAG, "Memory allocation failed (strdup)");
return FALSE;
}
settings->RdpSecurity = config->ServerRdpSecurity;
settings->TlsSecurity = config->ServerTlsSecurity;
settings->NlaSecurity = FALSE; /* currently NLA is not supported in proxy server */
settings->NlaSecurity = config->ServerNlaSecurity;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
settings->ColorDepth = 32;
settings->SuppressOutput = TRUE;
@ -341,11 +420,12 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
peer->PostConnect = pf_server_post_connect;
peer->Activate = pf_server_activate;
peer->Logon = pf_server_logon;
peer->AdjustMonitorsLayout = pf_server_adjust_monitor_layout;
peer->settings->MultifragMaxRequestSize = 0xFFFFFF; /* FIXME */
/* virtual channels receive data hook */
server_receive_channel_data_original = peer->ReceiveChannelData;
pdata->server_receive_channel_data_original = peer->ReceiveChannelData;
peer->ReceiveChannelData = pf_server_receive_channel_data_hook;
if (!ArrayList_Append(server->clients, pdata))
@ -362,7 +442,7 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
*/
static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
{
HANDLE eventHandles[32];
HANDLE eventHandles[32] = { 0 };
HANDLE ChannelEvent;
DWORD eventCount;
DWORD tmp;
@ -371,7 +451,12 @@ static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
rdpContext* pc;
proxyData* pdata;
freerdp_peer* client = (freerdp_peer*)arg;
proxyServer* server = (proxyServer*)client->ContextExtra;
proxyServer* server;
WINPR_ASSERT(client);
server = (proxyServer*)client->ContextExtra;
WINPR_ASSERT(server);
if (!pf_context_init_server_context(client))
goto out_free_peer;
@ -380,11 +465,16 @@ static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
goto out_free_peer;
ps = (pServerContext*)client->context;
pdata = ps->pdata;
WINPR_ASSERT(ps);
pdata = ps->pdata;
WINPR_ASSERT(pdata);
WINPR_ASSERT(client->Initialize);
client->Initialize(client);
LOG_INFO(TAG, ps, "new connection: proxy address: %s, client address: %s", pdata->config->Host,
client->hostname);
PROXY_LOG_INFO(TAG, ps, "new connection: proxy address: %s, client address: %s",
pdata->config->Host, client->hostname);
/* Main client event handling loop */
ChannelEvent = WTSVirtualChannelManagerGetEventHandle(ps->vcm);
@ -392,6 +482,7 @@ static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
{
eventCount = 0;
{
WINPR_ASSERT(client->GetEventHandles);
tmp = client->GetEventHandles(client, &eventHandles[eventCount], 32 - eventCount);
if (tmp == 0)
@ -413,6 +504,7 @@ static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
break;
}
WINPR_ASSERT(client->CheckFileDescriptor);
if (client->CheckFileDescriptor(client) != TRUE)
break;
@ -461,19 +553,26 @@ static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
fail:
PROXY_LOG_INFO(TAG, ps, "starting shutdown of connection");
PROXY_LOG_INFO(TAG, ps, "stopping proxy's client");
pc = (rdpContext*)pdata->pc;
LOG_INFO(TAG, ps, "starting shutdown of connection");
LOG_INFO(TAG, ps, "stopping proxy's client");
freerdp_client_stop(pc);
pf_modules_run_hook(HOOK_TYPE_SERVER_SESSION_END, pdata);
LOG_INFO(TAG, ps, "freeing server's channels");
pf_server_channels_free(ps);
LOG_INFO(TAG, ps, "freeing proxy data");
pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_SESSION_END, pdata, client);
PROXY_LOG_INFO(TAG, ps, "freeing server's channels");
pf_server_channels_free(ps, client);
PROXY_LOG_INFO(TAG, ps, "freeing proxy data");
ArrayList_Remove(server->clients, pdata);
proxy_data_free(pdata);
freerdp_client_context_free(pc);
WINPR_ASSERT(client->Close);
client->Close(client);
WINPR_ASSERT(client->Disconnect);
client->Disconnect(client);
out_free_peer:
freerdp_peer_context_free(client);
freerdp_peer_free(client);
@ -482,10 +581,11 @@ out_free_peer:
return 0;
}
static BOOL pf_server_peer_accepted(freerdp_listener* listener, freerdp_peer* client)
static BOOL pf_server_start_peer(freerdp_peer* client)
{
HANDLE hThread;
client->ContextExtra = listener->info;
WINPR_ASSERT(client);
if (!(hThread = CreateThread(NULL, 0, pf_server_handle_peer, (void*)client, 0, NULL)))
return FALSE;
@ -494,57 +594,31 @@ static BOOL pf_server_peer_accepted(freerdp_listener* listener, freerdp_peer* cl
return TRUE;
}
static DWORD WINAPI pf_server_mainloop(LPVOID arg)
static BOOL pf_server_peer_accepted(freerdp_listener* listener, freerdp_peer* client)
{
HANDLE eventHandles[32];
DWORD eventCount;
DWORD status;
proxyServer* server = (proxyServer*)arg;
freerdp_listener* listener = server->listener;
WINPR_ASSERT(listener);
WINPR_ASSERT(client);
while (1)
{
eventCount = listener->GetEventHandles(listener, eventHandles, 32);
client->ContextExtra = listener->info;
if (0 == eventCount)
{
WLog_ERR(TAG, "Failed to get FreeRDP event handles");
break;
}
eventHandles[eventCount++] = server->stopEvent;
status = WaitForMultipleObjects(eventCount, eventHandles, FALSE, INFINITE);
if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
break;
if (WAIT_FAILED == status)
{
WLog_ERR(TAG, "select failed");
break;
}
if (listener->CheckFileDescriptor(listener) != TRUE)
{
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
break;
}
}
listener->Close(listener);
ExitThread(0);
return 0;
return pf_server_start_peer(client);
}
BOOL pf_server_start(proxyServer* server)
{
WSADATA wsaData;
WINPR_ASSERT(server);
WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
goto error;
WINPR_ASSERT(server->config);
WINPR_ASSERT(server->listener);
WINPR_ASSERT(server->listener->Open);
if (!server->listener->Open(server->listener, server->config->Host, server->config->Port))
{
switch (errno)
@ -563,10 +637,45 @@ BOOL pf_server_start(proxyServer* server)
goto error;
}
server->thread = CreateThread(NULL, 0, pf_server_mainloop, (void*)server, 0, NULL);
if (!server->thread)
return TRUE;
error:
WSACleanup();
return FALSE;
}
BOOL pf_server_start_from_socket(proxyServer* server, int socket)
{
WSADATA wsaData;
WINPR_ASSERT(server);
WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
goto error;
WINPR_ASSERT(server->listener);
WINPR_ASSERT(server->listener->OpenFromSocket);
if (!server->listener->OpenFromSocket(server->listener, socket))
{
switch (errno)
{
case EADDRINUSE:
WLog_ERR(TAG, "failed to start listener: address already in use!");
break;
case EACCES:
WLog_ERR(TAG, "failed to start listener: insufficent permissions!");
break;
default:
WLog_ERR(TAG, "failed to start listener: errno=%d", errno);
break;
}
goto error;
}
return TRUE;
error:
@ -574,25 +683,85 @@ error:
return FALSE;
}
BOOL pf_server_start_with_peer_socket(proxyServer* server, int peer_fd)
{
struct sockaddr_storage peer_addr;
socklen_t len = sizeof(peer_addr);
freerdp_peer* client = freerdp_peer_new(peer_fd);
WINPR_ASSERT(server);
if (!client)
goto fail;
if (getpeername(peer_fd, (struct sockaddr*)&peer_addr, &len) != 0)
goto fail;
if (!freerdp_peer_set_local_and_hostname(client, &peer_addr))
goto fail;
client->ContextExtra = server;
if (!pf_server_start_peer(client))
goto fail;
return TRUE;
fail:
WLog_ERR(TAG, "PeerAccepted callback failed");
freerdp_peer_free(client);
return FALSE;
}
static void pf_server_clients_list_client_free(void* obj)
{
proxyData* pdata = (proxyData*)obj;
proxy_data_abort_connect(pdata);
}
proxyServer* pf_server_new(proxyConfig* config)
static BOOL are_all_required_modules_loaded(proxyModule* module, const proxyConfig* config)
{
size_t i;
for (i = 0; i < pf_config_required_plugins_count(config); i++)
{
const char* plugin_name = pf_config_required_plugin(config, i);
if (!pf_modules_is_plugin_loaded(module, plugin_name))
{
WLog_ERR(TAG, "Required plugin '%s' is not loaded. stopping.", plugin_name);
return FALSE;
}
}
return TRUE;
}
proxyServer* pf_server_new(const proxyConfig* config)
{
wObject* obj;
proxyServer* server;
if (!config)
return NULL;
WINPR_ASSERT(config);
server = calloc(1, sizeof(proxyServer));
if (!server)
return NULL;
server->config = config;
if (!pf_config_clone(&server->config, config))
goto out;
server->module = pf_modules_new(FREERDP_PROXY_PLUGINDIR, pf_config_modules(config),
pf_config_modules_count(config));
if (!server->module)
{
WLog_ERR(TAG, "failed to initialize proxy modules!");
goto out;
}
pf_modules_list_loaded_plugins(server->module);
if (!are_all_required_modules_loaded(server->module, server->config))
goto out;
server->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!server->stopEvent)
@ -622,6 +791,58 @@ out:
return NULL;
}
BOOL pf_server_run(proxyServer* server)
{
BOOL rc = TRUE;
HANDLE eventHandles[32] = { 0 };
DWORD eventCount;
DWORD status;
freerdp_listener* listener;
WINPR_ASSERT(server);
listener = server->listener;
WINPR_ASSERT(listener);
while (1)
{
WINPR_ASSERT(listener->GetEventHandles);
eventCount = listener->GetEventHandles(listener, eventHandles, 32);
if (0 == eventCount)
{
WLog_ERR(TAG, "Failed to get FreeRDP event handles");
break;
}
WINPR_ASSERT(server->stopEvent);
eventHandles[eventCount++] = server->stopEvent;
status = WaitForMultipleObjects(eventCount, eventHandles, FALSE, INFINITE);
if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
break;
if (WAIT_FAILED == status)
{
WLog_ERR(TAG, "select failed");
rc = FALSE;
break;
}
WINPR_ASSERT(listener->CheckFileDescriptor);
if (listener->CheckFileDescriptor(listener) != TRUE)
{
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
rc = FALSE;
break;
}
}
WINPR_ASSERT(listener->Close);
listener->Close(listener);
return rc;
}
void pf_server_stop(proxyServer* server)
{
HANDLE waitHandle = INVALID_HANDLE_VALUE;
@ -639,7 +860,6 @@ void pf_server_stop(proxyServer* server)
/* signal main thread to stop and wait for the thread to exit */
SetEvent(server->stopEvent);
WaitForSingleObject(server->thread, INFINITE);
}
void pf_server_free(proxyServer* server)
@ -654,8 +874,15 @@ void pf_server_free(proxyServer* server)
if (server->stopEvent)
CloseHandle(server->stopEvent);
if (server->thread)
CloseHandle(server->thread);
pf_server_config_free(server->config);
pf_modules_free(server->module);
free(server);
}
BOOL pf_server_add_module(proxyServer* server, proxyModuleEntryPoint ep, void* userdata)
{
WINPR_ASSERT(server);
WINPR_ASSERT(ep);
return pf_modules_add(server->module, ep, userdata);
}

View File

@ -19,29 +19,24 @@
* limitations under the License.
*/
#ifndef FREERDP_SERVER_PROXY_SERVER_H
#define FREERDP_SERVER_PROXY_SERVER_H
#ifndef _FREERDP_SERVER_PROXY_SERVER_H
#define _FREERDP_SERVER_PROXY_SERVER_H
#include <winpr/collections.h>
#include <freerdp/listener.h>
#include "pf_config.h"
#include <freerdp/server/proxy/proxy_config.h>
#include "proxy_modules.h"
typedef struct proxy_server
struct proxy_server
{
proxyModule* module;
proxyConfig* config;
freerdp_listener* listener;
wArrayList* clients; /* maintain a list of active sessions, for stats */
wCountdownEvent* waitGroup; /* wait group used for gracefull shutdown */
HANDLE thread; /* main server thread - freerdp listener thread */
HANDLE stopEvent; /* an event used to signal the main thread to stop */
} proxyServer;
};
proxyServer* pf_server_new(proxyConfig* config);
void pf_server_free(proxyServer* server);
BOOL pf_server_start(proxyServer* server);
void pf_server_stop(proxyServer* server);
#endif /* FREERDP_SERVER_PROXY_SERVER_H */
#endif /* _FREERDP_SERVER_PROXY_SERVER_H */

View File

@ -21,27 +21,41 @@
#include <freerdp/display.h>
#include <freerdp/session.h>
#include <winpr/assert.h>
#include <winpr/image.h>
#include <winpr/sysinfo.h>
#include "pf_modules.h"
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_update.h"
#include "pf_context.h"
#include "pf_log.h"
#include <freerdp/server/proxy/proxy_context.h>
#include "proxy_modules.h"
#define TAG PROXY_TAG("update")
static BOOL pf_server_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
{
pServerContext* ps = (pServerContext*)context;
rdpContext* pc = (rdpContext*)ps->pdata->pc;
rdpContext* pc;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
pc = (rdpContext*)ps->pdata->pc;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->update);
WINPR_ASSERT(pc->update->RefreshRect);
return pc->update->RefreshRect(pc, count, areas);
}
static BOOL pf_server_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
{
pServerContext* ps = (pServerContext*)context;
rdpContext* pc = (rdpContext*)ps->pdata->pc;
rdpContext* pc;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->pdata);
pc = (rdpContext*)ps->pdata->pc;
WINPR_ASSERT(pc);
WINPR_ASSERT(pc->update);
WINPR_ASSERT(pc->update->SuppressOutput);
return pc->update->SuppressOutput(pc, allow, area);
}
@ -54,8 +68,15 @@ static BOOL pf_server_suppress_output(rdpContext* context, BYTE allow, const REC
static BOOL pf_client_begin_paint(rdpContext* context)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->BeginPaint);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->BeginPaint(ps);
}
@ -68,8 +89,15 @@ static BOOL pf_client_begin_paint(rdpContext* context)
static BOOL pf_client_end_paint(rdpContext* context)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->EndPaint);
WLog_DBG(TAG, __FUNCTION__);
@ -77,7 +105,7 @@ static BOOL pf_client_end_paint(rdpContext* context)
if (!ps->update->EndPaint(ps))
return FALSE;
if (!pf_modules_run_hook(HOOK_TYPE_CLIENT_END_PAINT, pdata))
if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_CLIENT_END_PAINT, pdata, context))
return FALSE;
return TRUE;
@ -86,8 +114,15 @@ static BOOL pf_client_end_paint(rdpContext* context)
static BOOL pf_client_bitmap_update(rdpContext* context, const BITMAP_UPDATE* bitmap)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->BitmapUpdate);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->BitmapUpdate(ps, bitmap);
}
@ -95,8 +130,17 @@ static BOOL pf_client_bitmap_update(rdpContext* context, const BITMAP_UPDATE* bi
static BOOL pf_client_desktop_resize(rdpContext* context)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->DesktopResize);
WINPR_ASSERT(context->settings);
WINPR_ASSERT(ps->settings);
WLog_DBG(TAG, __FUNCTION__);
ps->settings->DesktopWidth = context->settings->DesktopWidth;
ps->settings->DesktopHeight = context->settings->DesktopHeight;
@ -107,8 +151,13 @@ static BOOL pf_client_remote_monitors(rdpContext* context, UINT32 count,
const MONITOR_DEF* monitors)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WLog_DBG(TAG, __FUNCTION__);
return freerdp_display_send_monitor_layout(ps, count, monitors);
}
@ -117,8 +166,16 @@ static BOOL pf_client_send_pointer_system(rdpContext* context,
const POINTER_SYSTEM_UPDATE* pointer_system)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->pointer);
WINPR_ASSERT(ps->update->pointer->PointerSystem);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->pointer->PointerSystem(ps, pointer_system);
}
@ -127,8 +184,16 @@ static BOOL pf_client_send_pointer_position(rdpContext* context,
const POINTER_POSITION_UPDATE* pointerPosition)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->pointer);
WINPR_ASSERT(ps->update->pointer->PointerPosition);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->pointer->PointerPosition(ps, pointerPosition);
}
@ -137,8 +202,16 @@ static BOOL pf_client_send_pointer_color(rdpContext* context,
const POINTER_COLOR_UPDATE* pointer_color)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->pointer);
WINPR_ASSERT(ps->update->pointer->PointerColor);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->pointer->PointerColor(ps, pointer_color);
}
@ -147,8 +220,16 @@ static BOOL pf_client_send_pointer_large(rdpContext* context,
const POINTER_LARGE_UPDATE* pointer_large)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->pointer);
WINPR_ASSERT(ps->update->pointer->PointerLarge);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->pointer->PointerLarge(ps, pointer_large);
}
@ -156,8 +237,16 @@ static BOOL pf_client_send_pointer_large(rdpContext* context,
static BOOL pf_client_send_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->pointer);
WINPR_ASSERT(ps->update->pointer->PointerNew);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->pointer->PointerNew(ps, pointer_new);
}
@ -166,18 +255,33 @@ static BOOL pf_client_send_pointer_cached(rdpContext* context,
const POINTER_CACHED_UPDATE* pointer_cached)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->pointer);
WINPR_ASSERT(ps->update->pointer->PointerCached);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->pointer->PointerCached(ps, pointer_cached);
}
static BOOL pf_client_save_session_info(rdpContext* context, UINT32 type, void* data)
{
pClientContext* pc = (pClientContext*)context;
proxyData* pdata = pc->pdata;
rdpContext* ps = (rdpContext*)pdata->ps;
logon_info* logonInfo = NULL;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->SaveSessionInfo);
WLog_DBG(TAG, __FUNCTION__);
@ -187,8 +291,8 @@ static BOOL pf_client_save_session_info(rdpContext* context, UINT32 type, void*
case INFO_TYPE_LOGON_LONG:
{
logonInfo = (logon_info*)data;
LOG_INFO(TAG, pc, "client logon info: Username: %s, Domain: %s", logonInfo->username,
logonInfo->domain);
PROXY_LOG_INFO(TAG, pc, "client logon info: Username: %s, Domain: %s",
logonInfo->username, logonInfo->domain);
break;
}
@ -202,7 +306,16 @@ static BOOL pf_client_save_session_info(rdpContext* context, UINT32 type, void*
static BOOL pf_client_server_status_info(rdpContext* context, UINT32 status)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->ServerStatusInfo);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->ServerStatusInfo(ps, status);
}
@ -210,7 +323,16 @@ static BOOL pf_client_server_status_info(rdpContext* context, UINT32 status)
static BOOL pf_client_set_keyboard_indicators(rdpContext* context, UINT16 led_flags)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->SetKeyboardIndicators);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->SetKeyboardIndicators(ps, led_flags);
}
@ -219,7 +341,16 @@ static BOOL pf_client_set_keyboard_ime_status(rdpContext* context, UINT16 imeId,
UINT32 imeConvMode)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->SetKeyboardImeStatus);
WLog_DBG(TAG, __FUNCTION__);
return ps->update->SetKeyboardImeStatus(ps, imeId, imeState, imeConvMode);
}
@ -227,9 +358,19 @@ static BOOL pf_client_set_keyboard_ime_status(rdpContext* context, UINT16 imeId,
static BOOL pf_client_window_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const WINDOW_STATE_ORDER* windowState)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->WindowCreate);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->WindowCreate(ps, orderInfo, windowState);
@ -240,9 +381,19 @@ static BOOL pf_client_window_create(rdpContext* context, const WINDOW_ORDER_INFO
static BOOL pf_client_window_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const WINDOW_STATE_ORDER* windowState)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->WindowUpdate);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->WindowUpdate(ps, orderInfo, windowState);
@ -253,9 +404,19 @@ static BOOL pf_client_window_update(rdpContext* context, const WINDOW_ORDER_INFO
static BOOL pf_client_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const WINDOW_ICON_ORDER* windowIcon)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->WindowIcon);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->WindowIcon(ps, orderInfo, windowIcon);
@ -266,9 +427,19 @@ static BOOL pf_client_window_icon(rdpContext* context, const WINDOW_ORDER_INFO*
static BOOL pf_client_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const WINDOW_CACHED_ICON_ORDER* windowCachedIcon)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->WindowCachedIcon);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->WindowCachedIcon(ps, orderInfo, windowCachedIcon);
@ -278,9 +449,19 @@ static BOOL pf_client_window_cached_icon(rdpContext* context, const WINDOW_ORDER
static BOOL pf_client_window_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->WindowDelete);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->WindowDelete(ps, orderInfo);
@ -291,9 +472,19 @@ static BOOL pf_client_window_delete(rdpContext* context, const WINDOW_ORDER_INFO
static BOOL pf_client_notify_icon_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const NOTIFY_ICON_STATE_ORDER* notifyIconState)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->NotifyIconCreate);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->NotifyIconCreate(ps, orderInfo, notifyIconState);
@ -304,9 +495,19 @@ static BOOL pf_client_notify_icon_create(rdpContext* context, const WINDOW_ORDER
static BOOL pf_client_notify_icon_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const NOTIFY_ICON_STATE_ORDER* notifyIconState)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->NotifyIconUpdate);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->NotifyIconUpdate(ps, orderInfo, notifyIconState);
@ -316,9 +517,20 @@ static BOOL pf_client_notify_icon_update(rdpContext* context, const WINDOW_ORDER
static BOOL pf_client_notify_icon_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->NotifyIconDelete);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->NotifyIconDelete(ps, orderInfo);
@ -329,9 +541,19 @@ static BOOL pf_client_notify_icon_delete(rdpContext* context, const WINDOW_ORDER
static BOOL pf_client_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const MONITORED_DESKTOP_ORDER* monitoredDesktop)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->MonitoredDesktop);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->MonitoredDesktop(ps, orderInfo, monitoredDesktop);
@ -341,9 +563,19 @@ static BOOL pf_client_monitored_desktop(rdpContext* context, const WINDOW_ORDER_
static BOOL pf_client_non_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
{
pClientContext* pc = (pClientContext*)context;
rdpContext* ps = (rdpContext*)pc->pdata->ps;
BOOL rc;
pClientContext* pc = (pClientContext*)context;
proxyData* pdata;
rdpContext* ps;
WINPR_ASSERT(pc);
pdata = pc->pdata;
WINPR_ASSERT(pdata);
ps = (rdpContext*)pdata->ps;
WINPR_ASSERT(ps);
WINPR_ASSERT(ps->update);
WINPR_ASSERT(ps->update->window);
WINPR_ASSERT(ps->update->window->NonMonitoredDesktop);
WLog_DBG(TAG, __FUNCTION__);
EnterCriticalSection(&ps->update->mux);
rc = ps->update->window->NonMonitoredDesktop(ps, orderInfo);
@ -353,12 +585,14 @@ static BOOL pf_client_non_monitored_desktop(rdpContext* context, const WINDOW_OR
void pf_server_register_update_callbacks(rdpUpdate* update)
{
WINPR_ASSERT(update);
update->RefreshRect = pf_server_refresh_rect;
update->SuppressOutput = pf_server_suppress_output;
}
void pf_client_register_update_callbacks(rdpUpdate* update)
{
WINPR_ASSERT(update);
update->BeginPaint = pf_client_begin_paint;
update->EndPaint = pf_client_end_paint;
update->BitmapUpdate = pf_client_bitmap_update;

View File

@ -26,7 +26,7 @@
#include <freerdp/gdi/gdi.h>
#include <freerdp/gdi/bitmap.h>
#include "pf_context.h"
#include <freerdp/server/proxy/proxy_context.h>
void pf_server_register_update_callbacks(rdpUpdate* update);
void pf_client_register_update_callbacks(rdpUpdate* update);

55
server/proxy/pf_utils.c Normal file
View File

@ -0,0 +1,55 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2021 Armin Novak <armin.novak@thincast.com>
* * Copyright 2021 Thincast Technologies GmbH
*
* 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 <winpr/assert.h>
#include <winpr/string.h>
#include <winpr/wtsapi.h>
#include "pf_utils.h"
int pf_utils_channel_is_passthrough(const proxyConfig* config, const char* name)
{
size_t i;
BOOL found = FALSE;
WINPR_ASSERT(config);
WINPR_ASSERT(name);
for (i = 0; i < config->PassthroughCount; i++)
{
const char* channel_name = config->Passthrough[i];
if (strncmp(name, channel_name, CHANNEL_NAME_LEN + 1) == 0)
{
found = TRUE;
break;
}
}
if (found)
{
if (config->PassthroughIsBlacklist)
return 0;
return 1;
}
if (config->PassthroughIsBlacklist)
return 1;
return -1;
}

37
server/proxy/pf_utils.h Normal file
View File

@ -0,0 +1,37 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2021 Armin Novak <armin.novak@thincast.com>
* * Copyright 2021 Thincast Technologies GmbH
*
* 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_PFUTILS_H
#define FREERDP_SERVER_PROXY_PFUTILS_H
#include <freerdp/server/proxy/proxy_config.h>
/**
* @brief pf_utils_channel_is_passthrough Checks of a channel identified by 'name'
* should be handled as passthrough.
*
* @param config The proxy configuration to check against. Must NOT be NULL.
* @param name The name of the channel. Must NOT be NULL.
* @return -1 if the channel is not handled, 0 if the channel should be ignored,
* 1 if the channel should be passed.
*/
int pf_utils_channel_is_passthrough(const proxyConfig* config, const char* name);
#endif /* FREERDP_SERVER_PROXY_PFUTILS_H */

View File

@ -0,0 +1,92 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
*
* 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_MODULES_H
#define FREERDP_SERVER_PROXY_MODULES_H
#include <winpr/wtypes.h>
#include <winpr/collections.h>
#include <freerdp/server/proxy/proxy_modules_api.h>
enum _PF_FILTER_TYPE
{
FILTER_TYPE_KEYBOARD, /* proxyKeyboardEventInfo */
FILTER_TYPE_MOUSE, /* proxyMouseEventInfo */
FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA, /* proxyChannelDataEventInfo */
FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA, /* proxyChannelDataEventInfo */
FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE, /* proxyChannelDataEventInfo */
FILTER_TYPE_SERVER_FETCH_TARGET_ADDR, /* proxyFetchTargetEventInfo */
FILTER_TYPE_SERVER_PEER_LOGON, /* proxyServerPeerLogon */
FILTER_LAST
};
typedef enum _PF_FILTER_TYPE PF_FILTER_TYPE;
enum _PF_HOOK_TYPE
{
HOOK_TYPE_CLIENT_INIT_CONNECT,
HOOK_TYPE_CLIENT_UNINIT_CONNECT,
HOOK_TYPE_CLIENT_PRE_CONNECT,
HOOK_TYPE_CLIENT_POST_CONNECT,
HOOK_TYPE_CLIENT_POST_DISCONNECT,
HOOK_TYPE_CLIENT_VERIFY_X509,
HOOK_TYPE_CLIENT_LOGIN_FAILURE,
HOOK_TYPE_CLIENT_END_PAINT,
HOOK_TYPE_SERVER_POST_CONNECT,
HOOK_TYPE_SERVER_ACTIVATE,
HOOK_TYPE_SERVER_CHANNELS_INIT,
HOOK_TYPE_SERVER_CHANNELS_FREE,
HOOK_TYPE_SERVER_SESSION_END,
HOOK_LAST
};
typedef enum _PF_HOOK_TYPE PF_HOOK_TYPE;
#ifdef __cplusplus
extern "C"
{
#endif
proxyModule* pf_modules_new(const char* root_dir, const char** modules, size_t count);
/**
* @brief pf_modules_add Registers a new plugin
* @param ep A module entry point function, must NOT be NULL
* @return TRUE for success, FALSE otherwise
*/
BOOL pf_modules_add(proxyModule* module, proxyModuleEntryPoint ep, void* userdata);
BOOL pf_modules_is_plugin_loaded(proxyModule* module, const char* plugin_name);
void pf_modules_list_loaded_plugins(proxyModule* module);
BOOL pf_modules_run_filter(proxyModule* module, PF_FILTER_TYPE type, proxyData* pdata,
void* param);
BOOL pf_modules_run_hook(proxyModule* module, PF_HOOK_TYPE type, proxyData* pdata,
void* custom);
void pf_modules_free(proxyModule* module);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_SERVER_PROXY_MODULES_H */