ReactOS 0.4.16-dev-329-g9223134
cmparse.c File Reference
#include "ntoskrnl.h"
#include "debug.h"
Include dependency graph for cmparse.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

BOOLEAN NTAPI CmpGetNextName (IN OUT PUNICODE_STRING RemainingName, OUT PUNICODE_STRING NextName, OUT PBOOLEAN LastName)
 
BOOLEAN NTAPI CmpGetSymbolicLink (IN PHHIVE Hive, IN OUT PUNICODE_STRING ObjectName, IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb, IN PUNICODE_STRING RemainingName OPTIONAL)
 
NTSTATUS NTAPI CmpDoCreateChild (IN PHHIVE Hive, IN HCELL_INDEX ParentCell, IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL, IN PACCESS_STATE AccessState, IN PUNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN PCM_PARSE_CONTEXT ParseContext, IN PCM_KEY_CONTROL_BLOCK ParentKcb, IN ULONG Flags, OUT PHCELL_INDEX KeyCell, OUT PVOID *Object)
 
NTSTATUS NTAPI CmpDoCreate (IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PACCESS_STATE AccessState, IN PUNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN PCM_PARSE_CONTEXT ParseContext, IN PCM_KEY_CONTROL_BLOCK ParentKcb, OUT PVOID *Object)
 
NTSTATUS NTAPI CmpDoOpen (IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PCM_KEY_NODE Node, IN PACCESS_STATE AccessState, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN PCM_PARSE_CONTEXT Context OPTIONAL, IN ULONG ControlFlags, IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb, IN PULONG KcbsLocked, IN PUNICODE_STRING KeyName, OUT PVOID *Object)
 
NTSTATUS NTAPI CmpCreateLinkNode (IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PACCESS_STATE AccessState, IN UNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN ULONG CreateOptions, IN PCM_PARSE_CONTEXT Context, IN PCM_KEY_CONTROL_BLOCK ParentKcb, IN PULONG KcbsLocked, OUT PVOID *Object)
 
VOID NTAPI CmpHandleExitNode (IN OUT PHHIVE *Hive, IN OUT HCELL_INDEX *Cell, IN OUT PCM_KEY_NODE *KeyNode, IN OUT PHHIVE *ReleaseHive, IN OUT HCELL_INDEX *ReleaseCell)
 
static ULONG CmpComputeHashValue (_In_ PUNICODE_STRING RemainingName, _In_ ULONG ConvKey, _Inout_ PCM_HASH_CACHE_STACK HashCacheStack, _Out_ PULONG TotalSubKeys)
 Computes the hashes of each subkey in key path name and stores them in a hash stack for cache lookup.
 
static BOOLEAN CmpCompareSubkeys (_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ PCM_KEY_CONTROL_BLOCK CurrentKcb, _In_ ULONG RemainingSubkeys, _Out_ PCM_KEY_CONTROL_BLOCK *ParentKcb)
 Compares each subkey's hash and name with those captured in the hash cache stack.
 
static VOID CmpRemoveSubkeysInRemainingName (_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ ULONG RemainingSubkeys, _Inout_ PUNICODE_STRING RemainingName)
 Removes the subkeys on a remaining key pathname.
 
static NTSTATUS CmpLookInCache (_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ BOOLEAN LockKcbsExclusive, _In_ ULONG TotalRemainingSubkeys, _Inout_ PUNICODE_STRING RemainingName, _Inout_ PULONG OuterStackArray, _Inout_ PCM_KEY_CONTROL_BLOCK *Kcb, _Out_ PHHIVE *Hive, _Out_ PHCELL_INDEX Cell, _Out_ PULONG MatchRemainSubkeyLevel)
 Looks up in the pool cache for key pathname that matches with one in the said cache and returns a KCB pointing to that name. This function performs locking of KCBs during cache lookup.
 
NTSTATUS NTAPI CmpBuildHashStackAndLookupCache (_In_ PCM_KEY_BODY ParseObject, _Inout_ PCM_KEY_CONTROL_BLOCK *Kcb, _In_ PUNICODE_STRING Current, _Out_ PHHIVE *Hive, _Out_ PHCELL_INDEX Cell, _Out_ PULONG TotalRemainingSubkeys, _Out_ PULONG MatchRemainSubkeyLevel, _Out_ PULONG TotalSubkeys, _Inout_ PULONG OuterStackArray, _Out_ PULONG *LockedKcbs)
 Builds a hash stack cache and looks up in the pool cache for a matching key pathname.
 
NTSTATUS NTAPI CmpParseKey (IN PVOID ParseObject, IN PVOID ObjectType, IN OUT PACCESS_STATE AccessState, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN OUT PUNICODE_STRING CompleteName, IN OUT PUNICODE_STRING RemainingName, IN OUT PVOID Context OPTIONAL, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, OUT PVOID *Object)
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file cmparse.c.

Function Documentation

◆ CmpBuildHashStackAndLookupCache()

NTSTATUS NTAPI CmpBuildHashStackAndLookupCache ( _In_ PCM_KEY_BODY  ParseObject,
_Inout_ PCM_KEY_CONTROL_BLOCK Kcb,
_In_ PUNICODE_STRING  Current,
_Out_ PHHIVE Hive,
_Out_ PHCELL_INDEX  Cell,
_Out_ PULONG  TotalRemainingSubkeys,
_Out_ PULONG  MatchRemainSubkeyLevel,
_Out_ PULONG  TotalSubkeys,
_Inout_ PULONG  OuterStackArray,
_Out_ PULONG LockedKcbs 
)

Builds a hash stack cache and looks up in the pool cache for a matching key pathname.

Parameters
[in]ParseObjectA pointer to a parse object, acting as a key body. This parameter is unused.
[in,out]KcbA pointer to a KCB. This KCB is used by the registry parser after hash stack and cache lookup are done. This KCB might change if the key is found to be cached in the cache pool.
[in]CurrentThe current remaining key pathname.
[out]HiveA pointer to a registry hive, returned by the caller.
[out]CellA pointer to a hive cell, returned by the caller.
[out]TotalRemainingSubkeysA pointer to a number of total remaining subkey levels, returned by the caller. This can be 0 if no subkey levels have been found.
[out]MatchRemainSubkeyLevelA pointer to a number of remaining subkey levels that match, returned by the caller. This can be 0 if no matching levels are found.
[out]TotalSubkeysA pointer to a number of total subkeys. This can be 0 if no subkey levels are found. By definition, both MatchRemainSubkeyLevel and TotalRemainingSubkeys are 0 as well.
[in,out]OuterStackArrayA pointer to an array that lives on the caller's stack. The expected size of the array is up to 32 elements, which is the imposed limit by CMP_HASH_STACK_LIMIT. This limit also corresponds to the maximum depth of subkey levels.
[out]LockedKcbsA pointer to an array of locked KCBs, returned by the caller.
Returns
Returns STATUS_SUCCESS if all the operations have succeeded without problems. STATUS_NAME_TOO_LONG is returned if the key pathname has too many subkey levels (more than 32 levels deep). A failure NTSTATUS code is returned otherwise. Refer to CmpLookInCache documentation for more information about other returned status codes. STATUS_UNSUCCESSFUL is returned if a KCB is referenced too many times.

Definition at line 1696 of file cmparse.c.

