/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    edithive.c

Abstract:

    Provides functionality for dumping and editing registry hive files from
    user-mode.

Author:

    John Vert (jvert) 26-Mar-1992

Revision History:

--*/
#include "edithive.h"
#include "nturtl.h"

extern GENERIC_MAPPING CmpKeyMapping;
extern LIST_ENTRY CmpHiveListHead;            // List of CMHIVEs

#define SECURITY_CELL_LENGTH(pDescriptor) \
    FIELD_OFFSET(CM_KEY_SECURITY,Descriptor) + \
    RtlLengthSecurityDescriptor(pDescriptor)


NTSTATUS
EhpAttachSecurity(
    IN PHHIVE Hive,
    IN HCELL_INDEX Cell
    );

PVOID
EhpAllocate(
    ULONG   Size
    );

VOID
EhpFree(
    PVOID   MemoryBlock
    );

BOOLEAN
EhpFileRead (
    HANDLE      FileHandle,
    PULONG      FileOffset,
    PVOID       DataBuffer,
    ULONG       DataLength
    );

BOOLEAN
EhpFileWrite(
    HANDLE      FileHandle,
    PULONG      FileOffset,
    PVOID       DataBuffer,
    ULONG       DataLength
    );

BOOLEAN
EhpFileFlush (
    HANDLE      FileHandle
    );

VOID
CmpGetObjectSecurity(
    IN HCELL_INDEX Cell,
    IN PHHIVE Hive,
    OUT PCM_KEY_SECURITY *Security,
    OUT PHCELL_INDEX SecurityCell OPTIONAL
    )

/*++

Routine Description:

    This routine maps in the security cell of a registry object.

Arguments:

    Cell - Supplies the cell index of the object.

    Hive - Supplies the hive the object's cell is in.

    Security - Returns a pointer to the security cell of the object.

    SecurityCell - Returns the index of the security cell

Return Value:

    NONE.

--*/

{
    HCELL_INDEX CellIndex;
    PCM_KEY_NODE Node;

    //
    // Map the node we need to get the security descriptor for
    //
    Node = (PCM_KEY_NODE) HvGetCell(Hive, Cell);

    CellIndex = Node->u1.s1.Security;

    //
    // Map in the security descriptor cell
    //
    *Security = (PCM_KEY_SECURITY) HvGetCell(Hive, CellIndex);

    if (ARGUMENT_PRESENT(SecurityCell)) {
        *SecurityCell = CellIndex;
    }

    return;
}


VOID
EhCloseHive(
    IN HANDLE HiveHandle
    )

/*++

Routine Description:

    Closes a hive, including writing all the data out to disk and freeing
    the relevant structures.

Arguments:

    HiveHandle - Supplies a handle to the hive control structure

Return Value:

    None.

--*/

{
    HvSyncHive((PHHIVE)HiveHandle);
    NtClose(((PCMHIVE)HiveHandle)->FileHandles[HFILE_TYPE_PRIMARY]);
    NtClose(((PCMHIVE)HiveHandle)->FileHandles[HFILE_TYPE_ALTERNATE]);
    NtClose(((PCMHIVE)HiveHandle)->FileHandles[HFILE_TYPE_LOG]);
    CmpFree((PCMHIVE)HiveHandle, sizeof(CMHIVE));

}


HANDLE
EhOpenHive(
    IN PUNICODE_STRING FileName,
    OUT PHANDLE RootHandle,
    IN PUNICODE_STRING RootName,
    IN ULONG HiveType
    )

/*++

Routine Description:

    Opens an existing hive.  If the filename does not exist it will be
    created.

    WARNING:    Allocate FileName large enough to acomodate .log or
                .alt extension.

Arguments:

    FileName - Supplies the NULL-terminated filename to open as a hive.

    HiveType - TYPE_SIMPLE = no log or alternate
               TYPE_LOG = log
               TYPE_ALT = alternate

Return Value:

    != NULL - Handle to the opened hive.
    == NULL - Indicates file could not be opened.

--*/

