|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
util.cxx
Abstract:
Utility routines
Author:
Cliff Van Dyke (cliffv) 11-Apr-2001
--*/
#include "pch.hxx"
#if DBG
//
// List of all allocated blocks
// AccessSerialized by AzGlAllocatorCritSect
LIST_ENTRY AzGlAllocatedBlocks; CRITICAL_SECTION AzGlAllocatorCritSect;
#endif // DBG
PVOID AzpAllocateHeap( IN SIZE_T Size ) /*++
Routine Description
Memory allocator
Arguments
Size - Size (in bytes) to allocate
Return Value
Returns a pointer to the allocated memory. NULL - Not enough memory
--*/ { #if DBG
ULONG HeaderSize = ROUND_UP_COUNT( sizeof(LIST_ENTRY), ALIGN_WORST );
PLIST_ENTRY RealBlock;
//
// Allocate a block with a header
//
RealBlock = (PLIST_ENTRY) LocalAlloc( 0, HeaderSize + Size );
if ( RealBlock == NULL ) { return NULL; }
//
// Link the block since we're nosey.
//
EnterCriticalSection( &AzGlAllocatorCritSect ); InsertHeadList( &AzGlAllocatedBlocks, RealBlock ); LeaveCriticalSection( &AzGlAllocatorCritSect );
return (PVOID)(((LPBYTE)RealBlock)+HeaderSize);
#else // DBG
return LocalAlloc( 0, Size ); #endif // DBG
}
VOID AzpFreeHeap( IN PVOID Buffer ) /*++
Routine Description
Memory de-allocator
Arguments
Buffer - address of buffer to free
Return Value
None
--*/ { #if DBG
ULONG HeaderSize = ROUND_UP_COUNT( sizeof(LIST_ENTRY), ALIGN_WORST ); PLIST_ENTRY RealBlock;
RealBlock = (PLIST_ENTRY)(((LPBYTE)Buffer)-HeaderSize);
EnterCriticalSection( &AzGlAllocatorCritSect ); RemoveEntryList( RealBlock ); LeaveCriticalSection( &AzGlAllocatorCritSect );
LocalFree( RealBlock ); #else // DBG
LocalFree( Buffer ); #endif // DBG
}
VOID AzpInitString( OUT PAZP_STRING AzpString, IN LPWSTR String OPTIONAL ) /*++
Routine Description
Initialize our private string structure to point to a passed in string.
Arguments
AzpString - Initialized string
String - zero terminated string to be reference If NULL, AzpString will be initialized to empty.
Return Value
None
--*/ { //
// Initialization
//
if ( String == NULL ) { AzpString->String = NULL; AzpString->StringSize = 0; } else { AzpString->String = String; AzpString->StringSize = (ULONG) ((wcslen(String)+1)*sizeof(WCHAR)); }
}
DWORD AzpCaptureString( OUT PAZP_STRING AzpString, IN LPCWSTR String, IN ULONG MaximumLength, IN BOOLEAN NullOk ) /*++
Routine Description
Capture the passed in string.
Arguments
AzpString - Captured copy of the passed in string. On success, string must be freed using AzpFreeString
String - zero terminated string to capture
MaximumLength - Maximum length of the string (in characters).
NullOk - if TRUE, a NULL string or zero length string is OK.
Return Value
NO_ERROR - The operation was successful ERROR_NOT_ENOUGH_MEMORY - not enough memory Other exception status codes
--*/ { ULONG WinStatus; ULONG StringSize;
//
// Initialization
//
AzpInitString( AzpString, NULL );
if ( String == NULL ) { if ( !NullOk ) { AzPrint(( AZD_INVPARM, "AzpCaptureString: NULL not ok\n" )); return ERROR_INVALID_PARAMETER; } return NO_ERROR; }
__try {
//
// Validate a passed in LPWSTR
//
ULONG StringLength;
StringLength = (ULONG) wcslen( String );
if ( StringLength == 0 ) { if ( !NullOk ) { AzPrint(( AZD_INVPARM, "AzpCaptureString: zero length not ok\n" )); return ERROR_INVALID_PARAMETER; } return NO_ERROR; }
if ( StringLength > MaximumLength ) { AzPrint(( AZD_INVPARM, "AzpCaptureString: string too long %ld %ld %ws\n", StringLength, MaximumLength, String )); return ERROR_INVALID_PARAMETER; }
StringSize = (StringLength+1)*sizeof(WCHAR);
//
// Allocate and copy the string
//
AzpString->String = (LPWSTR) AzpAllocateHeap( StringSize );
if ( AzpString->String == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; } else {
RtlCopyMemory( AzpString->String, String, StringSize );
AzpString->StringSize = StringSize;
WinStatus = NO_ERROR; }
} __except( EXCEPTION_EXECUTE_HANDLER ) {
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
AzpFreeString( AzpString ); }
return WinStatus; }
DWORD AzpCaptureSid( OUT PAZP_STRING AzpString, IN PSID Sid ) /*++
Routine Description
Capture the passed in SID
Arguments
AzpString - Captured copy of the passed in sid. On success, string must be freed using AzpFreeString
Sid - Sid to capture
Return Value
NO_ERROR - The operation was successful ERROR_NOT_ENOUGH_MEMORY - not enough memory Other exception status codes
--*/ { ULONG WinStatus; ULONG StringSize;
//
// Initialization
//
AzpInitString( AzpString, NULL );
__try {
//
// Validate a passed in SID
//
if ( !RtlValidSid( Sid ) ) { AzPrint(( AZD_INVPARM, "AzpCaptureString: SID not valid\n" )); return ERROR_INVALID_PARAMETER; }
StringSize = RtlLengthSid( Sid );
//
// Allocate and copy the SID
//
AzpString->String = (LPWSTR) AzpAllocateHeap( StringSize );
if ( AzpString->String == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; } else {
RtlCopyMemory( AzpString->String, Sid, StringSize );
AzpString->StringSize = StringSize;
WinStatus = NO_ERROR; }
} __except( EXCEPTION_EXECUTE_HANDLER ) {
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
AzpFreeString( AzpString ); }
return WinStatus; }
DWORD AzpCaptureUlong( IN PVOID PropertyValue, OUT PULONG UlongValue ) /*++
Routine Description
Support routine for the SetProperty API. Capture a parameter for the user application.
Arguments
PropertyValue - Specifies a pointer to the property.
UlongValue - Value to return to make a copy of.
Return Value NO_ERROR - The operation was successful Other exception status codes
--*/ { DWORD WinStatus;
__try { *UlongValue = *(PULONG)PropertyValue; WinStatus = NO_ERROR; } __except( EXCEPTION_EXECUTE_HANDLER ) { WinStatus = RtlNtStatusToDosError( GetExceptionCode()); }
return WinStatus; }
DWORD AzpDuplicateString( OUT PAZP_STRING AzpOutString, IN PAZP_STRING AzpInString ) /*++
Routine Description
Make a duplicate of the passed in string
Arguments
AzpOutString - Returns a copy of the passed in string. On success, string must be freed using AzpFreeString.
AzpInString - Specifies a string to make a copy of.
Return Value
NO_ERROR - The operation was successful ERROR_NOT_ENOUGH_MEMORY - not enough memory
--*/ { ULONG WinStatus;
//
// Initialization
//
AzpInitString( AzpOutString, NULL );
//
// Handle an empty string
//
if ( AzpInString->StringSize == 0 || AzpInString->String == NULL ) {
WinStatus = NO_ERROR;
//
// Allocate and copy the string
//
} else { AzpOutString->String = (LPWSTR) AzpAllocateHeap( AzpInString->StringSize );
if ( AzpOutString->String == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; } else {
RtlCopyMemory( AzpOutString->String, AzpInString->String, AzpInString->StringSize );
AzpOutString->StringSize = AzpInString->StringSize;
WinStatus = NO_ERROR; } }
return WinStatus; }
BOOL AzpEqualStrings( IN PAZP_STRING AzpString1, IN PAZP_STRING AzpString2 ) /*++
Routine Description
Does a case insensitive comparison of two strings
Arguments
AzpString1 - First string to compare
AzpString2 - Second string to compare
Return Value
TRUE: the strings are equal FALSE: the strings are not equal
--*/ {
//
// Simply compare the strings
//
return (AzpCompareStrings( AzpString1, AzpString2 ) == CSTR_EQUAL);
}
LONG AzpCompareStrings( IN PAZP_STRING AzpString1, IN PAZP_STRING AzpString2 ) /*++
Routine Description
Does a case insensitive comparison of two strings
Arguments
AzpString1 - First string to compare
AzpString2 - Second string to compare
Return Value
0: An error ocurred. Call GetLastError(); CSTR_LESS_THAN: String 1 is less than string 2 CSTR_EQUAL: String 1 is equal to string 2 CSTR_GREATER_THAN: String 1 is greater than string 2
--*/ {
//
// Handle NULL
//
if ( AzpString1->String == NULL ) { if ( AzpString2->String == NULL ) { return CSTR_EQUAL; }else { return CSTR_LESS_THAN; } } else { if ( AzpString2->String == NULL ) { return CSTR_GREATER_THAN; } }
//
// Compare the Unicode strings
// Don't compare the trailing zero character.
// (Some callers pass in strings where the trailing character isn't a zero.)
//
return CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, AzpString1->String, (AzpString1->StringSize/sizeof(WCHAR))-1, AzpString2->String, (AzpString2->StringSize/sizeof(WCHAR))-1 );
}
VOID AzpSwapStrings( IN OUT PAZP_STRING AzpString1, IN OUT PAZP_STRING AzpString2 ) /*++
Routine Description
Swap two strings
Arguments
AzpString1 - First string to swap
AzpString2 - Second string to swap
Return Value
None
--*/ { AZP_STRING TempString;
TempString = *AzpString1; *AzpString1 = *AzpString2; *AzpString2 = TempString;
}
VOID AzpFreeString( IN PAZP_STRING AzpString ) /*++
Routine Description
Free the specified string
Arguments
AzpString - String to be freed.
Return Value
None
--*/ { if ( AzpString->String != NULL ) { AzpFreeHeap( AzpString->String ); }
AzpInitString( AzpString, NULL ); }
DWORD AzpAddPtr( IN PAZP_PTR_ARRAY AzpPtrArray, IN PVOID Pointer, IN ULONG Index ) /*++
Routine Description
Inserts a pointer into the array of pointers.
The array will be automatically expanded to be large enough to contain the new pointer. All existing pointers from slot # 'Index' through the end of the existing array will be shifted to later slots.
Arguments
AzpPtrArray - Array that the pointer will be inserted into.
Pointer - Pointer to be inserted.
Index - Index into the array where the 'Pointer' will be inserted If Index is larger than the current size of the array or AZP_ADD_ENDOFLIST, 'Pointer' will be inserted after the existing elements of the array.
Return Value
NO_ERROR - The operation was successful ERROR_NOT_ENOUGH_MEMORY - not enough memory
--*/ {
//
// Ensure Index isn't too large
//
if ( Index > AzpPtrArray->UsedCount ) { Index = AzpPtrArray->UsedCount; }
//
// If the array isn't large enough, make it bigger
//
if ( AzpPtrArray->UsedCount >= AzpPtrArray->AllocatedCount ) { PVOID *TempArray;
//
// Allocate a new array
//
TempArray = (PVOID *) AzpAllocateHeap( (AzpPtrArray->AllocatedCount + AZP_PTR_ARRAY_INCREMENT) * sizeof(PVOID) );
if ( TempArray == NULL ) { return ERROR_NOT_ENOUGH_MEMORY; }
//
// Copy the data into the new array and free the old array
//
if ( AzpPtrArray->Array != NULL ) {
RtlCopyMemory( TempArray, AzpPtrArray->Array, AzpPtrArray->AllocatedCount * sizeof(PVOID) );
AzpFreeHeap( AzpPtrArray->Array ); AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: Free old array\n", AzpPtrArray, AzpPtrArray->Array )); }
//
// Grab the pointer to the new array and clear the new part of the array
//
AzpPtrArray->Array = TempArray; AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: Allocate array\n", AzpPtrArray, AzpPtrArray->Array ));
RtlZeroMemory( &TempArray[AzpPtrArray->UsedCount], AZP_PTR_ARRAY_INCREMENT * sizeof(PVOID) );
AzpPtrArray->AllocatedCount += AZP_PTR_ARRAY_INCREMENT;
}
//
// Shift any old data
//
if ( Index != AzpPtrArray->UsedCount ) {
RtlMoveMemory( &(AzpPtrArray->Array[Index+1]), &(AzpPtrArray->Array[Index]), (AzpPtrArray->UsedCount-Index) * sizeof(PVOID) ); }
//
// Insert the new element
//
AzpPtrArray->Array[Index] = Pointer; AzpPtrArray->UsedCount ++;
return NO_ERROR; }
VOID AzpRemovePtrByIndex( IN PAZP_PTR_ARRAY AzpPtrArray, IN ULONG Index ) /*++
Routine Description
Remove a pointer from the array of pointers.
All existing pointers from slot # 'Index' through the end of the existing array will be shifted to earlier slots.
Arguments
AzpPtrArray - Array that the pointer will be removed into.
Index - Index into the array where the 'Pointer' will be removed from.
Return Value
None
--*/ {
//
// Ensure Index isn't too large
//
ASSERT( Index < AzpPtrArray->UsedCount );
//
// Shift any old data
//
if ( Index+1 != AzpPtrArray->UsedCount ) {
RtlMoveMemory( &(AzpPtrArray->Array[Index]), &(AzpPtrArray->Array[Index+1]), (AzpPtrArray->UsedCount-Index-1) * sizeof(PVOID) ); }
//
// Clear the last element
//
AzpPtrArray->UsedCount--; AzpPtrArray->Array[AzpPtrArray->UsedCount] = NULL;
}
VOID AzpRemovePtrByPtr( IN PAZP_PTR_ARRAY AzpPtrArray, IN PVOID Pointer ) /*++
Routine Description
Removed a pointer from the array of pointers.
All existing pointers following the specified pointer will be shifted to earlier slots.
Arguments
AzpPtrArray - Array that the pointer will be removed into.
Pointer - Pointer to be removed
Return Value
None
--*/ { ULONG i; BOOLEAN FoundIt = FALSE;
for ( i=0; i<AzpPtrArray->UsedCount; i++ ) {
if ( Pointer == AzpPtrArray->Array[i] ) { AzpRemovePtrByIndex( AzpPtrArray, i ); FoundIt = TRUE; break; } }
ASSERT( FoundIt );
}
PVOID AzpGetStringProperty( IN PAZP_STRING AzpString ) /*++
Routine Description
Support routine for the GetProperty API. Convert an AzpString to the form supported by GetProperty.
Empty string are returned as Zero length string instead of NULL
Arguments
AzpString - Specifies a string to make a copy of.
Return Value
Pointer to allocated string. String should be freed using AzFreeMemory. NULL - Not enough memory was available to allocate the string
--*/ { LPWSTR String; ULONG AllocatedSize;
//
// Allocate and copy the string
//
AllocatedSize = AzpString->StringSize ? AzpString->StringSize : sizeof(WCHAR); String = (LPWSTR) AzpAllocateHeap( AllocatedSize );
if ( String != NULL ) {
//
// Convert NULL strings to zero length strings
//
if ( AzpString->StringSize == 0 ) { *String = L'\0';
} else {
RtlCopyMemory( String, AzpString->String, AzpString->StringSize ); }
}
return String; }
PVOID AzpGetUlongProperty( IN ULONG UlongValue ) /*++
Routine Description
Support routine for the GetProperty API. Convert a ULONG to the form supported by GetProperty.
Arguments
UlongValue - Value to return to make a copy of.
Return Value
Pointer to allocated string. String should be freed using AzFreeMemory. NULL - Not enough memory was available to allocate the string
--*/ { PULONG RetValue;
//
// Allocate and copy the string
//
RetValue = (PULONG) AzpAllocateHeap( sizeof(ULONG) );
if ( RetValue != NULL ) {
*RetValue = UlongValue;
}
return RetValue; }
//
// Debugging support
//
#ifdef AZROLESDBG
#include <stdio.h>
CRITICAL_SECTION AzGlLogFileCritSect; ULONG AzGlDbFlag; // HANDLE AzGlLogFile;
#define MAX_PRINTF_LEN 1024 // Arbitrary.
VOID AzpPrintRoutineV( IN DWORD DebugFlag, IN LPSTR Format, va_list arglist ) /*++
Routine Description
Debug routine for azroles
Arguments
DebugFlag - Flag to indicating the functionality being debugged
--- Other printf parameters
Return Value
--*/
{ static LPSTR AzGlLogFileOutputBuffer = NULL; ULONG length; int lengthTmp; // DWORD BytesWritten;
static BeginningOfLine = TRUE; static LineCount = 0; static TruncateLogFileInProgress = FALSE; static LogProblemWarned = FALSE;
//
// If we aren't debugging this functionality, just return.
//
if ( DebugFlag != 0 && (AzGlDbFlag & DebugFlag) == 0 ) { return; }
//
// Allocate a buffer to build the line in.
// If there isn't already one.
//
length = 0;
if ( AzGlLogFileOutputBuffer == NULL ) { AzGlLogFileOutputBuffer = (LPSTR) LocalAlloc( 0, MAX_PRINTF_LEN + 1 );
if ( AzGlLogFileOutputBuffer == NULL ) { return; } }
//
// Handle the beginning of a new line.
//
//
if ( BeginningOfLine ) {
//
// Never print empty lines.
//
if ( Format[0] == '\n' && Format[1] == '\0' ) { return; }
#if 0
//
// If the log file is getting huge,
// truncate it.
//
if ( AzGlLogFile != INVALID_HANDLE_VALUE && !TruncateLogFileInProgress ) {
//
// Only check every 50 lines,
//
LineCount++; if ( LineCount >= 50 ) { DWORD FileSize; LineCount = 0;
//
// Is the log file too big?
//
FileSize = GetFileSize( AzGlLogFile, NULL ); if ( FileSize == 0xFFFFFFFF ) { (void) DbgPrint( "[NETLOGON] Cannot GetFileSize %ld\n", GetLastError ); } else if ( FileSize > AzGlParameters.LogFileMaxSize ) { TruncateLogFileInProgress = TRUE; LeaveCriticalSection( &AzGlLogFileCritSect ); NlOpenDebugFile( TRUE ); NlPrint(( NL_MISC, "Logfile truncated because it was larger than %ld bytes\n", AzGlParameters.LogFileMaxSize )); EnterCriticalSection( &AzGlLogFileCritSect ); TruncateLogFileInProgress = FALSE; }
} }
//
// If we're writing to the debug terminal,
// indicate this is a azroles message.
//
if ( AzGlLogFile == INVALID_HANDLE_VALUE ) { length += (ULONG) sprintf( &AzGlLogFileOutputBuffer[length], "[AZROLES] " ); }
//
// Put the timestamp at the begining of the line.
//
{ SYSTEMTIME SystemTime; GetLocalTime( &SystemTime ); length += (ULONG) sprintf( &AzGlLogFileOutputBuffer[length], "%02u/%02u %02u:%02u:%02u ", SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond ); } #endif // 0
//
// Indicate the type of message on the line
//
{ char *Text;
switch (DebugFlag) { case AZD_HANDLE: Text = "HANDLE"; break; case AZD_OBJLIST: Text = "OBJLIST"; break; case AZD_INVPARM: Text = "INVPARM"; break; case AZD_PERSIST: case AZD_PERSIST_MORE: Text = "PERSIST"; break; case AZD_REF: Text = "REF"; break; default: Text = "UNKNOWN"; break;
case 0: Text = NULL; } if ( Text != NULL ) { length += (ULONG) sprintf( &AzGlLogFileOutputBuffer[length], "[%s] ", Text ); } } }
//
// Put a the information requested by the caller onto the line
//
lengthTmp = (ULONG) _vsnprintf( &AzGlLogFileOutputBuffer[length], MAX_PRINTF_LEN - length - 1, Format, arglist );
if ( lengthTmp < 0 ) { length = MAX_PRINTF_LEN - 1; // always end the line which cannot fit into the buffer
AzGlLogFileOutputBuffer[length-1] = '\n'; } else { length += lengthTmp; }
BeginningOfLine = (length > 0 && AzGlLogFileOutputBuffer[length-1] == '\n' ); if ( BeginningOfLine ) { AzGlLogFileOutputBuffer[length-1] = '\r'; AzGlLogFileOutputBuffer[length] = '\n'; AzGlLogFileOutputBuffer[length+1] = '\0'; length++; }
#if 0
//
// If the log file isn't open,
// just output to the debug terminal
//
if ( AzGlLogFile == INVALID_HANDLE_VALUE ) { #if DBG
if ( !LogProblemWarned ) { (void) DbgPrint( "[NETLOGON] Cannot write to log file [Invalid Handle]\n" ); LogProblemWarned = TRUE; } #endif // DBG
//
// Write the debug info to the log file.
//
} else { if ( !WriteFile( AzGlLogFile, AzGlLogFileOutputBuffer, length, &BytesWritten, NULL ) ) { #if DBG
if ( !LogProblemWarned ) { (void) DbgPrint( "[NETLOGON] Cannot write to log file %ld\n", GetLastError() ); LogProblemWarned = TRUE; } #endif // DBG
}
} #else // 0
printf( "%s", AzGlLogFileOutputBuffer ); #endif // 0
}
VOID AzpPrintRoutine( IN DWORD DebugFlag, IN LPSTR Format, ... )
{ va_list arglist;
//
// vsprintf isn't multithreaded + we don't want to intermingle output
// from different threads.
//
EnterCriticalSection( &AzGlLogFileCritSect );
//
// Simply change arguments to va_list form and call NlPrintRoutineV
//
va_start(arglist, Format);
AzpPrintRoutineV( DebugFlag, Format, arglist );
va_end(arglist);
LeaveCriticalSection( &AzGlLogFileCritSect );
} // AzPrintRoutine
#endif // AZROLESDBG
|