/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    obquery.c

Abstract:

    Query Object system service

Author:

    Steve Wood (stevewo) 12-May-1989

Revision History:

--*/

#include "obp.h"

#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE,NtQueryObject)
#pragma alloc_text(PAGE,ObQueryNameString)
#pragma alloc_text(PAGE,ObQueryTypeName)
#pragma alloc_text(PAGE,ObQueryTypeInfo)
#pragma alloc_text(PAGE,ObQueryObjectAuditingByHandle)
#pragma alloc_text(PAGE,NtSetInformationObject)
#endif

NTSTATUS
NtQueryObject(
    IN HANDLE Handle,
    IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
    OUT PVOID ObjectInformation,
    IN ULONG ObjectInformationLength,
    OUT PULONG ReturnLength OPTIONAL
    )
{
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;
    PVOID Object;
    POBJECT_HEADER ObjectHeader;
    POBJECT_HEADER_QUOTA_INFO QuotaInfo;
    POBJECT_HEADER_NAME_INFO NameInfo;
    POBJECT_TYPE ObjectType;
    POBJECT_HEADER ObjectDirectoryHeader;
    POBJECT_DIRECTORY ObjectDirectory;
    ACCESS_MASK GrantedAccess;
    POBJECT_HANDLE_FLAG_INFORMATION HandleFlags;
    OBJECT_HANDLE_INFORMATION HandleInformation;
    ULONG NameInfoSize;
    ULONG SecurityDescriptorSize;
    ULONG TempReturnLength;
    OBJECT_BASIC_INFORMATION ObjectBasicInfo;
    POBJECT_TYPES_INFORMATION TypesInformation;
    POBJECT_TYPE_INFORMATION TypeInfo;
    ULONG i, TypesInfoSize;

    PAGED_CODE();

    //
    // Get previous processor mode and probe output argument if necessary.
    //

    PreviousMode = KeGetPreviousMode();
    if (PreviousMode != KernelMode) {
        try {
            if ( ObjectInformationClass != ObjectHandleFlagInformation ) {
                ProbeForWrite( ObjectInformation,
                               ObjectInformationLength,
                               sizeof( ULONG )
                             );
                }
            else {
                ProbeForWrite( ObjectInformation,
                               ObjectInformationLength,
                               1
                             );
                }

            if (ARGUMENT_PRESENT( ReturnLength )) {
                ProbeForWriteUlong( ReturnLength );
                *ReturnLength = 0;
                }
            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            return( GetExceptionCode() );
            }
        }

    if (ObjectInformationClass != ObjectTypesInformation) {
        Status = ObReferenceObjectByHandle( Handle,
                                            0,
                                            NULL,
                                            PreviousMode,
                                            &Object,
                                            &HandleInformation
                                          );
        if (!NT_SUCCESS( Status )) {
            return( Status );
            }

        GrantedAccess = HandleInformation.GrantedAccess;

        ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
        ObjectType = ObjectHeader->Type;
        }
    else {
        GrantedAccess = 0;
        Object = NULL;
        ObjectHeader = NULL;
        ObjectType = NULL;
        }

    switch( ObjectInformationClass ) {
    case ObjectBasicInformation:
        if (ObjectInformationLength != sizeof( OBJECT_BASIC_INFORMATION )) {
            ObDereferenceObject( Object );
            return( STATUS_INFO_LENGTH_MISMATCH );
            }

        ObjectBasicInfo.Attributes = HandleInformation.HandleAttributes;
        if (ObjectHeader->Flags & OB_FLAG_PERMANENT_OBJECT) {
            ObjectBasicInfo.Attributes |= OBJ_PERMANENT;
            }
        if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) {
            ObjectBasicInfo.Attributes |= OBJ_EXCLUSIVE;
            }

        ObjectBasicInfo.GrantedAccess = GrantedAccess;
        ObjectBasicInfo.HandleCount = ObjectHeader->HandleCount;
        ObjectBasicInfo.PointerCount = ObjectHeader->PointerCount;
        QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader );
        if (QuotaInfo != NULL) {
            ObjectBasicInfo.PagedPoolCharge = QuotaInfo->PagedPoolCharge;
            ObjectBasicInfo.NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;
            }
        else {
            ObjectBasicInfo.PagedPoolCharge = 0;
            ObjectBasicInfo.NonPagedPoolCharge = 0;
            }

        if (ObjectType == ObpSymbolicLinkObjectType) {
            ObjectBasicInfo.CreationTime = ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime;
            }
        else {
            RtlZeroMemory( &ObjectBasicInfo.CreationTime,
                           sizeof( ObjectBasicInfo.CreationTime )
                         );
            }

        NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
        if (NameInfo != NULL && NameInfo->Directory != NULL) {
            ObjectDirectory = NameInfo->Directory;
            if (ObjectDirectory) {
                NameInfoSize = sizeof( OBJ_NAME_PATH_SEPARATOR ) + NameInfo->Name.Length;
                while (ObjectDirectory) {
                    ObjectDirectoryHeader = OBJECT_TO_OBJECT_HEADER( ObjectDirectory );
                    NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectDirectoryHeader );
                    if (NameInfo != NULL && NameInfo->Directory != NULL) {
                        NameInfoSize += sizeof( OBJ_NAME_PATH_SEPARATOR ) + NameInfo->Name.Length;
                        ObjectDirectory = NameInfo->Directory;
                        }
                    else {
                        break;
                        }
                    }
                NameInfoSize += sizeof( OBJECT_NAME_INFORMATION ) + sizeof( UNICODE_NULL );
                }
            }
        else {
            NameInfoSize = 0;
            }
        ObjectBasicInfo.NameInfoSize = NameInfoSize;
        ObjectBasicInfo.TypeInfoSize = ObjectType->Name.Length + sizeof( UNICODE_NULL ) +
                                        sizeof( OBJECT_TYPE_INFORMATION );
        if ((GrantedAccess & READ_CONTROL) &&
            ARGUMENT_PRESENT( ObjectHeader->SecurityDescriptor ) ) {

            SecurityDescriptorSize = RtlLengthSecurityDescriptor(
                                         ObjectHeader->SecurityDescriptor);
            }
        else {
            SecurityDescriptorSize = 0;
            }
        ObjectBasicInfo.SecurityDescriptorSize = SecurityDescriptorSize;

        try {
            *(POBJECT_BASIC_INFORMATION) ObjectInformation = ObjectBasicInfo;

            if (ARGUMENT_PRESENT( ReturnLength ) ) {
                *ReturnLength = ObjectInformationLength;
                }
            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            //
            // Fall through, since we cannot undo what we have done.
            //
            }

        break;

    case ObjectNameInformation:
        if (!ARGUMENT_PRESENT( ReturnLength ) ) {
            TempReturnLength = 0;
            ReturnLength = &TempReturnLength;
            }

        Status = ObQueryNameString( Object,
                                    (POBJECT_NAME_INFORMATION)ObjectInformation,
                                    ObjectInformationLength,
                                    ReturnLength
                                  );
        break;

    case ObjectTypeInformation:
        if (!ARGUMENT_PRESENT( ReturnLength ) ) {
            TempReturnLength = 0;
            ReturnLength = &TempReturnLength;
            }

        Status = ObQueryTypeInfo( ObjectType,
                                  (POBJECT_TYPE_INFORMATION)ObjectInformation,
                                  ObjectInformationLength,
                                  ReturnLength
                                );
        break;

    case ObjectTypesInformation:
        if (!ARGUMENT_PRESENT( ReturnLength ) ) {
            TempReturnLength = 0;
            ReturnLength = &TempReturnLength;
            }

        TypesInfoSize = sizeof( ULONG );
        for (i=0; i<OBP_MAX_DEFINED_OBJECT_TYPES; i++) {
            ObjectType = ObpObjectTypes[ i ];
            if (ObjectType == NULL) {
                break;
                }

            ObjectType = ObjectType;
            TypesInfoSize += (sizeof( OBJECT_TYPES_INFORMATION ) - sizeof( ULONG ));
            TypesInfoSize += ObjectType->Name.Length + sizeof( UNICODE_NULL );
            }

        try {
            if (ARGUMENT_PRESENT( ReturnLength ) ) {
                *ReturnLength = sizeof( OBJECT_TYPES_INFORMATION );
                }
            TypesInformation = (POBJECT_TYPES_INFORMATION)ObjectInformation;
            if (ObjectInformationLength < sizeof( OBJECT_TYPES_INFORMATION ) ) {
                Status = STATUS_INFO_LENGTH_MISMATCH;
                }
            else {
                TypesInformation->NumberOfTypes = 0;
                for (i=0; i<OBP_MAX_DEFINED_OBJECT_TYPES; i++) {
                    ObjectType = ObpObjectTypes[ i ];
                    if (ObjectType == NULL) {
                        break;
                        }

                    TypesInformation->NumberOfTypes += 1;
                    }
                }

            TypeInfo = (POBJECT_TYPE_INFORMATION)(TypesInformation + 1);
            for (i=0; i<OBP_MAX_DEFINED_OBJECT_TYPES; i++) {
                ObjectType = ObpObjectTypes[ i ];
                if (ObjectType == NULL) {
                    break;
                    }

                Status = ObQueryTypeInfo( ObjectType,
                                          TypeInfo,
                                          ObjectInformationLength,
                                          ReturnLength
                                        );
                if (NT_SUCCESS( Status )) {
                    TypeInfo = (POBJECT_TYPE_INFORMATION)
                        ((PCHAR)(TypeInfo+1) + ALIGN_UP( TypeInfo->TypeName.MaximumLength, ULONG ));
                    }
                }
            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            Status = GetExceptionCode();
            }

        break;

    case ObjectHandleFlagInformation:
        try {
            if (ARGUMENT_PRESENT(ReturnLength)) {
                *ReturnLength = sizeof(OBJECT_HANDLE_FLAG_INFORMATION);
            }

            HandleFlags = (POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation;
            if (ObjectInformationLength < sizeof( OBJECT_HANDLE_FLAG_INFORMATION)) {
                Status = STATUS_INFO_LENGTH_MISMATCH;

            } else {
                HandleFlags->Inherit = FALSE;
                if (HandleInformation.HandleAttributes & OBJ_INHERIT) {
                    HandleFlags->Inherit = TRUE;
                }

                HandleFlags->ProtectFromClose = FALSE;
                if (HandleInformation.HandleAttributes & OBJ_PROTECT_CLOSE) {
                    HandleFlags->ProtectFromClose = TRUE;
                }
            }

        } except( EXCEPTION_EXECUTE_HANDLER ) {
            Status = GetExceptionCode();
        }

        break;

    default:
        ObDereferenceObject( Object );
        return( STATUS_INVALID_INFO_CLASS );
    }

    if (Object != NULL) {
        ObDereferenceObject( Object );
        }

    return( Status );
}


