Add settings to load a custom SSPI shared library module

This commit is contained in:
Marc-André Moreau 2022-05-26 11:42:28 -04:00 committed by akallabeth
parent 4c4b5bfd87
commit 1d5c0be5ec
11 changed files with 115 additions and 27 deletions

View File

@ -1772,6 +1772,11 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
arg->Value))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "sspi-module")
{
if (!freerdp_settings_set_string(settings, FreeRDP_SspiModule, arg->Value))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "redirect-prefer")
{
size_t count = 0;

View File

@ -351,6 +351,8 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
"SPN authentication service class" },
{ "ssh-agent", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "ssh-agent",
"SSH Agent forwarding channel" },
{ "sspi-module", COMMAND_LINE_VALUE_REQUIRED, "<SSPI module path>", NULL, NULL, -1, NULL,
"SSPI shared library module file path" },
{ "disable-output", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
"Deactivate all graphics decoding in the client session. Useful for load tests with many "
"simultaneous connections" },

View File

@ -635,6 +635,7 @@ typedef struct
#define FreeRDP_NtlmSamFile (1103)
#define FreeRDP_FIPSMode (1104)
#define FreeRDP_TlsSecLevel (1105)
#define FreeRDP_SspiModule (1106)
#define FreeRDP_MstscCookieMode (1152)
#define FreeRDP_CookieMaxLength (1153)
#define FreeRDP_PreconnectionId (1154)
@ -1119,7 +1120,8 @@ struct rdp_settings
ALIGN64 char* NtlmSamFile; /* 1103 */
ALIGN64 BOOL FIPSMode; /* 1104 */
ALIGN64 UINT32 TlsSecLevel; /* 1105 */
UINT64 padding1152[1152 - 1106]; /* 1106 */
ALIGN64 char* SspiModule; /* 1106 */
UINT64 padding1152[1152 - 1107]; /* 1107 */
/* Connection Cookie */
ALIGN64 BOOL MstscCookieMode; /* 1152 */

View File

@ -2574,6 +2574,9 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id)
case FreeRDP_SmartcardPrivateKey:
return settings->SmartcardPrivateKey;
case FreeRDP_SspiModule:
return settings->SspiModule;
case FreeRDP_TargetNetAddress:
return settings->TargetNetAddress;
@ -2832,6 +2835,9 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id)
case FreeRDP_SmartcardPrivateKey:
return settings->SmartcardPrivateKey;
case FreeRDP_SspiModule:
return settings->SspiModule;
case FreeRDP_TargetNetAddress:
return settings->TargetNetAddress;
@ -3100,6 +3106,9 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char*
case FreeRDP_SmartcardPrivateKey:
return update_string(&settings->SmartcardPrivateKey, cnv.cc, len, cleanup);
case FreeRDP_SspiModule:
return update_string(&settings->SspiModule, cnv.cc, len, cleanup);
case FreeRDP_TargetNetAddress:
return update_string(&settings->TargetNetAddress, cnv.cc, len, cleanup);

View File

@ -387,6 +387,7 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_ShellWorkingDirectory, 7, "FreeRDP_ShellWorkingDirectory" },
{ FreeRDP_SmartcardCertificate, 7, "FreeRDP_SmartcardCertificate" },
{ FreeRDP_SmartcardPrivateKey, 7, "FreeRDP_SmartcardPrivateKey" },
{ FreeRDP_SspiModule, 7, "FreeRDP_SspiModule" },
{ FreeRDP_TargetNetAddress, 7, "FreeRDP_TargetNetAddress" },
{ FreeRDP_TransportDumpFile, 7, "FreeRDP_TransportDumpFile" },
{ FreeRDP_Username, 7, "FreeRDP_Username" },

View File

