Example #1
0
BOOLEAN
NTAPI
CmpFreeKeyBody(IN PHHIVE Hive,
               IN HCELL_INDEX Cell)
{
    PCELL_DATA CellData;

    /* Get the key node */
    CellData = HvGetCell(Hive, Cell);
    if (!CellData) ASSERT(FALSE);

    /* Check if we can delete the child cells */
    if (!(CellData->u.KeyNode.Flags & KEY_HIVE_EXIT))
    {
        /* Check if we have a security cell */
        if (CellData->u.KeyNode.Security != HCELL_NIL)
        {
            /* Free the security cell */
            HvFreeCell(Hive, CellData->u.KeyNode.Security);
        }

        /* Check if we have a class */
        if (CellData->u.KeyNode.ClassLength > 0)
        {
            /* Free it */
            HvFreeCell(Hive, CellData->u.KeyNode.Class);
        }
    }

    /* Release and free the cell */
    HvReleaseCell(Hive, Cell);
    HvFreeCell(Hive, Cell);
    return TRUE;
}
Example #2
0
VOID
NTAPI
CmpCleanUpSubKeyInfo(IN PCM_KEY_CONTROL_BLOCK Kcb)
{
    PCM_KEY_NODE KeyNode;

    /* Sanity check */
    ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
           (CmpTestRegistryLockExclusive() == TRUE));

    /* Check if there's any cached subkey */
    if (Kcb->ExtFlags & (CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT))
    {
        /* Check if there's a hint */
        if (Kcb->ExtFlags & (CM_KCB_SUBKEY_HINT))
        {
            /* Kill it */
            CmpFree(Kcb->IndexHint, 0);
        }

        /* Remove subkey flags */
        Kcb->ExtFlags &= ~(CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT);
    }

    /* Check if there's no linked cell */
    if (Kcb->KeyCell == HCELL_NIL)
    {
        /* Make sure it's a delete */
        ASSERT(Kcb->Delete);
        KeyNode = NULL;
    }
    else
    {
        /* Get the key node */
        KeyNode = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive, Kcb->KeyCell);
    }

    /* Check if we got the node */
    if (!KeyNode)
    {
        /* We didn't, mark the cached data invalid */
        Kcb->ExtFlags |= CM_KCB_INVALID_CACHED_INFO;
    }
    else
    {
        /* We have a keynode, update subkey counts */
        Kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
        Kcb->SubKeyCount = KeyNode->SubKeyCounts[Stable] +
                           KeyNode->SubKeyCounts[Volatile];

        /* Release the cell */
        HvReleaseCell(Kcb->KeyHive, Kcb->KeyCell);
    }
}
Example #3
0
BOOLEAN
NTAPI
CmpMarkKeyDirty(IN PHHIVE Hive,
                IN HCELL_INDEX Cell,
                IN BOOLEAN CheckNoSubkeys)
{
    PCELL_DATA CellData, ListData, SecurityData, ValueData;
    ULONG i;

    /* Get the cell data for our target */
    CellData = HvGetCell(Hive, Cell);
    if (!CellData) return FALSE;

    /* Check if sanity checks requested */
    if (CheckNoSubkeys)
    {
        /* Do them */
        ASSERT(CellData->u.KeyNode.SubKeyCounts[Stable] == 0);
        ASSERT(CellData->u.KeyNode.SubKeyCounts[Volatile] == 0);
    }

    /* If this is an exit hive, there's nothing to do */
    if (CellData->u.KeyNode.Flags & KEY_HIVE_EXIT)
    {
        /* Release the cell and get out */
        HvReleaseCell(Hive, Cell);
        return TRUE;
    }

    /* Otherwise, mark it dirty and release it */
    HvMarkCellDirty(Hive, Cell, FALSE);
    HvReleaseCell(Hive, Cell);

    /* Check if we have a class */
    if (CellData->u.KeyNode.Class != HCELL_NIL)
    {
        /* Mark it dirty */
        HvMarkCellDirty(Hive, CellData->u.KeyNode.Class, FALSE);
    }

    /* Check if we have security */
    if (CellData->u.KeyNode.Security != HCELL_NIL)
    {
        /* Mark it dirty */
        HvMarkCellDirty(Hive, CellData->u.KeyNode.Security, FALSE);

        /* Get the security data and release it */
        SecurityData = HvGetCell(Hive, CellData->u.KeyNode.Security);
        if (!SecurityData) ASSERT(FALSE);
        HvReleaseCell(Hive, CellData->u.KeyNode.Security);

        /* Mark the security links dirty too */
        HvMarkCellDirty(Hive, SecurityData->u.KeySecurity.Flink, FALSE);
        HvMarkCellDirty(Hive, SecurityData->u.KeySecurity.Blink, FALSE);
    }

    /* Check if we have any values */
    if (CellData->u.KeyNode.ValueList.Count > 0)
    {
        /* Dirty the value list */
        HvMarkCellDirty(Hive, CellData->u.KeyNode.ValueList.List, FALSE);

        /* Get the list data itself, and release it */
        ListData = HvGetCell(Hive, CellData->u.KeyNode.ValueList.List);
        if (!ListData) ASSERT(FALSE);
        HvReleaseCell(Hive, CellData->u.KeyNode.ValueList.List);

        /* Loop all values */
        for (i = 0; i < CellData->u.KeyNode.ValueList.Count; i++)
        {
            /* Dirty each value */
            HvMarkCellDirty(Hive, ListData->u.KeyList[i], FALSE);

            /* Get the value data and release it */
            ValueData = HvGetCell(Hive, ListData->u.KeyList[i]);
            ASSERT(ValueData);
            HvReleaseCell(Hive,ListData->u.KeyList[i]);

            /* Mark the value data dirty too */
            if (!CmpMarkValueDataDirty(Hive, &ValueData->u.KeyValue))
            {
                /* Failure */
                return FALSE;
            }
        }
    }

    /* If this is an entry hive, we're done */
    if (CellData->u.KeyNode.Flags & KEY_HIVE_ENTRY) return TRUE;

    /* Otherwise mark the index dirty too */
    if (!CmpMarkIndexDirty(Hive, CellData->u.KeyNode.Parent, Cell))
    {
        /* Failure */
        return FALSE;
    }

    /* Finally, mark the parent dirty */
    HvMarkCellDirty(Hive, CellData->u.KeyNode.Parent, FALSE);
    return TRUE;
}
Example #4
0
NTSTATUS
NTAPI
CmpFreeKeyByCell(IN PHHIVE Hive,
                 IN HCELL_INDEX Cell,
                 IN BOOLEAN Unlink)
{
    PCELL_DATA CellData, ParentData, ListData;
    ULONG i;
    BOOLEAN Result;

    /* Mark the entire key dirty */
    CmpMarkKeyDirty(Hive, Cell ,TRUE);

    /* Get the target node and release it */
    CellData = HvGetCell(Hive, Cell);
    if (!CellData) ASSERT(FALSE);
    HvReleaseCell(Hive, Cell);

    /* Make sure we don't have subkeys */
    ASSERT((CellData->u.KeyNode.SubKeyCounts[Stable] +
            CellData->u.KeyNode.SubKeyCounts[Volatile]) == 0);

    /* Check if we have to unlink */
    if (Unlink)
    {
        /* Remove the subkey */
        Result = CmpRemoveSubKey(Hive, CellData->u.KeyNode.Parent, Cell);
        if (!Result) return STATUS_INSUFFICIENT_RESOURCES;

        /* Get the parent node and release it */
        ParentData = HvGetCell(Hive, CellData->u.KeyNode.Parent);
        if (!ParentData) ASSERT(FALSE);
        HvReleaseCell(Hive, CellData->u.KeyNode.Parent);

        /* Check if the parent node has no more subkeys */
        if (!(ParentData->u.KeyNode.SubKeyCounts[Stable] +
                ParentData->u.KeyNode.SubKeyCounts[Volatile]))
        {
            /* Then free the cached name/class lengths */
            ParentData->u.KeyNode.MaxNameLen = 0;
            ParentData->u.KeyNode.MaxClassLen = 0;
        }
    }

    /* Check if we have any values */
    if (CellData->u.KeyNode.ValueList.Count > 0)
    {
        /* Get the value list and release it */
        ListData = HvGetCell(Hive, CellData->u.KeyNode.ValueList.List);
        if (!ListData) ASSERT(FALSE);
        HvReleaseCell(Hive, CellData->u.KeyNode.ValueList.List);

        /* Loop every value */
        for (i = 0; i < CellData->u.KeyNode.ValueList.Count; i++)
        {
            /* Free it */
            if (!CmpFreeValue(Hive, ListData->u.KeyList[i])) ASSERT(FALSE);
        }

        /* Free the value list */
        HvFreeCell(Hive, CellData->u.KeyNode.ValueList.List);
    }

    /* Free the key body itself, and then return our status */
    if (!CmpFreeKeyBody(Hive, Cell)) return STATUS_INSUFFICIENT_RESOURCES;
    return STATUS_SUCCESS;
}
Example #5
0
NTSTATUS
NTAPI
CmpFreeKeyByCell(IN PHHIVE Hive,
                 IN HCELL_INDEX Cell,
                 IN BOOLEAN Unlink)
{
    PCM_KEY_NODE CellData, ParentData;
    PCELL_DATA ListData;
    ULONG i;
    BOOLEAN Result;

    /* Mark the entire key dirty */
    CmpMarkKeyDirty(Hive, Cell, TRUE);

    /* Get the target node and release it */
    CellData = HvGetCell(Hive, Cell);
    if (!CellData) ASSERT(FALSE);
    HvReleaseCell(Hive, Cell);

    /* Make sure we don't have subkeys */
    ASSERT(CellData->SubKeyCounts[Stable] + CellData->SubKeyCounts[Volatile] == 0);

    /* Check if we have to unlink */
    if (Unlink)
    {
        /* Remove the subkey */
        Result = CmpRemoveSubKey(Hive, CellData->Parent, Cell);
        if (!Result) return STATUS_INSUFFICIENT_RESOURCES;

        /* Get the parent node and release it */
        ParentData = HvGetCell(Hive, CellData->Parent);
        if (!ParentData) ASSERT(FALSE);
        HvReleaseCell(Hive, CellData->Parent);

        /* Check if the parent node has no more subkeys */
        if (ParentData->SubKeyCounts[Stable] + ParentData->SubKeyCounts[Volatile] == 0)
        {
            /* Then free the cached name/class lengths */
            ParentData->MaxNameLen  = 0;
            ParentData->MaxClassLen = 0;
        }
    }

    // TODO: Handle predefined keys (Flags: KEY_PREDEF_HANDLE)
    /* If this is an exit node, we don't have values */
    if (!(CellData->Flags & KEY_HIVE_EXIT))
    {
        /* Check if we have any values */
        if (CellData->ValueList.Count > 0)
        {
            /* Get the value list and release it */
            ListData = HvGetCell(Hive, CellData->ValueList.List);
            if (!ListData) ASSERT(FALSE);
            HvReleaseCell(Hive, CellData->ValueList.List);

            /* Loop every value */
            for (i = 0; i < CellData->ValueList.Count; i++)
            {
                /* Free it */
                if (!CmpFreeValue(Hive, ListData->u.KeyList[i])) ASSERT(FALSE);
            }

            /* Free the value list */
            HvFreeCell(Hive, CellData->ValueList.List);
        }

        /* Free the key security descriptor */
        CmpFreeSecurityDescriptor(Hive, Cell);
    }

    /* Free the key body itself, and then return our status */
    if (!CmpFreeKeyBody(Hive, Cell)) return STATUS_INSUFFICIENT_RESOURCES;
    return STATUS_SUCCESS;
}
Example #6
0
VALUE_SEARCH_RETURN_TYPE
NTAPI
CmpCompareNewValueDataAgainstKCBCache(IN PCM_KEY_CONTROL_BLOCK Kcb,
                                      IN PUNICODE_STRING ValueName,
                                      IN ULONG Type,
                                      IN PVOID Data,
                                      IN ULONG DataSize)
{
    VALUE_SEARCH_RETURN_TYPE SearchResult;
    PCM_KEY_NODE KeyNode;
    PCM_CACHED_VALUE *CachedValue;
    ULONG Index;
    PCM_KEY_VALUE Value;
    BOOLEAN ValueCached, BufferAllocated = FALSE;
    PVOID Buffer;
    HCELL_INDEX ValueCellToRelease = HCELL_NIL, CellToRelease = HCELL_NIL;
    BOOLEAN IsSmall;
    ULONG CompareResult;
    PAGED_CODE();

    /* Check if this is a symlink */
    if (Kcb->Flags & KEY_SYM_LINK)
    {
        /* We need the exclusive lock */
        if (!(CmpIsKcbLockedExclusive(Kcb)) &&
            !(CmpTryToConvertKcbSharedToExclusive(Kcb)))
        {
            /* We need the exclusive lock */
            return SearchNeedExclusiveLock;
        }
        
        /* Otherwise, get the key node */
        KeyNode = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive, Kcb->KeyCell);
        if (!KeyNode) return SearchFail;
        
        /* Cleanup the KCB cache */
        CmpCleanUpKcbValueCache(Kcb);
        
        /* Sanity checks */
        ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)));
        ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND));
        
        /* Set the value cache */
        Kcb->ValueCache.Count = KeyNode->ValueList.Count;
        Kcb->ValueCache.ValueList = KeyNode->ValueList.List;
        
        /* Release the cell */
        HvReleaseCell(Kcb->KeyHive, Kcb->KeyCell);
    }
    
    /* Do the search */
    SearchResult = CmpFindValueByNameFromCache(Kcb,
                                               ValueName,
                                               &CachedValue,
                                               &Index,
                                               &Value,
                                               &ValueCached,
                                               &ValueCellToRelease);
    if (SearchResult == SearchNeedExclusiveLock)
    {
        /* We need the exclusive lock */
        ASSERT(!CmpIsKcbLockedExclusive(Kcb));
        ASSERT(ValueCellToRelease == HCELL_NIL);
        ASSERT(Value == NULL);
        goto Quickie;
    }
    else if (SearchResult == SearchSuccess)
    {
        /* Sanity check */
        ASSERT(Value);
        
        /* First of all, check if the key size and type matches */
        if ((Type == Value->Type) &&
            (DataSize == (Value->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE)))
        {
            /* Check if this is a small key */
            IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE;
            if (IsSmall)
            {
                /* Compare against the data directly */
                Buffer = &Value->Data;
            }
            else
            {
                /* Do a search */
                SearchResult = CmpGetValueDataFromCache(Kcb,
                                                        CachedValue,
                                                        (PCELL_DATA)Value,
                                                        ValueCached,
                                                        &Buffer,
                                                        &BufferAllocated,
                                                        &CellToRelease);
                if (SearchResult != SearchSuccess)
                {
                    /* Sanity checks */
                    ASSERT(Buffer == NULL);
                    ASSERT(BufferAllocated == FALSE);
                    goto Quickie;
                }
            }
            
            /* Now check the data size */
            if (DataSize)
            {
                /* Do the compare */
                CompareResult = RtlCompareMemory(Buffer,
                                                 Data,
                                                 DataSize &
                                                 ~CM_KEY_VALUE_SPECIAL_SIZE);
            }
            else
            {
                /* It's equal */
                CompareResult = 0;
            }
            
            /* Now check if the compare wasn't equal */
            if (CompareResult != DataSize) SearchResult = SearchFail;
        }
        else
        {
            /* The length or type isn't equal */
            SearchResult = SearchFail;
        }
    }

