/*++ 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; SAFE_CRITICAL_SECTION AzGlAllocatorCritSect; GUID AzGlZeroGuid; // // Force C++ to use our allocator // void * __cdecl operator new(size_t s) { return AzpAllocateHeap( s, NULL ); } void __cdecl operator delete(void *pv) { AzpFreeHeap( pv ); } #endif // DBG PVOID AzpAllocateHeap( IN SIZE_T Size, IN LPSTR pDescr OPTIONAL ) /*++ Routine Description Memory allocator. The pDescr field is ignored for Free builds Arguments Size - Size (in bytes) to allocate pDescr - Optional string identifying the block of not more than 8 chars. Return Value Returns a pointer to the allocated memory. NULL - Not enough memory --*/ { DBG_UNREFERENCED_PARAMETER( pDescr ); //ignore return LocalAlloc( 0, Size ); } VOID AzpFreeHeap( IN PVOID Buffer ) /*++ Routine Description Memory de-allocator. Arguments Buffer - address of buffer to free Return Value None --*/ { LocalFree( Buffer ); } DWORD AzpHresultToWinStatus( HRESULT hr ) /*++ Routine Description Convert an Hresult to a WIN 32 status code Arguments hr - Hresult to convert Return Value --*/ { DWORD WinStatus = ERROR_INTERNAL_ERROR; // // Success is still success // if ( hr == NO_ERROR ) { WinStatus = NO_ERROR; // // If the facility is WIN32, // the translation is easy. // } else if ((HRESULT_FACILITY(hr) == FACILITY_WIN32) && (FAILED(hr))) { WinStatus = HRESULT_CODE(hr); if ( WinStatus == ERROR_SUCCESS ) { WinStatus = ERROR_INTERNAL_ERROR; } // // All others should be left intact // } else { WinStatus = hr; } return WinStatus; } // // Debugging support // #ifdef AZROLESDBG #include SAFE_CRITICAL_SECTION AzGlLogFileCritSect; ULONG AzGlDbFlag; // HANDLE AzGlLogFile; #define MAX_PRINTF_LEN 1024 // Arbitrary. VOID AzpDumpGuid( IN DWORD DebugFlag, IN GUID *Guid OPTIONAL ) /*++ Routine Description: Dumps a GUID to the debugger output. Arguments: DebugFlag: Debug flag to pass on to AzPrintRoutine Guid: Guid to print Return Value: none --*/ { RPC_STATUS RpcStatus; unsigned char *StringGuid; // // If we aren't debugging this functionality, just return. // if ( DebugFlag != 0 && (AzGlDbFlag & DebugFlag) == 0 ) { return; } if ( Guid == NULL ) { AzPrint(( DebugFlag, "(null)" )); } else { RpcStatus = UuidToStringA( Guid, &StringGuid ); if ( RpcStatus != RPC_S_OK ) { return; } AzPrint(( DebugFlag, "%s", StringGuid )); RpcStringFreeA( &StringGuid ); } } DWORD AzpConvertSelfRelativeToAbsoluteSD( IN PSECURITY_DESCRIPTOR pSelfRelativeSd, OUT PSECURITY_DESCRIPTOR *ppAbsoluteSD, OUT PACL *ppDacl, OUT PACL *ppSacl ) /*++ Routine Description: This routine returns an absolute form SD for a passed in self-relative form SD. The returned SD and all of its required component(s) need to be freed using AzFreeMemory routine. Arguments: pSelfRelativeSd - Passed in self-relative form SD ppAbsoluteSD - Returned absolute form SD ppDacl - Returned Dacl component if needed ppSacl - Returned Sacl component if needed Return Values: NO_ERROR - The absolute form SD was created successfully Other status codes --*/ { DWORD WinStatus = 0; DWORD dAbsoluteSDLen = 0; DWORD dDaclLen = 0; DWORD dSaclLen = 0; DWORD dOwnerLen = 0; DWORD dGroupLen = 0; PSID pOwner = NULL; PSID pGroup = NULL; // // We first need to get the size for each of its fields // if ( !MakeAbsoluteSD( pSelfRelativeSd, NULL, &dAbsoluteSDLen, NULL, &dDaclLen, NULL, &dSaclLen, NULL, &dOwnerLen, NULL, &dGroupLen ) ) { *ppAbsoluteSD = (PSECURITY_DESCRIPTOR) AzpAllocateHeap( dAbsoluteSDLen, NULL ); if ( *ppAbsoluteSD == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } if ( ppDacl ) { *ppDacl = (PACL) AzpAllocateHeap( dDaclLen, NULL ); if ( *ppDacl == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } } if ( ppSacl ) { *ppSacl = (PACL) AzpAllocateHeap( dSaclLen, NULL ); if ( *ppSacl == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } } if ( dOwnerLen > 0 ) { pOwner = (PSID) AzpAllocateHeap( dOwnerLen, NULL ); if ( pOwner == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } } if ( dGroupLen > 0 ) { pGroup = (PSID) AzpAllocateHeap( dGroupLen, NULL ); if ( pGroup == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } } // // Now do the conversion // if ( !MakeAbsoluteSD( pSelfRelativeSd, *ppAbsoluteSD, &dAbsoluteSDLen, *ppDacl, &dDaclLen, NULL, &dSaclLen, pOwner, &dOwnerLen, pGroup, &dGroupLen ) ) { WinStatus = GetLastError(); goto Cleanup; } } else { WinStatus = GetLastError(); goto Cleanup; } WinStatus = NO_ERROR; Cleanup: if ( pOwner != NULL ) { AzpFreeHeap( pOwner ); } if ( pGroup != NULL ) { AzpFreeHeap( pGroup ); } return WinStatus; } #if 0 // VOID AzpDumpGoRef( IN LPSTR Text, IN struct _GENERIC_OBJECT *GenericObject ) /*++ Routine Description: Dumps the ref count for a generic object Arguments: Text - Description of why the ref count is changing GenericObject - a pointer to the object being ref counted Return Value: none --*/ { LPWSTR StringSid = NULL; LPWSTR StringToPrint; // // If we aren't debugging this functionality, just return. // if ( (AzGlDbFlag & AZD_REF) == 0 ) { return; } // // Convert the sid to a string // if ( GenericObject->ObjectName == NULL ) { StringToPrint = NULL; } else if ( GenericObject->ObjectName->ObjectName.IsSid ) { if ( ConvertSidToStringSid( (PSID)GenericObject->ObjectName->ObjectName.String, &StringSid)) { StringToPrint = StringSid; } else { StringToPrint = L""; } } else { StringToPrint = GenericObject->ObjectName->ObjectName.String; } AzPrint(( AZD_REF, "0x%lx %ld (%ld) %ws: %s\n", GenericObject, GenericObject->ObjectType, GenericObject->ReferenceCount, StringToPrint, Text )); if ( StringSid != NULL ) { LocalFree( StringSid ); } } #endif // 0 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; SafeLeaveCriticalSection( &AzGlLogFileCritSect ); NlOpenDebugFile( TRUE ); NlPrint(( NL_MISC, "Logfile truncated because it was larger than %ld bytes\n", AzGlParameters.LogFileMaxSize )); SafeEnterCriticalSection( &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 = "OBJREF"; break; case AZD_DISPATCH: Text = "DISPATCH"; break; case AZD_ACCESS: case AZD_ACCESS_MORE: Text = "ACCESS"; break; case AZD_DOMREF: Text = "DOMREF"; break; case AZD_XML: Text = "XML"; break; case AZD_SCRIPT: case AZD_SCRIPT_MORE: Text = "SCRIPT"; break; case AZD_CRITICAL: Text = "CRITICAL"; 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. // SafeEnterCriticalSection( &AzGlLogFileCritSect ); // // Simply change arguments to va_list form and call NlPrintRoutineV // va_start(arglist, Format); AzpPrintRoutineV( DebugFlag, Format, arglist ); va_end(arglist); SafeLeaveCriticalSection( &AzGlLogFileCritSect ); } // AzPrintRoutine #endif // AZROLESDBG