{
    NTSTATUS Status;
    HANDLE File;
    BOOLEAN Allocate;
    PCMHIVE Hive;
    IO_STATUS_BLOCK IoStatus;
    ULONG CreateDisposition;
    OBJECT_ATTRIBUTES ObjectAttributes;
    PCM_KEY_NODE RootNode;
    HANDLE Handle;
    HANDLE  Primary;
    HANDLE  Log;
    HANDLE  Alt;
    ULONG   FileType;
    ULONG   Disposition;
    ULONG   SecondaryDisposition;
    ULONG   Operation;

    Alt = NULL;
    Log = NULL;
    InitializeListHead(&CmpHiveListHead);

    switch (HiveType) {
    case TYPE_SIMPLE:
        Status = CmpOpenHiveFiles(
                    FileName,
                    NULL,
                    &Primary,
                    NULL,
                    &Disposition,
                    &SecondaryDisposition,
                    TRUE,
                    NULL
                    );
        if (!NT_SUCCESS(Status))
        {
            return NULL;
        }
        FileType = HFILE_TYPE_PRIMARY;
        break;

    case TYPE_LOG:
        Status = CmpOpenHiveFiles(
                    FileName,
                    L".log",
                    &Primary,
                    &Log,
                    &Disposition,
                    &SecondaryDisposition,
                    TRUE,
                    NULL
                    );
        if (!NT_SUCCESS(Status))
        {
            return NULL;
        }
        if (Log == NULL) {
            return NULL;
        }
        FileType = HFILE_TYPE_LOG;
        break;

    case TYPE_ALT:
        Status = CmpOpenHiveFiles(
                    FileName,
                    L".alt",
                    &Primary,
                    &Alt,
                    &Disposition,
                    &SecondaryDisposition,
                    TRUE,
                    NULL
                    );
        if (!NT_SUCCESS(Status))
        {
            return NULL;
        }
        if (Alt == NULL) {
            return NULL;
        }
        FileType = HFILE_TYPE_ALTERNATE;
        break;

    default:
        return NULL;
    }

    //
    // Initialize hive
    //
    if (Disposition == FILE_CREATED) {
        Operation = HINIT_CREATE;
        Allocate = TRUE;
    } else {
        Operation = HINIT_FILE;
        Allocate = FALSE;
    }

    if ( ! CmpInitializeHive(
                    &Hive,
                    Operation,
                    FALSE,
                    FileType,
                    NULL,
                    Primary,
                    Alt,
                    Log,
                    NULL,
                    NULL
                    ))
    {
        return NULL;
    }

    if (!Allocate) {
        *RootHandle = (HANDLE)(Hive->Hive.BaseBlock->RootCell);
        RootNode = (PCM_KEY_NODE)HvGetCell(
                                (PHHIVE)Hive, Hive->Hive.BaseBlock->RootCell);
        RootName->Length = RootName->MaximumLength = RootNode->NameLength;
        RootName->Buffer = RootNode->Name;
    } else {
        RtlInitUnicodeString(RootName, L"HiveRoot");
        *RootHandle = (HANDLE)HCELL_NIL;
        HvSyncHive((PHHIVE)Hive);
    }


    return((HANDLE)Hive);
}


NTSTATUS
EhEnumerateKey(
    IN HANDLE HiveHandle,
    IN HANDLE CellHandle,
    IN ULONG Index,
    IN KEY_INFORMATION_CLASS KeyInformationClass,
    IN PVOID KeyInformation,
    IN ULONG Length,
    IN PULONG ResultLength
    )