Quickie:
    /* Release the value cell */
    if (ValueCellToRelease) HvReleaseCell(Kcb->KeyHive, ValueCellToRelease);
    
    /* Free the buffer */
    if (BufferAllocated) CmpFree(Buffer, 0);
    
    /* Free the cell */
    if (CellToRelease) HvReleaseCell(Kcb->KeyHive, CellToRelease);

    /* Return the search result */
    return SearchResult;
}
Example #7
0
VALUE_SEARCH_RETURN_TYPE
NTAPI
CmpFindValueByNameFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb,
                            IN PCUNICODE_STRING Name,
                            OUT PCM_CACHED_VALUE **CachedValue,
                            OUT ULONG *Index,
                            OUT PCM_KEY_VALUE *Value,
                            OUT BOOLEAN *ValueIsCached,
                            OUT PHCELL_INDEX CellToRelease)
{
    PHHIVE Hive;
    VALUE_SEARCH_RETURN_TYPE SearchResult = SearchFail;
    LONG Result;
    UNICODE_STRING SearchName;
    PCELL_DATA CellData;
    PCACHED_CHILD_LIST ChildList;
    PCM_KEY_VALUE KeyValue;
    BOOLEAN IndexIsCached;
    ULONG i = 0;
    HCELL_INDEX Cell = HCELL_NIL;
    PCM_KEY_NODE KeyNode;

    /* Set defaults */
    *CellToRelease = HCELL_NIL;
    *Value = NULL;

    /* Get the hive and child list */
    Hive = Kcb->KeyHive;
    ChildList = &Kcb->ValueCache;
    KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell);
    ChildList = (PCACHED_CHILD_LIST)&KeyNode->ValueList;

    /* Check if the child list has any entries */
    if (ChildList->Count != 0)
    {
        /* Get the value list associated to this child list */
        SearchResult = CmpGetValueListFromCache(Kcb,
                                                &CellData,
                                                &IndexIsCached,
                                                &Cell);
        if (SearchResult != SearchSuccess)
        {
            /* We either failed or need the exclusive lock */
            ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb)));
            ASSERT(Cell == HCELL_NIL);
            return SearchResult;
        }

        /* The index shouldn't be cached right now */
        if (IndexIsCached) ASSERT_VALUE_CACHE();

        /* Loop every value */
        while (TRUE)
        {
            /* Check if there's any cell to release */
            if (*CellToRelease != HCELL_NIL)
            {
                /* Release it now */
                HvReleaseCell(Hive, *CellToRelease);
                *CellToRelease = HCELL_NIL;
            }

            /* Get the key value for this index */
            SearchResult =  CmpGetValueKeyFromCache(Kcb,
                                                    CellData,
                                                    i,
                                                    CachedValue,
                                                    Value,
                                                    IndexIsCached,
                                                    ValueIsCached,
                                                    CellToRelease);
            if (SearchResult != SearchSuccess)
            {
                /* We either failed or need the exclusive lock */
                ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb)));
                ASSERT(Cell == HCELL_NIL);
                return SearchResult;
            }

            /* Check if the both the index and the value are cached */
            if ((IndexIsCached) && (*ValueIsCached))
            {
                /* We don't expect this yet */
                ASSERT_VALUE_CACHE();
                Result = -1;
            }
            else
            {
                /* No cache, so try to compare the name. Is it compressed? */
                KeyValue = *Value;
                if (KeyValue->Flags & VALUE_COMP_NAME)
                {
                    /* It is, do a compressed name comparison */
                    Result = CmpCompareCompressedName(Name,
                                                      KeyValue->Name,
                                                      KeyValue->NameLength);
                }
                else
                {
                    /* It's not compressed, so do a standard comparison */
                    SearchName.Length = KeyValue->NameLength;
                    SearchName.MaximumLength = SearchName.Length;
                    SearchName.Buffer = KeyValue->Name;
                    Result = RtlCompareUnicodeString(Name, &SearchName, TRUE);
                }
            }

            /* Check if we found the value data */
            if (!Result)
            {
                /* We have, return the index of the value and success */
                *Index = i;
                SearchResult = SearchSuccess;
                goto Quickie;
            }

            /* We didn't find it, try the next entry */
            if (++i == ChildList->Count)
            {
                /* The entire list was parsed, fail */
                *Value = NULL;
                SearchResult = SearchFail;
                goto Quickie;
            }
        }
    }

    /* We should only get here if the child list is empty */
    ASSERT(ChildList->Count == 0);

