937 lines
28 KiB
C++
937 lines
28 KiB
C++
/*++
|
||
|
||
Copyright (C) 1998-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
COMTRANS.CPP
|
||
|
||
Abstract:
|
||
|
||
Connects via COM
|
||
|
||
History:
|
||
|
||
a-davj 13-Jan-98 Created.
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#include <wbemidl.h>
|
||
#include <wbemint.h>
|
||
//#include "corepol.h"
|
||
#include <reg.h>
|
||
#include <wbemutil.h>
|
||
#include <objidl.h>
|
||
#include <cominit.h>
|
||
#include "wbemprox.h"
|
||
#include "comtrans.h"
|
||
#include "proxutil.h"
|
||
#include <winntsec.h>
|
||
#include <genutils.h>
|
||
//#include <winntsec.h>
|
||
#include <arrtempl.h>
|
||
#include <umi.h>
|
||
#include <wmiutils.h>
|
||
#include "dscallres.h"
|
||
#include "reqobjs.h"
|
||
#include "dssvexwrap.h"
|
||
#include "utils.h"
|
||
|
||
//***************************************************************************
|
||
//
|
||
// CDCOMTrans::CDCOMTrans
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Constructor.
|
||
//
|
||
//***************************************************************************
|
||
|
||
CDCOMTrans::CDCOMTrans()
|
||
{
|
||
m_cRef=0;
|
||
m_pLevel1 = NULL;
|
||
m_pConnection = NULL;
|
||
m_pUnk = NULL; // dont free
|
||
InterlockedIncrement(&g_cObj);
|
||
m_bInitialized = TRUE;
|
||
}
|
||
|
||
//***************************************************************************
|
||
//
|
||
// CDCOMTrans::~CDCOMTrans
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Destructor.
|
||
//
|
||
//***************************************************************************
|
||
|
||
CDCOMTrans::~CDCOMTrans(void)
|
||
{
|
||
if(m_pLevel1)
|
||
m_pLevel1->Release();
|
||
if(m_pConnection)
|
||
m_pConnection->Release();
|
||
InterlockedDecrement(&g_cObj);
|
||
}
|
||
|
||
//***************************************************************************
|
||
// HRESULT CDCOMTrans::QueryInterface
|
||
// long CDCOMTrans::AddRef
|
||
// long CDCOMTrans::Release
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Standard Com IUNKNOWN functions.
|
||
//
|
||
//***************************************************************************
|
||
|
||
STDMETHODIMP CDCOMTrans::QueryInterface (
|
||
|
||
IN REFIID riid,
|
||
OUT PPVOID ppv
|
||
)
|
||
{
|
||
*ppv=NULL;
|
||
|
||
|
||
if (m_bInitialized && (IID_IUnknown==riid || riid == IID_IWbemClientTransport))
|
||
*ppv=(IWbemClientTransport *)this;
|
||
else if(riid == IID_IWbemConnection)
|
||
*ppv=(IWbemConnection *)this;
|
||
|
||
if (NULL!=*ppv)
|
||
{
|
||
((LPUNKNOWN)*ppv)->AddRef();
|
||
return NOERROR;
|
||
}
|
||
|
||
return ResultFromScode(E_NOINTERFACE);
|
||
}
|
||
|
||
bool IsImpersonating(SECURITY_IMPERSONATION_LEVEL &impLevel)
|
||
{
|
||
HANDLE hThreadToken;
|
||
bool bImpersonating = false;
|
||
if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,
|
||
&hThreadToken))
|
||
{
|
||
|
||
DWORD dwBytesReturned = 0;
|
||
if(GetTokenInformation(
|
||
hThreadToken,
|
||
TokenImpersonationLevel,
|
||
&impLevel,
|
||
sizeof(DWORD),
|
||
&dwBytesReturned
|
||
) && ((SecurityImpersonation == impLevel) ||
|
||
(SecurityDelegation == impLevel)))
|
||
bImpersonating = true;
|
||
CloseHandle(hThreadToken);
|
||
}
|
||
return bImpersonating;
|
||
}
|
||
|
||
//***************************************************************************
|
||
//
|
||
// IsLocalConnection(IWbemLevel1Login * pLogin)
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Querries the server to see if this is a local connection. This is done
|
||
// by creating a event and asking the server to set it. This will only work
|
||
// if the server is the same box.
|
||
//
|
||
// RETURN VALUE:
|
||
//
|
||
// true if the server is the same box.
|
||
//
|
||
//***************************************************************************
|
||
|
||
bool IsLocalConnection(IUnknown * pLogin, bool bSet, BSTR PrincipalArg, bool bAuthenticate,
|
||
COAUTHIDENTITY *pauthident, bool bImpersonatingThread, BSTR UserArg)
|
||
{
|
||
bool bRet = false;
|
||
IWbemLoginHelper * pLoginHelper = NULL;
|
||
SCODE sc = pLogin->QueryInterface(IID_IWbemLoginHelper, (void **)&pLoginHelper);
|
||
if(sc != S_OK)
|
||
return false;
|
||
|
||
if(bSet)
|
||
sc = WbemSetProxyBlanket(
|
||
pLoginHelper,
|
||
(PrincipalArg) ? 16 : RPC_C_AUTHN_WINNT,
|
||
RPC_C_AUTHZ_NONE,
|
||
PrincipalArg,
|
||
(bAuthenticate) ? RPC_C_AUTHN_LEVEL_DEFAULT : RPC_C_AUTHN_LEVEL_NONE,
|
||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||
pauthident,
|
||
(bImpersonatingThread && !UserArg && IsW2KOrMore ()) ? EOAC_STATIC_CLOAKING : EOAC_NONE);
|
||
|
||
CReleaseMe rm(pLoginHelper);
|
||
GUID guid;
|
||
|
||
// The name of the event will be a guid
|
||
|
||
sc = CoCreateGuid(&guid);
|
||
if(sc != S_OK)
|
||
return false;
|
||
WCHAR wcID[50];
|
||
if(0 ==StringFromGUID2(guid, wcID, 50))
|
||
return false;
|
||
|
||
char cID[50];
|
||
wcstombs(cID, wcID, 50);
|
||
// Create the event and set its security so that all can access
|
||
#ifdef UNICODE
|
||
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, wcID);
|
||
#else
|
||
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, cID);
|
||
#endif
|
||
if(hEvent == NULL)
|
||
return false;
|
||
SetObjectAccess(hEvent);
|
||
CCloseMe cm(hEvent);
|
||
|
||
// Ask the server to set the event.
|
||
|
||
sc = pLoginHelper->SetEvent(cID);
|
||
if(sc == S_OK)
|
||
{
|
||
DWORD dwRes = WaitForSingleObject(hEvent, 0);
|
||
if(dwRes == WAIT_OBJECT_0)
|
||
return true;
|
||
}
|
||
return false;
|
||
|
||
}
|
||
|
||
//***************************************************************************
|
||
//
|
||
// SetClientIdentity
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Passes the machine name and process id to the server. Failure is not
|
||
// serious since this is debugging type info in any case.
|
||
//
|
||
//***************************************************************************
|
||
|
||
void SetClientIdentity(IUnknown * pLogin, bool bSet, BSTR PrincipalArg, bool bAuthenticate,
|
||
COAUTHIDENTITY *pauthident, bool bImpersonatingThread, BSTR UserArg)
|
||
{
|
||
bool bRet = false;
|
||
IWbemLoginClientID * pLoginHelper = NULL;
|
||
SCODE sc = pLogin->QueryInterface(IID_IWbemLoginClientID, (void **)&pLoginHelper);
|
||
if(sc != S_OK)
|
||
return;
|
||
|
||
if(bSet)
|
||
sc = WbemSetProxyBlanket(
|
||
pLoginHelper,
|
||
(PrincipalArg) ? 16 : RPC_C_AUTHN_WINNT,
|
||
RPC_C_AUTHZ_NONE,
|
||
PrincipalArg,
|
||
(bAuthenticate) ? RPC_C_AUTHN_LEVEL_DEFAULT : RPC_C_AUTHN_LEVEL_NONE,
|
||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||
pauthident,
|
||
(bImpersonatingThread && !UserArg && IsW2KOrMore ()) ? EOAC_STATIC_CLOAKING : EOAC_NONE);
|
||
|
||
CReleaseMe rm(pLoginHelper);
|
||
TCHAR tcMyName[MAX_COMPUTERNAME_LENGTH + 1];
|
||
DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
|
||
if(!GetComputerName(tcMyName,&dwSize))
|
||
return;
|
||
long lProcID = GetCurrentProcessId();
|
||
pLoginHelper->SetClientInfo(tcMyName, lProcID, 0);
|
||
}
|
||
|
||
SCODE CDCOMTrans::DoConnection(
|
||
BSTR NetworkResource,
|
||
BSTR User,
|
||
BSTR Password,
|
||
BSTR Locale,
|
||
long lFlags,
|
||
BSTR Authority,
|
||
IWbemContext *pCtx,
|
||
REFIID riid,
|
||
void **pInterface,
|
||
bool bUseLevel1Login)
|
||
{
|
||
HRESULT hr = DoActualConnection(NetworkResource, User, Password, Locale,
|
||
lFlags, Authority, pCtx, riid, pInterface, bUseLevel1Login);
|
||
|
||
if(hr == 0x800706be)
|
||
{
|
||
ERRORTRACE((LOG_WBEMPROX,"Initial connection failed with 0x800706be, retrying\n"));
|
||
Sleep(5000);
|
||
hr = DoActualConnection(NetworkResource, User, Password, Locale,
|
||
lFlags, Authority, pCtx, riid, pInterface, bUseLevel1Login);
|
||
}
|
||
return hr;
|
||
}
|
||
|
||
SCODE CDCOMTrans::DoActualConnection(
|
||
BSTR NetworkResource,
|
||
BSTR User,
|
||
BSTR Password,
|
||
BSTR Locale,
|
||
long lFlags,
|
||
BSTR Authority,
|
||
IWbemContext *pCtx,
|
||
REFIID riid,
|
||
void **pInterface,
|
||
bool bUseLevel1Login)
|
||
{
|
||
|
||
BSTR AuthArg = NULL, UserArg = NULL, PrincipalArg = NULL;
|
||
LPWSTR pNTDomain = NULL;
|
||
bool bAuthenticate = true;
|
||
bool bSet = false;
|
||
char *szUser = NULL, * szDomain = NULL, *szPassword = NULL;
|
||
|
||
SCODE sc = WBEM_E_FAILED;
|
||
|
||
// The GetDSNs handles the paths that are ds specific. If it returns true,
|
||
// then we are done.
|
||
|
||
//postponed till Blackcomb if(GetDSNs(User, Password, lFlags, NetworkResource, (IWbemServices **)pInterface, sc, pCtx))
|
||
//postponed till Blackcomb return sc;
|
||
|
||
sc = DetermineLoginTypeEx(AuthArg, UserArg, PrincipalArg, Authority, User);
|
||
if(sc != S_OK)
|
||
{
|
||
ERRORTRACE((LOG_WBEMPROX, "Cannot determine Login type, Authority = %S, User = %S\n",Authority, User));
|
||
return sc;
|
||
}
|
||
|
||
// Determine if it is local
|
||
|
||
WCHAR *t_ServerMachine = ExtractMachineName ( NetworkResource ) ;
|
||
if ( t_ServerMachine == NULL )
|
||
{
|
||
ERRORTRACE((LOG_WBEMPROX, "Cannot extract machine name -%S-\n", NetworkResource));
|
||
return WBEM_E_INVALID_PARAMETER ;
|
||
}
|
||
CVectorDeleteMe<WCHAR> dm(t_ServerMachine);
|
||
BOOL t_Local = bAreWeLocal ( t_ServerMachine ) ;
|
||
|
||
SECURITY_IMPERSONATION_LEVEL impLevel = SecurityImpersonation;
|
||
bool bImpersonatingThread = IsImpersonating (impLevel);
|
||
bool bCredentialsSpecified = (UserArg || AuthArg || Password);
|
||
|
||
// Setup the authentication structures
|
||
|
||
COSERVERINFO si;
|
||
si.pwszName = t_ServerMachine;
|
||
si.dwReserved1 = 0;
|
||
si.dwReserved2 = 0;
|
||
si.pAuthInfo = NULL;
|
||
|
||
COAUTHINFO ai;
|
||
|
||
if(bCredentialsSpecified)
|
||
si.pAuthInfo = &ai;
|
||
else
|
||
si.pAuthInfo = NULL;
|
||
|
||
ai.dwAuthzSvc = RPC_C_AUTHZ_NONE;
|
||
if(PrincipalArg)
|
||
{
|
||
ai.dwAuthnSvc = 16; // kerberos, hard coded due to header file bug!
|
||
ai.pwszServerPrincName = PrincipalArg;
|
||
}
|
||
else
|
||
{
|
||
ai.dwAuthnSvc = RPC_C_AUTHN_WINNT;
|
||
ai.pwszServerPrincName = NULL;
|
||
}
|
||
ai.dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
|
||
ai.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
|
||
ai.dwCapabilities = 0;
|
||
|
||
COAUTHIDENTITY authident;
|
||
ai.pAuthIdentityData = &authident;
|
||
|
||
// Load up the structure.
|
||
memset((void *)&authident,0,sizeof(COAUTHIDENTITY));
|
||
if(IsNT())
|
||
{
|
||
if(UserArg)
|
||
{
|
||
authident.UserLength = wcslen(UserArg);
|
||
authident.User = (LPWSTR)UserArg;
|
||
}
|
||
if(AuthArg)
|
||
{
|
||
authident.DomainLength = wcslen(AuthArg);
|
||
authident.Domain = (LPWSTR)AuthArg;
|
||
}
|
||
if(Password)
|
||
{
|
||
authident.PasswordLength = wcslen(Password);
|
||
authident.Password = (LPWSTR)Password;
|
||
}
|
||
authident.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||
}
|
||
else
|
||
{
|
||
// Fill in the indentity structure
|
||
|
||
if(UserArg)
|
||
{
|
||
szUser = new char[MAX_PATH+1];
|
||
if(szUser == NULL)
|
||
return WBEM_E_OUT_OF_MEMORY;
|
||
wcstombs(szUser, UserArg, MAX_PATH);
|
||
authident.UserLength = strlen(szUser);
|
||
authident.User = (LPWSTR)szUser;
|
||
}
|
||
if(AuthArg)
|
||
{
|
||
szDomain = new char[MAX_PATH+1];
|
||
if(szDomain == NULL)
|
||
{
|
||
delete [] szUser;
|
||
return WBEM_E_OUT_OF_MEMORY;
|
||
}
|
||
wcstombs(szDomain, AuthArg, MAX_PATH);
|
||
authident.DomainLength = strlen(szDomain);
|
||
authident.Domain = (LPWSTR)szDomain;
|
||
}
|
||
if(Password)
|
||
{
|
||
szPassword = new char[MAX_PATH+1];
|
||
if(szPassword == NULL)
|
||
{
|
||
delete [] szUser;
|
||
delete [] szDomain;
|
||
return WBEM_E_OUT_OF_MEMORY;
|
||
}
|
||
wcstombs(szPassword, Password, MAX_PATH);
|
||
authident.PasswordLength = strlen(szPassword);
|
||
authident.Password = (LPWSTR)szPassword;
|
||
}
|
||
authident.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
||
}
|
||
CVectorDeleteMe<char> dm1(szUser);
|
||
CVectorDeleteMe<char> dm2(szDomain);
|
||
CVectorDeleteMe<char> dm3(szUser);
|
||
|
||
|
||
// Nt 4.0 rpc crashes if given a null domain name along with a valid user name
|
||
// [marioh, NT RAID: 239135, 03/03/2001]
|
||
/*if(authident.DomainLength == 0 && authident.UserLength > 0 && IsNT())
|
||
{
|
||
|
||
CNtSid::SidType st = CNtSid::CURRENT_USER;
|
||
if(bImpersonatingThread)
|
||
st = CNtSid::CURRENT_THREAD;
|
||
CNtSid sid(st);
|
||
DWORD dwRet = sid.GetInfo(NULL, &pNTDomain, NULL);
|
||
if(dwRet == 0)
|
||
{
|
||
authident.DomainLength = wcslen(pNTDomain);
|
||
authident.Domain = (LPWSTR)pNTDomain;
|
||
}
|
||
}*/
|
||
|
||
// Nt 4.0 rpc crashes if given a null domain and null user name along with a password
|
||
|
||
if(authident.DomainLength == 0 && authident.UserLength == 0 && authident.PasswordLength > 0
|
||
&& IsNT() && !IsW2KOrMore())
|
||
{
|
||
return WBEM_E_INVALID_PARAMETER;
|
||
}
|
||
|
||
// Get the IWbemLevel1Login pointer
|
||
|
||
sc = DoCCI(&si ,t_Local, bUseLevel1Login, lFlags);
|
||
|
||
if((sc == 0x800706d3 || sc == 0x800706ba) && !t_Local)
|
||
{
|
||
// If we are going to a stand alone dcom box, try again with the authentication level lowered
|
||
|
||
ai.dwAuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
|
||
SCODE hr = DoCCI(&si ,t_Local, bUseLevel1Login, lFlags);
|
||
if(hr == S_OK)
|
||
{
|
||
sc = S_OK;
|
||
bAuthenticate = false;
|
||
}
|
||
}
|
||
if(sc == 0x80080005 && t_Local)
|
||
{
|
||
// special patch for the case where win98 occasionally loses its class factory registration;
|
||
|
||
HANDLE hNeedRegistration = OpenEvent(EVENT_MODIFY_STATE , FALSE, TEXT("WINMGMT_NEED_REGISTRATION"));
|
||
HANDLE hRegistrationDone = OpenEvent(EVENT_MODIFY_STATE , FALSE, TEXT("WINMGMT_REGISTRATION_DONE"));
|
||
if(hNeedRegistration && hRegistrationDone)
|
||
{
|
||
ResetEvent(hRegistrationDone);
|
||
SetEvent(hNeedRegistration);
|
||
WaitForSingleObject(hRegistrationDone, 30000);
|
||
sc = DoCCI(&si ,t_Local, bUseLevel1Login,lFlags);
|
||
CloseHandle(hNeedRegistration);
|
||
CloseHandle(hRegistrationDone);
|
||
}
|
||
|
||
}
|
||
|
||
if(sc != S_OK)
|
||
goto cleanup;
|
||
|
||
// Do the security negotiation
|
||
|
||
if(!t_Local)
|
||
{
|
||
// Suppress the SetBlanket call if we are on a Win2K delegation-level thread with implicit credentials
|
||
if (!(bImpersonatingThread && IsW2KOrMore() && !bCredentialsSpecified && (SecurityDelegation == impLevel)))
|
||
{
|
||
// Note that if we are on a Win2K impersonating thread with no user specified
|
||
// we should allow DCOM to use whatever EOAC capabilities are set up for this
|
||
// application. This allows remote connections with NULL User/Password but
|
||
// non-NULL authority to succeed.
|
||
|
||
sc = WbemSetProxyBlanket(
|
||
m_pUnk,
|
||
(PrincipalArg) ? 16 : RPC_C_AUTHN_WINNT,
|
||
RPC_C_AUTHZ_NONE,
|
||
PrincipalArg,
|
||
(bAuthenticate) ? RPC_C_AUTHN_LEVEL_DEFAULT : RPC_C_AUTHN_LEVEL_NONE,
|
||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||
(bCredentialsSpecified) ? &authident : NULL,
|
||
(bImpersonatingThread && !UserArg && IsW2KOrMore ()) ? EOAC_STATIC_CLOAKING : EOAC_NONE);
|
||
|
||
bSet = true;
|
||
if(sc != S_OK)
|
||
{
|
||
ERRORTRACE((LOG_WBEMPROX,"Error setting Level1 login interface security pointer, return code is 0x%x\n", sc));
|
||
goto cleanup;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// if impersonating and nt5, then set cloaking
|
||
|
||
if(bImpersonatingThread && IsW2KOrMore())
|
||
{
|
||
sc = WbemSetProxyBlanket(
|
||
m_pUnk,
|
||
RPC_C_AUTHN_WINNT,
|
||
RPC_C_AUTHZ_NONE,
|
||
PrincipalArg,
|
||
(bAuthenticate) ? RPC_C_AUTHN_LEVEL_DEFAULT : RPC_C_AUTHN_LEVEL_NONE,
|
||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||
NULL,
|
||
EOAC_STATIC_CLOAKING);
|
||
if(sc != S_OK && sc != 0x80004002) // no such interface is ok since you get that when
|
||
// called inproc!
|
||
{
|
||
ERRORTRACE((LOG_WBEMPROX,"Error setting Level1 login interface security pointer, return code is 0x%x\n", sc));
|
||
goto cleanup;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
SetClientIdentity(m_pUnk, bSet, PrincipalArg,
|
||
bAuthenticate, &authident, bImpersonatingThread, UserArg);
|
||
if(bCredentialsSpecified &&
|
||
IsLocalConnection(m_pUnk, bSet, PrincipalArg,
|
||
bAuthenticate, &authident, bImpersonatingThread, UserArg))
|
||
{
|
||
ERRORTRACE((LOG_WBEMPROX,"Credentials were specified for a local connections\n"));
|
||
sc = WBEM_E_LOCAL_CREDENTIALS;
|
||
goto cleanup;
|
||
}
|
||
|
||
// The MAX_WAIT flag only applies to CoCreateInstanceEx, get rid of it
|
||
|
||
lFlags = lFlags & ~WBEM_FLAG_CONNECT_USE_MAX_WAIT;
|
||
if(m_pLevel1)
|
||
sc = m_pLevel1->NTLMLogin(NetworkResource, Locale, lFlags, pCtx,(IWbemServices**) pInterface);
|
||
else
|
||
sc = m_pConnection->ConnectorLogin(NetworkResource, Locale, lFlags,
|
||
pCtx, riid, pInterface);
|
||
|
||
if(sc == 0x800706d3 && !t_Local)
|
||
{
|
||
// If we are going to a stand alone dcom box, try again with the authentication level lowered
|
||
|
||
HRESULT hr;
|
||
if(m_pLevel1)
|
||
hr = m_pLevel1->NTLMLogin(NetworkResource, Locale, lFlags, pCtx, (IWbemServices**)pInterface);
|
||
else
|
||
hr = m_pConnection->ConnectorLogin(NetworkResource, Locale, lFlags,
|
||
pCtx, riid, pInterface);
|
||
if(hr == S_OK)
|
||
{
|
||
sc = S_OK;
|
||
SetInterfaceSecurity((IUnknown *)*pInterface, &authident, false);
|
||
}
|
||
}
|
||
|
||
if((sc != S_OK) && (sc != WBEM_E_INVALID_NAMESPACE))
|
||
ERRORTRACE((LOG_WBEMPROX,"NTLMLogin resulted in hr = 0x%x\n", sc));
|
||
else
|
||
cleanup:
|
||
if(UserArg)
|
||
SysFreeString(UserArg);
|
||
if(PrincipalArg)
|
||
SysFreeString(PrincipalArg);
|
||
if(AuthArg)
|
||
SysFreeString(AuthArg);
|
||
if(pNTDomain)
|
||
delete pNTDomain;
|
||
return sc;
|
||
}
|
||
|
||
|
||
//***************************************************************************
|
||
//
|
||
// SCODE CDCOMTrans::ConnectServer
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Connects up to either local or remote WBEM Server. Returns
|
||
// standard SCODE and more importantly sets the address of an initial
|
||
// stub pointer.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// AddressType Not used
|
||
// dwBinaryAddressLength Not used
|
||
// pbBinaryAddress Not used
|
||
//
|
||
// NetworkResource Namespace path
|
||
// User User name
|
||
// Password password
|
||
// LocaleId language locale
|
||
// lFlags flags
|
||
// Authority domain
|
||
// ppProv set to provdider proxy
|
||
//
|
||
// RETURN VALUE:
|
||
//
|
||
// S_OK all is well
|
||
// else error listed in WBEMSVC.H
|
||
//
|
||
//***************************************************************************
|
||
|
||
|
||
SCODE CDCOMTrans::ConnectServer (
|
||
IN BSTR AddressType,
|
||
IN DWORD dwBinaryAddressLength,
|
||
IN BYTE* pbBinaryAddress,
|
||
|
||
IN BSTR NetworkResource,
|
||
IN BSTR User,
|
||
IN BSTR Password,
|
||
IN BSTR LocaleId,
|
||
IN long lFlags,
|
||
IN BSTR Authority,
|
||
IWbemContext __RPC_FAR *pCtx,
|
||
OUT IWbemServices FAR* FAR* ppProv
|
||
)
|
||
{
|
||
return DoConnection(NetworkResource, User, Password, LocaleId, lFlags,
|
||
Authority, pCtx, IID_IWbemServices, (void **)ppProv, true);
|
||
}
|
||
|
||
struct WaitThreadArg
|
||
{
|
||
DWORD m_dwThreadId;
|
||
HANDLE m_hTerminate;
|
||
};
|
||
|
||
DWORD WINAPI TimeoutThreadRoutine(LPVOID lpParameter)
|
||
{
|
||
|
||
WaitThreadArg * pReq = (WaitThreadArg *)lpParameter;
|
||
DWORD dwRet = WaitForSingleObject(pReq->m_hTerminate, 60000);
|
||
if(dwRet == WAIT_TIMEOUT)
|
||
{
|
||
HRESULT hr = CoInitializeEx(NULL,COINIT_MULTITHREADED );
|
||
if(FAILED(hr))
|
||
return 1;
|
||
ICancelMethodCalls * px = NULL;
|
||
hr = CoGetCancelObject(pReq->m_dwThreadId, IID_ICancelMethodCalls,
|
||
(void **)&px);
|
||
if(SUCCEEDED(hr))
|
||
{
|
||
hr = px->Cancel(0);
|
||
px->Release();
|
||
}
|
||
CoUninitialize();
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
//***************************************************************************
|
||
//
|
||
// DoCCI
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Connects up to WBEM via DCOM. But before making the call, a thread cancel
|
||
// thread may be created to handle the case where we try to connect up
|
||
// to a box which is hanging
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// NetworkResource Namespze path
|
||
// ppLogin set to Login proxy
|
||
// bLocal Indicates if connection is local
|
||
// lFlags Mainly used for WBEM_FLAG_CONNECT_USE_MAX_WAIT flag
|
||
//
|
||
// RETURN VALUE:
|
||
//
|
||
// S_OK all is well
|
||
// else error listed in WBEMSVC.H
|
||
//
|
||
//***************************************************************************
|
||
|
||
SCODE CDCOMTrans::DoCCI (IN COSERVERINFO * psi, IN BOOL bLocal, bool bUseLevel1Login,long lFlags )
|
||
{
|
||
|
||
if(lFlags & WBEM_FLAG_CONNECT_USE_MAX_WAIT)
|
||
{
|
||
// special case. we want to spawn off a thread that will kill of our
|
||
// request if it takes too long
|
||
|
||
WaitThreadArg arg;
|
||
arg.m_hTerminate = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||
if(arg.m_hTerminate == NULL)
|
||
return WBEM_E_OUT_OF_MEMORY;
|
||
CCloseMe cm(arg.m_hTerminate);
|
||
arg.m_dwThreadId = GetCurrentThreadId();
|
||
|
||
DWORD dwIDLikeIcare;
|
||
HRESULT hr = CoEnableCallCancellation(NULL);
|
||
if(FAILED(hr))
|
||
return hr;
|
||
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TimeoutThreadRoutine,
|
||
(LPVOID)&arg, 0, &dwIDLikeIcare);
|
||
if(hThread == NULL)
|
||
{
|
||
CoDisableCallCancellation(NULL);
|
||
return WBEM_E_OUT_OF_MEMORY;
|
||
}
|
||
CCloseMe cm2(hThread);
|
||
hr = DoActualCCI (psi, bLocal, bUseLevel1Login,
|
||
lFlags & ~WBEM_FLAG_CONNECT_USE_MAX_WAIT );
|
||
CoDisableCallCancellation(NULL);
|
||
SetEvent(arg.m_hTerminate);
|
||
WaitForSingleObject(hThread, INFINITE);
|
||
return hr;
|
||
}
|
||
else
|
||
return DoActualCCI (psi, bLocal, bUseLevel1Login, lFlags );
|
||
|
||
}
|
||
|
||
//***************************************************************************
|
||
//
|
||
// DoActualCCI
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Connects up to WBEM via DCOM.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// NetworkResource Namespze path
|
||
// ppLogin set to Login proxy
|
||
// bLocal Indicates if connection is local
|
||
// lFlags Not used
|
||
//
|
||
// RETURN VALUE:
|
||
//
|
||
// S_OK all is well
|
||
// else error listed in WBEMSVC.H
|
||
//
|
||
//***************************************************************************
|
||
|
||
SCODE CDCOMTrans::DoActualCCI (IN COSERVERINFO * psi, IN BOOL bLocal, bool bUseLevel1Login,long lFlags )
|
||
{
|
||
HRESULT t_Result ;
|
||
MULTI_QI mqi;
|
||
|
||
|
||
if(bUseLevel1Login)
|
||
mqi.pIID = &IID_IWbemLevel1Login;
|
||
else
|
||
mqi.pIID = &IID_IWbemConnectorLogin;
|
||
mqi.pItf = 0;
|
||
mqi.hr = 0;
|
||
|
||
t_Result = CoCreateInstanceEx (
|
||
CLSID_WbemLevel1Login,
|
||
NULL,
|
||
CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
|
||
( bLocal ) ? NULL : psi ,
|
||
1,
|
||
&mqi
|
||
);
|
||
|
||
if ( t_Result == S_OK )
|
||
{
|
||
if(bUseLevel1Login)
|
||
m_pLevel1 = (IWbemLevel1Login*) mqi.pItf ;
|
||
else
|
||
m_pConnection = (IWbemConnectorLogin*) mqi.pItf;
|
||
m_pUnk = mqi.pItf; // just a copy, dont release!
|
||
DEBUGTRACE((LOG_WBEMPROX,"ConnectViaDCOM, CoCreateInstanceEx resulted in hr = 0x%x\n", t_Result ));
|
||
}
|
||
else
|
||
{
|
||
ERRORTRACE((LOG_WBEMPROX,"ConnectViaDCOM, CoCreateInstanceEx resulted in hr = 0x%x\n", t_Result ));
|
||
}
|
||
|
||
return t_Result ;
|
||
}
|
||
|
||
SCODE CDCOMTrans::Open(
|
||
/* [in] */ const BSTR strObject,
|
||
/* [in] */ const BSTR User,
|
||
/* [in] */ const BSTR Password,
|
||
/* [in] */ const BSTR Locale,
|
||
/* [in] */ long lFlags,
|
||
/* [in] */ IWbemContext __RPC_FAR *pCtx,
|
||
/* [in] */ REFIID riid,
|
||
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *pInterface,
|
||
/* [out] */ IWbemCallResultEx __RPC_FAR *__RPC_FAR *pCallRes)
|
||
{
|
||
|
||
/* // parse the path and get its info
|
||
|
||
IWbemPath *pParser = 0;
|
||
IWbemPathKeyList * pKeyList = NULL;
|
||
IWbemServices * pServ = NULL;
|
||
|
||
SCODE sc = CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER,
|
||
IID_IWbemPath, (LPVOID *) &pParser);
|
||
if(FAILED(sc))
|
||
return sc;
|
||
|
||
sc = pParser->SetText(WBEMPATH_CREATE_ACCEPT_ALL | WBEMPATH_TREAT_SINGLE_IDENT_AS_NS, strObject);
|
||
if(FAILED(sc))
|
||
return sc;
|
||
|
||
unsigned __int64 ull;
|
||
sc = pParser->GetInfo(0,&ull);
|
||
if(FAILED(sc))
|
||
return sc;
|
||
|
||
// if the path is for the ds providers, special case them
|
||
|
||
if((ull & WBEMPATH_INFO_NATIVE_PATH) || (ull & WBEMPATH_INFO_WMI_PATH))
|
||
{
|
||
|
||
IUmiURL * pUrlPath = NULL;
|
||
sc = pParser->QueryInterface(IID_IUmiURL, (void **) &pUrlPath);
|
||
if(FAILED(sc))
|
||
return sc;
|
||
CReleaseMe rm(pUrlPath);
|
||
|
||
// if the clsid is a ds provider
|
||
|
||
CLSID clsid;
|
||
sc = GetProviderCLSID(clsid, pUrlPath);
|
||
if(SUCCEEDED(sc))
|
||
{
|
||
sc = ConnectServer (NULL, 0, NULL, strObject, User, Password, Locale,
|
||
lFlags, NULL, pCtx, &pServ);
|
||
if(SUCCEEDED(sc))
|
||
{
|
||
sc = pServ->QueryInterface(riid, pInterface);
|
||
pServ->Release();
|
||
}
|
||
return sc;
|
||
}
|
||
}
|
||
|
||
// Get the namespace path
|
||
|
||
DWORD dwLen = wcslen(strObject) + 20; // a bit extra for \\. and null terminator
|
||
DWORD dwSize = dwLen;
|
||
WCHAR * pNamespace = new WCHAR[dwLen];
|
||
if(pNamespace == NULL)
|
||
return WBEM_E_OUT_OF_MEMORY;
|
||
CDeleteMe<WCHAR> dm(pNamespace);
|
||
sc = pParser->GetText(WBEMPATH_GET_SERVER_AND_NAMESPACE_ONLY, &dwSize, pNamespace);
|
||
if(FAILED(sc))
|
||
return sc;
|
||
*/
|
||
// Get the actual namespace
|
||
|
||
SCODE sc = S_OK;
|
||
VARIANT var;
|
||
VariantInit(&var);
|
||
if(pCtx)
|
||
sc = pCtx->GetValue(L"__authority", 0, &var);
|
||
if(SUCCEEDED(sc) && pCtx)
|
||
{
|
||
sc = DoConnection (strObject, User, Password, Locale,
|
||
lFlags, var.bstrVal, pCtx, riid, pInterface, false);
|
||
VariantClear(&var);
|
||
}
|
||
else
|
||
sc = DoConnection (strObject, User, Password, Locale,
|
||
lFlags, NULL, pCtx, riid, pInterface, false);
|
||
/* if(FAILED(sc))
|
||
return sc;
|
||
CReleaseMe rm(pServ);
|
||
|
||
// If path type is a namespace, then just return that
|
||
|
||
if(WBEMPATH_INFO_SERVER_NAMESPACE_ONLY & ull)
|
||
return pServ->QueryInterface(riid, pInterface);
|
||
|
||
// otherwise, get the object path
|
||
|
||
IWbemClassObject * pObj = NULL;
|
||
dwSize = dwLen;
|
||
sc = pParser->GetText(WBEMPATH_GET_RELATIVE_ONLY, &dwSize, pNamespace);
|
||
if(FAILED(sc))
|
||
return sc;
|
||
|
||
BSTR strObjectPath = SysAllocString(pNamespace);
|
||
if(strObjectPath == NULL)
|
||
return WBEM_E_OUT_OF_MEMORY;
|
||
|
||
sc = pServ->GetObject(strObjectPath, lFlags, pCtx, &pObj, NULL);
|
||
SysFreeString(strObjectPath);
|
||
if(FAILED(sc))
|
||
return sc;
|
||
|
||
return pObj->QueryInterface(riid, pInterface);
|
||
*/
|
||
return sc;
|
||
|
||
}
|
||
|
||
SCODE CDCOMTrans::OpenAsync(
|
||
/* [in] */ const BSTR strObject,
|
||
/* [in] */ const BSTR strUser,
|
||
/* [in] */ const BSTR strPassword,
|
||
/* [in] */ const BSTR strLocale,
|
||
/* [in] */ long lFlags,
|
||
/* [in] */ IWbemContext __RPC_FAR *pCtx,
|
||
/* [in] */ REFIID riid,
|
||
/* [in] */ IWbemObjectSinkEx __RPC_FAR *pResponseHandler)
|
||
{
|
||
return WBEM_E_FAILED;
|
||
}
|
||
|
||
SCODE CDCOMTrans::Cancel(
|
||
/* [in] */ long lFlags,
|
||
/* [in] */ IWbemObjectSinkEx __RPC_FAR *pHandler)
|
||
{
|
||
return WBEM_E_FAILED;
|
||
}
|
||
|