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.
723 lines
17 KiB
723 lines
17 KiB
|
|
#include "precomp.h"
|
|
#include <wbemutil.h>
|
|
#include <arrtempl.h>
|
|
#include <wmimsg.h>
|
|
#include <ntdsapi.h>
|
|
#include "fconsend.h"
|
|
|
|
// flags below 0x10000 are reserved for msg implementations.
|
|
|
|
#define FWD_FLAG_NO_INDIRECT 0x00010000
|
|
|
|
// {DDE18466-D244-4a5b-B91F-93D17E13178D}
|
|
static const GUID g_guidQueueType =
|
|
{0xdde18466, 0xd244, 0x4a5b, {0xb9, 0x1f, 0x93, 0xd1, 0x7e, 0x13, 0x17, 0x8d}};
|
|
|
|
HRESULT IsTcpIpAddress( LPCWSTR wszTarget )
|
|
{
|
|
HRESULT hr;
|
|
WSADATA wsaData;
|
|
WORD wVersionRequested;
|
|
wVersionRequested = MAKEWORD( 2, 2 );
|
|
|
|
int err = WSAStartup( wVersionRequested, &wsaData );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
IN_ADDR ia;
|
|
|
|
//
|
|
// convert unicode addr to ansi ..
|
|
//
|
|
|
|
int cTarget = wcstombs( NULL, wszTarget, 0 );
|
|
LPSTR szTarget = new char[cTarget+1];
|
|
|
|
if ( szTarget != NULL )
|
|
{
|
|
wcstombs( szTarget, wszTarget, cTarget+1 );
|
|
ULONG in_ad = inet_addr( szTarget );
|
|
hr = in_ad == INADDR_NONE ? WBEM_S_FALSE : WBEM_S_NO_ERROR;
|
|
delete [] szTarget;
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
WSACleanup();
|
|
}
|
|
else
|
|
{
|
|
hr = WMIMSG_E_REQSVCNOTAVAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetDnsName( LPCWSTR wszTarget, LPWSTR* pwszDnsName )
|
|
{
|
|
HRESULT hr;
|
|
*pwszDnsName = NULL;
|
|
|
|
//
|
|
// first make sure winsock is initialized.
|
|
//
|
|
|
|
WSADATA wsaData;
|
|
WORD wVersionRequested;
|
|
wVersionRequested = MAKEWORD( 2, 2 );
|
|
|
|
int err = WSAStartup( wVersionRequested, &wsaData );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
IN_ADDR ia;
|
|
HOSTENT* pHost;
|
|
|
|
//
|
|
// convert unicode addr to ansi ..
|
|
//
|
|
|
|
int cTarget = wcstombs( NULL, wszTarget, 0 );
|
|
LPSTR szTarget = new char[cTarget+1];
|
|
|
|
if ( szTarget != NULL )
|
|
{
|
|
wcstombs( szTarget, wszTarget, cTarget+1 );
|
|
|
|
//
|
|
// see if its an ip address ...
|
|
//
|
|
|
|
ULONG in_ad = inet_addr( szTarget );
|
|
|
|
if ( in_ad == INADDR_NONE )
|
|
{
|
|
pHost = gethostbyname( szTarget );
|
|
}
|
|
else
|
|
{
|
|
pHost = gethostbyaddr( (char*)&in_ad, 4, PF_INET );
|
|
}
|
|
|
|
if ( pHost != NULL )
|
|
{
|
|
int cDnsTarget = MultiByteToWideChar( CP_ACP,
|
|
0,
|
|
pHost->h_name,
|
|
-1,
|
|
NULL,
|
|
0 );
|
|
|
|
*pwszDnsName = new WCHAR[cDnsTarget+1];
|
|
|
|
if ( *pwszDnsName != NULL )
|
|
{
|
|
MultiByteToWideChar( CP_ACP,
|
|
0,
|
|
pHost->h_name,
|
|
-1,
|
|
*pwszDnsName,
|
|
cDnsTarget+1 );
|
|
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WMIMSG_E_INVALIDADDRESS;
|
|
}
|
|
|
|
delete [] szTarget;
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
WSACleanup();
|
|
}
|
|
else
|
|
{
|
|
hr = WMIMSG_E_REQSVCNOTAVAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetSpn( LPCWSTR wszTarget, LPWSTR* wszSpn )
|
|
{
|
|
HRESULT hr;
|
|
*wszSpn = NULL;
|
|
|
|
LPWSTR wszNormTarget;
|
|
hr = GetDnsName( wszTarget, &wszNormTarget );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
CVectorDeleteMe<WCHAR> vdm( wszNormTarget );
|
|
|
|
DWORD cSpn = 0;
|
|
|
|
DWORD dwRes = DsMakeSpn( L"HOST", wszNormTarget, NULL, 0,
|
|
NULL, &cSpn, NULL);
|
|
|
|
if ( dwRes == ERROR_MORE_DATA || dwRes == ERROR_BUFFER_OVERFLOW )
|
|
{
|
|
*wszSpn = new WCHAR[cSpn];
|
|
|
|
if ( *wszSpn != NULL )
|
|
{
|
|
dwRes = DsMakeSpn( L"HOST",
|
|
wszNormTarget,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&cSpn,
|
|
*wszSpn );
|
|
|
|
if ( dwRes == ERROR_SUCCESS )
|
|
{
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
delete [] *wszSpn;
|
|
*wszSpn = NULL;
|
|
hr = HRESULT_FROM_WIN32( dwRes );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32( dwRes );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/********************************************************************
|
|
CFwdConsSend
|
|
*********************************************************************/
|
|
|
|
HRESULT CFwdConsSend::AddMSMQSender( LPCWSTR wszName )
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// need to construct the Ack address for this sender.
|
|
//
|
|
|
|
TCHAR atchComputer[MAX_COMPUTERNAME_LENGTH+1];
|
|
DWORD cComputer = MAX_COMPUTERNAME_LENGTH+1;
|
|
GetComputerName( atchComputer, &cComputer );
|
|
WCHAR awchComputer[MAX_COMPUTERNAME_LENGTH+1];
|
|
cComputer = MAX_COMPUTERNAME_LENGTH+1;
|
|
|
|
tsz2wsz( atchComputer, awchComputer, &cComputer );
|
|
|
|
WString wsAckQueueName = L"DIRECT=OS:";
|
|
wsAckQueueName += awchComputer;
|
|
wsAckQueueName += L"\\private$\\WMIFwdAck";
|
|
|
|
//
|
|
// create the sender object and add it to the multisender.
|
|
//
|
|
|
|
CWbemPtr<IWmiMessageSender> pSender;
|
|
|
|
hr = CoCreateInstance( CLSID_WmiMessageMsmqSender,
|
|
NULL,
|
|
CLSCTX_INPROC,
|
|
IID_IWmiMessageSender,
|
|
(void**)&pSender );
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
CWbemPtr<IWmiMessageSendReceive> pSend;
|
|
|
|
DWORD dwFlags = m_dwFlags |
|
|
WMIMSG_FLAG_SNDR_LAZY_INIT |
|
|
WMIMSG_FLAG_SNDR_PRIV_SIGN |
|
|
WMIMSG_FLAG_SNDR_NACK_ONLY;
|
|
|
|
hr = pSender->Open( wszName,
|
|
dwFlags,
|
|
NULL,
|
|
wsAckQueueName,
|
|
m_pTraceSink,
|
|
&pSend );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return m_pMultiSend->Add( WMIMSG_FLAG_MULTISEND_TERMINATING_SENDER, pSend);
|
|
}
|
|
|
|
HRESULT CFwdConsSend::AddAsyncSender( LPCWSTR wszMachine )
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// derive the msmq address from the target and add the sender.
|
|
//
|
|
|
|
WString wsQueueName;
|
|
|
|
if ( (m_dwFlags & WMIMSG_FLAG_SNDR_ENCRYPT) == 0 )
|
|
{
|
|
//
|
|
// we can use a direct format name to identify the target. This is
|
|
// the most flexible type of address besides a private format name,
|
|
// but those cannot be derived. ( public pathnames can only be used
|
|
// when online )
|
|
//
|
|
|
|
wsQueueName = L"DIRECT=";
|
|
|
|
hr = IsTcpIpAddress( wszMachine );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if ( hr == WBEM_S_NO_ERROR )
|
|
{
|
|
wsQueueName += L"TCP:";
|
|
}
|
|
else
|
|
{
|
|
wsQueueName += L"OS:";
|
|
}
|
|
|
|
wsQueueName += wszMachine;
|
|
wsQueueName += L"\\private$\\";
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we must use a public queue pathname to reference the queue. this is
|
|
// because msmq will not accept direct format names for encryption.
|
|
// encryption is supported by msmq only when the sender has access to
|
|
// ds. This means when this machine is offline, we cannot encrypt
|
|
// messages.
|
|
//
|
|
wsQueueName = L"wszMachine\\";
|
|
}
|
|
|
|
DWORD dwQos = m_dwFlags & WMIMSG_MASK_QOS;
|
|
|
|
_DBG_ASSERT( dwQos != WMIMSG_FLAG_QOS_SYNCHRONOUS );
|
|
|
|
if( dwQos == WMIMSG_FLAG_QOS_EXPRESS )
|
|
{
|
|
wsQueueName += L"WMIFwdExpress";
|
|
}
|
|
else if( dwQos == WMIMSG_FLAG_QOS_GUARANTEED )
|
|
{
|
|
wsQueueName += L"WMIFwdGuaranteed";
|
|
}
|
|
else if ( dwQos == WMIMSG_FLAG_QOS_XACT )
|
|
{
|
|
wsQueueName += L"WMIFwdXact";
|
|
}
|
|
|
|
if ( m_dwFlags & WMIMSG_FLAG_SNDR_ENCRYPT )
|
|
{
|
|
wsQueueName += L"Encrypt";
|
|
}
|
|
else if ( m_dwFlags & WMIMSG_FLAG_SNDR_AUTHENTICATE )
|
|
{
|
|
wsQueueName += L"Auth";
|
|
}
|
|
|
|
return AddMSMQSender(wsQueueName);
|
|
}
|
|
|
|
HRESULT CFwdConsSend::AddSyncSender( LPCWSTR wszMachine )
|
|
{
|
|
HRESULT hr;
|
|
|
|
CWbemPtr<IWmiMessageSender> pSender;
|
|
|
|
hr = CoCreateInstance( CLSID_WmiMessageRpcSender,
|
|
NULL,
|
|
CLSCTX_INPROC,
|
|
IID_IWmiMessageSender,
|
|
(void**)&pSender );
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// construct target binding : OBJID@ncacn_ip_tcp:target
|
|
//
|
|
|
|
WString wsTarget = L"7879E40D-9FB5-450a-8A6D-00C89F349FCE@ncacn_ip_tcp:";
|
|
wsTarget += wszMachine;
|
|
|
|
//
|
|
// construct the target principal name - for kerberos. We expect that
|
|
// has registered its SPN with AD. we only need to do this if we
|
|
// are sending authenticated though ...
|
|
//
|
|
|
|
LPWSTR wszSpn = NULL;
|
|
|
|
if ( m_dwFlags & WMIMSG_FLAG_SNDR_AUTHENTICATE )
|
|
{
|
|
hr = GetSpn( wszMachine, &wszSpn );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
DEBUGTRACE((LOG_ESS,"FC: Could not determine SPN for target %S. "
|
|
"hr=0x%x. Will try to forward events using NTLM\n",
|
|
wszMachine, hr ));
|
|
}
|
|
}
|
|
|
|
CVectorDeleteMe<WCHAR> vdm2( wszSpn );
|
|
|
|
WMIMSG_SNDR_AUTH_INFO AuthInfo;
|
|
ZeroMemory( &AuthInfo, sizeof( WMIMSG_SNDR_AUTH_INFO ) );
|
|
|
|
AuthInfo.wszTargetPrincipal = wszSpn;
|
|
|
|
//
|
|
// open sender
|
|
//
|
|
|
|
CWbemPtr<IWmiMessageSendReceive> pSend;
|
|
|
|
hr = pSender->Open( wsTarget,
|
|
m_dwFlags | WMIMSG_FLAG_SNDR_LAZY_INIT,
|
|
&AuthInfo,
|
|
NULL,
|
|
m_pTraceSink,
|
|
&pSend );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// add to multi sender and return.
|
|
//
|
|
|
|
return m_pMultiSend->Add(WMIMSG_FLAG_MULTISEND_TERMINATING_SENDER, pSend );
|
|
}
|
|
|
|
HRESULT CFwdConsSend::AddPhysicalSender( LPCWSTR wszMachine )
|
|
{
|
|
HRESULT hr;
|
|
|
|
#ifndef __WHISTLER_UNCUT
|
|
|
|
if ( (m_dwFlags & WMIMSG_MASK_QOS) != WMIMSG_FLAG_QOS_SYNCHRONOUS )
|
|
{
|
|
return WBEM_E_NOT_SUPPORTED;
|
|
}
|
|
|
|
return AddSyncSender( wszMachine );
|
|
|
|
#else
|
|
|
|
//
|
|
// here, we always add a sync sender first even if a qos
|
|
// of async is specified. Later this type of service may change to
|
|
// be its own QoS class.
|
|
//
|
|
|
|
hr = AddSyncSender( wszMachine );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if ( (m_dwFlags & WMIMSG_MASK_QOS) == WMIMSG_FLAG_QOS_SYNCHRONOUS )
|
|
{
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
return AddAsyncSender( wszMachine );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
HRESULT CFwdConsSend::AddLogicalSender( LPCWSTR wszTarget )
|
|
{
|
|
HRESULT hr;
|
|
|
|
CWbemPtr<IWmiMessageSendReceive> pSend;
|
|
|
|
hr = Create( m_pControl,
|
|
wszTarget,
|
|
m_dwFlags | FWD_FLAG_NO_INDIRECT,
|
|
NULL,
|
|
m_pTraceSink,
|
|
&pSend );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return m_pMultiSend->Add( 0, pSend );
|
|
}
|
|
|
|
HRESULT CFwdConsSend::AddLogicalSender( LPCWSTR wszObjpath, LPCWSTR wszProp )
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Check to make sure that indirect names are supported.
|
|
// This flag is mostly used to prohibit recursive indirect
|
|
// addesses.
|
|
//
|
|
|
|
if ( m_dwFlags & FWD_FLAG_NO_INDIRECT )
|
|
{
|
|
return WBEM_E_NOT_SUPPORTED;
|
|
}
|
|
|
|
CWbemBSTR bsObjPath = wszObjpath;
|
|
|
|
//
|
|
// Resolve the address by obtaining the object and getting
|
|
// the value of the specified property.
|
|
//
|
|
|
|
VARIANT var;
|
|
CWbemPtr<IWbemClassObject> pObj;
|
|
|
|
hr = m_pDefaultSvc->GetObject( bsObjPath, 0, NULL, &pObj, NULL );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
hr = pObj->Get( wszProp, 0, &var, NULL, NULL );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
CClearMe cmvar(&var);
|
|
|
|
//
|
|
// Add a new logical sender after resolving the address.
|
|
// Before adding the new sender, make sure we disable indirect
|
|
// addresses on it to prohibit recursive resolution.
|
|
//
|
|
|
|
DWORD dwFlags = m_dwFlags | FWD_FLAG_NO_INDIRECT;
|
|
|
|
if ( V_VT(&var) == VT_BSTR )
|
|
{
|
|
return AddLogicalSender( V_BSTR(&var) );
|
|
}
|
|
else if ( V_VT(&var) == (VT_ARRAY | VT_BSTR) )
|
|
{
|
|
BSTR* abstrNames;
|
|
hr = SafeArrayAccessData( V_ARRAY(&var), (void**)&abstrNames );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
long lUbound;
|
|
hr = SafeArrayGetUBound( V_ARRAY(&var), 0, &lUbound );
|
|
_DBG_ASSERT(SUCCEEDED(hr));
|
|
|
|
for( long i=0; i < lUbound+1; i++ )
|
|
{
|
|
AddLogicalSender( V_BSTR(&var) );
|
|
}
|
|
|
|
SafeArrayUnaccessData( V_ARRAY(&var) );
|
|
}
|
|
else
|
|
{
|
|
return WBEM_E_TYPE_MISMATCH;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CFwdConsSend::EnsureSender()
|
|
{
|
|
HRESULT hr;
|
|
|
|
CInCritSec ics(&m_cs);
|
|
|
|
if ( m_bResolved )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
WString wsTarget = m_wsTarget;
|
|
|
|
LPWSTR wszToken = wcstok( wsTarget, L"!" );
|
|
|
|
LPWSTR wszToken2 = wcstok( NULL, L"!" );
|
|
|
|
if ( wszToken2 == NULL )
|
|
{
|
|
hr = AddPhysicalSender( wszToken );
|
|
}
|
|
#ifdef __WHISTLER_UNCUT
|
|
else if ( wbem_wcsicmp( wszToken, L"msmq" ) == 0 )
|
|
{
|
|
hr = AddMSMQSender( wszToken2 );
|
|
}
|
|
else if ( wbem_wcsicmp( wszToken, L"wmi" ) == 0 )
|
|
{
|
|
LPWSTR wszToken3 = wcstok( NULL, L"!" );
|
|
|
|
if ( wszToken3 == NULL )
|
|
{
|
|
return WMIMSG_E_INVALIDADDRESS;
|
|
}
|
|
|
|
hr = AddLogicalSender( wszToken2, wszToken3 );
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
return WMIMSG_E_INVALIDADDRESS;
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
m_bResolved = TRUE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CFwdConsSend::HandleTrace( HRESULT hr, IUnknown* pCtx )
|
|
{
|
|
if ( m_pTraceSink == NULL )
|
|
{
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
return m_pTraceSink->Notify( hr, g_guidQueueType, m_wsTarget, pCtx );
|
|
}
|
|
|
|
HRESULT CFwdConsSend::SendReceive( PBYTE pData,
|
|
ULONG cData,
|
|
PBYTE pAuxData,
|
|
ULONG cAuxData,
|
|
DWORD dwFlagStatus,
|
|
IUnknown* pCtx )
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = EnsureSender();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
HandleTrace( hr, pCtx );
|
|
return hr;
|
|
}
|
|
|
|
return m_pMultiSend->SendReceive( pData,
|
|
cData,
|
|
pAuxData,
|
|
cAuxData,
|
|
dwFlagStatus,
|
|
pCtx );
|
|
}
|
|
|
|
HRESULT CFwdConsSend::Create( CLifeControl* pCtl,
|
|
LPCWSTR wszTarget,
|
|
DWORD dwFlags,
|
|
IWbemServices* pDefaultSvc,
|
|
IWmiMessageTraceSink* pTraceSink,
|
|
IWmiMessageSendReceive** ppSend )
|
|
{
|
|
HRESULT hr;
|
|
|
|
*ppSend = NULL;
|
|
|
|
CWbemPtr<IWmiMessageMultiSendReceive> pMultiSend;
|
|
|
|
hr = CoCreateInstance( CLSID_WmiMessageMultiSendReceive,
|
|
NULL,
|
|
CLSCTX_INPROC,
|
|
IID_IWmiMessageMultiSendReceive,
|
|
(void**)&pMultiSend );
|
|
if ( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
CWbemPtr<CFwdConsSend> pSend = new CFwdConsSend( pCtl );
|
|
|
|
if ( pSend == NULL )
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if ( wszTarget != NULL && *wszTarget != 0 )
|
|
{
|
|
pSend->m_wsTarget = wszTarget;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// the default is to send to local computer.
|
|
//
|
|
|
|
TCHAR achComputer[MAX_COMPUTERNAME_LENGTH+1];
|
|
ULONG ulSize = MAX_COMPUTERNAME_LENGTH+1;
|
|
GetComputerName( achComputer, &ulSize );
|
|
pSend->m_wsTarget = achComputer;
|
|
}
|
|
|
|
pSend->m_dwFlags = dwFlags;
|
|
pSend->m_pDefaultSvc = pDefaultSvc;
|
|
pSend->m_pTraceSink = pTraceSink;
|
|
pSend->m_pMultiSend = pMultiSend;
|
|
|
|
hr = pSend->QueryInterface( IID_IWmiMessageSendReceive, (void**)ppSend );
|
|
_DBG_ASSERT(SUCCEEDED(hr));
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|