windows-nt/Source/XPSP1/NT/ds/adsi/winnt/cumiconn.cxx
2020-09-26 16:20:57 +08:00

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