コード例 #1
0
ファイル: cmsubs.c プロジェクト: chunhualiu/OpenNT
VOID
CmpRemoveKeyControlBlock(
    PCM_KEY_CONTROL_BLOCK   KeyControlBlock
    )
/*++

Routine Description:

    Remove a key control block from the KCB tree.

    It is expected that no notify control blocks remain.

    The kcb will NOT be freed, call DereferenceKeyControlBlock for that.

    This call assumes the KCB tree is already locked or registry is locked exclusively.

Arguments:

    KeyControlBlock - pointer to a key control block.

Return Value:

    NONE.

--*/
{
    ASSERT_KCB(KeyControlBlock);

    //
    // Remove the KCB from the hash table
    //
    CmpRemoveKeyHash(&KeyControlBlock->KeyHash);

    return;
}
コード例 #2
0
ファイル: cmsubs.c プロジェクト: chunhualiu/OpenNT
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;
}
コード例 #3
0
ファイル: cmsubs.c プロジェクト: chunhualiu/OpenNT
VOID
CmpSearchKeyControlBlockTree(
    PKCB_WORKER_ROUTINE WorkerRoutine,
    PVOID               Context1,
    PVOID               Context2
    )
/*++

Routine Description:

    Traverse the kcb tree.  We will visit all nodes unless WorkerRoutine
    tells us to stop part way through.

    For each node, call WorkerRoutine(..., Context1, Contex2).  If it returns
    KCB_WORKER_DONE, we are done, simply return.  If it returns
    KCB_WORKER_CONTINUE, just continue the search. If it returns KCB_WORKER_DELETE,
    the specified KCB is marked as deleted.

    This routine has the side-effect of removing all delayed-close KCBs.

Arguments:

    WorkerRoutine - applied to nodes witch Match.

    Context1 - data we pass through

    Context2 - data we pass through


Return Value:

    NONE.

--*/
{
    PCM_KEY_CONTROL_BLOCK   Current;
    PCM_KEY_CONTROL_BLOCK   Next;
    PCM_KEY_HASH *Prev;
    ULONG                   WorkerResult;
    ULONG                   i;

    //
    // Walk the hash table
    //
    for (i=0; i<CmpHashTableSize; i++) {
        Prev = &CmpCacheTable[i];
        while (*Prev) {
            Current = CONTAINING_RECORD(*Prev,
                                        CM_KEY_CONTROL_BLOCK,
                                        KeyHash);
            ASSERT_KCB(Current);
            ASSERT(!Current->Delete);
            if (Current->RefCount == 0) {
                //
                // This kcb is in DelayClose case, remove it.
                //
                CmpRemoveFromDelayedClose(Current);
                CmpCleanUpKcbCacheWithLock(Current);

                //
                // The HashTable is changed, start over in this index again.
                //
                Prev = &CmpCacheTable[i];
                continue;
            }

            WorkerResult = (WorkerRoutine)(Current, Context1, Context2);
            if (WorkerResult == KCB_WORKER_DONE) {
                return;
            } else if (WorkerResult == KCB_WORKER_DELETE) {
                ASSERT(Current->Delete);
                *Prev = Current->NextHash;
                continue;
            } else {
                ASSERT(WorkerResult == KCB_WORKER_CONTINUE);
                Prev = &Current->NextHash;
            }
        }
    }
}
コード例 #4
0
ファイル: cmsubs.c プロジェクト: chunhualiu/OpenNT
VOID
CmpDereferenceKeyControlBlockWithLock(
    PCM_KEY_CONTROL_BLOCK   KeyControlBlock
    )
{
    ULONG_PTR FreeIndex;
    PCM_KEY_CONTROL_BLOCK KcbToFree;



    ASSERT_KCB(KeyControlBlock);

    if (--KeyControlBlock->RefCount == 0) {
        //
        // Remove kcb from the tree
        //
        if (KeyControlBlock->ExtFlags & CM_KCB_NO_DELAY_CLOSE) {
            //
            // Free storage directly so we can clean up junk quickly.
            //
            //
            // Need to free all cached Index List, Index Leaf, Value, etc.
            //
            CmpCleanUpKcbCacheWithLock(KeyControlBlock);
        } else if (!KeyControlBlock->Delete) {

            //
            // Put this kcb on our delayed close list.
            //
            // First check the free list for a free slot.
            //
            FreeIndex = CmpDelayedFreeIndex;
            if (FreeIndex != -1) {
                ASSERT(FreeIndex < CmpDelayedCloseSize);
                CmpDelayedFreeIndex = (ULONG_PTR)CmpDelayedCloseTable[FreeIndex];
                KeyControlBlock->DelayedCloseIndex = (USHORT) FreeIndex;
                ASSERT((CmpDelayedFreeIndex == -1) ||
                       (CmpDelayedFreeIndex < CmpDelayedCloseSize));
                CmpDelayedCloseTable[FreeIndex] = KeyControlBlock;
            } else {

                //
                // Nothing is free, we have to get rid of something.
                //
                ASSERT(*CmpDelayedCloseCurrent != NULL);
                ASSERT(!(*CmpDelayedCloseCurrent)->Delete);
                //
                // Need to free all cached Index List, Index Leaf, Value, etc.
                // Change the code sequence for the recurrsive call to dereference the parent.
                //
                KcbToFree = *CmpDelayedCloseCurrent;
                *CmpDelayedCloseCurrent = KeyControlBlock;
                KeyControlBlock->DelayedCloseIndex = (USHORT)(CmpDelayedCloseCurrent - CmpDelayedCloseTable);
                ++CmpDelayedCloseCurrent;
                if ((ULONG)(CmpDelayedCloseCurrent - CmpDelayedCloseTable) == CmpDelayedCloseSize) {
                    CmpDelayedCloseCurrent = CmpDelayedCloseTable;
                }

                CmpCleanUpKcbCacheWithLock(KcbToFree);
            }
        } else {
            //
            // Free storage directly as there is no point in putting this on
            // our delayed close list.
            //
            //
            // Need to free all cached Index List, Index Leaf, Value, etc.
            //
            CmpCleanUpKcbCacheWithLock(KeyControlBlock);
        }
    }

    return;
}
コード例 #5
0
ファイル: cmdelete.c プロジェクト: BaoYu0721/WRK-1.2
VOID
CmpLateUnloadHiveWorker(
    IN PVOID Hive
    )
