Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3586 lines
124 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. cmparse.c
  5. Abstract:
  6. This module contains parse routines for the configuration manager, particularly
  7. the registry.
  8. Author:
  9. Bryan M. Willman (bryanwi) 10-Sep-1991
  10. Revision History:
  11. --*/
  12. #include "cmp.h"
  13. #ifdef ALLOC_DATA_PRAGMA
  14. #pragma const_seg("PAGECONST")
  15. #endif
  16. const ULONG CmpCacheOnFlag = CM_CACHE_FAKE_KEY;
  17. extern PCMHIVE CmpMasterHive;
  18. extern BOOLEAN CmpNoMasterCreates;
  19. extern PCM_KEY_CONTROL_BLOCK CmpKeyControlBlockRoot;
  20. extern UNICODE_STRING CmSymbolicLinkValueName;
  21. #define CM_HASH_STACK_SIZE 30
  22. typedef struct _CM_HASH_ENTRY {
  23. ULONG ConvKey;
  24. UNICODE_STRING KeyName;
  25. } CM_HASH_ENTRY, *PCM_HASH_ENTRY;
  26. BOOLEAN
  27. CmpGetHiveName(
  28. PCMHIVE CmHive,
  29. PUNICODE_STRING HiveName
  30. );
  31. ULONG
  32. CmpComputeHashValue(
  33. IN PCM_HASH_ENTRY HashStack,
  34. IN OUT ULONG *TotalSubkeys,
  35. IN ULONG BaseConvKey,
  36. IN PUNICODE_STRING RemainingName
  37. );
  38. NTSTATUS
  39. CmpCacheLookup(
  40. IN PCM_HASH_ENTRY HashStack,
  41. IN ULONG TotalRemainingSubkeys,
  42. OUT ULONG *MatchRemainSubkeyLevel,
  43. IN OUT PCM_KEY_CONTROL_BLOCK *Kcb,
  44. OUT PUNICODE_STRING RemainingName,
  45. OUT PHHIVE *Hive,
  46. OUT HCELL_INDEX *Cell
  47. );
  48. VOID
  49. CmpCacheAdd(
  50. IN PCM_HASH_ENTRY LastHashEntry,
  51. IN ULONG Count
  52. );
  53. PCM_KEY_CONTROL_BLOCK
  54. CmpAddInfoAfterParseFailure(
  55. PHHIVE Hive,
  56. HCELL_INDEX Cell,
  57. PCM_KEY_NODE Node,
  58. PCM_KEY_CONTROL_BLOCK kcb,
  59. PUNICODE_STRING NodeName
  60. );
  61. //
  62. // Prototypes for procedures private to this file
  63. //
  64. BOOLEAN
  65. CmpGetSymbolicLink(
  66. IN PHHIVE Hive,
  67. IN OUT PUNICODE_STRING ObjectName,
  68. IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb,
  69. IN PUNICODE_STRING RemainingName
  70. );
  71. NTSTATUS
  72. CmpDoOpen(
  73. IN PHHIVE Hive,
  74. IN HCELL_INDEX Cell,
  75. IN PCM_KEY_NODE Node,
  76. IN PACCESS_STATE AccessState,
  77. IN KPROCESSOR_MODE AccessMode,
  78. IN ULONG Attributes,
  79. IN PCM_PARSE_CONTEXT Context OPTIONAL,
  80. IN BOOLEAN CompleteKeyCached,
  81. IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb,
  82. IN PUNICODE_STRING KeyName,
  83. IN PCMHIVE OriginatingHive OPTIONAL,
  84. OUT PVOID *Object,
  85. OUT PBOOLEAN NeedDeref OPTIONAL
  86. );
  87. NTSTATUS
  88. CmpCreateLinkNode(
  89. IN PHHIVE Hive,
  90. IN HCELL_INDEX Cell,
  91. IN PACCESS_STATE AccessState,
  92. IN UNICODE_STRING Name,
  93. IN KPROCESSOR_MODE AccessMode,
  94. IN ULONG Attributes,
  95. IN PCM_PARSE_CONTEXT Context,
  96. IN PCM_KEY_CONTROL_BLOCK ParentKcb,
  97. OUT PVOID *Object
  98. );
  99. #ifdef CM_DYN_SYM_LINK
  100. BOOLEAN
  101. CmpCaptureProcessEnvironmentString(
  102. OUT PWSTR *ProcessEnvironment,
  103. OUT PULONG Length
  104. );
  105. PWSTR
  106. CmpExpandEnvVars(
  107. IN PWSTR StringToExpand,
  108. IN ULONG LengthToExpand,
  109. OUT PULONG ExpandedLength
  110. );
  111. BOOLEAN
  112. CmpGrowAndCopyString(
  113. IN OUT PWSTR *OldString,
  114. IN OUT PULONG OldStringSize,
  115. IN ULONG GrowIncrements
  116. );
  117. BOOLEAN
  118. CmpFindEnvVar(
  119. IN PWSTR ProcessEnv,
  120. IN ULONG ProcessEnvLength,
  121. IN PWSTR CurrentEnvVar,
  122. IN ULONG CurrentEnvLength,
  123. OUT PWSTR *CurrentEnvValue,
  124. OUT PULONG CurrentEnvValueLength
  125. );
  126. #endif
  127. BOOLEAN
  128. CmpOKToFollowLink( IN PCMHIVE OrigHive,
  129. IN PCMHIVE DestHive
  130. );
  131. #ifdef ALLOC_PRAGMA
  132. #pragma alloc_text(PAGE,CmpParseKey)
  133. #pragma alloc_text(PAGE,CmpGetNextName)
  134. #pragma alloc_text(PAGE,CmpDoOpen)
  135. #pragma alloc_text(PAGE,CmpCreateLinkNode)
  136. #pragma alloc_text(PAGE,CmpGetSymbolicLink)
  137. #pragma alloc_text(PAGE,CmpComputeHashValue)
  138. #pragma alloc_text(PAGE,CmpCacheLookup)
  139. #pragma alloc_text(PAGE,CmpAddInfoAfterParseFailure)
  140. #ifdef CM_DYN_SYM_LINK
  141. #pragma alloc_text(PAGE,CmpCaptureProcessEnvironmentString)
  142. #pragma alloc_text(PAGE,CmpExpandEnvVars)
  143. #pragma alloc_text(PAGE,CmpGrowAndCopyString)
  144. #pragma alloc_text(PAGE,CmpFindEnvVar)
  145. #endif //CM_DYN_SYM_LINK
  146. #pragma alloc_text(PAGE,CmpOKToFollowLink)
  147. #endif
  148. /*
  149. VOID
  150. CmpStepThroughExit(
  151. IN OUT PHHIVE *Hive,
  152. IN OUT HCELL_INDEX *Cell,
  153. IN OUT PCM_KEY_NODE *pNode
  154. )
  155. */
  156. #define CmpStepThroughExit(h,c,n,ReleaseHive,ReleaseCell) \
  157. if ((n)->Flags & KEY_HIVE_EXIT) { \
  158. if( ReleaseCell != HCELL_NIL ) { \
  159. ASSERT( ReleaseHive != NULL ); \
  160. HvReleaseCell( ReleaseHive,ReleaseCell); \
  161. } \
  162. (h)=(n)->ChildHiveReference.KeyHive; \
  163. (c)=(n)->ChildHiveReference.KeyCell; \
  164. (n)=(PCM_KEY_NODE)HvGetCell((h),(c)); \
  165. if( (n) == NULL ) { \
  166. ReleaseHive = NULL; \
  167. ReleaseCell = HCELL_NIL; \
  168. } else { \
  169. ReleaseHive = (h); \
  170. ReleaseCell = (c); \
  171. } \
  172. }
  173. #define CmpReleasePreviousAndHookNew(NewHive,NewCell,ReleaseHive,ReleaseCell) \
  174. if( ReleaseCell != HCELL_NIL ) { \
  175. ASSERT( ReleaseHive != NULL ); \
  176. HvReleaseCell( ReleaseHive,ReleaseCell); \
  177. } \
  178. ReleaseHive = (NewHive); \
  179. ReleaseCell = (NewCell)
  180. #define CMP_PARSE_GOTO_NONE 0
  181. #define CMP_PARSE_GOTO_CREATE 1
  182. #define CMP_PARSE_GOTO_RETURN 2
  183. #define CMP_PARSE_GOTO_RETURN2 3
  184. #ifdef CMP_STATS
  185. extern BOOLEAN CmpNtFakeCreateStarted;
  186. extern ULONG CmpNtFakeCreate;
  187. #endif
  188. NTSTATUS
  189. CmpParseKey(
  190. IN PVOID ParseObject,
  191. IN PVOID ObjectType,
  192. IN OUT PACCESS_STATE AccessState,
  193. IN KPROCESSOR_MODE AccessMode,
  194. IN ULONG Attributes,
  195. IN OUT PUNICODE_STRING CompleteName,
  196. IN OUT PUNICODE_STRING RemainingName,
  197. IN OUT PVOID Context OPTIONAL,
  198. IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
  199. OUT PVOID *Object
  200. )
  201. /*++
  202. Routine Description:
  203. This routine interfaces to the NT Object Manager. It is invoked when
  204. the object system is given the name of an entity to create or open and
  205. a Key or KeyRoot is encountered in the path. In practice this means
  206. that this routine is called for all objects whose names are of the
  207. form \REGISTRY\...
  208. This routine will create a Key object, which is effectively an open
  209. instance to a registry key node, and return its address
  210. (for the success case.)
  211. Arguments:
  212. ParseObject - Pointer to a KeyRoot or Key, thus -> KEY_BODY.
  213. ObjectType - Type of the object being opened.
  214. AccessState - Running security access state information for operation.
  215. AccessMode - Access mode of the original caller.
  216. Attributes - Attributes to be applied to the object.
  217. CompleteName - Supplies complete name of the object.
  218. RemainingName - Remaining name of the object.
  219. Context - if create or hive root open, points to a CM_PARSE_CONTEXT
  220. structure,
  221. if open, is NULL.
  222. SecurityQos - Optional security quality of service indicator.
  223. Object - The address of a variable to receive the created key object, if
  224. any.
  225. Return Value:
  226. The function return value is one of the following:
  227. a) Success - This indicates that the function succeeded and the object
  228. parameter contains the address of the created key object.
  229. b) STATUS_REPARSE - This indicates that a symbolic link key was
  230. found, and the path should be reparsed.
  231. c) Error - This indicates that the file was not found or created and
  232. no file object was created.
  233. --*/
  234. {
  235. NTSTATUS status = STATUS_UNSUCCESSFUL;
  236. BOOLEAN rc;
  237. PHHIVE Hive = NULL;
  238. PCM_KEY_NODE Node = NULL;
  239. HCELL_INDEX Cell = HCELL_NIL;
  240. HCELL_INDEX NextCell;
  241. PCM_PARSE_CONTEXT lcontext;
  242. UNICODE_STRING Current;
  243. UNICODE_STRING NextName = {0}; // Component last returned by CmpGetNextName,
  244. // will always be behind Current.
  245. BOOLEAN Last; // TRUE if component NextName points to
  246. // is the last one in the path.
  247. ULONG TotalRemainingSubkeys;
  248. ULONG MatchRemainSubkeyLevel = 0;
  249. ULONG TotalSubkeys=0;
  250. PCM_KEY_CONTROL_BLOCK kcb;
  251. PCM_KEY_CONTROL_BLOCK ParentKcb = NULL;
  252. UNICODE_STRING TmpNodeName;
  253. ULONG GoToValue = CMP_PARSE_GOTO_NONE;
  254. BOOLEAN CompleteKeyCached = FALSE;
  255. PHHIVE HiveToRelease = NULL;
  256. HCELL_INDEX CellToRelease = HCELL_NIL;
  257. PAGED_CODE();
  258. UNREFERENCED_PARAMETER (SecurityQos);
  259. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpParseKey:\n\t"));
  260. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CompleteName = '%wZ'\n\t", CompleteName));
  261. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"RemainingName = '%wZ'\n", RemainingName));
  262. //
  263. // Strip off any trailing path separators
  264. //
  265. while ((RemainingName->Length > 0) &&
  266. (RemainingName->Buffer[(RemainingName->Length/sizeof(WCHAR)) - 1] == OBJ_NAME_PATH_SEPARATOR)) {
  267. RemainingName->Length -= sizeof(WCHAR);
  268. }
  269. Current = *RemainingName;
  270. if (ObjectType != CmpKeyObjectType) {
  271. return STATUS_OBJECT_TYPE_MISMATCH;
  272. }
  273. if( ARGUMENT_PRESENT(Context) && (((PCM_PARSE_CONTEXT)Context)->CreateOperation == TRUE) ) {
  274. lcontext = (PCM_PARSE_CONTEXT)Context;
  275. } else {
  276. //
  277. // keep the old behaviour (open == parse without context)
  278. //
  279. lcontext = NULL;
  280. }
  281. //
  282. // PreCreate callback
  283. //
  284. if ( CmAreCallbacksRegistered() ) {
  285. if( ARGUMENT_PRESENT(lcontext) ) {
  286. //
  287. // NtCreateKey
  288. //
  289. REG_CREATE_KEY_INFORMATION PreCreateInfo;
  290. PreCreateInfo.CompleteName = CompleteName;
  291. PreCreateInfo.RootObject = ParseObject;
  292. status = CmpCallCallBacks(RegNtPreCreateKeyEx,&PreCreateInfo);
  293. } else {
  294. //
  295. // NtOpenKey
  296. //
  297. REG_OPEN_KEY_INFORMATION PreOpenInfo;
  298. PreOpenInfo.CompleteName = CompleteName;
  299. PreOpenInfo.RootObject = ParseObject;
  300. status = CmpCallCallBacks(RegNtPreOpenKeyEx,&PreOpenInfo);
  301. }
  302. if( !NT_SUCCESS(status) ) {
  303. return status;
  304. }
  305. }
  306. BEGIN_LOCK_CHECKPOINT;
  307. kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock;
  308. BEGIN_KCB_LOCK_GUARD;
  309. //
  310. // give back the stack after we don't need it anymore.
  311. //
  312. {
  313. CM_HASH_ENTRY HashStack[CM_HASH_STACK_SIZE];
  314. ULONG HashKeyCopy;
  315. BOOLEAN RegLocked = FALSE;
  316. RetryHash:
  317. HashKeyCopy = kcb->ConvKey;
  318. //
  319. // Compute the hash values of each subkeys
  320. //
  321. TotalRemainingSubkeys = CmpComputeHashValue(HashStack,
  322. &TotalSubkeys,
  323. HashKeyCopy,
  324. &Current);
  325. PERFINFO_REG_PARSE(kcb, RemainingName);
  326. //
  327. // we now lock it shared as 85% of the create calls are in fact opens
  328. // the lock will be aquired exclusively in CmpDoCreate/CmpCreateLinkNode
  329. //
  330. // We only lock the registry here, in the parse routine to reduce contention
  331. // on the registry lock (NO reason to wait on OB)
  332. //
  333. if( !RegLocked ) {
  334. CmpLockRegistry();
  335. RegLocked = TRUE;
  336. //CmpLockRegistryExclusive();
  337. }
  338. if( kcb->ConvKey != HashKeyCopy ) {
  339. goto RetryHash;
  340. }
  341. //
  342. // Check to make sure the passed in root key is not marked for deletion.
  343. //
  344. if (((PCM_KEY_BODY)ParseObject)->KeyControlBlock->Delete == TRUE) {
  345. ASSERT( RegLocked );
  346. CmpUnlockRegistry();
  347. return(STATUS_KEY_DELETED);
  348. }
  349. //
  350. // Fetch the starting Hive.Cell. Because of the way the parse
  351. // paths work, this will always be defined. (ObOpenObjectByName
  352. // had to bounce off of a KeyObject or KeyRootObject to get here)
  353. //
  354. Hive = kcb->KeyHive;
  355. Cell = kcb->KeyCell;
  356. CmpLockKCBTree();
  357. // Look up from the cache. kcb will be changed if we find a partial or exact match
  358. // PCmpCacheEntry, the entry found, will be moved to the front of
  359. // the Cache.
  360. status = CmpCacheLookup(HashStack,
  361. TotalRemainingSubkeys,
  362. &MatchRemainSubkeyLevel,
  363. &kcb,
  364. &Current,
  365. &Hive,
  366. &Cell);
  367. //
  368. // The RefCount of kcb was increased in the CmpCacheLookup process,
  369. // It is to protect it from being kicked out of cache.
  370. // Make sure we dereference it after we are done.
  371. //
  372. }
  373. //
  374. // First make sure it is OK to proceed.
  375. //
  376. if (!NT_SUCCESS (status)) {
  377. CmpUnlockKCBTree();
  378. goto JustReturn;
  379. }
  380. ParentKcb = kcb;
  381. if(TotalRemainingSubkeys == 0) {
  382. //
  383. // We REALLY don't want to mess with the cache code below
  384. // in this case (this could only happen if we called with
  385. // the lpSubkey = NULL )
  386. //
  387. CompleteKeyCached = TRUE;
  388. CmpUnlockKCBTree();
  389. goto Found;
  390. }
  391. //
  392. // First check if there are further information in the cached kcb.
  393. //
  394. // The additional information can be
  395. // 1. This cached key is a fake key (CM_KCB_KEY_NON_EXIST), then either let it be created
  396. // or return STATUS_OBJECT_NAME_NOT_FOUND.
  397. // 2. The cached key is not the destination and it has no subkey (CM_KCB_NO_SUBKEY).
  398. // 3. The cached key is not the destination and it has
  399. // the first four characters of its subkeys. If the flag is CM_KCB_SUBKEY_ONE, there is only one subkey
  400. // and the four char is embedded in the KCB. If the flag is CM_KCB_SUBKEY_INFO, then there is
  401. // an allocation for these info.
  402. //
  403. // We do need to lock KCB tree to protect the KCB being modified. Currently there is not lock contention problem
  404. // on KCBs, We can change KCB lock to a read-write lock if this becomes a problem.
  405. // We already have the lock on the kcb tree and we need it until we finish work on the cache table.
  406. //
  407. StartOver:
  408. if( kcb->Delete ) {
  409. //
  410. // kcb has been deleted while playing with the lock
  411. //
  412. status = STATUS_OBJECT_NAME_NOT_FOUND;
  413. CmpUnlockKCBTree();
  414. goto JustReturn;
  415. }
  416. if (kcb->ExtFlags & CM_KCB_CACHE_MASK) {
  417. if (MatchRemainSubkeyLevel == TotalRemainingSubkeys) {
  418. //
  419. // We have found a cache for the complete path,
  420. //
  421. if (kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) {
  422. //
  423. // This key does not exist.
  424. //
  425. if (ARGUMENT_PRESENT(lcontext)) {
  426. ULONG LevelToSkip = TotalRemainingSubkeys-1;
  427. ULONG i=0;
  428. // Promote KCB Lock if not already EX
  429. if (CmpKcbOwner != KeGetCurrentThread()) {
  430. InterlockedIncrement( (PLONG)&kcb->RefCount );
  431. CmpUnlockKCBTree();
  432. CmpLockKCBTreeExclusive();
  433. InterlockedDecrement( (PLONG)&kcb->RefCount );
  434. goto StartOver;
  435. }
  436. //
  437. // The non-existing key is the destination key and lcontext is present.
  438. // delete this fake kcb and let the real one be created.
  439. //
  440. // Temporarily increase the RefCount of the ParentKcb so it's
  441. // not removed while removing the fake and creating the real KCB.
  442. //
  443. ParentKcb = kcb->ParentKcb;
  444. if (CmpReferenceKeyControlBlock(ParentKcb)) {
  445. kcb->Delete = TRUE;
  446. CmpRemoveKeyControlBlock(kcb);
  447. CmpDereferenceKeyControlBlockWithLock(kcb);
  448. //
  449. // Update Hive, Cell and Node
  450. //
  451. Hive = ParentKcb->KeyHive;
  452. Cell = ParentKcb->KeyCell;
  453. Node = (PCM_KEY_NODE)HvGetCell(Hive,Cell);
  454. if( Node == NULL ) {
  455. //
  456. // we couldn't map the bin contianing this cell
  457. //
  458. CmpUnlockKCBTree();
  459. status = STATUS_INSUFFICIENT_RESOURCES;
  460. goto FreeAndReturn;
  461. }
  462. CmpReleasePreviousAndHookNew(Hive,Cell,HiveToRelease,CellToRelease);
  463. //
  464. // Now get the child name to be created.
  465. //
  466. NextName = *RemainingName;
  467. if ((NextName.Buffer == NULL) || (NextName.Length == 0)) {
  468. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Something wrong in finding the child name\n"));
  469. DbgBreakPoint();
  470. }
  471. //
  472. // Skip over leading path separators
  473. //
  474. while (*(NextName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
  475. NextName.Buffer++;
  476. NextName.Length -= sizeof(WCHAR);
  477. NextName.MaximumLength -= sizeof(WCHAR);
  478. }
  479. while (i < LevelToSkip) {
  480. if (*(NextName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
  481. i++;
  482. while (*(NextName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
  483. NextName.Buffer++;
  484. NextName.Length -= sizeof(WCHAR);
  485. NextName.MaximumLength -= sizeof(WCHAR);
  486. }
  487. } else {
  488. NextName.Buffer++;
  489. NextName.Length -= sizeof(WCHAR);
  490. NextName.MaximumLength -= sizeof(WCHAR);
  491. }
  492. }
  493. GoToValue = CMP_PARSE_GOTO_CREATE;
  494. } else {
  495. //
  496. // We have maxed the RefCount of ParentKcb; treate it as key cannot be created.
  497. // The ParentKcb will not be dereferenced at the end.
  498. //
  499. status = STATUS_INSUFFICIENT_RESOURCES;
  500. GoToValue = CMP_PARSE_GOTO_RETURN2;
  501. }
  502. } else {
  503. status = STATUS_OBJECT_NAME_NOT_FOUND;
  504. GoToValue = CMP_PARSE_GOTO_RETURN;
  505. }
  506. }
  507. } else if (kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) {
  508. //
  509. // one subkey (not destination) in the path does not exist. no point to continue.
  510. //
  511. status = STATUS_OBJECT_NAME_NOT_FOUND;
  512. GoToValue = CMP_PARSE_GOTO_RETURN;
  513. } else if (kcb->ExtFlags & CM_KCB_NO_SUBKEY) {
  514. //
  515. // one parent in the path has no subkey. see if it is a create.
  516. //
  517. if (((TotalRemainingSubkeys - MatchRemainSubkeyLevel) == 1) && (ARGUMENT_PRESENT(lcontext))) {
  518. //
  519. // Now we are going to create this subkey.
  520. // The kcb cache will be updated in CmpDoCreate routine.
  521. //
  522. } else {
  523. status = STATUS_OBJECT_NAME_NOT_FOUND;
  524. GoToValue = CMP_PARSE_GOTO_RETURN;
  525. }
  526. } else {
  527. //
  528. // We have a partial match. Current is the remaining name to be parsed.
  529. // The Key has either one or a few subkeys and has index hint. check if it is the candidate.
  530. //
  531. BOOLEAN NoMatch = TRUE;
  532. ULONG NextHashKey;
  533. PULONG TempHashKey;
  534. ULONG HintCounts;
  535. ULONG CmpCount;
  536. //
  537. // When NoMatch is TRUE, we know for sure there is no subkey that can match.
  538. // When NoMatch is FALSE, it can we either we found a match or
  539. // there is not enough information. Either case, we need to continue
  540. // the parse.
  541. //
  542. TmpNodeName = Current;
  543. rc = CmpGetNextName(&TmpNodeName, &NextName, &Last);
  544. NextHashKey = CmpComputeHashKey(&NextName);
  545. if (kcb->ExtFlags & CM_KCB_SUBKEY_ONE) {
  546. HintCounts = 1;
  547. TempHashKey = &(kcb->HashKey);
  548. } else {
  549. //
  550. // More than one child, the hint info in not inside the kcb but pointed by kcb.
  551. //
  552. HintCounts = kcb->IndexHint->Count;
  553. TempHashKey = &(kcb->IndexHint->HashKey[0]);
  554. }
  555. for (CmpCount=0; CmpCount<HintCounts; CmpCount++) {
  556. if( TempHashKey[CmpCount] == 0) {
  557. //
  558. // No hint available; assume the subkey exist and go on with the parse
  559. //
  560. //DbgPrint("KCB cache hit [0]\n");
  561. NoMatch = FALSE;
  562. break;
  563. }
  564. if( NextHashKey == TempHashKey[CmpCount] ) {
  565. //
  566. // There is a match.
  567. //
  568. //DbgPrint("KCB cache hit [1]\n");
  569. NoMatch = FALSE;
  570. break;
  571. }
  572. }
  573. if (NoMatch) {
  574. if (((TotalRemainingSubkeys - MatchRemainSubkeyLevel) == 1) && (ARGUMENT_PRESENT(lcontext))) {
  575. //
  576. // No we are going to create this subkey.
  577. // The kcb cache will be updated in CmpDoCreate.
  578. //
  579. } else {
  580. status = STATUS_OBJECT_NAME_NOT_FOUND;
  581. GoToValue = CMP_PARSE_GOTO_RETURN;
  582. }
  583. }
  584. }
  585. }
  586. CmpUnlockKCBTree();
  587. END_KCB_LOCK_GUARD;
  588. if (GoToValue == CMP_PARSE_GOTO_CREATE) {
  589. goto CreateChild;
  590. } else if (GoToValue == CMP_PARSE_GOTO_RETURN) {
  591. goto FreeAndReturn;
  592. } else if (GoToValue == CMP_PARSE_GOTO_RETURN2) {
  593. goto JustReturn;
  594. }
  595. if (MatchRemainSubkeyLevel) {
  596. // Found something, update the information to start the search
  597. // from the new BaseName
  598. if (MatchRemainSubkeyLevel == TotalSubkeys) {
  599. // The complete key has been found in the cache,
  600. // go directly to the CmpDoOpen.
  601. //
  602. // Found the whole thing cached.
  603. //
  604. //
  605. CompleteKeyCached = TRUE;
  606. goto Found;
  607. }
  608. ASSERT( (Cell == kcb->KeyCell) && (Hive == kcb->KeyHive) );
  609. }
  610. //
  611. // Check if we hit a symbolic link case
  612. //
  613. if (kcb->Flags & KEY_SYM_LINK) {
  614. //
  615. // The given key was a symbolic link. Find the name of
  616. // its link, and return STATUS_REPARSE to the Object Manager.
  617. //
  618. rc = CmpGetNextName(&Current, &NextName, &Last);
  619. Current.Buffer = NextName.Buffer;
  620. if (Current.Length + NextName.Length > MAXUSHORT) {
  621. status = STATUS_NAME_TOO_LONG;
  622. goto FreeAndReturn;
  623. }
  624. Current.Length = (USHORT)(Current.Length + NextName.Length);
  625. if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT) {
  626. status = STATUS_NAME_TOO_LONG;
  627. goto FreeAndReturn;
  628. }
  629. Current.MaximumLength = (USHORT)(Current.MaximumLength + NextName.MaximumLength);
  630. if (CmpGetSymbolicLink(Hive,
  631. CompleteName,
  632. kcb,
  633. &Current)) {
  634. status = STATUS_REPARSE;
  635. CmpParseRecordOriginatingPoint(Context,(PCMHIVE)kcb->KeyHive);
  636. } else {
  637. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpParseKey: couldn't find symbolic link name\n"));
  638. status = STATUS_OBJECT_NAME_NOT_FOUND;
  639. }
  640. goto FreeAndReturn;
  641. }
  642. Node = (PCM_KEY_NODE)HvGetCell(Hive,Cell);
  643. if( Node == NULL ) {
  644. //
  645. // we couldn't map the bin contianing this cell
  646. //
  647. status = STATUS_INSUFFICIENT_RESOURCES;
  648. goto FreeAndReturn;
  649. }
  650. CmpReleasePreviousAndHookNew(Hive,Cell,HiveToRelease,CellToRelease);
  651. //
  652. // Parse the path.
  653. //
  654. status = STATUS_SUCCESS;
  655. while (TRUE) {
  656. //
  657. // Parse out next component of name
  658. //
  659. rc = CmpGetNextName(&Current, &NextName, &Last);
  660. if ((NextName.Length > 0) && (rc == TRUE)) {
  661. //
  662. // As we iterate through, we will create a kcb for each subkey parsed.
  663. //
  664. // Always use the information in kcb to avoid
  665. // touching registry data.
  666. //
  667. #ifdef CMP_KCB_CACHE_VALIDATION
  668. {
  669. PCM_KEY_NODE TempNode;
  670. TempNode = (PCM_KEY_NODE)HvGetCell(kcb->KeyHive,kcb->KeyCell);
  671. if( TempNode == NULL ) {
  672. //
  673. // we couldn't map the bin contianing this cell
  674. //
  675. status = STATUS_INSUFFICIENT_RESOURCES;
  676. break;
  677. }
  678. ASSERT( TempNode->Flags == kcb->Flags );
  679. HvReleaseCell(kcb->KeyHive,kcb->KeyCell);
  680. }
  681. #endif
  682. if (!(kcb->Flags & KEY_SYM_LINK)) {
  683. //
  684. // Got a legal name component, see if we can find a sub key
  685. // that actually has such a name.
  686. //
  687. NextCell = CmpFindSubKeyByName(Hive,
  688. Node,
  689. &NextName);
  690. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpParseKey:\n\t"));
  691. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"NextName = '%wZ'\n\t", &NextName));
  692. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"NextCell = %08lx Last = %01lx\n", NextCell, Last));
  693. if (NextCell != HCELL_NIL) {
  694. Cell = NextCell;
  695. Node = (PCM_KEY_NODE)HvGetCell(Hive,Cell);
  696. if( Node == NULL ) {
  697. //
  698. // we couldn't map the bin contianing this cell
  699. //
  700. status = STATUS_INSUFFICIENT_RESOURCES;
  701. break;
  702. }
  703. CmpReleasePreviousAndHookNew(Hive,Cell,HiveToRelease,CellToRelease);
  704. if (Last == TRUE) {
  705. BOOLEAN NeedDeref;
  706. Found:
  707. //
  708. // We will open the key regardless of whether the
  709. // call was open or create, so step through exit
  710. // portholes here.
  711. //
  712. if (CompleteKeyCached == TRUE) {
  713. //
  714. // If the key found is already cached,
  715. // do not need to StepThroughExit
  716. // (no kcb is created using exit node).
  717. // This prevents us from touching the key node just for the Flags.
  718. //
  719. } else {
  720. CmpStepThroughExit(Hive, Cell, Node,HiveToRelease,CellToRelease);
  721. if( Node == NULL ) {
  722. //
  723. // we couldn't map view for this cell
  724. //
  725. status = STATUS_INSUFFICIENT_RESOURCES;
  726. break;
  727. }
  728. }
  729. //
  730. // We have found the entire path, so we want to open
  731. // it (for both Open and Create calls).
  732. // Hive,Cell -> the key we are supposed to open.
  733. //
  734. #ifdef CMP_STATS
  735. if(CmpNtFakeCreateStarted == TRUE) {
  736. CmpNtFakeCreate++;
  737. }
  738. #endif
  739. status = CmpDoOpen(Hive,
  740. Cell,
  741. Node,
  742. AccessState,
  743. AccessMode,
  744. Attributes,
  745. lcontext,
  746. CompleteKeyCached,
  747. &kcb,
  748. &NextName,
  749. CmpParseGetOriginatingPoint(Context),
  750. Object,
  751. &NeedDeref);
  752. if (status == STATUS_REPARSE) {
  753. //
  754. // The given key was a symbolic link. Find the name of
  755. // its link, and return STATUS_REPARSE to the Object Manager.
  756. //
  757. if (!CmpGetSymbolicLink(Hive,
  758. CompleteName,
  759. kcb,
  760. NULL)) {
  761. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpParseKey: couldn't find symbolic link name\n"));
  762. status = STATUS_OBJECT_NAME_NOT_FOUND;
  763. }
  764. CmpParseRecordOriginatingPoint(Context,(PCMHIVE)kcb->KeyHive);
  765. if( TRUE == NeedDeref ) {
  766. CmpDereferenceKeyControlBlock(kcb);
  767. }
  768. } else {
  769. ASSERT( !NeedDeref );
  770. }
  771. break;
  772. }
  773. // else
  774. // Not at end, so we'll simply iterate and consume
  775. // the next component.
  776. //
  777. //
  778. // Step through exit portholes here.
  779. // This ensures that no KCB is created using
  780. // the Exit node.
  781. //
  782. CmpStepThroughExit(Hive, Cell, Node,HiveToRelease,CellToRelease);
  783. if( Node == NULL ) {
  784. //
  785. // we couldn't map view for this cell
  786. //
  787. status = STATUS_INSUFFICIENT_RESOURCES;
  788. break;
  789. }
  790. //
  791. // Create a kcb for each subkey parsed.
  792. //
  793. kcb = CmpCreateKeyControlBlock(Hive,
  794. Cell,
  795. Node,
  796. ParentKcb,
  797. FALSE,
  798. &NextName);
  799. if (kcb == NULL) {
  800. status = STATUS_INSUFFICIENT_RESOURCES;
  801. goto FreeAndReturn;
  802. //
  803. // Currently, the kcb has one extra reference conut to be decremented.
  804. // Remember it so we can dereference it properly.
  805. //
  806. }
  807. //
  808. // Now we have created a kcb for the next level,
  809. // the kcb in the previous level is no longer needed.
  810. // Dereference the parent kcb.
  811. //
  812. CmpDereferenceKeyControlBlock(ParentKcb);
  813. ParentKcb = kcb;
  814. } else {
  815. //
  816. // We did not find a key matching the name, but no
  817. // unexpected error occured
  818. //
  819. if ((Last == TRUE) && (ARGUMENT_PRESENT(lcontext))) {
  820. CreateChild:
  821. //
  822. // Only unfound component is last one, and operation
  823. // is a create, so perform the create.
  824. //
  825. //
  826. // There are two possibilities here. The normal one
  827. // is that we are simply creating a new node.
  828. //
  829. // The abnormal one is that we are creating a root
  830. // node that is linked to the main hive. In this
  831. // case, we must create the link. Once the link is
  832. // created, we can check to see if the root node
  833. // exists, then either create it or open it as
  834. // necessary.
  835. //
  836. // CmpCreateLinkNode creates the link, and calls
  837. // back to CmpDoCreate or CmpDoOpen to create or open
  838. // the root node as appropriate.
  839. //
  840. //
  841. // either one of this will drop the reglock and reaquire it
  842. // exclusive; we need not to hurt ourselves, so release
  843. // all cells here
  844. //
  845. CmpReleasePreviousAndHookNew(NULL,HCELL_NIL,HiveToRelease,CellToRelease);
  846. if (lcontext->CreateLink) {
  847. status = CmpCreateLinkNode(Hive,
  848. Cell,
  849. AccessState,
  850. NextName,
  851. AccessMode,
  852. Attributes,
  853. lcontext,
  854. ParentKcb,
  855. Object);
  856. } else {
  857. if ( (Hive == &(CmpMasterHive->Hive)) &&
  858. (CmpNoMasterCreates == TRUE) ) {
  859. //
  860. // attempting to create a cell in the master
  861. // hive, and not a link, so blow out of here,
  862. // since it wouldn't work anyway.
  863. //
  864. status = STATUS_INVALID_PARAMETER;
  865. break;
  866. }
  867. status = CmpDoCreate(Hive,
  868. Cell,
  869. AccessState,
  870. &NextName,
  871. AccessMode,
  872. lcontext,
  873. ParentKcb,
  874. CmpParseGetOriginatingPoint(Context),
  875. Object);
  876. }
  877. if( status == STATUS_REPARSE ) {
  878. //
  879. // somebody else created the key in between;
  880. // let the Object Manager work for us !!!
  881. // now we have the lock exclusive, so nothing can happen in between
  882. // next iterarion will find the key very quick
  883. //
  884. break;
  885. }
  886. lcontext->Disposition = REG_CREATED_NEW_KEY;
  887. break;
  888. } else {
  889. //
  890. // Did not find a key to match the component, and
  891. // are not at the end of the path. Thus, open must
  892. // fail because the whole path dosn't exist, create must
  893. // fail because more than 1 component doesn't exist.
  894. //
  895. //
  896. // We have a lookup failure here, so having additional information
  897. // about this kcb may help us not to go through all the code just to fail again.
  898. //
  899. ParentKcb = CmpAddInfoAfterParseFailure(Hive,
  900. Cell,
  901. Node,
  902. kcb,
  903. &NextName
  904. );
  905. status = STATUS_OBJECT_NAME_NOT_FOUND;
  906. break;
  907. }
  908. }
  909. } else {
  910. //
  911. // The given key was a symbolic link. Find the name of
  912. // its link, and return STATUS_REPARSE to the Object Manager.
  913. //
  914. Current.Buffer = NextName.Buffer;
  915. if (Current.Length + NextName.Length > MAXUSHORT) {
  916. status = STATUS_NAME_TOO_LONG;
  917. break;
  918. }
  919. Current.Length = (USHORT)(Current.Length + NextName.Length);
  920. if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT) {
  921. status = STATUS_NAME_TOO_LONG;
  922. break;
  923. }
  924. Current.MaximumLength = (USHORT)(Current.MaximumLength + NextName.MaximumLength);
  925. if (CmpGetSymbolicLink(Hive,
  926. CompleteName,
  927. kcb,
  928. &Current)) {
  929. status = STATUS_REPARSE;
  930. CmpParseRecordOriginatingPoint(Context,(PCMHIVE)kcb->KeyHive);
  931. break;
  932. } else {
  933. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpParseKey: couldn't find symbolic link name\n"));
  934. status = STATUS_OBJECT_NAME_NOT_FOUND;
  935. break;
  936. }
  937. }
  938. } else if (rc == TRUE && Last == TRUE) {
  939. //
  940. // We will open the \Registry root.
  941. // Or some strange remaining name that
  942. // messes up the lookup.
  943. //
  944. CmpStepThroughExit(Hive, Cell, Node,HiveToRelease,CellToRelease);
  945. if( Node == NULL ) {
  946. //
  947. // we couldn't map view for this cell
  948. //
  949. status = STATUS_INSUFFICIENT_RESOURCES;
  950. break;
  951. }
  952. //
  953. // We have found the entire path, so we want to open
  954. // it (for both Open and Create calls).
  955. // Hive,Cell -> the key we are supposed to open.
  956. //
  957. status = CmpDoOpen(Hive,
  958. Cell,
  959. Node,
  960. AccessState,
  961. AccessMode,
  962. Attributes,
  963. lcontext,
  964. TRUE,
  965. &kcb,
  966. &NextName,
  967. CmpParseGetOriginatingPoint(Context),
  968. Object,
  969. NULL);
  970. if(status == STATUS_REPARSE ) {
  971. CmpParseRecordOriginatingPoint(Context,(PCMHIVE)kcb->KeyHive);
  972. }
  973. break;
  974. } else {
  975. //
  976. // bogus path -> fail
  977. //
  978. status = STATUS_INVALID_PARAMETER;
  979. break;
  980. }
  981. } // while
  982. FreeAndReturn:
  983. //
  984. // Now we have to free the last kcb that still has one extra reference count to
  985. // protect it from being freed.
  986. //
  987. if( ParentKcb != NULL ) {
  988. CmpDereferenceKeyControlBlock(ParentKcb);
  989. }
  990. JustReturn:
  991. CmpReleasePreviousAndHookNew(NULL,HCELL_NIL,HiveToRelease,CellToRelease);
  992. CmpUnlockRegistry();
  993. END_LOCK_CHECKPOINT;
  994. //
  995. // PostCreate callback. just a notification; disregard the return status
  996. //
  997. CmPostCallbackNotification((ARGUMENT_PRESENT(lcontext)?RegNtPostCreateKeyEx:RegNtPostOpenKeyEx),(*Object),status);
  998. return status;
  999. }
  1000. BOOLEAN
  1001. CmpGetNextName(
  1002. IN OUT PUNICODE_STRING RemainingName,
  1003. OUT PUNICODE_STRING NextName,
  1004. OUT PBOOLEAN Last
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. This routine parses off the next component of a registry path, returning
  1009. all of the interesting state about it, including whether it's legal.
  1010. Arguments:
  1011. Current - supplies pointer to variable which points to path to parse.
  1012. on input - parsing starts from here
  1013. on output - updated to reflect starting position for next call.
  1014. NextName - supplies pointer to a unicode_string, which will be set up
  1015. to point into the parse string.
  1016. Last - supplies a pointer to a boolean - set to TRUE if this is the
  1017. last component of the name being parse, FALSE otherwise.
  1018. Return Value:
  1019. TRUE if all is well.
  1020. FALSE if illegal name (too long component, bad character, etc.)
  1021. (if false, all out parameter values are bogus.)
  1022. --*/
  1023. {
  1024. BOOLEAN rc = TRUE;
  1025. //
  1026. // Deal with NULL paths, and pointers to NULL paths
  1027. //
  1028. if ((RemainingName->Buffer == NULL) || (RemainingName->Length == 0)) {
  1029. *Last = TRUE;
  1030. NextName->Buffer = NULL;
  1031. NextName->Length = 0;
  1032. return TRUE;
  1033. }
  1034. if (*(RemainingName->Buffer) == UNICODE_NULL) {
  1035. *Last = TRUE;
  1036. NextName->Buffer = NULL;
  1037. NextName->Length = 0;
  1038. return TRUE;
  1039. }
  1040. //
  1041. // Skip over leading path separators
  1042. //
  1043. if (*(RemainingName->Buffer) == OBJ_NAME_PATH_SEPARATOR) {
  1044. RemainingName->Buffer++;
  1045. RemainingName->Length -= sizeof(WCHAR);
  1046. RemainingName->MaximumLength -= sizeof(WCHAR);
  1047. }
  1048. //
  1049. // Remember where the component starts, and scan to the end
  1050. //
  1051. NextName->Buffer = RemainingName->Buffer;
  1052. while (TRUE) {
  1053. if (RemainingName->Length == 0) {
  1054. break;
  1055. }
  1056. if (*RemainingName->Buffer == OBJ_NAME_PATH_SEPARATOR) {
  1057. break;
  1058. }
  1059. //
  1060. // NOT at end
  1061. // NOT another path sep
  1062. //
  1063. RemainingName->Buffer++;
  1064. RemainingName->Length -= sizeof(WCHAR);
  1065. RemainingName->MaximumLength -= sizeof(WCHAR);
  1066. }
  1067. //
  1068. // Compute component length, return error if it's illegal
  1069. //
  1070. NextName->Length = (USHORT)
  1071. ((PUCHAR)RemainingName->Buffer - (PUCHAR)(NextName->Buffer));
  1072. if (NextName->Length > REG_MAX_KEY_NAME_LENGTH)
  1073. {
  1074. rc = FALSE;
  1075. }
  1076. NextName->MaximumLength = NextName->Length;
  1077. //
  1078. // Set last, return success
  1079. //
  1080. *Last = (RemainingName->Length == 0) ? TRUE : FALSE;
  1081. return rc;
  1082. }
  1083. NTSTATUS
  1084. CmpDoOpen(
  1085. IN PHHIVE Hive,
  1086. IN HCELL_INDEX Cell,
  1087. IN PCM_KEY_NODE Node,
  1088. IN PACCESS_STATE AccessState,
  1089. IN KPROCESSOR_MODE AccessMode,
  1090. IN ULONG Attributes,
  1091. IN PCM_PARSE_CONTEXT Context OPTIONAL,
  1092. IN BOOLEAN CompleteKeyCached,
  1093. IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb,
  1094. IN PUNICODE_STRING KeyName,
  1095. IN PCMHIVE OriginatingHive OPTIONAL,
  1096. OUT PVOID *Object,
  1097. OUT PBOOLEAN NeedDeref OPTIONAL
  1098. )
  1099. /*++
  1100. Routine Description:
  1101. Open a registry key, create a keycontrol block.
  1102. Arguments:
  1103. Hive - supplies a pointer to the hive control structure for the hive
  1104. Cell - supplies index of node to delete
  1105. AccessState - Running security access state information for operation.
  1106. AccessMode - Access mode of the original caller.
  1107. Attributes - Attributes to be applied to the object.
  1108. Context - if create or hive root open, points to a CM_PARSE_CONTEXT
  1109. structure,
  1110. if open, is NULL.
  1111. CompleteKeyCached - BOOLEAN to indicate it the completekey is cached.
  1112. CachedKcb - If the completekey is cached, this is the kcb for the destination.
  1113. If not, this is the parent kcb.
  1114. KeyName - Relative name (to BaseName)
  1115. Object - The address of a variable to receive the created key object, if
  1116. any.
  1117. NeedDeref - if specified, keep reference in the fake create kcb (link case). Caller
  1118. is responsible to release the fake kcb after it finishes with it.
  1119. Return Value:
  1120. NTSTATUS
  1121. --*/
  1122. {
  1123. NTSTATUS status;
  1124. PCM_KEY_BODY pbody;
  1125. PCM_KEY_CONTROL_BLOCK kcb = NULL;
  1126. KPROCESSOR_MODE mode;
  1127. BOOLEAN BackupRestore;
  1128. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpDoOpen:\n"));
  1129. if( ARGUMENT_PRESENT(NeedDeref) ) {
  1130. *NeedDeref = FALSE;
  1131. }
  1132. if (ARGUMENT_PRESENT(Context)) {
  1133. //
  1134. // It's a create of some sort
  1135. //
  1136. if (Context->CreateLink) {
  1137. //
  1138. // The node already exists as a regular key, so it cannot be
  1139. // turned into a link node.
  1140. //
  1141. return STATUS_ACCESS_DENIED;
  1142. } else if (Context->CreateOptions & REG_OPTION_CREATE_LINK) {
  1143. //
  1144. // Attempt to create a symbolic link has hit an existing key
  1145. // so return an error
  1146. //
  1147. return STATUS_OBJECT_NAME_COLLISION;
  1148. } else {
  1149. //
  1150. // Operation is an open, so set Disposition
  1151. //
  1152. Context->Disposition = REG_OPENED_EXISTING_KEY;
  1153. }
  1154. }
  1155. //
  1156. // Check for symbolic link and caller does not want to open a link
  1157. //
  1158. if (CompleteKeyCached) {
  1159. //
  1160. // The complete key is cached.
  1161. //
  1162. BEGIN_KCB_LOCK_GUARD;
  1163. CmpLockKCBTree();
  1164. StartOver:
  1165. if ((*CachedKcb)->Flags & KEY_SYM_LINK && !(Attributes & OBJ_OPENLINK)) {
  1166. //
  1167. // If the key is a symbolic link, check if the link has been resolved.
  1168. // If the link is resolved, change the kcb to the real KCB.
  1169. // Otherwise, return for reparse.
  1170. //
  1171. if ((*CachedKcb)->ExtFlags & CM_KCB_SYM_LINK_FOUND) {
  1172. kcb = (*CachedKcb)->ValueCache.RealKcb;
  1173. if (kcb->Delete == TRUE) {
  1174. // Promote KCB Lock if not already EX
  1175. if (CmpKcbOwner != KeGetCurrentThread()) {
  1176. InterlockedIncrement( (PLONG)&kcb->RefCount );
  1177. CmpUnlockKCBTree();
  1178. CmpLockKCBTreeExclusive();
  1179. InterlockedDecrement( (PLONG)&kcb->RefCount );
  1180. goto StartOver;
  1181. }
  1182. //
  1183. // The real key it pointes to had been deleted.
  1184. // We have no way of knowing if the key has been recreated.
  1185. // Just clean up the cache and do a reparse.
  1186. //
  1187. CmpCleanUpKcbValueCache(*CachedKcb);
  1188. CmpUnlockKCBTree();
  1189. return(STATUS_REPARSE);
  1190. }
  1191. } else {
  1192. CmpUnlockKCBTree();
  1193. return(STATUS_REPARSE);
  1194. }
  1195. } else {
  1196. //
  1197. // Not a symbolic link, increase the reference Count of Kcb.
  1198. //
  1199. kcb = *CachedKcb;
  1200. }
  1201. // common path instead of repeating code
  1202. if (!CmpReferenceKeyControlBlock(kcb)) {
  1203. CmpUnlockKCBTree();
  1204. return STATUS_INSUFFICIENT_RESOURCES;
  1205. }
  1206. CmpUnlockKCBTree();
  1207. END_KCB_LOCK_GUARD;
  1208. } else {
  1209. //
  1210. // The key is not in cache, the CachedKcb is the parentkcb of this
  1211. // key to be opened.
  1212. //
  1213. if (Node->Flags & KEY_SYM_LINK && !(Attributes & OBJ_OPENLINK)) {
  1214. //
  1215. // Create a KCB for this symbolic key and put it in delay close.
  1216. //
  1217. kcb = CmpCreateKeyControlBlock(Hive, Cell, Node, *CachedKcb, FALSE, KeyName);
  1218. if (kcb == NULL) {
  1219. return STATUS_INSUFFICIENT_RESOURCES;
  1220. }
  1221. if( ARGUMENT_PRESENT(NeedDeref) ) {
  1222. //
  1223. // caller will perform deref.
  1224. //
  1225. *NeedDeref = TRUE;
  1226. } else {
  1227. CmpDereferenceKeyControlBlock(kcb);
  1228. }
  1229. *CachedKcb = kcb;
  1230. return(STATUS_REPARSE);
  1231. }
  1232. //
  1233. // If key control block does not exist, and cannot be created, fail,
  1234. // else just increment the ref count (done for us by CreateKeyControlBlock)
  1235. //
  1236. kcb = CmpCreateKeyControlBlock(Hive, Cell, Node, *CachedKcb, FALSE, KeyName);
  1237. if (kcb == NULL) {
  1238. return STATUS_INSUFFICIENT_RESOURCES;
  1239. }
  1240. ASSERT(kcb->Delete == FALSE);
  1241. *CachedKcb = kcb;
  1242. }
  1243. #if DBG
  1244. if( kcb->ExtFlags & CM_KCB_KEY_NON_EXIST ) {
  1245. //
  1246. // we shouldn't fall into this
  1247. //
  1248. DbgBreakPoint();
  1249. return STATUS_OBJECT_NAME_NOT_FOUND;
  1250. }
  1251. #endif //DBG
  1252. if(!CmpOKToFollowLink(OriginatingHive,(PCMHIVE)Hive) ) {
  1253. //
  1254. // about to cross class of trust boundary
  1255. //
  1256. status = STATUS_ACCESS_DENIED;
  1257. } else {
  1258. //
  1259. // Allocate the object.
  1260. //
  1261. status = ObCreateObject(AccessMode,
  1262. CmpKeyObjectType,
  1263. NULL,
  1264. AccessMode,
  1265. NULL,
  1266. sizeof(CM_KEY_BODY),
  1267. 0,
  1268. 0,
  1269. Object);
  1270. }
  1271. if (NT_SUCCESS(status)) {
  1272. pbody = (PCM_KEY_BODY)(*Object);
  1273. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_POOL,"CmpDoOpen: object allocated at:%p\n", pbody));
  1274. //
  1275. // Check for predefined handle
  1276. //
  1277. pbody = (PCM_KEY_BODY)(*Object);
  1278. if (kcb->Flags & KEY_PREDEF_HANDLE) {
  1279. pbody->Type = kcb->ValueCache.Count;
  1280. pbody->KeyControlBlock = kcb;
  1281. return(STATUS_PREDEFINED_HANDLE);
  1282. } else {
  1283. //
  1284. // Fill in CM specific fields in the object
  1285. //
  1286. pbody->Type = KEY_BODY_TYPE;
  1287. pbody->KeyControlBlock = kcb;
  1288. pbody->NotifyBlock = NULL;
  1289. pbody->ProcessID = PsGetCurrentProcessId();
  1290. ENLIST_KEYBODY_IN_KEYBODY_LIST(pbody);
  1291. }
  1292. #ifdef CM_BREAK_ON_KEY_OPEN
  1293. if( kcb->Flags & KEY_BREAK_ON_OPEN ) {
  1294. DbgPrint("\n\n Current process is opening a key tagged as BREAK ON OPEN\n");
  1295. DbgPrint("\nPlease type the following in the debugger window: !reg kcb %p\n\n\n",kcb);
  1296. try {
  1297. DbgBreakPoint();
  1298. } except (EXCEPTION_EXECUTE_HANDLER) {
  1299. //
  1300. // no debugger enabled, just keep going
  1301. //
  1302. }
  1303. }
  1304. #endif //CM_BREAK_ON_KEY_OPEN
  1305. } else {
  1306. //
  1307. // Failed to create object, so undo key control block work
  1308. //
  1309. CmpDereferenceKeyControlBlock(kcb);
  1310. return status;
  1311. }
  1312. //
  1313. // Check to make sure the caller can access the key.
  1314. //
  1315. BackupRestore = FALSE;
  1316. if (ARGUMENT_PRESENT(Context)) {
  1317. if (Context->CreateOptions & REG_OPTION_BACKUP_RESTORE) {
  1318. BackupRestore = TRUE;
  1319. }
  1320. }
  1321. status = STATUS_SUCCESS;
  1322. if (BackupRestore == TRUE) {
  1323. //
  1324. // this is an open to support a backup or restore
  1325. // operation, do the special case work
  1326. //
  1327. AccessState->RemainingDesiredAccess = 0;
  1328. AccessState->PreviouslyGrantedAccess = 0;
  1329. mode = KeGetPreviousMode();
  1330. if (SeSinglePrivilegeCheck(SeBackupPrivilege, mode)) {
  1331. AccessState->PreviouslyGrantedAccess |=
  1332. KEY_READ | ACCESS_SYSTEM_SECURITY;
  1333. }
  1334. if (SeSinglePrivilegeCheck(SeRestorePrivilege, mode)) {
  1335. AccessState->PreviouslyGrantedAccess |=
  1336. KEY_WRITE | ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER;
  1337. }
  1338. if (AccessState->PreviouslyGrantedAccess == 0) {
  1339. //
  1340. // relevent privileges not asserted/possessed, so
  1341. // deref (which will cause CmpDeleteKeyObject to clean up)
  1342. // and return an error.
  1343. //
  1344. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpDoOpen for backup restore: access denied\n"));
  1345. #ifdef CM_CHECK_FOR_ORPHANED_KCBS
  1346. //DbgPrint("CmpDoOpen for backup restore: access denied , hive = %p\n",Hive);
  1347. #endif //CM_CHECK_FOR_ORPHANED_KCBS
  1348. ObDereferenceObject(*Object);
  1349. return STATUS_ACCESS_DENIED;
  1350. }
  1351. } else {
  1352. if (!ObCheckObjectAccess(*Object,
  1353. AccessState,
  1354. TRUE, // Type mutex already locked
  1355. AccessMode,
  1356. &status))
  1357. {
  1358. //
  1359. // Access denied, so deref object, will cause CmpDeleteKeyObject
  1360. // to be called, it will clean up.
  1361. //
  1362. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpDoOpen: access denied\n"));
  1363. #ifdef CM_CHECK_FOR_ORPHANED_KCBS
  1364. //DbgPrint("CmpDoOpen: access denied , hive = %p\n",Hive);
  1365. #endif //CM_CHECK_FOR_ORPHANED_KCBS
  1366. ObDereferenceObject(*Object);
  1367. }
  1368. }
  1369. return status;
  1370. }
  1371. #ifdef CM_CHECK_FOR_ORPHANED_KCBS
  1372. ULONG CmpCheckOrphanedKcbFix = 0;
  1373. #endif //CM_CHECK_FOR_ORPHANED_KCBS
  1374. NTSTATUS
  1375. CmpCreateLinkNode(
  1376. IN PHHIVE Hive,
  1377. IN HCELL_INDEX Cell,
  1378. IN PACCESS_STATE AccessState,
  1379. IN UNICODE_STRING Name,
  1380. IN KPROCESSOR_MODE AccessMode,
  1381. IN ULONG Attributes,
  1382. IN PCM_PARSE_CONTEXT Context,
  1383. IN PCM_KEY_CONTROL_BLOCK ParentKcb,
  1384. OUT PVOID *Object
  1385. )
  1386. /*++
  1387. Routine Description:
  1388. Perform the creation of a link node. Allocate all components,
  1389. and attach to parent key. Calls CmpDoCreate or CmpDoOpen to
  1390. create or open the root node of the hive as appropriate.
  1391. Note that you can only create link nodes in the master hive.
  1392. Arguments:
  1393. Hive - supplies a pointer to the hive control structure for the hive
  1394. Cell - supplies index of node to create child under
  1395. Name - supplies pointer to a UNICODE string which is the name of
  1396. the child to be created.
  1397. AccessMode - Access mode of the original caller.
  1398. Attributes - Attributes to be applied to the object.
  1399. Context - pointer to CM_PARSE_CONTEXT structure passed through
  1400. the object manager
  1401. BaseName - Name of object create is relative to
  1402. KeyName - Relative name (to BaseName)
  1403. Object - The address of a variable to receive the created key object, if
  1404. any.
  1405. Return Value:
  1406. NTSTATUS
  1407. --*/
  1408. {
  1409. NTSTATUS Status;
  1410. PCELL_DATA Parent;
  1411. PCELL_DATA Link;
  1412. PCELL_DATA CellData;
  1413. HCELL_INDEX LinkCell;
  1414. HCELL_INDEX KeyCell;
  1415. HCELL_INDEX ChildCell;
  1416. PCM_KEY_CONTROL_BLOCK kcb = ParentKcb;
  1417. PCM_KEY_BODY KeyBody;
  1418. LARGE_INTEGER systemtime;
  1419. PCM_KEY_NODE TempNode;
  1420. LARGE_INTEGER TimeStamp;
  1421. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1422. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpCreateLinkNode:\n"));
  1423. if (Hive != &CmpMasterHive->Hive) {
  1424. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpCreateLinkNode: attempt to create link node in\n"));
  1425. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE," non-master hive %p\n", Hive));
  1426. return(STATUS_ACCESS_DENIED);
  1427. }
  1428. #if DBG
  1429. //
  1430. // debug only code
  1431. //
  1432. *Object = NULL;
  1433. #endif
  1434. //
  1435. // this is a create, so we need exclusive access on the registry
  1436. // first get the time stamp to see if somebody messed with this key
  1437. // this might be more easier if we decide to cache the LastWriteTime
  1438. // in the KCB ; now it IS !!!
  1439. //
  1440. if( CmIsKcbReadOnly(ParentKcb) ) {
  1441. //
  1442. // key is protected
  1443. //
  1444. return STATUS_ACCESS_DENIED;
  1445. }
  1446. TimeStamp = ParentKcb->KcbLastWriteTime;
  1447. CmpUnlockRegistry();
  1448. CmpLockRegistryExclusive();
  1449. #ifdef CHECK_REGISTRY_USECOUNT
  1450. CmpCheckRegistryUseCount();
  1451. #endif //CHECK_REGISTRY_USECOUNT
  1452. //
  1453. // make sure nothing changed in between:
  1454. // 1. ParentKcb is still valid
  1455. // 2. Child was not already added by somebody else
  1456. //
  1457. if( ParentKcb->Delete ) {
  1458. //
  1459. // key was deleted in between
  1460. //
  1461. return STATUS_OBJECT_NAME_NOT_FOUND;
  1462. }
  1463. if( TimeStamp.QuadPart != ParentKcb->KcbLastWriteTime.QuadPart ) {
  1464. //
  1465. // key was changed in between; possibly this key was already created ==> reparse
  1466. //
  1467. return STATUS_REPARSE;
  1468. }
  1469. //
  1470. // Allocate link node
  1471. //
  1472. // Link nodes are always in the master hive, so their storage type is
  1473. // mostly irrelevent.
  1474. //
  1475. LinkCell = HvAllocateCell(Hive, CmpHKeyNodeSize(Hive, &Name), Stable,HCELL_NIL);
  1476. if (LinkCell == HCELL_NIL) {
  1477. return STATUS_INSUFFICIENT_RESOURCES;
  1478. }
  1479. KeyCell = Context->ChildHive.KeyCell;
  1480. if (KeyCell != HCELL_NIL) {
  1481. //
  1482. // This hive already exists, so we just need to open the root node.
  1483. //
  1484. ChildCell=KeyCell;
  1485. //
  1486. // The root cell in the hive does not has the Name buffer
  1487. // space reseverd. This is why we need to pass in the Name for creating KCB
  1488. // instead of using the name in the keynode.
  1489. //
  1490. CellData = HvGetCell(Context->ChildHive.KeyHive, ChildCell);
  1491. if( CellData == NULL ) {
  1492. //
  1493. // we couldn't map the bin contianing this cell
  1494. //
  1495. HvFreeCell(Hive, LinkCell);
  1496. return STATUS_INSUFFICIENT_RESOURCES;
  1497. }
  1498. // release the cell right here as we are holding the reglock exclusive
  1499. HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
  1500. CellData->u.KeyNode.Parent = LinkCell;
  1501. CellData->u.KeyNode.Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
  1502. TempNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive,KeyCell);
  1503. if( TempNode == NULL ) {
  1504. //
  1505. // we couldn't map the bin contianing this cell
  1506. //
  1507. HvFreeCell(Hive, LinkCell);
  1508. return STATUS_INSUFFICIENT_RESOURCES;
  1509. }
  1510. // release the cell right here as we are holding the reglock exclusive
  1511. HvReleaseCell(Context->ChildHive.KeyHive,KeyCell);
  1512. Status = CmpDoOpen( Context->ChildHive.KeyHive,
  1513. KeyCell,
  1514. TempNode,
  1515. AccessState,
  1516. AccessMode,
  1517. Attributes,
  1518. NULL,
  1519. FALSE,
  1520. &kcb,
  1521. &Name,
  1522. CmpParseGetOriginatingPoint(Context),
  1523. Object,
  1524. NULL);
  1525. } else {
  1526. //
  1527. // This is a newly created hive, so we must allocate and initialize
  1528. // the root node.
  1529. //
  1530. Status = CmpDoCreateChild( Context->ChildHive.KeyHive,
  1531. Cell,
  1532. NULL,
  1533. AccessState,
  1534. &Name,
  1535. AccessMode,
  1536. Context,
  1537. ParentKcb,
  1538. KEY_HIVE_ENTRY | KEY_NO_DELETE,
  1539. &ChildCell,
  1540. Object );
  1541. if (NT_SUCCESS(Status)) {
  1542. //
  1543. // Initialize hive root cell pointer.
  1544. //
  1545. Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell;
  1546. }
  1547. }
  1548. if (NT_SUCCESS(Status)) {
  1549. #ifdef CM_CHECK_FOR_ORPHANED_KCBS
  1550. if(CmpCheckOrphanedKcbFix) {
  1551. DbgPrint("CmpCreateLinkNode: Force return with STATUS_NO_LOG_SPACE\n");
  1552. Status = STATUS_NO_LOG_SPACE;
  1553. goto Cleanup;
  1554. }
  1555. #endif //CM_CHECK_FOR_ORPHANED_KCBS
  1556. //
  1557. // Initialize parent and flags. Note that we do this whether the
  1558. // root has been created or opened, because we are not guaranteed
  1559. // that the link node is always the same cell in the master hive.
  1560. //
  1561. if (!HvMarkCellDirty(Context->ChildHive.KeyHive, ChildCell)) {
  1562. Status = STATUS_NO_LOG_SPACE;
  1563. goto Cleanup;
  1564. }
  1565. CellData = HvGetCell(Context->ChildHive.KeyHive, ChildCell);
  1566. if( CellData == NULL ) {
  1567. //
  1568. // we couldn't map the bin contianing this cell
  1569. //
  1570. HvFreeCell(Hive, LinkCell);
  1571. Status = STATUS_INSUFFICIENT_RESOURCES;
  1572. goto Cleanup;
  1573. }
  1574. // release the cell right here as we are holding the reglock exclusive
  1575. HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
  1576. CellData->u.KeyNode.Parent = LinkCell;
  1577. CellData->u.KeyNode.Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
  1578. //
  1579. // Initialize special link node flags and data
  1580. //
  1581. Link = HvGetCell(Hive, LinkCell);
  1582. if( Link == NULL ) {
  1583. //
  1584. // we couldn't map the bin contianing this cell
  1585. // this shouldn't happen as we just allocated this cell
  1586. // (i.e. it should be PINNED in memory at this point)
  1587. //
  1588. ASSERT( FALSE );
  1589. HvFreeCell(Hive, LinkCell);
  1590. Status = STATUS_INSUFFICIENT_RESOURCES;
  1591. goto Cleanup;
  1592. }
  1593. // release the cell right here as we are holding the reglock exclusive
  1594. HvReleaseCell(Hive,LinkCell);
  1595. Link->u.KeyNode.Signature = CM_LINK_NODE_SIGNATURE;
  1596. Link->u.KeyNode.Flags = KEY_HIVE_EXIT | KEY_NO_DELETE;
  1597. Link->u.KeyNode.Parent = Cell;
  1598. Link->u.KeyNode.NameLength = CmpCopyName(Hive, Link->u.KeyNode.Name, &Name);
  1599. if (Link->u.KeyNode.NameLength < Name.Length) {
  1600. Link->u.KeyNode.Flags |= KEY_COMP_NAME;
  1601. }
  1602. KeQuerySystemTime(&systemtime);
  1603. Link->u.KeyNode.LastWriteTime = systemtime;
  1604. //
  1605. // Zero out unused fields.
  1606. //
  1607. Link->u.KeyNode.SubKeyCounts[Stable] = 0;
  1608. Link->u.KeyNode.SubKeyCounts[Volatile] = 0;
  1609. Link->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL;
  1610. Link->u.KeyNode.SubKeyLists[Volatile] = HCELL_NIL;
  1611. Link->u.KeyNode.ValueList.Count = 0;
  1612. Link->u.KeyNode.ValueList.List = HCELL_NIL;
  1613. Link->u.KeyNode.ClassLength = 0;
  1614. //
  1615. // Fill in the link node's pointer to the root node
  1616. //
  1617. Link->u.KeyNode.ChildHiveReference.KeyHive = Context->ChildHive.KeyHive;
  1618. Link->u.KeyNode.ChildHiveReference.KeyCell = ChildCell;
  1619. //
  1620. // get the parent first, we don't need to do unneccessary cleanup
  1621. //
  1622. Parent = HvGetCell(Hive, Cell);
  1623. if( Parent == NULL ) {
  1624. //
  1625. // we couldn't map the bin contianing this cell
  1626. //
  1627. HvFreeCell(Hive, LinkCell);
  1628. Status = STATUS_INSUFFICIENT_RESOURCES;
  1629. goto Cleanup;
  1630. }
  1631. // release the cell right here as we are holding the reglock exclusive
  1632. HvReleaseCell(Hive,Cell);
  1633. //
  1634. // Fill in the parent cell's child list
  1635. //
  1636. if (! CmpAddSubKey(Hive, Cell, LinkCell)) {
  1637. HvFreeCell(Hive, LinkCell);
  1638. Status = STATUS_INSUFFICIENT_RESOURCES;
  1639. goto Cleanup;
  1640. }
  1641. //
  1642. // If the parent has the subkey info or hint cached, free it.
  1643. //
  1644. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1645. KeyBody = (PCM_KEY_BODY)(*Object);
  1646. CmpCleanUpSubKeyInfo (KeyBody->KeyControlBlock->ParentKcb);
  1647. //
  1648. // Update max keyname and class name length fields
  1649. //
  1650. //
  1651. // It seems to me that the original code is wrong.
  1652. // Isn't the definition of MaxNameLen just the length of the subkey?
  1653. //
  1654. // some sanity asserts
  1655. ASSERT( KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell );
  1656. ASSERT( KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive );
  1657. ASSERT( KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == Parent->u.KeyNode.MaxNameLen );
  1658. //
  1659. // update the LastWriteTime on both keynode and kcb;
  1660. //
  1661. KeQuerySystemTime(&systemtime);
  1662. Parent->u.KeyNode.LastWriteTime = systemtime;
  1663. KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = systemtime;
  1664. if (Parent->u.KeyNode.MaxNameLen < Name.Length) {
  1665. Parent->u.KeyNode.MaxNameLen = Name.Length;
  1666. KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name.Length;
  1667. }
  1668. if (Parent->u.KeyNode.MaxClassLen < Context->Class.Length) {
  1669. Parent->u.KeyNode.MaxClassLen = Context->Class.Length;
  1670. }
  1671. Cleanup:
  1672. if( !NT_SUCCESS(Status) ) {
  1673. ASSERT( (*Object) != NULL );
  1674. //
  1675. // mark the kcb as "no-delay-close" so it gets kicked out of cache when
  1676. // refcount goes down to 0
  1677. //
  1678. KeyBody = (PCM_KEY_BODY)(*Object);
  1679. ASSERT( KeyBody->KeyControlBlock );
  1680. ASSERT_KCB( KeyBody->KeyControlBlock );
  1681. KeyBody->KeyControlBlock->ExtFlags |= CM_KCB_NO_DELAY_CLOSE;
  1682. ObDereferenceObject(*Object);
  1683. }
  1684. } else {
  1685. HvFreeCell(Hive, LinkCell);
  1686. }
  1687. return(Status);
  1688. }
  1689. BOOLEAN
  1690. CmpGetSymbolicLink(
  1691. IN PHHIVE Hive,
  1692. IN OUT PUNICODE_STRING ObjectName,
  1693. IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb,
  1694. IN PUNICODE_STRING RemainingName OPTIONAL
  1695. )
  1696. /*++
  1697. Routine Description:
  1698. This routine extracts the symbolic link name from a key, if it is
  1699. marked as a symbolic link.
  1700. Arguments:
  1701. Hive - Supplies the hive of the key.
  1702. ObjectName - Supplies the current ObjectName.
  1703. Returns the new ObjectName. If the new name is longer
  1704. than the maximum length of the current ObjectName, the
  1705. old buffer will be freed and a new buffer allocated.
  1706. RemainingName - Supplies the remaining path. If present, this will be
  1707. concatenated with the symbolic link to form the new objectname.
  1708. Return Value:
  1709. TRUE - symbolic link succesfully found
  1710. FALSE - Key is not a symbolic link, or an error occurred
  1711. --*/
  1712. {
  1713. NTSTATUS Status;
  1714. HCELL_INDEX LinkCell = HCELL_NIL;
  1715. PCM_KEY_VALUE LinkValue = NULL;
  1716. PWSTR LinkName = NULL;
  1717. BOOLEAN LinkNameAllocated = FALSE;
  1718. PWSTR NewBuffer;
  1719. ULONG Length = 0;
  1720. ULONG ValueLength = 0;
  1721. extern ULONG CmpHashTableSize;
  1722. extern PCM_KEY_HASH *CmpCacheTable;
  1723. PUNICODE_STRING ConstructedName = NULL;
  1724. ULONG ConvKey=0;
  1725. PCM_KEY_HASH KeyHash;
  1726. PCM_KEY_CONTROL_BLOCK RealKcb;
  1727. BOOLEAN KcbFound = FALSE;
  1728. ULONG Cnt;
  1729. WCHAR *Cp;
  1730. WCHAR *Cp2;
  1731. ULONG TotalLevels;
  1732. BOOLEAN FreeConstructedName = FALSE;
  1733. BOOLEAN Result = TRUE;
  1734. HCELL_INDEX CellToRelease = HCELL_NIL;
  1735. #ifdef CM_DYN_SYM_LINK
  1736. BOOLEAN DynamicLink = FALSE;
  1737. PWSTR ExpandedLinkName = NULL;
  1738. #endif //CM_DYN_SYM_LINK
  1739. BEGIN_KCB_LOCK_GUARD;
  1740. CmpLockKCBTree();
  1741. if (SymbolicKcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) {
  1742. //
  1743. // First see of the real kcb for this symbolic name has been found
  1744. //
  1745. ConstructedName = CmpConstructName(SymbolicKcb->ValueCache.RealKcb);
  1746. if (ConstructedName) {
  1747. FreeConstructedName = TRUE;
  1748. LinkName = ConstructedName->Buffer;
  1749. ValueLength = ConstructedName->Length;
  1750. Length = (USHORT)ValueLength + sizeof(WCHAR);
  1751. }
  1752. }
  1753. CmpUnlockKCBTree();
  1754. END_KCB_LOCK_GUARD;
  1755. if (FreeConstructedName == FALSE) {
  1756. PCM_KEY_NODE Node;
  1757. //
  1758. // Find the SymbolicLinkValue value. This is the name of the symbolic link.
  1759. //
  1760. Node = (PCM_KEY_NODE)HvGetCell(SymbolicKcb->KeyHive,SymbolicKcb->KeyCell);
  1761. if( Node == NULL ) {
  1762. //
  1763. // we couldn't map the bin containing this cell
  1764. //
  1765. Result = FALSE;
  1766. goto Exit;
  1767. }
  1768. LinkCell = CmpFindValueByName(Hive,
  1769. Node,
  1770. &CmSymbolicLinkValueName);
  1771. // release the node here as we don't need it anymore
  1772. HvReleaseCell(SymbolicKcb->KeyHive,SymbolicKcb->KeyCell);
  1773. if (LinkCell == HCELL_NIL) {
  1774. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpGetSymbolicLink: couldn't open symbolic link\n"));
  1775. Result = FALSE;
  1776. goto Exit;
  1777. }
  1778. LinkValue = (PCM_KEY_VALUE)HvGetCell(Hive, LinkCell);
  1779. if( LinkValue == NULL ) {
  1780. //
  1781. // we couldn't map the bin containing this cell
  1782. //
  1783. Result = FALSE;
  1784. goto Exit;
  1785. }
  1786. #ifdef CM_DYN_SYM_LINK
  1787. if( LinkValue->Type == REG_DYN_LINK ) {
  1788. //
  1789. // we have found a dynamic link
  1790. //
  1791. DynamicLink = TRUE;
  1792. } else
  1793. #endif //CM_DYN_SYM_LINK
  1794. if (LinkValue->Type != REG_LINK) {
  1795. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpGetSymbolicLink: link value is wrong type: %08lx", LinkValue->Type));
  1796. Result = FALSE;
  1797. goto Exit;
  1798. }
  1799. if( CmpGetValueData(Hive,LinkValue,&ValueLength,&LinkName,&LinkNameAllocated,&CellToRelease) == FALSE ) {
  1800. //
  1801. // insufficient resources; return NULL
  1802. //
  1803. ASSERT( LinkNameAllocated == FALSE );
  1804. ASSERT( LinkName == NULL );
  1805. Result = FALSE;
  1806. goto Exit;
  1807. }
  1808. #ifdef CM_DYN_SYM_LINK
  1809. if( DynamicLink == TRUE ) {
  1810. ULONG DestLength;
  1811. ExpandedLinkName = CmpExpandEnvVars(LinkName,ValueLength,&DestLength);
  1812. if( ExpandedLinkName == NULL ) {
  1813. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Dynamic link not resolved !\n"));
  1814. Result = FALSE;
  1815. goto Exit;
  1816. }
  1817. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Dynamic link resolved to: (%.*S)\n",DestLength/sizeof(WCHAR),ExpandedLinkName));
  1818. //
  1819. // if we are here, we successfully resolved the link
  1820. //
  1821. LinkName = ExpandedLinkName;
  1822. ValueLength = DestLength;
  1823. }
  1824. #endif //CM_DYN_SYM_LINK
  1825. Length = (USHORT)ValueLength + sizeof(WCHAR);
  1826. #ifdef CM_DYN_SYM_LINK
  1827. if( DynamicLink == FALSE ) {
  1828. #endif //CM_DYN_SYM_LINK
  1829. //
  1830. // Now see if we have this kcb cached.
  1831. //
  1832. Cp = LinkName;
  1833. //
  1834. // first char SHOULD be OBJ_NAME_PATH_SEPARATOR, otherwise we could get into real trouble!!!
  1835. //
  1836. if( *Cp != OBJ_NAME_PATH_SEPARATOR ) {
  1837. Result = FALSE;
  1838. goto Exit;
  1839. }
  1840. TotalLevels = 0;
  1841. for (Cnt=0; Cnt<ValueLength; Cnt += sizeof(WCHAR)) {
  1842. if (*Cp != OBJ_NAME_PATH_SEPARATOR) {
  1843. ConvKey = 37 * ConvKey + (ULONG) CmUpcaseUnicodeChar(*Cp);
  1844. } else {
  1845. TotalLevels++;
  1846. }
  1847. ++Cp;
  1848. }
  1849. BEGIN_KCB_LOCK_GUARD;
  1850. CmpLockKCBTreeExclusive();
  1851. KeyHash = GET_HASH_ENTRY(CmpCacheTable, ConvKey);
  1852. while (KeyHash) {
  1853. RealKcb = CONTAINING_RECORD(KeyHash, CM_KEY_CONTROL_BLOCK, KeyHash);
  1854. if ((ConvKey == KeyHash->ConvKey) && (TotalLevels == RealKcb->TotalLevels) && (!(RealKcb->ExtFlags & CM_KCB_KEY_NON_EXIST)) ) {
  1855. ConstructedName = CmpConstructName(RealKcb);
  1856. if (ConstructedName) {
  1857. FreeConstructedName = TRUE;
  1858. if (ConstructedName->Length == ValueLength) {
  1859. KcbFound = TRUE;
  1860. Cp = LinkName;
  1861. Cp2 = ConstructedName->Buffer;
  1862. for (Cnt=0; Cnt<ConstructedName->Length; Cnt += sizeof(WCHAR)) {
  1863. if (CmUpcaseUnicodeChar(*Cp) != CmUpcaseUnicodeChar(*Cp2)) {
  1864. KcbFound = FALSE;
  1865. break;
  1866. }
  1867. ++Cp;
  1868. ++Cp2;
  1869. }
  1870. if (KcbFound) {
  1871. //
  1872. // Now the RealKcb is also pointed to by its symbolic link Kcb,
  1873. // Increase the reference count.
  1874. // Need to dereference the realkcb when the symbolic kcb is removed.
  1875. // Do this in CmpCleanUpKcbCacheWithLock();
  1876. //
  1877. if (CmpReferenceKeyControlBlock(RealKcb)) {
  1878. if( CmpOKToFollowLink( (((PCMHIVE)(SymbolicKcb->KeyHive))->Flags&CM_CMHIVE_FLAG_UNTRUSTED)?(PCMHIVE)(SymbolicKcb->KeyHive):NULL,
  1879. (PCMHIVE)(RealKcb->KeyHive))) {
  1880. //
  1881. // This symbolic kcb may have value lookup for the path
  1882. // Cleanup the value cache.
  1883. //
  1884. CmpCleanUpKcbValueCache(SymbolicKcb);
  1885. SymbolicKcb->ExtFlags |= CM_KCB_SYM_LINK_FOUND;
  1886. SymbolicKcb->ValueCache.RealKcb = RealKcb;
  1887. } else {
  1888. //
  1889. // let go of the extra ref and break
  1890. //
  1891. CmpDereferenceKeyControlBlockWithLock(RealKcb);
  1892. break;
  1893. }
  1894. } else {
  1895. //
  1896. // We have maxed out the ref count on the real kcb.
  1897. // do not cache the symbolic link.
  1898. //
  1899. }
  1900. break;
  1901. }
  1902. }
  1903. } else {
  1904. break;
  1905. }
  1906. }
  1907. if (FreeConstructedName) {
  1908. ExFreePoolWithTag(ConstructedName, CM_NAME_TAG | PROTECTED_POOL);
  1909. FreeConstructedName = FALSE;
  1910. }
  1911. KeyHash = KeyHash->NextHash;
  1912. }
  1913. CmpUnlockKCBTree();
  1914. END_KCB_LOCK_GUARD;
  1915. #ifdef CM_DYN_SYM_LINK
  1916. }
  1917. #endif //CM_DYN_SYM_LINK
  1918. }
  1919. if (ARGUMENT_PRESENT(RemainingName)) {
  1920. Length += RemainingName->Length + sizeof(WCHAR);
  1921. }
  1922. //
  1923. // Overflow test: If Length overflows the USHRT_MAX value
  1924. // cleanup and return FALSE
  1925. //
  1926. if( Length>0xFFFF ) {
  1927. Result = FALSE;
  1928. goto Exit;
  1929. }
  1930. if (Length > ObjectName->MaximumLength) {
  1931. UNICODE_STRING NewObjectName;
  1932. //
  1933. // The new name is too long to fit in the existing ObjectName buffer,
  1934. // so allocate a new buffer.
  1935. //
  1936. NewBuffer = ExAllocatePool(PagedPool, Length);
  1937. if (NewBuffer == NULL) {
  1938. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpGetSymbolicLink: couldn't allocate new name buffer\n"));
  1939. Result = FALSE;
  1940. goto Exit;
  1941. }
  1942. NewObjectName.Buffer = NewBuffer;
  1943. NewObjectName.MaximumLength = (USHORT)Length;
  1944. NewObjectName.Length = (USHORT)ValueLength;
  1945. RtlCopyMemory(NewBuffer, LinkName, ValueLength);
  1946. #if DBG
  1947. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpGetSymbolicLink: LinkName is %wZ\n", ObjectName));
  1948. if (ARGUMENT_PRESENT(RemainingName)) {
  1949. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE," RemainingName is %wZ\n", RemainingName));
  1950. } else {
  1951. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE," RemainingName is NULL\n"));
  1952. }
  1953. #endif
  1954. if (ARGUMENT_PRESENT(RemainingName)) {
  1955. NewBuffer[ ValueLength / sizeof(WCHAR) ] = OBJ_NAME_PATH_SEPARATOR;
  1956. NewObjectName.Length += sizeof(WCHAR);
  1957. Status = RtlAppendUnicodeStringToString(&NewObjectName, RemainingName);
  1958. ASSERT(NT_SUCCESS(Status));
  1959. }
  1960. ExFreePool(ObjectName->Buffer);
  1961. *ObjectName = NewObjectName;
  1962. } else {
  1963. //
  1964. // The new name will fit within the maximum length of the existing
  1965. // ObjectName, so do the expansion in-place. Note that the remaining
  1966. // name must be moved into its new position first since the symbolic
  1967. // link may or may not overlap it.
  1968. //
  1969. ObjectName->Length = (USHORT)ValueLength;
  1970. if (ARGUMENT_PRESENT(RemainingName)) {
  1971. RtlMoveMemory(&ObjectName->Buffer[(ValueLength / sizeof(WCHAR)) + 1],
  1972. RemainingName->Buffer,
  1973. RemainingName->Length);
  1974. ObjectName->Buffer[ValueLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
  1975. ObjectName->Length += RemainingName->Length + sizeof(WCHAR);
  1976. }
  1977. RtlCopyMemory(ObjectName->Buffer, LinkName, ValueLength);
  1978. }
  1979. ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] = UNICODE_NULL;
  1980. Exit:
  1981. if( LinkNameAllocated ) {
  1982. ExFreePool(LinkName);
  1983. }
  1984. if (FreeConstructedName) {
  1985. ExFreePoolWithTag(ConstructedName, CM_NAME_TAG | PROTECTED_POOL);
  1986. }
  1987. #ifdef CM_DYN_SYM_LINK
  1988. if( ExpandedLinkName ) {
  1989. ExFreePool(ExpandedLinkName);
  1990. }
  1991. #endif //CM_DYN_SYM_LINK
  1992. if( LinkValue != NULL ) {
  1993. ASSERT( LinkCell != HCELL_NIL );
  1994. HvReleaseCell(Hive,LinkCell);
  1995. }
  1996. if( CellToRelease != HCELL_NIL ) {
  1997. HvReleaseCell(Hive,CellToRelease);
  1998. }
  1999. return Result;
  2000. }
  2001. ULONG
  2002. CmpComputeHashValue(
  2003. IN PCM_HASH_ENTRY HashStack,
  2004. IN OUT ULONG *TotalSubkeys,
  2005. IN ULONG BaseConvKey,
  2006. IN PUNICODE_STRING RemainingName
  2007. )
  2008. /*++
  2009. Routine Description:
  2010. This routine parses the complete path of a request registry key and calculate
  2011. the hash value at each level.
  2012. Arguments:
  2013. HashStack - Array for filling the hash value of each level.
  2014. TotalSubkeys - a pointer to fill the total number of subkeys
  2015. BaseConvKey - Supplies the convkey for the base key.
  2016. RemainingName - supplies pointer to a unicode_string for RemainingName.
  2017. Return Value:
  2018. Number of Levels in RemainingName
  2019. --*/
  2020. {
  2021. ULONG TotalRemainingSubkeys=0;
  2022. ULONG TotalKeys=0;
  2023. ULONG ConvKey=BaseConvKey;
  2024. USHORT Cnt;
  2025. WCHAR *Cp;
  2026. WCHAR *Begin;
  2027. USHORT Length;
  2028. if (RemainingName->Length) {
  2029. Cp = RemainingName->Buffer;
  2030. Cnt = RemainingName->Length;
  2031. //Skip the leading OBJ_NAME_PATH_SEPARATOR
  2032. while (*Cp == OBJ_NAME_PATH_SEPARATOR) {
  2033. Cp++;
  2034. Cnt -= sizeof(WCHAR);
  2035. }
  2036. Begin = Cp;
  2037. Length = 0;
  2038. HashStack[TotalRemainingSubkeys].KeyName.Buffer = Cp;
  2039. while (Cnt) {
  2040. if (*Cp == OBJ_NAME_PATH_SEPARATOR) {
  2041. if (TotalRemainingSubkeys < CM_HASH_STACK_SIZE) {
  2042. HashStack[TotalRemainingSubkeys].ConvKey = ConvKey;
  2043. //
  2044. // Due to the changes in KCB structure, we now only have the subkey name
  2045. // in the kcb (not the full path). Change the name in the stack to store
  2046. // the parse element (each subkey) only.
  2047. //
  2048. HashStack[TotalRemainingSubkeys].KeyName.Length = Length;
  2049. Length = 0;
  2050. TotalRemainingSubkeys++;
  2051. }
  2052. TotalKeys++;
  2053. //
  2054. // Now skip over leading path separators
  2055. // Just in case someone has a RemainingName '..A\\\\B..'
  2056. //
  2057. //
  2058. // We are stripping all OBJ_NAME_PATH_SEPARATOR (The origainl code keep the first one).
  2059. // so the KeyName.Buffer is set properly.
  2060. //
  2061. while(*Cp == OBJ_NAME_PATH_SEPARATOR) {
  2062. Cp++;
  2063. Cnt -= sizeof(WCHAR);
  2064. }
  2065. if (TotalRemainingSubkeys < CM_HASH_STACK_SIZE) {
  2066. HashStack[TotalRemainingSubkeys].KeyName.Buffer = Cp;
  2067. }
  2068. } else {
  2069. ConvKey = 37 * ConvKey + (ULONG) CmUpcaseUnicodeChar(*Cp);
  2070. //
  2071. // We are stripping all OBJ_NAME_PATH_SEPARATOR in the above code,
  2072. // we should only move to the next char in the else case.
  2073. //
  2074. Cp++;
  2075. Cnt -= sizeof(WCHAR);
  2076. Length += sizeof(WCHAR);
  2077. }
  2078. }
  2079. //
  2080. // Since we have stripped off all trailing path separators in CmpParseKey routine,
  2081. // the last char will not be OBJ_NAME_PATH_SEPARATOR.
  2082. //
  2083. if (TotalRemainingSubkeys < CM_HASH_STACK_SIZE) {
  2084. HashStack[TotalRemainingSubkeys].ConvKey = ConvKey;
  2085. HashStack[TotalRemainingSubkeys].KeyName.Length = Length;
  2086. TotalRemainingSubkeys++;
  2087. }
  2088. TotalKeys++;
  2089. (*TotalSubkeys) = TotalKeys;
  2090. }
  2091. return(TotalRemainingSubkeys);
  2092. }
  2093. NTSTATUS
  2094. CmpCacheLookup(
  2095. IN PCM_HASH_ENTRY HashStack,
  2096. IN ULONG TotalRemainingSubkeys,
  2097. OUT ULONG *MatchRemainSubkeyLevel,
  2098. IN OUT PCM_KEY_CONTROL_BLOCK *Kcb,
  2099. OUT PUNICODE_STRING RemainingName,
  2100. OUT PHHIVE *Hive,
  2101. OUT HCELL_INDEX *Cell
  2102. )
  2103. /*++
  2104. Routine Description:
  2105. This routine Search the cache to find the matching path in the Cache.
  2106. Arguments:
  2107. HashStack - Array that has the hash value of each level.
  2108. TotalRemainingSubkeys - Total Subkey counts from base.
  2109. MatchRemainSubkeyLevel - Number of Levels in RemaingName
  2110. that matches. (0 if not found)
  2111. kcb - Pointer to the kcb of the basename.
  2112. Will be changed to the kcb for the new basename.
  2113. RemainingName - Returns remaining name
  2114. Hive - Returns the hive of the cache entry found (if any)
  2115. Cell - Returns the cell of the cache entry found (if any)
  2116. Return Value:
  2117. Status
  2118. --*/
  2119. {
  2120. LONG i;
  2121. LONG j;
  2122. NTSTATUS status = STATUS_SUCCESS;
  2123. ULONG CurrentLevel;
  2124. PCM_KEY_HASH Current;
  2125. PCM_KEY_CONTROL_BLOCK BaseKcb;
  2126. PCM_KEY_CONTROL_BLOCK CurrentKcb;
  2127. PCM_KEY_CONTROL_BLOCK ParentKcb;
  2128. BOOLEAN Found = FALSE;
  2129. BaseKcb = *Kcb;
  2130. CurrentLevel = TotalRemainingSubkeys + BaseKcb->TotalLevels + 1;
  2131. for(i = TotalRemainingSubkeys-1; i>=0; i--) {
  2132. //
  2133. // Try to find the longest path in the cache.
  2134. //
  2135. // First, find the kcb that match the hash value.
  2136. //
  2137. CurrentLevel--;
  2138. RetryLevel:
  2139. Current = GET_HASH_ENTRY(CmpCacheTable, HashStack[i].ConvKey);
  2140. while (Current) {
  2141. ASSERT_KEY_HASH(Current);
  2142. //
  2143. // Check against both the ConvKey and total levels;
  2144. //
  2145. CurrentKcb = (CONTAINING_RECORD(Current, CM_KEY_CONTROL_BLOCK, KeyHash));
  2146. if (CurrentKcb->TotalLevels == CurrentLevel) {
  2147. //
  2148. // The total subkey levels match.
  2149. // Iterate through the kcb path and compare each subkey.
  2150. //
  2151. Found = TRUE;
  2152. ParentKcb = CurrentKcb;
  2153. for (j=i; j>=0; j--) {
  2154. if (HashStack[j].ConvKey == ParentKcb->ConvKey) {
  2155. //
  2156. // Convkey matches, compare the string
  2157. //
  2158. LONG Result;
  2159. UNICODE_STRING TmpNodeName;
  2160. if (ParentKcb->NameBlock->Compressed) {
  2161. Result = CmpCompareCompressedName(&(HashStack[j].KeyName),
  2162. ParentKcb->NameBlock->Name,
  2163. ParentKcb->NameBlock->NameLength,
  2164. CMP_DEST_UP // name block is always UPPERCASE!!!
  2165. );
  2166. } else {
  2167. TmpNodeName.Buffer = ParentKcb->NameBlock->Name;
  2168. TmpNodeName.Length = ParentKcb->NameBlock->NameLength;
  2169. TmpNodeName.MaximumLength = ParentKcb->NameBlock->NameLength;
  2170. //
  2171. // use the cmp compare variant as we know the destination is already uppercased.
  2172. //
  2173. Result = CmpCompareUnicodeString(&(HashStack[j].KeyName),
  2174. &TmpNodeName,
  2175. CMP_DEST_UP);
  2176. }
  2177. if (Result) {
  2178. Found = FALSE;
  2179. break;
  2180. }
  2181. ParentKcb = ParentKcb->ParentKcb;
  2182. } else {
  2183. Found = FALSE;
  2184. break;
  2185. }
  2186. }
  2187. if (Found) {
  2188. //
  2189. // All remaining key matches. Now compare the BaseKcb.
  2190. //
  2191. if (BaseKcb == ParentKcb) {
  2192. // if neither of these, don't need to ugrade KCB lock
  2193. if (CurrentKcb->ParentKcb->Delete || CurrentKcb->Delete) {
  2194. if (CmpKcbOwner != KeGetCurrentThread()) {
  2195. InterlockedIncrement( (PLONG)&CurrentKcb->RefCount );
  2196. CmpUnlockKCBTree();
  2197. CmpLockKCBTreeExclusive();
  2198. InterlockedDecrement( (PLONG)&CurrentKcb->RefCount );
  2199. goto RetryLevel;
  2200. }
  2201. if (CurrentKcb->ParentKcb->Delete) {
  2202. //
  2203. // The parentkcb is marked deleted.
  2204. // So this must be a fake key created when the parent still existed.
  2205. // Otherwise it cannot be in the cache
  2206. //
  2207. ASSERT (CurrentKcb->ExtFlags & CM_KCB_KEY_NON_EXIST);
  2208. //
  2209. // It is possible that the parent key was deleted but now recreated.
  2210. // In that case this fake key is not longer valid for the ParentKcb is bad.
  2211. // We must now remove this fake key out of cache so, if this is a
  2212. // create operation, we do get hit this kcb in CmpCreateKeyControlBlock.
  2213. //
  2214. if (CurrentKcb->RefCount == 0) {
  2215. //
  2216. // No one is holding this fake kcb, just delete it.
  2217. //
  2218. CmpRemoveFromDelayedClose(CurrentKcb);
  2219. CmpCleanUpKcbCacheWithLock(CurrentKcb);
  2220. } else {
  2221. //
  2222. // Someone is still holding this fake kcb,
  2223. // Mark it as delete and remove it out of cache.
  2224. //
  2225. CurrentKcb->Delete = TRUE;
  2226. CmpRemoveKeyControlBlock(CurrentKcb);
  2227. }
  2228. Found = FALSE;
  2229. break;
  2230. } else if(CurrentKcb->Delete) {
  2231. //
  2232. // the key has been deleted, but still kept in the cache for
  2233. // this kcb does not belong here
  2234. //
  2235. CmpRemoveKeyControlBlock(CurrentKcb);
  2236. return STATUS_OBJECT_NAME_NOT_FOUND;
  2237. }
  2238. }
  2239. //
  2240. // We have a match, update the RemainingName.
  2241. //
  2242. //
  2243. // Skip the leading OBJ_NAME_PATH_SEPARATOR
  2244. //
  2245. while ((RemainingName->Length > 0) &&
  2246. (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) {
  2247. RemainingName->Buffer++;
  2248. RemainingName->Length -= sizeof(WCHAR);
  2249. }
  2250. //
  2251. // Skip all subkeys plus OBJ_NAME_PATH_SEPARATOR
  2252. //
  2253. for(j=0; j<=i; j++) {
  2254. RemainingName->Buffer += HashStack[j].KeyName.Length/sizeof(WCHAR) + 1;
  2255. RemainingName->Length -= HashStack[j].KeyName.Length + sizeof(WCHAR);
  2256. }
  2257. //
  2258. // Update the KCB, Hive and Cell.
  2259. //
  2260. *Kcb = CurrentKcb;
  2261. *Hive = CurrentKcb->KeyHive;
  2262. *Cell = CurrentKcb->KeyCell;
  2263. break;
  2264. } else {
  2265. Found = FALSE;
  2266. }
  2267. }
  2268. }
  2269. Current = Current->NextHash;
  2270. }
  2271. if (Found) {
  2272. break;
  2273. }
  2274. }
  2275. if((*Kcb)->Delete) {
  2276. //
  2277. // the key has been deleted, but still kept in the cache for
  2278. // this kcb does not belong here
  2279. //
  2280. return STATUS_OBJECT_NAME_NOT_FOUND;
  2281. }
  2282. //
  2283. // Now the kcb will be used in the parse routine.
  2284. // Increase its reference count.
  2285. // Make sure we remember to dereference it at the parse routine.
  2286. //
  2287. if (!CmpReferenceKeyControlBlock(*Kcb)) {
  2288. status = STATUS_INSUFFICIENT_RESOURCES;
  2289. }
  2290. *MatchRemainSubkeyLevel = i+1;
  2291. return status;
  2292. }
  2293. PCM_KEY_CONTROL_BLOCK
  2294. CmpAddInfoAfterParseFailure(
  2295. PHHIVE Hive,
  2296. HCELL_INDEX Cell,
  2297. PCM_KEY_NODE Node,
  2298. PCM_KEY_CONTROL_BLOCK kcb,
  2299. PUNICODE_STRING NodeName
  2300. )
  2301. /*++
  2302. Routine Description:
  2303. This routine builds up further information in the cache when parse
  2304. fails. The additional information can be
  2305. 1. The key is has no subkey (CM_KCB_NO_SUBKEY).
  2306. 2. The key has a few subkeys, then build the index hint in the cache.
  2307. 3. If lookup failed even we have index hint cached, then create a fake key so
  2308. we do not fail again. This is very usful for lookup failure under keys like
  2309. \registry\machine\software\classes\clsid, which have 1500+ subkeys and lots of
  2310. them have the smae first four chars.
  2311. NOTE. Currently we are not seeing too many fake keys being created.
  2312. We need to monitor this periodly and work out a way to work around if
  2313. we do create too many fake keys.
  2314. One solution is to use hash value for index hint (We can do it in the cache only
  2315. if we need to be backward comparible).
  2316. Arguments:
  2317. Hive - Supplies Hive that holds the key we are creating a KCB for.
  2318. Cell - Supplies Cell that contains the key we are creating a KCB for.
  2319. Node - Supplies pointer to key node.
  2320. KeyName - The KeyName.
  2321. Return Value:
  2322. The KCB that CmpParse need to dereference at the end.
  2323. If resources problem, it returns NULL, and the caller is responsible for cleanup
  2324. --*/
  2325. {
  2326. ULONG TotalSubKeyCounts;
  2327. BOOLEAN CreateFakeKcb = FALSE;
  2328. BOOLEAN HintCached;
  2329. PCM_KEY_CONTROL_BLOCK ParentKcb;
  2330. USHORT i,j;
  2331. HCELL_INDEX CellToRelease;
  2332. ULONG HashKey;
  2333. if (!UseFastIndex(Hive)) {
  2334. //
  2335. // Older version of hive, do not bother to cache hint.
  2336. //
  2337. return (kcb);
  2338. }
  2339. TotalSubKeyCounts = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  2340. if (TotalSubKeyCounts == 0) {
  2341. BEGIN_KCB_LOCK_GUARD;
  2342. CmpLockKCBTreeExclusive();
  2343. kcb->ExtFlags |= CM_KCB_NO_SUBKEY;
  2344. // clean up the invalid flag (if any)
  2345. kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
  2346. CmpUnlockKCBTree();
  2347. END_KCB_LOCK_GUARD;
  2348. } else if (TotalSubKeyCounts == 1) {
  2349. BEGIN_KCB_LOCK_GUARD;
  2350. CmpLockKCBTreeExclusive();
  2351. if (!(kcb->ExtFlags & CM_KCB_SUBKEY_ONE)) {
  2352. //
  2353. // Build the subkey hint to avoid unnecessary lookups in the index leaf
  2354. //
  2355. PCM_KEY_INDEX Index;
  2356. HCELL_INDEX SubKeyCell = 0;
  2357. PCM_KEY_NODE SubKeyNode;
  2358. UNICODE_STRING TmpStr;
  2359. if (Node->SubKeyCounts[Stable] == 1) {
  2360. CellToRelease = Node->SubKeyLists[Stable];
  2361. Index = (PCM_KEY_INDEX)HvGetCell(Hive, CellToRelease);
  2362. } else {
  2363. CellToRelease = Node->SubKeyLists[Volatile];
  2364. Index = (PCM_KEY_INDEX)HvGetCell(Hive, CellToRelease);
  2365. }
  2366. if( Index == NULL ) {
  2367. //
  2368. // we couldn't map the bin containing this cell
  2369. // return NULL; The caller must handle this gracefully!
  2370. //
  2371. CmpUnlockKCBTree();
  2372. return NULL;
  2373. }
  2374. if( Index->Signature == CM_KEY_INDEX_ROOT ) {
  2375. //
  2376. // don't cache root indexes; they are too big
  2377. //
  2378. HvReleaseCell(Hive,CellToRelease);
  2379. CmpUnlockKCBTree();
  2380. return NULL;
  2381. }
  2382. HashKey = 0;
  2383. if ( Index->Signature == CM_KEY_HASH_LEAF ) {
  2384. PCM_KEY_FAST_INDEX FastIndex;
  2385. FastIndex = (PCM_KEY_FAST_INDEX)Index;
  2386. //
  2387. // we already have the hash key handy; preserve it for the kcb hint
  2388. //
  2389. HashKey = FastIndex->List[0].HashKey;
  2390. } else if(Index->Signature == CM_KEY_FAST_LEAF) {
  2391. PCM_KEY_FAST_INDEX FastIndex;
  2392. FastIndex = (PCM_KEY_FAST_INDEX)Index;
  2393. SubKeyCell = FastIndex->List[0].Cell;
  2394. } else {
  2395. SubKeyCell = Index->List[0];
  2396. }
  2397. //DbgPrint("CmpAddInfoAfterParseFailure [0]\n");
  2398. if( HashKey != 0 ) {
  2399. kcb->HashKey = HashKey;
  2400. kcb->ExtFlags |= CM_KCB_SUBKEY_ONE;
  2401. // clean up the invalid flag (if any)
  2402. kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
  2403. } else {
  2404. SubKeyNode = (PCM_KEY_NODE)HvGetCell(Hive,SubKeyCell);
  2405. if( SubKeyNode != NULL ) {
  2406. if (SubKeyNode->Flags & KEY_COMP_NAME) {
  2407. kcb->HashKey = CmpComputeHashKeyForCompressedName(SubKeyNode->Name,SubKeyNode->NameLength);
  2408. } else {
  2409. TmpStr.Buffer = SubKeyNode->Name;
  2410. TmpStr.Length = SubKeyNode->NameLength;
  2411. kcb->HashKey = CmpComputeHashKey(&TmpStr);
  2412. }
  2413. HvReleaseCell(Hive,SubKeyCell);
  2414. kcb->ExtFlags |= CM_KCB_SUBKEY_ONE;
  2415. // clean up the invalid flag (if any)
  2416. kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
  2417. } else {
  2418. //
  2419. // we couldn't map the bin containing this cell
  2420. // return NULL; The caller must handle this gracefully!
  2421. //
  2422. HvReleaseCell(Hive,CellToRelease);
  2423. CmpUnlockKCBTree();
  2424. return NULL;
  2425. }
  2426. }
  2427. HvReleaseCell(Hive,CellToRelease);
  2428. } else {
  2429. //
  2430. // The name hint does not prevent from this look up
  2431. // Create the fake Kcb.
  2432. //
  2433. CreateFakeKcb = TRUE;
  2434. }
  2435. CmpUnlockKCBTree();
  2436. END_KCB_LOCK_GUARD;
  2437. } else if (TotalSubKeyCounts < CM_MAX_CACHE_HINT_SIZE) {
  2438. BEGIN_KCB_LOCK_GUARD;
  2439. CmpLockKCBTreeExclusive();
  2440. if (!(kcb->ExtFlags & CM_KCB_SUBKEY_HINT)) {
  2441. //
  2442. // Build the index leaf info in the parent KCB
  2443. // How to sync the cache with the registry data is a problem to be resolved.
  2444. //
  2445. ULONG Size;
  2446. PCM_KEY_INDEX Index;
  2447. PCM_KEY_FAST_INDEX FastIndex;
  2448. HCELL_INDEX SubKeyCell = 0;
  2449. PCM_KEY_NODE SubKeyNode;
  2450. ULONG HintCrt;
  2451. UNICODE_STRING TmpStr;
  2452. Size = sizeof(ULONG) * (Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile] + 1);
  2453. kcb->IndexHint = ExAllocatePoolWithTag(PagedPool,
  2454. Size,
  2455. CM_CACHE_INDEX_TAG | PROTECTED_POOL);
  2456. HintCached = TRUE;
  2457. if (kcb->IndexHint) {
  2458. kcb->IndexHint->Count = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  2459. HintCrt = 0;
  2460. //DbgPrint("CmpAddInfoAfterParseFailure [1]\n");
  2461. for (i = 0; i < Hive->StorageTypeCount; i++) {
  2462. if(Node->SubKeyCounts[i]) {
  2463. CellToRelease = Node->SubKeyLists[i];
  2464. Index = (PCM_KEY_INDEX)HvGetCell(Hive, CellToRelease);
  2465. if( Index == NULL ) {
  2466. //
  2467. // we couldn't map the bin containing this cell
  2468. // return NULL; The caller must handle this gracefully!
  2469. //
  2470. CmpUnlockKCBTree();
  2471. return NULL;
  2472. }
  2473. if( Index->Signature == CM_KEY_INDEX_ROOT ) {
  2474. HvReleaseCell(Hive,CellToRelease);
  2475. HintCached = FALSE;
  2476. break;
  2477. } else {
  2478. for (j=0; j<Node->SubKeyCounts[i]; j++) {
  2479. HashKey = 0;
  2480. if ( Index->Signature == CM_KEY_HASH_LEAF ) {
  2481. FastIndex = (PCM_KEY_FAST_INDEX)Index;
  2482. //
  2483. // preserve the hash key for the kcb hint
  2484. //
  2485. HashKey = FastIndex->List[j].HashKey;
  2486. } else if( Index->Signature == CM_KEY_FAST_LEAF ) {
  2487. FastIndex = (PCM_KEY_FAST_INDEX)Index;
  2488. SubKeyCell = FastIndex->List[j].Cell;
  2489. } else {
  2490. SubKeyCell = Index->List[j];
  2491. }
  2492. if( HashKey != 0 ) {
  2493. kcb->IndexHint->HashKey[HintCrt] = HashKey;
  2494. } else {
  2495. SubKeyNode = (PCM_KEY_NODE)HvGetCell(Hive,SubKeyCell);
  2496. if( SubKeyNode == NULL ) {
  2497. //
  2498. // couldn't map view; bad luck; don't cache hint for this kcb
  2499. //
  2500. HintCached = FALSE;
  2501. break;
  2502. }
  2503. if (SubKeyNode->Flags & KEY_COMP_NAME) {
  2504. kcb->IndexHint->HashKey[HintCrt] = CmpComputeHashKeyForCompressedName(SubKeyNode->Name,SubKeyNode->NameLength);
  2505. } else {
  2506. TmpStr.Buffer = SubKeyNode->Name;
  2507. TmpStr.Length = SubKeyNode->NameLength;
  2508. kcb->IndexHint->HashKey[HintCrt] = CmpComputeHashKey(&TmpStr);
  2509. }
  2510. HvReleaseCell(Hive,SubKeyCell);
  2511. }
  2512. //
  2513. // advance to the new hint
  2514. //
  2515. HintCrt++;
  2516. }
  2517. }
  2518. HvReleaseCell(Hive,CellToRelease);
  2519. }
  2520. }
  2521. if (HintCached) {
  2522. kcb->ExtFlags |= CM_KCB_SUBKEY_HINT;
  2523. // clean up the invalid flag (if any)
  2524. kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
  2525. } else {
  2526. //
  2527. // Do not have a FAST_LEAF, free the allocation.
  2528. //
  2529. ExFreePoolWithTag(kcb->IndexHint, CM_CACHE_INDEX_TAG | PROTECTED_POOL);
  2530. }
  2531. }
  2532. } else {
  2533. //
  2534. // The name hint does not prevent from this look up
  2535. // Create the fake Kcb.
  2536. //
  2537. CreateFakeKcb = TRUE;
  2538. }
  2539. CmpUnlockKCBTree();
  2540. END_KCB_LOCK_GUARD;
  2541. } else {
  2542. CreateFakeKcb = TRUE;
  2543. }
  2544. ParentKcb = kcb;
  2545. if (CreateFakeKcb && (CmpCacheOnFlag & CM_CACHE_FAKE_KEY)) {
  2546. //
  2547. // It has more than a few children but not the one we are interested.
  2548. // Create a kcb for this non-existing key so we do not try to find it
  2549. // again. Use the cell and node from the parent.
  2550. //
  2551. // Before we create a new one. Dereference the current kcb.
  2552. //
  2553. // CmpCacheOnFlag is for us to turn it on/off easily.
  2554. //
  2555. kcb = CmpCreateKeyControlBlock(Hive,
  2556. Cell,
  2557. Node,
  2558. ParentKcb,
  2559. TRUE,
  2560. NodeName);
  2561. if (kcb) {
  2562. CmpDereferenceKeyControlBlock(ParentKcb);
  2563. ParentKcb = kcb;
  2564. }
  2565. }
  2566. return (ParentKcb);
  2567. }
  2568. #ifdef CM_DYN_SYM_LINK
  2569. //
  2570. // this code is commented out of the current builds;
  2571. // there is a potential security breach in the way RtlAcquirePebLock()
  2572. // works by calling a user mode routine (stored in the PEB) to lock the PEB
  2573. // We need to find a way to work around that before enabling this code
  2574. //
  2575. //
  2576. // Commenting the body of this function, to make sure code will not go in without
  2577. // fixing the above problem
  2578. //
  2579. BOOLEAN
  2580. CmpCaptureProcessEnvironmentString(
  2581. OUT PWSTR *ProcessEnvironment,
  2582. OUT PULONG Length
  2583. )
  2584. /*++
  2585. Routine Description:
  2586. Captures the process environment; It first Probe the env, then captures its
  2587. address. Parse the whole env to the end and count it's length.
  2588. Then allocate a buffer for it and copy.
  2589. All of these are done in try/except to protect for bogus user-mode data.
  2590. We need to lock the teb while working on it.
  2591. Arguments:
  2592. ProcessEnvironment - to receive the captured stuff
  2593. Length - length of the above - in bytes
  2594. Return Value:
  2595. TRUE or FALSE
  2596. when TRUE, the caller is responsible of freeing ProcessEnvironment
  2597. --*/
  2598. {
  2599. /*
  2600. BOOLEAN Result = TRUE;
  2601. PPEB Peb;
  2602. PWSTR LocalEnv;
  2603. PWSTR p;
  2604. PAGED_CODE();
  2605. *ProcessEnvironment = NULL;
  2606. *Length = 0;
  2607. try {
  2608. //
  2609. // grab the peb lock and the peb
  2610. //
  2611. RtlAcquirePebLock();
  2612. Peb = PsGetCurrentProcess()->Peb;
  2613. //
  2614. // probe the env from peb
  2615. //
  2616. LocalEnv = (PWSTR)ProbeAndReadPointer((PVOID *)(&(Peb->ProcessParameters->Environment)));
  2617. //
  2618. // parse the env to find its length
  2619. //
  2620. //
  2621. // The environment variable block consists of zero or more null
  2622. // terminated UNICODE strings. Each string is of the form:
  2623. //
  2624. // name=value
  2625. //
  2626. // where the null termination is after the value.
  2627. //
  2628. p = LocalEnv;
  2629. if (p != NULL) while (*p) {
  2630. while (*p) {
  2631. p++;
  2632. *Length += sizeof(WCHAR);
  2633. }
  2634. //
  2635. // Skip over the terminating null character for this name=value
  2636. // pair in preparation for the next iteration of the loop.
  2637. //
  2638. p++;
  2639. *Length += sizeof(WCHAR);
  2640. }
  2641. //
  2642. // adjust the length to accomodate the last two UNICODE_NULL
  2643. //
  2644. *Length += 2*sizeof(WCHAR);
  2645. //
  2646. // allocate a buffer for the captured env and copy
  2647. //
  2648. *ProcessEnvironment = (PWSTR)ExAllocatePoolWithTag(PagedPool,*Length,CM_FIND_LEAK_TAG41);
  2649. if( *ProcessEnvironment != NULL ) {
  2650. RtlCopyMemory(*ProcessEnvironment,LocalEnv, *Length);
  2651. } else {
  2652. *Length = 0;
  2653. }
  2654. //
  2655. // release the peb lock
  2656. //
  2657. RtlReleasePebLock();
  2658. } except (EXCEPTION_EXECUTE_HANDLER) {
  2659. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"!!CmpCaptureProcessEnvironmentString: code:%08lx\n", GetExceptionCode()));
  2660. Result = FALSE;
  2661. if( *ProcessEnvironment != NULL) {
  2662. ExFreePool(*ProcessEnvironment);
  2663. *ProcessEnvironment = NULL;
  2664. }
  2665. *Length = 0;
  2666. //
  2667. // release the peb lock
  2668. //
  2669. RtlReleasePebLock();
  2670. }
  2671. return Result;
  2672. */
  2673. }
  2674. #define GROW_INCREMENT 64*sizeof(WCHAR) // grow 64 wide-chars at a time
  2675. PWSTR
  2676. CmpExpandEnvVars(
  2677. IN PWSTR StringToExpand,
  2678. IN ULONG LengthToExpand,
  2679. OUT PULONG ExpandedLength
  2680. )
  2681. /*++
  2682. Routine Description:
  2683. Replaces all env vars from StringToExpand with their values, from the process
  2684. environment. Allocates a new buffer for the result and returns it.
  2685. Arguments:
  2686. StringToExpand - to receive the captured stuff
  2687. LengthToExpand - length of the above - in bytes
  2688. ExpandedLength - the actual length of the expanded string
  2689. Return Value:
  2690. NULL - the string could not be expanded (or not all the env inside it could be resolved)
  2691. valid buffer - the expanded string, it is the caller's responsibility to free it.
  2692. --*/
  2693. {
  2694. PWSTR ProcessEnv;
  2695. ULONG ProcessEnvLength;
  2696. PWSTR ExpandedString;
  2697. ULONG ExpandedStringSize;
  2698. PWSTR CurrentEnvVar;
  2699. ULONG CurrentEnvLength;
  2700. PWSTR CurrentEnvValue;
  2701. ULONG CurrentEnvValueLength;
  2702. PAGED_CODE();
  2703. *ExpandedLength = 0;
  2704. if( !CmpCaptureProcessEnvironmentString(&ProcessEnv,&ProcessEnvLength) ) {
  2705. //
  2706. // could not secure the process env
  2707. //
  2708. ASSERT( (ProcessEnv == NULL) && (ProcessEnvLength == 0) );
  2709. return NULL;
  2710. }
  2711. //
  2712. // allocate a buffer twice as the unexpanded buffer; we shall grow it if it's not big enough
  2713. //
  2714. ExpandedStringSize = LengthToExpand * 2;
  2715. ExpandedString = (PWSTR)ExAllocatePoolWithTag(PagedPool,ExpandedStringSize,CM_FIND_LEAK_TAG42);
  2716. if( ExpandedString == NULL ) {
  2717. goto JustReturn;
  2718. }
  2719. //
  2720. // convert to number of WCHARs
  2721. //
  2722. LengthToExpand /= sizeof(WCHAR);
  2723. //
  2724. // iterate through the string to be expanded and copy everything that's not and env var
  2725. // expand the env vars and replace them with their value
  2726. //
  2727. while( LengthToExpand ) {
  2728. //
  2729. // find a % sign
  2730. //
  2731. while( LengthToExpand && (*StringToExpand != L'%') ) {
  2732. if( *ExpandedLength == ExpandedStringSize ) {
  2733. //
  2734. // we need to grow the expanded string
  2735. //
  2736. if( !CmpGrowAndCopyString(&ExpandedString,&ExpandedStringSize,GROW_INCREMENT) ) {
  2737. goto ErrorExit;
  2738. }
  2739. }
  2740. ExpandedString[(*ExpandedLength) / sizeof(WCHAR)] = *StringToExpand;
  2741. (*ExpandedLength) += sizeof(WCHAR);
  2742. LengthToExpand--;
  2743. StringToExpand++;
  2744. }
  2745. if( LengthToExpand == 0 ) {
  2746. if( *StringToExpand != L'%') {
  2747. //
  2748. // we have exited the loop because of the end of the string
  2749. //
  2750. goto JustReturn;
  2751. } else {
  2752. //
  2753. // we have found a mismatched %
  2754. //
  2755. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpExpandEnvVars : mismatched % sign\n"));
  2756. goto ErrorExit;
  2757. }
  2758. }
  2759. ASSERT( *StringToExpand == L'%' );
  2760. //
  2761. // skip it; then mark the beggining of an env var
  2762. //
  2763. StringToExpand++;
  2764. LengthToExpand--;
  2765. CurrentEnvVar = StringToExpand;
  2766. CurrentEnvLength = 0;
  2767. //
  2768. // find a % match sign
  2769. //
  2770. while( LengthToExpand && (*StringToExpand != L'%') ) {
  2771. LengthToExpand--;
  2772. StringToExpand++;
  2773. CurrentEnvLength += sizeof(WCHAR);
  2774. }
  2775. if( LengthToExpand == 0 ) {
  2776. if( (*StringToExpand == L'%') && (CurrentEnvLength != 0) ) {
  2777. //
  2778. // end of string and no empty env var; we'll return (exit the surrounding
  2779. // while loop) after expanding this string
  2780. //
  2781. } else {
  2782. //
  2783. // we didn't find a matching % sign, or we are in the %% case
  2784. //
  2785. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpExpandEnvVars : mismatched % sign\n"));
  2786. goto ErrorExit;
  2787. }
  2788. } else {
  2789. //
  2790. // skip this % sign
  2791. //
  2792. StringToExpand++;
  2793. LengthToExpand--;
  2794. }
  2795. //
  2796. // find the value for this env var
  2797. //
  2798. if( !CmpFindEnvVar(ProcessEnv,ProcessEnvLength,CurrentEnvVar,CurrentEnvLength,&CurrentEnvValue,&CurrentEnvValueLength) ) {
  2799. //
  2800. // could not resolve this env var
  2801. //
  2802. ASSERT( CurrentEnvValue == NULL );
  2803. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpExpandEnvVars : could not resolve (%.*S)\n",CurrentEnvLength/sizeof(WCHAR),CurrentEnvVar));
  2804. goto ErrorExit;
  2805. }
  2806. ASSERT( (CurrentEnvValueLength % sizeof(WCHAR)) == 0 );
  2807. //
  2808. // found it; strcat it at the end of the expanded string
  2809. //
  2810. if( (*ExpandedLength + CurrentEnvValueLength) >= ExpandedStringSize ) {
  2811. //
  2812. // we first need to grow the buffer
  2813. //
  2814. if( !CmpGrowAndCopyString(&ExpandedString,&ExpandedStringSize,CurrentEnvValueLength) ) {
  2815. goto ErrorExit;
  2816. }
  2817. }
  2818. ASSERT( (*ExpandedLength + CurrentEnvValueLength) < ExpandedStringSize );
  2819. RtlCopyMemory(((PUCHAR)ExpandedString) + (*ExpandedLength),CurrentEnvValue,CurrentEnvValueLength);
  2820. *ExpandedLength += CurrentEnvValueLength;
  2821. }
  2822. goto JustReturn;
  2823. ErrorExit:
  2824. if( ExpandedString != NULL ) {
  2825. ExFreePool(ExpandedString);
  2826. ExpandedString = NULL;
  2827. }
  2828. JustReturn:
  2829. ExFreePool(ProcessEnv);
  2830. return ExpandedString;
  2831. }
  2832. BOOLEAN
  2833. CmpGrowAndCopyString(
  2834. IN OUT PWSTR *OldString,
  2835. IN OUT PULONG OldStringSize,
  2836. IN ULONG GrowIncrements
  2837. )
  2838. {
  2839. PWSTR NewString;
  2840. PAGED_CODE();
  2841. ASSERT( (*OldStringSize % sizeof(WCHAR)) == 0 );
  2842. ASSERT( (GrowIncrements % sizeof(WCHAR)) == 0 );
  2843. NewString = (PWSTR)ExAllocatePoolWithTag(PagedPool,*OldStringSize + GrowIncrements,CM_FIND_LEAK_TAG42);
  2844. if( NewString == NULL ) {
  2845. return FALSE;
  2846. }
  2847. RtlCopyMemory(NewString,*OldString,*OldStringSize);
  2848. ExFreePool(*OldString);
  2849. *OldString = NewString;
  2850. *OldStringSize = *OldStringSize + GrowIncrements;
  2851. return TRUE;
  2852. }
  2853. BOOLEAN
  2854. CmpFindEnvVar(
  2855. IN PWSTR ProcessEnv,
  2856. IN ULONG ProcessEnvLength,
  2857. IN PWSTR CurrentEnvVar,
  2858. IN ULONG CurrentEnvLength,
  2859. OUT PWSTR *CurrentEnvValue,
  2860. OUT PULONG CurrentEnvValueLength
  2861. )
  2862. /*++
  2863. Routine Description:
  2864. finds a specified envvar in the env string;
  2865. if found returns a pointer to it in the env string, along
  2866. with its size
  2867. Arguments:
  2868. ProcessEnvironment - to receive the captured stuff
  2869. Length - length of the above - in bytes
  2870. Return Value:
  2871. TRUE or FALSE
  2872. when TRUE, the caller is responsible of freeing ProcessEnvironment
  2873. --*/
  2874. {
  2875. PWSTR p;
  2876. UNICODE_STRING CurrentName;
  2877. UNICODE_STRING CurrentValue;
  2878. UNICODE_STRING SearchedName;
  2879. PAGED_CODE();
  2880. *CurrentEnvValue = NULL;
  2881. if( ProcessEnv == NULL ) {
  2882. return FALSE;
  2883. }
  2884. p = ProcessEnv;
  2885. SearchedName.Buffer = CurrentEnvVar;
  2886. SearchedName.Length = (USHORT)CurrentEnvLength;
  2887. SearchedName.MaximumLength = (USHORT)CurrentEnvLength;
  2888. //
  2889. // The environment variable block consists of zero or more null
  2890. // terminated UNICODE strings. Each string is of the form:
  2891. //
  2892. // name=value
  2893. //
  2894. // where the null termination is after the value.
  2895. //
  2896. while (ProcessEnvLength) {
  2897. //
  2898. // Determine the size of the name and value portions of
  2899. // the current string of the environment variable block.
  2900. //
  2901. CurrentName.Buffer = p;
  2902. CurrentName.Length = 0;
  2903. CurrentName.MaximumLength = 0;
  2904. while (*p) {
  2905. //
  2906. // If we see an equal sign, then compute the size of
  2907. // the name portion and scan for the end of the value.
  2908. //
  2909. if (*p == L'=' && p != CurrentName.Buffer) {
  2910. CurrentName.Length = (USHORT)(p - CurrentName.Buffer)*sizeof(WCHAR);
  2911. CurrentName.MaximumLength = (USHORT)(CurrentName.Length+sizeof(WCHAR));
  2912. CurrentValue.Buffer = ++p;
  2913. ProcessEnvLength -= sizeof(WCHAR);
  2914. while(*p) {
  2915. p++;
  2916. ProcessEnvLength -= sizeof(WCHAR);
  2917. }
  2918. CurrentValue.Length = (USHORT)(p - CurrentValue.Buffer)*sizeof(WCHAR);
  2919. CurrentValue.MaximumLength = (USHORT)(CurrentValue.Length+sizeof(WCHAR));
  2920. //
  2921. // At this point we have the length of both the name
  2922. // and value portions, so exit the loop so we can
  2923. // do the compare.
  2924. //
  2925. break;
  2926. }
  2927. else {
  2928. ProcessEnvLength -= sizeof(WCHAR);
  2929. p++;
  2930. }
  2931. }
  2932. //
  2933. // Skip over the terminating null character for this name=value
  2934. // pair in preparation for the next iteration of the loop.
  2935. //
  2936. p++;
  2937. ProcessEnvLength -= sizeof(WCHAR);
  2938. //
  2939. // Compare the current name with the one requested, ignore
  2940. // case.
  2941. //
  2942. if (RtlEqualUnicodeString( &SearchedName, &CurrentName, TRUE )) {
  2943. //
  2944. // Names are equal. Always return the length of the
  2945. // value string, excluding the terminating null.
  2946. //
  2947. *CurrentEnvValue = CurrentValue.Buffer;
  2948. *CurrentEnvValueLength = CurrentValue.Length;
  2949. return TRUE;
  2950. }
  2951. }
  2952. return FALSE;
  2953. }
  2954. #endif //CM_DYN_SYM_LINK
  2955. BOOLEAN
  2956. CmpOKToFollowLink( IN PCMHIVE OrigHive,
  2957. IN PCMHIVE DestHive
  2958. )
  2959. /*++
  2960. Routine Description:
  2961. 1. You can follow links from TRUSTED to anywhere.
  2962. 2. You cannot follow links from UNTRUSTED to TRUSTED.
  2963. 3. Inside the UNTRUSTED name space, you can only follow links inside the same class of trust.
  2964. OBS: OrigHive is just an address. It should not be dereferenced, as it may not be valid anymore (ie.
  2965. hive could have been unloaded in between). We don't really care as if it was, it will not be
  2966. in the trust list for the SourceKcb's hive
  2967. If OrigHive == NULL it means we have originated in a trusted hive.
  2968. Arguments:
  2969. Return Value:
  2970. TRUE or FALSE
  2971. --*/
  2972. {
  2973. PCMHIVE TmpHive;
  2974. PLIST_ENTRY AnchorAddr;
  2975. PAGED_CODE();
  2976. if( OrigHive == NULL ) {
  2977. //
  2978. // OK to follow links from trusted to anywhere
  2979. //
  2980. return TRUE;
  2981. }
  2982. if( OrigHive == DestHive ) {
  2983. //
  2984. // OK to follow links inside the same hive
  2985. //
  2986. return TRUE;
  2987. }
  2988. if( !(DestHive->Flags & CM_CMHIVE_FLAG_UNTRUSTED) ) {
  2989. //
  2990. // fail to follow from untrusted to trusted
  2991. //
  2992. //return FALSE;
  2993. goto Fail;
  2994. }
  2995. //
  2996. // both untrusted; see if they are in the same class of trust
  2997. //
  2998. ASSERT( DestHive->Flags & CM_CMHIVE_FLAG_UNTRUSTED );
  2999. LOCK_HIVE_LIST();
  3000. //
  3001. // walk the TrustClassEntry list of SrcHive, to see if we can find DstSrc
  3002. //
  3003. AnchorAddr = &(DestHive->TrustClassEntry);
  3004. TmpHive = (PCMHIVE)(DestHive->TrustClassEntry.Flink);
  3005. while ( TmpHive != (PCMHIVE)AnchorAddr ) {
  3006. TmpHive = CONTAINING_RECORD(
  3007. TmpHive,
  3008. CMHIVE,
  3009. TrustClassEntry
  3010. );
  3011. if( TmpHive == OrigHive ) {
  3012. //
  3013. // found it ==> same class of trust
  3014. //
  3015. UNLOCK_HIVE_LIST();
  3016. return TRUE;
  3017. }
  3018. //
  3019. // skip to the next element
  3020. //
  3021. TmpHive = (PCMHIVE)(TmpHive->TrustClassEntry.Flink);
  3022. }
  3023. UNLOCK_HIVE_LIST();
  3024. Fail:
  3025. /*
  3026. {
  3027. UNICODE_STRING Source = {0}, Dest = {0};
  3028. CmpGetHiveName(OrigHive,&Source);
  3029. CmpGetHiveName(DestHive,&Dest);
  3030. DbgPrint("\nAttempt to cross trust boundary:\n");
  3031. DbgPrint("\t FROM: %wZ \n",&Source);
  3032. DbgPrint("\t TO: %wZ \n",&Dest);
  3033. DbgPrint("This call will fail after we get the DCR ready\n");
  3034. RtlFreeUnicodeString(&Source);
  3035. RtlFreeUnicodeString(&Dest);
  3036. DbgBreakPoint();
  3037. }
  3038. */
  3039. //
  3040. // returning TRUE here will disable the 'don't follow links outside class of trust' behavior
  3041. //
  3042. return FALSE;
  3043. }
  3044. #ifdef ALLOC_DATA_PRAGMA
  3045. #pragma const_seg()
  3046. #endif