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.

513 lines
12 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // dsobject.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file defines the class DSObject.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 02/20/1998 Original version.
  16. // 06/09/1998 Refresh property cache before enumerating dirty objects.
  17. // 02/11/1999 Keep downlevel parameters in sync.
  18. // 03/16/1999 Return error if downlevel update fails.
  19. //
  20. ///////////////////////////////////////////////////////////////////////////////
  21. #include <ias.h>
  22. #include <iasutil.h>
  23. #include <dsenum.h>
  24. #include <dsobject.h>
  25. #include <vector>
  26. WCHAR USER_PARAMETERS_NAME[] = L"UserParameters";
  27. // Smart pointer for an IADsPropertyEntryPtr.
  28. _COM_SMARTPTR_TYPEDEF(IADsPropertyEntry, __uuidof(IADsPropertyEntry));
  29. //////////
  30. // Prefix added to all RDN's.
  31. //////////
  32. _bstr_t DSObject::thePrefix(L"CN=");
  33. //////////
  34. // The name of the 'name' property.
  35. //////////
  36. _bstr_t DSObject::theNameProperty(L"name");
  37. _bstr_t DSObject::theUserParametersProperty(USER_PARAMETERS_NAME);
  38. DSObject::DSObject(IUnknown* subject)
  39. : oldParms(NULL)
  40. {
  41. _Module.Lock();
  42. // All subjects must support IADs && IDirectoryObject.
  43. _com_util::CheckError(subject->QueryInterface(
  44. __uuidof(IADs),
  45. (PVOID*)&leaf
  46. ));
  47. _com_util::CheckError(Restore());
  48. }
  49. DSObject::~DSObject() throw ()
  50. {
  51. SysFreeString(oldParms);
  52. _Module.Unlock();
  53. }
  54. //////////
  55. // IUnknown implementation is copied from CComObject<>.
  56. //////////
  57. STDMETHODIMP_(ULONG) DSObject::AddRef()
  58. {
  59. return InternalAddRef();
  60. }
  61. STDMETHODIMP_(ULONG) DSObject::Release()
  62. {
  63. ULONG l = InternalRelease();
  64. if (l == 0) { delete this; }
  65. return l;
  66. }
  67. STDMETHODIMP DSObject::QueryInterface(REFIID iid, void ** ppvObject)
  68. {
  69. return _InternalQueryInterface(iid, ppvObject);
  70. }
  71. STDMETHODIMP DSObject::get_Name(BSTR* pVal)
  72. {
  73. if (pVal == NULL) { return E_OUTOFMEMORY; }
  74. VARIANT v;
  75. RETURN_ERROR(leaf->Get(theNameProperty, &v));
  76. // We should have gotten back a non-null BSTR.
  77. if (V_VT(&v) != VT_BSTR || V_BSTR(&v) == NULL) { return E_FAIL; }
  78. *pVal = V_BSTR(&v);
  79. return S_OK;
  80. }
  81. STDMETHODIMP DSObject::get_Class(BSTR* pVal)
  82. {
  83. return leaf->get_Class(pVal);
  84. }
  85. STDMETHODIMP DSObject::get_GUID(BSTR* pVal)
  86. {
  87. return leaf->get_GUID(pVal);
  88. }
  89. STDMETHODIMP DSObject::get_Container(IDataStoreContainer** pVal)
  90. {
  91. return E_NOTIMPL;
  92. }
  93. STDMETHODIMP DSObject::GetValue(BSTR bstrName, VARIANT* pVal)
  94. {
  95. return leaf->Get(bstrName, pVal);
  96. }
  97. STDMETHODIMP DSObject::GetValueEx(BSTR bstrName, VARIANT* pVal)
  98. {
  99. return leaf->GetEx(bstrName, pVal);
  100. }
  101. STDMETHODIMP DSObject::PutValue(BSTR bstrName, VARIANT* pVal)
  102. {
  103. if (pVal == NULL) { return E_INVALIDARG; }
  104. // Flag the object as dirty.
  105. dirty = TRUE;
  106. // Synch up the downlevel parameters.
  107. downlevel.PutValue(bstrName, pVal);
  108. if ( VT_EMPTY == V_VT(pVal) )
  109. {
  110. return leaf->PutEx(ADS_PROPERTY_CLEAR, bstrName, *pVal);
  111. }
  112. else if ( VT_ARRAY == (V_VT(pVal) & VT_ARRAY) )
  113. {
  114. return leaf->PutEx(ADS_PROPERTY_UPDATE, bstrName, *pVal);
  115. }
  116. else
  117. {
  118. return leaf->Put(bstrName, *pVal);
  119. }
  120. }
  121. STDMETHODIMP DSObject::Update()
  122. {
  123. // Update the UserParameters.
  124. PWSTR newParms;
  125. HRESULT hr = downlevel.Update(oldParms, &newParms);
  126. if (FAILED(hr)) { return hr; }
  127. // Convert to a VARIANT.
  128. VARIANT value;
  129. VariantInit(&value);
  130. V_VT(&value) = VT_BSTR;
  131. V_BSTR(&value) = SysAllocString(newParms);
  132. // Set the UserParameters property.
  133. leaf->Put(theUserParametersProperty, value);
  134. // Clean-up.
  135. VariantClear(&value);
  136. LocalFree(newParms);
  137. return leaf->SetInfo();
  138. }
  139. STDMETHODIMP DSObject::Restore()
  140. {
  141. // Free the old UserParameters.
  142. if (oldParms)
  143. {
  144. SysFreeString(oldParms);
  145. oldParms = NULL;
  146. }
  147. dirty = FALSE;
  148. HRESULT hr = leaf->GetInfo();
  149. if (SUCCEEDED(hr))
  150. {
  151. // Read the UserParameters property.
  152. VARIANT value;
  153. if (leaf->Get(theUserParametersProperty, &value) == S_OK)
  154. {
  155. if (V_VT(&value) == VT_BSTR)
  156. {
  157. oldParms = V_BSTR(&value);
  158. }
  159. else
  160. {
  161. // This should never happen.
  162. VariantClear(&value);
  163. }
  164. }
  165. }
  166. else if (hr == E_ADS_OBJECT_UNBOUND)
  167. {
  168. hr = S_OK;
  169. }
  170. return hr;
  171. }
  172. STDMETHODIMP DSObject::Item(BSTR bstrName, IDataStoreProperty** pVal)
  173. {
  174. if (bstrName == NULL || pVal == NULL) { return E_INVALIDARG; }
  175. *pVal = NULL;
  176. // Get the value for this item.
  177. _variant_t value;
  178. RETURN_ERROR(leaf->Get(bstrName, &value));
  179. try
  180. {
  181. // Create a new property object.
  182. (*pVal = new MyProperty(bstrName, value, this))->AddRef();
  183. }
  184. CATCH_AND_RETURN()
  185. return S_OK;
  186. }
  187. STDMETHODIMP DSObject::get_PropertyCount(long* pVal)
  188. {
  189. if (pVal == NULL) { return E_INVALIDARG; }
  190. if (dirty)
  191. {
  192. RETURN_ERROR(Restore());
  193. }
  194. MyProperties properties(leaf);
  195. if (!properties)
  196. {
  197. // Some ADSI providers may not implement IADsPropertyList.
  198. *pVal = 0;
  199. return E_NOTIMPL;
  200. }
  201. return properties->get_PropertyCount(pVal);
  202. }
  203. STDMETHODIMP DSObject::get_NewPropertyEnum(IUnknown** pVal)
  204. {
  205. if (pVal == NULL) { return E_INVALIDARG; }
  206. *pVal = NULL;
  207. if (dirty)
  208. {
  209. RETURN_ERROR(Restore());
  210. }
  211. MyProperties properties(leaf);
  212. // Some ADSI providers may not implement IADsPropertyList.
  213. if (!properties) { return E_NOTIMPL; }
  214. // Reset the list in case this isn't the first time we've enumerated it.
  215. properties->Reset();
  216. try
  217. {
  218. using _com_util::CheckError;
  219. // How many properties are there?
  220. long count;
  221. CheckError(properties->get_PropertyCount(&count));
  222. // Create a temporary array of items.
  223. std::vector<_variant_t> items;
  224. items.reserve(count);
  225. //////////
  226. // Load all the properties into the temporary array.
  227. //////////
  228. while (count--)
  229. {
  230. // Get the next item in the list.
  231. _variant_t item;
  232. CheckError(properties->Next(&item));
  233. // Convert it to a Property Entry.
  234. IADsPropertyEntryPtr entry(item);
  235. // Get the property name.
  236. BSTR bstrName;
  237. CheckError(entry->get_Name(&bstrName));
  238. _bstr_t name(bstrName, false);
  239. // Get the property value.
  240. _variant_t value;
  241. HRESULT hr = leaf->Get(name, &value);
  242. if (FAILED(hr))
  243. {
  244. if (hr == E_ADS_CANT_CONVERT_DATATYPE)
  245. {
  246. // This must be one of those nasty NTDS attributes that has
  247. // no VARIANT representation.
  248. continue;
  249. }
  250. _com_issue_error(hr);
  251. }
  252. // Create the property object and add it to the vector.
  253. items.push_back(new MyProperty(name, value, this));
  254. }
  255. //////////
  256. // Create and initialize an enumerator for the items.
  257. //////////
  258. CComPtr<EnumVARIANT> newEnum(new CComObject<EnumVARIANT>);
  259. _com_util::CheckError(newEnum->Init(items.begin(),
  260. items.end(),
  261. NULL,
  262. AtlFlagCopy));
  263. // Return it to the caller.
  264. (*pVal = newEnum)->AddRef();
  265. }
  266. CATCH_AND_RETURN()
  267. return S_OK;
  268. }
  269. STDMETHODIMP DSObject::Item(BSTR bstrName, IDataStoreObject** ppObject)
  270. {
  271. if (ppObject == NULL) { return E_INVALIDARG; }
  272. try
  273. {
  274. // Get the ADSI object.
  275. CComPtr<IDispatch> disp;
  276. _com_util::CheckError(node->GetObject(NULL,
  277. thePrefix + bstrName,
  278. &disp));
  279. // Convert to a DSObject.
  280. *ppObject = spawn(disp);
  281. }
  282. CATCH_AND_RETURN()
  283. return S_OK;
  284. }
  285. STDMETHODIMP DSObject::Create(BSTR bstrClass,
  286. BSTR bstrName,
  287. IDataStoreObject** ppObject)
  288. {
  289. if (ppObject == NULL) { return E_INVALIDARG; }
  290. try
  291. {
  292. // Create the ADSI object.
  293. CComPtr<IDispatch> disp;
  294. _com_util::CheckError(node->Create(bstrClass,
  295. thePrefix + bstrName,
  296. &disp));
  297. // Convert to a DSObject.
  298. *ppObject = spawn(disp);
  299. }
  300. CATCH_AND_RETURN()
  301. return S_OK;
  302. }
  303. STDMETHODIMP DSObject::MoveHere(IDataStoreObject* pObject,
  304. BSTR bstrNewName)
  305. {
  306. if (pObject == NULL) { return E_INVALIDARG; }
  307. try
  308. {
  309. using _com_util::CheckError;
  310. // Downcast to a DSObject.
  311. DSObject* obj = DSObject::narrow(pObject);
  312. // Get the absolute path of the object being moved.
  313. CComBSTR path;
  314. CheckError(obj->leaf->get_ADsPath(&path));
  315. // Is the object being renamed?
  316. _bstr_t newName(bstrNewName ? thePrefix + bstrNewName : _bstr_t());
  317. // Move it to this container.
  318. CComPtr<IDispatch> disp;
  319. CheckError(node->MoveHere(path, newName, &disp));
  320. //////////
  321. // Set the leaf to the new object.
  322. //////////
  323. CComPtr<IADs> ads;
  324. CheckError(disp->QueryInterface(__uuidof(IADs), (PVOID*)&ads));
  325. obj->leaf.Release();
  326. obj->leaf = ads;
  327. }
  328. CATCH_AND_RETURN()
  329. return S_OK;
  330. }
  331. STDMETHODIMP DSObject::Remove(BSTR bstrClass, BSTR bstrName)
  332. {
  333. if (bstrClass == NULL) { return E_INVALIDARG; }
  334. try
  335. {
  336. _com_util::CheckError(node->Delete(bstrClass, thePrefix + bstrName));
  337. }
  338. CATCH_AND_RETURN()
  339. return S_OK;
  340. }
  341. STDMETHODIMP DSObject::get_ChildCount(long *pVal)
  342. {
  343. return node->get_Count(pVal);
  344. }
  345. STDMETHODIMP DSObject::get_NewChildEnum(IUnknown** pVal)
  346. {
  347. if (pVal == NULL) { return E_INVALIDARG; }
  348. *pVal = NULL;
  349. try
  350. {
  351. // Get the ADSI enumerator.
  352. CComPtr<IUnknown> unk;
  353. _com_util::CheckError(node->get__NewEnum(&unk));
  354. // Convert to an IEnumVARIANT.
  355. CComPtr<IEnumVARIANT> enumVariant;
  356. _com_util::CheckError(unk->QueryInterface(__uuidof(IEnumVARIANT),
  357. (PVOID*)&enumVariant));
  358. // Construct our wrapper around the real enumerator.
  359. (*pVal = new DSEnumerator(this, enumVariant))->AddRef();
  360. }
  361. CATCH_AND_RETURN()
  362. return S_OK;
  363. }
  364. IDataStoreObject* DSObject::spawn(IUnknown* subject)
  365. {
  366. DSObject* child = new DSObject(subject);
  367. child->InternalAddRef();
  368. return child;
  369. }
  370. DSObject* DSObject::narrow(IUnknown* p)
  371. {
  372. DSObject* object;
  373. using _com_util::CheckError;
  374. CheckError(p->QueryInterface(__uuidof(DSObject), (PVOID*)&object));
  375. // We can get away with InternalRelease since the caller must still
  376. // have a reference to this object.
  377. object->InternalRelease();
  378. return object;
  379. }
  380. HRESULT WINAPI DSObject::getContainer(void* pv, REFIID, LPVOID* ppv, DWORD_PTR)
  381. {
  382. DSObject* obj = (DSObject*)pv;
  383. // If we don't have a node pointer, try to get one.
  384. if (obj->node == NULL)
  385. {
  386. obj->leaf->QueryInterface(__uuidof(IADsContainer), (PVOID*)&obj->node);
  387. }
  388. // If node is not NULL, then we are a container.
  389. if (obj->node != NULL)
  390. {
  391. *ppv = (IDataStoreContainer*)obj;
  392. obj->AddRef();
  393. return S_OK;
  394. }
  395. *ppv = NULL;
  396. return E_NOINTERFACE;
  397. }