/*++ Copyright (c) 1997-2000 Microsoft Corporation Module Name: common.h Abstract: This file contains structures and functions used in Ntdll.dll and advapi32.dll --*/ #define STRSAFE_NO_DEPRECATE #include #define EtwpNtStatusToDosError(Status) ((ULONG)((Status == STATUS_SUCCESS)?ERROR_SUCCESS:RtlNtStatusToDosError(Status))) #define DEFAULT_ALLOC_SIZE 4096 #define MAXSTR 1024 #if !defined (_NTDLLBUILD_) extern void EtwpCallHWConfig(ULONG Reason); #endif HANDLE EtwpWin32Event; __inline ULONG EtwpSetDosError( IN ULONG DosError ) { #if defined (_NTDLLBUILD_) EtwpSetLastError(DosError); #else SetLastError(DosError); #endif return DosError; } #if defined (_NTDLLBUILD_) extern RTL_CRITICAL_SECTION UMLogCritSect; BOOLEAN EtwLocksInitialized = FALSE; #endif HINSTANCE DllInstanceHandle; extern HANDLE EtwpKMHandle; #if DBG #define MOFLISTSIZEGUESS 1 BOOLEAN EtwpLoggingEnabled = FALSE; #else #define MOFLISTSIZEGUESS 10 #endif #ifndef MEMPHIS RTL_CRITICAL_SECTION PMCritSect; HANDLE EtwpCBInProgressEvent = NULL; PVOID EtwpProcessHeap = NULL; HANDLE EtwpDeviceHandle; #else HANDLE PMMutex; #endif NTSTATUS EtwpInitializeDll( void ) /*+++ Routine Description: Arguments: Return Value: ---*/ { #ifdef MEMPHIS NTSTATUS Status; OBJECT_ATTRIBUTES Obja; Status = NtCreateMutant(&PMMutex, MUTANT_ALL_ACCESS, BaseFormatObjectAttributes(&Obja, NULL, NULL) FALSE); if (! NT_SUCCESS(Status)) { return(Status); } #else NTSTATUS Status; Status = RtlInitializeCriticalSection(&PMCritSect); if (! NT_SUCCESS(Status)) { return(Status); } Status = NtCreateEvent(&EtwpCBInProgressEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, TRUE); if (! NT_SUCCESS(Status)) { RtlDeleteCriticalSection(&PMCritSect); // Delete PMCritSec. return (Status); } #if defined (_NTDLLBUILD_) Status = RtlInitializeCriticalSection(&UMLogCritSect); if (! NT_SUCCESS(Status)) { RtlDeleteCriticalSection(&PMCritSect); // Delete PMCritSec. NtClose(EtwpCBInProgressEvent); EtwpCBInProgressEvent = NULL; return(Status); } EtwLocksInitialized = TRUE; #endif #endif return(STATUS_SUCCESS); } void EtwpDeinitializeDll( void ) /*+++ Routine Description: Arguments: Return Value: ---*/ { #ifdef MEMPHIS CloseHandle(PMMutex); #else #if defined (_NTDLLBUILD_) if(EtwLocksInitialized){ EtwLocksInitialized = FALSE; #endif RtlDeleteCriticalSection(&PMCritSect); NtClose(EtwpCBInProgressEvent); EtwpCBInProgressEvent = NULL; #if defined (_NTDLLBUILD_) RtlDeleteCriticalSection(&UMLogCritSect); } #endif if ((EtwpProcessHeap != NULL) && (EtwpProcessHeap != RtlProcessHeap())) { RtlDestroyHeap(EtwpProcessHeap); EtwpProcessHeap = NULL; } if (EtwpDeviceHandle != NULL) { #if defined (_NTDLLBUILD_) EtwpCloseHandle(EtwpDeviceHandle); #else CloseHandle(EtwpDeviceHandle); #endif EtwpDeviceHandle = NULL; } #endif if (EtwpWin32Event != NULL) { #if defined (_NTDLLBUILD_) EtwpCloseHandle(EtwpWin32Event); #else CloseHandle(EtwpWin32Event); #endif EtwpWin32Event = NULL; } } NTSTATUS EtwpRegOpenKey( IN PCWSTR lpKeyName, OUT PHANDLE KeyHandle ) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName; RtlInitUnicodeString( &KeyName, lpKeyName ); RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES)); InitializeObjectAttributes( &ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL ); return NtOpenKey( KeyHandle, KEY_READ, &ObjectAttributes ); } NTSTATUS EtwpRegQueryValueKey( IN HANDLE KeyHandle, IN LPWSTR lpValueName, IN ULONG Length, OUT PVOID KeyValue, OUT PULONG ResultLength ) { UNICODE_STRING ValueName; ULONG BufferLength; NTSTATUS Status; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; RtlInitUnicodeString( &ValueName, lpValueName ); BufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + Length; KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) RtlAllocateHeap (RtlProcessHeap(),0,BufferLength); if (KeyValueInformation == NULL) { return STATUS_NO_MEMORY; } Status = NtQueryValueKey( KeyHandle, &ValueName, KeyValuePartialInformation, KeyValueInformation, BufferLength, ResultLength ); if (NT_SUCCESS(Status)) { RtlCopyMemory(KeyValue, KeyValueInformation->Data, KeyValueInformation->DataLength ); *ResultLength = KeyValueInformation->DataLength; if (KeyValueInformation->Type == REG_SZ) { if (KeyValueInformation->DataLength + sizeof(WCHAR) > Length) { KeyValueInformation->DataLength -= sizeof(WCHAR); } ((PUCHAR)KeyValue)[KeyValueInformation->DataLength++] = 0; ((PUCHAR)KeyValue)[KeyValueInformation->DataLength] = 0; *ResultLength = KeyValueInformation->DataLength + sizeof(WCHAR); } } RtlFreeHeap(RtlProcessHeap(),0,KeyValueInformation); return Status; } #if DBG NTSTATUS EtwpGetRegistryValue( TCHAR *ValueName, PULONG Value ) { NTSTATUS Status = STATUS_UNSUCCESSFUL; ULONG DataLength; HANDLE Handle = INVALID_HANDLE_VALUE; Status = EtwpRegOpenKey(WmiRegKeyText, &Handle); if (NT_SUCCESS(Status)) { Status = EtwpRegQueryValueKey(Handle, ValueName, sizeof(DWORD), (PVOID)Value, &DataLength ); NtClose(Handle); } return Status; } #endif BOOLEAN WmiDllInitialize( IN PVOID DllBase, IN ULONG Reason, IN PCONTEXT Context OPTIONAL ) /*++ Routine Description: This function implements Win32 base dll initialization. Arguments: DllHandle - Reason - attach\detach Context - Not Used Return Value: STATUS_SUCCESS --*/ { // // NOTE : Do not use WMI heap in this function // or in any of the routines called subsequently // as WMI Heap is not initialized until any ETW API // is called. // NTSTATUS Status = STATUS_SUCCESS; ULONG Foo; DllInstanceHandle = (HINSTANCE)DllBase; if (Reason == DLL_PROCESS_ATTACH) { #if DBG Foo = EtwpLoggingEnabled ? 1 : 0; EtwpGetRegistryValue(LoggingEnableValueText, &Foo); EtwpLoggingEnabled = (Foo == 0) ? FALSE : TRUE; #endif Status = EtwpInitializeDll(); } else if (Reason == DLL_PROCESS_DETACH) { // // Don't need to clean up if process is exiting // if (Context == NULL) { EtwpDeinitializeDll(); } if (EtwpKMHandle != (HANDLE)NULL) { #if defined (_NTDLLBUILD_) EtwpCloseHandle(EtwpKMHandle); #else CloseHandle(EtwpKMHandle); #endif } } #if !defined (_NTDLLBUILD_) EtwpCallHWConfig(Reason); #endif return(NT_SUCCESS(Status)); } #ifndef MEMPHIS VOID EtwpCreateHeap( void ) { EtwpEnterPMCritSection(); if (EtwpProcessHeap == NULL) { EtwpProcessHeap = RtlCreateHeap(HEAP_GROWABLE, NULL, DLLRESERVEDHEAPSIZE, DLLCOMMITHEAPSIZE, NULL, NULL); if (EtwpProcessHeap == NULL) { EtwpDebugPrint(("WMI: Cannot create EtwpProcessHeap, using process default\n")); EtwpProcessHeap = RtlProcessHeap(); } } EtwpLeavePMCritSection(); // // This has been copied to this function as in ntdll // we cannot execute WmiInitializeDll codepath. And // EtwpLoggingEnabled has to be checked only once. // So this place should be okay to initialze // EtwpLoggingEnabled // #if DBG && defined(_NTDLLBUILD_) { ULONG Foo; Foo = EtwpLoggingEnabled ? 1 : 0; EtwpGetRegistryValue(&LoggingEnableValueText, &Foo); EtwpLoggingEnabled = (Foo == 0) ? FALSE : TRUE; } #endif } #endif ULONG EtwpGetMofResourceList( PWMIMOFLIST *MofListPtr ) { ULONG MofListSize; PWMIMOFLIST MofList; ULONG RetSize=0; ULONG Status; // // Make an intelligent guess as to the size needed to get all of // the MOF resources // *MofListPtr = NULL; MofListSize = MOFLISTSIZEGUESS * (sizeof(WMIMOFLIST) + (MAX_PATH + MAX_PATH) * sizeof(WCHAR)); MofList = EtwpAlloc(MofListSize); if (MofList != NULL) { Status = EtwpSendWmiKMRequest(NULL, IOCTL_WMI_ENUMERATE_MOF_RESOURCES, NULL, 0, MofList, MofListSize, &RetSize, NULL); if ((Status == ERROR_SUCCESS) && (RetSize == sizeof(ULONG))) { // // The buffer was too small, but we now know how much we'll // need. // MofListSize = MofList->MofListCount; EtwpFree(MofList); MofList = EtwpAlloc(MofListSize); if (MofList != NULL) { // // Now lets retry the query // Status = EtwpSendWmiKMRequest(NULL, IOCTL_WMI_ENUMERATE_MOF_RESOURCES, NULL, 0, MofList, MofListSize, &RetSize, NULL); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } } } else { Status = ERROR_NOT_ENOUGH_MEMORY; } if (Status == ERROR_SUCCESS) { if (RetSize >= sizeof(WMIMOFLIST)) { *MofListPtr = MofList; } else { Status = ERROR_INVALID_PARAMETER; EtwpFree(MofList); } } else if (MofList != NULL) { EtwpFree(MofList); } return(Status); } PWCHAR EtwpRegistryToImagePath( PWCHAR ImagePath, PWCHAR RegistryPath ) /*++ Routine Description: This routine will determine the location of the device driver's image file from its registry path Arguments: RegistryPath is a pointer to the driver's registry path ImagePath is buffer of length MAX_PATH and returns the image path Return Value: pointer to Image path of driver or NULL if image path is unavailable --*/ { #define SystemRoot TEXT("\\SystemRoot\\") #ifdef MEMPHIS #define SystemRootDirectory TEXT("%WinDir%\\") #else #define SystemRootDirectory TEXT("%SystemRoot%\\") #endif #define SystemRootCharSize (( sizeof(SystemRoot) / sizeof(WCHAR) ) - 1) #define DriversDirectory TEXT("\\System32\\Drivers\\") #define NdisDriversDirectory TEXT("\\System\\") #define QuestionPrefix TEXT("\\??\\") #define QuestionPrefixSize (( sizeof(QuestionPrefix) / sizeof(WCHAR) ) - 1) #define RegistryPrefix TEXT("\\Registry") HKEY RegKey; PWCHAR ImagePathPtr = NULL; ULONG ValueType; ULONG Size; PWCHAR DriverName; ULONG Len; BOOLEAN DefaultImageName; PWCHAR DriversDirectoryPath; WCHAR *Buffer; WCHAR *FullRegistryPath; WCHAR RegBuffer[DEFAULT_ALLOC_SIZE]; Buffer = (PTCHAR)EtwpAlloc(2 * MAX_PATH * sizeof(WCHAR)); if (Buffer != NULL) { FullRegistryPath = Buffer + MAX_PATH; // // Get the driver file name or the MOF image path from the KM // registry path. Here are the rules: // // 1. First check the MofImagePath value in the registry in case the // mof resource is in a different file from the driver. // 2. Next check the ImagePath value since the mof resource is assumed // to be part of the driver image. // 3. If no MofImagePath or ImagePath values then assume the mof resource // is in the driver file and compose the driver file name as // %SystemRoot%\System32\driver.sys. // 4. If MofImagePath or ImagePath was specified then // - Check first char for % or second character for :, or prefix // of \??\ and if so use EtwpExpandEnvironmentStringsW // - Check first part of path for \SystemRoot\, if so rebuild string // as %SystemRoot%\ and use ExpandEnvironementStrings // - Assume format D below and prepend %SystemRoot%\ and use // EtwpExpandEnvironmentStringsW // If MofImagePath or ImagePath value is present and it is a REG_EXPAND_SZ // then it is used to locate the file that holds the mof resource. It // can be in one of the following formats: // Format A - %SystemRoot%\System32\Foo.Dll // Format B -C:\WINNT\SYSTEM32\Drivers\Foo.SYS // Format C - \SystemRoot\System32\Drivers\Foo.SYS // Format D - System32\Drivers\Foo.Sys // Format E - \??\c:\foo.sys Len = wcslen(RegistryPath); if (Len > 0) { DriverName = RegistryPath + Len; while ((*(--DriverName) != '\\') && (--Len > 0)) ; } if (Len == 0) { EtwpDebugPrint(("WMI: Badly formed registry path %ws\n", RegistryPath)); EtwpFree(Buffer); return(NULL); } DriverName++; StringCchCopyW(FullRegistryPath, MAX_PATH, TEXT("System\\CurrentControlSet\\Services\\")); StringCchCatW(FullRegistryPath, MAX_PATH, DriverName); DefaultImageName = TRUE; #if defined(_NTDLLBUILD_) StringCbPrintfW(RegBuffer, DEFAULT_ALLOC_SIZE, L"%ws\\%ws", L"\\REGISTRY\\MACHINE", FullRegistryPath); if (EtwpRegOpenKey(RegBuffer, &RegKey) == ERROR_SUCCESS) { ULONG cbSize; PKEY_VALUE_PARTIAL_INFORMATION Buf; Size = MAX_PATH * sizeof(WCHAR); cbSize = Size + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); Buf = EtwpAlloc(cbSize); if( Buf ) { UNICODE_STRING UnicodeString; RtlInitUnicodeString(&UnicodeString, L"MofImagePath"); if( NtQueryValueKey(RegKey, &UnicodeString, KeyValuePartialInformation, Buf, Size, &Size) == ERROR_SUCCESS) { RtlCopyMemory(ImagePath, &Buf->Data[0], Buf->DataLength); ValueType = Buf->Type; DefaultImageName = FALSE; } else { RtlInitUnicodeString(&UnicodeString, L"ImagePath"); if( NtQueryValueKey(RegKey, &UnicodeString, KeyValuePartialInformation, Buf, Size, &Size) == ERROR_SUCCESS) { RtlCopyMemory(ImagePath, &Buf->Data[0], Buf->DataLength); ValueType = Buf->Type; DefaultImageName = FALSE; } } } EtwpFree(Buf); } #else if (RegOpenKey(HKEY_LOCAL_MACHINE, FullRegistryPath, &RegKey) == ERROR_SUCCESS) { Size = MAX_PATH * sizeof(WCHAR); if (RegQueryValueEx(RegKey, TEXT("MofImagePath"), NULL, &ValueType, (PBYTE)ImagePath, &Size) == ERROR_SUCCESS) { DefaultImageName = FALSE; } else { Size = MAX_PATH * sizeof(WCHAR); if (RegQueryValueEx(RegKey, TEXT("ImagePath"), NULL, &ValueType, (PBYTE)ImagePath, &Size) == ERROR_SUCCESS) { DefaultImageName = FALSE; } } NtClose(RegKey); } #endif if ((DefaultImageName) || ((ValueType != REG_EXPAND_SZ) && (ValueType != REG_SZ)) || (Size < (2 * sizeof(WCHAR)))) { // // No special ImagePath or MofImagePath so assume image file is // %SystemRoot%\System32\Drivers\Driver.Sys StringCchCopyW(Buffer, MAX_PATH, TEXT("%SystemRoot%\\System32\\Drivers\\")); StringCchCatW(Buffer, MAX_PATH, DriverName); StringCchCatW(Buffer, MAX_PATH, TEXT(".SYS")); } else { if (_wcsnicmp(ImagePath, SystemRoot, SystemRootCharSize) == 0) { // // Looks like format C StringCchCopyW(Buffer, MAX_PATH, SystemRootDirectory); StringCchCatW(Buffer, MAX_PATH, &ImagePath[SystemRootCharSize]); } else if ((*ImagePath == '%') || ( (Size > 3*sizeof(WCHAR)) && ImagePath[1] == TEXT(':')) ) { // // Looks like format B or format A StringCchCopyW(Buffer, MAX_PATH, ImagePath); } else if (_wcsnicmp(ImagePath, QuestionPrefix, QuestionPrefixSize) == 0) { // // Looks like format E StringCchCopyW(Buffer, MAX_PATH, ImagePath+QuestionPrefixSize); } else { // // Assume format D StringCchCopyW(Buffer, MAX_PATH, SystemRootDirectory); StringCchCatW(Buffer, MAX_PATH, ImagePath); } } #if defined(_NTDLLBUILD_) Size = EtwpExpandEnvironmentStringsW(Buffer, ImagePath, MAX_PATH); #else Size = ExpandEnvironmentStrings(Buffer, ImagePath, MAX_PATH); #endif #ifdef MEMPHIS EtwpDebugPrint(("WMI: %s has mof in %s\n", DriverName, ImagePath)); #else EtwpDebugPrint(("WMI: %ws has mof in %ws\n", DriverName, ImagePath)); #endif EtwpFree(Buffer); } else { ImagePath = NULL; } return(ImagePath); } BOOLEAN EtwpCopyMRString( PWCHAR Buffer, ULONG BufferRemaining, PULONG BufferUsed, PWCHAR SourceString ) { BOOLEAN BufferNotFull; ULONG len; len = wcslen(SourceString) + 1; if (len <= BufferRemaining) { wcscpy(Buffer, SourceString); *BufferUsed = len; BufferNotFull = TRUE; } else { BufferNotFull = FALSE; } return(BufferNotFull); } BOOLEAN EtwpFileExists( PWCHAR FileName ) { HANDLE FindHandle; BOOLEAN Found; PWIN32_FIND_DATA FindData; FindData = (PWIN32_FIND_DATA)EtwpAlloc(sizeof(WIN32_FIND_DATA)); if (FindData != NULL) { // // Now we need to make sure that the file a ctually exists // #if defined(_NTDLLBUILD_) FindHandle = EtwpFindFirstFileW(FileName, FindData); #else FindHandle = FindFirstFile(FileName, FindData); #endif if (FindHandle == INVALID_HANDLE_VALUE) { Found = FALSE; } else { #if defined(_NTDLLBUILD_) EtwpFindClose(FindHandle); #else FindClose(FindHandle); #endif Found = TRUE; } EtwpFree(FindData); } else { Found = FALSE; } return(Found); } ULONG EtwpGetWindowsDirectory( PWCHAR *s, PWCHAR Static, ULONG StaticSize ) { ULONG Size; ULONG Status = ERROR_SUCCESS; #if defined(_NTDLLBUILD_) Size = EtwpGetSystemWindowsDirectoryW(Static, StaticSize); #else Size = GetWindowsDirectory(Static, StaticSize); #endif if (Size > StaticSize) { Size += sizeof(UNICODE_NULL); *s = EtwpAlloc(Size * sizeof(WCHAR)); if (*s != NULL) { #if defined(_NTDLLBUILD_) Size = EtwpGetSystemWindowsDirectoryW(*s, Size); #else Size = GetWindowsDirectory(*s, Size); #endif } else { Status = ERROR_NOT_ENOUGH_MEMORY; } } else if (Size == 0) { #if defined(_NTDLLBUILD_) Status = EtwpGetLastError(); #else Status = GetLastError(); #endif } else { *s = Static; } if (Status == ERROR_SUCCESS) { if ( (*s)[Size-1] == L'\\') { (*s)[Size-1] = 0; } } return(Status); } ULONG EtwpBuildMUIPath( PWCHAR Buffer, ULONG BufferRemaining, PULONG BufferUsed, PWCHAR EnglishPath, PWCHAR Language, PBOOLEAN BufferNotFull ) { #define FallbackDir L"\\MUI\\Fallback\\" #define MUIPath L"\\MUI\\" #define MUITail L".mui" ULONG EnglishLen; PWCHAR WinDir; PWCHAR s, p; ULONG len; ULONG Status, SizeNeeded; PWCHAR LanguagePath; PWCHAR WinDirStatic; ULONG WinDirStaticSize; WinDirStaticSize = MAX_PATH+1; WinDirStatic = EtwpAlloc(WinDirStaticSize * sizeof(WCHAR)); if (WinDirStatic != NULL) { Status = ERROR_FILE_NOT_FOUND; LanguagePath = Buffer; EtwpDebugPrint(("WMI: Building MUI path for %ws in language %ws\n", EnglishPath, Language)); EnglishLen = wcslen(EnglishPath); p = EnglishPath + EnglishLen; len = EnglishLen; // // Work from the end of the string to try to find the last \ so // we can then slip in the language name // while ( (len != 0) && (*p != L'\\')) { len--; p--; } if (len != 0) { p++; } EtwpDebugPrint(("WMI: Tail of %ws is %ws\n", EnglishPath, p)); // // First try looking in \\MUI\\ which is where 3rd // parties will install their resource only drivers. We look for // foo.sys and then foo.sys.mui. // SizeNeeded = len + wcslen(Language) + wcslen(MUIPath) + 1 + wcslen(p) + 1 + wcslen(MUITail); if (SizeNeeded <= BufferRemaining) { if (len != 0) { wcsncpy(LanguagePath, EnglishPath, len); LanguagePath[len] = 0; wcscat(LanguagePath, MUIPath); } else { LanguagePath[len] = 0; } wcscat(LanguagePath, Language); wcscat(LanguagePath, L"\\"); wcscat(LanguagePath, p); if (EtwpFileExists(LanguagePath)) { *BufferUsed = wcslen(LanguagePath) + 1; *BufferNotFull = TRUE; Status = ERROR_SUCCESS; EtwpDebugPrint(("WMI: #1 - Found %ws\n", LanguagePath)); } else { wcscat(LanguagePath, MUITail); if (EtwpFileExists(LanguagePath)) { *BufferUsed = wcslen(LanguagePath) + 1; *BufferNotFull = TRUE; Status = ERROR_SUCCESS; EtwpDebugPrint(("WMI: #2 - Found %ws\n", LanguagePath)); } } } else { *BufferNotFull = FALSE; Status = ERROR_SUCCESS; } if (Status != ERROR_SUCCESS) { // // Next lets check the fallback directory, // %windir%\MUI\Fallback\. This is where system components // are installed by default. // Status = EtwpGetWindowsDirectory(&WinDir, WinDirStatic, WinDirStaticSize); if (Status == ERROR_SUCCESS) { SizeNeeded = wcslen(WinDir) + wcslen(FallbackDir) + wcslen(Language) + 1 + wcslen(p) + 1 + wcslen(MUITail); if (SizeNeeded <= BufferRemaining) { wcscpy(LanguagePath, WinDir); wcscat(LanguagePath, FallbackDir); wcscat(LanguagePath, Language); wcscat(LanguagePath, L"\\"); wcscat(LanguagePath, p); wcscat(LanguagePath, MUITail); if ( EtwpFileExists(LanguagePath)) { *BufferUsed = wcslen(LanguagePath) + 1; *BufferNotFull = TRUE; Status = ERROR_SUCCESS; EtwpDebugPrint(("WMI: #3 - Found %ws\n", LanguagePath)); } else { Status = ERROR_FILE_NOT_FOUND; } } else { *BufferNotFull = FALSE; Status = ERROR_SUCCESS; } if (WinDir != WinDirStatic) { EtwpFree(WinDir); } } } EtwpFree(WinDirStatic); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } return(Status); } typedef struct { ULONG Count; ULONG MaxCount; PWCHAR *List; } ENUMLANGCTX, *PENUMLANGCTX; BOOL EnumUILanguageCallback( LPWSTR Language, LONG_PTR Context ) { PENUMLANGCTX EnumLangCtx = (PENUMLANGCTX)Context; PWCHAR *p; PWCHAR w; ULONG NewMaxCount; if (EnumLangCtx->Count == EnumLangCtx->MaxCount) { NewMaxCount = EnumLangCtx->MaxCount * 2; p = EtwpAlloc( sizeof(PWCHAR) * NewMaxCount); if (p != NULL) { memset(p, 0, sizeof(PWCHAR) * NewMaxCount); memcpy(p, EnumLangCtx->List, EnumLangCtx->Count * sizeof(PWCHAR)); EtwpFree(EnumLangCtx->List); EnumLangCtx->List = p; EnumLangCtx->MaxCount = NewMaxCount; } else { return(FALSE); } } w = EtwpAlloc( (wcslen(Language)+1) * sizeof(WCHAR) ); if (w != NULL) { EnumLangCtx->List[EnumLangCtx->Count++] = w; wcscpy(w, Language); } else { return(FALSE); } return(TRUE); } ULONG EtwpGetLanguageList( PWCHAR **List, PULONG Count ) { ENUMLANGCTX EnumLangCtx; BOOL b; ULONG Status; *List = NULL; *Count = 0; EnumLangCtx.Count = 0; EnumLangCtx.MaxCount = 8; EnumLangCtx.List = EtwpAlloc( 8 * sizeof(PWCHAR) ); if (EnumLangCtx.List != NULL) { #if defined(_NTDLLBUILD_) b = EtwpEnumUILanguages(EnumUILanguageCallback, 0, (LONG_PTR)&EnumLangCtx); #else b = EnumUILanguages(EnumUILanguageCallback, 0, (LONG_PTR)&EnumLangCtx); #endif if (b) { *Count = EnumLangCtx.Count; *List = EnumLangCtx.List; Status = ERROR_SUCCESS; } else { if (EnumLangCtx.List != NULL) { EtwpFree(EnumLangCtx.List); } #if defined(_NTDLLBUILD_) Status = EtwpGetLastError(); #else Status = GetLastError(); #endif } } else { Status = ERROR_NOT_ENOUGH_MEMORY; } return(Status); } BOOL EtwpSynchReadFile( HANDLE LogFile, LPVOID Buffer, DWORD NumberOfBytesToRead, LPDWORD NumberOfBytesRead, LPOVERLAPPED Overlapped ) /*++ Routine Description: This routine performs synchronous read on a given file. Since logfile is opened for asychronous IO, current file position is not available. Thus, for synch read, we need to use this. Arguments: LogFile - handle to file Buffer - data buffer NumberOfBytesToRead - number of bytes to read NumberOfBytesRead - number of bytes read Overlapped - overlapped structure Returned Value: TRUE if succeeded. --*/ { BOOL ReadSuccess; if (Overlapped == NULL || Overlapped->hEvent == NULL || Overlapped->hEvent == INVALID_HANDLE_VALUE) { return FALSE; } #if defined (_NTDLLBUILD_) if (!EtwpResetEvent(Overlapped->hEvent)) { return FALSE; } ReadSuccess = EtwpReadFile(LogFile, Buffer, NumberOfBytesToRead, NULL, Overlapped); if (ReadSuccess || EtwpGetLastError() == ERROR_IO_PENDING) { ReadSuccess = EtwpGetOverlappedResult(LogFile, Overlapped, NumberOfBytesRead, TRUE); if (!ReadSuccess && EtwpGetLastError() == ERROR_HANDLE_EOF) { *NumberOfBytesRead = 0; EtwpSetEvent(Overlapped->hEvent); } return ReadSuccess; } else { *NumberOfBytesRead = 0; EtwpSetEvent(Overlapped->hEvent); return FALSE; } #else if (!ResetEvent(Overlapped->hEvent)) { return FALSE; } ReadSuccess = ReadFile(LogFile, Buffer, NumberOfBytesToRead, NULL, Overlapped); if (ReadSuccess || GetLastError() == ERROR_IO_PENDING) { ReadSuccess = GetOverlappedResult(LogFile, Overlapped, NumberOfBytesRead, TRUE); if (!ReadSuccess && GetLastError() == ERROR_HANDLE_EOF) { *NumberOfBytesRead = 0; SetEvent(Overlapped->hEvent); } return ReadSuccess; } else { *NumberOfBytesRead = 0; SetEvent(Overlapped->hEvent); return FALSE; } #endif } PVOID EtwpMemReserve( IN SIZE_T Size ) { NTSTATUS Status; PVOID lpAddress = NULL; try { Status = NtAllocateVirtualMemory( NtCurrentProcess(), &lpAddress, 0, &Size, MEM_RESERVE, PAGE_READWRITE); } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } if (NT_SUCCESS(Status)) { return lpAddress; } else { EtwpSetDosError(EtwpNtStatusToDosError(Status)); return NULL; } } PVOID EtwpMemCommit( IN PVOID Buffer, IN SIZE_T Size ) { NTSTATUS Status; try { Status = NtAllocateVirtualMemory( NtCurrentProcess(), &Buffer, 0, &Size, MEM_COMMIT, PAGE_READWRITE); } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } if (NT_SUCCESS(Status)) { return Buffer; } else { EtwpSetDosError(EtwpNtStatusToDosError(Status)); return NULL; } } ULONG EtwpMemFree( IN PVOID Buffer ) { NTSTATUS Status; SIZE_T Size = 0; HANDLE hProcess = NtCurrentProcess(); if (Buffer == NULL) { EtwpSetDosError(ERROR_INVALID_PARAMETER); return FALSE; } try { Status = NtFreeVirtualMemory( hProcess, &Buffer, &Size, MEM_RELEASE); } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } if (NT_SUCCESS(Status)) { return TRUE; } else { if (Status == STATUS_INVALID_PAGE_PROTECTION) { if (RtlFlushSecureMemoryCache(Buffer, Size)) { Status = NtFreeVirtualMemory( hProcess, Buffer, &Size, MEM_RELEASE); if (NT_SUCCESS(Status)) { return TRUE; } } } EtwpSetDosError(EtwpNtStatusToDosError(Status)); return FALSE; } } ULONG EtwpConvertWADToAnsi( PWNODE_ALL_DATA Wnode ) /*+++ Routine Description: This routine will convert the instance names in a WNODE_ALL_DATA to ansi. The conversion is done in place since we can assume that ansi strings are no longer than unicode strings. Arguments: Wnode is the WNODE_ALL_DATA whose instance names are to be converted to ANSI Return Value: Returns ERROR_SUCCESS or an error code. ---*/ { ULONG i; ULONG Linkage; ULONG InstanceCount; PULONG InstanceNameOffsets; PWCHAR Ptr; ULONG Status = ERROR_SUCCESS; EtwpAssert(!(Wnode->WnodeHeader.Flags & WNODE_FLAG_ANSI_INSTANCENAMES)); do { Wnode->WnodeHeader.Flags |= WNODE_FLAG_ANSI_INSTANCENAMES; InstanceCount = Wnode->InstanceCount; InstanceNameOffsets = (PULONG)(((PUCHAR)Wnode) + Wnode->OffsetInstanceNameOffsets); for (i = 0; i < InstanceCount; i++) { Ptr = (PWCHAR)(((PUCHAR)Wnode) + InstanceNameOffsets[i]); try { Status = EtwpCountedUnicodeToCountedAnsi(Ptr, (PCHAR)Ptr); } except(EXCEPTION_EXECUTE_HANDLER) { // Wnode->WnodeHeader.Flags |= WNODE_FLAG_INVALID; return(ERROR_SUCCESS); } if (Status != ERROR_SUCCESS) { #if defined (_NTDLLBUILD_) EtwpSetLastError(Status); #else SetLastError(Status); #endif goto Done; } } Linkage = Wnode->WnodeHeader.Linkage; Wnode = (PWNODE_ALL_DATA)(((PUCHAR)Wnode) + Linkage); } while (Linkage != 0); Done: return(Status); } ULONG EtwpUnicodeToAnsi( LPCWSTR pszW, LPSTR * ppszA, ULONG *AnsiSizeInBytes OPTIONAL ){ ANSI_STRING DestinationString; UNICODE_STRING SourceString; NTSTATUS Status; BOOLEAN AllocateString; ULONG AnsiLength; // // If output is null then return error as we don't have // any place to put output string // if( ppszA==NULL ){ return(STATUS_INVALID_PARAMETER_2); } // // If input is null then just return the same. // if (pszW == NULL) { *ppszA = NULL; return(ERROR_SUCCESS); } // // We ASSUME that if *ppszA!=NULL then we have sufficient // amount of memory to copy // AllocateString = ((*ppszA) == NULL ); RtlInitUnicodeString(&SourceString,(LPWSTR)pszW); AnsiLength = RtlUnicodeStringToAnsiSize(&SourceString); if ( AnsiLength > MAXUSHORT ) { return STATUS_INVALID_PARAMETER_1; } DestinationString.Length = (USHORT)(AnsiLength - 1); DestinationString.MaximumLength = (USHORT)AnsiLength; DestinationString.Buffer = EtwpAlloc(AnsiLength); if ( DestinationString.Buffer == NULL ) { return STATUS_NO_MEMORY; } Status = RtlUnicodeStringToAnsiString( &DestinationString, &SourceString, FALSE); if( NT_SUCCESS(Status) ) { if( AllocateString ) { *ppszA = DestinationString.Buffer; } else { memcpy((*ppszA),DestinationString.Buffer,AnsiLength); EtwpFree(DestinationString.Buffer); } if (AnsiSizeInBytes != NULL){ *AnsiSizeInBytes = DestinationString.Length; } } else { EtwpFree(DestinationString.Buffer); } return Status; } ULONG EtwpCountedUnicodeToCountedAnsi( PWCHAR Unicode, PCHAR Ansi ) /*++ Routine Description: Translate a counted ansi string into a counted unicode string. Conversion may be done inplace, that is Ansi == Unicode. Arguments: Unicode is the counted unicode string to convert to ansi Ansi is the buffer to place the converted string into Return Value: ERROR_SUCCESS or an error code --*/ { PCHAR APtr; PWCHAR WPtr; ULONG AnsiSize, UnicodeSize; ULONG Status; UnicodeSize = *Unicode; WPtr = EtwpAlloc(UnicodeSize + sizeof(WCHAR)); if (WPtr != NULL) { memcpy(WPtr, Unicode + 1, UnicodeSize); WPtr[UnicodeSize/sizeof(WCHAR)] = UNICODE_NULL; APtr = NULL; Status = EtwpUnicodeToAnsi(WPtr, &APtr, &AnsiSize); if (Status == ERROR_SUCCESS) { *((PUSHORT)Ansi) = (USHORT)AnsiSize; memcpy(Ansi+sizeof(USHORT), APtr, AnsiSize); Status = ERROR_SUCCESS; EtwpFree(APtr); } EtwpFree(WPtr); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } return(Status); }