20#include <winpr/config.h>
23#include <winpr/assert.h>
24#include <winpr/sspi.h>
25#include <winpr/print.h>
26#include <winpr/string.h>
27#include <winpr/tchar.h>
28#include <winpr/sysinfo.h>
29#include <winpr/registry.h>
30#include <winpr/endian.h>
31#include <winpr/build-config.h>
34#include "ntlm_export.h"
37#include "ntlm_message.h"
39#include "../../utils.h"
42#define TAG WINPR_TAG("sspi.NTLM")
45#define MIN(a, b) ((a) < (b)) ? (a) : (b)
48#define WINPR_KEY "Software\\%s\\WinPR\\NTLM"
50static char* NTLM_PACKAGE_NAME =
"NTLM";
52#define check_context(ctx) check_context_((ctx), __FILE__, __func__, __LINE__)
53static BOOL check_context_(
NTLM_CONTEXT* context,
const char* file,
const char* fkt,
size_t line)
56 wLog* log = WLog_Get(TAG);
57 const DWORD log_level = WLOG_ERROR;
61 if (WLog_IsLevelActive(log, log_level))
62 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"invalid context");
67 if (!context->RecvRc4Seal)
69 if (WLog_IsLevelActive(log, log_level))
70 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"invalid context->RecvRc4Seal");
73 if (!context->SendRc4Seal)
75 if (WLog_IsLevelActive(log, log_level))
76 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"invalid context->SendRc4Seal");
80 if (!context->SendSigningKey)
82 if (WLog_IsLevelActive(log, log_level))
83 WLog_PrintTextMessage(log, log_level, line, file, fkt,
84 "invalid context->SendSigningKey");
87 if (!context->RecvSigningKey)
89 if (WLog_IsLevelActive(log, log_level))
90 WLog_PrintTextMessage(log, log_level, line, file, fkt,
91 "invalid context->RecvSigningKey");
94 if (!context->SendSealingKey)
96 if (WLog_IsLevelActive(log, log_level))
97 WLog_PrintTextMessage(log, log_level, line, file, fkt,
98 "invalid context->SendSealingKey");
101 if (!context->RecvSealingKey)
103 if (WLog_IsLevelActive(log, log_level))
104 WLog_PrintTextMessage(log, log_level, line, file, fkt,
105 "invalid context->RecvSealingKey");
111char* get_computer_name(COMPUTER_NAME_FORMAT type,
size_t* pSize)
118 if (GetComputerNameExA(type,
nullptr, &nSize))
121 if (GetLastError() != ERROR_MORE_DATA)
124 char* computerName = calloc(1, nSize);
129 if (!GetComputerNameExA(type, computerName, &nSize))
140static int ntlm_SetContextWorkstation(
NTLM_CONTEXT* context,
char* Workstation)
142 char* ws = Workstation;
143 CHAR* computerName =
nullptr;
145 WINPR_ASSERT(context);
149 computerName = get_computer_name(ComputerNameNetBIOS,
nullptr);
156 context->Workstation.Buffer = ConvertUtf8ToWCharAlloc(ws, &len);
160 if (!context->Workstation.Buffer || (len > UINT16_MAX /
sizeof(WCHAR)))
163 context->Workstation.Length = (USHORT)(len *
sizeof(WCHAR));
167static int ntlm_SetContextServicePrincipalNameW(
NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
169 WINPR_ASSERT(context);
171 if (!ServicePrincipalName)
173 context->ServicePrincipalName.Buffer =
nullptr;
174 context->ServicePrincipalName.Length = 0;
178 context->ServicePrincipalName.Length = (USHORT)(_wcslen(ServicePrincipalName) * 2);
179 context->ServicePrincipalName.Buffer = (PWSTR)malloc(context->ServicePrincipalName.Length + 2);
181 if (!context->ServicePrincipalName.Buffer)
184 memcpy(context->ServicePrincipalName.Buffer, ServicePrincipalName,
185 context->ServicePrincipalName.Length + 2);
189static int ntlm_SetContextTargetName(
NTLM_CONTEXT* context,
char* TargetName)
191 char* name = TargetName;
192 WINPR_ASSERT(context);
197 char* computerName = get_computer_name(ComputerNameNetBIOS, &nSize);
202 if (nSize > MAX_COMPUTERNAME_LENGTH)
203 computerName[MAX_COMPUTERNAME_LENGTH] =
'\0';
214 context->TargetName.pvBuffer = ConvertUtf8ToWCharAlloc(name, &len);
216 if (!context->TargetName.pvBuffer || (len > UINT16_MAX /
sizeof(WCHAR)))
218 free(context->TargetName.pvBuffer);
219 context->TargetName.pvBuffer =
nullptr;
227 context->TargetName.cbBuffer = (USHORT)(len *
sizeof(WCHAR));
246 context->NTLMv2 = TRUE;
247 context->UseMIC = FALSE;
248 context->SendVersionInfo = TRUE;
249 context->SendSingleHostData = FALSE;
250 context->SendWorkstationName = TRUE;
251 context->NegotiateKeyExchange = TRUE;
252 context->UseSamFileDatabase = TRUE;
255 char* key = winpr_getApplicatonDetailsRegKey(WINPR_KEY);
259 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
262 if (status == ERROR_SUCCESS)
264 if (RegQueryValueEx(hKey, _T(
"NTLMv2"),
nullptr, &dwType, (BYTE*)&dwValue,
265 &dwSize) == ERROR_SUCCESS)
266 context->NTLMv2 = dwValue ? 1 : 0;
268 if (RegQueryValueEx(hKey, _T(
"UseMIC"),
nullptr, &dwType, (BYTE*)&dwValue,
269 &dwSize) == ERROR_SUCCESS)
270 context->UseMIC = dwValue ? 1 : 0;
272 if (RegQueryValueEx(hKey, _T(
"SendVersionInfo"),
nullptr, &dwType, (BYTE*)&dwValue,
273 &dwSize) == ERROR_SUCCESS)
274 context->SendVersionInfo = dwValue ? 1 : 0;
276 if (RegQueryValueEx(hKey, _T(
"SendSingleHostData"),
nullptr, &dwType,
277 (BYTE*)&dwValue, &dwSize) == ERROR_SUCCESS)
278 context->SendSingleHostData = dwValue ? 1 : 0;
280 if (RegQueryValueEx(hKey, _T(
"SendWorkstationName"),
nullptr, &dwType,
281 (BYTE*)&dwValue, &dwSize) == ERROR_SUCCESS)
282 context->SendWorkstationName = dwValue ? 1 : 0;
284 if (RegQueryValueEx(hKey, _T(
"WorkstationName"),
nullptr, &dwType,
nullptr,
285 &dwSize) == ERROR_SUCCESS)
287 char* workstation = (
char*)malloc(dwSize + 1);
295 const LONG rc = RegQueryValueExA(hKey,
"WorkstationName",
nullptr, &dwType,
296 (BYTE*)workstation, &dwSize);
297 if (rc != ERROR_SUCCESS)
298 WLog_WARN(TAG,
"Key ''WorkstationName' not found");
299 workstation[dwSize] =
'\0';
301 if (ntlm_SetContextWorkstation(context, workstation) < 0)
320 context->SuppressExtendedProtection = FALSE;
322 RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"System\\CurrentControlSet\\Control\\LSA"), 0,
323 KEY_READ | KEY_WOW64_64KEY, &hKey);
325 if (status == ERROR_SUCCESS)
327 if (RegQueryValueEx(hKey, _T(
"SuppressExtendedProtection"),
nullptr, &dwType,
328 (BYTE*)&dwValue, &dwSize) == ERROR_SUCCESS)
329 context->SuppressExtendedProtection = dwValue ? 1 : 0;
334 context->NegotiateFlags = 0;
335 context->LmCompatibilityLevel = 3;
336 ntlm_change_state(context, NTLM_STATE_INITIAL);
337 FillMemory(context->MachineID,
sizeof(context->MachineID), 0xAA);
340 context->UseMIC = TRUE;
350 winpr_RC4_Free(context->SendRc4Seal);
351 winpr_RC4_Free(context->RecvRc4Seal);
352 sspi_SecBufferFree(&context->NegotiateMessage);
353 sspi_SecBufferFree(&context->ChallengeMessage);
354 sspi_SecBufferFree(&context->AuthenticateMessage);
355 sspi_SecBufferFree(&context->ChallengeTargetInfo);
356 sspi_SecBufferFree(&context->TargetName);
357 sspi_SecBufferFree(&context->NtChallengeResponse);
358 sspi_SecBufferFree(&context->LmChallengeResponse);
359 free(context->ServicePrincipalName.Buffer);
360 free(context->Workstation.Buffer);
363 memset(context->NtlmHash, 0,
sizeof(context->NtlmHash));
364 memset(context->NtlmV2Hash, 0,
sizeof(context->NtlmV2Hash));
365 memset(context->SessionBaseKey, 0,
sizeof(context->SessionBaseKey));
366 memset(context->KeyExchangeKey, 0,
sizeof(context->KeyExchangeKey));
367 memset(context->RandomSessionKey, 0,
sizeof(context->RandomSessionKey));
368 memset(context->ExportedSessionKey, 0,
sizeof(context->ExportedSessionKey));
369 memset(context->EncryptedRandomSessionKey, 0,
sizeof(context->EncryptedRandomSessionKey));
370 memset(context->NtProofString, 0,
sizeof(context->NtProofString));
374static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
375 WINPR_ATTR_UNUSED SEC_WCHAR* pszPrincipal, WINPR_ATTR_UNUSED SEC_WCHAR* pszPackage,
376 ULONG fCredentialUse, WINPR_ATTR_UNUSED
void* pvLogonID,
void* pAuthData,
377 SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
382 if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && (fCredentialUse != SECPKG_CRED_INBOUND) &&
383 (fCredentialUse != SECPKG_CRED_BOTH))
385 return SEC_E_INVALID_PARAMETER;
391 return SEC_E_INTERNAL_ERROR;
393 credentials->fCredentialUse = fCredentialUse;
394 credentials->pGetKeyFn = pGetKeyFn;
395 credentials->pvGetKeyArgument = pvGetKeyArgument;
399 UINT32 identityFlags = sspi_GetAuthIdentityFlags(pAuthData);
401 if (sspi_CopyAuthIdentity(&(credentials->identity),
404 sspi_CredentialsFree(credentials);
405 return SEC_E_INVALID_PARAMETER;
408 if (identityFlags & SEC_WINNT_AUTH_IDENTITY_EXTENDED)
417 if (!credentials->ntlmSettings.
samFile)
419 sspi_CredentialsFree(credentials);
420 return SEC_E_INSUFFICIENT_MEMORY;
427 sspi_SecureHandleSetLowerPointer(phCredential, (
void*)credentials);
428 sspi_SecureHandleSetUpperPointer(phCredential, (
void*)NTLM_PACKAGE_NAME);
432static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(
433 SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse,
void* pvLogonID,
434 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
437 SECURITY_STATUS status = SEC_E_INSUFFICIENT_MEMORY;
438 SEC_WCHAR* principal =
nullptr;
439 SEC_WCHAR*
package = nullptr;
443 principal = ConvertUtf8ToWCharAlloc(pszPrincipal,
nullptr);
449 package = ConvertUtf8ToWCharAlloc(pszPackage, nullptr);
455 ntlm_AcquireCredentialsHandleW(principal, package, fCredentialUse, pvLogonID, pAuthData,
456 pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry);
465static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(
PCredHandle phCredential)
468 return SEC_E_INVALID_HANDLE;
472 sspi_SecureHandleInvalidate(phCredential);
474 return SEC_E_INVALID_HANDLE;
476 sspi_CredentialsFree(credentials);
480static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(
481 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
482 WINPR_ATTR_UNUSED
void* pBuffer)
484 if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
489 WLog_ERR(TAG,
"TODO: Implement");
490 return SEC_E_UNSUPPORTED_FUNCTION;
493static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(
PCredHandle phCredential,
494 ULONG ulAttribute,
void* pBuffer)
496 return ntlm_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
502static SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(
505 WINPR_ATTR_UNUSED PULONG pfContextAttr, WINPR_ATTR_UNUSED
PTimeStamp ptsTimeStamp)
507 SECURITY_STATUS status = 0;
513 if (phContext && !phContext->dwLower && !phContext->dwUpper)
514 return SEC_E_INVALID_HANDLE;
520 context = ntlm_ContextNew();
523 return SEC_E_INSUFFICIENT_MEMORY;
525 context->server = TRUE;
527 if (fContextReq & ASC_REQ_CONFIDENTIALITY)
528 context->confidentiality = TRUE;
530 credentials = (
SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
531 context->credentials = credentials;
532 context->SamFile = credentials->ntlmSettings.
samFile;
533 context->HashCallback = credentials->ntlmSettings.
hashCallback;
536 ntlm_SetContextTargetName(context,
nullptr);
537 sspi_SecureHandleSetLowerPointer(phNewContext, context);
538 sspi_SecureHandleSetUpperPointer(phNewContext, (
void*)NTLM_PACKAGE_NAME);
541 switch (ntlm_get_state(context))
543 case NTLM_STATE_INITIAL:
545 ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
548 return SEC_E_INVALID_TOKEN;
550 if (pInput->cBuffers < 1)
551 return SEC_E_INVALID_TOKEN;
553 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
556 return SEC_E_INVALID_TOKEN;
558 if (input_buffer->cbBuffer < 1)
559 return SEC_E_INVALID_TOKEN;
561 status = ntlm_read_NegotiateMessage(context, input_buffer);
562 if (status != SEC_I_CONTINUE_NEEDED)
565 if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
568 return SEC_E_INVALID_TOKEN;
570 if (pOutput->cBuffers < 1)
571 return SEC_E_INVALID_TOKEN;
573 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
575 if (!output_buffer->BufferType)
576 return SEC_E_INVALID_TOKEN;
578 if (output_buffer->cbBuffer < 1)
579 return SEC_E_INSUFFICIENT_MEMORY;
581 return ntlm_write_ChallengeMessage(context, output_buffer);
584 return SEC_E_OUT_OF_SEQUENCE;
587 case NTLM_STATE_AUTHENTICATE:
590 return SEC_E_INVALID_TOKEN;
592 if (pInput->cBuffers < 1)
593 return SEC_E_INVALID_TOKEN;
595 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
598 return SEC_E_INVALID_TOKEN;
600 if (input_buffer->cbBuffer < 1)
601 return SEC_E_INVALID_TOKEN;
603 status = ntlm_read_AuthenticateMessage(context, input_buffer);
607 for (ULONG i = 0; i < pOutput->cBuffers; i++)
609 pOutput->pBuffers[i].cbBuffer = 0;
610 pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN;
618 return SEC_E_OUT_OF_SEQUENCE;
622static SECURITY_STATUS SEC_ENTRY
623ntlm_ImpersonateSecurityContext(WINPR_ATTR_UNUSED
PCtxtHandle phContext)
628static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
630 WINPR_ATTR_UNUSED ULONG Reserved1, WINPR_ATTR_UNUSED ULONG TargetDataRep,
PSecBufferDesc pInput,
632 WINPR_ATTR_UNUSED PULONG pfContextAttr, WINPR_ATTR_UNUSED
PTimeStamp ptsExpiry)
634 SECURITY_STATUS status = 0;
640 if (phContext && !phContext->dwLower && !phContext->dwUpper)
641 return SEC_E_INVALID_HANDLE;
647 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
652 context = ntlm_ContextNew();
655 return SEC_E_INSUFFICIENT_MEMORY;
657 if (fContextReq & ISC_REQ_CONFIDENTIALITY)
658 context->confidentiality = TRUE;
660 credentials = (
SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
661 context->credentials = credentials;
663 if (context->Workstation.Length < 1)
665 if (ntlm_SetContextWorkstation(context,
nullptr) < 0)
667 ntlm_ContextFree(context);
668 return SEC_E_INTERNAL_ERROR;
672 if (ntlm_SetContextServicePrincipalNameW(context, pszTargetName) < 0)
674 ntlm_ContextFree(context);
675 return SEC_E_INTERNAL_ERROR;
678 sspi_SecureHandleSetLowerPointer(phNewContext, context);
679 sspi_SecureHandleSetUpperPointer(phNewContext, NTLM_SSP_NAME);
682 if ((!input_buffer) || (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE))
685 return SEC_E_INVALID_TOKEN;
687 if (pOutput->cBuffers < 1)
688 return SEC_E_INVALID_TOKEN;
690 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
693 return SEC_E_INVALID_TOKEN;
695 if (output_buffer->cbBuffer < 1)
696 return SEC_E_INVALID_TOKEN;
698 if (ntlm_get_state(context) == NTLM_STATE_INITIAL)
699 ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
701 if (ntlm_get_state(context) == NTLM_STATE_NEGOTIATE)
702 return ntlm_write_NegotiateMessage(context, output_buffer);
704 return SEC_E_OUT_OF_SEQUENCE;
709 return SEC_E_INVALID_TOKEN;
711 if (input_buffer->cbBuffer < 1)
712 return SEC_E_INVALID_TOKEN;
714 PSecBuffer channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
716 if (channel_bindings)
718 context->Bindings.BindingsLength = channel_bindings->cbBuffer;
722 if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
724 status = ntlm_read_ChallengeMessage(context, input_buffer);
726 if (status != SEC_I_CONTINUE_NEEDED)
730 return SEC_E_INVALID_TOKEN;
732 if (pOutput->cBuffers < 1)
733 return SEC_E_INVALID_TOKEN;
735 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
738 return SEC_E_INVALID_TOKEN;
740 if (output_buffer->cbBuffer < 1)
741 return SEC_E_INSUFFICIENT_MEMORY;
743 if (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE)
744 return ntlm_write_AuthenticateMessage(context, output_buffer);
747 return SEC_E_OUT_OF_SEQUENCE;
750 return SEC_E_OUT_OF_SEQUENCE;
756static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
758 ULONG Reserved1, ULONG TargetDataRep,
PSecBufferDesc pInput, ULONG Reserved2,
761 SECURITY_STATUS status = 0;
762 SEC_WCHAR* pszTargetNameW =
nullptr;
766 pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName,
nullptr);
768 return SEC_E_INTERNAL_ERROR;
771 status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,
772 Reserved1, TargetDataRep, pInput, Reserved2,
773 phNewContext, pOutput, pfContextAttr, ptsExpiry);
774 free(pszTargetNameW);
780static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(
PCtxtHandle phContext)
783 sspi_SecureHandleInvalidate(phContext);
784 ntlm_ContextFree(context);
790 BYTE* blob =
nullptr;
794 WINPR_ASSERT(ntproof);
796 target = &ntlm->ChallengeTargetInfo;
798 if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer))
799 return SEC_E_INSUFFICIENT_MEMORY;
801 blob = (BYTE*)ntproof->pvBuffer;
802 CopyMemory(blob, ntlm->ServerChallenge, 8);
806 CopyMemory(&blob[16], ntlm->Timestamp, 8);
807 CopyMemory(&blob[24], ntlm->ClientChallenge, 8);
810 CopyMemory(&blob[36], target->pvBuffer, target->cbBuffer);
816 BYTE* blob =
nullptr;
820 WINPR_ASSERT(micvalue);
822 msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
823 ntlm->AuthenticateMessage.cbBuffer;
825 if (!sspi_SecBufferAlloc(micvalue, msgSize))
826 return SEC_E_INSUFFICIENT_MEMORY;
828 blob = (BYTE*)micvalue->pvBuffer;
829 CopyMemory(blob, ntlm->NegotiateMessage.pvBuffer, ntlm->NegotiateMessage.cbBuffer);
830 blob += ntlm->NegotiateMessage.cbBuffer;
831 CopyMemory(blob, ntlm->ChallengeMessage.pvBuffer, ntlm->ChallengeMessage.cbBuffer);
832 blob += ntlm->ChallengeMessage.cbBuffer;
833 CopyMemory(blob, ntlm->AuthenticateMessage.pvBuffer, ntlm->AuthenticateMessage.cbBuffer);
834 blob += ntlm->MessageIntegrityCheckOffset;
835 ZeroMemory(blob, 16);
840static bool identityToAuthIdentity(
const SEC_WINNT_AUTH_IDENTITY* identity,
843 WINPR_ASSERT(identity);
849 *pAuthIdentity = empty;
851 if ((identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
853 if (identity->UserLength > 0)
855 if (ConvertWCharNToUtf8(identity->User, identity->UserLength, pAuthIdentity->User,
856 ARRAYSIZE(pAuthIdentity->User)) <= 0)
860 if (identity->DomainLength > 0)
862 if (ConvertWCharNToUtf8(identity->Domain, identity->DomainLength, pAuthIdentity->Domain,
863 ARRAYSIZE(pAuthIdentity->Domain)) <= 0)
867 else if ((identity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
869 if (identity->UserLength > 0)
871 const size_t len = MIN(ARRAYSIZE(pAuthIdentity->User) - 1, identity->UserLength);
872 strncpy(pAuthIdentity->User, (
char*)identity->User, len);
873 pAuthIdentity->User[len] =
'\0';
876 if (identity->DomainLength > 0)
878 const size_t len = MIN(ARRAYSIZE(pAuthIdentity->Domain) - 1, identity->DomainLength);
879 strncpy(pAuthIdentity->Domain, (
char*)identity->Domain, len);
880 pAuthIdentity->Domain[len] =
'\0';
889static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesCommon(
PCtxtHandle phContext,
890 ULONG ulAttribute,
void* pBuffer)
893 return SEC_E_INVALID_HANDLE;
896 return SEC_E_INSUFFICIENT_MEMORY;
899 if (!check_context(context))
900 return SEC_E_INVALID_HANDLE;
902 if (ulAttribute == SECPKG_ATTR_AUTH_IDENTITY)
907 return SEC_E_INTERNAL_ERROR;
908 if (!identityToAuthIdentity(&credentials->identity, AuthIdentity))
909 return SEC_E_INTERNAL_ERROR;
910 context->UseSamFileDatabase = FALSE;
913 else if (ulAttribute == SECPKG_ATTR_SIZES)
916 ContextSizes->cbMaxToken = 2010;
917 ContextSizes->cbMaxSignature = 16;
918 ContextSizes->cbBlockSize = 0;
919 ContextSizes->cbSecurityTrailer = 16;
923 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_NTPROOF_VALUE)
925 return ntlm_computeProofValue(context, (
SecBuffer*)pBuffer);
927 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_RANDKEY)
932 if (!sspi_SecBufferAlloc(randkey, 16))
933 return (SEC_E_INSUFFICIENT_MEMORY);
935 CopyMemory(randkey->pvBuffer, context->EncryptedRandomSessionKey, 16);
938 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MIC)
943 if (!sspi_SecBufferAlloc(mic, 16))
944 return (SEC_E_INSUFFICIENT_MEMORY);
946 CopyMemory(mic->pvBuffer, message->MessageIntegrityCheck, 16);
949 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MIC_VALUE)
951 return ntlm_computeMicValue(context, (
SecBuffer*)pBuffer);
954 WLog_ERR(TAG,
"TODO: Implement ulAttribute=0x%08" PRIx32, ulAttribute);
955 return SEC_E_UNSUPPORTED_FUNCTION;
960static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(
PCtxtHandle phContext,
961 ULONG ulAttribute,
void* pBuffer)
964 return SEC_E_INVALID_HANDLE;
967 return SEC_E_INSUFFICIENT_MEMORY;
970 if (!check_context(context))
971 return SEC_E_INVALID_HANDLE;
973 if (ulAttribute == SECPKG_ATTR_PACKAGE_INFO)
978 (
SecPkgInfoW*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size);
981 return SEC_E_INSUFFICIENT_MEMORY;
983 pPackageInfo->fCapabilities = NTLM_SecPkgInfoW.fCapabilities;
984 pPackageInfo->wVersion = NTLM_SecPkgInfoW.wVersion;
985 pPackageInfo->wRPCID = NTLM_SecPkgInfoW.wRPCID;
986 pPackageInfo->cbMaxToken = NTLM_SecPkgInfoW.cbMaxToken;
987 pPackageInfo->Name = _wcsdup(NTLM_SecPkgInfoW.Name);
988 pPackageInfo->Comment = _wcsdup(NTLM_SecPkgInfoW.Comment);
990 if (!pPackageInfo->Name || !pPackageInfo->Comment)
992 sspi_ContextBufferFree(pPackageInfo);
993 return SEC_E_INSUFFICIENT_MEMORY;
995 PackageInfo->PackageInfo = pPackageInfo;
999 return ntlm_QueryContextAttributesCommon(phContext, ulAttribute, pBuffer);
1002static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(
PCtxtHandle phContext,
1003 ULONG ulAttribute,
void* pBuffer)
1006 return SEC_E_INVALID_HANDLE;
1009 return SEC_E_INSUFFICIENT_MEMORY;
1012 if (!check_context(context))
1013 return SEC_E_INVALID_HANDLE;
1015 if (ulAttribute == SECPKG_ATTR_PACKAGE_INFO)
1020 (
SecPkgInfoA*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size);
1023 return SEC_E_INSUFFICIENT_MEMORY;
1025 pPackageInfo->fCapabilities = NTLM_SecPkgInfoA.fCapabilities;
1026 pPackageInfo->wVersion = NTLM_SecPkgInfoA.wVersion;
1027 pPackageInfo->wRPCID = NTLM_SecPkgInfoA.wRPCID;
1028 pPackageInfo->cbMaxToken = NTLM_SecPkgInfoA.cbMaxToken;
1029 pPackageInfo->Name = _strdup(NTLM_SecPkgInfoA.Name);
1030 pPackageInfo->Comment = _strdup(NTLM_SecPkgInfoA.Comment);
1032 if (!pPackageInfo->Name || !pPackageInfo->Comment)
1034 sspi_ContextBufferFree(pPackageInfo);
1035 return SEC_E_INSUFFICIENT_MEMORY;
1037 PackageInfo->PackageInfo = pPackageInfo;
1041 return ntlm_QueryContextAttributesCommon(phContext, ulAttribute, pBuffer);
1044static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(
PCtxtHandle phContext,
1045 ULONG ulAttribute,
void* pBuffer,
1049 return SEC_E_INVALID_HANDLE;
1052 return SEC_E_INVALID_PARAMETER;
1056 return SEC_E_INVALID_HANDLE;
1058 if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH)
1063 return SEC_E_INVALID_PARAMETER;
1065 if (AuthNtlmHash->Version == 1)
1066 CopyMemory(context->NtlmHash, AuthNtlmHash->NtlmHash, 16);
1067 else if (AuthNtlmHash->Version == 2)
1068 CopyMemory(context->NtlmV2Hash, AuthNtlmHash->NtlmHash, 16);
1072 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MESSAGE)
1077 return SEC_E_INVALID_PARAMETER;
1079 if (AuthNtlmMessage->type == 1)
1081 sspi_SecBufferFree(&context->NegotiateMessage);
1083 if (!sspi_SecBufferAlloc(&context->NegotiateMessage, AuthNtlmMessage->length))
1084 return SEC_E_INSUFFICIENT_MEMORY;
1086 CopyMemory(context->NegotiateMessage.pvBuffer, AuthNtlmMessage->buffer,
1087 AuthNtlmMessage->length);
1089 else if (AuthNtlmMessage->type == 2)
1091 sspi_SecBufferFree(&context->ChallengeMessage);
1093 if (!sspi_SecBufferAlloc(&context->ChallengeMessage, AuthNtlmMessage->length))
1094 return SEC_E_INSUFFICIENT_MEMORY;
1096 CopyMemory(context->ChallengeMessage.pvBuffer, AuthNtlmMessage->buffer,
1097 AuthNtlmMessage->length);
1099 else if (AuthNtlmMessage->type == 3)
1101 sspi_SecBufferFree(&context->AuthenticateMessage);
1103 if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, AuthNtlmMessage->length))
1104 return SEC_E_INSUFFICIENT_MEMORY;
1106 CopyMemory(context->AuthenticateMessage.pvBuffer, AuthNtlmMessage->buffer,
1107 AuthNtlmMessage->length);
1112 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_TIMESTAMP)
1118 return SEC_E_INVALID_PARAMETER;
1120 if (AuthNtlmTimestamp->ChallengeOrResponse)
1121 CopyMemory(context->ChallengeTimestamp, AuthNtlmTimestamp->Timestamp, 8);
1123 CopyMemory(context->Timestamp, AuthNtlmTimestamp->Timestamp, 8);
1127 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE)
1133 return SEC_E_INVALID_PARAMETER;
1135 CopyMemory(context->ClientChallenge, AuthNtlmClientChallenge->ClientChallenge, 8);
1138 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE)
1144 return SEC_E_INVALID_PARAMETER;
1146 CopyMemory(context->ServerChallenge, AuthNtlmServerChallenge->ServerChallenge, 8);
1150 WLog_ERR(TAG,
"TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
1151 return SEC_E_UNSUPPORTED_FUNCTION;
1154static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesA(
PCtxtHandle phContext,
1155 ULONG ulAttribute,
void* pBuffer,
1158 return ntlm_SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer);
1161static SECURITY_STATUS SEC_ENTRY ntlm_SetCredentialsAttributesW(
1162 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
1163 WINPR_ATTR_UNUSED
void* pBuffer, WINPR_ATTR_UNUSED ULONG cbBuffer)
1165 return SEC_E_UNSUPPORTED_FUNCTION;
1168static SECURITY_STATUS SEC_ENTRY ntlm_SetCredentialsAttributesA(
1169 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
1170 WINPR_ATTR_UNUSED
void* pBuffer, WINPR_ATTR_UNUSED ULONG cbBuffer)
1172 return SEC_E_UNSUPPORTED_FUNCTION;
1175static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(WINPR_ATTR_UNUSED
PCtxtHandle phContext)
1180static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(
PCtxtHandle phContext,
1181 WINPR_ATTR_UNUSED ULONG fQOP,
1184 const UINT32 SeqNo = MessageSeqNo;
1186 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1187 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1192 if (!check_context(context))
1193 return SEC_E_INVALID_HANDLE;
1195 for (ULONG index = 0; index < pMessage->cBuffers; index++)
1197 SecBuffer* cur = &pMessage->pBuffers[index];
1199 if (cur->BufferType & SECBUFFER_DATA)
1201 else if (cur->BufferType & SECBUFFER_TOKEN)
1202 signature_buffer = cur;
1206 return SEC_E_INVALID_TOKEN;
1208 if (!signature_buffer)
1209 return SEC_E_INVALID_TOKEN;
1212 ULONG length = data_buffer->cbBuffer;
1213 void* data = malloc(length);
1216 return SEC_E_INSUFFICIENT_MEMORY;
1218 CopyMemory(data, data_buffer->pvBuffer, length);
1220 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1222 BOOL success = FALSE;
1226 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH))
1229 winpr_Data_Write_UINT32(&value, SeqNo);
1231 if (!winpr_HMAC_Update(hmac, (
void*)&value, 4))
1233 if (!winpr_HMAC_Update(hmac, data, length))
1235 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1242 winpr_HMAC_Free(hmac);
1246 return SEC_E_INSUFFICIENT_MEMORY;
1250 if ((data_buffer->BufferType & SECBUFFER_READONLY) == 0)
1252 if (context->confidentiality)
1254 if (!winpr_RC4_Update(context->SendRc4Seal, length, (BYTE*)data,
1255 (BYTE*)data_buffer->pvBuffer))
1258 return SEC_E_INSUFFICIENT_MEMORY;
1262 CopyMemory(data_buffer->pvBuffer, data, length);
1265#ifdef WITH_DEBUG_NTLM
1266 WLog_DBG(TAG,
"Data Buffer (length = %" PRIu32
")", length);
1267 winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1268 WLog_DBG(TAG,
"Encrypted Data Buffer (length = %" PRIu32
")", data_buffer->cbBuffer);
1269 winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1273 if (!winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum))
1274 return SEC_E_INSUFFICIENT_MEMORY;
1275 if ((signature_buffer->BufferType & SECBUFFER_READONLY) == 0)
1277 BYTE* signature = signature_buffer->pvBuffer;
1279 winpr_Data_Write_UINT32(signature, version);
1280 CopyMemory(&signature[4], (
void*)checksum, 8);
1281 winpr_Data_Write_UINT32(&signature[12], SeqNo);
1283 context->SendSeqNum++;
1284#ifdef WITH_DEBUG_NTLM
1285 WLog_DBG(TAG,
"Signature (length = %" PRIu32
")", signature_buffer->cbBuffer);
1286 winpr_HexDump(TAG, WLOG_DEBUG, signature_buffer->pvBuffer, signature_buffer->cbBuffer);
1293 WINPR_ATTR_UNUSED PULONG pfQOP)
1295 const UINT32 SeqNo = (UINT32)MessageSeqNo;
1297 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1298 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1300 BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1304 if (!check_context(context))
1305 return SEC_E_INVALID_HANDLE;
1307 for (ULONG index = 0; index < pMessage->cBuffers; index++)
1309 if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
1310 data_buffer = &pMessage->pBuffers[index];
1311 else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
1312 signature_buffer = &pMessage->pBuffers[index];
1316 return SEC_E_INVALID_TOKEN;
1318 if (!signature_buffer)
1319 return SEC_E_INVALID_TOKEN;
1322 const ULONG length = data_buffer->cbBuffer;
1323 void* data = malloc(length);
1326 return SEC_E_INSUFFICIENT_MEMORY;
1328 CopyMemory(data, data_buffer->pvBuffer, length);
1332 if (context->confidentiality)
1334 if (!winpr_RC4_Update(context->RecvRc4Seal, length, (BYTE*)data,
1335 (BYTE*)data_buffer->pvBuffer))
1338 return SEC_E_INSUFFICIENT_MEMORY;
1342 CopyMemory(data_buffer->pvBuffer, data, length);
1345 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1347 BOOL success = FALSE;
1352 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->RecvSigningKey, WINPR_MD5_DIGEST_LENGTH))
1355 winpr_Data_Write_UINT32(&value, SeqNo);
1357 if (!winpr_HMAC_Update(hmac, (
void*)&value, 4))
1359 if (!winpr_HMAC_Update(hmac, data_buffer->pvBuffer, data_buffer->cbBuffer))
1361 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1367 winpr_HMAC_Free(hmac);
1371 return SEC_E_INSUFFICIENT_MEMORY;
1374#ifdef WITH_DEBUG_NTLM
1375 WLog_DBG(TAG,
"Encrypted Data Buffer (length = %" PRIu32
")", length);
1376 winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1377 WLog_DBG(TAG,
"Data Buffer (length = %" PRIu32
")", data_buffer->cbBuffer);
1378 winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1382 if (!winpr_RC4_Update(context->RecvRc4Seal, 8, digest, checksum))
1383 return SEC_E_MESSAGE_ALTERED;
1386 winpr_Data_Write_UINT32(expected_signature, version);
1387 CopyMemory(&expected_signature[4], (
void*)checksum, 8);
1388 winpr_Data_Write_UINT32(&expected_signature[12], SeqNo);
1389 context->RecvSeqNum++;
1391 if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0)
1394 WLog_ERR(TAG,
"signature verification failed, something nasty is going on!");
1395#ifdef WITH_DEBUG_NTLM
1396 WLog_ERR(TAG,
"Expected Signature:");
1397 winpr_HexDump(TAG, WLOG_ERROR, expected_signature, 16);
1398 WLog_ERR(TAG,
"Actual Signature:");
1399 winpr_HexDump(TAG, WLOG_ERROR, (BYTE*)signature_buffer->pvBuffer, 16);
1401 return SEC_E_MESSAGE_ALTERED;
1407static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(
PCtxtHandle phContext,
1408 WINPR_ATTR_UNUSED ULONG fQOP,
1411 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
1415 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1416 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1418 NTLM_CONTEXT* context = sspi_SecureHandleGetLowerPointer(phContext);
1419 if (!check_context(context))
1420 return SEC_E_INVALID_HANDLE;
1422 for (ULONG i = 0; i < pMessage->cBuffers; i++)
1424 if (pMessage->pBuffers[i].BufferType == SECBUFFER_DATA)
1425 data_buffer = &pMessage->pBuffers[i];
1426 else if (pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1427 sig_buffer = &pMessage->pBuffers[i];
1430 if (!data_buffer || !sig_buffer)
1431 return SEC_E_INVALID_TOKEN;
1433 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1435 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH))
1438 winpr_Data_Write_UINT32(&seq_no, MessageSeqNo);
1439 if (!winpr_HMAC_Update(hmac, (BYTE*)&seq_no, 4))
1441 if (!winpr_HMAC_Update(hmac, data_buffer->pvBuffer, data_buffer->cbBuffer))
1443 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1446 if (!winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum))
1449 BYTE* signature = sig_buffer->pvBuffer;
1450 winpr_Data_Write_UINT32(signature, 1L);
1451 CopyMemory(&signature[4], checksum, 8);
1452 winpr_Data_Write_UINT32(&signature[12], seq_no);
1453 sig_buffer->cbBuffer = 16;
1458 winpr_HMAC_Free(hmac);
1462static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(
PCtxtHandle phContext,
1464 WINPR_ATTR_UNUSED PULONG pfQOP)
1466 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
1470 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1471 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1472 BYTE signature[16] = WINPR_C_ARRAY_INIT;
1474 NTLM_CONTEXT* context = sspi_SecureHandleGetLowerPointer(phContext);
1475 if (!check_context(context))
1476 return SEC_E_INVALID_HANDLE;
1478 for (ULONG i = 0; i < pMessage->cBuffers; i++)
1480 if (pMessage->pBuffers[i].BufferType == SECBUFFER_DATA)
1481 data_buffer = &pMessage->pBuffers[i];
1482 else if (pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1483 sig_buffer = &pMessage->pBuffers[i];
1486 if (!data_buffer || !sig_buffer)
1487 return SEC_E_INVALID_TOKEN;
1489 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1491 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->RecvSigningKey, WINPR_MD5_DIGEST_LENGTH))
1494 winpr_Data_Write_UINT32(&seq_no, MessageSeqNo);
1495 if (!winpr_HMAC_Update(hmac, (BYTE*)&seq_no, 4))
1497 if (!winpr_HMAC_Update(hmac, data_buffer->pvBuffer, data_buffer->cbBuffer))
1499 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1502 if (!winpr_RC4_Update(context->RecvRc4Seal, 8, digest, checksum))
1505 winpr_Data_Write_UINT32(signature, 1L);
1506 CopyMemory(&signature[4], checksum, 8);
1507 winpr_Data_Write_UINT32(&signature[12], seq_no);
1510 if (memcmp(sig_buffer->pvBuffer, signature, 16) != 0)
1511 status = SEC_E_MESSAGE_ALTERED;
1514 winpr_HMAC_Free(hmac);
1521 ntlm_QueryCredentialsAttributesA,
1522 ntlm_AcquireCredentialsHandleA,
1523 ntlm_FreeCredentialsHandle,
1525 ntlm_InitializeSecurityContextA,
1526 ntlm_AcceptSecurityContext,
1528 ntlm_DeleteSecurityContext,
1530 ntlm_QueryContextAttributesA,
1531 ntlm_ImpersonateSecurityContext,
1532 ntlm_RevertSecurityContext,
1534 ntlm_VerifySignature,
1544 ntlm_EncryptMessage,
1545 ntlm_DecryptMessage,
1546 ntlm_SetContextAttributesA,
1547 ntlm_SetCredentialsAttributesA,
1553 ntlm_QueryCredentialsAttributesW,
1554 ntlm_AcquireCredentialsHandleW,
1555 ntlm_FreeCredentialsHandle,
1557 ntlm_InitializeSecurityContextW,
1558 ntlm_AcceptSecurityContext,
1560 ntlm_DeleteSecurityContext,
1562 ntlm_QueryContextAttributesW,
1563 ntlm_ImpersonateSecurityContext,
1564 ntlm_RevertSecurityContext,
1566 ntlm_VerifySignature,
1576 ntlm_EncryptMessage,
1577 ntlm_DecryptMessage,
1578 ntlm_SetContextAttributesW,
1579 ntlm_SetCredentialsAttributesW,
1588 "NTLM Security Package"
1591static WCHAR NTLM_SecPkgInfoW_NameBuffer[32] = WINPR_C_ARRAY_INIT;
1592static WCHAR NTLM_SecPkgInfoW_CommentBuffer[32] = WINPR_C_ARRAY_INIT;
1599 NTLM_SecPkgInfoW_NameBuffer,
1600 NTLM_SecPkgInfoW_CommentBuffer
1603char* ntlm_negotiate_flags_string(
char* buffer,
size_t size, UINT32 flags)
1605 if (!buffer || (size == 0))
1608 (void)_snprintf(buffer, size,
"[0x%08" PRIx32
"] ", flags);
1610 for (
int x = 0; x < 31; x++)
1612 const UINT32 mask = 1u << x;
1613 size_t len = strnlen(buffer, size);
1616 const char* str = ntlm_get_negotiate_string(mask);
1617 const size_t flen = strlen(str);
1619 if ((len > 0) && (buffer[len - 1] !=
' '))
1623 winpr_str_append(
"|", buffer, size,
nullptr);
1627 if (size - len < flen)
1629 winpr_str_append(str, buffer, size,
nullptr);
1636const char* ntlm_message_type_string(UINT32 messageType)
1638 switch (messageType)
1640 case MESSAGE_TYPE_NEGOTIATE:
1641 return "MESSAGE_TYPE_NEGOTIATE";
1642 case MESSAGE_TYPE_CHALLENGE:
1643 return "MESSAGE_TYPE_CHALLENGE";
1644 case MESSAGE_TYPE_AUTHENTICATE:
1645 return "MESSAGE_TYPE_AUTHENTICATE";
1647 return "MESSAGE_TYPE_UNKNOWN";
1651const char* ntlm_state_string(NTLM_STATE state)
1655 case NTLM_STATE_INITIAL:
1656 return "NTLM_STATE_INITIAL";
1657 case NTLM_STATE_NEGOTIATE:
1658 return "NTLM_STATE_NEGOTIATE";
1659 case NTLM_STATE_CHALLENGE:
1660 return "NTLM_STATE_CHALLENGE";
1661 case NTLM_STATE_AUTHENTICATE:
1662 return "NTLM_STATE_AUTHENTICATE";
1663 case NTLM_STATE_FINAL:
1664 return "NTLM_STATE_FINAL";
1666 return "NTLM_STATE_UNKNOWN";
1669void ntlm_change_state(
NTLM_CONTEXT* ntlm, NTLM_STATE state)
1672 WLog_DBG(TAG,
"change state from %s to %s", ntlm_state_string(ntlm->state),
1673 ntlm_state_string(state));
1674 ntlm->state = state;
1683BOOL ntlm_reset_cipher_state(
PSecHandle phContext)
1685 NTLM_CONTEXT* context = sspi_SecureHandleGetLowerPointer(phContext);
1689 check_context(context);
1690 winpr_RC4_Free(context->SendRc4Seal);
1691 winpr_RC4_Free(context->RecvRc4Seal);
1692 context->SendRc4Seal = winpr_RC4_New(context->RecvSealingKey, 16);
1693 context->RecvRc4Seal = winpr_RC4_New(context->SendSealingKey, 16);
1695 if (!context->SendRc4Seal)
1697 WLog_ERR(TAG,
"Failed to allocate context->SendRc4Seal");
1700 if (!context->RecvRc4Seal)
1702 WLog_ERR(TAG,
"Failed to allocate context->RecvRc4Seal");
1712 InitializeConstWCharFromUtf8(NTLM_SecPkgInfoA.Name, NTLM_SecPkgInfoW_NameBuffer,
1713 ARRAYSIZE(NTLM_SecPkgInfoW_NameBuffer));
1714 InitializeConstWCharFromUtf8(NTLM_SecPkgInfoA.Comment, NTLM_SecPkgInfoW_CommentBuffer,
1715 ARRAYSIZE(NTLM_SecPkgInfoW_CommentBuffer));
WINPR_ATTR_NODISCARD psSspiNtlmHashCallback hashCallback