#if DBG
PUNICODE_STRING
ObGetObjectName(
    IN PVOID Object
    )
{
    POBJECT_HEADER ObjectHeader;
    POBJECT_HEADER_NAME_INFO NameInfo;

    ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );

    if (NameInfo != NULL && NameInfo->Name.Length != 0) {
        return &NameInfo->Name;
        }
    else {
        return NULL;
        }
}
#endif // DBG

#define OBP_MISSING_NAME_LITERAL L"..."
#define OBP_MISSING_NAME_LITERAL_SIZE (sizeof( OBP_MISSING_NAME_LITERAL ) - sizeof( UNICODE_NULL ))

NTSTATUS
ObQueryNameString(
    IN PVOID Object,
    OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
    IN ULONG Length,
    OUT PULONG ReturnLength
    )
{
    NTSTATUS Status;
    POBJECT_HEADER ObjectHeader;
    POBJECT_HEADER_NAME_INFO NameInfo;
    POBJECT_HEADER ObjectDirectoryHeader;
    POBJECT_DIRECTORY ObjectDirectory;
    ULONG NameInfoSize;
    PUNICODE_STRING String;
    PWCH StringBuffer;
    ULONG NameSize;

    PAGED_CODE();

    ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );

    if (ObjectHeader->Type->TypeInfo.QueryNameProcedure != NULL) {
        try {
            KIRQL SaveIrql;

            ObpBeginTypeSpecificCallOut( SaveIrql );
            ObpEndTypeSpecificCallOut( SaveIrql, "Query", ObjectHeader->Type, Object );
            Status = (*ObjectHeader->Type->TypeInfo.QueryNameProcedure)(
                        Object,
                        (BOOLEAN)(NameInfo != NULL && NameInfo->Name.Length != 0),
                        ObjectNameInfo,
                        Length,
                        ReturnLength
                        );
            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            Status = GetExceptionCode();
            }

        return( Status );
        }

    if (NameInfo == NULL || NameInfo->Name.Buffer == NULL) {
        NameInfoSize = sizeof( OBJECT_NAME_INFORMATION );
        try {
            *ReturnLength = NameInfoSize;
            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            return( GetExceptionCode() );
            }

        if (Length < NameInfoSize) {
            return( STATUS_INFO_LENGTH_MISMATCH );
            }

        try {
            ObjectNameInfo->Name.Length = 0;
            ObjectNameInfo->Name.MaximumLength = 0;
            ObjectNameInfo->Name.Buffer = NULL;
            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            //
            // Fall through, since we cannot undo what we have done.
            //
            }

        return( STATUS_SUCCESS );
        }

    if (Object == ObpRootDirectoryObject) {
        NameSize = sizeof( OBJ_NAME_PATH_SEPARATOR );
        }
    else {
        ObjectDirectory = NameInfo->Directory;
        NameSize = sizeof( OBJ_NAME_PATH_SEPARATOR ) + NameInfo->Name.Length;
        while (ObjectDirectory != ObpRootDirectoryObject && (ObjectDirectory)) {
            ObjectDirectoryHeader = OBJECT_TO_OBJECT_HEADER( ObjectDirectory );
            NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectDirectoryHeader );
            if (NameInfo != NULL && NameInfo->Directory != NULL) {
                NameSize += sizeof( OBJ_NAME_PATH_SEPARATOR ) + NameInfo->Name.Length;
                ObjectDirectory = NameInfo->Directory;
                }
            else {
                NameSize += sizeof( OBJ_NAME_PATH_SEPARATOR ) + OBP_MISSING_NAME_LITERAL_SIZE;
                break;
                }
            }
        }
    NameInfoSize = NameSize + sizeof( OBJECT_NAME_INFORMATION ) + sizeof( UNICODE_NULL );

    try {
        *ReturnLength = NameInfoSize;
        }
    except( EXCEPTION_EXECUTE_HANDLER ) {
        return( GetExceptionCode() );
        }

    if (Length < NameInfoSize) {
        return( STATUS_INFO_LENGTH_MISMATCH );
        }

    if (NameInfoSize != 0) {
        StringBuffer = (PWCH)ObjectNameInfo;
        StringBuffer = (PWCH)((PCH)StringBuffer + NameInfoSize);
        NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );

        try {
            *--StringBuffer = UNICODE_NULL;
            if (Object != ObpRootDirectoryObject) {
                String = &NameInfo->Name;
                StringBuffer = (PWCH)((PCH)StringBuffer - String->Length);
                RtlMoveMemory( StringBuffer, String->Buffer, String->Length );

                ObjectDirectory = NameInfo->Directory;
                while ((ObjectDirectory != ObpRootDirectoryObject) && (ObjectDirectory)) {
                    ObjectDirectoryHeader = OBJECT_TO_OBJECT_HEADER( ObjectDirectory );
                    NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectDirectoryHeader );
                    *--StringBuffer = OBJ_NAME_PATH_SEPARATOR;
                    if (NameInfo != NULL && NameInfo->Directory != NULL) {
                        String = &NameInfo->Name;
                        StringBuffer = (PWCH)((PCH)StringBuffer - String->Length);
                        RtlMoveMemory( StringBuffer, String->Buffer, String->Length );
                        ObjectDirectory = NameInfo->Directory;
                        }
                    else {
                        StringBuffer = (PWCH)((PCH)StringBuffer - OBP_MISSING_NAME_LITERAL_SIZE);
                        RtlMoveMemory( StringBuffer,
                                       OBP_MISSING_NAME_LITERAL,
                                       OBP_MISSING_NAME_LITERAL_SIZE
                                     );
                        break;
                        }
                    }
                }
            *--StringBuffer = OBJ_NAME_PATH_SEPARATOR;

            ObjectNameInfo->Name.Length = (USHORT)NameSize;
            ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize+sizeof( UNICODE_NULL ));
            ObjectNameInfo->Name.Buffer = StringBuffer;
            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            //
            // Fall through, since we cannot undo what we have done.
            //
            }
        }

    return( STATUS_SUCCESS );
}