/*++

Routine Description:

    "Late" unloads the hive; If nothing goes badly wrong (i.e. insufficient resources),
    this function should succeed

Arguments:

    CmHive - the frozen hive to be unloaded

Return Value:

    NONE.

--*/
{
    NTSTATUS                Status;
    HCELL_INDEX             Cell;
    PCM_KEY_CONTROL_BLOCK   RootKcb;
    PCMHIVE                 CmHive;

    CM_PAGED_CODE();

    //
    // first, load the registry exclusive
    //
    CmpLockRegistryExclusive();

    //
    // hive is the parameter to this worker; make sure we free the work item
    // allocated by CmpDeleteKeyObject
    //
    CmHive = (PCMHIVE)Hive;

    ASSERT( CmHive->UnloadWorkItem != NULL );
    ExFreePool( CmHive->UnloadWorkItem );

    //
    // if this attempt doesn't succeed, mark that we can try another
    //
    CmHive->UnloadWorkItem = NULL;

    ASSERT( !(CmHive->Hive.HiveFlags & HIVE_IS_UNLOADING) );
    if( CmHive->Frozen == FALSE )  {
        //
        // another thread mounted the exact same hive in the exact same place, hence unfreezing the hive
        // we've done the cleanup part (free the workitem) nothing more to do.
        // or hive is already in process of being unloaded
        //
        ASSERT( CmHive->RootKcb == NULL );
        CmpUnlockRegistry();
        return;
    }
    //
    // this is just about the only possible way the hive can get corrupted in between
    //
    if( HvShutdownComplete == TRUE ) {
        // too late to do anything
        CmpUnlockRegistry();
        return;
    }

    //
    // hive should be frozen, otherwise we wouldn't get here
    //
    ASSERT( CmHive->Frozen == TRUE );

    RootKcb = CmHive->RootKcb;
    //
    // root kcb must be valid and has only our "artificial" refcount on it
    //
    ASSERT( RootKcb != NULL );

    if( RootKcb->RefCount > 1 ) {
        //
        // somebody else must've gotten in between dropping/reacquiring the reglock
        // and opened a handle inside this hive; bad luck, we can't unload
        //
        CmpUnlockRegistry();
        return;
    }

    ASSERT_KCB(RootKcb);

    Cell = RootKcb->KeyCell;
    Status = CmUnloadKey(RootKcb,0,CM_UNLOAD_REG_LOCKED_EX);
    ASSERT( (Status != STATUS_CANNOT_DELETE) && (Status != STATUS_INVALID_PARAMETER) );

    if(NT_SUCCESS(Status)) {
        // CmUnloadKey already released the lock
        CmpLockRegistry();
        CmpDereferenceKeyControlBlock(RootKcb);
    } 
    CmpUnlockRegistry();
}