libwinpr-sspi: add custom API for passing NTLM hashes and credentials dynamically

This commit is contained in:
Marc-André Moreau 2014-06-09 15:25:00 -04:00
parent ac9b527991
commit 0ebc7e2ab4
10 changed files with 359 additions and 232 deletions

View File

@ -44,7 +44,7 @@ SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextA(PCredHandle phCrede
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
{
CREDSSP_CONTEXT* context;
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
context = (CREDSSP_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
@ -55,7 +55,7 @@ SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextA(PCredHandle phCrede
if (!context)
return SEC_E_INSUFFICIENT_MEMORY;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
sspi_SecureHandleSetLowerPointer(phNewContext, context);
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) CREDSSP_PACKAGE_NAME);
@ -106,7 +106,7 @@ SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleA(SEC_CHAR* pszPrincip
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
SEC_WINNT_AUTH_IDENTITY* identity;
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
@ -138,9 +138,9 @@ SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA(PCredHandle phCred
{
if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
return SEC_E_OK;
}
@ -150,12 +150,12 @@ SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA(PCredHandle phCred
SECURITY_STATUS SEC_ENTRY credssp_FreeCredentialsHandle(PCredHandle phCredential)
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
if (!phCredential)
return SEC_E_INVALID_HANDLE;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
if (!credentials)
return SEC_E_INVALID_HANDLE;

View File

@ -246,10 +246,6 @@ void ntlm_ContextFree(NTLM_CONTEXT* context)
sspi_SecBufferFree(&context->LmChallengeResponse);
free(context->ServicePrincipalName.Buffer);
free(context->identity.User);
free(context->identity.Password);
free(context->identity.Domain);
free(context->Workstation.Buffer);
free(context);
}
@ -258,43 +254,32 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
SEC_WINNT_AUTH_IDENTITY* identity;
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
(fCredentialUse != SECPKG_CRED_INBOUND) &&
(fCredentialUse != SECPKG_CRED_BOTH))
{
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INSUFFICIENT_MEMORY;
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (identity)
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
return SEC_E_OK;
return SEC_E_INVALID_PARAMETER;
}
else if (fCredentialUse == SECPKG_CRED_INBOUND)
{
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INSUFFICIENT_MEMORY;
credentials = sspi_CredentialsNew();
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (!credentials)
return SEC_E_INTERNAL_ERROR;
if (identity)
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
credentials->fCredentialUse = fCredentialUse;
credentials->pGetKeyFn = pGetKeyFn;
credentials->pvGetKeyArgument = pvGetKeyArgument;
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
return SEC_E_OK;
}
if (identity)
sspi_CopyAuthIdentity(&(credentials->identity), identity);
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
return SEC_E_OK;
}
@ -303,55 +288,44 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal,
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
SEC_WINNT_AUTH_IDENTITY* identity;
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
(fCredentialUse != SECPKG_CRED_INBOUND) &&
(fCredentialUse != SECPKG_CRED_BOTH))
{
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INSUFFICIENT_MEMORY;
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (identity)
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
return SEC_E_OK;
return SEC_E_INVALID_PARAMETER;
}
else if (fCredentialUse == SECPKG_CRED_INBOUND)
{
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INSUFFICIENT_MEMORY;
credentials = sspi_CredentialsNew();
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (!credentials)
return SEC_E_INTERNAL_ERROR;
if (identity)
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
credentials->fCredentialUse = fCredentialUse;
credentials->pGetKeyFn = pGetKeyFn;
credentials->pvGetKeyArgument = pvGetKeyArgument;
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
return SEC_E_OK;
}
if (identity)
sspi_CopyAuthIdentity(&(credentials->identity), identity);
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
return SEC_E_OK;
}
SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential)
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
if (!phCredential)
return SEC_E_INVALID_HANDLE;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
if (!credentials)
return SEC_E_INVALID_HANDLE;
@ -385,7 +359,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
{
NTLM_CONTEXT* context;
SECURITY_STATUS status;
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
PSecBuffer input_buffer;
PSecBuffer output_buffer;
@ -403,10 +377,8 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
if (fContextReq & ASC_REQ_CONFIDENTIALITY)
context->confidentiality = TRUE;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
if (sspi_CopyAuthIdentity(&context->identity, &credentials->identity) < 0)
return SEC_E_INSUFFICIENT_MEMORY;
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
context->credentials = credentials;
ntlm_SetContextTargetName(context, NULL);
@ -502,7 +474,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti
{
NTLM_CONTEXT* context;
SECURITY_STATUS status;
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
PSecBuffer input_buffer = NULL;
PSecBuffer output_buffer = NULL;
PSecBuffer channel_bindings = NULL;
@ -519,19 +491,17 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti
if (fContextReq & ISC_REQ_CONFIDENTIALITY)
context->confidentiality = TRUE;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
context->credentials = credentials;
if (context->Workstation.Length < 1)
{
if (ntlm_SetContextWorkstation(context, NULL) < 0)
return SEC_E_INSUFFICIENT_MEMORY;
return SEC_E_INTERNAL_ERROR;
}
if (ntlm_SetContextServicePrincipalNameW(context, pszTargetName) < 0)
return SEC_E_INSUFFICIENT_MEMORY;
if (sspi_CopyAuthIdentity(&context->identity, &credentials->identity) < 0)
return SEC_E_INSUFFICIENT_MEMORY;
return SEC_E_INTERNAL_ERROR;
sspi_SecureHandleSetLowerPointer(phNewContext, context);
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME);
@ -624,7 +594,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(PCredHandle phCredenti
if (pszTargetName)
{
if (ConvertToUnicode(CP_UTF8, 0, pszTargetName, -1, &pszTargetNameW, 0) <= 0)
return SEC_E_INSUFFICIENT_MEMORY;
return SEC_E_INTERNAL_ERROR;
}
status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,

View File

@ -228,6 +228,8 @@ struct _NTLM_CONTEXT
NTLM_STATE state;
int SendSeqNum;
int RecvSeqNum;
BYTE NtlmHash[16];
BYTE NtlmV2Hash[16];
BYTE MachineID[32];
BOOL SendVersionInfo;
BOOL confidentiality;
@ -243,7 +245,7 @@ struct _NTLM_CONTEXT
BOOL SendWorkstationName;
UNICODE_STRING Workstation;
UNICODE_STRING ServicePrincipalName;
SEC_WINNT_AUTH_IDENTITY identity;
SSPI_CREDENTIALS* credentials;
BYTE* ChannelBindingToken;
BYTE ChannelBindingsHash[16];
SecPkgContext_Bindings Bindings;

View File

@ -39,6 +39,9 @@ static const char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client si
static const char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server sealing key magic constant";
static const char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant";
static const BYTE NTLM_NULL_HASH[16] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/**
* Populate VERSION structure.\n
* VERSION @msdn{cc236654}
@ -200,10 +203,11 @@ void ntlm_generate_timestamp(NTLM_CONTEXT* context)
ntlm_current_time(context->Timestamp);
}
int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
{
WINPR_SAM* sam;
WINPR_SAM_ENTRY* entry;
SSPI_CREDENTIALS* credentials = context->credentials;
sam = SamOpen(TRUE);
@ -211,8 +215,8 @@ int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
return -1;
entry = SamLookupUserW(sam,
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2);
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2);
if (entry)
{
@ -222,8 +226,8 @@ int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
#endif
NTOWFv2FromHashW(entry->NtHash,
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
(BYTE*) hash);
SamFreeEntry(sam, entry);
@ -233,7 +237,7 @@ int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
}
entry = SamLookupUserW(sam,
(LPWSTR) context->identity.User, context->identity.UserLength * 2, NULL, 0);
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, NULL, 0);
if (entry)
{
@ -243,8 +247,8 @@ int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
#endif
NTOWFv2FromHashW(entry->NtHash,
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
(BYTE*) hash);
SamFreeEntry(sam, entry);
@ -269,12 +273,14 @@ int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
int i, hn, ln;
char* PasswordHash = NULL;
UINT32 PasswordHashLength = 0;
SSPI_CREDENTIALS* credentials = context->credentials;
/* Password contains a password hash of length (PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR) */
PasswordHashLength = context->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR;
PasswordHashLength = credentials->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR;
status = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR) context->identity.Password, PasswordHashLength, &PasswordHash, 0, NULL, NULL);
status = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR) credentials->identity.Password,
PasswordHashLength, &PasswordHash, 0, NULL, NULL);
if (status <= 0)
return -1;
@ -293,27 +299,34 @@ int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
return 1;
}
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
{
if (context->identity.PasswordLength > 256)
SSPI_CREDENTIALS* credentials = context->credentials;
if (memcmp(context->NtlmHash, NTLM_NULL_HASH, 16) != 0)
{
BYTE PasswordHash[16];
/* Special case for WinPR: password hash */
if (ntlm_convert_password_hash(context, PasswordHash) < 0)
return -1;
NTOWFv2FromHashW(PasswordHash,
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
NTOWFv2FromHashW(context->NtlmHash,
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
(BYTE*) hash);
}
else if (context->identity.PasswordLength > 0)
else if (credentials->identity.PasswordLength > 256)
{
NTOWFv2W((LPWSTR) context->identity.Password, context->identity.PasswordLength * 2,
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2, (BYTE*) hash);
/* Special case for WinPR: password hash */
if (ntlm_convert_password_hash(context, context->NtlmHash) < 0)
return -1;
NTOWFv2FromHashW(context->NtlmHash,
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
(BYTE*) hash);
}
else if (credentials->identity.PasswordLength > 0)
{
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, (BYTE*) hash);
}
else
{
@ -325,9 +338,8 @@ int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
{
char* response;
char value[16];
char ntlm_v2_hash[16];
BYTE* response;
BYTE value[16];
if (context->LmCompatibilityLevel < 2)
{
@ -341,7 +353,7 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
/* Compute the NTLMv2 hash */
if (ntlm_compute_ntlm_v2_hash(context, ntlm_v2_hash) < 0)
if (ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash) < 0)
return -1;
/* Concatenate the server and client challenges */
@ -351,10 +363,10 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
return -1;
response = (char*) context->LmChallengeResponse.pvBuffer;
response = (BYTE*) context->LmChallengeResponse.pvBuffer;
/* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (void*) value, 16, (void*) response, NULL);
HMAC(EVP_md5(), (void*) context->NtlmV2Hash, 16, (BYTE*) value, 16, (BYTE*) response, NULL);
/* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response (24 bytes) */
CopyMemory(&response[16], context->ClientChallenge, 8);
@ -372,7 +384,6 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
{
BYTE* blob;
BYTE ntlm_v2_hash[16];
BYTE nt_proof_str[16];
SecBuffer ntlm_v2_temp;
SecBuffer ntlm_v2_temp_chal;
@ -388,7 +399,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
/* Compute the NTLMv2 hash */
if (ntlm_compute_ntlm_v2_hash(context, (char*) ntlm_v2_hash) < 0)
if (ntlm_compute_ntlm_v2_hash(context, (BYTE*) context->NtlmV2Hash) < 0)
return -1;
#ifdef WITH_DEBUG_NTLM
@ -409,7 +420,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
fprintf(stderr, "\n");
fprintf(stderr, "NTOWFv2, NTLMv2 Hash\n");
winpr_HexDump(ntlm_v2_hash, 16);
winpr_HexDump(context->NtlmV2Hash, 16);
fprintf(stderr, "\n");
#endif
@ -438,8 +449,8 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
CopyMemory(blob, context->ServerChallenge, 8);
CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (BYTE*) ntlm_v2_temp_chal.pvBuffer,
ntlm_v2_temp_chal.cbBuffer, (void*) nt_proof_str, NULL);
HMAC(EVP_md5(), (BYTE*) context->NtlmV2Hash, 16, (BYTE*) ntlm_v2_temp_chal.pvBuffer,
ntlm_v2_temp_chal.cbBuffer, (BYTE*) nt_proof_str, NULL);
/* NtChallengeResponse, Concatenate NTProofStr with temp */
@ -451,7 +462,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
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 */
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (void*) nt_proof_str, 16, (void*) context->SessionBaseKey, NULL);
HMAC(EVP_md5(), (BYTE*) context->NtlmV2Hash, 16, (BYTE*) nt_proof_str, 16, (BYTE*) context->SessionBaseKey, NULL);
sspi_SecBufferFree(&ntlm_v2_temp);
sspi_SecBufferFree(&ntlm_v2_temp_chal);

View File

@ -38,7 +38,7 @@ void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
void ntlm_current_time(BYTE* timestamp);
void ntlm_generate_timestamp(NTLM_CONTEXT* context);
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash);
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash);
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);

