You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1585 lines
43 KiB
1585 lines
43 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dbhandle.c
|
|
|
|
Abstract:
|
|
|
|
LSA Database Handle Manager
|
|
|
|
Access to an LSA database object involves a sequence of API calls
|
|
which involve the following:
|
|
|
|
o A call to an object-type dependent "open" API
|
|
o One or more calls to API that manipulate the object
|
|
o A call to the LsaClose API
|
|
|
|
It is necessary to track context for each open of an object, for example,
|
|
the accesses granted and the underlying LSA database handle to the
|
|
object. Lsa handles provide this mechanism: an Lsa handle is simply a
|
|
pointer to a data structure containing this context.
|
|
|
|
Author:
|
|
|
|
Scott Birrell (ScottBi) May 29, 1991
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <lsapch2.h>
|
|
#include "dbp.h"
|
|
#include "adtp.h"
|
|
|
|
|
|
//
|
|
// Handle Table anchor. The handle table is just a linked list
|
|
//
|
|
|
|
struct _LSAP_DB_HANDLE LsapDbHandleTable;
|
|
LSAP_DB_HANDLE_TABLE LsapDbHandleTableEx;
|
|
|
|
NTSTATUS
|
|
LsapDbInitHandleTables(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the LSA Database Handle Tables. It initializes the table members
|
|
and the locks, so it must be called before the table is accessed.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
LsapDbHandleTableEx.UserCount = 0;
|
|
InitializeListHead( &LsapDbHandleTableEx.UserHandleList );
|
|
|
|
LsapDbHandleTableEx.FreedUserEntryCount = 0;
|
|
|
|
//
|
|
// Now, also initialize the flat list
|
|
//
|
|
LsapDbHandleTable.Next = &LsapDbHandleTable;
|
|
LsapDbHandleTable.Previous = &LsapDbHandleTable;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsapDbInsertHandleInTable(
|
|
IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
|
|
IN LSAPR_HANDLE NewHandle,
|
|
IN PLUID UserId,
|
|
IN HANDLE UserToken
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will enter a new handle into the lsa global policy handle table.
|
|
|
|
|
|
Arguments:
|
|
|
|
ObjectInformation - Information on the object being created.
|
|
|
|
NewHandle - New handle to be inserted
|
|
|
|
UserId - LUID of the user creating the handle.
|
|
0: means trusted handle
|
|
|
|
UserToken - Token handle of the user creating the handle. NULL means local system
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Success
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY HandleEntry;
|
|
PLSAP_DB_HANDLE_TABLE_USER_ENTRY CurrentUserEntry = NULL;
|
|
BOOLEAN UserAdded = FALSE;
|
|
BOOLEAN PolicyHandleCountIncremented = FALSE;
|
|
LSAP_DB_HANDLE DbHandle = ( LSAP_DB_HANDLE )NewHandle;
|
|
|
|
LsapEnterFunc( "LsapDbInsertHandleInTable" );
|
|
|
|
//
|
|
// First, grab the handle table lock.
|
|
//
|
|
LsapDbLockAcquire( &LsapDbState.HandleTableLock );
|
|
|
|
//
|
|
// Find the entry that corresponds to our given user.
|
|
//
|
|
|
|
for ( HandleEntry = LsapDbHandleTableEx.UserHandleList.Flink;
|
|
HandleEntry != &LsapDbHandleTableEx.UserHandleList;
|
|
HandleEntry = HandleEntry->Flink ) {
|
|
|
|
CurrentUserEntry = CONTAINING_RECORD( HandleEntry,
|
|
LSAP_DB_HANDLE_TABLE_USER_ENTRY,
|
|
Next );
|
|
|
|
if ( RtlEqualLuid( &CurrentUserEntry->LogonId, UserId ) ) {
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE, "Handle 0x%lp belongs to entry 0x%lp\n",
|
|
NewHandle,
|
|
CurrentUserEntry ));
|
|
break;
|
|
|
|
}
|
|
|
|
CurrentUserEntry = NULL;
|
|
}
|
|
|
|
//
|
|
// Allocate a new entry if necessary.
|
|
//
|
|
if ( CurrentUserEntry == NULL ) {
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE, "Handle list not found for user %x:%x\n",
|
|
UserId->HighPart,
|
|
UserId->LowPart ));
|
|
|
|
//
|
|
// See if we can grab one off the lookaside list
|
|
//
|
|
if ( LsapDbHandleTableEx.FreedUserEntryCount ) {
|
|
|
|
CurrentUserEntry = LsapDbHandleTableEx.FreedUserEntryList[
|
|
LsapDbHandleTableEx.FreedUserEntryCount - 1 ];
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Using user entry 0x%lp from free list spot %lu\n",
|
|
CurrentUserEntry,
|
|
LsapDbHandleTableEx.FreedUserEntryCount-1 ));
|
|
LsapDbHandleTableEx.FreedUserEntryCount--;
|
|
|
|
ASSERT( CurrentUserEntry );
|
|
|
|
|
|
} else {
|
|
|
|
CurrentUserEntry = LsapAllocateLsaHeap( sizeof( LSAP_DB_HANDLE_TABLE_USER_ENTRY ) );
|
|
|
|
if ( CurrentUserEntry == NULL ) {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto InsertHandleInTableEntryExit;
|
|
}
|
|
}
|
|
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Allocated user entry 0x%lp\n", CurrentUserEntry ));
|
|
|
|
//
|
|
// Set the information in the new entry, and then insert it into the lists
|
|
//
|
|
InitializeListHead( &CurrentUserEntry->PolicyHandles );
|
|
InitializeListHead( &CurrentUserEntry->ObjectHandles );
|
|
CurrentUserEntry->PolicyHandlesCount = 0;
|
|
RtlCopyLuid( &CurrentUserEntry->LogonId, UserId );
|
|
CurrentUserEntry->MaxPolicyHandles = LSAP_DB_MAXIMUM_HANDLES_PER_USER ;
|
|
|
|
if ( RtlEqualLuid( UserId, &LsapSystemLogonId ) ||
|
|
RtlEqualLuid( UserId, &LsapZeroLogonId ) )
|
|
{
|
|
|
|
CurrentUserEntry->MaxPolicyHandles = 0x7FFFFFFF ;
|
|
|
|
}
|
|
else if ( UserToken != NULL )
|
|
{
|
|
UCHAR Buffer[ 128 ];
|
|
PTOKEN_USER User ;
|
|
NTSTATUS Status2 ;
|
|
ULONG Size ;
|
|
|
|
User = (PTOKEN_USER) Buffer ;
|
|
|
|
Status2 = NtQueryInformationToken(
|
|
UserToken,
|
|
TokenUser,
|
|
User,
|
|
sizeof( Buffer ),
|
|
&Size );
|
|
|
|
if ( NT_SUCCESS( Status2 ) )
|
|
{
|
|
if ( RtlEqualSid( User->User.Sid, LsapAnonymousSid ) )
|
|
{
|
|
CurrentUserEntry->MaxPolicyHandles = 0x7FFFFFFF ;
|
|
}
|
|
}
|
|
|
|
}
|
|
#if DBG
|
|
if ( UserToken != NULL ) {
|
|
|
|
OBJECT_ATTRIBUTES ObjAttrs;
|
|
SECURITY_QUALITY_OF_SERVICE SecurityQofS;
|
|
NTSTATUS Status2;
|
|
|
|
//
|
|
// Duplicate the token
|
|
//
|
|
InitializeObjectAttributes( &ObjAttrs, NULL, 0L, NULL, NULL );
|
|
SecurityQofS.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
|
|
SecurityQofS.ImpersonationLevel = SecurityImpersonation;
|
|
SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
|
|
SecurityQofS.EffectiveOnly = FALSE;
|
|
ObjAttrs.SecurityQualityOfService = &SecurityQofS;
|
|
|
|
Status2 = NtDuplicateToken( UserToken,
|
|
TOKEN_READ | TOKEN_WRITE | TOKEN_EXECUTE,
|
|
&ObjAttrs,
|
|
FALSE,
|
|
TokenImpersonation,
|
|
&CurrentUserEntry->UserToken );
|
|
if ( !NT_SUCCESS( Status2 ) ) {
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Failed to duplicate the token for handle 0x%lp: 0x%lx\n",
|
|
NewHandle,
|
|
Status2 ));
|
|
|
|
CurrentUserEntry->UserToken = NULL;
|
|
}
|
|
|
|
//
|
|
// A failure to copy the token doesn constitute a failure to add the entry
|
|
//
|
|
|
|
}
|
|
#endif
|
|
|
|
InsertTailList( &LsapDbHandleTableEx.UserHandleList,
|
|
&CurrentUserEntry->Next );
|
|
LsapDbHandleTableEx.UserCount++;
|
|
UserAdded = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Ok, now that we have the entry, let's add it to the appropriate list...
|
|
//
|
|
if ( ObjectInformation->ObjectTypeId == PolicyObject ) {
|
|
ASSERT( DbHandle->ObjectTypeId == PolicyObject );
|
|
|
|
if ( CurrentUserEntry->PolicyHandlesCount >= CurrentUserEntry->MaxPolicyHandles ) {
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Quota exceeded for user %x:%x, handle 0x%lp\n",
|
|
UserId->HighPart,
|
|
UserId->LowPart,
|
|
NewHandle ));
|
|
Status = STATUS_QUOTA_EXCEEDED;
|
|
goto InsertHandleInTableEntryExit;
|
|
|
|
} else {
|
|
|
|
InsertTailList( &CurrentUserEntry->PolicyHandles, &DbHandle->UserHandleList );
|
|
CurrentUserEntry->PolicyHandlesCount++;
|
|
PolicyHandleCountIncremented = TRUE;
|
|
}
|
|
|
|
} else {
|
|
ASSERT( DbHandle->ObjectTypeId != PolicyObject );
|
|
|
|
InsertTailList( &CurrentUserEntry->ObjectHandles, &DbHandle->UserHandleList );
|
|
}
|
|
|
|
//
|
|
// Finally, make sure to insert it in the flat list
|
|
//
|
|
DbHandle->Next = LsapDbHandleTable.Next;
|
|
DbHandle->Previous = &LsapDbHandleTable;
|
|
DbHandle->Next->Previous = DbHandle;
|
|
DbHandle->Previous->Next = DbHandle;
|
|
|
|
DbHandle->UserEntry = ( PVOID )CurrentUserEntry;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
InsertHandleInTableEntryExit:
|
|
|
|
//
|
|
// If we succesfully created the entry, make sure we remove it...
|
|
//
|
|
if ( !NT_SUCCESS( Status ) && UserAdded ) {
|
|
|
|
RemoveEntryList( &DbHandle->UserHandleList );
|
|
if ( PolicyHandleCountIncremented ) {
|
|
CurrentUserEntry->PolicyHandlesCount--;
|
|
}
|
|
|
|
if ( CurrentUserEntry->UserToken ) {
|
|
|
|
NtClose( CurrentUserEntry->UserToken );
|
|
}
|
|
|
|
LsapDbHandleTableEx.UserCount--;
|
|
RemoveEntryList( &CurrentUserEntry->Next );
|
|
LsapFreeLsaHeap( CurrentUserEntry );
|
|
|
|
}
|
|
|
|
LsapDbLockRelease( &LsapDbState.HandleTableLock );
|
|
|
|
LsapExitFunc( "LsapDbInsertHandleInTable", Status );
|
|
return( Status );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
LsapDbFindIdenticalHandleInTable(
|
|
IN OUT PLSAPR_HANDLE OriginalHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will find an existing handle in the lsa global policy handle
|
|
table that matches the passed in handle. If a matching handle is found,
|
|
the passed in handle is dereferenced and the matching handle is returned.
|
|
|
|
If no matching handle is found, the original passed in handle is returned.
|
|
|
|
Arguments:
|
|
|
|
OriginalHandle - Passes in the original handle to compare with.
|
|
Returns the handle that is to be used.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Original handle was returned or new handle was returned.
|
|
|
|
FALSE - New handle would exceed maximum allowed reference count if it were used.
|
|
Original handle is returned.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN RetBool = TRUE;
|
|
LSAP_DB_HANDLE InputHandle;
|
|
LSAP_DB_HANDLE DbHandle;
|
|
PLIST_ENTRY HandleEntry;
|
|
PLSAP_DB_HANDLE_TABLE_USER_ENTRY CurrentUserEntry = NULL;
|
|
|
|
LsapEnterFunc( "LsapDbFindIndenticalHandleInTable" );
|
|
|
|
//
|
|
// Return immediately if the handle isn't a policy handle
|
|
//
|
|
|
|
InputHandle = (LSAP_DB_HANDLE) *OriginalHandle;
|
|
if ( InputHandle->ObjectTypeId != PolicyObject ) {
|
|
LsapExitFunc( "LsapDbFindIdenticalHandleInTable", 0 );
|
|
return TRUE;
|
|
}
|
|
|
|
CurrentUserEntry = (PLSAP_DB_HANDLE_TABLE_USER_ENTRY) InputHandle->UserEntry;
|
|
ASSERT( CurrentUserEntry != NULL );
|
|
|
|
//
|
|
// First, grab the handle table lock.
|
|
//
|
|
LsapDbLockAcquire( &LsapDbState.HandleTableLock );
|
|
|
|
|
|
|
|
//
|
|
// If this is not a trusted handle,
|
|
// try to share the handle.
|
|
//
|
|
|
|
if ( !RtlEqualLuid( &CurrentUserEntry->LogonId, &LsapZeroLogonId ) ) {
|
|
|
|
//
|
|
// Now, walk the appropriate list to find one for the matching access.
|
|
//
|
|
|
|
for ( HandleEntry = CurrentUserEntry->PolicyHandles.Flink;
|
|
HandleEntry != &CurrentUserEntry->PolicyHandles;
|
|
HandleEntry = HandleEntry->Flink ) {
|
|
|
|
//
|
|
// See if the access masks match. If so, we have a winner
|
|
//
|
|
DbHandle = CONTAINING_RECORD( HandleEntry,
|
|
struct _LSAP_DB_HANDLE,
|
|
UserHandleList );
|
|
|
|
//
|
|
// Ignore the original handle
|
|
//
|
|
|
|
if ( DbHandle == InputHandle ) {
|
|
/* Do nothing here */
|
|
|
|
|
|
//
|
|
// The handles are considered identical if the GrantedAccess matches.
|
|
//
|
|
|
|
} else if ( DbHandle->GrantedAccess == InputHandle->GrantedAccess ) {
|
|
|
|
//
|
|
// Don't let this handle be cloned too many times
|
|
//
|
|
|
|
if ( DbHandle->ReferenceCount >= LSAP_DB_MAXIMUM_REFERENCE_COUNT ) {
|
|
RetBool = FALSE;
|
|
break;
|
|
}
|
|
|
|
DbHandle->ReferenceCount++;
|
|
|
|
|
|
#if DBG
|
|
GetSystemTimeAsFileTime( (LPFILETIME) &DbHandle->HandleLastAccessTime );
|
|
#endif // DBG
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Found handle 0x%lp for user %x:%x using access 0x%lx (%ld)\n",
|
|
DbHandle,
|
|
CurrentUserEntry->LogonId.HighPart,
|
|
CurrentUserEntry->LogonId.LowPart,
|
|
DbHandle->GrantedAccess,
|
|
DbHandle->ReferenceCount ));
|
|
|
|
*OriginalHandle = (LSAPR_HANDLE)DbHandle;
|
|
|
|
//
|
|
// Dereference the original handle.
|
|
//
|
|
|
|
LsapDbDereferenceHandle( (LSAPR_HANDLE)InputHandle, TRUE );
|
|
break;
|
|
|
|
} else {
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Handle 0x%lp for user %x:%x has access 0x%lx, need 0x%lx\n",
|
|
DbHandle,
|
|
CurrentUserEntry->LogonId.HighPart,
|
|
CurrentUserEntry->LogonId.LowPart,
|
|
DbHandle->GrantedAccess,
|
|
InputHandle->GrantedAccess ));
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
LsapDbLockRelease( &LsapDbState.HandleTableLock );
|
|
|
|
LsapExitFunc( "LsapDbFindIdenticalHandleInTable", 0 );
|
|
return RetBool;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbRemoveHandleFromTable(
|
|
IN PLSAPR_HANDLE Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes an existing handle from all tables it is in.
|
|
|
|
Enter with LsapDbState.HandleTableLock locked.
|
|
|
|
Arguments:
|
|
|
|
Handle - Handle to remove.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Success
|
|
|
|
STATUS_OBJECT_NAME_NOT_FOUND - The handle for the specified user cannot be found
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PLIST_ENTRY HandleList, HandleEntry;
|
|
PLSAP_DB_HANDLE_TABLE_USER_ENTRY CurrentUserEntry = NULL;
|
|
LSAP_DB_HANDLE DbHandle = ( LSAP_DB_HANDLE )Handle, FoundHandle;
|
|
PULONG EntryToDecrement ;
|
|
|
|
LsapEnterFunc( "LsapDbRemoveHandleFromTable" );
|
|
|
|
CurrentUserEntry = DbHandle->UserEntry;
|
|
ASSERT( CurrentUserEntry != NULL );
|
|
|
|
|
|
if ( DbHandle->ObjectTypeId == PolicyObject ) {
|
|
|
|
HandleList = &CurrentUserEntry->PolicyHandles;
|
|
EntryToDecrement = &CurrentUserEntry->PolicyHandlesCount;
|
|
|
|
} else {
|
|
|
|
HandleList = &CurrentUserEntry->ObjectHandles;
|
|
EntryToDecrement = NULL ;
|
|
}
|
|
|
|
Status = STATUS_NOT_FOUND;
|
|
|
|
for ( HandleEntry = HandleList->Flink;
|
|
HandleEntry != HandleList;
|
|
HandleEntry = HandleEntry->Flink ) {
|
|
|
|
|
|
FoundHandle = CONTAINING_RECORD( HandleEntry,
|
|
struct _LSAP_DB_HANDLE,
|
|
UserHandleList );
|
|
|
|
if ( FoundHandle == DbHandle ) {
|
|
|
|
RemoveEntryList( &FoundHandle->UserHandleList );
|
|
FoundHandle->Next->Previous = FoundHandle->Previous;
|
|
FoundHandle->Previous->Next = FoundHandle->Next;
|
|
|
|
if ( EntryToDecrement ) {
|
|
*EntryToDecrement -= 1 ;
|
|
}
|
|
|
|
//
|
|
// See if we can remove the entry itself
|
|
//
|
|
if ( IsListEmpty( &CurrentUserEntry->PolicyHandles ) &&
|
|
IsListEmpty( &CurrentUserEntry->ObjectHandles ) ) {
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Removing empty user list 0x%lp\n",
|
|
CurrentUserEntry ));
|
|
|
|
RemoveEntryList( &CurrentUserEntry->Next );
|
|
|
|
LsapDbHandleTableEx.UserCount--;
|
|
|
|
if ( CurrentUserEntry->UserToken ) {
|
|
|
|
NtClose( CurrentUserEntry->UserToken );
|
|
}
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Removing user entry 0x%lp\n", CurrentUserEntry ));
|
|
|
|
if ( LsapDbHandleTableEx.FreedUserEntryCount < LSAP_DB_HANDLE_FREE_LIST_SIZE ) {
|
|
|
|
LsapDbHandleTableEx.FreedUserEntryList[
|
|
LsapDbHandleTableEx.FreedUserEntryCount ] = CurrentUserEntry;
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Moving user entry 0x%lp to free list spot %lu\n",
|
|
CurrentUserEntry,
|
|
LsapDbHandleTableEx.FreedUserEntryCount ));
|
|
LsapDbHandleTableEx.FreedUserEntryCount++;
|
|
|
|
} else {
|
|
|
|
LsapFreeLsaHeap( CurrentUserEntry );
|
|
}
|
|
}
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
} else {
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE,
|
|
"Looking for user entry 0x%lp against 0x%lp\n",
|
|
FoundHandle,
|
|
DbHandle ));
|
|
}
|
|
}
|
|
|
|
|
|
LsapExitFunc( "LsapDbRemoveHandleFromTable", Status );
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbCreateHandle(
|
|
IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
|
|
IN ULONG Options,
|
|
IN ULONG CreateHandleOptions,
|
|
OUT LSAPR_HANDLE *CreatedHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates and initializes a handle for an LSA Database object.
|
|
The handle is allocated from the LSA Heap and added to the handle table.
|
|
Using the Object Type, and either the Sid or Name provided in
|
|
ObjectInformation, the Logical and Physical Names of the object are
|
|
constructed and pointers to them are stored in the handle. The LSA
|
|
Database must be locked before calling this function.
|
|
|
|
If there is a Container Handle specified in the ObjectInformation, the
|
|
newly created handle inherits its trusted status (TRUE if trusted, else
|
|
FALSE). If there is no container handle, the trusted status is set
|
|
to FALSE by default. When a non-trusted handle is used to access an
|
|
object, impersonation and access validation occurs.
|
|
|
|
Arguments:
|
|
|
|
ObjectInformation - Pointer to object information structure which must
|
|
have been validated by a calling routine. The following information
|
|
items must be specified:
|
|
|
|
o Object Type Id
|
|
o Object Logical Name (as ObjectAttributes->ObjectName, a pointer to
|
|
a Unicode string)
|
|
o Container object handle (for any object except the Policy object).
|
|
o Object Sid (if any)
|
|
All other fields in ObjectAttributes portion of ObjectInformation
|
|
such as SecurityDescriptor are ignored.
|
|
|
|
Options - Optional actions
|
|
|
|
LSAP_DB_TRUSTED - Handle is to be marked as Trusted.
|
|
handle is use, access checking will be bypassed. If the
|
|
handle is used to create or open a lower level object, that
|
|
object's handle will by default inherit the Trusted property.
|
|
|
|
LSAP_DB_NON_TRUSTED - Handle is to be marked as Non-Trusted.
|
|
|
|
If neither of the above options is specified, the handle will
|
|
either inherit the trusted status of the Container Handle
|
|
provilde in ObjectInformation, or, if none, the handle will
|
|
be marked non-trusted.
|
|
|
|
CreateHandleOptions - Options used to control the behavior of the CreateHandle function.
|
|
|
|
CreatedHandle - Where the created handle is returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -- Success
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
|
|
|
|
STATUS_INVALID_SID - A bogus sid was encountered
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
LSAP_DB_HANDLE Handle = NULL;
|
|
PSID Sid = NULL;
|
|
ULONG SidLength;
|
|
BOOLEAN ObjectInReg = TRUE, ObjectInDs = FALSE, NewTrustObject = FALSE;
|
|
HANDLE ClientToken;
|
|
LUID UserId;
|
|
TOKEN_STATISTICS TokenStats;
|
|
ULONG InfoReturned;
|
|
BOOL Locked = FALSE ;
|
|
HANDLE ClientTokenToFree = NULL;
|
|
|
|
//
|
|
// First, grab the handle table lock.
|
|
//
|
|
LsapDbLockAcquire( &LsapDbState.HandleTableLock );
|
|
|
|
Locked = TRUE ;
|
|
|
|
|
|
//
|
|
// Get the current users token, unless we are trusted...
|
|
//
|
|
|
|
UserId = LsapZeroLogonId;
|
|
if ( ObjectInformation->ObjectAttributes.RootDirectory == NULL ||
|
|
!( (LSAP_DB_HANDLE)ObjectInformation->ObjectAttributes.RootDirectory )->Trusted ) {
|
|
|
|
Status = I_RpcMapWin32Status( RpcImpersonateClient( 0 ) );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
Status = NtOpenThreadToken( NtCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_DUPLICATE,
|
|
TRUE,
|
|
&ClientToken );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
Status = NtQueryInformationToken( ClientToken,
|
|
TokenStatistics,
|
|
&TokenStats,
|
|
sizeof( TokenStats ),
|
|
&InfoReturned );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
UserId = TokenStats.AuthenticationId;
|
|
}
|
|
|
|
ClientTokenToFree = ClientToken;
|
|
}
|
|
|
|
Status = I_RpcMapWin32Status( RpcRevertToSelf() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LsapDbLockRelease( &LsapDbState.HandleTableLock );
|
|
|
|
Locked = FALSE ;
|
|
|
|
//
|
|
// Allocate memory for the new handle from the process heap.
|
|
//
|
|
|
|
Handle = LsapAllocateLsaHeap(sizeof(struct _LSAP_DB_HANDLE));
|
|
|
|
if (Handle == NULL) {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CreateHandleError;
|
|
}
|
|
|
|
//
|
|
// Mark the handle as allocated and initialize the reference count
|
|
// to one. Initialize other fields based on the object information
|
|
// supplied.
|
|
//
|
|
|
|
Handle->Allocated = TRUE;
|
|
Handle->KeyHandle = NULL;
|
|
Handle->ReferenceCount = 1;
|
|
Handle->ObjectTypeId = ObjectInformation->ObjectTypeId;
|
|
Handle->ContainerHandle = ( LSAP_DB_HANDLE )ObjectInformation->ObjectAttributes.RootDirectory;
|
|
Handle->Sid = NULL;
|
|
Handle->Trusted = FALSE;
|
|
Handle->DeletedObject = FALSE;
|
|
Handle->GenerateOnClose = FALSE;
|
|
Handle->Options = Options;
|
|
Handle->LogicalNameU.Buffer = NULL;
|
|
Handle->PhysicalNameU.Buffer = NULL;
|
|
Handle->PhysicalNameDs.Buffer = NULL;
|
|
Handle->RequestedAccess = ObjectInformation->DesiredObjectAccess;
|
|
InitializeListHead( &Handle->UserHandleList );
|
|
Handle->UserEntry = NULL;
|
|
Handle->SceHandle = (( Options & LSAP_DB_SCE_POLICY_HANDLE ) != 0 );
|
|
Handle->SceHandleChild = (( ObjectInformation->ObjectAttributes.RootDirectory != NULL ) &&
|
|
((( LSAP_DB_HANDLE )ObjectInformation->ObjectAttributes.RootDirectory)->SceHandle ));
|
|
#ifdef DBG
|
|
|
|
//
|
|
// ScePolicy lock must be held when opening an SCE Policy handle
|
|
//
|
|
|
|
if ( Handle->SceHandle ) {
|
|
|
|
ASSERT( LsapDbResourceIsLocked( ( PSAFE_RESOURCE )&LsapDbState.ScePolicyLock ));
|
|
}
|
|
|
|
RtlZeroMemory( &Handle->HandleLastAccessTime, sizeof( LARGE_INTEGER ) );
|
|
|
|
GetSystemTimeAsFileTime( (LPFILETIME) &Handle->HandleCreateTime );
|
|
|
|
#endif
|
|
|
|
//
|
|
// By default, the handle inherits the Trusted status of the
|
|
// container handle.
|
|
//
|
|
|
|
if (Handle->ContainerHandle != NULL) {
|
|
|
|
Handle->Trusted = Handle->ContainerHandle->Trusted;
|
|
}
|
|
|
|
//
|
|
// If Trusted/Non-Trusted status is explicitly specified, set the
|
|
// status to that specified.
|
|
//
|
|
|
|
if (Options & LSAP_DB_TRUSTED) {
|
|
|
|
Handle->Trusted = TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// Capture the object's Logical and construct Physical Names from the
|
|
// Object Information and store them in the handle. These names are
|
|
// internal to the Lsa Database. Note that the input Logical Name
|
|
// cannot be directly stored in the handle because it will be in
|
|
// storage that is scoped only to the underlying server API call if
|
|
// the object for which this create handle is being done is of a type
|
|
// that is opened or created by name rather than by Sid.
|
|
//
|
|
|
|
//
|
|
// Set the objects location
|
|
//
|
|
Handle->PhysicalNameDs.Length = 0;
|
|
|
|
switch ( ObjectInformation->ObjectTypeId ) {
|
|
|
|
case TrustedDomainObject:
|
|
case NewTrustedDomainObject:
|
|
|
|
ObjectInReg = !LsapDsWriteDs;
|
|
ObjectInDs = LsapDsWriteDs;
|
|
Handle->ObjectTypeId = TrustedDomainObject;
|
|
break;
|
|
|
|
case AccountObject:
|
|
case PolicyObject:
|
|
|
|
ObjectInReg = TRUE;
|
|
ObjectInDs = FALSE;
|
|
break;
|
|
|
|
case SecretObject:
|
|
|
|
ObjectInReg = TRUE;
|
|
if ( LsapDsWriteDs && FLAG_ON( Options, LSAP_DB_OBJECT_SCOPE_DS ) ) {
|
|
|
|
ObjectInDs = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Status = LsapDbGetNamesObject( ObjectInformation,
|
|
CreateHandleOptions,
|
|
&Handle->LogicalNameU,
|
|
ObjectInReg ? &Handle->PhysicalNameU : NULL,
|
|
ObjectInDs ? &Handle->PhysicalNameDs : NULL );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto CreateHandleError;
|
|
}
|
|
|
|
//
|
|
// Make a copy of the object's Sid and store pointer to it in
|
|
// the handle.
|
|
//
|
|
|
|
if (ObjectInformation->Sid != NULL) {
|
|
|
|
Sid = ObjectInformation->Sid;
|
|
|
|
if (!RtlValidSid( Sid )) {
|
|
|
|
Status = STATUS_INVALID_SID;
|
|
goto CreateHandleError;
|
|
}
|
|
|
|
SidLength = RtlLengthSid( Sid );
|
|
|
|
Handle->Sid = LsapAllocateLsaHeap( SidLength );
|
|
|
|
if (Handle->Sid == NULL) {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CreateHandleError;
|
|
}
|
|
|
|
RtlCopySid( SidLength, Handle->Sid, Sid );
|
|
}
|
|
|
|
//
|
|
// Append the handle to the linked list
|
|
//
|
|
|
|
|
|
LsapDbLockAcquire( &LsapDbState.HandleTableLock );
|
|
|
|
Locked = TRUE ;
|
|
|
|
Status = LsapDbInsertHandleInTable( ObjectInformation,
|
|
Handle,
|
|
&UserId,
|
|
ClientTokenToFree
|
|
);
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
|
|
goto CreateHandleError;
|
|
}
|
|
|
|
//
|
|
// Increment the handle table count
|
|
//
|
|
|
|
LsapDbState.OpenHandleCount++;
|
|
|
|
CreateHandleFinish:
|
|
|
|
if ( ClientTokenToFree ) {
|
|
|
|
NtClose( ClientTokenToFree );
|
|
}
|
|
|
|
*CreatedHandle = ( LSAPR_HANDLE )Handle;
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE, "Handle Created 0x%lp\n",
|
|
Handle ));
|
|
|
|
if ( Locked )
|
|
{
|
|
LsapDbLockRelease( &LsapDbState.HandleTableLock );
|
|
}
|
|
|
|
return( Status );
|
|
|
|
CreateHandleError:
|
|
|
|
//
|
|
// If necessary, free the handle and contents.
|
|
//
|
|
|
|
if (Handle != NULL) {
|
|
|
|
//
|
|
// If a Sid was allocated, free it.
|
|
//
|
|
|
|
if (Handle->Sid != NULL) {
|
|
|
|
LsapFreeLsaHeap( Handle->Sid );
|
|
}
|
|
|
|
//
|
|
// If a Logical Name Buffer was allocated, free it.
|
|
//
|
|
|
|
if ((Handle->LogicalNameU.Length != 0) &&
|
|
(Handle->LogicalNameU.Buffer != NULL)) {
|
|
|
|
RtlFreeUnicodeString( &Handle->LogicalNameU );
|
|
}
|
|
|
|
//
|
|
// If a Physical Name Buffer was allocated, free it.
|
|
//
|
|
|
|
if ((Handle->PhysicalNameU.Length != 0) &&
|
|
(Handle->PhysicalNameU.Buffer != NULL)) {
|
|
|
|
LsapFreeLsaHeap( Handle->PhysicalNameU.Buffer );
|
|
}
|
|
|
|
//
|
|
// Free the handle itself.
|
|
//
|
|
|
|
LsapFreeLsaHeap( Handle );
|
|
Handle = NULL;
|
|
}
|
|
|
|
Handle = NULL;
|
|
goto CreateHandleFinish;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbVerifyHandle(
|
|
IN LSAPR_HANDLE ObjectHandle,
|
|
IN ULONG Options,
|
|
IN LSAP_DB_OBJECT_TYPE_ID ExpectedObjectTypeId,
|
|
IN BOOLEAN ReferenceHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function verifies that a handle has a valid address and is of valid
|
|
format. The handle must be allocated and have a positive reference
|
|
count within the valid range. The object type id must be within range
|
|
and optionally equal to a specified type. The Lsa Database must be
|
|
locked before calling this function.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - Handle to be validated.
|
|
|
|
Options - Specifies optional actions to be taken
|
|
|
|
LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES - Allow handles for
|
|
deleted objects to pass the validation.
|
|
|
|
Other option flags may be specified. They will be ignored.
|
|
|
|
ExpectedObjectTypeId - Expected object type. If NullObject is
|
|
specified, the object type id is only range checked.
|
|
|
|
ReferenceHandle - True if handle reference count is to be incemented
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_INVALID_HANDLE - Invalid address or handle contents
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
|
|
|
|
//
|
|
// Lock the handle table.
|
|
//
|
|
|
|
LsapDbLockAcquire( &LsapDbState.HandleTableLock );
|
|
|
|
|
|
//
|
|
// First verify that the handle's address is valid.
|
|
//
|
|
|
|
if (!LsapDbLookupHandle( ObjectHandle )) {
|
|
|
|
goto VerifyHandleError;
|
|
}
|
|
|
|
//
|
|
// Verify that the handle is allocated
|
|
//
|
|
|
|
if (!Handle->Allocated) {
|
|
|
|
goto VerifyHandleError;
|
|
}
|
|
|
|
//
|
|
// If the handle is marked as invalid, return an error unless
|
|
// these are admissible, e.g when validating for a close option
|
|
//
|
|
|
|
if (Handle->DeletedObject) {
|
|
|
|
if (!(Options & LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES)) {
|
|
|
|
goto VerifyHandleError;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Verify that the handle contains a non-NULL handle to a Registry
|
|
// Key
|
|
//
|
|
|
|
if (!Handle->fWriteDs && Handle->KeyHandle == NULL) {
|
|
|
|
goto VerifyHandleError;
|
|
}
|
|
|
|
//
|
|
// Now either range-check or match the handle type
|
|
//
|
|
|
|
if (ExpectedObjectTypeId == NullObject) {
|
|
|
|
if ((Handle->ObjectTypeId < PolicyObject) ||
|
|
(Handle->ObjectTypeId >= DummyLastObject)) {
|
|
|
|
goto VerifyHandleError;
|
|
}
|
|
|
|
} else {
|
|
|
|
ASSERT (ExpectedObjectTypeId >= PolicyObject &&
|
|
ExpectedObjectTypeId < DummyLastObject);
|
|
|
|
if (Handle->ObjectTypeId != ExpectedObjectTypeId) {
|
|
|
|
//
|
|
// For a secret object, it's possible that we were given a trusted domain
|
|
// handle as well.
|
|
//
|
|
if ( !(ExpectedObjectTypeId == SecretObject &&
|
|
Handle->ObjectTypeId == TrustedDomainObject &&
|
|
FLAG_ON( Handle->Options, LSAP_DB_DS_TRUSTED_DOMAIN_AS_SECRET ) ) ) {
|
|
|
|
goto VerifyHandleError;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Verify that the handle's reference count is valid and positive
|
|
//
|
|
|
|
if (Handle->ReferenceCount == 0) {
|
|
goto VerifyHandleError;
|
|
}
|
|
|
|
#ifdef LSAP_TRACK_HANDLE
|
|
GetSystemTimeAsFileTime( (LPFILETIME) &Handle->HandleLastAccessTime );
|
|
#endif
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
VerifyHandleFinish:
|
|
|
|
//ASSERT( Status != STATUS_INVALID_HANDLE );
|
|
|
|
|
|
//
|
|
// Reference the handle
|
|
//
|
|
if ( ReferenceHandle && NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// This is an internal reference.
|
|
// Don't enforce LSAP_DB_MAXIMUM_REFERENCE_COUNT.
|
|
//
|
|
|
|
Handle->ReferenceCount++;
|
|
LsapDsDebugOut(( DEB_HANDLE, "Handle Rref 0x%lp (%ld)\n",
|
|
Handle,
|
|
Handle->ReferenceCount ));
|
|
}
|
|
|
|
LsapDbLockRelease( &LsapDbState.HandleTableLock );
|
|
return(Status);
|
|
|
|
VerifyHandleError:
|
|
Status = STATUS_INVALID_HANDLE;
|
|
goto VerifyHandleFinish;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
LsapDbLookupHandle(
|
|
IN LSAPR_HANDLE ObjectHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function checks if a handle address is valid. The Lsa Database must
|
|
be locked before calling this function.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - handle to be validated.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if handle is valid. FALSE if handle does not exist or
|
|
is invalid.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN ReturnValue = FALSE;
|
|
LSAP_DB_HANDLE ThisHandle;
|
|
|
|
LsapDbLockAcquire( &LsapDbState.HandleTableLock );
|
|
|
|
//
|
|
// Simply do a linear scan of the small list of handles. Jazz this
|
|
// up later if needed.
|
|
//
|
|
|
|
for (ThisHandle = LsapDbHandleTable.Next;
|
|
ThisHandle != &LsapDbHandleTable && ThisHandle != NULL;
|
|
ThisHandle = ThisHandle->Next) {
|
|
|
|
if (ThisHandle == (LSAP_DB_HANDLE) ObjectHandle) {
|
|
|
|
ReturnValue = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT( ThisHandle );
|
|
|
|
LsapDbLockRelease( &LsapDbState.HandleTableLock );
|
|
|
|
return( ReturnValue );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbCloseHandle(
|
|
IN LSAPR_HANDLE ObjectHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function closes an LSA Handle. The memory for the handle is
|
|
freed. The LSA database must be locked before calling this function.
|
|
|
|
NOTE: Currently, handles do not have reference counts since they
|
|
are not shared among client threads.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - Handle to be closed.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Return code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
LSAP_DB_HANDLE TempHandle;
|
|
|
|
//
|
|
// Verify that the handle exists. It may be marked invalid
|
|
//
|
|
|
|
LsapDbLockAcquire( &LsapDbState.HandleTableLock );
|
|
Status = LsapDbVerifyHandle(
|
|
ObjectHandle,
|
|
LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES,
|
|
NullObject,
|
|
FALSE );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
LsapDbDereferenceHandle( ObjectHandle, FALSE );
|
|
}
|
|
|
|
LsapDbLockRelease( &LsapDbState.HandleTableLock );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
LsapDbDereferenceHandle(
|
|
IN LSAPR_HANDLE ObjectHandle,
|
|
IN BOOLEAN CalledInSuccessPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function decrement the reference count on the handle.
|
|
If the reference count is decremented to zero,
|
|
this function unlinks a handle and frees its memory. If the handle
|
|
contains a non-NULL Registry Key handle that handle is closed.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - handle to be dereferenced
|
|
|
|
CalledInSuccessPath - TRUE if this function is called in a success path.
|
|
With this information, we can decide if we will crash the server if auditing
|
|
fails when LsapCrashOnAuditFail is TRUE.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the reference count reached zero.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
|
|
BOOLEAN RetVal = FALSE;
|
|
BOOL RevertResult = FALSE;
|
|
BOOL Impersonating = FALSE;
|
|
//
|
|
// Dereference the handle
|
|
//
|
|
LsapDbLockAcquire( &LsapDbState.HandleTableLock );
|
|
Handle->ReferenceCount --;
|
|
if ( Handle->ReferenceCount != 0 ) {
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE, "Handle Deref 0x%lp %ld\n",
|
|
Handle,
|
|
Handle->ReferenceCount ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Avoid freeing the global policy handle
|
|
//
|
|
if ( ObjectHandle == LsapPolicyHandle ) {
|
|
|
|
ASSERT( Handle->ReferenceCount != 0 );
|
|
if ( Handle->ReferenceCount == 0 ) {
|
|
Handle->ReferenceCount++;
|
|
}
|
|
#ifdef DBG
|
|
DbgPrint("Freeing global policy handle\n");
|
|
#endif
|
|
goto Cleanup;
|
|
}
|
|
|
|
LsapDsDebugOut(( DEB_HANDLE, "Handle Freed 0x%lp\n",
|
|
Handle ));
|
|
|
|
//
|
|
// Unhook the handle from the linked list
|
|
//
|
|
Status = LsapDbRemoveHandleFromTable( ObjectHandle );
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
DbgPrint( "LSASRV:Failed to remove handle 0x%lp from the global table!\n", ObjectHandle );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Free the Registry Key Handle (if any).
|
|
//
|
|
|
|
if (Handle->KeyHandle != NULL) {
|
|
|
|
Status = NtClose(Handle->KeyHandle);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
Handle->KeyHandle = NULL;
|
|
}
|
|
|
|
//
|
|
// we generate the audit only when we are being called in sucess path
|
|
// in the failure path, the open audit was not generated thus there is
|
|
// no point in generating the close audit either
|
|
//
|
|
|
|
if ( CalledInSuccessPath ) {
|
|
|
|
//
|
|
// impersonate the client so that audit event shows correct user
|
|
// Do this only for untrusted clients
|
|
|
|
if ( !Handle->Trusted ) {
|
|
|
|
if ( Handle->Options & LSAP_DB_USE_LPC_IMPERSONATE ) {
|
|
|
|
Status = LsapImpersonateClient( );
|
|
|
|
} else {
|
|
|
|
Status = I_RpcMapWin32Status(RpcImpersonateClient(0));
|
|
}
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
Impersonating = TRUE;
|
|
}
|
|
else if ( ( Status == RPC_NT_NO_CALL_ACTIVE ) ||
|
|
( Status == RPC_NT_NO_CONTEXT_AVAILABLE ) ) {
|
|
|
|
//
|
|
// we dont want to fail the audit if
|
|
// -- the call is not over RPC (RPC_NT_NO_CALL_ACTIVE)
|
|
// -- the client died prematurely (RPC_NT_NO_CONTEXT_AVAILABLE)
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
DsysAssertMsg( NT_SUCCESS(Status), "LsapDbDereferenceHandle: failed to impersonate" );
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
LsapAuditFailed( Status );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Audit that we're closing the handle
|
|
//
|
|
|
|
Status = NtCloseObjectAuditAlarm (
|
|
&LsapState.SubsystemName,
|
|
ObjectHandle,
|
|
Handle->GenerateOnClose );
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
LsapAuditFailed( Status );
|
|
}
|
|
|
|
if ( !Handle->Trusted ) {
|
|
|
|
//
|
|
// unimpersonate
|
|
//
|
|
|
|
if ( Impersonating ) {
|
|
|
|
if ( Handle->Options & LSAP_DB_USE_LPC_IMPERSONATE ) {
|
|
|
|
RevertResult = RevertToSelf();
|
|
DsysAssertMsg( RevertResult, "LsapDbDereferenceHandle: RevertToSelf() failed" );
|
|
|
|
} else {
|
|
|
|
Status = I_RpcMapWin32Status(RpcRevertToSelf());
|
|
|
|
DsysAssertMsg( NT_SUCCESS(Status), "LsapDbDereferenceHandle: RpcRevertToSelf() failed" );
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Mark the handle as not allocated.
|
|
//
|
|
|
|
Handle->Allocated = FALSE;
|
|
|
|
//
|
|
// Free fields of the handle
|
|
//
|
|
|
|
if (Handle->LogicalNameU.Buffer != NULL) {
|
|
|
|
RtlFreeUnicodeString( &Handle->LogicalNameU );
|
|
}
|
|
|
|
if (Handle->PhysicalNameU.Buffer != NULL) {
|
|
|
|
LsapFreeLsaHeap( Handle->PhysicalNameU.Buffer );
|
|
}
|
|
|
|
if (Handle->PhysicalNameDs.Buffer != NULL) {
|
|
|
|
LsapFreeLsaHeap( Handle->PhysicalNameDs.Buffer );
|
|
}
|
|
|
|
if (Handle->Sid != NULL) {
|
|
|
|
LsapFreeLsaHeap( Handle->Sid );
|
|
}
|
|
|
|
if (Handle->SceHandle) {
|
|
|
|
#ifdef DBG
|
|
ASSERT( WAIT_TIMEOUT == WaitForSingleObject( LsapDbState.SceSyncEvent, 0 ));
|
|
ASSERT( g_ScePolicyLocked );
|
|
g_ScePolicyLocked = FALSE;
|
|
#endif
|
|
|
|
RtlReleaseResource( &LsapDbState.ScePolicyLock );
|
|
SetEvent( LsapDbState.SceSyncEvent );
|
|
}
|
|
|
|
//
|
|
// Decrement the count of open handles.
|
|
//
|
|
|
|
ASSERT(LsapDbState.OpenHandleCount > 0);
|
|
LsapDbState.OpenHandleCount--;
|
|
|
|
#ifdef LSAP_TRACK_HANDLE
|
|
if ( Handle->ClientToken ) {
|
|
|
|
NtClose( Handle->ClientToken );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Free the handle structure itself
|
|
|
|
LsapFreeLsaHeap( ObjectHandle );
|
|
RetVal = TRUE;
|
|
|
|
Cleanup:
|
|
LsapDbLockRelease( &LsapDbState.HandleTableLock );
|
|
|
|
return RetVal;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbMarkDeletedObjectHandles(
|
|
IN LSAPR_HANDLE ObjectHandle,
|
|
IN BOOLEAN MarkSelf
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function invalidates open handles to an object. It is used
|
|
by object deletion code. Once an object has been deleted, the only
|
|
operation permitted on open handles remaining is to close them.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - Handle to an Lsa object.
|
|
|
|
MarkSelf - If TRUE, all handles to the object will be marked to
|
|
indicate that the object to which they relate has been deleted.
|
|
including the passed handle. If FALSE, all handles to the object
|
|
except the passed handle will be so marked.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
LSAP_DB_HANDLE ThisHandle;
|
|
LSAP_DB_HANDLE Handle = ObjectHandle;
|
|
|
|
LsapDbLockAcquire( &LsapDbState.HandleTableLock );
|
|
|
|
ThisHandle = LsapDbHandleTable.Next;
|
|
|
|
while (ThisHandle != &LsapDbHandleTable) {
|
|
|
|
//
|
|
// Match on Object Type Id.
|
|
//
|
|
|
|
if (ThisHandle->ObjectTypeId == Handle->ObjectTypeId) {
|
|
|
|
//
|
|
// Object Type Id's match. If the Logical Names also
|
|
// match, invalidate the handle unless the handle is the
|
|
// passed one and we're to leave it valid.
|
|
//
|
|
|
|
if (RtlEqualUnicodeString(
|
|
&(ThisHandle->LogicalNameU),
|
|
&(Handle->LogicalNameU),
|
|
FALSE
|
|
)) {
|
|
|
|
if (MarkSelf || ThisHandle != (LSAP_DB_HANDLE) ObjectHandle) {
|
|
|
|
ThisHandle->DeletedObject = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
ThisHandle = ThisHandle->Next;
|
|
}
|
|
|
|
LsapDbLockRelease( &LsapDbState.HandleTableLock );
|
|
|
|
|
|
return(Status);
|
|
}
|