969 lines
19 KiB
C
969 lines
19 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1989 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
obsdata.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Object Manager Security Descriptor Caching
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Robert Reichel (robertre) 12-Oct-1993
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "obp.h"
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
#define OB_DIAGNOSTICS_ENABLED 1
|
||
|
#endif // DBG
|
||
|
|
||
|
|
||
|
// These definitions are useful diagnostics aids
|
||
|
|
||
|
|
||
|
#if OB_DIAGNOSTICS_ENABLED
|
||
|
|
||
|
ULONG ObsDebugFlags = 0;
|
||
|
|
||
|
|
||
|
// Test for enabled diagnostic
|
||
|
|
||
|
|
||
|
#define IF_OB_GLOBAL( FlagName ) if (ObsDebugFlags & (OBS_DEBUG_##FlagName))
|
||
|
|
||
|
|
||
|
// Diagnostics print statement
|
||
|
|
||
|
|
||
|
#define ObPrint( FlagName, _Text_ ) IF_OB_GLOBAL( FlagName ) DbgPrint _Text_
|
||
|
|
||
|
#else
|
||
|
|
||
|
|
||
|
// diagnostics not enabled - No diagnostics included in build
|
||
|
|
||
|
|
||
|
|
||
|
// Test for diagnostics enabled
|
||
|
|
||
|
|
||
|
#define IF_OB_GLOBAL( FlagName ) if (FALSE)
|
||
|
|
||
|
|
||
|
// Diagnostics print statement (expands to no-op)
|
||
|
|
||
|
|
||
|
#define ObPrint( FlagName, _Text_ ) ;
|
||
|
|
||
|
#endif // OB_DIAGNOSTICS_ENABLED
|
||
|
|
||
|
|
||
|
#if OB_DIAGNOSTICS_ENABLED
|
||
|
|
||
|
ULONG ObsTotalCacheEntries = 0;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// The following flags enable or disable various diagnostic
|
||
|
// capabilities within OB code. These flags are set in
|
||
|
// ObGlobalFlag (only available within a DBG system).
|
||
|
|
||
|
|
||
|
|
||
|
#define OBS_DEBUG_ALLOC_TRACKING ((ULONG) 0x00000001L)
|
||
|
#define OBS_DEBUG_CACHE_FREES ((ULONG) 0x00000002L)
|
||
|
#define OBS_DEBUG_BREAK_ON_INIT ((ULONG) 0x00000004L)
|
||
|
#define OBS_DEBUG_SHOW_COLLISIONS ((ULONG) 0x00000008L)
|
||
|
#define OBS_DEBUG_SHOW_STATISTICS ((ULONG) 0x00000010L)
|
||
|
#define OBS_DEBUG_SHOW_REFERENCES ((ULONG) 0x00000020L)
|
||
|
#define OBS_DEBUG_SHOW_DEASSIGN ((ULONG) 0x00000040L)
|
||
|
#define OBS_DEBUG_STOP_INVALID_DESCRIPTOR ((ULONG) 0x00000080L)
|
||
|
#define OBS_DEBUG_SHOW_HEADER_FREE ((ULONG) 0x00000100L)
|
||
|
|
||
|
|
||
|
// Array of pointers to security descriptor entries
|
||
|
|
||
|
|
||
|
PLIST_ENTRY *ObsSecurityDescriptorCache = NULL;
|
||
|
|
||
|
|
||
|
|
||
|
// Resource used to protect the security descriptor cache
|
||
|
|
||
|
|
||
|
ERESOURCE ObsSecurityDescriptorCacheLock;
|
||
|
|
||
|
#if defined (ALLOC_PRAGMA)
|
||
|
#pragma alloc_text(PAGE,ObpDereferenceSecurityDescriptor)
|
||
|
#pragma alloc_text(PAGE,ObpDestroySecurityDescriptorHeader)
|
||
|
#pragma alloc_text(PAGE,ObpHashBuffer)
|
||
|
#pragma alloc_text(PAGE,ObpHashSecurityDescriptor)
|
||
|
#pragma alloc_text(PAGE,ObpInitSecurityDescriptorCache)
|
||
|
#pragma alloc_text(PAGE,ObpLogSecurityDescriptor)
|
||
|
#pragma alloc_text(PAGE,ObpReferenceSecurityDescriptor)
|
||
|
#pragma alloc_text(PAGE,ObpCreateCacheEntry)
|
||
|
#endif
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
ObpInitSecurityDescriptorCache (
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Allocates and initializes the globalSecurity Descriptor Cache
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS on success, NTSTATUS on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG Size;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
IF_OB_GLOBAL( BREAK_ON_INIT ) {
|
||
|
|
||
|
DbgBreakPoint();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Allocate the cache of pointers and zero it out
|
||
|
|
||
|
|
||
|
Size = SECURITY_DESCRIPTOR_CACHE_ENTRIES * sizeof(PLIST_ENTRY);
|
||
|
ObsSecurityDescriptorCache = ExAllocatePoolWithTag( PagedPool, Size, 'cCdS' );
|
||
|
|
||
|
if (ObsSecurityDescriptorCache == NULL ) {
|
||
|
|
||
|
return( STATUS_INSUFFICIENT_RESOURCES );
|
||
|
}
|
||
|
|
||
|
RtlZeroMemory( ObsSecurityDescriptorCache, Size );
|
||
|
|
||
|
|
||
|
// Initialize the resource used to protect the security cache
|
||
|
|
||
|
|
||
|
Status = ExInitializeResource ( &ObsSecurityDescriptorCacheLock );
|
||
|
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
|
||
|
ExFreePool( ObsSecurityDescriptorCache );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
// And return to our caller
|
||
|
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
ObpHashSecurityDescriptor (
|
||
|
PSECURITY_DESCRIPTOR SecurityDescriptor
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Hashes a security descriptor to a 32 bit value
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
SecurityDescriptor - Provides the security descriptor to be hashed
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ULONG - a 32 bit hash value.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSID Owner = NULL;
|
||
|
PSID Group = NULL;
|
||
|
|
||
|
PACL Dacl;
|
||
|
PACL Sacl;
|
||
|
|
||
|
ULONG Hash = 0;
|
||
|
BOOLEAN Junk;
|
||
|
NTSTATUS Status;
|
||
|
BOOLEAN DaclPresent = FALSE;
|
||
|
BOOLEAN SaclPresent = FALSE;
|
||
|
PISECURITY_DESCRIPTOR sd;
|
||
|
|
||
|
|
||
|
// Cast the actually opaque security descriptor into something
|
||
|
// that we can decipher
|
||
|
|
||
|
|
||
|
sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
|
||
|
|
||
|
Status = RtlGetOwnerSecurityDescriptor( sd, &Owner, &Junk );
|
||
|
Status = RtlGetGroupSecurityDescriptor( sd, &Group, &Junk );
|
||
|
Status = RtlGetDaclSecurityDescriptor( sd, &DaclPresent, &Dacl, &Junk );
|
||
|
Status = RtlGetSaclSecurityDescriptor( sd, &SaclPresent, &Sacl, &Junk );
|
||
|
|
||
|
if ( Owner != NULL ) {
|
||
|
|
||
|
Hash = ObpHashBuffer( Owner, RtlLengthSid( Owner ));
|
||
|
}
|
||
|
|
||
|
if ( Group != NULL ) {
|
||
|
|
||
|
Hash += ObpHashBuffer( Group, RtlLengthSid( Group));
|
||
|
}
|
||
|
|
||
|
if ( DaclPresent && (Dacl != NULL)) {
|
||
|
|
||
|
Hash += ObpHashBuffer( Dacl, Dacl->AclSize);
|
||
|
}
|
||
|
|
||
|
if ( SaclPresent && (Sacl != NULL)) {
|
||
|
|
||
|
Hash += ObpHashBuffer( Sacl, Sacl->AclSize);
|
||
|
}
|
||
|
|
||
|
return( Hash );
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
ObpHashBuffer (
|
||
|
PVOID Data,
|
||
|
ULONG Length
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Hashes a buffer into a 32 bit value
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Data - Buffer containing the data to be hashed.
|
||
|
|
||
|
Length - The length in bytes of the buffer
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ULONG - a 32 bit hash value.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCHAR Buffer;
|
||
|
ULONG Result = 0;
|
||
|
LONG i;
|
||
|
|
||
|
Buffer = (PCHAR)Data;
|
||
|
|
||
|
for (i = 0; i <= (LONG)((Length-3)-sizeof(ULONG)); i++) {
|
||
|
|
||
|
ULONG Tmp;
|
||
|
|
||
|
Tmp = *((ULONG UNALIGNED *)(Buffer + i));
|
||
|
Result += Tmp;
|
||
|
}
|
||
|
|
||
|
return( Result );
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
ObpLogSecurityDescriptor (
|
||
|
IN PSECURITY_DESCRIPTOR InputSecurityDescriptor,
|
||
|
OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Takes a passed security descriptor and registers it into the
|
||
|
security descriptor database.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
InputSecurityDescriptor - The new security descriptor to be logged into
|
||
|
the database. On a successful return this memory will have been
|
||
|
freed back to pool.
|
||
|
|
||
|
OutputSecurityDescriptor - Output security descriptor to be used by the
|
||
|
caller.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
An appropriate status value
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG FullHash;
|
||
|
UCHAR SmallHash;
|
||
|
PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
|
||
|
PLIST_ENTRY Front;
|
||
|
PLIST_ENTRY Back;
|
||
|
PSECURITY_DESCRIPTOR_HEADER Header;
|
||
|
BOOLEAN Match;
|
||
|
|
||
|
FullHash = ObpHashSecurityDescriptor( InputSecurityDescriptor );
|
||
|
SmallHash = (UCHAR)FullHash;
|
||
|
|
||
|
|
||
|
// See if the entry matching SmallHash is in use.
|
||
|
// Lock the table first, unlock if if we don't need it.
|
||
|
|
||
|
|
||
|
ObpAcquireDescriptorCacheWriteLock();
|
||
|
|
||
|
Front = ObsSecurityDescriptorCache[SmallHash];
|
||
|
Back = NULL;
|
||
|
Match = FALSE;
|
||
|
|
||
|
|
||
|
// Zoom down the hash bucket looking for a full hash match
|
||
|
|
||
|
|
||
|
while ( Front != NULL ) {
|
||
|
|
||
|
Header = LINK_TO_SD_HEADER( Front );
|
||
|
|
||
|
|
||
|
// **** is this test really right? Is the full hash value really
|
||
|
// ordered like this?
|
||
|
|
||
|
|
||
|
if ( Header->FullHash > FullHash ) {
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( Header->FullHash == FullHash ) {
|
||
|
|
||
|
Match = ObpCompareSecurityDescriptors( InputSecurityDescriptor,
|
||
|
&Header->SecurityDescriptor );
|
||
|
|
||
|
if ( Match ) {
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ObPrint( SHOW_COLLISIONS,("Got a collision on %d, no match\n",SmallHash));
|
||
|
}
|
||
|
|
||
|
Back = Front;
|
||
|
Front = Front->Flink;
|
||
|
}
|
||
|
|
||
|
|
||
|
// If we have a match then we'll get the caller to use the old
|
||
|
// cached descriptor, but bumping its ref count, freeing what
|
||
|
// the caller supplied and returning the old one to our caller
|
||
|
|
||
|
|
||
|
if ( Match ) {
|
||
|
|
||
|
Header->RefCount++;
|
||
|
|
||
|
ObPrint( SHOW_REFERENCES, ("Reference Hash = 0x%lX, New RefCount = %d\n",Header->FullHash,Header->RefCount));
|
||
|
|
||
|
*OutputSecurityDescriptor = &Header->SecurityDescriptor;
|
||
|
|
||
|
ExFreePool( InputSecurityDescriptor );
|
||
|
|
||
|
ObpReleaseDescriptorCacheLock();
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
}
|
||
|
|
||
|
|
||
|
// Can't use an existing one, create a new entry
|
||
|
// and insert it into the list.
|
||
|
|
||
|
|
||
|
NewDescriptor = ObpCreateCacheEntry( InputSecurityDescriptor,
|
||
|
FullHash );
|
||
|
|
||
|
if ( NewDescriptor == NULL ) {
|
||
|
|
||
|
ObpReleaseDescriptorCacheLock();
|
||
|
|
||
|
return( STATUS_INSUFFICIENT_RESOURCES );
|
||
|
}
|
||
|
|
||
|
#if OB_DIAGNOSTICS_ENABLED
|
||
|
|
||
|
ObsTotalCacheEntries++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
ObPrint( SHOW_STATISTICS, ("ObsTotalCacheEntries = %d \n",ObsTotalCacheEntries));
|
||
|
ObPrint( SHOW_COLLISIONS, ("Adding new entry for index #%d \n",SmallHash));
|
||
|
|
||
|
|
||
|
// We don't need the old security descriptor any more.
|
||
|
|
||
|
|
||
|
ExFreePool( InputSecurityDescriptor );
|
||
|
|
||
|
|
||
|
// The following logic inserts the new security descriptor into the
|
||
|
// small hash list. We need to first decide if the we're adding
|
||
|
// the entry to the beginning of the list (back is null) or if we're
|
||
|
// further in the list.
|
||
|
|
||
|
// **** This logic is plain bizzare because (1) the small hash
|
||
|
// should probably just be an array of list heads and not single
|
||
|
// pointer value and (2) the doubly linked list of security descriptors
|
||
|
// is not circular! This should be fixed to use the regular set
|
||
|
// of link list macros
|
||
|
|
||
|
|
||
|
if ( Back == NULL ) {
|
||
|
|
||
|
|
||
|
// We're inserting at the beginning of the list for this
|
||
|
// minor index
|
||
|
|
||
|
|
||
|
NewDescriptor->Link.Flink = ObsSecurityDescriptorCache[SmallHash];
|
||
|
ObsSecurityDescriptorCache[SmallHash] = &NewDescriptor->Link;
|
||
|
|
||
|
if ( NewDescriptor->Link.Flink != NULL ) {
|
||
|
|
||
|
NewDescriptor->Link.Flink->Blink = &NewDescriptor->Link;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
|
||
|
// Hook new descriptor entry into list.
|
||
|
|
||
|
|
||
|
NewDescriptor->Link.Flink = Front;
|
||
|
|
||
|
NewDescriptor->Link.Blink = Back;
|
||
|
|
||
|
Back->Flink = &NewDescriptor->Link;
|
||
|
|
||
|
if (Front != NULL) {
|
||
|
|
||
|
Front->Blink = &NewDescriptor->Link;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set the output security descriptor and return to our caller
|
||
|
|
||
|
|
||
|
*OutputSecurityDescriptor = &NewDescriptor->SecurityDescriptor;
|
||
|
ObpReleaseDescriptorCacheLock();
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
}
|
||
|
|
||
|
|
||
|
PSECURITY_DESCRIPTOR_HEADER
|
||
|
ObpCreateCacheEntry (
|
||
|
PSECURITY_DESCRIPTOR InputSecurityDescriptor,
|
||
|
ULONG FullHash
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Allocates and initializes a new cache entry.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
InputSecurityDescriptor - The security descriptor to be cached.
|
||
|
|
||
|
FullHash - Full 32 bit hash of the security descriptor.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
A pointer to the newly allocated cache entry, or NULL
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
ULONG SecurityDescriptorLength;
|
||
|
ULONG CacheEntrySize;
|
||
|
PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
|
||
|
|
||
|
|
||
|
// Compute the size that we'll need to allocate. We need space for
|
||
|
// the security descriptor cache minus the funny quad at the end and the
|
||
|
// security descriptor itself.
|
||
|
|
||
|
|
||
|
SecurityDescriptorLength = RtlLengthSecurityDescriptor ( InputSecurityDescriptor );
|
||
|
CacheEntrySize = SecurityDescriptorLength + (sizeof(SECURITY_DESCRIPTOR_HEADER) - sizeof( QUAD ));
|
||
|
|
||
|
|
||
|
// Now allocate space for the cached entry
|
||
|
|
||
|
|
||
|
NewDescriptor = ExAllocatePoolWithTag( PagedPool, CacheEntrySize, 'dSeS');
|
||
|
|
||
|
if ( NewDescriptor == NULL ) {
|
||
|
|
||
|
return( NULL );
|
||
|
}
|
||
|
|
||
|
|
||
|
// Fill the header, copy over the descriptor data, and return to our
|
||
|
// caller
|
||
|
|
||
|
|
||
|
NewDescriptor->RefCount = 1;
|
||
|
NewDescriptor->FullHash = FullHash;
|
||
|
NewDescriptor->Link.Flink = NULL;
|
||
|
NewDescriptor->Link.Blink = NULL;
|
||
|
|
||
|
RtlCopyMemory( &NewDescriptor->SecurityDescriptor,
|
||
|
InputSecurityDescriptor,
|
||
|
SecurityDescriptorLength );
|
||
|
|
||
|
return( NewDescriptor );
|
||
|
}
|
||
|
|
||
|
|
||
|
PSECURITY_DESCRIPTOR
|
||
|
ObpReferenceSecurityDescriptor (
|
||
|
PVOID Object
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
References the security descriptor of the passed object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Object - Object being access validated.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The security descriptor of the object.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
|
||
|
POBJECT_HEADER ObjectHeader;
|
||
|
POBJECT_TYPE ObjectType;
|
||
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
||
|
|
||
|
|
||
|
// Make sure the sure that the object in question is being
|
||
|
// maintained by the system and doesn't have it own security
|
||
|
// management routines.
|
||
|
|
||
|
// **** the first two lines should probably be only done on
|
||
|
// a checked build
|
||
|
|
||
|
|
||
|
ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
|
||
|
ObjectType = ObjectHeader->Type;
|
||
|
ASSERT( ObpCentralizedSecurity(ObjectType) );
|
||
|
|
||
|
|
||
|
// Lock the security descriptor cache and get the objects
|
||
|
// security descriptor
|
||
|
|
||
|
|
||
|
ObpAcquireDescriptorCacheWriteLock();
|
||
|
|
||
|
SecurityDescriptor = OBJECT_TO_OBJECT_HEADER( Object )->SecurityDescriptor;
|
||
|
|
||
|
IF_OB_GLOBAL( STOP_INVALID_DESCRIPTOR ) {
|
||
|
|
||
|
if((SecurityDescriptor != NULL) &&
|
||
|
(!RtlValidSecurityDescriptor ( SecurityDescriptor ))) {
|
||
|
|
||
|
DbgBreakPoint();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// If the object has a security descriptor then we need to
|
||
|
// get the security descriptor header and increment its
|
||
|
// ref count before releasing the lock and returning to
|
||
|
// our caller
|
||
|
|
||
|
|
||
|
if ( SecurityDescriptor != NULL ) {
|
||
|
|
||
|
SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
|
||
|
ObPrint( SHOW_REFERENCES, ("Referencing Hash %lX, Refcount = %d \n",SecurityDescriptorHeader->FullHash,SecurityDescriptorHeader->RefCount));
|
||
|
SecurityDescriptorHeader->RefCount++;
|
||
|
}
|
||
|
|
||
|
ObpReleaseDescriptorCacheLock();
|
||
|
|
||
|
return( SecurityDescriptor );
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
ObDeassignSecurity (
|
||
|
IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine dereferences the input security descriptor
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
SecurityDescriptor - Supplies the security descriptor
|
||
|
being modified
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Only returns STATUS_SUCCESS
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSECURITY_DESCRIPTOR_HEADER Header;
|
||
|
|
||
|
|
||
|
// Lock the security descriptor cache and get a pointer
|
||
|
// to the security descriptor header
|
||
|
|
||
|
|
||
|
ObpAcquireDescriptorCacheWriteLock();
|
||
|
|
||
|
|
||
|
// **** the following diagnostic code should really be done only on
|
||
|
// a checked build
|
||
|
|
||
|
|
||
|
Header = SD_TO_SD_HEADER( *SecurityDescriptor );
|
||
|
ObPrint( SHOW_DEASSIGN,("Deassigning security descriptor %x, hash = %lX\n",*SecurityDescriptor, Header->FullHash));
|
||
|
|
||
|
|
||
|
// Call the actual routine to dereference the security descriptor
|
||
|
|
||
|
|
||
|
ObpDereferenceSecurityDescriptor( *SecurityDescriptor );
|
||
|
|
||
|
|
||
|
// NULL out the SecurityDescriptor in the object's
|
||
|
// header so we don't try to free it again.
|
||
|
|
||
|
|
||
|
*SecurityDescriptor = NULL;
|
||
|
|
||
|
|
||
|
// Unlock the security descriptor cache and return to our caller
|
||
|
|
||
|
|
||
|
ObpReleaseDescriptorCacheLock();
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ObpDereferenceSecurityDescriptor (
|
||
|
PSECURITY_DESCRIPTOR SecurityDescriptor
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Decrements the refcount of a cached security descriptor
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
SecurityDescriptor - Points to a cached security descriptor
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
|
||
|
|
||
|
|
||
|
// Lock the security descriptor cache and get a pointer
|
||
|
// to the security descriptor header
|
||
|
|
||
|
|
||
|
ObpAcquireDescriptorCacheWriteLock();
|
||
|
|
||
|
SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
|
||
|
|
||
|
|
||
|
// Do some debug work
|
||
|
|
||
|
|
||
|
ObPrint( SHOW_REFERENCES, ("Dereferencing SecurityDescriptor %x, hash %lx, refcount = %d \n", SecurityDescriptor, SecurityDescriptorHeader->FullHash,SecurityDescriptorHeader->RefCount));
|
||
|
|
||
|
ASSERT(SecurityDescriptorHeader->RefCount != 0);
|
||
|
|
||
|
|
||
|
// Decrement the ref count and if it is now zero then
|
||
|
// we can completely remove this entry from the cache
|
||
|
|
||
|
|
||
|
if (--SecurityDescriptorHeader->RefCount == 0) {
|
||
|
|
||
|
ObpDestroySecurityDescriptorHeader( SecurityDescriptorHeader );
|
||
|
}
|
||
|
|
||
|
|
||
|
// Unlock the security descriptor cache and return to our caller
|
||
|
|
||
|
|
||
|
ObpReleaseDescriptorCacheLock();
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ObpDestroySecurityDescriptorHeader (
|
||
|
IN PSECURITY_DESCRIPTOR_HEADER Header
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Frees a cached security descriptor and unlinks it from the chain.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Header - Pointer to a security descriptor header (cached security
|
||
|
descriptor)
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PLIST_ENTRY Forward;
|
||
|
PLIST_ENTRY Rear;
|
||
|
UCHAR SmallHash;
|
||
|
|
||
|
ASSERT ( Header->RefCount == 0 );
|
||
|
|
||
|
#if OB_DIAGNOSTICS_ENABLED
|
||
|
|
||
|
ObsTotalCacheEntries--;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
ObPrint( SHOW_STATISTICS, ("ObsTotalCacheEntries = %d \n",ObsTotalCacheEntries));
|
||
|
|
||
|
|
||
|
// Unlink the cached security descriptor from its linked list and
|
||
|
// from the small hash table if it was at the head of the list
|
||
|
|
||
|
// **** this should all be rewritten to use the regular set of
|
||
|
// link list macros
|
||
|
|
||
|
|
||
|
SmallHash = (UCHAR)Header->FullHash;
|
||
|
|
||
|
Forward = Header->Link.Flink;
|
||
|
Rear = Header->Link.Blink;
|
||
|
|
||
|
if ( Forward != NULL ) {
|
||
|
|
||
|
Forward->Blink = Rear;
|
||
|
}
|
||
|
|
||
|
if ( Rear != NULL ) {
|
||
|
|
||
|
Rear->Flink = Forward;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
|
||
|
// if Rear is NULL, we're deleting the head of the list
|
||
|
|
||
|
|
||
|
ObsSecurityDescriptorCache[SmallHash] = Forward;
|
||
|
}
|
||
|
|
||
|
ObPrint( SHOW_HEADER_FREE, ("Freeing memory at %x \n",Header));
|
||
|
|
||
|
|
||
|
// Now return the cached descriptor to pool and return to our caller
|
||
|
|
||
|
|
||
|
ExFreePool( Header );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
ObpCompareSecurityDescriptors (
|
||
|
IN PSECURITY_DESCRIPTOR SD1,
|
||
|
IN PSECURITY_DESCRIPTOR SD2
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Performs a byte by byte comparison of two self relative security
|
||
|
descriptors to determine if they are identical.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
SD1, SD2 - Security descriptors to be compared.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - They are the same.
|
||
|
|
||
|
FALSE - They are different.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG Length1;
|
||
|
ULONG Length2;
|
||
|
ULONG Compare;
|
||
|
|
||
|
|
||
|
// Calculating the length is pretty fast, see if we
|
||
|
// can get away with doing only that.
|
||
|
|
||
|
|
||
|
Length1 = RtlLengthSecurityDescriptor ( SD1 );
|
||
|
Length2 = RtlLengthSecurityDescriptor ( SD2 );
|
||
|
|
||
|
if (Length1 != Length2) {
|
||
|
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
return (BOOLEAN)RtlEqualMemory ( SD1, SD2, Length1 );
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ObpAcquireDescriptorCacheWriteLock (
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Takes a write lock on the security descriptor cache.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
none
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
KeEnterCriticalRegion();
|
||
|
(VOID)ExAcquireResourceExclusive( &ObsSecurityDescriptorCacheLock, TRUE );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ObpAcquireDescriptorCacheReadLock (
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Takes a read lock on the security descriptor cache.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
none
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
KeEnterCriticalRegion();
|
||
|
(VOID)ExAcquireResourceShared( &ObsSecurityDescriptorCacheLock,TRUE );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ObpReleaseDescriptorCacheLock (
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Releases a lock on the security descriptor cache.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
none
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
(VOID)ExReleaseResource( &ObsSecurityDescriptorCacheLock );
|
||
|
KeLeaveCriticalRegion ();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|