libwinpr-sspi: even more code hardening
This commit is contained in:
parent
220f885774
commit
1b5a2340d2
@ -1000,7 +1000,7 @@ extern "C" {
|
||||
WINPR_API void sspi_GlobalInit(void);
|
||||
WINPR_API void sspi_GlobalFinish(void);
|
||||
|
||||
WINPR_API void sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size);
|
||||
WINPR_API void* sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size);
|
||||
WINPR_API void sspi_SecBufferFree(PSecBuffer SecBuffer);
|
||||
|
||||
WINPR_API int sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, char* user, char* domain, char* password);
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* 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.
|
||||
|
@ -173,34 +173,45 @@ NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAv
|
||||
return pAvPairCopy;
|
||||
}
|
||||
|
||||
void ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
|
||||
int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
|
||||
{
|
||||
char* name;
|
||||
int length;
|
||||
int status;
|
||||
DWORD nSize = 0;
|
||||
|
||||
GetComputerNameExA(type, NULL, &nSize);
|
||||
name = malloc(nSize);
|
||||
GetComputerNameExA(type, name, &nSize);
|
||||
|
||||
name = (char*) malloc(nSize);
|
||||
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
if (!GetComputerNameExA(type, name, &nSize))
|
||||
return -1;
|
||||
|
||||
if (type == ComputerNameNetBIOS)
|
||||
CharUpperA(name);
|
||||
|
||||
length = ConvertToUnicode(CP_UTF8, 0, name, -1, &pName->Buffer, 0);
|
||||
status = ConvertToUnicode(CP_UTF8, 0, name, -1, &pName->Buffer, 0);
|
||||
|
||||
pName->Length = (length - 1) * 2;
|
||||
if (status <= 0)
|
||||
return status;
|
||||
|
||||
pName->Length = (USHORT) ((status - 1) * 2);
|
||||
pName->MaximumLength = pName->Length;
|
||||
|
||||
free(name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_free_unicode_string(PUNICODE_STRING string)
|
||||
{
|
||||
if (string != NULL)
|
||||
if (string)
|
||||
{
|
||||
if (string->Length > 0)
|
||||
{
|
||||
if (string->Buffer != NULL)
|
||||
if (string->Buffer)
|
||||
free(string->Buffer);
|
||||
|
||||
string->Buffer = NULL;
|
||||
@ -297,7 +308,7 @@ void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
|
||||
FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
|
||||
}
|
||||
|
||||
void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
int length;
|
||||
ULONG AvPairsCount;
|
||||
@ -310,16 +321,24 @@ void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
UNICODE_STRING DnsComputerName;
|
||||
|
||||
NbDomainName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS);
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
|
||||
return -1;
|
||||
|
||||
NbComputerName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS);
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0)
|
||||
return -1;
|
||||
|
||||
DnsDomainName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain);
|
||||
|
||||
if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0)
|
||||
return -1;
|
||||
|
||||
DnsComputerName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname);
|
||||
|
||||
if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0)
|
||||
return -1;
|
||||
|
||||
AvPairsCount = 5;
|
||||
AvPairsLength = NbDomainName.Length + NbComputerName.Length +
|
||||
@ -342,9 +361,11 @@ void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
ntlm_free_unicode_string(&NbComputerName);
|
||||
ntlm_free_unicode_string(&DnsDomainName);
|
||||
ntlm_free_unicode_string(&DnsComputerName);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
ULONG size;
|
||||
ULONG AvPairsCount;
|
||||
@ -369,31 +390,31 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsTreeName);
|
||||
AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvTimestamp);
|
||||
|
||||
if (AvNbDomainName != NULL)
|
||||
if (AvNbDomainName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvNbDomainName */
|
||||
AvPairsValueLength += AvNbDomainName->AvLen;
|
||||
}
|
||||
|
||||
if (AvNbComputerName != NULL)
|
||||
if (AvNbComputerName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvNbComputerName */
|
||||
AvPairsValueLength += AvNbComputerName->AvLen;
|
||||
}
|
||||
|
||||
if (AvDnsDomainName != NULL)
|
||||
if (AvDnsDomainName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvDnsDomainName */
|
||||
AvPairsValueLength += AvDnsDomainName->AvLen;
|
||||
}
|
||||
|
||||
if (AvDnsComputerName != NULL)
|
||||
if (AvDnsComputerName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvDnsComputerName */
|
||||
AvPairsValueLength += AvDnsComputerName->AvLen;
|
||||
}
|
||||
|
||||
if (AvDnsTreeName != NULL)
|
||||
if (AvDnsTreeName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvDnsTreeName */
|
||||
AvPairsValueLength += AvDnsTreeName->AvLen;
|
||||
@ -448,22 +469,22 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
|
||||
ntlm_av_pair_list_init(AuthenticateTargetInfo);
|
||||
|
||||
if (AvNbDomainName != NULL)
|
||||
if (AvNbDomainName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbDomainName);
|
||||
|
||||
if (AvNbComputerName != NULL)
|
||||
if (AvNbComputerName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbComputerName);
|
||||
|
||||
if (AvDnsDomainName != NULL)
|
||||
if (AvDnsDomainName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsDomainName);
|
||||
|
||||
if (AvDnsComputerName != NULL)
|
||||
if (AvDnsComputerName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsComputerName);
|
||||
|
||||
if (AvDnsTreeName != NULL)
|
||||
if (AvDnsTreeName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsTreeName);
|
||||
|
||||
if (AvTimestamp != NULL)
|
||||
if (AvTimestamp)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvTimestamp);
|
||||
|
||||
if (context->UseMIC)
|
||||
@ -497,4 +518,6 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvEOL);
|
||||
ZeroMemory((void*) AvEOL, 4);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId);
|
||||
NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId, PBYTE Value, UINT16 AvLen);
|
||||
NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAvPair);
|
||||
|
||||
void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context);
|
||||
void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context);
|
||||
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context);
|
||||
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_AV_PAIRS_H */
|
||||
|
@ -32,12 +32,12 @@
|
||||
|
||||
#include "ntlm_compute.h"
|
||||
|
||||
const char lm_magic[] = "KGS!@#$%";
|
||||
const char LM_MAGIC[] = "KGS!@#$%";
|
||||
|
||||
static const char client_sign_magic[] = "session key to client-to-server signing key magic constant";
|
||||
static const char server_sign_magic[] = "session key to server-to-client signing key magic constant";
|
||||
static const char client_seal_magic[] = "session key to client-to-server sealing key magic constant";
|
||||
static const char server_seal_magic[] = "session key to server-to-client sealing key magic constant";
|
||||
static const char NTLM_CLIENT_SIGN_MAGIC[] = "session key to client-to-server signing key magic constant";
|
||||
static const char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client signing key magic constant";
|
||||
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";
|
||||
|
||||
/**
|
||||
* Populate VERSION structure.\n
|
||||
@ -66,13 +66,18 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return -1;
|
||||
|
||||
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 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,7 +112,7 @@ void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
fprintf(stderr, "\tNTLMRevisionCurrent: 0x%02X\n", versionInfo->NTLMRevisionCurrent);
|
||||
}
|
||||
|
||||
void ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
@ -121,10 +126,16 @@ void ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* cha
|
||||
|
||||
size = Stream_Length(s) - Stream_GetPosition(s);
|
||||
challenge->AvPairs = (NTLM_AV_PAIR*) malloc(size);
|
||||
|
||||
if (!challenge->AvPairs)
|
||||
return -1;
|
||||
|
||||
Stream_Read(s, challenge->AvPairs, size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
ULONG length;
|
||||
|
||||
@ -138,57 +149,22 @@ void ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* ch
|
||||
|
||||
length = ntlm_av_pair_list_length(challenge->AvPairs);
|
||||
Stream_Write(s, challenge->AvPairs, length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
{
|
||||
Stream_Read(s, response->Response, 16);
|
||||
ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
return ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
void ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
{
|
||||
Stream_Write(s, response->Response, 16);
|
||||
ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
return ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* Output Restriction_Encoding.\n
|
||||
* Restriction_Encoding @msdn{cc236647}
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_output_restriction_encoding(NTLM_CONTEXT* context)
|
||||
{
|
||||
wStream* s;
|
||||
AV_PAIR* restrictions = &context->av_pairs->Restrictions;
|
||||
|
||||
BYTE machineID[32] =
|
||||
"\x3A\x15\x8E\xA6\x75\x82\xD8\xF7\x3E\x06\xFA\x7A\xB4\xDF\xFD\x43"
|
||||
"\x84\x6C\x02\x3A\xFD\x5A\x94\xFE\xCF\x97\x0F\x3D\x19\x2C\x38\x20";
|
||||
|
||||
restrictions->value = malloc(48);
|
||||
restrictions->length = 48;
|
||||
|
||||
s = PStreamAllocAttach(restrictions->value, restrictions->length);
|
||||
|
||||
Stream_Write_UINT32(s, 48); /* Size */
|
||||
Stream_Zero(s, 4); /* Z4 (set to zero) */
|
||||
|
||||
/* IntegrityLevel (bit 31 set to 1) */
|
||||
Stream_Write_UINT8(s, 1);
|
||||
Stream_Zero(s, 3);
|
||||
|
||||
Stream_Write_UINT32(s, 0x00002000); /* SubjectIntegrityLevel */
|
||||
Stream_Write(s, machineID, 32); /* MachineID */
|
||||
|
||||
PStreamFreeDetach(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get current time, in tenths of microseconds since midnight of January 1, 1601.
|
||||
* @param[out] timestamp 64-bit little-endian timestamp
|
||||
@ -224,20 +200,21 @@ void ntlm_generate_timestamp(NTLM_CONTEXT* context)
|
||||
ntlm_current_time(context->Timestamp);
|
||||
}
|
||||
|
||||
void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
{
|
||||
WINPR_SAM* sam;
|
||||
WINPR_SAM_ENTRY* entry;
|
||||
|
||||
sam = SamOpen(1);
|
||||
if (sam == NULL)
|
||||
return;
|
||||
sam = SamOpen(TRUE);
|
||||
|
||||
if (!sam)
|
||||
return -1;
|
||||
|
||||
entry = SamLookupUserW(sam,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2);
|
||||
|
||||
if (entry != NULL)
|
||||
if (entry)
|
||||
{
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "NTLM Hash:\n");
|
||||
@ -252,13 +229,13 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
SamFreeEntry(sam, entry);
|
||||
SamClose(sam);
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
entry = SamLookupUserW(sam,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2, NULL, 0);
|
||||
|
||||
if (entry != NULL)
|
||||
if (entry)
|
||||
{
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "NTLM Hash:\n");
|
||||
@ -273,17 +250,22 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
SamFreeEntry(sam, entry);
|
||||
SamClose(sam);
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: Could not find user in SAM database\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SamClose(sam);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
int status;
|
||||
int i, hn, ln;
|
||||
char* PasswordHash = NULL;
|
||||
UINT32 PasswordHashLength = 0;
|
||||
@ -291,7 +273,12 @@ void ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
/* Password contains a password hash of length (PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR) */
|
||||
|
||||
PasswordHashLength = context->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR;
|
||||
ConvertFromUnicode(CP_UTF8, 0, context->identity.Password, PasswordHashLength, &PasswordHash, 0, NULL, NULL);
|
||||
|
||||
status = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR) context->identity.Password, PasswordHashLength, &PasswordHash, 0, NULL, NULL);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
CharUpperBuffA(PasswordHash, PasswordHashLength);
|
||||
|
||||
for (i = 0; i < 32; i += 2)
|
||||
@ -302,16 +289,20 @@ void ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
}
|
||||
|
||||
free(PasswordHash);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
{
|
||||
if (context->identity.PasswordLength > 256)
|
||||
{
|
||||
BYTE PasswordHash[16];
|
||||
|
||||
/* Special case for WinPR: password hash */
|
||||
ntlm_convert_password_hash(context, PasswordHash);
|
||||
|
||||
if (ntlm_convert_password_hash(context, PasswordHash) < 0)
|
||||
return -1;
|
||||
|
||||
NTOWFv2FromHashW(PasswordHash,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
@ -328,9 +319,11 @@ void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
{
|
||||
ntlm_fetch_ntlm_v2_hash(context, hash);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
char* response;
|
||||
char value[16];
|
||||
@ -338,19 +331,26 @@ void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
|
||||
if (context->LmCompatibilityLevel < 2)
|
||||
{
|
||||
sspi_SecBufferAlloc(&context->LmChallengeResponse, 24);
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
|
||||
ZeroMemory(context->LmChallengeResponse.pvBuffer, 24);
|
||||
return;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
ntlm_compute_ntlm_v2_hash(context, ntlm_v2_hash);
|
||||
|
||||
if (ntlm_compute_ntlm_v2_hash(context, ntlm_v2_hash) < 0)
|
||||
return -1;
|
||||
|
||||
/* Concatenate the server and client challenges */
|
||||
CopyMemory(value, context->ServerChallenge, 8);
|
||||
CopyMemory(&value[8], context->ClientChallenge, 8);
|
||||
|
||||
sspi_SecBufferAlloc(&context->LmChallengeResponse, 24);
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
|
||||
response = (char*) context->LmChallengeResponse.pvBuffer;
|
||||
|
||||
/* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */
|
||||
@ -358,6 +358,8 @@ void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
|
||||
/* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response (24 bytes) */
|
||||
CopyMemory(&response[16], context->ClientChallenge, 8);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -367,7 +369,7 @@ void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
BYTE* blob;
|
||||
BYTE ntlm_v2_hash[16];
|
||||
@ -378,13 +380,16 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
|
||||
TargetInfo = &context->ChallengeTargetInfo;
|
||||
|
||||
sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28);
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28))
|
||||
return -1;
|
||||
|
||||
ZeroMemory(ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
blob = (BYTE*) ntlm_v2_temp.pvBuffer;
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
ntlm_compute_ntlm_v2_hash(context, (char*) ntlm_v2_hash);
|
||||
|
||||
if (ntlm_compute_ntlm_v2_hash(context, (char*) ntlm_v2_hash) < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "Password (length = %d)\n", context->identity.PasswordLength * 2);
|
||||
@ -425,16 +430,22 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
#endif
|
||||
|
||||
/* Concatenate server challenge with temp */
|
||||
sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8))
|
||||
return -1;
|
||||
|
||||
blob = (BYTE*) ntlm_v2_temp_chal.pvBuffer;
|
||||
CopyMemory(blob, context->ServerChallenge, 8);
|
||||
CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
|
||||
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, ntlm_v2_temp_chal.pvBuffer,
|
||||
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (BYTE*) ntlm_v2_temp_chal.pvBuffer,
|
||||
ntlm_v2_temp_chal.cbBuffer, (void*) nt_proof_str, NULL);
|
||||
|
||||
/* NtChallengeResponse, Concatenate NTProofStr with temp */
|
||||
sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16))
|
||||
return -1;
|
||||
|
||||
blob = (BYTE*) context->NtChallengeResponse.pvBuffer;
|
||||
CopyMemory(blob, nt_proof_str, 16);
|
||||
CopyMemory(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
@ -444,6 +455,8 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
|
||||
sspi_SecBufferFree(&ntlm_v2_temp);
|
||||
sspi_SecBufferFree(&ntlm_v2_temp_chal);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -548,7 +561,7 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
* @param signing_key Destination signing key
|
||||
*/
|
||||
|
||||
void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, BYTE* signing_key)
|
||||
int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, BYTE* signing_key)
|
||||
{
|
||||
int length;
|
||||
BYTE* value;
|
||||
@ -557,6 +570,9 @@ void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic
|
||||
length = 16 + sign_magic->cbBuffer;
|
||||
value = (BYTE*) malloc(length);
|
||||
|
||||
if (!value)
|
||||
return -1;
|
||||
|
||||
/* Concatenate ExportedSessionKey with sign magic */
|
||||
CopyMemory(value, exported_session_key, 16);
|
||||
CopyMemory(&value[16], sign_magic->pvBuffer, sign_magic->cbBuffer);
|
||||
@ -566,6 +582,8 @@ void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic
|
||||
MD5_Final(signing_key, &md5);
|
||||
|
||||
free(value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -576,10 +594,12 @@ void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic
|
||||
|
||||
void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer sign_magic;
|
||||
sign_magic.pvBuffer = (void*) client_sign_magic;
|
||||
sign_magic.cbBuffer = sizeof(client_sign_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sign_magic, context->ClientSigningKey);
|
||||
SecBuffer signMagic;
|
||||
|
||||
signMagic.pvBuffer = (void*) NTLM_CLIENT_SIGN_MAGIC;
|
||||
signMagic.cbBuffer = sizeof(NTLM_CLIENT_SIGN_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ClientSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -590,10 +610,12 @@ void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer sign_magic;
|
||||
sign_magic.pvBuffer = (void*) server_sign_magic;
|
||||
sign_magic.cbBuffer = sizeof(server_sign_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sign_magic, context->ServerSigningKey);
|
||||
SecBuffer signMagic;
|
||||
|
||||
signMagic.pvBuffer = (void*) NTLM_SERVER_SIGN_MAGIC;
|
||||
signMagic.cbBuffer = sizeof(NTLM_SERVER_SIGN_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ServerSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -604,13 +626,15 @@ void ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
* @param sealing_key Destination sealing key
|
||||
*/
|
||||
|
||||
void ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, BYTE* sealing_key)
|
||||
int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, BYTE* sealing_key)
|
||||
{
|
||||
BYTE* p;
|
||||
MD5_CTX md5;
|
||||
SecBuffer buffer;
|
||||
|
||||
sspi_SecBufferAlloc(&buffer, 16 + seal_magic->cbBuffer);
|
||||
if (!sspi_SecBufferAlloc(&buffer, 16 + seal_magic->cbBuffer))
|
||||
return -1;
|
||||
|
||||
p = (BYTE*) buffer.pvBuffer;
|
||||
|
||||
/* Concatenate ExportedSessionKey with seal magic */
|
||||
@ -622,6 +646,8 @@ void ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic
|
||||
MD5_Final(sealing_key, &md5);
|
||||
|
||||
sspi_SecBufferFree(&buffer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -632,10 +658,12 @@ void ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic
|
||||
|
||||
void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer seal_magic;
|
||||
seal_magic.pvBuffer = (void*) client_seal_magic;
|
||||
seal_magic.cbBuffer = sizeof(client_seal_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &seal_magic, context->ClientSealingKey);
|
||||
SecBuffer sealMagic;
|
||||
|
||||
sealMagic.pvBuffer = (void*) NTLM_CLIENT_SEAL_MAGIC;
|
||||
sealMagic.cbBuffer = sizeof(NTLM_CLIENT_SEAL_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ClientSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -646,10 +674,12 @@ void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer seal_magic;
|
||||
seal_magic.pvBuffer = (void*) server_seal_magic;
|
||||
seal_magic.cbBuffer = sizeof(server_seal_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &seal_magic, context->ServerSealingKey);
|
||||
SecBuffer sealMagic;
|
||||
|
||||
sealMagic.pvBuffer = (void*) NTLM_SERVER_SEAL_MAGIC;
|
||||
sealMagic.cbBuffer = sizeof(NTLM_SERVER_SEAL_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ServerSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -690,9 +720,9 @@ void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context)
|
||||
|
||||
HMAC_CTX_init(&hmac_ctx);
|
||||
HMAC_Init_ex(&hmac_ctx, context->ExportedSessionKey, 16, EVP_md5(), NULL);
|
||||
HMAC_Update(&hmac_ctx, context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, (BYTE*) context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, (BYTE*) context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, (BYTE*) context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer);
|
||||
HMAC_Final(&hmac_ctx, context->MessageIntegrityCheck, NULL);
|
||||
HMAC_CTX_cleanup(&hmac_ctx);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Compute)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* 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.
|
||||
@ -25,24 +25,22 @@
|
||||
#include "ntlm_av_pairs.h"
|
||||
|
||||
void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
|
||||
void ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
void ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
|
||||
void ntlm_output_restriction_encoding(NTLM_CONTEXT* context);
|
||||
void ntlm_output_target_name(NTLM_CONTEXT* context);
|
||||
void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_current_time(BYTE* timestamp);
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_compute_ntlm_hash(UINT16* password, UINT32 length, char* hash);
|
||||
void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash);
|
||||
void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash);
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext);
|
||||
void ntlm_generate_client_challenge(NTLM_CONTEXT* context);
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
#include "ntlm_message.h"
|
||||
|
||||
static const char NTLM_SIGNATURE[8] = "NTLMSSP\0";
|
||||
static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' };
|
||||
|
||||
static const char* const NTLM_NEGOTIATE_STRINGS[] =
|
||||
{
|
||||
@ -90,10 +90,15 @@ void ntlm_print_negotiate_flags(UINT32 flags)
|
||||
fprintf(stderr, "}\n");
|
||||
}
|
||||
|
||||
void ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
|
||||
int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
|
||||
{
|
||||
if (Stream_GetRemainingLength(s) < 12)
|
||||
return -1;
|
||||
|
||||
Stream_Read(s, header->Signature, sizeof(NTLM_SIGNATURE));
|
||||
Stream_Read_UINT32(s, header->MessageType);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
|
||||
@ -125,11 +130,16 @@ BOOL ntlm_validate_message_header(wStream* s, NTLM_MESSAGE_HEADER* header, UINT3
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
|
||||
int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
|
||||
{
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return -1;
|
||||
|
||||
Stream_Read_UINT16(s, fields->Len); /* Len (2 bytes) */
|
||||
Stream_Read_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */
|
||||
Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
|
||||
@ -142,14 +152,20 @@ void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
|
||||
Stream_Write_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
|
||||
}
|
||||
|
||||
void ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
|
||||
int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
|
||||
{
|
||||
if (fields->Len > 0)
|
||||
{
|
||||
fields->Buffer = malloc(fields->Len);
|
||||
fields->Buffer = (PBYTE) malloc(fields->Len);
|
||||
|
||||
if (!fields->Buffer)
|
||||
return -1;
|
||||
|
||||
Stream_SetPosition(s, fields->BufferOffset);
|
||||
Stream_Read(s, fields->Buffer, fields->Len);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
|
||||
@ -163,9 +179,9 @@ void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
|
||||
|
||||
void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
|
||||
{
|
||||
if (fields != NULL)
|
||||
if (fields)
|
||||
{
|
||||
if (fields->Buffer != NULL)
|
||||
if (fields->Buffer)
|
||||
{
|
||||
free(fields->Buffer);
|
||||
|
||||
@ -197,9 +213,13 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf
|
||||
message = &context->NEGOTIATE_MESSAGE;
|
||||
ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE));
|
||||
|
||||
s = Stream_New(buffer->pvBuffer, buffer->cbBuffer);
|
||||
s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer);
|
||||
|
||||
ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) message);
|
||||
if (!s)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) message) < 0)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (!ntlm_validate_message_header(s, (NTLM_MESSAGE_HEADER*) message, MESSAGE_TYPE_NEGOTIATE))
|
||||
{
|
||||
@ -222,21 +242,26 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf
|
||||
|
||||
/* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
|
||||
|
||||
/* DomainNameFields (8 bytes) */
|
||||
ntlm_read_message_fields(s, &(message->DomainName));
|
||||
if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
/* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
|
||||
|
||||
/* WorkstationFields (8 bytes) */
|
||||
ntlm_read_message_fields(s, &(message->Workstation));
|
||||
if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
|
||||
ntlm_read_version_info(s, &(message->Version)); /* Version (8 bytes) */
|
||||
{
|
||||
if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
length = Stream_GetPosition(s);
|
||||
buffer->cbBuffer = length;
|
||||
|
||||
sspi_SecBufferAlloc(&context->NegotiateMessage, length);
|
||||
if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length))
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
|
||||
context->NegotiateMessage.BufferType = buffer->BufferType;
|
||||
|
||||
@ -267,7 +292,10 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu
|
||||
message = &context->NEGOTIATE_MESSAGE;
|
||||
ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE));
|
||||
|
||||
s = Stream_New(buffer->pvBuffer, buffer->cbBuffer);
|
||||
s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer);
|
||||
|
||||
if (!s)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
ntlm_populate_message_header((NTLM_MESSAGE_HEADER*) message, MESSAGE_TYPE_NEGOTIATE);
|
||||
|
||||
@ -320,7 +348,9 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu
|
||||
length = Stream_GetPosition(s);
|
||||
buffer->cbBuffer = length;
|
||||
|
||||
sspi_SecBufferAlloc(&context->NegotiateMessage, length);
|
||||
if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length))
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
|
||||
context->NegotiateMessage.BufferType = buffer->BufferType;
|
||||
|
||||
@ -354,11 +384,15 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
|
||||
message = &context->CHALLENGE_MESSAGE;
|
||||
ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE));
|
||||
|
||||
s = Stream_New(buffer->pvBuffer, buffer->cbBuffer);
|
||||
s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer);
|
||||
|
||||
if (!s)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
StartOffset = Stream_Pointer(s);
|
||||
|
||||
ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) message);
|
||||
if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) message) < 0)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (!ntlm_validate_message_header(s, (NTLM_MESSAGE_HEADER*) message, MESSAGE_TYPE_CHALLENGE))
|
||||
{
|
||||
@ -366,39 +400,55 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
/* TargetNameFields (8 bytes) */
|
||||
ntlm_read_message_fields(s, &(message->TargetName));
|
||||
if (ntlm_read_message_fields(s, &(message->TargetName)) < 0) /* TargetNameFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
|
||||
context->NegotiateFlags = message->NegotiateFlags;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
Stream_Read(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */
|
||||
CopyMemory(context->ServerChallenge, message->ServerChallenge, 8);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
Stream_Read(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */
|
||||
|
||||
/* TargetInfoFields (8 bytes) */
|
||||
ntlm_read_message_fields(s, &(message->TargetInfo));
|
||||
if (ntlm_read_message_fields(s, &(message->TargetInfo)) < 0) /* TargetInfoFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
|
||||
ntlm_read_version_info(s, &(message->Version)); /* Version (8 bytes) */
|
||||
{
|
||||
if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
/* Payload (variable) */
|
||||
PayloadOffset = Stream_Pointer(s);
|
||||
|
||||
if (message->TargetName.Len > 0)
|
||||
ntlm_read_message_fields_buffer(s, &(message->TargetName));
|
||||
{
|
||||
if (ntlm_read_message_fields_buffer(s, &(message->TargetName)) < 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (message->TargetInfo.Len > 0)
|
||||
{
|
||||
ntlm_read_message_fields_buffer(s, &(message->TargetInfo));
|
||||
if (ntlm_read_message_fields_buffer(s, &(message->TargetInfo)) < 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer;
|
||||
context->ChallengeTargetInfo.cbBuffer = message->TargetInfo.Len;
|
||||
|
||||
AvTimestamp = ntlm_av_pair_get((NTLM_AV_PAIR*) message->TargetInfo.Buffer, MsvAvTimestamp);
|
||||
|
||||
if (AvTimestamp != NULL)
|
||||
if (AvTimestamp)
|
||||
{
|
||||
if (context->NTLMv2)
|
||||
context->UseMIC = TRUE;
|
||||
@ -409,7 +459,9 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
|
||||
|
||||
length = (PayloadOffset - StartOffset) + message->TargetName.Len + message->TargetInfo.Len;
|
||||
|
||||
sspi_SecBufferAlloc(&context->ChallengeMessage, length);
|
||||
if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length))
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(context->ChallengeMessage.pvBuffer, StartOffset, length);
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
@ -435,32 +487,29 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
|
||||
|
||||
if (context->NTLMv2)
|
||||
{
|
||||
ntlm_construct_authenticate_target_info(context);
|
||||
if (ntlm_construct_authenticate_target_info(context) < 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecBufferFree(&context->ChallengeTargetInfo);
|
||||
context->ChallengeTargetInfo.pvBuffer = context->AuthenticateTargetInfo.pvBuffer;
|
||||
context->ChallengeTargetInfo.cbBuffer = context->AuthenticateTargetInfo.cbBuffer;
|
||||
}
|
||||
|
||||
/* Timestamp */
|
||||
ntlm_generate_timestamp(context);
|
||||
ntlm_generate_timestamp(context); /* Timestamp */
|
||||
|
||||
/* LmChallengeResponse */
|
||||
ntlm_compute_lm_v2_response(context);
|
||||
if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
/* NtChallengeResponse */
|
||||
ntlm_compute_ntlm_v2_response(context);
|
||||
if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
/* KeyExchangeKey */
|
||||
ntlm_generate_key_exchange_key(context);
|
||||
ntlm_generate_key_exchange_key(context); /* KeyExchangeKey */
|
||||
|
||||
/* RandomSessionKey */
|
||||
ntlm_generate_random_session_key(context);
|
||||
ntlm_generate_random_session_key(context); /* RandomSessionKey */
|
||||
|
||||
/* ExportedSessionKey */
|
||||
ntlm_generate_exported_session_key(context);
|
||||
ntlm_generate_exported_session_key(context); /* ExportedSessionKey */
|
||||
|
||||
/* EncryptedRandomSessionKey */
|
||||
ntlm_encrypt_random_session_key(context);
|
||||
ntlm_encrypt_random_session_key(context); /* EncryptedRandomSessionKey */
|
||||
|
||||
/* Generate signing keys */
|
||||
ntlm_generate_client_signing_key(context);
|
||||
@ -538,22 +587,21 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
|
||||
message = &context->CHALLENGE_MESSAGE;
|
||||
ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE));
|
||||
|
||||
s = Stream_New(buffer->pvBuffer, buffer->cbBuffer);
|
||||
s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer);
|
||||
|
||||
/* Version */
|
||||
ntlm_get_version_info(&(message->Version));
|
||||
if (!s)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
/* Server Challenge */
|
||||
ntlm_generate_server_challenge(context);
|
||||
ntlm_get_version_info(&(message->Version)); /* Version */
|
||||
|
||||
/* Timestamp */
|
||||
ntlm_generate_timestamp(context);
|
||||
ntlm_generate_server_challenge(context); /* Server Challenge */
|
||||
|
||||
/* TargetInfo */
|
||||
ntlm_construct_challenge_target_info(context);
|
||||
ntlm_generate_timestamp(context); /* Timestamp */
|
||||
|
||||
/* ServerChallenge */
|
||||
CopyMemory(message->ServerChallenge, context->ServerChallenge, 8);
|
||||
if (ntlm_construct_challenge_target_info(context) < 0) /* TargetInfo */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(message->ServerChallenge, context->ServerChallenge, 8); /* ServerChallenge */
|
||||
|
||||
message->NegotiateFlags = context->NegotiateFlags;
|
||||
|
||||
@ -565,7 +613,7 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
|
||||
if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
|
||||
{
|
||||
message->TargetName.Len = (UINT16) context->TargetName.cbBuffer;
|
||||
message->TargetName.Buffer = context->TargetName.pvBuffer;
|
||||
message->TargetName.Buffer = (PBYTE) context->TargetName.pvBuffer;
|
||||
}
|
||||
|
||||
message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
|
||||
@ -573,7 +621,7 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
|
||||
if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
|
||||
{
|
||||
message->TargetInfo.Len = (UINT16) context->ChallengeTargetInfo.cbBuffer;
|
||||
message->TargetInfo.Buffer = context->ChallengeTargetInfo.pvBuffer;
|
||||
message->TargetInfo.Buffer = (PBYTE) context->ChallengeTargetInfo.pvBuffer;
|
||||
}
|
||||
|
||||
PayloadOffset = 48;
|
||||
@ -609,7 +657,9 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
|
||||
length = Stream_GetPosition(s);
|
||||
buffer->cbBuffer = length;
|
||||
|
||||
sspi_SecBufferAlloc(&context->ChallengeMessage, length);
|
||||
if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length))
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length);
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
@ -652,9 +702,13 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE));
|
||||
ZeroMemory(&response, sizeof(NTLMv2_RESPONSE));
|
||||
|
||||
s = Stream_New(buffer->pvBuffer, buffer->cbBuffer);
|
||||
s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer);
|
||||
|
||||
ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) message);
|
||||
if (!s)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) message) < 0)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (!ntlm_validate_message_header(s, (NTLM_MESSAGE_HEADER*) message, MESSAGE_TYPE_AUTHENTICATE))
|
||||
{
|
||||
@ -662,44 +716,63 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
ntlm_read_message_fields(s, &(message->LmChallengeResponse)); /* LmChallengeResponseFields (8 bytes) */
|
||||
if (ntlm_read_message_fields(s, &(message->LmChallengeResponse)) < 0) /* LmChallengeResponseFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
ntlm_read_message_fields(s, &(message->NtChallengeResponse)); /* NtChallengeResponseFields (8 bytes) */
|
||||
if (ntlm_read_message_fields(s, &(message->NtChallengeResponse)) < 0) /* NtChallengeResponseFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
/* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
|
||||
|
||||
ntlm_read_message_fields(s, &(message->DomainName)); /* DomainNameFields (8 bytes) */
|
||||
if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
ntlm_read_message_fields(s, &(message->UserName)); /* UserNameFields (8 bytes) */
|
||||
if (ntlm_read_message_fields(s, &(message->UserName)) < 0) /* UserNameFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
/* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
|
||||
|
||||
ntlm_read_message_fields(s, &(message->Workstation)); /* WorkstationFields (8 bytes) */
|
||||
if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
ntlm_read_message_fields(s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKeyFields (8 bytes) */
|
||||
if (ntlm_read_message_fields(s, &(message->EncryptedRandomSessionKey)) < 0) /* EncryptedRandomSessionKeyFields (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
|
||||
|
||||
if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
|
||||
ntlm_read_version_info(s, &(message->Version)); /* Version (8 bytes) */
|
||||
{
|
||||
if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
PayloadBufferOffset = Stream_GetPosition(s);
|
||||
|
||||
ntlm_read_message_fields_buffer(s, &(message->DomainName)); /* DomainName */
|
||||
if (ntlm_read_message_fields_buffer(s, &(message->DomainName)) < 0) /* DomainName */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
ntlm_read_message_fields_buffer(s, &(message->UserName)); /* UserName */
|
||||
if (ntlm_read_message_fields_buffer(s, &(message->UserName)) < 0) /* UserName */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
ntlm_read_message_fields_buffer(s, &(message->Workstation)); /* Workstation */
|
||||
if (ntlm_read_message_fields_buffer(s, &(message->Workstation)) < 0) /* Workstation */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
ntlm_read_message_fields_buffer(s, &(message->LmChallengeResponse)); /* LmChallengeResponse */
|
||||
if (ntlm_read_message_fields_buffer(s, &(message->LmChallengeResponse)) < 0) /* LmChallengeResponse */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
ntlm_read_message_fields_buffer(s, &(message->NtChallengeResponse)); /* NtChallengeResponse */
|
||||
if (ntlm_read_message_fields_buffer(s, &(message->NtChallengeResponse)) < 0) /* NtChallengeResponse */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
if (message->NtChallengeResponse.Len > 0)
|
||||
{
|
||||
wStream* s = Stream_New(message->NtChallengeResponse.Buffer, message->NtChallengeResponse.Len);
|
||||
ntlm_read_ntlm_v2_response(s, &response);
|
||||
Stream_Free(s, FALSE);
|
||||
wStream* snt = Stream_New(message->NtChallengeResponse.Buffer, message->NtChallengeResponse.Len);
|
||||
|
||||
if (!snt)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
ntlm_read_ntlm_v2_response(snt, &response);
|
||||
|
||||
Stream_Free(snt, FALSE);
|
||||
|
||||
context->NtChallengeResponse.pvBuffer = message->NtChallengeResponse.Buffer;
|
||||
context->NtChallengeResponse.cbBuffer = message->NtChallengeResponse.Len;
|
||||
@ -711,16 +784,20 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
|
||||
AvFlags = ntlm_av_pair_get(response.Challenge.AvPairs, MsvAvFlags);
|
||||
|
||||
if (AvFlags != NULL)
|
||||
if (AvFlags)
|
||||
flags = *((UINT32*) ntlm_av_pair_get_value_pointer(AvFlags));
|
||||
}
|
||||
|
||||
/* EncryptedRandomSessionKey */
|
||||
ntlm_read_message_fields_buffer(s, &(message->EncryptedRandomSessionKey));
|
||||
if (ntlm_read_message_fields_buffer(s, &(message->EncryptedRandomSessionKey)) < 0) /* EncryptedRandomSessionKey */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(context->EncryptedRandomSessionKey, message->EncryptedRandomSessionKey.Buffer, 16);
|
||||
|
||||
length = Stream_GetPosition(s);
|
||||
sspi_SecBufferAlloc(&context->AuthenticateMessage, length);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length))
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
|
||||
buffer->cbBuffer = length;
|
||||
|
||||
@ -760,6 +837,10 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
if (message->UserName.Len > 0)
|
||||
{
|
||||
context->identity.User = (UINT16*) malloc(message->UserName.Len);
|
||||
|
||||
if (!context->identity.User)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(context->identity.User, message->UserName.Buffer, message->UserName.Len);
|
||||
context->identity.UserLength = message->UserName.Len / 2;
|
||||
}
|
||||
@ -767,15 +848,19 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
if (message->DomainName.Len > 0)
|
||||
{
|
||||
context->identity.Domain = (UINT16*) malloc(message->DomainName.Len);
|
||||
|
||||
if (!context->identity.Domain)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(context->identity.Domain, message->DomainName.Buffer, message->DomainName.Len);
|
||||
context->identity.DomainLength = message->DomainName.Len / 2;
|
||||
}
|
||||
|
||||
/* LmChallengeResponse */
|
||||
ntlm_compute_lm_v2_response(context);
|
||||
if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
/* NtChallengeResponse */
|
||||
ntlm_compute_ntlm_v2_response(context);
|
||||
if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
/* KeyExchangeKey */
|
||||
ntlm_generate_key_exchange_key(context);
|
||||
@ -895,7 +980,10 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
message = &context->AUTHENTICATE_MESSAGE;
|
||||
ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE));
|
||||
|
||||
s = Stream_New(buffer->pvBuffer, buffer->cbBuffer);
|
||||
s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer);
|
||||
|
||||
if (!s)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
if (context->NTLMv2)
|
||||
{
|
||||
@ -947,9 +1035,6 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
message->LmChallengeResponse.Len = (UINT16) context->LmChallengeResponse.cbBuffer;
|
||||
message->LmChallengeResponse.Buffer = (BYTE*) context->LmChallengeResponse.pvBuffer;
|
||||
|
||||
//if (context->NTLMv2)
|
||||
// ZeroMemory(message->LmChallengeResponse.Buffer, message->LmChallengeResponse.Len);
|
||||
|
||||
message->NtChallengeResponse.Len = (UINT16) context->NtChallengeResponse.cbBuffer;
|
||||
message->NtChallengeResponse.Buffer = (BYTE*) context->NtChallengeResponse.pvBuffer;
|
||||
|
||||
@ -1017,7 +1102,10 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
ntlm_write_message_fields_buffer(s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKey */
|
||||
|
||||
length = Stream_GetPosition(s);
|
||||
sspi_SecBufferAlloc(&context->AuthenticateMessage, length);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length))
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
|
||||
buffer->cbBuffer = length;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Message)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* 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.
|
||||
|
@ -223,10 +223,15 @@ void sspi_CredentialsFree(CREDENTIALS* credentials)
|
||||
free(credentials);
|
||||
}
|
||||
|
||||
void sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size)
|
||||
void* sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size)
|
||||
{
|
||||
if (!SecBuffer)
|
||||
return NULL;
|
||||
|
||||
SecBuffer->cbBuffer = size;
|
||||
SecBuffer->pvBuffer = calloc(1, size);
|
||||
|
||||
return SecBuffer->pvBuffer;
|
||||
}
|
||||
|
||||
void sspi_SecBufferFree(PSecBuffer SecBuffer)
|
||||
|
Loading…
Reference in New Issue
Block a user