NTSTATUS
ObQueryTypeName(
    IN PVOID Object,
    PUNICODE_STRING ObjectTypeName,
    IN ULONG Length,
    OUT PULONG ReturnLength
    )
{
    POBJECT_TYPE ObjectType;
    POBJECT_HEADER ObjectHeader;
    ULONG TypeNameSize;
    PUNICODE_STRING String;
    PWCH StringBuffer;
    ULONG NameSize;

    PAGED_CODE();

    ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    ObjectType = ObjectHeader->Type;

    NameSize = ObjectType->Name.Length;
    TypeNameSize = NameSize + sizeof( UNICODE_NULL ) + sizeof( UNICODE_STRING );

    try {
        *ReturnLength = TypeNameSize;
        }
    except( EXCEPTION_EXECUTE_HANDLER ) {
        return( GetExceptionCode() );
        }

    if (Length < TypeNameSize) {
        return( STATUS_INFO_LENGTH_MISMATCH );
        }

    if (TypeNameSize != 0) {
        StringBuffer = (PWCH)ObjectTypeName;
        StringBuffer = (PWCH)((PCH)StringBuffer + TypeNameSize);
        String = &ObjectType->Name;
        try {
            *--StringBuffer = UNICODE_NULL;
            StringBuffer = (PWCH)((PCH)StringBuffer - String->Length);
            RtlMoveMemory( StringBuffer, String->Buffer, String->Length );
            ObjectTypeName->Length = (USHORT)NameSize;
            ObjectTypeName->MaximumLength = (USHORT)(NameSize+sizeof( UNICODE_NULL ));
            ObjectTypeName->Buffer = StringBuffer;
            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            //
            // Fall through, since we cannot undo what we have done.
            //
            }
        }

    return( STATUS_SUCCESS );
}