@ -1051,7 +1051,10 @@ static int nla_client_init(rdpNla* nla)
#else
nla->ServicePrincipalName = spn;
#endif
nla->table = InitSecurityInterfaceEx(0);
if (!nla_sspi_module_init(nla))
return -1;
nla->status = nla_update_package_name(nla);
if (nla->status != SEC_E_OK)
return -1;
@ -1381,31 +1384,8 @@ static int nla_server_init(rdpNla* nla)
return -1;
}
if (nla->SspiModule)
{
HMODULE hSSPI;
INIT_SECURITY_INTERFACE pInitSecurityInterface;
hSSPI = LoadLibraryX(nla->SspiModule);
if (!hSSPI)
{
WLog_ERR(TAG, "Failed to load SSPI module: %s", nla->SspiModule);
return -1;
}
#ifdef UNICODE
pInitSecurityInterface =
(INIT_SECURITY_INTERFACE)GetProcAddress(hSSPI, "InitSecurityInterfaceW");
#else
pInitSecurityInterface =
(INIT_SECURITY_INTERFACE)GetProcAddress(hSSPI, "InitSecurityInterfaceA");
#endif
nla->table = pInitSecurityInterface();
}
else
{
nla->table = InitSecurityInterfaceEx(0);
}
if (!nla_sspi_module_init(nla))
return -1;
nla->status = nla_update_package_name(nla);
@ -2724,6 +2704,14 @@ rdpNla* nla_new(rdpContext* context, rdpTransport* transport)
goto cleanup;
}
if (settings->SspiModule)
{
nla->SspiModule = _strdup(settings->SspiModule);
if (!nla->SspiModule)
goto cleanup;
}
/* init to 0 or we end up freeing a bad pointer if the alloc fails */
if (!nla_sec_buffer_alloc(&nla->ClientNonce, NonceLength))
goto cleanup;
@ -2814,6 +2802,9 @@ void nla_free(rdpNla* nla)
free(nla->SamFile);
nla->SamFile = NULL;
free(nla->SspiModule);
nla->SspiModule = NULL;
nla_buffer_free(nla);
sspi_SecBufferFree(&nla->ClientNonce);
sspi_SecBufferFree(&nla->PublicKey);
@ -2864,6 +2855,65 @@ BOOL nla_set_service_principal(rdpNla* nla, LPTSTR principal)
return TRUE;
}
BOOL nla_set_sspi_module(rdpNla* nla, const char* sspiModule)
{
if (!nla)
return FALSE;
if (nla->SspiModule)
{
free(nla->SspiModule);
nla->SspiModule = NULL;
}
if (!sspiModule)
return TRUE;
#ifdef UNICODE
ConvertToUnicode(CP_UTF8, 0, sspiModule, -1, &nla->SspiModule, 0);
#else
nla->SspiModule = _strdup(sspiModule);
#endif
if (!nla->SspiModule)
return FALSE;
return TRUE;
}
BOOL nla_sspi_module_init(rdpNla* nla)
{
if (!nla)
return FALSE;
if (nla->SspiModule)
{
INIT_SECURITY_INTERFACE pInitSecurityInterface;
HMODULE hSSPI = LoadLibraryX(nla->SspiModule);
if (!hSSPI)
{
WLog_ERR(TAG, "Failed to load SSPI module: %s", nla->SspiModule);
return FALSE;
}
#ifdef UNICODE
pInitSecurityInterface =
(INIT_SECURITY_INTERFACE)GetProcAddress(hSSPI, "InitSecurityInterfaceW");
#else
pInitSecurityInterface =
(INIT_SECURITY_INTERFACE)GetProcAddress(hSSPI, "InitSecurityInterfaceA");
#endif
nla->table = pInitSecurityInterface();
}
else
{
nla->table = InitSecurityInterfaceEx(0);
}
return TRUE;
}
BOOL nla_impersonate(rdpNla* nla)
{
if (!nla)

View File

@ -62,6 +62,9 @@ FREERDP_LOCAL DWORD nla_get_error(rdpNla* nla);
FREERDP_LOCAL BOOL nla_set_service_principal(rdpNla* nla, LPTSTR principal);
FREERDP_LOCAL BOOL nla_set_sspi_module(rdpNla* nla, const char* sspiModule);
FREERDP_LOCAL BOOL nla_sspi_module_init(rdpNla* nla);
FREERDP_LOCAL BOOL nla_impersonate(rdpNla* nla);
FREERDP_LOCAL BOOL nla_revert_to_self(rdpNla* nla);

View File

@ -396,6 +396,7 @@ static const size_t string_list_indices[] = {
FreeRDP_ShellWorkingDirectory,
FreeRDP_SmartcardCertificate,
FreeRDP_SmartcardPrivateKey,
FreeRDP_SspiModule,
FreeRDP_TargetNetAddress,
FreeRDP_TransportDumpFile,
FreeRDP_Username,

View File

@ -70,6 +70,13 @@ elseif(WITH_GSSAPI)
endif()
endif()
# This option MUST be off to avoid symbol conflicts when loading an external SSPI module library
option(SSPI_DLL "Define and export SSPI API symbols for usage as a Windows SSPI DLL replacement" OFF)
if(SSPI_DLL)
add_definitions("-DSSPI_DLL")
endif()
include(CMakeDependentOption)
CMAKE_DEPENDENT_OPTION(WITH_GSS_NO_NTLM_FALLBACK "Do not fall back to NTLM if no kerberos ticket available" OFF "WITH_GSSAPI" OFF)
if (WITH_GSS_NO_NTLM_FALLBACK)

View File

@ -1053,6 +1053,8 @@ extern "C"
{
#endif
#ifdef SSPI_DLL
/* Package Management */
WINPR_API SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesA(ULONG* pcPackages,
@ -1148,6 +1150,8 @@ extern "C"
PSecBufferDesc pMessage, ULONG MessageSeqNo,
PULONG pfQOP);
#endif /* SSPI_DLL */
#ifdef __cplusplus
}
#endif

View File

@ -39,6 +39,8 @@ typedef LONG SECURITY_STATUS;
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
#endif
#ifdef SSPI_DLL
/**
* Standard SSPI API
*/
@ -322,6 +324,8 @@ SSPI_EXPORT SECURITY_STATUS SEC_ENTRY VerifySignature(void* phContext, void* pMe
return sspi_VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP);
}
#endif /* SSPI_DLL */
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif