Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
120
third_party/FreeRDP/winpr/libwinpr/sspi/CMakeLists.txt
vendored
Normal file
120
third_party/FreeRDP/winpr/libwinpr/sspi/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
# WinPR: Windows Portable Runtime
|
||||
# libwinpr-sspi cmake build script
|
||||
#
|
||||
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set(MODULE_PREFIX "WINPR_SSPI")
|
||||
|
||||
set(${MODULE_PREFIX}_NTLM_SRCS
|
||||
NTLM/ntlm_av_pairs.c
|
||||
NTLM/ntlm_av_pairs.h
|
||||
NTLM/ntlm_compute.c
|
||||
NTLM/ntlm_compute.h
|
||||
NTLM/ntlm_message.c
|
||||
NTLM/ntlm_message.h
|
||||
NTLM/ntlm.c
|
||||
NTLM/ntlm.h
|
||||
NTLM/ntlm_export.h
|
||||
)
|
||||
|
||||
set(${MODULE_PREFIX}_KERBEROS_SRCS Kerberos/kerberos.c Kerberos/kerberos.h)
|
||||
|
||||
set(${MODULE_PREFIX}_NEGOTIATE_SRCS Negotiate/negotiate.c Negotiate/negotiate.h)
|
||||
|
||||
set(${MODULE_PREFIX}_SCHANNEL_SRCS Schannel/schannel_openssl.c Schannel/schannel_openssl.h Schannel/schannel.c
|
||||
Schannel/schannel.h
|
||||
)
|
||||
|
||||
set(${MODULE_PREFIX}_CREDSSP_SRCS CredSSP/credssp.c CredSSP/credssp.h)
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
sspi_winpr.c
|
||||
sspi_winpr.h
|
||||
sspi_export.c
|
||||
sspi_gss.c
|
||||
sspi_gss.h
|
||||
sspi.c
|
||||
sspi.h
|
||||
)
|
||||
|
||||
set(KRB5_DEFAULT OFF)
|
||||
if(NOT WIN32 AND NOT ANDROID AND NOT IOS AND NOT APPLE)
|
||||
set(KRB5_DEFAULT ON)
|
||||
endif()
|
||||
|
||||
option(WITH_DEBUG_SCHANNEL "Compile support for SCHANNEL debug" ${DEFAULT_DEBUG_OPTION})
|
||||
if(WITH_DEBUG_SCHANNEL)
|
||||
winpr_definition_add(WITH_DEBUG_SCHANNEL)
|
||||
endif()
|
||||
|
||||
option(WITH_KRB5 "Compile support for kerberos authentication." ${KRB5_DEFAULT})
|
||||
if(WITH_KRB5)
|
||||
find_package(KRB5 REQUIRED)
|
||||
|
||||
list(APPEND ${MODULE_PREFIX}_KERBEROS_SRCS Kerberos/krb5glue.h)
|
||||
|
||||
winpr_system_include_directory_add(${KRB5_INCLUDEDIR})
|
||||
winpr_system_include_directory_add(${KRB5_INCLUDE_DIRS})
|
||||
winpr_library_add_private(${KRB5_LIBRARIES})
|
||||
winpr_library_add_private(${KRB5_LIBRARY})
|
||||
winpr_library_add_compile_options(${KRB5_CFLAGS})
|
||||
winpr_library_add_link_options(${KRB5_LDFLAGS})
|
||||
winpr_library_add_link_directory(${KRB5_LIBRARY_DIRS})
|
||||
|
||||
winpr_definition_add(WITH_KRB5)
|
||||
|
||||
if(KRB5_FLAVOUR STREQUAL "MIT")
|
||||
winpr_definition_add(WITH_KRB5_MIT)
|
||||
winpr_pc_add_requires_private("mit-krb5")
|
||||
list(APPEND ${MODULE_PREFIX}_KERBEROS_SRCS Kerberos/krb5glue_mit.c)
|
||||
elseif(KRB5_FLAVOUR STREQUAL "Heimdal")
|
||||
winpr_definition_add(WITH_KRB5_HEIMDAL)
|
||||
winpr_pc_add_requires_private("krb5")
|
||||
list(APPEND ${MODULE_PREFIX}_KERBEROS_SRCS Kerberos/krb5glue_heimdal.c)
|
||||
else()
|
||||
message(WARNING "Kerberos version not detected")
|
||||
endif()
|
||||
|
||||
include(CMakeDependentOption)
|
||||
cmake_dependent_option(
|
||||
WITH_KRB5_NO_NTLM_FALLBACK "Do not fall back to NTLM if no kerberos ticket available" OFF "WITH_KRB5" OFF
|
||||
)
|
||||
if(WITH_KRB5_NO_NTLM_FALLBACK)
|
||||
add_compile_definitions("WITH_KRB5_NO_NTLM_FALLBACK")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
winpr_module_add(
|
||||
${${MODULE_PREFIX}_CREDSSP_SRCS} ${${MODULE_PREFIX}_NTLM_SRCS} ${${MODULE_PREFIX}_KERBEROS_SRCS}
|
||||
${${MODULE_PREFIX}_NEGOTIATE_SRCS} ${${MODULE_PREFIX}_SCHANNEL_SRCS} ${${MODULE_PREFIX}_SRCS}
|
||||
)
|
||||
|
||||
if(OPENSSL_FOUND)
|
||||
winpr_system_include_directory_add(${OPENSSL_INCLUDE_DIR})
|
||||
winpr_library_add_private(${OPENSSL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(MBEDTLS_FOUND)
|
||||
winpr_system_include_directory_add(${MBEDTLS_INCLUDE_DIR})
|
||||
winpr_library_add_private(${MBEDTLS_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
winpr_library_add_public(ws2_32)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
339
third_party/FreeRDP/winpr/libwinpr/sspi/CredSSP/credssp.c
vendored
Normal file
339
third_party/FreeRDP/winpr/libwinpr/sspi/CredSSP/credssp.c
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Credential Security Support Provider (CredSSP)
|
||||
*
|
||||
* Copyright 2010-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#include "credssp.h"
|
||||
|
||||
#include "../sspi.h"
|
||||
#include "../../log.h"
|
||||
|
||||
#define TAG WINPR_TAG("sspi.CredSSP")
|
||||
|
||||
static const char* CREDSSP_PACKAGE_NAME = "CredSSP";
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextW(
|
||||
WINPR_ATTR_UNUSED PCredHandle phCredential, WINPR_ATTR_UNUSED PCtxtHandle phContext,
|
||||
WINPR_ATTR_UNUSED SEC_WCHAR* pszTargetName, WINPR_ATTR_UNUSED ULONG fContextReq,
|
||||
WINPR_ATTR_UNUSED ULONG Reserved1, WINPR_ATTR_UNUSED ULONG TargetDataRep,
|
||||
WINPR_ATTR_UNUSED PSecBufferDesc pInput, WINPR_ATTR_UNUSED ULONG Reserved2,
|
||||
WINPR_ATTR_UNUSED PCtxtHandle phNewContext, WINPR_ATTR_UNUSED PSecBufferDesc pOutput,
|
||||
WINPR_ATTR_UNUSED PULONG pfContextAttr, WINPR_ATTR_UNUSED PTimeStamp ptsExpiry)
|
||||
{
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextA(
|
||||
PCredHandle phCredential, PCtxtHandle phContext, WINPR_ATTR_UNUSED SEC_CHAR* pszTargetName,
|
||||
WINPR_ATTR_UNUSED ULONG fContextReq, WINPR_ATTR_UNUSED ULONG Reserved1,
|
||||
WINPR_ATTR_UNUSED ULONG TargetDataRep, WINPR_ATTR_UNUSED PSecBufferDesc pInput,
|
||||
WINPR_ATTR_UNUSED ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
WINPR_ATTR_UNUSED PSecBufferDesc pOutput, WINPR_ATTR_UNUSED PULONG pfContextAttr,
|
||||
WINPR_ATTR_UNUSED PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDSSP_CONTEXT* context = nullptr;
|
||||
SSPI_CREDENTIALS* credentials = nullptr;
|
||||
|
||||
/* behave like windows SSPIs that don't want empty context */
|
||||
if (phContext && !phContext->dwLower && !phContext->dwUpper)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
context = (CREDSSP_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
union
|
||||
{
|
||||
const void* cpv;
|
||||
void* pv;
|
||||
} cnv;
|
||||
context = credssp_ContextNew();
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
credentials = (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
{
|
||||
credssp_ContextFree(context);
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
|
||||
cnv.cpv = CREDSSP_PACKAGE_NAME;
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, cnv.pv);
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
CREDSSP_CONTEXT* credssp_ContextNew(void)
|
||||
{
|
||||
CREDSSP_CONTEXT* context = nullptr;
|
||||
context = (CREDSSP_CONTEXT*)calloc(1, sizeof(CREDSSP_CONTEXT));
|
||||
|
||||
if (!context)
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void credssp_ContextFree(CREDSSP_CONTEXT* context)
|
||||
{
|
||||
free(context);
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_QueryContextAttributes(PCtxtHandle phContext,
|
||||
WINPR_ATTR_UNUSED ULONG ulAttribute,
|
||||
void* pBuffer)
|
||||
{
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleW(
|
||||
WINPR_ATTR_UNUSED SEC_WCHAR* pszPrincipal, WINPR_ATTR_UNUSED SEC_WCHAR* pszPackage,
|
||||
WINPR_ATTR_UNUSED ULONG fCredentialUse, WINPR_ATTR_UNUSED void* pvLogonID,
|
||||
WINPR_ATTR_UNUSED void* pAuthData, WINPR_ATTR_UNUSED SEC_GET_KEY_FN pGetKeyFn,
|
||||
WINPR_ATTR_UNUSED void* pvGetKeyArgument, WINPR_ATTR_UNUSED PCredHandle phCredential,
|
||||
WINPR_ATTR_UNUSED PTimeStamp ptsExpiry)
|
||||
{
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleA(
|
||||
WINPR_ATTR_UNUSED SEC_CHAR* pszPrincipal, WINPR_ATTR_UNUSED SEC_CHAR* pszPackage,
|
||||
WINPR_ATTR_UNUSED ULONG fCredentialUse, WINPR_ATTR_UNUSED void* pvLogonID,
|
||||
WINPR_ATTR_UNUSED void* pAuthData, WINPR_ATTR_UNUSED SEC_GET_KEY_FN pGetKeyFn,
|
||||
WINPR_ATTR_UNUSED void* pvGetKeyArgument, WINPR_ATTR_UNUSED PCredHandle phCredential,
|
||||
WINPR_ATTR_UNUSED PTimeStamp ptsExpiry)
|
||||
{
|
||||
SSPI_CREDENTIALS* credentials = nullptr;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity = nullptr;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
{
|
||||
union
|
||||
{
|
||||
const void* cpv;
|
||||
void* pv;
|
||||
} cnv;
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*)pAuthData;
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
|
||||
|
||||
cnv.cpv = CREDSSP_PACKAGE_NAME;
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, cnv.pv);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesW(
|
||||
WINPR_ATTR_UNUSED PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
|
||||
WINPR_ATTR_UNUSED void* pBuffer)
|
||||
{
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA(
|
||||
WINPR_ATTR_UNUSED PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
|
||||
WINPR_ATTR_UNUSED void* pBuffer)
|
||||
{
|
||||
if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
|
||||
{
|
||||
SSPI_CREDENTIALS* credentials =
|
||||
(SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_FreeCredentialsHandle(PCredHandle phCredential)
|
||||
{
|
||||
SSPI_CREDENTIALS* credentials = nullptr;
|
||||
|
||||
if (!phCredential)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
credentials = (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
sspi_CredentialsFree(credentials);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_EncryptMessage(WINPR_ATTR_UNUSED PCtxtHandle phContext,
|
||||
WINPR_ATTR_UNUSED ULONG fQOP,
|
||||
WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
|
||||
WINPR_ATTR_UNUSED ULONG MessageSeqNo)
|
||||
{
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_DecryptMessage(WINPR_ATTR_UNUSED PCtxtHandle phContext,
|
||||
WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
|
||||
WINPR_ATTR_UNUSED ULONG MessageSeqNo,
|
||||
WINPR_ATTR_UNUSED ULONG* pfQOP)
|
||||
{
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_MakeSignature(WINPR_ATTR_UNUSED PCtxtHandle phContext,
|
||||
WINPR_ATTR_UNUSED ULONG fQOP,
|
||||
WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
|
||||
WINPR_ATTR_UNUSED ULONG MessageSeqNo)
|
||||
{
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY credssp_VerifySignature(WINPR_ATTR_UNUSED PCtxtHandle phContext,
|
||||
WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
|
||||
WINPR_ATTR_UNUSED ULONG MessageSeqNo,
|
||||
WINPR_ATTR_UNUSED ULONG* pfQOP)
|
||||
{
|
||||
WLog_ERR(TAG, "TODO: Implement");
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
const SecurityFunctionTableA CREDSSP_SecurityFunctionTableA = {
|
||||
3, /* dwVersion */
|
||||
nullptr, /* EnumerateSecurityPackages */
|
||||
credssp_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
|
||||
credssp_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
|
||||
credssp_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
nullptr, /* Reserved2 */
|
||||
credssp_InitializeSecurityContextA, /* InitializeSecurityContext */
|
||||
nullptr, /* AcceptSecurityContext */
|
||||
nullptr, /* CompleteAuthToken */
|
||||
nullptr, /* DeleteSecurityContext */
|
||||
nullptr, /* ApplyControlToken */
|
||||
credssp_QueryContextAttributes, /* QueryContextAttributes */
|
||||
nullptr, /* ImpersonateSecurityContext */
|
||||
nullptr, /* RevertSecurityContext */
|
||||
credssp_MakeSignature, /* MakeSignature */
|
||||
credssp_VerifySignature, /* VerifySignature */
|
||||
nullptr, /* FreeContextBuffer */
|
||||
nullptr, /* QuerySecurityPackageInfo */
|
||||
nullptr, /* Reserved3 */
|
||||
nullptr, /* Reserved4 */
|
||||
nullptr, /* ExportSecurityContext */
|
||||
nullptr, /* ImportSecurityContext */
|
||||
nullptr, /* AddCredentials */
|
||||
nullptr, /* Reserved8 */
|
||||
nullptr, /* QuerySecurityContextToken */
|
||||
credssp_EncryptMessage, /* EncryptMessage */
|
||||
credssp_DecryptMessage, /* DecryptMessage */
|
||||
nullptr, /* SetContextAttributes */
|
||||
nullptr, /* SetCredentialsAttributes */
|
||||
};
|
||||
|
||||
const SecurityFunctionTableW CREDSSP_SecurityFunctionTableW = {
|
||||
3, /* dwVersion */
|
||||
nullptr, /* EnumerateSecurityPackages */
|
||||
credssp_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
|
||||
credssp_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
|
||||
credssp_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
nullptr, /* Reserved2 */
|
||||
credssp_InitializeSecurityContextW, /* InitializeSecurityContext */
|
||||
nullptr, /* AcceptSecurityContext */
|
||||
nullptr, /* CompleteAuthToken */
|
||||
nullptr, /* DeleteSecurityContext */
|
||||
nullptr, /* ApplyControlToken */
|
||||
credssp_QueryContextAttributes, /* QueryContextAttributes */
|
||||
nullptr, /* ImpersonateSecurityContext */
|
||||
nullptr, /* RevertSecurityContext */
|
||||
credssp_MakeSignature, /* MakeSignature */
|
||||
credssp_VerifySignature, /* VerifySignature */
|
||||
nullptr, /* FreeContextBuffer */
|
||||
nullptr, /* QuerySecurityPackageInfo */
|
||||
nullptr, /* Reserved3 */
|
||||
nullptr, /* Reserved4 */
|
||||
nullptr, /* ExportSecurityContext */
|
||||
nullptr, /* ImportSecurityContext */
|
||||
nullptr, /* AddCredentials */
|
||||
nullptr, /* Reserved8 */
|
||||
nullptr, /* QuerySecurityContextToken */
|
||||
credssp_EncryptMessage, /* EncryptMessage */
|
||||
credssp_DecryptMessage, /* DecryptMessage */
|
||||
nullptr, /* SetContextAttributes */
|
||||
nullptr, /* SetCredentialsAttributes */
|
||||
};
|
||||
|
||||
const SecPkgInfoA CREDSSP_SecPkgInfoA = {
|
||||
0x000110733, /* fCapabilities */
|
||||
1, /* wVersion */
|
||||
0xFFFF, /* wRPCID */
|
||||
0x000090A8, /* cbMaxToken */
|
||||
"CREDSSP", /* Name */
|
||||
"Microsoft CredSSP Security Provider" /* Comment */
|
||||
};
|
||||
|
||||
static WCHAR CREDSSP_SecPkgInfoW_NameBuffer[128] = WINPR_C_ARRAY_INIT;
|
||||
static WCHAR CREDSSP_SecPkgInfoW_CommentBuffer[128] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
const SecPkgInfoW CREDSSP_SecPkgInfoW = {
|
||||
0x000110733, /* fCapabilities */
|
||||
1, /* wVersion */
|
||||
0xFFFF, /* wRPCID */
|
||||
0x000090A8, /* cbMaxToken */
|
||||
CREDSSP_SecPkgInfoW_NameBuffer, /* Name */
|
||||
CREDSSP_SecPkgInfoW_CommentBuffer /* Comment */
|
||||
};
|
||||
|
||||
BOOL CREDSSP_init(void)
|
||||
{
|
||||
InitializeConstWCharFromUtf8(CREDSSP_SecPkgInfoA.Name, CREDSSP_SecPkgInfoW_NameBuffer,
|
||||
ARRAYSIZE(CREDSSP_SecPkgInfoW_NameBuffer));
|
||||
InitializeConstWCharFromUtf8(CREDSSP_SecPkgInfoA.Comment, CREDSSP_SecPkgInfoW_CommentBuffer,
|
||||
ARRAYSIZE(CREDSSP_SecPkgInfoW_CommentBuffer));
|
||||
return TRUE;
|
||||
}
|
||||
42
third_party/FreeRDP/winpr/libwinpr/sspi/CredSSP/credssp.h
vendored
Normal file
42
third_party/FreeRDP/winpr/libwinpr/sspi/CredSSP/credssp.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Credential Security Support Provider (CredSSP)
|
||||
*
|
||||
* Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_CREDSSP_PRIVATE_H
|
||||
#define WINPR_SSPI_CREDSSP_PRIVATE_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#include "../sspi.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BOOL server;
|
||||
} CREDSSP_CONTEXT;
|
||||
|
||||
CREDSSP_CONTEXT* credssp_ContextNew(void);
|
||||
void credssp_ContextFree(CREDSSP_CONTEXT* context);
|
||||
|
||||
extern const SecPkgInfoA CREDSSP_SecPkgInfoA;
|
||||
extern const SecPkgInfoW CREDSSP_SecPkgInfoW;
|
||||
extern const SecurityFunctionTableA CREDSSP_SecurityFunctionTableA;
|
||||
extern const SecurityFunctionTableW CREDSSP_SecurityFunctionTableW;
|
||||
|
||||
BOOL CREDSSP_init(void);
|
||||
|
||||
#endif /* WINPR_SSPI_CREDSSP_PRIVATE_H */
|
||||
2464
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/kerberos.c
vendored
Normal file
2464
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/kerberos.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
39
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/kerberos.h
vendored
Normal file
39
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/kerberos.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* Kerberos Auth Protocol
|
||||
*
|
||||
* Copyright 2015 ANSSI, Author Thomas Calderon
|
||||
* Copyright 2017 Dorian Ducournau <dorian.ducournau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_KERBEROS_PRIVATE_H
|
||||
#define WINPR_SSPI_KERBEROS_PRIVATE_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include "../sspi.h"
|
||||
#include "../../log.h"
|
||||
|
||||
typedef struct s_KRB_CONTEXT KRB_CONTEXT;
|
||||
|
||||
extern const SecPkgInfoA KERBEROS_SecPkgInfoA;
|
||||
extern const SecPkgInfoW KERBEROS_SecPkgInfoW;
|
||||
extern const SecurityFunctionTableA KERBEROS_SecurityFunctionTableA;
|
||||
extern const SecurityFunctionTableW KERBEROS_SecurityFunctionTableW;
|
||||
|
||||
BOOL KERBEROS_init(void);
|
||||
|
||||
#endif /* WINPR_SSPI_KERBEROS_PRIVATE_H */
|
||||
108
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/krb5glue.h
vendored
Normal file
108
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/krb5glue.h
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* Kerberos Auth Protocol
|
||||
*
|
||||
* Copyright 2022 Isaac Klein <fifthdegree@protonmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_KERBEROS_GLUE_PRIVATE_H
|
||||
#define WINPR_SSPI_KERBEROS_GLUE_PRIVATE_H
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#include <krb5.h>
|
||||
|
||||
#if defined(WITH_KRB5_MIT)
|
||||
typedef krb5_key krb5glue_key;
|
||||
typedef krb5_authenticator* krb5glue_authenticator;
|
||||
|
||||
#define krb5glue_free_authenticator(ctx, auth) krb5_free_authenticator((ctx), (auth))
|
||||
|
||||
#define krb5glue_crypto_length(ctx, key, type, size) \
|
||||
krb5_c_crypto_length(ctx, krb5_k_key_enctype(ctx, key), type, size)
|
||||
#define krb5glue_crypto_length_iov(ctx, key, iov, size) \
|
||||
krb5_c_crypto_length_iov(ctx, krb5_k_key_enctype(ctx, key), iov, size)
|
||||
#define krb5glue_encrypt_iov(ctx, key, usage, iov, size) \
|
||||
krb5_k_encrypt_iov(ctx, key, usage, nullptr, iov, size)
|
||||
#define krb5glue_decrypt_iov(ctx, key, usage, iov, size) \
|
||||
krb5_k_decrypt_iov(ctx, key, usage, nullptr, iov, size)
|
||||
#define krb5glue_make_checksum_iov(ctx, key, usage, iov, size) \
|
||||
krb5_k_make_checksum_iov(ctx, 0, key, usage, iov, size)
|
||||
#define krb5glue_verify_checksum_iov(ctx, key, usage, iov, size, is_valid) \
|
||||
krb5_k_verify_checksum_iov(ctx, 0, key, usage, iov, size, is_valid)
|
||||
#define krb5glue_auth_con_set_cksumtype(ctx, auth_ctx, cksumtype) \
|
||||
krb5_auth_con_set_req_cksumtype(ctx, auth_ctx, cksumtype)
|
||||
#define krb5glue_set_principal_realm(ctx, principal, realm) \
|
||||
krb5_set_principal_realm(ctx, principal, realm)
|
||||
#define krb5glue_free_keytab_entry_contents(ctx, entry) krb5_free_keytab_entry_contents(ctx, entry)
|
||||
#define krb5glue_auth_con_setuseruserkey(ctx, auth_ctx, keytab) \
|
||||
krb5_auth_con_setuseruserkey(ctx, auth_ctx, keytab)
|
||||
#define krb5glue_free_data_contents(ctx, data) krb5_free_data_contents(ctx, data)
|
||||
krb5_prompt_type krb5glue_get_prompt_type(krb5_context ctx, krb5_prompt prompts[], int index);
|
||||
|
||||
#define krb5glue_creds_getkey(creds) creds.keyblock
|
||||
|
||||
#elif defined(WITH_KRB5_HEIMDAL)
|
||||
typedef krb5_crypto krb5glue_key;
|
||||
typedef krb5_authenticator krb5glue_authenticator;
|
||||
|
||||
#define krb5glue_free_authenticator(ctx, auth) krb5_free_authenticator((ctx), &(auth))
|
||||
|
||||
krb5_error_code krb5glue_crypto_length(krb5_context ctx, krb5glue_key key, int type,
|
||||
unsigned int* size);
|
||||
#define krb5glue_crypto_length_iov(ctx, key, iov, size) krb5_crypto_length_iov(ctx, key, iov, size)
|
||||
#define krb5glue_encrypt_iov(ctx, key, usage, iov, size) \
|
||||
krb5_encrypt_iov_ivec(ctx, key, usage, iov, size, nullptr)
|
||||
#define krb5glue_decrypt_iov(ctx, key, usage, iov, size) \
|
||||
krb5_decrypt_iov_ivec(ctx, key, usage, iov, size, nullptr)
|
||||
#define krb5glue_make_checksum_iov(ctx, key, usage, iov, size) \
|
||||
krb5_create_checksum_iov(ctx, key, usage, iov, size, nullptr)
|
||||
krb5_error_code krb5glue_verify_checksum_iov(krb5_context ctx, krb5glue_key key,
|
||||
krb5_keyusage usage, krb5_crypto_iov* iov,
|
||||
unsigned int iov_size, krb5_boolean* is_valid);
|
||||
#define krb5glue_auth_con_set_cksumtype(ctx, auth_ctx, cksumtype) \
|
||||
krb5_auth_con_setcksumtype(ctx, auth_ctx, cksumtype)
|
||||
#define krb5glue_set_principal_realm(ctx, principal, realm) \
|
||||
krb5_principal_set_realm(ctx, principal, realm)
|
||||
#define krb5glue_free_keytab_entry_contents(ctx, entry) krb5_kt_free_entry(ctx, entry)
|
||||
#define krb5glue_auth_con_setuseruserkey(ctx, auth_ctx, keytab) \
|
||||
krb5_auth_con_setuserkey(ctx, auth_ctx, keytab)
|
||||
#define krb5glue_free_data_contents(ctx, data) krb5_data_free(data)
|
||||
#define krb5glue_get_prompt_type(ctx, prompts, index) prompts[index].type
|
||||
|
||||
#define krb5glue_creds_getkey(creds) creds.session
|
||||
#else
|
||||
#error "Missing implementation for KRB5 provider"
|
||||
#endif
|
||||
|
||||
struct krb5glue_keyset
|
||||
{
|
||||
krb5glue_key session_key;
|
||||
krb5glue_key initiator_key;
|
||||
krb5glue_key acceptor_key;
|
||||
};
|
||||
|
||||
void krb5glue_keys_free(krb5_context ctx, struct krb5glue_keyset* keyset);
|
||||
krb5_error_code krb5glue_update_keyset(krb5_context ctx, krb5_auth_context auth_ctx, BOOL acceptor,
|
||||
struct krb5glue_keyset* keyset);
|
||||
krb5_error_code krb5glue_log_error(krb5_context ctx, krb5_data* msg, const char* tag);
|
||||
BOOL krb5glue_authenticator_validate_chksum(krb5glue_authenticator authenticator, int cksumtype,
|
||||
uint32_t* flags);
|
||||
krb5_error_code krb5glue_get_init_creds(krb5_context ctx, krb5_principal princ, krb5_ccache ccache,
|
||||
krb5_prompter_fct prompter, char* password,
|
||||
SEC_WINPR_KERBEROS_SETTINGS* krb_settings);
|
||||
|
||||
#endif /* WINPR_SSPI_KERBEROS_GLUE_PRIVATE_H */
|
||||
216
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/krb5glue_heimdal.c
vendored
Normal file
216
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/krb5glue_heimdal.c
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* Kerberos Auth Protocol
|
||||
*
|
||||
* Copyright 2022 Isaac Klein <fifthdegree@protonmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WITH_KRB5_HEIMDAL
|
||||
#error "This file must only be included with HEIMDAL kerberos"
|
||||
#endif
|
||||
|
||||
#include <winpr/endian.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/assert.h>
|
||||
#include "krb5glue.h"
|
||||
|
||||
void krb5glue_keys_free(krb5_context ctx, struct krb5glue_keyset* keyset)
|
||||
{
|
||||
if (!ctx || !keyset)
|
||||
return;
|
||||
if (keyset->session_key)
|
||||
krb5_crypto_destroy(ctx, keyset->session_key);
|
||||
if (keyset->initiator_key)
|
||||
krb5_crypto_destroy(ctx, keyset->initiator_key);
|
||||
if (keyset->acceptor_key)
|
||||
krb5_crypto_destroy(ctx, keyset->acceptor_key);
|
||||
}
|
||||
|
||||
krb5_error_code krb5glue_update_keyset(krb5_context ctx, krb5_auth_context auth_ctx, BOOL acceptor,
|
||||
struct krb5glue_keyset* keyset)
|
||||
{
|
||||
krb5_keyblock* keyblock = nullptr;
|
||||
krb5_error_code rv = 0;
|
||||
|
||||
WINPR_ASSERT(ctx);
|
||||
WINPR_ASSERT(auth_ctx);
|
||||
WINPR_ASSERT(keyset);
|
||||
|
||||
krb5glue_keys_free(ctx, keyset);
|
||||
|
||||
rv = krb5_auth_con_getkey(ctx, auth_ctx, &keyblock);
|
||||
if (!rv)
|
||||
{
|
||||
krb5_crypto_init(ctx, keyblock, ENCTYPE_NULL, &keyset->session_key);
|
||||
krb5_free_keyblock(ctx, keyblock);
|
||||
keyblock = nullptr;
|
||||
}
|
||||
|
||||
if (acceptor)
|
||||
rv = krb5_auth_con_getremotesubkey(ctx, auth_ctx, &keyblock);
|
||||
else
|
||||
rv = krb5_auth_con_getlocalsubkey(ctx, auth_ctx, &keyblock);
|
||||
|
||||
if (!rv && keyblock)
|
||||
{
|
||||
krb5_crypto_init(ctx, keyblock, ENCTYPE_NULL, &keyset->initiator_key);
|
||||
krb5_free_keyblock(ctx, keyblock);
|
||||
keyblock = nullptr;
|
||||
}
|
||||
|
||||
if (acceptor)
|
||||
rv = krb5_auth_con_getlocalsubkey(ctx, auth_ctx, &keyblock);
|
||||
else
|
||||
rv = krb5_auth_con_getremotesubkey(ctx, auth_ctx, &keyblock);
|
||||
|
||||
if (!rv && keyblock)
|
||||
{
|
||||
krb5_crypto_init(ctx, keyblock, ENCTYPE_NULL, &keyset->acceptor_key);
|
||||
krb5_free_keyblock(ctx, keyblock);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
krb5_error_code krb5glue_verify_checksum_iov(krb5_context ctx, krb5glue_key key,
|
||||
krb5_keyusage usage, krb5_crypto_iov* iov,
|
||||
unsigned int iov_size, krb5_boolean* is_valid)
|
||||
{
|
||||
krb5_error_code rv = 0;
|
||||
|
||||
WINPR_ASSERT(ctx);
|
||||
WINPR_ASSERT(key);
|
||||
WINPR_ASSERT(is_valid);
|
||||
|
||||
rv = krb5_verify_checksum_iov(ctx, key, usage, iov, iov_size, nullptr);
|
||||
*is_valid = (rv == 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
krb5_error_code krb5glue_crypto_length(krb5_context ctx, krb5glue_key key, int type,
|
||||
unsigned int* size)
|
||||
{
|
||||
krb5_error_code rv = 0;
|
||||
size_t s = 0;
|
||||
|
||||
WINPR_ASSERT(ctx);
|
||||
WINPR_ASSERT(key);
|
||||
WINPR_ASSERT(size);
|
||||
|
||||
rv = krb5_crypto_length(ctx, key, type, &s);
|
||||
*size = (UINT)s;
|
||||
return rv;
|
||||
}
|
||||
|
||||
krb5_error_code krb5glue_log_error(krb5_context ctx, krb5_data* msg, const char* tag)
|
||||
{
|
||||
krb5_error error = WINPR_C_ARRAY_INIT;
|
||||
krb5_error_code rv = 0;
|
||||
|
||||
WINPR_ASSERT(ctx);
|
||||
WINPR_ASSERT(msg);
|
||||
WINPR_ASSERT(tag);
|
||||
|
||||
if (!(rv = krb5_rd_error(ctx, msg, &error)))
|
||||
{
|
||||
WLog_ERR(tag, "KRB_ERROR: %" PRIx32, error.error_code);
|
||||
krb5_free_error_contents(ctx, &error);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
BOOL krb5glue_authenticator_validate_chksum(krb5glue_authenticator authenticator, int cksumtype,
|
||||
uint32_t* flags)
|
||||
{
|
||||
WINPR_ASSERT(flags);
|
||||
|
||||
if (!authenticator || !authenticator->cksum || authenticator->cksum->cksumtype != cksumtype ||
|
||||
authenticator->cksum->checksum.length < 24)
|
||||
return FALSE;
|
||||
|
||||
const BYTE* data = authenticator->cksum->checksum.data;
|
||||
Data_Read_UINT32((data + 20), (*flags));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
krb5_error_code krb5glue_get_init_creds(krb5_context ctx, krb5_principal princ, krb5_ccache ccache,
|
||||
krb5_prompter_fct prompter, char* password,
|
||||
SEC_WINPR_KERBEROS_SETTINGS* krb_settings)
|
||||
{
|
||||
krb5_error_code rv = 0;
|
||||
krb5_deltat start_time = 0;
|
||||
krb5_get_init_creds_opt* gic_opt = nullptr;
|
||||
krb5_init_creds_context creds_ctx = nullptr;
|
||||
krb5_creds creds = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(ctx);
|
||||
|
||||
do
|
||||
{
|
||||
if ((rv = krb5_get_init_creds_opt_alloc(ctx, &gic_opt)) != 0)
|
||||
break;
|
||||
|
||||
krb5_get_init_creds_opt_set_forwardable(gic_opt, 0);
|
||||
krb5_get_init_creds_opt_set_proxiable(gic_opt, 0);
|
||||
|
||||
if (krb_settings)
|
||||
{
|
||||
if (krb_settings->startTime)
|
||||
start_time = krb_settings->startTime;
|
||||
if (krb_settings->lifeTime)
|
||||
krb5_get_init_creds_opt_set_tkt_life(gic_opt, krb_settings->lifeTime);
|
||||
if (krb_settings->renewLifeTime)
|
||||
krb5_get_init_creds_opt_set_renew_life(gic_opt, krb_settings->renewLifeTime);
|
||||
if (krb_settings->withPac)
|
||||
krb5_get_init_creds_opt_set_pac_request(ctx, gic_opt, TRUE);
|
||||
if (krb_settings->pkinitX509Anchors || krb_settings->pkinitX509Identity)
|
||||
{
|
||||
if ((rv = krb5_get_init_creds_opt_set_pkinit(
|
||||
ctx, gic_opt, princ, krb_settings->pkinitX509Identity,
|
||||
krb_settings->pkinitX509Anchors, nullptr, nullptr, 0, prompter, password,
|
||||
password)) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rv = krb5_init_creds_init(ctx, princ, prompter, password, start_time, gic_opt,
|
||||
&creds_ctx)) != 0)
|
||||
break;
|
||||
if ((rv = krb5_init_creds_set_password(ctx, creds_ctx, password)) != 0)
|
||||
break;
|
||||
if (krb_settings && krb_settings->armorCache)
|
||||
{
|
||||
krb5_ccache armor_cc = nullptr;
|
||||
if ((rv = krb5_cc_resolve(ctx, krb_settings->armorCache, &armor_cc)) != 0)
|
||||
break;
|
||||
if ((rv = krb5_init_creds_set_fast_ccache(ctx, creds_ctx, armor_cc)) != 0)
|
||||
break;
|
||||
krb5_cc_close(ctx, armor_cc);
|
||||
}
|
||||
if ((rv = krb5_init_creds_get(ctx, creds_ctx)) != 0)
|
||||
break;
|
||||
if ((rv = krb5_init_creds_get_creds(ctx, creds_ctx, &creds)) != 0)
|
||||
break;
|
||||
if ((rv = krb5_cc_store_cred(ctx, ccache, &creds)) != 0)
|
||||
break;
|
||||
} while (0);
|
||||
|
||||
krb5_free_cred_contents(ctx, &creds);
|
||||
krb5_init_creds_free(ctx, creds_ctx);
|
||||
krb5_get_init_creds_opt_free(ctx, gic_opt);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
258
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/krb5glue_mit.c
vendored
Normal file
258
third_party/FreeRDP/winpr/libwinpr/sspi/Kerberos/krb5glue_mit.c
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* Kerberos Auth Protocol
|
||||
*
|
||||
* Copyright 2022 Isaac Klein <fifthdegree@protonmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WITH_KRB5_MIT
|
||||
#error "This file must only be included with MIT kerberos"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/endian.h>
|
||||
#include <winpr/crypto.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <errno.h>
|
||||
#include "krb5glue.h"
|
||||
#include <profile.h>
|
||||
|
||||
static char* create_temporary_file(void)
|
||||
{
|
||||
BYTE buffer[32];
|
||||
char* hex = nullptr;
|
||||
char* path = nullptr;
|
||||
|
||||
if (winpr_RAND(buffer, sizeof(buffer)) < 0)
|
||||
return nullptr;
|
||||
hex = winpr_BinToHexString(buffer, sizeof(buffer), FALSE);
|
||||
path = GetKnownSubPath(KNOWN_PATH_TEMP, hex);
|
||||
free(hex);
|
||||
return path;
|
||||
}
|
||||
|
||||
void krb5glue_keys_free(krb5_context ctx, struct krb5glue_keyset* keyset)
|
||||
{
|
||||
WINPR_ASSERT(ctx);
|
||||
WINPR_ASSERT(keyset);
|
||||
|
||||
krb5_k_free_key(ctx, keyset->session_key);
|
||||
krb5_k_free_key(ctx, keyset->initiator_key);
|
||||
krb5_k_free_key(ctx, keyset->acceptor_key);
|
||||
}
|
||||
|
||||
krb5_error_code krb5glue_update_keyset(krb5_context ctx, krb5_auth_context auth_ctx, BOOL acceptor,
|
||||
struct krb5glue_keyset* keyset)
|
||||
{
|
||||
WINPR_ASSERT(ctx);
|
||||
WINPR_ASSERT(auth_ctx);
|
||||
WINPR_ASSERT(keyset);
|
||||
|
||||
krb5glue_keys_free(ctx, keyset);
|
||||
krb5_auth_con_getkey_k(ctx, auth_ctx, &keyset->session_key);
|
||||
if (acceptor)
|
||||
{
|
||||
krb5_auth_con_getsendsubkey_k(ctx, auth_ctx, &keyset->acceptor_key);
|
||||
krb5_auth_con_getrecvsubkey_k(ctx, auth_ctx, &keyset->initiator_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
krb5_auth_con_getsendsubkey_k(ctx, auth_ctx, &keyset->initiator_key);
|
||||
krb5_auth_con_getrecvsubkey_k(ctx, auth_ctx, &keyset->acceptor_key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_prompt_type krb5glue_get_prompt_type(krb5_context ctx, krb5_prompt prompts[], int index)
|
||||
{
|
||||
WINPR_ASSERT(ctx);
|
||||
WINPR_ASSERT(prompts);
|
||||
WINPR_UNUSED(prompts);
|
||||
|
||||
krb5_prompt_type* types = krb5_get_prompt_types(ctx);
|
||||
return types ? types[index] : 0;
|
||||
}
|
||||
|
||||
krb5_error_code krb5glue_log_error(krb5_context ctx, krb5_data* msg, const char* tag)
|
||||
{
|
||||
krb5_error* error = nullptr;
|
||||
krb5_error_code rv = 0;
|
||||
|
||||
WINPR_ASSERT(ctx);
|
||||
WINPR_ASSERT(msg);
|
||||
WINPR_ASSERT(tag);
|
||||
|
||||
if (!(rv = krb5_rd_error(ctx, msg, &error)))
|
||||
{
|
||||
WLog_ERR(tag, "KRB_ERROR: %s", error->text.data);
|
||||
krb5_free_error(ctx, error);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
BOOL krb5glue_authenticator_validate_chksum(krb5glue_authenticator authenticator, int cksumtype,
|
||||
uint32_t* flags)
|
||||
{
|
||||
WINPR_ASSERT(flags);
|
||||
|
||||
if (!authenticator || !authenticator->checksum ||
|
||||
authenticator->checksum->checksum_type != cksumtype || authenticator->checksum->length < 24)
|
||||
return FALSE;
|
||||
*flags = winpr_Data_Get_UINT32((authenticator->checksum->contents + 20));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
krb5_error_code krb5glue_get_init_creds(krb5_context ctx, krb5_principal princ, krb5_ccache ccache,
|
||||
krb5_prompter_fct prompter, char* password,
|
||||
SEC_WINPR_KERBEROS_SETTINGS* krb_settings)
|
||||
{
|
||||
krb5_error_code rv = 0;
|
||||
krb5_deltat start_time = 0;
|
||||
krb5_get_init_creds_opt* gic_opt = nullptr;
|
||||
krb5_init_creds_context creds_ctx = nullptr;
|
||||
char* tmp_profile_path = create_temporary_file();
|
||||
profile_t profile = nullptr;
|
||||
BOOL is_temp_ctx = FALSE;
|
||||
|
||||
WINPR_ASSERT(ctx);
|
||||
|
||||
rv = krb5_get_init_creds_opt_alloc(ctx, &gic_opt);
|
||||
if (rv)
|
||||
goto cleanup;
|
||||
|
||||
krb5_get_init_creds_opt_set_forwardable(gic_opt, 0);
|
||||
krb5_get_init_creds_opt_set_proxiable(gic_opt, 0);
|
||||
|
||||
if (krb_settings)
|
||||
{
|
||||
if (krb_settings->startTime)
|
||||
start_time = krb_settings->startTime;
|
||||
if (krb_settings->lifeTime)
|
||||
krb5_get_init_creds_opt_set_tkt_life(gic_opt, krb_settings->lifeTime);
|
||||
if (krb_settings->renewLifeTime)
|
||||
krb5_get_init_creds_opt_set_renew_life(gic_opt, krb_settings->renewLifeTime);
|
||||
if (krb_settings->withPac)
|
||||
{
|
||||
rv = krb5_get_init_creds_opt_set_pac_request(ctx, gic_opt, TRUE);
|
||||
if (rv)
|
||||
goto cleanup;
|
||||
}
|
||||
if (krb_settings->armorCache)
|
||||
{
|
||||
rv = krb5_get_init_creds_opt_set_fast_ccache_name(ctx, gic_opt,
|
||||
krb_settings->armorCache);
|
||||
if (rv)
|
||||
goto cleanup;
|
||||
}
|
||||
if (krb_settings->pkinitX509Identity)
|
||||
{
|
||||
rv = krb5_get_init_creds_opt_set_pa(ctx, gic_opt, "X509_user_identity",
|
||||
krb_settings->pkinitX509Identity);
|
||||
if (rv)
|
||||
goto cleanup;
|
||||
}
|
||||
if (krb_settings->pkinitX509Anchors)
|
||||
{
|
||||
rv = krb5_get_init_creds_opt_set_pa(ctx, gic_opt, "X509_anchors",
|
||||
krb_settings->pkinitX509Anchors);
|
||||
if (rv)
|
||||
goto cleanup;
|
||||
}
|
||||
if (krb_settings->kdcUrl && (strnlen(krb_settings->kdcUrl, 2) > 0))
|
||||
{
|
||||
const char* names[4] = WINPR_C_ARRAY_INIT;
|
||||
char* realm = nullptr;
|
||||
char* kdc_url = nullptr;
|
||||
size_t size = 0;
|
||||
|
||||
if ((rv = krb5_get_profile(ctx, &profile)))
|
||||
goto cleanup;
|
||||
|
||||
rv = ENOMEM;
|
||||
if (winpr_asprintf(&kdc_url, &size, "https://%s/KdcProxy", krb_settings->kdcUrl) <= 0)
|
||||
{
|
||||
free(kdc_url);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
realm = calloc(princ->realm.length + 1, 1);
|
||||
if (!realm)
|
||||
{
|
||||
free(kdc_url);
|
||||
goto cleanup;
|
||||
}
|
||||
CopyMemory(realm, princ->realm.data, princ->realm.length);
|
||||
|
||||
names[0] = "realms";
|
||||
names[1] = realm;
|
||||
names[2] = "kdc";
|
||||
|
||||
profile_clear_relation(profile, names);
|
||||
profile_add_relation(profile, names, kdc_url);
|
||||
|
||||
/* Since we know who the KDC is, tell krb5 that its certificate is valid for pkinit */
|
||||
names[2] = "pkinit_kdc_hostname";
|
||||
profile_add_relation(profile, names, krb_settings->kdcUrl);
|
||||
|
||||
free(kdc_url);
|
||||
free(realm);
|
||||
|
||||
long lrv = profile_flush_to_file(profile, tmp_profile_path);
|
||||
if (lrv)
|
||||
goto cleanup;
|
||||
|
||||
profile_abandon(profile);
|
||||
profile = nullptr;
|
||||
lrv = profile_init_path(tmp_profile_path, &profile);
|
||||
if (lrv)
|
||||
goto cleanup;
|
||||
|
||||
rv = krb5_init_context_profile(profile, 0, &ctx);
|
||||
if (rv)
|
||||
goto cleanup;
|
||||
is_temp_ctx = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rv = krb5_get_init_creds_opt_set_in_ccache(ctx, gic_opt, ccache)))
|
||||
goto cleanup;
|
||||
|
||||
if ((rv = krb5_get_init_creds_opt_set_out_ccache(ctx, gic_opt, ccache)))
|
||||
goto cleanup;
|
||||
|
||||
if ((rv =
|
||||
krb5_init_creds_init(ctx, princ, prompter, password, start_time, gic_opt, &creds_ctx)))
|
||||
goto cleanup;
|
||||
|
||||
if ((rv = krb5_init_creds_get(ctx, creds_ctx)))
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
krb5_init_creds_free(ctx, creds_ctx);
|
||||
krb5_get_init_creds_opt_free(ctx, gic_opt);
|
||||
if (is_temp_ctx)
|
||||
krb5_free_context(ctx);
|
||||
profile_abandon(profile);
|
||||
winpr_DeleteFile(tmp_profile_path);
|
||||
free(tmp_profile_path);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
7
third_party/FreeRDP/winpr/libwinpr/sspi/ModuleOptions.cmake
vendored
Normal file
7
third_party/FreeRDP/winpr/libwinpr/sspi/ModuleOptions.cmake
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
set(MINWIN_LAYER "0")
|
||||
set(MINWIN_GROUP "none")
|
||||
set(MINWIN_MAJOR_VERSION "0")
|
||||
set(MINWIN_MINOR_VERSION "0")
|
||||
set(MINWIN_SHORT_NAME "sspi")
|
||||
set(MINWIN_LONG_NAME "Security Support Provider Interface")
|
||||
set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")
|
||||
1584
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm.c
vendored
Normal file
1584
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
301
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm.h
vendored
Normal file
301
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm.h
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_NTLM_PRIVATE_H
|
||||
#define WINPR_SSPI_NTLM_PRIVATE_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include <winpr/nt.h>
|
||||
#include <winpr/crypto.h>
|
||||
|
||||
#include "../sspi.h"
|
||||
|
||||
#define MESSAGE_TYPE_NEGOTIATE 1
|
||||
#define MESSAGE_TYPE_CHALLENGE 2
|
||||
#define MESSAGE_TYPE_AUTHENTICATE 3
|
||||
|
||||
#define NTLMSSP_NEGOTIATE_56 0x80000000 /* W (0) */
|
||||
#define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V (1) */
|
||||
#define NTLMSSP_NEGOTIATE_128 0x20000000 /* U (2) */
|
||||
#define NTLMSSP_RESERVED1 0x10000000 /* r1 (3) */
|
||||
#define NTLMSSP_RESERVED2 0x08000000 /* r2 (4) */
|
||||
#define NTLMSSP_RESERVED3 0x04000000 /* r3 (5) */
|
||||
#define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T (6) */
|
||||
#define NTLMSSP_RESERVED4 0x01000000 /* r4 (7) */
|
||||
#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S (8) */
|
||||
#define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R (9) */
|
||||
#define NTLMSSP_RESERVED5 0x00200000 /* r5 (10) */
|
||||
#define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q (11) */
|
||||
#define NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY 0x00080000 /* P (12) */
|
||||
#define NTLMSSP_RESERVED6 0x00040000 /* r6 (13) */
|
||||
#define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O (14) */
|
||||
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N (15) */
|
||||
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M (16) */
|
||||
#define NTLMSSP_RESERVED7 0x00004000 /* r7 (17) */
|
||||
#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000 /* L (18) */
|
||||
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000 /* K (19) */
|
||||
#define NTLMSSP_NEGOTIATE_ANONYMOUS 0x00000800 /* J (20) */
|
||||
#define NTLMSSP_RESERVED8 0x00000400 /* r8 (21) */
|
||||
#define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H (22) */
|
||||
#define NTLMSSP_RESERVED9 0x00000100 /* r9 (23) */
|
||||
#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G (24) */
|
||||
#define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F (25) */
|
||||
#define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E (26) */
|
||||
#define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D (27) */
|
||||
#define NTLMSSP_RESERVED10 0x00000008 /* r10 (28) */
|
||||
#define NTLMSSP_REQUEST_TARGET 0x00000004 /* C (29) */
|
||||
#define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B (30) */
|
||||
#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A (31) */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NTLM_STATE_INITIAL,
|
||||
NTLM_STATE_NEGOTIATE,
|
||||
NTLM_STATE_CHALLENGE,
|
||||
NTLM_STATE_AUTHENTICATE,
|
||||
NTLM_STATE_FINAL
|
||||
} NTLM_STATE;
|
||||
|
||||
#ifdef __MINGW32__
|
||||
typedef MSV1_0_AVID NTLM_AV_ID;
|
||||
|
||||
#if __MINGW64_VERSION_MAJOR < 9
|
||||
enum
|
||||
{
|
||||
MsvAvTimestamp = MsvAvFlags + 1,
|
||||
MsvAvRestrictions,
|
||||
MsvAvTargetName,
|
||||
MsvAvChannelBindings,
|
||||
MsvAvSingleHost = MsvAvRestrictions
|
||||
};
|
||||
|
||||
#else
|
||||
#ifndef MsvAvSingleHost
|
||||
#define MsvAvSingleHost MsvAvRestrictions
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
typedef enum
|
||||
{
|
||||
MsvAvEOL,
|
||||
MsvAvNbComputerName,
|
||||
MsvAvNbDomainName,
|
||||
MsvAvDnsComputerName,
|
||||
MsvAvDnsDomainName,
|
||||
MsvAvDnsTreeName,
|
||||
MsvAvFlags,
|
||||
MsvAvTimestamp,
|
||||
MsvAvSingleHost,
|
||||
MsvAvTargetName,
|
||||
MsvAvChannelBindings
|
||||
} NTLM_AV_ID;
|
||||
#endif /* __MINGW32__ */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT16 AvId;
|
||||
UINT16 AvLen;
|
||||
} NTLM_AV_PAIR;
|
||||
|
||||
#define MSV_AV_FLAGS_AUTHENTICATION_CONSTRAINED 0x00000001
|
||||
#define MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK 0x00000002
|
||||
#define MSV_AV_FLAGS_TARGET_SPN_UNTRUSTED_SOURCE 0x00000004
|
||||
|
||||
#define WINDOWS_MAJOR_VERSION_5 0x05
|
||||
#define WINDOWS_MAJOR_VERSION_6 0x06
|
||||
#define WINDOWS_MINOR_VERSION_0 0x00
|
||||
#define WINDOWS_MINOR_VERSION_1 0x01
|
||||
#define WINDOWS_MINOR_VERSION_2 0x02
|
||||
#define NTLMSSP_REVISION_W2K3 0x0F
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 ProductMajorVersion;
|
||||
UINT8 ProductMinorVersion;
|
||||
UINT16 ProductBuild;
|
||||
BYTE Reserved[3];
|
||||
UINT8 NTLMRevisionCurrent;
|
||||
} NTLM_VERSION_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 Size;
|
||||
UINT32 Z4;
|
||||
UINT32 DataPresent;
|
||||
UINT32 CustomData;
|
||||
BYTE MachineID[32];
|
||||
} NTLM_SINGLE_HOST_DATA;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Response[24];
|
||||
} NTLM_RESPONSE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 RespType;
|
||||
UINT8 HiRespType;
|
||||
UINT16 Reserved1;
|
||||
UINT32 Reserved2;
|
||||
BYTE Timestamp[8];
|
||||
BYTE ClientChallenge[8];
|
||||
UINT32 Reserved3;
|
||||
NTLM_AV_PAIR* AvPairs;
|
||||
UINT32 cbAvPairs;
|
||||
} NTLMv2_CLIENT_CHALLENGE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Response[16];
|
||||
NTLMv2_CLIENT_CHALLENGE Challenge;
|
||||
} NTLMv2_RESPONSE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT16 Len;
|
||||
UINT16 MaxLen;
|
||||
PBYTE Buffer;
|
||||
UINT32 BufferOffset;
|
||||
} NTLM_MESSAGE_FIELDS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Signature[8];
|
||||
UINT32 MessageType;
|
||||
} NTLM_MESSAGE_HEADER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NTLM_MESSAGE_HEADER header;
|
||||
UINT32 NegotiateFlags;
|
||||
NTLM_VERSION_INFO Version;
|
||||
NTLM_MESSAGE_FIELDS DomainName;
|
||||
NTLM_MESSAGE_FIELDS Workstation;
|
||||
} NTLM_NEGOTIATE_MESSAGE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NTLM_MESSAGE_HEADER header;
|
||||
UINT32 NegotiateFlags;
|
||||
BYTE ServerChallenge[8];
|
||||
BYTE Reserved[8];
|
||||
NTLM_VERSION_INFO Version;
|
||||
NTLM_MESSAGE_FIELDS TargetName;
|
||||
NTLM_MESSAGE_FIELDS TargetInfo;
|
||||
} NTLM_CHALLENGE_MESSAGE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NTLM_MESSAGE_HEADER header;
|
||||
UINT32 NegotiateFlags;
|
||||
NTLM_VERSION_INFO Version;
|
||||
NTLM_MESSAGE_FIELDS DomainName;
|
||||
NTLM_MESSAGE_FIELDS UserName;
|
||||
NTLM_MESSAGE_FIELDS Workstation;
|
||||
NTLM_MESSAGE_FIELDS LmChallengeResponse;
|
||||
NTLM_MESSAGE_FIELDS NtChallengeResponse;
|
||||
NTLM_MESSAGE_FIELDS EncryptedRandomSessionKey;
|
||||
BYTE MessageIntegrityCheck[16];
|
||||
} NTLM_AUTHENTICATE_MESSAGE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BOOL server;
|
||||
BOOL NTLMv2;
|
||||
BOOL UseMIC;
|
||||
NTLM_STATE state;
|
||||
int SendSeqNum;
|
||||
int RecvSeqNum;
|
||||
char* SamFile;
|
||||
BYTE NtlmHash[16];
|
||||
BYTE NtlmV2Hash[16];
|
||||
BYTE MachineID[32];
|
||||
BOOL SendVersionInfo;
|
||||
BOOL confidentiality;
|
||||
WINPR_RC4_CTX* SendRc4Seal;
|
||||
WINPR_RC4_CTX* RecvRc4Seal;
|
||||
BYTE* SendSigningKey;
|
||||
BYTE* RecvSigningKey;
|
||||
BYTE* SendSealingKey;
|
||||
BYTE* RecvSealingKey;
|
||||
UINT32 NegotiateFlags;
|
||||
BOOL UseSamFileDatabase;
|
||||
int LmCompatibilityLevel;
|
||||
int SuppressExtendedProtection;
|
||||
BOOL SendWorkstationName;
|
||||
UNICODE_STRING Workstation;
|
||||
UNICODE_STRING ServicePrincipalName;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
BYTE* ChannelBindingToken;
|
||||
BYTE ChannelBindingsHash[16];
|
||||
SecPkgContext_Bindings Bindings;
|
||||
BOOL SendSingleHostData;
|
||||
BOOL NegotiateKeyExchange;
|
||||
NTLM_SINGLE_HOST_DATA SingleHostData;
|
||||
NTLM_NEGOTIATE_MESSAGE NEGOTIATE_MESSAGE;
|
||||
NTLM_CHALLENGE_MESSAGE CHALLENGE_MESSAGE;
|
||||
NTLM_AUTHENTICATE_MESSAGE AUTHENTICATE_MESSAGE;
|
||||
size_t MessageIntegrityCheckOffset;
|
||||
SecBuffer NegotiateMessage;
|
||||
SecBuffer ChallengeMessage;
|
||||
SecBuffer AuthenticateMessage;
|
||||
SecBuffer ChallengeTargetInfo;
|
||||
SecBuffer AuthenticateTargetInfo;
|
||||
SecBuffer TargetName;
|
||||
SecBuffer NtChallengeResponse;
|
||||
SecBuffer LmChallengeResponse;
|
||||
NTLMv2_RESPONSE NTLMv2Response;
|
||||
BYTE NtProofString[16];
|
||||
BYTE Timestamp[8];
|
||||
BYTE ChallengeTimestamp[8];
|
||||
BYTE ServerChallenge[8];
|
||||
BYTE ClientChallenge[8];
|
||||
BYTE SessionBaseKey[16];
|
||||
BYTE KeyExchangeKey[16];
|
||||
BYTE RandomSessionKey[16];
|
||||
BYTE ExportedSessionKey[16];
|
||||
BYTE EncryptedRandomSessionKey[16];
|
||||
BYTE ClientSigningKey[16];
|
||||
BYTE ClientSealingKey[16];
|
||||
BYTE ServerSigningKey[16];
|
||||
BYTE ServerSealingKey[16];
|
||||
psSspiNtlmHashCallback HashCallback;
|
||||
void* HashCallbackArg;
|
||||
} NTLM_CONTEXT;
|
||||
|
||||
char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags);
|
||||
const char* ntlm_message_type_string(UINT32 messageType);
|
||||
|
||||
const char* ntlm_state_string(NTLM_STATE state);
|
||||
void ntlm_change_state(NTLM_CONTEXT* ntlm, NTLM_STATE state);
|
||||
NTLM_STATE ntlm_get_state(NTLM_CONTEXT* ntlm);
|
||||
BOOL ntlm_reset_cipher_state(PSecHandle phContext);
|
||||
|
||||
SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof);
|
||||
SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue);
|
||||
|
||||
#ifdef WITH_DEBUG_NLA
|
||||
#define WITH_DEBUG_NTLM
|
||||
#endif
|
||||
|
||||
BOOL NTLM_init(void);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_PRIVATE_H */
|
||||
808
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c
vendored
Normal file
808
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c
vendored
Normal file
@@ -0,0 +1,808 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (AV_PAIRs)
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include "ntlm.h"
|
||||
#include "../sspi.h"
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/crypto.h>
|
||||
|
||||
#include "ntlm_compute.h"
|
||||
|
||||
#include "ntlm_av_pairs.h"
|
||||
|
||||
#if defined(WITH_DEBUG_NTLM)
|
||||
#include "../../log.h"
|
||||
#define TAG WINPR_TAG("sspi.NTLM")
|
||||
#endif
|
||||
|
||||
static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset);
|
||||
|
||||
static BOOL ntlm_av_pair_check_data(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair, size_t size)
|
||||
{
|
||||
size_t offset = 0;
|
||||
if (!pAvPair || cbAvPair < sizeof(NTLM_AV_PAIR) + size)
|
||||
return FALSE;
|
||||
if (!ntlm_av_pair_get_next_offset(pAvPair, cbAvPair, &offset))
|
||||
return FALSE;
|
||||
return cbAvPair >= offset;
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
static const char* get_av_pair_string(UINT16 pair)
|
||||
{
|
||||
switch (pair)
|
||||
{
|
||||
case MsvAvEOL:
|
||||
return "MsvAvEOL";
|
||||
case MsvAvNbComputerName:
|
||||
return "MsvAvNbComputerName";
|
||||
case MsvAvNbDomainName:
|
||||
return "MsvAvNbDomainName";
|
||||
case MsvAvDnsComputerName:
|
||||
return "MsvAvDnsComputerName";
|
||||
case MsvAvDnsDomainName:
|
||||
return "MsvAvDnsDomainName";
|
||||
case MsvAvDnsTreeName:
|
||||
return "MsvAvDnsTreeName";
|
||||
case MsvAvFlags:
|
||||
return "MsvAvFlags";
|
||||
case MsvAvTimestamp:
|
||||
return "MsvAvTimestamp";
|
||||
case MsvAvSingleHost:
|
||||
return "MsvAvSingleHost";
|
||||
case MsvAvTargetName:
|
||||
return "MsvAvTargetName";
|
||||
case MsvAvChannelBindings:
|
||||
return "MsvAvChannelBindings";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair);
|
||||
static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvPairList);
|
||||
|
||||
static inline void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id)
|
||||
{
|
||||
WINPR_ASSERT(pAvPair);
|
||||
winpr_Data_Write_UINT16(&pAvPair->AvId, id);
|
||||
}
|
||||
|
||||
static inline void ntlm_av_pair_set_len(NTLM_AV_PAIR* pAvPair, UINT16 len)
|
||||
{
|
||||
WINPR_ASSERT(pAvPair);
|
||||
winpr_Data_Write_UINT16(&pAvPair->AvLen, len);
|
||||
}
|
||||
|
||||
static BOOL ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
|
||||
{
|
||||
NTLM_AV_PAIR* pAvPair = pAvPairList;
|
||||
|
||||
if (!pAvPair || (cbAvPairList < sizeof(NTLM_AV_PAIR)))
|
||||
return FALSE;
|
||||
|
||||
ntlm_av_pair_set_id(pAvPair, MsvAvEOL);
|
||||
ntlm_av_pair_set_len(pAvPair, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline BOOL ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair, size_t size, UINT16* pair)
|
||||
{
|
||||
if (!pAvPair || !pair)
|
||||
return FALSE;
|
||||
|
||||
if (size < sizeof(NTLM_AV_PAIR))
|
||||
return FALSE;
|
||||
|
||||
const UINT16 AvId = winpr_Data_Get_UINT16(&pAvPair->AvId);
|
||||
|
||||
*pair = AvId;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
|
||||
{
|
||||
size_t cbAvPair = 0;
|
||||
NTLM_AV_PAIR* pAvPair = nullptr;
|
||||
|
||||
pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
|
||||
if (!pAvPair)
|
||||
return 0;
|
||||
|
||||
if (pAvPair < pAvPairList)
|
||||
return 0;
|
||||
|
||||
const size_t size = WINPR_ASSERTING_INT_CAST(size_t, ((PBYTE)pAvPair - (PBYTE)pAvPairList)) +
|
||||
sizeof(NTLM_AV_PAIR);
|
||||
WINPR_ASSERT(size <= UINT32_MAX);
|
||||
WINPR_ASSERT(size >= 0);
|
||||
return (ULONG)size;
|
||||
}
|
||||
|
||||
static inline BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pAvLen)
|
||||
{
|
||||
if (!pAvPair)
|
||||
return FALSE;
|
||||
|
||||
if (size < sizeof(NTLM_AV_PAIR))
|
||||
return FALSE;
|
||||
|
||||
const UINT16 AvLen = winpr_Data_Get_UINT16(&pAvPair->AvLen);
|
||||
|
||||
*pAvLen = AvLen;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
|
||||
{
|
||||
UINT16 pair = 0;
|
||||
size_t cbAvPair = cbAvPairList;
|
||||
NTLM_AV_PAIR* pAvPair = pAvPairList;
|
||||
|
||||
if (!ntlm_av_pair_check(pAvPair, cbAvPair))
|
||||
return;
|
||||
|
||||
WLog_VRB(TAG, "AV_PAIRs =");
|
||||
|
||||
while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL))
|
||||
{
|
||||
size_t cbLen = 0;
|
||||
ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen);
|
||||
|
||||
WLog_VRB(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, ntlm_av_pair_get_value_pointer(pAvPair), cbLen);
|
||||
|
||||
pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t ntlm_av_pair_list_size(size_t AvPairsCount, size_t AvPairsValueLength)
|
||||
{
|
||||
/* size of headers + value lengths + terminating MsvAvEOL AV_PAIR */
|
||||
return ((AvPairsCount + 1) * 4ULL) + AvPairsValueLength;
|
||||
}
|
||||
|
||||
PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
|
||||
{
|
||||
WINPR_ASSERT(pAvPair);
|
||||
return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
|
||||
}
|
||||
|
||||
static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset)
|
||||
{
|
||||
size_t avLen = 0;
|
||||
if (!pOffset)
|
||||
return FALSE;
|
||||
|
||||
if (!ntlm_av_pair_get_len(pAvPair, size, &avLen))
|
||||
return FALSE;
|
||||
*pOffset = avLen + sizeof(NTLM_AV_PAIR);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
|
||||
{
|
||||
return ntlm_av_pair_check_data(pAvPair, cbAvPair, 0);
|
||||
}
|
||||
|
||||
static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPair, size_t* pcbAvPair)
|
||||
{
|
||||
size_t offset = 0;
|
||||
|
||||
if (!pcbAvPair)
|
||||
return nullptr;
|
||||
if (!ntlm_av_pair_check(pAvPair, *pcbAvPair))
|
||||
return nullptr;
|
||||
|
||||
if (!ntlm_av_pair_get_next_offset(pAvPair, *pcbAvPair, &offset))
|
||||
return nullptr;
|
||||
|
||||
*pcbAvPair -= offset;
|
||||
return (NTLM_AV_PAIR*)((PBYTE)pAvPair + offset);
|
||||
}
|
||||
|
||||
NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
|
||||
size_t* pcbAvPairListRemaining)
|
||||
{
|
||||
UINT16 id = 0;
|
||||
size_t cbAvPair = cbAvPairList;
|
||||
NTLM_AV_PAIR* pAvPair = pAvPairList;
|
||||
|
||||
if (!ntlm_av_pair_check(pAvPair, cbAvPair))
|
||||
pAvPair = nullptr;
|
||||
|
||||
while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &id))
|
||||
{
|
||||
if (id == AvId)
|
||||
break;
|
||||
if (id == MsvAvEOL)
|
||||
{
|
||||
pAvPair = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
|
||||
}
|
||||
|
||||
if (!pAvPair)
|
||||
cbAvPair = 0;
|
||||
if (pcbAvPairListRemaining)
|
||||
*pcbAvPairListRemaining = cbAvPair;
|
||||
|
||||
return pAvPair;
|
||||
}
|
||||
|
||||
static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
|
||||
PBYTE Value, UINT16 AvLen)
|
||||
{
|
||||
size_t cbAvPair = 0;
|
||||
NTLM_AV_PAIR* pAvPair = nullptr;
|
||||
|
||||
pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
|
||||
|
||||
/* size of header + value length + terminating MsvAvEOL AV_PAIR */
|
||||
if (!pAvPair || cbAvPair < 2 * sizeof(NTLM_AV_PAIR) + AvLen)
|
||||
return FALSE;
|
||||
|
||||
ntlm_av_pair_set_id(pAvPair, (UINT16)AvId);
|
||||
ntlm_av_pair_set_len(pAvPair, AvLen);
|
||||
if (AvLen)
|
||||
{
|
||||
WINPR_ASSERT(Value != nullptr);
|
||||
CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen);
|
||||
}
|
||||
|
||||
pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
|
||||
return ntlm_av_pair_list_init(pAvPair, cbAvPair);
|
||||
}
|
||||
|
||||
static BOOL ntlm_av_pair_valid(UINT16 pair)
|
||||
{
|
||||
switch (pair)
|
||||
{
|
||||
case MsvAvEOL:
|
||||
case MsvAvNbComputerName:
|
||||
case MsvAvNbDomainName:
|
||||
case MsvAvDnsComputerName:
|
||||
case MsvAvDnsDomainName:
|
||||
case MsvAvDnsTreeName:
|
||||
case MsvAvFlags:
|
||||
case MsvAvTimestamp:
|
||||
case MsvAvSingleHost:
|
||||
case MsvAvTargetName:
|
||||
case MsvAvChannelBindings:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList,
|
||||
NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
|
||||
{
|
||||
UINT16 pair = 0;
|
||||
size_t avLen = 0;
|
||||
|
||||
if (!ntlm_av_pair_check(pAvPair, cbAvPair))
|
||||
return FALSE;
|
||||
|
||||
if (!ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair))
|
||||
return FALSE;
|
||||
|
||||
if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen))
|
||||
return FALSE;
|
||||
|
||||
if (!ntlm_av_pair_valid(pair))
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(avLen <= UINT16_MAX);
|
||||
return ntlm_av_pair_add(pAvPairList, cbAvPairList, WINPR_ASSERTING_INT_CAST(NTLM_AV_ID, pair),
|
||||
ntlm_av_pair_get_value_pointer(pAvPair), (UINT16)avLen);
|
||||
}
|
||||
|
||||
static char* get_name(COMPUTER_NAME_FORMAT type)
|
||||
{
|
||||
DWORD nSize = 0;
|
||||
|
||||
if (GetComputerNameExA(type, nullptr, &nSize))
|
||||
return nullptr;
|
||||
|
||||
if (GetLastError() != ERROR_MORE_DATA)
|
||||
return nullptr;
|
||||
|
||||
char* computerName = calloc(1, nSize);
|
||||
|
||||
if (!computerName)
|
||||
return nullptr;
|
||||
|
||||
if (!GetComputerNameExA(type, computerName, &nSize))
|
||||
{
|
||||
free(computerName);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return computerName;
|
||||
}
|
||||
|
||||
static int ntlm_get_target_computer_name(PUNICODE_STRING pName,
|
||||
WINPR_ATTR_UNUSED COMPUTER_NAME_FORMAT type)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
WINPR_ASSERT(pName);
|
||||
|
||||
char* name = get_name(ComputerNameNetBIOS);
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
CharUpperA(name);
|
||||
|
||||
size_t len = 0;
|
||||
pName->Buffer = ConvertUtf8ToWCharAlloc(name, &len);
|
||||
free(name);
|
||||
|
||||
if (!pName->Buffer || (len == 0) || (len > UINT16_MAX / sizeof(WCHAR)))
|
||||
{
|
||||
free(pName->Buffer);
|
||||
pName->Buffer = nullptr;
|
||||
return status;
|
||||
}
|
||||
|
||||
pName->Length = (USHORT)((len) * sizeof(WCHAR));
|
||||
pName->MaximumLength = pName->Length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ntlm_free_unicode_string(PUNICODE_STRING string)
|
||||
{
|
||||
if (string)
|
||||
{
|
||||
if (string->Length > 0)
|
||||
{
|
||||
free(string->Buffer);
|
||||
string->Buffer = nullptr;
|
||||
string->Length = 0;
|
||||
string->MaximumLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* From http://www.ietf.org/proceedings/72/slides/sasl-2.pdf:
|
||||
*
|
||||
* tls-server-end-point:
|
||||
*
|
||||
* The hash of the TLS server's end entity certificate as it appears, octet for octet,
|
||||
* in the server's Certificate message (note that the Certificate message contains a
|
||||
* certificate_list, the first element of which is the server's end entity certificate.)
|
||||
* The hash function to be selected is as follows: if the certificate's signature hash
|
||||
* algorithm is either MD5 or SHA-1, then use SHA-256, otherwise use the certificate's
|
||||
* signature hash algorithm.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Channel Bindings sample usage:
|
||||
* https://raw.github.com/mozilla/mozilla-central/master/extensions/auth/nsAuthSSPI.cpp
|
||||
*/
|
||||
|
||||
/*
|
||||
typedef struct gss_channel_bindings_struct {
|
||||
OM_uint32 initiator_addrtype;
|
||||
gss_buffer_desc initiator_address;
|
||||
OM_uint32 acceptor_addrtype;
|
||||
gss_buffer_desc acceptor_address;
|
||||
gss_buffer_desc application_data;
|
||||
} *gss_channel_bindings_t;
|
||||
*/
|
||||
|
||||
static BOOL ntlm_md5_update_uint32_be(WINPR_DIGEST_CTX* md5, UINT32 num)
|
||||
{
|
||||
BYTE be32[4];
|
||||
be32[0] = (num >> 0) & 0xFF;
|
||||
be32[1] = (num >> 8) & 0xFF;
|
||||
be32[2] = (num >> 16) & 0xFF;
|
||||
be32[3] = (num >> 24) & 0xFF;
|
||||
return winpr_Digest_Update(md5, be32, 4);
|
||||
}
|
||||
|
||||
static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_DIGEST_CTX* md5 = nullptr;
|
||||
BYTE* ChannelBindingToken = nullptr;
|
||||
UINT32 ChannelBindingTokenLength = 0;
|
||||
SEC_CHANNEL_BINDINGS* ChannelBindings = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH);
|
||||
ChannelBindings = context->Bindings.Bindings;
|
||||
|
||||
if (!ChannelBindings)
|
||||
return;
|
||||
|
||||
if (!(md5 = winpr_Digest_New()))
|
||||
return;
|
||||
|
||||
if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
|
||||
goto out;
|
||||
|
||||
ChannelBindingTokenLength = context->Bindings.BindingsLength - sizeof(SEC_CHANNEL_BINDINGS);
|
||||
ChannelBindingToken = &((BYTE*)ChannelBindings)[ChannelBindings->dwApplicationDataOffset];
|
||||
|
||||
if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwInitiatorAddrType))
|
||||
goto out;
|
||||
|
||||
if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbInitiatorLength))
|
||||
goto out;
|
||||
|
||||
if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwAcceptorAddrType))
|
||||
goto out;
|
||||
|
||||
if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbAcceptorLength))
|
||||
goto out;
|
||||
|
||||
if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbApplicationDataLength))
|
||||
goto out;
|
||||
|
||||
if (!winpr_Digest_Update(md5, (void*)ChannelBindingToken, ChannelBindingTokenLength))
|
||||
goto out;
|
||||
|
||||
if (!winpr_Digest_Final(md5, context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
winpr_Digest_Free(md5);
|
||||
}
|
||||
|
||||
static void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
/**
|
||||
* The Single_Host_Data structure allows a client to send machine-specific information
|
||||
* within an authentication exchange to services on the same machine. The client can
|
||||
* produce additional information to be processed in an implementation-specific way when
|
||||
* the client and server are on the same host. If the server and client platforms are
|
||||
* different or if they are on different hosts, then the information MUST be ignored.
|
||||
* Any fields after the MachineID field MUST be ignored on receipt.
|
||||
*/
|
||||
winpr_Data_Write_UINT32(&context->SingleHostData.Size, 48);
|
||||
winpr_Data_Write_UINT32(&context->SingleHostData.Z4, 0);
|
||||
winpr_Data_Write_UINT32(&context->SingleHostData.DataPresent, 1);
|
||||
winpr_Data_Write_UINT32(&context->SingleHostData.CustomData, SECURITY_MANDATORY_MEDIUM_RID);
|
||||
FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
|
||||
}
|
||||
|
||||
BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
ULONG AvPairsCount = 0;
|
||||
ULONG AvPairsLength = 0;
|
||||
NTLM_AV_PAIR* pAvPairList = nullptr;
|
||||
size_t cbAvPairList = 0;
|
||||
UNICODE_STRING NbDomainName = WINPR_C_ARRAY_INIT;
|
||||
UNICODE_STRING NbComputerName = WINPR_C_ARRAY_INIT;
|
||||
UNICODE_STRING DnsDomainName = WINPR_C_ARRAY_INIT;
|
||||
UNICODE_STRING DnsComputerName = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
|
||||
goto fail;
|
||||
|
||||
NbComputerName.Buffer = nullptr;
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0)
|
||||
goto fail;
|
||||
|
||||
DnsDomainName.Buffer = nullptr;
|
||||
|
||||
if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0)
|
||||
goto fail;
|
||||
|
||||
DnsComputerName.Buffer = nullptr;
|
||||
|
||||
if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0)
|
||||
goto fail;
|
||||
|
||||
AvPairsCount = 5;
|
||||
AvPairsLength = NbDomainName.Length + NbComputerName.Length + DnsDomainName.Length +
|
||||
DnsComputerName.Length + 8;
|
||||
{
|
||||
const size_t length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
|
||||
if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, length)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pAvPairList = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
|
||||
cbAvPairList = context->ChallengeTargetInfo.cbBuffer;
|
||||
|
||||
if (!ntlm_av_pair_list_init(pAvPairList, cbAvPairList))
|
||||
goto fail;
|
||||
|
||||
if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbDomainName, (PBYTE)NbDomainName.Buffer,
|
||||
NbDomainName.Length))
|
||||
goto fail;
|
||||
|
||||
if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbComputerName,
|
||||
(PBYTE)NbComputerName.Buffer, NbComputerName.Length))
|
||||
goto fail;
|
||||
|
||||
if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsDomainName,
|
||||
(PBYTE)DnsDomainName.Buffer, DnsDomainName.Length))
|
||||
goto fail;
|
||||
|
||||
if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsComputerName,
|
||||
(PBYTE)DnsComputerName.Buffer, DnsComputerName.Length))
|
||||
goto fail;
|
||||
|
||||
if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvTimestamp, context->Timestamp,
|
||||
sizeof(context->Timestamp)))
|
||||
goto fail;
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
ntlm_free_unicode_string(&NbDomainName);
|
||||
ntlm_free_unicode_string(&NbComputerName);
|
||||
ntlm_free_unicode_string(&DnsDomainName);
|
||||
ntlm_free_unicode_string(&DnsComputerName);
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
ULONG AvPairsCount = 0;
|
||||
size_t AvPairsValueLength = 0;
|
||||
NTLM_AV_PAIR* AvTimestamp = nullptr;
|
||||
NTLM_AV_PAIR* AvNbDomainName = nullptr;
|
||||
NTLM_AV_PAIR* AvNbComputerName = nullptr;
|
||||
NTLM_AV_PAIR* AvDnsDomainName = nullptr;
|
||||
NTLM_AV_PAIR* AvDnsComputerName = nullptr;
|
||||
NTLM_AV_PAIR* AvDnsTreeName = nullptr;
|
||||
NTLM_AV_PAIR* ChallengeTargetInfo = nullptr;
|
||||
NTLM_AV_PAIR* AuthenticateTargetInfo = nullptr;
|
||||
size_t cbAvTimestamp = 0;
|
||||
size_t cbAvNbDomainName = 0;
|
||||
size_t cbAvNbComputerName = 0;
|
||||
size_t cbAvDnsDomainName = 0;
|
||||
size_t cbAvDnsComputerName = 0;
|
||||
size_t cbAvDnsTreeName = 0;
|
||||
size_t cbChallengeTargetInfo = 0;
|
||||
size_t cbAuthenticateTargetInfo = 0;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
AvPairsCount = 1;
|
||||
ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
|
||||
cbChallengeTargetInfo = context->ChallengeTargetInfo.cbBuffer;
|
||||
AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvNbDomainName,
|
||||
&cbAvNbDomainName);
|
||||
AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
|
||||
MsvAvNbComputerName, &cbAvNbComputerName);
|
||||
AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
|
||||
MsvAvDnsDomainName, &cbAvDnsDomainName);
|
||||
AvDnsComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
|
||||
MsvAvDnsComputerName, &cbAvDnsComputerName);
|
||||
AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvDnsTreeName,
|
||||
&cbAvDnsTreeName);
|
||||
AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvTimestamp,
|
||||
&cbAvTimestamp);
|
||||
|
||||
if (AvNbDomainName)
|
||||
{
|
||||
size_t avLen = 0;
|
||||
if (!ntlm_av_pair_get_len(AvNbDomainName, cbAvNbDomainName, &avLen))
|
||||
goto fail;
|
||||
AvPairsCount++; /* MsvAvNbDomainName */
|
||||
AvPairsValueLength += avLen;
|
||||
}
|
||||
|
||||
if (AvNbComputerName)
|
||||
{
|
||||
size_t avLen = 0;
|
||||
if (!ntlm_av_pair_get_len(AvNbComputerName, cbAvNbComputerName, &avLen))
|
||||
goto fail;
|
||||
AvPairsCount++; /* MsvAvNbComputerName */
|
||||
AvPairsValueLength += avLen;
|
||||
}
|
||||
|
||||
if (AvDnsDomainName)
|
||||
{
|
||||
size_t avLen = 0;
|
||||
if (!ntlm_av_pair_get_len(AvDnsDomainName, cbAvDnsDomainName, &avLen))
|
||||
goto fail;
|
||||
AvPairsCount++; /* MsvAvDnsDomainName */
|
||||
AvPairsValueLength += avLen;
|
||||
}
|
||||
|
||||
if (AvDnsComputerName)
|
||||
{
|
||||
size_t avLen = 0;
|
||||
if (!ntlm_av_pair_get_len(AvDnsComputerName, cbAvDnsComputerName, &avLen))
|
||||
goto fail;
|
||||
AvPairsCount++; /* MsvAvDnsComputerName */
|
||||
AvPairsValueLength += avLen;
|
||||
}
|
||||
|
||||
if (AvDnsTreeName)
|
||||
{
|
||||
size_t avLen = 0;
|
||||
if (!ntlm_av_pair_get_len(AvDnsTreeName, cbAvDnsTreeName, &avLen))
|
||||
goto fail;
|
||||
AvPairsCount++; /* MsvAvDnsTreeName */
|
||||
AvPairsValueLength += avLen;
|
||||
}
|
||||
|
||||
AvPairsCount++; /* MsvAvTimestamp */
|
||||
AvPairsValueLength += 8;
|
||||
|
||||
if (context->UseMIC)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvFlags */
|
||||
AvPairsValueLength += 4;
|
||||
}
|
||||
|
||||
if (context->SendSingleHostData)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvSingleHost */
|
||||
ntlm_compute_single_host_data(context);
|
||||
AvPairsValueLength += context->SingleHostData.Size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended Protection for Authentication:
|
||||
* http://blogs.technet.com/b/srd/archive/2009/12/08/extended-protection-for-authentication.aspx
|
||||
*/
|
||||
|
||||
if (!context->SuppressExtendedProtection)
|
||||
{
|
||||
/**
|
||||
* SEC_CHANNEL_BINDINGS structure
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd919963/
|
||||
*/
|
||||
AvPairsCount++; /* MsvAvChannelBindings */
|
||||
AvPairsValueLength += 16;
|
||||
ntlm_compute_channel_bindings(context);
|
||||
|
||||
if (context->ServicePrincipalName.Length > 0)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvTargetName */
|
||||
AvPairsValueLength += context->ServicePrincipalName.Length;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
size_t size = ntlm_av_pair_list_size(AvPairsCount, AvPairsValueLength);
|
||||
if (context->NTLMv2)
|
||||
size += 8; /* unknown 8-byte padding */
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->AuthenticateTargetInfo,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, size)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
AuthenticateTargetInfo = (NTLM_AV_PAIR*)context->AuthenticateTargetInfo.pvBuffer;
|
||||
cbAuthenticateTargetInfo = context->AuthenticateTargetInfo.cbBuffer;
|
||||
|
||||
if (!ntlm_av_pair_list_init(AuthenticateTargetInfo, cbAuthenticateTargetInfo))
|
||||
goto fail;
|
||||
|
||||
if (AvNbDomainName)
|
||||
{
|
||||
if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvNbDomainName,
|
||||
cbAvNbDomainName))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (AvNbComputerName)
|
||||
{
|
||||
if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
|
||||
AvNbComputerName, cbAvNbComputerName))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (AvDnsDomainName)
|
||||
{
|
||||
if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
|
||||
AvDnsDomainName, cbAvDnsDomainName))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (AvDnsComputerName)
|
||||
{
|
||||
if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
|
||||
AvDnsComputerName, cbAvDnsComputerName))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (AvDnsTreeName)
|
||||
{
|
||||
if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvDnsTreeName,
|
||||
cbAvDnsTreeName))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (AvTimestamp)
|
||||
{
|
||||
if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvTimestamp,
|
||||
cbAvTimestamp))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (context->UseMIC)
|
||||
{
|
||||
UINT32 flags = 0;
|
||||
winpr_Data_Write_UINT32(&flags, MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK);
|
||||
|
||||
if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvFlags,
|
||||
(PBYTE)&flags, 4))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (context->SendSingleHostData)
|
||||
{
|
||||
WINPR_ASSERT(context->SingleHostData.Size <= UINT16_MAX);
|
||||
if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost,
|
||||
(PBYTE)&context->SingleHostData,
|
||||
(UINT16)context->SingleHostData.Size))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!context->SuppressExtendedProtection)
|
||||
{
|
||||
if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
|
||||
MsvAvChannelBindings, context->ChannelBindingsHash, 16))
|
||||
goto fail;
|
||||
|
||||
if (context->ServicePrincipalName.Length > 0)
|
||||
{
|
||||
if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvTargetName,
|
||||
(PBYTE)context->ServicePrincipalName.Buffer,
|
||||
context->ServicePrincipalName.Length))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->NTLMv2)
|
||||
{
|
||||
NTLM_AV_PAIR* AvEOL = nullptr;
|
||||
AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL, nullptr);
|
||||
|
||||
if (!AvEOL)
|
||||
goto fail;
|
||||
|
||||
ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
fail:
|
||||
sspi_SecBufferFree(&context->AuthenticateTargetInfo);
|
||||
return FALSE;
|
||||
}
|
||||
42
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h
vendored
Normal file
42
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (AV_PAIRs)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_NTLM_AV_PAIRS_H
|
||||
#define WINPR_SSPI_NTLM_AV_PAIRS_H
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include "ntlm.h"
|
||||
|
||||
#include <winpr/stream.h>
|
||||
|
||||
ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList);
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList);
|
||||
#endif
|
||||
|
||||
PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair);
|
||||
NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
|
||||
size_t* pcbAvPairListRemaining);
|
||||
|
||||
BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_AV_PAIRS_H */
|
||||
960
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_compute.c
vendored
Normal file
960
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_compute.c
vendored
Normal file
@@ -0,0 +1,960 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Compute)
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include "ntlm.h"
|
||||
#include "../sspi.h"
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sam.h>
|
||||
#include <winpr/ntlm.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/crypto.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
#include "ntlm_compute.h"
|
||||
|
||||
#include "../../log.h"
|
||||
#define TAG WINPR_TAG("sspi.NTLM")
|
||||
|
||||
#define NTLM_CheckAndLogRequiredCapacity(tag, s, nmemb, what) \
|
||||
Stream_CheckAndLogRequiredCapacityEx(tag, WLOG_WARN, s, nmemb, 1, "%s(%s:%" PRIuz ") " what, \
|
||||
__func__, __FILE__, (size_t)__LINE__)
|
||||
|
||||
static char NTLM_CLIENT_SIGN_MAGIC[] = "session key to client-to-server signing key magic constant";
|
||||
static char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client signing key magic constant";
|
||||
static char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server sealing key magic constant";
|
||||
static char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant";
|
||||
|
||||
static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
/**
|
||||
* Populate VERSION structure msdn{cc236654}
|
||||
* @param versionInfo A pointer to the version struct
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
|
||||
BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
#if defined(WITH_WINPR_DEPRECATED)
|
||||
OSVERSIONINFOA osVersionInfo = WINPR_C_ARRAY_INIT;
|
||||
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
||||
if (!GetVersionExA(&osVersionInfo))
|
||||
return FALSE;
|
||||
versionInfo->ProductMajorVersion = (UINT8)osVersionInfo.dwMajorVersion;
|
||||
versionInfo->ProductMinorVersion = (UINT8)osVersionInfo.dwMinorVersion;
|
||||
versionInfo->ProductBuild = (UINT16)osVersionInfo.dwBuildNumber;
|
||||
#else
|
||||
/* Always return fixed version number.
|
||||
*
|
||||
* ProductVersion is fixed since windows 10 to Major 10, Minor 0
|
||||
* ProductBuild taken from https://en.wikipedia.org/wiki/Windows_11_version_history
|
||||
* with most recent (pre) release build number
|
||||
*/
|
||||
versionInfo->ProductMajorVersion = 10;
|
||||
versionInfo->ProductMinorVersion = 0;
|
||||
versionInfo->ProductBuild = 22631;
|
||||
#endif
|
||||
ZeroMemory(versionInfo->Reserved, sizeof(versionInfo->Reserved));
|
||||
versionInfo->NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read VERSION structure. msdn{cc236654}
|
||||
* @param s A pointer to a stream to read
|
||||
* @param versionInfo A pointer to the struct to read data to
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
|
||||
BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
|
||||
Stream_Read_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
|
||||
Stream_Read(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
|
||||
Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write VERSION structure. msdn{cc236654}
|
||||
* @param s A pointer to the stream to write to
|
||||
* @param versionInfo A pointer to the buffer to read the data from
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
|
||||
BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredCapacityEx(
|
||||
TAG, WLOG_WARN, s, 5ull + sizeof(versionInfo->Reserved), 1ull,
|
||||
"%s(%s:%" PRIuz ") NTLM_VERSION_INFO", __func__, __FILE__, (size_t)__LINE__))
|
||||
return FALSE;
|
||||
|
||||
Stream_Write_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
|
||||
Stream_Write_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
|
||||
Stream_Write_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
|
||||
Stream_Write(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
|
||||
Stream_Write_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print VERSION structure. msdn{cc236654}
|
||||
* @param versionInfo A pointer to the struct containing the data to print
|
||||
*/
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
WLog_VRB(TAG, "VERSION ={");
|
||||
WLog_VRB(TAG, "\tProductMajorVersion: %" PRIu8 "", versionInfo->ProductMajorVersion);
|
||||
WLog_VRB(TAG, "\tProductMinorVersion: %" PRIu8 "", versionInfo->ProductMinorVersion);
|
||||
WLog_VRB(TAG, "\tProductBuild: %" PRIu16 "", versionInfo->ProductBuild);
|
||||
WLog_VRB(TAG, "\tReserved: 0x%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "", versionInfo->Reserved[0],
|
||||
versionInfo->Reserved[1], versionInfo->Reserved[2]);
|
||||
WLog_VRB(TAG, "\tNTLMRevisionCurrent: 0x%02" PRIX8 "", versionInfo->NTLMRevisionCurrent);
|
||||
}
|
||||
#endif
|
||||
|
||||
static BOOL ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
size_t size = 0;
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(challenge);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 28))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, challenge->RespType);
|
||||
Stream_Read_UINT8(s, challenge->HiRespType);
|
||||
Stream_Read_UINT16(s, challenge->Reserved1);
|
||||
Stream_Read_UINT32(s, challenge->Reserved2);
|
||||
Stream_Read(s, challenge->Timestamp, 8);
|
||||
Stream_Read(s, challenge->ClientChallenge, 8);
|
||||
Stream_Read_UINT32(s, challenge->Reserved3);
|
||||
size = Stream_Length(s) - Stream_GetPosition(s);
|
||||
|
||||
if (size > UINT32_MAX)
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::cbAvPairs too large, got %" PRIuz "bytes", size);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
challenge->cbAvPairs = (UINT32)size;
|
||||
challenge->AvPairs = (NTLM_AV_PAIR*)malloc(challenge->cbAvPairs);
|
||||
|
||||
if (!challenge->AvPairs)
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::AvPairs failed to allocate %" PRIu32 "bytes",
|
||||
challenge->cbAvPairs);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read(s, challenge->AvPairs, size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL ntlm_write_ntlm_v2_client_challenge(wStream* s,
|
||||
const NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
ULONG length = 0;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(challenge);
|
||||
|
||||
if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, 28, "NTLMv2_CLIENT_CHALLENGE"))
|
||||
return FALSE;
|
||||
|
||||
Stream_Write_UINT8(s, challenge->RespType);
|
||||
Stream_Write_UINT8(s, challenge->HiRespType);
|
||||
Stream_Write_UINT16(s, challenge->Reserved1);
|
||||
Stream_Write_UINT32(s, challenge->Reserved2);
|
||||
Stream_Write(s, challenge->Timestamp, 8);
|
||||
Stream_Write(s, challenge->ClientChallenge, 8);
|
||||
Stream_Write_UINT32(s, challenge->Reserved3);
|
||||
length = ntlm_av_pair_list_length(challenge->AvPairs, challenge->cbAvPairs);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
|
||||
return FALSE;
|
||||
|
||||
Stream_Write(s, challenge->AvPairs, length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(response);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 16))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read(s, response->Response, 16);
|
||||
return ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(response);
|
||||
|
||||
if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, 16ull, "NTLMv2_RESPONSE"))
|
||||
return FALSE;
|
||||
|
||||
Stream_Write(s, response->Response, 16);
|
||||
return ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current time, in tenths of microseconds since midnight of January 1, 1601.
|
||||
* @param[out] timestamp 64-bit little-endian timestamp
|
||||
*/
|
||||
|
||||
static void ntlm_current_time(BYTE* timestamp, WINPR_ATTR_UNUSED size_t size)
|
||||
{
|
||||
FILETIME ft = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(timestamp);
|
||||
WINPR_ASSERT(size >= sizeof(ft));
|
||||
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
CopyMemory(timestamp, &(ft), sizeof(ft));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate timestamp for AUTHENTICATE_MESSAGE.
|
||||
*
|
||||
* @param context A pointer to the NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (memcmp(context->ChallengeTimestamp, NTLM_NULL_BUFFER, 8) != 0)
|
||||
CopyMemory(context->Timestamp, context->ChallengeTimestamp, 8);
|
||||
else
|
||||
ntlm_current_time(context->Timestamp, sizeof(context->Timestamp));
|
||||
}
|
||||
|
||||
static BOOL ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
WINPR_SAM* sam = nullptr;
|
||||
WINPR_SAM_ENTRY* entry = nullptr;
|
||||
SSPI_CREDENTIALS* credentials = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(hash);
|
||||
|
||||
credentials = context->credentials;
|
||||
sam = SamOpen(context->SamFile, TRUE);
|
||||
|
||||
if (!sam)
|
||||
goto fail;
|
||||
|
||||
entry = SamLookupUserW(
|
||||
sam, (LPWSTR)credentials->identity.User, credentials->identity.UserLength * sizeof(WCHAR),
|
||||
(LPWSTR)credentials->identity.Domain, credentials->identity.DomainLength * sizeof(WCHAR));
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
entry = SamLookupUserW(sam, (LPWSTR)credentials->identity.User,
|
||||
credentials->identity.UserLength * sizeof(WCHAR), nullptr, 0);
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
goto fail;
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
WLog_VRB(TAG, "NTLM Hash:");
|
||||
winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16);
|
||||
#endif
|
||||
NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User,
|
||||
credentials->identity.UserLength * sizeof(WCHAR),
|
||||
(LPWSTR)credentials->identity.Domain,
|
||||
credentials->identity.DomainLength * sizeof(WCHAR), hash);
|
||||
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
SamFreeEntry(sam, entry);
|
||||
SamClose(sam);
|
||||
if (!rc)
|
||||
WLog_ERR(TAG, "Error: Could not find user in SAM database");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int hexchar2nibble(WCHAR wc)
|
||||
{
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
union
|
||||
{
|
||||
BYTE b[2];
|
||||
WCHAR w;
|
||||
} cnv;
|
||||
cnv.w = wc;
|
||||
const BYTE b = cnv.b[0];
|
||||
cnv.b[0] = cnv.b[1];
|
||||
cnv.b[1] = b;
|
||||
wc = cnv.w;
|
||||
#endif
|
||||
|
||||
switch (wc)
|
||||
{
|
||||
case L'0':
|
||||
case L'1':
|
||||
case L'2':
|
||||
case L'3':
|
||||
case L'4':
|
||||
case L'5':
|
||||
case L'6':
|
||||
case L'7':
|
||||
case L'8':
|
||||
case L'9':
|
||||
return wc - L'0';
|
||||
case L'a':
|
||||
case L'b':
|
||||
case L'c':
|
||||
case L'd':
|
||||
case L'e':
|
||||
case L'f':
|
||||
return wc - L'a' + 10;
|
||||
case L'A':
|
||||
case L'B':
|
||||
case L'C':
|
||||
case L'D':
|
||||
case L'E':
|
||||
case L'F':
|
||||
return wc - L'A' + 10;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
static int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash, size_t hashlen)
|
||||
{
|
||||
const size_t required_len = 2ull * hashlen;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(hash);
|
||||
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
/* Password contains a password hash of length (PasswordLength -
|
||||
* SSPI_CREDENTIALS_HASH_LENGTH_OFFSET) */
|
||||
const ULONG PasswordHashLength = credentials->identity.PasswordLength -
|
||||
/* Macro [globalScope] */ SSPI_CREDENTIALS_HASH_LENGTH_OFFSET;
|
||||
|
||||
if (PasswordHashLength != required_len)
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"PasswordHash has invalid length %" PRIu32 " must be exactly %" PRIuz " bytes",
|
||||
PasswordHashLength, required_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const WCHAR* PasswordHash = credentials->identity.Password;
|
||||
for (size_t x = 0; x < hashlen; x++)
|
||||
{
|
||||
const int hi = hexchar2nibble(PasswordHash[2 * x]);
|
||||
if (hi < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "PasswordHash has an invalid value at position %" PRIuz, 2 * x);
|
||||
return -1;
|
||||
}
|
||||
const int lo = hexchar2nibble(PasswordHash[2 * x + 1]);
|
||||
if (lo < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "PasswordHash has an invalid value at position %" PRIuz, 2 * x + 1);
|
||||
return -1;
|
||||
}
|
||||
const BYTE val = (BYTE)((hi << 4) | lo);
|
||||
hash[x] = val;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
SSPI_CREDENTIALS* credentials = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(hash);
|
||||
|
||||
credentials = context->credentials;
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
|
||||
if (credentials)
|
||||
{
|
||||
WLog_VRB(TAG, "Password (length = %" PRIu32 ")", credentials->identity.PasswordLength * 2);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Password,
|
||||
credentials->identity.PasswordLength * 2);
|
||||
WLog_VRB(TAG, "Username (length = %" PRIu32 ")", credentials->identity.UserLength * 2);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.User,
|
||||
credentials->identity.UserLength * 2);
|
||||
WLog_VRB(TAG, "Domain (length = %" PRIu32 ")", credentials->identity.DomainLength * 2);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Domain,
|
||||
credentials->identity.DomainLength * 2);
|
||||
}
|
||||
else
|
||||
WLog_VRB(TAG, "Strange, NTLM_CONTEXT is missing valid credentials...");
|
||||
|
||||
WLog_VRB(TAG, "Workstation (length = %" PRIu16 ")", context->Workstation.Length);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)context->Workstation.Buffer, context->Workstation.Length);
|
||||
WLog_VRB(TAG, "NTOWFv2, NTLMv2 Hash");
|
||||
winpr_HexDump(TAG, WLOG_TRACE, context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH);
|
||||
#endif
|
||||
|
||||
if (memcmp(context->NtlmV2Hash, NTLM_NULL_BUFFER, 16) != 0)
|
||||
return TRUE;
|
||||
|
||||
if (!credentials)
|
||||
return FALSE;
|
||||
else if (memcmp(context->NtlmHash, NTLM_NULL_BUFFER, 16) != 0)
|
||||
{
|
||||
return NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User,
|
||||
credentials->identity.UserLength * 2,
|
||||
(LPWSTR)credentials->identity.Domain,
|
||||
credentials->identity.DomainLength * 2, hash);
|
||||
}
|
||||
else if (credentials->identity.PasswordLength > SSPI_CREDENTIALS_HASH_LENGTH_OFFSET)
|
||||
{
|
||||
/* Special case for WinPR: password hash */
|
||||
if (ntlm_convert_password_hash(context, context->NtlmHash, sizeof(context->NtlmHash)) < 0)
|
||||
return FALSE;
|
||||
|
||||
return NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User,
|
||||
credentials->identity.UserLength * 2,
|
||||
(LPWSTR)credentials->identity.Domain,
|
||||
credentials->identity.DomainLength * 2, hash);
|
||||
}
|
||||
else if (credentials->identity.Password)
|
||||
{
|
||||
return NTOWFv2W(
|
||||
(LPWSTR)credentials->identity.Password, credentials->identity.PasswordLength * 2,
|
||||
(LPWSTR)credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR)credentials->identity.Domain, credentials->identity.DomainLength * 2, hash);
|
||||
}
|
||||
else if (context->HashCallback)
|
||||
{
|
||||
SecBuffer proofValue = WINPR_C_ARRAY_INIT;
|
||||
SecBuffer micValue = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (ntlm_computeProofValue(context, &proofValue) != SEC_E_OK)
|
||||
return FALSE;
|
||||
|
||||
if (ntlm_computeMicValue(context, &micValue) != SEC_E_OK)
|
||||
{
|
||||
sspi_SecBufferFree(&proofValue);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const SECURITY_STATUS ret = context->HashCallback(
|
||||
context->HashCallbackArg, &credentials->identity, &proofValue,
|
||||
context->EncryptedRandomSessionKey, context->AUTHENTICATE_MESSAGE.MessageIntegrityCheck,
|
||||
&micValue, hash);
|
||||
sspi_SecBufferFree(&proofValue);
|
||||
sspi_SecBufferFree(&micValue);
|
||||
return ret == SEC_E_OK;
|
||||
}
|
||||
else if (context->UseSamFileDatabase)
|
||||
{
|
||||
return ntlm_fetch_ntlm_v2_hash(context, hash);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
SECURITY_STATUS ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
BYTE* response = nullptr;
|
||||
BYTE value[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (context->LmCompatibilityLevel < 2)
|
||||
{
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
ZeroMemory(context->LmChallengeResponse.pvBuffer, 24);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
|
||||
if (!ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash))
|
||||
return SEC_E_NO_CREDENTIALS;
|
||||
|
||||
/* Concatenate the server and client challenges */
|
||||
CopyMemory(value, context->ServerChallenge, 8);
|
||||
CopyMemory(&value[8], context->ClientChallenge, 8);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
response = (BYTE*)context->LmChallengeResponse.pvBuffer;
|
||||
/* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */
|
||||
winpr_HMAC(WINPR_MD_MD5, (void*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH, (BYTE*)value,
|
||||
WINPR_MD5_DIGEST_LENGTH, response, WINPR_MD5_DIGEST_LENGTH);
|
||||
/* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response
|
||||
* (24 bytes) */
|
||||
CopyMemory(&response[16], context->ClientChallenge, 8);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute NTLMv2 Response.
|
||||
*
|
||||
* NTLMv2_RESPONSE msdn{cc236653}
|
||||
* NTLMv2 Authentication msdn{cc236700}
|
||||
*
|
||||
* @param context A pointer to the NTLM context
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
|
||||
SECURITY_STATUS ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer ntlm_v2_temp = WINPR_C_ARRAY_INIT;
|
||||
SecBuffer ntlm_v2_temp_chal = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
PSecBuffer TargetInfo = &context->ChallengeTargetInfo;
|
||||
SECURITY_STATUS ret = SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28))
|
||||
goto exit;
|
||||
|
||||
ZeroMemory(ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
{
|
||||
BYTE* blob = (BYTE*)ntlm_v2_temp.pvBuffer;
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
ret = SEC_E_NO_CREDENTIALS;
|
||||
if (!ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash))
|
||||
goto exit;
|
||||
|
||||
/* Construct temp */
|
||||
blob[0] = 1; /* RespType (1 byte) */
|
||||
blob[1] = 1; /* HighRespType (1 byte) */
|
||||
/* Reserved1 (2 bytes) */
|
||||
/* Reserved2 (4 bytes) */
|
||||
CopyMemory(&blob[8], context->Timestamp, 8); /* Timestamp (8 bytes) */
|
||||
CopyMemory(&blob[16], context->ClientChallenge, 8); /* ClientChallenge (8 bytes) */
|
||||
/* Reserved3 (4 bytes) */
|
||||
CopyMemory(&blob[28], TargetInfo->pvBuffer, TargetInfo->cbBuffer);
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
WLog_VRB(TAG, "NTLMv2 Response Temp Blob");
|
||||
winpr_HexDump(TAG, WLOG_TRACE, ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
#endif
|
||||
}
|
||||
/* Concatenate server challenge with temp */
|
||||
ret = SEC_E_INSUFFICIENT_MEMORY;
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8))
|
||||
goto exit;
|
||||
|
||||
{
|
||||
BYTE* blob = (BYTE*)ntlm_v2_temp_chal.pvBuffer;
|
||||
CopyMemory(blob, context->ServerChallenge, 8);
|
||||
CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
|
||||
(BYTE*)ntlm_v2_temp_chal.pvBuffer, ntlm_v2_temp_chal.cbBuffer,
|
||||
context->NtProofString, WINPR_MD5_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
/* NtChallengeResponse, Concatenate NTProofStr with temp */
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16))
|
||||
goto exit;
|
||||
|
||||
{
|
||||
BYTE* blob = (BYTE*)context->NtChallengeResponse.pvBuffer;
|
||||
CopyMemory(blob, context->NtProofString, WINPR_MD5_DIGEST_LENGTH);
|
||||
CopyMemory(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
}
|
||||
/* Compute SessionBaseKey, the HMAC-MD5 hash of NTProofStr using the NTLMv2 hash as the key */
|
||||
winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
|
||||
context->NtProofString, WINPR_MD5_DIGEST_LENGTH, context->SessionBaseKey,
|
||||
WINPR_MD5_DIGEST_LENGTH);
|
||||
ret = SEC_E_OK;
|
||||
exit:
|
||||
sspi_SecBufferFree(&ntlm_v2_temp);
|
||||
sspi_SecBufferFree(&ntlm_v2_temp_chal);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the given plain text using RC4 and the given key.
|
||||
* @param key RC4 key
|
||||
* @param length text length
|
||||
* @param plaintext plain text
|
||||
* @param ciphertext cipher text
|
||||
*/
|
||||
|
||||
BOOL ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext)
|
||||
{
|
||||
WINPR_RC4_CTX* rc4 = winpr_RC4_New(key, 16);
|
||||
|
||||
if (!rc4)
|
||||
return FALSE;
|
||||
|
||||
const BOOL rc = winpr_RC4_Update(rc4, length, plaintext, ciphertext);
|
||||
winpr_RC4_Free(rc4);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate client challenge (8-byte nonce).
|
||||
* @param context A pointer to the NTLM context
|
||||
*/
|
||||
|
||||
BOOL ntlm_generate_client_challenge(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
/* ClientChallenge is used in computation of LMv2 and NTLMv2 responses */
|
||||
if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, sizeof(context->ClientChallenge)) != 0)
|
||||
return TRUE;
|
||||
|
||||
return winpr_RAND(context->ClientChallenge, sizeof(context->ClientChallenge)) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate server challenge (8-byte nonce).
|
||||
* @param context A pointer to the NTLM context
|
||||
*/
|
||||
|
||||
BOOL ntlm_generate_server_challenge(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, sizeof(context->ServerChallenge)) != 0)
|
||||
return TRUE;
|
||||
|
||||
return winpr_RAND(context->ServerChallenge, sizeof(context->ServerChallenge)) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate KeyExchangeKey (the 128-bit SessionBaseKey). msdn{cc236710}
|
||||
* @param context A pointer to the NTLM context
|
||||
*/
|
||||
|
||||
BOOL ntlm_generate_key_exchange_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(sizeof(context->KeyExchangeKey) == sizeof(context->SessionBaseKey));
|
||||
|
||||
/* In NTLMv2, KeyExchangeKey is the 128-bit SessionBaseKey */
|
||||
CopyMemory(context->KeyExchangeKey, context->SessionBaseKey, sizeof(context->KeyExchangeKey));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate RandomSessionKey (16-byte nonce).
|
||||
* @param context A pointer to the NTLM context
|
||||
*/
|
||||
|
||||
BOOL ntlm_generate_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
return winpr_RAND(context->RandomSessionKey, sizeof(context->RandomSessionKey)) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate ExportedSessionKey (the RandomSessionKey, exported)
|
||||
* @param context A pointer to the NTLM context
|
||||
*/
|
||||
|
||||
BOOL ntlm_generate_exported_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(sizeof(context->ExportedSessionKey) >= sizeof(context->RandomSessionKey));
|
||||
|
||||
CopyMemory(context->ExportedSessionKey, context->RandomSessionKey,
|
||||
sizeof(context->ExportedSessionKey));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt RandomSessionKey (RC4-encrypted RandomSessionKey, using KeyExchangeKey as the key).
|
||||
* @param context A pointer to the NTLM context
|
||||
*/
|
||||
|
||||
BOOL ntlm_encrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
/* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the
|
||||
* KeyExchangeKey */
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_rc4k(context->KeyExchangeKey, 16, context->RandomSessionKey,
|
||||
context->EncryptedRandomSessionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt RandomSessionKey (RC4-encrypted RandomSessionKey, using KeyExchangeKey as the key).
|
||||
* @param context A pointer to the NTLM context
|
||||
*/
|
||||
|
||||
BOOL ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
/* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the
|
||||
* KeyExchangeKey */
|
||||
|
||||
/**
|
||||
* if (NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
|
||||
* Set RandomSessionKey to RC4K(KeyExchangeKey,
|
||||
* AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey) else Set RandomSessionKey to KeyExchangeKey
|
||||
*/
|
||||
if (context->NegotiateKeyExchange)
|
||||
{
|
||||
WINPR_ASSERT(sizeof(context->EncryptedRandomSessionKey) ==
|
||||
sizeof(context->RandomSessionKey));
|
||||
return ntlm_rc4k(context->KeyExchangeKey, sizeof(context->EncryptedRandomSessionKey),
|
||||
context->EncryptedRandomSessionKey, context->RandomSessionKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
WINPR_ASSERT(sizeof(context->RandomSessionKey) == sizeof(context->KeyExchangeKey));
|
||||
CopyMemory(context->RandomSessionKey, context->KeyExchangeKey,
|
||||
sizeof(context->RandomSessionKey));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate signing key msdn{cc236711}
|
||||
*
|
||||
* @param exported_session_key ExportedSessionKey
|
||||
* @param sign_magic Sign magic string
|
||||
* @param signing_key Destination signing key
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
|
||||
static BOOL ntlm_generate_signing_key(BYTE* exported_session_key, const SecBuffer* sign_magic,
|
||||
BYTE* signing_key)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
size_t length = 0;
|
||||
BYTE* value = nullptr;
|
||||
|
||||
WINPR_ASSERT(exported_session_key);
|
||||
WINPR_ASSERT(sign_magic);
|
||||
WINPR_ASSERT(signing_key);
|
||||
|
||||
length = WINPR_MD5_DIGEST_LENGTH + sign_magic->cbBuffer;
|
||||
value = (BYTE*)malloc(length);
|
||||
|
||||
if (!value)
|
||||
goto out;
|
||||
|
||||
/* Concatenate ExportedSessionKey with sign magic */
|
||||
CopyMemory(value, exported_session_key, WINPR_MD5_DIGEST_LENGTH);
|
||||
CopyMemory(&value[WINPR_MD5_DIGEST_LENGTH], sign_magic->pvBuffer, sign_magic->cbBuffer);
|
||||
|
||||
rc = winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH);
|
||||
|
||||
out:
|
||||
free(value);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate client signing key (ClientSigningKey). msdn{cc236711}
|
||||
* @param context A pointer to the NTLM context
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
|
||||
BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
const SecBuffer signMagic = { sizeof(NTLM_CLIENT_SIGN_MAGIC), 0, NTLM_CLIENT_SIGN_MAGIC };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic,
|
||||
context->ClientSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate server signing key (ServerSigningKey). msdn{cc236711}
|
||||
* @param context A pointer to the NTLM context
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
|
||||
BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
const SecBuffer signMagic = { sizeof(NTLM_SERVER_SIGN_MAGIC), 0, NTLM_SERVER_SIGN_MAGIC };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic,
|
||||
context->ServerSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate client sealing key (ClientSealingKey). msdn{cc236712}
|
||||
* @param context A pointer to the NTLM context
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
|
||||
BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
const SecBuffer sealMagic = { sizeof(NTLM_CLIENT_SEAL_MAGIC), 0, NTLM_CLIENT_SEAL_MAGIC };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic,
|
||||
context->ClientSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate server sealing key (ServerSealingKey). msdn{cc236712}
|
||||
* @param context A pointer to the NTLM context
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
|
||||
BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
const SecBuffer sealMagic = { sizeof(NTLM_SERVER_SEAL_MAGIC), 0, NTLM_SERVER_SEAL_MAGIC };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic,
|
||||
context->ServerSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize RC4 stream cipher states for sealing.
|
||||
* @param context A pointer to the NTLM context
|
||||
*/
|
||||
|
||||
BOOL ntlm_init_rc4_seal_states(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
if (context->server)
|
||||
{
|
||||
context->SendSigningKey = context->ServerSigningKey;
|
||||
context->RecvSigningKey = context->ClientSigningKey;
|
||||
context->SendSealingKey = context->ClientSealingKey;
|
||||
context->RecvSealingKey = context->ServerSealingKey;
|
||||
context->SendRc4Seal =
|
||||
winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey));
|
||||
context->RecvRc4Seal =
|
||||
winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
context->SendSigningKey = context->ClientSigningKey;
|
||||
context->RecvSigningKey = context->ServerSigningKey;
|
||||
context->SendSealingKey = context->ServerSealingKey;
|
||||
context->RecvSealingKey = context->ClientSealingKey;
|
||||
context->SendRc4Seal =
|
||||
winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey));
|
||||
context->RecvRc4Seal =
|
||||
winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey));
|
||||
}
|
||||
if (!context->SendRc4Seal)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to allocate context->SendRc4Seal");
|
||||
return FALSE;
|
||||
}
|
||||
if (!context->RecvRc4Seal)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to allocate context->RecvRc4Seal");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
/*
|
||||
* Compute the HMAC-MD5 hash of ConcatenationOf(NEGOTIATE_MESSAGE,
|
||||
* CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey
|
||||
*/
|
||||
WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(mic);
|
||||
WINPR_ASSERT(size >= WINPR_MD5_DIGEST_LENGTH);
|
||||
|
||||
memset(mic, 0, size);
|
||||
if (!hmac)
|
||||
return FALSE;
|
||||
|
||||
if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->ExportedSessionKey, WINPR_MD5_DIGEST_LENGTH))
|
||||
goto fail;
|
||||
|
||||
if (!winpr_HMAC_Update(hmac, (BYTE*)context->NegotiateMessage.pvBuffer,
|
||||
context->NegotiateMessage.cbBuffer))
|
||||
goto fail;
|
||||
if (!winpr_HMAC_Update(hmac, (BYTE*)context->ChallengeMessage.pvBuffer,
|
||||
context->ChallengeMessage.cbBuffer))
|
||||
goto fail;
|
||||
|
||||
if (context->MessageIntegrityCheckOffset > 0)
|
||||
{
|
||||
const BYTE* auth = (BYTE*)context->AuthenticateMessage.pvBuffer;
|
||||
const BYTE data[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
|
||||
const size_t rest = context->MessageIntegrityCheckOffset + sizeof(data);
|
||||
|
||||
WINPR_ASSERT(rest <= context->AuthenticateMessage.cbBuffer);
|
||||
if (!winpr_HMAC_Update(hmac, &auth[0], context->MessageIntegrityCheckOffset))
|
||||
goto fail;
|
||||
if (!winpr_HMAC_Update(hmac, data, sizeof(data)))
|
||||
goto fail;
|
||||
if (!winpr_HMAC_Update(hmac, &auth[rest], context->AuthenticateMessage.cbBuffer - rest))
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!winpr_HMAC_Update(hmac, (BYTE*)context->AuthenticateMessage.pvBuffer,
|
||||
context->AuthenticateMessage.cbBuffer))
|
||||
goto fail;
|
||||
}
|
||||
rc = winpr_HMAC_Final(hmac, mic, WINPR_MD5_DIGEST_LENGTH);
|
||||
|
||||
fail:
|
||||
winpr_HMAC_Free(hmac);
|
||||
return rc;
|
||||
}
|
||||
63
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_compute.h
vendored
Normal file
63
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_compute.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Compute)
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_NTLM_COMPUTE_H
|
||||
#define WINPR_SSPI_NTLM_COMPUTE_H
|
||||
|
||||
#include "ntlm.h"
|
||||
|
||||
#include "ntlm_av_pairs.h"
|
||||
|
||||
BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo);
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo);
|
||||
#endif
|
||||
|
||||
BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response);
|
||||
|
||||
void ntlm_output_target_name(NTLM_CONTEXT* context);
|
||||
void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context);
|
||||
|
||||
SECURITY_STATUS ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
SECURITY_STATUS ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
|
||||
BOOL ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext);
|
||||
BOOL ntlm_generate_client_challenge(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_server_challenge(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_key_exchange_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_random_session_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_exported_session_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_encrypt_random_session_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_decrypt_random_session_key(NTLM_CONTEXT* context);
|
||||
|
||||
BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_init_rc4_seal_states(NTLM_CONTEXT* context);
|
||||
|
||||
BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size);
|
||||
|
||||
#endif /* WINPR_AUTH_NTLM_COMPUTE_H */
|
||||
40
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_export.h
vendored
Normal file
40
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_export.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package
|
||||
*
|
||||
* Copyright 2021 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2021 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_NTLM_EXPORT_H
|
||||
#define WINPR_SSPI_NTLM_EXPORT_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern const SecPkgInfoA NTLM_SecPkgInfoA;
|
||||
extern const SecPkgInfoW NTLM_SecPkgInfoW;
|
||||
extern const SecurityFunctionTableA NTLM_SecurityFunctionTableA;
|
||||
extern const SecurityFunctionTableW NTLM_SecurityFunctionTableW;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1437
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_message.c
vendored
Normal file
1437
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_message.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
36
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_message.h
vendored
Normal file
36
third_party/FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_message.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Message)
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_NTLM_MESSAGE_H
|
||||
#define WINPR_SSPI_NTLM_MESSAGE_H
|
||||
|
||||
#include "ntlm.h"
|
||||
|
||||
SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, SecBuffer* buffer);
|
||||
SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SecBuffer* buffer);
|
||||
SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* buffer);
|
||||
SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* buffer);
|
||||
SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer* buffer);
|
||||
SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer* buffer);
|
||||
|
||||
SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context);
|
||||
|
||||
const char* ntlm_get_negotiate_string(UINT32 flag);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_MESSAGE_H */
|
||||
1750
third_party/FreeRDP/winpr/libwinpr/sspi/Negotiate/negotiate.c
vendored
Normal file
1750
third_party/FreeRDP/winpr/libwinpr/sspi/Negotiate/negotiate.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
68
third_party/FreeRDP/winpr/libwinpr/sspi/Negotiate/negotiate.h
vendored
Normal file
68
third_party/FreeRDP/winpr/libwinpr/sspi/Negotiate/negotiate.h
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Negotiate Security Package
|
||||
*
|
||||
* Copyright 2011-2012 Jiten Pathy
|
||||
*
|
||||
* 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 WINPR_SSPI_NEGOTIATE_PRIVATE_H
|
||||
#define WINPR_SSPI_NEGOTIATE_PRIVATE_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#include "../sspi.h"
|
||||
|
||||
#define NTLM_OID "1.3.6.1.4.1.311.2.2.10"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NEGOTIATE_STATE_INITIAL,
|
||||
NEGOTIATE_STATE_FINAL_OPTIMISTIC,
|
||||
NEGOTIATE_STATE_NEGORESP,
|
||||
NEGOTIATE_STATE_MIC,
|
||||
NEGOTIATE_STATE_FINAL,
|
||||
} NEGOTIATE_STATE;
|
||||
|
||||
typedef struct Mech_st Mech;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NEGOTIATE_STATE state;
|
||||
CtxtHandle sub_context;
|
||||
SecBuffer mechTypes;
|
||||
const Mech* mech;
|
||||
BOOL mic;
|
||||
BOOL spnego;
|
||||
} NEGOTIATE_CONTEXT;
|
||||
|
||||
static inline NEGOTIATE_CONTEXT NEGOTIATE_CONTEXT_init(void)
|
||||
{
|
||||
const NEGOTIATE_CONTEXT empty = { .state = NEGOTIATE_STATE_INITIAL,
|
||||
.sub_context = { 0 },
|
||||
.mechTypes = { 0 },
|
||||
.mech = nullptr,
|
||||
.mic = FALSE,
|
||||
.spnego = FALSE };
|
||||
return empty;
|
||||
}
|
||||
|
||||
extern const SecPkgInfoA NEGOTIATE_SecPkgInfoA;
|
||||
extern const SecPkgInfoW NEGOTIATE_SecPkgInfoW;
|
||||
extern const SecurityFunctionTableA NEGOTIATE_SecurityFunctionTableA;
|
||||
extern const SecurityFunctionTableW NEGOTIATE_SecurityFunctionTableW;
|
||||
|
||||
BOOL NEGOTIATE_init(void);
|
||||
|
||||
#endif /* WINPR_SSPI_NEGOTIATE_PRIVATE_H */
|
||||
475
third_party/FreeRDP/winpr/libwinpr/sspi/Schannel/schannel.c
vendored
Normal file
475
third_party/FreeRDP/winpr/libwinpr/sspi/Schannel/schannel.c
vendored
Normal file
@@ -0,0 +1,475 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Schannel Security Package
|
||||
*
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#include "schannel.h"
|
||||
|
||||
#include "../sspi.h"
|
||||
#include "../../log.h"
|
||||
|
||||
static char* SCHANNEL_PACKAGE_NAME = "Schannel";
|
||||
|
||||
#define TAG WINPR_TAG("sspi.Schannel")
|
||||
|
||||
SCHANNEL_CONTEXT* schannel_ContextNew(void)
|
||||
{
|
||||
SCHANNEL_CONTEXT* context = nullptr;
|
||||
context = (SCHANNEL_CONTEXT*)calloc(1, sizeof(SCHANNEL_CONTEXT));
|
||||
|
||||
if (!context)
|
||||
return nullptr;
|
||||
|
||||
context->openssl = schannel_openssl_new();
|
||||
|
||||
if (!context->openssl)
|
||||
{
|
||||
free(context);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void schannel_ContextFree(SCHANNEL_CONTEXT* context)
|
||||
{
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
schannel_openssl_free(context->openssl);
|
||||
free(context);
|
||||
}
|
||||
|
||||
static SCHANNEL_CREDENTIALS* schannel_CredentialsNew(void)
|
||||
{
|
||||
SCHANNEL_CREDENTIALS* credentials = nullptr;
|
||||
credentials = (SCHANNEL_CREDENTIALS*)calloc(1, sizeof(SCHANNEL_CREDENTIALS));
|
||||
return credentials;
|
||||
}
|
||||
|
||||
static void schannel_CredentialsFree(SCHANNEL_CREDENTIALS* credentials)
|
||||
{
|
||||
free(credentials);
|
||||
}
|
||||
|
||||
static ALG_ID schannel_SupportedAlgs[] = { CALG_AES_128,
|
||||
CALG_AES_256,
|
||||
CALG_RC4,
|
||||
CALG_DES,
|
||||
CALG_3DES,
|
||||
CALG_MD5,
|
||||
CALG_SHA1,
|
||||
CALG_SHA_256,
|
||||
CALG_SHA_384,
|
||||
CALG_SHA_512,
|
||||
CALG_RSA_SIGN,
|
||||
CALG_DH_EPHEM,
|
||||
(ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RESERVED7 |
|
||||
6), /* what is this? */
|
||||
CALG_DSS_SIGN,
|
||||
CALG_ECDSA };
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesW(
|
||||
WINPR_ATTR_UNUSED PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
if (ulAttribute == SECPKG_ATTR_SUPPORTED_ALGS)
|
||||
{
|
||||
PSecPkgCred_SupportedAlgs SupportedAlgs = (PSecPkgCred_SupportedAlgs)pBuffer;
|
||||
SupportedAlgs->cSupportedAlgs = sizeof(schannel_SupportedAlgs) / sizeof(ALG_ID);
|
||||
SupportedAlgs->palgSupportedAlgs = (ALG_ID*)schannel_SupportedAlgs;
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (ulAttribute == SECPKG_ATTR_CIPHER_STRENGTHS)
|
||||
{
|
||||
PSecPkgCred_CipherStrengths CipherStrengths = (PSecPkgCred_CipherStrengths)pBuffer;
|
||||
CipherStrengths->dwMinimumCipherStrength = 40;
|
||||
CipherStrengths->dwMaximumCipherStrength = 256;
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (ulAttribute == SECPKG_ATTR_SUPPORTED_PROTOCOLS)
|
||||
{
|
||||
PSecPkgCred_SupportedProtocols SupportedProtocols = (PSecPkgCred_SupportedProtocols)pBuffer;
|
||||
/* Observed SupportedProtocols: 0x208A0 */
|
||||
SupportedProtocols->grbitProtocol = (SP_PROT_CLIENTS | SP_PROT_SERVERS);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesA(PCredHandle phCredential,
|
||||
ULONG ulAttribute,
|
||||
void* pBuffer)
|
||||
{
|
||||
return schannel_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_AcquireCredentialsHandleW(
|
||||
WINPR_ATTR_UNUSED SEC_WCHAR* pszPrincipal, WINPR_ATTR_UNUSED SEC_WCHAR* pszPackage,
|
||||
ULONG fCredentialUse, WINPR_ATTR_UNUSED void* pvLogonID, void* pAuthData,
|
||||
WINPR_ATTR_UNUSED SEC_GET_KEY_FN pGetKeyFn, WINPR_ATTR_UNUSED void* pvGetKeyArgument,
|
||||
PCredHandle phCredential, WINPR_ATTR_UNUSED PTimeStamp ptsExpiry)
|
||||
{
|
||||
SCHANNEL_CREDENTIALS* credentials = nullptr;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
{
|
||||
SCHANNEL_CRED* cred = nullptr;
|
||||
credentials = schannel_CredentialsNew();
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
cred = (SCHANNEL_CRED*)pAuthData;
|
||||
|
||||
if (cred)
|
||||
{
|
||||
CopyMemory(&credentials->cred, cred, sizeof(SCHANNEL_CRED));
|
||||
}
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*)SCHANNEL_PACKAGE_NAME);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (fCredentialUse == SECPKG_CRED_INBOUND)
|
||||
{
|
||||
credentials = schannel_CredentialsNew();
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*)SCHANNEL_PACKAGE_NAME);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_AcquireCredentialsHandleA(
|
||||
SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
|
||||
void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
|
||||
PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status = 0;
|
||||
SEC_WCHAR* pszPrincipalW = nullptr;
|
||||
SEC_WCHAR* pszPackageW = nullptr;
|
||||
if (pszPrincipal)
|
||||
pszPrincipalW = ConvertUtf8ToWCharAlloc(pszPrincipal, nullptr);
|
||||
if (pszPackage)
|
||||
pszPackageW = ConvertUtf8ToWCharAlloc(pszPackage, nullptr);
|
||||
|
||||
status = schannel_AcquireCredentialsHandleW(pszPrincipalW, pszPackageW, fCredentialUse,
|
||||
pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument,
|
||||
phCredential, ptsExpiry);
|
||||
free(pszPrincipalW);
|
||||
free(pszPackageW);
|
||||
return status;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_FreeCredentialsHandle(PCredHandle phCredential)
|
||||
{
|
||||
SCHANNEL_CREDENTIALS* credentials = nullptr;
|
||||
|
||||
if (!phCredential)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
schannel_CredentialsFree(credentials);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextW(
|
||||
PCredHandle phCredential, PCtxtHandle phContext, WINPR_ATTR_UNUSED SEC_WCHAR* pszTargetName,
|
||||
WINPR_ATTR_UNUSED ULONG fContextReq, WINPR_ATTR_UNUSED ULONG Reserved1,
|
||||
WINPR_ATTR_UNUSED ULONG TargetDataRep, PSecBufferDesc pInput, WINPR_ATTR_UNUSED ULONG Reserved2,
|
||||
PCtxtHandle phNewContext, PSecBufferDesc pOutput, WINPR_ATTR_UNUSED PULONG pfContextAttr,
|
||||
WINPR_ATTR_UNUSED PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status = 0;
|
||||
SCHANNEL_CONTEXT* context = nullptr;
|
||||
SCHANNEL_CREDENTIALS* credentials = nullptr;
|
||||
|
||||
/* behave like windows SSPIs that don't want empty context */
|
||||
if (phContext && !phContext->dwLower && !phContext->dwUpper)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
context = sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = schannel_ContextNew();
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
context->server = FALSE;
|
||||
CopyMemory(&context->cred, &credentials->cred, sizeof(SCHANNEL_CRED));
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
|
||||
schannel_openssl_client_init(context->openssl);
|
||||
}
|
||||
|
||||
status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput);
|
||||
return status;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextA(
|
||||
PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, ULONG fContextReq,
|
||||
ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
|
||||
PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status = 0;
|
||||
SEC_WCHAR* pszTargetNameW = nullptr;
|
||||
|
||||
if (pszTargetName != nullptr)
|
||||
{
|
||||
pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName, nullptr);
|
||||
if (!pszTargetNameW)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
status = schannel_InitializeSecurityContextW(
|
||||
phCredential, phContext, pszTargetNameW, fContextReq, Reserved1, TargetDataRep, pInput,
|
||||
Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
free(pszTargetNameW);
|
||||
return status;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContext(
|
||||
WINPR_ATTR_UNUSED PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
|
||||
WINPR_ATTR_UNUSED ULONG fContextReq, WINPR_ATTR_UNUSED ULONG TargetDataRep,
|
||||
PCtxtHandle phNewContext, PSecBufferDesc pOutput, WINPR_ATTR_UNUSED PULONG pfContextAttr,
|
||||
WINPR_ATTR_UNUSED PTimeStamp ptsTimeStamp)
|
||||
{
|
||||
SECURITY_STATUS status = 0;
|
||||
SCHANNEL_CONTEXT* context = nullptr;
|
||||
|
||||
/* behave like windows SSPIs that don't want empty context */
|
||||
if (phContext && !phContext->dwLower && !phContext->dwUpper)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = schannel_ContextNew();
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
context->server = TRUE;
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
|
||||
schannel_openssl_server_init(context->openssl);
|
||||
}
|
||||
|
||||
status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
|
||||
return status;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
SCHANNEL_CONTEXT* context = nullptr;
|
||||
context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
schannel_ContextFree(context);
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_QueryContextAttributes(PCtxtHandle phContext,
|
||||
ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (ulAttribute == SECPKG_ATTR_SIZES)
|
||||
{
|
||||
SecPkgContext_Sizes* Sizes = (SecPkgContext_Sizes*)pBuffer;
|
||||
Sizes->cbMaxToken = 0x6000;
|
||||
Sizes->cbMaxSignature = 16;
|
||||
Sizes->cbBlockSize = 0;
|
||||
Sizes->cbSecurityTrailer = 16;
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (ulAttribute == SECPKG_ATTR_STREAM_SIZES)
|
||||
{
|
||||
SecPkgContext_StreamSizes* StreamSizes = (SecPkgContext_StreamSizes*)pBuffer;
|
||||
StreamSizes->cbHeader = 5;
|
||||
StreamSizes->cbTrailer = 36;
|
||||
StreamSizes->cbMaximumMessage = 0x4000;
|
||||
StreamSizes->cBuffers = 4;
|
||||
StreamSizes->cbBlockSize = 16;
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_MakeSignature(WINPR_ATTR_UNUSED PCtxtHandle phContext,
|
||||
WINPR_ATTR_UNUSED ULONG fQOP,
|
||||
WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
|
||||
WINPR_ATTR_UNUSED ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_VerifySignature(WINPR_ATTR_UNUSED PCtxtHandle phContext,
|
||||
WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
|
||||
WINPR_ATTR_UNUSED ULONG MessageSeqNo,
|
||||
WINPR_ATTR_UNUSED ULONG* pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_EncryptMessage(WINPR_ATTR_UNUSED PCtxtHandle phContext,
|
||||
WINPR_ATTR_UNUSED ULONG fQOP,
|
||||
PSecBufferDesc pMessage,
|
||||
WINPR_ATTR_UNUSED ULONG MessageSeqNo)
|
||||
{
|
||||
SECURITY_STATUS status = 0;
|
||||
SCHANNEL_CONTEXT* context = nullptr;
|
||||
context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
status = schannel_openssl_encrypt_message(context->openssl, pMessage);
|
||||
return status;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY schannel_DecryptMessage(PCtxtHandle phContext,
|
||||
PSecBufferDesc pMessage,
|
||||
WINPR_ATTR_UNUSED ULONG MessageSeqNo,
|
||||
WINPR_ATTR_UNUSED ULONG* pfQOP)
|
||||
{
|
||||
SECURITY_STATUS status = 0;
|
||||
SCHANNEL_CONTEXT* context = nullptr;
|
||||
context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
status = schannel_openssl_decrypt_message(context->openssl, pMessage);
|
||||
return status;
|
||||
}
|
||||
|
||||
const SecurityFunctionTableA SCHANNEL_SecurityFunctionTableA = {
|
||||
3, /* dwVersion */
|
||||
nullptr, /* EnumerateSecurityPackages */
|
||||
schannel_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
|
||||
schannel_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
|
||||
schannel_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
nullptr, /* Reserved2 */
|
||||
schannel_InitializeSecurityContextA, /* InitializeSecurityContext */
|
||||
schannel_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
nullptr, /* CompleteAuthToken */
|
||||
schannel_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
nullptr, /* ApplyControlToken */
|
||||
schannel_QueryContextAttributes, /* QueryContextAttributes */
|
||||
nullptr, /* ImpersonateSecurityContext */
|
||||
nullptr, /* RevertSecurityContext */
|
||||
schannel_MakeSignature, /* MakeSignature */
|
||||
schannel_VerifySignature, /* VerifySignature */
|
||||
nullptr, /* FreeContextBuffer */
|
||||
nullptr, /* QuerySecurityPackageInfo */
|
||||
nullptr, /* Reserved3 */
|
||||
nullptr, /* Reserved4 */
|
||||
nullptr, /* ExportSecurityContext */
|
||||
nullptr, /* ImportSecurityContext */
|
||||
nullptr, /* AddCredentials */
|
||||
nullptr, /* Reserved8 */
|
||||
nullptr, /* QuerySecurityContextToken */
|
||||
schannel_EncryptMessage, /* EncryptMessage */
|
||||
schannel_DecryptMessage, /* DecryptMessage */
|
||||
nullptr, /* SetContextAttributes */
|
||||
nullptr, /* SetCredentialsAttributes */
|
||||
};
|
||||
|
||||
const SecurityFunctionTableW SCHANNEL_SecurityFunctionTableW = {
|
||||
3, /* dwVersion */
|
||||
nullptr, /* EnumerateSecurityPackages */
|
||||
schannel_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
|
||||
schannel_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
|
||||
schannel_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
nullptr, /* Reserved2 */
|
||||
schannel_InitializeSecurityContextW, /* InitializeSecurityContext */
|
||||
schannel_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
nullptr, /* CompleteAuthToken */
|
||||
schannel_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
nullptr, /* ApplyControlToken */
|
||||
schannel_QueryContextAttributes, /* QueryContextAttributes */
|
||||
nullptr, /* ImpersonateSecurityContext */
|
||||
nullptr, /* RevertSecurityContext */
|
||||
schannel_MakeSignature, /* MakeSignature */
|
||||
schannel_VerifySignature, /* VerifySignature */
|
||||
nullptr, /* FreeContextBuffer */
|
||||
nullptr, /* QuerySecurityPackageInfo */
|
||||
nullptr, /* Reserved3 */
|
||||
nullptr, /* Reserved4 */
|
||||
nullptr, /* ExportSecurityContext */
|
||||
nullptr, /* ImportSecurityContext */
|
||||
nullptr, /* AddCredentials */
|
||||
nullptr, /* Reserved8 */
|
||||
nullptr, /* QuerySecurityContextToken */
|
||||
schannel_EncryptMessage, /* EncryptMessage */
|
||||
schannel_DecryptMessage, /* DecryptMessage */
|
||||
nullptr, /* SetContextAttributes */
|
||||
nullptr, /* SetCredentialsAttributes */
|
||||
};
|
||||
|
||||
const SecPkgInfoA SCHANNEL_SecPkgInfoA = {
|
||||
0x000107B3, /* fCapabilities */
|
||||
1, /* wVersion */
|
||||
0x000E, /* wRPCID */
|
||||
SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
|
||||
"Schannel", /* Name */
|
||||
"Schannel Security Package" /* Comment */
|
||||
};
|
||||
|
||||
static WCHAR SCHANNEL_SecPkgInfoW_NameBuffer[32] = WINPR_C_ARRAY_INIT;
|
||||
static WCHAR SCHANNEL_SecPkgInfoW_CommentBuffer[32] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
const SecPkgInfoW SCHANNEL_SecPkgInfoW = {
|
||||
0x000107B3, /* fCapabilities */
|
||||
1, /* wVersion */
|
||||
0x000E, /* wRPCID */
|
||||
SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
|
||||
SCHANNEL_SecPkgInfoW_NameBuffer, /* Name */
|
||||
SCHANNEL_SecPkgInfoW_CommentBuffer /* Comment */
|
||||
};
|
||||
|
||||
BOOL SCHANNEL_init(void)
|
||||
{
|
||||
InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Name, SCHANNEL_SecPkgInfoW_NameBuffer,
|
||||
ARRAYSIZE(SCHANNEL_SecPkgInfoW_NameBuffer));
|
||||
InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Comment, SCHANNEL_SecPkgInfoW_CommentBuffer,
|
||||
ARRAYSIZE(SCHANNEL_SecPkgInfoW_CommentBuffer));
|
||||
return TRUE;
|
||||
}
|
||||
53
third_party/FreeRDP/winpr/libwinpr/sspi/Schannel/schannel.h
vendored
Normal file
53
third_party/FreeRDP/winpr/libwinpr/sspi/Schannel/schannel.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Schannel Security Package
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_SCHANNEL_PRIVATE_H
|
||||
#define WINPR_SSPI_SCHANNEL_PRIVATE_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/schannel.h>
|
||||
|
||||
#include "../sspi.h"
|
||||
|
||||
#include "schannel_openssl.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SCHANNEL_CRED cred;
|
||||
ULONG fCredentialUse;
|
||||
} SCHANNEL_CREDENTIALS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BOOL server;
|
||||
SCHANNEL_CRED cred;
|
||||
SCHANNEL_OPENSSL* openssl;
|
||||
} SCHANNEL_CONTEXT;
|
||||
|
||||
SCHANNEL_CONTEXT* schannel_ContextNew(void);
|
||||
void schannel_ContextFree(SCHANNEL_CONTEXT* context);
|
||||
|
||||
extern const SecPkgInfoA SCHANNEL_SecPkgInfoA;
|
||||
extern const SecPkgInfoW SCHANNEL_SecPkgInfoW;
|
||||
extern const SecurityFunctionTableA SCHANNEL_SecurityFunctionTableA;
|
||||
extern const SecurityFunctionTableW SCHANNEL_SecurityFunctionTableW;
|
||||
|
||||
BOOL SCHANNEL_init(void);
|
||||
|
||||
#endif /* WINPR_SSPI_SCHANNEL_PRIVATE_H */
|
||||
657
third_party/FreeRDP/winpr/libwinpr/sspi/Schannel/schannel_openssl.c
vendored
Normal file
657
third_party/FreeRDP/winpr/libwinpr/sspi/Schannel/schannel_openssl.c
vendored
Normal file
@@ -0,0 +1,657 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Schannel Security Package (OpenSSL)
|
||||
*
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include "schannel_openssl.h"
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/ssl.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/crypto.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#define LIMIT_INTMAX(a) ((a) > INT32_MAX) ? INT32_MAX : (int)(a)
|
||||
|
||||
struct S_SCHANNEL_OPENSSL
|
||||
{
|
||||
SSL* ssl;
|
||||
SSL_CTX* ctx;
|
||||
BOOL connected;
|
||||
BIO* bioRead;
|
||||
BIO* bioWrite;
|
||||
BYTE* ReadBuffer;
|
||||
BYTE* WriteBuffer;
|
||||
};
|
||||
|
||||
#include "../../log.h"
|
||||
#define TAG WINPR_TAG("sspi.schannel")
|
||||
|
||||
static char* openssl_get_ssl_error_string(int ssl_error)
|
||||
{
|
||||
switch (ssl_error)
|
||||
{
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return "SSL_ERROR_ZERO_RETURN";
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return "SSL_ERROR_WANT_READ";
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return "SSL_ERROR_WANT_WRITE";
|
||||
|
||||
case SSL_ERROR_SYSCALL:
|
||||
return "SSL_ERROR_SYSCALL";
|
||||
|
||||
case SSL_ERROR_SSL:
|
||||
return "SSL_ERROR_SSL";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "SSL_ERROR_UNKNOWN";
|
||||
}
|
||||
|
||||
static void schannel_context_cleanup(SCHANNEL_OPENSSL* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
free(context->ReadBuffer);
|
||||
context->ReadBuffer = nullptr;
|
||||
|
||||
if (context->bioWrite)
|
||||
BIO_free_all(context->bioWrite);
|
||||
context->bioWrite = nullptr;
|
||||
|
||||
if (context->bioRead)
|
||||
BIO_free_all(context->bioRead);
|
||||
context->bioRead = nullptr;
|
||||
|
||||
if (context->ssl)
|
||||
SSL_free(context->ssl);
|
||||
context->ssl = nullptr;
|
||||
|
||||
if (context->ctx)
|
||||
SSL_CTX_free(context->ctx);
|
||||
context->ctx = nullptr;
|
||||
}
|
||||
|
||||
static const SSL_METHOD* get_method(BOOL server)
|
||||
{
|
||||
if (server)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
return SSLv23_server_method();
|
||||
#else
|
||||
return TLS_server_method();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
return SSLv23_client_method();
|
||||
#else
|
||||
return TLS_client_method();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
int schannel_openssl_client_init(SCHANNEL_OPENSSL* context)
|
||||
{
|
||||
int status = 0;
|
||||
long options = 0;
|
||||
context->ctx = SSL_CTX_new(get_method(FALSE));
|
||||
|
||||
if (!context->ctx)
|
||||
{
|
||||
WLog_ERR(TAG, "SSL_CTX_new failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* SSL_OP_NO_COMPRESSION:
|
||||
*
|
||||
* The Microsoft RDP server does not advertise support
|
||||
* for TLS compression, but alternative servers may support it.
|
||||
* This was observed between early versions of the FreeRDP server
|
||||
* and the FreeRDP client, and caused major performance issues,
|
||||
* which is why we're disabling it.
|
||||
*/
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
options |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
/**
|
||||
* SSL_OP_TLS_BLOCK_PADDING_BUG:
|
||||
*
|
||||
* The Microsoft RDP server does *not* support TLS padding.
|
||||
* It absolutely needs to be disabled otherwise it won't work.
|
||||
*/
|
||||
options |= SSL_OP_TLS_BLOCK_PADDING_BUG;
|
||||
/**
|
||||
* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:
|
||||
*
|
||||
* Just like TLS padding, the Microsoft RDP server does not
|
||||
* support empty fragments. This needs to be disabled.
|
||||
*/
|
||||
options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
|
||||
SSL_CTX_set_options(context->ctx, WINPR_ASSERTING_INT_CAST(uint64_t, options));
|
||||
context->ssl = SSL_new(context->ctx);
|
||||
|
||||
if (!context->ssl)
|
||||
{
|
||||
WLog_ERR(TAG, "SSL_new failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
context->bioRead = BIO_new(BIO_s_mem());
|
||||
|
||||
if (!context->bioRead)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_new failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = BIO_set_write_buf_size(context->bioRead, SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (status != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_set_write_buf_size on bioRead failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
context->bioWrite = BIO_new(BIO_s_mem());
|
||||
|
||||
if (!context->bioWrite)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_new failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = BIO_set_write_buf_size(context->bioWrite, SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (status != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_set_write_buf_size on bioWrite failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = BIO_make_bio_pair(context->bioRead, context->bioWrite);
|
||||
|
||||
if (status != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_make_bio_pair failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SSL_set_bio(context->ssl, context->bioRead, context->bioWrite);
|
||||
context->ReadBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (!context->ReadBuffer)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to allocate ReadBuffer");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
context->WriteBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (!context->WriteBuffer)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to allocate ReadBuffer");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
schannel_context_cleanup(context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int schannel_openssl_server_init(SCHANNEL_OPENSSL* context)
|
||||
{
|
||||
int status = 0;
|
||||
unsigned long options = 0;
|
||||
|
||||
context->ctx = SSL_CTX_new(get_method(TRUE));
|
||||
|
||||
if (!context->ctx)
|
||||
{
|
||||
WLog_ERR(TAG, "SSL_CTX_new failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SSL_OP_NO_SSLv2:
|
||||
*
|
||||
* We only want SSLv3 and TLSv1, so disable SSLv2.
|
||||
* SSLv3 is used by, eg. Microsoft RDC for Mac OS X.
|
||||
*/
|
||||
options |= SSL_OP_NO_SSLv2;
|
||||
/**
|
||||
* SSL_OP_NO_COMPRESSION:
|
||||
*
|
||||
* The Microsoft RDP server does not advertise support
|
||||
* for TLS compression, but alternative servers may support it.
|
||||
* This was observed between early versions of the FreeRDP server
|
||||
* and the FreeRDP client, and caused major performance issues,
|
||||
* which is why we're disabling it.
|
||||
*/
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
options |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
/**
|
||||
* SSL_OP_TLS_BLOCK_PADDING_BUG:
|
||||
*
|
||||
* The Microsoft RDP server does *not* support TLS padding.
|
||||
* It absolutely needs to be disabled otherwise it won't work.
|
||||
*/
|
||||
options |= SSL_OP_TLS_BLOCK_PADDING_BUG;
|
||||
/**
|
||||
* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:
|
||||
*
|
||||
* Just like TLS padding, the Microsoft RDP server does not
|
||||
* support empty fragments. This needs to be disabled.
|
||||
*/
|
||||
options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
|
||||
SSL_CTX_set_options(context->ctx, options);
|
||||
|
||||
#if defined(WITH_DEBUG_SCHANNEL)
|
||||
if (SSL_CTX_use_RSAPrivateKey_file(context->ctx, "/tmp/localhost.key", SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
WLog_ERR(TAG, "SSL_CTX_use_RSAPrivateKey_file failed");
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
context->ssl = SSL_new(context->ctx);
|
||||
|
||||
if (!context->ssl)
|
||||
{
|
||||
WLog_ERR(TAG, "SSL_new failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (SSL_use_certificate_file(context->ssl, "/tmp/localhost.crt", SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
WLog_ERR(TAG, "SSL_use_certificate_file failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
context->bioRead = BIO_new(BIO_s_mem());
|
||||
|
||||
if (!context->bioRead)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_new failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = BIO_set_write_buf_size(context->bioRead, SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (status != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_set_write_buf_size failed for bioRead");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
context->bioWrite = BIO_new(BIO_s_mem());
|
||||
|
||||
if (!context->bioWrite)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_new failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = BIO_set_write_buf_size(context->bioWrite, SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (status != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_set_write_buf_size failed for bioWrite");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = BIO_make_bio_pair(context->bioRead, context->bioWrite);
|
||||
|
||||
if (status != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_make_bio_pair failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SSL_set_bio(context->ssl, context->bioRead, context->bioWrite);
|
||||
context->ReadBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (!context->ReadBuffer)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to allocate memory for ReadBuffer");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
context->WriteBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (!context->WriteBuffer)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to allocate memory for WriteBuffer");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
schannel_context_cleanup(context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context,
|
||||
PSecBufferDesc pInput,
|
||||
PSecBufferDesc pOutput)
|
||||
{
|
||||
int status = 0;
|
||||
int ssl_error = 0;
|
||||
PSecBuffer pBuffer = nullptr;
|
||||
|
||||
if (!context->connected)
|
||||
{
|
||||
if (pInput)
|
||||
{
|
||||
if (pInput->cBuffers < 1)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
pBuffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
ERR_clear_error();
|
||||
status =
|
||||
BIO_write(context->bioRead, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
|
||||
if (status < 0)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
status = SSL_connect(context->ssl);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
ssl_error = SSL_get_error(context->ssl, status);
|
||||
WLog_ERR(TAG, "SSL_connect error: %s", openssl_get_ssl_error_string(ssl_error));
|
||||
}
|
||||
|
||||
if (status == 1)
|
||||
context->connected = TRUE;
|
||||
|
||||
ERR_clear_error();
|
||||
status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (pOutput->cBuffers < 1)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
pBuffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (status > 0)
|
||||
{
|
||||
if (pBuffer->cbBuffer < WINPR_ASSERTING_INT_CAST(uint32_t, status))
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, status));
|
||||
pBuffer->cbBuffer = WINPR_ASSERTING_INT_CAST(uint32_t, status);
|
||||
return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
pBuffer->cbBuffer = 0;
|
||||
return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context,
|
||||
PSecBufferDesc pInput,
|
||||
PSecBufferDesc pOutput)
|
||||
{
|
||||
int status = 0;
|
||||
int ssl_error = 0;
|
||||
PSecBuffer pBuffer = nullptr;
|
||||
|
||||
if (!context->connected)
|
||||
{
|
||||
if (pInput->cBuffers < 1)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
pBuffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
ERR_clear_error();
|
||||
status = BIO_write(context->bioRead, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
|
||||
if (status >= 0)
|
||||
status = SSL_accept(context->ssl);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
ssl_error = SSL_get_error(context->ssl, status);
|
||||
WLog_ERR(TAG, "SSL_accept error: %s", openssl_get_ssl_error_string(ssl_error));
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
if (status == 1)
|
||||
context->connected = TRUE;
|
||||
|
||||
ERR_clear_error();
|
||||
status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
|
||||
if (status < 0)
|
||||
{
|
||||
ssl_error = SSL_get_error(context->ssl, status);
|
||||
WLog_ERR(TAG, "BIO_read: %s", openssl_get_ssl_error_string(ssl_error));
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
if (pOutput->cBuffers < 1)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
pBuffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (status > 0)
|
||||
{
|
||||
if (pBuffer->cbBuffer < WINPR_ASSERTING_INT_CAST(uint32_t, status))
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, status));
|
||||
pBuffer->cbBuffer = WINPR_ASSERTING_INT_CAST(uint32_t, status);
|
||||
return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
pBuffer->cbBuffer = 0;
|
||||
return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
|
||||
{
|
||||
int status = 0;
|
||||
int ssl_error = 0;
|
||||
PSecBuffer pStreamBodyBuffer = nullptr;
|
||||
PSecBuffer pStreamHeaderBuffer = nullptr;
|
||||
PSecBuffer pStreamTrailerBuffer = nullptr;
|
||||
pStreamHeaderBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_HEADER);
|
||||
pStreamBodyBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);
|
||||
pStreamTrailerBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_TRAILER);
|
||||
|
||||
if ((!pStreamHeaderBuffer) || (!pStreamBodyBuffer) || (!pStreamTrailerBuffer))
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
status = SSL_write(context->ssl, pStreamBodyBuffer->pvBuffer,
|
||||
LIMIT_INTMAX(pStreamBodyBuffer->cbBuffer));
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
ssl_error = SSL_get_error(context->ssl, status);
|
||||
WLog_ERR(TAG, "SSL_write: %s", openssl_get_ssl_error_string(ssl_error));
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
|
||||
|
||||
if (status > 0)
|
||||
{
|
||||
size_t ustatus = (size_t)status;
|
||||
size_t length = 0;
|
||||
size_t offset = 0;
|
||||
|
||||
length =
|
||||
(pStreamHeaderBuffer->cbBuffer > ustatus) ? ustatus : pStreamHeaderBuffer->cbBuffer;
|
||||
CopyMemory(pStreamHeaderBuffer->pvBuffer, &context->ReadBuffer[offset], length);
|
||||
ustatus -= length;
|
||||
offset += length;
|
||||
length = (pStreamBodyBuffer->cbBuffer > ustatus) ? ustatus : pStreamBodyBuffer->cbBuffer;
|
||||
CopyMemory(pStreamBodyBuffer->pvBuffer, &context->ReadBuffer[offset], length);
|
||||
ustatus -= length;
|
||||
offset += length;
|
||||
length =
|
||||
(pStreamTrailerBuffer->cbBuffer > ustatus) ? ustatus : pStreamTrailerBuffer->cbBuffer;
|
||||
CopyMemory(pStreamTrailerBuffer->pvBuffer, &context->ReadBuffer[offset], length);
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
|
||||
{
|
||||
int status = 0;
|
||||
int length = 0;
|
||||
BYTE* buffer = nullptr;
|
||||
int ssl_error = 0;
|
||||
PSecBuffer pBuffer = nullptr;
|
||||
pBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
ERR_clear_error();
|
||||
status = BIO_write(context->bioRead, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
|
||||
if (status > 0)
|
||||
status = SSL_read(context->ssl, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
ssl_error = SSL_get_error(context->ssl, status);
|
||||
WLog_ERR(TAG, "SSL_read: %s", openssl_get_ssl_error_string(ssl_error));
|
||||
}
|
||||
|
||||
length = status;
|
||||
buffer = pBuffer->pvBuffer;
|
||||
pMessage->pBuffers[0].BufferType = SECBUFFER_STREAM_HEADER;
|
||||
pMessage->pBuffers[0].cbBuffer = 5;
|
||||
pMessage->pBuffers[1].BufferType = SECBUFFER_DATA;
|
||||
pMessage->pBuffers[1].pvBuffer = buffer;
|
||||
pMessage->pBuffers[1].cbBuffer = WINPR_ASSERTING_INT_CAST(uint32_t, length);
|
||||
pMessage->pBuffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
|
||||
pMessage->pBuffers[2].cbBuffer = 36;
|
||||
pMessage->pBuffers[3].BufferType = SECBUFFER_EMPTY;
|
||||
pMessage->pBuffers[3].cbBuffer = 0;
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SCHANNEL_OPENSSL* schannel_openssl_new(void)
|
||||
{
|
||||
SCHANNEL_OPENSSL* context = nullptr;
|
||||
context = (SCHANNEL_OPENSSL*)calloc(1, sizeof(SCHANNEL_OPENSSL));
|
||||
|
||||
if (context != nullptr)
|
||||
{
|
||||
winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
|
||||
context->connected = FALSE;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void schannel_openssl_free(SCHANNEL_OPENSSL* context)
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
free(context->ReadBuffer);
|
||||
free(context->WriteBuffer);
|
||||
free(context);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int schannel_openssl_client_init(SCHANNEL_OPENSSL* context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int schannel_openssl_server_init(SCHANNEL_OPENSSL* context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context,
|
||||
PSecBufferDesc pInput,
|
||||
PSecBufferDesc pOutput)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context,
|
||||
PSecBufferDesc pInput,
|
||||
PSecBufferDesc pOutput)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SCHANNEL_OPENSSL* schannel_openssl_new(void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void schannel_openssl_free(SCHANNEL_OPENSSL* context)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
53
third_party/FreeRDP/winpr/libwinpr/sspi/Schannel/schannel_openssl.h
vendored
Normal file
53
third_party/FreeRDP/winpr/libwinpr/sspi/Schannel/schannel_openssl.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Schannel Security Package (OpenSSL)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_SCHANNEL_OPENSSL_H
|
||||
#define WINPR_SSPI_SCHANNEL_OPENSSL_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#include "../sspi.h"
|
||||
|
||||
/* OpenSSL includes windows.h */
|
||||
#include <winpr/windows.h>
|
||||
|
||||
typedef struct S_SCHANNEL_OPENSSL SCHANNEL_OPENSSL;
|
||||
|
||||
int schannel_openssl_client_init(SCHANNEL_OPENSSL* context);
|
||||
int schannel_openssl_server_init(SCHANNEL_OPENSSL* context);
|
||||
|
||||
SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context,
|
||||
PSecBufferDesc pInput,
|
||||
PSecBufferDesc pOutput);
|
||||
SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context,
|
||||
PSecBufferDesc pInput,
|
||||
PSecBufferDesc pOutput);
|
||||
|
||||
SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context,
|
||||
PSecBufferDesc pMessage);
|
||||
SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context,
|
||||
PSecBufferDesc pMessage);
|
||||
|
||||
void schannel_openssl_free(SCHANNEL_OPENSSL* context);
|
||||
|
||||
WINPR_ATTR_MALLOC(schannel_openssl_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
SCHANNEL_OPENSSL* schannel_openssl_new(void);
|
||||
|
||||
#endif /* WINPR_SSPI_SCHANNEL_OPENSSL_H */
|
||||
990
third_party/FreeRDP/winpr/libwinpr/sspi/sspi.c
vendored
Normal file
990
third_party/FreeRDP/winpr/libwinpr/sspi/sspi.c
vendored
Normal file
@@ -0,0 +1,990 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/platform.h>
|
||||
#include <winpr/config.h>
|
||||
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
|
||||
WINPR_PRAGMA_DIAG_IGNORED_UNUSED_MACRO
|
||||
|
||||
#define _NO_KSECDD_IMPORT_ 1 // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
|
||||
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/library.h>
|
||||
#include <winpr/environment.h>
|
||||
|
||||
#include "sspi.h"
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define IFCALLRESULT(_default_return, _cb, ...) \
|
||||
__extension__({ \
|
||||
if (_cb == nullptr) \
|
||||
{ \
|
||||
WLog_VRB("com.winpr.api", "IFCALLRESULT(" #_cb ") == nullptr"); \
|
||||
} \
|
||||
((_cb != nullptr) ? _cb(__VA_ARGS__) : (_default_return)); \
|
||||
})
|
||||
#else
|
||||
#define IFCALLRESULT(_default_return, _cb, ...) \
|
||||
((_cb != nullptr) ? _cb(__VA_ARGS__) : (_default_return))
|
||||
#endif
|
||||
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISSING_PROTOTYPES
|
||||
|
||||
static wLog* g_Log = nullptr;
|
||||
|
||||
static INIT_ONCE g_Initialized = INIT_ONCE_STATIC_INIT;
|
||||
#if defined(WITH_NATIVE_SSPI)
|
||||
static HMODULE g_SspiModule = nullptr;
|
||||
static SecurityFunctionTableW windows_SecurityFunctionTableW = WINPR_C_ARRAY_INIT;
|
||||
static SecurityFunctionTableA windows_SecurityFunctionTableA = WINPR_C_ARRAY_INIT;
|
||||
#endif
|
||||
|
||||
static SecurityFunctionTableW* g_SspiW = nullptr;
|
||||
static SecurityFunctionTableA* g_SspiA = nullptr;
|
||||
|
||||
#if defined(WITH_NATIVE_SSPI)
|
||||
static BOOL ShouldUseNativeSspi(void);
|
||||
static BOOL InitializeSspiModule_Native(void);
|
||||
#endif
|
||||
|
||||
#if defined(WITH_NATIVE_SSPI)
|
||||
BOOL ShouldUseNativeSspi(void)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
#ifdef _WIN32
|
||||
LPCSTR sspi = "WINPR_NATIVE_SSPI";
|
||||
DWORD nSize;
|
||||
char* env = nullptr;
|
||||
nSize = GetEnvironmentVariableA(sspi, nullptr, 0);
|
||||
|
||||
if (!nSize)
|
||||
return TRUE;
|
||||
|
||||
env = (LPSTR)malloc(nSize);
|
||||
|
||||
if (!env)
|
||||
return TRUE;
|
||||
|
||||
if (GetEnvironmentVariableA(sspi, env, nSize) != nSize - 1)
|
||||
{
|
||||
free(env);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (strcmp(env, "0") == 0)
|
||||
status = FALSE;
|
||||
else
|
||||
status = TRUE;
|
||||
|
||||
free(env);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_NATIVE_SSPI)
|
||||
BOOL InitializeSspiModule_Native(void)
|
||||
{
|
||||
SecurityFunctionTableW* pSspiW = nullptr;
|
||||
SecurityFunctionTableA* pSspiA = nullptr;
|
||||
INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW;
|
||||
INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA;
|
||||
g_SspiModule = LoadLibraryA("secur32.dll");
|
||||
|
||||
if (!g_SspiModule)
|
||||
g_SspiModule = LoadLibraryA("sspicli.dll");
|
||||
|
||||
if (!g_SspiModule)
|
||||
return FALSE;
|
||||
|
||||
pInitSecurityInterfaceW =
|
||||
GetProcAddressAs(g_SspiModule, "InitSecurityInterfaceW", INIT_SECURITY_INTERFACE_W);
|
||||
pInitSecurityInterfaceA =
|
||||
GetProcAddressAs(g_SspiModule, "InitSecurityInterfaceA", INIT_SECURITY_INTERFACE_A);
|
||||
|
||||
if (pInitSecurityInterfaceW)
|
||||
{
|
||||
pSspiW = pInitSecurityInterfaceW();
|
||||
|
||||
if (pSspiW)
|
||||
{
|
||||
g_SspiW = &windows_SecurityFunctionTableW;
|
||||
CopyMemory(g_SspiW, pSspiW,
|
||||
FIELD_OFFSET(SecurityFunctionTableW, SetContextAttributesW));
|
||||
|
||||
g_SspiW->dwVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION_3;
|
||||
|
||||
g_SspiW->SetContextAttributesW = GetProcAddressAs(g_SspiModule, "SetContextAttributesW",
|
||||
SET_CONTEXT_ATTRIBUTES_FN_W);
|
||||
|
||||
g_SspiW->SetCredentialsAttributesW = GetProcAddressAs(
|
||||
g_SspiModule, "SetCredentialsAttributesW", SET_CREDENTIALS_ATTRIBUTES_FN_W);
|
||||
}
|
||||
}
|
||||
|
||||
if (pInitSecurityInterfaceA)
|
||||
{
|
||||
pSspiA = pInitSecurityInterfaceA();
|
||||
|
||||
if (pSspiA)
|
||||
{
|
||||
g_SspiA = &windows_SecurityFunctionTableA;
|
||||
CopyMemory(g_SspiA, pSspiA,
|
||||
FIELD_OFFSET(SecurityFunctionTableA, SetContextAttributesA));
|
||||
|
||||
g_SspiA->dwVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION_3;
|
||||
|
||||
g_SspiA->SetContextAttributesA = GetProcAddressAs(g_SspiModule, "SetContextAttributesA",
|
||||
SET_CONTEXT_ATTRIBUTES_FN_W);
|
||||
|
||||
g_SspiA->SetCredentialsAttributesA = GetProcAddressAs(
|
||||
g_SspiModule, "SetCredentialsAttributesA", SET_CREDENTIALS_ATTRIBUTES_FN_W);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static BOOL CALLBACK InitializeSspiModuleInt(WINPR_ATTR_UNUSED PINIT_ONCE once,
|
||||
WINPR_ATTR_UNUSED PVOID param,
|
||||
WINPR_ATTR_UNUSED PVOID* context)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
#if defined(WITH_NATIVE_SSPI)
|
||||
DWORD flags = 0;
|
||||
|
||||
if (param)
|
||||
flags = *(DWORD*)param;
|
||||
|
||||
#endif
|
||||
sspi_GlobalInit();
|
||||
g_Log = WLog_Get("com.winpr.sspi");
|
||||
#if defined(WITH_NATIVE_SSPI)
|
||||
|
||||
if (flags && (flags & SSPI_INTERFACE_NATIVE))
|
||||
{
|
||||
status = InitializeSspiModule_Native();
|
||||
}
|
||||
else if (flags && (flags & SSPI_INTERFACE_WINPR))
|
||||
{
|
||||
g_SspiW = winpr_InitSecurityInterfaceW();
|
||||
g_SspiA = winpr_InitSecurityInterfaceA();
|
||||
status = TRUE;
|
||||
}
|
||||
|
||||
if (!status && ShouldUseNativeSspi())
|
||||
{
|
||||
status = InitializeSspiModule_Native();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (!status)
|
||||
{
|
||||
g_SspiW = winpr_InitSecurityInterfaceW();
|
||||
g_SspiA = winpr_InitSecurityInterfaceA();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char* GetSecurityStatusString(SECURITY_STATUS status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case SEC_E_OK:
|
||||
return "SEC_E_OK";
|
||||
|
||||
case SEC_E_INSUFFICIENT_MEMORY:
|
||||
return "SEC_E_INSUFFICIENT_MEMORY";
|
||||
|
||||
case SEC_E_INVALID_HANDLE:
|
||||
return "SEC_E_INVALID_HANDLE";
|
||||
|
||||
case SEC_E_UNSUPPORTED_FUNCTION:
|
||||
return "SEC_E_UNSUPPORTED_FUNCTION";
|
||||
|
||||
case SEC_E_TARGET_UNKNOWN:
|
||||
return "SEC_E_TARGET_UNKNOWN";
|
||||
|
||||
case SEC_E_INTERNAL_ERROR:
|
||||
return "SEC_E_INTERNAL_ERROR";
|
||||
|
||||
case SEC_E_SECPKG_NOT_FOUND:
|
||||
return "SEC_E_SECPKG_NOT_FOUND";
|
||||
|
||||
case SEC_E_NOT_OWNER:
|
||||
return "SEC_E_NOT_OWNER";
|
||||
|
||||
case SEC_E_CANNOT_INSTALL:
|
||||
return "SEC_E_CANNOT_INSTALL";
|
||||
|
||||
case SEC_E_INVALID_TOKEN:
|
||||
return "SEC_E_INVALID_TOKEN";
|
||||
|
||||
case SEC_E_CANNOT_PACK:
|
||||
return "SEC_E_CANNOT_PACK";
|
||||
|
||||
case SEC_E_QOP_NOT_SUPPORTED:
|
||||
return "SEC_E_QOP_NOT_SUPPORTED";
|
||||
|
||||
case SEC_E_NO_IMPERSONATION:
|
||||
return "SEC_E_NO_IMPERSONATION";
|
||||
|
||||
case SEC_E_LOGON_DENIED:
|
||||
return "SEC_E_LOGON_DENIED";
|
||||
|
||||
case SEC_E_UNKNOWN_CREDENTIALS:
|
||||
return "SEC_E_UNKNOWN_CREDENTIALS";
|
||||
|
||||
case SEC_E_NO_CREDENTIALS:
|
||||
return "SEC_E_NO_CREDENTIALS";
|
||||
|
||||
case SEC_E_MESSAGE_ALTERED:
|
||||
return "SEC_E_MESSAGE_ALTERED";
|
||||
|
||||
case SEC_E_OUT_OF_SEQUENCE:
|
||||
return "SEC_E_OUT_OF_SEQUENCE";
|
||||
|
||||
case SEC_E_NO_AUTHENTICATING_AUTHORITY:
|
||||
return "SEC_E_NO_AUTHENTICATING_AUTHORITY";
|
||||
|
||||
case SEC_E_BAD_PKGID:
|
||||
return "SEC_E_BAD_PKGID";
|
||||
|
||||
case SEC_E_CONTEXT_EXPIRED:
|
||||
return "SEC_E_CONTEXT_EXPIRED";
|
||||
|
||||
case SEC_E_INCOMPLETE_MESSAGE:
|
||||
return "SEC_E_INCOMPLETE_MESSAGE";
|
||||
|
||||
case SEC_E_INCOMPLETE_CREDENTIALS:
|
||||
return "SEC_E_INCOMPLETE_CREDENTIALS";
|
||||
|
||||
case SEC_E_BUFFER_TOO_SMALL:
|
||||
return "SEC_E_BUFFER_TOO_SMALL";
|
||||
|
||||
case SEC_E_WRONG_PRINCIPAL:
|
||||
return "SEC_E_WRONG_PRINCIPAL";
|
||||
|
||||
case SEC_E_TIME_SKEW:
|
||||
return "SEC_E_TIME_SKEW";
|
||||
|
||||
case SEC_E_UNTRUSTED_ROOT:
|
||||
return "SEC_E_UNTRUSTED_ROOT";
|
||||
|
||||
case SEC_E_ILLEGAL_MESSAGE:
|
||||
return "SEC_E_ILLEGAL_MESSAGE";
|
||||
|
||||
case SEC_E_CERT_UNKNOWN:
|
||||
return "SEC_E_CERT_UNKNOWN";
|
||||
|
||||
case SEC_E_CERT_EXPIRED:
|
||||
return "SEC_E_CERT_EXPIRED";
|
||||
|
||||
case SEC_E_ENCRYPT_FAILURE:
|
||||
return "SEC_E_ENCRYPT_FAILURE";
|
||||
|
||||
case SEC_E_DECRYPT_FAILURE:
|
||||
return "SEC_E_DECRYPT_FAILURE";
|
||||
|
||||
case SEC_E_ALGORITHM_MISMATCH:
|
||||
return "SEC_E_ALGORITHM_MISMATCH";
|
||||
|
||||
case SEC_E_SECURITY_QOS_FAILED:
|
||||
return "SEC_E_SECURITY_QOS_FAILED";
|
||||
|
||||
case SEC_E_UNFINISHED_CONTEXT_DELETED:
|
||||
return "SEC_E_UNFINISHED_CONTEXT_DELETED";
|
||||
|
||||
case SEC_E_NO_TGT_REPLY:
|
||||
return "SEC_E_NO_TGT_REPLY";
|
||||
|
||||
case SEC_E_NO_IP_ADDRESSES:
|
||||
return "SEC_E_NO_IP_ADDRESSES";
|
||||
|
||||
case SEC_E_WRONG_CREDENTIAL_HANDLE:
|
||||
return "SEC_E_WRONG_CREDENTIAL_HANDLE";
|
||||
|
||||
case SEC_E_CRYPTO_SYSTEM_INVALID:
|
||||
return "SEC_E_CRYPTO_SYSTEM_INVALID";
|
||||
|
||||
case SEC_E_MAX_REFERRALS_EXCEEDED:
|
||||
return "SEC_E_MAX_REFERRALS_EXCEEDED";
|
||||
|
||||
case SEC_E_MUST_BE_KDC:
|
||||
return "SEC_E_MUST_BE_KDC";
|
||||
|
||||
case SEC_E_STRONG_CRYPTO_NOT_SUPPORTED:
|
||||
return "SEC_E_STRONG_CRYPTO_NOT_SUPPORTED";
|
||||
|
||||
case SEC_E_TOO_MANY_PRINCIPALS:
|
||||
return "SEC_E_TOO_MANY_PRINCIPALS";
|
||||
|
||||
case SEC_E_NO_PA_DATA:
|
||||
return "SEC_E_NO_PA_DATA";
|
||||
|
||||
case SEC_E_PKINIT_NAME_MISMATCH:
|
||||
return "SEC_E_PKINIT_NAME_MISMATCH";
|
||||
|
||||
case SEC_E_SMARTCARD_LOGON_REQUIRED:
|
||||
return "SEC_E_SMARTCARD_LOGON_REQUIRED";
|
||||
|
||||
case SEC_E_SHUTDOWN_IN_PROGRESS:
|
||||
return "SEC_E_SHUTDOWN_IN_PROGRESS";
|
||||
|
||||
case SEC_E_KDC_INVALID_REQUEST:
|
||||
return "SEC_E_KDC_INVALID_REQUEST";
|
||||
|
||||
case SEC_E_KDC_UNABLE_TO_REFER:
|
||||
return "SEC_E_KDC_UNABLE_TO_REFER";
|
||||
|
||||
case SEC_E_KDC_UNKNOWN_ETYPE:
|
||||
return "SEC_E_KDC_UNKNOWN_ETYPE";
|
||||
|
||||
case SEC_E_UNSUPPORTED_PREAUTH:
|
||||
return "SEC_E_UNSUPPORTED_PREAUTH";
|
||||
|
||||
case SEC_E_DELEGATION_REQUIRED:
|
||||
return "SEC_E_DELEGATION_REQUIRED";
|
||||
|
||||
case SEC_E_BAD_BINDINGS:
|
||||
return "SEC_E_BAD_BINDINGS";
|
||||
|
||||
case SEC_E_MULTIPLE_ACCOUNTS:
|
||||
return "SEC_E_MULTIPLE_ACCOUNTS";
|
||||
|
||||
case SEC_E_NO_KERB_KEY:
|
||||
return "SEC_E_NO_KERB_KEY";
|
||||
|
||||
case SEC_E_CERT_WRONG_USAGE:
|
||||
return "SEC_E_CERT_WRONG_USAGE";
|
||||
|
||||
case SEC_E_DOWNGRADE_DETECTED:
|
||||
return "SEC_E_DOWNGRADE_DETECTED";
|
||||
|
||||
case SEC_E_SMARTCARD_CERT_REVOKED:
|
||||
return "SEC_E_SMARTCARD_CERT_REVOKED";
|
||||
|
||||
case SEC_E_ISSUING_CA_UNTRUSTED:
|
||||
return "SEC_E_ISSUING_CA_UNTRUSTED";
|
||||
|
||||
case SEC_E_REVOCATION_OFFLINE_C:
|
||||
return "SEC_E_REVOCATION_OFFLINE_C";
|
||||
|
||||
case SEC_E_PKINIT_CLIENT_FAILURE:
|
||||
return "SEC_E_PKINIT_CLIENT_FAILURE";
|
||||
|
||||
case SEC_E_SMARTCARD_CERT_EXPIRED:
|
||||
return "SEC_E_SMARTCARD_CERT_EXPIRED";
|
||||
|
||||
case SEC_E_NO_S4U_PROT_SUPPORT:
|
||||
return "SEC_E_NO_S4U_PROT_SUPPORT";
|
||||
|
||||
case SEC_E_CROSSREALM_DELEGATION_FAILURE:
|
||||
return "SEC_E_CROSSREALM_DELEGATION_FAILURE";
|
||||
|
||||
case SEC_E_REVOCATION_OFFLINE_KDC:
|
||||
return "SEC_E_REVOCATION_OFFLINE_KDC";
|
||||
|
||||
case SEC_E_ISSUING_CA_UNTRUSTED_KDC:
|
||||
return "SEC_E_ISSUING_CA_UNTRUSTED_KDC";
|
||||
|
||||
case SEC_E_KDC_CERT_EXPIRED:
|
||||
return "SEC_E_KDC_CERT_EXPIRED";
|
||||
|
||||
case SEC_E_KDC_CERT_REVOKED:
|
||||
return "SEC_E_KDC_CERT_REVOKED";
|
||||
|
||||
case SEC_E_INVALID_PARAMETER:
|
||||
return "SEC_E_INVALID_PARAMETER";
|
||||
|
||||
case SEC_E_DELEGATION_POLICY:
|
||||
return "SEC_E_DELEGATION_POLICY";
|
||||
|
||||
case SEC_E_POLICY_NLTM_ONLY:
|
||||
return "SEC_E_POLICY_NLTM_ONLY";
|
||||
|
||||
case SEC_E_NO_CONTEXT:
|
||||
return "SEC_E_NO_CONTEXT";
|
||||
|
||||
case SEC_E_PKU2U_CERT_FAILURE:
|
||||
return "SEC_E_PKU2U_CERT_FAILURE";
|
||||
|
||||
case SEC_E_MUTUAL_AUTH_FAILED:
|
||||
return "SEC_E_MUTUAL_AUTH_FAILED";
|
||||
|
||||
case SEC_I_CONTINUE_NEEDED:
|
||||
return "SEC_I_CONTINUE_NEEDED";
|
||||
|
||||
case SEC_I_COMPLETE_NEEDED:
|
||||
return "SEC_I_COMPLETE_NEEDED";
|
||||
|
||||
case SEC_I_COMPLETE_AND_CONTINUE:
|
||||
return "SEC_I_COMPLETE_AND_CONTINUE";
|
||||
|
||||
case SEC_I_LOCAL_LOGON:
|
||||
return "SEC_I_LOCAL_LOGON";
|
||||
|
||||
case SEC_I_CONTEXT_EXPIRED:
|
||||
return "SEC_I_CONTEXT_EXPIRED";
|
||||
|
||||
case SEC_I_INCOMPLETE_CREDENTIALS:
|
||||
return "SEC_I_INCOMPLETE_CREDENTIALS";
|
||||
|
||||
case SEC_I_RENEGOTIATE:
|
||||
return "SEC_I_RENEGOTIATE";
|
||||
|
||||
case SEC_I_NO_LSA_CONTEXT:
|
||||
return "SEC_I_NO_LSA_CONTEXT";
|
||||
|
||||
case SEC_I_SIGNATURE_NEEDED:
|
||||
return "SEC_I_SIGNATURE_NEEDED";
|
||||
|
||||
case SEC_I_NO_RENEGOTIATION:
|
||||
return "SEC_I_NO_RENEGOTIATION";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NtStatus2Tag(status);
|
||||
}
|
||||
|
||||
BOOL IsSecurityStatusError(SECURITY_STATUS status)
|
||||
{
|
||||
BOOL error = TRUE;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case SEC_E_OK:
|
||||
case SEC_I_CONTINUE_NEEDED:
|
||||
case SEC_I_COMPLETE_NEEDED:
|
||||
case SEC_I_COMPLETE_AND_CONTINUE:
|
||||
case SEC_I_LOCAL_LOGON:
|
||||
case SEC_I_CONTEXT_EXPIRED:
|
||||
case SEC_I_INCOMPLETE_CREDENTIALS:
|
||||
case SEC_I_RENEGOTIATE:
|
||||
case SEC_I_NO_LSA_CONTEXT:
|
||||
case SEC_I_SIGNATURE_NEEDED:
|
||||
case SEC_I_NO_RENEGOTIATION:
|
||||
error = FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
SecurityFunctionTableW* SEC_ENTRY InitSecurityInterfaceExW(DWORD flags)
|
||||
{
|
||||
if (!InitOnceExecuteOnce(&g_Initialized, InitializeSspiModuleInt, &flags, nullptr))
|
||||
return nullptr;
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "InitSecurityInterfaceExW");
|
||||
return g_SspiW;
|
||||
}
|
||||
|
||||
SecurityFunctionTableA* SEC_ENTRY InitSecurityInterfaceExA(DWORD flags)
|
||||
{
|
||||
if (!InitOnceExecuteOnce(&g_Initialized, InitializeSspiModuleInt, &flags, nullptr))
|
||||
return nullptr;
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "InitSecurityInterfaceExA");
|
||||
return g_SspiA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard SSPI API
|
||||
*/
|
||||
|
||||
static SECURITY_STATUS sspi_init(void)
|
||||
{
|
||||
if (!InitOnceExecuteOnce(&g_Initialized, InitializeSspiModuleInt, nullptr, nullptr))
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
if (!g_SspiA || !g_SspiW)
|
||||
{
|
||||
WLog_Print(g_Log, WLOG_WARN, "Security module does not provide an implementation");
|
||||
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
return SEC_E_OK;
|
||||
}
|
||||
/* Package Management */
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesW(ULONG* pcPackages,
|
||||
PSecPkgInfoW* ppPackageInfo)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
|
||||
status = g_SspiW->EnumerateSecurityPackagesW(pcPackages, ppPackageInfo);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "EnumerateSecurityPackagesW: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesA(ULONG* pcPackages,
|
||||
PSecPkgInfoA* ppPackageInfo)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiA->EnumerateSecurityPackagesA,
|
||||
pcPackages, ppPackageInfo);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "EnumerateSecurityPackagesA: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SecurityFunctionTableW* SEC_ENTRY sspi_InitSecurityInterfaceW(void)
|
||||
{
|
||||
if (!InitOnceExecuteOnce(&g_Initialized, InitializeSspiModuleInt, nullptr, nullptr))
|
||||
return nullptr;
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "InitSecurityInterfaceW");
|
||||
return g_SspiW;
|
||||
}
|
||||
|
||||
SecurityFunctionTableA* SEC_ENTRY sspi_InitSecurityInterfaceA(void)
|
||||
{
|
||||
if (!InitOnceExecuteOnce(&g_Initialized, InitializeSspiModuleInt, nullptr, nullptr))
|
||||
return nullptr;
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "InitSecurityInterfaceA");
|
||||
return g_SspiA;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoW(SEC_WCHAR* pszPackageName,
|
||||
PSecPkgInfoW* ppPackageInfo)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->QuerySecurityPackageInfoW,
|
||||
pszPackageName, ppPackageInfo);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "QuerySecurityPackageInfoW: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoA(SEC_CHAR* pszPackageName,
|
||||
PSecPkgInfoA* ppPackageInfo)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiA->QuerySecurityPackageInfoA,
|
||||
pszPackageName, ppPackageInfo);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "QuerySecurityPackageInfoA: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Credential Management */
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleW(
|
||||
SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
|
||||
void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
|
||||
PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->AcquireCredentialsHandleW,
|
||||
pszPrincipal, pszPackage, fCredentialUse, pvLogonID, pAuthData, pGetKeyFn,
|
||||
pvGetKeyArgument, phCredential, ptsExpiry);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "AcquireCredentialsHandleW: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleA(
|
||||
SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
|
||||
void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
|
||||
PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiA->AcquireCredentialsHandleA,
|
||||
pszPrincipal, pszPackage, fCredentialUse, pvLogonID, pAuthData, pGetKeyFn,
|
||||
pvGetKeyArgument, phCredential, ptsExpiry);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "AcquireCredentialsHandleA: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_ExportSecurityContext(PCtxtHandle phContext, ULONG fFlags,
|
||||
PSecBuffer pPackedContext, HANDLE* pToken)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->ExportSecurityContext, phContext,
|
||||
fFlags, pPackedContext, pToken);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "ExportSecurityContext: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_FreeCredentialsHandle(PCredHandle phCredential)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->FreeCredentialsHandle, phCredential);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "FreeCredentialsHandle: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextW(SEC_WCHAR* pszPackage,
|
||||
PSecBuffer pPackedContext, HANDLE pToken,
|
||||
PCtxtHandle phContext)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->ImportSecurityContextW, pszPackage,
|
||||
pPackedContext, pToken, phContext);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "ImportSecurityContextW: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextA(SEC_CHAR* pszPackage,
|
||||
PSecBuffer pPackedContext, HANDLE pToken,
|
||||
PCtxtHandle phContext)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiA->ImportSecurityContextA, pszPackage,
|
||||
pPackedContext, pToken, phContext);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "ImportSecurityContextA: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesW(PCredHandle phCredential,
|
||||
ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->QueryCredentialsAttributesW,
|
||||
phCredential, ulAttribute, pBuffer);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "QueryCredentialsAttributesW: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesA(PCredHandle phCredential,
|
||||
ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiA->QueryCredentialsAttributesA,
|
||||
phCredential, ulAttribute, pBuffer);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "QueryCredentialsAttributesA: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Context Management */
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_AcceptSecurityContext(PCredHandle phCredential,
|
||||
PCtxtHandle phContext, PSecBufferDesc pInput,
|
||||
ULONG fContextReq, ULONG TargetDataRep,
|
||||
PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr,
|
||||
PTimeStamp ptsTimeStamp)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->AcceptSecurityContext, phCredential,
|
||||
phContext, pInput, fContextReq, TargetDataRep, phNewContext, pOutput,
|
||||
pfContextAttr, ptsTimeStamp);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "AcceptSecurityContext: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_ApplyControlToken(PCtxtHandle phContext, PSecBufferDesc pInput)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status =
|
||||
IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->ApplyControlToken, phContext, pInput);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "ApplyControlToken: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_CompleteAuthToken(PCtxtHandle phContext, PSecBufferDesc pToken)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status =
|
||||
IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->CompleteAuthToken, phContext, pToken);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "CompleteAuthToken: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_DeleteSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->DeleteSecurityContext, phContext);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "DeleteSecurityContext: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_FreeContextBuffer(void* pvContextBuffer)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->FreeContextBuffer, pvContextBuffer);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "FreeContextBuffer: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_ImpersonateSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status =
|
||||
IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->ImpersonateSecurityContext, phContext);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "ImpersonateSecurityContext: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextW(
|
||||
PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR* pszTargetName, ULONG fContextReq,
|
||||
ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
|
||||
PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status =
|
||||
IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->InitializeSecurityContextW, phCredential,
|
||||
phContext, pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput,
|
||||
Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "InitializeSecurityContextW: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextA(
|
||||
PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, ULONG fContextReq,
|
||||
ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
|
||||
PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status =
|
||||
IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiA->InitializeSecurityContextA, phCredential,
|
||||
phContext, pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput,
|
||||
Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "InitializeSecurityContextA: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute,
|
||||
void* pBuffer)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->QueryContextAttributesW, phContext,
|
||||
ulAttribute, pBuffer);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "QueryContextAttributesW: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute,
|
||||
void* pBuffer)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiA->QueryContextAttributesA, phContext,
|
||||
ulAttribute, pBuffer);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "QueryContextAttributesA: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityContextToken(PCtxtHandle phContext, HANDLE* phToken)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->QuerySecurityContextToken, phContext,
|
||||
phToken);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "QuerySecurityContextToken: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute,
|
||||
void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->SetContextAttributesW, phContext,
|
||||
ulAttribute, pBuffer, cbBuffer);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "SetContextAttributesW: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute,
|
||||
void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiA->SetContextAttributesA, phContext,
|
||||
ulAttribute, pBuffer, cbBuffer);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "SetContextAttributesA: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_RevertSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->RevertSecurityContext, phContext);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "RevertSecurityContext: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Message Support */
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage,
|
||||
ULONG MessageSeqNo, PULONG pfQOP)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->DecryptMessage, phContext, pMessage,
|
||||
MessageSeqNo, pfQOP);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "DecryptMessage: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
|
||||
PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->EncryptMessage, phContext, fQOP,
|
||||
pMessage, MessageSeqNo);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "EncryptMessage: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
|
||||
PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->MakeSignature, phContext, fQOP,
|
||||
pMessage, MessageSeqNo);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "MakeSignature: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY sspi_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage,
|
||||
ULONG MessageSeqNo, PULONG pfQOP)
|
||||
{
|
||||
SECURITY_STATUS status = sspi_init();
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
status = IFCALLRESULT(SEC_E_UNSUPPORTED_FUNCTION, g_SspiW->VerifySignature, phContext, pMessage,
|
||||
MessageSeqNo, pfQOP);
|
||||
WLog_Print(g_Log, WLOG_DEBUG, "VerifySignature: %s (0x%08" PRIX32 ")",
|
||||
GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
|
||||
return status;
|
||||
}
|
||||
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
|
||||
static void zfree(WCHAR* str, size_t len, BOOL isWCHAR)
|
||||
{
|
||||
if (str)
|
||||
memset(str, 0, len * (isWCHAR ? sizeof(WCHAR) : sizeof(char)));
|
||||
free(str);
|
||||
}
|
||||
|
||||
void sspi_FreeAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity)
|
||||
{
|
||||
if (!identity)
|
||||
return;
|
||||
|
||||
const BOOL wc = (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0;
|
||||
zfree(identity->User, identity->UserLength, wc);
|
||||
zfree(identity->Domain, identity->DomainLength, wc);
|
||||
|
||||
/* identity->PasswordLength does have a dual use. In Pass The Hash (PTH) mode the maximum
|
||||
* password length (512) is added to the real length to mark this as a hash. when we free up
|
||||
* this field without removing these additional bytes we would corrupt the stack.
|
||||
*/
|
||||
size_t len = identity->PasswordLength;
|
||||
if (len > SSPI_CREDENTIALS_HASH_LENGTH_OFFSET)
|
||||
len -= SSPI_CREDENTIALS_HASH_LENGTH_OFFSET;
|
||||
zfree(identity->Password, len, wc);
|
||||
|
||||
const SEC_WINNT_AUTH_IDENTITY empty = WINPR_C_ARRAY_INIT;
|
||||
*identity = empty;
|
||||
}
|
||||
93
third_party/FreeRDP/winpr/libwinpr/sspi/sspi.h
vendored
Normal file
93
third_party/FreeRDP/winpr/libwinpr/sspi/sspi.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_PRIVATE_H
|
||||
#define WINPR_SSPI_PRIVATE_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#define SCHANNEL_CB_MAX_TOKEN 0x00006000
|
||||
|
||||
#define SSPI_CREDENTIALS_PASSWORD_HASH 0x00000001
|
||||
|
||||
#define SSPI_CREDENTIALS_HASH_LENGTH_OFFSET 512
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD flags;
|
||||
ULONG fCredentialUse;
|
||||
SEC_GET_KEY_FN pGetKeyFn;
|
||||
void* pvGetKeyArgument;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
SEC_WINPR_NTLM_SETTINGS ntlmSettings;
|
||||
SEC_WINPR_KERBEROS_SETTINGS kerbSettings;
|
||||
} SSPI_CREDENTIALS;
|
||||
|
||||
SSPI_CREDENTIALS* sspi_CredentialsNew(void);
|
||||
void sspi_CredentialsFree(SSPI_CREDENTIALS* credentials);
|
||||
|
||||
PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType);
|
||||
|
||||
SecHandle* sspi_SecureHandleAlloc(void);
|
||||
void sspi_SecureHandleInvalidate(SecHandle* handle);
|
||||
void* sspi_SecureHandleGetLowerPointer(SecHandle* handle);
|
||||
void sspi_SecureHandleSetLowerPointer(SecHandle* handle, void* pointer);
|
||||
void* sspi_SecureHandleGetUpperPointer(SecHandle* handle);
|
||||
void sspi_SecureHandleSetUpperPointer(SecHandle* handle, void* pointer);
|
||||
void sspi_SecureHandleFree(SecHandle* handle);
|
||||
|
||||
enum SecurityFunctionTableIndex
|
||||
{
|
||||
EnumerateSecurityPackagesIndex = 1,
|
||||
Reserved1Index = 2,
|
||||
QueryCredentialsAttributesIndex = 3,
|
||||
AcquireCredentialsHandleIndex = 4,
|
||||
FreeCredentialsHandleIndex = 5,
|
||||
Reserved2Index = 6,
|
||||
InitializeSecurityContextIndex = 7,
|
||||
AcceptSecurityContextIndex = 8,
|
||||
CompleteAuthTokenIndex = 9,
|
||||
DeleteSecurityContextIndex = 10,
|
||||
ApplyControlTokenIndex = 11,
|
||||
QueryContextAttributesIndex = 12,
|
||||
ImpersonateSecurityContextIndex = 13,
|
||||
RevertSecurityContextIndex = 14,
|
||||
MakeSignatureIndex = 15,
|
||||
VerifySignatureIndex = 16,
|
||||
FreeContextBufferIndex = 17,
|
||||
QuerySecurityPackageInfoIndex = 18,
|
||||
Reserved3Index = 19,
|
||||
Reserved4Index = 20,
|
||||
ExportSecurityContextIndex = 21,
|
||||
ImportSecurityContextIndex = 22,
|
||||
AddCredentialsIndex = 23,
|
||||
Reserved8Index = 24,
|
||||
QuerySecurityContextTokenIndex = 25,
|
||||
EncryptMessageIndex = 26,
|
||||
DecryptMessageIndex = 27,
|
||||
SetContextAttributesIndex = 28,
|
||||
SetCredentialsAttributesIndex = 29
|
||||
};
|
||||
|
||||
BOOL IsSecurityStatusError(SECURITY_STATUS status);
|
||||
|
||||
#include "sspi_gss.h"
|
||||
#include "sspi_winpr.h"
|
||||
|
||||
#endif /* WINPR_SSPI_PRIVATE_H */
|
||||
347
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_export.c
vendored
Normal file
347
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_export.c
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/platform.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/config.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SEC_ENTRY __stdcall
|
||||
#define SSPI_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#include <winpr/winpr.h>
|
||||
#if defined(SSPI_DLL)
|
||||
#define SEC_ENTRY
|
||||
#define SSPI_EXPORT WINPR_API
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef long LONG;
|
||||
typedef unsigned long ULONG;
|
||||
#endif
|
||||
typedef LONG SECURITY_STATUS;
|
||||
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISSING_PROTOTYPES
|
||||
|
||||
#ifdef SSPI_DLL
|
||||
|
||||
/**
|
||||
* Standard SSPI API
|
||||
*/
|
||||
|
||||
/* Package Management */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesW(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesW(void* pcPackages,
|
||||
void* ppPackageInfo)
|
||||
{
|
||||
return sspi_EnumerateSecurityPackagesW(pcPackages, ppPackageInfo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesA(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesA(void* pcPackages,
|
||||
void* ppPackageInfo)
|
||||
{
|
||||
return sspi_EnumerateSecurityPackagesA(pcPackages, ppPackageInfo);
|
||||
}
|
||||
|
||||
extern void* SEC_ENTRY sspi_InitSecurityInterfaceW(void);
|
||||
|
||||
SSPI_EXPORT void* SEC_ENTRY InitSecurityInterfaceW(void)
|
||||
{
|
||||
return sspi_InitSecurityInterfaceW();
|
||||
}
|
||||
|
||||
extern void* SEC_ENTRY sspi_InitSecurityInterfaceA(void);
|
||||
|
||||
SSPI_EXPORT void* SEC_ENTRY InitSecurityInterfaceA(void)
|
||||
{
|
||||
return sspi_InitSecurityInterfaceA();
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoW(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QuerySecurityPackageInfoW(void* pszPackageName,
|
||||
void* ppPackageInfo)
|
||||
{
|
||||
return sspi_QuerySecurityPackageInfoW(pszPackageName, ppPackageInfo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoA(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QuerySecurityPackageInfoA(void* pszPackageName,
|
||||
void* ppPackageInfo)
|
||||
{
|
||||
return sspi_QuerySecurityPackageInfoA(pszPackageName, ppPackageInfo);
|
||||
}
|
||||
|
||||
/* Credential Management */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleW(void*, void*, ULONG, void*, void*,
|
||||
void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY AcquireCredentialsHandleW(
|
||||
void* pszPrincipal, void* pszPackage, ULONG fCredentialUse, void* pvLogonID, void* pAuthData,
|
||||
void* pGetKeyFn, void* pvGetKeyArgument, void* phCredential, void* ptsExpiry)
|
||||
{
|
||||
return sspi_AcquireCredentialsHandleW(pszPrincipal, pszPackage, fCredentialUse, pvLogonID,
|
||||
pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential,
|
||||
ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleA(void*, void*, ULONG, void*, void*,
|
||||
void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY AcquireCredentialsHandleA(
|
||||
void* pszPrincipal, void* pszPackage, ULONG fCredentialUse, void* pvLogonID, void* pAuthData,
|
||||
void* pGetKeyFn, void* pvGetKeyArgument, void* phCredential, void* ptsExpiry)
|
||||
{
|
||||
return sspi_AcquireCredentialsHandleA(pszPrincipal, pszPackage, fCredentialUse, pvLogonID,
|
||||
pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential,
|
||||
ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ExportSecurityContext(void*, ULONG, void*, void**);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ExportSecurityContext(void* phContext, ULONG fFlags,
|
||||
void* pPackedContext, void** pToken)
|
||||
{
|
||||
return sspi_ExportSecurityContext(phContext, fFlags, pPackedContext, pToken);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_FreeCredentialsHandle(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY FreeCredentialsHandle(void* phCredential)
|
||||
{
|
||||
return sspi_FreeCredentialsHandle(phCredential);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextW(void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ImportSecurityContextW(void* pszPackage, void* pPackedContext,
|
||||
void* pToken, void* phContext)
|
||||
{
|
||||
return sspi_ImportSecurityContextW(pszPackage, pPackedContext, pToken, phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextA(void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ImportSecurityContextA(void* pszPackage, void* pPackedContext,
|
||||
void* pToken, void* phContext)
|
||||
{
|
||||
return sspi_ImportSecurityContextA(pszPackage, pPackedContext, pToken, phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesW(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryCredentialsAttributesW(void* phCredential,
|
||||
ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesA(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryCredentialsAttributesA(void* phCredential,
|
||||
ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryCredentialsAttributesA(phCredential, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
/* Context Management */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_AcceptSecurityContext(void*, void*, void*, ULONG, ULONG,
|
||||
void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY AcceptSecurityContext(void* phCredential, void* phContext,
|
||||
void* pInput, ULONG fContextReq,
|
||||
ULONG TargetDataRep, void* phNewContext,
|
||||
void* pOutput, void* pfContextAttr,
|
||||
void* ptsTimeStamp)
|
||||
{
|
||||
return sspi_AcceptSecurityContext(phCredential, phContext, pInput, fContextReq, TargetDataRep,
|
||||
phNewContext, pOutput, pfContextAttr, ptsTimeStamp);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ApplyControlToken(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ApplyControlToken(void* phContext, void* pInput)
|
||||
{
|
||||
return sspi_ApplyControlToken(phContext, pInput);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_CompleteAuthToken(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY CompleteAuthToken(void* phContext, void* pToken)
|
||||
{
|
||||
return sspi_CompleteAuthToken(phContext, pToken);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_DeleteSecurityContext(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY DeleteSecurityContext(void* phContext)
|
||||
{
|
||||
return sspi_DeleteSecurityContext(phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_FreeContextBuffer(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY FreeContextBuffer(void* pvContextBuffer)
|
||||
{
|
||||
return sspi_FreeContextBuffer(pvContextBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ImpersonateSecurityContext(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ImpersonateSecurityContext(void* phContext)
|
||||
{
|
||||
return sspi_ImpersonateSecurityContext(phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextW(void*, void*, void*, ULONG, ULONG,
|
||||
ULONG, void*, ULONG, void*, void*,
|
||||
void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY InitializeSecurityContextW(
|
||||
void* phCredential, void* phContext, void* pszTargetName, ULONG fContextReq, ULONG Reserved1,
|
||||
ULONG TargetDataRep, void* pInput, ULONG Reserved2, void* phNewContext, void* pOutput,
|
||||
void* pfContextAttr, void* ptsExpiry)
|
||||
{
|
||||
return sspi_InitializeSecurityContextW(phCredential, phContext, pszTargetName, fContextReq,
|
||||
Reserved1, TargetDataRep, pInput, Reserved2,
|
||||
phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextA(void*, void*, void*, ULONG, ULONG,
|
||||
ULONG, void*, ULONG, void*, void*,
|
||||
void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY InitializeSecurityContextA(
|
||||
void* phCredential, void* phContext, void* pszTargetName, ULONG fContextReq, ULONG Reserved1,
|
||||
ULONG TargetDataRep, void* pInput, ULONG Reserved2, void* phNewContext, void* pOutput,
|
||||
void* pfContextAttr, void* ptsExpiry)
|
||||
{
|
||||
return sspi_InitializeSecurityContextA(phCredential, phContext, pszTargetName, fContextReq,
|
||||
Reserved1, TargetDataRep, pInput, Reserved2,
|
||||
phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesW(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryContextAttributesW(void* phContext, ULONG ulAttribute,
|
||||
void* pBuffer)
|
||||
{
|
||||
return sspi_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesA(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryContextAttributesA(void* phContext, ULONG ulAttribute,
|
||||
void* pBuffer)
|
||||
{
|
||||
return sspi_QueryContextAttributesA(phContext, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityContextToken(void*, void**);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QuerySecurityContextToken(void* phContext, void** phToken)
|
||||
{
|
||||
return sspi_QuerySecurityContextToken(phContext, phToken);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesW(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY SetContextAttributesW(void* phContext, ULONG ulAttribute,
|
||||
void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return sspi_SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesA(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY SetContextAttributesA(void* phContext, ULONG ulAttribute,
|
||||
void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return sspi_SetContextAttributesA(phContext, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_SetCredentialsAttributesW(void*, ULONG, void*, ULONG);
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY SetCredentialsAttributesW(void* phCredential, ULONG ulAttribute,
|
||||
void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return sspi_SetCredentialsAttributesW(phCredential, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_SetCredentialsAttributesA(void*, ULONG, void*, ULONG);
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY SetCredentialsAttributesA(void* phCredential, ULONG ulAttribute,
|
||||
void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return sspi_SetCredentialsAttributesA(phCredential, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_RevertSecurityContext(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY RevertSecurityContext(void* phContext)
|
||||
{
|
||||
return sspi_RevertSecurityContext(phContext);
|
||||
}
|
||||
|
||||
/* Message Support */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_DecryptMessage(void*, void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY DecryptMessage(void* phContext, void* pMessage,
|
||||
ULONG MessageSeqNo, void* pfQOP)
|
||||
{
|
||||
return sspi_DecryptMessage(phContext, pMessage, MessageSeqNo, pfQOP);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_EncryptMessage(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY EncryptMessage(void* phContext, ULONG fQOP, void* pMessage,
|
||||
ULONG MessageSeqNo)
|
||||
{
|
||||
return sspi_EncryptMessage(phContext, fQOP, pMessage, MessageSeqNo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_MakeSignature(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY MakeSignature(void* phContext, ULONG fQOP, void* pMessage,
|
||||
ULONG MessageSeqNo)
|
||||
{
|
||||
return sspi_MakeSignature(phContext, fQOP, pMessage, MessageSeqNo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_VerifySignature(void*, void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY VerifySignature(void* phContext, void* pMessage,
|
||||
ULONG MessageSeqNo, void* pfQOP)
|
||||
{
|
||||
return sspi_VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP);
|
||||
}
|
||||
|
||||
#endif /* SSPI_DLL */
|
||||
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
120
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_gss.c
vendored
Normal file
120
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_gss.c
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Generic Security Service Application Program Interface (GSSAPI)
|
||||
*
|
||||
* Copyright 2015 ANSSI, Author Thomas Calderon
|
||||
* Copyright 2015 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2017 Dorian Ducournau <dorian.ducournau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/endian.h>
|
||||
#include <winpr/asn1.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "sspi_gss.h"
|
||||
|
||||
BOOL sspi_gss_wrap_token(SecBuffer* buf, const WinPrAsn1_OID* oid, uint16_t tok_id,
|
||||
const sspi_gss_data* token)
|
||||
{
|
||||
WinPrAsn1Encoder* enc = nullptr;
|
||||
BYTE tok_id_buf[2];
|
||||
WinPrAsn1_MemoryChunk mc = { 2, tok_id_buf };
|
||||
wStream s;
|
||||
size_t len = 0;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
WINPR_ASSERT(buf);
|
||||
WINPR_ASSERT(oid);
|
||||
WINPR_ASSERT(token);
|
||||
|
||||
winpr_Data_Write_UINT16_BE(tok_id_buf, tok_id);
|
||||
|
||||
enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
|
||||
if (!enc)
|
||||
return FALSE;
|
||||
|
||||
/* initialContextToken [APPLICATION 0] */
|
||||
if (!WinPrAsn1EncAppContainer(enc, 0))
|
||||
goto cleanup;
|
||||
|
||||
/* thisMech OID */
|
||||
if (!WinPrAsn1EncOID(enc, oid))
|
||||
goto cleanup;
|
||||
|
||||
/* TOK_ID */
|
||||
if (!WinPrAsn1EncRawContent(enc, &mc))
|
||||
goto cleanup;
|
||||
|
||||
/* innerToken */
|
||||
mc.data = (BYTE*)token->data;
|
||||
mc.len = token->length;
|
||||
if (!WinPrAsn1EncRawContent(enc, &mc))
|
||||
goto cleanup;
|
||||
|
||||
if (!WinPrAsn1EncEndContainer(enc))
|
||||
goto cleanup;
|
||||
|
||||
if (!WinPrAsn1EncStreamSize(enc, &len) || len > buf->cbBuffer)
|
||||
goto cleanup;
|
||||
|
||||
Stream_StaticInit(&s, buf->pvBuffer, len);
|
||||
if (WinPrAsn1EncToStream(enc, &s))
|
||||
{
|
||||
buf->cbBuffer = (UINT32)len;
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
WinPrAsn1Encoder_Free(&enc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL sspi_gss_unwrap_token(const SecBuffer* buf, WinPrAsn1_OID* oid, uint16_t* tok_id,
|
||||
sspi_gss_data* token)
|
||||
{
|
||||
WinPrAsn1Decoder dec = WinPrAsn1Decoder_init();
|
||||
WinPrAsn1Decoder dec2 = WinPrAsn1Decoder_init();
|
||||
WinPrAsn1_tagId tag = 0;
|
||||
wStream sbuffer = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = nullptr;
|
||||
|
||||
WINPR_ASSERT(buf);
|
||||
WINPR_ASSERT(oid);
|
||||
WINPR_ASSERT(token);
|
||||
|
||||
WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, buf->pvBuffer, buf->cbBuffer);
|
||||
|
||||
if (!WinPrAsn1DecReadApp(&dec, &tag, &dec2) || tag != 0)
|
||||
return FALSE;
|
||||
|
||||
if (!WinPrAsn1DecReadOID(&dec2, oid, FALSE))
|
||||
return FALSE;
|
||||
|
||||
sbuffer = WinPrAsn1DecGetStream(&dec2);
|
||||
s = &sbuffer;
|
||||
|
||||
if (Stream_Length(s) < 2)
|
||||
return FALSE;
|
||||
|
||||
if (tok_id)
|
||||
Stream_Read_UINT16_BE(s, *tok_id);
|
||||
|
||||
token->data = Stream_Pointer(s);
|
||||
token->length = (UINT)Stream_GetRemainingLength(s);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
85
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_gss.h
vendored
Normal file
85
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_gss.h
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Generic Security Service Application Program Interface (GSSAPI)
|
||||
*
|
||||
* Copyright 2015 ANSSI, Author Thomas Calderon
|
||||
* Copyright 2015 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2017 Dorian Ducournau <dorian.ducournau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_GSS_PRIVATE_H
|
||||
#define WINPR_SSPI_GSS_PRIVATE_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/asn1.h>
|
||||
|
||||
#ifdef WITH_KRB5_MIT
|
||||
#include <krb5.h>
|
||||
typedef krb5_data sspi_gss_data;
|
||||
#elif defined(WITH_KRB5_HEIMDAL)
|
||||
#include <krb5.h>
|
||||
typedef krb5_data sspi_gss_data;
|
||||
#else
|
||||
typedef struct
|
||||
{
|
||||
int32_t magic;
|
||||
unsigned int length;
|
||||
char* data;
|
||||
} sspi_gss_data;
|
||||
#endif
|
||||
|
||||
#define SSPI_GSS_C_DELEG_FLAG 1
|
||||
#define SSPI_GSS_C_MUTUAL_FLAG 2
|
||||
#define SSPI_GSS_C_REPLAY_FLAG 4
|
||||
#define SSPI_GSS_C_SEQUENCE_FLAG 8
|
||||
#define SSPI_GSS_C_CONF_FLAG 16
|
||||
#define SSPI_GSS_C_INTEG_FLAG 32
|
||||
|
||||
#define FLAG_SENDER_IS_ACCEPTOR 0x01
|
||||
#define FLAG_WRAP_CONFIDENTIAL 0x02
|
||||
#define FLAG_ACCEPTOR_SUBKEY 0x04
|
||||
|
||||
#define KG_USAGE_ACCEPTOR_SEAL 22
|
||||
#define KG_USAGE_ACCEPTOR_SIGN 23
|
||||
#define KG_USAGE_INITIATOR_SEAL 24
|
||||
#define KG_USAGE_INITIATOR_SIGN 25
|
||||
|
||||
#define TOK_ID_AP_REQ 0x0100
|
||||
#define TOK_ID_AP_REP 0x0200
|
||||
#define TOK_ID_ERROR 0x0300
|
||||
#define TOK_ID_TGT_REQ 0x0400
|
||||
#define TOK_ID_TGT_REP 0x0401
|
||||
|
||||
#define TOK_ID_MIC 0x0404
|
||||
#define TOK_ID_WRAP 0x0504
|
||||
#define TOK_ID_MIC_V1 0x0101
|
||||
#define TOK_ID_WRAP_V1 0x0201
|
||||
|
||||
#define GSS_CHECKSUM_TYPE 0x8003
|
||||
|
||||
static inline BOOL sspi_gss_oid_compare(const WinPrAsn1_OID* oid1, const WinPrAsn1_OID* oid2)
|
||||
{
|
||||
WINPR_ASSERT(oid1);
|
||||
WINPR_ASSERT(oid2);
|
||||
|
||||
return (oid1->len == oid2->len) && (memcmp(oid1->data, oid2->data, oid1->len) == 0);
|
||||
}
|
||||
|
||||
BOOL sspi_gss_wrap_token(SecBuffer* buf, const WinPrAsn1_OID* oid, uint16_t tok_id,
|
||||
const sspi_gss_data* token);
|
||||
BOOL sspi_gss_unwrap_token(const SecBuffer* buf, WinPrAsn1_OID* oid, uint16_t* tok_id,
|
||||
sspi_gss_data* token);
|
||||
|
||||
#endif /* WINPR_SSPI_GSS_PRIVATE_H */
|
||||
2068
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_winpr.c
vendored
Normal file
2068
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_winpr.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
31
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_winpr.h
vendored
Normal file
31
third_party/FreeRDP/winpr/libwinpr/sspi/sspi_winpr.h
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_WINPR_H
|
||||
#define WINPR_SSPI_WINPR_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
SecurityFunctionTableW* SEC_ENTRY winpr_InitSecurityInterfaceW(void);
|
||||
SecurityFunctionTableA* SEC_ENTRY winpr_InitSecurityInterfaceA(void);
|
||||
|
||||
void* sspi_ContextBufferAlloc(UINT32 allocatorIndex, size_t size);
|
||||
void sspi_ContextBufferFree(void* contextBuffer);
|
||||
|
||||
#endif /* WINPR_SSPI_WINPR_H */
|
||||
34
third_party/FreeRDP/winpr/libwinpr/sspi/test/CMakeLists.txt
vendored
Normal file
34
third_party/FreeRDP/winpr/libwinpr/sspi/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
set(MODULE_NAME "TestSspi")
|
||||
set(MODULE_PREFIX "TEST_SSPI")
|
||||
|
||||
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestQuerySecurityPackageInfo.c TestEnumerateSecurityPackages.c TestInitializeSecurityContext.c
|
||||
TestAcquireCredentialsHandle.c TestCredSSP.c
|
||||
#TestSchannel.c
|
||||
TestNTLM.c
|
||||
)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
if(WIN32)
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} secur32 crypt32)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS} winpr)
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
|
||||
61
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestAcquireCredentialsHandle.c
vendored
Normal file
61
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestAcquireCredentialsHandle.c
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/winpr.h>
|
||||
|
||||
static const char* test_User = "User";
|
||||
static const char* test_Domain = "Domain";
|
||||
static const char* test_Password = "Password";
|
||||
|
||||
int TestAcquireCredentialsHandle(int argc, char* argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
SECURITY_STATUS status = 0;
|
||||
CredHandle credentials = WINPR_C_ARRAY_INIT;
|
||||
TimeStamp expiration;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
SecurityFunctionTable* table = nullptr;
|
||||
SecPkgCredentials_Names credential_names;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
sspi_GlobalInit();
|
||||
table = InitSecurityInterfaceEx(0);
|
||||
identity.User = (UINT16*)_strdup(test_User);
|
||||
identity.Domain = (UINT16*)_strdup(test_Domain);
|
||||
identity.Password = (UINT16*)_strdup(test_Password);
|
||||
|
||||
if (!identity.User || !identity.Domain || !identity.Password)
|
||||
goto fail;
|
||||
|
||||
identity.UserLength = strlen(test_User);
|
||||
identity.DomainLength = strlen(test_Domain);
|
||||
identity.PasswordLength = strlen(test_Password);
|
||||
identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
||||
status =
|
||||
table->AcquireCredentialsHandle(nullptr, NTLM_SSP_NAME, SECPKG_CRED_OUTBOUND, nullptr,
|
||||
&identity, nullptr, nullptr, &credentials, &expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
goto fail;
|
||||
|
||||
status =
|
||||
table->QueryCredentialsAttributes(&credentials, SECPKG_CRED_ATTR_NAMES, &credential_names);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
goto fail;
|
||||
|
||||
rc = 0;
|
||||
fail:
|
||||
|
||||
if (SecIsValidHandle(&credentials))
|
||||
table->FreeCredentialsHandle(&credentials);
|
||||
|
||||
free(identity.User);
|
||||
free(identity.Domain);
|
||||
free(identity.Password);
|
||||
sspi_GlobalFinish();
|
||||
return rc;
|
||||
}
|
||||
8
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestCredSSP.c
vendored
Normal file
8
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestCredSSP.c
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
int TestCredSSP(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
40
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestEnumerateSecurityPackages.c
vendored
Normal file
40
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestEnumerateSecurityPackages.c
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/tchar.h>
|
||||
|
||||
int TestEnumerateSecurityPackages(int argc, char* argv[])
|
||||
{
|
||||
ULONG cPackages = 0;
|
||||
SECURITY_STATUS status = 0;
|
||||
SecPkgInfo* pPackageInfo = nullptr;
|
||||
SecurityFunctionTable* table = nullptr;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
sspi_GlobalInit();
|
||||
table = InitSecurityInterfaceEx(0);
|
||||
|
||||
status = table->EnumerateSecurityPackages(&cPackages, &pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
sspi_GlobalFinish();
|
||||
return -1;
|
||||
}
|
||||
|
||||
_tprintf(_T("\nEnumerateSecurityPackages (%") _T(PRIu32) _T("):\n"), cPackages);
|
||||
|
||||
for (size_t index = 0; index < cPackages; index++)
|
||||
{
|
||||
_tprintf(_T("\"%s\", \"%s\"\n"), pPackageInfo[index].Name, pPackageInfo[index].Comment);
|
||||
}
|
||||
|
||||
table->FreeContextBuffer(pPackageInfo);
|
||||
sspi_GlobalFinish();
|
||||
|
||||
return 0;
|
||||
}
|
||||
116
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestInitializeSecurityContext.c
vendored
Normal file
116
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestInitializeSecurityContext.c
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/winpr.h>
|
||||
|
||||
static const char* test_User = "User";
|
||||
static const char* test_Domain = "Domain";
|
||||
static const char* test_Password = "Password";
|
||||
|
||||
int TestInitializeSecurityContext(int argc, char* argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
UINT32 cbMaxLen = 0;
|
||||
UINT32 fContextReq = 0;
|
||||
void* output_buffer = nullptr;
|
||||
CtxtHandle context;
|
||||
ULONG pfContextAttr = 0;
|
||||
SECURITY_STATUS status = 0;
|
||||
CredHandle credentials = WINPR_C_ARRAY_INIT;
|
||||
TimeStamp expiration;
|
||||
PSecPkgInfo pPackageInfo = nullptr;
|
||||
SEC_WINNT_AUTH_IDENTITY identity = WINPR_C_ARRAY_INIT;
|
||||
SecurityFunctionTable* table = nullptr;
|
||||
PSecBuffer p_SecBuffer = nullptr;
|
||||
SecBuffer output_SecBuffer;
|
||||
SecBufferDesc output_SecBuffer_desc;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
sspi_GlobalInit();
|
||||
table = InitSecurityInterfaceEx(0);
|
||||
status = table->QuerySecurityPackageInfo(NTLM_SSP_NAME, &pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("QuerySecurityPackageInfo status: 0x%08" PRIX32 "\n", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cbMaxLen = pPackageInfo->cbMaxToken;
|
||||
identity.User = (UINT16*)_strdup(test_User);
|
||||
identity.Domain = (UINT16*)_strdup(test_Domain);
|
||||
identity.Password = (UINT16*)_strdup(test_Password);
|
||||
|
||||
if (!identity.User || !identity.Domain || !identity.Password)
|
||||
goto fail;
|
||||
|
||||
identity.UserLength = strlen(test_User);
|
||||
identity.DomainLength = strlen(test_Domain);
|
||||
identity.PasswordLength = strlen(test_Password);
|
||||
identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
||||
status =
|
||||
table->AcquireCredentialsHandle(nullptr, NTLM_SSP_NAME, SECPKG_CRED_OUTBOUND, nullptr,
|
||||
&identity, nullptr, nullptr, &credentials, &expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("AcquireCredentialsHandle status: 0x%08" PRIX32 "\n", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY |
|
||||
ISC_REQ_DELEGATE;
|
||||
output_buffer = malloc(cbMaxLen);
|
||||
|
||||
if (!output_buffer)
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
output_SecBuffer_desc.ulVersion = 0;
|
||||
output_SecBuffer_desc.cBuffers = 1;
|
||||
output_SecBuffer_desc.pBuffers = &output_SecBuffer;
|
||||
output_SecBuffer.cbBuffer = cbMaxLen;
|
||||
output_SecBuffer.BufferType = SECBUFFER_TOKEN;
|
||||
output_SecBuffer.pvBuffer = output_buffer;
|
||||
status = table->InitializeSecurityContext(&credentials, nullptr, nullptr, fContextReq, 0, 0,
|
||||
nullptr, 0, &context, &output_SecBuffer_desc,
|
||||
&pfContextAttr, &expiration);
|
||||
|
||||
if (status != SEC_I_CONTINUE_NEEDED)
|
||||
{
|
||||
printf("InitializeSecurityContext status: 0x%08" PRIX32 "\n", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printf("cBuffers: %" PRIu32 " ulVersion: %" PRIu32 "\n", output_SecBuffer_desc.cBuffers,
|
||||
output_SecBuffer_desc.ulVersion);
|
||||
p_SecBuffer = &output_SecBuffer_desc.pBuffers[0];
|
||||
printf("BufferType: 0x%08" PRIX32 " cbBuffer: %" PRIu32 "\n", p_SecBuffer->BufferType,
|
||||
p_SecBuffer->cbBuffer);
|
||||
status = table->DeleteSecurityContext(&context);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("DeleteSecurityContext status: 0x%08" PRIX32 "\n", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
fail:
|
||||
free(identity.User);
|
||||
free(identity.Domain);
|
||||
free(identity.Password);
|
||||
free(output_buffer);
|
||||
|
||||
if (SecIsValidHandle(&credentials))
|
||||
table->FreeCredentialsHandle(&credentials);
|
||||
|
||||
table->FreeContextBuffer(pPackageInfo);
|
||||
sspi_GlobalFinish();
|
||||
return rc;
|
||||
}
|
||||
792
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestNTLM.c
vendored
Normal file
792
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestNTLM.c
vendored
Normal file
@@ -0,0 +1,792 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
struct test_input_t
|
||||
{
|
||||
const char* user;
|
||||
const char* domain;
|
||||
const char* pwd;
|
||||
const BYTE* ntlm;
|
||||
const BYTE* ntlmv2;
|
||||
BOOL dynamic;
|
||||
BOOL expected;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CtxtHandle context;
|
||||
ULONG cbMaxToken;
|
||||
ULONG fContextReq;
|
||||
ULONG pfContextAttr;
|
||||
TimeStamp expiration;
|
||||
PSecBuffer pBuffer;
|
||||
SecBuffer inputBuffer[2];
|
||||
SecBuffer outputBuffer[2];
|
||||
BOOL haveContext;
|
||||
BOOL haveInputBuffer;
|
||||
BOOL UseNtlmV2Hash;
|
||||
LPTSTR ServicePrincipalName;
|
||||
SecBufferDesc inputBufferDesc;
|
||||
SecBufferDesc outputBufferDesc;
|
||||
CredHandle credentials;
|
||||
BOOL confidentiality;
|
||||
SecPkgInfo* pPackageInfo;
|
||||
SecurityFunctionTable* table;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
} TEST_NTLM_SERVER;
|
||||
|
||||
static BYTE TEST_NTLM_TIMESTAMP[8] = { 0x33, 0x57, 0xbd, 0xb1, 0x07, 0x8b, 0xcf, 0x01 };
|
||||
|
||||
static BYTE TEST_NTLM_CLIENT_CHALLENGE[8] = { 0x20, 0xc0, 0x2b, 0x3d, 0xc0, 0x61, 0xa7, 0x73 };
|
||||
|
||||
static BYTE TEST_NTLM_SERVER_CHALLENGE[8] = { 0xa4, 0xf1, 0xba, 0xa6, 0x7c, 0xdc, 0x1a, 0x12 };
|
||||
|
||||
static BYTE TEST_NTLM_NEGOTIATE[] =
|
||||
"\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x06\x03\x80\x25\x00\x00\x00\x0f";
|
||||
|
||||
static BYTE TEST_NTLM_CHALLENGE[] =
|
||||
"\x4e\x54\x4c\x4d\x53\x53\x50\x00\x02\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x38\x00\x00\x00\x07\x82\x88\xa2\xa4\xf1\xba\xa6\x7c\xdc\x1a\x12"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x66\x00\x66\x00\x38\x00\x00\x00"
|
||||
"\x06\x03\x80\x25\x00\x00\x00\x0f\x02\x00\x0e\x00\x4e\x00\x45\x00"
|
||||
"\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x01\x00\x0e\x00\x4e\x00"
|
||||
"\x45\x00\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x04\x00\x1c\x00"
|
||||
"\x6c\x00\x61\x00\x62\x00\x2e\x00\x77\x00\x61\x00\x79\x00\x6b\x00"
|
||||
"\x2e\x00\x6c\x00\x6f\x00\x63\x00\x61\x00\x6c\x00\x03\x00\x0e\x00"
|
||||
"\x6e\x00\x65\x00\x77\x00\x79\x00\x65\x00\x61\x00\x72\x00\x07\x00"
|
||||
"\x08\x00\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x00\x00\x00\x00";
|
||||
|
||||
static BYTE TEST_NTLM_AUTHENTICATE[] =
|
||||
"\x4e\x54\x4c\x4d\x53\x53\x50\x00\x03\x00\x00\x00\x18\x00\x18\x00"
|
||||
"\x82\x00\x00\x00\x08\x01\x08\x01\x9a\x00\x00\x00\x0c\x00\x0c\x00"
|
||||
"\x58\x00\x00\x00\x10\x00\x10\x00\x64\x00\x00\x00\x0e\x00\x0e\x00"
|
||||
"\x74\x00\x00\x00\x00\x00\x00\x00\xa2\x01\x00\x00\x05\x82\x88\xa2"
|
||||
"\x06\x03\x80\x25\x00\x00\x00\x0f\x12\xe5\x5a\xf5\x80\xee\x3f\x29"
|
||||
"\xe1\xde\x90\x4d\x73\x77\x06\x25\x44\x00\x6f\x00\x6d\x00\x61\x00"
|
||||
"\x69\x00\x6e\x00\x55\x00\x73\x00\x65\x00\x72\x00\x6e\x00\x61\x00"
|
||||
"\x6d\x00\x65\x00\x4e\x00\x45\x00\x57\x00\x59\x00\x45\x00\x41\x00"
|
||||
"\x52\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x62\x14\x68\xc8\x98\x12"
|
||||
"\xe7\x39\xd8\x76\x1b\xe9\xf7\x54\xb5\xe3\x01\x01\x00\x00\x00\x00"
|
||||
"\x00\x00\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x20\xc0\x2b\x3d\xc0\x61"
|
||||
"\xa7\x73\x00\x00\x00\x00\x02\x00\x0e\x00\x4e\x00\x45\x00\x57\x00"
|
||||
"\x59\x00\x45\x00\x41\x00\x52\x00\x01\x00\x0e\x00\x4e\x00\x45\x00"
|
||||
"\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x04\x00\x1c\x00\x6c\x00"
|
||||
"\x61\x00\x62\x00\x2e\x00\x77\x00\x61\x00\x79\x00\x6b\x00\x2e\x00"
|
||||
"\x6c\x00\x6f\x00\x63\x00\x61\x00\x6c\x00\x03\x00\x0e\x00\x6e\x00"
|
||||
"\x65\x00\x77\x00\x79\x00\x65\x00\x61\x00\x72\x00\x07\x00\x08\x00"
|
||||
"\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x06\x00\x04\x00\x02\x00\x00\x00"
|
||||
"\x08\x00\x30\x00\x30\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
|
||||
"\x00\x20\x00\x00\x1e\x10\xf5\x2c\x54\x2f\x2e\x77\x1c\x13\xbf\xc3"
|
||||
"\x3f\xe1\x7b\x28\x7e\x0b\x93\x5a\x39\xd2\xce\x12\xd7\xbd\x8c\x4e"
|
||||
"\x2b\xb5\x0b\xf5\x0a\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x1a\x00\x48\x00\x54\x00"
|
||||
"\x54\x00\x50\x00\x2f\x00\x72\x00\x77\x00\x2e\x00\x6c\x00\x6f\x00"
|
||||
"\x63\x00\x61\x00\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00";
|
||||
|
||||
#define TEST_SSPI_INTERFACE SSPI_INTERFACE_WINPR
|
||||
|
||||
static const char* TEST_NTLM_USER = "Username";
|
||||
static const char* TEST_NTLM_DOMAIN = "Domain";
|
||||
static const char* TEST_NTLM_PASSWORD = "P4ss123!";
|
||||
|
||||
// static const char* TEST_NTLM_HASH_STRING = "d5922a65c4d5c082ca444af1be0001db";
|
||||
|
||||
static const BYTE TEST_NTLM_HASH[16] = { 0xd5, 0x92, 0x2a, 0x65, 0xc4, 0xd5, 0xc0, 0x82,
|
||||
0xca, 0x44, 0x4a, 0xf1, 0xbe, 0x00, 0x01, 0xdb };
|
||||
|
||||
// static const char* TEST_NTLM_HASH_V2_STRING = "4c7f706f7dde05a9d1a0f4e7ffe3bfb8";
|
||||
|
||||
static const BYTE TEST_NTLM_V2_HASH[16] = { 0x4c, 0x7f, 0x70, 0x6f, 0x7d, 0xde, 0x05, 0xa9,
|
||||
0xd1, 0xa0, 0xf4, 0xe7, 0xff, 0xe3, 0xbf, 0xb8 };
|
||||
|
||||
static const BYTE TEST_EMPTY_PWD_NTLM_HASH[] = { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31,
|
||||
0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 };
|
||||
|
||||
static const BYTE TEST_EMPTY_PWD_NTLM_V2_HASH[] = {
|
||||
0x0b, 0xce, 0x54, 0x87, 0x4e, 0x94, 0x20, 0x9e, 0x34, 0x48, 0x97, 0xc1, 0x60, 0x03, 0x6e, 0x3b
|
||||
};
|
||||
|
||||
#define NTLM_PACKAGE_NAME NTLM_SSP_NAME
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CtxtHandle context;
|
||||
ULONG cbMaxToken;
|
||||
ULONG fContextReq;
|
||||
ULONG pfContextAttr;
|
||||
TimeStamp expiration;
|
||||
PSecBuffer pBuffer;
|
||||
SecBuffer inputBuffer[2];
|
||||
SecBuffer outputBuffer[2];
|
||||
BOOL haveContext;
|
||||
BOOL haveInputBuffer;
|
||||
LPTSTR ServicePrincipalName;
|
||||
SecBufferDesc inputBufferDesc;
|
||||
SecBufferDesc outputBufferDesc;
|
||||
CredHandle credentials;
|
||||
BOOL confidentiality;
|
||||
SecPkgInfo* pPackageInfo;
|
||||
SecurityFunctionTable* table;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
} TEST_NTLM_CLIENT;
|
||||
|
||||
static int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm, const char* user, const char* domain,
|
||||
const char* password)
|
||||
{
|
||||
SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
|
||||
|
||||
WINPR_ASSERT(ntlm);
|
||||
|
||||
SecInvalidateHandle(&(ntlm->context));
|
||||
ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
|
||||
if (!ntlm->table)
|
||||
return -1;
|
||||
const int rc = sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
(void)fprintf(stderr, "QuerySecurityPackageInfo status: %s (0x%08" PRIX32 ")\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
|
||||
status = ntlm->table->AcquireCredentialsHandle(nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_OUTBOUND,
|
||||
nullptr, &ntlm->identity, nullptr, nullptr,
|
||||
&ntlm->credentials, &ntlm->expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
(void)fprintf(stderr, "AcquireCredentialsHandle status: %s (0x%08" PRIX32 ")\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->haveContext = FALSE;
|
||||
ntlm->haveInputBuffer = FALSE;
|
||||
ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer));
|
||||
ntlm->fContextReq = 0;
|
||||
|
||||
/* NLA authentication flags */
|
||||
ntlm->fContextReq |= ISC_REQ_MUTUAL_AUTH;
|
||||
ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
|
||||
ntlm->fContextReq |= ISC_REQ_USE_SESSION_KEY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_ntlm_client_uninit(TEST_NTLM_CLIENT* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
if (ntlm->outputBuffer[0].pvBuffer)
|
||||
{
|
||||
free(ntlm->outputBuffer[0].pvBuffer);
|
||||
ntlm->outputBuffer[0].pvBuffer = nullptr;
|
||||
}
|
||||
|
||||
free(ntlm->identity.User);
|
||||
free(ntlm->identity.Domain);
|
||||
free(ntlm->identity.Password);
|
||||
free(ntlm->ServicePrincipalName);
|
||||
|
||||
if (ntlm->table)
|
||||
{
|
||||
SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
|
||||
WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
|
||||
(status == SEC_E_UNSUPPORTED_FUNCTION));
|
||||
|
||||
status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
|
||||
WINPR_ASSERT((status == SEC_E_OK) || (status = SEC_E_INVALID_HANDLE));
|
||||
|
||||
status = ntlm->table->DeleteSecurityContext(&ntlm->context);
|
||||
WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
|
||||
(status == SEC_E_UNSUPPORTED_FUNCTION));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SSPI Client Ceremony
|
||||
*
|
||||
* --------------
|
||||
* ( Client Begin )
|
||||
* --------------
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* -----------+--------------
|
||||
* | AcquireCredentialsHandle |
|
||||
* --------------------------
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* -------------+--------------
|
||||
* +---------------> / InitializeSecurityContext /
|
||||
* | ----------------------------
|
||||
* | |
|
||||
* | |
|
||||
* | \|/
|
||||
* --------------------------- ---------+------------- ----------------------
|
||||
* / Receive blob from server / < Received security blob? > --Yes-> / Send blob to server /
|
||||
* -------------+------------- ----------------------- ----------------------
|
||||
* /|\ | |
|
||||
* | No |
|
||||
* Yes \|/ |
|
||||
* | ------------+----------- |
|
||||
* +---------------- < Received Continue Needed > <-----------------+
|
||||
* ------------------------
|
||||
* |
|
||||
* No
|
||||
* \|/
|
||||
* ------+-------
|
||||
* ( Client End )
|
||||
* --------------
|
||||
*/
|
||||
static BOOL IsSecurityStatusError(SECURITY_STATUS status)
|
||||
{
|
||||
BOOL error = TRUE;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case SEC_E_OK:
|
||||
case SEC_I_CONTINUE_NEEDED:
|
||||
case SEC_I_COMPLETE_NEEDED:
|
||||
case SEC_I_COMPLETE_AND_CONTINUE:
|
||||
case SEC_I_LOCAL_LOGON:
|
||||
case SEC_I_CONTEXT_EXPIRED:
|
||||
case SEC_I_INCOMPLETE_CREDENTIALS:
|
||||
case SEC_I_RENEGOTIATE:
|
||||
case SEC_I_NO_LSA_CONTEXT:
|
||||
case SEC_I_SIGNATURE_NEEDED:
|
||||
case SEC_I_NO_RENEGOTIATION:
|
||||
error = FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
|
||||
|
||||
WINPR_ASSERT(ntlm);
|
||||
if (ntlm->outputBuffer[0].pvBuffer)
|
||||
{
|
||||
free(ntlm->outputBuffer[0].pvBuffer);
|
||||
ntlm->outputBuffer[0].pvBuffer = nullptr;
|
||||
}
|
||||
|
||||
ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->outputBufferDesc.cBuffers = 1;
|
||||
ntlm->outputBufferDesc.pBuffers = ntlm->outputBuffer;
|
||||
ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
|
||||
ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
|
||||
|
||||
if (!ntlm->outputBuffer[0].pvBuffer)
|
||||
return -1;
|
||||
|
||||
if (ntlm->haveInputBuffer)
|
||||
{
|
||||
ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->inputBufferDesc.cBuffers = 1;
|
||||
ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
|
||||
ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
}
|
||||
|
||||
if ((!ntlm) || (!ntlm->table))
|
||||
{
|
||||
(void)fprintf(stderr, "ntlm_authenticate: invalid ntlm context\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = ntlm->table->InitializeSecurityContext(
|
||||
&ntlm->credentials, (ntlm->haveContext) ? &ntlm->context : nullptr,
|
||||
(ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : nullptr, ntlm->fContextReq, 0,
|
||||
SECURITY_NATIVE_DREP, (ntlm->haveInputBuffer) ? &ntlm->inputBufferDesc : nullptr, 0,
|
||||
&ntlm->context, &ntlm->outputBufferDesc, &ntlm->pfContextAttr, &ntlm->expiration);
|
||||
|
||||
if (IsSecurityStatusError(status))
|
||||
return -1;
|
||||
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
if (ntlm->table->CompleteAuthToken)
|
||||
{
|
||||
SECURITY_STATUS rc =
|
||||
ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
|
||||
if (rc != SEC_E_OK)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if (ntlm->haveInputBuffer)
|
||||
{
|
||||
free(ntlm->inputBuffer[0].pvBuffer);
|
||||
}
|
||||
|
||||
ntlm->haveInputBuffer = TRUE;
|
||||
ntlm->haveContext = TRUE;
|
||||
return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
|
||||
}
|
||||
|
||||
static TEST_NTLM_CLIENT* test_ntlm_client_new(void)
|
||||
{
|
||||
TEST_NTLM_CLIENT* ntlm = (TEST_NTLM_CLIENT*)calloc(1, sizeof(TEST_NTLM_CLIENT));
|
||||
|
||||
if (!ntlm)
|
||||
return nullptr;
|
||||
|
||||
return ntlm;
|
||||
}
|
||||
|
||||
static void test_ntlm_client_free(TEST_NTLM_CLIENT* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
test_ntlm_client_uninit(ntlm);
|
||||
free(ntlm);
|
||||
}
|
||||
|
||||
static int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
|
||||
|
||||
WINPR_ASSERT(ntlm);
|
||||
|
||||
ntlm->UseNtlmV2Hash = TRUE;
|
||||
SecInvalidateHandle(&(ntlm->context));
|
||||
ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
|
||||
if (!ntlm->table)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
(void)fprintf(stderr, "QuerySecurityPackageInfo status: %s (0x%08" PRIX32 ")\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
|
||||
status = ntlm->table->AcquireCredentialsHandle(nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_INBOUND,
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
&ntlm->credentials, &ntlm->expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
(void)fprintf(stderr, "AcquireCredentialsHandle status: %s (0x%08" PRIX32 ")\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->haveContext = FALSE;
|
||||
ntlm->haveInputBuffer = FALSE;
|
||||
ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer));
|
||||
ntlm->fContextReq = 0;
|
||||
/* NLA authentication flags */
|
||||
ntlm->fContextReq |= ASC_REQ_MUTUAL_AUTH;
|
||||
ntlm->fContextReq |= ASC_REQ_CONFIDENTIALITY;
|
||||
ntlm->fContextReq |= ASC_REQ_CONNECTION;
|
||||
ntlm->fContextReq |= ASC_REQ_USE_SESSION_KEY;
|
||||
ntlm->fContextReq |= ASC_REQ_REPLAY_DETECT;
|
||||
ntlm->fContextReq |= ASC_REQ_SEQUENCE_DETECT;
|
||||
ntlm->fContextReq |= ASC_REQ_EXTENDED_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_ntlm_server_uninit(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
if (ntlm->outputBuffer[0].pvBuffer)
|
||||
{
|
||||
free(ntlm->outputBuffer[0].pvBuffer);
|
||||
ntlm->outputBuffer[0].pvBuffer = nullptr;
|
||||
}
|
||||
|
||||
free(ntlm->identity.User);
|
||||
free(ntlm->identity.Domain);
|
||||
free(ntlm->identity.Password);
|
||||
free(ntlm->ServicePrincipalName);
|
||||
|
||||
if (ntlm->table)
|
||||
{
|
||||
SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
|
||||
WINPR_ASSERT(status == SEC_E_OK);
|
||||
status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
|
||||
WINPR_ASSERT(status == SEC_E_OK);
|
||||
status = ntlm->table->DeleteSecurityContext(&ntlm->context);
|
||||
WINPR_ASSERT(status == SEC_E_OK);
|
||||
}
|
||||
}
|
||||
|
||||
static int test_ntlm_server_authenticate(const struct test_input_t* targ, TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
|
||||
|
||||
WINPR_ASSERT(ntlm);
|
||||
WINPR_ASSERT(targ);
|
||||
|
||||
ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->inputBufferDesc.cBuffers = 1;
|
||||
ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
|
||||
ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->outputBufferDesc.cBuffers = 1;
|
||||
ntlm->outputBufferDesc.pBuffers = &ntlm->outputBuffer[0];
|
||||
ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
|
||||
ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
|
||||
|
||||
if (!ntlm->outputBuffer[0].pvBuffer)
|
||||
return -1;
|
||||
|
||||
status = ntlm->table->AcceptSecurityContext(
|
||||
&ntlm->credentials, ntlm->haveContext ? &ntlm->context : nullptr, &ntlm->inputBufferDesc,
|
||||
ntlm->fContextReq, SECURITY_NATIVE_DREP, &ntlm->context, &ntlm->outputBufferDesc,
|
||||
&ntlm->pfContextAttr, &ntlm->expiration);
|
||||
|
||||
if (status == SEC_I_CONTINUE_NEEDED)
|
||||
{
|
||||
SecPkgContext_AuthNtlmHash AuthNtlmHash = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (ntlm->UseNtlmV2Hash)
|
||||
{
|
||||
AuthNtlmHash.Version = 2;
|
||||
CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlmv2, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
AuthNtlmHash.Version = 1;
|
||||
CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlm, 16);
|
||||
}
|
||||
|
||||
status =
|
||||
ntlm->table->SetContextAttributes(&ntlm->context, SECPKG_ATTR_AUTH_NTLM_HASH,
|
||||
&AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash));
|
||||
}
|
||||
|
||||
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
|
||||
{
|
||||
(void)fprintf(stderr, "AcceptSecurityContext status: %s (0x%08" PRIX32 ")\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1; /* Access Denied */
|
||||
}
|
||||
|
||||
ntlm->haveContext = TRUE;
|
||||
return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
|
||||
}
|
||||
|
||||
static TEST_NTLM_SERVER* test_ntlm_server_new(void)
|
||||
{
|
||||
TEST_NTLM_SERVER* ntlm = (TEST_NTLM_SERVER*)calloc(1, sizeof(TEST_NTLM_SERVER));
|
||||
|
||||
if (!ntlm)
|
||||
return nullptr;
|
||||
|
||||
return ntlm;
|
||||
}
|
||||
|
||||
static void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
test_ntlm_server_uninit(ntlm);
|
||||
free(ntlm);
|
||||
}
|
||||
|
||||
static BOOL test_default(const struct test_input_t* arg)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
PSecBuffer pSecBuffer = nullptr;
|
||||
|
||||
WINPR_ASSERT(arg);
|
||||
|
||||
printf("testcase {user=%s, domain=%s, password=%s, dynamic=%s}\n", arg->user, arg->domain,
|
||||
arg->pwd, arg->dynamic ? "TRUE" : "FALSE");
|
||||
|
||||
/**
|
||||
* Client Initialization
|
||||
*/
|
||||
TEST_NTLM_CLIENT* client = test_ntlm_client_new();
|
||||
TEST_NTLM_SERVER* server = test_ntlm_server_new();
|
||||
|
||||
if (!client || !server)
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int status = test_ntlm_client_init(client, arg->user, arg->domain, arg->pwd);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_client_init failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server Initialization
|
||||
*/
|
||||
|
||||
status = test_ntlm_server_init(server);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_server_init failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client -> Negotiate Message
|
||||
*/
|
||||
status = test_ntlm_client_authenticate(client);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_client_authenticate failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!arg->dynamic)
|
||||
{
|
||||
SecPkgContext_AuthNtlmTimestamp AuthNtlmTimestamp = WINPR_C_ARRAY_INIT;
|
||||
SecPkgContext_AuthNtlmClientChallenge AuthNtlmClientChallenge = WINPR_C_ARRAY_INIT;
|
||||
SecPkgContext_AuthNtlmServerChallenge AuthNtlmServerChallenge = WINPR_C_ARRAY_INIT;
|
||||
CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
|
||||
AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
|
||||
SECURITY_STATUS rc = client->table->SetContextAttributes(
|
||||
&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
|
||||
sizeof(SecPkgContext_AuthNtlmTimestamp));
|
||||
WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
|
||||
|
||||
AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
|
||||
rc = client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
|
||||
&AuthNtlmTimestamp,
|
||||
sizeof(SecPkgContext_AuthNtlmTimestamp));
|
||||
WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
|
||||
|
||||
CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
|
||||
CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
|
||||
rc = client->table->SetContextAttributes(
|
||||
&client->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
|
||||
sizeof(SecPkgContext_AuthNtlmClientChallenge));
|
||||
WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
|
||||
|
||||
rc = client->table->SetContextAttributes(
|
||||
&client->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
|
||||
sizeof(SecPkgContext_AuthNtlmServerChallenge));
|
||||
WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
|
||||
}
|
||||
|
||||
pSecBuffer = &(client->outputBuffer[0]);
|
||||
|
||||
if (!arg->dynamic)
|
||||
{
|
||||
pSecBuffer->cbBuffer = sizeof(TEST_NTLM_NEGOTIATE) - 1;
|
||||
free(pSecBuffer->pvBuffer);
|
||||
pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
|
||||
|
||||
if (!pSecBuffer->pvBuffer)
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_NEGOTIATE, pSecBuffer->cbBuffer);
|
||||
}
|
||||
|
||||
(void)fprintf(stderr, "NTLM_NEGOTIATE (length = %" PRIu32 "):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
/**
|
||||
* Server <- Negotiate Message
|
||||
* Server -> Challenge Message
|
||||
*/
|
||||
server->haveInputBuffer = TRUE;
|
||||
server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
|
||||
server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
|
||||
status = test_ntlm_server_authenticate(arg, server);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_server_authenticate failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!arg->dynamic)
|
||||
{
|
||||
SecPkgContext_AuthNtlmTimestamp AuthNtlmTimestamp = WINPR_C_ARRAY_INIT;
|
||||
SecPkgContext_AuthNtlmClientChallenge AuthNtlmClientChallenge = WINPR_C_ARRAY_INIT;
|
||||
SecPkgContext_AuthNtlmServerChallenge AuthNtlmServerChallenge = WINPR_C_ARRAY_INIT;
|
||||
CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
|
||||
AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
|
||||
SECURITY_STATUS rc = client->table->SetContextAttributes(
|
||||
&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
|
||||
sizeof(SecPkgContext_AuthNtlmTimestamp));
|
||||
WINPR_ASSERT(rc == SEC_E_OK);
|
||||
|
||||
AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
|
||||
rc = client->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
|
||||
&AuthNtlmTimestamp,
|
||||
sizeof(SecPkgContext_AuthNtlmTimestamp));
|
||||
WINPR_ASSERT(rc == SEC_E_OK);
|
||||
|
||||
CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
|
||||
CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
|
||||
rc = server->table->SetContextAttributes(
|
||||
&server->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
|
||||
sizeof(SecPkgContext_AuthNtlmClientChallenge));
|
||||
WINPR_ASSERT(rc == SEC_E_OK);
|
||||
|
||||
rc = server->table->SetContextAttributes(
|
||||
&server->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
|
||||
sizeof(SecPkgContext_AuthNtlmServerChallenge));
|
||||
WINPR_ASSERT(rc == SEC_E_OK);
|
||||
}
|
||||
|
||||
pSecBuffer = &(server->outputBuffer[0]);
|
||||
|
||||
if (!arg->dynamic)
|
||||
{
|
||||
SecPkgContext_AuthNtlmMessage AuthNtlmMessage = WINPR_C_ARRAY_INIT;
|
||||
pSecBuffer->cbBuffer = sizeof(TEST_NTLM_CHALLENGE) - 1;
|
||||
free(pSecBuffer->pvBuffer);
|
||||
pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
|
||||
|
||||
if (!pSecBuffer->pvBuffer)
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_CHALLENGE, pSecBuffer->cbBuffer);
|
||||
AuthNtlmMessage.type = 2;
|
||||
AuthNtlmMessage.length = pSecBuffer->cbBuffer;
|
||||
AuthNtlmMessage.buffer = (BYTE*)pSecBuffer->pvBuffer;
|
||||
SECURITY_STATUS rc = server->table->SetContextAttributes(
|
||||
&server->context, SECPKG_ATTR_AUTH_NTLM_MESSAGE, &AuthNtlmMessage,
|
||||
sizeof(SecPkgContext_AuthNtlmMessage));
|
||||
if (rc != SEC_E_OK)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
(void)fprintf(stderr, "NTLM_CHALLENGE (length = %" PRIu32 "):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
/**
|
||||
* Client <- Challenge Message
|
||||
* Client -> Authenticate Message
|
||||
*/
|
||||
client->haveInputBuffer = TRUE;
|
||||
client->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
client->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
|
||||
client->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
|
||||
status = test_ntlm_client_authenticate(client);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_client_authenticate failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pSecBuffer = &(client->outputBuffer[0]);
|
||||
|
||||
if (!arg->dynamic)
|
||||
{
|
||||
pSecBuffer->cbBuffer = sizeof(TEST_NTLM_AUTHENTICATE) - 1;
|
||||
free(pSecBuffer->pvBuffer);
|
||||
pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
|
||||
|
||||
if (!pSecBuffer->pvBuffer)
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_AUTHENTICATE, pSecBuffer->cbBuffer);
|
||||
}
|
||||
|
||||
(void)fprintf(stderr, "NTLM_AUTHENTICATE (length = %" PRIu32 "):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
/**
|
||||
* Server <- Authenticate Message
|
||||
*/
|
||||
server->haveInputBuffer = TRUE;
|
||||
server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
|
||||
server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
|
||||
status = test_ntlm_server_authenticate(arg, server);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_server_authenticate failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
/**
|
||||
* Cleanup & Termination
|
||||
*/
|
||||
test_ntlm_client_free(client);
|
||||
test_ntlm_server_free(server);
|
||||
|
||||
printf("testcase {user=%s, domain=%s, password=%s, dynamic=%s} returns %d\n", arg->user,
|
||||
arg->domain, arg->pwd, arg->dynamic ? "TRUE" : "FALSE", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TestNTLM(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
const struct test_input_t inputs[] = {
|
||||
{ TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
|
||||
TRUE, TRUE },
|
||||
{ TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
|
||||
FALSE, TRUE },
|
||||
{ TEST_NTLM_USER, TEST_NTLM_DOMAIN, "", TEST_EMPTY_PWD_NTLM_HASH,
|
||||
TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, TRUE },
|
||||
{ TEST_NTLM_USER, TEST_NTLM_DOMAIN, nullptr, TEST_EMPTY_PWD_NTLM_HASH,
|
||||
TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, FALSE }
|
||||
};
|
||||
|
||||
int rc = 0;
|
||||
for (size_t x = 0; x < ARRAYSIZE(inputs); x++)
|
||||
{
|
||||
const struct test_input_t* cur = &inputs[x];
|
||||
const BOOL res = test_default(cur);
|
||||
if (res != cur->expected)
|
||||
rc = -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
34
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestQuerySecurityPackageInfo.c
vendored
Normal file
34
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestQuerySecurityPackageInfo.c
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/tchar.h>
|
||||
|
||||
int TestQuerySecurityPackageInfo(int argc, char* argv[])
|
||||
{
|
||||
int rc = 0;
|
||||
SECURITY_STATUS status = 0;
|
||||
SecPkgInfo* pPackageInfo = nullptr;
|
||||
SecurityFunctionTable* table = nullptr;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
sspi_GlobalInit();
|
||||
table = InitSecurityInterfaceEx(0);
|
||||
|
||||
status = table->QuerySecurityPackageInfo(NTLM_SSP_NAME, &pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
_tprintf(_T("\nQuerySecurityPackageInfo:\n"));
|
||||
_tprintf(_T("\"%s\", \"%s\"\n"), pPackageInfo->Name, pPackageInfo->Comment);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
table->FreeContextBuffer(pPackageInfo);
|
||||
sspi_GlobalFinish();
|
||||
return rc;
|
||||
}
|
||||
854
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestSchannel.c
vendored
Normal file
854
third_party/FreeRDP/winpr/libwinpr/sspi/test/TestSchannel.c
vendored
Normal file
@@ -0,0 +1,854 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/pipe.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/crypto.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/schannel.h>
|
||||
|
||||
static BOOL g_ClientWait = FALSE;
|
||||
static BOOL g_ServerWait = FALSE;
|
||||
|
||||
static HANDLE g_ClientReadPipe = nullptr;
|
||||
static HANDLE g_ClientWritePipe = nullptr;
|
||||
static HANDLE g_ServerReadPipe = nullptr;
|
||||
static HANDLE g_ServerWritePipe = nullptr;
|
||||
|
||||
static const BYTE test_localhost_crt[1029] = {
|
||||
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
|
||||
0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x4D, 0x49, 0x49, 0x43,
|
||||
0x79, 0x6A, 0x43, 0x43, 0x41, 0x62, 0x4B, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x45,
|
||||
0x63, 0x61, 0x64, 0x63, 0x72, 0x7A, 0x41, 0x4E, 0x42, 0x67, 0x6B, 0x71, 0x68, 0x6B, 0x69, 0x47,
|
||||
0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x41, 0x55, 0x4D, 0x52, 0x49, 0x77,
|
||||
0x45, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x77, 0x6C, 0x73, 0x0A, 0x62, 0x32, 0x4E,
|
||||
0x68, 0x62, 0x47, 0x68, 0x76, 0x63, 0x33, 0x51, 0x77, 0x48, 0x68, 0x63, 0x4E, 0x4D, 0x54, 0x4D,
|
||||
0x78, 0x4D, 0x44, 0x45, 0x78, 0x4D, 0x44, 0x59, 0x78, 0x4E, 0x7A, 0x55, 0x31, 0x57, 0x68, 0x63,
|
||||
0x4E, 0x4D, 0x54, 0x51, 0x78, 0x4D, 0x44, 0x45, 0x78, 0x4D, 0x44, 0x59, 0x78, 0x4E, 0x7A, 0x55,
|
||||
0x31, 0x57, 0x6A, 0x41, 0x55, 0x4D, 0x52, 0x49, 0x77, 0x45, 0x41, 0x59, 0x44, 0x0A, 0x56, 0x51,
|
||||
0x51, 0x44, 0x45, 0x77, 0x6C, 0x73, 0x62, 0x32, 0x4E, 0x68, 0x62, 0x47, 0x68, 0x76, 0x63, 0x33,
|
||||
0x51, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4D, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49,
|
||||
0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77,
|
||||
0x41, 0x77, 0x67, 0x67, 0x45, 0x4B, 0x41, 0x6F, 0x49, 0x42, 0x41, 0x51, 0x43, 0x33, 0x0A, 0x65,
|
||||
0x6E, 0x33, 0x68, 0x5A, 0x4F, 0x53, 0x33, 0x6B, 0x51, 0x2F, 0x55, 0x54, 0x30, 0x53, 0x45, 0x6C,
|
||||
0x30, 0x48, 0x6E, 0x50, 0x79, 0x64, 0x48, 0x75, 0x35, 0x39, 0x61, 0x69, 0x71, 0x64, 0x73, 0x64,
|
||||
0x53, 0x55, 0x74, 0x6E, 0x43, 0x41, 0x37, 0x46, 0x66, 0x74, 0x30, 0x4F, 0x36, 0x51, 0x79, 0x68,
|
||||
0x49, 0x71, 0x58, 0x7A, 0x30, 0x47, 0x32, 0x53, 0x76, 0x77, 0x4C, 0x54, 0x62, 0x79, 0x68, 0x0A,
|
||||
0x59, 0x54, 0x68, 0x31, 0x36, 0x78, 0x31, 0x72, 0x45, 0x48, 0x68, 0x31, 0x57, 0x47, 0x5A, 0x6D,
|
||||
0x36, 0x77, 0x64, 0x2B, 0x4B, 0x76, 0x38, 0x6B, 0x31, 0x6B, 0x2F, 0x36, 0x6F, 0x41, 0x2F, 0x4F,
|
||||
0x51, 0x76, 0x65, 0x61, 0x38, 0x6B, 0x63, 0x45, 0x64, 0x53, 0x72, 0x54, 0x64, 0x75, 0x71, 0x4A,
|
||||
0x33, 0x65, 0x66, 0x74, 0x48, 0x4A, 0x4A, 0x6E, 0x43, 0x4B, 0x30, 0x41, 0x62, 0x68, 0x34, 0x39,
|
||||
0x0A, 0x41, 0x47, 0x41, 0x50, 0x39, 0x79, 0x58, 0x77, 0x77, 0x59, 0x41, 0x6A, 0x51, 0x49, 0x52,
|
||||
0x6E, 0x38, 0x2B, 0x4F, 0x63, 0x63, 0x48, 0x74, 0x6F, 0x4E, 0x75, 0x75, 0x79, 0x52, 0x63, 0x6B,
|
||||
0x49, 0x50, 0x71, 0x75, 0x70, 0x78, 0x79, 0x31, 0x4A, 0x5A, 0x4B, 0x39, 0x64, 0x76, 0x76, 0x62,
|
||||
0x34, 0x79, 0x53, 0x6B, 0x49, 0x75, 0x7A, 0x62, 0x79, 0x50, 0x6F, 0x54, 0x41, 0x79, 0x61, 0x55,
|
||||
0x2B, 0x0A, 0x51, 0x72, 0x70, 0x34, 0x78, 0x67, 0x64, 0x4B, 0x46, 0x54, 0x70, 0x6B, 0x50, 0x46,
|
||||
0x34, 0x33, 0x6A, 0x32, 0x4D, 0x6D, 0x5A, 0x72, 0x46, 0x63, 0x42, 0x76, 0x79, 0x6A, 0x69, 0x35,
|
||||
0x6A, 0x4F, 0x37, 0x74, 0x66, 0x6F, 0x56, 0x61, 0x6B, 0x59, 0x47, 0x53, 0x2F, 0x4C, 0x63, 0x78,
|
||||
0x77, 0x47, 0x2B, 0x77, 0x51, 0x77, 0x63, 0x4F, 0x43, 0x54, 0x42, 0x45, 0x78, 0x2F, 0x7A, 0x31,
|
||||
0x53, 0x30, 0x0A, 0x37, 0x49, 0x2F, 0x6A, 0x62, 0x44, 0x79, 0x53, 0x4E, 0x68, 0x44, 0x35, 0x63,
|
||||
0x61, 0x63, 0x54, 0x75, 0x4E, 0x36, 0x50, 0x68, 0x33, 0x58, 0x30, 0x71, 0x70, 0x47, 0x73, 0x37,
|
||||
0x79, 0x50, 0x6B, 0x4E, 0x79, 0x69, 0x4A, 0x33, 0x57, 0x52, 0x69, 0x6C, 0x35, 0x75, 0x57, 0x73,
|
||||
0x4B, 0x65, 0x79, 0x63, 0x64, 0x71, 0x42, 0x4E, 0x72, 0x34, 0x75, 0x32, 0x62, 0x49, 0x52, 0x6E,
|
||||
0x63, 0x54, 0x51, 0x0A, 0x46, 0x72, 0x68, 0x73, 0x58, 0x39, 0x69, 0x77, 0x37, 0x35, 0x76, 0x75,
|
||||
0x53, 0x64, 0x35, 0x46, 0x39, 0x37, 0x56, 0x70, 0x41, 0x67, 0x4D, 0x42, 0x41, 0x41, 0x47, 0x6A,
|
||||
0x4A, 0x44, 0x41, 0x69, 0x4D, 0x42, 0x4D, 0x47, 0x41, 0x31, 0x55, 0x64, 0x4A, 0x51, 0x51, 0x4D,
|
||||
0x4D, 0x41, 0x6F, 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x4D, 0x42,
|
||||
0x4D, 0x41, 0x73, 0x47, 0x0A, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49,
|
||||
0x45, 0x4D, 0x44, 0x41, 0x4E, 0x42, 0x67, 0x6B, 0x71, 0x68, 0x6B, 0x69, 0x47, 0x39, 0x77, 0x30,
|
||||
0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4F, 0x43, 0x41, 0x51, 0x45, 0x41, 0x49, 0x51, 0x66,
|
||||
0x75, 0x2F, 0x77, 0x39, 0x45, 0x34, 0x4C, 0x6F, 0x67, 0x30, 0x71, 0x35, 0x4B, 0x53, 0x38, 0x71,
|
||||
0x46, 0x78, 0x62, 0x36, 0x6F, 0x0A, 0x36, 0x31, 0x62, 0x35, 0x37, 0x6F, 0x6D, 0x6E, 0x46, 0x59,
|
||||
0x52, 0x34, 0x47, 0x43, 0x67, 0x33, 0x6F, 0x6A, 0x4F, 0x4C, 0x54, 0x66, 0x38, 0x7A, 0x6A, 0x4D,
|
||||
0x43, 0x52, 0x6D, 0x75, 0x59, 0x32, 0x76, 0x30, 0x4E, 0x34, 0x78, 0x66, 0x68, 0x69, 0x35, 0x4B,
|
||||
0x69, 0x59, 0x67, 0x64, 0x76, 0x4E, 0x4C, 0x4F, 0x33, 0x52, 0x42, 0x6D, 0x4E, 0x50, 0x76, 0x59,
|
||||
0x58, 0x50, 0x52, 0x46, 0x41, 0x76, 0x0A, 0x66, 0x61, 0x76, 0x66, 0x57, 0x75, 0x6C, 0x44, 0x31,
|
||||
0x64, 0x50, 0x36, 0x31, 0x69, 0x35, 0x62, 0x36, 0x59, 0x66, 0x56, 0x6C, 0x78, 0x62, 0x31, 0x61,
|
||||
0x57, 0x46, 0x37, 0x4C, 0x5A, 0x44, 0x32, 0x55, 0x6E, 0x63, 0x41, 0x6A, 0x37, 0x4E, 0x38, 0x78,
|
||||
0x38, 0x2B, 0x36, 0x58, 0x6B, 0x30, 0x6B, 0x63, 0x70, 0x58, 0x46, 0x38, 0x6C, 0x77, 0x58, 0x48,
|
||||
0x55, 0x57, 0x57, 0x55, 0x6D, 0x73, 0x2B, 0x0A, 0x4B, 0x56, 0x44, 0x34, 0x34, 0x39, 0x68, 0x6F,
|
||||
0x4D, 0x2B, 0x77, 0x4E, 0x4A, 0x49, 0x61, 0x4F, 0x52, 0x39, 0x4C, 0x46, 0x2B, 0x6B, 0x6F, 0x32,
|
||||
0x32, 0x37, 0x7A, 0x74, 0x37, 0x54, 0x41, 0x47, 0x64, 0x56, 0x35, 0x4A, 0x75, 0x7A, 0x71, 0x38,
|
||||
0x32, 0x2F, 0x6B, 0x75, 0x73, 0x6F, 0x65, 0x32, 0x69, 0x75, 0x57, 0x77, 0x54, 0x65, 0x42, 0x6C,
|
||||
0x53, 0x5A, 0x6E, 0x6B, 0x42, 0x38, 0x63, 0x64, 0x0A, 0x77, 0x4D, 0x30, 0x5A, 0x42, 0x58, 0x6D,
|
||||
0x34, 0x35, 0x48, 0x38, 0x6F, 0x79, 0x75, 0x36, 0x4A, 0x71, 0x59, 0x71, 0x45, 0x6D, 0x75, 0x4A,
|
||||
0x51, 0x64, 0x67, 0x79, 0x52, 0x2B, 0x63, 0x53, 0x53, 0x41, 0x7A, 0x2B, 0x4F, 0x32, 0x6D, 0x61,
|
||||
0x62, 0x68, 0x50, 0x5A, 0x65, 0x49, 0x76, 0x78, 0x65, 0x67, 0x6A, 0x6A, 0x61, 0x5A, 0x61, 0x46,
|
||||
0x4F, 0x71, 0x74, 0x73, 0x2B, 0x64, 0x33, 0x72, 0x39, 0x0A, 0x79, 0x71, 0x4A, 0x78, 0x67, 0x75,
|
||||
0x39, 0x43, 0x38, 0x39, 0x5A, 0x69, 0x33, 0x39, 0x57, 0x34, 0x38, 0x46, 0x66, 0x46, 0x63, 0x49,
|
||||
0x58, 0x4A, 0x4F, 0x6B, 0x39, 0x43, 0x4E, 0x46, 0x41, 0x2F, 0x69, 0x70, 0x54, 0x57, 0x6A, 0x74,
|
||||
0x74, 0x4E, 0x2F, 0x6B, 0x4F, 0x6B, 0x5A, 0x42, 0x70, 0x6F, 0x6A, 0x2F, 0x32, 0x6A, 0x4E, 0x45,
|
||||
0x62, 0x4F, 0x59, 0x7A, 0x7A, 0x6E, 0x4B, 0x77, 0x3D, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D,
|
||||
0x45, 0x4E, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D,
|
||||
0x2D, 0x2D, 0x2D, 0x2D, 0x0A
|
||||
};
|
||||
|
||||
static const BYTE test_localhost_key[1704] = {
|
||||
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41,
|
||||
0x54, 0x45, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x4D, 0x49, 0x49, 0x45,
|
||||
0x76, 0x51, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4E, 0x42, 0x67, 0x6B, 0x71, 0x68, 0x6B, 0x69, 0x47,
|
||||
0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x53, 0x43, 0x42, 0x4B, 0x63, 0x77,
|
||||
0x67, 0x67, 0x53, 0x6A, 0x41, 0x67, 0x45, 0x41, 0x41, 0x6F, 0x49, 0x42, 0x41, 0x51, 0x43, 0x33,
|
||||
0x65, 0x6E, 0x33, 0x68, 0x5A, 0x4F, 0x53, 0x33, 0x6B, 0x51, 0x2F, 0x55, 0x0A, 0x54, 0x30, 0x53,
|
||||
0x45, 0x6C, 0x30, 0x48, 0x6E, 0x50, 0x79, 0x64, 0x48, 0x75, 0x35, 0x39, 0x61, 0x69, 0x71, 0x64,
|
||||
0x73, 0x64, 0x53, 0x55, 0x74, 0x6E, 0x43, 0x41, 0x37, 0x46, 0x66, 0x74, 0x30, 0x4F, 0x36, 0x51,
|
||||
0x79, 0x68, 0x49, 0x71, 0x58, 0x7A, 0x30, 0x47, 0x32, 0x53, 0x76, 0x77, 0x4C, 0x54, 0x62, 0x79,
|
||||
0x68, 0x59, 0x54, 0x68, 0x31, 0x36, 0x78, 0x31, 0x72, 0x45, 0x48, 0x68, 0x31, 0x0A, 0x57, 0x47,
|
||||
0x5A, 0x6D, 0x36, 0x77, 0x64, 0x2B, 0x4B, 0x76, 0x38, 0x6B, 0x31, 0x6B, 0x2F, 0x36, 0x6F, 0x41,
|
||||
0x2F, 0x4F, 0x51, 0x76, 0x65, 0x61, 0x38, 0x6B, 0x63, 0x45, 0x64, 0x53, 0x72, 0x54, 0x64, 0x75,
|
||||
0x71, 0x4A, 0x33, 0x65, 0x66, 0x74, 0x48, 0x4A, 0x4A, 0x6E, 0x43, 0x4B, 0x30, 0x41, 0x62, 0x68,
|
||||
0x34, 0x39, 0x41, 0x47, 0x41, 0x50, 0x39, 0x79, 0x58, 0x77, 0x77, 0x59, 0x41, 0x6A, 0x0A, 0x51,
|
||||
0x49, 0x52, 0x6E, 0x38, 0x2B, 0x4F, 0x63, 0x63, 0x48, 0x74, 0x6F, 0x4E, 0x75, 0x75, 0x79, 0x52,
|
||||
0x63, 0x6B, 0x49, 0x50, 0x71, 0x75, 0x70, 0x78, 0x79, 0x31, 0x4A, 0x5A, 0x4B, 0x39, 0x64, 0x76,
|
||||
0x76, 0x62, 0x34, 0x79, 0x53, 0x6B, 0x49, 0x75, 0x7A, 0x62, 0x79, 0x50, 0x6F, 0x54, 0x41, 0x79,
|
||||
0x61, 0x55, 0x2B, 0x51, 0x72, 0x70, 0x34, 0x78, 0x67, 0x64, 0x4B, 0x46, 0x54, 0x70, 0x6B, 0x0A,
|
||||
0x50, 0x46, 0x34, 0x33, 0x6A, 0x32, 0x4D, 0x6D, 0x5A, 0x72, 0x46, 0x63, 0x42, 0x76, 0x79, 0x6A,
|
||||
0x69, 0x35, 0x6A, 0x4F, 0x37, 0x74, 0x66, 0x6F, 0x56, 0x61, 0x6B, 0x59, 0x47, 0x53, 0x2F, 0x4C,
|
||||
0x63, 0x78, 0x77, 0x47, 0x2B, 0x77, 0x51, 0x77, 0x63, 0x4F, 0x43, 0x54, 0x42, 0x45, 0x78, 0x2F,
|
||||
0x7A, 0x31, 0x53, 0x30, 0x37, 0x49, 0x2F, 0x6A, 0x62, 0x44, 0x79, 0x53, 0x4E, 0x68, 0x44, 0x35,
|
||||
0x0A, 0x63, 0x61, 0x63, 0x54, 0x75, 0x4E, 0x36, 0x50, 0x68, 0x33, 0x58, 0x30, 0x71, 0x70, 0x47,
|
||||
0x73, 0x37, 0x79, 0x50, 0x6B, 0x4E, 0x79, 0x69, 0x4A, 0x33, 0x57, 0x52, 0x69, 0x6C, 0x35, 0x75,
|
||||
0x57, 0x73, 0x4B, 0x65, 0x79, 0x63, 0x64, 0x71, 0x42, 0x4E, 0x72, 0x34, 0x75, 0x32, 0x62, 0x49,
|
||||
0x52, 0x6E, 0x63, 0x54, 0x51, 0x46, 0x72, 0x68, 0x73, 0x58, 0x39, 0x69, 0x77, 0x37, 0x35, 0x76,
|
||||
0x75, 0x0A, 0x53, 0x64, 0x35, 0x46, 0x39, 0x37, 0x56, 0x70, 0x41, 0x67, 0x4D, 0x42, 0x41, 0x41,
|
||||
0x45, 0x43, 0x67, 0x67, 0x45, 0x41, 0x42, 0x36, 0x6A, 0x6C, 0x65, 0x48, 0x4E, 0x74, 0x32, 0x50,
|
||||
0x77, 0x46, 0x58, 0x53, 0x65, 0x79, 0x42, 0x4A, 0x63, 0x4C, 0x2B, 0x55, 0x74, 0x35, 0x71, 0x46,
|
||||
0x54, 0x38, 0x34, 0x68, 0x72, 0x48, 0x77, 0x6F, 0x39, 0x68, 0x62, 0x66, 0x59, 0x47, 0x6F, 0x6E,
|
||||
0x44, 0x59, 0x0A, 0x66, 0x70, 0x47, 0x2B, 0x32, 0x52, 0x30, 0x50, 0x62, 0x43, 0x63, 0x4B, 0x35,
|
||||
0x30, 0x46, 0x61, 0x4A, 0x46, 0x36, 0x71, 0x63, 0x56, 0x4A, 0x4E, 0x75, 0x52, 0x36, 0x48, 0x71,
|
||||
0x2B, 0x43, 0x55, 0x4A, 0x74, 0x48, 0x35, 0x39, 0x48, 0x48, 0x37, 0x62, 0x68, 0x6A, 0x39, 0x62,
|
||||
0x64, 0x78, 0x45, 0x6D, 0x6F, 0x48, 0x30, 0x4A, 0x76, 0x68, 0x45, 0x76, 0x67, 0x4D, 0x2F, 0x55,
|
||||
0x38, 0x42, 0x51, 0x0A, 0x65, 0x57, 0x4F, 0x4E, 0x68, 0x78, 0x50, 0x73, 0x69, 0x73, 0x6D, 0x57,
|
||||
0x6B, 0x78, 0x61, 0x5A, 0x6F, 0x6C, 0x72, 0x32, 0x69, 0x44, 0x56, 0x72, 0x7A, 0x54, 0x37, 0x55,
|
||||
0x4A, 0x71, 0x6A, 0x74, 0x59, 0x49, 0x74, 0x67, 0x2B, 0x37, 0x59, 0x43, 0x32, 0x70, 0x55, 0x58,
|
||||
0x6B, 0x64, 0x49, 0x35, 0x4A, 0x4D, 0x67, 0x6C, 0x44, 0x47, 0x4D, 0x52, 0x5A, 0x35, 0x55, 0x5A,
|
||||
0x48, 0x75, 0x63, 0x7A, 0x0A, 0x41, 0x56, 0x2B, 0x71, 0x77, 0x77, 0x33, 0x65, 0x45, 0x52, 0x74,
|
||||
0x78, 0x44, 0x50, 0x61, 0x61, 0x61, 0x34, 0x54, 0x39, 0x50, 0x64, 0x33, 0x44, 0x31, 0x6D, 0x62,
|
||||
0x71, 0x58, 0x66, 0x75, 0x45, 0x68, 0x42, 0x6D, 0x33, 0x51, 0x6F, 0x2B, 0x75, 0x7A, 0x51, 0x32,
|
||||
0x36, 0x76, 0x73, 0x66, 0x48, 0x75, 0x56, 0x76, 0x61, 0x39, 0x38, 0x32, 0x4F, 0x6A, 0x41, 0x55,
|
||||
0x6A, 0x6E, 0x64, 0x30, 0x70, 0x0A, 0x77, 0x43, 0x53, 0x6E, 0x42, 0x49, 0x48, 0x67, 0x70, 0x73,
|
||||
0x30, 0x79, 0x61, 0x45, 0x50, 0x63, 0x37, 0x46, 0x78, 0x39, 0x71, 0x45, 0x63, 0x6D, 0x33, 0x70,
|
||||
0x7A, 0x41, 0x56, 0x31, 0x69, 0x72, 0x31, 0x4E, 0x4E, 0x63, 0x51, 0x47, 0x55, 0x45, 0x75, 0x45,
|
||||
0x6C, 0x4A, 0x78, 0x76, 0x2B, 0x69, 0x57, 0x34, 0x6D, 0x35, 0x70, 0x7A, 0x4C, 0x6A, 0x64, 0x53,
|
||||
0x63, 0x49, 0x30, 0x59, 0x45, 0x73, 0x0A, 0x4D, 0x61, 0x33, 0x78, 0x32, 0x79, 0x48, 0x74, 0x6E,
|
||||
0x77, 0x79, 0x65, 0x4C, 0x4D, 0x54, 0x4B, 0x6C, 0x72, 0x46, 0x4B, 0x70, 0x55, 0x4E, 0x4A, 0x62,
|
||||
0x78, 0x73, 0x35, 0x32, 0x62, 0x5A, 0x4B, 0x71, 0x49, 0x56, 0x33, 0x33, 0x4A, 0x53, 0x34, 0x41,
|
||||
0x51, 0x4B, 0x42, 0x67, 0x51, 0x44, 0x73, 0x4C, 0x54, 0x49, 0x68, 0x35, 0x59, 0x38, 0x4C, 0x2F,
|
||||
0x48, 0x33, 0x64, 0x74, 0x68, 0x63, 0x62, 0x0A, 0x53, 0x43, 0x45, 0x77, 0x32, 0x64, 0x42, 0x49,
|
||||
0x76, 0x49, 0x79, 0x54, 0x7A, 0x39, 0x53, 0x72, 0x62, 0x33, 0x58, 0x37, 0x37, 0x41, 0x77, 0x57,
|
||||
0x45, 0x4C, 0x53, 0x4D, 0x49, 0x57, 0x53, 0x50, 0x55, 0x43, 0x4B, 0x54, 0x49, 0x70, 0x6A, 0x4D,
|
||||
0x73, 0x6E, 0x7A, 0x6B, 0x46, 0x67, 0x32, 0x32, 0x59, 0x32, 0x53, 0x75, 0x47, 0x38, 0x4C, 0x72,
|
||||
0x50, 0x6D, 0x76, 0x73, 0x46, 0x4A, 0x34, 0x30, 0x0A, 0x32, 0x67, 0x35, 0x44, 0x55, 0x6C, 0x59,
|
||||
0x33, 0x59, 0x6D, 0x53, 0x4F, 0x46, 0x61, 0x45, 0x4A, 0x54, 0x70, 0x55, 0x47, 0x44, 0x4D, 0x79,
|
||||
0x65, 0x33, 0x74, 0x36, 0x4F, 0x30, 0x6C, 0x63, 0x51, 0x41, 0x66, 0x79, 0x6D, 0x58, 0x66, 0x41,
|
||||
0x38, 0x74, 0x50, 0x42, 0x48, 0x6A, 0x5A, 0x78, 0x56, 0x61, 0x38, 0x78, 0x78, 0x52, 0x5A, 0x6E,
|
||||
0x56, 0x43, 0x31, 0x41, 0x62, 0x75, 0x49, 0x49, 0x52, 0x0A, 0x6E, 0x77, 0x72, 0x4E, 0x46, 0x2B,
|
||||
0x42, 0x6F, 0x53, 0x4B, 0x55, 0x41, 0x73, 0x78, 0x2B, 0x46, 0x75, 0x35, 0x5A, 0x4A, 0x4B, 0x4F,
|
||||
0x66, 0x79, 0x4D, 0x51, 0x4B, 0x42, 0x67, 0x51, 0x44, 0x47, 0x34, 0x50, 0x52, 0x39, 0x2F, 0x58,
|
||||
0x58, 0x6B, 0x51, 0x54, 0x36, 0x6B, 0x7A, 0x4B, 0x64, 0x34, 0x50, 0x6C, 0x50, 0x4D, 0x63, 0x2B,
|
||||
0x4B, 0x51, 0x79, 0x4C, 0x45, 0x6C, 0x4B, 0x39, 0x71, 0x47, 0x0A, 0x41, 0x6D, 0x6E, 0x2F, 0x31,
|
||||
0x68, 0x64, 0x69, 0x57, 0x57, 0x4F, 0x52, 0x57, 0x46, 0x62, 0x32, 0x38, 0x30, 0x4D, 0x77, 0x76,
|
||||
0x77, 0x41, 0x64, 0x78, 0x72, 0x66, 0x65, 0x4C, 0x57, 0x4D, 0x57, 0x32, 0x66, 0x76, 0x4C, 0x59,
|
||||
0x4B, 0x66, 0x6C, 0x4F, 0x35, 0x50, 0x51, 0x44, 0x59, 0x67, 0x4B, 0x4A, 0x78, 0x35, 0x79, 0x50,
|
||||
0x37, 0x52, 0x64, 0x38, 0x2F, 0x64, 0x50, 0x79, 0x5A, 0x59, 0x36, 0x0A, 0x7A, 0x56, 0x37, 0x47,
|
||||
0x47, 0x6B, 0x51, 0x5A, 0x42, 0x4B, 0x36, 0x79, 0x74, 0x61, 0x66, 0x32, 0x35, 0x44, 0x50, 0x67,
|
||||
0x50, 0x72, 0x32, 0x77, 0x73, 0x59, 0x4D, 0x43, 0x6C, 0x53, 0x74, 0x6C, 0x56, 0x74, 0x72, 0x6D,
|
||||
0x4F, 0x78, 0x59, 0x55, 0x56, 0x77, 0x42, 0x59, 0x4F, 0x69, 0x36, 0x45, 0x62, 0x50, 0x69, 0x6B,
|
||||
0x78, 0x47, 0x48, 0x5A, 0x70, 0x59, 0x6F, 0x5A, 0x5A, 0x70, 0x68, 0x4A, 0x0A, 0x4E, 0x61, 0x38,
|
||||
0x4F, 0x4C, 0x31, 0x69, 0x77, 0x75, 0x51, 0x4B, 0x42, 0x67, 0x51, 0x44, 0x42, 0x55, 0x55, 0x31,
|
||||
0x54, 0x79, 0x5A, 0x2B, 0x4A, 0x5A, 0x43, 0x64, 0x79, 0x72, 0x33, 0x58, 0x43, 0x63, 0x77, 0x77,
|
||||
0x58, 0x2F, 0x48, 0x49, 0x73, 0x31, 0x34, 0x6B, 0x4B, 0x42, 0x48, 0x68, 0x44, 0x79, 0x33, 0x78,
|
||||
0x37, 0x74, 0x50, 0x38, 0x2F, 0x6F, 0x48, 0x54, 0x6F, 0x72, 0x76, 0x79, 0x74, 0x0A, 0x41, 0x68,
|
||||
0x38, 0x4B, 0x36, 0x4B, 0x72, 0x43, 0x41, 0x75, 0x65, 0x50, 0x6D, 0x79, 0x32, 0x6D, 0x4F, 0x54,
|
||||
0x31, 0x54, 0x39, 0x6F, 0x31, 0x61, 0x47, 0x55, 0x49, 0x6C, 0x66, 0x38, 0x72, 0x76, 0x33, 0x2F,
|
||||
0x30, 0x45, 0x78, 0x67, 0x53, 0x6B, 0x57, 0x50, 0x6D, 0x4F, 0x41, 0x38, 0x35, 0x49, 0x32, 0x2F,
|
||||
0x58, 0x48, 0x65, 0x66, 0x71, 0x54, 0x6F, 0x45, 0x48, 0x30, 0x44, 0x65, 0x41, 0x4E, 0x0A, 0x7A,
|
||||
0x6C, 0x4B, 0x4C, 0x71, 0x79, 0x44, 0x56, 0x30, 0x42, 0x56, 0x4E, 0x76, 0x48, 0x42, 0x57, 0x79,
|
||||
0x32, 0x49, 0x51, 0x35, 0x62, 0x50, 0x42, 0x57, 0x76, 0x30, 0x37, 0x63, 0x34, 0x2B, 0x6A, 0x39,
|
||||
0x4E, 0x62, 0x57, 0x67, 0x64, 0x44, 0x43, 0x43, 0x35, 0x52, 0x6B, 0x4F, 0x6A, 0x70, 0x33, 0x4D,
|
||||
0x4E, 0x45, 0x58, 0x47, 0x56, 0x43, 0x69, 0x51, 0x51, 0x4B, 0x42, 0x67, 0x43, 0x7A, 0x4D, 0x0A,
|
||||
0x77, 0x65, 0x61, 0x62, 0x73, 0x50, 0x48, 0x68, 0x44, 0x4B, 0x5A, 0x38, 0x2F, 0x34, 0x43, 0x6A,
|
||||
0x73, 0x61, 0x62, 0x4E, 0x75, 0x41, 0x7A, 0x62, 0x57, 0x4B, 0x52, 0x42, 0x38, 0x37, 0x44, 0x61,
|
||||
0x58, 0x46, 0x78, 0x6F, 0x4D, 0x73, 0x35, 0x52, 0x79, 0x6F, 0x38, 0x55, 0x4D, 0x6B, 0x72, 0x67,
|
||||
0x30, 0x35, 0x4C, 0x6F, 0x67, 0x37, 0x4D, 0x78, 0x62, 0x33, 0x76, 0x61, 0x42, 0x34, 0x63, 0x2F,
|
||||
0x0A, 0x52, 0x57, 0x77, 0x7A, 0x38, 0x72, 0x34, 0x39, 0x70, 0x48, 0x64, 0x71, 0x68, 0x4F, 0x6D,
|
||||
0x63, 0x6C, 0x45, 0x77, 0x79, 0x4D, 0x34, 0x51, 0x79, 0x6A, 0x39, 0x52, 0x6D, 0x57, 0x62, 0x51,
|
||||
0x58, 0x54, 0x54, 0x45, 0x63, 0x2B, 0x35, 0x67, 0x54, 0x4B, 0x50, 0x4E, 0x53, 0x33, 0x6D, 0x70,
|
||||
0x4D, 0x54, 0x36, 0x39, 0x46, 0x45, 0x74, 0x2F, 0x35, 0x72, 0x4D, 0x52, 0x70, 0x4B, 0x2B, 0x52,
|
||||
0x68, 0x0A, 0x49, 0x32, 0x42, 0x58, 0x6B, 0x51, 0x71, 0x31, 0x36, 0x6E, 0x72, 0x31, 0x61, 0x45,
|
||||
0x4D, 0x6D, 0x64, 0x51, 0x42, 0x51, 0x79, 0x4B, 0x59, 0x4A, 0x6C, 0x30, 0x6C, 0x50, 0x68, 0x69,
|
||||
0x42, 0x2F, 0x75, 0x6C, 0x5A, 0x63, 0x72, 0x67, 0x4C, 0x70, 0x41, 0x6F, 0x47, 0x41, 0x65, 0x30,
|
||||
0x65, 0x74, 0x50, 0x4A, 0x77, 0x6D, 0x51, 0x46, 0x6B, 0x6A, 0x4D, 0x70, 0x66, 0x4D, 0x44, 0x61,
|
||||
0x4E, 0x34, 0x0A, 0x70, 0x7A, 0x71, 0x45, 0x51, 0x72, 0x52, 0x35, 0x4B, 0x35, 0x4D, 0x6E, 0x54,
|
||||
0x48, 0x76, 0x47, 0x67, 0x2F, 0x70, 0x6A, 0x57, 0x6A, 0x43, 0x57, 0x58, 0x56, 0x48, 0x67, 0x35,
|
||||
0x76, 0x36, 0x46, 0x6F, 0x5A, 0x48, 0x35, 0x6E, 0x59, 0x2B, 0x56, 0x2F, 0x57, 0x75, 0x57, 0x38,
|
||||
0x38, 0x6A, 0x6C, 0x4B, 0x53, 0x50, 0x6C, 0x77, 0x6A, 0x50, 0x7A, 0x41, 0x67, 0x7A, 0x47, 0x33,
|
||||
0x45, 0x41, 0x55, 0x0A, 0x71, 0x57, 0x6B, 0x42, 0x67, 0x30, 0x71, 0x75, 0x50, 0x4D, 0x72, 0x54,
|
||||
0x6B, 0x73, 0x69, 0x6E, 0x58, 0x50, 0x2B, 0x58, 0x6B, 0x51, 0x65, 0x46, 0x66, 0x58, 0x61, 0x33,
|
||||
0x38, 0x6A, 0x72, 0x70, 0x62, 0x4B, 0x46, 0x4F, 0x72, 0x7A, 0x49, 0x6F, 0x6A, 0x69, 0x65, 0x6C,
|
||||
0x4B, 0x55, 0x4D, 0x50, 0x4D, 0x78, 0x2F, 0x78, 0x70, 0x53, 0x6A, 0x63, 0x55, 0x42, 0x68, 0x62,
|
||||
0x4E, 0x34, 0x45, 0x54, 0x0A, 0x4F, 0x30, 0x66, 0x63, 0x57, 0x47, 0x6F, 0x61, 0x56, 0x50, 0x72,
|
||||
0x63, 0x6E, 0x38, 0x62, 0x58, 0x4D, 0x54, 0x45, 0x4E, 0x53, 0x31, 0x41, 0x3D, 0x0A, 0x2D, 0x2D,
|
||||
0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4B,
|
||||
0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A
|
||||
};
|
||||
|
||||
static const BYTE test_DummyMessage[64] = {
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
|
||||
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD
|
||||
};
|
||||
|
||||
static const BYTE test_LastDummyMessage[64] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static int schannel_send(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phContext,
|
||||
BYTE* buffer, UINT32 length)
|
||||
{
|
||||
BYTE* ioBuffer;
|
||||
UINT32 ioBufferLength;
|
||||
BYTE* pMessageBuffer;
|
||||
SecBuffer Buffers[4] = WINPR_C_ARRAY_INIT;
|
||||
SecBufferDesc Message;
|
||||
SECURITY_STATUS status;
|
||||
DWORD NumberOfBytesWritten;
|
||||
SecPkgContext_StreamSizes StreamSizes = WINPR_C_ARRAY_INIT;
|
||||
|
||||
status = table->QueryContextAttributes(phContext, SECPKG_ATTR_STREAM_SIZES, &StreamSizes);
|
||||
ioBufferLength = StreamSizes.cbHeader + StreamSizes.cbMaximumMessage + StreamSizes.cbTrailer;
|
||||
ioBuffer = (BYTE*)calloc(1, ioBufferLength);
|
||||
if (!ioBuffer)
|
||||
return -1;
|
||||
pMessageBuffer = ioBuffer + StreamSizes.cbHeader;
|
||||
CopyMemory(pMessageBuffer, buffer, length);
|
||||
Buffers[0].pvBuffer = ioBuffer;
|
||||
Buffers[0].cbBuffer = StreamSizes.cbHeader;
|
||||
Buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
|
||||
Buffers[1].pvBuffer = pMessageBuffer;
|
||||
Buffers[1].cbBuffer = length;
|
||||
Buffers[1].BufferType = SECBUFFER_DATA;
|
||||
Buffers[2].pvBuffer = pMessageBuffer + length;
|
||||
Buffers[2].cbBuffer = StreamSizes.cbTrailer;
|
||||
Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
|
||||
Buffers[3].pvBuffer = nullptr;
|
||||
Buffers[3].cbBuffer = 0;
|
||||
Buffers[3].BufferType = SECBUFFER_EMPTY;
|
||||
Message.ulVersion = SECBUFFER_VERSION;
|
||||
Message.cBuffers = 4;
|
||||
Message.pBuffers = Buffers;
|
||||
ioBufferLength =
|
||||
Message.pBuffers[0].cbBuffer + Message.pBuffers[1].cbBuffer + Message.pBuffers[2].cbBuffer;
|
||||
status = table->EncryptMessage(phContext, 0, &Message, 0);
|
||||
printf("EncryptMessage status: 0x%08" PRIX32 "\n", status);
|
||||
printf("EncryptMessage output: cBuffers: %" PRIu32 " [0]: %" PRIu32 " / %" PRIu32
|
||||
" [1]: %" PRIu32 " / %" PRIu32 " [2]: %" PRIu32 " / %" PRIu32 " [3]: %" PRIu32
|
||||
" / %" PRIu32 "\n",
|
||||
Message.cBuffers, Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType,
|
||||
Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType,
|
||||
Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType,
|
||||
Message.pBuffers[3].cbBuffer, Message.pBuffers[3].BufferType);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
return -1;
|
||||
|
||||
printf("Client > Server (%" PRIu32 ")\n", ioBufferLength);
|
||||
winpr_HexDump("sspi.test", WLOG_DEBUG, ioBuffer, ioBufferLength);
|
||||
|
||||
if (!WriteFile(hPipe, ioBuffer, ioBufferLength, &NumberOfBytesWritten, nullptr))
|
||||
{
|
||||
printf("schannel_send: failed to write to pipe\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int schannel_recv(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phContext)
|
||||
{
|
||||
BYTE* ioBuffer;
|
||||
UINT32 ioBufferLength;
|
||||
// BYTE* pMessageBuffer;
|
||||
SecBuffer Buffers[4] = WINPR_C_ARRAY_INIT;
|
||||
SecBufferDesc Message;
|
||||
SECURITY_STATUS status;
|
||||
DWORD NumberOfBytesRead;
|
||||
SecPkgContext_StreamSizes StreamSizes = WINPR_C_ARRAY_INIT;
|
||||
|
||||
status = table->QueryContextAttributes(phContext, SECPKG_ATTR_STREAM_SIZES, &StreamSizes);
|
||||
ioBufferLength = StreamSizes.cbHeader + StreamSizes.cbMaximumMessage + StreamSizes.cbTrailer;
|
||||
ioBuffer = (BYTE*)calloc(1, ioBufferLength);
|
||||
if (!ioBuffer)
|
||||
return -1;
|
||||
|
||||
if (!ReadFile(hPipe, ioBuffer, ioBufferLength, &NumberOfBytesRead, nullptr))
|
||||
{
|
||||
printf("schannel_recv: failed to read from pipe\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Buffers[0].pvBuffer = ioBuffer;
|
||||
Buffers[0].cbBuffer = NumberOfBytesRead;
|
||||
Buffers[0].BufferType = SECBUFFER_DATA;
|
||||
Buffers[1].pvBuffer = nullptr;
|
||||
Buffers[1].cbBuffer = 0;
|
||||
Buffers[1].BufferType = SECBUFFER_EMPTY;
|
||||
Buffers[2].pvBuffer = nullptr;
|
||||
Buffers[2].cbBuffer = 0;
|
||||
Buffers[2].BufferType = SECBUFFER_EMPTY;
|
||||
Buffers[3].pvBuffer = nullptr;
|
||||
Buffers[3].cbBuffer = 0;
|
||||
Buffers[3].BufferType = SECBUFFER_EMPTY;
|
||||
Message.ulVersion = SECBUFFER_VERSION;
|
||||
Message.cBuffers = 4;
|
||||
Message.pBuffers = Buffers;
|
||||
status = table->DecryptMessage(phContext, &Message, 0, nullptr);
|
||||
printf("DecryptMessage status: 0x%08" PRIX32 "\n", status);
|
||||
printf("DecryptMessage output: cBuffers: %" PRIu32 " [0]: %" PRIu32 " / %" PRIu32
|
||||
" [1]: %" PRIu32 " / %" PRIu32 " [2]: %" PRIu32 " / %" PRIu32 " [3]: %" PRIu32
|
||||
" / %" PRIu32 "\n",
|
||||
Message.cBuffers, Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType,
|
||||
Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType,
|
||||
Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType,
|
||||
Message.pBuffers[3].cbBuffer, Message.pBuffers[3].BufferType);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
return -1;
|
||||
|
||||
printf("Decrypted Message (%" PRIu32 ")\n", Message.pBuffers[1].cbBuffer);
|
||||
winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*)Message.pBuffers[1].pvBuffer,
|
||||
Message.pBuffers[1].cbBuffer);
|
||||
|
||||
if (memcmp(Message.pBuffers[1].pvBuffer, test_LastDummyMessage,
|
||||
sizeof(test_LastDummyMessage)) == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI schannel_test_server_thread(LPVOID arg)
|
||||
{
|
||||
BOOL extraData;
|
||||
BYTE* lpTokenIn;
|
||||
BYTE* lpTokenOut;
|
||||
TimeStamp expiry;
|
||||
UINT32 cbMaxToken;
|
||||
UINT32 fContextReq;
|
||||
ULONG fContextAttr;
|
||||
SCHANNEL_CRED cred = WINPR_C_ARRAY_INIT;
|
||||
CtxtHandle context;
|
||||
CredHandle credentials;
|
||||
DWORD cchNameString;
|
||||
LPTSTR pszNameString;
|
||||
HCERTSTORE hCertStore;
|
||||
PCCERT_CONTEXT pCertContext;
|
||||
PSecBuffer pSecBuffer;
|
||||
SecBuffer SecBuffer_in[2] = WINPR_C_ARRAY_INIT;
|
||||
SecBuffer SecBuffer_out[2] = WINPR_C_ARRAY_INIT;
|
||||
SecBufferDesc SecBufferDesc_in;
|
||||
SecBufferDesc SecBufferDesc_out;
|
||||
DWORD NumberOfBytesRead;
|
||||
SECURITY_STATUS status;
|
||||
PSecPkgInfo pPackageInfo;
|
||||
PSecurityFunctionTable table;
|
||||
DWORD NumberOfBytesWritten;
|
||||
printf("Starting Server\n");
|
||||
SecInvalidateHandle(&context);
|
||||
SecInvalidateHandle(&credentials);
|
||||
table = InitSecurityInterface();
|
||||
status = QuerySecurityPackageInfo(SCHANNEL_NAME, &pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("QuerySecurityPackageInfo failure: 0x%08" PRIX32 "\n", status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cbMaxToken = pPackageInfo->cbMaxToken;
|
||||
hCertStore = CertOpenSystemStore(0, _T("MY"));
|
||||
|
||||
if (!hCertStore)
|
||||
{
|
||||
printf("Error opening system store\n");
|
||||
// return nullptr;
|
||||
}
|
||||
|
||||
#ifdef CERT_FIND_HAS_PRIVATE_KEY
|
||||
pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0,
|
||||
CERT_FIND_HAS_PRIVATE_KEY, nullptr, nullptr);
|
||||
#else
|
||||
pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY,
|
||||
nullptr, nullptr);
|
||||
#endif
|
||||
|
||||
if (!pCertContext)
|
||||
{
|
||||
printf("Error finding certificate in store\n");
|
||||
// return nullptr;
|
||||
}
|
||||
|
||||
cchNameString =
|
||||
CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr, nullptr, 0);
|
||||
pszNameString = (LPTSTR)malloc(cchNameString * sizeof(TCHAR));
|
||||
if (!pszNameString)
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
return 0;
|
||||
}
|
||||
cchNameString = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr,
|
||||
pszNameString, cchNameString);
|
||||
_tprintf(_T("Certificate Name: %s\n"), pszNameString);
|
||||
cred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
cred.cCreds = 1;
|
||||
cred.paCred = &pCertContext;
|
||||
cred.cSupportedAlgs = 0;
|
||||
cred.palgSupportedAlgs = nullptr;
|
||||
cred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER;
|
||||
cred.dwFlags = SCH_CRED_NO_SYSTEM_MAPPER;
|
||||
status = table->AcquireCredentialsHandle(nullptr, SCHANNEL_NAME, SECPKG_CRED_INBOUND, nullptr,
|
||||
&cred, nullptr, nullptr, &credentials, nullptr);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("AcquireCredentialsHandle failure: 0x%08" PRIX32 "\n", status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extraData = FALSE;
|
||||
g_ServerWait = TRUE;
|
||||
if (!(lpTokenIn = (BYTE*)malloc(cbMaxToken)))
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (!(lpTokenOut = (BYTE*)malloc(cbMaxToken)))
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
free(lpTokenIn);
|
||||
return 0;
|
||||
}
|
||||
fContextReq = ASC_REQ_STREAM | ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT |
|
||||
ASC_REQ_CONFIDENTIALITY | ASC_REQ_EXTENDED_ERROR;
|
||||
|
||||
do
|
||||
{
|
||||
if (!extraData)
|
||||
{
|
||||
if (g_ServerWait)
|
||||
{
|
||||
if (!ReadFile(g_ServerReadPipe, lpTokenIn, cbMaxToken, &NumberOfBytesRead, nullptr))
|
||||
{
|
||||
printf("Failed to read from server pipe\n");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NumberOfBytesRead = 0;
|
||||
}
|
||||
}
|
||||
|
||||
extraData = FALSE;
|
||||
g_ServerWait = TRUE;
|
||||
SecBuffer_in[0].BufferType = SECBUFFER_TOKEN;
|
||||
SecBuffer_in[0].pvBuffer = lpTokenIn;
|
||||
SecBuffer_in[0].cbBuffer = NumberOfBytesRead;
|
||||
SecBuffer_in[1].BufferType = SECBUFFER_EMPTY;
|
||||
SecBuffer_in[1].pvBuffer = nullptr;
|
||||
SecBuffer_in[1].cbBuffer = 0;
|
||||
SecBufferDesc_in.ulVersion = SECBUFFER_VERSION;
|
||||
SecBufferDesc_in.cBuffers = 2;
|
||||
SecBufferDesc_in.pBuffers = SecBuffer_in;
|
||||
SecBuffer_out[0].BufferType = SECBUFFER_TOKEN;
|
||||
SecBuffer_out[0].pvBuffer = lpTokenOut;
|
||||
SecBuffer_out[0].cbBuffer = cbMaxToken;
|
||||
SecBufferDesc_out.ulVersion = SECBUFFER_VERSION;
|
||||
SecBufferDesc_out.cBuffers = 1;
|
||||
SecBufferDesc_out.pBuffers = SecBuffer_out;
|
||||
status = table->AcceptSecurityContext(
|
||||
&credentials, SecIsValidHandle(&context) ? &context : nullptr, &SecBufferDesc_in,
|
||||
fContextReq, 0, &context, &SecBufferDesc_out, &fContextAttr, &expiry);
|
||||
|
||||
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED) &&
|
||||
(status != SEC_E_INCOMPLETE_MESSAGE))
|
||||
{
|
||||
printf("AcceptSecurityContext unexpected status: 0x%08" PRIX32 "\n", status);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NumberOfBytesWritten = 0;
|
||||
|
||||
if (status == SEC_E_OK)
|
||||
printf("AcceptSecurityContext status: SEC_E_OK\n");
|
||||
else if (status == SEC_I_CONTINUE_NEEDED)
|
||||
printf("AcceptSecurityContext status: SEC_I_CONTINUE_NEEDED\n");
|
||||
else if (status == SEC_E_INCOMPLETE_MESSAGE)
|
||||
printf("AcceptSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n");
|
||||
|
||||
printf("Server cBuffers: %" PRIu32 " pBuffers[0]: %" PRIu32 " type: %" PRIu32 "\n",
|
||||
SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer,
|
||||
SecBufferDesc_out.pBuffers[0].BufferType);
|
||||
printf("Server Input cBuffers: %" PRIu32 " pBuffers[0]: %" PRIu32 " type: %" PRIu32
|
||||
" pBuffers[1]: %" PRIu32 " type: %" PRIu32 "\n",
|
||||
SecBufferDesc_in.cBuffers, SecBufferDesc_in.pBuffers[0].cbBuffer,
|
||||
SecBufferDesc_in.pBuffers[0].BufferType, SecBufferDesc_in.pBuffers[1].cbBuffer,
|
||||
SecBufferDesc_in.pBuffers[1].BufferType);
|
||||
|
||||
if (SecBufferDesc_in.pBuffers[1].BufferType == SECBUFFER_EXTRA)
|
||||
{
|
||||
printf("AcceptSecurityContext SECBUFFER_EXTRA\n");
|
||||
pSecBuffer = &SecBufferDesc_in.pBuffers[1];
|
||||
CopyMemory(lpTokenIn, &lpTokenIn[NumberOfBytesRead - pSecBuffer->cbBuffer],
|
||||
pSecBuffer->cbBuffer);
|
||||
NumberOfBytesRead = pSecBuffer->cbBuffer;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status != SEC_E_INCOMPLETE_MESSAGE)
|
||||
{
|
||||
pSecBuffer = &SecBufferDesc_out.pBuffers[0];
|
||||
|
||||
if (pSecBuffer->cbBuffer > 0)
|
||||
{
|
||||
printf("Server > Client (%" PRIu32 ")\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer,
|
||||
pSecBuffer->cbBuffer);
|
||||
|
||||
if (!WriteFile(g_ClientWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer,
|
||||
&NumberOfBytesWritten, nullptr))
|
||||
{
|
||||
printf("failed to write to client pipe\n");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status == SEC_E_OK)
|
||||
{
|
||||
printf("Server Handshake Complete\n");
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
do
|
||||
{
|
||||
if (schannel_recv(table, g_ServerReadPipe, &context) < 0)
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_test_certificate_files(void)
|
||||
{
|
||||
FILE* fp;
|
||||
char* fullpath = nullptr;
|
||||
int ret = -1;
|
||||
|
||||
/*
|
||||
* Output Certificate File
|
||||
*/
|
||||
fullpath = GetCombinedPath("/tmp", "localhost.crt");
|
||||
if (!fullpath)
|
||||
return -1;
|
||||
|
||||
fp = winpr_fopen(fullpath, "w+");
|
||||
if (fp)
|
||||
{
|
||||
if (fwrite((void*)test_localhost_crt, sizeof(test_localhost_crt), 1, fp) != 1)
|
||||
goto out_fail;
|
||||
fclose(fp);
|
||||
fp = nullptr;
|
||||
}
|
||||
free(fullpath);
|
||||
|
||||
/*
|
||||
* Output Private Key File
|
||||
*/
|
||||
fullpath = GetCombinedPath("/tmp", "localhost.key");
|
||||
if (!fullpath)
|
||||
return -1;
|
||||
fp = winpr_fopen(fullpath, "w+");
|
||||
if (fp && fwrite((void*)test_localhost_key, sizeof(test_localhost_key), 1, fp) != 1)
|
||||
goto out_fail;
|
||||
|
||||
ret = 1;
|
||||
out_fail:
|
||||
free(fullpath);
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TestSchannel(int argc, char* argv[])
|
||||
{
|
||||
int count;
|
||||
ALG_ID algId;
|
||||
HANDLE thread;
|
||||
BYTE* lpTokenIn;
|
||||
BYTE* lpTokenOut;
|
||||
TimeStamp expiry;
|
||||
UINT32 cbMaxToken;
|
||||
SCHANNEL_CRED cred = WINPR_C_ARRAY_INIT;
|
||||
UINT32 fContextReq;
|
||||
ULONG fContextAttr;
|
||||
CtxtHandle context;
|
||||
CredHandle credentials;
|
||||
SECURITY_STATUS status;
|
||||
PSecPkgInfo pPackageInfo;
|
||||
PSecBuffer pSecBuffer;
|
||||
PSecurityFunctionTable table;
|
||||
DWORD NumberOfBytesRead;
|
||||
DWORD NumberOfBytesWritten;
|
||||
SecPkgCred_SupportedAlgs SupportedAlgs = WINPR_C_ARRAY_INIT;
|
||||
SecPkgCred_CipherStrengths CipherStrengths = WINPR_C_ARRAY_INIT;
|
||||
SecPkgCred_SupportedProtocols SupportedProtocols = WINPR_C_ARRAY_INIT;
|
||||
return 0; /* disable by default - causes crash */
|
||||
sspi_GlobalInit();
|
||||
dump_test_certificate_files();
|
||||
SecInvalidateHandle(&context);
|
||||
SecInvalidateHandle(&credentials);
|
||||
|
||||
if (!CreatePipe(&g_ClientReadPipe, &g_ClientWritePipe, nullptr, 0))
|
||||
{
|
||||
printf("Failed to create client pipe\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!CreatePipe(&g_ServerReadPipe, &g_ServerWritePipe, nullptr, 0))
|
||||
{
|
||||
printf("Failed to create server pipe\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(thread = CreateThread(nullptr, 0, schannel_test_server_thread, nullptr, 0, nullptr)))
|
||||
{
|
||||
printf("Failed to create server thread\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
table = InitSecurityInterface();
|
||||
status = QuerySecurityPackageInfo(SCHANNEL_NAME, &pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("QuerySecurityPackageInfo failure: 0x%08" PRIX32 "\n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cbMaxToken = pPackageInfo->cbMaxToken;
|
||||
cred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
cred.cCreds = 0;
|
||||
cred.paCred = nullptr;
|
||||
cred.cSupportedAlgs = 0;
|
||||
cred.palgSupportedAlgs = nullptr;
|
||||
cred.grbitEnabledProtocols = SP_PROT_SSL3TLS1_CLIENTS;
|
||||
cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS;
|
||||
cred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
|
||||
cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
|
||||
status = table->AcquireCredentialsHandle(nullptr, SCHANNEL_NAME, SECPKG_CRED_OUTBOUND, nullptr,
|
||||
&cred, nullptr, nullptr, &credentials, nullptr);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("AcquireCredentialsHandle failure: 0x%08" PRIX32 "\n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status =
|
||||
table->QueryCredentialsAttributes(&credentials, SECPKG_ATTR_SUPPORTED_ALGS, &SupportedAlgs);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("QueryCredentialsAttributes SECPKG_ATTR_SUPPORTED_ALGS failure: 0x%08" PRIX32 "\n",
|
||||
status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* SupportedAlgs: 15
|
||||
* 0x660E 0x6610 0x6801 0x6603 0x6601 0x8003 0x8004
|
||||
* 0x800C 0x800D 0x800E 0x2400 0xAA02 0xAE06 0x2200 0x2203
|
||||
*/
|
||||
printf("SupportedAlgs: %" PRIu32 "\n", SupportedAlgs.cSupportedAlgs);
|
||||
|
||||
for (DWORD index = 0; index < SupportedAlgs.cSupportedAlgs; index++)
|
||||
{
|
||||
algId = SupportedAlgs.palgSupportedAlgs[index];
|
||||
printf("\t0x%08" PRIX32 " CLASS: %" PRIu32 " TYPE: %" PRIu32 " SID: %" PRIu32 "\n", algId,
|
||||
((GET_ALG_CLASS(algId)) >> 13), ((GET_ALG_TYPE(algId)) >> 9), GET_ALG_SID(algId));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
status = table->QueryCredentialsAttributes(&credentials, SECPKG_ATTR_CIPHER_STRENGTHS,
|
||||
&CipherStrengths);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("QueryCredentialsAttributes SECPKG_ATTR_CIPHER_STRENGTHS failure: 0x%08" PRIX32 "\n",
|
||||
status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* CipherStrengths: Minimum: 40 Maximum: 256 */
|
||||
printf("CipherStrengths: Minimum: %" PRIu32 " Maximum: %" PRIu32 "\n",
|
||||
CipherStrengths.dwMinimumCipherStrength, CipherStrengths.dwMaximumCipherStrength);
|
||||
status = table->QueryCredentialsAttributes(&credentials, SECPKG_ATTR_SUPPORTED_PROTOCOLS,
|
||||
&SupportedProtocols);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("QueryCredentialsAttributes SECPKG_ATTR_SUPPORTED_PROTOCOLS failure: 0x%08" PRIX32
|
||||
"\n",
|
||||
status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* SupportedProtocols: 0x208A0 */
|
||||
printf("SupportedProtocols: 0x%08" PRIX32 "\n", SupportedProtocols.grbitProtocol);
|
||||
fContextReq = ISC_REQ_STREAM | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
|
||||
ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY;
|
||||
if (!(lpTokenIn = (BYTE*)malloc(cbMaxToken)))
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (!(lpTokenOut = (BYTE*)malloc(cbMaxToken)))
|
||||
{
|
||||
printf("Memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
g_ClientWait = FALSE;
|
||||
|
||||
do
|
||||
{
|
||||
SecBuffer SecBuffer_in[2] = WINPR_C_ARRAY_INIT;
|
||||
SecBuffer SecBuffer_out[1] = WINPR_C_ARRAY_INIT;
|
||||
SecBufferDesc SecBufferDesc_in = WINPR_C_ARRAY_INIT;
|
||||
SecBufferDesc SecBufferDesc_out = WINPR_C_ARRAY_INIT;
|
||||
if (g_ClientWait)
|
||||
{
|
||||
if (!ReadFile(g_ClientReadPipe, lpTokenIn, cbMaxToken, &NumberOfBytesRead, nullptr))
|
||||
{
|
||||
printf("failed to read from server pipe\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NumberOfBytesRead = 0;
|
||||
}
|
||||
|
||||
g_ClientWait = TRUE;
|
||||
printf("NumberOfBytesRead: %" PRIu32 "\n", NumberOfBytesRead);
|
||||
SecBuffer_in[0].BufferType = SECBUFFER_TOKEN;
|
||||
SecBuffer_in[0].pvBuffer = lpTokenIn;
|
||||
SecBuffer_in[0].cbBuffer = NumberOfBytesRead;
|
||||
SecBuffer_in[1].pvBuffer = nullptr;
|
||||
SecBuffer_in[1].cbBuffer = 0;
|
||||
SecBuffer_in[1].BufferType = SECBUFFER_EMPTY;
|
||||
SecBufferDesc_in.ulVersion = SECBUFFER_VERSION;
|
||||
SecBufferDesc_in.cBuffers = 2;
|
||||
SecBufferDesc_in.pBuffers = SecBuffer_in;
|
||||
SecBuffer_out[0].BufferType = SECBUFFER_TOKEN;
|
||||
SecBuffer_out[0].pvBuffer = lpTokenOut;
|
||||
SecBuffer_out[0].cbBuffer = cbMaxToken;
|
||||
SecBufferDesc_out.ulVersion = SECBUFFER_VERSION;
|
||||
SecBufferDesc_out.cBuffers = 1;
|
||||
SecBufferDesc_out.pBuffers = SecBuffer_out;
|
||||
status = table->InitializeSecurityContext(
|
||||
&credentials, SecIsValidHandle(&context) ? &context : nullptr, _T("localhost"),
|
||||
fContextReq, 0, 0, &SecBufferDesc_in, 0, &context, &SecBufferDesc_out, &fContextAttr,
|
||||
&expiry);
|
||||
|
||||
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED) &&
|
||||
(status != SEC_E_INCOMPLETE_MESSAGE))
|
||||
{
|
||||
printf("InitializeSecurityContext unexpected status: 0x%08" PRIX32 "\n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
NumberOfBytesWritten = 0;
|
||||
|
||||
if (status == SEC_E_OK)
|
||||
printf("InitializeSecurityContext status: SEC_E_OK\n");
|
||||
else if (status == SEC_I_CONTINUE_NEEDED)
|
||||
printf("InitializeSecurityContext status: SEC_I_CONTINUE_NEEDED\n");
|
||||
else if (status == SEC_E_INCOMPLETE_MESSAGE)
|
||||
printf("InitializeSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n");
|
||||
|
||||
printf("Client Output cBuffers: %" PRIu32 " pBuffers[0]: %" PRIu32 " type: %" PRIu32 "\n",
|
||||
SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer,
|
||||
SecBufferDesc_out.pBuffers[0].BufferType);
|
||||
printf("Client Input cBuffers: %" PRIu32 " pBuffers[0]: %" PRIu32 " type: %" PRIu32
|
||||
" pBuffers[1]: %" PRIu32 " type: %" PRIu32 "\n",
|
||||
SecBufferDesc_in.cBuffers, SecBufferDesc_in.pBuffers[0].cbBuffer,
|
||||
SecBufferDesc_in.pBuffers[0].BufferType, SecBufferDesc_in.pBuffers[1].cbBuffer,
|
||||
SecBufferDesc_in.pBuffers[1].BufferType);
|
||||
|
||||
if (status != SEC_E_INCOMPLETE_MESSAGE)
|
||||
{
|
||||
pSecBuffer = &SecBufferDesc_out.pBuffers[0];
|
||||
|
||||
if (pSecBuffer->cbBuffer > 0)
|
||||
{
|
||||
printf("Client > Server (%" PRIu32 ")\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer,
|
||||
pSecBuffer->cbBuffer);
|
||||
|
||||
if (!WriteFile(g_ServerWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer,
|
||||
&NumberOfBytesWritten, nullptr))
|
||||
{
|
||||
printf("failed to write to server pipe\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status == SEC_E_OK)
|
||||
{
|
||||
printf("Client Handshake Complete\n");
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (schannel_send(table, g_ServerWritePipe, &context, test_DummyMessage,
|
||||
sizeof(test_DummyMessage)) < 0)
|
||||
break;
|
||||
|
||||
for (DWORD index = 0; index < sizeof(test_DummyMessage); index++)
|
||||
{
|
||||
BYTE b, ln, hn;
|
||||
b = test_DummyMessage[index];
|
||||
ln = (b & 0x0F);
|
||||
hn = ((b & 0xF0) >> 4);
|
||||
ln = (ln + 1) % 0xF;
|
||||
hn = (ln + 1) % 0xF;
|
||||
b = (ln | (hn << 4));
|
||||
test_DummyMessage[index] = b;
|
||||
}
|
||||
|
||||
Sleep(100);
|
||||
count++;
|
||||
} while (count < 3);
|
||||
|
||||
schannel_send(table, g_ServerWritePipe, &context, test_LastDummyMessage,
|
||||
sizeof(test_LastDummyMessage));
|
||||
(void)WaitForSingleObject(thread, INFINITE);
|
||||
sspi_GlobalFinish();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user