|
|
/*++
Copyright (c) 1995-1999 Microsoft Corporation
Module Name: dllinit.c
Abstract: This module contians the DLL attach/detach event entry point for the pdh.dll
Author: Bob Watson (a-robw) Jul 95
Revision History: --*/
#include <windows.h>
#include <wmistr.h>
#include <objbase.h>
#include <initguid.h>
#include <evntrace.h>
#include <wmiguid.h>
#include <wmium.h>
#include "strsafe.h"
#include "pdh.h"
#include "pdhp.h"
#include "pdhitype.h"
#define _INIT_PDH_DEBUGTRACE
#include "pdhidef.h"
#include "pdhmsg.h"
#include "strings.h"
#define PDH_DEFAULT_COLLECT_TIMEOUT 300 // 5 minutes
HANDLE ThisDLLHandle = NULL; WCHAR szStaticLocalMachineName[MAX_COMPUTERNAME_LENGTH + 3] = {0}; HANDLE hPdhDataMutex = NULL; HANDLE hPdhContextMutex = NULL; HANDLE hPdhHeap = NULL; HANDLE hEventLog = NULL;
LONGLONG llRemoteRetryTime = RETRY_TIME_INTERVAL; BOOL bEnableRemotePdhAccess = TRUE; DWORD dwPdhiLocalDefaultDataSource = DATA_SOURCE_REGISTRY; LONG dwCurrentRealTimeDataSource = 0; ULONGLONG ulPdhCollectTimeout = PDH_DEFAULT_COLLECT_TIMEOUT; BOOL bProcessIsDetaching = FALSE;
LPWSTR GetStringResource( DWORD dwResId ) { LPWSTR szReturnString = NULL; LPWSTR szTmpString = NULL; DWORD dwStrLen = (2048 * sizeof(WCHAR));
szReturnString = (LPWSTR) G_ALLOC(dwStrLen); if (szReturnString != NULL) { dwStrLen /= sizeof(WCHAR); dwStrLen = LoadStringW(ThisDLLHandle, (UINT) dwResId, szReturnString, dwStrLen); if (dwStrLen > 0) { // then realloc down to the size used
dwStrLen ++; // to include the NULL
dwStrLen *= sizeof(WCHAR); szTmpString = szReturnString; szReturnString = G_REALLOC(szTmpString, dwStrLen); if (szReturnString == NULL) { G_FREE(szTmpString); szTmpString = NULL; } } else { // free the memory since the look up failed
G_FREE(szReturnString); szReturnString = NULL; } } //else allocation failed
return szReturnString; }
STATIC_BOOL PdhiOpenEventLog( HANDLE * phEventLogHandle ) { HANDLE hReturn; BOOL bReturn = FALSE;
if ((hReturn = RegisterEventSourceW(NULL, cszAppShortName)) != NULL) { * phEventLogHandle = hReturn; bReturn = TRUE; } return bReturn; }
STATIC_BOOL PdhiGetRegistryDefaults() { DWORD dwStatus; DWORD dwType, dwSize, dwValue;
HKEY hKeyPDH;
ulPdhCollectTimeout = ((ULONGLONG) PDH_DEFAULT_COLLECT_TIMEOUT) * ((ULONGLONG) 10000000); // the local data source is not initialized so use it
dwStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, cszPdhKey, 0L, KEY_READ, & hKeyPDH); if (dwStatus == ERROR_SUCCESS) { // get the default null data source
//
dwValue = 0; dwType = 0; dwSize = sizeof (dwValue); dwStatus = RegQueryValueExW(hKeyPDH, cszDefaultNullDataSource, NULL, & dwType, (LPBYTE) & dwValue, & dwSize); if (dwStatus != ERROR_SUCCESS || dwType != REG_DWORD) { dwValue = DATA_SOURCE_REGISTRY; } else { // check the value for validity
switch (dwValue) { case DATA_SOURCE_WBEM: case DATA_SOURCE_REGISTRY: // this is OK
break;
case DATA_SOURCE_LOGFILE: default: // these are not OK so insert default
dwValue = DATA_SOURCE_REGISTRY; break; } } dwPdhiLocalDefaultDataSource = dwValue;
//
// get the retry timeout
//
dwValue = 0; dwType = 0; dwSize = sizeof (dwValue); dwStatus = RegQueryValueExW(hKeyPDH, cszRemoteMachineRetryTime, NULL, & dwType, (LPBYTE) & dwValue, & dwSize); if (dwStatus != ERROR_SUCCESS || dwType != REG_DWORD) { dwValue = 0; } else { // check the value for validity
// must be 30 seconds or more yet no more than an hour
if ((dwValue <= 30) || (dwValue > 3600)) { dwValue = 0; } } if (dwValue != 0) { // convert to 100NS units
llRemoteRetryTime = dwValue * 10000000; } else { // use default
llRemoteRetryTime = RETRY_TIME_INTERVAL; }
// get the remote access mode
//
dwValue = 0; dwType = 0; dwSize = sizeof (dwValue); dwStatus = RegQueryValueExW(hKeyPDH, cszEnableRemotePdhAccess, NULL, & dwType, (LPBYTE) & dwValue, & dwSize); if (dwStatus != ERROR_SUCCESS || dwType != REG_DWORD) { dwValue = TRUE; } else { // check the value for validity
if (dwValue != 0) { dwValue = TRUE; } } bEnableRemotePdhAccess = (BOOL) dwValue;
// get RegQueryValueEx(HKEY_PERFORMANCE_DATA) elapsed time maximum
//
dwValue = 0; dwType = 0; dwSize = sizeof(dwValue); dwStatus = RegQueryValueExW(hKeyPDH, cszCollectTimeout, NULL, & dwType, (LPBYTE) & dwValue, & dwSize); if (dwStatus != ERROR_SUCCESS || dwType != REG_DWORD) { dwValue = PDH_DEFAULT_COLLECT_TIMEOUT; } else if (dwValue < 30 || dwValue > 3600) { // must between 30 seconds and 1 hour
//
dwValue = PDH_DEFAULT_COLLECT_TIMEOUT; } ulPdhCollectTimeout = ((ULONGLONG) dwValue) * ((ULONGLONG) 10000000);
// close the registry key
RegCloseKey(hKeyPDH); } return TRUE; }
STATIC_BOOL PdhiCloseEventLog( HANDLE * phEventLogHandle ) { BOOL bReturn = TRUE;
if (* phEventLogHandle != NULL) { bReturn = DeregisterEventSource(* phEventLogHandle); * phEventLogHandle = NULL; } return bReturn; }
HRESULT PdhiPlaInitMutex() { HRESULT hr = ERROR_SUCCESS; BOOL bResult = TRUE;
PSECURITY_DESCRIPTOR SD = NULL; SECURITY_ATTRIBUTES sa; PSID AuthenticatedUsers = NULL; PSID BuiltInAdministrators = NULL; PSID NetworkService = NULL; PSID LoggingUsers = NULL; DWORD dwAclSize; ACL *Acl;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
bResult = AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, &BuiltInAdministrators); if( !bResult ){goto cleanup;}
bResult = AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_AUTHENTICATED_USER_RID, 0,0,0,0,0,0,0, &AuthenticatedUsers); if( !bResult ){goto cleanup;}
bResult = AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_NETWORK_SERVICE_RID, 0,0,0,0,0,0,0, &NetworkService); if( !bResult ){goto cleanup;}
bResult = AllocateAndInitializeSid( &NtAuthority, 1, DOMAIN_ALIAS_RID_LOGGING_USERS, 0,0,0,0,0,0,0, &LoggingUsers); if( !bResult ){goto cleanup;}
dwAclSize = sizeof (ACL) + (4 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (ULONG))) + GetLengthSid(AuthenticatedUsers) + GetLengthSid(BuiltInAdministrators) + GetLengthSid(NetworkService) + GetLengthSid(LoggingUsers);
SD = (PSECURITY_DESCRIPTOR)G_ALLOC(SECURITY_DESCRIPTOR_MIN_LENGTH + dwAclSize); if( NULL == SD ){ goto cleanup; }
ZeroMemory( SD, sizeof(SD) ); Acl = (ACL *)((BYTE *)SD + SECURITY_DESCRIPTOR_MIN_LENGTH);
bResult = InitializeAcl( Acl, dwAclSize, ACL_REVISION); if( !bResult ){goto cleanup;}
bResult = AddAccessAllowedAce(Acl, ACL_REVISION, MUTEX_ALL_ACCESS, AuthenticatedUsers ); if( !bResult ){goto cleanup;}
bResult = AddAccessAllowedAce(Acl, ACL_REVISION, MUTEX_ALL_ACCESS , NetworkService ); if( !bResult ){goto cleanup;}
bResult = AddAccessAllowedAce(Acl, ACL_REVISION, MUTEX_ALL_ACCESS , LoggingUsers ); if( !bResult ){goto cleanup;} bResult = AddAccessAllowedAce(Acl, ACL_REVISION, GENERIC_ALL, BuiltInAdministrators ); if( !bResult ){goto cleanup;}
bResult = InitializeSecurityDescriptor(SD, SECURITY_DESCRIPTOR_REVISION); if( !bResult ){goto cleanup;}
bResult = SetSecurityDescriptorDacl(SD, TRUE, Acl, FALSE); if( !bResult ){goto cleanup;} sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = SD; sa.bInheritHandle = FALSE;
hPdhPlaMutex = CreateMutexW( &sa, FALSE, PDH_PLA_MUTEX );
cleanup: if( hPdhPlaMutex == NULL || !bResult ){ hr = GetLastError(); } if( NULL != AuthenticatedUsers ){ FreeSid(AuthenticatedUsers); } if( NULL != BuiltInAdministrators){ FreeSid(BuiltInAdministrators); } if( NULL != NetworkService){ FreeSid(NetworkService); } if( NULL != LoggingUsers){ FreeSid(LoggingUsers); } G_FREE(SD);
return hr; }
const LPCWSTR cszTraceLevel = L"DebugTraceLevel"; const LPCWSTR cszTraceFileValue = L"DebugTraceFile"; const LPCWSTR cszTraceLogName = L"PDH Debug Logger"; const LPCWSTR cszDefaultTraceFile = L"PdhDbg.Etl"; const LPCWSTR cszDefaultTraceFileName = L"C:\\PdhDbg.Etl";
TRACEHANDLE g_hTraceHandle = 0; LONG g_lDbgStarted = 0;
DEFINE_GUID( /* 51af3adf-28b1-4ba5-b59a-3aeec16deb3c */ PdhDebugGuid, 0x51af3adf, 0x28b1, 0x4ba5, 0xb5, 0x9a, 0x3a, 0xee, 0xc1, 0x6d, 0xeb, 0x3c );
PDH_FUNCTION PdhDebugStartTrace() { DWORD status = ERROR_SUCCESS; DWORD dwType = 0; DWORD dwSize = 0; DWORD dwTraceLevel = PDH_DBG_TRACE_NONE; HKEY hKey = NULL; TRACEHANDLE TraceHandle = 0; LPWSTR szTraceFileName = NULL; CHAR Buffer[SMALL_BUFFER_SIZE]; PCHAR ptr; ULONG lFileNameSize = 0;
PEVENT_TRACE_PROPERTIES Properties;
if (InterlockedCompareExchange(& g_lDbgStarted, 1, 0) != 0) { return ERROR_SUCCESS; }
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\PDH", 0L, KEY_READ, & hKey); if (status == ERROR_SUCCESS) { dwSize = sizeof(DWORD); dwType = 0; status = RegQueryValueExW(hKey, cszTraceLevel, NULL, & dwType, (LPBYTE) & dwTraceLevel, & dwSize); if ((status != ERROR_SUCCESS) || (dwType != REG_DWORD)) { dwTraceLevel = PDH_DBG_TRACE_NONE; } }
if (dwTraceLevel == PDH_DBG_TRACE_NONE) goto Cleanup;
dwType = 0; dwSize = 0; status = RegQueryValueExW(hKey, cszTraceFileValue, NULL, & dwType, (LPBYTE) szTraceFileName, & dwSize); while (status == ERROR_MORE_DATA) { if (szTraceFileName != NULL) HeapFree(GetProcessHeap(), 0, szTraceFileName); szTraceFileName = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize); status = RegQueryValueExW(hKey, cszTraceFileValue, NULL, & dwType, (LPBYTE) szTraceFileName, & dwSize); } if (status != ERROR_SUCCESS || dwType != REG_SZ) { DWORD dwFileSize = MAX_PATH + lstrlenW(cszDefaultTraceFile) + 2;
if (szTraceFileName != NULL) HeapFree(GetProcessHeap(), 0, szTraceFileName); szTraceFileName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * dwFileSize); if (szTraceFileName == NULL) { goto Cleanup; }
if (GetSystemWindowsDirectoryW(szTraceFileName, MAX_PATH) > 0) { StringCchCatW(szTraceFileName, dwFileSize, L"\\"); StringCchCatW(szTraceFileName, dwFileSize, cszDefaultTraceFile); } else { StringCchCopyW(szTraceFileName, MAX_PATH, cszDefaultTraceFileName); } } lFileNameSize = sizeof(WCHAR) * (lstrlenW(szTraceFileName) + 1);
Properties = (PEVENT_TRACE_PROPERTIES) Buffer;
ZeroMemory(Buffer, SMALL_BUFFER_SIZE); Properties->Wnode.BufferSize = SMALL_BUFFER_SIZE; Properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; Properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); Properties->LogFileNameOffset = Properties->LoggerNameOffset + sizeof(cszTraceLogName); ptr = (PCHAR) (((PCHAR) Buffer) + Properties->LoggerNameOffset); RtlCopyMemory(ptr, cszTraceLogName, sizeof(cszTraceLogName)); ptr = (PCHAR) (((PCHAR) Buffer) + Properties->LogFileNameOffset); RtlCopyMemory(ptr, szTraceFileName, lFileNameSize); status = QueryTraceW(0, cszTraceLogName, Properties); if (status == ERROR_SUCCESS) { TraceHandle = (TRACEHANDLE) Properties->Wnode.HistoricalContext; goto Cleanup; }
// Reinitialize structure again for StartTrace()
//
ZeroMemory(Buffer, SMALL_BUFFER_SIZE); Properties->Wnode.BufferSize = SMALL_BUFFER_SIZE; Properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; Properties->BufferSize = 64; Properties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL | EVENT_TRACE_USE_PAGED_MEMORY | EVENT_TRACE_FILE_MODE_APPEND; Properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); Properties->LogFileNameOffset = Properties->LoggerNameOffset + sizeof(cszTraceLogName); ptr = (PCHAR) (((PCHAR) Buffer) + Properties->LoggerNameOffset); RtlCopyMemory(ptr, cszTraceLogName, sizeof(cszTraceLogName)); ptr = (PCHAR) (((PCHAR) Buffer) + Properties->LogFileNameOffset); RtlCopyMemory(ptr, szTraceFileName, lFileNameSize);
status = StartTraceW(& TraceHandle, cszTraceLogName, Properties); if (status == ERROR_SUCCESS) { g_hTraceHandle = TraceHandle; } else { dwTraceLevel = PDH_DBG_TRACE_NONE; TraceHandle = (TRACEHANDLE) 0; }
Cleanup: if (hKey != NULL && hKey != INVALID_HANDLE_VALUE) RegCloseKey(hKey); if (szTraceFileName != NULL) HeapFree(GetProcessHeap(), 0, szTraceFileName); g_dwDebugTraceLevel = dwTraceLevel; g_hTraceHandle = TraceHandle; return status; }
VOID PdhDbgTrace( ULONG LineNumber, ULONG ModuleNumber, ULONG OptArgs, ULONG Status, ... ) { ULONG ErrorCode; struct _MY_EVENT { EVENT_TRACE_HEADER Header; MOF_FIELD MofField[MAX_MOF_FIELDS]; } MyEvent; ULONG i; va_list ArgList; PVOID source; SIZE_T len; DWORD dwLastError;
dwLastError = GetLastError(); RtlZeroMemory(& MyEvent, sizeof(EVENT_TRACE_HEADER));
va_start(ArgList, Status); for (i = 3; i < MAX_MOF_FIELDS; i ++) { source = va_arg(ArgList, PVOID); if (source == NULL) break; len = va_arg(ArgList, SIZE_T); if (len == 0) break; MyEvent.MofField[i].DataPtr = (ULONGLONG) source; MyEvent.MofField[i].Length = (ULONG) len; } va_end(ArgList);
MyEvent.Header.Class.Type = (UCHAR) ModuleNumber; MyEvent.Header.Size = (USHORT) ( sizeof(EVENT_TRACE_HEADER) + (i * sizeof(MOF_FIELD))); MyEvent.Header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR | WNODE_FLAG_USE_GUID_PTR; MyEvent.Header.GuidPtr = (ULONGLONG) & PdhDebugGuid; MyEvent.MofField[0].DataPtr = (ULONGLONG) & LineNumber; MyEvent.MofField[0].Length = sizeof(LineNumber); MyEvent.MofField[1].DataPtr = (ULONGLONG) & Status; MyEvent.MofField[1].Length = sizeof(Status); MyEvent.MofField[2].DataPtr = (ULONGLONG) & OptArgs; MyEvent.MofField[2].Length = sizeof(OptArgs);
__try { ErrorCode = TraceEvent(g_hTraceHandle, (PEVENT_TRACE_HEADER) & MyEvent); } __except (EXCEPTION_EXECUTE_HANDLER) { ErrorCode = GetLastError(); }
if (ErrorCode != ERROR_SUCCESS) { DebugPrint((1, "ErrorCode = %d Module = %d Line = %d Status = 0X%08X\n", ErrorCode, ModuleNumber, LineNumber, Status)); }
SetLastError(dwLastError); }
BOOL _stdcall PdhDllInitRoutine( IN HANDLE DLLHandle, IN DWORD Reason, IN LPVOID ReservedAndUnused ) { BOOL bStatus; BOOL bReturn = TRUE; OSVERSIONINFOW os; ReservedAndUnused;
switch(Reason) { case DLL_PROCESS_ATTACH: bProcessIsDetaching = FALSE; { DWORD dwBufferLength = 0;
ThisDLLHandle = DLLHandle;
// make sure this is the correct operating system
ZeroMemory(& os, sizeof(OSVERSIONINFOW)); os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); bReturn = GetVersionExW(& os); if (bReturn) { // check for windows NT v4.0
if (os.dwPlatformId != VER_PLATFORM_WIN32_NT) { // not WINDOWS NT
bReturn = FALSE; } else if (os.dwMajorVersion < 4) { // it's windows NT, but an old one
bReturn = FALSE; } } else { // unable to read version so give up
}
if (bReturn) { // disable thread init calls
DisableThreadLibraryCalls(DLLHandle);
// initialize the event log so events can be reported
PdhDebugStartTrace(); bStatus = PdhiOpenEventLog(& hEventLog); bStatus = PdhiGetRegistryDefaults();
// initialize the local computer name buffer
if (szStaticLocalMachineName[0] == 0) { // initialize the computer name for this computer
szStaticLocalMachineName[0] = BACKSLASH_L; szStaticLocalMachineName[1] = BACKSLASH_L; dwBufferLength = MAX_COMPUTERNAME_LENGTH + 1; GetComputerNameW(& szStaticLocalMachineName[2], & dwBufferLength); } hPdhDataMutex = CreateMutexW(NULL, FALSE, NULL); hPdhContextMutex = CreateMutexW(NULL, FALSE, NULL); hPdhHeap = HeapCreate(0, 0, 0); if (hPdhHeap == NULL) { // unable to create our own heap, so use the
// process heap
hPdhHeap = GetProcessHeap(); } PdhiPlaInitMutex(); } } break;
case DLL_PROCESS_DETACH:
// close all pending loggers
//
bProcessIsDetaching = (ReservedAndUnused != NULL) ? (TRUE) : (FALSE); PdhiCloseAllLoggers();
// walk down query list and close (at least disconnect) queries.
PdhiQueryCleanup (); FreeAllMachines(bProcessIsDetaching); PdhiFreeAllWbemServers(); if (hPdhDataMutex != NULL) { bStatus = CloseHandle(hPdhDataMutex); hPdhDataMutex = NULL; } if (hPdhContextMutex != NULL) { bStatus = CloseHandle(hPdhContextMutex); hPdhContextMutex = NULL; }
if (hPdhHeap != GetProcessHeap()) { HeapDestroy(hPdhHeap); hPdhHeap = NULL; }
// lastly close the event log interface
bStatus = PdhiCloseEventLog(& hEventLog); bReturn = TRUE; break ;
case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: bReturn = TRUE; break; }
return (bReturn); }
|