3638 lines
90 KiB
C++
3638 lines
90 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
genobj.cxx
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Generic object implementation.
|
||
|
|
||
|
AZ roles has so many objects that need creation, enumeration, etc
|
||
|
that it seems prudent to have a single body of code for doing those operations
|
||
|
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Cliff Van Dyke (cliffv) 11-Apr-2001
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include "pch.hxx"
|
||
|
|
||
|
//
|
||
|
// Table of sizes of the specific objects
|
||
|
//
|
||
|
|
||
|
DWORD SpecificObjectSize[OBJECT_TYPE_MAXIMUM] = {
|
||
|
0, // OBJECT_TYPE_ROOT
|
||
|
sizeof(AZP_ADMIN_MANAGER), // OBJECT_TYPE_ADMIN_MANAGER
|
||
|
sizeof(AZP_APPLICATION), // OBJECT_TYPE_APPLICATION
|
||
|
sizeof(AZP_OPERATION), // OBJECT_TYPE_OPERATION
|
||
|
sizeof(AZP_TASK), // OBJECT_TYPE_TASK
|
||
|
sizeof(AZP_SCOPE), // OBJECT_TYPE_SCOPE
|
||
|
sizeof(AZP_GROUP), // OBJECT_TYPE_GROUP
|
||
|
sizeof(AZP_ROLE), // OBJECT_TYPE_ROLE
|
||
|
sizeof(AZP_JUNCTION_POINT), // OBJECT_TYPE_JUNCTION_POINT
|
||
|
sizeof(AZP_SID), // OBJECT_TYPE_SID
|
||
|
sizeof(AZP_CLIENT_CONTEXT), // OBJECT_TYPE_CLIENT_CONTEXT
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Maximum length of the object name
|
||
|
//
|
||
|
|
||
|
DWORD MaxObjectNameLength[OBJECT_TYPE_MAXIMUM] = {
|
||
|
0, // OBJECT_TYPE_ROOT
|
||
|
0, // OBJECT_TYPE_ADMIN_MANAGER
|
||
|
AZ_MAX_APPLICATION_NAME_LENGTH,
|
||
|
AZ_MAX_OPERATION_NAME_LENGTH,
|
||
|
AZ_MAX_TASK_NAME_LENGTH,
|
||
|
AZ_MAX_SCOPE_NAME_LENGTH,
|
||
|
AZ_MAX_GROUP_NAME_LENGTH,
|
||
|
AZ_MAX_ROLE_NAME_LENGTH,
|
||
|
AZ_MAX_JUNCTION_POINT_NAME_LENGTH,
|
||
|
0, // OBJECT_TYPE_SID
|
||
|
0, // OBJECT_TYPE_CLIENT_CONTEXT
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Table of object init routines
|
||
|
//
|
||
|
// Specifies a routine to call to initialize the object type specific fields
|
||
|
// when adding a generic object.
|
||
|
//
|
||
|
|
||
|
OBJECT_INIT_ROUTINE *ObjectInitRoutine[OBJECT_TYPE_MAXIMUM] = {
|
||
|
NULL, // OBJECT_TYPE_ROOT
|
||
|
&AzpAdminManagerInit, // OBJECT_TYPE_ADMIN_MANAGER
|
||
|
&AzpApplicationInit, // OBJECT_TYPE_APPLICATION
|
||
|
&AzpOperationInit, // OBJECT_TYPE_OPERATION
|
||
|
&AzpTaskInit, // OBJECT_TYPE_TASK
|
||
|
&AzpScopeInit, // OBJECT_TYPE_SCOPE
|
||
|
&AzpGroupInit, // OBJECT_TYPE_GROUP
|
||
|
&AzpRoleInit, // OBJECT_TYPE_ROLE
|
||
|
&AzpJunctionPointInit, // OBJECT_TYPE_JUNCTION_POINT
|
||
|
&AzpSidInit, // OBJECT_TYPE_SID
|
||
|
&AzpClientContextInit, // OBJECT_TYPE_CLIENT_CONTEXT
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Table of object free routines
|
||
|
//
|
||
|
// Specifies a routine to call to free the object type specific fields
|
||
|
// when freeing a generic object.
|
||
|
//
|
||
|
|
||
|
OBJECT_FREE_ROUTINE *ObjectFreeRoutine[OBJECT_TYPE_MAXIMUM] = {
|
||
|
NULL, // OBJECT_TYPE_ROOT
|
||
|
&AzpAdminManagerFree, // OBJECT_TYPE_ADMIN_MANAGER
|
||
|
&AzpApplicationFree, // OBJECT_TYPE_APPLICATION
|
||
|
&AzpOperationFree, // OBJECT_TYPE_OPERATION
|
||
|
&AzpTaskFree, // OBJECT_TYPE_TASK
|
||
|
&AzpScopeFree, // OBJECT_TYPE_SCOPE
|
||
|
&AzpGroupFree, // OBJECT_TYPE_GROUP
|
||
|
&AzpRoleFree, // OBJECT_TYPE_ROLE
|
||
|
&AzpJunctionPointFree, // OBJECT_TYPE_JUNCTION_POINT
|
||
|
&AzpSidFree, // OBJECT_TYPE_SID
|
||
|
&AzpClientContextFree, // OBJECT_TYPE_CLIENT_CONTEXT
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Table of object specific GetProperty routines
|
||
|
//
|
||
|
// Specifies a routine to call to get object type specific fields
|
||
|
// when querying a generic object.
|
||
|
//
|
||
|
// NULL means there are no object specific fields.
|
||
|
//
|
||
|
|
||
|
OBJECT_GET_PROPERTY_ROUTINE *ObjectGetPropertyRoutine[OBJECT_TYPE_MAXIMUM] = {
|
||
|
NULL, // OBJECT_TYPE_ROOT
|
||
|
NULL, // OBJECT_TYPE_ADMIN_MANAGER
|
||
|
NULL, // OBJECT_TYPE_APPLICATION
|
||
|
&AzpOperationGetProperty, // OBJECT_TYPE_OPERATION
|
||
|
&AzpTaskGetProperty, // OBJECT_TYPE_TASK
|
||
|
NULL, // OBJECT_TYPE_SCOPE
|
||
|
&AzpGroupGetProperty, // OBJECT_TYPE_GROUP
|
||
|
&AzpRoleGetProperty, // OBJECT_TYPE_ROLE
|
||
|
&AzpJunctionPointGetProperty, // OBJECT_TYPE_JUNCTION_POINT
|
||
|
NULL, // OBJECT_TYPE_SID
|
||
|
NULL, // OBJECT_TYPE_CLIENT_CONTEXT
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Table of object specific SetProperty routines
|
||
|
//
|
||
|
// Specifies a routine to call to set object type specific fields
|
||
|
// when modifying a generic object.
|
||
|
//
|
||
|
// NULL means there are no object specific fields.
|
||
|
//
|
||
|
|
||
|
OBJECT_SET_PROPERTY_ROUTINE *ObjectSetPropertyRoutine[OBJECT_TYPE_MAXIMUM] = {
|
||
|
NULL, // OBJECT_TYPE_ROOT
|
||
|
NULL, // OBJECT_TYPE_ADMIN_MANAGER
|
||
|
NULL, // OBJECT_TYPE_APPLICATION
|
||
|
&AzpOperationSetProperty, // OBJECT_TYPE_OPERATION
|
||
|
&AzpTaskSetProperty, // OBJECT_TYPE_TASK
|
||
|
NULL, // OBJECT_TYPE_SCOPE
|
||
|
&AzpGroupSetProperty, // OBJECT_TYPE_GROUP
|
||
|
NULL, // OBJECT_TYPE_ROLE
|
||
|
&AzpJunctionPointSetProperty, // OBJECT_TYPE_JUNCTION_POINT
|
||
|
NULL, // OBJECT_TYPE_SID
|
||
|
NULL, // OBJECT_TYPE_CLIENT_CONTEXT
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Table of object specific AddPropertyItem routines
|
||
|
//
|
||
|
// Specifies a routine to call to add property type specific fields.
|
||
|
//
|
||
|
// NULL means there is no object specific action to take
|
||
|
//
|
||
|
|
||
|
OBJECT_ADD_PROPERTY_ITEM_ROUTINE *ObjectAddPropertyItemRoutine[OBJECT_TYPE_MAXIMUM] = {
|
||
|
NULL, // OBJECT_TYPE_ROOT
|
||
|
NULL, // OBJECT_TYPE_ADMIN_MANAGER
|
||
|
NULL, // OBJECT_TYPE_APPLICATION
|
||
|
NULL, // OBJECT_TYPE_OPERATION
|
||
|
NULL, // OBJECT_TYPE_TASK
|
||
|
NULL, // OBJECT_TYPE_SCOPE
|
||
|
&AzpGroupAddPropertyItem, // OBJECT_TYPE_GROUP
|
||
|
NULL, // OBJECT_TYPE_ROLE
|
||
|
&AzpJunctionPointAddPropertyItem, // OBJECT_TYPE_JUNCTION_POINT
|
||
|
NULL, // OBJECT_TYPE_SID
|
||
|
NULL, // OBJECT_TYPE_CLIENT_CONTEXT
|
||
|
};
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ObInitGenericHead(
|
||
|
IN PGENERIC_OBJECT_HEAD GenericObjectHead,
|
||
|
IN ULONG ObjectType,
|
||
|
IN PGENERIC_OBJECT ParentGenericObject,
|
||
|
IN PGENERIC_OBJECT_HEAD SiblingGenericObjectHead OPTIONAL,
|
||
|
IN PGENERIC_OBJECT_HEAD SharedNamespace OPTIONAL
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Initialize the head of a list of generic objects
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObjectHead - Specifies the list head to initialize
|
||
|
|
||
|
ObjectType - Specifies the type of objects in the list
|
||
|
|
||
|
ParentGenericObject - Specifies a back link to parent generic object
|
||
|
that host the object head being initialized.
|
||
|
|
||
|
SiblingGenericObjectHead - Specifies a pointer to an object head that
|
||
|
is a sibling of the one being initialized.
|
||
|
|
||
|
SharedNamespace - Specifies a pointer to an object head that shares
|
||
|
a namespace with the objects in the list being initialized.
|
||
|
The structure pointed to by SharedNamespace must already be initialized.
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Initialize the linked list
|
||
|
//
|
||
|
|
||
|
InitializeListHead( &GenericObjectHead->Head );
|
||
|
|
||
|
//
|
||
|
// Initialize the sequence number
|
||
|
// Start at 1 since a zero EnumerationContext means beginning of list.
|
||
|
//
|
||
|
|
||
|
GenericObjectHead->NextSequenceNumber = 1;
|
||
|
|
||
|
//
|
||
|
// Initialize the list of shared namespaces
|
||
|
//
|
||
|
|
||
|
if ( SharedNamespace == NULL ) {
|
||
|
InitializeListHead( &GenericObjectHead->SharedNamespace );
|
||
|
} else {
|
||
|
InsertHeadList( &SharedNamespace->SharedNamespace, &GenericObjectHead->SharedNamespace );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Store the ObjectType
|
||
|
//
|
||
|
|
||
|
GenericObjectHead->ObjectType = ObjectType;
|
||
|
|
||
|
//
|
||
|
// Store the back pointer to the parent generic object
|
||
|
//
|
||
|
|
||
|
GenericObjectHead->ParentGenericObject = ParentGenericObject;
|
||
|
|
||
|
//
|
||
|
// Store the link to the next Generic head
|
||
|
//
|
||
|
|
||
|
GenericObjectHead->SiblingGenericObjectHead = SiblingGenericObjectHead;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ObFreeGenericHead(
|
||
|
IN PGENERIC_OBJECT_HEAD GenericObjectHead
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Free any ojects on a generic head structure
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObjectHead - Specifies the list head to free
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PLIST_ENTRY ListEntry;
|
||
|
PGENERIC_OBJECT GenericObject;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Walk the list of child objects dereferencing each.
|
||
|
//
|
||
|
|
||
|
while ( !IsListEmpty( &GenericObjectHead->Head ) ) {
|
||
|
|
||
|
//
|
||
|
// Remove the entry from the list
|
||
|
//
|
||
|
|
||
|
ListEntry = RemoveHeadList( &GenericObjectHead->Head );
|
||
|
|
||
|
GenericObject = CONTAINING_RECORD( ListEntry,
|
||
|
GENERIC_OBJECT,
|
||
|
Next );
|
||
|
|
||
|
ObDereferenceObject( GenericObject );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Remove ourselves from the shared namespace list
|
||
|
//
|
||
|
|
||
|
RemoveEntryList( &GenericObjectHead->SharedNamespace );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
PGENERIC_OBJECT
|
||
|
ObAllocateGenericObject(
|
||
|
IN ULONG ObjectType,
|
||
|
IN PAZP_STRING ObjectName
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Allocate memory for the private object structure of the specified type
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
ObjectType - Specifies the type of object to create
|
||
|
|
||
|
ObjectName - Name of the object
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
Returns a pointer to the allocated object. The caller should dereference the
|
||
|
returned object by calling ObDereferenceObject.
|
||
|
|
||
|
NULL: not enough memory
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT GenericObject;
|
||
|
ULONG BaseSize;
|
||
|
|
||
|
//
|
||
|
// Ensure the object is supported
|
||
|
//
|
||
|
|
||
|
if ( ObjectType > OBJECT_TYPE_MAXIMUM ||
|
||
|
SpecificObjectSize[ObjectType] == 0 ) {
|
||
|
|
||
|
ASSERT( ObjectType <= OBJECT_TYPE_MAXIMUM );
|
||
|
ASSERT( SpecificObjectSize[ObjectType] != 0 );
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BaseSize = SpecificObjectSize[ObjectType];
|
||
|
ASSERT( BaseSize >= sizeof(GENERIC_OBJECT) );
|
||
|
|
||
|
//
|
||
|
// Allocate the memory
|
||
|
//
|
||
|
|
||
|
GenericObject = (PGENERIC_OBJECT) AzpAllocateHeap( BaseSize );
|
||
|
|
||
|
if ( GenericObject == NULL ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize it
|
||
|
//
|
||
|
|
||
|
RtlZeroMemory( GenericObject, BaseSize );
|
||
|
|
||
|
InitializeListHead( &GenericObject->Next );
|
||
|
GenericObject->ObjectType = ObjectType;
|
||
|
|
||
|
GenericObject->ReferenceCount = 1;
|
||
|
AzPrint(( AZD_REF, "0x%lx %ld (%ld): Allocate object\n", GenericObject, GenericObject->ObjectType, GenericObject->ReferenceCount ));
|
||
|
|
||
|
//
|
||
|
// Initialize the string name
|
||
|
//
|
||
|
|
||
|
WinStatus = AzpDuplicateString( &GenericObject->ObjectName, ObjectName );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
AzpFreeHeap( GenericObject );
|
||
|
GenericObject = NULL;
|
||
|
}
|
||
|
|
||
|
return GenericObject;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ObFreeGenericObject(
|
||
|
IN PGENERIC_OBJECT GenericObject,
|
||
|
IN BOOLEAN JustRefresh
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Free memory for the private object structure of the specified type
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObject - Specifies the pointer to the generic object to free
|
||
|
|
||
|
JustRefresh - TRUE if only those attributes that can be refreshed from the
|
||
|
policy store are to be freed.
|
||
|
FALSE if all attributes are to be freed.
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PGENERIC_OBJECT_HEAD ChildGenericObjectHead;
|
||
|
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
if ( !JustRefresh ) {
|
||
|
ASSERT( GenericObject->HandleReferenceCount == 0 );
|
||
|
ASSERT( GenericObject->ReferenceCount == 0 );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Delink the entry from the parent
|
||
|
//
|
||
|
|
||
|
if ( !JustRefresh ) {
|
||
|
RemoveEntryList( &GenericObject->Next );
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Call the routine to do object type specific freeing
|
||
|
//
|
||
|
|
||
|
if ( ObjectFreeRoutine[GenericObject->ObjectType] == NULL ) {
|
||
|
ASSERT( ObjectFreeRoutine[GenericObject->ObjectType] != NULL );
|
||
|
} else {
|
||
|
|
||
|
ObjectFreeRoutine[GenericObject->ObjectType](GenericObject );
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Free children of this object
|
||
|
// Loop for each type of child
|
||
|
//
|
||
|
|
||
|
if ( !JustRefresh ) {
|
||
|
for ( ChildGenericObjectHead = GenericObject->ChildGenericObjectHead;
|
||
|
ChildGenericObjectHead != NULL;
|
||
|
ChildGenericObjectHead = ChildGenericObjectHead->SiblingGenericObjectHead ) {
|
||
|
|
||
|
ObFreeGenericHead( ChildGenericObjectHead );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Remove all references to/from this object
|
||
|
// If we're just refreshing, only remove the forward links
|
||
|
//
|
||
|
|
||
|
ObRemoveObjectListLinks( GenericObject, !JustRefresh );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free the fields
|
||
|
// Leave the name on 'JustRefresh' to support lookups by name.
|
||
|
//
|
||
|
|
||
|
if ( !JustRefresh ) {
|
||
|
AzpFreeString( &GenericObject->ObjectName );
|
||
|
}
|
||
|
AzpFreeString( &GenericObject->Description );
|
||
|
|
||
|
//
|
||
|
// Free the object itself
|
||
|
//
|
||
|
|
||
|
if ( !JustRefresh ) {
|
||
|
AzpFreeHeap( GenericObject );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ObInsertGenericObject(
|
||
|
IN PGENERIC_OBJECT_HEAD ParentGenericObjectHead,
|
||
|
IN PGENERIC_OBJECT ChildGenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Insert the specified object into the specified list.
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
ParentGenericObjectHead - Specifies the list head of the list to insert into
|
||
|
|
||
|
ChildGenericObject - Specifies the object to insert into the list
|
||
|
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Set the sequence number
|
||
|
//
|
||
|
|
||
|
ChildGenericObject->SequenceNumber = ParentGenericObjectHead->NextSequenceNumber;
|
||
|
ParentGenericObjectHead->NextSequenceNumber ++;
|
||
|
|
||
|
//
|
||
|
// Insert the object
|
||
|
// Insert at the tail to keep the list in sequence number order.
|
||
|
//
|
||
|
|
||
|
ASSERT( ParentGenericObjectHead->ObjectType == ChildGenericObject->ObjectType );
|
||
|
InsertTailList( &ParentGenericObjectHead->Head, &ChildGenericObject->Next );
|
||
|
|
||
|
//
|
||
|
// Provide a back link
|
||
|
//
|
||
|
|
||
|
ASSERT( ChildGenericObject->ParentGenericObjectHead == NULL );
|
||
|
ChildGenericObject->ParentGenericObjectHead = ParentGenericObjectHead;
|
||
|
|
||
|
//
|
||
|
// Increment the reference count to ensure the object isn't deleted
|
||
|
//
|
||
|
|
||
|
InterlockedIncrement( &ChildGenericObject->ReferenceCount );
|
||
|
AzPrint(( AZD_REF, "0x%lx %ld (%ld): Insert object\n", ChildGenericObject, ChildGenericObject->ObjectType, ChildGenericObject->ReferenceCount ));
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ObIncrHandleRefCount(
|
||
|
IN PGENERIC_OBJECT GenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Increment the "handle" reference count on an object.
|
||
|
|
||
|
On entry, AzGlResource must be locked shared.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObject - Specifies the object to insert into the list
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedShared( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Keep a reference to our parent object.
|
||
|
// We validate the handle by inspecting walking the list of children in our parent.
|
||
|
// So, prevent our parent from being deleted as long as the user has a handle to the child.
|
||
|
//
|
||
|
|
||
|
if ( GenericObject->ParentGenericObjectHead->ParentGenericObject != NULL ) {
|
||
|
InterlockedIncrement ( &GenericObject->ParentGenericObjectHead->ParentGenericObject->ReferenceCount );
|
||
|
AzPrint(( AZD_REF, "0x%lx %ld (%ld): Child handle ref\n", GenericObject->ParentGenericObjectHead->ParentGenericObject, GenericObject->ParentGenericObjectHead->ParentGenericObject->ObjectType, GenericObject->ParentGenericObjectHead->ParentGenericObject->ReferenceCount ));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The handle ref count is a real ref count. Increment it too.
|
||
|
//
|
||
|
|
||
|
InterlockedIncrement( &GenericObject->ReferenceCount );
|
||
|
AzPrint(( AZD_REF, "0x%lx %ld (%ld): Handle ref\n", GenericObject, GenericObject->ObjectType, GenericObject->ReferenceCount ));
|
||
|
|
||
|
//
|
||
|
// Increment the handle ref count
|
||
|
//
|
||
|
|
||
|
InterlockedIncrement( &GenericObject->HandleReferenceCount );
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld (%ld): Open Handle\n", GenericObject, GenericObject->ObjectType, GenericObject->HandleReferenceCount ));
|
||
|
|
||
|
//
|
||
|
// Increment the total handle reference count on the entire tree of objects
|
||
|
//
|
||
|
InterlockedIncrement( &GenericObject->AdminManagerObject->TotalHandleReferenceCount );
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ObDecrHandleRefCount(
|
||
|
IN PGENERIC_OBJECT GenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Decrement the "handle" reference count on an object.
|
||
|
|
||
|
On entry, AzGlResource must be locked shared.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObject - Specifies the object to insert into the list
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedShared( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Decrement the handle ref count
|
||
|
//
|
||
|
|
||
|
InterlockedDecrement( &GenericObject->HandleReferenceCount );
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld (%ld): Close Handle\n", GenericObject, GenericObject->ObjectType, GenericObject->HandleReferenceCount ));
|
||
|
|
||
|
//
|
||
|
// Decrement the total handle reference count on the entire tree of objects
|
||
|
//
|
||
|
InterlockedDecrement( &GenericObject->AdminManagerObject->TotalHandleReferenceCount );
|
||
|
|
||
|
//
|
||
|
// The handle ref count is a real ref count. Decrement it too.
|
||
|
//
|
||
|
|
||
|
ObDereferenceObject( GenericObject );
|
||
|
|
||
|
//
|
||
|
// Finally, decrement the ref count we have on our parent.
|
||
|
//
|
||
|
|
||
|
if ( GenericObject->ParentGenericObjectHead->ParentGenericObject != NULL ) {
|
||
|
ObDereferenceObject( GenericObject->ParentGenericObjectHead->ParentGenericObject );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObGetHandleType(
|
||
|
IN PGENERIC_OBJECT Handle,
|
||
|
IN BOOL AllowDeletedObjects,
|
||
|
OUT PULONG ObjectType
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
This routine takes a handle passed by an application and safely determines what the
|
||
|
handle type is.
|
||
|
|
||
|
This routine allows a caller to support various handle types rather than being
|
||
|
limited to one.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
Handle - Handle to check
|
||
|
|
||
|
AllowDeletedObjects - TRUE if it is OK to use a handle to a deleted object
|
||
|
|
||
|
ObjectType - Returns the type of object the handle represents
|
||
|
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
NO_ERROR - the handle is OK
|
||
|
ERROR_INVALID_HANDLE - the handle isn't OK
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
PGENERIC_OBJECT GenericObject = Handle;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
if ( Handle == NULL ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx: NULL handle is invalid\n", Handle ));
|
||
|
return ERROR_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Use a try/except since we're touching memory assuming the handle is valid
|
||
|
//
|
||
|
|
||
|
WinStatus = NO_ERROR;
|
||
|
__try {
|
||
|
|
||
|
//
|
||
|
// Sanity check the scalar values on the object
|
||
|
//
|
||
|
|
||
|
if ( GenericObject->ObjectType >= OBJECT_TYPE_MAXIMUM ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld: Handle Object type is too large.\n", GenericObject, GenericObject->ObjectType ));
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
|
||
|
} else if ( GenericObject->HandleReferenceCount <= 0 ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld: Handle has no handle reference count.\n", GenericObject, GenericObject->ObjectType ));
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
|
||
|
} else if ( GenericObject->ParentGenericObjectHead == NULL ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld: Handle has no ParentGenericObjectHead.\n", GenericObject, GenericObject->ObjectType ));
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
|
||
|
} else if ( !AllowDeletedObjects &&
|
||
|
(GenericObject->Flags & GENOBJ_FLAGS_DELETED) != 0 ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld: Object is deleted.\n", GenericObject, GenericObject->ObjectType ));
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
|
||
|
} else {
|
||
|
PGENERIC_OBJECT_HEAD ParentGenericObjectHead = GenericObject->ParentGenericObjectHead;
|
||
|
|
||
|
//
|
||
|
// Sanity check the object with its head
|
||
|
//
|
||
|
|
||
|
if ( ParentGenericObjectHead->ObjectType != GenericObject->ObjectType ) {
|
||
|
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld: Object type doesn't match parent.\n", GenericObject, GenericObject->ObjectType ));
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
|
||
|
} else if ( GenericObject->SequenceNumber >= ParentGenericObjectHead->NextSequenceNumber ) {
|
||
|
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld: Sequence number doesn't match parent.\n", GenericObject, GenericObject->ObjectType ));
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
*ObjectType = GenericObject->ObjectType;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx: AV accessing handle\n", GenericObject ));
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObReferenceObjectByName(
|
||
|
IN PGENERIC_OBJECT_HEAD GenericObjectHead,
|
||
|
IN PAZP_STRING ObjectName,
|
||
|
IN BOOLEAN RefreshCache,
|
||
|
OUT PGENERIC_OBJECT *RetGenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
This routine finds an object by the specified name.
|
||
|
|
||
|
On entry, AzGlResource must be locked shared.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObjectHead - Head of the list of objects to check
|
||
|
|
||
|
ObjectName - Object Name of the object to look for
|
||
|
|
||
|
RefreshCache - If TRUE, the returned object has its cache entry refreshed from
|
||
|
the policy database if needed.
|
||
|
If FALSE, the entry is returned unrefreshed.
|
||
|
|
||
|
RetGenericObject - On success, returns a pointer to the object
|
||
|
The returned pointer must be dereferenced using ObDereferenceObject.
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
NO_ERROR: The object was returned
|
||
|
ERROR_NOT_FOUND: The object could not be found
|
||
|
Others: The object could not be refreshed
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
PGENERIC_OBJECT GenericObject;
|
||
|
PLIST_ENTRY ListEntry;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedShared( &AzGlResource ) );
|
||
|
*RetGenericObject = NULL;
|
||
|
|
||
|
//
|
||
|
// Loop trying to find the named object
|
||
|
//
|
||
|
|
||
|
for ( ListEntry = GenericObjectHead->Head.Flink ;
|
||
|
ListEntry != &GenericObjectHead->Head ;
|
||
|
ListEntry = ListEntry->Flink) {
|
||
|
|
||
|
GenericObject = CONTAINING_RECORD( ListEntry,
|
||
|
GENERIC_OBJECT,
|
||
|
Next );
|
||
|
|
||
|
//
|
||
|
// Ignore deleted objects
|
||
|
//
|
||
|
|
||
|
if ( GenericObject->Flags & GENOBJ_FLAGS_DELETED ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we found the object,
|
||
|
// grab a reference.
|
||
|
//
|
||
|
if ( AzpEqualStrings( &GenericObject->ObjectName, ObjectName ) ) {
|
||
|
|
||
|
//
|
||
|
// If the caller wants the object to be refreshed,
|
||
|
// do so now.
|
||
|
//
|
||
|
|
||
|
if ( RefreshCache &&
|
||
|
(GenericObject->Flags & GENOBJ_FLAGS_REFRESH_ME) != 0 ) {
|
||
|
|
||
|
//
|
||
|
// Need exclusive access
|
||
|
//
|
||
|
|
||
|
AzpLockResourceSharedToExclusive( &AzGlResource );
|
||
|
|
||
|
WinStatus = AzpPersistRefresh( GenericObject );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
return WinStatus;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the object to the caller
|
||
|
//
|
||
|
|
||
|
InterlockedIncrement( &GenericObject->ReferenceCount );
|
||
|
AzPrint(( AZD_REF, "0x%lx %ld (%ld): Ref by name\n", GenericObject, GenericObject->ObjectType, GenericObject->ReferenceCount ));
|
||
|
|
||
|
*RetGenericObject = GenericObject;
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ERROR_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObReferenceObjectByHandle(
|
||
|
IN PGENERIC_OBJECT Handle,
|
||
|
IN BOOL AllowDeletedObjects,
|
||
|
IN BOOLEAN RefreshCache,
|
||
|
IN ULONG ObjectType
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
This routine takes a handle passed by an application and safely determines whether
|
||
|
it is a valid handle. If so, this routine increments the reference count on the
|
||
|
handle to prevent the handle from being closed.
|
||
|
|
||
|
On entry, AzGlResource must be locked shared.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
Handle - Handle to check
|
||
|
|
||
|
AllowDeletedObjects - TRUE if it is OK to use a handle to a deleted object
|
||
|
|
||
|
RefreshCache - If TRUE, the returned object has its cache entry refreshed from
|
||
|
the policy database if needed.
|
||
|
If FALSE, the entry is returned unrefreshed.
|
||
|
|
||
|
ObjectType - Specifies the type of object the caller expects the handle to be
|
||
|
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
NO_ERROR - the handle is OK
|
||
|
ERROR_INVALID_HANDLE - the handle isn't OK
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
PGENERIC_OBJECT GenericObject = Handle;
|
||
|
ULONG LocalObjectType;
|
||
|
|
||
|
PGENERIC_OBJECT Current;
|
||
|
PLIST_ENTRY ListEntry;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedShared( &AzGlResource ) );
|
||
|
|
||
|
if ( Handle == NULL ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx: NULL handle not allowed.\n", NULL ));
|
||
|
return ERROR_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Use a try/except since we're touching memory assuming the handle is valid
|
||
|
//
|
||
|
|
||
|
__try {
|
||
|
|
||
|
|
||
|
WinStatus = ObGetHandleType( Handle, AllowDeletedObjects, &LocalObjectType );
|
||
|
|
||
|
if ( WinStatus == NO_ERROR ) {
|
||
|
|
||
|
if ( ObjectType != LocalObjectType ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld: Object Type not local object type\n", GenericObject, GenericObject->ObjectType ));
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
} else {
|
||
|
PGENERIC_OBJECT_HEAD ParentGenericObjectHead = GenericObject->ParentGenericObjectHead;
|
||
|
|
||
|
//
|
||
|
// Ensure the object is actually in the list
|
||
|
//
|
||
|
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
for ( ListEntry = ParentGenericObjectHead->Head.Flink ;
|
||
|
ListEntry != &ParentGenericObjectHead->Head ;
|
||
|
ListEntry = ListEntry->Flink) {
|
||
|
|
||
|
Current = CONTAINING_RECORD( ListEntry,
|
||
|
GENERIC_OBJECT,
|
||
|
Next );
|
||
|
|
||
|
//
|
||
|
// If we found the object,
|
||
|
// grab a reference.
|
||
|
//
|
||
|
if ( Current == GenericObject ) {
|
||
|
|
||
|
//
|
||
|
// If the caller wants the object to be refreshed,
|
||
|
// do so now.
|
||
|
//
|
||
|
|
||
|
if ( RefreshCache &&
|
||
|
(GenericObject->Flags & GENOBJ_FLAGS_REFRESH_ME) != 0 ) {
|
||
|
|
||
|
//
|
||
|
// Need exclusive access
|
||
|
//
|
||
|
|
||
|
AzpLockResourceSharedToExclusive( &AzGlResource );
|
||
|
|
||
|
WinStatus = AzpPersistRefresh( GenericObject );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Grab a reference to the object
|
||
|
//
|
||
|
|
||
|
InterlockedIncrement( &GenericObject->ReferenceCount );
|
||
|
AzPrint(( AZD_REF, "0x%lx %ld (%ld): Ref by Handle\n", GenericObject, GenericObject->ObjectType, GenericObject->ReferenceCount ));
|
||
|
WinStatus = NO_ERROR;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If not,
|
||
|
// the handle is invalid.
|
||
|
//
|
||
|
|
||
|
if ( WinStatus == ERROR_INVALID_HANDLE ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx %ld: Handle not in list.\n", GenericObject, GenericObject->ObjectType ));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
AzPrint(( AZD_HANDLE, "0x%lx: AV accessing handle\n", GenericObject ));
|
||
|
WinStatus = ERROR_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ObDereferenceObject(
|
||
|
IN PGENERIC_OBJECT GenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Decrement the reference count on an object.
|
||
|
|
||
|
When the last reference count is removed, delete the object.
|
||
|
|
||
|
On entry, AzGlResource must be locked shared. If the ref count reaches zero,
|
||
|
AzGlResource must be locked exclusively. We can get away with that because
|
||
|
we force the ref count to zero only when closing the AdminManager object.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObject - Specifies the object to insert into the list
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG RefCount;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedShared( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Decrement the reference count
|
||
|
//
|
||
|
|
||
|
RefCount = InterlockedDecrement( &GenericObject->ReferenceCount );
|
||
|
AzPrint(( AZD_REF, "0x%lx %ld (%ld): Deref\n", GenericObject, GenericObject->ObjectType, GenericObject->ReferenceCount ));
|
||
|
|
||
|
//
|
||
|
// Check if the object is no longer referenced
|
||
|
//
|
||
|
|
||
|
if ( RefCount == 0 ) {
|
||
|
|
||
|
//
|
||
|
// Grab the lock exclusively
|
||
|
//
|
||
|
|
||
|
ASSERT( GenericObject->HandleReferenceCount == 0 );
|
||
|
AzpLockResourceSharedToExclusive( &AzGlResource );
|
||
|
|
||
|
//
|
||
|
// Free the object itself
|
||
|
//
|
||
|
|
||
|
ObFreeGenericObject( GenericObject, FALSE );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObCreateObject(
|
||
|
IN PGENERIC_OBJECT ParentGenericObject,
|
||
|
IN PGENERIC_OBJECT_HEAD GenericChildHead,
|
||
|
IN ULONG ChildObjectType,
|
||
|
IN PAZP_STRING ChildObjectNameString,
|
||
|
OUT PGENERIC_OBJECT *RetChildGenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates a child object in the scope of the specified parent object.
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ParentGenericObject - Specifies the parent object to add the child object onto.
|
||
|
be verified.
|
||
|
|
||
|
GenericChildHead - Specifies a pointer to the head of the list of children of
|
||
|
ParentGenericObject.
|
||
|
|
||
|
ChildObjectType - Specifies the object type RetChildGenericObject.
|
||
|
|
||
|
ChildObjectNameString - Specifies the name of the child object.
|
||
|
This name must be unique at the current scope.
|
||
|
|
||
|
RetChildGenericObject - Returns a pointer to the allocated generic child object
|
||
|
This pointer must be dereferenced using ObDereferenceObject.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful
|
||
|
|
||
|
ERROR_ALREADY_EXISTS - An object by that name already exists
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT_HEAD CurrentObjectHead;
|
||
|
PGENERIC_OBJECT ChildGenericObject = NULL;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( ChildObjectType != OBJECT_TYPE_ROOT );
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Do duplicate detection
|
||
|
//
|
||
|
// Loop through all of the lists that share a namespace
|
||
|
//
|
||
|
|
||
|
CurrentObjectHead = GenericChildHead;
|
||
|
for (;;) {
|
||
|
PLIST_ENTRY ListEntry;
|
||
|
|
||
|
//
|
||
|
// Ensure the new name doesn't exist in the current list
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByName( CurrentObjectHead,
|
||
|
ChildObjectNameString,
|
||
|
FALSE, // No need to refresh the cache
|
||
|
&ChildGenericObject );
|
||
|
|
||
|
if ( WinStatus == NO_ERROR ) {
|
||
|
WinStatus = ERROR_ALREADY_EXISTS;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we've tried all of the lists,
|
||
|
// we're done.
|
||
|
//
|
||
|
|
||
|
ListEntry = CurrentObjectHead->SharedNamespace.Flink;
|
||
|
CurrentObjectHead = CONTAINING_RECORD( ListEntry,
|
||
|
GENERIC_OBJECT_HEAD,
|
||
|
SharedNamespace );
|
||
|
|
||
|
if ( CurrentObjectHead == GenericChildHead ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Allocate the structure to return to the caller
|
||
|
//
|
||
|
|
||
|
ChildGenericObject = ObAllocateGenericObject( ChildObjectType, ChildObjectNameString );
|
||
|
|
||
|
if ( ChildGenericObject == NULL ) {
|
||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Keep a pointer to the object at the root of the tree
|
||
|
// Back pointers don't increment reference count.
|
||
|
//
|
||
|
|
||
|
if ( ChildObjectType == OBJECT_TYPE_ADMIN_MANAGER ) {
|
||
|
ChildGenericObject->AdminManagerObject = (PAZP_ADMIN_MANAGER) ChildGenericObject;
|
||
|
} else {
|
||
|
ChildGenericObject->AdminManagerObject = (PAZP_ADMIN_MANAGER)
|
||
|
ParentGenericObject->AdminManagerObject;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Call the routine to do object type specific initialization
|
||
|
//
|
||
|
|
||
|
if ( ObjectInitRoutine[ChildObjectType] == NULL ) {
|
||
|
ASSERT( ObjectInitRoutine[ChildObjectType] != NULL );
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
WinStatus = ObjectInitRoutine[ChildObjectType](
|
||
|
ParentGenericObject,
|
||
|
ChildGenericObject );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Insert the child into the list of children for this parent
|
||
|
//
|
||
|
|
||
|
ObInsertGenericObject( GenericChildHead, ChildGenericObject );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Return the pointer to the new structure
|
||
|
//
|
||
|
|
||
|
*RetChildGenericObject = ChildGenericObject;
|
||
|
|
||
|
WinStatus = NO_ERROR;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
if ( WinStatus != NO_ERROR && ChildGenericObject != NULL ) {
|
||
|
ObDereferenceObject( ChildGenericObject );
|
||
|
}
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObCommonCreateObject(
|
||
|
IN PGENERIC_OBJECT ParentGenericObject,
|
||
|
IN ULONG ParentObjectType,
|
||
|
IN PGENERIC_OBJECT_HEAD GenericChildHead,
|
||
|
IN ULONG ChildObjectType,
|
||
|
IN LPCWSTR ChildObjectName,
|
||
|
IN DWORD Reserved,
|
||
|
OUT PGENERIC_OBJECT *RetChildGenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates a child object in the scope of the specified parent object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ParentGenericObject - Specifies a handle to the parent object to add the child
|
||
|
object onto. This "handle" has been passed from the application and needs to
|
||
|
be verified.
|
||
|
|
||
|
ParentObjectType - Specifies the object type ParentGenericObject.
|
||
|
|
||
|
GenericChildHead - Specifies a pointer to the head of the list of children of
|
||
|
ParentGenericObject. This is a computed pointer and is considered untrustworthy
|
||
|
until ParentGenericObject has been verified.
|
||
|
|
||
|
ChildObjectType - Specifies the object type RetChildGenericObject.
|
||
|
|
||
|
ChildObjectName - Specifies the name of the child object.
|
||
|
This name must be unique at the current scope.
|
||
|
This name is passed from the application and needs to be verified.
|
||
|
|
||
|
Reserved - Reserved. Must by zero.
|
||
|
|
||
|
RetChildGenericObject - Return a handle to the generic child object
|
||
|
The caller must close this handle by calling AzCloseHandle.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful
|
||
|
|
||
|
ERROR_ALREADY_EXISTS - An object by that name already exists
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT ReferencedParentObject = NULL;
|
||
|
PGENERIC_OBJECT ChildGenericObject = NULL;
|
||
|
AZP_STRING ChildObjectNameString;
|
||
|
|
||
|
//
|
||
|
// Grab the global lock
|
||
|
//
|
||
|
|
||
|
ASSERT( ParentObjectType != OBJECT_TYPE_ROOT );
|
||
|
ASSERT( ChildObjectType != OBJECT_TYPE_ADMIN_MANAGER );
|
||
|
AzpLockResourceExclusive( &AzGlResource );
|
||
|
AzpInitString( &ChildObjectNameString, NULL );
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
__try {
|
||
|
*RetChildGenericObject = NULL;
|
||
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
|
||
|
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the input parameters
|
||
|
//
|
||
|
if ( Reserved != 0 ) {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonCreateObject: Reserved != 0\n" ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the passed in handle
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByHandle( ParentGenericObject,
|
||
|
FALSE, // Don't allow deleted objects
|
||
|
TRUE, // Refresh the cache
|
||
|
ParentObjectType );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ReferencedParentObject = ParentGenericObject;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Capture the object name string from the caller
|
||
|
//
|
||
|
|
||
|
WinStatus = AzpCaptureString( &ChildObjectNameString,
|
||
|
ChildObjectName,
|
||
|
MaxObjectNameLength[ChildObjectType],
|
||
|
FALSE ); // NULL names not OK
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create the object
|
||
|
//
|
||
|
|
||
|
WinStatus = ObCreateObject(
|
||
|
ParentGenericObject,
|
||
|
GenericChildHead,
|
||
|
ChildObjectType,
|
||
|
&ChildObjectNameString,
|
||
|
&ChildGenericObject );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Mark the object as needing to be written
|
||
|
//
|
||
|
|
||
|
ChildGenericObject->Flags |= GENOBJ_FLAGS_DIRTY;
|
||
|
|
||
|
//
|
||
|
// Return the handle to the caller
|
||
|
//
|
||
|
|
||
|
ObIncrHandleRefCount( ChildGenericObject );
|
||
|
*RetChildGenericObject = ChildGenericObject;
|
||
|
|
||
|
WinStatus = NO_ERROR;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
if ( ReferencedParentObject != NULL ) {
|
||
|
ObDereferenceObject( ReferencedParentObject );
|
||
|
}
|
||
|
|
||
|
if ( ChildGenericObject != NULL ) {
|
||
|
ObDereferenceObject( ChildGenericObject );
|
||
|
}
|
||
|
AzpFreeString( &ChildObjectNameString );
|
||
|
|
||
|
//
|
||
|
// Drop the global lock
|
||
|
//
|
||
|
|
||
|
AzpUnlockResource( &AzGlResource );
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObCommonOpenObject(
|
||
|
IN PGENERIC_OBJECT ParentGenericObject,
|
||
|
IN ULONG ParentObjectType,
|
||
|
IN PGENERIC_OBJECT_HEAD GenericChildHead,
|
||
|
IN ULONG ChildObjectType,
|
||
|
IN LPCWSTR ChildObjectName,
|
||
|
IN DWORD Reserved,
|
||
|
OUT PGENERIC_OBJECT *RetChildGenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine opens a child object in the scope of the specified parent object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ParentGenericObject - Specifies a handle to the parent object to open the child
|
||
|
object from. This "handle" has been passed from the application and needs to
|
||
|
be verified.
|
||
|
|
||
|
ParentObjectType - Specifies the object type ParentGenericObject.
|
||
|
|
||
|
GenericChildHead - Specifies a pointer to the head of the list of children of
|
||
|
ParentGenericObject. This is a computed pointer and is considered untrustworthy
|
||
|
until ParentGenericObject has been verified.
|
||
|
|
||
|
ChildObjectType - Specifies the object type RetChildGenericObject.
|
||
|
|
||
|
ChildObjectName - Specifies the name of the child object.
|
||
|
This name is passed from the application and needs to be verified.
|
||
|
|
||
|
Reserved - Reserved. Must by zero.
|
||
|
|
||
|
RetChildGenericObject - Return a handle to the generic child object
|
||
|
The caller must close this handle by calling AzCloseHandle.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful
|
||
|
|
||
|
ERROR_NOT_FOUND - There is no object by that name
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT ReferencedParentObject = NULL;
|
||
|
PGENERIC_OBJECT ChildGenericObject = NULL;
|
||
|
|
||
|
AZP_STRING ChildObjectNameString;
|
||
|
|
||
|
//
|
||
|
// Grab the global lock
|
||
|
//
|
||
|
|
||
|
AzpLockResourceShared( &AzGlResource );
|
||
|
ASSERT( ParentObjectType != OBJECT_TYPE_ROOT );
|
||
|
ASSERT( ChildObjectType != OBJECT_TYPE_ADMIN_MANAGER );
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
AzpInitString( &ChildObjectNameString, NULL );
|
||
|
__try {
|
||
|
*RetChildGenericObject = NULL;
|
||
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
|
||
|
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the input parameters
|
||
|
//
|
||
|
if ( Reserved != 0 ) {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonOpenObject: Reserved != 0\n" ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the passed in handle
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByHandle( ParentGenericObject,
|
||
|
FALSE, // Don't allow deleted objects
|
||
|
TRUE, // Refresh the cache
|
||
|
ParentObjectType );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ReferencedParentObject = ParentGenericObject;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Capture the object name string from the caller
|
||
|
//
|
||
|
|
||
|
WinStatus = AzpCaptureString( &ChildObjectNameString,
|
||
|
ChildObjectName,
|
||
|
MaxObjectNameLength[ChildObjectType],
|
||
|
FALSE ); // NULL names not OK
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Find the named object
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByName( GenericChildHead,
|
||
|
&ChildObjectNameString,
|
||
|
TRUE, // Refresh the cache for this object
|
||
|
&ChildGenericObject );
|
||
|
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Return the handle to the caller
|
||
|
//
|
||
|
|
||
|
ObIncrHandleRefCount( ChildGenericObject );
|
||
|
*RetChildGenericObject = ChildGenericObject;
|
||
|
|
||
|
WinStatus = NO_ERROR;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
if ( ReferencedParentObject != NULL ) {
|
||
|
ObDereferenceObject( ReferencedParentObject );
|
||
|
}
|
||
|
|
||
|
if ( ChildGenericObject != NULL ) {
|
||
|
ObDereferenceObject( ChildGenericObject );
|
||
|
}
|
||
|
|
||
|
AzpFreeString( &ChildObjectNameString );
|
||
|
|
||
|
//
|
||
|
// Drop the global lock
|
||
|
//
|
||
|
|
||
|
AzpUnlockResource( &AzGlResource );
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
ObEnumObjects(
|
||
|
IN PGENERIC_OBJECT_HEAD GenericChildHead,
|
||
|
IN BOOL EnumerateDeletedObjects,
|
||
|
IN BOOL RefreshCache,
|
||
|
IN OUT PULONG EnumerationContext,
|
||
|
OUT PGENERIC_OBJECT *RetChildGenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine enumerates the next child object from the scope of the specified parent object.
|
||
|
|
||
|
On entry, AzGlResource must be locked shared.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericChildHead - Specifies a pointer to the head of the list of children of
|
||
|
ParentGenericObject.
|
||
|
|
||
|
EnumerateDeletedObjects - Specifies whether deleted objects are to be returned
|
||
|
in the enumeration.
|
||
|
|
||
|
RefreshCache - If TRUE, the returned object has its cache entry refreshed from
|
||
|
the policy database if needed.
|
||
|
If FALSE, the entry is returned unrefreshed.
|
||
|
|
||
|
EnumerationContext - Specifies a context indicating the next object to return
|
||
|
On input for the first call, should point to zero.
|
||
|
On input for subsequent calls, should point to the value returned on the previous call.
|
||
|
On output, returns a value to be passed on the next call.
|
||
|
|
||
|
RetChildGenericObject - Returns a pointer to the generic child object
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful (a handle was returned)
|
||
|
|
||
|
ERROR_NO_MORE_ITEMS - No more items were available for enumeration
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PLIST_ENTRY ListEntry;
|
||
|
PGENERIC_OBJECT ChildGenericObject = NULL;
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// If we've already returned the whole list,
|
||
|
// don't bother walking the list.
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedShared( &AzGlResource ) );
|
||
|
|
||
|
if ( *EnumerationContext >= GenericChildHead->NextSequenceNumber ) {
|
||
|
WinStatus = ERROR_NO_MORE_ITEMS;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Walk the list of children finding where we left off
|
||
|
//
|
||
|
|
||
|
for ( ListEntry = GenericChildHead->Head.Flink ;
|
||
|
ListEntry != &GenericChildHead->Head ;
|
||
|
ListEntry = ListEntry->Flink) {
|
||
|
|
||
|
ChildGenericObject = CONTAINING_RECORD( ListEntry,
|
||
|
GENERIC_OBJECT,
|
||
|
Next );
|
||
|
|
||
|
//
|
||
|
// See if this is it
|
||
|
//
|
||
|
|
||
|
if ( ChildGenericObject->SequenceNumber > *EnumerationContext ) {
|
||
|
|
||
|
//
|
||
|
// Ignore deleted object if the caller doesn't want to see them
|
||
|
//
|
||
|
// If this is not a deleted object,
|
||
|
// or the caller wants deleted objects to be returned,
|
||
|
// return it.
|
||
|
//
|
||
|
|
||
|
if ((ChildGenericObject->Flags & GENOBJ_FLAGS_DELETED) == 0 ||
|
||
|
EnumerateDeletedObjects ) {
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
ChildGenericObject = NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we've already returned the whole list,
|
||
|
// indicate so.
|
||
|
//
|
||
|
|
||
|
if ( ChildGenericObject == NULL ) {
|
||
|
WinStatus = ERROR_NO_MORE_ITEMS;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the caller wants the object to be refreshed,
|
||
|
// do so now.
|
||
|
//
|
||
|
|
||
|
if ( RefreshCache &&
|
||
|
(ChildGenericObject->Flags & GENOBJ_FLAGS_REFRESH_ME) != 0 ) {
|
||
|
|
||
|
//
|
||
|
// Need exclusive access
|
||
|
//
|
||
|
|
||
|
AzpLockResourceSharedToExclusive( &AzGlResource );
|
||
|
|
||
|
WinStatus = AzpPersistRefresh( ChildGenericObject );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the handle to the caller
|
||
|
//
|
||
|
|
||
|
*EnumerationContext = ChildGenericObject->SequenceNumber;
|
||
|
*RetChildGenericObject = ChildGenericObject;
|
||
|
|
||
|
WinStatus = NO_ERROR;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
ObCommonEnumObjects(
|
||
|
IN PGENERIC_OBJECT ParentGenericObject,
|
||
|
IN ULONG ParentObjectType,
|
||
|
IN PGENERIC_OBJECT_HEAD GenericChildHead,
|
||
|
IN OUT PULONG EnumerationContext,
|
||
|
IN DWORD Reserved,
|
||
|
OUT PGENERIC_OBJECT *RetChildGenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine enumerates the next child object from the scope of the specified parent object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ParentGenericObject - Specifies a handle to the parent object to enumerate the child
|
||
|
objects of.
|
||
|
This "handle" has been passed from the application and needs to be verified.
|
||
|
|
||
|
ParentObjectType - Specifies the object type ParentGenericObject.
|
||
|
|
||
|
GenericChildHead - Specifies a pointer to the head of the list of children of
|
||
|
ParentGenericObject. This is a computed pointer and is considered untrustworthy
|
||
|
until ParentGenericObject has been verified.
|
||
|
|
||
|
EnumerationContext - Specifies a context indicating the next object to return
|
||
|
On input for the first call, should point to zero.
|
||
|
On input for subsequent calls, should point to the value returned on the previous call.
|
||
|
On output, returns a value to be passed on the next call.
|
||
|
|
||
|
Reserved - Reserved. Must by zero.
|
||
|
|
||
|
RetChildGenericObject - Returns a handle to the generic child object
|
||
|
The caller must close this handle by calling AzpDzCloseHandle.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful (a handle was returned)
|
||
|
|
||
|
ERROR_NO_MORE_ITEMS - No more items were available for enumeration
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT ReferencedParentObject = NULL;
|
||
|
PGENERIC_OBJECT ChildGenericObject = NULL;
|
||
|
|
||
|
//
|
||
|
// Grab the global lock
|
||
|
//
|
||
|
ASSERT( ParentObjectType != OBJECT_TYPE_ROOT );
|
||
|
|
||
|
AzpLockResourceShared( &AzGlResource );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialize the return handle
|
||
|
//
|
||
|
|
||
|
__try {
|
||
|
*RetChildGenericObject = NULL;
|
||
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
|
||
|
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the input parameters
|
||
|
//
|
||
|
if ( Reserved != 0 ) {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonEnumObjects: Reserved != 0\n" ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the passed in handle
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByHandle( ParentGenericObject,
|
||
|
FALSE, // Don't allow deleted objects
|
||
|
TRUE, // Refresh the cache
|
||
|
ParentObjectType );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ReferencedParentObject = ParentGenericObject;
|
||
|
|
||
|
//
|
||
|
// Call the common routine to do the actual enumeration
|
||
|
//
|
||
|
|
||
|
WinStatus = ObEnumObjects( GenericChildHead,
|
||
|
FALSE, // Don't enumerate deleted objects
|
||
|
TRUE, // Refresh the cache
|
||
|
EnumerationContext,
|
||
|
&ChildGenericObject );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the handle to the caller
|
||
|
//
|
||
|
|
||
|
ObIncrHandleRefCount( ChildGenericObject );
|
||
|
*RetChildGenericObject = ChildGenericObject;
|
||
|
|
||
|
WinStatus = NO_ERROR;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
if ( ReferencedParentObject != NULL ) {
|
||
|
ObDereferenceObject( ReferencedParentObject );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Drop the global lock
|
||
|
//
|
||
|
|
||
|
AzpUnlockResource( &AzGlResource );
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObCommonGetProperty(
|
||
|
IN PGENERIC_OBJECT GenericObject,
|
||
|
IN ULONG ObjectType,
|
||
|
IN ULONG PropertyId,
|
||
|
IN DWORD Reserved,
|
||
|
OUT PVOID *PropertyValue
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Returns the specified property for a generic object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericObject - Specifies a handle to the object to get the property from.
|
||
|
This "handle" has been passed from the application and needs to be verified.
|
||
|
|
||
|
ObjectType - Specifies the expected object type GenericObject.
|
||
|
|
||
|
PropertyId - Specifies which property to return.
|
||
|
|
||
|
Reserved - Reserved. Must by zero.
|
||
|
|
||
|
PropertyValue - Specifies a pointer to return the property in.
|
||
|
The returned pointer must be freed using AzFreeMemory.
|
||
|
The returned value and type depends in PropertyId. The valid values are:
|
||
|
|
||
|
AZ_PROP_NAME LPWSTR - Object name of the object
|
||
|
AZ_PROP_DESCRIPTION LPWSTR - Description of the object
|
||
|
|
||
|
Any object specific properties.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful
|
||
|
ERROR_INVALID_PARAMETER - PropertyId isn't valid
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT ReferencedGenericObject = NULL;
|
||
|
|
||
|
//
|
||
|
// Grab the global lock
|
||
|
//
|
||
|
|
||
|
AzpLockResourceShared( &AzGlResource );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialize the return value
|
||
|
//
|
||
|
|
||
|
__try {
|
||
|
*PropertyValue = NULL;
|
||
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
|
||
|
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the input parameters
|
||
|
//
|
||
|
if ( Reserved != 0 ) {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonGetProperty: Reserved != 0\n" ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the passed in handle
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByHandle( GenericObject,
|
||
|
FALSE, // Don't allow deleted objects
|
||
|
TRUE, // Refresh the cache
|
||
|
ObjectType );
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ReferencedGenericObject = GenericObject;
|
||
|
|
||
|
//
|
||
|
// Return any common attribute
|
||
|
//
|
||
|
// Return object name to the caller
|
||
|
//
|
||
|
|
||
|
switch ( PropertyId ) {
|
||
|
case AZ_PROP_NAME:
|
||
|
|
||
|
*PropertyValue = AzpGetStringProperty( &GenericObject->ObjectName );
|
||
|
|
||
|
if ( *PropertyValue == NULL ) {
|
||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// Return object description to the caller
|
||
|
//
|
||
|
case AZ_PROP_DESCRIPTION:
|
||
|
|
||
|
*PropertyValue = AzpGetStringProperty( &GenericObject->Description );
|
||
|
|
||
|
if ( *PropertyValue == NULL ) {
|
||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ASSERT ( PropertyId >= AZ_PROP_FIRST_SPECIFIC );
|
||
|
|
||
|
//
|
||
|
// Call the routine to do object type specific querying
|
||
|
//
|
||
|
|
||
|
if ( ObjectGetPropertyRoutine[GenericObject->ObjectType] != NULL ) {
|
||
|
|
||
|
WinStatus = ObjectGetPropertyRoutine[GenericObject->ObjectType](
|
||
|
GenericObject,
|
||
|
PropertyId,
|
||
|
PropertyValue );
|
||
|
|
||
|
} else {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonGetProperty: No get property routine.\n", GenericObject->ObjectType, PropertyId ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Return the value to the caller
|
||
|
//
|
||
|
WinStatus = NO_ERROR;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
if ( ReferencedGenericObject != NULL ) {
|
||
|
ObDereferenceObject( ReferencedGenericObject );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Drop the global lock
|
||
|
//
|
||
|
|
||
|
AzpUnlockResource( &AzGlResource );
|
||
|
|
||
|
return WinStatus;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObCommonSetProperty(
|
||
|
IN PGENERIC_OBJECT GenericObject,
|
||
|
IN ULONG ObjectType,
|
||
|
IN ULONG PropertyId,
|
||
|
IN DWORD Reserved,
|
||
|
IN PVOID PropertyValue
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Sets the specified property for a generic object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericObject - Specifies a handle to the object to modify.
|
||
|
This "handle" has been passed from the application and needs to be verified.
|
||
|
|
||
|
ObjectType - Specifies the expected object type GenericObject.
|
||
|
|
||
|
PropertyId - Specifies which property to return.
|
||
|
|
||
|
Reserved - Reserved. Must by zero.
|
||
|
|
||
|
|
||
|
PropertyValue - Specifies a pointer to the property.
|
||
|
The specified value and type depends in PropertyId. The valid values are:
|
||
|
|
||
|
AZ_PROP_NAME LPWSTR - Object name of the object
|
||
|
AZ_PROP_DESCRIPTION LPWSTR - Description of the object
|
||
|
|
||
|
Any object specific properties.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful
|
||
|
ERROR_INVALID_PARAMETER - PropertyId isn't valid
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT ReferencedGenericObject = NULL;
|
||
|
AZP_STRING CapturedString;
|
||
|
|
||
|
//
|
||
|
// Grab the global lock
|
||
|
//
|
||
|
|
||
|
AzpInitString( &CapturedString, NULL );
|
||
|
AzpLockResourceExclusive( &AzGlResource );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Validate the input parameters
|
||
|
//
|
||
|
if ( Reserved != 0 ) {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonSetProperty: Reserved != 0\n" ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the passed in handle
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByHandle( GenericObject,
|
||
|
FALSE, // Don't allow deleted objects
|
||
|
TRUE, // Refresh the cache
|
||
|
ObjectType );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ReferencedGenericObject = GenericObject;
|
||
|
|
||
|
//
|
||
|
// Return any common attribute
|
||
|
//
|
||
|
// Return object name to the caller
|
||
|
//
|
||
|
|
||
|
switch ( PropertyId ) {
|
||
|
case AZ_PROP_NAME:
|
||
|
|
||
|
//
|
||
|
// Capture the input string
|
||
|
//
|
||
|
|
||
|
WinStatus = AzpCaptureString( &CapturedString,
|
||
|
(LPWSTR) PropertyValue,
|
||
|
MaxObjectNameLength[ObjectType],
|
||
|
FALSE ); // NULL not ok
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check to see if the name conflicts with an existing name
|
||
|
// ???
|
||
|
|
||
|
//
|
||
|
// Swap the old/new names
|
||
|
//
|
||
|
|
||
|
AzpSwapStrings( &CapturedString, &GenericObject->ObjectName );
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// Return object description to the caller
|
||
|
//
|
||
|
case AZ_PROP_DESCRIPTION:
|
||
|
|
||
|
//
|
||
|
// Capture the input string
|
||
|
//
|
||
|
|
||
|
WinStatus = AzpCaptureString( &CapturedString,
|
||
|
(LPWSTR) PropertyValue,
|
||
|
AZ_MAX_DESCRIPTION_LENGTH,
|
||
|
TRUE ); // NULL is OK
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Swap the old/new names
|
||
|
//
|
||
|
|
||
|
AzpSwapStrings( &CapturedString, &GenericObject->Description );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ASSERT ( PropertyId >= AZ_PROP_FIRST_SPECIFIC );
|
||
|
|
||
|
//
|
||
|
// Call the routine to do object type specific set property
|
||
|
//
|
||
|
|
||
|
if ( ObjectSetPropertyRoutine[GenericObject->ObjectType] != NULL ) {
|
||
|
|
||
|
WinStatus = ObjectSetPropertyRoutine[GenericObject->ObjectType](
|
||
|
GenericObject,
|
||
|
PropertyId,
|
||
|
PropertyValue );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonSetProperty: non set property routine\n", GenericObject->ObjectType, PropertyId ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Mark the object as needing to be written
|
||
|
//
|
||
|
|
||
|
GenericObject->Flags |= GENOBJ_FLAGS_DIRTY;
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Return the value to the caller
|
||
|
//
|
||
|
WinStatus = NO_ERROR;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
if ( ReferencedGenericObject != NULL ) {
|
||
|
ObDereferenceObject( ReferencedGenericObject );
|
||
|
}
|
||
|
|
||
|
AzpFreeString( &CapturedString );
|
||
|
|
||
|
//
|
||
|
// Drop the global lock
|
||
|
//
|
||
|
|
||
|
AzpUnlockResource( &AzGlResource );
|
||
|
|
||
|
return WinStatus;
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ObMarkObjectDeleted(
|
||
|
IN PGENERIC_OBJECT GenericObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Mark this object and all child objects as deleted.
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObject - Specifies the object to mark
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PGENERIC_OBJECT_HEAD ChildGenericObjectHead;
|
||
|
|
||
|
PGENERIC_OBJECT ChildGenericObject;
|
||
|
PLIST_ENTRY ListEntry;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Mark the entry as deleted
|
||
|
//
|
||
|
|
||
|
GenericObject->Flags |= GENOBJ_FLAGS_DELETED;
|
||
|
|
||
|
//
|
||
|
// Delete all children of this object
|
||
|
//
|
||
|
// Loop for each type of child object
|
||
|
//
|
||
|
|
||
|
for ( ChildGenericObjectHead = GenericObject->ChildGenericObjectHead;
|
||
|
ChildGenericObjectHead != NULL;
|
||
|
ChildGenericObjectHead = ChildGenericObjectHead->SiblingGenericObjectHead ) {
|
||
|
|
||
|
//
|
||
|
// Loop for each child object
|
||
|
//
|
||
|
|
||
|
for ( ListEntry = ChildGenericObjectHead->Head.Flink ;
|
||
|
ListEntry != &ChildGenericObjectHead->Head ;
|
||
|
ListEntry = ListEntry->Flink) {
|
||
|
|
||
|
ChildGenericObject = CONTAINING_RECORD( ListEntry,
|
||
|
GENERIC_OBJECT,
|
||
|
Next );
|
||
|
|
||
|
//
|
||
|
// Mark that object
|
||
|
//
|
||
|
|
||
|
ObMarkObjectDeleted( ChildGenericObject );
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Delete all references to this object
|
||
|
//
|
||
|
|
||
|
ObRemoveObjectListLinks( GenericObject, TRUE );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObCommonDeleteObject(
|
||
|
IN PGENERIC_OBJECT ParentGenericObject,
|
||
|
IN ULONG ParentObjectType,
|
||
|
IN PGENERIC_OBJECT_HEAD GenericChildHead,
|
||
|
IN ULONG ChildObjectType,
|
||
|
IN LPCWSTR ChildObjectName,
|
||
|
IN DWORD Reserved
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine deletes a child object from the scope of the specified parent object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ParentGenericObject - Specifies a handle to the parent object to delete the child
|
||
|
object from. This "handle" has been passed from the application and needs to
|
||
|
be verified.
|
||
|
|
||
|
ParentObjectType - Specifies the object type ParentGenericObject.
|
||
|
|
||
|
GenericChildHead - Specifies a pointer to the head of the list of children of
|
||
|
ParentGenericObject. This is a computed pointer and is considered untrustworthy
|
||
|
until ParentGenericObject has been verified.
|
||
|
|
||
|
ChildObjectType - Specifies the object type RetChildGenericObject.
|
||
|
|
||
|
ChildObjectName - Specifies the name of the child object.
|
||
|
This name is passed from the application and needs to be verified.
|
||
|
|
||
|
Reserved - Reserved. Must by zero.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful
|
||
|
|
||
|
ERROR_NOT_FOUND - An object by that name cannot be found
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT ReferencedParentObject = NULL;
|
||
|
PGENERIC_OBJECT ChildGenericObject = NULL;
|
||
|
|
||
|
AZP_STRING ChildObjectNameString;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
AzpInitString( &ChildObjectNameString, NULL );
|
||
|
ASSERT( ParentObjectType != OBJECT_TYPE_ROOT );
|
||
|
ASSERT( ChildObjectType != OBJECT_TYPE_ADMIN_MANAGER );
|
||
|
|
||
|
//
|
||
|
// Grab the global lock
|
||
|
//
|
||
|
|
||
|
AzpLockResourceExclusive( &AzGlResource );
|
||
|
|
||
|
//
|
||
|
// Validate the input parameters
|
||
|
//
|
||
|
if ( Reserved != 0 ) {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonDeleteObject: Reserved != 0\n" ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the passed in handle
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByHandle( ParentGenericObject,
|
||
|
FALSE, // Don't allow deleted objects
|
||
|
FALSE, // No need to refresh the cache on a delete
|
||
|
ParentObjectType );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ReferencedParentObject = ParentGenericObject;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Capture the object name string from the caller
|
||
|
//
|
||
|
|
||
|
WinStatus = AzpCaptureString( &ChildObjectNameString,
|
||
|
ChildObjectName,
|
||
|
MaxObjectNameLength[ChildObjectType],
|
||
|
FALSE ); // NULL names not OK
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Find the object to delete.
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByName( GenericChildHead,
|
||
|
&ChildObjectNameString,
|
||
|
FALSE, // no need to refresh the cache
|
||
|
&ChildGenericObject );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Actually, delete the object
|
||
|
//
|
||
|
|
||
|
WinStatus = AzpPersistSubmit( ChildGenericObject, TRUE );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Mark the entry (and its child objects) as deleted
|
||
|
// We do this since other threads may have references to the objects.
|
||
|
// We want to ensure those threads know the objects are deleted.
|
||
|
//
|
||
|
|
||
|
ObMarkObjectDeleted( ChildGenericObject );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Remove the reference representing the list from the parent.
|
||
|
//
|
||
|
|
||
|
ObDereferenceObject( ChildGenericObject );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Return to the caller
|
||
|
//
|
||
|
|
||
|
WinStatus = NO_ERROR;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
if ( ReferencedParentObject != NULL ) {
|
||
|
ObDereferenceObject( ReferencedParentObject );
|
||
|
}
|
||
|
|
||
|
if ( ChildGenericObject != NULL ) {
|
||
|
ObDereferenceObject( ChildGenericObject );
|
||
|
}
|
||
|
|
||
|
AzpFreeString( &ChildObjectNameString );
|
||
|
|
||
|
//
|
||
|
// Drop the global lock
|
||
|
//
|
||
|
|
||
|
AzpUnlockResource( &AzGlResource );
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ObInitObjectList(
|
||
|
IN OUT PGENERIC_OBJECT_LIST GenericObjectList,
|
||
|
IN PGENERIC_OBJECT_LIST NextGenericObjectList OPTIONAL,
|
||
|
IN BOOL IsBackLink,
|
||
|
IN ULONG LinkPairId,
|
||
|
IN PGENERIC_OBJECT_HEAD GenericObjectHead0 OPTIONAL,
|
||
|
IN PGENERIC_OBJECT_HEAD GenericObjectHead1 OPTIONAL,
|
||
|
IN PGENERIC_OBJECT_HEAD GenericObjectHead2 OPTIONAL
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Initialize a list of generic objects.
|
||
|
|
||
|
The caller must call ObFreeObjectList after calling this routine.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObjectList - Specifies the object list to initialize
|
||
|
|
||
|
NextGenericObjectList - Specifies a pointer to the next GenericObjectList
|
||
|
that is hosted in the same generic object as this one.
|
||
|
|
||
|
IsBackLink - TRUE if the link is a backlink
|
||
|
See GENERIC_OBJECT_LIST definition.
|
||
|
|
||
|
LinkPairId - LinkPairId for this object list.
|
||
|
See GENERIC_OBJECT_LIST definition.
|
||
|
|
||
|
GenericObjectHeadN - Specifies a pointer to the head of the list of objects
|
||
|
that are candidates for being pointed to by the object list.
|
||
|
|
||
|
If this object list is maintained by an external API (and not a "back" list),
|
||
|
then at least one GenericObjectHead must be specified.
|
||
|
|
||
|
If this is a back list, all GenericObjectHeads must be NULL.
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Initialize most fields to zero
|
||
|
//
|
||
|
|
||
|
RtlZeroMemory( GenericObjectList, sizeof(*GenericObjectList) );
|
||
|
|
||
|
//
|
||
|
// Initialize the pointer to the next generic object list for this object
|
||
|
//
|
||
|
|
||
|
GenericObjectList->NextGenericObjectList = NextGenericObjectList;
|
||
|
|
||
|
//
|
||
|
// Initialize the link pair information
|
||
|
//
|
||
|
|
||
|
GenericObjectList->IsBackLink = IsBackLink;
|
||
|
GenericObjectList->LinkPairId = LinkPairId;
|
||
|
|
||
|
//
|
||
|
// Initialize the pointers to the object heads
|
||
|
//
|
||
|
|
||
|
GenericObjectList->GenericObjectHeads[0] = GenericObjectHead0;
|
||
|
GenericObjectList->GenericObjectHeads[1] = GenericObjectHead1;
|
||
|
GenericObjectList->GenericObjectHeads[2] = GenericObjectHead2;
|
||
|
|
||
|
AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: ObInitObjectList\n", &GenericObjectList->GenericObjects, GenericObjectList->GenericObjects.Array ));
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Table of mappings to backlink object list tables
|
||
|
//
|
||
|
|
||
|
struct {
|
||
|
ULONG LinkFromObjectType;
|
||
|
ULONG LinkToObjectType;
|
||
|
BOOL IsBackLink;
|
||
|
ULONG LinkPairId;
|
||
|
ULONG ObjectListOffset;
|
||
|
} ObjectListOffsetTable[] = {
|
||
|
{ OBJECT_TYPE_TASK, OBJECT_TYPE_OPERATION, FALSE, 0, offsetof(_AZP_TASK, Operations) },
|
||
|
{ OBJECT_TYPE_OPERATION, OBJECT_TYPE_TASK, TRUE, 0, offsetof(_AZP_OPERATION, backTasks) },
|
||
|
{ OBJECT_TYPE_GROUP, OBJECT_TYPE_GROUP, FALSE, AZP_LINKPAIR_MEMBERS, offsetof(_AZP_GROUP, AppMembers) },
|
||
|
{ OBJECT_TYPE_GROUP, OBJECT_TYPE_GROUP, TRUE, AZP_LINKPAIR_MEMBERS, offsetof(_AZP_GROUP, backAppMembers) },
|
||
|
{ OBJECT_TYPE_GROUP, OBJECT_TYPE_GROUP, FALSE, AZP_LINKPAIR_NON_MEMBERS, offsetof(_AZP_GROUP, AppNonMembers) },
|
||
|
{ OBJECT_TYPE_GROUP, OBJECT_TYPE_GROUP, TRUE, AZP_LINKPAIR_NON_MEMBERS, offsetof(_AZP_GROUP, backAppNonMembers) },
|
||
|
{ OBJECT_TYPE_ROLE, OBJECT_TYPE_GROUP, FALSE, 0, offsetof(_AZP_ROLE, AppMembers) },
|
||
|
{ OBJECT_TYPE_GROUP, OBJECT_TYPE_ROLE, TRUE, 0, offsetof(_AZP_GROUP, backRoles) },
|
||
|
{ OBJECT_TYPE_ROLE, OBJECT_TYPE_OPERATION, FALSE, 0, offsetof(_AZP_ROLE, Operations) },
|
||
|
{ OBJECT_TYPE_OPERATION, OBJECT_TYPE_ROLE, TRUE, 0, offsetof(_AZP_OPERATION, backRoles) },
|
||
|
{ OBJECT_TYPE_ROLE, OBJECT_TYPE_SCOPE, FALSE, 0, offsetof(_AZP_ROLE, Scopes) },
|
||
|
{ OBJECT_TYPE_SCOPE, OBJECT_TYPE_ROLE, TRUE, 0, offsetof(_AZP_SCOPE, backRoles) },
|
||
|
{ OBJECT_TYPE_JUNCTION_POINT, OBJECT_TYPE_APPLICATION, FALSE, 0, offsetof(_AZP_JUNCTION_POINT, Applications) },
|
||
|
{ OBJECT_TYPE_APPLICATION, OBJECT_TYPE_JUNCTION_POINT, TRUE, 0, offsetof(_AZP_APPLICATION, backJunctionPoints) },
|
||
|
{ OBJECT_TYPE_GROUP, OBJECT_TYPE_SID, FALSE, AZP_LINKPAIR_SID_MEMBERS, offsetof(_AZP_GROUP, SidMembers) },
|
||
|
{ OBJECT_TYPE_SID, OBJECT_TYPE_GROUP, TRUE, AZP_LINKPAIR_SID_MEMBERS, offsetof(_AZP_SID, backGroupMembers) },
|
||
|
{ OBJECT_TYPE_GROUP, OBJECT_TYPE_SID, FALSE, AZP_LINKPAIR_SID_NON_MEMBERS, offsetof(_AZP_GROUP, SidNonMembers) },
|
||
|
{ OBJECT_TYPE_SID, OBJECT_TYPE_GROUP, TRUE, AZP_LINKPAIR_SID_NON_MEMBERS, offsetof(_AZP_SID, backGroupNonMembers) },
|
||
|
{ OBJECT_TYPE_ROLE, OBJECT_TYPE_SID, FALSE, 0, offsetof(_AZP_ROLE, SidMembers) },
|
||
|
{ OBJECT_TYPE_SID, OBJECT_TYPE_ROLE, TRUE, 0, offsetof(_AZP_SID, backRoles) },
|
||
|
};
|
||
|
|
||
|
|
||
|
PGENERIC_OBJECT_LIST
|
||
|
ObGetObjectListPtr(
|
||
|
IN PGENERIC_OBJECT GenericObject,
|
||
|
IN ULONG LinkToObjectType,
|
||
|
IN PGENERIC_OBJECT_LIST LinkToGenericObjectList
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Returns a pointer to a GENERIC_OBJECT_LIST structure within the passed in
|
||
|
GenericObject the is suitable for linking an object of type LinkToObjectType
|
||
|
into.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObject - Specifies the object the link is from.
|
||
|
|
||
|
LinkToObjectType - Specifies the object type the link is to.
|
||
|
|
||
|
LinkToGenericObjectList - Specifies a pointer to the generic object list
|
||
|
structure that is within the LinkToGenericObject.
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
Returns a pointer to the generic object list.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PGENERIC_OBJECT_LIST GenericObjectList = NULL;
|
||
|
ULONG i;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Compute the address of the generic address list the object is in.
|
||
|
// We could do this more generically, but that would scatter this data
|
||
|
// over too wide an array.
|
||
|
//
|
||
|
|
||
|
for ( i=0; i<sizeof(ObjectListOffsetTable)/sizeof(ObjectListOffsetTable[0]); i++ ) {
|
||
|
|
||
|
//
|
||
|
// Find the entry in the table that matches our situation
|
||
|
//
|
||
|
|
||
|
if ( GenericObject->ObjectType == ObjectListOffsetTable[i].LinkFromObjectType &&
|
||
|
LinkToObjectType == ObjectListOffsetTable[i].LinkToObjectType &&
|
||
|
LinkToGenericObjectList->IsBackLink != ObjectListOffsetTable[i].IsBackLink &&
|
||
|
LinkToGenericObjectList->LinkPairId == ObjectListOffsetTable[i].LinkPairId ) {
|
||
|
|
||
|
GenericObjectList = (PGENERIC_OBJECT_LIST)
|
||
|
(((LPBYTE)GenericObject)+(ObjectListOffsetTable[i].ObjectListOffset));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ASSERT( GenericObjectList != NULL );
|
||
|
|
||
|
return GenericObjectList;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ObRemoveObjectListLink(
|
||
|
IN PGENERIC_OBJECT LinkFromGenericObject,
|
||
|
IN PGENERIC_OBJECT LinkToGenericObject,
|
||
|
IN PGENERIC_OBJECT_LIST LinkToGenericObjectList
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Remove the link from LinkedFromGenericObject to LinkToGenericObject.
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
LinkFromGenericObject - Specifies the object the link is from
|
||
|
|
||
|
LinkToGenericObject - Specifies the object the link is to
|
||
|
|
||
|
LinkToGenericObjectList - Specifies a pointer to the generic object list
|
||
|
structure that is within the LinkToGenericObject. (Notice, this isn't
|
||
|
the object list we're removing LinkFromGenericObject from. This is the
|
||
|
'other' object list.)
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PGENERIC_OBJECT_LIST GenericObjectList;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get a pointer to the object list to remove this entry from
|
||
|
//
|
||
|
|
||
|
GenericObjectList = ObGetObjectListPtr( LinkFromGenericObject,
|
||
|
LinkToGenericObject->ObjectType,
|
||
|
LinkToGenericObjectList );
|
||
|
|
||
|
ASSERT( GenericObjectList != NULL );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Remove the entry from the list
|
||
|
//
|
||
|
|
||
|
AzpRemovePtrByPtr( &GenericObjectList->GenericObjects, LinkToGenericObject );
|
||
|
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
ObLookupPropertyItem(
|
||
|
IN PGENERIC_OBJECT_LIST GenericObjectList,
|
||
|
IN PAZP_STRING ObjectName,
|
||
|
OUT PULONG InsertionPoint OPTIONAL
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine determins if the specified object name is already in the
|
||
|
object list.
|
||
|
|
||
|
On entry, AzGlResource must be locked share
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericObjectList - Specifies the object list to be searched
|
||
|
|
||
|
ObjectName - Specifies the ObjectName to lookup
|
||
|
|
||
|
InsertionPoint - On ERROR_NOT_FOUND, returns the point where one would insert the named
|
||
|
object. On ERROR_ALREADY_EXISTS, returns an index to the object.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ERROR_ALREADY_EXISTS - An object by that name already exists in the list
|
||
|
|
||
|
ERROR_NOT_FOUND - There is no object by that name
|
||
|
|
||
|
Misc other failure statuses.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus = NO_ERROR;
|
||
|
ULONG i;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedShared( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Loop through the existing list of names finding the insertion point.
|
||
|
// The list is maintained in alphabetical order.
|
||
|
// ??? Could be binary search
|
||
|
//
|
||
|
|
||
|
for ( i=0; i<GenericObjectList->GenericObjects.UsedCount; i++ ) {
|
||
|
PGENERIC_OBJECT ExistingObject;
|
||
|
LONG CompareResult;
|
||
|
|
||
|
|
||
|
ExistingObject= (PGENERIC_OBJECT) (GenericObjectList->GenericObjects.Array[i]);
|
||
|
|
||
|
CompareResult = AzpCompareStrings( ObjectName,
|
||
|
&ExistingObject->ObjectName );
|
||
|
|
||
|
if ( CompareResult == 0 ) {
|
||
|
WinStatus = GetLastError();
|
||
|
goto Cleanup;
|
||
|
} else if ( CompareResult == CSTR_EQUAL ) {
|
||
|
if ( InsertionPoint != NULL ) {
|
||
|
*InsertionPoint = i;
|
||
|
}
|
||
|
WinStatus = ERROR_ALREADY_EXISTS;
|
||
|
goto Cleanup;
|
||
|
} else if ( CompareResult == CSTR_LESS_THAN ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( InsertionPoint != NULL ) {
|
||
|
*InsertionPoint = i;
|
||
|
}
|
||
|
WinStatus = ERROR_NOT_FOUND;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free any local resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObAddPropertyItem(
|
||
|
IN PGENERIC_OBJECT GenericObject,
|
||
|
IN PGENERIC_OBJECT_LIST GenericObjectList,
|
||
|
IN PAZP_STRING ObjectName
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Adds an object to the list of objects specified by GenericObjectList.
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericObject - Specifies a pointer to the object the link is from
|
||
|
|
||
|
GenericObjectList - Specifies the object list to add the object into.
|
||
|
|
||
|
ObjectName - Specifies a pointer to name of the object to add.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful.
|
||
|
|
||
|
ERROR_NOT_FOUND - There is no object by that name
|
||
|
|
||
|
ERROR_ALREADY_EXISTS - An object by that name already exists in the list
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
ULONG InsertionPoint;
|
||
|
ULONG ObjectTypeIndex;
|
||
|
|
||
|
PGENERIC_OBJECT FoundGenericObject = NULL;
|
||
|
PGENERIC_OBJECT_LIST BackGenericObjectList;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Loop through the various lists of objects that can be referenced
|
||
|
//
|
||
|
|
||
|
for ( ObjectTypeIndex=0; ObjectTypeIndex<GEN_OBJECT_HEAD_COUNT; ObjectTypeIndex++ ) {
|
||
|
|
||
|
//
|
||
|
// Stop when there are no more lists to search
|
||
|
//
|
||
|
|
||
|
if ( GenericObjectList->GenericObjectHeads[ObjectTypeIndex] == NULL ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find the specified object in this list
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByName(
|
||
|
GenericObjectList->GenericObjectHeads[ObjectTypeIndex],
|
||
|
ObjectName,
|
||
|
FALSE, // No need to refresh the cache
|
||
|
&FoundGenericObject );
|
||
|
|
||
|
|
||
|
if ( WinStatus == NO_ERROR ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If this is a link to a SID object,
|
||
|
// create the SID object.
|
||
|
//
|
||
|
// AzpSids are pseudo objects that come into existence as they are needed.
|
||
|
//
|
||
|
|
||
|
if ( AzpIsSidList( GenericObjectList ) ) {
|
||
|
|
||
|
WinStatus = ObCreateObject(
|
||
|
GenericObjectList->GenericObjectHeads[0]->ParentGenericObject,
|
||
|
GenericObjectList->GenericObjectHeads[0],
|
||
|
OBJECT_TYPE_SID,
|
||
|
ObjectName,
|
||
|
&FoundGenericObject );
|
||
|
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If none of the lists had an object by the requested name,
|
||
|
// complain.
|
||
|
//
|
||
|
|
||
|
if ( FoundGenericObject == NULL ) {
|
||
|
WinStatus = ERROR_NOT_FOUND;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Prevent a reference to ourself
|
||
|
//
|
||
|
|
||
|
if ( GenericObject == FoundGenericObject ) {
|
||
|
AzPrint(( AZD_INVPARM, "Reference to self\n" ));
|
||
|
WinStatus = ERROR_DS_LOOP_DETECT;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Call the object specific routine to validate the request
|
||
|
//
|
||
|
|
||
|
if ( ObjectAddPropertyItemRoutine[GenericObject->ObjectType] != NULL ) {
|
||
|
|
||
|
WinStatus = ObjectAddPropertyItemRoutine[GenericObject->ObjectType](
|
||
|
GenericObject,
|
||
|
GenericObjectList,
|
||
|
FoundGenericObject );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Find the insertion point for this name.
|
||
|
//
|
||
|
|
||
|
WinStatus = ObLookupPropertyItem( GenericObjectList,
|
||
|
ObjectName,
|
||
|
&InsertionPoint );
|
||
|
|
||
|
if ( WinStatus != ERROR_NOT_FOUND ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Insert the generic object into the list
|
||
|
//
|
||
|
|
||
|
WinStatus = AzpAddPtr(
|
||
|
&GenericObjectList->GenericObjects,
|
||
|
FoundGenericObject,
|
||
|
InsertionPoint );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get a pointer to the backlink object list
|
||
|
//
|
||
|
|
||
|
BackGenericObjectList = ObGetObjectListPtr( FoundGenericObject,
|
||
|
GenericObject->ObjectType,
|
||
|
GenericObjectList );
|
||
|
|
||
|
ASSERT( BackGenericObjectList != NULL );
|
||
|
|
||
|
//
|
||
|
// Maintain a back link from the generic object we just linked to back
|
||
|
// to this object.
|
||
|
//
|
||
|
|
||
|
WinStatus = AzpAddPtr(
|
||
|
&BackGenericObjectList->GenericObjects,
|
||
|
GenericObject,
|
||
|
AZP_ADD_ENDOFLIST );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
|
||
|
// Undo the forward link
|
||
|
AzpRemovePtrByIndex( &GenericObjectList->GenericObjects, InsertionPoint );
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Return to the caller
|
||
|
//
|
||
|
|
||
|
WinStatus = NO_ERROR;
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
if ( FoundGenericObject != NULL ) {
|
||
|
ObDereferenceObject( FoundGenericObject );
|
||
|
}
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObCommonAddPropertyItem(
|
||
|
IN PGENERIC_OBJECT GenericObject,
|
||
|
IN ULONG ObjectType,
|
||
|
IN PGENERIC_OBJECT_LIST GenericObjectList,
|
||
|
IN DWORD Reserved,
|
||
|
IN LPWSTR ObjectName
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Adds an object to the list of objects specified by GenericObjectList.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericObject - Specifies a handle to the object to add the object to.
|
||
|
This "handle" has been passed from the application and needs to be verified.
|
||
|
|
||
|
ObjectType - Specifies the object type of GenericObject.
|
||
|
|
||
|
GenericObjectList - Specifies the object list to add the object into.
|
||
|
This is a computed pointer and is considered untrustworthy
|
||
|
until GenericObject has been verified.
|
||
|
|
||
|
Reserved - Reserved. Must by zero.
|
||
|
|
||
|
ObjectName - Specifies a pointer to name of the object to add.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful.
|
||
|
|
||
|
ERROR_NOT_FOUND - There is no object by that name
|
||
|
|
||
|
ERROR_ALREADY_EXISTS - An object by that name already exists in the list
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT ReferencedObject = NULL;
|
||
|
|
||
|
AZP_STRING ObjectNameString;
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
AzpInitString( &ObjectNameString, NULL );
|
||
|
|
||
|
//
|
||
|
// Grab the global lock
|
||
|
//
|
||
|
|
||
|
AzpLockResourceExclusive( &AzGlResource );
|
||
|
|
||
|
//
|
||
|
// Validate the input parameters
|
||
|
//
|
||
|
if ( Reserved != 0 ) {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonAddPropertyItem: Reserved != 0\n" ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the passed in handle
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByHandle( GenericObject,
|
||
|
FALSE, // Don't allow deleted objects
|
||
|
TRUE, // Refresh the cache
|
||
|
ObjectType );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ReferencedObject = GenericObject;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Capture the object name string from the caller
|
||
|
//
|
||
|
|
||
|
if ( AzpIsSidList( GenericObjectList ) ) {
|
||
|
WinStatus = AzpCaptureSid( &ObjectNameString,
|
||
|
ObjectName );
|
||
|
} else {
|
||
|
WinStatus = AzpCaptureString( &ObjectNameString,
|
||
|
ObjectName,
|
||
|
AZ_MAX_NAME_LENGTH, // Don't need to validate size exactly
|
||
|
FALSE ); // NULL names not OK
|
||
|
}
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Actually add the property item
|
||
|
//
|
||
|
|
||
|
WinStatus = ObAddPropertyItem( GenericObject,
|
||
|
GenericObjectList,
|
||
|
&ObjectNameString );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
if ( ReferencedObject != NULL ) {
|
||
|
ObDereferenceObject( ReferencedObject );
|
||
|
}
|
||
|
|
||
|
AzpFreeString( &ObjectNameString );
|
||
|
|
||
|
//
|
||
|
// Drop the global lock
|
||
|
//
|
||
|
|
||
|
AzpUnlockResource( &AzGlResource );
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObRemovePropertyItem(
|
||
|
IN PGENERIC_OBJECT GenericObject,
|
||
|
IN PGENERIC_OBJECT_LIST GenericObjectList,
|
||
|
IN PAZP_STRING ObjectName
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Removes a generic object from the list of items specified by GenericObjectList
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericObject - Specifies the object the link is from.
|
||
|
|
||
|
GenericObjectList - Specifies the obejct list to remote the object from.
|
||
|
|
||
|
ObjectName - Specifies a pointer to the name of the object to remove.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful.
|
||
|
|
||
|
ERROR_NOT_FOUND - There is no object by that name in the list
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT FoundGenericObject;
|
||
|
ULONG InsertionPoint;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Lookup that name in the object list
|
||
|
//
|
||
|
|
||
|
WinStatus = ObLookupPropertyItem( GenericObjectList,
|
||
|
ObjectName,
|
||
|
&InsertionPoint );
|
||
|
|
||
|
if ( WinStatus != ERROR_ALREADY_EXISTS ) {
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
FoundGenericObject = (PGENERIC_OBJECT) (GenericObjectList->GenericObjects.Array[InsertionPoint]);
|
||
|
|
||
|
//
|
||
|
// Remove the object from the list
|
||
|
//
|
||
|
|
||
|
AzpRemovePtrByIndex( &GenericObjectList->GenericObjects, InsertionPoint );
|
||
|
|
||
|
//
|
||
|
// Remove the back link, too
|
||
|
//
|
||
|
|
||
|
ObRemoveObjectListLink( FoundGenericObject, GenericObject, GenericObjectList );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Return to the caller
|
||
|
//
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ObCommonRemovePropertyItem(
|
||
|
IN PGENERIC_OBJECT GenericObject,
|
||
|
IN ULONG ObjectType,
|
||
|
IN PGENERIC_OBJECT_LIST GenericObjectList,
|
||
|
IN DWORD Reserved,
|
||
|
IN LPWSTR ObjectName
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Removes a generic object from the list of items specified by GenericObjectList
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericObject - Specifies a handle to the object to remove the object from.
|
||
|
This "handle" has been passed from the application and needs to be verified.
|
||
|
|
||
|
ObjectType - Specifies the object type of GenericObject.
|
||
|
|
||
|
GenericObjectList - Specifies the obejct list to remote the object from.
|
||
|
This is a computed pointer and is considered untrustworthy
|
||
|
until GenericObject has been verified.
|
||
|
|
||
|
Reserved - Reserved. Must by zero.
|
||
|
|
||
|
ObjectName - Specifies a pointer to the name of the object to remove.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR - The operation was successful.
|
||
|
|
||
|
ERROR_NOT_FOUND - There is no object by that name in the list
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD WinStatus;
|
||
|
|
||
|
PGENERIC_OBJECT ReferencedObject = NULL;
|
||
|
|
||
|
AZP_STRING ObjectNameString;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
AzpInitString( &ObjectNameString, NULL );
|
||
|
|
||
|
//
|
||
|
// Grab the global lock
|
||
|
//
|
||
|
|
||
|
AzpLockResourceExclusive( &AzGlResource );
|
||
|
|
||
|
//
|
||
|
// Validate the input parameters
|
||
|
//
|
||
|
if ( Reserved != 0 ) {
|
||
|
AzPrint(( AZD_INVPARM, "ObCommonRemovePropertyItem: Reserved != 0\n" ));
|
||
|
WinStatus = ERROR_INVALID_PARAMETER;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the passed in handle
|
||
|
//
|
||
|
|
||
|
WinStatus = ObReferenceObjectByHandle( GenericObject,
|
||
|
FALSE, // Don't allow deleted objects
|
||
|
TRUE, // Refresh the cache
|
||
|
ObjectType );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ReferencedObject = GenericObject;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Capture the object name string from the caller
|
||
|
//
|
||
|
|
||
|
if ( AzpIsSidList( GenericObjectList ) ) {
|
||
|
WinStatus = AzpCaptureSid( &ObjectNameString,
|
||
|
ObjectName );
|
||
|
} else {
|
||
|
WinStatus = AzpCaptureString( &ObjectNameString,
|
||
|
ObjectName,
|
||
|
AZ_MAX_NAME_LENGTH, // Don't need to validate size exactly
|
||
|
FALSE ); // NULL names not OK
|
||
|
}
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Remove the item from the list and backlist
|
||
|
//
|
||
|
|
||
|
WinStatus = ObRemovePropertyItem( GenericObject,
|
||
|
GenericObjectList,
|
||
|
&ObjectNameString );
|
||
|
|
||
|
if ( WinStatus != NO_ERROR ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Mark the object as needing to be written
|
||
|
//
|
||
|
|
||
|
GenericObject->Flags |= GENOBJ_FLAGS_DIRTY;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free locally used resources
|
||
|
//
|
||
|
Cleanup:
|
||
|
|
||
|
if ( ReferencedObject != NULL ) {
|
||
|
ObDereferenceObject( ReferencedObject );
|
||
|
}
|
||
|
|
||
|
AzpFreeString( &ObjectNameString );
|
||
|
|
||
|
//
|
||
|
// Drop the global lock
|
||
|
//
|
||
|
|
||
|
AzpUnlockResource( &AzGlResource );
|
||
|
|
||
|
return WinStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
PAZ_STRING_ARRAY
|
||
|
ObGetPropertyItems(
|
||
|
IN PGENERIC_OBJECT_LIST GenericObjectList
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Return a list of generic object names as an array of object name strings.
|
||
|
|
||
|
On entry, AzGlResource must be locked shared
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericObjectList - Specifies the object list to get the entries for.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns the array of object name strings in a single allocated buffer.
|
||
|
Free the buffer using AzFreeMemory.
|
||
|
NULL - Not enough memory was available to allocate the string
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAZP_PTR_ARRAY GenericObjects;
|
||
|
ULONG i;
|
||
|
|
||
|
ULONG Size;
|
||
|
LPBYTE Where;
|
||
|
|
||
|
PGENERIC_OBJECT GenericObject;
|
||
|
|
||
|
PAZ_STRING_ARRAY StringArray;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedShared( &AzGlResource ) );
|
||
|
GenericObjects = &GenericObjectList->GenericObjects;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Loop through the list of objects computing the size of the buffer to allocate
|
||
|
//
|
||
|
|
||
|
Size = 0;
|
||
|
|
||
|
for ( i=0; i<GenericObjects->UsedCount; i++ ) {
|
||
|
|
||
|
GenericObject = (PGENERIC_OBJECT) (GenericObjects->Array[i]);
|
||
|
|
||
|
Size += GenericObject->ObjectName.StringSize;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate a buffer to return to the caller
|
||
|
//
|
||
|
|
||
|
Size += sizeof(AZ_STRING_ARRAY) + (GenericObjects->UsedCount * sizeof(LPWSTR));
|
||
|
|
||
|
StringArray = (PAZ_STRING_ARRAY) AzpAllocateHeap( Size );
|
||
|
|
||
|
if ( StringArray == NULL ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
StringArray->StringCount = GenericObjects->UsedCount;
|
||
|
StringArray->Strings = (LPWSTR *)(StringArray+1);
|
||
|
Where = (LPBYTE)(&StringArray->Strings[GenericObjects->UsedCount]);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Loop through the list of objects copying the names into the return buffer
|
||
|
//
|
||
|
|
||
|
for ( i=0; i<GenericObjects->UsedCount; i++ ) {
|
||
|
|
||
|
GenericObject = (PGENERIC_OBJECT) (GenericObjects->Array[i]);
|
||
|
|
||
|
StringArray->Strings[i] = (LPWSTR) Where;
|
||
|
|
||
|
RtlCopyMemory( Where,
|
||
|
GenericObject->ObjectName.String,
|
||
|
GenericObject->ObjectName.StringSize );
|
||
|
|
||
|
Where += GenericObject->ObjectName.StringSize;
|
||
|
|
||
|
}
|
||
|
|
||
|
ASSERT( (ULONG)(Where - (LPBYTE)StringArray) == Size );
|
||
|
|
||
|
return StringArray;
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ObRemoveObjectListLinks(
|
||
|
IN PGENERIC_OBJECT GenericObject,
|
||
|
IN BOOLEAN BackwardLinksToo
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Remove any links to/from the specified object.
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
GenericObject - Specifies the object to remove links to/from
|
||
|
|
||
|
BackwardLinksToo - TRUE if the back links are to be removed to.
|
||
|
|
||
|
Return Value
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PGENERIC_OBJECT_LIST GenericObjectList;
|
||
|
PGENERIC_OBJECT OtherGenericObject;
|
||
|
ULONG Index;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
|
||
|
//
|
||
|
// Walk all of the GenericObjectLists rooted on by this object
|
||
|
//
|
||
|
// The GenericObjectList may be forward links or backward links. We don't care.
|
||
|
// All links must be removed.
|
||
|
//
|
||
|
|
||
|
for ( GenericObjectList = GenericObject->GenericObjectLists;
|
||
|
GenericObjectList != NULL;
|
||
|
GenericObjectList = GenericObjectList->NextGenericObjectList ) {
|
||
|
|
||
|
|
||
|
//
|
||
|
// Skip back links if the caller wants them left
|
||
|
//
|
||
|
|
||
|
if ( !BackwardLinksToo && GenericObjectList->IsBackLink ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: %ld: ObRemoveObjectListLinks\n", &GenericObjectList->GenericObjects, GenericObjectList->GenericObjects.Array, GenericObjectList->GenericObjects.UsedCount ));
|
||
|
|
||
|
|
||
|
//
|
||
|
// Walk the list removing the current entry and removing the corresponding
|
||
|
// pointer back.
|
||
|
//
|
||
|
|
||
|
while ( GenericObjectList->GenericObjects.UsedCount != 0 ) {
|
||
|
|
||
|
//
|
||
|
// Remove the last entry in the list
|
||
|
//
|
||
|
|
||
|
Index = GenericObjectList->GenericObjects.UsedCount - 1;
|
||
|
|
||
|
OtherGenericObject = (PGENERIC_OBJECT)
|
||
|
(GenericObjectList->GenericObjects.Array[Index]);
|
||
|
|
||
|
AzpRemovePtrByIndex( &GenericObjectList->GenericObjects,
|
||
|
Index );
|
||
|
|
||
|
//
|
||
|
// Remove the entry in the opposite direction
|
||
|
//
|
||
|
|
||
|
ObRemoveObjectListLink( OtherGenericObject,
|
||
|
GenericObject,
|
||
|
GenericObjectList );
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Free the array itself
|
||
|
//
|
||
|
|
||
|
ObFreeObjectList( GenericObjectList );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ObFreeObjectList(
|
||
|
IN OUT PGENERIC_OBJECT_LIST GenericObjectList
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Free any memory pointed to by an array of object name strings.
|
||
|
|
||
|
On entry, AzGlResource must be locked exclusive.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
GenericObjectList - Specifies the object list to free.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns the array of object name strings in a single allocated buffer.
|
||
|
Free the buffer using AzFreeMemory.
|
||
|
NULL - Not enough memory was available to allocate the string
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAZP_PTR_ARRAY GenericObjects;
|
||
|
|
||
|
//
|
||
|
// Initialization
|
||
|
//
|
||
|
|
||
|
AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: ObFreeObjectList\n", &GenericObjectList->GenericObjects, GenericObjectList->GenericObjects.Array ));
|
||
|
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
|
||
|
GenericObjects = &GenericObjectList->GenericObjects;
|
||
|
ASSERT( GenericObjects->UsedCount == 0 );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free the actual array
|
||
|
//
|
||
|
|
||
|
if ( GenericObjects->Array != NULL ) {
|
||
|
AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: Free array\n", GenericObjects, GenericObjects->Array ));
|
||
|
AzpFreeHeap( GenericObjects->Array );
|
||
|
GenericObjects->Array = NULL;
|
||
|
}
|
||
|
|
||
|
}
|