Exemple #1
0
VOID
NTAPI
CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
                           IN BOOLEAN LockHeldExclusively)
{
    PCM_KEY_CONTROL_BLOCK Parent;
    PAGED_CODE();

    /* Sanity checks */
    ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
           (CmpTestRegistryLockExclusive() == TRUE));
    ASSERT(Kcb->RefCount == 0);

    /* Cleanup the value cache */
    CmpCleanUpKcbValueCache(Kcb);

    /* Dereference the NCB */
    CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock);

    /* Check if we have an index hint block and free it */
    if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) CmpFree(Kcb->IndexHint, 0);

    /* Check if we were already deleted */
    Parent = Kcb->ParentKcb;
    if (!Kcb->Delete) CmpRemoveKeyControlBlock(Kcb);

    /* Set invalid KCB signature */
    Kcb->Signature = CM_KCB_INVALID_SIGNATURE;

    /* Free the KCB as well */
    CmpFreeKeyControlBlock(Kcb);

    /* Check if we have a parent */
    if (Parent)
    {
        /* Dereference the parent */
        LockHeldExclusively ?
        CmpDereferenceKeyControlBlockWithLock(Parent,LockHeldExclusively) :
        CmpDelayDerefKeyControlBlock(Parent);
    }
}
Exemple #2
0
PCM_KEY_CONTROL_BLOCK
CmpCreateKeyControlBlock(
    PHHIVE          Hive,
    HCELL_INDEX     Cell,
    PCM_KEY_NODE    Node,
    PCM_KEY_CONTROL_BLOCK ParentKcb,
    BOOLEAN         FakeKey,
    PUNICODE_STRING KeyName
    )
