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.

898 lines
21 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. obsdata.c
  5. Abstract:
  6. Object Manager Security Descriptor Caching
  7. Author:
  8. Robert Reichel (robertre) 12-Oct-1993
  9. Revision History:
  10. Neill Clift (NeillC) 16-Nov-2000
  11. General cleanup. Don't free/allocate pool under locks. Don't do unaligned fetches during hashing.
  12. Reduce lock contention etc. Add fast referencing of security descriptor.
  13. --*/
  14. #include "obp.h"
  15. #if DBG
  16. #define OB_DIAGNOSTICS_ENABLED 1
  17. #endif // DBG
  18. //
  19. // These definitions are useful diagnostics aids
  20. //
  21. #if OB_DIAGNOSTICS_ENABLED
  22. //
  23. // Test for enabled diagnostic
  24. //
  25. #define IF_OB_GLOBAL( FlagName ) if (ObsDebugFlags & (OBS_DEBUG_##FlagName))
  26. //
  27. // Diagnostics print statement
  28. //
  29. #define ObPrint( FlagName, _Text_ ) IF_OB_GLOBAL( FlagName ) DbgPrint _Text_
  30. #else
  31. //
  32. // diagnostics not enabled - No diagnostics included in build
  33. //
  34. //
  35. // Test for diagnostics enabled
  36. //
  37. #define IF_OB_GLOBAL( FlagName ) if (FALSE)
  38. //
  39. // Diagnostics print statement (expands to no-op)
  40. //
  41. #define ObPrint( FlagName, _Text_ ) ;
  42. #endif // OB_DIAGNOSTICS_ENABLED
  43. //
  44. // The following flags enable or disable various diagnostic
  45. // capabilities within OB code. These flags are set in
  46. // ObGlobalFlag (only available within a DBG system).
  47. //
  48. //
  49. #define OBS_DEBUG_ALLOC_TRACKING ((ULONG) 0x00000001L)
  50. #define OBS_DEBUG_CACHE_FREES ((ULONG) 0x00000002L)
  51. #define OBS_DEBUG_BREAK_ON_INIT ((ULONG) 0x00000004L)
  52. #define OBS_DEBUG_SHOW_COLLISIONS ((ULONG) 0x00000008L)
  53. #define OBS_DEBUG_SHOW_STATISTICS ((ULONG) 0x00000010L)
  54. #define OBS_DEBUG_SHOW_REFERENCES ((ULONG) 0x00000020L)
  55. #define OBS_DEBUG_SHOW_DEASSIGN ((ULONG) 0x00000040L)
  56. #define OBS_DEBUG_STOP_INVALID_DESCRIPTOR ((ULONG) 0x00000080L)
  57. #define OBS_DEBUG_SHOW_HEADER_FREE ((ULONG) 0x00000100L)
  58. //
  59. // Define struct of single hash clash chain
  60. //
  61. typedef struct _OB_SD_CACHE_LIST {
  62. EX_PUSH_LOCK PushLock;
  63. LIST_ENTRY Head;
  64. } OB_SD_CACHE_LIST, *POB_SD_CACHE_LIST;
  65. //
  66. // Array of pointers to security descriptor entries
  67. //
  68. #ifdef ALLOC_DATA_PRAGMA
  69. #pragma data_seg("PAGEDATA")
  70. #endif
  71. OB_SD_CACHE_LIST ObsSecurityDescriptorCache[SECURITY_DESCRIPTOR_CACHE_ENTRIES];
  72. #if OB_DIAGNOSTICS_ENABLED
  73. LONG ObsTotalCacheEntries = 0;
  74. ULONG ObsDebugFlags = 0;
  75. #endif
  76. #ifdef ALLOC_DATA_PRAGMA
  77. #pragma data_seg()
  78. #endif
  79. #if defined (ALLOC_PRAGMA)
  80. #pragma alloc_text(INIT,ObpInitSecurityDescriptorCache)
  81. #pragma alloc_text(PAGE,ObpHashSecurityDescriptor)
  82. #pragma alloc_text(PAGE,ObpHashBuffer)
  83. #pragma alloc_text(PAGE,ObLogSecurityDescriptor)
  84. #pragma alloc_text(PAGE,ObpCreateCacheEntry)
  85. #pragma alloc_text(PAGE,ObpReferenceSecurityDescriptor)
  86. #pragma alloc_text(PAGE,ObDeassignSecurity)
  87. #pragma alloc_text(PAGE,ObDereferenceSecurityDescriptor)
  88. #pragma alloc_text(PAGE,ObpDestroySecurityDescriptorHeader)
  89. #pragma alloc_text(PAGE,ObpCompareSecurityDescriptors)
  90. #pragma alloc_text(PAGE,ObReferenceSecurityDescriptor)
  91. #endif
  92. NTSTATUS
  93. ObpInitSecurityDescriptorCache (
  94. VOID
  95. )
  96. /*++
  97. Routine Description:
  98. Allocates and initializes the globalSecurity Descriptor Cache
  99. Arguments:
  100. None
  101. Return Value:
  102. STATUS_SUCCESS on success, NTSTATUS on failure.
  103. --*/
  104. {
  105. ULONG i;
  106. IF_OB_GLOBAL( BREAK_ON_INIT ) {
  107. DbgBreakPoint();
  108. }
  109. //
  110. // Initialize all the list heads and their associated locks.
  111. //
  112. for (i = 0; i < SECURITY_DESCRIPTOR_CACHE_ENTRIES; i++) {
  113. ExInitializePushLock (&ObsSecurityDescriptorCache[i].PushLock);
  114. InitializeListHead (&ObsSecurityDescriptorCache[i].Head);
  115. }
  116. //
  117. // And return to our caller
  118. //
  119. return( STATUS_SUCCESS );
  120. }
  121. ULONG
  122. ObpHashSecurityDescriptor (
  123. PSECURITY_DESCRIPTOR SecurityDescriptor,
  124. ULONG Length
  125. )
  126. /*++
  127. Routine Description:
  128. Hashes a security descriptor to a 32 bit value
  129. Arguments:
  130. SecurityDescriptor - Provides the security descriptor to be hashed
  131. Length - Length of security descriptor
  132. Return Value:
  133. ULONG - a 32 bit hash value.
  134. --*/
  135. {
  136. ULONG Hash;
  137. Hash = ObpHashBuffer (SecurityDescriptor, Length);
  138. return Hash;
  139. }
  140. ULONG
  141. ObpHashBuffer (
  142. PVOID Data,
  143. ULONG Length
  144. )
  145. /*++
  146. Routine Description:
  147. Hashes a buffer into a 32 bit value
  148. Arguments:
  149. Data - Buffer containing the data to be hashed.
  150. Length - The length in bytes of the buffer
  151. Return Value:
  152. ULONG - a 32 bit hash value.
  153. --*/
  154. {
  155. PULONG Buffer, BufferEnd;
  156. PUCHAR Bufferp, BufferEndp;
  157. ULONG Result = 0;
  158. //
  159. // Calculate buffer bounds as byte pointers
  160. //
  161. Bufferp = Data;
  162. BufferEndp = Bufferp + Length;
  163. //
  164. // Calculate buffer bounds as rounded down ULONG pointers
  165. //
  166. Buffer = Data;
  167. BufferEnd = (PULONG)(Bufferp + (Length&~(sizeof (ULONG) - 1)));
  168. //
  169. // Loop over a whole number of ULONGs
  170. //
  171. while (Buffer < BufferEnd) {
  172. Result ^= *Buffer++;
  173. Result = _rotl (Result, 3);
  174. }
  175. //
  176. // Pull in the remaining bytes
  177. //
  178. Bufferp = (PUCHAR) Buffer;
  179. while (Bufferp < BufferEndp) {
  180. Result ^= *Bufferp++;
  181. Result = _rotl (Result, 3);
  182. }
  183. return Result;
  184. }
  185. NTSTATUS
  186. ObLogSecurityDescriptor (
  187. IN PSECURITY_DESCRIPTOR InputSecurityDescriptor,
  188. OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
  189. IN ULONG RefBias
  190. )
  191. /*++
  192. Routine Description:
  193. Takes a passed security descriptor and registers it into the
  194. security descriptor database.
  195. Arguments:
  196. InputSecurityDescriptor - The new security descriptor to be logged into
  197. the database. On a successful return this memory will have been
  198. freed back to pool.
  199. OutputSecurityDescriptor - Output security descriptor to be used by the
  200. caller.
  201. RefBias - Amount to bias the security descriptor reference count by.
  202. Typicaly either 1 or ExFastRefGetAdditionalReferenceCount () + 1,
  203. Return Value:
  204. An appropriate status value
  205. --*/
  206. {
  207. ULONG FullHash;
  208. ULONG Slot;
  209. PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
  210. PLIST_ENTRY Front;
  211. PSECURITY_DESCRIPTOR_HEADER Header = NULL;
  212. BOOLEAN Match;
  213. POB_SD_CACHE_LIST Chain;
  214. PETHREAD CurrentThread;
  215. ULONG Length;
  216. Length = RtlLengthSecurityDescriptor (InputSecurityDescriptor);
  217. FullHash = ObpHashSecurityDescriptor (InputSecurityDescriptor, Length);
  218. Slot = FullHash % SECURITY_DESCRIPTOR_CACHE_ENTRIES;
  219. NewDescriptor = NULL;
  220. //
  221. // First lock the table for read access. We will change this to write if we have to insert later
  222. //
  223. Chain = &ObsSecurityDescriptorCache[Slot];
  224. CurrentThread = PsGetCurrentThread ();
  225. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  226. ExAcquirePushLockShared (&Chain->PushLock);
  227. do {
  228. //
  229. // See if the list for this slot is in use.
  230. // Lock the table first, unlock if if we don't need it.
  231. //
  232. Match = FALSE;
  233. //
  234. // Zoom down the hash bucket looking for a full hash match
  235. //
  236. for (Front = Chain->Head.Flink;
  237. Front != &Chain->Head;
  238. Front = Front->Flink) {
  239. Header = LINK_TO_SD_HEADER (Front);
  240. //
  241. // The list is ordered by full hash value and is maintained this way by virtue
  242. // of the fact that we use the 'Back' variable for the insert.
  243. //
  244. if (Header->FullHash > FullHash) {
  245. break;
  246. }
  247. if (Header->FullHash == FullHash) {
  248. Match = ObpCompareSecurityDescriptors (InputSecurityDescriptor,
  249. Length,
  250. &Header->SecurityDescriptor);
  251. if (Match) {
  252. break;
  253. }
  254. ObPrint (SHOW_COLLISIONS, ("Got a collision on %d, no match\n", Slot));
  255. }
  256. }
  257. //
  258. // If we have a match then we'll get the caller to use the old
  259. // cached descriptor, but bumping its ref count, freeing what
  260. // the caller supplied and returning the old one to our caller
  261. //
  262. if (Match) {
  263. InterlockedExchangeAdd ((PLONG)&Header->RefCount, RefBias);
  264. ObPrint (SHOW_REFERENCES, ("Reference Hash = 0x%lX, New RefCount = %d\n", Header->FullHash, Header->RefCount));
  265. ExReleasePushLock (&Chain->PushLock);
  266. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  267. *OutputSecurityDescriptor = &Header->SecurityDescriptor;
  268. if (NewDescriptor != NULL) {
  269. ExFreePool (NewDescriptor);
  270. }
  271. return STATUS_SUCCESS;
  272. }
  273. if (NewDescriptor == NULL) {
  274. ExReleasePushLockShared (&Chain->PushLock);
  275. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  276. //
  277. // Can't use an existing one, create a new entry
  278. // and insert it into the list.
  279. //
  280. NewDescriptor = ObpCreateCacheEntry (InputSecurityDescriptor,
  281. Length,
  282. FullHash,
  283. RefBias);
  284. if (NewDescriptor == NULL) {
  285. return STATUS_INSUFFICIENT_RESOURCES;
  286. }
  287. //
  288. // Reacquire the lock in write mode. We will probably have to insert now
  289. //
  290. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  291. ExAcquirePushLockExclusive (&Chain->PushLock);
  292. } else {
  293. break;
  294. }
  295. } while (1);
  296. #if OB_DIAGNOSTICS_ENABLED
  297. InterlockedIncrement (&ObsTotalCacheEntries);
  298. #endif
  299. ObPrint (SHOW_STATISTICS, ("ObsTotalCacheEntries = %d \n", ObsTotalCacheEntries));
  300. ObPrint (SHOW_COLLISIONS, ("Adding new entry for index #%d \n", Slot));
  301. //
  302. // Insert the entry before the 'Front' entry. If there is no 'Front' entry then this
  303. // is just inserting at the head
  304. //
  305. InsertTailList (Front, &NewDescriptor->Link);
  306. ExReleasePushLockExclusive (&Chain->PushLock);
  307. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  308. //
  309. // Set the output security descriptor and return to our caller
  310. //
  311. *OutputSecurityDescriptor = &NewDescriptor->SecurityDescriptor;
  312. return( STATUS_SUCCESS );
  313. }
  314. PSECURITY_DESCRIPTOR_HEADER
  315. ObpCreateCacheEntry (
  316. PSECURITY_DESCRIPTOR InputSecurityDescriptor,
  317. ULONG SecurityDescriptorLength,
  318. ULONG FullHash,
  319. ULONG RefBias
  320. )
  321. /*++
  322. Routine Description:
  323. Allocates and initializes a new cache entry.
  324. Arguments:
  325. InputSecurityDescriptor - The security descriptor to be cached.
  326. Length - Length of security descriptor
  327. FullHash - Full 32 bit hash of the security descriptor.
  328. RefBias - Amount to bias the security descriptor reference count by.
  329. Typicaly either 1 or ExFastRefGetAdditionalReferenceCount () + 1,
  330. Return Value:
  331. A pointer to the newly allocated cache entry, or NULL
  332. --*/
  333. {
  334. ULONG CacheEntrySize;
  335. PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
  336. //
  337. // Compute the size that we'll need to allocate. We need space for
  338. // the security descriptor cache minus the funny quad at the end and the
  339. // security descriptor itself.
  340. //
  341. ASSERT (SecurityDescriptorLength == RtlLengthSecurityDescriptor (InputSecurityDescriptor));
  342. CacheEntrySize = SecurityDescriptorLength + (sizeof (SECURITY_DESCRIPTOR_HEADER) - sizeof(QUAD));
  343. //
  344. // Now allocate space for the cached entry
  345. //
  346. NewDescriptor = ExAllocatePoolWithTag (PagedPool, CacheEntrySize, 'cSbO');
  347. if (NewDescriptor == NULL) {
  348. return NULL;
  349. }
  350. //
  351. // Fill the header, copy over the descriptor data, and return to our
  352. // caller
  353. //
  354. NewDescriptor->RefCount = RefBias;
  355. NewDescriptor->FullHash = FullHash;
  356. RtlCopyMemory (&NewDescriptor->SecurityDescriptor,
  357. InputSecurityDescriptor,
  358. SecurityDescriptorLength);
  359. return NewDescriptor;
  360. }
  361. VOID
  362. ObReferenceSecurityDescriptor (
  363. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  364. IN ULONG Count
  365. )
  366. /*++
  367. Routine Description:
  368. References the security descriptor.
  369. Arguments:
  370. SecurityDescriptor - Security descriptor inside the cache to reference.
  371. Count - Amount to reference by
  372. Return Value:
  373. None.
  374. --*/
  375. {
  376. PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
  377. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  378. ObPrint( SHOW_REFERENCES, ("Referencing Hash %lX, Refcount = %d \n",SecurityDescriptorHeader->FullHash,
  379. SecurityDescriptorHeader->RefCount));
  380. //
  381. // Increment the reference count
  382. //
  383. InterlockedExchangeAdd ((PLONG)&SecurityDescriptorHeader->RefCount, Count);
  384. }
  385. PSECURITY_DESCRIPTOR
  386. ObpReferenceSecurityDescriptor (
  387. POBJECT_HEADER ObjectHeader
  388. )
  389. /*++
  390. Routine Description:
  391. References the security descriptor of the passed object.
  392. Arguments:
  393. Object - Object being access validated.
  394. Return Value:
  395. The security descriptor of the object.
  396. --*/
  397. {
  398. PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
  399. PSECURITY_DESCRIPTOR SecurityDescriptor;
  400. PEX_FAST_REF FastRef;
  401. EX_FAST_REF OldRef;
  402. ULONG RefsToAdd, Unused;
  403. //
  404. // Attempt the fast reference
  405. //
  406. FastRef = (PEX_FAST_REF) &ObjectHeader->SecurityDescriptor;
  407. OldRef = ExFastReference (FastRef);
  408. SecurityDescriptor = ExFastRefGetObject (OldRef);
  409. //
  410. // See if we can fast reference this security descriptor. Return NULL if there wasn't one
  411. // and go the slow way if there are no more cached references left.
  412. //
  413. Unused = ExFastRefGetUnusedReferences (OldRef);
  414. if (Unused >= 1 || SecurityDescriptor == NULL) {
  415. if (Unused == 1) {
  416. //
  417. // If we took the counter to zero then attempt to make life easier for
  418. // the next referencer by resetting the counter to its max. Since we now
  419. // have a reference to the security descriptor we can do this.
  420. //
  421. RefsToAdd = ExFastRefGetAdditionalReferenceCount ();
  422. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  423. InterlockedExchangeAdd ((PLONG)&SecurityDescriptorHeader->RefCount, RefsToAdd);
  424. //
  425. // Try to add the added references to the cache. If we fail then just
  426. // release them. This dereference can not take the reference count to zero.
  427. //
  428. if (!ExFastRefAddAdditionalReferenceCounts (FastRef, SecurityDescriptor, RefsToAdd)) {
  429. InterlockedExchangeAdd ((PLONG)&SecurityDescriptorHeader->RefCount, -(LONG)RefsToAdd);
  430. }
  431. }
  432. return SecurityDescriptor;
  433. }
  434. ObpLockObjectShared( ObjectHeader );
  435. SecurityDescriptor = ExFastRefGetObject (*FastRef);
  436. IF_OB_GLOBAL( STOP_INVALID_DESCRIPTOR ) {
  437. if(!RtlValidSecurityDescriptor ( SecurityDescriptor )) {
  438. DbgBreakPoint();
  439. }
  440. }
  441. //
  442. // The obejcts security descriptor is not allowed to go fron NON-NULL to NULL.
  443. //
  444. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  445. ObPrint( SHOW_REFERENCES, ("Referencing Hash %lX, Refcount = %d \n",SecurityDescriptorHeader->FullHash,
  446. SecurityDescriptorHeader->RefCount));
  447. //
  448. // Increment the reference count
  449. //
  450. InterlockedIncrement ((PLONG) &SecurityDescriptorHeader->RefCount);
  451. ObpUnlockObject( ObjectHeader );
  452. return( SecurityDescriptor );
  453. }
  454. NTSTATUS
  455. ObDeassignSecurity (
  456. IN OUT PSECURITY_DESCRIPTOR *pSecurityDescriptor
  457. )
  458. /*++
  459. Routine Description:
  460. This routine dereferences the input security descriptor
  461. Arguments:
  462. SecurityDescriptor - Supplies the security descriptor
  463. being modified
  464. Return Value:
  465. Only returns STATUS_SUCCESS
  466. --*/
  467. {
  468. PSECURITY_DESCRIPTOR SecurityDescriptor;
  469. EX_FAST_REF FastRef;
  470. ObPrint( SHOW_DEASSIGN,("Deassigning security descriptor %x\n",*pSecurityDescriptor));
  471. //
  472. // NULL out the SecurityDescriptor in the object's
  473. // header so we don't try to free it again.
  474. //
  475. FastRef = *(PEX_FAST_REF) pSecurityDescriptor;
  476. *pSecurityDescriptor = NULL;
  477. SecurityDescriptor = ExFastRefGetObject (FastRef);
  478. ObDereferenceSecurityDescriptor (SecurityDescriptor, ExFastRefGetUnusedReferences (FastRef) + 1);
  479. return STATUS_SUCCESS;
  480. }
  481. VOID
  482. ObDereferenceSecurityDescriptor (
  483. PSECURITY_DESCRIPTOR SecurityDescriptor,
  484. ULONG Count
  485. )
  486. /*++
  487. Routine Description:
  488. Decrements the refcount of a cached security descriptor
  489. Arguments:
  490. SecurityDescriptor - Points to a cached security descriptor
  491. Return Value:
  492. None.
  493. --*/
  494. {
  495. PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
  496. PVOID PoolToFree;
  497. LONG OldValue, NewValue;
  498. POB_SD_CACHE_LIST Chain;
  499. PETHREAD CurrentThread;
  500. ULONG Slot;
  501. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  502. //
  503. // First see if its possible to do a non-zero transition lock free.
  504. //
  505. OldValue = SecurityDescriptorHeader->RefCount;
  506. //
  507. // If the old value is equal to the decrement then we will be the deleter of this block. We need the lock for that
  508. //
  509. while (OldValue != (LONG) Count) {
  510. NewValue = InterlockedCompareExchange ((PLONG)&SecurityDescriptorHeader->RefCount, OldValue - Count, OldValue);
  511. if (NewValue == OldValue) {
  512. return;
  513. }
  514. OldValue = NewValue;
  515. }
  516. //
  517. // Lock the security descriptor cache and get a pointer
  518. // to the security descriptor header
  519. //
  520. Slot = SecurityDescriptorHeader->FullHash % SECURITY_DESCRIPTOR_CACHE_ENTRIES;
  521. Chain = &ObsSecurityDescriptorCache[Slot];
  522. CurrentThread = PsGetCurrentThread ();
  523. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  524. ExAcquirePushLockExclusive (&Chain->PushLock);
  525. //
  526. // Do some debug work
  527. //
  528. ObPrint( SHOW_REFERENCES, ("Dereferencing SecurityDescriptor %x, hash %lx, refcount = %d \n", SecurityDescriptor,
  529. SecurityDescriptorHeader->FullHash,
  530. SecurityDescriptorHeader->RefCount));
  531. ASSERT(SecurityDescriptorHeader->RefCount != 0);
  532. //
  533. // Decrement the ref count and if it is now zero then
  534. // we can completely remove this entry from the cache
  535. //
  536. if (InterlockedExchangeAdd ((PLONG)&SecurityDescriptorHeader->RefCount, -(LONG)Count) == (LONG)Count) {
  537. PoolToFree = ObpDestroySecurityDescriptorHeader (SecurityDescriptorHeader);
  538. //
  539. // Unlock the security descriptor cache and free the pool
  540. //
  541. ExReleasePushLockExclusive (&Chain->PushLock);
  542. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  543. ExFreePool (PoolToFree);
  544. } else {
  545. //
  546. // Unlock the security descriptor cache and return to our caller
  547. //
  548. ExReleasePushLockExclusive (&Chain->PushLock);
  549. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  550. }
  551. }
  552. PVOID
  553. ObpDestroySecurityDescriptorHeader (
  554. IN PSECURITY_DESCRIPTOR_HEADER Header
  555. )
  556. /*++
  557. Routine Description:
  558. Frees a cached security descriptor and unlinks it from the chain.
  559. Arguments:
  560. Header - Pointer to a security descriptor header (cached security
  561. descriptor)
  562. Return Value:
  563. None.
  564. --*/
  565. {
  566. ASSERT ( Header->RefCount == 0 );
  567. #if OB_DIAGNOSTICS_ENABLED
  568. InterlockedDecrement (&ObsTotalCacheEntries);
  569. #endif
  570. ObPrint( SHOW_STATISTICS, ("ObsTotalCacheEntries = %d \n",ObsTotalCacheEntries));
  571. //
  572. // Unlink the cached security descriptor from its linked list
  573. //
  574. RemoveEntryList (&Header->Link);
  575. ObPrint( SHOW_HEADER_FREE, ("Freeing memory at %x \n",Header));
  576. //
  577. // Now return the cached descriptor to our caller to free
  578. //
  579. return Header;
  580. }
  581. BOOLEAN
  582. ObpCompareSecurityDescriptors (
  583. IN PSECURITY_DESCRIPTOR SD1,
  584. IN ULONG Length1,
  585. IN PSECURITY_DESCRIPTOR SD2
  586. )
  587. /*++
  588. Routine Description:
  589. Performs a byte by byte comparison of two self relative security
  590. descriptors to determine if they are identical.
  591. Arguments:
  592. SD1, SD2 - Security descriptors to be compared.
  593. Length1 - Length of SD1
  594. Return Value:
  595. TRUE - They are the same.
  596. FALSE - They are different.
  597. --*/
  598. {
  599. ULONG Length2;
  600. //
  601. // Calculating the length is pretty fast, see if we
  602. // can get away with doing only that.
  603. //
  604. ASSERT (Length1 == RtlLengthSecurityDescriptor ( SD1 ));
  605. Length2 = RtlLengthSecurityDescriptor ( SD2 );
  606. if (Length1 != Length2) {
  607. return( FALSE );
  608. }
  609. return (BOOLEAN)RtlEqualMemory ( SD1, SD2, Length1 );
  610. }