Source code of Windows XP (NT5)
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.

1922 lines
61 KiB

  1. /*++
  2. File Description:
  3. This file contains the driver functions to modify the
  4. domain SID on a machine.
  5. Author:
  6. Matt Holle (matth) Oct 1997
  7. --*/
  8. //
  9. // System header files
  10. //
  11. #include <nt.h>
  12. //
  13. // Disable the DbgPrint for non-debug builds
  14. //
  15. #ifndef DBG
  16. #define _DBGNT_
  17. #endif
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <ntverp.h>
  21. #include <wtypes.h>
  22. #include <ntddksec.h>
  23. #ifdef IA64
  24. #include <winioctl.h>
  25. #include <efisbent.h>
  26. #if defined(EFI_NVRAM_ENABLED)
  27. #include <efi.h>
  28. #include <efiapi.h>
  29. #endif
  30. #endif
  31. //
  32. // CRT header files
  33. //
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. //
  37. // Private header files
  38. //
  39. #include "setupcl.h"
  40. #include "msg.h"
  41. #ifdef IA64
  42. // Seed for GUID generator function:
  43. //
  44. // This is initialized first at the beginning of main() with the NtQuerySystemTime()
  45. // and then is updated every time the CreateNewGuid function is called.
  46. // We use the system time at the time CreateNewGuid is called for another part of the GUID.
  47. // This is done so that we achieve some variability accross machines, as the time delta between
  48. // calls to NtQuerySystemTime() should be somewhat different accross machines and invocations of
  49. // this program.
  50. //
  51. ULONG RandomSeed;
  52. #endif
  53. // Start time for setupcl. This is used so we can display a UI if setupcl takes longer than 15 seconds to
  54. // complete. Note that the checks for time only happen in the recursive function calls so if a step is added
  55. // to setupcl that takes a considerable amount of time DisplayUI() should be called as part of that step as well.
  56. //
  57. LARGE_INTEGER StartTime;
  58. LARGE_INTEGER CurrentTime;
  59. LARGE_INTEGER LastDotTime; // For putting up dots every few seconds.
  60. BOOL bDisplayUI = FALSE; // Initially don't display the UI.
  61. NTSTATUS
  62. ProcessHives(
  63. VOID
  64. );
  65. NTSTATUS
  66. FinalHiveCleanup(
  67. VOID
  68. );
  69. NTSTATUS
  70. ProcessRepairHives(
  71. VOID
  72. );
  73. NTSTATUS
  74. RetrieveOldSid(
  75. VOID
  76. );
  77. NTSTATUS
  78. GenerateUniqueSid(
  79. IN DWORD Seed
  80. );
  81. NTSTATUS
  82. ProcessHives(
  83. VOID
  84. )
  85. /*++
  86. ===============================================================================
  87. Routine Description:
  88. This function check keys (and all subkeys) for:
  89. - keys with the old SID name
  90. - value keys with the old SID value
  91. Arguments:
  92. None.
  93. Return Value:
  94. NTSTATUS.
  95. ===============================================================================
  96. --*/
  97. {
  98. ULONG i;
  99. NTSTATUS Status;
  100. PWSTR KeysToWhack[] = {
  101. //
  102. // SAM hive...
  103. //
  104. L"\\REGISTRY\\MACHINE\\SAM\\SAM",
  105. //
  106. // Security hive...
  107. //
  108. L"\\REGISTRY\\MACHINE\\SECURITY",
  109. //
  110. // Software hive...
  111. //
  112. L"\\REGISTRY\\MACHINE\\SOFTWARE",
  113. //
  114. // System hive...
  115. //
  116. L"\\REGISTRY\\MACHINE\\SYSTEM",
  117. };
  118. LARGE_INTEGER Start_Time, End_Time;
  119. //
  120. // Record our start time.
  121. //
  122. NtQuerySystemTime( &Start_Time );
  123. for( i = 0; i < sizeof(KeysToWhack) / sizeof(PWSTR); i++ ) {
  124. DbgPrint( "\nSETUPCL: ProcessHives - About to process %ws\n", KeysToWhack[i] );
  125. Status = SiftKey( KeysToWhack[i] );
  126. TEST_STATUS( "SETUPCL: ProcessHives - Failed to process key..." );
  127. }
  128. //
  129. // Record our end time.
  130. //
  131. NtQuerySystemTime( &End_Time );
  132. //
  133. // Record our execution time.
  134. //
  135. End_Time.QuadPart = End_Time.QuadPart - Start_Time.QuadPart;
  136. #if 0
  137. Status = SetKey( TEXT(REG_SYSTEM_SETUP),
  138. TEXT("SetupCL_Run_Time"),
  139. (PUCHAR)&End_Time.LowPart,
  140. sizeof( DWORD ),
  141. REG_DWORD );
  142. #endif
  143. return( Status );
  144. }
  145. NTSTATUS
  146. FinalHiveCleanup(
  147. VOID
  148. )
  149. /*++
  150. ===============================================================================
  151. Routine Description:
  152. This function will go load each user-specific hive on the machine and
  153. propogate the new SID into it.
  154. Arguments:
  155. None.
  156. Return Value:
  157. NTSTATUS.
  158. ===============================================================================
  159. --*/
  160. {
  161. NTSTATUS Status = STATUS_SUCCESS;
  162. OBJECT_ATTRIBUTES Obja;
  163. UNICODE_STRING UnicodeString,
  164. UnicodeValue;
  165. HANDLE hKey, hKeyChild;
  166. ULONG ResultLength,
  167. KeyValueLength,
  168. Index,
  169. LengthNeeded;
  170. PKEY_BASIC_INFORMATION KeyInfo;
  171. WCHAR KeyBuffer[BASIC_INFO_BUFFER_SIZE];
  172. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo = NULL;
  173. //
  174. // ========================
  175. // User Profile Hives
  176. // ========================
  177. //
  178. DbgPrint( "\nAbout to operate on user-specific profile hives.\n" );
  179. //
  180. // We need to go check the user profile hives out on the disk.
  181. // If we find any, we need to change his ACLs to reflect the new
  182. // SID.
  183. //
  184. //
  185. // Open the PROFILELIST key.
  186. //
  187. INIT_OBJA( &Obja, &UnicodeString, TEXT( REG_SOFTWARE_PROFILELIST ) );
  188. Status = NtOpenKey( &hKey,
  189. KEY_ALL_ACCESS,
  190. &Obja );
  191. TEST_STATUS( "SETUPCL: FinalHiveCleanup - Failed to open PROFILELIST key." );
  192. KeyInfo = (PKEY_BASIC_INFORMATION)KeyBuffer;
  193. //
  194. // Now enumerate all his subkeys and see if any of them have a
  195. // ProfileImagePath key.
  196. //
  197. for( Index = 0; ; Index++ ) {
  198. // Local variable.
  199. //
  200. DWORD dwPass;
  201. PWCHAR lpszHiveName[] = {
  202. L"\\NTUSER.DAT",
  203. L"\\Local Settings\\Application Data\\Microsoft\\Windows\\UsrClass.dat"
  204. };
  205. Status = NtEnumerateKey( hKey,
  206. Index,
  207. KeyBasicInformation,
  208. KeyInfo,
  209. sizeof(KeyBuffer),
  210. &ResultLength );
  211. if(!NT_SUCCESS(Status)) {
  212. if(Status == STATUS_NO_MORE_ENTRIES) {
  213. Status = STATUS_SUCCESS;
  214. } else {
  215. TEST_STATUS( "SETUPCL: FinalHiveCleanup - Failure during enumeration of subkeys." );
  216. }
  217. break;
  218. }
  219. //
  220. // Zero-terminate the subkey name just in case.
  221. //
  222. KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0;
  223. DbgPrint( "SETUPCL: FinalHiveCleanup - enumerated %ws\n", KeyInfo->Name );
  224. //
  225. // Generate a handle for this child key and open him too.
  226. //
  227. INIT_OBJA( &Obja, &UnicodeString, KeyInfo->Name );
  228. Obja.RootDirectory = hKey;
  229. Status = NtOpenKey( &hKeyChild,
  230. KEY_ALL_ACCESS,
  231. &Obja );
  232. //
  233. // ISSUE-2002/02/26-brucegr,jcohen - If NtOpenKey fails, hKey is leaked
  234. //
  235. TEST_STATUS_RETURN( "SETUPCL: FinalHiveCleanup - Failed to open child key." );
  236. //
  237. // Now get the ProfileImagePath value.
  238. //
  239. RtlInitUnicodeString( &UnicodeString, TEXT( PROFILEIMAGEPATH ) );
  240. //
  241. // How big of a buffer do we need?
  242. //
  243. Status = NtQueryValueKey( hKeyChild,
  244. &UnicodeString,
  245. KeyValuePartialInformation,
  246. NULL,
  247. 0,
  248. &LengthNeeded );
  249. //
  250. // ISSUE-2002/02/26-brucegr,jcohen - Check for STATUS_SUCCESS, not assume success on STATUS_OBJECT_NAME_NOT_FOUND
  251. //
  252. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  253. DbgPrint( "SETUPCL: FinalHiveCleanup - Unable to query key %ws size. Error (%lx)\n", TEXT( PROFILEIMAGEPATH ), Status );
  254. } else {
  255. Status = STATUS_SUCCESS;
  256. }
  257. //
  258. // Allocate a block.
  259. //
  260. if( NT_SUCCESS( Status ) ) {
  261. if( KeyValueInfo ) {
  262. RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
  263. KeyValueInfo = NULL;
  264. }
  265. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
  266. 0,
  267. LengthNeeded + 0x10 );
  268. if( KeyValueInfo == NULL ) {
  269. DbgPrint( "SETUPCL: FinalHiveCleanup - Unable to allocate buffer\n" );
  270. Status = STATUS_NO_MEMORY;
  271. }
  272. }
  273. //
  274. // Get the data.
  275. //
  276. if( NT_SUCCESS( Status ) ) {
  277. Status = NtQueryValueKey( hKeyChild,
  278. &UnicodeString,
  279. KeyValuePartialInformation,
  280. (PVOID)KeyValueInfo,
  281. LengthNeeded,
  282. &KeyValueLength );
  283. if( !NT_SUCCESS( Status ) ) {
  284. DbgPrint( "SETUPCL: FinalHiveCleanup - Failed to query key %ws (%lx)\n", TEXT( PROFILEIMAGEPATH ), Status );
  285. }
  286. }
  287. NtClose( hKeyChild );
  288. //
  289. // Do two passes. First pass will be for the NTUSER.DAT hive and the second will be for
  290. // UsrClass.dat hive.
  291. //
  292. for ( dwPass = 0; dwPass < AS(lpszHiveName); dwPass++ ) {
  293. if( NT_SUCCESS( Status ) ) {
  294. PWCHAR TmpChar;
  295. ULONG i;
  296. memset( TmpBuffer, 0, sizeof(TmpBuffer) );
  297. wcsncpy( TmpBuffer, (PWCHAR)&KeyValueInfo->Data, AS(TmpBuffer) - 1);
  298. //
  299. // We've got the path to the profile hive, but it will contain
  300. // an environment variable. Expand the variable.
  301. //
  302. DbgPrint( "SETUPCL: FinalHiveCleanup - Before the expand, I think his ProfileImagePath is: %ws\n", TmpBuffer );
  303. RtlInitUnicodeString( &UnicodeString, TmpBuffer );
  304. UnicodeValue.Length = 0;
  305. UnicodeValue.MaximumLength = MAX_PATH * sizeof(WCHAR);
  306. UnicodeValue.Buffer = (PWSTR)RtlAllocateHeap( RtlProcessHeap(), 0, UnicodeValue.MaximumLength );
  307. //
  308. // Prefix Bug # 111373.
  309. //
  310. if ( UnicodeValue.Buffer )
  311. {
  312. RtlZeroMemory( UnicodeValue.Buffer, UnicodeValue.MaximumLength );
  313. Status = RtlExpandEnvironmentStrings_U( NULL, &UnicodeString, &UnicodeValue, NULL );
  314. //
  315. // RtlExpandEnvironmentStrings_U has given us a path, but
  316. // it will contain a drive letter. We need an NT path.
  317. // Go convert it.
  318. //
  319. if( NT_SUCCESS( Status ) &&
  320. ( (UnicodeValue.Length + (wcslen(lpszHiveName[dwPass]) * sizeof(WCHAR))) < sizeof(TmpBuffer) ) )
  321. {
  322. WCHAR DriveLetter[3];
  323. WCHAR NTPath[MAX_PATH] = {0};
  324. //
  325. // TmpBuffer will contain the complete path, except
  326. // he's got the drive letter.
  327. //
  328. RtlCopyMemory( TmpBuffer, UnicodeValue.Buffer, UnicodeValue.Length );
  329. TmpBuffer[(UnicodeValue.Length / sizeof(WCHAR))] = 0;
  330. wcscat( TmpBuffer, lpszHiveName[dwPass] );
  331. DbgPrint( "SETUPCL: FinalHiveCleanup - I think the dospath to his ProfileImagePath is: %ws\n", TmpBuffer );
  332. DriveLetter[0] = TmpBuffer[0];
  333. DriveLetter[1] = L':';
  334. DriveLetter[2] = 0;
  335. //
  336. // Get the symbolic link from the drive letter.
  337. //
  338. Status = DriveLetterToNTPath( DriveLetter[0], NTPath, AS(NTPath) );
  339. if( NT_SUCCESS( Status ) ) {
  340. //
  341. // Translation was successful. Insert the ntpath into our
  342. // path to the profile.
  343. //
  344. Status = StringSwitchString( TmpBuffer, AS(TmpBuffer), DriveLetter, NTPath );
  345. } else {
  346. DbgPrint( "SETUPCL: FinalHiveCleanup - We failed our call to DriveLetterToNTPath (%lx)\n", Status );
  347. }
  348. DbgPrint( "SETUPCL: FinalHiveCleanup - After the expand, I think his ProfileImagePath is: %ws\n", TmpBuffer );
  349. } else {
  350. DbgPrint( "SETUPCL: FinalHiveCleanup - We failed our call to RtlExpandEnvironmentStrings_U (%lx)\n", Status );
  351. }
  352. RtlFreeHeap( RtlProcessHeap(),
  353. 0,
  354. UnicodeValue.Buffer );
  355. }
  356. //
  357. // Attempt to load the hive, open his root key, then
  358. // go swap ACLs on all the subkeys.
  359. //
  360. Status = LoadUnloadHive( TEXT( TMP_HIVE_NAME ),
  361. TmpBuffer );
  362. if( NT_SUCCESS( Status ) ) {
  363. //
  364. // Let's go search for any instance of the SID in our
  365. // newly loaded hive.
  366. //
  367. Status = SiftKey( TEXT( TMP_HIVE_NAME ) );
  368. TEST_STATUS( "SETUPCL: FinalHiveCleanup - Failed to push new sid into user's hive." );
  369. #if 0
  370. //
  371. // Move call to SetKeySecurityRecursive into
  372. // SiftKey so that implicitly fixup ACLs too.
  373. //
  374. //
  375. // Open the root of our newly loaded hive.
  376. //
  377. INIT_OBJA( &Obja, &UnicodeString, TEXT( TMP_HIVE_NAME ) );
  378. Status = NtOpenKey( &hKeyChild,
  379. KEY_ALL_ACCESS,
  380. &Obja );
  381. //
  382. // Now go attempt to whack the ACLs on this, and
  383. // all subkeys.
  384. //
  385. if( NT_SUCCESS( Status ) ) {
  386. SetKeySecurityRecursive( hKeyChild );
  387. NtClose( hKeyChild );
  388. } else {
  389. DbgPrint( "SETUPCL: FinalHiveCleanup - Failed open of TmpHive root.\n" );
  390. }
  391. #endif
  392. LoadUnloadHive( TEXT( TMP_HIVE_NAME ),
  393. NULL );
  394. } else {
  395. DbgPrint( "SETUPCL: FinalHiveCleanup - Failed load of TmpHive.\n" );
  396. }
  397. }
  398. }
  399. }
  400. NtClose( hKey );
  401. //
  402. // ========================
  403. // \REGISTRY\MACHINE\SYSTEM\CURRENTCONTROLSET\CONTROL\REGISTRYSIZELIMIT
  404. // ========================
  405. //
  406. DbgPrint( "\nAbout to operate on SYSTEM\\CURRENTCONTROLSET\\CONTROL\\REGISTRYSIZELIMIT.\n" );
  407. //
  408. // sysprep bumped the registry limit up by 4Mb. We need to lower it
  409. // back down.
  410. //
  411. INIT_OBJA( &Obja,
  412. &UnicodeString,
  413. TEXT(REG_SYSTEM_CONTROL) );
  414. Status = NtOpenKey( &hKey,
  415. KEY_ALL_ACCESS,
  416. &Obja );
  417. TEST_STATUS( "SETUPCL: ProcessSYSTEMHive - Failed to open Control key!" );
  418. //
  419. // ISSUE-2002/02/26-brucegr,jcohen - Shouldn't try to query value if NtOpenKey fails!
  420. //
  421. //
  422. // Get the data out of this key.
  423. //
  424. RtlInitUnicodeString(&UnicodeString, TEXT(REG_SIZE_LIMIT) );
  425. //
  426. // How big of a buffer do we need?
  427. //
  428. Status = NtQueryValueKey( hKey,
  429. &UnicodeString,
  430. KeyValuePartialInformation,
  431. NULL,
  432. 0,
  433. &LengthNeeded );
  434. //
  435. // ISSUE-2002/02/26-brucegr,jcohen - Check for STATUS_SUCCESS, not assume success on STATUS_OBJECT_NAME_NOT_FOUND
  436. //
  437. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  438. DbgPrint( "SETUPCL: FinalHiveCleanup - Unable to query key %ws size. Error (%lx)\n", TEXT(REG_SIZE_LIMIT), Status );
  439. } else {
  440. Status = STATUS_SUCCESS;
  441. }
  442. //
  443. // Allocate a block.
  444. //
  445. if( NT_SUCCESS( Status ) ) {
  446. if( KeyValueInfo ) {
  447. RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
  448. KeyValueInfo = NULL;
  449. }
  450. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
  451. 0,
  452. LengthNeeded + 0x10 );
  453. if( KeyValueInfo == NULL ) {
  454. DbgPrint( "SETUPCL: FinalHiveCleanup - Unable to allocate buffer\n" );
  455. Status = STATUS_NO_MEMORY;
  456. }
  457. }
  458. //
  459. // Get the data.
  460. //
  461. if( NT_SUCCESS( Status ) ) {
  462. Status = NtQueryValueKey( hKey,
  463. &UnicodeString,
  464. KeyValuePartialInformation,
  465. (PVOID)KeyValueInfo,
  466. LengthNeeded,
  467. &KeyValueLength );
  468. if( !NT_SUCCESS( Status ) ) {
  469. DbgPrint( "SETUPCL: FinalHiveCleanup - Failed to query key %ws (%lx)\n", TEXT(REG_SIZE_LIMIT), Status );
  470. }
  471. else{
  472. Index = *(PDWORD)(&KeyValueInfo->Data);
  473. Index = Index - REGISTRY_QUOTA_BUMP; //Bring it back to original value
  474. //
  475. // Set him.
  476. //
  477. Status = SetKey( TEXT(REG_SYSTEM_CONTROL),
  478. TEXT(REG_SIZE_LIMIT),
  479. (PUCHAR)&Index,
  480. sizeof( DWORD ),
  481. REG_DWORD );
  482. DbgPrint("SETUPCL: ProcessSYSTEMHive - Size allocated = %lx\n",Index);
  483. TEST_STATUS( "SETUPCL: ProcessSYSTEMHive - Failed to update SYSTEM\\CURRENTCONTROLSET\\CONTROL\\REGISTRYSIZELIMIT key." );
  484. }
  485. }
  486. NtClose( hKey );
  487. //
  488. // ========================
  489. // \REGISTRY\MACHINE\SYSTEM\CURRENTCONTROLSET\Control\Session Manager\SetupExecute
  490. // ========================
  491. //
  492. DbgPrint( "\nAbout to operate on SYSTEM\\CURRENTCONTROLSET\\CONTROL\\SESSION MANAGER\\SETUPEXECUTE key.\n" );
  493. //
  494. // Open the Session manager key.
  495. //
  496. INIT_OBJA( &Obja,
  497. &UnicodeString,
  498. TEXT(REG_SYSTEM_SESSIONMANAGER) );
  499. Status = NtOpenKey( &hKey,
  500. KEY_ALL_ACCESS,
  501. &Obja );
  502. TEST_STATUS_RETURN( "SETUPCL: ProcessSYSTEMHive - Failed to open Session Manager key!" );
  503. //
  504. // Now delete the SetupExecute Key.
  505. //
  506. RtlInitUnicodeString(&UnicodeString, TEXT(EXECUTE) );
  507. Status = NtDeleteValueKey( hKey, &UnicodeString );
  508. NtClose( hKey );
  509. TEST_STATUS( "SETUPCL: ProcessSYSTEMHive - Failed to update SYSTEM\\CURRENTCONTROLSET\\CONTROL\\SESSION MANAGER\\SETUPEXECUTE key." );
  510. if( KeyValueInfo ) {
  511. RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
  512. KeyValueInfo = NULL;
  513. }
  514. return Status;
  515. }
  516. NTSTATUS
  517. ProcessRepairHives(
  518. VOID
  519. )
  520. /*++
  521. ===============================================================================
  522. Routine Description:
  523. This function check keys (and all subkeys) for:
  524. - keys with the old SID name
  525. - value keys with the old SID value
  526. Arguments:
  527. None.
  528. Return Value:
  529. NTSTATUS.
  530. ===============================================================================
  531. --*/
  532. {
  533. ULONG i;
  534. NTSTATUS Status;
  535. PWSTR KeysToWhack[] = {
  536. //
  537. // SAM hive...
  538. //
  539. L"\\REGISTRY\\MACHINE\\RSAM",
  540. //
  541. // Security hive...
  542. //
  543. L"\\REGISTRY\\MACHINE\\RSECURITY",
  544. //
  545. // Software hive...
  546. //
  547. L"\\REGISTRY\\MACHINE\\RSOFTWARE",
  548. //
  549. // System hive...
  550. //
  551. L"\\REGISTRY\\MACHINE\\RSYSTEM",
  552. };
  553. PWSTR KeysToLoad[] = {
  554. //
  555. // SAM hive...
  556. //
  557. L"\\SYSTEMROOT\\REPAIR\\SAM",
  558. //
  559. // Security hive...
  560. //
  561. L"\\SYSTEMROOT\\REPAIR\\SECURITY",
  562. //
  563. // Software hive...
  564. //
  565. L"\\SYSTEMROOT\\REPAIR\\SOFTWARE",
  566. //
  567. // System hive...
  568. //
  569. L"\\SYSTEMROOT\\REPAIR\\SYSTEM",
  570. };
  571. for( i = 0; i < sizeof(KeysToWhack) / sizeof(PWSTR); i++ ) {
  572. //
  573. // Load the repair hive.
  574. //
  575. DbgPrint( "\nSETUPCL: ProcessRepairHives - About to load %ws hive.\n", KeysToLoad[i] );
  576. Status = LoadUnloadHive( KeysToWhack[i],
  577. KeysToLoad[i] );
  578. TEST_STATUS_RETURN( "SETUPCL: ProcessRepairHives - Failed to load repair hive." );
  579. //
  580. // Now operate on it.
  581. //
  582. DbgPrint( "SETUPCL: ProcessRepairHives - About to process %ws\n", KeysToWhack[i] );
  583. Status = SiftKey( KeysToWhack[i] );
  584. TEST_STATUS( "SETUPCL: ProcessRepairHives - Failed to process key..." );
  585. //
  586. // Unload the hive.
  587. //
  588. DbgPrint( "SETUPCL: ProcessRepairHives - About to unload %ws hive.\n", KeysToLoad[i] );
  589. Status = LoadUnloadHive( KeysToWhack[i],
  590. NULL );
  591. TEST_STATUS( "SETUPCL: ProcessRepairHives - Failed to unload repair hive." );
  592. }
  593. return( Status );
  594. }
  595. NTSTATUS
  596. RetrieveOldSid(
  597. VOID
  598. )
  599. /*++
  600. ===============================================================================
  601. Routine Description:
  602. Retrieves the current SID (as read from the registry.
  603. Use RtlFreeSid() to free the SID allocated by this routine.
  604. Arguments:
  605. Return Value:
  606. Status code indicating outcome.
  607. ===============================================================================
  608. --*/
  609. {
  610. NTSTATUS Status;
  611. HANDLE hKey;
  612. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo = NULL;
  613. OBJECT_ATTRIBUTES ObjectAttributes;
  614. UNICODE_STRING UnicodeString;
  615. ULONG KeyValueLength,
  616. LengthNeeded;
  617. UNICODE_STRING SidString;
  618. //
  619. // We can conveniently retrieve our SID from
  620. // \registry\machine\Security\Policy\PolAcDmS\<No Name>
  621. //
  622. // We'll open him up, read his data, then blast that into
  623. // a SID structure.
  624. //
  625. //
  626. // Open the PolAcDmS key.
  627. //
  628. INIT_OBJA( &ObjectAttributes, &UnicodeString, TEXT(REG_SECURITY_POLACDMS) );
  629. Status = NtOpenKey( &hKey,
  630. KEY_ALL_ACCESS,
  631. &ObjectAttributes );
  632. TEST_STATUS_RETURN( "SETUPCL: RetrieveOldSid - Failed to open PolAcDmS key!" );
  633. //
  634. // Get the data out of this key.
  635. //
  636. RtlInitUnicodeString(&UnicodeString, TEXT("") );
  637. //
  638. // How big of a buffer do we need?
  639. //
  640. Status = NtQueryValueKey( hKey,
  641. &UnicodeString,
  642. KeyValuePartialInformation,
  643. NULL,
  644. 0,
  645. &LengthNeeded );
  646. //
  647. // ISSUE-2002/02/26-brucegr,jcohen - Check for STATUS_SUCCESS, not assume success on STATUS_OBJECT_NAME_NOT_FOUND
  648. //
  649. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  650. DbgPrint( "SETUPCL: RetrieveOldSid - Unable to query size of old sid. Error (%lx)\n", Status );
  651. } else {
  652. Status = STATUS_SUCCESS;
  653. }
  654. //
  655. // Allocate a block.
  656. //
  657. if( NT_SUCCESS( Status ) ) {
  658. //
  659. // ISSUE-2002/02/26-brucegr,jcohen - This block will never get hit
  660. //
  661. if( KeyValueInfo ) {
  662. RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
  663. KeyValueInfo = NULL;
  664. }
  665. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
  666. 0,
  667. LengthNeeded + 0x10 );
  668. if( KeyValueInfo == NULL ) {
  669. DbgPrint( "SETUPCL: RetrieveOldSid - Unable to allocate buffer\n" );
  670. Status = STATUS_NO_MEMORY;
  671. }
  672. }
  673. //
  674. // Get the data.
  675. //
  676. if( NT_SUCCESS( Status ) ) {
  677. Status = NtQueryValueKey( hKey,
  678. &UnicodeString,
  679. KeyValuePartialInformation,
  680. (PVOID)KeyValueInfo,
  681. LengthNeeded,
  682. &KeyValueLength );
  683. if( !NT_SUCCESS( Status ) ) {
  684. DbgPrint( "SETUPCL: RetrieveOldSid - Failed to query old sid key (%lx)\n", Status );
  685. }
  686. }
  687. TEST_STATUS_RETURN( "SETUPCL: RetrieveOldSid - Failed to query PolAcDmS key!" );
  688. //
  689. // Allocate space for our new SID.
  690. //
  691. G_OldSid = RtlAllocateHeap( RtlProcessHeap(), 0,
  692. SID_SIZE );
  693. if( G_OldSid == NULL ) {
  694. DbgPrint( "SETUPCL: Call to RtlAllocateHeap failed!\n" );
  695. return( STATUS_NO_MEMORY );
  696. }
  697. //
  698. // Blast our Old SID into the memory we just allocated...
  699. //
  700. RtlCopyMemory( G_OldSid, ((PUCHAR)&KeyValueInfo->Data), SID_SIZE );
  701. //
  702. // ISSUE-2002/02/26-brucegr,jcohen - Close the key sooner!
  703. //
  704. NtClose( hKey );
  705. //
  706. // I need to get a text version of the 3 values that make
  707. // up this SID's uniqueness. This is pretty gross. It turns
  708. // out that the first 8 characters of the SID string (as gotten
  709. // from a call to RtlConvertSidtoUnicodeString) are the same
  710. // for any Domain SID. And it's always the 9th character that
  711. // starts the 3 unique numbers.
  712. //
  713. Status = RtlConvertSidToUnicodeString( &SidString, G_OldSid, TRUE );
  714. TEST_STATUS_RETURN( "SETUPCL: RetrieveOldSid - RtlConvertSidToUnicodeString failed!" );
  715. memset( G_OldSidSubString, 0, sizeof(G_OldSidSubString) );
  716. wcsncpy( G_OldSidSubString, &SidString.Buffer[9], AS(G_OldSidSubString) - 1 );
  717. #ifdef DBG
  718. //
  719. // Debug spew.
  720. //
  721. {
  722. int i;
  723. DbgPrint( "SETUPCL: RetrieveOldSid - Retrieved SID:\n" );
  724. for( i = 0; i < SID_SIZE; i += 4 ) {
  725. DbgPrint( "%08lx ", *(PULONG)((PUCHAR)(G_OldSid) + i));
  726. }
  727. DbgPrint( "\n" );
  728. DbgPrint("Old Sid = %ws \n",SidString.Buffer);
  729. }
  730. #endif
  731. RtlFreeUnicodeString( &SidString );
  732. //
  733. // ISSUE-2002/02/26-brucegr,jcohen - Free the value buffer sooner? Do we need to assign KeyValueInfo to NULL after we're done with it?
  734. //
  735. if( KeyValueInfo ) {
  736. RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
  737. KeyValueInfo = NULL;
  738. }
  739. return( STATUS_SUCCESS );
  740. }
  741. BOOL
  742. SetupGenRandom(
  743. OUT PVOID pbRandomKey,
  744. IN ULONG cbRandomKey
  745. )
  746. {
  747. BOOL fRet = FALSE;
  748. HANDLE hFile;
  749. NTSTATUS Status;
  750. UNICODE_STRING DriverName;
  751. IO_STATUS_BLOCK IOSB;
  752. OBJECT_ATTRIBUTES ObjA;
  753. //
  754. // have to use the Nt flavor of the file open call because it's a base
  755. // device not aliased to \DosDevices
  756. //
  757. RtlInitUnicodeString( &DriverName, DD_KSEC_DEVICE_NAME_U );
  758. InitializeObjectAttributes( &ObjA,
  759. &DriverName,
  760. OBJ_CASE_INSENSITIVE,
  761. 0,
  762. 0 );
  763. Status = NtOpenFile( &hFile,
  764. SYNCHRONIZE | FILE_READ_DATA,
  765. &ObjA,
  766. &IOSB,
  767. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  768. FILE_SYNCHRONOUS_IO_ALERT );
  769. if ( NT_SUCCESS(Status) )
  770. {
  771. Status = NtDeviceIoControlFile( hFile,
  772. NULL,
  773. NULL,
  774. NULL,
  775. &IOSB,
  776. IOCTL_KSEC_RNG_REKEY, // indicate a RNG rekey
  777. NULL, // input buffer (existing material)
  778. 0, // input buffer size
  779. pbRandomKey, // output buffer
  780. cbRandomKey ); // output buffer size
  781. if ( NT_SUCCESS(Status) )
  782. {
  783. fRet = TRUE;
  784. }
  785. else
  786. {
  787. PRINT_STATUS( "SetupGenRandom: NtDeviceIoControlFile failed!" );
  788. }
  789. NtClose( hFile );
  790. }
  791. else
  792. {
  793. PRINT_STATUS( "SetupGenRandom: NtOpenFile failed!" );
  794. }
  795. return fRet;
  796. }
  797. NTSTATUS
  798. SetupGenerateRandomDomainSid(
  799. OUT PSID NewDomainSid
  800. )
  801. /*++
  802. Routine Description:
  803. This function will generate a random sid to be used for the new account domain sid during
  804. setup.
  805. Arguments:
  806. NewDomainSid - Where the new domain sid is returned. Freed via RtlFreeSid()
  807. Return Values:
  808. STATUS_SUCCESS -- Success.
  809. STATUS_INVALID_PARAMETER -- We couldn't generate a random number
  810. STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
  811. --*/
  812. {
  813. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  814. ULONG SubAuth1, SubAuth2, SubAuth3;
  815. //
  816. // Generate three random numbers for the new domain SID...
  817. //
  818. if ( SetupGenRandom( &SubAuth1, sizeof(SubAuth1) ) &&
  819. SetupGenRandom( &SubAuth2, sizeof(SubAuth2) ) &&
  820. SetupGenRandom( &SubAuth3, sizeof(SubAuth3) ) )
  821. {
  822. SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
  823. #ifdef DBG
  824. DbgPrint( "New SID: 0x%lx, 0x%lx, 0x%lx\n", SubAuth1, SubAuth2, SubAuth3 );
  825. #endif
  826. Status = RtlAllocateAndInitializeSid( &IdentifierAuthority,
  827. 4,
  828. 0x15,
  829. SubAuth1,
  830. SubAuth2,
  831. SubAuth3,
  832. 0,
  833. 0,
  834. 0,
  835. 0,
  836. NewDomainSid );
  837. }
  838. return( Status );
  839. }
  840. NTSTATUS
  841. GenerateUniqueSid(
  842. IN DWORD Seed
  843. )
  844. /*++
  845. ===============================================================================
  846. Routine Description:
  847. Generates a (hopefully) unique SID for use by Setup. Setup uses this
  848. SID as the Domain SID for the Account domain.
  849. Use RtlFreeSid() to free the SID allocated by this routine.
  850. Arguments:
  851. Sid - On return points to the created SID.
  852. Return Value:
  853. Status code indicating outcome.
  854. ===============================================================================
  855. --*/
  856. {
  857. NTSTATUS Status;
  858. HANDLE hKey;
  859. UNICODE_STRING SidString;
  860. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo = NULL;
  861. //
  862. // Use the same logic as LSASS to generate a unique system SID...
  863. //
  864. Status = SetupGenerateRandomDomainSid( &G_NewSid );
  865. TEST_STATUS_RETURN( "SETUPCL: GenerateUniqueSid - LsapGenerateRandomDomainSid failed!" );
  866. //
  867. // I need to get a text version of the 3 values that make
  868. // up this SID's uniqueness. This is pretty gross. It turns
  869. // out that the first 8 characters of the SID string (as gotten
  870. // from a call to RtlConvertSidtoUnicodeString) are the same
  871. // for any Domain SID. And it's always the 9th character that
  872. // starts the 3 unique numbers.
  873. //
  874. Status = RtlConvertSidToUnicodeString( &SidString, G_NewSid, TRUE );
  875. TEST_STATUS_RETURN( "SETUPCL: GenerateUniqueSid - RtlConvertSidToUnicodeString failed!" );
  876. wcscpy( G_NewSidSubString, &SidString.Buffer[9] );
  877. #ifdef DBG
  878. //
  879. // Debug spew.
  880. //
  881. {
  882. int i;
  883. DbgPrint( "SETUPCL: SetupGenerateUniqueSid - Generated SID:\n" );
  884. for( i = 0; i < SID_SIZE; i += 4 ) {
  885. DbgPrint( "%08lx ", *(PULONG)((PUCHAR)(G_NewSid) + i));
  886. }
  887. DbgPrint( "\n" );
  888. DbgPrint("Generated Sid = %ws \n",SidString.Buffer);
  889. }
  890. #endif
  891. RtlFreeUnicodeString( &SidString );
  892. if( KeyValueInfo ) {
  893. RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
  894. KeyValueInfo = NULL;
  895. }
  896. return Status;
  897. }
  898. #ifdef IA64
  899. VOID
  900. CreateNewGuid(
  901. IN GUID *Guid
  902. )
  903. /*++
  904. Routine Description:
  905. Creates a new pseudo GUID.
  906. Arguments:
  907. Guid - Place holder for the new pseudo
  908. Return Value:
  909. None.
  910. --*/
  911. {
  912. if (Guid)
  913. {
  914. LARGE_INTEGER Time;
  915. ULONG Random1 = RtlRandom(&RandomSeed);
  916. ULONG Random2 = RtlRandom(&RandomSeed);
  917. //
  918. // Get system time
  919. //
  920. NtQuerySystemTime(&Time);
  921. RtlZeroMemory(Guid, sizeof(GUID));
  922. //
  923. // First 8 bytes is system time
  924. //
  925. RtlCopyMemory(Guid, &(Time.QuadPart), sizeof(Time.QuadPart));
  926. //
  927. // Next 8 bytes are two random numbers
  928. //
  929. RtlCopyMemory(Guid->Data4, &Random1, sizeof(ULONG));
  930. RtlCopyMemory(((PCHAR)Guid->Data4) + sizeof(ULONG),
  931. &Random2, sizeof(ULONG));
  932. }
  933. }
  934. VOID* MyMalloc(size_t Size)
  935. {
  936. return RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, Size );
  937. }
  938. VOID MyFree(VOID *Memory)
  939. {
  940. RtlFreeHeap( RtlProcessHeap(), 0, Memory );
  941. }
  942. NTSTATUS
  943. GetAndWriteBootEntry(
  944. IN POS_BOOT_ENTRY pBootEntry
  945. )
  946. /*++
  947. Routine Description:
  948. Get the boot entry from NVRAM for the given boot entry Id. Construct a filename
  949. of the form BootXXXX, where XXXX = id. Put the file in the same directory as the
  950. EFI OS loader. The directory is determined from the LoaderFile string.
  951. Arguments:
  952. pBootEntry pointer to the POS_BOOT_ENTRY structure
  953. Return Value:
  954. NTSTATUS
  955. Remarks:
  956. This was ported from \textmode\kernel\spboot.c on 6/9/2001.
  957. --*/
  958. {
  959. NTSTATUS status;
  960. UNICODE_STRING idStringUnicode;
  961. WCHAR idStringWChar[9] = {0};
  962. WCHAR BootEntryPath[MAX_PATH] = {0};
  963. HANDLE hfile;
  964. OBJECT_ATTRIBUTES oa;
  965. IO_STATUS_BLOCK iostatus;
  966. UCHAR* bootVar = NULL;
  967. ULONG bootVarSize;
  968. UNICODE_STRING uFilePath;
  969. UINT64 BootNumber;
  970. UINT64 BootSize;
  971. GUID EfiBootVariablesGuid = EFI_GLOBAL_VARIABLE;
  972. ULONG Id = 0;
  973. WCHAR* pwsFilePart = NULL;
  974. hfile = NULL;
  975. if (NULL == pBootEntry)
  976. return STATUS_INVALID_PARAMETER;
  977. //
  978. // BootEntryPath = OsLoaderVolumeName + OsLoaderPath
  979. // OsLoaderVolumeName = "\Device\HarddriveVolume1"
  980. // OsLoaderPath = "\Efi\Microsoft\Winnt50\ia64ldr.efi"
  981. // Then Strip off the ia64ldr.efi and replace with BootXXX.
  982. //
  983. wcsncpy(BootEntryPath, pBootEntry->OsLoaderVolumeName, AS(BootEntryPath) - 1);
  984. wcsncpy(BootEntryPath + wcslen(BootEntryPath), pBootEntry->OsLoaderPath, AS(BootEntryPath) - wcslen(BootEntryPath) - 1);
  985. //
  986. // Backup to last backslash before ia64ldr.efi careful of clength
  987. //
  988. pwsFilePart = wcsrchr(BootEntryPath, L'\\');
  989. *(++pwsFilePart) = L'\0';
  990. //
  991. // Id = BootEntry Id
  992. //
  993. Id = pBootEntry->Id;
  994. //
  995. // Retrieve the NVRAM entry for the Id specified
  996. //
  997. _snwprintf( idStringWChar, AS(idStringWChar) - 1, L"Boot%04x", Id);
  998. //
  999. // Append the BootXXXX
  1000. //
  1001. wcsncpy(BootEntryPath + wcslen(BootEntryPath), idStringWChar, AS(BootEntryPath) - wcslen(BootEntryPath) - 1);
  1002. DbgPrint("SETUPCL: Writing to NVRBoot file %ws.\n", BootEntryPath);
  1003. RtlInitUnicodeString( &idStringUnicode, idStringWChar);
  1004. bootVarSize = 0;
  1005. status = NtQuerySystemEnvironmentValueEx(&idStringUnicode,
  1006. &EfiBootVariablesGuid,
  1007. NULL,
  1008. &bootVarSize,
  1009. NULL);
  1010. if (status != STATUS_BUFFER_TOO_SMALL) {
  1011. ASSERT(FALSE);
  1012. DbgPrint("SETUPCL: Failed to get size for boot entry buffer.\n");
  1013. goto Done;
  1014. } else {
  1015. bootVar = RtlAllocateHeap(RtlProcessHeap(), 0, bootVarSize);
  1016. if (!bootVar) {
  1017. status = STATUS_NO_MEMORY;
  1018. DbgPrint("SETUPCL: Failed to allocate boot entry buffer.\n");
  1019. goto Done;
  1020. }
  1021. status = NtQuerySystemEnvironmentValueEx(&idStringUnicode,
  1022. &EfiBootVariablesGuid,
  1023. bootVar,
  1024. &bootVarSize,
  1025. NULL);
  1026. if (status != STATUS_SUCCESS) {
  1027. ASSERT(FALSE);
  1028. DbgPrint("SETUPCL: Failed to get boot entry.\n");
  1029. goto Done;
  1030. }
  1031. }
  1032. //
  1033. // open the file
  1034. //
  1035. INIT_OBJA(&oa, &uFilePath, BootEntryPath);
  1036. status = NtCreateFile(&hfile,
  1037. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  1038. &oa,
  1039. &iostatus,
  1040. NULL,
  1041. FILE_ATTRIBUTE_NORMAL,
  1042. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1043. FILE_OVERWRITE_IF,
  1044. FILE_SYNCHRONOUS_IO_NONALERT,
  1045. NULL,
  1046. 0
  1047. );
  1048. if ( ! NT_SUCCESS(status) ) {
  1049. DbgPrint("SETUPCL: Failed to create boot entry recovery file %lx.\n", status);
  1050. goto Done;
  1051. }
  1052. //
  1053. // Write the bits to disk using the format required
  1054. // by base/efiutil/efinvram/savrstor.c
  1055. //
  1056. // [BootNumber][BootSize][BootEntry (of BootSize)]
  1057. //
  1058. //
  1059. // build the header info for the boot entry block
  1060. //
  1061. // [header] include the boot id
  1062. BootNumber = Id;
  1063. status = NtWriteFile( hfile,
  1064. NULL,
  1065. NULL,
  1066. NULL,
  1067. &iostatus,
  1068. &BootNumber,
  1069. sizeof(BootNumber),
  1070. NULL,
  1071. NULL
  1072. );
  1073. if ( ! NT_SUCCESS(status) ) {
  1074. DbgPrint("SETUPCL: Failed writing boot number to boot entry recovery file.\n");
  1075. goto Done;
  1076. }
  1077. // [header] include the boot size
  1078. BootSize = bootVarSize;
  1079. status = NtWriteFile( hfile,
  1080. NULL,
  1081. NULL,
  1082. NULL,
  1083. &iostatus,
  1084. &BootSize,
  1085. sizeof(BootSize),
  1086. NULL,
  1087. NULL
  1088. );
  1089. if ( ! NT_SUCCESS(status) ) {
  1090. DbgPrint("SETUPCL: Failed writing boot entry size to boot entry recovery file.\n");
  1091. goto Done;
  1092. }
  1093. // boot entry bits
  1094. status = NtWriteFile( hfile,
  1095. NULL,
  1096. NULL,
  1097. NULL,
  1098. &iostatus,
  1099. bootVar,
  1100. bootVarSize,
  1101. NULL,
  1102. NULL
  1103. );
  1104. if ( ! NT_SUCCESS(status) ) {
  1105. DbgPrint("SETUPCL: Failed writing boot entry to boot entry recovery file.\n");
  1106. goto Done;
  1107. }
  1108. Done:
  1109. //
  1110. // We are done
  1111. //
  1112. if (bootVar) {
  1113. RtlFreeHeap(RtlProcessHeap(), 0, bootVar);
  1114. }
  1115. if (hfile) {
  1116. NtClose( hfile );
  1117. }
  1118. return status;
  1119. }
  1120. NTSTATUS
  1121. ResetDiskGuids(VOID)
  1122. {
  1123. NTSTATUS Status;
  1124. SYSTEM_DEVICE_INFORMATION sdi;
  1125. ULONG iDrive;
  1126. // Clean up the memory
  1127. //
  1128. RtlZeroMemory(&sdi, sizeof(sdi));
  1129. // Query the number of physical devices on the system
  1130. //
  1131. Status = NtQuerySystemInformation(SystemDeviceInformation, &sdi, sizeof(SYSTEM_DEVICE_INFORMATION), NULL);
  1132. // We successfully queried the devices and there are devices there
  1133. //
  1134. if ( NT_SUCCESS(Status) && sdi.NumberOfDisks)
  1135. {
  1136. POS_BOOT_OPTIONS pBootOptions = NULL;
  1137. POS_BOOT_OPTIONS pBootOptionsInitial = NULL;
  1138. POS_BOOT_ENTRY pBootEntry = NULL;
  1139. DbgPrint("Successfully queried (%lx) disks.\n", sdi.NumberOfDisks);
  1140. // Initialize the library with our own memory management functions
  1141. //
  1142. if ( OSBOLibraryInit(MyMalloc, MyFree) )
  1143. {
  1144. // Determine initial BootOptions
  1145. //
  1146. pBootOptions = EFIOSBOCreate();
  1147. pBootOptionsInitial = EFIOSBOCreate();
  1148. // Were we able to create the BootOptions
  1149. //
  1150. if ( pBootOptions && pBootOptionsInitial )
  1151. {
  1152. // Iterate through each disk and determine the GUID
  1153. //
  1154. for ( iDrive = 0; iDrive < sdi.NumberOfDisks && NT_SUCCESS(Status); iDrive++ )
  1155. {
  1156. WCHAR szPhysicalDrives[MAX_PATH] = {0};
  1157. UNICODE_STRING UnicodeString;
  1158. OBJECT_ATTRIBUTES Obja;
  1159. HANDLE DiskHandle;
  1160. IO_STATUS_BLOCK IoStatusBlock;
  1161. // Generate the path to the drive
  1162. //
  1163. _snwprintf(szPhysicalDrives, AS(szPhysicalDrives) - 1, L"\\Device\\Harddisk%d\\Partition0", iDrive);
  1164. // Initialize the handle to unicode string
  1165. //
  1166. INIT_OBJA(&Obja,&UnicodeString,szPhysicalDrives);
  1167. // Attempt to open the file
  1168. //
  1169. Status = NtCreateFile( &DiskHandle,
  1170. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  1171. &Obja,
  1172. &IoStatusBlock,
  1173. NULL,
  1174. FILE_ATTRIBUTE_NORMAL,
  1175. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1176. FILE_OPEN,
  1177. 0,
  1178. NULL,
  1179. 0 );
  1180. // Check to see if we were able to open the disk
  1181. //
  1182. if ( !NT_SUCCESS(Status) )
  1183. {
  1184. DbgPrint("Unable to open file on %ws. Error (%lx)\n", szPhysicalDrives, Status);
  1185. }
  1186. else
  1187. {
  1188. PDRIVE_LAYOUT_INFORMATION_EX pLayoutInfoEx = NULL;
  1189. ULONG lengthLayoutEx = 0,
  1190. iPart;
  1191. DbgPrint("Successfully opened file on %ws\n", szPhysicalDrives);
  1192. lengthLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX) * 128);
  1193. pLayoutInfoEx = (PDRIVE_LAYOUT_INFORMATION_EX) MyMalloc( lengthLayoutEx );
  1194. if ( pLayoutInfoEx )
  1195. {
  1196. // Attempt to get the drive layout
  1197. //
  1198. Status = NtDeviceIoControlFile( DiskHandle, 0, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, pLayoutInfoEx, lengthLayoutEx );
  1199. // Check the status of the drive layout
  1200. //
  1201. if ( !NT_SUCCESS(Status) )
  1202. DbgPrint("Unable to open IOCTL on %ws. Error (%lx)\n", szPhysicalDrives, Status);
  1203. else
  1204. {
  1205. DbgPrint("Opened IOCTL on drive %ws. Error (%lx)\n", szPhysicalDrives, Status);
  1206. DbgPrint("\tPhysical Disk %d\n", iDrive);
  1207. DbgPrint("\tPartition Count: %d\n", pLayoutInfoEx->PartitionCount);
  1208. // Iterate through each partition
  1209. //
  1210. for (iPart = 0; iPart < pLayoutInfoEx->PartitionCount; iPart++)
  1211. {
  1212. // We only would like to deal with GPT partitions
  1213. //
  1214. if ( pLayoutInfoEx->PartitionEntry[iPart].PartitionStyle == PARTITION_STYLE_GPT )
  1215. {
  1216. const UUID GuidNull = { 0 };
  1217. #ifdef DBG
  1218. UNICODE_STRING cGuid;
  1219. UNICODE_STRING cGuidNew;
  1220. #endif
  1221. // Only replace the Guid if it's NULL.
  1222. //
  1223. if (IsEqualGUID(&(pLayoutInfoEx->PartitionEntry[iPart].Gpt.PartitionId), &GuidNull))
  1224. {
  1225. //
  1226. // ISSUE-2002/02/26-brucegr,jcohen - CreateNewGuid expects GUID structure. Possible mismatch?
  1227. //
  1228. // (acosma 2002/04/24) Fix this issue in Longhorn. UUID is typedef to GUID or the
  1229. // other way around so they are the same thing, however for readability we will fix this.
  1230. //
  1231. UUID Guid;
  1232. // Create a new GUID for this machine
  1233. //
  1234. CreateNewGuid(&Guid);
  1235. #ifdef DBG
  1236. if ( NT_SUCCESS( RtlStringFromGUID((LPGUID) &(pLayoutInfoEx->PartitionEntry[iPart].Gpt.PartitionId), &cGuid) ) )
  1237. {
  1238. if ( NT_SUCCESS( RtlStringFromGUID((LPGUID) &Guid, &cGuidNew) ) )
  1239. {
  1240. DbgPrint("\tPartition: %ws (%x), %ws %ws\n",
  1241. pLayoutInfoEx->PartitionEntry[iPart].Gpt.Name, iPart, cGuid.Buffer, cGuidNew.Buffer);
  1242. RtlFreeUnicodeString(&cGuidNew);
  1243. }
  1244. RtlFreeUnicodeString(&cGuid);
  1245. }
  1246. #endif
  1247. // This is a struct to struct assignment. It is legal in C.
  1248. //
  1249. pLayoutInfoEx->PartitionEntry[iPart].Gpt.PartitionId = Guid;
  1250. }
  1251. }
  1252. }
  1253. }
  1254. TEST_STATUS("SETUPCL: ResetDiskGuids - Failed to reset Disk Guids.");
  1255. if ( NT_SUCCESS( Status = NtDeviceIoControlFile( DiskHandle, 0, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, pLayoutInfoEx, lengthLayoutEx, NULL, 0 ) ) )
  1256. {
  1257. DbgPrint("\tSuccessfully reset %ws\n", szPhysicalDrives);
  1258. }
  1259. //
  1260. // Free the layout info buffer...
  1261. //
  1262. MyFree( pLayoutInfoEx );
  1263. }
  1264. // Clean up the memory
  1265. //
  1266. NtClose( DiskHandle );
  1267. }
  1268. }
  1269. // Delete the old boot entries and recreate them so we pick up the new GUIDS if they changed.
  1270. //
  1271. if ( NT_SUCCESS(Status) )
  1272. {
  1273. POS_BOOT_ENTRY pActiveBootEntry = NULL;
  1274. DWORD dwBootEntryCount = OSBOGetBootEntryCount(pBootOptionsInitial);
  1275. DbgPrint("SETUPCL: ResetDiskGuids - Updating boot entries to use new GUIDS.\n");
  1276. if (dwBootEntryCount)
  1277. {
  1278. ULONG Index;
  1279. BOOL bSetActive = FALSE;
  1280. // Get the current boot entry
  1281. //
  1282. pActiveBootEntry = OSBOGetActiveBootEntry(pBootOptionsInitial);
  1283. pBootEntry = OSBOGetFirstBootEntry(pBootOptionsInitial, &Index);
  1284. while ( pBootEntry )
  1285. {
  1286. // Don't set the current entry active by default.
  1287. //
  1288. bSetActive = FALSE;
  1289. if ( OSBE_IS_WINDOWS(pBootEntry) )
  1290. {
  1291. POS_BOOT_ENTRY pBootEntryToDelete = NULL;
  1292. WCHAR FriendlyName[MAX_PATH],
  1293. OsLoaderVolumeName[MAX_PATH],
  1294. OsLoaderPath[MAX_PATH],
  1295. BootVolumeName[MAX_PATH],
  1296. BootPath[MAX_PATH],
  1297. OsLoadOptions[MAX_PATH];
  1298. // Load the boot entry parameters into their own buffer
  1299. //
  1300. memset(FriendlyName, 0, AS(FriendlyName));
  1301. memset(OsLoaderVolumeName, 0, AS(OsLoaderVolumeName));
  1302. memset(OsLoaderPath, 0, AS(OsLoaderPath));
  1303. memset(BootVolumeName, 0, AS(BootVolumeName));
  1304. memset(BootPath, 0, AS(BootPath));
  1305. memset(OsLoadOptions, 0, AS(OsLoadOptions));
  1306. wcsncpy(FriendlyName, OSBEGetFriendlyName(pBootEntry), AS(FriendlyName) - 1);
  1307. wcsncpy(OsLoaderVolumeName, OSBEGetOsLoaderVolumeName(pBootEntry), AS(OsLoaderVolumeName) - 1);
  1308. wcsncpy(OsLoaderPath, OSBEGetOsLoaderPath(pBootEntry), AS(OsLoaderPath) - 1);
  1309. wcsncpy(BootVolumeName, OSBEGetBootVolumeName(pBootEntry), AS(BootVolumeName) - 1);
  1310. wcsncpy(BootPath, OSBEGetBootPath(pBootEntry), AS(BootPath) - 1);
  1311. wcsncpy(OsLoadOptions, OSBEGetOsLoadOptions(pBootEntry), AS(OsLoadOptions) - 1);
  1312. // If this is the active boot entry set active the new boot entry that we are going to create.
  1313. //
  1314. if ( pBootEntry == pActiveBootEntry )
  1315. {
  1316. bSetActive = TRUE;
  1317. }
  1318. if ( ( pBootEntryToDelete = OSBOFindBootEntry(pBootOptions, pBootEntry->Id) ) &&
  1319. OSBODeleteBootEntry(pBootOptions, pBootEntryToDelete) )
  1320. {
  1321. POS_BOOT_ENTRY pBootEntryNew = NULL;
  1322. pBootEntryNew = OSBOAddNewBootEntry(pBootOptions,
  1323. FriendlyName,
  1324. OsLoaderVolumeName,
  1325. OsLoaderPath,
  1326. BootVolumeName,
  1327. BootPath,
  1328. OsLoadOptions);
  1329. if ( pBootEntryNew )
  1330. {
  1331. if ( bSetActive )
  1332. {
  1333. OSBOSetActiveBootEntry(pBootOptions, pBootEntryNew);
  1334. }
  1335. // Update the NVRBoot file
  1336. //
  1337. GetAndWriteBootEntry(pBootEntryNew);
  1338. // Flush out the boot options
  1339. //
  1340. OSBEFlush(pBootEntryNew);
  1341. }
  1342. else
  1343. {
  1344. DbgPrint("SETUPCL: ResetDiskGuids - Failed to add a boot entry [%ws]\n", FriendlyName);
  1345. }
  1346. }
  1347. else
  1348. {
  1349. DbgPrint("SETUPCL: ResetDiskGuids - Failed to delete a boot entry [%ws]\n", FriendlyName);
  1350. }
  1351. }
  1352. // Get the next entry.
  1353. //
  1354. pBootEntry = OSBOGetNextBootEntry(pBootOptionsInitial, &Index);
  1355. }
  1356. }
  1357. // Flush the boot options if we've changed GUIDS.
  1358. //
  1359. OSBOFlush(pBootOptions);
  1360. }
  1361. }
  1362. else
  1363. {
  1364. DbgPrint("SETUPCL: ResetDiskGuids - Failed to load the existing boot entries.\n");
  1365. }
  1366. //
  1367. // Free the boot option structures.
  1368. //
  1369. if ( pBootOptions )
  1370. {
  1371. OSBODelete(pBootOptions);
  1372. }
  1373. if ( pBootOptionsInitial )
  1374. {
  1375. OSBODelete(pBootOptionsInitial);
  1376. }
  1377. }
  1378. else
  1379. {
  1380. DbgPrint("SETUPCL: ResetDiskGuids - Failed to initialize the boot options library.\n");
  1381. }
  1382. }
  1383. return Status;
  1384. }
  1385. #endif \\ #ifdef IA64
  1386. // This function always deletes a CRLF from the end of the string. It assumes that there
  1387. // is a CRLF at the end of the line and just removes the last two characters.
  1388. //
  1389. void OutputString(LPTSTR szMsg)
  1390. {
  1391. UNICODE_STRING uMsg;
  1392. RtlInitUnicodeString(&uMsg, szMsg);
  1393. // Whack the CRLF at the end of the string. Doing this here for performance reasons.
  1394. // Don't want to put this in DisplayUI().
  1395. //
  1396. if (uMsg.Length > ( 2 * sizeof(WCHAR)) )
  1397. {
  1398. uMsg.Length -= (2 * sizeof(WCHAR));
  1399. uMsg.Buffer[uMsg.Length / sizeof(WCHAR)] = 0; // UNICODE_NULL
  1400. }
  1401. NtDisplayString(&uMsg);
  1402. }
  1403. // Keep this function as short as possible. This gets called a lot in the recursive functions of setupcl.
  1404. // Do not create any stack based variables here for performance reasons.
  1405. //
  1406. __inline void DisplayUI()
  1407. {
  1408. NtQuerySystemTime(&CurrentTime);
  1409. if ( !bDisplayUI )
  1410. {
  1411. if ( (CurrentTime.QuadPart - StartTime.QuadPart) > UITIME )
  1412. {
  1413. static UNICODE_STRING UnicodeString = { 0 };
  1414. bDisplayUI = TRUE;
  1415. LastDotTime.QuadPart = CurrentTime.QuadPart;
  1416. if ( LoadStringResource(&UnicodeString, IDS_UIMAIN) )
  1417. {
  1418. OutputString(UnicodeString.Buffer);
  1419. RtlFreeUnicodeString(&UnicodeString);
  1420. }
  1421. }
  1422. }
  1423. else
  1424. { // If more than 3 seconds passed since our last output put up a dot.
  1425. //
  1426. if ( (CurrentTime.QuadPart - LastDotTime.QuadPart) > UIDOTTIME )
  1427. {
  1428. LastDotTime.QuadPart = CurrentTime.QuadPart;
  1429. OutputString(TEXT("."));
  1430. }
  1431. }
  1432. }
  1433. int __cdecl
  1434. main(
  1435. int argc,
  1436. char** argv,
  1437. char** envp,
  1438. ULONG DebugParameter
  1439. )
  1440. /*++
  1441. ===============================================================================
  1442. Routine Description:
  1443. This routine is the main entry point for the program.
  1444. We do a bit of error checking, then, if all goes well, we update the
  1445. registry to enable execution of our second half.
  1446. ===============================================================================
  1447. --*/
  1448. {
  1449. BOOLEAN b;
  1450. int i;
  1451. NTSTATUS Status;
  1452. LARGE_INTEGER Time;
  1453. //
  1454. // Get Time for seed generation...
  1455. //
  1456. NtQuerySystemTime(&Time);
  1457. #ifdef IA64
  1458. // Setup the Seed for generating GUIDs
  1459. //
  1460. RandomSeed = (ULONG) Time.LowPart;
  1461. #endif
  1462. // Initialize the StartTime
  1463. //
  1464. StartTime.QuadPart = Time.QuadPart;
  1465. LastDotTime.QuadPart = Time.QuadPart;
  1466. i = 0;
  1467. //
  1468. // Enable several privileges that we will need.
  1469. //
  1470. //
  1471. // NTRAID#NTBUG9-545904-2002/02/26-brucegr,jcohen - Do something smarter with regard to error conditions.
  1472. //
  1473. Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE,TRUE,FALSE,&b);
  1474. TEST_STATUS( "SETUPCL: Warning - unable to enable SE_BACKUP_PRIVILEGE privilege!" );
  1475. Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,TRUE,FALSE,&b);
  1476. TEST_STATUS( "SETUPCL: Warning - unable to enable SE_RESTORE_PRIVILEGE privilege!" );
  1477. Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,TRUE,FALSE,&b);
  1478. TEST_STATUS( "SETUPCL: Warning - unable to enable SE_SHUTDOWN_PRIVILEGE privilege!" );
  1479. Status = RtlAdjustPrivilege(SE_TAKE_OWNERSHIP_PRIVILEGE,TRUE,FALSE,&b);
  1480. TEST_STATUS( "SETUPCL: Warning - unable to enable SE_TAKE_OWNERSHIP_PRIVILEGE privilege!" );
  1481. Status = RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE,TRUE,FALSE,&b);
  1482. TEST_STATUS( "SETUPCL: Warning - unable to enable SE_SECURITY_PRIVILEGE privilege!" );
  1483. Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE,TRUE,FALSE,&b);
  1484. TEST_STATUS( "SETUPCL: Warning - unable to enable SE_TCB_PRIVILEGE privilege!" );
  1485. #ifdef IA64
  1486. //
  1487. // Reset the Disk GUIDs.
  1488. //
  1489. DbgPrint("We are currently running on IA64. Resetting disk GUIDs.\n");
  1490. //
  1491. // ISSUE-2002/02/26-brucegr,jcohen - Error code isn't tested!
  1492. //
  1493. ResetDiskGuids();
  1494. #endif
  1495. //
  1496. // Retrieve old Security ID.
  1497. //
  1498. Status = RetrieveOldSid( );
  1499. TEST_STATUS_RETURN( "SETUPCL: Retrieval of old SID failed!" );
  1500. //
  1501. // Generate a new Security ID.
  1502. //
  1503. //
  1504. // NTRAID#NTBUG9-545855-2002/02/26-brucegr,jcohen - Use same sid generation algorithm as LsapGenerateRandomDomainSid
  1505. // in ds\security\base\lsa\server\dspolicy\dbinit.c
  1506. //
  1507. Status = GenerateUniqueSid( Time.LowPart );
  1508. TEST_STATUS_RETURN( "SETUPCL: Generation of new SID failed!" );
  1509. //
  1510. // Make a copy of the repair hives.
  1511. //
  1512. Status = BackupRepairHives();
  1513. if( NT_SUCCESS(Status) ) {
  1514. //
  1515. // Do the repair hives.
  1516. //
  1517. Status = ProcessRepairHives();
  1518. TEST_STATUS( "SETUPCL: Failed to update one of the Repair hives." );
  1519. }
  1520. //
  1521. // Decide if we need to restore the repair hives from our backups.
  1522. //
  1523. CleanupRepairHives( Status );
  1524. //
  1525. // Now process the hives, one at a time.
  1526. //
  1527. //
  1528. // NTRAID#NTBUG9-545904-2002/02/26-brucegr,jcohen - Do something smarter with regard to error conditions.
  1529. //
  1530. Status = ProcessHives();
  1531. //
  1532. // NTRAID#NTBUG9-545904-2002/02/26-brucegr,jcohen - Do something smarter with regard to error conditions.
  1533. //
  1534. Status = FinalHiveCleanup();
  1535. //
  1536. // Now go enumerate all the drives. For each NTFS drive,
  1537. // we'll whack the ACL to reflect the new SID.
  1538. //
  1539. //
  1540. // NTRAID#NTBUG9-545904-2002/02/26-brucegr,jcohen - Do something smarter with regard to error conditions.
  1541. //
  1542. Status = EnumerateDrives();
  1543. return Status;
  1544. }
  1545. //
  1546. // Disable the DbgPrint for non-debug builds
  1547. //
  1548. #ifndef DBG
  1549. void DbgPrintSub(char *szBuffer, ...)
  1550. {
  1551. return;
  1552. }
  1553. #endif