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