Exemple #1
0
PUNICODE_STRING
NTAPI
CmpConstructName(IN PCM_KEY_CONTROL_BLOCK Kcb)
{
    PUNICODE_STRING KeyName;
    ULONG NameLength, i;
    PCM_KEY_CONTROL_BLOCK MyKcb;
    PCM_KEY_NODE KeyNode;
    BOOLEAN DeletedKey = FALSE;
    PWCHAR TargetBuffer, CurrentNameW;
    PUCHAR CurrentName;

    /* Calculate how much size our key name is going to occupy */
    NameLength = 0;
    MyKcb = Kcb;

    while (MyKcb)
    {
        /* Add length of the name */
        if (!MyKcb->NameBlock->Compressed)
        {
            NameLength += MyKcb->NameBlock->NameLength;
        }
        else
        {
            NameLength += CmpCompressedNameSize(MyKcb->NameBlock->Name,
                                                MyKcb->NameBlock->NameLength);
        }

        /* Sum up the separator too */
        NameLength += sizeof(WCHAR);

        /* Go to the parent KCB */
        MyKcb = MyKcb->ParentKcb;
    }

    /* Allocate the unicode string now */
    KeyName = CmpAllocate(NameLength + sizeof(UNICODE_STRING),
                          TRUE,
                          TAG_CM);

    if (!KeyName) return NULL;

    /* Set it up */
    KeyName->Buffer = (PWSTR)(KeyName + 1);
    KeyName->Length = NameLength;
    KeyName->MaximumLength = NameLength;

    /* Loop the keys again, now adding names */
    NameLength = 0;
    MyKcb = Kcb;

    while (MyKcb)
    {
        /* Sanity checks for deleted and fake keys */
        if ((!MyKcb->KeyCell && !MyKcb->Delete) ||
                !MyKcb->KeyHive ||
                MyKcb->ExtFlags & CM_KCB_KEY_NON_EXIST)
        {
            /* Failure */
            CmpFree(KeyName, 0);
            return NULL;
        }

        /* Try to get the name from the keynode,
           if the key is not deleted */
        if (!DeletedKey && !MyKcb->Delete)
        {
            KeyNode = HvGetCell(MyKcb->KeyHive, MyKcb->KeyCell);

            if (!KeyNode)
            {
                /* Failure */
                CmpFree(KeyName, 0);
                return NULL;
            }
        }
        else
        {
            /* The key was deleted */
            KeyNode = NULL;
            DeletedKey = TRUE;
        }

        /* Get the pointer to the beginning of the current key name */
        NameLength += (MyKcb->NameBlock->NameLength + 1) * sizeof(WCHAR);
        TargetBuffer = &KeyName->Buffer[(KeyName->Length - NameLength) / sizeof(WCHAR)];

        /* Add a separator */
        TargetBuffer[0] = OBJ_NAME_PATH_SEPARATOR;

        /* Add the name, but remember to go from the end to the beginning */
        if (!MyKcb->NameBlock->Compressed)
        {
            /* Get the pointer to the name (from the keynode, if possible) */
            if ((MyKcb->Flags & (KEY_HIVE_ENTRY | KEY_HIVE_EXIT)) ||
                    !KeyNode)
            {
                CurrentNameW = MyKcb->NameBlock->Name;
            }
            else
            {
                CurrentNameW = KeyNode->Name;
            }

            /* Copy the name */
            for (i=0; i < MyKcb->NameBlock->NameLength; i++)
            {
                TargetBuffer[i+1] = *CurrentNameW;
                CurrentNameW++;
            }
        }
        else
        {
            /* Get the pointer to the name (from the keynode, if possible) */
            if ((MyKcb->Flags & (KEY_HIVE_ENTRY | KEY_HIVE_EXIT)) ||
                    !KeyNode)
            {
                CurrentName = (PUCHAR)MyKcb->NameBlock->Name;
            }
            else
            {
                CurrentName = (PUCHAR)KeyNode->Name;
            }

            /* Copy the name */
            for (i=0; i < MyKcb->NameBlock->NameLength; i++)
            {
                TargetBuffer[i+1] = (WCHAR)*CurrentName;
                CurrentName++;
            }
        }

        /* Release the cell, if needed */
        if (KeyNode) HvReleaseCell(MyKcb->KeyHive, MyKcb->KeyCell);

        /* Go to the parent KCB */
        MyKcb = MyKcb->ParentKcb;
    }

    /* Return resulting buffer (both UNICODE_STRING and
       its buffer following it) */
    return KeyName;
}
Exemple #2
0
VALUE_SEARCH_RETURN_TYPE
NTAPI
CmpQueryKeyValueData(IN PCM_KEY_CONTROL_BLOCK Kcb,
                     IN PCM_CACHED_VALUE *CachedValue,
                     IN PCM_KEY_VALUE ValueKey,
                     IN BOOLEAN ValueIsCached,
                     IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
                     IN PVOID KeyValueInformation,
                     IN ULONG Length,
                     OUT PULONG ResultLength,
                     OUT PNTSTATUS Status)
{
    PKEY_VALUE_INFORMATION Info = (PKEY_VALUE_INFORMATION)KeyValueInformation;
    PCELL_DATA CellData;
    USHORT NameSize;
    ULONG Size, MinimumSize, SizeLeft, KeySize, AlignedData = 0, DataOffset;
    PVOID Buffer;
    BOOLEAN IsSmall, BufferAllocated = FALSE;
    HCELL_INDEX CellToRelease = HCELL_NIL;
    VALUE_SEARCH_RETURN_TYPE Result = SearchSuccess;

    /* Get the value data */
    CellData = (PCELL_DATA)ValueKey;

    /* Check if the value is compressed */
    if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME)
    {
        /* Get the compressed name size */
        NameSize = CmpCompressedNameSize(CellData->u.KeyValue.Name,
                                         CellData->u.KeyValue.NameLength);
    }
    else
    {
        /* Get the real size */
        NameSize = CellData->u.KeyValue.NameLength;
    }

    /* Check what kind of information the caller is requesting */
    switch (KeyValueInformationClass)
    {
        /* Basic information */
        case KeyValueBasicInformation:

            /* This is how much size we'll need */
            Size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) + NameSize;

            /* This is the minimum we can work with */
            MinimumSize = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);

            /* Return the size we'd like, and assume success */
            *ResultLength = Size;
            *Status = STATUS_SUCCESS;

            /* Check if the caller gave us below our minimum */
            if (Length < MinimumSize)
            {
                /* Then we must fail */
                *Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            /* Fill out the basic information */
            Info->KeyValueBasicInformation.TitleIndex = 0;
            Info->KeyValueBasicInformation.Type = CellData->u.KeyValue.Type;
            Info->KeyValueBasicInformation.NameLength = NameSize;

            /* Now only the name is left */
            SizeLeft = Length - MinimumSize;
            Size = NameSize;

            /* Check if the remaining buffer is too small for the name */
            if (SizeLeft < Size)
            {
                /* Copy only as much as can fit, and tell the caller */
                Size = SizeLeft;
                *Status = STATUS_BUFFER_OVERFLOW;
            }

            /* Check if this is a compressed name */
            if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME)
            {
                /* Copy as much as we can of the compressed name */
                CmpCopyCompressedName(Info->KeyValueBasicInformation.Name,
                                      Size,
                                      CellData->u.KeyValue.Name,
                                      CellData->u.KeyValue.NameLength);
            }
            else
            {
                /* Copy as much as we can of the raw name */
                RtlCopyMemory(Info->KeyValueBasicInformation.Name,
                              CellData->u.KeyValue.Name,
                              Size);
            }

            /* We're all done */
            break;

        /* Full key information */
        case KeyValueFullInformation:
        case KeyValueFullInformationAlign64:

            /* Check if this is a small key and compute key size */
            IsSmall = CmpIsKeyValueSmall(&KeySize,
                                         CellData->u.KeyValue.DataLength);

            /* Calculate the total size required */
            Size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) +
                   NameSize +
                   KeySize;

            /* And this is the least we can work with */
            MinimumSize = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);

            /* Check if there's any key data */
            if (KeySize > 0)
            {
                /* Calculate the data offset */
                DataOffset = Size - KeySize;

#ifdef _WIN64
                /* On 64-bit, always align to 8 bytes */
                AlignedData = ALIGN_UP(DataOffset, ULONGLONG);
#else
                /* On 32-bit, align the offset to 4 or 8 bytes */
                if (KeyValueInformationClass == KeyValueFullInformationAlign64)
                {
                    AlignedData = ALIGN_UP(DataOffset, ULONGLONG);
                }
                else
                {
                    AlignedData = ALIGN_UP(DataOffset, ULONG);
                }
#endif
                /* If alignment was required, we'll need more space */
                if (AlignedData > DataOffset) Size += (AlignedData-DataOffset);
            }

            /* Tell the caller the size we'll finally need, and set success */
            *ResultLength = Size;
            *Status = STATUS_SUCCESS;

            /* Check if the caller is giving us too little */
            if (Length < MinimumSize)
            {
                /* Then fail right now */
                *Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            /* Fill out the basic information */
            Info->KeyValueFullInformation.TitleIndex = 0;
            Info->KeyValueFullInformation.Type = CellData->u.KeyValue.Type;
            Info->KeyValueFullInformation.DataLength = KeySize;
            Info->KeyValueFullInformation.NameLength = NameSize;

            /* Only the name is left now */
            SizeLeft = Length - MinimumSize;
            Size = NameSize;

            /* Check if the name fits */
            if (SizeLeft < Size)
            {
                /* It doesn't, truncate what we'll copy, and tell the caller */
                Size = SizeLeft;
                *Status = STATUS_BUFFER_OVERFLOW;
            }

            /* Check if this key value is compressed */
            if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME)
            {
                /* It is, copy the compressed name */
                CmpCopyCompressedName(Info->KeyValueFullInformation.Name,
                                      Size,
                                      CellData->u.KeyValue.Name,
                                      CellData->u.KeyValue.NameLength);
            }
            else
            {
                /* It's not, copy the raw name */
                RtlCopyMemory(Info->KeyValueFullInformation.Name,
                              CellData->u.KeyValue.Name,
                              Size);
            }

            /* Now check if the key had any data */
            if (KeySize > 0)
            {
                /* Was it a small key? */
                if (IsSmall)
                {
                    /* Then the data is directly into the cell */
                    Buffer = &CellData->u.KeyValue.Data;
                }
                else
                {
                    /* Otherwise, we must retrieve it from the value cache */
                    Result = CmpGetValueDataFromCache(Kcb,
                                                      CachedValue,
                                                      CellData,
                                                      ValueIsCached,
                                                      &Buffer,
                                                      &BufferAllocated,
                                                      &CellToRelease);
                    if (Result != SearchSuccess)
                    {
                        /* We failed, nothing should be allocated */
                        ASSERT(Buffer == NULL);
                        ASSERT(BufferAllocated == FALSE);
                        *Status = STATUS_INSUFFICIENT_RESOURCES;
                    }
                }

                /* Now that we know we truly have data, set its offset */
                Info->KeyValueFullInformation.DataOffset = AlignedData;

                /* Only the data remains to be copied */
                SizeLeft = (((LONG)Length - (LONG)AlignedData) < 0) ?
                           0 : (Length - AlignedData);
                Size = KeySize;

                /* Check if the caller has no space for it */
                if (SizeLeft < Size)
                {
                    /* Truncate what we'll copy, and tell the caller */
                    Size = SizeLeft;
                    *Status = STATUS_BUFFER_OVERFLOW;
                }

                /* Sanity check */
                ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE));

                /* Make sure we have a valid buffer */
                if (Buffer)
                {
                    /* Copy the data into the aligned offset */
                    RtlCopyMemory((PVOID)((ULONG_PTR)Info + AlignedData),
                                  Buffer,
                                  Size);
                }
            }
            else
            {
                /* We don't have any data, set the offset to -1, not 0! */
                Info->KeyValueFullInformation.DataOffset = 0xFFFFFFFF;
            }

            /* We're done! */
            break;

        /* Partial information requested (no name or alignment!) */
        case KeyValuePartialInformation:

            /* Check if this is a small key and compute key size */
            IsSmall = CmpIsKeyValueSmall(&KeySize,
                                         CellData->u.KeyValue.DataLength);

            /* Calculate the total size required */
            Size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + KeySize;

            /* And this is the least we can work with */
            MinimumSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);

            /* Tell the caller the size we'll finally need, and set success */
            *ResultLength = Size;
            *Status = STATUS_SUCCESS;

            /* Check if the caller is giving us too little */
            if (Length < MinimumSize)
            {
                /* Then fail right now */
                *Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            /* Fill out the basic information */
            Info->KeyValuePartialInformation.TitleIndex = 0;
            Info->KeyValuePartialInformation.Type = CellData->u.KeyValue.Type;
            Info->KeyValuePartialInformation.DataLength = KeySize;

            /* Now check if the key had any data */
            if (KeySize > 0)
            {
                /* Was it a small key? */
                if (IsSmall)
                {
                    /* Then the data is directly into the cell */
                    Buffer = &CellData->u.KeyValue.Data;
                }
                else
                {
                    /* Otherwise, we must retrieve it from the value cache */
                    Result = CmpGetValueDataFromCache(Kcb,
                                                      CachedValue,
                                                      CellData,
                                                      ValueIsCached,
                                                      &Buffer,
                                                      &BufferAllocated,
                                                      &CellToRelease);
                    if (Result != SearchSuccess)
                    {
                        /* We failed, nothing should be allocated */
                        ASSERT(Buffer == NULL);
                        ASSERT(BufferAllocated == FALSE);
                        *Status = STATUS_INSUFFICIENT_RESOURCES;
                    }
                }

                /* Only the data remains to be copied */
                SizeLeft = Length - MinimumSize;
                Size = KeySize;

                /* Check if the caller has no space for it */
                if (SizeLeft < Size)
                {
                    /* Truncate what we'll copy, and tell the caller */
                    Size = SizeLeft;
                    *Status = STATUS_BUFFER_OVERFLOW;
                }

                /* Sanity check */
                ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE));

                /* Make sure we have a valid buffer */
                if (Buffer)
                {
                    /* Copy the data into the aligned offset */
                    RtlCopyMemory(Info->KeyValuePartialInformation.Data,
                                  Buffer,
                                  Size);
                }
            }

            /* We're done! */
            break;

        /* Other information class */
        default:

            /* We got some class that we don't support */
            DPRINT1("Caller requested unknown class: %lx\n", KeyValueInformationClass);
            *Status = STATUS_INVALID_PARAMETER;
            break;
    }

    /* Return the search result as well */
    return Result;
}
Exemple #3
0
NTSTATUS
CmpQueryKeyDataFromCache(
    PCM_KEY_CONTROL_BLOCK   Kcb,
    KEY_INFORMATION_CLASS   KeyInformationClass,
    PVOID                   KeyInformation,
    ULONG                   Length,
    PULONG                  ResultLength
    )
