Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

949 lines
24 KiB

//***************************************************************************
//
// NTEVTTHRD.CPP
//
// Module: WBEM NT EVENT PROVIDER
//
// Purpose: Contains the thread which listens for events and processes
// them.
//
// Copyright (c) 1996-2001 Microsoft Corporation, All Rights Reserved
//
//***************************************************************************
#include "precomp.h"
#include <winperf.h>
#include <time.h>
#include <wbemtime.h>
#define NUM_THREADS 1
const DWORD CEventLogMonitor::m_PollTimeOut = 60000; // 10 minute poll period
extern CCriticalSection g_ProvLock;
CEventProviderManager::CEventProviderManager() : m_IsFirstSinceLogon (FALSE), m_monitorArray (NULL)
{
ProvThreadObject::Startup();
}
CEventProviderManager::~CEventProviderManager()
{
ProvThreadObject::Closedown();
}
BOOL CEventProviderManager::Register(CNTEventProvider* prov)
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventProviderManager::Register\r\n");
)
BOOL retVal = FALSE;
BOOL bUnReg = FALSE;
{
ScopeLock<CCriticalSection> sl(m_MonitorLock);
{
ScopeLock<CCriticalSection> sl(m_ControlObjects.m_Lock);
prov->AddRefAll();
m_ControlObjects.SetAt((UINT_PTR)prov, prov);
}
bUnReg = TRUE;
if (NULL == m_monitorArray)
{
InitialiseMonitorArray();
}
if (NULL != m_monitorArray)
{
for (int x=0; x < NUM_THREADS; x++)
{
if ( m_monitorArray[x]->IsMonitoring() )
{
//at least one monitor is working
retVal = TRUE;
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager::Register:Successfully monitoring monitor %lx : \r\n" ,
x
) ;
)
break;
}
else
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager::Register:Not monitoring monitor %lx : \r\n" ,
x
) ;
)
}
}
}
}
if ((!retVal) && (bUnReg))
{
UnRegister(prov);
}
return retVal;
}
void CEventProviderManager::UnRegister(CNTEventProvider* prov)
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventProviderManager::UnRegister\r\n");
)
BOOL bDestroyMonitorArray = FALSE;
{
ScopeLock<CCriticalSection> sl(m_MonitorLock);
{
{
ScopeLock<CCriticalSection> sl(m_ControlObjects.m_Lock);
if (m_ControlObjects.RemoveKey((UINT_PTR)prov))
{
prov->ReleaseAll();
if (m_ControlObjects.IsEmpty() && (NULL != m_monitorArray))
{
bDestroyMonitorArray = TRUE;
}
}
}
if (bDestroyMonitorArray)
{
DestroyMonitorArray();
m_monitorArray = NULL;
}
}
}
}
IWbemServices* CEventProviderManager::GetNamespacePtr()
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventProviderManager::GetNamespacePtr\r\n");
)
IWbemServices* retVal = NULL;
{
ScopeLock<CCriticalSection> sl(m_ControlObjects.m_Lock);
POSITION pos = m_ControlObjects.GetStartPosition();
if (pos)
{
CNTEventProvider* pCntrl;
UINT_PTR key;
m_ControlObjects.GetNextAssoc(pos, key, pCntrl);
retVal = pCntrl->GetNamespace();
}
}
return retVal;
}
void CEventProviderManager::SendEvent(IWbemClassObject* evtObj)
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventProviderManager::SendEvent\r\n");
)
if (evtObj == NULL)
{
return;
}
//copy the list of control objects to minimize amount of work
//done in locked section of code. also cannot call into webm
//in blocked code may cause deadlock if webnm calls back.
CList<CNTEventProvider*, CNTEventProvider*> controlObjects;
{
ScopeLock<CCriticalSection> sl(m_ControlObjects.m_Lock);
POSITION pos = m_ControlObjects.GetStartPosition();
while (NULL != pos)
{
CNTEventProvider* pCntrl;
UINT_PTR key;
m_ControlObjects.GetNextAssoc(pos, key, pCntrl);
pCntrl->AddRefAll();
controlObjects.AddTail(pCntrl);
}
}
//loop through the different control objects and send the event to each
while (!controlObjects.IsEmpty())
{
CNTEventProvider* pCntrl = controlObjects.RemoveTail();
IWbemServices* ns = pCntrl->GetNamespace();
IWbemObjectSink* es = pCntrl->GetEventSink();
es->Indicate(1, &evtObj);
es->Release();
ns->Release();
pCntrl->ReleaseAll();
}
}
BOOL CEventProviderManager::InitialiseMonitorArray()
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventProviderManager::InitialiseMonitorArray\r\n");
)
// open registry for log names
HKEY hkResult;
LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
EVENTLOG_BASE, 0,
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
&hkResult);
if (status != ERROR_SUCCESS)
{
DWORD t_LastError = GetLastError () ;
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager::InitialiseMonitorArray:Failed to open registry key %s , %lx: \r\n" ,
EVENTLOG_BASE ,
status
) ;
)
// indicate error
return FALSE;
}
DWORD iValue = 0;
WCHAR logname[MAX_PATH+1];
DWORD lognameSize = MAX_PATH+1;
CArray<CStringW*, CStringW*> logfiles;
//usually three logfiles, grow in 10s!
logfiles.SetSize(3, 10);
// read all entries under this key to find all logfiles...
while ((status = RegEnumKey(hkResult, iValue, logname, lognameSize)) != ERROR_NO_MORE_ITEMS)
{
// if error during read
if (status != ERROR_SUCCESS)
{
RegCloseKey(hkResult);
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager::InitialiseMonitorArray:Failed to enumerate registry subkeys %s : \r\n" ,
EVENTLOG_BASE
) ;
)
// indicate error
return FALSE;
}
//store the logfilename
CStringW* logfile = new CStringW(logname);
logfiles.SetAtGrow(iValue, logfile);
// read next parameter
iValue++;
} // end while
RegCloseKey(hkResult);
m_monitorArray = new CEventLogMonitor*[NUM_THREADS];
memset(m_monitorArray, 0, NUM_THREADS * sizeof(CEventLogMonitor*));
//use the array
#if NUM_THREADS > 1
//multi-threaded monitor
//TO DO: Partition the eventlogs to the monitors
//and start each monitor
#else
//single threaded monitor
try
{
m_monitorArray[0] = new CEventLogMonitor(this, logfiles);
m_monitorArray[0]->AddRef();
(*m_monitorArray)->BeginThread();
(*m_monitorArray)->WaitForStartup();
(*m_monitorArray)->StartMonitoring();
}
catch (...)
{
if (m_monitorArray[0])
{
m_monitorArray[0]->Release();
}
delete [] m_monitorArray;
m_monitorArray = NULL;
throw;
}
#endif
//delete array contents AFTER threads startup!
LONG count = logfiles.GetSize();
if (count > 0)
{
for (LONG x = 0; x < count; x++)
{
delete logfiles[x];
}
logfiles.RemoveAll();
}
return TRUE;
}
void CEventProviderManager::DestroyMonitorArray()
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventProviderManager::DestroyMonitorArray\r\n");
)
if (NULL != m_monitorArray)
{
for (int x=0; x < NUM_THREADS; x++)
{
m_monitorArray[x]->PostSignalThreadShutdown();
m_monitorArray[x]->Release();
m_monitorArray[x] = NULL;
}
delete [] m_monitorArray;
m_monitorArray = NULL;
}
}
BSTR CEventProviderManager::GetLastBootTime()
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventProviderManager::GetLastBootTime\r\n");
)
if (!m_BootTimeString.IsEmpty())
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventProviderManager::GetLastBootTime returning %s\r\n",
m_BootTimeString
);
)
return m_BootTimeString.AllocSysString();
}
HKEY hKeyPerflib009;
BSTR retStr = NULL;
SYSTEM_TIMEOFDAY_INFORMATION t_TODInformation;
if ( NT_SUCCESS(NtQuerySystemInformation(SystemTimeOfDayInformation,
&t_TODInformation,
sizeof(t_TODInformation),
NULL)) )
{
FILETIME t_ft;
memcpy(&t_ft, &t_TODInformation.BootTime, sizeof(t_TODInformation.BootTime));
WBEMTime wbemboottime(t_ft);
retStr = wbemboottime.GetDMTF(TRUE);
m_BootTimeString = (LPCWSTR)(retStr);
}
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"Returning from CEventProviderManager::GetLastBootTime with %s",
(retStr == NULL ? L"NULL": retStr)
) ;
)
return retStr;
}
void CEventProviderManager :: SetFirstSinceLogon(IWbemServices* ns, IWbemContext *pCtx)
{
BSTR boottmStr = GetLastBootTime();
if (boottmStr == NULL)
{
return;
}
IWbemClassObject* pObj = NULL;
HRESULT hr = WBEM_E_OUT_OF_MEMORY ;
BSTR bstrPath = SysAllocString (CONFIG_INSTANCE);
if ( bstrPath )
{
hr = ns->GetObject(bstrPath, 0, pCtx, &pObj, NULL);
SysFreeString(bstrPath);
}
if ( hr == WBEM_E_NOT_FOUND )
{
hr = WBEM_E_OUT_OF_MEMORY ;
bstrPath = SysAllocString (CONFIG_CLASS);
if ( bstrPath )
{
hr = ns->GetObject(bstrPath, 0, pCtx, &pObj, NULL);
SysFreeString(bstrPath);
}
if (FAILED(hr))
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->Write (
L"\r\n"
) ;
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager :: IsFirstSinceLogon: Failed to get config class"
) ;
)
}
else
{
IWbemClassObject* pInst = NULL;
hr = pObj->SpawnInstance(0, &pInst);
pObj->Release();
if (FAILED(hr))
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->Write (
L"\r\n"
) ;
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager :: IsFirstSinceLogon: Failed to spawn config instance"
) ;
)
}
else
{
VARIANT v;
VariantInit(&v);
hr = WBEM_E_OUT_OF_MEMORY ;
v.bstrVal = SysAllocString(boottmStr);;
if ( v.bstrVal )
{
v.vt = VT_BSTR;
hr = pInst->Put(LAST_BOOT_PROP, 0, &v, 0);
}
VariantClear(&v);
if (FAILED(hr))
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->Write (
L"\r\n"
) ;
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager :: IsFirstSinceLogon: Failed to put config property"
) ;
)
}
else
{
hr = ns->PutInstance(pInst, WBEM_FLAG_CREATE_ONLY, pCtx, NULL);
if (FAILED(hr))
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->Write (
L"\r\n"
) ;
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager :: IsFirstSinceLogon: Failed to put new config instance"
) ;
)
}
else
{
m_IsFirstSinceLogon = TRUE;
}
}
pInst->Release();
}
}
}
else
{
VARIANT v;
hr = pObj->Get(LAST_BOOT_PROP, 0, &v, NULL, NULL);
if (FAILED(hr))
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->Write (
L"\r\n"
) ;
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager :: IsFirstSinceLogon: Failed to get config's last boot time from instance"
) ;
)
}
else
{
if (v.vt == VT_BSTR)
{
if (wcscmp(v.bstrVal, boottmStr) == 0)
{
}
else
{
VariantClear(&v);
VariantInit(&v);
hr = WBEM_E_OUT_OF_MEMORY ;
v.bstrVal = SysAllocString(boottmStr);
if ( v.bstrVal )
{
v.vt = VT_BSTR;
hr = pObj->Put(LAST_BOOT_PROP, 0, &v, 0);
}
VariantClear (&v) ;
if (FAILED(hr))
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->Write (
L"\r\n"
) ;
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager :: IsFirstSinceLogon: Failed to put config property in instance"
) ;
)
}
else
{
hr = ns->PutInstance(pObj, WBEM_FLAG_UPDATE_ONLY, pCtx, NULL);
if (FAILED(hr))
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->Write (
L"\r\n"
) ;
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager :: IsFirstSinceLogon: Failed to put config instance"
) ;
)
}
else
{
m_IsFirstSinceLogon = TRUE;
}
}
}
}
else
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->Write (
L"\r\n"
) ;
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventProviderManager :: IsFirstSinceLogon: one (maybe both) boot times are of wrong type"
) ;
)
}
VariantClear(&v);
}
pObj->Release();
}
SysFreeString(boottmStr);
}
CEventLogMonitor::CEventLogMonitor(CEventProviderManager* parentptr, CArray<CStringW*, CStringW*>& logs)
: ProvThreadObject(EVENTTHREADNAME, m_PollTimeOut), m_LogCount(logs.GetSize()), m_Logs(NULL),
m_bMonitoring(FALSE), m_pParent(parentptr), m_Ref(0)
{
InterlockedIncrement(&(CNTEventProviderClassFactory::objectsInProgress));
// create array from argument
if (m_LogCount > 0)
{
//usually three logfiles, grow in 10s!
m_LogNames.SetSize(3, 10);
for (LONG x = 0; x < m_LogCount; x++)
{
CStringW* logfile = new CStringW( * logs.GetAt ( x ) );
m_LogNames.SetAtGrow(x, logfile);
}
}
}
CEventLogMonitor::~CEventLogMonitor()
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventLogMonitor::~CEventLogMonitor\r\n");
)
InterlockedDecrement(&(CNTEventProviderClassFactory::objectsInProgress));
//delete array contents
LONG count = m_LogNames.GetSize();
if (count > 0)
{
for (LONG x = 0; x < count; x++)
{
delete m_LogNames[x];
}
m_LogNames.RemoveAll();
}
}
void CEventLogMonitor::Poll()
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventLogMonitor::Poll\r\n");
)
if (m_Logs != NULL)
{
for (ULONG x = 0; x < m_LogCount; x++)
{
if (m_Logs[x]->IsValid())
{
m_Logs[x]->Process();
}
}
}
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"leaving CEventLogMonitor::Poll\r\n");
)
}
void CEventLogMonitor::TimedOut()
{
if (m_bMonitoring)
{
Poll();
}
}
void CEventLogMonitor::StartMonitoring()
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventLogMonitor::StartMonitoring()"
) ;
)
//single threaded monitor
//cheat, check for logon event
//if we go multi-threaded this will
//have to be done by the manager
if (m_Logs)
{
DWORD logtime = 0;
if (m_pParent->IsFirstSinceLogon())
{
//find the System log
for (ULONG x = 0; x < m_LogCount; x++)
{
if ((m_Logs[x]->IsValid()) && (0 == _wcsicmp(L"System", m_Logs[x]->GetLogName())))
{
DWORD dwRecID;
logtime = m_Logs[x]->FindOldEvent(LOGON_EVTID, LOGON_SOURCE, &dwRecID, LOGON_TIME);
if (0 != logtime)
{
m_Logs[x]->SetProcessRecord(dwRecID);
m_Logs[x]->Process();
}
else
{
if (!m_Logs[x]->IsValid())
{
m_Logs[x]->RefreshHandle();
if (m_Logs[x]->IsValid())
{
m_Logs[x]->ReadLastRecord();
}
}
else
{
m_Logs[x]->ReadLastRecord();
}
}
break;
}
}
if (0 != logtime)
{
time_t tm;
time(&tm);
for (x = 0; x < m_LogCount; x++)
{
if ((m_Logs[x]->IsValid()) && (0 != _wcsicmp(L"System", m_Logs[x]->GetLogName())))
{
DWORD dwRecID;
m_Logs[x]->FindOldEvent(0, NULL, &dwRecID, tm - logtime);
if (m_Logs[x]->IsValid())
{
m_Logs[x]->SetProcessRecord(dwRecID);
m_Logs[x]->Process();
}
}
}
}
}
//now start the monitors monitoring!
for (ULONG x = 0; x < m_LogCount; x++)
{
if (m_Logs[x]->IsValid())
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventLogMonitor::StartMonitoring() monitoring log %d of %d logs\r\n",
x, m_LogCount
) ;
)
ScheduleTask(*(m_Logs[x]));
}
}
}
m_bMonitoring = TRUE;
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"leaving CEventLogMonitor::StartMonitoring()\r\n"
) ;
)
}
void CEventLogMonitor::Initialise()
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventLogMonitor::Initialise\r\n"
) ;
)
AddRef();
InitializeCom();
//for each logfilename create a logfile
if (m_LogCount != 0)
{
m_Logs = new CMonitoredEventLogFile*[m_LogCount];
BOOL bValid = FALSE;
for (ULONG x = 0; x < m_LogCount; x++)
{
CStringW* tmp = m_LogNames.GetAt(x);
m_Logs[x] = new CMonitoredEventLogFile(m_pParent, *tmp);
if ( !( (m_Logs[x])->IsValid() ) )
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventLogMonitor::Initialise logfile %d named %s is invalid\r\n",
x, *tmp
) ;
)
}
else
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventLogMonitor::Initialise logfile %d named %s is valid\r\n",
x, *tmp
) ;
)
bValid = TRUE;
}
}
if (!bValid)
{
delete [] m_Logs;
m_Logs = NULL;
}
}
else
{
//should never happen
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"CEventLogMonitor::Initialise() !!!NO LOGFILES TO MONITOR!!!\r\n"
) ;
)
}
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
_T(__FILE__),__LINE__,
L"leaving CEventLogMonitor::Initialise()\r\n"
) ;
)
}
void CEventLogMonitor::Uninitialise()
{
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventLogMonitor::Uninitialise\r\n");
)
if (m_Logs != NULL)
{
for (ULONG x = 0; x < m_LogCount; x++)
{
delete m_Logs[x];
}
delete [] m_Logs;
}
CoUninitialize();
Release();
DebugOut(
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine(_T(__FILE__),__LINE__,
L"CEventLogMonitor::Uninitialise: Leaving method\r\n");
)
}
LONG CEventLogMonitor ::AddRef(void)
{
return InterlockedIncrement ( & m_Ref ) ;
}
LONG CEventLogMonitor ::Release(void)
{
LONG t_Ref ;
if ( ( t_Ref = InterlockedDecrement ( & m_Ref ) ) == 0 )
{
delete this ;
return 0 ;
}
else
{
return t_Ref ;
}
}