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; }
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); } }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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)
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; }
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; }
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; }
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; }