View File

@ -676,6 +676,7 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
NTLMv2_RESPONSE response;
UINT32 PayloadBufferOffset;
NTLM_AUTHENTICATE_MESSAGE* message;
SSPI_CREDENTIALS* credentials = context->credentials;
flags = 0;
MicOffset = 0;
@ -821,24 +822,94 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
if (message->UserName.Len > 0)
{
context->identity.User = (UINT16*) malloc(message->UserName.Len);
credentials->identity.User = (UINT16*) malloc(message->UserName.Len);
if (!context->identity.User)
if (!credentials->identity.User)
return SEC_E_INTERNAL_ERROR;
CopyMemory(context->identity.User, message->UserName.Buffer, message->UserName.Len);
context->identity.UserLength = message->UserName.Len / 2;
CopyMemory(credentials->identity.User, message->UserName.Buffer, message->UserName.Len);
credentials->identity.UserLength = message->UserName.Len / 2;
}
if (message->DomainName.Len > 0)
{
context->identity.Domain = (UINT16*) malloc(message->DomainName.Len);
credentials->identity.Domain = (UINT16*) malloc(message->DomainName.Len);
if (!context->identity.Domain)
if (!credentials->identity.Domain)
return SEC_E_INTERNAL_ERROR;
CopyMemory(context->identity.Domain, message->DomainName.Buffer, message->DomainName.Len);
context->identity.DomainLength = message->DomainName.Len / 2;
CopyMemory(credentials->identity.Domain, message->DomainName.Buffer, message->DomainName.Len);
credentials->identity.DomainLength = message->DomainName.Len / 2;
}
/* Computations beyond this point require the NTLM hash of the password */
if (credentials->pGetKeyFn)
{
BYTE* value;
void* pKey = NULL;
SECURITY_STATUS GetKeyStatus = SEC_E_UNSUPPORTED_FUNCTION;
if (GetKeyStatus != SEC_E_OK)
{
pKey = &(credentials->identity);
GetKeyStatus = SEC_E_UNSUPPORTED_FUNCTION;
/* plaintext password */
credentials->pGetKeyFn(credentials->pvGetKeyArgument, "NTLM", 0, &pKey, &GetKeyStatus);
if (GetKeyStatus == SEC_E_OK)
{
int status;
value = (BYTE*) pKey;
credentials->identity.Password = NULL;
status = ConvertToUnicode(CP_UTF8, 0, (char*) value, -1,
(LPWSTR*) &credentials->identity.Password, 0);
if (status <= 0)
return SEC_E_INTERNAL_ERROR;
credentials->identity.PasswordLength = (ULONG) (status - 1);
}
}
if (GetKeyStatus != SEC_E_OK)
{
pKey = &(credentials->identity);
GetKeyStatus = SEC_E_UNSUPPORTED_FUNCTION;
/* NTLMv1 Hash */
credentials->pGetKeyFn(credentials->pvGetKeyArgument, "NTLM", 1, &pKey, &GetKeyStatus);
if (GetKeyStatus == SEC_E_OK)
{
value = (BYTE*) pKey;
CopyMemory(context->NtlmHash, value, 16);
}
}
if (GetKeyStatus != SEC_E_OK)
{
pKey = &(credentials->identity);
GetKeyStatus = SEC_E_UNSUPPORTED_FUNCTION;
/* NTLMv2 Hash */
credentials->pGetKeyFn(credentials->pvGetKeyArgument, "NTLM", 2, &pKey, &GetKeyStatus);
if (GetKeyStatus == SEC_E_OK)
{
value = (BYTE*) pKey;
CopyMemory(context->NtlmHash, value, 16);
}
}
if (GetKeyStatus != SEC_E_OK)
{
/* no credentials on the server */
return SEC_E_LOGON_DENIED;
}
}
if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */
@ -961,6 +1032,7 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
UINT32 MicOffset = 0;
UINT32 PayloadBufferOffset;
NTLM_AUTHENTICATE_MESSAGE* message;
SSPI_CREDENTIALS* credentials = context->credentials;
message = &context->AUTHENTICATE_MESSAGE;
ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE));
@ -1007,15 +1079,15 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
message->Workstation.Buffer = (BYTE*) context->Workstation.Buffer;
}
if (context->identity.DomainLength > 0)
if (credentials->identity.DomainLength > 0)
{
message->NegotiateFlags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
message->DomainName.Len = (UINT16) context->identity.DomainLength * 2;
message->DomainName.Buffer = (BYTE*) context->identity.Domain;
message->DomainName.Len = (UINT16) credentials->identity.DomainLength * 2;
message->DomainName.Buffer = (BYTE*) credentials->identity.Domain;
}
message->UserName.Len = (UINT16) context->identity.UserLength * 2;
message->UserName.Buffer = (BYTE*) context->identity.User;
message->UserName.Len = (UINT16) credentials->identity.UserLength * 2;
message->UserName.Buffer = (BYTE*) credentials->identity.User;
message->LmChallengeResponse.Len = (UINT16) context->LmChallengeResponse.cbBuffer;
message->LmChallengeResponse.Buffer = (BYTE*) context->LmChallengeResponse.pvBuffer;

