520 lines
14 KiB
C
520 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
obinsert.c
|
||
|
||
Abstract:
|
||
|
||
Object instantiation API
|
||
|
||
Author:
|
||
|
||
Steve Wood (stevewo) 31-Mar-1989
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "obp.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,ObInsertObject)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
ObInsertObject (
|
||
IN PVOID Object,
|
||
IN PACCESS_STATE AccessState OPTIONAL,
|
||
IN ACCESS_MASK DesiredAccess OPTIONAL,
|
||
IN ULONG ObjectPointerBias,
|
||
OUT PVOID *NewObject OPTIONAL,
|
||
OUT PHANDLE Handle OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine inserts an object into the current processes handle table.
|
||
|
||
The Object header includes a pointer to a SecurityDescriptor passed in
|
||
an object creation call. This SecurityDescriptor is not assumed to have
|
||
been captured. This routine is responsible for making an appropriate
|
||
SecurityDescriptor and removing the reference in the object header.
|
||
|
||
Arguments:
|
||
|
||
Object - Supplies a pointer to the new object body
|
||
|
||
AccessState - Optionally supplies the access state for the new
|
||
handle
|
||
|
||
DesiredAccess - Optionally supplies the desired access we want for the
|
||
new handle
|
||
|
||
ObjectPointerBias - Supplies a bias to apply for the pointer count for the
|
||
object
|
||
|
||
NewObject - Optionally receives the pointer to the new object that we've
|
||
created a handle for
|
||
|
||
Handle - Receives the new handle, If NULL then no handle is created.
|
||
Objects that don't have handles created must be unnamed and
|
||
have an object bias of zero.
|
||
|
||
Return Value:
|
||
|
||
An appropriate NTSTATUS value.
|
||
|
||
--*/
|
||
|
||
{
|
||
POBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
||
POBJECT_HEADER ObjectHeader;
|
||
PUNICODE_STRING ObjectName;
|
||
POBJECT_TYPE ObjectType;
|
||
POBJECT_HEADER_NAME_INFO NameInfo;
|
||
PSECURITY_DESCRIPTOR ParentDescriptor = NULL;
|
||
PVOID InsertObject;
|
||
HANDLE NewHandle;
|
||
OB_OPEN_REASON OpenReason;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ACCESS_STATE LocalAccessState;
|
||
AUX_ACCESS_DATA AuxData;
|
||
BOOLEAN SecurityDescriptorAllocated;
|
||
KPROCESSOR_MODE PreviousMode;
|
||
NTSTATUS ReturnStatus;
|
||
PVOID DirObject = NULL;
|
||
OBP_LOOKUP_CONTEXT LookupContext;
|
||
|
||
PAGED_CODE();
|
||
|
||
ObpValidateIrql("ObInsertObject");
|
||
|
||
//
|
||
// Get the address of the object header, the object create information,
|
||
// the object type, and the address of the object name descriptor, if
|
||
// specified.
|
||
//
|
||
|
||
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
|
||
|
||
#if DBG
|
||
|
||
if ((ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) == 0) {
|
||
|
||
KdPrint(("OB: Attempting to insert existing object %08x\n", Object));
|
||
KdBreakPoint();
|
||
|
||
ObDereferenceObject(Object);
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
#endif
|
||
|
||
ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
|
||
|
||
ObjectType = ObjectHeader->Type;
|
||
|
||
NameInfo = ObpReferenceNameInfo( ObjectHeader );
|
||
|
||
ObjectName = NULL;
|
||
|
||
if ((NameInfo != NULL) && (NameInfo->Name.Buffer != NULL)) {
|
||
|
||
ObjectName = &NameInfo->Name;
|
||
}
|
||
|
||
ASSERT (ARGUMENT_PRESENT (Handle) || (ObjectPointerBias == 0 && ObjectName == NULL &&
|
||
ObjectType->TypeInfo.SecurityRequired && NewObject == NULL));
|
||
|
||
//
|
||
// If security checks are not required and an object name is not
|
||
// specified, insert an unnamed object, biasing the count
|
||
// by one, dereference the bias, and return to our caller
|
||
//
|
||
|
||
PreviousMode = KeGetPreviousMode();
|
||
|
||
if (!ObjectType->TypeInfo.SecurityRequired && (ObjectName == NULL)) {
|
||
|
||
ObjectHeader->ObjectCreateInfo = NULL;
|
||
|
||
*Handle = NULL;
|
||
|
||
Status = ObpCreateUnnamedHandle( Object,
|
||
DesiredAccess,
|
||
1 + ObjectPointerBias,
|
||
ObjectCreateInfo->Attributes,
|
||
PreviousMode,
|
||
NewObject,
|
||
Handle );
|
||
//
|
||
// Free the object creation information and dereference the object.
|
||
//
|
||
|
||
ObpFreeObjectCreateInformation(ObjectCreateInfo);
|
||
|
||
ObpDereferenceNameInfo( NameInfo );
|
||
ObDereferenceObject(Object);
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// The object is either named or requires full security checks. If the
|
||
// caller hasn't specified an access state then dummy up a local one
|
||
// using the requested desired access
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(AccessState)) {
|
||
|
||
AccessState = &LocalAccessState;
|
||
|
||
Status = SeCreateAccessState( &LocalAccessState,
|
||
&AuxData,
|
||
DesiredAccess,
|
||
&ObjectType->TypeInfo.GenericMapping );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
ObpDereferenceNameInfo( NameInfo );
|
||
ObDereferenceObject(Object);
|
||
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;
|
||
|
||
//
|
||
// Check the desired access mask against the security descriptor
|
||
//
|
||
|
||
Status = ObpValidateAccessMask( AccessState );
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
|
||
ObpDereferenceNameInfo( NameInfo );
|
||
ObDereferenceObject(Object);
|
||
|
||
return( Status );
|
||
}
|
||
|
||
//
|
||
// Set some local state variables
|
||
//
|
||
|
||
ObpInitializeLookupContext(&LookupContext);
|
||
|
||
InsertObject = Object;
|
||
OpenReason = ObCreateHandle;
|
||
|
||
//
|
||
// Check if we have an object name. If so then
|
||
// lookup the name
|
||
//
|
||
|
||
if (ObjectName != NULL) {
|
||
|
||
Status = ObpLookupObjectName( ObjectCreateInfo->RootDirectory,
|
||
ObjectName,
|
||
ObjectCreateInfo->Attributes,
|
||
ObjectType,
|
||
(KPROCESSOR_MODE)(ObjectHeader->Flags & OB_FLAG_KERNEL_OBJECT
|
||
? KernelMode : UserMode),
|
||
ObjectCreateInfo->ParseContext,
|
||
ObjectCreateInfo->SecurityQos,
|
||
Object,
|
||
AccessState,
|
||
&LookupContext,
|
||
&InsertObject );
|
||
|
||
//
|
||
// We found the name and it is not the object we have as our input.
|
||
// So we cannot insert the object again so we'll return an
|
||
// appropriate status
|
||
//
|
||
|
||
if (NT_SUCCESS(Status) &&
|
||
(InsertObject != NULL) &&
|
||
(InsertObject != Object)) {
|
||
|
||
OpenReason = ObOpenHandle;
|
||
|
||
if (ObjectCreateInfo->Attributes & OBJ_OPENIF) {
|
||
|
||
if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type) {
|
||
|
||
Status = STATUS_OBJECT_TYPE_MISMATCH;
|
||
|
||
} else {
|
||
|
||
Status = STATUS_OBJECT_NAME_EXISTS; // Warning only
|
||
}
|
||
|
||
} else {
|
||
|
||
Status = STATUS_OBJECT_NAME_COLLISION;
|
||
}
|
||
}
|
||
|
||
//
|
||
// We did not find the name so we'll cleanup after ourselves
|
||
// and return to our caller
|
||
//
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
|
||
ObpReleaseLookupContext( &LookupContext );
|
||
|
||
ObpDereferenceNameInfo( NameInfo );
|
||
ObDereferenceObject( Object );
|
||
|
||
//
|
||
// Free security information if we allocated it
|
||
//
|
||
|
||
if (AccessState == &LocalAccessState) {
|
||
|
||
SeDeleteAccessState( AccessState );
|
||
}
|
||
|
||
return( Status );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Otherwise we did locate the object name
|
||
//
|
||
// If we just created a named symbolic link then call out to
|
||
// handle any Dos Device name semanatics.
|
||
//
|
||
|
||
if (ObjectType == ObpSymbolicLinkObjectType) {
|
||
|
||
ObpCreateSymbolicLinkName( (POBJECT_SYMBOLIC_LINK)InsertObject );
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we are creating a new object, then we need assign security
|
||
// to it. A pointer to the captured caller-proposed security
|
||
// descriptor is contained in the AccessState structure. The
|
||
// SecurityDescriptor field in the object header must point to
|
||
// the final security descriptor, or to NULL if no security is
|
||
// to be assigned to the object.
|
||
//
|
||
|
||
if (InsertObject == Object) {
|
||
|
||
//
|
||
// Only the following objects have security descriptors:
|
||
//
|
||
// - Named Objects
|
||
// - Unnamed objects whose object-type information explicitly
|
||
// indicates a security descriptor is required.
|
||
//
|
||
|
||
if ((ObjectName != NULL) || ObjectType->TypeInfo.SecurityRequired) {
|
||
|
||
//
|
||
// Get the parent's descriptor, if there is one...
|
||
//
|
||
|
||
if ((NameInfo != NULL) && (NameInfo->Directory != NULL)) {
|
||
|
||
//
|
||
// This will allocate a block of memory and copy
|
||
// the parent's security descriptor into it, and
|
||
// return the pointer to the block.
|
||
//
|
||
// Call ObReleaseObjectSecurity to free up this
|
||
// memory.
|
||
//
|
||
|
||
ObGetObjectSecurity( NameInfo->Directory,
|
||
&ParentDescriptor,
|
||
&SecurityDescriptorAllocated );
|
||
}
|
||
|
||
//
|
||
// Take the captured security descriptor in the AccessState,
|
||
// put it into the proper format, and call the object's
|
||
// security method to assign the new security descriptor to
|
||
// the new object.
|
||
//
|
||
|
||
Status = ObAssignSecurity( AccessState,
|
||
ParentDescriptor,
|
||
Object,
|
||
ObjectType );
|
||
|
||
if (ParentDescriptor != NULL) {
|
||
|
||
ObReleaseObjectSecurity( ParentDescriptor,
|
||
SecurityDescriptorAllocated );
|
||
|
||
} else if (NT_SUCCESS( Status )) {
|
||
|
||
SeReleaseSecurityDescriptor( ObjectCreateInfo->SecurityDescriptor,
|
||
ObjectCreateInfo->ProbeMode,
|
||
TRUE );
|
||
|
||
ObjectCreateInfo->SecurityDescriptor = NULL;
|
||
AccessState->SecurityDescriptor = NULL;
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
|
||
//
|
||
// The attempt to assign the security descriptor to
|
||
// the object failed.
|
||
//
|
||
|
||
if (LookupContext.DirectoryLocked) {
|
||
|
||
//
|
||
// If ObpLookupObjectName already inserted the
|
||
// object into the directory we have to backup this
|
||
//
|
||
|
||
//
|
||
// Capture the object Directory
|
||
//
|
||
|
||
DirObject = NameInfo->Directory;
|
||
|
||
ObpDeleteDirectoryEntry( &LookupContext );
|
||
}
|
||
|
||
ObpReleaseLookupContext( &LookupContext );
|
||
|
||
//
|
||
// If ObpLookupObjectName inserted the object into the directory
|
||
// it added a reference to the object and to its directory
|
||
// object. We should remove the extra-references
|
||
//
|
||
|
||
if (DirObject) {
|
||
|
||
ObDereferenceObject( Object );
|
||
ObDereferenceObject( DirObject );
|
||
}
|
||
|
||
//
|
||
// The first backout logic used ObpDeleteNameCheck
|
||
// which is wrong because the security descriptor for
|
||
// the object is not initialized. Actually ObpDeleteNameCheck
|
||
// had no effect because the object was removed before from
|
||
// the directory
|
||
//
|
||
|
||
ObpDereferenceNameInfo( NameInfo );
|
||
ObDereferenceObject( Object );
|
||
|
||
//
|
||
// Free security information if we allocated it
|
||
//
|
||
|
||
if (AccessState == &LocalAccessState) {
|
||
|
||
SeDeleteAccessState( AccessState );
|
||
}
|
||
|
||
return( Status );
|
||
}
|
||
}
|
||
|
||
ReturnStatus = Status;
|
||
|
||
ObjectHeader->ObjectCreateInfo = NULL;
|
||
|
||
//
|
||
// Create a named handle for the object with a pointer bias
|
||
// This call also will unlock the directory lock is necessary
|
||
// on return
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT (Handle)) {
|
||
|
||
Status = ObpCreateHandle( OpenReason,
|
||
InsertObject,
|
||
NULL,
|
||
AccessState,
|
||
1 + ObjectPointerBias,
|
||
ObjectCreateInfo->Attributes,
|
||
&LookupContext,
|
||
PreviousMode,
|
||
NewObject,
|
||
&NewHandle );
|
||
|
||
//
|
||
// If the insertion failed, the following dereference will cause
|
||
// the newly created object to be deallocated.
|
||
//
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
|
||
//
|
||
// Make the name reference go away if an error.
|
||
//
|
||
|
||
if (ObjectName != NULL) {
|
||
|
||
ObpDeleteNameCheck( Object );
|
||
}
|
||
|
||
*Handle = NULL;
|
||
|
||
ReturnStatus = Status;
|
||
|
||
} else {
|
||
*Handle = NewHandle;
|
||
}
|
||
|
||
ObpDereferenceNameInfo( NameInfo );
|
||
|
||
ObDereferenceObject( Object );
|
||
|
||
|
||
} else {
|
||
|
||
BOOLEAN IsNewObject;
|
||
|
||
//
|
||
// Charge the user quota for the object.
|
||
//
|
||
|
||
ObpLockObject( ObjectHeader );
|
||
|
||
ReturnStatus = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &IsNewObject );
|
||
|
||
ObpUnlockObject( ObjectHeader );
|
||
|
||
if (!NT_SUCCESS (ReturnStatus)) {
|
||
ObDereferenceObject( Object );
|
||
}
|
||
}
|
||
|
||
ObpFreeObjectCreateInformation( ObjectCreateInfo );
|
||
|
||
//
|
||
// Free security information if we allocated it
|
||
//
|
||
|
||
if (AccessState == &LocalAccessState) {
|
||
|
||
SeDeleteAccessState( AccessState );
|
||
}
|
||
|
||
return( ReturnStatus );
|
||
}
|