1707{
1709 ULONG ConvKey;
1710 ULONG SubkeysInTotal, RemainingSubkeysInTotal, MatchRemainingSubkeys;
1712
1713 /* Make sure it's not a dead KCB */
1714 ASSERT((*Kcb)->RefCount > 0);
1715
1716 /* Lock the registry */
1718
1719 /* Calculate hash values for every subkey this key path has */
1720 ConvKey = (*Kcb)->ConvKey;
1721 RemainingSubkeysInTotal = CmpComputeHashValue(Current,
1722 ConvKey,
1723 HashCacheStack,
1724 &SubkeysInTotal);
1725
1726 /* This key path has too many subkeys */
1727 if (SubkeysInTotal > CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1728 {
1729 DPRINT1("The key path has too many subkeys - %lu\n", SubkeysInTotal);
1730 *LockedKcbs = NULL;
1731 return STATUS_NAME_TOO_LONG;
1732 }
1733
1734 /* Return hive and cell data */
1735 *Hive = (*Kcb)->KeyHive;
1736 *Cell = (*Kcb)->KeyCell;
1737
1738 /* Do we have any subkeys? */
1739 if (!RemainingSubkeysInTotal && !SubkeysInTotal)
1740 {
1741 /*
1742 * We don't have any subkeys nor remaining levels, the
1743 * KCB points to the actual key. Lock it.
1744 */
1745 if (!CmpReferenceKeyControlBlock(*Kcb))
1746 {
1747 /* This key is opened too many times, bail out */
1748 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1749 return STATUS_UNSUCCESSFUL;
1750 }
1751
1753
1754 /* Add this KCB in the array of locked KCBs */
1755 OuterStackArray[0] = 1;
1756 OuterStackArray[1] = GET_HASH_INDEX(ConvKey);
1757 *LockedKcbs = OuterStackArray;
1758
1759 /* And return all the subkey level counters */
1760 *TotalRemainingSubkeys = RemainingSubkeysInTotal;
1761 *MatchRemainSubkeyLevel = 0;
1762 *TotalSubkeys = SubkeysInTotal;
1763 return STATUS_SUCCESS;
1764 }
1765
1766 /* Lookup in the cache */
1767 Status = CmpLookInCache(HashCacheStack,
1768 FALSE,
1769 RemainingSubkeysInTotal,
1770 Current,
1771 OuterStackArray,
1772 Kcb,
1773 Hive,
1774 Cell,
1775 &MatchRemainingSubkeys);
1776 if (!NT_SUCCESS(Status))
1777 {
1778 /* Bail out if cache lookup failed for other reasons */
1779 if (Status != STATUS_RETRY)
1780 {
1781 DPRINT1("CmpLookInCache() failed (Status 0x%lx)\n", Status);
1782 *LockedKcbs = NULL;
1783 return Status;
1784 }
1785
1786 /* Retry looking in the cache but with KCBs locked exclusively */
1787 Status = CmpLookInCache(HashCacheStack,
1788 TRUE,
1789 RemainingSubkeysInTotal,
1790 Current,
1791 OuterStackArray,
1792 Kcb,
1793 Hive,
1794 Cell,
1795 &MatchRemainingSubkeys);
1796 if (!NT_SUCCESS(Status))
1797 {
1798 DPRINT1("CmpLookInCache() failed after retry (Status 0x%lx)\n", Status);
1799 *LockedKcbs = NULL;
1800 return Status;
1801 }
1802 }
1803
1804 /*
1805 * Check if we have a full match of remaining levels.
1806 *
1807 * FIXME: It is possible we can catch a fake key from the cache
1808 * when we did the lookup, in such case we should not do any
1809 * locking as such KCB does not point to any real information.
1810 * Currently ReactOS doesn't create fake KCBs so we are good
1811 * for now.
1812 */
1813 if (RemainingSubkeysInTotal == MatchRemainingSubkeys)
1814 {
1815 /*
1816 * Just simply lock this KCB as it points to the full
1817 * subkey levels in cache.
1818 */
1820 OuterStackArray[0] = 1;
1821 OuterStackArray[1] = GET_HASH_INDEX((*Kcb)->ConvKey);
1822 *LockedKcbs = OuterStackArray;
1823 }
1824 else
1825 {
1826 /*
1827 * We only have a partial match so other subkey levels
1828 * have each KCB. Simply just lock them.
1829 */
1830 *LockedKcbs = CmpBuildAndLockKcbArray(HashCacheStack,
1832 *Kcb,
1833 OuterStackArray,
1834 RemainingSubkeysInTotal,
1835 MatchRemainingSubkeys);
1836 NT_ASSERT(*LockedKcbs);
1837 }
1838
1839 /* Return all the subkey level counters */
1840 *TotalRemainingSubkeys = RemainingSubkeysInTotal;
1841 *MatchRemainSubkeyLevel = MatchRemainingSubkeys;
1842 *TotalSubkeys = SubkeysInTotal;
1843 return Status;
1844}
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define CMP_SUBKEY_LEVELS_DEPTH_LIMIT
Definition: cm.h:131
#define CMP_LOCK_KCB_ARRAY_EXCLUSIVE
Definition: cm.h:101
#define GET_HASH_INDEX(ConvKey)
Definition: cm_x.h:37
#define CmpAcquireKcbLockSharedByIndex(i)
Definition: cm_x.h:108
BOOLEAN NTAPI CmpReferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:357
PULONG NTAPI CmpBuildAndLockKcbArray(_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ ULONG KcbLockFlags, _In_ PCM_KEY_CONTROL_BLOCK Kcb, _Inout_ PULONG OuterStackArray, _In_ ULONG TotalRemainingSubkeys, _In_ ULONG MatchRemainSubkeyLevel)
Builds an array of KCBs and locks them. Whether these KCBs are locked exclusively or in shared mode b...
Definition: cmkcbncb.c:1302
static NTSTATUS CmpLookInCache(_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ BOOLEAN LockKcbsExclusive, _In_ ULONG TotalRemainingSubkeys, _Inout_ PUNICODE_STRING RemainingName, _Inout_ PULONG OuterStackArray, _Inout_ PCM_KEY_CONTROL_BLOCK *Kcb, _Out_ PHHIVE *Hive, _Out_ PHCELL_INDEX Cell, _Out_ PULONG MatchRemainSubkeyLevel)
Looks up in the pool cache for key pathname that matches with one in the said cache and returns a KCB...
Definition: cmparse.c:1460
static ULONG CmpComputeHashValue(_In_ PUNICODE_STRING RemainingName, _In_ ULONG ConvKey, _Inout_ PCM_HASH_CACHE_STACK HashCacheStack, _Out_ PULONG TotalSubKeys)
Computes the hashes of each subkey in key path name and stores them in a hash stack for cache lookup.
Definition: cmparse.c:1141
VOID NTAPI CmpLockRegistry(VOID)
Definition: cmsysini.c:1970
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
Status
Definition: gdiplustypes.h:25
#define ASSERT(a)
Definition: mode.c:44
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:498
#define STATUS_SUCCESS
Definition: shellext.h:65
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_RETRY
Definition: udferr_usr.h:182
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define NT_ASSERT
Definition: rtlfuncs.h:3327

Referenced by CmpParseKey().

◆ CmpCompareSubkeys()

static BOOLEAN CmpCompareSubkeys ( _In_ PCM_HASH_CACHE_STACK  HashCacheStack,
_In_ PCM_KEY_CONTROL_BLOCK  CurrentKcb,
_In_ ULONG  RemainingSubkeys,
_Out_ PCM_KEY_CONTROL_BLOCK ParentKcb 
)
static

Compares each subkey's hash and name with those captured in the hash cache stack.

Parameters
[in]HashCacheStackA pointer to a hash cache stack array filled with subkey hashes and names for comparison.
[in]CurrentKcbA pointer to the currently given KCB.
[in]RemainingSubkeysThe remaining subkey levels to be supplied.
[out]ParentKcbA pointer to the parent KCB returned to the caller. This parameter points to the parent of the current KCB if all the subkeys match, otherwise it points to the actual current KCB.
Returns
Returns TRUE if all the subkey levels match, otherwise FALSE is returned.

Definition at line 1284 of file cmparse.c.

1289{
1290 LONG HashStackIndex;
1291 LONG Result;
1292 PCM_NAME_CONTROL_BLOCK NameBlock;
1293 UNICODE_STRING CurrentNameBlock;
1294
1295 ASSERT(CurrentKcb != NULL);
1296
1297 /* Loop each hash and check that they match */
1298 HashStackIndex = RemainingSubkeys;
1299 while (HashStackIndex >= 0)
1300 {
1301 /* Does the subkey hash match? */
1302 if (CurrentKcb->ConvKey != HashCacheStack[HashStackIndex].ConvKey)
1303 {
1304 *ParentKcb = CurrentKcb;
1305 return FALSE;
1306 }
1307
1308 /* Compare the subkey string, is the name compressed? */
1309 NameBlock = CurrentKcb->NameBlock;
1310 if (NameBlock->Compressed)
1311 {
1312 Result = CmpCompareCompressedName(&HashCacheStack[HashStackIndex].NameOfKey,
1313 NameBlock->Name,
1314 NameBlock->NameLength);
1315 }
1316 else
1317 {
1318 CurrentNameBlock.Buffer = NameBlock->Name;
1319 CurrentNameBlock.Length = NameBlock->NameLength;
1320 CurrentNameBlock.MaximumLength = NameBlock->NameLength;
1321
1322 Result = RtlCompareUnicodeString(&HashCacheStack[HashStackIndex].NameOfKey,
1323 &CurrentNameBlock,
1324 TRUE);
1325 }
1326
1327 /* Do the subkey names match? */
1328 if (Result)
1329 {
1330 *ParentKcb = CurrentKcb;
1331 return FALSE;
1332 }
1333
1334 /* Go to the next subkey hash */
1335 HashStackIndex--;
1336 }
1337
1338 /* All the subkeys match */
1339 *ParentKcb = CurrentKcb->ParentKcb;
1340 return TRUE;
1341}
LONG NTAPI CmpCompareCompressedName(IN PCUNICODE_STRING SearchName, IN PWCHAR CompressedName, IN ULONG NameLength)
Definition: cmname.c:109
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
long LONG
Definition: pedump.c:60
BOOLEAN Compressed
Definition: cm.h:251
USHORT NameLength
Definition: cm.h:260
WCHAR Name[ANYSIZE_ARRAY]
Definition: cm.h:261
USHORT MaximumLength
Definition: env_spec_w32.h:370
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409

Referenced by CmpLookInCache().

◆ CmpComputeHashValue()

static ULONG CmpComputeHashValue ( _In_ PUNICODE_STRING  RemainingName,
_In_ ULONG  ConvKey,
_Inout_ PCM_HASH_CACHE_STACK  HashCacheStack,
_Out_ PULONG  TotalSubKeys 
)
static

Computes the hashes of each subkey in key path name and stores them in a hash stack for cache lookup.

Parameters
[in]RemainingNameA Unicode string structure consisting of the remaining registry key path name.
[in]ConvKeyThe hash convkey of the current KCB to be supplied.
[in,out]HashCacheStackAn array stack. This function uses this array to store all the computed hashes of a key pathname.
[out]TotalSubKeysThe number of total subkeys that have been found, returned by this function to the caller. If no subkey levels are found the function returns 0.
Returns
Returns the number of remaining subkey levels to caller. If no subkey levels are found then this function returns 0.

Definition at line 1141 of file cmparse.c.

1146{
1147 ULONG CopyConvKey;
1148 ULONG SubkeysInTotal;
1149 ULONG RemainingSubkeysInTotal;
1150 PWCHAR RemainingNameBuffer;
1151 USHORT RemainingNameLength;
1153
1154 /* Don't compute the hashes on a NULL remaining name */
1155 RemainingNameBuffer = RemainingName->Buffer;
1156 RemainingNameLength = RemainingName->Length;
1157 if (RemainingNameLength == 0)
1158 {
1159 *TotalSubKeys = 0;
1160 return 0;
1161 }
1162
1163 /* Skip any leading separator */
1164 while (RemainingNameLength >= sizeof(WCHAR) &&
1165 *RemainingNameBuffer == OBJ_NAME_PATH_SEPARATOR)
1166 {
1167 RemainingNameBuffer++;
1168 RemainingNameLength -= sizeof(WCHAR);
1169 }
1170
1171 /* Now set up the hash stack entries and compute the hashes */
1172 SubkeysInTotal = 0;
1173 RemainingSubkeysInTotal = 0;
1174 KeyNameLength = 0;
1175 CopyConvKey = ConvKey;
1176 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Buffer = RemainingNameBuffer;
1177 while (RemainingNameLength > 0)
1178 {
1179 /* Is this character a separator? */
1180 if (*RemainingNameBuffer != OBJ_NAME_PATH_SEPARATOR)
1181 {
1182 /* It's not, add it to the hash */
1183 CopyConvKey = COMPUTE_HASH_CHAR(CopyConvKey, *RemainingNameBuffer);
1184
1185 /* Go to the next character (add up the length of the character as well) */
1186 RemainingNameBuffer++;
1187 KeyNameLength += sizeof(WCHAR);
1188 RemainingNameLength -= sizeof(WCHAR);
1189
1190 /*
1191 * We are at the end of the key name path. Take into account
1192 * the last character and if we still have space in the hash
1193 * stack, add it up in the remaining list.
1194 */
1195 if (RemainingNameLength == 0)
1196 {
1197 if (RemainingSubkeysInTotal < CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1198 {
1199 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Length = KeyNameLength;
1200 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.MaximumLength = KeyNameLength;
1201 HashCacheStack[RemainingSubkeysInTotal].ConvKey = CopyConvKey;
1202 RemainingSubkeysInTotal++;
1203 }
1204
1205 SubkeysInTotal++;
1206 }
1207 }
1208 else
1209 {
1210 /* Skip any leading separator */
1211 while (RemainingNameLength >= sizeof(WCHAR) &&
1212 *RemainingNameBuffer == OBJ_NAME_PATH_SEPARATOR)
1213 {
1214 RemainingNameBuffer++;
1215 RemainingNameLength -= sizeof(WCHAR);
1216 }
1217
1218 /*
1219 * It would be possible that a malformed key pathname may be passed
1220 * to the registry parser such as a path with only separators like
1221 * "\\\\" for example. This would trick the function into believing
1222 * the key path has subkeys albeit that is not the case.
1223 */
1224 ASSERT(RemainingNameLength != 0);
1225
1226 /* Take into account this subkey */
1227 SubkeysInTotal++;
1228
1229 /* And add it up to the hash stack */
1230 if (RemainingSubkeysInTotal < CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1231 {
1232 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Length = KeyNameLength;
1233 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.MaximumLength = KeyNameLength;
1234 HashCacheStack[RemainingSubkeysInTotal].ConvKey = CopyConvKey;
1235
1236 RemainingSubkeysInTotal++;
1237 KeyNameLength = 0;
1238
1239 /*
1240 * Precaution check -- we have added up a remaining
1241 * subkey above but we must ensure we still have space
1242 * to hold up the new subkey for which we will compute
1243 * the hashes, so that we don't blow up the hash stack.
1244 */
1245 if (RemainingSubkeysInTotal < CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1246 {
1247 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Buffer = RemainingNameBuffer;
1248 }
1249 }
1250 }
1251 }
1252
1253 *TotalSubKeys = SubkeysInTotal;
1254 return RemainingSubkeysInTotal;
1255}
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
_Inout_ PFCB _Inout_ PUNICODE_STRING RemainingName
Definition: cdprocs.h:802
#define COMPUTE_HASH_CHAR(ConvKey, Char)
Definition: cm_x.h:31
unsigned short USHORT
Definition: pedump.c:61
uint16_t * PWCHAR
Definition: typedefs.h:56
_In_ ULONG _In_ ULONG KeyNameLength
Definition: usbdlib.h:208
__wchar_t WCHAR
Definition: xmlstorage.h:180

Referenced by CmpBuildHashStackAndLookupCache().

◆ CmpCreateLinkNode()

NTSTATUS NTAPI CmpCreateLinkNode ( IN PHHIVE  Hive,
IN HCELL_INDEX  Cell,
IN PACCESS_STATE  AccessState,
IN UNICODE_STRING  Name,
IN KPROCESSOR_MODE  AccessMode,
IN ULONG  CreateOptions,
IN PCM_PARSE_CONTEXT  Context,
IN PCM_KEY_CONTROL_BLOCK  ParentKcb,
IN PULONG  KcbsLocked,
OUT PVOID Object 
)

Definition at line 830 of file cmparse.c.

840{
842 HCELL_INDEX KeyCell, LinkCell, ChildCell;
843 PCM_KEY_BODY KeyBody;
845 PCM_KEY_NODE KeyNode;
846 PCM_KEY_CONTROL_BLOCK Kcb = ParentKcb;
847
848 /* Link nodes only allowed on the master */
849 if (Hive != &CmiVolatileHive->Hive)
850 {
851 /* Fail */
852 DPRINT1("Invalid link node attempt\n");
854 }
855
856 /* Make sure the KCB is locked and lock the flusher */
857 CMP_ASSERT_KCB_LOCK(ParentKcb);
859 CmpLockHiveFlusherShared((PCMHIVE)Context->ChildHive.KeyHive);
860
861 /* Bail out on read-only KCBs */
862 if (ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY)
863 {
865 goto Exit;
866 }
867
868 /* Check if the parent is being deleted */
869 if (ParentKcb->Delete)
870 {
871 /* It is, quit */
872 ASSERT(FALSE);
874 goto Exit;
875 }
876
877 /* Allocate a link node */
878 LinkCell = HvAllocateCell(Hive,
880 CmpNameSize(Hive, &Name),
881 Stable,
882 HCELL_NIL);
883 if (LinkCell == HCELL_NIL)
884 {
885 /* Fail */
887 goto Exit;
888 }
889
890 /* Get the key cell */
891 KeyCell = Context->ChildHive.KeyCell;
892 if (KeyCell != HCELL_NIL)
893 {
894 /* Hive exists! */
895 ChildCell = KeyCell;
896
897 /* Get the node data */
898 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);
899 if (!KeyNode)
900 {
901 /* Fail */
902 ASSERT(FALSE);
904 goto Exit;
905 }
906
907 /* Fill out the data */
908 KeyNode->Parent = LinkCell;
909 KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
910 HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
911
912 /* Now open the key cell */
913 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, KeyCell);
914 if (!KeyNode)
915 {
916 /* Fail */
917 ASSERT(FALSE);
919 goto Exit;
920 }
921
922 /* Open the parent */
923 Status = CmpDoOpen(Context->ChildHive.KeyHive,
924 KeyCell,
925 KeyNode,
929 NULL,
931 &Kcb,
932 KcbsLocked,
933 &Name,
934 Object);
935 HvReleaseCell(Context->ChildHive.KeyHive, KeyCell);
936 }
937 else
938 {
939 /* Do the actual create operation */
940 Status = CmpDoCreateChild(Context->ChildHive.KeyHive,
941 Cell,
942 NULL,
944 &Name,
946 Context,
947 ParentKcb,
949 &ChildCell,
950 Object);
951 if (NT_SUCCESS(Status))
952 {
953 /* Setup root pointer */
954 Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell;
955 }
956 }
957
958 /* Check if open or create suceeded */
959 if (NT_SUCCESS(Status))
960 {
961 /* Mark the cell dirty */
962 HvMarkCellDirty(Context->ChildHive.KeyHive, ChildCell, FALSE);
963
964 /* Get the key node */
965 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);
966 if (!KeyNode)
967 {
968 /* Fail */
969 ASSERT(FALSE);
971 goto Exit;
972 }
973
974 /* Release it */
975 HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
976
977 /* Set the parent and flags */
978 KeyNode->Parent = LinkCell;
979 KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
980
981 /* Get the link node */
982 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, LinkCell);
983 if (!KeyNode)
984 {
985 /* Fail */
986 ASSERT(FALSE);
988 goto Exit;
989 }
990
991 /* Set it up */
993 KeyNode->Flags = KEY_HIVE_EXIT | KEY_NO_DELETE;
994 KeyNode->Parent = Cell;
995 KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, &Name);
996 if (KeyNode->NameLength < Name.Length) KeyNode->Flags |= KEY_COMP_NAME;
998 KeyNode->LastWriteTime = TimeStamp;
999
1000 /* Clear out the rest */
1001 KeyNode->SubKeyCounts[Stable] = 0;
1002 KeyNode->SubKeyCounts[Volatile] = 0;
1003 KeyNode->SubKeyLists[Stable] = HCELL_NIL;
1004 KeyNode->SubKeyLists[Volatile] = HCELL_NIL;
1005 KeyNode->ValueList.Count = 0;
1006 KeyNode->ValueList.List = HCELL_NIL;
1007 KeyNode->ClassLength = 0;
1008
1009 /* Reference the root node */
1010 KeyNode->ChildHiveReference.KeyHive = Context->ChildHive.KeyHive;
1011 KeyNode->ChildHiveReference.KeyCell = ChildCell;
1012 HvReleaseCell(Hive, LinkCell);
1013
1014 /* Get the parent node */
1015 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
1016 if (!KeyNode)
1017 {
1018 /* Fail */
1019 ASSERT(FALSE);
1021 goto Exit;
1022 }
1023
1024 /* Now add the subkey */
1025 if (!CmpAddSubKey(Hive, Cell, LinkCell))
1026 {
1027 /* Failure! We don't handle this yet! */
1028 ASSERT(FALSE);
1029 }
1030
1031 /* Get the key body */
1032 KeyBody = (PCM_KEY_BODY)*Object;
1033
1034 /* Clean up information on this subkey */
1035 CmpCleanUpSubKeyInfo(KeyBody->KeyControlBlock->ParentKcb);
1036
1037 /* Sanity checks */
1038 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell);
1039 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive);
1040 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen);
1041
1042 /* Update the timestamp */
1044 KeyNode->LastWriteTime = TimeStamp;
1045 KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
1046
1047 /* Check if we need to update name maximum */
1048 if (KeyNode->MaxNameLen < Name.Length)
1049 {
1050 /* Do it */
1051 KeyNode->MaxNameLen = Name.Length;
1052 KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name.Length;
1053 }
1054
1055 /* Check if we need to update class length maximum */
1056 if (KeyNode->MaxClassLen < Context->Class.Length)
1057 {
1058 /* Update it */
1059 KeyNode->MaxClassLen = Context->Class.Length;
1060 }
1061
1062 /* Release the cell */
1063 HvReleaseCell(Hive, Cell);
1064 }
1065 else
1066 {
1067 /* Release the link cell */
1068 HvReleaseCell(Hive, LinkCell);
1069 }
1070
1071Exit:
1072 /* Release the flusher locks and return status */
1073 CmpUnlockHiveFlusher((PCMHIVE)Context->ChildHive.KeyHive);
1075 return Status;
1076}
struct _CM_KEY_BODY * PCM_KEY_BODY
#define CMP_CREATE_KCB_KCB_LOCKED
Definition: cm.h:89
#define CM_KCB_READ_ONLY_KEY
Definition: cm.h:59
#define CMP_ASSERT_KCB_LOCK(k)
Definition: cm_x.h:278
struct _CM_KEY_NODE * PCM_KEY_NODE
#define KEY_COMP_NAME
Definition: cmdata.h:35
#define KEY_NO_DELETE
Definition: cmdata.h:33
#define KEY_HIVE_EXIT
Definition: cmdata.h:31
#define CM_LINK_NODE_SIGNATURE
Definition: cmdata.h:22
#define KEY_HIVE_ENTRY
Definition: cmdata.h:32
BOOLEAN NTAPI CmpAddSubKey(IN PHHIVE Hive, IN HCELL_INDEX Parent, IN HCELL_INDEX Child)
Definition: cmindex.c:1465
VOID NTAPI CmpCleanUpSubKeyInfo(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:517
#define HvReleaseCell(Hive, Cell)
Definition: cmlib.h:460
USHORT NTAPI CmpCopyName(IN PHHIVE Hive, OUT PWCHAR Destination, IN PCUNICODE_STRING Source)
Definition: cmname.c:21
USHORT NTAPI CmpNameSize(IN PHHIVE Hive, IN PCUNICODE_STRING Name)
Definition: cmname.c:74
BOOLEAN CMAPI HvMarkCellDirty(PHHIVE RegistryHive, HCELL_INDEX CellOffset, BOOLEAN HoldingLock)
Definition: hivecell.c:109
#define HvGetCell(Hive, Cell)
Definition: cmlib.h:457
HCELL_INDEX CMAPI HvAllocateCell(PHHIVE RegistryHive, ULONG Size, HSTORAGE_TYPE Storage, IN HCELL_INDEX Vicinity)
NTSTATUS NTAPI CmpDoOpen(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PCM_KEY_NODE Node, IN PACCESS_STATE AccessState, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN PCM_PARSE_CONTEXT Context OPTIONAL, IN ULONG ControlFlags, IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb, IN PULONG KcbsLocked, IN PUNICODE_STRING KeyName, OUT PVOID *Object)
Definition: cmparse.c:601
NTSTATUS NTAPI CmpDoCreateChild(IN PHHIVE Hive, IN HCELL_INDEX ParentCell, IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL, IN PACCESS_STATE AccessState, IN PUNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN PCM_PARSE_CONTEXT ParseContext, IN PCM_KEY_CONTROL_BLOCK ParentKcb, IN ULONG Flags, OUT PHCELL_INDEX KeyCell, OUT PVOID *Object)
Definition: cmparse.c:204
VOID NTAPI CmpLockHiveFlusherShared(IN PCMHIVE Hive)
Definition: cmsysini.c:2017
PCMHIVE CmiVolatileHive
Definition: cmsysini.c:16
VOID NTAPI CmpUnlockHiveFlusher(IN PCMHIVE Hive)
Definition: cmsysini.c:2028
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
@ Volatile
Definition: hivedata.h:128
@ Stable
Definition: hivedata.h:127
#define HCELL_NIL
Definition: hivedata.h:110
ULONG HCELL_INDEX
Definition: hivedata.h:105
SECURITY_INTEGER TimeStamp
Definition: sspi.h:78
static void Exit(void)
Definition: sock.c:1330
HCELL_INDEX List
Definition: cmdata.h:75
ULONG Count
Definition: cmdata.h:74
Definition: cmlib.h:316
HHIVE Hive
Definition: cmlib.h:317
struct _CM_KEY_CONTROL_BLOCK * KeyControlBlock
Definition: cm.h:237
USHORT Signature
Definition: cmdata.h:92
CM_KEY_REFERENCE ChildHiveReference
Definition: cmdata.h:105
HCELL_INDEX Parent
Definition: cmdata.h:96
WCHAR Name[ANYSIZE_ARRAY]
Definition: cmdata.h:116
HCELL_INDEX SubKeyLists[HTYPE_COUNT]
Definition: cmdata.h:102
ULONG MaxNameLen
Definition: cmdata.h:109
ULONG SubKeyCounts[HTYPE_COUNT]
Definition: cmdata.h:97
USHORT NameLength
Definition: cmdata.h:114
USHORT ClassLength
Definition: cmdata.h:115
ULONG MaxClassLen
Definition: cmdata.h:110
CHILD_LIST ValueList
Definition: cmdata.h:103
USHORT Flags
Definition: cmdata.h:93
LARGE_INTEGER LastWriteTime
Definition: cmdata.h:94
PHHIVE KeyHive
Definition: cmdata.h:84
HCELL_INDEX KeyCell
Definition: cmdata.h:83
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
_Must_inspect_result_ _In_ WDFCOLLECTION _In_ WDFOBJECT Object
_Must_inspect_result_ _In_opt_ WDFKEY _In_ PCUNICODE_STRING _In_ ACCESS_MASK _In_ ULONG CreateOptions
Definition: wdfregistry.h:118
_In_ PEPROCESS _In_ KPROCESSOR_MODE AccessMode
Definition: mmfuncs.h:396
_In_opt_ PVOID _In_opt_ PUNICODE_STRING _In_ PSECURITY_DESCRIPTOR _In_ PACCESS_STATE AccessState
Definition: sefuncs.h:417

Referenced by CmpParseKey().

◆ CmpDoCreate()

NTSTATUS NTAPI CmpDoCreate ( IN PHHIVE  Hive,
IN HCELL_INDEX  Cell,
IN PACCESS_STATE  AccessState,
IN PUNICODE_STRING  Name,
IN KPROCESSOR_MODE  AccessMode,
IN PCM_PARSE_CONTEXT  ParseContext,
IN PCM_KEY_CONTROL_BLOCK  ParentKcb,
OUT PVOID Object 
)

Definition at line 404 of file cmparse.c.

412{
414 PCELL_DATA CellData;
415 HCELL_INDEX KeyCell;
416 ULONG ParentType;
417 PCM_KEY_BODY KeyBody;
420 PCM_KEY_NODE KeyNode;
421
422 /* Make sure the KCB is locked and lock the flusher */
423 CMP_ASSERT_KCB_LOCK(ParentKcb);
425
426 /* Bail out on read-only KCBs */
427 if (ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY)
428 {
430 goto Exit;
431 }
432
433 /* Check if the parent is being deleted */
434 if (ParentKcb->Delete)
435 {
436 /* It has, quit */
437 ASSERT(FALSE);
439 goto Exit;
440 }
441
442 /* Get the parent node */
443 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
444 if (!KeyNode)
445 {
446 /* Fail */
447 ASSERT(FALSE);
449 goto Exit;
450 }
451
452 /* Make sure nobody added us yet */
453 if (CmpFindSubKeyByName(Hive, KeyNode, Name) != HCELL_NIL)
454 {
455 /* Fail */
456 ASSERT(FALSE);
458 goto Exit;
459 }
460
461 /* Sanity check */
462 ASSERT(Cell == ParentKcb->KeyCell);
463
464 /* Get the parent type */
465 ParentType = HvGetCellType(Cell);
466 if ((ParentType == Volatile) &&
467 !(ParseContext->CreateOptions & REG_OPTION_VOLATILE))
468 {
469 /* Children of volatile parents must also be volatile */
470 //ASSERT(FALSE);
472 goto Exit;
473 }
474
475 /* Don't allow children under symlinks */
476 if (ParentKcb->Flags & KEY_SYM_LINK)
477 {
478 /* Fail */
479 ASSERT(FALSE);
481 goto Exit;
482 }
483
484 /* Make the cell dirty for now */
485 HvMarkCellDirty(Hive, Cell, FALSE);
486
487 /* Do the actual create operation */
489 Cell,
492 Name,
494 ParseContext,
495 ParentKcb,
496 0,
497 &KeyCell,
498 Object);
499 if (NT_SUCCESS(Status))
500 {
501 /* Get the key body */
502 KeyBody = (PCM_KEY_BODY)(*Object);
503
504 /* Now add the subkey */
505 if (!CmpAddSubKey(Hive, Cell, KeyCell))
506 {
507 /* Free the created child */
508 CmpFreeKeyByCell(Hive, KeyCell, FALSE);
509
510 /* Purge out this KCB */
511 KeyBody->KeyControlBlock->Delete = TRUE;
513
514 /* And cleanup the key body object */
517 goto Exit;
518 }
519
520 /* Get the key node */
521 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
522 if (!KeyNode)
523 {
524 /* Fail, this shouldn't happen */
525 CmpFreeKeyByCell(Hive, KeyCell, TRUE); // Subkey linked above
526
527 /* Purge out this KCB */
528 KeyBody->KeyControlBlock->Delete = TRUE;
530
531 /* And cleanup the key body object */
534 goto Exit;
535 }
536
537 /* Clean up information on this subkey */
538 CmpCleanUpSubKeyInfo(KeyBody->KeyControlBlock->ParentKcb);
539
540 /* Sanity checks */
541 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell);
542 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive);
543 ASSERT(KeyBody->KeyControlBlock->ParentKcb == ParentKcb);
544 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen);
545
546 /* Update the timestamp */
548 KeyNode->LastWriteTime = TimeStamp;
549 KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
550
551 /* Check if we need to update name maximum */
552 if (KeyNode->MaxNameLen < Name->Length)
553 {
554 /* Do it */
555 KeyNode->MaxNameLen = Name->Length;
556 KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name->Length;
557 }
558
559 /* Check if we need to update class length maximum */
560 if (KeyNode->MaxClassLen < ParseContext->Class.Length)
561 {
562 /* Update it */
563 KeyNode->MaxClassLen = ParseContext->Class.Length;
564 }
565
566 /* Check if we're creating a symbolic link */
567 if (ParseContext->CreateOptions & REG_OPTION_CREATE_LINK)
568 {
569 /* Get the cell data */
570 CellData = HvGetCell(Hive, KeyCell);
571 if (!CellData)
572 {
573 /* This shouldn't happen */
574 CmpFreeKeyByCell(Hive, KeyCell, TRUE); // Subkey linked above
575
576 /* Purge out this KCB */
577 KeyBody->KeyControlBlock->Delete = TRUE;
579
580 /* And cleanup the key body object */
583 goto Exit;
584 }
585
586 /* Update the flags */
587 CellData->u.KeyNode.Flags |= KEY_SYM_LINK;
588 KeyBody->KeyControlBlock->Flags = CellData->u.KeyNode.Flags;
589 HvReleaseCell(Hive, KeyCell);
590 }
591 }
592
593Exit:
594 /* Release the flusher lock and return status */
596 return Status;
597}
#define KEY_SYM_LINK
Definition: cmdata.h:34
HCELL_INDEX NTAPI CmpFindSubKeyByName(IN PHHIVE Hive, IN PCM_KEY_NODE Parent, IN PCUNICODE_STRING SearchName)
Definition: cmindex.c:683
VOID NTAPI CmpRemoveKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:306
NTSTATUS NTAPI CmpFreeKeyByCell(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN BOOLEAN Unlink)
Definition: cmkeydel.c:159
#define HvGetCellType(Cell)
Definition: hivedata.h:120
#define REG_OPTION_CREATE_LINK
Definition: nt_native.h:1063
#define REG_OPTION_VOLATILE
Definition: nt_native.h:1060
#define STATUS_REPARSE
Definition: ntstatus.h:83
#define STATUS_CHILD_MUST_BE_VOLATILE
Definition: ntstatus.h:618
VOID NTAPI ObDereferenceObjectDeferDelete(IN PVOID Object)
Definition: obref.c:358
CM_KEY_NODE KeyNode
Definition: cmdata.h:200
union _CELL_DATA::@4305 u
_In_ USHORT _In_ ULONG _In_ PSOCKADDR _In_ PSOCKADDR _Reserved_ ULONG _In_opt_ PVOID _In_opt_ const WSK_CLIENT_CONNECTION_DISPATCH _In_opt_ PEPROCESS _In_opt_ PETHREAD _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor
Definition: wsk.h:191