NTSTATUS
ObQueryTypeInfo(
    IN POBJECT_TYPE ObjectType,
    OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo,
    IN ULONG Length,
    OUT PULONG ReturnLength
    )
{
    NTSTATUS Status;

    try {
        *ReturnLength += sizeof( *ObjectTypeInfo ) + ALIGN_UP( ObjectType->Name.MaximumLength, ULONG );
        if (Length < *ReturnLength) {
            Status = STATUS_INFO_LENGTH_MISMATCH;
            }
        else {
            ObjectTypeInfo->TotalNumberOfObjects = ObjectType->TotalNumberOfObjects;
            ObjectTypeInfo->TotalNumberOfHandles = ObjectType->TotalNumberOfHandles;
            ObjectTypeInfo->HighWaterNumberOfObjects = ObjectType->HighWaterNumberOfObjects;
            ObjectTypeInfo->HighWaterNumberOfHandles = ObjectType->HighWaterNumberOfHandles;
            ObjectTypeInfo->InvalidAttributes = ObjectType->TypeInfo.InvalidAttributes;
            ObjectTypeInfo->GenericMapping = ObjectType->TypeInfo.GenericMapping;
            ObjectTypeInfo->ValidAccessMask = ObjectType->TypeInfo.ValidAccessMask;
            ObjectTypeInfo->SecurityRequired = ObjectType->TypeInfo.SecurityRequired;
            ObjectTypeInfo->MaintainHandleCount = ObjectType->TypeInfo.MaintainHandleCount;
            ObjectTypeInfo->PoolType = ObjectType->TypeInfo.PoolType;
            ObjectTypeInfo->DefaultPagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
            ObjectTypeInfo->DefaultNonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
            ObjectTypeInfo->TypeName.Buffer = (PWSTR)(ObjectTypeInfo+1);
            ObjectTypeInfo->TypeName.MaximumLength = ObjectType->Name.MaximumLength;
            RtlCopyUnicodeString( &ObjectTypeInfo->TypeName, &ObjectType->Name );
            Status = STATUS_SUCCESS;
            }
        }
    except( EXCEPTION_EXECUTE_HANDLER ) {
        Status = GetExceptionCode();
        }

    return Status;
}

