mirror of https://github.com/tongzx/nt5src
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
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);
|
|
}
|
|
|