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.

2048 lines
62 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. cmse.c
  5. Abstract:
  6. This module implements security routines for the configuration manager.
  7. Author:
  8. John Vert (jvert) 20-Jan-1992
  9. Revision History:
  10. Richard Ward (richardw) 14-Apr-1992 Changed ACE_HEADER
  11. --*/
  12. #include "cmp.h"
  13. //
  14. // Function prototypes private to this module
  15. //
  16. //
  17. // Dragos: modified to use the security cache
  18. //
  19. BOOLEAN
  20. CmpFindMatchingDescriptorCell(
  21. IN PCMHIVE CmHive,
  22. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  23. IN ULONG Type,
  24. OUT PHCELL_INDEX MatchingCell,
  25. OUT OPTIONAL PCM_KEY_SECURITY_CACHE *CachedSecurityPointer
  26. );
  27. ////////////////
  28. NTSTATUS
  29. CmpSetSecurityDescriptorInfo(
  30. IN PCM_KEY_CONTROL_BLOCK kcb,
  31. IN PSECURITY_INFORMATION SecurityInformation,
  32. IN PSECURITY_DESCRIPTOR ModificationDescriptor,
  33. IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  34. IN POOL_TYPE PoolType,
  35. IN PGENERIC_MAPPING GenericMapping
  36. );
  37. NTSTATUS
  38. CmpQuerySecurityDescriptorInfo(
  39. IN PCM_KEY_CONTROL_BLOCK kcb,
  40. IN PSECURITY_INFORMATION SecurityInformation,
  41. OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  42. IN OUT PULONG Length,
  43. IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor
  44. );
  45. PCM_KEY_SECURITY
  46. CmpGetKeySecurity(
  47. IN PHHIVE Hive,
  48. IN PCM_KEY_NODE Key,
  49. OUT PHCELL_INDEX SecurityCell OPTIONAL
  50. );
  51. NTSTATUS
  52. CmpGetObjectSecurity(
  53. IN HCELL_INDEX Cell,
  54. IN PHHIVE Hive,
  55. OUT PCM_KEY_SECURITY *Security,
  56. OUT PHCELL_INDEX SecurityCell OPTIONAL
  57. );
  58. BOOLEAN
  59. CmpInsertSecurityCellList(
  60. IN PHHIVE Hive,
  61. IN HCELL_INDEX NodeCell,
  62. IN HCELL_INDEX SecurityCell
  63. );
  64. VOID
  65. CmpRemoveSecurityCellList(
  66. IN PHHIVE Hive,
  67. IN HCELL_INDEX SecurityCell
  68. );
  69. ULONG
  70. CmpSecurityExceptionFilter(
  71. IN PEXCEPTION_POINTERS ExceptionPointers
  72. );
  73. //
  74. // This macro takes a PSECURITY_DESCRIPTOR and returns the size of the
  75. // hive cell required to contain the entire security descriptor.
  76. //
  77. #define SECURITY_CELL_LENGTH(pDescriptor) \
  78. FIELD_OFFSET(CM_KEY_SECURITY,Descriptor) + \
  79. RtlLengthSecurityDescriptor(pDescriptor)
  80. #ifdef ALLOC_PRAGMA
  81. #pragma alloc_text(PAGE,CmpSecurityMethod )
  82. #pragma alloc_text(PAGE,CmpSetSecurityDescriptorInfo)
  83. #pragma alloc_text(PAGE,CmpAssignSecurityDescriptor)
  84. #pragma alloc_text(PAGE,CmpQuerySecurityDescriptorInfo)
  85. #pragma alloc_text(PAGE,CmpCheckCreateAccess)
  86. #pragma alloc_text(PAGE,CmpCheckNotifyAccess)
  87. #pragma alloc_text(PAGE,CmpGetObjectSecurity)
  88. #pragma alloc_text(PAGE,CmpGetKeySecurity)
  89. #pragma alloc_text(PAGE,CmpHiveRootSecurityDescriptor)
  90. #pragma alloc_text(PAGE,CmpFreeSecurityDescriptor)
  91. #pragma alloc_text(PAGE,CmpInsertSecurityCellList)
  92. #pragma alloc_text(PAGE,CmpRemoveSecurityCellList)
  93. #pragma alloc_text(PAGE,CmpSecurityExceptionFilter)
  94. #endif
  95. ULONG
  96. CmpSecurityExceptionFilter(
  97. IN PEXCEPTION_POINTERS ExceptionPointers
  98. )
  99. /*++
  100. Routine Description:
  101. Debug code to find registry security exceptions that are being swallowed
  102. Return Value:
  103. EXCEPTION_EXECUTE_HANDLER
  104. --*/
  105. {
  106. #ifndef _CM_LDR_
  107. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CM: Registry security exception %lx, ExceptionPointers = %p\n",
  108. ExceptionPointers->ExceptionRecord->ExceptionCode,
  109. ExceptionPointers);
  110. #endif //_CM_LDR_
  111. //
  112. // This is a request from the base test team; no dbg should be hit on the free builds
  113. // at the client; after RC2 is shipped we should enable this on free builds too.
  114. //
  115. #if DBG
  116. try {
  117. DbgBreakPoint();
  118. } except (EXCEPTION_EXECUTE_HANDLER) {
  119. //
  120. // no debugger enabled, just keep going
  121. //
  122. }
  123. #endif
  124. return(EXCEPTION_EXECUTE_HANDLER);
  125. }
  126. NTSTATUS
  127. CmpSecurityMethod (
  128. IN PVOID Object,
  129. IN SECURITY_OPERATION_CODE OperationCode,
  130. IN PSECURITY_INFORMATION SecurityInformation,
  131. IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  132. IN OUT PULONG CapturedLength,
  133. IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  134. IN POOL_TYPE PoolType,
  135. IN PGENERIC_MAPPING GenericMapping
  136. )
  137. /*++
  138. Routine Description:
  139. This is the security method for registry objects. It is responsible for
  140. retrieving, setting, and deleting the security descriptor of a registry
  141. object. It is not used to assign the original security descriptor to an
  142. object (use SeAssignSecurity for that purpose).
  143. IT IS ASSUMED THAT THE OBJECT MANAGER HAS ALREADY DONE THE ACCESS
  144. VALIDATIONS NECESSARY TO ALLOW THE REQUESTED OPERATIONS TO BE PERFORMED.
  145. Arguments:
  146. Object - Supplies a pointer to the object being used.
  147. OperationCode - Indicates if the operation is for setting, querying, or
  148. deleting the object's security descriptor.
  149. SecurityInformation - Indicates which security information is being
  150. queried or set. This argument is ignored for the delete operation.
  151. SecurityDescriptor - The meaning of this parameter depends on the
  152. OperationCode:
  153. QuerySecurityDescriptor - For the query operation this supplies the
  154. buffer to copy the descriptor into. The security descriptor is
  155. assumed to have been probed up to the size passed in in Length.
  156. Since it still points into user space, it must always be
  157. accessed in a try clause in case it should suddenly disappear.
  158. SetSecurityDescriptor - For a set operation this supplies the
  159. security descriptor to copy into the object. The security
  160. descriptor must be captured before this routine is called.
  161. DeleteSecurityDescriptor - It is ignored when deleting a security
  162. descriptor.
  163. AssignSecurityDescriptor - For assign operations this is the
  164. security descriptor that will be assigned to the object.
  165. It is assumed to be in kernel space, and is therefore not
  166. probed or captured.
  167. CapturedLength - For the query operation this specifies the length, in
  168. bytes, of the security descriptor buffer, and upon return contains
  169. the number of bytes needed to store the descriptor. If the length
  170. needed is greater than the length supplied the operation will fail.
  171. It is ignored in the set and delete operation.
  172. This parameter is assumed to be captured and probed as appropriate.
  173. ObjectsSecurityDescriptor - For the Set operation this supplies the address
  174. of a pointer to the object's current security descriptor. This routine
  175. will either modify the security descriptor in place or deallocate/
  176. allocate a new security descriptor and use this variable to indicate
  177. its new location. For the query operation it simply supplies
  178. the security descriptor being queried.
  179. PoolType - For the set operation this specifies the pool type to use if
  180. a new security descriptor needs to be allocated. It is ignored
  181. in the query and delete operation.
  182. GenericMapping - Passed only for the set operation, this argument provides
  183. the mapping of generic to specific/standard access types for the object
  184. being accessed. This mapping structure is expected to be safe to
  185. access (i.e., captured if necessary) prior to be passed to this routine.
  186. Return Value:
  187. NTSTATUS - STATUS_SUCCESS if the operation is successful and an
  188. appropriate error status otherwise.
  189. --*/
  190. {
  191. PCM_KEY_CONTROL_BLOCK kcb;
  192. NTSTATUS Status;
  193. CM_KEY_REFERENCE Key;
  194. PCM_KEY_NODE TempNode;
  195. //
  196. // Make sure the common parts of our input are proper
  197. //
  198. PAGED_CODE();
  199. ASSERT_KEY_OBJECT(Object);
  200. ASSERT( (OperationCode == SetSecurityDescriptor) ||
  201. (OperationCode == QuerySecurityDescriptor) ||
  202. (OperationCode == AssignSecurityDescriptor) ||
  203. (OperationCode == DeleteSecurityDescriptor) );
  204. //
  205. // Lock hive for shared or exclusive, depending on what we need
  206. // to do.
  207. //
  208. if (OperationCode == QuerySecurityDescriptor) {
  209. CmpLockRegistry();
  210. } else {
  211. CmpLockRegistryExclusive();
  212. #ifdef CHECK_REGISTRY_USECOUNT
  213. CmpCheckRegistryUseCount();
  214. #endif //CHECK_REGISTRY_USECOUNT
  215. }
  216. if (((PCM_KEY_BODY)Object)->KeyControlBlock->Delete) {
  217. //
  218. // Key has been deleted, performing security operations on
  219. // it is Not Allowed.
  220. //
  221. CmpUnlockRegistry();
  222. return(STATUS_KEY_DELETED);
  223. }
  224. kcb = ((PCM_KEY_BODY)Object)->KeyControlBlock;
  225. try {
  226. //
  227. // This routine simply cases off of the operation code to decide
  228. // which support routine to call
  229. //
  230. switch (OperationCode) {
  231. case SetSecurityDescriptor:
  232. //
  233. // check the rest of our input and call the set security
  234. // method
  235. //
  236. ASSERT( (PoolType == PagedPool) || (PoolType == NonPagedPool) );
  237. Status = CmpSetSecurityDescriptorInfo( kcb,
  238. SecurityInformation,
  239. SecurityDescriptor,
  240. ObjectsSecurityDescriptor,
  241. PoolType,
  242. GenericMapping );
  243. //
  244. // this is the one and only path on which a user could change
  245. // a security descriptor, therefore, report such changes for
  246. // notification here.
  247. //
  248. if (NT_SUCCESS(Status)) {
  249. CmpReportNotify(kcb,
  250. kcb->KeyHive,
  251. kcb->KeyCell,
  252. REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_SECURITY);
  253. }
  254. break;
  255. case QuerySecurityDescriptor:
  256. //
  257. // check the rest of our input and call the default query security
  258. // method
  259. //
  260. ASSERT( CapturedLength != NULL );
  261. Status = CmpQuerySecurityDescriptorInfo( kcb,
  262. SecurityInformation,
  263. SecurityDescriptor,
  264. CapturedLength,
  265. ObjectsSecurityDescriptor );
  266. break;
  267. case DeleteSecurityDescriptor:
  268. //
  269. // Nobody should ever call the delete method. When the key is
  270. // freed, the security descriptor associated with it is
  271. // explicitly freed (CmpFreeSecurityDescriptor)
  272. //
  273. ASSERT(FALSE);
  274. break;
  275. case AssignSecurityDescriptor:
  276. //
  277. // Set the SecurityDescriptor field in the object's header to
  278. // NULL. This indicates that our security method needs to be
  279. // called for any security descriptor operations.
  280. //
  281. Status = ObAssignObjectSecurityDescriptor(Object, NULL, PagedPool);
  282. ASSERT( NT_SUCCESS( Status ));
  283. TempNode = (PCM_KEY_NODE)HvGetCell(kcb->KeyHive, kcb->KeyCell);
  284. if( TempNode == NULL ) {
  285. //
  286. // we couldn't map the bin containing this cell
  287. //
  288. Status = STATUS_INSUFFICIENT_RESOURCES;
  289. // step thru exit
  290. break;
  291. }
  292. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  293. // release the cell right here as we are holding the reglock exclusive
  294. HvReleaseCell(kcb->KeyHive, kcb->KeyCell);
  295. //
  296. // Assign the actual descriptor.
  297. //
  298. Status = CmpAssignSecurityDescriptor( kcb->KeyHive,
  299. kcb->KeyCell,
  300. TempNode,
  301. SecurityDescriptor );
  302. //
  303. // Security has been changed, update the cache.
  304. //
  305. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  306. CmpAssignSecurityToKcb(kcb,TempNode->Security);
  307. break;
  308. default:
  309. //
  310. // Bugcheck on any other operation code, We won't get here if
  311. // the earlier asserts are still checked.
  312. //
  313. CM_BUGCHECK( REGISTRY_ERROR,BAD_SECURITY_METHOD,1,kcb,OperationCode);
  314. }
  315. } except (CmpSecurityExceptionFilter(GetExceptionInformation())) {
  316. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"!!CmpSecurityMethod: code:%08lx\n", GetExceptionCode()));
  317. Status = GetExceptionCode();
  318. }
  319. CmpUnlockRegistry();
  320. return(Status);
  321. }
  322. NTSTATUS
  323. CmpSetSecurityDescriptorInfo(
  324. IN PCM_KEY_CONTROL_BLOCK Key,
  325. IN PSECURITY_INFORMATION SecurityInformation,
  326. IN PSECURITY_DESCRIPTOR ModificationDescriptor,
  327. IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  328. IN POOL_TYPE PoolType,
  329. IN PGENERIC_MAPPING GenericMapping
  330. )
  331. /*++
  332. Routine Description:
  333. This routine will set a node's security descriptor. The input
  334. security descriptor must be previously captured.
  335. Arguments:
  336. Key - Supplies a pointer to the KEY_CONTROL_BLOCK for the node whose
  337. security descriptor will be set.
  338. SecurityInformation - Indicates which security information is
  339. to be applied to the object. The value(s) to be assigned are
  340. passed in the SecurityDescriptor parameter.
  341. ModificationDescriptor - Supplies the input security descriptor to be
  342. applied to the object. The caller of this routine is expected
  343. to probe and capture the passed security descriptor before calling
  344. and release it after calling.
  345. ObjectsSecurityDescriptor - Supplies the address of a pointer to
  346. the objects security descriptor that is going to be altered by
  347. this procedure
  348. PoolType - Specifies the type of pool to allocate for the objects
  349. security descriptor.
  350. GenericMapping - This argument provides the mapping of generic to
  351. specific/standard access types for the object being accessed.
  352. This mapping structure is expected to be safe to access
  353. (i.e., captured if necessary) prior to be passed to this routine.
  354. Return Value:
  355. NTSTATUS - STATUS_SUCCESS if successful and an appropriate error
  356. value otherwise
  357. --*/
  358. {
  359. NTSTATUS Status;
  360. HCELL_INDEX SecurityCell;
  361. HCELL_INDEX MatchSecurityCell;
  362. HCELL_INDEX NewCell;
  363. HCELL_INDEX OldCell;
  364. PCM_KEY_SECURITY Security;
  365. PCM_KEY_SECURITY NewSecurity;
  366. PCM_KEY_SECURITY FlinkSecurity;
  367. PCM_KEY_SECURITY BlinkSecurity;
  368. PCM_KEY_NODE Node;
  369. ULONG DescriptorLength;
  370. PSECURITY_DESCRIPTOR DescriptorCopy;
  371. PSECURITY_DESCRIPTOR OldDescriptorCopy;
  372. ULONG Type;
  373. LARGE_INTEGER SystemTime;
  374. PHHIVE Hive;
  375. PCM_KEY_SECURITY_CACHE CachedSecurity;
  376. PAGED_CODE();
  377. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpSetSecurityDescriptorInfo:\n"));
  378. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  379. Node = (PCM_KEY_NODE)HvGetCell(Key->KeyHive, Key->KeyCell);
  380. if( Node == NULL ) {
  381. //
  382. // we couldn't map the bin containing this cell;
  383. // this shouldn't happen as we are about to modify the cell
  384. // (i.e. it should be dirty/pinned by this time)
  385. //
  386. return STATUS_INSUFFICIENT_RESOURCES;
  387. }
  388. // release the cell right here as we are holding the reglock exclusive
  389. HvReleaseCell(Key->KeyHive, Key->KeyCell);
  390. //
  391. // Map in the hive cell for the security descriptor before we make
  392. // the call to SeSetSecurityDescriptorInfo. This prevents us from
  393. // changing its security descriptor and then being unable to bring
  394. // the hive cell into memory for updating.
  395. //
  396. Security = CmpGetKeySecurity(Key->KeyHive,
  397. Node,
  398. &SecurityCell);
  399. if( Security == NULL ) {
  400. //
  401. // couldn't map view inside
  402. //
  403. return STATUS_INSUFFICIENT_RESOURCES;
  404. }
  405. //
  406. // SeSetSecurityDescriptorInfo takes a pointer to the original
  407. // descriptor. This pointer is not freed, but a new pointer will
  408. // be returned.
  409. //
  410. DescriptorCopy = &Security->Descriptor;
  411. Status = SeSetSecurityDescriptorInfo( NULL,
  412. SecurityInformation,
  413. ModificationDescriptor,
  414. &DescriptorCopy,
  415. PoolType,
  416. GenericMapping );
  417. if (!NT_SUCCESS(Status)) {
  418. return(Status);
  419. }
  420. //
  421. // Set Security operation succeeded, so we update the security
  422. // descriptor in the hive.
  423. //
  424. DescriptorLength = RtlLengthSecurityDescriptor(DescriptorCopy);
  425. Type = HvGetCellType(Key->KeyCell);
  426. Hive = Key->KeyHive;
  427. if (! (HvMarkCellDirty(Hive, Key->KeyCell) &&
  428. HvMarkCellDirty(Hive, SecurityCell)))
  429. {
  430. ExFreePool(DescriptorCopy);
  431. return STATUS_NO_LOG_SPACE;
  432. }
  433. //
  434. // Try to find an existing security descriptor that we can share.
  435. //
  436. if (CmpFindMatchingDescriptorCell((PCMHIVE)Hive, DescriptorCopy, Type, &MatchSecurityCell,&CachedSecurity)) {
  437. //
  438. // A match was found.
  439. //
  440. if( MatchSecurityCell == SecurityCell ) {
  441. //
  442. // Whoops !!!; what we want to set is already here ! bail out
  443. // (office instalation does this !!!!)
  444. //
  445. ExFreePool(DescriptorCopy);
  446. //
  447. // Update the LastWriteTime of the key. Do we need to do that? ==> Ask John.
  448. //
  449. #pragma message ("Dragos ==> John - Do we need to update the time even though nothing changed?")
  450. KeQuerySystemTime(&SystemTime);
  451. Node->LastWriteTime = SystemTime;
  452. // update the time in kcb too, to keep the cache in sync
  453. Key->KcbLastWriteTime = SystemTime;
  454. return STATUS_SUCCESS;
  455. } else {
  456. if (!HvMarkCellDirty(Hive, MatchSecurityCell)) {
  457. ExFreePool(DescriptorCopy);
  458. return(STATUS_NO_LOG_SPACE);
  459. }
  460. if (Security->ReferenceCount == 1) {
  461. //
  462. // No more references to the old security cell, so we can free it now.
  463. //
  464. if (! (HvMarkCellDirty(Hive, Security->Flink) &&
  465. HvMarkCellDirty(Hive, Security->Blink))) {
  466. ExFreePool(DescriptorCopy);
  467. return(STATUS_NO_LOG_SPACE);
  468. }
  469. CmpRemoveSecurityCellList(Hive, SecurityCell);
  470. HvFreeCell(Hive, SecurityCell);
  471. } else {
  472. //
  473. // Just decrement the count on the old security cell
  474. //
  475. Security->ReferenceCount -= 1;
  476. }
  477. //
  478. // Set the node to point at the matching security cell.
  479. //
  480. Security = (PCM_KEY_SECURITY)HvGetCell(Hive, MatchSecurityCell);
  481. if( Security == NULL ) {
  482. //
  483. // we couldn't map the bin containing this cell
  484. // this should not happen as we just marked the cell dirty
  485. //
  486. ASSERT( FALSE );
  487. ExFreePool(DescriptorCopy);
  488. return STATUS_INSUFFICIENT_RESOURCES;
  489. }
  490. // release the cell right here as we are holding the reglock exclusive
  491. HvReleaseCell(Hive, MatchSecurityCell);
  492. Security->ReferenceCount += 1;
  493. Node->Security = MatchSecurityCell;
  494. }
  495. } else {
  496. //
  497. // No match was found, we need to create a new cell.
  498. //
  499. if (Security->ReferenceCount > 1) {
  500. //
  501. // We can't change the existing security cell, since it is shared
  502. // by multiple keys. Allocate a new cell and decrement the existing
  503. // one's reference count.
  504. //
  505. NewCell = HvAllocateCell(Key->KeyHive,
  506. SECURITY_CELL_LENGTH(DescriptorCopy),
  507. Type,
  508. HCELL_NIL);
  509. if (NewCell == HCELL_NIL) {
  510. ExFreePool(DescriptorCopy);
  511. return(STATUS_INSUFFICIENT_RESOURCES);
  512. }
  513. if (! HvMarkCellDirty(Key->KeyHive, Security->Flink)) {
  514. ExFreePool(DescriptorCopy);
  515. return STATUS_NO_LOG_SPACE;
  516. }
  517. Security->ReferenceCount -= 1;
  518. //
  519. // Map in the new cell and insert it into the linked list.
  520. //
  521. NewSecurity = (PCM_KEY_SECURITY) HvGetCell(Key->KeyHive, NewCell);
  522. if( NewSecurity == NULL ) {
  523. //
  524. // we couldn't map the bin containing this cell
  525. //
  526. ExFreePool(DescriptorCopy);
  527. return STATUS_INSUFFICIENT_RESOURCES;
  528. }
  529. // release the cell right here as we are holding the reglock exclusive
  530. HvReleaseCell(Key->KeyHive, NewCell);
  531. NewSecurity->Blink = SecurityCell;
  532. NewSecurity->Flink = Security->Flink;
  533. FlinkSecurity = (PCM_KEY_SECURITY) HvGetCell(Key->KeyHive, Security->Flink);
  534. if( FlinkSecurity == NULL ) {
  535. //
  536. // we couldn't map the bin containing this cell
  537. //
  538. ExFreePool(DescriptorCopy);
  539. return STATUS_INSUFFICIENT_RESOURCES;
  540. }
  541. // release the cell right here as we are holding the reglock exclusive
  542. HvReleaseCell(Key->KeyHive, Security->Flink);
  543. Security->Flink = FlinkSecurity->Blink = NewCell;
  544. //
  545. // initialize new cell
  546. //
  547. NewSecurity->Signature = CM_KEY_SECURITY_SIGNATURE;
  548. NewSecurity->ReferenceCount = 1;
  549. NewSecurity->DescriptorLength = DescriptorLength;
  550. Security=NewSecurity;
  551. //
  552. // copy the descriptor
  553. //
  554. RtlCopyMemory( &(Security->Descriptor),
  555. DescriptorCopy,
  556. DescriptorLength );
  557. //
  558. // Add the new created security cell to the cache
  559. //
  560. if( !NT_SUCCESS(CmpAddSecurityCellToCache( (PCMHIVE)Key->KeyHive,NewCell,FALSE)) ) {
  561. //
  562. // we couldn't map the bin containing this cell
  563. // this shouldn't happen as we just allocated (marked dirty) the cell
  564. //
  565. ASSERT( FALSE );
  566. ExFreePool(DescriptorCopy);
  567. return STATUS_INSUFFICIENT_RESOURCES;
  568. }
  569. //
  570. // Update the pointer in the node cell.
  571. //
  572. Node->Security = NewCell;
  573. } else {
  574. //
  575. // when this is FALSE, the new cell is ADDED to cache;
  576. // Otherwise (the cell index and size did not change),
  577. // the new sd is copied over the one in cache
  578. //
  579. BOOLEAN UpdateCache;
  580. if (DescriptorLength != Security->DescriptorLength) {
  581. //
  582. // The security descriptor's size has changed, and it is not shared
  583. // by any other cells, so reallocate the cell.
  584. //
  585. if (! (HvMarkCellDirty(Key->KeyHive, Security->Flink) &&
  586. HvMarkCellDirty(Key->KeyHive, Security->Blink))) {
  587. ExFreePool(DescriptorCopy);
  588. return(STATUS_INSUFFICIENT_RESOURCES);
  589. }
  590. DCmCheckRegistry((PCMHIVE)(Key->KeyHive));
  591. OldCell = SecurityCell;
  592. SecurityCell = HvReallocateCell( Key->KeyHive,
  593. SecurityCell,
  594. SECURITY_CELL_LENGTH(DescriptorCopy) );
  595. if (SecurityCell == HCELL_NIL) {
  596. ExFreePool(DescriptorCopy);
  597. return(STATUS_INSUFFICIENT_RESOURCES);
  598. }
  599. //
  600. // remove the old cell from security cache and signal that the new one should be added
  601. //
  602. CmpRemoveFromSecurityCache ((PCMHIVE)Key->KeyHive,OldCell);
  603. UpdateCache = FALSE;
  604. //
  605. // Update the Node's security data.
  606. //
  607. Node->Security = SecurityCell;
  608. //
  609. // Update Security to point to where the new security object is
  610. //
  611. Security = (PCM_KEY_SECURITY) HvGetCell(Key->KeyHive, SecurityCell);
  612. if( Security == NULL ) {
  613. //
  614. // we couldn't map the bin containing this cell
  615. // this shouldn't happen as we just allocated this cell
  616. // (i.e. it should be pinned into memory at this point)
  617. //
  618. ASSERT( FALSE );
  619. ExFreePool(DescriptorCopy);
  620. return STATUS_INSUFFICIENT_RESOURCES;
  621. }
  622. // release the cell right here as we are holding the reglock exclusive
  623. HvReleaseCell(Key->KeyHive, SecurityCell);
  624. ASSERT_SECURITY(Security);
  625. //
  626. // Update other list references to the node
  627. //
  628. if (Security->Flink == OldCell) {
  629. Security->Flink = SecurityCell; // point to new self
  630. } else {
  631. FlinkSecurity = (PCM_KEY_SECURITY) HvGetCell(
  632. Key->KeyHive,
  633. Security->Flink
  634. );
  635. if( FlinkSecurity == NULL ) {
  636. //
  637. // we couldn't map the bin containing this cell
  638. //
  639. ExFreePool(DescriptorCopy);
  640. return STATUS_INSUFFICIENT_RESOURCES;
  641. }
  642. // release the cell right here as we are holding the reglock exclusive
  643. HvReleaseCell(Key->KeyHive, Security->Flink);
  644. FlinkSecurity->Blink = SecurityCell;
  645. }
  646. if (Security->Blink == OldCell) {
  647. Security->Blink = SecurityCell; // point to new self
  648. } else {
  649. BlinkSecurity = (PCM_KEY_SECURITY) HvGetCell(
  650. Key->KeyHive,
  651. Security->Blink
  652. );
  653. if( BlinkSecurity == NULL ) {
  654. //
  655. // we couldn't map the bin containing this cell
  656. //
  657. ExFreePool(DescriptorCopy);
  658. return STATUS_INSUFFICIENT_RESOURCES;
  659. }
  660. // release the cell right here as we are holding the reglock exclusive
  661. HvReleaseCell(Key->KeyHive,Security->Blink);
  662. BlinkSecurity->Flink = SecurityCell;
  663. }
  664. //
  665. // Finally, update the length field in the cell
  666. //
  667. Security->DescriptorLength = DescriptorLength;
  668. DCmCheckRegistry((PCMHIVE)(Key->KeyHive));
  669. } else {
  670. //
  671. // Size hasn't changed, and it's not shared by any other cells, so
  672. // we can just write the new bits over the old bits.
  673. //
  674. //
  675. // new bits should be copied over the cached security
  676. // descriptor too, to keep cache consistency
  677. //
  678. //
  679. // get the cached security structure for this security cell
  680. //
  681. ULONG Index;
  682. if( CmpFindSecurityCellCacheIndex ((PCMHIVE)Hive,SecurityCell,&Index) == FALSE ) {
  683. //
  684. // this cannot happen !!!
  685. //
  686. CM_BUGCHECK( REGISTRY_ERROR,BAD_SECURITY_CACHE,2,Key,SecurityCell);
  687. }
  688. CachedSecurity = ((PCMHIVE)Hive)->SecurityCache[Index].CachedSecurity;
  689. UpdateCache = TRUE;
  690. }
  691. RtlCopyMemory( &(Security->Descriptor),
  692. DescriptorCopy,
  693. DescriptorLength );
  694. if( UpdateCache == TRUE ) {
  695. //
  696. // we just need to copy the descriptor over the existing one
  697. // (keep the security cache in sync !!!)
  698. //
  699. RtlCopyMemory( &(CachedSecurity->Descriptor),
  700. DescriptorCopy,
  701. DescriptorLength );
  702. //
  703. // recalculate the conv key and insert the sd in the proper place in the hash
  704. //
  705. CmpRemoveEntryList(&(CachedSecurity->List));
  706. CachedSecurity->ConvKey = CmpSecConvKey(DescriptorLength,(PULONG)(DescriptorCopy));
  707. InsertTailList( &(((PCMHIVE)Hive)->SecurityHash[CachedSecurity->ConvKey % CmpSecHashTableSize]),
  708. &(CachedSecurity->List)
  709. );
  710. } else {
  711. //
  712. // add new cell to the security cache
  713. //
  714. if( !NT_SUCCESS(CmpAddSecurityCellToCache( (PCMHIVE)Hive,SecurityCell,FALSE)) ) {
  715. //
  716. // we couldn't map the bin containing this cell
  717. // this shouldn't happen as we just allocated (marked dirty) the cell
  718. //
  719. ASSERT( FALSE );
  720. ExFreePool(DescriptorCopy);
  721. return STATUS_INSUFFICIENT_RESOURCES;
  722. }
  723. }
  724. }
  725. }
  726. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"\tObject's SD has been changed\n"));
  727. //CmpDumpSecurityDescriptor(DescriptorCopy, "NEW DESCRIPTOR\n");
  728. ExFreePool(DescriptorCopy);
  729. //
  730. // Update the LastWriteTime of the key.
  731. //
  732. KeQuerySystemTime(&SystemTime);
  733. Node->LastWriteTime = SystemTime;
  734. // update the time in kcb too, to keep the cache in sync
  735. Key->KcbLastWriteTime = SystemTime;
  736. //
  737. // Security has changed, update the cache.
  738. //
  739. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  740. CmpAssignSecurityToKcb(Key,Node->Security);
  741. return(STATUS_SUCCESS);
  742. }
  743. NTSTATUS
  744. CmpAssignSecurityDescriptor(
  745. IN PHHIVE Hive,
  746. IN HCELL_INDEX Cell,
  747. IN PCM_KEY_NODE Node,
  748. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  749. )
  750. /*++
  751. Routine Description:
  752. This routine assigns the given security descriptor to the specified
  753. node in the configuration tree.
  754. Arguments:
  755. Hive - Supplies a pointer to the Hive for the node whose security
  756. descriptor will be assigned.
  757. Cell - Supplies the HCELL_INDEX of the node whose security descriptor
  758. will be assigned.
  759. Node - Supplies a pointer to the node whose security descriptor will
  760. be assigned.
  761. SecurityDescriptor - Supplies a pointer to the security descriptor to
  762. be assigned to the node.
  763. PoolType - Supplies the type of pool the SecurityDescriptor was a
  764. allocated from.
  765. Return Value:
  766. NTSTATUS - STATUS_SUCCESS if successful and an appropriate error value
  767. otherwise
  768. --*/
  769. {
  770. HCELL_INDEX SecurityCell;
  771. PCM_KEY_SECURITY Security;
  772. ULONG DescriptorLength;
  773. ULONG Type;
  774. PAGED_CODE();
  775. //
  776. // Map the node that we need to assign the security descriptor to.
  777. //
  778. if (! HvMarkCellDirty(Hive, Cell)) {
  779. return STATUS_NO_LOG_SPACE;
  780. }
  781. ASSERT_NODE(Node);
  782. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  783. #if DBG
  784. {
  785. UNICODE_STRING Name;
  786. Name.MaximumLength = Name.Length = Node->NameLength;
  787. Name.Buffer = Node->Name;
  788. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpAssignSecurityDescriptor: '%wZ' (H %p C %lx)\n",&Name,Hive,Cell ));
  789. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"\tSecurityCell = %lx\n",Node->Security));
  790. }
  791. #endif
  792. ASSERT(Node->Security==HCELL_NIL);
  793. //
  794. // This is a CreateKey, so the registry node has just been created and
  795. // the security descriptor we have been passed needs to be associated
  796. // with the new registry node and inserted into the hive.
  797. //
  798. //CmpDumpSecurityDescriptor(SecurityDescriptor, "ASSIGN DESCRIPTOR\n");
  799. //
  800. // Try to find an existing security descriptor that matches this one.
  801. // If successful, then we don't need to allocate a new cell, we can
  802. // just point to the existing one and increment its reference count.
  803. //
  804. Type = HvGetCellType(Cell);
  805. if (!CmpFindMatchingDescriptorCell( (PCMHIVE)Hive,
  806. SecurityDescriptor,
  807. Type,
  808. &SecurityCell,
  809. NULL)) {
  810. //
  811. // No matching descriptor found, allocate and initialize a new one.
  812. //
  813. SecurityCell = HvAllocateCell(Hive,
  814. SECURITY_CELL_LENGTH(SecurityDescriptor),
  815. Type,
  816. HCELL_NIL);
  817. if (SecurityCell == HCELL_NIL) {
  818. return STATUS_INSUFFICIENT_RESOURCES;
  819. }
  820. //
  821. // Map the security cell
  822. //
  823. Security = (PCM_KEY_SECURITY) HvGetCell(Hive, SecurityCell);
  824. if( Security == NULL ) {
  825. //
  826. // we couldn't map the bin containing this cell
  827. // this shouldn't happen as we just allocated this cell
  828. // (i.e. it should be PINNED into memory at this point)
  829. //
  830. ASSERT( FALSE );
  831. HvFreeCell(Hive, SecurityCell);
  832. return STATUS_INSUFFICIENT_RESOURCES;
  833. }
  834. // release the cell right here as we are holding the reglock exclusive
  835. HvReleaseCell(Hive, SecurityCell);
  836. //
  837. // Initialize the security cell
  838. //
  839. DescriptorLength = RtlLengthSecurityDescriptor(SecurityDescriptor);
  840. Security->Signature = CM_KEY_SECURITY_SIGNATURE;
  841. Security->ReferenceCount = 1;
  842. Security->DescriptorLength = DescriptorLength;
  843. RtlCopyMemory( &(Security->Descriptor),
  844. SecurityDescriptor,
  845. DescriptorLength );
  846. //
  847. // Insert the new security descriptor into the list of security
  848. // cells; takes care of cache too
  849. //
  850. if (!CmpInsertSecurityCellList(Hive,Cell,SecurityCell))
  851. {
  852. HvFreeCell(Hive, SecurityCell);
  853. return STATUS_NO_LOG_SPACE;
  854. }
  855. } else {
  856. //
  857. // Found identical descriptor already existing. Map it in and
  858. // increment its reference count.
  859. //
  860. if (! HvMarkCellDirty(Hive, SecurityCell)) {
  861. return STATUS_NO_LOG_SPACE;
  862. }
  863. Security = (PCM_KEY_SECURITY) HvGetCell(Hive, SecurityCell);
  864. if( Security == NULL ) {
  865. //
  866. // we couldn't map the bin containing this cell
  867. // this shouldn't happen as we just marked the cell dirty
  868. // (dirty means PIN !)
  869. //
  870. ASSERT( FALSE );
  871. return STATUS_INSUFFICIENT_RESOURCES;
  872. }
  873. // release the cell right here as we are holding the reglock exclusive
  874. HvReleaseCell(Hive, SecurityCell);
  875. Security->ReferenceCount += 1;
  876. }
  877. //
  878. // Initialize the reference in the node cell
  879. //
  880. Node->Security = SecurityCell;
  881. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"\tSecurityCell = %lx\n",Node->Security));
  882. return(STATUS_SUCCESS);
  883. }
  884. NTSTATUS
  885. CmpQuerySecurityDescriptorInfo(
  886. IN PCM_KEY_CONTROL_BLOCK kcb,
  887. IN PSECURITY_INFORMATION SecurityInformation,
  888. OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  889. IN OUT PULONG Length,
  890. IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor
  891. )
  892. /*++
  893. Routine Description:
  894. This routine will extract the desired information from the
  895. passed security descriptor and return the information in
  896. the passed buffer as a security descriptor in absolute format.
  897. Arguments:
  898. Key - Supplies a pointer to the CM_KEY_REFERENCE for the node whose
  899. security descriptor will be deleted.
  900. SecurityInformation - Specifies what information is being queried.
  901. SecurityDescriptor - Supplies the buffer to output the requested
  902. information into.
  903. This buffer has been probed only to the size indicated by
  904. the Length parameter. Since it still points into user space,
  905. it must always be accessed in a try clause.
  906. Length - Supplies the address of a variable containing the length of
  907. the security descriptor buffer. Upon return this variable will
  908. contain the length needed to store the requested information.
  909. ObjectsSecurityDescriptor - Supplies the address of a pointer to
  910. the objects security descriptor. The passed security descriptor
  911. must be in self-relative format.
  912. Return Value:
  913. NTSTATUS - STATUS_SUCCESS if successful and an appropriate error value
  914. otherwise
  915. Note:
  916. In the new implementation this function looks just in the security cache
  917. --*/
  918. {
  919. NTSTATUS Status;
  920. PSECURITY_DESCRIPTOR CellSecurityDescriptor;
  921. PAGED_CODE();
  922. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpQuerySecurityDescriptorInfo:\n"));
  923. CellSecurityDescriptor = &(kcb->CachedSecurity->Descriptor);
  924. Status = SeQuerySecurityDescriptorInfo( SecurityInformation,
  925. SecurityDescriptor,
  926. Length,
  927. &CellSecurityDescriptor );
  928. return Status;
  929. }
  930. BOOLEAN
  931. CmpCheckCreateAccess(
  932. IN PUNICODE_STRING RelativeName,
  933. IN PSECURITY_DESCRIPTOR Descriptor,
  934. IN PACCESS_STATE AccessState,
  935. IN KPROCESSOR_MODE PreviousMode,
  936. IN ACCESS_MASK AdditionalAccess,
  937. OUT PNTSTATUS AccessStatus
  938. )
  939. /*++
  940. Routine Description:
  941. This routine checks to see if we are allowed to create a sub-key in the
  942. given key, and performs auditing as appropriate.
  943. Arguments:
  944. RelativeName - Supplies the relative name of the key being created.
  945. Descriptor - Supplies the security descriptor of the key in which
  946. the sub-key is to be created.
  947. CreateAccess - The access mask corresponding to create access for
  948. this directory type.
  949. AccessState - Checks for traverse access will typically be incidental
  950. to some other access attempt. Information on the current state of
  951. that access attempt is required so that the constituent access
  952. attempts may be associated with each other in the audit log.
  953. PreviousMode - The previous processor mode.
  954. AdditionalAccess - access rights in addition to KEY_CREATE_SUB_KEY
  955. that are required. (e.g. KEY_CREATE_LINK)
  956. AccessStatus - Pointer to a variable to return the status code of the
  957. access attempt. In the case of failure this status code must be
  958. propagated back to the user.
  959. Return Value:
  960. BOOLEAN - TRUE if access is allowed and FALSE otherwise. AccessStatus
  961. contains the status code to be passed back to the caller. It is not
  962. correct to simply pass back STATUS_ACCESS_DENIED, since this will have
  963. to change with the advent of mandatory access control.
  964. --*/
  965. {
  966. BOOLEAN AccessAllowed;
  967. ACCESS_MASK GrantedAccess = 0;
  968. BOOLEAN AuditPerformed = FALSE;
  969. PAGED_CODE();
  970. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpCheckCreateAccess:\n"));
  971. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  972. AccessAllowed = SeAccessCheck(
  973. Descriptor,
  974. &AccessState->SubjectSecurityContext,
  975. TRUE, // Token is read locked
  976. (KEY_CREATE_SUB_KEY | AdditionalAccess),
  977. 0,
  978. NULL,
  979. &CmpKeyObjectType->TypeInfo.GenericMapping,
  980. PreviousMode,
  981. &GrantedAccess,
  982. AccessStatus
  983. );
  984. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  985. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"Create access %s\n",AccessAllowed ? "granted" : "denied"));
  986. /*
  987. #if DBG
  988. if (!AccessAllowed) {
  989. CmpDumpSecurityDescriptor(Descriptor, "DENYING DESCRIPTOR");
  990. }
  991. #endif
  992. */
  993. return(AccessAllowed);
  994. }
  995. BOOLEAN
  996. CmpCheckNotifyAccess(
  997. IN PCM_NOTIFY_BLOCK NotifyBlock,
  998. IN PHHIVE Hive,
  999. IN PCM_KEY_NODE Node
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. Check whether the subject process/thread/user specified by the
  1004. security data in the NotifyBlock has required access to the
  1005. key specified by Hive.Cell.
  1006. Arguments:
  1007. NotifyBlock - pointer to structure that describes the notify
  1008. operation, including the identity of the subject
  1009. that opened the notify.
  1010. Hive - Supplies pointer to hive containing Node.
  1011. Node - Supplies pointer to key of interest.
  1012. Return Value:
  1013. TRUE if RequiredAccess is in fact possessed by the subject,
  1014. else FALSE.
  1015. Note:
  1016. In the new implementation get the sd from the security cache.
  1017. --*/
  1018. {
  1019. PCM_KEY_SECURITY Security;
  1020. PSECURITY_DESCRIPTOR SecurityDescriptor;
  1021. BOOLEAN AccessAllowed;
  1022. NTSTATUS Status;
  1023. ACCESS_MASK GrantedAccess = 0;
  1024. ULONG Index;
  1025. PAGED_CODE();
  1026. ASSERT_CM_LOCK_OWNED();
  1027. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpCheckAccessForNotify:\n"));
  1028. if( CmpFindSecurityCellCacheIndex ((PCMHIVE)Hive,Node->Security,&Index) == FALSE ) {
  1029. return FALSE;
  1030. }
  1031. SeLockSubjectContext( &NotifyBlock->SubjectContext );
  1032. SecurityDescriptor = &(((PCMHIVE)Hive)->SecurityCache[Index].CachedSecurity->Descriptor);
  1033. AccessAllowed = SeAccessCheck( SecurityDescriptor,
  1034. &NotifyBlock->SubjectContext,
  1035. TRUE,
  1036. KEY_NOTIFY,
  1037. 0,
  1038. NULL,
  1039. &CmpKeyObjectType->TypeInfo.GenericMapping,
  1040. UserMode,
  1041. &GrantedAccess,
  1042. &Status );
  1043. SeUnlockSubjectContext( &NotifyBlock->SubjectContext );
  1044. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"Notify access %s\n",AccessAllowed ? "granted" : "denied"));
  1045. /*
  1046. #if DBG
  1047. if (!AccessAllowed) {
  1048. CmpDumpSecurityDescriptor(SecurityDescriptor, "DENYING DESCRIPTOR");
  1049. }
  1050. #endif
  1051. */
  1052. return AccessAllowed;
  1053. }
  1054. NTSTATUS
  1055. CmpGetObjectSecurity(
  1056. IN HCELL_INDEX Cell,
  1057. IN PHHIVE Hive,
  1058. OUT PCM_KEY_SECURITY *Security,
  1059. OUT PHCELL_INDEX SecurityCell OPTIONAL
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. This routine maps in the security cell of a registry object.
  1064. Arguments:
  1065. Cell - Supplies the cell index of the object.
  1066. Hive - Supplies the hive the object's cell is in.
  1067. Security - Returns a pointer to the security cell of the object.
  1068. SecurityCell - Returns the index of the security cell
  1069. Return Value:
  1070. NTSTATUS.
  1071. --*/
  1072. {
  1073. HCELL_INDEX CellIndex;
  1074. PCM_KEY_NODE Node;
  1075. PAGED_CODE();
  1076. //
  1077. // Map the node we need to get the security descriptor for
  1078. //
  1079. Node = (PCM_KEY_NODE) HvGetCell(Hive, Cell);
  1080. if( Node == NULL ) {
  1081. //
  1082. // we couldn't map the bin containing this cell
  1083. //
  1084. return STATUS_INSUFFICIENT_RESOURCES;
  1085. }
  1086. #if DBG
  1087. {
  1088. UNICODE_STRING Name;
  1089. Name.MaximumLength = Name.Length = Node->NameLength;
  1090. Name.Buffer = Node->Name;
  1091. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpGetObjectSecurity for: "));
  1092. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"%wZ\n", &Name));
  1093. }
  1094. #endif
  1095. *Security = CmpGetKeySecurity(Hive,Node,SecurityCell);
  1096. HvReleaseCell(Hive, Cell);
  1097. if( *Security == NULL ) {
  1098. //
  1099. // couldn't map view inside
  1100. //
  1101. return STATUS_INSUFFICIENT_RESOURCES;
  1102. }
  1103. return STATUS_SUCCESS;
  1104. }
  1105. PCM_KEY_SECURITY
  1106. CmpGetKeySecurity(
  1107. IN PHHIVE Hive,
  1108. IN PCM_KEY_NODE Key,
  1109. OUT PHCELL_INDEX SecurityCell OPTIONAL
  1110. )
  1111. /*++
  1112. Routine Description:
  1113. This routine returns the security of a registry key.
  1114. Arguments:
  1115. Hive - Supplies the hive the object's cell is in.
  1116. Key - Supplies a pointer to the key node.
  1117. SecurityCell - Returns the index of the security cell
  1118. Return Value:
  1119. Returns a pointer to the security cell of the object
  1120. NULL, if resources problem
  1121. --*/
  1122. {
  1123. HCELL_INDEX CellIndex;
  1124. PCM_KEY_SECURITY Security;
  1125. PAGED_CODE();
  1126. ASSERT(Key->Signature == CM_KEY_NODE_SIGNATURE);
  1127. ASSERT_NODE(Key);
  1128. #if DBG
  1129. {
  1130. UNICODE_STRING Name;
  1131. Name.MaximumLength = Name.Length = Key->NameLength;
  1132. Name.Buffer = Key->Name;
  1133. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpGetObjectSecurity for: "));
  1134. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"%wZ\n", &Name));
  1135. }
  1136. #endif
  1137. CellIndex = Key->Security;
  1138. //
  1139. // Map in the security descriptor cell
  1140. //
  1141. Security = (PCM_KEY_SECURITY) HvGetCell(Hive, CellIndex);
  1142. if( Security == NULL ) {
  1143. //
  1144. // we couldn't map the bin containing this cell
  1145. //
  1146. return NULL;
  1147. }
  1148. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1149. HvReleaseCell(Hive, CellIndex);
  1150. ASSERT_SECURITY(Security);
  1151. if (ARGUMENT_PRESENT(SecurityCell)) {
  1152. *SecurityCell = CellIndex;
  1153. }
  1154. return(Security);
  1155. }
  1156. PSECURITY_DESCRIPTOR
  1157. CmpHiveRootSecurityDescriptor(
  1158. VOID
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. This routine allocates and initializes the default security descriptor
  1163. for a system-created registry key.
  1164. The caller is responsible for freeing the allocated security descriptor
  1165. when he is done with it.
  1166. Arguments:
  1167. None
  1168. Return Value:
  1169. Pointer to an initialized security descriptor if successful.
  1170. Bugcheck otherwise.
  1171. --*/
  1172. {
  1173. NTSTATUS Status;
  1174. PSECURITY_DESCRIPTOR SecurityDescriptor=NULL;
  1175. PACL Acl=NULL;
  1176. PACL AclCopy;
  1177. PSID WorldSid=NULL;
  1178. PSID RestrictedSid=NULL;
  1179. PSID SystemSid=NULL;
  1180. PSID AdminSid=NULL;
  1181. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1182. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1183. ULONG AceLength;
  1184. ULONG AclLength;
  1185. PACE_HEADER AceHeader;
  1186. PAGED_CODE();
  1187. //
  1188. // Allocate and initialize the SIDs we will need.
  1189. //
  1190. WorldSid = ExAllocatePool(PagedPool, RtlLengthRequiredSid(1));
  1191. RestrictedSid = ExAllocatePool(PagedPool, RtlLengthRequiredSid(1));
  1192. SystemSid = ExAllocatePool(PagedPool, RtlLengthRequiredSid(1));
  1193. AdminSid = ExAllocatePool(PagedPool, RtlLengthRequiredSid(2));
  1194. if ((WorldSid == NULL) ||
  1195. (RestrictedSid == NULL) ||
  1196. (SystemSid == NULL) ||
  1197. (AdminSid == NULL)) {
  1198. CM_BUGCHECK(REGISTRY_ERROR, ALLOCATE_SECURITY_DESCRIPTOR, 1, 0, 0);
  1199. }
  1200. if ((!NT_SUCCESS(RtlInitializeSid(WorldSid, &WorldAuthority, 1))) ||
  1201. (!NT_SUCCESS(RtlInitializeSid(RestrictedSid, &NtAuthority, 1))) ||
  1202. (!NT_SUCCESS(RtlInitializeSid(SystemSid, &NtAuthority, 1))) ||
  1203. (!NT_SUCCESS(RtlInitializeSid(AdminSid, &NtAuthority, 2)))) {
  1204. CM_BUGCHECK(REGISTRY_ERROR, ALLOCATE_SECURITY_DESCRIPTOR, 2, 0, 0);
  1205. }
  1206. *(RtlSubAuthoritySid(WorldSid, 0)) = SECURITY_WORLD_RID;
  1207. *(RtlSubAuthoritySid(RestrictedSid, 0)) = SECURITY_RESTRICTED_CODE_RID;
  1208. *(RtlSubAuthoritySid(SystemSid, 0)) = SECURITY_LOCAL_SYSTEM_RID;
  1209. *(RtlSubAuthoritySid(AdminSid, 0)) = SECURITY_BUILTIN_DOMAIN_RID;
  1210. *(RtlSubAuthoritySid(AdminSid, 1)) = DOMAIN_ALIAS_RID_ADMINS;
  1211. ASSERT(RtlValidSid(WorldSid));
  1212. ASSERT(RtlValidSid(RestrictedSid));
  1213. ASSERT(RtlValidSid(SystemSid));
  1214. ASSERT(RtlValidSid(AdminSid));
  1215. //
  1216. // Compute the size of the ACE list
  1217. //
  1218. AceLength = (SeLengthSid(WorldSid) -
  1219. sizeof(ULONG) +
  1220. sizeof(ACCESS_ALLOWED_ACE))
  1221. + (SeLengthSid(RestrictedSid) -
  1222. sizeof(ULONG) +
  1223. sizeof(ACCESS_ALLOWED_ACE))
  1224. + (SeLengthSid(SystemSid) -
  1225. sizeof(ULONG) +
  1226. sizeof(ACCESS_ALLOWED_ACE))
  1227. + (SeLengthSid(AdminSid) -
  1228. sizeof(ULONG) +
  1229. sizeof(ACCESS_ALLOWED_ACE));
  1230. //
  1231. // Allocate and initialize the ACL
  1232. //
  1233. AclLength = AceLength + sizeof(ACL);
  1234. Acl = ExAllocatePool(PagedPool, AclLength);
  1235. if (Acl == NULL) {
  1236. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpHiveRootSecurityDescriptor: couldn't allocate ACL\n"));
  1237. CM_BUGCHECK(REGISTRY_ERROR, ALLOCATE_SECURITY_DESCRIPTOR, 3, 0, 0);
  1238. }
  1239. Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION);
  1240. if (!NT_SUCCESS(Status)) {
  1241. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpHiveRootSecurityDescriptor: couldn't initialize ACL\n"));
  1242. CM_BUGCHECK(REGISTRY_ERROR, ALLOCATE_SECURITY_DESCRIPTOR, 4, Status, 0);
  1243. }
  1244. //
  1245. // Now add the ACEs to the ACL
  1246. //
  1247. Status = RtlAddAccessAllowedAce(Acl,
  1248. ACL_REVISION,
  1249. KEY_ALL_ACCESS,
  1250. SystemSid);
  1251. if (NT_SUCCESS(Status)) {
  1252. Status = RtlAddAccessAllowedAce(Acl,
  1253. ACL_REVISION,
  1254. KEY_ALL_ACCESS,
  1255. AdminSid);
  1256. }
  1257. if (NT_SUCCESS(Status)) {
  1258. Status = RtlAddAccessAllowedAce(Acl,
  1259. ACL_REVISION,
  1260. KEY_READ,
  1261. WorldSid);
  1262. }
  1263. if (NT_SUCCESS(Status)) {
  1264. Status = RtlAddAccessAllowedAce(Acl,
  1265. ACL_REVISION,
  1266. KEY_READ,
  1267. RestrictedSid);
  1268. }
  1269. if (!NT_SUCCESS(Status)) {
  1270. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpHiveRootSecurityDescriptor: RtlAddAce failed status %08lx\n", Status));
  1271. CM_BUGCHECK(REGISTRY_ERROR, ALLOCATE_SECURITY_DESCRIPTOR, 5, Status, 0);
  1272. }
  1273. //
  1274. // Make the ACEs inheritable
  1275. //
  1276. Status = RtlGetAce(Acl,0,&AceHeader);
  1277. ASSERT(NT_SUCCESS(Status));
  1278. AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
  1279. Status = RtlGetAce(Acl,1,&AceHeader);
  1280. ASSERT(NT_SUCCESS(Status));
  1281. AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
  1282. Status = RtlGetAce(Acl,2,&AceHeader);
  1283. ASSERT(NT_SUCCESS(Status));
  1284. AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
  1285. Status = RtlGetAce(Acl,3,&AceHeader);
  1286. ASSERT(NT_SUCCESS(Status));
  1287. AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
  1288. //
  1289. // We are finally ready to allocate and initialize the security descriptor
  1290. // Allocate enough space to hold both the security descriptor and the
  1291. // ACL. This allows us to free the whole thing at once when we are
  1292. // done with it.
  1293. //
  1294. SecurityDescriptor = ExAllocatePool(
  1295. PagedPool,
  1296. sizeof(SECURITY_DESCRIPTOR) + AclLength
  1297. );
  1298. if (SecurityDescriptor == NULL) {
  1299. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpHiveRootSecurityDescriptor: Couldn't allocate Sec. Desc.\n"));
  1300. CM_BUGCHECK(REGISTRY_ERROR, ALLOCATE_SECURITY_DESCRIPTOR, 6, 0, 0);
  1301. }
  1302. AclCopy = (PACL)((PISECURITY_DESCRIPTOR)SecurityDescriptor+1);
  1303. RtlCopyMemory(AclCopy, Acl, AclLength);
  1304. Status = RtlCreateSecurityDescriptor( SecurityDescriptor,
  1305. SECURITY_DESCRIPTOR_REVISION );
  1306. if (!NT_SUCCESS(Status)) {
  1307. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpHiveRootSecurityDescriptor: CreateSecDesc failed %08lx\n",Status));
  1308. ExFreePool(SecurityDescriptor);
  1309. SecurityDescriptor=NULL;
  1310. CM_BUGCHECK(REGISTRY_ERROR, ALLOCATE_SECURITY_DESCRIPTOR, 7, Status, 0);
  1311. }
  1312. Status = RtlSetDaclSecurityDescriptor( SecurityDescriptor,
  1313. TRUE,
  1314. AclCopy,
  1315. FALSE );
  1316. if (!NT_SUCCESS(Status)) {
  1317. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpHiveRootSecurityDescriptor: SetDacl failed %08lx\n",Status));
  1318. ExFreePool(SecurityDescriptor);
  1319. SecurityDescriptor=NULL;
  1320. CM_BUGCHECK(REGISTRY_ERROR, ALLOCATE_SECURITY_DESCRIPTOR, 8, Status, 0);
  1321. }
  1322. //
  1323. // free any allocations we made
  1324. //
  1325. if (WorldSid!=NULL) {
  1326. ExFreePool(WorldSid);
  1327. }
  1328. if (RestrictedSid!=NULL) {
  1329. ExFreePool(RestrictedSid);
  1330. }
  1331. if (SystemSid!=NULL) {
  1332. ExFreePool(SystemSid);
  1333. }
  1334. if (AdminSid!=NULL) {
  1335. ExFreePool(AdminSid);
  1336. }
  1337. if (Acl!=NULL) {
  1338. ExFreePool(Acl);
  1339. }
  1340. return(SecurityDescriptor);
  1341. }
  1342. VOID
  1343. CmpFreeSecurityDescriptor(
  1344. IN PHHIVE Hive,
  1345. IN HCELL_INDEX Cell
  1346. )
  1347. /*++
  1348. Routine Description:
  1349. Frees the security descriptor associated with a particular node. This
  1350. can only happen when the node is actually being deleted from the
  1351. registry.
  1352. NOTE: Caller is expected to have already marked relevent cells dirty.
  1353. Arguments:
  1354. Hive - Supplies thepointer to hive control structure for hive of interest
  1355. Cell - Supplies index for cell to free storage for (the target)
  1356. Return Value:
  1357. None.
  1358. --*/
  1359. {
  1360. PCELL_DATA Node;
  1361. PCELL_DATA Security;
  1362. HCELL_INDEX SecurityCell;
  1363. PAGED_CODE();
  1364. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpFreeSecurityDescriptor for cell %ld\n",Cell));
  1365. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  1366. //
  1367. // Map in the cell whose security descriptor is being freed
  1368. //
  1369. Node = HvGetCell(Hive, Cell);
  1370. if( Node == NULL ) {
  1371. //
  1372. // we couldn't map the bin containing this cell
  1373. // Sorry, we cannot free the descriptor
  1374. return;
  1375. }
  1376. ASSERT_NODE(&(Node->u.KeyNode));
  1377. //
  1378. // Map in the cell containing the security descriptor.
  1379. //
  1380. SecurityCell = Node->u.KeyNode.Security;
  1381. Security = HvGetCell(Hive, SecurityCell);
  1382. if( Security == NULL ) {
  1383. //
  1384. // we couldn't map the bin containing this cell
  1385. // Sorry, we cannot free the descriptor
  1386. HvReleaseCell(Hive, Cell);
  1387. return;
  1388. }
  1389. ASSERT_SECURITY(&(Security->u.KeySecurity));
  1390. if (Security->u.KeySecurity.ReferenceCount == 1) {
  1391. //
  1392. // This is the only cell that references this security descriptor,
  1393. // so it is ok to free it now.
  1394. //
  1395. CmpRemoveSecurityCellList(Hive, SecurityCell);
  1396. HvFreeCell(Hive, SecurityCell);
  1397. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpFreeSecurityDescriptor: freeing security cell\n"));
  1398. } else {
  1399. //
  1400. // More than one node references this security descriptor, so
  1401. // just decrement the reference count.
  1402. //
  1403. Security->u.KeySecurity.ReferenceCount -= 1;
  1404. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpFreeSecurityDescriptor: decrementing reference count\n"));
  1405. }
  1406. //
  1407. // Zero out the pointer to the security descriptdr in the main cell
  1408. //
  1409. Node->u.KeyNode.Security = HCELL_NIL;
  1410. // release the cells
  1411. HvReleaseCell(Hive, Cell);
  1412. HvReleaseCell(Hive, SecurityCell);
  1413. }
  1414. BOOLEAN
  1415. CmpInsertSecurityCellList(
  1416. IN PHHIVE Hive,
  1417. IN HCELL_INDEX NodeCell,
  1418. IN HCELL_INDEX SecurityCell
  1419. )
  1420. /*++
  1421. Routine Description:
  1422. Inserts a newly-created security cell into the per-hive linked list of
  1423. security cells.
  1424. NOTE: Assumes that NodeCell and SecurityCell have already been
  1425. marked dirty.
  1426. Arguments:
  1427. Hive - Supplies a pointer to the hive control structure.
  1428. NodeCell - Supplies the cell index of the node that owns the security cell
  1429. SecurityCell - Supplies the cell index of the security cell.
  1430. Return Value:
  1431. TRUE - it worked
  1432. FALSE - some failure - generally STATUS_NO_LOG_SPACE
  1433. --*/
  1434. {
  1435. PCM_KEY_SECURITY FlinkCell;
  1436. PCM_KEY_SECURITY BlinkCell;
  1437. PCM_KEY_SECURITY Cell;
  1438. PCM_KEY_NODE Node;
  1439. PCM_KEY_NODE ParentNode;
  1440. PAGED_CODE();
  1441. //
  1442. // If the new cell's storage type is Volatile, simply make it the
  1443. // anchor of it's own list. (Volatile security entries will disappear
  1444. // at reboot, restore, etc, so we don't need the list to hunt them
  1445. // down at those times.)
  1446. //
  1447. // Else, the storage type is Stable.
  1448. // Map in the node that owns the new security cell. If it is a root
  1449. // cell, then we are creating the hive for the first time, so this is
  1450. // the only security cell in the list. If it is not a root cell, then
  1451. // we simply find its parent's security cell and stick the new security
  1452. // cell into the list immediately after it.
  1453. //
  1454. //
  1455. // we have the lock exclusive or nobody is operating inside this hive
  1456. //
  1457. //ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1458. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  1459. Cell = (PCM_KEY_SECURITY) HvGetCell(Hive, SecurityCell);
  1460. if( Cell == NULL ) {
  1461. //
  1462. // we couldn't map the bin containing this cell
  1463. //
  1464. return FALSE;
  1465. }
  1466. // release the cell as we hold the reglock exclusive
  1467. HvReleaseCell(Hive, SecurityCell);
  1468. ASSERT_SECURITY(Cell);
  1469. if (HvGetCellType(SecurityCell) == Volatile) {
  1470. Cell->Flink = Cell->Blink = SecurityCell;
  1471. } else {
  1472. Node = (PCM_KEY_NODE) HvGetCell(Hive, NodeCell);
  1473. if( Node == NULL ) {
  1474. //
  1475. // we couldn't map the bin containing this cell
  1476. //
  1477. return FALSE;
  1478. }
  1479. // release the cell as we hold the reglock exclusive
  1480. HvReleaseCell(Hive, NodeCell);
  1481. ASSERT_NODE(Node);
  1482. if (Node->Flags & KEY_HIVE_ENTRY) {
  1483. //
  1484. // This must be the hive creation, so this cell becomes the anchor
  1485. // for the list.
  1486. //
  1487. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpInsertSecurityCellList: hive creation\n"));
  1488. Cell->Flink = Cell->Blink = SecurityCell;
  1489. } else {
  1490. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpInsertSecurityCellList: insert at parent\n"));
  1491. //
  1492. // Map in the node's parent's security cell, so we can hook into
  1493. // the list there.
  1494. //
  1495. ParentNode = (PCM_KEY_NODE) HvGetCell(Hive, Node->Parent);
  1496. if( ParentNode == NULL ) {
  1497. //
  1498. // we couldn't map the bin containing this cell
  1499. //
  1500. return FALSE;
  1501. }
  1502. // release the cell as we hold the reglock exclusive
  1503. HvReleaseCell(Hive, Node->Parent);
  1504. ASSERT_NODE(ParentNode);
  1505. BlinkCell = (PCM_KEY_SECURITY) HvGetCell(
  1506. Hive,
  1507. ParentNode->Security
  1508. );
  1509. if( BlinkCell == NULL ) {
  1510. //
  1511. // we couldn't map the bin containing this cell
  1512. //
  1513. return FALSE;
  1514. }
  1515. // release the cell as we hold the reglock exclusive
  1516. HvReleaseCell(Hive, ParentNode->Security);
  1517. ASSERT_SECURITY(BlinkCell);
  1518. //
  1519. // Map in the Flink of the parent's security cell.
  1520. //
  1521. FlinkCell = (PCM_KEY_SECURITY) HvGetCell(
  1522. Hive,
  1523. BlinkCell->Flink
  1524. );
  1525. if( FlinkCell == NULL ) {
  1526. //
  1527. // we couldn't map the bin containing this cell
  1528. //
  1529. return FALSE;
  1530. }
  1531. // release the cell as we hold the reglock exclusive
  1532. HvReleaseCell(Hive, BlinkCell->Flink);
  1533. ASSERT_SECURITY(FlinkCell);
  1534. if (! (HvMarkCellDirty(Hive, ParentNode->Security) &&
  1535. HvMarkCellDirty(Hive, BlinkCell->Flink)))
  1536. {
  1537. return FALSE;
  1538. }
  1539. //
  1540. // Insert the new security cell in between the Flink and Blink cells
  1541. //
  1542. Cell->Flink = BlinkCell->Flink;
  1543. Cell->Blink = FlinkCell->Blink;
  1544. BlinkCell->Flink = SecurityCell;
  1545. FlinkCell->Blink = SecurityCell;
  1546. }
  1547. }
  1548. //
  1549. // add the new security cell to the hive's security cache
  1550. //
  1551. if( !NT_SUCCESS( CmpAddSecurityCellToCache ( (PCMHIVE)Hive,SecurityCell,FALSE) ) ) {
  1552. return FALSE;
  1553. }
  1554. return TRUE;
  1555. }
  1556. VOID
  1557. CmpRemoveSecurityCellList(
  1558. IN PHHIVE Hive,
  1559. IN HCELL_INDEX SecurityCell
  1560. )
  1561. /*++
  1562. Routine Description:
  1563. Removes a security cell from the per-hive linked list of security cells.
  1564. (This means the cell is going to be deleted!)
  1565. NOTE: Caller is expected to have already marked relevent cells dirty
  1566. Arguments:
  1567. Hive - Supplies a pointer to the hive control structure
  1568. SecurityCell - Supplies the cell index of the security cell to be
  1569. removed
  1570. Return Value:
  1571. None.
  1572. --*/
  1573. {
  1574. PCM_KEY_SECURITY FlinkCell;
  1575. PCM_KEY_SECURITY BlinkCell;
  1576. PCM_KEY_SECURITY Cell;
  1577. PAGED_CODE();
  1578. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpRemoveSecurityCellList: index %ld\n",SecurityCell));
  1579. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  1580. Cell = (PCM_KEY_SECURITY) HvGetCell(Hive, SecurityCell);
  1581. if( Cell == NULL ) {
  1582. //
  1583. // we couldn't map the bin containing one of these cells
  1584. //
  1585. return;
  1586. }
  1587. FlinkCell = (PCM_KEY_SECURITY) HvGetCell(Hive, Cell->Flink);
  1588. if( FlinkCell == NULL ) {
  1589. //
  1590. // we couldn't map the bin containing one of these cells
  1591. //
  1592. HvReleaseCell(Hive, SecurityCell);
  1593. return;
  1594. }
  1595. BlinkCell = (PCM_KEY_SECURITY) HvGetCell(Hive, Cell->Blink);
  1596. if( BlinkCell == NULL ) {
  1597. //
  1598. // we couldn't map the bin containing one of these cells
  1599. //
  1600. HvReleaseCell(Hive, SecurityCell);
  1601. HvReleaseCell(Hive, Cell->Flink);
  1602. return;
  1603. }
  1604. ASSERT(FlinkCell->Blink == SecurityCell);
  1605. ASSERT(BlinkCell->Flink == SecurityCell);
  1606. FlinkCell->Blink = Cell->Blink;
  1607. BlinkCell->Flink = Cell->Flink;
  1608. //
  1609. // finally, remove the security cell from cache, as it'll be freed
  1610. //
  1611. CmpRemoveFromSecurityCache ( (PCMHIVE)Hive,SecurityCell);
  1612. //
  1613. // release used cells
  1614. //
  1615. HvReleaseCell(Hive, Cell->Blink);
  1616. HvReleaseCell(Hive, Cell->Flink);
  1617. HvReleaseCell(Hive, SecurityCell);
  1618. }