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.

892 lines
20 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. ULONG 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 Size;
  106. NTSTATUS Status;
  107. ULONG i;
  108. IF_OB_GLOBAL( BREAK_ON_INIT ) {
  109. DbgBreakPoint();
  110. }
  111. //
  112. // Initialize all the list heads and their associated locks.
  113. //
  114. for (i = 0; i < SECURITY_DESCRIPTOR_CACHE_ENTRIES; i++) {
  115. ExInitializePushLock (&ObsSecurityDescriptorCache[i].PushLock);
  116. InitializeListHead (&ObsSecurityDescriptorCache[i].Head);
  117. }
  118. //
  119. // And return to our caller
  120. //
  121. return( STATUS_SUCCESS );
  122. }
  123. ULONG
  124. ObpHashSecurityDescriptor (
  125. PSECURITY_DESCRIPTOR SecurityDescriptor
  126. )
  127. /*++
  128. Routine Description:
  129. Hashes a security descriptor to a 32 bit value
  130. Arguments:
  131. SecurityDescriptor - Provides the security descriptor to be hashed
  132. Return Value:
  133. ULONG - a 32 bit hash value.
  134. --*/
  135. {
  136. ULONG Length;
  137. ULONG Hash;
  138. Length = RtlLengthSecurityDescriptor (SecurityDescriptor);
  139. Hash = ObpHashBuffer (SecurityDescriptor, Length);
  140. return Hash;
  141. }
  142. ULONG
  143. ObpHashBuffer (
  144. PVOID Data,
  145. ULONG Length
  146. )
  147. /*++
  148. Routine Description:
  149. Hashes a buffer into a 32 bit value
  150. Arguments:
  151. Data - Buffer containing the data to be hashed.
  152. Length - The length in bytes of the buffer
  153. Return Value:
  154. ULONG - a 32 bit hash value.
  155. --*/
  156. {
  157. PULONG Buffer, BufferEnd;
  158. PUCHAR Bufferp, BufferEndp;
  159. ULONG Result = 0;
  160. //
  161. // Calculate buffer bounds as byte pointers
  162. //
  163. Bufferp = Data;
  164. BufferEndp = Bufferp + Length;
  165. //
  166. // Calculate buffer bounds as rounded down ULONG pointers
  167. //
  168. Buffer = Data;
  169. BufferEnd = (PULONG)(Bufferp + (Length&~(sizeof (ULONG) - 1)));
  170. //
  171. // Loop over a whole number of ULONGs
  172. //
  173. while (Buffer < BufferEnd) {
  174. Result ^= *Buffer++;
  175. Result = _rotl (Result, 3);
  176. }
  177. //
  178. // Pull in the remaining bytes
  179. //
  180. Bufferp = (PUCHAR) Buffer;
  181. while (Bufferp < BufferEndp) {
  182. Result ^= *Bufferp++;
  183. Result = _rotl (Result, 3);
  184. }
  185. return Result;
  186. }
  187. NTSTATUS
  188. ObLogSecurityDescriptor (
  189. IN PSECURITY_DESCRIPTOR InputSecurityDescriptor,
  190. OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
  191. IN ULONG RefBias
  192. )
  193. /*++
  194. Routine Description:
  195. Takes a passed security descriptor and registers it into the
  196. security descriptor database.
  197. Arguments:
  198. InputSecurityDescriptor - The new security descriptor to be logged into
  199. the database. On a successful return this memory will have been
  200. freed back to pool.
  201. OutputSecurityDescriptor - Output security descriptor to be used by the
  202. caller.
  203. RefBias - Amount to bias the security descriptor reference count by.
  204. Typicaly either 1 or ExFastRefGetAdditionalReferenceCount () + 1,
  205. Return Value:
  206. An appropriate status value
  207. --*/
  208. {
  209. ULONG FullHash;
  210. ULONG Slot;
  211. PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
  212. PLIST_ENTRY Front;
  213. PSECURITY_DESCRIPTOR_HEADER Header;
  214. BOOLEAN Match;
  215. POB_SD_CACHE_LIST Chain;
  216. PETHREAD CurrentThread;
  217. FullHash = ObpHashSecurityDescriptor (InputSecurityDescriptor);
  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. &Header->SecurityDescriptor);
  250. if (Match) {
  251. break;
  252. }
  253. ObPrint (SHOW_COLLISIONS, ("Got a collision on %d, no match\n", Slot));
  254. }
  255. }
  256. //
  257. // If we have a match then we'll get the caller to use the old
  258. // cached descriptor, but bumping its ref count, freeing what
  259. // the caller supplied and returning the old one to our caller
  260. //
  261. if (Match) {
  262. InterlockedExchangeAdd (&Header->RefCount, RefBias);
  263. ObPrint (SHOW_REFERENCES, ("Reference Hash = 0x%lX, New RefCount = %d\n", Header->FullHash, Header->RefCount));
  264. ExReleasePushLock (&Chain->PushLock);
  265. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  266. *OutputSecurityDescriptor = &Header->SecurityDescriptor;
  267. if (NewDescriptor != NULL) {
  268. ExFreePool (NewDescriptor);
  269. }
  270. return STATUS_SUCCESS;
  271. }
  272. if (NewDescriptor == NULL) {
  273. ExReleasePushLockShared (&Chain->PushLock);
  274. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  275. //
  276. // Can't use an existing one, create a new entry
  277. // and insert it into the list.
  278. //
  279. NewDescriptor = ObpCreateCacheEntry (InputSecurityDescriptor,
  280. FullHash,
  281. RefBias);
  282. if (NewDescriptor == NULL) {
  283. return STATUS_INSUFFICIENT_RESOURCES;
  284. }
  285. //
  286. // Reacquire the lock in write mode. We will probably have to insert now
  287. //
  288. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  289. ExAcquirePushLockExclusive (&Chain->PushLock);
  290. } else {
  291. break;
  292. }
  293. } while (1);
  294. #if OB_DIAGNOSTICS_ENABLED
  295. InterlockedIncrement (&ObsTotalCacheEntries);
  296. #endif
  297. ObPrint (SHOW_STATISTICS, ("ObsTotalCacheEntries = %d \n", ObsTotalCacheEntries));
  298. ObPrint (SHOW_COLLISIONS, ("Adding new entry for index #%d \n", Slot));
  299. //
  300. // Insert the entry before the 'Front' entry. If there is no 'Front' entry then this
  301. // is just inserting at the head
  302. //
  303. InsertTailList (Front, &NewDescriptor->Link);
  304. ExReleasePushLockExclusive (&Chain->PushLock);
  305. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  306. //
  307. // Set the output security descriptor and return to our caller
  308. //
  309. *OutputSecurityDescriptor = &NewDescriptor->SecurityDescriptor;
  310. return( STATUS_SUCCESS );
  311. }
  312. PSECURITY_DESCRIPTOR_HEADER
  313. ObpCreateCacheEntry (
  314. PSECURITY_DESCRIPTOR InputSecurityDescriptor,
  315. ULONG FullHash,
  316. ULONG RefBias
  317. )
  318. /*++
  319. Routine Description:
  320. Allocates and initializes a new cache entry.
  321. Arguments:
  322. InputSecurityDescriptor - The security descriptor to be cached.
  323. FullHash - Full 32 bit hash of the security descriptor.
  324. RefBias - Amount to bias the security descriptor reference count by.
  325. Typicaly either 1 or ExFastRefGetAdditionalReferenceCount () + 1,
  326. Return Value:
  327. A pointer to the newly allocated cache entry, or NULL
  328. --*/
  329. {
  330. ULONG SecurityDescriptorLength;
  331. ULONG CacheEntrySize;
  332. PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
  333. //
  334. // Compute the size that we'll need to allocate. We need space for
  335. // the security descriptor cache minus the funny quad at the end and the
  336. // security descriptor itself.
  337. //
  338. SecurityDescriptorLength = RtlLengthSecurityDescriptor (InputSecurityDescriptor);
  339. CacheEntrySize = SecurityDescriptorLength + (sizeof (SECURITY_DESCRIPTOR_HEADER) - sizeof(QUAD));
  340. //
  341. // Now allocate space for the cached entry
  342. //
  343. NewDescriptor = ExAllocatePoolWithTag (PagedPool, CacheEntrySize, 'cSbO');
  344. if (NewDescriptor == NULL) {
  345. return NULL;
  346. }
  347. //
  348. // Fill the header, copy over the descriptor data, and return to our
  349. // caller
  350. //
  351. NewDescriptor->RefCount = RefBias;
  352. NewDescriptor->FullHash = FullHash;
  353. RtlCopyMemory (&NewDescriptor->SecurityDescriptor,
  354. InputSecurityDescriptor,
  355. SecurityDescriptorLength);
  356. return NewDescriptor;
  357. }
  358. VOID
  359. ObReferenceSecurityDescriptor (
  360. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  361. IN ULONG Count
  362. )
  363. /*++
  364. Routine Description:
  365. References the security descriptor.
  366. Arguments:
  367. SecurityDescriptor - Security descriptor inside the cache to reference.
  368. Count - Amount to reference by
  369. Return Value:
  370. None.
  371. --*/
  372. {
  373. PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
  374. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  375. ObPrint( SHOW_REFERENCES, ("Referencing Hash %lX, Refcount = %d \n",SecurityDescriptorHeader->FullHash,
  376. SecurityDescriptorHeader->RefCount));
  377. //
  378. // Increment the reference count
  379. //
  380. InterlockedExchangeAdd (&SecurityDescriptorHeader->RefCount, Count);
  381. }
  382. PSECURITY_DESCRIPTOR
  383. ObpReferenceSecurityDescriptor (
  384. POBJECT_HEADER ObjectHeader
  385. )
  386. /*++
  387. Routine Description:
  388. References the security descriptor of the passed object.
  389. Arguments:
  390. Object - Object being access validated.
  391. Return Value:
  392. The security descriptor of the object.
  393. --*/
  394. {
  395. PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
  396. PSECURITY_DESCRIPTOR SecurityDescriptor;
  397. PEX_FAST_REF FastRef;
  398. EX_FAST_REF OldRef;
  399. ULONG RefsToAdd, Unused;
  400. //
  401. // Attempt the fast reference
  402. //
  403. FastRef = (PEX_FAST_REF) &ObjectHeader->SecurityDescriptor;
  404. OldRef = ExFastReference (FastRef);
  405. SecurityDescriptor = ExFastRefGetObject (OldRef);
  406. //
  407. // See if we can fast reference this security descriptor. Return NULL if there wasn't one
  408. // and go the slow way if there are no more cached references left.
  409. //
  410. Unused = ExFastRefGetUnusedReferences (OldRef);
  411. if (Unused >= 1 || SecurityDescriptor == NULL) {
  412. if (Unused == 1) {
  413. //
  414. // If we took the counter to zero then attempt to make life easier for
  415. // the next referencer by resetting the counter to its max. Since we now
  416. // have a reference to the security descriptor we can do this.
  417. //
  418. RefsToAdd = ExFastRefGetAdditionalReferenceCount ();
  419. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  420. InterlockedExchangeAdd (&SecurityDescriptorHeader->RefCount, RefsToAdd);
  421. //
  422. // Try to add the added references to the cache. If we fail then just
  423. // release them. This dereference can not take the reference count to zero.
  424. //
  425. if (!ExFastRefAddAdditionalReferenceCounts (FastRef, SecurityDescriptor, RefsToAdd)) {
  426. InterlockedExchangeAdd (&SecurityDescriptorHeader->RefCount, -(LONG)RefsToAdd);
  427. }
  428. }
  429. return SecurityDescriptor;
  430. }
  431. ObpLockObjectShared( ObjectHeader );
  432. SecurityDescriptor = ExFastRefGetObject (*FastRef);
  433. IF_OB_GLOBAL( STOP_INVALID_DESCRIPTOR ) {
  434. if(!RtlValidSecurityDescriptor ( SecurityDescriptor )) {
  435. DbgBreakPoint();
  436. }
  437. }
  438. //
  439. // The obejcts security descriptor is not allowed to go fron NON-NULL to NULL.
  440. //
  441. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  442. ObPrint( SHOW_REFERENCES, ("Referencing Hash %lX, Refcount = %d \n",SecurityDescriptorHeader->FullHash,
  443. SecurityDescriptorHeader->RefCount));
  444. //
  445. // Increment the reference count
  446. //
  447. InterlockedIncrement (&SecurityDescriptorHeader->RefCount);
  448. ObpUnlockObject( ObjectHeader );
  449. return( SecurityDescriptor );
  450. }
  451. NTSTATUS
  452. ObDeassignSecurity (
  453. IN OUT PSECURITY_DESCRIPTOR *pSecurityDescriptor
  454. )
  455. /*++
  456. Routine Description:
  457. This routine dereferences the input security descriptor
  458. Arguments:
  459. SecurityDescriptor - Supplies the security descriptor
  460. being modified
  461. Return Value:
  462. Only returns STATUS_SUCCESS
  463. --*/
  464. {
  465. PSECURITY_DESCRIPTOR SecurityDescriptor;
  466. EX_FAST_REF FastRef;
  467. ObPrint( SHOW_DEASSIGN,("Deassigning security descriptor %x\n",*pSecurityDescriptor));
  468. //
  469. // NULL out the SecurityDescriptor in the object's
  470. // header so we don't try to free it again.
  471. //
  472. FastRef = *(PEX_FAST_REF) pSecurityDescriptor;
  473. *pSecurityDescriptor = NULL;
  474. SecurityDescriptor = ExFastRefGetObject (FastRef);
  475. ObDereferenceSecurityDescriptor (SecurityDescriptor, ExFastRefGetUnusedReferences (FastRef) + 1);
  476. return STATUS_SUCCESS;
  477. }
  478. VOID
  479. ObDereferenceSecurityDescriptor (
  480. PSECURITY_DESCRIPTOR SecurityDescriptor,
  481. ULONG Count
  482. )
  483. /*++
  484. Routine Description:
  485. Decrements the refcount of a cached security descriptor
  486. Arguments:
  487. SecurityDescriptor - Points to a cached security descriptor
  488. Return Value:
  489. None.
  490. --*/
  491. {
  492. PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
  493. PVOID PoolToFree;
  494. LONG OldValue, NewValue;
  495. POB_SD_CACHE_LIST Chain;
  496. PETHREAD CurrentThread;
  497. ULONG Slot;
  498. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  499. //
  500. // First see if its possible to do a non-zero transition lock free.
  501. //
  502. OldValue = SecurityDescriptorHeader->RefCount;
  503. //
  504. // If the old value is equal to the decrement then we will be the deleter of this block. We need the lock for that
  505. //
  506. while (OldValue != Count) {
  507. NewValue = InterlockedCompareExchange (&SecurityDescriptorHeader->RefCount, OldValue - Count, OldValue);
  508. if (NewValue == OldValue) {
  509. return;
  510. }
  511. OldValue = NewValue;
  512. }
  513. //
  514. // Lock the security descriptor cache and get a pointer
  515. // to the security descriptor header
  516. //
  517. Slot = SecurityDescriptorHeader->FullHash % SECURITY_DESCRIPTOR_CACHE_ENTRIES;
  518. Chain = &ObsSecurityDescriptorCache[Slot];
  519. CurrentThread = PsGetCurrentThread ();
  520. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  521. ExAcquirePushLockExclusive (&Chain->PushLock);
  522. //
  523. // Do some debug work
  524. //
  525. ObPrint( SHOW_REFERENCES, ("Dereferencing SecurityDescriptor %x, hash %lx, refcount = %d \n", SecurityDescriptor,
  526. SecurityDescriptorHeader->FullHash,
  527. SecurityDescriptorHeader->RefCount));
  528. ASSERT(SecurityDescriptorHeader->RefCount != 0);
  529. //
  530. // Decrement the ref count and if it is now zero then
  531. // we can completely remove this entry from the cache
  532. //
  533. if (InterlockedExchangeAdd (&SecurityDescriptorHeader->RefCount, -(LONG)Count) == Count) {
  534. PoolToFree = ObpDestroySecurityDescriptorHeader (SecurityDescriptorHeader);
  535. //
  536. // Unlock the security descriptor cache and free the pool
  537. //
  538. ExReleasePushLockExclusive (&Chain->PushLock);
  539. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  540. ExFreePool (PoolToFree);
  541. } else {
  542. //
  543. // Unlock the security descriptor cache and return to our caller
  544. //
  545. ExReleasePushLockExclusive (&Chain->PushLock);
  546. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  547. }
  548. }
  549. PVOID
  550. ObpDestroySecurityDescriptorHeader (
  551. IN PSECURITY_DESCRIPTOR_HEADER Header
  552. )
  553. /*++
  554. Routine Description:
  555. Frees a cached security descriptor and unlinks it from the chain.
  556. Arguments:
  557. Header - Pointer to a security descriptor header (cached security
  558. descriptor)
  559. Return Value:
  560. None.
  561. --*/
  562. {
  563. ASSERT ( Header->RefCount == 0 );
  564. #if OB_DIAGNOSTICS_ENABLED
  565. InterlockedDecrement (&ObsTotalCacheEntries);
  566. #endif
  567. ObPrint( SHOW_STATISTICS, ("ObsTotalCacheEntries = %d \n",ObsTotalCacheEntries));
  568. //
  569. // Unlink the cached security descriptor from its linked list
  570. //
  571. RemoveEntryList (&Header->Link);
  572. ObPrint( SHOW_HEADER_FREE, ("Freeing memory at %x \n",Header));
  573. //
  574. // Now return the cached descriptor to our caller to free
  575. //
  576. return Header;
  577. }
  578. BOOLEAN
  579. ObpCompareSecurityDescriptors (
  580. IN PSECURITY_DESCRIPTOR SD1,
  581. IN PSECURITY_DESCRIPTOR SD2
  582. )
  583. /*++
  584. Routine Description:
  585. Performs a byte by byte comparison of two self relative security
  586. descriptors to determine if they are identical.
  587. Arguments:
  588. SD1, SD2 - Security descriptors to be compared.
  589. Return Value:
  590. TRUE - They are the same.
  591. FALSE - They are different.
  592. --*/
  593. {
  594. ULONG Length1;
  595. ULONG Length2;
  596. ULONG Compare;
  597. //
  598. // Calculating the length is pretty fast, see if we
  599. // can get away with doing only that.
  600. //
  601. Length1 = RtlLengthSecurityDescriptor ( SD1 );
  602. Length2 = RtlLengthSecurityDescriptor ( SD2 );
  603. if (Length1 != Length2) {
  604. return( FALSE );
  605. }
  606. return (BOOLEAN)RtlEqualMemory ( SD1, SD2, Length1 );
  607. }