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.

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