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.

640 lines
15 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. persist.cxx
  5. Abstract:
  6. Routines implementing the common logic for persisting the authz policy.
  7. This file contains routine called by the core logic to submit changes.
  8. It also contains routines that are called by the particular providers to
  9. find out information about the changed objects.
  10. Author:
  11. Cliff Van Dyke (cliffv) 9-May-2001
  12. --*/
  13. #include "pch.hxx"
  14. //
  15. // The enumeration context describes the current state of an enumeration
  16. // through the list of all the objects in the authz policy database
  17. //
  18. typedef struct _AZP_PERSIST_ENUM_CONTEXT {
  19. //
  20. // Stack Index
  21. // The enumeration walks the tree of objects. While enumerating child objects,
  22. // the context of the parent object enumeration is kept on the stack of contexts.
  23. //
  24. ULONG StackIndex;
  25. #define AZ_PERSIST_MAX_INDEX 4
  26. //
  27. // Pointer to the current Generic Child Head being enumerated
  28. //
  29. PGENERIC_OBJECT_HEAD GenericChildHead[AZ_PERSIST_MAX_INDEX];
  30. ULONG EnumerationContext[AZ_PERSIST_MAX_INDEX];
  31. } AZP_PERSIST_ENUM_CONTEXT, *PAZP_PERSIST_ENUM_CONTEXT;
  32. DWORD
  33. AzpPersistOpen(
  34. IN PAZP_ADMIN_MANAGER AdminManager,
  35. IN BOOL CreatePolicy
  36. )
  37. /*++
  38. Routine Description:
  39. This routine open the authz policy database.
  40. This routine also reads the policy database into cache.
  41. On Success, the caller should call SamplePersistClose to free any resources
  42. consumed by the open.
  43. This routine routes the request to the correct provider.
  44. On entry, AzGlResource must be locked exclusive.
  45. Arguments:
  46. AdminManager - Specifies the policy database that is to be read.
  47. CreatePolicy - TRUE if the policy database is to be created.
  48. FALSE if the policy database already exists
  49. Return Value:
  50. NO_ERROR - The operation was successful
  51. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  52. ERROR_ALREADY_EXISTS - CreatePolicy is TRUE and the policy already exists
  53. ERROR_FILE_NOT_FOUND - CreatePolicy is FALSE and the policy does not already exist
  54. Other status codes
  55. --*/
  56. {
  57. //
  58. // Call the appropriate provider
  59. //
  60. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  61. return SamplePersistOpen( AdminManager, CreatePolicy );
  62. }
  63. VOID
  64. AzpPersistClose(
  65. IN PAZP_ADMIN_MANAGER AdminManager
  66. )
  67. /*++
  68. Routine Description:
  69. This routine closes the authz policy database storage handles.
  70. This routine routes the request to the correct provider.
  71. On entry, AzGlResource must be locked exclusive.
  72. Arguments:
  73. AdminManager - Specifies the policy database that is to be read.
  74. Return Value:
  75. NO_ERROR - The operation was successful
  76. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  77. Other status codes
  78. --*/
  79. {
  80. //
  81. // Call the appropriate provider
  82. //
  83. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  84. SamplePersistClose( AdminManager );
  85. }
  86. DWORD
  87. AzpPersistSubmit(
  88. IN PGENERIC_OBJECT GenericObject,
  89. IN BOOLEAN DeleteMe
  90. )
  91. /*++
  92. Routine Description:
  93. This routine submits changes made to the authz policy database.
  94. This routine routes the request to the correct provider.
  95. If the object is being created, the GenericObject->PersistenceGuid field will be
  96. zero on input. Upon successful creation, this routine will set PersistenceGuid to
  97. non-zero. Upon failed creation, this routine will leave PersistenceGuid as zero.
  98. On entry, AzGlResource must be locked exclusive.
  99. Arguments:
  100. GenericObject - Specifies the object in the database that is to be updated
  101. in the underlying store.
  102. DeleteMe - TRUE if the object and all of its children are to be deleted.
  103. FALSE if the object is to be updated.
  104. Return Value:
  105. NO_ERROR - The operation was successful
  106. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  107. Other status codes
  108. --*/
  109. {
  110. DWORD WinStatus = NO_ERROR;
  111. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  112. //
  113. // Only persist dirty objects
  114. //
  115. if ( (GenericObject->Flags & GENOBJ_FLAGS_DIRTY) != 0 ||
  116. DeleteMe ) {
  117. //
  118. // Call the appropriate provider
  119. //
  120. WinStatus = SamplePersistSubmit( GenericObject, DeleteMe );
  121. //
  122. // Turn off the dirty bit
  123. if ( WinStatus == NO_ERROR ) {
  124. GenericObject->Flags &= ~GENOBJ_FLAGS_DIRTY;
  125. }
  126. }
  127. return WinStatus;
  128. }
  129. DWORD
  130. AzpPersistRefresh(
  131. IN PGENERIC_OBJECT GenericObject
  132. )
  133. /*++
  134. Routine Description:
  135. This routine updates the attributes of the object from the policy database.
  136. This routine routes the request to the correct provider.
  137. On entry, AzGlResource must be locked exclusive.
  138. Arguments:
  139. GenericObject - Specifies the object in the database whose cache entry is to be
  140. updated
  141. The GenericObject->PersistenceGuid field should be non-zero on input.
  142. Return Value:
  143. NO_ERROR - The operation was successful
  144. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  145. Other status codes
  146. --*/
  147. {
  148. DWORD WinStatus = NO_ERROR;
  149. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  150. //
  151. // Clear the attributes from the object so that the underlying routines only have
  152. // to re-populate the attributes.
  153. //
  154. ObFreeGenericObject( GenericObject, TRUE );
  155. //
  156. // Object no longer needs to be refreshed and is no longer dirty.
  157. //
  158. GenericObject->Flags &= ~(GENOBJ_FLAGS_REFRESH_ME|GENOBJ_FLAGS_DIRTY);
  159. //
  160. // Call the appropriate provider
  161. //
  162. WinStatus = SamplePersistRefresh( GenericObject );
  163. if ( WinStatus != NO_ERROR ) {
  164. //
  165. // Object needs to be refreshed
  166. //
  167. GenericObject->Flags |= GENOBJ_FLAGS_REFRESH_ME;
  168. }
  169. return WinStatus;
  170. }
  171. #if 0 // Providers don't actually call these yet
  172. DWORD
  173. AzpPersistEnumOpen(
  174. IN PAZP_ADMIN_MANAGER AdminManager,
  175. OUT PVOID *PersistEnumContext
  176. )
  177. /*++
  178. Routine Description:
  179. This routine begins an enumeration of the all objects in the authz policy database.
  180. A peristance provider will call this routine to determine which objects have changed.
  181. On entry, AzGlResource must be locked exclusive.
  182. Arguments:
  183. AdminManager - Specifies the policy database that is being queried
  184. PersistEnumContext - Returns a context that can be passed to AzpPersistEnumNext.
  185. This context must be closed by calling AzpPersistClose.
  186. Return Value:
  187. NO_ERROR - The operation was successful
  188. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  189. Other status codes
  190. --*/
  191. {
  192. PAZP_PERSIST_ENUM_CONTEXT Context = NULL;
  193. //
  194. // Allocate memory for the context
  195. //
  196. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  197. Context = (PAZP_PERSIST_ENUM_CONTEXT) AzpAllocateHeap( sizeof(*Context) );
  198. if ( Context == NULL ) {
  199. return ERROR_NOT_ENOUGH_MEMORY;
  200. }
  201. //
  202. // Initialize it
  203. //
  204. Context->StackIndex = 0;
  205. Context->GenericChildHead[0] = AdminManager->GenericObject.ChildGenericObjectHead;
  206. Context->EnumerationContext[0] = 0;
  207. //
  208. // Return the context to the caller
  209. //
  210. *PersistEnumContext = Context;
  211. return NO_ERROR;
  212. }
  213. DWORD
  214. AzpPersistEnumNext(
  215. IN PVOID PersistEnumContext,
  216. OUT PGENERIC_OBJECT *GenericObject
  217. )
  218. /*++
  219. Routine Description:
  220. This routine returns the next object in the list of all objects in the authz policy database.
  221. A peristance provider will call this routine to determine which objects have changed.
  222. On entry, AzGlResource must be locked exclusive.
  223. Arguments:
  224. PersistEnumContext - A context describing the current state of the enumeration
  225. GenericObject - Returns a pointer to an next object. The provider should inspect the
  226. GENOBJ_FLAGS_DELETED and GENOBJ_FLAGS_DIRTY flags to determine whether the
  227. object has been modified.
  228. Return Value:
  229. NO_ERROR - The operation was successful (a GenericObject was returned)
  230. ERROR_NO_MORE_ITEMS - No more items were available for enumeration
  231. Other status codes
  232. --*/
  233. {
  234. DWORD WinStatus;
  235. PAZP_PERSIST_ENUM_CONTEXT Context = (PAZP_PERSIST_ENUM_CONTEXT) PersistEnumContext;
  236. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  237. //
  238. // Loop until we find another object to return
  239. //
  240. for (;;) {
  241. //
  242. // Don't return pseudo objects to the caller.
  243. //
  244. if ( Context->GenericChildHead[Context->StackIndex]->ObjectType != OBJECT_TYPE_SID ) {
  245. //
  246. // Get the next object from the current list
  247. //
  248. WinStatus = ObEnumObjects( Context->GenericChildHead[Context->StackIndex],
  249. TRUE, // return deleted objects
  250. FALSE, // Don't refresh the cache
  251. &Context->EnumerationContext[Context->StackIndex],
  252. GenericObject );
  253. //
  254. // Before returning the current object,
  255. // set up the context to enumerate all children of the current context
  256. //
  257. if ( WinStatus == NO_ERROR ) {
  258. //
  259. // Only push onto the stack if the current object can have children
  260. //
  261. if ( (*GenericObject)->ChildGenericObjectHead != NULL ) {
  262. if ( Context->StackIndex+1 >= AZ_PERSIST_MAX_INDEX ) {
  263. ASSERT(FALSE);
  264. return ERROR_INTERNAL_ERROR;
  265. }
  266. Context->StackIndex++;
  267. Context->GenericChildHead[Context->StackIndex] = (*GenericObject)->ChildGenericObjectHead;
  268. Context->EnumerationContext[Context->StackIndex] = 0;
  269. }
  270. return NO_ERROR;
  271. }
  272. if ( WinStatus != ERROR_NO_MORE_ITEMS ) {
  273. return WinStatus;
  274. }
  275. }
  276. //
  277. // Move on to the next set of sibling object types.
  278. //
  279. Context->EnumerationContext[Context->StackIndex] = 0;
  280. if ( Context->GenericChildHead[Context->StackIndex]->SiblingGenericObjectHead != NULL ) {
  281. Context->GenericChildHead[Context->StackIndex] = Context->GenericChildHead[Context->StackIndex]->SiblingGenericObjectHead;
  282. continue;
  283. }
  284. //
  285. // There are no more sibling object types for the same parent.
  286. // Continue the enumeration of the parent objects
  287. //
  288. if ( Context->StackIndex == 0 ) {
  289. return ERROR_NO_MORE_ITEMS;
  290. }
  291. Context->StackIndex--;
  292. }
  293. }
  294. DWORD
  295. AzpPersistEnumClose(
  296. IN PVOID PersistEnumContext
  297. )
  298. /*++
  299. Routine Description:
  300. This routine returns free any resources consumed by the PersistEnumContext.
  301. A peristance provider will call this routine after determining which objects have changed.
  302. On entry, AzGlResource must be locked exclusive.
  303. Arguments:
  304. PersistEnumContext - A context describing the current state of the enumeration
  305. Return Value:
  306. NO_ERROR - The operation was successful
  307. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  308. Other status codes
  309. --*/
  310. {
  311. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  312. AzpFreeHeap( PersistEnumContext );
  313. return NO_ERROR;
  314. }
  315. #endif // 0 // Providers don't actually call these yet
  316. DWORD
  317. WINAPI
  318. AzSubmit(
  319. IN AZ_HANDLE AzHandle,
  320. IN DWORD Reserved
  321. )
  322. /*++
  323. Routine Description:
  324. Submit the changes made to the object via the *Create, *SetProperty, or *SetPropertyItem
  325. APIs.
  326. On failure, any changes made to the object are undone.
  327. Arguments:
  328. AzHandle - Passes in the handle to be updated.
  329. Reserved - Reserved. Must by zero.
  330. Return Value:
  331. NO_ERROR - The operation was successful.
  332. ERROR_INVALID_HANDLE - The passed in handle was invalid
  333. --*/
  334. {
  335. DWORD WinStatus;
  336. PGENERIC_OBJECT ReferencedGenericObject = NULL;
  337. PGENERIC_OBJECT GenericObject = (PGENERIC_OBJECT) AzHandle;
  338. DWORD ObjectType;
  339. //
  340. // Grab the global lock
  341. // Only for the admin manager case do we modify anything.
  342. //
  343. AzpLockResourceExclusive( &AzGlResource );
  344. //
  345. // Validate the input parameters
  346. //
  347. if ( Reserved != 0 ) {
  348. AzPrint(( AZD_INVPARM, "AzCloseHandle: Reserved != 0\n" ));
  349. WinStatus = ERROR_INVALID_PARAMETER;
  350. goto Cleanup;
  351. }
  352. //
  353. // Determine the type of the object
  354. //
  355. WinStatus = ObGetHandleType( GenericObject,
  356. FALSE, // Don't allow deleted objects
  357. &ObjectType );
  358. if ( WinStatus != NO_ERROR ) {
  359. goto Cleanup;
  360. }
  361. //
  362. // Grab the lock exclusively if we're going to change the database
  363. //
  364. if ( ObjectType == OBJECT_TYPE_ADMIN_MANAGER ) {
  365. AzPrint(( AZD_INVPARM, "AzCloseHandle: Can't persist admin manager.\n" ));
  366. WinStatus = ERROR_INVALID_PARAMETER;
  367. goto Cleanup;
  368. }
  369. //
  370. // Validate the passed in handle
  371. //
  372. WinStatus = ObReferenceObjectByHandle( GenericObject,
  373. FALSE, // Don't allow deleted objects
  374. TRUE, // Refresh the cache
  375. ObjectType );
  376. if ( WinStatus != NO_ERROR ) {
  377. goto Cleanup;
  378. }
  379. ReferencedGenericObject = GenericObject;
  380. //
  381. // Submit the change
  382. // ??? On failure, update the cache to match the object
  383. //
  384. WinStatus = AzpPersistSubmit( GenericObject, FALSE );
  385. if ( WinStatus != NO_ERROR ) {
  386. //
  387. // Update the cache to match the real object
  388. //
  389. // If we were trying to persist a creation of the object,
  390. // delete the object from the cache.
  391. //
  392. if ( IsEqualGUID( GenericObject->PersistenceGuid, AzGlZeroGuid ) ) {
  393. //
  394. // Mark the entry (and its child objects) as deleted
  395. // We do this since other threads may have references to the objects.
  396. // We want to ensure those threads know the objects are deleted.
  397. //
  398. ObMarkObjectDeleted( GenericObject );
  399. //
  400. // Remove the reference representing the list from the parent.
  401. //
  402. ObDereferenceObject( GenericObject );
  403. } else {
  404. //
  405. // Refresh the cache
  406. // Ignore the status code
  407. //
  408. (VOID) AzpPersistRefresh( GenericObject );
  409. }
  410. goto Cleanup;
  411. }
  412. WinStatus = NO_ERROR;
  413. //
  414. // Free locally used resources
  415. //
  416. Cleanup:
  417. if ( ReferencedGenericObject != NULL ) {
  418. ObDereferenceObject( ReferencedGenericObject );
  419. }
  420. //
  421. // Drop the global lock
  422. //
  423. AzpUnlockResource( &AzGlResource );
  424. return WinStatus;
  425. }