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.
1991 lines
49 KiB
1991 lines
49 KiB
//***************************************************************************
|
|
//
|
|
// NTEVTLOGR.CPP
|
|
//
|
|
// Module: WBEM NT EVENT PROVIDER
|
|
//
|
|
// Purpose: Contains the Eventlog record classes
|
|
//
|
|
// Copyright (c) 1996-2002 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
//***************************************************************************
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <time.h>
|
|
#include <wbemtime.h>
|
|
#include <Ntdsapi.h>
|
|
#include <Sddl.h>
|
|
|
|
#include <autoptr.h>
|
|
#include <scopeguard.h>
|
|
|
|
#define MAX_INSERT_OPS 100
|
|
|
|
CEventlogRecord::CEventlogRecord(const wchar_t* logfile, const EVENTLOGRECORD* pEvt, IWbemServices* ns,
|
|
IWbemClassObject* pClass, IWbemClassObject* pAClass)
|
|
: m_nspace(NULL), m_pClass(NULL), m_pAClass(NULL)
|
|
{
|
|
m_EvtType = 0;
|
|
m_Data = NULL;
|
|
m_Obj = NULL;
|
|
m_NumStrs = 0;
|
|
m_DataLen = 0;
|
|
m_nspace = ns;
|
|
|
|
if (m_nspace != NULL)
|
|
{
|
|
m_nspace->AddRef();
|
|
}
|
|
else
|
|
{
|
|
m_pClass = pClass;
|
|
|
|
if (m_pClass != NULL)
|
|
{
|
|
m_pClass->AddRef();
|
|
}
|
|
|
|
m_pAClass = pAClass;
|
|
|
|
if (m_pAClass != NULL)
|
|
{
|
|
m_pAClass->AddRef();
|
|
}
|
|
}
|
|
if ((NULL == logfile) || ((m_pClass == NULL) && (m_nspace == NULL)))
|
|
{
|
|
m_Valid = FALSE;
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::CEventlogRecord:Created INVALID Record\r\n"
|
|
) ;
|
|
)
|
|
}
|
|
else
|
|
{
|
|
m_Logfile = logfile;
|
|
m_Valid = Init(pEvt);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
CEventlogRecord::~CEventlogRecord()
|
|
{
|
|
if (m_pClass != NULL)
|
|
{
|
|
m_pClass->Release();
|
|
}
|
|
|
|
if (m_pAClass != NULL)
|
|
{
|
|
m_pAClass->Release();
|
|
}
|
|
|
|
if (m_nspace != NULL)
|
|
{
|
|
m_nspace->Release();
|
|
}
|
|
|
|
for (LONG x = 0; x < m_NumStrs; x++)
|
|
{
|
|
delete [] m_InsStrs[x];
|
|
}
|
|
|
|
if (m_Data != NULL)
|
|
{
|
|
delete [] m_Data;
|
|
}
|
|
|
|
if (m_Obj != NULL)
|
|
{
|
|
m_Obj->Release();
|
|
}
|
|
}
|
|
|
|
BOOL CEventlogRecord::Init(const EVENTLOGRECORD* pEvt)
|
|
{
|
|
if (NULL == pEvt)
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::Init:No DATA return FALSE\r\n"
|
|
) ;
|
|
)
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetInstance())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_Record = pEvt->RecordNumber;
|
|
m_EvtID = pEvt->EventID;
|
|
m_SourceName = (const wchar_t*)((UCHAR*)pEvt + sizeof(EVENTLOGRECORD));
|
|
m_CompName = (const wchar_t*)((UCHAR*)pEvt + sizeof(EVENTLOGRECORD)) + wcslen(m_SourceName) + 1;
|
|
SetType(pEvt->EventType);
|
|
m_Category = pEvt->EventCategory;
|
|
SetTimeStr(m_TimeGen, pEvt->TimeGenerated);
|
|
SetTimeStr(m_TimeWritten, pEvt->TimeWritten);
|
|
|
|
if (pEvt->UserSidLength > 0)
|
|
{
|
|
PSID pSid = NULL;
|
|
pSid = (PSID)((UCHAR*)pEvt + pEvt->UserSidOffset);
|
|
|
|
if ( pSid && IsValidSid ( pSid ) )
|
|
{
|
|
SetUser( pSid );
|
|
}
|
|
}
|
|
|
|
if (pEvt->NumStrings)
|
|
{
|
|
//Must have an element for every expected insertion string
|
|
//don't know how many that is so create max size array and
|
|
//intitialize all to NULL
|
|
memset(m_InsStrs, 0, MAX_NUM_OF_INS_STRS * sizeof(wchar_t*));
|
|
|
|
const wchar_t* pstr = (const wchar_t*)((UCHAR*)pEvt + pEvt->StringOffset);
|
|
|
|
for (WORD x = 0; x < pEvt->NumStrings; x++)
|
|
{
|
|
LONG len = wcslen(pstr) + 1;
|
|
m_InsStrs[x] = new wchar_t[len];
|
|
m_NumStrs++;
|
|
StringCchCopyW ( m_InsStrs[x], len, pstr );
|
|
pstr += len;
|
|
}
|
|
}
|
|
|
|
SetMessage();
|
|
|
|
if (pEvt->DataLength)
|
|
{
|
|
m_Data = new UCHAR[pEvt->DataLength];
|
|
m_DataLen = pEvt->DataLength;
|
|
memcpy((void*)m_Data, (void*)((UCHAR*)pEvt + pEvt->DataOffset), pEvt->DataLength);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CEventlogRecord::GenerateInstance(IWbemClassObject** ppInst)
|
|
{
|
|
if (ppInst == NULL)
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GenerateInstance:Invalid parameter\r\n"
|
|
) ;
|
|
)
|
|
return FALSE;
|
|
}
|
|
|
|
*ppInst = NULL;
|
|
|
|
if (!m_Valid)
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GenerateInstance:Invalid record\r\n"
|
|
) ;
|
|
)
|
|
return FALSE;
|
|
}
|
|
|
|
if (!SetProperty(LOGFILE_PROP, m_Logfile))
|
|
{
|
|
m_Valid = FALSE;
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GenerateInstance:Failed to set key\r\n"
|
|
) ;
|
|
)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GenerateInstance:Log: %s\r\n", m_Logfile
|
|
) ;
|
|
)
|
|
}
|
|
|
|
if (!SetProperty(RECORD_PROP, m_Record))
|
|
{
|
|
m_Valid = FALSE;
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GenerateInstance:Failed to set key\r\n"
|
|
) ;
|
|
)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GenerateInstance:Record: %d\r\n", m_Record
|
|
) ;
|
|
)
|
|
}
|
|
|
|
SetProperty(TYPE_PROP, m_Type);
|
|
SetProperty(EVTTYPE_PROP, (DWORD)m_EvtType);
|
|
|
|
if (!m_SourceName.IsEmpty())
|
|
{
|
|
SetProperty(SOURCE_PROP, m_SourceName);
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GenerateInstance:Source: %s\r\n", m_SourceName
|
|
) ;
|
|
)
|
|
}
|
|
|
|
SetProperty(EVTID_PROP, m_EvtID);
|
|
SetProperty(EVTID2_PROP, (m_EvtID & 0xFFFF));
|
|
|
|
if (!m_TimeGen.IsEmpty())
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GenerateInstance:TimeGenerated: %s\r\n", m_TimeGen
|
|
) ;
|
|
)
|
|
SetProperty(GENERATED_PROP, m_TimeGen);
|
|
}
|
|
|
|
if (!m_TimeWritten.IsEmpty())
|
|
{
|
|
SetProperty(WRITTEN_PROP, m_TimeWritten);
|
|
}
|
|
|
|
if (!m_CompName.IsEmpty())
|
|
{
|
|
SetProperty(COMPUTER_PROP, m_CompName);
|
|
}
|
|
|
|
if (!m_User.IsEmpty())
|
|
{
|
|
SetProperty(USER_PROP, m_User);
|
|
}
|
|
|
|
if (!m_Message.IsEmpty())
|
|
{
|
|
SetProperty(MESSAGE_PROP, m_Message);
|
|
}
|
|
|
|
if (!m_CategoryString.IsEmpty())
|
|
{
|
|
SetProperty(CATSTR_PROP, m_CategoryString);
|
|
}
|
|
|
|
SetProperty(CATEGORY_PROP, (DWORD)m_Category);
|
|
|
|
VARIANT v;
|
|
|
|
if (m_Data != NULL)
|
|
{
|
|
SAFEARRAYBOUND rgsabound[1];
|
|
SAFEARRAY* psa = NULL;
|
|
UCHAR* pdata = NULL;
|
|
rgsabound[0].lLbound = 0;
|
|
VariantInit(&v);
|
|
rgsabound[0].cElements = m_DataLen;
|
|
psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
|
|
if (NULL != psa)
|
|
{
|
|
v.vt = VT_ARRAY|VT_UI1;
|
|
v.parray = psa;
|
|
|
|
if (SUCCEEDED(SafeArrayAccessData(psa, (void **)&pdata)))
|
|
{
|
|
memcpy((void *)pdata, (void *)m_Data, m_DataLen);
|
|
SafeArrayUnaccessData(psa);
|
|
m_Obj->Put(DATA_PROP, 0, &v, 0);
|
|
}
|
|
else
|
|
{
|
|
VariantClear (&v) ;
|
|
return FALSE ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VariantClear(&v);
|
|
return FALSE ;
|
|
}
|
|
|
|
VariantClear(&v);
|
|
}
|
|
|
|
if (0 != m_NumStrs)
|
|
{
|
|
SAFEARRAYBOUND rgsabound[1];
|
|
SAFEARRAY* psa = NULL;
|
|
BSTR* pBstr = NULL;
|
|
rgsabound[0].lLbound = 0;
|
|
VariantInit(&v);
|
|
rgsabound[0].cElements = m_NumStrs;
|
|
|
|
psa = SafeArrayCreate(VT_BSTR, 1, rgsabound);
|
|
if (NULL != psa)
|
|
{
|
|
v.vt = VT_ARRAY|VT_BSTR;
|
|
v.parray = psa;
|
|
|
|
if (SUCCEEDED(SafeArrayAccessData(psa, (void **)&pBstr)))
|
|
{
|
|
for (LONG x = 0; x < m_NumStrs; x++)
|
|
{
|
|
pBstr[x] = SysAllocString(m_InsStrs[x]);
|
|
if ( NULL == pBstr[x] )
|
|
{
|
|
SafeArrayUnaccessData(psa);
|
|
VariantClear (&v) ;
|
|
return FALSE ;
|
|
}
|
|
}
|
|
|
|
SafeArrayUnaccessData(psa);
|
|
m_Obj->Put(INSSTRS_PROP, 0, &v, 0);
|
|
}
|
|
else
|
|
{
|
|
VariantClear (&v) ;
|
|
return FALSE ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VariantClear(&v);
|
|
return FALSE ;
|
|
}
|
|
|
|
VariantClear(&v);
|
|
}
|
|
|
|
*ppInst = m_Obj;
|
|
m_Obj->AddRef();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CEventlogRecord::SetProperty(wchar_t* prop, CStringW val)
|
|
{
|
|
VARIANT v;
|
|
VariantInit(&v);
|
|
v.vt = VT_BSTR;
|
|
v.bstrVal = val.AllocSysString();
|
|
|
|
HRESULT hr = m_Obj->Put(prop, 0, &v, 0);
|
|
VariantClear(&v);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::SetProperty:Failed to set %s with %s\r\n",
|
|
prop, val
|
|
) ;
|
|
)
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CEventlogRecord::SetProperty(wchar_t* prop, DWORD val)
|
|
{
|
|
VARIANT v;
|
|
VariantInit(&v);
|
|
v.vt = VT_I4;
|
|
v.lVal = val;
|
|
|
|
HRESULT hr = m_Obj->Put(prop, 0, &v, 0);
|
|
VariantClear(&v);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::SetProperty:Failed to set %s with %lx\r\n",
|
|
prop, val
|
|
) ;
|
|
)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CEventlogRecord::SetUser(PSID psidUserSid)
|
|
{
|
|
m_User = GetUser(psidUserSid);
|
|
}
|
|
|
|
ULONG CEventlogRecord::CheckInsertionStrings(HKEY hk, HKEY hkPrimary)
|
|
{
|
|
//
|
|
// If the message doesn't have any percent signs, it can't have any
|
|
// insertions.
|
|
//
|
|
|
|
if (!m_Message.IsEmpty() && !wcschr(m_Message, L'%'))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
HINSTANCE hParamModule = NULL;
|
|
|
|
CStringW paramModule = CEventLogFile::GetFileName(hk, PARAM_MODULE);
|
|
if (paramModule.IsEmpty())
|
|
{
|
|
if ( hkPrimary )
|
|
{
|
|
paramModule = CEventLogFile::GetFileName(hkPrimary, PARAM_MODULE);
|
|
}
|
|
}
|
|
|
|
if (!paramModule.IsEmpty())
|
|
{
|
|
hParamModule = GetDll(paramModule);
|
|
}
|
|
|
|
ULONG size = 0;
|
|
|
|
LPWSTR Message = NULL;
|
|
Message = new WCHAR [ ( m_Message.GetLength() + 1 ) ];
|
|
|
|
StringCchCopy ( Message, m_Message.GetLength() + 1, m_Message );
|
|
wchar_t* lpszString = Message; // set initial pointer
|
|
|
|
UINT nInsertions = 0; // limit number of recursions
|
|
|
|
while ( lpszString && *lpszString )
|
|
{
|
|
wchar_t* lpStartDigit = wcschr(lpszString, L'%');
|
|
|
|
//
|
|
// If there are no more insertion markers in the source string,
|
|
// we're done.
|
|
//
|
|
|
|
if (lpStartDigit == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// get the offset of %string from the beggining of buffer for future replacement
|
|
//
|
|
|
|
UINT nOffset = (DWORD) ( lpStartDigit - Message );
|
|
UINT nStrSize = wcslen ( lpStartDigit );
|
|
|
|
//
|
|
// Found a possible insertion marker. If it's followed by a
|
|
// number, it's an insert string. If it's followed by another
|
|
// percent, it could be a parameter insert.
|
|
//
|
|
|
|
if ( nStrSize > 1 && lpStartDigit[1] >= L'0' && lpStartDigit[1] <= L'9' )
|
|
{
|
|
// Object with percent-sign in name messes up object access audit
|
|
// This might fail because an inserted string itself contained
|
|
// text which looks like an insertion parameter, such as "%20".
|
|
// Ignore the return value and continue with further replacements.
|
|
|
|
(void) ReplaceStringInsert (
|
|
&Message,
|
|
nOffset,
|
|
&lpStartDigit,
|
|
&size
|
|
);
|
|
|
|
// set pointer to the beginning of replacement
|
|
lpszString = lpStartDigit;
|
|
|
|
//
|
|
// If we've reached the limit of insertion operations, quit.
|
|
// This shouldn't normally happen and could indicate that
|
|
// the insert strings or parameter strings are self referencing
|
|
// and would create an infinite loop.
|
|
//
|
|
|
|
if (++nInsertions >= MAX_INSERT_OPS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else if ( nStrSize > 2 && lpStartDigit[1] == '%' )
|
|
{
|
|
//
|
|
// Found %%. If that is followed by a digit, it's a parameter string.
|
|
//
|
|
|
|
if (lpStartDigit[2] >= L'0' && lpStartDigit[2] <= L'9')
|
|
{
|
|
if ( SUCCEEDED ( ReplaceParameterInsert (
|
|
hParamModule,
|
|
paramModule,
|
|
&Message,
|
|
nOffset,
|
|
&lpStartDigit,
|
|
&size
|
|
)
|
|
)
|
|
)
|
|
{
|
|
// set pointer to the beginning of replacement
|
|
lpszString = lpStartDigit;
|
|
|
|
//
|
|
// If we've reached the limit of insertion operations, quit.
|
|
// This shouldn't normally happen and could indicate that
|
|
// the insert strings or parameter strings are self referencing
|
|
// and would create an infinite loop.
|
|
//
|
|
|
|
if (++nInsertions >= MAX_INSERT_OPS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// unable to replace (error). Just keep moving.
|
|
//
|
|
|
|
lpszString++;
|
|
}
|
|
}
|
|
else if ( nStrSize > 3 && lpStartDigit[2] == '%' )
|
|
{
|
|
//
|
|
// Found %%%. If that is followed by a digit, it's a insertion string.
|
|
//
|
|
|
|
if (lpStartDigit[3] >= L'0' && lpStartDigit[3] <= L'9')
|
|
{
|
|
//
|
|
// Got %%%n, where n is a number. For compatibility with
|
|
// old event viewer, must replace this with %%x, where x
|
|
// is insertion string n. If insertion string n is itself
|
|
// a number m, this becomes %%m, which is treated as parameter
|
|
// message number m.
|
|
//
|
|
|
|
lpStartDigit += 2; // point at %n
|
|
|
|
//
|
|
// nOffset shows offset from the beginning of the buffer where
|
|
// replacement is going to happen to first % character lpStartDigit
|
|
//
|
|
// as we are chaging %%%n to be be %%x where x = %n, implementation
|
|
// needs to move offset to point to the x here to get correct replacement
|
|
//
|
|
|
|
if ( SUCCEEDED ( ReplaceStringInsert (
|
|
&Message,
|
|
nOffset+2,
|
|
&lpStartDigit,
|
|
&size
|
|
)
|
|
)
|
|
)
|
|
{
|
|
//
|
|
// set pointer to the beginning of %%x (x=%n)
|
|
//
|
|
// this operation is done by substract as lpStartDigit pointer could
|
|
// possibly change when original buffer gets reallocated
|
|
//
|
|
|
|
lpszString = lpStartDigit-2;
|
|
|
|
//
|
|
// If we've reached the limit of insertion operations, quit.
|
|
// This shouldn't normally happen and could indicate that
|
|
// the insert strings or parameter strings are self referencing
|
|
// and would create an infinite loop.
|
|
//
|
|
|
|
if (++nInsertions >= MAX_INSERT_OPS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// unable to replace (error). Just keep moving.
|
|
//
|
|
|
|
lpszString++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Got %%%x, where x is non-digit. skip first percent;
|
|
// maybe x is % and is followed by digit.
|
|
//
|
|
|
|
lpszString++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Got %%x, where x is non-digit. skip first percent;
|
|
// maybe x is % and is followed by digit.
|
|
//
|
|
|
|
lpszString++;
|
|
}
|
|
}
|
|
else if (nStrSize >= 3 && (lpStartDigit[1] == L'{') && (lpStartDigit[2] != L'S'))
|
|
{
|
|
// Parameters of form %{guid}, where {guid} is a string of
|
|
// hex digits in the form returned by ::StringFromGUID2 (e.g.
|
|
// {c200e360-38c5-11ce-ae62-08002b2b79ef}), and represents a
|
|
// unique object in the Active Directory.
|
|
//
|
|
// These parameters are only found in the security event logs
|
|
// of NT5 domain controllers. We will attempt to map the guid
|
|
// to the human-legible name of the DS object. Failing to find
|
|
// a mapping, we will leave the parameter untouched.
|
|
|
|
// look for closing }
|
|
wchar_t *strEnd = wcschr(lpStartDigit + 2, L'}');
|
|
if (!strEnd)
|
|
{
|
|
//ignore this %{?
|
|
lpszString++;
|
|
}
|
|
else
|
|
{
|
|
//guid string braces but no percent sign...
|
|
CStringW strGUID((LPWSTR)(lpStartDigit+1), (int)(strEnd - lpStartDigit));
|
|
strEnd++; // now points past '}'
|
|
|
|
wchar_t t_csbuf[MAX_COMPUTERNAME_LENGTH + 1];
|
|
DWORD t_csbuflen = MAX_COMPUTERNAME_LENGTH + 1;
|
|
|
|
if (GetComputerName(t_csbuf, &t_csbuflen))
|
|
{
|
|
CStringW temp = GetMappedGUID(t_csbuf, strGUID);
|
|
if (temp.GetLength())
|
|
{
|
|
DWORD nParmSize = strEnd - lpStartDigit;
|
|
if ( SUCCEEDED ( ReplaceSubStr (
|
|
temp,
|
|
&Message,
|
|
nOffset,
|
|
nParmSize,
|
|
&lpStartDigit,
|
|
&size
|
|
)
|
|
)
|
|
)
|
|
{
|
|
// set pointer to the beginning of replacement
|
|
lpszString = lpStartDigit;
|
|
|
|
//
|
|
// If we've reached the limit of insertion operations, quit.
|
|
// This shouldn't normally happen and could indicate that
|
|
// the insert strings or parameter strings are self referencing
|
|
// and would create an infinite loop.
|
|
//
|
|
|
|
if (++nInsertions >= MAX_INSERT_OPS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// unable to replace (error). Just keep moving.
|
|
//
|
|
|
|
lpszString = strEnd;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// couldn't get a replacement, so skip it.
|
|
lpszString = strEnd;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// couldn't get a replacement, so skip it.
|
|
lpszString = strEnd;
|
|
}
|
|
}
|
|
}
|
|
else if (nStrSize >= 3 && (lpStartDigit[1] == L'{') && (lpStartDigit[2] == L'S'))
|
|
{
|
|
//
|
|
// Parameters of form %{S}, where S is a string-ized SID returned
|
|
// by ConvertSidToStringSid, are converted to an object name if
|
|
// possible.
|
|
//
|
|
|
|
// look for closing }
|
|
wchar_t *strEnd = wcschr(lpStartDigit + 2, L'}');
|
|
if (!strEnd)
|
|
{
|
|
//ignore this %{?
|
|
lpszString++;
|
|
}
|
|
else
|
|
{
|
|
//sid string no braces or percent sign...
|
|
CStringW strSID((LPWSTR)(lpStartDigit+2), (int)(strEnd - lpStartDigit - 2));
|
|
strEnd++; // now points past '}'
|
|
PSID t_pSid = NULL;
|
|
|
|
if (ConvertStringSidToSid((LPCWSTR) strSID, &t_pSid))
|
|
{
|
|
CStringW temp = GetUser(t_pSid);
|
|
LocalFree(t_pSid);
|
|
|
|
if (temp.GetLength())
|
|
{
|
|
DWORD nParmSize = strEnd - lpStartDigit;
|
|
if ( SUCCEEDED ( ReplaceSubStr (
|
|
temp,
|
|
&Message,
|
|
nOffset,
|
|
nParmSize,
|
|
&lpStartDigit,
|
|
&size
|
|
)
|
|
)
|
|
)
|
|
{
|
|
// set pointer to the beginning of replacement
|
|
lpszString = lpStartDigit;
|
|
|
|
//
|
|
// If we've reached the limit of insertion operations, quit.
|
|
// This shouldn't normally happen and could indicate that
|
|
// the insert strings or parameter strings are self referencing
|
|
// and would create an infinite loop.
|
|
//
|
|
|
|
if (++nInsertions >= MAX_INSERT_OPS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// unable to replace (error). Just keep moving.
|
|
//
|
|
|
|
lpszString = strEnd;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// couldn't get a replacement, so skip it.
|
|
lpszString = strEnd;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// couldn't get a replacement, so skip it.
|
|
lpszString = strEnd;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Found %x where x is neither a % nor a digit. Just keep moving.
|
|
//
|
|
|
|
lpszString++;
|
|
}
|
|
}
|
|
|
|
m_Message.Empty();
|
|
m_Message = Message;
|
|
|
|
delete [] Message;
|
|
Message = NULL;
|
|
|
|
return size;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ReplaceStringInsert
|
|
//
|
|
// Synopsis: Replace the string insert (%n, where n is a number) at
|
|
// [Message + nOffset] with insert string number n from the
|
|
// event log record [lpParmBuffer].
|
|
//
|
|
// Modifies: lpStartDigit to point to replacement
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
HRESULT CEventlogRecord::ReplaceStringInsert (
|
|
LPWSTR* ppwszBuf,
|
|
ULONG nOffset,
|
|
LPWSTR* ppwszReplacement,
|
|
ULONG* pulSize
|
|
)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
*ppwszReplacement += 1; // point to start of potential digit
|
|
if (**ppwszReplacement != 0) // check to see there is
|
|
{
|
|
LPWSTR pwszEnd = NULL;
|
|
ULONG idxInsertStr = wcstoul(*ppwszReplacement, &pwszEnd, 10);
|
|
if ( idxInsertStr && idxInsertStr <= m_NumStrs )
|
|
{
|
|
DWORD nParmSize = pwszEnd - *ppwszReplacement + 1;
|
|
hr = ReplaceSubStr (
|
|
m_InsStrs [ idxInsertStr-1 ],
|
|
ppwszBuf,
|
|
nOffset,
|
|
nParmSize,
|
|
ppwszReplacement,
|
|
pulSize
|
|
);
|
|
}
|
|
|
|
//
|
|
// else
|
|
// {
|
|
// we fail as we didn't recognize replacement
|
|
// and/or insertion string
|
|
//
|
|
// see comment in CheckInsertionString
|
|
// }
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ReplaceParameterInsert
|
|
//
|
|
// Synopsis: Replace the parameter insert (double percent sign number) at
|
|
// [ppwszReplacement] with a string loaded from a parameter message
|
|
// file module.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
HRESULT CEventlogRecord::ReplaceParameterInsert (
|
|
HINSTANCE& hParamModule,
|
|
CStringW& paramModule,
|
|
LPWSTR* ppwszBuf,
|
|
ULONG nOffset,
|
|
LPWSTR* ppwszReplacement,
|
|
ULONG* pulSize
|
|
)
|
|
{
|
|
DWORD nChars = 0;
|
|
wchar_t* lpParmBuffer = NULL;
|
|
ULONG nParmSize = 0;
|
|
|
|
ULONG flFmtMsgFlags =
|
|
FORMAT_MESSAGE_IGNORE_INSERTS |
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
|
|
|
LPWSTR pwszEnd = NULL;
|
|
ULONG idxParameterStr = wcstoul(*ppwszReplacement + 2, &pwszEnd, 10);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// Allow "%%0"
|
|
if ( idxParameterStr || (L'0' == *(*ppwszReplacement + 2)))
|
|
{
|
|
if (hParamModule != NULL)
|
|
{
|
|
nChars = FormatMessage (
|
|
flFmtMsgFlags |
|
|
FORMAT_MESSAGE_FROM_HMODULE, // look thru message DLL
|
|
(LPVOID) hParamModule, // use parameter file
|
|
idxParameterStr, // parameter number to get
|
|
(ULONG) NULL, // specify no language
|
|
(LPWSTR) &lpParmBuffer, // address for buffer pointer
|
|
256, // minimum space to allocate
|
|
NULL // no inserted strings
|
|
);
|
|
}
|
|
|
|
if (nChars == 0)
|
|
{
|
|
if (hParamModule != NULL)
|
|
{
|
|
LocalFree(lpParmBuffer);
|
|
lpParmBuffer = NULL;
|
|
}
|
|
|
|
//
|
|
// It is common practice to write events with an insertion string whose
|
|
// value is %%n, where n is a win32 error code, and to specify a
|
|
// parameter message file of kernel32.dll. Unfortunately, kernel32.dll
|
|
// doesn't contain messages for all win32 error codes.
|
|
//
|
|
// So if the parameter wasn't found, and the parameter message file was
|
|
// kernel32.dll, attempt a format message from system.
|
|
//
|
|
|
|
paramModule.MakeLower();
|
|
if ( wcsstr( paramModule, L"kernel32.dll") )
|
|
{
|
|
nChars = FormatMessage (
|
|
flFmtMsgFlags |
|
|
FORMAT_MESSAGE_FROM_SYSTEM, // look thru system
|
|
NULL, // no module
|
|
idxParameterStr, // parameter number to get
|
|
(ULONG) NULL, // specify no language
|
|
(LPWSTR) &lpParmBuffer, // address for buffer pointer
|
|
256, // minimum space to allocate
|
|
NULL // no inserted strings
|
|
);
|
|
|
|
if (nChars == 0)
|
|
{
|
|
LocalFree(lpParmBuffer);
|
|
lpParmBuffer = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( lpParmBuffer )
|
|
{
|
|
try
|
|
{
|
|
DWORD nParmSize = pwszEnd - *ppwszReplacement;
|
|
hr = ReplaceSubStr (
|
|
lpParmBuffer,
|
|
ppwszBuf,
|
|
nOffset,
|
|
nParmSize,
|
|
ppwszReplacement,
|
|
pulSize
|
|
);
|
|
}
|
|
catch ( ... )
|
|
{
|
|
if ( lpParmBuffer )
|
|
{
|
|
LocalFree(lpParmBuffer);
|
|
lpParmBuffer = NULL;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
|
|
LocalFree(lpParmBuffer);
|
|
lpParmBuffer = NULL;
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
// move past whole parameter
|
|
*ppwszReplacement = pwszEnd;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ReplaceSubStr
|
|
//
|
|
// Synopsis: Replace the characters from *[ppwszInsertPoint] to just
|
|
// before [pwszSubStrEnd] with the string [pwszToInsert].
|
|
//
|
|
// Arguments: [pwszToInsert] - string to insert; may be L"" but not NULL.
|
|
// [ppwszBuf] - buffer in which insertion occurs
|
|
// [ulOffset] - point in *[ppwszBuf] to insert
|
|
// [ulCharsOld] - number of chars to replace
|
|
// [pulSize] - number of chars replaced
|
|
//
|
|
// Returns: S_OK
|
|
// E_INVALIDARG
|
|
//
|
|
// Modifies: [ppwszBuf], [pptrReplacement]
|
|
//
|
|
// Notes: The substring to be replaced must be > 0 chars in length.
|
|
//
|
|
// The replacement string can be >= 0 chars.
|
|
//
|
|
// Therefore if the substring to replace is "%%12" and the
|
|
// string to insert is "C:", on exit *[pcchRemain] will have
|
|
// been incremented by 2.
|
|
//
|
|
// If there are insufficient characters remaining to replace
|
|
// the substring with the insert string, reallocates the
|
|
// buffer.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
HRESULT CEventlogRecord::ReplaceSubStr (
|
|
LPCWSTR pwszToInsert,
|
|
LPWSTR *ppwszBuf,
|
|
ULONG nOffset,
|
|
ULONG nCharsOld,
|
|
LPWSTR *pptrReplacement,
|
|
ULONG *pulSize
|
|
)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
try
|
|
{
|
|
if ( pwszToInsert )
|
|
{
|
|
ULONG nChars = wcslen(pwszToInsert);
|
|
|
|
UINT nStrSize = wcslen(*ppwszBuf)+1; // calculate original length
|
|
UINT nNewSize = nStrSize+nChars-nCharsOld; // calculate new length
|
|
|
|
wchar_t* tmp = *ppwszBuf;
|
|
|
|
//
|
|
// do we need to reallocate?
|
|
//
|
|
|
|
if (nNewSize > nStrSize)
|
|
{
|
|
tmp = new wchar_t[nNewSize]; // allocate new buffer
|
|
if ( tmp == NULL ) // there is exception raisen in current implementation
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
*pptrReplacement -= 1; // get back to % as memory could get back
|
|
}
|
|
else
|
|
{
|
|
StringCchCopyW ( tmp, nNewSize, *ppwszBuf );
|
|
delete [] *ppwszBuf;
|
|
*ppwszBuf = tmp;
|
|
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
if ( SUCCEEDED ( hr ) )
|
|
{
|
|
*pptrReplacement = *ppwszBuf + nOffset; // point to start of current % (we are replacing)
|
|
nStrSize = wcslen(*pptrReplacement)-nCharsOld+1; // calculate length of remainder of string
|
|
|
|
//
|
|
// perform move
|
|
//
|
|
memmove((void *)(*pptrReplacement+nChars), // destination address
|
|
(void *)(*pptrReplacement+nCharsOld), // source address
|
|
nStrSize*sizeof(wchar_t)); // amount of data to move
|
|
|
|
memmove((void *)*pptrReplacement, // destination address
|
|
(void *)pwszToInsert, // source address
|
|
nChars*sizeof(wchar_t)); // amount of data to move
|
|
|
|
*pulSize += ( nChars + 1 );
|
|
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
if (*ppwszBuf)
|
|
{
|
|
delete [] *ppwszBuf;
|
|
*ppwszBuf = NULL;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
CStringW CEventlogRecord::GetUser(PSID userSid)
|
|
{
|
|
CStringW retVal;
|
|
BOOL bFound = FALSE;
|
|
|
|
MyPSID usrSID(userSid);
|
|
|
|
{
|
|
ScopeLock<CSIDMap> sl(sm_usersMap);
|
|
if (!sm_usersMap.IsEmpty() && sm_usersMap.Lookup(usrSID, retVal))
|
|
{
|
|
bFound = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
DWORD dwVersion = GetVersion();
|
|
|
|
if ( (4 < (DWORD)(LOBYTE(LOWORD(dwVersion))))
|
|
|| ObtainedSerialAccess(CNTEventProvider::g_secMutex) )
|
|
{
|
|
|
|
wchar_t szDomBuff[MAX_PATH];
|
|
wchar_t szUsrBuff[MAX_PATH];
|
|
DWORD domBuffLen = MAX_PATH;
|
|
DWORD usrBuffLen = MAX_PATH;
|
|
SID_NAME_USE snu;
|
|
|
|
if (LookupAccountSid( // lookup account name
|
|
NULL, // system to lookup account on
|
|
userSid, // pointer to SID for this account
|
|
szUsrBuff, // return account name in this buffer
|
|
&usrBuffLen, // pointer to size of account name returned
|
|
szDomBuff, // domain where account was found
|
|
&domBuffLen, //pointer to size of domain name
|
|
&snu)) // sid name use field pointer
|
|
{
|
|
retVal = szDomBuff;
|
|
retVal += L'\\';
|
|
retVal += szUsrBuff;
|
|
}
|
|
else
|
|
{
|
|
LONG lasterr = GetLastError();
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GetUser:API (LookupAccountSid) failed with %lx\r\n",
|
|
lasterr
|
|
) ;
|
|
)
|
|
}
|
|
|
|
if ( 5 > (DWORD)(LOBYTE(LOWORD(dwVersion))) )
|
|
{
|
|
ReleaseSerialAccess(CNTEventProvider::g_secMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GetUser:Failed to get serial access to security APIs\r\n"
|
|
) ;
|
|
)
|
|
}
|
|
|
|
|
|
|
|
//regardless of error enter this into map so we
|
|
//don't look up this PSID again
|
|
{
|
|
ScopeLock<CSIDMap> sl(sm_usersMap);
|
|
CStringW LookretVal;
|
|
|
|
if (!sm_usersMap.IsEmpty() && sm_usersMap.Lookup(usrSID, LookretVal))
|
|
{
|
|
return LookretVal;
|
|
}
|
|
else
|
|
{
|
|
DWORD sidlen = GetLengthSid(userSid);
|
|
MyPSID key;
|
|
key.m_SID = (PSID) new UCHAR[sidlen];
|
|
CopySid(sidlen, key.m_SID, userSid);
|
|
sm_usersMap[key] = retVal;
|
|
}
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
void CEventlogRecord::EmptyUsersMap()
|
|
{
|
|
if (sm_usersMap.Lock())
|
|
{
|
|
sm_usersMap.RemoveAll();
|
|
sm_usersMap.Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
HINSTANCE CEventlogRecord::GetDll(CStringW path)
|
|
{
|
|
HINSTANCE retVal = NULL;
|
|
CStringW key(path);
|
|
key.MakeUpper();
|
|
BOOL bFound = FALSE;
|
|
|
|
{
|
|
ScopeLock<CDllMap> sl(sm_dllMap);
|
|
|
|
if (!sm_dllMap.IsEmpty() && sm_dllMap.Lookup(key, retVal))
|
|
{
|
|
bFound = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
retVal = LoadLibraryEx(path, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
|
|
|
|
if (retVal == NULL)
|
|
{
|
|
DebugOut(
|
|
DWORD lasterr = GetLastError();
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GetDll:API (LoadLibraryEx) failed with %lx for %s\r\n",
|
|
lasterr, path
|
|
) ;
|
|
)
|
|
}
|
|
else
|
|
{
|
|
HINSTANCE LookretVal = NULL;
|
|
ScopeLock<CDllMap> sl(sm_dllMap);
|
|
|
|
if (!sm_dllMap.IsEmpty() && sm_dllMap.Lookup(key, LookretVal))
|
|
{
|
|
FreeLibrary(retVal); //release the ref count as we increased it by one as above.
|
|
return LookretVal;
|
|
|
|
} else {
|
|
|
|
sm_dllMap[key] = retVal;
|
|
|
|
}
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
void CEventlogRecord::EmptyDllMap()
|
|
{
|
|
if (sm_dllMap.Lock())
|
|
{
|
|
sm_dllMap.RemoveAll();
|
|
sm_dllMap.Unlock();
|
|
}
|
|
}
|
|
|
|
void CEventlogRecord::SetMessage()
|
|
{
|
|
HINSTANCE hMsgModule;
|
|
wchar_t* lpBuffer = NULL;
|
|
|
|
CStringW log(EVENTLOG_BASE);
|
|
log += L"\\";
|
|
log += m_Logfile;
|
|
|
|
HKEY hkResult;
|
|
|
|
LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, log, 0, KEY_READ, &hkResult);
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::SetMessage:API (RegOpenKeyEx) failed with %lx for %s\r\n",
|
|
status, log
|
|
) ;
|
|
)
|
|
|
|
return;
|
|
}
|
|
|
|
ON_BLOCK_EXIT ( RegCloseKey, hkResult ) ;
|
|
|
|
DWORD dwType;
|
|
wchar_t* prim = NULL;
|
|
|
|
prim = new wchar_t[MAX_PATH];
|
|
DWORD datalen = MAX_PATH * sizeof(wchar_t);
|
|
|
|
status = RegQueryValueEx(hkResult, PRIM_MODULE, 0, &dwType, (LPBYTE)prim, &datalen);
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
if (status == ERROR_MORE_DATA)
|
|
{
|
|
delete [] prim;
|
|
prim = new wchar_t[datalen];
|
|
status = RegQueryValueEx(hkResult, PRIM_MODULE, 0, &dwType, (LPBYTE)prim, &datalen);
|
|
}
|
|
}
|
|
|
|
HKEY hkPrimary = NULL;
|
|
HKEY hkSource = NULL;
|
|
|
|
wmilib::auto_buffer < wchar_t > Smartprim ( prim ) ;
|
|
if ( ERROR_SUCCESS == status && dwType == REG_SZ )
|
|
{
|
|
// this is path to primary log
|
|
CStringW primLog = log + L"\\";
|
|
primLog += prim;
|
|
|
|
// open a registry for primary event log key
|
|
if ((_wcsicmp(m_SourceName, prim)) != 0)
|
|
{
|
|
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, primLog, 0, KEY_READ, &hkPrimary);
|
|
}
|
|
}
|
|
|
|
ON_BLOCK_EXIT ( RegCloseKey, hkPrimary ) ;
|
|
|
|
// this is path to source log
|
|
CStringW sourceLog = log + L"\\";
|
|
sourceLog += m_SourceName;
|
|
|
|
// check to see there is a registry for source
|
|
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sourceLog, 0, KEY_READ, &hkSource);
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::SetMessage:API (RegOpenKeyEx) failed with %lx for %s\r\n",
|
|
status, log
|
|
) ;
|
|
)
|
|
return;
|
|
}
|
|
|
|
ON_BLOCK_EXIT ( RegCloseKey, hkSource ) ;
|
|
|
|
// get category file
|
|
CStringW cat_modname = CEventLogFile::GetFileName(hkSource, CAT_MODULE);
|
|
if (cat_modname.IsEmpty())
|
|
{
|
|
if ( hkPrimary )
|
|
{
|
|
// try primary event log key as source doesn't have category
|
|
cat_modname = CEventLogFile::GetFileName(hkPrimary, CAT_MODULE);
|
|
}
|
|
}
|
|
|
|
// workout category and category string if possible
|
|
if (!cat_modname.IsEmpty())
|
|
{
|
|
hMsgModule = GetDll(cat_modname);
|
|
if (hMsgModule != NULL)
|
|
{
|
|
if (0 != FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | // let api build buffer
|
|
FORMAT_MESSAGE_IGNORE_INSERTS | // indicate no string inserts
|
|
FORMAT_MESSAGE_FROM_HMODULE | // look thru message DLL
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK ,
|
|
(LPVOID) hMsgModule, // handle to message module
|
|
m_Category, // message number to get
|
|
(ULONG) NULL, // specify no language
|
|
(LPWSTR) &lpBuffer, // address for buffer pointer
|
|
80, // minimum space to allocate
|
|
NULL))
|
|
{
|
|
m_CategoryString = lpBuffer;
|
|
m_CategoryString.TrimRight();
|
|
LocalFree(lpBuffer);
|
|
}
|
|
else
|
|
{
|
|
DWORD lasterr = GetLastError();
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::SetMessage:API (FormatMessage) failed with %lx\r\n",
|
|
lasterr
|
|
) ;
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// get event message file
|
|
CStringW* names;
|
|
DWORD count = CEventLogFile::GetFileNames(hkSource, &names);
|
|
if ( !count )
|
|
{
|
|
if ( hkPrimary )
|
|
{
|
|
// try primary event log key as source doesn't have event message file
|
|
count = CEventLogFile::GetFileNames(hkPrimary, &names);
|
|
}
|
|
}
|
|
|
|
// work out event messages
|
|
if (count != 0)
|
|
{
|
|
for (int x = 0; x < count; x++)
|
|
{
|
|
hMsgModule = GetDll(names[x]);
|
|
if (hMsgModule != NULL)
|
|
{
|
|
if (0 != FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | // let api build buffer
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY | // indicate an array of string inserts
|
|
FORMAT_MESSAGE_IGNORE_INSERTS | // indicate no string inserts
|
|
FORMAT_MESSAGE_FROM_HMODULE, // look thru message DLL
|
|
(LPVOID) hMsgModule, // handle to message module
|
|
m_EvtID, // message number to get
|
|
(ULONG) NULL, // specify no language
|
|
(LPWSTR) &lpBuffer, // address for buffer pointer
|
|
80, // minimum space to allocate
|
|
NULL))
|
|
{
|
|
m_Message = lpBuffer;
|
|
LocalFree(lpBuffer);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
DWORD lasterr = GetLastError();
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::SetMessage:API (FormatMessage) failed with %lx\r\n",
|
|
lasterr
|
|
) ;
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
delete [] names;
|
|
}
|
|
|
|
if (m_NumStrs != 0)
|
|
{
|
|
CheckInsertionStrings(hkSource, hkPrimary);
|
|
}
|
|
}
|
|
|
|
void CEventlogRecord::SetTimeStr(CStringW& str, DWORD timeVal)
|
|
{
|
|
WBEMTime tmpTime((time_t)timeVal);
|
|
BSTR tStr = tmpTime.GetDMTF(TRUE);
|
|
str = tStr;
|
|
SysFreeString(tStr);
|
|
}
|
|
|
|
void CEventlogRecord::SetType(WORD type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case 0:
|
|
{
|
|
m_Type = m_TypeArray[0];
|
|
m_EvtType = 0;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
m_Type = m_TypeArray[1];
|
|
m_EvtType = 1;
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
m_Type = m_TypeArray[2];
|
|
m_EvtType = 2;
|
|
break;
|
|
}
|
|
case 4:
|
|
{
|
|
m_Type = m_TypeArray[3];
|
|
m_EvtType = 3;
|
|
break;
|
|
}
|
|
case 8:
|
|
{
|
|
m_Type = m_TypeArray[4];
|
|
m_EvtType = 4;
|
|
break;
|
|
}
|
|
case 16:
|
|
{
|
|
m_Type = m_TypeArray[5];
|
|
m_EvtType = 5;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::SetType:Unknown type %lx\r\n",
|
|
(long)type
|
|
) ;
|
|
)
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if (m_Type.IsEmpty())
|
|
{
|
|
wchar_t* buff = m_Type.GetBuffer(20);
|
|
_ultow((ULONG)type, buff, 10);
|
|
m_Type.ReleaseBuffer();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
ULONG CEventlogRecord::GetIndex(wchar_t* indexStr, BOOL* bError)
|
|
{
|
|
int val = _wtoi(indexStr);
|
|
*bError = FALSE;
|
|
ULONG index = 0;
|
|
|
|
switch (val)
|
|
{
|
|
case EVENTLOG_SUCCESS: //0
|
|
{
|
|
index = 0;
|
|
break;
|
|
}
|
|
case EVENTLOG_ERROR_TYPE: //1
|
|
{
|
|
index = 1;
|
|
break;
|
|
}
|
|
case EVENTLOG_WARNING_TYPE: //2
|
|
{
|
|
index = 2;
|
|
break;
|
|
}
|
|
case EVENTLOG_INFORMATION_TYPE: //4
|
|
{
|
|
index = 3;
|
|
break;
|
|
}
|
|
case EVENTLOG_AUDIT_SUCCESS: //8
|
|
{
|
|
index = 4;
|
|
break;
|
|
}
|
|
case EVENTLOG_AUDIT_FAILURE: //16
|
|
{
|
|
index = 5;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
*bError = TRUE;
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::Index:Unknown index %lx\r\n",
|
|
val
|
|
) ;
|
|
)
|
|
|
|
}
|
|
}
|
|
|
|
return index;
|
|
}
|
|
|
|
BOOL CEventlogRecord::SetEnumArray(IWbemClassObject* pClass, wchar_t* propname, CStringW* strArray, ULONG strArrayLen, GetIndexFunc IndexFunc)
|
|
{
|
|
BOOL retVal = FALSE;
|
|
IWbemQualifierSet* pQuals = NULL;
|
|
|
|
if (SUCCEEDED(pClass->GetPropertyQualifierSet(propname, &pQuals)))
|
|
{
|
|
VARIANT vVals;
|
|
|
|
if (SUCCEEDED(pQuals->Get(EVT_ENUM_QUAL, 0, &vVals, NULL)))
|
|
{
|
|
VARIANT vInds;
|
|
|
|
if (SUCCEEDED(pQuals->Get(EVT_MAP_QUAL, 0, &vInds, NULL)))
|
|
{
|
|
if ((vInds.vt == vVals.vt) && (vInds.vt == (VT_BSTR | VT_ARRAY)) &&
|
|
(SafeArrayGetDim(vInds.parray) == SafeArrayGetDim(vVals.parray)) &&
|
|
(SafeArrayGetDim(vVals.parray) == 1) && (vInds.parray->rgsabound[0].cElements == strArrayLen) &&
|
|
(vInds.parray->rgsabound[0].cElements == vVals.parray->rgsabound[0].cElements) )
|
|
{
|
|
BSTR *strInds = NULL;
|
|
|
|
if (SUCCEEDED(SafeArrayAccessData(vInds.parray, (void **)&strInds)) )
|
|
{
|
|
BSTR *strVals = NULL;
|
|
|
|
if (SUCCEEDED(SafeArrayAccessData(vVals.parray, (void **)&strVals)) )
|
|
{
|
|
BOOL bErr = FALSE;
|
|
retVal = TRUE;
|
|
|
|
for (ULONG x = 0; x < strArrayLen; x++)
|
|
{
|
|
ULONG index = IndexFunc(strInds[x], &bErr);
|
|
|
|
if (!bErr)
|
|
{
|
|
if (strArray[index].IsEmpty())
|
|
{
|
|
strArray[index] = strVals[x];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retVal = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SafeArrayUnaccessData(vVals.parray);
|
|
}
|
|
|
|
SafeArrayUnaccessData(vInds.parray);
|
|
}
|
|
}
|
|
|
|
VariantClear(&vInds);
|
|
}
|
|
|
|
VariantClear(&vVals);
|
|
}
|
|
else
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::SetEnumArray:Failed to get enumeration qualifier.\r\n"
|
|
) ;
|
|
)
|
|
|
|
}
|
|
|
|
pQuals->Release();
|
|
}
|
|
else
|
|
{
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::SetEnumArray:Failed to get qualifier set for enumeration.\r\n"
|
|
) ;
|
|
)
|
|
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
BOOL CEventlogRecord::GetInstance()
|
|
{
|
|
BSTR path = SysAllocString(NTEVT_CLASS);
|
|
if ( NULL == path )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
if (m_nspace != NULL)
|
|
{
|
|
if (!WbemTaskObject::GetClassObject(path, FALSE, m_nspace, NULL, &m_pClass ))
|
|
{
|
|
m_pClass = NULL;
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GetInstance:Failed to get Class object\r\n"
|
|
) ;
|
|
)
|
|
|
|
}
|
|
|
|
if (!WbemTaskObject::GetClassObject(path, TRUE, m_nspace, NULL, &m_pAClass ))
|
|
{
|
|
m_pAClass = NULL;
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GetInstance:Failed to get Amended Class object\r\n"
|
|
) ;
|
|
)
|
|
|
|
}
|
|
|
|
m_nspace->Release();
|
|
m_nspace = NULL;
|
|
}
|
|
|
|
|
|
if (m_pClass != NULL)
|
|
{
|
|
m_pClass->SpawnInstance(0, &m_Obj);
|
|
|
|
if (m_pAClass)
|
|
{
|
|
SetEnumArray(m_pAClass, TYPE_PROP,(CStringW*)m_TypeArray, TYPE_ARRAY_LEN, (GetIndexFunc)GetIndex);
|
|
m_pAClass->Release();
|
|
m_pAClass = NULL;
|
|
}
|
|
|
|
m_pClass->Release();
|
|
m_pClass = NULL;
|
|
}
|
|
|
|
SysFreeString(path);
|
|
|
|
if (m_Obj != NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
DebugOut(
|
|
CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
|
|
|
|
_T(__FILE__),__LINE__,
|
|
L"CEventlogRecord::GetInstance:Failed to spawn instance\r\n"
|
|
) ;
|
|
)
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
class CDsBindingHandle
|
|
{
|
|
public:
|
|
|
|
// initally unbound
|
|
|
|
CDsBindingHandle()
|
|
:
|
|
m_hDS(0)
|
|
{
|
|
}
|
|
|
|
~CDsBindingHandle()
|
|
{
|
|
if ( m_hDS )
|
|
{
|
|
DsUnBind(&m_hDS);
|
|
}
|
|
}
|
|
|
|
// only re-binds if the dc name differs...
|
|
|
|
DWORD Bind(LPCWSTR strDcName);
|
|
|
|
// don't call DsUnBind on an instance of this class: you'll only regret
|
|
// it later. Let the dtor do the unbind.
|
|
|
|
operator HANDLE()
|
|
{
|
|
return m_hDS;
|
|
}
|
|
|
|
DWORD CrackGuid(LPCWSTR pwzGuid, CStringW &strResult);
|
|
|
|
private:
|
|
|
|
HANDLE m_hDS;
|
|
};
|
|
|
|
DWORD CDsBindingHandle::Bind(LPCWSTR strDcName)
|
|
{
|
|
DWORD err = NO_ERROR;
|
|
|
|
if (m_hDS)
|
|
{
|
|
DsUnBind(&m_hDS);
|
|
m_hDS = NULL;
|
|
}
|
|
|
|
//
|
|
// NULL is used for connecting GC
|
|
//
|
|
LPCWSTR szDcName = NULL ;
|
|
if ( NULL != *strDcName )
|
|
{
|
|
szDcName = strDcName ;
|
|
}
|
|
|
|
err = DsBind ( szDcName, 0, &m_hDS ) ;
|
|
|
|
if (err != NO_ERROR)
|
|
{
|
|
m_hDS = NULL;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
DWORD CDsBindingHandle::CrackGuid(LPCWSTR pwzGuid, CStringW &strResult)
|
|
{
|
|
DWORD err = ERROR;
|
|
|
|
if( NULL == m_hDS ) return err;
|
|
|
|
strResult.Empty();
|
|
|
|
DS_NAME_RESULT* name_result = 0;
|
|
err = DsCrackNames(
|
|
m_hDS,
|
|
DS_NAME_NO_FLAGS,
|
|
DS_UNIQUE_ID_NAME,
|
|
DS_FQDN_1779_NAME,
|
|
1, // only 1 name to crack
|
|
&pwzGuid,
|
|
&name_result);
|
|
|
|
if (err == NO_ERROR && name_result)
|
|
{
|
|
DS_NAME_RESULT_ITEM* item = name_result->rItems;
|
|
|
|
if (item)
|
|
{
|
|
// the API may return success, but each cracked name also carries
|
|
// an error code, which we effectively check by checking the name
|
|
// field for a value.
|
|
|
|
if (item->pName)
|
|
{
|
|
strResult = item->pName;
|
|
}
|
|
}
|
|
|
|
DsFreeNameResult(name_result);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
CStringW CEventlogRecord::GetMappedGUID(LPCWSTR strDcName, LPCWSTR strGuid)
|
|
{
|
|
GUID guid;
|
|
CDsBindingHandle s_hDS;
|
|
|
|
if (RPC_S_OK == UuidFromString((LPWSTR)strGuid, &guid))
|
|
{
|
|
return CStringW();
|
|
}
|
|
|
|
CStringW strResult;
|
|
ULONG ulError = NO_ERROR;
|
|
|
|
do
|
|
{
|
|
ulError = s_hDS.Bind(strDcName);
|
|
|
|
if (ulError != NO_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
DS_SCHEMA_GUID_MAP* guidmap = 0;
|
|
ulError = DsMapSchemaGuids(s_hDS, 1, &guid, &guidmap);
|
|
if (ulError != NO_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (guidmap->pName)
|
|
{
|
|
strResult = guidmap->pName;
|
|
}
|
|
|
|
DsFreeSchemaGuidMap(guidmap);
|
|
|
|
if (strResult.GetLength())
|
|
{
|
|
// the guid mapped as a schema guid: we're done
|
|
break;
|
|
}
|
|
|
|
// the guid is not a schema guid. Proabably an object guid.
|
|
ulError = s_hDS.CrackGuid(strGuid, strResult);
|
|
}
|
|
while (0);
|
|
|
|
do
|
|
{
|
|
//
|
|
// If we've got a string from the guid already, we're done.
|
|
//
|
|
|
|
if (strResult.GetLength())
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// one last try. in this case, we bind to a GC to try to crack the
|
|
// name.
|
|
|
|
// empty string implies GC
|
|
if (s_hDS.Bind(L"") != NO_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ulError = s_hDS.CrackGuid(strGuid, strResult);
|
|
}
|
|
while (0);
|
|
|
|
return strResult;
|
|
}
|
|
|
|
|