/*++

Routine Description:

    Allocate and initialize a key control block, insert it into
    the kcb tree.

    Full path will be BaseName + '\' + KeyName, unless BaseName
    NULL, in which case the full path is simply KeyName.

    RefCount of returned KCB WILL have been incremented to reflect
    callers ref.

Arguments:

    Hive - Supplies Hive that holds the key we are creating a KCB for.

    Cell - Supplies Cell that contains the key we are creating a KCB for.

    Node - Supplies pointer to key node.

    ParentKcb - Parent kcb of the kcb to be created

    FakeKey - Whether the kcb to be create is a fake one or not

    KeyName - the subkey name to of the KCB to be created.
 
    NOTE:  We need the parameter instead of just using the name in the KEY_NODE 
           because there is no name in the root cell of a hive.

Return Value:

    NULL - failure (insufficient memory)
    else a pointer to the new kcb.

--*/
{
    PCM_KEY_CONTROL_BLOCK   kcb;
    PCM_KEY_CONTROL_BLOCK   kcbmatch=NULL;
    PCMHIVE CmHive;
    ULONG namelength;
    PUNICODE_STRING         fullname;
    ULONG       Size;
    ULONG i;

    UNICODE_STRING         NodeName;
    ULONG ConvKey=0;
    ULONG Cnt;
    WCHAR *Cp;

    //
    // ParentKCb has the base hash value.
    //
    if (ParentKcb) {
        ConvKey = ParentKcb->ConvKey;
    }

    NodeName = *KeyName;

    while ((NodeName.Length > 0) && (NodeName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) {
        //
        // This must be the \REGISTRY.
        // Strip off the leading OBJ_NAME_PATH_SEPARATOR
        //
        NodeName.Buffer++;
        NodeName.Length -= sizeof(WCHAR);
    }

    //
    // Manually compute the hash to use.
    //
    ASSERT(NodeName.Length > 0);

    if (NodeName.Length) {
        Cp = NodeName.Buffer;
        for (Cnt=0; Cnt<NodeName.Length; Cnt += sizeof(WCHAR)) {
            if ((*Cp != OBJ_NAME_PATH_SEPARATOR) &&
                (*Cp != UNICODE_NULL)) {
                ConvKey = 37 * ConvKey + (ULONG)RtlUpcaseUnicodeChar(*Cp);
            }
            ++Cp;
        }
    }

    //
    // Create a new kcb, which we will free if one already exists
    // for this key.
    // Now it is a fixed size structure.
    //
    kcb = ExAllocatePoolWithTag(PagedPool,
                                sizeof(CM_KEY_CONTROL_BLOCK),
                                CM_KCB_TAG | PROTECTED_POOL);


    if (kcb == NULL) {
        return(NULL);
    } else {
        SET_KCB_SIGNATURE(kcb, KCB_SIGNATURE);
        INIT_KCB_KEYBODY_LIST(kcb);
        kcb->Delete = FALSE;
        kcb->RefCount = 1;
        kcb->KeyHive = Hive;
        kcb->KeyCell = Cell;
        kcb->KeyNode = Node;
        kcb->ConvKey = ConvKey;

    }

    ASSERT_KCB(kcb);
    //
    // Find location to insert kcb in kcb tree.
    //


    LOCK_KCB_TREE();

    //
    // Add the KCB to the hash table
    //
    kcbmatch = CmpInsertKeyHash(&kcb->KeyHash, FakeKey);
    if (kcbmatch != NULL) {
        //
        // A match was found.
        //
        ASSERT(!kcbmatch->Delete);
        SET_KCB_SIGNATURE(kcb, '1FmC');
        ASSERT_KEYBODY_LIST_EMPTY(kcb);
        ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
        ASSERT_KCB(kcbmatch);
        kcb = kcbmatch;
        if (kcb->RefCount == 0) {
            //
            // This kcb is on the delayed close list. Remove it from that
            // list.
            //
            CmpRemoveFromDelayedClose(kcb);
        }
        if ((USHORT)(kcb->RefCount + 1) == 0) {
            //
            // We have maxed out the ref count on this key. Probably
            // some bogus app has opened the same key 64K times without
            // ever closing it. Just fail the open, they've got enough
            // handles already.
            //
            ASSERT(kcb->RefCount + 1 != 0);
            kcb = NULL;
        } else {
            ++kcb->RefCount;
        }
    }
    else {
        //
        // No kcb created previously, fill in all the data.
        //

        //
        // Now try to reference the parentkcb
        //
        
        if (ParentKcb) {
            if (CmpReferenceKeyControlBlock(ParentKcb)) {
                kcb->ParentKcb = ParentKcb;
                kcb->TotalLevels = ParentKcb->TotalLevels + 1;
            } else {
                //
                // We have maxed out the ref count on the parent.
                // Since it has been cached in the cachetable,
                // remove it first before we free the allocation.
                //
                CmpRemoveKeyControlBlock(kcb);
                SET_KCB_SIGNATURE(kcb, '2FmC');
                ASSERT_KEYBODY_LIST_EMPTY(kcb);
                ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
                kcb = NULL;
            }
        } else {
            //
            // It is the \REGISTRY node.
            //
            kcb->ParentKcb = NULL;
            kcb->TotalLevels = 1;
        }

        if (kcb) {
            //
            // Now try to find the Name Control block that has the name for this node.
            //
    
            kcb->NameBlock = CmpGetNameControlBlock (&NodeName);

            if (kcb->NameBlock) {
                //
                // Now fill in all the data needed for the cache.
                //
                kcb->ValueCache.Count = Node->ValueList.Count;
                kcb->ValueCache.ValueList = (ULONG_PTR) Node->ValueList.List;
        
                kcb->Flags = Node->Flags;
                kcb->ExtFlags = 0;
                kcb->DelayedCloseIndex = 0;
        
                //
                // Cache the security cells in the kcb
                //
                kcb->Security = Node->Security;
        
                if (FakeKey) {
                    //
                    // The KCb to be created is a fake one
                    //
                    kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST;
                }
            } else {
                //
                // We have maxed out the ref count on the Name.
                //
                
                //
                // First dereference the parent KCB.
                //
                CmpDereferenceKeyControlBlockWithLock(ParentKcb);

                CmpRemoveKeyControlBlock(kcb);
                SET_KCB_SIGNATURE(kcb, '3FmC');
                ASSERT_KEYBODY_LIST_EMPTY(kcb);
                ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
                kcb = NULL;
            }
        }
    }


    UNLOCK_KCB_TREE();
    return kcb;
}
Exemple #3
0
VOID
CmpCleanUpKcbCacheWithLock(
    PCM_KEY_CONTROL_BLOCK   KeyControlBlock
    )
/*++

Routine Description:

    Clean up all cached allocations that are associated to this key.
    If the parent is still open just because of this one, Remove the parent as well.

Arguments:

    KeyControlBlock - pointer to a key control block.

Return Value:

    NONE.

--*/
{
    PCM_KEY_CONTROL_BLOCK   Kcb;
    PCM_KEY_CONTROL_BLOCK   ParentKcb;

    Kcb = KeyControlBlock;

    ASSERT(KeyControlBlock->RefCount == 0);

    while (Kcb->RefCount == 0) {
        //
        // First, free allocations for Value/data.
        //
    
        CmpCleanUpKcbValueCache(Kcb);
    
        //
        // Free the kcb and dereference parentkcb and nameblock.
        //
    
        CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock);
    
        if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) {
            //
            // Now free the HintIndex allocation
            //
            ExFreePoolWithTag(Kcb->IndexHint, CM_CACHE_INDEX_TAG | PROTECTED_POOL);
        }

        //
        // Save the ParentKcb before we free the Kcb
        //
        ParentKcb = Kcb->ParentKcb;
        
        //
        // We cannot call CmpDereferenceKeyControlBlockWithLock so we can avoid recurrsion.
        //
        
        if (!Kcb->Delete) {
            CmpRemoveKeyControlBlock(Kcb);
        }
        SET_KCB_SIGNATURE(Kcb, '4FmC');
        ASSERT_KEYBODY_LIST_EMPTY(Kcb);
        ExFreePoolWithTag(Kcb, CM_KCB_TAG | PROTECTED_POOL);

        Kcb = ParentKcb;
        Kcb->RefCount--;
    }
}
Exemple #4
0
ULONG
CmpSearchForOpenSubKeys(
    PCM_KEY_CONTROL_BLOCK   KeyControlBlock,
    SUBKEY_SEARCH_TYPE      SearchType
    )
