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

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