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.
 
 
 
 
 
 

765 lines
20 KiB

#include "precomp.h"
#include <sspi.h>
#include <secext.h>
#include <ntdsapi.h>
#include <stdio.h>
#include <buffer.h>
#include <winntsec.h>
#include <callsec.h>
#include <wbemint.h>
#include <wbemutil.h>
#include <arrtempl.h>
#include "fevprov.h"
#include "fwdhdr.h"
static LPWSTR g_wszEventClass = L"MSFT_ForwardedEvent";
static LPWSTR g_wszEventProp = L"Event";
static LPWSTR g_wszMachineProp = L"Machine";
static LPWSTR g_wszConsumerProp = L"Consumer";
static LPWSTR g_wszNamespaceProp = L"Namespace";
static LPWSTR g_wszAuthenticatedProp = L"Authenticated";
static LPWSTR g_wszAccountProp = L"Account";
static LPWSTR g_wszSDProp = L"SECURITY_DESCRIPTOR";
static LPWSTR g_wszTimeProp = L"Time";
// {0F3162C5-7B5A-469f-955C-79603B7EB5A6}
static const GUID g_guidQueueType =
{ 0xf3162c5, 0x7b5a, 0x469f, {0x95, 0x5c, 0x79, 0x60, 0x3b, 0x7e, 0xb5, 0xa6}};
LPCWSTR g_awszQueueNames[] = { L".\\private$\\WMIFwdGuaranteed",
L".\\private$\\WMIFwdExpress",
L".\\private$\\WMIFwdGuaranteedAuth",
L".\\private$\\WMIFwdExpressAuth",
L".\\WMIFwdGuaranteedEncrypt",
L".\\WMIFwdExpressEncrypt" };
BOOL g_adwQueueQos[] = { WMIMSG_FLAG_QOS_GUARANTEED,
WMIMSG_FLAG_QOS_EXPRESS,
WMIMSG_FLAG_QOS_GUARANTEED,
WMIMSG_FLAG_QOS_EXPRESS,
WMIMSG_FLAG_QOS_GUARANTEED,
WMIMSG_FLAG_QOS_EXPRESS };
BOOL g_abQueueAuth[] = { FALSE, FALSE, TRUE, TRUE, TRUE, TRUE };
extern BOOL AllowUnauthenticatedEvents();
/**************************************************************************
CFwdEventProv
***************************************************************************/
CFwdEventProv::CFwdEventProv( CLifeControl* pCtl, IUnknown* pUnk )
: CUnk( pCtl, pUnk ), m_XErrorSink( this ), m_XSendReceive( this ),
m_XProv( this ), m_XQuery( this ), m_XInit( this ),
m_lMachineProp(-1), m_lConsumerProp(-1), m_lNamespaceProp(-1),
m_lAuthProp(-1), m_lAccountProp(-1), m_lTimeProp(-1), m_lSDProp(-1)
{
}
CFwdEventProv::~CFwdEventProv()
{
}
void* CFwdEventProv::GetInterface( REFIID riid )
{
if ( riid == IID_IWbemEventProvider )
{
return &m_XProv;
}
else if ( riid == IID_IWbemProviderInit )
{
return &m_XInit;
}
else if ( riid == IID_IWmiMessageTraceSink )
{
return &m_XErrorSink;
}
else if ( riid == IID_IWmiMessageSendReceive )
{
return &m_XSendReceive;
}
else if ( riid == IID_IWbemEventProviderQuerySink )
{
return &m_XQuery;
}
return NULL;
}
HRESULT CFwdEventProv::Init( IWbemServices* pSvc,
IWbemProviderInitSink* pInitSink )
{
ENTER_API_CALL
HRESULT hr;
m_pSvc = pSvc;
hr = pSvc->GetObject( g_wszEventClass,
0,
NULL,
&m_pEventClass,
NULL );
if ( FAILED(hr) )
{
return hr;
}
//
// get handles for all the properties in the event .
//
CWbemPtr<_IWmiObject> pWmiEventClass;
hr = m_pEventClass->QueryInterface( IID__IWmiObject,
(void**)&pWmiEventClass );
if ( FAILED(hr) )
{
return hr;
}
hr = pWmiEventClass->GetPropertyHandleEx( g_wszMachineProp,
0,
NULL,
&m_lMachineProp );
if ( FAILED(hr) )
{
return hr;
}
hr = pWmiEventClass->GetPropertyHandleEx( g_wszConsumerProp,
0,
NULL,
&m_lConsumerProp );
if ( FAILED(hr) )
{
return hr;
}
hr = pWmiEventClass->GetPropertyHandleEx( g_wszNamespaceProp,
0,
NULL,
&m_lNamespaceProp );
if ( FAILED(hr) )
{
return hr;
}
hr = pWmiEventClass->GetPropertyHandleEx( g_wszAuthenticatedProp,
0,
NULL,
&m_lAuthProp );
if ( FAILED(hr) )
{
return hr;
}
hr = pWmiEventClass->GetPropertyHandleEx( g_wszSDProp,
0,
NULL,
&m_lSDProp );
if ( FAILED(hr) )
{
return hr;
}
hr = pWmiEventClass->GetPropertyHandleEx( g_wszAccountProp,
0,
NULL,
&m_lAccountProp );
if ( FAILED(hr) )
{
return hr;
}
hr = pWmiEventClass->GetPropertyHandleEx( g_wszTimeProp,
0,
NULL,
&m_lTimeProp );
if ( FAILED(hr) )
{
return hr;
}
hr = CoCreateInstance( CLSID_WmiSmartObjectUnmarshal,
NULL,
CLSCTX_INPROC,
IID_IWmiObjectMarshal,
(void**)&m_pMrsh );
if ( FAILED(hr) )
{
return hr;
}
return pInitSink->SetStatus( WBEM_S_INITIALIZED, 0 );
EXIT_API_CALL
}
HRESULT CFwdEventProv::InitializeEvent( IWbemClassObject* pOriginalEvent,
IWmiMessageReceiverContext* pRecvCtx,
LPCWSTR wszConsumer,
LPCWSTR wszNamespace,
PBYTE pSD,
ULONG cSD,
IWbemClassObject* pEvent )
{
HRESULT hr;
VARIANT var;
CWbemPtr<_IWmiObject> pWmiEvent;
hr = pEvent->QueryInterface( IID__IWmiObject, (void**)&pWmiEvent );
if ( FAILED(hr) )
{
return hr;
}
SYSTEMTIME st;
BYTE achBuff[256];
CBuffer Buff( achBuff, 256, FALSE );
WCHAR* pwchBuff = (WCHAR*)Buff.GetRawData();
ULONG cBuff = Buff.GetSize() / 2;
//
// Time Sent
//
hr = pRecvCtx->GetTimeSent( &st );
if ( FAILED(hr) )
{
return hr;
}
StringCchPrintfW( pwchBuff,
cBuff,
L"%04.4d%02.2d%02.2d%02.2d%02.2d%02.2d.%06.6d+000",
st.wYear, st.wMonth, st.wDay, st.wHour,
st.wMinute, st.wSecond, 0 );
hr = pWmiEvent->WritePropertyValue( m_lTimeProp,
(wcslen(pwchBuff)+1)*2,
Buff.GetRawData() );
if ( FAILED(hr) )
{
return hr;
}
//
// Sending Machine
//
pwchBuff = (WCHAR*)Buff.GetRawData();
cBuff = Buff.GetSize() / 2;
hr = pRecvCtx->GetSendingMachine( pwchBuff, cBuff, &cBuff );
if ( hr == WBEM_S_FALSE )
{
hr = Buff.SetSize( cBuff*2 ); // note: size for wchars
if ( FAILED(hr) )
{
return hr;
}
pwchBuff = (WCHAR*)Buff.GetRawData();
cBuff = Buff.GetSize() / 2;
hr = pRecvCtx->GetSendingMachine( pwchBuff, cBuff, &cBuff );
}
if ( SUCCEEDED(hr) && cBuff > 0 )
{
hr = pWmiEvent->WritePropertyValue( m_lMachineProp,
cBuff*2,
Buff.GetRawData() );
}
//
// Sender Authenticated
//
hr = pRecvCtx->IsSenderAuthenticated();
if ( FAILED(hr) )
{
return hr;
}
hr = pWmiEvent->WriteDWORD( m_lAuthProp, hr == S_OK ? 1 : 0 );
if ( FAILED(hr) )
{
return hr;
}
//
// Sender Identity
//
ULONG cSid;
hr = pRecvCtx->GetSenderId( Buff.GetRawData(), Buff.GetSize(), &cSid );
if ( hr == WBEM_S_FALSE )
{
hr = Buff.SetSize( cSid );
if ( FAILED(hr) )
{
return hr;
}
hr = pRecvCtx->GetSenderId( Buff.GetRawData(), Buff.GetSize(), &cSid );
}
if ( SUCCEEDED(hr) && cSid > 0 )
{
hr = pWmiEvent->SetArrayPropRangeByHandle( m_lAccountProp,
WMIARRAY_FLAG_ALLELEMENTS,
0,
cSid,
cSid,
Buff.GetRawData() );
}
//
// Original Event
//
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = pOriginalEvent;
hr = pEvent->Put( g_wszEventProp, 0, &var, NULL );
if ( FAILED(hr) )
{
return hr;
}
//
// Sending Consumer Name
//
if ( wszConsumer != NULL )
{
hr = pWmiEvent->WritePropertyValue( m_lConsumerProp,
(wcslen(wszConsumer)+1)*2,
PBYTE(wszConsumer) );
if ( FAILED(hr) )
{
return hr;
}
}
//
// Sending Consumer Namespace
//
if ( wszNamespace != NULL )
{
hr = pWmiEvent->WritePropertyValue( m_lNamespaceProp,
(wcslen(wszNamespace)+1)*2,
PBYTE(wszNamespace) );
if ( FAILED(hr) )
{
return hr;
}
}
//
// set the security descriptor on the event if specified.
//
if ( cSD > 0 )
{
hr = pWmiEvent->SetArrayPropRangeByHandle( m_lSDProp,
WMIARRAY_FLAG_ALLELEMENTS,
0,
cSD,
cSD,
pSD );
if ( FAILED(hr) )
{
return hr;
}
}
return WBEM_S_NO_ERROR;
}
HRESULT CFwdEventProv::ProvideEvents( IWbemObjectSink* pSink, long lFlags )
{
ENTER_API_CALL
m_pEventSink = pSink;
//
// we were waiting to obtain the sink before starting up the
// receivers.
//
DEBUGTRACE((LOG_ESS,"FEVPROV: Begin Initializing.\n"));
BOOL bAllowUnauth = AllowUnauthenticatedEvents();
HRESULT hr;
#ifdef __WHISTLER_UNCUT
hr = InitializeQueues( bAllowUnauth );
if ( FAILED(hr) )
{
return hr;
}
#endif
hr = InitializeReceivers( bAllowUnauth );
DEBUGTRACE((LOG_ESS,"FEVPROV: End Initializing.\n"));
return hr;
EXIT_API_CALL
}
HRESULT CFwdEventProv::InitializeQueues( BOOL bAllowUnauth )
{
HRESULT hr;
DWORD dwQuota = 0xffffffff;
PSECURITY_DESCRIPTOR pSecDesc = NULL;
CWbemPtr<IWmiMessageQueueManager> pQueueMgr;
hr = CoCreateInstance( CLSID_WmiMessageQueueManager,
NULL,
CLSCTX_INPROC,
IID_IWmiMessageQueueManager,
(void**)&pQueueMgr );
if ( FAILED(hr) )
{
return hr;
}
for( int i=0 ; i < sizeof(g_adwQueueQos)/sizeof(DWORD); i++ )
{
if ( g_abQueueAuth[i] || (!g_abQueueAuth[i] && bAllowUnauth) )
{
hr = pQueueMgr->Create( g_awszQueueNames[i],
g_guidQueueType,
g_abQueueAuth[i],
g_adwQueueQos[i],
dwQuota,
pSecDesc );
if ( FAILED(hr) && hr != WBEM_E_ALREADY_EXISTS )
{
ERRORTRACE((LOG_ESS,"FEVPROV: Could not create/open queue %S, "
"HR=0x%x\n", g_awszQueueNames[i], hr ));
}
}
else
{
//
// since we're not going to allow unauthenticated queues, make
// sure that we delete any existing ones so that there's not an
// open unauthenticated entry point on the machine. There will
// only be a queue actually there to clean up if we're
// transitioning from unauthenticated allowed to not allowed.
//
pQueueMgr->Destroy( g_awszQueueNames[i] );
}
}
return WBEM_S_NO_ERROR;
}
HRESULT CFwdEventProv::InitializeReceivers( BOOL bAllowUnauth )
{
HRESULT hr;
DWORD dwFlags = 0;
if ( !bAllowUnauth )
{
dwFlags |= WMIMSG_FLAG_RCVR_SECURE_ONLY;
}
//
// Initialize Sync DCOM Receiver.
//
hr = CoCreateInstance( CLSID_WmiMessageRpcReceiver,
NULL,
CLSCTX_INPROC,
IID_IWmiMessageReceiver,
(void**)&m_pDcomRcvr );
if ( FAILED(hr) )
{
return hr;
}
hr = m_pDcomRcvr->Open(
L"7879E40D-9FB5-450a-8A6D-00C89F349FCE@ncacn_ip_tcp:",
WMIMSG_FLAG_QOS_SYNCHRONOUS | dwFlags,
NULL,
&m_XSendReceive );
if ( FAILED(hr) )
{
ERRORTRACE((LOG_ESS,"FEVPROV: Could not open dcom rcvr, "
"HR=0x%x\n", hr ));
return hr;
}
#ifdef __WHISTLER_UNCUT
for( int i=0; i < sizeof(g_adwQueueQos)/sizeof(DWORD); i++ )
{
if ( g_abQueueAuth[i] || (!g_abQueueAuth[i] && bAllowUnauth) )
{
hr = CoCreateInstance( CLSID_WmiMessageMsmqReceiver,
NULL,
CLSCTX_INPROC,
IID_IWmiMessageReceiver,
(void**)&m_apQueueRcvr[i] );
if ( FAILED(hr) )
{
return hr;
}
hr = m_apQueueRcvr[i]->Open( g_awszQueueNames[i],
g_adwQueueQos[i] | dwFlags,
NULL,
&m_XSendReceive );
if ( FAILED(hr) )
{
ERRORTRACE((LOG_ESS,"FEVPROV: Could not open rcvr for queue %S"
", HR=0x%x\n", g_awszQueueNames[i], hr ));
}
}
}
#endif
return WBEM_S_NO_ERROR;
}
HRESULT CFwdEventProv::NewQuery( DWORD dwId, LPWSTR wszQuery )
{
return WBEM_S_NO_ERROR;
}
HRESULT CFwdEventProv::CancelQuery( DWORD dwId )
{
return WBEM_S_NO_ERROR;
}
HRESULT CFwdEventProv::Receive( PBYTE pData,
ULONG cData,
PBYTE pAuxData,
ULONG cAuxData,
DWORD dwStatus,
IUnknown* pCtx )
{
ENTER_API_CALL
HRESULT hr;
CBuffer DataStrm( pData, cData, FALSE );
CBuffer HdrStrm( pAuxData, cAuxData, FALSE );
//
// read and verify msg hdr - don't do much with it though - it mostly
// contains info for nack event prov.
//
CFwdMsgHeader FwdHdr;
hr = FwdHdr.Unpersist( HdrStrm );
if ( FAILED(hr) )
{
return hr;
}
//
// read objects and generate event.
//
#define MAXEVENTS 256
IWbemClassObject* apEvents[MAXEVENTS];
DWORD i=0;
hr = S_OK;
CWbemPtr<IWmiMessageReceiverContext> pRecvCtx;
if ( pCtx == NULL || pCtx->QueryInterface( IID_IWmiMessageReceiverContext,
(void**)&pRecvCtx ) != S_OK )
{
return WBEM_E_CRITICAL_ERROR;
}
//
// if possible, convert our recv ctx to com context so that ess can
// impersonate the sender if necessary.
//
IWbemCallSecurity* pSec = NULL;
hr = pRecvCtx->ImpersonateSender();
if ( SUCCEEDED(hr) )
{
pSec = CWbemCallSecurity::CreateInst(); // ref is 1 on create.
if ( pSec == NULL )
{
pRecvCtx->RevertToSelf();
return WBEM_E_OUT_OF_MEMORY;
}
hr = pSec->CloneThreadContext( FALSE );
pRecvCtx->RevertToSelf();
IUnknown* pUnkSec = NULL;
if ( SUCCEEDED(hr) )
{
hr = CoSwitchCallContext( pSec, &pUnkSec );
}
if ( FAILED(hr) )
{
pSec->Release();
return hr;
}
_DBG_ASSERT( pUnkSec == NULL );
}
else if ( pRecvCtx->IsSenderAuthenticated() == S_FALSE )
{
//
// it is expected that ImpersonateClient will fail if
// the sender is not authenticated.
//
hr = WBEM_S_NO_ERROR;
}
else
{
//
// something else wrong here.
//
return WMIMSG_E_AUTHFAILURE;
}
const PSECURITY_DESCRIPTOR pSD = FwdHdr.GetTargetSD();
ULONG cSD = FwdHdr.GetTargetSDLength();
ULONG iData = DataStrm.GetIndex();
while( i < FwdHdr.GetNumObjects() && SUCCEEDED(hr) )
{
for( DWORD j=0; j < MAXEVENTS && j+i < FwdHdr.GetNumObjects(); j++ )
{
ULONG cUsed;
CWbemPtr<IWbemClassObject> pOriginalEvent;
hr = m_pMrsh->Unpack( cData-iData,
pData+iData,
0,
&pOriginalEvent,
&cUsed );
if ( FAILED(hr) )
{
break;
}
iData += cUsed;
CWbemPtr<IWbemClassObject> pEvent;
hr = m_pEventClass->SpawnInstance( NULL, &pEvent );
if ( FAILED(hr) )
{
break;
}
hr = InitializeEvent( pOriginalEvent,
pRecvCtx,
FwdHdr.GetConsumer(),
FwdHdr.GetNamespace(),
PBYTE(pSD),
cSD,
pEvent );
if ( FAILED(hr) )
{
break;
}
pEvent->AddRef();
apEvents[j] = pEvent;
}
i += j;
if ( SUCCEEDED(hr) )
{
hr = m_pEventSink->Indicate( j, apEvents );
}
for( DWORD k=0; k < j; k++ )
{
apEvents[k]->Release();
}
}
//
// if we switched the com call context, then switch it back.
//
if ( pSec != NULL )
{
IUnknown* pDummy;
if ( SUCCEEDED(CoSwitchCallContext( NULL, &pDummy ) ) )
{
_DBG_ASSERT( pDummy == pSec );
pSec->Release();
}
}
return hr;
EXIT_API_CALL
}
HRESULT CFwdEventProv::HandleRecvError( HRESULT hr, LPCWSTR wszError )
{
//
// right now just log to ESS log.
//
ERRORTRACE((LOG_ESS,"FEVPROV: RECV Error, ErrorString=%S, HR=0x%x\n",
wszError, hr ));
return S_OK;
}