windows-nt/Source/XPSP1/NT/net/ias/sdo/sdoias/dsconnection.cpp
2020-09-26 16:20:57 +08:00

676 lines
19 KiB
C++

///////////////////////////////////////////////////////////////////////////
//
// Copyright(C) 1997-2001 Microsoft Corporation all rights reserved.
//
// Module: dsconnection.cpp
//
// Project: Everest
//
// Description: data store connection implementation
//
// Author: TLP
//
// When Who What
// ---- --- ----
// 4/6/98 TLP Original Version
//
///////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "dsconnection.h"
#include "sdo.h"
#include <dsgetdc.h>
#include <lmaccess.h>
#include <lmapibuf.h>
#include <winsock2.h>
namespace
{
BOOL
WINAPI
IsComputerLocalEx(
PCWSTR computerName,
COMPUTER_NAME_FORMAT nameType
) throw ()
{
WCHAR buffer[256];
DWORD nSize = sizeof(buffer)/sizeof(WCHAR);
BOOL success = GetComputerNameEx(
nameType,
buffer,
&nSize
);
return success && !_wcsicmp(buffer, computerName);
}
BOOL
WINAPI
IsComputerLocal(
PCWSTR computerName
) throw ()
{
return IsComputerLocalEx(
computerName,
ComputerNameNetBIOS
) ||
IsComputerLocalEx(
computerName,
ComputerNameDnsHostname
) ||
IsComputerLocalEx(
computerName,
ComputerNameDnsFullyQualified
) ||
IsComputerLocalEx(
computerName,
ComputerNamePhysicalNetBIOS
) ||
IsComputerLocalEx(
computerName,
ComputerNamePhysicalDnsHostname
) ||
IsComputerLocalEx(
computerName,
ComputerNamePhysicalDnsFullyQualified
);
}
}
///////////////////////////////////////////////////////////////////////////
CDsConnection::CDsConnection()
: m_eState(DISCONNECTED),
m_bIsRemoteServer(false),
m_bIsMixedMode(false),
m_bInitializedDS(false),
m_pDSRoot(NULL),
m_pDSRootObject(NULL),
m_pDSRootContainer(NULL)
{
m_szServerName[0] = '\0';
m_szConfigPath[0] = '\0';
}
///////////////////////////////////////////////////////////////////////////
CDsConnection::~CDsConnection()
{
_ASSERT( DISCONNECTED == m_eState );
}
///////////////////////////////////////////////////////////////////////////
bool CDsConnection::SetServerName(LPCWSTR lpszServerName, bool bLocal)
{
bool success = false;
if ((lpszServerName != 0) && (*lpszServerName != L'\0'))
{
////////
// Caller wants a specific server.
////////
// Strip any leading backslashes.
lpszServerName += wcsspn(lpszServerName, L"\\");
// Make sure the name will fit in our buffer.
if (wcslen(lpszServerName) <= IAS_MAX_SERVER_NAME)
{
// Save the name ...
wcscpy(m_szServerName, lpszServerName);
// ... and determine if it's local or remote.
m_bIsRemoteServer = !IsComputerLocal(m_szServerName);
success = true;
}
}
else if (bLocal)
{
////////
// Caller wants the local machine.
////////
DWORD dwSize = IAS_MAX_SERVER_NAME + 1;
GetComputerNameW(m_szServerName, &dwSize);
m_bIsRemoteServer = false;
success = true;
}
else
{
////////
// Caller wants a domain controller.
////////
PDOMAIN_CONTROLLER_INFOW dci;
DWORD error = DsGetDcNameW(
NULL,
NULL,
NULL,
NULL,
DS_DIRECTORY_SERVICE_REQUIRED,
&dci
);
if (!error && dci->DomainControllerName)
{
success = SetServerName(dci->DomainControllerName, false);
NetApiBufferFree(dci);
}
}
IASTracePrintf("INFO CDsConnection::SetServerName ServerName = %S \n"
"m_szServerName = %S IsRemoteServer %d Success = %d\n",
lpszServerName,
m_szServerName,
m_bIsRemoteServer,
success);
return success;
}
///////////////////////////////////////////////////////////////////////////
HRESULT CDsConnectionIAS::Connect(
/*[in]*/ LPCWSTR lpszServerName,
/*[in]*/ LPCWSTR lpszUserName,
/*[in]*/ LPCWSTR lpszPassword
)
{
HRESULT hr = E_FAIL;
_ASSERT( DISCONNECTED == m_eState );
if ( SetServerName(lpszServerName, true) )
{
m_eState = CONNECTED;
hr = S_OK;
}
else
{
m_szServerName[0] = '\0';
m_szConfigPath[0] = '\0';
}
return hr;
}
///////////////////////////////////////////////////////////////////////////
HRESULT CDsConnectionIAS::InitializeDS()
{
HRESULT hr = S_OK;
WCHAR szConfigPathBuff[IAS_MAX_CONFIG_PATH + 16];
_ASSERT( CONNECTED == m_eState );
if ( ! m_bInitializedDS )
{
// Set the path to the IAS configuration database
//
hr = E_FAIL;
if ( SetConfigPath() )
{
// Create and initialize the IAS data store
//
CComPtr<IDataStore2> pDSRoot;
hr = CoCreateInstance(
__uuidof(OleDBDataStore),
NULL,
CLSCTX_SERVER,
__uuidof(IDataStore2),
(void**)&pDSRoot
);
if ( SUCCEEDED(hr) )
{
// We need to give the object permission to impersonate us. There's
// no reason to abort if this fails; we'll just try with the
// existing blanket.
CoSetProxyBlanket(
pDSRoot,
RPC_C_AUTHN_DEFAULT,
RPC_C_AUTHZ_DEFAULT,
COLE_DEFAULT_PRINCIPAL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_DEFAULT
);
wsprintf(
szConfigPathBuff,
TEXT("%s\\%s"),
m_szConfigPath,
IAS_CONFIG_DB_LOCATION
);
CComBSTR bstrConfigPath(szConfigPathBuff);
if (!bstrConfigPath) { return E_OUTOFMEMORY; }
hr = pDSRoot->Initialize(
bstrConfigPath,
NULL,
NULL
);
if ( SUCCEEDED(hr) )
{
// Save references to the data store root object and root object container
//
CComPtr<IDataStoreObject> pDSRootObject;
hr = pDSRoot->get_Root(&pDSRootObject);
if ( SUCCEEDED(hr) )
{
CComPtr<IDataStoreContainer> pDSRootContainer;
hr = pDSRootObject->QueryInterface(IID_IDataStoreContainer, (void**)&pDSRootContainer);
if ( SUCCEEDED(hr) )
{
pDSRoot->AddRef();
pDSRootObject->AddRef();
pDSRootContainer->AddRef();
m_pDSRoot = pDSRoot;
m_pDSRootObject = pDSRootObject;
m_pDSRootContainer = pDSRootContainer;
m_bInitializedDS = true;
}
}
if ( FAILED(hr) )
pDSRoot->Shutdown();
}
}
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////
void CDsConnectionIAS::Disconnect()
{
if ( m_pDSRootContainer )
{
m_pDSRootContainer->Release();
m_pDSRootContainer = NULL;
}
if ( m_pDSRootObject )
{
m_pDSRootObject->Release();
m_pDSRootObject = NULL;
}
if ( m_pDSRoot )
{
m_pDSRoot->Shutdown();
m_pDSRoot->Release();
m_pDSRoot = NULL;
}
m_szServerName[0] = '\0';
m_szConfigPath[0] = '\0';
m_eState = DISCONNECTED;
}
///////////////////////////////////////////////////////////////////////////
bool CDsConnectionIAS::SetConfigPath()
{
bool bReturn = false;
DWORD dwSize = IAS_MAX_CONFIG_PATH;
DWORD dwResult = ERROR_SUCCESS;
HKEY hKeyRemote = HKEY_LOCAL_MACHINE;
WCHAR *pColon;
CRegKey IASKey;
WCHAR szConfigPathBuff[IAS_MAX_CONFIG_PATH];
if ( m_bIsRemoteServer )
dwResult = RegConnectRegistry(m_szServerName, HKEY_LOCAL_MACHINE, &hKeyRemote);
if ( ERROR_SUCCESS == dwResult )
{
// Open the IAS Service Key
//
dwResult = IASKey.Open(
hKeyRemote,
IAS_POLICY_REG_KEY,
KEY_READ
);
if ( ERROR_SUCCESS == dwResult )
{
// Get the value of the "ProgramDir" registry entry
//
dwSize = IAS_MAX_CONFIG_PATH;
dwResult = IASKey.QueryValue(
szConfigPathBuff,
(LPCTSTR)IAS_SERVICE_DIRECTORY,
&dwSize
);
if ( ERROR_SUCCESS == dwResult )
{
// If remote machine then create a path to the admin share.
// Otherwise assume we're using the configuration on the local machine
//
if ( m_bIsRemoteServer )
{
if ( IAS_MAX_CONFIG_PATH > lstrlen(m_szServerName) + dwSize )
{
// Replace "Drive:" with "Drive$"
//
pColon = wcsrchr(szConfigPathBuff, L':');
if (pColon == NULL)
{
return false;
}
*pColon = L'$';
// Add leading "\\"
//
wsprintf(
m_szConfigPath,
TEXT("\\\\%s\\%s"),
m_szServerName,
szConfigPathBuff
);
bReturn = true;
}
}
else
{
lstrcpy(m_szConfigPath, szConfigPathBuff);
bReturn = true;
}
}
}
}
IASTracePrintf("INFO CDsConnectionIAS::SetConfigPath. m_szConfigPath= %S\n"
,m_szConfigPath);
return bReturn;
}
///////////////////////////////////////////////////////////////////////////
HRESULT CDsConnectionAD::Connect(
/*[in]*/ LPCWSTR lpszServerName,
/*[in]*/ LPCWSTR lpszUserName,
/*[in]*/ LPCWSTR lpszPassword
)
{
HRESULT hr = E_FAIL;
_ASSERT( DISCONNECTED == m_eState );
if ( SetServerName(lpszServerName, false) )
{
m_eState = CONNECTED;
hr = S_OK;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////
HRESULT CDsConnectionAD::InitializeDS()
{
HRESULT hr = S_OK;
_ASSERT( CONNECTED == m_eState );
if ( ! m_bInitializedDS )
{
_variant_t vtConfigNamingContext;
_variant_t vtDefaultNamingContext;
// Get the naming contexts at the specified directory server
//
hr = GetNamingContexts(&vtConfigNamingContext, &vtDefaultNamingContext);
if ( SUCCEEDED(hr) )
{
// Set the domain mode - mixed or native
//
hr = SetMode(&vtDefaultNamingContext);
if ( SUCCEEDED(hr) )
{
// Get the path to the DS configuration information (policies & profiles)
//
hr = SetConfigPath(&vtConfigNamingContext);
if ( SUCCEEDED(hr) )
m_bInitializedDS = true;
}
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////
void CDsConnectionAD::Disconnect()
{
if ( m_pDSRootContainer )
{
m_pDSRootContainer->Release();
m_pDSRootContainer = NULL;
}
if ( m_pDSRootObject )
{
m_pDSRootObject->Release();
m_pDSRootObject = NULL;
}
if ( m_pDSRoot )
{
m_pDSRoot->Shutdown();
m_pDSRoot->Release();
m_pDSRoot = NULL;
}
m_eState = DISCONNECTED;
m_szServerName[0] = '\0';
m_szConfigPath[0] = '\0';
}
///////////////////////////////////////////////////////////////////////////
HRESULT CDsConnectionAD::GetNamingContexts(
/*[out]*/ VARIANT* pvtConfigNamingContext,
/*[out]*/ VARIANT* pvtDefaultNamingContext
)
{
HRESULT hr = E_FAIL;
DWORD dwLength;
_bstr_t bstrNamingContext;
WCHAR szRootDSE[MAX_PATH];
// Check preconditons
//
_ASSERT( NULL != pvtConfigNamingContext && NULL != pvtDefaultNamingContext );
dwLength = lstrlen(IAS_NTDS_LDAP_PROVIDER) +
lstrlen(m_szServerName) +
lstrlen(IAS_NTDS_ROOT_DSE);
_ASSERT( MAX_PATH > dwLength );
if ( MAX_PATH > dwLength )
{
wsprintf(
szRootDSE,
TEXT("%s%s/%s"),
IAS_NTDS_LDAP_PROVIDER,
m_szServerName,
IAS_NTDS_ROOT_DSE
);
CComPtr<IDataStore2> pDS2;
hr = CoCreateInstance(
__uuidof(ADsDataStore),
NULL,
CLSCTX_INPROC_SERVER,
IID_IDataStore2,
(void**)&pDS2
);
if ( SUCCEEDED(hr) )
{
hr = pDS2->Initialize(
szRootDSE,
NULL,
NULL
);
if ( SUCCEEDED(hr) )
{
CComPtr<IDataStoreObject> pRootDSE;
hr = pDS2->get_Root(&pRootDSE);
if ( SUCCEEDED(hr) )
{
_bstr_t bstrNamingContext = IAS_NTDS_CONFIG_NAMING_CONTEXT;
hr = pRootDSE->GetValue(bstrNamingContext, pvtConfigNamingContext);
if ( SUCCEEDED(hr) )
{
bstrNamingContext = IAS_NTDS_DEFAULT_NAMING_CONTEXT;
hr = pRootDSE->GetValue(bstrNamingContext, pvtDefaultNamingContext);
if ( FAILED(hr) )
VariantClear(pvtConfigNamingContext);
}
}
pDS2->Shutdown();
}
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////
HRESULT CDsConnectionAD::SetMode(
/*[in]*/ VARIANT* pvtDefaultNamingContext
)
{
HRESULT hr = E_FAIL;
DWORD dwLength;
WCHAR szPath[MAX_PATH + 1];
// Set the mixed mode flag based on the value of the "ntMixedDomain" property
//
_ASSERT ( NULL != pvtDefaultNamingContext );
dwLength = lstrlen(IAS_NTDS_LDAP_PROVIDER) +
lstrlen(m_szServerName) +
lstrlen(V_BSTR(pvtDefaultNamingContext));
_ASSERT( dwLength < MAX_PATH );
if ( dwLength < MAX_PATH )
{
wsprintf(
szPath,
TEXT("%s%s/%s"),
IAS_NTDS_LDAP_PROVIDER,
m_szServerName,
V_BSTR(pvtDefaultNamingContext)
);
CComPtr<IDataStore2> pDS2;
hr = CoCreateInstance(
__uuidof(ADsDataStore),
NULL,
CLSCTX_INPROC_SERVER,
IID_IDataStore2,
(void**)&pDS2
);
if ( SUCCEEDED(hr) )
{
hr = pDS2->Initialize(
szPath,
NULL,
NULL
);
if ( SUCCEEDED(hr) )
{
CComPtr<IDataStoreObject> pDefaultNamingContext;
hr = pDS2->get_Root(&pDefaultNamingContext);
if ( SUCCEEDED(hr) )
{
_variant_t vtMode;
hr = pDefaultNamingContext->GetValue(IAS_NTDS_MIXED_MODE_FLAG, &vtMode);
if ( SUCCEEDED(hr) )
{
if ( IAS_MIXED_MODE == V_I4(&vtMode) )
m_bMixedMode = true;
else
m_bMixedMode = false;
}
}
pDS2->Shutdown();
}
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////
HRESULT CDsConnectionAD::SetConfigPath(
/*[in]*/ VARIANT* pvtConfigNamingContext
)
{
HRESULT hr = E_FAIL;
DWORD dwLength;
WCHAR szPath[MAX_PATH + 1];
// Set the root and root container for the IAS configuration information
//
_ASSERT ( NULL != pvtConfigNamingContext );
dwLength = lstrlen(IAS_NTDS_LDAP_PROVIDER) +
lstrlen(m_szServerName) +
lstrlen(IAS_NTDS_COMMON_NAMES) +
lstrlen(V_BSTR(pvtConfigNamingContext));
_ASSERT( dwLength < MAX_PATH );
if ( dwLength < MAX_PATH )
{
wsprintf(
szPath,
// TEXT("%s%s/%s%s"),
TEXT("%s%s/%s"),
IAS_NTDS_LDAP_PROVIDER,
m_szServerName,
//IAS_NTDS_COMMON_NAMES,
V_BSTR(pvtConfigNamingContext)
);
CComPtr<IDataStore2> pDSRoot;
hr = CoCreateInstance(
__uuidof(ADsDataStore),
NULL,
CLSCTX_INPROC_SERVER,
IID_IDataStore2,
(void**)&pDSRoot
);
if ( SUCCEEDED(hr) )
{
hr = pDSRoot->Initialize(
szPath,
NULL,
NULL
);
if ( SUCCEEDED(hr) )
{
CComPtr<IDataStoreObject> pDSRootObject;
hr = pDSRoot->get_Root(&pDSRootObject);
if ( SUCCEEDED(hr) )
{
CComPtr<IDataStoreContainer> pDSRootContainer;
hr = pDSRootObject->QueryInterface(IID_IDataStoreContainer, (void**)&pDSRootContainer);
if ( SUCCEEDED(hr) )
{
pDSRoot->AddRef();
pDSRootObject->AddRef();
pDSRootContainer->AddRef();
m_pDSRoot = pDSRoot;
m_pDSRootObject = pDSRootObject;
m_pDSRootContainer = pDSRootContainer;
}
}
if ( FAILED(hr) )
pDSRoot->Shutdown();
}
}
}
return hr;
}