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.
 
 
 
 
 
 

664 lines
21 KiB

#include "precomp.h"
#include <stdio.h>
#include <wbemutil.h>
#include <wbemcomn.h>
#include <GroupsForUser.h>
#include "evtlog.h"
#include <GenUtils.h>
#include <comdef.h>
#include <Sddl.h>
#undef _ASSERT
#include <atlbase.h>
#define EVENTLOG_PROPNAME_SERVER L"UNCServerName"
#define EVENTLOG_PROPNAME_SOURCE L"SourceName"
#define EVENTLOG_PROPNAME_EVENTID L"EventID"
#define EVENTLOG_PROPNAME_TYPE L"EventType"
#define EVENTLOG_PROPNAME_CATEGORY L"Category"
#define EVENTLOG_PROPNAME_NUMSTRINGS L"NumberOfInsertionStrings"
#define EVENTLOG_PROPNAME_STRINGS L"InsertionStringTemplates"
#define EVENTLOG_PROPNAME_CREATORSID L"CreatorSid"
#define EVENTLOG_PROPNAME_DATANAME L"NameOfRawDataProperty"
#define EVENTLOG_PROPNAME_SIDNAME L"NameOfUserSIDProperty"
HRESULT STDMETHODCALLTYPE CEventLogConsumer::XProvider::FindConsumer(
IWbemClassObject* pLogicalConsumer,
IWbemUnboundObjectSink** ppConsumer)
{
CEventLogSink* pSink = new CEventLogSink(m_pObject->m_pControl);
if(pSink == NULL)
return WBEM_E_OUT_OF_MEMORY;
HRESULT hres = pSink->Initialize(pLogicalConsumer);
if(FAILED(hres))
{
delete pSink;
*ppConsumer = NULL;
return hres;
}
else return pSink->QueryInterface(IID_IWbemUnboundObjectSink,
(void**)ppConsumer);
}
void* CEventLogConsumer::GetInterface(REFIID riid)
{
if(riid == IID_IWbemEventConsumerProvider)
return &m_XProvider;
else return NULL;
}
CEventLogSink::~CEventLogSink()
{
if(m_hEventLog)
DeregisterEventSource(m_hEventLog);
if(m_aTemplates)
delete [] m_aTemplates;
if(m_pSidCreator)
delete [] m_pSidCreator;
}
HRESULT CEventLogSink::Initialize(IWbemClassObject* pLogicalConsumer)
{
// Get the information
// ===================
HRESULT hres = WBEM_S_NO_ERROR;
CComVariant v;
// Get the server and source
// =========================
WString wsServer;
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_SERVER, 0, &v, NULL, NULL);
if(FAILED(hres)) return hres;
if(V_VT(&v) == VT_BSTR)
wsServer = V_BSTR(&v);
VariantClear(&v);
WString wsSource;
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_SOURCE, 0, &v, NULL, NULL);
if(SUCCEEDED(hres) && (V_VT(&v) == VT_BSTR))
wsSource = V_BSTR(&v);
VariantClear(&v);
m_hEventLog = RegisterEventSourceW(
( (wsServer.Length() == 0) ? NULL : (LPCWSTR)wsServer),
wsSource);
if(m_hEventLog == NULL)
{
ERRORTRACE((LOG_ESS, "Unable to register event source '%S' on server "
"'%S'. Error code: %X\n", (LPCWSTR)wsSource, (LPCWSTR)wsServer,
GetLastError()));
return WBEM_E_FAILED;
}
// Get event parameters
// ====================
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_EVENTID, 0, &v, NULL, NULL);
if(SUCCEEDED(hres) && (V_VT(&v) == VT_I4))
m_dwEventId = V_I4(&v);
else
// This will mean we need to try to get the event information off of each
// event class as it arrives.
m_dwEventId = 0;
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_TYPE, 0, &v, NULL, NULL);
if(FAILED(hres) || (V_VT(&v) != VT_I4))
return WBEM_E_INVALID_PARAMETER;
m_dwType = V_I4(&v);
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_CATEGORY, 0, &v, NULL, NULL);
if(FAILED(hres) || (V_VT(&v) != VT_I4))
m_dwCategory = 0;
else
m_dwCategory = V_I4(&v);
if (m_dwCategory > 0xFFFF)
return WBEM_E_INVALID_PARAMETER;
// Get insertion strings
// =====================
// Only get this stuff if the logical consumer has an event id.
if (m_dwEventId)
{
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_NUMSTRINGS, 0, &v,
NULL, NULL);
if(FAILED(hres) || (V_VT(&v) != VT_I4))
return WBEM_E_INVALID_PARAMETER;
m_dwNumTemplates = V_I4(&v);
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_STRINGS, 0, &v, NULL, NULL);
if(FAILED(hres))
return WBEM_E_INVALID_PARAMETER;
// array of bstrs or null, else bail
if ((V_VT(&v) != (VT_BSTR | VT_ARRAY)) && (V_VT(&v) != VT_NULL))
{
VariantClear(&v);
return WBEM_E_INVALID_PARAMETER;
}
if ((V_VT(&v) == VT_NULL) && (m_dwNumTemplates > 0))
return WBEM_E_INVALID_PARAMETER;
if (m_dwNumTemplates > 0)
{
CVarVector vv(VT_BSTR, V_ARRAY(&v));
VariantClear(&v);
if (vv.Size() < m_dwNumTemplates)
return WBEM_E_INVALID_PARAMETER;
m_aTemplates = new CTextTemplate[m_dwNumTemplates];
if(m_aTemplates == NULL)
return WBEM_E_OUT_OF_MEMORY;
for(DWORD i = 0; i < m_dwNumTemplates; i++)
{
m_aTemplates[i].SetTemplate(vv.GetAt(i).GetLPWSTR());
}
}
}
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_DATANAME, 0, &v,
NULL, NULL);
if (SUCCEEDED(hres) && (v.vt == VT_BSTR) && (v.bstrVal != NULL))
{
m_dataName = v.bstrVal;
}
VariantClear(&v);
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_SIDNAME, 0, &v,
NULL, NULL);
if (SUCCEEDED(hres) && (v.vt == VT_BSTR) && (v.bstrVal != NULL))
{
m_sidName = v.bstrVal;
}
VariantClear(&v);
hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_CREATORSID, 0, &v,
NULL, NULL);
if (SUCCEEDED(hres) && (v.vt != VT_NULL))
{
if((v.vt != (VT_ARRAY | VT_UI1)))
{
VariantClear(&v);
return WBEM_E_INVALID_OBJECT;
}
long ubound;
if(SUCCEEDED(hres = SafeArrayGetUBound(V_ARRAY(&v), 1, &ubound)))
{
PVOID pVoid;
if(SUCCEEDED(hres = SafeArrayAccessData(V_ARRAY(&v), &pVoid)))
{
m_pSidCreator = new BYTE[ubound +1];
if(m_pSidCreator == NULL)
hres = WBEM_E_OUT_OF_MEMORY;
else
memcpy(m_pSidCreator, pVoid, ubound + 1);
SafeArrayUnaccessData(V_ARRAY(&v));
}
}
}
VariantClear(&v);
return hres;
}
HRESULT CEventLogSink::XSink::GetDatEmbeddedObjectOut(IWbemClassObject* pObject, WCHAR* objectName, IWbemClassObject*& pEmbeddedObject)
{
HRESULT hr;
VARIANT vObject;
VariantInit(&vObject);
hr = pObject->Get(objectName, 0, &vObject, NULL, NULL);
if (FAILED(hr))
{
ERRORTRACE((LOG_ESS, "NT Event Log Consumer: could not retrieve %S, 0x%08X\n", objectName, hr));
}
else if ((vObject.vt != VT_UNKNOWN) || (vObject.punkVal == NULL)
|| FAILED(vObject.punkVal->QueryInterface(IID_IWbemClassObject, (void**)&pEmbeddedObject)))
{
ERRORTRACE((LOG_ESS, "NT Event Log Consumer: %S is not an embedded object\n", objectName));
hr = WBEM_E_INVALID_PARAMETER;
}
VariantClear(&vObject);
return hr;
}
HRESULT CEventLogSink::XSink::GetDatDataVariant(IWbemClassObject* pEventObj, WCHAR* dataName, VARIANT& vData)
{
WCHAR* propName = NULL;
IWbemClassObject* pDataObj = NULL;
HRESULT hr = WBEM_S_NO_ERROR;
// parse out data name
WCHAR* pDot;
if (pDot = wcschr(dataName, L'.'))
{
// found a dot, we're dealing with an embedded object
// mask out dot to make our life easier
*pDot = L'\0';
WCHAR* pNextDot;
pNextDot = wcschr(pDot+1, L'.');
if (pNextDot)
// we have a doubly embedded object, that's as deep as we support
{
// we now have three prop names with nulls between
*pNextDot = '\0';
IWbemClassObject* pIntermediateObj = NULL;
if (SUCCEEDED(hr = GetDatEmbeddedObjectOut(pEventObj, dataName, pIntermediateObj)))
{
hr = GetDatEmbeddedObjectOut(pIntermediateObj, pDot +1, pDataObj);
pIntermediateObj->Release();
}
propName = pNextDot +1;
// put dot back
*pDot = L'.';
// put dot dot back back
*pNextDot = L'.';
}
else
// we have a singly embedded object. cool.
{
hr = GetDatEmbeddedObjectOut(pEventObj, dataName, pDataObj);
// put dot back
*pDot = L'.';
propName = pDot +1;
}
}
else
{
// not an embedded object
pDataObj = pEventObj;
pDataObj->AddRef();
propName = dataName;
}
if (SUCCEEDED(hr) && pDataObj)
{
if (FAILED(hr = pDataObj->Get(propName, 0, &vData, NULL, NULL)))
DEBUGTRACE((LOG_ESS, "NT Event Log Consumer: could not retrieve property '%S' 0x%08X\n", dataName, hr));
}
if (pDataObj)
pDataObj->Release();
return hr;
}
// assumes that dataName is a valid string
// retrieves data from event object
// upon return pData points at data contained in variant
// calls responsibility to clear variant (don't delete pData)
// void return, any errors are logged - we don't want to block an event log if we can avoid it
void CEventLogSink::XSink::GetDatData(IWbemClassObject* pEventObj, WCHAR* dataName,
VARIANT& vData, BYTE*& pData, DWORD& dataSize)
{
pData = NULL;
dataSize = 0;
HRESULT hr;
if (SUCCEEDED(GetDatDataVariant(pEventObj, dataName, vData)))
{
hr = VariantChangeType(&vData, &vData, 0, (VT_UI1 | VT_ARRAY));
if (FAILED(hr) || (vData.vt != (VT_UI1 | VT_ARRAY)))
{
ERRORTRACE((LOG_ESS, "NT Event Log Consumer: %S cannot be converted to a byte array (0x%08X)\n", dataName, hr));
VariantClear(&vData);
}
else
// should be good to go!
{
if (FAILED(hr = SafeArrayAccessData(vData.parray, (void**)&pData)))
{
ERRORTRACE((LOG_ESS, "NT Event Log Consumer: failed to access %S, 0x%08X\n", dataName, hr));
VariantClear(&vData);
}
long lDataSize;
SafeArrayGetUBound(vData.parray, 1, &lDataSize);
dataSize = (DWORD)lDataSize + 1;
}
}
}
// assumes that dataName is a valid string
// retrieves data from event object
// void return, any errors are logged - we don't want to block an event log if we can avoid it
void CEventLogSink::XSink::GetDatSID(IWbemClassObject* pEventObj, WCHAR* dataName, PSID& pSid)
{
HRESULT hr;
VARIANT vData;
VariantInit(&vData);
pSid = NULL;
if (SUCCEEDED(hr = GetDatDataVariant(pEventObj, dataName, vData)))
{
if (vData.vt == (VT_UI1 | VT_ARRAY))
{
BYTE* pData;
// this should be a binary SID
if (FAILED(hr = SafeArrayAccessData(vData.parray, (void**)&pData)))
ERRORTRACE((LOG_ESS, "NT Event Log Consumer: failed to access %S, 0x%08X\n", dataName, hr));
else
{
if (IsValidSid((PSID)pData))
{
DWORD l = GetLengthSid((PSID)pData);
if (pSid = new BYTE[l])
CopySid(l, pSid, (PSID)pData);
}
}
}
else if ((vData.vt == VT_BSTR) && (vData.bstrVal != NULL))
{
PSID pLocalSid;
if (!ConvertStringSidToSid(vData.bstrVal, &pLocalSid))
ERRORTRACE((LOG_ESS, "NT Event Log Consumer: cannot convert %S to a SID\n", vData.bstrVal));
else
{
DWORD l = GetLengthSid(pLocalSid);
if (pSid = new BYTE[l])
CopySid(l, pSid, pLocalSid);
FreeSid(pLocalSid);
}
}
else
ERRORTRACE((LOG_ESS, "NT Event Log Consumer: %S is not a SID\n", dataName));
VariantClear(&vData);
}
}
HRESULT STDMETHODCALLTYPE CEventLogSink::XSink::IndicateToConsumer(
IWbemClassObject* pLogicalConsumer, long lNumObjects,
IWbemClassObject** apObjects)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (IsNT())
{
PSID pSidSystem;
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
if (AllocateAndInitializeSid(&id, 1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0,0,0,0,0,0,&pSidSystem))
{
// guilty until proven innocent
hr = WBEM_E_ACCESS_DENIED;
// check to see if sid is either Local System or an admin of some sort...
if ((EqualSid(pSidSystem, m_pObject->m_pSidCreator)) ||
(S_OK == IsUserAdministrator(m_pObject->m_pSidCreator)))
hr = WBEM_S_NO_ERROR;
// We're done with this
FreeSid(pSidSystem);
if (FAILED(hr))
return hr;
}
else
return WBEM_E_OUT_OF_MEMORY;
}
for(int i = 0; i < lNumObjects; i++)
{
int j;
BOOL bRes = FALSE;
// Do all events use the same ID?
if (m_pObject->m_dwEventId)
{
BSTR* astrStrings = new BSTR[m_pObject->m_dwNumTemplates];
if(astrStrings == NULL)
return WBEM_E_OUT_OF_MEMORY;
for(j = 0; j < m_pObject->m_dwNumTemplates; j++)
{
BSTR strText = m_pObject->m_aTemplates[j].Apply(apObjects[i]);
if(strText == NULL)
{
strText = SysAllocString(L"invalid log entry");
if(strText == NULL)
{
delete [] astrStrings;
return WBEM_E_OUT_OF_MEMORY;
}
}
astrStrings[j] = strText;
}
DWORD dataSize = NULL;
// data is actually held in the variant
// pData just makes access easier (clear the variant, don't delete pData!)
VARIANT vData;
VariantInit(&vData);
BYTE *pData = NULL;
PSID pSid = NULL;
if (m_pObject->m_dataName.Length() > 0)
GetDatData(apObjects[i], m_pObject->m_dataName, vData, pData, dataSize);
if (m_pObject->m_sidName.Length() > 0)
GetDatSID(apObjects[i], m_pObject->m_sidName, pSid);
bRes = ReportEventW(m_pObject->m_hEventLog, m_pObject->m_dwType,
m_pObject->m_dwCategory, m_pObject->m_dwEventId, pSid,
m_pObject->m_dwNumTemplates, dataSize,
(LPCWSTR*)astrStrings, pData);
// sid was allocated as an array of BYTE, not via AllocateAndInitializeSid
if (pSid)
delete[] pSid;
if (vData.vt == (VT_UI1 | VT_ARRAY))
SafeArrayUnaccessData(vData.parray);
VariantClear(&vData);
pData = NULL;
if(!bRes)
{
ERRORTRACE((LOG_ESS, "Failed to log an event: %X\n",
GetLastError()));
hr = WBEM_E_FAILED;
}
for(j = 0; j < m_pObject->m_dwNumTemplates; j++)
{
SysFreeString(astrStrings[j]);
}
delete [] astrStrings;
}
// If each event supplies its own ID, we have some work to do.
else
{
IWbemQualifierSet *pQuals = NULL;
if (SUCCEEDED(apObjects[i]->GetQualifierSet(&pQuals)))
{
_variant_t vMsgID;
if (SUCCEEDED(pQuals->Get(EVENTLOG_PROPNAME_EVENTID, 0, &vMsgID, NULL)) &&
((vMsgID.vt == VT_BSTR) || (vMsgID.vt == VT_I4)))
{
_variant_t vTemplates;
BSTR *pstrInsertionStrings = NULL;
DWORD nStrings = 0;
if (SUCCEEDED(pQuals->Get(
EVENTLOG_PROPNAME_STRINGS, 0, &vTemplates, NULL)) &&
vTemplates.vt == (VT_ARRAY | VT_BSTR) &&
vTemplates.parray->rgsabound[0].cElements > 0)
{
CTextTemplate *pTemplates;
nStrings = vTemplates.parray->rgsabound[0].cElements;
pTemplates = new CTextTemplate[nStrings];
if(pTemplates == NULL)
return WBEM_E_OUT_OF_MEMORY;
pstrInsertionStrings = new BSTR[nStrings];
if(pstrInsertionStrings == NULL)
{
delete [] pTemplates;
return WBEM_E_OUT_OF_MEMORY;
}
if (pTemplates && pstrInsertionStrings)
{
BSTR *pTemplateStrings = (BSTR*) vTemplates.parray->pvData;
for (j = 0; j < nStrings; j++)
{
pTemplates[j].SetTemplate(pTemplateStrings[j]);
pstrInsertionStrings[j] = pTemplates[j].Apply(apObjects[i]);
}
}
else
nStrings = 0;
if (pTemplates)
delete [] pTemplates;
}
DWORD dwEventID,
dwType,
dwCategory;
_variant_t vTemp;
WCHAR *szBad;
if (vMsgID.vt == VT_BSTR)
dwEventID = wcstoul(V_BSTR(&vMsgID), &szBad, 10);
else if (vMsgID.vt == VT_I4)
dwEventID = V_I4(&vMsgID);
if ((SUCCEEDED(pQuals->Get(EVENTLOG_PROPNAME_TYPE, 0, &vTemp, NULL))) &&
(V_VT(&vTemp) == VT_I4))
dwType = V_I4(&vTemp);
else
dwType = m_pObject->m_dwType;
if (SUCCEEDED(pQuals->Get(
EVENTLOG_PROPNAME_CATEGORY, 0, &vTemp, NULL)))
dwCategory = V_I4(&vTemp);
else
dwCategory = m_pObject->m_dwCategory;
DWORD dataSize = NULL;
// data is actually held in the variant
// pData just makes access easier (clear the variant, don't delete pData!)
VARIANT vData;
VariantInit(&vData);
BYTE *pData = NULL;
PSID pSid = NULL;
if (m_pObject->m_dataName.Length() > 0)
GetDatData(apObjects[i], m_pObject->m_dataName, vData, pData, dataSize);
if (m_pObject->m_sidName.Length() > 0)
GetDatSID(apObjects[i], m_pObject->m_sidName, pSid);
bRes =
ReportEventW(
m_pObject->m_hEventLog,
dwType,
dwCategory,
dwEventID,
pSid,
nStrings,
dataSize,
(LPCWSTR*) pstrInsertionStrings,
pData);
// sid was allocated as an array of BYTE, not via AllocateAndInitializeSid
if (pSid)
delete[] pSid;
if (vData.vt == (VT_UI1 | VT_ARRAY))
SafeArrayUnaccessData(vData.parray);
VariantClear(&vData);
pData = NULL;
if (!bRes)
{
ERRORTRACE((LOG_ESS, "Failed to log an event: %X\n",
GetLastError()));
hr = WBEM_E_FAILED;
}
for (j = 0; j < nStrings; j++)
SysFreeString(pstrInsertionStrings[j]);
delete [] pstrInsertionStrings;
} // SUCCEEDED(Get)
pQuals->Release();
} // SUCCEEDED(GetQualifierSet)
}
}
return hr;
}
void* CEventLogSink::GetInterface(REFIID riid)
{
if(riid == IID_IWbemUnboundObjectSink)
return &m_XSink;
else return NULL;
}