Quickie:
    /* Release the value list cell if required, and return search result */
    if (Cell != HCELL_NIL) HvReleaseCell(Hive, Cell);
    return SearchResult;
}
Example #8
0
BOOLEAN
NTAPI
CmpFindNameInList(IN PHHIVE Hive,
                  IN PCHILD_LIST ChildList,
                  IN PUNICODE_STRING Name,
                  IN PULONG ChildIndex,
                  IN PHCELL_INDEX CellIndex)
{
    PCELL_DATA CellData;
    HCELL_INDEX CellToRelease = HCELL_NIL;
    ULONG i;
    PCM_KEY_VALUE KeyValue;
    LONG Result;
    UNICODE_STRING SearchName;
    BOOLEAN Success;

    /* Make sure there's actually something on the list */
    if (ChildList->Count != 0)
    {
        /* Get the cell data */
        CellData = (PCELL_DATA)HvGetCell(Hive, ChildList->List);
        if (!CellData)
        {
            /* Couldn't get the cell... tell the caller */
            *CellIndex = HCELL_NIL;
            return FALSE;
        }

        /* Now loop every entry */
        for (i = 0; i < ChildList->Count; i++)
        {
            /* Check if we have a cell to release */
            if (CellToRelease != HCELL_NIL)
            {
                /* Release it */
                HvReleaseCell(Hive, CellToRelease);
                CellToRelease = HCELL_NIL;
            }

            /* Get this value */
            KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellData->u.KeyList[i]);
            if (!KeyValue)
            {
                /* Return with no data found */
                *CellIndex = HCELL_NIL;
                Success = FALSE;
                goto Return;
            }

            /* Save the cell to release */
            CellToRelease = CellData->u.KeyList[i];

            /* Check if it's a compressed value name */
            if (KeyValue->Flags & VALUE_COMP_NAME)
            {
                /* Use the compressed name check */
                Result = CmpCompareCompressedName(Name,
                                                  KeyValue->Name,
                                                  KeyValue->NameLength);
            }
            else
            {
                /* Setup the Unicode string */
                SearchName.Length = KeyValue->NameLength;
                SearchName.MaximumLength = SearchName.Length;
                SearchName.Buffer = KeyValue->Name;
                Result = RtlCompareUnicodeString(Name, &SearchName, TRUE);
            }

            /* Check if we found it */
            if (!Result)
            {
                /* We did...return info to caller */
                if (ChildIndex) *ChildIndex = i;
                *CellIndex = CellData->u.KeyList[i];

                /* Set success state */
                Success = TRUE;
                goto Return;
            }
        }

        /* Got to the end of the list */
        if (ChildIndex) *ChildIndex = i;
        *CellIndex = HCELL_NIL;

        /* Nothing found if we got here */
        Success = TRUE;
        goto Return;
    }

    /* Nothing found...check if the caller wanted more info */
    ASSERT(ChildList->Count == 0);
    if (ChildIndex) *ChildIndex = 0;
    *CellIndex = HCELL_NIL;

    /* Nothing found if we got here */
    return TRUE;

