diff --git a/CMakeLists.txt b/CMakeLists.txt index 029ed955f..6a26e3f0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/channels/rdpsnd/client/proxy/rdpsnd_proxy.c b/channels/rdpsnd/client/proxy/rdpsnd_proxy.c index 58e3019a4..01a8d47ee 100644 --- a/channels/rdpsnd/client/proxy/rdpsnd_proxy.c +++ b/channels/rdpsnd/client/proxy/rdpsnd_proxy.c @@ -34,7 +34,7 @@ #include #include "rdpsnd_main.h" -#include "../../../../server/proxy/pf_context.h" +#include typedef struct rdpsnd_proxy_plugin rdpsndProxyPlugin; diff --git a/ci/cmake-preloads/config-windows.txt b/ci/cmake-preloads/config-windows.txt index fcc78aeec..8c6027cd6 100644 --- a/ci/cmake-preloads/config-windows.txt +++ b/ci/cmake-preloads/config-windows.txt @@ -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) diff --git a/include/freerdp/server/proxy/proxy_config.h b/include/freerdp/server/proxy/proxy_config.h new file mode 100644 index 000000000..7a5e00b3e --- /dev/null +++ b/include/freerdp/server/proxy/proxy_config.h @@ -0,0 +1,185 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2021 Armin Novak + * 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 +#include + +#include + +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 */ diff --git a/server/proxy/pf_context.h b/include/freerdp/server/proxy/proxy_context.h similarity index 85% rename from server/proxy/pf_context.h rename to include/freerdp/server/proxy/proxy_context.h index c4f6a5bb7..f4cf0b31f 100644 --- a/server/proxy/pf_context.h +++ b/include/freerdp/server/proxy/proxy_context.h @@ -34,12 +34,13 @@ #include #include -#include "pf_config.h" -#include "pf_server.h" +#include #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); diff --git a/server/proxy/pf_log.h b/include/freerdp/server/proxy/proxy_log.h similarity index 82% rename from server/proxy/pf_log.h rename to include/freerdp/server/proxy/proxy_log.h index 109571fe5..4a32f5f00 100644 --- a/server/proxy/pf_log.h +++ b/include/freerdp/server/proxy/proxy_log.h @@ -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 @@ -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 */ diff --git a/include/freerdp/server/proxy/proxy_modules_api.h b/include/freerdp/server/proxy/proxy_modules_api.h new file mode 100644 index 000000000..0c869ca7a --- /dev/null +++ b/include/freerdp/server/proxy/proxy_modules_api.h @@ -0,0 +1,187 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2019 Kobi Mizrachi + * Copyright 2019 Idan Freiberg + * + * 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 +#include +#include + +#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 +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 + +#endif /* FREERDP_SERVER_PROXY_MODULES_API_H */ diff --git a/include/freerdp/server/proxy/proxy_server.h b/include/freerdp/server/proxy/proxy_server.h new file mode 100644 index 000000000..740aa74f3 --- /dev/null +++ b/include/freerdp/server/proxy/proxy_server.h @@ -0,0 +1,114 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2021 Armin Novak + * 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 +#include +#include + +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 */ diff --git a/libfreerdp/core/listener.c b/libfreerdp/core/listener.c index 080624c61..468c6aef3 100644 --- a/libfreerdp/core/listener.c +++ b/libfreerdp/core/listener.c @@ -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; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 4c350fd60..1ca82f72c 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -893,6 +893,7 @@ BOOL tls_accept(rdpTls* tls, BIO* underlying, rdpSettings* settings) BIO* bio; EVP_PKEY* privkey; X509* x509; + /** * SSL_OP_NO_SSLv2: * diff --git a/server/proxy/CMakeLists.txt b/server/proxy/CMakeLists.txt index 741a7fffd..0ec472170 100644 --- a/server/proxy/CMakeLists.txt +++ b/server/proxy/CMakeLists.txt @@ -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() diff --git a/server/proxy/FreeRDP-ProxyConfig.cmake.in b/server/proxy/FreeRDP-ProxyConfig.cmake.in new file mode 100644 index 000000000..406da3ad3 --- /dev/null +++ b/server/proxy/FreeRDP-ProxyConfig.cmake.in @@ -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") diff --git a/server/proxy/cli/CMakeLists.txt b/server/proxy/cli/CMakeLists.txt new file mode 100644 index 000000000..15ee9a69b --- /dev/null +++ b/server/proxy/cli/CMakeLists.txt @@ -0,0 +1,46 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP Proxy Server +# +# Copyright 2021 Armin Novak +# 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") diff --git a/server/proxy/freerdp_proxy.c b/server/proxy/cli/freerdp_proxy.c similarity index 62% rename from server/proxy/freerdp_proxy.c rename to server/proxy/cli/freerdp_proxy.c index 4f641a58c..ebd9d1132 100644 --- a/server/proxy/freerdp_proxy.c +++ b/server/proxy/cli/freerdp_proxy.c @@ -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 #include -#include -#include +#include + +#include +#include + #include #include @@ -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; } diff --git a/server/proxy/freerdp-proxy.pc.in b/server/proxy/freerdp-proxy.pc.in new file mode 100644 index 000000000..235ca6726 --- /dev/null +++ b/server/proxy/freerdp-proxy.pc.in @@ -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} diff --git a/server/proxy/modules/README.md b/server/proxy/modules/README.md index c6b3b81c1..f1d2206ec 100644 --- a/server/proxy/modules/README.md +++ b/server/proxy/modules/README.md @@ -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 `/lib/freerdp3/proxy` folder and match the pattern +`proxy--plugin.` (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`. \ No newline at end of file +A demo can be found in `filter_demo.c`. diff --git a/server/proxy/modules/capture/CMakeLists.txt b/server/proxy/modules/capture/CMakeLists.txt index 80ba3b77e..cc3e419c4 100644 --- a/server/proxy/modules/capture/CMakeLists.txt +++ b/server/proxy/modules/capture/CMakeLists.txt @@ -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}) diff --git a/server/proxy/modules/capture/cap_config.c b/server/proxy/modules/capture/cap_config.c index 32e02ae4d..efa3010c1 100644 --- a/server/proxy/modules/capture/cap_config.c +++ b/server/proxy/modules/capture/cap_config.c @@ -75,7 +75,7 @@ BOOL capture_plugin_init_config(captureConfig* config) return FALSE; } - config->port = port; + config->port = (UINT16)port; free(tmp); } else diff --git a/server/proxy/modules/capture/cap_main.c b/server/proxy/modules/capture/cap_main.c index a947c4988..d0128f004 100644 --- a/server/proxy/modules/capture/cap_main.c +++ b/server/proxy/modules/capture/cap_main.c @@ -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 #include #include #include -#include "pf_log.h" -#include "modules_api.h" -#include "pf_context.h" +#include +#include + +#include #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); } diff --git a/server/proxy/modules/capture/cap_protocol.c b/server/proxy/modules/capture/cap_protocol.c index 7e61fcd98..30f18649f 100644 --- a/server/proxy/modules/capture/cap_protocol.c +++ b/server/proxy/modules/capture/cap_protocol.c @@ -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, diff --git a/server/proxy/modules/capture/cap_protocol.h b/server/proxy/modules/capture/cap_protocol.h index fcc7f3d65..1b4ac86c2 100644 --- a/server/proxy/modules/capture/cap_protocol.h +++ b/server/proxy/modules/capture/cap_protocol.h @@ -20,7 +20,7 @@ #include #include -#include "pf_context.h" +#include /* protocol message sizes */ #define HEADER_SIZE 6 diff --git a/server/proxy/modules/demo/CMakeLists.txt b/server/proxy/modules/demo/CMakeLists.txt index f1bc26a4b..08bdbcd2c 100644 --- a/server/proxy/modules/demo/CMakeLists.txt +++ b/server/proxy/modules/demo/CMakeLists.txt @@ -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}) diff --git a/server/proxy/modules/demo/demo.cpp b/server/proxy/modules/demo/demo.cpp index f77e265f6..e1d58ce0b 100644 --- a/server/proxy/modules/demo/demo.cpp +++ b/server/proxy/modules/demo/demo.cpp @@ -19,59 +19,309 @@ #include -#include "modules_api.h" +#include #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(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(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(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(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(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(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(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(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); } diff --git a/server/proxy/modules/modules_api.h b/server/proxy/modules/modules_api.h deleted file mode 100644 index c3a733f7e..000000000 --- a/server/proxy/modules/modules_api.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Proxy Server - * - * Copyright 2019 Kobi Mizrachi - * Copyright 2019 Idan Freiberg - * - * 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 -#include - -#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 -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 - -#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 */ diff --git a/server/proxy/pf_channels.c b/server/proxy/pf_channels.c index f8a249eaf..abdd99f7d 100644 --- a/server/proxy/pf_channels.c +++ b/server/proxy/pf_channels.c @@ -23,6 +23,8 @@ #include "config.h" #endif +#include + #include #include @@ -31,21 +33,26 @@ #include #include +#include + #include "pf_channels.h" #include "pf_client.h" -#include "pf_context.h" +#include +#include #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); } diff --git a/server/proxy/pf_channels.h b/server/proxy/pf_channels.h index 5f6805a9f..3fa79a794 100644 --- a/server/proxy/pf_channels.h +++ b/server/proxy/pf_channels.h @@ -25,12 +25,12 @@ #include #include -#include "pf_context.h" +#include 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 */ diff --git a/server/proxy/pf_client.c b/server/proxy/pf_client.c index 9e64b2b89..40c9c6dca 100644 --- a/server/proxy/pf_client.c +++ b/server/proxy/pf_client.c @@ -27,22 +27,29 @@ #include #include +#include +#include +#include +#include + #include "pf_channels.h" #include "pf_gdi.h" #include "pf_graphics.h" #include "pf_client.h" -#include "pf_context.h" +#include #include "pf_update.h" -#include "pf_log.h" -#include "pf_modules.h" #include "pf_input.h" +#include +#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,13 +67,19 @@ 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, - freerdp_get_error_info_string(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 */ freerdp_set_error_info(ps->context.rdp, e->code); @@ -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); - settings->SupportDynamicChannels = TRUE; + if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, DRDYNVC_SVC_CHANNEL_NAME)) + settings->SupportDynamicChannels = TRUE; /* Multimon */ settings->UseMultimon = TRUE; /* Sound */ - settings->AudioPlayback = FALSE; - settings->DeviceRedirection = TRUE; + 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)) - return FALSE; + if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA, + pdata, &ev)) + return TRUE; /* Silently drop */ - 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); + /* 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; + + 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; + } + + 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); } - - return 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,32 +632,38 @@ 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", - settings->RdpSecurity, settings->TlsSecurity, settings->NlaSecurity); + 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)) { 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; diff --git a/server/proxy/pf_cliprdr.c b/server/proxy/pf_cliprdr.c index dca8f0ef6..7e622facf 100644 --- a/server/proxy/pf_cliprdr.c +++ b/server/proxy/pf_cliprdr.c @@ -18,8 +18,11 @@ * limitations under the License. */ +#include +#include + #include "pf_cliprdr.h" -#include "pf_log.h" +#include #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; diff --git a/server/proxy/pf_cliprdr.h b/server/proxy/pf_cliprdr.h index 74d3cdf21..e22c98a08 100644 --- a/server/proxy/pf_cliprdr.h +++ b/server/proxy/pf_cliprdr.h @@ -24,7 +24,7 @@ #include #include -#include "pf_context.h" +#include BOOL pf_server_cliprdr_init(pServerContext* ps); void pf_cliprdr_register_callbacks(CliprdrClientContext* cliprdr_client, diff --git a/server/proxy/pf_config.c b/server/proxy/pf_config.c index 4d29ac9a6..b03cb98cb 100644 --- a/server/proxy/pf_config.c +++ b/server/proxy/pf_config.c @@ -24,15 +24,18 @@ #include #include -#include "pf_log.h" #include "pf_server.h" -#include "pf_config.h" -#include "pf_modules.h" +#include + +#include +#include #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,7 +141,8 @@ const char* pf_config_get_str(wIniFile* ini, const char* section, const char* ke if (!value) { - WLog_ERR(TAG, "[%s]: key '%s.%s' not found.", __FUNCTION__, section, key); + 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,11 +276,190 @@ 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) +{ + const char* tmp1; + const char* tmp2; + + WINPR_ASSERT(ini); + WINPR_ASSERT(config); + + tmp1 = pf_config_get_str(ini, "Certificates", "CertificateFile", FALSE); + if (tmp1) + { + 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; + } + + tmp1 = pf_config_get_str(ini, "Certificates", "PrivateKeyFile", FALSE); + if (tmp1) + { + 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); + } + + 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; + + if (!pf_config_load_target(ini, config)) + goto out; + + if (!pf_config_load_channels(ini, config)) + goto out; + + if (!pf_config_load_input(ini, config)) + goto out; + + if (!pf_config_load_security(ini, config)) + goto out; + + if (!pf_config_load_modules(ini, config)) + goto out; + + if (!pf_config_load_clipboard(ini, config)) + goto out; + + if (!pf_config_load_gfx_settings(ini, config)) + goto out; + + if (!pf_config_load_certificates(ini, config)) + goto out; + } + return config; +out: + 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(); @@ -247,7 +467,7 @@ proxyConfig* pf_server_config_load(const char* path) if (!ini) { WLog_ERR(TAG, "[%s]: IniFile_New() failed!", __FUNCTION__); - return FALSE; + return NULL; } if (IniFile_ReadFile(ini, path) < 0) @@ -256,51 +476,26 @@ proxyConfig* pf_server_config_load(const char* path) goto out; } - config = calloc(1, sizeof(proxyConfig)); - - if (!pf_config_load_server(ini, config)) - goto out; - - if (!pf_config_load_target(ini, config)) - goto out; - - if (!pf_config_load_channels(ini, config)) - goto out; - - if (!pf_config_load_input(ini, config)) - goto out; - - if (!pf_config_load_security(ini, config)) - goto out; - - if (!pf_config_load_modules(ini, config)) - goto out; - - if (!pf_config_load_clipboard(ini, config)) - goto out; - - if (!pf_config_load_gfx_settings(ini, config)) - goto out; - - IniFile_Free(ini); - return config; - + config = server_config_load_ini(ini); out: IniFile_Free(ini); - pf_server_config_free(config); - return NULL; + 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; +} diff --git a/server/proxy/pf_config.h b/server/proxy/pf_config.h deleted file mode 100644 index 83b55f16e..000000000 --- a/server/proxy/pf_config.h +++ /dev/null @@ -1,101 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Proxy Server - * - * Copyright 2019 Kobi Mizrachi - * Copyright 2019 Idan Freiberg - * - * 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 -#include -#include - -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 */ diff --git a/server/proxy/pf_context.c b/server/proxy/pf_context.c index 24d38deba..7573f98c6 100644 --- a/server/proxy/pf_context.c +++ b/server/proxy/pf_context.c @@ -22,30 +22,18 @@ #include #include +#include + #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 /* 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; } diff --git a/server/proxy/pf_disp.c b/server/proxy/pf_disp.c index d6d62e7da..8518de4f4 100644 --- a/server/proxy/pf_disp.c +++ b/server/proxy/pf_disp.c @@ -17,16 +17,18 @@ * limitations under the License. */ +#include #include +#include #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 */ diff --git a/server/proxy/pf_disp.h b/server/proxy/pf_disp.h index 4a20a3a6d..72629e99f 100644 --- a/server/proxy/pf_disp.h +++ b/server/proxy/pf_disp.h @@ -23,7 +23,7 @@ #include #include -#include "pf_context.h" +#include BOOL pf_server_disp_init(pServerContext* ps); void pf_disp_register_callbacks(DispClientContext* client, DispServerContext* server, diff --git a/server/proxy/pf_gdi.c b/server/proxy/pf_gdi.c index d27144149..e66fb325b 100644 --- a/server/proxy/pf_gdi.c +++ b/server/proxy/pf_gdi.c @@ -23,6 +23,8 @@ #include "config.h" #endif +#include + #include #include #include @@ -30,39 +32,55 @@ #include #include #include -#include "pf_gdi.h" -#include "pf_log.h" -#include +#include + +#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; diff --git a/server/proxy/pf_graphics.c b/server/proxy/pf_graphics.c index f787dca78..17c56041d 100644 --- a/server/proxy/pf_graphics.c +++ b/server/proxy/pf_graphics.c @@ -24,13 +24,15 @@ #endif #include +#include #include +#include + #include "pf_graphics.h" -#include "pf_log.h" #include "pf_gdi.h" -#include "pf_context.h" +#include #include #include @@ -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; diff --git a/server/proxy/pf_input.c b/server/proxy/pf_input.c index 2a9baaa91..33fc26b62 100644 --- a/server/proxy/pf_input.c +++ b/server/proxy/pf_input.c @@ -19,23 +19,46 @@ * limitations under the License. */ +#include + #include "pf_input.h" -#include "pf_context.h" -#include "pf_modules.h" +#include +#include + +#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; diff --git a/server/proxy/pf_modules.c b/server/proxy/pf_modules.c index d45aa6101..326200dce 100644 --- a/server/proxy/pf_modules.c +++ b/server/proxy/pf_modules.c @@ -22,22 +22,27 @@ #include #include +#include #include #include #include -#include "pf_log.h" -#include "pf_modules.h" -#include "pf_context.h" +#include +#include + +#include +#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) { - size_t i; - - if (!PathFileExistsA(root_dir)) - { - if (!CreateDirectoryA(root_dir, 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; - } - - for (i = 0; i < count; i++) - { - char* fullpath = GetCombinedPath(root_dir, modules[i]); - pf_modules_load_module(fullpath); - free(fullpath); - } - - return TRUE; - -error: - ArrayList_Free(plugins_list); - plugins_list = NULL; - ArrayList_Free(handles_list); - handles_list = NULL; - return FALSE; -} - -static BOOL pf_modules_free_ArrayList_ForEachFkt(void* data, size_t index, va_list ap) -{ - proxyPlugin* plugin = (proxyPlugin*)data; - - WINPR_UNUSED(index); - WINPR_UNUSED(ap); - - if (!IFCALLRESULT(TRUE, plugin->PluginUnload)) - WLog_WARN(TAG, "PluginUnload failed for plugin '%s'", plugin->name); - return TRUE; -} - -static BOOL pf_modules_free_handles_ArrayList_ForEachFkt(void* data, size_t index, va_list ap) -{ - HANDLE handle = (HANDLE)data; - - WINPR_UNUSED(index); - WINPR_UNUSED(ap); + HANDLE handle = (HANDLE)obj; if (handle) FreeLibrary(handle); - return TRUE; } -void pf_modules_free(void) +static void free_plugin(void* obj) { - if (plugins_list) + 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; + + 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) { - ArrayList_ForEach(plugins_list, pf_modules_free_ArrayList_ForEachFkt); - ArrayList_Free(plugins_list); - plugins_list = 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); + goto error; + } + } + + if (winpr_PathFileExists(path)) + WLog_DBG(TAG, "modules root directory: %s", path); + + for (i = 0; i < count; i++) + { + 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); + } } - if (handles_list) - { - ArrayList_ForEach(handles_list, pf_modules_free_handles_ArrayList_ForEachFkt); - ArrayList_Free(handles_list); - handles_list = NULL; - } + free(path); + return module; + +error: + free(path); + pf_modules_free(module); + return NULL; +} + +void pf_modules_free(proxyModule* module) +{ + if (!module) + return; + + ArrayList_Free(module->plugins); + ArrayList_Free(module->handles); + free(module); +} + +BOOL pf_modules_add(proxyModule* module, proxyModuleEntryPoint ep, void* userdata) +{ + WINPR_ASSERT(module); + WINPR_ASSERT(ep); + + return ep(&module->mgr, userdata); } diff --git a/server/proxy/pf_modules.h b/server/proxy/pf_modules.h deleted file mode 100644 index be874d5e3..000000000 --- a/server/proxy/pf_modules.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Proxy Server - * - * Copyright 2019 Kobi Mizrachi - * Copyright 2019 Idan Freiberg - * - * 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 -#include - -#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 */ diff --git a/server/proxy/pf_rail.c b/server/proxy/pf_rail.c index 41fe11e56..2a1520cc9 100644 --- a/server/proxy/pf_rail.c +++ b/server/proxy/pf_rail.c @@ -19,18 +19,23 @@ * limitations under the License. */ +#include + #include #include +#include #include "pf_rail.h" -#include "pf_context.h" -#include "pf_log.h" +#include #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; diff --git a/server/proxy/pf_rail.h b/server/proxy/pf_rail.h index 6d99bab20..5126998fd 100644 --- a/server/proxy/pf_rail.h +++ b/server/proxy/pf_rail.h @@ -25,7 +25,7 @@ #include #include -#include "pf_context.h" +#include BOOL pf_rail_context_init(pServerContext* ps); void pf_rail_pipeline_init(RailClientContext* client, RailServerContext* server, proxyData* pdata); diff --git a/server/proxy/pf_rdpgfx.c b/server/proxy/pf_rdpgfx.c index 408aeac65..05d5d4d9e 100644 --- a/server/proxy/pf_rdpgfx.c +++ b/server/proxy/pf_rdpgfx.c @@ -21,18 +21,22 @@ #include #include +#include #include +#include #include "pf_rdpgfx.h" -#include "pf_context.h" -#include "pf_log.h" +#include +#include #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); diff --git a/server/proxy/pf_rdpgfx.h b/server/proxy/pf_rdpgfx.h index ab35a0c1b..70b1f84e3 100644 --- a/server/proxy/pf_rdpgfx.h +++ b/server/proxy/pf_rdpgfx.h @@ -26,7 +26,7 @@ #include #include -#include "pf_context.h" +#include BOOL pf_server_rdpgfx_init(pServerContext* ps); void pf_rdpgfx_pipeline_init(RdpgfxClientContext* gfx, RdpgfxServerContext* server, diff --git a/server/proxy/pf_rdpsnd.c b/server/proxy/pf_rdpsnd.c index 432f8c0ea..e53c14b56 100644 --- a/server/proxy/pf_rdpsnd.c +++ b/server/proxy/pf_rdpsnd.c @@ -18,13 +18,15 @@ */ #include +#include + #include #include #include #include +#include #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) diff --git a/server/proxy/pf_rdpsnd.h b/server/proxy/pf_rdpsnd.h index 27bfe3ae1..613587b3c 100644 --- a/server/proxy/pf_rdpsnd.h +++ b/server/proxy/pf_rdpsnd.h @@ -23,7 +23,7 @@ #include #include -#include "pf_context.h" +#include BOOL pf_server_rdpsnd_init(pServerContext* ps); void pf_server_rdpsnd_free(pServerContext* ps); diff --git a/server/proxy/pf_server.c b/server/proxy/pf_server.c index 202abdc6b..e4c2bf226 100644 --- a/server/proxy/pf_server.c +++ b/server/proxy/pf_server.c @@ -30,23 +30,25 @@ #include #include #include +#include + +#include +#include #include "pf_server.h" -#include "pf_log.h" -#include "pf_config.h" +#include #include "pf_client.h" -#include "pf_context.h" +#include #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, - client_settings->ServerPort); + 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); +} diff --git a/server/proxy/pf_server.h b/server/proxy/pf_server.h index 6d920e0aa..1d1f13a40 100644 --- a/server/proxy/pf_server.h +++ b/server/proxy/pf_server.h @@ -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 #include -#include "pf_config.h" +#include +#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 */ diff --git a/server/proxy/pf_update.c b/server/proxy/pf_update.c index 3bf40a3be..1382c91bf 100644 --- a/server/proxy/pf_update.c +++ b/server/proxy/pf_update.c @@ -21,27 +21,41 @@ #include #include +#include #include #include -#include "pf_modules.h" +#include + #include "pf_update.h" -#include "pf_context.h" -#include "pf_log.h" +#include +#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; diff --git a/server/proxy/pf_update.h b/server/proxy/pf_update.h index 30a6a19de..81a9c321d 100644 --- a/server/proxy/pf_update.h +++ b/server/proxy/pf_update.h @@ -26,7 +26,7 @@ #include #include -#include "pf_context.h" +#include void pf_server_register_update_callbacks(rdpUpdate* update); void pf_client_register_update_callbacks(rdpUpdate* update); diff --git a/server/proxy/pf_utils.c b/server/proxy/pf_utils.c new file mode 100644 index 000000000..e3dd92016 --- /dev/null +++ b/server/proxy/pf_utils.c @@ -0,0 +1,55 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2021 Armin Novak + * * 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 +#include +#include + +#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; +} diff --git a/server/proxy/pf_utils.h b/server/proxy/pf_utils.h new file mode 100644 index 000000000..b754bc223 --- /dev/null +++ b/server/proxy/pf_utils.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2021 Armin Novak + * * 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 + +/** + * @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 */ diff --git a/server/proxy/proxy_modules.h b/server/proxy/proxy_modules.h new file mode 100644 index 000000000..eccca8f42 --- /dev/null +++ b/server/proxy/proxy_modules.h @@ -0,0 +1,92 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Proxy Server + * + * Copyright 2019 Kobi Mizrachi + * Copyright 2019 Idan Freiberg + * + * 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 +#include + +#include + +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 */