ReactOS 0.4.17-dev-683-g0dafdc5
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 1717 of file cmparse.c.

1728{
1730 ULONG ConvKey;
1731 ULONG SubkeysInTotal, RemainingSubkeysInTotal, MatchRemainingSubkeys;
1733
1734 /* Make sure it's not a dead KCB */
1735 ASSERT((*Kcb)->RefCount > 0);
1736
1737 /* Lock the registry */
1739
1740 /* Calculate hash values for every subkey this key path has */
1741 ConvKey = (*Kcb)->ConvKey;
1742 RemainingSubkeysInTotal = CmpComputeHashValue(Current,
1743 ConvKey,
1744 HashCacheStack,
1745 &SubkeysInTotal);
1746
1747 /* This key path has too many subkeys */
1748 if (SubkeysInTotal > CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1749 {
1750 DPRINT1("The key path has too many subkeys - %lu\n", SubkeysInTotal);
1751 *LockedKcbs = NULL;
1752 return STATUS_NAME_TOO_LONG;
1753 }
1754
1755 /* Return hive and cell data */
1756 *Hive = (*Kcb)->KeyHive;
1757 *Cell = (*Kcb)->KeyCell;
1758
1759 /* Do we have any subkeys? */
1760 if (!RemainingSubkeysInTotal && !SubkeysInTotal)
1761 {
1762 /*
1763 * We don't have any subkeys nor remaining levels, the
1764 * KCB points to the actual key. Lock it.
1765 */
1766 if (!CmpReferenceKeyControlBlock(*Kcb))
1767 {
1768 /* This key is opened too many times, bail out */
1769 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1770 return STATUS_UNSUCCESSFUL;
1771 }
1772
1774
1775 /* Add this KCB in the array of locked KCBs */
1776 OuterStackArray[0] = 1;
1777 OuterStackArray[1] = GET_HASH_INDEX(ConvKey);
1778 *LockedKcbs = OuterStackArray;
1779
1780 /* And return all the subkey level counters */
1781 *TotalRemainingSubkeys = RemainingSubkeysInTotal;
1782 *MatchRemainSubkeyLevel = 0;
1783 *TotalSubkeys = SubkeysInTotal;
1784 return STATUS_SUCCESS;
1785 }
1786
1787 /* Lookup in the cache */
1788 Status = CmpLookInCache(HashCacheStack,
1789 FALSE,
1790 RemainingSubkeysInTotal,
1791 Current,
1792 OuterStackArray,
1793 Kcb,
1794 Hive,
1795 Cell,
1796 &MatchRemainingSubkeys);
1797 if (!NT_SUCCESS(Status))
1798 {
1799 /* Bail out if cache lookup failed for other reasons */
1800 if (Status != STATUS_RETRY)
1801 {
1802 DPRINT1("CmpLookInCache() failed (Status 0x%lx)\n", Status);
1803 *LockedKcbs = NULL;
1804 return Status;
1805 }
1806
1807 /* Retry looking in the cache but with KCBs locked exclusively */
1808 Status = CmpLookInCache(HashCacheStack,
1809 TRUE,
1810 RemainingSubkeysInTotal,
1811 Current,
1812 OuterStackArray,
1813 Kcb,
1814 Hive,
1815 Cell,
1816 &MatchRemainingSubkeys);
1817 if (!NT_SUCCESS(Status))
1818 {
1819 DPRINT1("CmpLookInCache() failed after retry (Status 0x%lx)\n", Status);
1820 *LockedKcbs = NULL;
1821 return Status;
1822 }
1823 }
1824
1825 /*
1826 * Check if we have a full match of remaining levels.
1827 *
1828 * FIXME: It is possible we can catch a fake key from the cache
1829 * when we did the lookup, in such case we should not do any
1830 * locking as such KCB does not point to any real information.
1831 * Currently ReactOS doesn't create fake KCBs so we are good
1832 * for now.
1833 */
1834 if (RemainingSubkeysInTotal == MatchRemainingSubkeys)
1835 {
1836 /*
1837 * Just simply lock this KCB as it points to the full
1838 * subkey levels in cache.
1839 */
1841 OuterStackArray[0] = 1;
1842 OuterStackArray[1] = GET_HASH_INDEX((*Kcb)->ConvKey);
1843 *LockedKcbs = OuterStackArray;
1844 }
1845 else
1846 {
1847 /*
1848 * We only have a partial match so other subkey levels
1849 * have each KCB. Simply just lock them.
1850 */
1851 *LockedKcbs = CmpBuildAndLockKcbArray(HashCacheStack,
1853 *Kcb,
1854 OuterStackArray,
1855 RemainingSubkeysInTotal,
1856 MatchRemainingSubkeys);
1857 NT_ASSERT(*LockedKcbs);
1858 }
1859
1860 /* Return all the subkey level counters */
1861 *TotalRemainingSubkeys = RemainingSubkeysInTotal;
1862 *MatchRemainSubkeyLevel = MatchRemainingSubkeys;
1863 *TotalSubkeys = SubkeysInTotal;
1864 return Status;
1865}
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:1470
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:1151
VOID NTAPI CmpLockRegistry(VOID)
Definition: cmsysini.c:1995
#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:24
#define ASSERT(a)
Definition: mode.c:44
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:592
#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 1294 of file cmparse.c.

1299{
1300 LONG HashStackIndex;
1301 LONG Result;
1302 PCM_NAME_CONTROL_BLOCK NameBlock;
1303 UNICODE_STRING CurrentNameBlock;
1304
1305 ASSERT(CurrentKcb != NULL);
1306
1307 /* Loop each hash and check that they match */
1308 HashStackIndex = RemainingSubkeys;
1309 while (HashStackIndex >= 0)
1310 {
1311 /* Does the subkey hash match? */
1312 if (CurrentKcb->ConvKey != HashCacheStack[HashStackIndex].ConvKey)
1313 {
1314 *ParentKcb = CurrentKcb;
1315 return FALSE;
1316 }
1317
1318 /* Compare the subkey string, is the name compressed? */
1319 NameBlock = CurrentKcb->NameBlock;
1320 if (NameBlock->Compressed)
1321 {
1322 Result = CmpCompareCompressedName(&HashCacheStack[HashStackIndex].NameOfKey,
1323 NameBlock->Name,
1324 NameBlock->NameLength);
1325 }
1326 else
1327 {
1328 CurrentNameBlock.Buffer = NameBlock->Name;
1329 CurrentNameBlock.Length = NameBlock->NameLength;
1330 CurrentNameBlock.MaximumLength = NameBlock->NameLength;
1331
1332 Result = RtlCompareUnicodeString(&HashCacheStack[HashStackIndex].NameOfKey,
1333 &CurrentNameBlock,
1334 TRUE);
1335 }
1336
1337 /* Do the subkey names match? */
1338 if (Result)
1339 {
1340 *ParentKcb = CurrentKcb;
1341 return FALSE;
1342 }
1343
1344 /* Go to the next subkey hash */
1345 HashStackIndex--;
1346 }
1347
1348 /* All the subkeys match */
1349 *ParentKcb = CurrentKcb->ParentKcb;
1350 return TRUE;
1351}
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 1151 of file cmparse.c.

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

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 840 of file cmparse.c.

850{
852 HCELL_INDEX KeyCell, LinkCell, ChildCell;
853 PCM_KEY_BODY KeyBody;
855 PCM_KEY_NODE KeyNode;
856 PCM_KEY_CONTROL_BLOCK Kcb = ParentKcb;
857
858 /* Link nodes only allowed on the master */
859 if (Hive != &CmiVolatileHive->Hive)
860 {
861 /* Fail */
862 DPRINT1("Invalid link node attempt\n");
864 }
865
866 /* Make sure the KCB is locked and lock the flusher */
867 CMP_ASSERT_KCB_LOCK(ParentKcb);
869 CmpLockHiveFlusherShared((PCMHIVE)Context->ChildHive.KeyHive);
870
871 /* Bail out on read-only KCBs */
872 if (ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY)
873 {
875 goto Exit;
876 }
877
878 /* Check if the parent is being deleted */
879 if (ParentKcb->Delete)
880 {
881 /* It is, quit */
882 ASSERT(FALSE);
884 goto Exit;
885 }
886
887 /* Allocate a link node */
888 LinkCell = HvAllocateCell(Hive,
890 CmpNameSize(Hive, &Name),
891 Stable,
892 HCELL_NIL);
893 if (LinkCell == HCELL_NIL)
894 {
895 /* Fail */
897 goto Exit;
898 }
899
900 /* Get the key cell */
901 KeyCell = Context->ChildHive.KeyCell;
902 if (KeyCell != HCELL_NIL)
903 {
904 /* Hive exists! */
905 ChildCell = KeyCell;
906
907 /* Get the node data */
908 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);
909 if (!KeyNode)
910 {
911 /* Fail */
912 ASSERT(FALSE);
914 goto Exit;
915 }
916
917 /* Fill out the data */
918 KeyNode->Parent = LinkCell;
919 KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
920 HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
921
922 /* Now open the key cell */
923 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, KeyCell);
924 if (!KeyNode)
925 {
926 /* Fail */
927 ASSERT(FALSE);
929 goto Exit;
930 }
931
932 /* Open the parent */
933 Status = CmpDoOpen(Context->ChildHive.KeyHive,
934 KeyCell,
935 KeyNode,
939 NULL,
941 &Kcb,
942 KcbsLocked,
943 &Name,
944 Object);
945 HvReleaseCell(Context->ChildHive.KeyHive, KeyCell);
946 }
947 else
948 {
949 /* Do the actual create operation */
950 Status = CmpDoCreateChild(Context->ChildHive.KeyHive,
951 Cell,
952 NULL,
954 &Name,
956 Context,
957 ParentKcb,
959 &ChildCell,
960 Object);
961 if (NT_SUCCESS(Status))
962 {
963 /* Setup root pointer */
964 Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell;
965 }
966 }
967
968 /* Check if open or create suceeded */
969 if (NT_SUCCESS(Status))
970 {
971 /* Mark the cell dirty */
972 HvMarkCellDirty(Context->ChildHive.KeyHive, ChildCell, FALSE);
973
974 /* Get the key node */
975 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);
976 if (!KeyNode)
977 {
978 /* Fail */
979 ASSERT(FALSE);
981 goto Exit;
982 }
983
984 /* Release it */
985 HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
986
987 /* Set the parent and flags */
988 KeyNode->Parent = LinkCell;
989 KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
990
991 /* Get the link node */
992 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, LinkCell);
993 if (!KeyNode)
994 {
995 /* Fail */
996 ASSERT(FALSE);
998 goto Exit;
999 }
1000
1001 /* Set it up */
1003 KeyNode->Flags = KEY_HIVE_EXIT | KEY_NO_DELETE;
1004 KeyNode->Parent = Cell;
1005 KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, &Name);
1006 if (KeyNode->NameLength < Name.Length) KeyNode->Flags |= KEY_COMP_NAME;
1008 KeyNode->LastWriteTime = TimeStamp;
1009
1010 /* Clear out the rest */
1011 KeyNode->SubKeyCounts[Stable] = 0;
1012 KeyNode->SubKeyCounts[Volatile] = 0;
1013 KeyNode->SubKeyLists[Stable] = HCELL_NIL;
1014 KeyNode->SubKeyLists[Volatile] = HCELL_NIL;
1015 KeyNode->ValueList.Count = 0;
1016 KeyNode->ValueList.List = HCELL_NIL;
1017 KeyNode->ClassLength = 0;
1018
1019 /* Reference the root node */
1020 KeyNode->ChildHiveReference.KeyHive = Context->ChildHive.KeyHive;
1021 KeyNode->ChildHiveReference.KeyCell = ChildCell;
1022 HvReleaseCell(Hive, LinkCell);
1023
1024 /* Get the parent node */
1025 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
1026 if (!KeyNode)
1027 {
1028 /* Fail */
1029 ASSERT(FALSE);
1031 goto Exit;
1032 }
1033
1034 /* Now add the subkey */
1035 if (!CmpAddSubKey(Hive, Cell, LinkCell))
1036 {
1037 /* Failure! We don't handle this yet! */
1038 ASSERT(FALSE);
1039 }
1040
1041 /* Get the key body */
1042 KeyBody = (PCM_KEY_BODY)*Object;
1043
1044 /* Clean up information on this subkey */
1045 CmpCleanUpSubKeyInfo(KeyBody->KeyControlBlock->ParentKcb);
1046
1047 /* Sanity checks */
1048 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell);
1049 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive);
1050 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen);
1051
1052 /* Update the timestamp */
1054 KeyNode->LastWriteTime = TimeStamp;
1055 KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
1056
1057 /* Check if we need to update name maximum */
1058 if (KeyNode->MaxNameLen < Name.Length)
1059 {
1060 /* Do it */
1061 KeyNode->MaxNameLen = Name.Length;
1062 KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name.Length;
1063 }
1064
1065 /* Check if we need to update class length maximum */
1066 if (KeyNode->MaxClassLen < Context->Class.Length)
1067 {
1068 /* Update it */
1069 KeyNode->MaxClassLen = Context->Class.Length;
1070 }
1071
1072 /* Release the cell */
1073 HvReleaseCell(Hive, Cell);
1074 }
1075 else
1076 {
1077 /* Release the link cell */
1078 HvReleaseCell(Hive, LinkCell);
1079 }
1080
1081Exit:
1082 /* Release the flusher locks and return status */
1083 CmpUnlockHiveFlusher((PCMHIVE)Context->ChildHive.KeyHive);
1085 return Status;
1086}
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:2042
PCMHIVE CmiVolatileHive
Definition: cmsysini.c:16
VOID NTAPI CmpUnlockHiveFlusher(IN PCMHIVE Hive)
Definition: cmsysini.c:2053
LPWSTR Name
Definition: desk.c:124
#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
_In_ PVOID Context
Definition: storport.h:2269
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:1066
#define REG_OPTION_VOLATILE
Definition: nt_native.h:1063
#define STATUS_REPARSE
Definition: ntstatus.h:136
#define STATUS_CHILD_MUST_BE_VOLATILE
Definition: ntstatus.h:712
VOID NTAPI ObDereferenceObjectDeferDelete(IN PVOID Object)
Definition: obref.c:357
union _CELL_DATA::@4795 u
CM_KEY_NODE KeyNode
Definition: cmdata.h:200
_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.cpp:179
#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:1040
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 */
671 Kcb = (*CachedKcb)->ValueCache.RealKcb;
672
673 /* Before we drop all locks, we need to reference the real KCB */
675 {
676 DPRINT("Failed to reference the real KCB, attempt a reparse\n");
677 return STATUS_REPARSE;
678 }
679
680 /*
681 * Lock the real KCB of the symlink exclusively, we don't want anybody
682 * to mess it up.
683 */
684 CmpUnLockKcbArray(KcbsLocked);
685 KcbsLocked[0] = 1;
686 KcbsLocked[1] = GET_HASH_INDEX(Kcb->ConvKey);
688 IsLockShared = FALSE;
689
690 /* Was the real KCB deleted? */
691 if (Kcb->Delete)
692 {
693 /*
694 * The real KCB is gone, do a reparse. We used to lock the KCB in
695 * shared mode as others may have taken use of it but since we
696 * must do a reparse of the key the only thing that matter is us.
697 * Lock the KCB exclusively so nobody is going to mess with the KCB.
698 */
699 DPRINT1("The real KCB is deleted, attempt a reparse\n");
700 CmpUnLockKcbArray(KcbsLocked);
703 CmpCleanUpKcbValueCache(*CachedKcb);
704 KcbsLocked[0] = 1;
705 KcbsLocked[1] = GET_HASH_INDEX((*CachedKcb)->ConvKey);
706 return STATUS_REPARSE;
707 }
708 }
709 else
710 {
711 /* We must do a reparse */
712 DPRINT("The symlink is not found, attempt a reparse\n");
713 return STATUS_REPARSE;
714 }
715 }
716 else
717 {
718 /* This is not a symlink, just give the cached KCB already */
719 Kcb = *CachedKcb;
720
721 /* The caller wants to open a cached KCB */
723 {
724 /* Return failure code */
726 }
727 }
728 }
729 else
730 {
731 /*
732 * The caller wants to create a new KCB. Unlike the code path above, here
733 * we must check if the lock is exclusively held because in the scenario
734 * where the caller doesn't want to create a KCB is because it is already
735 * in the cache and it must have a shared lock instead.
736 */
737 ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
738
739 /* Check if this is a symlink */
740 if ((Node->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK))
741 {
742 /* Create the KCB for the symlink */
743 Kcb = CmpCreateKeyControlBlock(Hive,
744 Cell,
745 Node,
746 *CachedKcb,
747 LockKcb ? CMP_LOCK_HASHES_FOR_KCB : 0,
748 KeyName);
749 if (!Kcb)
750 {
751 /* Return failure */
753 }
754
755 /* Make sure it's also locked, and set the pointer */
757 *CachedKcb = Kcb;
758
759 /* Return reparse required */
760 return STATUS_REPARSE;
761 }
762
763 /* Create the KCB */
764 Kcb = CmpCreateKeyControlBlock(Hive,
765 Cell,
766 Node,
767 *CachedKcb,
768 LockKcb ? CMP_LOCK_HASHES_FOR_KCB : 0,
769 KeyName);
770 if (!Kcb)
771 {
772 /* Return failure */
774 }
775
776 /* Make sure it's also locked, and set the pointer */
778 *CachedKcb = Kcb;
779 }
780
781 /* Allocate the key object */
784 NULL,
786 NULL,
787 sizeof(CM_KEY_BODY),
788 0,
789 0,
790 Object);
791 if (NT_SUCCESS(Status))
792 {
793 /* Get the key body and fill it out */
794 KeyBody = (PCM_KEY_BODY)(*Object);
795 KeyBody->KeyControlBlock = Kcb;
796 KeyBody->Type = CM_KEY_BODY_TYPE;
797 KeyBody->ProcessID = PsGetCurrentProcessId();
798 KeyBody->NotifyBlock = NULL;
799
800 /* Link to the KCB */
802
803 /*
804 * We are already holding a lock against the KCB that is assigned
805 * to this key body. This is to prevent a potential deadlock on
806 * CmpSecurityMethod as ObCheckObjectAccess will invoke the Object
807 * Manager to call that method, of which CmpSecurityMethod would
808 * attempt to acquire a lock again.
809 */
810 KeyBody->KcbLocked = TRUE;
811
814 FALSE,
816 &Status))
817 {
818 /* Access check failed */
820 }
821
822 /*
823 * We are done, the lock we are holding will be released
824 * once the registry parsing is done.
825 */
826 KeyBody->KcbLocked = FALSE;
827 }
828 else
829 {
830 /* Failed, dereference the KCB */
832 }
833
834 /* Return status */
835 return Status;
836}
unsigned char BOOLEAN
Definition: actypes.h:127
#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
VOID NTAPI CmpDereferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:571
#define KeGetCurrentThread
Definition: hal.h:55
#define HIVE_IS_UNLOADING
Definition: hivedata.h:28
#define REG_OPENED_EXISTING_KEY
Definition: nt_native.h:1088
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 OBJ_OPENLINK
Definition: winternl.h:230
#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:2705

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:1503
#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 1090 of file cmparse.c.

