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

  1. #include "pch.h"
  2. #include <atlbase.h>
  3. #include "dsrole.h"
  4. #include "strsafe.h"
  5. #pragma hdrstop
  6. /*-----------------------------------------------------------------------------
  7. / Display specifier helpers/cache functions
  8. /----------------------------------------------------------------------------*/
  9. #define DEFAULT_LANGUAGE 0x409
  10. #define DISPLAY_SPECIFIERS L"CN=displaySpecifiers"
  11. #define SPECIFIER_PREFIX L"CN="
  12. #define SPECIFIER_POSTFIX L"-Display"
  13. #define DEFAULT_SPECIFIER L"default"
  14. /*-----------------------------------------------------------------------------
  15. / GetDisplaySpecifier
  16. / -------------------
  17. / Get the specified display specifier (sic), given it an LANGID etc.
  18. /
  19. / In:
  20. / pccgi -> CLASSCACHEGETINFO structure.
  21. / riid = interface
  22. / ppvObject = object requested
  23. /
  24. / Out:
  25. HRESULT
  26. /----------------------------------------------------------------------------*/
  27. HRESULT _GetServerConfigPath(LPWSTR pszConfigPath, int cchConfigPath, LPCLASSCACHEGETINFO pccgi)
  28. {
  29. HRESULT hres;
  30. IADs* padsRootDSE = NULL;
  31. BSTR bstrConfigContainer = NULL;
  32. VARIANT variant = {0};
  33. INT cchString;
  34. LPWSTR pszServer = pccgi->pServer;
  35. LPWSTR pszMachineServer = NULL;
  36. //
  37. // open the RootDSE for the server we are interested in, if we are using the default
  38. // server then lets just use the cached version.
  39. //
  40. hres = GetCacheInfoRootDSE(pccgi, &padsRootDSE);
  41. if ( (hres == HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN)) && !pccgi->pServer )
  42. {
  43. TraceMsg("Failed to get the RootDSE from the server - not found");
  44. DSROLE_PRIMARY_DOMAIN_INFO_BASIC *pInfo;
  45. if ( DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (BYTE**)&pInfo) == WN_SUCCESS )
  46. {
  47. if ( pInfo->DomainNameDns )
  48. {
  49. Trace(TEXT("Machine domain is: %s"), pInfo->DomainNameDns);
  50. CLASSCACHEGETINFO ccgi = *pccgi;
  51. ccgi.pServer = pInfo->DomainNameDns;
  52. hres = GetCacheInfoRootDSE(&ccgi, &padsRootDSE);
  53. if ( SUCCEEDED(hres) )
  54. {
  55. hres = LocalAllocStringW(&pszMachineServer, pInfo->DomainNameDns);
  56. pszServer = pszMachineServer;
  57. }
  58. }
  59. DsRoleFreeMemory(pInfo);
  60. }
  61. }
  62. FailGracefully(hres, "Failed to get the IADs for the RootDSE");
  63. //
  64. // we now have the RootDSE, so lets read the config container path and compose
  65. // a string that the outside world cna use
  66. //
  67. hres = padsRootDSE->Get(CComBSTR(L"configurationNamingContext"), &variant);
  68. FailGracefully(hres, "Failed to get the 'configurationNamingContext' property");
  69. if ( V_VT(&variant) != VT_BSTR )
  70. ExitGracefully(hres, E_FAIL, "configurationNamingContext is not a BSTR");
  71. // copy the string
  72. (void)StringCchCopy(pszConfigPath, cchConfigPath, L"LDAP://");
  73. if ( pszServer )
  74. {
  75. (void)StringCchCat(pszConfigPath, cchConfigPath, pszServer);
  76. (void)StringCchCat(pszConfigPath, cchConfigPath, L"/");
  77. }
  78. hres = StringCchCat(pszConfigPath, cchConfigPath, V_BSTR(&variant));
  79. FailGracefully(hres, "Failed to complete the config path");
  80. Trace(TEXT("Server config path is: %s"), pszConfigPath);
  81. hres = S_OK; // success
  82. exit_gracefully:
  83. DoRelease(padsRootDSE);
  84. SysFreeString(bstrConfigContainer);
  85. LocalFreeStringW(&pszMachineServer);
  86. VariantClear(&variant);
  87. return hres;
  88. }
  89. HRESULT _ComposeSpecifierPath(LPWSTR pSpecifier, LANGID langid, LPWSTR pConfigPath, IADsPathname* pDsPathname, BSTR *pbstrDisplaySpecifier)
  90. {
  91. HRESULT hr = pDsPathname->Set(CComBSTR(pConfigPath), ADS_SETTYPE_FULL);
  92. if (SUCCEEDED(hr))
  93. {
  94. hr = pDsPathname->AddLeafElement(CComBSTR(DISPLAY_SPECIFIERS));
  95. if ( !langid )
  96. langid = GetUserDefaultUILanguage();
  97. TCHAR szLANGID[16];
  98. hr = StringCchPrintf(szLANGID, ARRAYSIZE(szLANGID), TEXT("CN=%x"), langid);
  99. if (SUCCEEDED(hr))
  100. {
  101. hr = pDsPathname->AddLeafElement(CComBSTR(szLANGID));
  102. if (SUCCEEDED(hr))
  103. {
  104. if ( pSpecifier )
  105. {
  106. WCHAR szSpecifierFull[INTERNET_MAX_URL_LENGTH];
  107. (void)StringCchCopy(szSpecifierFull, ARRAYSIZE(szSpecifierFull), SPECIFIER_PREFIX);
  108. (void)StringCchCat(szSpecifierFull, ARRAYSIZE(szSpecifierFull), pSpecifier);
  109. hr = StringCchCat(szSpecifierFull, ARRAYSIZE(szSpecifierFull), SPECIFIER_POSTFIX);
  110. if (SUCCEEDED(hr))
  111. {
  112. Trace(TEXT("szSpecifierFull: %s"), szSpecifierFull);
  113. hr = pDsPathname->AddLeafElement(CComBSTR(szSpecifierFull)); // add to the name we are dealing with
  114. }
  115. }
  116. }
  117. }
  118. }
  119. return FAILED(hr) ? hr:pDsPathname->Retrieve(ADS_FORMAT_WINDOWS, pbstrDisplaySpecifier);
  120. }
  121. HRESULT GetDisplaySpecifier(LPCLASSCACHEGETINFO pccgi, REFIID riid, LPVOID* ppvObject)
  122. {
  123. HRESULT hr;
  124. IADsPathname* pDsPathname = NULL;
  125. BSTR bstrDisplaySpecifier = NULL;
  126. WCHAR szConfigPath[INTERNET_MAX_URL_LENGTH];
  127. TraceEnter(TRACE_CACHE, "GetDisplaySpecifier");
  128. Trace(TEXT("Display specifier %s, LANGID %x"), pccgi->pObjectClass, pccgi->langid);
  129. // When dealing with the local case lets ensure that we enable/disable the flags
  130. // accordingly.
  131. if ( !(pccgi->dwFlags & CLASSCACHE_DSAVAILABLE) && !ShowDirectoryUI() )
  132. {
  133. ExitGracefully(hr, HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT), "ShowDirectoryUI returned FALSE, and the CLASSCAHCE_DSAVAILABLE flag is not set");
  134. }
  135. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IADsPathname, &pDsPathname));
  136. FailGracefully(hr, "Failed to get the IADsPathname interface");
  137. // check to see if we have a valid server config path
  138. if ( !pccgi->pServerConfigPath )
  139. {
  140. hr = _GetServerConfigPath(szConfigPath, ARRAYSIZE(szConfigPath), pccgi);
  141. FailGracefully(hr, "Failed to allocate server config path");
  142. }
  143. else
  144. {
  145. hr = StringCchCopy(szConfigPath, ARRAYSIZE(szConfigPath), pccgi->pServerConfigPath);
  146. FailGracefully(hr, "Failed to copy the config path");
  147. }
  148. hr = _ComposeSpecifierPath(pccgi->pObjectClass, pccgi->langid, szConfigPath, pDsPathname, &bstrDisplaySpecifier);
  149. FailGracefully(hr, "Failed to retrieve the display specifier path");
  150. // attempt to bind to the display specifier object, if we fail to find the object
  151. // then try defaults.
  152. Trace(TEXT("Calling GetObject on: %s"), bstrDisplaySpecifier);
  153. hr = ClassCache_OpenObject(bstrDisplaySpecifier, riid, ppvObject, pccgi);
  154. SysFreeString(bstrDisplaySpecifier);
  155. if ( hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT) )
  156. {
  157. // Display specifier not found. Try the default specifier in the
  158. // caller's locale. The default specifier is the catch-all for classes
  159. // that don't have their own specifier.
  160. hr = _ComposeSpecifierPath(DEFAULT_SPECIFIER, pccgi->langid, szConfigPath, pDsPathname, &bstrDisplaySpecifier);
  161. FailGracefully(hr, "Failed to retrieve the display specifier path");
  162. Trace(TEXT("Calling GetObject on: %s"), bstrDisplaySpecifier);
  163. hr = ClassCache_OpenObject(bstrDisplaySpecifier, riid, ppvObject, pccgi);
  164. SysFreeString(bstrDisplaySpecifier);
  165. if ((hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT)) && (pccgi->langid != DEFAULT_LANGUAGE))
  166. {
  167. // Now try the object's specifier in the default locale.
  168. hr = _ComposeSpecifierPath(pccgi->pObjectClass, DEFAULT_LANGUAGE, szConfigPath, pDsPathname, &bstrDisplaySpecifier);
  169. FailGracefully(hr, "Failed to retrieve the display specifier path");
  170. Trace(TEXT("Calling GetObject on: %s"), bstrDisplaySpecifier);
  171. hr = ClassCache_OpenObject(bstrDisplaySpecifier, riid, ppvObject, pccgi);
  172. SysFreeString(bstrDisplaySpecifier);
  173. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT))
  174. {
  175. // Finally try the default specifier in the default locale.
  176. hr = _ComposeSpecifierPath(DEFAULT_SPECIFIER, DEFAULT_LANGUAGE, szConfigPath, pDsPathname, &bstrDisplaySpecifier);
  177. FailGracefully(hr, "Failed to retrieve the display specifier path");
  178. Trace(TEXT("Calling GetObject on: %s"), bstrDisplaySpecifier);
  179. hr = ClassCache_OpenObject(bstrDisplaySpecifier, riid, ppvObject, pccgi);
  180. SysFreeString(bstrDisplaySpecifier);
  181. }
  182. }
  183. }
  184. FailGracefully(hr, "Failed in ADsOpenObject for display specifier");
  185. // hr = S_OK; // success
  186. exit_gracefully:
  187. DoRelease(pDsPathname);
  188. TraceLeaveResult(hr);
  189. }
  190. /*-----------------------------------------------------------------------------
  191. / GetServerAndCredentails
  192. / -----------------------
  193. / Read the server and credentails information from the IDataObject.
  194. /
  195. / In:
  196. / pccgi -> CLASSCACHEGETINFO structure to be filled
  197. /
  198. / Out:
  199. / HRESULT
  200. /----------------------------------------------------------------------------*/
  201. HRESULT GetServerAndCredentails(CLASSCACHEGETINFO *pccgi)
  202. {
  203. HRESULT hres;
  204. STGMEDIUM medium = { TYMED_NULL };
  205. FORMATETC fmte = {g_cfDsDispSpecOptions, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  206. DSDISPLAYSPECOPTIONS *pdso = NULL;
  207. TraceEnter(TRACE_UI, "GetServerAndCredentails");
  208. // we can only get this information if we have a pDataObject to call.
  209. pccgi->pUserName = NULL;
  210. pccgi->pPassword = NULL;
  211. pccgi->pServer = NULL;
  212. pccgi->pServerConfigPath = NULL;
  213. if ( pccgi->pDataObject )
  214. {
  215. if ( SUCCEEDED(pccgi->pDataObject->GetData(&fmte, &medium)) )
  216. {
  217. pdso = (DSDISPLAYSPECOPTIONS*)GlobalLock(medium.hGlobal);
  218. TraceAssert(pdso);
  219. // mirror the flags into the CCGI structure
  220. if ( pdso->dwFlags & DSDSOF_SIMPLEAUTHENTICATE )
  221. {
  222. TraceMsg("Setting simple authentication");
  223. pccgi->dwFlags |= CLASSCACHE_SIMPLEAUTHENTICATE;
  224. }
  225. if ( pdso->dwFlags & DSDSOF_DSAVAILABLE )
  226. {
  227. TraceMsg("Setting 'DS is available' flags");
  228. pccgi->dwFlags |= CLASSCACHE_DSAVAILABLE;
  229. }
  230. // if we have credentail information that should be copied then lets grab
  231. // that and put it into the structure.
  232. if ( pdso->dwFlags & DSDSOF_HASUSERANDSERVERINFO )
  233. {
  234. if ( pdso->offsetUserName )
  235. {
  236. LPCWSTR pszUserName = (LPCWSTR)ByteOffset(pdso, pdso->offsetUserName);
  237. hres = LocalAllocStringW(&pccgi->pUserName, pszUserName);
  238. FailGracefully(hres, "Failed to copy the user name");
  239. }
  240. if ( pdso->offsetPassword )
  241. {
  242. LPCWSTR pszPassword = (LPCWSTR)ByteOffset(pdso, pdso->offsetPassword);
  243. hres = LocalAllocStringW(&pccgi->pPassword, pszPassword);
  244. FailGracefully(hres, "Failed to copy the password");
  245. }
  246. if ( pdso->offsetServer )
  247. {
  248. LPCWSTR pszServer = (LPCWSTR)ByteOffset(pdso, pdso->offsetServer);
  249. hres = LocalAllocStringW(&pccgi->pServer, pszServer);
  250. FailGracefully(hres, "Failed to copy the server");
  251. }
  252. if ( pdso->offsetServerConfigPath )
  253. {
  254. LPCWSTR pszServerConfigPath = (LPCWSTR)ByteOffset(pdso, pdso->offsetServerConfigPath);
  255. hres = LocalAllocStringW(&pccgi->pServerConfigPath, pszServerConfigPath);
  256. FailGracefully(hres, "Failed to copy the server config path");
  257. }
  258. }
  259. }
  260. }
  261. hres = S_OK; // success
  262. exit_gracefully:
  263. if ( FAILED(hres) )
  264. {
  265. SecureLocalFreeStringW(&pccgi->pUserName);
  266. SecureLocalFreeStringW(&pccgi->pPassword);
  267. SecureLocalFreeStringW(&pccgi->pServer);
  268. LocalFreeStringW(&pccgi->pServerConfigPath);
  269. }
  270. if (pdso)
  271. GlobalUnlock(medium.hGlobal);
  272. ReleaseStgMedium(&medium);
  273. TraceLeaveResult(hres);
  274. }
  275. /*-----------------------------------------------------------------------------
  276. / GetAttributePrefix
  277. / ------------------
  278. / Get the attribtue prefix we must use to pick up information from the
  279. / cache / DS. This is part of the IDataObject we are given, if not then
  280. / we default to shell behaviour.
  281. /
  282. / In:
  283. / ppAttributePrefix -> receives the attribute prefix string
  284. / pDataObject = IDataObject to query against.
  285. /
  286. / Out:
  287. / HRESULT
  288. /----------------------------------------------------------------------------*/
  289. HRESULT GetAttributePrefix(LPWSTR* ppAttributePrefix, IDataObject* pDataObject)
  290. {
  291. HRESULT hr;
  292. STGMEDIUM medium = { TYMED_NULL };
  293. FORMATETC fmte = {g_cfDsDispSpecOptions, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  294. PDSDISPLAYSPECOPTIONS pOptions;
  295. LPWSTR pPrefix = NULL;
  296. TraceEnter(TRACE_UI, "GetAttributePrefix");
  297. if ( (SUCCEEDED(pDataObject->GetData(&fmte, &medium))) && (medium.tymed == TYMED_HGLOBAL) )
  298. {
  299. pOptions = (PDSDISPLAYSPECOPTIONS)medium.hGlobal;
  300. pPrefix = (LPWSTR)ByteOffset(pOptions, pOptions->offsetAttribPrefix);
  301. Trace(TEXT("pOptions->dwSize %d"), pOptions->dwSize);
  302. Trace(TEXT("pOptions->dwFlags %08x"), pOptions->dwFlags);
  303. Trace(TEXT("pOptions->offsetAttribPrefix %d (%s)"), pOptions->offsetAttribPrefix, pPrefix);
  304. hr = LocalAllocStringW(ppAttributePrefix, pPrefix);
  305. FailGracefully(hr, "Failed when copying prefix from StgMedium");
  306. }
  307. else
  308. {
  309. hr = LocalAllocStringW(ppAttributePrefix, DS_PROP_SHELL_PREFIX);
  310. FailGracefully(hr, "Failed when defaulting the attribute prefix string");
  311. }
  312. Trace(TEXT("Resulting prefix: %s"), *ppAttributePrefix);
  313. // hr = S_OK; // success
  314. exit_gracefully:
  315. ReleaseStgMedium(&medium);
  316. TraceLeaveResult(hr);
  317. }
  318. /*-----------------------------------------------------------------------------
  319. / GetCacheInfoRootDSE
  320. / -------------------
  321. / Get the RootDSE given an CLASSCACHEGETINFO structure
  322. /
  323. / In:
  324. / pccgi -> CLASSCACHEGETINFO structure.
  325. / pads -> IADs* interface
  326. /
  327. / Out:
  328. HRESULT
  329. /----------------------------------------------------------------------------*/
  330. HRESULT GetCacheInfoRootDSE(LPCLASSCACHEGETINFO pccgi, IADs **ppads)
  331. {
  332. HRESULT hres;
  333. LPWSTR pszRootDSE = L"/RootDSE";
  334. WCHAR szBuffer[INTERNET_MAX_URL_LENGTH];
  335. TraceEnter(TRACE_CACHE, "GetRootDSE");
  336. (void)StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), L"LDAP://");
  337. if (pccgi->pServer)
  338. (void)StringCchCat(szBuffer, ARRAYSIZE(szBuffer), pccgi->pServer);
  339. else
  340. pszRootDSE++;
  341. hres = StringCchCat(szBuffer, ARRAYSIZE(szBuffer), pszRootDSE);
  342. FailGracefully(hres, "Failed to compute RootDSE path, buffer too small");
  343. Trace(TEXT("RootDSE path is: %s"), szBuffer);
  344. hres = ClassCache_OpenObject(szBuffer, IID_PPV_ARG(IADs, ppads), pccgi);
  345. exit_gracefully:
  346. TraceLeaveResult(hres);
  347. }