4948 lines
156 KiB
C
4948 lines
156 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996-1999 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
smlogsvc.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
service to log performance counter and trace data,
|
|||
|
and to scan for alert conditions.
|
|||
|
--*/
|
|||
|
|
|||
|
#ifndef UNICODE
|
|||
|
#define UNICODE 1
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef _UNICODE
|
|||
|
#define _UNICODE 1
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef _IMPLEMENT_WMI
|
|||
|
#define _IMPLEMENT_WMI 1
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef _DEBUG_OUTPUT
|
|||
|
#define _DEBUG_OUTPUT 0
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Windows Include files
|
|||
|
//
|
|||
|
#pragma warning ( disable : 4201)
|
|||
|
#pragma warning ( disable : 4127)
|
|||
|
|
|||
|
// Define the following to use the minimum of shlwapip.h
|
|||
|
|
|||
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <nturtl.h>
|
|||
|
#include <wtypes.h>
|
|||
|
#include <limits.h>
|
|||
|
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
#include <wmistr.h>
|
|||
|
#include <objbase.h>
|
|||
|
#include <initguid.h>
|
|||
|
#include <evntrace.h>
|
|||
|
#include <wmiguid.h>
|
|||
|
#include <wmium.h>
|
|||
|
#include <pdhmsg.h> // For BuildCurrentLogFileName
|
|||
|
#include <pdhp.h>
|
|||
|
#endif
|
|||
|
|
|||
|
#include <tchar.h>
|
|||
|
#include <assert.h>
|
|||
|
#include <limits.h>
|
|||
|
#include "common.h"
|
|||
|
#include "smlogsvc.h"
|
|||
|
#include "smlogmsg.h"
|
|||
|
|
|||
|
#define NT_KERNEL_LOGGER ((LPWSTR)L"NT Kernel Logger")
|
|||
|
#define DEFAULT_LOG_FILE_FOLDER L"%SystemDrive%\\PerfLogs"
|
|||
|
#define STATUS_MASK ((DWORD)0x3FFFFFFF)
|
|||
|
|
|||
|
// todo: Move SECONDS_IN_DAY definition
|
|||
|
#define SECONDS_IN_DAY ((LONGLONG)(86400))
|
|||
|
|
|||
|
// Global variables used by all modules
|
|||
|
HANDLE hEventLog = NULL;
|
|||
|
HINSTANCE hModule = NULL;
|
|||
|
DWORD* arrPdhDataCollectSuccess = NULL;
|
|||
|
INT iPdhDataCollectSuccessCount = 0;
|
|||
|
|
|||
|
// hNewQueryEvent is signalled when a new query is started. This tells the main
|
|||
|
// thread to reconfigure its array of Wait objects.
|
|||
|
HANDLE hNewQueryEvent = NULL;
|
|||
|
|
|||
|
SERVICE_STATUS_HANDLE hSmLogStatus;
|
|||
|
SERVICE_STATUS ssSmLogStatus;
|
|||
|
|
|||
|
// Static variables used by this module only
|
|||
|
|
|||
|
static PLOG_QUERY_DATA pFirstQuery = NULL;
|
|||
|
static CRITICAL_SECTION QueryDataLock;
|
|||
|
static CRITICAL_SECTION ConfigurationLock;
|
|||
|
static TCHAR gszDefaultLogFileFolder[MAX_PATH+1] = TEXT("");
|
|||
|
|
|||
|
// Active session count should match the number of query data objects.
|
|||
|
static DWORD dwActiveSessionCount = 0;
|
|||
|
static DWORD dwMaxActiveSessionCount = MAXIMUM_WAIT_OBJECTS - 1;
|
|||
|
static HANDLE arrSessionHandle[MAXIMUM_WAIT_OBJECTS];
|
|||
|
|
|||
|
|
|||
|
// Local function prototypes
|
|||
|
DWORD
|
|||
|
LoadCommonConfig(
|
|||
|
IN PLOG_QUERY_DATA pQuery);
|
|||
|
|
|||
|
void
|
|||
|
LockQueryData ( void );
|
|||
|
|
|||
|
void
|
|||
|
UnlockQueryData ( void );
|
|||
|
|
|||
|
PLOG_QUERY_DATA
|
|||
|
GetQueryData (
|
|||
|
LPCTSTR szQueryName );
|
|||
|
|
|||
|
void
|
|||
|
FreeQueryData (
|
|||
|
IN PLOG_QUERY_DATA pQuery );
|
|||
|
|
|||
|
void
|
|||
|
RemoveAndFreeQueryData (
|
|||
|
HANDLE hThisQuery );
|
|||
|
|
|||
|
BOOL
|
|||
|
AlertFieldsMatch (
|
|||
|
IN PLOG_QUERY_DATA pFirstQuery,
|
|||
|
IN PLOG_QUERY_DATA pSecondQuery );
|
|||
|
|
|||
|
BOOL
|
|||
|
CommonFieldsMatch (
|
|||
|
IN PLOG_QUERY_DATA pFirstQuery,
|
|||
|
IN PLOG_QUERY_DATA pSecondQuery );
|
|||
|
|
|||
|
BOOL
|
|||
|
FieldsMatch (
|
|||
|
IN PLOG_QUERY_DATA pFirstQuery,
|
|||
|
IN PLOG_QUERY_DATA pSecondQuery );
|
|||
|
|
|||
|
DWORD
|
|||
|
ConfigureQuery (
|
|||
|
HKEY hKeyLogQuery,
|
|||
|
TCHAR* szQueryKeyNameBuffer,
|
|||
|
TCHAR* szQueryNameBuffer );
|
|||
|
|
|||
|
void
|
|||
|
ClearTraceProperties (
|
|||
|
IN PLOG_QUERY_DATA pQuery );
|
|||
|
|
|||
|
BOOL
|
|||
|
TraceStopRestartFieldsMatch (
|
|||
|
IN PLOG_QUERY_DATA pOrigQuery,
|
|||
|
IN PLOG_QUERY_DATA pNewQuery );
|
|||
|
|
|||
|
DWORD
|
|||
|
ReconfigureQuery (
|
|||
|
IN PLOG_QUERY_DATA pQuery );
|
|||
|
|
|||
|
DWORD
|
|||
|
StartQuery (
|
|||
|
IN PLOG_QUERY_DATA pQuery );
|
|||
|
|
|||
|
DWORD
|
|||
|
HandleMaxQueriesExceeded (
|
|||
|
IN PLOG_QUERY_DATA pQuery );
|
|||
|
|
|||
|
DWORD
|
|||
|
InitTraceGuids(
|
|||
|
IN PLOG_QUERY_DATA pQuery );
|
|||
|
|
|||
|
BOOL
|
|||
|
IsKernelTraceMode (
|
|||
|
IN DWORD dwTraceFlags );
|
|||
|
|
|||
|
DWORD
|
|||
|
LoadPdhLogUpdateSuccess ( void );
|
|||
|
|
|||
|
void
|
|||
|
LoadDefaultLogFileFolder ( void );
|
|||
|
|
|||
|
DWORD
|
|||
|
ProcessLogFileFolder (
|
|||
|
IN PLOG_QUERY_DATA pQuery,
|
|||
|
IN BOOL bReconfigure );
|
|||
|
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
|
|||
|
DWORD
|
|||
|
IsCreateNewFile (
|
|||
|
IN PLOG_QUERY_DATA pQuery,
|
|||
|
OUT BOOL* pbValidBySize,
|
|||
|
OUT BOOL* pbValidByTime );
|
|||
|
|
|||
|
ULONG
|
|||
|
TraceNotificationCallback(
|
|||
|
IN PWNODE_HEADER pWnode,
|
|||
|
IN UINT_PTR LogFileIndex )
|
|||
|
{
|
|||
|
UNREFERENCED_PARAMETER(LogFileIndex);
|
|||
|
|
|||
|
if ( (IsEqualGUID(& pWnode->Guid, & TraceErrorGuid))
|
|||
|
&& (pWnode->BufferSize >= (sizeof(WNODE_HEADER) + sizeof(ULONG))))
|
|||
|
{
|
|||
|
ULONG LoggerId = (ULONG) pWnode->HistoricalContext;
|
|||
|
PLOG_QUERY_DATA pQuery = pFirstQuery;
|
|||
|
ULONG Status = * ((ULONG *)
|
|||
|
(((PUCHAR) pWnode) + sizeof(WNODE_HEADER)));
|
|||
|
LOG_QUERY_DATA lqdTemp;
|
|||
|
HRESULT hr = ERROR_SUCCESS;
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
|
|||
|
while ( NULL != pQuery ) {
|
|||
|
// todo: Need to lock queue?
|
|||
|
if (pQuery->Properties.Wnode.HistoricalContext == LoggerId) {
|
|||
|
break;
|
|||
|
}
|
|||
|
pQuery = pQuery->next;
|
|||
|
}
|
|||
|
|
|||
|
if ( STATUS_LOG_FILE_FULL == Status
|
|||
|
|| STATUS_THREAD_IS_TERMINATING == Status ) {
|
|||
|
|
|||
|
if ( NULL != pQuery ) {
|
|||
|
SetEvent (pQuery->hExitEvent);
|
|||
|
}
|
|||
|
|
|||
|
} else if ( STATUS_MEDIA_CHANGED == Status ) {
|
|||
|
|
|||
|
BOOL bRun = TRUE;
|
|||
|
|
|||
|
if ( NULL != pQuery ) {
|
|||
|
|
|||
|
if( pQuery->hUserToken == NULL ){
|
|||
|
// see if we can get a user token
|
|||
|
hr = PdhiPlaRunAs( pQuery->szQueryName, NULL, &pQuery->hUserToken );
|
|||
|
|
|||
|
if ( ERROR_SUCCESS != hr ){
|
|||
|
LPWSTR szStringArray[2];
|
|||
|
szStringArray[0] = pQuery->szQueryName;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_INVALID_CREDENTIALS,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(HRESULT),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&hr
|
|||
|
);
|
|||
|
bRun = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
// Run command file, supplying previous filename
|
|||
|
if ( bRun && NULL != pQuery->szCmdFileName ) {
|
|||
|
DoLogCommandFile (pQuery, pQuery->szLogFileName, TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Retrieve the current log file name for the next notification.
|
|||
|
dwStatus = GetTraceQueryStatus ( pQuery, &lqdTemp );
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
lstrcpy ( pQuery->szLogFileName, lqdTemp.szLogFileName );
|
|||
|
RegisterCurrentFile( pQuery->hKeyQuery, pQuery->szLogFileName, 0 );
|
|||
|
} // else { todo report error
|
|||
|
|
|||
|
// Query to get the new filename
|
|||
|
} else {
|
|||
|
// report error
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return ERROR_SUCCESS;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
// Functions
|
|||
|
|
|||
|
DWORD
|
|||
|
GetSystemWideDefaultNullDataSource()
|
|||
|
{
|
|||
|
static BOOLEAN bRead = FALSE;
|
|||
|
static DWORD dwNullDataSource = DATA_SOURCE_REGISTRY;
|
|||
|
|
|||
|
if (bRead == FALSE) {
|
|||
|
HKEY hKeyPDH = NULL;
|
|||
|
DWORD dwStatus;
|
|||
|
DWORD dwType = 0;
|
|||
|
DWORD dwSize = sizeof(DWORD);
|
|||
|
|
|||
|
dwStatus = RegOpenKeyExW(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\PDH",
|
|||
|
0L,
|
|||
|
KEY_READ,
|
|||
|
& hKeyPDH);
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
dwStatus = RegQueryValueExW(hKeyPDH,
|
|||
|
L"DefaultNullDataSource",
|
|||
|
NULL,
|
|||
|
& dwType,
|
|||
|
(LPBYTE) & dwNullDataSource,
|
|||
|
& dwSize);
|
|||
|
if ( dwStatus == ERROR_SUCCESS
|
|||
|
&& dwType == REG_DWORD
|
|||
|
&& dwNullDataSource == DATA_SOURCE_WBEM) {
|
|||
|
dwNullDataSource = DATA_SOURCE_WBEM;
|
|||
|
}
|
|||
|
else {
|
|||
|
dwNullDataSource = DATA_SOURCE_REGISTRY;
|
|||
|
}
|
|||
|
RegCloseKey(hKeyPDH);
|
|||
|
}
|
|||
|
bRead = TRUE;
|
|||
|
}
|
|||
|
return dwNullDataSource;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScanHexFormat(
|
|||
|
IN const WCHAR* Buffer,
|
|||
|
IN ULONG MaximumLength,
|
|||
|
IN const WCHAR* Format,
|
|||
|
...)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Scans a source Buffer and places values from that buffer into the parameters
|
|||
|
as specified by Format.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Buffer -
|
|||
|
Contains the source buffer which is to be scanned.
|
|||
|
|
|||
|
MaximumLength -
|
|||
|
Contains the maximum length in characters for which Buffer is searched.
|
|||
|
This implies that Buffer need not be UNICODE_NULL terminated.
|
|||
|
|
|||
|
Format -
|
|||
|
Contains the format string which defines both the acceptable string format
|
|||
|
contained in Buffer, and the variable parameters which follow.
|
|||
|
|
|||
|
NOTE: This code is from \ntos\rtl\guid.c
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the number of parameters filled if the end of the Buffer is reached,
|
|||
|
else -1 on an error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
va_list ArgList;
|
|||
|
int FormatItems;
|
|||
|
|
|||
|
va_start(ArgList, Format);
|
|||
|
for (FormatItems = 0;;) {
|
|||
|
switch (*Format) {
|
|||
|
case 0:
|
|||
|
return (*Buffer && MaximumLength) ? -1 : FormatItems;
|
|||
|
case '%':
|
|||
|
Format++;
|
|||
|
if (*Format != '%') {
|
|||
|
ULONG Number;
|
|||
|
int Width;
|
|||
|
int Long;
|
|||
|
PVOID Pointer;
|
|||
|
|
|||
|
for (Long = 0, Width = 0;; Format++) {
|
|||
|
if ((*Format >= '0') && (*Format <= '9')) {
|
|||
|
Width = Width * 10 + *Format - '0';
|
|||
|
} else if (*Format == 'l') {
|
|||
|
Long++;
|
|||
|
} else if ((*Format == 'X') || (*Format == 'x')) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
Format++;
|
|||
|
for (Number = 0; Width--; Buffer++, MaximumLength--) {
|
|||
|
if (!MaximumLength)
|
|||
|
return (DWORD)(-1);
|
|||
|
Number *= 16;
|
|||
|
if ((*Buffer >= '0') && (*Buffer <= '9')) {
|
|||
|
Number += (*Buffer - '0');
|
|||
|
} else if ((*Buffer >= 'a') && (*Buffer <= 'f')) {
|
|||
|
Number += (*Buffer - 'a' + 10);
|
|||
|
} else if ((*Buffer >= 'A') && (*Buffer <= 'F')) {
|
|||
|
Number += (*Buffer - 'A' + 10);
|
|||
|
} else {
|
|||
|
return (DWORD)(-1);
|
|||
|
}
|
|||
|
}
|
|||
|
Pointer = va_arg(ArgList, PVOID);
|
|||
|
if (Long) {
|
|||
|
*(PULONG)Pointer = Number;
|
|||
|
} else {
|
|||
|
*(PUSHORT)Pointer = (USHORT)Number;
|
|||
|
}
|
|||
|
FormatItems++;
|
|||
|
break;
|
|||
|
}
|
|||
|
/* no break */
|
|||
|
default:
|
|||
|
if (!MaximumLength || (*Buffer != *Format)) {
|
|||
|
return (DWORD)(-1);
|
|||
|
}
|
|||
|
Buffer++;
|
|||
|
MaximumLength--;
|
|||
|
Format++;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
GUIDFromString(
|
|||
|
IN PUNICODE_STRING GuidString,
|
|||
|
OUT GUID* Guid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Retrieves a the binary format of a textual GUID presented in the standard
|
|||
|
string version of a GUID: "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}".
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
GuidString -
|
|||
|
Place from which to retrieve the textual form of the GUID.
|
|||
|
|
|||
|
Guid -
|
|||
|
Place in which to put the binary form of the GUID.
|
|||
|
|
|||
|
NOTE: This code is from \ntos\rtl\guid.c
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns ERROR_SUCCESS if the buffer contained a valid GUID, else
|
|||
|
ERROR_INVALID_PARAMETER if the string was invalid.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
USHORT Data4[8];
|
|||
|
int Count;
|
|||
|
|
|||
|
WCHAR GuidFormat[] = L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
|
|||
|
|
|||
|
for (Count = 0; Count < sizeof(Data4)/sizeof(Data4[0]); Count++) {
|
|||
|
Data4[Count] = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (ScanHexFormat(GuidString->Buffer, GuidString->Length / sizeof(WCHAR), GuidFormat, &Guid->Data1, &Guid->Data2, &Guid->Data3, &Data4[0], &Data4[1], &Data4[2], &Data4[3], &Data4[4], &Data4[5], &Data4[6], &Data4[7]) == -1) {
|
|||
|
return (DWORD)(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
for (Count = 0; Count < sizeof(Data4)/sizeof(Data4[0]); Count++) {
|
|||
|
Guid->Data4[Count] = (UCHAR)Data4[Count];
|
|||
|
}
|
|||
|
|
|||
|
return ERROR_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LPWSTR
|
|||
|
FormatEventLogMessage(DWORD dwStatus)
|
|||
|
{
|
|||
|
|
|||
|
LPVOID lpMsgBuf = NULL;
|
|||
|
HINSTANCE hPdh = NULL;
|
|||
|
DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM;
|
|||
|
|
|||
|
hPdh = LoadLibrary (_T("PDH.DLL"));
|
|||
|
|
|||
|
if (NULL != hPdh){
|
|||
|
dwFlags |= FORMAT_MESSAGE_FROM_HMODULE;
|
|||
|
}
|
|||
|
|
|||
|
FormatMessage(
|
|||
|
dwFlags,
|
|||
|
hPdh,
|
|||
|
dwStatus,
|
|||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|||
|
(LPTSTR)&lpMsgBuf,
|
|||
|
MAX_PATH,
|
|||
|
NULL );
|
|||
|
|
|||
|
if ( NULL != hPdh ) {
|
|||
|
FreeLibrary( hPdh );
|
|||
|
}
|
|||
|
|
|||
|
return lpMsgBuf;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
IsKernelTraceMode (
|
|||
|
IN DWORD dwTraceFlags )
|
|||
|
{
|
|||
|
BOOL bReturn = FALSE;
|
|||
|
DWORD dwKernelMask = SLQ_TLI_ENABLE_KERNEL_TRACE
|
|||
|
| SLQ_TLI_ENABLE_KERNEL_TRACE
|
|||
|
| SLQ_TLI_ENABLE_MEMMAN_TRACE
|
|||
|
| SLQ_TLI_ENABLE_FILEIO_TRACE
|
|||
|
| SLQ_TLI_ENABLE_PROCESS_TRACE
|
|||
|
| SLQ_TLI_ENABLE_THREAD_TRACE
|
|||
|
| SLQ_TLI_ENABLE_DISKIO_TRACE
|
|||
|
| SLQ_TLI_ENABLE_NETWORK_TCPIP_TRACE;
|
|||
|
|
|||
|
bReturn = ( dwKernelMask & dwTraceFlags ) ? TRUE : FALSE;
|
|||
|
|
|||
|
return bReturn;
|
|||
|
}
|
|||
|
|
|||
|
long
|
|||
|
JulianDateFromSystemTime(
|
|||
|
SYSTEMTIME *pST )
|
|||
|
{
|
|||
|
static WORD wDaysInRegularMonth[] = {
|
|||
|
31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
|
|||
|
};
|
|||
|
|
|||
|
static WORD wDaysInLeapYearMonth[] = {
|
|||
|
31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
|
|||
|
};
|
|||
|
|
|||
|
long JDate = 0;
|
|||
|
|
|||
|
// Check for leap year.
|
|||
|
if (pST->wMonth > 1) {
|
|||
|
if ( ( pST->wYear % 400 == 0 )
|
|||
|
|| ( pST->wYear % 100 != 0
|
|||
|
&& pST->wYear % 4 == 0 ) ) {
|
|||
|
// this is a leap year
|
|||
|
JDate += wDaysInLeapYearMonth[pST->wMonth - 2];
|
|||
|
} else {
|
|||
|
// this is not a leap year
|
|||
|
JDate += wDaysInRegularMonth[pST->wMonth - 2];
|
|||
|
}
|
|||
|
}
|
|||
|
// Add in days for this month.
|
|||
|
JDate += pST->wDay;
|
|||
|
|
|||
|
// Add in year.
|
|||
|
JDate += (pST->wYear) * 1000;
|
|||
|
|
|||
|
return JDate;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ReadRegistrySlqTime (
|
|||
|
HKEY hKey,
|
|||
|
LPCWSTR szQueryName, // For error logging
|
|||
|
LPCWSTR szValueName,
|
|||
|
PSLQ_TIME_INFO pPlqtDefault,
|
|||
|
PSLQ_TIME_INFO pPlqtValue
|
|||
|
)
|
|||
|
//
|
|||
|
// reads the time value "szValueName" from under hKey and
|
|||
|
// returns it in the Value buffer
|
|||
|
//
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
DWORD dwType = 0;
|
|||
|
DWORD dwBufferSize = 0;
|
|||
|
|
|||
|
SLQ_TIME_INFO plqLocal;
|
|||
|
|
|||
|
assert (pPlqtValue != NULL);
|
|||
|
assert (szValueName != NULL);
|
|||
|
|
|||
|
if (hKey != NULL) {
|
|||
|
// then there should be something to read
|
|||
|
// find out the size of the required buffer
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
hKey,
|
|||
|
szValueName,
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
NULL,
|
|||
|
&dwBufferSize);
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
if ((dwBufferSize == sizeof(SLQ_TIME_INFO)) && (dwType == REG_BINARY)) {
|
|||
|
// then there's something to read
|
|||
|
dwType = 0;
|
|||
|
memset (&plqLocal, 0, sizeof(SLQ_TIME_INFO));
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
hKey,
|
|||
|
szValueName,
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
(LPBYTE)&plqLocal,
|
|||
|
&dwBufferSize);
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
*pPlqtValue = plqLocal;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// nothing to read
|
|||
|
dwStatus = ERROR_NO_DATA;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// unable to read buffer
|
|||
|
// dwStatus has error
|
|||
|
}
|
|||
|
} else {
|
|||
|
// null key
|
|||
|
dwStatus = ERROR_BADKEY;
|
|||
|
}
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
LPCWSTR szStringArray[2];
|
|||
|
szStringArray[0] = szValueName;
|
|||
|
szStringArray[1] = szQueryName;
|
|||
|
|
|||
|
// apply default if it exists
|
|||
|
if (pPlqtDefault != NULL) {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_QUERY_VALUE,
|
|||
|
NULL,
|
|||
|
2,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
|
|||
|
*pPlqtValue = *pPlqtDefault;
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
// else no default.
|
|||
|
// Leave it to the caller to log event.
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ReadRegistryDwordValue (
|
|||
|
HKEY hKey,
|
|||
|
LPCWSTR szQueryName,
|
|||
|
LPCWSTR szValueName,
|
|||
|
PDWORD pdwDefault,
|
|||
|
LPDWORD pdwValue
|
|||
|
)
|
|||
|
//
|
|||
|
// reads the DWORD value "szValueName" from under hKey and
|
|||
|
// returns it in the Value buffer
|
|||
|
//
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
DWORD dwType = 0;
|
|||
|
DWORD dwBufferSize = 0;
|
|||
|
DWORD dwRegValue;
|
|||
|
|
|||
|
assert (pdwValue != NULL);
|
|||
|
assert (szValueName != NULL);
|
|||
|
|
|||
|
if (hKey != NULL) {
|
|||
|
// then there should be something to read
|
|||
|
// find out the size of the required buffer
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
hKey,
|
|||
|
szValueName,
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
NULL,
|
|||
|
&dwBufferSize);
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
if ( (dwBufferSize == sizeof(DWORD))
|
|||
|
&& ( (REG_DWORD == dwType) || ( REG_BINARY == dwType) ) ) {
|
|||
|
// then there's something to read
|
|||
|
dwType = 0;
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
hKey,
|
|||
|
szValueName,
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
(LPBYTE)&dwRegValue,
|
|||
|
&dwBufferSize);
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
*pdwValue = dwRegValue;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// nothing to read
|
|||
|
dwStatus = ERROR_NO_DATA;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// unable to read buffer
|
|||
|
// dwStatus has error
|
|||
|
}
|
|||
|
} else {
|
|||
|
// null key
|
|||
|
dwStatus = ERROR_BADKEY;
|
|||
|
}
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
LPCWSTR szStringArray[2];
|
|||
|
szStringArray[0] = szValueName;
|
|||
|
szStringArray[1] = szQueryName;
|
|||
|
|
|||
|
if (pdwDefault != NULL) {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_QUERY_VALUE,
|
|||
|
NULL,
|
|||
|
2,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
|
|||
|
*pdwValue = *pdwDefault;
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
} // else no default.
|
|||
|
// Leave it to the caller to log event.
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ReadRegistryStringValue (
|
|||
|
HKEY hKey,
|
|||
|
LPCWSTR szQueryName,
|
|||
|
LPCWSTR szValueName,
|
|||
|
LPCWSTR szDefault,
|
|||
|
LPWSTR *pszBuffer,
|
|||
|
LPDWORD pdwLength
|
|||
|
)
|
|||
|
//
|
|||
|
// reads the string value "szValueName" from under hKey and
|
|||
|
// frees any existing buffer referenced by pszBuffer,
|
|||
|
// then allocates a new buffer returning it with the
|
|||
|
// string value read from the registry and the size of the
|
|||
|
// buffer (in bytes)
|
|||
|
//
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
DWORD dwType = 0;
|
|||
|
DWORD dwBufferSize = 0;
|
|||
|
WCHAR* szNewStringBuffer = NULL;
|
|||
|
|
|||
|
assert (pdwLength!= NULL);
|
|||
|
assert (szValueName != NULL);
|
|||
|
|
|||
|
*pdwLength = 0;
|
|||
|
|
|||
|
if (hKey != NULL) {
|
|||
|
// then there should be something to read
|
|||
|
// find out the size of the required buffer
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
hKey,
|
|||
|
szValueName,
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
NULL,
|
|||
|
&dwBufferSize);
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
// NULL character size is 2 bytes
|
|||
|
if (dwBufferSize > 2) {
|
|||
|
// then there's something to read
|
|||
|
szNewStringBuffer = (WCHAR*) G_ALLOC ( dwBufferSize ); // new UCHAR[dwBufferSize];
|
|||
|
if (szNewStringBuffer != NULL) {
|
|||
|
dwType = 0;
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
hKey,
|
|||
|
szValueName,
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
(LPBYTE)szNewStringBuffer,
|
|||
|
&dwBufferSize);
|
|||
|
|
|||
|
if ( 0 == lstrlenW ( szNewStringBuffer ) ) {
|
|||
|
dwStatus = ERROR_NO_DATA;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Todo: Report event for this case.
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// nothing to read
|
|||
|
dwStatus = ERROR_NO_DATA;
|
|||
|
}
|
|||
|
} // else unable to read buffer
|
|||
|
// dwStatus has error
|
|||
|
} else {
|
|||
|
// null key
|
|||
|
dwStatus = ERROR_BADKEY;
|
|||
|
}
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
LPCWSTR szStringArray[2];
|
|||
|
szStringArray[0] = szValueName;
|
|||
|
szStringArray[1] = szQueryName;
|
|||
|
|
|||
|
if (szNewStringBuffer != NULL) {
|
|||
|
G_FREE ( szNewStringBuffer ); //delete (szNewStringBuffer);
|
|||
|
szNewStringBuffer = NULL;
|
|||
|
dwBufferSize = 0;
|
|||
|
}
|
|||
|
// apply default
|
|||
|
if (szDefault != NULL) {
|
|||
|
|
|||
|
dwBufferSize = lstrlenW(szDefault) + 1;
|
|||
|
if ( 1 < dwBufferSize ) {
|
|||
|
dwBufferSize *= sizeof (WCHAR);
|
|||
|
|
|||
|
szNewStringBuffer = (WCHAR*) G_ALLOC ( dwBufferSize );
|
|||
|
|
|||
|
if (szNewStringBuffer != NULL) {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_QUERY_VALUE,
|
|||
|
NULL,
|
|||
|
2,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
|
|||
|
lstrcpyW (
|
|||
|
szNewStringBuffer,
|
|||
|
szDefault);
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_QUERY_DEF_VAL,
|
|||
|
NULL,
|
|||
|
2,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
}
|
|||
|
}
|
|||
|
} // else no default so no data returned
|
|||
|
// Let the caller log the event if they want to.
|
|||
|
// Todo: Report event for OUTOFMEMORY case.
|
|||
|
}
|
|||
|
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
// then delete the old buffer and replace it with
|
|||
|
// the new one
|
|||
|
if (*pszBuffer != NULL) {
|
|||
|
G_FREE (*pszBuffer ); //delete (*pszBuffer );
|
|||
|
}
|
|||
|
*pszBuffer = szNewStringBuffer;
|
|||
|
*pdwLength = dwBufferSize;
|
|||
|
} else {
|
|||
|
// if error then delete the buffer
|
|||
|
if (szNewStringBuffer != NULL) {
|
|||
|
G_FREE ( szNewStringBuffer ); //delete (szNewStringBuffer);
|
|||
|
*pdwLength = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ReadRegistryIndirectStringValue (
|
|||
|
HKEY hKey,
|
|||
|
LPCWSTR szQueryName, // For error logging
|
|||
|
LPCWSTR szValueName,
|
|||
|
LPCWSTR szDefault,
|
|||
|
LPWSTR* pszBuffer,
|
|||
|
UINT* puiLength )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
LPCWSTR szStringArray[2];
|
|||
|
|
|||
|
szStringArray[0] = szValueName;
|
|||
|
szStringArray[1] = szQueryName;
|
|||
|
|
|||
|
dwStatus = SmReadRegistryIndirectStringValue (
|
|||
|
hKey,
|
|||
|
szValueName,
|
|||
|
szDefault,
|
|||
|
pszBuffer,
|
|||
|
puiLength );
|
|||
|
/*
|
|||
|
Todo: Report event on failure
|
|||
|
if ( NULL != szDefault ) {
|
|||
|
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_QUERY_VALUE_NODEF,
|
|||
|
NULL,
|
|||
|
2,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
}
|
|||
|
*/
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WriteRegistryDwordValue (
|
|||
|
HKEY hKey,
|
|||
|
LPCWSTR szValueName,
|
|||
|
LPDWORD pdwValue,
|
|||
|
DWORD dwType
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
DWORD dwValue = sizeof(DWORD);
|
|||
|
|
|||
|
assert ((dwType == REG_DWORD) ||
|
|||
|
(dwType == REG_BINARY));
|
|||
|
|
|||
|
dwStatus = RegSetValueEx (
|
|||
|
hKey, szValueName, 0L,
|
|||
|
dwType,
|
|||
|
(CONST BYTE *)pdwValue,
|
|||
|
dwValue);
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
WriteRegistrySlqTime (
|
|||
|
HKEY hKey,
|
|||
|
LPCWSTR szValueName,
|
|||
|
PSLQ_TIME_INFO pSlqTime
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
DWORD dwValue = sizeof(SLQ_TIME_INFO);
|
|||
|
|
|||
|
dwStatus = RegSetValueEx (
|
|||
|
hKey, szValueName, 0L,
|
|||
|
REG_BINARY,
|
|||
|
(CONST BYTE *)pSlqTime,
|
|||
|
dwValue);
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
BuildCurrentLogFileName (
|
|||
|
IN LPCTSTR szQueryName,
|
|||
|
IN LPCTSTR szBaseFileName,
|
|||
|
IN LPCTSTR szDefaultDir,
|
|||
|
IN LPCTSTR szSqlLogName,
|
|||
|
IN LPTSTR szOutFileBuffer,
|
|||
|
IN LPDWORD lpdwSerialNumber,
|
|||
|
IN DWORD dwAutoNameFormat,
|
|||
|
IN DWORD dwLogFileType,
|
|||
|
IN INT iCnfSerial
|
|||
|
)
|
|||
|
// presumes OutFileBuffer is large enough (i.e. >= MAX_PATH+1)
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
PPDH_PLA_INFO pInfo = NULL;
|
|||
|
DWORD dwStrBufLen = 0;
|
|||
|
DWORD dwInfoSize = 0;
|
|||
|
DWORD dwFlags = 0;
|
|||
|
|
|||
|
dwStatus = PdhPlaGetInfo(
|
|||
|
(LPTSTR)szQueryName,
|
|||
|
NULL,
|
|||
|
&dwInfoSize,
|
|||
|
pInfo );
|
|||
|
|
|||
|
if( ERROR_SUCCESS == dwStatus && 0 != dwInfoSize ){
|
|||
|
pInfo = (PPDH_PLA_INFO)G_ALLOC(dwInfoSize);
|
|||
|
if( NULL != pInfo && (sizeof(PDH_PLA_INFO) <= dwInfoSize) ){
|
|||
|
ZeroMemory( pInfo, dwInfoSize );
|
|||
|
|
|||
|
pInfo->dwMask = PLA_INFO_FLAG_FORMAT|
|
|||
|
PLA_INFO_FLAG_FILENAME|
|
|||
|
PLA_INFO_FLAG_AUTOFORMAT|
|
|||
|
PLA_INFO_FLAG_TYPE|
|
|||
|
PLA_INFO_FLAG_DEFAULTDIR|
|
|||
|
PLA_INFO_FLAG_SRLNUMBER|
|
|||
|
PLA_INFO_FLAG_SQLNAME|
|
|||
|
PLA_INFO_FLAG_STATUS;
|
|||
|
|
|||
|
dwStatus = PdhPlaGetInfo(
|
|||
|
(LPTSTR)szQueryName,
|
|||
|
NULL,
|
|||
|
&dwInfoSize,
|
|||
|
pInfo );
|
|||
|
|
|||
|
pInfo->dwFileFormat = dwLogFileType;
|
|||
|
pInfo->strBaseFileName = (LPTSTR)szBaseFileName;
|
|||
|
pInfo->dwAutoNameFormat = dwAutoNameFormat;
|
|||
|
// PLA_INFO_FLAG_TYPE is counter log vs trace log vs alert
|
|||
|
|
|||
|
pInfo->strDefaultDir = (LPTSTR)szDefaultDir;
|
|||
|
pInfo->dwLogFileSerialNumber = *lpdwSerialNumber;
|
|||
|
pInfo->strSqlName = (LPTSTR)szSqlLogName;
|
|||
|
|
|||
|
dwFlags = PLA_FILENAME_CREATEONLY;
|
|||
|
|
|||
|
// iCnfSerial = 0 - No serial suffix for Create New File
|
|||
|
// iCnfSerial = -1 - Include format string for trace file serial number.
|
|||
|
if ( 0 == iCnfSerial ) {
|
|||
|
pInfo->ptCreateNewFile.dwAutoMode = SLQ_AUTO_MODE_NONE;
|
|||
|
} else {
|
|||
|
dwFlags |= PLA_FILENAME_USE_SUBEXT;
|
|||
|
if ( -1 == iCnfSerial ) {
|
|||
|
dwFlags |= PLA_FILENAME_GET_SUBFMT;
|
|||
|
pInfo->ptCreateNewFile.dwAutoMode = SLQ_AUTO_MODE_SIZE;
|
|||
|
} else {
|
|||
|
pInfo->ptCreateNewFile.dwAutoMode = SLQ_AUTO_MODE_AFTER;
|
|||
|
pInfo->dwReserved1 = iCnfSerial;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
dwStatus = PdhPlaGetLogFileName (
|
|||
|
(LPTSTR)szQueryName,
|
|||
|
NULL,
|
|||
|
pInfo,
|
|||
|
dwFlags,
|
|||
|
&dwStrBufLen,
|
|||
|
NULL );
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus || PDH_INSUFFICIENT_BUFFER == dwStatus ) {
|
|||
|
// todo: remove buf length restriction
|
|||
|
if ( dwStrBufLen <= MAX_PATH * sizeof(WCHAR) ) {
|
|||
|
dwStatus = PdhPlaGetLogFileName (
|
|||
|
(LPTSTR)szQueryName,
|
|||
|
NULL,
|
|||
|
pInfo,
|
|||
|
dwFlags,
|
|||
|
&dwStrBufLen,
|
|||
|
szOutFileBuffer );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != pInfo ) {
|
|||
|
G_FREE( pInfo );
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
FileExists (
|
|||
|
IN LPCTSTR szFileName )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
BOOL bFileExists = FALSE;
|
|||
|
HANDLE hFile = NULL;
|
|||
|
LONG lErrorMode;
|
|||
|
|
|||
|
|
|||
|
if ( NULL != szFileName ) {
|
|||
|
lErrorMode = SetErrorMode ( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
|
|||
|
|
|||
|
hFile = CreateFile(
|
|||
|
szFileName,
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|||
|
NULL,
|
|||
|
OPEN_EXISTING,
|
|||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (INVALID_HANDLE_VALUE == hFile ) {
|
|||
|
dwStatus = GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != hFile
|
|||
|
&& INVALID_HANDLE_VALUE != hFile
|
|||
|
&& ERROR_SUCCESS == dwStatus )
|
|||
|
{
|
|||
|
bFileExists = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
CloseHandle(hFile);
|
|||
|
|
|||
|
SetErrorMode ( lErrorMode );
|
|||
|
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
return bFileExists;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
LoadCommonConfig(
|
|||
|
IN PLOG_QUERY_DATA pQuery)
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
DWORD dwBufferSize = 0;
|
|||
|
UINT uiBufferLen = 0;
|
|||
|
SLQ_TIME_INFO stiDefault;
|
|||
|
DWORD dwDefault;
|
|||
|
DWORD dwTempRestart;
|
|||
|
SYSTEMTIME stLocalTime;
|
|||
|
FILETIME ftLocalTime;
|
|||
|
DWORD dwLocalMask = 0;
|
|||
|
DWORD dwLocalAttributes = 0;
|
|||
|
|
|||
|
// Schedule
|
|||
|
|
|||
|
dwDefault = SLQ_QUERY_STOPPED;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Current State",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwCurrentState);
|
|||
|
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
// Pass NULL default to avoid warning message.
|
|||
|
// A missing value here is normal, converting from Win2000 config.
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"RealTime DataSource",
|
|||
|
NULL,
|
|||
|
&pQuery->dwRealTimeQuery);
|
|||
|
|
|||
|
if ( ERROR_NO_DATA == dwStatus
|
|||
|
|| ERROR_FILE_NOT_FOUND == dwStatus
|
|||
|
|| ( 0 == pQuery->dwRealTimeQuery ) ) {
|
|||
|
|
|||
|
pQuery->dwRealTimeQuery = GetSystemWideDefaultNullDataSource();
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
GetLocalTime (&stLocalTime);
|
|||
|
SystemTimeToFileTime (&stLocalTime, &ftLocalTime);
|
|||
|
|
|||
|
stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
|
|||
|
stiDefault.wTimeType = SLQ_TT_TTYPE_START;
|
|||
|
stiDefault.dwAutoMode = SLQ_AUTO_MODE_AT;
|
|||
|
stiDefault.llDateTime = *(LONGLONG *)&ftLocalTime;
|
|||
|
|
|||
|
dwStatus = ReadRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Start",
|
|||
|
&stiDefault,
|
|||
|
&pQuery->stiRegStart);
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
|
|||
|
stiDefault.wTimeType = SLQ_TT_TTYPE_STOP;
|
|||
|
stiDefault.dwAutoMode = SLQ_AUTO_MODE_NONE;
|
|||
|
stiDefault.llDateTime = MIN_TIME_VALUE;
|
|||
|
|
|||
|
dwStatus = ReadRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Stop",
|
|||
|
&stiDefault,
|
|||
|
&pQuery->stiRegStop);
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
// Apply default value outside of Read method, to avoid
|
|||
|
// error message. This value does not exist in Windows 2000
|
|||
|
dwStatus = ReadRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Create New File",
|
|||
|
NULL,
|
|||
|
&pQuery->stiCreateNewFile);
|
|||
|
|
|||
|
if ( ERROR_NO_DATA == dwStatus || ERROR_FILE_NOT_FOUND == dwStatus ) {
|
|||
|
stiDefault.wDataType = SLQ_TT_DTYPE_UNITS;
|
|||
|
stiDefault.wTimeType = SLQ_TT_TTYPE_CREATE_NEW_FILE;
|
|||
|
stiDefault.dwAutoMode = SLQ_AUTO_MODE_NONE;
|
|||
|
stiDefault.dwUnitType = SLQ_TT_UTYPE_SECONDS;
|
|||
|
stiDefault.dwValue = 0;
|
|||
|
|
|||
|
pQuery->stiCreateNewFile = stiDefault;
|
|||
|
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Restart flag is replaced by the Repeat time structure after Windows 2000.
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
// If autostop, collect Restart value.
|
|||
|
// Apply default value outside of Read method, to avoid
|
|||
|
// error message. This value does not exist in Windows 2000
|
|||
|
if ( pQuery->stiRegStop.dwAutoMode != SLQ_AUTO_MODE_NONE ) {
|
|||
|
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Restart",
|
|||
|
NULL,
|
|||
|
&dwTempRestart );
|
|||
|
if ( ERROR_NO_DATA == dwStatus
|
|||
|
|| ERROR_FILE_NOT_FOUND == dwStatus )
|
|||
|
{
|
|||
|
dwTempRestart = SLQ_AUTO_MODE_NONE;
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
// If autostop, collect Repeat value.
|
|||
|
|
|||
|
// Apply default value outside of Read method, to avoid
|
|||
|
// error message. This value does not exist in Windows 2000
|
|||
|
|
|||
|
if ( pQuery->stiRegStop.dwAutoMode != SLQ_AUTO_MODE_NONE ) {
|
|||
|
|
|||
|
dwStatus = ReadRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Repeat Schedule",
|
|||
|
NULL,
|
|||
|
&pQuery->stiRepeat );
|
|||
|
|
|||
|
if ( ERROR_NO_DATA == dwStatus
|
|||
|
|| ERROR_FILE_NOT_FOUND == dwStatus
|
|||
|
|| SLQ_AUTO_MODE_NONE == pQuery->stiRepeat.dwAutoMode )
|
|||
|
{
|
|||
|
// If the repeat value doesn't exist or is set to NONE,
|
|||
|
// default to the Restart mode value: NONE or AFTER
|
|||
|
|
|||
|
stiDefault.wDataType = SLQ_TT_DTYPE_UNITS;
|
|||
|
stiDefault.wTimeType = SLQ_TT_TTYPE_REPEAT_SCHEDULE;
|
|||
|
|
|||
|
stiDefault.dwAutoMode = dwTempRestart;
|
|||
|
stiDefault.dwUnitType = SLQ_TT_UTYPE_MINUTES;
|
|||
|
stiDefault.dwValue = 0;
|
|||
|
|
|||
|
pQuery->stiRepeat = stiDefault;
|
|||
|
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
// Todo: Log error events
|
|||
|
|
|||
|
if ( NULL == pQuery->szLogFileComment ) {
|
|||
|
uiBufferLen = 0;
|
|||
|
} else {
|
|||
|
uiBufferLen = lstrlen ( pQuery->szLogFileComment ) + 1;
|
|||
|
}
|
|||
|
|
|||
|
ReadRegistryIndirectStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCWSTR)L"Comment",
|
|||
|
NULL,
|
|||
|
&pQuery->szLogFileComment,
|
|||
|
&uiBufferLen );
|
|||
|
|
|||
|
// Ignore status, default is empty.
|
|||
|
}
|
|||
|
// Todo: File attributes only for counter and trace logs
|
|||
|
// File attributes
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
dwDefault = (DWORD)-1;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Log File Max Size",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwMaxFileSize);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
dwDefault = SLF_BIN_FILE;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Log File Type",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwLogFileType);
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
pQuery->dwLogFileType = LOWORD(pQuery->dwLogFileType);
|
|||
|
|
|||
|
// For Whistler Beta 1, append mode stored in high word of
|
|||
|
// the log type registry value
|
|||
|
pQuery->dwAppendMode =
|
|||
|
(pQuery->dwLogFileType & 0xFFFF0000) == SLF_FILE_APPEND;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
// Pass NULL default to avoid warning message.
|
|||
|
// A missing value here is normal, converting from Win2000 config.
|
|||
|
dwLocalAttributes = 0;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Data Store Attributes",
|
|||
|
NULL,
|
|||
|
&dwLocalAttributes );
|
|||
|
|
|||
|
// Extract log file size units
|
|||
|
if ( ERROR_NO_DATA == dwStatus
|
|||
|
|| ERROR_FILE_NOT_FOUND == dwStatus
|
|||
|
|| ( 0 == ( dwLocalAttributes & SLF_DATA_STORE_SIZE_MASK ) ) ) {
|
|||
|
// If file size unit value is missing, default to Win2000 values
|
|||
|
if ( SLQ_COUNTER_LOG == pQuery->dwLogType ) {
|
|||
|
if ( SLF_SQL_LOG != pQuery->dwLogFileType ) {
|
|||
|
pQuery->dwLogFileSizeUnit = ONE_KB;
|
|||
|
} else {
|
|||
|
pQuery->dwLogFileSizeUnit = ONE_RECORD;
|
|||
|
}
|
|||
|
} else if ( SLQ_TRACE_LOG == pQuery->dwLogType ) {
|
|||
|
pQuery->dwLogFileSizeUnit = ONE_MB;
|
|||
|
}
|
|||
|
} else {
|
|||
|
if ( dwLocalAttributes & SLF_DATA_STORE_SIZE_ONE_MB ) {
|
|||
|
pQuery->dwLogFileSizeUnit = ONE_MB;
|
|||
|
} else if ( dwLocalAttributes & SLF_DATA_STORE_SIZE_ONE_KB ) {
|
|||
|
pQuery->dwLogFileSizeUnit = ONE_KB;
|
|||
|
} else if ( dwLocalAttributes & SLF_DATA_STORE_SIZE_ONE_RECORD ) {
|
|||
|
pQuery->dwLogFileSizeUnit = ONE_RECORD;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Extract append flag if not already set by Whistler Beta 1 code
|
|||
|
if ( 0 == pQuery->dwAppendMode ) {
|
|||
|
if ( ERROR_NO_DATA == dwStatus
|
|||
|
|| ERROR_FILE_NOT_FOUND == dwStatus
|
|||
|
|| ( 0 == ( dwLocalAttributes & SLF_DATA_STORE_APPEND_MASK ) ) )
|
|||
|
{
|
|||
|
// If file append mode value is missing, default to Win2000 values
|
|||
|
assert ( SLF_SQL_LOG != pQuery->dwLogFileType );
|
|||
|
if ( SLF_SQL_LOG != pQuery->dwLogFileType ) {
|
|||
|
pQuery->dwAppendMode = 0;
|
|||
|
}
|
|||
|
} else {
|
|||
|
pQuery->dwAppendMode = ( dwLocalAttributes & SLF_DATA_STORE_APPEND );
|
|||
|
}
|
|||
|
}
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
dwDefault = SLF_NAME_NNNNNN;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Log File Auto Format",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwAutoNameFormat );
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
WCHAR szDefault[MAX_PATH+1];
|
|||
|
|
|||
|
// Dependent on AutoNameFormat setting.
|
|||
|
|
|||
|
if ( SLF_NAME_NONE == pQuery->dwAutoNameFormat ) {
|
|||
|
// Default log file name is query name, if no autoformat.
|
|||
|
lstrcpyW ( ( LPWSTR)szDefault, pQuery->szQueryName );
|
|||
|
} else {
|
|||
|
szDefault[0] = _T('\0');
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL == pQuery->szBaseFileName ) {
|
|||
|
uiBufferLen = 0;
|
|||
|
} else {
|
|||
|
uiBufferLen = lstrlen ( pQuery->szBaseFileName ) + 1;
|
|||
|
}
|
|||
|
|
|||
|
ReadRegistryIndirectStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCWSTR)L"Log File Base Name",
|
|||
|
szDefault,
|
|||
|
&pQuery->szBaseFileName,
|
|||
|
&uiBufferLen );
|
|||
|
|
|||
|
ReplaceBlanksWithUnderscores ( pQuery->szBaseFileName );
|
|||
|
|
|||
|
if ( 0 == lstrlen (szDefault) ) {
|
|||
|
if ( NULL != pQuery->szBaseFileName ) {
|
|||
|
if ( 0 == lstrlen ( pQuery->szBaseFileName ) ) {
|
|||
|
// Ignore bad status if the base log file name
|
|||
|
//is NULL and auto format is enabled.
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Ignore bad status if the base log file name
|
|||
|
//is NULL and auto format is enabled.
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
TCHAR* pszTemp = NULL;
|
|||
|
DWORD cchLen = 0;
|
|||
|
DWORD cchExpandedLen = 0;
|
|||
|
|
|||
|
|
|||
|
dwStatus = ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Log File Folder",
|
|||
|
gszDefaultLogFileFolder,
|
|||
|
&pszTemp,
|
|||
|
&dwBufferSize );
|
|||
|
|
|||
|
//
|
|||
|
// Parse all environment variables
|
|||
|
//
|
|||
|
if (pszTemp != NULL) {
|
|||
|
cchLen = ExpandEnvironmentStrings ( pszTemp, NULL, 0 );
|
|||
|
|
|||
|
if ( 0 < cchLen ) {
|
|||
|
//
|
|||
|
// cchLen includes NULL.
|
|||
|
//
|
|||
|
if ( NULL != pQuery->szLogFileFolder ) {
|
|||
|
G_FREE (pQuery->szLogFileFolder );
|
|||
|
pQuery->szLogFileFolder = NULL;
|
|||
|
}
|
|||
|
pQuery->szLogFileFolder = G_ALLOC ( cchLen * sizeof(WCHAR) );
|
|||
|
|
|||
|
if ( NULL != pQuery->szLogFileFolder ) {
|
|||
|
|
|||
|
cchExpandedLen = ExpandEnvironmentStrings (
|
|||
|
pszTemp,
|
|||
|
pQuery->szLogFileFolder,
|
|||
|
cchLen );
|
|||
|
|
|||
|
if ( 0 == cchExpandedLen ) {
|
|||
|
dwStatus = GetLastError();
|
|||
|
pQuery->szLogFileFolder[0] = L'\0';
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = GetLastError();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != pszTemp ) {
|
|||
|
G_FREE ( pszTemp );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Sql Log Base Name",
|
|||
|
NULL,
|
|||
|
&pQuery->szSqlLogName,
|
|||
|
&dwBufferSize );
|
|||
|
// Ignore status, default is empty.
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
dwDefault = 1;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Log File Serial Number",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwCurrentSerialNumber );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
LoadQueryConfig(
|
|||
|
IN PLOG_QUERY_DATA pQuery )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
DWORD dwBufferSize;
|
|||
|
UINT uiBufferLen = 0;
|
|||
|
LPTSTR szStringArray[2];
|
|||
|
SLQ_TIME_INFO stiDefault;
|
|||
|
SLQ_TIME_INFO stiTemp;
|
|||
|
DWORD dwDefault;
|
|||
|
DWORD dwType;
|
|||
|
|
|||
|
// Do not write event for invalid log type.
|
|||
|
|
|||
|
dwType = REG_DWORD;
|
|||
|
dwBufferSize = sizeof(DWORD);
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
(LPCTSTR)L"Log Type",
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
(LPBYTE)&pQuery->dwLogType,
|
|||
|
&dwBufferSize);
|
|||
|
|
|||
|
if ( SLQ_COUNTER_LOG == pQuery->dwLogType ) {
|
|||
|
|
|||
|
// Counters
|
|||
|
|
|||
|
dwStatus = ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Counter List",
|
|||
|
NULL,
|
|||
|
&pQuery->mszCounterList,
|
|||
|
&dwBufferSize );
|
|||
|
|
|||
|
if ( (ERROR_SUCCESS != dwStatus ) || ( 0 == dwBufferSize ) ) {
|
|||
|
// no counter list retrieved so there's not much
|
|||
|
// point in continuing
|
|||
|
szStringArray[0] = pQuery->szQueryName;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_COUNTER_LIST,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
} else {
|
|||
|
// Schedule
|
|||
|
|
|||
|
// Collect Command file value.
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"EOF Command File",
|
|||
|
NULL,
|
|||
|
&pQuery->szCmdFileName,
|
|||
|
&dwBufferSize );
|
|||
|
// Ignore status, default is empty.
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
stiDefault.wDataType = SLQ_TT_DTYPE_UNITS;
|
|||
|
stiDefault.wTimeType = SLQ_TT_TTYPE_SAMPLE;
|
|||
|
stiDefault.dwAutoMode = SLQ_AUTO_MODE_AFTER;
|
|||
|
stiDefault.dwUnitType = SLQ_TT_UTYPE_SECONDS;
|
|||
|
stiDefault.dwValue = 15;
|
|||
|
|
|||
|
dwStatus = ReadRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Sample Interval",
|
|||
|
&stiDefault,
|
|||
|
&stiTemp);
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
LONGLONG llMillisecInterval;
|
|||
|
TimeInfoToMilliseconds( &stiTemp, &llMillisecInterval );
|
|||
|
assert ( ULONG_MAX > llMillisecInterval );
|
|||
|
if ( ULONG_MAX > llMillisecInterval ) {
|
|||
|
pQuery->dwMillisecondSampleInterval = (DWORD)(llMillisecInterval);
|
|||
|
} else {
|
|||
|
pQuery->dwMillisecondSampleInterval = ULONG_MAX - 1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} else if ( SLQ_ALERT == pQuery->dwLogType) {
|
|||
|
// Counters & alert limits
|
|||
|
|
|||
|
dwStatus = ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Counter List",
|
|||
|
NULL,
|
|||
|
&pQuery->mszCounterList,
|
|||
|
&dwBufferSize );
|
|||
|
|
|||
|
if ( (ERROR_SUCCESS != dwStatus ) || ( 0 == dwBufferSize ) ) {
|
|||
|
// no counter list retrieved so there's not much
|
|||
|
// point in continuing
|
|||
|
szStringArray[0] = pQuery->szQueryName;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_COUNTER_LIST,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
} else {
|
|||
|
// Schedule
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
stiDefault.wDataType = SLQ_TT_DTYPE_UNITS;
|
|||
|
stiDefault.wTimeType = SLQ_TT_TTYPE_SAMPLE;
|
|||
|
stiDefault.dwAutoMode = SLQ_AUTO_MODE_AFTER;
|
|||
|
stiDefault.dwUnitType = SLQ_TT_UTYPE_SECONDS;
|
|||
|
stiDefault.dwValue = 15;
|
|||
|
|
|||
|
dwStatus = ReadRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Sample Interval",
|
|||
|
&stiDefault,
|
|||
|
&stiTemp);
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
LONGLONG llMillisecInterval;
|
|||
|
TimeInfoToMilliseconds( &stiTemp, &llMillisecInterval );
|
|||
|
assert ( ULONG_MAX > llMillisecInterval );
|
|||
|
if ( ULONG_MAX > llMillisecInterval ) {
|
|||
|
pQuery->dwMillisecondSampleInterval = (DWORD)(llMillisecInterval);
|
|||
|
} else {
|
|||
|
pQuery->dwMillisecondSampleInterval = ULONG_MAX - 1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
// get action flags
|
|||
|
dwDefault = 0;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Action Flags",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwAlertActionFlags);
|
|||
|
}
|
|||
|
|
|||
|
if (( ERROR_SUCCESS == dwStatus ) &&
|
|||
|
((pQuery->dwAlertActionFlags & ALRT_ACTION_SEND_MSG) != 0)) {
|
|||
|
dwStatus = ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Network Name",
|
|||
|
(LPCTSTR)L"",
|
|||
|
&pQuery->szNetName,
|
|||
|
&dwBufferSize );
|
|||
|
}
|
|||
|
|
|||
|
if (( ERROR_SUCCESS == dwStatus ) &&
|
|||
|
((pQuery->dwAlertActionFlags & ALRT_ACTION_EXEC_CMD) != 0)) {
|
|||
|
ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Command File",
|
|||
|
NULL,
|
|||
|
&pQuery->szCmdFileName,
|
|||
|
&dwBufferSize );
|
|||
|
|
|||
|
if (( ERROR_SUCCESS == dwStatus ) &&
|
|||
|
((pQuery->dwAlertActionFlags & ALRT_CMD_LINE_U_TEXT) != 0)) {
|
|||
|
|
|||
|
// Todo: Log error events
|
|||
|
|
|||
|
if ( NULL == pQuery->szUserText ) {
|
|||
|
uiBufferLen = 0;
|
|||
|
} else {
|
|||
|
uiBufferLen = lstrlen ( pQuery->szUserText ) + 1;
|
|||
|
}
|
|||
|
|
|||
|
ReadRegistryIndirectStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"User Text",
|
|||
|
(LPCTSTR)L"",
|
|||
|
&pQuery->szUserText,
|
|||
|
&uiBufferLen );
|
|||
|
|
|||
|
// Ignore status, default is empty.
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (( ERROR_SUCCESS == dwStatus ) &&
|
|||
|
((pQuery->dwAlertActionFlags & ALRT_ACTION_START_LOG) != 0)) {
|
|||
|
dwStatus = ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Perf Log Name",
|
|||
|
(LPCTSTR)L"",
|
|||
|
&pQuery->szPerfLogName,
|
|||
|
&dwBufferSize );
|
|||
|
}
|
|||
|
}
|
|||
|
} else if ( SLQ_TRACE_LOG == pQuery->dwLogType ) {
|
|||
|
|
|||
|
// get trace log values
|
|||
|
DWORD dwProviderStatus;
|
|||
|
|
|||
|
dwDefault = 0;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Trace Flags",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwFlags);
|
|||
|
|
|||
|
dwProviderStatus = ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Trace Provider List",
|
|||
|
NULL,
|
|||
|
&pQuery->mszProviderList,
|
|||
|
&dwBufferSize );
|
|||
|
|
|||
|
if ( 0 == dwBufferSize ) {
|
|||
|
if ( (ERROR_SUCCESS != dwProviderStatus )
|
|||
|
&& ( ! IsKernelTraceMode( pQuery->dwFlags ) ) ) {
|
|||
|
// No provider list retrieved and not kernel trace so there's not much
|
|||
|
// point in continuing
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
dwStatus = SMLOG_UNABLE_READ_PROVIDER_LIST;
|
|||
|
}
|
|||
|
szStringArray[0] = pQuery->szQueryName;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_PROVIDER_LIST,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
} else {
|
|||
|
// Allocate a minimal buffer for the NULL character to simplify later logic.
|
|||
|
pQuery->mszProviderList = G_ALLOC ( sizeof(TCHAR) );
|
|||
|
if ( NULL != pQuery->mszProviderList ) {
|
|||
|
pQuery->mszProviderList[0] = _T('\0');
|
|||
|
} else{
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
szStringArray[0] = pQuery->szQueryName;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_PROVIDER_LIST,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
dwDefault = 4;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Trace Buffer Size",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwBufferSize);
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
dwDefault = 2;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Trace Buffer Min Count",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwBufferMinCount);
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
dwDefault = 25;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Trace Buffer Max Count",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwBufferMaxCount);
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
dwDefault = 0;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Trace Buffer Flush Interval",
|
|||
|
&dwDefault,
|
|||
|
&pQuery->dwBufferFlushInterval);
|
|||
|
}
|
|||
|
// Schedule
|
|||
|
|
|||
|
// Collect Command file value.
|
|||
|
// This is true for both Counter and Trace log files.
|
|||
|
// Alerts use the Command file field for Alert command file.
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
ReadRegistryStringValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"EOF Command File",
|
|||
|
NULL,
|
|||
|
&pQuery->szCmdFileName,
|
|||
|
&dwBufferSize );
|
|||
|
// Ignore status, default is empty.
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Ignore partly created logs and alerts.
|
|||
|
assert ( SLQ_NEW_LOG == pQuery->dwLogType );
|
|||
|
if ( SLQ_NEW_LOG == pQuery->dwLogType ) {
|
|||
|
dwStatus = SMLOG_LOG_TYPE_NEW;
|
|||
|
} else {
|
|||
|
dwStatus = SMLOG_INVALID_LOG_TYPE;
|
|||
|
|
|||
|
szStringArray[0] = pQuery->szQueryName;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_INVALID_LOG_TYPE,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&pQuery->dwLogType);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
dwStatus = LoadCommonConfig ( pQuery );
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
LockQueryData ( void )
|
|||
|
{
|
|||
|
EnterCriticalSection ( &QueryDataLock );
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
UnlockQueryData ( void )
|
|||
|
{
|
|||
|
LeaveCriticalSection ( &QueryDataLock );
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
EnterConfigure ( void )
|
|||
|
{
|
|||
|
EnterCriticalSection ( &QueryDataLock );
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
ExitConfigure ( void )
|
|||
|
{
|
|||
|
LeaveCriticalSection ( &QueryDataLock );
|
|||
|
}
|
|||
|
|
|||
|
PLOG_QUERY_DATA
|
|||
|
GetQueryData (
|
|||
|
LPCTSTR szQueryName )
|
|||
|
{
|
|||
|
PLOG_QUERY_DATA pQuery;
|
|||
|
|
|||
|
LockQueryData();
|
|||
|
|
|||
|
pQuery = pFirstQuery;
|
|||
|
|
|||
|
while ( NULL != pQuery ) {
|
|||
|
if ( !lstrcmpi(pQuery->szQueryName, szQueryName ) ) {
|
|||
|
// If the exit event isn't set, then this query is still active.
|
|||
|
if ((WaitForSingleObject (pQuery->hExitEvent, 0)) != WAIT_OBJECT_0) {
|
|||
|
break;
|
|||
|
}
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
else {
|
|||
|
{
|
|||
|
TCHAR szDebugString[MAX_PATH];
|
|||
|
swprintf (szDebugString, (LPCWSTR)L" Query %s: Exit event is set\n", pQuery->szQueryName);
|
|||
|
OutputDebugString (szDebugString);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
pQuery = pQuery->next;
|
|||
|
}
|
|||
|
|
|||
|
UnlockQueryData();
|
|||
|
|
|||
|
return pQuery;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PLOG_QUERY_DATA
|
|||
|
GetQueryDataPtr (
|
|||
|
HANDLE hThisQuery
|
|||
|
)
|
|||
|
{
|
|||
|
PLOG_QUERY_DATA pQuery = NULL;
|
|||
|
LockQueryData();
|
|||
|
|
|||
|
// Find the query data block in the list.
|
|||
|
|
|||
|
if ( hThisQuery == pFirstQuery->hThread ) {
|
|||
|
pQuery = pFirstQuery;
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL == pQuery ) {
|
|||
|
|
|||
|
for ( pQuery = pFirstQuery;
|
|||
|
NULL != pQuery->next;
|
|||
|
pQuery = pQuery->next ) {
|
|||
|
|
|||
|
if ( hThisQuery == pQuery->next->hThread ) {
|
|||
|
pQuery = pQuery->next;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
UnlockQueryData();
|
|||
|
return pQuery;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
DeallocateQueryBuffers (
|
|||
|
IN PLOG_QUERY_DATA pQuery )
|
|||
|
{
|
|||
|
// Deallocate the buffers that can be deleted when the collection
|
|||
|
// thread is reconfigured.
|
|||
|
if (( SLQ_COUNTER_LOG == pQuery->dwLogType ) ||
|
|||
|
( SLQ_ALERT == pQuery->dwLogType)) {
|
|||
|
|
|||
|
if (pQuery->mszCounterList != NULL) {
|
|||
|
G_FREE(pQuery->mszCounterList);
|
|||
|
pQuery->mszCounterList = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( SLQ_ALERT == pQuery->dwLogType) {
|
|||
|
if (pQuery->szNetName != NULL) {
|
|||
|
G_FREE(pQuery->szNetName);
|
|||
|
pQuery->szNetName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (pQuery->szPerfLogName != NULL) {
|
|||
|
G_FREE(pQuery->szPerfLogName);
|
|||
|
pQuery->szPerfLogName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (pQuery->szUserText != NULL) {
|
|||
|
G_FREE (pQuery->szUserText);
|
|||
|
pQuery->szUserText = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( SLQ_TRACE_LOG == pQuery->dwLogType) {
|
|||
|
if (pQuery->mszProviderList != NULL) {
|
|||
|
G_FREE(pQuery->mszProviderList);
|
|||
|
pQuery->mszProviderList = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (pQuery->szLogFileComment != NULL) {
|
|||
|
G_FREE(pQuery->szLogFileComment);
|
|||
|
pQuery->szLogFileComment = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (pQuery->szBaseFileName != NULL) {
|
|||
|
G_FREE(pQuery->szBaseFileName);
|
|||
|
pQuery->szBaseFileName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (pQuery->szLogFileFolder != NULL) {
|
|||
|
G_FREE(pQuery->szLogFileFolder);
|
|||
|
pQuery->szLogFileFolder = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (pQuery->szSqlLogName != NULL) {
|
|||
|
G_FREE(pQuery->szSqlLogName);
|
|||
|
pQuery->szSqlLogName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (pQuery->szCmdFileName != NULL) {
|
|||
|
G_FREE(pQuery->szCmdFileName);
|
|||
|
pQuery->szCmdFileName = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
ClearTraceProperties (
|
|||
|
IN PLOG_QUERY_DATA pQuery )
|
|||
|
{
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
G_ZERO (& pQuery->Properties, sizeof(EVENT_TRACE_PROPERTIES));
|
|||
|
G_ZERO (pQuery->szLoggerName, sizeof(pQuery->szLoggerName));
|
|||
|
G_ZERO (pQuery->szLogFileName, sizeof(pQuery->szLogFileName));
|
|||
|
|
|||
|
if ( NULL != pQuery->arrpGuid ) {
|
|||
|
ULONG ulIndex;
|
|||
|
|
|||
|
for ( ulIndex = 0; ulIndex < pQuery->ulGuidCount; ulIndex++ ) {
|
|||
|
if ( NULL != pQuery->arrpGuid[ulIndex] ) {
|
|||
|
G_FREE ( pQuery->arrpGuid[ulIndex] );
|
|||
|
pQuery->arrpGuid[ulIndex] = NULL;
|
|||
|
}
|
|||
|
if ( NULL != pQuery->arrpszProviderName[ulIndex] ) {
|
|||
|
G_FREE ( pQuery->arrpszProviderName[ulIndex] );
|
|||
|
pQuery->arrpszProviderName[ulIndex] = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
G_FREE ( pQuery->arrpGuid );
|
|||
|
pQuery->arrpGuid = NULL;
|
|||
|
|
|||
|
if ( NULL != pQuery->arrpszProviderName ) {
|
|||
|
G_FREE ( pQuery->arrpszProviderName );
|
|||
|
pQuery->arrpszProviderName = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
pQuery->ulGuidCount = 0;
|
|||
|
|
|||
|
pQuery->Properties.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
|
|||
|
pQuery->Properties.LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES)
|
|||
|
+ sizeof(pQuery->szLoggerName);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
LoadPdhLogUpdateSuccess ( void )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
HKEY hKeySysmonLog = NULL;
|
|||
|
|
|||
|
dwStatus = RegOpenKeyEx (
|
|||
|
(HKEY)HKEY_LOCAL_MACHINE,
|
|||
|
(LPCTSTR)TEXT("SYSTEM\\CurrentControlSet\\Services\\SysmonLog"),
|
|||
|
0L,
|
|||
|
KEY_READ,
|
|||
|
(PHKEY)&hKeySysmonLog);
|
|||
|
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
TCHAR* mszStatusList = NULL;
|
|||
|
DWORD dwBufferSize = 0;
|
|||
|
DWORD dwType = 0;
|
|||
|
|
|||
|
// find out the size of the required buffer
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
hKeySysmonLog,
|
|||
|
(LPCTSTR)_T("PdhDataCollectSuccessStatus"),
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
NULL,
|
|||
|
&dwBufferSize); // In bytes
|
|||
|
|
|||
|
// If there is something to read
|
|||
|
if ( (ERROR_SUCCESS == dwStatus ) && ( 0 < dwBufferSize ) ) {
|
|||
|
mszStatusList = G_ALLOC ( dwBufferSize );
|
|||
|
|
|||
|
if ( NULL != mszStatusList ) {
|
|||
|
mszStatusList[0] = _T('\0');
|
|||
|
dwType = 0;
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
hKeySysmonLog,
|
|||
|
(LPCTSTR)_T("PdhDataCollectSuccessStatus"),
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
(UCHAR*)mszStatusList,
|
|||
|
&dwBufferSize);
|
|||
|
|
|||
|
if ( (ERROR_SUCCESS == dwStatus )
|
|||
|
&& ( 0 < dwBufferSize )
|
|||
|
&& ( _T('\0') != mszStatusList[0] ) ) {
|
|||
|
|
|||
|
// Allocate and load Pdh data collection status value array.
|
|||
|
INT iStatusCount = 0;
|
|||
|
TCHAR* szThisStatus;
|
|||
|
|
|||
|
for (szThisStatus = mszStatusList;
|
|||
|
*szThisStatus != 0;
|
|||
|
szThisStatus += lstrlen(szThisStatus) + 1) {
|
|||
|
iStatusCount++;
|
|||
|
}
|
|||
|
|
|||
|
arrPdhDataCollectSuccess = G_ALLOC ( iStatusCount * sizeof ( DWORD ) );
|
|||
|
|
|||
|
if ( NULL != arrPdhDataCollectSuccess ) {
|
|||
|
INT iStatusIndex;
|
|||
|
|
|||
|
szThisStatus = mszStatusList;
|
|||
|
for ( iStatusIndex = 0; iStatusIndex < iStatusCount; iStatusIndex++ ) {
|
|||
|
if (0 != *szThisStatus ) {
|
|||
|
arrPdhDataCollectSuccess[iStatusIndex] = (DWORD)_ttoi( szThisStatus );
|
|||
|
szThisStatus += lstrlen(szThisStatus) + 1;
|
|||
|
} else {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
iPdhDataCollectSuccessCount = iStatusCount;
|
|||
|
}
|
|||
|
if ( NULL != mszStatusList ) {
|
|||
|
G_FREE ( mszStatusList );
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
InitTraceGuids(
|
|||
|
IN PLOG_QUERY_DATA pQuery )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
LPTSTR pszThisGuid;
|
|||
|
LONG ulGuidIndex;
|
|||
|
LONG ulpszGuidIndex;
|
|||
|
LONG ulGuidCount = 0;
|
|||
|
LPGUID* arrpGuid = NULL;
|
|||
|
PTCHAR* arrpszGuid = NULL;
|
|||
|
WCHAR pszThisGuidBuffer[64];
|
|||
|
UNICODE_STRING ustrGuid;
|
|||
|
|
|||
|
if ( NULL != pQuery ) {
|
|||
|
if ( NULL != pQuery->mszProviderList ) {
|
|||
|
for (pszThisGuid = pQuery->mszProviderList;
|
|||
|
*pszThisGuid != 0;
|
|||
|
pszThisGuid += lstrlen(pszThisGuid) + 1) {
|
|||
|
ulGuidCount += 1;
|
|||
|
if ( NULL == pszThisGuid ) {
|
|||
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
arrpGuid = G_ALLOC ( ulGuidCount * sizeof ( LPGUID ) );
|
|||
|
if (NULL == arrpGuid) {
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
} else {
|
|||
|
G_ZERO ( arrpGuid, ulGuidCount * sizeof ( LPGUID ) );
|
|||
|
for ( ulGuidIndex = 0; ulGuidIndex < ulGuidCount; ulGuidIndex++) {
|
|||
|
arrpGuid[ulGuidIndex] = G_ALLOC ( sizeof(GUID) );
|
|||
|
if (NULL == arrpGuid[ulGuidIndex]) {
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
// Create an array of pointers to individual provider Guids in the
|
|||
|
// mszProviderList. The provider Guids are used as provider
|
|||
|
// names in error messages, and for comparison with provider list
|
|||
|
arrpszGuid = G_ALLOC ( ulGuidCount * sizeof ( TCHAR* ) );
|
|||
|
if (NULL == arrpszGuid) {
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
} else {
|
|||
|
G_ZERO ( arrpszGuid, ulGuidCount * sizeof ( TCHAR* ) );
|
|||
|
|
|||
|
for ( ulpszGuidIndex = 0; ulpszGuidIndex < ulGuidCount; ulpszGuidIndex++) {
|
|||
|
arrpszGuid[ulpszGuidIndex] = G_ALLOC ( sizeof(TCHAR[MAX_PATH]) );
|
|||
|
if (NULL == arrpszGuid[ulpszGuidIndex]) {
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ERROR_SUCCESS == dwStatus) {
|
|||
|
ulGuidIndex = 0;
|
|||
|
for (pszThisGuid = pQuery->mszProviderList;
|
|||
|
*pszThisGuid != 0;
|
|||
|
pszThisGuid += lstrlen(pszThisGuid) + 1) {
|
|||
|
|
|||
|
lstrcpyW ((LPWSTR)pszThisGuidBuffer, pszThisGuid);
|
|||
|
|
|||
|
ustrGuid.Length = (USHORT)(lstrlen(pszThisGuidBuffer)*sizeof(TCHAR)); // Size of GUID length << USHORT
|
|||
|
ustrGuid.MaximumLength = sizeof (pszThisGuidBuffer);
|
|||
|
ustrGuid.Buffer = pszThisGuidBuffer;
|
|||
|
|
|||
|
dwStatus = GUIDFromString (&ustrGuid, arrpGuid[ulGuidIndex] );
|
|||
|
|
|||
|
lstrcpy ( arrpszGuid[ulGuidIndex], pszThisGuid );
|
|||
|
|
|||
|
ulGuidIndex++;
|
|||
|
}
|
|||
|
|
|||
|
pQuery->ulGuidCount = ulGuidCount;
|
|||
|
pQuery->arrpGuid = arrpGuid;
|
|||
|
pQuery->arrpszProviderName = arrpszGuid;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ERROR_SUCCESS != dwStatus) {
|
|||
|
// If failure anywhere, deallocate arrays
|
|||
|
if ( NULL != arrpszGuid ) {
|
|||
|
for (ulpszGuidIndex--; ulpszGuidIndex>=0; ulpszGuidIndex--) {
|
|||
|
G_FREE(arrpszGuid[ulpszGuidIndex]);
|
|||
|
}
|
|||
|
G_FREE(arrpszGuid);
|
|||
|
}
|
|||
|
if (NULL != arrpGuid) {
|
|||
|
for (ulGuidIndex--; ulGuidIndex>=0; ulGuidIndex--) {
|
|||
|
G_FREE(arrpGuid[ulGuidIndex]);
|
|||
|
}
|
|||
|
G_FREE(arrpGuid);
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
#else
|
|||
|
dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
|
|||
|
#endif
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
IsCreateNewFile (
|
|||
|
IN PLOG_QUERY_DATA pQuery,
|
|||
|
OUT BOOL* pbValidBySize,
|
|||
|
OUT BOOL* pbValidByTime )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
BOOL bLocalValidBySize = FALSE;
|
|||
|
BOOL bLocalValidByTime = FALSE;
|
|||
|
|
|||
|
|
|||
|
if ( ( NULL != pQuery ) ) {
|
|||
|
if ( SLQ_AUTO_MODE_SIZE == pQuery->stiCreateNewFile.dwAutoMode ) {
|
|||
|
|
|||
|
if ( ( SLF_SEQ_TRACE_FILE == pQuery->dwLogFileType )
|
|||
|
&& ( -1 != pQuery->dwMaxFileSize )
|
|||
|
&& ( 0 != pQuery->dwMaxFileSize ) )
|
|||
|
{
|
|||
|
bLocalValidBySize = TRUE;
|
|||
|
}
|
|||
|
} else if ( SLQ_AUTO_MODE_AFTER == pQuery->stiCreateNewFile.dwAutoMode ) {
|
|||
|
bLocalValidByTime = TRUE;
|
|||
|
}
|
|||
|
if ( NULL != pbValidBySize ) {
|
|||
|
*pbValidBySize = bLocalValidBySize;
|
|||
|
}
|
|||
|
if ( NULL != pbValidByTime ) {
|
|||
|
*pbValidByTime = bLocalValidByTime;
|
|||
|
}
|
|||
|
} else {
|
|||
|
assert ( FALSE );
|
|||
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
InitTraceProperties (
|
|||
|
IN PLOG_QUERY_DATA pQuery,
|
|||
|
IN BOOL bUpdateSerial,
|
|||
|
IN OUT DWORD* pdwSessionSerial,
|
|||
|
IN OUT INT* piCnfSerial )
|
|||
|
{
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
|
|||
|
HRESULT hr;
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
PPDH_PLA_INFO pInfo = NULL;
|
|||
|
DWORD dwInfoSize = 0;
|
|||
|
BOOL bBySize = FALSE;
|
|||
|
BOOL bByTime = FALSE;
|
|||
|
INT iLocalCnfSerial;
|
|||
|
DWORD dwLocalSessionSerial = 0; // Init for Prefix check
|
|||
|
BOOL bFileExists;
|
|||
|
|
|||
|
if ( NULL != pQuery && NULL != piCnfSerial ) {
|
|||
|
|
|||
|
hr = PdhPlaGetInfoW( pQuery->szQueryName, NULL, &dwInfoSize, pInfo );
|
|||
|
if( ERROR_SUCCESS == hr && 0 != dwInfoSize ) {
|
|||
|
pInfo = (PPDH_PLA_INFO)G_ALLOC(dwInfoSize);
|
|||
|
if( NULL != pInfo && (sizeof(PDH_PLA_INFO) <= dwInfoSize) ){
|
|||
|
ZeroMemory( pInfo, dwInfoSize );
|
|||
|
|
|||
|
pInfo->dwMask = PLA_INFO_FLAG_MODE|PLA_INFO_FLAG_LOGGERNAME;
|
|||
|
hr = PdhPlaGetInfoW( pQuery->szQueryName, NULL, &dwInfoSize, pInfo );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ClearTraceProperties ( pQuery );
|
|||
|
|
|||
|
dwStatus = IsCreateNewFile ( pQuery, &bBySize, &bByTime );
|
|||
|
|
|||
|
// Create format string, store it in pQuery->szLogFileName
|
|||
|
|
|||
|
if ( bBySize ) {
|
|||
|
// In BuildCurrentLogFileName, iCnfSerial of -1 signals code to
|
|||
|
// return the format string for cnf serial number
|
|||
|
iLocalCnfSerial = -1;
|
|||
|
} else {
|
|||
|
if ( bByTime ) {
|
|||
|
*piCnfSerial += 1;
|
|||
|
iLocalCnfSerial = *piCnfSerial;
|
|||
|
} else {
|
|||
|
iLocalCnfSerial = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != pdwSessionSerial ) {
|
|||
|
dwLocalSessionSerial = *pdwSessionSerial;
|
|||
|
} else {
|
|||
|
dwLocalSessionSerial = pQuery->dwCurrentSerialNumber;
|
|||
|
}
|
|||
|
|
|||
|
dwStatus = BuildCurrentLogFileName (
|
|||
|
pQuery->szQueryName,
|
|||
|
pQuery->szBaseFileName,
|
|||
|
pQuery->szLogFileFolder,
|
|||
|
pQuery->szSqlLogName,
|
|||
|
pQuery->szLogFileName,
|
|||
|
&dwLocalSessionSerial,
|
|||
|
pQuery->dwAutoNameFormat,
|
|||
|
pQuery->dwLogFileType,
|
|||
|
iLocalCnfSerial );
|
|||
|
|
|||
|
RegisterCurrentFile( pQuery->hKeyQuery, pQuery->szLogFileName, iLocalCnfSerial );
|
|||
|
|
|||
|
// Update log serial number if modified.
|
|||
|
if ( bUpdateSerial && SLF_NAME_NNNNNN == pQuery->dwAutoNameFormat ) {
|
|||
|
|
|||
|
pQuery->dwCurrentSerialNumber++;
|
|||
|
|
|||
|
// Todo: Info event on number wrap - Server Beta 3.
|
|||
|
if ( MAXIMUM_SERIAL_NUMBER < pQuery->dwCurrentSerialNumber ) {
|
|||
|
pQuery->dwCurrentSerialNumber = MINIMUM_SERIAL_NUMBER;
|
|||
|
}
|
|||
|
|
|||
|
WriteRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
(LPCTSTR)L"Log File Serial Number",
|
|||
|
&pQuery->dwCurrentSerialNumber,
|
|||
|
REG_DWORD);
|
|||
|
// Todo: log event on error.
|
|||
|
}
|
|||
|
|
|||
|
pQuery->Properties.Wnode.BufferSize = sizeof(pQuery->Properties)
|
|||
|
+ sizeof(pQuery->szLoggerName)
|
|||
|
+ sizeof(pQuery->szLogFileName);
|
|||
|
|
|||
|
if ( TRUE == bBySize ) {
|
|||
|
// Add room for trace code to to return formatted filename string.
|
|||
|
pQuery->Properties.Wnode.BufferSize += 8;
|
|||
|
}
|
|||
|
|
|||
|
pQuery->Properties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
|||
|
|
|||
|
// Fill out properties block and start.
|
|||
|
pQuery->Properties.BufferSize = pQuery->dwBufferSize;
|
|||
|
pQuery->Properties.MinimumBuffers = pQuery->dwBufferMinCount;
|
|||
|
pQuery->Properties.MaximumBuffers = pQuery->dwBufferMaxCount;
|
|||
|
|
|||
|
if ( pInfo ) {
|
|||
|
if ( pInfo->Trace.strLoggerName != NULL ) {
|
|||
|
lstrcpy ( pQuery->szLoggerName, pInfo->Trace.strLoggerName );
|
|||
|
}
|
|||
|
} else {
|
|||
|
lstrcpy ( pQuery->szLoggerName, pQuery->szQueryName );
|
|||
|
}
|
|||
|
|
|||
|
if ( (BOOL)( 0 == (pQuery->dwFlags & SLQ_TLI_ENABLE_BUFFER_FLUSH)) )
|
|||
|
pQuery->Properties.FlushTimer = 0;
|
|||
|
else
|
|||
|
pQuery->Properties.FlushTimer = pQuery->dwBufferFlushInterval;
|
|||
|
|
|||
|
if ( IsKernelTraceMode ( pQuery->dwFlags ) ) {
|
|||
|
pQuery->Properties.Wnode.Guid = SystemTraceControlGuid;
|
|||
|
|
|||
|
lstrcpy ( pQuery->szLoggerName, NT_KERNEL_LOGGER );
|
|||
|
|
|||
|
|
|||
|
if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_KERNEL_TRACE)) ) {
|
|||
|
// NT5 Beta 2 Single Kernel flag
|
|||
|
pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_PROCESS |
|
|||
|
EVENT_TRACE_FLAG_THREAD |
|
|||
|
EVENT_TRACE_FLAG_DISK_IO |
|
|||
|
EVENT_TRACE_FLAG_NETWORK_TCPIP;
|
|||
|
} else {
|
|||
|
if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_PROCESS_TRACE)) )
|
|||
|
pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_PROCESS;
|
|||
|
|
|||
|
if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_THREAD_TRACE)) )
|
|||
|
pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_THREAD;
|
|||
|
|
|||
|
if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_DISKIO_TRACE)) )
|
|||
|
pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_DISK_IO;
|
|||
|
|
|||
|
if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_NETWORK_TCPIP_TRACE)) )
|
|||
|
pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_NETWORK_TCPIP;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_MEMMAN_TRACE)) )
|
|||
|
pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS;
|
|||
|
|
|||
|
if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_FILEIO_TRACE)) )
|
|||
|
pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_DISK_FILE_IO;
|
|||
|
|
|||
|
} else {
|
|||
|
InitTraceGuids ( pQuery );
|
|||
|
}
|
|||
|
|
|||
|
if ( -1 == pQuery->dwMaxFileSize ) {
|
|||
|
pQuery->Properties.MaximumFileSize = 0;
|
|||
|
} else {
|
|||
|
pQuery->Properties.MaximumFileSize = pQuery->dwMaxFileSize;
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus && TRUE == bBySize ) {
|
|||
|
pQuery->Properties.LogFileMode =
|
|||
|
EVENT_TRACE_FILE_MODE_SEQUENTIAL | EVENT_TRACE_FILE_MODE_NEWFILE;
|
|||
|
} else if ( SLF_SEQ_TRACE_FILE == pQuery->dwLogFileType ) {
|
|||
|
pQuery->Properties.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
|
|||
|
|
|||
|
// Only set Append mode if the file already exists.
|
|||
|
if ( pQuery->dwAppendMode && FileExists ( pQuery->szLogFileName ) ) {
|
|||
|
pQuery->Properties.LogFileMode |= EVENT_TRACE_FILE_MODE_APPEND;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
assert ( SLF_CIRC_TRACE_FILE == pQuery->dwLogFileType );
|
|||
|
pQuery->Properties.LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
|
|||
|
}
|
|||
|
|
|||
|
if ( pInfo ) {
|
|||
|
pQuery->Properties.LogFileMode |= pInfo->Trace.dwMode;
|
|||
|
G_FREE( pInfo );
|
|||
|
}
|
|||
|
if ( NULL != pdwSessionSerial ) {
|
|||
|
*pdwSessionSerial = dwLocalSessionSerial;
|
|||
|
}
|
|||
|
} // Todo: else report error, return error
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
FreeQueryData (
|
|||
|
IN PLOG_QUERY_DATA pQuery )
|
|||
|
{
|
|||
|
// Caller must remove the thread data block from the list.
|
|||
|
|
|||
|
// Threads are deleted by only one thread, so this should not
|
|||
|
// be deleted out from under.
|
|||
|
assert ( NULL != pQuery );
|
|||
|
|
|||
|
if ( NULL != pQuery ) {
|
|||
|
// Free this entry.
|
|||
|
|
|||
|
if (( SLQ_COUNTER_LOG == pQuery->dwLogType ) ||
|
|||
|
( SLQ_ALERT == pQuery->dwLogType ) ){
|
|||
|
|
|||
|
while ( NULL != pQuery->pFirstCounter ) {
|
|||
|
PLOG_COUNTER_INFO pDelCI = pQuery->pFirstCounter;
|
|||
|
pQuery->pFirstCounter = pDelCI->next;
|
|||
|
|
|||
|
G_FREE( pDelCI );
|
|||
|
}
|
|||
|
} else {
|
|||
|
if ( NULL != pQuery->arrpGuid ) {
|
|||
|
ULONG ulIndex;
|
|||
|
|
|||
|
for ( ulIndex = 0; ulIndex < pQuery->ulGuidCount; ulIndex++ ) {
|
|||
|
if ( NULL != pQuery->arrpGuid[ulIndex] ) {
|
|||
|
G_FREE ( pQuery->arrpGuid[ulIndex] );
|
|||
|
pQuery->arrpGuid[ulIndex] = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
G_FREE ( pQuery->arrpGuid );
|
|||
|
pQuery->arrpGuid = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != pQuery->hThread ) {
|
|||
|
CloseHandle ( pQuery->hThread );
|
|||
|
pQuery->hThread = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != pQuery->hUserToken ) {
|
|||
|
CloseHandle ( pQuery->hUserToken );
|
|||
|
pQuery->hUserToken = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != pQuery->hExitEvent ) {
|
|||
|
CloseHandle ( pQuery->hExitEvent );
|
|||
|
pQuery->hExitEvent = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != pQuery->hReconfigEvent ) {
|
|||
|
CloseHandle ( pQuery->hReconfigEvent );
|
|||
|
pQuery->hReconfigEvent = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != pQuery->hKeyQuery ) {
|
|||
|
RegCloseKey ( pQuery->hKeyQuery );
|
|||
|
pQuery->hKeyQuery = NULL;
|
|||
|
}
|
|||
|
|
|||
|
DeallocateQueryBuffers( pQuery );
|
|||
|
|
|||
|
G_FREE (pQuery);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
RemoveAndFreeQueryData (
|
|||
|
HANDLE hThisQuery
|
|||
|
)
|
|||
|
{
|
|||
|
PLOG_QUERY_DATA pQuery = NULL;
|
|||
|
BOOL bFound = FALSE;
|
|||
|
|
|||
|
LockQueryData();
|
|||
|
|
|||
|
// Find the query data block and remove it from the list.
|
|||
|
|
|||
|
if ( hThisQuery == pFirstQuery->hThread ) {
|
|||
|
bFound = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if ( bFound ) {
|
|||
|
pQuery = pFirstQuery;
|
|||
|
pFirstQuery = pFirstQuery->next;
|
|||
|
} else {
|
|||
|
|
|||
|
PLOG_QUERY_DATA pQueryRemaining;
|
|||
|
|
|||
|
for ( pQuery = pFirstQuery;
|
|||
|
NULL != pQuery->next;
|
|||
|
pQuery = pQuery->next ) {
|
|||
|
|
|||
|
if ( hThisQuery == pQuery->next->hThread ) {
|
|||
|
pQueryRemaining = pQuery;
|
|||
|
pQuery = pQuery->next;
|
|||
|
pQueryRemaining->next = pQuery->next;
|
|||
|
bFound = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
assert ( bFound );
|
|||
|
|
|||
|
if ( bFound ) {
|
|||
|
dwActiveSessionCount -= 1;
|
|||
|
}
|
|||
|
|
|||
|
UnlockQueryData();
|
|||
|
|
|||
|
assert ( NULL != pQuery );
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
{
|
|||
|
TCHAR szDebugString[MAX_PATH];
|
|||
|
swprintf (szDebugString, (LPCWSTR)L" Query %s: Query removed\n", pQuery->szQueryName);
|
|||
|
OutputDebugString (szDebugString);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if ( bFound ) {
|
|||
|
FreeQueryData( pQuery );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LONGLONG
|
|||
|
ComputeStartWaitTics(
|
|||
|
IN PLOG_QUERY_DATA pQuery,
|
|||
|
IN BOOL bWriteToRegistry
|
|||
|
)
|
|||
|
{
|
|||
|
LONGLONG llWaitTics = ((LONGLONG)0);
|
|||
|
LONGLONG llLocalDateTime;
|
|||
|
LONGLONG llRptLocalDays = 0;
|
|||
|
LONGLONG llRptStartTime = 0;
|
|||
|
LONGLONG llRptStopTime = 0;
|
|||
|
LONGLONG llRptLocalTime = 0;
|
|||
|
SLQ_TIME_INFO stiSched;
|
|||
|
|
|||
|
|
|||
|
// Compute time to wait before logging starts.
|
|||
|
//
|
|||
|
// Time returned is millisecond granularity.
|
|||
|
//
|
|||
|
// Return value:
|
|||
|
//
|
|||
|
// Start time minus Now when At time is in the future.
|
|||
|
//
|
|||
|
// 0 signals no wait. This is true when:
|
|||
|
// Start is either Manual or At mode and start time set to before now.
|
|||
|
// Exceptions for both of these cases are noted below.
|
|||
|
//
|
|||
|
// NULL_INTERVAL_TICS signals exit immediately. This is true when:
|
|||
|
// Start is Manual and Start time is MAX_TIME_VALUE
|
|||
|
// Stop is At mode and Stop time is past.
|
|||
|
// Stop is Manual mode and Stop time is MIN_TIME_VALUE or any value <= Now
|
|||
|
// Stop is After mode, After value is 0 (UI should protect against this).
|
|||
|
// Stop is After mode, Start is At mode, stop time is past and repeat mode is Manual.
|
|||
|
//
|
|||
|
|
|||
|
GetLocalFileTime (&llLocalDateTime);
|
|||
|
|
|||
|
if ( ( MAX_TIME_VALUE == pQuery->stiRegStart.llDateTime )
|
|||
|
&& ( SLQ_AUTO_MODE_NONE == pQuery->stiRegStart.dwAutoMode ) ) {
|
|||
|
// Manual Start, start time is MAX_TIME_VALUE
|
|||
|
// Note: For repeat funcionality, manual start time might be > now.
|
|||
|
// Need to keep the start mode Manual in this case to ensure that
|
|||
|
// SetStoppedStatus works.
|
|||
|
// Todo: Don't allow repeat or restart with Manual mode?
|
|||
|
llWaitTics = NULL_INTERVAL_TICS;
|
|||
|
} else if ( ( SLQ_AUTO_MODE_NONE == pQuery->stiRegStop.dwAutoMode )
|
|||
|
&& ( pQuery->stiRegStop.llDateTime <= llLocalDateTime ) ) {
|
|||
|
// Past Stop Manual time.
|
|||
|
llWaitTics = NULL_INTERVAL_TICS;
|
|||
|
} else if ( ( ( SLQ_AUTO_MODE_AT == pQuery->stiRegStop.dwAutoMode )
|
|||
|
&& ( SLQ_AUTO_MODE_CALENDAR != pQuery->stiRepeat.dwAutoMode ) )
|
|||
|
&& ( pQuery->stiRegStop.llDateTime <= llLocalDateTime ) ) {
|
|||
|
// Past Stop At or time and repeat mode not set to calendar.
|
|||
|
llWaitTics = NULL_INTERVAL_TICS;
|
|||
|
} else if ( SLQ_AUTO_MODE_AFTER == pQuery->stiRegStop.dwAutoMode ) {
|
|||
|
if ( 0 == pQuery->stiRegStop.dwValue ) {
|
|||
|
// Stop After mode and value is 0.
|
|||
|
llWaitTics = NULL_INTERVAL_TICS;
|
|||
|
} else if ( ( SLQ_AUTO_MODE_AT == pQuery->stiRegStart.dwAutoMode )
|
|||
|
&& ( SLQ_AUTO_MODE_NONE == pQuery->stiRepeat.dwAutoMode ) ) {
|
|||
|
LONGLONG llTics;
|
|||
|
|
|||
|
TimeInfoToTics ( &pQuery->stiRegStop, &llTics );
|
|||
|
|
|||
|
if ( ( pQuery->stiRegStart.llDateTime + llTics ) < llLocalDateTime ) {
|
|||
|
// Start at, Stop After modes, stop time is past and no restart.
|
|||
|
llWaitTics = NULL_INTERVAL_TICS;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// This code writes to local start and stop time structures to compute
|
|||
|
// start wait tics. This avoids excessive log stops and starts, since
|
|||
|
// the original registry data structures are compared when the registry
|
|||
|
// has been modified, to determine if a log config has been changed by the UI.
|
|||
|
if ( NULL_INTERVAL_TICS != llWaitTics ) {
|
|||
|
|
|||
|
pQuery->stiCurrentStart = pQuery->stiRegStart;
|
|||
|
pQuery->stiCurrentStop = pQuery->stiRegStop;
|
|||
|
|
|||
|
// Handle repeat option separately.
|
|||
|
if ( SLQ_AUTO_MODE_CALENDAR == pQuery->stiRepeat.dwAutoMode ) {
|
|||
|
|
|||
|
assert ( SLQ_AUTO_MODE_AT == pQuery->stiCurrentStart.dwAutoMode );
|
|||
|
assert ( SLQ_AUTO_MODE_AT == pQuery->stiCurrentStop.dwAutoMode );
|
|||
|
// assert ( ( pQuery->stiCurrentStop.llDateTime - pQuery->stiCurrentStart.llDateTime )
|
|||
|
// < (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) );
|
|||
|
|
|||
|
if ( pQuery->stiCurrentStop.llDateTime <= llLocalDateTime ) {
|
|||
|
|
|||
|
llRptLocalDays = llLocalDateTime / (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY);
|
|||
|
llRptLocalTime = llLocalDateTime - llRptLocalDays;
|
|||
|
|
|||
|
llRptStopTime = pQuery->stiCurrentStop.llDateTime
|
|||
|
- ( pQuery->stiCurrentStop.llDateTime
|
|||
|
/ (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) );
|
|||
|
|
|||
|
pQuery->stiCurrentStop.llDateTime = llRptLocalDays + llRptStopTime;
|
|||
|
if ( llRptStopTime < llRptLocalTime ) {
|
|||
|
// Set to stop tomorrow.
|
|||
|
pQuery->stiCurrentStop.llDateTime += (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) ;
|
|||
|
}
|
|||
|
|
|||
|
llRptStartTime = pQuery->stiCurrentStart.llDateTime
|
|||
|
- ( pQuery->stiCurrentStart.llDateTime
|
|||
|
/ (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) );
|
|||
|
|
|||
|
pQuery->stiCurrentStart.llDateTime = llRptLocalDays + llRptStartTime;
|
|||
|
|
|||
|
if ( (pQuery->stiCurrentStop.llDateTime - pQuery->stiCurrentStart.llDateTime)
|
|||
|
> (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) ) {
|
|||
|
// Set to start tomorrow.
|
|||
|
pQuery->stiCurrentStart.llDateTime += (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( bWriteToRegistry ) {
|
|||
|
stiSched.wDataType = SLQ_TT_DTYPE_DATETIME;
|
|||
|
stiSched.wTimeType = SLQ_TT_TTYPE_REPEAT_START;
|
|||
|
stiSched.dwAutoMode = SLQ_AUTO_MODE_AT;
|
|||
|
stiSched.llDateTime = pQuery->stiCurrentStart.llDateTime;
|
|||
|
|
|||
|
WriteRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
(LPCWSTR)L"Repeat Schedule Start",
|
|||
|
&stiSched );
|
|||
|
|
|||
|
stiSched.wTimeType = SLQ_TT_TTYPE_REPEAT_STOP;
|
|||
|
stiSched.dwAutoMode = SLQ_AUTO_MODE_AT;
|
|||
|
stiSched.llDateTime = pQuery->stiCurrentStop.llDateTime;
|
|||
|
|
|||
|
WriteRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
(LPCWSTR)L"Repeat Schedule Stop",
|
|||
|
&stiSched );
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( pQuery->stiCurrentStart.llDateTime <= llLocalDateTime ) {
|
|||
|
llWaitTics = ((LONGLONG)(0));
|
|||
|
} else {
|
|||
|
llWaitTics = pQuery->stiCurrentStart.llDateTime - llLocalDateTime;
|
|||
|
}
|
|||
|
|
|||
|
// If manual mode, set the start time to now, to handle repeat schedule.
|
|||
|
// If any thread other than the log thread accesses this field for a
|
|||
|
// running query, then need to synchronize access to the field.
|
|||
|
if( SLQ_AUTO_MODE_NONE == pQuery->stiCurrentStart.dwAutoMode
|
|||
|
&& MIN_TIME_VALUE == pQuery->stiCurrentStart.llDateTime )
|
|||
|
{
|
|||
|
pQuery->stiCurrentStart.llDateTime = llLocalDateTime + llWaitTics;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return llWaitTics;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LoadDefaultLogFileFolder ( void )
|
|||
|
{
|
|||
|
HKEY hKeyLogService = NULL;
|
|||
|
TCHAR szLocalPath[MAX_PATH+1] = TEXT("");
|
|||
|
DWORD cchExpandedLen;
|
|||
|
DWORD dwStatus;
|
|||
|
|
|||
|
dwStatus = RegOpenKeyEx (
|
|||
|
(HKEY)HKEY_LOCAL_MACHINE,
|
|||
|
(LPCTSTR)TEXT("SYSTEM\\CurrentControlSet\\Services\\SysmonLog"),
|
|||
|
0L,
|
|||
|
KEY_READ,
|
|||
|
(PHKEY)&hKeyLogService);
|
|||
|
|
|||
|
// update the service status
|
|||
|
ssSmLogStatus.dwCheckPoint++;
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
DWORD dwBufferSize = sizeof ( szLocalPath );
|
|||
|
|
|||
|
dwStatus = RegQueryValueExW (
|
|||
|
hKeyLogService,
|
|||
|
(LPCTSTR)L"DefaultLogFileFolder",
|
|||
|
NULL,
|
|||
|
0L,
|
|||
|
(LPBYTE)szLocalPath,
|
|||
|
&dwBufferSize);
|
|||
|
|
|||
|
RegCloseKey (hKeyLogService);
|
|||
|
|
|||
|
} // No message on error. Just use load the local default.
|
|||
|
|
|||
|
if ( 0 == lstrlen (szLocalPath ) ) {
|
|||
|
lstrcpy ( szLocalPath, DEFAULT_LOG_FILE_FOLDER );
|
|||
|
}
|
|||
|
|
|||
|
// Todo: local and global buffer sizes are fixed.
|
|||
|
|
|||
|
cchExpandedLen = ExpandEnvironmentStrings (
|
|||
|
szLocalPath,
|
|||
|
gszDefaultLogFileFolder,
|
|||
|
MAX_PATH+1 );
|
|||
|
|
|||
|
if ( 0 == cchExpandedLen ) {
|
|||
|
gszDefaultLogFileFolder[0] = L'\0';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ProcessLogFileFolder (
|
|||
|
IN PLOG_QUERY_DATA pQuery,
|
|||
|
IN BOOL bReconfigure )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
TCHAR szLocalPath [MAX_PATH];
|
|||
|
|
|||
|
szLocalPath[0] = _T('\0');
|
|||
|
|
|||
|
if (GetFullPathName (
|
|||
|
pQuery->szLogFileFolder,
|
|||
|
MAX_PATH,
|
|||
|
szLocalPath,
|
|||
|
NULL) > 0) {
|
|||
|
|
|||
|
LPTSTR szEnd;
|
|||
|
LPSECURITY_ATTRIBUTES lpSA = NULL;
|
|||
|
TCHAR cBackslash = TEXT('\\');
|
|||
|
szEnd = &szLocalPath[3];
|
|||
|
|
|||
|
if (*szEnd != 0) {
|
|||
|
LONG lErrorMode;
|
|||
|
|
|||
|
lErrorMode = SetErrorMode ( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
|
|||
|
|
|||
|
// then there are sub dirs to create
|
|||
|
while (*szEnd != 0) {
|
|||
|
// go to next backslash
|
|||
|
while ((*szEnd != cBackslash) && (*szEnd != 0)) szEnd++;
|
|||
|
if (*szEnd == cBackslash) {
|
|||
|
// terminate path here and create directory
|
|||
|
*szEnd = 0;
|
|||
|
if (!CreateDirectory (szLocalPath, lpSA)) {
|
|||
|
// see what the error was and "adjust" it if necessary
|
|||
|
dwStatus = GetLastError();
|
|||
|
if ( ERROR_ALREADY_EXISTS == dwStatus ) {
|
|||
|
// this is OK
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
// replace backslash and go to next dir
|
|||
|
*szEnd++ = cBackslash;
|
|||
|
}
|
|||
|
}
|
|||
|
// create last dir in path now
|
|||
|
if (!CreateDirectory (szLocalPath, lpSA)) {
|
|||
|
// see what the error was and "adjust" it if necessary
|
|||
|
dwStatus = GetLastError();
|
|||
|
if ( ERROR_ALREADY_EXISTS == dwStatus ) {
|
|||
|
// this is OK
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SetErrorMode ( lErrorMode );
|
|||
|
} else {
|
|||
|
// Root directory is ok.
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
// Report event on error
|
|||
|
if ( ERROR_SUCCESS != dwStatus ) {
|
|||
|
DWORD dwMessageId;
|
|||
|
LPCWSTR szStringArray[3];
|
|||
|
|
|||
|
szStringArray[0] = pQuery->szLogFileFolder;
|
|||
|
szStringArray[1] = pQuery->szQueryName;
|
|||
|
szStringArray[2] = FormatEventLogMessage(dwStatus);
|
|||
|
|
|||
|
if ( bReconfigure ) {
|
|||
|
dwMessageId = SMLOG_INVALID_LOG_FOLDER_STOP;
|
|||
|
} else {
|
|||
|
dwMessageId = SMLOG_INVALID_LOG_FOLDER_START;
|
|||
|
}
|
|||
|
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
dwMessageId,
|
|||
|
NULL,
|
|||
|
3,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
OpenLogQueriesKey (
|
|||
|
REGSAM regsamAccess,
|
|||
|
PHKEY phKeyLogQueries )
|
|||
|
{
|
|||
|
|
|||
|
DWORD dwStatus;
|
|||
|
|
|||
|
dwStatus = RegOpenKeyEx (
|
|||
|
(HKEY)HKEY_LOCAL_MACHINE,
|
|||
|
(LPCTSTR)TEXT("SYSTEM\\CurrentControlSet\\Services\\SysmonLog\\Log Queries"),
|
|||
|
0L,
|
|||
|
regsamAccess,
|
|||
|
phKeyLogQueries);
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ClearQueryRunStates ( void )
|
|||
|
{
|
|||
|
|
|||
|
DWORD dwStatus;
|
|||
|
HKEY hKeyLogQueries = NULL;
|
|||
|
HKEY hKeyThisLogQuery = NULL;
|
|||
|
DWORD dwQueryIndex;
|
|||
|
TCHAR szQueryNameBuffer[MAX_PATH+1];
|
|||
|
DWORD dwQueryNameBufferSize;
|
|||
|
TCHAR szQueryClassBuffer[MAX_PATH+1];
|
|||
|
DWORD dwQueryClassBufferSize;
|
|||
|
LPTSTR szCollectionName = NULL;
|
|||
|
UINT uiCollectionNameLen = 0;
|
|||
|
LPTSTR szStringArray[2];
|
|||
|
DWORD dwCurrentState;
|
|||
|
DWORD dwDefault;
|
|||
|
DWORD dwLogType;
|
|||
|
|
|||
|
// For every query in the registry, if the state is SLQ_QUERY_RUNNING,
|
|||
|
// set it to SLQ_QUERY_STOPPED.
|
|||
|
//
|
|||
|
// This method must be called before starting the query threads.
|
|||
|
//
|
|||
|
// Only the service sets the state to SLQ_QUERY_RUNNING, so there is no
|
|||
|
// race condition.
|
|||
|
|
|||
|
// Open (each) query in the registry
|
|||
|
|
|||
|
dwStatus = OpenLogQueriesKey (
|
|||
|
KEY_READ | KEY_SET_VALUE,
|
|||
|
(PHKEY)&hKeyLogQueries);
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
if (dwStatus == ERROR_FILE_NOT_FOUND) {
|
|||
|
// there is no logs nor alerts setting, bail out quietly
|
|||
|
//
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
else {
|
|||
|
// unable to read the log query information from the registry
|
|||
|
dwStatus = GetLastError();
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_OPEN_LOG_QUERY,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
dwStatus = SMLOG_UNABLE_OPEN_LOG_QUERY;
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
dwQueryIndex = 0;
|
|||
|
*szQueryNameBuffer = 0;
|
|||
|
dwQueryNameBufferSize = MAX_PATH+1;
|
|||
|
*szQueryClassBuffer = 0;
|
|||
|
dwQueryClassBufferSize = MAX_PATH+1;
|
|||
|
|
|||
|
while ((dwStatus = RegEnumKeyEx (
|
|||
|
hKeyLogQueries,
|
|||
|
dwQueryIndex,
|
|||
|
szQueryNameBuffer,
|
|||
|
&dwQueryNameBufferSize,
|
|||
|
NULL,
|
|||
|
szQueryClassBuffer,
|
|||
|
&dwQueryClassBufferSize,
|
|||
|
NULL)) != ERROR_NO_MORE_ITEMS) {
|
|||
|
|
|||
|
// open this key
|
|||
|
dwStatus = RegOpenKeyEx (
|
|||
|
hKeyLogQueries,
|
|||
|
szQueryNameBuffer,
|
|||
|
0L,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
(PHKEY)&hKeyThisLogQuery);
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
szStringArray[0] = szQueryNameBuffer;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_LOG_QUERY,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
// skip to next item
|
|||
|
goto CONTINUE_ENUM_LOOP;
|
|||
|
}
|
|||
|
|
|||
|
// update the service status
|
|||
|
ssSmLogStatus.dwCheckPoint++;
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
|
|||
|
dwStatus = SmReadRegistryIndirectStringValue (
|
|||
|
hKeyThisLogQuery,
|
|||
|
L"Collection Name",
|
|||
|
NULL,
|
|||
|
&szCollectionName,
|
|||
|
&uiCollectionNameLen );
|
|||
|
|
|||
|
if ( NULL != szCollectionName ) {
|
|||
|
if ( 0 < lstrlen ( szCollectionName ) ) {
|
|||
|
lstrcpyn (
|
|||
|
szQueryNameBuffer,
|
|||
|
szCollectionName,
|
|||
|
min(MAX_PATH, lstrlen(szCollectionName)+1 ) );
|
|||
|
}
|
|||
|
|
|||
|
G_FREE ( szCollectionName );
|
|||
|
szCollectionName = NULL;
|
|||
|
uiCollectionNameLen = 0;
|
|||
|
}
|
|||
|
|
|||
|
dwDefault = ((DWORD)-1);
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
hKeyThisLogQuery,
|
|||
|
szQueryNameBuffer,
|
|||
|
(LPCTSTR)L"Log Type",
|
|||
|
&dwDefault,
|
|||
|
&dwLogType );
|
|||
|
|
|||
|
if ( ( SLQ_COUNTER_LOG == dwLogType )
|
|||
|
|| ( SLQ_TRACE_LOG == dwLogType )
|
|||
|
|| ( SLQ_ALERT == dwLogType ) ) {
|
|||
|
|
|||
|
// Check the current state of the query. If it is SLQ_QUERY_RUNNING,
|
|||
|
// set it to SLQ_QUERY_STOPPED. If, in addition, the Start mode is
|
|||
|
// manual, set the start time to MAX, so that the query doesn't
|
|||
|
// start automatically.
|
|||
|
|
|||
|
// If the current state is SLQ_QUERY_START_PENDING, it is assumed to be a new
|
|||
|
// request, so leave the registry as is.
|
|||
|
//
|
|||
|
|
|||
|
// Note: For trace logs, this code only coordinates between trace log
|
|||
|
// configs that are stored in the registry.
|
|||
|
|
|||
|
dwDefault = SLQ_QUERY_STOPPED;
|
|||
|
dwStatus = ReadRegistryDwordValue (
|
|||
|
hKeyThisLogQuery,
|
|||
|
szQueryNameBuffer,
|
|||
|
(LPCTSTR)L"Current State",
|
|||
|
&dwDefault,
|
|||
|
&dwCurrentState );
|
|||
|
assert (dwStatus == ERROR_SUCCESS);
|
|||
|
// Status always success if default provided.
|
|||
|
|
|||
|
// If query is in START_PENDING or STOPPED state, then
|
|||
|
// the registry contents are correct. If it is in
|
|||
|
// RUNNING state, then the service was stopped before
|
|||
|
// it could clean up the registry state.
|
|||
|
if ( SLQ_QUERY_RUNNING == dwCurrentState ) {
|
|||
|
SLQ_TIME_INFO stiDefault;
|
|||
|
SLQ_TIME_INFO stiActual;
|
|||
|
LONGLONG ftLocalTime;
|
|||
|
|
|||
|
dwCurrentState = SLQ_QUERY_STOPPED;
|
|||
|
dwStatus = WriteRegistryDwordValue (
|
|||
|
hKeyThisLogQuery,
|
|||
|
(LPCTSTR)L"Current State",
|
|||
|
&dwCurrentState,
|
|||
|
REG_DWORD );
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
szStringArray[0] = szQueryNameBuffer;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_WRITE_STOP_STATE,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
// skip to next item
|
|||
|
goto CONTINUE_ENUM_LOOP;
|
|||
|
}
|
|||
|
|
|||
|
// If Start is manual mode, set start time to MAX, to signal
|
|||
|
// not started.
|
|||
|
GetLocalFileTime ( &ftLocalTime );
|
|||
|
|
|||
|
stiDefault.wTimeType = SLQ_TT_TTYPE_START;
|
|||
|
stiDefault.dwAutoMode = SLQ_AUTO_MODE_AT;
|
|||
|
stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
|
|||
|
stiDefault.llDateTime = *(LONGLONG *)&ftLocalTime;
|
|||
|
|
|||
|
dwStatus = ReadRegistrySlqTime (
|
|||
|
hKeyThisLogQuery,
|
|||
|
szQueryNameBuffer,
|
|||
|
(LPCTSTR)L"Start",
|
|||
|
&stiDefault,
|
|||
|
&stiActual );
|
|||
|
|
|||
|
assert (dwStatus == ERROR_SUCCESS);
|
|||
|
// Status always success if default provided.
|
|||
|
|
|||
|
if ( ( SLQ_AUTO_MODE_NONE == stiActual.dwAutoMode )
|
|||
|
&& ( MAX_TIME_VALUE != stiActual.llDateTime ) ) {
|
|||
|
|
|||
|
stiActual.llDateTime = MAX_TIME_VALUE;
|
|||
|
dwStatus = WriteRegistrySlqTime (
|
|||
|
hKeyThisLogQuery,
|
|||
|
(LPCTSTR)L"Start",
|
|||
|
&stiActual);
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
szStringArray[0] = szQueryNameBuffer;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_RESET_START_TIME,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
// skip to next item
|
|||
|
goto CONTINUE_ENUM_LOOP;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// If Stop is manual mode, set stop time to MIN, to signal
|
|||
|
// not started.
|
|||
|
GetLocalFileTime ( &ftLocalTime );
|
|||
|
|
|||
|
stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
|
|||
|
stiDefault.wTimeType = SLQ_TT_TTYPE_STOP;
|
|||
|
stiDefault.dwAutoMode = SLQ_AUTO_MODE_NONE;
|
|||
|
stiDefault.llDateTime = MIN_TIME_VALUE;
|
|||
|
|
|||
|
dwStatus = ReadRegistrySlqTime (
|
|||
|
hKeyThisLogQuery,
|
|||
|
szQueryNameBuffer,
|
|||
|
(LPCTSTR)L"Stop",
|
|||
|
&stiDefault,
|
|||
|
&stiActual );
|
|||
|
|
|||
|
assert (dwStatus == ERROR_SUCCESS);
|
|||
|
// Status always success if default provided.
|
|||
|
|
|||
|
if ( ( SLQ_AUTO_MODE_NONE == stiActual.dwAutoMode )
|
|||
|
&& ( MIN_TIME_VALUE != stiActual.llDateTime ) ) {
|
|||
|
|
|||
|
stiActual.llDateTime = MIN_TIME_VALUE;
|
|||
|
dwStatus = WriteRegistrySlqTime (
|
|||
|
hKeyThisLogQuery,
|
|||
|
(LPCTSTR)L"Stop",
|
|||
|
&stiActual);
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
szStringArray[0] = szQueryNameBuffer;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_RESET_STOP_TIME,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
// skip to next item
|
|||
|
goto CONTINUE_ENUM_LOOP;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} // Ignore invalid log types when clearing status.
|
|||
|
|
|||
|
CONTINUE_ENUM_LOOP:
|
|||
|
if ( NULL != hKeyThisLogQuery )
|
|||
|
RegCloseKey (hKeyThisLogQuery);
|
|||
|
hKeyThisLogQuery = NULL;
|
|||
|
// prepare for next loop
|
|||
|
dwQueryIndex++;
|
|||
|
*szQueryNameBuffer = 0;
|
|||
|
dwQueryNameBufferSize = MAX_PATH+1;
|
|||
|
*szQueryClassBuffer = 0;
|
|||
|
dwQueryClassBufferSize = MAX_PATH+1;
|
|||
|
} // end enumeration of log queries
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != hKeyLogQueries ) {
|
|||
|
RegCloseKey (hKeyLogQueries);
|
|||
|
}
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
TraceStopRestartFieldsMatch (
|
|||
|
IN PLOG_QUERY_DATA pOrigQuery,
|
|||
|
IN PLOG_QUERY_DATA pNewQuery )
|
|||
|
{
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
// These are fields for which trace logging must
|
|||
|
// be stopped and restarted in order to reconfigure.
|
|||
|
BOOL bRequested;
|
|||
|
BOOL bCurrent;
|
|||
|
ULONG ulGuidCount = 0;
|
|||
|
ULONG ulGuidIndex = 0;
|
|||
|
TCHAR* pszThisGuid = NULL;
|
|||
|
|
|||
|
assert ( SLQ_TRACE_LOG == pOrigQuery->dwLogType );
|
|||
|
assert ( SLQ_TRACE_LOG == pNewQuery->dwLogType );
|
|||
|
|
|||
|
if ( !CommonFieldsMatch ( pOrigQuery, pNewQuery ) )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pOrigQuery->stiCreateNewFile.dwAutoMode != pNewQuery->stiCreateNewFile.dwAutoMode ) {
|
|||
|
return FALSE;
|
|||
|
} else {
|
|||
|
if ( ( SLQ_AUTO_MODE_AFTER == pOrigQuery->stiCreateNewFile.dwAutoMode )
|
|||
|
&& ( pOrigQuery->stiCreateNewFile.llDateTime != pNewQuery->stiCreateNewFile.llDateTime ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Compare new query fields against the existing properties structure.
|
|||
|
// Compare everything but flush interval, max buffer count and file name.
|
|||
|
if ( pOrigQuery->Properties.BufferSize != pNewQuery->dwBufferSize )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pOrigQuery->Properties.MinimumBuffers != pNewQuery->dwBufferMinCount )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
// Not kernel trace, so check query name
|
|||
|
if ((BOOL)( 0 == ( pNewQuery->dwFlags & SLQ_TLI_ENABLE_KERNEL_TRACE ) ) ) {
|
|||
|
if ( 0 != lstrcmpi ( pOrigQuery->szLoggerName, pNewQuery->szQueryName ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bRequested = (BOOL)( 0 != ( pNewQuery->dwFlags & SLQ_TLI_ENABLE_KERNEL_TRACE ) );
|
|||
|
bCurrent = IsEqualGUID( &pOrigQuery->Properties.Wnode.Guid, &SystemTraceControlGuid );
|
|||
|
|
|||
|
if ( bRequested != bCurrent ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// Extended memory trace
|
|||
|
|
|||
|
bRequested = (BOOL)( 0 != ( pNewQuery->dwFlags & SLQ_TLI_ENABLE_MEMMAN_TRACE ) );
|
|||
|
bCurrent = (BOOL)( 0 != ( pOrigQuery->Properties.EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS ) );
|
|||
|
|
|||
|
if ( bRequested != bCurrent ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// Extended I/O trace
|
|||
|
|
|||
|
bRequested = (BOOL)( 0 != ( pNewQuery->dwFlags & SLQ_TLI_ENABLE_FILEIO_TRACE ) );
|
|||
|
bCurrent = (BOOL)( 0 != ( pOrigQuery->Properties.EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO ) );
|
|||
|
|
|||
|
if ( bRequested != bCurrent ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if ( -1 == pNewQuery->dwMaxFileSize ) {
|
|||
|
if ( 0 != pOrigQuery->Properties.MaximumFileSize ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
} else if ( pOrigQuery->Properties.MaximumFileSize != pNewQuery->dwMaxFileSize ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if ( ( SLF_SEQ_TRACE_FILE == pNewQuery->dwLogFileType )
|
|||
|
&& ( EVENT_TRACE_FILE_MODE_SEQUENTIAL != pOrigQuery->Properties.LogFileMode ) ) {
|
|||
|
return FALSE;
|
|||
|
} else if ( ( SLF_CIRC_TRACE_FILE == pNewQuery->dwLogFileType )
|
|||
|
&& ( EVENT_TRACE_FILE_MODE_CIRCULAR != pOrigQuery->Properties.LogFileMode ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// Compare each provider string against array element.
|
|||
|
for (pszThisGuid = pNewQuery->mszProviderList;
|
|||
|
*pszThisGuid != 0;
|
|||
|
pszThisGuid += lstrlen(pszThisGuid) + 1) {
|
|||
|
ulGuidCount += 1;
|
|||
|
}
|
|||
|
|
|||
|
if ( pOrigQuery->ulGuidCount != ulGuidCount )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
ulGuidIndex = 0;
|
|||
|
for (pszThisGuid = pNewQuery->mszProviderList;
|
|||
|
*pszThisGuid != 0;
|
|||
|
pszThisGuid += lstrlen(pszThisGuid) + 1) {
|
|||
|
|
|||
|
if ( 0 != lstrcmpi ( pOrigQuery->arrpszProviderName[ulGuidIndex], pszThisGuid ) )
|
|||
|
return FALSE;
|
|||
|
ulGuidIndex++;
|
|||
|
assert ( ulGuidIndex <= ulGuidCount );
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
#else
|
|||
|
return FALSE;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
AlertFieldsMatch (
|
|||
|
IN PLOG_QUERY_DATA pFirstQuery,
|
|||
|
IN PLOG_QUERY_DATA pSecondQuery )
|
|||
|
{
|
|||
|
if ( pFirstQuery->dwAlertActionFlags != pSecondQuery->dwAlertActionFlags )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( 0 != (pFirstQuery->dwAlertActionFlags & ALRT_ACTION_SEND_MSG) ) {
|
|||
|
if ( 0 != lstrcmpi ( pFirstQuery->szNetName, pSecondQuery->szNetName ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( 0 != (pFirstQuery->dwAlertActionFlags & ALRT_ACTION_EXEC_CMD) ) {
|
|||
|
if ( 0 != lstrcmpi ( pFirstQuery->szCmdFileName, pSecondQuery->szCmdFileName ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if ( 0 != (pFirstQuery->dwAlertActionFlags & ALRT_CMD_LINE_U_TEXT ) ) {
|
|||
|
if ( 0 != lstrcmpi ( pFirstQuery->szUserText, pSecondQuery->szUserText ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( 0 != (pFirstQuery->dwAlertActionFlags & ALRT_ACTION_START_LOG) ) {
|
|||
|
if ( 0 != lstrcmpi ( pFirstQuery->szPerfLogName, pSecondQuery->szPerfLogName ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
CommonFieldsMatch (
|
|||
|
IN PLOG_QUERY_DATA pFirstQuery,
|
|||
|
IN PLOG_QUERY_DATA pSecondQuery )
|
|||
|
{
|
|||
|
if ( pFirstQuery->dwCurrentState != pSecondQuery->dwCurrentState )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwLogFileType != pSecondQuery->dwLogFileType )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwAutoNameFormat != pSecondQuery->dwAutoNameFormat )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwMaxFileSize != pSecondQuery->dwMaxFileSize )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->stiRegStart.dwAutoMode != pSecondQuery->stiRegStart.dwAutoMode )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->stiRegStop.dwAutoMode != pSecondQuery->stiRegStop.dwAutoMode )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->stiRepeat.dwAutoMode != pSecondQuery->stiRepeat.dwAutoMode )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->stiRegStart.llDateTime != pSecondQuery->stiRegStart.llDateTime )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->stiRegStop.llDateTime != pSecondQuery->stiRegStop.llDateTime )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->stiRepeat.llDateTime != pSecondQuery->stiRepeat.llDateTime )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if (( SLQ_COUNTER_LOG == pFirstQuery->dwLogType ) ||
|
|||
|
( SLQ_TRACE_LOG == pFirstQuery->dwLogType)) {
|
|||
|
|
|||
|
if ( 0 != lstrcmpi ( pFirstQuery->szBaseFileName, pSecondQuery->szBaseFileName ) )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( 0 != lstrcmpi ( pFirstQuery->szLogFileFolder, pSecondQuery->szLogFileFolder ) )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( 0 != lstrcmpi ( pFirstQuery->szSqlLogName, pSecondQuery->szSqlLogName ) )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( 0 != lstrcmpi ( pFirstQuery->szLogFileComment, pSecondQuery->szLogFileComment ) )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwCurrentSerialNumber != pSecondQuery->dwCurrentSerialNumber )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwLogFileSizeUnit != pSecondQuery->dwLogFileSizeUnit )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwAppendMode != pSecondQuery->dwAppendMode )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->stiCreateNewFile.dwAutoMode != pSecondQuery->stiCreateNewFile.dwAutoMode )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->stiCreateNewFile.llDateTime != pSecondQuery->stiCreateNewFile.llDateTime )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( 0 != lstrcmpi(pFirstQuery->szCmdFileName, pSecondQuery->szCmdFileName ) )
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (( SLQ_COUNTER_LOG == pFirstQuery->dwLogType ) ||
|
|||
|
( SLQ_ALERT == pFirstQuery->dwLogType)) {
|
|||
|
|
|||
|
LPTSTR szFirstPath;
|
|||
|
LPTSTR szSecondPath;
|
|||
|
|
|||
|
if ( pFirstQuery->dwMillisecondSampleInterval != pSecondQuery->dwMillisecondSampleInterval ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// Compare each counter string. Note: If counter order has changed, the query is
|
|||
|
// reconfigured.
|
|||
|
// For Alert queries, this code also checks the limit threshold logic and value.
|
|||
|
szSecondPath = pSecondQuery->mszCounterList;
|
|||
|
for ( szFirstPath = pFirstQuery->mszCounterList;
|
|||
|
*szFirstPath != 0;
|
|||
|
szFirstPath += lstrlen(szFirstPath) + 1) {
|
|||
|
|
|||
|
if ( 0 != lstrcmpi( szFirstPath, szSecondPath ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
szSecondPath += lstrlen(szSecondPath) + 1;
|
|||
|
}
|
|||
|
|
|||
|
if ( 0 != *szSecondPath ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
FieldsMatch (
|
|||
|
IN PLOG_QUERY_DATA pFirstQuery,
|
|||
|
IN PLOG_QUERY_DATA pSecondQuery )
|
|||
|
{
|
|||
|
assert ( pFirstQuery->dwLogType == pSecondQuery->dwLogType );
|
|||
|
|
|||
|
if ( !CommonFieldsMatch ( pFirstQuery, pSecondQuery ) )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( SLQ_ALERT == pFirstQuery->dwLogType ) {
|
|||
|
if ( !AlertFieldsMatch( pFirstQuery, pSecondQuery ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
} else if ( SLQ_TRACE_LOG == pFirstQuery->dwLogType ) {
|
|||
|
LPTSTR szFirstProv;
|
|||
|
LPTSTR szSecondProv;
|
|||
|
|
|||
|
if ( pFirstQuery->dwBufferSize != pSecondQuery->dwBufferSize )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwBufferMinCount != pSecondQuery->dwBufferMinCount )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwBufferMaxCount != pSecondQuery->dwBufferMaxCount )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwBufferFlushInterval != pSecondQuery->dwBufferFlushInterval )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if ( pFirstQuery->dwFlags != pSecondQuery->dwFlags )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
szSecondProv = pSecondQuery->mszProviderList;
|
|||
|
|
|||
|
for ( szFirstProv = pFirstQuery->mszProviderList;
|
|||
|
*szFirstProv != 0;
|
|||
|
szFirstProv += lstrlen(szFirstProv) + 1) {
|
|||
|
|
|||
|
|
|||
|
if ( 0 != lstrcmpi ( szFirstProv, szSecondProv ) )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
szSecondProv += lstrlen(szSecondProv) + 1;
|
|||
|
}
|
|||
|
|
|||
|
if ( 0 != *szSecondProv) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
} else if ( SLQ_COUNTER_LOG == pFirstQuery->dwLogType ) {
|
|||
|
if ( pFirstQuery->stiCreateNewFile.dwAutoMode != pSecondQuery->stiCreateNewFile.dwAutoMode ) {
|
|||
|
return FALSE;
|
|||
|
} else {
|
|||
|
if ( SLQ_AUTO_MODE_AFTER == pFirstQuery->stiCreateNewFile.dwAutoMode
|
|||
|
&& pFirstQuery->stiCreateNewFile.llDateTime != pSecondQuery->stiCreateNewFile.llDateTime ) {
|
|||
|
return FALSE;
|
|||
|
} // else change in max size handled in commmon fields match check.
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
IsModified (
|
|||
|
IN PLOG_QUERY_DATA pQuery,
|
|||
|
OUT BOOL* pbModified
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD dwStatus;
|
|||
|
SLQ_TIME_INFO stiLastModified;
|
|||
|
SLQ_TIME_INFO stiDefault;
|
|||
|
|
|||
|
*pbModified = TRUE;
|
|||
|
|
|||
|
// Check the last read date against 'last modified' in
|
|||
|
// the registry.
|
|||
|
// If it is earlier than the registry, and the data in the
|
|||
|
// registry has changed, return TRUE.
|
|||
|
//
|
|||
|
// The check of thread data against registry data reduces the
|
|||
|
// number of times that the logging thread is interrupted.
|
|||
|
// This is necessary because each property page OnApply
|
|||
|
// generates this check.
|
|||
|
//
|
|||
|
stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
|
|||
|
stiDefault.wTimeType = SLQ_TT_TTYPE_LAST_MODIFIED;
|
|||
|
stiDefault.dwAutoMode = SLQ_AUTO_MODE_AT;
|
|||
|
stiDefault.llDateTime = MAX_TIME_VALUE;
|
|||
|
|
|||
|
dwStatus = ReadRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
pQuery->szQueryName,
|
|||
|
(LPCTSTR)L"Last Modified",
|
|||
|
&stiDefault,
|
|||
|
&stiLastModified );
|
|||
|
|
|||
|
assert( ERROR_SUCCESS == dwStatus );
|
|||
|
// Status always success if default provided.
|
|||
|
|
|||
|
if ( stiLastModified.llDateTime <= pQuery->llLastConfigured ) {
|
|||
|
*pbModified = FALSE;
|
|||
|
} else {
|
|||
|
LOG_QUERY_DATA TempQuery;
|
|||
|
|
|||
|
memset (&TempQuery, 0, sizeof(TempQuery));
|
|||
|
lstrcpy (TempQuery.szQueryName, pQuery->szQueryName);
|
|||
|
TempQuery.hKeyQuery = pQuery->hKeyQuery;
|
|||
|
|
|||
|
if ( ERROR_SUCCESS != LoadQueryConfig( &TempQuery ) ) {
|
|||
|
// Event has been logged. Set mod flag to stop the query.
|
|||
|
*pbModified = TRUE;
|
|||
|
} else {
|
|||
|
*pbModified = !FieldsMatch ( pQuery, &TempQuery );
|
|||
|
}
|
|||
|
|
|||
|
// Delete memory allocated by registry data load.
|
|||
|
DeallocateQueryBuffers ( &TempQuery );
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ReconfigureQuery (
|
|||
|
IN PLOG_QUERY_DATA pQuery )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
|
|||
|
|
|||
|
// *** Optimization - perform this check within IsModified, to avoid extra
|
|||
|
// load from the registry.
|
|||
|
LOG_QUERY_DATA TempQuery;
|
|||
|
BOOL bStopQuery = FALSE;
|
|||
|
|
|||
|
memset (&TempQuery, 0, sizeof(TempQuery));
|
|||
|
lstrcpy (TempQuery.szQueryName, pQuery->szQueryName);
|
|||
|
TempQuery.hKeyQuery = pQuery->hKeyQuery;
|
|||
|
|
|||
|
if ( ERROR_SUCCESS != LoadQueryConfig( &TempQuery ) ) {
|
|||
|
// Event has been logged. Stop the query.
|
|||
|
bStopQuery = TRUE;
|
|||
|
} else {
|
|||
|
bStopQuery = ( NULL_INTERVAL_TICS == ComputeStartWaitTics ( &TempQuery, FALSE ) );
|
|||
|
}
|
|||
|
|
|||
|
if ( !bStopQuery ) {
|
|||
|
if ( SLQ_TRACE_LOG == pQuery->dwLogType
|
|||
|
|| SLQ_COUNTER_LOG == pQuery->dwLogType ) {
|
|||
|
// Stop the query if new log file folder is not valid.
|
|||
|
bStopQuery = ( ERROR_SUCCESS != ProcessLogFileFolder( &TempQuery, TRUE ) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( bStopQuery ) {
|
|||
|
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
{
|
|||
|
TCHAR szDebugString[MAX_PATH];
|
|||
|
swprintf (szDebugString, (LPCWSTR)L" Query %s: Set exit event\n", pQuery->szQueryName);
|
|||
|
OutputDebugString (szDebugString);
|
|||
|
}
|
|||
|
#endif
|
|||
|
SetEvent (pQuery->hExitEvent);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (( SLQ_COUNTER_LOG == pQuery->dwLogType ) ||
|
|||
|
( SLQ_ALERT == pQuery->dwLogType ) ){
|
|||
|
// Signal the logging thread to reconfigure.
|
|||
|
pQuery->bLoadNewConfig= TRUE;
|
|||
|
SetEvent (pQuery->hReconfigEvent);
|
|||
|
} else {
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
BOOL bMustStopRestart;
|
|||
|
|
|||
|
assert( SLQ_TRACE_LOG == pQuery->dwLogType );
|
|||
|
|
|||
|
//
|
|||
|
// Change the current query. For some properties, this
|
|||
|
// means stopping then restarting the query.
|
|||
|
//
|
|||
|
|
|||
|
bMustStopRestart = !TraceStopRestartFieldsMatch ( pQuery, &TempQuery );
|
|||
|
|
|||
|
if ( !bMustStopRestart ) {
|
|||
|
|
|||
|
if ( ERROR_SUCCESS != LoadQueryConfig( pQuery ) ) {
|
|||
|
SetEvent (pQuery->hExitEvent);
|
|||
|
} else {
|
|||
|
|
|||
|
// Update the trace log session. Do not increment
|
|||
|
// the file autoformat serial number.
|
|||
|
// Todo: File name serial number is already incremented.
|
|||
|
InitTraceProperties ( pQuery, FALSE, NULL, NULL );
|
|||
|
|
|||
|
dwStatus = GetTraceQueryStatus ( pQuery, NULL );
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
dwStatus = UpdateTrace(
|
|||
|
pQuery->LoggerHandle,
|
|||
|
pQuery->szLoggerName,
|
|||
|
&pQuery->Properties );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
// Signal the logging thread to reconfigure.
|
|||
|
pQuery->bLoadNewConfig= TRUE;
|
|||
|
SetEvent (pQuery->hReconfigEvent);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#else
|
|||
|
dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
|
|||
|
#endif
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
GetTraceQueryStatus (
|
|||
|
IN PLOG_QUERY_DATA pQuery,
|
|||
|
IN OUT PLOG_QUERY_DATA pReturnQuery )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
PLOG_QUERY_DATA pLocalQuery = NULL;
|
|||
|
|
|||
|
if ( NULL != pQuery ) {
|
|||
|
|
|||
|
if ( NULL != pReturnQuery ) {
|
|||
|
pLocalQuery = pReturnQuery;
|
|||
|
} else {
|
|||
|
pLocalQuery = G_ALLOC ( sizeof (LOG_QUERY_DATA) );
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != pLocalQuery ) {
|
|||
|
ClearTraceProperties ( pLocalQuery );
|
|||
|
|
|||
|
pLocalQuery->Properties.Wnode.BufferSize = sizeof(pQuery->Properties)
|
|||
|
+ sizeof(pQuery->szLoggerName)
|
|||
|
+ sizeof(pQuery->szLogFileName);
|
|||
|
|
|||
|
pLocalQuery->Properties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
|||
|
|
|||
|
dwStatus = QueryTrace (
|
|||
|
pQuery->LoggerHandle,
|
|||
|
pQuery->szLoggerName,
|
|||
|
&pLocalQuery->Properties );
|
|||
|
|
|||
|
if ( NULL == pReturnQuery ) {
|
|||
|
G_FREE ( pLocalQuery );
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
#else
|
|||
|
dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
|
|||
|
#endif
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
StartQuery (
|
|||
|
IN PLOG_QUERY_DATA pQuery )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
LPTSTR szStringArray[2];
|
|||
|
|
|||
|
HANDLE hThread = NULL;
|
|||
|
DWORD dwThreadId;
|
|||
|
|
|||
|
pQuery->bLoadNewConfig= FALSE;
|
|||
|
|
|||
|
// Create the logging thread.
|
|||
|
hThread = CreateThread (
|
|||
|
NULL, 0, LoggingThreadProc,
|
|||
|
(LPVOID)pQuery, 0, &dwThreadId);
|
|||
|
|
|||
|
if ( NULL != hThread ) {
|
|||
|
pQuery->hThread = hThread;
|
|||
|
} else {
|
|||
|
// unable to start thread
|
|||
|
dwStatus = GetLastError();
|
|||
|
szStringArray[0] = pQuery->szQueryName;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_START_THREAD,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS != dwStatus ) {
|
|||
|
SetStoppedStatus ( pQuery );
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
SetStoppedStatus (
|
|||
|
IN PLOG_QUERY_DATA pQuery )
|
|||
|
{
|
|||
|
DWORD dwStatus;
|
|||
|
SYSTEMTIME st;
|
|||
|
LONGLONG llTime;
|
|||
|
|
|||
|
pQuery->dwCurrentState = SLQ_QUERY_STOPPED;
|
|||
|
dwStatus = WriteRegistryDwordValue (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
(LPCTSTR)L"Current State",
|
|||
|
&pQuery->dwCurrentState,
|
|||
|
REG_DWORD );
|
|||
|
|
|||
|
if ( SLQ_AUTO_MODE_NONE == pQuery->stiRegStart.dwAutoMode ) {
|
|||
|
pQuery->stiRegStart.llDateTime = MAX_TIME_VALUE;
|
|||
|
dwStatus = WriteRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
(LPCTSTR)L"Start",
|
|||
|
&pQuery->stiRegStart);
|
|||
|
}
|
|||
|
|
|||
|
GetLocalTime(&st);
|
|||
|
SystemTimeToFileTime (&st, (FILETIME *)&llTime);
|
|||
|
|
|||
|
// If stop is manual or StopAt with time before now (no repeat), set to manual
|
|||
|
// with MIN_TIME_VALUE
|
|||
|
if ( SLQ_AUTO_MODE_NONE == pQuery->stiRegStop.dwAutoMode
|
|||
|
&& llTime >= pQuery->stiRegStop.llDateTime )
|
|||
|
{
|
|||
|
pQuery->stiRegStop.dwAutoMode = SLQ_AUTO_MODE_NONE;
|
|||
|
pQuery->stiRegStop.llDateTime = MIN_TIME_VALUE;
|
|||
|
dwStatus = WriteRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
(LPCTSTR)L"Stop",
|
|||
|
&pQuery->stiRegStop);
|
|||
|
|
|||
|
} else if ( ( SLQ_AUTO_MODE_AT == pQuery->stiRegStop.dwAutoMode
|
|||
|
&& ( SLQ_AUTO_MODE_CALENDAR != pQuery->stiRepeat.dwAutoMode ) )
|
|||
|
&& ( llTime >= pQuery->stiRegStop.llDateTime ) ) {
|
|||
|
|
|||
|
pQuery->stiRegStop.dwAutoMode = SLQ_AUTO_MODE_NONE;
|
|||
|
pQuery->stiRegStop.llDateTime = MIN_TIME_VALUE;
|
|||
|
dwStatus = WriteRegistrySlqTime (
|
|||
|
pQuery->hKeyQuery,
|
|||
|
(LPCTSTR)L"Stop",
|
|||
|
&pQuery->stiRegStop);
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
HandleMaxQueriesExceeded (
|
|||
|
IN PLOG_QUERY_DATA pQuery )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
|
|||
|
// The query has not been started yet, but still in "Start Pending" state.
|
|||
|
SetStoppedStatus ( pQuery );
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ConfigureQuery (
|
|||
|
HKEY hKeyLogQuery,
|
|||
|
TCHAR* szQueryKeyNameBuffer,
|
|||
|
TCHAR* szQueryNameBuffer )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
PLOG_QUERY_DATA pQuery = NULL;
|
|||
|
|
|||
|
pQuery = GetQueryData ( szQueryNameBuffer );
|
|||
|
if ( NULL != pQuery ) {
|
|||
|
BOOL bModified;
|
|||
|
|
|||
|
dwStatus = IsModified ( pQuery, &bModified );
|
|||
|
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
if ( bModified ) {
|
|||
|
dwStatus = ReconfigureQuery ( pQuery );
|
|||
|
// LastModified and LastConfigured values are stored as GMT
|
|||
|
GetSystemTimeAsFileTime ( (LPFILETIME)(&pQuery->llLastConfigured) );
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
// No query data block found. Create one and insert it into the list.
|
|||
|
BOOL bStartQuery = FALSE;
|
|||
|
LPTSTR szStringArray[2];
|
|||
|
|
|||
|
// Allocate a thread info block.
|
|||
|
pQuery = G_ALLOC (sizeof(LOG_QUERY_DATA));
|
|||
|
|
|||
|
if (pQuery != NULL) {
|
|||
|
|
|||
|
// initialize the query data block
|
|||
|
G_ZERO (pQuery, sizeof(LOG_QUERY_DATA));
|
|||
|
|
|||
|
pQuery->hKeyQuery = hKeyLogQuery;
|
|||
|
lstrcpy (pQuery->szQueryName, szQueryNameBuffer);
|
|||
|
lstrcpy (pQuery->szQueryKeyName, szQueryKeyNameBuffer);
|
|||
|
|
|||
|
// Determine whether to continue, based on whether start wait time
|
|||
|
// is 0 or greater.
|
|||
|
|
|||
|
// The thread is reinitialized in the logging procedure.
|
|||
|
// This pre-check avoids spurious thread creation.
|
|||
|
dwStatus = LoadQueryConfig( pQuery );
|
|||
|
|
|||
|
if ( ERROR_SUCCESS != dwStatus ) {
|
|||
|
// Event already logged.
|
|||
|
bStartQuery = FALSE;
|
|||
|
} else {
|
|||
|
bStartQuery = ( NULL_INTERVAL_TICS != ComputeStartWaitTics ( pQuery, FALSE ) );
|
|||
|
}
|
|||
|
|
|||
|
if ( bStartQuery ) {
|
|||
|
if ( SLQ_TRACE_LOG == pQuery->dwLogType
|
|||
|
|| SLQ_COUNTER_LOG == pQuery->dwLogType ) {
|
|||
|
|
|||
|
bStartQuery = ( ERROR_SUCCESS == ProcessLogFileFolder( pQuery, FALSE ) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( bStartQuery ) {
|
|||
|
|
|||
|
LockQueryData();
|
|||
|
|
|||
|
if ( dwActiveSessionCount < dwMaxActiveSessionCount ) {
|
|||
|
pQuery->hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|||
|
|
|||
|
if ( NULL != pQuery->hExitEvent ) {
|
|||
|
|
|||
|
pQuery->hReconfigEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|||
|
|
|||
|
if ( NULL != pQuery->hReconfigEvent ) {
|
|||
|
// LastModified and LastConfigured values are stored as GMT
|
|||
|
GetSystemTimeAsFileTime ( (LPFILETIME)(&pQuery->llLastConfigured) );
|
|||
|
|
|||
|
dwStatus = StartQuery( pQuery );
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
// add it to the list and continue
|
|||
|
if (pFirstQuery == NULL) {
|
|||
|
// then this is the first thread so add it
|
|||
|
pQuery->next = NULL;
|
|||
|
pFirstQuery = pQuery;
|
|||
|
} else {
|
|||
|
// insert this at the head of the list since
|
|||
|
// that's the easiest and the order isn't
|
|||
|
// really important
|
|||
|
pQuery->next = pFirstQuery;
|
|||
|
pFirstQuery = pQuery;
|
|||
|
}
|
|||
|
|
|||
|
dwActiveSessionCount += 1;
|
|||
|
SetEvent (hNewQueryEvent );
|
|||
|
|
|||
|
} else {
|
|||
|
// Unable to start query.
|
|||
|
// Event has already been logged.
|
|||
|
FreeQueryData ( pQuery );
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Unable to create reconfig event.
|
|||
|
dwStatus = GetLastError();
|
|||
|
szStringArray[0] = szQueryNameBuffer;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_CREATE_RECONFIG_EVENT,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
|
|||
|
FreeQueryData( pQuery );
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Unable to create exit event.
|
|||
|
dwStatus = GetLastError();
|
|||
|
szStringArray[0] = szQueryNameBuffer;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_CREATE_EXIT_EVENT,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
|
|||
|
FreeQueryData( pQuery );
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
szStringArray[0] = szQueryNameBuffer;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_MAXIMUM_QUERY_LIMIT,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
0,
|
|||
|
szStringArray,
|
|||
|
NULL);
|
|||
|
|
|||
|
dwStatus = HandleMaxQueriesExceeded ( pQuery );
|
|||
|
|
|||
|
FreeQueryData ( pQuery );
|
|||
|
}
|
|||
|
|
|||
|
UnlockQueryData();
|
|||
|
|
|||
|
} else {
|
|||
|
// Wait time is -1, or config load error.
|
|||
|
FreeQueryData( pQuery );
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Memory allocation error.
|
|||
|
dwStatus = GetLastError();
|
|||
|
szStringArray[0] = szQueryNameBuffer;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_ALLOCATE_DATABLOCK,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
DoLogCommandFile (
|
|||
|
IN PLOG_QUERY_DATA pArg,
|
|||
|
IN LPTSTR szLogFileName,
|
|||
|
IN BOOL bStillRunning
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD dwStatus;
|
|||
|
BOOL bStatus = FALSE;
|
|||
|
const INT ciExtraChars = 3;
|
|||
|
INT iBufLen = 0;
|
|||
|
INT iStrLen = 0;
|
|||
|
LPTSTR szCommandString = NULL;
|
|||
|
LPTSTR szTempBuffer = NULL;
|
|||
|
LONG lErrorMode;
|
|||
|
LPWSTR szStringArray[3];
|
|||
|
STARTUPINFO si;
|
|||
|
PROCESS_INFORMATION pi;
|
|||
|
DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS;
|
|||
|
|
|||
|
if ( NULL != pArg && NULL != szLogFileName ) {
|
|||
|
|
|||
|
if ( NULL != pArg->szCmdFileName ) {
|
|||
|
|
|||
|
dwStatus = pArg->dwCmdFileFailure;
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
iStrLen = lstrlen ( szLogFileName );
|
|||
|
iBufLen = iStrLen + ciExtraChars + 1; // 1 is for NULL
|
|||
|
|
|||
|
szCommandString = (LPTSTR)G_ALLOC(iBufLen * sizeof(TCHAR));
|
|||
|
|
|||
|
iBufLen += lstrlen ( pArg->szCmdFileName ) + 1; // 1 is for space char,
|
|||
|
// NULL already counted.
|
|||
|
|
|||
|
szTempBuffer = (LPTSTR)G_ALLOC(iBufLen * sizeof(TCHAR));
|
|||
|
|
|||
|
if ( NULL != szCommandString && NULL != szTempBuffer ) {
|
|||
|
// build command line arguments
|
|||
|
szCommandString[0] = _T('\"');
|
|||
|
lstrcpy (&szCommandString[1], szLogFileName );
|
|||
|
lstrcpy (&szCommandString[iStrLen+1], (LPCTSTR)(LPCTSTR)TEXT("\" "));
|
|||
|
lstrcpy (&szCommandString[iStrLen+2],
|
|||
|
(bStillRunning ? (LPCTSTR)(LPCTSTR)TEXT("1") : (LPCTSTR)TEXT("0")));
|
|||
|
|
|||
|
// initialize Startup Info block
|
|||
|
memset (&si, 0, sizeof(si));
|
|||
|
si.cb = sizeof(si);
|
|||
|
si.dwFlags = STARTF_USESHOWWINDOW ;
|
|||
|
si.wShowWindow = SW_SHOWNOACTIVATE ;
|
|||
|
|
|||
|
//si.lpDesktop = L"WinSta0\\Default";
|
|||
|
memset (&pi, 0, sizeof(pi));
|
|||
|
|
|||
|
// supress pop-ups in the detached process
|
|||
|
lErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
|||
|
|
|||
|
lstrcpy (szTempBuffer, pArg->szCmdFileName) ;
|
|||
|
|
|||
|
// see if this is a CMD or a BAT file
|
|||
|
// if it is then create a process with a console window, otherwise
|
|||
|
// assume it's an executable file that will create it's own window
|
|||
|
// or console if necessary
|
|||
|
//
|
|||
|
_tcslwr (szTempBuffer);
|
|||
|
if ((_tcsstr(szTempBuffer, (LPCTSTR)TEXT(".bat")) != NULL)
|
|||
|
|| (_tcsstr(szTempBuffer, (LPCTSTR)TEXT(".cmd")) != NULL))
|
|||
|
{
|
|||
|
dwCreationFlags |= CREATE_NEW_CONSOLE;
|
|||
|
} else {
|
|||
|
dwCreationFlags |= DETACHED_PROCESS;
|
|||
|
}
|
|||
|
|
|||
|
// recopy the image name to the temp buffer since it was modified
|
|||
|
// (i.e. lowercased) for the previous comparison.
|
|||
|
|
|||
|
lstrcpy (szTempBuffer, pArg->szCmdFileName) ;
|
|||
|
iStrLen = lstrlen (szTempBuffer) ;
|
|||
|
|
|||
|
// now add on the alert text preceded with a space char
|
|||
|
szTempBuffer [iStrLen] = TEXT(' ') ;
|
|||
|
iStrLen++ ;
|
|||
|
lstrcpy (&szTempBuffer[iStrLen], szCommandString) ;
|
|||
|
|
|||
|
if( pArg->hUserToken != NULL ){
|
|||
|
bStatus = CreateProcessAsUser (
|
|||
|
pArg->hUserToken,
|
|||
|
NULL,
|
|||
|
szTempBuffer,
|
|||
|
NULL, NULL, FALSE,
|
|||
|
dwCreationFlags,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&si,
|
|||
|
&pi);
|
|||
|
} else {
|
|||
|
bStatus = CreateProcess (
|
|||
|
NULL,
|
|||
|
szTempBuffer,
|
|||
|
NULL, NULL, FALSE,
|
|||
|
dwCreationFlags,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&si,
|
|||
|
&pi);
|
|||
|
}
|
|||
|
|
|||
|
SetErrorMode(lErrorMode);
|
|||
|
|
|||
|
if (bStatus) {
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
if ( NULL != pi.hThread && INVALID_HANDLE_VALUE != pi.hThread ) {
|
|||
|
CloseHandle(pi.hThread);
|
|||
|
pi.hThread = NULL;
|
|||
|
}
|
|||
|
if ( NULL != pi.hProcess && INVALID_HANDLE_VALUE != pi.hProcess ) {
|
|||
|
CloseHandle(pi.hProcess);
|
|||
|
pi.hProcess = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
dwStatus = GetLastError();
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS != dwStatus ) {
|
|||
|
|
|||
|
szStringArray[0] = szTempBuffer;
|
|||
|
szStringArray[1] = pArg->szQueryName;
|
|||
|
szStringArray[2] = FormatEventLogMessage(dwStatus);
|
|||
|
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_LOG_CMD_FAIL,
|
|||
|
NULL,
|
|||
|
3,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus );
|
|||
|
|
|||
|
pArg->dwCmdFileFailure = dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
if (szCommandString != NULL) G_FREE(szCommandString);
|
|||
|
if (szTempBuffer != NULL) G_FREE(szTempBuffer);
|
|||
|
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
GetQueryKeyName (
|
|||
|
IN LPCTSTR szQueryName,
|
|||
|
OUT LPTSTR szQueryKeyName,
|
|||
|
IN DWORD dwQueryKeyNameLen )
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
HKEY hKeyLogQueries = NULL;
|
|||
|
HKEY hKeyThisLogQuery = NULL;
|
|||
|
DWORD dwQueryIndex;
|
|||
|
TCHAR szQueryNameBuffer[MAX_PATH+1];
|
|||
|
DWORD dwQueryNameBufferSize;
|
|||
|
TCHAR szQueryKeyNameBuffer[MAX_PATH+1];
|
|||
|
TCHAR szQueryClassBuffer[MAX_PATH+1];
|
|||
|
DWORD dwQueryClassBufferSize;
|
|||
|
LPTSTR szCollectionName = NULL;
|
|||
|
UINT uiCollectionNameLen = 0;
|
|||
|
LPTSTR szStringArray[2];
|
|||
|
|
|||
|
assert ( 0 < lstrlen ( szQueryName ) );
|
|||
|
|
|||
|
if ( NULL != szQueryName
|
|||
|
&& NULL != szQueryKeyName ) {
|
|||
|
if ( 0 < lstrlen ( szQueryName )
|
|||
|
&& 0 < dwQueryKeyNameLen ) {
|
|||
|
|
|||
|
// Note: This method does not reallocate buffer or return
|
|||
|
// actual buffer size required.
|
|||
|
|
|||
|
memset ( szQueryKeyName, 0, dwQueryKeyNameLen * sizeof (TCHAR) );
|
|||
|
|
|||
|
dwStatus = OpenLogQueriesKey (
|
|||
|
KEY_READ,
|
|||
|
(PHKEY)&hKeyLogQueries);
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
// unable to read the log query information from the registry
|
|||
|
dwStatus = GetLastError();
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_OPEN_LOG_QUERY,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
} else {
|
|||
|
|
|||
|
// Enumerate the queries in the registry.
|
|||
|
dwQueryIndex = 0;
|
|||
|
*szQueryNameBuffer = 0;
|
|||
|
dwQueryNameBufferSize = MAX_PATH+1;
|
|||
|
*szQueryClassBuffer = 0;
|
|||
|
dwQueryClassBufferSize = MAX_PATH+1;
|
|||
|
|
|||
|
while ((dwStatus = RegEnumKeyEx (
|
|||
|
hKeyLogQueries,
|
|||
|
dwQueryIndex,
|
|||
|
szQueryNameBuffer,
|
|||
|
&dwQueryNameBufferSize,
|
|||
|
NULL,
|
|||
|
szQueryClassBuffer,
|
|||
|
&dwQueryClassBufferSize,
|
|||
|
NULL)) != ERROR_NO_MORE_ITEMS)
|
|||
|
{
|
|||
|
// open this key
|
|||
|
dwStatus = RegOpenKeyEx (
|
|||
|
hKeyLogQueries,
|
|||
|
szQueryNameBuffer,
|
|||
|
0L,
|
|||
|
KEY_READ,
|
|||
|
(PHKEY)&hKeyThisLogQuery);
|
|||
|
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
if ( 0 == lstrcmpi ( szQueryNameBuffer, szQueryName ) ) {
|
|||
|
if ( dwQueryKeyNameLen > (DWORD)lstrlen ( szQueryName ) ) {
|
|||
|
lstrcpyn ( szQueryKeyName, szQueryName, min (MAX_PATH, lstrlen (szQueryName) + 1 ) );
|
|||
|
break;
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = SmReadRegistryIndirectStringValue (
|
|||
|
hKeyThisLogQuery,
|
|||
|
L"Collection Name",
|
|||
|
NULL,
|
|||
|
&szCollectionName,
|
|||
|
&uiCollectionNameLen );
|
|||
|
|
|||
|
if ( NULL != szCollectionName ) {
|
|||
|
if ( 0 < lstrlen(szCollectionName) ) {
|
|||
|
if ( 0 == lstrcmpi ( szCollectionName, szQueryName ) ) {
|
|||
|
if ( dwQueryKeyNameLen > (DWORD)lstrlen ( szQueryNameBuffer ) ) {
|
|||
|
lstrcpyn ( szQueryKeyName, szQueryNameBuffer, min (MAX_PATH, lstrlen (szQueryNameBuffer) + 1 ) );
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
G_FREE ( szCollectionName );
|
|||
|
szCollectionName = NULL;
|
|||
|
uiCollectionNameLen = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if ( NULL != hKeyThisLogQuery ) {
|
|||
|
RegCloseKey ( hKeyThisLogQuery );
|
|||
|
hKeyThisLogQuery = NULL;
|
|||
|
}
|
|||
|
// prepare for next loop
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
dwQueryIndex++;
|
|||
|
*szQueryNameBuffer = 0;
|
|||
|
dwQueryNameBufferSize = MAX_PATH;
|
|||
|
*szQueryClassBuffer = 0;
|
|||
|
dwQueryClassBufferSize = MAX_PATH;
|
|||
|
} // end enumeration of log queries
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_NO_MORE_ITEMS == dwStatus ) {
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != hKeyLogQueries ) {
|
|||
|
RegCloseKey (hKeyLogQueries );
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
Configure ( void )
|
|||
|
{
|
|||
|
DWORD dwStatus;
|
|||
|
HKEY hKeyLogQueries = NULL;
|
|||
|
HKEY hKeyThisLogQuery = NULL;
|
|||
|
DWORD dwQueryIndex;
|
|||
|
TCHAR szQueryNameBuffer[MAX_PATH+1];
|
|||
|
DWORD dwQueryNameBufferSize;
|
|||
|
TCHAR szQueryKeyNameBuffer[MAX_PATH+1];
|
|||
|
TCHAR szQueryClassBuffer[MAX_PATH+1];
|
|||
|
DWORD dwQueryClassBufferSize;
|
|||
|
LPTSTR szCollectionName = NULL;
|
|||
|
UINT uiCollectionNameLen = 0;
|
|||
|
LPTSTR szStringArray[2];
|
|||
|
|
|||
|
__try {
|
|||
|
|
|||
|
// Open each query in the registry
|
|||
|
dwStatus = OpenLogQueriesKey (
|
|||
|
KEY_READ,
|
|||
|
(PHKEY)&hKeyLogQueries);
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS) {
|
|||
|
if (dwStatus == ERROR_FILE_NOT_FOUND) {
|
|||
|
// no logs nor alerts settings, bail out quietly
|
|||
|
//
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
else {
|
|||
|
// unable to read the log query information from the registry
|
|||
|
dwStatus = GetLastError();
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_OPEN_LOG_QUERY,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
// enumerate and restart or start the queries in the registry
|
|||
|
dwQueryIndex = 0;
|
|||
|
*szQueryNameBuffer = 0;
|
|||
|
dwQueryNameBufferSize = MAX_PATH+1;
|
|||
|
*szQueryClassBuffer = 0;
|
|||
|
dwQueryClassBufferSize = MAX_PATH+1;
|
|||
|
|
|||
|
while ((dwStatus = RegEnumKeyEx (
|
|||
|
hKeyLogQueries,
|
|||
|
dwQueryIndex,
|
|||
|
szQueryNameBuffer,
|
|||
|
&dwQueryNameBufferSize,
|
|||
|
NULL,
|
|||
|
szQueryClassBuffer,
|
|||
|
&dwQueryClassBufferSize,
|
|||
|
NULL)) != ERROR_NO_MORE_ITEMS) {
|
|||
|
|
|||
|
// open this key
|
|||
|
dwStatus = RegOpenKeyEx (
|
|||
|
hKeyLogQueries,
|
|||
|
szQueryNameBuffer,
|
|||
|
0L,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
(PHKEY)&hKeyThisLogQuery);
|
|||
|
|
|||
|
if (dwStatus == ERROR_SUCCESS) {
|
|||
|
|
|||
|
// update the service status
|
|||
|
ssSmLogStatus.dwCheckPoint++;
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
|
|||
|
if ( 0 < lstrlen(szQueryNameBuffer) ) {
|
|||
|
lstrcpyn (
|
|||
|
szQueryKeyNameBuffer,
|
|||
|
szQueryNameBuffer,
|
|||
|
min(MAX_PATH, lstrlen(szQueryNameBuffer)+1 ) );
|
|||
|
}
|
|||
|
|
|||
|
dwStatus = SmReadRegistryIndirectStringValue (
|
|||
|
hKeyThisLogQuery,
|
|||
|
L"Collection Name",
|
|||
|
NULL,
|
|||
|
&szCollectionName,
|
|||
|
&uiCollectionNameLen );
|
|||
|
|
|||
|
if ( NULL != szCollectionName ) {
|
|||
|
if ( 0 < lstrlen(szCollectionName) ) {
|
|||
|
lstrcpyn (
|
|||
|
szQueryNameBuffer,
|
|||
|
szCollectionName,
|
|||
|
min(MAX_PATH, lstrlen(szCollectionName)+1 ) );
|
|||
|
}
|
|||
|
G_FREE ( szCollectionName );
|
|||
|
szCollectionName = NULL;
|
|||
|
uiCollectionNameLen = 0;
|
|||
|
}
|
|||
|
|
|||
|
dwStatus = ConfigureQuery (
|
|||
|
hKeyThisLogQuery,
|
|||
|
szQueryKeyNameBuffer,
|
|||
|
szQueryNameBuffer );
|
|||
|
// hKeyThisLogQuery is stored in the Query data structure.
|
|||
|
|
|||
|
} else {
|
|||
|
szStringArray[0] = szQueryNameBuffer;
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_READ_LOG_QUERY,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
sizeof(DWORD),
|
|||
|
szStringArray,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
}
|
|||
|
|
|||
|
// prepare for next loop
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
dwQueryIndex++;
|
|||
|
*szQueryNameBuffer = 0;
|
|||
|
dwQueryNameBufferSize = MAX_PATH;
|
|||
|
*szQueryClassBuffer = 0;
|
|||
|
dwQueryClassBufferSize = MAX_PATH;
|
|||
|
} // end enumeration of log queries
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_NO_MORE_ITEMS == dwStatus ) {
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
} __except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|||
|
|
|||
|
|
|||
|
dwStatus = SMLOG_THREAD_FAILED;
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != hKeyLogQueries ) {
|
|||
|
RegCloseKey (hKeyLogQueries );
|
|||
|
}
|
|||
|
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void SysmonLogServiceControlHandler(
|
|||
|
IN DWORD dwControl
|
|||
|
)
|
|||
|
{
|
|||
|
PLOG_QUERY_DATA pQuery;
|
|||
|
DWORD dwStatus;
|
|||
|
|
|||
|
switch (dwControl) {
|
|||
|
|
|||
|
case SERVICE_CONTROL_SYNCHRONIZE:
|
|||
|
EnterConfigure();
|
|||
|
dwStatus = Configure ();
|
|||
|
ExitConfigure();
|
|||
|
if ( ERROR_SUCCESS == dwStatus )
|
|||
|
break;
|
|||
|
// If not successful, fall through to shutdown.
|
|||
|
// Errors already logged.
|
|||
|
|
|||
|
case SERVICE_CONTROL_SHUTDOWN:
|
|||
|
case SERVICE_CONTROL_STOP:
|
|||
|
// stop logging & close queries and files
|
|||
|
// set stop event for all running thread
|
|||
|
|
|||
|
LockQueryData();
|
|||
|
|
|||
|
ssSmLogStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
|
|||
|
pQuery = pFirstQuery;
|
|||
|
|
|||
|
while (pQuery != NULL) {
|
|||
|
SetEvent (pQuery->hExitEvent);
|
|||
|
pQuery = pQuery->next;
|
|||
|
}
|
|||
|
|
|||
|
UnlockQueryData();
|
|||
|
break;
|
|||
|
|
|||
|
case SERVICE_CONTROL_PAUSE:
|
|||
|
// stop logging, close queries and files
|
|||
|
// not supported, yet
|
|||
|
break;
|
|||
|
case SERVICE_CONTROL_CONTINUE:
|
|||
|
// reload ration and restart logging
|
|||
|
// not supported, yet
|
|||
|
break;
|
|||
|
case SERVICE_CONTROL_INTERROGATE:
|
|||
|
// update current status
|
|||
|
default:
|
|||
|
// report to event log that an unrecognized control
|
|||
|
// request was received.
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
SysmonLogServiceStart (
|
|||
|
IN DWORD argc,
|
|||
|
IN LPTSTR *argv
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
DWORD dwQueryIndex;
|
|||
|
BOOL bInteractive = FALSE;
|
|||
|
BOOL bLogQueriesKeyExists = TRUE;
|
|||
|
|
|||
|
if ((argc == 1) && (*argv[0] == 'I')) bInteractive = TRUE;
|
|||
|
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
if ( NULL != hEventLog ) {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_INFORMATION_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_DEBUG_STARTING_SERVICE,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
#endif
|
|||
|
if (!bInteractive) {
|
|||
|
ssSmLogStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|||
|
ssSmLogStatus.dwCurrentState = SERVICE_START_PENDING;
|
|||
|
ssSmLogStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
|
|||
|
// SERVICE_ACCEPT_PAUSE_CONTINUE |
|
|||
|
SERVICE_ACCEPT_SHUTDOWN;
|
|||
|
ssSmLogStatus.dwWin32ExitCode = 0;
|
|||
|
ssSmLogStatus.dwServiceSpecificExitCode = 0;
|
|||
|
ssSmLogStatus.dwCheckPoint = 0;
|
|||
|
ssSmLogStatus.dwWaitHint = 1000;
|
|||
|
|
|||
|
hSmLogStatus = RegisterServiceCtrlHandler (
|
|||
|
(LPCTSTR)TEXT("SysmonLog"), SysmonLogServiceControlHandler);
|
|||
|
|
|||
|
if (hSmLogStatus == (SERVICE_STATUS_HANDLE)0) {
|
|||
|
dwStatus = GetLastError();
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_REGISTER_HANDLER,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
sizeof(DWORD),
|
|||
|
NULL,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
// this is fatal so bail out
|
|||
|
}
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
else {
|
|||
|
if ( NULL != hEventLog ) {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_INFORMATION_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_DEBUG_HANDLER_REGISTERED,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
InitializeCriticalSection ( &QueryDataLock );
|
|||
|
InitializeCriticalSection ( &ConfigurationLock );
|
|||
|
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
ssSmLogStatus.dwCurrentState = SERVICE_RUNNING;
|
|||
|
ssSmLogStatus.dwCheckPoint++;
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
#endif
|
|||
|
dwStatus = ClearQueryRunStates();
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
if ( NULL != hEventLog ) {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_INFORMATION_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_DEBUG_CLEAR_RUN_STATES,
|
|||
|
NULL,
|
|||
|
sizeof(DWORD),
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
}
|
|||
|
#endif
|
|||
|
// Continue even if query run state error, unless
|
|||
|
// the Log Queries key is missing or not accessible.
|
|||
|
if ( SMLOG_UNABLE_OPEN_LOG_QUERY == dwStatus ) {
|
|||
|
bLogQueriesKeyExists = FALSE;
|
|||
|
// Sleep long enough for event to be written to event log.
|
|||
|
Sleep(500);
|
|||
|
if (!bInteractive) {
|
|||
|
ssSmLogStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
|
|||
|
// Use status mask so that error matches the code in the application log.
|
|||
|
ssSmLogStatus.dwServiceSpecificExitCode = (SMLOG_UNABLE_OPEN_LOG_QUERY & STATUS_MASK);
|
|||
|
}
|
|||
|
} else {
|
|||
|
dwStatus = ERROR_SUCCESS;
|
|||
|
|
|||
|
// Continue on error.
|
|||
|
LoadDefaultLogFileFolder();
|
|||
|
|
|||
|
// Ignore PDH errors. The only possible error is that the default
|
|||
|
// data source has already been set for this process.
|
|||
|
// Set the default for the service to DATA_SOURCE_REGISTRY
|
|||
|
dwStatus = PdhSetDefaultRealTimeDataSource ( DATA_SOURCE_REGISTRY );
|
|||
|
|
|||
|
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
if ( NULL != hEventLog ) {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_INFORMATION_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_DEBUG_DEFAULT_FOLDER_LOADED,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// Continue on error.
|
|||
|
LoadPdhLogUpdateSuccess();
|
|||
|
|
|||
|
hNewQueryEvent = CreateEvent ( NULL, TRUE, FALSE, NULL );
|
|||
|
|
|||
|
if ( NULL == hNewQueryEvent ) {
|
|||
|
|
|||
|
// Unable to create new query configuration event.
|
|||
|
dwStatus = GetLastError();
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_CREATE_CONFIG_EVENT,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
sizeof(DWORD),
|
|||
|
NULL,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
// this is fatal so bail out
|
|||
|
if (!bInteractive) {
|
|||
|
// Sleep long enough for event to be written to event log.
|
|||
|
Sleep(500);
|
|||
|
ssSmLogStatus.dwWin32ExitCode = dwStatus;
|
|||
|
}
|
|||
|
}
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
else {
|
|||
|
if ( NULL != hEventLog ) {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_INFORMATION_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_DEBUG_CONFIG_EVENT_CREATED,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if ( ( ERROR_SUCCESS == dwStatus ) && !bInteractive) {
|
|||
|
// Thread synchronization mechanisms now created,
|
|||
|
// so set status to Running.
|
|||
|
ssSmLogStatus.dwCurrentState = SERVICE_RUNNING;
|
|||
|
ssSmLogStatus.dwCheckPoint = 0;
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
// Disable 64-bit warning
|
|||
|
#if _MSC_VER >= 1200
|
|||
|
#pragma warning(push)
|
|||
|
#endif
|
|||
|
#pragma warning ( disable : 4152 )
|
|||
|
|
|||
|
dwStatus = WmiNotificationRegistration(
|
|||
|
(const LPGUID) & TraceErrorGuid,
|
|||
|
TRUE,
|
|||
|
TraceNotificationCallback,
|
|||
|
0,
|
|||
|
NOTIFICATION_CALLBACK_DIRECT);
|
|||
|
#if _MSC_VER >= 1200
|
|||
|
#pragma warning(pop)
|
|||
|
#endif
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// Set up the queries and start threads.
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == dwStatus && bLogQueriesKeyExists) {
|
|||
|
EnterConfigure();
|
|||
|
dwStatus = Configure ();
|
|||
|
ExitConfigure();
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL == pFirstQuery ) {
|
|||
|
// Nothing to do. Stop the service.
|
|||
|
if (!bInteractive) {
|
|||
|
ssSmLogStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
}
|
|||
|
} else if ( ERROR_SUCCESS == dwStatus ) {
|
|||
|
|
|||
|
// Loop in WaitForMultipleObjects. When any
|
|||
|
// query is signaled, deallocate that query data block
|
|||
|
// and close its handles.
|
|||
|
|
|||
|
while ( TRUE ) {
|
|||
|
BOOL bStatus;
|
|||
|
|
|||
|
LockQueryData();
|
|||
|
|
|||
|
// About to reconfigure the Wait array, so clear the event.
|
|||
|
bStatus = ResetEvent ( hNewQueryEvent );
|
|||
|
|
|||
|
if ( NULL == pFirstQuery ) {
|
|||
|
|
|||
|
if (!bInteractive) {
|
|||
|
ssSmLogStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
}
|
|||
|
|
|||
|
UnlockQueryData();
|
|||
|
break;
|
|||
|
} else {
|
|||
|
DWORD dwIndex = 0;
|
|||
|
DWORD dwWaitStatus;
|
|||
|
PLOG_QUERY_DATA pQuery;
|
|||
|
|
|||
|
assert ( 0 < dwActiveSessionCount );
|
|||
|
|
|||
|
G_ZERO( arrSessionHandle, sizeof( HANDLE ) * ( dwActiveSessionCount + 1) );
|
|||
|
|
|||
|
// The first element is the global hNewQueryEvent to signal new sessions.
|
|||
|
arrSessionHandle[dwIndex] = hNewQueryEvent;
|
|||
|
dwIndex++;
|
|||
|
|
|||
|
for ( pQuery = pFirstQuery;
|
|||
|
NULL != pQuery;
|
|||
|
pQuery = pQuery->next ) {
|
|||
|
|
|||
|
assert ( NULL != pQuery->hThread );
|
|||
|
if ( NULL != pQuery->hExitEvent && NULL != pQuery->hThread ) {
|
|||
|
arrSessionHandle[dwIndex] = pQuery->hThread;
|
|||
|
dwIndex++;
|
|||
|
assert ( dwIndex <= dwActiveSessionCount + 1 );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
UnlockQueryData();
|
|||
|
// xxx handle error
|
|||
|
dwWaitStatus = WaitForMultipleObjects (
|
|||
|
dwIndex,
|
|||
|
arrSessionHandle,
|
|||
|
FALSE,
|
|||
|
INFINITE );
|
|||
|
|
|||
|
// when here, either a new query has been started, or
|
|||
|
// at least one logging thread or has terminated so the
|
|||
|
// memory can be released.
|
|||
|
dwQueryIndex = dwWaitStatus - WAIT_OBJECT_0;
|
|||
|
|
|||
|
// release the dynamic memory if the wait object is not the StartQuery event.
|
|||
|
if ( 0 < dwQueryIndex && dwQueryIndex < dwIndex ) {
|
|||
|
SetStoppedStatus( GetQueryDataPtr( arrSessionHandle[dwQueryIndex] ) );
|
|||
|
RemoveAndFreeQueryData( arrSessionHandle[dwQueryIndex] );
|
|||
|
}
|
|||
|
}
|
|||
|
} // End while
|
|||
|
}
|
|||
|
|
|||
|
#if _IMPLEMENT_WMI
|
|||
|
// Disable 64-bit warning
|
|||
|
#if _MSC_VER >= 1200
|
|||
|
#pragma warning(push)
|
|||
|
#endif
|
|||
|
#pragma warning ( disable : 4152 )
|
|||
|
WmiNotificationRegistration(
|
|||
|
(const LPGUID) & TraceErrorGuid,
|
|||
|
FALSE,
|
|||
|
TraceNotificationCallback,
|
|||
|
0,
|
|||
|
NOTIFICATION_CALLBACK_DIRECT);
|
|||
|
#if _MSC_VER >= 1200
|
|||
|
#pragma warning(pop)
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
|
|||
|
if ( NULL != hNewQueryEvent ) {
|
|||
|
CloseHandle ( hNewQueryEvent );
|
|||
|
hNewQueryEvent = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DeleteCriticalSection ( &QueryDataLock );
|
|||
|
DeleteCriticalSection ( &ConfigurationLock );
|
|||
|
}
|
|||
|
|
|||
|
if (!bInteractive) {
|
|||
|
// Update the service status
|
|||
|
ssSmLogStatus.dwCurrentState = SERVICE_STOPPED;
|
|||
|
SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
|
|||
|
}
|
|||
|
|
|||
|
if ( NULL != arrPdhDataCollectSuccess ) {
|
|||
|
G_FREE ( arrPdhDataCollectSuccess );
|
|||
|
arrPdhDataCollectSuccess = NULL;
|
|||
|
iPdhDataCollectSuccessCount = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (hEventLog != NULL) {
|
|||
|
DeregisterEventSource ( hEventLog );
|
|||
|
hEventLog = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
__cdecl main (
|
|||
|
int argc,
|
|||
|
char *argv[])
|
|||
|
/*++
|
|||
|
|
|||
|
main
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Arguments
|
|||
|
|
|||
|
|
|||
|
ReturnValue
|
|||
|
|
|||
|
0 (ERROR_SUCCESS) if command was processed
|
|||
|
Non-Zero if command error was detected.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
BOOL bInteractive = FALSE;
|
|||
|
|
|||
|
SERVICE_TABLE_ENTRY DispatchTable[] = {
|
|||
|
{(LPTSTR)TEXT("SysmonLog"), SysmonLogServiceStart },
|
|||
|
{NULL, NULL }
|
|||
|
};
|
|||
|
|
|||
|
hEventLog = RegisterEventSource (NULL, (LPCTSTR)TEXT("SysmonLog"));
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
if ( NULL != hEventLog ) {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_INFORMATION_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_DEBUG_EVENT_SOURCE_REGISTERED,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
hModule = (HINSTANCE) GetModuleHandle(NULL);
|
|||
|
|
|||
|
if (argc > 1) {
|
|||
|
if ((argv[1][0] == '-') || (argv[1][0] == '/')) {
|
|||
|
if ((argv[1][1] == 'i') || (argv[1][1] == 'I')) {
|
|||
|
bInteractive = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (bInteractive) {
|
|||
|
DWORD dwArgs = 1;
|
|||
|
LPTSTR szArgs[1];
|
|||
|
szArgs[0] = (LPTSTR)TEXT("I");
|
|||
|
SysmonLogServiceStart (dwArgs, szArgs);
|
|||
|
} else {
|
|||
|
if (!StartServiceCtrlDispatcher (DispatchTable)) {
|
|||
|
dwStatus = GetLastError();
|
|||
|
// log failure to event log
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_UNABLE_START_DISPATCHER,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
sizeof(DWORD),
|
|||
|
NULL,
|
|||
|
(LPVOID)&dwStatus);
|
|||
|
}
|
|||
|
#if _DEBUG_OUTPUT
|
|||
|
else {
|
|||
|
ReportEvent (hEventLog,
|
|||
|
EVENTLOG_INFORMATION_TYPE,
|
|||
|
0,
|
|||
|
SMLOG_DEBUG_SERVICE_CTRL_DISP_STARTED,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|