- Rewrite the SD Cache functions to use the Windows 2003 structures (thanks to Alex for providing them).

- Use pushlocks instead of the fast mutex that was previously used.
- Improve the performance of some paths by reducing lock acquisition time, and using atomic operations instead when possible.
- Implement the exported Ob APIs which were added in Windows XP to access the Sd cache (ObReference/DereferenceSecurityDescriptor and ObLogSecurityDescriptor). These are used by file systems (such as NPFS) on Windows XP and higher.

svn path=/trunk/; revision=32814
This commit is contained in:
Aleksey Bragin 2008-04-01 21:09:28 +00:00
parent 1417fd5fa6
commit 007702fce4
5 changed files with 534 additions and 463 deletions

View file

@ -82,6 +82,18 @@
#define ObpGetHandleObject(x) \
((POBJECT_HEADER)((ULONG_PTR)x->Object & ~OBJ_HANDLE_ATTRIBUTES))
//
// Recovers the security descriptor from a cached security descriptor header
//
#define ObpGetHeaderForSd(x) \
CONTAINING_RECORD((x), SECURITY_DESCRIPTOR_HEADER, SecurityDescriptor)
//
// Recovers the security descriptor from a cached security descriptor list entry
//
#define ObpGetHeaderForEntry(x) \
CONTAINING_RECORD((x), SECURITY_DESCRIPTOR_HEADER, Link)
//
// Context Structures for Ex*Handle Callbacks
//
@ -90,11 +102,13 @@ typedef struct _OBP_SET_HANDLE_ATTRIBUTES_CONTEXT
KPROCESSOR_MODE PreviousMode;
OBJECT_HANDLE_ATTRIBUTE_INFORMATION Information;
} OBP_SET_HANDLE_ATTRIBUTES_CONTEXT, *POBP_SET_HANDLE_ATTRIBUTES_CONTEXT;
typedef struct _OBP_CLOSE_HANDLE_CONTEXT
{
PHANDLE_TABLE HandleTable;
KPROCESSOR_MODE AccessMode;
} OBP_CLOSE_HANDLE_CONTEXT, *POBP_CLOSE_HANDLE_CONTEXT;
typedef struct _OBP_FIND_HANDLE_DATA
{
POBJECT_HEADER ObjectHeader;
@ -102,6 +116,26 @@ typedef struct _OBP_FIND_HANDLE_DATA
POBJECT_HANDLE_INFORMATION HandleInformation;
} OBP_FIND_HANDLE_DATA, *POBP_FIND_HANDLE_DATA;
//
// Cached Security Descriptor Header
//
typedef struct _SECURITY_DESCRIPTOR_HEADER
{
LIST_ENTRY Link;
ULONG RefCount;
ULONG FullHash;
QUAD SecurityDescriptor;
} SECURITY_DESCRIPTOR_HEADER, *PSECURITY_DESCRIPTOR_HEADER;
//
// Cached Security Descriptor List
//
typedef struct _OB_SD_CACHE_LIST
{
EX_PUSH_LOCK PushLock;
LIST_ENTRY Head;
} OB_SD_CACHE_LIST, *POB_SD_CACHE_LIST;
//
// Structure for quick-compare of a DOS Device path
//
@ -388,23 +422,10 @@ ObpInitSdCache(
VOID
);
NTSTATUS
NTAPI
ObpAddSecurityDescriptor(
IN PSECURITY_DESCRIPTOR SourceSD,
OUT PSECURITY_DESCRIPTOR *DestinationSD
);
PSECURITY_DESCRIPTOR
NTAPI
ObpReferenceCachedSecurityDescriptor(
IN PSECURITY_DESCRIPTOR SecurityDescriptor
);
VOID
NTAPI
ObpDereferenceCachedSecurityDescriptor(
IN PSECURITY_DESCRIPTOR SecurityDescriptor
ObpReferenceSecurityDescriptor(
IN POBJECT_HEADER ObjectHeader
);
//

View file

@ -69,7 +69,7 @@ ObpReleaseObjectLock(IN POBJECT_HEADER ObjectHeader)
/* Pick a slot */
Slot = ObpSelectObjectLockSlot(ObjectHeader);
/* Enter a critical region and acquire the resource */
/* Release the resource and leave a critical region */
ExReleaseResourceLite(&ObjectType->ObjectLocks[Slot]);
KeLeaveCriticalRegion();

View file

@ -0,0 +1,460 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ob/sdcache.c
* PURPOSE: No purpose listed.
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
#define SD_CACHE_ENTRIES 0x100
OB_SD_CACHE_LIST ObsSecurityDescriptorCache[SD_CACHE_ENTRIES];
ULONGLONG Cycles;
ULONG TimeDelta;
#define ObpSdCacheBeginPerfCount() \
Cycles = __rdtsc();
#define ObpSdCacheEndPerfCount() \
TimeDelta += __rdtsc() - Cycles;
/* PRIVATE FUNCTIONS **********************************************************/
VOID
FORCEINLINE
ObpSdAcquireLock(IN POB_SD_CACHE_LIST CacheEntry)
{
/* Acquire the lock */
KeEnterCriticalRegion();
ExAcquirePushLockExclusive(&CacheEntry->PushLock);
}
VOID
FORCEINLINE
ObpSdReleaseLock(IN POB_SD_CACHE_LIST CacheEntry)
{
/* Release the lock */
ExReleasePushLockExclusive(&CacheEntry->PushLock);
KeLeaveCriticalRegion();
}
VOID
FORCEINLINE
ObpSdAcquireLockShared(IN POB_SD_CACHE_LIST CacheEntry)
{
/* Acquire the lock */
KeEnterCriticalRegion();
ExAcquirePushLockShared(&CacheEntry->PushLock);
}
VOID
FORCEINLINE
ObpSdReleaseLockShared(IN POB_SD_CACHE_LIST CacheEntry)
{
/* Release the lock */
ExReleasePushLock(&CacheEntry->PushLock);
KeLeaveCriticalRegion();
}
NTSTATUS
NTAPI
ObpInitSdCache(VOID)
{
ULONG i;
/* Loop each cache entry */
for (i = 0; i < SD_CACHE_ENTRIES; i++)
{
/* Initialize the lock and the list */
InitializeListHead(&ObsSecurityDescriptorCache[i].Head);
ExInitializePushLock((PULONG_PTR)&ObsSecurityDescriptorCache[i].PushLock);
}
/* Return success */
return STATUS_SUCCESS;
}
ULONG
NTAPI
ObpHash(IN PVOID Buffer,
IN ULONG Length)
{
PULONG p, pp;
PUCHAR pb, ppb;
ULONG Hash = 0;
/* Setup aligned and byte buffers */
p = Buffer;
ppb = (PUCHAR)((ULONG_PTR)Buffer + Length);
pp = (PULONG)ALIGN_DOWN(p + Length, ULONG);
/* Loop aligned data */
while (p < pp)
{
/* XOR-rotate */
Hash ^= *p++;
Hash = _rotl(Hash, 3);
}
/* Loop non-aligned data */
pb = (PUCHAR)p;
while (pb < ppb)
{
/* XOR-rotate */
Hash ^= *pb++;
Hash = _rotl(Hash, 3);
}
/* Return the hash */
return Hash;
}
ULONG
NTAPI
ObpHashSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG Length)
{
/* Just hash the entire SD */
return ObpHash(SecurityDescriptor, Length);
}
PSECURITY_DESCRIPTOR_HEADER
NTAPI
ObpCreateCacheEntry(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG Length,
IN ULONG FullHash,
IN ULONG RefCount)
{
ULONG CacheSize;
PSECURITY_DESCRIPTOR_HEADER SdHeader;
ASSERT(Length == RtlLengthSecurityDescriptor(SecurityDescriptor));
/* Calculate the memory we'll need to allocate and allocate it */
CacheSize = Length + (sizeof(SECURITY_DESCRIPTOR_HEADER) - sizeof(QUAD));
SdHeader = ExAllocatePoolWithTag(PagedPool, CacheSize, TAG('O', 'b', 'S', 'c'));
if (!SdHeader) return NULL;
/* Setup the header */
SdHeader->RefCount = RefCount;
SdHeader->FullHash = FullHash;
/* Copy the descriptor */
RtlCopyMemory(&SdHeader->SecurityDescriptor, SecurityDescriptor, Length);
/* Return it */
return SdHeader;
}
BOOLEAN
NTAPI
ObpCompareSecurityDescriptors(IN PSECURITY_DESCRIPTOR Sd1,
IN ULONG Length1,
IN PSECURITY_DESCRIPTOR Sd2)
{
ULONG Length2;
ASSERT(Length1 == RtlLengthSecurityDescriptor(Sd1));
/* Get the length of the second SD */
Length2 = RtlLengthSecurityDescriptor(Sd2);
/* Compare lengths */
if (Length1 != Length2) return FALSE;
/* Compare contents */
return RtlEqualMemory(Sd1, Sd2, Length1);
}
PVOID
NTAPI
ObpDestroySecurityDescriptorHeader(IN PSECURITY_DESCRIPTOR_HEADER SdHeader)
{
ASSERT(SdHeader->RefCount == 0);
/* Just unlink the SD and return it back to the caller */
RemoveEntryList(&SdHeader->Link);
return SdHeader;
}
PSECURITY_DESCRIPTOR
NTAPI
ObpReferenceSecurityDescriptor(IN POBJECT_HEADER ObjectHeader)
{
PSECURITY_DESCRIPTOR SecurityDescriptor;
PSECURITY_DESCRIPTOR_HEADER SdHeader;
ObpSdCacheBeginPerfCount();
/* Get the SD */
SecurityDescriptor = ObjectHeader->SecurityDescriptor;
if (!SecurityDescriptor)
{
/* No SD, nothing to do */
ObpSdCacheEndPerfCount();
return NULL;
}
/* Lock the object */
ObpAcquireObjectLockShared(ObjectHeader);
/* Get the object header */
SdHeader = ObpGetHeaderForSd(SecurityDescriptor);
/* Do the reference */
InterlockedIncrement((PLONG)&SdHeader->RefCount);
/* Release the lock and return */
ObpReleaseObjectLock(ObjectHeader);
ObpSdCacheEndPerfCount();
return SecurityDescriptor;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*++
* @name ObReferenceSecurityDescriptor
* @implemented NT5.2
*
* The ObReferenceSecurityDescriptor routine <FILLMEIN>
*
* @param SecurityDescriptor
* <FILLMEIN>
*
* @param Count
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
VOID
NTAPI
ObReferenceSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG Count)
{
PSECURITY_DESCRIPTOR_HEADER SdHeader;
ObpSdCacheBeginPerfCount();
/* Get the header */
SdHeader = ObpGetHeaderForSd(SecurityDescriptor);
/* Do the references */
InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, Count);
ObpSdCacheEndPerfCount();
}
/*++
* @name ObDereferenceSecurityDescriptor
* @implemented NT5.2
*
* The ObDereferenceSecurityDescriptor routine <FILLMEIN>
*
* @param SecurityDescriptor
* <FILLMEIN>
*
* @param Count
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
VOID
NTAPI
ObDereferenceSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG Count)
{
PSECURITY_DESCRIPTOR_HEADER SdHeader;
LONG OldValue, NewValue;
ULONG Index;
POB_SD_CACHE_LIST CacheEntry;
ObpSdCacheBeginPerfCount();
/* Get the header */
SdHeader = ObpGetHeaderForSd(SecurityDescriptor);
/* Get the current reference count */
OldValue = SdHeader->RefCount;
/* Check if the caller is destroying this SD -- we need the lock for that */
while (OldValue != Count)
{
/* He isn't, we can just try to derefeference atomically */
NewValue = InterlockedCompareExchange((PLONG)&SdHeader->RefCount,
OldValue - Count,
OldValue);
if (NewValue == OldValue) ObpSdCacheEndPerfCount(); return;
/* Try again */
OldValue = NewValue;
}
/* At this point, we need the lock, so choose an entry */
Index = SdHeader->FullHash % SD_CACHE_ENTRIES;
CacheEntry = &ObsSecurityDescriptorCache[Index];
/* Acquire the lock for it */
ObpSdAcquireLock(CacheEntry);
ASSERT(SdHeader->RefCount != 0);
/* Now do the dereference */
if (InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, -(LONG)Count) == Count)
{
/* We're down to zero -- destroy the header */
SdHeader = ObpDestroySecurityDescriptorHeader(SdHeader);
/* Release the lock */
ObpSdReleaseLock(CacheEntry);
/* Free the header */
ExFreePool(SdHeader);
}
else
{
/* Just release the lock */
ObpSdReleaseLock(CacheEntry);
}
ObpSdCacheEndPerfCount();
}
/*++
* @name ObLogSecurityDescriptor
* @implemented NT5.2
*
* The ObLogSecurityDescriptor routine <FILLMEIN>
*
* @param InputSecurityDescriptor
* <FILLMEIN>
*
* @param OutputSecurityDescriptor
* <FILLMEIN>
*
* @param RefBias
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObLogSecurityDescriptor(IN PSECURITY_DESCRIPTOR InputSecurityDescriptor,
OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
IN ULONG RefBias)
{
PSECURITY_DESCRIPTOR_HEADER SdHeader = NULL, NewHeader = NULL;
ULONG Length, Hash, Index;
POB_SD_CACHE_LIST CacheEntry;
BOOLEAN Result;
PLIST_ENTRY NextEntry;
ObpSdCacheBeginPerfCount();
/* Get the length */
Length = RtlLengthSecurityDescriptor(InputSecurityDescriptor);
/* Get the hash */
Hash = ObpHashSecurityDescriptor(InputSecurityDescriptor, Length);
/* Now select the appropriate cache entry */
Index = Hash % SD_CACHE_ENTRIES;
CacheEntry = &ObsSecurityDescriptorCache[Index];
/* Lock it shared */
ObpSdAcquireLockShared(CacheEntry);
/* Start our search */
while (TRUE)
{
/* Reset result found */
Result = FALSE;
/* Loop the hash list */
NextEntry = CacheEntry->Head.Flink;
while (NextEntry != &CacheEntry->Head)
{
/* Get the header */
SdHeader = ObpGetHeaderForEntry(NextEntry);
/* Our hashes are ordered, so quickly check if we should stop now */
if (SdHeader->FullHash > Hash) break;
/* We survived the quick hash check, now check for equalness */
if (SdHeader->FullHash == Hash)
{
/* Hashes match, now compare descriptors */
Result = ObpCompareSecurityDescriptors(InputSecurityDescriptor,
Length,
&SdHeader->SecurityDescriptor);
if (Result) break;
}
/* Go to the next entry */
NextEntry = NextEntry->Flink;
}
/* Check if we found anything */
if (Result)
{
/* Increment its reference count */
InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, RefBias);
/* Release the lock */
ObpSdReleaseLockShared(CacheEntry);
/* Return the descriptor */
*OutputSecurityDescriptor = &SdHeader->SecurityDescriptor;
/* Free anything that we may have had to create */
if (NewHeader) ExFreePool(NewHeader);
ObpSdCacheEndPerfCount();
return STATUS_SUCCESS;
}
/* Check if we got here, and didn't create a descriptor yet */
if (!NewHeader)
{
/* Release the lock */
ObpSdReleaseLockShared(CacheEntry);
/* This should be our first time in the loop, create it */
NewHeader = ObpCreateCacheEntry(InputSecurityDescriptor,
Length,
Hash,
RefBias);
if (!NewHeader) return STATUS_INSUFFICIENT_RESOURCES;
/* Now acquire the exclusive lock and we should hit the right path */
ObpSdAcquireLock(CacheEntry);
}
else
{
/* We have inserted the SD, we're fine now */
break;
}
}
/* Okay, now let's do the insert, we should have the exclusive lock */
InsertTailList(NextEntry, &NewHeader->Link);
/* Release the lock */
ObpSdReleaseLock(CacheEntry);
/* Return the SD*/
*OutputSecurityDescriptor = &NewHeader->SecurityDescriptor;
ObpSdCacheEndPerfCount();
return STATUS_SUCCESS;
}
/* EOF */