/*++
Routine Description:

    This routine searches the KCB tree for any open handles to keys that
    are subkeys of the given key.

    It is used by CmRestoreKey to verify that the tree being restored to
    has no open handles.

Arguments:

    KeyControlBlock - Supplies the key control block for the key for which
        open subkeys are to be found.

    SearchType - the type of the search
        SearchIfExist - exits at the first open subkey found ==> returns 1 if any subkey is open
        
        SearchAndDeref - Forces the keys underneath the Key referenced KeyControlBlock to 
                be marked as not referenced (see the REG_FORCE_RESTORE flag in CmRestoreKey) 
                returns 1 if at least one deref was made
        
        SearchAndCount - Counts all open subkeys - returns the number of them

Return Value:

    TRUE  - open handles to subkeys of the given key exist

    FALSE - open handles to subkeys of the given key do not exist.
--*/
{
    ULONG i;
    PCM_KEY_HASH *Current;
    PCM_KEY_CONTROL_BLOCK kcb;
    PCM_KEY_CONTROL_BLOCK Realkcb;
    PCM_KEY_CONTROL_BLOCK Parent;
    USHORT LevelDiff, l;
    ULONG   Count = 0;
    
    //
    // Registry lock should be held exclusively, so no need to KCB lock
    //
    ASSERT_CM_LOCK_OWNED_EXCLUSIVE();


    //
    // First, clean up all subkeys in the cache
    //
    for (i=0; i<CmpHashTableSize; i++) {
        Current = &CmpCacheTable[i];
        while (*Current) {
            kcb = CONTAINING_RECORD(*Current, CM_KEY_CONTROL_BLOCK, KeyHash);
            if (kcb->RefCount == 0) {
                //
                // This kcb is in DelayClose case, remove it.
                //
                CmpRemoveFromDelayedClose(kcb);
                CmpCleanUpKcbCacheWithLock(kcb);

                //
                // The HashTable is changed, start over in this index again.
                //
                Current = &CmpCacheTable[i];
                continue;
            }
            Current = &kcb->NextHash;
        }
    }

    if (KeyControlBlock->RefCount == 1) {
        //
        // There is only one open handle, so there must be no open subkeys.
        //
        Count = 0;
    } else {
        //
        // Now search for an open subkey handle.
        //
        Count = 0;

     
#ifdef KCB_TO_KEYBODY_LINK
        //
        // dump the root first if we were asked to do so.
        //
        if(SearchType == SearchAndCount) {
            CmpDumpKeyBodyList(KeyControlBlock,&Count);
        }
#endif
        for (i=0; i<CmpHashTableSize; i++) {

StartDeref:
            Current = &CmpCacheTable[i];
            while (*Current) {
                kcb = CONTAINING_RECORD(*Current, CM_KEY_CONTROL_BLOCK, KeyHash);
                if (kcb->TotalLevels > KeyControlBlock->TotalLevels) {
                    LevelDiff = kcb->TotalLevels - KeyControlBlock->TotalLevels;
                
                    Parent = kcb;
                    for (l=0; l<LevelDiff; l++) {
                        Parent = Parent->ParentKcb;
                    }
    
                    if (Parent == KeyControlBlock) {
                        //
                        // Found a match;
                        //
                        if( SearchType == SearchIfExist ) {
                            Count = 1;
                            break;
                        } else if(SearchType == SearchAndDeref) {
                            //
                            // Mark the key as deleted, remove it from cache, but don't add it
                            // to the Delay Close table (we want the key to be visible only to
                            // the one(s) that have open handles on it.
                            //

                            ASSERT_CM_LOCK_OWNED_EXCLUSIVE();

                            //
                            // flush any pending notifies as the kcb won't be around any longer
                            //
#ifdef KCB_TO_KEYBODY_LINK
                            CmpFlushNotifiesOnKeyBodyList(kcb);
#endif
                            
                            CmpCleanUpSubKeyInfo(kcb->ParentKcb);
                            kcb->Delete = TRUE;
                            CmpRemoveKeyControlBlock(kcb);
                            kcb->KeyCell = HCELL_NIL;
                            kcb->KeyNode = NULL;
                            Count++;
                         
                            //
                            // Restart the search 
                            // 
                            goto StartDeref;
                        
                        } else if(SearchType == SearchAndCount) {
                            //
                            // here do the dumping and count incrementing stuff
                            //
                        #ifdef KCB_TO_KEYBODY_LINK
                            CmpDumpKeyBodyList(kcb,&Count);
                        #else
                            Count++;
                        #endif
                        }
                    }   

                }
                Current = &kcb->NextHash;
            }
        }
    }
    
                           
    return Count;
}
Exemple #5
0
PCM_KEY_CONTROL_BLOCK
NTAPI
CmpCreateKeyControlBlock(IN PHHIVE Hive,
                         IN HCELL_INDEX Index,
                         IN PCM_KEY_NODE Node,
                         IN PCM_KEY_CONTROL_BLOCK Parent,
                         IN ULONG Flags,
                         IN PUNICODE_STRING KeyName)
{
    PCM_KEY_CONTROL_BLOCK Kcb, FoundKcb = NULL;
    UNICODE_STRING NodeName;
    ULONG ConvKey = 0, i;
    BOOLEAN IsFake, HashLock;
    PWCHAR p;

    /* Make sure we own this hive in case it's being unloaded */
    if ((Hive->HiveFlags & HIVE_IS_UNLOADING) &&
            (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread()))
    {
        /* Fail */
        return NULL;
    }

    /* Check if this is a fake KCB */
    IsFake = Flags & CMP_CREATE_FAKE_KCB ? TRUE : FALSE;

    /* If we have a parent, use its ConvKey */
    if (Parent) ConvKey = Parent->ConvKey;

    /* Make a copy of the name */
    NodeName = *KeyName;

    /* Remove leading slash */
    while ((NodeName.Length) && (*NodeName.Buffer == OBJ_NAME_PATH_SEPARATOR))
    {
        /* Move the buffer by one */
        NodeName.Buffer++;
        NodeName.Length -= sizeof(WCHAR);
    }

    /* Make sure we didn't get just a slash or something */
    ASSERT(NodeName.Length > 0);

    /* Now setup the hash */
    p = NodeName.Buffer;
    for (i = 0; i < NodeName.Length; i += sizeof(WCHAR))
    {
        /* Make sure it's a valid character */
        if (*p != OBJ_NAME_PATH_SEPARATOR)
        {
            /* Add this key to the hash */
            ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p);
        }

        /* Move on */
        p++;
    }

    /* Allocate the KCB */
    Kcb = CmpAllocateKeyControlBlock();
    if (!Kcb) return NULL;

    /* Initailize the key list */
    InitializeKCBKeyBodyList(Kcb);

    /* Set it up */
    Kcb->Signature = CM_KCB_SIGNATURE;
    Kcb->Delete = FALSE;
    Kcb->RefCount = 1;
    Kcb->KeyHive = Hive;
    Kcb->KeyCell = Index;
    Kcb->ConvKey = ConvKey;
    Kcb->DelayedCloseIndex = CmpDelayedCloseSize;
    Kcb->InDelayClose = 0;
    ASSERT_KCB_VALID(Kcb);

    /* Check if we have two hash entires */
    HashLock = Flags & CMP_LOCK_HASHES_FOR_KCB ? TRUE : FALSE;
    if (!HashLock)
    {
        /* It's not locked, do we have a parent? */
        if (Parent)
        {
            /* Lock the parent KCB and ourselves */
            CmpAcquireTwoKcbLocksExclusiveByKey(ConvKey, Parent->ConvKey);
        }
        else
        {
            /* Lock only ourselves */
            CmpAcquireKcbLockExclusive(Kcb);
        }
    }

    /* Check if we already have a KCB */
    FoundKcb = CmpInsertKeyHash(&Kcb->KeyHash, IsFake);
    if (FoundKcb)
    {
        /* Sanity check */
        ASSERT(!FoundKcb->Delete);
        Kcb->Signature = CM_KCB_INVALID_SIGNATURE;

        /* Free the one we allocated and reference this one */
        CmpFreeKeyControlBlock(Kcb);
        ASSERT_KCB_VALID(FoundKcb);
        Kcb = FoundKcb;
        if (!CmpReferenceKeyControlBlock(Kcb))
        {
            /* We got too many handles */
            ASSERT(Kcb->RefCount + 1 != 0);
            Kcb = NULL;
        }
        else
        {
            /* Check if we're not creating a fake one, but it used to be fake */
            if ((Kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) && !(IsFake))
            {
                /* Set the hive and cell */
                Kcb->KeyHive = Hive;
                Kcb->KeyCell = Index;

                /* This means that our current information is invalid */
                Kcb->ExtFlags = CM_KCB_INVALID_CACHED_INFO;
            }

            /* Check if we didn't have any valid data */
            if (!(Kcb->ExtFlags & (CM_KCB_NO_SUBKEY |
                                   CM_KCB_SUBKEY_ONE |
                                   CM_KCB_SUBKEY_HINT)))
            {
                /* Calculate the index hint */
                Kcb->SubKeyCount = Node->SubKeyCounts[Stable] +
                                   Node->SubKeyCounts[Volatile];

                /* Cached information is now valid */
                Kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
            }

            /* Setup the other data */
            Kcb->KcbLastWriteTime = Node->LastWriteTime;
            Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
            Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
            Kcb->KcbMaxValueDataLen = Node->MaxValueDataLen;
        }
    }
    else
    {
        /* No KCB, do we have a parent? */
        if (Parent)
        {
            /* Reference the parent */
            if (((Parent->TotalLevels + 1) < 512) &&
                    (CmpReferenceKeyControlBlock(Parent)))
            {
                /* Link it */
                Kcb->ParentKcb = Parent;
                Kcb->TotalLevels = Parent->TotalLevels + 1;
            }
            else
            {
                /* Remove the KCB and free it */
                CmpRemoveKeyControlBlock(Kcb);
                Kcb->Signature = CM_KCB_INVALID_SIGNATURE;
                CmpFreeKeyControlBlock(Kcb);
                Kcb = NULL;
            }
        }
        else
        {
            /* No parent, this is the root node */
            Kcb->ParentKcb = NULL;
            Kcb->TotalLevels = 1;
        }

        /* Check if we have a KCB */
        if (Kcb)
        {
            /* Get the NCB */
            Kcb->NameBlock = CmpGetNameControlBlock(&NodeName);
            if (Kcb->NameBlock)
            {
                /* Fill it out */
                Kcb->ValueCache.Count = Node->ValueList.Count;
                Kcb->ValueCache.ValueList = Node->ValueList.List;
                Kcb->Flags = Node->Flags;
                Kcb->ExtFlags = 0;
                Kcb->DelayedCloseIndex = CmpDelayedCloseSize;

                /* Remember if this is a fake key */
                if (IsFake) Kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST;

                /* Setup the other data */
                Kcb->SubKeyCount = Node->SubKeyCounts[Stable] +
                                   Node->SubKeyCounts[Volatile];
                Kcb->KcbLastWriteTime = Node->LastWriteTime;
                Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
                Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
                Kcb->KcbMaxValueDataLen = (USHORT)Node->MaxValueDataLen;
            }
            else
            {
                /* Dereference the KCB */
                CmpDereferenceKeyControlBlockWithLock(Parent, FALSE);

                /* Remove the KCB and free it */
                CmpRemoveKeyControlBlock(Kcb);
                Kcb->Signature = CM_KCB_INVALID_SIGNATURE;
                CmpFreeKeyControlBlock(Kcb);
                Kcb = NULL;
            }
        }
    }

    /* Check if this is a KCB inside a frozen hive */
    if ((Kcb) && (((PCMHIVE)Hive)->Frozen) && (!(Kcb->Flags & KEY_SYM_LINK)))
    {
        /* Don't add these to the delay close */
        Kcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE;
    }

    /* Sanity check */
    ASSERT((!Kcb) || (Kcb->Delete == FALSE));

    /* Check if we had locked the hashes */
    if (!HashLock)
    {
        /* We locked them manually, do we have a parent? */
        if (Parent)
        {
            /* Unlock the parent KCB and ourselves */
            CmpReleaseTwoKcbLockByKey(ConvKey, Parent->ConvKey);
        }
        else
        {
            /* Unlock only ourselves */
            CmpReleaseKcbLockByKey(ConvKey);
        }
    }

    /* Return the KCB */
    return Kcb;
}