/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    cmquery.c

Abstract:

    This module contains the object name query method for the registry.

Author:

    Bryan M. Willman (bryanwi) 8-Apr-1992

Revision History:

--*/

#include    "cmp.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpQueryKeyName)
#endif

NTSTATUS
CmpQueryKeyName(
    IN PVOID Object,
    IN BOOLEAN HasObjectName,
    OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
    IN ULONG Length,
    OUT PULONG ReturnLength
    )
/*++

Routine Description:

    This routine interfaces to the NT Object Manager.  It is invoked when
    the object system wishes to discover the name of an object that
    belongs to the registry.

Arguments:

    Object - pointer to a Key, thus -> KEY_BODY.

    HasObjectName - indicates whether the object manager knows about a name
        for this object

    ObjectNameInfo - place where we report the name

    Length - maximum length they can deal with

    ReturnLength - supplies variable to receive actual length

Return Value:

    STATUS_SUCCESS

    STATUS_INFO_LENGTH_MISMATCH

--*/

{
    PUNICODE_STRING Name;
    PWCHAR t;
    PWCHAR s;
    ULONG l;
    NTSTATUS status;

    UNREFERENCED_PARAMETER(HasObjectName);

    CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpQueryKeyName:\n"));

    CmpLockRegistry();

    if ( ((PCM_KEY_BODY)Object)->KeyControlBlock->Delete) {
        CmpUnlockRegistry();
        return STATUS_KEY_DELETED;
    }
    Name = CmpConstructName(((PCM_KEY_BODY)Object)->KeyControlBlock);
    if (Name == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        CmpUnlockRegistry();
        return status;
    }

    if (Length <= sizeof(OBJECT_NAME_INFORMATION)) {
        *ReturnLength = Name->Length + sizeof(WCHAR) + sizeof(OBJECT_NAME_INFORMATION);
        ExFreePoolWithTag(Name, CM_NAME_TAG | PROTECTED_POOL);
        CmpUnlockRegistry();
        return STATUS_INFO_LENGTH_MISMATCH;  // they can't even handle null
    }

    t = (PWCHAR)(ObjectNameInfo + 1);
    s = Name->Buffer;
    l = Name->Length;
    l += sizeof(WCHAR);     // account for null


    *ReturnLength = l + sizeof(OBJECT_NAME_INFORMATION);
    if (l > Length - sizeof(OBJECT_NAME_INFORMATION)) {
        l = Length - sizeof(OBJECT_NAME_INFORMATION);
        status = STATUS_INFO_LENGTH_MISMATCH;
    } else {
        status = STATUS_SUCCESS;
    }
    l -= sizeof(WCHAR);

    //
    // The ObjectNameInfo buffer is a usermode buffer, so make sure we have an
    // exception handler in case a malicious app changes the protection out from
    // under us.
    //
    // Note the object manager is responsible for probing the buffer and ensuring
    // that a top-level exception handler returns the correct error code. We just
    // need to make sure we drop our lock.
    //
    try {
        RtlCopyMemory(t, s, l);
        t[l/sizeof(WCHAR)] = UNICODE_NULL;
        ObjectNameInfo->Name.Length = (USHORT)l;
        ObjectNameInfo->Name.MaximumLength = ObjectNameInfo->Name.Length;
        ObjectNameInfo->Name.Buffer = t;
    } finally {
        ExFreePoolWithTag(Name, CM_NAME_TAG | PROTECTED_POOL);
        CmpUnlockRegistry();
    }
    return status;
}