|
|
/*++
Copyright (c) 1995-1997 Microsoft Corporation
Module Name:
autostart.c
Abstract:
Autostart wmi loggers. Takes arguments from tracing registry (This code may end up in wpp framework, hence Wpp prefix)
Author:
Gor Nishanov (gorn) 29-Oct-2000
Revision History:
--*/
#include "clusrtlp.h"
#include <wmistr.h>
#include <evntrace.h>
#define WppDebug(x,y)
#define WPPINIT_STATIC
#define WPP_REG_TRACE_REGKEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Tracing"
#define WPP_TEXTGUID_LEN 37
static TRACEHANDLE WppQueryLogger(PCWSTR LoggerName) { ULONG status; EVENT_TRACE_PROPERTIES LoggerInfo;
ZeroMemory(&LoggerInfo, sizeof(LoggerInfo)); LoggerInfo.Wnode.BufferSize = sizeof(LoggerInfo); LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
status = QueryTraceW(0, LoggerName, &LoggerInfo); WppDebug(4, ("QueryLogger(%ws) => %x:%x %d\n", LoggerName, LoggerInfo.Wnode.HistoricalContext, status) ); if (status == ERROR_SUCCESS || status == ERROR_MORE_DATA) { return (TRACEHANDLE) LoggerInfo.Wnode.HistoricalContext; } return 0; }
WPPINIT_STATIC __inline UINT WppHexVal(int ch) { return isdigit(ch) ? ch - '0' : ch - 'a' + 10; }
WPPINIT_STATIC UINT WppHex(LPCWSTR s, int n) { UINT res = 0; while(n--) { res = res * 16 + WppHexVal(*s++); } return res; }
WPPINIT_STATIC VOID WppGuidFromStr( IN LPCWSTR str, OUT LPGUID guid) { guid->Data1 = WppHex(str + 0, 8); guid->Data2 = (USHORT)WppHex(str + 9, 4); guid->Data3 = (USHORT)WppHex(str + 14, 4); guid->Data4[0] = (UCHAR) WppHex(str + 19, 2); guid->Data4[1] = (UCHAR) WppHex(str + 21, 2); guid->Data4[2] = (UCHAR) WppHex(str + 24, 2); guid->Data4[3] = (UCHAR) WppHex(str + 26, 2); guid->Data4[4] = (UCHAR) WppHex(str + 28, 2); guid->Data4[5] = (UCHAR) WppHex(str + 30, 2); guid->Data4[6] = (UCHAR) WppHex(str + 32, 2); guid->Data4[7] = (UCHAR) WppHex(str + 34, 2); }
#define WPP_BUF_SIZE(hmem) ((hmem) ? (ULONG)LocalSize(hmem) : 0)
// Make sure that the buffer is at least of size dwSize
WPPINIT_STATIC DWORD WppGrowBuf(PVOID *Buf, DWORD dwSize) { DWORD status = ERROR_SUCCESS; WppDebug(4, ("WppGrowBuf(%x, %d (%d)) => ", *Buf, dwSize, WPP_BUF_SIZE(*Buf)) ); if (*Buf == 0) { *Buf = LocalAlloc(LMEM_FIXED, dwSize); if (*Buf == 0) { status = GetLastError(); } } else if (LocalSize(*Buf) < dwSize) { PVOID newBuf = LocalReAlloc(*Buf, dwSize, LMEM_MOVEABLE); if (newBuf) { *Buf = newBuf; } else { status = GetLastError(); } } WppDebug(4, ("(%x (%d), %d)\n", *Buf, WPP_BUF_SIZE(*Buf), status) ); return status; }
WPPINIT_STATIC DWORD WppRegQueryGuid( IN HKEY hKey, IN LPCWSTR ValueName, OUT LPGUID pGuid ) { WCHAR GuidTxt[WPP_TEXTGUID_LEN]; DWORD status; DWORD dwLen = sizeof(GuidTxt); DWORD Type;
status = RegQueryValueExW( hKey, // handle to key
ValueName, // value name
0, // reserved
&Type, // type buffer
(LPBYTE)GuidTxt, // data buffer //
&dwLen // size of data buffer
);
if (status != ERROR_SUCCESS || Type != REG_SZ || dwLen < 35) { return status; }
WppGuidFromStr(GuidTxt, pGuid);
return status; }
WPPINIT_STATIC DWORD WppRegQueryDword( IN HKEY hKey, IN LPCWSTR ValueName, IN DWORD Default, IN DWORD MinVal, IN DWORD MaxVal ) { DWORD Result = Default; DWORD dwLen = sizeof(DWORD);
RegQueryValueExW(hKey, ValueName, 0, NULL, // lpReserved, lpType,
(LPBYTE)&Result, &dwLen);
if (Result < MinVal || Result > MaxVal) { Result = Default; }
return Result; }
WPPINIT_STATIC DWORD WppRegQueryString( IN HKEY hKey, IN LPCWSTR ValueName, IN OUT PWCHAR *Buf, IN DWORD ExtraPadding // Add this amount whenever we need to alloc more memory
) { DWORD ExpandSize; DWORD BufSize; DWORD ValueSize = WPP_BUF_SIZE(*Buf); DWORD status; DWORD Type = 0;
status = RegQueryValueExW( hKey, // handle to key
ValueName, // value name
0, // reserved
&Type, // type buffer
(LPBYTE)(ValueSize?*Buf:ValueName), // data buffer //
&ValueSize // size of data buffer
); if (status == ERROR_MORE_DATA) { if (Type == REG_EXPAND_SZ) { ExtraPadding += ValueSize + 100; // Room for ExpandEnvStrings
} status = WppGrowBuf(Buf, ValueSize + ExtraPadding); if (status != ERROR_SUCCESS) { return status; } status = RegQueryValueExW( hKey, // handle to key
ValueName, // value name
0, // reserved
&Type, // type buffer
(LPBYTE)*Buf, // data buffer
&ValueSize // size of data buffer
); } if (status != ERROR_SUCCESS) { return status; } if (Type == REG_SZ) { return ERROR_SUCCESS; } if (Type != REG_EXPAND_SZ) { return ERROR_DATATYPE_MISMATCH; } if (wcschr(*Buf, '%') == 0) { // nothing to expand
return ERROR_SUCCESS; } BufSize = (ULONG)LocalSize(*Buf); ExpandSize = sizeof(WCHAR) * ExpandEnvironmentStringsW( *Buf, (LPWSTR)((LPBYTE)*Buf + ValueSize), (BufSize - ValueSize) / sizeof(WCHAR) ) ; if (ExpandSize + ValueSize > BufSize) { status = WppGrowBuf(Buf, ExpandSize + max(ExpandSize, ValueSize) + ExtraPadding ); if (status != ERROR_SUCCESS) { return status; } ExpandSize = ExpandEnvironmentStringsW(*Buf, (LPWSTR)((LPBYTE)*Buf + ValueSize), ExpandSize / sizeof(WCHAR)); } if (ExpandSize == 0) { return GetLastError(); } // Copy expanded string on top of the original one
MoveMemory(*Buf, (LPBYTE)*Buf + ValueSize, ExpandSize); return ERROR_SUCCESS; }
WPPINIT_STATIC void WppSetExt(LPWSTR buf, int i) { buf[0] = '.'; buf[4] = 0; buf[3] = (WCHAR)('0' + i % 10); i = i / 10; buf[2] = (WCHAR)('0' + i % 10); i = i / 10; buf[1] = (WCHAR)('0' + i % 10); }
#if !defined(WPP_DEFAULT_LOGGER_FLAGS)
# define WPP_DEFAULT_LOGGER_FLAGS (EVENT_TRACE_FILE_MODE_CIRCULAR | EVENT_TRACE_USE_GLOBAL_SEQUENCE)
#endif
// A set of buffers used by an autostart
// Buffers are reused between iterations and recursive invocations
// to minimize number of allocations
typedef struct _WPP_AUTO_START_BUFFERS { PWCHAR LogSessionName; PWCHAR Buf; } WPP_AUTO_START_BUFFERS, *PWPP_AUTO_START_BUFFERS;
WPPINIT_STATIC DWORD WppReadLoggerInfo( IN HKEY LoggerKey, IN OUT PWPP_AUTO_START_BUFFERS x, OUT TRACEHANDLE* Logger) { DWORD status; PEVENT_TRACE_PROPERTIES Trace; DWORD len, sessionNameLen;
DWORD MaxBackups = 0; DWORD ExtraPadding; // add this amount when we need to allocate
status = WppRegQueryString(LoggerKey, L"LogSessionName", &x->LogSessionName, 0); if (status != ERROR_SUCCESS) { // this registry node doesn't contain a logger
return status; }
sessionNameLen = wcslen(x->LogSessionName); *Logger = WppQueryLogger(x->LogSessionName);
if (*Logger) { WppDebug(1,("[WppInit] Logger %ls is already running\n", x->LogSessionName) ); return ERROR_SUCCESS; }
// The TraceProperties property buffer that we need to give to StartTrace
// should be of size EVENT_TRACE_PROPERTIES + len(sessionName) + len(logFileName)
// However, we don't know the length of logFileName at the moment. To eliminate
// extra allocations we will add ExtraPadding to an any allocation, so that the final
// buffer will be of required size
ExtraPadding = sizeof(EVENT_TRACE_PROPERTIES) + (sessionNameLen + 1) * sizeof(WCHAR);
status = WppRegQueryString(LoggerKey, L"LogFileName", &x->Buf, ExtraPadding); if (status != ERROR_SUCCESS) { WppDebug(1,("[WppInit] Read %ls\\LogFileName failed, %d\n", x->LogSessionName, status) ); return status; } len = wcslen(x->Buf);
MaxBackups = WppRegQueryDword(LoggerKey, L"MaxBackups", 0, 0, 999);
if (MaxBackups) { int i, success; LPWSTR FromExt, ToExt, From, To; // Copy current.evm => current.evm.001, 001 => 002, etc
// MakeSure, Buffer is big enought for two file names + .000 extensions
WppGrowBuf(&x->Buf, (len + 5) * 2 * sizeof(WCHAR) + ExtraPadding); // .xxx\0 (5)
From = x->Buf; // MyFileName.evm MyFileName.evm.001
FromExt = From + len ; // ^ ^ ^ ^
To = FromExt + 5; // .xxx0 // From Ext1 To Ext2
ToExt = To + len;
memcpy(To, From, (len + 1) * sizeof(WCHAR) ); for (i = MaxBackups; i >= 1; --i) { WppSetExt(ToExt, i); if (i == 1) { *FromExt = 0; // remove extension
} else { WppSetExt(FromExt, i-1); } success = MoveFileExW(From, To, MOVEFILE_REPLACE_EXISTING); if (!success) { status = GetLastError(); } else { status = ERROR_SUCCESS; } WppDebug(3, ("[WppInit] Rename %ls => %ls, status %d\n", From, To, status) ); } }
status = WppGrowBuf(&x->Buf, ExtraPadding + (len + 1) * sizeof(WCHAR) ); if (status != ERROR_SUCCESS) { return status; } MoveMemory((LPBYTE)x->Buf + sizeof(EVENT_TRACE_PROPERTIES), x->Buf, (len + 1) * sizeof(WCHAR) ); // Free room for the header
Trace = (PEVENT_TRACE_PROPERTIES)x->Buf; ZeroMemory(Trace, sizeof(EVENT_TRACE_PROPERTIES) );
Trace->Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + (len + sessionNameLen + 2) * sizeof(WCHAR); Trace->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
Trace->BufferSize = WppRegQueryDword(LoggerKey, L"BufferSize", 0, 0, ~0u); Trace->MinimumBuffers = WppRegQueryDword(LoggerKey, L"MinimumBuffers", 0, 0, ~0u); Trace->MaximumBuffers = WppRegQueryDword(LoggerKey, L"MaximumBuffers", 0, 0, ~0u); Trace->MaximumFileSize = WppRegQueryDword(LoggerKey, L"MaximumFileSize", 0, 0, ~0u); Trace->LogFileMode = WppRegQueryDword(LoggerKey, L"LogFileMode", WPP_DEFAULT_LOGGER_FLAGS, 0, ~0u); Trace->FlushTimer = WppRegQueryDword(LoggerKey, L"FlushTimer", 0, 0, ~0u); Trace->EnableFlags = WppRegQueryDword(LoggerKey, L"EnableFlags", 0, 0, ~0u); Trace->AgeLimit = WppRegQueryDword(LoggerKey, L"AgeLimit", 0, 0, ~0u);
Trace->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES); Trace->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + (len + 1) * sizeof(WCHAR);
wcscpy((LPWSTR)((LPBYTE)x->Buf + Trace->LoggerNameOffset), x->LogSessionName);
status = StartTraceW(Logger, x->LogSessionName, Trace); WppDebug(1, ("[WppInit] Logger %ls started %x:%x %d\n", x->LogSessionName, *Logger, status) ); return status; }
typedef struct _WPP_INHERITED_DATA { TRACEHANDLE Logger; ULONG ControlFlags; ULONG ControlLevel; } WPP_INHERITED_DATA, *PWPP_INHERITED_DATA;
WPPINIT_STATIC ULONG WppAutoStartInternal( IN HKEY Dir OPTIONAL, // if 0, use TracingKey ...
IN LPCWSTR ProductName, IN PWPP_INHERITED_DATA InheritedData OPTIONAL, IN OUT PWPP_AUTO_START_BUFFERS x // to minimize data allocations, the buffers are reused
) { ULONG status; WPP_INHERITED_DATA data; HKEY CloseMe = 0; HKEY hk = 0; DWORD dwSizeOfModuleName; DWORD dwIndex; GUID Guid;
WppDebug(2, ("[WppInit] Init %ls\n", ProductName) );
if (InheritedData) { data = *InheritedData; } else { ZeroMemory(&data, sizeof(data)); }
if (!Dir) { status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, WPP_REG_TRACE_REGKEY, 0, KEY_READ, &Dir); if (status != ERROR_SUCCESS) { WppDebug(1, ("[WppInit] Failed to open Trace Key, %d\n", status) ); goto exit_gracefully; } CloseMe = Dir; if (WppRegQueryDword(Dir, L"NoAutoStart", 0, 0, 1) == 1) { WppDebug(1, ("[WppInit] Auto-start vetoed\n") ); goto exit_gracefully; } }
status = RegOpenKeyExW(Dir, ProductName, 0, KEY_READ, &hk); if (status != ERROR_SUCCESS) { WppDebug(1, ("[WppInit] Failed to open %ls subkey, %d\n", ProductName, status) ); goto exit_gracefully; }
if (WppRegQueryDword(Dir, L"Active", 1, 0, 1) == 0) { WppDebug(1, ("[WppInit] Tracing is not active for %ls\n", ProductName) ); goto exit_gracefully; }
WppReadLoggerInfo(hk, x, &data.Logger);
data.ControlLevel = WppRegQueryDword(hk, L"ControlLevel", data.ControlLevel, 0, ~0u); data.ControlFlags = WppRegQueryDword(hk, L"ControlFlags", data.ControlFlags, 0, ~0u);
if (WppRegQueryGuid(hk, L"Guid", &Guid) == ERROR_SUCCESS) {
// We can try to start tracing //
if (data.Logger) { status = EnableTrace(1, data.ControlFlags, data.ControlLevel, &Guid, data.Logger); WppDebug(1, ("[WppInit] Enable %ls, status %d\n", ProductName, status) ); } }
dwSizeOfModuleName = WPP_BUF_SIZE(x->Buf); dwIndex = 0; while (ERROR_SUCCESS == (status = RegEnumKeyExW(hk, dwIndex, x->Buf, &dwSizeOfModuleName, NULL, NULL, NULL, NULL))) { status = WppAutoStartInternal(hk, x->Buf, &data, x);
dwSizeOfModuleName = WPP_BUF_SIZE(x->Buf); ++dwIndex; }
if (ERROR_NO_MORE_ITEMS == status) { status = ERROR_SUCCESS; }
exit_gracefully: if (CloseMe) { RegCloseKey(CloseMe); } if (hk) { RegCloseKey(hk); } return status; }
ULONG WppAutoStart( IN LPCWSTR ProductName ) { WPP_AUTO_START_BUFFERS x; ULONG status; x.LogSessionName = 0; x.Buf = 0;
if (ProductName == NULL) { return ERROR_SUCCESS; }
if( WppGrowBuf(&x.Buf, 1024) == ERROR_SUCCESS && WppGrowBuf(&x.LogSessionName, 64) == ERROR_SUCCESS ) {
WppDebug(1, ("[WppInit] Initialize %ls\n", ProductName) ); status = WppAutoStartInternal(0, ProductName, 0, &x);
} else { WppDebug(1, ("[WppInit] Allocation failure\n") ); status = ERROR_OUTOFMEMORY; }
LocalFree(x.Buf); LocalFree(x.LogSessionName);
return status; }
|