Added runtime configuration option for kerberos/NTLM fallback

This commit is contained in:
Armin Novak 2022-02-15 09:41:39 +01:00 committed by akallabeth
parent 082720a392
commit 8231a7e7a7
2 changed files with 77 additions and 11 deletions

View File

@ -67,7 +67,7 @@ elseif(WITH_GSSAPI)
endif() endif()
include(CMakeDependentOption) 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) CMAKE_DEPENDENT_OPTION(WITH_GSS_NO_NTLM_FALLBACK "Do not fall back to NTLM if no kerberos ticket available" OFF "WITH_GSSAPI" ON)
if (WITH_GSS_NO_NTLM_FALLBACK) if (WITH_GSS_NO_NTLM_FALLBACK)
add_definitions("-DWITH_GSS_NO_NTLM_FALLBACK") add_definitions("-DWITH_GSS_NO_NTLM_FALLBACK")
endif() endif()

View File

@ -26,6 +26,8 @@
#include <winpr/sspi.h> #include <winpr/sspi.h>
#include <winpr/tchar.h> #include <winpr/tchar.h>
#include <winpr/assert.h> #include <winpr/assert.h>
#include <winpr/registry.h>
#include <winpr/build-config.h>
#include "negotiate.h" #include "negotiate.h"
@ -33,6 +35,9 @@
#include "../../log.h" #include "../../log.h"
#define TAG WINPR_TAG("negotiate") #define TAG WINPR_TAG("negotiate")
static const char NEGO_REG_KEY[] =
"Software\\" WINPR_VENDOR_STRING "\\" WINPR_PRODUCT_STRING "\\SSPI\\Negotiate";
extern const SecurityFunctionTableA NTLM_SecurityFunctionTableA; extern const SecurityFunctionTableA NTLM_SecurityFunctionTableA;
extern const SecurityFunctionTableW NTLM_SecurityFunctionTableW; extern const SecurityFunctionTableW NTLM_SecurityFunctionTableW;
@ -108,13 +113,68 @@ static void negotiate_ContextFree(NEGOTIATE_CONTEXT* context)
free(context); free(context);
} }
static BOOL negotaite_get_dword(HKEY hKey, const char* subkey, DWORD* pdwValue)
{
DWORD dwValue = 0, dwType = 0;
DWORD dwSize = sizeof(dwValue);
LONG rc = RegQueryValueExA(hKey, subkey, NULL, &dwType, (BYTE*)&dwValue, &dwSize);
if (rc != ERROR_SUCCESS)
return FALSE;
if (dwType != REG_DWORD)
return FALSE;
*pdwValue = dwValue;
return TRUE;
}
static BOOL negotiate_get_config(BOOL* kerberos, BOOL* ntlm)
{
HKEY hKey = NULL;
LONG rc;
WINPR_ASSERT(kerberos);
WINPR_ASSERT(ntlm);
#if !defined(WITH_GSS_NO_NTLM_FALLBACK)
*ntlm = TRUE;
#else
*ntlm = FALSE;
#endif
*kerberos = TRUE;
rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, NEGO_REG_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
if (rc == ERROR_SUCCESS)
{
DWORD dwValue;
if (negotaite_get_dword(hKey, "kerberos", &dwValue))
*kerberos = (dwValue != 0) ? TRUE : FALSE;
#if !defined(WITH_GSS_NO_NTLM_FALLBACK)
if (negotaite_get_dword(hKey, "ntlm", &dwValue))
*ntlm = (dwValue != 0) ? TRUE : FALSE;
#endif
RegCloseKey(hKey);
}
return TRUE;
}
static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW( static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(
PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR* pszTargetName, ULONG fContextReq, PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR* pszTargetName, ULONG fContextReq,
ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2, ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry) PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
{ {
SECURITY_STATUS status; BOOL ntlm = TRUE;
NEGOTIATE_CONTEXT* context; BOOL kerberos = TRUE;
SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
NEGOTIATE_CONTEXT* context = NULL;
if (!negotiate_get_config(&kerberos, &ntlm))
return status;
context = (NEGOTIATE_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext); context = (NEGOTIATE_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
if (!context) if (!context)
@ -129,7 +189,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(
} }
/* if Kerberos has previously failed or WITH_GSSAPI is not defined, we use NTLM directly */ /* if Kerberos has previously failed or WITH_GSSAPI is not defined, we use NTLM directly */
if (ErrorInitContextKerberos == FALSE) if (kerberos && !ErrorInitContextKerberos)
{ {
if (!pInput) if (!pInput)
{ {
@ -144,7 +204,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(
ptsExpiry); ptsExpiry);
#if !defined(WITH_GSS_NO_NTLM_FALLBACK) #if !defined(WITH_GSS_NO_NTLM_FALLBACK)
if (status == SEC_E_NO_CREDENTIALS) if (ntlm && (status == SEC_E_NO_CREDENTIALS))
{ {
WLog_WARN(TAG, "No Kerberos credentials. Retry with NTLM"); WLog_WARN(TAG, "No Kerberos credentials. Retry with NTLM");
ErrorInitContextKerberos = TRUE; ErrorInitContextKerberos = TRUE;
@ -154,7 +214,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(
#endif #endif
} }
if (ErrorInitContextKerberos) if (ntlm && ErrorInitContextKerberos)
{ {
if (!pInput) if (!pInput)
{ {
@ -177,8 +237,14 @@ static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(
ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2, ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry) PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
{ {
SECURITY_STATUS status; BOOL ntlm = TRUE;
NEGOTIATE_CONTEXT* context; BOOL kerberos = TRUE;
SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
NEGOTIATE_CONTEXT* context = NULL;
if (!negotiate_get_config(&kerberos, &ntlm))
return status;
context = (NEGOTIATE_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext); context = (NEGOTIATE_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
if (!context) if (!context)
@ -193,7 +259,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(
} }
/* if Kerberos has previously failed or WITH_GSSAPI is not defined, we use NTLM directly */ /* if Kerberos has previously failed or WITH_GSSAPI is not defined, we use NTLM directly */
if (ErrorInitContextKerberos == FALSE) if (kerberos && !ErrorInitContextKerberos)
{ {
if (!pInput) if (!pInput)
{ {
@ -208,7 +274,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(
ptsExpiry); ptsExpiry);
#if !defined(WITH_GSS_NO_NTLM_FALLBACK) #if !defined(WITH_GSS_NO_NTLM_FALLBACK)
if (status == SEC_E_NO_CREDENTIALS) if (ntlm && (status == SEC_E_NO_CREDENTIALS))
{ {
WLog_WARN(TAG, "No Kerberos credentials. Retry with NTLM"); WLog_WARN(TAG, "No Kerberos credentials. Retry with NTLM");
ErrorInitContextKerberos = TRUE; ErrorInitContextKerberos = TRUE;
@ -218,7 +284,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(
#endif #endif
} }
if (ErrorInitContextKerberos) if (ntlm && ErrorInitContextKerberos)
{ {
if (!pInput) if (!pInput)
{ {