/*++

Routine Description:

    Enumerate sub keys, return data on Index'th entry.

    CmEnumerateKey returns the name of the Index'th sub key of the open
    key specified.  The value STATUS_NO_MORE_ENTRIES will be
    returned if value of Index is larger than the number of sub keys.

    Note that Index is simply a way to select among child keys.  Two calls
    to CmEnumerateKey with the same Index are NOT guaranteed to return
    the same results.

    If KeyInformation is not long enough to hold all requested data,
    STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
    set to the number of bytes actually required.

Arguments:

    Hive - supplies a pointer to the hive control structure for the hive

    Cell - supplies index of node to whose sub keys are to be found

    Index - Specifies the (0-based) number of the sub key to be returned.

    KeyInformationClass - Specifies the type of information returned in
        Buffer.  One of the following types:

        KeyBasicInformation - return last write time, title index, and name.
            (see KEY_BASIC_INFORMATION structure)

        KeyNodeInformation - return last write time, title index, name, class.
            (see KEY_NODE_INFORMATION structure)

    KeyInformation -Supplies pointer to buffer to receive the data.

    Length - Length of KeyInformation in bytes.

    ResultLength - Number of bytes actually written into KeyInformation.

Return Value:

    NTSTATUS - Result code from call, among the following:

        <TBS>

--*/
{
    CM_KEY_CONTROL_BLOCK    kcb;

    kcb.Signature = CM_KEY_CONTROL_BLOCK_SIGNATURE;
    kcb.Delete = FALSE;
    kcb.KeyHive = &((PCMHIVE)HiveHandle)->Hive;
    kcb.KeyCell = (HCELL_INDEX)CellHandle;
    kcb.RefCount = 1;

    return(CmEnumerateKey(&kcb,
                          Index,
                          KeyInformationClass,
                          KeyInformation,
                          Length,
                          ResultLength));
}


NTSTATUS
EhEnumerateValueKey(
    IN HANDLE HiveHandle,
    IN HANDLE CellHandle,
    IN ULONG Index,
    IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
    IN PVOID KeyValueInformation,
    IN ULONG Length,
    IN PULONG ResultLength
    )
/*++

Routine Description:

    The value entries of an open key may be enumerated.

    CmEnumerateValueKey returns the name of the Index'th value
    entry of the open key specified by KeyHandle.  The value
    STATUS_NO_MORE_ENTRIES will be returned if value of Index is
    larger than the number of sub keys.

    Note that Index is simply a way to select among value
    entries.  Two calls to NtEnumerateValueKey with the same Index
    are NOT guaranteed to return the same results.

    If KeyValueInformation is not long enough to hold all requested data,
    STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
    set to the number of bytes actually required.

Arguments:

    Hive - supplies a handle to the hive

    Cell - supplies handle to node whose sub keys are to be found

    Index - Specifies the (0-based) number of the sub key to be returned.

    KeyValueInformationClass - Specifies the type of information returned
    in Buffer. One of the following types:

        KeyValueBasicInformation - return time of last write,
            title index, and name.  (See KEY_VALUE_BASIC_INFORMATION)

        KeyValueFullInformation - return time of last write,
            title index, name, class.  (See KEY_VALUE_FULL_INFORMATION)

    KeyValueInformation -Supplies pointer to buffer to receive the data.

    Length - Length of KeyValueInformation in bytes.

    ResultLength - Number of bytes actually written into KeyValueInformation.

Return Value:

    NTSTATUS - Result code from call, among the following:

        <TBS>

--*/
{
    CM_KEY_CONTROL_BLOCK    kcb;

    kcb.Signature = CM_KEY_CONTROL_BLOCK_SIGNATURE;
    kcb.Delete = FALSE;
    kcb.KeyHive = (PHHIVE)&(((PCMHIVE)HiveHandle)->Hive);
    kcb.KeyCell = (HCELL_INDEX)CellHandle;
    kcb.RefCount = 1;

    return(CmEnumerateValueKey(&kcb,
                               Index,
                               KeyValueInformationClass,
                               KeyValueInformation,
                               Length,
                               ResultLength));
}


NTSTATUS
EhOpenChildByNumber(
    IN HANDLE HiveHandle,
    IN HANDLE CellHandle,
    IN ULONG  Index,
    IN NODE_TYPE   Type,
    OUT PHANDLE ChildCell
    )