Referenced by CmpParseKey().

◆ CmpDoCreateChild()

NTSTATUS NTAPI CmpDoCreateChild ( IN PHHIVE  Hive,
IN HCELL_INDEX  ParentCell,
IN PSECURITY_DESCRIPTOR ParentDescriptor  OPTIONAL,
IN PACCESS_STATE  AccessState,
IN PUNICODE_STRING  Name,
IN KPROCESSOR_MODE  AccessMode,
IN PCM_PARSE_CONTEXT  ParseContext,
IN PCM_KEY_CONTROL_BLOCK  ParentKcb,
IN ULONG  Flags,
OUT PHCELL_INDEX  KeyCell,
OUT PVOID Object 
)

Definition at line 204 of file cmparse.c.

215{
217 PCM_KEY_BODY KeyBody;
218 HCELL_INDEX ClassCell = HCELL_NIL;
219 PCM_KEY_NODE KeyNode;
220 PCELL_DATA CellData;
221 ULONG StorageType;
224
225 /* Get the storage type */
226 StorageType = Stable;
227 if (ParseContext->CreateOptions & REG_OPTION_VOLATILE) StorageType = Volatile;
228
229 /* Allocate the child */
230 *KeyCell = HvAllocateCell(Hive,
232 CmpNameSize(Hive, Name),
233 StorageType,
234 HCELL_NIL);
235 if (*KeyCell == HCELL_NIL)
236 {
237 /* Fail */
239 goto Quickie;
240 }
241
242 /* Get the key node */
243 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, *KeyCell);
244 if (!KeyNode)
245 {
246 /* Fail, this should never happen */
247 ASSERT(FALSE);
249 goto Quickie;
250 }
251
252 /* Release the cell */
253 HvReleaseCell(Hive, *KeyCell);
254
255 /* Check if we have a class name */
256 if (ParseContext->Class.Length > 0)
257 {
258 /* Allocate a class cell */
259 ClassCell = HvAllocateCell(Hive,
260 ParseContext->Class.Length,
261 StorageType,
262 HCELL_NIL);
263 if (ClassCell == HCELL_NIL)
264 {
265 /* Fail */
267 goto Quickie;
268 }
269 }
270
271 /* Allocate the Cm Object */
274 NULL,
276 NULL,
277 sizeof(CM_KEY_BODY),
278 0,
279 0,
280 Object);
281 if (!NT_SUCCESS(Status)) goto Quickie;
282
283 /* Setup the key body */
284 KeyBody = (PCM_KEY_BODY)(*Object);
285 KeyBody->Type = CM_KEY_BODY_TYPE;
286 KeyBody->KeyControlBlock = NULL;
287 KeyBody->KcbLocked = FALSE;
288
289 /* Check if we had a class */
290 if (ParseContext->Class.Length > 0)
291 {
292 /* Get the class cell */
293 CellData = HvGetCell(Hive, ClassCell);
294 if (!CellData)
295 {
296 /* Fail, this should never happen */
297 ASSERT(FALSE);
300 goto Quickie;
301 }
302
303 /* Release the cell */
304 HvReleaseCell(Hive, ClassCell);
305
306 /* Copy the class data */
307 RtlCopyMemory(&CellData->u.KeyString[0],
308 ParseContext->Class.Buffer,
309 ParseContext->Class.Length);
310 }
311
312 /* Fill out the key node */
314 KeyNode->Flags = Flags;
316 KeyNode->Spare = 0;
317 KeyNode->Parent = ParentCell;
318 KeyNode->SubKeyCounts[Stable] = 0;
319 KeyNode->SubKeyCounts[Volatile] = 0;
320 KeyNode->SubKeyLists[Stable] = HCELL_NIL;
321 KeyNode->SubKeyLists[Volatile] = HCELL_NIL;
322 KeyNode->ValueList.Count = 0;
323 KeyNode->ValueList.List = HCELL_NIL;
324 KeyNode->Security = HCELL_NIL;
325 KeyNode->Class = ClassCell;
326 KeyNode->ClassLength = ParseContext->Class.Length;
327 KeyNode->MaxValueDataLen = 0;
328 KeyNode->MaxNameLen = 0;
329 KeyNode->MaxValueNameLen = 0;
330 KeyNode->MaxClassLen = 0;
331 KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, Name);
332 if (KeyNode->NameLength < Name->Length) KeyNode->Flags |= KEY_COMP_NAME;
333
334 /* Create the KCB */
335 Kcb = CmpCreateKeyControlBlock(Hive,
336 *KeyCell,
337 KeyNode,
338 ParentKcb,
340 Name);
341 if (!Kcb)
342 {
343 /* Fail */
346 goto Quickie;
347 }
348
349 /* Sanity check */
350 ASSERT(Kcb->RefCount == 1);
351
352 /* Now fill out the Cm object */
353 KeyBody->NotifyBlock = NULL;
354 KeyBody->ProcessID = PsGetCurrentProcessId();
355 KeyBody->KeyControlBlock = Kcb;
356
357 /* Link it with the KCB */
359
360 /* Assign security */
361 Status = SeAssignSecurity(ParentDescriptor,
362 AccessState->SecurityDescriptor,
364 TRUE,
365 &AccessState->SubjectSecurityContext,
366 &CmpKeyObjectType->TypeInfo.GenericMapping,
367 CmpKeyObjectType->TypeInfo.PoolType);
368 if (NT_SUCCESS(Status))
369 {
370 /*
371 * FIXME: We must acquire a security lock when assigning
372 * a security descriptor to this hive but since the
373 * CmpAssignSecurityDescriptor function does nothing
374 * (we lack the necessary security management implementations
375 * anyway), do not do anything for now.
376 */
378 }
379
380 /* Now that the security descriptor is copied in the hive, we can free the original */
381 SeDeassignSecurity(&NewDescriptor);
382
383 if (NT_SUCCESS(Status))
384 {
385 /* Send notification to registered callbacks */
387 }
388
389Quickie:
390 /* Check if we got here because of failure */
391 if (!NT_SUCCESS(Status))
392 {
393 /* Free any cells we might've allocated */
394 if (ParseContext->Class.Length > 0) HvFreeCell(Hive, ClassCell);
395 HvFreeCell(Hive, *KeyCell);
396 }
397
398 /* Return status */
399 return Status;
400}
#define CmpKeyObjectType
Definition: ObTypes.c:127
#define CMP_LOCK_HASHES_FOR_KCB
Definition: cm.h:84
#define CM_KEY_BODY_TYPE
Definition: cm.h:64
#define CMP_ENLIST_KCB_LOCKED_EXCLUSIVE
Definition: cm.h:96
#define CM_KEY_NODE_SIGNATURE
Definition: cmdata.h:21
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)
Definition: cmkcbncb.c:655
VOID NTAPI EnlistKeyBodyWithKCB(IN PCM_KEY_BODY KeyBody, IN ULONG Flags)
Definition: cmkcbncb.c:1042
VOID CMAPI HvFreeCell(PHHIVE RegistryHive, HCELL_INDEX CellOffset)
Definition: hivecell.c:468
VOID NTAPI CmpReportNotify(IN PCM_KEY_CONTROL_BLOCK Kcb, IN PHHIVE Hive, IN HCELL_INDEX Cell, IN ULONG Filter)
Definition: cmnotify.c:19
NTSTATUS CmpAssignSecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb, IN PSECURITY_DESCRIPTOR SecurityDescriptor)
Definition: cmse.c:251
HANDLE NTAPI PsGetCurrentProcessId(VOID)
Definition: process.c:1123
NTSTATUS NTAPI ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, IN POBJECT_TYPE Type, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, IN ULONG ObjectSize, IN ULONG PagedPoolCharge OPTIONAL, IN ULONG NonPagedPoolCharge OPTIONAL, OUT PVOID *Object)
Definition: oblife.c:1039
WCHAR KeyString[ANYSIZE_ARRAY]
Definition: cmdata.h:206
ULONG Type
Definition: cm.h:236
HANDLE ProcessID
Definition: cm.h:239
BOOLEAN KcbLocked
Definition: cm.h:243
struct _CM_NOTIFY_BLOCK * NotifyBlock
Definition: cm.h:238
ULONG RefCount
Definition: cm.h:272
HCELL_INDEX KeyCell
Definition: cm.h:289
ULONG Spare
Definition: cmdata.h:95
ULONG MaxValueNameLen
Definition: cmdata.h:111
HCELL_INDEX Security
Definition: cmdata.h:107
HCELL_INDEX Class
Definition: cmdata.h:108
ULONG MaxValueDataLen
Definition: cmdata.h:112
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define REG_NOTIFY_CHANGE_NAME
Definition: winreg.h:38
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define ObDereferenceObject
Definition: obfuncs.h:203
_In_opt_ PSECURITY_DESCRIPTOR _Out_ PSECURITY_DESCRIPTOR * NewDescriptor
Definition: sefuncs.h:30