Return:
    /* Release the first cell we got */
    if (CellData) HvReleaseCell(Hive, ChildList->List);

    /* Release the secondary one, if we have one */
    if (CellToRelease) HvReleaseCell(Hive, CellToRelease);
    return Success;
}
Example #9
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;
}
Example #10
0
VALUE_SEARCH_RETURN_TYPE
CmpFindValueByNameFromCache(
    IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
    IN PUNICODE_STRING      Name,
    OUT PPCM_CACHED_VALUE   *ContainingList,
    OUT ULONG               *Index,
    OUT PCM_KEY_VALUE       *Value,
    OUT BOOLEAN             *ValueCached,
    OUT PHCELL_INDEX        CellToRelease
    )
/*++

Routine Description:

    Find a value node given a value list array and a value name.  It sequentially walk
    through each value node to look for a match.  If the array and 
    value nodes touched are not already cached, cache them.

Arguments:

    Hive - pointer to hive control structure for hive of interest

    ChildList - pointer/index to the Value Index array

    Name - name of value to find

    ContainlingList - The address of the entry that will receive the found cached value.

    Index - pointer to variable to receive index for child
    
    ValueCached - Indicate if the value node is cached.

Return Value:

    HCELL_INDEX for the found cell
    HCELL_NIL if not found


Notes:
    
    New hives (Minor >= 4) have ValueList sorted; this implies ValueCache is sorted too;
    So, we can do a binary search here!

--*/
{
    UNICODE_STRING      Candidate;
    LONG                Result;
    PCELL_DATA          List;
    BOOLEAN             IndexCached;
    ULONG               Current;
    HCELL_INDEX         ValueListToRelease = HCELL_NIL;
    ULONG               HashKey = 0;
    PHHIVE              Hive = KeyControlBlock->KeyHive;
    PCACHED_CHILD_LIST  ChildList = &(KeyControlBlock->ValueCache);
    VALUE_SEARCH_RETURN_TYPE    ret = SearchFail;

    ASSERT_KCB_LOCKED(KeyControlBlock);

    *CellToRelease = HCELL_NIL;
    *Value = NULL;

    if (ChildList->Count != 0) {
        ret = CmpGetValueListFromCache(KeyControlBlock,&List, &IndexCached,&ValueListToRelease);
        if( ret != SearchSuccess ) {
            //
            // retry with exclusive lock, since we need to update the cache
            // or fail altogether
            //
            ASSERT( (ret == SearchFail) || (CmpIsKCBLockedExclusive(KeyControlBlock) == FALSE) );    
            ASSERT( ValueListToRelease == HCELL_NIL );    
            return ret;
        } 
        
        if( IndexCached ) {
            try {
                HashKey = CmpComputeHashKey(0,Name
#if DBG
                                            , TRUE
#endif
                    );
            } except (EXCEPTION_EXECUTE_HANDLER) {
                ret = SearchFail;
                goto Exit;
            }
        }
        //
        // old plain hive; simulate a for
        //
        Current = 0;

        while( TRUE ) {
            if( *CellToRelease != HCELL_NIL ) {
                HvReleaseCell(Hive,*CellToRelease);
                *CellToRelease = HCELL_NIL;
            }
            ret =  CmpGetValueKeyFromCache(KeyControlBlock, List, Current, ContainingList, Value, IndexCached, ValueCached, CellToRelease);
            if( ret != SearchSuccess ) {
                //
                // retry with exclusive lock, since we need to update the cache
                // or fail altogether
                //
                ASSERT( (ret == SearchFail) || (CmpIsKCBLockedExclusive(KeyControlBlock) == FALSE) );    
                ASSERT( *CellToRelease == HCELL_NIL );    
                return ret;
            } 

            //
            // only compare names when hash matches.
            //
            if( IndexCached && (*ValueCached) && (HashKey != ((PCM_CACHED_VALUE)((CMP_GET_CACHED_ADDRESS(**ContainingList))))->HashKey) ) {
                //
                // no hash match; skip it
                //
#if DBG
                try {
                    //
                    // Name has user-mode buffer.
                    //

                    if ((*Value)->Flags & VALUE_COMP_NAME) {
                        Result = CmpCompareCompressedName(  Name,
                                                            (*Value)->Name,
                                                            (*Value)->NameLength,
                                                            0);
                    } else {
                        Candidate.Length = (*Value)->NameLength;
                        Candidate.MaximumLength = Candidate.Length;
                        Candidate.Buffer = (*Value)->Name;
                        Result = RtlCompareUnicodeString(   Name,
                                                            &Candidate,
                                                            TRUE);
                    }


                } except (EXCEPTION_EXECUTE_HANDLER) {
                    CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"CmpFindValueByNameFromCache: code:%08lx\n", GetExceptionCode()));
                    //
                    // the caller will bail out. Some ,alicious caller altered the Name buffer since we probed it.
                    //
                    *Value = NULL;
                    ret = SearchFail;
                    goto Exit;
                }
                ASSERT( Result != 0 );
#endif
                Result = 1;
            } else {
                try {
                    //
                    // Name has user-mode buffer.
                    //

                    if( (*Value)->Flags & VALUE_COMP_NAME) {
                        Result = CmpCompareCompressedName(  Name,
                                                            (*Value)->Name,
                                                            (*Value)->NameLength,
                                                            0);
                    } else {
                        Candidate.Length = (*Value)->NameLength;
                        Candidate.MaximumLength = Candidate.Length;
                        Candidate.Buffer = (*Value)->Name;
                        Result = RtlCompareUnicodeString(   Name,
                                                            &Candidate,
                                                            TRUE);
                    }


                } except (EXCEPTION_EXECUTE_HANDLER) {
                    CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"CmpFindValueByNameFromCache: code:%08lx\n", GetExceptionCode()));
                    //
                    // the caller will bail out. Some ,alicious caller altered the Name buffer since we probed it.
                    //
                    *Value = NULL;
                    ret = SearchFail;
                    goto Exit;
                }
            }
            if (Result == 0) {
                //
                // Success, fill the index, return data to caller and exit
                //
                *Index = Current;
                ret = SearchSuccess;
                goto Exit;
            }

            //
            // compute the next index to try: old'n plain hive; go on
			//
            Current++;
            if( Current == ChildList->Count ) {
                //
                // we've reached the end of the list; nicely return
                //
                (*Value) = NULL;
                ret = SearchFail;
                goto Exit;
            }

        } // while(TRUE)