/*++

Routine Description:

    Return the cell index of the Nth child cell.

Arguments:

    HiveHandle - handle of hive control structure for hive of interest

    CellHandle - handle for parent cell

    Index - number of desired child

    Type - type of the child object

    ChildCell - supplies a pointer to a variable to receive the
                    HCELL_INDEX of the Index'th child.

Return Value:

    status

--*/
{
    return(CmpFindChildByNumber(&((PCMHIVE)HiveHandle)->Hive,
                                (HCELL_INDEX)CellHandle,
                                Index,
                                Type,
                                (PHCELL_INDEX)ChildCell));

}


NTSTATUS
EhSetValueKey(
    IN HANDLE HiveHandle,
    IN HANDLE CellHandle,
    IN PUNICODE_STRING ValueName,
    IN ULONG TitleIndex OPTIONAL,
    IN ULONG Type,
    IN PVOID Data,
    IN ULONG DataSize
    )
/*++

Routine Description:

    A value entry may be created or replaced with EhSetValueKey.

    If a value entry with a Value ID (i.e. name) matching the
    one specified by ValueName exists, it is deleted and replaced
    with the one specified.  If no such value entry exists, a new
    one is created.  NULL is a legal Value ID.  While Value IDs must
    be unique within any given key, the same Value ID may appear
    in many different keys.

Arguments:

    HiveHandle - handle of hive control structure for hive of interest

    CellHandle - handle for parent cell

    ValueName - The unique (relative to the containing key) name
        of the value entry.  May be NULL.

    TitleIndex - Supplies the title index for ValueName.  The title
        index specifies the index of the localized alias for the ValueName.

    Type - The integer type number of the value entry.

    Data - Pointer to buffer with actual data for the value entry.

    DataSize - Size of Data buffer.


Return Value:

    NTSTATUS - Result code from call, among the following:

        <TBS>

--*/
{
    CM_KEY_CONTROL_BLOCK kcb;

    kcb.Delete = FALSE;
    kcb.Signature = CM_KEY_CONTROL_BLOCK_SIGNATURE;
    kcb.KeyHive = (PHHIVE)&(((PCMHIVE)HiveHandle)->Hive);
    kcb.KeyCell = (HCELL_INDEX)CellHandle;
    kcb.FullName.Length = 0;
    kcb.FullName.MaximumLength = 0;
    kcb.FullName.Buffer = NULL;

    return(CmSetValueKey(&kcb,
                         *ValueName,
                         TitleIndex,
                         Type,
                         Data,
                         DataSize));

}


NTSTATUS
EhOpenChildByName(
    HANDLE HiveHandle,
    HANDLE CellHandle,
    PUNICODE_STRING  Name,
    PHANDLE ChildCell
    )
/*++

Routine Description:

    Find the child subkey cell specified by Name.

Arguments:

    HiveHandle - handle of hive control structure for hive of interest

    CellHandle - handle for parent cell

    Name - name of child object to find

    ChildCell - pointer to variable to receive cell index of child

Return Value:

    status

--*/
{
    PHCELL_INDEX    Index;

    return(CmpFindChildByName(&((PCMHIVE)HiveHandle)->Hive,
                              (HCELL_INDEX)CellHandle,
                              *Name,
                              KeyBodyNode,
                              (PHCELL_INDEX)ChildCell,
                              &Index));
}


NTSTATUS
EhCreateChild(
    IN HANDLE HiveHandle,
    IN HANDLE CellHandle,
    IN PUNICODE_STRING  Name,
    OUT PHANDLE ChildCell,
    OUT PULONG Disposition OPTIONAL
    )