Referenced by CmpCreateLinkNode(), and CmpDoCreate().

◆ CmpDoOpen()

NTSTATUS NTAPI CmpDoOpen ( IN PHHIVE  Hive,
IN HCELL_INDEX  Cell,
IN PCM_KEY_NODE  Node,
IN PACCESS_STATE  AccessState,
IN KPROCESSOR_MODE  AccessMode,
IN ULONG  Attributes,
IN PCM_PARSE_CONTEXT Context  OPTIONAL,
IN ULONG  ControlFlags,
IN OUT PCM_KEY_CONTROL_BLOCK CachedKcb,
IN PULONG  KcbsLocked,
IN PUNICODE_STRING  KeyName,
OUT PVOID Object 
)

Definition at line 601 of file cmparse.c.

613{
615 BOOLEAN LockKcb = FALSE;
616 BOOLEAN IsLockShared = FALSE;
617 PCM_KEY_BODY KeyBody = NULL;
619
620 /* Make sure the hive isn't locked */
621 if ((Hive->HiveFlags & HIVE_IS_UNLOADING) &&
622 (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread()))
623 {
624 /* It is, don't touch it */
626 }
627
628 /* Check if we have a context */
629 if (Context)
630 {
631 /* Check if this is a link create (which shouldn't be an open) */
632 if (Context->CreateLink)
633 {
635 }
636
637 /* Check if this is symlink create attempt */
638 if (Context->CreateOptions & REG_OPTION_CREATE_LINK)
639 {
640 /* Key already exists */
642 }
643
644 /* Set the disposition */
645 Context->Disposition = REG_OPENED_EXISTING_KEY;
646 }
647
648 /* Lock the KCB on creation if asked */
649 if (ControlFlags & CMP_CREATE_KCB_KCB_LOCKED)
650 {
651 LockKcb = TRUE;
652 }
653
654 /* Check if caller doesn't want to create a KCB */
655 if (ControlFlags & CMP_OPEN_KCB_NO_CREATE)
656 {
657 /*
658 * The caller doesn't want to create a KCB. This means the KCB
659 * is already in cache and other threads may take use of it
660 * so it has to be locked in share mode.
661 */
662 IsLockShared = TRUE;
663
664 /* Check if this is a symlink */
665 if (((*CachedKcb)->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK))
666 {
667 /* Is this symlink found? */
668 if ((*CachedKcb)->ExtFlags & CM_KCB_SYM_LINK_FOUND)
669 {
670 /* Get the real KCB, is this deleted? */
671 Kcb = (*CachedKcb)->ValueCache.RealKcb;
672 if (Kcb->Delete)
673 {
674 /*
675 * The real KCB is gone, do a reparse. We used to lock the KCB in
676 * shared mode as others may have taken use of it but since we
677 * must do a reparse of the key the only thing that matter is us.
678 * Lock the KCB exclusively so nobody is going to mess with the KCB.
679 */
680 DPRINT1("The real KCB is deleted, attempt a reparse\n");
681 CmpUnLockKcbArray(KcbsLocked);
683 CmpCleanUpKcbValueCache(*CachedKcb);
684 KcbsLocked[0] = 1;
685 KcbsLocked[1] = GET_HASH_INDEX((*CachedKcb)->ConvKey);
686 return STATUS_REPARSE;
687 }
688
689 /*
690 * The symlink has been found. As in the similar case above,
691 * the KCB of the symlink exclusively, we don't want anybody
692 * to mess it up.
693 */
694 CmpUnLockKcbArray(KcbsLocked);
696 KcbsLocked[0] = 1;
697 KcbsLocked[1] = GET_HASH_INDEX((*CachedKcb)->ConvKey);
698 }
699 else
700 {
701 /* We must do a reparse */
702 DPRINT("The symlink is not found, attempt a reparse\n");
703 return STATUS_REPARSE;
704 }
705 }
706 else
707 {
708 /* This is not a symlink, just give the cached KCB already */
709 Kcb = *CachedKcb;
710 }
711
712 /* The caller wants to open a cached KCB */
714 {
715 /* Return failure code */
717 }
718 }
719 else
720 {
721 /*
722 * The caller wants to create a new KCB. Unlike the code path above, here
723 * we must check if the lock is exclusively held because in the scenario
724 * where the caller doesn't want to create a KCB is because it is already
725 * in the cache and it must have a shared lock instead.
726 */
727 ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
728
729 /* Check if this is a symlink */
730 if ((Node->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK))
731 {
732 /* Create the KCB for the symlink */
733 Kcb = CmpCreateKeyControlBlock(Hive,
734 Cell,
735 Node,
736 *CachedKcb,
737 LockKcb ? CMP_LOCK_HASHES_FOR_KCB : 0,
738 KeyName);
739 if (!Kcb)
740 {
741 /* Return failure */
743 }
744
745 /* Make sure it's also locked, and set the pointer */
747 *CachedKcb = Kcb;
748
749 /* Return reparse required */
750 return STATUS_REPARSE;
751 }
752
753 /* Create the KCB */
754 Kcb = CmpCreateKeyControlBlock(Hive,
755 Cell,
756 Node,
757 *CachedKcb,
758 LockKcb ? CMP_LOCK_HASHES_FOR_KCB : 0,
759 KeyName);
760 if (!Kcb)
761 {
762 /* Return failure */
764 }
765
766 /* Make sure it's also locked, and set the pointer */
768 *CachedKcb = Kcb;
769 }
770
771 /* Allocate the key object */
774 NULL,
776 NULL,
777 sizeof(CM_KEY_BODY),
778 0,
779 0,
780 Object);
781 if (NT_SUCCESS(Status))
782 {
783 /* Get the key body and fill it out */
784 KeyBody = (PCM_KEY_BODY)(*Object);
785 KeyBody->KeyControlBlock = Kcb;
786 KeyBody->Type = CM_KEY_BODY_TYPE;
787 KeyBody->ProcessID = PsGetCurrentProcessId();
788 KeyBody->NotifyBlock = NULL;
789
790 /* Link to the KCB */
792
793 /*
794 * We are already holding a lock against the KCB that is assigned
795 * to this key body. This is to prevent a potential deadlock on
796 * CmpSecurityMethod as ObCheckObjectAccess will invoke the Object
797 * Manager to call that method, of which CmpSecurityMethod would
798 * attempt to acquire a lock again.
799 */
800 KeyBody->KcbLocked = TRUE;
801
804 FALSE,
806 &Status))
807 {
808 /* Access check failed */
810 }
811
812 /*
813 * We are done, the lock we are holding will be released
814 * once the registry parsing is done.
815 */
816 KeyBody->KcbLocked = FALSE;
817 }
818 else
819 {
820 /* Failed, dereference the KCB */
822 }
823
824 /* Return status */
825 return Status;
826}
unsigned char BOOLEAN
#define CMP_ENLIST_KCB_LOCKED_SHARED
Definition: cm.h:95
#define CMP_OPEN_KCB_NO_CREATE
Definition: cm.h:90
#define CM_KCB_SYM_LINK_FOUND
Definition: cm.h:55
FORCEINLINE VOID CmpAcquireKcbLockExclusiveByIndex(ULONG Index)
Definition: cm_x.h:118
#define CmpIsKcbLockedExclusive(k)
Definition: cm_x.h:101
VOID CmpUnLockKcbArray(_In_ PULONG KcbArray)
Unlocks a number of KCBs provided by a KCB array.
Definition: cmkcbncb.c:1145
VOID NTAPI CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:431
VOID NTAPI CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, IN BOOLEAN LockHeldExclusively)
Definition: cmkcbncb.c:606
#define KeGetCurrentThread
Definition: hal.h:55
#define HIVE_IS_UNLOADING
Definition: hivedata.h:28
#define OBJ_OPENLINK
Definition: winternl.h:230
#define REG_OPENED_EXISTING_KEY
Definition: nt_native.h:1085
BOOLEAN NTAPI ObCheckObjectAccess(IN PVOID Object, IN OUT PACCESS_STATE AccessState, IN BOOLEAN LockHeld, IN KPROCESSOR_MODE AccessMode, OUT PNTSTATUS ReturnedStatus)
Definition: obsecure.c:441
#define DPRINT
Definition: sndvol32.h:73
struct _CM_KEY_CONTROL_BLOCK * RealKcb
Definition: cm.h:218
CACHED_CHILD_LIST ValueCache
Definition: cm.h:295
#define STATUS_OBJECT_NAME_COLLISION
Definition: udferr_usr.h:150
Definition: dlist.c:348
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2699