Example #11
0
VOID
CmGetSystemControlValues(
    __in PVOID                   SystemHiveBuffer,
    __inout PCM_SYSTEM_CONTROL_VECTOR  ControlVector
    )
/*++

Routine Description:

    Look for registry values in current control set, as specified
    by entries in ControlVector.  Report data for value entries
    (if any) to variables ControlVector points to.

Arguments:

    SystemHiveBuffer - pointer to flat image of the system hive

    ControlVector - pointer to structure that describes what values
                    to pull out and store

Return Value:

    NONE.

--*/
{
    NTSTATUS        status;
    PHHIVE          SystemHive;
    HCELL_INDEX     RootCell;
    HCELL_INDEX     BaseCell;
    UNICODE_STRING  Name;
    HCELL_INDEX     KeyCell;
    HCELL_INDEX     ValueCell;
    PCM_KEY_VALUE   ValueBody;
    ULONG           Length;
    BOOLEAN         AutoSelect;
    BOOLEAN         small;
    ULONG           tmplength;
    PCM_KEY_NODE    Node;

    //
    // set up to read flat system hive image loader passes us
    //
    RtlZeroMemory((PVOID)&CmControlHive, sizeof(CmControlHive));
    SystemHive = &(CmControlHive.Hive);
    CmpInitHiveViewList((PCMHIVE)SystemHive);
    CmpInitSecurityCache((PCMHIVE)SystemHive);
    status = HvInitializeHive(
                SystemHive,
                HINIT_FLAT,
                HIVE_VOLATILE,
                HFILE_TYPE_PRIMARY,
                SystemHiveBuffer,
                NULL,
                NULL,
                NULL,
                NULL,
                NULL,
                NULL,
                1,
                NULL
                );
    if (!NT_SUCCESS(status)) {
         CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_SYSTEM_CONTROL_VALUES,1,SystemHive,status);
    }

    //
    // don't bother locking/releasing cells
    //
    ASSERT( SystemHive->ReleaseCellRoutine == NULL );
    //
    // get hive.cell of root of current control set
    //
    RootCell = ((PHBASE_BLOCK)SystemHiveBuffer)->RootCell;
    RtlInitUnicodeString(&Name, L"current");
    BaseCell = CmpFindControlSet(
                    SystemHive,
                    RootCell,
                    &Name,
                    &AutoSelect
                    );
    if (BaseCell == HCELL_NIL) {
        CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_SYSTEM_CONTROL_VALUES,2,SystemHive,&Name);
    }

    Node = (PCM_KEY_NODE)HvGetCell(SystemHive,BaseCell);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //
        return;
    }
    RtlInitUnicodeString(&Name, L"control");
    BaseCell = CmpFindSubKeyByName(SystemHive,
                                   Node,
                                   &Name);
    if (BaseCell == HCELL_NIL) {
        CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_SYSTEM_CONTROL_VALUES,3,Node,&Name);
    }

    //
    // SystemHive.BaseCell = \registry\machine\system\currentcontrolset\control
    //

    //
    // step through vector, trying to fetch each value
    //
    while (ControlVector->KeyPath != NULL) {

        //
        //  Assume we will fail to find the key or value.
        //
        
        Length = (ULONG)-1;

        KeyCell = CmpWalkPath(SystemHive, BaseCell, ControlVector->KeyPath);

        if (KeyCell != HCELL_NIL) {

            //
            // found the key, look for the value entry
            //
            Node = (PCM_KEY_NODE)HvGetCell(SystemHive,KeyCell);
            if( Node == NULL ) {
                //
                // we couldn't map a view for the bin containing this cell
                //
                return;
            }
            RtlInitUnicodeString(&Name, ControlVector->ValueName);
            ValueCell = CmpFindValueByName(SystemHive,
                                           Node,
                                           &Name);
            if (ValueCell != HCELL_NIL) {

                //
                // SystemHive.ValueCell is value entry body
                //

                if (ControlVector->BufferLength == NULL) {
                    tmplength = sizeof(ULONG);
                } else {
                    tmplength = *(ControlVector->BufferLength);
                }

                ValueBody = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
                if( ValueBody == NULL ) {
                    //
                    // we couldn't map a view for the bin containing this cell
                    //
                    return;
                }

                small = CmpIsHKeyValueSmall(Length, ValueBody->DataLength);

                if (tmplength < Length) {
                    Length = tmplength;
                }

                if (Length > 0) {

                    PCELL_DATA  Buffer;
                    BOOLEAN     BufferAllocated;
                    ULONG       realsize;
                    HCELL_INDEX CellToRelease;

                    ASSERT((small ? (Length <= CM_KEY_VALUE_SMALL) : TRUE));
                    //
                    // get the data from source, regardless of the size
                    //
                    if( CmpGetValueData(SystemHive,ValueBody,&realsize,&Buffer,&BufferAllocated,&CellToRelease) == FALSE ) {
                        //
                        // insufficient resources; return NULL
                        //
                        ASSERT( BufferAllocated == FALSE );
                        ASSERT( Buffer == NULL );
                        return;
                    }

                    RtlCopyMemory(
                        ControlVector->Buffer,
                        Buffer,
                        Length
                        );

                    //
                    // cleanup the temporary buffer
                    //
                    if( BufferAllocated == TRUE ) {
                        ExFreePool( Buffer );
                    }
                    if( CellToRelease != HCELL_NIL ) {
                        HvReleaseCell(SystemHive,CellToRelease);
                    }
                }

                if (ControlVector->Type != NULL) {
                    *(ControlVector->Type) = ValueBody->Type;
                }
            }
        }

        //
        // Stash the length of result (-1 if nothing was found)
        //
        
        if (ControlVector->BufferLength != NULL) {
            *(ControlVector->BufferLength) = Length;
        }

        ControlVector++;
    }

    //
    // Get the default locale ID for the system from the registry.
    //

    if (CmDefaultLanguageIdType == REG_SZ) {
        PsDefaultSystemLocaleId = (LCID) CmpConvertLangId( 
                                                CmDefaultLanguageId,
                                                CmDefaultLanguageIdLength);
    } else {
        PsDefaultSystemLocaleId = 0x00000409;
    }

    //
    // Get the install (native UI) language ID for the system from the registry.
    //

    if (CmInstallUILanguageIdType == REG_SZ) {
        PsInstallUILanguageId =  CmpConvertLangId( 
                                                CmInstallUILanguageId,
                                                CmInstallUILanguageIdLength);
    } else {
        PsInstallUILanguageId = LANGIDFROMLCID(PsDefaultSystemLocaleId);
    }

    //
    // Set the default thread locale to the default system locale
    // for now.  This will get changed as soon as somebody logs in.
    // Use the install (native) language id as our default UI language id. 
    // This also will get changed as soon as somebody logs in.
    //

    PsDefaultThreadLocaleId = PsDefaultSystemLocaleId;
    PsDefaultUILanguageId = PsInstallUILanguageId;
}
Example #12
0
VALUE_SEARCH_RETURN_TYPE
CmpQueryKeyValueData(
    PCM_KEY_CONTROL_BLOCK KeyControlBlock,
    PPCM_CACHED_VALUE   ContainingList,
    PCM_KEY_VALUE       ValueKey,
    BOOLEAN             ValueCached,
    KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
    PVOID               KeyValueInformation,
    ULONG               Length,
    PULONG              ResultLength,
    NTSTATUS            *status
    )
