904 lines
26 KiB
C++
904 lines
26 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2000.
|
|
//
|
|
// File: cumiconn.cxx
|
|
//
|
|
// Contents: Contains the UMI connection object implementation
|
|
//
|
|
// History: 03-02-00 SivaramR Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "winnt.hxx"
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: CreateConnection
|
|
//
|
|
// Synopsis: Creates a connection object. Called by class factory.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// iid Interface requested. Only interface supported is IUmiConnection.
|
|
// ppInterface Returns pointer to interface requested
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: *ppInterface to return a pointer to the interface requested
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CUmiConnection::CreateConnection(
|
|
REFIID iid,
|
|
LPVOID *ppInterface
|
|
)
|
|
{
|
|
CUmiConnection *pConn = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
ADsAssert(ppInterface);
|
|
|
|
pConn = new CUmiConnection();
|
|
if(NULL == pConn)
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
|
|
// initialize connection object
|
|
hr = pConn->FInit();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pConn->QueryInterface(iid, ppInterface);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pConn->Release();
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
if(pConn != NULL)
|
|
delete pConn;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: CUmiConnection
|
|
//
|
|
// Synopsis: Constructor. Initializes all member variables
|
|
//
|
|
// Arguments:
|
|
//
|
|
// None
|
|
//
|
|
// Returns: Nothing.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CUmiConnection::CUmiConnection(void)
|
|
{
|
|
m_pIUmiPropList = NULL;
|
|
m_pCUmiPropList = NULL;
|
|
m_ulErrorStatus = 0;
|
|
m_pIADsOpenDSObj = NULL;
|
|
m_fAlreadyOpened = FALSE;
|
|
m_pszComputerName = NULL;
|
|
m_pszDomainName = NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: ~CUmiConnection
|
|
//
|
|
// Synopsis: Destructor. Frees member variables
|
|
//
|
|
// Arguments:
|
|
//
|
|
// None
|
|
//
|
|
// Returns: Nothing.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CUmiConnection::~CUmiConnection(void)
|
|
{
|
|
if(m_pIUmiPropList != NULL)
|
|
m_pIUmiPropList->Release();
|
|
|
|
if(m_pszComputerName != NULL)
|
|
FreeADsStr(m_pszComputerName);
|
|
|
|
if(m_pszDomainName != NULL)
|
|
FreeADsStr(m_pszDomainName);
|
|
|
|
if(m_pIADsOpenDSObj != NULL)
|
|
m_pIADsOpenDSObj->Release();
|
|
|
|
// m_pCUmiPropList does not have to be deleted since the Release() above
|
|
// has already done it.
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: FInit
|
|
//
|
|
// Synopsis: Initializes connection object.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// None
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CUmiConnection::FInit(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CUmiPropList *pPropList = NULL;
|
|
|
|
pPropList = new CUmiPropList(ConnectionClass, g_dwConnectionTableSize);
|
|
if(NULL == pPropList)
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
|
|
hr = pPropList->FInit(NULL, g_UmiConUnImplProps);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pPropList->QueryInterface(
|
|
IID_IUmiPropList,
|
|
(void **) &m_pIUmiPropList
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// DECLARE_STD_REFCOUNTING initializes the refcount to 1. Call Release()
|
|
// on the created object, so that releasing the interface pointer will
|
|
// free the object.
|
|
pPropList->Release();
|
|
|
|
m_pCUmiPropList = pPropList;
|
|
|
|
hr = m_pCUmiPropList->SetDefaultConnProps();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
if(m_pIUmiPropList != NULL) {
|
|
m_pIUmiPropList->Release();
|
|
m_pIUmiPropList = NULL;
|
|
m_pCUmiPropList = NULL;
|
|
}
|
|
else if(pPropList != NULL)
|
|
delete pPropList;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: QueryInterface
|
|
//
|
|
// Synopsis: Queries connection object for supported interfaces. Only
|
|
// IUmiConnection is supported.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// iid interface requested
|
|
// ppInterface Returns pointer to interface requested. NULL if interface
|
|
// is not supported.
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: *ppInterface to return interface pointer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CUmiConnection::QueryInterface(
|
|
REFIID iid,
|
|
LPVOID *ppInterface
|
|
)
|
|
{
|
|
if(NULL == ppInterface)
|
|
RRETURN(E_INVALIDARG);
|
|
|
|
*ppInterface = NULL;
|
|
|
|
if(IsEqualIID(iid, IID_IUnknown))
|
|
*ppInterface = (IUmiConnection *) this;
|
|
else if(IsEqualIID(iid, IID_IUmiConnection))
|
|
*ppInterface = (IUmiConnection *) this;
|
|
else if(IsEqualIID(iid, IID_IUmiBaseObject))
|
|
*ppInterface = (IUmiBaseObject *) this;
|
|
else if(IsEqualIID(iid, IID_IUmiPropList))
|
|
*ppInterface = (IUmiPropList *) this;
|
|
else
|
|
RRETURN(E_NOINTERFACE);
|
|
|
|
AddRef();
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: GetLastStatus
|
|
//
|
|
// Synopsis: Returns status or error code from the last operation. Currently
|
|
// only numeric status is returned i.e, no error objects are
|
|
// returned. Implements IUmiBaseObject::GetLastStatus().
|
|
//
|
|
// Arguments:
|
|
//
|
|
// uFlags Reserved. Must be 0 for now.
|
|
// puSpecificStatus Returns status code
|
|
// riid IID requested. Ignored currently.
|
|
// pStatusObj Returns interface requested. Always returns NULL currently.
|
|
//
|
|
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
|
|
//
|
|
// Modifies: *puSpecificStatus to return status code.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CUmiConnection::GetLastStatus(
|
|
ULONG uFlags,
|
|
ULONG *puSpecificStatus,
|
|
REFIID riid,
|
|
LPVOID *pStatusObj
|
|
)
|
|
{
|
|
if(pStatusObj != NULL)
|
|
*pStatusObj = NULL;
|
|
|
|
if(puSpecificStatus != NULL)
|
|
*puSpecificStatus = 0;
|
|
|
|
if(uFlags != 0)
|
|
RRETURN(UMI_E_INVALID_FLAGS);
|
|
|
|
if(NULL == puSpecificStatus)
|
|
RRETURN(UMI_E_INVALIDARG);
|
|
|
|
*puSpecificStatus = m_ulErrorStatus;
|
|
|
|
RRETURN(UMI_S_NO_ERROR);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: GetInterfacePropList
|
|
//
|
|
// Synopsis: Returns a pointer to the interface property list implementation
|
|
// for the connection object. Implements
|
|
// IUmiBaseObject::GetInterfacePropList().
|
|
//
|
|
// Arguments:
|
|
//
|
|
// uFlags Reserved. Must be 0 for now.
|
|
// pPropList Returns pointer to IUmiPropertyList interface
|
|
//
|
|
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
|
|
//
|
|
// Modifies: *pPropList to return interface pointer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CUmiConnection::GetInterfacePropList(
|
|
ULONG uFlags,
|
|
IUmiPropList **pPropList
|
|
)
|
|
{
|
|
HRESULT hr = UMI_S_NO_ERROR;
|
|
|
|
SetLastStatus(0);
|
|
|
|
if(uFlags != 0)
|
|
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
|
|
|
|
if(NULL == pPropList)
|
|
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
|
|
|
|
ADsAssert(m_pIUmiPropList != NULL);
|
|
|
|
hr = m_pIUmiPropList->QueryInterface(IID_IUmiPropList, (void **)pPropList);
|
|
|
|
error:
|
|
|
|
if(FAILED(hr))
|
|
SetLastStatus(hr);
|
|
|
|
RRETURN(MapHrToUmiError(hr));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: SetLastStatus
|
|
//
|
|
// Synopsis: Sets the status of the last operation.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ulStatus Status to be set
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void CUmiConnection::SetLastStatus(ULONG ulStatus)
|
|
{
|
|
m_ulErrorStatus = ulStatus;
|
|
|
|
return;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: Open
|
|
//
|
|
// Synopsis: Opens the object specified by a URL and gets the interface
|
|
// requested on this object. Implements IUmiConnection::Open().
|
|
//
|
|
// Arguments:
|
|
//
|
|
// pURL Pointer to an IUmiURL interface
|
|
// uFlags Reserved. Must be 0 for now.
|
|
// TargetIID Interface requested
|
|
// ppInterface Returns pointer to interface requested
|
|
//
|
|
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
|
|
//
|
|
// Modifies: *ppInterface to return interface pointer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CUmiConnection::Open(
|
|
IUmiURL *pURL,
|
|
ULONG uFlags,
|
|
REFIID TargetIID,
|
|
LPVOID *ppInterface
|
|
)
|
|
{
|
|
HRESULT hr = UMI_S_NO_ERROR;
|
|
LPWSTR pszUserName = NULL, pszPassword = NULL;
|
|
DWORD dwBindFlags = 0, dwNumComponents = 0, dwIndex = 0;
|
|
LPWSTR *ppszClasses = NULL;
|
|
WCHAR pszUrl[MAX_URL+1];
|
|
WCHAR *pszLongUrl = pszUrl;
|
|
ULONG ulUrlLen = MAX_URL;
|
|
IUnknown *pIUnknown = NULL;
|
|
CWinNTNamespaceCF tmpNamCF;
|
|
ULONGLONG PathType = 0;
|
|
BOOL fPrevAlreadyOpened = FALSE;
|
|
LPWSTR pszPrevComputer = NULL, pszPrevDomain = NULL;
|
|
|
|
SetLastStatus(0);
|
|
|
|
if(uFlags != 0)
|
|
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
|
|
|
|
if( (NULL == pURL) || (NULL == ppInterface) )
|
|
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
|
|
|
|
*ppInterface = NULL;
|
|
|
|
// Check if the user specified any interface properties for authentication
|
|
hr = GetUserName(&pszUserName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = GetPassword(&pszPassword);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = GetBindFlags(&dwBindFlags);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// check if this is a native path or UMI path
|
|
hr = pURL->GetPathInfo(0, &PathType);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if(PathType & UMIPATH_INFO_NATIVE_STRING) {
|
|
// Get the native path from the URL
|
|
hr = pURL->Get(0, &ulUrlLen, pszUrl);
|
|
|
|
if(WBEM_E_BUFFER_TOO_SMALL == hr) {
|
|
// need to allocate more memory for URL
|
|
pszLongUrl = (WCHAR *) AllocADsMem(ulUrlLen * sizeof(WCHAR));
|
|
if(NULL == pszLongUrl)
|
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
|
|
|
hr = pURL->Get(0, &ulUrlLen, pszLongUrl);
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
else {
|
|
// assume UMI path if not native
|
|
hr = UmiToWinNTPath(
|
|
pURL,
|
|
&pszLongUrl,
|
|
&dwNumComponents,
|
|
&ppszClasses
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = tmpNamCF.CreateInstance(
|
|
NULL,
|
|
IID_IADsOpenDSObject,
|
|
(void **) &m_pIADsOpenDSObj
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// we need a way to distinguish between calls to OpenDSObject from UMI
|
|
// vs ADSI. We use the bind flags for this purpose. If ADS_AUTH_RESERVED
|
|
// is set, then the call is from UMI. ADSI clients are not allowed to use
|
|
// this flag - OLEDB relies on this.
|
|
//
|
|
|
|
hr = m_pIADsOpenDSObj->OpenDSObject(
|
|
pszLongUrl,
|
|
pszUserName,
|
|
pszPassword,
|
|
dwBindFlags | ADS_AUTH_RESERVED,
|
|
(IDispatch **) &pIUnknown
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// save off state in case we need to restore it later
|
|
fPrevAlreadyOpened = m_fAlreadyOpened;
|
|
pszPrevComputer = m_pszComputerName;
|
|
pszPrevDomain = m_pszDomainName;
|
|
|
|
// ensure that the returned object is what the user requested and that the
|
|
// object is on the same domain/server that this connection is for
|
|
hr = CheckObject(
|
|
pIUnknown,
|
|
dwNumComponents,
|
|
ppszClasses
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pIUnknown->QueryInterface(
|
|
TargetIID,
|
|
ppInterface
|
|
);
|
|
if(FAILED(hr)) {
|
|
// restore state of connection
|
|
m_fAlreadyOpened = fPrevAlreadyOpened;
|
|
|
|
if(m_pszComputerName != pszPrevComputer) {
|
|
if(m_pszComputerName != NULL)
|
|
FreeADsStr(m_pszComputerName);
|
|
m_pszComputerName = pszPrevComputer;
|
|
}
|
|
if(m_pszDomainName != pszPrevDomain) {
|
|
if(m_pszDomainName != NULL)
|
|
FreeADsStr(m_pszDomainName);
|
|
m_pszDomainName = pszPrevDomain;
|
|
}
|
|
|
|
goto error;
|
|
}
|
|
|
|
// make interface properties read-only
|
|
m_pCUmiPropList->DisableWrites();
|
|
|
|
error:
|
|
|
|
if(pszUserName != NULL)
|
|
FreeADsMem(pszUserName);
|
|
|
|
if(pszPassword != NULL)
|
|
FreeADsMem(pszPassword);
|
|
|
|
if(pIUnknown != NULL)
|
|
pIUnknown->Release();
|
|
|
|
if( (pszLongUrl != NULL) && (pszLongUrl != pszUrl) )
|
|
FreeADsMem(pszLongUrl);
|
|
|
|
if(ppszClasses != NULL) {
|
|
for(dwIndex = 0; dwIndex < dwNumComponents; dwIndex++) {
|
|
if(ppszClasses[dwIndex] != NULL)
|
|
FreeADsStr(ppszClasses[dwIndex]);
|
|
}
|
|
FreeADsMem(ppszClasses);
|
|
}
|
|
|
|
if(FAILED(hr)) {
|
|
SetLastStatus(hr);
|
|
|
|
if(m_pIADsOpenDSObj != NULL) {
|
|
m_pIADsOpenDSObj->Release();
|
|
m_pIADsOpenDSObj = NULL;
|
|
}
|
|
}
|
|
|
|
RRETURN(MapHrToUmiError(hr));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: GetUserName
|
|
//
|
|
// Synopsis: Gets the username from the interface property cache. If the
|
|
// interface property was not set, the default username is
|
|
// returned.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ppszUserName Returns pointer to the username
|
|
//
|
|
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
|
|
//
|
|
// Modifies: *ppszUserName to return the username.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CUmiConnection::GetUserName(LPWSTR *ppszUserName)
|
|
{
|
|
HRESULT hr = UMI_S_NO_ERROR;
|
|
UMI_PROPERTY_VALUES *pUmiProp = NULL;
|
|
LPWSTR pszUserName = NULL;
|
|
|
|
ADsAssert(ppszUserName != NULL);
|
|
|
|
*ppszUserName = NULL;
|
|
|
|
hr = m_pIUmiPropList->Get(
|
|
TEXT(CONN_INTF_PROP_USERNAME),
|
|
0,
|
|
&pUmiProp
|
|
);
|
|
|
|
if(FAILED(hr)) {
|
|
// shouldn't happen
|
|
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
|
|
}
|
|
|
|
ADsAssert(UMI_TYPE_LPWSTR == pUmiProp->pPropArray->uType);
|
|
ADsAssert(pUmiProp->pPropArray->pUmiValue != NULL);
|
|
|
|
pszUserName = pUmiProp->pPropArray->pUmiValue->pszStrValue[0];
|
|
|
|
if(pszUserName != NULL) {
|
|
*ppszUserName = AllocADsStr(pszUserName);
|
|
if(NULL == *ppszUserName)
|
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
|
}
|
|
else
|
|
*ppszUserName = NULL;
|
|
|
|
error:
|
|
|
|
if(pUmiProp != NULL)
|
|
m_pIUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: GetPassword
|
|
//
|
|
// Synopsis: Gets the password from the interface property cache. If the
|
|
// interface property was not set, the default password is
|
|
// returned.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ppszPassword Returns pointer to the password
|
|
//
|
|
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
|
|
//
|
|
// Modifies: *ppszPassword to return the password.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CUmiConnection::GetPassword(LPWSTR *ppszPassword)
|
|
{
|
|
HRESULT hr = UMI_S_NO_ERROR;
|
|
UMI_PROPERTY_VALUES *pUmiProp = NULL;
|
|
LPWSTR pszPassword = NULL;
|
|
|
|
ADsAssert(ppszPassword != NULL);
|
|
|
|
*ppszPassword = NULL;
|
|
|
|
hr = m_pCUmiPropList->GetHelper(
|
|
TEXT(CONN_INTF_PROP_PASSWORD),
|
|
0,
|
|
&pUmiProp,
|
|
UMI_TYPE_NULL, // no-op
|
|
TRUE // this is an internal call to GetHelper
|
|
);
|
|
|
|
if(FAILED(hr)) {
|
|
// shouldn't happen
|
|
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
|
|
}
|
|
|
|
ADsAssert(UMI_TYPE_LPWSTR == pUmiProp->pPropArray->uType);
|
|
ADsAssert(pUmiProp->pPropArray->pUmiValue != NULL);
|
|
|
|
pszPassword = pUmiProp->pPropArray->pUmiValue->pszStrValue[0];
|
|
|
|
if(pszPassword != NULL) {
|
|
*ppszPassword = AllocADsStr(pszPassword);
|
|
if(NULL == *ppszPassword)
|
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
|
}
|
|
else
|
|
*ppszPassword = NULL;
|
|
|
|
error:
|
|
|
|
if(pUmiProp != NULL)
|
|
m_pCUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: GetBindFlags
|
|
//
|
|
// Synopsis: Gets the bind flags from the interface property cache. If the
|
|
// interface properties were not set, the default bind flags are
|
|
// returned.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// pdwBindFlags Returns the bind flags.
|
|
//
|
|
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
|
|
//
|
|
// Modifies: *pdwBindFlags to return the bind flags.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CUmiConnection::GetBindFlags(DWORD *pdwBindFlags)
|
|
{
|
|
HRESULT hr = UMI_S_NO_ERROR;
|
|
UMI_PROPERTY_VALUES *pUmiProp = NULL;
|
|
DWORD dwUmiBindFlags = 0;
|
|
|
|
ADsAssert(pdwBindFlags != NULL);
|
|
|
|
hr = m_pIUmiPropList->Get(
|
|
TEXT(CONN_INTF_PROP_SECURE_AUTH),
|
|
0,
|
|
&pUmiProp
|
|
);
|
|
|
|
if(SUCCEEDED(hr)) {
|
|
ADsAssert(UMI_TYPE_BOOL == pUmiProp->pPropArray->uType);
|
|
ADsAssert(pUmiProp->pPropArray->pUmiValue != NULL);
|
|
|
|
if(TRUE == pUmiProp->pPropArray->pUmiValue->bValue[0])
|
|
dwUmiBindFlags |= ADS_SECURE_AUTHENTICATION;
|
|
|
|
m_pIUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
|
|
pUmiProp = NULL;
|
|
}
|
|
else
|
|
// shouldn't happen
|
|
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
|
|
|
|
hr = m_pIUmiPropList->Get(
|
|
TEXT(CONN_INTF_PROP_READONLY_SERVER),
|
|
0,
|
|
&pUmiProp
|
|
);
|
|
|
|
if(SUCCEEDED(hr)) {
|
|
ADsAssert(UMI_TYPE_BOOL == pUmiProp->pPropArray->uType);
|
|
ADsAssert(pUmiProp->pPropArray->pUmiValue != NULL);
|
|
|
|
if(TRUE == pUmiProp->pPropArray->pUmiValue->bValue[0])
|
|
dwUmiBindFlags |= ADS_READONLY_SERVER;
|
|
|
|
m_pIUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
|
|
pUmiProp = NULL;
|
|
}
|
|
else
|
|
// shouldn't happen
|
|
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
|
|
|
|
*pdwBindFlags = dwUmiBindFlags;
|
|
|
|
error:
|
|
|
|
if(pUmiProp != NULL)
|
|
m_pIUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: CheckObject
|
|
//
|
|
// Synopsis: Checks that the returned object is the same as what the user
|
|
// requested, if the user passed in a UMI path i.e the classes
|
|
// of the components in the UMI path to the object retrieved
|
|
// should be the same as what the user requested.
|
|
// This function also checks to make sure that subsequent calls to
|
|
// Open(), after the first call, specify the same server/domain
|
|
// as the first call. If the path used in the first call to Open()
|
|
// specifies only a domain name, then all subsequent Open() calls
|
|
// should also specify only a domain name and no computer name.
|
|
// If the first call to Open() specified only a computer name, then
|
|
// all subsequent calls should specify the same computer name. If
|
|
// the first call to Open specified the WinNT namespace path
|
|
// (umi:///winnt or WinNT:), then subsequent Open() calls can
|
|
// connect to any domain/computer. Also, the namespace object can
|
|
// be opened successfully even if we already connected to a
|
|
// computer/domain.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// pUnknown Pointer to the IUnknown of object retrieved
|
|
// dwNumComps Number of components if the path is a UMI path. 0 otherwise.
|
|
// ppszClasses Array containing the class of each component, if the path is
|
|
// a UMI path to an object other than the namespace obejct.
|
|
// NULL otherwise.
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CUmiConnection::CheckObject(
|
|
IUnknown *pUnknown,
|
|
DWORD dwNumComps,
|
|
LPWSTR *ppszClasses
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IUmiADSIPrivate *pUmiPrivate = NULL;
|
|
CCoreADsObject *pCoreObj = NULL;
|
|
LPWSTR pszComputerName = NULL, pszDomainName = NULL;
|
|
DWORD dwIndex = 0, dwCoreIndex = 0;
|
|
|
|
ADsAssert(pUnknown != NULL);
|
|
|
|
hr = pUnknown->QueryInterface(
|
|
IID_IUmiADSIPrivate,
|
|
(LPVOID *) &pUmiPrivate
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pUmiPrivate->GetCoreObject((void **) &pCoreObj);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if(ppszClasses != NULL) {
|
|
// user specified a UMI path and it was not umi:///winnt. Make sure the
|
|
// classes are the same, as mentioned above.
|
|
|
|
// walk the list of classes in reverse order. Reason for reverse order
|
|
// is that the WinNT provider may tack on an additional component to
|
|
// the ADsPath stored in the core object. For example,
|
|
// Open("WinNT://ntdsdc1") would return an ADsPath of
|
|
// "WinNT://ntdev/ntdsdc1".
|
|
|
|
dwCoreIndex = pCoreObj->_dwNumComponents - 1;
|
|
for(dwIndex = dwNumComps - 1; ((long) dwIndex) >= 0; dwIndex--) {
|
|
if( _wcsicmp(
|
|
ppszClasses[dwIndex],
|
|
pCoreObj->_CompClasses[dwCoreIndex]) ) {
|
|
|
|
if( (0 == dwIndex) && (dwNumComps > 1) ) {
|
|
|
|
if(0 == _wcsicmp(pCoreObj->_CompClasses[1],
|
|
SCHEMA_CLASS_NAME)) {
|
|
// if the first component of a schema path doesn't match,
|
|
// make sure it is "Domain". Need this special case because
|
|
// of a bug in the WinNT provider. First component of a
|
|
// schema path is ignored and hence the UMI path always
|
|
// returns "Computer" as the class for this component. This
|
|
// special case allows binding using a path like
|
|
// umi://winnt/domain=ntdev/schema=schema.
|
|
if(0 == _wcsicmp(ppszClasses[dwIndex],
|
|
DOMAIN_CLASS_NAME)) {
|
|
dwCoreIndex--;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
|
|
}
|
|
|
|
dwCoreIndex--;
|
|
}
|
|
} // if(ppszClasses...)
|
|
|
|
// get the domain/computer name specified in the path
|
|
if(pCoreObj->_dwNumComponents > 0) {
|
|
for(dwIndex = pCoreObj->_dwNumComponents - 1; ((long) dwIndex) >= 0;
|
|
dwIndex--) {
|
|
if(0 == (_wcsicmp(
|
|
pCoreObj->_CompClasses[dwIndex],
|
|
SCHEMA_CLASS_NAME)) ) {
|
|
// schema container is a special case. We can connect to the
|
|
// schema on any computer/domain irrespective of where we are
|
|
// connected currently. This is to allow for CIMOM to connect to
|
|
// the schema container for a computer. Currently, the WinNT
|
|
// provider returns WinNT://ntdev/schema as the schema path on the
|
|
// object WinNT://ntdsdc1. Hence we need to allow CIMOM to connect
|
|
// to ntdev even after connecting to ntdsdc1.
|
|
|
|
break; // pszComputerName and pszDomainName are both NULL
|
|
}
|
|
|
|
if(0 == (_wcsicmp(
|
|
pCoreObj->_CompClasses[dwIndex],
|
|
COMPUTER_CLASS_NAME)) ) {
|
|
pszComputerName =
|
|
pCoreObj->_ObjectInfo.DisplayComponentArray[dwIndex];
|
|
break;
|
|
}
|
|
else if(0 == (_wcsicmp(
|
|
pCoreObj->_CompClasses[dwIndex],
|
|
DOMAIN_CLASS_NAME)) ) {
|
|
pszDomainName =
|
|
pCoreObj->_ObjectInfo.DisplayComponentArray[dwIndex];
|
|
break;
|
|
}
|
|
} // for(..)
|
|
} // if(pCoreObj...)
|
|
|
|
if(FALSE == m_fAlreadyOpened) {
|
|
// first call to Open()
|
|
if(pszComputerName != NULL) {
|
|
m_pszComputerName = AllocADsStr(pszComputerName);
|
|
if(NULL == m_pszComputerName) {
|
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
else if(pszDomainName != NULL) {
|
|
m_pszDomainName = AllocADsStr(pszDomainName);
|
|
if(NULL == m_pszDomainName) {
|
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
m_fAlreadyOpened = TRUE;
|
|
}
|
|
else if( (pszComputerName != NULL) || (pszDomainName != NULL) ) {
|
|
// Already opened connection and this is not the namespace object.
|
|
// Make sure that the domain/computer is same as before.
|
|
|
|
if(m_pszComputerName != NULL) {
|
|
if( (NULL == pszComputerName) ||
|
|
(_wcsicmp(m_pszComputerName, pszComputerName)) ) {
|
|
BAIL_ON_FAILURE(hr = UMI_E_MISMATCHED_SERVER);
|
|
}
|
|
}
|
|
else if(m_pszDomainName != NULL) {
|
|
if( (NULL == pszDomainName) ||
|
|
(_wcsicmp(m_pszDomainName, pszDomainName)) ) {
|
|
BAIL_ON_FAILURE(hr = UMI_E_MISMATCHED_DOMAIN);
|
|
}
|
|
}
|
|
else {
|
|
// both m_pszComputerName and m_pszDomainName are NULL. Previous
|
|
// open() must have been for a namespace object.
|
|
if(pszComputerName != NULL) {
|
|
m_pszComputerName = AllocADsStr(pszComputerName);
|
|
if(NULL == m_pszComputerName) {
|
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
else if(pszDomainName != NULL) {
|
|
m_pszDomainName = AllocADsStr(pszDomainName);
|
|
if(NULL == m_pszDomainName) {
|
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
} // else {
|
|
|
|
} // else if(pszComputer...)
|
|
|
|
error:
|
|
|
|
if(pUmiPrivate != NULL)
|
|
pUmiPrivate->Release();
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|