Referenced by CmpCreateLinkNode(), and CmpParseKey().

◆ CmpGetNextName()

BOOLEAN NTAPI CmpGetNextName ( IN OUT PUNICODE_STRING  RemainingName,
OUT PUNICODE_STRING  NextName,
OUT PBOOLEAN  LastName 
)

Definition at line 21 of file cmparse.c.

24{
25 BOOLEAN NameValid = TRUE;
26
27 ASSERT(RemainingName->Length % sizeof(WCHAR) == 0);
28
29 /* Check if there's nothing left in the name */
30 if (!(RemainingName->Buffer) ||
31 (!RemainingName->Length) ||
32 !(*RemainingName->Buffer))
33 {
34 /* Clear the next name and set this as last */
35 *LastName = TRUE;
36 NextName->Buffer = NULL;
37 NextName->Length = 0;
38 return TRUE;
39 }
40
41 /* Check if we have a path separator */
42 while (RemainingName->Length &&
44 {
45 /* Skip it */
46 RemainingName->Buffer++;
47 RemainingName->Length -= sizeof(WCHAR);
48 RemainingName->MaximumLength -= sizeof(WCHAR);
49 }
50
51 /* Start loop at where the current buffer is */
52 NextName->Buffer = RemainingName->Buffer;
53 while (RemainingName->Length &&
55 {
56 /* Move to the next character */
57 RemainingName->Buffer++;
58 RemainingName->Length -= sizeof(WCHAR);
59 RemainingName->MaximumLength -= sizeof(WCHAR);
60 }
61
62 /* See how many chars we parsed and validate the length */
63 NextName->Length = (USHORT)((ULONG_PTR)RemainingName->Buffer -
64 (ULONG_PTR)NextName->Buffer);
65 if (NextName->Length > 512) NameValid = FALSE;
66 NextName->MaximumLength = NextName->Length;
67
68 /* If there's nothing left, we're last */
69 *LastName = !RemainingName->Length;
70 return NameValid;
71}
#define ULONG_PTR
Definition: config.h:101
uint32_t ULONG_PTR
Definition: typedefs.h:65

Referenced by CmpParseKey(), and CmpWalkPath().

◆ CmpGetSymbolicLink()

BOOLEAN NTAPI CmpGetSymbolicLink ( IN PHHIVE  Hive,
IN OUT PUNICODE_STRING  ObjectName,
IN OUT PCM_KEY_CONTROL_BLOCK  SymbolicKcb,
IN PUNICODE_STRING RemainingName  OPTIONAL 
)

Definition at line 75 of file cmparse.c.

79{
80 HCELL_INDEX LinkCell = HCELL_NIL;
81 PCM_KEY_VALUE LinkValue = NULL;
82 PWSTR LinkName = NULL;
83 BOOLEAN LinkNameAllocated = FALSE;
84 PWSTR NewBuffer;
85 ULONG Length = 0;
88 HCELL_INDEX CellToRelease = HCELL_NIL;
90 UNICODE_STRING NewObjectName;
91
92 /* Make sure we're not being deleted */
93 if (SymbolicKcb->Delete) return FALSE;
94
95 /* Get the key node */
96 Node = (PCM_KEY_NODE)HvGetCell(SymbolicKcb->KeyHive, SymbolicKcb->KeyCell);
97 if (!Node) goto Exit;
98
99 /* Find the symbolic link key */
101 HvReleaseCell(SymbolicKcb->KeyHive, SymbolicKcb->KeyCell);
102 if (LinkCell == HCELL_NIL) goto Exit;
103
104 /* Get the value cell */
105 LinkValue = (PCM_KEY_VALUE)HvGetCell(Hive, LinkCell);
106 if (!LinkValue) goto Exit;
107
108 /* Make sure it's a registry link */
109 if (LinkValue->Type != REG_LINK) goto Exit;
110
111 /* Now read the value data */
112 if (!CmpGetValueData(Hive,
113 LinkValue,
115 (PVOID*)&LinkName,
116 &LinkNameAllocated,
117 &CellToRelease))
118 {
119 /* Fail */
120 goto Exit;
121 }
122
123 /* Get the length */
124 Length = ValueLength + sizeof(WCHAR);
125
126 /* Make sure we start with a slash */
127 if (*LinkName != OBJ_NAME_PATH_SEPARATOR) goto Exit;
128
129 /* Add the remaining name if needed */
130 if (RemainingName) Length += RemainingName->Length + sizeof(WCHAR);
131
132 /* Check for overflow */
133 if (Length > 0xFFFF) goto Exit;
134
135 /* Check if we need a new buffer */
136 if (Length > ObjectName->MaximumLength)
137 {
138 /* We do -- allocate one */
140 if (!NewBuffer) goto Exit;
141
142 /* Setup the new string and copy the symbolic target */
143 NewObjectName.Buffer = NewBuffer;
144 NewObjectName.MaximumLength = (USHORT)Length;
145 NewObjectName.Length = (USHORT)ValueLength;
146 RtlCopyMemory(NewBuffer, LinkName, ValueLength);
147
148 /* Check if we need to add anything else */
149 if (RemainingName)
150 {
151 /* Add the remaining name */
152 NewBuffer[ValueLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
153 NewObjectName.Length += sizeof(WCHAR);
155 }
156
157 /* Free the old buffer */
158 ExFreePool(ObjectName->Buffer);
159 *ObjectName = NewObjectName;
160 }
161 else
162 {
163 /* The old name is large enough -- update the length */
164 ObjectName->Length = (USHORT)ValueLength;
165 if (RemainingName)
166 {
167 /* Copy the remaining name inside */
168 RtlMoveMemory(&ObjectName->Buffer[(ValueLength / sizeof(WCHAR)) + 1],
169 RemainingName->Buffer,
170 RemainingName->Length);
171
172 /* Add the slash and update the length */
174 ObjectName->Length += RemainingName->Length + sizeof(WCHAR);
175 }
176
177 /* Copy the symbolic link target name */
178 RtlCopyMemory(ObjectName->Buffer, LinkName, ValueLength);
179 }
180
181 /* Null-terminate the whole thing */
182 ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] = UNICODE_NULL;
183 Result = TRUE;
184
185Exit:
186 /* Free the link name */
187 if (LinkNameAllocated) ExFreePool(LinkName);
188
189 /* Check if we had a value cell */
190 if (LinkValue)
191 {
192 /* Release it */
193 ASSERT(LinkCell != HCELL_NIL);
194 HvReleaseCell(Hive, LinkCell);
195 }
196
197 /* Check if we had an active cell and release it, then return the result */
198 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
199 return Result;
200}
UNICODE_STRING CmSymbolicLinkValueName
Definition: cmdata.c:52
struct _CM_KEY_VALUE * PCM_KEY_VALUE
BOOLEAN NTAPI CmpGetValueData(IN PHHIVE Hive, IN PCM_KEY_VALUE Value, OUT PULONG Length, OUT PVOID *Buffer, OUT PBOOLEAN BufferAllocated, OUT PHCELL_INDEX CellToRelease)
Definition: cmvalue.c:125
HCELL_INDEX NTAPI CmpFindValueByName(IN PHHIVE Hive, IN PCM_KEY_NODE KeyNode, IN PCUNICODE_STRING Name)
Definition: cmvalue.c:99
#define TAG_CM
Definition: cmlib.h:212
union node Node
Definition: types.h:1255
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define PagedPool
Definition: env_spec_w32.h:308
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
#define REG_LINK
Definition: nt_native.h:1500
#define UNICODE_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
ULONG Type
Definition: cmdata.h:128
uint16_t * PWSTR
Definition: typedefs.h:56
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
_In_ PVOID _Out_opt_ PULONG_PTR _Outptr_opt_ PCUNICODE_STRING * ObjectName
Definition: cmfuncs.h:64

Referenced by CmpParseKey().

◆ CmpHandleExitNode()

VOID NTAPI CmpHandleExitNode ( IN OUT PHHIVE Hive,
IN OUT HCELL_INDEX Cell,
IN OUT PCM_KEY_NODE KeyNode,
IN OUT PHHIVE ReleaseHive,
IN OUT HCELL_INDEX ReleaseCell 
)

Definition at line 1080 of file cmparse.c.

1085{
1086 /* Check if we have anything to release */
1087 if (*ReleaseCell != HCELL_NIL)
1088 {
1089 /* Release it */
1090 ASSERT(*ReleaseHive != NULL);
1091 HvReleaseCell(*ReleaseHive, *ReleaseCell);
1092 }
1093
1094 /* Get the link references */
1095 *Hive = (*KeyNode)->ChildHiveReference.KeyHive;
1096 *Cell = (*KeyNode)->ChildHiveReference.KeyCell;
1097
1098 /* Get the new node */
1099 *KeyNode = (PCM_KEY_NODE)HvGetCell(*Hive, *Cell);
1100 if (*KeyNode)
1101 {
1102 /* Set the new release values */
1103 *ReleaseCell = *Cell;
1104 *ReleaseHive = *Hive;
1105 }
1106 else
1107 {
1108 /* Nothing to release */
1109 *ReleaseCell = HCELL_NIL;
1110 *ReleaseHive = NULL;
1111 }
1112}

Referenced by CmpParseKey().

◆ CmpLookInCache()

static NTSTATUS CmpLookInCache ( _In_ PCM_HASH_CACHE_STACK  HashCacheStack,
_In_ BOOLEAN  LockKcbsExclusive,
_In_ ULONG  TotalRemainingSubkeys,
_Inout_ PUNICODE_STRING  RemainingName,
_Inout_ PULONG  OuterStackArray,
_Inout_ PCM_KEY_CONTROL_BLOCK Kcb,
_Out_ PHHIVE Hive,
_Out_ PHCELL_INDEX  Cell,
_Out_ PULONG  MatchRemainSubkeyLevel 
)
static

Looks up in the pool cache for key pathname that matches with one in the said cache and returns a KCB pointing to that name. This function performs locking of KCBs during cache lookup.

Parameters
[in]HashCacheStackA pointer to a hash cache stack array filled with subkey hashes and names.
[in]LockKcbsExclusiveIf set to TRUE, the KCBs are locked exclusively by the calling thread, otherwise they are locked in shared mode. See Remarks for further information.
[in]TotalRemainingSubkeysThe total remaining subkey levels to be supplied.
[in,out]RemainingNameA Unicode string structure consisting of the remaining registry key path name. The remaining name is updated by the function if a key pathname is found in cache.
[in,out]OuterStackArrayA pointer to an array that lives on the caller's stack. The expected size of the array is up to 32 elements, which is the imposed limit by CMP_HASH_STACK_LIMIT. This limit also corresponds to the maximum depth of subkey levels.
[in,out]KcbA pointer to a KCB, this KCB is changed if the key pathname is found in cache.
[out]HiveA pointer to a hive, this hive is changed if the key pathname is found in cache.
[out]CellA pointer to a cell, this cell is changed if the key pathname is found in cache.
[out]MatchRemainSubkeyLevelA pointer to match subkey levels returned by the function. If no match levels are found, this is 0.
Returns
Returns STATUS_SUCCESS if cache lookup has completed successfully. STATUS_OBJECT_NAME_NOT_FOUND is returned if the current KCB of the key pathname has been deleted. STATUS_RETRY is returned if at least the current KCB or its parent have been deleted and a cache lookup must be retried again. STATUS_UNSUCCESSFUL is returned if a KCB is referenced too many times.
Remarks
The function attempts to do a cache lookup with a shared lock on KCBs so that other threads can simultaneously get access to these KCBs. When the captured KCB is being deleted on us we have to retry a lookup with exclusive look so that no other threads will mess with the KCBs and perform appropriate actions if a KCB is deleted.

Definition at line 1460 of file cmparse.c.

1470{
1471 LONG RemainingSubkeys;
1472 ULONG TotalLevels;
1473 BOOLEAN SubkeysMatch;
1474 PCM_KEY_CONTROL_BLOCK CurrentKcb, ParentKcb;
1476 BOOLEAN KeyFoundInCache = FALSE;
1477 PULONG LockedKcbs = NULL;
1478
1479 /* Reference the KCB */
1480 if (!CmpReferenceKeyControlBlock(*Kcb))
1481 {
1482 /* This key is opened too many times, bail out */
1483 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1484 return STATUS_UNSUCCESSFUL;
1485 }
1486
1487 /* Prepare to lock the KCBs */
1488 LockedKcbs = CmpBuildAndLockKcbArray(HashCacheStack,
1490 *Kcb,
1491 OuterStackArray,
1492 TotalRemainingSubkeys,
1493 0);
1494 NT_ASSERT(LockedKcbs);
1495
1496 /* Lookup in the cache */
1497 RemainingSubkeys = TotalRemainingSubkeys - 1;
1498 TotalLevels = TotalRemainingSubkeys + (*Kcb)->TotalLevels + 1;
1499 while (RemainingSubkeys >= 0)
1500 {
1501 /* Get the hash entry from the cache */
1502 HashEntry = GET_HASH_ENTRY(CmpCacheTable, HashCacheStack[RemainingSubkeys].ConvKey)->Entry;
1503
1504 /* Take one level down as we are processing this hash entry */
1505 TotalLevels--;
1506
1507 while (HashEntry != NULL)
1508 {
1509 /* Validate this hash and obtain the current KCB */
1512
1513 /* Does this KCB have matching levels? */
1514 if (TotalLevels == CurrentKcb->TotalLevels)
1515 {
1516 /*
1517 * We have matching subkey levels but don't directly assume we have
1518 * a matching key path in cache. Start comparing each subkey.
1519 */
1520 SubkeysMatch = CmpCompareSubkeys(HashCacheStack,
1521 CurrentKcb,
1522 RemainingSubkeys,
1523 &ParentKcb);
1524 if (SubkeysMatch)
1525 {
1526 /* All subkeys match, now check if the base KCB matches with parent */
1527 if (*Kcb == ParentKcb)
1528 {
1529 /* Is the KCB marked as deleted? */
1530 if (CurrentKcb->Delete ||
1531 CurrentKcb->ParentKcb->Delete)
1532 {
1533 /*
1534 * Either the current or its parent KCB is marked
1535 * but we had a shared lock so probably a naughty
1536 * thread was deleting it. Retry doing a cache
1537 * lookup again with exclusive lock.
1538 */
1539 if (!LockKcbsExclusive)
1540 {
1541 CmpUnLockKcbArray(LockedKcbs);
1543 DPRINT1("The current KCB or its parent is deleted, retrying looking in the cache\n");
1544 return STATUS_RETRY;
1545 }
1546
1547 /* We're under an exclusive lock, is the KCB deleted yet? */
1548 if (CurrentKcb->Delete)
1549 {
1550 /* The KCB is gone, the key should no longer belong in the cache */
1551 CmpRemoveKeyControlBlock(CurrentKcb);
1552 CmpUnLockKcbArray(LockedKcbs);
1554 DPRINT1("The current KCB is deleted (KCB 0x%p)\n", CurrentKcb);
1556 }
1557
1558 /*
1559 * The parent is deleted so it must be that somebody created
1560 * a fake key. Assert ourselves that is the case.
1561 */
1562 ASSERT(CurrentKcb->ExtFlags & CM_KCB_KEY_NON_EXIST);
1563
1564 /* Remove this KCB out of cache if someone still uses it */
1565 if (CurrentKcb->RefCount != 0)
1566 {
1567 CurrentKcb->Delete = TRUE;
1568 CmpRemoveKeyControlBlock(CurrentKcb);
1569 }
1570 else
1571 {
1572 /* Otherwise expunge it */
1573 CmpRemoveFromDelayedClose(CurrentKcb);
1574 CmpCleanUpKcbCacheWithLock(CurrentKcb, FALSE);
1575 }
1576
1577 /* Stop looking for next hashes as the KCB is kaput */
1578 break;
1579 }
1580
1581 /* We finally found the key in cache, acknowledge it */
1582 KeyFoundInCache = TRUE;
1583
1584 /* Remove the subkeys in the remaining name and stop looking in the cache */
1585 CmpRemoveSubkeysInRemainingName(HashCacheStack, RemainingSubkeys, RemainingName);
1586 break;
1587 }
1588 }
1589 }
1590
1591 /* Go to the next hash */
1592 HashEntry = HashEntry->NextHash;
1593 }
1594
1595 /* Stop looking in cache if we found the matching key */
1596 if (KeyFoundInCache)
1597 {
1598 DPRINT("Key found in cache, stop looking\n");
1599 break;
1600 }
1601
1602 /* Keep looking in the cache until we run out of remaining subkeys */
1603 RemainingSubkeys--;
1604 }
1605
1606 /* Return the matching subkey levels */
1607 *MatchRemainSubkeyLevel = RemainingSubkeys + 1;
1608
1609 /* We have to update the KCB if the key was found in cache */
1610 if (KeyFoundInCache)
1611 {
1612 /*
1613 * Before we change the KCB we must dereference the prior
1614 * KCB that we no longer need it.
1615 */
1617 *Kcb = CurrentKcb;
1618
1619 /* Reference the new KCB now */
1620 if (!CmpReferenceKeyControlBlock(*Kcb))
1621 {
1622 /* This key is opened too many times, bail out */
1623 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1624 return STATUS_UNSUCCESSFUL;
1625 }
1626
1627 /* Update hive and cell data from current KCB */
1628 *Hive = CurrentKcb->KeyHive;
1629 *Cell = CurrentKcb->KeyCell;
1630 }
1631
1632 /* Unlock the KCBs */
1633 CmpUnLockKcbArray(LockedKcbs);
1634 return STATUS_SUCCESS;
1635}
#define CMP_LOCK_KCB_ARRAY_SHARED
Definition: cm.h:102
#define CM_KCB_KEY_NON_EXIST
Definition: cm.h:56
#define ASSERT_VALID_HASH(h)
Definition: cm_x.h:41
#define GET_HASH_ENTRY(Table, ConvKey)
Definition: cm_x.h:39
VOID NTAPI CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmdelay.c:425
VOID NTAPI CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, IN BOOLEAN LockHeldExclusively)
Definition: cmkcbncb.c:476
PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable
Definition: cmkcbncb.c:18
VOID NTAPI CmpDereferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:571
static BOOLEAN CmpCompareSubkeys(_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ PCM_KEY_CONTROL_BLOCK CurrentKcb, _In_ ULONG RemainingSubkeys, _Out_ PCM_KEY_CONTROL_BLOCK *ParentKcb)
Compares each subkey's hash and name with those captured in the hash cache stack.
Definition: cmparse.c:1284
static VOID CmpRemoveSubkeysInRemainingName(_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ ULONG RemainingSubkeys, _Inout_ PUNICODE_STRING RemainingName)
Removes the subkeys on a remaining key pathname.
Definition: cmparse.c:1361
Definition: hash.c:61
ULONG TotalLevels
Definition: cm.h:279
PHHIVE KeyHive
Definition: cm.h:288
struct _CM_KEY_CONTROL_BLOCK * ParentKcb
Definition: cm.h:292
ULONG ExtFlags
Definition: cm.h:275
uint32_t * PULONG
Definition: typedefs.h:59
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260

Referenced by CmpBuildHashStackAndLookupCache().

◆ CmpParseKey()

NTSTATUS NTAPI CmpParseKey ( IN PVOID  ParseObject,
IN PVOID  ObjectType,
IN OUT PACCESS_STATE  AccessState,
IN KPROCESSOR_MODE  AccessMode,
IN ULONG  Attributes,
IN OUT PUNICODE_STRING  CompleteName,
IN OUT PUNICODE_STRING  RemainingName,
IN OUT PVOID Context  OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos  OPTIONAL,
OUT PVOID Object 
)

Definition at line 1848 of file cmparse.c.

1858{
1860 PCM_KEY_CONTROL_BLOCK Kcb, ParentKcb;
1861 PHHIVE Hive = NULL;
1863 HCELL_INDEX Cell = HCELL_NIL, NextCell;
1864 PHHIVE HiveToRelease = NULL;
1865 HCELL_INDEX CellToRelease = HCELL_NIL;
1866 UNICODE_STRING Current, NextName;
1867 PCM_PARSE_CONTEXT ParseContext = Context;
1868 ULONG TotalRemainingSubkeys = 0, MatchRemainSubkeyLevel = 0, TotalSubkeys = 0;
1869 ULONG LockedKcbArray[CMP_KCBS_IN_ARRAY_LIMIT];
1870 PULONG LockedKcbs;
1871 BOOLEAN IsKeyCached = FALSE;
1872 BOOLEAN Result, Last;
1873 PAGED_CODE();
1874
1875 /* Loop path separators at the end */
1876 while (RemainingName->Length &&
1877 (RemainingName->Buffer[(RemainingName->Length / sizeof(WCHAR)) - 1] ==
1879 {
1880 /* Remove path separator */
1881 RemainingName->Length -= sizeof(WCHAR);
1882 }
1883
1884 /* Fail if this isn't a key object */
1886
1887 /* Copy the remaining name */
1888 Current = *RemainingName;
1889
1890 /* Check if this is a create */
1891 if (!ParseContext || !ParseContext->CreateOperation)
1892 {
1893 /* It isn't, so no context */
1894 ParseContext = NULL;
1895 }
1896
1897 /* Grab the KCB */
1898 Kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock;
1899
1900 /* Sanity check */
1901 ASSERT(Kcb != NULL);
1902
1903 /* Fail if the key was marked as deleted */
1904 if (Kcb->Delete)
1905 return STATUS_KEY_DELETED;
1906
1907 /* Lookup in the cache */
1909 &Kcb,
1910 &Current,
1911 &Hive,
1912 &Cell,
1913 &TotalRemainingSubkeys,
1914 &MatchRemainSubkeyLevel,
1915 &TotalSubkeys,
1916 LockedKcbArray,
1917 &LockedKcbs);
1919 if (!NT_SUCCESS(Status))
1920 {
1921 DPRINT1("Failed to look in cache, stop parsing (Status 0x%lx)\n", Status);
1922 ParentKcb = NULL;
1923 goto Quickie;
1924 }
1925
1926 /* This is now the parent */
1927 ParentKcb = Kcb;
1928
1929 /* Sanity check */
1930 ASSERT(ParentKcb != NULL);
1931
1932 /* Don't do anything if we're being deleted */
1933 if (Kcb->Delete)
1934 {
1936 goto Quickie;
1937 }
1938
1939 /* Check if everything was found cached */
1940 if (!TotalRemainingSubkeys)
1941 {
1942 /*
1943 * We don't have any remaining subkey levels so we're good
1944 * that we have an already perfect candidate for a KCB, just
1945 * do the open directly.
1946 */
1947 DPRINT("No remaining subkeys, the KCB points to the actual key\n");
1948 IsKeyCached = TRUE;
1949 goto KeyCachedOpenNow;
1950 }
1951
1952 /* Check if we have a matching level */
1953 if (MatchRemainSubkeyLevel)
1954 {
1955 /*
1956 * We have a matching level, check if that matches
1957 * with the total levels of subkeys. Do the open directly
1958 * if that is the case, because the whole subkeys levels
1959 * is cached.
1960 */
1961 if (MatchRemainSubkeyLevel == TotalSubkeys)
1962 {
1963 DPRINT("We have a full matching level, open the key now\n");
1964 IsKeyCached = TRUE;
1965 goto KeyCachedOpenNow;
1966 }
1967
1968 /*
1969 * We only have a partial match, make sure we did not
1970 * get mismatched hive data.
1971 */
1972 ASSERT(Hive == Kcb->KeyHive);
1973 ASSERT(Cell == Kcb->KeyCell);
1974 }
1975
1976 /*
1977 * FIXME: Currently the registry parser doesn't check for fake
1978 * KCBs. CmpCreateKeyControlBlock does have the necessary implementation
1979 * to create such fake keys but we don't create these fake keys anywhere.
1980 * When we will do, we must improve the registry parser routine to handle
1981 * fake keys a bit differently here.
1982 */
1983
1984 /* Check if this is a symlink */
1985 if (Kcb->Flags & KEY_SYM_LINK)
1986 {
1987 /* Get the next name */
1988 Result = CmpGetNextName(&Current, &NextName, &Last);
1989 Current.Buffer = NextName.Buffer;
1990
1991 /* Validate the current name string length */
1992 if (Current.Length + NextName.Length > MAXUSHORT)
1993 {
1994 /* too long */
1996 goto Quickie;
1997 }
1998 Current.Length += NextName.Length;
1999
2000 /* Validate the current name string maximum length */
2001 if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
2002 {
2003 /* too long */
2005 goto Quickie;
2006 }
2007 Current.MaximumLength += NextName.MaximumLength;
2008
2009 /* CmpGetSymbolicLink doesn't want a lock */
2010 CmpUnLockKcbArray(LockedKcbs);
2011 LockedKcbs = NULL;
2012
2013 /* Parse the symlink */
2014 if (CmpGetSymbolicLink(Hive,
2015 CompleteName,
2016 Kcb,
2017 &Current))
2018 {
2019 /* Symlink parse succeeded */
2021 }
2022 else
2023 {
2024 /* Couldn't find symlink */
2026 }
2027
2028 /* We're done */
2029 goto Quickie;
2030 }
2031
2032 /* Get the key node */
2033 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
2034 if (!Node)
2035 {
2037 goto Quickie;
2038 }
2039
2040 /* Start parsing */
2042 while (TRUE)
2043 {
2044 /* Get the next component */
2045 Result = CmpGetNextName(&Current, &NextName, &Last);
2046 if (Result && NextName.Length)
2047 {
2048 /* See if this is a sym link */
2049 if (!(Kcb->Flags & KEY_SYM_LINK))
2050 {
2051 /* Find the subkey */
2052 NextCell = CmpFindSubKeyByName(Hive, Node, &NextName);
2053 if (NextCell != HCELL_NIL)
2054 {
2055 /* Get the new node */
2056 Cell = NextCell;
2057 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
2058 ASSERT(Node);
2059
2060 /* Check if this was the last key */
2061 if (Last)
2062 {
2063 /* Is this an exit node */
2064 if (Node->Flags & KEY_HIVE_EXIT)
2065 {
2066 /* Handle it */
2067 CmpHandleExitNode(&Hive,
2068 &Cell,
2069 &Node,
2070 &HiveToRelease,
2071 &CellToRelease);
2072 if (!Node)
2073 {
2074 /* Fail */
2076 break;
2077 }
2078 }
2079
2080KeyCachedOpenNow:
2081 /* Do the open */
2082 Status = CmpDoOpen(Hive,
2083 Cell,
2084 Node,
2086 AccessMode,
2087 Attributes,
2088 ParseContext,
2090 &Kcb,
2091 LockedKcbs,
2092 &NextName,
2093 Object);
2094 if (Status == STATUS_REPARSE)
2095 {
2096 /* CmpGetSymbolicLink doesn't want a lock */
2097 CmpUnLockKcbArray(LockedKcbs);
2098 LockedKcbs = NULL;
2099
2100 /* Parse the symlink */
2101 if (!CmpGetSymbolicLink(Hive,
2102 CompleteName,
2103 Kcb,
2104 NULL))
2105 {
2106 /* Symlink parse failed */
2108 }
2109 }
2110
2111 /* We are done */
2112 break;
2113 }
2114
2115 /* Is this an exit node */
2116 if (Node->Flags & KEY_HIVE_EXIT)
2117 {
2118 /* Handle it */
2119 CmpHandleExitNode(&Hive,
2120 &Cell,
2121 &Node,
2122 &HiveToRelease,
2123 &CellToRelease);
2124 if (!Node)
2125 {
2126 /* Fail */
2128 break;
2129 }
2130 }
2131
2132 /* Create a KCB for this key */
2133 Kcb = CmpCreateKeyControlBlock(Hive,
2134 Cell,
2135 Node,
2136 ParentKcb,
2138 &NextName);
2139 if (!Kcb)
2140 {
2141 /* Fail */
2143 break;
2144 }
2145
2146 /* Dereference the parent and set the new one */
2148 ParentKcb = Kcb;
2149 }
2150 else
2151 {
2152 /* Check if this was the last key for a create */
2153 if (Last && ParseContext)
2154 {
2155 /* Check if we're doing a link node */
2156 if (ParseContext->CreateLink)
2157 {
2158 /* The only thing we should see */
2160 Cell,
2162 NextName,
2163 AccessMode,
2164 Attributes,
2165 ParseContext,
2166 ParentKcb,
2167 LockedKcbs,
2168 Object);
2169 }
2170 else if (Hive == &CmiVolatileHive->Hive && CmpNoVolatileCreates)
2171 {
2172 /* Creating keys in the master hive is not allowed */
2174 }
2175 else
2176 {
2177 /* Do the create */
2178 Status = CmpDoCreate(Hive,
2179 Cell,
2181 &NextName,
2182 AccessMode,
2183 ParseContext,
2184 ParentKcb,
2185 Object);
2186 }
2187
2188 /* Check for reparse (in this case, someone beat us) */
2189 if (Status == STATUS_REPARSE) break;
2190
2191 /* Update disposition */
2192 ParseContext->Disposition = REG_CREATED_NEW_KEY;
2193 break;
2194 }
2195 else
2196 {
2197 /* Key not found */
2199 break;
2200 }
2201 }
2202 }
2203 else
2204 {
2205 /* Save the next name */
2206 Current.Buffer = NextName.Buffer;
2207
2208 /* Validate the current name string length */
2209 if (Current.Length + NextName.Length > MAXUSHORT)
2210 {
2211 /* too long */
2213 break;
2214 }
2215 Current.Length += NextName.Length;
2216
2217 /* Validate the current name string maximum length */
2218 if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
2219 {
2220 /* too long */
2222 break;
2223 }
2224 Current.MaximumLength += NextName.MaximumLength;
2225
2226 /* CmpGetSymbolicLink doesn't want a lock */
2227 CmpUnLockKcbArray(LockedKcbs);
2228 LockedKcbs = NULL;
2229
2230 /* Parse the symlink */
2231 if (CmpGetSymbolicLink(Hive,
2232 CompleteName,
2233 Kcb,
2234 &Current))
2235 {
2236 /* Symlink parse succeeded */
2238 }
2239 else
2240 {
2241 /* Couldn't find symlink */
2243 }
2244
2245 /* We're done */
2246 break;
2247 }
2248 }
2249 else if (Result && Last)
2250 {
2251 /* Opening the root. Is this an exit node? */
2252 if (Node->Flags & KEY_HIVE_EXIT)
2253 {
2254 /* Handle it */
2255 CmpHandleExitNode(&Hive,
2256 &Cell,
2257 &Node,
2258 &HiveToRelease,
2259 &CellToRelease);
2260 if (!Node)
2261 {
2262 /* Fail */
2264 break;
2265 }
2266 }
2267
2268 /* Do the open */
2269 Status = CmpDoOpen(Hive,
2270 Cell,
2271 Node,
2273 AccessMode,
2274 Attributes,
2275 ParseContext,
2277 &Kcb,
2278 LockedKcbs,
2279 &NextName,
2280 Object);
2281 if (Status == STATUS_REPARSE)
2282 {
2283 /* Nothing to do */
2284 }
2285
2286 /* We're done */
2287 break;
2288 }
2289 else
2290 {
2291 /* Bogus */
2293 break;
2294 }
2295 }
2296
2297Quickie:
2298 /* Unlock all the KCBs */
2299 if (LockedKcbs != NULL)
2300 {
2301 CmpUnLockKcbArray(LockedKcbs);
2302 }
2303
2304 /* Dereference the parent if it exists */
2305 if (ParentKcb)
2307
2308 /* Unlock the registry */
2310 return Status;
2311}
#define PAGED_CODE()
#define CMP_KCBS_IN_ARRAY_LIMIT
Definition: cm.h:132
#define CMP_ASSERT_REGISTRY_LOCK()
Definition: cm_x.h:65
NTSTATUS NTAPI CmpBuildHashStackAndLookupCache(_In_ PCM_KEY_BODY ParseObject, _Inout_ PCM_KEY_CONTROL_BLOCK *Kcb, _In_ PUNICODE_STRING Current, _Out_ PHHIVE *Hive, _Out_ PHCELL_INDEX Cell, _Out_ PULONG TotalRemainingSubkeys, _Out_ PULONG MatchRemainSubkeyLevel, _Out_ PULONG TotalSubkeys, _Inout_ PULONG OuterStackArray, _Out_ PULONG *LockedKcbs)
Builds a hash stack cache and looks up in the pool cache for a matching key pathname.
Definition: cmparse.c:1696
BOOLEAN NTAPI CmpGetSymbolicLink(IN PHHIVE Hive, IN OUT PUNICODE_STRING ObjectName, IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb, IN PUNICODE_STRING RemainingName OPTIONAL)
Definition: cmparse.c:75
NTSTATUS NTAPI CmpCreateLinkNode(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PACCESS_STATE AccessState, IN UNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN ULONG CreateOptions, IN PCM_PARSE_CONTEXT Context, IN PCM_KEY_CONTROL_BLOCK ParentKcb, IN PULONG KcbsLocked, OUT PVOID *Object)
Definition: cmparse.c:830
VOID NTAPI CmpHandleExitNode(IN OUT PHHIVE *Hive, IN OUT HCELL_INDEX *Cell, IN OUT PCM_KEY_NODE *KeyNode, IN OUT PHHIVE *ReleaseHive, IN OUT HCELL_INDEX *ReleaseCell)
Definition: cmparse.c:1080
NTSTATUS NTAPI CmpDoCreate(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PACCESS_STATE AccessState, IN PUNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN PCM_PARSE_CONTEXT ParseContext, IN PCM_KEY_CONTROL_BLOCK ParentKcb, OUT PVOID *Object)
Definition: cmparse.c:404
BOOLEAN NTAPI CmpGetNextName(IN OUT PUNICODE_STRING RemainingName, OUT PUNICODE_STRING NextName, OUT PBOOLEAN LastName)
Definition: cmparse.c:21
VOID NTAPI CmpUnlockRegistry(VOID)
Definition: cmsysini.c:2056
BOOLEAN CmpNoVolatileCreates
Definition: cmsysini.c:34
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
#define STATUS_OBJECT_TYPE_MISMATCH
Definition: d3dkmdt.h:46
ObjectType
Definition: metafile.c:81
#define REG_CREATED_NEW_KEY
Definition: nt_native.h:1084
#define STATUS_KEY_DELETED
Definition: ntstatus.h:613
ULONG Disposition
Definition: cm.h:440
BOOLEAN CreateLink
Definition: cm.h:443
BOOLEAN CreateOperation
Definition: cm.h:444
#define MAXUSHORT
Definition: typedefs.h:83
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135

Referenced by CmpCreateObjectTypes().

◆ CmpRemoveSubkeysInRemainingName()

static VOID CmpRemoveSubkeysInRemainingName ( _In_ PCM_HASH_CACHE_STACK  HashCacheStack,
_In_ ULONG  RemainingSubkeys,
_Inout_ PUNICODE_STRING  RemainingName 
)
static

Removes the subkeys on a remaining key pathname.

Parameters
[in]HashCacheStackA pointer to a hash cache stack array filled with subkey hashes and names.
[in]RemainingSubkeysThe remaining subkey levels to be supplied.
[in,out]RemainingNameA Unicode string structure consisting of the remaining registry key path name, where the subkeys of such path are to be removed.

Definition at line 1361 of file cmparse.c.

1365{
1366 ULONG HashStackIndex = 0;
1367
1368 /* Skip any leading separator on matching name */
1369 while (RemainingName->Length >= sizeof(WCHAR) &&
1371 {
1372 RemainingName->Buffer++;
1373 RemainingName->Length -= sizeof(WCHAR);
1374 }
1375
1376 /* Skip the subkeys as well */
1377 while (HashStackIndex <= RemainingSubkeys)
1378 {
1379 RemainingName->Buffer += HashCacheStack[HashStackIndex].NameOfKey.Length / sizeof(WCHAR);
1380 RemainingName->Length -= HashCacheStack[HashStackIndex].NameOfKey.Length;
1381
1382 /* Skip any leading separator */
1383 while (RemainingName->Length >= sizeof(WCHAR) &&
1385 {
1386 RemainingName->Buffer++;
1387 RemainingName->Length -= sizeof(WCHAR);
1388 }
1389
1390 /* Go to the next hash */
1391 HashStackIndex++;
1392 }
1393}

Referenced by CmpLookInCache().