/*++

Routine Description:

    Do the actual copy of data for a key into caller's buffer.

    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.

    Works only for the information cached into kcb. I.e. KeyBasicInformation
    and KeyCachedInfo


Arguments:

    Kcb - Supplies pointer to the kcb to be queried

    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)

        KeyCachedInformation - return last write time, title index, name ....
            (see KEY_CACHED_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

--*/
{
    NTSTATUS            status;
    PKEY_INFORMATION    pbuffer;
    ULONG               requiredlength;
    USHORT              NameLength;
    PCM_KEY_NODE        Node; // this is to be used only in case of cache incoherency

    CM_PAGED_CODE();

    //
    // we cannot afford to return the kcb NameBlock as the key name
    // for KeyBasicInformation as there are lots of callers expecting
    // the name to be case-sensitive; KeyCachedInformation is new
    // and used only by the Win32 layer, which is not case sensitive
    // Note: future clients of KeyCachedInformation must be made aware 
    // that name is NOT case-sensitive
    //
    ASSERT( KeyInformationClass == KeyCachedInformation );

    // 
    // we are going to need the nameblock; if it is NULL, bail out
    //
    if( Kcb->NameBlock == NULL ) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    pbuffer = (PKEY_INFORMATION)KeyInformation;
    
    if (Kcb->NameBlock->Compressed) {
        NameLength = CmpCompressedNameSize(Kcb->NameBlock->Name,Kcb->NameBlock->NameLength);
    } else {
        NameLength = Kcb->NameBlock->NameLength;
    }
    
    // Assume success
    status = STATUS_SUCCESS;

    switch (KeyInformationClass) {

    case KeyCachedInformation:

        //
        // LastWriteTime, TitleIndex, 
        // SubKeys, MaxNameLen, Values, MaxValueNameLen,
        // MaxValueDataLen, Name
        //
        requiredlength = sizeof(KEY_CACHED_INFORMATION);

        *ResultLength = requiredlength;

        if (Length < requiredlength) {

            status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyCachedInformation.LastWriteTime = Kcb->KcbLastWriteTime;

            pbuffer->KeyCachedInformation.TitleIndex = 0;

            pbuffer->KeyCachedInformation.NameLength = NameLength;

            pbuffer->KeyCachedInformation.Values = Kcb->ValueCache.Count;
            
            pbuffer->KeyCachedInformation.MaxNameLen = Kcb->KcbMaxNameLen;
            
            pbuffer->KeyCachedInformation.MaxValueNameLen = Kcb->KcbMaxValueNameLen;
            
            pbuffer->KeyCachedInformation.MaxValueDataLen = Kcb->KcbMaxValueDataLen;

            if( !(Kcb->ExtFlags & CM_KCB_INVALID_CACHED_INFO) ) {
                // there is some cached info
                if( Kcb->ExtFlags & CM_KCB_NO_SUBKEY ) {
                    pbuffer->KeyCachedInformation.SubKeys = 0;
                } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_ONE ) {
                    pbuffer->KeyCachedInformation.SubKeys = 1;
                } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_HINT ) {
                    pbuffer->KeyCachedInformation.SubKeys = Kcb->IndexHint->Count;
                } else {
                    pbuffer->KeyCachedInformation.SubKeys = Kcb->SubKeyCount;
                }
            } else {
                //
                // kcb cache is not coherent; get the info from knode
                // 
                CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Kcb cache incoherency detected, kcb = %p\n",Kcb));

                Node = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive,Kcb->KeyCell);
                if( Node == NULL ) {
                    //
                    // couldn't map view for this cell
                    //
                    status = STATUS_INSUFFICIENT_RESOURCES;
                    break;
                }

                pbuffer->KeyCachedInformation.SubKeys = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
                HvReleaseCell(Kcb->KeyHive,Kcb->KeyCell);

            }

        }

        break;

    default:
        status = STATUS_INVALID_PARAMETER;
        break;
    }

    return status;
}