Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

465 lines
16 KiB

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