/*++

Routine Description:

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

    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

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

    KeyValueInformation -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

--*/
{
    PKEY_VALUE_INFORMATION pbuffer;
    PCELL_DATA  pcell;
    LONG        leftlength;
    ULONG       requiredlength;
    ULONG       minimumlength;
    ULONG       offset;
    ULONG       base;
    ULONG       realsize;
    PUCHAR      datapointer;
    BOOLEAN     small;
    USHORT      NameLength;
    BOOLEAN     BufferAllocated = FALSE;
    HCELL_INDEX CellToRelease = HCELL_NIL;
    PHHIVE      Hive;
    VALUE_SEARCH_RETURN_TYPE SearchValue = SearchSuccess;

    Hive = KeyControlBlock->KeyHive;
    pbuffer = (PKEY_VALUE_INFORMATION)KeyValueInformation;

    pcell = (PCELL_DATA) ValueKey;
    NameLength = CmpValueNameLen(&pcell->u.KeyValue);

    switch (KeyValueInformationClass) {

    case KeyValueBasicInformation:

        //
        // TitleIndex, Type, NameLength, Name
        //
        requiredlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) +
                         NameLength;

        minimumlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);

        *ResultLength = requiredlength;

        *status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            *status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyValueBasicInformation.TitleIndex = 0;

            pbuffer->KeyValueBasicInformation.Type =
                pcell->u.KeyValue.Type;

            pbuffer->KeyValueBasicInformation.NameLength =
                NameLength;

            leftlength = Length - minimumlength;
            requiredlength = NameLength;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                *status = STATUS_BUFFER_OVERFLOW;
            }

            if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
                CmpCopyCompressedName(pbuffer->KeyValueBasicInformation.Name,
                                      requiredlength,
                                      pcell->u.KeyValue.Name,
                                      pcell->u.KeyValue.NameLength);
            } else {
                RtlCopyMemory(&(pbuffer->KeyValueBasicInformation.Name[0]),
                              &(pcell->u.KeyValue.Name[0]),
                              requiredlength);
            }
        }

        break;



    case KeyValueFullInformation:
    case KeyValueFullInformationAlign64:

        //
        // TitleIndex, Type, DataOffset, DataLength, NameLength,
        // Name, Data
        //
        small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);

        requiredlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) +
                         NameLength +
                         realsize;

        minimumlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
        offset = 0;
        if (realsize > 0) {
            base = requiredlength - realsize;

#if defined(_WIN64)

            offset = ALIGN_OFFSET64(base);

#else

            if (KeyValueInformationClass == KeyValueFullInformationAlign64) {
                offset = ALIGN_OFFSET64(base);

            } else {
                offset = ALIGN_OFFSET(base);
            }

#endif

            if (offset > base) {
                requiredlength += (offset - base);
            }

#if DBG && defined(_WIN64)

            //
            // Some clients will have passed in a structure that they "know"
            // will be exactly the right size.  The fact that alignment
            // has changed on NT64 may cause these clients to have problems.
            //
            // The solution is to fix the client, but print out some debug
            // spew here if it looks like this is the case.  This problem
            // isn't particularly easy to spot from the client end.
            //

            if((KeyValueInformationClass == KeyValueFullInformation) &&
                (Length != minimumlength) &&
                (requiredlength > Length) &&
                ((requiredlength - Length) <=
                                (ALIGN_OFFSET64(base) - ALIGN_OFFSET(base)))) {

                CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"ntos/config-64 KeyValueFullInformation: "
                                                                 "Possible client buffer size problem.\n"));

                CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"    Required size = %d\n", requiredlength));
                CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"    Supplied size = %d\n", Length));
            }