View File

@ -68,7 +68,7 @@ SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(PCredHandle phCre
{
SECURITY_STATUS status;
NEGOTIATE_CONTEXT* context;
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
@ -79,7 +79,7 @@ SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(PCredHandle phCre
if (!context)
return SEC_E_INTERNAL_ERROR;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
sspi_SecureHandleSetLowerPointer(phNewContext, context);
@ -100,7 +100,7 @@ SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(PCredHandle phCre
{
SECURITY_STATUS status;
NEGOTIATE_CONTEXT* context;
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
@ -111,7 +111,7 @@ SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(PCredHandle phCre
if (!context)
return SEC_E_INTERNAL_ERROR;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
sspi_SecureHandleSetLowerPointer(phNewContext, context);
@ -131,7 +131,7 @@ SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(PCredHandle phCredenti
{
SECURITY_STATUS status;
NEGOTIATE_CONTEXT* context;
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
@ -142,7 +142,7 @@ SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(PCredHandle phCredenti
if (!context)
return SEC_E_INTERNAL_ERROR;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
sspi_SecureHandleSetLowerPointer(phNewContext, context);
@ -264,90 +264,68 @@ SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleW(SEC_WCHAR* pszPrin
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
SEC_WINNT_AUTH_IDENTITY* identity;
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
(fCredentialUse != SECPKG_CRED_INBOUND) &&
(fCredentialUse != SECPKG_CRED_BOTH))
{
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INTERNAL_ERROR;
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (identity)
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
return SEC_E_OK;
}
else if (fCredentialUse == SECPKG_CRED_INBOUND)
{
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INTERNAL_ERROR;
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (identity)
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
return SEC_E_OK;
return SEC_E_INVALID_PARAMETER;
}
return SEC_E_UNSUPPORTED_FUNCTION;
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INTERNAL_ERROR;
credentials->fCredentialUse = fCredentialUse;
credentials->pGetKeyFn = pGetKeyFn;
credentials->pvGetKeyArgument = pvGetKeyArgument;
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (identity)
sspi_CopyAuthIdentity(&(credentials->identity), identity);
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
return SEC_E_OK;
}
SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage,
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
SEC_WINNT_AUTH_IDENTITY* identity;
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
(fCredentialUse != SECPKG_CRED_INBOUND) &&
(fCredentialUse != SECPKG_CRED_BOTH))
{
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INTERNAL_ERROR;
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (identity)
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
return SEC_E_OK;
}
else if (fCredentialUse == SECPKG_CRED_INBOUND)
{
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INTERNAL_ERROR;
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (identity)
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
return SEC_E_OK;
return SEC_E_INVALID_PARAMETER;
}
return SEC_E_UNSUPPORTED_FUNCTION;
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INTERNAL_ERROR;
credentials->fCredentialUse = fCredentialUse;
credentials->pGetKeyFn = pGetKeyFn;
credentials->pvGetKeyArgument = pvGetKeyArgument;
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
if (identity)
sspi_CopyAuthIdentity(&(credentials->identity), identity);
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
return SEC_E_OK;
}
SECURITY_STATUS SEC_ENTRY negotiate_QueryCredentialsAttributesW(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
@ -362,12 +340,12 @@ SECURITY_STATUS SEC_ENTRY negotiate_QueryCredentialsAttributesA(PCredHandle phCr
SECURITY_STATUS SEC_ENTRY negotiate_FreeCredentialsHandle(PCredHandle phCredential)
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
if (!phCredential)
return SEC_E_INVALID_HANDLE;
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
if (!credentials)
return SEC_E_INVALID_HANDLE;

View File

@ -28,15 +28,18 @@
#define SSPI_CREDENTIALS_HASH_LENGTH_FACTOR 64
struct _CREDENTIALS
struct _SSPI_CREDENTIALS
{
DWORD flags;
ULONG fCredentialUse;
SEC_GET_KEY_FN pGetKeyFn;
void* pvGetKeyArgument;
SEC_WINNT_AUTH_IDENTITY identity;
};
typedef struct _CREDENTIALS CREDENTIALS;
typedef struct _SSPI_CREDENTIALS SSPI_CREDENTIALS;
CREDENTIALS* sspi_CredentialsNew(void);
void sspi_CredentialsFree(CREDENTIALS* credentials);
SSPI_CREDENTIALS* sspi_CredentialsNew(void);
void sspi_CredentialsFree(SSPI_CREDENTIALS* credentials);
PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType);

View File

@ -216,16 +216,16 @@ void* sspi_ContextBufferAlloc(UINT32 allocatorIndex, size_t size)
return sspi_ContextBufferAlloc(allocatorIndex, size);
}
CREDENTIALS* sspi_CredentialsNew()
SSPI_CREDENTIALS* sspi_CredentialsNew()
{
CREDENTIALS* credentials;
SSPI_CREDENTIALS* credentials;
credentials = (CREDENTIALS*) calloc(1, sizeof(CREDENTIALS));
credentials = (SSPI_CREDENTIALS*) calloc(1, sizeof(SSPI_CREDENTIALS));
return credentials;
}
void sspi_CredentialsFree(CREDENTIALS* credentials)
void sspi_CredentialsFree(SSPI_CREDENTIALS* credentials)
{
if (!credentials)
return;

View File

@ -3,6 +3,17 @@
#include <winpr/sspi.h>
#include <winpr/print.h>
#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 };
struct _TEST_NTLM_CLIENT
{
CtxtHandle context;
@ -33,7 +44,7 @@ int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm, const char* user, const char*
SecInvalidateHandle(&(ntlm->context));
ntlm->table = InitSecurityInterfaceEx(SSPI_INTERFACE_WINPR);
ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password);
@ -177,7 +188,7 @@ int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm)
0, &ntlm->context, &ntlm->outputBufferDesc,
&ntlm->pfContextAttr, &ntlm->expiration);
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_E_OK))
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
{
if (ntlm->table->CompleteAuthToken)
ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
@ -252,15 +263,97 @@ struct _TEST_NTLM_SERVER
};
typedef struct _TEST_NTLM_SERVER TEST_NTLM_SERVER;
int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm, const char* user, const char* domain, const char* password)
void SEC_ENTRY test_ntlm_server_get_key(void* pArg, void* pPrincipal, ULONG KeyVer, void** ppKey, SECURITY_STATUS* pStatus)
{
char* User = NULL;
char* Domain = NULL;
TEST_NTLM_SERVER* ntlm;
SEC_WINNT_AUTH_IDENTITY* identity;
SECURITY_STATUS status = SEC_E_NO_CREDENTIALS;
if (!pPrincipal || !ppKey)
{
*pStatus = SEC_E_INVALID_PARAMETER;
return;
}
ntlm = (TEST_NTLM_SERVER*) pArg;
identity = (SEC_WINNT_AUTH_IDENTITY*) *ppKey;
if (!ntlm || !identity)
{
*pStatus = SEC_E_INVALID_PARAMETER;
return;
}
if (strcmp((char*) pPrincipal, "NTLM") != 0)
{
*pStatus = SEC_E_UNSUPPORTED_FUNCTION;
return;
}
ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) identity->User, identity->UserLength, &User, 0, NULL, NULL);
if (identity->Domain)
ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) identity->Domain, identity->DomainLength, &Domain, 0, NULL, NULL);
if (KeyVer == 0) /* plaintext password */
{
#if 0
char* password;
if (strcmp(User, TEST_NTLM_USER) == 0)
{
password = _strdup(TEST_NTLM_PASSWORD);
*ppKey = (void*) password;
status = SEC_E_OK;
}
#endif
}
else if (KeyVer == 1) /* NTLMv1 Hash */
{
BYTE* hash;
status = SEC_E_NO_CREDENTIALS;
hash = (BYTE*) calloc(1, 16);
if (!hash)
{
*pStatus = SEC_E_INTERNAL_ERROR;
return;
}
if (strcmp(User, TEST_NTLM_USER) == 0)
{
CopyMemory(hash, TEST_NTLM_HASH, 16);
*ppKey = (void*) hash;
status = SEC_E_OK;
}
}
else if (KeyVer == 2) /* NTLMv2 Hash */
{
status = SEC_E_NO_CREDENTIALS;
}
else
{
/* unknown */
status = SEC_E_UNSUPPORTED_FUNCTION;
}
fprintf(stderr, "SecGetKey %s\\%s status: %s (0x%04X)\n",
Domain, User, GetSecurityStatusString(status), status);
*pStatus = status;
}
int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm)
{
SECURITY_STATUS status;
SecInvalidateHandle(&(ntlm->context));
ntlm->table = InitSecurityInterfaceEx(SSPI_INTERFACE_WINPR);
sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password);
ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
status = ntlm->table->QuerySecurityPackageInfo(NTLMSP_NAME, &ntlm->pPackageInfo);
@ -274,7 +367,9 @@ int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm, const char* user, const char*
ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
status = ntlm->table->AcquireCredentialsHandle(NULL, NTLMSP_NAME,
SECPKG_CRED_OUTBOUND, NULL, &ntlm->identity, NULL, NULL, &ntlm->credentials, &ntlm->expiration);
SECPKG_CRED_INBOUND, NULL, NULL,
test_ntlm_server_get_key, (void*) ntlm,
&ntlm->credentials, &ntlm->expiration);
if (status != SEC_E_OK)
{
@ -387,10 +482,6 @@ void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
free(ntlm);
}
static const char* TEST_NTLM_USERNAME = "Username";
static const char* TEST_NTLM_DOMAIN = "Domain";
static const char* TEST_NTLM_PASSWORD = "P4ss123!";
int TestNTLM(int argc, char* argv[])
{
int status;
@ -404,7 +495,7 @@ int TestNTLM(int argc, char* argv[])
client = test_ntlm_client_new();
status = test_ntlm_client_init(client, TEST_NTLM_USERNAME, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD);
status = test_ntlm_client_init(client, TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD);
if (status < 0)
{
@ -418,7 +509,7 @@ int TestNTLM(int argc, char* argv[])
server = test_ntlm_server_new();
status = test_ntlm_server_init(server, TEST_NTLM_USERNAME, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD);
status = test_ntlm_server_init(server);
if (status < 0)
{