//+----------------------------------------------------------------------- // // 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 #include #include //+------------------------------------------------------------------------- // // 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 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; }