#endif

        }

        *ResultLength = requiredlength;

        *status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            *status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyValueFullInformation.TitleIndex = 0;

            pbuffer->KeyValueFullInformation.Type =
                pcell->u.KeyValue.Type;

            pbuffer->KeyValueFullInformation.DataLength =
                realsize;

            pbuffer->KeyValueFullInformation.NameLength =
                NameLength;

            leftlength = Length - minimumlength;
            requiredlength = NameLength;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                *status = STATUS_BUFFER_OVERFLOW;
            }

            if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
                CmpCopyCompressedName(pbuffer->KeyValueFullInformation.Name,
                                      requiredlength,
                                      pcell->u.KeyValue.Name,
                                      pcell->u.KeyValue.NameLength);
            } else {
                RtlCopyMemory(
                    &(pbuffer->KeyValueFullInformation.Name[0]),
                    &(pcell->u.KeyValue.Name[0]),
                    requiredlength
                    );
            }

            if (realsize > 0) {

                if (small == TRUE) {
                    datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
                } else {
                    SearchValue = CmpGetValueDataFromCache(KeyControlBlock, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease);
                    if( SearchValue != SearchSuccess ) {
                        ASSERT( datapointer == NULL );
                        ASSERT( BufferAllocated == FALSE );
                        *status = STATUS_INSUFFICIENT_RESOURCES;
                    }
                }

                pbuffer->KeyValueFullInformation.DataOffset = offset;

                leftlength = (((LONG)Length - (LONG)offset) < 0) ?
                                    0 :
                                    Length - offset;

                requiredlength = realsize;

                if (leftlength < (LONG)requiredlength) {
                    requiredlength = leftlength;
                    *status = STATUS_BUFFER_OVERFLOW;
                }

                ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));

                if( datapointer != NULL ) {
                    try {
                        RtlCopyMemory(
                            ((PUCHAR)pbuffer + offset),
                            datapointer,
                            requiredlength
                            );
                    } finally {
                        if( BufferAllocated == TRUE ) {
                            ExFreePool(datapointer);
                        }
                        if( CellToRelease != HCELL_NIL ) {
                            HvReleaseCell(Hive,CellToRelease);
                        }
                    }
                }

            } else {
                pbuffer->KeyValueFullInformation.DataOffset = (ULONG)-1;
            }
        }

        break;


    case KeyValuePartialInformation:

        //
        // TitleIndex, Type, DataLength, Data
        //
        small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
        requiredlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
                         realsize;

        minimumlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);

        *ResultLength = requiredlength;

        *status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            *status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyValuePartialInformation.TitleIndex = 0;

            pbuffer->KeyValuePartialInformation.Type =
                pcell->u.KeyValue.Type;

            pbuffer->KeyValuePartialInformation.DataLength =
                realsize;

            leftlength = Length - minimumlength;
            requiredlength = realsize;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                *status = STATUS_BUFFER_OVERFLOW;
            }

            if (realsize > 0) {

                if (small == TRUE) {
                    datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
                } else {
                    SearchValue = CmpGetValueDataFromCache(KeyControlBlock, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease);
                    if( SearchValue != SearchSuccess ) {
                        ASSERT( datapointer == NULL );
                        ASSERT( BufferAllocated == FALSE );
                        *status = STATUS_INSUFFICIENT_RESOURCES;
                    }
                }

                ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));

                if( datapointer != NULL ) {
                    try {
                        RtlCopyMemory((PUCHAR)&(pbuffer->KeyValuePartialInformation.Data[0]),
                                      datapointer,
                                      requiredlength);
                    } finally {
                        if( BufferAllocated == TRUE ) {
                            ExFreePool(datapointer);
                        }
                        if(CellToRelease != HCELL_NIL) {
                            HvReleaseCell(Hive,CellToRelease);
                        }
                    }
                }
            }
        }

        break;
    case KeyValuePartialInformationAlign64:

        //
        // TitleIndex, Type, DataLength, Data
        //
        small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
        requiredlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, Data) +
                         realsize;

        minimumlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, Data);

        *ResultLength = requiredlength;

        *status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            *status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyValuePartialInformationAlign64.Type =
                pcell->u.KeyValue.Type;

            pbuffer->KeyValuePartialInformationAlign64.DataLength =
                realsize;

            leftlength = Length - minimumlength;
            requiredlength = realsize;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                *status = STATUS_BUFFER_OVERFLOW;
            }

            if (realsize > 0) {

                if (small == TRUE) {
                    datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
                } else {
                    SearchValue = CmpGetValueDataFromCache(KeyControlBlock, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease);
                    if( SearchValue != SearchSuccess ) {
                        ASSERT( datapointer == NULL );
                        ASSERT( BufferAllocated == FALSE );
                        *status = STATUS_INSUFFICIENT_RESOURCES;
                    }
                }

                ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
                if( datapointer != NULL ) {
                    try {
                        RtlCopyMemory((PUCHAR)&(pbuffer->KeyValuePartialInformationAlign64.Data[0]),
                                      datapointer,
                                      requiredlength);
                    } finally {
                        if( BufferAllocated == TRUE ) {
                            ExFreePool(datapointer);
                        }
                        if(CellToRelease != HCELL_NIL) {
                            HvReleaseCell(Hive,CellToRelease);
                        }
                    }
                }
            }
        }

        break;

    default:
        *status = STATUS_INVALID_PARAMETER;
        break;
    }
