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.

5073 lines
143 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. cmsysini.c
  5. Abstract:
  6. This module contains init support for the configuration manager,
  7. particularly the registry.
  8. Author:
  9. Bryan M. Willman (bryanwi) 26-Aug-1991
  10. Revision History:
  11. Elliot Shmukler (t-ellios) 24-Aug-1998
  12. Added CmpSaveBootControlSet & CmpDeleteCloneTree in order to
  13. perform some of the LKG work that has been moved into the kernel.
  14. Modified system initialization to permit operation and LKG control
  15. set saves without a CurrentControlSet clone.
  16. --*/
  17. #include "cmp.h"
  18. #include "arc.h"
  19. #pragma hdrstop
  20. #include "arccodes.h"
  21. #pragma warning(disable:4204) // non constant aggregate initializer
  22. #pragma warning(disable:4221) // initialization using address of automatic
  23. typedef struct _VERSION_DATA_KEY
  24. {
  25. PWCHAR InitialKeyPath;
  26. PWCHAR AdditionalKeyPath;
  27. } VERSION_DATA_KEY, *PVERSION_DATA_KEY;
  28. VERSION_DATA_KEY VersionDataKeys[] =
  29. {
  30. { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft", NULL },
  31. #if defined(_WIN64)
  32. { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node", L"Microsoft" },
  33. #endif
  34. { NULL, NULL }
  35. } ;
  36. //
  37. // paths
  38. //
  39. #define INIT_REGISTRY_MASTERPATH L"\\REGISTRY\\"
  40. extern PKPROCESS CmpSystemProcess;
  41. extern ERESOURCE CmpRegistryLock;
  42. extern EX_PUSH_LOCK CmpKcbLock;
  43. extern PKTHREAD CmpKcbOwner;
  44. extern EX_PUSH_LOCK CmpKcbLocks[MAX_KCB_LOCKS];
  45. extern FAST_MUTEX CmpPostLock;
  46. extern FAST_MUTEX CmpWriteLock;
  47. extern BOOLEAN CmFirstTime;
  48. extern BOOLEAN HvShutdownComplete;
  49. //
  50. // List of MACHINE hives to load.
  51. //
  52. extern HIVE_LIST_ENTRY CmpMachineHiveList[];
  53. extern UCHAR SystemHiveFullPathBuffer[];
  54. extern UNICODE_STRING SystemHiveFullPathName;
  55. #define SYSTEM_PATH L"\\registry\\machine\\system"
  56. //
  57. // special keys for backwards compatibility with 1.0
  58. //
  59. #define HKEY_PERFORMANCE_TEXT (( HANDLE ) (ULONG_PTR)((LONG)0x80000050) )
  60. #define HKEY_PERFORMANCE_NLSTEXT (( HANDLE ) (ULONG_PTR)((LONG)0x80000060) )
  61. extern UNICODE_STRING CmpSystemFileName;
  62. extern UNICODE_STRING CmSymbolicLinkValueName;
  63. extern UNICODE_STRING CmpLoadOptions; // sys options from FW or boot.ini
  64. extern PWCHAR CmpProcessorControl;
  65. extern PWCHAR CmpControlSessionManager;
  66. //
  67. //
  68. // Object type definition support.
  69. //
  70. // Key objects (CmpKeyObjectType) represent open instances of keys in the
  71. // registry. They do not have object names, rather, their names are
  72. // defined by the registry backing store.
  73. //
  74. //
  75. // Master Hive
  76. //
  77. // The KEY_NODEs for \REGISTRY, \REGISTRY\MACHINE, and \REGISTRY\USER
  78. // are stored in a small memory only hive called the Master Hive.
  79. // All other hives have link nodes in this hive which point to them.
  80. //
  81. extern PCMHIVE CmpMasterHive;
  82. extern BOOLEAN CmpNoMasterCreates; // Init False, Set TRUE after we're done to
  83. // prevent random creates in the
  84. // master hive, which is not backed
  85. // by a file.
  86. extern LIST_ENTRY CmpHiveListHead; // List of CMHIVEs
  87. //
  88. // Addresses of object type descriptors:
  89. //
  90. extern POBJECT_TYPE CmpKeyObjectType;
  91. //
  92. // Define attributes that Key objects are not allowed to have.
  93. //
  94. #define CMP_KEY_INVALID_ATTRIBUTES (OBJ_EXCLUSIVE |\
  95. OBJ_PERMANENT)
  96. //
  97. // Global control values
  98. //
  99. //
  100. // Write-Control:
  101. // CmpNoWrite is initially true. When set this way write and flush
  102. // do nothing, simply returning success. When cleared to FALSE, I/O
  103. // is enabled. This change is made after the I/O system is started
  104. // AND autocheck (chkdsk) has done its thing.
  105. //
  106. extern BOOLEAN CmpNoWrite;
  107. //
  108. // Buffer used for quick-stash transfers in CmSetValueKey
  109. //
  110. extern PUCHAR CmpStashBuffer;
  111. extern ULONG CmpStashBufferSize;
  112. //
  113. // set to true if disk full when trying to save the changes made between system hive loading and registry initalization
  114. //
  115. extern BOOLEAN CmpCannotWriteConfiguration;
  116. //
  117. // Global "constants"
  118. //
  119. extern const UNICODE_STRING nullclass;
  120. extern BOOLEAN CmpTrackHiveClose;
  121. extern LIST_ENTRY CmpSelfHealQueueListHead;
  122. extern FAST_MUTEX CmpSelfHealQueueLock;
  123. //
  124. // Private prototypes
  125. //
  126. VOID
  127. CmpCreatePredefined(
  128. IN HANDLE Root,
  129. IN PWSTR KeyName,
  130. IN HANDLE PredefinedHandle
  131. );
  132. VOID
  133. CmpCreatePerfKeys(
  134. VOID
  135. );
  136. BOOLEAN
  137. CmpLinkKeyToHive(
  138. PWSTR KeyPath,
  139. PWSTR HivePath
  140. );
  141. NTSTATUS
  142. CmpCreateControlSet(
  143. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  144. );
  145. NTSTATUS
  146. CmpCloneControlSet(
  147. VOID
  148. );
  149. NTSTATUS
  150. CmpCreateObjectTypes(
  151. VOID
  152. );
  153. BOOLEAN
  154. CmpCreateRegistryRoot(
  155. VOID
  156. );
  157. BOOLEAN
  158. CmpCreateRootNode(
  159. IN PHHIVE Hive,
  160. IN PWSTR Name,
  161. OUT PHCELL_INDEX RootCellIndex
  162. );
  163. VOID
  164. CmpFreeDriverList(
  165. IN PHHIVE Hive,
  166. IN PLIST_ENTRY DriverList
  167. );
  168. VOID
  169. CmpInitializeHiveList(
  170. VOID
  171. );
  172. BOOLEAN
  173. CmpInitializeSystemHive(
  174. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  175. );
  176. NTSTATUS
  177. CmpInterlockedFunction (
  178. PWCHAR RegistryValueKey,
  179. VOID (*InterlockedFunction)(VOID)
  180. );
  181. VOID
  182. CmpConfigureProcessors (
  183. VOID
  184. );
  185. #if i386
  186. VOID
  187. KeOptimizeProcessorControlState (
  188. VOID
  189. );
  190. #endif
  191. NTSTATUS
  192. CmpAddDockingInfo (
  193. IN HANDLE Key,
  194. IN PROFILE_PARAMETER_BLOCK * ProfileBlock
  195. );
  196. NTSTATUS
  197. CmpAddAliasEntry (
  198. IN HANDLE IDConfigDB,
  199. IN PROFILE_PARAMETER_BLOCK * ProfileBlock,
  200. IN ULONG ProfileNumber
  201. );
  202. NTSTATUS CmpDeleteCloneTree(VOID);
  203. VOID
  204. CmpDiskFullWarning(
  205. VOID
  206. );
  207. VOID
  208. CmpLoadHiveThread(
  209. IN PVOID StartContext
  210. );
  211. NTSTATUS
  212. CmpSetupPrivateWrite(
  213. PCMHIVE CmHive
  214. );
  215. NTSTATUS
  216. CmpSetSystemValues(
  217. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  218. );
  219. NTSTATUS
  220. CmpSetNetworkValue(
  221. IN PNETWORK_LOADER_BLOCK NetworkLoaderBlock
  222. );
  223. VOID
  224. CmpInitCallback(VOID);
  225. VOID
  226. CmpMarkCurrentValueDirty(
  227. IN PHHIVE SystemHive,
  228. IN HCELL_INDEX RootCell
  229. );
  230. #ifdef ALLOC_PRAGMA
  231. NTSTATUS
  232. CmpHwprofileDefaultSelect (
  233. IN PCM_HARDWARE_PROFILE_LIST ProfileList,
  234. OUT PULONG ProfileIndexToUse,
  235. IN PVOID Context
  236. );
  237. #pragma alloc_text(INIT,CmInitSystem1)
  238. #pragma alloc_text(INIT,CmIsLastKnownGoodBoot)
  239. #pragma alloc_text(INIT,CmpHwprofileDefaultSelect)
  240. #pragma alloc_text(INIT,CmpCreateControlSet)
  241. #pragma alloc_text(INIT,CmpCloneControlSet)
  242. #pragma alloc_text(INIT,CmpCreateObjectTypes)
  243. #pragma alloc_text(INIT,CmpCreateRegistryRoot)
  244. #pragma alloc_text(INIT,CmpCreateRootNode)
  245. #pragma alloc_text(INIT,CmpInitializeSystemHive)
  246. #pragma alloc_text(INIT,CmGetSystemDriverList)
  247. #pragma alloc_text(INIT,CmpFreeDriverList)
  248. #pragma alloc_text(INIT,CmpSetSystemValues)
  249. #pragma alloc_text(INIT,CmpSetNetworkValue)
  250. #pragma alloc_text(PAGE,CmpInitializeHiveList)
  251. #pragma alloc_text(PAGE,CmpLinkHiveToMaster)
  252. #pragma alloc_text(PAGE,CmpSetVersionData)
  253. #pragma alloc_text(PAGE,CmBootLastKnownGood)
  254. #pragma alloc_text(PAGE,CmpSaveBootControlSet)
  255. #pragma alloc_text(PAGE,CmpInitHiveFromFile)
  256. #pragma alloc_text(PAGE,CmpLinkKeyToHive)
  257. #pragma alloc_text(PAGE,CmpCreatePredefined)
  258. #pragma alloc_text(PAGE,CmpCreatePerfKeys)
  259. #pragma alloc_text(PAGE,CmpInterlockedFunction)
  260. #pragma alloc_text(PAGE,CmpConfigureProcessors)
  261. #pragma alloc_text(INIT,CmpAddDockingInfo)
  262. #pragma alloc_text(INIT,CmpAddAliasEntry)
  263. #pragma alloc_text(PAGE,CmpDeleteCloneTree)
  264. #pragma alloc_text(PAGE,CmpSetupPrivateWrite)
  265. #pragma alloc_text(PAGE,CmpLoadHiveThread)
  266. #pragma alloc_text(PAGE,CmpMarkCurrentValueDirty)
  267. #endif
  268. BOOLEAN
  269. CmInitSystem1(
  270. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  271. )
  272. /*++
  273. Routine Description:
  274. This function is called as part of phase1 init, after the object
  275. manager has been inited, but before IoInit. It's purpose is to
  276. set up basic registry object operations, and transform data
  277. captured during boot into registry format (whether it was read
  278. from the SYSTEM hive file by the osloader or computed by recognizers.)
  279. After this call, Nt*Key calls work, but only part of the name
  280. space is available and any changes written must be held in
  281. memory.
  282. CmpMachineHiveList entries marked CM_PHASE_1 are available
  283. after return from this call, but writes must be held in memory.
  284. This function will:
  285. 1. Create the regisrty worker/lazy-write thread
  286. 2. Create the registry key object type
  287. 4. Create the master hive
  288. 5. Create the \REGISTRY node
  289. 6. Create a KEY object that refers to \REGISTRY
  290. 7. Create \REGISTRY\MACHINE node
  291. 8. Create the SYSTEM hive, fill in with data from loader
  292. 9. Create the HARDWARE hive, fill in with data from loader
  293. 10. Create:
  294. \REGISTRY\MACHINE\SYSTEM
  295. \REGISTRY\MACHINE\HARDWARE
  296. Both of which will be link nodes in the master hive.
  297. NOTE: We do NOT free allocated pool in failure case. This is because
  298. our caller is going to bugcheck anyway, and having the memory
  299. object to look at is useful.
  300. Arguments:
  301. LoaderBlock - supplies the LoaderBlock passed in from the OSLoader.
  302. By looking through the memory descriptor list we can find the
  303. SYSTEM hive which the OSLoader has placed in memory for us.
  304. Return Value:
  305. TRUE if all operations were successful, false if any failed.
  306. Bugchecks when something went wrong (CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,.....)
  307. --*/
  308. {
  309. HANDLE key1;
  310. OBJECT_ATTRIBUTES ObjectAttributes;
  311. NTSTATUS status;
  312. PSECURITY_DESCRIPTOR SecurityDescriptor;
  313. PCMHIVE HardwareHive;
  314. //
  315. // Set the mini NT flag if we are booting into Mini NT
  316. // environment
  317. //
  318. if (InitIsWinPEMode) {
  319. CmpMiniNTBoot = InitIsWinPEMode;
  320. //
  321. // On Remote boot client share the system hives
  322. //
  323. // NOTE : We can't assume exclusive access to WinPE
  324. // remote boot clients. We don't flush anything to
  325. // system hives in WinPE. All the system hives are
  326. // loaded in memory in scratch mode
  327. //
  328. CmpShareSystemHives = TRUE;
  329. }
  330. PAGED_CODE();
  331. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"CmInitSystem1\n"));
  332. //
  333. // Initialize Names of all registry paths.
  334. // This simply initializes unicode strings so we don't have to bother
  335. // with it later. This can not fail.
  336. //
  337. CmpInitializeRegistryNames();
  338. //
  339. // Compute registry global quota
  340. //
  341. CmpComputeGlobalQuotaAllowed();
  342. //
  343. // Initialize the hive list head
  344. //
  345. InitializeListHead(&CmpHiveListHead);
  346. ExInitializeFastMutex(&CmpHiveListHeadLock);
  347. //
  348. // Initialize the global registry resource
  349. //
  350. ExInitializeResourceLite(&CmpRegistryLock);
  351. //
  352. // Initialize the KCB tree mutex
  353. //
  354. ExInitializePushLock(&CmpKcbLock);
  355. CmpKcbOwner = NULL;
  356. {
  357. int i;
  358. for (i = 0; i < MAX_KCB_LOCKS; i++) {
  359. ExInitializePushLock(&CmpKcbLocks[i]);
  360. }
  361. }
  362. //
  363. // Initialize the PostList mutex
  364. //
  365. ExInitializeFastMutex(&CmpPostLock);
  366. //
  367. // Initialize the Stash Buffer mutex
  368. //
  369. ExInitializeFastMutex(&CmpStashBufferLock);
  370. //
  371. // Initialize the Write mutex
  372. //
  373. ExInitializeFastMutex(&CmpWriteLock);
  374. //
  375. // Initialize the cache
  376. //
  377. CmpInitializeCache ();
  378. //
  379. // Initialize private allocator
  380. //
  381. CmpInitCmPrivateAlloc();
  382. //
  383. // Initialize callback module
  384. //
  385. CmpInitCallback();
  386. //
  387. // Self Heal workitem queue
  388. //
  389. InitializeListHead(&CmpSelfHealQueueListHead);
  390. ExInitializeFastMutex(&CmpSelfHealQueueLock);
  391. //
  392. // start tracking quota allocations
  393. //
  394. CM_TRACK_QUOTA_START();
  395. #ifdef CM_TRACK_QUOTA_LEAKS
  396. //
  397. // Initialize the Quota track mutex
  398. //
  399. ExInitializeFastMutex(&CmpQuotaLeaksMutex);
  400. #endif // CM_TRACK_QUOTA_LEAKS
  401. //
  402. // Save the current process to allow us to attach to it later.
  403. //
  404. CmpSystemProcess = &PsGetCurrentProcess()->Pcb;
  405. CmpLockRegistryExclusive();
  406. //
  407. // Create the Key object type.
  408. //
  409. status = CmpCreateObjectTypes();
  410. if (!NT_SUCCESS(status) ) {
  411. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmInitSystem1: CmpCreateObjectTypes failed\n"));
  412. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,1,status,0); // could not registrate with object manager
  413. #if defined(_CM_LDR_)
  414. return FALSE;
  415. #endif
  416. }
  417. //
  418. // Create the master hive and initialize it.
  419. //
  420. status = CmpInitializeHive(&CmpMasterHive,
  421. HINIT_CREATE,
  422. HIVE_VOLATILE,
  423. HFILE_TYPE_PRIMARY, // i.e. no logging, no alterate
  424. NULL,
  425. NULL,
  426. NULL,
  427. NULL,
  428. NULL,
  429. 0);
  430. if (!NT_SUCCESS(status)) {
  431. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmInitSystem1: CmpInitializeHive(master) failed\n"));
  432. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,2,status,0); // could not initialize master hive
  433. #if defined(_CM_LDR_)
  434. return (FALSE);
  435. #endif
  436. }
  437. //
  438. // try to allocate a stash buffer. if we can't get 1 page this
  439. // early on, we're in deep trouble, so punt.
  440. //
  441. CmpStashBuffer = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE,CM_STASHBUFFER_TAG);
  442. if (CmpStashBuffer == NULL) {
  443. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,3,0,0); // odds against this are huge
  444. #if defined(_CM_LDR_)
  445. return FALSE;
  446. #endif
  447. }
  448. CmpStashBufferSize = PAGE_SIZE;
  449. //
  450. // Create the \REGISTRY node
  451. //
  452. if (!CmpCreateRegistryRoot()) {
  453. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmInitSystem1: CmpCreateRegistryRoot failed\n"));
  454. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,4,0,0); // could not create root of the registry
  455. #if defined(_CM_LDR_)
  456. return FALSE;
  457. #endif
  458. }
  459. //
  460. // --- 6. Create \REGISTRY\MACHINE and \REGISTRY\USER nodes ---
  461. //
  462. //
  463. // Get default security descriptor for the nodes we will create.
  464. //
  465. SecurityDescriptor = CmpHiveRootSecurityDescriptor();
  466. InitializeObjectAttributes(
  467. &ObjectAttributes,
  468. &CmRegistryMachineName,
  469. OBJ_CASE_INSENSITIVE,
  470. (HANDLE)NULL,
  471. SecurityDescriptor
  472. );
  473. if (!NT_SUCCESS(status = NtCreateKey(
  474. &key1,
  475. KEY_READ | KEY_WRITE,
  476. &ObjectAttributes,
  477. 0,
  478. (PUNICODE_STRING)&nullclass,
  479. 0,
  480. NULL
  481. )))
  482. {
  483. ExFreePool(SecurityDescriptor);
  484. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmInitSystem1: NtCreateKey(MACHINE) failed\n"));
  485. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,5,status,0); // could not create HKLM
  486. #if defined(_CM_LDR_)
  487. return FALSE;
  488. #endif
  489. }
  490. NtClose(key1);
  491. InitializeObjectAttributes(
  492. &ObjectAttributes,
  493. &CmRegistryUserName,
  494. OBJ_CASE_INSENSITIVE,
  495. (HANDLE)NULL,
  496. SecurityDescriptor
  497. );
  498. if (!NT_SUCCESS(status = NtCreateKey(
  499. &key1,
  500. KEY_READ | KEY_WRITE,
  501. &ObjectAttributes,
  502. 0,
  503. (PUNICODE_STRING)&nullclass,
  504. 0,
  505. NULL
  506. )))
  507. {
  508. ExFreePool(SecurityDescriptor);
  509. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmInitSystem1: NtCreateKey(USER) failed\n"));
  510. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,6,status,0); // could not create HKUSER
  511. #if defined(_CM_LDR_)
  512. return FALSE;
  513. #endif
  514. }
  515. NtClose(key1);
  516. //
  517. // --- 7. Create the SYSTEM hive, fill in with data from loader ---
  518. //
  519. if (!CmpInitializeSystemHive(LoaderBlock)) {
  520. ExFreePool(SecurityDescriptor);
  521. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitSystem1: "));
  522. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"Hive allocation failure for SYSTEM\n"));
  523. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,7,0,0); // could not create SystemHive
  524. #if defined(_CM_LDR_)
  525. return(FALSE);
  526. #endif
  527. }
  528. //
  529. // Create the symbolic link \Registry\Machine\System\CurrentControlSet
  530. //
  531. status = CmpCreateControlSet(LoaderBlock);
  532. if (!NT_SUCCESS(status)) {
  533. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,8,status,0); // could not create CurrentControlSet
  534. #if defined(_CM_LDR_)
  535. return(FALSE);
  536. #endif
  537. }
  538. //
  539. // Handle the copying of the CurrentControlSet to a Clone volatile
  540. // hive (but only if we really want to have a clone)
  541. //
  542. #if CLONE_CONTROL_SET
  543. //
  544. // Create the Clone temporary hive, link it into the master hive,
  545. // and make a symbolic link to it.
  546. //
  547. status = CmpInitializeHive(&CloneHive,
  548. HINIT_CREATE,
  549. HIVE_VOLATILE,
  550. HFILE_TYPE_PRIMARY,
  551. NULL,
  552. NULL,
  553. NULL,
  554. NULL,
  555. NULL,
  556. 0);
  557. if (!NT_SUCCESS(status)) {
  558. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitSystem1: "));
  559. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"Could not initialize CLONE hive\n"));
  560. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,9,status,0); // could not initialize clone hive
  561. return(FALSE);
  562. }
  563. status = CmpLinkHiveToMaster(
  564. &CmRegistrySystemCloneName,
  565. NULL,
  566. CloneHive,
  567. TRUE,
  568. SecurityDescriptor
  569. );
  570. if ( status != STATUS_SUCCESS)
  571. {
  572. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmInitSystem1: CmpLinkHiveToMaster(Clone) failed\n"));
  573. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,10,status,0); // could not link clone hive to master hive
  574. return FALSE;
  575. }
  576. CmpAddToHiveFileList(CloneHive);
  577. CmpMachineHiveList[CLONE_HIVE_INDEX].CmHive = CloneHive;
  578. CmpLinkKeyToHive(
  579. L"\\Registry\\Machine\\System\\Clone",
  580. L"\\Registry\\Machine\\CLONE\\CLONE"
  581. );
  582. //
  583. // Clone the current control set for the service controller
  584. //
  585. status = CmpCloneControlSet();
  586. //
  587. // If this didn't work, it's bad, but not bad enough to fail the boot
  588. //
  589. ASSERT(NT_SUCCESS(status));
  590. #endif
  591. //
  592. // --- 8. Create the HARDWARE hive, fill in with data from loader ---
  593. //
  594. status = CmpInitializeHive(&HardwareHive,
  595. HINIT_CREATE,
  596. HIVE_VOLATILE,
  597. HFILE_TYPE_PRIMARY, // i.e. no log, no alternate
  598. NULL,
  599. NULL,
  600. NULL,
  601. NULL,
  602. NULL,
  603. 0);
  604. if (!NT_SUCCESS(status)) {
  605. ExFreePool(SecurityDescriptor);
  606. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitSystem1: "));
  607. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"Could not initialize HARDWARE hive\n"));
  608. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,11,status,0); // could not initialize hardware hive
  609. #if defined(_CM_LDR_)
  610. return FALSE;
  611. #endif
  612. }
  613. //
  614. // Allocate the root node
  615. //
  616. status = CmpLinkHiveToMaster(
  617. &CmRegistryMachineHardwareName,
  618. NULL,
  619. HardwareHive,
  620. TRUE,
  621. SecurityDescriptor
  622. );
  623. if ( status != STATUS_SUCCESS )
  624. {
  625. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmInitSystem1: CmpLinkHiveToMaster(Hardware) failed\n"));
  626. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,12,status,0); // could not link hardware hive to master hive
  627. #if defined(_CM_LDR_)
  628. return FALSE;
  629. #endif
  630. }
  631. CmpAddToHiveFileList(HardwareHive);
  632. ExFreePool(SecurityDescriptor);
  633. CmpMachineHiveList[0].CmHive = HardwareHive;
  634. //
  635. // put loader configuration tree data to our hardware registry.
  636. //
  637. status = CmpInitializeHardwareConfiguration(LoaderBlock);
  638. if (!NT_SUCCESS(status)) {
  639. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,13,status,0); // could not initialize hardware configuration
  640. #if defined(_CM_LDR_)
  641. return FALSE;
  642. #endif
  643. }
  644. CmpNoMasterCreates = TRUE;
  645. CmpUnlockRegistry();
  646. //
  647. // put machine dependant configuration data to our hardware registry.
  648. //
  649. status = CmpInitializeMachineDependentConfiguration(LoaderBlock);
  650. if (!NT_SUCCESS(status)) {
  651. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,14,status,0); // could not open CurrentControlSet\\Control
  652. #if defined(_CM_LDR_)
  653. return(FALSE);
  654. #endif
  655. }
  656. //
  657. // Write system start options to registry
  658. //
  659. status = CmpSetSystemValues(LoaderBlock);
  660. if (!NT_SUCCESS(status)) {
  661. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,15,status,0);
  662. #if defined(_CM_LDR_)
  663. return(FALSE);
  664. #endif
  665. }
  666. ExFreePool(CmpLoadOptions.Buffer);
  667. //
  668. // Write Network LoaderBlock values to registry
  669. //
  670. if ( (LoaderBlock->Extension->Size >=
  671. RTL_SIZEOF_THROUGH_FIELD(LOADER_PARAMETER_EXTENSION, NetworkLoaderBlock)) &&
  672. (LoaderBlock->Extension->NetworkLoaderBlock != NULL) ) {
  673. status = CmpSetNetworkValue(LoaderBlock->Extension->NetworkLoaderBlock);
  674. if (!NT_SUCCESS(status)) {
  675. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM1,16,status,0);
  676. #if defined(_CM_LDR_)
  677. return(FALSE);
  678. #endif
  679. }
  680. }
  681. return TRUE;
  682. }
  683. //
  684. // All paralel threads will get this shared, and CmpInitializeHiveList will wait for it exclusive
  685. //
  686. KEVENT CmpLoadWorkerEvent;
  687. LONG CmpLoadWorkerIncrement = 0;
  688. KEVENT CmpLoadWorkerDebugEvent;
  689. VOID
  690. CmpInitializeHiveList(
  691. VOID
  692. )
  693. /*++
  694. Routine Description:
  695. This function is called to map hive files to hives. It both
  696. maps existing hives to files, and creates new hives from files.
  697. It operates on files in "\SYSTEMROOT\CONFIG".
  698. NOTE: MUST run in the context of the process that the CmpWorker
  699. thread runs in. Caller is expected to arrange this.
  700. NOTE: Will bugcheck on failure.
  701. Arguments:
  702. Return Value:
  703. NONE.
  704. --*/
  705. {
  706. #define MAX_NAME 128
  707. HANDLE Thread;
  708. NTSTATUS Status;
  709. UCHAR FileBuffer[MAX_NAME];
  710. UCHAR RegBuffer[MAX_NAME];
  711. UNICODE_STRING TempName;
  712. UNICODE_STRING FileName;
  713. UNICODE_STRING RegName;
  714. USHORT FileStart;
  715. USHORT RegStart;
  716. ULONG i;
  717. PSECURITY_DESCRIPTOR SecurityDescriptor;
  718. #ifdef CM_PERF_ISSUES
  719. LARGE_INTEGER StartSystemTime;
  720. LARGE_INTEGER EndSystemTime;
  721. LARGE_INTEGER deltaTime;
  722. #endif //CM_PERF_ISSUES
  723. PAGED_CODE();
  724. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"CmpInitializeHiveList\n"));
  725. #ifdef CM_PERF_ISSUES
  726. KeQuerySystemTime(&StartSystemTime);
  727. #endif //CM_PERF_ISSUES
  728. CmpNoWrite = FALSE;
  729. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  730. FileName.MaximumLength = MAX_NAME;
  731. FileName.Length = 0;
  732. FileName.Buffer = (PWSTR)&(FileBuffer[0]);
  733. RegName.MaximumLength = MAX_NAME;
  734. RegName.Length = 0;
  735. RegName.Buffer = (PWSTR)&(RegBuffer[0]);
  736. RtlInitUnicodeString(
  737. &TempName,
  738. INIT_SYSTEMROOT_HIVEPATH
  739. );
  740. RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
  741. FileStart = FileName.Length;
  742. RtlInitUnicodeString(
  743. &TempName,
  744. INIT_REGISTRY_MASTERPATH
  745. );
  746. RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
  747. RegStart = RegName.Length;
  748. //
  749. // Initialize the syncronization event
  750. //
  751. KeInitializeEvent (&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);
  752. KeInitializeEvent (&CmpLoadWorkerDebugEvent, SynchronizationEvent, FALSE);
  753. CmpSpecialBootCondition = TRUE;
  754. SecurityDescriptor = CmpHiveRootSecurityDescriptor();
  755. if (CmpShareSystemHives) {
  756. for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) {
  757. if (CmpMachineHiveList[i].Name) {
  758. CmpMachineHiveList[i].HHiveFlags |= HIVE_VOLATILE;
  759. }
  760. }
  761. }
  762. for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) {
  763. ASSERT( CmpMachineHiveList[i].Name != NULL );
  764. //
  765. // just spawn the Threads to load the hives in paralel
  766. //
  767. Status = PsCreateSystemThread(
  768. &Thread,
  769. THREAD_ALL_ACCESS,
  770. NULL,
  771. 0,
  772. NULL,
  773. CmpLoadHiveThread,
  774. (PVOID)(ULONG_PTR)(ULONG)i
  775. );
  776. if (NT_SUCCESS(Status)) {
  777. ZwClose(Thread);
  778. } else {
  779. //
  780. // cannot spawn thread; Fatal error
  781. //
  782. CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_HIVE_LIST,3,i,Status);
  783. }
  784. }
  785. ASSERT( CmpMachineHiveList[i].Name == NULL );
  786. KeWaitForSingleObject( &CmpLoadWorkerEvent,
  787. Executive,
  788. KernelMode,
  789. FALSE,
  790. NULL );
  791. CmpSpecialBootCondition = FALSE;
  792. ASSERT( CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES );
  793. //
  794. // Now add all hives to the hivelist
  795. //
  796. for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) {
  797. ASSERT( CmpMachineHiveList[i].ThreadFinished == TRUE );
  798. ASSERT( CmpMachineHiveList[i].ThreadStarted == TRUE );
  799. if (CmpMachineHiveList[i].CmHive == NULL) {
  800. ASSERT( CmpMachineHiveList[i].CmHive2 != NULL );
  801. //
  802. // Compute the name of the file, and the name to link to in
  803. // the registry.
  804. //
  805. // REGISTRY
  806. RegName.Length = RegStart;
  807. RtlInitUnicodeString(
  808. &TempName,
  809. CmpMachineHiveList[i].BaseName
  810. );
  811. RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
  812. // REGISTRY\MACHINE or REGISTRY\USER
  813. if (RegName.Buffer[ (RegName.Length / sizeof( WCHAR )) - 1 ] == '\\') {
  814. RtlInitUnicodeString(
  815. &TempName,
  816. CmpMachineHiveList[i].Name
  817. );
  818. RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
  819. }
  820. // REGISTRY\[MACHINE|USER]\HIVE
  821. // <sysroot>\config
  822. //
  823. // Link hive into master hive
  824. //
  825. Status = CmpLinkHiveToMaster(
  826. &RegName,
  827. NULL,
  828. CmpMachineHiveList[i].CmHive2,
  829. CmpMachineHiveList[i].Allocate,
  830. SecurityDescriptor
  831. );
  832. if ( Status != STATUS_SUCCESS)
  833. {
  834. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitializeHiveList: "));
  835. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpLinkHiveToMaster failed\n"));
  836. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\ti=%d s='%ws'\n", i, CmpMachineHiveList[i]));
  837. CM_BUGCHECK(CONFIG_LIST_FAILED,BAD_CORE_HIVE,Status,i,&RegName);
  838. }
  839. if( CmpMachineHiveList[i].Allocate == TRUE ) {
  840. HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
  841. }
  842. } else {
  843. //
  844. // do nothing here as all of it has been done in separate thread.
  845. //
  846. }
  847. if( CmpMachineHiveList[i].CmHive2 != NULL ) {
  848. CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive2);
  849. }
  850. } // for
  851. ExFreePool(SecurityDescriptor);
  852. //
  853. // Create symbolic link from SECURITY hive into SAM hive.
  854. //
  855. CmpLinkKeyToHive(
  856. L"\\Registry\\Machine\\Security\\SAM",
  857. L"\\Registry\\Machine\\SAM\\SAM"
  858. );
  859. //
  860. // Create symbolic link from S-1-5-18 to .Default
  861. //
  862. CmpNoMasterCreates = FALSE;
  863. CmpLinkKeyToHive(
  864. L"\\Registry\\User\\S-1-5-18",
  865. L"\\Registry\\User\\.Default"
  866. );
  867. CmpNoMasterCreates = TRUE;
  868. //
  869. // Create predefined handles.
  870. //
  871. CmpCreatePerfKeys();
  872. //
  873. // from now on we will attempt to self heal hives
  874. //
  875. CmpSelfHeal = TRUE;
  876. #ifdef CM_PERF_ISSUES
  877. KeQuerySystemTime(&EndSystemTime);
  878. deltaTime.QuadPart = EndSystemTime.QuadPart - StartSystemTime.QuadPart;
  879. DbgPrint("\nCmpInitializeHiveList took %lu.%lu ms\n",(ULONG)(deltaTime.LowPart/10000),(ULONG)(deltaTime.LowPart%10000));
  880. if( deltaTime.HighPart != 0 ) {
  881. DbgPrint("deltaTime.HighPart = %lu\n",(ULONG)deltaTime.HighPart);
  882. }
  883. #endif //CM_PERF_ISSUES
  884. return;
  885. }
  886. NTSTATUS
  887. CmpCreateObjectTypes(
  888. VOID
  889. )
  890. /*++
  891. Routine Description:
  892. Create the Key object type
  893. Arguments:
  894. NONE.
  895. Return Value:
  896. Status of the ObCreateType call
  897. --*/
  898. {
  899. NTSTATUS Status;
  900. OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
  901. UNICODE_STRING TypeName;
  902. //
  903. // Structure that describes the mapping of generic access rights to object
  904. // specific access rights for registry key objects.
  905. //
  906. GENERIC_MAPPING CmpKeyMapping = {
  907. KEY_READ,
  908. KEY_WRITE,
  909. KEY_EXECUTE,
  910. KEY_ALL_ACCESS
  911. };
  912. PAGED_CODE();
  913. //
  914. // --- Create the registry key object type ---
  915. //
  916. //
  917. // Initialize string descriptor.
  918. //
  919. RtlInitUnicodeString(&TypeName, L"Key");
  920. //
  921. // Create key object type descriptor.
  922. //
  923. RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
  924. ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
  925. ObjectTypeInitializer.InvalidAttributes = CMP_KEY_INVALID_ATTRIBUTES;
  926. ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
  927. ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
  928. ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
  929. ObjectTypeInitializer.SecurityRequired = TRUE;
  930. ObjectTypeInitializer.PoolType = PagedPool;
  931. ObjectTypeInitializer.MaintainHandleCount = FALSE;
  932. ObjectTypeInitializer.UseDefaultObject = TRUE;
  933. ObjectTypeInitializer.DumpProcedure = NULL;
  934. ObjectTypeInitializer.OpenProcedure = NULL;
  935. ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
  936. ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
  937. ObjectTypeInitializer.ParseProcedure = CmpParseKey;
  938. ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
  939. ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
  940. Status = ObCreateObjectType(
  941. &TypeName,
  942. &ObjectTypeInitializer,
  943. (PSECURITY_DESCRIPTOR)NULL,
  944. &CmpKeyObjectType
  945. );
  946. if (!NT_SUCCESS(Status)) {
  947. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpCreateObjectTypes: "));
  948. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"ObCreateObjectType(Key) failed %08lx\n", Status));
  949. }
  950. return Status;
  951. }
  952. BOOLEAN
  953. CmpCreateRegistryRoot(
  954. VOID
  955. )
  956. /*++
  957. Routine Description:
  958. Manually create \REGISTRY in the master hive, create a key
  959. object to refer to it, and insert the key object into
  960. the root (\) of the object space.
  961. Arguments:
  962. None
  963. Return Value:
  964. TRUE == success, FALSE == failure
  965. --*/
  966. {
  967. NTSTATUS Status;
  968. PVOID ObjectPointer;
  969. PCM_KEY_BODY Object;
  970. OBJECT_ATTRIBUTES ObjectAttributes;
  971. PCM_KEY_CONTROL_BLOCK kcb;
  972. HCELL_INDEX RootCellIndex;
  973. PSECURITY_DESCRIPTOR SecurityDescriptor;
  974. PCM_KEY_NODE TempNode;
  975. PAGED_CODE();
  976. //
  977. // --- Create hive entry for \REGISTRY ---
  978. //
  979. if (!CmpCreateRootNode(
  980. &(CmpMasterHive->Hive), L"REGISTRY", &RootCellIndex))
  981. {
  982. return FALSE;
  983. }
  984. //
  985. // --- Create a KEY object that refers to \REGISTRY ---
  986. //
  987. //
  988. // Create the object manager object
  989. //
  990. //
  991. // WARNING: \\REGISTRY is not in pool, so if anybody ever tries to
  992. // free it, we are in deep trouble. On the other hand,
  993. // this implies somebody has removed \\REGISTRY from the
  994. // root, so we're in trouble anyway.
  995. //
  996. SecurityDescriptor = CmpHiveRootSecurityDescriptor();
  997. InitializeObjectAttributes(
  998. &ObjectAttributes,
  999. &CmRegistryRootName,
  1000. OBJ_CASE_INSENSITIVE,
  1001. (HANDLE)NULL,
  1002. SecurityDescriptor
  1003. );
  1004. Status = ObCreateObject(
  1005. KernelMode,
  1006. CmpKeyObjectType,
  1007. &ObjectAttributes,
  1008. UserMode,
  1009. NULL, // Parse context
  1010. sizeof(CM_KEY_BODY),
  1011. 0,
  1012. 0,
  1013. (PVOID *)&Object
  1014. );
  1015. ExFreePool(SecurityDescriptor);
  1016. if (!NT_SUCCESS(Status)) {
  1017. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpCreateRegistryRoot: "));
  1018. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"ObCreateObject(\\REGISTRY) failed %08lx\n", Status));
  1019. return FALSE;
  1020. }
  1021. ASSERT( (&CmpMasterHive->Hive)->ReleaseCellRoutine == NULL );
  1022. TempNode = (PCM_KEY_NODE)HvGetCell(&CmpMasterHive->Hive,RootCellIndex);
  1023. if( TempNode == NULL ) {
  1024. //
  1025. // we couldn't map the bin containing this cell
  1026. //
  1027. return FALSE;
  1028. }
  1029. //
  1030. // Create the key control block
  1031. //
  1032. kcb = CmpCreateKeyControlBlock(
  1033. &(CmpMasterHive->Hive),
  1034. RootCellIndex,
  1035. TempNode,
  1036. NULL,
  1037. FALSE,
  1038. &CmRegistryRootName
  1039. );
  1040. if (kcb==NULL) {
  1041. return(FALSE);
  1042. }
  1043. //
  1044. // Initialize the type specific body
  1045. //
  1046. Object->Type = KEY_BODY_TYPE;
  1047. Object->KeyControlBlock = kcb;
  1048. Object->NotifyBlock = NULL;
  1049. Object->ProcessID = PsGetCurrentProcessId();
  1050. ENLIST_KEYBODY_IN_KEYBODY_LIST(Object);
  1051. //
  1052. // Put the object in the root directory
  1053. //
  1054. Status = ObInsertObject(
  1055. Object,
  1056. NULL,
  1057. (ACCESS_MASK)0,
  1058. 0,
  1059. NULL,
  1060. &CmpRegistryRootHandle
  1061. );
  1062. if (!NT_SUCCESS(Status)) {
  1063. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpCreateRegistryRoot: "));
  1064. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"ObInsertObject(\\REGISTRY) failed %08lx\n", Status));
  1065. return FALSE;
  1066. }
  1067. //
  1068. // We cannot make the root permanent because registry objects in
  1069. // general are not allowed to be. (They're stable via virtue of being
  1070. // stored in the registry, not the object manager.) But we never
  1071. // ever want the root to go away. So reference it.
  1072. //
  1073. if (! NT_SUCCESS(Status = ObReferenceObjectByHandle(
  1074. CmpRegistryRootHandle,
  1075. KEY_READ,
  1076. NULL,
  1077. KernelMode,
  1078. &ObjectPointer,
  1079. NULL
  1080. )))
  1081. {
  1082. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpCreateRegistryRoot: "));
  1083. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"ObReferenceObjectByHandle failed %08lx\n", Status));
  1084. return FALSE;
  1085. }
  1086. return TRUE;
  1087. }
  1088. BOOLEAN
  1089. CmpCreateRootNode(
  1090. IN PHHIVE Hive,
  1091. IN PWSTR Name,
  1092. OUT PHCELL_INDEX RootCellIndex
  1093. )
  1094. /*++
  1095. Routine Description:
  1096. Manually create the root node of a hive.
  1097. Arguments:
  1098. Hive - pointer to a Hive (Hv level) control structure
  1099. Name - pointer to a unicode name string
  1100. RootCellIndex - supplies pointer to a variable to recieve
  1101. the cell index of the created node.
  1102. Return Value:
  1103. TRUE == success, FALSE == failure
  1104. --*/
  1105. {
  1106. UNICODE_STRING temp;
  1107. PCELL_DATA CellData;
  1108. CM_KEY_REFERENCE Key;
  1109. LARGE_INTEGER systemtime;
  1110. PAGED_CODE();
  1111. //
  1112. // Allocate the node.
  1113. //
  1114. RtlInitUnicodeString(&temp, Name);
  1115. *RootCellIndex = HvAllocateCell(
  1116. Hive,
  1117. CmpHKeyNodeSize(Hive, &temp),
  1118. Stable,
  1119. HCELL_NIL
  1120. );
  1121. if (*RootCellIndex == HCELL_NIL) {
  1122. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpCreateRootNode: HvAllocateCell failed\n"));
  1123. return FALSE;
  1124. }
  1125. Hive->BaseBlock->RootCell = *RootCellIndex;
  1126. CellData = HvGetCell(Hive, *RootCellIndex);
  1127. if( CellData == NULL ) {
  1128. //
  1129. // we couldn't map the bin containing this cell
  1130. //
  1131. return FALSE;
  1132. }
  1133. //
  1134. // Initialize the node
  1135. //
  1136. CellData->u.KeyNode.Signature = CM_KEY_NODE_SIGNATURE;
  1137. CellData->u.KeyNode.Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
  1138. KeQuerySystemTime(&systemtime);
  1139. CellData->u.KeyNode.LastWriteTime = systemtime;
  1140. // CellData->u.KeyNode.TitleIndex = 0;
  1141. CellData->u.KeyNode.Parent = HCELL_NIL;
  1142. CellData->u.KeyNode.SubKeyCounts[Stable] = 0;
  1143. CellData->u.KeyNode.SubKeyCounts[Volatile] = 0;
  1144. CellData->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL;
  1145. CellData->u.KeyNode.SubKeyLists[Volatile] = HCELL_NIL;
  1146. CellData->u.KeyNode.ValueList.Count = 0;
  1147. CellData->u.KeyNode.ValueList.List = HCELL_NIL;
  1148. CellData->u.KeyNode.Security = HCELL_NIL;
  1149. CellData->u.KeyNode.Class = HCELL_NIL;
  1150. CellData->u.KeyNode.ClassLength = 0;
  1151. CellData->u.KeyNode.MaxValueDataLen = 0;
  1152. CellData->u.KeyNode.MaxNameLen = 0;
  1153. CellData->u.KeyNode.MaxValueNameLen = 0;
  1154. CellData->u.KeyNode.MaxClassLen = 0;
  1155. CellData->u.KeyNode.NameLength = CmpCopyName(Hive,
  1156. CellData->u.KeyNode.Name,
  1157. &temp);
  1158. if (CellData->u.KeyNode.NameLength < temp.Length) {
  1159. CellData->u.KeyNode.Flags |= KEY_COMP_NAME;
  1160. }
  1161. Key.KeyHive = Hive;
  1162. Key.KeyCell = *RootCellIndex;
  1163. HvReleaseCell(Hive, *RootCellIndex);
  1164. return TRUE;
  1165. }
  1166. NTSTATUS
  1167. CmpLinkHiveToMaster(
  1168. PUNICODE_STRING LinkName,
  1169. HANDLE RootDirectory,
  1170. PCMHIVE CmHive,
  1171. BOOLEAN Allocate,
  1172. PSECURITY_DESCRIPTOR SecurityDescriptor
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. The existing, "free floating" hive CmHive describes is linked into
  1177. the name space at the node named by LinkName. The node will be created.
  1178. The hive is assumed to already have an appropriate root node.
  1179. Arguments:
  1180. LinkName - supplies a pointer to a unicode string which describes where
  1181. in the registry name space the hive is to be linked.
  1182. All components but the last must exist. The last must not.
  1183. RootDirectory - Supplies the handle the LinkName is relative to.
  1184. CmHive - pointer to a CMHIVE structure describing the hive to link in.
  1185. Allocate - TRUE indicates that the root cell is to be created
  1186. FALSE indicates the root cell already exists.
  1187. SecurityDescriptor - supplies a pointer to the security descriptor to
  1188. be placed on the hive root.
  1189. Return Value:
  1190. TRUE == success, FALSE == failure
  1191. --*/
  1192. {
  1193. OBJECT_ATTRIBUTES ObjectAttributes;
  1194. HANDLE KeyHandle;
  1195. CM_PARSE_CONTEXT ParseContext;
  1196. NTSTATUS Status;
  1197. PCM_KEY_BODY KeyBody;
  1198. PAGED_CODE();
  1199. //
  1200. // Fill in special ParseContext to indicate that we are creating
  1201. // a link node and opening or creating a root node.
  1202. //
  1203. ParseContext.TitleIndex = 0;
  1204. ParseContext.Class.Length = 0;
  1205. ParseContext.Class.MaximumLength = 0;
  1206. ParseContext.Class.Buffer = NULL;
  1207. ParseContext.CreateOptions = 0;
  1208. ParseContext.CreateLink = TRUE;
  1209. ParseContext.ChildHive.KeyHive = &CmHive->Hive;
  1210. ParseContext.CreateOperation = TRUE;
  1211. ParseContext.OriginatingPoint = NULL;
  1212. if (Allocate) {
  1213. //
  1214. // Creating a new root node
  1215. //
  1216. ParseContext.ChildHive.KeyCell = HCELL_NIL;
  1217. } else {
  1218. //
  1219. // Opening an existing root node
  1220. //
  1221. ParseContext.ChildHive.KeyCell = CmHive->Hive.BaseBlock->RootCell;
  1222. }
  1223. //
  1224. // Create a path to the hive
  1225. //
  1226. InitializeObjectAttributes(
  1227. &ObjectAttributes,
  1228. LinkName,
  1229. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1230. (HANDLE)RootDirectory,
  1231. SecurityDescriptor
  1232. );
  1233. Status = ObOpenObjectByName( &ObjectAttributes,
  1234. CmpKeyObjectType,
  1235. KernelMode,
  1236. NULL,
  1237. KEY_READ | KEY_WRITE,
  1238. (PVOID)&ParseContext,
  1239. &KeyHandle );
  1240. if (!NT_SUCCESS(Status)) {
  1241. #ifdef CM_CHECK_FOR_ORPHANED_KCBS
  1242. DbgPrint("CmpLinkHiveToMaster: ObOpenObjectByName for CmHive = %p , LinkName = %.*S failed with status %lx\n",CmHive,LinkName->Length/2,LinkName->Buffer,Status);
  1243. #endif //CM_CHECK_FOR_ORPHANED_KCBS
  1244. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpLinkHiveToMaster: "));
  1245. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"ObOpenObjectByName() failed %08lx\n", Status));
  1246. //CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\tLinkName='%ws'\n", LinkName->Buffer));
  1247. return Status;
  1248. }
  1249. //
  1250. // Report the notification event
  1251. //
  1252. Status = ObReferenceObjectByHandle(KeyHandle,
  1253. 0,
  1254. CmpKeyObjectType,
  1255. KernelMode,
  1256. (PVOID *)&KeyBody,
  1257. NULL);
  1258. ASSERT(NT_SUCCESS(Status));
  1259. if (NT_SUCCESS(Status)) {
  1260. CmpReportNotify(KeyBody->KeyControlBlock,
  1261. KeyBody->KeyControlBlock->KeyHive,
  1262. KeyBody->KeyControlBlock->KeyCell,
  1263. REG_NOTIFY_CHANGE_NAME);
  1264. ObDereferenceObject((PVOID)KeyBody);
  1265. }
  1266. ZwClose(KeyHandle);
  1267. return STATUS_SUCCESS;
  1268. }
  1269. VOID
  1270. CmpSetVersionData(
  1271. VOID
  1272. )
  1273. /*++
  1274. Routine Description:
  1275. Create \REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion:
  1276. CurrentVersion = VER_PRODUCTVERSION_STR // From ntverp.h
  1277. CurrentBuildNumber = VER_PRODUCTBUILD // From ntverp.h
  1278. CurrentType = "[Multiprocessor|Uniprocessor] // From NT_UP
  1279. [Retail|Free|Checked]" // From DBG, DEVL
  1280. SystemRoot = "[c:\nt]"
  1281. BuildLab = BUILD_MACHINE_TAG // From ntos\inti.c from makefile.def
  1282. NOTE: It is not worth bugchecking over this, so if it doesn't
  1283. work, just fail.
  1284. Arguments:
  1285. Return Value:
  1286. --*/
  1287. {
  1288. ANSI_STRING AnsiString;
  1289. UNICODE_STRING NameString;
  1290. UNICODE_STRING ValueString;
  1291. HANDLE key1, key2;
  1292. CHAR WorkString[128];
  1293. WCHAR ValueBuffer[128];
  1294. OBJECT_ATTRIBUTES ObjectAttributes;
  1295. NTSTATUS status;
  1296. PCHAR proctype;
  1297. PCHAR buildtype;
  1298. PVERSION_DATA_KEY VersionDataKey;
  1299. PSECURITY_DESCRIPTOR SecurityDescriptor;
  1300. PAGED_CODE();
  1301. //
  1302. // Get default security descriptor for the nodes we will create.
  1303. //
  1304. SecurityDescriptor = CmpHiveRootSecurityDescriptor();
  1305. for (VersionDataKey = VersionDataKeys; VersionDataKey->InitialKeyPath != NULL ; VersionDataKey++) {
  1306. //
  1307. // Create the key
  1308. //
  1309. RtlInitUnicodeString(
  1310. &NameString,
  1311. VersionDataKey->InitialKeyPath
  1312. );
  1313. InitializeObjectAttributes(
  1314. &ObjectAttributes,
  1315. &NameString,
  1316. OBJ_CASE_INSENSITIVE,
  1317. (HANDLE)NULL,
  1318. SecurityDescriptor
  1319. );
  1320. status = NtCreateKey(
  1321. &key1,
  1322. KEY_CREATE_SUB_KEY,
  1323. &ObjectAttributes,
  1324. 0,
  1325. (PUNICODE_STRING)&nullclass,
  1326. 0,
  1327. NULL
  1328. );
  1329. if (!NT_SUCCESS(status)) {
  1330. #if DBG
  1331. #ifndef _CM_LDR_
  1332. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_WARNING_LEVEL,"CMINIT: CreateKey of %wZ failed - Status == %lx\n",
  1333. &NameString, status);
  1334. #endif //_CM_LDR_
  1335. #endif
  1336. ExFreePool(SecurityDescriptor);
  1337. return;
  1338. }
  1339. #if defined(_WIN64)
  1340. if (VersionDataKey->AdditionalKeyPath != NULL) {
  1341. RtlInitUnicodeString(
  1342. &NameString,
  1343. VersionDataKey->AdditionalKeyPath
  1344. );
  1345. InitializeObjectAttributes(
  1346. &ObjectAttributes,
  1347. &NameString,
  1348. OBJ_CASE_INSENSITIVE,
  1349. key1,
  1350. SecurityDescriptor
  1351. );
  1352. status = NtCreateKey(
  1353. &key2,
  1354. KEY_SET_VALUE,
  1355. &ObjectAttributes,
  1356. 0,
  1357. (PUNICODE_STRING)&nullclass,
  1358. 0,
  1359. NULL
  1360. );
  1361. NtClose(key1);
  1362. key1 = key2;
  1363. }
  1364. #endif
  1365. RtlInitUnicodeString(
  1366. &NameString,
  1367. L"Windows NT"
  1368. );
  1369. InitializeObjectAttributes(
  1370. &ObjectAttributes,
  1371. &NameString,
  1372. OBJ_CASE_INSENSITIVE,
  1373. key1,
  1374. SecurityDescriptor
  1375. );
  1376. status = NtCreateKey(
  1377. &key2,
  1378. KEY_SET_VALUE,
  1379. &ObjectAttributes,
  1380. 0,
  1381. (PUNICODE_STRING)&nullclass,
  1382. 0,
  1383. NULL
  1384. );
  1385. NtClose(key1);
  1386. RtlInitUnicodeString(
  1387. &NameString,
  1388. L"CurrentVersion"
  1389. );
  1390. InitializeObjectAttributes(
  1391. &ObjectAttributes,
  1392. &NameString,
  1393. OBJ_CASE_INSENSITIVE,
  1394. key2,
  1395. SecurityDescriptor
  1396. );
  1397. status = NtCreateKey(
  1398. &key1,
  1399. KEY_SET_VALUE,
  1400. &ObjectAttributes,
  1401. 0,
  1402. (PUNICODE_STRING)&nullclass,
  1403. 0,
  1404. NULL
  1405. );
  1406. NtClose(key2);
  1407. if (!NT_SUCCESS(status)) {
  1408. #if DBG
  1409. #ifndef _CM_LDR_
  1410. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_WARNING_LEVEL,"CMINIT: CreateKey of %wZ failed - Status == %lx\n",
  1411. &NameString, status);
  1412. #endif //_CM_LDR_
  1413. #endif
  1414. ExFreePool(SecurityDescriptor);
  1415. return;
  1416. }
  1417. //
  1418. // Set the value entries for the key
  1419. //
  1420. RtlInitUnicodeString(
  1421. &NameString,
  1422. L"CurrentVersion"
  1423. );
  1424. status = NtSetValueKey(
  1425. key1,
  1426. &NameString,
  1427. 0, // TitleIndex
  1428. REG_SZ,
  1429. CmVersionString.Buffer,
  1430. CmVersionString.Length + sizeof( UNICODE_NULL )
  1431. );
  1432. #if DBG
  1433. if (!NT_SUCCESS(status)) {
  1434. #ifndef _CM_LDR_
  1435. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CMINIT: SetValueKey of %wZ failed - Status == %lx\n",&NameString, status);
  1436. #endif //_CM_LDR_
  1437. }
  1438. #endif
  1439. RtlInitUnicodeString(
  1440. &NameString,
  1441. L"CurrentBuildNumber"
  1442. );
  1443. sprintf(
  1444. WorkString,
  1445. "%u",
  1446. NtBuildNumber & 0xFFFF
  1447. );
  1448. RtlInitAnsiString( &AnsiString, WorkString );
  1449. ValueString.Buffer = ValueBuffer;
  1450. ValueString.Length = 0;
  1451. ValueString.MaximumLength = sizeof( ValueBuffer );
  1452. RtlAnsiStringToUnicodeString( &ValueString, &AnsiString, FALSE );
  1453. status = NtSetValueKey(
  1454. key1,
  1455. &NameString,
  1456. 0, // TitleIndex
  1457. REG_SZ,
  1458. ValueString.Buffer,
  1459. ValueString.Length + sizeof( UNICODE_NULL )
  1460. );
  1461. #if DBG
  1462. if (!NT_SUCCESS(status)) {
  1463. #ifndef _CM_LDR_
  1464. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CMINIT: SetValueKey of %wZ failed - Status == %lx\n",&NameString, status);
  1465. #endif //_CM_LDR_
  1466. }
  1467. #endif
  1468. RtlInitUnicodeString(
  1469. &NameString,
  1470. L"BuildLab"
  1471. );
  1472. RtlInitAnsiString( &AnsiString, NtBuildLab );
  1473. ValueString.Buffer = ValueBuffer;
  1474. ValueString.Length = 0;
  1475. ValueString.MaximumLength = sizeof( ValueBuffer );
  1476. status = RtlAnsiStringToUnicodeString( &ValueString, &AnsiString, FALSE );
  1477. if (NT_SUCCESS(status)) {
  1478. status = NtSetValueKey(
  1479. key1,
  1480. &NameString,
  1481. 0,
  1482. REG_SZ,
  1483. ValueString.Buffer,
  1484. ValueString.Length + sizeof( UNICODE_NULL )
  1485. );
  1486. #if DBG
  1487. if (!NT_SUCCESS(status)) {
  1488. DbgPrint("CMINIT: SetValueKey of %wZ failed - Status == %lx\n",
  1489. &NameString, status);
  1490. }
  1491. } else {
  1492. DbgPrint("CMINIT: RtlAnsiStringToUnicodeString of %wZ failed - Status == %lx\n",
  1493. &NameString, status);
  1494. #endif
  1495. }
  1496. RtlInitUnicodeString(
  1497. &NameString,
  1498. L"CurrentType"
  1499. );
  1500. #if defined(NT_UP)
  1501. proctype = "Uniprocessor";
  1502. #else
  1503. proctype = "Multiprocessor";
  1504. #endif
  1505. #if DBG
  1506. buildtype = "Checked";
  1507. #else
  1508. #if DEVL
  1509. buildtype = "Free";
  1510. #else
  1511. buildtype = "Retail";
  1512. #endif
  1513. #endif
  1514. sprintf(
  1515. WorkString,
  1516. "%s %s",
  1517. proctype,
  1518. buildtype
  1519. );
  1520. RtlInitAnsiString( &AnsiString, WorkString );
  1521. ValueString.Buffer = ValueBuffer;
  1522. ValueString.Length = 0;
  1523. ValueString.MaximumLength = sizeof( ValueBuffer );
  1524. RtlAnsiStringToUnicodeString( &ValueString, &AnsiString, FALSE );
  1525. status = NtSetValueKey(
  1526. key1,
  1527. &NameString,
  1528. 0, // TitleIndex
  1529. REG_SZ,
  1530. ValueString.Buffer,
  1531. ValueString.Length + sizeof( UNICODE_NULL )
  1532. );
  1533. RtlInitUnicodeString(
  1534. &NameString,
  1535. L"CSDVersion"
  1536. );
  1537. if (CmCSDVersionString.Length != 0) {
  1538. status = NtSetValueKey(
  1539. key1,
  1540. &NameString,
  1541. 0, // TitleIndex
  1542. REG_SZ,
  1543. CmCSDVersionString.Buffer,
  1544. CmCSDVersionString.Length + sizeof( UNICODE_NULL )
  1545. );
  1546. #if DBG
  1547. if (!NT_SUCCESS(status)) {
  1548. #ifndef _CM_LDR_
  1549. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CMINIT: SetValueKey of %wZ failed - Status == %lx\n",&NameString, status);
  1550. #endif //_CM_LDR_
  1551. }
  1552. #endif
  1553. (RtlFreeStringRoutine)( CmCSDVersionString.Buffer );
  1554. RtlInitUnicodeString( &CmCSDVersionString, NULL );
  1555. } else {
  1556. status = NtDeleteValueKey(
  1557. key1,
  1558. &NameString
  1559. );
  1560. #if DBG
  1561. if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) {
  1562. #ifndef _CM_LDR_
  1563. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CMINIT: DeleteValueKey of %wZ failed - Status == %lx\n",&NameString, status);
  1564. #endif //_CM_LDR_
  1565. }
  1566. #endif
  1567. }
  1568. RtlInitUnicodeString(&NameString,
  1569. L"SystemRoot");
  1570. status = NtSetValueKey(key1,
  1571. &NameString,
  1572. 0,
  1573. REG_SZ,
  1574. NtSystemRoot.Buffer,
  1575. NtSystemRoot.Length + sizeof(UNICODE_NULL));
  1576. #if DBG
  1577. if (!NT_SUCCESS(status)) {
  1578. #ifndef _CM_LDR_
  1579. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CMINIT: SetValueKey of %wZ failed - Status == %lx\n",&NameString,status);
  1580. #endif //_CM_LDR_
  1581. }
  1582. #endif
  1583. NtClose(key1);
  1584. }
  1585. (RtlFreeStringRoutine)( CmVersionString.Buffer );
  1586. RtlInitUnicodeString( &CmVersionString, NULL );
  1587. ExFreePool(SecurityDescriptor);
  1588. //
  1589. // Set each processor to it's optimal configuration.
  1590. //
  1591. // Note: this call is performed interlocked such that the user
  1592. // can disable this automatic configuration update.
  1593. //
  1594. CmpInterlockedFunction(CmpProcessorControl, CmpConfigureProcessors);
  1595. return;
  1596. }
  1597. NTSTATUS
  1598. CmpInterlockedFunction (
  1599. PWCHAR RegistryValueKey,
  1600. VOID (*InterlockedFunction)(VOID)
  1601. )
  1602. /*++
  1603. Routine Description:
  1604. This routine guards calling the InterlockedFunction in the
  1605. passed RegistryValueKey.
  1606. The RegistryValueKey will record the status of the first
  1607. call to the InterlockedFunction. If the system crashes
  1608. durning this call then ValueKey will be left in a state
  1609. where the InterlockedFunction will not be called on subsequent
  1610. attempts.
  1611. Arguments:
  1612. RegistryValueKey - ValueKey name for Control\Session Manager
  1613. InterlockedFunction - Function to call
  1614. Return Value:
  1615. STATUS_SUCCESS - The interlocked function was successfully called
  1616. --*/
  1617. {
  1618. OBJECT_ATTRIBUTES objectAttributes;
  1619. HANDLE hControl, hSession;
  1620. UNICODE_STRING Name;
  1621. UCHAR Buffer [sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG)];
  1622. ULONG length, Value;
  1623. NTSTATUS status;
  1624. PAGED_CODE();
  1625. //
  1626. // Open CurrentControlSet
  1627. //
  1628. InitializeObjectAttributes (
  1629. &objectAttributes,
  1630. &CmRegistryMachineSystemCurrentControlSet,
  1631. OBJ_CASE_INSENSITIVE,
  1632. NULL,
  1633. NULL
  1634. );
  1635. status = NtOpenKey (&hControl, KEY_READ | KEY_WRITE, &objectAttributes);
  1636. if (!NT_SUCCESS(status)) {
  1637. return status;
  1638. }
  1639. //
  1640. // Open Control\Session Manager
  1641. //
  1642. RtlInitUnicodeString (&Name, CmpControlSessionManager);
  1643. InitializeObjectAttributes (
  1644. &objectAttributes,
  1645. &Name,
  1646. OBJ_CASE_INSENSITIVE,
  1647. hControl,
  1648. NULL
  1649. );
  1650. status = NtOpenKey (&hSession, KEY_READ | KEY_WRITE, &objectAttributes );
  1651. NtClose (hControl);
  1652. if (!NT_SUCCESS(status)) {
  1653. return status;
  1654. }
  1655. //
  1656. // Read ValueKey to interlock operation with
  1657. //
  1658. RtlInitUnicodeString (&Name, RegistryValueKey);
  1659. status = NtQueryValueKey (hSession,
  1660. &Name,
  1661. KeyValuePartialInformation,
  1662. Buffer,
  1663. sizeof (Buffer),
  1664. &length );
  1665. Value = 0;
  1666. if (NT_SUCCESS(status)) {
  1667. Value = ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data[0];
  1668. }
  1669. //
  1670. // Value 0 - Before InterlockedFunction
  1671. // 1 - In the middle of InterlockedFunction
  1672. // 2 - After InterlockedFunction
  1673. //
  1674. // If the value is a 0, then we haven't tried calling this
  1675. // interlocked function, set the value to a 1 and try it.
  1676. //
  1677. // If the value is a 1, then we crased durning an execution
  1678. // of the interlocked function last time, don't try it again.
  1679. //
  1680. // If the value is a 2, then we called the interlocked function
  1681. // before and it worked. Call it again this time.
  1682. //
  1683. if (Value != 1) {
  1684. if (Value != 2) {
  1685. //
  1686. // This interlocked function is not known to work. Write
  1687. // a 1 to this value so we can detect if we crash durning
  1688. // this call.
  1689. //
  1690. Value = 1;
  1691. NtSetValueKey (hSession, &Name, 0L, REG_DWORD, &Value, sizeof (Value));
  1692. NtFlushKey (hSession); // wait until it's on the disk
  1693. }
  1694. InterlockedFunction();
  1695. if (Value != 2) {
  1696. //
  1697. // The worker function didn't crash - update the value for
  1698. // this interlocked function to 2.
  1699. //
  1700. Value = 2;
  1701. NtSetValueKey (hSession, &Name, 0L, REG_DWORD, &Value, sizeof (Value));
  1702. }
  1703. } else {
  1704. status = STATUS_UNSUCCESSFUL;
  1705. }
  1706. NtClose (hSession);
  1707. return status;
  1708. }
  1709. VOID
  1710. CmpConfigureProcessors (
  1711. VOID
  1712. )
  1713. /*++
  1714. Routine Description:
  1715. Set each processor to it's optimal settings for NT.
  1716. --*/
  1717. {
  1718. ULONG i;
  1719. PAGED_CODE();
  1720. //
  1721. // Set each processor into its best NT configuration
  1722. //
  1723. for (i=0; i < (ULONG)KeNumberProcessors; i++) {
  1724. KeSetSystemAffinityThread(AFFINITY_MASK(i));
  1725. #if i386
  1726. // for now x86 only
  1727. KeOptimizeProcessorControlState ();
  1728. #endif
  1729. }
  1730. //
  1731. // Restore threads affinity
  1732. //
  1733. KeRevertToUserAffinityThread();
  1734. }
  1735. BOOLEAN
  1736. CmpInitializeSystemHive(
  1737. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  1738. )
  1739. /*++
  1740. Routine Description:
  1741. Initializes the SYSTEM hive based on the raw hive image passed in
  1742. from the OS Loader.
  1743. Arguments:
  1744. LoaderBlock - Supplies a pointer to the Loader Block passed in by
  1745. the OS Loader.
  1746. Return Value:
  1747. TRUE - it worked
  1748. FALSE - it failed
  1749. --*/
  1750. {
  1751. PCMHIVE SystemHive;
  1752. PVOID HiveImageBase;
  1753. BOOLEAN Allocate=FALSE;
  1754. PSECURITY_DESCRIPTOR SecurityDescriptor;
  1755. NTSTATUS Status;
  1756. STRING TempString;
  1757. PAGED_CODE();
  1758. //
  1759. // capture tail of boot.ini line (load options, portable)
  1760. //
  1761. RtlInitAnsiString(
  1762. &TempString,
  1763. LoaderBlock->LoadOptions
  1764. );
  1765. CmpLoadOptions.Length = 0;
  1766. CmpLoadOptions.MaximumLength = (TempString.Length+1)*sizeof(WCHAR);
  1767. CmpLoadOptions.Buffer = ExAllocatePool(
  1768. PagedPool, (TempString.Length+1)*sizeof(WCHAR));
  1769. if (CmpLoadOptions.Buffer == NULL) {
  1770. CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_SYSTEM_HIVE,1,LoaderBlock,0);
  1771. }
  1772. RtlAnsiStringToUnicodeString(
  1773. &CmpLoadOptions,
  1774. &TempString,
  1775. FALSE
  1776. );
  1777. CmpLoadOptions.Buffer[TempString.Length] = UNICODE_NULL;
  1778. CmpLoadOptions.Length += sizeof(WCHAR);
  1779. //
  1780. // move the loaded registry into the real registry
  1781. //
  1782. HiveImageBase = LoaderBlock->RegistryBase;
  1783. //
  1784. // We need to initialize the system hive as NO_LAZY_FLUSH
  1785. // - this is just temporary, untill we get a chance to open the primary
  1786. // file for the hive. Failure to do so, will result in loss of data on the
  1787. // LazyFlush worker (see CmpFileWrite, the
  1788. // if (FileHandle == NULL) {
  1789. // return TRUE;
  1790. // }
  1791. // test. This might be a problem in 5.0 too, if system crashes between the
  1792. // LazyFlush reported the hive as saved and the moment we actually open the
  1793. // file and save it again
  1794. //
  1795. if (HiveImageBase == NULL) {
  1796. //
  1797. // No memory descriptor for the hive, so we must recreate it.
  1798. //
  1799. Status = CmpInitializeHive(&SystemHive,
  1800. HINIT_CREATE,
  1801. HIVE_NOLAZYFLUSH,
  1802. HFILE_TYPE_LOG,
  1803. NULL,
  1804. NULL,
  1805. NULL,
  1806. NULL,
  1807. &CmpSystemFileName,
  1808. 0);
  1809. if (!NT_SUCCESS(Status)) {
  1810. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitializeSystemHive: "));
  1811. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"Couldn't initialize newly allocated SYSTEM hive\n"));
  1812. return(FALSE);
  1813. }
  1814. Allocate = TRUE;
  1815. } else {
  1816. //
  1817. // There is a memory image for the hive, copy it and make it active
  1818. //
  1819. Status = CmpInitializeHive(&SystemHive,
  1820. HINIT_MEMORY,
  1821. HIVE_NOLAZYFLUSH,
  1822. HFILE_TYPE_LOG,
  1823. HiveImageBase,
  1824. NULL,
  1825. NULL,
  1826. NULL,
  1827. &CmpSystemFileName,
  1828. CM_CHECK_REGISTRY_SYSTEM_CLEAN);
  1829. if (!NT_SUCCESS(Status)) {
  1830. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitializeSystemHive: "));
  1831. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"Couldn't initialize OS Loader-loaded SYSTEM hive\n"));
  1832. CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_SYSTEM_HIVE,2,SystemHive,Status);
  1833. }
  1834. Allocate = FALSE;
  1835. //
  1836. // Mark the system hive as volatile, while in MiniNT boot
  1837. // case
  1838. //
  1839. if (CmpShareSystemHives) {
  1840. SystemHive->Hive.HiveFlags = HIVE_VOLATILE;
  1841. }
  1842. }
  1843. CmpBootType = SystemHive->Hive.BaseBlock->BootType;
  1844. //
  1845. // Create the link node
  1846. //
  1847. SecurityDescriptor = CmpHiveRootSecurityDescriptor();
  1848. Status = CmpLinkHiveToMaster(&CmRegistryMachineSystemName,
  1849. NULL,
  1850. SystemHive,
  1851. Allocate,
  1852. SecurityDescriptor);
  1853. ExFreePool(SecurityDescriptor);
  1854. if (!NT_SUCCESS(Status)) {
  1855. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmInitSystem1: CmpLinkHiveToMaster(Hardware) failed\n"));
  1856. return(FALSE);
  1857. }
  1858. CmpMachineHiveList[SYSTEM_HIVE_INDEX].CmHive = SystemHive;
  1859. return(TRUE);
  1860. }
  1861. PHANDLE
  1862. CmGetSystemDriverList(
  1863. VOID
  1864. )
  1865. /*++
  1866. Routine Description:
  1867. Traverses the current SERVICES subtree and creates the list of drivers
  1868. to be loaded during Phase 1 initialization.
  1869. Arguments:
  1870. None
  1871. Return Value:
  1872. A pointer to an array of handles, each of which refers to a key in
  1873. the \Services section of the control set. The caller will traverse
  1874. this array and load and initialize the drivers described by the keys.
  1875. The last key will be NULL. The array is allocated in Pool and should
  1876. be freed by the caller.
  1877. --*/
  1878. {
  1879. OBJECT_ATTRIBUTES ObjectAttributes;
  1880. HANDLE SystemHandle;
  1881. UNICODE_STRING Name;
  1882. NTSTATUS Status;
  1883. PCM_KEY_BODY KeyBody;
  1884. LIST_ENTRY DriverList;
  1885. PHHIVE Hive;
  1886. HCELL_INDEX RootCell;
  1887. HCELL_INDEX ControlCell;
  1888. ULONG DriverCount;
  1889. PLIST_ENTRY Current;
  1890. PHANDLE Handle;
  1891. PBOOT_DRIVER_LIST_ENTRY DriverEntry;
  1892. BOOLEAN Success;
  1893. BOOLEAN AutoSelect;
  1894. PAGED_CODE();
  1895. InitializeListHead(&DriverList);
  1896. RtlInitUnicodeString(&Name,
  1897. L"\\Registry\\Machine\\System");
  1898. InitializeObjectAttributes(&ObjectAttributes,
  1899. &Name,
  1900. OBJ_CASE_INSENSITIVE,
  1901. (HANDLE)NULL,
  1902. NULL);
  1903. Status = NtOpenKey(&SystemHandle,
  1904. KEY_READ,
  1905. &ObjectAttributes);
  1906. if (!NT_SUCCESS(Status)) {
  1907. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmGetSystemDriverList couldn't open registry key %wZ\n",&Name));
  1908. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: status %08lx\n", Status));
  1909. return(NULL);
  1910. }
  1911. Status = ObReferenceObjectByHandle( SystemHandle,
  1912. KEY_QUERY_VALUE,
  1913. CmpKeyObjectType,
  1914. KernelMode,
  1915. (PVOID *)(&KeyBody),
  1916. NULL );
  1917. if (!NT_SUCCESS(Status)) {
  1918. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmGetSystemDriverList couldn't dereference System handle\n"));
  1919. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: status %08lx\n", Status));
  1920. NtClose(SystemHandle);
  1921. return(NULL);
  1922. }
  1923. CmpLockRegistryExclusive();
  1924. Hive = KeyBody->KeyControlBlock->KeyHive;
  1925. RootCell = KeyBody->KeyControlBlock->KeyCell;
  1926. //
  1927. // Now we have found out the PHHIVE and HCELL_INDEX of the root of the
  1928. // SYSTEM hive, we can use all the same code that the OS Loader does.
  1929. //
  1930. RtlInitUnicodeString(&Name, L"Current");
  1931. ControlCell = CmpFindControlSet(Hive,
  1932. RootCell,
  1933. &Name,
  1934. &AutoSelect);
  1935. if (ControlCell == HCELL_NIL) {
  1936. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmGetSystemDriverList couldn't find control set\n"));
  1937. CmpUnlockRegistry();
  1938. ObDereferenceObject((PVOID)KeyBody);
  1939. NtClose(SystemHandle);
  1940. return(NULL);
  1941. }
  1942. Success = CmpFindDrivers(Hive,
  1943. ControlCell,
  1944. SystemLoad,
  1945. NULL,
  1946. &DriverList);
  1947. if (!Success) {
  1948. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmGetSystemDriverList couldn't find any valid drivers\n"));
  1949. CmpFreeDriverList(Hive, &DriverList);
  1950. CmpUnlockRegistry();
  1951. ObDereferenceObject((PVOID)KeyBody);
  1952. NtClose(SystemHandle);
  1953. return(NULL);
  1954. }
  1955. if (!CmpSortDriverList(Hive,
  1956. ControlCell,
  1957. &DriverList)) {
  1958. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmGetSystemDriverList couldn't sort driver list\n"));
  1959. CmpFreeDriverList(Hive, &DriverList);
  1960. CmpUnlockRegistry();
  1961. ObDereferenceObject((PVOID)KeyBody);
  1962. NtClose(SystemHandle);
  1963. return(NULL);
  1964. }
  1965. if (!CmpResolveDriverDependencies(&DriverList)) {
  1966. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmGetSystemDriverList couldn't resolve driver dependencies\n"));
  1967. CmpFreeDriverList(Hive, &DriverList);
  1968. CmpUnlockRegistry();
  1969. ObDereferenceObject((PVOID)KeyBody);
  1970. NtClose(SystemHandle);
  1971. return(NULL);
  1972. }
  1973. CmpUnlockRegistry();
  1974. ObDereferenceObject((PVOID)KeyBody);
  1975. NtClose(SystemHandle);
  1976. //
  1977. // We now have a fully sorted and ordered list of drivers to be loaded
  1978. // by IoInit.
  1979. //
  1980. //
  1981. // Count the nodes in the list.
  1982. //
  1983. Current = DriverList.Flink;
  1984. DriverCount = 0;
  1985. while (Current != &DriverList) {
  1986. ++DriverCount;
  1987. Current = Current->Flink;
  1988. }
  1989. Handle = (PHANDLE)ExAllocatePool(NonPagedPool,
  1990. (DriverCount+1) * sizeof(HANDLE));
  1991. if (Handle == NULL) {
  1992. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_SYSTEM_DRIVER_LIST,1,0,0); // odds against this are huge
  1993. }
  1994. //
  1995. // Walk the list, opening each registry key and adding it to the
  1996. // table of handles.
  1997. //
  1998. Current = DriverList.Flink;
  1999. DriverCount = 0;
  2000. while (Current != &DriverList) {
  2001. DriverEntry = CONTAINING_RECORD(Current,
  2002. BOOT_DRIVER_LIST_ENTRY,
  2003. Link);
  2004. InitializeObjectAttributes(&ObjectAttributes,
  2005. &DriverEntry->RegistryPath,
  2006. OBJ_CASE_INSENSITIVE,
  2007. (HANDLE)NULL,
  2008. NULL);
  2009. Status = NtOpenKey(Handle+DriverCount,
  2010. KEY_READ | KEY_WRITE,
  2011. &ObjectAttributes);
  2012. if (!NT_SUCCESS(Status)) {
  2013. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmGetSystemDriverList couldn't open driver "));
  2014. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"key %wZ\n", &DriverEntry->RegistryPath));
  2015. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK," status %08lx\n",Status));
  2016. } else {
  2017. ++DriverCount;
  2018. }
  2019. Current = Current->Flink;
  2020. }
  2021. Handle[DriverCount] = NULL;
  2022. CmpFreeDriverList(Hive, &DriverList);
  2023. return(Handle);
  2024. }
  2025. VOID
  2026. CmpFreeDriverList(
  2027. IN PHHIVE Hive,
  2028. IN PLIST_ENTRY DriverList
  2029. )
  2030. /*++
  2031. Routine Description:
  2032. Walks down the driver list, freeing each node in it.
  2033. Note that this calls the hive's free routine pointer to free the memory.
  2034. Arguments:
  2035. Hive - Supplies a pointer to the hive control structure.
  2036. DriverList - Supplies a pointer to the head of the Driver List. Note
  2037. that the head of the list is not actually freed, only all the
  2038. entries in the list.
  2039. Return Value:
  2040. None.
  2041. --*/
  2042. {
  2043. PLIST_ENTRY Next;
  2044. PLIST_ENTRY Current;
  2045. PBOOT_DRIVER_NODE DriverNode;
  2046. PAGED_CODE();
  2047. Current = DriverList->Flink;
  2048. while (Current != DriverList) {
  2049. Next = Current->Flink;
  2050. DriverNode = (PBOOT_DRIVER_NODE)Current;
  2051. if( DriverNode->Name.Buffer != NULL ){
  2052. (Hive->Free)(DriverNode->Name.Buffer,DriverNode->Name.Length);
  2053. }
  2054. if( DriverNode->ListEntry.RegistryPath.Buffer != NULL ){
  2055. (Hive->Free)(DriverNode->ListEntry.RegistryPath.Buffer,DriverNode->ListEntry.RegistryPath.MaximumLength);
  2056. }
  2057. if( DriverNode->ListEntry.FilePath.Buffer != NULL ){
  2058. (Hive->Free)(DriverNode->ListEntry.FilePath.Buffer,DriverNode->ListEntry.FilePath.MaximumLength);
  2059. }
  2060. (Hive->Free)((PVOID)Current, sizeof(BOOT_DRIVER_NODE));
  2061. Current = Next;
  2062. }
  2063. }
  2064. NTSTATUS
  2065. CmpInitHiveFromFile(
  2066. IN PUNICODE_STRING FileName,
  2067. IN ULONG HiveFlags,
  2068. OUT PCMHIVE *CmHive,
  2069. IN OUT PBOOLEAN Allocate,
  2070. IN OUT PBOOLEAN RegistryLocked,
  2071. IN ULONG CheckFlags
  2072. )
  2073. /*++
  2074. Routine Description:
  2075. This routine opens a file and log, allocates a CMHIVE, and initializes
  2076. it.
  2077. Arguments:
  2078. FileName - Supplies name of file to be loaded.
  2079. HiveFlags - Supplies hive flags to be passed to CmpInitializeHive
  2080. CmHive - Returns pointer to initialized hive (if successful)
  2081. Allocate - IN: if TRUE ok to allocate, if FALSE hive must exist
  2082. (bug .log may get created)
  2083. OUT: TRUE if actually created hive, FALSE if existed before
  2084. Return Value:
  2085. NTSTATUS
  2086. --*/
  2087. {
  2088. PCMHIVE NewHive;
  2089. ULONG Disposition;
  2090. ULONG SecondaryDisposition;
  2091. HANDLE PrimaryHandle;
  2092. HANDLE LogHandle;
  2093. NTSTATUS Status;
  2094. ULONG FileType;
  2095. ULONG Operation;
  2096. PVOID HiveData = NULL;
  2097. BOOLEAN NoBuffering = FALSE;
  2098. BOOLEAN LockedHeldOnCall;
  2099. PAGED_CODE();
  2100. #ifndef CM_ENABLE_MAPPED_VIEWS
  2101. NoBuffering = TRUE;
  2102. #endif //CM_ENABLE_MAPPED_VIEWS
  2103. RetryNoBuffering:
  2104. *CmHive = NULL;
  2105. LockedHeldOnCall = *RegistryLocked;
  2106. Status = CmpOpenHiveFiles(FileName,
  2107. L".LOG",
  2108. &PrimaryHandle,
  2109. &LogHandle,
  2110. &Disposition,
  2111. &SecondaryDisposition,
  2112. *Allocate,
  2113. FALSE,
  2114. NoBuffering,
  2115. NULL);
  2116. if (!NT_SUCCESS(Status)) {
  2117. return(Status);
  2118. }
  2119. if (LogHandle == NULL) {
  2120. FileType = HFILE_TYPE_PRIMARY;
  2121. } else {
  2122. FileType = HFILE_TYPE_LOG;
  2123. }
  2124. if (Disposition == FILE_CREATED) {
  2125. Operation = HINIT_CREATE;
  2126. *Allocate = TRUE;
  2127. } else {
  2128. if( NoBuffering == TRUE ) {
  2129. Operation = HINIT_FILE;
  2130. } else {
  2131. Operation = HINIT_MAPFILE;
  2132. }
  2133. *Allocate = FALSE;
  2134. }
  2135. if (CmpShareSystemHives) {
  2136. FileType = HFILE_TYPE_PRIMARY;
  2137. if (LogHandle) {
  2138. ZwClose(LogHandle);
  2139. LogHandle = NULL;
  2140. }
  2141. }
  2142. if( !(*RegistryLocked) ) {
  2143. //
  2144. // Registry should be locked exclusive
  2145. // if not, lock it now and signal this to the caller
  2146. //
  2147. CmpLockRegistryExclusive();
  2148. *RegistryLocked = TRUE;
  2149. }
  2150. if( HvShutdownComplete == TRUE ) {
  2151. ZwClose(PrimaryHandle);
  2152. if (LogHandle != NULL) {
  2153. ZwClose(LogHandle);
  2154. }
  2155. return STATUS_TOO_LATE;
  2156. }
  2157. Status = CmpInitializeHive(&NewHive,
  2158. Operation,
  2159. HiveFlags,
  2160. FileType,
  2161. HiveData,
  2162. PrimaryHandle,
  2163. LogHandle,
  2164. NULL,
  2165. FileName,
  2166. CheckFlags
  2167. );
  2168. if (!NT_SUCCESS(Status)) {
  2169. CmpTrackHiveClose = TRUE;
  2170. ZwClose(PrimaryHandle);
  2171. CmpTrackHiveClose = FALSE;
  2172. if (LogHandle != NULL) {
  2173. ZwClose(LogHandle);
  2174. }
  2175. if( Status == STATUS_RETRY ) {
  2176. if( NoBuffering == FALSE ) {
  2177. NoBuffering = TRUE;
  2178. if( !LockedHeldOnCall ) {
  2179. *RegistryLocked = FALSE;
  2180. CmpUnlockRegistry();
  2181. }
  2182. goto RetryNoBuffering;
  2183. }
  2184. }
  2185. return(Status);
  2186. } else {
  2187. *CmHive = NewHive;
  2188. //
  2189. // mark handles as protected. If other kernel component tries to close them ==> bugcheck.
  2190. //
  2191. CmpSetHandleProtection(PrimaryHandle,TRUE);
  2192. if (LogHandle != NULL) {
  2193. CmpSetHandleProtection(LogHandle,TRUE);
  2194. }
  2195. //
  2196. // Capture the file name; in case we need it later for double load check
  2197. //
  2198. (*CmHive)->FileUserName.Buffer = ExAllocatePoolWithTag(PagedPool,
  2199. FileName->Length,
  2200. CM_NAME_TAG | PROTECTED_POOL);
  2201. if ((*CmHive)->FileUserName.Buffer) {
  2202. RtlCopyMemory((*CmHive)->FileUserName.Buffer,
  2203. FileName->Buffer,
  2204. FileName->Length);
  2205. (*CmHive)->FileUserName.Length = FileName->Length;
  2206. (*CmHive)->FileUserName.MaximumLength = FileName->Length;
  2207. }
  2208. if(((PHHIVE)(*CmHive))->BaseBlock->BootType & HBOOT_SELFHEAL) {
  2209. //
  2210. // Warn the user;
  2211. //
  2212. CmpRaiseSelfHealWarning(&((*CmHive)->FileUserName));
  2213. }
  2214. return(STATUS_SUCCESS);
  2215. }
  2216. }
  2217. NTSTATUS
  2218. CmpAddDockingInfo (
  2219. IN HANDLE Key,
  2220. IN PROFILE_PARAMETER_BLOCK * ProfileBlock
  2221. )
  2222. /*++
  2223. Routine Description:
  2224. Write DockID SerialNumber DockState and Capabilities intot the given
  2225. registry key.
  2226. --*/
  2227. {
  2228. NTSTATUS status = STATUS_SUCCESS;
  2229. UNICODE_STRING name;
  2230. ULONG value;
  2231. PAGED_CODE ();
  2232. value = ProfileBlock->DockingState;
  2233. RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKING_STATE);
  2234. status = NtSetValueKey (Key,
  2235. &name,
  2236. 0,
  2237. REG_DWORD,
  2238. &value,
  2239. sizeof (value));
  2240. if (!NT_SUCCESS (status)) {
  2241. return status;
  2242. }
  2243. value = ProfileBlock->Capabilities;
  2244. RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_CAPABILITIES);
  2245. status = NtSetValueKey (Key,
  2246. &name,
  2247. 0,
  2248. REG_DWORD,
  2249. &value,
  2250. sizeof (value));
  2251. if (!NT_SUCCESS (status)) {
  2252. return status;
  2253. }
  2254. value = ProfileBlock->DockID;
  2255. RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKID);
  2256. status = NtSetValueKey (Key,
  2257. &name,
  2258. 0,
  2259. REG_DWORD,
  2260. &value,
  2261. sizeof (value));
  2262. if (!NT_SUCCESS (status)) {
  2263. return status;
  2264. }
  2265. value = ProfileBlock->SerialNumber;
  2266. RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_SERIAL_NUMBER);
  2267. status = NtSetValueKey (Key,
  2268. &name,
  2269. 0,
  2270. REG_DWORD,
  2271. &value,
  2272. sizeof (value));
  2273. if (!NT_SUCCESS (status)) {
  2274. return status;
  2275. }
  2276. return status;
  2277. }
  2278. NTSTATUS
  2279. CmpAddAliasEntry (
  2280. IN HANDLE IDConfigDB,
  2281. IN PROFILE_PARAMETER_BLOCK * ProfileBlock,
  2282. IN ULONG ProfileNumber
  2283. )
  2284. /*++
  2285. Routine Description:
  2286. Create an alias entry in the IDConfigDB database for the given
  2287. hardware profile.
  2288. Create the "Alias" key if it does not exist.
  2289. Parameters:
  2290. IDConfigDB - Pointer to "..\CurrentControlSet\Control\IDConfigDB"
  2291. ProfileBlock - Description of the current Docking information
  2292. ProfileNumber -
  2293. --*/
  2294. {
  2295. OBJECT_ATTRIBUTES attributes;
  2296. NTSTATUS status = STATUS_SUCCESS;
  2297. CHAR asciiBuffer [128];
  2298. WCHAR unicodeBuffer [128];
  2299. ANSI_STRING ansiString;
  2300. UNICODE_STRING name;
  2301. HANDLE aliasKey = NULL;
  2302. HANDLE aliasEntry = NULL;
  2303. ULONG value;
  2304. ULONG disposition;
  2305. ULONG aliasNumber = 0;
  2306. PAGED_CODE ();
  2307. //
  2308. // Find the Alias Key or Create it if it does not already exist.
  2309. //
  2310. RtlInitUnicodeString (&name,CM_HARDWARE_PROFILE_STR_ALIAS);
  2311. InitializeObjectAttributes (&attributes,
  2312. &name,
  2313. OBJ_CASE_INSENSITIVE,
  2314. IDConfigDB,
  2315. NULL);
  2316. status = NtOpenKey (&aliasKey,
  2317. KEY_READ | KEY_WRITE,
  2318. &attributes);
  2319. if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
  2320. status = NtCreateKey (&aliasKey,
  2321. KEY_READ | KEY_WRITE,
  2322. &attributes,
  2323. 0, // no title
  2324. NULL, // no class
  2325. 0, // no options
  2326. &disposition);
  2327. }
  2328. if (!NT_SUCCESS (status)) {
  2329. aliasKey = NULL;
  2330. goto Exit;
  2331. }
  2332. //
  2333. // Create an entry key
  2334. //
  2335. while (aliasNumber < 200) {
  2336. aliasNumber++;
  2337. sprintf(asciiBuffer, "%04d", aliasNumber);
  2338. RtlInitAnsiString(&ansiString, asciiBuffer);
  2339. name.MaximumLength = sizeof(unicodeBuffer);
  2340. name.Buffer = unicodeBuffer;
  2341. status = RtlAnsiStringToUnicodeString(&name,
  2342. &ansiString,
  2343. FALSE);
  2344. ASSERT (STATUS_SUCCESS == status);
  2345. InitializeObjectAttributes(&attributes,
  2346. &name,
  2347. OBJ_CASE_INSENSITIVE,
  2348. aliasKey,
  2349. NULL);
  2350. status = NtOpenKey (&aliasEntry,
  2351. KEY_READ | KEY_WRITE,
  2352. &attributes);
  2353. if (NT_SUCCESS (status)) {
  2354. NtClose (aliasEntry);
  2355. } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
  2356. status = STATUS_SUCCESS;
  2357. break;
  2358. } else {
  2359. break;
  2360. }
  2361. }
  2362. if (!NT_SUCCESS (status)) {
  2363. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: cmpCreateAliasEntry error finding new set %08lx\n",status));
  2364. aliasEntry = 0;
  2365. goto Exit;
  2366. }
  2367. status = NtCreateKey (&aliasEntry,
  2368. KEY_READ | KEY_WRITE,
  2369. &attributes,
  2370. 0,
  2371. NULL,
  2372. 0,
  2373. &disposition);
  2374. if (!NT_SUCCESS (status)) {
  2375. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: cmpCreateAliasEntry error creating new set %08lx\n",status));
  2376. aliasEntry = 0;
  2377. goto Exit;
  2378. }
  2379. //
  2380. // Write the standard goo
  2381. //
  2382. CmpAddDockingInfo (aliasEntry, ProfileBlock);
  2383. //
  2384. // Write the Profile Number
  2385. //
  2386. value = ProfileNumber;
  2387. RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PROFILE_NUMBER);
  2388. status = NtSetValueKey (aliasEntry,
  2389. &name,
  2390. 0,
  2391. REG_DWORD,
  2392. &value,
  2393. sizeof (value));
  2394. Exit:
  2395. if (aliasKey) {
  2396. NtClose (aliasKey);
  2397. }
  2398. if (aliasEntry) {
  2399. NtClose (aliasEntry);
  2400. }
  2401. return status;
  2402. }
  2403. NTSTATUS
  2404. CmpHwprofileDefaultSelect (
  2405. IN PCM_HARDWARE_PROFILE_LIST ProfileList,
  2406. OUT PULONG ProfileIndexToUse,
  2407. IN PVOID Context
  2408. )
  2409. {
  2410. UNREFERENCED_PARAMETER (ProfileList);
  2411. UNREFERENCED_PARAMETER (Context);
  2412. * ProfileIndexToUse = 0;
  2413. return STATUS_SUCCESS;
  2414. }
  2415. NTSTATUS
  2416. CmpCreateControlSet(
  2417. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  2418. )
  2419. /*++
  2420. Routine Description:
  2421. This routine sets up the symbolic links from
  2422. \Registry\Machine\System\CurrentControlSet to
  2423. \Registry\Machine\System\ControlSetNNN
  2424. \Registry\Machine\System\CurrentControlSet\Hardware Profiles\Current to
  2425. \Registry\Machine\System\ControlSetNNN\Hardware Profiles\NNNN
  2426. based on the value of \Registry\Machine\System\Select:Current. and
  2427. \Registry\Machine\System\ControlSetNNN\Control\IDConfigDB:CurrentConfig
  2428. Arguments:
  2429. None
  2430. Return Value:
  2431. status
  2432. --*/
  2433. {
  2434. UNICODE_STRING IDConfigDBName;
  2435. UNICODE_STRING SelectName;
  2436. UNICODE_STRING CurrentName;
  2437. OBJECT_ATTRIBUTES Attributes;
  2438. HANDLE SelectHandle;
  2439. HANDLE CurrentHandle;
  2440. HANDLE IDConfigDB = NULL;
  2441. HANDLE CurrentProfile = NULL;
  2442. HANDLE ParentOfProfile = NULL;
  2443. CHAR AsciiBuffer[128];
  2444. WCHAR UnicodeBuffer[128];
  2445. UCHAR ValueBuffer[128];
  2446. ULONG ControlSet;
  2447. ULONG HWProfile;
  2448. PKEY_VALUE_FULL_INFORMATION Value;
  2449. ANSI_STRING AnsiString;
  2450. NTSTATUS Status;
  2451. ULONG ResultLength;
  2452. ULONG Disposition;
  2453. BOOLEAN signalAcpiEvent = FALSE;
  2454. PAGED_CODE();
  2455. RtlInitUnicodeString(&SelectName, L"\\Registry\\Machine\\System\\Select");
  2456. InitializeObjectAttributes(&Attributes,
  2457. &SelectName,
  2458. OBJ_CASE_INSENSITIVE,
  2459. NULL,
  2460. NULL);
  2461. Status = NtOpenKey(&SelectHandle,
  2462. KEY_READ,
  2463. &Attributes);
  2464. if (!NT_SUCCESS(Status)) {
  2465. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCreateControlSet: Couldn't open Select node %08lx\n",Status));
  2466. return(Status);
  2467. }
  2468. RtlInitUnicodeString(&CurrentName, L"Current");
  2469. Status = NtQueryValueKey(SelectHandle,
  2470. &CurrentName,
  2471. KeyValueFullInformation,
  2472. ValueBuffer,
  2473. sizeof(ValueBuffer),
  2474. &ResultLength);
  2475. NtClose(SelectHandle);
  2476. if (!NT_SUCCESS(Status)) {
  2477. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCreateControlSet: Couldn't query Select value %08lx\n",Status));
  2478. return(Status);
  2479. }
  2480. Value = (PKEY_VALUE_FULL_INFORMATION)ValueBuffer;
  2481. ControlSet = *(PULONG)((PUCHAR)Value + Value->DataOffset);
  2482. RtlInitUnicodeString(&CurrentName, L"\\Registry\\Machine\\System\\CurrentControlSet");
  2483. InitializeObjectAttributes(&Attributes,
  2484. &CurrentName,
  2485. OBJ_CASE_INSENSITIVE,
  2486. NULL,
  2487. NULL);
  2488. Status = NtCreateKey(&CurrentHandle,
  2489. KEY_CREATE_LINK,
  2490. &Attributes,
  2491. 0,
  2492. NULL,
  2493. REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
  2494. &Disposition);
  2495. if (!NT_SUCCESS(Status)) {
  2496. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCreateControlSet: couldn't create CurrentControlSet %08lx\n",Status));
  2497. return(Status);
  2498. }
  2499. //
  2500. // Check to make sure that the key was created, not just opened. Since
  2501. // this key is always created volatile, it should never be present in
  2502. // the hive when we boot.
  2503. //
  2504. ASSERT(Disposition == REG_CREATED_NEW_KEY);
  2505. //
  2506. // Create symbolic link for current hardware profile.
  2507. //
  2508. sprintf(AsciiBuffer, "\\Registry\\Machine\\System\\ControlSet%03d", ControlSet);
  2509. RtlInitAnsiString(&AnsiString, AsciiBuffer);
  2510. CurrentName.MaximumLength = sizeof(UnicodeBuffer);
  2511. CurrentName.Buffer = UnicodeBuffer;
  2512. Status = RtlAnsiStringToUnicodeString(&CurrentName,
  2513. &AnsiString,
  2514. FALSE);
  2515. Status = NtSetValueKey(CurrentHandle,
  2516. &CmSymbolicLinkValueName,
  2517. 0,
  2518. REG_LINK,
  2519. CurrentName.Buffer,
  2520. CurrentName.Length);
  2521. if (!NT_SUCCESS(Status)) {
  2522. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCreateControlSet: couldn't create symbolic link "));
  2523. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"to %wZ\n",&CurrentName));
  2524. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK," Status=%08lx\n",Status));
  2525. NtClose(CurrentHandle);
  2526. return(Status);
  2527. }
  2528. //
  2529. // Determine the Current Hardware Profile Number
  2530. //
  2531. RtlInitUnicodeString(&IDConfigDBName, L"Control\\IDConfigDB");
  2532. InitializeObjectAttributes(&Attributes,
  2533. &IDConfigDBName,
  2534. OBJ_CASE_INSENSITIVE,
  2535. CurrentHandle,
  2536. NULL);
  2537. Status = NtOpenKey(&IDConfigDB,
  2538. KEY_READ,
  2539. &Attributes);
  2540. NtClose(CurrentHandle);
  2541. if (!NT_SUCCESS(Status)) {
  2542. IDConfigDB = 0;
  2543. goto Cleanup;
  2544. }
  2545. RtlInitUnicodeString(&CurrentName, L"CurrentConfig");
  2546. Status = NtQueryValueKey(IDConfigDB,
  2547. &CurrentName,
  2548. KeyValueFullInformation,
  2549. ValueBuffer,
  2550. sizeof(ValueBuffer),
  2551. &ResultLength);
  2552. if (!NT_SUCCESS(Status) ||
  2553. (((PKEY_VALUE_FULL_INFORMATION)ValueBuffer)->Type != REG_DWORD)) {
  2554. goto Cleanup;
  2555. }
  2556. Value = (PKEY_VALUE_FULL_INFORMATION)ValueBuffer;
  2557. HWProfile = *(PULONG)((PUCHAR)Value + Value->DataOffset);
  2558. //
  2559. // We know now the config set that the user selected.
  2560. // namely: HWProfile.
  2561. //
  2562. RtlInitUnicodeString(
  2563. &CurrentName,
  2564. L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles");
  2565. InitializeObjectAttributes(&Attributes,
  2566. &CurrentName,
  2567. OBJ_CASE_INSENSITIVE,
  2568. NULL,
  2569. NULL);
  2570. Status = NtOpenKey(&ParentOfProfile,
  2571. KEY_READ,
  2572. &Attributes);
  2573. if (!NT_SUCCESS (Status)) {
  2574. ParentOfProfile = 0;
  2575. goto Cleanup;
  2576. }
  2577. sprintf(AsciiBuffer, "%04d",HWProfile);
  2578. RtlInitAnsiString(&AnsiString, AsciiBuffer);
  2579. CurrentName.MaximumLength = sizeof(UnicodeBuffer);
  2580. CurrentName.Buffer = UnicodeBuffer;
  2581. Status = RtlAnsiStringToUnicodeString(&CurrentName,
  2582. &AnsiString,
  2583. FALSE);
  2584. ASSERT (STATUS_SUCCESS == Status);
  2585. InitializeObjectAttributes(&Attributes,
  2586. &CurrentName,
  2587. OBJ_CASE_INSENSITIVE,
  2588. ParentOfProfile,
  2589. NULL);
  2590. Status = NtOpenKey (&CurrentProfile,
  2591. KEY_READ | KEY_WRITE,
  2592. &Attributes);
  2593. if (!NT_SUCCESS (Status)) {
  2594. CurrentProfile = 0;
  2595. goto Cleanup;
  2596. }
  2597. //
  2598. // We need to determine if Value was selected by exact match
  2599. // (TRUE_MATCH) or because the profile selected was aliasable.
  2600. //
  2601. // If aliasable we need to manufacture another alias entry in the
  2602. // alias table.
  2603. //
  2604. // If the profile information is there and not failed then we should
  2605. // mark the Docking state information:
  2606. // (DockID, SerialNumber, DockState, and Capabilities)
  2607. //
  2608. if (NULL != LoaderBlock->Extension) {
  2609. PLOADER_PARAMETER_EXTENSION extension;
  2610. extension = LoaderBlock->Extension;
  2611. switch (extension->Profile.Status) {
  2612. case HW_PROFILE_STATUS_PRISTINE_MATCH:
  2613. //
  2614. // If the selected profile is pristine then we need to clone.
  2615. //
  2616. Status = CmpCloneHwProfile (IDConfigDB,
  2617. ParentOfProfile,
  2618. CurrentProfile,
  2619. HWProfile,
  2620. extension->Profile.DockingState,
  2621. &CurrentProfile,
  2622. &HWProfile);
  2623. if (!NT_SUCCESS (Status)) {
  2624. CurrentProfile = 0;
  2625. goto Cleanup;
  2626. }
  2627. RtlInitUnicodeString(&CurrentName, L"CurrentConfig");
  2628. Status = NtSetValueKey (IDConfigDB,
  2629. &CurrentName,
  2630. 0,
  2631. REG_DWORD,
  2632. &HWProfile,
  2633. sizeof (HWProfile));
  2634. if (!NT_SUCCESS (Status)) {
  2635. goto Cleanup;
  2636. }
  2637. //
  2638. // Fall through
  2639. //
  2640. case HW_PROFILE_STATUS_ALIAS_MATCH:
  2641. //
  2642. // Create the alias entry for this profile.
  2643. //
  2644. Status = CmpAddAliasEntry (IDConfigDB,
  2645. &extension->Profile,
  2646. HWProfile);
  2647. //
  2648. // Fall through
  2649. //
  2650. case HW_PROFILE_STATUS_TRUE_MATCH:
  2651. //
  2652. // Write DockID, SerialNumber, DockState, and Caps into the current
  2653. // Hardware profile.
  2654. //
  2655. RtlInitUnicodeString (&CurrentName,
  2656. CM_HARDWARE_PROFILE_STR_CURRENT_DOCK_INFO);
  2657. InitializeObjectAttributes (&Attributes,
  2658. &CurrentName,
  2659. OBJ_CASE_INSENSITIVE,
  2660. IDConfigDB,
  2661. NULL);
  2662. Status = NtCreateKey (&CurrentHandle,
  2663. KEY_READ | KEY_WRITE,
  2664. &Attributes,
  2665. 0,
  2666. NULL,
  2667. REG_OPTION_VOLATILE,
  2668. &Disposition);
  2669. ASSERT (STATUS_SUCCESS == Status);
  2670. Status = CmpAddDockingInfo (CurrentHandle, &extension->Profile);
  2671. NtClose(CurrentHandle);
  2672. if (HW_PROFILE_DOCKSTATE_UNDOCKED == extension->Profile.DockingState) {
  2673. signalAcpiEvent = TRUE;
  2674. }
  2675. break;
  2676. case HW_PROFILE_STATUS_SUCCESS:
  2677. case HW_PROFILE_STATUS_FAILURE:
  2678. break;
  2679. default:
  2680. ASSERTMSG ("Invalid Profile status state", FALSE);
  2681. }
  2682. }
  2683. //
  2684. // Create the symbolic link.
  2685. //
  2686. RtlInitUnicodeString(&CurrentName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
  2687. InitializeObjectAttributes(&Attributes,
  2688. &CurrentName,
  2689. OBJ_CASE_INSENSITIVE,
  2690. NULL,
  2691. NULL);
  2692. Status = NtCreateKey(&CurrentHandle,
  2693. KEY_CREATE_LINK,
  2694. &Attributes,
  2695. 0,
  2696. NULL,
  2697. REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
  2698. &Disposition);
  2699. if (!NT_SUCCESS(Status)) {
  2700. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCreateControlSet: couldn't create Hardware Profile\\Current %08lx\n",Status));
  2701. } else {
  2702. ASSERT(Disposition == REG_CREATED_NEW_KEY);
  2703. sprintf(AsciiBuffer, "\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\%04d",HWProfile);
  2704. RtlInitAnsiString(&AnsiString, AsciiBuffer);
  2705. CurrentName.MaximumLength = sizeof(UnicodeBuffer);
  2706. CurrentName.Buffer = UnicodeBuffer;
  2707. Status = RtlAnsiStringToUnicodeString(&CurrentName,
  2708. &AnsiString,
  2709. FALSE);
  2710. ASSERT (STATUS_SUCCESS == Status);
  2711. Status = NtSetValueKey(CurrentHandle,
  2712. &CmSymbolicLinkValueName,
  2713. 0,
  2714. REG_LINK,
  2715. CurrentName.Buffer,
  2716. CurrentName.Length);
  2717. NtClose(CurrentHandle);
  2718. if (!NT_SUCCESS(Status)) {
  2719. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCreateControlSet: couldn't create symbolic link "));
  2720. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"to %wZ\n",&CurrentName));
  2721. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK," Status=%08lx\n",Status));
  2722. }
  2723. }
  2724. if (signalAcpiEvent) {
  2725. //
  2726. // We are booting in the undocked state.
  2727. // This is interesting because our buddies in PnP cannot tell
  2728. // us when we are booting without a dock. They can only tell
  2729. // us when they see a hot undock.
  2730. //
  2731. // Therefore in the interest of matching a boot undocked with
  2732. // a hot undock, we need to simulate an acpi undock event.
  2733. //
  2734. PROFILE_ACPI_DOCKING_STATE newDockState;
  2735. HANDLE profile;
  2736. BOOLEAN changed;
  2737. newDockState.DockingState = HW_PROFILE_DOCKSTATE_UNDOCKED;
  2738. newDockState.SerialLength = 2;
  2739. newDockState.SerialNumber[0] = L'\0';
  2740. Status = CmSetAcpiHwProfile (&newDockState,
  2741. CmpHwprofileDefaultSelect,
  2742. NULL,
  2743. &profile,
  2744. &changed);
  2745. ASSERT (NT_SUCCESS (Status));
  2746. NtClose (profile);
  2747. }
  2748. Cleanup:
  2749. if (IDConfigDB) {
  2750. NtClose (IDConfigDB);
  2751. }
  2752. if (CurrentProfile) {
  2753. NtClose (CurrentProfile);
  2754. }
  2755. if (ParentOfProfile) {
  2756. NtClose (ParentOfProfile);
  2757. }
  2758. return(STATUS_SUCCESS);
  2759. }
  2760. NTSTATUS
  2761. CmpCloneControlSet(
  2762. VOID
  2763. )
  2764. /*++
  2765. Routine Description:
  2766. First, create a new hive, \registry\machine\clone, which will be
  2767. HIVE_VOLATILE.
  2768. Second, link \Registry\Machine\System\Clone to it.
  2769. Third, tree copy \Registry\Machine\System\CurrentControlSet into
  2770. \Registry\Machine\System\Clone (and thus into the clone hive.)
  2771. When the service controller is done with the clone hive, it can
  2772. simply NtUnloadKey it to free its storage.
  2773. Arguments:
  2774. None. \Registry\Machine\System\CurrentControlSet must already exist.
  2775. Return Value:
  2776. NTSTATUS
  2777. --*/
  2778. {
  2779. UNICODE_STRING Current;
  2780. UNICODE_STRING Clone;
  2781. HANDLE CurrentHandle;
  2782. HANDLE CloneHandle;
  2783. OBJECT_ATTRIBUTES Attributes;
  2784. NTSTATUS Status;
  2785. PCM_KEY_BODY CurrentKey;
  2786. PCM_KEY_BODY CloneKey;
  2787. ULONG Disposition;
  2788. PSECURITY_DESCRIPTOR Security;
  2789. ULONG SecurityLength;
  2790. PAGED_CODE();
  2791. RtlInitUnicodeString(&Current,
  2792. L"\\Registry\\Machine\\System\\CurrentControlSet");
  2793. RtlInitUnicodeString(&Clone,
  2794. L"\\Registry\\Machine\\System\\Clone");
  2795. InitializeObjectAttributes(&Attributes,
  2796. &Current,
  2797. OBJ_CASE_INSENSITIVE,
  2798. NULL,
  2799. NULL);
  2800. Status = NtOpenKey(&CurrentHandle,
  2801. KEY_READ,
  2802. &Attributes);
  2803. if (!NT_SUCCESS(Status)) {
  2804. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCloneControlSet couldn't open CurrentControlSet %08lx\n",Status));
  2805. return(Status);
  2806. }
  2807. //
  2808. // Get the security descriptor from the key so we can create the clone
  2809. // tree with the correct ACL.
  2810. //
  2811. Status = NtQuerySecurityObject(CurrentHandle,
  2812. DACL_SECURITY_INFORMATION,
  2813. NULL,
  2814. 0,
  2815. &SecurityLength);
  2816. if (Status==STATUS_BUFFER_TOO_SMALL) {
  2817. Security=ExAllocatePool(PagedPool,SecurityLength);
  2818. if (Security!=NULL) {
  2819. Status = NtQuerySecurityObject(CurrentHandle,
  2820. DACL_SECURITY_INFORMATION,
  2821. Security,
  2822. SecurityLength,
  2823. &SecurityLength);
  2824. if (!NT_SUCCESS(Status)) {
  2825. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCloneControlSet - NtQuerySecurityObject failed %08lx\n",Status));
  2826. ExFreePool(Security);
  2827. Security=NULL;
  2828. }
  2829. }
  2830. } else {
  2831. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCloneControlSet - NtQuerySecurityObject returned %08lx\n",Status));
  2832. Security=NULL;
  2833. }
  2834. InitializeObjectAttributes(&Attributes,
  2835. &Clone,
  2836. OBJ_CASE_INSENSITIVE,
  2837. NULL,
  2838. Security);
  2839. Status = NtCreateKey(&CloneHandle,
  2840. KEY_READ | KEY_WRITE,
  2841. &Attributes,
  2842. 0,
  2843. NULL,
  2844. REG_OPTION_VOLATILE,
  2845. &Disposition);
  2846. if (Security!=NULL) {
  2847. ExFreePool(Security);
  2848. }
  2849. if (!NT_SUCCESS(Status)) {
  2850. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCloneControlSet couldn't create Clone %08lx\n",Status));
  2851. NtClose(CurrentHandle);
  2852. return(Status);
  2853. }
  2854. //
  2855. // Check to make sure the key was created. If it already exists,
  2856. // something is wrong.
  2857. //
  2858. if (Disposition != REG_CREATED_NEW_KEY) {
  2859. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCloneControlSet: Clone tree already exists!\n"));
  2860. //
  2861. // WARNNOTE:
  2862. // If somebody somehow managed to create a key in our way,
  2863. // they'll thwart last known good. Tough luck.
  2864. // Claim it worked and go on.
  2865. //
  2866. Status = STATUS_SUCCESS;
  2867. goto Exit;
  2868. }
  2869. Status = ObReferenceObjectByHandle(CurrentHandle,
  2870. KEY_READ,
  2871. CmpKeyObjectType,
  2872. KernelMode,
  2873. (PVOID *)(&CurrentKey),
  2874. NULL);
  2875. if (!NT_SUCCESS(Status)) {
  2876. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCloneControlSet: couldn't reference CurrentHandle %08lx\n",Status));
  2877. goto Exit;
  2878. }
  2879. Status = ObReferenceObjectByHandle(CloneHandle,
  2880. KEY_WRITE,
  2881. CmpKeyObjectType,
  2882. KernelMode,
  2883. (PVOID *)(&CloneKey),
  2884. NULL);
  2885. if (!NT_SUCCESS(Status)) {
  2886. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCloneControlSet: couldn't reference CurrentHandle %08lx\n",Status));
  2887. ObDereferenceObject((PVOID)CurrentKey);
  2888. goto Exit;
  2889. }
  2890. CmpLockRegistryExclusive();
  2891. if (CmpCopyTree(CurrentKey->KeyControlBlock->KeyHive,
  2892. CurrentKey->KeyControlBlock->KeyCell,
  2893. CloneKey->KeyControlBlock->KeyHive,
  2894. CloneKey->KeyControlBlock->KeyCell)) {
  2895. //
  2896. // Set the max subkey name property for the new target key.
  2897. //
  2898. CmpRebuildKcbCache(CloneKey->KeyControlBlock);
  2899. Status = STATUS_SUCCESS;
  2900. } else {
  2901. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpCloneControlSet: tree copy failed.\n"));
  2902. Status = STATUS_REGISTRY_CORRUPT;
  2903. }
  2904. CmpUnlockRegistry();
  2905. ObDereferenceObject((PVOID)CurrentKey);
  2906. ObDereferenceObject((PVOID)CloneKey);
  2907. Exit:
  2908. NtClose(CurrentHandle);
  2909. NtClose(CloneHandle);
  2910. return(Status);
  2911. }
  2912. NTSTATUS
  2913. CmpSaveBootControlSet(USHORT ControlSetNum)
  2914. /*++
  2915. Routine Description:
  2916. This routine is responsible for saving the control set
  2917. used to accomplish the latest boot into a different control
  2918. set (presumably so that the different control set may be
  2919. marked as the LKG control set).
  2920. This routine is called from NtInitializeRegistry when
  2921. a boot is accepted via that routine.
  2922. Arguments:
  2923. ControlSetNum - The number of the control set that will
  2924. be used to save the boot control set.
  2925. Return Value:
  2926. NTSTATUS result code from call, among the following:
  2927. STATUS_SUCCESS - everything worked perfectly
  2928. STATUS_REGISTRY_CORRUPT - could not save the boot control set,
  2929. it is likely that the copy or sync
  2930. operation used for this save failed
  2931. and some part of the boot control
  2932. set was not saved.
  2933. --*/
  2934. {
  2935. UNICODE_STRING SavedBoot;
  2936. HANDLE BootHandle, SavedBootHandle;
  2937. OBJECT_ATTRIBUTES Attributes;
  2938. NTSTATUS Status;
  2939. PCM_KEY_BODY BootKey, SavedBootKey;
  2940. ULONG Disposition;
  2941. PSECURITY_DESCRIPTOR Security;
  2942. ULONG SecurityLength;
  2943. BOOLEAN CopyRet;
  2944. WCHAR Buffer[128];
  2945. //
  2946. // Figure out where the boot control set is
  2947. //
  2948. #if CLONE_CONTROL_SET
  2949. //
  2950. // If we have cloned the control set, then use the clone
  2951. // since it is guaranteed to have an untouched copy of the
  2952. // boot control set
  2953. //
  2954. RtlInitUnicodeString(&Boot,
  2955. L"\\Registry\\Machine\\System\\Clone");
  2956. InitializeObjectAttributes(&Attributes,
  2957. &Boot,
  2958. OBJ_CASE_INSENSITIVE,
  2959. NULL,
  2960. NULL);
  2961. #else
  2962. //
  2963. // If we are not using the clone, then just use the
  2964. // current control set.
  2965. //
  2966. InitializeObjectAttributes(&Attributes,
  2967. &CmRegistryMachineSystemCurrentControlSet,
  2968. OBJ_CASE_INSENSITIVE,
  2969. NULL,
  2970. NULL);
  2971. #endif
  2972. //
  2973. // Open the boot control set
  2974. //
  2975. Status = NtOpenKey(&BootHandle,
  2976. KEY_READ,
  2977. &Attributes);
  2978. if (!NT_SUCCESS(Status)) return(Status);
  2979. //
  2980. // We may be saving the boot control set into a brand new
  2981. // tree that we will create. If this is true, then we will
  2982. // need to create the root node of this tree below
  2983. // and give it the right security descriptor. So, we fish
  2984. // the security descriptor out of the root node of the
  2985. // boot control set tree.
  2986. //
  2987. Status = NtQuerySecurityObject(BootHandle,
  2988. DACL_SECURITY_INFORMATION,
  2989. NULL,
  2990. 0,
  2991. &SecurityLength);
  2992. if (Status==STATUS_BUFFER_TOO_SMALL) {
  2993. Security=ExAllocatePool(PagedPool,SecurityLength);
  2994. if (Security!=NULL) {
  2995. Status = NtQuerySecurityObject(BootHandle,
  2996. DACL_SECURITY_INFORMATION,
  2997. Security,
  2998. SecurityLength,
  2999. &SecurityLength);
  3000. if (!NT_SUCCESS(Status)) {
  3001. ExFreePool(Security);
  3002. Security=NULL;
  3003. }
  3004. }
  3005. } else {
  3006. Security=NULL;
  3007. }
  3008. //
  3009. // Now, create the path of the control set we will be saving to
  3010. //
  3011. swprintf(Buffer, L"\\Registry\\Machine\\System\\ControlSet%03d", ControlSetNum);
  3012. RtlInitUnicodeString(&SavedBoot,
  3013. Buffer);
  3014. //
  3015. // Open/Create the control set to which we are saving
  3016. //
  3017. InitializeObjectAttributes(&Attributes,
  3018. &SavedBoot,
  3019. OBJ_CASE_INSENSITIVE,
  3020. NULL,
  3021. Security);
  3022. Status = NtCreateKey(&SavedBootHandle,
  3023. KEY_READ | KEY_WRITE,
  3024. &Attributes,
  3025. 0,
  3026. NULL,
  3027. REG_OPTION_NON_VOLATILE,
  3028. &Disposition);
  3029. if (Security) ExFreePool(Security);
  3030. if (!NT_SUCCESS(Status)) {
  3031. NtClose(BootHandle);
  3032. return(Status);
  3033. }
  3034. //
  3035. // Get the key objects for out two controls
  3036. //
  3037. Status = ObReferenceObjectByHandle(BootHandle,
  3038. KEY_READ,
  3039. CmpKeyObjectType,
  3040. KernelMode,
  3041. (PVOID *)(&BootKey),
  3042. NULL);
  3043. if (!NT_SUCCESS(Status)) goto Exit;
  3044. Status = ObReferenceObjectByHandle(SavedBootHandle,
  3045. KEY_WRITE,
  3046. CmpKeyObjectType,
  3047. KernelMode,
  3048. (PVOID *)(&SavedBootKey),
  3049. NULL);
  3050. if (!NT_SUCCESS(Status)) {
  3051. ObDereferenceObject((PVOID)BootKey);
  3052. goto Exit;
  3053. }
  3054. //
  3055. // Lock the registry and do the actual saving
  3056. //
  3057. CmpLockRegistryExclusive();
  3058. if (Disposition == REG_CREATED_NEW_KEY) {
  3059. PCM_KEY_NODE Node;
  3060. //
  3061. // If we are saving to a control set that we have just
  3062. // created, it is most efficient to just copy
  3063. // the boot control set tree into the new control set.
  3064. //
  3065. //
  3066. // N.B. We copy the volatile keys only if we are using
  3067. // a clone and thus our boot control set tree is
  3068. // composed only of volatile keys.
  3069. //
  3070. CopyRet = CmpCopyTreeEx(BootKey->KeyControlBlock->KeyHive,
  3071. BootKey->KeyControlBlock->KeyCell,
  3072. SavedBootKey->KeyControlBlock->KeyHive,
  3073. SavedBootKey->KeyControlBlock->KeyCell,
  3074. CLONE_CONTROL_SET);
  3075. //
  3076. // Set the max subkey name property for the new target key.
  3077. //
  3078. Node = (PCM_KEY_NODE)HvGetCell(BootKey->KeyControlBlock->KeyHive,BootKey->KeyControlBlock->KeyCell);
  3079. if( Node ) {
  3080. ULONG MaxNameLen = Node->MaxNameLen;
  3081. HvReleaseCell(BootKey->KeyControlBlock->KeyHive,BootKey->KeyControlBlock->KeyCell);
  3082. Node = (PCM_KEY_NODE)HvGetCell(SavedBootKey->KeyControlBlock->KeyHive,SavedBootKey->KeyControlBlock->KeyCell);
  3083. if( Node ) {
  3084. if ( HvMarkCellDirty(SavedBootKey->KeyControlBlock->KeyHive,SavedBootKey->KeyControlBlock->KeyCell) ) {
  3085. Node->MaxNameLen = MaxNameLen;
  3086. }
  3087. HvReleaseCell(SavedBootKey->KeyControlBlock->KeyHive,SavedBootKey->KeyControlBlock->KeyCell);
  3088. }
  3089. }
  3090. CmpRebuildKcbCache(SavedBootKey->KeyControlBlock);
  3091. } else {
  3092. //
  3093. // If we are saving to a control set that already exists
  3094. // then its likely that this control set is nearly identical
  3095. // to the boot control set (control sets don't change much
  3096. // between boots).
  3097. //
  3098. // Furthermore, the control set we are saving to must be old
  3099. // and hence has not been modified at all since it ceased
  3100. // being a current control set.
  3101. //
  3102. // Thus, it is most efficient for us to simply synchronize
  3103. // the target control set with the boot control set.
  3104. //
  3105. //
  3106. // N.B. We sync the volatile keys only if we are using
  3107. // a clone for the same reasons as stated above.
  3108. //
  3109. CopyRet = CmpSyncTrees(BootKey->KeyControlBlock->KeyHive,
  3110. BootKey->KeyControlBlock->KeyCell,
  3111. SavedBootKey->KeyControlBlock->KeyHive,
  3112. SavedBootKey->KeyControlBlock->KeyCell,
  3113. CLONE_CONTROL_SET);
  3114. CmpRebuildKcbCache(SavedBootKey->KeyControlBlock);
  3115. }
  3116. //
  3117. // Check if the Copy/Sync succeeded and adjust our return code
  3118. // accordingly.
  3119. //
  3120. if (CopyRet) {
  3121. Status = STATUS_SUCCESS;
  3122. } else {
  3123. Status = STATUS_REGISTRY_CORRUPT;
  3124. }
  3125. //
  3126. // All done. Clean up.
  3127. //
  3128. CmpUnlockRegistry();
  3129. ObDereferenceObject((PVOID)BootKey);
  3130. ObDereferenceObject((PVOID)SavedBootKey);
  3131. Exit:
  3132. NtClose(BootHandle);
  3133. NtClose(SavedBootHandle);
  3134. #if CLONE_CONTROL_SET
  3135. //
  3136. // If we have been using a clone, then the clone is no longer
  3137. // needed since we have saved its contents into a non-volatile
  3138. // control set. Thus, we can just erase it.
  3139. //
  3140. if(NT_SUCCESS(Status))
  3141. {
  3142. CmpDeleteCloneTree();
  3143. }
  3144. #endif
  3145. return(Status);
  3146. }
  3147. NTSTATUS
  3148. CmpDeleteCloneTree()
  3149. /*++
  3150. Routine Description:
  3151. Deletes the cloned CurrentControlSet by unloading the CLONE hive.
  3152. Arguments:
  3153. NONE.
  3154. Return Value:
  3155. NTSTATUS return from NtUnloadKey.
  3156. --*/
  3157. {
  3158. OBJECT_ATTRIBUTES Obja;
  3159. InitializeObjectAttributes(
  3160. &Obja,
  3161. &CmRegistrySystemCloneName,
  3162. OBJ_CASE_INSENSITIVE,
  3163. (HANDLE)NULL,
  3164. NULL);
  3165. return NtUnloadKey(&Obja);
  3166. }
  3167. VOID
  3168. CmBootLastKnownGood(
  3169. ULONG ErrorLevel
  3170. )
  3171. /*++
  3172. Routine Description:
  3173. This function is called to indicate a failure during the boot process.
  3174. The actual result is based on the value of ErrorLevel:
  3175. IGNORE - Will return, boot should proceed
  3176. NORMAL - Will return, boot should proceed
  3177. SEVERE - If not booting LastKnownGood, will switch to LastKnownGood
  3178. and reboot the system.
  3179. If already booting LastKnownGood, will return. Boot should
  3180. proceed.
  3181. CRITICAL - If not booting LastKnownGood, will switch to LastKnownGood
  3182. and reboot the system.
  3183. If already booting LastKnownGood, will bugcheck.
  3184. Arguments:
  3185. ErrorLevel - Supplies the severity level of the failure
  3186. Return Value:
  3187. None. If it returns, boot should proceed. May cause the system to
  3188. reboot.
  3189. --*/
  3190. {
  3191. ARC_STATUS Status;
  3192. PAGED_CODE();
  3193. if (CmFirstTime != TRUE) {
  3194. //
  3195. // NtInitializeRegistry has been called, so handling
  3196. // driver errors is not a task for ScReg.
  3197. // Treat all errors as Normal
  3198. //
  3199. return;
  3200. }
  3201. switch (ErrorLevel) {
  3202. case NormalError:
  3203. case IgnoreError:
  3204. break;
  3205. case SevereError:
  3206. if (CmIsLastKnownGoodBoot()) {
  3207. break;
  3208. } else {
  3209. Status = HalSetEnvironmentVariable("LastKnownGood", "TRUE");
  3210. if (Status == ESUCCESS) {
  3211. HalReturnToFirmware(HalRebootRoutine);
  3212. }
  3213. }
  3214. break;
  3215. case CriticalError:
  3216. if (CmIsLastKnownGoodBoot()) {
  3217. CM_BUGCHECK( CRITICAL_SERVICE_FAILED, BAD_LAST_KNOWN_GOOD, 1, 0, 0 );
  3218. } else {
  3219. Status = HalSetEnvironmentVariable("LastKnownGood", "TRUE");
  3220. if (Status == ESUCCESS) {
  3221. HalReturnToFirmware(HalRebootRoutine);
  3222. } else {
  3223. CM_BUGCHECK( SET_ENV_VAR_FAILED, BAD_LAST_KNOWN_GOOD, 2, 0, 0 );
  3224. }
  3225. }
  3226. break;
  3227. }
  3228. return;
  3229. }
  3230. BOOLEAN
  3231. CmIsLastKnownGoodBoot(
  3232. VOID
  3233. )
  3234. /*++
  3235. Routine Description:
  3236. Determines whether the current system boot is a LastKnownGood boot or
  3237. not. It does this by comparing the following two values:
  3238. \registry\machine\system\select:Current
  3239. \registry\machine\system\select:LastKnownGood
  3240. If both of these values refer to the same control set, and this control
  3241. set is different from:
  3242. \registry\machine\system\select:Default
  3243. we are booting LastKnownGood.
  3244. Arguments:
  3245. None.
  3246. Return Value:
  3247. TRUE - Booting LastKnownGood
  3248. FALSE - Not booting LastKnownGood
  3249. --*/
  3250. {
  3251. NTSTATUS Status;
  3252. ULONG Default = 0;//prefast initialization
  3253. ULONG Current = 0;//prefast initialization
  3254. ULONG LKG = 0; //prefast initialization
  3255. RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
  3256. {NULL, RTL_QUERY_REGISTRY_DIRECT,
  3257. L"Current", &Current,
  3258. REG_DWORD, (PVOID)&Current, 0 },
  3259. {NULL, RTL_QUERY_REGISTRY_DIRECT,
  3260. L"LastKnownGood", &LKG,
  3261. REG_DWORD, (PVOID)&LKG, 0 },
  3262. {NULL, RTL_QUERY_REGISTRY_DIRECT,
  3263. L"Default", &Default,
  3264. REG_DWORD, (PVOID)&Default, 0 },
  3265. {NULL, 0,
  3266. NULL, NULL,
  3267. REG_NONE, NULL, 0 }
  3268. };
  3269. PAGED_CODE();
  3270. Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  3271. L"\\Registry\\Machine\\System\\Select",
  3272. QueryTable,
  3273. NULL,
  3274. NULL);
  3275. //
  3276. // If this failed, something is severely wrong.
  3277. //
  3278. ASSERT(NT_SUCCESS(Status));
  3279. if (!NT_SUCCESS(Status)) {
  3280. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"CmIsLastKnownGoodBoot: RtlQueryRegistryValues "));
  3281. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"failed, Status %08lx\n", Status));
  3282. return(FALSE);
  3283. }
  3284. if ((LKG == Current) && (Current != Default)){
  3285. return(TRUE);
  3286. } else {
  3287. return(FALSE);
  3288. }
  3289. }
  3290. BOOLEAN
  3291. CmpLinkKeyToHive(
  3292. PWSTR KeyPath,
  3293. PWSTR HivePath
  3294. )
  3295. /*++
  3296. Routine Description:
  3297. Creates a symbolic link at KeyPath that points to HivePath.
  3298. Arguments:
  3299. KeyPath - pointer to unicode string with name of key
  3300. (e.g. L"\\Registry\\Machine\\Security\\SAM")
  3301. HivePath - pointer to unicode string with name of hive root
  3302. (e.g. L"\\Registry\\Machine\\SAM\\SAM")
  3303. Return Value:
  3304. TRUE if links were successfully created, FALSE otherwise
  3305. --*/
  3306. {
  3307. UNICODE_STRING KeyName;
  3308. UNICODE_STRING LinkName;
  3309. OBJECT_ATTRIBUTES Attributes;
  3310. HANDLE LinkHandle;
  3311. ULONG Disposition;
  3312. NTSTATUS Status;
  3313. PAGED_CODE();
  3314. //
  3315. // Create link for CLONE hive
  3316. //
  3317. RtlInitUnicodeString(&KeyName, KeyPath);
  3318. InitializeObjectAttributes(&Attributes,
  3319. &KeyName,
  3320. OBJ_CASE_INSENSITIVE,
  3321. NULL,
  3322. NULL);
  3323. Status = NtCreateKey(&LinkHandle,
  3324. KEY_CREATE_LINK,
  3325. &Attributes,
  3326. 0,
  3327. NULL,
  3328. REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
  3329. &Disposition);
  3330. if (!NT_SUCCESS(Status)) {
  3331. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpLinkKeyToHive: couldn't create %S\n", &KeyName));
  3332. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK," Status = %08lx\n",Status));
  3333. return(FALSE);
  3334. }
  3335. //
  3336. // Check to make sure that the key was created, not just opened. Since
  3337. // this key is always created volatile, it should never be present in
  3338. // the hive when we boot.
  3339. //
  3340. if (Disposition != REG_CREATED_NEW_KEY) {
  3341. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpLinkKeyToHive: %S already exists!\n", &KeyName));
  3342. NtClose(LinkHandle);
  3343. return(FALSE);
  3344. }
  3345. RtlInitUnicodeString(&LinkName, HivePath);
  3346. Status = NtSetValueKey(LinkHandle,
  3347. &CmSymbolicLinkValueName,
  3348. 0,
  3349. REG_LINK,
  3350. LinkName.Buffer,
  3351. LinkName.Length);
  3352. NtClose(LinkHandle);
  3353. if (!NT_SUCCESS(Status)) {
  3354. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CM: CmpLinkKeyToHive: couldn't create symbolic link for %S\n", HivePath));
  3355. return(FALSE);
  3356. }
  3357. return(TRUE);
  3358. }
  3359. VOID
  3360. CmpCreatePerfKeys(
  3361. VOID
  3362. )
  3363. /*++
  3364. Routine Description:
  3365. Creates predefined keys for the performance text to support old apps on 1.0a
  3366. Arguments:
  3367. None.
  3368. Return Value:
  3369. None.
  3370. --*/
  3371. {
  3372. HANDLE Perflib;
  3373. NTSTATUS Status;
  3374. WCHAR LanguageId[4];
  3375. OBJECT_ATTRIBUTES Attributes;
  3376. UNICODE_STRING String;
  3377. USHORT Language;
  3378. LONG i;
  3379. WCHAR c;
  3380. extern PWCHAR CmpRegistryPerflibString;
  3381. RtlInitUnicodeString(&String, CmpRegistryPerflibString);
  3382. InitializeObjectAttributes(&Attributes,
  3383. &String,
  3384. OBJ_CASE_INSENSITIVE,
  3385. NULL,
  3386. NULL);
  3387. Status = NtOpenKey(&Perflib,
  3388. KEY_WRITE,
  3389. &Attributes);
  3390. if (!NT_SUCCESS(Status)) {
  3391. return;
  3392. }
  3393. //
  3394. // Always create the predefined keys for the english language
  3395. //
  3396. CmpCreatePredefined(Perflib,
  3397. L"009",
  3398. HKEY_PERFORMANCE_TEXT);
  3399. //
  3400. // If the default language is not english, create a predefined key for
  3401. // that, too.
  3402. //
  3403. if (PsDefaultSystemLocaleId != 0x00000409) {
  3404. Language = LANGIDFROMLCID(PsDefaultUILanguageId) & 0xff;
  3405. LanguageId[3] = L'\0';
  3406. for (i=2;i>=0;i--) {
  3407. c = Language % 16;
  3408. if (c>9) {
  3409. LanguageId[i]= c+L'A'-10;
  3410. } else {
  3411. LanguageId[i]= c+L'0';
  3412. }
  3413. Language = Language >> 4;
  3414. }
  3415. CmpCreatePredefined(Perflib,
  3416. LanguageId,
  3417. HKEY_PERFORMANCE_NLSTEXT);
  3418. }
  3419. }
  3420. VOID
  3421. CmpCreatePredefined(
  3422. IN HANDLE Root,
  3423. IN PWSTR KeyName,
  3424. IN HANDLE PredefinedHandle
  3425. )
  3426. /*++
  3427. Routine Description:
  3428. Creates a special key that will always return the given predefined handle
  3429. instead of a real handle.
  3430. Arguments:
  3431. Root - supplies the handle the keyname is relative to
  3432. KeyName - supplies the name of the key.
  3433. PredefinedHandle - supplies the predefined handle to be returned when this
  3434. key is opened.
  3435. Return Value:
  3436. None.
  3437. --*/
  3438. {
  3439. OBJECT_ATTRIBUTES ObjectAttributes;
  3440. CM_PARSE_CONTEXT ParseContext;
  3441. NTSTATUS Status;
  3442. UNICODE_STRING Name;
  3443. HANDLE Handle;
  3444. ParseContext.Class.Length = 0;
  3445. ParseContext.Class.Buffer = NULL;
  3446. ParseContext.TitleIndex = 0;
  3447. ParseContext.CreateOptions = REG_OPTION_VOLATILE | REG_OPTION_PREDEF_HANDLE;
  3448. ParseContext.Disposition = 0;
  3449. ParseContext.CreateLink = FALSE;
  3450. ParseContext.PredefinedHandle = PredefinedHandle;
  3451. ParseContext.CreateOperation = TRUE;
  3452. ParseContext.OriginatingPoint = NULL;
  3453. RtlInitUnicodeString(&Name, KeyName);
  3454. InitializeObjectAttributes(&ObjectAttributes,
  3455. &Name,
  3456. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  3457. Root,
  3458. NULL);
  3459. Status = ObOpenObjectByName(&ObjectAttributes,
  3460. CmpKeyObjectType,
  3461. KernelMode,
  3462. NULL,
  3463. KEY_READ,
  3464. (PVOID)&ParseContext,
  3465. &Handle);
  3466. ASSERT(CmpMiniNTBoot || NT_SUCCESS(Status));
  3467. if (NT_SUCCESS(Status))
  3468. ZwClose(Handle);
  3469. }
  3470. BOOLEAN CmpSystemHiveConversionFailed = FALSE;
  3471. NTSTATUS
  3472. CmpSetupPrivateWrite(
  3473. PCMHIVE CmHive
  3474. )
  3475. /*++
  3476. Routine Description:
  3477. Converts the primary file to private write stream
  3478. Arguments:
  3479. CmHive - hive to convert, tipically SYSTEM
  3480. Return Value:
  3481. NONE; bugchecks if something wrong
  3482. --*/
  3483. {
  3484. ULONG FileOffset;
  3485. ULONG Data;
  3486. NTSTATUS Status;
  3487. PAGED_CODE()
  3488. //
  3489. // We need to issue a read from the file, to trigger the cache initialization
  3490. //
  3491. FileOffset = 0;
  3492. if ( ! (((PHHIVE)CmHive)->FileRead)(
  3493. (PHHIVE)CmHive,
  3494. HFILE_TYPE_PRIMARY,
  3495. &FileOffset,
  3496. (PVOID)&Data,
  3497. sizeof(ULONG)
  3498. )
  3499. )
  3500. {
  3501. return STATUS_REGISTRY_IO_FAILED;
  3502. }
  3503. //
  3504. // Aquire the file object for the primary; This should be called AFTER the
  3505. // cache has been initialized.
  3506. //
  3507. Status = CmpAquireFileObjectForFile(CmHive,CmHive->FileHandles[HFILE_TYPE_PRIMARY],&(CmHive->FileObject));
  3508. if( !NT_SUCCESS(Status) ) {
  3509. return Status;
  3510. }
  3511. //
  3512. // set the getCell and releaseCell routines to the right one(s)
  3513. //
  3514. CmHive->Hive.GetCellRoutine = HvpGetCellMapped;
  3515. CmHive->Hive.ReleaseCellRoutine = HvpReleaseCellMapped;
  3516. return STATUS_SUCCESS;
  3517. }
  3518. //
  3519. // This thread is used to load the machine hives in paralel
  3520. //
  3521. extern ULONG CmpCheckHiveIndex;
  3522. VOID
  3523. CmpLoadHiveThread(
  3524. IN PVOID StartContext
  3525. )
  3526. /*++
  3527. Routine Description:
  3528. Loads the hive at index StartContext in CmpMachineHiveList
  3529. Warning. We need to protect when enlisting the hives in CmpHiveListHead !!!
  3530. Arguments:
  3531. Return Value:
  3532. --*/
  3533. {
  3534. UCHAR FileBuffer[MAX_NAME];
  3535. UCHAR RegBuffer[MAX_NAME];
  3536. UNICODE_STRING TempName;
  3537. UNICODE_STRING FileName;
  3538. UNICODE_STRING RegName;
  3539. USHORT FileStart;
  3540. USHORT RegStart;
  3541. ULONG i;
  3542. PCMHIVE CmHive;
  3543. HANDLE PrimaryHandle;
  3544. HANDLE LogHandle;
  3545. ULONG PrimaryDisposition;
  3546. ULONG SecondaryDisposition;
  3547. ULONG Length;
  3548. NTSTATUS Status = STATUS_SUCCESS;
  3549. BOOLEAN RegistryLocked = TRUE;
  3550. PVOID ErrorParameters;
  3551. ULONG ErrorResponse;
  3552. ULONG ClusterSize;
  3553. ULONG LocalWorkerIncrement;
  3554. PAGED_CODE();
  3555. i = (ULONG)(ULONG_PTR)StartContext;
  3556. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"CmpLoadHiveThread %i ... starting\n",i));
  3557. ASSERT( CmpMachineHiveList[i].Name != NULL );
  3558. if( i == CmpCheckHiveIndex ) {
  3559. //
  3560. // we want to hold this thread until all the others finish, so we have a chance to debug it.
  3561. // last one that finishes will wake us
  3562. //
  3563. KeWaitForSingleObject( &CmpLoadWorkerDebugEvent,
  3564. Executive,
  3565. KernelMode,
  3566. FALSE,
  3567. NULL );
  3568. ASSERT( CmpLoadWorkerIncrement == (CM_NUMBER_OF_MACHINE_HIVES - 1) );
  3569. DbgBreakPoint();
  3570. }
  3571. //
  3572. // signal that we have started
  3573. //
  3574. CmpMachineHiveList[i].ThreadStarted = TRUE;
  3575. FileName.MaximumLength = MAX_NAME;
  3576. FileName.Length = 0;
  3577. FileName.Buffer = (PWSTR)&(FileBuffer[0]);
  3578. RegName.MaximumLength = MAX_NAME;
  3579. RegName.Length = 0;
  3580. RegName.Buffer = (PWSTR)&(RegBuffer[0]);
  3581. RtlInitUnicodeString(
  3582. &TempName,
  3583. INIT_SYSTEMROOT_HIVEPATH
  3584. );
  3585. RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
  3586. FileStart = FileName.Length;
  3587. RtlInitUnicodeString(
  3588. &TempName,
  3589. INIT_REGISTRY_MASTERPATH
  3590. );
  3591. RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
  3592. RegStart = RegName.Length;
  3593. //
  3594. // Compute the name of the file, and the name to link to in
  3595. // the registry.
  3596. //
  3597. // REGISTRY
  3598. RegName.Length = RegStart;
  3599. RtlInitUnicodeString(
  3600. &TempName,
  3601. CmpMachineHiveList[i].BaseName
  3602. );
  3603. RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
  3604. // REGISTRY\MACHINE or REGISTRY\USER
  3605. if (RegName.Buffer[ (RegName.Length / sizeof( WCHAR )) - 1 ] == '\\') {
  3606. RtlInitUnicodeString(
  3607. &TempName,
  3608. CmpMachineHiveList[i].Name
  3609. );
  3610. RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
  3611. }
  3612. // REGISTRY\[MACHINE|USER]\HIVE
  3613. // <sysroot>\config
  3614. RtlInitUnicodeString(
  3615. &TempName,
  3616. CmpMachineHiveList[i].Name
  3617. );
  3618. FileName.Length = FileStart;
  3619. RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
  3620. // <sysroot>\config\hive
  3621. if (CmpMachineHiveList[i].CmHive == NULL) {
  3622. //
  3623. // Hive has not been inited in any way.
  3624. //
  3625. CmpMachineHiveList[i].Allocate = TRUE;
  3626. Status = CmpInitHiveFromFile(&FileName,
  3627. CmpMachineHiveList[i].HHiveFlags,
  3628. &CmHive,
  3629. &(CmpMachineHiveList[i].Allocate),
  3630. &RegistryLocked,
  3631. CM_CHECK_REGISTRY_CHECK_CLEAN
  3632. );
  3633. if ( (!NT_SUCCESS(Status)) ||
  3634. (!CmpShareSystemHives && (CmHive->FileHandles[HFILE_TYPE_LOG] == NULL)) )
  3635. {
  3636. ErrorParameters = &FileName;
  3637. ExRaiseHardError(
  3638. STATUS_CANNOT_LOAD_REGISTRY_FILE,
  3639. 1,
  3640. 1,
  3641. (PULONG_PTR)&ErrorParameters,
  3642. OptionOk,
  3643. &ErrorResponse
  3644. );
  3645. }
  3646. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"CmpInitializeHiveList:\n"));
  3647. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"\tCmHive for '%ws' @", CmpMachineHiveList[i]));
  3648. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"%08lx", CmHive));
  3649. CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;
  3650. CmpMachineHiveList[i].CmHive2 = CmHive;
  3651. /*
  3652. //
  3653. // Dragos: This cannot be done here; we need to do it one step at the time back in CmpInitializeHiveList
  3654. //
  3655. //
  3656. // Link hive into master hive
  3657. //
  3658. Status = CmpLinkHiveToMaster(
  3659. &RegName,
  3660. NULL,
  3661. CmHive,
  3662. Allocate,
  3663. SecurityDescriptor
  3664. );
  3665. if ( Status != STATUS_SUCCESS)
  3666. {
  3667. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitializeHiveList: "));
  3668. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpLinkHiveToMaster failed\n"));
  3669. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\ti=%d s='%ws'\n", i, CmpMachineHiveList[i]));
  3670. CM_BUGCHECK(CONFIG_LIST_FAILED,BAD_CORE_HIVE,Status,i,&RegName);
  3671. }
  3672. CmpAddToHiveFileList(CmHive);
  3673. if (Allocate) {
  3674. //
  3675. // I suspect this is the problem.
  3676. //HvSyncHive((PHHIVE)CmHive);
  3677. //
  3678. }
  3679. */
  3680. } else {
  3681. CmHive = CmpMachineHiveList[i].CmHive;
  3682. if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) {
  3683. //
  3684. // CmHive already exists. It is not an entirely volatile
  3685. // hive (we do nothing for those.)
  3686. //
  3687. // First, open the files (Primary and Alternate) that
  3688. // back the hive. Stuff their handles into the CmHive
  3689. // object. Force the size of the files to match the
  3690. // in memory images. Call HvSyncHive to write changes
  3691. // out to disk.
  3692. //
  3693. BOOLEAN NoBufering = FALSE; // first try to open it cached;
  3694. retryNoBufering:
  3695. Status = CmpOpenHiveFiles(&FileName,
  3696. L".LOG",
  3697. &PrimaryHandle,
  3698. &LogHandle,
  3699. &PrimaryDisposition,
  3700. &SecondaryDisposition,
  3701. TRUE,
  3702. TRUE,
  3703. NoBufering,
  3704. &ClusterSize);
  3705. if ( ( ! NT_SUCCESS(Status)) ||
  3706. (LogHandle == NULL) )
  3707. {
  3708. fatal:
  3709. ErrorParameters = &FileName;
  3710. ExRaiseHardError(
  3711. STATUS_CANNOT_LOAD_REGISTRY_FILE,
  3712. 1,
  3713. 1,
  3714. (PULONG_PTR)&ErrorParameters,
  3715. OptionOk,
  3716. &ErrorResponse
  3717. );
  3718. //
  3719. // WARNNOTE
  3720. // We've just told the user that something essential,
  3721. // like the SYSTEM hive, is hosed. Don't try to run,
  3722. // we just risk destroying user data. Punt.
  3723. //
  3724. CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_HIVE_LIST,0,i,Status);
  3725. }
  3726. CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
  3727. CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
  3728. if( NoBufering == FALSE ) {
  3729. //
  3730. // intitialize cache and mark the stream as PRIVATE_WRITE;
  3731. // next flush will do the actual conversion
  3732. //
  3733. Status = CmpSetupPrivateWrite(CmHive);
  3734. }
  3735. if( !NT_SUCCESS(Status) ) {
  3736. if( (NoBufering == TRUE) || (Status != STATUS_RETRY) ) {
  3737. //
  3738. // we have tried both ways and it didn't work; bad luck
  3739. //
  3740. goto fatal;
  3741. }
  3742. #ifndef _CM_LDR_
  3743. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Failed to convert SYSTEM hive to mapped (0x%lx) ... loading it in paged pool\n",Status);
  3744. #endif //_CM_LDR_
  3745. //
  3746. // close handle and make another attempt to open them without buffering
  3747. //
  3748. CmpTrackHiveClose = TRUE;
  3749. ZwClose(PrimaryHandle);
  3750. CmpTrackHiveClose = FALSE;
  3751. ZwClose(LogHandle);
  3752. NoBufering = TRUE;
  3753. goto retryNoBufering;
  3754. }
  3755. //
  3756. // now that we successfully opened the hive files, clear off the lazy flush flag
  3757. //
  3758. ASSERT( CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH );
  3759. CmHive->Hive.HiveFlags &= (~HIVE_NOLAZYFLUSH);
  3760. Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
  3761. //
  3762. // When an in-memory hive is opened with no backing
  3763. // file, ClusterSize is assumed to be 1. When the file
  3764. // is opened later (for the SYSTEM hive) we need
  3765. // to update this field in the hive if we are
  3766. // booting from media where the cluster size > 1
  3767. //
  3768. if (CmHive->Hive.Cluster != ClusterSize) {
  3769. //
  3770. // The cluster size is different than previous assumed.
  3771. // Since a cluster in the dirty vector must be either
  3772. // completely dirty or completely clean, go through the
  3773. // dirty vector and mark all clusters that contain a dirty
  3774. // logical sector as completely dirty.
  3775. //
  3776. PRTL_BITMAP BitMap;
  3777. ULONG Index;
  3778. BitMap = &(CmHive->Hive.DirtyVector);
  3779. for (Index = 0;
  3780. Index < CmHive->Hive.DirtyVector.SizeOfBitMap;
  3781. Index += ClusterSize)
  3782. {
  3783. if (!RtlAreBitsClear (BitMap, Index, ClusterSize)) {
  3784. RtlSetBits (BitMap, Index, ClusterSize);
  3785. }
  3786. }
  3787. //
  3788. // Update DirtyCount and Cluster
  3789. //
  3790. CmHive->Hive.DirtyCount = RtlNumberOfSetBits(&CmHive->Hive.DirtyVector);
  3791. CmHive->Hive.Cluster = ClusterSize;
  3792. }
  3793. if (!CmpFileSetSize(
  3794. (PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length,Length)
  3795. )
  3796. {
  3797. //
  3798. // WARNNOTE
  3799. // Data written into the system hive since boot
  3800. // cannot be written out, punt.
  3801. //
  3802. CmpCannotWriteConfiguration = TRUE;
  3803. }
  3804. ASSERT(FIELD_OFFSET(CMHIVE, Hive) == 0);
  3805. if( CmHive->Hive.BaseBlock->BootRecover != 0 ) {
  3806. //
  3807. // boot loader recovered the hive; we need to flush it all to the disk
  3808. // mark everything dirty; the next flush will do take care of the rest
  3809. //
  3810. PRTL_BITMAP BitMap;
  3811. BitMap = &(CmHive->Hive.DirtyVector);
  3812. RtlSetAllBits(BitMap);
  3813. CmHive->Hive.DirtyCount = BitMap->SizeOfBitMap;
  3814. //
  3815. // we only need to flush the hive when the loader has recovered it
  3816. //
  3817. HvSyncHive((PHHIVE)CmHive);
  3818. }
  3819. CmpMachineHiveList[i].CmHive2 = CmHive;
  3820. ASSERT( CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2 );
  3821. /*
  3822. Cannot do that here as it requires the registry lock
  3823. CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive);
  3824. */
  3825. if( CmpCannotWriteConfiguration ) {
  3826. //
  3827. // The system disk is full; Give user a chance to log-on and make room
  3828. //
  3829. CmpDiskFullWarning();
  3830. }
  3831. //
  3832. // copy the full file name for the conversion worker thread
  3833. //
  3834. SystemHiveFullPathName.MaximumLength = MAX_NAME;
  3835. SystemHiveFullPathName.Length = 0;
  3836. SystemHiveFullPathName.Buffer = (PWSTR)&(SystemHiveFullPathBuffer[0]);
  3837. RtlAppendStringToString((PSTRING)&SystemHiveFullPathName, (PSTRING)&FileName);
  3838. } else if (CmpMiniNTBoot) {
  3839. //
  3840. // copy the full file name for the conversion worker thread
  3841. //
  3842. SystemHiveFullPathName.MaximumLength = MAX_NAME;
  3843. SystemHiveFullPathName.Length = 0;
  3844. SystemHiveFullPathName.Buffer = (PWSTR)&(SystemHiveFullPathBuffer[0]);
  3845. RtlAppendStringToString((PSTRING)&SystemHiveFullPathName, (PSTRING)&FileName);
  3846. }
  3847. if(i == SYSTEM_HIVE_INDEX) {
  3848. //
  3849. // marks the System\Select!Current value dirty so we preserve what was set by the loader.
  3850. //
  3851. CmpMarkCurrentValueDirty((PHHIVE)CmHive,CmHive->Hive.BaseBlock->RootCell);
  3852. }
  3853. }
  3854. CmpMachineHiveList[i].ThreadFinished = TRUE;
  3855. LocalWorkerIncrement = InterlockedIncrement (&CmpLoadWorkerIncrement);
  3856. if ( LocalWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES ) {
  3857. //
  3858. // this was the last thread (the lazyest); signal the main thread
  3859. //
  3860. KeSetEvent (&CmpLoadWorkerEvent, 0, FALSE);
  3861. }
  3862. if ( (LocalWorkerIncrement == (CM_NUMBER_OF_MACHINE_HIVES -1)) && // there is one more thread
  3863. (CmpCheckHiveIndex < CM_NUMBER_OF_MACHINE_HIVES ) // which is waiting to be debugged
  3864. ) {
  3865. //
  3866. // wake up the thread to be debugged
  3867. //
  3868. KeSetEvent (&CmpLoadWorkerDebugEvent, 0, FALSE);
  3869. }
  3870. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"CmpLoadHiveThread %i ... terminating\n",i));
  3871. PsTerminateSystemThread(Status);
  3872. }
  3873. NTSTATUS
  3874. CmpSetNetworkValue(
  3875. IN PNETWORK_LOADER_BLOCK NetworkLoaderBlock
  3876. )
  3877. /*++
  3878. Routine Description:
  3879. This function will save the information in the Network Loader
  3880. Block to the registry.
  3881. Arguments:
  3882. NetworkLoaderBlock - Supplies a pointer to the network loader block
  3883. that was created by the OS Loader.
  3884. Return Value:
  3885. NTSTATUS code.
  3886. --*/
  3887. {
  3888. NTSTATUS status;
  3889. OBJECT_ATTRIBUTES objectAttributes;
  3890. UNICODE_STRING string;
  3891. HANDLE handle;
  3892. ULONG disposition;
  3893. ASSERT( NetworkLoaderBlock != NULL );
  3894. ASSERT( NetworkLoaderBlock->DHCPServerACKLength > 0 );
  3895. RtlInitUnicodeString( &string, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\PXE" );
  3896. InitializeObjectAttributes(
  3897. &objectAttributes,
  3898. &string,
  3899. OBJ_CASE_INSENSITIVE,
  3900. NULL,
  3901. NULL
  3902. );
  3903. status = NtCreateKey(&handle,
  3904. KEY_ALL_ACCESS,
  3905. &objectAttributes,
  3906. 0,
  3907. (PUNICODE_STRING)NULL,
  3908. 0,
  3909. &disposition
  3910. );
  3911. if ( !NT_SUCCESS(status) ) {
  3912. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL, "CmpSetNetworkValue: Unable to open PXE key: %x\n", status ));
  3913. goto Error;
  3914. }
  3915. RtlInitUnicodeString( &string, L"DHCPServerACK" );
  3916. status = NtSetValueKey(handle,
  3917. &string,
  3918. 0,
  3919. REG_BINARY,
  3920. NetworkLoaderBlock->DHCPServerACK,
  3921. NetworkLoaderBlock->DHCPServerACKLength
  3922. );
  3923. if ( !NT_SUCCESS(status) ) {
  3924. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL, "CmpSetNetworkValue: Unable to set DHCPServerACK key: %x\n", status ));
  3925. goto Error;
  3926. }
  3927. RtlInitUnicodeString( &string, L"BootServerReply" );
  3928. status = NtSetValueKey(handle,
  3929. &string,
  3930. 0,
  3931. REG_BINARY,
  3932. NetworkLoaderBlock->BootServerReplyPacket,
  3933. NetworkLoaderBlock->BootServerReplyPacketLength
  3934. );
  3935. if ( !NT_SUCCESS(status) ) {
  3936. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL, "CmpSetNetworkValue: Unable to set BootServerReplyPacket key: %x\n", status ));
  3937. goto Error;
  3938. }
  3939. status = STATUS_SUCCESS;
  3940. Cleanup:
  3941. NtClose( handle );
  3942. return status;
  3943. Error:
  3944. goto Cleanup;
  3945. }
  3946. NTSTATUS
  3947. CmpSetSystemValues(
  3948. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  3949. )
  3950. /*++
  3951. Routine Description:
  3952. This function will save the system start information to
  3953. the registry.
  3954. Arguments:
  3955. LoaderBlock - Supplies a pointer to the loader block.
  3956. Return Value:
  3957. NTSTATUS code.
  3958. --*/
  3959. {
  3960. NTSTATUS status;
  3961. OBJECT_ATTRIBUTES objectAttributes;
  3962. UNICODE_STRING string;
  3963. UNICODE_STRING value;
  3964. HANDLE handle;
  3965. ASSERT( LoaderBlock != NULL );
  3966. value.Buffer = NULL;
  3967. //
  3968. // Open the control key
  3969. //
  3970. RtlInitUnicodeString( &string, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control" );
  3971. InitializeObjectAttributes(
  3972. &objectAttributes,
  3973. &string,
  3974. OBJ_CASE_INSENSITIVE,
  3975. NULL,
  3976. NULL
  3977. );
  3978. status = NtOpenKey(
  3979. &handle,
  3980. KEY_ALL_ACCESS,
  3981. &objectAttributes
  3982. );
  3983. if ( !NT_SUCCESS(status) ) {
  3984. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpSetSystemValues: Unable to Open Control Key: %x\n", status ));
  3985. goto Error;
  3986. }
  3987. //
  3988. // Set the System start options key
  3989. //
  3990. RtlInitUnicodeString( &string, L"SystemStartOptions" );
  3991. status = NtSetValueKey (
  3992. handle,
  3993. &string,
  3994. 0,
  3995. REG_SZ,
  3996. CmpLoadOptions.Buffer,
  3997. CmpLoadOptions.Length
  3998. );
  3999. if ( !NT_SUCCESS(status) ) {
  4000. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpSetSystemValue: Unable to set SystemStartOptions key: %x\n", status ));
  4001. goto Error;
  4002. }
  4003. //
  4004. // Set the System Boot Device
  4005. //
  4006. RtlInitUnicodeString( &string, L"SystemBootDevice" );
  4007. RtlCreateUnicodeStringFromAsciiz( &value, LoaderBlock->ArcBootDeviceName );
  4008. status = NtSetValueKey(handle,
  4009. &string,
  4010. 0,
  4011. REG_SZ,
  4012. value.Buffer,
  4013. value.Length + sizeof(WCHAR)
  4014. );
  4015. if ( !NT_SUCCESS(status) ) {
  4016. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpSetSystemValue: Unable to set SystemBootDevice key: %x\n", status ));
  4017. goto Error;
  4018. }
  4019. status = STATUS_SUCCESS;
  4020. Cleanup:
  4021. if ( value.Buffer ) {
  4022. RtlFreeUnicodeString(&value);
  4023. }
  4024. NtClose( handle );
  4025. return status;
  4026. Error:
  4027. goto Cleanup;
  4028. }
  4029. VOID
  4030. CmpMarkCurrentValueDirty(
  4031. IN PHHIVE SystemHive,
  4032. IN HCELL_INDEX RootCell
  4033. )
  4034. {
  4035. PCM_KEY_NODE Node;
  4036. HCELL_INDEX Select;
  4037. UNICODE_STRING Name;
  4038. HCELL_INDEX ValueCell;
  4039. PAGED_CODE();
  4040. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  4041. //
  4042. // Find \SYSTEM\SELECT node.
  4043. //
  4044. Node = (PCM_KEY_NODE)HvGetCell(SystemHive,RootCell);
  4045. if( Node == NULL ) {
  4046. //
  4047. // we couldn't map a view for the bin containing this cell
  4048. //
  4049. return;
  4050. }
  4051. HvReleaseCell(SystemHive,RootCell);
  4052. RtlInitUnicodeString(&Name, L"select");
  4053. Select = CmpFindSubKeyByName(SystemHive,
  4054. Node,
  4055. &Name);
  4056. if (Select == HCELL_NIL) {
  4057. return;
  4058. }
  4059. Node = (PCM_KEY_NODE)HvGetCell(SystemHive,Select);
  4060. if( Node == NULL ) {
  4061. //
  4062. // we couldn't map a view for the bin containing this cell
  4063. //
  4064. return;
  4065. }
  4066. HvReleaseCell(SystemHive,Select);
  4067. RtlInitUnicodeString(&Name, L"Current");
  4068. ValueCell = CmpFindValueByName(SystemHive,
  4069. Node,
  4070. &Name);
  4071. if (ValueCell != HCELL_NIL) {
  4072. HvMarkCellDirty(SystemHive, ValueCell);
  4073. }
  4074. }