/*++

Routine Description:

    Attempts to open the given child subkey specified by name.  If the
    child does not exist, it is created.

Arguments:

    HiveHandle - handle of hive control structure for hive of interest

    CellHandle - handle for parent cell


    Name - name of child object to create

    ChildCell - pointer to variable to receive cell index of child

    Disposition - This optional parameter is a pointer to a variable
        that will receive a value indicating whether a new Registry
        key was created or an existing one opened:

        REG_CREATED_NEW_KEY - A new Registry Key was created
        REG_OPENED_EXISTING_KEY - An existing Registry Key was opened

Return Value:

    status

--*/
{
    PHCELL_INDEX Index;
    NTSTATUS Status;
    PHHIVE Hive;
    HCELL_INDEX NewCell;
    HCELL_INDEX NewListCell;
    HCELL_INDEX OldListCell;
    PHCELL_INDEX NewList;
    PHCELL_INDEX OldList;
    PCM_KEY_NODE Child;
    PCM_KEY_NODE Parent;
    PCM_KEY_SECURITY Security;
    HANDLE Handle;
    ULONG oldcount;

    Hive = &((PCMHIVE)HiveHandle)->Hive;

    if ((HCELL_INDEX)CellHandle == HCELL_NIL) {
        if (Hive->BaseBlock->RootCell != HCELL_NIL) {
            *ChildCell = (HANDLE)(Hive->BaseBlock->RootCell);
            if (ARGUMENT_PRESENT(Disposition)) {
                *Disposition = REG_OPENED_EXISTING_KEY;
            }
            return(STATUS_SUCCESS);
        } else {
            Status = STATUS_OBJECT_NAME_NOT_FOUND;
        }
    } else {
        Parent = (PCM_KEY_NODE)HvGetCell(Hive, (HCELL_INDEX)CellHandle);
        Status = CmpFindChildByName(Hive,
                                    (HCELL_INDEX)CellHandle,
                                    *Name,
                                    KeyBodyNode,
                                    (PHCELL_INDEX)ChildCell,
                                    &Index);
    }
    if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {

        NewCell = HvAllocateCell(Hive,
                                 CmpHKeyNodeSize(Hive,Name->Length),
                                 Stable);
        if (NewCell != HCELL_NIL) {

            *ChildCell = (HANDLE)NewCell;
            Child = (PCM_KEY_NODE)HvGetCell(Hive, NewCell);

            Child->Signature = CM_KEY_NODE_SIGNATURE;
            Child->Flags = 0;

            KeQuerySystemTime(&(Child->LastWriteTime));

            Child->Spare = 0;
            Child->Parent = (HCELL_INDEX)CellHandle;

            Child->ValueList.Count = 0;
            Child->ValueList.List = HCELL_NIL;
            Child->u1.s1.Security = HCELL_NIL;
            Child->u1.s1.Class = HCELL_NIL;
            Child->NameLength = Name->Length;
            Child->ClassLength = 0;

            Child->SubKeyCounts[Stable] = 0;
            Child->SubKeyCounts[Volatile] = 0;
            Child->SubKeyLists[Stable] = HCELL_NIL;
            Child->SubKeyLists[Volatile] = HCELL_NIL;

            Child->MaxValueDataLen = 0;
            Child->MaxNameLen = 0;
            Child->MaxValueNameLen = 0;
            Child->MaxClassLen = 0;

            if((HCELL_INDEX)CellHandle == HCELL_NIL) {
                Hive->BaseBlock->RootCell = NewCell;
                Status = EhpAttachSecurity(Hive, NewCell);
            } else {
                Child->u1.s1.Security = Parent->u1.s1.Security;
                Security = (PCM_KEY_SECURITY)HvGetCell(Hive, Child->u1.s1.Security);
                ++Security->ReferenceCount;
            }

            RtlMoveMemory(
                &(Child->Name[0]),
                Name->Buffer,
                Name->Length
                );

            Status = STATUS_SUCCESS;
        } else {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            return(Status);
        }
        if (ARGUMENT_PRESENT(Disposition)) {
            *Disposition = REG_CREATED_NEW_KEY;
        }

        if ((HCELL_INDEX)CellHandle != HCELL_NIL) {

            //
            // put newly created child into parent's sub key list
            //
            if (! CmpAddSubKey(Hive, (HCELL_INDEX)CellHandle, NewCell)) {
                CmpFreeKeyByCell(Hive, NewCell, FALSE);
                return STATUS_INSUFFICIENT_RESOURCES;
            }

            Parent = (PCM_KEY_NODE)HvGetCell(Hive, (HCELL_INDEX)CellHandle);

            if (Parent->MaxNameLen < Name->Length) {
                Parent->MaxNameLen = Name->Length;
            }
            Parent->MaxClassLen = 0;
        }
    } else {
        Status = STATUS_SUCCESS;
        if (ARGUMENT_PRESENT(Disposition)) {
            *Disposition = REG_OPENED_EXISTING_KEY;
        }
    }
    return(Status);
}


