NT4/private/lsa/server/dbhandle.c
2020-09-30 17:12:29 +02:00

995 lines
21 KiB
C

/*++
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 "lsasrvp.h"
#include "dbp.h"
//
// Handle Table anchor. The handle table is just a linked list
//
struct _LSAP_DB_HANDLE LsapDbHandleTable;
NTSTATUS
LsapDbInitializeHandleTable()
/*++
Routine Description:
This function initializes the LSA Database Handle Table
Arguments:
None.
Return Value:
NTSTATUS - Standard Nt Result Code. Currently, STATUS_SUCCESS is
the only result code returned.
--*/
{
NTSTATUS Status;
Status = STATUS_SUCCESS;
//
// Just make the statically declared handle point to itself
//
LsapDbHandleTable.Next = &LsapDbHandleTable;
LsapDbHandleTable.Previous = &LsapDbHandleTable;
//
// Initialize the count of open handles to 0
//
LsapDbState.OpenHandleCount = 0;
return(Status);
}
LSAPR_HANDLE
LsapDbCreateHandle(
IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
IN ULONG Options
)
/*++
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.
Return Value:
If successful, the newly created handle is returned otherwise NULL
is returned.
--*/
{
NTSTATUS Status;
LSAP_DB_HANDLE Handle = NULL;
PSID Sid = NULL;
ULONG SidLength;
if (!LsapDbIsLocked()) {
goto CreateHandleError;
}
//
// Allocate memory for the new handle from the process heap.
//
Handle = LsapAllocateLsaHeap(sizeof(struct _LSAP_DB_HANDLE));
if (Handle == NULL) {
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;
//
// 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;
} else if (Options & LSAP_DB_NOT_TRUSTED) {
Handle->Trusted = FALSE;
}
//
// 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.
//
Status = LsapDbGetNamesObject(
ObjectInformation,
&Handle->LogicalNameU,
&Handle->PhysicalNameU
);
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 )) {
goto CreateHandleError;
}
SidLength = RtlLengthSid( Sid );
Handle->Sid = LsapAllocateLsaHeap( SidLength );
if (Handle->Sid == NULL) {
goto CreateHandleError;
}
RtlCopySid( SidLength, Handle->Sid, Sid );
}
//
// Append the handle to the linked list
//
Handle->Next = LsapDbHandleTable.Next;
Handle->Previous = &LsapDbHandleTable;
Handle->Next->Previous = Handle;
Handle->Previous->Next = Handle;
//
// Increment the handle table count
//
LsapDbState.OpenHandleCount++;
#ifdef TRACK_HANDLE_CLOSE
if (Handle == (LSAP_DB_HANDLE) LsapDbHandle)
{
DbgPrint("BUGBUG: Creating global policy handle\n");
DbgBreakPoint();
}
#endif
CreateHandleFinish:
return (Handle);
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)) {
RtlFreeUnicodeString( &Handle->PhysicalNameU );
}
//
// 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
)
/*++
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.
Return Value:
NTSTATUS - Standard Nt Result Code
STATUS_INVALID_HANDLE - Invalid address or handle contents
--*/
{
NTSTATUS Status = STATUS_INVALID_HANDLE;
LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
//
// Verify that the Lsa Database is locked.
//
ASSERT (LsapDbIsLocked());
//
// 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->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) {
goto VerifyHandleError;
}
}
//
// Verify that the handle's reference count is valid and positive
//
if (Handle->ReferenceCount == 0 ||
Handle->ReferenceCount > LSAP_DB_MAXIMUM_REFERENCE_COUNT) {
goto VerifyHandleError;
}
Status = STATUS_SUCCESS;
VerifyHandleFinish:
return(Status);
VerifyHandleError:
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.
--*/
{
LSAP_DB_HANDLE ThisHandle;
ASSERT (LsapDbIsLocked());
//
// Simply do a linear scan of the small list of handles. Jazz this
// up later if needed.
//
for (ThisHandle = LsapDbHandleTable.Next;
ThisHandle != &LsapDbHandleTable;
ThisHandle = ThisHandle->Next) {
if (ThisHandle == (LSAP_DB_HANDLE) ObjectHandle) {
return TRUE;
}
}
return FALSE;
}
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;
ASSERT (LsapDbIsLocked());
//
// Verify that the handle exists. It may be marked invalid
//
Status = LsapDbVerifyHandle(
ObjectHandle,
LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES,
NullObject
);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Unhook the handle from the linked list
//
TempHandle = (LSAP_DB_HANDLE) ObjectHandle;
TempHandle->Next->Previous = TempHandle->Previous;
TempHandle->Previous->Next = TempHandle->Next;
//
// Unlink the handle and free its memory
//
LsapDbFreeHandle( ObjectHandle );
return STATUS_SUCCESS;
}
VOID
LsapDbFreeHandle(
IN LSAPR_HANDLE ObjectHandle
)
/*++
Routine Description:
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 freed.
Return Value:
None. Any error is an internal error.
--*/
{
NTSTATUS Status;
LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
#ifdef TRACK_HANDLE_CLOSE
if (ObjectHandle == LsapDbHandle)
{
DbgPrint("BUGBUG: Closing global policy handle\n");
DbgBreakPoint();
}
#endif
//
// Free the Registry Key Handle (if any).
//
if (Handle->KeyHandle != NULL) {
Status = NtClose(Handle->KeyHandle);
ASSERT(NT_SUCCESS(Status));
Handle->KeyHandle = NULL;
}
//
// Mark the handle as not allocated.
//
Handle->Allocated = FALSE;
//
// Unlink the handle.
//
Handle->Next->Previous = Handle->Previous;
Handle->Previous->Next = Handle->Next;
Handle->Next = NULL;
Handle->Previous = NULL;
//
// Free fields of the handle
//
if (Handle->LogicalNameU.Buffer != NULL) {
RtlFreeUnicodeString( &Handle->LogicalNameU );
}
if (Handle->PhysicalNameU.Buffer != NULL) {
RtlFreeUnicodeString( &Handle->PhysicalNameU );
}
if (Handle->Sid != NULL) {
LsapFreeLsaHeap( Handle->Sid );
}
//
// Decrement the count of open handles.
//
ASSERT(LsapDbState.OpenHandleCount > 0);
LsapDbState.OpenHandleCount--;
//
// Free the handle structure itself
LsapFreeLsaHeap( ObjectHandle );
}
NTSTATUS
LsapDbReferencesHandle(
IN LSAPR_HANDLE ObjectHandle,
OUT PULONG ReferenceCount
)
/*++
Routine Description:
This function returns the Reference Count for an object given a handle.
This is the sum of the Reference Counts found in each open handle. The
LSA Database must be locked before calling this function.
Arguments:
ObjectHandle - Handle to the object.
ReferenceCount - Receives the Reference Count for the object.
Return Value:
NTSTATUS - Standard Nt Result Code
STATUS_INVALID_HANDLE - Specified handle is invalid.
--*/
{
NTSTATUS Status;
LSAP_DB_HANDLE ThisHandle;
LSAP_DB_HANDLE Handle = ObjectHandle;
ULONG ReferenceCountToDate = 0;
//
// Verify that the handle is valid
//
Status = LsapDbVerifyHandle(
ObjectHandle,
LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES,
NullObject
);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Scan the Handle List looking for a match on object type.
//
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, add the Reference Count of the target handle
// to the total Reference Count obtained so far.
//
if (RtlEqualUnicodeString(
&(ThisHandle->LogicalNameU),
&(Handle->LogicalNameU),
FALSE
)) {
ReferenceCountToDate += ThisHandle->ReferenceCount;
}
}
ThisHandle = ThisHandle->Next;
}
*ReferenceCount = ReferenceCountToDate;
return Status;
}
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;
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;
}
return(Status);
}
NTSTATUS
LsapDbObjectNameFromHandle(
IN LSAPR_HANDLE ObjectHandle,
IN BOOLEAN MakeCopy,
IN LSAP_DB_OBJECT_NAME_TYPE ObjectNameType,
OUT PLSAPR_UNICODE_STRING ObjectName
)
/*++
Routine Description:
This function retrieves a name from an Lsa Object Handle. The handle
is assumed to be valid and the Lsa Database lock should be held while
calling this function.
Arguments
ObjectHandle - A handle to the object
MakeCopy - TRUE if a copy of the object name Unicode buffer is
to be allocated via MIDL_user_allocate, else FALSE.
ObjectNameType - Specifies the type of obejct name to be returned.
LsapDbObjectPhysicalName - Return the Physical Name
LsapDbObjectLogicalName - Return the Logical Name
ObjectName - Pointer to Unicode String structure which will be
initialized to point to the object name.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_SUCCESS The call completed successfully
STATUS_NO_MEMORY - Insufficient memory to allocate the buffer
for a copy of the object name when MakeCopy = TRUE.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
LSAPR_UNICODE_STRING OutputObjectName;
PLSAPR_UNICODE_STRING SourceName = NULL;
//
// Copy over the name.
//
switch (ObjectNameType) {
case LsapDbObjectPhysicalName:
SourceName = (PLSAPR_UNICODE_STRING) &InternalHandle->PhysicalNameU;
break;
case LsapDbObjectLogicalName:
SourceName = (PLSAPR_UNICODE_STRING) &InternalHandle->LogicalNameU;
break;
default:
Status = STATUS_INVALID_PARAMETER;
break;
}
if (!NT_SUCCESS(Status)) {
goto ObjectNameFromHandleError;
}
OutputObjectName = *SourceName;
//
// If a copy was requested, allocate memory
//
if (MakeCopy) {
OutputObjectName.Buffer = MIDL_user_allocate( OutputObjectName.MaximumLength );
Status = STATUS_NO_MEMORY;
if (OutputObjectName.Buffer == NULL) {
goto ObjectNameFromHandleError;
}
Status = STATUS_SUCCESS;
RtlMoveMemory(
OutputObjectName.Buffer,
SourceName->Buffer,
SourceName->Length
);
}
*ObjectName = OutputObjectName;
ObjectNameFromHandleFinish:
return(Status);
ObjectNameFromHandleError:
ObjectName->Buffer = NULL;
ObjectName->Length = ObjectName->MaximumLength = 0;
goto ObjectNameFromHandleFinish;
}
VOID
LsapDbDecrementReferenceCountHandle(
IN OUT LSAPR_HANDLE ObjectHandle
)
/*++
Routine Description:
This function decrements the reference count in a handle.
Arguments:
ObjectHandle - Lsa Object handle
Return Values:
None
--*/
{
LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
InternalHandle->ReferenceCount--;
return;
}
VOID
LsapDbMarkTrustedHandle(
IN OUT LSAPR_HANDLE ObjectHandle
)
/*++
Routine Description:
This function marks a handle as being Trusted. No access checking is
done on Trusted Handles, so only clients in the Security Process (lsass)
may use Trusted handles. The handle is assumed to be valid, and the Lsa
Database lock must be held while this function is called.
Arguments:
ObjectHandle - Handle to be marked Trusted
Return Values:
None.
--*/
{
LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
InternalHandle->Trusted = TRUE;
return;
}