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.

672 lines
22 KiB

  1. //******************************************************************************
  2. //
  3. // Microsoft Confidential. Copyright (c) Microsoft Corporation 1999. All rights reserved
  4. //
  5. // File: Collect.cpp
  6. //
  7. // Description: Support for Namespace Garbage Collection
  8. //
  9. // History: 12-01-99 leonardm Created
  10. //
  11. //******************************************************************************
  12. #include "uenv.h"
  13. #include "collect.h"
  14. #include "..\rsoputil\smartptr.h"
  15. #include "..\rsoputil\rsoputil.h"
  16. #include "..\rsoputil\wbemtime.h"
  17. //******************************************************************************
  18. //
  19. // Function: GetMinutesElapsed
  20. //
  21. // Description: Returns the number of minutes elapsed between a time represented
  22. // in a BSTR in WBEM format and the present time.
  23. // It expects a string in WBEM datetime format: "yyyymmddhhmmss.000000+000"
  24. // where yyyy=year, mm=month, dd=day, hh=hour, mm=minutes, ss=seconds
  25. //
  26. //
  27. // Parameters: xbstrOldTime - Reference to XBStr representing the time from which
  28. // calculate the time span.
  29. //
  30. // pMinutesElapsed - Pointer to a ULONG that receives the minutes elapsed
  31. // between xbstrOldTime and the present time.
  32. //
  33. // Return: S_OK on success. An HRESULT error code on failure.
  34. //
  35. // History: 12/01/99 leonardm Created.
  36. //
  37. //******************************************************************************
  38. HRESULT GetMinutesElapsed(XBStr& xbstrOldTime, ULONG* pMinutesElapsed)
  39. {
  40. //
  41. // Convert the WbemTime value to a SYSTEMTIME value.
  42. //
  43. SYSTEMTIME systemTime_Old;
  44. HRESULT hr = WbemTimeToSystemTime(xbstrOldTime, systemTime_Old);
  45. if(FAILED(hr))
  46. {
  47. DebugMsg((DM_WARNING, TEXT("GetMinutesElapsed: WbemTimeToSystemTime failed. hr=0x%08X."), hr));
  48. return hr;
  49. }
  50. //
  51. // Convert the SYSTEMTIME value to a FILETIME value.
  52. //
  53. BOOL bRes;
  54. FILETIME fileTime_Old;
  55. bRes = SystemTimeToFileTime(&systemTime_Old, &fileTime_Old);
  56. if(!bRes)
  57. {
  58. DWORD dwLastError = GetLastError();
  59. DebugMsg((DM_WARNING, TEXT("GetMinutesElapsed: SystemTimeToFileTime failed. LastError=0x%08X."), dwLastError));
  60. return E_FAIL;
  61. }
  62. unsigned __int64 old = fileTime_Old.dwHighDateTime;
  63. old <<= 32;
  64. old |= fileTime_Old.dwLowDateTime;
  65. //
  66. // Get the current time in SYSTEMTIME format
  67. //
  68. SYSTEMTIME systemTime_Current;
  69. GetSystemTime(&systemTime_Current);
  70. //
  71. // Convert the current time from a SYSTEMTIME to a FILETIME value
  72. //
  73. FILETIME fileTime_Current;
  74. bRes = SystemTimeToFileTime(&systemTime_Current, &fileTime_Current);
  75. if(!bRes)
  76. {
  77. DWORD dwLastError = GetLastError();
  78. DebugMsg((DM_WARNING, TEXT("GetMinutesElapsed: SystemTimeToFileTime failed. LastError=0x%08X."), dwLastError));
  79. return E_FAIL;
  80. }
  81. //
  82. // The time passed in as a parameter must precede the current time
  83. //
  84. unsigned __int64 current = fileTime_Current.dwHighDateTime;
  85. current <<= 32;
  86. current |= fileTime_Current.dwLowDateTime;
  87. if(old > current)
  88. {
  89. return WBEM_E_INVALID_PARAMETER;
  90. }
  91. //
  92. // We have converted SYSTEMTIMEs to FILETIMEs.
  93. // "The FILETIME structure is a 64-bit value representing the number
  94. // of 100-nanosecond intervals since January 1, 1601."
  95. // Therefore we need to divide by ten million to obtain seconds
  96. // and by sixty to obtain minutes.
  97. //
  98. *pMinutesElapsed = (ULONG) (( current - old ) / (60 * 10 * 1000 * 1000));
  99. return S_OK;
  100. }
  101. //******************************************************************************
  102. //
  103. // Function: IsNamespaceStale
  104. //
  105. // Description: Check if namespace is stale Sub-namespaces 'User' and 'Computer' are expected to have
  106. // RSOP_Session. The data member 'creationTime' of that instance is examined when
  107. // evaluating whether the sub-namespace should be deleted. For some failures treat the
  108. // namespace as garbage-collectable because we don't clean up properly when an error is
  109. // encountered during the creation of the namespace, and setting up security etc.
  110. //
  111. //
  112. // Parameters: pChildNamespace - Pointer to IWbemServices associated with child namespace
  113. // TTLMinutes - ULONG variable that represents the maximum number of
  114. // minutes that may have elapsed before a sub-namespace is
  115. // deleted.
  116. //
  117. // Return: True if namespace is stale, false otherwise
  118. //
  119. //******************************************************************************
  120. BOOL IsNamespaceStale( IWbemServices *pChildNamespace, ULONG TTLMinutes )
  121. {
  122. //
  123. // compute TTL
  124. // To do so compare the "creationTime" data member of class RSOP_Session with
  125. // the current time. If the time span exceeds the threshold (as found in the
  126. // registry), the namespace is to be deleted.
  127. //
  128. XBStr xbstrInstancePath = L"RSOP_Session.id=\"Session1\"";
  129. if(!xbstrInstancePath)
  130. {
  131. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory.")));
  132. return FALSE;
  133. }
  134. XInterface<IWbemClassObject>xpInstance = NULL;
  135. HRESULT hr = pChildNamespace->GetObject(xbstrInstancePath, 0, NULL, &xpInstance, NULL);
  136. if(FAILED(hr))
  137. {
  138. DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: GetObject failed. hr=0x%08X"), hr));
  139. return TRUE;
  140. }
  141. XBStr xbstrPropertyName = L"creationTime";
  142. if(!xbstrPropertyName)
  143. {
  144. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory.")));
  145. return TRUE;
  146. }
  147. VARIANT var;
  148. VariantInit(&var);
  149. XVariant xVar(&var);
  150. hr = xpInstance->Get(xbstrPropertyName, 0, &var, NULL, NULL);
  151. if(FAILED(hr))
  152. {
  153. DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: Get failed. hr=0x%08X."), hr));
  154. return TRUE;
  155. }
  156. if ( var.vt == VT_NULL )
  157. return TRUE;
  158. XBStr xbstrPropertyValue = var.bstrVal;
  159. if(!xbstrPropertyValue)
  160. {
  161. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory.")));
  162. return FALSE;
  163. }
  164. ULONG minutesElapsed = 10;
  165. hr = GetMinutesElapsed(xbstrPropertyValue, &minutesElapsed);
  166. if(FAILED(hr))
  167. {
  168. DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: GetMinutesElapsed failed. hr=0x%08X."), hr));
  169. return TRUE;
  170. }
  171. if(minutesElapsed > TTLMinutes)
  172. return TRUE;
  173. else
  174. return FALSE;
  175. }
  176. //******************************************************************************
  177. //
  178. // Function: GarbageCollectNamespace
  179. //
  180. // Description: Garabage-collects the namespace passed in as a parameter.
  181. // If no sub-namespaces are found or if all sub-namespaces
  182. // are deleted, it deletes the parent namespace as well.
  183. // It deletes sub-namespaces whose TTL has expired.
  184. // It computes the TTL from the 'creationTime' data member of the only
  185. // instance of class RSOP_Session as defined in rsop.mof.
  186. //
  187. // Any of the sub-namespaces that is older than TTLMinutes will be deleted.
  188. // If no sub-namespaces are left, then the parent namespace is deleted as well.
  189. //
  190. // Garbage-collectable are those namespaces which satisfy a set of
  191. // criteria which at the present time is based solely on the naming convention
  192. // as follows: namespaces under root\rsop whose name starts with "NS"
  193. //
  194. // Sub-namespaces 'User' and 'Computer' are expected to have an instance of class
  195. // RSOP_Session. The data member 'creationTime' of that instance is examined when
  196. // evaluating whether the sub-namespace should be deleted.
  197. //
  198. //
  199. // Parameters: bstrNamespace - Name of the namesapce to garbage collect.
  200. // pWbemServices - Pointer to IWbemServices associated with
  201. // the parent of bstrNamespace (root\rsop)
  202. // TTLMinutes - ULONG variable that represents the maximum number of
  203. // minutes that may have elapsed before a sub-namespace is
  204. // deleted.
  205. //
  206. // Return: S_OK on success. An HRESULT error code on failure.
  207. //
  208. // History: 12/01/99 leonardm Created.
  209. //
  210. //******************************************************************************
  211. HRESULT GarbageCollectNamespace(BSTR bstrNamespace, IWbemServices* pWbemServices, ULONG TTLMinutes)
  212. {
  213. if(!bstrNamespace || !pWbemServices)
  214. {
  215. return E_FAIL;
  216. }
  217. //
  218. // Connect to that namespace and enumerate instances of __namespace.
  219. // It's assumed that there will be at most 2 namespaces:
  220. // "User" and "Computer".
  221. //
  222. XInterface<IWbemServices> xpParentNamespace;
  223. HRESULT hr = pWbemServices->OpenNamespace( bstrNamespace,
  224. 0,
  225. NULL,
  226. &xpParentNamespace,
  227. NULL);
  228. if(FAILED(hr))
  229. {
  230. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: OpenNamespace failed. hr=0x%08X"), hr));
  231. return hr;
  232. }
  233. //
  234. // Enumerate all instances of __namespace.
  235. //
  236. XInterface<IEnumWbemClassObject> xpEnum;
  237. XBStr xbstrClass = L"__namespace";
  238. if(!xbstrClass)
  239. {
  240. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory")));
  241. return E_OUTOFMEMORY;
  242. }
  243. hr = xpParentNamespace->CreateInstanceEnum( xbstrClass,
  244. WBEM_FLAG_SHALLOW | WBEM_FLAG_FORWARD_ONLY,
  245. NULL,
  246. &xpEnum);
  247. if(FAILED(hr))
  248. {
  249. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: CreateInstanceEnum failed. hr=0x%08X" ), hr ));
  250. return hr;
  251. }
  252. //
  253. // We re interested in data member "Name" of class __namespace.
  254. //
  255. XBStr xbstrProperty = L"Name";
  256. if(!xbstrProperty)
  257. {
  258. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory")));
  259. return E_FAIL;
  260. }
  261. //
  262. // This pointer will be used to iterate through every instance
  263. // in the enumeration.
  264. //
  265. XInterface<IWbemClassObject>xpInstance = NULL;
  266. ULONG ulReturned = 0;
  267. long namespacesFound = 0;
  268. long namespacesDeleted = 0;
  269. while(1)
  270. {
  271. //
  272. // Retrieve the next instance in the enumeration.
  273. //
  274. hr = xpEnum->Next( WBEM_NO_WAIT, 1, &xpInstance, &ulReturned);
  275. if (hr != WBEM_S_NO_ERROR || !ulReturned)
  276. {
  277. //
  278. // Either the end of the enumeration has been reached or an error
  279. // ocurred. We will find out outside the loop.
  280. //
  281. break;
  282. }
  283. namespacesFound++;
  284. //
  285. // Get the namespace name.
  286. //
  287. VARIANT var;
  288. VariantInit(&var);
  289. hr = xpInstance->Get(xbstrProperty, 0L, &var, NULL, NULL);
  290. //
  291. // Release the pointer to the current element of the enumeration..
  292. //
  293. xpInstance = NULL;
  294. if(FAILED(hr))
  295. {
  296. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Get failed. hr=0x%x" ), hr ));
  297. return E_FAIL;
  298. }
  299. //
  300. // Use the name of the namespace to connect to it.
  301. //
  302. XBStr xbstrChildNamespace = var.bstrVal;
  303. VariantClear( &var );
  304. if(!xbstrChildNamespace)
  305. {
  306. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory" )));
  307. return E_FAIL;
  308. }
  309. XInterface<IWbemServices> xpChildNamespace = NULL;
  310. hr = xpParentNamespace->OpenNamespace( xbstrChildNamespace,
  311. 0,
  312. NULL,
  313. &xpChildNamespace,
  314. NULL);
  315. if(FAILED(hr))
  316. {
  317. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: OpenNamespace returned 0x%x"), hr));
  318. return hr;
  319. }
  320. BOOL bStale = IsNamespaceStale( xpChildNamespace, TTLMinutes );
  321. xpChildNamespace = NULL;
  322. if ( bStale )
  323. {
  324. //
  325. // DeleteInstance
  326. //
  327. CWString sNamespaceToDelete = L"__namespace.name=\"";
  328. sNamespaceToDelete += (WCHAR*)xbstrChildNamespace;
  329. sNamespaceToDelete += L"\"";
  330. if(!sNamespaceToDelete.ValidString())
  331. {
  332. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory.")));
  333. return E_OUTOFMEMORY;
  334. }
  335. XBStr xbstrInstancePath = sNamespaceToDelete;
  336. if(!xbstrInstancePath)
  337. {
  338. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory.")));
  339. return E_OUTOFMEMORY;
  340. }
  341. hr = xpParentNamespace->DeleteInstance(xbstrInstancePath, 0, NULL, NULL);
  342. if(FAILED(hr))
  343. {
  344. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: DeleteInstance returned 0x%x"), hr));
  345. return hr;
  346. }
  347. DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: Deleted namespace:%ws\\%ws\n"),
  348. (WCHAR*)bstrNamespace, (WCHAR*)xbstrChildNamespace ));
  349. namespacesDeleted++;
  350. }
  351. }
  352. //
  353. // Check to find out whther the loop was exited because the end of the
  354. // enumeration was reached or because an error ocurred.
  355. //
  356. if(hr != (HRESULT) WBEM_S_FALSE || ulReturned)
  357. {
  358. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Get failed. hr=0x%x" ), hr ));
  359. return E_FAIL;
  360. }
  361. //
  362. // If no namespaces are found or if namespaces in enumeration
  363. // equal deleted namespaces delete the parent namespace as well.
  364. //
  365. if((!namespacesFound) || (namespacesDeleted == namespacesFound))
  366. {
  367. xpParentNamespace = NULL;
  368. CWString sNamespaceToDelete = L"__namespace.name=\"";
  369. sNamespaceToDelete += (WCHAR*)bstrNamespace;
  370. sNamespaceToDelete += L"\"";
  371. if(!sNamespaceToDelete.ValidString())
  372. {
  373. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory.")));
  374. return E_OUTOFMEMORY;
  375. }
  376. XBStr xbstrInstancePath = sNamespaceToDelete;
  377. if(!xbstrInstancePath)
  378. {
  379. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory.")));
  380. return E_OUTOFMEMORY;
  381. }
  382. hr = pWbemServices->DeleteInstance(xbstrInstancePath, 0, NULL, NULL);
  383. if(FAILED(hr))
  384. {
  385. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: DeleteInstance returned 0x%x"), hr));
  386. return hr;
  387. }
  388. DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: Deleted namespace %ws\n"),
  389. (WCHAR*)bstrNamespace ));
  390. }
  391. return S_OK;
  392. }
  393. //******************************************************************************
  394. //
  395. // Function: IsGarbageCollectable
  396. //
  397. // Description: Determines whether a namespace is garbage-collectable.
  398. // Garbage-collectable are those namespaces which satisfy a set of
  399. // criteria which at the present time is based solely on the naming convention
  400. // as follows: namespaces under root\rsop whose name starts with "NS"
  401. //
  402. //
  403. // Parameters: bstrNamespace - BSTR that represents the namespace name.
  404. //
  405. // Return: 'true' or 'false'.
  406. //
  407. // History: 12/01/99 leonardm Created.
  408. //
  409. //******************************************************************************
  410. bool IsGarbageCollectable(BSTR bstrNamespace)
  411. {
  412. if(bstrNamespace && wcslen(bstrNamespace) > 1 && _wcsnicmp(bstrNamespace, L"NS", 2) == 0)
  413. {
  414. return true;
  415. }
  416. return false;
  417. }
  418. //******************************************************************************
  419. //
  420. // Function: GarbageCollectNamespaces
  421. //
  422. // Description: Iterates through namespaces under root\rsop and for each of those
  423. // that are determined to be garbage-collectable, it connects to
  424. // sub-namespaces 'User' and 'Computer'.
  425. //
  426. // Any of the sub-namespaces that is older than TTLMinutes will be deleted.
  427. // If no sub-namespaces are left, then the parent namespace is deleted as well.
  428. //
  429. // Garbage-collectable are those namespaces which satisfy a set of
  430. // criteria which at the present time is based solely on the naming convention
  431. // as follows: namespaces under root\rsop whose name starts with "NS"
  432. //
  433. // Sub-namespaces 'User' and 'Computer' are expected to have an instance of class
  434. // RSOP_Session. The data member 'creationTime' of that instance is examined when
  435. // evaluating whether the sub-namespace should be deleted.
  436. //
  437. //
  438. // Parameters: TTLMinutes - The maximum number of minutes that may have
  439. // elapsed since the creation of a sub-namespace
  440. //
  441. // Return:
  442. //
  443. // History: 12/01/99 leonardm Created.
  444. //
  445. //******************************************************************************
  446. HRESULT GarbageCollectNamespaces(ULONG TTLMinutes)
  447. {
  448. XInterface<IWbemLocator> xpWbemLocator = NULL;
  449. //
  450. // Connect to namespace ROOT\RSOP
  451. //
  452. HRESULT hr = CoCreateInstance( CLSID_WbemLocator,
  453. NULL,
  454. CLSCTX_INPROC_SERVER,
  455. IID_IWbemLocator,
  456. (LPVOID*) &xpWbemLocator);
  457. if(FAILED(hr))
  458. {
  459. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: CoCreateInstance returned 0x%x"), hr));
  460. return hr;
  461. }
  462. XInterface<IWbemServices> xpWbemServices = NULL;
  463. XBStr xbstrNamespace = L"root\\rsop";
  464. if(!xbstrNamespace)
  465. {
  466. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Failed to allocate memory.")));
  467. return E_OUTOFMEMORY;
  468. }
  469. hr = xpWbemLocator->ConnectServer(xbstrNamespace,
  470. NULL,
  471. NULL,
  472. 0L,
  473. 0L,
  474. NULL,
  475. NULL,
  476. &xpWbemServices);
  477. if(FAILED(hr))
  478. {
  479. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: ConnectServer failed. hr=0x%x" ), hr ));
  480. return hr;
  481. }
  482. //
  483. // Enumerate all instances of __namespace at the root\rsop level.
  484. //
  485. XInterface<IEnumWbemClassObject> xpEnum;
  486. XBStr xbstrClass = L"__namespace";
  487. if(!xbstrClass)
  488. {
  489. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Failed to allocate memory.")));
  490. return E_OUTOFMEMORY;
  491. }
  492. hr = xpWbemServices->CreateInstanceEnum( xbstrClass,
  493. WBEM_FLAG_SHALLOW | WBEM_FLAG_FORWARD_ONLY,
  494. NULL,
  495. &xpEnum);
  496. if(FAILED(hr))
  497. {
  498. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: CreateInstanceEnum failed. hr=0x%x" ), hr ));
  499. return hr;
  500. }
  501. XBStr xbstrProperty = L"Name";
  502. if(!xbstrProperty)
  503. {
  504. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Failed to allocate memory")));
  505. return E_FAIL;
  506. }
  507. XInterface<IWbemClassObject>xpInstance = NULL;
  508. ULONG ulReturned = 1;
  509. while(1)
  510. {
  511. hr = xpEnum->Next( WBEM_NO_WAIT, 1, &xpInstance, &ulReturned);
  512. if (hr != WBEM_S_NO_ERROR || !ulReturned)
  513. {
  514. break;
  515. }
  516. VARIANT var;
  517. VariantInit(&var);
  518. hr = xpInstance->Get(xbstrProperty, 0L, &var, NULL, NULL);
  519. xpInstance = NULL;
  520. if(FAILED(hr))
  521. {
  522. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Get failed. hr=0x%x" ), hr ));
  523. return E_FAIL;
  524. }
  525. XBStr xbstrGCNamespace = var.bstrVal;
  526. VariantClear( &var );
  527. if(!xbstrGCNamespace)
  528. {
  529. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Failed to allocate memory.")));
  530. return E_OUTOFMEMORY;
  531. }
  532. //
  533. // For every instance of __namespace under ROOT\RSOP
  534. // find out whether it is garbage-collectable.
  535. //
  536. if(IsGarbageCollectable(xbstrGCNamespace))
  537. {
  538. //
  539. // If it is garbage-collectable, delete it if it
  540. // was created more than 'TTLMinutes' minutes ago.
  541. // In case of failure, continue with next namespace
  542. // in the enumeration.
  543. //
  544. GarbageCollectNamespace(xbstrGCNamespace, xpWbemServices, TTLMinutes);
  545. }
  546. }
  547. if(hr != (HRESULT) WBEM_S_FALSE || ulReturned)
  548. {
  549. DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Get failed. hr=0x%x" ), hr ));
  550. return E_FAIL;
  551. }
  552. return S_OK;
  553. }