Esempio n. 1
0
PCM_NAME_CONTROL_BLOCK
CmpGetNameControlBlock(
    PUNICODE_STRING NodeName
    )
{
    PCM_NAME_CONTROL_BLOCK   Ncb;
    ULONG  Cnt;
    WCHAR *Cp;
    WCHAR *Cp2;
    ULONG Index;
    ULONG i;
    ULONG      Size;
    PCM_NAME_HASH CurrentName;
    ULONG rc;
    BOOLEAN NameFound = FALSE;
    USHORT NameSize;
    BOOLEAN NameCompressed;
    ULONG NameConvKey=0;
    LONG Result;

    //
    // Calculate the ConvKey for this NadeName;
    //

    Cp = NodeName->Buffer;
    for (Cnt=0; Cnt<NodeName->Length; Cnt += sizeof(WCHAR)) {
        if (*Cp != OBJ_NAME_PATH_SEPARATOR) {
            NameConvKey = 37 * NameConvKey + (ULONG) RtlUpcaseUnicodeChar(*Cp);
        }
        ++Cp;
    }

    //
    // Find the Name Size;
    // 
    NameCompressed = TRUE;
    NameSize = NodeName->Length / sizeof(WCHAR);
    for (i=0;i<NodeName->Length/sizeof(WCHAR);i++) {
        if ((USHORT)NodeName->Buffer[i] > (UCHAR)-1) {
            NameSize = NodeName->Length;
            NameCompressed = FALSE;
        }
    }

    Index = GET_HASH_INDEX(NameConvKey);
    CurrentName = CmpNameCacheTable[Index];

    while (CurrentName) {
        Ncb =  CONTAINING_RECORD(CurrentName, CM_NAME_CONTROL_BLOCK, NameHash);

        if ((NameConvKey == CurrentName->ConvKey) &&
            (NameSize == Ncb->NameLength)) {
            //
            // Hash value matches, compare the names.
            //
            NameFound = TRUE;
            if (Ncb->Compressed) {
                if (CmpCompareCompressedName(NodeName, Ncb->Name, NameSize)) {
                    NameFound = FALSE;
                }
            } else {
                Cp = (WCHAR *) NodeName->Buffer;
                Cp2 = (WCHAR *) Ncb->Name;
                for (i=0 ;i<Ncb->NameLength; i+= sizeof(WCHAR)) {
                    if (RtlUpcaseUnicodeChar(*Cp) != RtlUpcaseUnicodeChar(*Cp2)) {
                        NameFound = FALSE;
                        break;
                    }
                    ++Cp;
                    ++Cp2;
                }
            }
            if (NameFound) {
                //
                // Found it, increase the refcount.
                //
                if ((USHORT) (Ncb->RefCount + 1) == 0) {
                    //
                    // We have maxed out the ref count.
                    // fail the call.
                    //
                    Ncb = NULL;
                } else {
                    ++Ncb->RefCount;
                }
                break;
            }
        }
        CurrentName = CurrentName->NextHash;
    }
    
    if (NameFound == FALSE) {
        //
        // Now need to create one Name block for this string.
        //
        Size = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + NameSize;
 
        Ncb = ExAllocatePoolWithTag(PagedPool,
                                    Size,
                                    CM_NAME_TAG | PROTECTED_POOL);
 
        if (Ncb == NULL) {
            return(NULL);
        }
        RtlZeroMemory(Ncb, Size);
 
        //
        // Update all the info for this newly created Name block.
        //
        if (NameCompressed) {
            Ncb->Compressed = TRUE;
            for (i=0;i<NameSize;i++) {
                ((PUCHAR)Ncb->Name)[i] = (UCHAR)(NodeName->Buffer[i]);
            }
        } else {
            Ncb->Compressed = FALSE;
            RtlCopyMemory((PVOID)(Ncb->Name), (PVOID)(NodeName->Buffer), NameSize);
        }

        Ncb->ConvKey = NameConvKey;
        Ncb->RefCount = 1;
        Ncb->NameLength = NameSize;
        
        CurrentName = &(Ncb->NameHash);
        //
        // Insert into Name Hash table.
        //
        CurrentName->NextHash = CmpNameCacheTable[Index];
        CmpNameCacheTable[Index] = CurrentName;
    }

    return(Ncb);
}
Esempio n. 2
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;
}
Esempio n. 3
0
PCM_NAME_CONTROL_BLOCK
NTAPI
CmpGetNameControlBlock(IN PUNICODE_STRING NodeName)
{
    PCM_NAME_CONTROL_BLOCK Ncb = NULL;
    ULONG ConvKey = 0;
    PWCHAR p, pp;
    ULONG i;
    BOOLEAN IsCompressed = TRUE, Found = FALSE;
    PCM_NAME_HASH HashEntry;
    ULONG Length, NcbSize;

    /* Loop the name */
    p = NodeName->Buffer;
    for (i = 0; i < NodeName->Length; i += sizeof(WCHAR))
    {
        /* Make sure it's not a slash */
        if (*p != OBJ_NAME_PATH_SEPARATOR)
        {
            /* Add it to the hash */
            ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p);
        }

        /* Next character */
        p++;
    }

    /* Set assumed lengh and loop to check */
    Length = NodeName->Length / sizeof(WCHAR);
    for (i = 0; i < (NodeName->Length / sizeof(WCHAR)); i++)
    {
        /* Check if this is a 16-bit character */
        if (NodeName->Buffer[i] > (UCHAR)-1)
        {
            /* This is the actual size, and we know we're not compressed */
            Length = NodeName->Length;
            IsCompressed = FALSE;
            break;
        }
    }

    /* Lock the NCB entry */
    CmpAcquireNcbLockExclusiveByKey(ConvKey);

    /* Get the hash entry */
    HashEntry = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry;
    while (HashEntry)
    {
        /* Get the current NCB */
        Ncb = CONTAINING_RECORD(HashEntry, CM_NAME_CONTROL_BLOCK, NameHash);

        /* Check if the hash matches */
        if ((ConvKey == HashEntry->ConvKey) && (Length == Ncb->NameLength))
        {
            /* Assume success */
            Found = TRUE;

            /* If the NCB is compressed, do a compressed name compare */
            if (Ncb->Compressed)
            {
                /* Compare names */
                if (CmpCompareCompressedName(NodeName, Ncb->Name, Length))
                {
                    /* We failed */
                    Found = FALSE;
                }
            }
            else
            {
                /* Do a manual compare */
                p = NodeName->Buffer;
                pp = Ncb->Name;
                for (i = 0; i < Ncb->NameLength; i += sizeof(WCHAR))
                {
                    /* Compare the character */
                    if (RtlUpcaseUnicodeChar(*p) != RtlUpcaseUnicodeChar(*pp))
                    {
                        /* Failed */
                        Found = FALSE;
                        break;
                    }

                    /* Next chars */
                    p++;
                    pp++;
                }
            }

            /* Check if we found a name */
            if (Found)
            {
                /* Reference it */
                ASSERT(Ncb->RefCount != 0xFFFF);
                Ncb->RefCount++;
                break;
            }
        }

        /* Go to the next hash */
        HashEntry = HashEntry->NextHash;
    }

    /* Check if we didn't find it */
    if (!Found)
    {
        /* Allocate one */
        NcbSize = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + Length;
        Ncb = CmpAllocate(NcbSize, TRUE, TAG_CM);
        if (!Ncb)
        {
            /* Release the lock and fail */
            CmpReleaseNcbLockByKey(ConvKey);
            return NULL;
        }

        /* Clear it out */
        RtlZeroMemory(Ncb, NcbSize);

        /* Check if the name was compressed */
        if (IsCompressed)
        {
            /* Copy the compressed name */
            for (i = 0; i < NodeName->Length / sizeof(WCHAR); i++)
            {
                /* Copy Unicode to ANSI */
                ((PCHAR)Ncb->Name)[i] = (CHAR)RtlUpcaseUnicodeChar(NodeName->Buffer[i]);
            }
        }
        else
        {
            /* Copy the name directly */
            for (i = 0; i < NodeName->Length / sizeof(WCHAR); i++)
            {
                /* Copy each unicode character */
                Ncb->Name[i] = RtlUpcaseUnicodeChar(NodeName->Buffer[i]);
            }
        }

        /* Setup the rest of the NCB */
        Ncb->Compressed = IsCompressed;
        Ncb->ConvKey = ConvKey;
        Ncb->RefCount++;
        Ncb->NameLength = Length;

        /* Insert the name in the hash table */
        HashEntry = &Ncb->NameHash;
        HashEntry->NextHash = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry;
        GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry = HashEntry;
    }

    /* Release NCB lock */
    CmpReleaseNcbLockByKey(ConvKey);

    /* Return the NCB found */
    return Ncb;
}
Esempio n. 4
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;
}
Esempio n. 5
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)