Leaked source code of windows server 2003
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.
 
 
 
 
 
 

445 lines
16 KiB

#include "pch.h"
#include <atlbase.h>
#include "dsrole.h"
#include "strsafe.h"
#pragma hdrstop
/*-----------------------------------------------------------------------------
/ Display specifier helpers/cache functions
/----------------------------------------------------------------------------*/
#define DEFAULT_LANGUAGE 0x409
#define DISPLAY_SPECIFIERS L"CN=displaySpecifiers"
#define SPECIFIER_PREFIX L"CN="
#define SPECIFIER_POSTFIX L"-Display"
#define DEFAULT_SPECIFIER L"default"
/*-----------------------------------------------------------------------------
/ GetDisplaySpecifier
/ -------------------
/ Get the specified display specifier (sic), given it an LANGID etc.
/
/ In:
/ pccgi -> CLASSCACHEGETINFO structure.
/ riid = interface
/ ppvObject = object requested
/
/ Out:
HRESULT
/----------------------------------------------------------------------------*/
HRESULT _GetServerConfigPath(LPWSTR pszConfigPath, int cchConfigPath, LPCLASSCACHEGETINFO pccgi)
{
HRESULT hres;
IADs* padsRootDSE = NULL;
BSTR bstrConfigContainer = NULL;
VARIANT variant = {0};
INT cchString;
LPWSTR pszServer = pccgi->pServer;
LPWSTR pszMachineServer = NULL;
//
// open the RootDSE for the server we are interested in, if we are using the default
// server then lets just use the cached version.
//
hres = GetCacheInfoRootDSE(pccgi, &padsRootDSE);
if ( (hres == HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN)) && !pccgi->pServer )
{
TraceMsg("Failed to get the RootDSE from the server - not found");
DSROLE_PRIMARY_DOMAIN_INFO_BASIC *pInfo;
if ( DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (BYTE**)&pInfo) == WN_SUCCESS )
{
if ( pInfo->DomainNameDns )
{
Trace(TEXT("Machine domain is: %s"), pInfo->DomainNameDns);
CLASSCACHEGETINFO ccgi = *pccgi;
ccgi.pServer = pInfo->DomainNameDns;
hres = GetCacheInfoRootDSE(&ccgi, &padsRootDSE);
if ( SUCCEEDED(hres) )
{
hres = LocalAllocStringW(&pszMachineServer, pInfo->DomainNameDns);
pszServer = pszMachineServer;
}
}
DsRoleFreeMemory(pInfo);
}
}
FailGracefully(hres, "Failed to get the IADs for the RootDSE");
//
// we now have the RootDSE, so lets read the config container path and compose
// a string that the outside world cna use
//
hres = padsRootDSE->Get(CComBSTR(L"configurationNamingContext"), &variant);
FailGracefully(hres, "Failed to get the 'configurationNamingContext' property");
if ( V_VT(&variant) != VT_BSTR )
ExitGracefully(hres, E_FAIL, "configurationNamingContext is not a BSTR");
// copy the string
(void)StringCchCopy(pszConfigPath, cchConfigPath, L"LDAP://");
if ( pszServer )
{
(void)StringCchCat(pszConfigPath, cchConfigPath, pszServer);
(void)StringCchCat(pszConfigPath, cchConfigPath, L"/");
}
hres = StringCchCat(pszConfigPath, cchConfigPath, V_BSTR(&variant));
FailGracefully(hres, "Failed to complete the config path");
Trace(TEXT("Server config path is: %s"), pszConfigPath);
hres = S_OK; // success
exit_gracefully:
DoRelease(padsRootDSE);
SysFreeString(bstrConfigContainer);
LocalFreeStringW(&pszMachineServer);
VariantClear(&variant);
return hres;
}
HRESULT _ComposeSpecifierPath(LPWSTR pSpecifier, LANGID langid, LPWSTR pConfigPath, IADsPathname* pDsPathname, BSTR *pbstrDisplaySpecifier)
{
HRESULT hr = pDsPathname->Set(CComBSTR(pConfigPath), ADS_SETTYPE_FULL);
if (SUCCEEDED(hr))
{
hr = pDsPathname->AddLeafElement(CComBSTR(DISPLAY_SPECIFIERS));
if ( !langid )
langid = GetUserDefaultUILanguage();
TCHAR szLANGID[16];
hr = StringCchPrintf(szLANGID, ARRAYSIZE(szLANGID), TEXT("CN=%x"), langid);
if (SUCCEEDED(hr))
{
hr = pDsPathname->AddLeafElement(CComBSTR(szLANGID));
if (SUCCEEDED(hr))
{
if ( pSpecifier )
{
WCHAR szSpecifierFull[INTERNET_MAX_URL_LENGTH];
(void)StringCchCopy(szSpecifierFull, ARRAYSIZE(szSpecifierFull), SPECIFIER_PREFIX);
(void)StringCchCat(szSpecifierFull, ARRAYSIZE(szSpecifierFull), pSpecifier);
hr = StringCchCat(szSpecifierFull, ARRAYSIZE(szSpecifierFull), SPECIFIER_POSTFIX);
if (SUCCEEDED(hr))
{
Trace(TEXT("szSpecifierFull: %s"), szSpecifierFull);
hr = pDsPathname->AddLeafElement(CComBSTR(szSpecifierFull)); // add to the name we are dealing with
}
}
}
}
}
return FAILED(hr) ? hr:pDsPathname->Retrieve(ADS_FORMAT_WINDOWS, pbstrDisplaySpecifier);
}
HRESULT GetDisplaySpecifier(LPCLASSCACHEGETINFO pccgi, REFIID riid, LPVOID* ppvObject)
{
HRESULT hr;
IADsPathname* pDsPathname = NULL;
BSTR bstrDisplaySpecifier = NULL;
WCHAR szConfigPath[INTERNET_MAX_URL_LENGTH];
TraceEnter(TRACE_CACHE, "GetDisplaySpecifier");
Trace(TEXT("Display specifier %s, LANGID %x"), pccgi->pObjectClass, pccgi->langid);
// When dealing with the local case lets ensure that we enable/disable the flags
// accordingly.
if ( !(pccgi->dwFlags & CLASSCACHE_DSAVAILABLE) && !ShowDirectoryUI() )
{
ExitGracefully(hr, HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT), "ShowDirectoryUI returned FALSE, and the CLASSCAHCE_DSAVAILABLE flag is not set");
}
hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IADsPathname, &pDsPathname));
FailGracefully(hr, "Failed to get the IADsPathname interface");
// check to see if we have a valid server config path
if ( !pccgi->pServerConfigPath )
{
hr = _GetServerConfigPath(szConfigPath, ARRAYSIZE(szConfigPath), pccgi);
FailGracefully(hr, "Failed to allocate server config path");
}
else
{
hr = StringCchCopy(szConfigPath, ARRAYSIZE(szConfigPath), pccgi->pServerConfigPath);
FailGracefully(hr, "Failed to copy the config path");
}
hr = _ComposeSpecifierPath(pccgi->pObjectClass, pccgi->langid, szConfigPath, pDsPathname, &bstrDisplaySpecifier);
FailGracefully(hr, "Failed to retrieve the display specifier path");
// attempt to bind to the display specifier object, if we fail to find the object
// then try defaults.
Trace(TEXT("Calling GetObject on: %s"), bstrDisplaySpecifier);
hr = ClassCache_OpenObject(bstrDisplaySpecifier, riid, ppvObject, pccgi);
SysFreeString(bstrDisplaySpecifier);
if ( hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT) )
{
// Display specifier not found. Try the default specifier in the
// caller's locale. The default specifier is the catch-all for classes
// that don't have their own specifier.
hr = _ComposeSpecifierPath(DEFAULT_SPECIFIER, pccgi->langid, szConfigPath, pDsPathname, &bstrDisplaySpecifier);
FailGracefully(hr, "Failed to retrieve the display specifier path");
Trace(TEXT("Calling GetObject on: %s"), bstrDisplaySpecifier);
hr = ClassCache_OpenObject(bstrDisplaySpecifier, riid, ppvObject, pccgi);
SysFreeString(bstrDisplaySpecifier);
if ((hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT)) && (pccgi->langid != DEFAULT_LANGUAGE))
{
// Now try the object's specifier in the default locale.
hr = _ComposeSpecifierPath(pccgi->pObjectClass, DEFAULT_LANGUAGE, szConfigPath, pDsPathname, &bstrDisplaySpecifier);
FailGracefully(hr, "Failed to retrieve the display specifier path");
Trace(TEXT("Calling GetObject on: %s"), bstrDisplaySpecifier);
hr = ClassCache_OpenObject(bstrDisplaySpecifier, riid, ppvObject, pccgi);
SysFreeString(bstrDisplaySpecifier);
if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT))
{
// Finally try the default specifier in the default locale.
hr = _ComposeSpecifierPath(DEFAULT_SPECIFIER, DEFAULT_LANGUAGE, szConfigPath, pDsPathname, &bstrDisplaySpecifier);
FailGracefully(hr, "Failed to retrieve the display specifier path");
Trace(TEXT("Calling GetObject on: %s"), bstrDisplaySpecifier);
hr = ClassCache_OpenObject(bstrDisplaySpecifier, riid, ppvObject, pccgi);
SysFreeString(bstrDisplaySpecifier);
}
}
}
FailGracefully(hr, "Failed in ADsOpenObject for display specifier");
// hr = S_OK; // success
exit_gracefully:
DoRelease(pDsPathname);
TraceLeaveResult(hr);
}
/*-----------------------------------------------------------------------------
/ GetServerAndCredentails
/ -----------------------
/ Read the server and credentails information from the IDataObject.
/
/ In:
/ pccgi -> CLASSCACHEGETINFO structure to be filled
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT GetServerAndCredentails(CLASSCACHEGETINFO *pccgi)
{
HRESULT hres;
STGMEDIUM medium = { TYMED_NULL };
FORMATETC fmte = {g_cfDsDispSpecOptions, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
DSDISPLAYSPECOPTIONS *pdso = NULL;
TraceEnter(TRACE_UI, "GetServerAndCredentails");
// we can only get this information if we have a pDataObject to call.
pccgi->pUserName = NULL;
pccgi->pPassword = NULL;
pccgi->pServer = NULL;
pccgi->pServerConfigPath = NULL;
if ( pccgi->pDataObject )
{
if ( SUCCEEDED(pccgi->pDataObject->GetData(&fmte, &medium)) )
{
pdso = (DSDISPLAYSPECOPTIONS*)GlobalLock(medium.hGlobal);
TraceAssert(pdso);
// mirror the flags into the CCGI structure
if ( pdso->dwFlags & DSDSOF_SIMPLEAUTHENTICATE )
{
TraceMsg("Setting simple authentication");
pccgi->dwFlags |= CLASSCACHE_SIMPLEAUTHENTICATE;
}
if ( pdso->dwFlags & DSDSOF_DSAVAILABLE )
{
TraceMsg("Setting 'DS is available' flags");
pccgi->dwFlags |= CLASSCACHE_DSAVAILABLE;
}
// if we have credentail information that should be copied then lets grab
// that and put it into the structure.
if ( pdso->dwFlags & DSDSOF_HASUSERANDSERVERINFO )
{
if ( pdso->offsetUserName )
{
LPCWSTR pszUserName = (LPCWSTR)ByteOffset(pdso, pdso->offsetUserName);
hres = LocalAllocStringW(&pccgi->pUserName, pszUserName);
FailGracefully(hres, "Failed to copy the user name");
}
if ( pdso->offsetPassword )
{
LPCWSTR pszPassword = (LPCWSTR)ByteOffset(pdso, pdso->offsetPassword);
hres = LocalAllocStringW(&pccgi->pPassword, pszPassword);
FailGracefully(hres, "Failed to copy the password");
}
if ( pdso->offsetServer )
{
LPCWSTR pszServer = (LPCWSTR)ByteOffset(pdso, pdso->offsetServer);
hres = LocalAllocStringW(&pccgi->pServer, pszServer);
FailGracefully(hres, "Failed to copy the server");
}
if ( pdso->offsetServerConfigPath )
{
LPCWSTR pszServerConfigPath = (LPCWSTR)ByteOffset(pdso, pdso->offsetServerConfigPath);
hres = LocalAllocStringW(&pccgi->pServerConfigPath, pszServerConfigPath);
FailGracefully(hres, "Failed to copy the server config path");
}
}
}
}
hres = S_OK; // success
exit_gracefully:
if ( FAILED(hres) )
{
SecureLocalFreeStringW(&pccgi->pUserName);
SecureLocalFreeStringW(&pccgi->pPassword);
SecureLocalFreeStringW(&pccgi->pServer);
LocalFreeStringW(&pccgi->pServerConfigPath);
}
if (pdso)
GlobalUnlock(medium.hGlobal);
ReleaseStgMedium(&medium);
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ GetAttributePrefix
/ ------------------
/ Get the attribtue prefix we must use to pick up information from the
/ cache / DS. This is part of the IDataObject we are given, if not then
/ we default to shell behaviour.
/
/ In:
/ ppAttributePrefix -> receives the attribute prefix string
/ pDataObject = IDataObject to query against.
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT GetAttributePrefix(LPWSTR* ppAttributePrefix, IDataObject* pDataObject)
{
HRESULT hr;
STGMEDIUM medium = { TYMED_NULL };
FORMATETC fmte = {g_cfDsDispSpecOptions, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
PDSDISPLAYSPECOPTIONS pOptions;
LPWSTR pPrefix = NULL;
TraceEnter(TRACE_UI, "GetAttributePrefix");
if ( (SUCCEEDED(pDataObject->GetData(&fmte, &medium))) && (medium.tymed == TYMED_HGLOBAL) )
{
pOptions = (PDSDISPLAYSPECOPTIONS)medium.hGlobal;
pPrefix = (LPWSTR)ByteOffset(pOptions, pOptions->offsetAttribPrefix);
Trace(TEXT("pOptions->dwSize %d"), pOptions->dwSize);
Trace(TEXT("pOptions->dwFlags %08x"), pOptions->dwFlags);
Trace(TEXT("pOptions->offsetAttribPrefix %d (%s)"), pOptions->offsetAttribPrefix, pPrefix);
hr = LocalAllocStringW(ppAttributePrefix, pPrefix);
FailGracefully(hr, "Failed when copying prefix from StgMedium");
}
else
{
hr = LocalAllocStringW(ppAttributePrefix, DS_PROP_SHELL_PREFIX);
FailGracefully(hr, "Failed when defaulting the attribute prefix string");
}
Trace(TEXT("Resulting prefix: %s"), *ppAttributePrefix);
// hr = S_OK; // success
exit_gracefully:
ReleaseStgMedium(&medium);
TraceLeaveResult(hr);
}
/*-----------------------------------------------------------------------------
/ GetCacheInfoRootDSE
/ -------------------
/ Get the RootDSE given an CLASSCACHEGETINFO structure
/
/ In:
/ pccgi -> CLASSCACHEGETINFO structure.
/ pads -> IADs* interface
/
/ Out:
HRESULT
/----------------------------------------------------------------------------*/
HRESULT GetCacheInfoRootDSE(LPCLASSCACHEGETINFO pccgi, IADs **ppads)
{
HRESULT hres;
LPWSTR pszRootDSE = L"/RootDSE";
WCHAR szBuffer[INTERNET_MAX_URL_LENGTH];
TraceEnter(TRACE_CACHE, "GetRootDSE");
(void)StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), L"LDAP://");
if (pccgi->pServer)
(void)StringCchCat(szBuffer, ARRAYSIZE(szBuffer), pccgi->pServer);
else
pszRootDSE++;
hres = StringCchCat(szBuffer, ARRAYSIZE(szBuffer), pszRootDSE);
FailGracefully(hres, "Failed to compute RootDSE path, buffer too small");
Trace(TEXT("RootDSE path is: %s"), szBuffer);
hres = ClassCache_OpenObject(szBuffer, IID_PPV_ARG(IADs, ppads), pccgi);
exit_gracefully:
TraceLeaveResult(hres);
}