NTSTATUS
ObQueryObjectAuditingByHandle(
    IN HANDLE Handle,
    OUT PBOOLEAN GenerateOnClose
    )
{
    PHANDLE_TABLE ObjectTable;
    POBJECT_TABLE_ENTRY ObjectTableEntry;
    PVOID Object;
    ULONG CapturedGrantedAccess;
    ULONG CapturedAttributes;
    POBJECT_HEADER ObjectHeader;
    NTSTATUS Status;

    PAGED_CODE();
    ObpValidateIrql( "ObQueryObjectAuditingByHandle" );

    ObjectTable = ObpGetObjectTable();
    ObjectTableEntry = (POBJECT_TABLE_ENTRY)ExMapHandleToPointer(
                   ObjectTable,
                   (HANDLE)OBJ_HANDLE_TO_HANDLE_INDEX( Handle ),
                   TRUE         // shared access
                   );

    if (ObjectTableEntry != NULL) {
        ObjectHeader = (POBJECT_HEADER)(ObjectTableEntry->Attributes & ~OBJ_HANDLE_ATTRIBUTES);
        CapturedAttributes = (ULONG)(ObjectTableEntry->Attributes);
        if (CapturedAttributes & OBJ_AUDIT_OBJECT_CLOSE) {
            *GenerateOnClose = TRUE;
        } else {
            *GenerateOnClose = FALSE;
        }
        ExUnlockHandleTableShared(ObjectTable);
        return(STATUS_SUCCESS);
    } else {
        return(STATUS_INVALID_HANDLE);
    }
}


