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.
 
 
 
 
 
 

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;
}