NTSTATUS
EhQueryKey(
    IN HANDLE HiveHandle,
    IN HANDLE KeyHandle,
    IN KEY_INFORMATION_CLASS KeyInformationClass,
    IN PVOID KeyInformation,
    IN ULONG Length,
    IN PULONG ResultLength
    )
/*++

Routine Description:

    Data about the class of a key, and the numbers and sizes of its
    children and value entries may be queried with CmQueryKey.

    NOTE: The returned lengths are guaranteed to be at least as
          long as the described values, but may be longer in
          some circumstances.

Arguments:

    Hive - supplies a handle to the hive control structure for the hive

    Cell - supplies handle of node to whose sub keys are to be found

    KeyInformationClass - Specifies the type of information
        returned in Buffer.  One of the following types:

        KeyBasicInformation - return last write time, title index, and name.
            (See KEY_BASIC_INFORMATION)

        KeyNodeInformation - return last write time, title index, name, class.
            (See KEY_NODE_INFORMATION)

        KeyFullInformation - return all data except for name and security.
            (See KEY_FULL_INFORMATION)

    KeyInformation -Supplies pointer to buffer to receive the data.

    Length - Length of KeyInformation in bytes.

    ResultLength - Number of bytes actually written into KeyInformation.

Return Value:

    NTSTATUS - Result code from call, among the following:

        <TBS>

--*/
{
    CM_KEY_CONTROL_BLOCK Kcb;

    Kcb.Delete = FALSE;
    Kcb.Signature = CM_KEY_CONTROL_BLOCK_SIGNATURE;
    Kcb.KeyHive = &((PCMHIVE)HiveHandle)->Hive;
    Kcb.KeyCell = (HCELL_INDEX)KeyHandle;
    Kcb.FullName.Length = 0;
    Kcb.FullName.MaximumLength = 0;
    Kcb.FullName.Buffer = NULL;

    return(CmQueryKey(&Kcb,
                      KeyInformationClass,
                      KeyInformation,
                      Length,
                      ResultLength));
}

PSECURITY_DESCRIPTOR
EhGetKeySecurity(
    IN HANDLE HiveHandle,
    IN HANDLE KeyHandle
    )
{
    PCM_KEY_SECURITY Security;

    CmpGetObjectSecurity((HCELL_INDEX)KeyHandle,
                         &((PCMHIVE)HiveHandle)->Hive,
                         &Security,
                         NULL);

    return(&Security->Descriptor);
}


NTSTATUS
EhQueryValueKey(
    IN HANDLE HiveHandle,
    IN HANDLE KeyHandle,
    IN PUNICODE_STRING ValueName,
    IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
    IN PVOID KeyValueInformation,
    IN ULONG Length,
    IN PULONG ResultLength
    )
/*++

Routine Description:

    The ValueName, TitleIndex, Type, and Data for any one of a key's
    value entries may be queried with CmQueryValueKey.

    If KeyValueInformation is not long enough to hold all requested data,
    STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
    set to the number of bytes actually required.

Arguments:

    Hive - supplies a pointer to the hive control structure for the hive

    Cell - supplies index of node to whose sub keys are to be found

    ValueName  - The name of the value entry to return data for.

    KeyValueInformationClass - Specifies the type of information
        returned in KeyValueInformation.  One of the following types:

        KeyValueBasicInformation - return time of last write, title
            index, and name.  (See KEY_VALUE_BASIC_INFORMATION)

        KeyValueFullInformation - return time of last write, title
            index, name, class.  (See KEY_VALUE_FULL_INFORMATION)

    KeyValueInformation -Supplies pointer to buffer to receive the data.

    Length - Length of KeyValueInformation in bytes.

    ResultLength - Number of bytes actually written into KeyValueInformation.

Return Value:

    NTSTATUS - Result code from call, among the following:

        <TBS>

--*/
{
    CM_KEY_CONTROL_BLOCK kcb;

    kcb.Delete = FALSE;
    kcb.Signature = CM_KEY_CONTROL_BLOCK_SIGNATURE;
    kcb.KeyHive = &((PCMHIVE)HiveHandle)->Hive;
    kcb.KeyCell = (HCELL_INDEX)KeyHandle;
    kcb.FullName.Length = 0;
    kcb.FullName.MaximumLength = 0;
    kcb.FullName.Buffer = NULL;

    return(CmQueryValueKey(&kcb,
                           *ValueName,
                           KeyValueInformationClass,
                           KeyValueInformation,
                           Length,
                           ResultLength));

}