BOOLEAN
ObpSetHandleAttributes(
    IN OUT PVOID TableEntry,
    IN ULONG Parameter
    )

{

    POBJECT_HANDLE_FLAG_INFORMATION ObjectInformation;
    POBJECT_TABLE_ENTRY ObjectTableEntry = (POBJECT_TABLE_ENTRY)TableEntry;

    ObjectInformation = (POBJECT_HANDLE_FLAG_INFORMATION)Parameter;
    if (ObjectInformation->Inherit) {
        ObjectTableEntry->Attributes |= OBJ_INHERIT;

    } else {
        ObjectTableEntry->Attributes &= ~OBJ_INHERIT;
    }

    if (ObjectInformation->ProtectFromClose) {
        ObjectTableEntry->Attributes |= OBJ_PROTECT_CLOSE;

    } else {
        ObjectTableEntry->Attributes &= ~OBJ_PROTECT_CLOSE;
    }

    return TRUE;
}


NTSTATUS
NTAPI
NtSetInformationObject(
    IN HANDLE Handle,
    IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
    IN PVOID ObjectInformation,
    IN ULONG ObjectInformationLength
    )

{

    OBJECT_HANDLE_FLAG_INFORMATION CapturedInformation;
    HANDLE ObjectHandle;
    PVOID ObjectTable;
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;

    PAGED_CODE();

    //
    // Check if the information class and information lenght are correct.
    //

    if (ObjectInformationClass != ObjectHandleFlagInformation) {
        return STATUS_INVALID_INFO_CLASS;
    }

    if (ObjectInformationLength != sizeof(OBJECT_HANDLE_FLAG_INFORMATION)) {
        return STATUS_INFO_LENGTH_MISMATCH;
    }

    //
    // Get previous processor mode and probe output argument if necessary.
    //

    PreviousMode = KeGetPreviousMode();
    try {
        if (PreviousMode != KernelMode) {
            ProbeForRead(ObjectInformation, ObjectInformationLength, 1);
        }

        CapturedInformation = *(POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation;

    } except(ExSystemExceptionFilter()) {
        return GetExceptionCode();
    }

    //
    // Get the address of the object table for the current process.
    //

    ObjectTable = ObpGetObjectTable();
    ObjectHandle = (HANDLE)OBJ_HANDLE_TO_HANDLE_INDEX(Handle);

    //
    // Make the change to the handle table entry
    //

    if (ExChangeHandle(ObjectTable,
                       ObjectHandle,
                       ObpSetHandleAttributes,
                       (ULONG)&CapturedInformation)) {

        Status = STATUS_SUCCESS;

    } else {
        Status = STATUS_ACCESS_DENIED;
    }

    return Status;
}