windows-nt/Source/XPSP1/NT/ds/security/azroles/persist.cxx
2020-09-26 16:20:57 +08:00

641 lines
15 KiB
C++

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
persist.cxx
Abstract:
Routines implementing the common logic for persisting the authz policy.
This file contains routine called by the core logic to submit changes.
It also contains routines that are called by the particular providers to
find out information about the changed objects.
Author:
Cliff Van Dyke (cliffv) 9-May-2001
--*/
#include "pch.hxx"
//
// The enumeration context describes the current state of an enumeration
// through the list of all the objects in the authz policy database
//
typedef struct _AZP_PERSIST_ENUM_CONTEXT {
//
// Stack Index
// The enumeration walks the tree of objects. While enumerating child objects,
// the context of the parent object enumeration is kept on the stack of contexts.
//
ULONG StackIndex;
#define AZ_PERSIST_MAX_INDEX 4
//
// Pointer to the current Generic Child Head being enumerated
//
PGENERIC_OBJECT_HEAD GenericChildHead[AZ_PERSIST_MAX_INDEX];
ULONG EnumerationContext[AZ_PERSIST_MAX_INDEX];
} AZP_PERSIST_ENUM_CONTEXT, *PAZP_PERSIST_ENUM_CONTEXT;
DWORD
AzpPersistOpen(
IN PAZP_ADMIN_MANAGER AdminManager,
IN BOOL CreatePolicy
)
/*++
Routine Description:
This routine open the authz policy database.
This routine also reads the policy database into cache.
On Success, the caller should call SamplePersistClose to free any resources
consumed by the open.
This routine routes the request to the correct provider.
On entry, AzGlResource must be locked exclusive.
Arguments:
AdminManager - Specifies the policy database that is to be read.
CreatePolicy - TRUE if the policy database is to be created.
FALSE if the policy database already exists
Return Value:
NO_ERROR - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - not enough memory
ERROR_ALREADY_EXISTS - CreatePolicy is TRUE and the policy already exists
ERROR_FILE_NOT_FOUND - CreatePolicy is FALSE and the policy does not already exist
Other status codes
--*/
{
//
// Call the appropriate provider
//
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
return SamplePersistOpen( AdminManager, CreatePolicy );
}
VOID
AzpPersistClose(
IN PAZP_ADMIN_MANAGER AdminManager
)
/*++
Routine Description:
This routine closes the authz policy database storage handles.
This routine routes the request to the correct provider.
On entry, AzGlResource must be locked exclusive.
Arguments:
AdminManager - Specifies the policy database that is to be read.
Return Value:
NO_ERROR - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - not enough memory
Other status codes
--*/
{
//
// Call the appropriate provider
//
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
SamplePersistClose( AdminManager );
}
DWORD
AzpPersistSubmit(
IN PGENERIC_OBJECT GenericObject,
IN BOOLEAN DeleteMe
)
/*++
Routine Description:
This routine submits changes made to the authz policy database.
This routine routes the request to the correct provider.
If the object is being created, the GenericObject->PersistenceGuid field will be
zero on input. Upon successful creation, this routine will set PersistenceGuid to
non-zero. Upon failed creation, this routine will leave PersistenceGuid as zero.
On entry, AzGlResource must be locked exclusive.
Arguments:
GenericObject - Specifies the object in the database that is to be updated
in the underlying store.
DeleteMe - TRUE if the object and all of its children are to be deleted.
FALSE if the object is to be updated.
Return Value:
NO_ERROR - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - not enough memory
Other status codes
--*/
{
DWORD WinStatus = NO_ERROR;
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
//
// Only persist dirty objects
//
if ( (GenericObject->Flags & GENOBJ_FLAGS_DIRTY) != 0 ||
DeleteMe ) {
//
// Call the appropriate provider
//
WinStatus = SamplePersistSubmit( GenericObject, DeleteMe );
//
// Turn off the dirty bit
if ( WinStatus == NO_ERROR ) {
GenericObject->Flags &= ~GENOBJ_FLAGS_DIRTY;
}
}
return WinStatus;
}
DWORD
AzpPersistRefresh(
IN PGENERIC_OBJECT GenericObject
)
/*++
Routine Description:
This routine updates the attributes of the object from the policy database.
This routine routes the request to the correct provider.
On entry, AzGlResource must be locked exclusive.
Arguments:
GenericObject - Specifies the object in the database whose cache entry is to be
updated
The GenericObject->PersistenceGuid field should be non-zero on input.
Return Value:
NO_ERROR - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - not enough memory
Other status codes
--*/
{
DWORD WinStatus = NO_ERROR;
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
//
// Clear the attributes from the object so that the underlying routines only have
// to re-populate the attributes.
//
ObFreeGenericObject( GenericObject, TRUE );
//
// Object no longer needs to be refreshed and is no longer dirty.
//
GenericObject->Flags &= ~(GENOBJ_FLAGS_REFRESH_ME|GENOBJ_FLAGS_DIRTY);
//
// Call the appropriate provider
//
WinStatus = SamplePersistRefresh( GenericObject );
if ( WinStatus != NO_ERROR ) {
//
// Object needs to be refreshed
//
GenericObject->Flags |= GENOBJ_FLAGS_REFRESH_ME;
}
return WinStatus;
}
#if 0 // Providers don't actually call these yet
DWORD
AzpPersistEnumOpen(
IN PAZP_ADMIN_MANAGER AdminManager,
OUT PVOID *PersistEnumContext
)
/*++
Routine Description:
This routine begins an enumeration of the all objects in the authz policy database.
A peristance provider will call this routine to determine which objects have changed.
On entry, AzGlResource must be locked exclusive.
Arguments:
AdminManager - Specifies the policy database that is being queried
PersistEnumContext - Returns a context that can be passed to AzpPersistEnumNext.
This context must be closed by calling AzpPersistClose.
Return Value:
NO_ERROR - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - not enough memory
Other status codes
--*/
{
PAZP_PERSIST_ENUM_CONTEXT Context = NULL;
//
// Allocate memory for the context
//
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
Context = (PAZP_PERSIST_ENUM_CONTEXT) AzpAllocateHeap( sizeof(*Context) );
if ( Context == NULL ) {
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Initialize it
//
Context->StackIndex = 0;
Context->GenericChildHead[0] = AdminManager->GenericObject.ChildGenericObjectHead;
Context->EnumerationContext[0] = 0;
//
// Return the context to the caller
//
*PersistEnumContext = Context;
return NO_ERROR;
}
DWORD
AzpPersistEnumNext(
IN PVOID PersistEnumContext,
OUT PGENERIC_OBJECT *GenericObject
)
/*++
Routine Description:
This routine returns the next object in the list of all objects in the authz policy database.
A peristance provider will call this routine to determine which objects have changed.
On entry, AzGlResource must be locked exclusive.
Arguments:
PersistEnumContext - A context describing the current state of the enumeration
GenericObject - Returns a pointer to an next object. The provider should inspect the
GENOBJ_FLAGS_DELETED and GENOBJ_FLAGS_DIRTY flags to determine whether the
object has been modified.
Return Value:
NO_ERROR - The operation was successful (a GenericObject was returned)
ERROR_NO_MORE_ITEMS - No more items were available for enumeration
Other status codes
--*/
{
DWORD WinStatus;
PAZP_PERSIST_ENUM_CONTEXT Context = (PAZP_PERSIST_ENUM_CONTEXT) PersistEnumContext;
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
//
// Loop until we find another object to return
//
for (;;) {
//
// Don't return pseudo objects to the caller.
//
if ( Context->GenericChildHead[Context->StackIndex]->ObjectType != OBJECT_TYPE_SID ) {
//
// Get the next object from the current list
//
WinStatus = ObEnumObjects( Context->GenericChildHead[Context->StackIndex],
TRUE, // return deleted objects
FALSE, // Don't refresh the cache
&Context->EnumerationContext[Context->StackIndex],
GenericObject );
//
// Before returning the current object,
// set up the context to enumerate all children of the current context
//
if ( WinStatus == NO_ERROR ) {
//
// Only push onto the stack if the current object can have children
//
if ( (*GenericObject)->ChildGenericObjectHead != NULL ) {
if ( Context->StackIndex+1 >= AZ_PERSIST_MAX_INDEX ) {
ASSERT(FALSE);
return ERROR_INTERNAL_ERROR;
}
Context->StackIndex++;
Context->GenericChildHead[Context->StackIndex] = (*GenericObject)->ChildGenericObjectHead;
Context->EnumerationContext[Context->StackIndex] = 0;
}
return NO_ERROR;
}
if ( WinStatus != ERROR_NO_MORE_ITEMS ) {
return WinStatus;
}
}
//
// Move on to the next set of sibling object types.
//
Context->EnumerationContext[Context->StackIndex] = 0;
if ( Context->GenericChildHead[Context->StackIndex]->SiblingGenericObjectHead != NULL ) {
Context->GenericChildHead[Context->StackIndex] = Context->GenericChildHead[Context->StackIndex]->SiblingGenericObjectHead;
continue;
}
//
// There are no more sibling object types for the same parent.
// Continue the enumeration of the parent objects
//
if ( Context->StackIndex == 0 ) {
return ERROR_NO_MORE_ITEMS;
}
Context->StackIndex--;
}
}
DWORD
AzpPersistEnumClose(
IN PVOID PersistEnumContext
)
/*++
Routine Description:
This routine returns free any resources consumed by the PersistEnumContext.
A peristance provider will call this routine after determining which objects have changed.
On entry, AzGlResource must be locked exclusive.
Arguments:
PersistEnumContext - A context describing the current state of the enumeration
Return Value:
NO_ERROR - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - not enough memory
Other status codes
--*/
{
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
AzpFreeHeap( PersistEnumContext );
return NO_ERROR;
}
#endif // 0 // Providers don't actually call these yet
DWORD
WINAPI
AzSubmit(
IN AZ_HANDLE AzHandle,
IN DWORD Reserved
)
/*++
Routine Description:
Submit the changes made to the object via the *Create, *SetProperty, or *SetPropertyItem
APIs.
On failure, any changes made to the object are undone.
Arguments:
AzHandle - Passes in the handle to be updated.
Reserved - Reserved. Must by zero.
Return Value:
NO_ERROR - The operation was successful.
ERROR_INVALID_HANDLE - The passed in handle was invalid
--*/
{
DWORD WinStatus;
PGENERIC_OBJECT ReferencedGenericObject = NULL;
PGENERIC_OBJECT GenericObject = (PGENERIC_OBJECT) AzHandle;
DWORD ObjectType;
//
// Grab the global lock
// Only for the admin manager case do we modify anything.
//
AzpLockResourceExclusive( &AzGlResource );
//
// Validate the input parameters
//
if ( Reserved != 0 ) {
AzPrint(( AZD_INVPARM, "AzCloseHandle: Reserved != 0\n" ));
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Determine the type of the object
//
WinStatus = ObGetHandleType( GenericObject,
FALSE, // Don't allow deleted objects
&ObjectType );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Grab the lock exclusively if we're going to change the database
//
if ( ObjectType == OBJECT_TYPE_ADMIN_MANAGER ) {
AzPrint(( AZD_INVPARM, "AzCloseHandle: Can't persist admin manager.\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;
//
// Submit the change
// ??? On failure, update the cache to match the object
//
WinStatus = AzpPersistSubmit( GenericObject, FALSE );
if ( WinStatus != NO_ERROR ) {
//
// Update the cache to match the real object
//
// If we were trying to persist a creation of the object,
// delete the object from the cache.
//
if ( IsEqualGUID( GenericObject->PersistenceGuid, AzGlZeroGuid ) ) {
//
// 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( GenericObject );
//
// Remove the reference representing the list from the parent.
//
ObDereferenceObject( GenericObject );
} else {
//
// Refresh the cache
// Ignore the status code
//
(VOID) AzpPersistRefresh( GenericObject );
}
goto Cleanup;
}
WinStatus = NO_ERROR;
//
// Free locally used resources
//
Cleanup:
if ( ReferencedGenericObject != NULL ) {
ObDereferenceObject( ReferencedGenericObject );
}
//
// Drop the global lock
//
AzpUnlockResource( &AzGlResource );
return WinStatus;
}