NTSTATUS
EhDeleteValueKey(
    IN HANDLE HiveHandle,
    IN HANDLE CellHandle,
    IN PUNICODE_STRING ValueName         // RAW
    )
/*++

Routine Description:

    One of the value entries of a registry key may be removed with this call.

    The value entry with ValueName matching ValueName is removed from the key.
    If no such entry exists, an error is returned.

Arguments:

    Hive - Supplies a handle to the hive control structure

    Cell - Supplies a handle to the registry key to be operated on

    ValueName - The name of the value to be deleted.  NULL is a legal name.

Return Value:

    NTSTATUS - Result code from call, among the following:

        <TBS>

--*/
{
    CM_KEY_CONTROL_BLOCK kcb;

    kcb.Delete = FALSE;
    kcb.Signature = CM_KEY_CONTROL_BLOCK_SIGNATURE;
    kcb.KeyHive = &((PCMHIVE)HiveHandle)->Hive;
    kcb.KeyCell = (HCELL_INDEX)CellHandle;
    kcb.FullName.Length = 0;
    kcb.FullName.MaximumLength = 0;
    kcb.FullName.Buffer = NULL;

    return(CmDeleteValueKey(&kcb, *ValueName));
}


NTSTATUS
EhpAttachSecurity(
    IN PHHIVE Hive,
    IN HCELL_INDEX Cell
    )

/*++

Routine Description:

    Creates a security descriptor cell and attaches it to the given
    node.

Arguments:

    Hive - Supplies a pointer to the hive control structure.

    Cell - Supplies the cell index of the node to attach the security
           descriptor to.

Return Value:

    None.

--*/

{
    NTSTATUS Status;
    HANDLE Token;
    HCELL_INDEX SecurityCell;
    PCM_KEY_NODE Node;
    PCM_KEY_SECURITY Security;
    PSECURITY_DESCRIPTOR Descriptor;
    ULONG DescriptorLength;
    HANDLE Handle;

    Status = NtOpenProcessToken( NtCurrentProcess(),
                                 TOKEN_QUERY,
                                 &Token );
    if (!NT_SUCCESS(Status)) {
        return(Status);
    }

    Status = RtlNewSecurityObject( NULL,
                                   NULL,
                                   &Descriptor,
                                   FALSE,
                                   Token,
                                   &CmpKeyMapping );
    if (!NT_SUCCESS(Status)) {
        return(Status);
    }

    Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
    SecurityCell = HvAllocateCell(Hive,
                                  SECURITY_CELL_LENGTH(Descriptor),
                                  Stable);
    if (SecurityCell == HCELL_NIL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    Node->u1.s1.Security = SecurityCell;
    Security = (PCM_KEY_SECURITY)HvGetCell(Hive, SecurityCell);
    DescriptorLength = RtlLengthSecurityDescriptor(Descriptor);
    Security->Signature = CM_KEY_SECURITY_SIGNATURE;
    Security->ReferenceCount = 1;
    Security->DescriptorLength = DescriptorLength;
    RtlMoveMemory( &Security->Descriptor,
                   Descriptor,
                   DescriptorLength );
    Security->Flink = Security->Blink = SecurityCell;
    return(STATUS_SUCCESS);

}
