windows-nt/Source/XPSP1/NT/termsrv/setup/tsdiag/evntutl/event.cpp
2020-09-26 16:20:57 +08:00

494 lines
14 KiB
C++

/////////////////////////////////////////////////////////////////////////////
//
// Copyright: Microsoft Corp. 1997-1999. All rights reserved
//
/////////////////////////////////////////////////////////////////////////////
// Event.cpp : Implementation of CEvent
#include "stdafx.h"
#include "Evntutl.h"
#include "Event.h"
/////////////////////////////////////////////////////////////////////////////
// CEvent
STDMETHODIMP CEvent::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IEvent
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
/*
Function: get_Server
Inputs: empty BSTR
Outputs: BSTR containing the Description for the Event (calculated)
Purpose: Allows user to access the description for an Event
*/
STDMETHODIMP CEvent::get_Description(BSTR *pVal)
{
HRESULT hr = S_OK;
unsigned int i;
if (pVal)
{
if (m_Description.length() == 0)
{
hr = CheckDefaultDescription(m_ppArgList);
if (SUCCEEDED(hr)) *pVal = m_Description.copy();
if (m_ppArgList)
{
// delete the ArgList
for (i=0;i<m_NumberOfStrings;i++)
delete [] m_ppArgList[i];
delete []m_ppArgList;
m_ppArgList = NULL;
}
}
}
else hr = E_POINTER;
return hr;
}
/*
Function: get_Source
Inputs: empty BSTR
Outputs: BSTR containing the name of the component which caused the Event
Purpose: Allows user to access the name of the component which caused the Event
*/
STDMETHODIMP CEvent::get_Source(BSTR *pVal)
{
HRESULT hr = S_OK;
if (pVal) *pVal = m_SourceName.copy();
else hr = E_POINTER;
return hr;
}
/*
Function: get_User
Inputs: empty BSTR
Outputs: BSTR containing the name and domain of the user who caused the Event
Purpose: Allows user to access the name and domain of the user who caused the Event
Notes: The first time this function is called, it will do a SID lookup
*/
STDMETHODIMP CEvent::get_User(BSTR *pVal)
{
HRESULT hr = S_OK;
if (pVal)
{
if (m_UserName.length() == 0)
{
SetUser();
}
*pVal = m_UserName.copy();
}
else hr = E_POINTER;
return hr;
}
/*
Function: get_ComputerName
Inputs: empty BSTR
Outputs: BSTR containing the name of the server on which the Event occured
Purpose: Allows user to access the name of the the server on which the Event occured
*/
STDMETHODIMP CEvent::get_ComputerName(BSTR *pVal)
{
HRESULT hr = S_OK;
if (pVal) *pVal = m_ComputerName.copy();
else hr = E_POINTER;
return hr;
}
/*
Function: get_EventID
Inputs: empty long
Outputs: long containing the ID of the Event
Purpose: Allows user to access the ID which can be used to lookup a message for the event
Notes: Since description is provided, this function is not very useful, however,
it is provided for completeness
*/
STDMETHODIMP CEvent::get_EventID(long *pVal)
{
HRESULT hr = S_OK;
// m_EventID = m_EventID & 0xFFFF; // The EventLog viewer uses this mask before displaying ID's
if (pVal) *pVal = m_EventID;
else hr = E_POINTER;
return hr;
}
/*
Function: get_Category
Inputs: empty long
Outputs: long containing the category ID for the event
Purpose: Allows user to access the category ID for the event
*/
STDMETHODIMP CEvent::get_Category(long *pVal)
{
HRESULT hr = S_OK;
if (pVal) *pVal = m_EventCategory;
else hr = E_POINTER;
return hr;
}
/*
Function: get_EventType
Inputs: empty enumeration
Outputs: enumeration containing the type of event that occured
Purpose: Allows user to access the type of event that occured
*/
STDMETHODIMP CEvent::get_EventType(eEventType *pVal)
{
HRESULT hr = S_OK;
if (pVal) *pVal = m_EventType;
else hr = E_POINTER;
return hr;
}
/*
Function: get_OccurenceTime
Inputs: empty DATE structure
Outputs: DATE structure containing the local system time when the event occured
Purpose: Allows user to access the time when the event occured
*/
STDMETHODIMP CEvent::get_OccurrenceTime(DATE *pVal)
{
HRESULT hr = S_OK;
if (pVal) *pVal = m_OccurrenceTime;
else hr = E_POINTER;
return hr;
}
/*
Function: get_Data
Inputs: empty variant
Outputs: variant containing an array of bytes
Purpose: Allows user to access the data set by the event. This may or may not be set,
and is frequently not useful
*/
STDMETHODIMP CEvent::get_Data(VARIANT *pVal)
{
HRESULT hr = S_OK;
if (pVal)
{
pVal->vt = VT_ARRAY | VT_UI1;
pVal->parray = m_pDataArray;
}
else hr = E_POINTER;
return hr;
}
/*
Function: Init
Inputs: pointer to an EVENTLOGRECORD structure
Outputs: does not modify input
Purpose: fill Event object properties which do not require loading external libs
*/
HRESULT CEvent::Init(EVENTLOGRECORD* pEventStructure, const LPCTSTR szEventLogName)
{
HRESULT hr = S_OK;
m_EventLogName = szEventLogName;
hr = ParseEventBlob(pEventStructure);
return hr;
}
/*
Function: ParseEventBlob
Inputs: pointer to an EVENTLOGRECORD structure
Outputs: does not modify input
Purpose: Parse an EVENTLOGRECORD and set the appropriate internal structures of Event
*/
HRESULT CEvent::ParseEventBlob(EVENTLOGRECORD* pEventStructure)
{
HRESULT hr = S_OK;
wchar_t* wTempString;
BYTE* pSourceName;
BYTE* pComputerName;
SAFEARRAYBOUND rgsabound[1];
ULONG StringsToRetrieve = 0, CharsRead = 0, i = 0;
long Index[1];
BYTE pTemp;
m_EventID = pEventStructure->EventID;
m_EventCategory = pEventStructure->EventCategory;
switch (pEventStructure->EventType)
{
case EVENTLOG_ERROR_TYPE:
m_EventType = ErrorEvent;
break;
case EVENTLOG_WARNING_TYPE:
m_EventType = WarningEvent;
break;
case EVENTLOG_INFORMATION_TYPE:
m_EventType = InformationEvent;
break;
case EVENTLOG_AUDIT_SUCCESS:
m_EventType = AuditSuccess;
break;
case EVENTLOG_AUDIT_FAILURE:
m_EventType = AuditFailure;
break;
default:
hr = E_FAIL;
}
// parse strings from the memory blob
// Set source name
pSourceName = (BYTE*) &(pEventStructure->DataOffset) + sizeof(pEventStructure->DataOffset);
wTempString = (wchar_t*)pSourceName;
m_SourceName = wTempString;
// Set computer name
pComputerName = (BYTE*)pSourceName + ((wcslen(wTempString)+1) * sizeof(wchar_t));
wTempString = (wchar_t*)pComputerName;
m_ComputerName = wTempString;
// Set SID
if ((pEventStructure->StringOffset - pEventStructure->UserSidOffset) != 0)
{
m_pSid = new BYTE[pEventStructure->UserSidLength]; // scope = CEvent, deleted in ~CEvent() or SetSID() whichever comes first
if (m_pSid != NULL) {
for (i = 0; i<pEventStructure->UserSidLength; i++)
m_pSid[i] = (BYTE)(*((BYTE*)pEventStructure + pEventStructure->UserSidOffset + i * sizeof(BYTE)));
}
}
// Set Occurence time
// this code is copied from MSDN
FILETIME FileTime, LocalFileTime;
SYSTEMTIME SysTime;
__int64 lgTemp;
__int64 SecsTo1970 = 116444736000000000;
lgTemp = Int32x32To64(pEventStructure->TimeGenerated,10000000) + SecsTo1970;
FileTime.dwLowDateTime = (DWORD) lgTemp;
FileTime.dwHighDateTime = (DWORD)(lgTemp >> 32);
FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
FileTimeToSystemTime(&LocalFileTime, &SysTime);
if(!SystemTimeToVariantTime(&SysTime, &m_OccurrenceTime)) hr = GetLastError();
// Set Data (create and fill a SafeArray)
if (pEventStructure->DataLength>0)
{
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = pEventStructure->DataLength;
m_pDataArray = SafeArrayCreate(VT_UI1, 1, rgsabound);
for (i=0;i<pEventStructure->DataLength;i++)
{
Index[0] = i;
pTemp = (BYTE) (pEventStructure->DataOffset + i * sizeof(BYTE));
hr = SafeArrayPutElement(m_pDataArray, Index, &pTemp);
if (FAILED(hr)) i = pEventStructure->DataLength;
}
}
// Set the description
m_Description = "";
if (m_SourceName.length() != 0)
{
// prepare the ArgList
m_NumberOfStrings = pEventStructure->NumStrings;
m_ppArgList = new wchar_t*[m_NumberOfStrings]; // scope = CEvent, deleted when ~CEvent or get_Description is called whichever is first
for (i=0;i<m_NumberOfStrings;i++)
m_ppArgList[i] = new wchar_t[(pEventStructure->DataOffset - pEventStructure->StringOffset)]; // can't be larger than the length of all the strings we got
for (i=0;i<m_NumberOfStrings;i++)
{
wTempString = (wchar_t*) (((BYTE*)(pEventStructure)) + pEventStructure->StringOffset + CharsRead * sizeof(wchar_t));
wcscpy(m_ppArgList[i], wTempString);
CharsRead = CharsRead + wcslen(wTempString) + 1; // + 1 for the null
}
}
else // if there is no module to load a default description, just put all the string args in the description
{
StringsToRetrieve = pEventStructure->NumStrings;
while (StringsToRetrieve > 0)
{
wTempString = (wchar_t*) (((BYTE*)(pEventStructure)) + pEventStructure->StringOffset + CharsRead * sizeof(wchar_t));
m_Description = m_Description + " " + wTempString;
CharsRead = CharsRead + wcslen(wTempString) + 1; // + 1 for the null
StringsToRetrieve--;
}
}
return hr;
}
/*
Function: CheckDefaultDescription
Inputs: pointer pointer to a wide character
Outputs: does not modify input
Purpose: format a message from an EventID, set of input strings, and a source module
*/
HRESULT CEvent::CheckDefaultDescription(wchar_t** Arguments)
{
HRESULT hr = S_OK;
BYTE* wMessagePath = NULL;
ULONG BufferSize = 40000;
ULONG* lPathLength = NULL;
wchar_t* wOrigionalPath = NULL;
wchar_t* wExpandedPath = NULL;
wchar_t* pBuffer = NULL;
_bstr_t btRegKey;
_bstr_t btTempString;
HMODULE hiLib;
HKEY hKey;
try{
lPathLength = new ULONG;
if (lPathLength)
{
*lPathLength = 256*2;
wMessagePath = new BYTE[*lPathLength];
if (wMessagePath)
{
// get registry value for Source module path
btRegKey = "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\" + m_EventLogName;
btRegKey = btRegKey + "\\";
btRegKey = btRegKey + m_SourceName;
hr = RegOpenKey(HKEY_LOCAL_MACHINE, btRegKey, &hKey);
if (hKey)
{
hr = RegQueryValueEx(hKey, L"EventMessageFile", NULL, NULL, wMessagePath, lPathLength);
if (hr == 0)
{
wOrigionalPath = (wchar_t*) wMessagePath;
wExpandedPath = new wchar_t[(int)*lPathLength];
if (wExpandedPath)
{
ExpandEnvironmentStrings(wOrigionalPath, wExpandedPath, *lPathLength);
btTempString = wExpandedPath;
// open the Source module
hiLib = LoadLibraryEx(btTempString, NULL, LOAD_LIBRARY_AS_DATAFILE);
hr = GetLastError();
if (hiLib)
{
pBuffer = new wchar_t[BufferSize];
if (pBuffer)
{
SetLastError(0);
FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
hiLib, m_EventID, 0, pBuffer, BufferSize,
reinterpret_cast<va_list*>(Arguments));
hr = HRESULT_FROM_WIN32(GetLastError());
m_Description = m_Description + pBuffer;
delete []pBuffer;
pBuffer = NULL;
}
else hr = E_OUTOFMEMORY;
FreeLibrary(hiLib);
}
delete [] wExpandedPath;
wExpandedPath = NULL;
}
else hr = E_OUTOFMEMORY;
}
else hr = HRESULT_FROM_WIN32(hr);
RegCloseKey(hKey);
}
else hr = HRESULT_FROM_WIN32(hr);
delete []wMessagePath;
wMessagePath = NULL;
}
else hr = E_OUTOFMEMORY;
delete lPathLength;
lPathLength = NULL;
}
else hr = E_OUTOFMEMORY;
} catch(...){
if (lPathLength != NULL) {
delete lPathLength;
}
if (wMessagePath != NULL) {
delete []wMessagePath;
}
if (wExpandedPath != NULL) {
delete [] wExpandedPath;
}
if (pBuffer != NULL) {
delete []pBuffer;
}
}
return hr;
}
/*
Function: SetUser
Inputs: none
Outputs: HRESULT indicating what error if any occured
Purpose: finds alias and domain for a given SID
*/
HRESULT CEvent::SetUser()
{
HRESULT hr = S_OK;
SID_NAME_USE SidNameUse;
wchar_t* wUserName;
wchar_t* wDomainName;
SID* pSid;
unsigned long UserNameLength = 256;
// Set user name and sid
if (m_pSid !=NULL)
{
pSid = (SID*)m_pSid;
wUserName = new wchar_t[UserNameLength];
if (wUserName)
{
wDomainName = new wchar_t[UserNameLength];
if (wDomainName)
{
m_UserName = "";
if (LookupAccountSid(NULL, pSid, wUserName, &UserNameLength, wDomainName,
&UserNameLength, &SidNameUse))
m_UserName = m_UserName + wDomainName + L"\\" + wUserName;
else hr = HRESULT_FROM_WIN32(GetLastError());
delete []wDomainName;
}
else hr = E_OUTOFMEMORY;
delete []wUserName;
}
else hr = E_OUTOFMEMORY;
delete []m_pSid;
m_pSid = NULL;
}
return hr;
}