|
|
#include "pch.h"
#include "dsrole.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 *ppszServerConfigPath, LPCLASSCACHEGETINFO pccgi) { HRESULT hres; IADs* padsRootDSE = NULL; BSTR bstrConfigContainer = NULL; VARIANT variant; INT cchString; LPWSTR pszServer = pccgi->pServer; LPWSTR pszMachineServer = NULL; USES_CONVERSION;
*ppszServerConfigPath = NULL; VariantInit(&variant);
//
// 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"), W2T(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(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");
cchString = lstrlenW(L"LDAP://") + lstrlenW(V_BSTR(&variant)); if ( pszServer ) cchString += lstrlenW(pszServer) + 1; // NB: +1 for '/'
//
// allocate the buffer we want to use, and fill it
//
hres = LocalAllocStringLenW(ppszServerConfigPath, cchString); FailGracefully(hres, "Failed to allocate buffer for server path");
StrCpyW(*ppszServerConfigPath, L"LDAP://"); if ( pszServer ) { StrCatW(*ppszServerConfigPath, pszServer); StrCatW(*ppszServerConfigPath, L"/"); }
StrCatW(*ppszServerConfigPath, V_BSTR(&variant));
Trace(TEXT("Server config path is: %s"), W2T(*ppszServerConfigPath)); 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) { TCHAR szLANGID[16]; WCHAR szSpecifierFull[MAX_PATH]; USES_CONVERSION; pDsPathname->Set(pConfigPath, ADS_SETTYPE_FULL); pDsPathname->AddLeafElement(DISPLAY_SPECIFIERS);
if ( !langid ) langid = GetUserDefaultUILanguage();
wsprintf(szLANGID, TEXT("CN=%x"), langid); pDsPathname->AddLeafElement(T2W(szLANGID));
if ( pSpecifier ) { StrCpyW(szSpecifierFull, SPECIFIER_PREFIX); StrCatW(szSpecifierFull, pSpecifier); StrCatW(szSpecifierFull, SPECIFIER_POSTFIX);
Trace(TEXT("szSpecifierFull: %s"), W2T(szSpecifierFull)); pDsPathname->AddLeafElement(szSpecifierFull); // add to the name we are dealing with
}
return pDsPathname->Retrieve(ADS_FORMAT_WINDOWS, pbstrDisplaySpecifier); }
HRESULT GetDisplaySpecifier(LPCLASSCACHEGETINFO pccgi, REFIID riid, LPVOID* ppvObject) { HRESULT hr; IADsPathname* pDsPathname = NULL; BSTR bstrDisplaySpecifier = NULL; LPWSTR pszServerConfigPath = NULL; USES_CONVERSION;
TraceEnter(TRACE_CACHE, "GetDisplaySpecifier"); Trace(TEXT("Display specifier %s, LANGID %x"), W2T(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_IADsPathname, (LPVOID*)&pDsPathname); FailGracefully(hr, "Failed to get the IADsPathname interface");
// check to see if we have a valid server config path
pszServerConfigPath = pccgi->pServerConfigPath;
if ( !pszServerConfigPath ) { hr = _GetServerConfigPath(&pszServerConfigPath, pccgi); FailGracefully(hr, "Failed to allocate server config path"); }
hr = _ComposeSpecifierPath(pccgi->pObjectClass, pccgi->langid, pszServerConfigPath, 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"), W2T(bstrDisplaySpecifier));
hr = ADsOpenObject(bstrDisplaySpecifier, pccgi->pUserName, pccgi->pPassword, pccgi->dwFlags & CLASSCACHE_SIMPLEAUTHENTICATE ? 0:ADS_SECURE_AUTHENTICATION, riid, ppvObject);
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, pszServerConfigPath, pDsPathname, &bstrDisplaySpecifier); FailGracefully(hr, "Failed to retrieve the display specifier path"); Trace(TEXT("Calling GetObject on: %s"), W2T(bstrDisplaySpecifier));
hr = ADsOpenObject(bstrDisplaySpecifier, pccgi->pUserName, pccgi->pPassword, pccgi->dwFlags & CLASSCACHE_SIMPLEAUTHENTICATE ? 0:ADS_SECURE_AUTHENTICATION, riid, ppvObject);
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, pszServerConfigPath, pDsPathname, &bstrDisplaySpecifier); FailGracefully(hr, "Failed to retrieve the display specifier path"); Trace(TEXT("Calling GetObject on: %s"), W2T(bstrDisplaySpecifier));
hr = ADsOpenObject(bstrDisplaySpecifier, pccgi->pUserName, pccgi->pPassword, pccgi->dwFlags & CLASSCACHE_SIMPLEAUTHENTICATE ? 0:ADS_SECURE_AUTHENTICATION, riid, ppvObject);
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, pszServerConfigPath, pDsPathname, &bstrDisplaySpecifier); FailGracefully(hr, "Failed to retrieve the display specifier path"); Trace(TEXT("Calling GetObject on: %s"), W2T(bstrDisplaySpecifier));
hr = ADsOpenObject(bstrDisplaySpecifier, pccgi->pUserName, pccgi->pPassword, pccgi->dwFlags & CLASSCACHE_SIMPLEAUTHENTICATE ? 0:ADS_SECURE_AUTHENTICATION, riid, ppvObject);
SysFreeString(bstrDisplaySpecifier); } } }
FailGracefully(hr, "Failed in ADsOpenObject for display specifier");
// hr = S_OK; // success
exit_gracefully:
DoRelease(pDsPathname);
if ( !pccgi->pServerConfigPath ) LocalFreeStringW(&pszServerConfigPath);
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}; USES_CONVERSION;
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)) ) { DSDISPLAYSPECOPTIONS *pdso = (DSDISPLAYSPECOPTIONS*)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) ) { LocalFreeStringW(&pccgi->pUserName); LocalFreeStringW(&pccgi->pPassword); LocalFreeStringW(&pccgi->pServer); LocalFreeStringW(&pccgi->pServerConfigPath); }
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; USES_CONVERSION;
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, W2T(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"), W2T(*ppAttributePrefix));
// hr = S_OK; // success
exit_gracefully:
ReleaseStgMedium(&medium);
TraceLeaveResult(hr); }
/*-----------------------------------------------------------------------------
/ GetRootDSE / ---------- / Get the RootDSE given an CLASSCACHEGETINFO structure / / In: / pccgi -> CLASSCACHEGETINFO structure. / pads -> IADs* interface / / Out: HRESULT /----------------------------------------------------------------------------*/ HRESULT GetRootDSE(LPCWSTR pszUserName, LPCWSTR pszPassword, LPCWSTR pszServer, BOOL fNotSecure, IADs **ppads) { HRESULT hres; LPWSTR pszRootDSE = L"/RootDSE"; WCHAR szBuffer[MAX_PATH]; USES_CONVERSION;
TraceEnter(TRACE_CACHE, "GetRootDSE");
StrCpyW(szBuffer, L"LDAP://");
if ( pszServer ) StrCatW(szBuffer, pszServer); else pszRootDSE++;
StrCatW(szBuffer, pszRootDSE);
Trace(TEXT("RootDSE path is: %s"), W2T(szBuffer));
hres = ADsOpenObject(szBuffer, (LPWSTR)pszUserName, (LPWSTR)pszPassword, fNotSecure ? 0:ADS_SECURE_AUTHENTICATION, IID_IADs, (void **)ppads); TraceLeaveResult(hres); }
HRESULT GetCacheInfoRootDSE(LPCLASSCACHEGETINFO pccgi, IADs **ppads) { return GetRootDSE(pccgi->pUserName, pccgi->pPassword, pccgi->pServer, (pccgi->dwFlags & CLASSCACHE_SIMPLEAUTHENTICATE), ppads); }
|