WindowsXP-SP1/admin/select/src/rootdse.cxx
2020-09-30 16:53:49 +02:00

513 lines
13 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 1998.
//
// File: rootdse.cxx
//
// Contents: Implementation of class to retrieve interfaces from
// objects accessed via the RootDSE container.
//
// Classes: CRootDSE
//
// History: 02-25-1998 DavidMun Created
//
//---------------------------------------------------------------------------
#include "headers.hxx"
#pragma hdrstop
DEBUG_DECLARE_INSTANCE_COUNTER(CRootDSE)
#define DSE_ATTEMPTED_INIT 0x0001
#define DSE_INIT_FAILED 0x0002
//+--------------------------------------------------------------------------
//
// Member: CRootDSE::CRootDSE
//
// Synopsis: ctor
//
// History: 02-25-1998 DavidMun Created
//
//---------------------------------------------------------------------------
CRootDSE::CRootDSE():
m_pADsRootDSE(NULL),
m_hrInitFailed(0)
{
TRACE_CONSTRUCTOR(CRootDSE);
DEBUG_INCREMENT_INSTANCE_COUNTER(CRootDSE);
m_wzTargetDomain[0] = L'\0';
m_wzTargetForest[0] = L'\0';
}
//+--------------------------------------------------------------------------
//
// Member: CRootDSE::CRootDSE
//
// Synopsis: Copy ctor
//
// History: 06-01-2000 DavidMun Created
//
//---------------------------------------------------------------------------
CRootDSE::CRootDSE(
const CRootDSE &rdse)
{
this->operator=(rdse);
}
//+--------------------------------------------------------------------------
//
// Member: CRootDSE::operator=
//
// Synopsis: Assignment operator
//
// Arguments: [rdse] - right hand side
//
// History: 06-01-2000 DavidMun Created
//
//---------------------------------------------------------------------------
CRootDSE &
CRootDSE::operator=(
const CRootDSE &rdse)
{
TRACE_CONSTRUCTOR(CRootDSE);
m_pADsRootDSE = rdse.m_pADsRootDSE;
if (m_pADsRootDSE)
{
m_pADsRootDSE->AddRef();
}
m_bstrConfigNamingContext = rdse.m_bstrConfigNamingContext;
lstrcpy(m_wzTargetDomain, rdse.m_wzTargetDomain);
lstrcpy(m_wzTargetForest, rdse.m_wzTargetForest);
return *this;
}
//+--------------------------------------------------------------------------
//
// Member: CRootDSE::Init
//
// Synopsis: Complete initialization.
//
// Arguments:
//
// Returns: HRESULT
//
// History: 05-27-1998 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT
CRootDSE::Init(
PCWSTR pwzTargetDomain,
PCWSTR pwzTargetForest)
{
TRACE_METHOD(CRootDSE, Init);
HRESULT hr = S_OK;
do
{
if (pwzTargetDomain && *pwzTargetDomain)
{
lstrcpyn(m_wzTargetDomain,
pwzTargetDomain,
ARRAYLEN(m_wzTargetDomain));
}
else
{
hr = E_INVALIDARG;
Dbg(DEB_ERROR,
"CRootDSE::Init: target machine not joined to domain\n");
break;
}
lstrcpyn(m_wzTargetForest,
pwzTargetForest,
ARRAYLEN(m_wzTargetForest));
} while (0);
return hr;
}
//+--------------------------------------------------------------------------
//
// Member: CRootDSE::~CRootDSE
//
// Synopsis: dtor
//
// History: 02-25-1998 DavidMun Created
//
//---------------------------------------------------------------------------
CRootDSE::~CRootDSE()
{
TRACE_DESTRUCTOR(CRootDSE);
DEBUG_DECREMENT_INSTANCE_COUNTER(CRootDSE);
SAFE_RELEASE(m_pADsRootDSE);
}
//+--------------------------------------------------------------------------
//
// Member: CRootDSE::BindToWellKnownPrincipalsContainer
//
// Synopsis: Bind to the wkp container for interface [riid] and return
// a pointer to that interface in *[ppvInterface].
//
// Arguments: [riid] - interface for which to bind
// [ppvInterface] - filled with interface instance
//
// Returns: HRESULT
//
// Modifies: *[ppvInterface]
//
// History: 07-21-1998 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT
CRootDSE::BindToWellKnownPrincipalsContainer(
HWND hwnd,
REFIID riid,
void **ppvInterface) const
{
TRACE_METHOD(CRootDSE, BindToWellKnownPrincipalsContainer);
HRESULT hr = S_OK;
String strWellKnown;
do
{
if (_IsFlagSet(DSE_INIT_FAILED))
{
hr = m_hrInitFailed;
break;
}
//
// Demand-initialize
//
if (!_IsFlagSet(DSE_ATTEMPTED_INIT))
{
hr = _Init(hwnd);
BREAK_ON_FAIL_HRESULT(hr);
}
//
// Create path to well-known security principals container
//
strWellKnown = String(c_wzLDAPPrefix) +
String(m_wzTargetDomain) +
String(L"/") +
String(c_wzWellKnown) +
String(m_bstrConfigNamingContext.c_str());
//
// Tell BindToObject that the config path may have a server portion
// different than the DN.
//
// In other words, while the DN specifies a path to the root domain for
// the WKSP container, the server portion will specify the joined
// domain.
//
// This is possible because all domains replicate the contents of the
// configuration container, which includes the WKSP container. This is
// a performance optimization because, in a large enterprise, the joined
// domain DCs are more likely to be physically close to the target
// machine than the root domain DCs.
//
hr = g_pBinder->BindToObject(hwnd,
strWellKnown.c_str(),
riid,
ppvInterface,
DSOP_BIND_FLAG_SERVER_NEQ_DN);
BREAK_ON_FAIL_HRESULT(hr);
} while (0);
ASSERT(SUCCEEDED(hr) && *ppvInterface ||
FAILED(hr) && !*ppvInterface);
return hr;
}
//+--------------------------------------------------------------------------
//
// Member: CRootDSE::BindToDisplaySpecifiersContainer
//
// Synopsis: Bind to the container beneath DisplaySpecifiers which
// represents the user's default LANGID.
//
// Arguments: [hwnd] - for bind
// [riid] - desired interface
// [ppvInterface] - filled with desired interface on success
//
// Returns: HRESULT
//
// History: 05-15-2000 DavidMun Created
//
// Notes: If unable to get user's default lang id, uses system's. If
// Unable to get system's, uses US English.
//
//---------------------------------------------------------------------------
HRESULT
CRootDSE::BindToDisplaySpecifiersContainer(
HWND hwnd,
REFIID riid,
void **ppvInterface) const
{
TRACE_METHOD(CRootDSE, BindToWellKnownPrincipalsContainer);
HRESULT hr = S_OK;
do
{
if (_IsFlagSet(DSE_INIT_FAILED))
{
hr = m_hrInitFailed;
break;
}
//
// Demand-initialize
//
if (!_IsFlagSet(DSE_ATTEMPTED_INIT))
{
hr = _Init(hwnd);
BREAK_ON_FAIL_HRESULT(hr);
}
//
// Create path to well-known security principals
//
String strContainerPath;
LANGID langid = GetUserDefaultUILanguage();
if (!langid)
{
DBG_OUT_LASTERROR;
langid = GetSystemDefaultUILanguage();
}
if (!langid)
{
DBG_OUT_LASTERROR;
//
// can't get user or system langid... try US English.
// a fancier strategy would be to enumerate containers beneath
// DisplaySpecifiers and pick one.
//
langid = 0x409;
}
strContainerPath = String(c_wzLDAPPrefix) +
String(m_wzTargetDomain )+
String(L"/") +
String::format(c_wzDisplaySpecifierContainerFmt,
langid) +
String(m_bstrConfigNamingContext.c_str());
hr = g_pBinder->BindToObject(hwnd,
strContainerPath.c_str(),
riid,
ppvInterface,
DSOP_BIND_FLAG_SERVER_NEQ_DN);
if(hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT))
{
//
//if langid is not 0x409, try with 0x409
//
if( langid != 0x409)
{
langid = 0x409;
strContainerPath = String(c_wzLDAPPrefix) +
String(m_wzTargetDomain )+
String(L"/") +
String::format(c_wzDisplaySpecifierContainerFmt,
langid) +
String(m_bstrConfigNamingContext.c_str());
hr = g_pBinder->BindToObject(hwnd,
strContainerPath.c_str(),
riid,
ppvInterface,
DSOP_BIND_FLAG_SERVER_NEQ_DN);
}
}
BREAK_ON_FAIL_HRESULT(hr);
} while (0);
ASSERT(SUCCEEDED(hr) && *ppvInterface ||
FAILED(hr) && !*ppvInterface);
return hr;
}
//+--------------------------------------------------------------------------
//
// Member: CRootDSE::GetSchemaNc
//
// Synopsis: Return the schema naming context (the DN of the schema
// container).
//
// Returns: Schema NC or empty string on error
//
// History: 06-28-2000 DavidMun Created
//
//---------------------------------------------------------------------------
String
CRootDSE::GetSchemaNc(
HWND hwnd) const
{
TRACE_METHOD(CRootDSE, GetSchemaNc);
String strSchemaNc;
do
{
if (_IsFlagSet(DSE_INIT_FAILED))
{
Dbg(DEB_ERROR, "DSE_INIT_FAILED set, returning empty string\n");
break;
}
//
// Demand-initialize
//
if (!_IsFlagSet(DSE_ATTEMPTED_INIT))
{
HRESULT hr = _Init(hwnd);
BREAK_ON_FAIL_HRESULT(hr);
}
strSchemaNc = m_bstrSchemaNamingContext.c_str();
} while (0);
return strSchemaNc;
}
//+--------------------------------------------------------------------------
//
// Member: CRootDSE::_Init
//
// Synopsis: Obtain an interface to the RootDSE object.
//
// Returns: HRESULT
//
// History: 02-25-1998 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT
CRootDSE::_Init(
HWND hwnd) const
{
TRACE_METHOD(CRootDSE, _Init);
HRESULT hr = S_OK;
Variant varConfig;
m_hrInitFailed = S_OK;
_SetFlag(DSE_ATTEMPTED_INIT);
do
{
hr = g_pBinder->GetDomainRootDSE(hwnd,
m_wzTargetDomain,
&m_pADsRootDSE);
BREAK_ON_FAIL_HRESULT(hr);
//
// Get the configuration naming context, used to build up
// paths to configuration container, partitions container, etc.
//
hr = m_pADsRootDSE->Get((PWSTR)c_wzConfigNamingContext, &varConfig);
BREAK_ON_FAIL_HRESULT(hr);
ASSERT(varConfig.GetBstr());
m_bstrConfigNamingContext = varConfig.GetBstr();
Dbg(DEB_TRACE,
"m_bstrConfigNamingContext = '%ws'\n",
m_bstrConfigNamingContext);
//
// Get the schema naming context
//
varConfig.Clear();
hr = m_pADsRootDSE->Get((PWSTR)c_wzSchemaNamingContext, &varConfig);
BREAK_ON_FAIL_HRESULT(hr);
ASSERT(varConfig.GetBstr());
m_bstrSchemaNamingContext = varConfig.GetBstr();
} while (0);
//
// If initialization failed because of a credential error, assume this
// means that the user hit Cancel in a credential prompt dialog, and
// clear the DSE_ATTEMPTED_INIT flag so that we will try again later
// and give the user a second chance to enter creds.
//
// If the initialization failed for any other reason, set the
// DSE_INIT_FAILED flag so we don't try to use the object.
//
if (FAILED(hr))
{
if (IsCredError(hr))
{
_ClearFlag(DSE_ATTEMPTED_INIT);
}
else
{
_SetFlag(DSE_INIT_FAILED);
m_hrInitFailed = hr;
}
}
return hr;
}