Example #13
0
NTSTATUS
CmpQueryKeyData(
    PHHIVE                  Hive,
    PCM_KEY_NODE            Node,
    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.

Arguments:

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

    Node - Supplies pointer to node whose subkeys 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 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

--*/
{
    NTSTATUS            status;
    PCELL_DATA          pclass;
    ULONG               requiredlength;
    LONG                leftlength;
    ULONG               offset;
    ULONG               minimumlength;
    PKEY_INFORMATION    pbuffer;
    USHORT              NameLength;

    pbuffer = (PKEY_INFORMATION)KeyInformation;
    NameLength = CmpHKeyNameLen(Node);

    switch (KeyInformationClass) {

    case KeyBasicInformation:

        //
        // LastWriteTime, TitleIndex, NameLength, Name
        //

        requiredlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) +
                         NameLength;

        minimumlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name);

        *ResultLength = requiredlength;

        status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyBasicInformation.LastWriteTime =
                Node->LastWriteTime;

            pbuffer->KeyBasicInformation.TitleIndex = 0;

            pbuffer->KeyBasicInformation.NameLength =
                NameLength;

            leftlength = Length - minimumlength;

            requiredlength = NameLength;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                status = STATUS_BUFFER_OVERFLOW;
            }

            if (Node->Flags & KEY_COMP_NAME) {
                CmpCopyCompressedName(pbuffer->KeyBasicInformation.Name,
                                      leftlength,
                                      Node->Name,
                                      Node->NameLength);
            } else {
                RtlCopyMemory(
                    &(pbuffer->KeyBasicInformation.Name[0]),
                    &(Node->Name[0]),
                    requiredlength
                    );
            }
        }

        break;


    case KeyNodeInformation:
        //
        // LastWriteTime, TitleIndex, ClassOffset, ClassLength
        // NameLength, Name, Class
        //
        requiredlength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) +
                         NameLength +
                         Node->ClassLength;

        minimumlength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name);

        *ResultLength = requiredlength;

        status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyNodeInformation.LastWriteTime =
                Node->LastWriteTime;

            pbuffer->KeyNodeInformation.TitleIndex = 0;

            pbuffer->KeyNodeInformation.ClassLength =
                Node->ClassLength;

            pbuffer->KeyNodeInformation.NameLength =
                NameLength;

            leftlength = Length - minimumlength;
            requiredlength = NameLength;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                status = STATUS_BUFFER_OVERFLOW;
            }

            if (Node->Flags & KEY_COMP_NAME) {
                CmpCopyCompressedName(pbuffer->KeyNodeInformation.Name,
                                      leftlength,
                                      Node->Name,
                                      Node->NameLength);
            } else {
                RtlCopyMemory(
                    &(pbuffer->KeyNodeInformation.Name[0]),
                    &(Node->Name[0]),
                    requiredlength
                    );
            }

            if (Node->ClassLength > 0) {

                offset = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) +
                            NameLength;
                offset = ALIGN_OFFSET(offset);

                pbuffer->KeyNodeInformation.ClassOffset = offset;

                pclass = HvGetCell(Hive, Node->Class);
                if( pclass == NULL ) {
                    //
                    // we couldn't map this cell
                    //
                    status = STATUS_INSUFFICIENT_RESOURCES;
                    break;
                }

                pbuffer = (PKEY_INFORMATION)((PUCHAR)pbuffer + offset);

                leftlength = (((LONG)Length - (LONG)offset) < 0) ?
                                    0 :
                                    Length - offset;

                requiredlength = Node->ClassLength;

                if (leftlength < (LONG)requiredlength) {
                    requiredlength = leftlength;
                    status = STATUS_BUFFER_OVERFLOW;
                }

                RtlCopyMemory(
                    pbuffer,
                    pclass,
                    requiredlength
                    );

                HvReleaseCell(Hive,Node->Class);

            } else {
                pbuffer->KeyNodeInformation.ClassOffset = (ULONG)-1;
            }
        }

        break;


    case KeyFullInformation:
        //
        // LastWriteTime, TitleIndex, ClassOffset, ClassLength,
        // SubKeys, MaxNameLen, MaxClassLen, Values, MaxValueNameLen,
        // MaxValueDataLen, Class
        //
        requiredlength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) +
                         Node->ClassLength;

        minimumlength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);

        *ResultLength = requiredlength;

        status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyFullInformation.LastWriteTime =
                Node->LastWriteTime;

            pbuffer->KeyFullInformation.TitleIndex = 0;

            pbuffer->KeyFullInformation.ClassLength =
                Node->ClassLength;

            if (Node->ClassLength > 0) {

                pbuffer->KeyFullInformation.ClassOffset =
                        FIELD_OFFSET(KEY_FULL_INFORMATION, Class);

                pclass = HvGetCell(Hive, Node->Class);
                if( pclass == NULL ) {
                    //
                    // we couldn't map this cell
                    //
                    status = STATUS_INSUFFICIENT_RESOURCES;
                    break;
                }

                leftlength = Length - minimumlength;
                requiredlength = Node->ClassLength;

                if (leftlength < (LONG)requiredlength) {
                    requiredlength = leftlength;
                    status = STATUS_BUFFER_OVERFLOW;
                }

                RtlCopyMemory(
                    &(pbuffer->KeyFullInformation.Class[0]),
                    pclass,
                    requiredlength
                    );

                HvReleaseCell(Hive,Node->Class);

            } else {
                pbuffer->KeyFullInformation.ClassOffset = (ULONG)-1;
            }

            pbuffer->KeyFullInformation.SubKeys =
                Node->SubKeyCounts[Stable] +
                Node->SubKeyCounts[Volatile];

            pbuffer->KeyFullInformation.Values =
                Node->ValueList.Count;

            pbuffer->KeyFullInformation.MaxNameLen =
                Node->MaxNameLen;

            pbuffer->KeyFullInformation.MaxClassLen =
                Node->MaxClassLen;

            pbuffer->KeyFullInformation.MaxValueNameLen =
                Node->MaxValueNameLen;

            pbuffer->KeyFullInformation.MaxValueDataLen =
                Node->MaxValueDataLen;

        }

        break;


    default:
        status = STATUS_INVALID_PARAMETER;
        break;
    }

    return status;
}
Example #14
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;
}