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.

2211 lines
69 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. cmnotify.c
  5. Abstract:
  6. This module contains support for NtNotifyChangeKey.
  7. Author:
  8. Bryan M. Willman (bryanwi) 03-Feb-1992
  9. Revision History:
  10. Dragos C. Sambotin (dragoss) 16-Mar-1999
  11. - fixing race conditions that when more than one thread simultaneously operates over the post list
  12. --*/
  13. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  14. // //
  15. // "The" POST BLOCK RULE : //
  16. // //
  17. // To operate on a post block (i.e. add or remove it from a list - notify,thread,slave), //
  18. // you should at least: //
  19. // 1. Hold the registry lock exclusively //
  20. // OR //
  21. // 2. Hold the registry lock shared and aquire the postblock mutex. //
  22. // //
  23. // //
  24. // WARNING!!! //
  25. // Failing to do that could arise in obscure registry deadlocks or usage of already freed memory (bugcheck) //
  26. // //
  27. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  28. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  29. // //
  30. // Other important rules to follow: //
  31. // //
  32. // 1. We DO NOT dereference objects in CmpPostApc ! //
  33. // 2. We DO NOT dereference objects while walking the notify list! //
  34. // 3. All operations with Thread PostList are done in CmpPostApc or at APC level. This should avoid two threads //
  35. // operating on the same list at the same time //
  36. // //
  37. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  38. #include "cmp.h"
  39. #ifdef CMP_NOTIFY_POSTBLOCK_CHECK
  40. /*++
  41. Routine Description:
  42. Check if the post block or it's slave (if any) has no reference
  43. to any key body object
  44. ++*/
  45. #define CmpCheckPostBlock(PostBlock ) \
  46. { \
  47. PCM_POST_BLOCK SlavePostBlock; \
  48. \
  49. /* this post block should have the link with key body already broken*/ \
  50. ASSERT( PostBlock->PostKeyBody == NULL ); \
  51. \
  52. /* only masters get to CmpPostApc */ \
  53. ASSERT( IsMasterPostBlock(PostBlock) ); \
  54. \
  55. if (CmpIsListEmpty(&(PostBlock->CancelPostList)) == FALSE) { \
  56. \
  57. /* get the slave and verify him too */ \
  58. SlavePostBlock = (PCM_POST_BLOCK)PostBlock->CancelPostList.Flink; \
  59. SlavePostBlock = CONTAINING_RECORD(SlavePostBlock, \
  60. CM_POST_BLOCK, \
  61. CancelPostList); \
  62. /* This should be true !*/ \
  63. ASSERT( !IsMasterPostBlock(SlavePostBlock) ); \
  64. \
  65. /* this post block shoul have the link with key body already broken */ \
  66. ASSERT( SlavePostBlock->PostKeyBody == NULL ); \
  67. } \
  68. }
  69. #else
  70. #define CmpCheckPostBlock(a) //nothing
  71. #endif
  72. //
  73. // "Back Side" of notify
  74. //
  75. extern PCMHIVE CmpMasterHive;
  76. VOID
  77. CmpReportNotifyHelper(
  78. PCM_KEY_CONTROL_BLOCK KeyControlBlock,
  79. IN PHHIVE SearchHive,
  80. IN PHHIVE Hive,
  81. IN HCELL_INDEX Cell,
  82. IN ULONG Filter
  83. );
  84. VOID
  85. CmpCancelSlavePost(
  86. PCM_POST_BLOCK PostBlock,
  87. PLIST_ENTRY DelayedDeref
  88. );
  89. VOID
  90. CmpFreeSlavePost(
  91. PCM_POST_BLOCK MasterPostBlock
  92. );
  93. VOID
  94. CmpAddToDelayedDeref(
  95. PCM_POST_BLOCK PostBlock,
  96. PLIST_ENTRY DelayedDeref
  97. );
  98. VOID
  99. CmpDelayedDerefKeys(
  100. PLIST_ENTRY DelayedDeref
  101. );
  102. BOOLEAN
  103. CmpNotifyTriggerCheck(
  104. IN PCM_NOTIFY_BLOCK NotifyBlock,
  105. IN PHHIVE Hive,
  106. IN PCM_KEY_NODE Node
  107. );
  108. VOID
  109. CmpDummyApc(
  110. struct _KAPC *Apc,
  111. PVOID *SystemArgument1,
  112. PVOID *SystemArgument2
  113. );
  114. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  115. VOID
  116. CmpFillPostBlockBuffer(
  117. PCM_POST_BLOCK PostBlock,
  118. PUNICODE_STRING ChangedKcbName OPTIONAL
  119. );
  120. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  121. #ifdef ALLOC_PRAGMA
  122. #pragma alloc_text(PAGE,CmpReportNotify)
  123. #pragma alloc_text(PAGE,CmpReportNotifyHelper)
  124. #pragma alloc_text(PAGE,CmpPostNotify)
  125. #pragma alloc_text(PAGE,CmpPostApc)
  126. #pragma alloc_text(PAGE,CmpPostApcRunDown)
  127. #pragma alloc_text(PAGE,CmNotifyRunDown)
  128. #pragma alloc_text(PAGE,CmpFlushNotify)
  129. #pragma alloc_text(PAGE,CmpNotifyChangeKey)
  130. #pragma alloc_text(PAGE,CmpCancelSlavePost)
  131. #pragma alloc_text(PAGE,CmpFreeSlavePost)
  132. #pragma alloc_text(PAGE,CmpAddToDelayedDeref)
  133. #pragma alloc_text(PAGE,CmpDelayedDerefKeys)
  134. #pragma alloc_text(PAGE,CmpNotifyTriggerCheck)
  135. #pragma alloc_text(PAGE,CmpDummyApc)
  136. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  137. #pragma alloc_text(PAGE,CmpFillCallerBuffer)
  138. #pragma alloc_text(PAGE,CmpFillPostBlockBuffer)
  139. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  140. #endif
  141. VOID
  142. CmpDummyApc(
  143. struct _KAPC *Apc,
  144. PVOID *SystemArgument1,
  145. PVOID *SystemArgument2
  146. )
  147. /*++
  148. Routine Description:
  149. Dummy routine to prevent user-mode callers to set special kernel apcs
  150. Arguments:
  151. Apc - pointer to apc object
  152. SystemArgument1 - IN: Status value for IoStatusBlock
  153. OUT: Ptr to IoStatusBlock (2nd arg to user apc routine)
  154. SystemArgument2 - Pointer to the PostBlock
  155. Return Value:
  156. NONE.
  157. --*/
  158. {
  159. UNREFERENCED_PARAMETER(Apc);
  160. UNREFERENCED_PARAMETER(SystemArgument1);
  161. UNREFERENCED_PARAMETER(SystemArgument2);
  162. }
  163. VOID
  164. CmpReportNotify(
  165. PCM_KEY_CONTROL_BLOCK KeyControlBlock,
  166. PHHIVE Hive,
  167. HCELL_INDEX Cell,
  168. ULONG Filter
  169. )
  170. /*++
  171. Routine Description:
  172. This routine is called when a notifiable event occurs. It will
  173. apply CmpReportNotifyHelper to the hive the event occured in,
  174. and the master hive if different.
  175. Arguments:
  176. KeyControlBlock - KCB of the key at which the event occured.
  177. For create or delete this is the created or deleted key.
  178. Hive - pointer to hive containing cell of Key at which event occured.
  179. Cell - cell of Key at which event occured
  180. (hive and cell correspond with name.)
  181. Filter - event to be reported
  182. Return Value:
  183. NONE.
  184. --*/
  185. {
  186. HCELL_INDEX CellToRelease = HCELL_NIL;
  187. PAGED_CODE();
  188. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"CmpReportNotify:\n"));
  189. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\tHive:%p Cell:%08lx Filter:%08lx\n", Hive, Cell, Filter));
  190. //
  191. // If the operation was create or delete, treat it as a change
  192. // to the parent.
  193. //
  194. if (Filter == REG_NOTIFY_CHANGE_NAME) {
  195. PCM_KEY_NODE pcell;
  196. ULONG flags;
  197. pcell = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
  198. if( pcell == NULL ) {
  199. //
  200. // we couldn't map the bin containing this cell
  201. // Bad luck! notifications will be broken.
  202. //
  203. return;
  204. }
  205. CellToRelease = Cell;
  206. flags = pcell->Flags;
  207. Cell = pcell->Parent;
  208. if (flags & KEY_HIVE_ENTRY) {
  209. ASSERT( CellToRelease != HCELL_NIL );
  210. HvReleaseCell(Hive,CellToRelease);
  211. Hive = &(CmpMasterHive->Hive);
  212. pcell = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
  213. if( pcell == NULL ) {
  214. //
  215. // we couldn't map the bin containing this cell
  216. // Bad luck! notifications will be broken.
  217. //
  218. return;
  219. }
  220. CellToRelease = Cell;
  221. }
  222. KeyControlBlock = KeyControlBlock->ParentKcb;
  223. //
  224. // if we're at an exit/link node, back up the real node
  225. // that MUST be it's parent.
  226. //
  227. if (pcell->Flags & KEY_HIVE_EXIT) {
  228. Cell = pcell->Parent;
  229. }
  230. ASSERT( CellToRelease != HCELL_NIL );
  231. HvReleaseCell(Hive,CellToRelease);
  232. }
  233. //
  234. // Report to notifies waiting on the event's hive
  235. //
  236. CmpReportNotifyHelper(KeyControlBlock, Hive, Hive, Cell, Filter);
  237. //
  238. // If containing hive is not the master hive, apply to master hive
  239. //
  240. if (Hive != &(CmpMasterHive->Hive)) {
  241. CmpReportNotifyHelper(KeyControlBlock,
  242. &(CmpMasterHive->Hive),
  243. Hive,
  244. Cell,
  245. Filter);
  246. }
  247. return;
  248. }
  249. BOOLEAN
  250. CmpNotifyTriggerCheck(
  251. IN PCM_NOTIFY_BLOCK NotifyBlock,
  252. IN PHHIVE Hive,
  253. IN PCM_KEY_NODE Node
  254. )
  255. /*++
  256. Routine Description:
  257. Checks if a notify can be triggered
  258. Arguments:
  259. NotifyBlock - the notify block
  260. Hive - Supplies hive containing node to match with.
  261. Node - pointer to key to match with (and check access to)
  262. Return Value:
  263. TRUE - yes.
  264. FALSE - no
  265. --*/
  266. {
  267. PCM_POST_BLOCK PostBlock;
  268. POST_BLOCK_TYPE NotifyType;
  269. PAGED_CODE();
  270. if(IsListEmpty(&(NotifyBlock->PostList)) == FALSE) {
  271. //
  272. // check if it is a kernel notify. Look at the first post block
  273. // to see that. If is a kernel post-block, then all posts in
  274. // the list should be kernel notifies
  275. //
  276. PostBlock = (PCM_POST_BLOCK)NotifyBlock->PostList.Flink;
  277. PostBlock = CONTAINING_RECORD(PostBlock,
  278. CM_POST_BLOCK,
  279. NotifyList);
  280. NotifyType = PostBlockType(PostBlock);
  281. if( NotifyType == PostAsyncKernel ) {
  282. // this is a kernel notify; always trigger it
  283. #if DBG
  284. //
  285. // DEBUG only code: All post blocks should be of the same type
  286. // (kernel/user)
  287. //
  288. while( PostBlock->NotifyList.Flink != &(NotifyBlock->PostList) ) {
  289. PostBlock = (PCM_POST_BLOCK)PostBlock->NotifyList.Flink;
  290. PostBlock = CONTAINING_RECORD(PostBlock,
  291. CM_POST_BLOCK,
  292. NotifyList);
  293. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"CmpNotifyTriggerCheck : NotifyBlock = %p\n",NotifyBlock));
  294. ASSERT( PostBlockType(PostBlock) == NotifyType );
  295. }
  296. #endif
  297. return TRUE;
  298. }
  299. }
  300. //
  301. // else, check if the caller has the right access
  302. //
  303. return CmpCheckNotifyAccess(NotifyBlock,Hive,Node);
  304. }
  305. VOID
  306. CmpReportNotifyHelper(
  307. PCM_KEY_CONTROL_BLOCK KeyControlBlock,
  308. IN PHHIVE SearchHive,
  309. IN PHHIVE Hive,
  310. IN HCELL_INDEX Cell,
  311. IN ULONG Filter
  312. )
  313. /*++
  314. Routine Description:
  315. Scan the list of active notifies for the specified hive. For
  316. any with scope including KeyControlBlock and filter matching
  317. Filter, and with proper security access, post the notify.
  318. Arguments:
  319. Name - canonical path name (as in a key control block) of the key
  320. at which the event occured. (This is the name for
  321. reporting purposes.)
  322. SearchHive - hive to search for matches (which notify list to check)
  323. Hive - Supplies hive containing node to match with.
  324. Cell - cell identifying the node in Hive
  325. Filter - type of event
  326. Return Value:
  327. NONE.
  328. --*/
  329. {
  330. PLIST_ENTRY NotifyPtr;
  331. PCM_NOTIFY_BLOCK NotifyBlock;
  332. PCMHIVE CmSearchHive;
  333. KIRQL OldIrql;
  334. LIST_ENTRY DelayedDeref;
  335. PCM_KEY_NODE Node;
  336. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  337. PUNICODE_STRING FullKcbName;
  338. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  339. PAGED_CODE();
  340. Node = (PCM_KEY_NODE)HvGetCell(Hive,Cell);
  341. if( Node == NULL ) {
  342. //
  343. // bad luck, we cannot map the view containing this cell
  344. //
  345. return;
  346. }
  347. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  348. FullKcbName = CmpConstructName(KeyControlBlock);
  349. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  350. KeRaiseIrql(APC_LEVEL, &OldIrql);
  351. CmSearchHive = CONTAINING_RECORD(SearchHive, CMHIVE, Hive);
  352. NotifyPtr = &(CmSearchHive->NotifyList);
  353. InitializeListHead(&(DelayedDeref));
  354. while (NotifyPtr->Flink != NULL) {
  355. NotifyPtr = NotifyPtr->Flink;
  356. NotifyBlock = CONTAINING_RECORD(NotifyPtr, CM_NOTIFY_BLOCK, HiveList);
  357. if (NotifyBlock->KeyControlBlock->TotalLevels > KeyControlBlock->TotalLevels) {
  358. //
  359. // list is level sorted, we're past all shorter entries
  360. //
  361. break;
  362. } else {
  363. PCM_KEY_CONTROL_BLOCK kcb;
  364. ULONG LevelDiff, l;
  365. LevelDiff = KeyControlBlock->TotalLevels - NotifyBlock->KeyControlBlock->TotalLevels;
  366. kcb = KeyControlBlock;
  367. for (l=0; l<LevelDiff; l++) {
  368. kcb = kcb->ParentKcb;
  369. }
  370. if (kcb == NotifyBlock->KeyControlBlock) {
  371. //
  372. // This Notify path is the prefix of this kcb.
  373. //
  374. if ((NotifyBlock->Filter & Filter)
  375. &&
  376. ((NotifyBlock->WatchTree == TRUE) ||
  377. (Cell == kcb->KeyCell))
  378. )
  379. {
  380. // Filter matches, this event is relevent to this notify
  381. // AND
  382. // Either the notify spans the whole subtree, or the cell
  383. // (key) of interest is the one it applies to
  384. //
  385. // THEREFORE: The notify is relevent.
  386. //
  387. //
  388. // Correct scope, does caller have access?
  389. //
  390. if (CmpNotifyTriggerCheck(NotifyBlock,Hive,Node)) {
  391. //
  392. // Notify block has KEY_NOTIFY access to the node
  393. // the event occured at. It is relevent. Therefore,
  394. // it gets to see this event. Post and be done.
  395. //
  396. // we specify that we want no key body dereferenciation
  397. // during the CmpPostNotify call. This is to prevent the
  398. // deletion of the current notify block
  399. //
  400. CmpPostNotify(
  401. NotifyBlock,
  402. NULL,
  403. Filter,
  404. STATUS_NOTIFY_ENUM_DIR,
  405. &DelayedDeref
  406. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  407. ,
  408. FullKcbName
  409. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  410. );
  411. } // else no KEY_NOTIFY access to node event occured at
  412. } // else not relevent (wrong scope, filter, etc)
  413. }
  414. }
  415. }
  416. KeLowerIrql(OldIrql);
  417. HvReleaseCell(Hive,Cell);
  418. //
  419. // finish the job started in CmpPostNotify (i.e. dereference the keybodies
  420. // we prevented. this may cause some notifyblocks to be freed
  421. //
  422. CmpDelayedDerefKeys(&DelayedDeref);
  423. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  424. if( FullKcbName != NULL ) {
  425. ExFreePoolWithTag(FullKcbName, CM_NAME_TAG | PROTECTED_POOL);
  426. }
  427. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  428. return;
  429. }
  430. VOID
  431. CmpPostNotify(
  432. PCM_NOTIFY_BLOCK NotifyBlock,
  433. PUNICODE_STRING Name OPTIONAL,
  434. ULONG Filter,
  435. NTSTATUS Status,
  436. PLIST_ENTRY ExternalKeyDeref OPTIONAL
  437. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  438. ,
  439. PUNICODE_STRING ChangedKcbName OPTIONAL
  440. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  441. )
  442. /*++
  443. Routine Description:
  444. Actually report the notify event by signalling events, enqueing
  445. APCs, and so forth.
  446. When Status is STATUS_NOTIFY_CLEANUP:
  447. - if the post block is a slave one, just cancel it.
  448. - if the post block is a master one, cancel all slave post blocks
  449. and trigger event on the master block.
  450. Comments:
  451. This routine is using a "delayed dereferencing" technique to prevent
  452. deadlocks that may appear when a keybody is dereferenced while holding
  453. the post block lock. As for this, a list with keybodies that have to be
  454. dereferenced is constructed while walking the list of postblocks attached
  455. to the current notify block and the related (slave or master) post blocks.
  456. The list is built by tricking postblocks. For all postblock about to be
  457. freed the PostKeyBody member is added to the local list and then set to NULL
  458. on the postblock. This will avoid the key body dereferencing in CmpFreePostBlock.
  459. Instead, after the postblock lock is released, the local list is iterated and
  460. the keybodies are dereferenced and the storage for associated CM_POST_KEY_BODY
  461. objects is freed.
  462. Arguments:
  463. NotifyBlock - pointer to structure that describes the notify
  464. operation. (Where to post to)
  465. Name - name of key at which event occurred.
  466. Filter - nature of event
  467. Status - completion status to report
  468. ExternalKeyDeref - this parameter (when not NULL) specifies that the caller doesn't
  469. want any keybody to be dereferenced while in this routine
  470. Return Value:
  471. NONE.
  472. --*/
  473. {
  474. PCM_POST_BLOCK PostBlock;
  475. PCM_POST_BLOCK SlavePostBlock;
  476. LIST_ENTRY LocalDelayedDeref;
  477. KIRQL OldIrql;
  478. PLIST_ENTRY DelayedDeref;
  479. Filter;
  480. Name;
  481. PAGED_CODE();
  482. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"CmpPostNotify:\n"));
  483. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\tNotifyBlock:%p ", NotifyBlock));
  484. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\tName = %wZ\n", Name));
  485. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\tFilter:%08lx Status=%08lx\n", Filter, Status));
  486. ASSERT_CM_LOCK_OWNED();
  487. if( ARGUMENT_PRESENT(ExternalKeyDeref) ) {
  488. //
  489. // The caller want to do all keybody dereferencing by himself
  490. //
  491. DelayedDeref = ExternalKeyDeref;
  492. } else {
  493. // local delayed dereferencing (the caller doesn't care!)
  494. DelayedDeref = &LocalDelayedDeref;
  495. InitializeListHead(DelayedDeref);
  496. }
  497. //
  498. // Aquire exclusive access over the postlist(s)
  499. //
  500. LOCK_POST_LIST();
  501. if (IsListEmpty(&(NotifyBlock->PostList)) == TRUE) {
  502. //
  503. // Nothing to post, set a mark and return
  504. //
  505. NotifyBlock->NotifyPending = TRUE;
  506. UNLOCK_POST_LIST();
  507. return;
  508. }
  509. NotifyBlock->NotifyPending = FALSE;
  510. //
  511. // IMPLEMENTATION NOTE:
  512. // If we ever want to actually implement the code that returns
  513. // names of things that changed, this is the place to add the
  514. // name and operation type to the buffer.
  515. //
  516. //
  517. // Pull and post all the entries in the post list
  518. //
  519. while (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) {
  520. //
  521. // Remove from the notify block list, and enqueue the apc.
  522. // The apc will remove itself from the thread list
  523. //
  524. PostBlock = (PCM_POST_BLOCK)RemoveHeadList(&(NotifyBlock->PostList));
  525. PostBlock = CONTAINING_RECORD(PostBlock,
  526. CM_POST_BLOCK,
  527. NotifyList);
  528. // Protect for multiple deletion of the same object
  529. CmpClearListEntry(&(PostBlock->NotifyList));
  530. if( (Status == STATUS_NOTIFY_CLEANUP) && !IsMasterPostBlock(PostBlock) ) {
  531. //
  532. // Cleanup notification (i.e. the key handle was closed or the key was deleted)
  533. // When the post is a slave one, just cancel it. Canceling means:
  534. // 1. Removing from the notify PostList (aldready done at this point - see above)
  535. // 2. Unchaining from the Master Block CancelPostList
  536. // 3. Delisting from the thread PostBlockList
  537. // 4. Actually freeing the memory
  538. //
  539. // Use Cmp variant to protect for multiple deletion of the same object
  540. CmpRemoveEntryList(&(PostBlock->CancelPostList));
  541. //
  542. // FIX 289351
  543. //
  544. // Use Cmp variant to protect for multiple deletion of the same object
  545. KeRaiseIrql(APC_LEVEL, &OldIrql);
  546. CmpRemoveEntryList(&(PostBlock->ThreadList));
  547. KeLowerIrql(OldIrql);
  548. #if DBG
  549. if(PostBlock->TraceIntoDebugger) {
  550. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]\tCmpPostNotify: PostBlock:%p is a slave block,and notify is CLEANUP==> just cleanning\n", PostBlock));
  551. }
  552. #endif
  553. if( PostBlock->NotifyType != PostSynchronous ) {
  554. // add to the deref list and clean the post block
  555. CmpAddToDelayedDeref(PostBlock,DelayedDeref);
  556. //
  557. // Front-end routine will do self cleanup for syncrounous notifications
  558. CmpFreePostBlock(PostBlock);
  559. }
  560. continue; //try the next one
  561. }
  562. //
  563. // Simulate that this block is the master one, so we can free the others
  564. // Doing that will ensure the right memory dealocation when the master
  565. // (from now on this block) will be freed.
  566. //
  567. if(!IsMasterPostBlock(PostBlock)) {
  568. //
  569. // oops.,this is not the master block, we have some more work to do
  570. //
  571. SlavePostBlock = PostBlock;
  572. do {
  573. SlavePostBlock = (PCM_POST_BLOCK)SlavePostBlock->CancelPostList.Flink;
  574. SlavePostBlock = CONTAINING_RECORD(SlavePostBlock,
  575. CM_POST_BLOCK,
  576. CancelPostList);
  577. //
  578. // reset the "master flag" if set
  579. //
  580. ClearMasterPostBlockFlag(SlavePostBlock);
  581. } while (SlavePostBlock != PostBlock);
  582. //
  583. // Make this post block the master one
  584. //
  585. SetMasterPostBlockFlag(PostBlock);
  586. }
  587. #if DBG
  588. if(PostBlock->TraceIntoDebugger) {
  589. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]\tCmpPostNotify: Master block switched to :%p\n", PostBlock));
  590. }
  591. #endif
  592. //
  593. // Cancel all slave Post requests that may be linked to self
  594. //
  595. if( PostBlockType(PostBlock) != PostSynchronous ) {
  596. //
  597. // Front-end routine will do self cleanup for syncrounous notifications
  598. CmpCancelSlavePost(PostBlock,DelayedDeref);
  599. //
  600. // Do the same for the master (in case master and slave got switched)
  601. // This will avoid dereferencing the keybody from CmpPostApc
  602. CmpAddToDelayedDeref(PostBlock,DelayedDeref);
  603. }
  604. switch (PostBlockType(PostBlock)) {
  605. case PostSynchronous:
  606. //
  607. // This is a SYNC notify call. There will be no user event,
  608. // and no user apc routine. Quick exit here, just fill in
  609. // the Status and poke the event.
  610. //
  611. // Holder of the systemevent will wake up and free the
  612. // postblock. If we free it here, we get a race & bugcheck.
  613. //
  614. // Set the flink to NULL so that the front side can tell this
  615. // has been removed if its wait aborts.
  616. //
  617. PostBlock->NotifyList.Flink = NULL;
  618. PostBlock->u->Sync.Status = Status;
  619. KeSetEvent(PostBlock->u->Sync.SystemEvent,
  620. 0,
  621. FALSE);
  622. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  623. //
  624. // store full qualified name into the post block private kernel buffer
  625. //
  626. CmpFillPostBlockBuffer(PostBlock,ChangedKcbName);
  627. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  628. break;
  629. case PostAsyncUser:
  630. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  631. //
  632. // store full qualified name into the post block private kernel buffer
  633. //
  634. CmpFillPostBlockBuffer(PostBlock,ChangedKcbName);
  635. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  636. //
  637. // Insert the APC into the queue
  638. //
  639. KeInsertQueueApc(PostBlock->u->AsyncUser.Apc,
  640. (PVOID)ULongToPtr(Status),
  641. (PVOID)PostBlock,
  642. 0);
  643. break;
  644. case PostAsyncKernel:
  645. //
  646. // Queue the work item, then free the post block.
  647. //
  648. if (PostBlock->u->AsyncKernel.WorkItem != NULL) {
  649. ExQueueWorkItem(PostBlock->u->AsyncKernel.WorkItem,
  650. PostBlock->u->AsyncKernel.QueueType);
  651. }
  652. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  653. //
  654. // fill the caller buffer (if any) - we only handle kernel mode adresses
  655. //
  656. CmpFillCallerBuffer(PostBlock,ChangedKcbName);
  657. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  658. //
  659. // Signal Event if present, and deref it.
  660. //
  661. if (PostBlock->u->AsyncKernel.Event != NULL) {
  662. KeSetEvent(PostBlock->u->AsyncKernel.Event,
  663. 0,
  664. FALSE);
  665. ObDereferenceObject(PostBlock->u->AsyncKernel.Event);
  666. }
  667. //
  668. // Multiple async kernel notification are not allowed
  669. //
  670. ASSERT(IsListEmpty(&(PostBlock->CancelPostList)) == TRUE);
  671. //
  672. // remove the post block from the thread list, and free it
  673. //
  674. // Use Cmp variant to protect for multiple deletion of the same object
  675. KeRaiseIrql(APC_LEVEL, &OldIrql);
  676. CmpRemoveEntryList(&(PostBlock->ThreadList));
  677. KeLowerIrql(OldIrql);
  678. // it was already added to delayed deref.
  679. CmpFreePostBlock(PostBlock);
  680. break;
  681. }
  682. }
  683. UNLOCK_POST_LIST();
  684. //
  685. // At this point we have a list of keybody elements that have to be dereferenciated
  686. // and the associated storage for the covering objects freed. The keybodies in this
  687. // list have only one reference count on them (they were referenced only in
  688. // NtNotifyChangeMultipleKeys), dereferencing them here should free the object
  689. //
  690. if( ARGUMENT_PRESENT(ExternalKeyDeref) ) {
  691. // do nothing; the caller wants to handle the dereferenciation by himself!
  692. } else {
  693. // dereferenciate all keybodies in the delayed list
  694. CmpDelayedDerefKeys(DelayedDeref);
  695. }
  696. return;
  697. }
  698. VOID
  699. CmpPostApc(
  700. struct _KAPC *Apc,
  701. PKNORMAL_ROUTINE *NormalRoutine,
  702. PVOID *NormalContext,
  703. PVOID *SystemArgument1,
  704. PVOID *SystemArgument2
  705. )
  706. /*++
  707. Routine Description:
  708. This is the kernel apc routine. It is called for all notifies,
  709. regardless of what form of notification the caller requested.
  710. We compute the postblock address from the apc object address.
  711. IoStatus is set. SystemEvent and UserEvent will be signalled
  712. as appropriate. If the user requested an APC, then NormalRoutine
  713. will be set at entry and executed when we exit. The PostBlock
  714. is freed here.
  715. Arguments:
  716. Apc - pointer to apc object
  717. NormalRoutine - Will be called when we return
  718. NormalContext - will be 1st argument to normal routine, ApcContext
  719. passed in when NtNotifyChangeKey was called
  720. SystemArgument1 - IN: Status value for IoStatusBlock
  721. OUT: Ptr to IoStatusBlock (2nd arg to user apc routine)
  722. SystemArgument2 - Pointer to the PostBlock
  723. Return Value:
  724. NONE.
  725. --*/
  726. {
  727. PCM_POST_BLOCK PostBlock;
  728. PAGED_CODE();
  729. #if !DBG
  730. UNREFERENCED_PARAMETER (Apc);
  731. UNREFERENCED_PARAMETER (NormalRoutine);
  732. UNREFERENCED_PARAMETER (NormalContext);
  733. #endif
  734. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"CmpPostApc:\n"));
  735. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\tApc:%p ", Apc));
  736. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"NormalRoutine:%p\n", NormalRoutine));
  737. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\tNormalContext:%08lx", NormalContext));
  738. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\tSystemArgument1=IoStatusBlock:%p\n", SystemArgument1));
  739. PostBlock = *(PCM_POST_BLOCK *)SystemArgument2;
  740. #if DBG
  741. if(PostBlock->TraceIntoDebugger) {
  742. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]CmpPostApc: PostBlock:%p\n", PostBlock));
  743. }
  744. #endif
  745. //
  746. // Fill in IO Status Block
  747. //
  748. // IMPLEMENTATION NOTE:
  749. // If we ever want to actually implement the code that returns
  750. // names of things that changed, this is the place to copy the
  751. // buffer into the caller's buffer.
  752. //
  753. // Sundown only: Use a 32bit IO_STATUS_BLOCK if the caller is 32bit.
  754. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  755. //
  756. // It looks like the time finally came :-)
  757. //
  758. CmpFillCallerBuffer(PostBlock,PostBlock->ChangedKcbFullName);
  759. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  760. try {
  761. CmpCheckIoStatusPointer(PostBlock->u->AsyncUser);
  762. CmpSetIoStatus(PostBlock->u->AsyncUser.IoStatusBlock,
  763. *((ULONG *)SystemArgument1),
  764. 0L,
  765. PsGetCurrentProcess()->Wow64Process != NULL);
  766. CmpCheckIoStatusPointer(PostBlock->u->AsyncUser);
  767. } except (EXCEPTION_EXECUTE_HANDLER) {
  768. NOTHING;
  769. }
  770. *SystemArgument1 = PostBlock->u->AsyncUser.IoStatusBlock;
  771. CmpCheckIoStatusPointer(PostBlock->u->AsyncUser);
  772. //
  773. // This is an Async notify, do all work here, including
  774. // cleaning up the post block
  775. //
  776. //
  777. // Signal UserEvent if present, and deref it.
  778. //
  779. if (PostBlock->u->AsyncUser.UserEvent != NULL) {
  780. KeSetEvent(PostBlock->u->AsyncUser.UserEvent,
  781. 0,
  782. FALSE);
  783. ObDereferenceObject(PostBlock->u->AsyncUser.UserEvent);
  784. }
  785. //
  786. // remove the post block from the thread list, and free it
  787. //
  788. // Use Cmp variant to protect for multiple deletion of the same object
  789. CmpRemoveEntryList(&(PostBlock->ThreadList));
  790. // debug only checks
  791. CmpCheckPostBlock(PostBlock);
  792. //
  793. // Free the slave post block to avoid "dangling" postblocks
  794. //
  795. CmpFreeSlavePost(PostBlock);
  796. //
  797. // free this post block
  798. //
  799. CmpFreePostBlock(PostBlock);
  800. return;
  801. }
  802. VOID
  803. CmpPostApcRunDown(
  804. struct _KAPC *Apc
  805. )
  806. /*++
  807. Routine Description:
  808. This routine is called to clear away apcs in the apc queue
  809. of a thread that has been terminated.
  810. Since the apc is in the apc queue, we know that it is NOT in
  811. any NotifyBlock's post list. It is, however, in the threads's
  812. PostBlockList.
  813. Therefore, poke any user events so that waiters are not stuck,
  814. drop the references so the event can be cleaned up, delist the
  815. PostBlock and free it.
  816. Since we are cleaning up the thread, SystemEvents are not interesting.
  817. Since the apc is in the apc queue, we know that if there were any other
  818. notifications related to this one, they are cleaned up by the
  819. CmPostNotify routine
  820. Arguments:
  821. Apc - pointer to apc object
  822. Return Value:
  823. NONE.
  824. --*/
  825. {
  826. PCM_POST_BLOCK PostBlock;
  827. KIRQL OldIrql;
  828. PAGED_CODE();
  829. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"CmpApcRunDown:"));
  830. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\tApc:%p \n", Apc));
  831. KeRaiseIrql(APC_LEVEL, &OldIrql);
  832. PostBlock = (PCM_POST_BLOCK)Apc->SystemArgument2;
  833. #if DBG
  834. if(PostBlock->TraceIntoDebugger) {
  835. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]CmpPostApcRunDown: PostBlock:%p\n", PostBlock));
  836. }
  837. #endif
  838. //
  839. // report status and wake up any threads that might otherwise
  840. // be stuck. also drop any event references we hold
  841. //
  842. // Sundown only: Use a 32bit IO_STATUS_BLOCK if the caller is 32bit.
  843. try {
  844. CmpCheckIoStatusPointer(PostBlock->u->AsyncUser);
  845. CmpSetIoStatus(PostBlock->u->AsyncUser.IoStatusBlock,
  846. STATUS_NOTIFY_CLEANUP,
  847. 0L,
  848. PsGetCurrentProcess()->Wow64Process != NULL);
  849. CmpCheckIoStatusPointer(PostBlock->u->AsyncUser);
  850. } except (EXCEPTION_EXECUTE_HANDLER) {
  851. NOTHING;
  852. }
  853. if (PostBlock->u->AsyncUser.UserEvent != NULL) {
  854. KeSetEvent(
  855. PostBlock->u->AsyncUser.UserEvent,
  856. 0,
  857. FALSE
  858. );
  859. ObDereferenceObject(PostBlock->u->AsyncUser.UserEvent);
  860. }
  861. //
  862. // delist the post block
  863. //
  864. // Use Cmp variant to protect for multiple deletion of the same object
  865. CmpRemoveEntryList(&(PostBlock->ThreadList));
  866. //
  867. // Free the slave post block to avoid "dangling" postblocks
  868. //
  869. CmpFreeSlavePost(PostBlock);
  870. //
  871. // Free the post block. Use Ex call because PostBlocks are NOT
  872. // part of the global registry pool computation, but are instead
  873. // part of NonPagedPool with Quota.
  874. //
  875. CmpFreePostBlock(PostBlock);
  876. KeLowerIrql(OldIrql);
  877. return;
  878. }
  879. //
  880. // Cleanup procedure
  881. //
  882. VOID
  883. CmNotifyRunDown(
  884. PETHREAD Thread
  885. )
  886. /*++
  887. Routine Description:
  888. This routine is called from PspExitThread to clean up any pending
  889. notify requests.
  890. It will traverse the thread's PostBlockList, for each PostBlock it
  891. finds, it will:
  892. 1. Remove it from the relevent NotifyBlock. This requires
  893. that we hold the Registry mutex.
  894. 2. Remove it from the thread's PostBlockList. This requires
  895. that we run at APC level.
  896. 3. By the time this procedure runs, user apcs are not interesting
  897. and neither are SystemEvents, so do not bother processing
  898. them.
  899. UserEvents and IoStatusBlocks could be refered to by other
  900. threads in the same process, or even a different process,
  901. so process them so those threads know what happened, use
  902. status code of STATUS_NOTIFY_CLEANUP.
  903. If the notify is a master one, cancel all slave notifications.
  904. Else only remove this notification from the master CancelPortList
  905. 4. Free the post block.
  906. Arguments:
  907. Thread - pointer to the executive thread object for the thread
  908. we wish to do rundown on.
  909. Return Value:
  910. NONE.
  911. --*/
  912. {
  913. PCM_POST_BLOCK PostBlock;
  914. KIRQL OldIrql;
  915. PAGED_CODE();
  916. if ( IsListEmpty(&(Thread->PostBlockList)) == TRUE ) {
  917. return;
  918. }
  919. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"CmNotifyRunDown: ethread:%p\n", Thread));
  920. CmpLockRegistryExclusive();
  921. //
  922. // Aquire exclusive access over the postlist(s)
  923. //
  924. // This is not needed (see the rule above)
  925. //LOCK_POST_LIST();
  926. KeRaiseIrql(APC_LEVEL, &OldIrql);
  927. while (IsListEmpty(&(Thread->PostBlockList)) == FALSE) {
  928. //
  929. // remove from thread list
  930. //
  931. PostBlock = (PCM_POST_BLOCK)RemoveHeadList(&(Thread->PostBlockList));
  932. PostBlock = CONTAINING_RECORD(
  933. PostBlock,
  934. CM_POST_BLOCK,
  935. ThreadList
  936. );
  937. // Protect for multiple deletion of the same object
  938. CmpClearListEntry(&(PostBlock->ThreadList));
  939. #if DBG
  940. if(PostBlock->TraceIntoDebugger) {
  941. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"[CM]CmpNotifyRunDown: ethread:%p, PostBlock:%p\n", Thread,PostBlock));
  942. }
  943. #endif
  944. //
  945. // Canceling a master notification implies canceling all the slave notifications
  946. // from the CancelPostList
  947. //
  948. if(IsMasterPostBlock(PostBlock)) {
  949. #if DBG
  950. if(PostBlock->TraceIntoDebugger) {
  951. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"[CM]\tCmpNotifyRunDown: PostBlock:%p is a master block\n", PostBlock));
  952. }
  953. #endif
  954. //
  955. // at this point, CmpReportNotify and friends will no longer
  956. // attempt to post this post block.
  957. //
  958. if (PostBlockType(PostBlock) == PostAsyncUser) {
  959. //
  960. // report status and wake up any threads that might otherwise
  961. // be stuck. also drop any event references we hold
  962. //
  963. // Sundown only: Use a 32bit IO_STATUS_BLOCK if the caller is 32bit.
  964. try {
  965. CmpCheckIoStatusPointer(PostBlock->u->AsyncUser);
  966. CmpSetIoStatus(PostBlock->u->AsyncUser.IoStatusBlock,
  967. STATUS_NOTIFY_CLEANUP,
  968. 0L,
  969. PsGetCurrentProcess()->Wow64Process != NULL);
  970. CmpCheckIoStatusPointer(PostBlock->u->AsyncUser);
  971. } except (EXCEPTION_EXECUTE_HANDLER) {
  972. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"!!CmNotifyRundown: code:%08lx\n", GetExceptionCode()));
  973. NOTHING;
  974. }
  975. if (PostBlock->u->AsyncUser.UserEvent != NULL) {
  976. KeSetEvent(
  977. PostBlock->u->AsyncUser.UserEvent,
  978. 0,
  979. FALSE
  980. );
  981. ObDereferenceObject(PostBlock->u->AsyncUser.UserEvent);
  982. }
  983. //
  984. // Cancel the APC. Otherwise the rundown routine will also
  985. // free the post block if the APC happens to be queued at
  986. // this point. If the APC is queued, then the post block has
  987. // already been removed from the notify list, so don't remove
  988. // it again.
  989. //
  990. if (!KeRemoveQueueApc(PostBlock->u->AsyncUser.Apc)) {
  991. //
  992. // remove from notify block's list
  993. //
  994. // Use Cmp variant to protect for multiple deletion of the same object
  995. CmpRemoveEntryList(&(PostBlock->NotifyList));
  996. //
  997. // Cancel all slave Post requests that may be linked to self
  998. //
  999. CmpCancelSlavePost(PostBlock,NULL); // we do not want delayed deref
  1000. } else {
  1001. //
  1002. // if we are here, the apc was in the apc queue, i.e. both master and slave
  1003. // post blocks were removed from the notify list. nothing more to do.
  1004. //
  1005. ASSERT( CmpIsListEmpty(&(PostBlock->NotifyList)) );
  1006. NOTHING;
  1007. }
  1008. } else {
  1009. //
  1010. // remove from notify block's list
  1011. //
  1012. // Use Cmp variant to protect for multiple deletion of the same object
  1013. CmpRemoveEntryList(&(PostBlock->NotifyList));
  1014. //
  1015. // Cancel all slave Post requests that may be linked to self
  1016. //
  1017. CmpCancelSlavePost(PostBlock,NULL); // we do not want delayed deref
  1018. }
  1019. //
  1020. // Free the slave Post blocks too
  1021. //
  1022. CmpFreeSlavePost(PostBlock);
  1023. //
  1024. // Free the post block. Use Ex call because PostBlocks are NOT
  1025. // part of the global registry pool computation, but are instead
  1026. // part of NonPagedPool with Quota.
  1027. //
  1028. CmpFreePostBlock(PostBlock);
  1029. } else {
  1030. #if DBG
  1031. if(PostBlock->TraceIntoDebugger) {
  1032. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"[CM]\tCmpNotifyRunDown: PostBlock:%p is a slave block\n", PostBlock));
  1033. }
  1034. #endif
  1035. //
  1036. // master should always be ahead of slaves; if we got here, we switched master
  1037. // and slaves back in CmpPostNotify; Show some respect and add slave at the end;
  1038. // master will control the cleanup
  1039. //
  1040. ASSERT( CmpIsListEmpty(&(PostBlock->CancelPostList)) == FALSE );
  1041. ASSERT( IsListEmpty(&(Thread->PostBlockList)) == FALSE );
  1042. InsertTailList(
  1043. &(Thread->PostBlockList),
  1044. &(PostBlock->ThreadList)
  1045. );
  1046. }
  1047. }
  1048. KeLowerIrql(OldIrql);
  1049. // This is not needed (see the rule above)
  1050. //UNLOCK_POST_LIST();
  1051. CmpUnlockRegistry();
  1052. return;
  1053. }
  1054. VOID
  1055. CmpFlushNotify(
  1056. PCM_KEY_BODY KeyBody,
  1057. BOOLEAN LockHeld
  1058. )
  1059. /*++
  1060. Routine Description:
  1061. Clean up notifyblock when a handle is closed or the key it refers
  1062. to is deleted.
  1063. Arguments:
  1064. KeyBody - supplies pointer to key object body for handle we
  1065. are cleaning up.
  1066. Return Value:
  1067. NONE
  1068. --*/
  1069. {
  1070. PCM_NOTIFY_BLOCK NotifyBlock;
  1071. PCMHIVE Hive;
  1072. PAGED_CODE();
  1073. ASSERT_CM_LOCK_OWNED();
  1074. if (KeyBody->NotifyBlock == NULL) {
  1075. return;
  1076. }
  1077. //
  1078. // Lock the hive exclusively to prevent multiple threads from whacking
  1079. // on the list.
  1080. //
  1081. Hive = CONTAINING_RECORD(KeyBody->KeyControlBlock->KeyHive,
  1082. CMHIVE,
  1083. Hive);
  1084. if( !LockHeld ) {
  1085. CmLockHive(Hive);
  1086. } else {
  1087. //
  1088. // we should be holding the reglock exclusive
  1089. //
  1090. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1091. }
  1092. //
  1093. // Reread the notify block in case it has already been freed.
  1094. //
  1095. NotifyBlock = KeyBody->NotifyBlock;
  1096. if (NotifyBlock == NULL) {
  1097. if( !LockHeld ) {
  1098. CmUnlockHive(Hive);
  1099. }
  1100. return;
  1101. }
  1102. //
  1103. // Clean up all PostBlocks waiting on the NotifyBlock
  1104. //
  1105. if (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) {
  1106. CmpPostNotify(
  1107. NotifyBlock,
  1108. NULL,
  1109. 0,
  1110. STATUS_NOTIFY_CLEANUP,
  1111. NULL
  1112. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  1113. ,
  1114. NULL
  1115. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  1116. );
  1117. }
  1118. //
  1119. // Reread the notify block in case it has already been freed.
  1120. //
  1121. NotifyBlock = KeyBody->NotifyBlock;
  1122. if (NotifyBlock == NULL) {
  1123. if( !LockHeld ) {
  1124. CmUnlockHive(Hive);
  1125. }
  1126. return;
  1127. }
  1128. //
  1129. // Release the subject context
  1130. //
  1131. SeReleaseSubjectContext(&NotifyBlock->SubjectContext);
  1132. //
  1133. // IMPLEMENTATION NOTE:
  1134. // If we ever do code to report names and types of events,
  1135. // this is the place to free the buffer.
  1136. //
  1137. //
  1138. // Remove the NotifyBlock from the hive chain
  1139. //
  1140. NotifyBlock->HiveList.Blink->Flink = NotifyBlock->HiveList.Flink;
  1141. if (NotifyBlock->HiveList.Flink != NULL) {
  1142. NotifyBlock->HiveList.Flink->Blink = NotifyBlock->HiveList.Blink;
  1143. }
  1144. // Protect for multiple deletion of the same object
  1145. CmpClearListEntry(&(NotifyBlock->HiveList));
  1146. KeyBody->NotifyBlock = NULL;
  1147. #ifdef CMP_ENTRYLIST_MANIPULATION
  1148. if (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) {
  1149. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpFlushNotify: NotifyBlock %08lx\n",NotifyBlock);
  1150. DbgBreakPoint();
  1151. }
  1152. //check is the notify has been deleted from the hive notify list
  1153. {
  1154. PCM_NOTIFY_BLOCK ValidNotifyBlock;
  1155. PLIST_ENTRY NotifyPtr;
  1156. NotifyPtr = &(Hive->NotifyList);
  1157. while (NotifyPtr->Flink != NULL) {
  1158. NotifyPtr = NotifyPtr->Flink;
  1159. ValidNotifyBlock = CONTAINING_RECORD(NotifyPtr, CM_NOTIFY_BLOCK, HiveList);
  1160. if( ValidNotifyBlock == NotifyBlock ) {
  1161. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpFlushNotify: NotifyBlock %08lx is about to be deleted but is still in the hive notify list\n",NotifyBlock);
  1162. DbgBreakPoint();
  1163. }
  1164. }
  1165. }
  1166. RtlZeroMemory((PVOID)NotifyBlock, sizeof(CM_NOTIFY_BLOCK));
  1167. #endif
  1168. if( !LockHeld ) {
  1169. CmUnlockHive(Hive);
  1170. }
  1171. //
  1172. // Free the block, clean up the KeyBody
  1173. //
  1174. ExFreePool(NotifyBlock);
  1175. return;
  1176. }
  1177. //
  1178. // "Front Side" of notify. See also Ntapi.c: ntnotifychangekey
  1179. //
  1180. NTSTATUS
  1181. CmpNotifyChangeKey(
  1182. IN PCM_KEY_BODY KeyBody,
  1183. IN PCM_POST_BLOCK PostBlock,
  1184. IN ULONG CompletionFilter,
  1185. IN BOOLEAN WatchTree,
  1186. IN PVOID Buffer,
  1187. IN ULONG BufferSize,
  1188. IN PCM_POST_BLOCK MasterPostBlock
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. This routine sets up the NotifyBlock, and attaches the PostBlock
  1193. to it. When it returns, the Notify is visible to the system,
  1194. and will receive event reports.
  1195. If there is already an event report pending, then the notify
  1196. call will be satisified at once.
  1197. Arguments:
  1198. KeyBody - pointer to key object that handle refers to, allows access
  1199. to key control block, notify block, etc.
  1200. PostBlock - pointer to structure that describes how/where the caller
  1201. is to be notified.
  1202. WARNING: PostBlock must come from Pool, THIS routine
  1203. will keep it, back side will free it. This
  1204. routine WILL free it in case of error.
  1205. CompletionFilter - what types of events the caller wants to see
  1206. WatchTree - TRUE to watch whole subtree, FALSE to watch only immediate
  1207. key the notify is applied to
  1208. Buffer - pointer to area to recieve notify data
  1209. BufferSize - size of buffer, also size user would like to allocate
  1210. for internal buffer
  1211. MasterPostBlock - the post block of the master notification. Used to
  1212. insert the PostBlock into the CancelPostList list.
  1213. Return Value:
  1214. Status.
  1215. --*/
  1216. {
  1217. PCM_NOTIFY_BLOCK NotifyBlock;
  1218. PCM_NOTIFY_BLOCK node;
  1219. PLIST_ENTRY ptr;
  1220. PCMHIVE Hive;
  1221. KIRQL OldIrql;
  1222. PAGED_CODE();
  1223. UNREFERENCED_PARAMETER (Buffer);
  1224. UNREFERENCED_PARAMETER (BufferSize);
  1225. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"CmpNotifyChangeKey:\n"));
  1226. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\tKeyBody:%p PostBlock:%p ", KeyBody, PostBlock));
  1227. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"Filter:%08lx WatchTree:%08lx\n", CompletionFilter, WatchTree));
  1228. //
  1229. // The registry lock should be aquired exclusively by the caller !!!
  1230. //
  1231. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1232. if (KeyBody->KeyControlBlock->Delete) {
  1233. ASSERT( KeyBody->NotifyBlock == NULL );
  1234. CmpFreePostBlock(PostBlock);
  1235. return STATUS_KEY_DELETED;
  1236. }
  1237. #if DBG
  1238. if(PostBlock->TraceIntoDebugger) {
  1239. WCHAR *NameBuffer = NULL;
  1240. UNICODE_STRING KeyName;
  1241. PCM_KEY_NODE TempNode;
  1242. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]CmpNotifyChangeKey: PostBlock:%p\tMasterBlock: %p\n", PostBlock,MasterPostBlock));
  1243. TempNode = (PCM_KEY_NODE)HvGetCell(KeyBody->KeyControlBlock->KeyHive, KeyBody->KeyControlBlock->KeyCell);
  1244. if( TempNode != NULL ) {
  1245. NameBuffer = ExAllocatePool(PagedPool, REG_MAX_KEY_NAME_LENGTH);
  1246. if(NameBuffer&& (KeyBody->KeyControlBlock->KeyCell != HCELL_NIL)) {
  1247. CmpInitializeKeyNameString(TempNode,&KeyName,NameBuffer);
  1248. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"\t[CM]CmpNotifyChangeKey: Key = %.*S\n",KeyName.Length / sizeof(WCHAR),KeyName.Buffer));
  1249. ExFreePool(NameBuffer);
  1250. }
  1251. HvReleaseCell(KeyBody->KeyControlBlock->KeyHive, KeyBody->KeyControlBlock->KeyCell);
  1252. }
  1253. }
  1254. #endif
  1255. Hive = (PCMHIVE)KeyBody->KeyControlBlock->KeyHive;
  1256. Hive = CONTAINING_RECORD(Hive, CMHIVE, Hive);
  1257. NotifyBlock = KeyBody->NotifyBlock;
  1258. if (NotifyBlock == NULL) {
  1259. //
  1260. // Set up new notify session
  1261. //
  1262. NotifyBlock = ExAllocatePoolWithQuotaTag(PagedPool|POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,sizeof(CM_NOTIFY_BLOCK),CM_NOTIFYBLOCK_TAG);
  1263. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_POOL,"**CmpNotifyChangeKey: allocate:%08lx, ", sizeof(CM_NOTIFY_BLOCK)));
  1264. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_POOL,"type:%d, at:%p\n", PagedPool, NotifyBlock));
  1265. if (NotifyBlock == NULL) {
  1266. CmpFreePostBlock(PostBlock);
  1267. return STATUS_INSUFFICIENT_RESOURCES;
  1268. }
  1269. NotifyBlock->KeyControlBlock = KeyBody->KeyControlBlock;
  1270. NotifyBlock->Filter = CompletionFilter;
  1271. NotifyBlock->WatchTree = WatchTree;
  1272. NotifyBlock->NotifyPending = FALSE;
  1273. InitializeListHead(&(NotifyBlock->PostList));
  1274. KeyBody->NotifyBlock = NotifyBlock;
  1275. NotifyBlock->KeyBody = KeyBody;
  1276. ASSERT( KeyBody->KeyControlBlock->Delete == FALSE );
  1277. #if DBG
  1278. if(PostBlock->TraceIntoDebugger) {
  1279. WCHAR *NameBuffer = NULL;
  1280. UNICODE_STRING KeyName;
  1281. PCM_KEY_NODE TempNode;
  1282. TempNode = (PCM_KEY_NODE)HvGetCell(KeyBody->KeyControlBlock->KeyHive, KeyBody->KeyControlBlock->KeyCell);
  1283. if( TempNode != NULL ) {
  1284. NameBuffer = ExAllocatePool(PagedPool, REG_MAX_KEY_NAME_LENGTH);
  1285. if(NameBuffer) {
  1286. CmpInitializeKeyNameString(TempNode,&KeyName,NameBuffer);
  1287. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]\tCmpNotifyChangeKey: New NotifyBlock at:%p was allocated for Key = %.*S\n",NotifyBlock,KeyName.Length / sizeof(WCHAR),KeyName.Buffer));
  1288. ExFreePool(NameBuffer);
  1289. }
  1290. HvReleaseCell(KeyBody->KeyControlBlock->KeyHive, KeyBody->KeyControlBlock->KeyCell);
  1291. }
  1292. }
  1293. #endif
  1294. //
  1295. // IMPLEMENTATION NOTE:
  1296. // If we ever want to actually return the buffers full of
  1297. // data, the buffer should be allocated and its address
  1298. // stored in the notify block here.
  1299. //
  1300. //
  1301. // Capture the subject context so we can do checking once the
  1302. // notify goes off.
  1303. //
  1304. SeCaptureSubjectContext(&NotifyBlock->SubjectContext);
  1305. //
  1306. // Attach notify block to hive in properly sorted order
  1307. //
  1308. ptr = &(Hive->NotifyList);
  1309. while (TRUE) {
  1310. if (ptr->Flink == NULL) {
  1311. //
  1312. // End of list, add self after ptr.
  1313. //
  1314. ptr->Flink = &(NotifyBlock->HiveList);
  1315. NotifyBlock->HiveList.Flink = NULL;
  1316. NotifyBlock->HiveList.Blink = ptr;
  1317. break;
  1318. }
  1319. ptr = ptr->Flink;
  1320. node = CONTAINING_RECORD(ptr, CM_NOTIFY_BLOCK, HiveList);
  1321. if (node->KeyControlBlock->TotalLevels >
  1322. KeyBody->KeyControlBlock->TotalLevels)
  1323. {
  1324. //
  1325. // ptr -> notify with longer name than us, insert in FRONT
  1326. //
  1327. NotifyBlock->HiveList.Flink = ptr;
  1328. ptr->Blink->Flink = &(NotifyBlock->HiveList);
  1329. NotifyBlock->HiveList.Blink = ptr->Blink;
  1330. ptr->Blink = &(NotifyBlock->HiveList);
  1331. break;
  1332. }
  1333. }
  1334. }
  1335. //
  1336. // Add post block to front of notify block's list, and add it to thread list.
  1337. //
  1338. InsertHeadList(
  1339. &(NotifyBlock->PostList),
  1340. &(PostBlock->NotifyList)
  1341. );
  1342. if( IsMasterPostBlock(PostBlock) ) {
  1343. //
  1344. // Protect against outrageous calls
  1345. //
  1346. ASSERT(PostBlock == MasterPostBlock);
  1347. //
  1348. // When the notification is a master one, initialize the CancelPostList list
  1349. //
  1350. InitializeListHead(&(PostBlock->CancelPostList));
  1351. } else {
  1352. //
  1353. // Add PostBlock at the end of the CancelPostList list from the master post
  1354. //
  1355. InsertTailList(
  1356. &(MasterPostBlock->CancelPostList),
  1357. &(PostBlock->CancelPostList)
  1358. );
  1359. }
  1360. KeRaiseIrql(APC_LEVEL, &OldIrql);
  1361. //
  1362. // show some respect and add masters to the front and slaves to the tail
  1363. //
  1364. if( IsMasterPostBlock(PostBlock) ) {
  1365. InsertHeadList(
  1366. &(PsGetCurrentThread()->PostBlockList),
  1367. &(PostBlock->ThreadList)
  1368. );
  1369. } else {
  1370. InsertTailList(
  1371. &(PsGetCurrentThread()->PostBlockList),
  1372. &(PostBlock->ThreadList)
  1373. );
  1374. }
  1375. #if DBG
  1376. if(PostBlock->TraceIntoDebugger) {
  1377. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]\tCmpNotifyChangeKey: Attaching the post:%p\t to thread:%p\n",PostBlock,PsGetCurrentThread()));
  1378. }
  1379. #endif
  1380. KeLowerIrql(OldIrql);
  1381. //
  1382. // If there is a notify pending (will not be if we just created
  1383. // the notify block) then post it at once. Note that this call
  1384. // ALWAYS returns STATUS_PENDING unless it fails. Caller must
  1385. // ALWAYS look in IoStatusBlock to see what happened.
  1386. //
  1387. if (NotifyBlock->NotifyPending == TRUE) {
  1388. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  1389. PUNICODE_STRING FullKcbName = CmpConstructName(KeyBody->KeyControlBlock);
  1390. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  1391. CmpPostNotify(
  1392. NotifyBlock,
  1393. NULL,
  1394. 0,
  1395. STATUS_NOTIFY_ENUM_DIR,
  1396. NULL
  1397. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  1398. ,
  1399. FullKcbName
  1400. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  1401. );
  1402. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  1403. if( FullKcbName != NULL ) {
  1404. ExFreePoolWithTag(FullKcbName, CM_NAME_TAG | PROTECTED_POOL);
  1405. }
  1406. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH
  1407. //
  1408. // return STATUS_SUCCESS to signal to the caller the the notify already been triggered
  1409. //
  1410. return STATUS_SUCCESS;
  1411. }
  1412. //
  1413. // return STATUS_PENDING to signal to the caller the the notify has not been triggered yet
  1414. //
  1415. return STATUS_PENDING;
  1416. }
  1417. VOID
  1418. CmpFreeSlavePost(
  1419. PCM_POST_BLOCK MasterPostBlock
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. Free the slave post block related to this master post block
  1424. Arguments:
  1425. MasterPostBlock - pointer to structure that describes the post requests.
  1426. It should be a master post!!
  1427. Return Value:
  1428. NONE.
  1429. --*/
  1430. {
  1431. PCM_POST_BLOCK SlavePostBlock;
  1432. PAGED_CODE();
  1433. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"CmpCancelSlavePost:\t"));
  1434. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"MasterPostBlock:%p\n", MasterPostBlock));
  1435. ASSERT(IsMasterPostBlock(MasterPostBlock));
  1436. #if DBG
  1437. if(MasterPostBlock->TraceIntoDebugger) {
  1438. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]CmCancelSlavePost: MasterPostBlock:%p\n", MasterPostBlock));
  1439. }
  1440. #endif
  1441. if (IsListEmpty(&(MasterPostBlock->CancelPostList)) == TRUE) {
  1442. //
  1443. // Nothing to cancel, just return
  1444. //
  1445. #if DBG
  1446. if(MasterPostBlock->TraceIntoDebugger) {
  1447. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]CmCancelSlavePost: MasterPostBlock:%p has no slaves\n", MasterPostBlock));
  1448. }
  1449. #endif
  1450. return;
  1451. }
  1452. //
  1453. // Pull all the entries in the cancel post list and unlink them (when they are slave requests)
  1454. // We base here on the assumption that there is only one slave.
  1455. //
  1456. // NOTE!!!
  1457. // When more than slave allowed, here to modify
  1458. //
  1459. SlavePostBlock = (PCM_POST_BLOCK)MasterPostBlock->CancelPostList.Flink;
  1460. SlavePostBlock = CONTAINING_RECORD(SlavePostBlock,
  1461. CM_POST_BLOCK,
  1462. CancelPostList);
  1463. #if DBG
  1464. if(MasterPostBlock->TraceIntoDebugger) {
  1465. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]CmCancelSlavePost: Cleaning SlavePostBlock:%p\n", SlavePostBlock));
  1466. }
  1467. #endif
  1468. //
  1469. // This should be true !
  1470. //
  1471. ASSERT( !IsMasterPostBlock(SlavePostBlock) );
  1472. //
  1473. // Unchain from the Master CancelPostList
  1474. //
  1475. // Use Cmp variant to protect for multiple deletion of the same object
  1476. CmpRemoveEntryList(&(SlavePostBlock->CancelPostList));
  1477. //
  1478. // delist the post block from the thread postblocklist
  1479. //
  1480. // Use Cmp variant to protect for multiple deletion of the same object
  1481. CmpRemoveEntryList(&(SlavePostBlock->ThreadList));
  1482. //
  1483. // Free the post block.
  1484. //
  1485. CmpFreePostBlock(SlavePostBlock);
  1486. //
  1487. // Result validation. was it the only slave?
  1488. //
  1489. ASSERT(IsListEmpty(&(MasterPostBlock->CancelPostList)));
  1490. }
  1491. VOID
  1492. CmpCancelSlavePost(
  1493. PCM_POST_BLOCK MasterPostBlock,
  1494. PLIST_ENTRY DelayedDeref
  1495. )
  1496. /*++
  1497. Routine Description:
  1498. Unlink the slave postblock from its notify list and dereferences (or adds to the delayed deref list)
  1499. the keybody related to this thread. This should disable the slave post block.
  1500. It will be cleared later in CmpPostApc.
  1501. Arguments:
  1502. MasterPostBlock - pointer to structure that describes the post requests.
  1503. It should be a master post!!
  1504. DelayedDeref - pointer to list of delayed deref keybodies. If this parameter is not NULL,
  1505. the keybody for the slave is not cleared before calling CmpFreePostBlock,
  1506. and instead is added to the list
  1507. Return Value:
  1508. NONE.
  1509. --*/
  1510. {
  1511. PCM_POST_BLOCK SlavePostBlock;
  1512. PAGED_CODE();
  1513. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"CmpCancelSlavePost:\t"));
  1514. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"MasterPostBlock:%p\n", MasterPostBlock));
  1515. ASSERT_CM_LOCK_OWNED();
  1516. ASSERT(IsMasterPostBlock(MasterPostBlock));
  1517. #if DBG
  1518. if(MasterPostBlock->TraceIntoDebugger) {
  1519. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]CmCancelSlavePost: MasterPostBlock:%p\n", MasterPostBlock));
  1520. }
  1521. #endif
  1522. if (IsListEmpty(&(MasterPostBlock->CancelPostList)) == TRUE) {
  1523. //
  1524. // Nothing to cancel, just return
  1525. //
  1526. #if DBG
  1527. if(MasterPostBlock->TraceIntoDebugger) {
  1528. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]CmCancelSlavePost: MasterPostBlock:%p has no slaves\n", MasterPostBlock));
  1529. }
  1530. #endif
  1531. return;
  1532. }
  1533. //
  1534. // Pull all the entries in the cancel post list and unlink them (when they are slave requests)
  1535. // We base here on the assumption that there is only one slave.
  1536. //
  1537. // NOTE!!!
  1538. // When more than slave allowed, here to modify
  1539. //
  1540. SlavePostBlock = (PCM_POST_BLOCK)MasterPostBlock->CancelPostList.Flink;
  1541. SlavePostBlock = CONTAINING_RECORD(SlavePostBlock,
  1542. CM_POST_BLOCK,
  1543. CancelPostList);
  1544. #if DBG
  1545. if(MasterPostBlock->TraceIntoDebugger) {
  1546. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_NOTIFY,"[CM]CmCancelSlavePost: Cleaning SlavePostBlock:%p\n", SlavePostBlock));
  1547. }
  1548. #endif
  1549. //
  1550. // This should be true !
  1551. //
  1552. ASSERT( !IsMasterPostBlock(SlavePostBlock) );
  1553. //
  1554. // Remove it from notify block's list
  1555. //
  1556. // Use Cmp variant to protect for multiple deletion of the same object
  1557. // This will disable the notifications that might come on the slave key
  1558. //
  1559. CmpRemoveEntryList(&(SlavePostBlock->NotifyList));
  1560. if( DelayedDeref ) {
  1561. //
  1562. // the caller wants to handle key body dereferenciation by himself
  1563. //
  1564. CmpAddToDelayedDeref(SlavePostBlock,DelayedDeref);
  1565. }
  1566. }
  1567. VOID
  1568. CmpAddToDelayedDeref(
  1569. PCM_POST_BLOCK PostBlock,
  1570. PLIST_ENTRY DelayedDeref
  1571. )
  1572. /*++
  1573. Routine Description:
  1574. Add the key body attached to the post block to the delayed deref list.
  1575. Cleans the post block KeyBody member, so it will not be dereferenced
  1576. when the post block is freed.
  1577. Arguments:
  1578. PostBlock - pointer to structure that describes the post requests.
  1579. DelayedDeref - the delayed deref list
  1580. Return Value:
  1581. NONE.
  1582. --*/
  1583. {
  1584. PAGED_CODE();
  1585. // common sense
  1586. ASSERT( PostBlock != NULL );
  1587. if( PostBlock->PostKeyBody ) {
  1588. //
  1589. // If the post block has a keybody attached, add it to delayed deref list and
  1590. // clear the post block member. The key body will be deref'd prior after
  1591. // postblock lock is released.
  1592. //
  1593. // extra validation
  1594. ASSERT(PostBlock->PostKeyBody->KeyBody != NULL);
  1595. ASSERT(DelayedDeref);
  1596. // add it to the end of the list
  1597. InsertTailList(
  1598. DelayedDeref,
  1599. &(PostBlock->PostKeyBody->KeyBodyList)
  1600. );
  1601. // make sure we don't deref it in CmpFreePostBlock
  1602. PostBlock->PostKeyBody = NULL;
  1603. }
  1604. return;
  1605. }
  1606. VOID
  1607. CmpDelayedDerefKeys(
  1608. PLIST_ENTRY DelayedDeref
  1609. )
  1610. /*++
  1611. Routine Description:
  1612. Walk through the entire list, dereference each keybody and free storage for the
  1613. CM_POST_KEY_BODY allocated for this purpose.
  1614. Arguments:
  1615. DelayedDeref - the delayed deref list
  1616. Return Value:
  1617. NONE.
  1618. --*/
  1619. {
  1620. PCM_POST_KEY_BODY PostKeyBody;
  1621. PAGED_CODE();
  1622. // common sense
  1623. ASSERT( DelayedDeref != NULL );
  1624. while(IsListEmpty(DelayedDeref) == FALSE) {
  1625. //
  1626. // Remove from the delayed deref list and deref the coresponding keybody
  1627. // free the storage associated with CM_POST_KEY_BODY
  1628. //
  1629. PostKeyBody = (PCM_POST_KEY_BODY)RemoveHeadList(DelayedDeref);
  1630. PostKeyBody = CONTAINING_RECORD(PostKeyBody,
  1631. CM_POST_KEY_BODY,
  1632. KeyBodyList);
  1633. // extra validation
  1634. ASSERT(PostKeyBody->KeyBody != NULL);
  1635. // this should be a valid key body
  1636. ASSERT(PostKeyBody->KeyBody->Type == KEY_BODY_TYPE);
  1637. // at last ..... dereference the key object
  1638. ObDereferenceObject(PostKeyBody->KeyBody);
  1639. // Free the storage for the CM_POST_KEY_BODY object (allocated by CmpAllocatePostBlock)
  1640. ExFreePool(PostKeyBody);
  1641. }
  1642. }
  1643. #ifdef CM_NOTIFY_CHANGED_KCB_FULLPATH
  1644. VOID
  1645. CmpFillCallerBuffer(
  1646. PCM_POST_BLOCK PostBlock,
  1647. PUNICODE_STRING ChangedKcbName
  1648. )
  1649. /*++
  1650. Routine Description:
  1651. Copies the full qualified name of the changed kcb to the
  1652. caller buffer (stored in the postblock).
  1653. Arguments:
  1654. PostBlock - post block holding the user buffer address and size
  1655. ChangedKcbName - unicode string holding the full qualified path of the kcb
  1656. - this may be null
  1657. Return Value:
  1658. NONE.
  1659. --*/
  1660. {
  1661. USHORT RequestedSize;
  1662. USHORT Length;
  1663. PUNICODE_STRING CallerUnicode;
  1664. PAGED_CODE();
  1665. if( PostBlock->CallerBuffer == NULL ) {
  1666. //
  1667. // nothing to do; the caller didn't request this info.
  1668. //
  1669. return;
  1670. }
  1671. //
  1672. // compute the requested size for the caller buffer
  1673. //
  1674. RequestedSize = sizeof(UNICODE_STRING);
  1675. if( PostBlock->CallerBufferSize < RequestedSize ) {
  1676. //
  1677. // bad luck!; not enough space- not even for an empty unicode string
  1678. //
  1679. return;
  1680. }
  1681. if(ChangedKcbName != NULL) {
  1682. Length = ChangedKcbName->Length;
  1683. } else {
  1684. Length = 0;
  1685. }
  1686. RequestedSize += Length;
  1687. //
  1688. // fill up the caller buffer
  1689. //
  1690. try {
  1691. CallerUnicode = (PUNICODE_STRING)PostBlock->CallerBuffer;
  1692. CallerUnicode->Buffer = (USHORT *) ((ULONG_PTR) CallerUnicode + sizeof(UNICODE_STRING));
  1693. CallerUnicode->MaximumLength = (USHORT)(PostBlock->CallerBufferSize - sizeof(UNICODE_STRING));
  1694. if( CallerUnicode->MaximumLength < Length ) {
  1695. Length = CallerUnicode->MaximumLength;
  1696. }
  1697. //
  1698. // copy the actual data
  1699. //
  1700. if( Length > 0 ) {
  1701. ASSERT( ChangedKcbName != NULL );
  1702. RtlCopyMemory(CallerUnicode->Buffer,ChangedKcbName->Buffer,Length);
  1703. }
  1704. CallerUnicode->Length = Length;
  1705. } except (EXCEPTION_EXECUTE_HANDLER) {
  1706. NOTHING;
  1707. }
  1708. }
  1709. VOID
  1710. CmpFillPostBlockBuffer(
  1711. PCM_POST_BLOCK PostBlock,
  1712. PUNICODE_STRING ChangedKcbName OPTIONAL
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. Copies the full qualified name of the changed kcb to the
  1717. postblock private kernel buffer
  1718. Arguments:
  1719. PostBlock - post block in question
  1720. ChangedKcbName - unicode string holding the full qualified path of the kcb
  1721. - this may be null
  1722. Return Value:
  1723. NONE.
  1724. --*/
  1725. {
  1726. PUNICODE_STRING FullName;
  1727. USHORT Size;
  1728. PAGED_CODE();
  1729. //
  1730. // we only store this info in masters (or promoted)
  1731. //
  1732. ASSERT( IsMasterPostBlock(PostBlock) );
  1733. //
  1734. // copy the kcb name (if any) into the postblock kernel mode buffer
  1735. //
  1736. if( ARGUMENT_PRESENT(ChangedKcbName) && // we have a kcb name
  1737. (PostBlock->CallerBuffer != NULL) // and the user requested for the info.
  1738. ) {
  1739. Size = sizeof(UNICODE_STRING) + ChangedKcbName->Length;
  1740. //
  1741. // allocate a kernel buffer to store the name; it'll be freed in CmpFreePostBlock
  1742. //
  1743. FullName = (PUNICODE_STRING) ExAllocatePoolWithTag(PagedPool,Size,CM_FIND_LEAK_TAG43);
  1744. if (FullName) {
  1745. FullName->Buffer = (USHORT *) ((ULONG_PTR) FullName + sizeof(UNICODE_STRING));
  1746. FullName->Length = ChangedKcbName->Length;
  1747. FullName->MaximumLength = ChangedKcbName->Length;
  1748. RtlCopyMemory(FullName->Buffer,ChangedKcbName->Buffer,FullName->Length);
  1749. PostBlock->ChangedKcbFullName = FullName;
  1750. }
  1751. //
  1752. // we successfully stored the full kcb name into the post block
  1753. // the apc (or the sync side of the notification will take care
  1754. // of transfering it to the caller buffer
  1755. //
  1756. }
  1757. }
  1758. #endif //CM_NOTIFY_CHANGED_KCB_FULLPATH