windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/msg/rpcsend.cpp
2020-09-26 16:20:57 +08:00

332 lines
7.6 KiB
C++

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
Abstract:
History:
--*/
#include "precomp.h"
#include <assert.h>
#include <comutl.h>
#include "rpchdr.h"
#include "rpcsend.h"
#include "rpcmsg.h"
extern HRESULT RpcResToWmiRes( RPC_STATUS stat, HRESULT hrDefault );
/*****************************************************************
CMsgRpcSender
******************************************************************/
HRESULT CMsgRpcSender::Open( LPCWSTR wszTarget,
DWORD dwFlags,
WMIMSG_SNDR_AUTH_INFOP pAuthInfo,
LPCWSTR wszResponse,
IWmiMessageTraceSink* pTraceSink,
IWmiMessageSendReceive** ppSend )
{
HRESULT hr;
ENTER_API_CALL
CWbemPtr<CMsgRpcSend> pSend;
pSend = new CMsgRpcSend( m_pControl,
wszTarget,
dwFlags,
pAuthInfo,
wszResponse,
pTraceSink );
if ( (dwFlags & WMIMSG_FLAG_SNDR_LAZY_INIT) == 0 )
{
hr = pSend->EnsureSender();
if ( FAILED(hr) )
{
return hr;
}
}
return pSend->QueryInterface(IID_IWmiMessageSendReceive, (void**)ppSend);
EXIT_API_CALL
}
/*****************************************************************
CMsgRpcSend
******************************************************************/
CMsgRpcSend::CMsgRpcSend( CLifeControl* pCtl,
LPCWSTR wszTarget,
DWORD dwFlags,
WMIMSG_SNDR_AUTH_INFOP pAuthInfo,
LPCWSTR wszResponse,
IWmiMessageTraceSink* pTraceSink )
: CUnkBase<IWmiMessageSendReceive,&IID_IWmiMessageSendReceive>(pCtl),
m_dwFlags(dwFlags), m_pTraceSink( pTraceSink ),
m_hBinding(NULL), m_bInit(FALSE)
{
//
// save our computer name.
//
TCHAR achComputer[MAX_COMPUTERNAME_LENGTH+1];
ULONG ulSize = MAX_COMPUTERNAME_LENGTH+1;
GetComputerName( achComputer, &ulSize );
m_wsComputer = achComputer;
//
// if the target is NULL, then we use our computer name as the target.
//
if ( wszTarget != NULL && *wszTarget != '\0' )
{
m_wsTarget = wszTarget;
}
else
{
m_wsTarget = m_wsComputer;
}
if ( pAuthInfo != NULL )
{
if ( pAuthInfo->wszTargetPrincipal != NULL )
{
m_wsTargetPrincipal = pAuthInfo->wszTargetPrincipal;
}
}
}
CMsgRpcSend::~CMsgRpcSend()
{
Clear();
}
HRESULT CMsgRpcSend::HandleTrace( HRESULT hr,
LPCWSTR wszTrace,
IUnknown* pCtx )
{
//
// we use the error sink approach instead of just returning an error
// because sometimes multiple senders are used in one send operation
// ( when using the multi send impl ) and we need to be able to
// distinguish which one failed.
//
if ( m_pTraceSink != NULL )
{
m_pTraceSink->Notify( hr, CLSID_WmiMessageRpcSender, wszTrace, pCtx );
}
return hr;
}
void CMsgRpcSend::Clear()
{
if ( m_hBinding != NULL )
{
RpcBindingFree( &m_hBinding );
m_hBinding = NULL;
}
m_bInit = FALSE;
}
HRESULT CMsgRpcSend::EnsureSender()
{
HRESULT hr = S_OK;
RPC_STATUS stat;
CInCritSec ics(&m_cs);
if ( m_bInit )
{
return WBEM_S_NO_ERROR;
}
Clear();
//
// connect to the stub at the target.
//
stat = RpcBindingFromStringBinding( m_wsTarget, &m_hBinding );
if ( stat != RPC_S_OK )
{
return RpcResToWmiRes( stat, WMIMSG_E_INVALIDADDRESS );
}
//
// binding may be dynamic, so we may have to resolve it.
//
stat = RpcEpResolveBinding( m_hBinding,
IWmiMessageRemoteSendReceive_v1_0_c_ifspec );
if ( stat != RPC_S_OK )
{
return RpcResToWmiRes( stat, WMIMSG_E_TARGETNOTFOUND );
}
//
// set binding auth info based on auth and encryption flags.
//
RPC_SECURITY_QOS qos;
DWORD dwAuthnSvc, dwAuthzSvc, dwAuthnLevel;
LPWSTR wszPrincipal = NULL;
if ( m_wsTargetPrincipal.Length() > 0 )
{
wszPrincipal = m_wsTargetPrincipal;
}
qos.Version = RPC_C_SECURITY_QOS_VERSION;
qos.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT;
if ( m_dwFlags & WMIMSG_FLAG_SNDR_ENCRYPT )
{
dwAuthnSvc = RPC_C_AUTHN_GSS_NEGOTIATE;
dwAuthzSvc = RPC_C_AUTHZ_DEFAULT;
dwAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
qos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
qos.ImpersonationType = RPC_C_IMP_LEVEL_IDENTIFY;
}
else if ( m_dwFlags & WMIMSG_FLAG_SNDR_AUTHENTICATE )
{
dwAuthnSvc = RPC_C_AUTHN_GSS_NEGOTIATE;
dwAuthzSvc = RPC_C_AUTHZ_DEFAULT;
qos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
qos.ImpersonationType = RPC_C_IMP_LEVEL_IDENTIFY;
dwAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
}
else
{
dwAuthnSvc = RPC_C_AUTHN_NONE;
dwAuthzSvc = RPC_C_AUTHZ_NONE;
qos.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC;
qos.ImpersonationType = RPC_C_IMP_LEVEL_ANONYMOUS;
dwAuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
}
stat = RpcBindingSetAuthInfoEx( m_hBinding,
wszPrincipal,
dwAuthnLevel,
dwAuthnSvc,
NULL,
dwAuthzSvc,
&qos );
if ( stat != RPC_S_OK )
{
return RpcResToWmiRes( stat, WMIMSG_E_AUTHFAILURE );
}
m_bInit = TRUE;
return hr;
}
HRESULT CMsgRpcSend::PerformSend( PBYTE pData,
ULONG cData,
PBYTE pAuxData,
ULONG cAuxData )
{
HRESULT hr;
RpcTryExcept
{
hr = ::SendReceive( m_hBinding,
pData,
cData,
pAuxData,
cAuxData );
}
RpcExcept(1)
{
hr = RpcResToWmiRes( RpcExceptionCode(), S_OK );
}
RpcEndExcept
return hr;
}
HRESULT CMsgRpcSend::SendReceive( PBYTE pData,
ULONG cData,
PBYTE pAuxData,
ULONG cAuxData,
DWORD dwFlagStatus,
IUnknown* pCtx )
{
HRESULT hr;
BYTE achHdr[512];
CBuffer HdrStrm( achHdr, 512, FALSE );
CMsgRpcHdr RpcHdr( m_wsComputer, cAuxData );
ENTER_API_CALL
hr = EnsureSender();
if ( FAILED(hr) )
{
return HandleTrace( hr, m_wsTarget, pCtx );
}
//
// create our Rpc hdr and prepend it to the user's hdr data.
//
hr = RpcHdr.Persist( HdrStrm );
if ( FAILED(hr) )
{
return HandleTrace( hr, m_wsTarget, pCtx );
}
hr = HdrStrm.Write( pAuxData, cAuxData, NULL );
if ( FAILED(hr) )
{
return HandleTrace( hr, m_wsTarget, pCtx );
}
hr = PerformSend( pData,
cData,
HdrStrm.GetRawData(),
HdrStrm.GetIndex() );
if ( FAILED(hr) )
{
//
// this is so the next call will reset us.
//
Clear();
hr = RpcResToWmiRes( hr, S_OK );
}
HandleTrace( hr, m_wsTarget, pCtx );
EXIT_API_CALL
return hr;
}