1095{
1096 /* Check if we have anything to release */
1097 if (*ReleaseCell != HCELL_NIL)
1098 {
1099 /* Release it */
1100 ASSERT(*ReleaseHive != NULL);
1101 HvReleaseCell(*ReleaseHive, *ReleaseCell);
1102 }
1103
1104 /* Get the link references */
1105 *Hive = (*KeyNode)->ChildHiveReference.KeyHive;
1106 *Cell = (*KeyNode)->ChildHiveReference.KeyCell;
1107
1108 /* Get the new node */
1109 *KeyNode = (PCM_KEY_NODE)HvGetCell(*Hive, *Cell);
1110 if (*KeyNode)
1111 {
1112 /* Set the new release values */
1113 *ReleaseCell = *Cell;
1114 *ReleaseHive = *Hive;
1115 }
1116 else
1117 {
1118 /* Nothing to release */
1119 *ReleaseCell = HCELL_NIL;
1120 *ReleaseHive = NULL;
1121 }
1122}

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 1470 of file cmparse.c.

1480{
1481 LONG RemainingSubkeys;
1482 ULONG TotalLevels;
1483 BOOLEAN SubkeysMatch;
1484 PCM_KEY_CONTROL_BLOCK CurrentKcb, ParentKcb;
1486 BOOLEAN KeyFoundInCache = FALSE;
1487 PULONG LockedKcbs = NULL;
1488
1489 /* Reference the KCB */
1490 if (!CmpReferenceKeyControlBlock(*Kcb))
1491 {
1492 /* This key is opened too many times, bail out */
1493 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1494 return STATUS_UNSUCCESSFUL;
1495 }
1496
1497 /* Prepare to lock the KCBs */
1498 LockedKcbs = CmpBuildAndLockKcbArray(HashCacheStack,
1500 *Kcb,
1501 OuterStackArray,
1502 TotalRemainingSubkeys,
1503 0);
1504 NT_ASSERT(LockedKcbs);
1505
1506 /* Lookup in the cache */
1507 RemainingSubkeys = TotalRemainingSubkeys - 1;
1508 TotalLevels = TotalRemainingSubkeys + (*Kcb)->TotalLevels + 1;
1509 while (RemainingSubkeys >= 0)
1510 {
1511 /* Get the hash entry from the cache */
1512 HashEntry = GET_HASH_ENTRY(CmpCacheTable, HashCacheStack[RemainingSubkeys].ConvKey)->Entry;
1513
1514 /* Take one level down as we are processing this hash entry */
1515 TotalLevels--;
1516
1517 while (HashEntry != NULL)
1518 {
1519 /* Validate this hash and obtain the current KCB */
1522
1523 /* Does this KCB have matching levels? */
1524 if (TotalLevels == CurrentKcb->TotalLevels)
1525 {
1526 /*
1527 * We have matching subkey levels but don't directly assume we have
1528 * a matching key path in cache. Start comparing each subkey.
1529 */
1530 SubkeysMatch = CmpCompareSubkeys(HashCacheStack,
1531 CurrentKcb,
1532 RemainingSubkeys,
1533 &ParentKcb);
1534 if (SubkeysMatch)
1535 {
1536 /* All subkeys match, now check if the base KCB matches with parent */
1537 if (*Kcb == ParentKcb)
1538 {
1539 /* Is the KCB marked as deleted? */
1540 if (CurrentKcb->Delete ||
1541 CurrentKcb->ParentKcb->Delete)
1542 {
1543 /*
1544 * Either the current or its parent KCB is marked
1545 * but we had a shared lock so probably a naughty
1546 * thread was deleting it. Retry doing a cache
1547 * lookup again with exclusive lock.
1548 */
1549 if (!LockKcbsExclusive)
1550 {
1551 CmpUnLockKcbArray(LockedKcbs);
1553 DPRINT1("The current KCB or its parent is deleted, retrying looking in the cache\n");
1554 return STATUS_RETRY;
1555 }
1556
1557 /* We're under an exclusive lock, is the KCB deleted yet? */
1558 if (CurrentKcb->Delete)
1559 {
1560 /* The KCB is gone, the key should no longer belong in the cache */
1561 CmpRemoveKeyControlBlock(CurrentKcb);
1562 CmpUnLockKcbArray(LockedKcbs);
1564 DPRINT1("The current KCB is deleted (KCB 0x%p)\n", CurrentKcb);
1566 }
1567
1568 /*
1569 * The parent is deleted so it must be that somebody created
1570 * a fake key. Assert ourselves that is the case.
1571 */
1572 ASSERT(CurrentKcb->ExtFlags & CM_KCB_KEY_NON_EXIST);
1573
1574 /* Remove this KCB out of cache if someone still uses it */
1575 if (CurrentKcb->RefCount != 0)
1576 {
1577 CurrentKcb->Delete = TRUE;
1578 CmpRemoveKeyControlBlock(CurrentKcb);
1579 }
1580 else
1581 {
1582 /* Otherwise expunge it */
1583 CmpRemoveFromDelayedClose(CurrentKcb);
1584 CmpCleanUpKcbCacheWithLock(CurrentKcb, FALSE);
1585 }
1586
1587 /* Stop looking for next hashes as the KCB is kaput */
1588 break;
1589 }
1590
1591 /* We finally found the key in cache, acknowledge it */
1592 KeyFoundInCache = TRUE;
1593
1594 /* Remove the subkeys in the remaining name and stop looking in the cache */
1595 CmpRemoveSubkeysInRemainingName(HashCacheStack, RemainingSubkeys, RemainingName);
1596 break;
1597 }
1598 }
1599 }
1600
1601 /* Go to the next hash */
1602 HashEntry = HashEntry->NextHash;
1603 }
1604
1605 /* Stop looking in cache if we found the matching key */
1606 if (KeyFoundInCache)
1607 {
1608 DPRINT("Key found in cache, stop looking\n");
1609 break;
1610 }
1611
1612 /* Keep looking in the cache until we run out of remaining subkeys */
1613 RemainingSubkeys--;
1614 }
1615
1616 /* Return the matching subkey levels */
1617 *MatchRemainSubkeyLevel = RemainingSubkeys + 1;
1618
1619 /* We have to update the KCB if the key was found in cache */
1620 if (KeyFoundInCache)
1621 {
1622 /*
1623 * Reference the new KCB before dropping the locks.
1624 */
1625 if (!CmpReferenceKeyControlBlock(CurrentKcb))
1626 {
1627 /* This key is opened too many times, bail out */
1628 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", CurrentKcb);
1629
1630 /*
1631 * Make sure to unlock the KCBs and release the KCB reference we took
1632 * at the start of the function, so that the caller sees a clean state.
1633 */
1634 CmpUnLockKcbArray(LockedKcbs);
1636 return STATUS_UNSUCCESSFUL;
1637 }
1638
1639 /*
1640 * Dereference the prior KCB that we no longer need
1641 * and switch to the newly referenced one.
1642 */
1643 CmpUnLockKcbArray(LockedKcbs);
1645 *Kcb = CurrentKcb;
1646
1647 /* Update hive and cell data from current KCB */
1648 *Hive = CurrentKcb->KeyHive;
1649 *Cell = CurrentKcb->KeyCell;
1650 return STATUS_SUCCESS;
1651 }
1652
1653 /* Unlock the KCBs */
1654 CmpUnLockKcbArray(LockedKcbs);
1655 return STATUS_SUCCESS;
1656}
#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
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:1294
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:1371
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 1869 of file cmparse.c.

