Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1812 lines
47 KiB

//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 2000
//
// File: ntdigestutil.cxx
//
// Contents: Utility functions for NtDigest package:
// UnicodeStringDuplicate
// SidDuplicate
// DigestAllocateMemory
// DigestFreeMemory
//
//
// History: KDamour 15Mar00 Stolen from NTLM ntlmutil.cxx
//
//------------------------------------------------------------------------
#include "global.h"
#include <stdio.h>
#include <malloc.h>
#include <des.h>
//+-------------------------------------------------------------------------
//
// Function: UnicodeStringDuplicate
//
// Synopsis: Duplicates a UNICODE_STRING. If the source string buffer is
// NULL the destionation will be too. Assumes Destination has
// no string info (called ClearUnicodeString)
//
// Arguments: DestinationString - Receives a copy of the source string
// SourceString - String to copy
//
// Returns: SEC_E_OK - the copy succeeded
// SEC_E_INSUFFICIENT_MEMORY - the call to allocate
// memory failed.
//
// Requires:
//
// Effects: allocates memory with DigestAllocateMemory
//
// Notes: will add a NULL character to resulting UNICODE_STRING
//
//--------------------------------------------------------------------------
NTSTATUS
UnicodeStringDuplicate(
OUT PUNICODE_STRING DestinationString,
IN OPTIONAL PUNICODE_STRING SourceString
)
{
// DebugLog((DEB_TRACE, "NTDigest:Entering DuplicateUnicodeString\n"));
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(!DestinationString->Buffer); // catch any memory leaks
DestinationString->Buffer = NULL;
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
if ((ARGUMENT_PRESENT(SourceString)) &&
(SourceString->Buffer != NULL))
{
DestinationString->Buffer = (LPWSTR) DigestAllocateMemory(SourceString->Length + sizeof(WCHAR));
if (DestinationString->Buffer != NULL)
{
DestinationString->Length = SourceString->Length;
DestinationString->MaximumLength = SourceString->Length + sizeof(WCHAR);
RtlCopyMemory(
DestinationString->Buffer,
SourceString->Buffer,
SourceString->Length
);
DestinationString->Buffer[SourceString->Length/sizeof(WCHAR)] = L'\0';
}
else
{
Status = SEC_E_INSUFFICIENT_MEMORY;
DebugLog((DEB_ERROR, "NTDigest: UnicodeStringDuplicate, Allocate returns NULL\n"));
goto CleanUp;
}
}
CleanUp:
// DebugLog((DEB_TRACE, "NTDigest: Leaving UnicodeStringDuplicate\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: UnicodeStringCopy
//
// Synopsis: Copies a UNICODE_STRING. If the source string buffer is
// NULL the destionation will be too. If there is enough room
// in the destination, no new memory will be allocated
//
// Arguments: DestinationString - Receives a copy of the source string
// SourceString - String to copy
//
// Returns: SEC_E_OK - the copy succeeded
// SEC_E_INSUFFICIENT_MEMORY - the call to allocate
// memory failed.
//
// Requires:
//
// Effects: no allocation of memory
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
UnicodeStringCopy(
OUT PUNICODE_STRING DestinationString,
IN OPTIONAL PUNICODE_STRING SourceString
)
{
// DebugLog((DEB_TRACE, "NTDigest: Entering StringCopy\n"));
NTSTATUS Status = STATUS_SUCCESS;
// DestinationString->Buffer = NULL;
// DestinationString->Length = 0;
// DestinationString->MaximumLength = 0;
if ((ARGUMENT_PRESENT(SourceString)) &&
(SourceString->Buffer != NULL) &&
(SourceString->Length))
{
if ((DestinationString->Buffer != NULL) &&
(DestinationString->MaximumLength >= (SourceString->Length + sizeof(WCHAR))))
{
DestinationString->Length = SourceString->Length;
RtlCopyMemory(
DestinationString->Buffer,
SourceString->Buffer,
SourceString->Length
);
DestinationString->Buffer[SourceString->Length/sizeof(WCHAR)] = L'\0';
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
DestinationString->Length = 0;
DebugLog((DEB_ERROR, "UnicodeStringCopy: DestinationString not enough space\n"));
goto CleanUp;
}
}
else
{ // Indicate that there is no content in this string
DestinationString->Length = 0;
}
CleanUp:
// DebugLog((DEB_TRACE, "NTDigest: Leaving StringDuplicate\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: UnicodeDuplicatePassword
//
// Synopsis: Duplicates a UNICODE_STRING. If the source string buffer is
// NULL the destionation will be too. The MaximumLength contains
// room for encryption padding data.
//
// Effects: allocates memory with LsaFunctions.AllocatePrivateHeap
//
// Arguments: DestinationString - Receives a copy of the source string
// SourceString - String to copy
//
// Requires:
//
// Returns: SEC_E_OK - the copy succeeded
// SEC_E_INSUFFICIENT_MEMORY - the call to allocate
// memory failed.
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
UnicodeStringDuplicatePassword(
OUT PUNICODE_STRING DestinationString,
IN OPTIONAL PUNICODE_STRING SourceString
)
{
// DebugLog((DEB_TRACE, "Entering UnicodeDuplicatePassword\n"));
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(DestinationString);
ASSERT(!DestinationString->Buffer); // catch any memory leaks
DestinationString->Buffer = NULL;
DestinationString->Length =
DestinationString->MaximumLength =
0;
if ((ARGUMENT_PRESENT(SourceString)) &&
(SourceString->Buffer != NULL))
{
USHORT PaddingLength;
PaddingLength = DESX_BLOCKLEN - (SourceString->Length % DESX_BLOCKLEN);
if( PaddingLength == DESX_BLOCKLEN )
{
PaddingLength = 0;
}
DestinationString->Buffer = (LPWSTR) DigestAllocateMemory(
SourceString->Length +
PaddingLength
);
if (DestinationString->Buffer != NULL)
{
DestinationString->Length = SourceString->Length;
DestinationString->MaximumLength = SourceString->Length + PaddingLength;
if( DestinationString->MaximumLength == SourceString->MaximumLength )
{
//
// duplicating an already padded buffer -- pickup the original
// pad.
//
RtlCopyMemory(
DestinationString->Buffer,
SourceString->Buffer,
SourceString->MaximumLength
);
} else {
//
// duplicating an unpadded buffer -- pickup only the string
// and fill the rest with the boot time pad.
//
RtlCopyMemory(
DestinationString->Buffer,
SourceString->Buffer,
SourceString->Length
);
}
}
else
{
Status = STATUS_NO_MEMORY;
DebugLog((DEB_ERROR, "UnicodeDuplicatePassword, DigestAllocateMemory returns NULL\n"));
goto CleanUp;
}
}
CleanUp:
// DebugLog((DEB_TRACE, "Entering UnicodeDuplicatePassword\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: UnicodeStringAllocate
//
// Synopsis: Allocates cb wide chars to STRING Buffer
//
// Arguments: pString - pointer to String to allocate memory to
//
// Returns: STATUS_SUCCESS - Normal completion
//
// Requires:
//
// Effects: allocates memory and sets STRING sizes
//
// Notes: Must call StringFree() to release memory
//
//--------------------------------------------------------------------------
NTSTATUS
UnicodeStringAllocate(
IN PUNICODE_STRING pString,
IN USHORT cNumWChars
)
{
// DebugLog((DEB_TRACE, "Entering UnicodeStringAllocate\n"));
NTSTATUS Status = STATUS_SUCCESS;
USHORT cb = 0;
ASSERT(pString);
ASSERT(!pString->Buffer);
cb = cNumWChars + 1; // Add in extra room for the terminating NULL
cb = cb * sizeof(WCHAR); // now convert to wide characters
if (ARGUMENT_PRESENT(pString))
{
pString->Length = 0;
pString->Buffer = (PWSTR)DigestAllocateMemory((ULONG)(cb));
if (pString->Buffer)
{
pString->MaximumLength = cb; // this value is in terms of bytes not WCHAR count
}
else
{
pString->MaximumLength = 0;
Status = SEC_E_INSUFFICIENT_MEMORY;
goto CleanUp;
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
goto CleanUp;
}
CleanUp:
// DebugLog((DEB_TRACE, "Leaving UnicodeStringAllocate\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: UnicodeStringClear
//
// Synopsis: Clears a UnicodeString and releases the memory
//
// Arguments: pString - pointer to UnicodeString to clear
//
// Returns: SEC_E_OK - released memory succeeded
//
// Requires:
//
// Effects: de-allocates memory with LsaFunctions.AllocateLsaHeap
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS
UnicodeStringFree(
OUT PUNICODE_STRING pString
)
{
// DebugLog((DEB_TRACE, "NTDigest:Entering UnicodeStringClear\n"));
NTSTATUS Status = STATUS_SUCCESS;
if (ARGUMENT_PRESENT(pString) &&
(pString->Buffer != NULL))
{
DigestFreeMemory(pString->Buffer);
pString->Length = 0;
pString->MaximumLength = 0;
pString->Buffer = NULL;
}
// DebugLog((DEB_TRACE, "NTDigest: Leaving UnicodeStringClear\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: StringVerify
//
// Synopsis: If STRING length non-zero, Buffer exist
//
// Arguments: pString - pointer to String to check
//
// Returns: STATUS_SUCCESS - released memory succeeded
// STATUS_INVALID_PARAMETER - String bad format
//
// Requires:
//
// Effects:
//
// Notes: If Strings are created properly, this should never fail
//
//--------------------------------------------------------------------------
NTSTATUS
StringVerify(
OUT PSTRING pString
)
{
NTSTATUS Status = STATUS_SUCCESS;
if (!pString)
{
return STATUS_INVALID_PARAMETER;
}
// If there is a length, buffer must exist
// MaxSize can not be smaller than string length
if (pString->Length &&
(!pString->Buffer ||
(pString->MaximumLength < pString->Length)))
{
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
//+-------------------------------------------------------------------------
//
// Function: StringDuplicate
//
// Synopsis: Duplicates a STRING. If the source string buffer is
// NULL the destionation will be too.
//
// Arguments: DestinationString - Receives a copy of the source string
// SourceString - String to copy
//
// Returns: SEC_E_OK - the copy succeeded
// SEC_E_INSUFFICIENT_MEMORY - the call to allocate
// memory failed.
//
// Requires:
//
// Effects: allocates memory with LsaFunctions.AllocateLsaHeap
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
StringDuplicate(
OUT PSTRING DestinationString,
IN OPTIONAL PSTRING SourceString
)
{
// DebugLog((DEB_TRACE, "NTDigest: Entering StringDuplicate\n"));
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(DestinationString);
ASSERT(!DestinationString->Buffer); // catch any memory leaks
DestinationString->Buffer = NULL;
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
if ((ARGUMENT_PRESENT(SourceString)) &&
(SourceString->Buffer != NULL))
{
DestinationString->Buffer = (LPSTR) DigestAllocateMemory(
SourceString->Length + sizeof(CHAR));
if (DestinationString->Buffer != NULL)
{
DestinationString->Length = SourceString->Length;
DestinationString->MaximumLength = SourceString->Length + sizeof(CHAR);
RtlCopyMemory(
DestinationString->Buffer,
SourceString->Buffer,
SourceString->Length
);
DestinationString->Buffer[SourceString->Length/sizeof(CHAR)] = '\0';
}
else
{
Status = SEC_E_INSUFFICIENT_MEMORY;
DebugLog((DEB_ERROR, "NTDigest: StringDuplicate, DigestAllocateMemory returns NULL\n"));
goto CleanUp;
}
}
CleanUp:
// DebugLog((DEB_TRACE, "NTDigest: Leaving StringDuplicate\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: StringCopy
//
// Synopsis: Copies a STRING. If the source string buffer is
// NULL the destionation will be too. If there is enough room
// in the destination, no new memory will be allocated
//
// Arguments: DestinationString - Receives a copy of the source string
// SourceString - String to copy
//
// Returns: SEC_E_OK - the copy succeeded
// SEC_E_INSUFFICIENT_MEMORY - the call to allocate
// memory failed.
//
// Requires:
//
// Effects: no allocation of memory
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
StringCopy(
OUT PSTRING DestinationString,
IN OPTIONAL PSTRING SourceString
)
{
// DebugLog((DEB_TRACE, "NTDigest: Entering StringCopy\n"));
NTSTATUS Status = STATUS_SUCCESS;
// DestinationString->Buffer = NULL;
// DestinationString->Length = 0;
// DestinationString->MaximumLength = 0;
if ((ARGUMENT_PRESENT(SourceString)) &&
(SourceString->Buffer != NULL) &&
(SourceString->Length))
{
if ((DestinationString->Buffer != NULL) &&
(DestinationString->MaximumLength >= (SourceString->Length + sizeof(CHAR))))
{
DestinationString->Length = SourceString->Length;
RtlCopyMemory(
DestinationString->Buffer,
SourceString->Buffer,
SourceString->Length
);
DestinationString->Buffer[SourceString->Length/sizeof(CHAR)] = '\0';
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
DestinationString->Length = 0;
DebugLog((DEB_ERROR, "StringCopy: DestinationString not enough space\n"));
goto CleanUp;
}
}
else
{ // Indicate that there is no content in this string
DestinationString->Length = 0;
}
CleanUp:
// DebugLog((DEB_TRACE, "NTDigest: Leaving StringDuplicate\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: StringReference
//
// Synopsis: Reference the source string to the destination. No memory allocated
//
// Arguments: DestinationString - Receives a reference of the source string
// SourceString - String to reference
//
// Returns: SEC_E_OK - the copy succeeded
// SEC_E_INSUFFICIENT_MEMORY - the call to allocate
// memory failed.
//
// Requires:
//
// Effects: no allocation of memory
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
StringReference(
OUT PSTRING pDestinationString,
IN PSTRING pSourceString
)
{
if (!pDestinationString || !pSourceString)
{
return STATUS_INVALID_PARAMETER;
}
// This will only create a reference - no string buffer memory actually copied
memcpy(pDestinationString, pSourceString, sizeof(STRING));
return STATUS_SUCCESS;
}
//+-------------------------------------------------------------------------
//
// Function: StringCharDuplicate
//
// Synopsis: Duplicates a NULL terminated char. If the source string buffer is
// NULL the destionation will be too.
//
// Arguments: Destination - Receives a copy of the source NULL Term char *
// czSource - String to copy
// uCnt - number of characters to copy over (0 if copy until NULL)
//
// Returns: SEC_E_OK - the copy succeeded
// SEC_E_INSUFFICIENT_MEMORY - the call to allocate
// memory failed.
//
// Requires:
//
// Effects: allocates memory with LsaFunctions.AllocateLsaHeap
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
StringCharDuplicate(
OUT PSTRING DestinationString,
IN OPTIONAL char *czSource,
IN OPTIONAL USHORT uCnt
)
{
// DebugLog((DEB_TRACE, "NTDigest: Entering StringCharDuplicate\n"));
NTSTATUS Status = STATUS_SUCCESS;
USHORT cbSourceCz = 0;
//ASSERT(DestinationString);
//ASSERT(!DestinationString->Buffer); // catch any memory leaks
DestinationString->Buffer = NULL;
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
// If uCnt specified then use that as max length, otherwise locate NULL terminator
if (uCnt)
{
cbSourceCz = uCnt;
}
else
{
cbSourceCz = strlen(czSource);
}
if ((ARGUMENT_PRESENT(czSource)) &&
(cbSourceCz != 0))
{
DestinationString->Buffer = (LPSTR) DigestAllocateMemory(cbSourceCz + sizeof(CHAR));
if (DestinationString->Buffer != NULL)
{
DestinationString->Length = cbSourceCz;
DestinationString->MaximumLength = cbSourceCz + sizeof(CHAR);
RtlCopyMemory(
DestinationString->Buffer,
czSource,
cbSourceCz
);
// Since AllocateMemory zeroes out buffer, already NULL terminated
}
else
{
Status = SEC_E_INSUFFICIENT_MEMORY;
DebugLog((DEB_ERROR, "NTDigest: StringCharDuplicate, DigestAllocateMemory returns NULL\n"));
goto CleanUp;
}
}
CleanUp:
// DebugLog((DEB_TRACE, "NTDigest: Leaving StringCharDuplicate\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: StringCharDuplicate
//
// Synopsis: Duplicates a NULL terminated char. If the source string buffer is
// NULL the destionation will be too.
//
// Arguments: Destination - Receives a copy of the source NULL Term char *
// czSource - String to copy
//
// Returns: SEC_E_OK - the copy succeeded
// SEC_E_INSUFFICIENT_MEMORY - the call to allocate
// memory failed.
//
// Requires:
//
// Effects: allocates memory with LsaFunctions.AllocateLsaHeap
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
UnicodeStringWCharDuplicate(
OUT PUNICODE_STRING DestinationString,
IN OPTIONAL WCHAR *szSource
)
{
// DebugLog((DEB_TRACE, "NTDigest: Entering StringCharDuplicate\n"));
NTSTATUS Status = STATUS_SUCCESS;
USHORT cbSourceSz = 0;
ASSERT(DestinationString);
ASSERT(!DestinationString->Buffer); // catch any memory leaks
DestinationString->Buffer = NULL;
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
if ((ARGUMENT_PRESENT(szSource)) &&
((cbSourceSz = (USHORT)wcslen(szSource)) != 0))
{
DestinationString->Buffer = (PWSTR) DigestAllocateMemory((cbSourceSz * sizeof(WCHAR)) + sizeof(WCHAR));
if (DestinationString->Buffer != NULL)
{
DestinationString->Length = (cbSourceSz * sizeof(WCHAR));
DestinationString->MaximumLength = ((cbSourceSz * sizeof(WCHAR)) + sizeof(WCHAR)); // Account for NULL WCHAR at end
RtlCopyMemory(
DestinationString->Buffer,
szSource,
(cbSourceSz * sizeof(WCHAR))
);
DestinationString->Buffer[cbSourceSz] = '\0';
}
else
{
Status = SEC_E_INSUFFICIENT_MEMORY;
DebugLog((DEB_ERROR, "NTDigest: StringCharDuplicate, DigestAllocateMemory returns NULL\n"));
goto CleanUp;
}
}
CleanUp:
// DebugLog((DEB_TRACE, "NTDigest: Leaving StringCharDuplicate\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: UnicodeStringReference
//
// Synopsis: Reference the source unicode_string to the destination. No memory allocated
//
// Arguments: DestinationString - Receives a reference of the source string
// SourceString - String to reference
//
// Returns: SEC_E_OK - the copy succeeded
// SEC_E_INSUFFICIENT_MEMORY - the call to allocate
// memory failed.
//
// Requires:
//
// Effects: no allocation of memory
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
UnicodeStringReference(
OUT PUNICODE_STRING pDestinationString,
IN PUNICODE_STRING pSourceString
)
{
if (!pDestinationString || !pSourceString)
{
return STATUS_INVALID_PARAMETER;
}
// This will only create a reference - no string buffer memory actually copied
memcpy(pDestinationString, pSourceString, sizeof(UNICODE_STRING));
return STATUS_SUCCESS;
}
//+-------------------------------------------------------------------------
//
// Function: DecodeUnicodeString
//
// Synopsis: Convert an encoded string into Unicode
//
// Arguments: pstrSource - pointer to String with encoded input
//
// pustrDestination - pointer to a destination Unicode string
//
// Returns: STATUS_SUCCESS - Normal completion
//
// Requires:
//
// Effects: allocates memory and sets UNICODE_STRING sizes
//
// Notes: Must call UnicodeStringFree() to release memory
//
//--------------------------------------------------------------------------
NTSTATUS
DecodeUnicodeString(
IN PSTRING pstrSource,
IN UINT CodePage,
OUT PUNICODE_STRING pustrDestination
)
{
NTSTATUS Status = STATUS_SUCCESS;
int cNumWChars = 0; // number of wide characters
int cb = 0; // number of bytes to allocate
int iRC = 0; // return code
DWORD dwError = 0;
// Handle case if there is no characters to convert
if (!pstrSource->Length)
{
pustrDestination->Length = 0;
pustrDestination->MaximumLength = 0;
pustrDestination->Buffer = NULL;
goto CleanUp;
}
// Determine number of characters needed in unicode string
cNumWChars = MultiByteToWideChar(CodePage,
0,
pstrSource->Buffer,
pstrSource->Length,
NULL,
0);
if (cNumWChars <= 0)
{
Status = E_FAIL;
dwError = GetLastError();
DebugLog((DEB_ERROR, "DecodeUnicodeString: failed to determine wchar count error 0x%x\n", dwError));
goto CleanUp;
}
Status = UnicodeStringAllocate(pustrDestination, (USHORT)cNumWChars);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR, "DecodeUnicodeString: Failed Unicode allocation\n"));
goto CleanUp;
}
// We now have the space allocated so convert encoded unicode
iRC = MultiByteToWideChar(CodePage,
0,
pstrSource->Buffer,
pstrSource->Length,
pustrDestination->Buffer,
cNumWChars);
if (iRC == 0)
{
UnicodeStringFree(pustrDestination); // Free up allocation on error
Status = E_FAIL;
dwError = GetLastError();
DebugLog((DEB_ERROR, "DecodeUnicodeString: failed to decode source string error 0x%x\n", dwError));
goto CleanUp;
}
// decoding successful set size of unicode string
pustrDestination->Length = (USHORT)(iRC * sizeof(WCHAR));
//DebugLog((DEB_TRACE, "DecodeUnicodeString: string (%Z) is unicode (%wZ)\n", pstrSource, pustrDestination));
//DebugLog((DEB_TRACE, "DecodeUnicodeString: unicode length %d maxlength %d\n",
//pustrDestination->Length, pustrDestination->MaximumLength));
CleanUp:
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: EncodeUnicodeString
//
// Synopsis: Encode a Unicode string into a charset string
//
// Arguments: pustrSource - pointer to Unicode_String with input
//
// pstrDestination - pointer to a destination encoded string
//
// pfUsedDefaultChar - pointer to BOOL if default character had to be used since
// the Source contains characters outside the character set specified
//
// Returns: STATUS_SUCCESS - Normal completion
//
// Requires:
//
// Effects: allocates memory and sets STRING sizes
//
// Notes: Must call StringFree() to release memory
//
//--------------------------------------------------------------------------
NTSTATUS
EncodeUnicodeString(
IN PUNICODE_STRING pustrSource,
IN UINT CodePage,
OUT PSTRING pstrDestination,
IN OUT PBOOL pfUsedDefaultChar
)
{
NTSTATUS Status = STATUS_SUCCESS;
int cNumChars = 0; // number of wide characters
int iRC = 0; // return code
DWORD dwError = 0;
PBOOL pfUsedDef = NULL;
DWORD dwFlags = 0;
// Handle case if there is no characters to convert
if (!pustrSource->Length)
{
pstrDestination->Length = 0;
pstrDestination->MaximumLength = 0;
pstrDestination->Buffer = NULL;
goto CleanUp;
}
// If UTF-8 then do not allow default char mapping (ref MSDN)
if (CodePage != CP_UTF8)
{
pfUsedDef = pfUsedDefaultChar;
dwFlags = WC_NO_BEST_FIT_CHARS;
}
// Determine number of characters needed in unicode string
cNumChars = WideCharToMultiByte(CodePage,
dwFlags,
pustrSource->Buffer,
(pustrSource->Length / sizeof(WCHAR)),
NULL,
0,
NULL,
NULL);
if (cNumChars <= 0)
{
Status = E_FAIL;
dwError = GetLastError();
DebugLog((DEB_ERROR, "EncodeUnicodeString: failed to determine char count error 0x%x\n", dwError));
goto CleanUp;
}
Status = StringAllocate(pstrDestination, (USHORT)cNumChars);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR, "EncodeUnicodeString: Failed String allocation\n"));
goto CleanUp;
}
// We now have the space allocated so convert to encoded unicode
iRC = WideCharToMultiByte(CodePage,
dwFlags,
pustrSource->Buffer,
(pustrSource->Length / sizeof(WCHAR)),
pstrDestination->Buffer,
cNumChars,
NULL,
pfUsedDef);
if (iRC == 0)
{
Status = E_FAIL;
dwError = GetLastError();
DebugLog((DEB_ERROR, "EncodeUnicodeString: failed to decode source string error 0x%x\n", dwError));
StringFree(pstrDestination); // Free up allocation on error
goto CleanUp;
}
// decoding successful set size of unicode string
pstrDestination->Length = (USHORT)iRC;
CleanUp:
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: StringFree
//
// Synopsis: Clears a String and releases the memory
//
// Arguments: pString - pointer to String to clear
//
// Returns: SEC_E_OK - released memory succeeded
//
// Requires:
//
// Effects: de-allocates memory with LsaFunctions.AllocateLsaHeap
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS
StringFree(
IN PSTRING pString
)
{
// DebugLog((DEB_TRACE, "NTDigest:Entering StringFree\n"));
NTSTATUS Status = STATUS_SUCCESS;
if (ARGUMENT_PRESENT(pString) &&
(pString->Buffer != NULL))
{
DigestFreeMemory(pString->Buffer);
pString->Length = 0;
pString->MaximumLength = 0;
pString->Buffer = NULL;
}
// DebugLog((DEB_TRACE, "NTDigest: Leaving StringFree\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: StringAllocate
//
// Synopsis: Allocates cb chars to STRING Buffer
//
// Arguments: pString - pointer to String to allocate memory to
//
// Returns: STATUS_SUCCESS - Normal completion
//
// Requires:
//
// Effects: allocates memory and sets STRING sizes
//
// Notes: Must call StringFree() to release memory
//
//--------------------------------------------------------------------------
NTSTATUS
StringAllocate(
IN PSTRING pString,
IN USHORT cb
)
{
// DebugLog((DEB_TRACE, "NTDigest:Entering StringAllocate\n"));
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(pString);
ASSERT(!pString->Buffer); // catch any memory leaks
cb = cb + 1; // Add in extra room for the terminating NULL
if (ARGUMENT_PRESENT(pString))
{
pString->Length = 0;
pString->Buffer = (char *)DigestAllocateMemory((ULONG)(cb * sizeof(CHAR)));
if (pString->Buffer)
{
pString->MaximumLength = cb;
}
else
{
pString->MaximumLength = 0;
Status = SEC_E_INSUFFICIENT_MEMORY;
goto CleanUp;
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
goto CleanUp;
}
CleanUp:
// DebugLog((DEB_TRACE, "NTDigest: Leaving StringAllocate\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: SidDuplicate
//
// Synopsis: Duplicates a SID
//
// Arguments: DestinationSid - Receives a copy of the SourceSid
// SourceSid - SID to copy
//
// Returns: STATUS_SUCCESS - the copy succeeded
// STATUS_INSUFFICIENT_RESOURCES - the call to allocate memory
// failed
//
// Requires:
//
// Effects: allocates memory with LsaFunctions.AllocateLsaHeap
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
SidDuplicate(
OUT PSID * DestinationSid,
IN PSID SourceSid
)
{
// DebugLog((DEB_TRACE, "NTDigest: Entering SidDuplicate\n"));
NTSTATUS Status = STATUS_SUCCESS;
ULONG SidSize;
// ASSERT(RtlValidSid(SourceSid));
SidSize = RtlLengthSid(SourceSid);
*DestinationSid = (PSID) DigestAllocateMemory( SidSize );
if (ARGUMENT_PRESENT(*DestinationSid))
{
RtlCopyMemory(
*DestinationSid,
SourceSid,
SidSize
);
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
DebugLog((DEB_ERROR, "NTDigest: SidDuplicate, DigestAllocateMemory returns NULL\n"));
goto CleanUp;
}
CleanUp:
// DebugLog((DEB_TRACE, "NTDigest: Leaving SidDuplicate\n"));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: DigestAllocateMemory
//
// Synopsis: Allocate memory in either lsa mode or user mode
//
// Effects: Allocated chunk is zeroed out
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
PVOID
DigestAllocateMemory(
IN ULONG BufferSize
)
{
PVOID Buffer = NULL;
// DebugLog((DEB_TRACE, "Entering DigestAllocateMemory\n"));
if (g_NtDigestState == NtDigestLsaMode)
{
Buffer = g_LsaFunctions->AllocateLsaHeap(BufferSize);
if (Buffer != NULL)
{
RtlZeroMemory(Buffer, BufferSize);
}
DebugLog((DEB_TRACE_MEM, "Memory: LSA alloc %lu bytes at 0x%x\n", BufferSize, Buffer ));
}
else
{
ASSERT(g_NtDigestState == NtDigestUserMode);
Buffer = LocalAlloc(LPTR, BufferSize);
DebugLog((DEB_TRACE_MEM, "Memory: Local alloc %lu bytes at 0x%x\n", BufferSize, Buffer ));
}
// DebugLog((DEB_TRACE, "Leaving DigestAllocateMemory\n"));
return Buffer;
}
//+-------------------------------------------------------------------------
//
// Function: DigestFreeMemory
//
// Synopsis: Free memory in either lsa mode or user mode
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID
DigestFreeMemory(
IN PVOID Buffer
)
{
// DebugLog((DEB_TRACE, "Entering DigestFreeMemory\n"));
if (ARGUMENT_PRESENT(Buffer))
{
if (g_NtDigestState == NtDigestLsaMode)
{
DebugLog((DEB_TRACE_MEM, "DigestFreeMemory: LSA free at 0x%x\n", Buffer ));
g_LsaFunctions->FreeLsaHeap(Buffer);
}
else
{
ASSERT(g_NtDigestState == NtDigestUserMode);
DebugLog((DEB_TRACE_MEM, "DigestFreeMemory: Local free at 0x%x\n", Buffer ));
LocalFree(Buffer);
}
}
// DebugLog((DEB_TRACE, "Leaving DigestFreeMemory\n"));
}
// Helper functions
/*++
Routine Description:
Convert binary data to ASCII hex representation
Arguments:
pSrc - binary data to convert
cSrc - length of binary data
pDst - buffer receiving ASCII representation of pSrc
Return Value:
Nothing
--*/
VOID
BinToHex(
LPBYTE pSrc,
UINT cSrc,
LPSTR pDst
)
{
#define TOHEX(a) ((a)>=10 ? 'a'+(a)-10 : '0'+(a))
for ( UINT x = 0, y = 0 ; x < cSrc ; ++x )
{
UINT v;
v = pSrc[x]>>4;
pDst[y++] = TOHEX( v );
v = pSrc[x]&0x0f;
pDst[y++] = TOHEX( v );
}
pDst[y] = '\0';
}
/*++
Routine Description:
Convert binary data to ASCII hex representation
Arguments:
pSrc - ASCII data to convert to binary
cSrc - length of ASCII data
pDst - buffer receiving binary representation of pSrc
Return Value:
Nothing
--*/
VOID
HexToBin(
LPSTR pSrc,
UINT cSrc,
LPBYTE pDst
)
{
#define TOBIN(a) ((a)>='a' ? (a)-'a'+10 : (a)-'0')
for ( UINT x = 0, y = 0 ; x < cSrc ; x = x + 2 )
{
BYTE v;
v = TOBIN(pSrc[x])<<4;
pDst[y++] = v + TOBIN(pSrc[x+1]);
}
}
//+-------------------------------------------------------------------------
//
// Function: CopyClientString
//
// Synopsis: copies a client string to local memory, including
// allocating space for it locally.
//
// Arguments:
// SourceString - Could be Ansi or Wchar in client process
// SourceLength - bytes
// DoUnicode - whether the string is Wchar
//
// Returns:
// DestinationString - Unicode String in Lsa Process
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS
CopyClientString(
IN PWSTR SourceString,
IN ULONG SourceLength,
IN BOOLEAN DoUnicode,
OUT PUNICODE_STRING DestinationString
)
{
// DebugLog((DEB_TRACE,"NTDigest: Entering CopyClientString\n"));
NTSTATUS Status = STATUS_SUCCESS;
STRING TemporaryString;
ULONG SourceSize = 0;
ULONG CharacterSize = sizeof(CHAR);
ASSERT(DestinationString);
ASSERT(!DestinationString->Buffer);
//
// First initialize the string to zero, in case the source is a null
// string
//
DestinationString->Length = DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
TemporaryString.Buffer = NULL;
if (SourceString != NULL)
{
//
// If the length is zero, allocate one byte for a "\0" terminator
//
if (SourceLength == 0)
{
DestinationString->Buffer = (LPWSTR) DigestAllocateMemory(sizeof(WCHAR));
if (DestinationString->Buffer == NULL)
{
DebugLog((DEB_ERROR,"CopyClientString, Error from DigestAllocate is 0x%lx\n", Status));
Status = SEC_E_INSUFFICIENT_MEMORY;
goto Cleanup;
}
DestinationString->MaximumLength = sizeof(WCHAR);
*DestinationString->Buffer = L'\0';
}
else
{
//
// Allocate a temporary buffer to hold the client string. We may
// then create a buffer for the unicode version. The length
// is the length in characters, so possible expand to hold unicode
// characters and a null terminator.
//
if (DoUnicode)
{
CharacterSize = sizeof(WCHAR);
}
SourceSize = (SourceLength + 1) * CharacterSize;
//
// insure no overflow aggainst UNICODE_STRING
//
if ( (SourceSize > 0xFFFF) ||
((SourceSize - CharacterSize) > 0xFFFF)
)
{
Status = STATUS_INVALID_PARAMETER;
DebugLog((DEB_ERROR,"CopyClientString: SourceSize is too large\n"));
goto Cleanup;
}
TemporaryString.Buffer = (LPSTR) DigestAllocateMemory(SourceSize);
if (TemporaryString.Buffer == NULL)
{
Status = SEC_E_INSUFFICIENT_MEMORY;
DebugLog((DEB_ERROR,"CopyClientString: Error from DigestAllocate is 0x%lx\n", Status));
goto Cleanup;
}
TemporaryString.Length = (USHORT) (SourceSize - CharacterSize);
TemporaryString.MaximumLength = (USHORT) SourceSize;
//
// Finally copy the string from the client
//
Status = g_LsaFunctions->CopyFromClientBuffer(
NULL,
SourceSize - CharacterSize,
TemporaryString.Buffer,
SourceString
);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"CopyClientString: Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
goto Cleanup;
}
//
// If we are doing unicode, finish up now
//
if (DoUnicode)
{
DestinationString->Buffer = (LPWSTR) TemporaryString.Buffer;
DestinationString->Length = (USHORT) (SourceSize - CharacterSize);
DestinationString->MaximumLength = (USHORT) SourceSize;
}
else
{
NTSTATUS Status1;
Status1 = RtlAnsiStringToUnicodeString(
DestinationString,
&TemporaryString,
TRUE
); // allocate destination
if (!NT_SUCCESS(Status1))
{
Status = SEC_E_INSUFFICIENT_MEMORY;
DebugLog((DEB_ERROR,"CopyClientString: Error from RtlAnsiStringToUnicodeString is 0x%lx\n", Status));
goto Cleanup;
}
}
}
}
Cleanup:
if (TemporaryString.Buffer != NULL)
{
//
// Free this if we failed and were doing unicode or if we weren't
// doing unicode
//
if ((DoUnicode && !NT_SUCCESS(Status)) || !DoUnicode)
{
DigestFreeMemory(TemporaryString.Buffer);
}
}
// DebugLog((DEB_TRACE,"NTDigest: Leaving CopyClientString\n"));
return(Status);
}
/*++
Routine Description:
This routine parses a Token Descriptor and pulls out the useful
information.
Arguments:
TokenDescriptor - Descriptor of the buffer containing the token.
BufferIndex - Selects which buffer to extract
Token - Handle to the SecBuffer to write selected buffer to.
ReadonlyOK - TRUE if the token buffer may be readonly.
Return Value:
TRUE - If token buffer was properly found.
--*/
BOOLEAN
SspGetTokenBufferByIndex(
IN PSecBufferDesc TokenDescriptor OPTIONAL,
IN ULONG BufferIndex,
OUT PSecBuffer * Token,
IN BOOLEAN ReadonlyOK
)
{
NTSTATUS StatusTmp = STATUS_SUCCESS;
ULONG i, Index = 0;
PSecBuffer Buffer = NULL;
//
// If there is no TokenDescriptor passed in,
// just pass out NULL to our caller.
//
ASSERT(*Token != NULL);
if ( !ARGUMENT_PRESENT( TokenDescriptor) ) {
return TRUE;
}
if (TokenDescriptor->ulVersion != SECBUFFER_VERSION)
{
DebugLog((DEB_ERROR,"SspGetTokenBufferByIndex: Wrong Version number\n"));
return FALSE;
}
//
// Verify that it is a valid location
//
if (BufferIndex >= TokenDescriptor->cBuffers)
{
DebugLog((DEB_ERROR,"SspGetTokenBufferByIndex: Index out of range for SecBufferDesc\n"));
return FALSE;
}
// DebugLog((DEB_TRACE,"SspGetTokenBufferByIndex: NumberTokens %d\n",TokenDescriptor->cBuffers));
Buffer = &TokenDescriptor->pBuffers[BufferIndex];
//
// If the buffer is readonly and readonly isn't OK,
// reject the buffer.
//
if (!ReadonlyOK && (Buffer->BufferType & SECBUFFER_READONLY))
{
DebugLog((DEB_TRACE,"SspGetTokenBufferByIndex: request write on READONLY Token buffer\n"));
return FALSE;
}
//
// Return the requested information
//
if (Buffer->cbBuffer && Buffer->pvBuffer)
{
StatusTmp = g_LsaFunctions->MapBuffer(Buffer, Buffer);
if (!NT_SUCCESS(StatusTmp))
{
DebugLog((DEB_ERROR,"SspGetTokenBufferByIndex: Unable to MapBuffer 0x%x\n", StatusTmp));
return FALSE;
}
}
*Token = Buffer;
return TRUE;
}
// determine strlen for a counted string buffer which may or may not be terminated
size_t strlencounted(const char *string,
size_t maxcnt)
{
size_t cnt = 0;
if (maxcnt <= 0)
{
return 0;
}
while (maxcnt--)
{
if (!*string)
{
break;
}
cnt++;
string++;
}
return cnt;
}
// determine strlen for a counted string buffer which may or may not be terminated
// maxcnt is the max number of BYTES (so number of unicode chars is 1/2 the maxcnt)
size_t ustrlencounted(const short *string,
size_t maxcnt)
{
size_t cnt = 0;
if (maxcnt <= 0)
{
return 0;
}
maxcnt = maxcnt / 2; // determine number of unicode characters to search
while (maxcnt--)
{
if (!*string)
{
break;
}
cnt++;
string++;
}
return cnt;
}
// Performs a Backslash encoding of the source string into the destination string per RFC 2831
// Section 7.2 and RFC 2616 sect 2.2
NTSTATUS BackslashEncodeString(IN PSTRING pstrSrc, OUT PSTRING pstrDst)
{
NTSTATUS Status = S_OK;
USHORT uCharsMax = 0;
PCHAR pcSrc = NULL;
PCHAR pcDst = NULL;
USHORT uCharsUsed = 0;
USHORT uCharSrcCnt = 0;
StringFree(pstrDst);
if (!pstrSrc || !pstrDst || !pstrSrc->Length)
{
return S_OK;
}
uCharsMax = pstrSrc->Length * 2; // Max size if each character needs to be encoded
Status = StringAllocate(pstrDst, uCharsMax);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"BackshlashEncodeString: String allocation failed 0x%x\n", Status));
goto CleanUp;
}
// now map over each character - encode as necessary
pcSrc = pstrSrc->Buffer;
pcDst = pstrDst->Buffer;
while (uCharSrcCnt < pstrSrc->Length)
{
switch (*pcSrc)
{
case CHAR_DQUOTE:
case CHAR_BACKSLASH:
*pcDst++ = CHAR_BACKSLASH;
*pcDst++ = *pcSrc++;
uCharsUsed+= 2;
break;
default:
*pcDst++ = *pcSrc++;
uCharsUsed++;
break;
}
uCharSrcCnt++;
}
pstrDst->Length = uCharsUsed;
CleanUp:
return Status;
}
// Print out the date and time from a given TimeStamp (converted to localtime)
NTSTATUS PrintTimeString(TimeStamp ConvertTime, BOOL fLocalTime)
{
NTSTATUS Status = STATUS_SUCCESS;
LARGE_INTEGER LocalTime;
LARGE_INTEGER SystemTime;
SystemTime = (LARGE_INTEGER)ConvertTime;
LocalTime.HighPart = 0;
LocalTime.LowPart = 0;
if (ConvertTime.HighPart == 0x7FFFFFFF)
{
DebugLog((DEB_TRACE, "PrintTimeString: Never ends\n"));
}
if (fLocalTime)
{
Status = RtlSystemTimeToLocalTime( &SystemTime, &LocalTime );
if (!NT_SUCCESS( Status )) {
DebugLog((DEB_ERROR, "PrintTimeString: Can't convert time from GMT to Local time\n"));
LocalTime = ConvertTime;
}
}
else
{
LocalTime = ConvertTime;
}
TIME_FIELDS TimeFields;
RtlTimeToTimeFields( &LocalTime, &TimeFields );
DebugLog((DEB_TRACE, "PrintTimeString: %ld/%ld/%ld %ld:%2.2ld:%2.2ld\n",
TimeFields.Month,
TimeFields.Day,
TimeFields.Year,
TimeFields.Hour,
TimeFields.Minute,
TimeFields.Second));
return Status;
}
// Printout the Hex representation of a buffer
NTSTATUS MyPrintBytes(void *pbuff, USHORT uNumBytes, PSTRING pstrOutput)
{
NTSTATUS Status = STATUS_SUCCESS;
USHORT uNumTotal = 0;
PCHAR pctr = NULL;
PCHAR pOut = NULL;
USHORT i = 0;
// Each byte will be encoded as XX <sp>
uNumTotal = (uNumBytes * 3) + 1;
StringFree(pstrOutput);
Status = StringAllocate(pstrOutput, uNumTotal);
if (!NT_SUCCESS (Status))
{
Status = SEC_E_INSUFFICIENT_MEMORY;
DebugLog((DEB_ERROR, "ContextInit: StringAllocate error 0x%x\n", Status));
goto CleanUp;
}
pOut = (PCHAR)pstrOutput->Buffer;
for (i = 0, pctr = (PCHAR)pbuff; i < uNumBytes; i++)
{
sprintf(pOut, "%02x ", (*pctr & 0xff));
pOut += 3;
pctr++;
}
pstrOutput->Length = uNumBytes * 3;
CleanUp:
return Status;
}