From 39e33d9e9d3da48e182d6d97ad43210dac0a1927 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 29 Jan 2026 09:37:59 +0100 Subject: [PATCH] [utils,helpers] add application details getter/setter * Allow an application to set a vendor/product/version namespace to search for configuration files/settings/... * Replace all FREERDP_VENDOR_STRING and similar macros with these getters. --- include/freerdp/utils/helpers.h | 51 +++++++ libfreerdp/codec/rfx.c | 45 +++--- libfreerdp/core/credssp_auth.c | 12 +- libfreerdp/core/nla.c | 2 - libfreerdp/core/settings.c | 243 +++++++++++++++++++------------- libfreerdp/core/utils.h | 31 ++++ libfreerdp/utils/helpers.c | 206 ++++++++++++++++++++++++--- 7 files changed, 447 insertions(+), 143 deletions(-) diff --git a/include/freerdp/utils/helpers.h b/include/freerdp/utils/helpers.h index f0a2bbcff..bd2567852 100644 --- a/include/freerdp/utils/helpers.h +++ b/include/freerdp/utils/helpers.h @@ -60,6 +60,57 @@ extern "C" WINPR_ATTR_NODISCARD FREERDP_API WINPR_JSON* freerdp_GetJSONConfigFile(BOOL system, const char* filename); + /** @brief set \b vendor and \b product information for an application + * + * This sets the application details for an application instance. These values determine where + * to look for configuration files and other vendor/product specific settings data. + * This function recursively also sets \ref freerdp_setApplicationDetails with a 'vendor' string + * of 'vendor/product', a 'product' string of WINPR_PRODUCT_STRING (build time constant) and a + * 'version' of -1. This limits the length of \b vendor + \b product to \b MAX_PATH or less.. + * + * @note When calling this function, the compile time options \b + * FREERDP_USE_VENDOR_PRODUCT_CONFIG_DIR and \b WITH_FULL_CONFIG_PATH are ignored and the config + * path will always have the format 'vendor/product' or 'vendor/product1' (1 for the actual + * version set) + * + * @param vendor A vendor name to use. Must not be \b NULL. Must not contain forbidden + * filesystem symbols for any os. Must be less than \b MAX_PATH bytes. + * @param product A product name to use. Must not be \b NULL. Must not contain forbidden + * filesystem symbols for any os. Must be less than \b MAX_PATH bytes. + * @param version An optional versioning value to append to paths to settings. Use \b -1 to + * disable. + * + * @return \b TRUE if set successfully, \b FALSE in case of any error. + * @since version 3.23.0 + */ + FREERDP_API WINPR_ATTR_NODISCARD BOOL freerdp_setApplicationDetails(const char* vendor, + const char* product, + SSIZE_T version); + + /** @brief Get the current \b vendor string of the application. Defaults to \ref + * FREERDP_VENDOR_STRING + * + * @return The current string set as \b vendor. + * @since version 3.23.0 + */ + FREERDP_API WINPR_ATTR_NODISCARD const char* freerdp_getApplicationDetailsVendor(void); + + /** @brief Get the current \b product string of the application. Defaults to \ref + * FREERDP_PRODUCT_STRING + * + * @return The current string set as \b product. + * @since version 3.23.0 + */ + FREERDP_API WINPR_ATTR_NODISCARD const char* freerdp_getApplicationDetailsProduct(void); + + /** @brief Get the current \b version of the application. Defaults to \ref FREERDP_API_VERSION + * if \b WITH_RESOURCE_VERSIONING is defined, otherwise \b -1 + * + * @return The current number set as \b version + * @since version 3.23.0 + */ + FREERDP_API WINPR_ATTR_NODISCARD SSIZE_T freerdp_getApplicationDetailsVersion(void); + #ifdef __cplusplus } #endif diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index 3cf4217f8..ad45633fd 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -47,13 +47,14 @@ #include "rfx_quantization.h" #include "rfx_dwt.h" #include "rfx_rlgr.h" +#include "../core/utils.h" #include "sse/rfx_sse2.h" #include "neon/rfx_neon.h" #define TAG FREERDP_TAG("codec") -#define RFX_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\RemoteFX" +#define RFX_KEY "Software\\%s\\RemoteFX" /** * The quantization values control the compression rate and quality. The value @@ -259,30 +260,32 @@ RFX_CONTEXT* rfx_context_new_ex(BOOL encoder, UINT32 ThreadingFlags) if (!priv->BufferPool) goto fail; + priv->UseThreads = FALSE; if (!(ThreadingFlags & THREADING_FLAGS_DISABLE_THREADS)) - { - HKEY hKey = NULL; priv->UseThreads = TRUE; - const LONG status = - RegOpenKeyExA(HKEY_LOCAL_MACHINE, RFX_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - - if (status == ERROR_SUCCESS) - { - DWORD dwType = 0; - DWORD dwValue = 0; - DWORD dwSize = sizeof(dwValue); - - if (RegQueryValueEx(hKey, _T("UseThreads"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) == - ERROR_SUCCESS) - priv->UseThreads = dwValue ? 1 : 0; - - RegCloseKey(hKey); - } - } - else { - priv->UseThreads = FALSE; + char* key = freerdp_getApplicatonDetailsRegKey(RFX_KEY); + if (key) + { + HKEY hKey = NULL; + const LONG status = + RegOpenKeyExA(HKEY_LOCAL_MACHINE, RFX_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + free(key); + + if (status == ERROR_SUCCESS) + { + DWORD dwType = 0; + DWORD dwValue = 0; + DWORD dwSize = sizeof(dwValue); + + if (RegQueryValueEx(hKey, _T("UseThreads"), NULL, &dwType, (BYTE*)&dwValue, + &dwSize) == ERROR_SUCCESS) + priv->UseThreads = dwValue ? 1 : 0; + + RegCloseKey(hKey); + } + } } if (priv->UseThreads) diff --git a/libfreerdp/core/credssp_auth.c b/libfreerdp/core/credssp_auth.c index e9afe92ad..0a488da46 100644 --- a/libfreerdp/core/credssp_auth.c +++ b/libfreerdp/core/credssp_auth.c @@ -40,7 +40,7 @@ #define TAG FREERDP_TAG("core.auth") -#define SERVER_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\Server" +#define SERVER_KEY "Software\\%s\\Server" enum AUTH_STATE { @@ -788,8 +788,14 @@ static void auth_get_sspi_module_from_reg(char** sspi_module) WINPR_ASSERT(sspi_module); *sspi_module = NULL; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, SERVER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey) != - ERROR_SUCCESS) + char* key = freerdp_getApplicatonDetailsRegKey(SERVER_KEY); + if (!key) + return; + + const LONG rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + free(key); + + if (rc != ERROR_SUCCESS) return; if (RegQueryValueExA(hKey, "SspiModule", NULL, &dwType, NULL, &dwSize) != ERROR_SUCCESS) diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 17d398aa0..a34bef682 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -54,8 +54,6 @@ #define TAG FREERDP_TAG("core.nla") -// #define SERVER_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\Server" - #define NLA_AUTH_PKG NEGO_SSP_NAME typedef enum diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 5a3a65856..406110004 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -40,6 +40,7 @@ #include #include +#include "../core/utils.h" #include "../crypto/certificate.h" #include "../crypto/privatekey.h" #include "capabilities.h" @@ -53,8 +54,8 @@ static const char client_dll[] = "C:\\Windows\\System32\\mstscax.dll"; -#define SERVER_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\Server" -#define CLIENT_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\Client" +#define SERVER_KEY "Software\\%s\\Server" +#define CLIENT_KEY "Software\\%s\\Client" #define BITMAP_CACHE_KEY CLIENT_KEY "\\BitmapCacheV2" #define GLYPH_CACHE_KEY CLIENT_KEY "\\GlyphCache" #define POINTER_CACHE_KEY CLIENT_KEY "\\PointerCache" @@ -187,119 +188,165 @@ static BOOL settings_reg_query_bool(rdpSettings* settings, FreeRDP_Settings_Keys static void settings_client_load_hkey_local_machine(rdpSettings* settings) { - HKEY hKey = NULL; - LONG status = 0; - status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, CLIENT_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - - if (status == ERROR_SUCCESS) { - settings_reg_query_dword(settings, FreeRDP_DesktopWidth, hKey, _T("DesktopWidth")); - settings_reg_query_dword(settings, FreeRDP_DesktopHeight, hKey, _T("DesktopHeight")); - settings_reg_query_bool(settings, FreeRDP_Fullscreen, hKey, _T("Fullscreen")); - settings_reg_query_dword(settings, FreeRDP_ColorDepth, hKey, _T("ColorDepth")); - settings_reg_query_dword(settings, FreeRDP_KeyboardType, hKey, _T("KeyboardType")); - settings_reg_query_dword(settings, FreeRDP_KeyboardSubType, hKey, _T("KeyboardSubType")); - settings_reg_query_dword(settings, FreeRDP_KeyboardFunctionKey, hKey, - _T("KeyboardFunctionKeys")); - settings_reg_query_dword(settings, FreeRDP_KeyboardLayout, hKey, _T("KeyboardLayout")); - settings_reg_query_bool(settings, FreeRDP_ExtSecurity, hKey, _T("ExtSecurity")); - settings_reg_query_bool(settings, FreeRDP_NlaSecurity, hKey, _T("NlaSecurity")); - settings_reg_query_bool(settings, FreeRDP_TlsSecurity, hKey, _T("TlsSecurity")); - settings_reg_query_bool(settings, FreeRDP_RdpSecurity, hKey, _T("RdpSecurity")); - settings_reg_query_bool(settings, FreeRDP_MstscCookieMode, hKey, _T("MstscCookieMode")); - settings_reg_query_dword(settings, FreeRDP_CookieMaxLength, hKey, _T("CookieMaxLength")); - settings_reg_query_bool(settings, FreeRDP_BitmapCacheEnabled, hKey, _T("BitmapCache")); - settings_reg_query_dword(settings, FreeRDP_OffscreenSupportLevel, hKey, - _T("OffscreenBitmapCache")); - settings_reg_query_dword(settings, FreeRDP_OffscreenCacheSize, hKey, - _T("OffscreenBitmapCacheSize")); - settings_reg_query_dword(settings, FreeRDP_OffscreenCacheEntries, hKey, - _T("OffscreenBitmapCacheEntries")); - RegCloseKey(hKey); - } - - status = - RegOpenKeyExA(HKEY_LOCAL_MACHINE, BITMAP_CACHE_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - - if (status == ERROR_SUCCESS) - { - settings_reg_query_dword(settings, FreeRDP_BitmapCacheV2NumCells, hKey, _T("NumCells")); - for (unsigned x = 0; x < 5; x++) + char* key = freerdp_getApplicatonDetailsRegKey(CLIENT_KEY); + if (key) { - DWORD val = 0; - TCHAR numentries[64] = { 0 }; - TCHAR persist[64] = { 0 }; - BITMAP_CACHE_V2_CELL_INFO cache = { 0 }; - (void)_sntprintf(numentries, ARRAYSIZE(numentries), _T("Cell%uNumEntries"), x); - (void)_sntprintf(persist, ARRAYSIZE(persist), _T("Cell%uPersistent"), x); - if (!settings_reg_query_dword_val(hKey, numentries, &val) || - !settings_reg_query_bool_val(hKey, persist, &cache.persistent) || - !freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, x, - &cache)) - WLog_WARN(TAG, "Failed to load registry keys to settings!"); - cache.numEntries = val; - } + HKEY hKey = NULL; + const LONG status = + RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + free(key); - settings_reg_query_bool(settings, FreeRDP_AllowCacheWaitingList, hKey, - _T("AllowCacheWaitingList")); - RegCloseKey(hKey); + if (status == ERROR_SUCCESS) + { + settings_reg_query_dword(settings, FreeRDP_DesktopWidth, hKey, _T("DesktopWidth")); + settings_reg_query_dword(settings, FreeRDP_DesktopHeight, hKey, + _T("DesktopHeight")); + settings_reg_query_bool(settings, FreeRDP_Fullscreen, hKey, _T("Fullscreen")); + settings_reg_query_dword(settings, FreeRDP_ColorDepth, hKey, _T("ColorDepth")); + settings_reg_query_dword(settings, FreeRDP_KeyboardType, hKey, _T("KeyboardType")); + settings_reg_query_dword(settings, FreeRDP_KeyboardSubType, hKey, + _T("KeyboardSubType")); + settings_reg_query_dword(settings, FreeRDP_KeyboardFunctionKey, hKey, + _T("KeyboardFunctionKeys")); + settings_reg_query_dword(settings, FreeRDP_KeyboardLayout, hKey, + _T("KeyboardLayout")); + settings_reg_query_bool(settings, FreeRDP_ExtSecurity, hKey, _T("ExtSecurity")); + settings_reg_query_bool(settings, FreeRDP_NlaSecurity, hKey, _T("NlaSecurity")); + settings_reg_query_bool(settings, FreeRDP_TlsSecurity, hKey, _T("TlsSecurity")); + settings_reg_query_bool(settings, FreeRDP_RdpSecurity, hKey, _T("RdpSecurity")); + settings_reg_query_bool(settings, FreeRDP_MstscCookieMode, hKey, + _T("MstscCookieMode")); + settings_reg_query_dword(settings, FreeRDP_CookieMaxLength, hKey, + _T("CookieMaxLength")); + settings_reg_query_bool(settings, FreeRDP_BitmapCacheEnabled, hKey, + _T("BitmapCache")); + settings_reg_query_dword(settings, FreeRDP_OffscreenSupportLevel, hKey, + _T("OffscreenBitmapCache")); + settings_reg_query_dword(settings, FreeRDP_OffscreenCacheSize, hKey, + _T("OffscreenBitmapCacheSize")); + settings_reg_query_dword(settings, FreeRDP_OffscreenCacheEntries, hKey, + _T("OffscreenBitmapCacheEntries")); + RegCloseKey(hKey); + } + } } - - status = - RegOpenKeyExA(HKEY_LOCAL_MACHINE, GLYPH_CACHE_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - - if (status == ERROR_SUCCESS) { - unsigned x = 0; - UINT32 GlyphSupportLevel = 0; - settings_reg_query_dword(settings, FreeRDP_GlyphSupportLevel, hKey, _T("SupportLevel")); - for (; x < 10; x++) + char* key = freerdp_getApplicatonDetailsRegKey(BITMAP_CACHE_KEY); + if (key) { - GLYPH_CACHE_DEFINITION cache = { 0 }; - TCHAR numentries[64] = { 0 }; - TCHAR maxsize[64] = { 0 }; - (void)_sntprintf(numentries, ARRAYSIZE(numentries), _T("Cache%uNumEntries"), x); - (void)_sntprintf(maxsize, ARRAYSIZE(maxsize), _T("Cache%uMaxCellSize"), x); + HKEY hKey = NULL; + const LONG status = + RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + free(key); - settings_reg_query_word_val(hKey, numentries, &cache.cacheEntries); - settings_reg_query_word_val(hKey, maxsize, &cache.cacheMaximumCellSize); - if (!freerdp_settings_set_pointer_array(settings, FreeRDP_GlyphCache, x, &cache)) - WLog_WARN(TAG, "Failed to store GlyphCache %u", x); + if (status == ERROR_SUCCESS) + { + settings_reg_query_dword(settings, FreeRDP_BitmapCacheV2NumCells, hKey, + _T("NumCells")); + for (unsigned x = 0; x < 5; x++) + { + DWORD val = 0; + TCHAR numentries[64] = { 0 }; + TCHAR persist[64] = { 0 }; + BITMAP_CACHE_V2_CELL_INFO cache = { 0 }; + (void)_sntprintf(numentries, ARRAYSIZE(numentries), _T("Cell%uNumEntries"), x); + (void)_sntprintf(persist, ARRAYSIZE(persist), _T("Cell%uPersistent"), x); + if (!settings_reg_query_dword_val(hKey, numentries, &val) || + !settings_reg_query_bool_val(hKey, persist, &cache.persistent) || + !freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, + x, &cache)) + WLog_WARN(TAG, "Failed to load registry keys to settings!"); + cache.numEntries = val; + } + + settings_reg_query_bool(settings, FreeRDP_AllowCacheWaitingList, hKey, + _T("AllowCacheWaitingList")); + RegCloseKey(hKey); + } } - { - GLYPH_CACHE_DEFINITION cache = { 0 }; - settings_reg_query_word_val(hKey, _T("FragCacheNumEntries"), &cache.cacheEntries); - settings_reg_query_word_val(hKey, _T("FragCacheMaxCellSize"), - &cache.cacheMaximumCellSize); - if (!freerdp_settings_set_pointer_array(settings, FreeRDP_FragCache, x, &cache)) - WLog_WARN(TAG, "Failed to store FragCache"); - } - - RegCloseKey(hKey); - - if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel, GlyphSupportLevel)) - WLog_WARN(TAG, "Failed to load registry keys to settings!"); } - - status = - RegOpenKeyExA(HKEY_LOCAL_MACHINE, POINTER_CACHE_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - - if (status == ERROR_SUCCESS) { - settings_reg_query_dword(settings, FreeRDP_LargePointerFlag, hKey, _T("LargePointer")); - settings_reg_query_dword(settings, FreeRDP_PointerCacheSize, hKey, _T("PointerCacheSize")); - settings_reg_query_dword(settings, FreeRDP_ColorPointerCacheSize, hKey, - _T("ColorPointerCacheSize")); - RegCloseKey(hKey); + char* key = freerdp_getApplicatonDetailsRegKey(GLYPH_CACHE_KEY); + if (key) + { + HKEY hKey = NULL; + const LONG status = + RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + free(key); + + if (status == ERROR_SUCCESS) + { + unsigned x = 0; + UINT32 GlyphSupportLevel = 0; + settings_reg_query_dword(settings, FreeRDP_GlyphSupportLevel, hKey, + _T("SupportLevel")); + for (; x < 10; x++) + { + GLYPH_CACHE_DEFINITION cache = { 0 }; + TCHAR numentries[64] = { 0 }; + TCHAR maxsize[64] = { 0 }; + (void)_sntprintf(numentries, ARRAYSIZE(numentries), _T("Cache%uNumEntries"), x); + (void)_sntprintf(maxsize, ARRAYSIZE(maxsize), _T("Cache%uMaxCellSize"), x); + + settings_reg_query_word_val(hKey, numentries, &cache.cacheEntries); + settings_reg_query_word_val(hKey, maxsize, &cache.cacheMaximumCellSize); + if (!freerdp_settings_set_pointer_array(settings, FreeRDP_GlyphCache, x, + &cache)) + WLog_WARN(TAG, "Failed to store GlyphCache %u", x); + } + { + GLYPH_CACHE_DEFINITION cache = { 0 }; + settings_reg_query_word_val(hKey, _T("FragCacheNumEntries"), + &cache.cacheEntries); + settings_reg_query_word_val(hKey, _T("FragCacheMaxCellSize"), + &cache.cacheMaximumCellSize); + if (!freerdp_settings_set_pointer_array(settings, FreeRDP_FragCache, x, &cache)) + WLog_WARN(TAG, "Failed to store FragCache"); + } + + RegCloseKey(hKey); + + if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel, + GlyphSupportLevel)) + WLog_WARN(TAG, "Failed to load registry keys to settings!"); + } + } + } + { + char* key = freerdp_getApplicatonDetailsRegKey(POINTER_CACHE_KEY); + if (key) + { + HKEY hKey = NULL; + const LONG status = + RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + free(key); + + if (status == ERROR_SUCCESS) + { + settings_reg_query_dword(settings, FreeRDP_LargePointerFlag, hKey, + _T("LargePointer")); + settings_reg_query_dword(settings, FreeRDP_PointerCacheSize, hKey, + _T("PointerCacheSize")); + settings_reg_query_dword(settings, FreeRDP_ColorPointerCacheSize, hKey, + _T("ColorPointerCacheSize")); + RegCloseKey(hKey); + } + } } } static void settings_server_load_hkey_local_machine(rdpSettings* settings) { HKEY hKey = NULL; - LONG status = 0; - status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, SERVER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + char* key = freerdp_getApplicatonDetailsRegKey(SERVER_KEY); + if (!key) + return; + + const LONG status = + RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + free(key); if (status != ERROR_SUCCESS) return; diff --git a/libfreerdp/core/utils.h b/libfreerdp/core/utils.h index 252a6244c..6d750de4d 100644 --- a/libfreerdp/core/utils.h +++ b/libfreerdp/core/utils.h @@ -62,4 +62,35 @@ char* utils_redir_flags_to_string(UINT32 flags, char* buffer, size_t size); BOOL utils_reload_channels(rdpContext* context); +/** @brief generate a registry key string of format 'someting\\%s\\foo' + * + * @param fmt A format string that must contain a single '%s' being replaced by the + * 'vendor\\product` values. + * + * @return A registry key to use or \b NULL if failed. + * @version since 3.23.0 + */ +WINPR_ATTR_MALLOC(free, 1) +WINPR_ATTR_NODISCARD +char* freerdp_getApplicatonDetailsRegKey(WINPR_FORMAT_ARG const char* fmt); + +/** @brief generate a 'vendor/product' string with desired separator + * + * @param separator the separator character to use + * + * @return A 'vendor/product' string to use or \b NULL if failed. + * @version since 3.23.0 + */ +WINPR_ATTR_MALLOC(free, 1) +WINPR_ATTR_NODISCARD +char* freerdp_getApplicatonDetailsCombined(char separator); + +/** @brief returns if we are using default compile time 'vendor' and 'product' settings or an + * application provided one. + * + * @return \b TRUE if \b freerdp_setApplicationDetails was called, \b FALSE otherwise. + * @version since 3.23.0 + */ +WINPR_ATTR_NODISCARD BOOL freerdp_areApplicationDetailsCustomized(void); + #endif /* FREERDP_LIB_CORE_UTILS_H */ diff --git a/libfreerdp/utils/helpers.c b/libfreerdp/utils/helpers.c index 85faa747b..ff1cc3703 100644 --- a/libfreerdp/utils/helpers.c +++ b/libfreerdp/utils/helpers.c @@ -23,9 +23,134 @@ #include #include +#include +#include #include #include +#include "../core/utils.h" + +static INIT_ONCE s_freerdp_app_details_once = INIT_ONCE_STATIC_INIT; +static char s_freerdp_vendor_string[MAX_PATH] = { 0 }; +static char s_freerdp_product_string[MAX_PATH] = { 0 }; +static SSIZE_T s_freerdp_version = -1; +static BOOL s_freerdp_app_details_are_custom = FALSE; + +static BOOL CALLBACK init_app_details(WINPR_ATTR_UNUSED PINIT_ONCE once, + WINPR_ATTR_UNUSED PVOID param, + WINPR_ATTR_UNUSED PVOID* context) +{ + const size_t vlen = sizeof(FREERDP_VENDOR_STRING); + const size_t plen = sizeof(FREERDP_PRODUCT_STRING); + const char* rvlen = strncpy(s_freerdp_vendor_string, FREERDP_VENDOR_STRING, vlen); + const char* rplen = strncpy(s_freerdp_product_string, FREERDP_PRODUCT_STRING, plen); + if (!rvlen || !rplen) + return FALSE; + +#if defined(WITH_RESOURCE_VERSIONING) + s_freerdp_version = FREERDP_API_VERSION; +#else + s_freerdp_version = -1; +#endif + return TRUE; +} + +static WINPR_ATTR_NODISCARD BOOL initializeApplicationDetails(void) +{ + InitOnceExecuteOnce(&s_freerdp_app_details_once, init_app_details, NULL, NULL); + return TRUE; +} + +BOOL freerdp_setApplicationDetails(const char* vendor, const char* product, SSIZE_T version) +{ + if (!initializeApplicationDetails()) + return -1; + + if (!vendor || !product) + return FALSE; + const size_t vlen = strnlen(vendor, MAX_PATH); + const size_t plen = strnlen(product, MAX_PATH); + if ((vlen == MAX_PATH) || (plen == MAX_PATH)) + return FALSE; + + if (!strncpy(s_freerdp_vendor_string, vendor, vlen + 1)) + return FALSE; + + if (!strncpy(s_freerdp_product_string, product, plen + 1)) + return FALSE; + + s_freerdp_version = version; + s_freerdp_app_details_are_custom = TRUE; + + const char separator = PathGetSeparatorA(PATH_STYLE_NATIVE); + char* str = freerdp_getApplicatonDetailsCombined(separator); + if (!str) + return FALSE; + + const BOOL rc = winpr_setApplicationDetails(str, "WinPR", -1); + free(str); + return rc; +} + +const char* freerdp_getApplicationDetailsVendor(void) +{ + if (!initializeApplicationDetails()) + return NULL; + return s_freerdp_vendor_string; +} + +const char* freerdp_getApplicationDetailsProduct(void) +{ + if (!initializeApplicationDetails()) + return NULL; + return s_freerdp_product_string; +} + +char* freerdp_getApplicatonDetailsRegKey(const char* fmt) +{ + char* val = freerdp_getApplicatonDetailsCombined('\\'); + if (!val) + return NULL; + + char* str = NULL; + size_t slen = 0; + (void)winpr_asprintf(&str, &slen, fmt, val); + free(val); + return str; +} + +char* freerdp_getApplicatonDetailsCombined(char separator) +{ + const SSIZE_T version = freerdp_getApplicationDetailsVersion(); + const char* vendor = freerdp_getApplicationDetailsVendor(); + const char* product = freerdp_getApplicationDetailsProduct(); + + size_t slen = 0; + char* str = NULL; + if (version < 0) + { + (void)winpr_asprintf(&str, &slen, "%s%c%s", vendor, separator, product); + } + else + { + (void)winpr_asprintf(&str, &slen, "%s%c%s%" PRIdz, vendor, separator, product, version); + } + + return str; +} + +SSIZE_T freerdp_getApplicationDetailsVersion(void) +{ + if (!initializeApplicationDetails()) + return -1; + return s_freerdp_version; +} + +BOOL freerdp_areApplicationDetailsCustomized(void) +{ + return s_freerdp_app_details_are_custom; +} + #if !defined(WITH_FULL_CONFIG_PATH) WINPR_ATTR_MALLOC(free, 1) WINPR_ATTR_NODISCARD @@ -47,31 +172,28 @@ static char* freerdp_settings_get_legacy_config_path(const char* filename) } #endif -char* freerdp_GetConfigFilePath(BOOL system, const char* filename) +WINPR_ATTR_NODISCARD +WINPR_ATTR_MALLOC(free, 1) static char* getCustomConfigPath(BOOL system, const char* filename) { eKnownPathTypes id = system ? KNOWN_PATH_SYSTEM_CONFIG_HOME : KNOWN_PATH_XDG_CONFIG_HOME; -#if defined(FREERDP_USE_VENDOR_PRODUCT_CONFIG_DIR) - char* vendor = GetKnownSubPath(id, FREERDP_VENDOR_STRING); -#else -#if !defined(WITH_FULL_CONFIG_PATH) - if (!system && (_stricmp(FREERDP_VENDOR_STRING, FREERDP_PRODUCT_STRING) == 0)) - return freerdp_settings_get_legacy_config_path(filename); -#endif + const char* vendor = freerdp_getApplicationDetailsVendor(); + const char* product = freerdp_getApplicationDetailsProduct(); + const SSIZE_T version = freerdp_getApplicationDetailsVersion(); - char* vendor = GetKnownPath(id); -#endif - if (!vendor) + if (!vendor || !product) return NULL; -#if defined(WITH_RESOURCE_VERSIONING) - const char* verstr = FREERDP_PRODUCT_STRING FREERDP_API_VERSION; -#else - const char* verstr = FREERDP_PRODUCT_STRING; -#endif + char* config = GetKnownSubPathV(id, "%s", vendor); + if (!config) + return NULL; - char* base = GetCombinedPath(vendor, verstr); - free(vendor); + char* base = NULL; + if (version < 0) + base = GetCombinedPathV(config, "%s", product); + else + base = GetCombinedPathV(config, "%s%" PRIdz, product, version); + free(config); if (!base) return NULL; @@ -79,7 +201,53 @@ char* freerdp_GetConfigFilePath(BOOL system, const char* filename) if (!filename) return base; - char* path = GetCombinedPath(base, filename); + char* path = GetCombinedPathV(base, "%s", filename); + free(base); + return path; +} + +char* freerdp_GetConfigFilePath(BOOL system, const char* filename) +{ +#if defined(FREERDP_USE_VENDOR_PRODUCT_CONFIG_DIR) + const BOOL customized = TRUE; +#else + const BOOL customized = freerdp_areApplicationDetailsCustomized(); +#endif + if (customized) + return getCustomConfigPath(system, filename); + + eKnownPathTypes id = system ? KNOWN_PATH_SYSTEM_CONFIG_HOME : KNOWN_PATH_XDG_CONFIG_HOME; + + const char* vendor = freerdp_getApplicationDetailsVendor(); + const char* product = freerdp_getApplicationDetailsProduct(); + const SSIZE_T version = freerdp_getApplicationDetailsVersion(); + + if (!vendor || !product) + return NULL; + +#if !defined(WITH_FULL_CONFIG_PATH) + if (!system && (_stricmp(vendor, product) == 0)) + return freerdp_settings_get_legacy_config_path(filename); +#endif + + char* config = GetKnownPath(id); + if (!config) + return NULL; + + char* base = NULL; + if (version < 0) + base = GetCombinedPathV(config, "%s", product); + else + base = GetCombinedPathV(config, "%s%" PRIdz, product, version); + free(config); + + if (!base) + return NULL; + + if (!filename) + return base; + + char* path = GetCombinedPathV(base, "%s", filename); free(base); return path; }