1879{
1881 PCM_KEY_CONTROL_BLOCK Kcb, ParentKcb;
1882 PHHIVE Hive = NULL;
1884 HCELL_INDEX Cell = HCELL_NIL, NextCell;
1885 PHHIVE HiveToRelease = NULL;
1886 HCELL_INDEX CellToRelease = HCELL_NIL;
1887 UNICODE_STRING Current, NextName;
1888 PCM_PARSE_CONTEXT ParseContext = Context;
1889 ULONG TotalRemainingSubkeys = 0, MatchRemainSubkeyLevel = 0, TotalSubkeys = 0;
1890 ULONG LockedKcbArray[CMP_KCBS_IN_ARRAY_LIMIT];
1891 PULONG LockedKcbs;
1892 BOOLEAN IsKeyCached = FALSE;
1893 BOOLEAN Result, Last;
1894 PAGED_CODE();
1895
1896 /* Loop path separators at the end */
1897 while (RemainingName->Length &&
1898 (RemainingName->Buffer[(RemainingName->Length / sizeof(WCHAR)) - 1] ==
1900 {
1901 /* Remove path separator */
1902 RemainingName->Length -= sizeof(WCHAR);
1903 }
1904
1905 /* Fail if this isn't a key object */
1907
1908 /* Copy the remaining name */
1909 Current = *RemainingName;
1910
1911 /* Check if this is a create */
1912 if (!ParseContext || !ParseContext->CreateOperation)
1913 {
1914 /* It isn't, so no context */
1915 ParseContext = NULL;
1916 }
1917
1918 /* Grab the KCB */
1919 Kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock;
1920
1921 /* Sanity check */
1922 ASSERT(Kcb != NULL);
1923
1924 /* Fail if the key was marked as deleted */
1925 if (Kcb->Delete)
1926 return STATUS_KEY_DELETED;
1927
1928 /* Lookup in the cache */
1930 &Kcb,
1931 &Current,
1932 &Hive,
1933 &Cell,
1934 &TotalRemainingSubkeys,
1935 &MatchRemainSubkeyLevel,
1936 &TotalSubkeys,
1937 LockedKcbArray,
1938 &LockedKcbs);
1940 if (!NT_SUCCESS(Status))
1941 {
1942 DPRINT1("Failed to look in cache, stop parsing (Status 0x%lx)\n", Status);
1943 ParentKcb = NULL;
1944 goto Quickie;
1945 }
1946
1947 /* This is now the parent */
1948 ParentKcb = Kcb;
1949
1950 /* Sanity check */
1951 ASSERT(ParentKcb != NULL);
1952
1953 /* Don't do anything if we're being deleted */
1954 if (Kcb->Delete)
1955 {
1957 goto Quickie;
1958 }
1959
1960 /* Check if everything was found cached */
1961 if (!TotalRemainingSubkeys)
1962 {
1963 /*
1964 * We don't have any remaining subkey levels so we're good
1965 * that we have an already perfect candidate for a KCB, just
1966 * do the open directly.
1967 */
1968 DPRINT("No remaining subkeys, the KCB points to the actual key\n");
1969 IsKeyCached = TRUE;
1970 goto KeyCachedOpenNow;
1971 }
1972
1973 /* Check if we have a matching level */
1974 if (MatchRemainSubkeyLevel)
1975 {
1976 /*
1977 * We have a matching level, check if that matches
1978 * with the total levels of subkeys. Do the open directly
1979 * if that is the case, because the whole subkeys levels
1980 * is cached.
1981 */
1982 if (MatchRemainSubkeyLevel == TotalSubkeys)
1983 {
1984 DPRINT("We have a full matching level, open the key now\n");
1985 IsKeyCached = TRUE;
1986 goto KeyCachedOpenNow;
1987 }
1988
1989 /*
1990 * We only have a partial match, make sure we did not
1991 * get mismatched hive data.
1992 */
1993 ASSERT(Hive == Kcb->KeyHive);
1994 ASSERT(Cell == Kcb->KeyCell);
1995 }
1996
1997 /*
1998 * FIXME: Currently the registry parser doesn't check for fake
1999 * KCBs. CmpCreateKeyControlBlock does have the necessary implementation
2000 * to create such fake keys but we don't create these fake keys anywhere.
2001 * When we will do, we must improve the registry parser routine to handle
2002 * fake keys a bit differently here.
2003 */
2004
2005 /* Check if this is a symlink */
2006 if (Kcb->Flags & KEY_SYM_LINK)
2007 {
2008 /* Get the next name */
2009 Result = CmpGetNextName(&Current, &NextName, &Last);
2010 Current.Buffer = NextName.Buffer;
2011
2012 /* Validate the current name string length */
2013 if (Current.Length + NextName.Length > MAXUSHORT)
2014 {
2015 /* too long */
2017 goto Quickie;
2018 }
2019 Current.Length += NextName.Length;
2020
2021 /* Validate the current name string maximum length */
2022 if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
2023 {
2024 /* too long */
2026 goto Quickie;
2027 }
2028 Current.MaximumLength += NextName.MaximumLength;
2029
2030 /* CmpGetSymbolicLink doesn't want a lock */
2031 CmpUnLockKcbArray(LockedKcbs);
2032 LockedKcbs = NULL;
2033
2034 /* Parse the symlink */
2035 if (CmpGetSymbolicLink(Hive,
2036 CompleteName,
2037 Kcb,
2038 &Current))
2039 {
2040 /* Symlink parse succeeded */
2042 }
2043 else
2044 {
2045 /* Couldn't find symlink */
2047 }
2048
2049 /* We're done */
2050 goto Quickie;
2051 }
2052
2053 /* Get the key node */
2054 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
2055 if (!Node)
2056 {
2058 goto Quickie;
2059 }
2060
2061 /* Start parsing */
2063 while (TRUE)
2064 {
2065 /* Get the next component */
2066 Result = CmpGetNextName(&Current, &NextName, &Last);
2067 if (Result && NextName.Length)
2068 {
2069 /* See if this is a sym link */
2070 if (!(Kcb->Flags & KEY_SYM_LINK))
2071 {
2072 /* Find the subkey */
2073 NextCell = CmpFindSubKeyByName(Hive, Node, &NextName);
2074 if (NextCell != HCELL_NIL)
2075 {
2076 /* Get the new node */
2077 Cell = NextCell;
2078 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
2079 ASSERT(Node);
2080
2081 /* Check if this was the last key */
2082 if (Last)
2083 {
2084 /* Is this an exit node */
2085 if (Node->Flags & KEY_HIVE_EXIT)
2086 {
2087 /* Handle it */
2088 CmpHandleExitNode(&Hive,
2089 &Cell,
2090 &Node,
2091 &HiveToRelease,
2092 &CellToRelease);
2093 if (!Node)
2094 {
2095 /* Fail */
2097 break;
2098 }
2099 }
2100
2101KeyCachedOpenNow:
2102 /* Do the open */
2103 Status = CmpDoOpen(Hive,
2104 Cell,
2105 Node,
2107 AccessMode,
2108 Attributes,
2109 ParseContext,
2111 &Kcb,
2112 LockedKcbs,
2113 &NextName,
2114 Object);
2115 if (Status == STATUS_REPARSE)
2116 {
2117 /* CmpGetSymbolicLink doesn't want a lock */
2118 CmpUnLockKcbArray(LockedKcbs);
2119 LockedKcbs = NULL;
2120
2121 /* Parse the symlink */
2122 if (!CmpGetSymbolicLink(Hive,
2123 CompleteName,
2124 Kcb,
2125 NULL))
2126 {
2127 /* Symlink parse failed */
2129 }
2130 }
2131
2132 /* We are done */
2133 break;
2134 }
2135
2136 /* Is this an exit node */
2137 if (Node->Flags & KEY_HIVE_EXIT)
2138 {
2139 /* Handle it */
2140 CmpHandleExitNode(&Hive,
2141 &Cell,
2142 &Node,
2143 &HiveToRelease,
2144 &CellToRelease);
2145 if (!Node)
2146 {
2147 /* Fail */
2149 break;
2150 }
2151 }
2152
2153 /* Create a KCB for this key */
2154 Kcb = CmpCreateKeyControlBlock(Hive,
2155 Cell,
2156 Node,
2157 ParentKcb,
2159 &NextName);
2160 if (!Kcb)
2161 {
2162 /* Fail */
2164 break;
2165 }
2166
2167 /* Dereference the parent and set the new one */
2169 ParentKcb = Kcb;
2170 }
2171 else
2172 {
2173 /* Check if this was the last key for a create */
2174 if (Last && ParseContext)
2175 {
2176 /* Check if we're doing a link node */
2177 if (ParseContext->CreateLink)
2178 {
2179 /* The only thing we should see */
2181 Cell,
2183 NextName,
2184 AccessMode,
2185 Attributes,
2186 ParseContext,
2187 ParentKcb,
2188 LockedKcbs,
2189 Object);
2190 }
2191 else if (Hive == &CmiVolatileHive->Hive && CmpNoVolatileCreates)
2192 {
2193 /* Creating keys in the master hive is not allowed */
2195 }
2196 else
2197 {
2198 /* Do the create */
2199 Status = CmpDoCreate(Hive,
2200 Cell,
2202 &NextName,
2203 AccessMode,
2204 ParseContext,
2205 ParentKcb,
2206 Object);
2207 }
2208
2209 /* Check for reparse (in this case, someone beat us) */
2210 if (Status == STATUS_REPARSE) break;
2211
2212 /* Update disposition */
2213 ParseContext->Disposition = REG_CREATED_NEW_KEY;
2214 break;
2215 }
2216 else
2217 {
2218 /* Key not found */
2220 break;
2221 }
2222 }
2223 }
2224 else
2225 {
2226 /* Save the next name */
2227 Current.Buffer = NextName.Buffer;
2228
2229 /* Validate the current name string length */
2230 if (Current.Length + NextName.Length > MAXUSHORT)
2231 {
2232 /* too long */
2234 break;
2235 }
2236 Current.Length += NextName.Length;
2237
2238 /* Validate the current name string maximum length */
2239 if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
2240 {
2241 /* too long */
2243 break;
2244 }
2245 Current.MaximumLength += NextName.MaximumLength;
2246
2247 /* CmpGetSymbolicLink doesn't want a lock */
2248 CmpUnLockKcbArray(LockedKcbs);
2249 LockedKcbs = NULL;
2250
2251 /* Parse the symlink */
2252 if (CmpGetSymbolicLink(Hive,
2253 CompleteName,
2254 Kcb,
2255 &Current))
2256 {
2257 /* Symlink parse succeeded */
2259 }
2260 else
2261 {
2262 /* Couldn't find symlink */
2264 }
2265
2266 /* We're done */
2267 break;
2268 }
2269 }
2270 else if (Result && Last)
2271 {
2272 /* Opening the root. Is this an exit node? */
2273 if (Node->Flags & KEY_HIVE_EXIT)
2274 {
2275 /* Handle it */
2276 CmpHandleExitNode(&Hive,
2277 &Cell,
2278 &Node,
2279 &HiveToRelease,
2280 &CellToRelease);
2281 if (!Node)
2282 {
2283 /* Fail */
2285 break;
2286 }
2287 }
2288
2289 /* Do the open */
2290 Status = CmpDoOpen(Hive,
2291 Cell,
2292 Node,
2294 AccessMode,
2295 Attributes,
2296 ParseContext,
2298 &Kcb,
2299 LockedKcbs,
2300 &NextName,
2301 Object);
2302 if (Status == STATUS_REPARSE)
2303 {
2304 /* Nothing to do */
2305 }
2306
2307 /* We're done */
2308 break;
2309 }
2310 else
2311 {
2312 /* Bogus */
2314 break;
2315 }
2316 }
2317
2318Quickie:
2319 /* Unlock all the KCBs */
2320 if (LockedKcbs != NULL)
2321 {
2322 CmpUnLockKcbArray(LockedKcbs);
2323 }
2324
2325 /* Dereference the parent if it exists */
2326 if (ParentKcb)
2328
2329 /* Unlock the registry */
2331 return Status;
2332}
#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:1717
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:840
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:1090
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:2081
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:88
#define REG_CREATED_NEW_KEY
Definition: nt_native.h:1087
#define STATUS_KEY_DELETED
Definition: ntstatus.h:707
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 1371 of file cmparse.c.

1375{
1376 ULONG HashStackIndex = 0;
1377
1378 /* Skip any leading separator on matching name */
1379 while (RemainingName->Length >= sizeof(WCHAR) &&
1381 {
1382 RemainingName->Buffer++;
1383 RemainingName->Length -= sizeof(WCHAR);
1384 }
1385
1386 /* Skip the subkeys as well */
1387 while (HashStackIndex <= RemainingSubkeys)
1388 {
1389 RemainingName->Buffer += HashCacheStack[HashStackIndex].NameOfKey.Length / sizeof(WCHAR);
1390 RemainingName->Length -= HashCacheStack[HashStackIndex].NameOfKey.Length;
1391
1392 /* Skip any leading separator */
1393 while (RemainingName->Length >= sizeof(WCHAR) &&
1395 {
1396 RemainingName->Buffer++;
1397 RemainingName->Length -= sizeof(WCHAR);
1398 }
1399
1400 /* Go to the next hash */
1401 HashStackIndex++;
1402 }
1403}

Referenced by CmpLookInCache().