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;
|
||
}
|
||
|