View file

@ -36,7 +36,7 @@ ObAssignObjectSecurityDescriptor(IN PVOID Object,
}
/* Add it to our internal cache */
Status = ObpAddSecurityDescriptor(SecurityDescriptor, &NewSd);
Status = ObLogSecurityDescriptor(SecurityDescriptor, &NewSd, 1);
if (NT_SUCCESS(Status))
{
/* Free the old copy */
@ -56,7 +56,7 @@ NTAPI
ObDeassignSecurity(IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor)
{
/* Dereference it */
ObpDereferenceCachedSecurityDescriptor(*SecurityDescriptor);
ObDereferenceSecurityDescriptor(*SecurityDescriptor, 1);
/* Don't free again later */
*SecurityDescriptor = NULL;
@ -82,7 +82,7 @@ ObQuerySecurityDescriptorInfo(IN PVOID Object,
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
/* Get the SD */
ObjectSd = ObpReferenceCachedSecurityDescriptor(ObjectHeader->SecurityDescriptor);
ObjectSd = ObpReferenceSecurityDescriptor(ObjectHeader);
/* Query the information */
Status = SeQuerySecurityDescriptorInfo(SecurityInformation,
@ -91,7 +91,7 @@ ObQuerySecurityDescriptorInfo(IN PVOID Object,
&ObjectSd);
/* Check if we have an object SD and dereference it, if so */
if (ObjectSd) ObpDereferenceCachedSecurityDescriptor(ObjectSd);
if (ObjectSd) ObDereferenceSecurityDescriptor(ObjectSd, 1);
/* Return status */
return Status;
@ -116,7 +116,7 @@ ObSetSecurityDescriptorInfo(IN PVOID Object,
while (TRUE)
{
/* Reference the old descriptor */
OldDescriptor = ObpReferenceCachedSecurityDescriptor(ObjectHeader->SecurityDescriptor);
OldDescriptor = ObpReferenceSecurityDescriptor(ObjectHeader);
NewDescriptor = OldDescriptor;
/* Set the SD information */
@ -129,7 +129,7 @@ ObSetSecurityDescriptorInfo(IN PVOID Object,
if (NT_SUCCESS(Status))
{
/* Now add this to the cache */
Status = ObpAddSecurityDescriptor(NewDescriptor, &CachedDescriptor);
Status = ObLogSecurityDescriptor(NewDescriptor, &CachedDescriptor, 1);
/* Let go of our uncached copy */
ExFreePool(NewDescriptor);
@ -144,20 +144,20 @@ ObSetSecurityDescriptorInfo(IN PVOID Object,
ObjectHeader->SecurityDescriptor = CachedDescriptor;
/* And dereference the old one */
ObpDereferenceCachedSecurityDescriptor(OldDescriptor);
ObDereferenceSecurityDescriptor(OldDescriptor, 1);
break;
}
else
{
/* We failed, dereference the old one */
ObpDereferenceCachedSecurityDescriptor(OldDescriptor);
ObDereferenceSecurityDescriptor(OldDescriptor, 1);
break;
}
}
else
{
/* We failed, dereference the old one */
if (OldDescriptor) ObpDereferenceCachedSecurityDescriptor(OldDescriptor);
if (OldDescriptor) ObDereferenceSecurityDescriptor(OldDescriptor, 1);
break;
}
}
@ -585,8 +585,7 @@ ObGetObjectSecurity(IN PVOID Object,
if (Type->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
{
/* Reference the descriptor */
*SecurityDescriptor =
ObpReferenceCachedSecurityDescriptor(Header->SecurityDescriptor);
*SecurityDescriptor = ObpReferenceSecurityDescriptor(Header);
return STATUS_SUCCESS;
}
@ -678,7 +677,7 @@ ObReleaseObjectSecurity(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
else
{
/* Otherwise this means we used an internal descriptor */
ObpDereferenceCachedSecurityDescriptor(SecurityDescriptor);
ObDereferenceSecurityDescriptor(SecurityDescriptor, 1);
}
}

View file

@ -1,409 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ob/sdcache.c
* PURPOSE: No purpose listed.
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* TYPES ********************************************************************/
typedef struct _SD_CACHE_ENTRY
{
LIST_ENTRY ListEntry;
ULONG HashValue;
ULONG Index;
ULONG RefCount;
} SD_CACHE_ENTRY, *PSD_CACHE_ENTRY;
/* GLOBALS ******************************************************************/
#define SD_CACHE_ENTRIES 0x100
LIST_ENTRY ObpSdCache[SD_CACHE_ENTRIES];
FAST_MUTEX ObpSdCacheMutex;
/* FUNCTIONS ****************************************************************/
NTSTATUS
NTAPI
ObpInitSdCache(VOID)
{
ULONG i;
for (i = 0; i < (sizeof(ObpSdCache) / sizeof(ObpSdCache[0])); i++)
{
InitializeListHead(&ObpSdCache[i]);
}
ExInitializeFastMutex(&ObpSdCacheMutex);
return STATUS_SUCCESS;
}
static __inline VOID
ObpSdCacheLock(VOID)
{
/* can't acquire a fast mutex in the early boot process... */
if(KeGetCurrentThread() != NULL)
{
ExAcquireFastMutex(&ObpSdCacheMutex);
}
}
static __inline VOID
ObpSdCacheUnlock(VOID)
{
/* can't acquire a fast mutex in the early boot process... */
if(KeGetCurrentThread() != NULL)
{
ExReleaseFastMutex(&ObpSdCacheMutex);
}
}
static ULONG
ObpHash(PVOID Buffer,
ULONG Length)
{
PUCHAR Ptr;
ULONG Value;
ULONG i;
Ptr = (PUCHAR)Buffer;
Value = 0;
for (i = 0; i < Length; i++)
{
Value += *Ptr;
Ptr++;
}
return Value;
}
static ULONG
ObpHashSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
ULONG Value;
BOOLEAN Defaulted;
BOOLEAN DaclPresent;
BOOLEAN SaclPresent;
PSID Owner = NULL;
PSID Group = NULL;
PACL Dacl = NULL;
PACL Sacl = NULL;
RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
&Owner,
&Defaulted);
RtlGetGroupSecurityDescriptor(SecurityDescriptor,
&Group,
&Defaulted);
RtlGetDaclSecurityDescriptor(SecurityDescriptor,
&DaclPresent,
&Dacl,
&Defaulted);
RtlGetSaclSecurityDescriptor(SecurityDescriptor,
&SaclPresent,
&Sacl,
&Defaulted);
Value = 0;
if (Owner != NULL)
{
Value += ObpHash(Owner, RtlLengthSid(Owner));
}
if (Group != NULL)
{
Value += ObpHash(Group, RtlLengthSid(Group));
}
if (DaclPresent == TRUE && Dacl != NULL)
{
Value += ObpHash(Dacl, Dacl->AclSize);
}
if (SaclPresent == TRUE && Sacl != NULL)
{
Value += ObpHash(Sacl, Sacl->AclSize);
}
return Value;
}
static PSD_CACHE_ENTRY
ObpCreateCacheEntry(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG HashValue,
IN ULONG Index,
OUT PSECURITY_DESCRIPTOR *NewSD)
{
PSECURITY_DESCRIPTOR Sd;
PSD_CACHE_ENTRY CacheEntry;
ULONG Length;
DPRINT("ObpCreateCacheEntry() called\n");
Length = RtlLengthSecurityDescriptor(SecurityDescriptor);
CacheEntry = ExAllocatePool(NonPagedPool,
sizeof(SD_CACHE_ENTRY) + Length);
if (CacheEntry == NULL)
{
DPRINT1("ExAllocatePool() failed\n");
return NULL;
}
CacheEntry->HashValue = HashValue;
CacheEntry->Index = Index;
CacheEntry->RefCount = 1;
Sd = (PSECURITY_DESCRIPTOR)(CacheEntry + 1);
RtlCopyMemory(Sd,
SecurityDescriptor,
Length);
*NewSD = Sd;
DPRINT("ObpCreateCacheEntry() done\n");
return CacheEntry;
}
static BOOLEAN
ObpCompareSecurityDescriptors(IN PSECURITY_DESCRIPTOR Sd1,
IN PSECURITY_DESCRIPTOR Sd2)
{
ULONG Length1;
ULONG Length2;
Length1 = RtlLengthSecurityDescriptor(Sd1);
Length2 = RtlLengthSecurityDescriptor(Sd2);
if (Length1 != Length2)
return FALSE;
if (RtlCompareMemory(Sd1, Sd2, Length1) != Length1)
return FALSE;
return TRUE;
}
NTSTATUS
NTAPI
ObpAddSecurityDescriptor(IN PSECURITY_DESCRIPTOR SourceSD,
OUT PSECURITY_DESCRIPTOR *DestinationSD)
{
PSECURITY_DESCRIPTOR Sd;
PLIST_ENTRY CurrentEntry;
PSD_CACHE_ENTRY CacheEntry;
ULONG HashValue;
ULONG Index;
NTSTATUS Status;
DPRINT("ObpAddSecurityDescriptor() called\n");
HashValue = ObpHashSecurityDescriptor(SourceSD);
Index = HashValue & 0xFF;
ObpSdCacheLock();
if (!IsListEmpty(&ObpSdCache[Index]))
{
CurrentEntry = ObpSdCache[Index].Flink;
while (CurrentEntry != &ObpSdCache[Index])
{
CacheEntry = CONTAINING_RECORD(CurrentEntry,
SD_CACHE_ENTRY,
ListEntry);
Sd = (PSECURITY_DESCRIPTOR)(CacheEntry + 1);
if (CacheEntry->HashValue == HashValue &&
ObpCompareSecurityDescriptors(SourceSD, Sd))
{
CacheEntry->RefCount++;
DPRINT("RefCount %lu\n", CacheEntry->RefCount);
*DestinationSD = Sd;
ObpSdCacheUnlock();
DPRINT("ObpAddSecurityDescriptor() done\n");
return STATUS_SUCCESS;
}
CurrentEntry = CurrentEntry->Flink;
}
}
CacheEntry = ObpCreateCacheEntry(SourceSD,
HashValue,
Index,
DestinationSD);
if (CacheEntry == NULL)
{
DPRINT1("ObpCreateCacheEntry() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
DPRINT("RefCount 1\n");
InsertTailList(&ObpSdCache[Index], &CacheEntry->ListEntry);
Status = STATUS_SUCCESS;
}
ObpSdCacheUnlock();
DPRINT("ObpAddSecurityDescriptor() done\n");
return Status;
}
NTSTATUS
NTAPI
ObpRemoveSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
PSD_CACHE_ENTRY CacheEntry;
DPRINT("ObpRemoveSecurityDescriptor() called\n");
ObpSdCacheLock();
CacheEntry = (PSD_CACHE_ENTRY)((ULONG_PTR)SecurityDescriptor - sizeof(SD_CACHE_ENTRY));
CacheEntry->RefCount--;
DPRINT("RefCount %lu\n", CacheEntry->RefCount);
if (CacheEntry->RefCount == 0)
{
DPRINT("Remove cache entry\n");
RemoveEntryList(&CacheEntry->ListEntry);
ExFreePool(CacheEntry);
}
ObpSdCacheUnlock();
DPRINT("ObpRemoveSecurityDescriptor() done\n");
return STATUS_SUCCESS;
}
PSECURITY_DESCRIPTOR
NTAPI
ObpReferenceCachedSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
PSD_CACHE_ENTRY CacheEntry;
/* Lock the cache */
ObpSdCacheLock();
/* Make sure we got a descriptor */
if (SecurityDescriptor)
{
/* Get the entry */
CacheEntry = (PSD_CACHE_ENTRY)((ULONG_PTR)SecurityDescriptor -
sizeof(SD_CACHE_ENTRY));
/* Reference it */
CacheEntry->RefCount++;
DPRINT("RefCount %lu\n", CacheEntry->RefCount);
}
/* Unlock the cache and return the descriptor */
ObpSdCacheUnlock();
return SecurityDescriptor;
}
VOID
NTAPI
ObpDereferenceCachedSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
DPRINT("ObpDereferenceCachedSecurityDescriptor() called\n");
ObpRemoveSecurityDescriptor(SecurityDescriptor);
DPRINT("ObpDereferenceCachedSecurityDescriptor() done\n");
}
/*++
* @name ObLogSecurityDescriptor
* @unimplemented NT5.2
*
* The ObLogSecurityDescriptor routine <FILLMEIN>
*
* @param InputSecurityDescriptor
* <FILLMEIN>
*
* @param OutputSecurityDescriptor
* <FILLMEIN>
*
* @param RefBias
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObLogSecurityDescriptor(IN PSECURITY_DESCRIPTOR InputSecurityDescriptor,
OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
IN ULONG RefBias)
{
/* HACK: Return the same descriptor back */
PISECURITY_DESCRIPTOR SdCopy;
ULONG Length;
DPRINT("ObLogSecurityDescriptor is not implemented!\n",
InputSecurityDescriptor);
Length = RtlLengthSecurityDescriptor(InputSecurityDescriptor);
SdCopy = ExAllocatePool(PagedPool, Length);
RtlCopyMemory(SdCopy, InputSecurityDescriptor, Length);
*OutputSecurityDescriptor = SdCopy;
return STATUS_SUCCESS;
}
/*++
* @name ObDereferenceSecurityDescriptor
* @unimplemented NT5.2
*
* The ObDereferenceSecurityDescriptor routine <FILLMEIN>
*
* @param SecurityDescriptor
* <FILLMEIN>
*
* @param Count
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
VOID
NTAPI
ObDereferenceSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG Count)
{
DPRINT1("ObDereferenceSecurityDescriptor is not implemented!\n");
}
/* EOF */