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.
826 lines
26 KiB
826 lines
26 KiB
/*++
|
|
|
|
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 <reg.h>
|
|
#include <wbemutil.h>
|
|
#include <objidl.h>
|
|
#include <cominit.h>
|
|
#include "wbemprox.h"
|
|
#include "comtrans.h"
|
|
#include <winntsec.h>
|
|
#include <genutils.h>
|
|
#include <arrtempl.h>
|
|
#include <wmiutils.h>
|
|
#include <strsafe.h>
|
|
#include <winsock2.h>
|
|
#include <autoptr.h>
|
|
|
|
// The following should not be changed since 9x boxes to not support privacy.
|
|
#define AUTH_LEVEL RPC_C_AUTHN_LEVEL_DEFAULT
|
|
|
|
class CSocketInit
|
|
{
|
|
private:
|
|
bool m_bInitDone;
|
|
public:
|
|
CSocketInit() : m_bInitDone(false){};
|
|
int Init();
|
|
~CSocketInit(){if(m_bInitDone) WSACleanup ();};
|
|
};
|
|
|
|
int CSocketInit::Init()
|
|
{
|
|
WORD wVersionRequested;
|
|
WSADATA wsaData;
|
|
int err;
|
|
wVersionRequested = MAKEWORD( 2, 2 );
|
|
int iRet = WSAStartup (wVersionRequested, & wsaData);
|
|
if(iRet == 0)
|
|
m_bInitDone = true;
|
|
return iRet;
|
|
}
|
|
|
|
BOOL bGotDot(char * pTest)
|
|
{
|
|
if(pTest == NULL)
|
|
return FALSE;
|
|
for(;*pTest && *pTest != '.'; pTest++); // intentional semi
|
|
if(*pTest == '.')
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
struct hostent * GetFQDN(WCHAR * pServer)
|
|
{
|
|
SIZE_T Len = wcslen(pServer);
|
|
SIZE_T LenAnsi = 4*Len;
|
|
wmilib::auto_buffer<CHAR> pAnsiServerName(new CHAR[LenAnsi+1]);
|
|
ULONG BytesCopyed = 0;
|
|
//
|
|
// Use the same routine that RPCRT4 uses
|
|
//
|
|
NTSTATUS Status = RtlUnicodeToMultiByteN(pAnsiServerName.get(),LenAnsi,&BytesCopyed,pServer,Len*sizeof(WCHAR));
|
|
if (0 != Status) return NULL;
|
|
pAnsiServerName[BytesCopyed] = 0;
|
|
|
|
// if it is an ip string
|
|
|
|
long lIP = inet_addr(pAnsiServerName.get());
|
|
if(lIP != INADDR_NONE)
|
|
{
|
|
struct hostent * pRet = gethostbyaddr((char *)&lIP, 4, AF_INET );
|
|
if(pRet && pRet->h_name)
|
|
{
|
|
// search the returned name for at least one dot. Sometimes, gethostbyaddr will just return
|
|
// the lanman name and not the fqdn.
|
|
|
|
if(bGotDot(pRet->h_name))
|
|
return pRet; // normal case, all is well!
|
|
|
|
// try passing the short name to get the fqdn version
|
|
|
|
DWORD dwLen = lstrlenA(pRet->h_name) + 1;
|
|
char * pNew = new char[dwLen];
|
|
if(pNew == NULL)
|
|
return NULL;
|
|
CVectorDeleteMe<char> dm2(pNew);
|
|
StringCchCopyA(pNew, dwLen, pRet->h_name);
|
|
pRet = gethostbyname(pNew);
|
|
if(pRet && bGotDot(pRet->h_name))
|
|
return pRet; // normal case, all is well!
|
|
}
|
|
}
|
|
return gethostbyname(pAnsiServerName.get());
|
|
}
|
|
|
|
#define PREFIXSTR L"RPCSS/"
|
|
|
|
HRESULT BuildReturnString(WCHAR * pFQDN, WCHAR ** ppResult)
|
|
{
|
|
if(pFQDN == NULL)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
DWORD dwBuffLen = wcslen(pFQDN) + wcslen(PREFIXSTR) + 1;
|
|
*ppResult = new WCHAR[dwBuffLen];
|
|
if(*ppResult == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
StringCchCopy(*ppResult, dwBuffLen, PREFIXSTR);
|
|
StringCchCat(*ppResult, dwBuffLen, pFQDN);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT GetPrincipal(WCHAR * pServerMachine, WCHAR ** ppResult, BOOL &bLocal, CSocketInit & sock)
|
|
{
|
|
|
|
DWORD dwLocalFQDNLen = 0;
|
|
DWORD dwBuffLen;
|
|
WCHAR * pwsCurrentCompFQDN = NULL;
|
|
bLocal = FALSE;
|
|
*ppResult = NULL;
|
|
|
|
// Get the current computer name in FQDN format
|
|
|
|
BOOL bRet = GetComputerNameEx(ComputerNameDnsFullyQualified, NULL, &dwLocalFQDNLen);
|
|
if(bRet || GetLastError() != ERROR_MORE_DATA)
|
|
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,GetLastError());
|
|
dwLocalFQDNLen++; // add one for the null
|
|
pwsCurrentCompFQDN = new WCHAR[dwLocalFQDNLen];
|
|
if(pwsCurrentCompFQDN == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
CVectorDeleteMe<WCHAR> dm(pwsCurrentCompFQDN);
|
|
bRet = GetComputerNameEx(ComputerNameDnsFullyQualified, pwsCurrentCompFQDN, &dwLocalFQDNLen);
|
|
if(!bRet)
|
|
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,GetLastError());
|
|
|
|
// if the name is "." or equal to the current machine, no need to do much fancy work here
|
|
|
|
if(bAreWeLocal ( pServerMachine ))
|
|
{
|
|
bLocal = TRUE;
|
|
return BuildReturnString(pwsCurrentCompFQDN, ppResult);
|
|
}
|
|
|
|
// probably not local. Use sockets to establish the FQDN of the server
|
|
|
|
if(0 != sock.Init())
|
|
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,GetLastError());
|
|
|
|
struct hostent * pEnt = GetFQDN(pServerMachine);
|
|
if(pEnt == NULL || pEnt->h_name == NULL)
|
|
{
|
|
// we failed. just return the best we can
|
|
return BuildReturnString(pServerMachine, ppResult);
|
|
}
|
|
|
|
// all is well. Convert the host name to WCHAR.
|
|
|
|
DWORD dwHostLen = lstrlenA(pEnt->h_name) + 1;
|
|
WCHAR * pwsHostFQDN = new WCHAR[dwHostLen];
|
|
if(pwsHostFQDN == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
CVectorDeleteMe<WCHAR> dm2(pwsHostFQDN);
|
|
mbstowcs(pwsHostFQDN, pEnt->h_name, dwHostLen);
|
|
|
|
// now there is the possibility that they specified the ip of the local machine.
|
|
// In that case, set the bLocal in case caller needs to know this
|
|
|
|
if(wbem_wcsicmp(pwsHostFQDN, pwsCurrentCompFQDN) == 0)
|
|
bLocal = TRUE;
|
|
|
|
// now, make the actual string.
|
|
|
|
return BuildReturnString(pwsHostFQDN, ppResult);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CDCOMTrans::CDCOMTrans
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CDCOMTrans::CDCOMTrans()
|
|
{
|
|
m_cRef=0;
|
|
m_pLevel1 = NULL;
|
|
InterlockedIncrement(&g_cObj);
|
|
m_bInitialized = TRUE;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CDCOMTrans::~CDCOMTrans
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Destructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CDCOMTrans::~CDCOMTrans(void)
|
|
{
|
|
if(m_pLevel1)
|
|
m_pLevel1->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;
|
|
|
|
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 * pInterface)
|
|
{
|
|
IRpcOptions *pRpcOpt = NULL;
|
|
ULONG_PTR dwProperty = 0;
|
|
HRESULT hr = pInterface->QueryInterface(IID_IRpcOptions, (void**)&pRpcOpt);
|
|
//DbgPrintfA(0,"QueryInterface(IID_IRpcOptions) hr = %08x\n",hr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pRpcOpt->Query(pInterface, COMBND_SERVER_LOCALITY, &dwProperty);
|
|
pRpcOpt->Release();
|
|
if (SUCCEEDED(hr))
|
|
return (SERVER_LOCALITY_REMOTE == dwProperty)?FALSE:TRUE;
|
|
}
|
|
else if (E_NOINTERFACE == hr) // real pointer, not a proxy
|
|
{
|
|
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, DWORD dwAuthenticationLevel,
|
|
COAUTHIDENTITY *pauthident, DWORD dwCapabilities, DWORD dwAuthnSvc)
|
|
{
|
|
bool bRet = false;
|
|
IWbemLoginClientID * pLoginHelper = NULL;
|
|
SCODE sc = pLogin->QueryInterface(IID_IWbemLoginClientID, (void **)&pLoginHelper);
|
|
if(sc != S_OK)
|
|
return;
|
|
|
|
if(bSet)
|
|
sc = WbemSetProxyBlanket(
|
|
pLoginHelper,
|
|
dwAuthnSvc,
|
|
RPC_C_AUTHZ_NONE,
|
|
PrincipalArg,
|
|
dwAuthenticationLevel,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
pauthident,
|
|
dwCapabilities);
|
|
|
|
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,
|
|
IWbemServices **pInterface)
|
|
{
|
|
HRESULT hr = DoActualConnection(NetworkResource, User, Password, Locale,
|
|
lFlags, Authority, pCtx, pInterface);
|
|
|
|
if(hr == 0x800706be)
|
|
{
|
|
ERRORTRACE((LOG_WBEMPROX,"Initial connection failed with 0x800706be, retrying\n"));
|
|
Sleep(5000);
|
|
hr = DoActualConnection(NetworkResource, User, Password, Locale,
|
|
lFlags, Authority, pCtx, pInterface);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
SCODE CDCOMTrans::DoActualConnection(
|
|
BSTR NetworkResource,
|
|
BSTR User,
|
|
BSTR Password,
|
|
BSTR Locale,
|
|
long lFlags,
|
|
BSTR Authority,
|
|
IWbemContext *pCtx,
|
|
IWbemServices **pInterface)
|
|
{
|
|
|
|
BSTR AuthArg = NULL, UserArg = NULL;
|
|
|
|
// this is the pricipal as extracted from the optional Authority argument
|
|
BSTR PrincipalArg = NULL;
|
|
|
|
// this is the pricipal which is calculated from the server name in the path
|
|
WCHAR * pwCalculatedPrincipal = NULL;
|
|
|
|
bool bAuthenticate = true;
|
|
bool bSet = false;
|
|
CSocketInit sock;
|
|
|
|
SCODE sc = WBEM_E_FAILED;
|
|
|
|
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;
|
|
}
|
|
CSysFreeMe fm1(AuthArg);
|
|
CSysFreeMe fm2(UserArg);
|
|
CSysFreeMe fm3(PrincipalArg);
|
|
|
|
// 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;
|
|
if(PrincipalArg == NULL)
|
|
{
|
|
sc = GetPrincipal(t_ServerMachine, &pwCalculatedPrincipal, t_Local, sock);
|
|
if(FAILED(sc))
|
|
{
|
|
t_Local = bAreWeLocal(t_ServerMachine);
|
|
ERRORTRACE((LOG_WBEMPROX, "GetPrincipal(%S) hr = %08x\n",t_ServerMachine,sc));
|
|
}
|
|
else
|
|
{
|
|
DEBUGTRACE((LOG_WBEMPROX, "Using the principal -%S-\n", pwCalculatedPrincipal));
|
|
}
|
|
}
|
|
else
|
|
t_Local = bAreWeLocal(t_ServerMachine);
|
|
|
|
CVectorDeleteMe<WCHAR> dm2(pwCalculatedPrincipal);
|
|
|
|
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;
|
|
si.pAuthInfo = &ai;
|
|
|
|
ai.dwAuthzSvc = RPC_C_AUTHZ_NONE;
|
|
if(PrincipalArg)
|
|
{
|
|
ai.dwAuthnSvc = RPC_C_AUTHN_GSS_KERBEROS;
|
|
ai.pwszServerPrincName = PrincipalArg;
|
|
}
|
|
else if (pwCalculatedPrincipal)
|
|
{
|
|
ai.dwAuthnSvc = RPC_C_AUTHN_GSS_NEGOTIATE;
|
|
ai.pwszServerPrincName = pwCalculatedPrincipal;
|
|
}
|
|
else
|
|
{
|
|
ai.dwAuthnSvc = RPC_C_AUTHN_WINNT;
|
|
ai.pwszServerPrincName = NULL;
|
|
}
|
|
ai.dwAuthnLevel = AUTH_LEVEL;
|
|
ai.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
|
|
ai.dwCapabilities = 0;
|
|
|
|
COAUTHIDENTITY authident;
|
|
|
|
if(bCredentialsSpecified)
|
|
{
|
|
// Load up the structure.
|
|
memset((void *)&authident,0,sizeof(COAUTHIDENTITY));
|
|
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;
|
|
ai.pAuthIdentityData = &authident;
|
|
}
|
|
else
|
|
ai.pAuthIdentityData = NULL;
|
|
|
|
// Get the IWbemLevel1Login pointer
|
|
|
|
sc = DoCCI(&si ,t_Local, 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, lFlags);
|
|
if(hr == S_OK)
|
|
{
|
|
sc = S_OK;
|
|
bAuthenticate = false;
|
|
}
|
|
}
|
|
|
|
if(sc != S_OK)
|
|
return sc;
|
|
|
|
// Set the values used for CoSetProxyBlanket calls. If the principal was passed in via the Authority
|
|
// argument, then it is used and kerberos is forced. Otherwise, the values will be set based on
|
|
// querying the Proxy it will be either NULL (if NTLM is used) or COLE_DEFAULT_PRINCIPAL.
|
|
|
|
DWORD dwAuthnSvc = RPC_C_AUTHN_WINNT;
|
|
WCHAR * pwCSPBPrincipal = NULL;
|
|
if(PrincipalArg)
|
|
{
|
|
dwAuthnSvc = RPC_C_AUTHN_GSS_KERBEROS;
|
|
pwCSPBPrincipal = PrincipalArg;
|
|
}
|
|
else
|
|
{
|
|
|
|
DWORD dwQueryAuthnLevel, dwQueryImpLevel, dwQueryCapabilities;
|
|
HRESULT hr = CoQueryProxyBlanket(
|
|
m_pLevel1, //Location for the proxy to query
|
|
&dwAuthnSvc, //Location for the current authentication service
|
|
NULL, //Location for the current authorization service
|
|
NULL, //Location for the current principal name
|
|
&dwQueryAuthnLevel, //Location for the current authentication level
|
|
&dwQueryImpLevel, //Location for the current impersonation level
|
|
NULL,
|
|
&dwQueryCapabilities //Location for flags indicating further capabilities of the proxy
|
|
);
|
|
|
|
if(SUCCEEDED(hr) && dwAuthnSvc != RPC_C_AUTHN_WINNT)
|
|
{
|
|
pwCSPBPrincipal = COLE_DEFAULT_PRINCIPAL;
|
|
}
|
|
else
|
|
{
|
|
dwAuthnSvc = RPC_C_AUTHN_WINNT;
|
|
pwCSPBPrincipal = NULL;
|
|
}
|
|
}
|
|
|
|
// The authentication level is set based on having to go to a share level box or not. The
|
|
// capabilities are set based on if we are an impersonating thread or not
|
|
|
|
DWORD dwAuthenticationLevel, dwCapabilities;
|
|
if(bAuthenticate)
|
|
dwAuthenticationLevel = AUTH_LEVEL;
|
|
else
|
|
dwAuthenticationLevel = RPC_C_AUTHN_LEVEL_NONE;
|
|
|
|
if(bImpersonatingThread && !UserArg)
|
|
dwCapabilities = EOAC_STATIC_CLOAKING;
|
|
else
|
|
dwCapabilities = EOAC_NONE;
|
|
|
|
// 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 && !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_pLevel1,
|
|
dwAuthnSvc,
|
|
RPC_C_AUTHZ_NONE,
|
|
pwCSPBPrincipal,
|
|
dwAuthenticationLevel,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
(bCredentialsSpecified) ? &authident : NULL,
|
|
dwCapabilities);
|
|
|
|
bSet = true;
|
|
if(sc != S_OK)
|
|
{
|
|
ERRORTRACE((LOG_WBEMPROX,"Error setting Level1 login interface security pointer, return code is 0x%x\n", sc));
|
|
return sc;
|
|
}
|
|
}
|
|
}
|
|
else // LOCAL case
|
|
{
|
|
// if impersonating set cloaking
|
|
|
|
if(bImpersonatingThread)
|
|
{
|
|
sc = WbemSetProxyBlanket(
|
|
m_pLevel1,
|
|
RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHZ_NONE,
|
|
NULL,
|
|
dwAuthenticationLevel,
|
|
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));
|
|
return sc;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
SetClientIdentity(m_pLevel1, bSet, PrincipalArg,
|
|
dwAuthenticationLevel,
|
|
&authident,
|
|
dwCapabilities,
|
|
dwAuthnSvc);
|
|
if(bCredentialsSpecified && IsLocalConnection(m_pLevel1))
|
|
{
|
|
ERRORTRACE((LOG_WBEMPROX,"Credentials were specified for a local connections\n"));
|
|
return WBEM_E_LOCAL_CREDENTIALS;
|
|
}
|
|
|
|
// The MAX_WAIT flag only applies to CoCreateInstanceEx, get rid of it
|
|
|
|
lFlags = lFlags & ~WBEM_FLAG_CONNECT_USE_MAX_WAIT;
|
|
sc = m_pLevel1->NTLMLogin(NetworkResource, Locale, lFlags, pCtx,(IWbemServices**) pInterface);
|
|
|
|
if(sc == 0x800706d3 && !t_Local) // RPC_S_UNKNOWN_AUTHN_SERVICE
|
|
{
|
|
// If we are going to a stand alone dcom box, try again with the authentication level lowered
|
|
ERRORTRACE((LOG_WBEMPROX,"Attempt to connect to %S returned RPC_S_UNKNOWN_AUTHN_SERVICE\n",NetworkResource));
|
|
HRESULT hr;
|
|
hr = SetInterfaceSecurityAuth(m_pLevel1, &authident, false);
|
|
if (SUCCEEDED(hr))
|
|
hr = m_pLevel1->NTLMLogin(NetworkResource, Locale, lFlags, pCtx, (IWbemServices**)pInterface);
|
|
if(hr == S_OK)
|
|
{
|
|
SetInterfaceSecurityAuth((IUnknown *)*pInterface, &authident, false);
|
|
}
|
|
}
|
|
else
|
|
if(SUCCEEDED(sc) && bAuthenticate == false && !t_Local)
|
|
{
|
|
|
|
// this is used to support share level boxs. The scripting code is written to expect that
|
|
// the IWbemServices pointer is ready to use and so it must be lowered before returning.
|
|
|
|
WbemSetProxyBlanket(*pInterface, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
|
|
RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE);
|
|
}
|
|
|
|
if(FAILED(sc))
|
|
ERRORTRACE((LOG_WBEMPROX,"NTLMLogin resulted in hr = 0x%x\n", sc));
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
|
|
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, 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,
|
|
lFlags & ~WBEM_FLAG_CONNECT_USE_MAX_WAIT );
|
|
CoDisableCallCancellation(NULL);
|
|
SetEvent(arg.m_hTerminate);
|
|
WaitForSingleObject(hThread, INFINITE);
|
|
return hr;
|
|
}
|
|
else
|
|
return DoActualCCI (psi, bLocal, 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, long lFlags )
|
|
{
|
|
HRESULT t_Result ;
|
|
MULTI_QI mqi;
|
|
|
|
mqi.pIID = &IID_IWbemLevel1Login;
|
|
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 )
|
|
{
|
|
m_pLevel1 = (IWbemLevel1Login*) mqi.pItf ;
|
|
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 ;
|
|
}
|
|
|